Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/harfbuzz/src/./../../../../gfx/harfbuzz/src/graph/pairpos-graph.hh
Warning:line 288, column 9
Value stored to 'coverage_size' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_gfx_harfbuzz_src0.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/harfbuzz/src -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/harfbuzz/src -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D PACKAGE_VERSION="moz" -D PACKAGE_BUGREPORT="http://bugzilla.mozilla.org/" -D HAVE_OT=1 -D HAVE_ROUND=1 -D HB_NO_BUFFER_VERIFY -D HB_NO_FALLBACK_SHAPE -D HB_NO_PAINT -D HB_NO_UCD -D HB_NO_UNICODE_FUNCS -D HB_NO_VAR_COMPOSITES -D HAVE_MMAP=1 -D HAVE_SYS_MMAN_H=1 -D HAVE_UNISTD_H=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/gfx/harfbuzz/src -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/harfbuzz/src -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-10-17-231001-351276-1 -x c++ Unified_cpp_gfx_harfbuzz_src0.cpp
1/*
2 * Copyright © 2022 Google, Inc.
3 *
4 * This is part of HarfBuzz, a text shaping library.
5 *
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
11 *
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16 * DAMAGE.
17 *
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 *
24 * Google Author(s): Garret Rieger
25 */
26
27#ifndef GRAPH_PAIRPOS_GRAPH_HH
28#define GRAPH_PAIRPOS_GRAPH_HH
29
30#include "split-helpers.hh"
31#include "coverage-graph.hh"
32#include "classdef-graph.hh"
33#include "../OT/Layout/GPOS/PairPos.hh"
34#include "../OT/Layout/GPOS/PosLookupSubTable.hh"
35
36namespace graph {
37
38struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>
39{
40 graph_result_t<void> sanitize (const graph_t::vertex_t& vertex) const
41 {
42 size_t vertex_len = vertex.table_size ();
43 unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size;
44 if (unlikely (vertex_len < min_size)__builtin_expect (bool(vertex_len < min_size), 0)) return Err(SANITIZE_FAILURE);
45 hb_barrier ();
46
47 if (unlikely (vertex_len < min_size + pairSet.get_size () - pairSet.len.get_size())__builtin_expect (bool(vertex_len < min_size + pairSet.get_size
() - pairSet.len.get_size()), 0)
)
48 return Err(SANITIZE_FAILURE);
49 return Ok();
50 }
51
52 graph_result_t<hb_vector_t<unsigned>> split_subtables (gsubgpos_graph_context_t& c,
53 unsigned this_index)
54 {
55 hb_set_t visited;
56
57 TRY_ASSIGN (const unsigned coverage_id, c.graph.index_for_offset (this_index, &coverage))auto _res_57 = (c.graph.index_for_offset (this_index, &coverage
)); if (__builtin_expect (bool(!_res_57.is_ok()), 0)) return Err
(std::move(_res_57).error()); const unsigned coverage_id = *std
::move(_res_57)
;
58 const unsigned coverage_size = c.graph.vertices_[coverage_id].table_size ();
59 const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size;
60
61 unsigned partial_coverage_size = 4;
62 unsigned accumulated = base_size;
63 hb_vector_t<unsigned> split_points;
64 for (unsigned i = 0; i < pairSet.len; i++)
65 {
66 TRY_ASSIGN (unsigned pair_set_index, pair_set_graph_index (c, this_index, i))auto _res_66 = (pair_set_graph_index (c, this_index, i)); if (
__builtin_expect (bool(!_res_66.is_ok()), 0)) return Err(std::
move(_res_66).error()); unsigned pair_set_index = *std::move(
_res_66)
;
67 unsigned accumulated_delta =
68 c.graph.find_subgraph_size (pair_set_index, visited).value_or (0) +
69 SmallTypes::size; // for PairSet offset.
70 partial_coverage_size += OT::HBUINT16::static_size;
71
72 accumulated += accumulated_delta;
73 unsigned total = accumulated + hb_min (partial_coverage_size, coverage_size);
74
75 if (total >= (1 << 16))
76 {
77 split_points.push (i);
78 TRY (graph_result_t<void>::from (split_points, ALLOCATION_FAILURE))do { auto _res = (graph_result_t<void>::from (split_points
, ALLOCATION_FAILURE)); if (__builtin_expect (bool(!_res.is_ok
()), 0)) return Err(std::move(_res).error()); } while (0)
;
79 accumulated = base_size + accumulated_delta;
80 partial_coverage_size = 6;
81 visited.clear (); // node sharing isn't allowed between splits.
82 }
83 }
84
85 split_context_t split_context {
86 c,
87 this,
88 this_index,
89 };
90
91 return actuate_subtable_split<split_context_t> (split_context, split_points);
92 }
93
94 private:
95
96 struct split_context_t {
97 gsubgpos_graph_context_t& c;
98 PairPosFormat1* thiz;
99 unsigned this_index;
100
101 unsigned original_count ()
102 {
103 return thiz->pairSet.len;
104 }
105
106 graph_result_t<unsigned> clone_range (unsigned start, unsigned end)
107 {
108 return thiz->clone_range (this->c, this->this_index, start, end);
109 }
110
111 graph_result_t<void> shrink (unsigned count)
112 {
113 return thiz->shrink (this->c, this->this_index, count);
114 }
115 };
116
117 graph_result_t<void> shrink (gsubgpos_graph_context_t& c,
118 unsigned this_index,
119 unsigned count)
120 {
121 DEBUG_MSG (SUBSET_REPACK, nullptr,_hb_debug_msg<(0 +0)> ("SUBSET_REPACK", (nullptr), nullptr
, false, 0, 0, " Shrinking PairPosFormat1 (%u) to [0, %u).",
this_index, count)
122 " Shrinking PairPosFormat1 (%u) to [0, %u).",_hb_debug_msg<(0 +0)> ("SUBSET_REPACK", (nullptr), nullptr
, false, 0, 0, " Shrinking PairPosFormat1 (%u) to [0, %u).",
this_index, count)
123 this_index,_hb_debug_msg<(0 +0)> ("SUBSET_REPACK", (nullptr), nullptr
, false, 0, 0, " Shrinking PairPosFormat1 (%u) to [0, %u).",
this_index, count)
124 count)_hb_debug_msg<(0 +0)> ("SUBSET_REPACK", (nullptr), nullptr
, false, 0, 0, " Shrinking PairPosFormat1 (%u) to [0, %u).",
this_index, count)
;
125 unsigned old_count = pairSet.len;
126 if (count >= old_count)
127 return Ok();
128
129 pairSet.len = count;
130 c.graph.vertices_[this_index].shrink_buffer ((old_count - count) * SmallTypes::size);
131
132 TRY_ASSIGN (auto coverage, c.graph.as_mutable_table<Coverage> (this_index, &this->coverage))auto _res_132 = (c.graph.as_mutable_table<Coverage> (this_index
, &this->coverage)); if (__builtin_expect (bool(!_res_132
.is_ok()), 0)) return Err(std::move(_res_132).error()); auto coverage
= *std::move(_res_132)
;
133
134 unsigned coverage_size = coverage.vertex->table_size ();
135 auto new_coverage =
136 + hb_zip (coverage.table->iter (), hb_range ())
137 | hb_filter ([&] (hb_pair_t<unsigned, unsigned> p) {
138 return p.second < count;
139 })
140 | hb_map_retains_sorting (hb_first)
141 ;
142
143 return Coverage::make_coverage (c, new_coverage, coverage.index, coverage_size);
144 }
145
146 // Create a new PairPos including PairSet's from start (inclusive) to end (exclusive).
147 // Returns object id of the new object.
148 graph_result_t<unsigned> clone_range (gsubgpos_graph_context_t& c,
149 unsigned this_index,
150 unsigned start, unsigned end) const
151 {
152 DEBUG_MSG (SUBSET_REPACK, nullptr,_hb_debug_msg<(0 +0)> ("SUBSET_REPACK", (nullptr), nullptr
, false, 0, 0, " Cloning PairPosFormat1 (%u) range [%u, %u)."
, this_index, start, end)
153 " Cloning PairPosFormat1 (%u) range [%u, %u).", this_index, start, end)_hb_debug_msg<(0 +0)> ("SUBSET_REPACK", (nullptr), nullptr
, false, 0, 0, " Cloning PairPosFormat1 (%u) range [%u, %u)."
, this_index, start, end)
;
154
155 unsigned num_pair_sets = end - start;
156 unsigned prime_size = OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size
157 + num_pair_sets * SmallTypes::size;
158
159 TRY_ASSIGN (unsigned pair_pos_prime_id, c.create_node (prime_size))auto _res_159 = (c.create_node (prime_size)); if (__builtin_expect
(bool(!_res_159.is_ok()), 0)) return Err(std::move(_res_159)
.error()); unsigned pair_pos_prime_id = *std::move(_res_159)
;
160
161 PairPosFormat1* pair_pos_prime = (PairPosFormat1*) c.graph.object (pair_pos_prime_id).head;
162 pair_pos_prime->format = this->format;
163 pair_pos_prime->valueFormat[0] = this->valueFormat[0];
164 pair_pos_prime->valueFormat[1] = this->valueFormat[1];
165 pair_pos_prime->pairSet.len = num_pair_sets;
166
167 for (unsigned i = start; i < end; i++)
168 {
169 TRY (c.graph.move_child<> (this_index,do { auto _res = (c.graph.move_child<> (this_index, &
pairSet[i], pair_pos_prime_id, &pair_pos_prime->pairSet
[i - start])); if (__builtin_expect (bool(!_res.is_ok()), 0))
return Err(std::move(_res).error()); } while (0)
170 &pairSet[i],do { auto _res = (c.graph.move_child<> (this_index, &
pairSet[i], pair_pos_prime_id, &pair_pos_prime->pairSet
[i - start])); if (__builtin_expect (bool(!_res.is_ok()), 0))
return Err(std::move(_res).error()); } while (0)
171 pair_pos_prime_id,do { auto _res = (c.graph.move_child<> (this_index, &
pairSet[i], pair_pos_prime_id, &pair_pos_prime->pairSet
[i - start])); if (__builtin_expect (bool(!_res.is_ok()), 0))
return Err(std::move(_res).error()); } while (0)
172 &pair_pos_prime->pairSet[i - start]))do { auto _res = (c.graph.move_child<> (this_index, &
pairSet[i], pair_pos_prime_id, &pair_pos_prime->pairSet
[i - start])); if (__builtin_expect (bool(!_res.is_ok()), 0))
return Err(std::move(_res).error()); } while (0)
;
173 }
174
175 // Restore correct ordering of the vertex links which are disturbed by move_child.
176 c.graph.vertices_[this_index].sort_real_links ();
177
178 TRY_ASSIGN (unsigned coverage_id, c.graph.index_for_offset (this_index, &coverage))auto _res_178 = (c.graph.index_for_offset (this_index, &coverage
)); if (__builtin_expect (bool(!_res_178.is_ok()), 0)) return
Err(std::move(_res_178).error()); unsigned coverage_id = *std
::move(_res_178)
;
179 TRY (Coverage::clone_coverage (c,do { auto _res = (Coverage::clone_coverage (c, coverage_id, pair_pos_prime_id
, 2, start, end)); if (__builtin_expect (bool(!_res.is_ok()),
0)) return Err(std::move(_res).error()); } while (0)
180 coverage_id,do { auto _res = (Coverage::clone_coverage (c, coverage_id, pair_pos_prime_id
, 2, start, end)); if (__builtin_expect (bool(!_res.is_ok()),
0)) return Err(std::move(_res).error()); } while (0)
181 pair_pos_prime_id,do { auto _res = (Coverage::clone_coverage (c, coverage_id, pair_pos_prime_id
, 2, start, end)); if (__builtin_expect (bool(!_res.is_ok()),
0)) return Err(std::move(_res).error()); } while (0)
182 2,do { auto _res = (Coverage::clone_coverage (c, coverage_id, pair_pos_prime_id
, 2, start, end)); if (__builtin_expect (bool(!_res.is_ok()),
0)) return Err(std::move(_res).error()); } while (0)
183 start, end))do { auto _res = (Coverage::clone_coverage (c, coverage_id, pair_pos_prime_id
, 2, start, end)); if (__builtin_expect (bool(!_res.is_ok()),
0)) return Err(std::move(_res).error()); } while (0)
;
184
185 return Ok(pair_pos_prime_id);
186 }
187
188
189
190 graph_result_t<unsigned> pair_set_graph_index (gsubgpos_graph_context_t& c, unsigned this_index, unsigned i) const
191 {
192 return c.graph.index_for_offset (this_index, &pairSet[i]);
193 }
194};
195
196struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>
197{
198 graph_result_t<void> sanitize (const graph_t::vertex_t& vertex) const
199 {
200 size_t vertex_len = vertex.table_size ();
201 unsigned min_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size;
202 if (unlikely (vertex_len < min_size)__builtin_expect (bool(vertex_len < min_size), 0)) return Err(SANITIZE_FAILURE);
203 hb_barrier ();
204
205 const unsigned class1_count = class1Count;
206 if (unlikely (vertex_len < min_size + class1_count * get_class1_record_size ())__builtin_expect (bool(vertex_len < min_size + class1_count
* get_class1_record_size ()), 0)
)
207 return Err(SANITIZE_FAILURE);
208 return Ok();
209 }
210
211 graph_result_t<hb_vector_t<unsigned>> split_subtables (gsubgpos_graph_context_t& c,
212 unsigned this_index)
213 {
214 const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size;
215 TRY_ASSIGN (const unsigned class_def_2_size, size_of (c, this_index, &classDef2))auto _res_215 = (size_of (c, this_index, &classDef2)); if
(__builtin_expect (bool(!_res_215.is_ok()), 0)) return Err(std
::move(_res_215).error()); const unsigned class_def_2_size = *
std::move(_res_215)
;
216 TRY_ASSIGN (const Coverage* coverage, get_coverage (c, this_index))auto _res_216 = (get_coverage (c, this_index)); if (__builtin_expect
(bool(!_res_216.is_ok()), 0)) return Err(std::move(_res_216)
.error()); const Coverage* coverage = *std::move(_res_216)
;
217 TRY_ASSIGN (const ClassDef* class_def_1, get_class_def_1 (c, this_index))auto _res_217 = (get_class_def_1 (c, this_index)); if (__builtin_expect
(bool(!_res_217.is_ok()), 0)) return Err(std::move(_res_217)
.error()); const ClassDef* class_def_1 = *std::move(_res_217)
;
218 auto gid_and_class =
219 + coverage->iter ()
220 | hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
221 return hb_codepoint_pair_t (gid, class_def_1->get_class (gid));
222 })
223 ;
224 TRY_ASSIGN (class_def_size_estimator_t estimator, class_def_size_estimator_t::create (gid_and_class))auto _res_224 = (class_def_size_estimator_t::create (gid_and_class
)); if (__builtin_expect (bool(!_res_224.is_ok()), 0)) return
Err(std::move(_res_224).error()); class_def_size_estimator_t
estimator = *std::move(_res_224)
;
225
226 const unsigned class1_count = class1Count;
227 const unsigned class2_count = class2Count;
228 const unsigned class1_record_size = get_class1_record_size ();
229
230 const unsigned value_1_len = valueFormat1.get_len ();
231 const unsigned value_2_len = valueFormat2.get_len ();
232 const unsigned total_value_len = value_1_len + value_2_len;
233
234 unsigned accumulated = base_size;
235 unsigned coverage_size = 4;
236 unsigned class_def_1_size = 4;
237 unsigned max_coverage_size = coverage_size;
238 unsigned max_class_def_1_size = class_def_1_size;
239
240 hb_vector_t<unsigned> split_points;
241
242 TRY_ASSIGN (auto device_tables, get_all_device_tables (c, this_index))auto _res_242 = (get_all_device_tables (c, this_index)); if (
__builtin_expect (bool(!_res_242.is_ok()), 0)) return Err(std
::move(_res_242).error()); auto device_tables = *std::move(_res_242
)
;
243 hb_vector_t<unsigned> format1_device_table_indices = valueFormat1.get_device_table_indices ();
244 hb_vector_t<unsigned> format2_device_table_indices = valueFormat2.get_device_table_indices ();
245 bool has_device_tables = bool(format1_device_table_indices) || bool(format2_device_table_indices);
246
247 hb_set_t visited;
248 for (unsigned i = 0; i < class1_count; i++)
249 {
250 unsigned accumulated_delta = class1_record_size;
251 class_def_1_size = estimator.add_class_def_size (i);
252 coverage_size = estimator.coverage_size ();
253 max_coverage_size = hb_max (max_coverage_size, coverage_size);
254 max_class_def_1_size = hb_max (max_class_def_1_size, class_def_1_size);
255
256 if (has_device_tables) {
257 for (unsigned j = 0; j < class2_count; j++)
258 {
259 unsigned value1_index = total_value_len * (class2_count * i + j);
260 unsigned value2_index = value1_index + value_1_len;
261 accumulated_delta += size_of_value_record_children (c,
262 device_tables,
263 format1_device_table_indices,
264 value1_index,
265 visited);
266 accumulated_delta += size_of_value_record_children (c,
267 device_tables,
268 format2_device_table_indices,
269 value2_index,
270 visited);
271 }
272 }
273
274 accumulated += accumulated_delta;
275 unsigned total = accumulated
276 + coverage_size + class_def_1_size + class_def_2_size
277 // The largest object will pack last and can exceed the size limit.
278 - hb_max (hb_max (coverage_size, class_def_1_size), class_def_2_size);
279 if (total >= (1 << 16))
280 {
281 split_points.push (i);
282 TRY (graph_result_t<void>::from (split_points, ALLOCATION_FAILURE))do { auto _res = (graph_result_t<void>::from (split_points
, ALLOCATION_FAILURE)); if (__builtin_expect (bool(!_res.is_ok
()), 0)) return Err(std::move(_res).error()); } while (0)
;
283 // split does not include i, so add the size for i when we reset the size counters.
284 accumulated = base_size + accumulated_delta;
285
286 estimator.reset();
287 class_def_1_size = estimator.add_class_def_size(i);
288 coverage_size = estimator.coverage_size();
Value stored to 'coverage_size' is never read
289 visited.clear (); // node sharing isn't allowed between splits.
290 }
291 }
292
293 split_context_t split_context {
294 c,
295 this,
296 this_index,
297 class1_record_size,
298 total_value_len,
299 value_1_len,
300 value_2_len,
301 max_coverage_size,
302 max_class_def_1_size,
303 device_tables,
304 format1_device_table_indices,
305 format2_device_table_indices
306 };
307
308 return actuate_subtable_split<split_context_t> (split_context, split_points);
309 }
310 private:
311
312 struct split_context_t
313 {
314 gsubgpos_graph_context_t& c;
315 PairPosFormat2* thiz;
316 unsigned this_index;
317 unsigned class1_record_size;
318 unsigned value_record_len;
319 unsigned value1_record_len;
320 unsigned value2_record_len;
321 unsigned max_coverage_size;
322 unsigned max_class_def_size;
323
324 const hb_hashmap_t<unsigned, unsigned>& device_tables;
325 const hb_vector_t<unsigned>& format1_device_table_indices;
326 const hb_vector_t<unsigned>& format2_device_table_indices;
327
328 unsigned original_count ()
329 {
330 return thiz->class1Count;
331 }
332
333 graph_result_t<unsigned> clone_range (unsigned start, unsigned end)
334 {
335 return thiz->clone_range (*this, start, end);
336 }
337
338 graph_result_t<void> shrink (unsigned count)
339 {
340 return thiz->shrink (*this, count);
341 }
342 };
343
344 size_t get_class1_record_size () const
345 {
346 const size_t class2_count = class2Count;
347 return
348 class2_count * (valueFormat1.get_size () + valueFormat2.get_size ());
349 }
350
351 graph_result_t<unsigned> clone_range (split_context_t& split_context,
352 unsigned start, unsigned end) const
353 {
354 DEBUG_MSG (SUBSET_REPACK, nullptr,_hb_debug_msg<(0 +0)> ("SUBSET_REPACK", (nullptr), nullptr
, false, 0, 0, " Cloning PairPosFormat2 (%u) range [%u, %u)."
, split_context.this_index, start, end)
355 " Cloning PairPosFormat2 (%u) range [%u, %u).", split_context.this_index, start, end)_hb_debug_msg<(0 +0)> ("SUBSET_REPACK", (nullptr), nullptr
, false, 0, 0, " Cloning PairPosFormat2 (%u) range [%u, %u)."
, split_context.this_index, start, end)
;
356
357 graph_t& graph = split_context.c.graph;
358
359 unsigned num_records = end - start;
360 unsigned prime_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size
361 + num_records * split_context.class1_record_size;
362
363 TRY_ASSIGN (unsigned pair_pos_prime_id, split_context.c.create_node (prime_size))auto _res_363 = (split_context.c.create_node (prime_size)); if
(__builtin_expect (bool(!_res_363.is_ok()), 0)) return Err(std
::move(_res_363).error()); unsigned pair_pos_prime_id = *std::
move(_res_363)
;
364
365 PairPosFormat2* pair_pos_prime =
366 (PairPosFormat2*) graph.object (pair_pos_prime_id).head;
367 pair_pos_prime->format = this->format;
368 pair_pos_prime->valueFormat1 = this->valueFormat1;
369 pair_pos_prime->valueFormat2 = this->valueFormat2;
370 pair_pos_prime->class1Count = num_records;
371 pair_pos_prime->class2Count = this->class2Count;
372 TRY (clone_class1_records (split_context,do { auto _res = (clone_class1_records (split_context, pair_pos_prime_id
, start, end)); if (__builtin_expect (bool(!_res.is_ok()), 0)
) return Err(std::move(_res).error()); } while (0)
373 pair_pos_prime_id,do { auto _res = (clone_class1_records (split_context, pair_pos_prime_id
, start, end)); if (__builtin_expect (bool(!_res.is_ok()), 0)
) return Err(std::move(_res).error()); } while (0)
374 start,do { auto _res = (clone_class1_records (split_context, pair_pos_prime_id
, start, end)); if (__builtin_expect (bool(!_res.is_ok()), 0)
) return Err(std::move(_res).error()); } while (0)
375 end))do { auto _res = (clone_class1_records (split_context, pair_pos_prime_id
, start, end)); if (__builtin_expect (bool(!_res.is_ok()), 0)
) return Err(std::move(_res).error()); } while (0)
;
376
377 TRY_ASSIGN (unsigned coverage_id,auto _res_378 = (graph.index_for_offset (split_context.this_index
, &coverage)); if (__builtin_expect (bool(!_res_378.is_ok
()), 0)) return Err(std::move(_res_378).error()); unsigned coverage_id
= *std::move(_res_378)
378 graph.index_for_offset (split_context.this_index, &coverage))auto _res_378 = (graph.index_for_offset (split_context.this_index
, &coverage)); if (__builtin_expect (bool(!_res_378.is_ok
()), 0)) return Err(std::move(_res_378).error()); unsigned coverage_id
= *std::move(_res_378)
;
379 TRY_ASSIGN (unsigned class_def_1_id,auto _res_380 = (graph.index_for_offset (split_context.this_index
, &classDef1)); if (__builtin_expect (bool(!_res_380.is_ok
()), 0)) return Err(std::move(_res_380).error()); unsigned class_def_1_id
= *std::move(_res_380)
380 graph.index_for_offset (split_context.this_index, &classDef1))auto _res_380 = (graph.index_for_offset (split_context.this_index
, &classDef1)); if (__builtin_expect (bool(!_res_380.is_ok
()), 0)) return Err(std::move(_res_380).error()); unsigned class_def_1_id
= *std::move(_res_380)
;
381
382 auto& coverage_v = graph.vertices_[coverage_id];
383 auto& class_def_1_v = graph.vertices_[class_def_1_id];
384 const Coverage* coverage_table = (const Coverage*) coverage_v.obj().head;
385 const ClassDef* class_def_1_table = (const ClassDef*) class_def_1_v.obj().head;
386 if (unlikely (!coverage_table || !class_def_1_table)__builtin_expect (bool(!coverage_table || !class_def_1_table)
, 0)
)
387 return Err(INVALID_ARGUMENT);
388 TRY (coverage_table->sanitize (coverage_v))do { auto _res = (coverage_table->sanitize (coverage_v)); if
(__builtin_expect (bool(!_res.is_ok()), 0)) return Err(std::
move(_res).error()); } while (0)
;
389 TRY (class_def_1_table->sanitize (class_def_1_v))do { auto _res = (class_def_1_table->sanitize (class_def_1_v
)); if (__builtin_expect (bool(!_res.is_ok()), 0)) return Err
(std::move(_res).error()); } while (0)
;
390
391 auto klass_map =
392 + coverage_table->iter ()
393 | hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
394 return hb_codepoint_pair_t (gid, class_def_1_table->get_class (gid));
395 })
396 | hb_filter ([&] (hb_codepoint_t klass) {
397 return klass >= start && klass < end;
398 }, hb_second)
399 | hb_map_retains_sorting ([&] (hb_codepoint_pair_t gid_and_class) {
400 // Classes must be from 0...N so subtract start
401 return hb_codepoint_pair_t (gid_and_class.first, gid_and_class.second - start);
402 })
403 ;
404
405 TRY (Coverage::add_coverage (split_context.c,do { auto _res = (Coverage::add_coverage (split_context.c, pair_pos_prime_id
, 2, + klass_map | hb_map_retains_sorting (hb_first), split_context
.max_coverage_size)); if (__builtin_expect (bool(!_res.is_ok(
)), 0)) return Err(std::move(_res).error()); } while (0)
406 pair_pos_prime_id,do { auto _res = (Coverage::add_coverage (split_context.c, pair_pos_prime_id
, 2, + klass_map | hb_map_retains_sorting (hb_first), split_context
.max_coverage_size)); if (__builtin_expect (bool(!_res.is_ok(
)), 0)) return Err(std::move(_res).error()); } while (0)
407 2,do { auto _res = (Coverage::add_coverage (split_context.c, pair_pos_prime_id
, 2, + klass_map | hb_map_retains_sorting (hb_first), split_context
.max_coverage_size)); if (__builtin_expect (bool(!_res.is_ok(
)), 0)) return Err(std::move(_res).error()); } while (0)
408 + klass_map | hb_map_retains_sorting (hb_first),do { auto _res = (Coverage::add_coverage (split_context.c, pair_pos_prime_id
, 2, + klass_map | hb_map_retains_sorting (hb_first), split_context
.max_coverage_size)); if (__builtin_expect (bool(!_res.is_ok(
)), 0)) return Err(std::move(_res).error()); } while (0)
409 split_context.max_coverage_size))do { auto _res = (Coverage::add_coverage (split_context.c, pair_pos_prime_id
, 2, + klass_map | hb_map_retains_sorting (hb_first), split_context
.max_coverage_size)); if (__builtin_expect (bool(!_res.is_ok(
)), 0)) return Err(std::move(_res).error()); } while (0)
;
410
411 // classDef1
412 TRY (ClassDef::add_class_def (split_context.c,do { auto _res = (ClassDef::add_class_def (split_context.c, pair_pos_prime_id
, 8, + klass_map, split_context.max_class_def_size)); if (__builtin_expect
(bool(!_res.is_ok()), 0)) return Err(std::move(_res).error()
); } while (0)
413 pair_pos_prime_id,do { auto _res = (ClassDef::add_class_def (split_context.c, pair_pos_prime_id
, 8, + klass_map, split_context.max_class_def_size)); if (__builtin_expect
(bool(!_res.is_ok()), 0)) return Err(std::move(_res).error()
); } while (0)
414 8,do { auto _res = (ClassDef::add_class_def (split_context.c, pair_pos_prime_id
, 8, + klass_map, split_context.max_class_def_size)); if (__builtin_expect
(bool(!_res.is_ok()), 0)) return Err(std::move(_res).error()
); } while (0)
415 + klass_map,do { auto _res = (ClassDef::add_class_def (split_context.c, pair_pos_prime_id
, 8, + klass_map, split_context.max_class_def_size)); if (__builtin_expect
(bool(!_res.is_ok()), 0)) return Err(std::move(_res).error()
); } while (0)
416 split_context.max_class_def_size))do { auto _res = (ClassDef::add_class_def (split_context.c, pair_pos_prime_id
, 8, + klass_map, split_context.max_class_def_size)); if (__builtin_expect
(bool(!_res.is_ok()), 0)) return Err(std::move(_res).error()
); } while (0)
;
417
418 // classDef2
419 TRY_ASSIGN (unsigned class_def_2_id,auto _res_420 = (graph.index_for_offset (split_context.this_index
, &classDef2)); if (__builtin_expect (bool(!_res_420.is_ok
()), 0)) return Err(std::move(_res_420).error()); unsigned class_def_2_id
= *std::move(_res_420)
420 graph.index_for_offset (split_context.this_index, &classDef2))auto _res_420 = (graph.index_for_offset (split_context.this_index
, &classDef2)); if (__builtin_expect (bool(!_res_420.is_ok
()), 0)) return Err(std::move(_res_420).error()); unsigned class_def_2_id
= *std::move(_res_420)
;
421
422 TRY(graph.vertices_[pair_pos_prime_id].add_real_link (SmallTypes::size, class_def_2_id, 10))do { auto _res = (graph.vertices_[pair_pos_prime_id].add_real_link
(SmallTypes::size, class_def_2_id, 10)); if (__builtin_expect
(bool(!_res.is_ok()), 0)) return Err(std::move(_res).error()
); } while (0)
;
423 TRY(graph.vertices_[class_def_2_id].add_parent (pair_pos_prime_id, false))do { auto _res = (graph.vertices_[class_def_2_id].add_parent (
pair_pos_prime_id, false)); if (__builtin_expect (bool(!_res.
is_ok()), 0)) return Err(std::move(_res).error()); } while (0
)
;
424
425 return Ok(pair_pos_prime_id);
426 }
427
428 graph_result_t<void> clone_class1_records (split_context_t& split_context,
429 unsigned pair_pos_prime_id,
430 unsigned start, unsigned end) const
431 {
432 PairPosFormat2* pair_pos_prime =
433 (PairPosFormat2*) split_context.c.graph.object (pair_pos_prime_id).head;
434
435 char* start_addr = ((char*)&values[0]) + start * split_context.class1_record_size;
436 unsigned num_records = end - start;
437 hb_memcpy (&pair_pos_prime->values[0],
438 start_addr,
439 num_records * split_context.class1_record_size);
440
441 if (!split_context.format1_device_table_indices
442 && !split_context.format2_device_table_indices)
443 // No device tables to move over.
444 return Ok();
445
446 unsigned class2_count = class2Count;
447 for (unsigned i = start; i < end; i++)
448 {
449 for (unsigned j = 0; j < class2_count; j++)
450 {
451 unsigned value1_index = split_context.value_record_len * (class2_count * i + j);
452 unsigned value2_index = value1_index + split_context.value1_record_len;
453
454 unsigned new_value1_index = split_context.value_record_len * (class2_count * (i - start) + j);
455 unsigned new_value2_index = new_value1_index + split_context.value1_record_len;
456
457 TRY (transfer_device_tables (split_context,do { auto _res = (transfer_device_tables (split_context, pair_pos_prime_id
, split_context.format1_device_table_indices, value1_index, new_value1_index
)); if (__builtin_expect (bool(!_res.is_ok()), 0)) return Err
(std::move(_res).error()); } while (0)
458 pair_pos_prime_id,do { auto _res = (transfer_device_tables (split_context, pair_pos_prime_id
, split_context.format1_device_table_indices, value1_index, new_value1_index
)); if (__builtin_expect (bool(!_res.is_ok()), 0)) return Err
(std::move(_res).error()); } while (0)
459 split_context.format1_device_table_indices,do { auto _res = (transfer_device_tables (split_context, pair_pos_prime_id
, split_context.format1_device_table_indices, value1_index, new_value1_index
)); if (__builtin_expect (bool(!_res.is_ok()), 0)) return Err
(std::move(_res).error()); } while (0)
460 value1_index,do { auto _res = (transfer_device_tables (split_context, pair_pos_prime_id
, split_context.format1_device_table_indices, value1_index, new_value1_index
)); if (__builtin_expect (bool(!_res.is_ok()), 0)) return Err
(std::move(_res).error()); } while (0)
461 new_value1_index))do { auto _res = (transfer_device_tables (split_context, pair_pos_prime_id
, split_context.format1_device_table_indices, value1_index, new_value1_index
)); if (__builtin_expect (bool(!_res.is_ok()), 0)) return Err
(std::move(_res).error()); } while (0)
;
462
463 TRY (transfer_device_tables (split_context,do { auto _res = (transfer_device_tables (split_context, pair_pos_prime_id
, split_context.format2_device_table_indices, value2_index, new_value2_index
)); if (__builtin_expect (bool(!_res.is_ok()), 0)) return Err
(std::move(_res).error()); } while (0)
464 pair_pos_prime_id,do { auto _res = (transfer_device_tables (split_context, pair_pos_prime_id
, split_context.format2_device_table_indices, value2_index, new_value2_index
)); if (__builtin_expect (bool(!_res.is_ok()), 0)) return Err
(std::move(_res).error()); } while (0)
465 split_context.format2_device_table_indices,do { auto _res = (transfer_device_tables (split_context, pair_pos_prime_id
, split_context.format2_device_table_indices, value2_index, new_value2_index
)); if (__builtin_expect (bool(!_res.is_ok()), 0)) return Err
(std::move(_res).error()); } while (0)
466 value2_index,do { auto _res = (transfer_device_tables (split_context, pair_pos_prime_id
, split_context.format2_device_table_indices, value2_index, new_value2_index
)); if (__builtin_expect (bool(!_res.is_ok()), 0)) return Err
(std::move(_res).error()); } while (0)
467 new_value2_index))do { auto _res = (transfer_device_tables (split_context, pair_pos_prime_id
, split_context.format2_device_table_indices, value2_index, new_value2_index
)); if (__builtin_expect (bool(!_res.is_ok()), 0)) return Err
(std::move(_res).error()); } while (0)
;
468 }
469 }
470 return Ok();
471 }
472
473 graph_result_t<void> transfer_device_tables (split_context_t& split_context,
474 unsigned pair_pos_prime_id,
475 const hb_vector_t<unsigned>& device_table_indices,
476 unsigned old_value_record_index,
477 unsigned new_value_record_index) const
478 {
479 PairPosFormat2* pair_pos_prime =
480 (PairPosFormat2*) split_context.c.graph.object (pair_pos_prime_id).head;
481
482 for (unsigned i : device_table_indices)
483 {
484 OT::Offset16* record = (OT::Offset16*) &values[old_value_record_index + i];
485 unsigned record_position = ((char*) record) - ((char*) this);
486 if (!split_context.device_tables.has (record_position)) continue;
487
488 TRY (split_context.c.graph.move_child (do { auto _res = (split_context.c.graph.move_child ( split_context
.this_index, record, pair_pos_prime_id, (OT::Offset16*) &
pair_pos_prime->values[new_value_record_index + i])); if (
__builtin_expect (bool(!_res.is_ok()), 0)) return Err(std::move
(_res).error()); } while (0)
489 split_context.this_index,do { auto _res = (split_context.c.graph.move_child ( split_context
.this_index, record, pair_pos_prime_id, (OT::Offset16*) &
pair_pos_prime->values[new_value_record_index + i])); if (
__builtin_expect (bool(!_res.is_ok()), 0)) return Err(std::move
(_res).error()); } while (0)
490 record,do { auto _res = (split_context.c.graph.move_child ( split_context
.this_index, record, pair_pos_prime_id, (OT::Offset16*) &
pair_pos_prime->values[new_value_record_index + i])); if (
__builtin_expect (bool(!_res.is_ok()), 0)) return Err(std::move
(_res).error()); } while (0)
491 pair_pos_prime_id,do { auto _res = (split_context.c.graph.move_child ( split_context
.this_index, record, pair_pos_prime_id, (OT::Offset16*) &
pair_pos_prime->values[new_value_record_index + i])); if (
__builtin_expect (bool(!_res.is_ok()), 0)) return Err(std::move
(_res).error()); } while (0)
492 (OT::Offset16*) &pair_pos_prime->values[new_value_record_index + i]))do { auto _res = (split_context.c.graph.move_child ( split_context
.this_index, record, pair_pos_prime_id, (OT::Offset16*) &
pair_pos_prime->values[new_value_record_index + i])); if (
__builtin_expect (bool(!_res.is_ok()), 0)) return Err(std::move
(_res).error()); } while (0)
;
493 }
494
495 // Restore correct ordering of the vertex links which are disturbed by move_child.
496 split_context.c.graph.vertices_[split_context.this_index].sort_real_links ();
497
498 return Ok();
499 }
500
501 graph_result_t<void> shrink (split_context_t& split_context,
502 unsigned count)
503 {
504 DEBUG_MSG (SUBSET_REPACK, nullptr,_hb_debug_msg<(0 +0)> ("SUBSET_REPACK", (nullptr), nullptr
, false, 0, 0, " Shrinking PairPosFormat2 (%u) to [0, %u).",
split_context.this_index, count)
505 " Shrinking PairPosFormat2 (%u) to [0, %u).",_hb_debug_msg<(0 +0)> ("SUBSET_REPACK", (nullptr), nullptr
, false, 0, 0, " Shrinking PairPosFormat2 (%u) to [0, %u).",
split_context.this_index, count)
506 split_context.this_index,_hb_debug_msg<(0 +0)> ("SUBSET_REPACK", (nullptr), nullptr
, false, 0, 0, " Shrinking PairPosFormat2 (%u) to [0, %u).",
split_context.this_index, count)
507 count)_hb_debug_msg<(0 +0)> ("SUBSET_REPACK", (nullptr), nullptr
, false, 0, 0, " Shrinking PairPosFormat2 (%u) to [0, %u).",
split_context.this_index, count)
;
508 unsigned old_count = class1Count;
509 if (count >= old_count)
510 return Ok();
511
512 graph_t& graph = split_context.c.graph;
513 class1Count = count;
514 graph.vertices_[split_context.this_index].shrink_buffer(
515 (old_count - count) * split_context.class1_record_size);
516
517 TRY_ASSIGN (auto coverage,auto _res_518 = (graph.as_mutable_table<Coverage> (split_context
.this_index, &this->coverage)); if (__builtin_expect (
bool(!_res_518.is_ok()), 0)) return Err(std::move(_res_518).error
()); auto coverage = *std::move(_res_518)
518 graph.as_mutable_table<Coverage> (split_context.this_index, &this->coverage))auto _res_518 = (graph.as_mutable_table<Coverage> (split_context
.this_index, &this->coverage)); if (__builtin_expect (
bool(!_res_518.is_ok()), 0)) return Err(std::move(_res_518).error
()); auto coverage = *std::move(_res_518)
;
519
520 TRY_ASSIGN (auto class_def_1,auto _res_521 = (graph.as_mutable_table<ClassDef> (split_context
.this_index, &classDef1)); if (__builtin_expect (bool(!_res_521
.is_ok()), 0)) return Err(std::move(_res_521).error()); auto class_def_1
= *std::move(_res_521)
521 graph.as_mutable_table<ClassDef> (split_context.this_index, &classDef1))auto _res_521 = (graph.as_mutable_table<ClassDef> (split_context
.this_index, &classDef1)); if (__builtin_expect (bool(!_res_521
.is_ok()), 0)) return Err(std::move(_res_521).error()); auto class_def_1
= *std::move(_res_521)
;
522
523 auto klass_map =
524 + coverage.table->iter ()
525 | hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
526 return hb_codepoint_pair_t (gid, class_def_1.table->get_class (gid));
527 })
528 | hb_filter ([&] (hb_codepoint_t klass) {
529 return klass < count;
530 }, hb_second)
531 ;
532
533 auto new_coverage = + klass_map | hb_map_retains_sorting (hb_first);
534 TRY (Coverage::make_coverage (split_context.c,do { auto _res = (Coverage::make_coverage (split_context.c, +
new_coverage, coverage.index, 4 + new_coverage.len() * 2)); if
(__builtin_expect (bool(!_res.is_ok()), 0)) return Err(std::
move(_res).error()); } while (0)
535 + new_coverage,do { auto _res = (Coverage::make_coverage (split_context.c, +
new_coverage, coverage.index, 4 + new_coverage.len() * 2)); if
(__builtin_expect (bool(!_res.is_ok()), 0)) return Err(std::
move(_res).error()); } while (0)
536 coverage.index,do { auto _res = (Coverage::make_coverage (split_context.c, +
new_coverage, coverage.index, 4 + new_coverage.len() * 2)); if
(__builtin_expect (bool(!_res.is_ok()), 0)) return Err(std::
move(_res).error()); } while (0)
537 // existing ranges my not be kept, worst case size is a format 1do { auto _res = (Coverage::make_coverage (split_context.c, +
new_coverage, coverage.index, 4 + new_coverage.len() * 2)); if
(__builtin_expect (bool(!_res.is_ok()), 0)) return Err(std::
move(_res).error()); } while (0)
538 // coverage table.do { auto _res = (Coverage::make_coverage (split_context.c, +
new_coverage, coverage.index, 4 + new_coverage.len() * 2)); if
(__builtin_expect (bool(!_res.is_ok()), 0)) return Err(std::
move(_res).error()); } while (0)
539 4 + new_coverage.len() * 2))do { auto _res = (Coverage::make_coverage (split_context.c, +
new_coverage, coverage.index, 4 + new_coverage.len() * 2)); if
(__builtin_expect (bool(!_res.is_ok()), 0)) return Err(std::
move(_res).error()); } while (0)
;
540
541 return ClassDef::make_class_def (split_context.c,
542 + klass_map,
543 class_def_1.index,
544 class_def_1.vertex->table_size ());
545 }
546
547 graph_result_t<hb_hashmap_t<unsigned, unsigned>>
548 get_all_device_tables (gsubgpos_graph_context_t& c,
549 unsigned this_index) const
550 {
551 const auto& v = c.graph.vertices_[this_index];
552 return v.position_to_index_map ();
553 }
554
555 graph_result_t<const Coverage*> get_coverage (gsubgpos_graph_context_t& c,
556 unsigned this_index) const
557 {
558 TRY_ASSIGN (unsigned coverage_id, c.graph.index_for_offset (this_index, &coverage))auto _res_558 = (c.graph.index_for_offset (this_index, &coverage
)); if (__builtin_expect (bool(!_res_558.is_ok()), 0)) return
Err(std::move(_res_558).error()); unsigned coverage_id = *std
::move(_res_558)
;
559 auto& coverage_v = c.graph.vertices_[coverage_id];
560
561 const Coverage* coverage_table = (const Coverage*) coverage_v.obj().head;
562 if (unlikely (!coverage_table)__builtin_expect (bool(!coverage_table), 0)) return Err(INVALID_ARGUMENT);
563 TRY(coverage_table->sanitize (coverage_v))do { auto _res = (coverage_table->sanitize (coverage_v)); if
(__builtin_expect (bool(!_res.is_ok()), 0)) return Err(std::
move(_res).error()); } while (0)
;
564
565 return coverage_table;
566 }
567
568 graph_result_t<const ClassDef*> get_class_def_1 (gsubgpos_graph_context_t& c,
569 unsigned this_index) const
570 {
571 TRY_ASSIGN (unsigned class_def_1_id, c.graph.index_for_offset (this_index, &classDef1))auto _res_571 = (c.graph.index_for_offset (this_index, &classDef1
)); if (__builtin_expect (bool(!_res_571.is_ok()), 0)) return
Err(std::move(_res_571).error()); unsigned class_def_1_id = *
std::move(_res_571)
;
572 auto& class_def_1_v = c.graph.vertices_[class_def_1_id];
573
574 const ClassDef* class_def_1_table = (const ClassDef*) class_def_1_v.obj().head;
575 if (unlikely (!class_def_1_table)__builtin_expect (bool(!class_def_1_table), 0)) return Err(INVALID_ARGUMENT);
576 TRY(class_def_1_table->sanitize (class_def_1_v))do { auto _res = (class_def_1_table->sanitize (class_def_1_v
)); if (__builtin_expect (bool(!_res.is_ok()), 0)) return Err
(std::move(_res).error()); } while (0)
;
577 return class_def_1_table;
578 }
579
580 unsigned size_of_value_record_children (gsubgpos_graph_context_t& c,
581 const hb_hashmap_t<unsigned, unsigned>& device_tables,
582 const hb_vector_t<unsigned> device_table_indices,
583 unsigned value_record_index,
584 hb_set_t& visited)
585 {
586 unsigned size = 0;
587 for (unsigned i : device_table_indices)
588 {
589 OT::Layout::GPOS_impl::Value* record = &values[value_record_index + i];
590 unsigned record_position = ((char*) record) - ((char*) this);
591 unsigned* obj_idx;
592 if (!device_tables.has (record_position, &obj_idx)) continue;
593 size += c.graph.find_subgraph_size (*obj_idx, visited).value_or (0);
594 }
595 return size;
596 }
597
598 graph_result_t<unsigned> size_of (gsubgpos_graph_context_t& c,
599 unsigned this_index,
600 const void* offset) const
601 {
602 TRY_ASSIGN (const unsigned id, c.graph.index_for_offset (this_index, offset))auto _res_602 = (c.graph.index_for_offset (this_index, offset
)); if (__builtin_expect (bool(!_res_602.is_ok()), 0)) return
Err(std::move(_res_602).error()); const unsigned id = *std::
move(_res_602)
;
603 return Ok(c.graph.vertices_[id].table_size ());
604 }
605};
606
607struct PairPos : public OT::Layout::GPOS_impl::PairPos
608{
609 graph_result_t<hb_vector_t<unsigned>> split_subtables (gsubgpos_graph_context_t& c,
610 unsigned this_index)
611 {
612 switch (u.format.v) {
613 case 1:
614 hb_barrier ();
615 return ((PairPosFormat1*)(&u.format1))->split_subtables (c, this_index);
616 case 2:
617 hb_barrier ();
618 return ((PairPosFormat2*)(&u.format2))->split_subtables (c, this_index);
619#ifndef HB_NO_BEYOND_64K
620 case 3: HB_FALLTHROUGH[[clang::fallthrough]];
621 case 4: HB_FALLTHROUGH[[clang::fallthrough]];
622 // Don't split 24bit PairPos's.
623#endif
624 default:
625 return Ok(hb_vector_t<unsigned> ());
626 }
627 }
628
629 graph_result_t<void> sanitize (const graph_t::vertex_t& vertex) const
630 {
631 size_t vertex_len = vertex.table_size();
632 if (unlikely (vertex_len < u.format.v.get_size ())__builtin_expect (bool(vertex_len < u.format.v.get_size ()
), 0)
) return Err(SANITIZE_FAILURE);
633 hb_barrier ();
634
635 switch (u.format.v) {
636 case 1:
637 hb_barrier ();
638 return ((PairPosFormat1*)(&u.format1))->sanitize (vertex);
639 case 2:
640 hb_barrier ();
641 return ((PairPosFormat2*)(&u.format2))->sanitize (vertex);
642#ifndef HB_NO_BEYOND_64K
643 case 3: HB_FALLTHROUGH[[clang::fallthrough]];
644 case 4: HB_FALLTHROUGH[[clang::fallthrough]];
645#endif
646 default:
647 // We don't handle format 3 and 4 here.
648 return Err(SANITIZE_FAILURE);
649 }
650 }
651};
652
653}
654
655#endif // GRAPH_PAIRPOS_GRAPH_HH