[amalgamation] Add HB_HAS_SUBSET and share SVG helpers Add HB_HAS_SUBSET to hb-features.h and wire it through the same HAVE_* feature plumbing used by the other HB_HAS_* macros. Refactor the raster/vector SVG helper code so the duplicated private helpers live in shared internal headers, avoiding duplicate definitions when sources are combined in a single translation unit. Testing: meson compile -C build Assisted-by: OpenAI Codex
diff --git a/docs/harfbuzz-sections.txt b/docs/harfbuzz-sections.txt index bee7ef0..5506375 100644 --- a/docs/harfbuzz-sections.txt +++ b/docs/harfbuzz-sections.txt
@@ -207,6 +207,7 @@ HB_HAS_GRAPHITE HB_HAS_ICU HB_HAS_RASTER +HB_HAS_SUBSET HB_HAS_UNISCRIBE HB_HAS_VECTOR HB_HAS_WASM
diff --git a/meson.build b/meson.build index c6af11f..3029675 100644 --- a/meson.build +++ b/meson.build
@@ -269,6 +269,10 @@ conf.set('HAVE_VECTOR', 1) endif +if not get_option('subset').disabled() + conf.set('HAVE_SUBSET', 1) +endif + if freetype_dep.found() conf.set('HAVE_FREETYPE', 1) check_freetype_funcs = [
diff --git a/src/hb-features.h.in b/src/hb-features.h.in index 9726140..99bc43f 100644 --- a/src/hb-features.h.in +++ b/src/hb-features.h.in
@@ -107,6 +107,13 @@ #mesondefine HB_HAS_RASTER /** + * HB_HAS_SUBSET: + * + * Defined if Harfbuzz has been built with the subset library. + */ +#mesondefine HB_HAS_SUBSET + +/** * HB_HAS_UNISCRIBE: * * Defined if Harfbuzz has been built with Uniscribe support.
diff --git a/src/hb-raster-svg-clip.cc b/src/hb-raster-svg-clip.cc index edae750..19714ea 100644 --- a/src/hb-raster-svg-clip.cc +++ b/src/hb-raster-svg-clip.cc
@@ -89,19 +89,6 @@ *ctx->had_alloc_failure = true; } -static void -svg_skip_subtree (hb_svg_xml_parser_t &parser) -{ - int depth = 1; - while (depth > 0) - { - hb_svg_token_type_t tok = parser.next (); - if (tok == SVG_TOKEN_EOF) break; - if (tok == SVG_TOKEN_CLOSE_TAG) depth--; - else if (tok == SVG_TOKEN_OPEN_TAG) depth++; - } -} - static inline bool svg_resolve_element_visibility (hb_svg_xml_parser_t &parser, bool parent_visible)
diff --git a/src/hb-raster-svg-parse.hh b/src/hb-raster-svg-parse.hh index b8fae86..21c782c 100644 --- a/src/hb-raster-svg-parse.hh +++ b/src/hb-raster-svg-parse.hh
@@ -202,6 +202,19 @@ } }; +static inline void +svg_skip_subtree (hb_svg_xml_parser_t &parser) +{ + int depth = 1; + while (depth > 0) + { + hb_svg_token_type_t tok = parser.next (); + if (tok == SVG_TOKEN_EOF) break; + if (tok == SVG_TOKEN_CLOSE_TAG) depth--; + else if (tok == SVG_TOKEN_OPEN_TAG) depth++; + } +} + static inline hb_svg_str_t svg_pick_attr_or_style (const hb_svg_xml_parser_t &parser, hb_svg_str_t style_value,
diff --git a/src/hb-raster-svg-render.cc b/src/hb-raster-svg-render.cc index e39b0d9..d07ce04 100644 --- a/src/hb-raster-svg-render.cc +++ b/src/hb-raster-svg-render.cc
@@ -306,19 +306,6 @@ ctx->allow_symbol_render_once = old_allow_symbol; } -static void -svg_skip_subtree (hb_svg_xml_parser_t &parser) -{ - int depth = 1; - while (depth > 0) - { - hb_svg_token_type_t tok = parser.next (); - if (tok == SVG_TOKEN_EOF) break; - if (tok == SVG_TOKEN_CLOSE_TAG) depth--; - else if (tok == SVG_TOKEN_OPEN_TAG) depth++; - } -} - /* Render one element (may be a container or shape) */ static void svg_render_element (hb_svg_render_context_t *ctx,
diff --git a/src/hb-vector-svg-draw.cc b/src/hb-vector-svg-draw.cc index dd80f74..82f31b4 100644 --- a/src/hb-vector-svg-draw.cc +++ b/src/hb-vector-svg-draw.cc
@@ -39,81 +39,7 @@ #include <math.h> #include <string.h> - -static bool -hb_svg_append_str (hb_vector_t<char> *buf, const char *s) -{ - return hb_svg_append_len (buf, s, (unsigned) strlen (s)); -} - -static bool -hb_svg_append_unsigned (hb_vector_t<char> *buf, unsigned v) -{ - char tmp[10]; - unsigned n = 0; - do { - tmp[n++] = (char) ('0' + (v % 10)); - v /= 10; - } while (v); - - unsigned old_len = buf->length; - if (unlikely (!buf->resize_dirty ((int) (old_len + n)))) - return false; - - for (unsigned i = 0; i < n; i++) - buf->arrayZ[old_len + i] = tmp[n - 1 - i]; - return true; -} - -static bool -hb_svg_append_hex_byte (hb_vector_t<char> *buf, unsigned v) -{ - static const char hex[] = "0123456789ABCDEF"; - char tmp[2] = {hex[(v >> 4) & 15], hex[v & 15]}; - return hb_svg_append_len (buf, tmp, 2); -} - -HB_UNUSED static bool -hb_svg_append_base64 (hb_vector_t<char> *buf, - const uint8_t *data, - unsigned len) -{ - static const char b64[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - unsigned out_len = ((len + 2) / 3) * 4; - unsigned old_len = buf->length; - if (unlikely (!buf->resize_dirty ((int) (old_len + out_len)))) - return false; - - char *dst = buf->arrayZ + old_len; - unsigned di = 0; - unsigned i = 0; - while (i + 2 < len) - { - unsigned v = ((unsigned) data[i] << 16) | - ((unsigned) data[i + 1] << 8) | - ((unsigned) data[i + 2]); - dst[di++] = b64[(v >> 18) & 63]; - dst[di++] = b64[(v >> 12) & 63]; - dst[di++] = b64[(v >> 6) & 63]; - dst[di++] = b64[v & 63]; - i += 3; - } - - if (i < len) - { - unsigned v = (unsigned) data[i] << 16; - if (i + 1 < len) - v |= (unsigned) data[i + 1] << 8; - dst[di++] = b64[(v >> 18) & 63]; - dst[di++] = b64[(v >> 12) & 63]; - dst[di++] = (i + 1 < len) ? b64[(v >> 6) & 63] : '='; - dst[di++] = '='; - } - - return true; -} +#include "hb-vector-svg.hh" HB_UNUSED static inline bool hb_svg_buffer_contains (const hb_vector_t<char> &buf, const char *needle) @@ -129,239 +55,6 @@ return false; } -struct hb_svg_blob_meta_t -{ - char *data; - int allocated; - bool transferred; - bool in_replace; -}; - -static hb_user_data_key_t hb_svg_blob_meta_user_data_key; - -static void -hb_svg_blob_meta_set_buffer (hb_svg_blob_meta_t *meta, - char *data, - int allocated) -{ - meta->data = data; - meta->allocated = allocated; - meta->transferred = false; -} - -static void -hb_svg_blob_meta_release_buffer (hb_svg_blob_meta_t *meta) -{ - if (!meta) - return; - if (!meta->transferred && meta->data) - hb_free (meta->data); - meta->data = nullptr; - meta->allocated = 0; - meta->transferred = true; -} - -static void -hb_svg_blob_meta_destroy (void *data) -{ - auto *meta = (hb_svg_blob_meta_t *) data; - hb_svg_blob_meta_release_buffer (meta); - if (meta->in_replace) - { - meta->in_replace = false; - return; - } - hb_free (meta); -} - -static hb_blob_t * -hb_svg_blob_from_buffer (hb_blob_t **recycled_blob, - hb_vector_t<char> *buf) -{ - unsigned len = 0; - int allocated = 0; - char *data = buf->steal (&len, &allocated); - if (!data) - return nullptr; - - hb_blob_t *blob = nullptr; - if (*recycled_blob) - blob = *recycled_blob; - bool reused_blob = blob && blob != hb_blob_get_empty (); - bool new_meta = false; - auto *meta = reused_blob - ? (hb_svg_blob_meta_t *) hb_blob_get_user_data (blob, &hb_svg_blob_meta_user_data_key) - : nullptr; - if (!meta) - { - meta = (hb_svg_blob_meta_t *) hb_malloc (sizeof (hb_svg_blob_meta_t)); - if (!meta) - { - hb_free (data); - return nullptr; - } - meta->data = nullptr; - meta->allocated = 0; - meta->transferred = true; - meta->in_replace = false; - new_meta = true; - } - - if (reused_blob) - { - /* replace_buffer() first destroys old buffer user_data; keep meta alive. */ - meta->in_replace = true; - blob->replace_buffer (data, len, HB_MEMORY_MODE_WRITABLE, meta, hb_svg_blob_meta_destroy); - hb_svg_blob_meta_set_buffer (meta, data, allocated); - } - else - { - hb_svg_blob_meta_set_buffer (meta, data, allocated); - blob = hb_blob_create_or_fail (data, len, HB_MEMORY_MODE_WRITABLE, meta, hb_svg_blob_meta_destroy); - if (unlikely (!blob)) - return nullptr; - } - - if (unlikely (blob == hb_blob_get_empty ())) - { - if (new_meta) - hb_free (meta); - hb_free (data); - return nullptr; - } - - if (new_meta && - !hb_blob_set_user_data (blob, - &hb_svg_blob_meta_user_data_key, - meta, - nullptr, - true)) - { - if (!reused_blob) - hb_blob_destroy (blob); - return nullptr; - } - - if (*recycled_blob) - *recycled_blob = nullptr; - - return blob; -} - -static void -hb_svg_recover_recycled_buffer (hb_blob_t *blob, - hb_vector_t<char> *buf) -{ - if (!blob) - return; - - auto *meta = (hb_svg_blob_meta_t *) hb_blob_get_user_data (blob, &hb_svg_blob_meta_user_data_key); - if (!meta || meta->transferred || !meta->data) - return; - - buf->recycle_buffer (meta->data, 0, meta->allocated); - meta->data = nullptr; - meta->allocated = 0; - meta->transferred = true; -} - -HB_UNUSED static void -hb_svg_append_color (hb_vector_t<char> *buf, - hb_color_t color, - bool with_alpha) -{ - static const char hex[] = "0123456789ABCDEF"; - unsigned r = hb_color_get_red (color); - unsigned g = hb_color_get_green (color); - unsigned b = hb_color_get_blue (color); - unsigned a = hb_color_get_alpha (color); - hb_svg_append_c (buf, '#'); - if (((r >> 4) == (r & 0xF)) && - ((g >> 4) == (g & 0xF)) && - ((b >> 4) == (b & 0xF))) - { - hb_svg_append_c (buf, hex[r & 0xF]); - hb_svg_append_c (buf, hex[g & 0xF]); - hb_svg_append_c (buf, hex[b & 0xF]); - } - else - { - hb_svg_append_hex_byte (buf, r); - hb_svg_append_hex_byte (buf, g); - hb_svg_append_hex_byte (buf, b); - } - if (with_alpha && a != 255) - { - hb_svg_append_str (buf, "\" fill-opacity=\""); - hb_svg_append_num (buf, a / 255.f, 4); - } -} - -static void -hb_svg_transform_point (const hb_transform_t<> &t, - float x_scale_factor, - float y_scale_factor, - float x, float y, - float *tx, float *ty) -{ - float xx = x, yy = y; - t.transform_point (xx, yy); - *tx = xx / (x_scale_factor > 0 ? x_scale_factor : 1.f); - *ty = yy / (y_scale_factor > 0 ? y_scale_factor : 1.f); -} - -static hb_bool_t -hb_svg_set_glyph_extents_common (const hb_transform_t<> &transform, - float x_scale_factor, - float y_scale_factor, - const hb_glyph_extents_t *glyph_extents, - hb_vector_extents_t *extents, - hb_bool_t *has_extents) -{ - float x0 = (float) glyph_extents->x_bearing; - float y0 = (float) glyph_extents->y_bearing; - float x1 = x0 + glyph_extents->width; - float y1 = y0 + glyph_extents->height; - - float px[4] = {x0, x0, x1, x1}; - float py[4] = {y0, y1, y0, y1}; - - float tx, ty; - hb_svg_transform_point (transform, x_scale_factor, y_scale_factor, px[0], py[0], &tx, &ty); - float tx_min = tx, tx_max = tx; - float ty_min = ty, ty_max = ty; - - for (unsigned i = 1; i < 4; i++) - { - hb_svg_transform_point (transform, x_scale_factor, y_scale_factor, px[i], py[i], &tx, &ty); - tx_min = hb_min (tx_min, tx); - tx_max = hb_max (tx_max, tx); - ty_min = hb_min (ty_min, ty); - ty_max = hb_max (ty_max, ty); - } - - if (tx_max <= tx_min || ty_max <= ty_min) - { - return false; - } - - if (*has_extents) - { - float x0 = hb_min (extents->x, tx_min); - float y0 = hb_min (extents->y, ty_min); - float x1 = hb_max (extents->x + extents->width, tx_max); - float y1 = hb_max (extents->y + extents->height, ty_max); - *extents = {x0, y0, x1 - x0, y1 - y0}; - } - else - { - *extents = {tx_min, ty_min, tx_max - tx_min, ty_max - ty_min}; - *has_extents = true; - } - return true; -} - - struct hb_vector_draw_t { hb_object_header_t header; @@ -391,63 +84,6 @@ } }; -static inline void -hb_svg_append_instance_transform (hb_vector_t<char> *out, - unsigned precision, - float x_scale_factor, - float y_scale_factor, - float xx, float yx, - float xy, float yy, - float tx, float ty) -{ - unsigned sprec = hb_svg_scale_precision (precision); - if (xx == 1.f && yx == 0.f && xy == 0.f && yy == 1.f) - { - float sx = 1.f / x_scale_factor; - float sy = 1.f / y_scale_factor; - hb_svg_append_str (out, "translate("); - hb_svg_append_num (out, tx / x_scale_factor, precision); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, -ty / y_scale_factor, precision); - hb_svg_append_str (out, ") scale("); - hb_svg_append_num (out, sx, sprec, true); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, -sy, sprec, true); - hb_svg_append_c (out, ')'); - } - else - { - hb_svg_append_str (out, "matrix("); - hb_svg_append_num (out, xx / x_scale_factor, sprec, true); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, yx / y_scale_factor, sprec, true); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, -xy / x_scale_factor, sprec, true); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, -yy / y_scale_factor, sprec, true); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, tx / x_scale_factor, precision); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, -ty / y_scale_factor, precision); - hb_svg_append_c (out, ')'); - } -} - -HB_UNUSED static inline void -hb_svg_append_image_instance_translate (hb_vector_t<char> *out, - unsigned precision, - float x_scale_factor, - float y_scale_factor, - float tx, float ty) -{ - hb_svg_append_str (out, "translate("); - hb_svg_append_num (out, tx / x_scale_factor, precision); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, -ty / y_scale_factor, precision); - hb_svg_append_c (out, ')'); -} - - static void hb_vector_draw_move_to (hb_draw_funcs_t *, void *draw_data,
diff --git a/src/hb-vector-svg-paint.cc b/src/hb-vector-svg-paint.cc index 31e61bc..b23efb7 100644 --- a/src/hb-vector-svg-paint.cc +++ b/src/hb-vector-svg-paint.cc
@@ -39,314 +39,7 @@ #include <math.h> #include <string.h> - -static bool -hb_svg_append_str (hb_vector_t<char> *buf, const char *s) -{ - return hb_svg_append_len (buf, s, (unsigned) strlen (s)); -} - -static bool -hb_svg_append_unsigned (hb_vector_t<char> *buf, unsigned v) -{ - char tmp[10]; - unsigned n = 0; - do { - tmp[n++] = (char) ('0' + (v % 10)); - v /= 10; - } while (v); - - unsigned old_len = buf->length; - if (unlikely (!buf->resize_dirty ((int) (old_len + n)))) - return false; - - for (unsigned i = 0; i < n; i++) - buf->arrayZ[old_len + i] = tmp[n - 1 - i]; - return true; -} - -static bool -hb_svg_append_hex_byte (hb_vector_t<char> *buf, unsigned v) -{ - static const char hex[] = "0123456789ABCDEF"; - char tmp[2] = {hex[(v >> 4) & 15], hex[v & 15]}; - return hb_svg_append_len (buf, tmp, 2); -} - -static bool -hb_svg_append_base64 (hb_vector_t<char> *buf, - const uint8_t *data, - unsigned len) -{ - static const char b64[] = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - unsigned out_len = ((len + 2) / 3) * 4; - unsigned old_len = buf->length; - if (unlikely (!buf->resize_dirty ((int) (old_len + out_len)))) - return false; - - char *dst = buf->arrayZ + old_len; - unsigned di = 0; - unsigned i = 0; - while (i + 2 < len) - { - unsigned v = ((unsigned) data[i] << 16) | - ((unsigned) data[i + 1] << 8) | - ((unsigned) data[i + 2]); - dst[di++] = b64[(v >> 18) & 63]; - dst[di++] = b64[(v >> 12) & 63]; - dst[di++] = b64[(v >> 6) & 63]; - dst[di++] = b64[v & 63]; - i += 3; - } - - if (i < len) - { - unsigned v = (unsigned) data[i] << 16; - if (i + 1 < len) - v |= (unsigned) data[i + 1] << 8; - dst[di++] = b64[(v >> 18) & 63]; - dst[di++] = b64[(v >> 12) & 63]; - dst[di++] = (i + 1 < len) ? b64[(v >> 6) & 63] : '='; - dst[di++] = '='; - } - - return true; -} - -struct hb_svg_blob_meta_t -{ - char *data; - int allocated; - bool transferred; - bool in_replace; -}; - -static hb_user_data_key_t hb_svg_blob_meta_user_data_key; - -static void -hb_svg_blob_meta_set_buffer (hb_svg_blob_meta_t *meta, - char *data, - int allocated) -{ - meta->data = data; - meta->allocated = allocated; - meta->transferred = false; -} - -static void -hb_svg_blob_meta_release_buffer (hb_svg_blob_meta_t *meta) -{ - if (!meta) - return; - if (!meta->transferred && meta->data) - hb_free (meta->data); - meta->data = nullptr; - meta->allocated = 0; - meta->transferred = true; -} - -static void -hb_svg_blob_meta_destroy (void *data) -{ - auto *meta = (hb_svg_blob_meta_t *) data; - hb_svg_blob_meta_release_buffer (meta); - if (meta->in_replace) - { - meta->in_replace = false; - return; - } - hb_free (meta); -} - -static hb_blob_t * -hb_svg_blob_from_buffer (hb_blob_t **recycled_blob, - hb_vector_t<char> *buf) -{ - unsigned len = 0; - int allocated = 0; - char *data = buf->steal (&len, &allocated); - if (!data) - return nullptr; - - hb_blob_t *blob = nullptr; - if (*recycled_blob) - blob = *recycled_blob; - bool reused_blob = blob && blob != hb_blob_get_empty (); - bool new_meta = false; - auto *meta = reused_blob - ? (hb_svg_blob_meta_t *) hb_blob_get_user_data (blob, &hb_svg_blob_meta_user_data_key) - : nullptr; - if (!meta) - { - meta = (hb_svg_blob_meta_t *) hb_malloc (sizeof (hb_svg_blob_meta_t)); - if (!meta) - { - hb_free (data); - return nullptr; - } - meta->data = nullptr; - meta->allocated = 0; - meta->transferred = true; - meta->in_replace = false; - new_meta = true; - } - - if (reused_blob) - { - /* replace_buffer() first destroys old buffer user_data; keep meta alive. */ - meta->in_replace = true; - blob->replace_buffer (data, len, HB_MEMORY_MODE_WRITABLE, meta, hb_svg_blob_meta_destroy); - hb_svg_blob_meta_set_buffer (meta, data, allocated); - } - else - { - hb_svg_blob_meta_set_buffer (meta, data, allocated); - blob = hb_blob_create_or_fail (data, len, HB_MEMORY_MODE_WRITABLE, meta, hb_svg_blob_meta_destroy); - if (unlikely (!blob)) - return nullptr; - } - - if (unlikely (blob == hb_blob_get_empty ())) - { - if (new_meta) - hb_free (meta); - hb_free (data); - return nullptr; - } - - if (new_meta && - !hb_blob_set_user_data (blob, - &hb_svg_blob_meta_user_data_key, - meta, - nullptr, - true)) - { - if (!reused_blob) - hb_blob_destroy (blob); - return nullptr; - } - - if (*recycled_blob) - *recycled_blob = nullptr; - - return blob; -} - -static void -hb_svg_recover_recycled_buffer (hb_blob_t *blob, - hb_vector_t<char> *buf) -{ - if (!blob) - return; - - auto *meta = (hb_svg_blob_meta_t *) hb_blob_get_user_data (blob, &hb_svg_blob_meta_user_data_key); - if (!meta || meta->transferred || !meta->data) - return; - - buf->recycle_buffer (meta->data, 0, meta->allocated); - meta->data = nullptr; - meta->allocated = 0; - meta->transferred = true; -} - -static void -hb_svg_append_color (hb_vector_t<char> *buf, - hb_color_t color, - bool with_alpha) -{ - static const char hex[] = "0123456789ABCDEF"; - unsigned r = hb_color_get_red (color); - unsigned g = hb_color_get_green (color); - unsigned b = hb_color_get_blue (color); - unsigned a = hb_color_get_alpha (color); - hb_svg_append_c (buf, '#'); - if (((r >> 4) == (r & 0xF)) && - ((g >> 4) == (g & 0xF)) && - ((b >> 4) == (b & 0xF))) - { - hb_svg_append_c (buf, hex[r & 0xF]); - hb_svg_append_c (buf, hex[g & 0xF]); - hb_svg_append_c (buf, hex[b & 0xF]); - } - else - { - hb_svg_append_hex_byte (buf, r); - hb_svg_append_hex_byte (buf, g); - hb_svg_append_hex_byte (buf, b); - } - if (with_alpha && a != 255) - { - hb_svg_append_str (buf, "\" fill-opacity=\""); - hb_svg_append_num (buf, a / 255.f, 4); - } -} - -static void -hb_svg_transform_point (const hb_transform_t<> &t, - float x_scale_factor, - float y_scale_factor, - float x, float y, - float *tx, float *ty) -{ - float xx = x, yy = y; - t.transform_point (xx, yy); - *tx = xx / (x_scale_factor > 0 ? x_scale_factor : 1.f); - *ty = yy / (y_scale_factor > 0 ? y_scale_factor : 1.f); -} - -static hb_bool_t -hb_svg_set_glyph_extents_common (const hb_transform_t<> &transform, - float x_scale_factor, - float y_scale_factor, - const hb_glyph_extents_t *glyph_extents, - hb_vector_extents_t *extents, - hb_bool_t *has_extents) -{ - float x0 = (float) glyph_extents->x_bearing; - float y0 = (float) glyph_extents->y_bearing; - float x1 = x0 + glyph_extents->width; - float y1 = y0 + glyph_extents->height; - - float px[4] = {x0, x0, x1, x1}; - float py[4] = {y0, y1, y0, y1}; - - float tx, ty; - hb_svg_transform_point (transform, x_scale_factor, y_scale_factor, px[0], py[0], &tx, &ty); - float tx_min = tx, tx_max = tx; - float ty_min = ty, ty_max = ty; - - for (unsigned i = 1; i < 4; i++) - { - hb_svg_transform_point (transform, x_scale_factor, y_scale_factor, px[i], py[i], &tx, &ty); - tx_min = hb_min (tx_min, tx); - tx_max = hb_max (tx_max, tx); - ty_min = hb_min (ty_min, ty); - ty_max = hb_max (ty_max, ty); - } - - if (tx_max <= tx_min || ty_max <= ty_min) - { - return false; - } - - if (*has_extents) - { - float x0 = hb_min (extents->x, tx_min); - float y0 = hb_min (extents->y, ty_min); - float x1 = hb_max (extents->x + extents->width, tx_max); - float y1 = hb_max (extents->y + extents->height, ty_max); - *extents = {x0, y0, x1 - x0, y1 - y0}; - } - else - { - *extents = {tx_min, ty_min, tx_max - tx_min, ty_max - ty_min}; - *has_extents = true; - } - return true; -} - +#include "hb-vector-svg.hh" struct hb_svg_color_glyph_cache_key_t { @@ -477,62 +170,6 @@ return {glyph, palette, foreground}; } -static inline void -hb_svg_append_instance_transform (hb_vector_t<char> *out, - unsigned precision, - float x_scale_factor, - float y_scale_factor, - float xx, float yx, - float xy, float yy, - float tx, float ty) -{ - unsigned sprec = hb_svg_scale_precision (precision); - if (xx == 1.f && yx == 0.f && xy == 0.f && yy == 1.f) - { - float sx = 1.f / x_scale_factor; - float sy = 1.f / y_scale_factor; - hb_svg_append_str (out, "translate("); - hb_svg_append_num (out, tx / x_scale_factor, precision); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, -ty / y_scale_factor, precision); - hb_svg_append_str (out, ") scale("); - hb_svg_append_num (out, sx, sprec, true); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, -sy, sprec, true); - hb_svg_append_c (out, ')'); - } - else - { - hb_svg_append_str (out, "matrix("); - hb_svg_append_num (out, xx / x_scale_factor, sprec, true); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, yx / y_scale_factor, sprec, true); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, -xy / x_scale_factor, sprec, true); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, -yy / y_scale_factor, sprec, true); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, tx / x_scale_factor, precision); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, -ty / y_scale_factor, precision); - hb_svg_append_c (out, ')'); - } -} - -static inline void -hb_svg_append_image_instance_translate (hb_vector_t<char> *out, - unsigned precision, - float x_scale_factor, - float y_scale_factor, - float tx, float ty) -{ - hb_svg_append_str (out, "translate("); - hb_svg_append_num (out, tx / x_scale_factor, precision); - hb_svg_append_c (out, ','); - hb_svg_append_num (out, -ty / y_scale_factor, precision); - hb_svg_append_c (out, ')'); -} - static hb_bool_t hb_svg_get_color_stops (hb_vector_paint_t *paint, hb_color_line_t *color_line,
diff --git a/src/hb-vector-svg-subset.cc b/src/hb-vector-svg-subset.cc index 54c25e2..b46f404 100644 --- a/src/hb-vector-svg-subset.cc +++ b/src/hb-vector-svg-subset.cc
@@ -41,32 +41,7 @@ #include <string.h> #ifndef HB_NO_SVG -static bool -hb_svg_append_str (hb_vector_t<char> *out, - const char *s) -{ - return hb_svg_append_len (out, s, (unsigned) strlen (s)); -} - -static bool -hb_svg_append_unsigned (hb_vector_t<char> *out, - unsigned v) -{ - char tmp[10]; - unsigned n = 0; - do { - tmp[n++] = (char) ('0' + (v % 10)); - v /= 10; - } while (v); - - unsigned old_len = out->length; - if (unlikely (!out->resize_dirty ((int) (old_len + n)))) - return false; - - for (unsigned i = 0; i < n; i++) - out->arrayZ[old_len + i] = tmp[n - 1 - i]; - return true; -} +#include "hb-vector-svg.hh" static bool hb_svg_append_with_prefix (hb_vector_t<char> *out,
diff --git a/src/hb-vector-svg.hh b/src/hb-vector-svg.hh new file mode 100644 index 0000000..418d5bc --- /dev/null +++ b/src/hb-vector-svg.hh
@@ -0,0 +1,366 @@ +#ifndef HB_VECTOR_SVG_HH +#define HB_VECTOR_SVG_HH + +#include "hb-vector.h" + +static inline bool +hb_svg_append_str (hb_vector_t<char> *buf, const char *s) +{ + return hb_svg_append_len (buf, s, (unsigned) strlen (s)); +} + +static inline bool +hb_svg_append_unsigned (hb_vector_t<char> *buf, unsigned v) +{ + char tmp[10]; + unsigned n = 0; + do { + tmp[n++] = (char) ('0' + (v % 10)); + v /= 10; + } while (v); + + unsigned old_len = buf->length; + if (unlikely (!buf->resize_dirty ((int) (old_len + n)))) + return false; + + for (unsigned i = 0; i < n; i++) + buf->arrayZ[old_len + i] = tmp[n - 1 - i]; + return true; +} + +static inline bool +hb_svg_append_hex_byte (hb_vector_t<char> *buf, unsigned v) +{ + static const char hex[] = "0123456789ABCDEF"; + char tmp[2] = {hex[(v >> 4) & 15], hex[v & 15]}; + return hb_svg_append_len (buf, tmp, 2); +} + +static inline bool +hb_svg_append_base64 (hb_vector_t<char> *buf, + const uint8_t *data, + unsigned len) +{ + static const char b64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + unsigned out_len = ((len + 2) / 3) * 4; + unsigned old_len = buf->length; + if (unlikely (!buf->resize_dirty ((int) (old_len + out_len)))) + return false; + + char *dst = buf->arrayZ + old_len; + unsigned di = 0; + unsigned i = 0; + while (i + 2 < len) + { + unsigned v = ((unsigned) data[i] << 16) | + ((unsigned) data[i + 1] << 8) | + ((unsigned) data[i + 2]); + dst[di++] = b64[(v >> 18) & 63]; + dst[di++] = b64[(v >> 12) & 63]; + dst[di++] = b64[(v >> 6) & 63]; + dst[di++] = b64[v & 63]; + i += 3; + } + + if (i < len) + { + unsigned v = (unsigned) data[i] << 16; + if (i + 1 < len) + v |= (unsigned) data[i + 1] << 8; + dst[di++] = b64[(v >> 18) & 63]; + dst[di++] = b64[(v >> 12) & 63]; + dst[di++] = (i + 1 < len) ? b64[(v >> 6) & 63] : '='; + dst[di++] = '='; + } + + return true; +} + +struct hb_svg_blob_meta_t +{ + char *data; + int allocated; + bool transferred; + bool in_replace; +}; + +static hb_user_data_key_t hb_svg_blob_meta_user_data_key; + +static inline void +hb_svg_blob_meta_set_buffer (hb_svg_blob_meta_t *meta, + char *data, + int allocated) +{ + meta->data = data; + meta->allocated = allocated; + meta->transferred = false; +} + +static inline void +hb_svg_blob_meta_release_buffer (hb_svg_blob_meta_t *meta) +{ + if (!meta) + return; + if (!meta->transferred && meta->data) + hb_free (meta->data); + meta->data = nullptr; + meta->allocated = 0; + meta->transferred = true; +} + +static inline void +hb_svg_blob_meta_destroy (void *data) +{ + auto *meta = (hb_svg_blob_meta_t *) data; + hb_svg_blob_meta_release_buffer (meta); + if (meta->in_replace) + { + meta->in_replace = false; + return; + } + hb_free (meta); +} + +static inline hb_blob_t * +hb_svg_blob_from_buffer (hb_blob_t **recycled_blob, + hb_vector_t<char> *buf) +{ + unsigned len = 0; + int allocated = 0; + char *data = buf->steal (&len, &allocated); + if (!data) + return nullptr; + + hb_blob_t *blob = nullptr; + if (*recycled_blob) + blob = *recycled_blob; + bool reused_blob = blob && blob != hb_blob_get_empty (); + bool new_meta = false; + auto *meta = reused_blob + ? (hb_svg_blob_meta_t *) hb_blob_get_user_data (blob, &hb_svg_blob_meta_user_data_key) + : nullptr; + if (!meta) + { + meta = (hb_svg_blob_meta_t *) hb_malloc (sizeof (hb_svg_blob_meta_t)); + if (!meta) + { + hb_free (data); + return nullptr; + } + meta->data = nullptr; + meta->allocated = 0; + meta->transferred = true; + meta->in_replace = false; + new_meta = true; + } + + if (reused_blob) + { + meta->in_replace = true; + blob->replace_buffer (data, len, HB_MEMORY_MODE_WRITABLE, meta, hb_svg_blob_meta_destroy); + hb_svg_blob_meta_set_buffer (meta, data, allocated); + } + else + { + hb_svg_blob_meta_set_buffer (meta, data, allocated); + blob = hb_blob_create_or_fail (data, len, HB_MEMORY_MODE_WRITABLE, meta, hb_svg_blob_meta_destroy); + if (unlikely (!blob)) + return nullptr; + } + + if (unlikely (blob == hb_blob_get_empty ())) + { + if (new_meta) + hb_free (meta); + hb_free (data); + return nullptr; + } + + if (new_meta && + !hb_blob_set_user_data (blob, + &hb_svg_blob_meta_user_data_key, + meta, + nullptr, + true)) + { + if (!reused_blob) + hb_blob_destroy (blob); + return nullptr; + } + + if (*recycled_blob) + *recycled_blob = nullptr; + + return blob; +} + +static inline void +hb_svg_recover_recycled_buffer (hb_blob_t *blob, + hb_vector_t<char> *buf) +{ + if (!blob) + return; + + auto *meta = (hb_svg_blob_meta_t *) hb_blob_get_user_data (blob, &hb_svg_blob_meta_user_data_key); + if (!meta || meta->transferred || !meta->data) + return; + + buf->recycle_buffer (meta->data, 0, meta->allocated); + meta->data = nullptr; + meta->allocated = 0; + meta->transferred = true; +} + +static inline void +hb_svg_append_color (hb_vector_t<char> *buf, + hb_color_t color, + bool with_alpha) +{ + static const char hex[] = "0123456789ABCDEF"; + unsigned r = hb_color_get_red (color); + unsigned g = hb_color_get_green (color); + unsigned b = hb_color_get_blue (color); + unsigned a = hb_color_get_alpha (color); + hb_svg_append_c (buf, '#'); + if (((r >> 4) == (r & 0xF)) && + ((g >> 4) == (g & 0xF)) && + ((b >> 4) == (b & 0xF))) + { + hb_svg_append_c (buf, hex[r & 0xF]); + hb_svg_append_c (buf, hex[g & 0xF]); + hb_svg_append_c (buf, hex[b & 0xF]); + } + else + { + hb_svg_append_hex_byte (buf, r); + hb_svg_append_hex_byte (buf, g); + hb_svg_append_hex_byte (buf, b); + } + if (with_alpha && a != 255) + { + hb_svg_append_str (buf, "\" fill-opacity=\""); + hb_svg_append_num (buf, a / 255.f, 4); + } +} + +static inline void +hb_svg_transform_point (const hb_transform_t<> &t, + float x_scale_factor, + float y_scale_factor, + float x, float y, + float *tx, float *ty) +{ + float xx = x, yy = y; + t.transform_point (xx, yy); + *tx = xx / (x_scale_factor > 0 ? x_scale_factor : 1.f); + *ty = yy / (y_scale_factor > 0 ? y_scale_factor : 1.f); +} + +static inline hb_bool_t +hb_svg_set_glyph_extents_common (const hb_transform_t<> &transform, + float x_scale_factor, + float y_scale_factor, + const hb_glyph_extents_t *glyph_extents, + hb_vector_extents_t *extents, + hb_bool_t *has_extents) +{ + float x0 = (float) glyph_extents->x_bearing; + float y0 = (float) glyph_extents->y_bearing; + float x1 = x0 + glyph_extents->width; + float y1 = y0 + glyph_extents->height; + + float px[4] = {x0, x0, x1, x1}; + float py[4] = {y0, y1, y0, y1}; + + float tx, ty; + hb_svg_transform_point (transform, x_scale_factor, y_scale_factor, px[0], py[0], &tx, &ty); + float tx_min = tx, tx_max = tx; + float ty_min = ty, ty_max = ty; + + for (unsigned i = 1; i < 4; i++) + { + hb_svg_transform_point (transform, x_scale_factor, y_scale_factor, px[i], py[i], &tx, &ty); + tx_min = hb_min (tx_min, tx); + tx_max = hb_max (tx_max, tx); + ty_min = hb_min (ty_min, ty); + ty_max = hb_max (ty_max, ty); + } + + if (tx_max <= tx_min || ty_max <= ty_min) + return false; + + if (*has_extents) + { + float x0 = hb_min (extents->x, tx_min); + float y0 = hb_min (extents->y, ty_min); + float x1 = hb_max (extents->x + extents->width, tx_max); + float y1 = hb_max (extents->y + extents->height, ty_max); + *extents = {x0, y0, x1 - x0, y1 - y0}; + } + else + { + *extents = {tx_min, ty_min, tx_max - tx_min, ty_max - ty_min}; + *has_extents = true; + } + return true; +} + +static inline void +hb_svg_append_instance_transform (hb_vector_t<char> *out, + unsigned precision, + float x_scale_factor, + float y_scale_factor, + float xx, float yx, + float xy, float yy, + float tx, float ty) +{ + unsigned sprec = hb_svg_scale_precision (precision); + if (xx == 1.f && yx == 0.f && xy == 0.f && yy == 1.f) + { + float sx = 1.f / x_scale_factor; + float sy = 1.f / y_scale_factor; + hb_svg_append_str (out, "translate("); + hb_svg_append_num (out, tx / x_scale_factor, precision); + hb_svg_append_c (out, ','); + hb_svg_append_num (out, -ty / y_scale_factor, precision); + hb_svg_append_str (out, ") scale("); + hb_svg_append_num (out, sx, sprec, true); + hb_svg_append_c (out, ','); + hb_svg_append_num (out, -sy, sprec, true); + hb_svg_append_c (out, ')'); + } + else + { + hb_svg_append_str (out, "matrix("); + hb_svg_append_num (out, xx / x_scale_factor, sprec, true); + hb_svg_append_c (out, ','); + hb_svg_append_num (out, yx / y_scale_factor, sprec, true); + hb_svg_append_c (out, ','); + hb_svg_append_num (out, -xy / x_scale_factor, sprec, true); + hb_svg_append_c (out, ','); + hb_svg_append_num (out, -yy / y_scale_factor, sprec, true); + hb_svg_append_c (out, ','); + hb_svg_append_num (out, tx / x_scale_factor, precision); + hb_svg_append_c (out, ','); + hb_svg_append_num (out, -ty / y_scale_factor, precision); + hb_svg_append_c (out, ')'); + } +} + +static inline void +hb_svg_append_image_instance_translate (hb_vector_t<char> *out, + unsigned precision, + float x_scale_factor, + float y_scale_factor, + float tx, float ty) +{ + hb_svg_append_str (out, "translate("); + hb_svg_append_num (out, tx / x_scale_factor, precision); + hb_svg_append_c (out, ','); + hb_svg_append_num (out, -ty / y_scale_factor, precision); + hb_svg_append_c (out, ')'); +} + +#endif /* HB_VECTOR_SVG_HH */
diff --git a/src/meson.build b/src/meson.build index 156a770..a92e46f 100644 --- a/src/meson.build +++ b/src/meson.build
@@ -587,6 +587,7 @@ 'GRAPHITE', 'ICU', 'RASTER', + 'SUBSET', 'UNISCRIBE', 'VECTOR', 'WASM',