xref: /aosp_15_r20/external/harfbuzz_ng/docs/repacker.md (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1*2d1272b8SAndroid Build Coastguard Worker# Introduction
2*2d1272b8SAndroid Build Coastguard Worker
3*2d1272b8SAndroid Build Coastguard WorkerSeveral tables in the opentype format are formed internally by a graph of subtables. Parent node's
4*2d1272b8SAndroid Build Coastguard Workerreference their children through the use of positive offsets, which are typically 16 bits wide.
5*2d1272b8SAndroid Build Coastguard WorkerSince offsets are always positive this forms a directed acyclic graph. For storage in the font file
6*2d1272b8SAndroid Build Coastguard Workerthe graph must be given a topological ordering and then the subtables packed in serial according to
7*2d1272b8SAndroid Build Coastguard Workerthat ordering. Since 16 bit offsets have a maximum value of 65,535 if the distance between a parent
8*2d1272b8SAndroid Build Coastguard Workersubtable and a child is more then 65,535 bytes then it's not possible for the offset to encode that
9*2d1272b8SAndroid Build Coastguard Workeredge.
10*2d1272b8SAndroid Build Coastguard Worker
11*2d1272b8SAndroid Build Coastguard WorkerFor many fonts with complex layout rules (such as Arabic) it's not unusual for the tables containing
12*2d1272b8SAndroid Build Coastguard Workerlayout rules ([GSUB/GPOS](https://docs.microsoft.com/en-us/typography/opentype/spec/gsub)) to be
13*2d1272b8SAndroid Build Coastguard Workerlarger than 65kb. As a result these types of fonts are susceptible to offset overflows when
14*2d1272b8SAndroid Build Coastguard Workerserializing to the binary font format.
15*2d1272b8SAndroid Build Coastguard Worker
16*2d1272b8SAndroid Build Coastguard WorkerOffset overflows can happen for a variety of reasons and require different strategies to resolve:
17*2d1272b8SAndroid Build Coastguard Worker*  Simple overflows can often be resolved with a different topological ordering.
18*2d1272b8SAndroid Build Coastguard Worker*  If a subtable has many parents this can result in the link from furthest parent(s)
19*2d1272b8SAndroid Build Coastguard Worker   being at risk for overflows. In these cases it's possible to duplicate the shared subtable which
20*2d1272b8SAndroid Build Coastguard Worker   allows it to be placed closer to it's parent.
21*2d1272b8SAndroid Build Coastguard Worker*  If subtables exist which are themselves larger than 65kb it's not possible for any offsets to point
22*2d1272b8SAndroid Build Coastguard Worker   past them. In these cases the subtable can usually be split into two smaller subtables to allow
23*2d1272b8SAndroid Build Coastguard Worker   for more flexibility in the ordering.
24*2d1272b8SAndroid Build Coastguard Worker*  In GSUB/GPOS overflows from Lookup subtables can be resolved by changing the Lookup to an extension
25*2d1272b8SAndroid Build Coastguard Worker   lookup which uses a 32 bit offset instead of 16 bit offset.
26*2d1272b8SAndroid Build Coastguard Worker
27*2d1272b8SAndroid Build Coastguard WorkerIn general there isn't a simple solution to produce an optimal topological ordering for a given graph.
28*2d1272b8SAndroid Build Coastguard WorkerFinding an ordering which doesn't overflow is a NP hard problem. Existing solutions use heuristics
29*2d1272b8SAndroid Build Coastguard Workerwhich attempt a combination of the above strategies to attempt to find a non-overflowing configuration.
30*2d1272b8SAndroid Build Coastguard Worker
31*2d1272b8SAndroid Build Coastguard WorkerThe harfbuzz subsetting library
32*2d1272b8SAndroid Build Coastguard Worker[includes a repacking algorithm](https://github.com/harfbuzz/harfbuzz/blob/main/src/hb-repacker.hh)
33*2d1272b8SAndroid Build Coastguard Workerwhich is used to resolve offset overflows that are present in the subsetted tables it produces. This
34*2d1272b8SAndroid Build Coastguard Workerdocument provides a deep dive into how the harfbuzz repacking algorithm works.
35*2d1272b8SAndroid Build Coastguard Worker
36*2d1272b8SAndroid Build Coastguard WorkerOther implementations exist, such as in
37*2d1272b8SAndroid Build Coastguard Worker[fontTools](https://github.com/fonttools/fonttools/blob/7af43123d49c188fcef4e540fa94796b3b44e858/Lib/fontTools/ttLib/tables/otBase.py#L72), however these are not covered in this document.
38*2d1272b8SAndroid Build Coastguard Worker
39*2d1272b8SAndroid Build Coastguard Worker# Foundations
40*2d1272b8SAndroid Build Coastguard Worker
41*2d1272b8SAndroid Build Coastguard WorkerThere's four key pieces to the harfbuzz approach:
42*2d1272b8SAndroid Build Coastguard Worker
43*2d1272b8SAndroid Build Coastguard Worker*  Subtable Graph: a table's internal structure is abstracted out into a lightweight graph
44*2d1272b8SAndroid Build Coastguard Worker   representation where each subtable is a node and each offset forms an edge. The nodes only need
45*2d1272b8SAndroid Build Coastguard Worker   to know how many bytes the corresponding subtable occupies. This lightweight representation can
46*2d1272b8SAndroid Build Coastguard Worker   be easily modified to test new ordering's and strategies as the repacking algorithm iterates.
47*2d1272b8SAndroid Build Coastguard Worker
48*2d1272b8SAndroid Build Coastguard Worker*  [Topological sorting algorithm](https://en.wikipedia.org/wiki/Topological_sorting): an algorithm
49*2d1272b8SAndroid Build Coastguard Worker   which given a graph gives a linear sorting of the nodes such that all offsets will be positive.
50*2d1272b8SAndroid Build Coastguard Worker
51*2d1272b8SAndroid Build Coastguard Worker*  Overflow check: given a graph and a topological sorting it checks if there will be any overflows
52*2d1272b8SAndroid Build Coastguard Worker   in any of the offsets. If there are overflows it returns a list of (parent, child) tuples that
53*2d1272b8SAndroid Build Coastguard Worker   will overflow. Since the graph has information on the size of each subtable it's straightforward
54*2d1272b8SAndroid Build Coastguard Worker   to calculate the final position of each subtable and then check if any offsets to it will
55*2d1272b8SAndroid Build Coastguard Worker   overflow.
56*2d1272b8SAndroid Build Coastguard Worker
57*2d1272b8SAndroid Build Coastguard Worker*  Content Aware Preprocessing: if the overflow resolver is aware of the format of the underlying
58*2d1272b8SAndroid Build Coastguard Worker   tables (eg. GSUB, GPOS) then in some cases preprocessing can be done to increase the chance of
59*2d1272b8SAndroid Build Coastguard Worker   successfully packing the graph. For example for GSUB and GPOS we can preprocess the graph and
60*2d1272b8SAndroid Build Coastguard Worker   promote lookups to extension lookups (upgrades a 16 bit offset to 32 bits) or split large lookup
61*2d1272b8SAndroid Build Coastguard Worker   subtables into two or more pieces.
62*2d1272b8SAndroid Build Coastguard Worker
63*2d1272b8SAndroid Build Coastguard Worker*  Offset resolution strategies: given a particular occurrence of an overflow these strategies
64*2d1272b8SAndroid Build Coastguard Worker   modify the graph to attempt to resolve the overflow.
65*2d1272b8SAndroid Build Coastguard Worker
66*2d1272b8SAndroid Build Coastguard Worker# High Level Algorithm
67*2d1272b8SAndroid Build Coastguard Worker
68*2d1272b8SAndroid Build Coastguard Worker```
69*2d1272b8SAndroid Build Coastguard Workerdef repack(graph):
70*2d1272b8SAndroid Build Coastguard Worker  graph.topological_sort()
71*2d1272b8SAndroid Build Coastguard Worker
72*2d1272b8SAndroid Build Coastguard Worker  if (graph.will_overflow())
73*2d1272b8SAndroid Build Coastguard Worker    preprocess(graph)
74*2d1272b8SAndroid Build Coastguard Worker    assign_spaces(graph)
75*2d1272b8SAndroid Build Coastguard Worker    graph.topological_sort()
76*2d1272b8SAndroid Build Coastguard Worker
77*2d1272b8SAndroid Build Coastguard Worker  while (overflows = graph.will_overflow()):
78*2d1272b8SAndroid Build Coastguard Worker    for overflow in overflows:
79*2d1272b8SAndroid Build Coastguard Worker      apply_offset_resolution_strategy (overflow, graph)
80*2d1272b8SAndroid Build Coastguard Worker    graph.topological_sort()
81*2d1272b8SAndroid Build Coastguard Worker```
82*2d1272b8SAndroid Build Coastguard Worker
83*2d1272b8SAndroid Build Coastguard WorkerThe actual code for this processing loop can be found in the function hb_resolve_overflows () of
84*2d1272b8SAndroid Build Coastguard Worker[hb-repacker.hh](https://github.com/harfbuzz/harfbuzz/blob/main/src/hb-repacker.hh).
85*2d1272b8SAndroid Build Coastguard Worker
86*2d1272b8SAndroid Build Coastguard Worker# Topological Sorting Algorithms
87*2d1272b8SAndroid Build Coastguard Worker
88*2d1272b8SAndroid Build Coastguard WorkerThe harfbuzz repacker uses two different algorithms for topological sorting:
89*2d1272b8SAndroid Build Coastguard Worker*  [Kahn's Algorithm](https://en.wikipedia.org/wiki/Topological_sorting#Kahn's_algorithm)
90*2d1272b8SAndroid Build Coastguard Worker*  Sorting by shortest distance
91*2d1272b8SAndroid Build Coastguard Worker
92*2d1272b8SAndroid Build Coastguard WorkerKahn's algorithm is approximately twice as fast as the shortest distance sort so that is attempted
93*2d1272b8SAndroid Build Coastguard Workerfirst (only on the first topological sort). If it fails to eliminate overflows then shortest distance
94*2d1272b8SAndroid Build Coastguard Workersort will be used for all subsequent topological sorting operations.
95*2d1272b8SAndroid Build Coastguard Worker
96*2d1272b8SAndroid Build Coastguard Worker## Shortest Distance Sort
97*2d1272b8SAndroid Build Coastguard Worker
98*2d1272b8SAndroid Build Coastguard WorkerThis algorithm orders the nodes based on total distance to each node. Nodes with a shorter distance
99*2d1272b8SAndroid Build Coastguard Workerare ordered first.
100*2d1272b8SAndroid Build Coastguard Worker
101*2d1272b8SAndroid Build Coastguard WorkerThe "weight" of an edge is the sum of the size of the sub-table being pointed to plus 2^16 for a 16 bit
102*2d1272b8SAndroid Build Coastguard Workeroffset and 2^32 for a 32 bit offset.
103*2d1272b8SAndroid Build Coastguard Worker
104*2d1272b8SAndroid Build Coastguard WorkerThe distance of a node is the sum of all weights along the shortest path from the root to that node
105*2d1272b8SAndroid Build Coastguard Workerplus a priority modifier (used to change where nodes are placed by moving increasing or
106*2d1272b8SAndroid Build Coastguard Workerdecreasing the effective distance). Ties between nodes with the same distance are broken based
107*2d1272b8SAndroid Build Coastguard Workeron the order of the offset in the sub table bytes.
108*2d1272b8SAndroid Build Coastguard Worker
109*2d1272b8SAndroid Build Coastguard WorkerThe shortest distance to each node is determined using
110*2d1272b8SAndroid Build Coastguard Worker[Djikstra's algorithm](https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm). Then the topological
111*2d1272b8SAndroid Build Coastguard Workerordering is produce by applying a modified version of Kahn's algorithm that uses a priority queue
112*2d1272b8SAndroid Build Coastguard Workerbased on the shortest distance to each node.
113*2d1272b8SAndroid Build Coastguard Worker
114*2d1272b8SAndroid Build Coastguard Worker## Optimizing the Sorting
115*2d1272b8SAndroid Build Coastguard Worker
116*2d1272b8SAndroid Build Coastguard WorkerThe topological sorting operation is the core of the repacker and is run on each iteration so it needs
117*2d1272b8SAndroid Build Coastguard Workerto be as fast as possible. There's a few things that are done to speed up subsequent sorting
118*2d1272b8SAndroid Build Coastguard Workeroperations:
119*2d1272b8SAndroid Build Coastguard Worker
120*2d1272b8SAndroid Build Coastguard Worker*  The number of incoming edges to each node is cached. This is required by the Kahn's algorithm
121*2d1272b8SAndroid Build Coastguard Worker   portion of both sorts. Where possible when the graph is modified we manually update the cached
122*2d1272b8SAndroid Build Coastguard Worker   edge counts of affected nodes.
123*2d1272b8SAndroid Build Coastguard Worker
124*2d1272b8SAndroid Build Coastguard Worker*  The distance to each node is cached. Where possible when the graph is modified we manually update
125*2d1272b8SAndroid Build Coastguard Worker   the cached distances of any affected nodes.
126*2d1272b8SAndroid Build Coastguard Worker
127*2d1272b8SAndroid Build Coastguard WorkerCaching these values allows the repacker to avoid recalculating them for the full graph on each
128*2d1272b8SAndroid Build Coastguard Workeriteration.
129*2d1272b8SAndroid Build Coastguard Worker
130*2d1272b8SAndroid Build Coastguard WorkerThe other important factor to speed is a fast priority queue which is a core datastructure to
131*2d1272b8SAndroid Build Coastguard Workerthe topological sorting algorithm. Currently a basic heap based queue is used. Heap based queue's
132*2d1272b8SAndroid Build Coastguard Workerdon't support fast priority decreases, but that can be worked around by just adding redundant entries
133*2d1272b8SAndroid Build Coastguard Workerto the priority queue and filtering the older ones out when poppping off entries. This is based
134*2d1272b8SAndroid Build Coastguard Workeron the recommendations in
135*2d1272b8SAndroid Build Coastguard Worker[a study of the practical performance of priority queues in Dijkstra's algorithm](https://www3.cs.stonybrook.edu/~rezaul/papers/TR-07-54.pdf)
136*2d1272b8SAndroid Build Coastguard Worker
137*2d1272b8SAndroid Build Coastguard Worker## Special Handling of 32 bit Offsets
138*2d1272b8SAndroid Build Coastguard Worker
139*2d1272b8SAndroid Build Coastguard WorkerIf a graph contains multiple 32 bit offsets then the shortest distance sorting will be likely be
140*2d1272b8SAndroid Build Coastguard Workersuboptimal. For example consider the case where a graph contains two 32 bit offsets that each point
141*2d1272b8SAndroid Build Coastguard Workerto a subgraph which are not connected to each other. The shortest distance sort will interleave the
142*2d1272b8SAndroid Build Coastguard Workersubtables of the two subgraphs, potentially resulting in overflows. Since each of these subgraphs are
143*2d1272b8SAndroid Build Coastguard Workerindependent of each other, and 32 bit offsets can point extremely long distances a better strategy is
144*2d1272b8SAndroid Build Coastguard Workerto pack the first subgraph in it's entirety and then have the second subgraph packed after with the 32
145*2d1272b8SAndroid Build Coastguard Workerbit offset pointing over the first subgraph. For example given the graph:
146*2d1272b8SAndroid Build Coastguard Worker
147*2d1272b8SAndroid Build Coastguard Worker
148*2d1272b8SAndroid Build Coastguard Worker```
149*2d1272b8SAndroid Build Coastguard Workera--- b -- d -- f
150*2d1272b8SAndroid Build Coastguard Worker \
151*2d1272b8SAndroid Build Coastguard Worker  \_ c -- e -- g
152*2d1272b8SAndroid Build Coastguard Worker```
153*2d1272b8SAndroid Build Coastguard Worker
154*2d1272b8SAndroid Build Coastguard WorkerWhere the links from a to b and a to c are 32 bit offsets, the shortest distance sort would be:
155*2d1272b8SAndroid Build Coastguard Worker
156*2d1272b8SAndroid Build Coastguard Worker```
157*2d1272b8SAndroid Build Coastguard Workera, b, c, d, e, f, g
158*2d1272b8SAndroid Build Coastguard Worker
159*2d1272b8SAndroid Build Coastguard Worker```
160*2d1272b8SAndroid Build Coastguard Worker
161*2d1272b8SAndroid Build Coastguard WorkerIf nodes d and e have a combined size greater than 65kb then the offset from d to f will overflow.
162*2d1272b8SAndroid Build Coastguard WorkerA better ordering is:
163*2d1272b8SAndroid Build Coastguard Worker
164*2d1272b8SAndroid Build Coastguard Worker```
165*2d1272b8SAndroid Build Coastguard Workera, b, d, f, c, e, g
166*2d1272b8SAndroid Build Coastguard Worker```
167*2d1272b8SAndroid Build Coastguard Worker
168*2d1272b8SAndroid Build Coastguard WorkerThe ability for 32 bit offsets to point long distances is utilized to jump over the subgraph of
169*2d1272b8SAndroid Build Coastguard Workerb which gives the remaining 16 bit offsets a better chance of not overflowing.
170*2d1272b8SAndroid Build Coastguard Worker
171*2d1272b8SAndroid Build Coastguard WorkerThe above is an ideal situation where the subgraphs are disconnected from each other, in practice
172*2d1272b8SAndroid Build Coastguard Workerthis is often not this case. So this idea can be generalized as follows:
173*2d1272b8SAndroid Build Coastguard Worker
174*2d1272b8SAndroid Build Coastguard WorkerIf there is a subgraph that is only reachable from one or more 32 bit offsets, then:
175*2d1272b8SAndroid Build Coastguard Worker*  That subgraph can be treated as an independent unit and all nodes of the subgraph packed in isolation
176*2d1272b8SAndroid Build Coastguard Worker   from the rest of the graph.
177*2d1272b8SAndroid Build Coastguard Worker*  In a table that occupies less than 4gb of space (in practice all fonts), that packed independent
178*2d1272b8SAndroid Build Coastguard Worker   subgraph can be placed anywhere after the parent nodes without overflowing the 32 bit offsets from
179*2d1272b8SAndroid Build Coastguard Worker   the parent nodes.
180*2d1272b8SAndroid Build Coastguard Worker
181*2d1272b8SAndroid Build Coastguard WorkerThe sorting algorithm incorporates this via a "space" modifier that can be applied to nodes in the
182*2d1272b8SAndroid Build Coastguard Workergraph. By default all nodes are treated as being in space zero. If a node is given a non-zero space, n,
183*2d1272b8SAndroid Build Coastguard Workerthen the computed distance to the node will be modified by adding `n * 2^32`. This will cause that
184*2d1272b8SAndroid Build Coastguard Workernode and it's descendants to be packed between all nodes in space n-1 and space n+1. Resulting in a
185*2d1272b8SAndroid Build Coastguard Workertopological sort like:
186*2d1272b8SAndroid Build Coastguard Worker
187*2d1272b8SAndroid Build Coastguard Worker```
188*2d1272b8SAndroid Build Coastguard Worker| space 0 subtables | space 1 subtables | .... | space n subtables |
189*2d1272b8SAndroid Build Coastguard Worker```
190*2d1272b8SAndroid Build Coastguard Worker
191*2d1272b8SAndroid Build Coastguard WorkerThe assign_spaces() step in the high level algorithm is responsible for identifying independent
192*2d1272b8SAndroid Build Coastguard Workersubgraphs and assigning unique spaces to each one. More information on the space assignment can be
193*2d1272b8SAndroid Build Coastguard Workerfound in the next section.
194*2d1272b8SAndroid Build Coastguard Worker
195*2d1272b8SAndroid Build Coastguard Worker# Graph Preprocessing
196*2d1272b8SAndroid Build Coastguard Worker
197*2d1272b8SAndroid Build Coastguard WorkerFor certain table types we can preprocess and modify the graph structure to reduce the occurences
198*2d1272b8SAndroid Build Coastguard Workerof overflows. Currently the repacker implements preprocessing only for GPOS and GSUB tables.
199*2d1272b8SAndroid Build Coastguard Worker
200*2d1272b8SAndroid Build Coastguard Worker## GSUB/GPOS Table Splitting
201*2d1272b8SAndroid Build Coastguard Worker
202*2d1272b8SAndroid Build Coastguard WorkerThe GSUB/GPOS preprocessor scans each lookup subtable and determines if the subtable's children are
203*2d1272b8SAndroid Build Coastguard Workerso large that no overflow resolution is possible (for example a single subtable that exceeds 65kb
204*2d1272b8SAndroid Build Coastguard Workercannot be pointed over). When such cases are detected table splitting is invoked:
205*2d1272b8SAndroid Build Coastguard Worker
206*2d1272b8SAndroid Build Coastguard Worker* The subtable is first analyzed to determine the smallest number of split points that will allow
207*2d1272b8SAndroid Build Coastguard Worker  for successful offset overflow resolution.
208*2d1272b8SAndroid Build Coastguard Worker
209*2d1272b8SAndroid Build Coastguard Worker* Then the subtable in the graph representation is modified to actually perform the split at the
210*2d1272b8SAndroid Build Coastguard Worker  previously computed split points. At a high level splits are done by inserting new subtables
211*2d1272b8SAndroid Build Coastguard Worker  which contain a subset of the data of the original subtable and then shrinking the original subtable.
212*2d1272b8SAndroid Build Coastguard Worker
213*2d1272b8SAndroid Build Coastguard WorkerTable splitting must be aware of the underlying format of each subtable type and thus needs custom
214*2d1272b8SAndroid Build Coastguard Workercode for each subtable type. Currently subtable splitting is only supported for GPOS subtable types.
215*2d1272b8SAndroid Build Coastguard Worker
216*2d1272b8SAndroid Build Coastguard Worker## GSUB/GPOS Extension Lookup Promotion
217*2d1272b8SAndroid Build Coastguard Worker
218*2d1272b8SAndroid Build Coastguard WorkerIn GSUB/GPOS tables lookups can be regular lookups which use 16 bit offsets to the children subtables
219*2d1272b8SAndroid Build Coastguard Workeror extension lookups which use 32 bit offsets to the children subtables. If the sub graph of all
220*2d1272b8SAndroid Build Coastguard Workerregular lookups is too large then it can be difficult to find an overflow free configuration. This
221*2d1272b8SAndroid Build Coastguard Workercan be remedied by promoting one or more regular lookups to extension lookups.
222*2d1272b8SAndroid Build Coastguard Worker
223*2d1272b8SAndroid Build Coastguard WorkerDuring preprocessing the graph is scanned to determine the size of the subgraph of regular lookups.
224*2d1272b8SAndroid Build Coastguard WorkerIf the graph is found to be too big then the analysis finds a set of lookups to promote to reduce
225*2d1272b8SAndroid Build Coastguard Workerthe subgraph size. Lastly the graph is modified to convert those lookups to extension lookups.
226*2d1272b8SAndroid Build Coastguard Worker
227*2d1272b8SAndroid Build Coastguard Worker# Offset Resolution Strategies
228*2d1272b8SAndroid Build Coastguard Worker
229*2d1272b8SAndroid Build Coastguard Worker## Space Assignment
230*2d1272b8SAndroid Build Coastguard Worker
231*2d1272b8SAndroid Build Coastguard WorkerThe goal of space assignment is to find connected subgraphs that are only reachable via 32 bit offsets
232*2d1272b8SAndroid Build Coastguard Workerand then assign each such subgraph to a unique non-zero space. The algorithm is roughly:
233*2d1272b8SAndroid Build Coastguard Worker
234*2d1272b8SAndroid Build Coastguard Worker1.  Collect the set, `S`, of nodes that are children of 32 bit offsets.
235*2d1272b8SAndroid Build Coastguard Worker
236*2d1272b8SAndroid Build Coastguard Worker2.  Do a directed traversal from each node in `S` and collect all encountered nodes into set `T`.
237*2d1272b8SAndroid Build Coastguard Worker    Mark all nodes in the graph that are not in `T` as being in space 0.
238*2d1272b8SAndroid Build Coastguard Worker
239*2d1272b8SAndroid Build Coastguard Worker3.  Set `next_space = 1`.
240*2d1272b8SAndroid Build Coastguard Worker
241*2d1272b8SAndroid Build Coastguard Worker4.  While set `S` is not empty:
242*2d1272b8SAndroid Build Coastguard Worker
243*2d1272b8SAndroid Build Coastguard Worker    a.  Pick a node `n` in set `S` then perform an undirected graph traversal and find the set `Q` of
244*2d1272b8SAndroid Build Coastguard Worker        nodes that are reachable from `n`.
245*2d1272b8SAndroid Build Coastguard Worker
246*2d1272b8SAndroid Build Coastguard Worker    b.  During traversal if a node, `m`, has a edge to a node in space 0 then `m` must be duplicated
247*2d1272b8SAndroid Build Coastguard Worker        to disconnect it from space 0.
248*2d1272b8SAndroid Build Coastguard Worker
249*2d1272b8SAndroid Build Coastguard Worker    d.  Remove all nodes in `Q` from `S` and assign all nodes in `Q` to `next_space`.
250*2d1272b8SAndroid Build Coastguard Worker
251*2d1272b8SAndroid Build Coastguard Worker
252*2d1272b8SAndroid Build Coastguard Worker    c.  Increment `next_space` by one.
253*2d1272b8SAndroid Build Coastguard Worker
254*2d1272b8SAndroid Build Coastguard Worker
255*2d1272b8SAndroid Build Coastguard Worker## Manual Iterative Resolutions
256*2d1272b8SAndroid Build Coastguard Worker
257*2d1272b8SAndroid Build Coastguard WorkerFor each overflow in each iteration the algorithm will attempt to apply offset overflow resolution
258*2d1272b8SAndroid Build Coastguard Workerstrategies to eliminate the overflow. The type of strategy applied is dependent on the characteristics
259*2d1272b8SAndroid Build Coastguard Workerof the overflowing link:
260*2d1272b8SAndroid Build Coastguard Worker
261*2d1272b8SAndroid Build Coastguard Worker*  If the overflowing offset is inside a space other than space 0 and the subgraph space has more
262*2d1272b8SAndroid Build Coastguard Worker   than one 32 bit offset pointing into the subgraph then subdivide the space by moving subgraph
263*2d1272b8SAndroid Build Coastguard Worker   from one of the 32 bit offsets into a new space via the duplication of shared nodes.
264*2d1272b8SAndroid Build Coastguard Worker
265*2d1272b8SAndroid Build Coastguard Worker*  If the overflowing offset is pointing to a subtable with more than one incoming edge: duplicate
266*2d1272b8SAndroid Build Coastguard Worker   the node so that the overflowing offset is pointing at it's own copy of that node.
267*2d1272b8SAndroid Build Coastguard Worker
268*2d1272b8SAndroid Build Coastguard Worker*  Otherwise, attempt to move the child subtable closer to it's parent. This is accomplished by
269*2d1272b8SAndroid Build Coastguard Worker   raising the priority of all children of the parent. Next time the topological sort is run the
270*2d1272b8SAndroid Build Coastguard Worker   children will be ordered closer to the parent.
271*2d1272b8SAndroid Build Coastguard Worker
272*2d1272b8SAndroid Build Coastguard Worker# Test Cases
273*2d1272b8SAndroid Build Coastguard Worker
274*2d1272b8SAndroid Build Coastguard WorkerThe harfbuzz repacker has tests defined using generic graphs: https://github.com/harfbuzz/harfbuzz/blob/main/src/test-repacker.cc
275*2d1272b8SAndroid Build Coastguard Worker
276*2d1272b8SAndroid Build Coastguard Worker# Future Improvements
277*2d1272b8SAndroid Build Coastguard Worker
278*2d1272b8SAndroid Build Coastguard WorkerCurrently for GPOS tables the repacker implementation is sufficient to handle both subsetting and the
279*2d1272b8SAndroid Build Coastguard Workergeneral case of font compilation repacking. However for GSUB the repacker is only sufficient for
280*2d1272b8SAndroid Build Coastguard Workersubsetting related overflows. To enable general case repacking of GSUB, support for splitting of
281*2d1272b8SAndroid Build Coastguard WorkerGSUB subtables will need to be added. Other table types such as COLRv1 shouldn't require table
282*2d1272b8SAndroid Build Coastguard Workersplitting due to the wide use of 24 bit offsets throughout the table.
283*2d1272b8SAndroid Build Coastguard Worker
284*2d1272b8SAndroid Build Coastguard WorkerBeyond subtable splitting there are a couple of "nice to have" improvements, but these are not required
285*2d1272b8SAndroid Build Coastguard Workerto support the general case:
286*2d1272b8SAndroid Build Coastguard Worker
287*2d1272b8SAndroid Build Coastguard Worker*  Extension demotion: currently extension promotion is supported but in some cases if the non-extension
288*2d1272b8SAndroid Build Coastguard Worker   subgraph is underfilled then packed size can be reduced by demoting extension lookups back to regular
289*2d1272b8SAndroid Build Coastguard Worker   lookups.
290*2d1272b8SAndroid Build Coastguard Worker
291*2d1272b8SAndroid Build Coastguard Worker*  Currently only children nodes are moved to resolve offsets. However, in many cases moving a parent
292*2d1272b8SAndroid Build Coastguard Worker   node closer to it's children will have less impact on the size of other offsets. Thus the algorithm
293*2d1272b8SAndroid Build Coastguard Worker   should use a heuristic (based on parent and child subtable sizes) to decide if the children's
294*2d1272b8SAndroid Build Coastguard Worker   priority should be increased or the parent's priority decreased.
295