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_GSUBGPOS_PRIVATE_HH |
| 30 #define HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH |
| 31 |
| 32 #include "hb-buffer-private.hh" |
| 33 #include "hb-ot-layout-gdef-private.hh" |
| 34 |
| 35 HB_BEGIN_DECLS |
| 36 |
| 37 |
| 38 /* buffer var allocations */ |
| 39 #define lig_id() var2.u16[0] /* unique ligature id */ |
| 40 #define lig_comp() var2.u16[1] /* component number in the ligature (0 = base) */ |
| 41 |
| 42 |
| 43 #ifndef HB_DEBUG_APPLY |
| 44 #define HB_DEBUG_APPLY (HB_DEBUG+0) |
| 45 #endif |
| 46 |
| 47 #define TRACE_APPLY() \ |
| 48 hb_trace_t<HB_DEBUG_APPLY> trace (&c->debug_depth, "APPLY", HB_FUNC, thi
s); \ |
| 49 |
| 50 |
| 51 HB_BEGIN_DECLS |
| 52 |
| 53 struct hb_apply_context_t |
| 54 { |
| 55 unsigned int debug_depth; |
| 56 hb_ot_layout_context_t *layout; |
| 57 hb_buffer_t *buffer; |
| 58 hb_mask_t lookup_mask; |
| 59 unsigned int context_length; |
| 60 unsigned int nesting_level_left; |
| 61 unsigned int lookup_props; |
| 62 unsigned int property; /* propety of first glyph */ |
| 63 |
| 64 |
| 65 inline void replace_glyph (hb_codepoint_t glyph_index) const |
| 66 { |
| 67 clear_property (); |
| 68 buffer->replace_glyph (glyph_index); |
| 69 } |
| 70 inline void replace_glyphs_be16 (unsigned int num_in, |
| 71 unsigned int num_out, |
| 72 const uint16_t *glyph_data_be) const |
| 73 { |
| 74 clear_property (); |
| 75 buffer->replace_glyphs_be16 (num_in, num_out, glyph_data_be); |
| 76 } |
| 77 |
| 78 inline void guess_glyph_class (unsigned int klass) |
| 79 { |
| 80 /* XXX if ! has gdef */ |
| 81 buffer->info[buffer->i].props_cache() = klass; |
| 82 } |
| 83 |
| 84 private: |
| 85 inline void clear_property (void) const |
| 86 { |
| 87 /* XXX if has gdef */ |
| 88 buffer->info[buffer->i].props_cache() = 0; |
| 89 } |
| 90 }; |
| 91 |
| 92 |
| 93 |
| 94 typedef bool (*match_func_t) (hb_codepoint_t glyph_id, const USHORT &value, cons
t void *data); |
| 95 typedef bool (*apply_lookup_func_t) (hb_apply_context_t *c, unsigned int lookup_
index); |
| 96 |
| 97 struct ContextFuncs |
| 98 { |
| 99 match_func_t match; |
| 100 apply_lookup_func_t apply; |
| 101 }; |
| 102 |
| 103 |
| 104 static inline bool match_glyph (hb_codepoint_t glyph_id, const USHORT &value, co
nst void *data HB_UNUSED) |
| 105 { |
| 106 return glyph_id == value; |
| 107 } |
| 108 |
| 109 static inline bool match_class (hb_codepoint_t glyph_id, const USHORT &value, co
nst void *data) |
| 110 { |
| 111 const ClassDef &class_def = *reinterpret_cast<const ClassDef *>(data); |
| 112 return class_def.get_class (glyph_id) == value; |
| 113 } |
| 114 |
| 115 static inline bool match_coverage (hb_codepoint_t glyph_id, const USHORT &value,
const void *data) |
| 116 { |
| 117 const OffsetTo<Coverage> &coverage = (const OffsetTo<Coverage>&)value; |
| 118 return (data+coverage) (glyph_id) != NOT_COVERED; |
| 119 } |
| 120 |
| 121 |
| 122 static inline bool match_input (hb_apply_context_t *c, |
| 123 unsigned int count, /* Including the first glyph
(not matched) */ |
| 124 const USHORT input[], /* Array of input values--
start with second glyph */ |
| 125 match_func_t match_func, |
| 126 const void *match_data, |
| 127 unsigned int *context_length_out) |
| 128 { |
| 129 unsigned int i, j; |
| 130 unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length); |
| 131 if (unlikely (c->buffer->i + count > end)) |
| 132 return false; |
| 133 |
| 134 for (i = 1, j = c->buffer->i + 1; i < count; i++, j++) |
| 135 { |
| 136 while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->loo
kup_props, NULL)) |
| 137 { |
| 138 if (unlikely (j + count - i == end)) |
| 139 return false; |
| 140 j++; |
| 141 } |
| 142 |
| 143 if (likely (!match_func (c->buffer->info[j].codepoint, input[i - 1], match_d
ata))) |
| 144 return false; |
| 145 } |
| 146 |
| 147 *context_length_out = j - c->buffer->i; |
| 148 |
| 149 return true; |
| 150 } |
| 151 |
| 152 static inline bool match_backtrack (hb_apply_context_t *c, |
| 153 unsigned int count, |
| 154 const USHORT backtrack[], |
| 155 match_func_t match_func, |
| 156 const void *match_data) |
| 157 { |
| 158 if (unlikely (c->buffer->out_len < count)) |
| 159 return false; |
| 160 |
| 161 for (unsigned int i = 0, j = c->buffer->out_len - 1; i < count; i++, j--) |
| 162 { |
| 163 while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->out_info[j], c-
>lookup_props, NULL)) |
| 164 { |
| 165 if (unlikely (j + 1 == count - i)) |
| 166 return false; |
| 167 j--; |
| 168 } |
| 169 |
| 170 if (likely (!match_func (c->buffer->out_info[j].codepoint, backtrack[i], mat
ch_data))) |
| 171 return false; |
| 172 } |
| 173 |
| 174 return true; |
| 175 } |
| 176 |
| 177 static inline bool match_lookahead (hb_apply_context_t *c, |
| 178 unsigned int count, |
| 179 const USHORT lookahead[], |
| 180 match_func_t match_func, |
| 181 const void *match_data, |
| 182 unsigned int offset) |
| 183 { |
| 184 unsigned int i, j; |
| 185 unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length); |
| 186 if (unlikely (c->buffer->i + offset + count > end)) |
| 187 return false; |
| 188 |
| 189 for (i = 0, j = c->buffer->i + offset; i < count; i++, j++) |
| 190 { |
| 191 while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[j], c->loo
kup_props, NULL)) |
| 192 { |
| 193 if (unlikely (j + count - i == end)) |
| 194 return false; |
| 195 j++; |
| 196 } |
| 197 |
| 198 if (likely (!match_func (c->buffer->info[j].codepoint, lookahead[i], match_d
ata))) |
| 199 return false; |
| 200 } |
| 201 |
| 202 return true; |
| 203 } |
| 204 |
| 205 HB_END_DECLS |
| 206 |
| 207 |
| 208 struct LookupRecord |
| 209 { |
| 210 inline bool sanitize (hb_sanitize_context_t *c) { |
| 211 TRACE_SANITIZE (); |
| 212 return c->check_struct (this); |
| 213 } |
| 214 |
| 215 USHORT sequenceIndex; /* Index into current glyph |
| 216 * sequence--first glyph = 0 */ |
| 217 USHORT lookupListIndex; /* Lookup to apply to that |
| 218 * position--zero--based */ |
| 219 public: |
| 220 DEFINE_SIZE_STATIC (4); |
| 221 }; |
| 222 |
| 223 |
| 224 HB_BEGIN_DECLS |
| 225 |
| 226 static inline bool apply_lookup (hb_apply_context_t *c, |
| 227 unsigned int count, /* Including the first glyp
h */ |
| 228 unsigned int lookupCount, |
| 229 const LookupRecord lookupRecord[], /* Array of
LookupRecords--in design order */ |
| 230 apply_lookup_func_t apply_func) |
| 231 { |
| 232 unsigned int end = MIN (c->buffer->len, c->buffer->i + c->context_length); |
| 233 if (unlikely (count == 0 || c->buffer->i + count > end)) |
| 234 return false; |
| 235 |
| 236 /* TODO We don't support lookupRecord arrays that are not increasing: |
| 237 * Should be easy for in_place ones at least. */ |
| 238 |
| 239 /* Note: If sublookup is reverse, it will underflow after the first loop |
| 240 * and we jump out of it. Not entirely disastrous. So we don't check |
| 241 * for reverse lookup here. |
| 242 */ |
| 243 for (unsigned int i = 0; i < count; /* NOP */) |
| 244 { |
| 245 while (_hb_ot_layout_skip_mark (c->layout->face, &c->buffer->info[c->buffer-
>i], c->lookup_props, NULL)) |
| 246 { |
| 247 if (unlikely (c->buffer->i == end)) |
| 248 return true; |
| 249 /* No lookup applied for this index */ |
| 250 c->buffer->next_glyph (); |
| 251 } |
| 252 |
| 253 if (lookupCount && i == lookupRecord->sequenceIndex) |
| 254 { |
| 255 unsigned int old_pos = c->buffer->i; |
| 256 |
| 257 /* Apply a lookup */ |
| 258 bool done = apply_func (c, lookupRecord->lookupListIndex); |
| 259 |
| 260 lookupRecord++; |
| 261 lookupCount--; |
| 262 /* Err, this is wrong if the lookup jumped over some glyphs */ |
| 263 i += c->buffer->i - old_pos; |
| 264 if (unlikely (c->buffer->i == end)) |
| 265 return true; |
| 266 |
| 267 if (!done) |
| 268 goto not_applied; |
| 269 } |
| 270 else |
| 271 { |
| 272 not_applied: |
| 273 /* No lookup applied for this index */ |
| 274 c->buffer->next_glyph (); |
| 275 i++; |
| 276 } |
| 277 } |
| 278 |
| 279 return true; |
| 280 } |
| 281 |
| 282 HB_END_DECLS |
| 283 |
| 284 |
| 285 /* Contextual lookups */ |
| 286 |
| 287 struct ContextLookupContext |
| 288 { |
| 289 ContextFuncs funcs; |
| 290 const void *match_data; |
| 291 }; |
| 292 |
| 293 static inline bool context_lookup (hb_apply_context_t *c, |
| 294 unsigned int inputCount, /* Including the fir
st glyph (not matched) */ |
| 295 const USHORT input[], /* Array of input value
s--start with second glyph */ |
| 296 unsigned int lookupCount, |
| 297 const LookupRecord lookupRecord[], |
| 298 ContextLookupContext &lookup_context) |
| 299 { |
| 300 hb_apply_context_t new_context = *c; |
| 301 return match_input (c, |
| 302 inputCount, input, |
| 303 lookup_context.funcs.match, lookup_context.match_data, |
| 304 &new_context.context_length) |
| 305 && apply_lookup (&new_context, |
| 306 inputCount, |
| 307 lookupCount, lookupRecord, |
| 308 lookup_context.funcs.apply); |
| 309 } |
| 310 |
| 311 struct Rule |
| 312 { |
| 313 friend struct RuleSet; |
| 314 |
| 315 private: |
| 316 inline bool apply (hb_apply_context_t *c, ContextLookupContext &lookup_context
) const |
| 317 { |
| 318 TRACE_APPLY (); |
| 319 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (input, inp
ut[0].static_size * (inputCount ? inputCount - 1 : 0)); |
| 320 return context_lookup (c, |
| 321 inputCount, input, |
| 322 lookupCount, lookupRecord, |
| 323 lookup_context); |
| 324 } |
| 325 |
| 326 public: |
| 327 inline bool sanitize (hb_sanitize_context_t *c) { |
| 328 TRACE_SANITIZE (); |
| 329 return inputCount.sanitize (c) |
| 330 && lookupCount.sanitize (c) |
| 331 && c->check_range (input, |
| 332 input[0].static_size * inputCount |
| 333 + lookupRecordX[0].static_size * lookupCount); |
| 334 } |
| 335 |
| 336 private: |
| 337 USHORT inputCount; /* Total number of glyphs in input |
| 338 * glyph sequence--includes the first |
| 339 * glyph */ |
| 340 USHORT lookupCount; /* Number of LookupRecords */ |
| 341 USHORT input[VAR]; /* Array of match inputs--start with |
| 342 * second glyph */ |
| 343 LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in |
| 344 * design order */ |
| 345 public: |
| 346 DEFINE_SIZE_ARRAY2 (4, input, lookupRecordX); |
| 347 }; |
| 348 |
| 349 struct RuleSet |
| 350 { |
| 351 inline bool apply (hb_apply_context_t *c, ContextLookupContext &lookup_context
) const |
| 352 { |
| 353 TRACE_APPLY (); |
| 354 unsigned int num_rules = rule.len; |
| 355 for (unsigned int i = 0; i < num_rules; i++) |
| 356 { |
| 357 if ((this+rule[i]).apply (c, lookup_context)) |
| 358 return true; |
| 359 } |
| 360 |
| 361 return false; |
| 362 } |
| 363 |
| 364 inline bool sanitize (hb_sanitize_context_t *c) { |
| 365 TRACE_SANITIZE (); |
| 366 return rule.sanitize (c, this); |
| 367 } |
| 368 |
| 369 private: |
| 370 OffsetArrayOf<Rule> |
| 371 rule; /* Array of Rule tables |
| 372 * ordered by preference */ |
| 373 public: |
| 374 DEFINE_SIZE_ARRAY (2, rule); |
| 375 }; |
| 376 |
| 377 |
| 378 struct ContextFormat1 |
| 379 { |
| 380 friend struct Context; |
| 381 |
| 382 private: |
| 383 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) cons
t |
| 384 { |
| 385 TRACE_APPLY (); |
| 386 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoin
t); |
| 387 if (likely (index == NOT_COVERED)) |
| 388 return false; |
| 389 |
| 390 const RuleSet &rule_set = this+ruleSet[index]; |
| 391 struct ContextLookupContext lookup_context = { |
| 392 {match_glyph, apply_func}, |
| 393 NULL |
| 394 }; |
| 395 return rule_set.apply (c, lookup_context); |
| 396 } |
| 397 |
| 398 inline bool sanitize (hb_sanitize_context_t *c) { |
| 399 TRACE_SANITIZE (); |
| 400 return coverage.sanitize (c, this) |
| 401 && ruleSet.sanitize (c, this); |
| 402 } |
| 403 |
| 404 private: |
| 405 USHORT format; /* Format identifier--format = 1 */ |
| 406 OffsetTo<Coverage> |
| 407 coverage; /* Offset to Coverage table--from |
| 408 * beginning of table */ |
| 409 OffsetArrayOf<RuleSet> |
| 410 ruleSet; /* Array of RuleSet tables |
| 411 * ordered by Coverage Index */ |
| 412 public: |
| 413 DEFINE_SIZE_ARRAY (6, ruleSet); |
| 414 }; |
| 415 |
| 416 |
| 417 struct ContextFormat2 |
| 418 { |
| 419 friend struct Context; |
| 420 |
| 421 private: |
| 422 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) cons
t |
| 423 { |
| 424 TRACE_APPLY (); |
| 425 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoin
t); |
| 426 if (likely (index == NOT_COVERED)) |
| 427 return false; |
| 428 |
| 429 const ClassDef &class_def = this+classDef; |
| 430 index = class_def (c->buffer->info[c->buffer->i].codepoint); |
| 431 const RuleSet &rule_set = this+ruleSet[index]; |
| 432 struct ContextLookupContext lookup_context = { |
| 433 {match_class, apply_func}, |
| 434 &class_def |
| 435 }; |
| 436 return rule_set.apply (c, lookup_context); |
| 437 } |
| 438 |
| 439 inline bool sanitize (hb_sanitize_context_t *c) { |
| 440 TRACE_SANITIZE (); |
| 441 return coverage.sanitize (c, this) |
| 442 && classDef.sanitize (c, this) |
| 443 && ruleSet.sanitize (c, this); |
| 444 } |
| 445 |
| 446 private: |
| 447 USHORT format; /* Format identifier--format = 2 */ |
| 448 OffsetTo<Coverage> |
| 449 coverage; /* Offset to Coverage table--from |
| 450 * beginning of table */ |
| 451 OffsetTo<ClassDef> |
| 452 classDef; /* Offset to glyph ClassDef table--from |
| 453 * beginning of table */ |
| 454 OffsetArrayOf<RuleSet> |
| 455 ruleSet; /* Array of RuleSet tables |
| 456 * ordered by class */ |
| 457 public: |
| 458 DEFINE_SIZE_ARRAY (8, ruleSet); |
| 459 }; |
| 460 |
| 461 |
| 462 struct ContextFormat3 |
| 463 { |
| 464 friend struct Context; |
| 465 |
| 466 private: |
| 467 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) cons
t |
| 468 { |
| 469 TRACE_APPLY (); |
| 470 unsigned int index = (this+coverage[0]) (c->buffer->info[c->buffer->i].codep
oint); |
| 471 if (likely (index == NOT_COVERED)) |
| 472 return false; |
| 473 |
| 474 const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage,
coverage[0].static_size * glyphCount); |
| 475 struct ContextLookupContext lookup_context = { |
| 476 {match_coverage, apply_func}, |
| 477 this |
| 478 }; |
| 479 return context_lookup (c, |
| 480 glyphCount, (const USHORT *) (coverage + 1), |
| 481 lookupCount, lookupRecord, |
| 482 lookup_context); |
| 483 } |
| 484 |
| 485 inline bool sanitize (hb_sanitize_context_t *c) { |
| 486 TRACE_SANITIZE (); |
| 487 if (!c->check_struct (this)) return false; |
| 488 unsigned int count = glyphCount; |
| 489 if (!c->check_array (coverage, coverage[0].static_size, count)) return false
; |
| 490 for (unsigned int i = 0; i < count; i++) |
| 491 if (!coverage[i].sanitize (c, this)) return false; |
| 492 LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverage, covera
ge[0].static_size * count); |
| 493 return c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCoun
t); |
| 494 } |
| 495 |
| 496 private: |
| 497 USHORT format; /* Format identifier--format = 3 */ |
| 498 USHORT glyphCount; /* Number of glyphs in the input glyph |
| 499 * sequence */ |
| 500 USHORT lookupCount; /* Number of LookupRecords */ |
| 501 OffsetTo<Coverage> |
| 502 coverage[VAR]; /* Array of offsets to Coverage |
| 503 * table in glyph sequence order */ |
| 504 LookupRecord lookupRecordX[VAR]; /* Array of LookupRecords--in |
| 505 * design order */ |
| 506 public: |
| 507 DEFINE_SIZE_ARRAY2 (6, coverage, lookupRecordX); |
| 508 }; |
| 509 |
| 510 struct Context |
| 511 { |
| 512 protected: |
| 513 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) cons
t |
| 514 { |
| 515 TRACE_APPLY (); |
| 516 switch (u.format) { |
| 517 case 1: return u.format1.apply (c, apply_func); |
| 518 case 2: return u.format2.apply (c, apply_func); |
| 519 case 3: return u.format3.apply (c, apply_func); |
| 520 default:return false; |
| 521 } |
| 522 } |
| 523 |
| 524 inline bool sanitize (hb_sanitize_context_t *c) { |
| 525 TRACE_SANITIZE (); |
| 526 if (!u.format.sanitize (c)) return false; |
| 527 switch (u.format) { |
| 528 case 1: return u.format1.sanitize (c); |
| 529 case 2: return u.format2.sanitize (c); |
| 530 case 3: return u.format3.sanitize (c); |
| 531 default:return true; |
| 532 } |
| 533 } |
| 534 |
| 535 private: |
| 536 union { |
| 537 USHORT format; /* Format identifier */ |
| 538 ContextFormat1 format1; |
| 539 ContextFormat2 format2; |
| 540 ContextFormat3 format3; |
| 541 } u; |
| 542 }; |
| 543 |
| 544 |
| 545 /* Chaining Contextual lookups */ |
| 546 |
| 547 struct ChainContextLookupContext |
| 548 { |
| 549 ContextFuncs funcs; |
| 550 const void *match_data[3]; |
| 551 }; |
| 552 |
| 553 static inline bool chain_context_lookup (hb_apply_context_t *c, |
| 554 unsigned int backtrackCount, |
| 555 const USHORT backtrack[], |
| 556 unsigned int inputCount, /* Including t
he first glyph (not matched) */ |
| 557 const USHORT input[], /* Array of input
values--start with second glyph */ |
| 558 unsigned int lookaheadCount, |
| 559 const USHORT lookahead[], |
| 560 unsigned int lookupCount, |
| 561 const LookupRecord lookupRecord[], |
| 562 ChainContextLookupContext &lookup_conte
xt) |
| 563 { |
| 564 /* First guess */ |
| 565 if (unlikely (c->buffer->out_len < backtrackCount || |
| 566 c->buffer->i + inputCount + lookaheadCount > c->buffer->len || |
| 567 inputCount + lookaheadCount > c->context_length)) |
| 568 return false; |
| 569 |
| 570 hb_apply_context_t new_context = *c; |
| 571 return match_backtrack (c, |
| 572 backtrackCount, backtrack, |
| 573 lookup_context.funcs.match, lookup_context.match_data[
0]) |
| 574 && match_input (c, |
| 575 inputCount, input, |
| 576 lookup_context.funcs.match, lookup_context.match_data[1], |
| 577 &new_context.context_length) |
| 578 && match_lookahead (c, |
| 579 lookaheadCount, lookahead, |
| 580 lookup_context.funcs.match, lookup_context.match_data[
2], |
| 581 new_context.context_length) |
| 582 && apply_lookup (&new_context, |
| 583 inputCount, |
| 584 lookupCount, lookupRecord, |
| 585 lookup_context.funcs.apply); |
| 586 } |
| 587 |
| 588 struct ChainRule |
| 589 { |
| 590 friend struct ChainRuleSet; |
| 591 |
| 592 private: |
| 593 inline bool apply (hb_apply_context_t *c, ChainContextLookupContext &lookup_co
ntext) const |
| 594 { |
| 595 TRACE_APPLY (); |
| 596 const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> >
(backtrack); |
| 597 const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); |
| 598 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (l
ookahead); |
| 599 return chain_context_lookup (c, |
| 600 backtrack.len, backtrack.array, |
| 601 input.len, input.array, |
| 602 lookahead.len, lookahead.array, |
| 603 lookup.len, lookup.array, |
| 604 lookup_context); |
| 605 } |
| 606 |
| 607 public: |
| 608 inline bool sanitize (hb_sanitize_context_t *c) { |
| 609 TRACE_SANITIZE (); |
| 610 if (!backtrack.sanitize (c)) return false; |
| 611 HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (back
track); |
| 612 if (!input.sanitize (c)) return false; |
| 613 ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input); |
| 614 if (!lookahead.sanitize (c)) return false; |
| 615 ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahe
ad); |
| 616 return lookup.sanitize (c); |
| 617 } |
| 618 |
| 619 private: |
| 620 ArrayOf<USHORT> |
| 621 backtrack; /* Array of backtracking values |
| 622 * (to be matched before the input |
| 623 * sequence) */ |
| 624 HeadlessArrayOf<USHORT> |
| 625 inputX; /* Array of input values (start with |
| 626 * second glyph) */ |
| 627 ArrayOf<USHORT> |
| 628 lookaheadX; /* Array of lookahead values's (to be |
| 629 * matched after the input sequence) */ |
| 630 ArrayOf<LookupRecord> |
| 631 lookupX; /* Array of LookupRecords--in |
| 632 * design order) */ |
| 633 public: |
| 634 DEFINE_SIZE_MIN (8); |
| 635 }; |
| 636 |
| 637 struct ChainRuleSet |
| 638 { |
| 639 inline bool apply (hb_apply_context_t *c, ChainContextLookupContext &lookup_co
ntext) const |
| 640 { |
| 641 TRACE_APPLY (); |
| 642 unsigned int num_rules = rule.len; |
| 643 for (unsigned int i = 0; i < num_rules; i++) |
| 644 { |
| 645 if ((this+rule[i]).apply (c, lookup_context)) |
| 646 return true; |
| 647 } |
| 648 |
| 649 return false; |
| 650 } |
| 651 |
| 652 inline bool sanitize (hb_sanitize_context_t *c) { |
| 653 TRACE_SANITIZE (); |
| 654 return rule.sanitize (c, this); |
| 655 } |
| 656 |
| 657 private: |
| 658 OffsetArrayOf<ChainRule> |
| 659 rule; /* Array of ChainRule tables |
| 660 * ordered by preference */ |
| 661 public: |
| 662 DEFINE_SIZE_ARRAY (2, rule); |
| 663 }; |
| 664 |
| 665 struct ChainContextFormat1 |
| 666 { |
| 667 friend struct ChainContext; |
| 668 |
| 669 private: |
| 670 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) cons
t |
| 671 { |
| 672 TRACE_APPLY (); |
| 673 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoin
t); |
| 674 if (likely (index == NOT_COVERED)) |
| 675 return false; |
| 676 |
| 677 const ChainRuleSet &rule_set = this+ruleSet[index]; |
| 678 struct ChainContextLookupContext lookup_context = { |
| 679 {match_glyph, apply_func}, |
| 680 {NULL, NULL, NULL} |
| 681 }; |
| 682 return rule_set.apply (c, lookup_context); |
| 683 } |
| 684 |
| 685 inline bool sanitize (hb_sanitize_context_t *c) { |
| 686 TRACE_SANITIZE (); |
| 687 return coverage.sanitize (c, this) |
| 688 && ruleSet.sanitize (c, this); |
| 689 } |
| 690 |
| 691 private: |
| 692 USHORT format; /* Format identifier--format = 1 */ |
| 693 OffsetTo<Coverage> |
| 694 coverage; /* Offset to Coverage table--from |
| 695 * beginning of table */ |
| 696 OffsetArrayOf<ChainRuleSet> |
| 697 ruleSet; /* Array of ChainRuleSet tables |
| 698 * ordered by Coverage Index */ |
| 699 public: |
| 700 DEFINE_SIZE_ARRAY (6, ruleSet); |
| 701 }; |
| 702 |
| 703 struct ChainContextFormat2 |
| 704 { |
| 705 friend struct ChainContext; |
| 706 |
| 707 private: |
| 708 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) cons
t |
| 709 { |
| 710 TRACE_APPLY (); |
| 711 unsigned int index = (this+coverage) (c->buffer->info[c->buffer->i].codepoin
t); |
| 712 if (likely (index == NOT_COVERED)) |
| 713 return false; |
| 714 |
| 715 const ClassDef &backtrack_class_def = this+backtrackClassDef; |
| 716 const ClassDef &input_class_def = this+inputClassDef; |
| 717 const ClassDef &lookahead_class_def = this+lookaheadClassDef; |
| 718 |
| 719 index = input_class_def (c->buffer->info[c->buffer->i].codepoint); |
| 720 const ChainRuleSet &rule_set = this+ruleSet[index]; |
| 721 struct ChainContextLookupContext lookup_context = { |
| 722 {match_class, apply_func}, |
| 723 {&backtrack_class_def, |
| 724 &input_class_def, |
| 725 &lookahead_class_def} |
| 726 }; |
| 727 return rule_set.apply (c, lookup_context); |
| 728 } |
| 729 |
| 730 inline bool sanitize (hb_sanitize_context_t *c) { |
| 731 TRACE_SANITIZE (); |
| 732 return coverage.sanitize (c, this) |
| 733 && backtrackClassDef.sanitize (c, this) |
| 734 && inputClassDef.sanitize (c, this) |
| 735 && lookaheadClassDef.sanitize (c, this) |
| 736 && ruleSet.sanitize (c, this); |
| 737 } |
| 738 |
| 739 private: |
| 740 USHORT format; /* Format identifier--format = 2 */ |
| 741 OffsetTo<Coverage> |
| 742 coverage; /* Offset to Coverage table--from |
| 743 * beginning of table */ |
| 744 OffsetTo<ClassDef> |
| 745 backtrackClassDef; /* Offset to glyph ClassDef table |
| 746 * containing backtrack sequence |
| 747 * data--from beginning of table */ |
| 748 OffsetTo<ClassDef> |
| 749 inputClassDef; /* Offset to glyph ClassDef |
| 750 * table containing input sequence |
| 751 * data--from beginning of table */ |
| 752 OffsetTo<ClassDef> |
| 753 lookaheadClassDef; /* Offset to glyph ClassDef table |
| 754 * containing lookahead sequence |
| 755 * data--from beginning of table */ |
| 756 OffsetArrayOf<ChainRuleSet> |
| 757 ruleSet; /* Array of ChainRuleSet tables |
| 758 * ordered by class */ |
| 759 public: |
| 760 DEFINE_SIZE_ARRAY (12, ruleSet); |
| 761 }; |
| 762 |
| 763 struct ChainContextFormat3 |
| 764 { |
| 765 friend struct ChainContext; |
| 766 |
| 767 private: |
| 768 |
| 769 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) cons
t |
| 770 { |
| 771 TRACE_APPLY (); |
| 772 const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> >
(backtrack); |
| 773 |
| 774 unsigned int index = (this+input[0]) (c->buffer->info[c->buffer->i].codepoin
t); |
| 775 if (likely (index == NOT_COVERED)) |
| 776 return false; |
| 777 |
| 778 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverag
e> > (input); |
| 779 const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (l
ookahead); |
| 780 struct ChainContextLookupContext lookup_context = { |
| 781 {match_coverage, apply_func}, |
| 782 {this, this, this} |
| 783 }; |
| 784 return chain_context_lookup (c, |
| 785 backtrack.len, (const USHORT *) backtrack.array
, |
| 786 input.len, (const USHORT *) input.array + 1, |
| 787 lookahead.len, (const USHORT *) lookahead.array
, |
| 788 lookup.len, lookup.array, |
| 789 lookup_context); |
| 790 } |
| 791 |
| 792 inline bool sanitize (hb_sanitize_context_t *c) { |
| 793 TRACE_SANITIZE (); |
| 794 if (!backtrack.sanitize (c, this)) return false; |
| 795 OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (back
track); |
| 796 if (!input.sanitize (c, this)) return false; |
| 797 OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (
input); |
| 798 if (!lookahead.sanitize (c, this)) return false; |
| 799 ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahe
ad); |
| 800 return lookup.sanitize (c); |
| 801 } |
| 802 |
| 803 private: |
| 804 USHORT format; /* Format identifier--format = 3 */ |
| 805 OffsetArrayOf<Coverage> |
| 806 backtrack; /* Array of coverage tables |
| 807 * in backtracking sequence, in glyph |
| 808 * sequence order */ |
| 809 OffsetArrayOf<Coverage> |
| 810 inputX ; /* Array of coverage |
| 811 * tables in input sequence, in glyph |
| 812 * sequence order */ |
| 813 OffsetArrayOf<Coverage> |
| 814 lookaheadX; /* Array of coverage tables |
| 815 * in lookahead sequence, in glyph |
| 816 * sequence order */ |
| 817 ArrayOf<LookupRecord> |
| 818 lookupX; /* Array of LookupRecords--in |
| 819 * design order) */ |
| 820 public: |
| 821 DEFINE_SIZE_MIN (10); |
| 822 }; |
| 823 |
| 824 struct ChainContext |
| 825 { |
| 826 protected: |
| 827 inline bool apply (hb_apply_context_t *c, apply_lookup_func_t apply_func) cons
t |
| 828 { |
| 829 TRACE_APPLY (); |
| 830 switch (u.format) { |
| 831 case 1: return u.format1.apply (c, apply_func); |
| 832 case 2: return u.format2.apply (c, apply_func); |
| 833 case 3: return u.format3.apply (c, apply_func); |
| 834 default:return false; |
| 835 } |
| 836 } |
| 837 |
| 838 inline bool sanitize (hb_sanitize_context_t *c) { |
| 839 TRACE_SANITIZE (); |
| 840 if (!u.format.sanitize (c)) return false; |
| 841 switch (u.format) { |
| 842 case 1: return u.format1.sanitize (c); |
| 843 case 2: return u.format2.sanitize (c); |
| 844 case 3: return u.format3.sanitize (c); |
| 845 default:return true; |
| 846 } |
| 847 } |
| 848 |
| 849 private: |
| 850 union { |
| 851 USHORT format; /* Format identifier */ |
| 852 ChainContextFormat1 format1; |
| 853 ChainContextFormat2 format2; |
| 854 ChainContextFormat3 format3; |
| 855 } u; |
| 856 }; |
| 857 |
| 858 |
| 859 struct ExtensionFormat1 |
| 860 { |
| 861 friend struct Extension; |
| 862 |
| 863 protected: |
| 864 inline unsigned int get_type (void) const { return extensionLookupType; } |
| 865 inline unsigned int get_offset (void) const { return extensionOffset; } |
| 866 |
| 867 inline bool sanitize (hb_sanitize_context_t *c) { |
| 868 TRACE_SANITIZE (); |
| 869 return c->check_struct (this); |
| 870 } |
| 871 |
| 872 private: |
| 873 USHORT format; /* Format identifier. Set to 1. */ |
| 874 USHORT extensionLookupType; /* Lookup type of subtable referenced |
| 875 * by ExtensionOffset (i.e. the |
| 876 * extension subtable). */ |
| 877 ULONG extensionOffset; /* Offset to the extension subtable, |
| 878 * of lookup type subtable. */ |
| 879 public: |
| 880 DEFINE_SIZE_STATIC (8); |
| 881 }; |
| 882 |
| 883 struct Extension |
| 884 { |
| 885 inline unsigned int get_type (void) const |
| 886 { |
| 887 switch (u.format) { |
| 888 case 1: return u.format1.get_type (); |
| 889 default:return 0; |
| 890 } |
| 891 } |
| 892 inline unsigned int get_offset (void) const |
| 893 { |
| 894 switch (u.format) { |
| 895 case 1: return u.format1.get_offset (); |
| 896 default:return 0; |
| 897 } |
| 898 } |
| 899 |
| 900 inline bool sanitize (hb_sanitize_context_t *c) { |
| 901 TRACE_SANITIZE (); |
| 902 if (!u.format.sanitize (c)) return false; |
| 903 switch (u.format) { |
| 904 case 1: return u.format1.sanitize (c); |
| 905 default:return true; |
| 906 } |
| 907 } |
| 908 |
| 909 private: |
| 910 union { |
| 911 USHORT format; /* Format identifier */ |
| 912 ExtensionFormat1 format1; |
| 913 } u; |
| 914 }; |
| 915 |
| 916 |
| 917 /* |
| 918 * GSUB/GPOS Common |
| 919 */ |
| 920 |
| 921 struct GSUBGPOS |
| 922 { |
| 923 static const hb_tag_t GSUBTag = HB_OT_TAG_GSUB; |
| 924 static const hb_tag_t GPOSTag = HB_OT_TAG_GPOS; |
| 925 |
| 926 inline unsigned int get_script_count (void) const |
| 927 { return (this+scriptList).len; } |
| 928 inline const Tag& get_script_tag (unsigned int i) const |
| 929 { return (this+scriptList).get_tag (i); } |
| 930 inline unsigned int get_script_tags (unsigned int start_offset, |
| 931 unsigned int *script_count /* IN/OUT */, |
| 932 hb_tag_t *script_tags /* OUT */) cons
t |
| 933 { return (this+scriptList).get_tags (start_offset, script_count, script_tags);
} |
| 934 inline const Script& get_script (unsigned int i) const |
| 935 { return (this+scriptList)[i]; } |
| 936 inline bool find_script_index (hb_tag_t tag, unsigned int *index) const |
| 937 { return (this+scriptList).find_index (tag, index); } |
| 938 |
| 939 inline unsigned int get_feature_count (void) const |
| 940 { return (this+featureList).len; } |
| 941 inline const Tag& get_feature_tag (unsigned int i) const |
| 942 { return (this+featureList).get_tag (i); } |
| 943 inline unsigned int get_feature_tags (unsigned int start_offset, |
| 944 unsigned int *feature_count /* IN/OUT */
, |
| 945 hb_tag_t *feature_tags /* OUT */) co
nst |
| 946 { return (this+featureList).get_tags (start_offset, feature_count, feature_tag
s); } |
| 947 inline const Feature& get_feature (unsigned int i) const |
| 948 { return (this+featureList)[i]; } |
| 949 inline bool find_feature_index (hb_tag_t tag, unsigned int *index) const |
| 950 { return (this+featureList).find_index (tag, index); } |
| 951 |
| 952 inline unsigned int get_lookup_count (void) const |
| 953 { return (this+lookupList).len; } |
| 954 inline const Lookup& get_lookup (unsigned int i) const |
| 955 { return (this+lookupList)[i]; } |
| 956 |
| 957 inline bool sanitize (hb_sanitize_context_t *c) { |
| 958 TRACE_SANITIZE (); |
| 959 return version.sanitize (c) && likely (version.major == 1) |
| 960 && scriptList.sanitize (c, this) |
| 961 && featureList.sanitize (c, this) |
| 962 && lookupList.sanitize (c, this); |
| 963 } |
| 964 |
| 965 protected: |
| 966 FixedVersion version; /* Version of the GSUB/GPOS table--initially set |
| 967 * to 0x00010000 */ |
| 968 OffsetTo<ScriptList> |
| 969 scriptList; /* ScriptList table */ |
| 970 OffsetTo<FeatureList> |
| 971 featureList; /* FeatureList table */ |
| 972 OffsetTo<LookupList> |
| 973 lookupList; /* LookupList table */ |
| 974 public: |
| 975 DEFINE_SIZE_STATIC (10); |
| 976 }; |
| 977 |
| 978 |
| 979 HB_END_DECLS |
| 980 |
| 981 #endif /* HB_OT_LAYOUT_GSUBGPOS_PRIVATE_HH */ |
OLD | NEW |