xref: /aosp_15_r20/external/harfbuzz_ng/src/graph/markbasepos-graph.hh (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
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