hb-ot-layout-gsub-table.hh revision 5d59f999204aedfc433ab4989664d875f96b0364
122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao/* 222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao * Copyright © 2007,2008,2009,2010 Red Hat, Inc. 322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao * Copyright © 2010,2012 Google, Inc. 422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao * 522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao * This is part of HarfBuzz, a text shaping library. 622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao * 722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao * Permission is hereby granted, without written agreement and without 822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao * license or royalty fees, to use, copy, modify, and distribute this 922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao * software and its documentation for any purpose, provided that the 1022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao * above copyright notice and the following two paragraphs appear in 1122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao * all copies of this software. 1222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao * 1322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 1422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 1522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 1622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 1722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao * DAMAGE. 1822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao * 1922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 2022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 2122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 2222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 2322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 2422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao * 2522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao * Red Hat Author(s): Behdad Esfahbod 2622add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao * Google Author(s): Behdad Esfahbod 2722add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao */ 2822add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao 2922add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao#ifndef HB_OT_LAYOUT_GSUB_TABLE_HH 3022add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao#define HB_OT_LAYOUT_GSUB_TABLE_HH 3122add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao 3222add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao#include "hb-ot-layout-gsubgpos-private.hh" 3322add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao 3422add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liao 3522add6ff3426df1a85089fe6a6e1597ee3b6f300Shih-wei Liaonamespace OT { 36 37 38struct SingleSubstFormat1 39{ 40 inline void closure (hb_closure_context_t *c) const 41 { 42 TRACE_CLOSURE (this); 43 Coverage::Iter iter; 44 for (iter.init (this+coverage); iter.more (); iter.next ()) { 45 hb_codepoint_t glyph_id = iter.get_glyph (); 46 if (c->glyphs->has (glyph_id)) 47 c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFF); 48 } 49 } 50 51 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 52 { 53 TRACE_COLLECT_GLYPHS (this); 54 Coverage::Iter iter; 55 for (iter.init (this+coverage); iter.more (); iter.next ()) { 56 hb_codepoint_t glyph_id = iter.get_glyph (); 57 c->input->add (glyph_id); 58 c->output->add ((glyph_id + deltaGlyphID) & 0xFFFF); 59 } 60 } 61 62 inline const Coverage &get_coverage (void) const 63 { 64 return this+coverage; 65 } 66 67 inline bool would_apply (hb_would_apply_context_t *c) const 68 { 69 TRACE_WOULD_APPLY (this); 70 return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); 71 } 72 73 inline bool apply (hb_apply_context_t *c) const 74 { 75 TRACE_APPLY (this); 76 hb_codepoint_t glyph_id = c->buffer->cur().codepoint; 77 unsigned int index = (this+coverage).get_coverage (glyph_id); 78 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 79 80 /* According to the Adobe Annotated OpenType Suite, result is always 81 * limited to 16bit. */ 82 glyph_id = (glyph_id + deltaGlyphID) & 0xFFFF; 83 c->replace_glyph (glyph_id); 84 85 return TRACE_RETURN (true); 86 } 87 88 inline bool serialize (hb_serialize_context_t *c, 89 Supplier<GlyphID> &glyphs, 90 unsigned int num_glyphs, 91 int delta) 92 { 93 TRACE_SERIALIZE (this); 94 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); 95 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false); 96 deltaGlyphID.set (delta); /* TODO(serilaize) overflow? */ 97 return TRACE_RETURN (true); 98 } 99 100 inline bool sanitize (hb_sanitize_context_t *c) { 101 TRACE_SANITIZE (this); 102 return TRACE_RETURN (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c)); 103 } 104 105 protected: 106 USHORT format; /* Format identifier--format = 1 */ 107 OffsetTo<Coverage> 108 coverage; /* Offset to Coverage table--from 109 * beginning of Substitution table */ 110 SHORT deltaGlyphID; /* Add to original GlyphID to get 111 * substitute GlyphID */ 112 public: 113 DEFINE_SIZE_STATIC (6); 114}; 115 116struct SingleSubstFormat2 117{ 118 inline void closure (hb_closure_context_t *c) const 119 { 120 TRACE_CLOSURE (this); 121 Coverage::Iter iter; 122 for (iter.init (this+coverage); iter.more (); iter.next ()) { 123 if (c->glyphs->has (iter.get_glyph ())) 124 c->glyphs->add (substitute[iter.get_coverage ()]); 125 } 126 } 127 128 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 129 { 130 TRACE_COLLECT_GLYPHS (this); 131 Coverage::Iter iter; 132 for (iter.init (this+coverage); iter.more (); iter.next ()) { 133 c->input->add (iter.get_glyph ()); 134 c->output->add (substitute[iter.get_coverage ()]); 135 } 136 } 137 138 inline const Coverage &get_coverage (void) const 139 { 140 return this+coverage; 141 } 142 143 inline bool would_apply (hb_would_apply_context_t *c) const 144 { 145 TRACE_WOULD_APPLY (this); 146 return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); 147 } 148 149 inline bool apply (hb_apply_context_t *c) const 150 { 151 TRACE_APPLY (this); 152 hb_codepoint_t glyph_id = c->buffer->cur().codepoint; 153 unsigned int index = (this+coverage).get_coverage (glyph_id); 154 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 155 156 if (unlikely (index >= substitute.len)) return TRACE_RETURN (false); 157 158 glyph_id = substitute[index]; 159 c->replace_glyph (glyph_id); 160 161 return TRACE_RETURN (true); 162 } 163 164 inline bool serialize (hb_serialize_context_t *c, 165 Supplier<GlyphID> &glyphs, 166 Supplier<GlyphID> &substitutes, 167 unsigned int num_glyphs) 168 { 169 TRACE_SERIALIZE (this); 170 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); 171 if (unlikely (!substitute.serialize (c, substitutes, num_glyphs))) return TRACE_RETURN (false); 172 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false); 173 return TRACE_RETURN (true); 174 } 175 176 inline bool sanitize (hb_sanitize_context_t *c) { 177 TRACE_SANITIZE (this); 178 return TRACE_RETURN (coverage.sanitize (c, this) && substitute.sanitize (c)); 179 } 180 181 protected: 182 USHORT format; /* Format identifier--format = 2 */ 183 OffsetTo<Coverage> 184 coverage; /* Offset to Coverage table--from 185 * beginning of Substitution table */ 186 ArrayOf<GlyphID> 187 substitute; /* Array of substitute 188 * GlyphIDs--ordered by Coverage Index */ 189 public: 190 DEFINE_SIZE_ARRAY (6, substitute); 191}; 192 193struct SingleSubst 194{ 195 inline bool serialize (hb_serialize_context_t *c, 196 Supplier<GlyphID> &glyphs, 197 Supplier<GlyphID> &substitutes, 198 unsigned int num_glyphs) 199 { 200 TRACE_SERIALIZE (this); 201 if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false); 202 unsigned int format = 2; 203 int delta; 204 if (num_glyphs) { 205 format = 1; 206 /* TODO(serialize) check for wrap-around */ 207 delta = substitutes[0] - glyphs[0]; 208 for (unsigned int i = 1; i < num_glyphs; i++) 209 if (delta != substitutes[i] - glyphs[i]) { 210 format = 2; 211 break; 212 } 213 } 214 u.format.set (format); 215 switch (u.format) { 216 case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, num_glyphs, delta)); 217 case 2: return TRACE_RETURN (u.format2.serialize (c, glyphs, substitutes, num_glyphs)); 218 default:return TRACE_RETURN (false); 219 } 220 } 221 222 template <typename context_t> 223 inline typename context_t::return_t dispatch (context_t *c) const 224 { 225 TRACE_DISPATCH (this); 226 switch (u.format) { 227 case 1: return TRACE_RETURN (c->dispatch (u.format1)); 228 case 2: return TRACE_RETURN (c->dispatch (u.format2)); 229 default:return TRACE_RETURN (c->default_return_value ()); 230 } 231 } 232 233 inline bool sanitize (hb_sanitize_context_t *c) { 234 TRACE_SANITIZE (this); 235 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 236 switch (u.format) { 237 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 238 case 2: return TRACE_RETURN (u.format2.sanitize (c)); 239 default:return TRACE_RETURN (true); 240 } 241 } 242 243 protected: 244 union { 245 USHORT format; /* Format identifier */ 246 SingleSubstFormat1 format1; 247 SingleSubstFormat2 format2; 248 } u; 249}; 250 251 252struct Sequence 253{ 254 inline void closure (hb_closure_context_t *c) const 255 { 256 TRACE_CLOSURE (this); 257 unsigned int count = substitute.len; 258 for (unsigned int i = 0; i < count; i++) 259 c->glyphs->add (substitute[i]); 260 } 261 262 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 263 { 264 TRACE_COLLECT_GLYPHS (this); 265 unsigned int count = substitute.len; 266 for (unsigned int i = 0; i < count; i++) 267 c->output->add (substitute[i]); 268 } 269 270 inline bool apply (hb_apply_context_t *c) const 271 { 272 TRACE_APPLY (this); 273 if (unlikely (!substitute.len)) return TRACE_RETURN (false); 274 275 unsigned int klass = c->buffer->cur().glyph_props() & 276 HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE ? HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0; 277 unsigned int count = substitute.len; 278 if (count == 1) /* Special-case to make it in-place. */ 279 { 280 c->replace_glyph (substitute.array[0]); 281 } 282 else 283 { 284 for (unsigned int i = 0; i < count; i++) { 285 set_lig_props_for_component (c->buffer->cur(), i); 286 c->output_glyph (substitute.array[i], klass); 287 } 288 c->buffer->skip_glyph (); 289 } 290 291 return TRACE_RETURN (true); 292 } 293 294 inline bool serialize (hb_serialize_context_t *c, 295 Supplier<GlyphID> &glyphs, 296 unsigned int num_glyphs) 297 { 298 TRACE_SERIALIZE (this); 299 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); 300 if (unlikely (!substitute.serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false); 301 return TRACE_RETURN (true); 302 } 303 304 inline bool sanitize (hb_sanitize_context_t *c) { 305 TRACE_SANITIZE (this); 306 return TRACE_RETURN (substitute.sanitize (c)); 307 } 308 309 protected: 310 ArrayOf<GlyphID> 311 substitute; /* String of GlyphIDs to substitute */ 312 public: 313 DEFINE_SIZE_ARRAY (2, substitute); 314}; 315 316struct MultipleSubstFormat1 317{ 318 inline void closure (hb_closure_context_t *c) const 319 { 320 TRACE_CLOSURE (this); 321 Coverage::Iter iter; 322 for (iter.init (this+coverage); iter.more (); iter.next ()) { 323 if (c->glyphs->has (iter.get_glyph ())) 324 (this+sequence[iter.get_coverage ()]).closure (c); 325 } 326 } 327 328 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 329 { 330 TRACE_COLLECT_GLYPHS (this); 331 (this+coverage).add_coverage (c->input); 332 unsigned int count = sequence.len; 333 for (unsigned int i = 0; i < count; i++) 334 (this+sequence[i]).collect_glyphs (c); 335 } 336 337 inline const Coverage &get_coverage (void) const 338 { 339 return this+coverage; 340 } 341 342 inline bool would_apply (hb_would_apply_context_t *c) const 343 { 344 TRACE_WOULD_APPLY (this); 345 return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); 346 } 347 348 inline bool apply (hb_apply_context_t *c) const 349 { 350 TRACE_APPLY (this); 351 352 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); 353 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 354 355 return TRACE_RETURN ((this+sequence[index]).apply (c)); 356 } 357 358 inline bool serialize (hb_serialize_context_t *c, 359 Supplier<GlyphID> &glyphs, 360 Supplier<unsigned int> &substitute_len_list, 361 unsigned int num_glyphs, 362 Supplier<GlyphID> &substitute_glyphs_list) 363 { 364 TRACE_SERIALIZE (this); 365 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); 366 if (unlikely (!sequence.serialize (c, num_glyphs))) return TRACE_RETURN (false); 367 for (unsigned int i = 0; i < num_glyphs; i++) 368 if (unlikely (!sequence[i].serialize (c, this).serialize (c, 369 substitute_glyphs_list, 370 substitute_len_list[i]))) return TRACE_RETURN (false); 371 substitute_len_list.advance (num_glyphs); 372 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false); 373 return TRACE_RETURN (true); 374 } 375 376 inline bool sanitize (hb_sanitize_context_t *c) { 377 TRACE_SANITIZE (this); 378 return TRACE_RETURN (coverage.sanitize (c, this) && sequence.sanitize (c, this)); 379 } 380 381 protected: 382 USHORT format; /* Format identifier--format = 1 */ 383 OffsetTo<Coverage> 384 coverage; /* Offset to Coverage table--from 385 * beginning of Substitution table */ 386 OffsetArrayOf<Sequence> 387 sequence; /* Array of Sequence tables 388 * ordered by Coverage Index */ 389 public: 390 DEFINE_SIZE_ARRAY (6, sequence); 391}; 392 393struct MultipleSubst 394{ 395 inline bool serialize (hb_serialize_context_t *c, 396 Supplier<GlyphID> &glyphs, 397 Supplier<unsigned int> &substitute_len_list, 398 unsigned int num_glyphs, 399 Supplier<GlyphID> &substitute_glyphs_list) 400 { 401 TRACE_SERIALIZE (this); 402 if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false); 403 unsigned int format = 1; 404 u.format.set (format); 405 switch (u.format) { 406 case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, substitute_len_list, num_glyphs, substitute_glyphs_list)); 407 default:return TRACE_RETURN (false); 408 } 409 } 410 411 template <typename context_t> 412 inline typename context_t::return_t dispatch (context_t *c) const 413 { 414 TRACE_DISPATCH (this); 415 switch (u.format) { 416 case 1: return TRACE_RETURN (c->dispatch (u.format1)); 417 default:return TRACE_RETURN (c->default_return_value ()); 418 } 419 } 420 421 inline bool sanitize (hb_sanitize_context_t *c) { 422 TRACE_SANITIZE (this); 423 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 424 switch (u.format) { 425 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 426 default:return TRACE_RETURN (true); 427 } 428 } 429 430 protected: 431 union { 432 USHORT format; /* Format identifier */ 433 MultipleSubstFormat1 format1; 434 } u; 435}; 436 437 438typedef ArrayOf<GlyphID> AlternateSet; /* Array of alternate GlyphIDs--in 439 * arbitrary order */ 440 441struct AlternateSubstFormat1 442{ 443 inline void closure (hb_closure_context_t *c) const 444 { 445 TRACE_CLOSURE (this); 446 Coverage::Iter iter; 447 for (iter.init (this+coverage); iter.more (); iter.next ()) { 448 if (c->glyphs->has (iter.get_glyph ())) { 449 const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()]; 450 unsigned int count = alt_set.len; 451 for (unsigned int i = 0; i < count; i++) 452 c->glyphs->add (alt_set[i]); 453 } 454 } 455 } 456 457 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 458 { 459 TRACE_COLLECT_GLYPHS (this); 460 Coverage::Iter iter; 461 for (iter.init (this+coverage); iter.more (); iter.next ()) { 462 c->input->add (iter.get_glyph ()); 463 const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()]; 464 unsigned int count = alt_set.len; 465 for (unsigned int i = 0; i < count; i++) 466 c->output->add (alt_set[i]); 467 } 468 } 469 470 inline const Coverage &get_coverage (void) const 471 { 472 return this+coverage; 473 } 474 475 inline bool would_apply (hb_would_apply_context_t *c) const 476 { 477 TRACE_WOULD_APPLY (this); 478 return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); 479 } 480 481 inline bool apply (hb_apply_context_t *c) const 482 { 483 TRACE_APPLY (this); 484 hb_codepoint_t glyph_id = c->buffer->cur().codepoint; 485 486 unsigned int index = (this+coverage).get_coverage (glyph_id); 487 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 488 489 const AlternateSet &alt_set = this+alternateSet[index]; 490 491 if (unlikely (!alt_set.len)) return TRACE_RETURN (false); 492 493 hb_mask_t glyph_mask = c->buffer->cur().mask; 494 hb_mask_t lookup_mask = c->lookup_mask; 495 496 /* Note: This breaks badly if two features enabled this lookup together. */ 497 unsigned int shift = _hb_ctz (lookup_mask); 498 unsigned int alt_index = ((lookup_mask & glyph_mask) >> shift); 499 500 if (unlikely (alt_index > alt_set.len || alt_index == 0)) return TRACE_RETURN (false); 501 502 glyph_id = alt_set[alt_index - 1]; 503 504 c->replace_glyph (glyph_id); 505 506 return TRACE_RETURN (true); 507 } 508 509 inline bool serialize (hb_serialize_context_t *c, 510 Supplier<GlyphID> &glyphs, 511 Supplier<unsigned int> &alternate_len_list, 512 unsigned int num_glyphs, 513 Supplier<GlyphID> &alternate_glyphs_list) 514 { 515 TRACE_SERIALIZE (this); 516 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); 517 if (unlikely (!alternateSet.serialize (c, num_glyphs))) return TRACE_RETURN (false); 518 for (unsigned int i = 0; i < num_glyphs; i++) 519 if (unlikely (!alternateSet[i].serialize (c, this).serialize (c, 520 alternate_glyphs_list, 521 alternate_len_list[i]))) return TRACE_RETURN (false); 522 alternate_len_list.advance (num_glyphs); 523 if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs, num_glyphs))) return TRACE_RETURN (false); 524 return TRACE_RETURN (true); 525 } 526 527 inline bool sanitize (hb_sanitize_context_t *c) { 528 TRACE_SANITIZE (this); 529 return TRACE_RETURN (coverage.sanitize (c, this) && alternateSet.sanitize (c, this)); 530 } 531 532 protected: 533 USHORT format; /* Format identifier--format = 1 */ 534 OffsetTo<Coverage> 535 coverage; /* Offset to Coverage table--from 536 * beginning of Substitution table */ 537 OffsetArrayOf<AlternateSet> 538 alternateSet; /* Array of AlternateSet tables 539 * ordered by Coverage Index */ 540 public: 541 DEFINE_SIZE_ARRAY (6, alternateSet); 542}; 543 544struct AlternateSubst 545{ 546 inline bool serialize (hb_serialize_context_t *c, 547 Supplier<GlyphID> &glyphs, 548 Supplier<unsigned int> &alternate_len_list, 549 unsigned int num_glyphs, 550 Supplier<GlyphID> &alternate_glyphs_list) 551 { 552 TRACE_SERIALIZE (this); 553 if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false); 554 unsigned int format = 1; 555 u.format.set (format); 556 switch (u.format) { 557 case 1: return TRACE_RETURN (u.format1.serialize (c, glyphs, alternate_len_list, num_glyphs, alternate_glyphs_list)); 558 default:return TRACE_RETURN (false); 559 } 560 } 561 562 template <typename context_t> 563 inline typename context_t::return_t dispatch (context_t *c) const 564 { 565 TRACE_DISPATCH (this); 566 switch (u.format) { 567 case 1: return TRACE_RETURN (c->dispatch (u.format1)); 568 default:return TRACE_RETURN (c->default_return_value ()); 569 } 570 } 571 572 inline bool sanitize (hb_sanitize_context_t *c) { 573 TRACE_SANITIZE (this); 574 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 575 switch (u.format) { 576 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 577 default:return TRACE_RETURN (true); 578 } 579 } 580 581 protected: 582 union { 583 USHORT format; /* Format identifier */ 584 AlternateSubstFormat1 format1; 585 } u; 586}; 587 588 589struct Ligature 590{ 591 inline void closure (hb_closure_context_t *c) const 592 { 593 TRACE_CLOSURE (this); 594 unsigned int count = component.len; 595 for (unsigned int i = 1; i < count; i++) 596 if (!c->glyphs->has (component[i])) 597 return; 598 c->glyphs->add (ligGlyph); 599 } 600 601 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 602 { 603 TRACE_COLLECT_GLYPHS (this); 604 unsigned int count = component.len; 605 for (unsigned int i = 1; i < count; i++) 606 c->input->add (component[i]); 607 c->output->add (ligGlyph); 608 } 609 610 inline bool would_apply (hb_would_apply_context_t *c) const 611 { 612 TRACE_WOULD_APPLY (this); 613 if (c->len != component.len) 614 return TRACE_RETURN (false); 615 616 for (unsigned int i = 1; i < c->len; i++) 617 if (likely (c->glyphs[i] != component[i])) 618 return TRACE_RETURN (false); 619 620 return TRACE_RETURN (true); 621 } 622 623 inline bool apply (hb_apply_context_t *c) const 624 { 625 TRACE_APPLY (this); 626 unsigned int count = component.len; 627 if (unlikely (count < 1)) return TRACE_RETURN (false); 628 629 unsigned int end_offset = 0; 630 bool is_mark_ligature = false; 631 unsigned int total_component_count = 0; 632 633 if (likely (!match_input (c, count, 634 &component[1], 635 match_glyph, 636 NULL, 637 &end_offset, 638 &is_mark_ligature, 639 &total_component_count))) 640 return TRACE_RETURN (false); 641 642 /* Deal, we are forming the ligature. */ 643 c->buffer->merge_clusters (c->buffer->idx, c->buffer->idx + end_offset); 644 645 ligate_input (c, 646 count, 647 &component[1], 648 match_glyph, 649 NULL, 650 ligGlyph, 651 is_mark_ligature, 652 total_component_count); 653 654 return TRACE_RETURN (true); 655 } 656 657 inline bool serialize (hb_serialize_context_t *c, 658 GlyphID ligature, 659 Supplier<GlyphID> &components, /* Starting from second */ 660 unsigned int num_components /* Including first component */) 661 { 662 TRACE_SERIALIZE (this); 663 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); 664 ligGlyph = ligature; 665 if (unlikely (!component.serialize (c, components, num_components))) return TRACE_RETURN (false); 666 return TRACE_RETURN (true); 667 } 668 669 public: 670 inline bool sanitize (hb_sanitize_context_t *c) { 671 TRACE_SANITIZE (this); 672 return TRACE_RETURN (ligGlyph.sanitize (c) && component.sanitize (c)); 673 } 674 675 protected: 676 GlyphID ligGlyph; /* GlyphID of ligature to substitute */ 677 HeadlessArrayOf<GlyphID> 678 component; /* Array of component GlyphIDs--start 679 * with the second component--ordered 680 * in writing direction */ 681 public: 682 DEFINE_SIZE_ARRAY (4, component); 683}; 684 685struct LigatureSet 686{ 687 inline void closure (hb_closure_context_t *c) const 688 { 689 TRACE_CLOSURE (this); 690 unsigned int num_ligs = ligature.len; 691 for (unsigned int i = 0; i < num_ligs; i++) 692 (this+ligature[i]).closure (c); 693 } 694 695 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 696 { 697 TRACE_COLLECT_GLYPHS (this); 698 unsigned int num_ligs = ligature.len; 699 for (unsigned int i = 0; i < num_ligs; i++) 700 (this+ligature[i]).collect_glyphs (c); 701 } 702 703 inline bool would_apply (hb_would_apply_context_t *c) const 704 { 705 TRACE_WOULD_APPLY (this); 706 unsigned int num_ligs = ligature.len; 707 for (unsigned int i = 0; i < num_ligs; i++) 708 { 709 const Ligature &lig = this+ligature[i]; 710 if (lig.would_apply (c)) 711 return TRACE_RETURN (true); 712 } 713 return TRACE_RETURN (false); 714 } 715 716 inline bool apply (hb_apply_context_t *c) const 717 { 718 TRACE_APPLY (this); 719 unsigned int num_ligs = ligature.len; 720 for (unsigned int i = 0; i < num_ligs; i++) 721 { 722 const Ligature &lig = this+ligature[i]; 723 if (lig.apply (c)) return TRACE_RETURN (true); 724 } 725 726 return TRACE_RETURN (false); 727 } 728 729 inline bool serialize (hb_serialize_context_t *c, 730 Supplier<GlyphID> &ligatures, 731 Supplier<unsigned int> &component_count_list, 732 unsigned int num_ligatures, 733 Supplier<GlyphID> &component_list /* Starting from second for each ligature */) 734 { 735 TRACE_SERIALIZE (this); 736 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); 737 if (unlikely (!ligature.serialize (c, num_ligatures))) return TRACE_RETURN (false); 738 for (unsigned int i = 0; i < num_ligatures; i++) 739 if (unlikely (!ligature[i].serialize (c, this).serialize (c, 740 ligatures[i], 741 component_list, 742 component_count_list[i]))) return TRACE_RETURN (false); 743 ligatures.advance (num_ligatures); 744 component_count_list.advance (num_ligatures); 745 return TRACE_RETURN (true); 746 } 747 748 inline bool sanitize (hb_sanitize_context_t *c) { 749 TRACE_SANITIZE (this); 750 return TRACE_RETURN (ligature.sanitize (c, this)); 751 } 752 753 protected: 754 OffsetArrayOf<Ligature> 755 ligature; /* Array LigatureSet tables 756 * ordered by preference */ 757 public: 758 DEFINE_SIZE_ARRAY (2, ligature); 759}; 760 761struct LigatureSubstFormat1 762{ 763 inline void closure (hb_closure_context_t *c) const 764 { 765 TRACE_CLOSURE (this); 766 Coverage::Iter iter; 767 for (iter.init (this+coverage); iter.more (); iter.next ()) { 768 if (c->glyphs->has (iter.get_glyph ())) 769 (this+ligatureSet[iter.get_coverage ()]).closure (c); 770 } 771 } 772 773 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 774 { 775 TRACE_COLLECT_GLYPHS (this); 776 Coverage::Iter iter; 777 for (iter.init (this+coverage); iter.more (); iter.next ()) { 778 c->input->add (iter.get_glyph ()); 779 (this+ligatureSet[iter.get_coverage ()]).collect_glyphs (c); 780 } 781 } 782 783 inline const Coverage &get_coverage (void) const 784 { 785 return this+coverage; 786 } 787 788 inline bool would_apply (hb_would_apply_context_t *c) const 789 { 790 TRACE_WOULD_APPLY (this); 791 unsigned int index = (this+coverage).get_coverage (c->glyphs[0]); 792 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 793 794 const LigatureSet &lig_set = this+ligatureSet[index]; 795 return TRACE_RETURN (lig_set.would_apply (c)); 796 } 797 798 inline bool apply (hb_apply_context_t *c) const 799 { 800 TRACE_APPLY (this); 801 hb_codepoint_t glyph_id = c->buffer->cur().codepoint; 802 803 unsigned int index = (this+coverage).get_coverage (glyph_id); 804 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 805 806 const LigatureSet &lig_set = this+ligatureSet[index]; 807 return TRACE_RETURN (lig_set.apply (c)); 808 } 809 810 inline bool serialize (hb_serialize_context_t *c, 811 Supplier<GlyphID> &first_glyphs, 812 Supplier<unsigned int> &ligature_per_first_glyph_count_list, 813 unsigned int num_first_glyphs, 814 Supplier<GlyphID> &ligatures_list, 815 Supplier<unsigned int> &component_count_list, 816 Supplier<GlyphID> &component_list /* Starting from second for each ligature */) 817 { 818 TRACE_SERIALIZE (this); 819 if (unlikely (!c->extend_min (*this))) return TRACE_RETURN (false); 820 if (unlikely (!ligatureSet.serialize (c, num_first_glyphs))) return TRACE_RETURN (false); 821 for (unsigned int i = 0; i < num_first_glyphs; i++) 822 if (unlikely (!ligatureSet[i].serialize (c, this).serialize (c, 823 ligatures_list, 824 component_count_list, 825 ligature_per_first_glyph_count_list[i], 826 component_list))) return TRACE_RETURN (false); 827 ligature_per_first_glyph_count_list.advance (num_first_glyphs); 828 if (unlikely (!coverage.serialize (c, this).serialize (c, first_glyphs, num_first_glyphs))) return TRACE_RETURN (false); 829 return TRACE_RETURN (true); 830 } 831 832 inline bool sanitize (hb_sanitize_context_t *c) { 833 TRACE_SANITIZE (this); 834 return TRACE_RETURN (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this)); 835 } 836 837 protected: 838 USHORT format; /* Format identifier--format = 1 */ 839 OffsetTo<Coverage> 840 coverage; /* Offset to Coverage table--from 841 * beginning of Substitution table */ 842 OffsetArrayOf<LigatureSet> 843 ligatureSet; /* Array LigatureSet tables 844 * ordered by Coverage Index */ 845 public: 846 DEFINE_SIZE_ARRAY (6, ligatureSet); 847}; 848 849struct LigatureSubst 850{ 851 inline bool serialize (hb_serialize_context_t *c, 852 Supplier<GlyphID> &first_glyphs, 853 Supplier<unsigned int> &ligature_per_first_glyph_count_list, 854 unsigned int num_first_glyphs, 855 Supplier<GlyphID> &ligatures_list, 856 Supplier<unsigned int> &component_count_list, 857 Supplier<GlyphID> &component_list /* Starting from second for each ligature */) 858 { 859 TRACE_SERIALIZE (this); 860 if (unlikely (!c->extend_min (u.format))) return TRACE_RETURN (false); 861 unsigned int format = 1; 862 u.format.set (format); 863 switch (u.format) { 864 case 1: return TRACE_RETURN (u.format1.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs, 865 ligatures_list, component_count_list, component_list)); 866 default:return TRACE_RETURN (false); 867 } 868 } 869 870 template <typename context_t> 871 inline typename context_t::return_t dispatch (context_t *c) const 872 { 873 TRACE_DISPATCH (this); 874 switch (u.format) { 875 case 1: return TRACE_RETURN (c->dispatch (u.format1)); 876 default:return TRACE_RETURN (c->default_return_value ()); 877 } 878 } 879 880 inline bool sanitize (hb_sanitize_context_t *c) { 881 TRACE_SANITIZE (this); 882 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 883 switch (u.format) { 884 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 885 default:return TRACE_RETURN (true); 886 } 887 } 888 889 protected: 890 union { 891 USHORT format; /* Format identifier */ 892 LigatureSubstFormat1 format1; 893 } u; 894}; 895 896 897struct ContextSubst : Context {}; 898 899struct ChainContextSubst : ChainContext {}; 900 901struct ExtensionSubst : Extension<ExtensionSubst> 902{ 903 typedef struct SubstLookupSubTable LookupSubTable; 904 905 inline bool is_reverse (void) const; 906}; 907 908 909struct ReverseChainSingleSubstFormat1 910{ 911 inline void closure (hb_closure_context_t *c) const 912 { 913 TRACE_CLOSURE (this); 914 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 915 916 unsigned int count; 917 918 count = backtrack.len; 919 for (unsigned int i = 0; i < count; i++) 920 if (!(this+backtrack[i]).intersects (c->glyphs)) 921 return; 922 923 count = lookahead.len; 924 for (unsigned int i = 0; i < count; i++) 925 if (!(this+lookahead[i]).intersects (c->glyphs)) 926 return; 927 928 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead); 929 Coverage::Iter iter; 930 for (iter.init (this+coverage); iter.more (); iter.next ()) { 931 if (c->glyphs->has (iter.get_glyph ())) 932 c->glyphs->add (substitute[iter.get_coverage ()]); 933 } 934 } 935 936 inline void collect_glyphs (hb_collect_glyphs_context_t *c) const 937 { 938 TRACE_COLLECT_GLYPHS (this); 939 940 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 941 942 unsigned int count; 943 944 (this+coverage).add_coverage (c->input); 945 946 count = backtrack.len; 947 for (unsigned int i = 0; i < count; i++) 948 (this+backtrack[i]).add_coverage (c->before); 949 950 count = lookahead.len; 951 for (unsigned int i = 0; i < count; i++) 952 (this+lookahead[i]).add_coverage (c->after); 953 954 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead); 955 count = substitute.len; 956 for (unsigned int i = 0; i < count; i++) 957 c->output->add (substitute[i]); 958 } 959 960 inline const Coverage &get_coverage (void) const 961 { 962 return this+coverage; 963 } 964 965 inline bool would_apply (hb_would_apply_context_t *c) const 966 { 967 TRACE_WOULD_APPLY (this); 968 return TRACE_RETURN (c->len == 1 && (this+coverage).get_coverage (c->glyphs[0]) != NOT_COVERED); 969 } 970 971 inline bool apply (hb_apply_context_t *c) const 972 { 973 TRACE_APPLY (this); 974 if (unlikely (c->nesting_level_left != MAX_NESTING_LEVEL)) 975 return TRACE_RETURN (false); /* No chaining to this type */ 976 977 unsigned int index = (this+coverage).get_coverage (c->buffer->cur().codepoint); 978 if (likely (index == NOT_COVERED)) return TRACE_RETURN (false); 979 980 const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 981 const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead); 982 983 if (match_backtrack (c, 984 backtrack.len, (USHORT *) backtrack.array, 985 match_coverage, this) && 986 match_lookahead (c, 987 lookahead.len, (USHORT *) lookahead.array, 988 match_coverage, this, 989 1)) 990 { 991 c->replace_glyph_inplace (substitute[index]); 992 c->buffer->idx--; /* Reverse! */ 993 return TRACE_RETURN (true); 994 } 995 996 return TRACE_RETURN (false); 997 } 998 999 inline bool sanitize (hb_sanitize_context_t *c) { 1000 TRACE_SANITIZE (this); 1001 if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this))) 1002 return TRACE_RETURN (false); 1003 OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack); 1004 if (!lookahead.sanitize (c, this)) 1005 return TRACE_RETURN (false); 1006 ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead); 1007 return TRACE_RETURN (substitute.sanitize (c)); 1008 } 1009 1010 protected: 1011 USHORT format; /* Format identifier--format = 1 */ 1012 OffsetTo<Coverage> 1013 coverage; /* Offset to Coverage table--from 1014 * beginning of table */ 1015 OffsetArrayOf<Coverage> 1016 backtrack; /* Array of coverage tables 1017 * in backtracking sequence, in glyph 1018 * sequence order */ 1019 OffsetArrayOf<Coverage> 1020 lookaheadX; /* Array of coverage tables 1021 * in lookahead sequence, in glyph 1022 * sequence order */ 1023 ArrayOf<GlyphID> 1024 substituteX; /* Array of substitute 1025 * GlyphIDs--ordered by Coverage Index */ 1026 public: 1027 DEFINE_SIZE_MIN (10); 1028}; 1029 1030struct ReverseChainSingleSubst 1031{ 1032 template <typename context_t> 1033 inline typename context_t::return_t dispatch (context_t *c) const 1034 { 1035 TRACE_DISPATCH (this); 1036 switch (u.format) { 1037 case 1: return TRACE_RETURN (c->dispatch (u.format1)); 1038 default:return TRACE_RETURN (c->default_return_value ()); 1039 } 1040 } 1041 1042 inline bool sanitize (hb_sanitize_context_t *c) { 1043 TRACE_SANITIZE (this); 1044 if (!u.format.sanitize (c)) return TRACE_RETURN (false); 1045 switch (u.format) { 1046 case 1: return TRACE_RETURN (u.format1.sanitize (c)); 1047 default:return TRACE_RETURN (true); 1048 } 1049 } 1050 1051 protected: 1052 union { 1053 USHORT format; /* Format identifier */ 1054 ReverseChainSingleSubstFormat1 format1; 1055 } u; 1056}; 1057 1058 1059 1060/* 1061 * SubstLookup 1062 */ 1063 1064struct SubstLookupSubTable 1065{ 1066 friend struct SubstLookup; 1067 1068 enum Type { 1069 Single = 1, 1070 Multiple = 2, 1071 Alternate = 3, 1072 Ligature = 4, 1073 Context = 5, 1074 ChainContext = 6, 1075 Extension = 7, 1076 ReverseChainSingle = 8 1077 }; 1078 1079 template <typename context_t> 1080 inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const 1081 { 1082 TRACE_DISPATCH (this); 1083 switch (lookup_type) { 1084 case Single: return TRACE_RETURN (u.single.dispatch (c)); 1085 case Multiple: return TRACE_RETURN (u.multiple.dispatch (c)); 1086 case Alternate: return TRACE_RETURN (u.alternate.dispatch (c)); 1087 case Ligature: return TRACE_RETURN (u.ligature.dispatch (c)); 1088 case Context: return TRACE_RETURN (u.context.dispatch (c)); 1089 case ChainContext: return TRACE_RETURN (u.chainContext.dispatch (c)); 1090 case Extension: return TRACE_RETURN (u.extension.dispatch (c)); 1091 case ReverseChainSingle: return TRACE_RETURN (u.reverseChainContextSingle.dispatch (c)); 1092 default: return TRACE_RETURN (c->default_return_value ()); 1093 } 1094 } 1095 1096 inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) { 1097 TRACE_SANITIZE (this); 1098 if (!u.header.sub_format.sanitize (c)) 1099 return TRACE_RETURN (false); 1100 switch (lookup_type) { 1101 case Single: return TRACE_RETURN (u.single.sanitize (c)); 1102 case Multiple: return TRACE_RETURN (u.multiple.sanitize (c)); 1103 case Alternate: return TRACE_RETURN (u.alternate.sanitize (c)); 1104 case Ligature: return TRACE_RETURN (u.ligature.sanitize (c)); 1105 case Context: return TRACE_RETURN (u.context.sanitize (c)); 1106 case ChainContext: return TRACE_RETURN (u.chainContext.sanitize (c)); 1107 case Extension: return TRACE_RETURN (u.extension.sanitize (c)); 1108 case ReverseChainSingle: return TRACE_RETURN (u.reverseChainContextSingle.sanitize (c)); 1109 default: return TRACE_RETURN (true); 1110 } 1111 } 1112 1113 protected: 1114 union { 1115 struct { 1116 USHORT sub_format; 1117 } header; 1118 SingleSubst single; 1119 MultipleSubst multiple; 1120 AlternateSubst alternate; 1121 LigatureSubst ligature; 1122 ContextSubst context; 1123 ChainContextSubst chainContext; 1124 ExtensionSubst extension; 1125 ReverseChainSingleSubst reverseChainContextSingle; 1126 } u; 1127 public: 1128 DEFINE_SIZE_UNION (2, header.sub_format); 1129}; 1130 1131 1132struct SubstLookup : Lookup 1133{ 1134 inline const SubstLookupSubTable& get_subtable (unsigned int i) const 1135 { return this+CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i]; } 1136 1137 inline static bool lookup_type_is_reverse (unsigned int lookup_type) 1138 { return lookup_type == SubstLookupSubTable::ReverseChainSingle; } 1139 1140 inline bool is_reverse (void) const 1141 { 1142 unsigned int type = get_type (); 1143 if (unlikely (type == SubstLookupSubTable::Extension)) 1144 return CastR<ExtensionSubst> (get_subtable(0)).is_reverse (); 1145 return lookup_type_is_reverse (type); 1146 } 1147 1148 inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const 1149 { 1150 TRACE_CLOSURE (this); 1151 c->set_recurse_func (dispatch_recurse_func<hb_closure_context_t>); 1152 return TRACE_RETURN (dispatch (c)); 1153 } 1154 1155 inline hb_collect_glyphs_context_t::return_t collect_glyphs_lookup (hb_collect_glyphs_context_t *c) const 1156 { 1157 TRACE_COLLECT_GLYPHS (this); 1158 c->set_recurse_func (dispatch_recurse_func<hb_collect_glyphs_context_t>); 1159 return TRACE_RETURN (dispatch (c)); 1160 } 1161 1162 template <typename set_t> 1163 inline void add_coverage (set_t *glyphs) const 1164 { 1165 hb_get_coverage_context_t c; 1166 const Coverage *last = NULL; 1167 unsigned int count = get_subtable_count (); 1168 for (unsigned int i = 0; i < count; i++) { 1169 const Coverage *coverage = &get_subtable (i).dispatch (&c, get_type ()); 1170 if (coverage != last) { 1171 coverage->add_coverage (glyphs); 1172 last = coverage; 1173 } 1174 } 1175 } 1176 1177 inline bool would_apply (hb_would_apply_context_t *c, const hb_set_digest_t *digest) const 1178 { 1179 TRACE_WOULD_APPLY (this); 1180 if (unlikely (!c->len)) return TRACE_RETURN (false); 1181 if (!digest->may_have (c->glyphs[0])) return TRACE_RETURN (false); 1182 return TRACE_RETURN (dispatch (c)); 1183 } 1184 1185 inline bool apply_once (hb_apply_context_t *c) const 1186 { 1187 TRACE_APPLY (this); 1188 if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props)) 1189 return TRACE_RETURN (false); 1190 return TRACE_RETURN (dispatch (c)); 1191 } 1192 1193 static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index); 1194 inline bool apply_string (hb_apply_context_t *c, const hb_set_digest_t *digest) const 1195 { 1196 bool ret = false; 1197 1198 if (unlikely (!c->buffer->len || !c->lookup_mask)) 1199 return false; 1200 1201 c->set_recurse_func (apply_recurse_func); 1202 c->set_lookup (*this); 1203 1204 if (likely (!is_reverse ())) 1205 { 1206 /* in/out forward substitution */ 1207 c->buffer->clear_output (); 1208 c->buffer->idx = 0; 1209 1210 while (c->buffer->idx < c->buffer->len) 1211 { 1212 if (digest->may_have (c->buffer->cur().codepoint) && 1213 (c->buffer->cur().mask & c->lookup_mask) && 1214 apply_once (c)) 1215 ret = true; 1216 else 1217 c->buffer->next_glyph (); 1218 } 1219 if (ret) 1220 c->buffer->swap_buffers (); 1221 } 1222 else 1223 { 1224 /* in-place backward substitution */ 1225 c->buffer->remove_output (); 1226 c->buffer->idx = c->buffer->len - 1; 1227 do 1228 { 1229 if (digest->may_have (c->buffer->cur().codepoint) && 1230 (c->buffer->cur().mask & c->lookup_mask) && 1231 apply_once (c)) 1232 ret = true; 1233 else 1234 c->buffer->idx--; 1235 1236 } 1237 while ((int) c->buffer->idx >= 0); 1238 } 1239 1240 return ret; 1241 } 1242 1243 inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c, 1244 unsigned int i) 1245 { return CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i].serialize (c, this); } 1246 1247 inline bool serialize_single (hb_serialize_context_t *c, 1248 uint32_t lookup_props, 1249 Supplier<GlyphID> &glyphs, 1250 Supplier<GlyphID> &substitutes, 1251 unsigned int num_glyphs) 1252 { 1253 TRACE_SERIALIZE (this); 1254 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Single, lookup_props, 1))) return TRACE_RETURN (false); 1255 return TRACE_RETURN (serialize_subtable (c, 0).u.single.serialize (c, glyphs, substitutes, num_glyphs)); 1256 } 1257 1258 inline bool serialize_multiple (hb_serialize_context_t *c, 1259 uint32_t lookup_props, 1260 Supplier<GlyphID> &glyphs, 1261 Supplier<unsigned int> &substitute_len_list, 1262 unsigned int num_glyphs, 1263 Supplier<GlyphID> &substitute_glyphs_list) 1264 { 1265 TRACE_SERIALIZE (this); 1266 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Multiple, lookup_props, 1))) return TRACE_RETURN (false); 1267 return TRACE_RETURN (serialize_subtable (c, 0).u.multiple.serialize (c, glyphs, substitute_len_list, num_glyphs, 1268 substitute_glyphs_list)); 1269 } 1270 1271 inline bool serialize_alternate (hb_serialize_context_t *c, 1272 uint32_t lookup_props, 1273 Supplier<GlyphID> &glyphs, 1274 Supplier<unsigned int> &alternate_len_list, 1275 unsigned int num_glyphs, 1276 Supplier<GlyphID> &alternate_glyphs_list) 1277 { 1278 TRACE_SERIALIZE (this); 1279 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Alternate, lookup_props, 1))) return TRACE_RETURN (false); 1280 return TRACE_RETURN (serialize_subtable (c, 0).u.alternate.serialize (c, glyphs, alternate_len_list, num_glyphs, 1281 alternate_glyphs_list)); 1282 } 1283 1284 inline bool serialize_ligature (hb_serialize_context_t *c, 1285 uint32_t lookup_props, 1286 Supplier<GlyphID> &first_glyphs, 1287 Supplier<unsigned int> &ligature_per_first_glyph_count_list, 1288 unsigned int num_first_glyphs, 1289 Supplier<GlyphID> &ligatures_list, 1290 Supplier<unsigned int> &component_count_list, 1291 Supplier<GlyphID> &component_list /* Starting from second for each ligature */) 1292 { 1293 TRACE_SERIALIZE (this); 1294 if (unlikely (!Lookup::serialize (c, SubstLookupSubTable::Ligature, lookup_props, 1))) return TRACE_RETURN (false); 1295 return TRACE_RETURN (serialize_subtable (c, 0).u.ligature.serialize (c, first_glyphs, ligature_per_first_glyph_count_list, num_first_glyphs, 1296 ligatures_list, component_count_list, component_list)); 1297 } 1298 1299 template <typename context_t> 1300 static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index); 1301 1302 template <typename context_t> 1303 inline typename context_t::return_t dispatch (context_t *c) const 1304 { 1305 TRACE_DISPATCH (this); 1306 unsigned int lookup_type = get_type (); 1307 unsigned int count = get_subtable_count (); 1308 for (unsigned int i = 0; i < count; i++) { 1309 typename context_t::return_t r = get_subtable (i).dispatch (c, lookup_type); 1310 if (c->stop_sublookup_iteration (r)) 1311 return TRACE_RETURN (r); 1312 } 1313 return TRACE_RETURN (c->default_return_value ()); 1314 } 1315 1316 inline bool sanitize (hb_sanitize_context_t *c) 1317 { 1318 TRACE_SANITIZE (this); 1319 if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false); 1320 OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable); 1321 if (unlikely (!list.sanitize (c, this, get_type ()))) return TRACE_RETURN (false); 1322 1323 if (unlikely (get_type () == SubstLookupSubTable::Extension)) 1324 { 1325 /* The spec says all subtables of an Extension lookup should 1326 * have the same type. This is specially important if one has 1327 * a reverse type! */ 1328 unsigned int type = get_subtable (0).u.extension.get_type (); 1329 unsigned int count = get_subtable_count (); 1330 for (unsigned int i = 1; i < count; i++) 1331 if (get_subtable (i).u.extension.get_type () != type) 1332 return TRACE_RETURN (false); 1333 } 1334 return TRACE_RETURN (true); 1335 } 1336}; 1337 1338typedef OffsetListOf<SubstLookup> SubstLookupList; 1339 1340/* 1341 * GSUB -- The Glyph Substitution Table 1342 */ 1343 1344struct GSUB : GSUBGPOS 1345{ 1346 static const hb_tag_t Tag = HB_OT_TAG_GSUB; 1347 1348 inline const SubstLookup& get_lookup (unsigned int i) const 1349 { return CastR<SubstLookup> (GSUBGPOS::get_lookup (i)); } 1350 1351 static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer); 1352 static inline void substitute_finish (hb_font_t *font, hb_buffer_t *buffer); 1353 1354 inline bool sanitize (hb_sanitize_context_t *c) { 1355 TRACE_SANITIZE (this); 1356 if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false); 1357 OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList); 1358 return TRACE_RETURN (list.sanitize (c, this)); 1359 } 1360 public: 1361 DEFINE_SIZE_STATIC (10); 1362}; 1363 1364 1365void 1366GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer) 1367{ 1368 HB_BUFFER_ALLOCATE_VAR (buffer, glyph_props); 1369 HB_BUFFER_ALLOCATE_VAR (buffer, lig_props); 1370 HB_BUFFER_ALLOCATE_VAR (buffer, syllable); 1371 1372 const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef; 1373 unsigned int count = buffer->len; 1374 for (unsigned int i = 0; i < count; i++) { 1375 buffer->info[i].lig_props() = buffer->info[i].syllable() = 0; 1376 buffer->info[i].glyph_props() = gdef.get_glyph_props (buffer->info[i].codepoint); 1377 } 1378} 1379 1380void 1381GSUB::substitute_finish (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer HB_UNUSED) 1382{ 1383} 1384 1385 1386/* Out-of-class implementation for methods recursing */ 1387 1388inline bool ExtensionSubst::is_reverse (void) const 1389{ 1390 unsigned int type = get_type (); 1391 if (unlikely (type == SubstLookupSubTable::Extension)) 1392 return CastR<ExtensionSubst> (get_subtable<SubstLookupSubTable>()).is_reverse (); 1393 return SubstLookup::lookup_type_is_reverse (type); 1394} 1395 1396template <typename context_t> 1397inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index) 1398{ 1399 const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub); 1400 const SubstLookup &l = gsub.get_lookup (lookup_index); 1401 return l.dispatch (c); 1402} 1403 1404inline bool SubstLookup::apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index) 1405{ 1406 const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub); 1407 const SubstLookup &l = gsub.get_lookup (lookup_index); 1408 unsigned int saved_lookup_props = c->lookup_props; 1409 c->set_lookup (l); 1410 bool ret = l.apply_once (c); 1411 c->lookup_props = saved_lookup_props; 1412 return ret; 1413} 1414 1415 1416} /* namespace OT */ 1417 1418 1419#endif /* HB_OT_LAYOUT_GSUB_TABLE_HH */ 1420