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

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial