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_MORX_TABLE_HH 28*2d1272b8SAndroid Build Coastguard Worker #define HB_AAT_LAYOUT_MORX_TABLE_HH 29*2d1272b8SAndroid Build Coastguard Worker 30*2d1272b8SAndroid Build Coastguard Worker #include "hb-open-type.hh" 31*2d1272b8SAndroid Build Coastguard Worker #include "hb-aat-layout-common.hh" 32*2d1272b8SAndroid Build Coastguard Worker #include "hb-ot-layout-common.hh" 33*2d1272b8SAndroid Build Coastguard Worker #include "hb-ot-layout-gdef-table.hh" 34*2d1272b8SAndroid Build Coastguard Worker #include "hb-aat-map.hh" 35*2d1272b8SAndroid Build Coastguard Worker 36*2d1272b8SAndroid Build Coastguard Worker /* 37*2d1272b8SAndroid Build Coastguard Worker * morx -- Extended Glyph Metamorphosis 38*2d1272b8SAndroid Build Coastguard Worker * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6morx.html 39*2d1272b8SAndroid Build Coastguard Worker * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6mort.html 40*2d1272b8SAndroid Build Coastguard Worker */ 41*2d1272b8SAndroid Build Coastguard Worker #define HB_AAT_TAG_morx HB_TAG('m','o','r','x') 42*2d1272b8SAndroid Build Coastguard Worker #define HB_AAT_TAG_mort HB_TAG('m','o','r','t') 43*2d1272b8SAndroid Build Coastguard Worker 44*2d1272b8SAndroid Build Coastguard Worker 45*2d1272b8SAndroid Build Coastguard Worker namespace AAT { 46*2d1272b8SAndroid Build Coastguard Worker 47*2d1272b8SAndroid Build Coastguard Worker using namespace OT; 48*2d1272b8SAndroid Build Coastguard Worker 49*2d1272b8SAndroid Build Coastguard Worker template <typename Types> 50*2d1272b8SAndroid Build Coastguard Worker struct RearrangementSubtable 51*2d1272b8SAndroid Build Coastguard Worker { 52*2d1272b8SAndroid Build Coastguard Worker typedef typename Types::HBUINT HBUINT; 53*2d1272b8SAndroid Build Coastguard Worker 54*2d1272b8SAndroid Build Coastguard Worker typedef void EntryData; 55*2d1272b8SAndroid Build Coastguard Worker 56*2d1272b8SAndroid Build Coastguard Worker struct driver_context_t 57*2d1272b8SAndroid Build Coastguard Worker { 58*2d1272b8SAndroid Build Coastguard Worker static constexpr bool in_place = true; 59*2d1272b8SAndroid Build Coastguard Worker enum Flags 60*2d1272b8SAndroid Build Coastguard Worker { 61*2d1272b8SAndroid Build Coastguard Worker MarkFirst = 0x8000, /* If set, make the current glyph the first 62*2d1272b8SAndroid Build Coastguard Worker * glyph to be rearranged. */ 63*2d1272b8SAndroid Build Coastguard Worker DontAdvance = 0x4000, /* If set, don't advance to the next glyph 64*2d1272b8SAndroid Build Coastguard Worker * before going to the new state. This means 65*2d1272b8SAndroid Build Coastguard Worker * that the glyph index doesn't change, even 66*2d1272b8SAndroid Build Coastguard Worker * if the glyph at that index has changed. */ 67*2d1272b8SAndroid Build Coastguard Worker MarkLast = 0x2000, /* If set, make the current glyph the last 68*2d1272b8SAndroid Build Coastguard Worker * glyph to be rearranged. */ 69*2d1272b8SAndroid Build Coastguard Worker Reserved = 0x1FF0, /* These bits are reserved and should be set to 0. */ 70*2d1272b8SAndroid Build Coastguard Worker Verb = 0x000F, /* The type of rearrangement specified. */ 71*2d1272b8SAndroid Build Coastguard Worker }; 72*2d1272b8SAndroid Build Coastguard Worker driver_context_tAAT::RearrangementSubtable::driver_context_t73*2d1272b8SAndroid Build Coastguard Worker driver_context_t (const RearrangementSubtable *table HB_UNUSED) : 74*2d1272b8SAndroid Build Coastguard Worker ret (false), 75*2d1272b8SAndroid Build Coastguard Worker start (0), end (0) {} 76*2d1272b8SAndroid Build Coastguard Worker is_actionableAAT::RearrangementSubtable::driver_context_t77*2d1272b8SAndroid Build Coastguard Worker bool is_actionable (hb_buffer_t *buffer HB_UNUSED, 78*2d1272b8SAndroid Build Coastguard Worker StateTableDriver<Types, EntryData> *driver HB_UNUSED, 79*2d1272b8SAndroid Build Coastguard Worker const Entry<EntryData> &entry) const 80*2d1272b8SAndroid Build Coastguard Worker { 81*2d1272b8SAndroid Build Coastguard Worker return (entry.flags & Verb) && start < end; 82*2d1272b8SAndroid Build Coastguard Worker } transitionAAT::RearrangementSubtable::driver_context_t83*2d1272b8SAndroid Build Coastguard Worker void transition (hb_buffer_t *buffer, 84*2d1272b8SAndroid Build Coastguard Worker StateTableDriver<Types, EntryData> *driver, 85*2d1272b8SAndroid Build Coastguard Worker const Entry<EntryData> &entry) 86*2d1272b8SAndroid Build Coastguard Worker { 87*2d1272b8SAndroid Build Coastguard Worker unsigned int flags = entry.flags; 88*2d1272b8SAndroid Build Coastguard Worker 89*2d1272b8SAndroid Build Coastguard Worker if (flags & MarkFirst) 90*2d1272b8SAndroid Build Coastguard Worker start = buffer->idx; 91*2d1272b8SAndroid Build Coastguard Worker 92*2d1272b8SAndroid Build Coastguard Worker if (flags & MarkLast) 93*2d1272b8SAndroid Build Coastguard Worker end = hb_min (buffer->idx + 1, buffer->len); 94*2d1272b8SAndroid Build Coastguard Worker 95*2d1272b8SAndroid Build Coastguard Worker if ((flags & Verb) && start < end) 96*2d1272b8SAndroid Build Coastguard Worker { 97*2d1272b8SAndroid Build Coastguard Worker /* The following map has two nibbles, for start-side 98*2d1272b8SAndroid Build Coastguard Worker * and end-side. Values of 0,1,2 mean move that many 99*2d1272b8SAndroid Build Coastguard Worker * to the other side. Value of 3 means move 2 and 100*2d1272b8SAndroid Build Coastguard Worker * flip them. */ 101*2d1272b8SAndroid Build Coastguard Worker const unsigned char map[16] = 102*2d1272b8SAndroid Build Coastguard Worker { 103*2d1272b8SAndroid Build Coastguard Worker 0x00, /* 0 no change */ 104*2d1272b8SAndroid Build Coastguard Worker 0x10, /* 1 Ax => xA */ 105*2d1272b8SAndroid Build Coastguard Worker 0x01, /* 2 xD => Dx */ 106*2d1272b8SAndroid Build Coastguard Worker 0x11, /* 3 AxD => DxA */ 107*2d1272b8SAndroid Build Coastguard Worker 0x20, /* 4 ABx => xAB */ 108*2d1272b8SAndroid Build Coastguard Worker 0x30, /* 5 ABx => xBA */ 109*2d1272b8SAndroid Build Coastguard Worker 0x02, /* 6 xCD => CDx */ 110*2d1272b8SAndroid Build Coastguard Worker 0x03, /* 7 xCD => DCx */ 111*2d1272b8SAndroid Build Coastguard Worker 0x12, /* 8 AxCD => CDxA */ 112*2d1272b8SAndroid Build Coastguard Worker 0x13, /* 9 AxCD => DCxA */ 113*2d1272b8SAndroid Build Coastguard Worker 0x21, /* 10 ABxD => DxAB */ 114*2d1272b8SAndroid Build Coastguard Worker 0x31, /* 11 ABxD => DxBA */ 115*2d1272b8SAndroid Build Coastguard Worker 0x22, /* 12 ABxCD => CDxAB */ 116*2d1272b8SAndroid Build Coastguard Worker 0x32, /* 13 ABxCD => CDxBA */ 117*2d1272b8SAndroid Build Coastguard Worker 0x23, /* 14 ABxCD => DCxAB */ 118*2d1272b8SAndroid Build Coastguard Worker 0x33, /* 15 ABxCD => DCxBA */ 119*2d1272b8SAndroid Build Coastguard Worker }; 120*2d1272b8SAndroid Build Coastguard Worker 121*2d1272b8SAndroid Build Coastguard Worker unsigned int m = map[flags & Verb]; 122*2d1272b8SAndroid Build Coastguard Worker unsigned int l = hb_min (2u, m >> 4); 123*2d1272b8SAndroid Build Coastguard Worker unsigned int r = hb_min (2u, m & 0x0F); 124*2d1272b8SAndroid Build Coastguard Worker bool reverse_l = 3 == (m >> 4); 125*2d1272b8SAndroid Build Coastguard Worker bool reverse_r = 3 == (m & 0x0F); 126*2d1272b8SAndroid Build Coastguard Worker 127*2d1272b8SAndroid Build Coastguard Worker if (end - start >= l + r && end-start <= HB_MAX_CONTEXT_LENGTH) 128*2d1272b8SAndroid Build Coastguard Worker { 129*2d1272b8SAndroid Build Coastguard Worker buffer->merge_clusters (start, hb_min (buffer->idx + 1, buffer->len)); 130*2d1272b8SAndroid Build Coastguard Worker buffer->merge_clusters (start, end); 131*2d1272b8SAndroid Build Coastguard Worker 132*2d1272b8SAndroid Build Coastguard Worker hb_glyph_info_t *info = buffer->info; 133*2d1272b8SAndroid Build Coastguard Worker hb_glyph_info_t buf[4]; 134*2d1272b8SAndroid Build Coastguard Worker 135*2d1272b8SAndroid Build Coastguard Worker hb_memcpy (buf, info + start, l * sizeof (buf[0])); 136*2d1272b8SAndroid Build Coastguard Worker hb_memcpy (buf + 2, info + end - r, r * sizeof (buf[0])); 137*2d1272b8SAndroid Build Coastguard Worker 138*2d1272b8SAndroid Build Coastguard Worker if (l != r) 139*2d1272b8SAndroid Build Coastguard Worker memmove (info + start + r, info + start + l, (end - start - l - r) * sizeof (buf[0])); 140*2d1272b8SAndroid Build Coastguard Worker 141*2d1272b8SAndroid Build Coastguard Worker hb_memcpy (info + start, buf + 2, r * sizeof (buf[0])); 142*2d1272b8SAndroid Build Coastguard Worker hb_memcpy (info + end - l, buf, l * sizeof (buf[0])); 143*2d1272b8SAndroid Build Coastguard Worker if (reverse_l) 144*2d1272b8SAndroid Build Coastguard Worker { 145*2d1272b8SAndroid Build Coastguard Worker buf[0] = info[end - 1]; 146*2d1272b8SAndroid Build Coastguard Worker info[end - 1] = info[end - 2]; 147*2d1272b8SAndroid Build Coastguard Worker info[end - 2] = buf[0]; 148*2d1272b8SAndroid Build Coastguard Worker } 149*2d1272b8SAndroid Build Coastguard Worker if (reverse_r) 150*2d1272b8SAndroid Build Coastguard Worker { 151*2d1272b8SAndroid Build Coastguard Worker buf[0] = info[start]; 152*2d1272b8SAndroid Build Coastguard Worker info[start] = info[start + 1]; 153*2d1272b8SAndroid Build Coastguard Worker info[start + 1] = buf[0]; 154*2d1272b8SAndroid Build Coastguard Worker } 155*2d1272b8SAndroid Build Coastguard Worker } 156*2d1272b8SAndroid Build Coastguard Worker } 157*2d1272b8SAndroid Build Coastguard Worker } 158*2d1272b8SAndroid Build Coastguard Worker 159*2d1272b8SAndroid Build Coastguard Worker public: 160*2d1272b8SAndroid Build Coastguard Worker bool ret; 161*2d1272b8SAndroid Build Coastguard Worker private: 162*2d1272b8SAndroid Build Coastguard Worker unsigned int start; 163*2d1272b8SAndroid Build Coastguard Worker unsigned int end; 164*2d1272b8SAndroid Build Coastguard Worker }; 165*2d1272b8SAndroid Build Coastguard Worker applyAAT::RearrangementSubtable166*2d1272b8SAndroid Build Coastguard Worker bool apply (hb_aat_apply_context_t *c) const 167*2d1272b8SAndroid Build Coastguard Worker { 168*2d1272b8SAndroid Build Coastguard Worker TRACE_APPLY (this); 169*2d1272b8SAndroid Build Coastguard Worker 170*2d1272b8SAndroid Build Coastguard Worker driver_context_t dc (this); 171*2d1272b8SAndroid Build Coastguard Worker 172*2d1272b8SAndroid Build Coastguard Worker StateTableDriver<Types, EntryData> driver (machine, c->face); 173*2d1272b8SAndroid Build Coastguard Worker 174*2d1272b8SAndroid Build Coastguard Worker if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) && 175*2d1272b8SAndroid Build Coastguard Worker !c->buffer_digest.may_have (c->machine_glyph_set)) 176*2d1272b8SAndroid Build Coastguard Worker return_trace (false); 177*2d1272b8SAndroid Build Coastguard Worker 178*2d1272b8SAndroid Build Coastguard Worker driver.drive (&dc, c); 179*2d1272b8SAndroid Build Coastguard Worker 180*2d1272b8SAndroid Build Coastguard Worker return_trace (dc.ret); 181*2d1272b8SAndroid Build Coastguard Worker } 182*2d1272b8SAndroid Build Coastguard Worker sanitizeAAT::RearrangementSubtable183*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c) const 184*2d1272b8SAndroid Build Coastguard Worker { 185*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 186*2d1272b8SAndroid Build Coastguard Worker return_trace (machine.sanitize (c)); 187*2d1272b8SAndroid Build Coastguard Worker } 188*2d1272b8SAndroid Build Coastguard Worker 189*2d1272b8SAndroid Build Coastguard Worker public: 190*2d1272b8SAndroid Build Coastguard Worker StateTable<Types, EntryData> machine; 191*2d1272b8SAndroid Build Coastguard Worker public: 192*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size)); 193*2d1272b8SAndroid Build Coastguard Worker }; 194*2d1272b8SAndroid Build Coastguard Worker 195*2d1272b8SAndroid Build Coastguard Worker template <typename Types> 196*2d1272b8SAndroid Build Coastguard Worker struct ContextualSubtable 197*2d1272b8SAndroid Build Coastguard Worker { 198*2d1272b8SAndroid Build Coastguard Worker typedef typename Types::HBUINT HBUINT; 199*2d1272b8SAndroid Build Coastguard Worker 200*2d1272b8SAndroid Build Coastguard Worker struct EntryData 201*2d1272b8SAndroid Build Coastguard Worker { 202*2d1272b8SAndroid Build Coastguard Worker HBUINT16 markIndex; /* Index of the substitution table for the 203*2d1272b8SAndroid Build Coastguard Worker * marked glyph (use 0xFFFF for none). */ 204*2d1272b8SAndroid Build Coastguard Worker HBUINT16 currentIndex; /* Index of the substitution table for the 205*2d1272b8SAndroid Build Coastguard Worker * current glyph (use 0xFFFF for none). */ 206*2d1272b8SAndroid Build Coastguard Worker public: 207*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_STATIC (4); 208*2d1272b8SAndroid Build Coastguard Worker }; 209*2d1272b8SAndroid Build Coastguard Worker 210*2d1272b8SAndroid Build Coastguard Worker struct driver_context_t 211*2d1272b8SAndroid Build Coastguard Worker { 212*2d1272b8SAndroid Build Coastguard Worker static constexpr bool in_place = true; 213*2d1272b8SAndroid Build Coastguard Worker enum Flags 214*2d1272b8SAndroid Build Coastguard Worker { 215*2d1272b8SAndroid Build Coastguard Worker SetMark = 0x8000, /* If set, make the current glyph the marked glyph. */ 216*2d1272b8SAndroid Build Coastguard Worker DontAdvance = 0x4000, /* If set, don't advance to the next glyph before 217*2d1272b8SAndroid Build Coastguard Worker * going to the new state. */ 218*2d1272b8SAndroid Build Coastguard Worker Reserved = 0x3FFF, /* These bits are reserved and should be set to 0. */ 219*2d1272b8SAndroid Build Coastguard Worker }; 220*2d1272b8SAndroid Build Coastguard Worker driver_context_tAAT::ContextualSubtable::driver_context_t221*2d1272b8SAndroid Build Coastguard Worker driver_context_t (const ContextualSubtable *table_, 222*2d1272b8SAndroid Build Coastguard Worker hb_aat_apply_context_t *c_) : 223*2d1272b8SAndroid Build Coastguard Worker ret (false), 224*2d1272b8SAndroid Build Coastguard Worker c (c_), 225*2d1272b8SAndroid Build Coastguard Worker gdef (*c->gdef_table), 226*2d1272b8SAndroid Build Coastguard Worker mark_set (false), 227*2d1272b8SAndroid Build Coastguard Worker has_glyph_classes (gdef.has_glyph_classes ()), 228*2d1272b8SAndroid Build Coastguard Worker mark (0), 229*2d1272b8SAndroid Build Coastguard Worker table (table_), 230*2d1272b8SAndroid Build Coastguard Worker subs (table+table->substitutionTables) {} 231*2d1272b8SAndroid Build Coastguard Worker is_actionableAAT::ContextualSubtable::driver_context_t232*2d1272b8SAndroid Build Coastguard Worker bool is_actionable (hb_buffer_t *buffer, 233*2d1272b8SAndroid Build Coastguard Worker StateTableDriver<Types, EntryData> *driver, 234*2d1272b8SAndroid Build Coastguard Worker const Entry<EntryData> &entry) const 235*2d1272b8SAndroid Build Coastguard Worker { 236*2d1272b8SAndroid Build Coastguard Worker if (buffer->idx == buffer->len && !mark_set) 237*2d1272b8SAndroid Build Coastguard Worker return false; 238*2d1272b8SAndroid Build Coastguard Worker 239*2d1272b8SAndroid Build Coastguard Worker return entry.data.markIndex != 0xFFFF || entry.data.currentIndex != 0xFFFF; 240*2d1272b8SAndroid Build Coastguard Worker } transitionAAT::ContextualSubtable::driver_context_t241*2d1272b8SAndroid Build Coastguard Worker void transition (hb_buffer_t *buffer, 242*2d1272b8SAndroid Build Coastguard Worker StateTableDriver<Types, EntryData> *driver, 243*2d1272b8SAndroid Build Coastguard Worker const Entry<EntryData> &entry) 244*2d1272b8SAndroid Build Coastguard Worker { 245*2d1272b8SAndroid Build Coastguard Worker /* Looks like CoreText applies neither mark nor current substitution for 246*2d1272b8SAndroid Build Coastguard Worker * end-of-text if mark was not explicitly set. */ 247*2d1272b8SAndroid Build Coastguard Worker if (buffer->idx == buffer->len && !mark_set) 248*2d1272b8SAndroid Build Coastguard Worker return; 249*2d1272b8SAndroid Build Coastguard Worker 250*2d1272b8SAndroid Build Coastguard Worker const HBGlyphID16 *replacement; 251*2d1272b8SAndroid Build Coastguard Worker 252*2d1272b8SAndroid Build Coastguard Worker replacement = nullptr; 253*2d1272b8SAndroid Build Coastguard Worker if (Types::extended) 254*2d1272b8SAndroid Build Coastguard Worker { 255*2d1272b8SAndroid Build Coastguard Worker if (entry.data.markIndex != 0xFFFF) 256*2d1272b8SAndroid Build Coastguard Worker { 257*2d1272b8SAndroid Build Coastguard Worker const Lookup<HBGlyphID16> &lookup = subs[entry.data.markIndex]; 258*2d1272b8SAndroid Build Coastguard Worker replacement = lookup.get_value (buffer->info[mark].codepoint, driver->num_glyphs); 259*2d1272b8SAndroid Build Coastguard Worker } 260*2d1272b8SAndroid Build Coastguard Worker } 261*2d1272b8SAndroid Build Coastguard Worker else 262*2d1272b8SAndroid Build Coastguard Worker { 263*2d1272b8SAndroid Build Coastguard Worker unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint; 264*2d1272b8SAndroid Build Coastguard Worker const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs; 265*2d1272b8SAndroid Build Coastguard Worker replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)]; 266*2d1272b8SAndroid Build Coastguard Worker if (!(replacement->sanitize (&c->sanitizer) && 267*2d1272b8SAndroid Build Coastguard Worker hb_barrier () && 268*2d1272b8SAndroid Build Coastguard Worker *replacement)) 269*2d1272b8SAndroid Build Coastguard Worker replacement = nullptr; 270*2d1272b8SAndroid Build Coastguard Worker } 271*2d1272b8SAndroid Build Coastguard Worker if (replacement) 272*2d1272b8SAndroid Build Coastguard Worker { 273*2d1272b8SAndroid Build Coastguard Worker buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len)); 274*2d1272b8SAndroid Build Coastguard Worker buffer->info[mark].codepoint = *replacement; 275*2d1272b8SAndroid Build Coastguard Worker c->buffer_digest.add (*replacement); 276*2d1272b8SAndroid Build Coastguard Worker if (has_glyph_classes) 277*2d1272b8SAndroid Build Coastguard Worker _hb_glyph_info_set_glyph_props (&buffer->info[mark], 278*2d1272b8SAndroid Build Coastguard Worker gdef.get_glyph_props (*replacement)); 279*2d1272b8SAndroid Build Coastguard Worker ret = true; 280*2d1272b8SAndroid Build Coastguard Worker } 281*2d1272b8SAndroid Build Coastguard Worker 282*2d1272b8SAndroid Build Coastguard Worker replacement = nullptr; 283*2d1272b8SAndroid Build Coastguard Worker unsigned int idx = hb_min (buffer->idx, buffer->len - 1); 284*2d1272b8SAndroid Build Coastguard Worker if (Types::extended) 285*2d1272b8SAndroid Build Coastguard Worker { 286*2d1272b8SAndroid Build Coastguard Worker if (entry.data.currentIndex != 0xFFFF) 287*2d1272b8SAndroid Build Coastguard Worker { 288*2d1272b8SAndroid Build Coastguard Worker const Lookup<HBGlyphID16> &lookup = subs[entry.data.currentIndex]; 289*2d1272b8SAndroid Build Coastguard Worker replacement = lookup.get_value (buffer->info[idx].codepoint, driver->num_glyphs); 290*2d1272b8SAndroid Build Coastguard Worker } 291*2d1272b8SAndroid Build Coastguard Worker } 292*2d1272b8SAndroid Build Coastguard Worker else 293*2d1272b8SAndroid Build Coastguard Worker { 294*2d1272b8SAndroid Build Coastguard Worker unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint; 295*2d1272b8SAndroid Build Coastguard Worker const UnsizedArrayOf<HBGlyphID16> &subs_old = (const UnsizedArrayOf<HBGlyphID16> &) subs; 296*2d1272b8SAndroid Build Coastguard Worker replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)]; 297*2d1272b8SAndroid Build Coastguard Worker if (!(replacement->sanitize (&c->sanitizer) && 298*2d1272b8SAndroid Build Coastguard Worker hb_barrier () && 299*2d1272b8SAndroid Build Coastguard Worker *replacement)) 300*2d1272b8SAndroid Build Coastguard Worker replacement = nullptr; 301*2d1272b8SAndroid Build Coastguard Worker } 302*2d1272b8SAndroid Build Coastguard Worker if (replacement) 303*2d1272b8SAndroid Build Coastguard Worker { 304*2d1272b8SAndroid Build Coastguard Worker buffer->info[idx].codepoint = *replacement; 305*2d1272b8SAndroid Build Coastguard Worker c->buffer_digest.add (*replacement); 306*2d1272b8SAndroid Build Coastguard Worker if (has_glyph_classes) 307*2d1272b8SAndroid Build Coastguard Worker _hb_glyph_info_set_glyph_props (&buffer->info[idx], 308*2d1272b8SAndroid Build Coastguard Worker gdef.get_glyph_props (*replacement)); 309*2d1272b8SAndroid Build Coastguard Worker ret = true; 310*2d1272b8SAndroid Build Coastguard Worker } 311*2d1272b8SAndroid Build Coastguard Worker 312*2d1272b8SAndroid Build Coastguard Worker if (entry.flags & SetMark) 313*2d1272b8SAndroid Build Coastguard Worker { 314*2d1272b8SAndroid Build Coastguard Worker mark_set = true; 315*2d1272b8SAndroid Build Coastguard Worker mark = buffer->idx; 316*2d1272b8SAndroid Build Coastguard Worker } 317*2d1272b8SAndroid Build Coastguard Worker } 318*2d1272b8SAndroid Build Coastguard Worker 319*2d1272b8SAndroid Build Coastguard Worker public: 320*2d1272b8SAndroid Build Coastguard Worker bool ret; 321*2d1272b8SAndroid Build Coastguard Worker private: 322*2d1272b8SAndroid Build Coastguard Worker hb_aat_apply_context_t *c; 323*2d1272b8SAndroid Build Coastguard Worker const OT::GDEF &gdef; 324*2d1272b8SAndroid Build Coastguard Worker bool mark_set; 325*2d1272b8SAndroid Build Coastguard Worker bool has_glyph_classes; 326*2d1272b8SAndroid Build Coastguard Worker unsigned int mark; 327*2d1272b8SAndroid Build Coastguard Worker const ContextualSubtable *table; 328*2d1272b8SAndroid Build Coastguard Worker const UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, void, false> &subs; 329*2d1272b8SAndroid Build Coastguard Worker }; 330*2d1272b8SAndroid Build Coastguard Worker applyAAT::ContextualSubtable331*2d1272b8SAndroid Build Coastguard Worker bool apply (hb_aat_apply_context_t *c) const 332*2d1272b8SAndroid Build Coastguard Worker { 333*2d1272b8SAndroid Build Coastguard Worker TRACE_APPLY (this); 334*2d1272b8SAndroid Build Coastguard Worker 335*2d1272b8SAndroid Build Coastguard Worker driver_context_t dc (this, c); 336*2d1272b8SAndroid Build Coastguard Worker 337*2d1272b8SAndroid Build Coastguard Worker StateTableDriver<Types, EntryData> driver (machine, c->face); 338*2d1272b8SAndroid Build Coastguard Worker 339*2d1272b8SAndroid Build Coastguard Worker if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) && 340*2d1272b8SAndroid Build Coastguard Worker !c->buffer_digest.may_have (c->machine_glyph_set)) 341*2d1272b8SAndroid Build Coastguard Worker return_trace (false); 342*2d1272b8SAndroid Build Coastguard Worker 343*2d1272b8SAndroid Build Coastguard Worker driver.drive (&dc, c); 344*2d1272b8SAndroid Build Coastguard Worker 345*2d1272b8SAndroid Build Coastguard Worker return_trace (dc.ret); 346*2d1272b8SAndroid Build Coastguard Worker } 347*2d1272b8SAndroid Build Coastguard Worker sanitizeAAT::ContextualSubtable348*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 352*2d1272b8SAndroid Build Coastguard Worker unsigned int num_entries = 0; 353*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!machine.sanitize (c, &num_entries))) return_trace (false); 354*2d1272b8SAndroid Build Coastguard Worker hb_barrier (); 355*2d1272b8SAndroid Build Coastguard Worker 356*2d1272b8SAndroid Build Coastguard Worker if (!Types::extended) 357*2d1272b8SAndroid Build Coastguard Worker return_trace (substitutionTables.sanitize (c, this, 0)); 358*2d1272b8SAndroid Build Coastguard Worker 359*2d1272b8SAndroid Build Coastguard Worker unsigned int num_lookups = 0; 360*2d1272b8SAndroid Build Coastguard Worker 361*2d1272b8SAndroid Build Coastguard Worker const Entry<EntryData> *entries = machine.get_entries (); 362*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < num_entries; i++) 363*2d1272b8SAndroid Build Coastguard Worker { 364*2d1272b8SAndroid Build Coastguard Worker const EntryData &data = entries[i].data; 365*2d1272b8SAndroid Build Coastguard Worker 366*2d1272b8SAndroid Build Coastguard Worker if (data.markIndex != 0xFFFF) 367*2d1272b8SAndroid Build Coastguard Worker num_lookups = hb_max (num_lookups, 1u + data.markIndex); 368*2d1272b8SAndroid Build Coastguard Worker if (data.currentIndex != 0xFFFF) 369*2d1272b8SAndroid Build Coastguard Worker num_lookups = hb_max (num_lookups, 1u + data.currentIndex); 370*2d1272b8SAndroid Build Coastguard Worker } 371*2d1272b8SAndroid Build Coastguard Worker 372*2d1272b8SAndroid Build Coastguard Worker return_trace (substitutionTables.sanitize (c, this, num_lookups)); 373*2d1272b8SAndroid Build Coastguard Worker } 374*2d1272b8SAndroid Build Coastguard Worker 375*2d1272b8SAndroid Build Coastguard Worker public: 376*2d1272b8SAndroid Build Coastguard Worker StateTable<Types, EntryData> 377*2d1272b8SAndroid Build Coastguard Worker machine; 378*2d1272b8SAndroid Build Coastguard Worker protected: 379*2d1272b8SAndroid Build Coastguard Worker NNOffsetTo<UnsizedListOfOffset16To<Lookup<HBGlyphID16>, HBUINT, void, false>, HBUINT> 380*2d1272b8SAndroid Build Coastguard Worker substitutionTables; 381*2d1272b8SAndroid Build Coastguard Worker public: 382*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size + HBUINT::static_size)); 383*2d1272b8SAndroid Build Coastguard Worker }; 384*2d1272b8SAndroid Build Coastguard Worker 385*2d1272b8SAndroid Build Coastguard Worker 386*2d1272b8SAndroid Build Coastguard Worker template <bool extended> 387*2d1272b8SAndroid Build Coastguard Worker struct LigatureEntry; 388*2d1272b8SAndroid Build Coastguard Worker 389*2d1272b8SAndroid Build Coastguard Worker template <> 390*2d1272b8SAndroid Build Coastguard Worker struct LigatureEntry<true> 391*2d1272b8SAndroid Build Coastguard Worker { 392*2d1272b8SAndroid Build Coastguard Worker enum Flags 393*2d1272b8SAndroid Build Coastguard Worker { 394*2d1272b8SAndroid Build Coastguard Worker SetComponent = 0x8000, /* Push this glyph onto the component stack for 395*2d1272b8SAndroid Build Coastguard Worker * eventual processing. */ 396*2d1272b8SAndroid Build Coastguard Worker DontAdvance = 0x4000, /* Leave the glyph pointer at this glyph for the 397*2d1272b8SAndroid Build Coastguard Worker next iteration. */ 398*2d1272b8SAndroid Build Coastguard Worker PerformAction = 0x2000, /* Use the ligActionIndex to process a ligature 399*2d1272b8SAndroid Build Coastguard Worker * group. */ 400*2d1272b8SAndroid Build Coastguard Worker Reserved = 0x1FFF, /* These bits are reserved and should be set to 0. */ 401*2d1272b8SAndroid Build Coastguard Worker }; 402*2d1272b8SAndroid Build Coastguard Worker 403*2d1272b8SAndroid Build Coastguard Worker struct EntryData 404*2d1272b8SAndroid Build Coastguard Worker { 405*2d1272b8SAndroid Build Coastguard Worker HBUINT16 ligActionIndex; /* Index to the first ligActionTable entry 406*2d1272b8SAndroid Build Coastguard Worker * for processing this group, if indicated 407*2d1272b8SAndroid Build Coastguard Worker * by the flags. */ 408*2d1272b8SAndroid Build Coastguard Worker public: 409*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_STATIC (2); 410*2d1272b8SAndroid Build Coastguard Worker }; 411*2d1272b8SAndroid Build Coastguard Worker performActionAAT::LigatureEntry412*2d1272b8SAndroid Build Coastguard Worker static bool performAction (const Entry<EntryData> &entry) 413*2d1272b8SAndroid Build Coastguard Worker { return entry.flags & PerformAction; } 414*2d1272b8SAndroid Build Coastguard Worker ligActionIndexAAT::LigatureEntry415*2d1272b8SAndroid Build Coastguard Worker static unsigned int ligActionIndex (const Entry<EntryData> &entry) 416*2d1272b8SAndroid Build Coastguard Worker { return entry.data.ligActionIndex; } 417*2d1272b8SAndroid Build Coastguard Worker }; 418*2d1272b8SAndroid Build Coastguard Worker template <> 419*2d1272b8SAndroid Build Coastguard Worker struct LigatureEntry<false> 420*2d1272b8SAndroid Build Coastguard Worker { 421*2d1272b8SAndroid Build Coastguard Worker enum Flags 422*2d1272b8SAndroid Build Coastguard Worker { 423*2d1272b8SAndroid Build Coastguard Worker SetComponent = 0x8000, /* Push this glyph onto the component stack for 424*2d1272b8SAndroid Build Coastguard Worker * eventual processing. */ 425*2d1272b8SAndroid Build Coastguard Worker DontAdvance = 0x4000, /* Leave the glyph pointer at this glyph for the 426*2d1272b8SAndroid Build Coastguard Worker next iteration. */ 427*2d1272b8SAndroid Build Coastguard Worker Offset = 0x3FFF, /* Byte offset from beginning of subtable to the 428*2d1272b8SAndroid Build Coastguard Worker * ligature action list. This value must be a 429*2d1272b8SAndroid Build Coastguard Worker * multiple of 4. */ 430*2d1272b8SAndroid Build Coastguard Worker }; 431*2d1272b8SAndroid Build Coastguard Worker 432*2d1272b8SAndroid Build Coastguard Worker typedef void EntryData; 433*2d1272b8SAndroid Build Coastguard Worker performActionAAT::LigatureEntry434*2d1272b8SAndroid Build Coastguard Worker static bool performAction (const Entry<EntryData> &entry) 435*2d1272b8SAndroid Build Coastguard Worker { return entry.flags & Offset; } 436*2d1272b8SAndroid Build Coastguard Worker ligActionIndexAAT::LigatureEntry437*2d1272b8SAndroid Build Coastguard Worker static unsigned int ligActionIndex (const Entry<EntryData> &entry) 438*2d1272b8SAndroid Build Coastguard Worker { return entry.flags & Offset; } 439*2d1272b8SAndroid Build Coastguard Worker }; 440*2d1272b8SAndroid Build Coastguard Worker 441*2d1272b8SAndroid Build Coastguard Worker 442*2d1272b8SAndroid Build Coastguard Worker template <typename Types> 443*2d1272b8SAndroid Build Coastguard Worker struct LigatureSubtable 444*2d1272b8SAndroid Build Coastguard Worker { 445*2d1272b8SAndroid Build Coastguard Worker typedef typename Types::HBUINT HBUINT; 446*2d1272b8SAndroid Build Coastguard Worker 447*2d1272b8SAndroid Build Coastguard Worker typedef LigatureEntry<Types::extended> LigatureEntryT; 448*2d1272b8SAndroid Build Coastguard Worker typedef typename LigatureEntryT::EntryData EntryData; 449*2d1272b8SAndroid Build Coastguard Worker 450*2d1272b8SAndroid Build Coastguard Worker struct driver_context_t 451*2d1272b8SAndroid Build Coastguard Worker { 452*2d1272b8SAndroid Build Coastguard Worker static constexpr bool in_place = false; 453*2d1272b8SAndroid Build Coastguard Worker enum 454*2d1272b8SAndroid Build Coastguard Worker { 455*2d1272b8SAndroid Build Coastguard Worker DontAdvance = LigatureEntryT::DontAdvance, 456*2d1272b8SAndroid Build Coastguard Worker }; 457*2d1272b8SAndroid Build Coastguard Worker enum LigActionFlags 458*2d1272b8SAndroid Build Coastguard Worker { 459*2d1272b8SAndroid Build Coastguard Worker LigActionLast = 0x80000000, /* This is the last action in the list. This also 460*2d1272b8SAndroid Build Coastguard Worker * implies storage. */ 461*2d1272b8SAndroid Build Coastguard Worker LigActionStore = 0x40000000, /* Store the ligature at the current cumulated index 462*2d1272b8SAndroid Build Coastguard Worker * in the ligature table in place of the marked 463*2d1272b8SAndroid Build Coastguard Worker * (i.e. currently-popped) glyph. */ 464*2d1272b8SAndroid Build Coastguard Worker LigActionOffset = 0x3FFFFFFF, /* A 30-bit value which is sign-extended to 32-bits 465*2d1272b8SAndroid Build Coastguard Worker * and added to the glyph ID, resulting in an index 466*2d1272b8SAndroid Build Coastguard Worker * into the component table. */ 467*2d1272b8SAndroid Build Coastguard Worker }; 468*2d1272b8SAndroid Build Coastguard Worker driver_context_tAAT::LigatureSubtable::driver_context_t469*2d1272b8SAndroid Build Coastguard Worker driver_context_t (const LigatureSubtable *table_, 470*2d1272b8SAndroid Build Coastguard Worker hb_aat_apply_context_t *c_) : 471*2d1272b8SAndroid Build Coastguard Worker ret (false), 472*2d1272b8SAndroid Build Coastguard Worker c (c_), 473*2d1272b8SAndroid Build Coastguard Worker table (table_), 474*2d1272b8SAndroid Build Coastguard Worker ligAction (table+table->ligAction), 475*2d1272b8SAndroid Build Coastguard Worker component (table+table->component), 476*2d1272b8SAndroid Build Coastguard Worker ligature (table+table->ligature), 477*2d1272b8SAndroid Build Coastguard Worker match_length (0) {} 478*2d1272b8SAndroid Build Coastguard Worker is_actionableAAT::LigatureSubtable::driver_context_t479*2d1272b8SAndroid Build Coastguard Worker bool is_actionable (hb_buffer_t *buffer HB_UNUSED, 480*2d1272b8SAndroid Build Coastguard Worker StateTableDriver<Types, EntryData> *driver HB_UNUSED, 481*2d1272b8SAndroid Build Coastguard Worker const Entry<EntryData> &entry) const 482*2d1272b8SAndroid Build Coastguard Worker { 483*2d1272b8SAndroid Build Coastguard Worker return LigatureEntryT::performAction (entry); 484*2d1272b8SAndroid Build Coastguard Worker } transitionAAT::LigatureSubtable::driver_context_t485*2d1272b8SAndroid Build Coastguard Worker void transition (hb_buffer_t *buffer, 486*2d1272b8SAndroid Build Coastguard Worker StateTableDriver<Types, EntryData> *driver, 487*2d1272b8SAndroid Build Coastguard Worker const Entry<EntryData> &entry) 488*2d1272b8SAndroid Build Coastguard Worker { 489*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG (APPLY, nullptr, "Ligature transition at %u", buffer->idx); 490*2d1272b8SAndroid Build Coastguard Worker if (entry.flags & LigatureEntryT::SetComponent) 491*2d1272b8SAndroid Build Coastguard Worker { 492*2d1272b8SAndroid Build Coastguard Worker /* Never mark same index twice, in case DontAdvance was used... */ 493*2d1272b8SAndroid Build Coastguard Worker if (match_length && match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] == buffer->out_len) 494*2d1272b8SAndroid Build Coastguard Worker match_length--; 495*2d1272b8SAndroid Build Coastguard Worker 496*2d1272b8SAndroid Build Coastguard Worker match_positions[match_length++ % ARRAY_LENGTH (match_positions)] = buffer->out_len; 497*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG (APPLY, nullptr, "Set component at %u", buffer->out_len); 498*2d1272b8SAndroid Build Coastguard Worker } 499*2d1272b8SAndroid Build Coastguard Worker 500*2d1272b8SAndroid Build Coastguard Worker if (LigatureEntryT::performAction (entry)) 501*2d1272b8SAndroid Build Coastguard Worker { 502*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG (APPLY, nullptr, "Perform action with %u", match_length); 503*2d1272b8SAndroid Build Coastguard Worker unsigned int end = buffer->out_len; 504*2d1272b8SAndroid Build Coastguard Worker 505*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!match_length)) 506*2d1272b8SAndroid Build Coastguard Worker return; 507*2d1272b8SAndroid Build Coastguard Worker 508*2d1272b8SAndroid Build Coastguard Worker if (buffer->idx >= buffer->len) 509*2d1272b8SAndroid Build Coastguard Worker return; /* TODO Work on previous instead? */ 510*2d1272b8SAndroid Build Coastguard Worker 511*2d1272b8SAndroid Build Coastguard Worker unsigned int cursor = match_length; 512*2d1272b8SAndroid Build Coastguard Worker 513*2d1272b8SAndroid Build Coastguard Worker unsigned int action_idx = LigatureEntryT::ligActionIndex (entry); 514*2d1272b8SAndroid Build Coastguard Worker action_idx = Types::offsetToIndex (action_idx, table, ligAction.arrayZ); 515*2d1272b8SAndroid Build Coastguard Worker const HBUINT32 *actionData = &ligAction[action_idx]; 516*2d1272b8SAndroid Build Coastguard Worker 517*2d1272b8SAndroid Build Coastguard Worker unsigned int ligature_idx = 0; 518*2d1272b8SAndroid Build Coastguard Worker unsigned int action; 519*2d1272b8SAndroid Build Coastguard Worker do 520*2d1272b8SAndroid Build Coastguard Worker { 521*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!cursor)) 522*2d1272b8SAndroid Build Coastguard Worker { 523*2d1272b8SAndroid Build Coastguard Worker /* Stack underflow. Clear the stack. */ 524*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG (APPLY, nullptr, "Stack underflow"); 525*2d1272b8SAndroid Build Coastguard Worker match_length = 0; 526*2d1272b8SAndroid Build Coastguard Worker break; 527*2d1272b8SAndroid Build Coastguard Worker } 528*2d1272b8SAndroid Build Coastguard Worker 529*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG (APPLY, nullptr, "Moving to stack position %u", cursor - 1); 530*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!buffer->move_to (match_positions[--cursor % ARRAY_LENGTH (match_positions)]))) return; 531*2d1272b8SAndroid Build Coastguard Worker 532*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!actionData->sanitize (&c->sanitizer))) break; 533*2d1272b8SAndroid Build Coastguard Worker hb_barrier (); 534*2d1272b8SAndroid Build Coastguard Worker action = *actionData; 535*2d1272b8SAndroid Build Coastguard Worker 536*2d1272b8SAndroid Build Coastguard Worker uint32_t uoffset = action & LigActionOffset; 537*2d1272b8SAndroid Build Coastguard Worker if (uoffset & 0x20000000) 538*2d1272b8SAndroid Build Coastguard Worker uoffset |= 0xC0000000; /* Sign-extend. */ 539*2d1272b8SAndroid Build Coastguard Worker int32_t offset = (int32_t) uoffset; 540*2d1272b8SAndroid Build Coastguard Worker unsigned int component_idx = buffer->cur().codepoint + offset; 541*2d1272b8SAndroid Build Coastguard Worker component_idx = Types::wordOffsetToIndex (component_idx, table, component.arrayZ); 542*2d1272b8SAndroid Build Coastguard Worker const HBUINT16 &componentData = component[component_idx]; 543*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!componentData.sanitize (&c->sanitizer))) break; 544*2d1272b8SAndroid Build Coastguard Worker hb_barrier (); 545*2d1272b8SAndroid Build Coastguard Worker ligature_idx += componentData; 546*2d1272b8SAndroid Build Coastguard Worker 547*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG (APPLY, nullptr, "Action store %d last %d", 548*2d1272b8SAndroid Build Coastguard Worker bool (action & LigActionStore), 549*2d1272b8SAndroid Build Coastguard Worker bool (action & LigActionLast)); 550*2d1272b8SAndroid Build Coastguard Worker if (action & (LigActionStore | LigActionLast)) 551*2d1272b8SAndroid Build Coastguard Worker { 552*2d1272b8SAndroid Build Coastguard Worker ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ); 553*2d1272b8SAndroid Build Coastguard Worker const HBGlyphID16 &ligatureData = ligature[ligature_idx]; 554*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break; 555*2d1272b8SAndroid Build Coastguard Worker hb_barrier (); 556*2d1272b8SAndroid Build Coastguard Worker hb_codepoint_t lig = ligatureData; 557*2d1272b8SAndroid Build Coastguard Worker 558*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG (APPLY, nullptr, "Produced ligature %u", lig); 559*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!buffer->replace_glyph (lig))) return; 560*2d1272b8SAndroid Build Coastguard Worker 561*2d1272b8SAndroid Build Coastguard Worker unsigned int lig_end = match_positions[(match_length - 1u) % ARRAY_LENGTH (match_positions)] + 1u; 562*2d1272b8SAndroid Build Coastguard Worker /* Now go and delete all subsequent components. */ 563*2d1272b8SAndroid Build Coastguard Worker while (match_length - 1u > cursor) 564*2d1272b8SAndroid Build Coastguard Worker { 565*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG (APPLY, nullptr, "Skipping ligature component"); 566*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!buffer->move_to (match_positions[--match_length % ARRAY_LENGTH (match_positions)]))) return; 567*2d1272b8SAndroid Build Coastguard Worker buffer->cur().unicode_props() |= UPROPS_MASK_IGNORABLE; 568*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!buffer->replace_glyph (DELETED_GLYPH))) return; 569*2d1272b8SAndroid Build Coastguard Worker } 570*2d1272b8SAndroid Build Coastguard Worker 571*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!buffer->move_to (lig_end))) return; 572*2d1272b8SAndroid Build Coastguard Worker buffer->merge_out_clusters (match_positions[cursor % ARRAY_LENGTH (match_positions)], buffer->out_len); 573*2d1272b8SAndroid Build Coastguard Worker } 574*2d1272b8SAndroid Build Coastguard Worker 575*2d1272b8SAndroid Build Coastguard Worker actionData++; 576*2d1272b8SAndroid Build Coastguard Worker } 577*2d1272b8SAndroid Build Coastguard Worker while (!(action & LigActionLast)); 578*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!buffer->move_to (end))) return; 579*2d1272b8SAndroid Build Coastguard Worker } 580*2d1272b8SAndroid Build Coastguard Worker } 581*2d1272b8SAndroid Build Coastguard Worker 582*2d1272b8SAndroid Build Coastguard Worker public: 583*2d1272b8SAndroid Build Coastguard Worker bool ret; 584*2d1272b8SAndroid Build Coastguard Worker private: 585*2d1272b8SAndroid Build Coastguard Worker hb_aat_apply_context_t *c; 586*2d1272b8SAndroid Build Coastguard Worker const LigatureSubtable *table; 587*2d1272b8SAndroid Build Coastguard Worker const UnsizedArrayOf<HBUINT32> &ligAction; 588*2d1272b8SAndroid Build Coastguard Worker const UnsizedArrayOf<HBUINT16> &component; 589*2d1272b8SAndroid Build Coastguard Worker const UnsizedArrayOf<HBGlyphID16> &ligature; 590*2d1272b8SAndroid Build Coastguard Worker unsigned int match_length; 591*2d1272b8SAndroid Build Coastguard Worker unsigned int match_positions[HB_MAX_CONTEXT_LENGTH]; 592*2d1272b8SAndroid Build Coastguard Worker }; 593*2d1272b8SAndroid Build Coastguard Worker applyAAT::LigatureSubtable594*2d1272b8SAndroid Build Coastguard Worker bool apply (hb_aat_apply_context_t *c) const 595*2d1272b8SAndroid Build Coastguard Worker { 596*2d1272b8SAndroid Build Coastguard Worker TRACE_APPLY (this); 597*2d1272b8SAndroid Build Coastguard Worker 598*2d1272b8SAndroid Build Coastguard Worker driver_context_t dc (this, c); 599*2d1272b8SAndroid Build Coastguard Worker 600*2d1272b8SAndroid Build Coastguard Worker StateTableDriver<Types, EntryData> driver (machine, c->face); 601*2d1272b8SAndroid Build Coastguard Worker 602*2d1272b8SAndroid Build Coastguard Worker if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) && 603*2d1272b8SAndroid Build Coastguard Worker !c->buffer_digest.may_have (c->machine_glyph_set)) 604*2d1272b8SAndroid Build Coastguard Worker return_trace (false); 605*2d1272b8SAndroid Build Coastguard Worker 606*2d1272b8SAndroid Build Coastguard Worker driver.drive (&dc, c); 607*2d1272b8SAndroid Build Coastguard Worker 608*2d1272b8SAndroid Build Coastguard Worker return_trace (dc.ret); 609*2d1272b8SAndroid Build Coastguard Worker } 610*2d1272b8SAndroid Build Coastguard Worker sanitizeAAT::LigatureSubtable611*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c) const 612*2d1272b8SAndroid Build Coastguard Worker { 613*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 614*2d1272b8SAndroid Build Coastguard Worker /* The rest of array sanitizations are done at run-time. */ 615*2d1272b8SAndroid Build Coastguard Worker return_trace (c->check_struct (this) && machine.sanitize (c) && 616*2d1272b8SAndroid Build Coastguard Worker hb_barrier () && 617*2d1272b8SAndroid Build Coastguard Worker ligAction && component && ligature); 618*2d1272b8SAndroid Build Coastguard Worker } 619*2d1272b8SAndroid Build Coastguard Worker 620*2d1272b8SAndroid Build Coastguard Worker public: 621*2d1272b8SAndroid Build Coastguard Worker StateTable<Types, EntryData> 622*2d1272b8SAndroid Build Coastguard Worker machine; 623*2d1272b8SAndroid Build Coastguard Worker protected: 624*2d1272b8SAndroid Build Coastguard Worker NNOffsetTo<UnsizedArrayOf<HBUINT32>, HBUINT> 625*2d1272b8SAndroid Build Coastguard Worker ligAction; /* Offset to the ligature action table. */ 626*2d1272b8SAndroid Build Coastguard Worker NNOffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT> 627*2d1272b8SAndroid Build Coastguard Worker component; /* Offset to the component table. */ 628*2d1272b8SAndroid Build Coastguard Worker NNOffsetTo<UnsizedArrayOf<HBGlyphID16>, HBUINT> 629*2d1272b8SAndroid Build Coastguard Worker ligature; /* Offset to the actual ligature lists. */ 630*2d1272b8SAndroid Build Coastguard Worker public: 631*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size + 3 * HBUINT::static_size)); 632*2d1272b8SAndroid Build Coastguard Worker }; 633*2d1272b8SAndroid Build Coastguard Worker 634*2d1272b8SAndroid Build Coastguard Worker template <typename Types> 635*2d1272b8SAndroid Build Coastguard Worker struct NoncontextualSubtable 636*2d1272b8SAndroid Build Coastguard Worker { applyAAT::NoncontextualSubtable637*2d1272b8SAndroid Build Coastguard Worker bool apply (hb_aat_apply_context_t *c) const 638*2d1272b8SAndroid Build Coastguard Worker { 639*2d1272b8SAndroid Build Coastguard Worker TRACE_APPLY (this); 640*2d1272b8SAndroid Build Coastguard Worker 641*2d1272b8SAndroid Build Coastguard Worker const OT::GDEF &gdef (*c->gdef_table); 642*2d1272b8SAndroid Build Coastguard Worker bool has_glyph_classes = gdef.has_glyph_classes (); 643*2d1272b8SAndroid Build Coastguard Worker 644*2d1272b8SAndroid Build Coastguard Worker bool ret = false; 645*2d1272b8SAndroid Build Coastguard Worker unsigned int num_glyphs = c->face->get_num_glyphs (); 646*2d1272b8SAndroid Build Coastguard Worker 647*2d1272b8SAndroid Build Coastguard Worker hb_glyph_info_t *info = c->buffer->info; 648*2d1272b8SAndroid Build Coastguard Worker unsigned int count = c->buffer->len; 649*2d1272b8SAndroid Build Coastguard Worker // If there's only one range, we already checked the flag. 650*2d1272b8SAndroid Build Coastguard Worker auto *last_range = c->range_flags && (c->range_flags->length > 1) ? &(*c->range_flags)[0] : nullptr; 651*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < count; i++) 652*2d1272b8SAndroid Build Coastguard Worker { 653*2d1272b8SAndroid Build Coastguard Worker /* This block copied from StateTableDriver::drive. Keep in sync. */ 654*2d1272b8SAndroid Build Coastguard Worker if (last_range) 655*2d1272b8SAndroid Build Coastguard Worker { 656*2d1272b8SAndroid Build Coastguard Worker auto *range = last_range; 657*2d1272b8SAndroid Build Coastguard Worker { 658*2d1272b8SAndroid Build Coastguard Worker unsigned cluster = info[i].cluster; 659*2d1272b8SAndroid Build Coastguard Worker while (cluster < range->cluster_first) 660*2d1272b8SAndroid Build Coastguard Worker range--; 661*2d1272b8SAndroid Build Coastguard Worker while (cluster > range->cluster_last) 662*2d1272b8SAndroid Build Coastguard Worker range++; 663*2d1272b8SAndroid Build Coastguard Worker 664*2d1272b8SAndroid Build Coastguard Worker last_range = range; 665*2d1272b8SAndroid Build Coastguard Worker } 666*2d1272b8SAndroid Build Coastguard Worker if (!(range->flags & c->subtable_flags)) 667*2d1272b8SAndroid Build Coastguard Worker continue; 668*2d1272b8SAndroid Build Coastguard Worker } 669*2d1272b8SAndroid Build Coastguard Worker 670*2d1272b8SAndroid Build Coastguard Worker const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs); 671*2d1272b8SAndroid Build Coastguard Worker if (replacement) 672*2d1272b8SAndroid Build Coastguard Worker { 673*2d1272b8SAndroid Build Coastguard Worker info[i].codepoint = *replacement; 674*2d1272b8SAndroid Build Coastguard Worker c->buffer_digest.add (*replacement); 675*2d1272b8SAndroid Build Coastguard Worker if (has_glyph_classes) 676*2d1272b8SAndroid Build Coastguard Worker _hb_glyph_info_set_glyph_props (&info[i], 677*2d1272b8SAndroid Build Coastguard Worker gdef.get_glyph_props (*replacement)); 678*2d1272b8SAndroid Build Coastguard Worker ret = true; 679*2d1272b8SAndroid Build Coastguard Worker } 680*2d1272b8SAndroid Build Coastguard Worker } 681*2d1272b8SAndroid Build Coastguard Worker 682*2d1272b8SAndroid Build Coastguard Worker return_trace (ret); 683*2d1272b8SAndroid Build Coastguard Worker } 684*2d1272b8SAndroid Build Coastguard Worker sanitizeAAT::NoncontextualSubtable685*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c) const 686*2d1272b8SAndroid Build Coastguard Worker { 687*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 688*2d1272b8SAndroid Build Coastguard Worker return_trace (substitute.sanitize (c)); 689*2d1272b8SAndroid Build Coastguard Worker } 690*2d1272b8SAndroid Build Coastguard Worker 691*2d1272b8SAndroid Build Coastguard Worker protected: 692*2d1272b8SAndroid Build Coastguard Worker Lookup<HBGlyphID16> substitute; 693*2d1272b8SAndroid Build Coastguard Worker public: 694*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_MIN (2); 695*2d1272b8SAndroid Build Coastguard Worker }; 696*2d1272b8SAndroid Build Coastguard Worker 697*2d1272b8SAndroid Build Coastguard Worker template <typename Types> 698*2d1272b8SAndroid Build Coastguard Worker struct InsertionSubtable 699*2d1272b8SAndroid Build Coastguard Worker { 700*2d1272b8SAndroid Build Coastguard Worker typedef typename Types::HBUINT HBUINT; 701*2d1272b8SAndroid Build Coastguard Worker 702*2d1272b8SAndroid Build Coastguard Worker struct EntryData 703*2d1272b8SAndroid Build Coastguard Worker { 704*2d1272b8SAndroid Build Coastguard Worker HBUINT16 currentInsertIndex; /* Zero-based index into the insertion glyph table. 705*2d1272b8SAndroid Build Coastguard Worker * The number of glyphs to be inserted is contained 706*2d1272b8SAndroid Build Coastguard Worker * in the currentInsertCount field in the flags. 707*2d1272b8SAndroid Build Coastguard Worker * A value of 0xFFFF indicates no insertion is to 708*2d1272b8SAndroid Build Coastguard Worker * be done. */ 709*2d1272b8SAndroid Build Coastguard Worker HBUINT16 markedInsertIndex; /* Zero-based index into the insertion glyph table. 710*2d1272b8SAndroid Build Coastguard Worker * The number of glyphs to be inserted is contained 711*2d1272b8SAndroid Build Coastguard Worker * in the markedInsertCount field in the flags. 712*2d1272b8SAndroid Build Coastguard Worker * A value of 0xFFFF indicates no insertion is to 713*2d1272b8SAndroid Build Coastguard Worker * be done. */ 714*2d1272b8SAndroid Build Coastguard Worker public: 715*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_STATIC (4); 716*2d1272b8SAndroid Build Coastguard Worker }; 717*2d1272b8SAndroid Build Coastguard Worker 718*2d1272b8SAndroid Build Coastguard Worker struct driver_context_t 719*2d1272b8SAndroid Build Coastguard Worker { 720*2d1272b8SAndroid Build Coastguard Worker static constexpr bool in_place = false; 721*2d1272b8SAndroid Build Coastguard Worker enum Flags 722*2d1272b8SAndroid Build Coastguard Worker { 723*2d1272b8SAndroid Build Coastguard Worker SetMark = 0x8000, /* If set, mark the current glyph. */ 724*2d1272b8SAndroid Build Coastguard Worker DontAdvance = 0x4000, /* If set, don't advance to the next glyph before 725*2d1272b8SAndroid Build Coastguard Worker * going to the new state. This does not mean 726*2d1272b8SAndroid Build Coastguard Worker * that the glyph pointed to is the same one as 727*2d1272b8SAndroid Build Coastguard Worker * before. If you've made insertions immediately 728*2d1272b8SAndroid Build Coastguard Worker * downstream of the current glyph, the next glyph 729*2d1272b8SAndroid Build Coastguard Worker * processed would in fact be the first one 730*2d1272b8SAndroid Build Coastguard Worker * inserted. */ 731*2d1272b8SAndroid Build Coastguard Worker CurrentIsKashidaLike= 0x2000, /* If set, and the currentInsertList is nonzero, 732*2d1272b8SAndroid Build Coastguard Worker * then the specified glyph list will be inserted 733*2d1272b8SAndroid Build Coastguard Worker * as a kashida-like insertion, either before or 734*2d1272b8SAndroid Build Coastguard Worker * after the current glyph (depending on the state 735*2d1272b8SAndroid Build Coastguard Worker * of the currentInsertBefore flag). If clear, and 736*2d1272b8SAndroid Build Coastguard Worker * the currentInsertList is nonzero, then the 737*2d1272b8SAndroid Build Coastguard Worker * specified glyph list will be inserted as a 738*2d1272b8SAndroid Build Coastguard Worker * split-vowel-like insertion, either before or 739*2d1272b8SAndroid Build Coastguard Worker * after the current glyph (depending on the state 740*2d1272b8SAndroid Build Coastguard Worker * of the currentInsertBefore flag). */ 741*2d1272b8SAndroid Build Coastguard Worker MarkedIsKashidaLike= 0x1000, /* If set, and the markedInsertList is nonzero, 742*2d1272b8SAndroid Build Coastguard Worker * then the specified glyph list will be inserted 743*2d1272b8SAndroid Build Coastguard Worker * as a kashida-like insertion, either before or 744*2d1272b8SAndroid Build Coastguard Worker * after the marked glyph (depending on the state 745*2d1272b8SAndroid Build Coastguard Worker * of the markedInsertBefore flag). If clear, and 746*2d1272b8SAndroid Build Coastguard Worker * the markedInsertList is nonzero, then the 747*2d1272b8SAndroid Build Coastguard Worker * specified glyph list will be inserted as a 748*2d1272b8SAndroid Build Coastguard Worker * split-vowel-like insertion, either before or 749*2d1272b8SAndroid Build Coastguard Worker * after the marked glyph (depending on the state 750*2d1272b8SAndroid Build Coastguard Worker * of the markedInsertBefore flag). */ 751*2d1272b8SAndroid Build Coastguard Worker CurrentInsertBefore= 0x0800, /* If set, specifies that insertions are to be made 752*2d1272b8SAndroid Build Coastguard Worker * to the left of the current glyph. If clear, 753*2d1272b8SAndroid Build Coastguard Worker * they're made to the right of the current glyph. */ 754*2d1272b8SAndroid Build Coastguard Worker MarkedInsertBefore= 0x0400, /* If set, specifies that insertions are to be 755*2d1272b8SAndroid Build Coastguard Worker * made to the left of the marked glyph. If clear, 756*2d1272b8SAndroid Build Coastguard Worker * they're made to the right of the marked glyph. */ 757*2d1272b8SAndroid Build Coastguard Worker CurrentInsertCount= 0x3E0, /* This 5-bit field is treated as a count of the 758*2d1272b8SAndroid Build Coastguard Worker * number of glyphs to insert at the current 759*2d1272b8SAndroid Build Coastguard Worker * position. Since zero means no insertions, the 760*2d1272b8SAndroid Build Coastguard Worker * largest number of insertions at any given 761*2d1272b8SAndroid Build Coastguard Worker * current location is 31 glyphs. */ 762*2d1272b8SAndroid Build Coastguard Worker MarkedInsertCount= 0x001F, /* This 5-bit field is treated as a count of the 763*2d1272b8SAndroid Build Coastguard Worker * number of glyphs to insert at the marked 764*2d1272b8SAndroid Build Coastguard Worker * position. Since zero means no insertions, the 765*2d1272b8SAndroid Build Coastguard Worker * largest number of insertions at any given 766*2d1272b8SAndroid Build Coastguard Worker * marked location is 31 glyphs. */ 767*2d1272b8SAndroid Build Coastguard Worker }; 768*2d1272b8SAndroid Build Coastguard Worker driver_context_tAAT::InsertionSubtable::driver_context_t769*2d1272b8SAndroid Build Coastguard Worker driver_context_t (const InsertionSubtable *table, 770*2d1272b8SAndroid Build Coastguard Worker hb_aat_apply_context_t *c_) : 771*2d1272b8SAndroid Build Coastguard Worker ret (false), 772*2d1272b8SAndroid Build Coastguard Worker c (c_), 773*2d1272b8SAndroid Build Coastguard Worker mark (0), 774*2d1272b8SAndroid Build Coastguard Worker insertionAction (table+table->insertionAction) {} 775*2d1272b8SAndroid Build Coastguard Worker is_actionableAAT::InsertionSubtable::driver_context_t776*2d1272b8SAndroid Build Coastguard Worker bool is_actionable (hb_buffer_t *buffer HB_UNUSED, 777*2d1272b8SAndroid Build Coastguard Worker StateTableDriver<Types, EntryData> *driver HB_UNUSED, 778*2d1272b8SAndroid Build Coastguard Worker const Entry<EntryData> &entry) const 779*2d1272b8SAndroid Build Coastguard Worker { 780*2d1272b8SAndroid Build Coastguard Worker return (entry.flags & (CurrentInsertCount | MarkedInsertCount)) && 781*2d1272b8SAndroid Build Coastguard Worker (entry.data.currentInsertIndex != 0xFFFF ||entry.data.markedInsertIndex != 0xFFFF); 782*2d1272b8SAndroid Build Coastguard Worker } transitionAAT::InsertionSubtable::driver_context_t783*2d1272b8SAndroid Build Coastguard Worker void transition (hb_buffer_t *buffer, 784*2d1272b8SAndroid Build Coastguard Worker StateTableDriver<Types, EntryData> *driver, 785*2d1272b8SAndroid Build Coastguard Worker const Entry<EntryData> &entry) 786*2d1272b8SAndroid Build Coastguard Worker { 787*2d1272b8SAndroid Build Coastguard Worker unsigned int flags = entry.flags; 788*2d1272b8SAndroid Build Coastguard Worker 789*2d1272b8SAndroid Build Coastguard Worker unsigned mark_loc = buffer->out_len; 790*2d1272b8SAndroid Build Coastguard Worker 791*2d1272b8SAndroid Build Coastguard Worker if (entry.data.markedInsertIndex != 0xFFFF) 792*2d1272b8SAndroid Build Coastguard Worker { 793*2d1272b8SAndroid Build Coastguard Worker unsigned int count = (flags & MarkedInsertCount); 794*2d1272b8SAndroid Build Coastguard Worker if (unlikely ((buffer->max_ops -= count) <= 0)) return; 795*2d1272b8SAndroid Build Coastguard Worker unsigned int start = entry.data.markedInsertIndex; 796*2d1272b8SAndroid Build Coastguard Worker const HBGlyphID16 *glyphs = &insertionAction[start]; 797*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0; 798*2d1272b8SAndroid Build Coastguard Worker hb_barrier (); 799*2d1272b8SAndroid Build Coastguard Worker 800*2d1272b8SAndroid Build Coastguard Worker bool before = flags & MarkedInsertBefore; 801*2d1272b8SAndroid Build Coastguard Worker 802*2d1272b8SAndroid Build Coastguard Worker unsigned int end = buffer->out_len; 803*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!buffer->move_to (mark))) return; 804*2d1272b8SAndroid Build Coastguard Worker 805*2d1272b8SAndroid Build Coastguard Worker if (buffer->idx < buffer->len && !before) 806*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!buffer->copy_glyph ())) return; 807*2d1272b8SAndroid Build Coastguard Worker /* TODO We ignore KashidaLike setting. */ 808*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return; 809*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < count; i++) 810*2d1272b8SAndroid Build Coastguard Worker c->buffer_digest.add (glyphs[i]); 811*2d1272b8SAndroid Build Coastguard Worker ret = true; 812*2d1272b8SAndroid Build Coastguard Worker if (buffer->idx < buffer->len && !before) 813*2d1272b8SAndroid Build Coastguard Worker buffer->skip_glyph (); 814*2d1272b8SAndroid Build Coastguard Worker 815*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!buffer->move_to (end + count))) return; 816*2d1272b8SAndroid Build Coastguard Worker 817*2d1272b8SAndroid Build Coastguard Worker buffer->unsafe_to_break_from_outbuffer (mark, hb_min (buffer->idx + 1, buffer->len)); 818*2d1272b8SAndroid Build Coastguard Worker } 819*2d1272b8SAndroid Build Coastguard Worker 820*2d1272b8SAndroid Build Coastguard Worker if (flags & SetMark) 821*2d1272b8SAndroid Build Coastguard Worker mark = mark_loc; 822*2d1272b8SAndroid Build Coastguard Worker 823*2d1272b8SAndroid Build Coastguard Worker if (entry.data.currentInsertIndex != 0xFFFF) 824*2d1272b8SAndroid Build Coastguard Worker { 825*2d1272b8SAndroid Build Coastguard Worker unsigned int count = (flags & CurrentInsertCount) >> 5; 826*2d1272b8SAndroid Build Coastguard Worker if (unlikely ((buffer->max_ops -= count) <= 0)) return; 827*2d1272b8SAndroid Build Coastguard Worker unsigned int start = entry.data.currentInsertIndex; 828*2d1272b8SAndroid Build Coastguard Worker const HBGlyphID16 *glyphs = &insertionAction[start]; 829*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0; 830*2d1272b8SAndroid Build Coastguard Worker hb_barrier (); 831*2d1272b8SAndroid Build Coastguard Worker 832*2d1272b8SAndroid Build Coastguard Worker bool before = flags & CurrentInsertBefore; 833*2d1272b8SAndroid Build Coastguard Worker 834*2d1272b8SAndroid Build Coastguard Worker unsigned int end = buffer->out_len; 835*2d1272b8SAndroid Build Coastguard Worker 836*2d1272b8SAndroid Build Coastguard Worker if (buffer->idx < buffer->len && !before) 837*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!buffer->copy_glyph ())) return; 838*2d1272b8SAndroid Build Coastguard Worker /* TODO We ignore KashidaLike setting. */ 839*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return; 840*2d1272b8SAndroid Build Coastguard Worker if (buffer->idx < buffer->len && !before) 841*2d1272b8SAndroid Build Coastguard Worker buffer->skip_glyph (); 842*2d1272b8SAndroid Build Coastguard Worker 843*2d1272b8SAndroid Build Coastguard Worker /* Humm. Not sure where to move to. There's this wording under 844*2d1272b8SAndroid Build Coastguard Worker * DontAdvance flag: 845*2d1272b8SAndroid Build Coastguard Worker * 846*2d1272b8SAndroid Build Coastguard Worker * "If set, don't update the glyph index before going to the new state. 847*2d1272b8SAndroid Build Coastguard Worker * This does not mean that the glyph pointed to is the same one as 848*2d1272b8SAndroid Build Coastguard Worker * before. If you've made insertions immediately downstream of the 849*2d1272b8SAndroid Build Coastguard Worker * current glyph, the next glyph processed would in fact be the first 850*2d1272b8SAndroid Build Coastguard Worker * one inserted." 851*2d1272b8SAndroid Build Coastguard Worker * 852*2d1272b8SAndroid Build Coastguard Worker * This suggests that if DontAdvance is NOT set, we should move to 853*2d1272b8SAndroid Build Coastguard Worker * end+count. If it *was*, then move to end, such that newly inserted 854*2d1272b8SAndroid Build Coastguard Worker * glyphs are now visible. 855*2d1272b8SAndroid Build Coastguard Worker * 856*2d1272b8SAndroid Build Coastguard Worker * https://github.com/harfbuzz/harfbuzz/issues/1224#issuecomment-427691417 857*2d1272b8SAndroid Build Coastguard Worker */ 858*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!buffer->move_to ((flags & DontAdvance) ? end : end + count))) return; 859*2d1272b8SAndroid Build Coastguard Worker } 860*2d1272b8SAndroid Build Coastguard Worker } 861*2d1272b8SAndroid Build Coastguard Worker 862*2d1272b8SAndroid Build Coastguard Worker public: 863*2d1272b8SAndroid Build Coastguard Worker bool ret; 864*2d1272b8SAndroid Build Coastguard Worker private: 865*2d1272b8SAndroid Build Coastguard Worker hb_aat_apply_context_t *c; 866*2d1272b8SAndroid Build Coastguard Worker unsigned int mark; 867*2d1272b8SAndroid Build Coastguard Worker const UnsizedArrayOf<HBGlyphID16> &insertionAction; 868*2d1272b8SAndroid Build Coastguard Worker }; 869*2d1272b8SAndroid Build Coastguard Worker applyAAT::InsertionSubtable870*2d1272b8SAndroid Build Coastguard Worker bool apply (hb_aat_apply_context_t *c) const 871*2d1272b8SAndroid Build Coastguard Worker { 872*2d1272b8SAndroid Build Coastguard Worker TRACE_APPLY (this); 873*2d1272b8SAndroid Build Coastguard Worker 874*2d1272b8SAndroid Build Coastguard Worker driver_context_t dc (this, c); 875*2d1272b8SAndroid Build Coastguard Worker 876*2d1272b8SAndroid Build Coastguard Worker StateTableDriver<Types, EntryData> driver (machine, c->face); 877*2d1272b8SAndroid Build Coastguard Worker 878*2d1272b8SAndroid Build Coastguard Worker if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) && 879*2d1272b8SAndroid Build Coastguard Worker !c->buffer_digest.may_have (c->machine_glyph_set)) 880*2d1272b8SAndroid Build Coastguard Worker return_trace (false); 881*2d1272b8SAndroid Build Coastguard Worker 882*2d1272b8SAndroid Build Coastguard Worker driver.drive (&dc, c); 883*2d1272b8SAndroid Build Coastguard Worker 884*2d1272b8SAndroid Build Coastguard Worker return_trace (dc.ret); 885*2d1272b8SAndroid Build Coastguard Worker } 886*2d1272b8SAndroid Build Coastguard Worker sanitizeAAT::InsertionSubtable887*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c) const 888*2d1272b8SAndroid Build Coastguard Worker { 889*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 890*2d1272b8SAndroid Build Coastguard Worker /* The rest of array sanitizations are done at run-time. */ 891*2d1272b8SAndroid Build Coastguard Worker return_trace (c->check_struct (this) && machine.sanitize (c) && 892*2d1272b8SAndroid Build Coastguard Worker hb_barrier () && 893*2d1272b8SAndroid Build Coastguard Worker insertionAction); 894*2d1272b8SAndroid Build Coastguard Worker } 895*2d1272b8SAndroid Build Coastguard Worker 896*2d1272b8SAndroid Build Coastguard Worker public: 897*2d1272b8SAndroid Build Coastguard Worker StateTable<Types, EntryData> 898*2d1272b8SAndroid Build Coastguard Worker machine; 899*2d1272b8SAndroid Build Coastguard Worker protected: 900*2d1272b8SAndroid Build Coastguard Worker NNOffsetTo<UnsizedArrayOf<HBGlyphID16>, HBUINT> 901*2d1272b8SAndroid Build Coastguard Worker insertionAction; /* Byte offset from stateHeader to the start of 902*2d1272b8SAndroid Build Coastguard Worker * the insertion glyph table. */ 903*2d1272b8SAndroid Build Coastguard Worker public: 904*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_STATIC ((StateTable<Types, EntryData>::static_size + HBUINT::static_size)); 905*2d1272b8SAndroid Build Coastguard Worker }; 906*2d1272b8SAndroid Build Coastguard Worker 907*2d1272b8SAndroid Build Coastguard Worker 908*2d1272b8SAndroid Build Coastguard Worker struct Feature 909*2d1272b8SAndroid Build Coastguard Worker { sanitizeAAT::Feature910*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c) const 911*2d1272b8SAndroid Build Coastguard Worker { 912*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 913*2d1272b8SAndroid Build Coastguard Worker return_trace (c->check_struct (this)); 914*2d1272b8SAndroid Build Coastguard Worker } 915*2d1272b8SAndroid Build Coastguard Worker 916*2d1272b8SAndroid Build Coastguard Worker public: 917*2d1272b8SAndroid Build Coastguard Worker HBUINT16 featureType; /* The type of feature. */ 918*2d1272b8SAndroid Build Coastguard Worker HBUINT16 featureSetting; /* The feature's setting (aka selector). */ 919*2d1272b8SAndroid Build Coastguard Worker HBUINT32 enableFlags; /* Flags for the settings that this feature 920*2d1272b8SAndroid Build Coastguard Worker * and setting enables. */ 921*2d1272b8SAndroid Build Coastguard Worker HBUINT32 disableFlags; /* Complement of flags for the settings that this 922*2d1272b8SAndroid Build Coastguard Worker * feature and setting disable. */ 923*2d1272b8SAndroid Build Coastguard Worker 924*2d1272b8SAndroid Build Coastguard Worker public: 925*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_STATIC (12); 926*2d1272b8SAndroid Build Coastguard Worker }; 927*2d1272b8SAndroid Build Coastguard Worker 928*2d1272b8SAndroid Build Coastguard Worker 929*2d1272b8SAndroid Build Coastguard Worker struct hb_accelerate_subtables_context_t : 930*2d1272b8SAndroid Build Coastguard Worker hb_dispatch_context_t<hb_accelerate_subtables_context_t> 931*2d1272b8SAndroid Build Coastguard Worker { 932*2d1272b8SAndroid Build Coastguard Worker struct hb_applicable_t 933*2d1272b8SAndroid Build Coastguard Worker { 934*2d1272b8SAndroid Build Coastguard Worker friend struct hb_accelerate_subtables_context_t; 935*2d1272b8SAndroid Build Coastguard Worker friend struct hb_aat_layout_lookup_accelerator_t; 936*2d1272b8SAndroid Build Coastguard Worker 937*2d1272b8SAndroid Build Coastguard Worker public: 938*2d1272b8SAndroid Build Coastguard Worker hb_set_digest_t digest; 939*2d1272b8SAndroid Build Coastguard Worker 940*2d1272b8SAndroid Build Coastguard Worker template <typename T> init_AAT::hb_accelerate_subtables_context_t::hb_applicable_t941*2d1272b8SAndroid Build Coastguard Worker auto init_ (const T &obj_, unsigned num_glyphs, hb_priority<1>) HB_AUTO_RETURN 942*2d1272b8SAndroid Build Coastguard Worker ( 943*2d1272b8SAndroid Build Coastguard Worker obj_.machine.collect_glyphs (this->digest, num_glyphs) 944*2d1272b8SAndroid Build Coastguard Worker ) 945*2d1272b8SAndroid Build Coastguard Worker 946*2d1272b8SAndroid Build Coastguard Worker template <typename T> 947*2d1272b8SAndroid Build Coastguard Worker void init_ (const T &obj_, unsigned num_glyphs, hb_priority<0>) 948*2d1272b8SAndroid Build Coastguard Worker { 949*2d1272b8SAndroid Build Coastguard Worker digest = digest.full (); 950*2d1272b8SAndroid Build Coastguard Worker } 951*2d1272b8SAndroid Build Coastguard Worker 952*2d1272b8SAndroid Build Coastguard Worker template <typename T> initAAT::hb_accelerate_subtables_context_t::hb_applicable_t953*2d1272b8SAndroid Build Coastguard Worker void init (const T &obj_, unsigned num_glyphs) 954*2d1272b8SAndroid Build Coastguard Worker { 955*2d1272b8SAndroid Build Coastguard Worker init_ (obj_, num_glyphs, hb_prioritize); 956*2d1272b8SAndroid Build Coastguard Worker } 957*2d1272b8SAndroid Build Coastguard Worker }; 958*2d1272b8SAndroid Build Coastguard Worker 959*2d1272b8SAndroid Build Coastguard Worker /* Dispatch interface. */ 960*2d1272b8SAndroid Build Coastguard Worker template <typename T> dispatchAAT::hb_accelerate_subtables_context_t961*2d1272b8SAndroid Build Coastguard Worker return_t dispatch (const T &obj) 962*2d1272b8SAndroid Build Coastguard Worker { 963*2d1272b8SAndroid Build Coastguard Worker hb_applicable_t *entry = &array[i++]; 964*2d1272b8SAndroid Build Coastguard Worker 965*2d1272b8SAndroid Build Coastguard Worker entry->init (obj, num_glyphs); 966*2d1272b8SAndroid Build Coastguard Worker 967*2d1272b8SAndroid Build Coastguard Worker return hb_empty_t (); 968*2d1272b8SAndroid Build Coastguard Worker } default_return_valueAAT::hb_accelerate_subtables_context_t969*2d1272b8SAndroid Build Coastguard Worker static return_t default_return_value () { return hb_empty_t (); } 970*2d1272b8SAndroid Build Coastguard Worker stop_sublookup_iterationAAT::hb_accelerate_subtables_context_t971*2d1272b8SAndroid Build Coastguard Worker bool stop_sublookup_iteration (return_t r) const { return false; } 972*2d1272b8SAndroid Build Coastguard Worker hb_accelerate_subtables_context_tAAT::hb_accelerate_subtables_context_t973*2d1272b8SAndroid Build Coastguard Worker hb_accelerate_subtables_context_t (hb_applicable_t *array_, unsigned num_glyphs_) : 974*2d1272b8SAndroid Build Coastguard Worker hb_dispatch_context_t<hb_accelerate_subtables_context_t> (), 975*2d1272b8SAndroid Build Coastguard Worker array (array_), num_glyphs (num_glyphs_) {} 976*2d1272b8SAndroid Build Coastguard Worker 977*2d1272b8SAndroid Build Coastguard Worker hb_applicable_t *array; 978*2d1272b8SAndroid Build Coastguard Worker unsigned num_glyphs; 979*2d1272b8SAndroid Build Coastguard Worker unsigned i = 0; 980*2d1272b8SAndroid Build Coastguard Worker }; 981*2d1272b8SAndroid Build Coastguard Worker 982*2d1272b8SAndroid Build Coastguard Worker struct hb_aat_layout_chain_accelerator_t 983*2d1272b8SAndroid Build Coastguard Worker { 984*2d1272b8SAndroid Build Coastguard Worker template <typename TChain> createAAT::hb_aat_layout_chain_accelerator_t985*2d1272b8SAndroid Build Coastguard Worker static hb_aat_layout_chain_accelerator_t *create (const TChain &chain, unsigned num_glyphs) 986*2d1272b8SAndroid Build Coastguard Worker { 987*2d1272b8SAndroid Build Coastguard Worker unsigned count = chain.get_subtable_count (); 988*2d1272b8SAndroid Build Coastguard Worker 989*2d1272b8SAndroid Build Coastguard Worker unsigned size = sizeof (hb_aat_layout_chain_accelerator_t) - 990*2d1272b8SAndroid Build Coastguard Worker HB_VAR_ARRAY * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t) + 991*2d1272b8SAndroid Build Coastguard Worker count * sizeof (hb_accelerate_subtables_context_t::hb_applicable_t); 992*2d1272b8SAndroid Build Coastguard Worker 993*2d1272b8SAndroid Build Coastguard Worker /* The following is a calloc because when we are collecting subtables, 994*2d1272b8SAndroid Build Coastguard Worker * some of them might be invalid and hence not collect; as a result, 995*2d1272b8SAndroid Build Coastguard Worker * we might not fill in all the count entries of the subtables array. 996*2d1272b8SAndroid Build Coastguard Worker * Zeroing it allows the set digest to gatekeep it without having to 997*2d1272b8SAndroid Build Coastguard Worker * initialize it further. */ 998*2d1272b8SAndroid Build Coastguard Worker auto *thiz = (hb_aat_layout_chain_accelerator_t *) hb_calloc (1, size); 999*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!thiz)) 1000*2d1272b8SAndroid Build Coastguard Worker return nullptr; 1001*2d1272b8SAndroid Build Coastguard Worker 1002*2d1272b8SAndroid Build Coastguard Worker hb_accelerate_subtables_context_t c_accelerate_subtables (thiz->subtables, num_glyphs); 1003*2d1272b8SAndroid Build Coastguard Worker chain.dispatch (&c_accelerate_subtables); 1004*2d1272b8SAndroid Build Coastguard Worker 1005*2d1272b8SAndroid Build Coastguard Worker return thiz; 1006*2d1272b8SAndroid Build Coastguard Worker } 1007*2d1272b8SAndroid Build Coastguard Worker 1008*2d1272b8SAndroid Build Coastguard Worker hb_accelerate_subtables_context_t::hb_applicable_t subtables[HB_VAR_ARRAY]; 1009*2d1272b8SAndroid Build Coastguard Worker }; 1010*2d1272b8SAndroid Build Coastguard Worker 1011*2d1272b8SAndroid Build Coastguard Worker template <typename Types> 1012*2d1272b8SAndroid Build Coastguard Worker struct ChainSubtable 1013*2d1272b8SAndroid Build Coastguard Worker { 1014*2d1272b8SAndroid Build Coastguard Worker typedef typename Types::HBUINT HBUINT; 1015*2d1272b8SAndroid Build Coastguard Worker 1016*2d1272b8SAndroid Build Coastguard Worker template <typename T> 1017*2d1272b8SAndroid Build Coastguard Worker friend struct Chain; 1018*2d1272b8SAndroid Build Coastguard Worker get_sizeAAT::ChainSubtable1019*2d1272b8SAndroid Build Coastguard Worker unsigned int get_size () const { return length; } get_typeAAT::ChainSubtable1020*2d1272b8SAndroid Build Coastguard Worker unsigned int get_type () const { return coverage & 0xFF; } get_coverageAAT::ChainSubtable1021*2d1272b8SAndroid Build Coastguard Worker unsigned int get_coverage () const { return coverage >> (sizeof (HBUINT) * 8 - 8); } 1022*2d1272b8SAndroid Build Coastguard Worker 1023*2d1272b8SAndroid Build Coastguard Worker enum Coverage 1024*2d1272b8SAndroid Build Coastguard Worker { 1025*2d1272b8SAndroid Build Coastguard Worker Vertical = 0x80, /* If set, this subtable will only be applied 1026*2d1272b8SAndroid Build Coastguard Worker * to vertical text. If clear, this subtable 1027*2d1272b8SAndroid Build Coastguard Worker * will only be applied to horizontal text. */ 1028*2d1272b8SAndroid Build Coastguard Worker Backwards = 0x40, /* If set, this subtable will process glyphs 1029*2d1272b8SAndroid Build Coastguard Worker * in descending order. If clear, it will 1030*2d1272b8SAndroid Build Coastguard Worker * process the glyphs in ascending order. */ 1031*2d1272b8SAndroid Build Coastguard Worker AllDirections = 0x20, /* If set, this subtable will be applied to 1032*2d1272b8SAndroid Build Coastguard Worker * both horizontal and vertical text (i.e. 1033*2d1272b8SAndroid Build Coastguard Worker * the state of bit 0x80000000 is ignored). */ 1034*2d1272b8SAndroid Build Coastguard Worker Logical = 0x10, /* If set, this subtable will process glyphs 1035*2d1272b8SAndroid Build Coastguard Worker * in logical order (or reverse logical order, 1036*2d1272b8SAndroid Build Coastguard Worker * depending on the value of bit 0x80000000). */ 1037*2d1272b8SAndroid Build Coastguard Worker }; 1038*2d1272b8SAndroid Build Coastguard Worker enum Type 1039*2d1272b8SAndroid Build Coastguard Worker { 1040*2d1272b8SAndroid Build Coastguard Worker Rearrangement = 0, 1041*2d1272b8SAndroid Build Coastguard Worker Contextual = 1, 1042*2d1272b8SAndroid Build Coastguard Worker Ligature = 2, 1043*2d1272b8SAndroid Build Coastguard Worker Noncontextual = 4, 1044*2d1272b8SAndroid Build Coastguard Worker Insertion = 5 1045*2d1272b8SAndroid Build Coastguard Worker }; 1046*2d1272b8SAndroid Build Coastguard Worker 1047*2d1272b8SAndroid Build Coastguard Worker template <typename context_t, typename ...Ts> dispatchAAT::ChainSubtable1048*2d1272b8SAndroid Build Coastguard Worker typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const 1049*2d1272b8SAndroid Build Coastguard Worker { 1050*2d1272b8SAndroid Build Coastguard Worker unsigned int subtable_type = get_type (); 1051*2d1272b8SAndroid Build Coastguard Worker TRACE_DISPATCH (this, subtable_type); 1052*2d1272b8SAndroid Build Coastguard Worker switch (subtable_type) { 1053*2d1272b8SAndroid Build Coastguard Worker case Rearrangement: return_trace (c->dispatch (u.rearrangement, std::forward<Ts> (ds)...)); 1054*2d1272b8SAndroid Build Coastguard Worker case Contextual: return_trace (c->dispatch (u.contextual, std::forward<Ts> (ds)...)); 1055*2d1272b8SAndroid Build Coastguard Worker case Ligature: return_trace (c->dispatch (u.ligature, std::forward<Ts> (ds)...)); 1056*2d1272b8SAndroid Build Coastguard Worker case Noncontextual: return_trace (c->dispatch (u.noncontextual, std::forward<Ts> (ds)...)); 1057*2d1272b8SAndroid Build Coastguard Worker case Insertion: return_trace (c->dispatch (u.insertion, std::forward<Ts> (ds)...)); 1058*2d1272b8SAndroid Build Coastguard Worker default: return_trace (c->default_return_value ()); 1059*2d1272b8SAndroid Build Coastguard Worker } 1060*2d1272b8SAndroid Build Coastguard Worker } 1061*2d1272b8SAndroid Build Coastguard Worker applyAAT::ChainSubtable1062*2d1272b8SAndroid Build Coastguard Worker bool apply (hb_aat_apply_context_t *c) const 1063*2d1272b8SAndroid Build Coastguard Worker { 1064*2d1272b8SAndroid Build Coastguard Worker TRACE_APPLY (this); 1065*2d1272b8SAndroid Build Coastguard Worker // Disabled for https://github.com/harfbuzz/harfbuzz/issues/4873 1066*2d1272b8SAndroid Build Coastguard Worker //hb_sanitize_with_object_t with (&c->sanitizer, this); 1067*2d1272b8SAndroid Build Coastguard Worker return_trace (dispatch (c)); 1068*2d1272b8SAndroid Build Coastguard Worker } 1069*2d1272b8SAndroid Build Coastguard Worker sanitizeAAT::ChainSubtable1070*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c) const 1071*2d1272b8SAndroid Build Coastguard Worker { 1072*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 1073*2d1272b8SAndroid Build Coastguard Worker if (!(length.sanitize (c) && 1074*2d1272b8SAndroid Build Coastguard Worker hb_barrier () && 1075*2d1272b8SAndroid Build Coastguard Worker length >= min_size && 1076*2d1272b8SAndroid Build Coastguard Worker c->check_range (this, length))) 1077*2d1272b8SAndroid Build Coastguard Worker return_trace (false); 1078*2d1272b8SAndroid Build Coastguard Worker 1079*2d1272b8SAndroid Build Coastguard Worker // Disabled for https://github.com/harfbuzz/harfbuzz/issues/4873 1080*2d1272b8SAndroid Build Coastguard Worker //hb_sanitize_with_object_t with (c, this); 1081*2d1272b8SAndroid Build Coastguard Worker return_trace (dispatch (c)); 1082*2d1272b8SAndroid Build Coastguard Worker } 1083*2d1272b8SAndroid Build Coastguard Worker 1084*2d1272b8SAndroid Build Coastguard Worker protected: 1085*2d1272b8SAndroid Build Coastguard Worker HBUINT length; /* Total subtable length, including this header. */ 1086*2d1272b8SAndroid Build Coastguard Worker HBUINT coverage; /* Coverage flags and subtable type. */ 1087*2d1272b8SAndroid Build Coastguard Worker HBUINT32 subFeatureFlags;/* The 32-bit mask identifying which subtable this is. */ 1088*2d1272b8SAndroid Build Coastguard Worker union { 1089*2d1272b8SAndroid Build Coastguard Worker RearrangementSubtable<Types> rearrangement; 1090*2d1272b8SAndroid Build Coastguard Worker ContextualSubtable<Types> contextual; 1091*2d1272b8SAndroid Build Coastguard Worker LigatureSubtable<Types> ligature; 1092*2d1272b8SAndroid Build Coastguard Worker NoncontextualSubtable<Types> noncontextual; 1093*2d1272b8SAndroid Build Coastguard Worker InsertionSubtable<Types> insertion; 1094*2d1272b8SAndroid Build Coastguard Worker } u; 1095*2d1272b8SAndroid Build Coastguard Worker public: 1096*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_MIN (2 * sizeof (HBUINT) + 4); 1097*2d1272b8SAndroid Build Coastguard Worker }; 1098*2d1272b8SAndroid Build Coastguard Worker 1099*2d1272b8SAndroid Build Coastguard Worker template <typename Types> 1100*2d1272b8SAndroid Build Coastguard Worker struct Chain 1101*2d1272b8SAndroid Build Coastguard Worker { 1102*2d1272b8SAndroid Build Coastguard Worker typedef typename Types::HBUINT HBUINT; 1103*2d1272b8SAndroid Build Coastguard Worker get_subtable_countAAT::Chain1104*2d1272b8SAndroid Build Coastguard Worker unsigned get_subtable_count () const { return subtableCount; } 1105*2d1272b8SAndroid Build Coastguard Worker compile_flagsAAT::Chain1106*2d1272b8SAndroid Build Coastguard Worker hb_mask_t compile_flags (const hb_aat_map_builder_t *map) const 1107*2d1272b8SAndroid Build Coastguard Worker { 1108*2d1272b8SAndroid Build Coastguard Worker hb_mask_t flags = defaultFlags; 1109*2d1272b8SAndroid Build Coastguard Worker { 1110*2d1272b8SAndroid Build Coastguard Worker unsigned int count = featureCount; 1111*2d1272b8SAndroid Build Coastguard Worker for (unsigned i = 0; i < count; i++) 1112*2d1272b8SAndroid Build Coastguard Worker { 1113*2d1272b8SAndroid Build Coastguard Worker const Feature &feature = featureZ[i]; 1114*2d1272b8SAndroid Build Coastguard Worker hb_aat_layout_feature_type_t type = (hb_aat_layout_feature_type_t) (unsigned int) feature.featureType; 1115*2d1272b8SAndroid Build Coastguard Worker hb_aat_layout_feature_selector_t setting = (hb_aat_layout_feature_selector_t) (unsigned int) feature.featureSetting; 1116*2d1272b8SAndroid Build Coastguard Worker retry: 1117*2d1272b8SAndroid Build Coastguard Worker // Check whether this type/setting pair was requested in the map, and if so, apply its flags. 1118*2d1272b8SAndroid Build Coastguard Worker // (The search here only looks at the type and setting fields of feature_info_t.) 1119*2d1272b8SAndroid Build Coastguard Worker hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 }; 1120*2d1272b8SAndroid Build Coastguard Worker if (map->current_features.bsearch (info)) 1121*2d1272b8SAndroid Build Coastguard Worker { 1122*2d1272b8SAndroid Build Coastguard Worker flags &= feature.disableFlags; 1123*2d1272b8SAndroid Build Coastguard Worker flags |= feature.enableFlags; 1124*2d1272b8SAndroid Build Coastguard Worker } 1125*2d1272b8SAndroid Build Coastguard Worker else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE && setting == HB_AAT_LAYOUT_FEATURE_SELECTOR_SMALL_CAPS) 1126*2d1272b8SAndroid Build Coastguard Worker { 1127*2d1272b8SAndroid Build Coastguard Worker /* Deprecated. https://github.com/harfbuzz/harfbuzz/issues/1342 */ 1128*2d1272b8SAndroid Build Coastguard Worker type = HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE; 1129*2d1272b8SAndroid Build Coastguard Worker setting = HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS; 1130*2d1272b8SAndroid Build Coastguard Worker goto retry; 1131*2d1272b8SAndroid Build Coastguard Worker } 1132*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_NO_AAT 1133*2d1272b8SAndroid Build Coastguard Worker else if (type == HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE && setting && 1134*2d1272b8SAndroid Build Coastguard Worker /* TODO: Rudimentary language matching. */ 1135*2d1272b8SAndroid Build Coastguard Worker hb_language_matches (map->face->table.ltag->get_language (setting - 1), map->props.language)) 1136*2d1272b8SAndroid Build Coastguard Worker { 1137*2d1272b8SAndroid Build Coastguard Worker flags &= feature.disableFlags; 1138*2d1272b8SAndroid Build Coastguard Worker flags |= feature.enableFlags; 1139*2d1272b8SAndroid Build Coastguard Worker } 1140*2d1272b8SAndroid Build Coastguard Worker #endif 1141*2d1272b8SAndroid Build Coastguard Worker } 1142*2d1272b8SAndroid Build Coastguard Worker } 1143*2d1272b8SAndroid Build Coastguard Worker return flags; 1144*2d1272b8SAndroid Build Coastguard Worker } 1145*2d1272b8SAndroid Build Coastguard Worker applyAAT::Chain1146*2d1272b8SAndroid Build Coastguard Worker void apply (hb_aat_apply_context_t *c, 1147*2d1272b8SAndroid Build Coastguard Worker const hb_aat_layout_chain_accelerator_t *accel) const 1148*2d1272b8SAndroid Build Coastguard Worker { 1149*2d1272b8SAndroid Build Coastguard Worker const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount)); 1150*2d1272b8SAndroid Build Coastguard Worker unsigned int count = subtableCount; 1151*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < count; i++) 1152*2d1272b8SAndroid Build Coastguard Worker { 1153*2d1272b8SAndroid Build Coastguard Worker bool reverse; 1154*2d1272b8SAndroid Build Coastguard Worker 1155*2d1272b8SAndroid Build Coastguard Worker if (hb_none (hb_iter (c->range_flags) | 1156*2d1272b8SAndroid Build Coastguard Worker hb_map ([&subtable] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable->subFeatureFlags & (_.flags); }))) 1157*2d1272b8SAndroid Build Coastguard Worker goto skip; 1158*2d1272b8SAndroid Build Coastguard Worker c->subtable_flags = subtable->subFeatureFlags; 1159*2d1272b8SAndroid Build Coastguard Worker c->machine_glyph_set = accel ? accel->subtables[i].digest : hb_set_digest_t::full (); 1160*2d1272b8SAndroid Build Coastguard Worker 1161*2d1272b8SAndroid Build Coastguard Worker if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) && 1162*2d1272b8SAndroid Build Coastguard Worker HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) != 1163*2d1272b8SAndroid Build Coastguard Worker bool (subtable->get_coverage() & ChainSubtable<Types>::Vertical)) 1164*2d1272b8SAndroid Build Coastguard Worker goto skip; 1165*2d1272b8SAndroid Build Coastguard Worker 1166*2d1272b8SAndroid Build Coastguard Worker /* Buffer contents is always in logical direction. Determine if 1167*2d1272b8SAndroid Build Coastguard Worker * we need to reverse before applying this subtable. We reverse 1168*2d1272b8SAndroid Build Coastguard Worker * back after if we did reverse indeed. 1169*2d1272b8SAndroid Build Coastguard Worker * 1170*2d1272b8SAndroid Build Coastguard Worker * Quoting the spac: 1171*2d1272b8SAndroid Build Coastguard Worker * """ 1172*2d1272b8SAndroid Build Coastguard Worker * Bits 28 and 30 of the coverage field control the order in which 1173*2d1272b8SAndroid Build Coastguard Worker * glyphs are processed when the subtable is run by the layout engine. 1174*2d1272b8SAndroid Build Coastguard Worker * Bit 28 is used to indicate if the glyph processing direction is 1175*2d1272b8SAndroid Build Coastguard Worker * the same as logical order or layout order. Bit 30 is used to 1176*2d1272b8SAndroid Build Coastguard Worker * indicate whether glyphs are processed forwards or backwards within 1177*2d1272b8SAndroid Build Coastguard Worker * that order. 1178*2d1272b8SAndroid Build Coastguard Worker 1179*2d1272b8SAndroid Build Coastguard Worker Bit 30 Bit 28 Interpretation for Horizontal Text 1180*2d1272b8SAndroid Build Coastguard Worker 0 0 The subtable is processed in layout order 1181*2d1272b8SAndroid Build Coastguard Worker (the same order as the glyphs, which is 1182*2d1272b8SAndroid Build Coastguard Worker always left-to-right). 1183*2d1272b8SAndroid Build Coastguard Worker 1 0 The subtable is processed in reverse layout order 1184*2d1272b8SAndroid Build Coastguard Worker (the order opposite that of the glyphs, which is 1185*2d1272b8SAndroid Build Coastguard Worker always right-to-left). 1186*2d1272b8SAndroid Build Coastguard Worker 0 1 The subtable is processed in logical order 1187*2d1272b8SAndroid Build Coastguard Worker (the same order as the characters, which may be 1188*2d1272b8SAndroid Build Coastguard Worker left-to-right or right-to-left). 1189*2d1272b8SAndroid Build Coastguard Worker 1 1 The subtable is processed in reverse logical order 1190*2d1272b8SAndroid Build Coastguard Worker (the order opposite that of the characters, which 1191*2d1272b8SAndroid Build Coastguard Worker may be right-to-left or left-to-right). 1192*2d1272b8SAndroid Build Coastguard Worker */ 1193*2d1272b8SAndroid Build Coastguard Worker reverse = subtable->get_coverage () & ChainSubtable<Types>::Logical ? 1194*2d1272b8SAndroid Build Coastguard Worker bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) : 1195*2d1272b8SAndroid Build Coastguard Worker bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) != 1196*2d1272b8SAndroid Build Coastguard Worker HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction); 1197*2d1272b8SAndroid Build Coastguard Worker 1198*2d1272b8SAndroid Build Coastguard Worker if (!c->buffer->message (c->font, "start chainsubtable %u", c->lookup_index)) 1199*2d1272b8SAndroid Build Coastguard Worker goto skip; 1200*2d1272b8SAndroid Build Coastguard Worker 1201*2d1272b8SAndroid Build Coastguard Worker if (reverse) 1202*2d1272b8SAndroid Build Coastguard Worker c->buffer->reverse (); 1203*2d1272b8SAndroid Build Coastguard Worker 1204*2d1272b8SAndroid Build Coastguard Worker subtable->apply (c); 1205*2d1272b8SAndroid Build Coastguard Worker 1206*2d1272b8SAndroid Build Coastguard Worker if (reverse) 1207*2d1272b8SAndroid Build Coastguard Worker c->buffer->reverse (); 1208*2d1272b8SAndroid Build Coastguard Worker 1209*2d1272b8SAndroid Build Coastguard Worker (void) c->buffer->message (c->font, "end chainsubtable %u", c->lookup_index); 1210*2d1272b8SAndroid Build Coastguard Worker 1211*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!c->buffer->successful)) return; 1212*2d1272b8SAndroid Build Coastguard Worker 1213*2d1272b8SAndroid Build Coastguard Worker skip: 1214*2d1272b8SAndroid Build Coastguard Worker subtable = &StructAfter<ChainSubtable<Types>> (*subtable); 1215*2d1272b8SAndroid Build Coastguard Worker c->set_lookup_index (c->lookup_index + 1); 1216*2d1272b8SAndroid Build Coastguard Worker } 1217*2d1272b8SAndroid Build Coastguard Worker } 1218*2d1272b8SAndroid Build Coastguard Worker get_sizeAAT::Chain1219*2d1272b8SAndroid Build Coastguard Worker unsigned int get_size () const { return length; } 1220*2d1272b8SAndroid Build Coastguard Worker 1221*2d1272b8SAndroid Build Coastguard Worker template <typename context_t, typename ...Ts> dispatchAAT::Chain1222*2d1272b8SAndroid Build Coastguard Worker typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const 1223*2d1272b8SAndroid Build Coastguard Worker { 1224*2d1272b8SAndroid Build Coastguard Worker const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount)); 1225*2d1272b8SAndroid Build Coastguard Worker unsigned int count = subtableCount; 1226*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < count; i++) 1227*2d1272b8SAndroid Build Coastguard Worker { 1228*2d1272b8SAndroid Build Coastguard Worker typename context_t::return_t ret = subtable->dispatch (c, std::forward<Ts> (ds)...); 1229*2d1272b8SAndroid Build Coastguard Worker if (c->stop_sublookup_iteration (ret)) 1230*2d1272b8SAndroid Build Coastguard Worker return ret; 1231*2d1272b8SAndroid Build Coastguard Worker subtable = &StructAfter<ChainSubtable<Types>> (*subtable); 1232*2d1272b8SAndroid Build Coastguard Worker } 1233*2d1272b8SAndroid Build Coastguard Worker return c->default_return_value (); 1234*2d1272b8SAndroid Build Coastguard Worker } 1235*2d1272b8SAndroid Build Coastguard Worker sanitizeAAT::Chain1236*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c, unsigned int version) const 1237*2d1272b8SAndroid Build Coastguard Worker { 1238*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 1239*2d1272b8SAndroid Build Coastguard Worker if (!(length.sanitize (c) && 1240*2d1272b8SAndroid Build Coastguard Worker hb_barrier () && 1241*2d1272b8SAndroid Build Coastguard Worker length >= min_size && 1242*2d1272b8SAndroid Build Coastguard Worker c->check_range (this, length))) 1243*2d1272b8SAndroid Build Coastguard Worker return_trace (false); 1244*2d1272b8SAndroid Build Coastguard Worker 1245*2d1272b8SAndroid Build Coastguard Worker if (!c->check_array (featureZ.arrayZ, featureCount)) 1246*2d1272b8SAndroid Build Coastguard Worker return_trace (false); 1247*2d1272b8SAndroid Build Coastguard Worker 1248*2d1272b8SAndroid Build Coastguard Worker const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount)); 1249*2d1272b8SAndroid Build Coastguard Worker unsigned int count = subtableCount; 1250*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < count; i++) 1251*2d1272b8SAndroid Build Coastguard Worker { 1252*2d1272b8SAndroid Build Coastguard Worker if (!subtable->sanitize (c)) 1253*2d1272b8SAndroid Build Coastguard Worker return_trace (false); 1254*2d1272b8SAndroid Build Coastguard Worker hb_barrier (); 1255*2d1272b8SAndroid Build Coastguard Worker subtable = &StructAfter<ChainSubtable<Types>> (*subtable); 1256*2d1272b8SAndroid Build Coastguard Worker } 1257*2d1272b8SAndroid Build Coastguard Worker 1258*2d1272b8SAndroid Build Coastguard Worker if (version >= 3) 1259*2d1272b8SAndroid Build Coastguard Worker { 1260*2d1272b8SAndroid Build Coastguard Worker const SubtableGlyphCoverage *coverage = (const SubtableGlyphCoverage *) subtable; 1261*2d1272b8SAndroid Build Coastguard Worker if (!coverage->sanitize (c, count)) 1262*2d1272b8SAndroid Build Coastguard Worker return_trace (false); 1263*2d1272b8SAndroid Build Coastguard Worker } 1264*2d1272b8SAndroid Build Coastguard Worker 1265*2d1272b8SAndroid Build Coastguard Worker return_trace (true); 1266*2d1272b8SAndroid Build Coastguard Worker } 1267*2d1272b8SAndroid Build Coastguard Worker 1268*2d1272b8SAndroid Build Coastguard Worker protected: 1269*2d1272b8SAndroid Build Coastguard Worker HBUINT32 defaultFlags; /* The default specification for subtables. */ 1270*2d1272b8SAndroid Build Coastguard Worker HBUINT32 length; /* Total byte count, including this header. */ 1271*2d1272b8SAndroid Build Coastguard Worker HBUINT featureCount; /* Number of feature subtable entries. */ 1272*2d1272b8SAndroid Build Coastguard Worker HBUINT subtableCount; /* The number of subtables in the chain. */ 1273*2d1272b8SAndroid Build Coastguard Worker 1274*2d1272b8SAndroid Build Coastguard Worker UnsizedArrayOf<Feature> featureZ; /* Features. */ 1275*2d1272b8SAndroid Build Coastguard Worker /*ChainSubtable firstSubtable;*//* Subtables. */ 1276*2d1272b8SAndroid Build Coastguard Worker /*SubtableGlyphCoverage coverages*//* Only if version >= 3. */ 1277*2d1272b8SAndroid Build Coastguard Worker 1278*2d1272b8SAndroid Build Coastguard Worker public: 1279*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_MIN (8 + 2 * sizeof (HBUINT)); 1280*2d1272b8SAndroid Build Coastguard Worker }; 1281*2d1272b8SAndroid Build Coastguard Worker 1282*2d1272b8SAndroid Build Coastguard Worker 1283*2d1272b8SAndroid Build Coastguard Worker /* 1284*2d1272b8SAndroid Build Coastguard Worker * The 'mort'/'morx' Table 1285*2d1272b8SAndroid Build Coastguard Worker */ 1286*2d1272b8SAndroid Build Coastguard Worker 1287*2d1272b8SAndroid Build Coastguard Worker template <typename T, typename Types, hb_tag_t TAG> 1288*2d1272b8SAndroid Build Coastguard Worker struct mortmorx 1289*2d1272b8SAndroid Build Coastguard Worker { 1290*2d1272b8SAndroid Build Coastguard Worker static constexpr hb_tag_t tableTag = TAG; 1291*2d1272b8SAndroid Build Coastguard Worker has_dataAAT::mortmorx1292*2d1272b8SAndroid Build Coastguard Worker bool has_data () const { return version != 0; } 1293*2d1272b8SAndroid Build Coastguard Worker 1294*2d1272b8SAndroid Build Coastguard Worker struct accelerator_t 1295*2d1272b8SAndroid Build Coastguard Worker { accelerator_tAAT::mortmorx::accelerator_t1296*2d1272b8SAndroid Build Coastguard Worker accelerator_t (hb_face_t *face) 1297*2d1272b8SAndroid Build Coastguard Worker { 1298*2d1272b8SAndroid Build Coastguard Worker hb_sanitize_context_t sc; 1299*2d1272b8SAndroid Build Coastguard Worker this->table = sc.reference_table<T> (face); 1300*2d1272b8SAndroid Build Coastguard Worker 1301*2d1272b8SAndroid Build Coastguard Worker this->chain_count = table->get_chain_count (); 1302*2d1272b8SAndroid Build Coastguard Worker 1303*2d1272b8SAndroid Build Coastguard Worker this->accels = (hb_atomic_ptr_t<hb_aat_layout_chain_accelerator_t> *) hb_calloc (this->chain_count, sizeof (*accels)); 1304*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!this->accels)) 1305*2d1272b8SAndroid Build Coastguard Worker { 1306*2d1272b8SAndroid Build Coastguard Worker this->chain_count = 0; 1307*2d1272b8SAndroid Build Coastguard Worker this->table.destroy (); 1308*2d1272b8SAndroid Build Coastguard Worker this->table = hb_blob_get_empty (); 1309*2d1272b8SAndroid Build Coastguard Worker } 1310*2d1272b8SAndroid Build Coastguard Worker } ~accelerator_tAAT::mortmorx::accelerator_t1311*2d1272b8SAndroid Build Coastguard Worker ~accelerator_t () 1312*2d1272b8SAndroid Build Coastguard Worker { 1313*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < this->chain_count; i++) 1314*2d1272b8SAndroid Build Coastguard Worker hb_free (this->accels[i]); 1315*2d1272b8SAndroid Build Coastguard Worker hb_free (this->accels); 1316*2d1272b8SAndroid Build Coastguard Worker this->table.destroy (); 1317*2d1272b8SAndroid Build Coastguard Worker } 1318*2d1272b8SAndroid Build Coastguard Worker get_blobAAT::mortmorx::accelerator_t1319*2d1272b8SAndroid Build Coastguard Worker hb_blob_t *get_blob () const { return table.get_blob (); } 1320*2d1272b8SAndroid Build Coastguard Worker 1321*2d1272b8SAndroid Build Coastguard Worker template <typename Chain> get_accelAAT::mortmorx::accelerator_t1322*2d1272b8SAndroid Build Coastguard Worker hb_aat_layout_chain_accelerator_t *get_accel (unsigned chain_index, const Chain &chain, unsigned num_glyphs) const 1323*2d1272b8SAndroid Build Coastguard Worker { 1324*2d1272b8SAndroid Build Coastguard Worker if (unlikely (chain_index >= chain_count)) return nullptr; 1325*2d1272b8SAndroid Build Coastguard Worker 1326*2d1272b8SAndroid Build Coastguard Worker retry: 1327*2d1272b8SAndroid Build Coastguard Worker auto *accel = accels[chain_index].get_acquire (); 1328*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!accel)) 1329*2d1272b8SAndroid Build Coastguard Worker { 1330*2d1272b8SAndroid Build Coastguard Worker accel = hb_aat_layout_chain_accelerator_t::create (chain, num_glyphs); 1331*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!accel)) 1332*2d1272b8SAndroid Build Coastguard Worker return nullptr; 1333*2d1272b8SAndroid Build Coastguard Worker 1334*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!accels[chain_index].cmpexch (nullptr, accel))) 1335*2d1272b8SAndroid Build Coastguard Worker { 1336*2d1272b8SAndroid Build Coastguard Worker hb_free (accel); 1337*2d1272b8SAndroid Build Coastguard Worker goto retry; 1338*2d1272b8SAndroid Build Coastguard Worker } 1339*2d1272b8SAndroid Build Coastguard Worker } 1340*2d1272b8SAndroid Build Coastguard Worker 1341*2d1272b8SAndroid Build Coastguard Worker return accel; 1342*2d1272b8SAndroid Build Coastguard Worker } 1343*2d1272b8SAndroid Build Coastguard Worker 1344*2d1272b8SAndroid Build Coastguard Worker hb_blob_ptr_t<T> table; 1345*2d1272b8SAndroid Build Coastguard Worker unsigned int chain_count; 1346*2d1272b8SAndroid Build Coastguard Worker hb_atomic_ptr_t<hb_aat_layout_chain_accelerator_t> *accels; 1347*2d1272b8SAndroid Build Coastguard Worker }; 1348*2d1272b8SAndroid Build Coastguard Worker 1349*2d1272b8SAndroid Build Coastguard Worker compile_flagsAAT::mortmorx1350*2d1272b8SAndroid Build Coastguard Worker void compile_flags (const hb_aat_map_builder_t *mapper, 1351*2d1272b8SAndroid Build Coastguard Worker hb_aat_map_t *map) const 1352*2d1272b8SAndroid Build Coastguard Worker { 1353*2d1272b8SAndroid Build Coastguard Worker const Chain<Types> *chain = &firstChain; 1354*2d1272b8SAndroid Build Coastguard Worker unsigned int count = chainCount; 1355*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!map->chain_flags.resize (count))) 1356*2d1272b8SAndroid Build Coastguard Worker return; 1357*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < count; i++) 1358*2d1272b8SAndroid Build Coastguard Worker { 1359*2d1272b8SAndroid Build Coastguard Worker map->chain_flags[i].push (hb_aat_map_t::range_flags_t {chain->compile_flags (mapper), 1360*2d1272b8SAndroid Build Coastguard Worker mapper->range_first, 1361*2d1272b8SAndroid Build Coastguard Worker mapper->range_last}); 1362*2d1272b8SAndroid Build Coastguard Worker chain = &StructAfter<Chain<Types>> (*chain); 1363*2d1272b8SAndroid Build Coastguard Worker } 1364*2d1272b8SAndroid Build Coastguard Worker } 1365*2d1272b8SAndroid Build Coastguard Worker get_chain_countAAT::mortmorx1366*2d1272b8SAndroid Build Coastguard Worker unsigned get_chain_count () const 1367*2d1272b8SAndroid Build Coastguard Worker { 1368*2d1272b8SAndroid Build Coastguard Worker return chainCount; 1369*2d1272b8SAndroid Build Coastguard Worker } 1370*2d1272b8SAndroid Build Coastguard Worker applyAAT::mortmorx1371*2d1272b8SAndroid Build Coastguard Worker void apply (hb_aat_apply_context_t *c, 1372*2d1272b8SAndroid Build Coastguard Worker const hb_aat_map_t &map, 1373*2d1272b8SAndroid Build Coastguard Worker const accelerator_t &accel) const 1374*2d1272b8SAndroid Build Coastguard Worker { 1375*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!c->buffer->successful)) return; 1376*2d1272b8SAndroid Build Coastguard Worker 1377*2d1272b8SAndroid Build Coastguard Worker c->buffer->unsafe_to_concat (); 1378*2d1272b8SAndroid Build Coastguard Worker 1379*2d1272b8SAndroid Build Coastguard Worker if (c->buffer->len < HB_AAT_BUFFER_DIGEST_THRESHOLD) 1380*2d1272b8SAndroid Build Coastguard Worker c->buffer_digest = c->buffer->digest (); 1381*2d1272b8SAndroid Build Coastguard Worker else 1382*2d1272b8SAndroid Build Coastguard Worker c->buffer_digest = hb_set_digest_t::full (); 1383*2d1272b8SAndroid Build Coastguard Worker 1384*2d1272b8SAndroid Build Coastguard Worker c->set_lookup_index (0); 1385*2d1272b8SAndroid Build Coastguard Worker const Chain<Types> *chain = &firstChain; 1386*2d1272b8SAndroid Build Coastguard Worker unsigned int count = chainCount; 1387*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < count; i++) 1388*2d1272b8SAndroid Build Coastguard Worker { 1389*2d1272b8SAndroid Build Coastguard Worker auto *chain_accel = accel.get_accel (i, *chain, c->face->get_num_glyphs ()); 1390*2d1272b8SAndroid Build Coastguard Worker c->range_flags = &map.chain_flags[i]; 1391*2d1272b8SAndroid Build Coastguard Worker chain->apply (c, chain_accel); 1392*2d1272b8SAndroid Build Coastguard Worker if (unlikely (!c->buffer->successful)) return; 1393*2d1272b8SAndroid Build Coastguard Worker chain = &StructAfter<Chain<Types>> (*chain); 1394*2d1272b8SAndroid Build Coastguard Worker } 1395*2d1272b8SAndroid Build Coastguard Worker } 1396*2d1272b8SAndroid Build Coastguard Worker sanitizeAAT::mortmorx1397*2d1272b8SAndroid Build Coastguard Worker bool sanitize (hb_sanitize_context_t *c) const 1398*2d1272b8SAndroid Build Coastguard Worker { 1399*2d1272b8SAndroid Build Coastguard Worker TRACE_SANITIZE (this); 1400*2d1272b8SAndroid Build Coastguard Worker if (!(version.sanitize (c) && 1401*2d1272b8SAndroid Build Coastguard Worker hb_barrier () && 1402*2d1272b8SAndroid Build Coastguard Worker version && 1403*2d1272b8SAndroid Build Coastguard Worker chainCount.sanitize (c))) 1404*2d1272b8SAndroid Build Coastguard Worker return_trace (false); 1405*2d1272b8SAndroid Build Coastguard Worker 1406*2d1272b8SAndroid Build Coastguard Worker const Chain<Types> *chain = &firstChain; 1407*2d1272b8SAndroid Build Coastguard Worker unsigned int count = chainCount; 1408*2d1272b8SAndroid Build Coastguard Worker for (unsigned int i = 0; i < count; i++) 1409*2d1272b8SAndroid Build Coastguard Worker { 1410*2d1272b8SAndroid Build Coastguard Worker if (!chain->sanitize (c, version)) 1411*2d1272b8SAndroid Build Coastguard Worker return_trace (false); 1412*2d1272b8SAndroid Build Coastguard Worker hb_barrier (); 1413*2d1272b8SAndroid Build Coastguard Worker chain = &StructAfter<Chain<Types>> (*chain); 1414*2d1272b8SAndroid Build Coastguard Worker } 1415*2d1272b8SAndroid Build Coastguard Worker 1416*2d1272b8SAndroid Build Coastguard Worker return_trace (true); 1417*2d1272b8SAndroid Build Coastguard Worker } 1418*2d1272b8SAndroid Build Coastguard Worker 1419*2d1272b8SAndroid Build Coastguard Worker protected: 1420*2d1272b8SAndroid Build Coastguard Worker HBUINT16 version; /* Version number of the glyph metamorphosis table. 1421*2d1272b8SAndroid Build Coastguard Worker * 1, 2, or 3. */ 1422*2d1272b8SAndroid Build Coastguard Worker HBUINT16 unused; /* Set to 0. */ 1423*2d1272b8SAndroid Build Coastguard Worker HBUINT32 chainCount; /* Number of metamorphosis chains contained in this 1424*2d1272b8SAndroid Build Coastguard Worker * table. */ 1425*2d1272b8SAndroid Build Coastguard Worker Chain<Types> firstChain; /* Chains. */ 1426*2d1272b8SAndroid Build Coastguard Worker 1427*2d1272b8SAndroid Build Coastguard Worker public: 1428*2d1272b8SAndroid Build Coastguard Worker DEFINE_SIZE_MIN (8); 1429*2d1272b8SAndroid Build Coastguard Worker }; 1430*2d1272b8SAndroid Build Coastguard Worker 1431*2d1272b8SAndroid Build Coastguard Worker struct morx : mortmorx<morx, ExtendedTypes, HB_AAT_TAG_morx> {}; 1432*2d1272b8SAndroid Build Coastguard Worker struct mort : mortmorx<mort, ObsoleteTypes, HB_AAT_TAG_mort> {}; 1433*2d1272b8SAndroid Build Coastguard Worker 1434*2d1272b8SAndroid Build Coastguard Worker struct morx_accelerator_t : morx::accelerator_t { morx_accelerator_tAAT::morx_accelerator_t1435*2d1272b8SAndroid Build Coastguard Worker morx_accelerator_t (hb_face_t *face) : morx::accelerator_t (face) {} 1436*2d1272b8SAndroid Build Coastguard Worker }; 1437*2d1272b8SAndroid Build Coastguard Worker struct mort_accelerator_t : mort::accelerator_t { mort_accelerator_tAAT::mort_accelerator_t1438*2d1272b8SAndroid Build Coastguard Worker mort_accelerator_t (hb_face_t *face) : mort::accelerator_t (face) {} 1439*2d1272b8SAndroid Build Coastguard Worker }; 1440*2d1272b8SAndroid Build Coastguard Worker 1441*2d1272b8SAndroid Build Coastguard Worker 1442*2d1272b8SAndroid Build Coastguard Worker } /* namespace AAT */ 1443*2d1272b8SAndroid Build Coastguard Worker 1444*2d1272b8SAndroid Build Coastguard Worker 1445*2d1272b8SAndroid Build Coastguard Worker #endif /* HB_AAT_LAYOUT_MORX_TABLE_HH */ 1446