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_MARKBASEPOS_GRAPH_HH 28*2d1272b8SAndroid Build Coastguard Worker #define GRAPH_MARKBASEPOS_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 "../OT/Layout/GPOS/MarkBasePos.hh" 33*2d1272b8SAndroid Build Coastguard Worker #include "../OT/Layout/GPOS/PosLookupSubTable.hh" 34*2d1272b8SAndroid Build Coastguard Worker 35*2d1272b8SAndroid Build Coastguard Worker namespace graph { 36*2d1272b8SAndroid Build Coastguard Worker 37*2d1272b8SAndroid Build Coastguard Worker struct AnchorMatrix : public OT::Layout::GPOS_impl::AnchorMatrix 38*2d1272b8SAndroid Build Coastguard Worker { sanitizegraph::AnchorMatrix39*2d1272b8SAndroid Build Coastguard Worker bool sanitize (graph_t::vertex_t& vertex, unsigned class_count) const 40*2d1272b8SAndroid Build Coastguard Worker { 41*2d1272b8SAndroid Build Coastguard Worker int64_t vertex_len = vertex.obj.tail - vertex.obj.head; 42*2d1272b8SAndroid Build Coastguard Worker if (vertex_len < AnchorMatrix::min_size) return false; 43*2d1272b8SAndroid Build Coastguard Worker hb_barrier (); 44*2d1272b8SAndroid Build Coastguard Worker 45*2d1272b8SAndroid Build Coastguard Worker return vertex_len >= AnchorMatrix::min_size + 46*2d1272b8SAndroid Build Coastguard Worker OT::Offset16::static_size * class_count * this->rows; 47*2d1272b8SAndroid Build Coastguard Worker } 48*2d1272b8SAndroid Build Coastguard Worker shrinkgraph::AnchorMatrix49*2d1272b8SAndroid Build Coastguard Worker bool shrink (gsubgpos_graph_context_t& c, 50*2d1272b8SAndroid Build Coastguard Worker unsigned this_index, 51*2d1272b8SAndroid Build Coastguard Worker unsigned old_class_count, 52*2d1272b8SAndroid Build Coastguard Worker unsigned new_class_count) 53*2d1272b8SAndroid Build Coastguard Worker { 54*2d1272b8SAndroid Build Coastguard Worker if (new_class_count >= old_class_count) return false; 55*2d1272b8SAndroid Build Coastguard Worker auto& o = c.graph.vertices_[this_index].obj; 56*2d1272b8SAndroid Build Coastguard Worker unsigned base_count = rows; 57*2d1272b8SAndroid Build Coastguard Worker o.tail = o.head + 58*2d1272b8SAndroid Build Coastguard Worker AnchorMatrix::min_size + 59*2d1272b8SAndroid Build Coastguard Worker OT::Offset16::static_size * base_count * new_class_count; 60*2d1272b8SAndroid Build Coastguard Worker 61*2d1272b8SAndroid Build Coastguard Worker // Reposition links into the new indexing scheme. 62*2d1272b8SAndroid Build Coastguard Worker for (auto& link : o.real_links.writer ()) 63*2d1272b8SAndroid Build Coastguard Worker { 64*2d1272b8SAndroid Build Coastguard Worker unsigned index = (link.position - 2) / 2; 65*2d1272b8SAndroid Build Coastguard Worker unsigned base = index / old_class_count; 66*2d1272b8SAndroid Build Coastguard Worker unsigned klass = index % old_class_count; 67*2d1272b8SAndroid Build Coastguard Worker if (klass >= new_class_count) 68*2d1272b8SAndroid Build Coastguard Worker // should have already been removed 69*2d1272b8SAndroid Build Coastguard Worker return false; 70*2d1272b8SAndroid Build Coastguard Worker 71*2d1272b8SAndroid Build Coastguard Worker unsigned new_index = base * new_class_count + klass; 72*2d1272b8SAndroid Build Coastguard Worker 73*2d1272b8SAndroid Build Coastguard Worker link.position = (char*) &(this->matrixZ[new_index]) - (char*) this; 74*2d1272b8SAndroid Build Coastguard Worker } 75*2d1272b8SAndroid Build Coastguard Worker 76*2d1272b8SAndroid Build Coastguard Worker return true; 77*2d1272b8SAndroid Build Coastguard Worker } 78*2d1272b8SAndroid Build Coastguard Worker clonegraph::AnchorMatrix79*2d1272b8SAndroid Build Coastguard Worker unsigned clone (gsubgpos_graph_context_t& c, 80*2d1272b8SAndroid Build Coastguard Worker unsigned this_index, 81*2d1272b8SAndroid Build Coastguard Worker unsigned start, 82*2d1272b8SAndroid Build Coastguard Worker unsigned end, 83*2d1272b8SAndroid Build Coastguard Worker unsigned class_count) 84*2d1272b8SAndroid Build Coastguard Worker { 85*2d1272b8SAndroid Build Coastguard Worker unsigned base_count = rows; 86*2d1272b8SAndroid Build Coastguard Worker unsigned new_class_count = end - start; 87*2d1272b8SAndroid Build Coastguard Worker unsigned size = AnchorMatrix::min_size + 88*2d1272b8SAndroid Build Coastguard Worker OT::Offset16::static_size * new_class_count * rows; 89*2d1272b8SAndroid Build Coastguard Worker unsigned prime_id = c.create_node (size); 90*2d1272b8SAndroid Build Coastguard Worker if (prime_id == (unsigned) -1) return -1; 91*2d1272b8SAndroid Build Coastguard Worker AnchorMatrix* prime = (AnchorMatrix*) c.graph.object (prime_id).head; 92*2d1272b8SAndroid Build Coastguard Worker prime->rows = base_count; 93*2d1272b8SAndroid Build Coastguard Worker 94*2d1272b8SAndroid Build Coastguard Worker auto& o = c.graph.vertices_[this_index].obj; 95*2d1272b8SAndroid Build Coastguard Worker int num_links = o.real_links.length; 96*2d1272b8SAndroid Build Coastguard Worker for (int i = 0; i < num_links; i++) 97*2d1272b8SAndroid Build Coastguard Worker { 98*2d1272b8SAndroid Build Coastguard Worker const auto& link = o.real_links[i]; 99*2d1272b8SAndroid Build Coastguard Worker unsigned old_index = (link.position - 2) / OT::Offset16::static_size; 100*2d1272b8SAndroid Build Coastguard Worker unsigned klass = old_index % class_count; 101*2d1272b8SAndroid Build Coastguard Worker if (klass < start || klass >= end) continue; 102*2d1272b8SAndroid Build Coastguard Worker 103*2d1272b8SAndroid Build Coastguard Worker unsigned base = old_index / class_count; 104*2d1272b8SAndroid Build Coastguard Worker unsigned new_klass = klass - start; 105*2d1272b8SAndroid Build Coastguard Worker unsigned new_index = base * new_class_count + new_klass; 106*2d1272b8SAndroid Build Coastguard Worker 107*2d1272b8SAndroid Build Coastguard Worker 108*2d1272b8SAndroid Build Coastguard Worker unsigned child_idx = link.objidx; 109*2d1272b8SAndroid Build Coastguard Worker c.graph.add_link (&(prime->matrixZ[new_index]), 110*2d1272b8SAndroid Build Coastguard Worker prime_id, 111*2d1272b8SAndroid Build Coastguard Worker child_idx); 112*2d1272b8SAndroid Build Coastguard Worker 113*2d1272b8SAndroid Build Coastguard Worker auto& child = c.graph.vertices_[child_idx]; 114*2d1272b8SAndroid Build Coastguard Worker child.remove_parent (this_index); 115*2d1272b8SAndroid Build Coastguard Worker 116*2d1272b8SAndroid Build Coastguard Worker o.real_links.remove_unordered (i); 117*2d1272b8SAndroid Build Coastguard Worker num_links--; 118*2d1272b8SAndroid Build Coastguard Worker i--; 119*2d1272b8SAndroid Build Coastguard Worker } 120*2d1272b8SAndroid Build Coastguard Worker 121*2d1272b8SAndroid Build Coastguard Worker return prime_id; 122*2d1272b8SAndroid Build Coastguard Worker } 123*2d1272b8SAndroid Build Coastguard Worker }; 124*2d1272b8SAndroid Build Coastguard Worker 125*2d1272b8SAndroid Build Coastguard Worker struct MarkArray : public OT::Layout::GPOS_impl::MarkArray 126*2d1272b8SAndroid Build Coastguard Worker { sanitizegraph::MarkArray127*2d1272b8SAndroid Build Coastguard Worker bool sanitize (graph_t::vertex_t& vertex) const 128*2d1272b8SAndroid Build Coastguard Worker { 129*2d1272b8SAndroid Build Coastguard Worker int64_t vertex_len = vertex.obj.tail - vertex.obj.head; 130*2d1272b8SAndroid Build Coastguard Worker unsigned min_size = MarkArray::min_size; 131*2d1272b8SAndroid Build Coastguard Worker if (vertex_len < min_size) return false; 132*2d1272b8SAndroid Build Coastguard Worker hb_barrier (); 133*2d1272b8SAndroid Build Coastguard Worker 134*2d1272b8SAndroid Build Coastguard Worker return vertex_len >= get_size (); 135*2d1272b8SAndroid Build Coastguard Worker } 136*2d1272b8SAndroid Build Coastguard Worker shrinkgraph::MarkArray137*2d1272b8SAndroid Build Coastguard Worker bool shrink (gsubgpos_graph_context_t& c, 138*2d1272b8SAndroid Build Coastguard Worker const hb_hashmap_t<unsigned, unsigned>& mark_array_links, 139*2d1272b8SAndroid Build Coastguard Worker unsigned this_index, 140*2d1272b8SAndroid Build Coastguard Worker unsigned new_class_count) 141*2d1272b8SAndroid Build Coastguard Worker { 142*2d1272b8SAndroid Build Coastguard Worker auto& o = c.graph.vertices_[this_index].obj; 143*2d1272b8SAndroid Build Coastguard Worker for (const auto& link : o.real_links) 144*2d1272b8SAndroid Build Coastguard Worker c.graph.vertices_[link.objidx].remove_parent (this_index); 145*2d1272b8SAndroid Build Coastguard Worker o.real_links.reset (); 146*2d1272b8SAndroid Build Coastguard Worker 147*2d1272b8SAndroid Build Coastguard Worker unsigned new_index = 0; 148*2d1272b8SAndroid Build Coastguard Worker for (const auto& record : this->iter ()) 149*2d1272b8SAndroid Build Coastguard Worker { 150*2d1272b8SAndroid Build Coastguard Worker unsigned klass = record.klass; 151*2d1272b8SAndroid Build Coastguard Worker if (klass >= new_class_count) continue; 152*2d1272b8SAndroid Build Coastguard Worker 153*2d1272b8SAndroid Build Coastguard Worker (*this)[new_index].klass = klass; 154*2d1272b8SAndroid Build Coastguard Worker unsigned position = (char*) &record.markAnchor - (char*) this; 155*2d1272b8SAndroid Build Coastguard Worker unsigned* objidx; 156*2d1272b8SAndroid Build Coastguard Worker if (!mark_array_links.has (position, &objidx)) 157*2d1272b8SAndroid Build Coastguard Worker { 158*2d1272b8SAndroid Build Coastguard Worker new_index++; 159*2d1272b8SAndroid Build Coastguard Worker continue; 160*2d1272b8SAndroid Build Coastguard Worker } 161*2d1272b8SAndroid Build Coastguard Worker 162*2d1272b8SAndroid Build Coastguard Worker c.graph.add_link (&(*this)[new_index].markAnchor, this_index, *objidx); 163*2d1272b8SAndroid Build Coastguard Worker new_index++; 164*2d1272b8SAndroid Build Coastguard Worker } 165*2d1272b8SAndroid Build Coastguard Worker 166*2d1272b8SAndroid Build Coastguard Worker this->len = new_index; 167*2d1272b8SAndroid Build Coastguard Worker o.tail = o.head + MarkArray::min_size + 168*2d1272b8SAndroid Build Coastguard Worker OT::Layout::GPOS_impl::MarkRecord::static_size * new_index; 169*2d1272b8SAndroid Build Coastguard Worker return true; 170*2d1272b8SAndroid Build Coastguard Worker } 171*2d1272b8SAndroid Build Coastguard Worker clonegraph::MarkArray172*2d1272b8SAndroid Build Coastguard Worker unsigned clone (gsubgpos_graph_context_t& c, 173*2d1272b8SAndroid Build Coastguard Worker unsigned this_index, 174*2d1272b8SAndroid Build Coastguard Worker const hb_hashmap_t<unsigned, unsigned>& pos_to_index, 175*2d1272b8SAndroid Build Coastguard Worker hb_set_t& marks, 176*2d1272b8SAndroid Build Coastguard Worker unsigned start_class) 177*2d1272b8SAndroid Build Coastguard Worker { 178*2d1272b8SAndroid Build Coastguard Worker unsigned size = MarkArray::min_size + 179*2d1272b8SAndroid Build Coastguard Worker OT::Layout::GPOS_impl::MarkRecord::static_size * 180*2d1272b8SAndroid Build Coastguard Worker marks.get_population (); 181*2d1272b8SAndroid Build Coastguard Worker unsigned prime_id = c.create_node (size); 182*2d1272b8SAndroid Build Coastguard Worker if (prime_id == (unsigned) -1) return -1; 183*2d1272b8SAndroid Build Coastguard Worker MarkArray* prime = (MarkArray*) c.graph.object (prime_id).head; 184*2d1272b8SAndroid Build Coastguard Worker prime->len = marks.get_population (); 185*2d1272b8SAndroid Build Coastguard Worker 186*2d1272b8SAndroid Build Coastguard Worker 187*2d1272b8SAndroid Build Coastguard Worker unsigned i = 0; 188*2d1272b8SAndroid Build Coastguard Worker for (hb_codepoint_t mark : marks) 189*2d1272b8SAndroid Build Coastguard Worker { 190*2d1272b8SAndroid Build Coastguard Worker (*prime)[i].klass = (*this)[mark].klass - start_class; 191*2d1272b8SAndroid Build Coastguard Worker unsigned offset_pos = (char*) &((*this)[mark].markAnchor) - (char*) this; 192*2d1272b8SAndroid Build Coastguard Worker unsigned* anchor_index; 193*2d1272b8SAndroid Build Coastguard Worker if (pos_to_index.has (offset_pos, &anchor_index)) 194*2d1272b8SAndroid Build Coastguard Worker c.graph.move_child (this_index, 195*2d1272b8SAndroid Build Coastguard Worker &((*this)[mark].markAnchor), 196*2d1272b8SAndroid Build Coastguard Worker prime_id, 197*2d1272b8SAndroid Build Coastguard Worker &((*prime)[i].markAnchor)); 198*2d1272b8SAndroid Build Coastguard Worker 199*2d1272b8SAndroid Build Coastguard Worker i++; 200*2d1272b8SAndroid Build Coastguard Worker } 201*2d1272b8SAndroid Build Coastguard Worker 202*2d1272b8SAndroid Build Coastguard Worker return prime_id; 203*2d1272b8SAndroid Build Coastguard Worker } 204*2d1272b8SAndroid Build Coastguard Worker }; 205*2d1272b8SAndroid Build Coastguard Worker 206*2d1272b8SAndroid Build Coastguard Worker struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<SmallTypes> 207*2d1272b8SAndroid Build Coastguard Worker { sanitizegraph::MarkBasePosFormat1208*2d1272b8SAndroid Build Coastguard Worker bool sanitize (graph_t::vertex_t& vertex) const 209*2d1272b8SAndroid Build Coastguard Worker { 210*2d1272b8SAndroid Build Coastguard Worker int64_t vertex_len = vertex.obj.tail - vertex.obj.head; 211*2d1272b8SAndroid Build Coastguard Worker return vertex_len >= MarkBasePosFormat1::static_size; 212*2d1272b8SAndroid Build Coastguard Worker } 213*2d1272b8SAndroid Build Coastguard Worker split_subtablesgraph::MarkBasePosFormat1214*2d1272b8SAndroid Build Coastguard Worker hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, 215*2d1272b8SAndroid Build Coastguard Worker unsigned parent_index, 216*2d1272b8SAndroid Build Coastguard Worker unsigned this_index) 217*2d1272b8SAndroid Build Coastguard Worker { 218*2d1272b8SAndroid Build Coastguard Worker hb_set_t visited; 219*2d1272b8SAndroid Build Coastguard Worker 220*2d1272b8SAndroid Build Coastguard Worker const unsigned base_coverage_id = c.graph.index_for_offset (this_index, &baseCoverage); 221*2d1272b8SAndroid Build Coastguard Worker const unsigned base_size = 222*2d1272b8SAndroid Build Coastguard Worker OT::Layout::GPOS_impl::MarkBasePosFormat1_2<SmallTypes>::min_size + 223*2d1272b8SAndroid Build Coastguard Worker MarkArray::min_size + 224*2d1272b8SAndroid Build Coastguard Worker AnchorMatrix::min_size + 225*2d1272b8SAndroid Build Coastguard Worker c.graph.vertices_[base_coverage_id].table_size (); 226*2d1272b8SAndroid Build Coastguard Worker 227*2d1272b8SAndroid Build Coastguard Worker hb_vector_t<class_info_t> class_to_info = get_class_info (c, this_index); 228*2d1272b8SAndroid Build Coastguard Worker 229*2d1272b8SAndroid Build Coastguard Worker unsigned class_count = classCount; 230*2d1272b8SAndroid Build Coastguard Worker auto base_array = c.graph.as_table<AnchorMatrix> (this_index, 231*2d1272b8SAndroid Build Coastguard Worker &baseArray, 232*2d1272b8SAndroid Build Coastguard Worker class_count); 233*2d1272b8SAndroid Build Coastguard Worker if (!base_array) return hb_vector_t<unsigned> (); 234*2d1272b8SAndroid Build Coastguard Worker unsigned base_count = base_array.table->rows; 235*2d1272b8SAndroid Build Coastguard Worker 236*2d1272b8SAndroid Build Coastguard Worker unsigned partial_coverage_size = 4; 237*2d1272b8SAndroid Build Coastguard Worker unsigned accumulated = base_size; 238*2d1272b8SAndroid Build Coastguard Worker hb_vector_t<unsigned> split_points; 239*2d1272b8SAndroid Build Coastguard Worker 240*2d1272b8SAndroid Build Coastguard Worker for (unsigned klass = 0; klass < class_count; klass++) 241*2d1272b8SAndroid Build Coastguard Worker { 242*2d1272b8SAndroid Build Coastguard Worker class_info_t& info = class_to_info[klass]; 243*2d1272b8SAndroid Build Coastguard Worker partial_coverage_size += OT::HBUINT16::static_size * info.marks.get_population (); 244*2d1272b8SAndroid Build Coastguard Worker unsigned accumulated_delta = 245*2d1272b8SAndroid Build Coastguard Worker OT::Layout::GPOS_impl::MarkRecord::static_size * info.marks.get_population () + 246*2d1272b8SAndroid Build Coastguard Worker OT::Offset16::static_size * base_count; 247*2d1272b8SAndroid Build Coastguard Worker 248*2d1272b8SAndroid Build Coastguard Worker for (unsigned objidx : info.child_indices) 249*2d1272b8SAndroid Build Coastguard Worker accumulated_delta += c.graph.find_subgraph_size (objidx, visited); 250*2d1272b8SAndroid Build Coastguard Worker 251*2d1272b8SAndroid Build Coastguard Worker accumulated += accumulated_delta; 252*2d1272b8SAndroid Build Coastguard Worker unsigned total = accumulated + partial_coverage_size; 253*2d1272b8SAndroid Build Coastguard Worker 254*2d1272b8SAndroid Build Coastguard Worker if (total >= (1 << 16)) 255*2d1272b8SAndroid Build Coastguard Worker { 256*2d1272b8SAndroid Build Coastguard Worker split_points.push (klass); 257*2d1272b8SAndroid Build Coastguard Worker accumulated = base_size + accumulated_delta; 258*2d1272b8SAndroid Build Coastguard Worker partial_coverage_size = 4 + OT::HBUINT16::static_size * info.marks.get_population (); 259*2d1272b8SAndroid Build Coastguard Worker visited.clear (); // node sharing isn't allowed between splits. 260*2d1272b8SAndroid Build Coastguard Worker } 261*2d1272b8SAndroid Build Coastguard Worker } 262*2d1272b8SAndroid Build Coastguard Worker 263*2d1272b8SAndroid Build Coastguard Worker 264*2d1272b8SAndroid Build Coastguard Worker const unsigned mark_array_id = c.graph.index_for_offset (this_index, &markArray); 265*2d1272b8SAndroid Build Coastguard Worker split_context_t split_context { 266*2d1272b8SAndroid Build Coastguard Worker c, 267*2d1272b8SAndroid Build Coastguard Worker this, 268*2d1272b8SAndroid Build Coastguard Worker c.graph.duplicate_if_shared (parent_index, this_index), 269*2d1272b8SAndroid Build Coastguard Worker std::move (class_to_info), 270*2d1272b8SAndroid Build Coastguard Worker c.graph.vertices_[mark_array_id].position_to_index_map (), 271*2d1272b8SAndroid Build Coastguard Worker }; 272*2d1272b8SAndroid Build Coastguard Worker 273*2d1272b8SAndroid Build Coastguard Worker return actuate_subtable_split<split_context_t> (split_context, split_points); 274*2d1272b8SAndroid Build Coastguard Worker } 275*2d1272b8SAndroid Build Coastguard Worker 276*2d1272b8SAndroid Build Coastguard Worker private: 277*2d1272b8SAndroid Build Coastguard Worker 278*2d1272b8SAndroid Build Coastguard Worker struct class_info_t { 279*2d1272b8SAndroid Build Coastguard Worker hb_set_t marks; 280*2d1272b8SAndroid Build Coastguard Worker hb_vector_t<unsigned> child_indices; 281*2d1272b8SAndroid Build Coastguard Worker }; 282*2d1272b8SAndroid Build Coastguard Worker 283*2d1272b8SAndroid Build Coastguard Worker struct split_context_t { 284*2d1272b8SAndroid Build Coastguard Worker gsubgpos_graph_context_t& c; 285*2d1272b8SAndroid Build Coastguard Worker MarkBasePosFormat1* thiz; 286*2d1272b8SAndroid Build Coastguard Worker unsigned this_index; 287*2d1272b8SAndroid Build Coastguard Worker hb_vector_t<class_info_t> class_to_info; 288*2d1272b8SAndroid Build Coastguard Worker hb_hashmap_t<unsigned, unsigned> mark_array_links; 289*2d1272b8SAndroid Build Coastguard Worker marks_forgraph::MarkBasePosFormat1::split_context_t290*2d1272b8SAndroid Build Coastguard Worker hb_set_t marks_for (unsigned start, unsigned end) 291*2d1272b8SAndroid Build Coastguard Worker { 292*2d1272b8SAndroid Build Coastguard Worker hb_set_t marks; 293*2d1272b8SAndroid Build Coastguard Worker for (unsigned klass = start; klass < end; klass++) 294*2d1272b8SAndroid Build Coastguard Worker { 295*2d1272b8SAndroid Build Coastguard Worker + class_to_info[klass].marks.iter () 296*2d1272b8SAndroid Build Coastguard Worker | hb_sink (marks) 297*2d1272b8SAndroid Build Coastguard Worker ; 298*2d1272b8SAndroid Build Coastguard Worker } 299*2d1272b8SAndroid Build Coastguard Worker return marks; 300*2d1272b8SAndroid Build Coastguard Worker } 301*2d1272b8SAndroid Build Coastguard Worker original_countgraph::MarkBasePosFormat1::split_context_t302*2d1272b8SAndroid Build Coastguard Worker unsigned original_count () 303*2d1272b8SAndroid Build Coastguard Worker { 304*2d1272b8SAndroid Build Coastguard Worker return thiz->classCount; 305*2d1272b8SAndroid Build Coastguard Worker } 306*2d1272b8SAndroid Build Coastguard Worker clone_rangegraph::MarkBasePosFormat1::split_context_t307*2d1272b8SAndroid Build Coastguard Worker unsigned clone_range (unsigned start, unsigned end) 308*2d1272b8SAndroid Build Coastguard Worker { 309*2d1272b8SAndroid Build Coastguard Worker return thiz->clone_range (*this, this->this_index, start, end); 310*2d1272b8SAndroid Build Coastguard Worker } 311*2d1272b8SAndroid Build Coastguard Worker shrinkgraph::MarkBasePosFormat1::split_context_t312*2d1272b8SAndroid Build Coastguard Worker bool shrink (unsigned count) 313*2d1272b8SAndroid Build Coastguard Worker { 314*2d1272b8SAndroid Build Coastguard Worker return thiz->shrink (*this, this->this_index, count); 315*2d1272b8SAndroid Build Coastguard Worker } 316*2d1272b8SAndroid Build Coastguard Worker }; 317*2d1272b8SAndroid Build Coastguard Worker get_class_infograph::MarkBasePosFormat1318*2d1272b8SAndroid Build Coastguard Worker hb_vector_t<class_info_t> get_class_info (gsubgpos_graph_context_t& c, 319*2d1272b8SAndroid Build Coastguard Worker unsigned this_index) 320*2d1272b8SAndroid Build Coastguard Worker { 321*2d1272b8SAndroid Build Coastguard Worker hb_vector_t<class_info_t> class_to_info; 322*2d1272b8SAndroid Build Coastguard Worker 323*2d1272b8SAndroid Build Coastguard Worker unsigned class_count = classCount; 324*2d1272b8SAndroid Build Coastguard Worker if (!class_count) return class_to_info; 325*2d1272b8SAndroid Build Coastguard Worker 326*2d1272b8SAndroid Build Coastguard Worker if (!class_to_info.resize (class_count)) 327*2d1272b8SAndroid Build Coastguard Worker return hb_vector_t<class_info_t>(); 328*2d1272b8SAndroid Build Coastguard Worker 329*2d1272b8SAndroid Build Coastguard Worker auto mark_array = c.graph.as_table<MarkArray> (this_index, &markArray); 330*2d1272b8SAndroid Build Coastguard Worker if (!mark_array) return hb_vector_t<class_info_t> (); 331*2d1272b8SAndroid Build Coastguard Worker unsigned mark_count = mark_array.table->len; 332*2d1272b8SAndroid Build Coastguard Worker for (unsigned mark = 0; mark < mark_count; mark++) 333*2d1272b8SAndroid Build Coastguard Worker { 334*2d1272b8SAndroid Build Coastguard Worker unsigned klass = (*mark_array.table)[mark].get_class (); 335*2d1272b8SAndroid Build Coastguard Worker if (klass >= class_count) continue; 336*2d1272b8SAndroid Build Coastguard Worker class_to_info[klass].marks.add (mark); 337*2d1272b8SAndroid Build Coastguard Worker } 338*2d1272b8SAndroid Build Coastguard Worker 339*2d1272b8SAndroid Build Coastguard Worker for (const auto& link : mark_array.vertex->obj.real_links) 340*2d1272b8SAndroid Build Coastguard Worker { 341*2d1272b8SAndroid Build Coastguard Worker unsigned mark = (link.position - 2) / 342*2d1272b8SAndroid Build Coastguard Worker OT::Layout::GPOS_impl::MarkRecord::static_size; 343*2d1272b8SAndroid Build Coastguard Worker unsigned klass = (*mark_array.table)[mark].get_class (); 344*2d1272b8SAndroid Build Coastguard Worker if (klass >= class_count) continue; 345*2d1272b8SAndroid Build Coastguard Worker class_to_info[klass].child_indices.push (link.objidx); 346*2d1272b8SAndroid Build Coastguard Worker } 347*2d1272b8SAndroid Build Coastguard Worker 348*2d1272b8SAndroid Build Coastguard Worker unsigned base_array_id = 349*2d1272b8SAndroid Build Coastguard Worker c.graph.index_for_offset (this_index, &baseArray); 350*2d1272b8SAndroid Build Coastguard Worker auto& base_array_v = c.graph.vertices_[base_array_id]; 351*2d1272b8SAndroid Build Coastguard Worker 352*2d1272b8SAndroid Build Coastguard Worker for (const auto& link : base_array_v.obj.real_links) 353*2d1272b8SAndroid Build Coastguard Worker { 354*2d1272b8SAndroid Build Coastguard Worker unsigned index = (link.position - 2) / OT::Offset16::static_size; 355*2d1272b8SAndroid Build Coastguard Worker unsigned klass = index % class_count; 356*2d1272b8SAndroid Build Coastguard Worker class_to_info[klass].child_indices.push (link.objidx); 357*2d1272b8SAndroid Build Coastguard Worker } 358*2d1272b8SAndroid Build Coastguard Worker 359*2d1272b8SAndroid Build Coastguard Worker return class_to_info; 360*2d1272b8SAndroid Build Coastguard Worker } 361*2d1272b8SAndroid Build Coastguard Worker shrinkgraph::MarkBasePosFormat1362*2d1272b8SAndroid Build Coastguard Worker bool shrink (split_context_t& sc, 363*2d1272b8SAndroid Build Coastguard Worker unsigned this_index, 364*2d1272b8SAndroid Build Coastguard Worker unsigned count) 365*2d1272b8SAndroid Build Coastguard Worker { 366*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG (SUBSET_REPACK, nullptr, 367*2d1272b8SAndroid Build Coastguard Worker " Shrinking MarkBasePosFormat1 (%u) to [0, %u).", 368*2d1272b8SAndroid Build Coastguard Worker this_index, 369*2d1272b8SAndroid Build Coastguard Worker count); 370*2d1272b8SAndroid Build Coastguard Worker 371*2d1272b8SAndroid Build Coastguard Worker unsigned old_count = classCount; 372*2d1272b8SAndroid Build Coastguard Worker if (count >= old_count) 373*2d1272b8SAndroid Build Coastguard Worker return true; 374*2d1272b8SAndroid Build Coastguard Worker 375*2d1272b8SAndroid Build Coastguard Worker classCount = count; 376*2d1272b8SAndroid Build Coastguard Worker 377*2d1272b8SAndroid Build Coastguard Worker auto mark_coverage = sc.c.graph.as_mutable_table<Coverage> (this_index, 378*2d1272b8SAndroid Build Coastguard Worker &markCoverage); 379*2d1272b8SAndroid Build Coastguard Worker if (!mark_coverage) return false; 380*2d1272b8SAndroid Build Coastguard Worker hb_set_t marks = sc.marks_for (0, count); 381*2d1272b8SAndroid Build Coastguard Worker auto new_coverage = 382*2d1272b8SAndroid Build Coastguard Worker + hb_enumerate (mark_coverage.table->iter ()) 383*2d1272b8SAndroid Build Coastguard Worker | hb_filter (marks, hb_first) 384*2d1272b8SAndroid Build Coastguard Worker | hb_map_retains_sorting (hb_second) 385*2d1272b8SAndroid Build Coastguard Worker ; 386*2d1272b8SAndroid Build Coastguard Worker if (!Coverage::make_coverage (sc.c, + new_coverage, 387*2d1272b8SAndroid Build Coastguard Worker mark_coverage.index, 388*2d1272b8SAndroid Build Coastguard Worker 4 + 2 * marks.get_population ())) 389*2d1272b8SAndroid Build Coastguard Worker return false; 390*2d1272b8SAndroid Build Coastguard Worker 391*2d1272b8SAndroid Build Coastguard Worker 392*2d1272b8SAndroid Build Coastguard Worker auto base_array = sc.c.graph.as_mutable_table<AnchorMatrix> (this_index, 393*2d1272b8SAndroid Build Coastguard Worker &baseArray, 394*2d1272b8SAndroid Build Coastguard Worker old_count); 395*2d1272b8SAndroid Build Coastguard Worker if (!base_array || !base_array.table->shrink (sc.c, 396*2d1272b8SAndroid Build Coastguard Worker base_array.index, 397*2d1272b8SAndroid Build Coastguard Worker old_count, 398*2d1272b8SAndroid Build Coastguard Worker count)) 399*2d1272b8SAndroid Build Coastguard Worker return false; 400*2d1272b8SAndroid Build Coastguard Worker 401*2d1272b8SAndroid Build Coastguard Worker auto mark_array = sc.c.graph.as_mutable_table<MarkArray> (this_index, 402*2d1272b8SAndroid Build Coastguard Worker &markArray); 403*2d1272b8SAndroid Build Coastguard Worker if (!mark_array || !mark_array.table->shrink (sc.c, 404*2d1272b8SAndroid Build Coastguard Worker sc.mark_array_links, 405*2d1272b8SAndroid Build Coastguard Worker mark_array.index, 406*2d1272b8SAndroid Build Coastguard Worker count)) 407*2d1272b8SAndroid Build Coastguard Worker return false; 408*2d1272b8SAndroid Build Coastguard Worker 409*2d1272b8SAndroid Build Coastguard Worker return true; 410*2d1272b8SAndroid Build Coastguard Worker } 411*2d1272b8SAndroid Build Coastguard Worker 412*2d1272b8SAndroid Build Coastguard Worker // Create a new MarkBasePos that has all of the data for classes from [start, end). clone_rangegraph::MarkBasePosFormat1413*2d1272b8SAndroid Build Coastguard Worker unsigned clone_range (split_context_t& sc, 414*2d1272b8SAndroid Build Coastguard Worker unsigned this_index, 415*2d1272b8SAndroid Build Coastguard Worker unsigned start, unsigned end) const 416*2d1272b8SAndroid Build Coastguard Worker { 417*2d1272b8SAndroid Build Coastguard Worker DEBUG_MSG (SUBSET_REPACK, nullptr, 418*2d1272b8SAndroid Build Coastguard Worker " Cloning MarkBasePosFormat1 (%u) range [%u, %u).", this_index, start, end); 419*2d1272b8SAndroid Build Coastguard Worker 420*2d1272b8SAndroid Build Coastguard Worker graph_t& graph = sc.c.graph; 421*2d1272b8SAndroid Build Coastguard Worker unsigned prime_size = OT::Layout::GPOS_impl::MarkBasePosFormat1_2<SmallTypes>::static_size; 422*2d1272b8SAndroid Build Coastguard Worker 423*2d1272b8SAndroid Build Coastguard Worker unsigned prime_id = sc.c.create_node (prime_size); 424*2d1272b8SAndroid Build Coastguard Worker if (prime_id == (unsigned) -1) return -1; 425*2d1272b8SAndroid Build Coastguard Worker 426*2d1272b8SAndroid Build Coastguard Worker MarkBasePosFormat1* prime = (MarkBasePosFormat1*) graph.object (prime_id).head; 427*2d1272b8SAndroid Build Coastguard Worker prime->format = this->format; 428*2d1272b8SAndroid Build Coastguard Worker unsigned new_class_count = end - start; 429*2d1272b8SAndroid Build Coastguard Worker prime->classCount = new_class_count; 430*2d1272b8SAndroid Build Coastguard Worker 431*2d1272b8SAndroid Build Coastguard Worker unsigned base_coverage_id = 432*2d1272b8SAndroid Build Coastguard Worker graph.index_for_offset (sc.this_index, &baseCoverage); 433*2d1272b8SAndroid Build Coastguard Worker graph.add_link (&(prime->baseCoverage), prime_id, base_coverage_id); 434*2d1272b8SAndroid Build Coastguard Worker graph.duplicate (prime_id, base_coverage_id); 435*2d1272b8SAndroid Build Coastguard Worker 436*2d1272b8SAndroid Build Coastguard Worker auto mark_coverage = sc.c.graph.as_table<Coverage> (this_index, 437*2d1272b8SAndroid Build Coastguard Worker &markCoverage); 438*2d1272b8SAndroid Build Coastguard Worker if (!mark_coverage) return false; 439*2d1272b8SAndroid Build Coastguard Worker hb_set_t marks = sc.marks_for (start, end); 440*2d1272b8SAndroid Build Coastguard Worker auto new_coverage = 441*2d1272b8SAndroid Build Coastguard Worker + hb_enumerate (mark_coverage.table->iter ()) 442*2d1272b8SAndroid Build Coastguard Worker | hb_filter (marks, hb_first) 443*2d1272b8SAndroid Build Coastguard Worker | hb_map_retains_sorting (hb_second) 444*2d1272b8SAndroid Build Coastguard Worker ; 445*2d1272b8SAndroid Build Coastguard Worker if (!Coverage::add_coverage (sc.c, 446*2d1272b8SAndroid Build Coastguard Worker prime_id, 447*2d1272b8SAndroid Build Coastguard Worker 2, 448*2d1272b8SAndroid Build Coastguard Worker + new_coverage, 449*2d1272b8SAndroid Build Coastguard Worker marks.get_population () * 2 + 4)) 450*2d1272b8SAndroid Build Coastguard Worker return -1; 451*2d1272b8SAndroid Build Coastguard Worker 452*2d1272b8SAndroid Build Coastguard Worker auto mark_array = 453*2d1272b8SAndroid Build Coastguard Worker graph.as_table <MarkArray> (sc.this_index, &markArray); 454*2d1272b8SAndroid Build Coastguard Worker if (!mark_array) return -1; 455*2d1272b8SAndroid Build Coastguard Worker unsigned new_mark_array = 456*2d1272b8SAndroid Build Coastguard Worker mark_array.table->clone (sc.c, 457*2d1272b8SAndroid Build Coastguard Worker mark_array.index, 458*2d1272b8SAndroid Build Coastguard Worker sc.mark_array_links, 459*2d1272b8SAndroid Build Coastguard Worker marks, 460*2d1272b8SAndroid Build Coastguard Worker start); 461*2d1272b8SAndroid Build Coastguard Worker graph.add_link (&(prime->markArray), prime_id, new_mark_array); 462*2d1272b8SAndroid Build Coastguard Worker 463*2d1272b8SAndroid Build Coastguard Worker unsigned class_count = classCount; 464*2d1272b8SAndroid Build Coastguard Worker auto base_array = 465*2d1272b8SAndroid Build Coastguard Worker graph.as_table<AnchorMatrix> (sc.this_index, &baseArray, class_count); 466*2d1272b8SAndroid Build Coastguard Worker if (!base_array) return -1; 467*2d1272b8SAndroid Build Coastguard Worker unsigned new_base_array = 468*2d1272b8SAndroid Build Coastguard Worker base_array.table->clone (sc.c, 469*2d1272b8SAndroid Build Coastguard Worker base_array.index, 470*2d1272b8SAndroid Build Coastguard Worker start, end, this->classCount); 471*2d1272b8SAndroid Build Coastguard Worker graph.add_link (&(prime->baseArray), prime_id, new_base_array); 472*2d1272b8SAndroid Build Coastguard Worker 473*2d1272b8SAndroid Build Coastguard Worker return prime_id; 474*2d1272b8SAndroid Build Coastguard Worker } 475*2d1272b8SAndroid Build Coastguard Worker }; 476*2d1272b8SAndroid Build Coastguard Worker 477*2d1272b8SAndroid Build Coastguard Worker 478*2d1272b8SAndroid Build Coastguard Worker struct MarkBasePos : public OT::Layout::GPOS_impl::MarkBasePos 479*2d1272b8SAndroid Build Coastguard Worker { split_subtablesgraph::MarkBasePos480*2d1272b8SAndroid Build Coastguard Worker hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, 481*2d1272b8SAndroid Build Coastguard Worker unsigned parent_index, 482*2d1272b8SAndroid Build Coastguard Worker unsigned this_index) 483*2d1272b8SAndroid Build Coastguard Worker { 484*2d1272b8SAndroid Build Coastguard Worker switch (u.format) { 485*2d1272b8SAndroid Build Coastguard Worker case 1: 486*2d1272b8SAndroid Build Coastguard Worker return ((MarkBasePosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index); 487*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_NO_BEYOND_64K 488*2d1272b8SAndroid Build Coastguard Worker case 2: HB_FALLTHROUGH; 489*2d1272b8SAndroid Build Coastguard Worker // Don't split 24bit MarkBasePos's. 490*2d1272b8SAndroid Build Coastguard Worker #endif 491*2d1272b8SAndroid Build Coastguard Worker default: 492*2d1272b8SAndroid Build Coastguard Worker return hb_vector_t<unsigned> (); 493*2d1272b8SAndroid Build Coastguard Worker } 494*2d1272b8SAndroid Build Coastguard Worker } 495*2d1272b8SAndroid Build Coastguard Worker sanitizegraph::MarkBasePos496*2d1272b8SAndroid Build Coastguard Worker bool sanitize (graph_t::vertex_t& vertex) const 497*2d1272b8SAndroid Build Coastguard Worker { 498*2d1272b8SAndroid Build Coastguard Worker int64_t vertex_len = vertex.obj.tail - vertex.obj.head; 499*2d1272b8SAndroid Build Coastguard Worker if (vertex_len < u.format.get_size ()) return false; 500*2d1272b8SAndroid Build Coastguard Worker hb_barrier (); 501*2d1272b8SAndroid Build Coastguard Worker 502*2d1272b8SAndroid Build Coastguard Worker switch (u.format) { 503*2d1272b8SAndroid Build Coastguard Worker case 1: 504*2d1272b8SAndroid Build Coastguard Worker return ((MarkBasePosFormat1*)(&u.format1))->sanitize (vertex); 505*2d1272b8SAndroid Build Coastguard Worker #ifndef HB_NO_BEYOND_64K 506*2d1272b8SAndroid Build Coastguard Worker case 2: HB_FALLTHROUGH; 507*2d1272b8SAndroid Build Coastguard Worker #endif 508*2d1272b8SAndroid Build Coastguard Worker default: 509*2d1272b8SAndroid Build Coastguard Worker // We don't handle format 3 and 4 here. 510*2d1272b8SAndroid Build Coastguard Worker return false; 511*2d1272b8SAndroid Build Coastguard Worker } 512*2d1272b8SAndroid Build Coastguard Worker } 513*2d1272b8SAndroid Build Coastguard Worker }; 514*2d1272b8SAndroid Build Coastguard Worker 515*2d1272b8SAndroid Build Coastguard Worker 516*2d1272b8SAndroid Build Coastguard Worker } 517*2d1272b8SAndroid Build Coastguard Worker 518*2d1272b8SAndroid Build Coastguard Worker #endif // GRAPH_MARKBASEPOS_GRAPH_HH 519