LCOV - code coverage report
Current view: top level - gfx/harfbuzz/src - hb-ot-layout-gpos-table.hh (source / functions) Hit Total Coverage
Test: output.info Lines: 233 609 38.3 %
Date: 2017-07-14 16:53:18 Functions: 57 111 51.4 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13