1*2d1272b8SAndroid Build Coastguard Worker /* 2*2d1272b8SAndroid Build Coastguard Worker * Copyright © 2022 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): Garret Rieger 25*2d1272b8SAndroid Build Coastguard Worker */ 26*2d1272b8SAndroid Build Coastguard Worker 27*2d1272b8SAndroid Build Coastguard Worker #include "graph.hh" 28*2d1272b8SAndroid Build Coastguard Worker #include "../hb-ot-layout-gsubgpos.hh" 29*2d1272b8SAndroid Build Coastguard Worker #include "../OT/Layout/GSUB/ExtensionSubst.hh" 30*2d1272b8SAndroid Build Coastguard Worker #include "gsubgpos-context.hh" 31*2d1272b8SAndroid Build Coastguard Worker #include "pairpos-graph.hh" 32*2d1272b8SAndroid Build Coastguard Worker #include "markbasepos-graph.hh" 33*2d1272b8SAndroid Build Coastguard Worker 34*2d1272b8SAndroid Build Coastguard Worker #ifndef GRAPH_GSUBGPOS_GRAPH_HH 35*2d1272b8SAndroid Build Coastguard Worker #define GRAPH_GSUBGPOS_GRAPH_HH 36*2d1272b8SAndroid Build Coastguard Worker 37*2d1272b8SAndroid Build Coastguard Worker namespace graph { 38*2d1272b8SAndroid Build Coastguard Worker 39*2d1272b8SAndroid Build Coastguard Worker struct Lookup; 40*2d1272b8SAndroid Build Coastguard Worker 41*2d1272b8SAndroid Build Coastguard Worker template<typename T> 42*2d1272b8SAndroid Build Coastguard Worker struct ExtensionFormat1 : public OT::ExtensionFormat1<T> 43*2d1272b8SAndroid Build Coastguard Worker { resetgraph::ExtensionFormat144*2d1272b8SAndroid Build Coastguard Worker void reset(unsigned type) 45*2d1272b8SAndroid Build Coastguard Worker { 46*2d1272b8SAndroid Build Coastguard Worker this->format = 1; 47*2d1272b8SAndroid Build Coastguard Worker this->extensionLookupType = type; 48*2d1272b8SAndroid Build Coastguard Worker this->extensionOffset = 0; 49*2d1272b8SAndroid Build Coastguard Worker } 50*2d1272b8SAndroid Build Coastguard Worker sanitizegraph::ExtensionFormat151*2d1272b8SAndroid Build Coastguard Worker bool sanitize (graph_t::vertex_t& vertex) const 52*2d1272b8SAndroid Build Coastguard Worker { 53*2d1272b8SAndroid Build Coastguard Worker int64_t vertex_len = vertex.obj.tail - vertex.obj.head; 54*2d1272b8SAndroid Build Coastguard Worker return vertex_len >= OT::ExtensionFormat1<T>::static_size; 55*2d1272b8SAndroid Build Coastguard Worker } 56*2d1272b8SAndroid Build Coastguard Worker get_lookup_typegraph::ExtensionFormat157*2d1272b8SAndroid Build Coastguard Worker unsigned get_lookup_type () const 58*2d1272b8SAndroid Build Coastguard Worker { 59*2d1272b8SAndroid Build Coastguard Worker return this->extensionLookupType; 60*2d1272b8SAndroid Build Coastguard Worker } 61*2d1272b8SAndroid Build Coastguard Worker get_subtable_indexgraph::ExtensionFormat162*2d1272b8SAndroid Build Coastguard Worker unsigned get_subtable_index (graph_t& graph, unsigned this_index) const 63*2d1272b8SAndroid Build Coastguard Worker { 64*2d1272b8SAndroid Build Coastguard Worker return graph.index_for_offset (this_index, &this->extensionOffset); 65*2d1272b8SAndroid Build Coastguard Worker } 66*2d1272b8SAndroid Build Coastguard Worker }; 67*2d1272b8SAndroid Build Coastguard Worker 68*2d1272b8SAndroid Build Coastguard Worker struct Lookup : public OT::Lookup 69*2d1272b8SAndroid Build Coastguard Worker { number_of_subtablesgraph::Lookup70*2d1272b8SAndroid Build Coastguard Worker unsigned number_of_subtables () const 71*2d1272b8SAndroid Build Coastguard Worker { 72*2d1272b8SAndroid Build Coastguard Worker return subTable.len; 73*2d1272b8SAndroid Build Coastguard Worker } 74*2d1272b8SAndroid Build Coastguard Worker sanitizegraph::Lookup75*2d1272b8SAndroid Build Coastguard Worker bool sanitize (graph_t::vertex_t& vertex) const 76*2d1272b8SAndroid Build Coastguard Worker { 77*2d1272b8SAndroid Build Coastguard Worker int64_t vertex_len = vertex.obj.tail - vertex.obj.head; 78*2d1272b8SAndroid Build Coastguard Worker if (vertex_len < OT::Lookup::min_size) return false; 79*2d1272b8SAndroid Build Coastguard Worker hb_barrier (); 80*2d1272b8SAndroid Build Coastguard Worker return vertex_len >= this->get_size (); 81*2d1272b8SAndroid Build Coastguard Worker } 82*2d1272b8SAndroid Build Coastguard Worker is_extensiongraph::Lookup83*2d1272b8SAndroid Build Coastguard Worker bool is_extension (hb_tag_t table_tag) const 84*2d1272b8SAndroid Build Coastguard Worker { 85*2d1272b8SAndroid Build Coastguard Worker return lookupType == extension_type (table_tag); 86*2d1272b8SAndroid Build Coastguard Worker } 87*2d1272b8SAndroid Build Coastguard Worker make_extensiongraph::Lookup88*2d1272b8SAndroid Build Coastguard Worker bool make_extension (gsubgpos_graph_context_t& c, 89*2d1272b8SAndroid Build Coastguard Worker unsigned this_index) 90*2d1272b8SAndroid Build Coastguard Worker { 91*2d1272b8SAndroid Build Coastguard Worker unsigned type = lookupType; 92*2d1272b8SAndroid Build Coastguard Worker unsigned ext_type = extension_type (c.table_tag); 93*2d1272b8SAndroid Build Coastguard Worker if (!ext_type || is_extension (c.table_tag)) 94*2d1272b8SAndroid Build Coastguard Worker { 95*2d1272b8SAndroid Build Coastguard Worker // NOOP 96*2d1272b8SAndroid Build Coastguard Worker return true; 97*2d1272b8SAndroid Build Coastguard Worker } 98*2d1272b8SAndroid Build Coastguard Worker 99*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG (SUBSET_REPACK, nullptr, 100*2d1272b8SAndroid Build Coastguard Worker "Promoting lookup type %u (obj %u) to extension.", 101*2d1272b8SAndroid Build Coastguard Worker type, 102*2d1272b8SAndroid Build Coastguard Worker this_index); 103*2d1272b8SAndroid Build Coastguard Worker 104*2d1272b8SAndroid Build Coastguard Worker for (unsigned i = 0; i < subTable.len; i++) 105*2d1272b8SAndroid Build Coastguard Worker { 106*2d1272b8SAndroid Build Coastguard Worker unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]); 107*2d1272b8SAndroid Build Coastguard Worker if (!make_subtable_extension (c, 108*2d1272b8SAndroid Build Coastguard Worker this_index, 109*2d1272b8SAndroid Build Coastguard Worker subtable_index)) 110*2d1272b8SAndroid Build Coastguard Worker return false; 111*2d1272b8SAndroid Build Coastguard Worker } 112*2d1272b8SAndroid Build Coastguard Worker 113*2d1272b8SAndroid Build Coastguard Worker lookupType = ext_type; 114*2d1272b8SAndroid Build Coastguard Worker return true; 115*2d1272b8SAndroid Build Coastguard Worker } 116*2d1272b8SAndroid Build Coastguard Worker split_subtables_if_neededgraph::Lookup117*2d1272b8SAndroid Build Coastguard Worker bool split_subtables_if_needed (gsubgpos_graph_context_t& c, 118*2d1272b8SAndroid Build Coastguard Worker unsigned this_index) 119*2d1272b8SAndroid Build Coastguard Worker { 120*2d1272b8SAndroid Build Coastguard Worker unsigned type = lookupType; 121*2d1272b8SAndroid Build Coastguard Worker bool is_ext = is_extension (c.table_tag); 122*2d1272b8SAndroid Build Coastguard Worker 123*2d1272b8SAndroid Build Coastguard Worker if (c.table_tag != HB_OT_TAG_GPOS) 124*2d1272b8SAndroid Build Coastguard Worker return true; 125*2d1272b8SAndroid Build Coastguard Worker 126*2d1272b8SAndroid Build Coastguard Worker if (!is_ext && 127*2d1272b8SAndroid Build Coastguard Worker type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair && 128*2d1272b8SAndroid Build Coastguard Worker type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::MarkBase) 129*2d1272b8SAndroid Build Coastguard Worker return true; 130*2d1272b8SAndroid Build Coastguard Worker 131*2d1272b8SAndroid Build Coastguard Worker hb_vector_t<hb_pair_t<unsigned, hb_vector_t<unsigned>>> all_new_subtables; 132*2d1272b8SAndroid Build Coastguard Worker for (unsigned i = 0; i < subTable.len; i++) 133*2d1272b8SAndroid Build Coastguard Worker { 134*2d1272b8SAndroid Build Coastguard Worker unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]); 135*2d1272b8SAndroid Build Coastguard Worker unsigned parent_index = this_index; 136*2d1272b8SAndroid Build Coastguard Worker if (is_ext) { 137*2d1272b8SAndroid Build Coastguard Worker unsigned ext_subtable_index = subtable_index; 138*2d1272b8SAndroid Build Coastguard Worker parent_index = ext_subtable_index; 139*2d1272b8SAndroid Build Coastguard Worker ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>* extension = 140*2d1272b8SAndroid Build Coastguard Worker (ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>*) 141*2d1272b8SAndroid Build Coastguard Worker c.graph.object (ext_subtable_index).head; 142*2d1272b8SAndroid Build Coastguard Worker if (!extension || !extension->sanitize (c.graph.vertices_[ext_subtable_index])) 143*2d1272b8SAndroid Build Coastguard Worker continue; 144*2d1272b8SAndroid Build Coastguard Worker 145*2d1272b8SAndroid Build Coastguard Worker subtable_index = extension->get_subtable_index (c.graph, ext_subtable_index); 146*2d1272b8SAndroid Build Coastguard Worker type = extension->get_lookup_type (); 147*2d1272b8SAndroid Build Coastguard Worker if (type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::Pair 148*2d1272b8SAndroid Build Coastguard Worker && type != OT::Layout::GPOS_impl::PosLookupSubTable::Type::MarkBase) 149*2d1272b8SAndroid Build Coastguard Worker continue; 150*2d1272b8SAndroid Build Coastguard Worker } 151*2d1272b8SAndroid Build Coastguard Worker 152*2d1272b8SAndroid Build Coastguard Worker hb_vector_t<unsigned> new_sub_tables; 153*2d1272b8SAndroid Build Coastguard Worker switch (type) 154*2d1272b8SAndroid Build Coastguard Worker { 155*2d1272b8SAndroid Build Coastguard Worker case 2: 156*2d1272b8SAndroid Build Coastguard Worker new_sub_tables = split_subtable<PairPos> (c, parent_index, subtable_index); break; 157*2d1272b8SAndroid Build Coastguard Worker case 4: 158*2d1272b8SAndroid Build Coastguard Worker new_sub_tables = split_subtable<MarkBasePos> (c, parent_index, subtable_index); break; 159*2d1272b8SAndroid Build Coastguard Worker default: 160*2d1272b8SAndroid Build Coastguard Worker break; 161*2d1272b8SAndroid Build Coastguard Worker } 162*2d1272b8SAndroid Build Coastguard Worker if (new_sub_tables.in_error ()) return false; 163*2d1272b8SAndroid Build Coastguard Worker if (!new_sub_tables) continue; 164*2d1272b8SAndroid Build Coastguard Worker hb_pair_t<unsigned, hb_vector_t<unsigned>>* entry = all_new_subtables.push (); 165*2d1272b8SAndroid Build Coastguard Worker entry->first = i; 166*2d1272b8SAndroid Build Coastguard Worker entry->second = std::move (new_sub_tables); 167*2d1272b8SAndroid Build Coastguard Worker } 168*2d1272b8SAndroid Build Coastguard Worker 169*2d1272b8SAndroid Build Coastguard Worker if (all_new_subtables) { 170*2d1272b8SAndroid Build Coastguard Worker return add_sub_tables (c, this_index, type, all_new_subtables); 171*2d1272b8SAndroid Build Coastguard Worker } 172*2d1272b8SAndroid Build Coastguard Worker 173*2d1272b8SAndroid Build Coastguard Worker return true; 174*2d1272b8SAndroid Build Coastguard Worker } 175*2d1272b8SAndroid Build Coastguard Worker 176*2d1272b8SAndroid Build Coastguard Worker template<typename T> split_subtablegraph::Lookup177*2d1272b8SAndroid Build Coastguard Worker hb_vector_t<unsigned> split_subtable (gsubgpos_graph_context_t& c, 178*2d1272b8SAndroid Build Coastguard Worker unsigned parent_idx, 179*2d1272b8SAndroid Build Coastguard Worker unsigned objidx) 180*2d1272b8SAndroid Build Coastguard Worker { 181*2d1272b8SAndroid Build Coastguard Worker T* sub_table = (T*) c.graph.object (objidx).head; 182*2d1272b8SAndroid Build Coastguard Worker if (!sub_table || !sub_table->sanitize (c.graph.vertices_[objidx])) 183*2d1272b8SAndroid Build Coastguard Worker return hb_vector_t<unsigned> (); 184*2d1272b8SAndroid Build Coastguard Worker 185*2d1272b8SAndroid Build Coastguard Worker return sub_table->split_subtables (c, parent_idx, objidx); 186*2d1272b8SAndroid Build Coastguard Worker } 187*2d1272b8SAndroid Build Coastguard Worker add_sub_tablesgraph::Lookup188*2d1272b8SAndroid Build Coastguard Worker bool add_sub_tables (gsubgpos_graph_context_t& c, 189*2d1272b8SAndroid Build Coastguard Worker unsigned this_index, 190*2d1272b8SAndroid Build Coastguard Worker unsigned type, 191*2d1272b8SAndroid Build Coastguard Worker hb_vector_t<hb_pair_t<unsigned, hb_vector_t<unsigned>>>& subtable_ids) 192*2d1272b8SAndroid Build Coastguard Worker { 193*2d1272b8SAndroid Build Coastguard Worker bool is_ext = is_extension (c.table_tag); 194*2d1272b8SAndroid Build Coastguard Worker auto& v = c.graph.vertices_[this_index]; 195*2d1272b8SAndroid Build Coastguard Worker fix_existing_subtable_links (c, this_index, subtable_ids); 196*2d1272b8SAndroid Build Coastguard Worker 197*2d1272b8SAndroid Build Coastguard Worker unsigned new_subtable_count = 0; 198*2d1272b8SAndroid Build Coastguard Worker for (const auto& p : subtable_ids) 199*2d1272b8SAndroid Build Coastguard Worker new_subtable_count += p.second.length; 200*2d1272b8SAndroid Build Coastguard Worker 201*2d1272b8SAndroid Build Coastguard Worker size_t new_size = v.table_size () 202*2d1272b8SAndroid Build Coastguard Worker + new_subtable_count * OT::Offset16::static_size; 203*2d1272b8SAndroid Build Coastguard Worker char* buffer = (char*) hb_calloc (1, new_size); 204*2d1272b8SAndroid Build Coastguard Worker if (!buffer) return false; 205*2d1272b8SAndroid Build Coastguard Worker if (!c.add_buffer (buffer)) 206*2d1272b8SAndroid Build Coastguard Worker { 207*2d1272b8SAndroid Build Coastguard Worker hb_free (buffer); 208*2d1272b8SAndroid Build Coastguard Worker return false; 209*2d1272b8SAndroid Build Coastguard Worker } 210*2d1272b8SAndroid Build Coastguard Worker hb_memcpy (buffer, v.obj.head, v.table_size()); 211*2d1272b8SAndroid Build Coastguard Worker 212*2d1272b8SAndroid Build Coastguard Worker v.obj.head = buffer; 213*2d1272b8SAndroid Build Coastguard Worker v.obj.tail = buffer + new_size; 214*2d1272b8SAndroid Build Coastguard Worker 215*2d1272b8SAndroid Build Coastguard Worker Lookup* new_lookup = (Lookup*) buffer; 216*2d1272b8SAndroid Build Coastguard Worker 217*2d1272b8SAndroid Build Coastguard Worker unsigned shift = 0; 218*2d1272b8SAndroid Build Coastguard Worker new_lookup->subTable.len = subTable.len + new_subtable_count; 219*2d1272b8SAndroid Build Coastguard Worker for (const auto& p : subtable_ids) 220*2d1272b8SAndroid Build Coastguard Worker { 221*2d1272b8SAndroid Build Coastguard Worker unsigned offset_index = p.first + shift + 1; 222*2d1272b8SAndroid Build Coastguard Worker shift += p.second.length; 223*2d1272b8SAndroid Build Coastguard Worker 224*2d1272b8SAndroid Build Coastguard Worker for (unsigned subtable_id : p.second) 225*2d1272b8SAndroid Build Coastguard Worker { 226*2d1272b8SAndroid Build Coastguard Worker if (is_ext) 227*2d1272b8SAndroid Build Coastguard Worker { 228*2d1272b8SAndroid Build Coastguard Worker unsigned ext_id = create_extension_subtable (c, subtable_id, type); 229*2d1272b8SAndroid Build Coastguard Worker c.graph.vertices_[subtable_id].add_parent (ext_id); 230*2d1272b8SAndroid Build Coastguard Worker subtable_id = ext_id; 231*2d1272b8SAndroid Build Coastguard Worker } 232*2d1272b8SAndroid Build Coastguard Worker 233*2d1272b8SAndroid Build Coastguard Worker auto* link = v.obj.real_links.push (); 234*2d1272b8SAndroid Build Coastguard Worker link->width = 2; 235*2d1272b8SAndroid Build Coastguard Worker link->objidx = subtable_id; 236*2d1272b8SAndroid Build Coastguard Worker link->position = (char*) &new_lookup->subTable[offset_index++] - 237*2d1272b8SAndroid Build Coastguard Worker (char*) new_lookup; 238*2d1272b8SAndroid Build Coastguard Worker c.graph.vertices_[subtable_id].add_parent (this_index); 239*2d1272b8SAndroid Build Coastguard Worker } 240*2d1272b8SAndroid Build Coastguard Worker } 241*2d1272b8SAndroid Build Coastguard Worker 242*2d1272b8SAndroid Build Coastguard Worker // Repacker sort order depends on link order, which we've messed up so resort it. 243*2d1272b8SAndroid Build Coastguard Worker v.obj.real_links.qsort (); 244*2d1272b8SAndroid Build Coastguard Worker 245*2d1272b8SAndroid Build Coastguard Worker // The head location of the lookup has changed, invalidating the lookups map entry 246*2d1272b8SAndroid Build Coastguard Worker // in the context. Update the map. 247*2d1272b8SAndroid Build Coastguard Worker c.lookups.set (this_index, new_lookup); 248*2d1272b8SAndroid Build Coastguard Worker return true; 249*2d1272b8SAndroid Build Coastguard Worker } 250*2d1272b8SAndroid Build Coastguard Worker fix_existing_subtable_linksgraph::Lookup251*2d1272b8SAndroid Build Coastguard Worker void fix_existing_subtable_links (gsubgpos_graph_context_t& c, 252*2d1272b8SAndroid Build Coastguard Worker unsigned this_index, 253*2d1272b8SAndroid Build Coastguard Worker hb_vector_t<hb_pair_t<unsigned, hb_vector_t<unsigned>>>& subtable_ids) 254*2d1272b8SAndroid Build Coastguard Worker { 255*2d1272b8SAndroid Build Coastguard Worker auto& v = c.graph.vertices_[this_index]; 256*2d1272b8SAndroid Build Coastguard Worker Lookup* lookup = (Lookup*) v.obj.head; 257*2d1272b8SAndroid Build Coastguard Worker 258*2d1272b8SAndroid Build Coastguard Worker unsigned shift = 0; 259*2d1272b8SAndroid Build Coastguard Worker for (const auto& p : subtable_ids) 260*2d1272b8SAndroid Build Coastguard Worker { 261*2d1272b8SAndroid Build Coastguard Worker unsigned insert_index = p.first + shift; 262*2d1272b8SAndroid Build Coastguard Worker unsigned pos_offset = p.second.length * OT::Offset16::static_size; 263*2d1272b8SAndroid Build Coastguard Worker unsigned insert_offset = (char*) &lookup->subTable[insert_index] - (char*) lookup; 264*2d1272b8SAndroid Build Coastguard Worker shift += p.second.length; 265*2d1272b8SAndroid Build Coastguard Worker 266*2d1272b8SAndroid Build Coastguard Worker for (auto& l : v.obj.all_links_writer ()) 267*2d1272b8SAndroid Build Coastguard Worker { 268*2d1272b8SAndroid Build Coastguard Worker if (l.position > insert_offset) l.position += pos_offset; 269*2d1272b8SAndroid Build Coastguard Worker } 270*2d1272b8SAndroid Build Coastguard Worker } 271*2d1272b8SAndroid Build Coastguard Worker } 272*2d1272b8SAndroid Build Coastguard Worker create_extension_subtablegraph::Lookup273*2d1272b8SAndroid Build Coastguard Worker unsigned create_extension_subtable (gsubgpos_graph_context_t& c, 274*2d1272b8SAndroid Build Coastguard Worker unsigned subtable_index, 275*2d1272b8SAndroid Build Coastguard Worker unsigned type) 276*2d1272b8SAndroid Build Coastguard Worker { 277*2d1272b8SAndroid Build Coastguard Worker unsigned extension_size = OT::ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>::static_size; 278*2d1272b8SAndroid Build Coastguard Worker 279*2d1272b8SAndroid Build Coastguard Worker unsigned ext_index = c.create_node (extension_size); 280*2d1272b8SAndroid Build Coastguard Worker if (ext_index == (unsigned) -1) 281*2d1272b8SAndroid Build Coastguard Worker return -1; 282*2d1272b8SAndroid Build Coastguard Worker 283*2d1272b8SAndroid Build Coastguard Worker auto& ext_vertex = c.graph.vertices_[ext_index]; 284*2d1272b8SAndroid Build Coastguard Worker ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>* extension = 285*2d1272b8SAndroid Build Coastguard Worker (ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>*) ext_vertex.obj.head; 286*2d1272b8SAndroid Build Coastguard Worker extension->reset (type); 287*2d1272b8SAndroid Build Coastguard Worker 288*2d1272b8SAndroid Build Coastguard Worker // Make extension point at the subtable. 289*2d1272b8SAndroid Build Coastguard Worker auto* l = ext_vertex.obj.real_links.push (); 290*2d1272b8SAndroid Build Coastguard Worker 291*2d1272b8SAndroid Build Coastguard Worker l->width = 4; 292*2d1272b8SAndroid Build Coastguard Worker l->objidx = subtable_index; 293*2d1272b8SAndroid Build Coastguard Worker l->position = 4; 294*2d1272b8SAndroid Build Coastguard Worker 295*2d1272b8SAndroid Build Coastguard Worker return ext_index; 296*2d1272b8SAndroid Build Coastguard Worker } 297*2d1272b8SAndroid Build Coastguard Worker make_subtable_extensiongraph::Lookup298*2d1272b8SAndroid Build Coastguard Worker bool make_subtable_extension (gsubgpos_graph_context_t& c, 299*2d1272b8SAndroid Build Coastguard Worker unsigned lookup_index, 300*2d1272b8SAndroid Build Coastguard Worker unsigned subtable_index) 301*2d1272b8SAndroid Build Coastguard Worker { 302*2d1272b8SAndroid Build Coastguard Worker unsigned type = lookupType; 303*2d1272b8SAndroid Build Coastguard Worker unsigned ext_index = -1; 304*2d1272b8SAndroid Build Coastguard Worker unsigned* existing_ext_index = nullptr; 305*2d1272b8SAndroid Build Coastguard Worker if (c.subtable_to_extension.has(subtable_index, &existing_ext_index)) { 306*2d1272b8SAndroid Build Coastguard Worker ext_index = *existing_ext_index; 307*2d1272b8SAndroid Build Coastguard Worker } else { 308*2d1272b8SAndroid Build Coastguard Worker ext_index = create_extension_subtable(c, subtable_index, type); 309*2d1272b8SAndroid Build Coastguard Worker c.subtable_to_extension.set(subtable_index, ext_index); 310*2d1272b8SAndroid Build Coastguard Worker } 311*2d1272b8SAndroid Build Coastguard Worker 312*2d1272b8SAndroid Build Coastguard Worker if (ext_index == (unsigned) -1) 313*2d1272b8SAndroid Build Coastguard Worker return false; 314*2d1272b8SAndroid Build Coastguard Worker 315*2d1272b8SAndroid Build Coastguard Worker auto& subtable_vertex = c.graph.vertices_[subtable_index]; 316*2d1272b8SAndroid Build Coastguard Worker auto& lookup_vertex = c.graph.vertices_[lookup_index]; 317*2d1272b8SAndroid Build Coastguard Worker for (auto& l : lookup_vertex.obj.real_links.writer ()) 318*2d1272b8SAndroid Build Coastguard Worker { 319*2d1272b8SAndroid Build Coastguard Worker if (l.objidx == subtable_index) { 320*2d1272b8SAndroid Build Coastguard Worker // Change lookup to point at the extension. 321*2d1272b8SAndroid Build Coastguard Worker l.objidx = ext_index; 322*2d1272b8SAndroid Build Coastguard Worker if (existing_ext_index) 323*2d1272b8SAndroid Build Coastguard Worker subtable_vertex.remove_parent(lookup_index); 324*2d1272b8SAndroid Build Coastguard Worker } 325*2d1272b8SAndroid Build Coastguard Worker } 326*2d1272b8SAndroid Build Coastguard Worker 327*2d1272b8SAndroid Build Coastguard Worker // Make extension point at the subtable. 328*2d1272b8SAndroid Build Coastguard Worker auto& ext_vertex = c.graph.vertices_[ext_index]; 329*2d1272b8SAndroid Build Coastguard Worker ext_vertex.add_parent (lookup_index); 330*2d1272b8SAndroid Build Coastguard Worker if (!existing_ext_index) 331*2d1272b8SAndroid Build Coastguard Worker subtable_vertex.remap_parent (lookup_index, ext_index); 332*2d1272b8SAndroid Build Coastguard Worker 333*2d1272b8SAndroid Build Coastguard Worker return true; 334*2d1272b8SAndroid Build Coastguard Worker } 335*2d1272b8SAndroid Build Coastguard Worker 336*2d1272b8SAndroid Build Coastguard Worker private: extension_typegraph::Lookup337*2d1272b8SAndroid Build Coastguard Worker unsigned extension_type (hb_tag_t table_tag) const 338*2d1272b8SAndroid Build Coastguard Worker { 339*2d1272b8SAndroid Build Coastguard Worker switch (table_tag) 340*2d1272b8SAndroid Build Coastguard Worker { 341*2d1272b8SAndroid Build Coastguard Worker case HB_OT_TAG_GPOS: return 9; 342*2d1272b8SAndroid Build Coastguard Worker case HB_OT_TAG_GSUB: return 7; 343*2d1272b8SAndroid Build Coastguard Worker default: return 0; 344*2d1272b8SAndroid Build Coastguard Worker } 345*2d1272b8SAndroid Build Coastguard Worker } 346*2d1272b8SAndroid Build Coastguard Worker }; 347*2d1272b8SAndroid Build Coastguard Worker 348*2d1272b8SAndroid Build Coastguard Worker template <typename T> 349*2d1272b8SAndroid Build Coastguard Worker struct LookupList : public OT::LookupList<T> 350*2d1272b8SAndroid Build Coastguard Worker { sanitizegraph::LookupList351*2d1272b8SAndroid Build Coastguard Worker bool sanitize (const graph_t::vertex_t& vertex) const 352*2d1272b8SAndroid Build Coastguard Worker { 353*2d1272b8SAndroid Build Coastguard Worker int64_t vertex_len = vertex.obj.tail - vertex.obj.head; 354*2d1272b8SAndroid Build Coastguard Worker if (vertex_len < OT::LookupList<T>::min_size) return false; 355*2d1272b8SAndroid Build Coastguard Worker hb_barrier (); 356*2d1272b8SAndroid Build Coastguard Worker return vertex_len >= OT::LookupList<T>::item_size * this->len; 357*2d1272b8SAndroid Build Coastguard Worker } 358*2d1272b8SAndroid Build Coastguard Worker }; 359*2d1272b8SAndroid Build Coastguard Worker 360*2d1272b8SAndroid Build Coastguard Worker struct GSTAR : public OT::GSUBGPOS 361*2d1272b8SAndroid Build Coastguard Worker { graph_to_gstargraph::GSTAR362*2d1272b8SAndroid Build Coastguard Worker static GSTAR* graph_to_gstar (graph_t& graph) 363*2d1272b8SAndroid Build Coastguard Worker { 364*2d1272b8SAndroid Build Coastguard Worker const auto& r = graph.root (); 365*2d1272b8SAndroid Build Coastguard Worker 366*2d1272b8SAndroid Build Coastguard Worker GSTAR* gstar = (GSTAR*) r.obj.head; 367*2d1272b8SAndroid Build Coastguard Worker if (!gstar || !gstar->sanitize (r)) 368*2d1272b8SAndroid Build Coastguard Worker return nullptr; 369*2d1272b8SAndroid Build Coastguard Worker hb_barrier (); 370*2d1272b8SAndroid Build Coastguard Worker 371*2d1272b8SAndroid Build Coastguard Worker return gstar; 372*2d1272b8SAndroid Build Coastguard Worker } 373*2d1272b8SAndroid Build Coastguard Worker get_lookup_list_field_offsetgraph::GSTAR374*2d1272b8SAndroid Build Coastguard Worker const void* get_lookup_list_field_offset () const 375*2d1272b8SAndroid Build Coastguard Worker { 376*2d1272b8SAndroid Build Coastguard Worker switch (u.version.major) { 377*2d1272b8SAndroid Build Coastguard Worker case 1: return u.version1.get_lookup_list_offset (); 378*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_NO_BEYOND_64K 379*2d1272b8SAndroid Build Coastguard Worker case 2: return u.version2.get_lookup_list_offset (); 380*2d1272b8SAndroid Build Coastguard Worker #endif 381*2d1272b8SAndroid Build Coastguard Worker default: return 0; 382*2d1272b8SAndroid Build Coastguard Worker } 383*2d1272b8SAndroid Build Coastguard Worker } 384*2d1272b8SAndroid Build Coastguard Worker sanitizegraph::GSTAR385*2d1272b8SAndroid Build Coastguard Worker bool sanitize (const graph_t::vertex_t& vertex) 386*2d1272b8SAndroid Build Coastguard Worker { 387*2d1272b8SAndroid Build Coastguard Worker int64_t len = vertex.obj.tail - vertex.obj.head; 388*2d1272b8SAndroid Build Coastguard Worker if (len < OT::GSUBGPOS::min_size) return false; 389*2d1272b8SAndroid Build Coastguard Worker hb_barrier (); 390*2d1272b8SAndroid Build Coastguard Worker return len >= get_size (); 391*2d1272b8SAndroid Build Coastguard Worker } 392*2d1272b8SAndroid Build Coastguard Worker find_lookupsgraph::GSTAR393*2d1272b8SAndroid Build Coastguard Worker void find_lookups (graph_t& graph, 394*2d1272b8SAndroid Build Coastguard Worker hb_hashmap_t<unsigned, Lookup*>& lookups /* OUT */) 395*2d1272b8SAndroid Build Coastguard Worker { 396*2d1272b8SAndroid Build Coastguard Worker switch (u.version.major) { 397*2d1272b8SAndroid Build Coastguard Worker case 1: find_lookups<SmallTypes> (graph, lookups); break; 398*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_NO_BEYOND_64K 399*2d1272b8SAndroid Build Coastguard Worker case 2: find_lookups<MediumTypes> (graph, lookups); break; 400*2d1272b8SAndroid Build Coastguard Worker #endif 401*2d1272b8SAndroid Build Coastguard Worker } 402*2d1272b8SAndroid Build Coastguard Worker } 403*2d1272b8SAndroid Build Coastguard Worker get_lookup_list_indexgraph::GSTAR404*2d1272b8SAndroid Build Coastguard Worker unsigned get_lookup_list_index (graph_t& graph) 405*2d1272b8SAndroid Build Coastguard Worker { 406*2d1272b8SAndroid Build Coastguard Worker return graph.index_for_offset (graph.root_idx (), 407*2d1272b8SAndroid Build Coastguard Worker get_lookup_list_field_offset()); 408*2d1272b8SAndroid Build Coastguard Worker } 409*2d1272b8SAndroid Build Coastguard Worker 410*2d1272b8SAndroid Build Coastguard Worker template<typename Types> find_lookupsgraph::GSTAR411*2d1272b8SAndroid Build Coastguard Worker void find_lookups (graph_t& graph, 412*2d1272b8SAndroid Build Coastguard Worker hb_hashmap_t<unsigned, Lookup*>& lookups /* OUT */) 413*2d1272b8SAndroid Build Coastguard Worker { 414*2d1272b8SAndroid Build Coastguard Worker unsigned lookup_list_idx = get_lookup_list_index (graph); 415*2d1272b8SAndroid Build Coastguard Worker const LookupList<Types>* lookupList = 416*2d1272b8SAndroid Build Coastguard Worker (const LookupList<Types>*) graph.object (lookup_list_idx).head; 417*2d1272b8SAndroid Build Coastguard Worker if (!lookupList || !lookupList->sanitize (graph.vertices_[lookup_list_idx])) 418*2d1272b8SAndroid Build Coastguard Worker return; 419*2d1272b8SAndroid Build Coastguard Worker 420*2d1272b8SAndroid Build Coastguard Worker for (unsigned i = 0; i < lookupList->len; i++) 421*2d1272b8SAndroid Build Coastguard Worker { 422*2d1272b8SAndroid Build Coastguard Worker unsigned lookup_idx = graph.index_for_offset (lookup_list_idx, &(lookupList->arrayZ[i])); 423*2d1272b8SAndroid Build Coastguard Worker Lookup* lookup = (Lookup*) graph.object (lookup_idx).head; 424*2d1272b8SAndroid Build Coastguard Worker if (!lookup || !lookup->sanitize (graph.vertices_[lookup_idx])) continue; 425*2d1272b8SAndroid Build Coastguard Worker lookups.set (lookup_idx, lookup); 426*2d1272b8SAndroid Build Coastguard Worker } 427*2d1272b8SAndroid Build Coastguard Worker } 428*2d1272b8SAndroid Build Coastguard Worker }; 429*2d1272b8SAndroid Build Coastguard Worker 430*2d1272b8SAndroid Build Coastguard Worker 431*2d1272b8SAndroid Build Coastguard Worker 432*2d1272b8SAndroid Build Coastguard Worker 433*2d1272b8SAndroid Build Coastguard Worker } 434*2d1272b8SAndroid Build Coastguard Worker 435*2d1272b8SAndroid Build Coastguard Worker #endif /* GRAPH_GSUBGPOS_GRAPH_HH */ 436