LCOV - code coverage report
Current view: directory - gfx/harfbuzz/src - hb-ot-layout-gpos-table.hh (source / functions) Found Hit Coverage
Test: app.info Lines: 605 0 0.0 %
Date: 2012-06-02 Functions: 74 0 0.0 %

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

Generated by: LCOV version 1.7