2 * Copyright © 2007,2008,2009 Red Hat, Inc.
3 * Copyright © 2010,2011,2012 Google, Inc.
5 * This is part of HarfBuzz, a text shaping library.
7 * Permission is hereby granted, without written agreement and without
8 * license or royalty fees, to use, copy, modify, and distribute this
9 * software and its documentation for any purpose, provided that the
10 * above copyright notice and the following two paragraphs appear in
11 * all copies of this software.
13 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
14 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
15 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
16 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
19 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
20 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
22 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
23 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
25 * Red Hat Author(s): Behdad Esfahbod
26 * Google Author(s): Behdad Esfahbod
29 #ifndef HB_OT_LAYOUT_GDEF_TABLE_HH
30 #define HB_OT_LAYOUT_GDEF_TABLE_HH
32 #include "hb-ot-layout-common.hh"
41 * Attachment List Table
44 /* Array of contour point indices--in increasing numerical order */
45 struct AttachPoint : Array16Of<HBUINT16>
47 bool subset (hb_subset_context_t *c) const
50 auto *out = c->serializer->start_embed (*this);
51 if (unlikely (!out)) return_trace (false);
53 return_trace (out->serialize (c->serializer, + iter ()));
59 unsigned int get_attach_points (hb_codepoint_t glyph_id,
60 unsigned int start_offset,
61 unsigned int *point_count /* IN/OUT */,
62 unsigned int *point_array /* OUT */) const
64 unsigned int index = (this+coverage).get_coverage (glyph_id);
65 if (index == NOT_COVERED)
72 const AttachPoint &points = this+attachPoint[index];
76 + points.sub_array (start_offset, point_count)
77 | hb_sink (hb_array (point_array, *point_count))
84 bool subset (hb_subset_context_t *c) const
87 const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
88 const hb_map_t &glyph_map = *c->plan->glyph_map;
90 auto *out = c->serializer->start_embed (*this);
91 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
93 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
94 + hb_zip (this+coverage, attachPoint)
95 | hb_filter (glyphset, hb_first)
96 | hb_filter (subset_offset_array (c, out->attachPoint, this), hb_second)
99 | hb_sink (new_coverage)
101 out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
102 return_trace (bool (new_coverage));
105 bool sanitize (hb_sanitize_context_t *c) const
107 TRACE_SANITIZE (this);
108 return_trace (coverage.sanitize (c, this) && attachPoint.sanitize (c, this));
113 coverage; /* Offset to Coverage table -- from
114 * beginning of AttachList table */
115 Array16OfOffset16To<AttachPoint>
116 attachPoint; /* Array of AttachPoint tables
117 * in Coverage Index order */
119 DEFINE_SIZE_ARRAY (4, attachPoint);
123 * Ligature Caret Table
126 struct CaretValueFormat1
128 friend struct CaretValue;
129 bool subset (hb_subset_context_t *c) const
132 auto *out = c->serializer->embed (this);
133 if (unlikely (!out)) return_trace (false);
138 hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction) const
140 return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate);
143 bool sanitize (hb_sanitize_context_t *c) const
145 TRACE_SANITIZE (this);
146 return_trace (c->check_struct (this));
150 HBUINT16 caretValueFormat; /* Format identifier--format = 1 */
151 FWORD coordinate; /* X or Y value, in design units */
153 DEFINE_SIZE_STATIC (4);
156 struct CaretValueFormat2
158 friend struct CaretValue;
159 bool subset (hb_subset_context_t *c) const
162 auto *out = c->serializer->embed (this);
163 if (unlikely (!out)) return_trace (false);
168 hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const
171 font->get_glyph_contour_point_for_origin (glyph_id, caretValuePoint, direction, &x, &y);
172 return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y;
175 bool sanitize (hb_sanitize_context_t *c) const
177 TRACE_SANITIZE (this);
178 return_trace (c->check_struct (this));
182 HBUINT16 caretValueFormat; /* Format identifier--format = 2 */
183 HBUINT16 caretValuePoint; /* Contour point index on glyph */
185 DEFINE_SIZE_STATIC (4);
188 struct CaretValueFormat3
190 friend struct CaretValue;
192 hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction,
193 const VariationStore &var_store) const
195 return HB_DIRECTION_IS_HORIZONTAL (direction) ?
196 font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) :
197 font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store);
200 bool subset (hb_subset_context_t *c) const
203 auto *out = c->serializer->embed (this);
204 if (unlikely (!out)) return_trace (false);
206 return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, this, c->serializer->to_bias (out),
207 hb_serialize_context_t::Head, c->plan->layout_variation_idx_map));
210 void collect_variation_indices (hb_set_t *layout_variation_indices) const
211 { (this+deviceTable).collect_variation_indices (layout_variation_indices); }
213 bool sanitize (hb_sanitize_context_t *c) const
215 TRACE_SANITIZE (this);
216 return_trace (c->check_struct (this) && deviceTable.sanitize (c, this));
220 HBUINT16 caretValueFormat; /* Format identifier--format = 3 */
221 FWORD coordinate; /* X or Y value, in design units */
223 deviceTable; /* Offset to Device table for X or Y
224 * value--from beginning of CaretValue
227 DEFINE_SIZE_STATIC (6);
232 hb_position_t get_caret_value (hb_font_t *font,
233 hb_direction_t direction,
234 hb_codepoint_t glyph_id,
235 const VariationStore &var_store) const
238 case 1: return u.format1.get_caret_value (font, direction);
239 case 2: return u.format2.get_caret_value (font, direction, glyph_id);
240 case 3: return u.format3.get_caret_value (font, direction, var_store);
245 template <typename context_t, typename ...Ts>
246 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
248 TRACE_DISPATCH (this, u.format);
249 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
251 case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
252 case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
253 case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
254 default:return_trace (c->default_return_value ());
258 void collect_variation_indices (hb_set_t *layout_variation_indices) const
265 u.format3.collect_variation_indices (layout_variation_indices);
271 bool sanitize (hb_sanitize_context_t *c) const
273 TRACE_SANITIZE (this);
274 if (!u.format.sanitize (c)) return_trace (false);
276 case 1: return_trace (u.format1.sanitize (c));
277 case 2: return_trace (u.format2.sanitize (c));
278 case 3: return_trace (u.format3.sanitize (c));
279 default:return_trace (true);
285 HBUINT16 format; /* Format identifier */
286 CaretValueFormat1 format1;
287 CaretValueFormat2 format2;
288 CaretValueFormat3 format3;
291 DEFINE_SIZE_UNION (2, format);
296 unsigned get_lig_carets (hb_font_t *font,
297 hb_direction_t direction,
298 hb_codepoint_t glyph_id,
299 const VariationStore &var_store,
300 unsigned start_offset,
301 unsigned *caret_count /* IN/OUT */,
302 hb_position_t *caret_array /* OUT */) const
306 + carets.sub_array (start_offset, caret_count)
307 | hb_map (hb_add (this))
308 | hb_map ([&] (const CaretValue &value) { return value.get_caret_value (font, direction, glyph_id, var_store); })
309 | hb_sink (hb_array (caret_array, *caret_count))
316 bool subset (hb_subset_context_t *c) const
319 auto *out = c->serializer->start_embed (*this);
320 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
323 | hb_apply (subset_offset_array (c, out->carets, this))
326 return_trace (bool (out->carets));
329 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
331 for (const Offset16To<CaretValue>& offset : carets.iter ())
332 (this+offset).collect_variation_indices (c->layout_variation_indices);
335 bool sanitize (hb_sanitize_context_t *c) const
337 TRACE_SANITIZE (this);
338 return_trace (carets.sanitize (c, this));
342 Array16OfOffset16To<CaretValue>
343 carets; /* Offset array of CaretValue tables
344 * --from beginning of LigGlyph table
345 * --in increasing coordinate order */
347 DEFINE_SIZE_ARRAY (2, carets);
352 unsigned int get_lig_carets (hb_font_t *font,
353 hb_direction_t direction,
354 hb_codepoint_t glyph_id,
355 const VariationStore &var_store,
356 unsigned int start_offset,
357 unsigned int *caret_count /* IN/OUT */,
358 hb_position_t *caret_array /* OUT */) const
360 unsigned int index = (this+coverage).get_coverage (glyph_id);
361 if (index == NOT_COVERED)
367 const LigGlyph &lig_glyph = this+ligGlyph[index];
368 return lig_glyph.get_lig_carets (font, direction, glyph_id, var_store, start_offset, caret_count, caret_array);
371 bool subset (hb_subset_context_t *c) const
374 const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
375 const hb_map_t &glyph_map = *c->plan->glyph_map;
377 auto *out = c->serializer->start_embed (*this);
378 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
380 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
381 + hb_zip (this+coverage, ligGlyph)
382 | hb_filter (glyphset, hb_first)
383 | hb_filter (subset_offset_array (c, out->ligGlyph, this), hb_second)
386 | hb_sink (new_coverage)
388 out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
389 return_trace (bool (new_coverage));
392 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
394 + hb_zip (this+coverage, ligGlyph)
395 | hb_filter (c->glyph_set, hb_first)
397 | hb_map (hb_add (this))
398 | hb_apply ([c] (const LigGlyph& _) { _.collect_variation_indices (c); })
402 bool sanitize (hb_sanitize_context_t *c) const
404 TRACE_SANITIZE (this);
405 return_trace (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this));
410 coverage; /* Offset to Coverage table--from
411 * beginning of LigCaretList table */
412 Array16OfOffset16To<LigGlyph>
413 ligGlyph; /* Array of LigGlyph tables
414 * in Coverage Index order */
416 DEFINE_SIZE_ARRAY (4, ligGlyph);
420 struct MarkGlyphSetsFormat1
422 bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
423 { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }
425 bool subset (hb_subset_context_t *c) const
428 auto *out = c->serializer->start_embed (*this);
429 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
430 out->format = format;
433 for (const Offset32To<Coverage>& offset : coverage.iter ())
435 auto *o = out->coverage.serialize_append (c->serializer);
442 //not using o->serialize_subset (c, offset, this, out) here because
443 //OTS doesn't allow null offset.
444 //See issue: https://github.com/khaledhosny/ots/issues/172
445 c->serializer->push ();
446 c->dispatch (this+offset);
447 c->serializer->add_link (*o, c->serializer->pop_pack ());
450 return_trace (ret && out->coverage.len);
453 bool sanitize (hb_sanitize_context_t *c) const
455 TRACE_SANITIZE (this);
456 return_trace (coverage.sanitize (c, this));
460 HBUINT16 format; /* Format identifier--format = 1 */
461 Array16Of<Offset32To<Coverage>>
462 coverage; /* Array of long offsets to mark set
465 DEFINE_SIZE_ARRAY (4, coverage);
470 bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
473 case 1: return u.format1.covers (set_index, glyph_id);
474 default:return false;
478 bool subset (hb_subset_context_t *c) const
482 case 1: return_trace (u.format1.subset (c));
483 default:return_trace (false);
487 bool sanitize (hb_sanitize_context_t *c) const
489 TRACE_SANITIZE (this);
490 if (!u.format.sanitize (c)) return_trace (false);
492 case 1: return_trace (u.format1.sanitize (c));
493 default:return_trace (true);
499 HBUINT16 format; /* Format identifier */
500 MarkGlyphSetsFormat1 format1;
503 DEFINE_SIZE_UNION (2, format);
508 * GDEF -- Glyph Definition
509 * https://docs.microsoft.com/en-us/typography/opentype/spec/gdef
515 static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF;
518 UnclassifiedGlyph = 0,
525 bool has_data () const { return version.to_int (); }
526 bool has_glyph_classes () const { return glyphClassDef != 0; }
527 unsigned int get_glyph_class (hb_codepoint_t glyph) const
528 { return (this+glyphClassDef).get_class (glyph); }
529 void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const
530 { (this+glyphClassDef).collect_class (glyphs, klass); }
532 bool has_mark_attachment_types () const { return markAttachClassDef != 0; }
533 unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const
534 { return (this+markAttachClassDef).get_class (glyph); }
536 bool has_attach_points () const { return attachList != 0; }
537 unsigned int get_attach_points (hb_codepoint_t glyph_id,
538 unsigned int start_offset,
539 unsigned int *point_count /* IN/OUT */,
540 unsigned int *point_array /* OUT */) const
541 { return (this+attachList).get_attach_points (glyph_id, start_offset, point_count, point_array); }
543 bool has_lig_carets () const { return ligCaretList != 0; }
544 unsigned int get_lig_carets (hb_font_t *font,
545 hb_direction_t direction,
546 hb_codepoint_t glyph_id,
547 unsigned int start_offset,
548 unsigned int *caret_count /* IN/OUT */,
549 hb_position_t *caret_array /* OUT */) const
550 { return (this+ligCaretList).get_lig_carets (font,
551 direction, glyph_id, get_var_store(),
552 start_offset, caret_count, caret_array); }
554 bool has_mark_sets () const { return version.to_int () >= 0x00010002u && markGlyphSetsDef != 0; }
555 bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
556 { return version.to_int () >= 0x00010002u && (this+markGlyphSetsDef).covers (set_index, glyph_id); }
558 bool has_var_store () const { return version.to_int () >= 0x00010003u && varStore != 0; }
559 const VariationStore &get_var_store () const
560 { return version.to_int () >= 0x00010003u ? this+varStore : Null (VariationStore); }
562 /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
563 * glyph class and other bits, and high 8-bit the mark attachment type (if any).
564 * Not to be confused with lookup_props which is very similar. */
565 unsigned int get_glyph_props (hb_codepoint_t glyph) const
567 unsigned int klass = get_glyph_class (glyph);
569 static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs), "");
570 static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures), "");
571 static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks), "");
575 case BaseGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH;
576 case LigatureGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
578 klass = get_mark_attachment_type (glyph);
579 return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8);
583 HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
584 hb_face_t *face) const;
588 accelerator_t (hb_face_t *face)
590 table = hb_sanitize_context_t ().reference_table<GDEF> (face);
591 if (unlikely (table->is_blocklisted (table.get_blob (), face)))
593 hb_blob_destroy (table.get_blob ());
594 table = hb_blob_get_empty ();
597 ~accelerator_t () { table.destroy (); }
599 hb_blob_ptr_t<GDEF> table;
602 unsigned int get_size () const
605 (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) +
606 (version.to_int () >= 0x00010003u ? varStore.static_size : 0);
609 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
610 { (this+ligCaretList).collect_variation_indices (c); }
612 void remap_layout_variation_indices (const hb_set_t *layout_variation_indices,
613 hb_map_t *layout_variation_idx_map /* OUT */) const
615 if (version.to_int () < 0x00010003u || !varStore) return;
616 if (layout_variation_indices->is_empty ()) return;
618 unsigned new_major = 0, new_minor = 0;
619 unsigned last_major = (layout_variation_indices->get_min ()) >> 16;
620 for (unsigned idx : layout_variation_indices->iter ())
622 uint16_t major = idx >> 16;
623 if (major >= (this+varStore).get_sub_table_count ()) break;
624 if (major != last_major)
630 unsigned new_idx = (new_major << 16) + new_minor;
631 layout_variation_idx_map->set (idx, new_idx);
637 bool subset (hb_subset_context_t *c) const
640 auto *out = c->serializer->embed (*this);
641 if (unlikely (!out)) return_trace (false);
643 bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
644 bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
645 bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
646 bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
648 bool subset_markglyphsetsdef = true;
649 if (version.to_int () >= 0x00010002u)
651 subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
652 if (!subset_markglyphsetsdef &&
653 version.to_int () == 0x00010002u)
654 out->version.minor = 0;
657 bool subset_varstore = true;
658 if (version.to_int () >= 0x00010003u)
660 subset_varstore = out->varStore.serialize_subset (c, varStore, this);
661 if (!subset_varstore && version.to_int () == 0x00010003u)
662 out->version.minor = 2;
665 return_trace (subset_glyphclassdef || subset_attachlist ||
666 subset_ligcaretlist || subset_markattachclassdef ||
667 (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) ||
668 (out->version.to_int () >= 0x00010003u && subset_varstore));
671 bool sanitize (hb_sanitize_context_t *c) const
673 TRACE_SANITIZE (this);
674 return_trace (version.sanitize (c) &&
675 likely (version.major == 1) &&
676 glyphClassDef.sanitize (c, this) &&
677 attachList.sanitize (c, this) &&
678 ligCaretList.sanitize (c, this) &&
679 markAttachClassDef.sanitize (c, this) &&
680 (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
681 (version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
685 FixedVersion<>version; /* Version of the GDEF table--currently
688 glyphClassDef; /* Offset to class definition table
689 * for glyph type--from beginning of
690 * GDEF header (may be Null) */
691 Offset16To<AttachList>
692 attachList; /* Offset to list of glyphs with
693 * attachment points--from beginning
694 * of GDEF header (may be Null) */
695 Offset16To<LigCaretList>
696 ligCaretList; /* Offset to list of positioning points
697 * for ligature carets--from beginning
698 * of GDEF header (may be Null) */
700 markAttachClassDef; /* Offset to class definition table for
701 * mark attachment type--from beginning
702 * of GDEF header (may be Null) */
703 Offset16To<MarkGlyphSets>
704 markGlyphSetsDef; /* Offset to the table of mark set
705 * definitions--from beginning of GDEF
706 * header (may be NULL). Introduced
707 * in version 0x00010002. */
708 Offset32To<VariationStore>
709 varStore; /* Offset to the table of Item Variation
710 * Store--from beginning of GDEF
711 * header (may be NULL). Introduced
712 * in version 0x00010003. */
714 DEFINE_SIZE_MIN (12);
717 struct GDEF_accelerator_t : GDEF::accelerator_t {
718 GDEF_accelerator_t (hb_face_t *face) : GDEF::accelerator_t (face) {}
724 #endif /* HB_OT_LAYOUT_GDEF_TABLE_HH */