Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/gfx/harfbuzz/src/./../../../../gfx/harfbuzz/src/OT/Color/svg/svg.hh
Warning:line 340, column 8
Excessive padding in 'struct OT::_hb_svg_cache_impl::open_elem_t' (10 padding bytes, where 2 is optimal). Optimal fields order: id, start, in_defs_content, is_defs, consider reordering the fields or adding explicit padding members

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-09-01-224014-2642839-1 -x c++ Unified_cpp_gfx_harfbuzz_src0.cpp
1/*
2 * Copyright © 2018 Ebrahim Byagowi
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
25#ifndef OT_COLOR_SVG_SVG_HH
26#define OT_COLOR_SVG_SVG_HH
27
28#include "../../../hb-open-type.hh"
29#include "../../../hb-blob.hh"
30#include "../../../hb-limits.hh"
31#include "../../../hb-map.hh"
32#include "../../../hb-paint.hh"
33#include "../../../hb-zlib.hh"
34#include <ctype.h>
35#include <string.h>
36
37/*
38 * SVG -- SVG (Scalable Vector Graphics)
39 * https://docs.microsoft.com/en-us/typography/opentype/spec/svg
40 */
41
42#define HB_OT_TAG_SVG((hb_tag_t)((((uint32_t)('S')&0xFF)<<24)|(((uint32_t
)('V')&0xFF)<<16)|(((uint32_t)('G')&0xFF)<<
8)|((uint32_t)(' ')&0xFF)))
HB_TAG('S','V','G',' ')((hb_tag_t)((((uint32_t)('S')&0xFF)<<24)|(((uint32_t
)('V')&0xFF)<<16)|(((uint32_t)('G')&0xFF)<<
8)|((uint32_t)(' ')&0xFF)))
43
44
45namespace OT {
46
47static inline hb_blob_t *
48hb_ot_svg_reference_normalized_blob (hb_blob_t *image,
49 const char **svg,
50 unsigned *len)
51{
52 hb_blob_t *blob = hb_blob_reference (image);
53 unsigned data_len = 0;
54 const char *data = hb_blob_get_data (blob, &data_len);
55
56 if (!data || !data_len)
57 goto fail;
58
59 if (hb_blob_is_gzip (data, data_len))
60 {
61 uint32_t expected_size = 0;
62 if (hb_gzip_get_uncompressed_size (data, data_len, &expected_size) &&
63 unlikely ((size_t) expected_size > (size_t) HB_SVG_MAX_DOCUMENT_SIZE)__builtin_expect (bool((size_t) expected_size > (size_t) (
(size_t) 16 << 20)), 0)
)
64 goto fail;
65
66 hb_blob_t *uncompressed = hb_blob_decompress_gzip (blob,
67 HB_SVG_MAX_DOCUMENT_SIZE((size_t) 16 << 20));
68 if (!uncompressed)
69 goto fail;
70
71 hb_blob_destroy (blob);
72 blob = uncompressed;
73 data = hb_blob_get_data (blob, &data_len);
74 if (!data || !data_len)
75 goto fail;
76 }
77
78 if (unlikely ((size_t) data_len > (size_t) HB_SVG_MAX_DOCUMENT_SIZE)__builtin_expect (bool((size_t) data_len > (size_t) ((size_t
) 16 << 20)), 0)
)
79 goto fail;
80
81 if (svg) *svg = data;
82 if (len) *len = data_len;
83 return blob;
84
85fail:
86 hb_blob_destroy (blob);
87 if (svg) *svg = nullptr;
88 if (len) *len = 0;
89 return nullptr;
90}
91
92struct SVGDocumentIndexEntry
93{
94 int cmp (hb_codepoint_t g) const
95 { return g < startGlyphID ? -1 : g > endGlyphID ? 1 : 0; }
96
97 hb_codepoint_t get_start_glyph () const
98 { return startGlyphID; }
99
100 hb_codepoint_t get_end_glyph () const
101 { return endGlyphID; }
102
103 hb_blob_t *reference_blob (hb_blob_t *svg_blob, unsigned int index_offset) const
104 {
105 return hb_blob_create_sub_blob (svg_blob,
106 index_offset + (unsigned int) svgDoc,
107 svgDocLength);
108 }
109
110 bool sanitize (hb_sanitize_context_t *c, const void *base) const
111 {
112 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
113 return_trace (c->check_struct (this) &&return trace.ret (c->check_struct (this) && hb_barrier
() && svgDoc.sanitize (c, base, svgDocLength), __PRETTY_FUNCTION__
, 115)
114 hb_barrier () &&return trace.ret (c->check_struct (this) && hb_barrier
() && svgDoc.sanitize (c, base, svgDocLength), __PRETTY_FUNCTION__
, 115)
115 svgDoc.sanitize (c, base, svgDocLength))return trace.ret (c->check_struct (this) && hb_barrier
() && svgDoc.sanitize (c, base, svgDocLength), __PRETTY_FUNCTION__
, 115)
;
116 }
117
118 protected:
119 HBUINT16 startGlyphID; /* The first glyph ID in the range described by
120 * this index entry. */
121 HBUINT16 endGlyphID; /* The last glyph ID in the range described by
122 * this index entry. Must be >= startGlyphID. */
123 NNOffset32To<UnsizedArrayOf<HBUINT8>>
124 svgDoc; /* Offset from the beginning of the SVG Document Index
125 * to an SVG document. Must be non-zero. */
126 HBUINT32 svgDocLength; /* Length of the SVG document.
127 * Must be non-zero. */
128 public:
129 DEFINE_SIZE_STATIC (12)void _instance_assertion_on_line_129 () const { static_assert
((sizeof (*this) == (12)), ""); } size_t get_size () const {
return (12); } static constexpr unsigned null_size = (12); static
constexpr unsigned min_size = (12); static constexpr unsigned
static_size = (12)
;
130};
131
132struct SVG
133{
134 static constexpr hb_tag_t tableTag = HB_OT_TAG_SVG((hb_tag_t)((((uint32_t)('S')&0xFF)<<24)|(((uint32_t
)('V')&0xFF)<<16)|(((uint32_t)('G')&0xFF)<<
8)|((uint32_t)(' ')&0xFF)))
;
135
136 struct svg_id_span_t
137 {
138 const char *p;
139 unsigned len;
140
141 bool operator == (const svg_id_span_t &o) const
142 {
143 return len == o.len && !memcmp (p, o.p, len);
144 }
145
146 uint32_t hash () const
147 {
148 uint32_t h = hb_hash (len);
149 for (unsigned i = 0; i < len; i++)
150 h = h * 33u + (unsigned char) p[i];
151 return h;
152 }
153 };
154
155 struct svg_defs_entry_t
156 {
157 svg_id_span_t id;
158 unsigned start;
159 unsigned end;
160 };
161
162 struct svg_doc_cache_t
163 {
164 hb_blob_t *blob = nullptr;
165 const char *svg = nullptr;
166 unsigned len = 0;
167 hb_vector_t<svg_defs_entry_t> defs_entries;
168 hb_codepoint_t start_glyph = HB_CODEPOINT_INVALID((hb_codepoint_t) -1);
169 hb_codepoint_t end_glyph = HB_CODEPOINT_INVALID((hb_codepoint_t) -1);
170 hb_vector_t<hb_pair_t<uint32_t, uint32_t>> glyph_spans;
171 hb_hashmap_t<svg_id_span_t, hb_pair_t<uint32_t, uint32_t>> id_spans;
172 };
173
174 bool has_data () const { return svgDocEntries; }
175
176 struct accelerator_t
177 {
178 accelerator_t (hb_face_t *face);
179 ~accelerator_t ();
180
181 hb_blob_t *reference_blob_for_glyph (hb_codepoint_t glyph_id) const
182 {
183 return table->get_glyph_entry (glyph_id).reference_blob (table.get_blob (),
184 table->svgDocEntries);
185 }
186
187 unsigned get_document_count () const
188 { return table->get_document_count (); }
189
190 bool get_glyph_document_index (hb_codepoint_t glyph_id, unsigned *index) const
191 { return table->get_glyph_document_index (glyph_id, index); }
192
193 bool get_document_glyph_range (unsigned index,
194 hb_codepoint_t *start_glyph,
195 hb_codepoint_t *end_glyph) const
196 { return table->get_document_glyph_range (index, start_glyph, end_glyph); }
197
198 bool has_data () const { return table->has_data (); }
199
200 const svg_doc_cache_t *
201 get_or_create_doc_cache (hb_blob_t *image,
202 const char *svg,
203 unsigned len,
204 unsigned doc_index,
205 hb_codepoint_t start_glyph,
206 hb_codepoint_t end_glyph) const;
207
208 const char *
209 doc_cache_get_svg (const svg_doc_cache_t *doc,
210 unsigned *len) const;
211
212 const hb_vector_t<svg_defs_entry_t> *
213 doc_cache_get_defs_entries (const svg_doc_cache_t *doc) const;
214
215 bool
216 doc_cache_get_glyph_span (const svg_doc_cache_t *doc,
217 hb_codepoint_t glyph,
218 unsigned *start,
219 unsigned *end) const;
220
221 bool
222 doc_cache_find_id_span (const svg_doc_cache_t *doc,
223 svg_id_span_t id,
224 unsigned *start,
225 unsigned *end) const;
226
227 bool
228 doc_cache_find_id_cstr (const svg_doc_cache_t *doc,
229 const char *id,
230 unsigned *start,
231 unsigned *end) const;
232
233 bool paint_glyph (hb_font_t *font HB_UNUSED__attribute__((unused)), hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const
234 {
235 if (!has_data ())
236 return false;
237
238 hb_blob_t *blob = reference_blob_for_glyph (glyph);
239
240 if (blob == hb_blob_get_empty ())
241 return false;
242
243 bool ret = funcs->image (data,
244 blob,
245 0, 0,
246 HB_PAINT_IMAGE_FORMAT_SVG((hb_tag_t)((((uint32_t)('s')&0xFF)<<24)|(((uint32_t
)('v')&0xFF)<<16)|(((uint32_t)('g')&0xFF)<<
8)|((uint32_t)(' ')&0xFF)))
,
247 0.f,
248 nullptr);
249
250 hb_blob_destroy (blob);
251
252 return ret;
253 }
254
255 private:
256 svg_doc_cache_t *
257 make_doc_cache (hb_blob_t *image,
258 const char *svg,
259 unsigned len,
260 hb_codepoint_t start_glyph,
261 hb_codepoint_t end_glyph) const;
262
263 static void destroy_doc_cache (svg_doc_cache_t *doc);
264
265 hb_blob_ptr_t<SVG> table;
266 mutable hb_vector_t<hb_atomic_t<svg_doc_cache_t *>> doc_caches;
267 public:
268 DEFINE_SIZE_STATIC (sizeof (hb_blob_ptr_t<SVG>) +void _instance_assertion_on_line_269 () const { static_assert
((sizeof (*this) == (sizeof (hb_blob_ptr_t<SVG>) + sizeof
(hb_vector_t<hb_atomic_t<svg_doc_cache_t *>>))),
""); } size_t get_size () const { return (sizeof (hb_blob_ptr_t
<SVG>) + sizeof (hb_vector_t<hb_atomic_t<svg_doc_cache_t
*>>)); } static constexpr unsigned null_size = (sizeof
(hb_blob_ptr_t<SVG>) + sizeof (hb_vector_t<hb_atomic_t
<svg_doc_cache_t *>>)); static constexpr unsigned min_size
= (sizeof (hb_blob_ptr_t<SVG>) + sizeof (hb_vector_t<
hb_atomic_t<svg_doc_cache_t *>>)); static constexpr unsigned
static_size = (sizeof (hb_blob_ptr_t<SVG>) + sizeof (hb_vector_t
<hb_atomic_t<svg_doc_cache_t *>>))
269 sizeof (hb_vector_t<hb_atomic_t<svg_doc_cache_t *>>))void _instance_assertion_on_line_269 () const { static_assert
((sizeof (*this) == (sizeof (hb_blob_ptr_t<SVG>) + sizeof
(hb_vector_t<hb_atomic_t<svg_doc_cache_t *>>))),
""); } size_t get_size () const { return (sizeof (hb_blob_ptr_t
<SVG>) + sizeof (hb_vector_t<hb_atomic_t<svg_doc_cache_t
*>>)); } static constexpr unsigned null_size = (sizeof
(hb_blob_ptr_t<SVG>) + sizeof (hb_vector_t<hb_atomic_t
<svg_doc_cache_t *>>)); static constexpr unsigned min_size
= (sizeof (hb_blob_ptr_t<SVG>) + sizeof (hb_vector_t<
hb_atomic_t<svg_doc_cache_t *>>)); static constexpr unsigned
static_size = (sizeof (hb_blob_ptr_t<SVG>) + sizeof (hb_vector_t
<hb_atomic_t<svg_doc_cache_t *>>))
;
270 };
271
272 const SVGDocumentIndexEntry &get_glyph_entry (hb_codepoint_t glyph_id) const
273 { return (this+svgDocEntries).bsearch (glyph_id); }
274
275 unsigned get_document_count () const
276 {
277 if (!has_data ())
278 return 0;
279 return (this + svgDocEntries).len;
280 }
281
282 bool get_glyph_document_index (hb_codepoint_t glyph_id, unsigned *index) const
283 {
284 if (!has_data ())
285 return false;
286 return (this + svgDocEntries).bfind (glyph_id, index);
287 }
288
289 bool get_document_glyph_range (unsigned index,
290 hb_codepoint_t *start_glyph,
291 hb_codepoint_t *end_glyph) const
292 {
293 if (!has_data ())
294 return false;
295
296 const auto &entries = this + svgDocEntries;
297 if (index >= entries.len)
298 return false;
299
300 const auto &entry = entries.arrayZ[index];
301 if (start_glyph) *start_glyph = entry.get_start_glyph ();
302 if (end_glyph) *end_glyph = entry.get_end_glyph ();
303 return true;
304 }
305
306 bool sanitize (hb_sanitize_context_t *c) const
307 {
308 TRACE_SANITIZE (this)hb_no_trace_t<bool> trace;
309 return_trace (likely (c->check_struct (this) &&return trace.ret (__builtin_expect (bool(c->check_struct (
this) && (this+svgDocEntries).sanitize_shallow (c)), 1
), __PRETTY_FUNCTION__, 310)
310 (this+svgDocEntries).sanitize_shallow (c)))return trace.ret (__builtin_expect (bool(c->check_struct (
this) && (this+svgDocEntries).sanitize_shallow (c)), 1
), __PRETTY_FUNCTION__, 310)
;
311 }
312
313 protected:
314 HBUINT16 version; /* Table version (starting at 0). */
315 Offset32To<SortedArray16Of<SVGDocumentIndexEntry>>
316 svgDocEntries; /* Offset (relative to the start of the SVG table) to the
317 * SVG Documents Index. Must be non-zero. */
318 /* Array of SVG Document Index Entries. */
319 HBUINT32 reserved; /* Set to 0. */
320 public:
321 DEFINE_SIZE_STATIC (10)void _instance_assertion_on_line_321 () const { static_assert
((sizeof (*this) == (10)), ""); } size_t get_size () const {
return (10); } static constexpr unsigned null_size = (10); static
constexpr unsigned min_size = (10); static constexpr unsigned
static_size = (10)
;
322};
323
324namespace _hb_svg_cache_impl {
325
326struct glyph_entry_t
327{
328 hb_codepoint_t glyph;
329 uint32_t start;
330 uint32_t end;
331};
332
333struct id_entry_t
334{
335 SVG::svg_id_span_t id;
336 uint32_t start;
337 uint32_t end;
338};
339
340struct open_elem_t
Excessive padding in 'struct OT::_hb_svg_cache_impl::open_elem_t' (10 padding bytes, where 2 is optimal). Optimal fields order: id, start, in_defs_content, is_defs, consider reordering the fields or adding explicit padding members
341{
342 unsigned start;
343 SVG::svg_id_span_t id;
344 bool in_defs_content;
345 bool is_defs;
346};
347
348static const unsigned MAX_DEPTH = 128;
349
350static inline int
351find_substr (const char *s,
352 unsigned n,
353 unsigned from,
354 const char *needle,
355 unsigned needle_len)
356{
357 if (!needle_len || from >= n || needle_len > n)
358 return -1;
359 for (unsigned i = from; i + needle_len <= n; i++)
360 if (s[i] == needle[0] && !memcmp (s + i, needle, needle_len))
361 return (int) i;
362 return -1;
363}
364
365static inline bool
366parse_id_in_start_tag (const char *svg,
367 unsigned tag_start,
368 unsigned tag_end,
369 SVG::svg_id_span_t *id)
370{
371 unsigned p = tag_start;
372 while (p + 4 <= tag_end)
373 {
374 if (!memcmp (svg + p, "id=\"", 4))
375 {
376 unsigned b = p + 4;
377 unsigned e = b;
378 while (e < tag_end && svg[e] != '"') e++;
379 if (e <= tag_end && e > b)
380 {
381 *id = {svg + b, e - b};
382 return true;
383 }
384 }
385 if (!memcmp (svg + p, "id='", 4))
386 {
387 unsigned b = p + 4;
388 unsigned e = b;
389 while (e < tag_end && svg[e] != '\'') e++;
390 if (e <= tag_end && e > b)
391 {
392 *id = {svg + b, e - b};
393 return true;
394 }
395 }
396 p++;
397 }
398 return false;
399}
400
401static inline bool
402parse_glyph_id_span (const SVG::svg_id_span_t &id,
403 hb_codepoint_t *glyph)
404{
405 if (id.len <= 5 || memcmp (id.p, "glyph", 5))
406 return false;
407
408 hb_codepoint_t gid = 0;
409 for (unsigned i = 5; i < id.len; i++)
410 {
411 unsigned char c = (unsigned char) id.p[i];
412 if (c < '0' || c > '9')
413 return false;
414 hb_codepoint_t digit = (hb_codepoint_t) (c - '0');
415 if (unlikely (gid > HB_CODEPOINT_INVALID / 10 ||__builtin_expect (bool(gid > ((hb_codepoint_t) -1) / 10 ||
(gid == ((hb_codepoint_t) -1) / 10 && digit > ((hb_codepoint_t
) -1) % 10)), 0)
416 (gid == HB_CODEPOINT_INVALID / 10 &&__builtin_expect (bool(gid > ((hb_codepoint_t) -1) / 10 ||
(gid == ((hb_codepoint_t) -1) / 10 && digit > ((hb_codepoint_t
) -1) % 10)), 0)
417 digit > HB_CODEPOINT_INVALID % 10))__builtin_expect (bool(gid > ((hb_codepoint_t) -1) / 10 ||
(gid == ((hb_codepoint_t) -1) / 10 && digit > ((hb_codepoint_t
) -1) % 10)), 0)
)
418 return false;
419 gid = (hb_codepoint_t) (gid * 10 + digit);
420 }
421
422 *glyph = gid;
423 return true;
424}
425
426static inline bool
427parse_cache_entries_linear (const char *svg,
428 unsigned len,
429 hb_vector_t<SVG::svg_defs_entry_t> *defs_entries,
430 hb_vector_t<glyph_entry_t> *glyph_spans,
431 hb_vector_t<id_entry_t> *id_entries)
432{
433 open_elem_t stack[MAX_DEPTH] = {};
434 unsigned depth = 0;
435 if (unlikely (!defs_entries->alloc (256) ||__builtin_expect (bool(!defs_entries->alloc (256) || !glyph_spans
->alloc (256) || !id_entries->alloc (256)), 0)
436 !glyph_spans->alloc (256) ||__builtin_expect (bool(!defs_entries->alloc (256) || !glyph_spans
->alloc (256) || !id_entries->alloc (256)), 0)
437 !id_entries->alloc (256))__builtin_expect (bool(!defs_entries->alloc (256) || !glyph_spans
->alloc (256) || !id_entries->alloc (256)), 0)
)
438 return false;
439
440 unsigned defs_depth = 0;
441 unsigned i = 0;
442 while (i < len)
443 {
444 if (svg[i] != '<')
445 {
446 i++;
447 continue;
448 }
449
450 if (i + 4 <= len && !memcmp (svg + i, "<!--", 4))
451 {
452 int cend = find_substr (svg, len, i + 4, "-->", 3);
453 if (cend < 0) return false;
454 i = (unsigned) cend + 3;
455 continue;
456 }
457 if (i + 9 <= len && !memcmp (svg + i, "<![CDATA[", 9))
458 {
459 int cend = find_substr (svg, len, i + 9, "]]>", 3);
460 if (cend < 0) return false;
461 i = (unsigned) cend + 3;
462 continue;
463 }
464
465 bool closing = (i + 1 < len && svg[i + 1] == '/');
466 bool special = (i + 1 < len && (svg[i + 1] == '!' || svg[i + 1] == '?'));
467
468 unsigned gt = i + 1;
469 char quote = 0;
470 while (gt < len)
471 {
472 char c = svg[gt];
473 if (quote)
474 {
475 if (c == quote) quote = 0;
476 }
477 else
478 {
479 if (c == '"' || c == '\'')
480 quote = c;
481 else if (c == '>')
482 break;
483 }
484 gt++;
485 }
486 if (gt >= len)
487 return false;
488
489 if (special)
490 {
491 i = gt + 1;
492 continue;
493 }
494
495 unsigned p = i + (closing ? 2 : 1);
496 while (p < gt && isspace ((unsigned char) svg[p])) p++;
497 const char *name = svg + p;
498 unsigned name_len = 0;
499 while (p + name_len < gt)
500 {
501 unsigned char c = (unsigned char) name[name_len];
502 if (!(ISALNUM (c) || c == '_' || c == '-' || c == ':'))
503 break;
504 name_len++;
505 }
506 bool is_defs = (name_len == 4 && !memcmp (name, "defs", 4));
507
508 if (closing)
509 {
510 if (!depth)
511 {
512 i = gt + 1;
513 continue;
514 }
515
516 open_elem_t e = stack[--depth];
517 unsigned end = gt + 1;
518
519 if (e.id.len)
520 {
521 if (unlikely (!id_entries->push_or_fail (id_entry_t {e.id, (uint32_t) e.start, (uint32_t) end}))__builtin_expect (bool(!id_entries->push_or_fail (id_entry_t
{e.id, (uint32_t) e.start, (uint32_t) end})), 0)
)
522 return false;
523
524 if (e.in_defs_content)
525 {
526 if (unlikely (!defs_entries->push_or_fail ())__builtin_expect (bool(!defs_entries->push_or_fail ()), 0))
527 return false;
528 auto &slot = defs_entries->tail ();
529 slot.id = e.id;
530 slot.start = e.start;
531 slot.end = end;
532 }
533
534 hb_codepoint_t gid;
535 if (parse_glyph_id_span (e.id, &gid))
536 {
537 if (unlikely (!glyph_spans->push_or_fail (glyph_entry_t {gid, (uint32_t) e.start, (uint32_t) end}))__builtin_expect (bool(!glyph_spans->push_or_fail (glyph_entry_t
{gid, (uint32_t) e.start, (uint32_t) end})), 0)
)
538 return false;
539 }
540 }
541
542 if (e.is_defs && defs_depth)
543 defs_depth--;
544
545 i = end;
546 continue;
547 }
548
549 SVG::svg_id_span_t id = {};
550 parse_id_in_start_tag (svg, i, gt, &id);
551
552 unsigned r = gt;
553 while (r > i && isspace ((unsigned char) svg[r - 1])) r--;
554 bool self_closing = (r > i && svg[r - 1] == '/');
555
556 open_elem_t e = {};
557 e.start = i;
558 e.id = id;
559 e.in_defs_content = defs_depth > 0;
560 e.is_defs = is_defs;
561
562 if (self_closing)
563 {
564 unsigned end = gt + 1;
565 if (e.id.len)
566 {
567 if (unlikely (!id_entries->push_or_fail (id_entry_t {e.id, (uint32_t) e.start, (uint32_t) end}))__builtin_expect (bool(!id_entries->push_or_fail (id_entry_t
{e.id, (uint32_t) e.start, (uint32_t) end})), 0)
)
568 return false;
569
570 if (e.in_defs_content)
571 {
572 if (unlikely (!defs_entries->push_or_fail ())__builtin_expect (bool(!defs_entries->push_or_fail ()), 0))
573 return false;
574 auto &slot = defs_entries->tail ();
575 slot.id = e.id;
576 slot.start = e.start;
577 slot.end = end;
578 }
579
580 hb_codepoint_t gid;
581 if (parse_glyph_id_span (e.id, &gid))
582 {
583 if (unlikely (!glyph_spans->push_or_fail (glyph_entry_t {gid, (uint32_t) e.start, (uint32_t) end}))__builtin_expect (bool(!glyph_spans->push_or_fail (glyph_entry_t
{gid, (uint32_t) e.start, (uint32_t) end})), 0)
)
584 return false;
585 }
586 }
587 }
588 else
589 {
590 if (unlikely (depth >= MAX_DEPTH)__builtin_expect (bool(depth >= MAX_DEPTH), 0))
591 return false;
592 stack[depth++] = e;
593 if (is_defs)
594 defs_depth++;
595 }
596
597 i = gt + 1;
598 }
599
600 return true;
601}
602
603} /* namespace _hb_svg_cache_impl */
604
605inline
606SVG::accelerator_t::accelerator_t (hb_face_t *face)
607{
608 table = hb_sanitize_context_t ().reference_table<SVG> (face);
609 doc_caches.init ();
610 unsigned doc_count = table->get_document_count ();
611 if (doc_count && unlikely (!doc_caches.resize (doc_count))__builtin_expect (bool(!doc_caches.resize (doc_count)), 0))
612 doc_caches.clear ();
613 for (unsigned i = 0; i < doc_caches.length; i++)
614 doc_caches.arrayZ[i].set_relaxed (nullptr);
615}
616
617inline
618SVG::accelerator_t::~accelerator_t ()
619{
620 for (unsigned i = 0; i < doc_caches.length; i++)
621 destroy_doc_cache (doc_caches.arrayZ[i].get_relaxed ());
622 doc_caches.fini ();
623 table.destroy ();
624}
625
626inline void
627SVG::accelerator_t::destroy_doc_cache (svg_doc_cache_t *doc)
628{
629 if (!doc)
630 return;
631 doc->glyph_spans.fini ();
632 doc->defs_entries.fini ();
633 doc->id_spans.fini ();
634 hb_blob_destroy (doc->blob);
635 hb_free (doc);
636}
637
638inline SVG::svg_doc_cache_t *
639SVG::accelerator_t::make_doc_cache (hb_blob_t *image,
640 const char *svg,
641 unsigned len,
642 hb_codepoint_t start_glyph,
643 hb_codepoint_t end_glyph) const
644{
645 static const uint32_t INVALID_SPAN = 0xFFFFFFFFu;
646
647 auto *doc = (svg_doc_cache_t *) hb_malloc (sizeof (svg_doc_cache_t));
648 if (!doc)
649 return nullptr;
650
651 doc->blob = nullptr;
652 doc->svg = nullptr;
653 doc->len = 0;
654 doc->defs_entries.init ();
655 doc->start_glyph = HB_CODEPOINT_INVALID((hb_codepoint_t) -1);
656 doc->end_glyph = HB_CODEPOINT_INVALID((hb_codepoint_t) -1);
657 doc->glyph_spans.init ();
658 doc->id_spans.init ();
659
660 doc->blob = hb_blob_reference (image);
661 doc->svg = svg;
662 doc->len = len;
663 doc->start_glyph = start_glyph;
664 doc->end_glyph = end_glyph;
665
666 if (unlikely (start_glyph == HB_CODEPOINT_INVALID || end_glyph < start_glyph)__builtin_expect (bool(start_glyph == ((hb_codepoint_t) -1) ||
end_glyph < start_glyph), 0)
)
667 {
668 destroy_doc_cache (doc);
669 return nullptr;
670 }
671
672 unsigned glyph_count = end_glyph - start_glyph + 1;
673 if (!doc->glyph_spans.resize ((int) glyph_count))
674 {
675 destroy_doc_cache (doc);
676 return nullptr;
677 }
678 for (unsigned i = 0; i < glyph_count; i++)
679 doc->glyph_spans.arrayZ[i] = hb_pair_t<uint32_t, uint32_t> (INVALID_SPAN, INVALID_SPAN);
680
681 hb_vector_t<_hb_svg_cache_impl::glyph_entry_t> glyph_spans;
682 glyph_spans.init ();
683 hb_vector_t<_hb_svg_cache_impl::id_entry_t> id_entries;
684 id_entries.init ();
685 if (!_hb_svg_cache_impl::parse_cache_entries_linear (svg, len,
686 &doc->defs_entries,
687 &glyph_spans,
688 &id_entries))
689 {
690 id_entries.fini ();
691 glyph_spans.fini ();
692 destroy_doc_cache (doc);
693 return nullptr;
694 }
695
696 for (unsigned i = 0; i < glyph_spans.length; i++)
697 {
698 const auto &span = glyph_spans.arrayZ[i];
699 if (unlikely (span.glyph < start_glyph || span.glyph > end_glyph)__builtin_expect (bool(span.glyph < start_glyph || span.glyph
> end_glyph), 0)
)
700 continue;
701 doc->glyph_spans.arrayZ[span.glyph - start_glyph] = hb_pair_t<uint32_t, uint32_t> (span.start, span.end);
702 }
703
704 for (unsigned i = 0; i < id_entries.length; i++)
705 {
706 const auto &e = id_entries.arrayZ[i];
707 hb_pair_t<uint32_t, uint32_t> *out = nullptr;
708 if (doc->id_spans.has (e.id, &out))
709 continue;
710 if (unlikely (!doc->id_spans.set (e.id, hb_pair_t<uint32_t, uint32_t> (e.start, e.end)))__builtin_expect (bool(!doc->id_spans.set (e.id, hb_pair_t
<uint32_t, uint32_t> (e.start, e.end))), 0)
)
711 {
712 id_entries.fini ();
713 glyph_spans.fini ();
714 destroy_doc_cache (doc);
715 return nullptr;
716 }
717 }
718
719 id_entries.fini ();
720 glyph_spans.fini ();
721 return doc;
722}
723
724inline const SVG::svg_doc_cache_t *
725SVG::accelerator_t::get_or_create_doc_cache (hb_blob_t *image,
726 const char *svg,
727 unsigned len,
728 unsigned doc_index,
729 hb_codepoint_t start_glyph,
730 hb_codepoint_t end_glyph) const
731{
732 if (doc_index >= doc_caches.length)
733 return nullptr;
734
735 auto &slot = doc_caches.arrayZ[doc_index];
736 auto *doc = slot.get_acquire ();
737 if (doc)
738 return doc;
739
740 auto *fresh = make_doc_cache (image, svg, len, start_glyph, end_glyph);
741 if (!fresh)
742 return nullptr;
743
744 auto *expected = (svg_doc_cache_t *) nullptr;
745 if (slot.cmpexch (expected, fresh))
746 return fresh;
747
748 destroy_doc_cache (fresh);
749 return expected;
750}
751
752inline const char *
753SVG::accelerator_t::doc_cache_get_svg (const svg_doc_cache_t *doc,
754 unsigned *len) const
755{
756 if (!doc)
757 {
758 if (len) *len = 0;
759 return nullptr;
760 }
761 if (len) *len = doc->len;
762 return doc->svg;
763}
764
765inline const hb_vector_t<SVG::svg_defs_entry_t> *
766SVG::accelerator_t::doc_cache_get_defs_entries (const svg_doc_cache_t *doc) const
767{
768 return doc ? &doc->defs_entries : nullptr;
769}
770
771inline bool
772SVG::accelerator_t::doc_cache_get_glyph_span (const svg_doc_cache_t *doc,
773 hb_codepoint_t glyph,
774 unsigned *start,
775 unsigned *end) const
776{
777 static const uint32_t INVALID_SPAN = 0xFFFFFFFFu;
778 if (!doc || doc->start_glyph == HB_CODEPOINT_INVALID((hb_codepoint_t) -1) ||
779 glyph < doc->start_glyph || glyph > doc->end_glyph)
780 return false;
781
782 const auto &span = doc->glyph_spans.arrayZ[glyph - doc->start_glyph];
783 if (span.first == INVALID_SPAN)
784 return false;
785 if (unlikely (span.first > span.second || span.second > doc->len)__builtin_expect (bool(span.first > span.second || span.second
> doc->len), 0)
)
786 return false;
787
788 if (start) *start = span.first;
789 if (end) *end = span.second;
790 return true;
791}
792
793inline bool
794SVG::accelerator_t::doc_cache_find_id_span (const svg_doc_cache_t *doc,
795 svg_id_span_t id,
796 unsigned *start,
797 unsigned *end) const
798{
799 if (!doc || !id.p || !id.len)
800 return false;
801 hb_pair_t<uint32_t, uint32_t> *span = nullptr;
802 if (!doc->id_spans.has (id, &span))
803 return false;
804 if (unlikely (span->first > span->second || span->second > doc->len)__builtin_expect (bool(span->first > span->second ||
span->second > doc->len), 0)
)
805 return false;
806 if (start) *start = span->first;
807 if (end) *end = span->second;
808 return true;
809}
810
811inline bool
812SVG::accelerator_t::doc_cache_find_id_cstr (const svg_doc_cache_t *doc,
813 const char *id,
814 unsigned *start,
815 unsigned *end) const
816{
817 if (!id) return false;
818 svg_id_span_t key = {id, (unsigned) strlen (id)};
819 return doc_cache_find_id_span (doc, key, start, end);
820}
821
822struct SVG_accelerator_t : SVG::accelerator_t {
823 SVG_accelerator_t (hb_face_t *face) : SVG::accelerator_t (face) {}
824};
825
826} /* namespace OT */
827
828
829#endif /* OT_COLOR_SVG_SVG_HH */