jdk/src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ot-layout-gpos-table.hh
changeset 34414 e496a8d8fc8a
child 40435 553eb1a50733
equal deleted inserted replaced
34413:bbed9966db6e 34414:e496a8d8fc8a
       
     1 /*
       
     2  * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
       
     3  * Copyright © 2010,2012,2013  Google, Inc.
       
     4  *
       
     5  *  This is part of HarfBuzz, a text shaping library.
       
     6  *
       
     7  * Permission is hereby granted, without written agreement and without
       
     8  * license or royalty fees, to use, copy, modify, and distribute this
       
     9  * software and its documentation for any purpose, provided that the
       
    10  * above copyright notice and the following two paragraphs appear in
       
    11  * all copies of this software.
       
    12  *
       
    13  * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
       
    14  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
       
    15  * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
       
    16  * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
       
    17  * DAMAGE.
       
    18  *
       
    19  * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
       
    20  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
       
    21  * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
       
    22  * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
       
    23  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
       
    24  *
       
    25  * Red Hat Author(s): Behdad Esfahbod
       
    26  * Google Author(s): Behdad Esfahbod
       
    27  */
       
    28 
       
    29 #ifndef HB_OT_LAYOUT_GPOS_TABLE_HH
       
    30 #define HB_OT_LAYOUT_GPOS_TABLE_HH
       
    31 
       
    32 #include "hb-ot-layout-gsubgpos-private.hh"
       
    33 
       
    34 
       
    35 namespace OT {
       
    36 
       
    37 
       
    38 /* buffer **position** var allocations */
       
    39 #define attach_lookback() var.u16[0] /* number of glyphs to go back to attach this glyph to its base */
       
    40 #define cursive_chain() var.i16[1] /* character to which this connects, may be positive or negative */
       
    41 
       
    42 
       
    43 /* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
       
    44 
       
    45 typedef USHORT Value;
       
    46 
       
    47 typedef Value ValueRecord[VAR];
       
    48 
       
    49 struct ValueFormat : USHORT
       
    50 {
       
    51   enum Flags {
       
    52     xPlacement  = 0x0001u,      /* Includes horizontal adjustment for placement */
       
    53     yPlacement  = 0x0002u,      /* Includes vertical adjustment for placement */
       
    54     xAdvance    = 0x0004u,      /* Includes horizontal adjustment for advance */
       
    55     yAdvance    = 0x0008u,      /* Includes vertical adjustment for advance */
       
    56     xPlaDevice  = 0x0010u,      /* Includes horizontal Device table for placement */
       
    57     yPlaDevice  = 0x0020u,      /* Includes vertical Device table for placement */
       
    58     xAdvDevice  = 0x0040u,      /* Includes horizontal Device table for advance */
       
    59     yAdvDevice  = 0x0080u,      /* Includes vertical Device table for advance */
       
    60     ignored     = 0x0F00u,      /* Was used in TrueType Open for MM fonts */
       
    61     reserved    = 0xF000u,      /* For future use */
       
    62 
       
    63     devices     = 0x00F0u       /* Mask for having any Device table */
       
    64   };
       
    65 
       
    66 /* All fields are options.  Only those available advance the value pointer. */
       
    67 #if 0
       
    68   SHORT         xPlacement;             /* Horizontal adjustment for
       
    69                                          * placement--in design units */
       
    70   SHORT         yPlacement;             /* Vertical adjustment for
       
    71                                          * placement--in design units */
       
    72   SHORT         xAdvance;               /* Horizontal adjustment for
       
    73                                          * advance--in design units (only used
       
    74                                          * for horizontal writing) */
       
    75   SHORT         yAdvance;               /* Vertical adjustment for advance--in
       
    76                                          * design units (only used for vertical
       
    77                                          * writing) */
       
    78   Offset        xPlaDevice;             /* Offset to Device table for
       
    79                                          * horizontal placement--measured from
       
    80                                          * beginning of PosTable (may be NULL) */
       
    81   Offset        yPlaDevice;             /* Offset to Device table for vertical
       
    82                                          * placement--measured from beginning
       
    83                                          * of PosTable (may be NULL) */
       
    84   Offset        xAdvDevice;             /* Offset to Device table for
       
    85                                          * horizontal advance--measured from
       
    86                                          * beginning of PosTable (may be NULL) */
       
    87   Offset        yAdvDevice;             /* Offset to Device table for vertical
       
    88                                          * advance--measured from beginning of
       
    89                                          * PosTable (may be NULL) */
       
    90 #endif
       
    91 
       
    92   inline unsigned int get_len (void) const
       
    93   { return _hb_popcount32 ((unsigned int) *this); }
       
    94   inline unsigned int get_size (void) const
       
    95   { return get_len () * Value::static_size; }
       
    96 
       
    97   void apply_value (hb_font_t            *font,
       
    98                     hb_direction_t        direction,
       
    99                     const void           *base,
       
   100                     const Value          *values,
       
   101                     hb_glyph_position_t  &glyph_pos) const
       
   102   {
       
   103     unsigned int x_ppem, y_ppem;
       
   104     unsigned int format = *this;
       
   105     hb_bool_t horizontal = HB_DIRECTION_IS_HORIZONTAL (direction);
       
   106 
       
   107     if (!format) return;
       
   108 
       
   109     if (format & xPlacement) glyph_pos.x_offset  += font->em_scale_x (get_short (values++));
       
   110     if (format & yPlacement) glyph_pos.y_offset  += font->em_scale_y (get_short (values++));
       
   111     if (format & xAdvance) {
       
   112       if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values));
       
   113       values++;
       
   114     }
       
   115     /* y_advance values grow downward but font-space grows upward, hence negation */
       
   116     if (format & yAdvance) {
       
   117       if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values));
       
   118       values++;
       
   119     }
       
   120 
       
   121     if (!has_device ()) return;
       
   122 
       
   123     x_ppem = font->x_ppem;
       
   124     y_ppem = font->y_ppem;
       
   125 
       
   126     if (!x_ppem && !y_ppem) return;
       
   127 
       
   128     /* pixel -> fractional pixel */
       
   129     if (format & xPlaDevice) {
       
   130       if (x_ppem) glyph_pos.x_offset  += (base + get_device (values)).get_x_delta (font);
       
   131       values++;
       
   132     }
       
   133     if (format & yPlaDevice) {
       
   134       if (y_ppem) glyph_pos.y_offset  += (base + get_device (values)).get_y_delta (font);
       
   135       values++;
       
   136     }
       
   137     if (format & xAdvDevice) {
       
   138       if (horizontal && x_ppem) glyph_pos.x_advance += (base + get_device (values)).get_x_delta (font);
       
   139       values++;
       
   140     }
       
   141     if (format & yAdvDevice) {
       
   142       /* y_advance values grow downward but font-space grows upward, hence negation */
       
   143       if (!horizontal && y_ppem) glyph_pos.y_advance -= (base + get_device (values)).get_y_delta (font);
       
   144       values++;
       
   145     }
       
   146   }
       
   147 
       
   148   private:
       
   149   inline bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
       
   150   {
       
   151     unsigned int format = *this;
       
   152 
       
   153     if (format & xPlacement) values++;
       
   154     if (format & yPlacement) values++;
       
   155     if (format & xAdvance)   values++;
       
   156     if (format & yAdvance)   values++;
       
   157 
       
   158     if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
       
   159     if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
       
   160     if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
       
   161     if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
       
   162 
       
   163     return true;
       
   164   }
       
   165 
       
   166   static inline OffsetTo<Device>& get_device (Value* value)
       
   167   { return *CastP<OffsetTo<Device> > (value); }
       
   168   static inline const OffsetTo<Device>& get_device (const Value* value)
       
   169   { return *CastP<OffsetTo<Device> > (value); }
       
   170 
       
   171   static inline const SHORT& get_short (const Value* value)
       
   172   { return *CastP<SHORT> (value); }
       
   173 
       
   174   public:
       
   175 
       
   176   inline bool has_device (void) const {
       
   177     unsigned int format = *this;
       
   178     return (format & devices) != 0;
       
   179   }
       
   180 
       
   181   inline bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
       
   182   {
       
   183     TRACE_SANITIZE (this);
       
   184     return_trace (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
       
   185   }
       
   186 
       
   187   inline bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
       
   188   {
       
   189     TRACE_SANITIZE (this);
       
   190     unsigned int len = get_len ();
       
   191 
       
   192     if (!c->check_array (values, get_size (), count)) return_trace (false);
       
   193 
       
   194     if (!has_device ()) return_trace (true);
       
   195 
       
   196     for (unsigned int i = 0; i < count; i++) {
       
   197       if (!sanitize_value_devices (c, base, values))
       
   198         return_trace (false);
       
   199       values += len;
       
   200     }
       
   201 
       
   202     return_trace (true);
       
   203   }
       
   204 
       
   205   /* Just sanitize referenced Device tables.  Doesn't check the values themselves. */
       
   206   inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const
       
   207   {
       
   208     TRACE_SANITIZE (this);
       
   209 
       
   210     if (!has_device ()) return_trace (true);
       
   211 
       
   212     for (unsigned int i = 0; i < count; i++) {
       
   213       if (!sanitize_value_devices (c, base, values))
       
   214         return_trace (false);
       
   215       values += stride;
       
   216     }
       
   217 
       
   218     return_trace (true);
       
   219   }
       
   220 };
       
   221 
       
   222 
       
   223 struct AnchorFormat1
       
   224 {
       
   225   inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
       
   226                           hb_position_t *x, hb_position_t *y) const
       
   227   {
       
   228       *x = font->em_scale_x (xCoordinate);
       
   229       *y = font->em_scale_y (yCoordinate);
       
   230   }
       
   231 
       
   232   inline bool sanitize (hb_sanitize_context_t *c) const
       
   233   {
       
   234     TRACE_SANITIZE (this);
       
   235     return_trace (c->check_struct (this));
       
   236   }
       
   237 
       
   238   protected:
       
   239   USHORT        format;                 /* Format identifier--format = 1 */
       
   240   SHORT         xCoordinate;            /* Horizontal value--in design units */
       
   241   SHORT         yCoordinate;            /* Vertical value--in design units */
       
   242   public:
       
   243   DEFINE_SIZE_STATIC (6);
       
   244 };
       
   245 
       
   246 struct AnchorFormat2
       
   247 {
       
   248   inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
       
   249                           hb_position_t *x, hb_position_t *y) const
       
   250   {
       
   251       unsigned int x_ppem = font->x_ppem;
       
   252       unsigned int y_ppem = font->y_ppem;
       
   253       hb_position_t cx, cy;
       
   254       hb_bool_t ret;
       
   255 
       
   256       ret = (x_ppem || y_ppem) &&
       
   257              font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
       
   258       *x = ret && x_ppem ? cx : font->em_scale_x (xCoordinate);
       
   259       *y = ret && y_ppem ? cy : font->em_scale_y (yCoordinate);
       
   260   }
       
   261 
       
   262   inline bool sanitize (hb_sanitize_context_t *c) const
       
   263   {
       
   264     TRACE_SANITIZE (this);
       
   265     return_trace (c->check_struct (this));
       
   266   }
       
   267 
       
   268   protected:
       
   269   USHORT        format;                 /* Format identifier--format = 2 */
       
   270   SHORT         xCoordinate;            /* Horizontal value--in design units */
       
   271   SHORT         yCoordinate;            /* Vertical value--in design units */
       
   272   USHORT        anchorPoint;            /* Index to glyph contour point */
       
   273   public:
       
   274   DEFINE_SIZE_STATIC (8);
       
   275 };
       
   276 
       
   277 struct AnchorFormat3
       
   278 {
       
   279   inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
       
   280                           hb_position_t *x, hb_position_t *y) const
       
   281   {
       
   282       *x = font->em_scale_x (xCoordinate);
       
   283       *y = font->em_scale_y (yCoordinate);
       
   284 
       
   285       if (font->x_ppem)
       
   286         *x += (this+xDeviceTable).get_x_delta (font);
       
   287       if (font->y_ppem)
       
   288         *y += (this+yDeviceTable).get_x_delta (font);
       
   289   }
       
   290 
       
   291   inline bool sanitize (hb_sanitize_context_t *c) const
       
   292   {
       
   293     TRACE_SANITIZE (this);
       
   294     return_trace (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
       
   295   }
       
   296 
       
   297   protected:
       
   298   USHORT        format;                 /* Format identifier--format = 3 */
       
   299   SHORT         xCoordinate;            /* Horizontal value--in design units */
       
   300   SHORT         yCoordinate;            /* Vertical value--in design units */
       
   301   OffsetTo<Device>
       
   302                 xDeviceTable;           /* Offset to Device table for X
       
   303                                          * coordinate-- from beginning of
       
   304                                          * Anchor table (may be NULL) */
       
   305   OffsetTo<Device>
       
   306                 yDeviceTable;           /* Offset to Device table for Y
       
   307                                          * coordinate-- from beginning of
       
   308                                          * Anchor table (may be NULL) */
       
   309   public:
       
   310   DEFINE_SIZE_STATIC (10);
       
   311 };
       
   312 
       
   313 struct Anchor
       
   314 {
       
   315   inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
       
   316                           hb_position_t *x, hb_position_t *y) const
       
   317   {
       
   318     *x = *y = 0;
       
   319     switch (u.format) {
       
   320     case 1: u.format1.get_anchor (font, glyph_id, x, y); return;
       
   321     case 2: u.format2.get_anchor (font, glyph_id, x, y); return;
       
   322     case 3: u.format3.get_anchor (font, glyph_id, x, y); return;
       
   323     default:                                             return;
       
   324     }
       
   325   }
       
   326 
       
   327   inline bool sanitize (hb_sanitize_context_t *c) const
       
   328   {
       
   329     TRACE_SANITIZE (this);
       
   330     if (!u.format.sanitize (c)) return_trace (false);
       
   331     switch (u.format) {
       
   332     case 1: return_trace (u.format1.sanitize (c));
       
   333     case 2: return_trace (u.format2.sanitize (c));
       
   334     case 3: return_trace (u.format3.sanitize (c));
       
   335     default:return_trace (true);
       
   336     }
       
   337   }
       
   338 
       
   339   protected:
       
   340   union {
       
   341   USHORT                format;         /* Format identifier */
       
   342   AnchorFormat1         format1;
       
   343   AnchorFormat2         format2;
       
   344   AnchorFormat3         format3;
       
   345   } u;
       
   346   public:
       
   347   DEFINE_SIZE_UNION (2, format);
       
   348 };
       
   349 
       
   350 
       
   351 struct AnchorMatrix
       
   352 {
       
   353   inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols, bool *found) const {
       
   354     *found = false;
       
   355     if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
       
   356     *found = !matrixZ[row * cols + col].is_null ();
       
   357     return this+matrixZ[row * cols + col];
       
   358   }
       
   359 
       
   360   inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const
       
   361   {
       
   362     TRACE_SANITIZE (this);
       
   363     if (!c->check_struct (this)) return_trace (false);
       
   364     if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return_trace (false);
       
   365     unsigned int count = rows * cols;
       
   366     if (!c->check_array (matrixZ, matrixZ[0].static_size, count)) return_trace (false);
       
   367     for (unsigned int i = 0; i < count; i++)
       
   368       if (!matrixZ[i].sanitize (c, this)) return_trace (false);
       
   369     return_trace (true);
       
   370   }
       
   371 
       
   372   USHORT        rows;                   /* Number of rows */
       
   373   protected:
       
   374   OffsetTo<Anchor>
       
   375                 matrixZ[VAR];           /* Matrix of offsets to Anchor tables--
       
   376                                          * from beginning of AnchorMatrix table */
       
   377   public:
       
   378   DEFINE_SIZE_ARRAY (2, matrixZ);
       
   379 };
       
   380 
       
   381 
       
   382 struct MarkRecord
       
   383 {
       
   384   friend struct MarkArray;
       
   385 
       
   386   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
       
   387   {
       
   388     TRACE_SANITIZE (this);
       
   389     return_trace (c->check_struct (this) && markAnchor.sanitize (c, base));
       
   390   }
       
   391 
       
   392   protected:
       
   393   USHORT        klass;                  /* Class defined for this mark */
       
   394   OffsetTo<Anchor>
       
   395                 markAnchor;             /* Offset to Anchor table--from
       
   396                                          * beginning of MarkArray table */
       
   397   public:
       
   398   DEFINE_SIZE_STATIC (4);
       
   399 };
       
   400 
       
   401 struct MarkArray : ArrayOf<MarkRecord>  /* Array of MarkRecords--in Coverage order */
       
   402 {
       
   403   inline bool apply (hb_apply_context_t *c,
       
   404                      unsigned int mark_index, unsigned int glyph_index,
       
   405                      const AnchorMatrix &anchors, unsigned int class_count,
       
   406                      unsigned int glyph_pos) const
       
   407   {
       
   408     TRACE_APPLY (this);
       
   409     hb_buffer_t *buffer = c->buffer;
       
   410     const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
       
   411     unsigned int mark_class = record.klass;
       
   412 
       
   413     const Anchor& mark_anchor = this + record.markAnchor;
       
   414     bool found;
       
   415     const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
       
   416     /* If this subtable doesn't have an anchor for this base and this class,
       
   417      * return false such that the subsequent subtables have a chance at it. */
       
   418     if (unlikely (!found)) return_trace (false);
       
   419 
       
   420     hb_position_t mark_x, mark_y, base_x, base_y;
       
   421 
       
   422     mark_anchor.get_anchor (c->font, buffer->cur().codepoint, &mark_x, &mark_y);
       
   423     glyph_anchor.get_anchor (c->font, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
       
   424 
       
   425     hb_glyph_position_t &o = buffer->cur_pos();
       
   426     o.x_offset = base_x - mark_x;
       
   427     o.y_offset = base_y - mark_y;
       
   428     o.attach_lookback() = buffer->idx - glyph_pos;
       
   429 
       
   430     buffer->idx++;
       
   431     return_trace (true);
       
   432   }
       
   433 
       
   434   inline bool sanitize (hb_sanitize_context_t *c) const
       
   435   {
       
   436     TRACE_SANITIZE (this);
       
   437     return_trace (ArrayOf<MarkRecord>::sanitize (c, this));
       
   438   }
       
   439 };
       
   440 
       
   441 
       
   442 /* Lookups */
       
   443 
       
   444 struct SinglePosFormat1
       
   445 {
       
   446   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
       
   447   {
       
   448     TRACE_COLLECT_GLYPHS (this);
       
   449     (this+coverage).add_coverage (c->input);
       
   450   }
       
   451 
       
   452   inline const Coverage &get_coverage (void) const
       
   453   {
       
   454     return this+coverage;
       
   455   }
       
   456 
       
   457   inline bool apply (hb_apply_context_t *c) const
       
   458   {
       
   459     TRACE_APPLY (this);
       
   460     hb_buffer_t *buffer = c->buffer;
       
   461     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
       
   462     if (likely (index == NOT_COVERED)) return_trace (false);
       
   463 
       
   464     valueFormat.apply_value (c->font, c->direction, this,
       
   465                              values, buffer->cur_pos());
       
   466 
       
   467     buffer->idx++;
       
   468     return_trace (true);
       
   469   }
       
   470 
       
   471   inline bool sanitize (hb_sanitize_context_t *c) const
       
   472   {
       
   473     TRACE_SANITIZE (this);
       
   474     return_trace (c->check_struct (this) &&
       
   475                   coverage.sanitize (c, this) &&
       
   476                   valueFormat.sanitize_value (c, this, values));
       
   477   }
       
   478 
       
   479   protected:
       
   480   USHORT        format;                 /* Format identifier--format = 1 */
       
   481   OffsetTo<Coverage>
       
   482                 coverage;               /* Offset to Coverage table--from
       
   483                                          * beginning of subtable */
       
   484   ValueFormat   valueFormat;            /* Defines the types of data in the
       
   485                                          * ValueRecord */
       
   486   ValueRecord   values;                 /* Defines positioning
       
   487                                          * value(s)--applied to all glyphs in
       
   488                                          * the Coverage table */
       
   489   public:
       
   490   DEFINE_SIZE_ARRAY (6, values);
       
   491 };
       
   492 
       
   493 struct SinglePosFormat2
       
   494 {
       
   495   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
       
   496   {
       
   497     TRACE_COLLECT_GLYPHS (this);
       
   498     (this+coverage).add_coverage (c->input);
       
   499   }
       
   500 
       
   501   inline const Coverage &get_coverage (void) const
       
   502   {
       
   503     return this+coverage;
       
   504   }
       
   505 
       
   506   inline bool apply (hb_apply_context_t *c) const
       
   507   {
       
   508     TRACE_APPLY (this);
       
   509     hb_buffer_t *buffer = c->buffer;
       
   510     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
       
   511     if (likely (index == NOT_COVERED)) return_trace (false);
       
   512 
       
   513     if (likely (index >= valueCount)) return_trace (false);
       
   514 
       
   515     valueFormat.apply_value (c->font, c->direction, this,
       
   516                              &values[index * valueFormat.get_len ()],
       
   517                              buffer->cur_pos());
       
   518 
       
   519     buffer->idx++;
       
   520     return_trace (true);
       
   521   }
       
   522 
       
   523   inline bool sanitize (hb_sanitize_context_t *c) const
       
   524   {
       
   525     TRACE_SANITIZE (this);
       
   526     return_trace (c->check_struct (this) &&
       
   527                   coverage.sanitize (c, this) &&
       
   528                   valueFormat.sanitize_values (c, this, values, valueCount));
       
   529   }
       
   530 
       
   531   protected:
       
   532   USHORT        format;                 /* Format identifier--format = 2 */
       
   533   OffsetTo<Coverage>
       
   534                 coverage;               /* Offset to Coverage table--from
       
   535                                          * beginning of subtable */
       
   536   ValueFormat   valueFormat;            /* Defines the types of data in the
       
   537                                          * ValueRecord */
       
   538   USHORT        valueCount;             /* Number of ValueRecords */
       
   539   ValueRecord   values;                 /* Array of ValueRecords--positioning
       
   540                                          * values applied to glyphs */
       
   541   public:
       
   542   DEFINE_SIZE_ARRAY (8, values);
       
   543 };
       
   544 
       
   545 struct SinglePos
       
   546 {
       
   547   template <typename context_t>
       
   548   inline typename context_t::return_t dispatch (context_t *c) const
       
   549   {
       
   550     TRACE_DISPATCH (this, u.format);
       
   551     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
       
   552     switch (u.format) {
       
   553     case 1: return_trace (c->dispatch (u.format1));
       
   554     case 2: return_trace (c->dispatch (u.format2));
       
   555     default:return_trace (c->default_return_value ());
       
   556     }
       
   557   }
       
   558 
       
   559   protected:
       
   560   union {
       
   561   USHORT                format;         /* Format identifier */
       
   562   SinglePosFormat1      format1;
       
   563   SinglePosFormat2      format2;
       
   564   } u;
       
   565 };
       
   566 
       
   567 
       
   568 struct PairValueRecord
       
   569 {
       
   570   friend struct PairSet;
       
   571 
       
   572   protected:
       
   573   GlyphID       secondGlyph;            /* GlyphID of second glyph in the
       
   574                                          * pair--first glyph is listed in the
       
   575                                          * Coverage table */
       
   576   ValueRecord   values;                 /* Positioning data for the first glyph
       
   577                                          * followed by for second glyph */
       
   578   public:
       
   579   DEFINE_SIZE_ARRAY (2, values);
       
   580 };
       
   581 
       
   582 struct PairSet
       
   583 {
       
   584   friend struct PairPosFormat1;
       
   585 
       
   586   inline void collect_glyphs (hb_collect_glyphs_context_t *c,
       
   587                               const ValueFormat *valueFormats) const
       
   588   {
       
   589     TRACE_COLLECT_GLYPHS (this);
       
   590     unsigned int len1 = valueFormats[0].get_len ();
       
   591     unsigned int len2 = valueFormats[1].get_len ();
       
   592     unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
       
   593 
       
   594     const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
       
   595     unsigned int count = len;
       
   596     for (unsigned int i = 0; i < count; i++)
       
   597     {
       
   598       c->input->add (record->secondGlyph);
       
   599       record = &StructAtOffset<PairValueRecord> (record, record_size);
       
   600     }
       
   601   }
       
   602 
       
   603   inline bool apply (hb_apply_context_t *c,
       
   604                      const ValueFormat *valueFormats,
       
   605                      unsigned int pos) const
       
   606   {
       
   607     TRACE_APPLY (this);
       
   608     hb_buffer_t *buffer = c->buffer;
       
   609     unsigned int len1 = valueFormats[0].get_len ();
       
   610     unsigned int len2 = valueFormats[1].get_len ();
       
   611     unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
       
   612 
       
   613     const PairValueRecord *record_array = CastP<PairValueRecord> (arrayZ);
       
   614     unsigned int count = len;
       
   615 
       
   616     /* Hand-coded bsearch. */
       
   617     if (unlikely (!count))
       
   618       return_trace (false);
       
   619     hb_codepoint_t x = buffer->info[pos].codepoint;
       
   620     int min = 0, max = (int) count - 1;
       
   621     while (min <= max)
       
   622     {
       
   623       int mid = (min + max) / 2;
       
   624       const PairValueRecord *record = &StructAtOffset<PairValueRecord> (record_array, record_size * mid);
       
   625       hb_codepoint_t mid_x = record->secondGlyph;
       
   626       if (x < mid_x)
       
   627         max = mid - 1;
       
   628       else if (x > mid_x)
       
   629         min = mid + 1;
       
   630       else
       
   631       {
       
   632         valueFormats[0].apply_value (c->font, c->direction, this,
       
   633                                      &record->values[0], buffer->cur_pos());
       
   634         valueFormats[1].apply_value (c->font, c->direction, this,
       
   635                                      &record->values[len1], buffer->pos[pos]);
       
   636         if (len2)
       
   637           pos++;
       
   638         buffer->idx = pos;
       
   639         return_trace (true);
       
   640       }
       
   641     }
       
   642 
       
   643     return_trace (false);
       
   644   }
       
   645 
       
   646   struct sanitize_closure_t {
       
   647     const void *base;
       
   648     const ValueFormat *valueFormats;
       
   649     unsigned int len1; /* valueFormats[0].get_len() */
       
   650     unsigned int stride; /* 1 + len1 + len2 */
       
   651   };
       
   652 
       
   653   inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
       
   654   {
       
   655     TRACE_SANITIZE (this);
       
   656     if (!(c->check_struct (this)
       
   657        && c->check_array (arrayZ, USHORT::static_size * closure->stride, len))) return_trace (false);
       
   658 
       
   659     unsigned int count = len;
       
   660     const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
       
   661     return_trace (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride) &&
       
   662                   closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
       
   663   }
       
   664 
       
   665   protected:
       
   666   USHORT        len;                    /* Number of PairValueRecords */
       
   667   USHORT        arrayZ[VAR];            /* Array of PairValueRecords--ordered
       
   668                                          * by GlyphID of the second glyph */
       
   669   public:
       
   670   DEFINE_SIZE_ARRAY (2, arrayZ);
       
   671 };
       
   672 
       
   673 struct PairPosFormat1
       
   674 {
       
   675   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
       
   676   {
       
   677     TRACE_COLLECT_GLYPHS (this);
       
   678     (this+coverage).add_coverage (c->input);
       
   679     unsigned int count = pairSet.len;
       
   680     for (unsigned int i = 0; i < count; i++)
       
   681       (this+pairSet[i]).collect_glyphs (c, &valueFormat1);
       
   682   }
       
   683 
       
   684   inline const Coverage &get_coverage (void) const
       
   685   {
       
   686     return this+coverage;
       
   687   }
       
   688 
       
   689   inline bool apply (hb_apply_context_t *c) const
       
   690   {
       
   691     TRACE_APPLY (this);
       
   692     hb_buffer_t *buffer = c->buffer;
       
   693     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
       
   694     if (likely (index == NOT_COVERED)) return_trace (false);
       
   695 
       
   696     hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
       
   697     skippy_iter.reset (buffer->idx, 1);
       
   698     if (!skippy_iter.next ()) return_trace (false);
       
   699 
       
   700     return_trace ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx));
       
   701   }
       
   702 
       
   703   inline bool sanitize (hb_sanitize_context_t *c) const
       
   704   {
       
   705     TRACE_SANITIZE (this);
       
   706 
       
   707     if (!c->check_struct (this)) return_trace (false);
       
   708 
       
   709     unsigned int len1 = valueFormat1.get_len ();
       
   710     unsigned int len2 = valueFormat2.get_len ();
       
   711     PairSet::sanitize_closure_t closure = {
       
   712       this,
       
   713       &valueFormat1,
       
   714       len1,
       
   715       1 + len1 + len2
       
   716     };
       
   717 
       
   718     return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
       
   719   }
       
   720 
       
   721   protected:
       
   722   USHORT        format;                 /* Format identifier--format = 1 */
       
   723   OffsetTo<Coverage>
       
   724                 coverage;               /* Offset to Coverage table--from
       
   725                                          * beginning of subtable */
       
   726   ValueFormat   valueFormat1;           /* Defines the types of data in
       
   727                                          * ValueRecord1--for the first glyph
       
   728                                          * in the pair--may be zero (0) */
       
   729   ValueFormat   valueFormat2;           /* Defines the types of data in
       
   730                                          * ValueRecord2--for the second glyph
       
   731                                          * in the pair--may be zero (0) */
       
   732   OffsetArrayOf<PairSet>
       
   733                 pairSet;                /* Array of PairSet tables
       
   734                                          * ordered by Coverage Index */
       
   735   public:
       
   736   DEFINE_SIZE_ARRAY (10, pairSet);
       
   737 };
       
   738 
       
   739 struct PairPosFormat2
       
   740 {
       
   741   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
       
   742   {
       
   743     TRACE_COLLECT_GLYPHS (this);
       
   744     /* (this+coverage).add_coverage (c->input); // Don't need this. */
       
   745 
       
   746     unsigned int count1 = class1Count;
       
   747     const ClassDef &klass1 = this+classDef1;
       
   748     for (unsigned int i = 0; i < count1; i++)
       
   749       klass1.add_class (c->input, i);
       
   750 
       
   751     unsigned int count2 = class2Count;
       
   752     const ClassDef &klass2 = this+classDef2;
       
   753     for (unsigned int i = 0; i < count2; i++)
       
   754       klass2.add_class (c->input, i);
       
   755   }
       
   756 
       
   757   inline const Coverage &get_coverage (void) const
       
   758   {
       
   759     return this+coverage;
       
   760   }
       
   761 
       
   762   inline bool apply (hb_apply_context_t *c) const
       
   763   {
       
   764     TRACE_APPLY (this);
       
   765     hb_buffer_t *buffer = c->buffer;
       
   766     unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
       
   767     if (likely (index == NOT_COVERED)) return_trace (false);
       
   768 
       
   769     hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
       
   770     skippy_iter.reset (buffer->idx, 1);
       
   771     if (!skippy_iter.next ()) return_trace (false);
       
   772 
       
   773     unsigned int len1 = valueFormat1.get_len ();
       
   774     unsigned int len2 = valueFormat2.get_len ();
       
   775     unsigned int record_len = len1 + len2;
       
   776 
       
   777     unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
       
   778     unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
       
   779     if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return_trace (false);
       
   780 
       
   781     const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
       
   782     valueFormat1.apply_value (c->font, c->direction, this,
       
   783                               v, buffer->cur_pos());
       
   784     valueFormat2.apply_value (c->font, c->direction, this,
       
   785                               v + len1, buffer->pos[skippy_iter.idx]);
       
   786 
       
   787     buffer->idx = skippy_iter.idx;
       
   788     if (len2)
       
   789       buffer->idx++;
       
   790 
       
   791     return_trace (true);
       
   792   }
       
   793 
       
   794   inline bool sanitize (hb_sanitize_context_t *c) const
       
   795   {
       
   796     TRACE_SANITIZE (this);
       
   797     if (!(c->check_struct (this)
       
   798        && coverage.sanitize (c, this)
       
   799        && classDef1.sanitize (c, this)
       
   800        && classDef2.sanitize (c, this))) return_trace (false);
       
   801 
       
   802     unsigned int len1 = valueFormat1.get_len ();
       
   803     unsigned int len2 = valueFormat2.get_len ();
       
   804     unsigned int stride = len1 + len2;
       
   805     unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
       
   806     unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
       
   807     return_trace (c->check_array (values, record_size, count) &&
       
   808                   valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
       
   809                   valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
       
   810   }
       
   811 
       
   812   protected:
       
   813   USHORT        format;                 /* Format identifier--format = 2 */
       
   814   OffsetTo<Coverage>
       
   815                 coverage;               /* Offset to Coverage table--from
       
   816                                          * beginning of subtable */
       
   817   ValueFormat   valueFormat1;           /* ValueRecord definition--for the
       
   818                                          * first glyph of the pair--may be zero
       
   819                                          * (0) */
       
   820   ValueFormat   valueFormat2;           /* ValueRecord definition--for the
       
   821                                          * second glyph of the pair--may be
       
   822                                          * zero (0) */
       
   823   OffsetTo<ClassDef>
       
   824                 classDef1;              /* Offset to ClassDef table--from
       
   825                                          * beginning of PairPos subtable--for
       
   826                                          * the first glyph of the pair */
       
   827   OffsetTo<ClassDef>
       
   828                 classDef2;              /* Offset to ClassDef table--from
       
   829                                          * beginning of PairPos subtable--for
       
   830                                          * the second glyph of the pair */
       
   831   USHORT        class1Count;            /* Number of classes in ClassDef1
       
   832                                          * table--includes Class0 */
       
   833   USHORT        class2Count;            /* Number of classes in ClassDef2
       
   834                                          * table--includes Class0 */
       
   835   ValueRecord   values;                 /* Matrix of value pairs:
       
   836                                          * class1-major, class2-minor,
       
   837                                          * Each entry has value1 and value2 */
       
   838   public:
       
   839   DEFINE_SIZE_ARRAY (16, values);
       
   840 };
       
   841 
       
   842 struct PairPos
       
   843 {
       
   844   template <typename context_t>
       
   845   inline typename context_t::return_t dispatch (context_t *c) const
       
   846   {
       
   847     TRACE_DISPATCH (this, u.format);
       
   848     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
       
   849     switch (u.format) {
       
   850     case 1: return_trace (c->dispatch (u.format1));
       
   851     case 2: return_trace (c->dispatch (u.format2));
       
   852     default:return_trace (c->default_return_value ());
       
   853     }
       
   854   }
       
   855 
       
   856   protected:
       
   857   union {
       
   858   USHORT                format;         /* Format identifier */
       
   859   PairPosFormat1        format1;
       
   860   PairPosFormat2        format2;
       
   861   } u;
       
   862 };
       
   863 
       
   864 
       
   865 struct EntryExitRecord
       
   866 {
       
   867   friend struct CursivePosFormat1;
       
   868 
       
   869   inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
       
   870   {
       
   871     TRACE_SANITIZE (this);
       
   872     return_trace (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
       
   873   }
       
   874 
       
   875   protected:
       
   876   OffsetTo<Anchor>
       
   877                 entryAnchor;            /* Offset to EntryAnchor table--from
       
   878                                          * beginning of CursivePos
       
   879                                          * subtable--may be NULL */
       
   880   OffsetTo<Anchor>
       
   881                 exitAnchor;             /* Offset to ExitAnchor table--from
       
   882                                          * beginning of CursivePos
       
   883                                          * subtable--may be NULL */
       
   884   public:
       
   885   DEFINE_SIZE_STATIC (4);
       
   886 };
       
   887 
       
   888 static void
       
   889 reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent);
       
   890 
       
   891 struct CursivePosFormat1
       
   892 {
       
   893   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
       
   894   {
       
   895     TRACE_COLLECT_GLYPHS (this);
       
   896     (this+coverage).add_coverage (c->input);
       
   897   }
       
   898 
       
   899   inline const Coverage &get_coverage (void) const
       
   900   {
       
   901     return this+coverage;
       
   902   }
       
   903 
       
   904   inline bool apply (hb_apply_context_t *c) const
       
   905   {
       
   906     TRACE_APPLY (this);
       
   907     hb_buffer_t *buffer = c->buffer;
       
   908 
       
   909     /* We don't handle mark glyphs here. */
       
   910     if (unlikely (_hb_glyph_info_is_mark (&buffer->cur()))) return_trace (false);
       
   911 
       
   912     const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (buffer->cur().codepoint)];
       
   913     if (!this_record.exitAnchor) return_trace (false);
       
   914 
       
   915     hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
       
   916     skippy_iter.reset (buffer->idx, 1);
       
   917     if (!skippy_iter.next ()) return_trace (false);
       
   918 
       
   919     const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint)];
       
   920     if (!next_record.entryAnchor) return_trace (false);
       
   921 
       
   922     unsigned int i = buffer->idx;
       
   923     unsigned int j = skippy_iter.idx;
       
   924 
       
   925     hb_position_t entry_x, entry_y, exit_x, exit_y;
       
   926     (this+this_record.exitAnchor).get_anchor (c->font, buffer->info[i].codepoint, &exit_x, &exit_y);
       
   927     (this+next_record.entryAnchor).get_anchor (c->font, buffer->info[j].codepoint, &entry_x, &entry_y);
       
   928 
       
   929     hb_glyph_position_t *pos = buffer->pos;
       
   930 
       
   931     hb_position_t d;
       
   932     /* Main-direction adjustment */
       
   933     switch (c->direction) {
       
   934       case HB_DIRECTION_LTR:
       
   935         pos[i].x_advance  =  exit_x + pos[i].x_offset;
       
   936 
       
   937         d = entry_x + pos[j].x_offset;
       
   938         pos[j].x_advance -= d;
       
   939         pos[j].x_offset  -= d;
       
   940         break;
       
   941       case HB_DIRECTION_RTL:
       
   942         d = exit_x + pos[i].x_offset;
       
   943         pos[i].x_advance -= d;
       
   944         pos[i].x_offset  -= d;
       
   945 
       
   946         pos[j].x_advance  =  entry_x + pos[j].x_offset;
       
   947         break;
       
   948       case HB_DIRECTION_TTB:
       
   949         pos[i].y_advance  =  exit_y + pos[i].y_offset;
       
   950 
       
   951         d = entry_y + pos[j].y_offset;
       
   952         pos[j].y_advance -= d;
       
   953         pos[j].y_offset  -= d;
       
   954         break;
       
   955       case HB_DIRECTION_BTT:
       
   956         d = exit_y + pos[i].y_offset;
       
   957         pos[i].y_advance -= d;
       
   958         pos[i].y_offset  -= d;
       
   959 
       
   960         pos[j].y_advance  =  entry_y;
       
   961         break;
       
   962       case HB_DIRECTION_INVALID:
       
   963       default:
       
   964         break;
       
   965     }
       
   966 
       
   967     /* Cross-direction adjustment */
       
   968 
       
   969     /* We attach child to parent (think graph theory and rooted trees whereas
       
   970      * the root stays on baseline and each node aligns itself against its
       
   971      * parent.
       
   972      *
       
   973      * Optimize things for the case of RightToLeft, as that's most common in
       
   974      * Arabinc. */
       
   975     unsigned int child  = i;
       
   976     unsigned int parent = j;
       
   977     hb_position_t x_offset = entry_x - exit_x;
       
   978     hb_position_t y_offset = entry_y - exit_y;
       
   979     if  (!(c->lookup_props & LookupFlag::RightToLeft))
       
   980     {
       
   981       unsigned int k = child;
       
   982       child = parent;
       
   983       parent = k;
       
   984       x_offset = -x_offset;
       
   985       y_offset = -y_offset;
       
   986     }
       
   987 
       
   988     /* If child was already connected to someone else, walk through its old
       
   989      * chain and reverse the link direction, such that the whole tree of its
       
   990      * previous connection now attaches to new parent.  Watch out for case
       
   991      * where new parent is on the path from old chain...
       
   992      */
       
   993     reverse_cursive_minor_offset (pos, child, c->direction, parent);
       
   994 
       
   995     pos[child].cursive_chain() = parent - child;
       
   996     if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
       
   997       pos[child].y_offset = y_offset;
       
   998     else
       
   999       pos[child].x_offset = x_offset;
       
  1000 
       
  1001     buffer->idx = j;
       
  1002     return_trace (true);
       
  1003   }
       
  1004 
       
  1005   inline bool sanitize (hb_sanitize_context_t *c) const
       
  1006   {
       
  1007     TRACE_SANITIZE (this);
       
  1008     return_trace (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
       
  1009   }
       
  1010 
       
  1011   protected:
       
  1012   USHORT        format;                 /* Format identifier--format = 1 */
       
  1013   OffsetTo<Coverage>
       
  1014                 coverage;               /* Offset to Coverage table--from
       
  1015                                          * beginning of subtable */
       
  1016   ArrayOf<EntryExitRecord>
       
  1017                 entryExitRecord;        /* Array of EntryExit records--in
       
  1018                                          * Coverage Index order */
       
  1019   public:
       
  1020   DEFINE_SIZE_ARRAY (6, entryExitRecord);
       
  1021 };
       
  1022 
       
  1023 struct CursivePos
       
  1024 {
       
  1025   template <typename context_t>
       
  1026   inline typename context_t::return_t dispatch (context_t *c) const
       
  1027   {
       
  1028     TRACE_DISPATCH (this, u.format);
       
  1029     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
       
  1030     switch (u.format) {
       
  1031     case 1: return_trace (c->dispatch (u.format1));
       
  1032     default:return_trace (c->default_return_value ());
       
  1033     }
       
  1034   }
       
  1035 
       
  1036   protected:
       
  1037   union {
       
  1038   USHORT                format;         /* Format identifier */
       
  1039   CursivePosFormat1     format1;
       
  1040   } u;
       
  1041 };
       
  1042 
       
  1043 
       
  1044 typedef AnchorMatrix BaseArray;         /* base-major--
       
  1045                                          * in order of BaseCoverage Index--,
       
  1046                                          * mark-minor--
       
  1047                                          * ordered by class--zero-based. */
       
  1048 
       
  1049 struct MarkBasePosFormat1
       
  1050 {
       
  1051   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
       
  1052   {
       
  1053     TRACE_COLLECT_GLYPHS (this);
       
  1054     (this+markCoverage).add_coverage (c->input);
       
  1055     (this+baseCoverage).add_coverage (c->input);
       
  1056   }
       
  1057 
       
  1058   inline const Coverage &get_coverage (void) const
       
  1059   {
       
  1060     return this+markCoverage;
       
  1061   }
       
  1062 
       
  1063   inline bool apply (hb_apply_context_t *c) const
       
  1064   {
       
  1065     TRACE_APPLY (this);
       
  1066     hb_buffer_t *buffer = c->buffer;
       
  1067     unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
       
  1068     if (likely (mark_index == NOT_COVERED)) return_trace (false);
       
  1069 
       
  1070     /* now we search backwards for a non-mark glyph */
       
  1071     hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
       
  1072     skippy_iter.reset (buffer->idx, 1);
       
  1073     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
       
  1074     do {
       
  1075       if (!skippy_iter.prev ()) return_trace (false);
       
  1076       /* We only want to attach to the first of a MultipleSubst sequence.  Reject others. */
       
  1077       if (0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx])) break;
       
  1078       skippy_iter.reject ();
       
  1079     } while (1);
       
  1080 
       
  1081     /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
       
  1082     if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { /*return_trace (false);*/ }
       
  1083 
       
  1084     unsigned int base_index = (this+baseCoverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint);
       
  1085     if (base_index == NOT_COVERED) return_trace (false);
       
  1086 
       
  1087     return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
       
  1088   }
       
  1089 
       
  1090   inline bool sanitize (hb_sanitize_context_t *c) const
       
  1091   {
       
  1092     TRACE_SANITIZE (this);
       
  1093     return_trace (c->check_struct (this) &&
       
  1094                   markCoverage.sanitize (c, this) &&
       
  1095                   baseCoverage.sanitize (c, this) &&
       
  1096                   markArray.sanitize (c, this) &&
       
  1097                   baseArray.sanitize (c, this, (unsigned int) classCount));
       
  1098   }
       
  1099 
       
  1100   protected:
       
  1101   USHORT        format;                 /* Format identifier--format = 1 */
       
  1102   OffsetTo<Coverage>
       
  1103                 markCoverage;           /* Offset to MarkCoverage table--from
       
  1104                                          * beginning of MarkBasePos subtable */
       
  1105   OffsetTo<Coverage>
       
  1106                 baseCoverage;           /* Offset to BaseCoverage table--from
       
  1107                                          * beginning of MarkBasePos subtable */
       
  1108   USHORT        classCount;             /* Number of classes defined for marks */
       
  1109   OffsetTo<MarkArray>
       
  1110                 markArray;              /* Offset to MarkArray table--from
       
  1111                                          * beginning of MarkBasePos subtable */
       
  1112   OffsetTo<BaseArray>
       
  1113                 baseArray;              /* Offset to BaseArray table--from
       
  1114                                          * beginning of MarkBasePos subtable */
       
  1115   public:
       
  1116   DEFINE_SIZE_STATIC (12);
       
  1117 };
       
  1118 
       
  1119 struct MarkBasePos
       
  1120 {
       
  1121   template <typename context_t>
       
  1122   inline typename context_t::return_t dispatch (context_t *c) const
       
  1123   {
       
  1124     TRACE_DISPATCH (this, u.format);
       
  1125     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
       
  1126     switch (u.format) {
       
  1127     case 1: return_trace (c->dispatch (u.format1));
       
  1128     default:return_trace (c->default_return_value ());
       
  1129     }
       
  1130   }
       
  1131 
       
  1132   protected:
       
  1133   union {
       
  1134   USHORT                format;         /* Format identifier */
       
  1135   MarkBasePosFormat1    format1;
       
  1136   } u;
       
  1137 };
       
  1138 
       
  1139 
       
  1140 typedef AnchorMatrix LigatureAttach;    /* component-major--
       
  1141                                          * in order of writing direction--,
       
  1142                                          * mark-minor--
       
  1143                                          * ordered by class--zero-based. */
       
  1144 
       
  1145 typedef OffsetListOf<LigatureAttach> LigatureArray;
       
  1146                                         /* Array of LigatureAttach
       
  1147                                          * tables ordered by
       
  1148                                          * LigatureCoverage Index */
       
  1149 
       
  1150 struct MarkLigPosFormat1
       
  1151 {
       
  1152   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
       
  1153   {
       
  1154     TRACE_COLLECT_GLYPHS (this);
       
  1155     (this+markCoverage).add_coverage (c->input);
       
  1156     (this+ligatureCoverage).add_coverage (c->input);
       
  1157   }
       
  1158 
       
  1159   inline const Coverage &get_coverage (void) const
       
  1160   {
       
  1161     return this+markCoverage;
       
  1162   }
       
  1163 
       
  1164   inline bool apply (hb_apply_context_t *c) const
       
  1165   {
       
  1166     TRACE_APPLY (this);
       
  1167     hb_buffer_t *buffer = c->buffer;
       
  1168     unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
       
  1169     if (likely (mark_index == NOT_COVERED)) return_trace (false);
       
  1170 
       
  1171     /* now we search backwards for a non-mark glyph */
       
  1172     hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
       
  1173     skippy_iter.reset (buffer->idx, 1);
       
  1174     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
       
  1175     if (!skippy_iter.prev ()) return_trace (false);
       
  1176 
       
  1177     /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
       
  1178     if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { /*return_trace (false);*/ }
       
  1179 
       
  1180     unsigned int j = skippy_iter.idx;
       
  1181     unsigned int lig_index = (this+ligatureCoverage).get_coverage  (buffer->info[j].codepoint);
       
  1182     if (lig_index == NOT_COVERED) return_trace (false);
       
  1183 
       
  1184     const LigatureArray& lig_array = this+ligatureArray;
       
  1185     const LigatureAttach& lig_attach = lig_array[lig_index];
       
  1186 
       
  1187     /* Find component to attach to */
       
  1188     unsigned int comp_count = lig_attach.rows;
       
  1189     if (unlikely (!comp_count)) return_trace (false);
       
  1190 
       
  1191     /* We must now check whether the ligature ID of the current mark glyph
       
  1192      * is identical to the ligature ID of the found ligature.  If yes, we
       
  1193      * can directly use the component index.  If not, we attach the mark
       
  1194      * glyph to the last component of the ligature. */
       
  1195     unsigned int comp_index;
       
  1196     unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]);
       
  1197     unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
       
  1198     unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
       
  1199     if (lig_id && lig_id == mark_id && mark_comp > 0)
       
  1200       comp_index = MIN (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
       
  1201     else
       
  1202       comp_index = comp_count - 1;
       
  1203 
       
  1204     return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
       
  1205   }
       
  1206 
       
  1207   inline bool sanitize (hb_sanitize_context_t *c) const
       
  1208   {
       
  1209     TRACE_SANITIZE (this);
       
  1210     return_trace (c->check_struct (this) &&
       
  1211                   markCoverage.sanitize (c, this) &&
       
  1212                   ligatureCoverage.sanitize (c, this) &&
       
  1213                   markArray.sanitize (c, this) &&
       
  1214                   ligatureArray.sanitize (c, this, (unsigned int) classCount));
       
  1215   }
       
  1216 
       
  1217   protected:
       
  1218   USHORT        format;                 /* Format identifier--format = 1 */
       
  1219   OffsetTo<Coverage>
       
  1220                 markCoverage;           /* Offset to Mark Coverage table--from
       
  1221                                          * beginning of MarkLigPos subtable */
       
  1222   OffsetTo<Coverage>
       
  1223                 ligatureCoverage;       /* Offset to Ligature Coverage
       
  1224                                          * table--from beginning of MarkLigPos
       
  1225                                          * subtable */
       
  1226   USHORT        classCount;             /* Number of defined mark classes */
       
  1227   OffsetTo<MarkArray>
       
  1228                 markArray;              /* Offset to MarkArray table--from
       
  1229                                          * beginning of MarkLigPos subtable */
       
  1230   OffsetTo<LigatureArray>
       
  1231                 ligatureArray;          /* Offset to LigatureArray table--from
       
  1232                                          * beginning of MarkLigPos subtable */
       
  1233   public:
       
  1234   DEFINE_SIZE_STATIC (12);
       
  1235 };
       
  1236 
       
  1237 struct MarkLigPos
       
  1238 {
       
  1239   template <typename context_t>
       
  1240   inline typename context_t::return_t dispatch (context_t *c) const
       
  1241   {
       
  1242     TRACE_DISPATCH (this, u.format);
       
  1243     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
       
  1244     switch (u.format) {
       
  1245     case 1: return_trace (c->dispatch (u.format1));
       
  1246     default:return_trace (c->default_return_value ());
       
  1247     }
       
  1248   }
       
  1249 
       
  1250   protected:
       
  1251   union {
       
  1252   USHORT                format;         /* Format identifier */
       
  1253   MarkLigPosFormat1     format1;
       
  1254   } u;
       
  1255 };
       
  1256 
       
  1257 
       
  1258 typedef AnchorMatrix Mark2Array;        /* mark2-major--
       
  1259                                          * in order of Mark2Coverage Index--,
       
  1260                                          * mark1-minor--
       
  1261                                          * ordered by class--zero-based. */
       
  1262 
       
  1263 struct MarkMarkPosFormat1
       
  1264 {
       
  1265   inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
       
  1266   {
       
  1267     TRACE_COLLECT_GLYPHS (this);
       
  1268     (this+mark1Coverage).add_coverage (c->input);
       
  1269     (this+mark2Coverage).add_coverage (c->input);
       
  1270   }
       
  1271 
       
  1272   inline const Coverage &get_coverage (void) const
       
  1273   {
       
  1274     return this+mark1Coverage;
       
  1275   }
       
  1276 
       
  1277   inline bool apply (hb_apply_context_t *c) const
       
  1278   {
       
  1279     TRACE_APPLY (this);
       
  1280     hb_buffer_t *buffer = c->buffer;
       
  1281     unsigned int mark1_index = (this+mark1Coverage).get_coverage  (buffer->cur().codepoint);
       
  1282     if (likely (mark1_index == NOT_COVERED)) return_trace (false);
       
  1283 
       
  1284     /* now we search backwards for a suitable mark glyph until a non-mark glyph */
       
  1285     hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
       
  1286     skippy_iter.reset (buffer->idx, 1);
       
  1287     skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
       
  1288     if (!skippy_iter.prev ()) return_trace (false);
       
  1289 
       
  1290     if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return_trace (false); }
       
  1291 
       
  1292     unsigned int j = skippy_iter.idx;
       
  1293 
       
  1294     unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur());
       
  1295     unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]);
       
  1296     unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur());
       
  1297     unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]);
       
  1298 
       
  1299     if (likely (id1 == id2)) {
       
  1300       if (id1 == 0) /* Marks belonging to the same base. */
       
  1301         goto good;
       
  1302       else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
       
  1303         goto good;
       
  1304     } else {
       
  1305       /* If ligature ids don't match, it may be the case that one of the marks
       
  1306        * itself is a ligature.  In which case match. */
       
  1307       if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
       
  1308         goto good;
       
  1309     }
       
  1310 
       
  1311     /* Didn't match. */
       
  1312     return_trace (false);
       
  1313 
       
  1314     good:
       
  1315     unsigned int mark2_index = (this+mark2Coverage).get_coverage  (buffer->info[j].codepoint);
       
  1316     if (mark2_index == NOT_COVERED) return_trace (false);
       
  1317 
       
  1318     return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
       
  1319   }
       
  1320 
       
  1321   inline bool sanitize (hb_sanitize_context_t *c) const
       
  1322   {
       
  1323     TRACE_SANITIZE (this);
       
  1324     return_trace (c->check_struct (this) &&
       
  1325                   mark1Coverage.sanitize (c, this) &&
       
  1326                   mark2Coverage.sanitize (c, this) &&
       
  1327                   mark1Array.sanitize (c, this) &&
       
  1328                   mark2Array.sanitize (c, this, (unsigned int) classCount));
       
  1329   }
       
  1330 
       
  1331   protected:
       
  1332   USHORT        format;                 /* Format identifier--format = 1 */
       
  1333   OffsetTo<Coverage>
       
  1334                 mark1Coverage;          /* Offset to Combining Mark1 Coverage
       
  1335                                          * table--from beginning of MarkMarkPos
       
  1336                                          * subtable */
       
  1337   OffsetTo<Coverage>
       
  1338                 mark2Coverage;          /* Offset to Combining Mark2 Coverage
       
  1339                                          * table--from beginning of MarkMarkPos
       
  1340                                          * subtable */
       
  1341   USHORT        classCount;             /* Number of defined mark classes */
       
  1342   OffsetTo<MarkArray>
       
  1343                 mark1Array;             /* Offset to Mark1Array table--from
       
  1344                                          * beginning of MarkMarkPos subtable */
       
  1345   OffsetTo<Mark2Array>
       
  1346                 mark2Array;             /* Offset to Mark2Array table--from
       
  1347                                          * beginning of MarkMarkPos subtable */
       
  1348   public:
       
  1349   DEFINE_SIZE_STATIC (12);
       
  1350 };
       
  1351 
       
  1352 struct MarkMarkPos
       
  1353 {
       
  1354   template <typename context_t>
       
  1355   inline typename context_t::return_t dispatch (context_t *c) const
       
  1356   {
       
  1357     TRACE_DISPATCH (this, u.format);
       
  1358     if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
       
  1359     switch (u.format) {
       
  1360     case 1: return_trace (c->dispatch (u.format1));
       
  1361     default:return_trace (c->default_return_value ());
       
  1362     }
       
  1363   }
       
  1364 
       
  1365   protected:
       
  1366   union {
       
  1367   USHORT                format;         /* Format identifier */
       
  1368   MarkMarkPosFormat1    format1;
       
  1369   } u;
       
  1370 };
       
  1371 
       
  1372 
       
  1373 struct ContextPos : Context {};
       
  1374 
       
  1375 struct ChainContextPos : ChainContext {};
       
  1376 
       
  1377 struct ExtensionPos : Extension<ExtensionPos>
       
  1378 {
       
  1379   typedef struct PosLookupSubTable LookupSubTable;
       
  1380 };
       
  1381 
       
  1382 
       
  1383 
       
  1384 /*
       
  1385  * PosLookup
       
  1386  */
       
  1387 
       
  1388 
       
  1389 struct PosLookupSubTable
       
  1390 {
       
  1391   friend struct PosLookup;
       
  1392 
       
  1393   enum Type {
       
  1394     Single              = 1,
       
  1395     Pair                = 2,
       
  1396     Cursive             = 3,
       
  1397     MarkBase            = 4,
       
  1398     MarkLig             = 5,
       
  1399     MarkMark            = 6,
       
  1400     Context             = 7,
       
  1401     ChainContext        = 8,
       
  1402     Extension           = 9
       
  1403   };
       
  1404 
       
  1405   template <typename context_t>
       
  1406   inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
       
  1407   {
       
  1408     TRACE_DISPATCH (this, lookup_type);
       
  1409     if (unlikely (!c->may_dispatch (this, &u.sub_format))) return_trace (c->no_dispatch_return_value ());
       
  1410     switch (lookup_type) {
       
  1411     case Single:                return_trace (u.single.dispatch (c));
       
  1412     case Pair:                  return_trace (u.pair.dispatch (c));
       
  1413     case Cursive:               return_trace (u.cursive.dispatch (c));
       
  1414     case MarkBase:              return_trace (u.markBase.dispatch (c));
       
  1415     case MarkLig:               return_trace (u.markLig.dispatch (c));
       
  1416     case MarkMark:              return_trace (u.markMark.dispatch (c));
       
  1417     case Context:               return_trace (u.context.dispatch (c));
       
  1418     case ChainContext:          return_trace (u.chainContext.dispatch (c));
       
  1419     case Extension:             return_trace (u.extension.dispatch (c));
       
  1420     default:                    return_trace (c->default_return_value ());
       
  1421     }
       
  1422   }
       
  1423 
       
  1424   protected:
       
  1425   union {
       
  1426   USHORT                sub_format;
       
  1427   SinglePos             single;
       
  1428   PairPos               pair;
       
  1429   CursivePos            cursive;
       
  1430   MarkBasePos           markBase;
       
  1431   MarkLigPos            markLig;
       
  1432   MarkMarkPos           markMark;
       
  1433   ContextPos            context;
       
  1434   ChainContextPos       chainContext;
       
  1435   ExtensionPos          extension;
       
  1436   } u;
       
  1437   public:
       
  1438   DEFINE_SIZE_UNION (2, sub_format);
       
  1439 };
       
  1440 
       
  1441 
       
  1442 struct PosLookup : Lookup
       
  1443 {
       
  1444   inline const PosLookupSubTable& get_subtable (unsigned int i) const
       
  1445   { return Lookup::get_subtable<PosLookupSubTable> (i); }
       
  1446 
       
  1447   inline bool is_reverse (void) const
       
  1448   {
       
  1449     return false;
       
  1450   }
       
  1451 
       
  1452   inline bool apply (hb_apply_context_t *c) const
       
  1453   {
       
  1454     TRACE_APPLY (this);
       
  1455     return_trace (dispatch (c));
       
  1456   }
       
  1457 
       
  1458   inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
       
  1459   {
       
  1460     TRACE_COLLECT_GLYPHS (this);
       
  1461     return_trace (dispatch (c));
       
  1462   }
       
  1463 
       
  1464   template <typename set_t>
       
  1465   inline void add_coverage (set_t *glyphs) const
       
  1466   {
       
  1467     hb_add_coverage_context_t<set_t> c (glyphs);
       
  1468     dispatch (&c);
       
  1469   }
       
  1470 
       
  1471   static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
       
  1472 
       
  1473   template <typename context_t>
       
  1474   static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
       
  1475 
       
  1476   template <typename context_t>
       
  1477   inline typename context_t::return_t dispatch (context_t *c) const
       
  1478   { return Lookup::dispatch<PosLookupSubTable> (c); }
       
  1479 
       
  1480   inline bool sanitize (hb_sanitize_context_t *c) const
       
  1481   {
       
  1482     TRACE_SANITIZE (this);
       
  1483     if (unlikely (!Lookup::sanitize (c))) return_trace (false);
       
  1484     return_trace (dispatch (c));
       
  1485   }
       
  1486 };
       
  1487 
       
  1488 typedef OffsetListOf<PosLookup> PosLookupList;
       
  1489 
       
  1490 /*
       
  1491  * GPOS -- The Glyph Positioning Table
       
  1492  */
       
  1493 
       
  1494 struct GPOS : GSUBGPOS
       
  1495 {
       
  1496   static const hb_tag_t tableTag        = HB_OT_TAG_GPOS;
       
  1497 
       
  1498   inline const PosLookup& get_lookup (unsigned int i) const
       
  1499   { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
       
  1500 
       
  1501   static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
       
  1502   static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer);
       
  1503 
       
  1504   inline bool sanitize (hb_sanitize_context_t *c) const
       
  1505   {
       
  1506     TRACE_SANITIZE (this);
       
  1507     if (unlikely (!GSUBGPOS::sanitize (c))) return_trace (false);
       
  1508     const OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
       
  1509     return_trace (list.sanitize (c, this));
       
  1510   }
       
  1511   public:
       
  1512   DEFINE_SIZE_STATIC (10);
       
  1513 };
       
  1514 
       
  1515 
       
  1516 static void
       
  1517 reverse_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction, unsigned int new_parent)
       
  1518 {
       
  1519   unsigned int j = pos[i].cursive_chain();
       
  1520   if (likely (!j))
       
  1521     return;
       
  1522 
       
  1523   j += i;
       
  1524 
       
  1525   pos[i].cursive_chain() = 0;
       
  1526 
       
  1527   /* Stop if we see new parent in the chain. */
       
  1528   if (j == new_parent)
       
  1529     return;
       
  1530 
       
  1531   reverse_cursive_minor_offset (pos, j, direction, new_parent);
       
  1532 
       
  1533   if (HB_DIRECTION_IS_HORIZONTAL (direction))
       
  1534     pos[j].y_offset = -pos[i].y_offset;
       
  1535   else
       
  1536     pos[j].x_offset = -pos[i].x_offset;
       
  1537 
       
  1538   pos[j].cursive_chain() = i - j;
       
  1539 }
       
  1540 static void
       
  1541 fix_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
       
  1542 {
       
  1543   unsigned int j = pos[i].cursive_chain();
       
  1544   if (likely (!j))
       
  1545     return;
       
  1546 
       
  1547   j += i;
       
  1548 
       
  1549   pos[i].cursive_chain() = 0;
       
  1550 
       
  1551   fix_cursive_minor_offset (pos, j, direction);
       
  1552 
       
  1553   if (HB_DIRECTION_IS_HORIZONTAL (direction))
       
  1554     pos[i].y_offset += pos[j].y_offset;
       
  1555   else
       
  1556     pos[i].x_offset += pos[j].x_offset;
       
  1557 }
       
  1558 
       
  1559 static void
       
  1560 fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
       
  1561 {
       
  1562   if (likely (!(pos[i].attach_lookback())))
       
  1563     return;
       
  1564 
       
  1565   unsigned int j = i - pos[i].attach_lookback();
       
  1566 
       
  1567   pos[i].x_offset += pos[j].x_offset;
       
  1568   pos[i].y_offset += pos[j].y_offset;
       
  1569 
       
  1570   if (HB_DIRECTION_IS_FORWARD (direction))
       
  1571     for (unsigned int k = j; k < i; k++) {
       
  1572       pos[i].x_offset -= pos[k].x_advance;
       
  1573       pos[i].y_offset -= pos[k].y_advance;
       
  1574     }
       
  1575   else
       
  1576     for (unsigned int k = j + 1; k < i + 1; k++) {
       
  1577       pos[i].x_offset += pos[k].x_advance;
       
  1578       pos[i].y_offset += pos[k].y_advance;
       
  1579     }
       
  1580 }
       
  1581 
       
  1582 void
       
  1583 GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
       
  1584 {
       
  1585   buffer->clear_positions ();
       
  1586 
       
  1587   unsigned int count = buffer->len;
       
  1588   for (unsigned int i = 0; i < count; i++)
       
  1589     buffer->pos[i].attach_lookback() = buffer->pos[i].cursive_chain() = 0;
       
  1590 }
       
  1591 
       
  1592 void
       
  1593 GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
       
  1594 {
       
  1595   _hb_buffer_assert_gsubgpos_vars (buffer);
       
  1596 
       
  1597   unsigned int len;
       
  1598   hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
       
  1599   hb_direction_t direction = buffer->props.direction;
       
  1600 
       
  1601   /* Handle cursive connections */
       
  1602   for (unsigned int i = 0; i < len; i++)
       
  1603     fix_cursive_minor_offset (pos, i, direction);
       
  1604 
       
  1605   /* Handle attachments */
       
  1606   for (unsigned int i = 0; i < len; i++)
       
  1607     fix_mark_attachment (pos, i, direction);
       
  1608 }
       
  1609 
       
  1610 
       
  1611 /* Out-of-class implementation for methods recursing */
       
  1612 
       
  1613 template <typename context_t>
       
  1614 /*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
       
  1615 {
       
  1616   const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
       
  1617   const PosLookup &l = gpos.get_lookup (lookup_index);
       
  1618   return l.dispatch (c);
       
  1619 }
       
  1620 
       
  1621 /*static*/ inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
       
  1622 {
       
  1623   const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
       
  1624   const PosLookup &l = gpos.get_lookup (lookup_index);
       
  1625   unsigned int saved_lookup_props = c->lookup_props;
       
  1626   unsigned int saved_lookup_index = c->lookup_index;
       
  1627   c->set_lookup_index (lookup_index);
       
  1628   c->set_lookup_props (l.get_props ());
       
  1629   bool ret = l.dispatch (c);
       
  1630   c->set_lookup_index (saved_lookup_index);
       
  1631   c->set_lookup_props (saved_lookup_props);
       
  1632   return ret;
       
  1633 }
       
  1634 
       
  1635 
       
  1636 #undef attach_lookback
       
  1637 #undef cursive_chain
       
  1638 
       
  1639 
       
  1640 } /* namespace OT */
       
  1641 
       
  1642 
       
  1643 #endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */