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