gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/harfbuzz/src/hb-ot-layout-gpos-table.hh	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1637 @@
     1.4 +/*
     1.5 + * Copyright © 2007,2008,2009,2010  Red Hat, Inc.
     1.6 + * Copyright © 2010,2012,2013  Google, Inc.
     1.7 + *
     1.8 + *  This is part of HarfBuzz, a text shaping library.
     1.9 + *
    1.10 + * Permission is hereby granted, without written agreement and without
    1.11 + * license or royalty fees, to use, copy, modify, and distribute this
    1.12 + * software and its documentation for any purpose, provided that the
    1.13 + * above copyright notice and the following two paragraphs appear in
    1.14 + * all copies of this software.
    1.15 + *
    1.16 + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
    1.17 + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
    1.18 + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
    1.19 + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
    1.20 + * DAMAGE.
    1.21 + *
    1.22 + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
    1.23 + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    1.24 + * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
    1.25 + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
    1.26 + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
    1.27 + *
    1.28 + * Red Hat Author(s): Behdad Esfahbod
    1.29 + * Google Author(s): Behdad Esfahbod
    1.30 + */
    1.31 +
    1.32 +#ifndef HB_OT_LAYOUT_GPOS_TABLE_HH
    1.33 +#define HB_OT_LAYOUT_GPOS_TABLE_HH
    1.34 +
    1.35 +#include "hb-ot-layout-gsubgpos-private.hh"
    1.36 +
    1.37 +
    1.38 +namespace OT {
    1.39 +
    1.40 +
    1.41 +/* buffer **position** var allocations */
    1.42 +#define attach_lookback() var.u16[0] /* number of glyphs to go back to attach this glyph to its base */
    1.43 +#define cursive_chain() var.i16[1] /* character to which this connects, may be positive or negative */
    1.44 +
    1.45 +
    1.46 +/* Shared Tables: ValueRecord, Anchor Table, and MarkArray */
    1.47 +
    1.48 +typedef USHORT Value;
    1.49 +
    1.50 +typedef Value ValueRecord[VAR];
    1.51 +
    1.52 +struct ValueFormat : USHORT
    1.53 +{
    1.54 +  enum Flags {
    1.55 +    xPlacement	= 0x0001,	/* Includes horizontal adjustment for placement */
    1.56 +    yPlacement	= 0x0002,	/* Includes vertical adjustment for placement */
    1.57 +    xAdvance	= 0x0004,	/* Includes horizontal adjustment for advance */
    1.58 +    yAdvance	= 0x0008,	/* Includes vertical adjustment for advance */
    1.59 +    xPlaDevice	= 0x0010,	/* Includes horizontal Device table for placement */
    1.60 +    yPlaDevice	= 0x0020,	/* Includes vertical Device table for placement */
    1.61 +    xAdvDevice	= 0x0040,	/* Includes horizontal Device table for advance */
    1.62 +    yAdvDevice	= 0x0080,	/* Includes vertical Device table for advance */
    1.63 +    ignored	= 0x0F00,	/* Was used in TrueType Open for MM fonts */
    1.64 +    reserved	= 0xF000,	/* For future use */
    1.65 +
    1.66 +    devices	= 0x00F0	/* Mask for having any Device table */
    1.67 +  };
    1.68 +
    1.69 +/* All fields are options.  Only those available advance the value pointer. */
    1.70 +#if 0
    1.71 +  SHORT		xPlacement;		/* Horizontal adjustment for
    1.72 +					 * placement--in design units */
    1.73 +  SHORT		yPlacement;		/* Vertical adjustment for
    1.74 +					 * placement--in design units */
    1.75 +  SHORT		xAdvance;		/* Horizontal adjustment for
    1.76 +					 * advance--in design units (only used
    1.77 +					 * for horizontal writing) */
    1.78 +  SHORT		yAdvance;		/* Vertical adjustment for advance--in
    1.79 +					 * design units (only used for vertical
    1.80 +					 * writing) */
    1.81 +  Offset	xPlaDevice;		/* Offset to Device table for
    1.82 +					 * horizontal placement--measured from
    1.83 +					 * beginning of PosTable (may be NULL) */
    1.84 +  Offset	yPlaDevice;		/* Offset to Device table for vertical
    1.85 +					 * placement--measured from beginning
    1.86 +					 * of PosTable (may be NULL) */
    1.87 +  Offset	xAdvDevice;		/* Offset to Device table for
    1.88 +					 * horizontal advance--measured from
    1.89 +					 * beginning of PosTable (may be NULL) */
    1.90 +  Offset	yAdvDevice;		/* Offset to Device table for vertical
    1.91 +					 * advance--measured from beginning of
    1.92 +					 * PosTable (may be NULL) */
    1.93 +#endif
    1.94 +
    1.95 +  inline unsigned int get_len (void) const
    1.96 +  { return _hb_popcount32 ((unsigned int) *this); }
    1.97 +  inline unsigned int get_size (void) const
    1.98 +  { return get_len () * Value::static_size; }
    1.99 +
   1.100 +  void apply_value (hb_font_t            *font,
   1.101 +		    hb_direction_t        direction,
   1.102 +		    const void           *base,
   1.103 +		    const Value          *values,
   1.104 +		    hb_glyph_position_t  &glyph_pos) const
   1.105 +  {
   1.106 +    unsigned int x_ppem, y_ppem;
   1.107 +    unsigned int format = *this;
   1.108 +    hb_bool_t horizontal = HB_DIRECTION_IS_HORIZONTAL (direction);
   1.109 +
   1.110 +    if (!format) return;
   1.111 +
   1.112 +    if (format & xPlacement) glyph_pos.x_offset  += font->em_scale_x (get_short (values++));
   1.113 +    if (format & yPlacement) glyph_pos.y_offset  += font->em_scale_y (get_short (values++));
   1.114 +    if (format & xAdvance) {
   1.115 +      if (likely (horizontal)) glyph_pos.x_advance += font->em_scale_x (get_short (values));
   1.116 +      values++;
   1.117 +    }
   1.118 +    /* y_advance values grow downward but font-space grows upward, hence negation */
   1.119 +    if (format & yAdvance) {
   1.120 +      if (unlikely (!horizontal)) glyph_pos.y_advance -= font->em_scale_y (get_short (values));
   1.121 +      values++;
   1.122 +    }
   1.123 +
   1.124 +    if (!has_device ()) return;
   1.125 +
   1.126 +    x_ppem = font->x_ppem;
   1.127 +    y_ppem = font->y_ppem;
   1.128 +
   1.129 +    if (!x_ppem && !y_ppem) return;
   1.130 +
   1.131 +    /* pixel -> fractional pixel */
   1.132 +    if (format & xPlaDevice) {
   1.133 +      if (x_ppem) glyph_pos.x_offset  += (base + get_device (values)).get_x_delta (font);
   1.134 +      values++;
   1.135 +    }
   1.136 +    if (format & yPlaDevice) {
   1.137 +      if (y_ppem) glyph_pos.y_offset  += (base + get_device (values)).get_y_delta (font);
   1.138 +      values++;
   1.139 +    }
   1.140 +    if (format & xAdvDevice) {
   1.141 +      if (horizontal && x_ppem) glyph_pos.x_advance += (base + get_device (values)).get_x_delta (font);
   1.142 +      values++;
   1.143 +    }
   1.144 +    if (format & yAdvDevice) {
   1.145 +      /* y_advance values grow downward but font-space grows upward, hence negation */
   1.146 +      if (!horizontal && y_ppem) glyph_pos.y_advance -= (base + get_device (values)).get_y_delta (font);
   1.147 +      values++;
   1.148 +    }
   1.149 +  }
   1.150 +
   1.151 +  private:
   1.152 +  inline bool sanitize_value_devices (hb_sanitize_context_t *c, void *base, Value *values) {
   1.153 +    unsigned int format = *this;
   1.154 +
   1.155 +    if (format & xPlacement) values++;
   1.156 +    if (format & yPlacement) values++;
   1.157 +    if (format & xAdvance)   values++;
   1.158 +    if (format & yAdvance)   values++;
   1.159 +
   1.160 +    if ((format & xPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
   1.161 +    if ((format & yPlaDevice) && !get_device (values++).sanitize (c, base)) return false;
   1.162 +    if ((format & xAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
   1.163 +    if ((format & yAdvDevice) && !get_device (values++).sanitize (c, base)) return false;
   1.164 +
   1.165 +    return true;
   1.166 +  }
   1.167 +
   1.168 +  static inline OffsetTo<Device>& get_device (Value* value)
   1.169 +  { return *CastP<OffsetTo<Device> > (value); }
   1.170 +  static inline const OffsetTo<Device>& get_device (const Value* value)
   1.171 +  { return *CastP<OffsetTo<Device> > (value); }
   1.172 +
   1.173 +  static inline const SHORT& get_short (const Value* value)
   1.174 +  { return *CastP<SHORT> (value); }
   1.175 +
   1.176 +  public:
   1.177 +
   1.178 +  inline bool has_device (void) const {
   1.179 +    unsigned int format = *this;
   1.180 +    return (format & devices) != 0;
   1.181 +  }
   1.182 +
   1.183 +  inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) {
   1.184 +    TRACE_SANITIZE (this);
   1.185 +    return TRACE_RETURN (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
   1.186 +  }
   1.187 +
   1.188 +  inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count) {
   1.189 +    TRACE_SANITIZE (this);
   1.190 +    unsigned int len = get_len ();
   1.191 +
   1.192 +    if (!c->check_array (values, get_size (), count)) return TRACE_RETURN (false);
   1.193 +
   1.194 +    if (!has_device ()) return TRACE_RETURN (true);
   1.195 +
   1.196 +    for (unsigned int i = 0; i < count; i++) {
   1.197 +      if (!sanitize_value_devices (c, base, values))
   1.198 +        return TRACE_RETURN (false);
   1.199 +      values += len;
   1.200 +    }
   1.201 +
   1.202 +    return TRACE_RETURN (true);
   1.203 +  }
   1.204 +
   1.205 +  /* Just sanitize referenced Device tables.  Doesn't check the values themselves. */
   1.206 +  inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count, unsigned int stride) {
   1.207 +    TRACE_SANITIZE (this);
   1.208 +
   1.209 +    if (!has_device ()) return TRACE_RETURN (true);
   1.210 +
   1.211 +    for (unsigned int i = 0; i < count; i++) {
   1.212 +      if (!sanitize_value_devices (c, base, values))
   1.213 +        return TRACE_RETURN (false);
   1.214 +      values += stride;
   1.215 +    }
   1.216 +
   1.217 +    return TRACE_RETURN (true);
   1.218 +  }
   1.219 +};
   1.220 +
   1.221 +
   1.222 +struct AnchorFormat1
   1.223 +{
   1.224 +  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
   1.225 +			  hb_position_t *x, hb_position_t *y) const
   1.226 +  {
   1.227 +      *x = font->em_scale_x (xCoordinate);
   1.228 +      *y = font->em_scale_y (yCoordinate);
   1.229 +  }
   1.230 +
   1.231 +  inline bool sanitize (hb_sanitize_context_t *c) {
   1.232 +    TRACE_SANITIZE (this);
   1.233 +    return TRACE_RETURN (c->check_struct (this));
   1.234 +  }
   1.235 +
   1.236 +  protected:
   1.237 +  USHORT	format;			/* Format identifier--format = 1 */
   1.238 +  SHORT		xCoordinate;		/* Horizontal value--in design units */
   1.239 +  SHORT		yCoordinate;		/* Vertical value--in design units */
   1.240 +  public:
   1.241 +  DEFINE_SIZE_STATIC (6);
   1.242 +};
   1.243 +
   1.244 +struct AnchorFormat2
   1.245 +{
   1.246 +  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
   1.247 +			  hb_position_t *x, hb_position_t *y) const
   1.248 +  {
   1.249 +      unsigned int x_ppem = font->x_ppem;
   1.250 +      unsigned int y_ppem = font->y_ppem;
   1.251 +      hb_position_t cx, cy;
   1.252 +      hb_bool_t ret;
   1.253 +
   1.254 +      ret = (x_ppem || y_ppem) &&
   1.255 +             font->get_glyph_contour_point_for_origin (glyph_id, anchorPoint, HB_DIRECTION_LTR, &cx, &cy);
   1.256 +      *x = ret && x_ppem ? cx : font->em_scale_x (xCoordinate);
   1.257 +      *y = ret && y_ppem ? cy : font->em_scale_y (yCoordinate);
   1.258 +  }
   1.259 +
   1.260 +  inline bool sanitize (hb_sanitize_context_t *c) {
   1.261 +    TRACE_SANITIZE (this);
   1.262 +    return TRACE_RETURN (c->check_struct (this));
   1.263 +  }
   1.264 +
   1.265 +  protected:
   1.266 +  USHORT	format;			/* Format identifier--format = 2 */
   1.267 +  SHORT		xCoordinate;		/* Horizontal value--in design units */
   1.268 +  SHORT		yCoordinate;		/* Vertical value--in design units */
   1.269 +  USHORT	anchorPoint;		/* Index to glyph contour point */
   1.270 +  public:
   1.271 +  DEFINE_SIZE_STATIC (8);
   1.272 +};
   1.273 +
   1.274 +struct AnchorFormat3
   1.275 +{
   1.276 +  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id HB_UNUSED,
   1.277 +			  hb_position_t *x, hb_position_t *y) const
   1.278 +  {
   1.279 +      *x = font->em_scale_x (xCoordinate);
   1.280 +      *y = font->em_scale_y (yCoordinate);
   1.281 +
   1.282 +      if (font->x_ppem)
   1.283 +	*x += (this+xDeviceTable).get_x_delta (font);
   1.284 +      if (font->y_ppem)
   1.285 +	*y += (this+yDeviceTable).get_x_delta (font);
   1.286 +  }
   1.287 +
   1.288 +  inline bool sanitize (hb_sanitize_context_t *c) {
   1.289 +    TRACE_SANITIZE (this);
   1.290 +    return TRACE_RETURN (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
   1.291 +  }
   1.292 +
   1.293 +  protected:
   1.294 +  USHORT	format;			/* Format identifier--format = 3 */
   1.295 +  SHORT		xCoordinate;		/* Horizontal value--in design units */
   1.296 +  SHORT		yCoordinate;		/* Vertical value--in design units */
   1.297 +  OffsetTo<Device>
   1.298 +		xDeviceTable;		/* Offset to Device table for X
   1.299 +					 * coordinate-- from beginning of
   1.300 +					 * Anchor table (may be NULL) */
   1.301 +  OffsetTo<Device>
   1.302 +		yDeviceTable;		/* Offset to Device table for Y
   1.303 +					 * coordinate-- from beginning of
   1.304 +					 * Anchor table (may be NULL) */
   1.305 +  public:
   1.306 +  DEFINE_SIZE_STATIC (10);
   1.307 +};
   1.308 +
   1.309 +struct Anchor
   1.310 +{
   1.311 +  inline void get_anchor (hb_font_t *font, hb_codepoint_t glyph_id,
   1.312 +			  hb_position_t *x, hb_position_t *y) const
   1.313 +  {
   1.314 +    *x = *y = 0;
   1.315 +    switch (u.format) {
   1.316 +    case 1: u.format1.get_anchor (font, glyph_id, x, y); return;
   1.317 +    case 2: u.format2.get_anchor (font, glyph_id, x, y); return;
   1.318 +    case 3: u.format3.get_anchor (font, glyph_id, x, y); return;
   1.319 +    default:						 return;
   1.320 +    }
   1.321 +  }
   1.322 +
   1.323 +  inline bool sanitize (hb_sanitize_context_t *c) {
   1.324 +    TRACE_SANITIZE (this);
   1.325 +    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
   1.326 +    switch (u.format) {
   1.327 +    case 1: return TRACE_RETURN (u.format1.sanitize (c));
   1.328 +    case 2: return TRACE_RETURN (u.format2.sanitize (c));
   1.329 +    case 3: return TRACE_RETURN (u.format3.sanitize (c));
   1.330 +    default:return TRACE_RETURN (true);
   1.331 +    }
   1.332 +  }
   1.333 +
   1.334 +  protected:
   1.335 +  union {
   1.336 +  USHORT		format;		/* Format identifier */
   1.337 +  AnchorFormat1		format1;
   1.338 +  AnchorFormat2		format2;
   1.339 +  AnchorFormat3		format3;
   1.340 +  } u;
   1.341 +  public:
   1.342 +  DEFINE_SIZE_UNION (2, format);
   1.343 +};
   1.344 +
   1.345 +
   1.346 +struct AnchorMatrix
   1.347 +{
   1.348 +  inline const Anchor& get_anchor (unsigned int row, unsigned int col, unsigned int cols, bool *found) const {
   1.349 +    *found = false;
   1.350 +    if (unlikely (row >= rows || col >= cols)) return Null(Anchor);
   1.351 +    *found = !matrix[row * cols + col].is_null ();
   1.352 +    return this+matrix[row * cols + col];
   1.353 +  }
   1.354 +
   1.355 +  inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) {
   1.356 +    TRACE_SANITIZE (this);
   1.357 +    if (!c->check_struct (this)) return TRACE_RETURN (false);
   1.358 +    if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return TRACE_RETURN (false);
   1.359 +    unsigned int count = rows * cols;
   1.360 +    if (!c->check_array (matrix, matrix[0].static_size, count)) return TRACE_RETURN (false);
   1.361 +    for (unsigned int i = 0; i < count; i++)
   1.362 +      if (!matrix[i].sanitize (c, this)) return TRACE_RETURN (false);
   1.363 +    return TRACE_RETURN (true);
   1.364 +  }
   1.365 +
   1.366 +  USHORT	rows;			/* Number of rows */
   1.367 +  protected:
   1.368 +  OffsetTo<Anchor>
   1.369 +		matrix[VAR];		/* Matrix of offsets to Anchor tables--
   1.370 +					 * from beginning of AnchorMatrix table */
   1.371 +  public:
   1.372 +  DEFINE_SIZE_ARRAY (2, matrix);
   1.373 +};
   1.374 +
   1.375 +
   1.376 +struct MarkRecord
   1.377 +{
   1.378 +  friend struct MarkArray;
   1.379 +
   1.380 +  inline bool sanitize (hb_sanitize_context_t *c, void *base) {
   1.381 +    TRACE_SANITIZE (this);
   1.382 +    return TRACE_RETURN (c->check_struct (this) && markAnchor.sanitize (c, base));
   1.383 +  }
   1.384 +
   1.385 +  protected:
   1.386 +  USHORT	klass;			/* Class defined for this mark */
   1.387 +  OffsetTo<Anchor>
   1.388 +		markAnchor;		/* Offset to Anchor table--from
   1.389 +					 * beginning of MarkArray table */
   1.390 +  public:
   1.391 +  DEFINE_SIZE_STATIC (4);
   1.392 +};
   1.393 +
   1.394 +struct MarkArray : ArrayOf<MarkRecord>	/* Array of MarkRecords--in Coverage order */
   1.395 +{
   1.396 +  inline bool apply (hb_apply_context_t *c,
   1.397 +		     unsigned int mark_index, unsigned int glyph_index,
   1.398 +		     const AnchorMatrix &anchors, unsigned int class_count,
   1.399 +		     unsigned int glyph_pos) const
   1.400 +  {
   1.401 +    TRACE_APPLY (this);
   1.402 +    hb_buffer_t *buffer = c->buffer;
   1.403 +    const MarkRecord &record = ArrayOf<MarkRecord>::operator[](mark_index);
   1.404 +    unsigned int mark_class = record.klass;
   1.405 +
   1.406 +    const Anchor& mark_anchor = this + record.markAnchor;
   1.407 +    bool found;
   1.408 +    const Anchor& glyph_anchor = anchors.get_anchor (glyph_index, mark_class, class_count, &found);
   1.409 +    /* If this subtable doesn't have an anchor for this base and this class,
   1.410 +     * return false such that the subsequent subtables have a chance at it. */
   1.411 +    if (unlikely (!found)) return TRACE_RETURN (false);
   1.412 +
   1.413 +    hb_position_t mark_x, mark_y, base_x, base_y;
   1.414 +
   1.415 +    mark_anchor.get_anchor (c->font, buffer->cur().codepoint, &mark_x, &mark_y);
   1.416 +    glyph_anchor.get_anchor (c->font, buffer->info[glyph_pos].codepoint, &base_x, &base_y);
   1.417 +
   1.418 +    hb_glyph_position_t &o = buffer->cur_pos();
   1.419 +    o.x_offset = base_x - mark_x;
   1.420 +    o.y_offset = base_y - mark_y;
   1.421 +    o.attach_lookback() = buffer->idx - glyph_pos;
   1.422 +
   1.423 +    buffer->idx++;
   1.424 +    return TRACE_RETURN (true);
   1.425 +  }
   1.426 +
   1.427 +  inline bool sanitize (hb_sanitize_context_t *c) {
   1.428 +    TRACE_SANITIZE (this);
   1.429 +    return TRACE_RETURN (ArrayOf<MarkRecord>::sanitize (c, this));
   1.430 +  }
   1.431 +};
   1.432 +
   1.433 +
   1.434 +/* Lookups */
   1.435 +
   1.436 +struct SinglePosFormat1
   1.437 +{
   1.438 +  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   1.439 +  {
   1.440 +    TRACE_COLLECT_GLYPHS (this);
   1.441 +    (this+coverage).add_coverage (c->input);
   1.442 +  }
   1.443 +
   1.444 +  inline const Coverage &get_coverage (void) const
   1.445 +  {
   1.446 +    return this+coverage;
   1.447 +  }
   1.448 +
   1.449 +  inline bool apply (hb_apply_context_t *c) const
   1.450 +  {
   1.451 +    TRACE_APPLY (this);
   1.452 +    hb_buffer_t *buffer = c->buffer;
   1.453 +    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
   1.454 +    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
   1.455 +
   1.456 +    valueFormat.apply_value (c->font, c->direction, this,
   1.457 +			     values, buffer->cur_pos());
   1.458 +
   1.459 +    buffer->idx++;
   1.460 +    return TRACE_RETURN (true);
   1.461 +  }
   1.462 +
   1.463 +  inline bool sanitize (hb_sanitize_context_t *c) {
   1.464 +    TRACE_SANITIZE (this);
   1.465 +    return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_value (c, this, values));
   1.466 +  }
   1.467 +
   1.468 +  protected:
   1.469 +  USHORT	format;			/* Format identifier--format = 1 */
   1.470 +  OffsetTo<Coverage>
   1.471 +		coverage;		/* Offset to Coverage table--from
   1.472 +					 * beginning of subtable */
   1.473 +  ValueFormat	valueFormat;		/* Defines the types of data in the
   1.474 +					 * ValueRecord */
   1.475 +  ValueRecord	values;			/* Defines positioning
   1.476 +					 * value(s)--applied to all glyphs in
   1.477 +					 * the Coverage table */
   1.478 +  public:
   1.479 +  DEFINE_SIZE_ARRAY (6, values);
   1.480 +};
   1.481 +
   1.482 +struct SinglePosFormat2
   1.483 +{
   1.484 +  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   1.485 +  {
   1.486 +    TRACE_COLLECT_GLYPHS (this);
   1.487 +    (this+coverage).add_coverage (c->input);
   1.488 +  }
   1.489 +
   1.490 +  inline const Coverage &get_coverage (void) const
   1.491 +  {
   1.492 +    return this+coverage;
   1.493 +  }
   1.494 +
   1.495 +  inline bool apply (hb_apply_context_t *c) const
   1.496 +  {
   1.497 +    TRACE_APPLY (this);
   1.498 +    hb_buffer_t *buffer = c->buffer;
   1.499 +    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
   1.500 +    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
   1.501 +
   1.502 +    if (likely (index >= valueCount)) return TRACE_RETURN (false);
   1.503 +
   1.504 +    valueFormat.apply_value (c->font, c->direction, this,
   1.505 +			     &values[index * valueFormat.get_len ()],
   1.506 +			     buffer->cur_pos());
   1.507 +
   1.508 +    buffer->idx++;
   1.509 +    return TRACE_RETURN (true);
   1.510 +  }
   1.511 +
   1.512 +  inline bool sanitize (hb_sanitize_context_t *c) {
   1.513 +    TRACE_SANITIZE (this);
   1.514 +    return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_values (c, this, values, valueCount));
   1.515 +  }
   1.516 +
   1.517 +  protected:
   1.518 +  USHORT	format;			/* Format identifier--format = 2 */
   1.519 +  OffsetTo<Coverage>
   1.520 +		coverage;		/* Offset to Coverage table--from
   1.521 +					 * beginning of subtable */
   1.522 +  ValueFormat	valueFormat;		/* Defines the types of data in the
   1.523 +					 * ValueRecord */
   1.524 +  USHORT	valueCount;		/* Number of ValueRecords */
   1.525 +  ValueRecord	values;			/* Array of ValueRecords--positioning
   1.526 +					 * values applied to glyphs */
   1.527 +  public:
   1.528 +  DEFINE_SIZE_ARRAY (8, values);
   1.529 +};
   1.530 +
   1.531 +struct SinglePos
   1.532 +{
   1.533 +  template <typename context_t>
   1.534 +  inline typename context_t::return_t dispatch (context_t *c) const
   1.535 +  {
   1.536 +    TRACE_DISPATCH (this);
   1.537 +    switch (u.format) {
   1.538 +    case 1: return TRACE_RETURN (c->dispatch (u.format1));
   1.539 +    case 2: return TRACE_RETURN (c->dispatch (u.format2));
   1.540 +    default:return TRACE_RETURN (c->default_return_value ());
   1.541 +    }
   1.542 +  }
   1.543 +
   1.544 +  inline bool sanitize (hb_sanitize_context_t *c) {
   1.545 +    TRACE_SANITIZE (this);
   1.546 +    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
   1.547 +    switch (u.format) {
   1.548 +    case 1: return TRACE_RETURN (u.format1.sanitize (c));
   1.549 +    case 2: return TRACE_RETURN (u.format2.sanitize (c));
   1.550 +    default:return TRACE_RETURN (true);
   1.551 +    }
   1.552 +  }
   1.553 +
   1.554 +  protected:
   1.555 +  union {
   1.556 +  USHORT		format;		/* Format identifier */
   1.557 +  SinglePosFormat1	format1;
   1.558 +  SinglePosFormat2	format2;
   1.559 +  } u;
   1.560 +};
   1.561 +
   1.562 +
   1.563 +struct PairValueRecord
   1.564 +{
   1.565 +  friend struct PairSet;
   1.566 +
   1.567 +  protected:
   1.568 +  GlyphID	secondGlyph;		/* GlyphID of second glyph in the
   1.569 +					 * pair--first glyph is listed in the
   1.570 +					 * Coverage table */
   1.571 +  ValueRecord	values;			/* Positioning data for the first glyph
   1.572 +					 * followed by for second glyph */
   1.573 +  public:
   1.574 +  DEFINE_SIZE_ARRAY (2, values);
   1.575 +};
   1.576 +
   1.577 +struct PairSet
   1.578 +{
   1.579 +  friend struct PairPosFormat1;
   1.580 +
   1.581 +  inline void collect_glyphs (hb_collect_glyphs_context_t *c,
   1.582 +			      const ValueFormat *valueFormats) const
   1.583 +  {
   1.584 +    TRACE_COLLECT_GLYPHS (this);
   1.585 +    unsigned int len1 = valueFormats[0].get_len ();
   1.586 +    unsigned int len2 = valueFormats[1].get_len ();
   1.587 +    unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
   1.588 +
   1.589 +    const PairValueRecord *record = CastP<PairValueRecord> (array);
   1.590 +    unsigned int count = len;
   1.591 +    for (unsigned int i = 0; i < count; i++)
   1.592 +    {
   1.593 +      c->input->add (record->secondGlyph);
   1.594 +      record = &StructAtOffset<PairValueRecord> (record, record_size);
   1.595 +    }
   1.596 +  }
   1.597 +
   1.598 +  inline bool apply (hb_apply_context_t *c,
   1.599 +		     const ValueFormat *valueFormats,
   1.600 +		     unsigned int pos) const
   1.601 +  {
   1.602 +    TRACE_APPLY (this);
   1.603 +    hb_buffer_t *buffer = c->buffer;
   1.604 +    unsigned int len1 = valueFormats[0].get_len ();
   1.605 +    unsigned int len2 = valueFormats[1].get_len ();
   1.606 +    unsigned int record_size = USHORT::static_size * (1 + len1 + len2);
   1.607 +
   1.608 +    const PairValueRecord *record = CastP<PairValueRecord> (array);
   1.609 +    unsigned int count = len;
   1.610 +    for (unsigned int i = 0; i < count; i++)
   1.611 +    {
   1.612 +      /* TODO bsearch */
   1.613 +      if (buffer->info[pos].codepoint == record->secondGlyph)
   1.614 +      {
   1.615 +	valueFormats[0].apply_value (c->font, c->direction, this,
   1.616 +				     &record->values[0], buffer->cur_pos());
   1.617 +	valueFormats[1].apply_value (c->font, c->direction, this,
   1.618 +				     &record->values[len1], buffer->pos[pos]);
   1.619 +	if (len2)
   1.620 +	  pos++;
   1.621 +	buffer->idx = pos;
   1.622 +	return TRACE_RETURN (true);
   1.623 +      }
   1.624 +      record = &StructAtOffset<PairValueRecord> (record, record_size);
   1.625 +    }
   1.626 +
   1.627 +    return TRACE_RETURN (false);
   1.628 +  }
   1.629 +
   1.630 +  struct sanitize_closure_t {
   1.631 +    void *base;
   1.632 +    ValueFormat *valueFormats;
   1.633 +    unsigned int len1; /* valueFormats[0].get_len() */
   1.634 +    unsigned int stride; /* 1 + len1 + len2 */
   1.635 +  };
   1.636 +
   1.637 +  inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) {
   1.638 +    TRACE_SANITIZE (this);
   1.639 +    if (!(c->check_struct (this)
   1.640 +       && c->check_array (array, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false);
   1.641 +
   1.642 +    unsigned int count = len;
   1.643 +    PairValueRecord *record = CastP<PairValueRecord> (array);
   1.644 +    return TRACE_RETURN (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride)
   1.645 +		      && closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
   1.646 +  }
   1.647 +
   1.648 +  protected:
   1.649 +  USHORT	len;			/* Number of PairValueRecords */
   1.650 +  USHORT	array[VAR];		/* Array of PairValueRecords--ordered
   1.651 +					 * by GlyphID of the second glyph */
   1.652 +  public:
   1.653 +  DEFINE_SIZE_ARRAY (2, array);
   1.654 +};
   1.655 +
   1.656 +struct PairPosFormat1
   1.657 +{
   1.658 +  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   1.659 +  {
   1.660 +    TRACE_COLLECT_GLYPHS (this);
   1.661 +    (this+coverage).add_coverage (c->input);
   1.662 +    unsigned int count = pairSet.len;
   1.663 +    for (unsigned int i = 0; i < count; i++)
   1.664 +      (this+pairSet[i]).collect_glyphs (c, &valueFormat1);
   1.665 +  }
   1.666 +
   1.667 +  inline const Coverage &get_coverage (void) const
   1.668 +  {
   1.669 +    return this+coverage;
   1.670 +  }
   1.671 +
   1.672 +  inline bool apply (hb_apply_context_t *c) const
   1.673 +  {
   1.674 +    TRACE_APPLY (this);
   1.675 +    hb_buffer_t *buffer = c->buffer;
   1.676 +    hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1);
   1.677 +    if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
   1.678 +
   1.679 +    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
   1.680 +    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
   1.681 +
   1.682 +    if (!skippy_iter.next ()) return TRACE_RETURN (false);
   1.683 +
   1.684 +    return TRACE_RETURN ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx));
   1.685 +  }
   1.686 +
   1.687 +  inline bool sanitize (hb_sanitize_context_t *c) {
   1.688 +    TRACE_SANITIZE (this);
   1.689 +
   1.690 +    unsigned int len1 = valueFormat1.get_len ();
   1.691 +    unsigned int len2 = valueFormat2.get_len ();
   1.692 +    PairSet::sanitize_closure_t closure = {
   1.693 +      this,
   1.694 +      &valueFormat1,
   1.695 +      len1,
   1.696 +      1 + len1 + len2
   1.697 +    };
   1.698 +
   1.699 +    return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
   1.700 +  }
   1.701 +
   1.702 +  protected:
   1.703 +  USHORT	format;			/* Format identifier--format = 1 */
   1.704 +  OffsetTo<Coverage>
   1.705 +		coverage;		/* Offset to Coverage table--from
   1.706 +					 * beginning of subtable */
   1.707 +  ValueFormat	valueFormat1;		/* Defines the types of data in
   1.708 +					 * ValueRecord1--for the first glyph
   1.709 +					 * in the pair--may be zero (0) */
   1.710 +  ValueFormat	valueFormat2;		/* Defines the types of data in
   1.711 +					 * ValueRecord2--for the second glyph
   1.712 +					 * in the pair--may be zero (0) */
   1.713 +  OffsetArrayOf<PairSet>
   1.714 +		pairSet;		/* Array of PairSet tables
   1.715 +					 * ordered by Coverage Index */
   1.716 +  public:
   1.717 +  DEFINE_SIZE_ARRAY (10, pairSet);
   1.718 +};
   1.719 +
   1.720 +struct PairPosFormat2
   1.721 +{
   1.722 +  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   1.723 +  {
   1.724 +    TRACE_COLLECT_GLYPHS (this);
   1.725 +    /* (this+coverage).add_coverage (c->input); // Don't need this. */
   1.726 +
   1.727 +    unsigned int count1 = class1Count;
   1.728 +    const ClassDef &klass1 = this+classDef1;
   1.729 +    for (unsigned int i = 0; i < count1; i++)
   1.730 +      klass1.add_class (c->input, i);
   1.731 +
   1.732 +    unsigned int count2 = class2Count;
   1.733 +    const ClassDef &klass2 = this+classDef2;
   1.734 +    for (unsigned int i = 0; i < count2; i++)
   1.735 +      klass2.add_class (c->input, i);
   1.736 +  }
   1.737 +
   1.738 +  inline const Coverage &get_coverage (void) const
   1.739 +  {
   1.740 +    return this+coverage;
   1.741 +  }
   1.742 +
   1.743 +  inline bool apply (hb_apply_context_t *c) const
   1.744 +  {
   1.745 +    TRACE_APPLY (this);
   1.746 +    hb_buffer_t *buffer = c->buffer;
   1.747 +    hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1);
   1.748 +    if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
   1.749 +
   1.750 +    unsigned int index = (this+coverage).get_coverage  (buffer->cur().codepoint);
   1.751 +    if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
   1.752 +
   1.753 +    if (!skippy_iter.next ()) return TRACE_RETURN (false);
   1.754 +
   1.755 +    unsigned int len1 = valueFormat1.get_len ();
   1.756 +    unsigned int len2 = valueFormat2.get_len ();
   1.757 +    unsigned int record_len = len1 + len2;
   1.758 +
   1.759 +    unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint);
   1.760 +    unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint);
   1.761 +    if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return TRACE_RETURN (false);
   1.762 +
   1.763 +    const Value *v = &values[record_len * (klass1 * class2Count + klass2)];
   1.764 +    valueFormat1.apply_value (c->font, c->direction, this,
   1.765 +			      v, buffer->cur_pos());
   1.766 +    valueFormat2.apply_value (c->font, c->direction, this,
   1.767 +			      v + len1, buffer->pos[skippy_iter.idx]);
   1.768 +
   1.769 +    buffer->idx = skippy_iter.idx;
   1.770 +    if (len2)
   1.771 +      buffer->idx++;
   1.772 +
   1.773 +    return TRACE_RETURN (true);
   1.774 +  }
   1.775 +
   1.776 +  inline bool sanitize (hb_sanitize_context_t *c) {
   1.777 +    TRACE_SANITIZE (this);
   1.778 +    if (!(c->check_struct (this)
   1.779 +       && coverage.sanitize (c, this)
   1.780 +       && classDef1.sanitize (c, this)
   1.781 +       && classDef2.sanitize (c, this))) return TRACE_RETURN (false);
   1.782 +
   1.783 +    unsigned int len1 = valueFormat1.get_len ();
   1.784 +    unsigned int len2 = valueFormat2.get_len ();
   1.785 +    unsigned int stride = len1 + len2;
   1.786 +    unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
   1.787 +    unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
   1.788 +    return TRACE_RETURN (c->check_array (values, record_size, count) &&
   1.789 +			 valueFormat1.sanitize_values_stride_unsafe (c, this, &values[0], count, stride) &&
   1.790 +			 valueFormat2.sanitize_values_stride_unsafe (c, this, &values[len1], count, stride));
   1.791 +  }
   1.792 +
   1.793 +  protected:
   1.794 +  USHORT	format;			/* Format identifier--format = 2 */
   1.795 +  OffsetTo<Coverage>
   1.796 +		coverage;		/* Offset to Coverage table--from
   1.797 +					 * beginning of subtable */
   1.798 +  ValueFormat	valueFormat1;		/* ValueRecord definition--for the
   1.799 +					 * first glyph of the pair--may be zero
   1.800 +					 * (0) */
   1.801 +  ValueFormat	valueFormat2;		/* ValueRecord definition--for the
   1.802 +					 * second glyph of the pair--may be
   1.803 +					 * zero (0) */
   1.804 +  OffsetTo<ClassDef>
   1.805 +		classDef1;		/* Offset to ClassDef table--from
   1.806 +					 * beginning of PairPos subtable--for
   1.807 +					 * the first glyph of the pair */
   1.808 +  OffsetTo<ClassDef>
   1.809 +		classDef2;		/* Offset to ClassDef table--from
   1.810 +					 * beginning of PairPos subtable--for
   1.811 +					 * the second glyph of the pair */
   1.812 +  USHORT	class1Count;		/* Number of classes in ClassDef1
   1.813 +					 * table--includes Class0 */
   1.814 +  USHORT	class2Count;		/* Number of classes in ClassDef2
   1.815 +					 * table--includes Class0 */
   1.816 +  ValueRecord	values;			/* Matrix of value pairs:
   1.817 +					 * class1-major, class2-minor,
   1.818 +					 * Each entry has value1 and value2 */
   1.819 +  public:
   1.820 +  DEFINE_SIZE_ARRAY (16, values);
   1.821 +};
   1.822 +
   1.823 +struct PairPos
   1.824 +{
   1.825 +  template <typename context_t>
   1.826 +  inline typename context_t::return_t dispatch (context_t *c) const
   1.827 +  {
   1.828 +    TRACE_DISPATCH (this);
   1.829 +    switch (u.format) {
   1.830 +    case 1: return TRACE_RETURN (c->dispatch (u.format1));
   1.831 +    case 2: return TRACE_RETURN (c->dispatch (u.format2));
   1.832 +    default:return TRACE_RETURN (c->default_return_value ());
   1.833 +    }
   1.834 +  }
   1.835 +
   1.836 +  inline bool sanitize (hb_sanitize_context_t *c) {
   1.837 +    TRACE_SANITIZE (this);
   1.838 +    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
   1.839 +    switch (u.format) {
   1.840 +    case 1: return TRACE_RETURN (u.format1.sanitize (c));
   1.841 +    case 2: return TRACE_RETURN (u.format2.sanitize (c));
   1.842 +    default:return TRACE_RETURN (true);
   1.843 +    }
   1.844 +  }
   1.845 +
   1.846 +  protected:
   1.847 +  union {
   1.848 +  USHORT		format;		/* Format identifier */
   1.849 +  PairPosFormat1	format1;
   1.850 +  PairPosFormat2	format2;
   1.851 +  } u;
   1.852 +};
   1.853 +
   1.854 +
   1.855 +struct EntryExitRecord
   1.856 +{
   1.857 +  friend struct CursivePosFormat1;
   1.858 +
   1.859 +  inline bool sanitize (hb_sanitize_context_t *c, void *base) {
   1.860 +    TRACE_SANITIZE (this);
   1.861 +    return TRACE_RETURN (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
   1.862 +  }
   1.863 +
   1.864 +  protected:
   1.865 +  OffsetTo<Anchor>
   1.866 +		entryAnchor;		/* Offset to EntryAnchor table--from
   1.867 +					 * beginning of CursivePos
   1.868 +					 * subtable--may be NULL */
   1.869 +  OffsetTo<Anchor>
   1.870 +		exitAnchor;		/* Offset to ExitAnchor table--from
   1.871 +					 * beginning of CursivePos
   1.872 +					 * subtable--may be NULL */
   1.873 +  public:
   1.874 +  DEFINE_SIZE_STATIC (4);
   1.875 +};
   1.876 +
   1.877 +struct CursivePosFormat1
   1.878 +{
   1.879 +  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
   1.880 +  {
   1.881 +    TRACE_COLLECT_GLYPHS (this);
   1.882 +    (this+coverage).add_coverage (c->input);
   1.883 +  }
   1.884 +
   1.885 +  inline const Coverage &get_coverage (void) const
   1.886 +  {
   1.887 +    return this+coverage;
   1.888 +  }
   1.889 +
   1.890 +  inline bool apply (hb_apply_context_t *c) const
   1.891 +  {
   1.892 +    TRACE_APPLY (this);
   1.893 +    hb_buffer_t *buffer = c->buffer;
   1.894 +
   1.895 +    /* We don't handle mark glyphs here. */
   1.896 +    if (unlikely (_hb_glyph_info_is_mark (&buffer->cur()))) return TRACE_RETURN (false);
   1.897 +
   1.898 +    hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1);
   1.899 +    if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
   1.900 +
   1.901 +    const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage  (buffer->cur().codepoint)];
   1.902 +    if (!this_record.exitAnchor) return TRACE_RETURN (false);
   1.903 +
   1.904 +    if (!skippy_iter.next ()) return TRACE_RETURN (false);
   1.905 +
   1.906 +    const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint)];
   1.907 +    if (!next_record.entryAnchor) return TRACE_RETURN (false);
   1.908 +
   1.909 +    unsigned int i = buffer->idx;
   1.910 +    unsigned int j = skippy_iter.idx;
   1.911 +
   1.912 +    hb_position_t entry_x, entry_y, exit_x, exit_y;
   1.913 +    (this+this_record.exitAnchor).get_anchor (c->font, buffer->info[i].codepoint, &exit_x, &exit_y);
   1.914 +    (this+next_record.entryAnchor).get_anchor (c->font, buffer->info[j].codepoint, &entry_x, &entry_y);
   1.915 +
   1.916 +    hb_glyph_position_t *pos = buffer->pos;
   1.917 +
   1.918 +    hb_position_t d;
   1.919 +    /* Main-direction adjustment */
   1.920 +    switch (c->direction) {
   1.921 +      case HB_DIRECTION_LTR:
   1.922 +	pos[i].x_advance  =  exit_x + pos[i].x_offset;
   1.923 +
   1.924 +	d = entry_x + pos[j].x_offset;
   1.925 +	pos[j].x_advance -= d;
   1.926 +	pos[j].x_offset  -= d;
   1.927 +	break;
   1.928 +      case HB_DIRECTION_RTL:
   1.929 +	d = exit_x + pos[i].x_offset;
   1.930 +	pos[i].x_advance -= d;
   1.931 +	pos[i].x_offset  -= d;
   1.932 +
   1.933 +	pos[j].x_advance  =  entry_x + pos[j].x_offset;
   1.934 +	break;
   1.935 +      case HB_DIRECTION_TTB:
   1.936 +	pos[i].y_advance  =  exit_y + pos[i].y_offset;
   1.937 +
   1.938 +	d = entry_y + pos[j].y_offset;
   1.939 +	pos[j].y_advance -= d;
   1.940 +	pos[j].y_offset  -= d;
   1.941 +	break;
   1.942 +      case HB_DIRECTION_BTT:
   1.943 +	d = exit_y + pos[i].y_offset;
   1.944 +	pos[i].y_advance -= d;
   1.945 +	pos[i].y_offset  -= d;
   1.946 +
   1.947 +	pos[j].y_advance  =  entry_y;
   1.948 +	break;
   1.949 +      case HB_DIRECTION_INVALID:
   1.950 +      default:
   1.951 +	break;
   1.952 +    }
   1.953 +
   1.954 +    /* Cross-direction adjustment */
   1.955 +    if  (c->lookup_props & LookupFlag::RightToLeft) {
   1.956 +      pos[i].cursive_chain() = j - i;
   1.957 +      if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
   1.958 +	pos[i].y_offset = entry_y - exit_y;
   1.959 +      else
   1.960 +	pos[i].x_offset = entry_x - exit_x;
   1.961 +    } else {
   1.962 +      pos[j].cursive_chain() = i - j;
   1.963 +      if (likely (HB_DIRECTION_IS_HORIZONTAL (c->direction)))
   1.964 +	pos[j].y_offset = exit_y - entry_y;
   1.965 +      else
   1.966 +	pos[j].x_offset = exit_x - entry_x;
   1.967 +    }
   1.968 +
   1.969 +    buffer->idx = j;
   1.970 +    return TRACE_RETURN (true);
   1.971 +  }
   1.972 +
   1.973 +  inline bool sanitize (hb_sanitize_context_t *c) {
   1.974 +    TRACE_SANITIZE (this);
   1.975 +    return TRACE_RETURN (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
   1.976 +  }
   1.977 +
   1.978 +  protected:
   1.979 +  USHORT	format;			/* Format identifier--format = 1 */
   1.980 +  OffsetTo<Coverage>
   1.981 +		coverage;		/* Offset to Coverage table--from
   1.982 +					 * beginning of subtable */
   1.983 +  ArrayOf<EntryExitRecord>
   1.984 +		entryExitRecord;	/* Array of EntryExit records--in
   1.985 +					 * Coverage Index order */
   1.986 +  public:
   1.987 +  DEFINE_SIZE_ARRAY (6, entryExitRecord);
   1.988 +};
   1.989 +
   1.990 +struct CursivePos
   1.991 +{
   1.992 +  template <typename context_t>
   1.993 +  inline typename context_t::return_t dispatch (context_t *c) const
   1.994 +  {
   1.995 +    TRACE_DISPATCH (this);
   1.996 +    switch (u.format) {
   1.997 +    case 1: return TRACE_RETURN (c->dispatch (u.format1));
   1.998 +    default:return TRACE_RETURN (c->default_return_value ());
   1.999 +    }
  1.1000 +  }
  1.1001 +
  1.1002 +  inline bool sanitize (hb_sanitize_context_t *c) {
  1.1003 +    TRACE_SANITIZE (this);
  1.1004 +    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
  1.1005 +    switch (u.format) {
  1.1006 +    case 1: return TRACE_RETURN (u.format1.sanitize (c));
  1.1007 +    default:return TRACE_RETURN (true);
  1.1008 +    }
  1.1009 +  }
  1.1010 +
  1.1011 +  protected:
  1.1012 +  union {
  1.1013 +  USHORT		format;		/* Format identifier */
  1.1014 +  CursivePosFormat1	format1;
  1.1015 +  } u;
  1.1016 +};
  1.1017 +
  1.1018 +
  1.1019 +typedef AnchorMatrix BaseArray;		/* base-major--
  1.1020 +					 * in order of BaseCoverage Index--,
  1.1021 +					 * mark-minor--
  1.1022 +					 * ordered by class--zero-based. */
  1.1023 +
  1.1024 +struct MarkBasePosFormat1
  1.1025 +{
  1.1026 +  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  1.1027 +  {
  1.1028 +    TRACE_COLLECT_GLYPHS (this);
  1.1029 +    (this+markCoverage).add_coverage (c->input);
  1.1030 +    (this+baseCoverage).add_coverage (c->input);
  1.1031 +  }
  1.1032 +
  1.1033 +  inline const Coverage &get_coverage (void) const
  1.1034 +  {
  1.1035 +    return this+markCoverage;
  1.1036 +  }
  1.1037 +
  1.1038 +  inline bool apply (hb_apply_context_t *c) const
  1.1039 +  {
  1.1040 +    TRACE_APPLY (this);
  1.1041 +    hb_buffer_t *buffer = c->buffer;
  1.1042 +    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
  1.1043 +    if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
  1.1044 +
  1.1045 +    /* now we search backwards for a non-mark glyph */
  1.1046 +    hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1);
  1.1047 +    skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
  1.1048 +    do {
  1.1049 +      if (!skippy_iter.prev ()) return TRACE_RETURN (false);
  1.1050 +      /* We only want to attach to the first of a MultipleSubst sequence.  Reject others. */
  1.1051 +      if (0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx])) break;
  1.1052 +      skippy_iter.reject ();
  1.1053 +    } while (1);
  1.1054 +
  1.1055 +    /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
  1.1056 +    if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { /*return TRACE_RETURN (false);*/ }
  1.1057 +
  1.1058 +    unsigned int base_index = (this+baseCoverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint);
  1.1059 +    if (base_index == NOT_COVERED) return TRACE_RETURN (false);
  1.1060 +
  1.1061 +    return TRACE_RETURN ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
  1.1062 +  }
  1.1063 +
  1.1064 +  inline bool sanitize (hb_sanitize_context_t *c) {
  1.1065 +    TRACE_SANITIZE (this);
  1.1066 +    return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && baseCoverage.sanitize (c, this) &&
  1.1067 +			 markArray.sanitize (c, this) && baseArray.sanitize (c, this, (unsigned int) classCount));
  1.1068 +  }
  1.1069 +
  1.1070 +  protected:
  1.1071 +  USHORT	format;			/* Format identifier--format = 1 */
  1.1072 +  OffsetTo<Coverage>
  1.1073 +		markCoverage;		/* Offset to MarkCoverage table--from
  1.1074 +					 * beginning of MarkBasePos subtable */
  1.1075 +  OffsetTo<Coverage>
  1.1076 +		baseCoverage;		/* Offset to BaseCoverage table--from
  1.1077 +					 * beginning of MarkBasePos subtable */
  1.1078 +  USHORT	classCount;		/* Number of classes defined for marks */
  1.1079 +  OffsetTo<MarkArray>
  1.1080 +		markArray;		/* Offset to MarkArray table--from
  1.1081 +					 * beginning of MarkBasePos subtable */
  1.1082 +  OffsetTo<BaseArray>
  1.1083 +		baseArray;		/* Offset to BaseArray table--from
  1.1084 +					 * beginning of MarkBasePos subtable */
  1.1085 +  public:
  1.1086 +  DEFINE_SIZE_STATIC (12);
  1.1087 +};
  1.1088 +
  1.1089 +struct MarkBasePos
  1.1090 +{
  1.1091 +  template <typename context_t>
  1.1092 +  inline typename context_t::return_t dispatch (context_t *c) const
  1.1093 +  {
  1.1094 +    TRACE_DISPATCH (this);
  1.1095 +    switch (u.format) {
  1.1096 +    case 1: return TRACE_RETURN (c->dispatch (u.format1));
  1.1097 +    default:return TRACE_RETURN (c->default_return_value ());
  1.1098 +    }
  1.1099 +  }
  1.1100 +
  1.1101 +  inline bool sanitize (hb_sanitize_context_t *c) {
  1.1102 +    TRACE_SANITIZE (this);
  1.1103 +    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
  1.1104 +    switch (u.format) {
  1.1105 +    case 1: return TRACE_RETURN (u.format1.sanitize (c));
  1.1106 +    default:return TRACE_RETURN (true);
  1.1107 +    }
  1.1108 +  }
  1.1109 +
  1.1110 +  protected:
  1.1111 +  union {
  1.1112 +  USHORT		format;		/* Format identifier */
  1.1113 +  MarkBasePosFormat1	format1;
  1.1114 +  } u;
  1.1115 +};
  1.1116 +
  1.1117 +
  1.1118 +typedef AnchorMatrix LigatureAttach;	/* component-major--
  1.1119 +					 * in order of writing direction--,
  1.1120 +					 * mark-minor--
  1.1121 +					 * ordered by class--zero-based. */
  1.1122 +
  1.1123 +typedef OffsetListOf<LigatureAttach> LigatureArray;
  1.1124 +					/* Array of LigatureAttach
  1.1125 +					 * tables ordered by
  1.1126 +					 * LigatureCoverage Index */
  1.1127 +
  1.1128 +struct MarkLigPosFormat1
  1.1129 +{
  1.1130 +  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  1.1131 +  {
  1.1132 +    TRACE_COLLECT_GLYPHS (this);
  1.1133 +    (this+markCoverage).add_coverage (c->input);
  1.1134 +    (this+ligatureCoverage).add_coverage (c->input);
  1.1135 +  }
  1.1136 +
  1.1137 +  inline const Coverage &get_coverage (void) const
  1.1138 +  {
  1.1139 +    return this+markCoverage;
  1.1140 +  }
  1.1141 +
  1.1142 +  inline bool apply (hb_apply_context_t *c) const
  1.1143 +  {
  1.1144 +    TRACE_APPLY (this);
  1.1145 +    hb_buffer_t *buffer = c->buffer;
  1.1146 +    unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
  1.1147 +    if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
  1.1148 +
  1.1149 +    /* now we search backwards for a non-mark glyph */
  1.1150 +    hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1);
  1.1151 +    skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
  1.1152 +    if (!skippy_iter.prev ()) return TRACE_RETURN (false);
  1.1153 +
  1.1154 +    /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
  1.1155 +    if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { /*return TRACE_RETURN (false);*/ }
  1.1156 +
  1.1157 +    unsigned int j = skippy_iter.idx;
  1.1158 +    unsigned int lig_index = (this+ligatureCoverage).get_coverage  (buffer->info[j].codepoint);
  1.1159 +    if (lig_index == NOT_COVERED) return TRACE_RETURN (false);
  1.1160 +
  1.1161 +    const LigatureArray& lig_array = this+ligatureArray;
  1.1162 +    const LigatureAttach& lig_attach = lig_array[lig_index];
  1.1163 +
  1.1164 +    /* Find component to attach to */
  1.1165 +    unsigned int comp_count = lig_attach.rows;
  1.1166 +    if (unlikely (!comp_count)) return TRACE_RETURN (false);
  1.1167 +
  1.1168 +    /* We must now check whether the ligature ID of the current mark glyph
  1.1169 +     * is identical to the ligature ID of the found ligature.  If yes, we
  1.1170 +     * can directly use the component index.  If not, we attach the mark
  1.1171 +     * glyph to the last component of the ligature. */
  1.1172 +    unsigned int comp_index;
  1.1173 +    unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]);
  1.1174 +    unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
  1.1175 +    unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
  1.1176 +    if (lig_id && lig_id == mark_id && mark_comp > 0)
  1.1177 +      comp_index = MIN (comp_count, _hb_glyph_info_get_lig_comp (&buffer->cur())) - 1;
  1.1178 +    else
  1.1179 +      comp_index = comp_count - 1;
  1.1180 +
  1.1181 +    return TRACE_RETURN ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
  1.1182 +  }
  1.1183 +
  1.1184 +  inline bool sanitize (hb_sanitize_context_t *c) {
  1.1185 +    TRACE_SANITIZE (this);
  1.1186 +    return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && ligatureCoverage.sanitize (c, this) &&
  1.1187 +			 markArray.sanitize (c, this) && ligatureArray.sanitize (c, this, (unsigned int) classCount));
  1.1188 +  }
  1.1189 +
  1.1190 +  protected:
  1.1191 +  USHORT	format;			/* Format identifier--format = 1 */
  1.1192 +  OffsetTo<Coverage>
  1.1193 +		markCoverage;		/* Offset to Mark Coverage table--from
  1.1194 +					 * beginning of MarkLigPos subtable */
  1.1195 +  OffsetTo<Coverage>
  1.1196 +		ligatureCoverage;	/* Offset to Ligature Coverage
  1.1197 +					 * table--from beginning of MarkLigPos
  1.1198 +					 * subtable */
  1.1199 +  USHORT	classCount;		/* Number of defined mark classes */
  1.1200 +  OffsetTo<MarkArray>
  1.1201 +		markArray;		/* Offset to MarkArray table--from
  1.1202 +					 * beginning of MarkLigPos subtable */
  1.1203 +  OffsetTo<LigatureArray>
  1.1204 +		ligatureArray;		/* Offset to LigatureArray table--from
  1.1205 +					 * beginning of MarkLigPos subtable */
  1.1206 +  public:
  1.1207 +  DEFINE_SIZE_STATIC (12);
  1.1208 +};
  1.1209 +
  1.1210 +struct MarkLigPos
  1.1211 +{
  1.1212 +  template <typename context_t>
  1.1213 +  inline typename context_t::return_t dispatch (context_t *c) const
  1.1214 +  {
  1.1215 +    TRACE_DISPATCH (this);
  1.1216 +    switch (u.format) {
  1.1217 +    case 1: return TRACE_RETURN (c->dispatch (u.format1));
  1.1218 +    default:return TRACE_RETURN (c->default_return_value ());
  1.1219 +    }
  1.1220 +  }
  1.1221 +
  1.1222 +  inline bool sanitize (hb_sanitize_context_t *c) {
  1.1223 +    TRACE_SANITIZE (this);
  1.1224 +    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
  1.1225 +    switch (u.format) {
  1.1226 +    case 1: return TRACE_RETURN (u.format1.sanitize (c));
  1.1227 +    default:return TRACE_RETURN (true);
  1.1228 +    }
  1.1229 +  }
  1.1230 +
  1.1231 +  protected:
  1.1232 +  union {
  1.1233 +  USHORT		format;		/* Format identifier */
  1.1234 +  MarkLigPosFormat1	format1;
  1.1235 +  } u;
  1.1236 +};
  1.1237 +
  1.1238 +
  1.1239 +typedef AnchorMatrix Mark2Array;	/* mark2-major--
  1.1240 +					 * in order of Mark2Coverage Index--,
  1.1241 +					 * mark1-minor--
  1.1242 +					 * ordered by class--zero-based. */
  1.1243 +
  1.1244 +struct MarkMarkPosFormat1
  1.1245 +{
  1.1246 +  inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
  1.1247 +  {
  1.1248 +    TRACE_COLLECT_GLYPHS (this);
  1.1249 +    (this+mark1Coverage).add_coverage (c->input);
  1.1250 +    (this+mark2Coverage).add_coverage (c->input);
  1.1251 +  }
  1.1252 +
  1.1253 +  inline const Coverage &get_coverage (void) const
  1.1254 +  {
  1.1255 +    return this+mark1Coverage;
  1.1256 +  }
  1.1257 +
  1.1258 +  inline bool apply (hb_apply_context_t *c) const
  1.1259 +  {
  1.1260 +    TRACE_APPLY (this);
  1.1261 +    hb_buffer_t *buffer = c->buffer;
  1.1262 +    unsigned int mark1_index = (this+mark1Coverage).get_coverage  (buffer->cur().codepoint);
  1.1263 +    if (likely (mark1_index == NOT_COVERED)) return TRACE_RETURN (false);
  1.1264 +
  1.1265 +    /* now we search backwards for a suitable mark glyph until a non-mark glyph */
  1.1266 +    hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1);
  1.1267 +    skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
  1.1268 +    if (!skippy_iter.prev ()) return TRACE_RETURN (false);
  1.1269 +
  1.1270 +    if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return TRACE_RETURN (false); }
  1.1271 +
  1.1272 +    unsigned int j = skippy_iter.idx;
  1.1273 +
  1.1274 +    unsigned int id1 = _hb_glyph_info_get_lig_id (&buffer->cur());
  1.1275 +    unsigned int id2 = _hb_glyph_info_get_lig_id (&buffer->info[j]);
  1.1276 +    unsigned int comp1 = _hb_glyph_info_get_lig_comp (&buffer->cur());
  1.1277 +    unsigned int comp2 = _hb_glyph_info_get_lig_comp (&buffer->info[j]);
  1.1278 +
  1.1279 +    if (likely (id1 == id2)) {
  1.1280 +      if (id1 == 0) /* Marks belonging to the same base. */
  1.1281 +	goto good;
  1.1282 +      else if (comp1 == comp2) /* Marks belonging to the same ligature component. */
  1.1283 +        goto good;
  1.1284 +    } else {
  1.1285 +      /* If ligature ids don't match, it may be the case that one of the marks
  1.1286 +       * itself is a ligature.  In which case match. */
  1.1287 +      if ((id1 > 0 && !comp1) || (id2 > 0 && !comp2))
  1.1288 +	goto good;
  1.1289 +    }
  1.1290 +
  1.1291 +    /* Didn't match. */
  1.1292 +    return TRACE_RETURN (false);
  1.1293 +
  1.1294 +    good:
  1.1295 +    unsigned int mark2_index = (this+mark2Coverage).get_coverage  (buffer->info[j].codepoint);
  1.1296 +    if (mark2_index == NOT_COVERED) return TRACE_RETURN (false);
  1.1297 +
  1.1298 +    return TRACE_RETURN ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
  1.1299 +  }
  1.1300 +
  1.1301 +  inline bool sanitize (hb_sanitize_context_t *c) {
  1.1302 +    TRACE_SANITIZE (this);
  1.1303 +    return TRACE_RETURN (c->check_struct (this) && mark1Coverage.sanitize (c, this) &&
  1.1304 +			 mark2Coverage.sanitize (c, this) && mark1Array.sanitize (c, this)
  1.1305 +			 && mark2Array.sanitize (c, this, (unsigned int) classCount));
  1.1306 +  }
  1.1307 +
  1.1308 +  protected:
  1.1309 +  USHORT	format;			/* Format identifier--format = 1 */
  1.1310 +  OffsetTo<Coverage>
  1.1311 +		mark1Coverage;		/* Offset to Combining Mark1 Coverage
  1.1312 +					 * table--from beginning of MarkMarkPos
  1.1313 +					 * subtable */
  1.1314 +  OffsetTo<Coverage>
  1.1315 +		mark2Coverage;		/* Offset to Combining Mark2 Coverage
  1.1316 +					 * table--from beginning of MarkMarkPos
  1.1317 +					 * subtable */
  1.1318 +  USHORT	classCount;		/* Number of defined mark classes */
  1.1319 +  OffsetTo<MarkArray>
  1.1320 +		mark1Array;		/* Offset to Mark1Array table--from
  1.1321 +					 * beginning of MarkMarkPos subtable */
  1.1322 +  OffsetTo<Mark2Array>
  1.1323 +		mark2Array;		/* Offset to Mark2Array table--from
  1.1324 +					 * beginning of MarkMarkPos subtable */
  1.1325 +  public:
  1.1326 +  DEFINE_SIZE_STATIC (12);
  1.1327 +};
  1.1328 +
  1.1329 +struct MarkMarkPos
  1.1330 +{
  1.1331 +  template <typename context_t>
  1.1332 +  inline typename context_t::return_t dispatch (context_t *c) const
  1.1333 +  {
  1.1334 +    TRACE_DISPATCH (this);
  1.1335 +    switch (u.format) {
  1.1336 +    case 1: return TRACE_RETURN (c->dispatch (u.format1));
  1.1337 +    default:return TRACE_RETURN (c->default_return_value ());
  1.1338 +    }
  1.1339 +  }
  1.1340 +
  1.1341 +  inline bool sanitize (hb_sanitize_context_t *c) {
  1.1342 +    TRACE_SANITIZE (this);
  1.1343 +    if (!u.format.sanitize (c)) return TRACE_RETURN (false);
  1.1344 +    switch (u.format) {
  1.1345 +    case 1: return TRACE_RETURN (u.format1.sanitize (c));
  1.1346 +    default:return TRACE_RETURN (true);
  1.1347 +    }
  1.1348 +  }
  1.1349 +
  1.1350 +  protected:
  1.1351 +  union {
  1.1352 +  USHORT		format;		/* Format identifier */
  1.1353 +  MarkMarkPosFormat1	format1;
  1.1354 +  } u;
  1.1355 +};
  1.1356 +
  1.1357 +
  1.1358 +struct ContextPos : Context {};
  1.1359 +
  1.1360 +struct ChainContextPos : ChainContext {};
  1.1361 +
  1.1362 +struct ExtensionPos : Extension<ExtensionPos>
  1.1363 +{
  1.1364 +  typedef struct PosLookupSubTable LookupSubTable;
  1.1365 +};
  1.1366 +
  1.1367 +
  1.1368 +
  1.1369 +/*
  1.1370 + * PosLookup
  1.1371 + */
  1.1372 +
  1.1373 +
  1.1374 +struct PosLookupSubTable
  1.1375 +{
  1.1376 +  friend struct PosLookup;
  1.1377 +
  1.1378 +  enum Type {
  1.1379 +    Single		= 1,
  1.1380 +    Pair		= 2,
  1.1381 +    Cursive		= 3,
  1.1382 +    MarkBase		= 4,
  1.1383 +    MarkLig		= 5,
  1.1384 +    MarkMark		= 6,
  1.1385 +    Context		= 7,
  1.1386 +    ChainContext	= 8,
  1.1387 +    Extension		= 9
  1.1388 +  };
  1.1389 +
  1.1390 +  template <typename context_t>
  1.1391 +  inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
  1.1392 +  {
  1.1393 +    TRACE_DISPATCH (this);
  1.1394 +    switch (lookup_type) {
  1.1395 +    case Single:		return TRACE_RETURN (u.single.dispatch (c));
  1.1396 +    case Pair:			return TRACE_RETURN (u.pair.dispatch (c));
  1.1397 +    case Cursive:		return TRACE_RETURN (u.cursive.dispatch (c));
  1.1398 +    case MarkBase:		return TRACE_RETURN (u.markBase.dispatch (c));
  1.1399 +    case MarkLig:		return TRACE_RETURN (u.markLig.dispatch (c));
  1.1400 +    case MarkMark:		return TRACE_RETURN (u.markMark.dispatch (c));
  1.1401 +    case Context:		return TRACE_RETURN (u.context.dispatch (c));
  1.1402 +    case ChainContext:		return TRACE_RETURN (u.chainContext.dispatch (c));
  1.1403 +    case Extension:		return TRACE_RETURN (u.extension.dispatch (c));
  1.1404 +    default:			return TRACE_RETURN (c->default_return_value ());
  1.1405 +    }
  1.1406 +  }
  1.1407 +
  1.1408 +  inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
  1.1409 +    TRACE_SANITIZE (this);
  1.1410 +    if (!u.header.sub_format.sanitize (c))
  1.1411 +      return TRACE_RETURN (false);
  1.1412 +    switch (lookup_type) {
  1.1413 +    case Single:		return TRACE_RETURN (u.single.sanitize (c));
  1.1414 +    case Pair:			return TRACE_RETURN (u.pair.sanitize (c));
  1.1415 +    case Cursive:		return TRACE_RETURN (u.cursive.sanitize (c));
  1.1416 +    case MarkBase:		return TRACE_RETURN (u.markBase.sanitize (c));
  1.1417 +    case MarkLig:		return TRACE_RETURN (u.markLig.sanitize (c));
  1.1418 +    case MarkMark:		return TRACE_RETURN (u.markMark.sanitize (c));
  1.1419 +    case Context:		return TRACE_RETURN (u.context.sanitize (c));
  1.1420 +    case ChainContext:		return TRACE_RETURN (u.chainContext.sanitize (c));
  1.1421 +    case Extension:		return TRACE_RETURN (u.extension.sanitize (c));
  1.1422 +    default:			return TRACE_RETURN (true);
  1.1423 +    }
  1.1424 +  }
  1.1425 +
  1.1426 +  protected:
  1.1427 +  union {
  1.1428 +  struct {
  1.1429 +    USHORT		sub_format;
  1.1430 +  } header;
  1.1431 +  SinglePos		single;
  1.1432 +  PairPos		pair;
  1.1433 +  CursivePos		cursive;
  1.1434 +  MarkBasePos		markBase;
  1.1435 +  MarkLigPos		markLig;
  1.1436 +  MarkMarkPos		markMark;
  1.1437 +  ContextPos		context;
  1.1438 +  ChainContextPos	chainContext;
  1.1439 +  ExtensionPos		extension;
  1.1440 +  } u;
  1.1441 +  public:
  1.1442 +  DEFINE_SIZE_UNION (2, header.sub_format);
  1.1443 +};
  1.1444 +
  1.1445 +
  1.1446 +struct PosLookup : Lookup
  1.1447 +{
  1.1448 +  inline const PosLookupSubTable& get_subtable (unsigned int i) const
  1.1449 +  { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
  1.1450 +
  1.1451 +  inline bool is_reverse (void) const
  1.1452 +  {
  1.1453 +    return false;
  1.1454 +  }
  1.1455 +
  1.1456 +  inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
  1.1457 +  {
  1.1458 +    TRACE_COLLECT_GLYPHS (this);
  1.1459 +    c->set_recurse_func (NULL);
  1.1460 +    return TRACE_RETURN (dispatch (c));
  1.1461 +  }
  1.1462 +
  1.1463 +  template <typename set_t>
  1.1464 +  inline void add_coverage (set_t *glyphs) const
  1.1465 +  {
  1.1466 +    hb_get_coverage_context_t c;
  1.1467 +    const Coverage *last = NULL;
  1.1468 +    unsigned int count = get_subtable_count ();
  1.1469 +    for (unsigned int i = 0; i < count; i++) {
  1.1470 +      const Coverage *coverage = &get_subtable (i).dispatch (&c, get_type ());
  1.1471 +      if (coverage != last) {
  1.1472 +        coverage->add_coverage (glyphs);
  1.1473 +        last = coverage;
  1.1474 +      }
  1.1475 +    }
  1.1476 +  }
  1.1477 +
  1.1478 +  inline bool apply_once (hb_apply_context_t *c) const
  1.1479 +  {
  1.1480 +    TRACE_APPLY (this);
  1.1481 +    if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
  1.1482 +      return TRACE_RETURN (false);
  1.1483 +    return TRACE_RETURN (dispatch (c));
  1.1484 +  }
  1.1485 +
  1.1486 +  static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
  1.1487 +
  1.1488 +  template <typename context_t>
  1.1489 +  static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
  1.1490 +
  1.1491 +  template <typename context_t>
  1.1492 +  inline typename context_t::return_t dispatch (context_t *c) const
  1.1493 +  {
  1.1494 +    TRACE_DISPATCH (this);
  1.1495 +    unsigned int lookup_type = get_type ();
  1.1496 +    unsigned int count = get_subtable_count ();
  1.1497 +    for (unsigned int i = 0; i < count; i++) {
  1.1498 +      typename context_t::return_t r = get_subtable (i).dispatch (c, lookup_type);
  1.1499 +      if (c->stop_sublookup_iteration (r))
  1.1500 +        return TRACE_RETURN (r);
  1.1501 +    }
  1.1502 +    return TRACE_RETURN (c->default_return_value ());
  1.1503 +  }
  1.1504 +
  1.1505 +  inline bool sanitize (hb_sanitize_context_t *c) {
  1.1506 +    TRACE_SANITIZE (this);
  1.1507 +    if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
  1.1508 +    OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
  1.1509 +    return TRACE_RETURN (list.sanitize (c, this, get_type ()));
  1.1510 +  }
  1.1511 +};
  1.1512 +
  1.1513 +typedef OffsetListOf<PosLookup> PosLookupList;
  1.1514 +
  1.1515 +/*
  1.1516 + * GPOS -- The Glyph Positioning Table
  1.1517 + */
  1.1518 +
  1.1519 +struct GPOS : GSUBGPOS
  1.1520 +{
  1.1521 +  static const hb_tag_t tableTag	= HB_OT_TAG_GPOS;
  1.1522 +
  1.1523 +  inline const PosLookup& get_lookup (unsigned int i) const
  1.1524 +  { return CastR<PosLookup> (GSUBGPOS::get_lookup (i)); }
  1.1525 +
  1.1526 +  static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
  1.1527 +  static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer);
  1.1528 +
  1.1529 +  inline bool sanitize (hb_sanitize_context_t *c) {
  1.1530 +    TRACE_SANITIZE (this);
  1.1531 +    if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
  1.1532 +    OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
  1.1533 +    return TRACE_RETURN (list.sanitize (c, this));
  1.1534 +  }
  1.1535 +  public:
  1.1536 +  DEFINE_SIZE_STATIC (10);
  1.1537 +};
  1.1538 +
  1.1539 +
  1.1540 +static void
  1.1541 +fix_cursive_minor_offset (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
  1.1542 +{
  1.1543 +  unsigned int j = pos[i].cursive_chain();
  1.1544 +  if (likely (!j))
  1.1545 +    return;
  1.1546 +
  1.1547 +  j += i;
  1.1548 +
  1.1549 +  pos[i].cursive_chain() = 0;
  1.1550 +
  1.1551 +  fix_cursive_minor_offset (pos, j, direction);
  1.1552 +
  1.1553 +  if (HB_DIRECTION_IS_HORIZONTAL (direction))
  1.1554 +    pos[i].y_offset += pos[j].y_offset;
  1.1555 +  else
  1.1556 +    pos[i].x_offset += pos[j].x_offset;
  1.1557 +}
  1.1558 +
  1.1559 +static void
  1.1560 +fix_mark_attachment (hb_glyph_position_t *pos, unsigned int i, hb_direction_t direction)
  1.1561 +{
  1.1562 +  if (likely (!(pos[i].attach_lookback())))
  1.1563 +    return;
  1.1564 +
  1.1565 +  unsigned int j = i - pos[i].attach_lookback();
  1.1566 +
  1.1567 +  pos[i].x_offset += pos[j].x_offset;
  1.1568 +  pos[i].y_offset += pos[j].y_offset;
  1.1569 +
  1.1570 +  if (HB_DIRECTION_IS_FORWARD (direction))
  1.1571 +    for (unsigned int k = j; k < i; k++) {
  1.1572 +      pos[i].x_offset -= pos[k].x_advance;
  1.1573 +      pos[i].y_offset -= pos[k].y_advance;
  1.1574 +    }
  1.1575 +  else
  1.1576 +    for (unsigned int k = j + 1; k < i + 1; k++) {
  1.1577 +      pos[i].x_offset += pos[k].x_advance;
  1.1578 +      pos[i].y_offset += pos[k].y_advance;
  1.1579 +    }
  1.1580 +}
  1.1581 +
  1.1582 +void
  1.1583 +GPOS::position_start (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
  1.1584 +{
  1.1585 +  buffer->clear_positions ();
  1.1586 +
  1.1587 +  unsigned int count = buffer->len;
  1.1588 +  for (unsigned int i = 0; i < count; i++)
  1.1589 +    buffer->pos[i].attach_lookback() = buffer->pos[i].cursive_chain() = 0;
  1.1590 +}
  1.1591 +
  1.1592 +void
  1.1593 +GPOS::position_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
  1.1594 +{
  1.1595 +  unsigned int len;
  1.1596 +  hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (buffer, &len);
  1.1597 +  hb_direction_t direction = buffer->props.direction;
  1.1598 +
  1.1599 +  /* Handle cursive connections */
  1.1600 +  for (unsigned int i = 0; i < len; i++)
  1.1601 +    fix_cursive_minor_offset (pos, i, direction);
  1.1602 +
  1.1603 +  /* Handle attachments */
  1.1604 +  for (unsigned int i = 0; i < len; i++)
  1.1605 +    fix_mark_attachment (pos, i, direction);
  1.1606 +
  1.1607 +  _hb_buffer_deallocate_gsubgpos_vars (buffer);
  1.1608 +}
  1.1609 +
  1.1610 +
  1.1611 +/* Out-of-class implementation for methods recursing */
  1.1612 +
  1.1613 +template <typename context_t>
  1.1614 +inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
  1.1615 +{
  1.1616 +  const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
  1.1617 +  const PosLookup &l = gpos.get_lookup (lookup_index);
  1.1618 +  return l.dispatch (c);
  1.1619 +}
  1.1620 +
  1.1621 +inline bool PosLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index)
  1.1622 +{
  1.1623 +  const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
  1.1624 +  const PosLookup &l = gpos.get_lookup (lookup_index);
  1.1625 +  unsigned int saved_lookup_props = c->lookup_props;
  1.1626 +  c->set_lookup (l);
  1.1627 +  bool ret = l.apply_once (c);
  1.1628 +  c->lookup_props = saved_lookup_props;
  1.1629 +  return ret;
  1.1630 +}
  1.1631 +
  1.1632 +
  1.1633 +#undef attach_lookback
  1.1634 +#undef cursive_chain
  1.1635 +
  1.1636 +
  1.1637 +} /* namespace OT */
  1.1638 +
  1.1639 +
  1.1640 +#endif /* HB_OT_LAYOUT_GPOS_TABLE_HH */

mercurial