From 470fe5b603b409bef136fdd4e9b33d2704dc77b7 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Tue, 9 Jan 2018 15:48:51 +0100 Subject: [PATCH] [aat] Implement Lookup table Untested, but compiles. --- src/hb-aat-layout-common-private.hh | 308 +++++++++++++++++++++++++++- src/hb-aat-layout-morx-table.hh | 9 +- src/hb-aat-layout.cc | 14 ++ src/hb-face.cc | 6 +- src/hb-open-type-private.hh | 16 +- src/hb-ot-cbdt-table.hh | 4 +- src/hb-ot-cmap-table.hh | 2 +- src/hb-ot-glyf-table.hh | 6 +- src/hb-ot-hmtx-table.hh | 8 +- src/hb-ot-kern-table.hh | 2 +- src/hb-ot-layout.cc | 6 +- src/hb-ot-post-table.hh | 2 +- src/hb-uniscribe.cc | 2 +- 13 files changed, 355 insertions(+), 30 deletions(-) diff --git a/src/hb-aat-layout-common-private.hh b/src/hb-aat-layout-common-private.hh index e1abd07b..88a9cd84 100644 --- a/src/hb-aat-layout-common-private.hh +++ b/src/hb-aat-layout-common-private.hh @@ -41,7 +41,6 @@ using namespace OT; struct BinSearchHeader { - friend struct BinSearchArray; inline bool sanitize (hb_sanitize_context_t *c) const { @@ -49,7 +48,6 @@ struct BinSearchHeader return_trace (c->check_struct (this)); } - protected: UINT16 unitSize; /* Size of a lookup unit for this search in bytes. */ UINT16 nUnits; /* Number of units of the preceding size to be searched. */ UINT16 searchRange; /* The value of unitSize times the largest power of 2 @@ -106,9 +104,23 @@ struct BinSearchArrayOf } template - inline Type *bsearch (const T &key) const + inline const Type *bsearch (const T &key) const { - return ::bsearch (&key, bytes, header.nUnits, header.unitSize, Type::cmp); + unsigned int size = header.unitSize; + int min = 0, max = (int) header.nUnits - 1; + while (min <= max) + { + int mid = (min + max) / 2; + const Type *p = (const Type *) (((const char *) bytes) + (mid * size)); + int c = p->cmp (key); + if (c < 0) + max = mid - 1; + else if (c > 0) + min = mid + 1; + else + return p; + } + return NULL; } private: @@ -128,6 +140,294 @@ struct BinSearchArrayOf }; +/* TODO Move this to hb-open-type-private.hh and use it in ArrayOf, HeadlessArrayOf, + * and other places around the code base?? */ +template +struct UnsizedArrayOf +{ + inline const Type& operator [] (unsigned int i) const { return arrayZ[i]; } + inline Type& operator [] (unsigned int i) { return arrayZ[i]; } + + inline bool sanitize (hb_sanitize_context_t *c, unsigned int count) const + { + TRACE_SANITIZE (this); + + /* Note: for structs that do not reference other structs, + * we do not need to call their sanitize() as we already did + * a bound check on the aggregate array size. We just include + * a small unreachable expression to make sure the structs + * pointed to do have a simple sanitize(), ie. they do not + * reference other structs via offsets. + */ + (void) (false && count && arrayZ->sanitize (c)); + + return_trace (c->check_array (arrayZ, arrayZ[0].static_size, count)); + } + + protected: + Type arrayZ[VAR]; + public: + DEFINE_SIZE_ARRAY (0, arrayZ); +}; + + +/* + * Lookup Table + */ + +template struct Lookup; + +template +struct LookupFormat0 +{ + friend struct Lookup; + + private: + inline const T& get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const + { + if (unlikely (glyph_id >= num_glyphs)) return Null(T); + return arrayZ[glyph_id]; + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (arrayZ.sanitize (c, c->num_glyphs)); + } + + protected: + UINT16 format; /* Format identifier--format = 0 */ + UnsizedArrayOf + arrayZ; /* Array of lookup values, indexed by glyph index. */ + public: + DEFINE_SIZE_ARRAY (2, arrayZ); +}; + + +template +struct LookupSegmentSingle +{ + inline int cmp (hb_codepoint_t g) const { + return g < first ? -1 : g <= last ? 0 : +1 ; + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && value.sanitize (c)); + } + + GlyphID last; /* Last GlyphID in this segment */ + GlyphID first; /* First GlyphID in this segment */ + T value; /* The lookup value (only one) */ + public: + DEFINE_SIZE_STATIC (4 + sizeof (T)); +}; + +template +struct LookupFormat2 +{ + friend struct Lookup; + + private: + inline const T& get_value (hb_codepoint_t glyph_id) const + { + const LookupSegmentSingle *v = segments.bsearch (glyph_id); + return v ? v->value : Null(T); + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (segments.sanitize (c)); + } + + protected: + UINT16 format; /* Format identifier--format = 2 */ + BinSearchArrayOf > + segments; /* The actual segments. These must already be sorted, + * according to the first word in each one (the last + * glyph in each segment). */ + public: + DEFINE_SIZE_ARRAY (8, segments); +}; + +template +struct LookupSegmentArray +{ + inline const T& get_value (hb_codepoint_t glyph_id, const void *base) const + { + return first <= glyph_id && glyph_id <= last ? (base+valuesZ)[glyph_id - first] : Null(T); + } + + inline int cmp (hb_codepoint_t g) const { + return g < first ? -1 : g <= last ? 0 : +1 ; + } + + inline bool sanitize (hb_sanitize_context_t *c, const void *base) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && + first <= last && + valuesZ.sanitize (c, base, last - first + 1)); + } + + GlyphID last; /* Last GlyphID in this segment */ + GlyphID first; /* First GlyphID in this segment */ + OffsetTo > + valuesZ; /* A 16-bit offset from the start of + * the table to the data. */ + public: + DEFINE_SIZE_STATIC (6); +}; + +template +struct LookupFormat4 +{ + friend struct Lookup; + + private: + inline const T& get_value (hb_codepoint_t glyph_id) const + { + const LookupSegmentArray *v = segments.bsearch (glyph_id); + return v ? v->get_value (glyph_id, this) : Null(T); + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (segments.sanitize (c, this)); + } + + protected: + UINT16 format; /* Format identifier--format = 2 */ + BinSearchArrayOf > + segments; /* The actual segments. These must already be sorted, + * according to the first word in each one (the last + * glyph in each segment). */ + public: + DEFINE_SIZE_ARRAY (8, segments); +}; + +template +struct LookupSingle +{ + inline int cmp (hb_codepoint_t g) const { return glyph.cmp (g); } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && value.sanitize (c)); + } + + GlyphID glyph; /* Last GlyphID */ + T value; /* The lookup value (only one) */ + public: + DEFINE_SIZE_STATIC (4 + sizeof (T)); +}; + +template +struct LookupFormat6 +{ + friend struct Lookup; + + private: + inline const T& get_value (hb_codepoint_t glyph_id) const + { + const LookupSingle *v = entries.bsearch (glyph_id); + return v ? v->value : Null(T); + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (entries.sanitize (c)); + } + + protected: + UINT16 format; /* Format identifier--format = 6 */ + BinSearchArrayOf > + entries; /* The actual entries, sorted by glyph index. */ + public: + DEFINE_SIZE_ARRAY (8, entries); +}; + +template +struct LookupFormat8 +{ + friend struct Lookup; + + private: + inline const T& get_value (hb_codepoint_t glyph_id) const + { + return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ? valueArrayZ[glyph_id - firstGlyph] : Null(T); + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount)); + } + + protected: + UINT16 format; /* Format identifier--format = 6 */ + GlyphID firstGlyph; /* First glyph index included in the trimmed array. */ + UINT16 glyphCount; /* Total number of glyphs (equivalent to the last + * glyph minus the value of firstGlyph plus 1). */ + UnsizedArrayOf + valueArrayZ; /* The lookup values (indexed by the glyph index + * minus the value of firstGlyph). */ + public: + DEFINE_SIZE_ARRAY (6, valueArrayZ); +}; + +template +struct Lookup +{ + inline const T& get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const + { + switch (u.format) { + case 0: return u.format0.get_value (glyph_id, num_glyphs); + case 2: return u.format2.get_value (glyph_id); + case 4: return u.format4.get_value (glyph_id); + case 6: return u.format6.get_value (glyph_id); + case 8: return u.format8.get_value (glyph_id); + default:return Null(T); + } + } + + inline bool sanitize (hb_sanitize_context_t *c) const + { + TRACE_SANITIZE (this); + if (!u.format.sanitize (c)) return_trace (false); + switch (u.format) { + case 0: return_trace (u.format0.sanitize (c)); + case 2: return_trace (u.format2.sanitize (c)); + case 4: return_trace (u.format4.sanitize (c)); + case 6: return_trace (u.format6.sanitize (c)); + case 8: return_trace (u.format8.sanitize (c)); + default:return_trace (true); + } + } + + protected: + union { + UINT16 format; /* Format identifier */ + LookupFormat0 format0; + LookupFormat2 format2; + LookupFormat4 format4; + LookupFormat6 format6; + LookupFormat8 format8; + } u; + public: + DEFINE_SIZE_UNION (2, format); +}; + +// Instantiate, to catch compile errors. +Lookup g; +Lookup t; + + } /* namespace AAT */ diff --git a/src/hb-aat-layout-morx-table.hh b/src/hb-aat-layout-morx-table.hh index a8a8de4d..2cd7743b 100644 --- a/src/hb-aat-layout-morx-table.hh +++ b/src/hb-aat-layout-morx-table.hh @@ -74,13 +74,16 @@ struct LigatureSubtable struct NoncontextualSubtable { - /* TODO */ inline bool sanitize (hb_sanitize_context_t *c) const { TRACE_SANITIZE (this); - /* TODO */ - return_trace (false); + return_trace (substitute.sanitize (c)); } + + protected: + Lookup substitute; + public: + DEFINE_SIZE_MIN (2); }; struct InsertionSubtable diff --git a/src/hb-aat-layout.cc b/src/hb-aat-layout.cc index 73ceafe3..bd647d5c 100644 --- a/src/hb-aat-layout.cc +++ b/src/hb-aat-layout.cc @@ -41,3 +41,17 @@ _get_morx (hb_face_t *face) hb_ot_layout_t * layout = hb_ot_layout_from_face (face); return *(layout->morx.get ()); } + +void +_hb_aat_layout_create (hb_face_t *face) +{ + OT::Sanitizer sanitizer; + sanitizer.set_num_glyphs (face->get_num_glyphs ()); + hb_blob_t *morx_blob = sanitizer.sanitize (face->reference_table (HB_AAT_TAG_MORX)); + OT::Sanitizer::lock_instance (morx_blob); + + if (0) + { + OT::Sanitizer >::lock_instance (morx_blob)->get_value (1, face->get_num_glyphs ()); + } +} diff --git a/src/hb-face.cc b/src/hb-face.cc index 26fddbe5..d8af8c1f 100644 --- a/src/hb-face.cc +++ b/src/hb-face.cc @@ -164,7 +164,7 @@ hb_face_create (hb_blob_t *blob, if (unlikely (!blob)) blob = hb_blob_get_empty (); - hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (OT::Sanitizer::sanitize (hb_blob_reference (blob)), index); + hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (OT::Sanitizer().sanitize (hb_blob_reference (blob)), index); if (unlikely (!closure)) return hb_face_get_empty (); @@ -424,7 +424,7 @@ hb_face_get_upem (hb_face_t *face) void hb_face_t::load_upem (void) const { - hb_blob_t *head_blob = OT::Sanitizer::sanitize (reference_table (HB_OT_TAG_head)); + hb_blob_t *head_blob = OT::Sanitizer().sanitize (reference_table (HB_OT_TAG_head)); const OT::head *head_table = OT::Sanitizer::lock_instance (head_blob); upem = head_table->get_upem (); hb_blob_destroy (head_blob); @@ -468,7 +468,7 @@ hb_face_get_glyph_count (hb_face_t *face) void hb_face_t::load_num_glyphs (void) const { - hb_blob_t *maxp_blob = OT::Sanitizer::sanitize (reference_table (HB_OT_TAG_maxp)); + hb_blob_t *maxp_blob = OT::Sanitizer().sanitize (reference_table (HB_OT_TAG_maxp)); const OT::maxp *maxp_table = OT::Sanitizer::lock_instance (maxp_blob); num_glyphs = maxp_table->get_num_glyphs (); hb_blob_destroy (maxp_blob); diff --git a/src/hb-open-type-private.hh b/src/hb-open-type-private.hh index 2f4e1b9e..b68568cc 100644 --- a/src/hb-open-type-private.hh +++ b/src/hb-open-type-private.hh @@ -187,7 +187,8 @@ struct hb_sanitize_context_t : debug_depth (0), start (nullptr), end (nullptr), writable (false), edit_count (0), - blob (nullptr) {} + blob (nullptr), + num_glyphs (0) {} inline const char *get_name (void) { return "SANITIZE"; } template @@ -298,6 +299,7 @@ struct hb_sanitize_context_t : bool writable; unsigned int edit_count; hb_blob_t *blob; + unsigned int num_glyphs; }; @@ -306,8 +308,9 @@ struct hb_sanitize_context_t : template struct Sanitizer { - static hb_blob_t *sanitize (hb_blob_t *blob) { - hb_sanitize_context_t c[1]; + inline Sanitizer (void) {} + + inline hb_blob_t *sanitize (hb_blob_t *blob) { bool sane; /* TODO is_sane() stuff */ @@ -370,6 +373,11 @@ struct Sanitizer const char *base = hb_blob_get_data (blob, nullptr); return unlikely (!base) ? &Null(Type) : CastP (base); } + + inline void set_num_glyphs (unsigned int num_glyphs) { c->num_glyphs = num_glyphs; } + + private: + hb_sanitize_context_t c[1]; }; @@ -1154,7 +1162,7 @@ struct hb_lazy_table_loader_t T *p = (T *) hb_atomic_ptr_get (&instance); if (unlikely (!p)) { - hb_blob_t *blob_ = OT::Sanitizer::sanitize (face->reference_table (T::tableTag)); + hb_blob_t *blob_ = OT::Sanitizer().sanitize (face->reference_table (T::tableTag)); p = const_cast(OT::Sanitizer::lock_instance (blob_)); if (!hb_atomic_ptr_cmpexch (const_cast(&instance), nullptr, p)) { diff --git a/src/hb-ot-cbdt-table.hh b/src/hb-ot-cbdt-table.hh index 415625e5..dad34e27 100644 --- a/src/hb-ot-cbdt-table.hh +++ b/src/hb-ot-cbdt-table.hh @@ -379,8 +379,8 @@ struct CBDT { upem = face->get_upem(); - cblc_blob = Sanitizer::sanitize (face->reference_table (HB_OT_TAG_CBLC)); - cbdt_blob = Sanitizer::sanitize (face->reference_table (HB_OT_TAG_CBDT)); + cblc_blob = Sanitizer().sanitize (face->reference_table (HB_OT_TAG_CBLC)); + cbdt_blob = Sanitizer().sanitize (face->reference_table (HB_OT_TAG_CBDT)); cbdt_len = hb_blob_get_length (cbdt_blob); if (hb_blob_get_length (cblc_blob) == 0) { diff --git a/src/hb-ot-cmap-table.hh b/src/hb-ot-cmap-table.hh index 883d7b3f..c61801cb 100644 --- a/src/hb-ot-cmap-table.hh +++ b/src/hb-ot-cmap-table.hh @@ -508,7 +508,7 @@ struct cmap { inline void init (hb_face_t *face) { - this->blob = OT::Sanitizer::sanitize (face->reference_table (HB_OT_TAG_cmap)); + this->blob = OT::Sanitizer().sanitize (face->reference_table (HB_OT_TAG_cmap)); const OT::cmap *cmap = OT::Sanitizer::lock_instance (this->blob); const OT::CmapSubtable *subtable = nullptr; const OT::CmapSubtableFormat14 *subtable_uvs = nullptr; diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index 88d3850b..c5a54e3a 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -96,7 +96,7 @@ struct glyf { inline void init (hb_face_t *face) { - hb_blob_t *head_blob = Sanitizer::sanitize (face->reference_table (HB_OT_TAG_head)); + hb_blob_t *head_blob = Sanitizer().sanitize (face->reference_table (HB_OT_TAG_head)); const head *head_table = Sanitizer::lock_instance (head_blob); if ((unsigned int) head_table->indexToLocFormat > 1 || head_table->glyphDataFormat != 0) { @@ -107,9 +107,9 @@ struct glyf short_offset = 0 == head_table->indexToLocFormat; hb_blob_destroy (head_blob); - loca_blob = Sanitizer::sanitize (face->reference_table (HB_OT_TAG_loca)); + loca_blob = Sanitizer().sanitize (face->reference_table (HB_OT_TAG_loca)); loca_table = Sanitizer::lock_instance (loca_blob); - glyf_blob = Sanitizer::sanitize (face->reference_table (HB_OT_TAG_glyf)); + glyf_blob = Sanitizer().sanitize (face->reference_table (HB_OT_TAG_glyf)); glyf_table = Sanitizer::lock_instance (glyf_blob); num_glyphs = MAX (1u, hb_blob_get_length (loca_blob) / (short_offset ? 2 : 4)) - 1; diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh index 29770f7a..934acde7 100644 --- a/src/hb-ot-hmtx-table.hh +++ b/src/hb-ot-hmtx-table.hh @@ -74,7 +74,7 @@ struct hmtxvmtx bool got_font_extents = false; if (T::os2Tag) { - hb_blob_t *os2_blob = Sanitizer::sanitize (face->reference_table (T::os2Tag)); + hb_blob_t *os2_blob = Sanitizer().sanitize (face->reference_table (T::os2Tag)); const os2 *os2_table = Sanitizer::lock_instance (os2_blob); #define USE_TYPO_METRICS (1u<<7) if (0 != (os2_table->fsSelection & USE_TYPO_METRICS)) @@ -87,7 +87,7 @@ struct hmtxvmtx hb_blob_destroy (os2_blob); } - hb_blob_t *_hea_blob = Sanitizer<_hea>::sanitize (face->reference_table (T::headerTag)); + hb_blob_t *_hea_blob = Sanitizer<_hea>().sanitize (face->reference_table (T::headerTag)); const _hea *_hea_table = Sanitizer<_hea>::lock_instance (_hea_blob); num_advances = _hea_table->numberOfLongMetrics; if (!got_font_extents) @@ -101,7 +101,7 @@ struct hmtxvmtx has_font_extents = got_font_extents; - blob = Sanitizer::sanitize (face->reference_table (T::tableTag)); + blob = Sanitizer().sanitize (face->reference_table (T::tableTag)); /* Cap num_metrics() and num_advances() based on table length. */ unsigned int len = hb_blob_get_length (blob); @@ -119,7 +119,7 @@ struct hmtxvmtx } table = Sanitizer::lock_instance (blob); - var_blob = Sanitizer::sanitize (face->reference_table (T::variationsTag)); + var_blob = Sanitizer().sanitize (face->reference_table (T::variationsTag)); var_table = Sanitizer::lock_instance (var_blob); } diff --git a/src/hb-ot-kern-table.hh b/src/hb-ot-kern-table.hh index e07faca6..c9aaf03c 100644 --- a/src/hb-ot-kern-table.hh +++ b/src/hb-ot-kern-table.hh @@ -360,7 +360,7 @@ struct kern { inline void init (hb_face_t *face) { - blob = Sanitizer::sanitize (face->reference_table (HB_OT_TAG_kern)); + blob = Sanitizer().sanitize (face->reference_table (HB_OT_TAG_kern)); table = Sanitizer::lock_instance (blob); table_length = hb_blob_get_length (blob); } diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index d4737393..14b64359 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -50,13 +50,13 @@ _hb_ot_layout_create (hb_face_t *face) if (unlikely (!layout)) return nullptr; - layout->gdef_blob = OT::Sanitizer::sanitize (face->reference_table (HB_OT_TAG_GDEF)); + layout->gdef_blob = OT::Sanitizer().sanitize (face->reference_table (HB_OT_TAG_GDEF)); layout->gdef = OT::Sanitizer::lock_instance (layout->gdef_blob); - layout->gsub_blob = OT::Sanitizer::sanitize (face->reference_table (HB_OT_TAG_GSUB)); + layout->gsub_blob = OT::Sanitizer().sanitize (face->reference_table (HB_OT_TAG_GSUB)); layout->gsub = OT::Sanitizer::lock_instance (layout->gsub_blob); - layout->gpos_blob = OT::Sanitizer::sanitize (face->reference_table (HB_OT_TAG_GPOS)); + layout->gpos_blob = OT::Sanitizer().sanitize (face->reference_table (HB_OT_TAG_GPOS)); layout->gpos = OT::Sanitizer::lock_instance (layout->gpos_blob); layout->math.init (face); diff --git a/src/hb-ot-post-table.hh b/src/hb-ot-post-table.hh index 7f1c2c42..523ba2a8 100644 --- a/src/hb-ot-post-table.hh +++ b/src/hb-ot-post-table.hh @@ -86,7 +86,7 @@ struct post { inline void init (hb_face_t *face) { - blob = Sanitizer::sanitize (face->reference_table (HB_OT_TAG_post)); + blob = Sanitizer().sanitize (face->reference_table (HB_OT_TAG_post)); const post *table = Sanitizer::lock_instance (blob); unsigned int table_length = hb_blob_get_length (blob); diff --git a/src/hb-uniscribe.cc b/src/hb-uniscribe.cc index 0b0bad58..5e05baa8 100644 --- a/src/hb-uniscribe.cc +++ b/src/hb-uniscribe.cc @@ -351,7 +351,7 @@ _hb_rename_font (hb_blob_t *blob, wchar_t *new_name) * full, PS. All of them point to the same name data with our unique name. */ - blob = OT::Sanitizer::sanitize (blob); + blob = OT::Sanitizer().sanitize (blob); unsigned int length, new_length, name_str_len; const char *orig_sfnt_data = hb_blob_get_data (blob, &length); -- GitLab