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