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 #ifndef GRAPH_PAIRPOS_GRAPH_HH 28*2d1272b8SAndroid Build Coastguard Worker #define GRAPH_PAIRPOS_GRAPH_HH 29*2d1272b8SAndroid Build Coastguard Worker 30*2d1272b8SAndroid Build Coastguard Worker #include "split-helpers.hh" 31*2d1272b8SAndroid Build Coastguard Worker #include "coverage-graph.hh" 32*2d1272b8SAndroid Build Coastguard Worker #include "classdef-graph.hh" 33*2d1272b8SAndroid Build Coastguard Worker #include "../OT/Layout/GPOS/PairPos.hh" 34*2d1272b8SAndroid Build Coastguard Worker #include "../OT/Layout/GPOS/PosLookupSubTable.hh" 35*2d1272b8SAndroid Build Coastguard Worker 36*2d1272b8SAndroid Build Coastguard Worker namespace graph { 37*2d1272b8SAndroid Build Coastguard Worker 38*2d1272b8SAndroid Build Coastguard Worker struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes> 39*2d1272b8SAndroid Build Coastguard Worker { sanitizegraph::PairPosFormat140*2d1272b8SAndroid Build Coastguard Worker bool sanitize (graph_t::vertex_t& vertex) const 41*2d1272b8SAndroid Build Coastguard Worker { 42*2d1272b8SAndroid Build Coastguard Worker int64_t vertex_len = vertex.obj.tail - vertex.obj.head; 43*2d1272b8SAndroid Build Coastguard Worker unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size; 44*2d1272b8SAndroid Build Coastguard Worker if (vertex_len < min_size) return false; 45*2d1272b8SAndroid Build Coastguard Worker hb_barrier (); 46*2d1272b8SAndroid Build Coastguard Worker 47*2d1272b8SAndroid Build Coastguard Worker return vertex_len >= 48*2d1272b8SAndroid Build Coastguard Worker min_size + pairSet.get_size () - pairSet.len.get_size(); 49*2d1272b8SAndroid Build Coastguard Worker } 50*2d1272b8SAndroid Build Coastguard Worker split_subtablesgraph::PairPosFormat151*2d1272b8SAndroid Build Coastguard Worker hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, 52*2d1272b8SAndroid Build Coastguard Worker unsigned parent_index, 53*2d1272b8SAndroid Build Coastguard Worker unsigned this_index) 54*2d1272b8SAndroid Build Coastguard Worker { 55*2d1272b8SAndroid Build Coastguard Worker hb_set_t visited; 56*2d1272b8SAndroid Build Coastguard Worker 57*2d1272b8SAndroid Build Coastguard Worker const unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage); 58*2d1272b8SAndroid Build Coastguard Worker const unsigned coverage_size = c.graph.vertices_[coverage_id].table_size (); 59*2d1272b8SAndroid Build Coastguard Worker const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size; 60*2d1272b8SAndroid Build Coastguard Worker 61*2d1272b8SAndroid Build Coastguard Worker unsigned partial_coverage_size = 4; 62*2d1272b8SAndroid Build Coastguard Worker unsigned accumulated = base_size; 63*2d1272b8SAndroid Build Coastguard Worker hb_vector_t<unsigned> split_points; 64*2d1272b8SAndroid Build Coastguard Worker for (unsigned i = 0; i < pairSet.len; i++) 65*2d1272b8SAndroid Build Coastguard Worker { 66*2d1272b8SAndroid Build Coastguard Worker unsigned pair_set_index = pair_set_graph_index (c, this_index, i); 67*2d1272b8SAndroid Build Coastguard Worker unsigned accumulated_delta = 68*2d1272b8SAndroid Build Coastguard Worker c.graph.find_subgraph_size (pair_set_index, visited) + 69*2d1272b8SAndroid Build Coastguard Worker SmallTypes::size; // for PairSet offset. 70*2d1272b8SAndroid Build Coastguard Worker partial_coverage_size += OT::HBUINT16::static_size; 71*2d1272b8SAndroid Build Coastguard Worker 72*2d1272b8SAndroid Build Coastguard Worker accumulated += accumulated_delta; 73*2d1272b8SAndroid Build Coastguard Worker unsigned total = accumulated + hb_min (partial_coverage_size, coverage_size); 74*2d1272b8SAndroid Build Coastguard Worker 75*2d1272b8SAndroid Build Coastguard Worker if (total >= (1 << 16)) 76*2d1272b8SAndroid Build Coastguard Worker { 77*2d1272b8SAndroid Build Coastguard Worker split_points.push (i); 78*2d1272b8SAndroid Build Coastguard Worker accumulated = base_size + accumulated_delta; 79*2d1272b8SAndroid Build Coastguard Worker partial_coverage_size = 6; 80*2d1272b8SAndroid Build Coastguard Worker visited.clear (); // node sharing isn't allowed between splits. 81*2d1272b8SAndroid Build Coastguard Worker } 82*2d1272b8SAndroid Build Coastguard Worker } 83*2d1272b8SAndroid Build Coastguard Worker 84*2d1272b8SAndroid Build Coastguard Worker split_context_t split_context { 85*2d1272b8SAndroid Build Coastguard Worker c, 86*2d1272b8SAndroid Build Coastguard Worker this, 87*2d1272b8SAndroid Build Coastguard Worker c.graph.duplicate_if_shared (parent_index, this_index), 88*2d1272b8SAndroid Build Coastguard Worker }; 89*2d1272b8SAndroid Build Coastguard Worker 90*2d1272b8SAndroid Build Coastguard Worker return actuate_subtable_split<split_context_t> (split_context, split_points); 91*2d1272b8SAndroid Build Coastguard Worker } 92*2d1272b8SAndroid Build Coastguard Worker 93*2d1272b8SAndroid Build Coastguard Worker private: 94*2d1272b8SAndroid Build Coastguard Worker 95*2d1272b8SAndroid Build Coastguard Worker struct split_context_t { 96*2d1272b8SAndroid Build Coastguard Worker gsubgpos_graph_context_t& c; 97*2d1272b8SAndroid Build Coastguard Worker PairPosFormat1* thiz; 98*2d1272b8SAndroid Build Coastguard Worker unsigned this_index; 99*2d1272b8SAndroid Build Coastguard Worker original_countgraph::PairPosFormat1::split_context_t100*2d1272b8SAndroid Build Coastguard Worker unsigned original_count () 101*2d1272b8SAndroid Build Coastguard Worker { 102*2d1272b8SAndroid Build Coastguard Worker return thiz->pairSet.len; 103*2d1272b8SAndroid Build Coastguard Worker } 104*2d1272b8SAndroid Build Coastguard Worker clone_rangegraph::PairPosFormat1::split_context_t105*2d1272b8SAndroid Build Coastguard Worker unsigned clone_range (unsigned start, unsigned end) 106*2d1272b8SAndroid Build Coastguard Worker { 107*2d1272b8SAndroid Build Coastguard Worker return thiz->clone_range (this->c, this->this_index, start, end); 108*2d1272b8SAndroid Build Coastguard Worker } 109*2d1272b8SAndroid Build Coastguard Worker shrinkgraph::PairPosFormat1::split_context_t110*2d1272b8SAndroid Build Coastguard Worker bool shrink (unsigned count) 111*2d1272b8SAndroid Build Coastguard Worker { 112*2d1272b8SAndroid Build Coastguard Worker return thiz->shrink (this->c, this->this_index, count); 113*2d1272b8SAndroid Build Coastguard Worker } 114*2d1272b8SAndroid Build Coastguard Worker }; 115*2d1272b8SAndroid Build Coastguard Worker shrinkgraph::PairPosFormat1116*2d1272b8SAndroid Build Coastguard Worker bool shrink (gsubgpos_graph_context_t& c, 117*2d1272b8SAndroid Build Coastguard Worker unsigned this_index, 118*2d1272b8SAndroid Build Coastguard Worker unsigned count) 119*2d1272b8SAndroid Build Coastguard Worker { 120*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG (SUBSET_REPACK, nullptr, 121*2d1272b8SAndroid Build Coastguard Worker " Shrinking PairPosFormat1 (%u) to [0, %u).", 122*2d1272b8SAndroid Build Coastguard Worker this_index, 123*2d1272b8SAndroid Build Coastguard Worker count); 124*2d1272b8SAndroid Build Coastguard Worker unsigned old_count = pairSet.len; 125*2d1272b8SAndroid Build Coastguard Worker if (count >= old_count) 126*2d1272b8SAndroid Build Coastguard Worker return true; 127*2d1272b8SAndroid Build Coastguard Worker 128*2d1272b8SAndroid Build Coastguard Worker pairSet.len = count; 129*2d1272b8SAndroid Build Coastguard Worker c.graph.vertices_[this_index].obj.tail -= (old_count - count) * SmallTypes::size; 130*2d1272b8SAndroid Build Coastguard Worker 131*2d1272b8SAndroid Build Coastguard Worker auto coverage = c.graph.as_mutable_table<Coverage> (this_index, &this->coverage); 132*2d1272b8SAndroid Build Coastguard Worker if (!coverage) return false; 133*2d1272b8SAndroid Build Coastguard Worker 134*2d1272b8SAndroid Build Coastguard Worker unsigned coverage_size = coverage.vertex->table_size (); 135*2d1272b8SAndroid Build Coastguard Worker auto new_coverage = 136*2d1272b8SAndroid Build Coastguard Worker + hb_zip (coverage.table->iter (), hb_range ()) 137*2d1272b8SAndroid Build Coastguard Worker | hb_filter ([&] (hb_pair_t<unsigned, unsigned> p) { 138*2d1272b8SAndroid Build Coastguard Worker return p.second < count; 139*2d1272b8SAndroid Build Coastguard Worker }) 140*2d1272b8SAndroid Build Coastguard Worker | hb_map_retains_sorting (hb_first) 141*2d1272b8SAndroid Build Coastguard Worker ; 142*2d1272b8SAndroid Build Coastguard Worker 143*2d1272b8SAndroid Build Coastguard Worker return Coverage::make_coverage (c, new_coverage, coverage.index, coverage_size); 144*2d1272b8SAndroid Build Coastguard Worker } 145*2d1272b8SAndroid Build Coastguard Worker 146*2d1272b8SAndroid Build Coastguard Worker // Create a new PairPos including PairSet's from start (inclusive) to end (exclusive). 147*2d1272b8SAndroid Build Coastguard Worker // Returns object id of the new object. clone_rangegraph::PairPosFormat1148*2d1272b8SAndroid Build Coastguard Worker unsigned clone_range (gsubgpos_graph_context_t& c, 149*2d1272b8SAndroid Build Coastguard Worker unsigned this_index, 150*2d1272b8SAndroid Build Coastguard Worker unsigned start, unsigned end) const 151*2d1272b8SAndroid Build Coastguard Worker { 152*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG (SUBSET_REPACK, nullptr, 153*2d1272b8SAndroid Build Coastguard Worker " Cloning PairPosFormat1 (%u) range [%u, %u).", this_index, start, end); 154*2d1272b8SAndroid Build Coastguard Worker 155*2d1272b8SAndroid Build Coastguard Worker unsigned num_pair_sets = end - start; 156*2d1272b8SAndroid Build Coastguard Worker unsigned prime_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size 157*2d1272b8SAndroid Build Coastguard Worker + num_pair_sets * SmallTypes::size; 158*2d1272b8SAndroid Build Coastguard Worker 159*2d1272b8SAndroid Build Coastguard Worker unsigned pair_pos_prime_id = c.create_node (prime_size); 160*2d1272b8SAndroid Build Coastguard Worker if (pair_pos_prime_id == (unsigned) -1) return -1; 161*2d1272b8SAndroid Build Coastguard Worker 162*2d1272b8SAndroid Build Coastguard Worker PairPosFormat1* pair_pos_prime = (PairPosFormat1*) c.graph.object (pair_pos_prime_id).head; 163*2d1272b8SAndroid Build Coastguard Worker pair_pos_prime->format = this->format; 164*2d1272b8SAndroid Build Coastguard Worker pair_pos_prime->valueFormat[0] = this->valueFormat[0]; 165*2d1272b8SAndroid Build Coastguard Worker pair_pos_prime->valueFormat[1] = this->valueFormat[1]; 166*2d1272b8SAndroid Build Coastguard Worker pair_pos_prime->pairSet.len = num_pair_sets; 167*2d1272b8SAndroid Build Coastguard Worker 168*2d1272b8SAndroid Build Coastguard Worker for (unsigned i = start; i < end; i++) 169*2d1272b8SAndroid Build Coastguard Worker { 170*2d1272b8SAndroid Build Coastguard Worker c.graph.move_child<> (this_index, 171*2d1272b8SAndroid Build Coastguard Worker &pairSet[i], 172*2d1272b8SAndroid Build Coastguard Worker pair_pos_prime_id, 173*2d1272b8SAndroid Build Coastguard Worker &pair_pos_prime->pairSet[i - start]); 174*2d1272b8SAndroid Build Coastguard Worker } 175*2d1272b8SAndroid Build Coastguard Worker 176*2d1272b8SAndroid Build Coastguard Worker unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage); 177*2d1272b8SAndroid Build Coastguard Worker if (!Coverage::clone_coverage (c, 178*2d1272b8SAndroid Build Coastguard Worker coverage_id, 179*2d1272b8SAndroid Build Coastguard Worker pair_pos_prime_id, 180*2d1272b8SAndroid Build Coastguard Worker 2, 181*2d1272b8SAndroid Build Coastguard Worker start, end)) 182*2d1272b8SAndroid Build Coastguard Worker return -1; 183*2d1272b8SAndroid Build Coastguard Worker 184*2d1272b8SAndroid Build Coastguard Worker return pair_pos_prime_id; 185*2d1272b8SAndroid Build Coastguard Worker } 186*2d1272b8SAndroid Build Coastguard Worker 187*2d1272b8SAndroid Build Coastguard Worker 188*2d1272b8SAndroid Build Coastguard Worker pair_set_graph_indexgraph::PairPosFormat1189*2d1272b8SAndroid Build Coastguard Worker unsigned pair_set_graph_index (gsubgpos_graph_context_t& c, unsigned this_index, unsigned i) const 190*2d1272b8SAndroid Build Coastguard Worker { 191*2d1272b8SAndroid Build Coastguard Worker return c.graph.index_for_offset (this_index, &pairSet[i]); 192*2d1272b8SAndroid Build Coastguard Worker } 193*2d1272b8SAndroid Build Coastguard Worker }; 194*2d1272b8SAndroid Build Coastguard Worker 195*2d1272b8SAndroid Build Coastguard Worker struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes> 196*2d1272b8SAndroid Build Coastguard Worker { sanitizegraph::PairPosFormat2197*2d1272b8SAndroid Build Coastguard Worker bool sanitize (graph_t::vertex_t& vertex) const 198*2d1272b8SAndroid Build Coastguard Worker { 199*2d1272b8SAndroid Build Coastguard Worker size_t vertex_len = vertex.table_size (); 200*2d1272b8SAndroid Build Coastguard Worker unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size; 201*2d1272b8SAndroid Build Coastguard Worker if (vertex_len < min_size) return false; 202*2d1272b8SAndroid Build Coastguard Worker hb_barrier (); 203*2d1272b8SAndroid Build Coastguard Worker 204*2d1272b8SAndroid Build Coastguard Worker const unsigned class1_count = class1Count; 205*2d1272b8SAndroid Build Coastguard Worker return vertex_len >= 206*2d1272b8SAndroid Build Coastguard Worker min_size + class1_count * get_class1_record_size (); 207*2d1272b8SAndroid Build Coastguard Worker } 208*2d1272b8SAndroid Build Coastguard Worker split_subtablesgraph::PairPosFormat2209*2d1272b8SAndroid Build Coastguard Worker hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, 210*2d1272b8SAndroid Build Coastguard Worker unsigned parent_index, 211*2d1272b8SAndroid Build Coastguard Worker unsigned this_index) 212*2d1272b8SAndroid Build Coastguard Worker { 213*2d1272b8SAndroid Build Coastguard Worker const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size; 214*2d1272b8SAndroid Build Coastguard Worker const unsigned class_def_2_size = size_of (c, this_index, &classDef2); 215*2d1272b8SAndroid Build Coastguard Worker const Coverage* coverage = get_coverage (c, this_index); 216*2d1272b8SAndroid Build Coastguard Worker const ClassDef* class_def_1 = get_class_def_1 (c, this_index); 217*2d1272b8SAndroid Build Coastguard Worker auto gid_and_class = 218*2d1272b8SAndroid Build Coastguard Worker + coverage->iter () 219*2d1272b8SAndroid Build Coastguard Worker | hb_map_retains_sorting ([&] (hb_codepoint_t gid) { 220*2d1272b8SAndroid Build Coastguard Worker return hb_codepoint_pair_t (gid, class_def_1->get_class (gid)); 221*2d1272b8SAndroid Build Coastguard Worker }) 222*2d1272b8SAndroid Build Coastguard Worker ; 223*2d1272b8SAndroid Build Coastguard Worker class_def_size_estimator_t estimator (gid_and_class); 224*2d1272b8SAndroid Build Coastguard Worker 225*2d1272b8SAndroid Build Coastguard Worker const unsigned class1_count = class1Count; 226*2d1272b8SAndroid Build Coastguard Worker const unsigned class2_count = class2Count; 227*2d1272b8SAndroid Build Coastguard Worker const unsigned class1_record_size = get_class1_record_size (); 228*2d1272b8SAndroid Build Coastguard Worker 229*2d1272b8SAndroid Build Coastguard Worker const unsigned value_1_len = valueFormat1.get_len (); 230*2d1272b8SAndroid Build Coastguard Worker const unsigned value_2_len = valueFormat2.get_len (); 231*2d1272b8SAndroid Build Coastguard Worker const unsigned total_value_len = value_1_len + value_2_len; 232*2d1272b8SAndroid Build Coastguard Worker 233*2d1272b8SAndroid Build Coastguard Worker unsigned accumulated = base_size; 234*2d1272b8SAndroid Build Coastguard Worker unsigned coverage_size = 4; 235*2d1272b8SAndroid Build Coastguard Worker unsigned class_def_1_size = 4; 236*2d1272b8SAndroid Build Coastguard Worker unsigned max_coverage_size = coverage_size; 237*2d1272b8SAndroid Build Coastguard Worker unsigned max_class_def_1_size = class_def_1_size; 238*2d1272b8SAndroid Build Coastguard Worker 239*2d1272b8SAndroid Build Coastguard Worker hb_vector_t<unsigned> split_points; 240*2d1272b8SAndroid Build Coastguard Worker 241*2d1272b8SAndroid Build Coastguard Worker hb_hashmap_t<unsigned, unsigned> device_tables = get_all_device_tables (c, this_index); 242*2d1272b8SAndroid Build Coastguard Worker hb_vector_t<unsigned> format1_device_table_indices = valueFormat1.get_device_table_indices (); 243*2d1272b8SAndroid Build Coastguard Worker hb_vector_t<unsigned> format2_device_table_indices = valueFormat2.get_device_table_indices (); 244*2d1272b8SAndroid Build Coastguard Worker bool has_device_tables = bool(format1_device_table_indices) || bool(format2_device_table_indices); 245*2d1272b8SAndroid Build Coastguard Worker 246*2d1272b8SAndroid Build Coastguard Worker hb_set_t visited; 247*2d1272b8SAndroid Build Coastguard Worker for (unsigned i = 0; i < class1_count; i++) 248*2d1272b8SAndroid Build Coastguard Worker { 249*2d1272b8SAndroid Build Coastguard Worker unsigned accumulated_delta = class1_record_size; 250*2d1272b8SAndroid Build Coastguard Worker class_def_1_size = estimator.add_class_def_size (i); 251*2d1272b8SAndroid Build Coastguard Worker coverage_size = estimator.coverage_size (); 252*2d1272b8SAndroid Build Coastguard Worker max_coverage_size = hb_max (max_coverage_size, coverage_size); 253*2d1272b8SAndroid Build Coastguard Worker max_class_def_1_size = hb_max (max_class_def_1_size, class_def_1_size); 254*2d1272b8SAndroid Build Coastguard Worker 255*2d1272b8SAndroid Build Coastguard Worker if (has_device_tables) { 256*2d1272b8SAndroid Build Coastguard Worker for (unsigned j = 0; j < class2_count; j++) 257*2d1272b8SAndroid Build Coastguard Worker { 258*2d1272b8SAndroid Build Coastguard Worker unsigned value1_index = total_value_len * (class2_count * i + j); 259*2d1272b8SAndroid Build Coastguard Worker unsigned value2_index = value1_index + value_1_len; 260*2d1272b8SAndroid Build Coastguard Worker accumulated_delta += size_of_value_record_children (c, 261*2d1272b8SAndroid Build Coastguard Worker device_tables, 262*2d1272b8SAndroid Build Coastguard Worker format1_device_table_indices, 263*2d1272b8SAndroid Build Coastguard Worker value1_index, 264*2d1272b8SAndroid Build Coastguard Worker visited); 265*2d1272b8SAndroid Build Coastguard Worker accumulated_delta += size_of_value_record_children (c, 266*2d1272b8SAndroid Build Coastguard Worker device_tables, 267*2d1272b8SAndroid Build Coastguard Worker format2_device_table_indices, 268*2d1272b8SAndroid Build Coastguard Worker value2_index, 269*2d1272b8SAndroid Build Coastguard Worker visited); 270*2d1272b8SAndroid Build Coastguard Worker } 271*2d1272b8SAndroid Build Coastguard Worker } 272*2d1272b8SAndroid Build Coastguard Worker 273*2d1272b8SAndroid Build Coastguard Worker accumulated += accumulated_delta; 274*2d1272b8SAndroid Build Coastguard Worker unsigned total = accumulated 275*2d1272b8SAndroid Build Coastguard Worker + coverage_size + class_def_1_size + class_def_2_size 276*2d1272b8SAndroid Build Coastguard Worker // The largest object will pack last and can exceed the size limit. 277*2d1272b8SAndroid Build Coastguard Worker - hb_max (hb_max (coverage_size, class_def_1_size), class_def_2_size); 278*2d1272b8SAndroid Build Coastguard Worker if (total >= (1 << 16)) 279*2d1272b8SAndroid Build Coastguard Worker { 280*2d1272b8SAndroid Build Coastguard Worker split_points.push (i); 281*2d1272b8SAndroid Build Coastguard Worker // split does not include i, so add the size for i when we reset the size counters. 282*2d1272b8SAndroid Build Coastguard Worker accumulated = base_size + accumulated_delta; 283*2d1272b8SAndroid Build Coastguard Worker 284*2d1272b8SAndroid Build Coastguard Worker estimator.reset(); 285*2d1272b8SAndroid Build Coastguard Worker class_def_1_size = estimator.add_class_def_size(i); 286*2d1272b8SAndroid Build Coastguard Worker coverage_size = estimator.coverage_size(); 287*2d1272b8SAndroid Build Coastguard Worker visited.clear (); // node sharing isn't allowed between splits. 288*2d1272b8SAndroid Build Coastguard Worker } 289*2d1272b8SAndroid Build Coastguard Worker } 290*2d1272b8SAndroid Build Coastguard Worker 291*2d1272b8SAndroid Build Coastguard Worker split_context_t split_context { 292*2d1272b8SAndroid Build Coastguard Worker c, 293*2d1272b8SAndroid Build Coastguard Worker this, 294*2d1272b8SAndroid Build Coastguard Worker c.graph.duplicate_if_shared (parent_index, this_index), 295*2d1272b8SAndroid Build Coastguard Worker class1_record_size, 296*2d1272b8SAndroid Build Coastguard Worker total_value_len, 297*2d1272b8SAndroid Build Coastguard Worker value_1_len, 298*2d1272b8SAndroid Build Coastguard Worker value_2_len, 299*2d1272b8SAndroid Build Coastguard Worker max_coverage_size, 300*2d1272b8SAndroid Build Coastguard Worker max_class_def_1_size, 301*2d1272b8SAndroid Build Coastguard Worker device_tables, 302*2d1272b8SAndroid Build Coastguard Worker format1_device_table_indices, 303*2d1272b8SAndroid Build Coastguard Worker format2_device_table_indices 304*2d1272b8SAndroid Build Coastguard Worker }; 305*2d1272b8SAndroid Build Coastguard Worker 306*2d1272b8SAndroid Build Coastguard Worker return actuate_subtable_split<split_context_t> (split_context, split_points); 307*2d1272b8SAndroid Build Coastguard Worker } 308*2d1272b8SAndroid Build Coastguard Worker private: 309*2d1272b8SAndroid Build Coastguard Worker 310*2d1272b8SAndroid Build Coastguard Worker struct split_context_t 311*2d1272b8SAndroid Build Coastguard Worker { 312*2d1272b8SAndroid Build Coastguard Worker gsubgpos_graph_context_t& c; 313*2d1272b8SAndroid Build Coastguard Worker PairPosFormat2* thiz; 314*2d1272b8SAndroid Build Coastguard Worker unsigned this_index; 315*2d1272b8SAndroid Build Coastguard Worker unsigned class1_record_size; 316*2d1272b8SAndroid Build Coastguard Worker unsigned value_record_len; 317*2d1272b8SAndroid Build Coastguard Worker unsigned value1_record_len; 318*2d1272b8SAndroid Build Coastguard Worker unsigned value2_record_len; 319*2d1272b8SAndroid Build Coastguard Worker unsigned max_coverage_size; 320*2d1272b8SAndroid Build Coastguard Worker unsigned max_class_def_size; 321*2d1272b8SAndroid Build Coastguard Worker 322*2d1272b8SAndroid Build Coastguard Worker const hb_hashmap_t<unsigned, unsigned>& device_tables; 323*2d1272b8SAndroid Build Coastguard Worker const hb_vector_t<unsigned>& format1_device_table_indices; 324*2d1272b8SAndroid Build Coastguard Worker const hb_vector_t<unsigned>& format2_device_table_indices; 325*2d1272b8SAndroid Build Coastguard Worker original_countgraph::PairPosFormat2::split_context_t326*2d1272b8SAndroid Build Coastguard Worker unsigned original_count () 327*2d1272b8SAndroid Build Coastguard Worker { 328*2d1272b8SAndroid Build Coastguard Worker return thiz->class1Count; 329*2d1272b8SAndroid Build Coastguard Worker } 330*2d1272b8SAndroid Build Coastguard Worker clone_rangegraph::PairPosFormat2::split_context_t331*2d1272b8SAndroid Build Coastguard Worker unsigned clone_range (unsigned start, unsigned end) 332*2d1272b8SAndroid Build Coastguard Worker { 333*2d1272b8SAndroid Build Coastguard Worker return thiz->clone_range (*this, start, end); 334*2d1272b8SAndroid Build Coastguard Worker } 335*2d1272b8SAndroid Build Coastguard Worker shrinkgraph::PairPosFormat2::split_context_t336*2d1272b8SAndroid Build Coastguard Worker bool shrink (unsigned count) 337*2d1272b8SAndroid Build Coastguard Worker { 338*2d1272b8SAndroid Build Coastguard Worker return thiz->shrink (*this, count); 339*2d1272b8SAndroid Build Coastguard Worker } 340*2d1272b8SAndroid Build Coastguard Worker }; 341*2d1272b8SAndroid Build Coastguard Worker get_class1_record_sizegraph::PairPosFormat2342*2d1272b8SAndroid Build Coastguard Worker size_t get_class1_record_size () const 343*2d1272b8SAndroid Build Coastguard Worker { 344*2d1272b8SAndroid Build Coastguard Worker const size_t class2_count = class2Count; 345*2d1272b8SAndroid Build Coastguard Worker return 346*2d1272b8SAndroid Build Coastguard Worker class2_count * (valueFormat1.get_size () + valueFormat2.get_size ()); 347*2d1272b8SAndroid Build Coastguard Worker } 348*2d1272b8SAndroid Build Coastguard Worker clone_rangegraph::PairPosFormat2349*2d1272b8SAndroid Build Coastguard Worker unsigned clone_range (split_context_t& split_context, 350*2d1272b8SAndroid Build Coastguard Worker unsigned start, unsigned end) const 351*2d1272b8SAndroid Build Coastguard Worker { 352*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG (SUBSET_REPACK, nullptr, 353*2d1272b8SAndroid Build Coastguard Worker " Cloning PairPosFormat2 (%u) range [%u, %u).", split_context.this_index, start, end); 354*2d1272b8SAndroid Build Coastguard Worker 355*2d1272b8SAndroid Build Coastguard Worker graph_t& graph = split_context.c.graph; 356*2d1272b8SAndroid Build Coastguard Worker 357*2d1272b8SAndroid Build Coastguard Worker unsigned num_records = end - start; 358*2d1272b8SAndroid Build Coastguard Worker unsigned prime_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size 359*2d1272b8SAndroid Build Coastguard Worker + num_records * split_context.class1_record_size; 360*2d1272b8SAndroid Build Coastguard Worker 361*2d1272b8SAndroid Build Coastguard Worker unsigned pair_pos_prime_id = split_context.c.create_node (prime_size); 362*2d1272b8SAndroid Build Coastguard Worker if (pair_pos_prime_id == (unsigned) -1) return -1; 363*2d1272b8SAndroid Build Coastguard Worker 364*2d1272b8SAndroid Build Coastguard Worker PairPosFormat2* pair_pos_prime = 365*2d1272b8SAndroid Build Coastguard Worker (PairPosFormat2*) graph.object (pair_pos_prime_id).head; 366*2d1272b8SAndroid Build Coastguard Worker pair_pos_prime->format = this->format; 367*2d1272b8SAndroid Build Coastguard Worker pair_pos_prime->valueFormat1 = this->valueFormat1; 368*2d1272b8SAndroid Build Coastguard Worker pair_pos_prime->valueFormat2 = this->valueFormat2; 369*2d1272b8SAndroid Build Coastguard Worker pair_pos_prime->class1Count = num_records; 370*2d1272b8SAndroid Build Coastguard Worker pair_pos_prime->class2Count = this->class2Count; 371*2d1272b8SAndroid Build Coastguard Worker clone_class1_records (split_context, 372*2d1272b8SAndroid Build Coastguard Worker pair_pos_prime_id, 373*2d1272b8SAndroid Build Coastguard Worker start, 374*2d1272b8SAndroid Build Coastguard Worker end); 375*2d1272b8SAndroid Build Coastguard Worker 376*2d1272b8SAndroid Build Coastguard Worker unsigned coverage_id = 377*2d1272b8SAndroid Build Coastguard Worker graph.index_for_offset (split_context.this_index, &coverage); 378*2d1272b8SAndroid Build Coastguard Worker unsigned class_def_1_id = 379*2d1272b8SAndroid Build Coastguard Worker graph.index_for_offset (split_context.this_index, &classDef1); 380*2d1272b8SAndroid Build Coastguard Worker auto& coverage_v = graph.vertices_[coverage_id]; 381*2d1272b8SAndroid Build Coastguard Worker auto& class_def_1_v = graph.vertices_[class_def_1_id]; 382*2d1272b8SAndroid Build Coastguard Worker Coverage* coverage_table = (Coverage*) coverage_v.obj.head; 383*2d1272b8SAndroid Build Coastguard Worker ClassDef* class_def_1_table = (ClassDef*) class_def_1_v.obj.head; 384*2d1272b8SAndroid Build Coastguard Worker if (!coverage_table 385*2d1272b8SAndroid Build Coastguard Worker || !coverage_table->sanitize (coverage_v) 386*2d1272b8SAndroid Build Coastguard Worker || !class_def_1_table 387*2d1272b8SAndroid Build Coastguard Worker || !class_def_1_table->sanitize (class_def_1_v)) 388*2d1272b8SAndroid Build Coastguard Worker return -1; 389*2d1272b8SAndroid Build Coastguard Worker 390*2d1272b8SAndroid Build Coastguard Worker auto klass_map = 391*2d1272b8SAndroid Build Coastguard Worker + coverage_table->iter () 392*2d1272b8SAndroid Build Coastguard Worker | hb_map_retains_sorting ([&] (hb_codepoint_t gid) { 393*2d1272b8SAndroid Build Coastguard Worker return hb_codepoint_pair_t (gid, class_def_1_table->get_class (gid)); 394*2d1272b8SAndroid Build Coastguard Worker }) 395*2d1272b8SAndroid Build Coastguard Worker | hb_filter ([&] (hb_codepoint_t klass) { 396*2d1272b8SAndroid Build Coastguard Worker return klass >= start && klass < end; 397*2d1272b8SAndroid Build Coastguard Worker }, hb_second) 398*2d1272b8SAndroid Build Coastguard Worker | hb_map_retains_sorting ([&] (hb_codepoint_pair_t gid_and_class) { 399*2d1272b8SAndroid Build Coastguard Worker // Classes must be from 0...N so subtract start 400*2d1272b8SAndroid Build Coastguard Worker return hb_codepoint_pair_t (gid_and_class.first, gid_and_class.second - start); 401*2d1272b8SAndroid Build Coastguard Worker }) 402*2d1272b8SAndroid Build Coastguard Worker ; 403*2d1272b8SAndroid Build Coastguard Worker 404*2d1272b8SAndroid Build Coastguard Worker if (!Coverage::add_coverage (split_context.c, 405*2d1272b8SAndroid Build Coastguard Worker pair_pos_prime_id, 406*2d1272b8SAndroid Build Coastguard Worker 2, 407*2d1272b8SAndroid Build Coastguard Worker + klass_map | hb_map_retains_sorting (hb_first), 408*2d1272b8SAndroid Build Coastguard Worker split_context.max_coverage_size)) 409*2d1272b8SAndroid Build Coastguard Worker return -1; 410*2d1272b8SAndroid Build Coastguard Worker 411*2d1272b8SAndroid Build Coastguard Worker // classDef1 412*2d1272b8SAndroid Build Coastguard Worker if (!ClassDef::add_class_def (split_context.c, 413*2d1272b8SAndroid Build Coastguard Worker pair_pos_prime_id, 414*2d1272b8SAndroid Build Coastguard Worker 8, 415*2d1272b8SAndroid Build Coastguard Worker + klass_map, 416*2d1272b8SAndroid Build Coastguard Worker split_context.max_class_def_size)) 417*2d1272b8SAndroid Build Coastguard Worker return -1; 418*2d1272b8SAndroid Build Coastguard Worker 419*2d1272b8SAndroid Build Coastguard Worker // classDef2 420*2d1272b8SAndroid Build Coastguard Worker unsigned class_def_2_id = 421*2d1272b8SAndroid Build Coastguard Worker graph.index_for_offset (split_context.this_index, &classDef2); 422*2d1272b8SAndroid Build Coastguard Worker auto* class_def_link = graph.vertices_[pair_pos_prime_id].obj.real_links.push (); 423*2d1272b8SAndroid Build Coastguard Worker class_def_link->width = SmallTypes::size; 424*2d1272b8SAndroid Build Coastguard Worker class_def_link->objidx = class_def_2_id; 425*2d1272b8SAndroid Build Coastguard Worker class_def_link->position = 10; 426*2d1272b8SAndroid Build Coastguard Worker graph.vertices_[class_def_2_id].add_parent (pair_pos_prime_id); 427*2d1272b8SAndroid Build Coastguard Worker graph.duplicate (pair_pos_prime_id, class_def_2_id); 428*2d1272b8SAndroid Build Coastguard Worker 429*2d1272b8SAndroid Build Coastguard Worker return pair_pos_prime_id; 430*2d1272b8SAndroid Build Coastguard Worker } 431*2d1272b8SAndroid Build Coastguard Worker clone_class1_recordsgraph::PairPosFormat2432*2d1272b8SAndroid Build Coastguard Worker void clone_class1_records (split_context_t& split_context, 433*2d1272b8SAndroid Build Coastguard Worker unsigned pair_pos_prime_id, 434*2d1272b8SAndroid Build Coastguard Worker unsigned start, unsigned end) const 435*2d1272b8SAndroid Build Coastguard Worker { 436*2d1272b8SAndroid Build Coastguard Worker PairPosFormat2* pair_pos_prime = 437*2d1272b8SAndroid Build Coastguard Worker (PairPosFormat2*) split_context.c.graph.object (pair_pos_prime_id).head; 438*2d1272b8SAndroid Build Coastguard Worker 439*2d1272b8SAndroid Build Coastguard Worker char* start_addr = ((char*)&values[0]) + start * split_context.class1_record_size; 440*2d1272b8SAndroid Build Coastguard Worker unsigned num_records = end - start; 441*2d1272b8SAndroid Build Coastguard Worker hb_memcpy (&pair_pos_prime->values[0], 442*2d1272b8SAndroid Build Coastguard Worker start_addr, 443*2d1272b8SAndroid Build Coastguard Worker num_records * split_context.class1_record_size); 444*2d1272b8SAndroid Build Coastguard Worker 445*2d1272b8SAndroid Build Coastguard Worker if (!split_context.format1_device_table_indices 446*2d1272b8SAndroid Build Coastguard Worker && !split_context.format2_device_table_indices) 447*2d1272b8SAndroid Build Coastguard Worker // No device tables to move over. 448*2d1272b8SAndroid Build Coastguard Worker return; 449*2d1272b8SAndroid Build Coastguard Worker 450*2d1272b8SAndroid Build Coastguard Worker unsigned class2_count = class2Count; 451*2d1272b8SAndroid Build Coastguard Worker for (unsigned i = start; i < end; i++) 452*2d1272b8SAndroid Build Coastguard Worker { 453*2d1272b8SAndroid Build Coastguard Worker for (unsigned j = 0; j < class2_count; j++) 454*2d1272b8SAndroid Build Coastguard Worker { 455*2d1272b8SAndroid Build Coastguard Worker unsigned value1_index = split_context.value_record_len * (class2_count * i + j); 456*2d1272b8SAndroid Build Coastguard Worker unsigned value2_index = value1_index + split_context.value1_record_len; 457*2d1272b8SAndroid Build Coastguard Worker 458*2d1272b8SAndroid Build Coastguard Worker unsigned new_value1_index = split_context.value_record_len * (class2_count * (i - start) + j); 459*2d1272b8SAndroid Build Coastguard Worker unsigned new_value2_index = new_value1_index + split_context.value1_record_len; 460*2d1272b8SAndroid Build Coastguard Worker 461*2d1272b8SAndroid Build Coastguard Worker transfer_device_tables (split_context, 462*2d1272b8SAndroid Build Coastguard Worker pair_pos_prime_id, 463*2d1272b8SAndroid Build Coastguard Worker split_context.format1_device_table_indices, 464*2d1272b8SAndroid Build Coastguard Worker value1_index, 465*2d1272b8SAndroid Build Coastguard Worker new_value1_index); 466*2d1272b8SAndroid Build Coastguard Worker 467*2d1272b8SAndroid Build Coastguard Worker transfer_device_tables (split_context, 468*2d1272b8SAndroid Build Coastguard Worker pair_pos_prime_id, 469*2d1272b8SAndroid Build Coastguard Worker split_context.format2_device_table_indices, 470*2d1272b8SAndroid Build Coastguard Worker value2_index, 471*2d1272b8SAndroid Build Coastguard Worker new_value2_index); 472*2d1272b8SAndroid Build Coastguard Worker } 473*2d1272b8SAndroid Build Coastguard Worker } 474*2d1272b8SAndroid Build Coastguard Worker } 475*2d1272b8SAndroid Build Coastguard Worker transfer_device_tablesgraph::PairPosFormat2476*2d1272b8SAndroid Build Coastguard Worker void transfer_device_tables (split_context_t& split_context, 477*2d1272b8SAndroid Build Coastguard Worker unsigned pair_pos_prime_id, 478*2d1272b8SAndroid Build Coastguard Worker const hb_vector_t<unsigned>& device_table_indices, 479*2d1272b8SAndroid Build Coastguard Worker unsigned old_value_record_index, 480*2d1272b8SAndroid Build Coastguard Worker unsigned new_value_record_index) const 481*2d1272b8SAndroid Build Coastguard Worker { 482*2d1272b8SAndroid Build Coastguard Worker PairPosFormat2* pair_pos_prime = 483*2d1272b8SAndroid Build Coastguard Worker (PairPosFormat2*) split_context.c.graph.object (pair_pos_prime_id).head; 484*2d1272b8SAndroid Build Coastguard Worker 485*2d1272b8SAndroid Build Coastguard Worker for (unsigned i : device_table_indices) 486*2d1272b8SAndroid Build Coastguard Worker { 487*2d1272b8SAndroid Build Coastguard Worker OT::Offset16* record = (OT::Offset16*) &values[old_value_record_index + i]; 488*2d1272b8SAndroid Build Coastguard Worker unsigned record_position = ((char*) record) - ((char*) this); 489*2d1272b8SAndroid Build Coastguard Worker if (!split_context.device_tables.has (record_position)) continue; 490*2d1272b8SAndroid Build Coastguard Worker 491*2d1272b8SAndroid Build Coastguard Worker split_context.c.graph.move_child ( 492*2d1272b8SAndroid Build Coastguard Worker split_context.this_index, 493*2d1272b8SAndroid Build Coastguard Worker record, 494*2d1272b8SAndroid Build Coastguard Worker pair_pos_prime_id, 495*2d1272b8SAndroid Build Coastguard Worker (OT::Offset16*) &pair_pos_prime->values[new_value_record_index + i]); 496*2d1272b8SAndroid Build Coastguard Worker } 497*2d1272b8SAndroid Build Coastguard Worker } 498*2d1272b8SAndroid Build Coastguard Worker shrinkgraph::PairPosFormat2499*2d1272b8SAndroid Build Coastguard Worker bool shrink (split_context_t& split_context, 500*2d1272b8SAndroid Build Coastguard Worker unsigned count) 501*2d1272b8SAndroid Build Coastguard Worker { 502*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG (SUBSET_REPACK, nullptr, 503*2d1272b8SAndroid Build Coastguard Worker " Shrinking PairPosFormat2 (%u) to [0, %u).", 504*2d1272b8SAndroid Build Coastguard Worker split_context.this_index, 505*2d1272b8SAndroid Build Coastguard Worker count); 506*2d1272b8SAndroid Build Coastguard Worker unsigned old_count = class1Count; 507*2d1272b8SAndroid Build Coastguard Worker if (count >= old_count) 508*2d1272b8SAndroid Build Coastguard Worker return true; 509*2d1272b8SAndroid Build Coastguard Worker 510*2d1272b8SAndroid Build Coastguard Worker graph_t& graph = split_context.c.graph; 511*2d1272b8SAndroid Build Coastguard Worker class1Count = count; 512*2d1272b8SAndroid Build Coastguard Worker graph.vertices_[split_context.this_index].obj.tail -= 513*2d1272b8SAndroid Build Coastguard Worker (old_count - count) * split_context.class1_record_size; 514*2d1272b8SAndroid Build Coastguard Worker 515*2d1272b8SAndroid Build Coastguard Worker auto coverage = 516*2d1272b8SAndroid Build Coastguard Worker graph.as_mutable_table<Coverage> (split_context.this_index, &this->coverage); 517*2d1272b8SAndroid Build Coastguard Worker if (!coverage) return false; 518*2d1272b8SAndroid Build Coastguard Worker 519*2d1272b8SAndroid Build Coastguard Worker auto class_def_1 = 520*2d1272b8SAndroid Build Coastguard Worker graph.as_mutable_table<ClassDef> (split_context.this_index, &classDef1); 521*2d1272b8SAndroid Build Coastguard Worker if (!class_def_1) return false; 522*2d1272b8SAndroid Build Coastguard Worker 523*2d1272b8SAndroid Build Coastguard Worker auto klass_map = 524*2d1272b8SAndroid Build Coastguard Worker + coverage.table->iter () 525*2d1272b8SAndroid Build Coastguard Worker | hb_map_retains_sorting ([&] (hb_codepoint_t gid) { 526*2d1272b8SAndroid Build Coastguard Worker return hb_codepoint_pair_t (gid, class_def_1.table->get_class (gid)); 527*2d1272b8SAndroid Build Coastguard Worker }) 528*2d1272b8SAndroid Build Coastguard Worker | hb_filter ([&] (hb_codepoint_t klass) { 529*2d1272b8SAndroid Build Coastguard Worker return klass < count; 530*2d1272b8SAndroid Build Coastguard Worker }, hb_second) 531*2d1272b8SAndroid Build Coastguard Worker ; 532*2d1272b8SAndroid Build Coastguard Worker 533*2d1272b8SAndroid Build Coastguard Worker auto new_coverage = + klass_map | hb_map_retains_sorting (hb_first); 534*2d1272b8SAndroid Build Coastguard Worker if (!Coverage::make_coverage (split_context.c, 535*2d1272b8SAndroid Build Coastguard Worker + new_coverage, 536*2d1272b8SAndroid Build Coastguard Worker coverage.index, 537*2d1272b8SAndroid Build Coastguard Worker // existing ranges my not be kept, worst case size is a format 1 538*2d1272b8SAndroid Build Coastguard Worker // coverage table. 539*2d1272b8SAndroid Build Coastguard Worker 4 + new_coverage.len() * 2)) 540*2d1272b8SAndroid Build Coastguard Worker return false; 541*2d1272b8SAndroid Build Coastguard Worker 542*2d1272b8SAndroid Build Coastguard Worker return ClassDef::make_class_def (split_context.c, 543*2d1272b8SAndroid Build Coastguard Worker + klass_map, 544*2d1272b8SAndroid Build Coastguard Worker class_def_1.index, 545*2d1272b8SAndroid Build Coastguard Worker class_def_1.vertex->table_size ()); 546*2d1272b8SAndroid Build Coastguard Worker } 547*2d1272b8SAndroid Build Coastguard Worker 548*2d1272b8SAndroid Build Coastguard Worker hb_hashmap_t<unsigned, unsigned> get_all_device_tablesgraph::PairPosFormat2549*2d1272b8SAndroid Build Coastguard Worker get_all_device_tables (gsubgpos_graph_context_t& c, 550*2d1272b8SAndroid Build Coastguard Worker unsigned this_index) const 551*2d1272b8SAndroid Build Coastguard Worker { 552*2d1272b8SAndroid Build Coastguard Worker const auto& v = c.graph.vertices_[this_index]; 553*2d1272b8SAndroid Build Coastguard Worker return v.position_to_index_map (); 554*2d1272b8SAndroid Build Coastguard Worker } 555*2d1272b8SAndroid Build Coastguard Worker get_coveragegraph::PairPosFormat2556*2d1272b8SAndroid Build Coastguard Worker const Coverage* get_coverage (gsubgpos_graph_context_t& c, 557*2d1272b8SAndroid Build Coastguard Worker unsigned this_index) const 558*2d1272b8SAndroid Build Coastguard Worker { 559*2d1272b8SAndroid Build Coastguard Worker unsigned coverage_id = c.graph.index_for_offset (this_index, &coverage); 560*2d1272b8SAndroid Build Coastguard Worker auto& coverage_v = c.graph.vertices_[coverage_id]; 561*2d1272b8SAndroid Build Coastguard Worker 562*2d1272b8SAndroid Build Coastguard Worker Coverage* coverage_table = (Coverage*) coverage_v.obj.head; 563*2d1272b8SAndroid Build Coastguard Worker if (!coverage_table || !coverage_table->sanitize (coverage_v)) 564*2d1272b8SAndroid Build Coastguard Worker return &Null(Coverage); 565*2d1272b8SAndroid Build Coastguard Worker return coverage_table; 566*2d1272b8SAndroid Build Coastguard Worker } 567*2d1272b8SAndroid Build Coastguard Worker get_class_def_1graph::PairPosFormat2568*2d1272b8SAndroid Build Coastguard Worker const ClassDef* get_class_def_1 (gsubgpos_graph_context_t& c, 569*2d1272b8SAndroid Build Coastguard Worker unsigned this_index) const 570*2d1272b8SAndroid Build Coastguard Worker { 571*2d1272b8SAndroid Build Coastguard Worker unsigned class_def_1_id = c.graph.index_for_offset (this_index, &classDef1); 572*2d1272b8SAndroid Build Coastguard Worker auto& class_def_1_v = c.graph.vertices_[class_def_1_id]; 573*2d1272b8SAndroid Build Coastguard Worker 574*2d1272b8SAndroid Build Coastguard Worker ClassDef* class_def_1_table = (ClassDef*) class_def_1_v.obj.head; 575*2d1272b8SAndroid Build Coastguard Worker if (!class_def_1_table || !class_def_1_table->sanitize (class_def_1_v)) 576*2d1272b8SAndroid Build Coastguard Worker return &Null(ClassDef); 577*2d1272b8SAndroid Build Coastguard Worker return class_def_1_table; 578*2d1272b8SAndroid Build Coastguard Worker } 579*2d1272b8SAndroid Build Coastguard Worker size_of_value_record_childrengraph::PairPosFormat2580*2d1272b8SAndroid Build Coastguard Worker unsigned size_of_value_record_children (gsubgpos_graph_context_t& c, 581*2d1272b8SAndroid Build Coastguard Worker const hb_hashmap_t<unsigned, unsigned>& device_tables, 582*2d1272b8SAndroid Build Coastguard Worker const hb_vector_t<unsigned> device_table_indices, 583*2d1272b8SAndroid Build Coastguard Worker unsigned value_record_index, 584*2d1272b8SAndroid Build Coastguard Worker hb_set_t& visited) 585*2d1272b8SAndroid Build Coastguard Worker { 586*2d1272b8SAndroid Build Coastguard Worker unsigned size = 0; 587*2d1272b8SAndroid Build Coastguard Worker for (unsigned i : device_table_indices) 588*2d1272b8SAndroid Build Coastguard Worker { 589*2d1272b8SAndroid Build Coastguard Worker OT::Layout::GPOS_impl::Value* record = &values[value_record_index + i]; 590*2d1272b8SAndroid Build Coastguard Worker unsigned record_position = ((char*) record) - ((char*) this); 591*2d1272b8SAndroid Build Coastguard Worker unsigned* obj_idx; 592*2d1272b8SAndroid Build Coastguard Worker if (!device_tables.has (record_position, &obj_idx)) continue; 593*2d1272b8SAndroid Build Coastguard Worker size += c.graph.find_subgraph_size (*obj_idx, visited); 594*2d1272b8SAndroid Build Coastguard Worker } 595*2d1272b8SAndroid Build Coastguard Worker return size; 596*2d1272b8SAndroid Build Coastguard Worker } 597*2d1272b8SAndroid Build Coastguard Worker size_ofgraph::PairPosFormat2598*2d1272b8SAndroid Build Coastguard Worker unsigned size_of (gsubgpos_graph_context_t& c, 599*2d1272b8SAndroid Build Coastguard Worker unsigned this_index, 600*2d1272b8SAndroid Build Coastguard Worker const void* offset) const 601*2d1272b8SAndroid Build Coastguard Worker { 602*2d1272b8SAndroid Build Coastguard Worker const unsigned id = c.graph.index_for_offset (this_index, offset); 603*2d1272b8SAndroid Build Coastguard Worker return c.graph.vertices_[id].table_size (); 604*2d1272b8SAndroid Build Coastguard Worker } 605*2d1272b8SAndroid Build Coastguard Worker }; 606*2d1272b8SAndroid Build Coastguard Worker 607*2d1272b8SAndroid Build Coastguard Worker struct PairPos : public OT::Layout::GPOS_impl::PairPos 608*2d1272b8SAndroid Build Coastguard Worker { split_subtablesgraph::PairPos609*2d1272b8SAndroid Build Coastguard Worker hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, 610*2d1272b8SAndroid Build Coastguard Worker unsigned parent_index, 611*2d1272b8SAndroid Build Coastguard Worker unsigned this_index) 612*2d1272b8SAndroid Build Coastguard Worker { 613*2d1272b8SAndroid Build Coastguard Worker switch (u.format) { 614*2d1272b8SAndroid Build Coastguard Worker case 1: 615*2d1272b8SAndroid Build Coastguard Worker return ((PairPosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index); 616*2d1272b8SAndroid Build Coastguard Worker case 2: 617*2d1272b8SAndroid Build Coastguard Worker return ((PairPosFormat2*)(&u.format2))->split_subtables (c, parent_index, this_index); 618*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_NO_BEYOND_64K 619*2d1272b8SAndroid Build Coastguard Worker case 3: HB_FALLTHROUGH; 620*2d1272b8SAndroid Build Coastguard Worker case 4: HB_FALLTHROUGH; 621*2d1272b8SAndroid Build Coastguard Worker // Don't split 24bit PairPos's. 622*2d1272b8SAndroid Build Coastguard Worker #endif 623*2d1272b8SAndroid Build Coastguard Worker default: 624*2d1272b8SAndroid Build Coastguard Worker return hb_vector_t<unsigned> (); 625*2d1272b8SAndroid Build Coastguard Worker } 626*2d1272b8SAndroid Build Coastguard Worker } 627*2d1272b8SAndroid Build Coastguard Worker sanitizegraph::PairPos628*2d1272b8SAndroid Build Coastguard Worker bool sanitize (graph_t::vertex_t& vertex) const 629*2d1272b8SAndroid Build Coastguard Worker { 630*2d1272b8SAndroid Build Coastguard Worker int64_t vertex_len = vertex.obj.tail - vertex.obj.head; 631*2d1272b8SAndroid Build Coastguard Worker if (vertex_len < u.format.get_size ()) return false; 632*2d1272b8SAndroid Build Coastguard Worker hb_barrier (); 633*2d1272b8SAndroid Build Coastguard Worker 634*2d1272b8SAndroid Build Coastguard Worker switch (u.format) { 635*2d1272b8SAndroid Build Coastguard Worker case 1: 636*2d1272b8SAndroid Build Coastguard Worker return ((PairPosFormat1*)(&u.format1))->sanitize (vertex); 637*2d1272b8SAndroid Build Coastguard Worker case 2: 638*2d1272b8SAndroid Build Coastguard Worker return ((PairPosFormat2*)(&u.format2))->sanitize (vertex); 639*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_NO_BEYOND_64K 640*2d1272b8SAndroid Build Coastguard Worker case 3: HB_FALLTHROUGH; 641*2d1272b8SAndroid Build Coastguard Worker case 4: HB_FALLTHROUGH; 642*2d1272b8SAndroid Build Coastguard Worker #endif 643*2d1272b8SAndroid Build Coastguard Worker default: 644*2d1272b8SAndroid Build Coastguard Worker // We don't handle format 3 and 4 here. 645*2d1272b8SAndroid Build Coastguard Worker return false; 646*2d1272b8SAndroid Build Coastguard Worker } 647*2d1272b8SAndroid Build Coastguard Worker } 648*2d1272b8SAndroid Build Coastguard Worker }; 649*2d1272b8SAndroid Build Coastguard Worker 650*2d1272b8SAndroid Build Coastguard Worker } 651*2d1272b8SAndroid Build Coastguard Worker 652*2d1272b8SAndroid Build Coastguard Worker #endif // GRAPH_PAIRPOS_GRAPH_HH 653