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