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 : ArrayOf<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 hb_array_t<const HBUINT16> array = points.sub_array (start_offset, point_count);
77 unsigned int count = array.length;
78 for (unsigned int i = 0; i < count; i++)
79 point_array[i] = array[i];
85 bool subset (hb_subset_context_t *c) const
88 const hb_set_t &glyphset = *c->plan->glyphset ();
89 const hb_map_t &glyph_map = *c->plan->glyph_map;
91 auto *out = c->serializer->start_embed (*this);
92 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
94 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
95 + hb_zip (this+coverage, attachPoint)
96 | hb_filter (glyphset, hb_first)
97 | hb_filter (subset_offset_array (c, out->attachPoint, this), hb_second)
100 | hb_sink (new_coverage)
102 out->coverage.serialize (c->serializer, out)
103 .serialize (c->serializer, new_coverage.iter ());
104 return_trace (bool (new_coverage));
107 bool sanitize (hb_sanitize_context_t *c) const
109 TRACE_SANITIZE (this);
110 return_trace (coverage.sanitize (c, this) && attachPoint.sanitize (c, this));
115 coverage; /* Offset to Coverage table -- from
116 * beginning of AttachList table */
117 OffsetArrayOf<AttachPoint>
118 attachPoint; /* Array of AttachPoint tables
119 * in Coverage Index order */
121 DEFINE_SIZE_ARRAY (4, attachPoint);
125 * Ligature Caret Table
128 struct CaretValueFormat1
130 friend struct CaretValue;
131 bool subset (hb_subset_context_t *c) const
134 auto *out = c->serializer->embed (this);
135 if (unlikely (!out)) return_trace (false);
140 hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction) const
142 return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate);
145 bool sanitize (hb_sanitize_context_t *c) const
147 TRACE_SANITIZE (this);
148 return_trace (c->check_struct (this));
152 HBUINT16 caretValueFormat; /* Format identifier--format = 1 */
153 FWORD coordinate; /* X or Y value, in design units */
155 DEFINE_SIZE_STATIC (4);
158 struct CaretValueFormat2
160 friend struct CaretValue;
161 bool subset (hb_subset_context_t *c) const
164 auto *out = c->serializer->embed (this);
165 if (unlikely (!out)) return_trace (false);
170 hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const
173 font->get_glyph_contour_point_for_origin (glyph_id, caretValuePoint, direction, &x, &y);
174 return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y;
177 bool sanitize (hb_sanitize_context_t *c) const
179 TRACE_SANITIZE (this);
180 return_trace (c->check_struct (this));
184 HBUINT16 caretValueFormat; /* Format identifier--format = 2 */
185 HBUINT16 caretValuePoint; /* Contour point index on glyph */
187 DEFINE_SIZE_STATIC (4);
190 struct CaretValueFormat3
192 friend struct CaretValue;
194 hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction,
195 const VariationStore &var_store) const
197 return HB_DIRECTION_IS_HORIZONTAL (direction) ?
198 font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) :
199 font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store);
202 bool subset (hb_subset_context_t *c) const
205 auto *out = c->serializer->embed (this);
206 if (unlikely (!out)) return_trace (false);
208 return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, this, c->serializer->to_bias (out),
209 hb_serialize_context_t::Head, c->plan->layout_variation_idx_map));
212 void collect_variation_indices (hb_set_t *layout_variation_indices) const
213 { (this+deviceTable).collect_variation_indices (layout_variation_indices); }
215 bool sanitize (hb_sanitize_context_t *c) const
217 TRACE_SANITIZE (this);
218 return_trace (c->check_struct (this) && deviceTable.sanitize (c, this));
222 HBUINT16 caretValueFormat; /* Format identifier--format = 3 */
223 FWORD coordinate; /* X or Y value, in design units */
225 deviceTable; /* Offset to Device table for X or Y
226 * value--from beginning of CaretValue
229 DEFINE_SIZE_STATIC (6);
234 hb_position_t get_caret_value (hb_font_t *font,
235 hb_direction_t direction,
236 hb_codepoint_t glyph_id,
237 const VariationStore &var_store) const
240 case 1: return u.format1.get_caret_value (font, direction);
241 case 2: return u.format2.get_caret_value (font, direction, glyph_id);
242 case 3: return u.format3.get_caret_value (font, direction, var_store);
247 template <typename context_t, typename ...Ts>
248 typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
250 TRACE_DISPATCH (this, u.format);
251 if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
253 case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
254 case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
255 case 3: return_trace (c->dispatch (u.format3, hb_forward<Ts> (ds)...));
256 default:return_trace (c->default_return_value ());
260 void collect_variation_indices (hb_set_t *layout_variation_indices) const
267 u.format3.collect_variation_indices (layout_variation_indices);
273 bool sanitize (hb_sanitize_context_t *c) const
275 TRACE_SANITIZE (this);
276 if (!u.format.sanitize (c)) return_trace (false);
278 case 1: return_trace (u.format1.sanitize (c));
279 case 2: return_trace (u.format2.sanitize (c));
280 case 3: return_trace (u.format3.sanitize (c));
281 default:return_trace (true);
287 HBUINT16 format; /* Format identifier */
288 CaretValueFormat1 format1;
289 CaretValueFormat2 format2;
290 CaretValueFormat3 format3;
293 DEFINE_SIZE_UNION (2, format);
298 unsigned get_lig_carets (hb_font_t *font,
299 hb_direction_t direction,
300 hb_codepoint_t glyph_id,
301 const VariationStore &var_store,
302 unsigned start_offset,
303 unsigned *caret_count /* IN/OUT */,
304 hb_position_t *caret_array /* OUT */) const
308 + carets.sub_array (start_offset, caret_count)
309 | hb_map (hb_add (this))
310 | hb_map ([&] (const CaretValue &value) { return value.get_caret_value (font, direction, glyph_id, var_store); })
311 | hb_sink (hb_array (caret_array, *caret_count))
318 bool subset (hb_subset_context_t *c) const
321 auto *out = c->serializer->start_embed (*this);
322 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
325 | hb_apply (subset_offset_array (c, out->carets, this))
328 return_trace (bool (out->carets));
331 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
333 for (const OffsetTo<CaretValue>& offset : carets.iter ())
334 (this+offset).collect_variation_indices (c->layout_variation_indices);
337 bool sanitize (hb_sanitize_context_t *c) const
339 TRACE_SANITIZE (this);
340 return_trace (carets.sanitize (c, this));
344 OffsetArrayOf<CaretValue>
345 carets; /* Offset array of CaretValue tables
346 * --from beginning of LigGlyph table
347 * --in increasing coordinate order */
349 DEFINE_SIZE_ARRAY (2, carets);
354 unsigned int get_lig_carets (hb_font_t *font,
355 hb_direction_t direction,
356 hb_codepoint_t glyph_id,
357 const VariationStore &var_store,
358 unsigned int start_offset,
359 unsigned int *caret_count /* IN/OUT */,
360 hb_position_t *caret_array /* OUT */) const
362 unsigned int index = (this+coverage).get_coverage (glyph_id);
363 if (index == NOT_COVERED)
369 const LigGlyph &lig_glyph = this+ligGlyph[index];
370 return lig_glyph.get_lig_carets (font, direction, glyph_id, var_store, start_offset, caret_count, caret_array);
373 bool subset (hb_subset_context_t *c) const
376 const hb_set_t &glyphset = *c->plan->glyphset ();
377 const hb_map_t &glyph_map = *c->plan->glyph_map;
379 auto *out = c->serializer->start_embed (*this);
380 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
382 hb_sorted_vector_t<hb_codepoint_t> new_coverage;
383 + hb_zip (this+coverage, ligGlyph)
384 | hb_filter (glyphset, hb_first)
385 | hb_filter (subset_offset_array (c, out->ligGlyph, this), hb_second)
388 | hb_sink (new_coverage)
390 out->coverage.serialize (c->serializer, out)
391 .serialize (c->serializer, new_coverage.iter ());
392 return_trace (bool (new_coverage));
395 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
397 + hb_zip (this+coverage, ligGlyph)
398 | hb_filter (c->glyph_set, hb_first)
400 | hb_map (hb_add (this))
401 | hb_apply ([c] (const LigGlyph& _) { _.collect_variation_indices (c); })
405 bool sanitize (hb_sanitize_context_t *c) const
407 TRACE_SANITIZE (this);
408 return_trace (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this));
413 coverage; /* Offset to Coverage table--from
414 * beginning of LigCaretList table */
415 OffsetArrayOf<LigGlyph>
416 ligGlyph; /* Array of LigGlyph tables
417 * in Coverage Index order */
419 DEFINE_SIZE_ARRAY (4, ligGlyph);
423 struct MarkGlyphSetsFormat1
425 bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
426 { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }
428 bool subset (hb_subset_context_t *c) const
431 auto *out = c->serializer->start_embed (*this);
432 if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
433 out->format = format;
436 for (const LOffsetTo<Coverage>& offset : coverage.iter ())
438 auto *o = out->coverage.serialize_append (c->serializer);
445 //not using o->serialize_subset (c, offset, this, out) here because
446 //OTS doesn't allow null offset.
447 //See issue: https://github.com/khaledhosny/ots/issues/172
448 c->serializer->push ();
449 c->dispatch (this+offset);
450 c->serializer->add_link (*o, c->serializer->pop_pack ());
453 return_trace (ret && out->coverage.len);
456 bool sanitize (hb_sanitize_context_t *c) const
458 TRACE_SANITIZE (this);
459 return_trace (coverage.sanitize (c, this));
463 HBUINT16 format; /* Format identifier--format = 1 */
464 ArrayOf<LOffsetTo<Coverage>>
465 coverage; /* Array of long offsets to mark set
468 DEFINE_SIZE_ARRAY (4, coverage);
473 bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
476 case 1: return u.format1.covers (set_index, glyph_id);
477 default:return false;
481 bool subset (hb_subset_context_t *c) const
485 case 1: return_trace (u.format1.subset (c));
486 default:return_trace (false);
490 bool sanitize (hb_sanitize_context_t *c) const
492 TRACE_SANITIZE (this);
493 if (!u.format.sanitize (c)) return_trace (false);
495 case 1: return_trace (u.format1.sanitize (c));
496 default:return_trace (true);
502 HBUINT16 format; /* Format identifier */
503 MarkGlyphSetsFormat1 format1;
506 DEFINE_SIZE_UNION (2, format);
511 * GDEF -- Glyph Definition
512 * https://docs.microsoft.com/en-us/typography/opentype/spec/gdef
518 static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF;
521 UnclassifiedGlyph = 0,
528 bool has_data () const { return version.to_int (); }
529 bool has_glyph_classes () const { return glyphClassDef != 0; }
530 unsigned int get_glyph_class (hb_codepoint_t glyph) const
531 { return (this+glyphClassDef).get_class (glyph); }
532 void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const
533 { (this+glyphClassDef).collect_class (glyphs, klass); }
535 bool has_mark_attachment_types () const { return markAttachClassDef != 0; }
536 unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const
537 { return (this+markAttachClassDef).get_class (glyph); }
539 bool has_attach_points () const { return attachList != 0; }
540 unsigned int get_attach_points (hb_codepoint_t glyph_id,
541 unsigned int start_offset,
542 unsigned int *point_count /* IN/OUT */,
543 unsigned int *point_array /* OUT */) const
544 { return (this+attachList).get_attach_points (glyph_id, start_offset, point_count, point_array); }
546 bool has_lig_carets () const { return ligCaretList != 0; }
547 unsigned int get_lig_carets (hb_font_t *font,
548 hb_direction_t direction,
549 hb_codepoint_t glyph_id,
550 unsigned int start_offset,
551 unsigned int *caret_count /* IN/OUT */,
552 hb_position_t *caret_array /* OUT */) const
553 { return (this+ligCaretList).get_lig_carets (font,
554 direction, glyph_id, get_var_store(),
555 start_offset, caret_count, caret_array); }
557 bool has_mark_sets () const { return version.to_int () >= 0x00010002u && markGlyphSetsDef != 0; }
558 bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
559 { return version.to_int () >= 0x00010002u && (this+markGlyphSetsDef).covers (set_index, glyph_id); }
561 bool has_var_store () const { return version.to_int () >= 0x00010003u && varStore != 0; }
562 const VariationStore &get_var_store () const
563 { return version.to_int () >= 0x00010003u ? this+varStore : Null (VariationStore); }
565 /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
566 * glyph class and other bits, and high 8-bit the mark attachment type (if any).
567 * Not to be confused with lookup_props which is very similar. */
568 unsigned int get_glyph_props (hb_codepoint_t glyph) const
570 unsigned int klass = get_glyph_class (glyph);
572 static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs), "");
573 static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures), "");
574 static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks), "");
578 case BaseGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH;
579 case LigatureGlyph: return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
581 klass = get_mark_attachment_type (glyph);
582 return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8);
586 HB_INTERNAL bool is_blacklisted (hb_blob_t *blob,
587 hb_face_t *face) const;
591 void init (hb_face_t *face)
593 this->table = hb_sanitize_context_t ().reference_table<GDEF> (face);
594 if (unlikely (this->table->is_blacklisted (this->table.get_blob (), face)))
596 hb_blob_destroy (this->table.get_blob ());
597 this->table = hb_blob_get_empty ();
601 void fini () { this->table.destroy (); }
603 hb_blob_ptr_t<GDEF> table;
606 unsigned int get_size () const
609 (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) +
610 (version.to_int () >= 0x00010003u ? varStore.static_size : 0);
613 void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
614 { (this+ligCaretList).collect_variation_indices (c); }
616 void remap_layout_variation_indices (const hb_set_t *layout_variation_indices,
617 hb_map_t *layout_variation_idx_map /* OUT */) const
619 if (version.to_int () < 0x00010003u || !varStore) return;
620 if (layout_variation_indices->is_empty ()) return;
622 unsigned new_major = 0, new_minor = 0;
623 unsigned last_major = (layout_variation_indices->get_min ()) >> 16;
624 for (unsigned idx : layout_variation_indices->iter ())
626 uint16_t major = idx >> 16;
627 if (major >= (this+varStore).get_sub_table_count ()) break;
628 if (major != last_major)
634 unsigned new_idx = (new_major << 16) + new_minor;
635 layout_variation_idx_map->set (idx, new_idx);
641 bool subset (hb_subset_context_t *c) const
644 auto *out = c->serializer->embed (*this);
645 if (unlikely (!out)) return_trace (false);
647 bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this);
648 bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
649 bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
650 bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this);
652 bool subset_markglyphsetsdef = true;
653 if (version.to_int () >= 0x00010002u)
655 subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
656 if (!subset_markglyphsetsdef &&
657 version.to_int () == 0x00010002u)
658 out->version.minor = 0;
661 bool subset_varstore = true;
662 if (version.to_int () >= 0x00010003u)
664 subset_varstore = out->varStore.serialize_subset (c, varStore, this);
665 if (!subset_varstore && version.to_int () == 0x00010003u)
666 out->version.minor = 2;
669 return_trace (subset_glyphclassdef || subset_attachlist ||
670 subset_ligcaretlist || subset_markattachclassdef ||
671 (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) ||
672 (out->version.to_int () >= 0x00010003u && subset_varstore));
675 bool sanitize (hb_sanitize_context_t *c) const
677 TRACE_SANITIZE (this);
678 return_trace (version.sanitize (c) &&
679 likely (version.major == 1) &&
680 glyphClassDef.sanitize (c, this) &&
681 attachList.sanitize (c, this) &&
682 ligCaretList.sanitize (c, this) &&
683 markAttachClassDef.sanitize (c, this) &&
684 (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
685 (version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
689 FixedVersion<>version; /* Version of the GDEF table--currently
692 glyphClassDef; /* Offset to class definition table
693 * for glyph type--from beginning of
694 * GDEF header (may be Null) */
696 attachList; /* Offset to list of glyphs with
697 * attachment points--from beginning
698 * of GDEF header (may be Null) */
699 OffsetTo<LigCaretList>
700 ligCaretList; /* Offset to list of positioning points
701 * for ligature carets--from beginning
702 * of GDEF header (may be Null) */
704 markAttachClassDef; /* Offset to class definition table for
705 * mark attachment type--from beginning
706 * of GDEF header (may be Null) */
707 OffsetTo<MarkGlyphSets>
708 markGlyphSetsDef; /* Offset to the table of mark set
709 * definitions--from beginning of GDEF
710 * header (may be NULL). Introduced
711 * in version 0x00010002. */
712 LOffsetTo<VariationStore>
713 varStore; /* Offset to the table of Item Variation
714 * Store--from beginning of GDEF
715 * header (may be NULL). Introduced
716 * in version 0x00010003. */
718 DEFINE_SIZE_MIN (12);
721 struct GDEF_accelerator_t : GDEF::accelerator_t {};
726 #endif /* HB_OT_LAYOUT_GDEF_TABLE_HH */