gfx/harfbuzz/src/hb-ot-layout-gsub-table.hh

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

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 */

mercurial