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