1*2d1272b8SAndroid Build Coastguard Worker /* 2*2d1272b8SAndroid Build Coastguard Worker * Copyright © 2017 Google, Inc. 3*2d1272b8SAndroid Build Coastguard Worker * 4*2d1272b8SAndroid Build Coastguard Worker * This is part of HarfBuzz, a text shaping library. 5*2d1272b8SAndroid Build Coastguard Worker * 6*2d1272b8SAndroid Build Coastguard Worker * Permission is hereby granted, without written agreement and without 7*2d1272b8SAndroid Build Coastguard Worker * license or royalty fees, to use, copy, modify, and distribute this 8*2d1272b8SAndroid Build Coastguard Worker * software and its documentation for any purpose, provided that the 9*2d1272b8SAndroid Build Coastguard Worker * above copyright notice and the following two paragraphs appear in 10*2d1272b8SAndroid Build Coastguard Worker * all copies of this software. 11*2d1272b8SAndroid Build Coastguard Worker * 12*2d1272b8SAndroid Build Coastguard Worker * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR 13*2d1272b8SAndroid Build Coastguard Worker * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES 14*2d1272b8SAndroid Build Coastguard Worker * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN 15*2d1272b8SAndroid Build Coastguard Worker * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH 16*2d1272b8SAndroid Build Coastguard Worker * DAMAGE. 17*2d1272b8SAndroid Build Coastguard Worker * 18*2d1272b8SAndroid Build Coastguard Worker * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, 19*2d1272b8SAndroid Build Coastguard Worker * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 20*2d1272b8SAndroid Build Coastguard Worker * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS 21*2d1272b8SAndroid Build Coastguard Worker * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO 22*2d1272b8SAndroid Build Coastguard Worker * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. 23*2d1272b8SAndroid Build Coastguard Worker * 24*2d1272b8SAndroid Build Coastguard Worker * Google Author(s): Behdad Esfahbod 25*2d1272b8SAndroid Build Coastguard Worker */ 26*2d1272b8SAndroid Build Coastguard Worker 27*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_AAT_LAYOUT_COMMON_HH 28*2d1272b8SAndroid Build Coastguard Worker #define HB_AAT_LAYOUT_COMMON_HH 29*2d1272b8SAndroid Build Coastguard Worker 30*2d1272b8SAndroid Build Coastguard Worker #include "hb-aat-layout.hh" 31*2d1272b8SAndroid Build Coastguard Worker #include "hb-aat-map.hh" 32*2d1272b8SAndroid Build Coastguard Worker #include "hb-open-type.hh" 33*2d1272b8SAndroid Build Coastguard Worker 34*2d1272b8SAndroid Build Coastguard Worker namespace OT { 35*2d1272b8SAndroid Build Coastguard Worker struct GDEF; 36*2d1272b8SAndroid Build Coastguard Worker }; 37*2d1272b8SAndroid Build Coastguard Worker 38*2d1272b8SAndroid Build Coastguard Worker namespace AAT { 39*2d1272b8SAndroid Build Coastguard Worker 40*2d1272b8SAndroid Build Coastguard Worker using namespace OT; 41*2d1272b8SAndroid Build Coastguard Worker 42*2d1272b8SAndroid Build Coastguard Worker #define HB_AAT_BUFFER_DIGEST_THRESHOLD 32 43*2d1272b8SAndroid Build Coastguard Worker 44*2d1272b8SAndroid Build Coastguard Worker struct ankr; 45*2d1272b8SAndroid Build Coastguard Worker 46*2d1272b8SAndroid Build Coastguard Worker struct hb_aat_apply_context_t : 47*2d1272b8SAndroid Build Coastguard Worker hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY> 48*2d1272b8SAndroid Build Coastguard Worker { get_nameAAT::hb_aat_apply_context_t49*2d1272b8SAndroid Build Coastguard Worker const char *get_name () { return "APPLY"; } 50*2d1272b8SAndroid Build Coastguard Worker template <typename T, typename ...Ts> dispatchAAT::hb_aat_apply_context_t51*2d1272b8SAndroid Build Coastguard Worker return_t dispatch (const T &obj, Ts&&... ds) 52*2d1272b8SAndroid Build Coastguard Worker { return obj.apply (this, std::forward<Ts> (ds)...); } default_return_valueAAT::hb_aat_apply_context_t53*2d1272b8SAndroid Build Coastguard Worker static return_t default_return_value () { return false; } stop_sublookup_iterationAAT::hb_aat_apply_context_t54*2d1272b8SAndroid Build Coastguard Worker bool stop_sublookup_iteration (return_t r) const { return r; } 55*2d1272b8SAndroid Build Coastguard Worker 56*2d1272b8SAndroid Build Coastguard Worker const hb_ot_shape_plan_t *plan; 57*2d1272b8SAndroid Build Coastguard Worker hb_font_t *font; 58*2d1272b8SAndroid Build Coastguard Worker hb_face_t *face; 59*2d1272b8SAndroid Build Coastguard Worker hb_buffer_t *buffer; 60*2d1272b8SAndroid Build Coastguard Worker hb_sanitize_context_t sanitizer; 61*2d1272b8SAndroid Build Coastguard Worker const ankr *ankr_table; 62*2d1272b8SAndroid Build Coastguard Worker const OT::GDEF *gdef_table; 63*2d1272b8SAndroid Build Coastguard Worker const hb_sorted_vector_t<hb_aat_map_t::range_flags_t> *range_flags = nullptr; 64*2d1272b8SAndroid Build Coastguard Worker hb_set_digest_t buffer_digest = hb_set_digest_t::full (); 65*2d1272b8SAndroid Build Coastguard Worker hb_set_digest_t machine_glyph_set = hb_set_digest_t::full (); 66*2d1272b8SAndroid Build Coastguard Worker hb_set_digest_t left_set = hb_set_digest_t::full (); 67*2d1272b8SAndroid Build Coastguard Worker hb_set_digest_t right_set = hb_set_digest_t::full (); 68*2d1272b8SAndroid Build Coastguard Worker hb_mask_t subtable_flags = 0; 69*2d1272b8SAndroid Build Coastguard Worker 70*2d1272b8SAndroid Build Coastguard Worker /* Unused. For debug tracing only. */ 71*2d1272b8SAndroid Build Coastguard Worker unsigned int lookup_index; 72*2d1272b8SAndroid Build Coastguard Worker 73*2d1272b8SAndroid Build Coastguard Worker HB_INTERNAL hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_, 74*2d1272b8SAndroid Build Coastguard Worker hb_font_t *font_, 75*2d1272b8SAndroid Build Coastguard Worker hb_buffer_t *buffer_, 76*2d1272b8SAndroid Build Coastguard Worker hb_blob_t *blob = const_cast<hb_blob_t *> (&Null (hb_blob_t))); 77*2d1272b8SAndroid Build Coastguard Worker 78*2d1272b8SAndroid Build Coastguard Worker HB_INTERNAL ~hb_aat_apply_context_t (); 79*2d1272b8SAndroid Build Coastguard Worker 80*2d1272b8SAndroid Build Coastguard Worker HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_); 81*2d1272b8SAndroid Build Coastguard Worker set_lookup_indexAAT::hb_aat_apply_context_t82*2d1272b8SAndroid Build Coastguard Worker void set_lookup_index (unsigned int i) { lookup_index = i; } 83*2d1272b8SAndroid Build Coastguard Worker }; 84*2d1272b8SAndroid Build Coastguard Worker 85*2d1272b8SAndroid Build Coastguard Worker 86*2d1272b8SAndroid Build Coastguard Worker /* 87*2d1272b8SAndroid Build Coastguard Worker * Lookup Table 88*2d1272b8SAndroid Build Coastguard Worker */ 89*2d1272b8SAndroid Build Coastguard Worker 90*2d1272b8SAndroid Build Coastguard Worker enum { DELETED_GLYPH = 0xFFFF }; 91*2d1272b8SAndroid Build Coastguard Worker 92*2d1272b8SAndroid Build Coastguard Worker template <typename T> struct Lookup; 93*2d1272b8SAndroid Build Coastguard Worker 94*2d1272b8SAndroid Build Coastguard Worker template <typename T> 95*2d1272b8SAndroid Build Coastguard Worker struct LookupFormat0 96*2d1272b8SAndroid Build Coastguard Worker { 97*2d1272b8SAndroid Build Coastguard Worker friend struct Lookup<T>; 98*2d1272b8SAndroid Build Coastguard Worker 99*2d1272b8SAndroid Build Coastguard Worker private: get_valueAAT::LookupFormat0100*2d1272b8SAndroid Build Coastguard Worker const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const 101*2d1272b8SAndroid Build Coastguard Worker { 102*2d1272b8SAndroid Build Coastguard Worker if (unlikely (glyph_id >= num_glyphs)) return nullptr; 103*2d1272b8SAndroid Build Coastguard Worker return &arrayZ[glyph_id]; 104*2d1272b8SAndroid Build Coastguard Worker } 105*2d1272b8SAndroid Build Coastguard Worker 106*2d1272b8SAndroid Build Coastguard Worker template <typename set_t> collect_glyphsAAT::LookupFormat0107*2d1272b8SAndroid Build Coastguard Worker void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const 108*2d1272b8SAndroid Build Coastguard Worker { 109*2d1272b8SAndroid Build Coastguard Worker glyphs.add_range (0, num_glyphs - 1); 110*2d1272b8SAndroid Build Coastguard Worker } 111*2d1272b8SAndroid Build Coastguard Worker sanitizeAAT::LookupFormat0112*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c) const 113*2d1272b8SAndroid Build Coastguard Worker { 114*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 115*2d1272b8SAndroid Build Coastguard Worker return_trace (arrayZ.sanitize (c, c->get_num_glyphs ())); 116*2d1272b8SAndroid Build Coastguard Worker } sanitizeAAT::LookupFormat0117*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c, const void *base) const 118*2d1272b8SAndroid Build Coastguard Worker { 119*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 120*2d1272b8SAndroid Build Coastguard Worker return_trace (arrayZ.sanitize (c, c->get_num_glyphs (), base)); 121*2d1272b8SAndroid Build Coastguard Worker } 122*2d1272b8SAndroid Build Coastguard Worker 123*2d1272b8SAndroid Build Coastguard Worker protected: 124*2d1272b8SAndroid Build Coastguard Worker HBUINT16 format; /* Format identifier--format = 0 */ 125*2d1272b8SAndroid Build Coastguard Worker UnsizedArrayOf<T> 126*2d1272b8SAndroid Build Coastguard Worker arrayZ; /* Array of lookup values, indexed by glyph index. */ 127*2d1272b8SAndroid Build Coastguard Worker public: 128*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_UNBOUNDED (2); 129*2d1272b8SAndroid Build Coastguard Worker }; 130*2d1272b8SAndroid Build Coastguard Worker 131*2d1272b8SAndroid Build Coastguard Worker 132*2d1272b8SAndroid Build Coastguard Worker template <typename T> 133*2d1272b8SAndroid Build Coastguard Worker struct LookupSegmentSingle 134*2d1272b8SAndroid Build Coastguard Worker { 135*2d1272b8SAndroid Build Coastguard Worker static constexpr unsigned TerminationWordCount = 2u; 136*2d1272b8SAndroid Build Coastguard Worker cmpAAT::LookupSegmentSingle137*2d1272b8SAndroid Build Coastguard Worker int cmp (hb_codepoint_t g) const 138*2d1272b8SAndroid Build Coastguard Worker { return g < first ? -1 : g <= last ? 0 : +1 ; } 139*2d1272b8SAndroid Build Coastguard Worker 140*2d1272b8SAndroid Build Coastguard Worker template <typename set_t> collect_glyphsAAT::LookupSegmentSingle141*2d1272b8SAndroid Build Coastguard Worker void collect_glyphs (set_t &glyphs) const 142*2d1272b8SAndroid Build Coastguard Worker { 143*2d1272b8SAndroid Build Coastguard Worker if (first == DELETED_GLYPH) 144*2d1272b8SAndroid Build Coastguard Worker return; 145*2d1272b8SAndroid Build Coastguard Worker glyphs.add_range (first, last); 146*2d1272b8SAndroid Build Coastguard Worker } 147*2d1272b8SAndroid Build Coastguard Worker sanitizeAAT::LookupSegmentSingle148*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c) const 149*2d1272b8SAndroid Build Coastguard Worker { 150*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 151*2d1272b8SAndroid Build Coastguard Worker return_trace (c->check_struct (this) && value.sanitize (c)); 152*2d1272b8SAndroid Build Coastguard Worker } sanitizeAAT::LookupSegmentSingle153*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c, const void *base) const 154*2d1272b8SAndroid Build Coastguard Worker { 155*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 156*2d1272b8SAndroid Build Coastguard Worker return_trace (c->check_struct (this) && value.sanitize (c, base)); 157*2d1272b8SAndroid Build Coastguard Worker } 158*2d1272b8SAndroid Build Coastguard Worker 159*2d1272b8SAndroid Build Coastguard Worker HBGlyphID16 last; /* Last GlyphID in this segment */ 160*2d1272b8SAndroid Build Coastguard Worker HBGlyphID16 first; /* First GlyphID in this segment */ 161*2d1272b8SAndroid Build Coastguard Worker T value; /* The lookup value (only one) */ 162*2d1272b8SAndroid Build Coastguard Worker public: 163*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_STATIC (4 + T::static_size); 164*2d1272b8SAndroid Build Coastguard Worker }; 165*2d1272b8SAndroid Build Coastguard Worker 166*2d1272b8SAndroid Build Coastguard Worker template <typename T> 167*2d1272b8SAndroid Build Coastguard Worker struct LookupFormat2 168*2d1272b8SAndroid Build Coastguard Worker { 169*2d1272b8SAndroid Build Coastguard Worker friend struct Lookup<T>; 170*2d1272b8SAndroid Build Coastguard Worker 171*2d1272b8SAndroid Build Coastguard Worker private: get_valueAAT::LookupFormat2172*2d1272b8SAndroid Build Coastguard Worker const T* get_value (hb_codepoint_t glyph_id) const 173*2d1272b8SAndroid Build Coastguard Worker { 174*2d1272b8SAndroid Build Coastguard Worker const LookupSegmentSingle<T> *v = segments.bsearch (glyph_id); 175*2d1272b8SAndroid Build Coastguard Worker return v ? &v->value : nullptr; 176*2d1272b8SAndroid Build Coastguard Worker } 177*2d1272b8SAndroid Build Coastguard Worker 178*2d1272b8SAndroid Build Coastguard Worker template <typename set_t> collect_glyphsAAT::LookupFormat2179*2d1272b8SAndroid Build Coastguard Worker void collect_glyphs (set_t &glyphs) const 180*2d1272b8SAndroid Build Coastguard Worker { 181*2d1272b8SAndroid Build Coastguard Worker unsigned count = segments.get_length (); 182*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < count; i++) 183*2d1272b8SAndroid Build Coastguard Worker segments[i].collect_glyphs (glyphs); 184*2d1272b8SAndroid Build Coastguard Worker } 185*2d1272b8SAndroid Build Coastguard Worker sanitizeAAT::LookupFormat2186*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c) const 187*2d1272b8SAndroid Build Coastguard Worker { 188*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 189*2d1272b8SAndroid Build Coastguard Worker return_trace (segments.sanitize (c)); 190*2d1272b8SAndroid Build Coastguard Worker } sanitizeAAT::LookupFormat2191*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c, const void *base) const 192*2d1272b8SAndroid Build Coastguard Worker { 193*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 194*2d1272b8SAndroid Build Coastguard Worker return_trace (segments.sanitize (c, base)); 195*2d1272b8SAndroid Build Coastguard Worker } 196*2d1272b8SAndroid Build Coastguard Worker 197*2d1272b8SAndroid Build Coastguard Worker protected: 198*2d1272b8SAndroid Build Coastguard Worker HBUINT16 format; /* Format identifier--format = 2 */ 199*2d1272b8SAndroid Build Coastguard Worker VarSizedBinSearchArrayOf<LookupSegmentSingle<T>> 200*2d1272b8SAndroid Build Coastguard Worker segments; /* The actual segments. These must already be sorted, 201*2d1272b8SAndroid Build Coastguard Worker * according to the first word in each one (the last 202*2d1272b8SAndroid Build Coastguard Worker * glyph in each segment). */ 203*2d1272b8SAndroid Build Coastguard Worker public: 204*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_ARRAY (8, segments); 205*2d1272b8SAndroid Build Coastguard Worker }; 206*2d1272b8SAndroid Build Coastguard Worker 207*2d1272b8SAndroid Build Coastguard Worker template <typename T> 208*2d1272b8SAndroid Build Coastguard Worker struct LookupSegmentArray 209*2d1272b8SAndroid Build Coastguard Worker { 210*2d1272b8SAndroid Build Coastguard Worker static constexpr unsigned TerminationWordCount = 2u; 211*2d1272b8SAndroid Build Coastguard Worker get_valueAAT::LookupSegmentArray212*2d1272b8SAndroid Build Coastguard Worker const T* get_value (hb_codepoint_t glyph_id, const void *base) const 213*2d1272b8SAndroid Build Coastguard Worker { 214*2d1272b8SAndroid Build Coastguard Worker return first <= glyph_id && glyph_id <= last ? &(base+valuesZ)[glyph_id - first] : nullptr; 215*2d1272b8SAndroid Build Coastguard Worker } 216*2d1272b8SAndroid Build Coastguard Worker 217*2d1272b8SAndroid Build Coastguard Worker template <typename set_t> collect_glyphsAAT::LookupSegmentArray218*2d1272b8SAndroid Build Coastguard Worker void collect_glyphs (set_t &glyphs) const 219*2d1272b8SAndroid Build Coastguard Worker { 220*2d1272b8SAndroid Build Coastguard Worker if (first == DELETED_GLYPH) 221*2d1272b8SAndroid Build Coastguard Worker return; 222*2d1272b8SAndroid Build Coastguard Worker glyphs.add_range (first, last); 223*2d1272b8SAndroid Build Coastguard Worker } 224*2d1272b8SAndroid Build Coastguard Worker cmpAAT::LookupSegmentArray225*2d1272b8SAndroid Build Coastguard Worker int cmp (hb_codepoint_t g) const 226*2d1272b8SAndroid Build Coastguard Worker { return g < first ? -1 : g <= last ? 0 : +1; } 227*2d1272b8SAndroid Build Coastguard Worker sanitizeAAT::LookupSegmentArray228*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c, const void *base) const 229*2d1272b8SAndroid Build Coastguard Worker { 230*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 231*2d1272b8SAndroid Build Coastguard Worker return_trace (c->check_struct (this) && 232*2d1272b8SAndroid Build Coastguard Worker hb_barrier () && 233*2d1272b8SAndroid Build Coastguard Worker first <= last && 234*2d1272b8SAndroid Build Coastguard Worker valuesZ.sanitize (c, base, last - first + 1)); 235*2d1272b8SAndroid Build Coastguard Worker } 236*2d1272b8SAndroid Build Coastguard Worker template <typename ...Ts> sanitizeAAT::LookupSegmentArray237*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const 238*2d1272b8SAndroid Build Coastguard Worker { 239*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 240*2d1272b8SAndroid Build Coastguard Worker return_trace (c->check_struct (this) && 241*2d1272b8SAndroid Build Coastguard Worker hb_barrier () && 242*2d1272b8SAndroid Build Coastguard Worker first <= last && 243*2d1272b8SAndroid Build Coastguard Worker valuesZ.sanitize (c, base, last - first + 1, std::forward<Ts> (ds)...)); 244*2d1272b8SAndroid Build Coastguard Worker } 245*2d1272b8SAndroid Build Coastguard Worker 246*2d1272b8SAndroid Build Coastguard Worker HBGlyphID16 last; /* Last GlyphID in this segment */ 247*2d1272b8SAndroid Build Coastguard Worker HBGlyphID16 first; /* First GlyphID in this segment */ 248*2d1272b8SAndroid Build Coastguard Worker NNOffset16To<UnsizedArrayOf<T>> 249*2d1272b8SAndroid Build Coastguard Worker valuesZ; /* A 16-bit offset from the start of 250*2d1272b8SAndroid Build Coastguard Worker * the table to the data. */ 251*2d1272b8SAndroid Build Coastguard Worker public: 252*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_STATIC (6); 253*2d1272b8SAndroid Build Coastguard Worker }; 254*2d1272b8SAndroid Build Coastguard Worker 255*2d1272b8SAndroid Build Coastguard Worker template <typename T> 256*2d1272b8SAndroid Build Coastguard Worker struct LookupFormat4 257*2d1272b8SAndroid Build Coastguard Worker { 258*2d1272b8SAndroid Build Coastguard Worker friend struct Lookup<T>; 259*2d1272b8SAndroid Build Coastguard Worker 260*2d1272b8SAndroid Build Coastguard Worker private: get_valueAAT::LookupFormat4261*2d1272b8SAndroid Build Coastguard Worker const T* get_value (hb_codepoint_t glyph_id) const 262*2d1272b8SAndroid Build Coastguard Worker { 263*2d1272b8SAndroid Build Coastguard Worker const LookupSegmentArray<T> *v = segments.bsearch (glyph_id); 264*2d1272b8SAndroid Build Coastguard Worker return v ? v->get_value (glyph_id, this) : nullptr; 265*2d1272b8SAndroid Build Coastguard Worker } 266*2d1272b8SAndroid Build Coastguard Worker 267*2d1272b8SAndroid Build Coastguard Worker template <typename set_t> collect_glyphsAAT::LookupFormat4268*2d1272b8SAndroid Build Coastguard Worker void collect_glyphs (set_t &glyphs) const 269*2d1272b8SAndroid Build Coastguard Worker { 270*2d1272b8SAndroid Build Coastguard Worker unsigned count = segments.get_length (); 271*2d1272b8SAndroid Build Coastguard Worker for (unsigned i = 0; i < count; i++) 272*2d1272b8SAndroid Build Coastguard Worker segments[i].collect_glyphs (glyphs); 273*2d1272b8SAndroid Build Coastguard Worker } 274*2d1272b8SAndroid Build Coastguard Worker sanitizeAAT::LookupFormat4275*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c) const 276*2d1272b8SAndroid Build Coastguard Worker { 277*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 278*2d1272b8SAndroid Build Coastguard Worker return_trace (segments.sanitize (c, this)); 279*2d1272b8SAndroid Build Coastguard Worker } sanitizeAAT::LookupFormat4280*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c, const void *base) const 281*2d1272b8SAndroid Build Coastguard Worker { 282*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 283*2d1272b8SAndroid Build Coastguard Worker return_trace (segments.sanitize (c, this, base)); 284*2d1272b8SAndroid Build Coastguard Worker } 285*2d1272b8SAndroid Build Coastguard Worker 286*2d1272b8SAndroid Build Coastguard Worker protected: 287*2d1272b8SAndroid Build Coastguard Worker HBUINT16 format; /* Format identifier--format = 4 */ 288*2d1272b8SAndroid Build Coastguard Worker VarSizedBinSearchArrayOf<LookupSegmentArray<T>> 289*2d1272b8SAndroid Build Coastguard Worker segments; /* The actual segments. These must already be sorted, 290*2d1272b8SAndroid Build Coastguard Worker * according to the first word in each one (the last 291*2d1272b8SAndroid Build Coastguard Worker * glyph in each segment). */ 292*2d1272b8SAndroid Build Coastguard Worker public: 293*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_ARRAY (8, segments); 294*2d1272b8SAndroid Build Coastguard Worker }; 295*2d1272b8SAndroid Build Coastguard Worker 296*2d1272b8SAndroid Build Coastguard Worker template <typename T> 297*2d1272b8SAndroid Build Coastguard Worker struct LookupSingle 298*2d1272b8SAndroid Build Coastguard Worker { 299*2d1272b8SAndroid Build Coastguard Worker static constexpr unsigned TerminationWordCount = 1u; 300*2d1272b8SAndroid Build Coastguard Worker cmpAAT::LookupSingle301*2d1272b8SAndroid Build Coastguard Worker int cmp (hb_codepoint_t g) const { return glyph.cmp (g); } 302*2d1272b8SAndroid Build Coastguard Worker 303*2d1272b8SAndroid Build Coastguard Worker template <typename set_t> collect_glyphsAAT::LookupSingle304*2d1272b8SAndroid Build Coastguard Worker void collect_glyphs (set_t &glyphs) const 305*2d1272b8SAndroid Build Coastguard Worker { 306*2d1272b8SAndroid Build Coastguard Worker if (glyph == DELETED_GLYPH) 307*2d1272b8SAndroid Build Coastguard Worker return; 308*2d1272b8SAndroid Build Coastguard Worker glyphs.add (glyph); 309*2d1272b8SAndroid Build Coastguard Worker } 310*2d1272b8SAndroid Build Coastguard Worker sanitizeAAT::LookupSingle311*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c) const 312*2d1272b8SAndroid Build Coastguard Worker { 313*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 314*2d1272b8SAndroid Build Coastguard Worker return_trace (c->check_struct (this) && value.sanitize (c)); 315*2d1272b8SAndroid Build Coastguard Worker } sanitizeAAT::LookupSingle316*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c, const void *base) const 317*2d1272b8SAndroid Build Coastguard Worker { 318*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 319*2d1272b8SAndroid Build Coastguard Worker return_trace (c->check_struct (this) && value.sanitize (c, base)); 320*2d1272b8SAndroid Build Coastguard Worker } 321*2d1272b8SAndroid Build Coastguard Worker 322*2d1272b8SAndroid Build Coastguard Worker HBGlyphID16 glyph; /* Last GlyphID */ 323*2d1272b8SAndroid Build Coastguard Worker T value; /* The lookup value (only one) */ 324*2d1272b8SAndroid Build Coastguard Worker public: 325*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_STATIC (2 + T::static_size); 326*2d1272b8SAndroid Build Coastguard Worker }; 327*2d1272b8SAndroid Build Coastguard Worker 328*2d1272b8SAndroid Build Coastguard Worker template <typename T> 329*2d1272b8SAndroid Build Coastguard Worker struct LookupFormat6 330*2d1272b8SAndroid Build Coastguard Worker { 331*2d1272b8SAndroid Build Coastguard Worker friend struct Lookup<T>; 332*2d1272b8SAndroid Build Coastguard Worker 333*2d1272b8SAndroid Build Coastguard Worker private: get_valueAAT::LookupFormat6334*2d1272b8SAndroid Build Coastguard Worker const T* get_value (hb_codepoint_t glyph_id) const 335*2d1272b8SAndroid Build Coastguard Worker { 336*2d1272b8SAndroid Build Coastguard Worker const LookupSingle<T> *v = entries.bsearch (glyph_id); 337*2d1272b8SAndroid Build Coastguard Worker return v ? &v->value : nullptr; 338*2d1272b8SAndroid Build Coastguard Worker } 339*2d1272b8SAndroid Build Coastguard Worker 340*2d1272b8SAndroid Build Coastguard Worker template <typename set_t> collect_glyphsAAT::LookupFormat6341*2d1272b8SAndroid Build Coastguard Worker void collect_glyphs (set_t &glyphs) const 342*2d1272b8SAndroid Build Coastguard Worker { 343*2d1272b8SAndroid Build Coastguard Worker unsigned count = entries.get_length (); 344*2d1272b8SAndroid Build Coastguard Worker for (unsigned i = 0; i < count; i++) 345*2d1272b8SAndroid Build Coastguard Worker entries[i].collect_glyphs (glyphs); 346*2d1272b8SAndroid Build Coastguard Worker } 347*2d1272b8SAndroid Build Coastguard Worker sanitizeAAT::LookupFormat6348*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c) const 349*2d1272b8SAndroid Build Coastguard Worker { 350*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 351*2d1272b8SAndroid Build Coastguard Worker return_trace (entries.sanitize (c)); 352*2d1272b8SAndroid Build Coastguard Worker } sanitizeAAT::LookupFormat6353*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c, const void *base) const 354*2d1272b8SAndroid Build Coastguard Worker { 355*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 356*2d1272b8SAndroid Build Coastguard Worker return_trace (entries.sanitize (c, base)); 357*2d1272b8SAndroid Build Coastguard Worker } 358*2d1272b8SAndroid Build Coastguard Worker 359*2d1272b8SAndroid Build Coastguard Worker protected: 360*2d1272b8SAndroid Build Coastguard Worker HBUINT16 format; /* Format identifier--format = 6 */ 361*2d1272b8SAndroid Build Coastguard Worker VarSizedBinSearchArrayOf<LookupSingle<T>> 362*2d1272b8SAndroid Build Coastguard Worker entries; /* The actual entries, sorted by glyph index. */ 363*2d1272b8SAndroid Build Coastguard Worker public: 364*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_ARRAY (8, entries); 365*2d1272b8SAndroid Build Coastguard Worker }; 366*2d1272b8SAndroid Build Coastguard Worker 367*2d1272b8SAndroid Build Coastguard Worker template <typename T> 368*2d1272b8SAndroid Build Coastguard Worker struct LookupFormat8 369*2d1272b8SAndroid Build Coastguard Worker { 370*2d1272b8SAndroid Build Coastguard Worker friend struct Lookup<T>; 371*2d1272b8SAndroid Build Coastguard Worker 372*2d1272b8SAndroid Build Coastguard Worker private: get_valueAAT::LookupFormat8373*2d1272b8SAndroid Build Coastguard Worker const T* get_value (hb_codepoint_t glyph_id) const 374*2d1272b8SAndroid Build Coastguard Worker { 375*2d1272b8SAndroid Build Coastguard Worker return firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount ? 376*2d1272b8SAndroid Build Coastguard Worker &valueArrayZ[glyph_id - firstGlyph] : nullptr; 377*2d1272b8SAndroid Build Coastguard Worker } 378*2d1272b8SAndroid Build Coastguard Worker 379*2d1272b8SAndroid Build Coastguard Worker template <typename set_t> collect_glyphsAAT::LookupFormat8380*2d1272b8SAndroid Build Coastguard Worker void collect_glyphs (set_t &glyphs) const 381*2d1272b8SAndroid Build Coastguard Worker { 382*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!glyphCount)) 383*2d1272b8SAndroid Build Coastguard Worker return; 384*2d1272b8SAndroid Build Coastguard Worker if (firstGlyph == DELETED_GLYPH) 385*2d1272b8SAndroid Build Coastguard Worker return; 386*2d1272b8SAndroid Build Coastguard Worker glyphs.add_range (firstGlyph, firstGlyph + glyphCount - 1); 387*2d1272b8SAndroid Build Coastguard Worker } 388*2d1272b8SAndroid Build Coastguard Worker sanitizeAAT::LookupFormat8389*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c) const 390*2d1272b8SAndroid Build Coastguard Worker { 391*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 392*2d1272b8SAndroid Build Coastguard Worker return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount)); 393*2d1272b8SAndroid Build Coastguard Worker } sanitizeAAT::LookupFormat8394*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c, const void *base) const 395*2d1272b8SAndroid Build Coastguard Worker { 396*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 397*2d1272b8SAndroid Build Coastguard Worker return_trace (c->check_struct (this) && valueArrayZ.sanitize (c, glyphCount, base)); 398*2d1272b8SAndroid Build Coastguard Worker } 399*2d1272b8SAndroid Build Coastguard Worker 400*2d1272b8SAndroid Build Coastguard Worker protected: 401*2d1272b8SAndroid Build Coastguard Worker HBUINT16 format; /* Format identifier--format = 8 */ 402*2d1272b8SAndroid Build Coastguard Worker HBGlyphID16 firstGlyph; /* First glyph index included in the trimmed array. */ 403*2d1272b8SAndroid Build Coastguard Worker HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last 404*2d1272b8SAndroid Build Coastguard Worker * glyph minus the value of firstGlyph plus 1). */ 405*2d1272b8SAndroid Build Coastguard Worker UnsizedArrayOf<T> 406*2d1272b8SAndroid Build Coastguard Worker valueArrayZ; /* The lookup values (indexed by the glyph index 407*2d1272b8SAndroid Build Coastguard Worker * minus the value of firstGlyph). */ 408*2d1272b8SAndroid Build Coastguard Worker public: 409*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_ARRAY (6, valueArrayZ); 410*2d1272b8SAndroid Build Coastguard Worker }; 411*2d1272b8SAndroid Build Coastguard Worker 412*2d1272b8SAndroid Build Coastguard Worker template <typename T> 413*2d1272b8SAndroid Build Coastguard Worker struct LookupFormat10 414*2d1272b8SAndroid Build Coastguard Worker { 415*2d1272b8SAndroid Build Coastguard Worker friend struct Lookup<T>; 416*2d1272b8SAndroid Build Coastguard Worker 417*2d1272b8SAndroid Build Coastguard Worker private: get_value_or_nullAAT::LookupFormat10418*2d1272b8SAndroid Build Coastguard Worker const typename T::type get_value_or_null (hb_codepoint_t glyph_id) const 419*2d1272b8SAndroid Build Coastguard Worker { 420*2d1272b8SAndroid Build Coastguard Worker if (!(firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount)) 421*2d1272b8SAndroid Build Coastguard Worker return Null (T); 422*2d1272b8SAndroid Build Coastguard Worker 423*2d1272b8SAndroid Build Coastguard Worker const HBUINT8 *p = &valueArrayZ[(glyph_id - firstGlyph) * valueSize]; 424*2d1272b8SAndroid Build Coastguard Worker 425*2d1272b8SAndroid Build Coastguard Worker unsigned int v = 0; 426*2d1272b8SAndroid Build Coastguard Worker unsigned int count = valueSize; 427*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < count; i++) 428*2d1272b8SAndroid Build Coastguard Worker v = (v << 8) | *p++; 429*2d1272b8SAndroid Build Coastguard Worker 430*2d1272b8SAndroid Build Coastguard Worker return v; 431*2d1272b8SAndroid Build Coastguard Worker } 432*2d1272b8SAndroid Build Coastguard Worker 433*2d1272b8SAndroid Build Coastguard Worker template <typename set_t> collect_glyphsAAT::LookupFormat10434*2d1272b8SAndroid Build Coastguard Worker void collect_glyphs (set_t &glyphs) const 435*2d1272b8SAndroid Build Coastguard Worker { 436*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!glyphCount)) 437*2d1272b8SAndroid Build Coastguard Worker return; 438*2d1272b8SAndroid Build Coastguard Worker if (firstGlyph == DELETED_GLYPH) 439*2d1272b8SAndroid Build Coastguard Worker return; 440*2d1272b8SAndroid Build Coastguard Worker glyphs.add_range (firstGlyph, firstGlyph + glyphCount - 1); 441*2d1272b8SAndroid Build Coastguard Worker } 442*2d1272b8SAndroid Build Coastguard Worker sanitizeAAT::LookupFormat10443*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c) const 444*2d1272b8SAndroid Build Coastguard Worker { 445*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 446*2d1272b8SAndroid Build Coastguard Worker return_trace (c->check_struct (this) && 447*2d1272b8SAndroid Build Coastguard Worker hb_barrier () && 448*2d1272b8SAndroid Build Coastguard Worker valueSize <= 4 && 449*2d1272b8SAndroid Build Coastguard Worker valueArrayZ.sanitize (c, glyphCount * valueSize)); 450*2d1272b8SAndroid Build Coastguard Worker } 451*2d1272b8SAndroid Build Coastguard Worker 452*2d1272b8SAndroid Build Coastguard Worker protected: 453*2d1272b8SAndroid Build Coastguard Worker HBUINT16 format; /* Format identifier--format = 8 */ 454*2d1272b8SAndroid Build Coastguard Worker HBUINT16 valueSize; /* Byte size of each value. */ 455*2d1272b8SAndroid Build Coastguard Worker HBGlyphID16 firstGlyph; /* First glyph index included in the trimmed array. */ 456*2d1272b8SAndroid Build Coastguard Worker HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last 457*2d1272b8SAndroid Build Coastguard Worker * glyph minus the value of firstGlyph plus 1). */ 458*2d1272b8SAndroid Build Coastguard Worker UnsizedArrayOf<HBUINT8> 459*2d1272b8SAndroid Build Coastguard Worker valueArrayZ; /* The lookup values (indexed by the glyph index 460*2d1272b8SAndroid Build Coastguard Worker * minus the value of firstGlyph). */ 461*2d1272b8SAndroid Build Coastguard Worker public: 462*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_ARRAY (8, valueArrayZ); 463*2d1272b8SAndroid Build Coastguard Worker }; 464*2d1272b8SAndroid Build Coastguard Worker 465*2d1272b8SAndroid Build Coastguard Worker template <typename T> 466*2d1272b8SAndroid Build Coastguard Worker struct Lookup 467*2d1272b8SAndroid Build Coastguard Worker { get_valueAAT::Lookup468*2d1272b8SAndroid Build Coastguard Worker const T* get_value (hb_codepoint_t glyph_id, unsigned int num_glyphs) const 469*2d1272b8SAndroid Build Coastguard Worker { 470*2d1272b8SAndroid Build Coastguard Worker switch (u.format) { 471*2d1272b8SAndroid Build Coastguard Worker case 0: hb_barrier (); return u.format0.get_value (glyph_id, num_glyphs); 472*2d1272b8SAndroid Build Coastguard Worker case 2: hb_barrier (); return u.format2.get_value (glyph_id); 473*2d1272b8SAndroid Build Coastguard Worker case 4: hb_barrier (); return u.format4.get_value (glyph_id); 474*2d1272b8SAndroid Build Coastguard Worker case 6: hb_barrier (); return u.format6.get_value (glyph_id); 475*2d1272b8SAndroid Build Coastguard Worker case 8: hb_barrier (); return u.format8.get_value (glyph_id); 476*2d1272b8SAndroid Build Coastguard Worker default:return nullptr; 477*2d1272b8SAndroid Build Coastguard Worker } 478*2d1272b8SAndroid Build Coastguard Worker } 479*2d1272b8SAndroid Build Coastguard Worker get_value_or_nullAAT::Lookup480*2d1272b8SAndroid Build Coastguard Worker const typename T::type get_value_or_null (hb_codepoint_t glyph_id, unsigned int num_glyphs) const 481*2d1272b8SAndroid Build Coastguard Worker { 482*2d1272b8SAndroid Build Coastguard Worker switch (u.format) { 483*2d1272b8SAndroid Build Coastguard Worker /* Format 10 cannot return a pointer. */ 484*2d1272b8SAndroid Build Coastguard Worker case 10: hb_barrier (); return u.format10.get_value_or_null (glyph_id); 485*2d1272b8SAndroid Build Coastguard Worker default: 486*2d1272b8SAndroid Build Coastguard Worker const T *v = get_value (glyph_id, num_glyphs); 487*2d1272b8SAndroid Build Coastguard Worker return v ? *v : Null (T); 488*2d1272b8SAndroid Build Coastguard Worker } 489*2d1272b8SAndroid Build Coastguard Worker } 490*2d1272b8SAndroid Build Coastguard Worker 491*2d1272b8SAndroid Build Coastguard Worker template <typename set_t> collect_glyphsAAT::Lookup492*2d1272b8SAndroid Build Coastguard Worker void collect_glyphs (set_t &glyphs, unsigned int num_glyphs) const 493*2d1272b8SAndroid Build Coastguard Worker { 494*2d1272b8SAndroid Build Coastguard Worker switch (u.format) { 495*2d1272b8SAndroid Build Coastguard Worker case 0: hb_barrier (); u.format0.collect_glyphs (glyphs, num_glyphs); return; 496*2d1272b8SAndroid Build Coastguard Worker case 2: hb_barrier (); u.format2.collect_glyphs (glyphs); return; 497*2d1272b8SAndroid Build Coastguard Worker case 4: hb_barrier (); u.format4.collect_glyphs (glyphs); return; 498*2d1272b8SAndroid Build Coastguard Worker case 6: hb_barrier (); u.format6.collect_glyphs (glyphs); return; 499*2d1272b8SAndroid Build Coastguard Worker case 8: hb_barrier (); u.format8.collect_glyphs (glyphs); return; 500*2d1272b8SAndroid Build Coastguard Worker case 10: hb_barrier (); u.format10.collect_glyphs (glyphs); return; 501*2d1272b8SAndroid Build Coastguard Worker default:return; 502*2d1272b8SAndroid Build Coastguard Worker } 503*2d1272b8SAndroid Build Coastguard Worker } 504*2d1272b8SAndroid Build Coastguard Worker get_classAAT::Lookup505*2d1272b8SAndroid Build Coastguard Worker typename T::type get_class (hb_codepoint_t glyph_id, 506*2d1272b8SAndroid Build Coastguard Worker unsigned int num_glyphs, 507*2d1272b8SAndroid Build Coastguard Worker unsigned int outOfRange) const 508*2d1272b8SAndroid Build Coastguard Worker { 509*2d1272b8SAndroid Build Coastguard Worker const T *v = get_value (glyph_id, num_glyphs); 510*2d1272b8SAndroid Build Coastguard Worker return v ? *v : outOfRange; 511*2d1272b8SAndroid Build Coastguard Worker } 512*2d1272b8SAndroid Build Coastguard Worker sanitizeAAT::Lookup513*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c) const 514*2d1272b8SAndroid Build Coastguard Worker { 515*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 516*2d1272b8SAndroid Build Coastguard Worker if (!u.format.sanitize (c)) return_trace (false); 517*2d1272b8SAndroid Build Coastguard Worker hb_barrier (); 518*2d1272b8SAndroid Build Coastguard Worker switch (u.format) { 519*2d1272b8SAndroid Build Coastguard Worker case 0: hb_barrier (); return_trace (u.format0.sanitize (c)); 520*2d1272b8SAndroid Build Coastguard Worker case 2: hb_barrier (); return_trace (u.format2.sanitize (c)); 521*2d1272b8SAndroid Build Coastguard Worker case 4: hb_barrier (); return_trace (u.format4.sanitize (c)); 522*2d1272b8SAndroid Build Coastguard Worker case 6: hb_barrier (); return_trace (u.format6.sanitize (c)); 523*2d1272b8SAndroid Build Coastguard Worker case 8: hb_barrier (); return_trace (u.format8.sanitize (c)); 524*2d1272b8SAndroid Build Coastguard Worker case 10: hb_barrier (); return_trace (u.format10.sanitize (c)); 525*2d1272b8SAndroid Build Coastguard Worker default:return_trace (true); 526*2d1272b8SAndroid Build Coastguard Worker } 527*2d1272b8SAndroid Build Coastguard Worker } sanitizeAAT::Lookup528*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c, const void *base) const 529*2d1272b8SAndroid Build Coastguard Worker { 530*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 531*2d1272b8SAndroid Build Coastguard Worker if (!u.format.sanitize (c)) return_trace (false); 532*2d1272b8SAndroid Build Coastguard Worker hb_barrier (); 533*2d1272b8SAndroid Build Coastguard Worker switch (u.format) { 534*2d1272b8SAndroid Build Coastguard Worker case 0: hb_barrier (); return_trace (u.format0.sanitize (c, base)); 535*2d1272b8SAndroid Build Coastguard Worker case 2: hb_barrier (); return_trace (u.format2.sanitize (c, base)); 536*2d1272b8SAndroid Build Coastguard Worker case 4: hb_barrier (); return_trace (u.format4.sanitize (c, base)); 537*2d1272b8SAndroid Build Coastguard Worker case 6: hb_barrier (); return_trace (u.format6.sanitize (c, base)); 538*2d1272b8SAndroid Build Coastguard Worker case 8: hb_barrier (); return_trace (u.format8.sanitize (c, base)); 539*2d1272b8SAndroid Build Coastguard Worker case 10: return_trace (false); /* We don't support format10 here currently. */ 540*2d1272b8SAndroid Build Coastguard Worker default:return_trace (true); 541*2d1272b8SAndroid Build Coastguard Worker } 542*2d1272b8SAndroid Build Coastguard Worker } 543*2d1272b8SAndroid Build Coastguard Worker 544*2d1272b8SAndroid Build Coastguard Worker protected: 545*2d1272b8SAndroid Build Coastguard Worker union { 546*2d1272b8SAndroid Build Coastguard Worker HBUINT16 format; /* Format identifier */ 547*2d1272b8SAndroid Build Coastguard Worker LookupFormat0<T> format0; 548*2d1272b8SAndroid Build Coastguard Worker LookupFormat2<T> format2; 549*2d1272b8SAndroid Build Coastguard Worker LookupFormat4<T> format4; 550*2d1272b8SAndroid Build Coastguard Worker LookupFormat6<T> format6; 551*2d1272b8SAndroid Build Coastguard Worker LookupFormat8<T> format8; 552*2d1272b8SAndroid Build Coastguard Worker LookupFormat10<T> format10; 553*2d1272b8SAndroid Build Coastguard Worker } u; 554*2d1272b8SAndroid Build Coastguard Worker public: 555*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_UNION (2, format); 556*2d1272b8SAndroid Build Coastguard Worker }; 557*2d1272b8SAndroid Build Coastguard Worker DECLARE_NULL_NAMESPACE_BYTES_TEMPLATE1 (AAT, Lookup, 2); 558*2d1272b8SAndroid Build Coastguard Worker 559*2d1272b8SAndroid Build Coastguard Worker /* 560*2d1272b8SAndroid Build Coastguard Worker * (Extended) State Table 561*2d1272b8SAndroid Build Coastguard Worker */ 562*2d1272b8SAndroid Build Coastguard Worker 563*2d1272b8SAndroid Build Coastguard Worker template <typename T> 564*2d1272b8SAndroid Build Coastguard Worker struct Entry 565*2d1272b8SAndroid Build Coastguard Worker { 566*2d1272b8SAndroid Build Coastguard Worker // This does seem like it's ever called. sanitizeAAT::Entry567*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c) const 568*2d1272b8SAndroid Build Coastguard Worker { 569*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 570*2d1272b8SAndroid Build Coastguard Worker /* Note, we don't recurse-sanitize data because we don't access it. 571*2d1272b8SAndroid Build Coastguard Worker * That said, in our DEFINE_SIZE_STATIC we access T::static_size, 572*2d1272b8SAndroid Build Coastguard Worker * which ensures that data has a simple sanitize(). To be determined 573*2d1272b8SAndroid Build Coastguard Worker * if I need to remove that as well. 574*2d1272b8SAndroid Build Coastguard Worker * 575*2d1272b8SAndroid Build Coastguard Worker * HOWEVER! Because we are a template, our DEFINE_SIZE_STATIC 576*2d1272b8SAndroid Build Coastguard Worker * assertion wouldn't be checked, hence the line below. */ 577*2d1272b8SAndroid Build Coastguard Worker static_assert (T::static_size, ""); 578*2d1272b8SAndroid Build Coastguard Worker 579*2d1272b8SAndroid Build Coastguard Worker return_trace (c->check_struct (this)); 580*2d1272b8SAndroid Build Coastguard Worker } 581*2d1272b8SAndroid Build Coastguard Worker 582*2d1272b8SAndroid Build Coastguard Worker public: 583*2d1272b8SAndroid Build Coastguard Worker HBUINT16 newState; /* Byte offset from beginning of state table 584*2d1272b8SAndroid Build Coastguard Worker * to the new state. Really?!?! Or just state 585*2d1272b8SAndroid Build Coastguard Worker * number? The latter in morx for sure. */ 586*2d1272b8SAndroid Build Coastguard Worker HBUINT16 flags; /* Table specific. */ 587*2d1272b8SAndroid Build Coastguard Worker T data; /* Optional offsets to per-glyph tables. */ 588*2d1272b8SAndroid Build Coastguard Worker public: 589*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_STATIC (4 + T::static_size); 590*2d1272b8SAndroid Build Coastguard Worker }; 591*2d1272b8SAndroid Build Coastguard Worker 592*2d1272b8SAndroid Build Coastguard Worker template <> 593*2d1272b8SAndroid Build Coastguard Worker struct Entry<void> 594*2d1272b8SAndroid Build Coastguard Worker { 595*2d1272b8SAndroid Build Coastguard Worker // This does seem like it's ever called. sanitizeAAT::Entry596*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c) const 597*2d1272b8SAndroid Build Coastguard Worker { 598*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 599*2d1272b8SAndroid Build Coastguard Worker return_trace (c->check_struct (this)); 600*2d1272b8SAndroid Build Coastguard Worker } 601*2d1272b8SAndroid Build Coastguard Worker 602*2d1272b8SAndroid Build Coastguard Worker public: 603*2d1272b8SAndroid Build Coastguard Worker HBUINT16 newState; /* Byte offset from beginning of state table to the new state. */ 604*2d1272b8SAndroid Build Coastguard Worker HBUINT16 flags; /* Table specific. */ 605*2d1272b8SAndroid Build Coastguard Worker public: 606*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_STATIC (4); 607*2d1272b8SAndroid Build Coastguard Worker }; 608*2d1272b8SAndroid Build Coastguard Worker 609*2d1272b8SAndroid Build Coastguard Worker enum Class 610*2d1272b8SAndroid Build Coastguard Worker { 611*2d1272b8SAndroid Build Coastguard Worker CLASS_END_OF_TEXT = 0, 612*2d1272b8SAndroid Build Coastguard Worker CLASS_OUT_OF_BOUNDS = 1, 613*2d1272b8SAndroid Build Coastguard Worker CLASS_DELETED_GLYPH = 2, 614*2d1272b8SAndroid Build Coastguard Worker CLASS_END_OF_LINE = 3, 615*2d1272b8SAndroid Build Coastguard Worker }; 616*2d1272b8SAndroid Build Coastguard Worker 617*2d1272b8SAndroid Build Coastguard Worker template <typename Types, typename Extra> 618*2d1272b8SAndroid Build Coastguard Worker struct StateTable 619*2d1272b8SAndroid Build Coastguard Worker { 620*2d1272b8SAndroid Build Coastguard Worker typedef typename Types::HBUINT HBUINT; 621*2d1272b8SAndroid Build Coastguard Worker typedef typename Types::HBUSHORT HBUSHORT; 622*2d1272b8SAndroid Build Coastguard Worker typedef typename Types::ClassTypeNarrow ClassType; 623*2d1272b8SAndroid Build Coastguard Worker 624*2d1272b8SAndroid Build Coastguard Worker enum State 625*2d1272b8SAndroid Build Coastguard Worker { 626*2d1272b8SAndroid Build Coastguard Worker STATE_START_OF_TEXT = 0, 627*2d1272b8SAndroid Build Coastguard Worker STATE_START_OF_LINE = 1, 628*2d1272b8SAndroid Build Coastguard Worker }; 629*2d1272b8SAndroid Build Coastguard Worker 630*2d1272b8SAndroid Build Coastguard Worker template <typename set_t> collect_glyphsAAT::StateTable631*2d1272b8SAndroid Build Coastguard Worker void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const 632*2d1272b8SAndroid Build Coastguard Worker { 633*2d1272b8SAndroid Build Coastguard Worker (this+classTable).collect_glyphs (glyphs, num_glyphs); 634*2d1272b8SAndroid Build Coastguard Worker } 635*2d1272b8SAndroid Build Coastguard Worker new_stateAAT::StateTable636*2d1272b8SAndroid Build Coastguard Worker int new_state (unsigned int newState) const 637*2d1272b8SAndroid Build Coastguard Worker { return Types::extended ? newState : ((int) newState - (int) stateArrayTable) / (int) nClasses; } 638*2d1272b8SAndroid Build Coastguard Worker 639*2d1272b8SAndroid Build Coastguard Worker template <typename set_t> get_classAAT::StateTable640*2d1272b8SAndroid Build Coastguard Worker unsigned int get_class (hb_codepoint_t glyph_id, 641*2d1272b8SAndroid Build Coastguard Worker unsigned int num_glyphs, 642*2d1272b8SAndroid Build Coastguard Worker const set_t &glyphs) const 643*2d1272b8SAndroid Build Coastguard Worker { 644*2d1272b8SAndroid Build Coastguard Worker if (unlikely (glyph_id == DELETED_GLYPH)) return CLASS_DELETED_GLYPH; 645*2d1272b8SAndroid Build Coastguard Worker if (!glyphs[glyph_id]) return CLASS_OUT_OF_BOUNDS; 646*2d1272b8SAndroid Build Coastguard Worker return (this+classTable).get_class (glyph_id, num_glyphs, CLASS_OUT_OF_BOUNDS); 647*2d1272b8SAndroid Build Coastguard Worker } 648*2d1272b8SAndroid Build Coastguard Worker get_entriesAAT::StateTable649*2d1272b8SAndroid Build Coastguard Worker const Entry<Extra> *get_entries () const 650*2d1272b8SAndroid Build Coastguard Worker { return (this+entryTable).arrayZ; } 651*2d1272b8SAndroid Build Coastguard Worker get_entryAAT::StateTable652*2d1272b8SAndroid Build Coastguard Worker const Entry<Extra> &get_entry (int state, unsigned int klass) const 653*2d1272b8SAndroid Build Coastguard Worker { 654*2d1272b8SAndroid Build Coastguard Worker if (unlikely (klass >= nClasses)) 655*2d1272b8SAndroid Build Coastguard Worker klass = CLASS_OUT_OF_BOUNDS; 656*2d1272b8SAndroid Build Coastguard Worker 657*2d1272b8SAndroid Build Coastguard Worker const HBUSHORT *states = (this+stateArrayTable).arrayZ; 658*2d1272b8SAndroid Build Coastguard Worker const Entry<Extra> *entries = (this+entryTable).arrayZ; 659*2d1272b8SAndroid Build Coastguard Worker 660*2d1272b8SAndroid Build Coastguard Worker unsigned int entry = states[state * nClasses + klass]; 661*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG (APPLY, nullptr, "e%u", entry); 662*2d1272b8SAndroid Build Coastguard Worker 663*2d1272b8SAndroid Build Coastguard Worker return entries[entry]; 664*2d1272b8SAndroid Build Coastguard Worker } 665*2d1272b8SAndroid Build Coastguard Worker sanitizeAAT::StateTable666*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c, 667*2d1272b8SAndroid Build Coastguard Worker unsigned int *num_entries_out = nullptr) const 668*2d1272b8SAndroid Build Coastguard Worker { 669*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 670*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!(c->check_struct (this) && 671*2d1272b8SAndroid Build Coastguard Worker hb_barrier () && 672*2d1272b8SAndroid Build Coastguard Worker nClasses >= 4 /* Ensure pre-defined classes fit. */ && 673*2d1272b8SAndroid Build Coastguard Worker classTable.sanitize (c, this)))) return_trace (false); 674*2d1272b8SAndroid Build Coastguard Worker 675*2d1272b8SAndroid Build Coastguard Worker const HBUSHORT *states = (this+stateArrayTable).arrayZ; 676*2d1272b8SAndroid Build Coastguard Worker const Entry<Extra> *entries = (this+entryTable).arrayZ; 677*2d1272b8SAndroid Build Coastguard Worker 678*2d1272b8SAndroid Build Coastguard Worker unsigned int num_classes = nClasses; 679*2d1272b8SAndroid Build Coastguard Worker if (unlikely (hb_unsigned_mul_overflows (num_classes, states[0].static_size))) 680*2d1272b8SAndroid Build Coastguard Worker return_trace (false); 681*2d1272b8SAndroid Build Coastguard Worker unsigned int row_stride = num_classes * states[0].static_size; 682*2d1272b8SAndroid Build Coastguard Worker 683*2d1272b8SAndroid Build Coastguard Worker /* Apple 'kern' table has this peculiarity: 684*2d1272b8SAndroid Build Coastguard Worker * 685*2d1272b8SAndroid Build Coastguard Worker * "Because the stateTableOffset in the state table header is (strictly 686*2d1272b8SAndroid Build Coastguard Worker * speaking) redundant, some 'kern' tables use it to record an initial 687*2d1272b8SAndroid Build Coastguard Worker * state where that should not be StartOfText. To determine if this is 688*2d1272b8SAndroid Build Coastguard Worker * done, calculate what the stateTableOffset should be. If it's different 689*2d1272b8SAndroid Build Coastguard Worker * from the actual stateTableOffset, use it as the initial state." 690*2d1272b8SAndroid Build Coastguard Worker * 691*2d1272b8SAndroid Build Coastguard Worker * We implement this by calling the initial state zero, but allow *negative* 692*2d1272b8SAndroid Build Coastguard Worker * states if the start state indeed was not the first state. Since the code 693*2d1272b8SAndroid Build Coastguard Worker * is shared, this will also apply to 'mort' table. The 'kerx' / 'morx' 694*2d1272b8SAndroid Build Coastguard Worker * tables are not affected since those address states by index, not offset. 695*2d1272b8SAndroid Build Coastguard Worker */ 696*2d1272b8SAndroid Build Coastguard Worker 697*2d1272b8SAndroid Build Coastguard Worker int min_state = 0; 698*2d1272b8SAndroid Build Coastguard Worker int max_state = 0; 699*2d1272b8SAndroid Build Coastguard Worker unsigned int num_entries = 0; 700*2d1272b8SAndroid Build Coastguard Worker 701*2d1272b8SAndroid Build Coastguard Worker int state_pos = 0; 702*2d1272b8SAndroid Build Coastguard Worker int state_neg = 0; 703*2d1272b8SAndroid Build Coastguard Worker unsigned int entry = 0; 704*2d1272b8SAndroid Build Coastguard Worker while (min_state < state_neg || state_pos <= max_state) 705*2d1272b8SAndroid Build Coastguard Worker { 706*2d1272b8SAndroid Build Coastguard Worker if (min_state < state_neg) 707*2d1272b8SAndroid Build Coastguard Worker { 708*2d1272b8SAndroid Build Coastguard Worker /* Negative states. */ 709*2d1272b8SAndroid Build Coastguard Worker if (unlikely (hb_unsigned_mul_overflows (min_state, num_classes))) 710*2d1272b8SAndroid Build Coastguard Worker return_trace (false); 711*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!c->check_range (&states[min_state * num_classes], 712*2d1272b8SAndroid Build Coastguard Worker -min_state, 713*2d1272b8SAndroid Build Coastguard Worker row_stride))) 714*2d1272b8SAndroid Build Coastguard Worker return_trace (false); 715*2d1272b8SAndroid Build Coastguard Worker if ((c->max_ops -= state_neg - min_state) <= 0) 716*2d1272b8SAndroid Build Coastguard Worker return_trace (false); 717*2d1272b8SAndroid Build Coastguard Worker { /* Sweep new states. */ 718*2d1272b8SAndroid Build Coastguard Worker const HBUSHORT *stop = &states[min_state * num_classes]; 719*2d1272b8SAndroid Build Coastguard Worker if (unlikely (stop > states)) 720*2d1272b8SAndroid Build Coastguard Worker return_trace (false); 721*2d1272b8SAndroid Build Coastguard Worker for (const HBUSHORT *p = states; stop < p; p--) 722*2d1272b8SAndroid Build Coastguard Worker num_entries = hb_max (num_entries, *(p - 1) + 1u); 723*2d1272b8SAndroid Build Coastguard Worker state_neg = min_state; 724*2d1272b8SAndroid Build Coastguard Worker } 725*2d1272b8SAndroid Build Coastguard Worker } 726*2d1272b8SAndroid Build Coastguard Worker 727*2d1272b8SAndroid Build Coastguard Worker if (state_pos <= max_state) 728*2d1272b8SAndroid Build Coastguard Worker { 729*2d1272b8SAndroid Build Coastguard Worker /* Positive states. */ 730*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!c->check_range (states, 731*2d1272b8SAndroid Build Coastguard Worker max_state + 1, 732*2d1272b8SAndroid Build Coastguard Worker row_stride))) 733*2d1272b8SAndroid Build Coastguard Worker return_trace (false); 734*2d1272b8SAndroid Build Coastguard Worker if ((c->max_ops -= max_state - state_pos + 1) <= 0) 735*2d1272b8SAndroid Build Coastguard Worker return_trace (false); 736*2d1272b8SAndroid Build Coastguard Worker { /* Sweep new states. */ 737*2d1272b8SAndroid Build Coastguard Worker if (unlikely (hb_unsigned_mul_overflows ((max_state + 1), num_classes))) 738*2d1272b8SAndroid Build Coastguard Worker return_trace (false); 739*2d1272b8SAndroid Build Coastguard Worker const HBUSHORT *stop = &states[(max_state + 1) * num_classes]; 740*2d1272b8SAndroid Build Coastguard Worker if (unlikely (stop < states)) 741*2d1272b8SAndroid Build Coastguard Worker return_trace (false); 742*2d1272b8SAndroid Build Coastguard Worker for (const HBUSHORT *p = &states[state_pos * num_classes]; p < stop; p++) 743*2d1272b8SAndroid Build Coastguard Worker num_entries = hb_max (num_entries, *p + 1u); 744*2d1272b8SAndroid Build Coastguard Worker state_pos = max_state + 1; 745*2d1272b8SAndroid Build Coastguard Worker } 746*2d1272b8SAndroid Build Coastguard Worker } 747*2d1272b8SAndroid Build Coastguard Worker 748*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!c->check_array (entries, num_entries))) 749*2d1272b8SAndroid Build Coastguard Worker return_trace (false); 750*2d1272b8SAndroid Build Coastguard Worker if ((c->max_ops -= num_entries - entry) <= 0) 751*2d1272b8SAndroid Build Coastguard Worker return_trace (false); 752*2d1272b8SAndroid Build Coastguard Worker { /* Sweep new entries. */ 753*2d1272b8SAndroid Build Coastguard Worker const Entry<Extra> *stop = &entries[num_entries]; 754*2d1272b8SAndroid Build Coastguard Worker for (const Entry<Extra> *p = &entries[entry]; p < stop; p++) 755*2d1272b8SAndroid Build Coastguard Worker { 756*2d1272b8SAndroid Build Coastguard Worker int newState = new_state (p->newState); 757*2d1272b8SAndroid Build Coastguard Worker min_state = hb_min (min_state, newState); 758*2d1272b8SAndroid Build Coastguard Worker max_state = hb_max (max_state, newState); 759*2d1272b8SAndroid Build Coastguard Worker } 760*2d1272b8SAndroid Build Coastguard Worker entry = num_entries; 761*2d1272b8SAndroid Build Coastguard Worker } 762*2d1272b8SAndroid Build Coastguard Worker } 763*2d1272b8SAndroid Build Coastguard Worker 764*2d1272b8SAndroid Build Coastguard Worker if (num_entries_out) 765*2d1272b8SAndroid Build Coastguard Worker *num_entries_out = num_entries; 766*2d1272b8SAndroid Build Coastguard Worker 767*2d1272b8SAndroid Build Coastguard Worker return_trace (true); 768*2d1272b8SAndroid Build Coastguard Worker } 769*2d1272b8SAndroid Build Coastguard Worker 770*2d1272b8SAndroid Build Coastguard Worker protected: 771*2d1272b8SAndroid Build Coastguard Worker HBUINT nClasses; /* Number of classes, which is the number of indices 772*2d1272b8SAndroid Build Coastguard Worker * in a single line in the state array. */ 773*2d1272b8SAndroid Build Coastguard Worker NNOffsetTo<ClassType, HBUINT> 774*2d1272b8SAndroid Build Coastguard Worker classTable; /* Offset to the class table. */ 775*2d1272b8SAndroid Build Coastguard Worker NNOffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT> 776*2d1272b8SAndroid Build Coastguard Worker stateArrayTable;/* Offset to the state array. */ 777*2d1272b8SAndroid Build Coastguard Worker NNOffsetTo<UnsizedArrayOf<Entry<Extra>>, HBUINT> 778*2d1272b8SAndroid Build Coastguard Worker entryTable; /* Offset to the entry array. */ 779*2d1272b8SAndroid Build Coastguard Worker 780*2d1272b8SAndroid Build Coastguard Worker public: 781*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_STATIC (4 * sizeof (HBUINT)); 782*2d1272b8SAndroid Build Coastguard Worker }; 783*2d1272b8SAndroid Build Coastguard Worker 784*2d1272b8SAndroid Build Coastguard Worker template <typename HBUCHAR> 785*2d1272b8SAndroid Build Coastguard Worker struct ClassTable 786*2d1272b8SAndroid Build Coastguard Worker { get_classAAT::ClassTable787*2d1272b8SAndroid Build Coastguard Worker unsigned int get_class (hb_codepoint_t glyph_id, unsigned int outOfRange) const 788*2d1272b8SAndroid Build Coastguard Worker { 789*2d1272b8SAndroid Build Coastguard Worker unsigned int i = glyph_id - firstGlyph; 790*2d1272b8SAndroid Build Coastguard Worker return i >= classArray.len ? outOfRange : classArray.arrayZ[i]; 791*2d1272b8SAndroid Build Coastguard Worker } get_classAAT::ClassTable792*2d1272b8SAndroid Build Coastguard Worker unsigned int get_class (hb_codepoint_t glyph_id, 793*2d1272b8SAndroid Build Coastguard Worker unsigned int num_glyphs HB_UNUSED, 794*2d1272b8SAndroid Build Coastguard Worker unsigned int outOfRange) const 795*2d1272b8SAndroid Build Coastguard Worker { 796*2d1272b8SAndroid Build Coastguard Worker return get_class (glyph_id, outOfRange); 797*2d1272b8SAndroid Build Coastguard Worker } 798*2d1272b8SAndroid Build Coastguard Worker 799*2d1272b8SAndroid Build Coastguard Worker template <typename set_t> collect_glyphsAAT::ClassTable800*2d1272b8SAndroid Build Coastguard Worker void collect_glyphs (set_t &glyphs, unsigned num_glyphs) const 801*2d1272b8SAndroid Build Coastguard Worker { 802*2d1272b8SAndroid Build Coastguard Worker for (unsigned i = 0; i < classArray.len; i++) 803*2d1272b8SAndroid Build Coastguard Worker if (classArray.arrayZ[i] != CLASS_OUT_OF_BOUNDS) 804*2d1272b8SAndroid Build Coastguard Worker glyphs.add (firstGlyph + i); 805*2d1272b8SAndroid Build Coastguard Worker } 806*2d1272b8SAndroid Build Coastguard Worker sanitizeAAT::ClassTable807*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c) const 808*2d1272b8SAndroid Build Coastguard Worker { 809*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 810*2d1272b8SAndroid Build Coastguard Worker return_trace (c->check_struct (this) && classArray.sanitize (c)); 811*2d1272b8SAndroid Build Coastguard Worker } 812*2d1272b8SAndroid Build Coastguard Worker protected: 813*2d1272b8SAndroid Build Coastguard Worker HBGlyphID16 firstGlyph; /* First glyph index included in the trimmed array. */ 814*2d1272b8SAndroid Build Coastguard Worker Array16Of<HBUCHAR> classArray; /* The class codes (indexed by glyph index minus 815*2d1272b8SAndroid Build Coastguard Worker * firstGlyph). */ 816*2d1272b8SAndroid Build Coastguard Worker public: 817*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_ARRAY (4, classArray); 818*2d1272b8SAndroid Build Coastguard Worker }; 819*2d1272b8SAndroid Build Coastguard Worker 820*2d1272b8SAndroid Build Coastguard Worker struct SubtableGlyphCoverage 821*2d1272b8SAndroid Build Coastguard Worker { sanitizeAAT::SubtableGlyphCoverage822*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c, unsigned subtable_count) const 823*2d1272b8SAndroid Build Coastguard Worker { 824*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 825*2d1272b8SAndroid Build Coastguard Worker 826*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!c->check_array (&subtableOffsets, subtable_count))) 827*2d1272b8SAndroid Build Coastguard Worker return_trace (false); 828*2d1272b8SAndroid Build Coastguard Worker 829*2d1272b8SAndroid Build Coastguard Worker unsigned bytes = (c->get_num_glyphs () + CHAR_BIT - 1) / CHAR_BIT; 830*2d1272b8SAndroid Build Coastguard Worker for (unsigned i = 0; i < subtable_count; i++) 831*2d1272b8SAndroid Build Coastguard Worker { 832*2d1272b8SAndroid Build Coastguard Worker uint32_t offset = (uint32_t) subtableOffsets[i]; 833*2d1272b8SAndroid Build Coastguard Worker if (offset == 0 || offset == 0xFFFFFFFF) 834*2d1272b8SAndroid Build Coastguard Worker continue; 835*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!subtableOffsets[i].sanitize (c, this, bytes))) 836*2d1272b8SAndroid Build Coastguard Worker return_trace (false); 837*2d1272b8SAndroid Build Coastguard Worker } 838*2d1272b8SAndroid Build Coastguard Worker 839*2d1272b8SAndroid Build Coastguard Worker return_trace (true); 840*2d1272b8SAndroid Build Coastguard Worker } 841*2d1272b8SAndroid Build Coastguard Worker protected: 842*2d1272b8SAndroid Build Coastguard Worker UnsizedArrayOf<NNOffset32To<UnsizedArrayOf<HBUINT8>>> subtableOffsets; 843*2d1272b8SAndroid Build Coastguard Worker /* Array of offsets from the beginning of the 844*2d1272b8SAndroid Build Coastguard Worker * subtable glyph coverage table to the glyph 845*2d1272b8SAndroid Build Coastguard Worker * coverage bitfield for a given subtable; there 846*2d1272b8SAndroid Build Coastguard Worker * is one offset for each subtable in the chain */ 847*2d1272b8SAndroid Build Coastguard Worker /* UnsizedArrayOf<HBUINT8> coverageBitfields; *//* The individual coverage bitfields. */ 848*2d1272b8SAndroid Build Coastguard Worker public: 849*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_ARRAY (0, subtableOffsets); 850*2d1272b8SAndroid Build Coastguard Worker }; 851*2d1272b8SAndroid Build Coastguard Worker 852*2d1272b8SAndroid Build Coastguard Worker struct ObsoleteTypes 853*2d1272b8SAndroid Build Coastguard Worker { 854*2d1272b8SAndroid Build Coastguard Worker static constexpr bool extended = false; 855*2d1272b8SAndroid Build Coastguard Worker typedef HBUINT16 HBUINT; 856*2d1272b8SAndroid Build Coastguard Worker typedef HBUINT8 HBUSHORT; 857*2d1272b8SAndroid Build Coastguard Worker typedef ClassTable<HBUINT8> ClassTypeNarrow; 858*2d1272b8SAndroid Build Coastguard Worker typedef ClassTable<HBUINT16> ClassTypeWide; 859*2d1272b8SAndroid Build Coastguard Worker 860*2d1272b8SAndroid Build Coastguard Worker template <typename T> offsetToIndexAAT::ObsoleteTypes861*2d1272b8SAndroid Build Coastguard Worker static unsigned int offsetToIndex (unsigned int offset, 862*2d1272b8SAndroid Build Coastguard Worker const void *base, 863*2d1272b8SAndroid Build Coastguard Worker const T *array) 864*2d1272b8SAndroid Build Coastguard Worker { 865*2d1272b8SAndroid Build Coastguard Worker /* https://github.com/harfbuzz/harfbuzz/issues/3483 */ 866*2d1272b8SAndroid Build Coastguard Worker /* If offset is less than base, return an offset that would 867*2d1272b8SAndroid Build Coastguard Worker * result in an address half a 32bit address-space away, 868*2d1272b8SAndroid Build Coastguard Worker * to make sure sanitize fails even on 32bit builds. */ 869*2d1272b8SAndroid Build Coastguard Worker if (unlikely (offset < unsigned ((const char *) array - (const char *) base))) 870*2d1272b8SAndroid Build Coastguard Worker return INT_MAX / T::static_size; 871*2d1272b8SAndroid Build Coastguard Worker 872*2d1272b8SAndroid Build Coastguard Worker /* https://github.com/harfbuzz/harfbuzz/issues/2816 */ 873*2d1272b8SAndroid Build Coastguard Worker return (offset - unsigned ((const char *) array - (const char *) base)) / T::static_size; 874*2d1272b8SAndroid Build Coastguard Worker } 875*2d1272b8SAndroid Build Coastguard Worker template <typename T> byteOffsetToIndexAAT::ObsoleteTypes876*2d1272b8SAndroid Build Coastguard Worker static unsigned int byteOffsetToIndex (unsigned int offset, 877*2d1272b8SAndroid Build Coastguard Worker const void *base, 878*2d1272b8SAndroid Build Coastguard Worker const T *array) 879*2d1272b8SAndroid Build Coastguard Worker { 880*2d1272b8SAndroid Build Coastguard Worker return offsetToIndex (offset, base, array); 881*2d1272b8SAndroid Build Coastguard Worker } 882*2d1272b8SAndroid Build Coastguard Worker template <typename T> wordOffsetToIndexAAT::ObsoleteTypes883*2d1272b8SAndroid Build Coastguard Worker static unsigned int wordOffsetToIndex (unsigned int offset, 884*2d1272b8SAndroid Build Coastguard Worker const void *base, 885*2d1272b8SAndroid Build Coastguard Worker const T *array) 886*2d1272b8SAndroid Build Coastguard Worker { 887*2d1272b8SAndroid Build Coastguard Worker return offsetToIndex (2 * offset, base, array); 888*2d1272b8SAndroid Build Coastguard Worker } 889*2d1272b8SAndroid Build Coastguard Worker }; 890*2d1272b8SAndroid Build Coastguard Worker struct ExtendedTypes 891*2d1272b8SAndroid Build Coastguard Worker { 892*2d1272b8SAndroid Build Coastguard Worker static constexpr bool extended = true; 893*2d1272b8SAndroid Build Coastguard Worker typedef HBUINT32 HBUINT; 894*2d1272b8SAndroid Build Coastguard Worker typedef HBUINT16 HBUSHORT; 895*2d1272b8SAndroid Build Coastguard Worker typedef Lookup<HBUINT16> ClassTypeNarrow; 896*2d1272b8SAndroid Build Coastguard Worker typedef Lookup<HBUINT16> ClassTypeWide; 897*2d1272b8SAndroid Build Coastguard Worker 898*2d1272b8SAndroid Build Coastguard Worker template <typename T> offsetToIndexAAT::ExtendedTypes899*2d1272b8SAndroid Build Coastguard Worker static unsigned int offsetToIndex (unsigned int offset, 900*2d1272b8SAndroid Build Coastguard Worker const void *base HB_UNUSED, 901*2d1272b8SAndroid Build Coastguard Worker const T *array HB_UNUSED) 902*2d1272b8SAndroid Build Coastguard Worker { 903*2d1272b8SAndroid Build Coastguard Worker return offset; 904*2d1272b8SAndroid Build Coastguard Worker } 905*2d1272b8SAndroid Build Coastguard Worker template <typename T> byteOffsetToIndexAAT::ExtendedTypes906*2d1272b8SAndroid Build Coastguard Worker static unsigned int byteOffsetToIndex (unsigned int offset, 907*2d1272b8SAndroid Build Coastguard Worker const void *base HB_UNUSED, 908*2d1272b8SAndroid Build Coastguard Worker const T *array HB_UNUSED) 909*2d1272b8SAndroid Build Coastguard Worker { 910*2d1272b8SAndroid Build Coastguard Worker return offset / 2; 911*2d1272b8SAndroid Build Coastguard Worker } 912*2d1272b8SAndroid Build Coastguard Worker template <typename T> wordOffsetToIndexAAT::ExtendedTypes913*2d1272b8SAndroid Build Coastguard Worker static unsigned int wordOffsetToIndex (unsigned int offset, 914*2d1272b8SAndroid Build Coastguard Worker const void *base HB_UNUSED, 915*2d1272b8SAndroid Build Coastguard Worker const T *array HB_UNUSED) 916*2d1272b8SAndroid Build Coastguard Worker { 917*2d1272b8SAndroid Build Coastguard Worker return offset; 918*2d1272b8SAndroid Build Coastguard Worker } 919*2d1272b8SAndroid Build Coastguard Worker }; 920*2d1272b8SAndroid Build Coastguard Worker 921*2d1272b8SAndroid Build Coastguard Worker template <typename Types, typename EntryData> 922*2d1272b8SAndroid Build Coastguard Worker struct StateTableDriver 923*2d1272b8SAndroid Build Coastguard Worker { 924*2d1272b8SAndroid Build Coastguard Worker using StateTableT = StateTable<Types, EntryData>; 925*2d1272b8SAndroid Build Coastguard Worker using EntryT = Entry<EntryData>; 926*2d1272b8SAndroid Build Coastguard Worker StateTableDriverAAT::StateTableDriver927*2d1272b8SAndroid Build Coastguard Worker StateTableDriver (const StateTableT &machine_, 928*2d1272b8SAndroid Build Coastguard Worker hb_face_t *face_) : 929*2d1272b8SAndroid Build Coastguard Worker machine (machine_), 930*2d1272b8SAndroid Build Coastguard Worker num_glyphs (face_->get_num_glyphs ()) {} 931*2d1272b8SAndroid Build Coastguard Worker 932*2d1272b8SAndroid Build Coastguard Worker template <typename context_t> is_idempotent_on_all_out_of_boundsAAT::StateTableDriver933*2d1272b8SAndroid Build Coastguard Worker bool is_idempotent_on_all_out_of_bounds (context_t *c, hb_aat_apply_context_t *ac) 934*2d1272b8SAndroid Build Coastguard Worker { 935*2d1272b8SAndroid Build Coastguard Worker const auto entry = machine.get_entry (StateTableT::STATE_START_OF_TEXT, CLASS_OUT_OF_BOUNDS); 936*2d1272b8SAndroid Build Coastguard Worker return !c->is_actionable (ac->buffer, this, entry) && 937*2d1272b8SAndroid Build Coastguard Worker machine.new_state (entry.newState) == StateTableT::STATE_START_OF_TEXT; 938*2d1272b8SAndroid Build Coastguard Worker } 939*2d1272b8SAndroid Build Coastguard Worker 940*2d1272b8SAndroid Build Coastguard Worker template <typename context_t> driveAAT::StateTableDriver941*2d1272b8SAndroid Build Coastguard Worker void drive (context_t *c, hb_aat_apply_context_t *ac) 942*2d1272b8SAndroid Build Coastguard Worker { 943*2d1272b8SAndroid Build Coastguard Worker hb_buffer_t *buffer = ac->buffer; 944*2d1272b8SAndroid Build Coastguard Worker 945*2d1272b8SAndroid Build Coastguard Worker if (!c->in_place) 946*2d1272b8SAndroid Build Coastguard Worker buffer->clear_output (); 947*2d1272b8SAndroid Build Coastguard Worker 948*2d1272b8SAndroid Build Coastguard Worker int state = StateTableT::STATE_START_OF_TEXT; 949*2d1272b8SAndroid Build Coastguard Worker // If there's only one range, we already checked the flag. 950*2d1272b8SAndroid Build Coastguard Worker auto *last_range = ac->range_flags && (ac->range_flags->length > 1) ? &(*ac->range_flags)[0] : nullptr; 951*2d1272b8SAndroid Build Coastguard Worker for (buffer->idx = 0; buffer->successful;) 952*2d1272b8SAndroid Build Coastguard Worker { 953*2d1272b8SAndroid Build Coastguard Worker /* This block is copied in NoncontextualSubtable::apply. Keep in sync. */ 954*2d1272b8SAndroid Build Coastguard Worker if (last_range) 955*2d1272b8SAndroid Build Coastguard Worker { 956*2d1272b8SAndroid Build Coastguard Worker auto *range = last_range; 957*2d1272b8SAndroid Build Coastguard Worker if (buffer->idx < buffer->len) 958*2d1272b8SAndroid Build Coastguard Worker { 959*2d1272b8SAndroid Build Coastguard Worker unsigned cluster = buffer->cur().cluster; 960*2d1272b8SAndroid Build Coastguard Worker while (cluster < range->cluster_first) 961*2d1272b8SAndroid Build Coastguard Worker range--; 962*2d1272b8SAndroid Build Coastguard Worker while (cluster > range->cluster_last) 963*2d1272b8SAndroid Build Coastguard Worker range++; 964*2d1272b8SAndroid Build Coastguard Worker 965*2d1272b8SAndroid Build Coastguard Worker 966*2d1272b8SAndroid Build Coastguard Worker last_range = range; 967*2d1272b8SAndroid Build Coastguard Worker } 968*2d1272b8SAndroid Build Coastguard Worker if (!(range->flags & ac->subtable_flags)) 969*2d1272b8SAndroid Build Coastguard Worker { 970*2d1272b8SAndroid Build Coastguard Worker if (buffer->idx == buffer->len || unlikely (!buffer->successful)) 971*2d1272b8SAndroid Build Coastguard Worker break; 972*2d1272b8SAndroid Build Coastguard Worker 973*2d1272b8SAndroid Build Coastguard Worker state = StateTableT::STATE_START_OF_TEXT; 974*2d1272b8SAndroid Build Coastguard Worker (void) buffer->next_glyph (); 975*2d1272b8SAndroid Build Coastguard Worker continue; 976*2d1272b8SAndroid Build Coastguard Worker } 977*2d1272b8SAndroid Build Coastguard Worker } 978*2d1272b8SAndroid Build Coastguard Worker 979*2d1272b8SAndroid Build Coastguard Worker unsigned int klass = likely (buffer->idx < buffer->len) ? 980*2d1272b8SAndroid Build Coastguard Worker machine.get_class (buffer->cur().codepoint, num_glyphs, ac->machine_glyph_set) : 981*2d1272b8SAndroid Build Coastguard Worker (unsigned) CLASS_END_OF_TEXT; 982*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx); 983*2d1272b8SAndroid Build Coastguard Worker const EntryT &entry = machine.get_entry (state, klass); 984*2d1272b8SAndroid Build Coastguard Worker const int next_state = machine.new_state (entry.newState); 985*2d1272b8SAndroid Build Coastguard Worker 986*2d1272b8SAndroid Build Coastguard Worker /* Conditions under which it's guaranteed safe-to-break before current glyph: 987*2d1272b8SAndroid Build Coastguard Worker * 988*2d1272b8SAndroid Build Coastguard Worker * 1. There was no action in this transition; and 989*2d1272b8SAndroid Build Coastguard Worker * 990*2d1272b8SAndroid Build Coastguard Worker * 2. If we break before current glyph, the results will be the same. That 991*2d1272b8SAndroid Build Coastguard Worker * is guaranteed if: 992*2d1272b8SAndroid Build Coastguard Worker * 993*2d1272b8SAndroid Build Coastguard Worker * 2a. We were already in start-of-text state; or 994*2d1272b8SAndroid Build Coastguard Worker * 995*2d1272b8SAndroid Build Coastguard Worker * 2b. We are epsilon-transitioning to start-of-text state; or 996*2d1272b8SAndroid Build Coastguard Worker * 997*2d1272b8SAndroid Build Coastguard Worker * 2c. Starting from start-of-text state seeing current glyph: 998*2d1272b8SAndroid Build Coastguard Worker * 999*2d1272b8SAndroid Build Coastguard Worker * 2c'. There won't be any actions; and 1000*2d1272b8SAndroid Build Coastguard Worker * 1001*2d1272b8SAndroid Build Coastguard Worker * 2c". We would end up in the same state that we were going to end up 1002*2d1272b8SAndroid Build Coastguard Worker * in now, including whether epsilon-transitioning. 1003*2d1272b8SAndroid Build Coastguard Worker * 1004*2d1272b8SAndroid Build Coastguard Worker * and 1005*2d1272b8SAndroid Build Coastguard Worker * 1006*2d1272b8SAndroid Build Coastguard Worker * 3. If we break before current glyph, there won't be any end-of-text action 1007*2d1272b8SAndroid Build Coastguard Worker * after previous glyph. 1008*2d1272b8SAndroid Build Coastguard Worker * 1009*2d1272b8SAndroid Build Coastguard Worker * This triples the transitions we need to look up, but is worth returning 1010*2d1272b8SAndroid Build Coastguard Worker * granular unsafe-to-break results. See eg.: 1011*2d1272b8SAndroid Build Coastguard Worker * 1012*2d1272b8SAndroid Build Coastguard Worker * https://github.com/harfbuzz/harfbuzz/issues/2860 1013*2d1272b8SAndroid Build Coastguard Worker */ 1014*2d1272b8SAndroid Build Coastguard Worker 1015*2d1272b8SAndroid Build Coastguard Worker const auto is_safe_to_break_extra = [&]() 1016*2d1272b8SAndroid Build Coastguard Worker { 1017*2d1272b8SAndroid Build Coastguard Worker /* 2c. */ 1018*2d1272b8SAndroid Build Coastguard Worker const auto &wouldbe_entry = machine.get_entry(StateTableT::STATE_START_OF_TEXT, klass); 1019*2d1272b8SAndroid Build Coastguard Worker 1020*2d1272b8SAndroid Build Coastguard Worker /* 2c'. */ 1021*2d1272b8SAndroid Build Coastguard Worker if (c->is_actionable (buffer, this, wouldbe_entry)) 1022*2d1272b8SAndroid Build Coastguard Worker return false; 1023*2d1272b8SAndroid Build Coastguard Worker 1024*2d1272b8SAndroid Build Coastguard Worker /* 2c". */ 1025*2d1272b8SAndroid Build Coastguard Worker return next_state == machine.new_state(wouldbe_entry.newState) 1026*2d1272b8SAndroid Build Coastguard Worker && (entry.flags & context_t::DontAdvance) == (wouldbe_entry.flags & context_t::DontAdvance); 1027*2d1272b8SAndroid Build Coastguard Worker }; 1028*2d1272b8SAndroid Build Coastguard Worker 1029*2d1272b8SAndroid Build Coastguard Worker const auto is_safe_to_break = [&]() 1030*2d1272b8SAndroid Build Coastguard Worker { 1031*2d1272b8SAndroid Build Coastguard Worker /* 1. */ 1032*2d1272b8SAndroid Build Coastguard Worker if (c->is_actionable (buffer, this, entry)) 1033*2d1272b8SAndroid Build Coastguard Worker return false; 1034*2d1272b8SAndroid Build Coastguard Worker 1035*2d1272b8SAndroid Build Coastguard Worker /* 2. */ 1036*2d1272b8SAndroid Build Coastguard Worker // This one is meh, I know... 1037*2d1272b8SAndroid Build Coastguard Worker const auto ok = 1038*2d1272b8SAndroid Build Coastguard Worker state == StateTableT::STATE_START_OF_TEXT 1039*2d1272b8SAndroid Build Coastguard Worker || ((entry.flags & context_t::DontAdvance) && next_state == StateTableT::STATE_START_OF_TEXT) 1040*2d1272b8SAndroid Build Coastguard Worker || is_safe_to_break_extra(); 1041*2d1272b8SAndroid Build Coastguard Worker if (!ok) 1042*2d1272b8SAndroid Build Coastguard Worker return false; 1043*2d1272b8SAndroid Build Coastguard Worker 1044*2d1272b8SAndroid Build Coastguard Worker /* 3. */ 1045*2d1272b8SAndroid Build Coastguard Worker return !c->is_actionable (buffer, this, machine.get_entry (state, CLASS_END_OF_TEXT)); 1046*2d1272b8SAndroid Build Coastguard Worker }; 1047*2d1272b8SAndroid Build Coastguard Worker 1048*2d1272b8SAndroid Build Coastguard Worker if (!is_safe_to_break () && buffer->backtrack_len () && buffer->idx < buffer->len) 1049*2d1272b8SAndroid Build Coastguard Worker buffer->unsafe_to_break_from_outbuffer (buffer->backtrack_len () - 1, buffer->idx + 1); 1050*2d1272b8SAndroid Build Coastguard Worker 1051*2d1272b8SAndroid Build Coastguard Worker c->transition (buffer, this, entry); 1052*2d1272b8SAndroid Build Coastguard Worker 1053*2d1272b8SAndroid Build Coastguard Worker state = next_state; 1054*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG (APPLY, nullptr, "s%d", state); 1055*2d1272b8SAndroid Build Coastguard Worker 1056*2d1272b8SAndroid Build Coastguard Worker if (buffer->idx == buffer->len || unlikely (!buffer->successful)) 1057*2d1272b8SAndroid Build Coastguard Worker break; 1058*2d1272b8SAndroid Build Coastguard Worker 1059*2d1272b8SAndroid Build Coastguard Worker if (!(entry.flags & context_t::DontAdvance) || buffer->max_ops-- <= 0) 1060*2d1272b8SAndroid Build Coastguard Worker (void) buffer->next_glyph (); 1061*2d1272b8SAndroid Build Coastguard Worker } 1062*2d1272b8SAndroid Build Coastguard Worker 1063*2d1272b8SAndroid Build Coastguard Worker if (!c->in_place) 1064*2d1272b8SAndroid Build Coastguard Worker buffer->sync (); 1065*2d1272b8SAndroid Build Coastguard Worker } 1066*2d1272b8SAndroid Build Coastguard Worker 1067*2d1272b8SAndroid Build Coastguard Worker public: 1068*2d1272b8SAndroid Build Coastguard Worker const StateTableT &machine; 1069*2d1272b8SAndroid Build Coastguard Worker unsigned int num_glyphs; 1070*2d1272b8SAndroid Build Coastguard Worker }; 1071*2d1272b8SAndroid Build Coastguard Worker 1072*2d1272b8SAndroid Build Coastguard Worker 1073*2d1272b8SAndroid Build Coastguard Worker } /* namespace AAT */ 1074*2d1272b8SAndroid Build Coastguard Worker 1075*2d1272b8SAndroid Build Coastguard Worker 1076*2d1272b8SAndroid Build Coastguard Worker #endif /* HB_AAT_LAYOUT_COMMON_HH */ 1077