xref: /aosp_15_r20/external/harfbuzz_ng/src/graph/pairpos-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_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