diff options
Diffstat (limited to 'thirdparty/harfbuzz')
110 files changed, 5082 insertions, 2077 deletions
diff --git a/thirdparty/harfbuzz/src/hb-aat-layout-common.hh b/thirdparty/harfbuzz/src/hb-aat-layout-common.hh index 1dcbe92904..1db0f1df92 100644 --- a/thirdparty/harfbuzz/src/hb-aat-layout-common.hh +++ b/thirdparty/harfbuzz/src/hb-aat-layout-common.hh @@ -839,7 +839,7 @@ struct StateTableDriver } if (!c->in_place) - buffer->swap_buffers (); + buffer->sync (); } public: diff --git a/thirdparty/harfbuzz/src/hb-aat-layout-just-table.hh b/thirdparty/harfbuzz/src/hb-aat-layout-just-table.hh index d745c11431..0bf9bd2912 100644 --- a/thirdparty/harfbuzz/src/hb-aat-layout-just-table.hh +++ b/thirdparty/harfbuzz/src/hb-aat-layout-just-table.hh @@ -146,7 +146,7 @@ struct DuctileGlyphAction HBUINT32 variationAxis; /* The 4-byte tag identifying the ductile axis. * This would normally be 0x64756374 ('duct'), * but you may use any axis the font contains. */ - HBFixed minimumLimit; /* The lowest value for the ductility axis tha + HBFixed minimumLimit; /* The lowest value for the ductility axis that * still yields an acceptable appearance. Normally * this will be 1.0. */ HBFixed noStretchValue; /* This is the default value that corresponds to diff --git a/thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh b/thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh index b77c1f4d44..2f99510925 100644 --- a/thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh +++ b/thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh @@ -1038,12 +1038,12 @@ struct Chain goto skip; if (reverse) - c->buffer->reverse (); + _hb_ot_layout_reverse_graphemes (c->buffer); subtable->apply (c); if (reverse) - c->buffer->reverse (); + _hb_ot_layout_reverse_graphemes (c->buffer); (void) c->buffer->message (c->font, "end chainsubtable %d", c->lookup_index); diff --git a/thirdparty/harfbuzz/src/hb-algs.hh b/thirdparty/harfbuzz/src/hb-algs.hh index 446d87e28b..c40a55cd1f 100644 --- a/thirdparty/harfbuzz/src/hb-algs.hh +++ b/thirdparty/harfbuzz/src/hb-algs.hh @@ -36,6 +36,7 @@ #include <algorithm> #include <initializer_list> +#include <functional> #include <new> /* @@ -210,12 +211,23 @@ struct } HB_FUNCOBJ (hb_bool); +template <typename T> +static inline +T hb_coerce (const T v) { return v; } +template <typename T, typename V, + hb_enable_if (!hb_is_same (hb_decay<T>, hb_decay<V>) && std::is_pointer<V>::value)> +static inline +T hb_coerce (const V v) { return *v; } + struct { private: template <typename T> constexpr auto - impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, hb_deref (v).hash ()) + impl (const T& v, hb_priority<2>) const HB_RETURN (uint32_t, hb_deref (v).hash ()) + + template <typename T> constexpr auto + impl (const T& v, hb_priority<1>) const HB_RETURN (uint32_t, std::hash<hb_decay<decltype (hb_deref (v))>>{} (hb_deref (v))) template <typename T, hb_enable_if (std::is_integral<T>::value)> constexpr auto @@ -435,23 +447,29 @@ struct private: template <typename T1, typename T2> auto - impl (T1&& v1, T2 &&v2, hb_priority<2>) const HB_AUTO_RETURN + impl (T1&& v1, T2 &&v2, hb_priority<3>) const HB_AUTO_RETURN ( std::forward<T2> (v2).cmp (std::forward<T1> (v1)) == 0 ) template <typename T1, typename T2> auto - impl (T1&& v1, T2 &&v2, hb_priority<1>) const HB_AUTO_RETURN + impl (T1&& v1, T2 &&v2, hb_priority<2>) const HB_AUTO_RETURN ( std::forward<T1> (v1).cmp (std::forward<T2> (v2)) == 0 ) template <typename T1, typename T2> auto - impl (T1&& v1, T2 &&v2, hb_priority<0>) const HB_AUTO_RETURN + impl (T1&& v1, T2 &&v2, hb_priority<1>) const HB_AUTO_RETURN ( std::forward<T1> (v1) == std::forward<T2> (v2) ) + template <typename T1, typename T2> auto + impl (T1&& v1, T2 &&v2, hb_priority<0>) const HB_AUTO_RETURN + ( + std::forward<T2> (v2) == std::forward<T1> (v1) + ) + public: template <typename T1, typename T2> auto @@ -472,11 +490,15 @@ struct hb_pair_t typedef T2 second_t; typedef hb_pair_t<T1, T2> pair_t; + template <typename U1 = T1, typename U2 = T2, + hb_enable_if (std::is_default_constructible<U1>::value && + std::is_default_constructible<U2>::value)> + hb_pair_t () : first (), second () {} hb_pair_t (T1 a, T2 b) : first (a), second (b) {} template <typename Q1, typename Q2, hb_enable_if (hb_is_convertible (T1, Q1) && - hb_is_convertible (T2, T2))> + hb_is_convertible (T2, Q2))> operator hb_pair_t<Q1, Q2> () { return hb_pair_t<Q1, Q2> (first, second); } hb_pair_t<T1, T2> reverse () const @@ -870,7 +892,7 @@ hb_bsearch_impl (unsigned *pos, /* Out */ #pragma GCC diagnostic ignored "-Wcast-align" V* p = (V*) (((const char *) base) + (mid * stride)); #pragma GCC diagnostic pop - int c = compar ((const void *) hb_addressof (key), (const void *) p, ds...); + int c = compar ((const void *) std::addressof (key), (const void *) p, ds...); if (c < 0) max = mid - 1; else if (c > 0) diff --git a/thirdparty/harfbuzz/src/hb-array.hh b/thirdparty/harfbuzz/src/hb-array.hh index dd61509b2e..1d1476d7cd 100644 --- a/thirdparty/harfbuzz/src/hb-array.hh +++ b/thirdparty/harfbuzz/src/hb-array.hh @@ -51,13 +51,19 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&> * Constructors. */ hb_array_t () = default; - hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_) {} + hb_array_t (const hb_array_t&) = default; + ~hb_array_t () = default; + hb_array_t& operator= (const hb_array_t&) = default; + hb_array_t& operator= (hb_array_t&&) = default; + + constexpr hb_array_t (std::nullptr_t) : hb_array_t () {} + constexpr hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_) {} template <unsigned int length_> - hb_array_t (Type (&array_)[length_]) : hb_array_t (array_, length_) {} + constexpr hb_array_t (Type (&array_)[length_]) : hb_array_t (array_, length_) {} template <typename U, hb_enable_if (hb_is_cr_convertible(U, Type))> - hb_array_t (const hb_array_t<U> &o) : + constexpr hb_array_t (const hb_array_t<U> &o) : hb_iter_with_fallback_t<hb_array_t, Type&> (), arrayZ (o.arrayZ), length (o.length), backwards_length (o.backwards_length) {} template <typename U, @@ -303,13 +309,19 @@ struct hb_sorted_array_t : static constexpr bool is_sorted_iterator = true; hb_sorted_array_t () = default; - hb_sorted_array_t (Type *array_, unsigned int length_) : hb_array_t<Type> (array_, length_) {} + hb_sorted_array_t (const hb_sorted_array_t&) = default; + ~hb_sorted_array_t () = default; + hb_sorted_array_t& operator= (const hb_sorted_array_t&) = default; + hb_sorted_array_t& operator= (hb_sorted_array_t&&) = default; + + constexpr hb_sorted_array_t (std::nullptr_t) : hb_sorted_array_t () {} + constexpr hb_sorted_array_t (Type *array_, unsigned int length_) : hb_array_t<Type> (array_, length_) {} template <unsigned int length_> - hb_sorted_array_t (Type (&array_)[length_]) : hb_array_t<Type> (array_) {} + constexpr hb_sorted_array_t (Type (&array_)[length_]) : hb_array_t<Type> (array_) {} template <typename U, hb_enable_if (hb_is_cr_convertible(U, Type))> - hb_sorted_array_t (const hb_array_t<U> &o) : + constexpr hb_sorted_array_t (const hb_array_t<U> &o) : hb_iter_t<hb_sorted_array_t, Type&> (), hb_array_t<Type> (o) {} template <typename U, @@ -400,7 +412,7 @@ bool hb_array_t<T>::operator == (const hb_array_t<T> &o) const return true; } -/* TODO Specialize opeator== for hb_bytes_t and hb_ubytes_t. */ +/* TODO Specialize operator== for hb_bytes_t and hb_ubytes_t. */ template <> inline uint32_t hb_array_t<const char>::hash () const { diff --git a/thirdparty/harfbuzz/src/hb-bimap.hh b/thirdparty/harfbuzz/src/hb-bimap.hh index d466af8b60..a9e1278de7 100644 --- a/thirdparty/harfbuzz/src/hb-bimap.hh +++ b/thirdparty/harfbuzz/src/hb-bimap.hh @@ -33,20 +33,6 @@ /* Bi-directional map */ struct hb_bimap_t { - /* XXX(remove) */ - void init () - { - forw_map.init (); - back_map.init (); - } - - /* XXX(remove) */ - void fini () - { - forw_map.fini (); - back_map.fini (); - } - void reset () { forw_map.reset (); diff --git a/thirdparty/harfbuzz/src/hb-buffer-verify.cc b/thirdparty/harfbuzz/src/hb-buffer-verify.cc new file mode 100644 index 0000000000..dea2c11c35 --- /dev/null +++ b/thirdparty/harfbuzz/src/hb-buffer-verify.cc @@ -0,0 +1,422 @@ +/* + * Copyright © 2022 Behdad Esfahbod + * + * This is part of HarfBuzz, a text shaping library. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and its documentation for any purpose, provided that the + * above copyright notice and the following two paragraphs appear in + * all copies of this software. + * + * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR + * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN + * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH + * DAMAGE. + * + * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, + * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO + * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + * + * Google Author(s): Behdad Esfahbod + */ + +#include "hb.hh" + +#ifndef HB_NO_BUFFER_VERIFY + +#include "hb-buffer.hh" + + +#define BUFFER_VERIFY_ERROR "buffer verify error: " +static inline void +buffer_verify_error (hb_buffer_t *buffer, + hb_font_t *font, + const char *fmt, + ...) HB_PRINTF_FUNC(3, 4); + +static inline void +buffer_verify_error (hb_buffer_t *buffer, + hb_font_t *font, + const char *fmt, + ...) +{ + va_list ap; + va_start (ap, fmt); + if (buffer->messaging ()) + { + buffer->message_impl (font, fmt, ap); + } + else + { + fprintf (stderr, "harfbuzz "); + vfprintf (stderr, fmt, ap); + fprintf (stderr, "\n"); + } + va_end (ap); +} + +static bool +buffer_verify_monotone (hb_buffer_t *buffer, + hb_font_t *font) +{ + /* Check that clusters are monotone. */ + if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES || + buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS) + { + bool is_forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer)); + + unsigned int num_glyphs; + hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs); + + for (unsigned int i = 1; i < num_glyphs; i++) + if (info[i-1].cluster != info[i].cluster && + (info[i-1].cluster < info[i].cluster) != is_forward) + { + buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "clusters are not monotone."); + return false; + } + } + + return true; +} + +static bool +buffer_verify_unsafe_to_break (hb_buffer_t *buffer, + hb_buffer_t *text_buffer, + hb_font_t *font, + const hb_feature_t *features, + unsigned int num_features, + const char * const *shapers) +{ + if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES && + buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS) + { + /* Cannot perform this check without monotone clusters. */ + return true; + } + + /* Check that breaking up shaping at safe-to-break is indeed safe. */ + + hb_buffer_t *fragment = hb_buffer_create_similar (buffer); + hb_buffer_set_flags (fragment, hb_buffer_get_flags (fragment) & ~HB_BUFFER_FLAG_VERIFY); + hb_buffer_t *reconstruction = hb_buffer_create_similar (buffer); + hb_buffer_set_flags (reconstruction, hb_buffer_get_flags (reconstruction) & ~HB_BUFFER_FLAG_VERIFY); + + unsigned int num_glyphs; + hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs); + + unsigned int num_chars; + hb_glyph_info_t *text = hb_buffer_get_glyph_infos (text_buffer, &num_chars); + + /* Chop text and shape fragments. */ + bool forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer)); + unsigned int start = 0; + unsigned int text_start = forward ? 0 : num_chars; + unsigned int text_end = text_start; + for (unsigned int end = 1; end < num_glyphs + 1; end++) + { + if (end < num_glyphs && + (info[end].cluster == info[end-1].cluster || + info[end-(forward?0:1)].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK)) + continue; + + /* Shape segment corresponding to glyphs start..end. */ + if (end == num_glyphs) + { + if (forward) + text_end = num_chars; + else + text_start = 0; + } + else + { + if (forward) + { + unsigned int cluster = info[end].cluster; + while (text_end < num_chars && text[text_end].cluster < cluster) + text_end++; + } + else + { + unsigned int cluster = info[end - 1].cluster; + while (text_start && text[text_start - 1].cluster >= cluster) + text_start--; + } + } + assert (text_start < text_end); + + if (0) + printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end); + + hb_buffer_clear_contents (fragment); + + hb_buffer_flags_t flags = hb_buffer_get_flags (fragment); + if (0 < text_start) + flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_BOT); + if (text_end < num_chars) + flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_EOT); + hb_buffer_set_flags (fragment, flags); + + hb_buffer_append (fragment, text_buffer, text_start, text_end); + if (!hb_shape_full (font, fragment, features, num_features, shapers)) + { + buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment."); + hb_buffer_destroy (reconstruction); + hb_buffer_destroy (fragment); + return false; + } + hb_buffer_append (reconstruction, fragment, 0, -1); + + start = end; + if (forward) + text_start = text_end; + else + text_end = text_start; + } + + bool ret = true; + hb_buffer_diff_flags_t diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0); + if (diff) + { + buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-break test failed."); + ret = false; + + /* Return the reconstructed result instead so it can be inspected. */ + hb_buffer_set_length (buffer, 0); + hb_buffer_append (buffer, reconstruction, 0, -1); + } + + hb_buffer_destroy (reconstruction); + hb_buffer_destroy (fragment); + + return ret; +} + +static bool +buffer_verify_unsafe_to_concat (hb_buffer_t *buffer, + hb_buffer_t *text_buffer, + hb_font_t *font, + const hb_feature_t *features, + unsigned int num_features, + const char * const *shapers) +{ + if (buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES && + buffer->cluster_level != HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS) + { + /* Cannot perform this check without monotone clusters. */ + return true; + } + + /* Check that shuffling up text before shaping at safe-to-concat points + * is indeed safe. */ + + /* This is what we do: + * + * 1. We shape text once. Then segment the text at all the safe-to-concat + * points; + * + * 2. Then we create two buffers, one containing all the even segments and + * one all the odd segments. + * + * 3. Because all these segments were safe-to-concat at both ends, we + * expect that concatenating them and shaping should NOT change the + * shaping results of each segment. As such, we expect that after + * shaping the two buffers, we still get cluster boundaries at the + * segment boundaries, and that those all are safe-to-concat points. + * Moreover, that there are NOT any safe-to-concat points within the + * segments. + * + * 4. Finally, we reconstruct the shaping results of the original text by + * simply interleaving the shaping results of the segments from the two + * buffers, and assert that the total shaping results is the same as + * the one from original buffer in step 1. + */ + + hb_buffer_t *fragments[2] {hb_buffer_create_similar (buffer), + hb_buffer_create_similar (buffer)}; + hb_buffer_set_flags (fragments[0], hb_buffer_get_flags (fragments[0]) & ~HB_BUFFER_FLAG_VERIFY); + hb_buffer_set_flags (fragments[1], hb_buffer_get_flags (fragments[1]) & ~HB_BUFFER_FLAG_VERIFY); + hb_buffer_t *reconstruction = hb_buffer_create_similar (buffer); + hb_buffer_set_flags (reconstruction, hb_buffer_get_flags (reconstruction) & ~HB_BUFFER_FLAG_VERIFY); + hb_segment_properties_t props; + hb_buffer_get_segment_properties (buffer, &props); + hb_buffer_set_segment_properties (fragments[0], &props); + hb_buffer_set_segment_properties (fragments[1], &props); + hb_buffer_set_segment_properties (reconstruction, &props); + + unsigned num_glyphs; + hb_glyph_info_t *info = hb_buffer_get_glyph_infos (buffer, &num_glyphs); + + unsigned num_chars; + hb_glyph_info_t *text = hb_buffer_get_glyph_infos (text_buffer, &num_chars); + + bool forward = HB_DIRECTION_IS_FORWARD (hb_buffer_get_direction (buffer)); + + if (!forward) + hb_buffer_reverse (buffer); + + /* + * Split text into segments and collect into to fragment streams. + */ + { + unsigned fragment_idx = 0; + unsigned start = 0; + unsigned text_start = 0; + unsigned text_end = 0; + for (unsigned end = 1; end < num_glyphs + 1; end++) + { + if (end < num_glyphs && + (info[end].cluster == info[end-1].cluster || + info[end].mask & HB_GLYPH_FLAG_UNSAFE_TO_CONCAT)) + continue; + + /* Accumulate segment corresponding to glyphs start..end. */ + if (end == num_glyphs) + text_end = num_chars; + else + { + unsigned cluster = info[end].cluster; + while (text_end < num_chars && text[text_end].cluster < cluster) + text_end++; + } + assert (text_start < text_end); + + if (0) + printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end); + +#if 0 + hb_buffer_flags_t flags = hb_buffer_get_flags (fragment); + if (0 < text_start) + flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_BOT); + if (text_end < num_chars) + flags = (hb_buffer_flags_t) (flags & ~HB_BUFFER_FLAG_EOT); + hb_buffer_set_flags (fragment, flags); +#endif + + hb_buffer_append (fragments[fragment_idx], text_buffer, text_start, text_end); + + start = end; + text_start = text_end; + fragment_idx = 1 - fragment_idx; + } + } + + bool ret = true; + hb_buffer_diff_flags_t diff; + + /* + * Shape the two fragment streams. + */ + if (!hb_shape_full (font, fragments[0], features, num_features, shapers)) + { + buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment."); + ret = false; + goto out; + } + if (!hb_shape_full (font, fragments[1], features, num_features, shapers)) + { + buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "shaping failed while shaping fragment."); + ret = false; + goto out; + } + + if (!forward) + { + hb_buffer_reverse (fragments[0]); + hb_buffer_reverse (fragments[1]); + } + + /* + * Reconstruct results. + */ + { + unsigned fragment_idx = 0; + unsigned fragment_start[2] {0, 0}; + unsigned fragment_num_glyphs[2]; + hb_glyph_info_t *fragment_info[2]; + for (unsigned i = 0; i < 2; i++) + fragment_info[i] = hb_buffer_get_glyph_infos (fragments[i], &fragment_num_glyphs[i]); + while (fragment_start[0] < fragment_num_glyphs[0] || + fragment_start[1] < fragment_num_glyphs[1]) + { + unsigned fragment_end = fragment_start[fragment_idx] + 1; + while (fragment_end < fragment_num_glyphs[fragment_idx] && + (fragment_info[fragment_idx][fragment_end].cluster == fragment_info[fragment_idx][fragment_end - 1].cluster || + fragment_info[fragment_idx][fragment_end].mask & HB_GLYPH_FLAG_UNSAFE_TO_CONCAT)) + fragment_end++; + + hb_buffer_append (reconstruction, fragments[fragment_idx], fragment_start[fragment_idx], fragment_end); + + fragment_start[fragment_idx] = fragment_end; + fragment_idx = 1 - fragment_idx; + } + } + + if (!forward) + { + hb_buffer_reverse (buffer); + hb_buffer_reverse (reconstruction); + } + + /* + * Diff results. + */ + diff = hb_buffer_diff (reconstruction, buffer, (hb_codepoint_t) -1, 0); + if (diff) + { + buffer_verify_error (buffer, font, BUFFER_VERIFY_ERROR "unsafe-to-concat test failed."); + ret = false; + + /* Return the reconstructed result instead so it can be inspected. */ + hb_buffer_set_length (buffer, 0); + hb_buffer_append (buffer, reconstruction, 0, -1); + } + + +out: + hb_buffer_destroy (reconstruction); + hb_buffer_destroy (fragments[0]); + hb_buffer_destroy (fragments[1]); + + return ret; +} + +bool +hb_buffer_t::verify (hb_buffer_t *text_buffer, + hb_font_t *font, + const hb_feature_t *features, + unsigned int num_features, + const char * const *shapers) +{ + bool ret = true; + if (!buffer_verify_monotone (this, font)) + ret = false; + if (!buffer_verify_unsafe_to_break (this, text_buffer, font, features, num_features, shapers)) + ret = false; + if ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) != 0 && + !buffer_verify_unsafe_to_concat (this, text_buffer, font, features, num_features, shapers)) + ret = false; + if (!ret) + { + unsigned len = text_buffer->len; + hb_vector_t<char> bytes; + if (likely (bytes.resize (len * 10 + 16))) + { + hb_buffer_serialize_unicode (text_buffer, + 0, len, + bytes.arrayZ, bytes.length, + &len, + HB_BUFFER_SERIALIZE_FORMAT_TEXT, + HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS); + buffer_verify_error (this, font, BUFFER_VERIFY_ERROR "text was: %s.", bytes.arrayZ); + } + } + return ret; +} + + +#endif diff --git a/thirdparty/harfbuzz/src/hb-buffer.cc b/thirdparty/harfbuzz/src/hb-buffer.cc index b4f7f72374..d36fcfde39 100644 --- a/thirdparty/harfbuzz/src/hb-buffer.cc +++ b/thirdparty/harfbuzz/src/hb-buffer.cc @@ -86,7 +86,46 @@ hb_segment_properties_hash (const hb_segment_properties_t *p) (intptr_t) (p->language); } +/** + * hb_segment_properties_overlay: + * @p: #hb_segment_properties_t to fill in. + * @src: #hb_segment_properties_t to fill in from. + * + * Fills in missing fields of @p from @src in a considered manner. + * + * First, if @p does not have direction set, direction is copied from @src. + * + * Next, if @p and @src have the same direction (which can be unset), if @p + * does not have script set, script is copied from @src. + * + * Finally, if @p and @src have the same direction and script (which either + * can be unset), if @p does not have language set, language is copied from + * @src. + * + * Since: 3.3.0 + **/ +void +hb_segment_properties_overlay (hb_segment_properties_t *p, + const hb_segment_properties_t *src) +{ + if (unlikely (!p || !src)) + return; + + if (!p->direction) + p->direction = src->direction; + + if (p->direction != src->direction) + return; + if (!p->script) + p->script = src->script; + + if (p->script != src->script) + return; + + if (!p->language) + p->language = src->language; +} /* Here is how the buffer works internally: * @@ -96,14 +135,14 @@ hb_segment_properties_hash (const hb_segment_properties_t *p) * As an optimization, both info and out_info may point to the * same piece of memory, which is owned by info. This remains the * case as long as out_len doesn't exceed i at any time. - * In that case, swap_buffers() is mostly no-op and the glyph operations + * In that case, sync() is mostly no-op and the glyph operations * operate mostly in-place. * * As soon as out_info gets longer than info, out_info is moved over * to an alternate buffer (which we reuse the pos buffer for), and its * current contents (out_len entries) are copied to the new place. * - * This should all remain transparent to the user. swap_buffers() then + * This should all remain transparent to the user. sync() then * switches info over to out_info and does housekeeping. */ @@ -217,11 +256,24 @@ hb_buffer_t::get_scratch_buffer (unsigned int *size) /* HarfBuzz-Internal API */ void +hb_buffer_t::similar (const hb_buffer_t &src) +{ + hb_unicode_funcs_destroy (unicode); + unicode = hb_unicode_funcs_reference (src.unicode); + flags = src.flags; + cluster_level = src.cluster_level; + replacement = src.invisible; + invisible = src.invisible; + not_found = src.not_found; +} + +void hb_buffer_t::reset () { hb_unicode_funcs_destroy (unicode); unicode = hb_unicode_funcs_reference (hb_unicode_funcs_get_default ()); flags = HB_BUFFER_FLAG_DEFAULT; + cluster_level = HB_BUFFER_CLUSTER_LEVEL_DEFAULT; replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT; invisible = 0; not_found = 0; @@ -232,11 +284,10 @@ hb_buffer_t::reset () void hb_buffer_t::clear () { + content_type = HB_BUFFER_CONTENT_TYPE_INVALID; hb_segment_properties_t default_props = HB_SEGMENT_PROPERTIES_DEFAULT; props = default_props; - scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT; - content_type = HB_BUFFER_CONTENT_TYPE_INVALID; successful = true; have_output = false; have_positions = false; @@ -244,15 +295,43 @@ hb_buffer_t::clear () idx = 0; len = 0; out_len = 0; - out_info = info; - serial = 0; + out_info = info; memset (context, 0, sizeof context); memset (context_len, 0, sizeof context_len); deallocate_var_all (); + serial = 0; + scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT; +} + +void +hb_buffer_t::enter () +{ + deallocate_var_all (); + serial = 0; + scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT; + if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_LEN_FACTOR))) + { + max_len = hb_max (len * HB_BUFFER_MAX_LEN_FACTOR, + (unsigned) HB_BUFFER_MAX_LEN_MIN); + } + if (likely (!hb_unsigned_mul_overflows (len, HB_BUFFER_MAX_OPS_FACTOR))) + { + max_ops = hb_max (len * HB_BUFFER_MAX_OPS_FACTOR, + (unsigned) HB_BUFFER_MAX_OPS_MIN); + } } +void +hb_buffer_t::leave () +{ + max_len = HB_BUFFER_MAX_LEN_DEFAULT; + max_ops = HB_BUFFER_MAX_OPS_DEFAULT; + deallocate_var_all (); + serial = 0; +} + void hb_buffer_t::add (hb_codepoint_t codepoint, @@ -307,7 +386,7 @@ hb_buffer_t::clear_positions () } void -hb_buffer_t::swap_buffers () +hb_buffer_t::sync () { assert (have_output); @@ -396,52 +475,6 @@ hb_buffer_t::set_masks (hb_mask_t value, } void -hb_buffer_t::reverse_range (unsigned int start, - unsigned int end) -{ - if (end - start < 2) - return; - - hb_array_t<hb_glyph_info_t> (info, len).reverse (start, end); - - if (have_positions) { - hb_array_t<hb_glyph_position_t> (pos, len).reverse (start, end); - } -} - -void -hb_buffer_t::reverse () -{ - if (unlikely (!len)) - return; - - reverse_range (0, len); -} - -void -hb_buffer_t::reverse_clusters () -{ - unsigned int i, start, count, last_cluster; - - if (unlikely (!len)) - return; - - reverse (); - - count = len; - start = 0; - last_cluster = info[0].cluster; - for (i = 1; i < count; i++) { - if (last_cluster != info[i].cluster) { - reverse_range (start, i); - start = i; - last_cluster = info[i].cluster; - } - } - reverse_range (start, i); -} - -void hb_buffer_t::merge_clusters_impl (unsigned int start, unsigned int end) { @@ -540,32 +573,6 @@ done: } void -hb_buffer_t::unsafe_to_break_impl (unsigned int start, unsigned int end) -{ - unsigned int cluster = UINT_MAX; - cluster = _unsafe_to_break_find_min_cluster (info, start, end, cluster); - _unsafe_to_break_set_mask (info, start, end, cluster); -} -void -hb_buffer_t::unsafe_to_break_from_outbuffer (unsigned int start, unsigned int end) -{ - if (!have_output) - { - unsafe_to_break_impl (start, end); - return; - } - - assert (start <= out_len); - assert (idx <= end); - - unsigned int cluster = UINT_MAX; - cluster = _unsafe_to_break_find_min_cluster (out_info, start, out_len, cluster); - cluster = _unsafe_to_break_find_min_cluster (info, idx, end, cluster); - _unsafe_to_break_set_mask (out_info, start, out_len, cluster); - _unsafe_to_break_set_mask (info, idx, end, cluster); -} - -void hb_buffer_t::guess_segment_properties () { assert_unicode (); @@ -610,12 +617,11 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT, 0, /* invisible */ 0, /* not_found */ - HB_BUFFER_SCRATCH_FLAG_DEFAULT, - HB_BUFFER_MAX_LEN_DEFAULT, - HB_BUFFER_MAX_OPS_DEFAULT, + HB_BUFFER_CONTENT_TYPE_INVALID, HB_SEGMENT_PROPERTIES_DEFAULT, + false, /* successful */ false, /* have_output */ true /* have_positions */ @@ -655,6 +661,46 @@ hb_buffer_create () } /** + * hb_buffer_create_similar: + * @src: An #hb_buffer_t + * + * Creates a new #hb_buffer_t, similar to hb_buffer_create(). The only + * difference is that the buffer is configured similarly to @src. + * + * Return value: (transfer full): + * A newly allocated #hb_buffer_t, similar to hb_buffer_create(). + * + * Since: 3.3.0 + **/ +hb_buffer_t * +hb_buffer_create_similar (const hb_buffer_t *src) +{ + hb_buffer_t *buffer = hb_buffer_create (); + + buffer->similar (*src); + + return buffer; +} + +/** + * hb_buffer_reset: + * @buffer: An #hb_buffer_t + * + * Resets the buffer to its initial status, as if it was just newly created + * with hb_buffer_create(). + * + * Since: 0.9.2 + **/ +void +hb_buffer_reset (hb_buffer_t *buffer) +{ + if (unlikely (hb_object_is_immutable (buffer))) + return; + + buffer->reset (); +} + +/** * hb_buffer_get_empty: * * Fetches an empty #hb_buffer_t. @@ -1202,24 +1248,6 @@ hb_buffer_get_not_found_glyph (hb_buffer_t *buffer) /** - * hb_buffer_reset: - * @buffer: An #hb_buffer_t - * - * Resets the buffer to its initial status, as if it was just newly created - * with hb_buffer_create(). - * - * Since: 0.9.2 - **/ -void -hb_buffer_reset (hb_buffer_t *buffer) -{ - if (unlikely (hb_object_is_immutable (buffer))) - return; - - buffer->reset (); -} - -/** * hb_buffer_clear_contents: * @buffer: An #hb_buffer_t * @@ -1761,7 +1789,7 @@ hb_buffer_add_codepoints (hb_buffer_t *buffer, **/ HB_EXTERN void hb_buffer_append (hb_buffer_t *buffer, - hb_buffer_t *source, + const hb_buffer_t *source, unsigned int start, unsigned int end) { @@ -1794,6 +1822,8 @@ hb_buffer_append (hb_buffer_t *buffer, if (!buffer->have_positions && source->have_positions) buffer->clear_positions (); + hb_segment_properties_overlay (&buffer->props, &source->props); + memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0])); if (buffer->have_positions) memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0])); diff --git a/thirdparty/harfbuzz/src/hb-buffer.h b/thirdparty/harfbuzz/src/hb-buffer.h index a183cb9d4a..ece7d2d8cf 100644 --- a/thirdparty/harfbuzz/src/hb-buffer.h +++ b/thirdparty/harfbuzz/src/hb-buffer.h @@ -76,18 +76,72 @@ typedef struct hb_glyph_info_t { * @HB_GLYPH_FLAG_UNSAFE_TO_BREAK: Indicates that if input text is broken at the * beginning of the cluster this glyph is part of, * then both sides need to be re-shaped, as the - * result might be different. On the flip side, - * it means that when this flag is not present, - * then it's safe to break the glyph-run at the - * beginning of this cluster, and the two sides - * represent the exact same result one would get - * if breaking input text at the beginning of - * this cluster and shaping the two sides - * separately. This can be used to optimize - * paragraph layout, by avoiding re-shaping - * of each line after line-breaking, or limiting - * the reshaping to a small piece around the - * breaking point only. + * result might be different. + * On the flip side, it means that when this + * flag is not present, then it is safe to break + * the glyph-run at the beginning of this + * cluster, and the two sides will represent the + * exact same result one would get if breaking + * input text at the beginning of this cluster + * and shaping the two sides separately. + * This can be used to optimize paragraph + * layout, by avoiding re-shaping of each line + * after line-breaking. + * @HB_GLYPH_FLAG_UNSAFE_TO_CONCAT: Indicates that if input text is changed on one + * side of the beginning of the cluster this glyph + * is part of, then the shaping results for the + * other side might change. + * Note that the absence of this flag will NOT by + * itself mean that it IS safe to concat text. + * Only two pieces of text both of which clear of + * this flag can be concatenated safely. + * This can be used to optimize paragraph + * layout, by avoiding re-shaping of each line + * after line-breaking, by limiting the + * reshaping to a small piece around the + * breaking positin only, even if the breaking + * position carries the + * #HB_GLYPH_FLAG_UNSAFE_TO_BREAK or when + * hyphenation or other text transformation + * happens at line-break position, in the following + * way: + * 1. Iterate back from the line-break position + * until the first cluster start position that is + * NOT unsafe-to-concat, 2. shape the segment from + * there till the end of line, 3. check whether the + * resulting glyph-run also is clear of the + * unsafe-to-concat at its start-of-text position; + * if it is, just splice it into place and the line + * is shaped; If not, move on to a position further + * back that is clear of unsafe-to-concat and retry + * from there, and repeat. + * At the start of next line a similar algorithm can + * be implemented. That is: 1. Iterate forward from + * the line-break position untill the first cluster + * start position that is NOT unsafe-to-concat, 2. + * shape the segment from beginning of the line to + * that position, 3. check whether the resulting + * glyph-run also is clear of the unsafe-to-concat + * at its end-of-text position; if it is, just splice + * it into place and the beginning is shaped; If not, + * move on to a position further forward that is clear + * of unsafe-to-concat and retry up to there, and repeat. + * A slight complication will arise in the + * implementation of the algorithm above, + * because while our buffer API has a way to + * return flags for position corresponding to + * start-of-text, there is currently no position + * corresponding to end-of-text. This limitation + * can be alleviated by shaping more text than needed + * and looking for unsafe-to-concat flag within text + * clusters. + * The #HB_GLYPH_FLAG_UNSAFE_TO_BREAK flag will + * always imply this flag. + * To use this flag, you must enable the buffer flag + * @HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT during + * shaping, otherwise the buffer flag will not be + * reliably produced. + * Since: 4.0.0 * @HB_GLYPH_FLAG_DEFINED: All the currently defined flags. * * Flags for #hb_glyph_info_t. @@ -96,8 +150,9 @@ typedef struct hb_glyph_info_t { */ typedef enum { /*< flags >*/ HB_GLYPH_FLAG_UNSAFE_TO_BREAK = 0x00000001, + HB_GLYPH_FLAG_UNSAFE_TO_CONCAT = 0x00000002, - HB_GLYPH_FLAG_DEFINED = 0x00000001 /* OR of all defined flags */ + HB_GLYPH_FLAG_DEFINED = 0x00000003 /* OR of all defined flags */ } hb_glyph_flags_t; HB_EXTERN hb_glyph_flags_t @@ -170,6 +225,9 @@ hb_segment_properties_equal (const hb_segment_properties_t *a, HB_EXTERN unsigned int hb_segment_properties_hash (const hb_segment_properties_t *p); +HB_EXTERN void +hb_segment_properties_overlay (hb_segment_properties_t *p, + const hb_segment_properties_t *src); /** @@ -185,6 +243,13 @@ HB_EXTERN hb_buffer_t * hb_buffer_create (void); HB_EXTERN hb_buffer_t * +hb_buffer_create_similar (const hb_buffer_t *src); + +HB_EXTERN void +hb_buffer_reset (hb_buffer_t *buffer); + + +HB_EXTERN hb_buffer_t * hb_buffer_get_empty (void); HB_EXTERN hb_buffer_t * @@ -295,7 +360,19 @@ hb_buffer_guess_segment_properties (hb_buffer_t *buffer); * @HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE: * flag indicating that a dotted circle should * not be inserted in the rendering of incorrect - * character sequences (such at <0905 093E>). Since: 2.4 + * character sequences (such at <0905 093E>). Since: 2.4.0 + * @HB_BUFFER_FLAG_VERIFY: + * flag indicating that the hb_shape() call and its variants + * should perform various verification processes on the results + * of the shaping operation on the buffer. If the verification + * fails, then either a buffer message is sent, if a message + * handler is installed on the buffer, or a message is written + * to standard error. In either case, the shaping result might + * be modified to show the failed output. Since: 3.4.0 + * @HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT: + * flag indicating that the @HB_GLYPH_FLAG_UNSAFE_TO_CONCAT + * glyph-flag should be produced by the shaper. By default + * it will not be produced since it incurs a cost. Since: 4.0.0 * * Flags for #hb_buffer_t. * @@ -307,7 +384,9 @@ typedef enum { /*< flags >*/ HB_BUFFER_FLAG_EOT = 0x00000002u, /* End-of-text */ HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES = 0x00000004u, HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES = 0x00000008u, - HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE = 0x00000010u + HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE = 0x00000010u, + HB_BUFFER_FLAG_VERIFY = 0x00000020u, + HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT = 0x00000040u } hb_buffer_flags_t; HB_EXTERN void @@ -391,8 +470,9 @@ HB_EXTERN hb_codepoint_t hb_buffer_get_not_found_glyph (hb_buffer_t *buffer); -HB_EXTERN void -hb_buffer_reset (hb_buffer_t *buffer); +/* + * Content API. + */ HB_EXTERN void hb_buffer_clear_contents (hb_buffer_t *buffer); @@ -460,7 +540,7 @@ hb_buffer_add_codepoints (hb_buffer_t *buffer, HB_EXTERN void hb_buffer_append (hb_buffer_t *buffer, - hb_buffer_t *source, + const hb_buffer_t *source, unsigned int start, unsigned int end); @@ -557,24 +637,24 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer, HB_EXTERN unsigned int hb_buffer_serialize_unicode (hb_buffer_t *buffer, - unsigned int start, - unsigned int end, - char *buf, - unsigned int buf_size, - unsigned int *buf_consumed, - hb_buffer_serialize_format_t format, - hb_buffer_serialize_flags_t flags); + unsigned int start, + unsigned int end, + char *buf, + unsigned int buf_size, + unsigned int *buf_consumed, + hb_buffer_serialize_format_t format, + hb_buffer_serialize_flags_t flags); HB_EXTERN unsigned int hb_buffer_serialize (hb_buffer_t *buffer, - unsigned int start, - unsigned int end, - char *buf, - unsigned int buf_size, - unsigned int *buf_consumed, - hb_font_t *font, - hb_buffer_serialize_format_t format, - hb_buffer_serialize_flags_t flags); + unsigned int start, + unsigned int end, + char *buf, + unsigned int buf_size, + unsigned int *buf_consumed, + hb_font_t *font, + hb_buffer_serialize_format_t format, + hb_buffer_serialize_flags_t flags); HB_EXTERN hb_bool_t hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, @@ -586,10 +666,10 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer, HB_EXTERN hb_bool_t hb_buffer_deserialize_unicode (hb_buffer_t *buffer, - const char *buf, - int buf_len, - const char **end_ptr, - hb_buffer_serialize_format_t format); + const char *buf, + int buf_len, + const char **end_ptr, + hb_buffer_serialize_format_t format); diff --git a/thirdparty/harfbuzz/src/hb-buffer.hh b/thirdparty/harfbuzz/src/hb-buffer.hh index bde28933e4..bc6992905e 100644 --- a/thirdparty/harfbuzz/src/hb-buffer.hh +++ b/thirdparty/harfbuzz/src/hb-buffer.hh @@ -67,8 +67,8 @@ enum hb_buffer_scratch_flags_t { HB_BUFFER_SCRATCH_FLAG_HAS_DEFAULT_IGNORABLES = 0x00000002u, HB_BUFFER_SCRATCH_FLAG_HAS_SPACE_FALLBACK = 0x00000004u, HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT = 0x00000008u, - HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK = 0x00000010u, - HB_BUFFER_SCRATCH_FLAG_HAS_CGJ = 0x00000020u, + HB_BUFFER_SCRATCH_FLAG_HAS_CGJ = 0x00000010u, + HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS = 0x00000020u, /* Reserved for complex shapers' internal use. */ HB_BUFFER_SCRATCH_FLAG_COMPLEX0 = 0x01000000u, @@ -87,18 +87,21 @@ struct hb_buffer_t { hb_object_header_t header; - /* Information about how the text in the buffer should be treated */ + /* + * Information about how the text in the buffer should be treated. + */ + hb_unicode_funcs_t *unicode; /* Unicode functions */ hb_buffer_flags_t flags; /* BOT / EOT / etc. */ hb_buffer_cluster_level_t cluster_level; hb_codepoint_t replacement; /* U+FFFD or something else. */ hb_codepoint_t invisible; /* 0 or something else. */ hb_codepoint_t not_found; /* 0 or something else. */ - hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */ - unsigned int max_len; /* Maximum allowed len. */ - int max_ops; /* Maximum allowed operations. */ - /* Buffer contents */ + /* + * Buffer contents + */ + hb_buffer_content_type_t content_type; hb_segment_properties_t props; /* Script, language, direction */ @@ -115,8 +118,6 @@ struct hb_buffer_t hb_glyph_info_t *out_info; hb_glyph_position_t *pos; - unsigned int serial; - /* Text before / after the main buffer contents. * Always in Unicode, and ordered outward. * Index 0 is for "pre-context", 1 for "post-context". */ @@ -124,7 +125,25 @@ struct hb_buffer_t hb_codepoint_t context[2][CONTEXT_LENGTH]; unsigned int context_len[2]; - /* Debugging API */ + + /* + * Managed by enter / leave + */ + +#ifndef HB_NDEBUG + uint8_t allocated_var_bits; +#endif + uint8_t serial; + hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */ + unsigned int max_len; /* Maximum allowed len. */ + int max_ops; /* Maximum allowed operations. */ + /* The bits here reflect current allocations of the bytes in glyph_info_t's var1 and var2. */ + + + /* + * Messaging callback + */ + #ifndef HB_NO_BUFFER_MESSAGE hb_buffer_message_func_t message_func; void *message_data; @@ -134,11 +153,6 @@ struct hb_buffer_t static constexpr unsigned message_depth = 0u; #endif - /* Internal debugging. */ - /* The bits here reflect current allocations of the bytes in glyph_info_t's var1 and var2. */ -#ifndef HB_NDEBUG - uint8_t allocated_var_bits; -#endif /* Methods */ @@ -190,23 +204,88 @@ struct hb_buffer_t hb_glyph_info_t &prev () { return out_info[out_len ? out_len - 1 : 0]; } hb_glyph_info_t prev () const { return out_info[out_len ? out_len - 1 : 0]; } + HB_INTERNAL void similar (const hb_buffer_t &src); HB_INTERNAL void reset (); HB_INTERNAL void clear (); + /* Called around shape() */ + HB_INTERNAL void enter (); + HB_INTERNAL void leave (); + +#ifndef HB_NO_BUFFER_VERIFY + HB_INTERNAL +#endif + bool verify (hb_buffer_t *text_buffer, + hb_font_t *font, + const hb_feature_t *features, + unsigned int num_features, + const char * const *shapers) +#ifndef HB_NO_BUFFER_VERIFY + ; +#else + { return true; } +#endif + unsigned int backtrack_len () const { return have_output ? out_len : idx; } unsigned int lookahead_len () const { return len - idx; } - unsigned int next_serial () { return serial++; } + uint8_t next_serial () { return ++serial ? serial : ++serial; } HB_INTERNAL void add (hb_codepoint_t codepoint, unsigned int cluster); HB_INTERNAL void add_info (const hb_glyph_info_t &glyph_info); - HB_INTERNAL void reverse_range (unsigned int start, unsigned int end); - HB_INTERNAL void reverse (); - HB_INTERNAL void reverse_clusters (); + void reverse_range (unsigned start, unsigned end) + { + hb_array_t<hb_glyph_info_t> (info, len).reverse (start, end); + if (have_positions) + hb_array_t<hb_glyph_position_t> (pos, len).reverse (start, end); + } + void reverse () { reverse_range (0, len); } + + template <typename FuncType> + void reverse_groups (const FuncType& group, + bool merge_clusters = false) + { + if (unlikely (!len)) + return; + + unsigned start = 0; + unsigned i; + for (i = 1; i < len; i++) + { + if (!group (info[i - 1], info[i])) + { + if (merge_clusters) + this->merge_clusters (start, i); + reverse_range (start, i); + start = i; + } + } + if (merge_clusters) + this->merge_clusters (start, i); + reverse_range (start, i); + + reverse (); + } + + template <typename FuncType> + unsigned group_end (unsigned start, const FuncType& group) const + { + while (++start < len && group (info[start - 1], info[start])) + ; + + return start; + } + + static bool _cluster_group_func (const hb_glyph_info_t& a, + const hb_glyph_info_t& b) + { return a.cluster == b.cluster; } + + void reverse_clusters () { reverse_groups (_cluster_group_func); } + HB_INTERNAL void guess_segment_properties (); - HB_INTERNAL void swap_buffers (); + HB_INTERNAL void sync (); HB_INTERNAL void clear_output (); HB_INTERNAL void clear_positions (); @@ -320,15 +399,87 @@ struct hb_buffer_t /* Merge clusters for deleting current glyph, and skip it. */ HB_INTERNAL void delete_glyph (); - void unsafe_to_break (unsigned int start, - unsigned int end) + + /* Adds glyph flags in mask to infos with clusters between start and end. + * The start index will be from out-buffer if from_out_buffer is true. + * If interior is true, then the cluster having the minimum value is skipped. */ + void _set_glyph_flags (hb_mask_t mask, + unsigned start = 0, + unsigned end = (unsigned) -1, + bool interior = false, + bool from_out_buffer = false) { - if (end - start < 2) + end = hb_min (end, len); + + if (interior && !from_out_buffer && end - start < 2) return; - unsafe_to_break_impl (start, end); + + scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS; + + if (!from_out_buffer || !have_output) + { + if (!interior) + { + for (unsigned i = start; i < end; i++) + info[i].mask |= mask; + } + else + { + unsigned cluster = _infos_find_min_cluster (info, start, end); + _infos_set_glyph_flags (info, start, end, cluster, mask); + } + } + else + { + assert (start <= out_len); + assert (idx <= end); + + if (!interior) + { + for (unsigned i = start; i < out_len; i++) + out_info[i].mask |= mask; + for (unsigned i = idx; i < end; i++) + info[i].mask |= mask; + } + else + { + unsigned cluster = _infos_find_min_cluster (info, idx, end); + cluster = _infos_find_min_cluster (out_info, start, out_len, cluster); + + _infos_set_glyph_flags (out_info, start, out_len, cluster, mask); + _infos_set_glyph_flags (info, idx, end, cluster, mask); + } + } + } + + void unsafe_to_break (unsigned int start = 0, unsigned int end = -1) + { + _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_BREAK | HB_GLYPH_FLAG_UNSAFE_TO_CONCAT, + start, end, + true); + } + void unsafe_to_concat (unsigned int start = 0, unsigned int end = -1) + { + if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0)) + return; + _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_CONCAT, + start, end, + true); + } + void unsafe_to_break_from_outbuffer (unsigned int start = 0, unsigned int end = -1) + { + _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_BREAK | HB_GLYPH_FLAG_UNSAFE_TO_CONCAT, + start, end, + true, true); + } + void unsafe_to_concat_from_outbuffer (unsigned int start = 0, unsigned int end = -1) + { + if (likely ((flags & HB_BUFFER_FLAG_PRODUCE_UNSAFE_TO_CONCAT) == 0)) + return; + _set_glyph_flags (HB_GLYPH_FLAG_UNSAFE_TO_CONCAT, + start, end, + false, true); } - HB_INTERNAL void unsafe_to_break_impl (unsigned int start, unsigned int end); - HB_INTERNAL void unsafe_to_break_from_outbuffer (unsigned int start, unsigned int end); /* Internal methods */ @@ -419,67 +570,50 @@ struct hb_buffer_t set_cluster (hb_glyph_info_t &inf, unsigned int cluster, unsigned int mask = 0) { if (inf.cluster != cluster) - { - if (mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK) - inf.mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK; - else - inf.mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_BREAK; - } + inf.mask = (inf.mask & ~HB_GLYPH_FLAG_DEFINED) | (mask & HB_GLYPH_FLAG_DEFINED); inf.cluster = cluster; } - - unsigned int - _unsafe_to_break_find_min_cluster (const hb_glyph_info_t *infos, - unsigned int start, unsigned int end, - unsigned int cluster) const - { - for (unsigned int i = start; i < end; i++) - cluster = hb_min (cluster, infos[i].cluster); - return cluster; - } void - _unsafe_to_break_set_mask (hb_glyph_info_t *infos, - unsigned int start, unsigned int end, - unsigned int cluster) + _infos_set_glyph_flags (hb_glyph_info_t *infos, + unsigned int start, unsigned int end, + unsigned int cluster, + hb_mask_t mask) { for (unsigned int i = start; i < end; i++) if (cluster != infos[i].cluster) { - scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK; - infos[i].mask |= HB_GLYPH_FLAG_UNSAFE_TO_BREAK; + scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS; + infos[i].mask |= mask; } } + static unsigned + _infos_find_min_cluster (const hb_glyph_info_t *infos, + unsigned start, unsigned end, + unsigned cluster = UINT_MAX) + { + for (unsigned int i = start; i < end; i++) + cluster = hb_min (cluster, infos[i].cluster); + return cluster; + } - void unsafe_to_break_all () { unsafe_to_break_impl (0, len); } - void safe_to_break_all () + void clear_glyph_flags (hb_mask_t mask = 0) { for (unsigned int i = 0; i < len; i++) - info[i].mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_BREAK; + info[i].mask = (info[i].mask & ~HB_GLYPH_FLAG_DEFINED) | (mask & HB_GLYPH_FLAG_DEFINED); } }; DECLARE_NULL_INSTANCE (hb_buffer_t); -/* Loop over clusters. Duplicated in foreach_syllable(). */ -#define foreach_cluster(buffer, start, end) \ +#define foreach_group(buffer, start, end, group_func) \ for (unsigned int \ _count = buffer->len, \ - start = 0, end = _count ? _next_cluster (buffer, 0) : 0; \ + start = 0, end = _count ? buffer->group_end (0, group_func) : 0; \ start < _count; \ - start = end, end = _next_cluster (buffer, start)) - -static inline unsigned int -_next_cluster (hb_buffer_t *buffer, unsigned int start) -{ - hb_glyph_info_t *info = buffer->info; - unsigned int count = buffer->len; - - unsigned int cluster = info[start].cluster; - while (++start < count && cluster == info[start].cluster) - ; + start = end, end = buffer->group_end (start, group_func)) - return start; -} +#define foreach_cluster(buffer, start, end) \ + foreach_group (buffer, start, end, hb_buffer_t::_cluster_group_func) #define HB_BUFFER_XALLOCATE_VAR(b, func, var) \ diff --git a/thirdparty/harfbuzz/src/hb-cff-interp-common.hh b/thirdparty/harfbuzz/src/hb-cff-interp-common.hh index c251e2d0ed..641de0eff2 100644 --- a/thirdparty/harfbuzz/src/hb-cff-interp-common.hh +++ b/thirdparty/harfbuzz/src/hb-cff-interp-common.hh @@ -217,9 +217,6 @@ inline unsigned int OpCode_Size (op_code_t op) { return Is_OpCode_ESC (op) ? 2: struct number_t { - void init () { set_real (0.0); } - void fini () {} - void set_int (int v) { value = v; } int to_int () const { return value; } @@ -245,7 +242,7 @@ struct number_t } protected: - double value; + double value = 0.; }; /* byte string */ @@ -380,10 +377,8 @@ struct cff_stack_t count = 0; elements.init (); elements.resize (kSizeLimit); - for (unsigned int i = 0; i < elements.length; i++) - elements[i].init (); } - void fini () { elements.fini_deep (); } + void fini () { elements.fini (); } ELEM& operator [] (unsigned int i) { @@ -523,9 +518,6 @@ struct arg_stack_t : cff_stack_t<ARG, 513> /* an operator prefixed by its operands in a byte string */ struct op_str_t { - void init () {} - void fini () {} - op_code_t op; byte_str_t str; }; @@ -553,7 +545,7 @@ struct parsed_values_t opStart = 0; values.init (); } - void fini () { values.fini_deep (); } + void fini () { values.fini (); } void add_op (op_code_t op, const byte_str_ref_t& str_ref = byte_str_ref_t ()) { diff --git a/thirdparty/harfbuzz/src/hb-cff-interp-cs-common.hh b/thirdparty/harfbuzz/src/hb-cff-interp-cs-common.hh index 52d778ffe2..ef299369b5 100644 --- a/thirdparty/harfbuzz/src/hb-cff-interp-cs-common.hh +++ b/thirdparty/harfbuzz/src/hb-cff-interp-cs-common.hh @@ -94,12 +94,6 @@ struct biased_subrs_t struct point_t { - void init () - { - x.init (); - y.init (); - } - void set_int (int _x, int _y) { x.set_int (_x); @@ -128,7 +122,7 @@ struct cs_interp_env_t : interp_env_t<ARG> hstem_count = 0; vstem_count = 0; hintmask_size = 0; - pt.init (); + pt.set_int (0, 0); callStack.init (); globalSubrs.init (globalSubrs_); localSubrs.init (localSubrs_); @@ -841,7 +835,6 @@ struct path_procs_t if (likely (env.argStack.get_count () == 11)) { point_t d; - d.init (); for (unsigned int i = 0; i < 10; i += 2) d.move (env.eval_arg (i), env.eval_arg (i+1)); diff --git a/thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh b/thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh index d961566447..766183760e 100644 --- a/thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh +++ b/thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh @@ -35,18 +35,6 @@ using namespace OT; struct blend_arg_t : number_t { - void init () - { - number_t::init (); - deltas.init (); - } - - void fini () - { - number_t::fini (); - deltas.fini_deep (); - } - void set_int (int v) { reset_blends (); number_t::set_int (v); } void set_fixed (int32_t v) { reset_blends (); number_t::set_fixed (v); } void set_real (double v) { reset_blends (); number_t::set_real (v); } @@ -202,7 +190,7 @@ struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PA switch (op) { case OpCode_callsubr: case OpCode_callgsubr: - /* a subroutine number shoudln't be a blended value */ + /* a subroutine number shouldn't be a blended value */ if (unlikely (env.argStack.peek ().blending ())) { env.set_error (); diff --git a/thirdparty/harfbuzz/src/hb-common.cc b/thirdparty/harfbuzz/src/hb-common.cc index 26c8ad0f49..41229b9183 100644 --- a/thirdparty/harfbuzz/src/hb-common.cc +++ b/thirdparty/harfbuzz/src/hb-common.cc @@ -29,10 +29,31 @@ #include "hb.hh" #include "hb-machinery.hh" +#if !defined(HB_NO_SETLOCALE) && (!defined(HAVE_NEWLOCALE) || !defined(HAVE_USELOCALE)) +#define HB_NO_SETLOCALE 1 +#endif + +#ifndef HB_NO_SETLOCALE + #include <locale.h> +#ifdef HAVE_XLOCALE_H +#include <xlocale.h> // Needed on BSD/OS X for uselocale +#endif + +#ifdef WIN32 +#define hb_locale_t _locale_t +#else +#define hb_locale_t locale_t +#endif +#define hb_setlocale setlocale +#define hb_uselocale uselocale + +#else + +#define hb_locale_t void * +#define hb_setlocale(Category, Locale) "C" +#define hb_uselocale(Locale) ((hb_locale_t) 0) -#ifdef HB_NO_SETLOCALE -#define setlocale(Category, Locale) "C" #endif /** @@ -122,7 +143,7 @@ hb_tag_from_string (const char *str, int len) * @tag: #hb_tag_t to convert * @buf: (out caller-allocates) (array fixed-size=4) (element-type uint8_t): Converted string * - * Converts an #hb_tag_t to a string and returns it in @buf. + * Converts an #hb_tag_t to a string and returns it in @buf. * Strings will be four characters long. * * Since: 0.9.5 @@ -151,13 +172,13 @@ const char direction_strings[][4] = { * @str: (array length=len) (element-type uint8_t): String to convert * @len: Length of @str, or -1 if it is %NULL-terminated * - * Converts a string to an #hb_direction_t. + * Converts a string to an #hb_direction_t. * * Matching is loose and applies only to the first letter. For * examples, "LTR" and "left-to-right" will both return #HB_DIRECTION_LTR. * * Unmatched strings will return #HB_DIRECTION_INVALID. - * + * * Return value: The #hb_direction_t matching @str * * Since: 0.9.2 @@ -413,7 +434,7 @@ hb_language_get_default () hb_language_t language = default_language; if (unlikely (language == HB_LANGUAGE_INVALID)) { - language = hb_language_from_string (setlocale (LC_CTYPE, nullptr), -1); + language = hb_language_from_string (hb_setlocale (LC_CTYPE, nullptr), -1); (void) default_language.cmpexch (HB_LANGUAGE_INVALID, language); } @@ -1039,6 +1060,47 @@ hb_variation_from_string (const char *str, int len, return false; } +#ifndef HB_NO_SETLOCALE + +static inline void free_static_C_locale (); + +static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<hb_locale_t>, + hb_C_locale_lazy_loader_t> +{ + static hb_locale_t create () + { + hb_locale_t l = newlocale (LC_ALL_MASK, "C", NULL); + if (!l) + return l; + + hb_atexit (free_static_C_locale); + + return l; + } + static void destroy (hb_locale_t l) + { + freelocale (l); + } + static hb_locale_t get_null () + { + return (hb_locale_t) 0; + } +} static_C_locale; + +static inline +void free_static_C_locale () +{ + static_C_locale.free_instance (); +} + +static hb_locale_t +get_C_locale () +{ + return static_C_locale.get_unconst (); +} + +#endif + /** * hb_variation_to_string: * @variation: an #hb_variation_t to convert @@ -1064,7 +1126,11 @@ hb_variation_to_string (hb_variation_t *variation, while (len && s[len - 1] == ' ') len--; s[len++] = '='; + + hb_locale_t oldlocale HB_UNUSED; + oldlocale = hb_uselocale (get_C_locale ()); len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) variation->value)); + (void) hb_uselocale (oldlocale); assert (len < ARRAY_LENGTH (s)); len = hb_min (len, size - 1); diff --git a/thirdparty/harfbuzz/src/hb-common.h b/thirdparty/harfbuzz/src/hb-common.h index 0384117a4d..7b897a6c51 100644 --- a/thirdparty/harfbuzz/src/hb-common.h +++ b/thirdparty/harfbuzz/src/hb-common.h @@ -130,6 +130,16 @@ typedef union _hb_var_int_t { int8_t i8[4]; } hb_var_int_t; +typedef union _hb_var_num_t { + float f; + uint32_t u32; + int32_t i32; + uint16_t u16[2]; + int16_t i16[2]; + uint8_t u8[4]; + int8_t i8[4]; +} hb_var_num_t; + /* hb_tag_t */ @@ -481,6 +491,7 @@ hb_language_get_default (void); * @HB_SCRIPT_TANGSA: `Tnsa`, Since: 3.0.0 * @HB_SCRIPT_TOTO: `Toto`, Since: 3.0.0 * @HB_SCRIPT_VITHKUQI: `Vith`, Since: 3.0.0 + * @HB_SCRIPT_MATH: `Zmth`, Since: 3.4.0 * @HB_SCRIPT_INVALID: No script set * * Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding @@ -697,6 +708,11 @@ typedef enum HB_SCRIPT_TOTO = HB_TAG ('T','o','t','o'), /*14.0*/ HB_SCRIPT_VITHKUQI = HB_TAG ('V','i','t','h'), /*14.0*/ + /* + * Since 3.4.0 + */ + HB_SCRIPT_MATH = HB_TAG ('Z','m','t','h'), + /* No script set. */ HB_SCRIPT_INVALID = HB_TAG_NONE, diff --git a/thirdparty/harfbuzz/src/hb-config.hh b/thirdparty/harfbuzz/src/hb-config.hh index ad800f0f74..4b46dea938 100644 --- a/thirdparty/harfbuzz/src/hb-config.hh +++ b/thirdparty/harfbuzz/src/hb-config.hh @@ -55,6 +55,7 @@ #define HB_NO_ATEXIT #define HB_NO_BUFFER_MESSAGE #define HB_NO_BUFFER_SERIALIZE +#define HB_NO_BUFFER_VERIFY #define HB_NO_BITMAP #define HB_NO_CFF #define HB_NO_COLOR @@ -84,10 +85,14 @@ #ifdef HB_MINI #define HB_NO_AAT #define HB_NO_LEGACY +#define HB_NO_BORING_EXPANSION #endif -#ifdef HAVE_CONFIG_OVERRIDE_H -#include "config-override.h" +#if defined(HAVE_CONFIG_OVERRIDE_H) || defined(HB_CONFIG_OVERRIDE_H) +#ifndef HB_CONFIG_OVERRIDE_H +#define HB_CONFIG_OVERRIDE_H "config-override.h" +#endif +#include HB_CONFIG_OVERRIDE_H #endif /* Closure of options. */ diff --git a/thirdparty/harfbuzz/src/hb-coretext.cc b/thirdparty/harfbuzz/src/hb-coretext.cc index 4b6c67c1ee..5f383064c4 100644 --- a/thirdparty/harfbuzz/src/hb-coretext.cc +++ b/thirdparty/harfbuzz/src/hb-coretext.cc @@ -481,8 +481,8 @@ struct active_feature_t { a->rec.setting < b->rec.setting ? -1 : a->rec.setting > b->rec.setting ? 1 : 0; } - bool operator== (const active_feature_t *f) { - return cmp (this, f) == 0; + bool operator== (const active_feature_t& f) const { + return cmp (this, &f) == 0; } }; @@ -677,7 +677,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan, { active_features.push (event->feature); } else { - active_feature_t *feature = active_features.find (&event->feature); + active_feature_t *feature = active_features.lsearch (event->feature); if (feature) active_features.remove (feature - active_features.arrayZ); } @@ -1213,7 +1213,8 @@ resize_and_retry: } } - buffer->unsafe_to_break_all (); + buffer->clear_glyph_flags (); + buffer->unsafe_to_break (); #undef FAIL diff --git a/thirdparty/harfbuzz/src/hb-directwrite.cc b/thirdparty/harfbuzz/src/hb-directwrite.cc index db7b53b259..f177ff31c0 100644 --- a/thirdparty/harfbuzz/src/hb-directwrite.cc +++ b/thirdparty/harfbuzz/src/hb-directwrite.cc @@ -43,14 +43,6 @@ * Functions for using HarfBuzz with DirectWrite fonts. **/ -/* Declare object creator for dynamic support of DWRITE */ -typedef HRESULT (* WINAPI t_DWriteCreateFactory)( - DWRITE_FACTORY_TYPE factoryType, - REFIID iid, - IUnknown **factory -); - - /* * DirectWrite font stream helpers */ @@ -145,7 +137,6 @@ public: struct hb_directwrite_face_data_t { - HMODULE dwrite_dll; IDWriteFactory *dwriteFactory; IDWriteFontFile *fontFile; DWriteFontFileStream *fontFileStream; @@ -167,33 +158,12 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face) return nullptr; \ } HB_STMT_END - data->dwrite_dll = LoadLibrary (TEXT ("DWRITE")); - if (unlikely (!data->dwrite_dll)) - FAIL ("Cannot find DWrite.DLL"); - - t_DWriteCreateFactory p_DWriteCreateFactory; - -#if defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-function-type" -#endif - - p_DWriteCreateFactory = (t_DWriteCreateFactory) - GetProcAddress (data->dwrite_dll, "DWriteCreateFactory"); - -#if defined(__GNUC__) -#pragma GCC diagnostic pop -#endif - - if (unlikely (!p_DWriteCreateFactory)) - FAIL ("Cannot find DWriteCreateFactory()."); - HRESULT hr; // TODO: factory and fontFileLoader should be cached separately IDWriteFactory* dwriteFactory; - hr = p_DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory), - (IUnknown**) &dwriteFactory); + hr = DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory), + (IUnknown**) &dwriteFactory); if (unlikely (hr != S_OK)) FAIL ("Failed to run DWriteCreateFactory()."); @@ -257,8 +227,6 @@ _hb_directwrite_shaper_face_data_destroy (hb_directwrite_face_data_t *data) delete data->fontFileStream; if (data->faceBlob) hb_blob_destroy (data->faceBlob); - if (data->dwrite_dll) - FreeLibrary (data->dwrite_dll); if (data) delete data; } @@ -794,6 +762,9 @@ retry_getglyphs: if (isRightToLeft) hb_buffer_reverse (buffer); + buffer->clear_glyph_flags (); + buffer->unsafe_to_break (); + delete [] clusterMap; delete [] glyphIndices; delete [] textProperties; diff --git a/thirdparty/harfbuzz/src/hb-draw.cc b/thirdparty/harfbuzz/src/hb-draw.cc index c0af6ce013..b31019b07e 100644 --- a/thirdparty/harfbuzz/src/hb-draw.cc +++ b/thirdparty/harfbuzz/src/hb-draw.cc @@ -25,237 +25,313 @@ #include "hb.hh" #ifndef HB_NO_DRAW -#ifdef HB_EXPERIMENTAL_API #include "hb-draw.hh" -#include "hb-ot.h" -#include "hb-ot-glyf-table.hh" -#include "hb-ot-cff1-table.hh" -#include "hb-ot-cff2-table.hh" /** - * hb_draw_funcs_set_move_to_func: - * @funcs: draw functions object - * @move_to: move-to callback + * SECTION:hb-draw + * @title: hb-draw + * @short_description: Glyph drawing + * @include: hb.h * - * Sets move-to callback to the draw functions object. - * - * Since: EXPERIMENTAL + * Functions for drawing (extracting) glyph shapes. **/ -void -hb_draw_funcs_set_move_to_func (hb_draw_funcs_t *funcs, - hb_draw_move_to_func_t move_to) + +static void +hb_draw_move_to_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED, + hb_draw_state_t *st HB_UNUSED, + float to_x HB_UNUSED, float to_y HB_UNUSED, + void *user_data HB_UNUSED) {} + +static void +hb_draw_line_to_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED, + hb_draw_state_t *st HB_UNUSED, + float to_x HB_UNUSED, float to_y HB_UNUSED, + void *user_data HB_UNUSED) {} + +static void +hb_draw_quadratic_to_nil (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float control_x, float control_y, + float to_x, float to_y, + void *user_data HB_UNUSED) { - if (unlikely (hb_object_is_immutable (funcs))) return; - funcs->move_to = move_to; + dfuncs->emit_cubic_to (draw_data, *st, + (st->current_x + 2.f * control_x) / 3.f, + (st->current_y + 2.f * control_y) / 3.f, + (to_x + 2.f * control_x) / 3.f, + (to_y + 2.f * control_y) / 3.f, + to_x, to_y); +} + +static void +hb_draw_cubic_to_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED, + hb_draw_state_t *st HB_UNUSED, + float control1_x HB_UNUSED, float control1_y HB_UNUSED, + float control2_x HB_UNUSED, float control2_y HB_UNUSED, + float to_x HB_UNUSED, float to_y HB_UNUSED, + void *user_data HB_UNUSED) {} + +static void +hb_draw_close_path_nil (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data HB_UNUSED, + hb_draw_state_t *st HB_UNUSED, + void *user_data HB_UNUSED) {} + + +#define HB_DRAW_FUNC_IMPLEMENT(name) \ + \ +void \ +hb_draw_funcs_set_##name##_func (hb_draw_funcs_t *dfuncs, \ + hb_draw_##name##_func_t func, \ + void *user_data, \ + hb_destroy_func_t destroy) \ +{ \ + if (hb_object_is_immutable (dfuncs)) \ + return; \ + \ + if (dfuncs->destroy.name) \ + dfuncs->destroy.name (dfuncs->user_data.name); \ + \ + if (func) { \ + dfuncs->func.name = func; \ + dfuncs->user_data.name = user_data; \ + dfuncs->destroy.name = destroy; \ + } else { \ + dfuncs->func.name = hb_draw_##name##_nil; \ + dfuncs->user_data.name = nullptr; \ + dfuncs->destroy.name = nullptr; \ + } \ } +HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_DRAW_FUNC_IMPLEMENT + /** - * hb_draw_funcs_set_line_to_func: - * @funcs: draw functions object - * @line_to: line-to callback + * hb_draw_funcs_create: (Xconstructor) + * + * Creates a new draw callbacks object. * - * Sets line-to callback to the draw functions object. + * Return value: (transfer full): + * A newly allocated #hb_draw_funcs_t with a reference count of 1. The initial + * reference count should be released with hb_draw_funcs_destroy when you are + * done using the #hb_draw_funcs_t. This function never returns %NULL. If + * memory cannot be allocated, a special singleton #hb_draw_funcs_t object will + * be returned. * - * Since: EXPERIMENTAL + * Since: 4.0.0 **/ -void -hb_draw_funcs_set_line_to_func (hb_draw_funcs_t *funcs, - hb_draw_line_to_func_t line_to) +hb_draw_funcs_t * +hb_draw_funcs_create () { - if (unlikely (hb_object_is_immutable (funcs))) return; - funcs->line_to = line_to; + hb_draw_funcs_t *dfuncs; + if (unlikely (!(dfuncs = hb_object_create<hb_draw_funcs_t> ()))) + return const_cast<hb_draw_funcs_t *> (&Null (hb_draw_funcs_t)); + + dfuncs->func = Null (hb_draw_funcs_t).func; + + return dfuncs; } +DEFINE_NULL_INSTANCE (hb_draw_funcs_t) = +{ + HB_OBJECT_HEADER_STATIC, + + { +#define HB_DRAW_FUNC_IMPLEMENT(name) hb_draw_##name##_nil, + HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_DRAW_FUNC_IMPLEMENT + } +}; + + /** - * hb_draw_funcs_set_quadratic_to_func: - * @funcs: draw functions object - * @move_to: quadratic-to callback + * hb_draw_funcs_reference: (skip) + * @dfuncs: draw functions + * + * Increases the reference count on @dfuncs by one. This prevents @buffer from + * being destroyed until a matching call to hb_draw_funcs_destroy() is made. * - * Sets quadratic-to callback to the draw functions object. + * Return value: (transfer full): + * The referenced #hb_draw_funcs_t. * - * Since: EXPERIMENTAL + * Since: 4.0.0 **/ -void -hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t *funcs, - hb_draw_quadratic_to_func_t quadratic_to) +hb_draw_funcs_t * +hb_draw_funcs_reference (hb_draw_funcs_t *dfuncs) { - if (unlikely (hb_object_is_immutable (funcs))) return; - funcs->quadratic_to = quadratic_to; - funcs->is_quadratic_to_set = true; + return hb_object_reference (dfuncs); } /** - * hb_draw_funcs_set_cubic_to_func: - * @funcs: draw functions - * @cubic_to: cubic-to callback + * hb_draw_funcs_destroy: (skip) + * @dfuncs: draw functions * - * Sets cubic-to callback to the draw functions object. + * Deallocate the @dfuncs. + * Decreases the reference count on @dfuncs by one. If the result is zero, then + * @dfuncs and all associated resources are freed. See hb_draw_funcs_reference(). * - * Since: EXPERIMENTAL + * Since: 4.0.0 **/ void -hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t *funcs, - hb_draw_cubic_to_func_t cubic_to) +hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs) { - if (unlikely (hb_object_is_immutable (funcs))) return; - funcs->cubic_to = cubic_to; + if (!hb_object_destroy (dfuncs)) return; + +#define HB_DRAW_FUNC_IMPLEMENT(name) \ + if (dfuncs->destroy.name) dfuncs->destroy.name (dfuncs->user_data.name); + HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_DRAW_FUNC_IMPLEMENT + + + hb_free (dfuncs); } /** - * hb_draw_funcs_set_close_path_func: - * @funcs: draw functions object - * @close_path: close-path callback + * hb_draw_funcs_make_immutable: + * @dfuncs: draw functions * - * Sets close-path callback to the draw functions object. + * Makes @dfuncs object immutable. * - * Since: EXPERIMENTAL + * Since: 4.0.0 **/ void -hb_draw_funcs_set_close_path_func (hb_draw_funcs_t *funcs, - hb_draw_close_path_func_t close_path) +hb_draw_funcs_make_immutable (hb_draw_funcs_t *dfuncs) { - if (unlikely (hb_object_is_immutable (funcs))) return; - funcs->close_path = close_path; -} - -static void -_move_to_nil (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {} - -static void -_line_to_nil (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {} - -static void -_quadratic_to_nil (hb_position_t control_x HB_UNUSED, hb_position_t control_y HB_UNUSED, - hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, - void *user_data HB_UNUSED) {} - -static void -_cubic_to_nil (hb_position_t control1_x HB_UNUSED, hb_position_t control1_y HB_UNUSED, - hb_position_t control2_x HB_UNUSED, hb_position_t control2_y HB_UNUSED, - hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, - void *user_data HB_UNUSED) {} + if (hb_object_is_immutable (dfuncs)) + return; -static void -_close_path_nil (void *user_data HB_UNUSED) {} + hb_object_make_immutable (dfuncs); +} /** - * hb_draw_funcs_create: + * hb_draw_funcs_is_immutable: + * @dfuncs: draw functions * - * Creates a new draw callbacks object. + * Checks whether @dfuncs is immutable. + * + * Return value: %true if @dfuncs is immutable, %false otherwise * - * Since: EXPERIMENTAL + * Since: 4.0.0 **/ -hb_draw_funcs_t * -hb_draw_funcs_create () +hb_bool_t +hb_draw_funcs_is_immutable (hb_draw_funcs_t *dfuncs) { - hb_draw_funcs_t *funcs; - if (unlikely (!(funcs = hb_object_create<hb_draw_funcs_t> ()))) - return const_cast<hb_draw_funcs_t *> (&Null (hb_draw_funcs_t)); - - funcs->move_to = (hb_draw_move_to_func_t) _move_to_nil; - funcs->line_to = (hb_draw_line_to_func_t) _line_to_nil; - funcs->quadratic_to = (hb_draw_quadratic_to_func_t) _quadratic_to_nil; - funcs->is_quadratic_to_set = false; - funcs->cubic_to = (hb_draw_cubic_to_func_t) _cubic_to_nil; - funcs->close_path = (hb_draw_close_path_func_t) _close_path_nil; - return funcs; + return hb_object_is_immutable (dfuncs); } + /** - * hb_draw_funcs_reference: - * @funcs: draw functions + * hb_draw_move_to: + * @dfuncs: draw functions + * @draw_data: associated draw data passed by the caller + * @st: current draw state + * @to_x: X component of target point + * @to_y: Y component of target point * - * Add to callbacks object refcount. + * Perform a "move-to" draw operation. * - * Returns: The same object. - * Since: EXPERIMENTAL + * Since: 4.0.0 **/ -hb_draw_funcs_t * -hb_draw_funcs_reference (hb_draw_funcs_t *funcs) +void +hb_draw_move_to (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float to_x, float to_y) { - return hb_object_reference (funcs); + dfuncs->move_to (draw_data, *st, + to_x, to_y); } /** - * hb_draw_funcs_destroy: - * @funcs: draw functions + * hb_draw_line_to: + * @dfuncs: draw functions + * @draw_data: associated draw data passed by the caller + * @st: current draw state + * @to_x: X component of target point + * @to_y: Y component of target point * - * Decreases refcount of callbacks object and deletes the object if it reaches - * to zero. + * Perform a "line-to" draw operation. * - * Since: EXPERIMENTAL + * Since: 4.0.0 **/ void -hb_draw_funcs_destroy (hb_draw_funcs_t *funcs) +hb_draw_line_to (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float to_x, float to_y) { - if (!hb_object_destroy (funcs)) return; - - hb_free (funcs); + dfuncs->line_to (draw_data, *st, + to_x, to_y); } /** - * hb_draw_funcs_make_immutable: - * @funcs: draw functions + * hb_draw_quadratic_to: + * @dfuncs: draw functions + * @draw_data: associated draw data passed by the caller + * @st: current draw state + * @control_x: X component of control point + * @control_y: Y component of control point + * @to_x: X component of target point + * @to_y: Y component of target point * - * Makes funcs object immutable. + * Perform a "quadratic-to" draw operation. * - * Since: EXPERIMENTAL + * Since: 4.0.0 **/ void -hb_draw_funcs_make_immutable (hb_draw_funcs_t *funcs) +hb_draw_quadratic_to (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float control_x, float control_y, + float to_x, float to_y) { - if (hb_object_is_immutable (funcs)) - return; - - hb_object_make_immutable (funcs); + dfuncs->quadratic_to (draw_data, *st, + control_x, control_y, + to_x, to_y); } /** - * hb_draw_funcs_is_immutable: - * @funcs: draw functions + * hb_draw_cubic_to: + * @dfuncs: draw functions + * @draw_data: associated draw data passed by the caller + * @st: current draw state + * @control1_x: X component of first control point + * @control1_y: Y component of first control point + * @control2_x: X component of second control point + * @control2_y: Y component of second control point + * @to_x: X component of target point + * @to_y: Y component of target point * - * Checks whether funcs is immutable. + * Perform a "cubic-to" draw operation. * - * Returns: If is immutable. - * Since: EXPERIMENTAL + * Since: 4.0.0 **/ -hb_bool_t -hb_draw_funcs_is_immutable (hb_draw_funcs_t *funcs) +void +hb_draw_cubic_to (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float control1_x, float control1_y, + float control2_x, float control2_y, + float to_x, float to_y) { - return hb_object_is_immutable (funcs); + dfuncs->cubic_to (draw_data, *st, + control1_x, control1_y, + control2_x, control2_y, + to_x, to_y); } /** - * hb_font_draw_glyph: - * @font: a font object - * @glyph: a glyph id - * @funcs: draw callbacks object - * @user_data: parameter you like be passed to the callbacks when are called + * hb_draw_close_path: + * @dfuncs: draw functions + * @draw_data: associated draw data passed by the caller + * @st: current draw state * - * Draw a glyph. + * Perform a "close-path" draw operation. * - * Returns: Whether the font had the glyph and the operation completed successfully. - * Since: EXPERIMENTAL + * Since: 4.0.0 **/ -hb_bool_t -hb_font_draw_glyph (hb_font_t *font, hb_codepoint_t glyph, - const hb_draw_funcs_t *funcs, - void *user_data) +void +hb_draw_close_path (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st) { - if (unlikely (funcs == &Null (hb_draw_funcs_t) || - glyph >= font->face->get_num_glyphs ())) - return false; - - draw_helper_t draw_helper (funcs, user_data); - if (font->face->table.glyf->get_path (font, glyph, draw_helper)) return true; -#ifndef HB_NO_CFF - if (font->face->table.cff1->get_path (font, glyph, draw_helper)) return true; - if (font->face->table.cff2->get_path (font, glyph, draw_helper)) return true; -#endif - - return false; + dfuncs->close_path (draw_data, *st); } -#endif + #endif diff --git a/thirdparty/harfbuzz/src/hb-draw.h b/thirdparty/harfbuzz/src/hb-draw.h index bddc876399..c45a53212a 100644 --- a/thirdparty/harfbuzz/src/hb-draw.h +++ b/thirdparty/harfbuzz/src/hb-draw.h @@ -33,65 +33,292 @@ HB_BEGIN_DECLS -#ifdef HB_EXPERIMENTAL_API -typedef void (*hb_draw_move_to_func_t) (hb_position_t to_x, hb_position_t to_y, void *user_data); -typedef void (*hb_draw_line_to_func_t) (hb_position_t to_x, hb_position_t to_y, void *user_data); -typedef void (*hb_draw_quadratic_to_func_t) (hb_position_t control_x, hb_position_t control_y, - hb_position_t to_x, hb_position_t to_y, - void *user_data); -typedef void (*hb_draw_cubic_to_func_t) (hb_position_t control1_x, hb_position_t control1_y, - hb_position_t control2_x, hb_position_t control2_y, - hb_position_t to_x, hb_position_t to_y, - void *user_data); -typedef void (*hb_draw_close_path_func_t) (void *user_data); + +/** + * hb_draw_state_t + * @path_open: Whether there is an open path + * @path_start_x: X component of the start of current path + * @path_start_y: Y component of the start of current path + * @current_x: X component of current point + * @current_y: Y component of current point + * + * Current drawing state. + * + * Since: 4.0.0 + **/ +typedef struct hb_draw_state_t { + hb_bool_t path_open; + + float path_start_x; + float path_start_y; + + float current_x; + float current_y; + + /*< private >*/ + hb_var_num_t reserved1; + hb_var_num_t reserved2; + hb_var_num_t reserved3; + hb_var_num_t reserved4; + hb_var_num_t reserved5; + hb_var_num_t reserved6; + hb_var_num_t reserved7; +} hb_draw_state_t; + +/** + * HB_DRAW_STATE_DEFAULT: + * + * The default #hb_draw_state_t at the start of glyph drawing. + */ +#define HB_DRAW_STATE_DEFAULT {0, 0.f, 0.f, 0.f, 0.f, {0.}, {0.}, {0.}} + /** * hb_draw_funcs_t: * * Glyph draw callbacks. * - * _move_to, _line_to and _cubic_to calls are nessecary to be defined but we - * translate _quadratic_to calls to _cubic_to if the callback isn't defined. + * #hb_draw_move_to_func_t, #hb_draw_line_to_func_t and + * #hb_draw_cubic_to_func_t calls are necessary to be defined but we translate + * #hb_draw_quadratic_to_func_t calls to #hb_draw_cubic_to_func_t if the + * callback isn't defined. * - * Since: EXPERIMENTAL + * Since: 4.0.0 **/ + typedef struct hb_draw_funcs_t hb_draw_funcs_t; + +/** + * hb_draw_move_to_func_t: + * @dfuncs: draw functions object + * @draw_data: The data accompanying the draw functions + * @st: current draw state + * @to_x: X component of target point + * @to_y: Y component of target point + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_draw_funcs_t to perform a "move-to" draw + * operation. + * + * Since: 4.0.0 + * + **/ +typedef void (*hb_draw_move_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float to_x, float to_y, + void *user_data); + +/** + * hb_draw_line_to_func_t: + * @dfuncs: draw functions object + * @draw_data: The data accompanying the draw functions + * @st: current draw state + * @to_x: X component of target point + * @to_y: Y component of target point + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_draw_funcs_t to perform a "line-to" draw + * operation. + * + * Since: 4.0.0 + * + **/ +typedef void (*hb_draw_line_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float to_x, float to_y, + void *user_data); + +/** + * hb_draw_quadratic_to_func_t: + * @dfuncs: draw functions object + * @draw_data: The data accompanying the draw functions + * @st: current draw state + * @control_x: X component of control point + * @control_y: Y component of control point + * @to_x: X component of target point + * @to_y: Y component of target point + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_draw_funcs_t to perform a "quadratic-to" draw + * operation. + * + * Since: 4.0.0 + * + **/ +typedef void (*hb_draw_quadratic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float control_x, float control_y, + float to_x, float to_y, + void *user_data); + +/** + * hb_draw_cubic_to_func_t: + * @dfuncs: draw functions object + * @draw_data: The data accompanying the draw functions + * @st: current draw state + * @control1_x: X component of first control point + * @control1_y: Y component of first control point + * @control2_x: X component of second control point + * @control2_y: Y component of second control point + * @to_x: X component of target point + * @to_y: Y component of target point + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_draw_funcs_t to perform a "cubic-to" draw + * operation. + * + * Since: 4.0.0 + * + **/ +typedef void (*hb_draw_cubic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float control1_x, float control1_y, + float control2_x, float control2_y, + float to_x, float to_y, + void *user_data); + +/** + * hb_draw_close_path_func_t: + * @dfuncs: draw functions object + * @draw_data: The data accompanying the draw functions + * @st: current draw state + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_draw_funcs_t to perform a "close-path" draw + * operation. + * + * Since: 4.0.0 + * + **/ +typedef void (*hb_draw_close_path_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + void *user_data); + +/** + * hb_draw_funcs_set_move_to_func: + * @dfuncs: draw functions object + * @func: (closure user_data) (destroy destroy) (scope notified): move-to callback + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore + * + * Sets move-to callback to the draw functions object. + * + * Since: 4.0.0 + **/ HB_EXTERN void -hb_draw_funcs_set_move_to_func (hb_draw_funcs_t *funcs, - hb_draw_move_to_func_t move_to); +hb_draw_funcs_set_move_to_func (hb_draw_funcs_t *dfuncs, + hb_draw_move_to_func_t func, + void *user_data, hb_destroy_func_t destroy); +/** + * hb_draw_funcs_set_line_to_func: + * @dfuncs: draw functions object + * @func: (closure user_data) (destroy destroy) (scope notified): line-to callback + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore + * + * Sets line-to callback to the draw functions object. + * + * Since: 4.0.0 + **/ HB_EXTERN void -hb_draw_funcs_set_line_to_func (hb_draw_funcs_t *funcs, - hb_draw_line_to_func_t line_to); +hb_draw_funcs_set_line_to_func (hb_draw_funcs_t *dfuncs, + hb_draw_line_to_func_t func, + void *user_data, hb_destroy_func_t destroy); +/** + * hb_draw_funcs_set_quadratic_to_func: + * @dfuncs: draw functions object + * @func: (closure user_data) (destroy destroy) (scope notified): quadratic-to callback + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore + * + * Sets quadratic-to callback to the draw functions object. + * + * Since: 4.0.0 + **/ HB_EXTERN void -hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t *funcs, - hb_draw_quadratic_to_func_t quadratic_to); +hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t *dfuncs, + hb_draw_quadratic_to_func_t func, + void *user_data, hb_destroy_func_t destroy); +/** + * hb_draw_funcs_set_cubic_to_func: + * @dfuncs: draw functions + * @func: (closure user_data) (destroy destroy) (scope notified): cubic-to callback + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore + * + * Sets cubic-to callback to the draw functions object. + * + * Since: 4.0.0 + **/ HB_EXTERN void -hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t *funcs, - hb_draw_cubic_to_func_t cubic_to); +hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t *dfuncs, + hb_draw_cubic_to_func_t func, + void *user_data, hb_destroy_func_t destroy); +/** + * hb_draw_funcs_set_close_path_func: + * @dfuncs: draw functions object + * @func: (closure user_data) (destroy destroy) (scope notified): close-path callback + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore + * + * Sets close-path callback to the draw functions object. + * + * Since: 4.0.0 + **/ HB_EXTERN void -hb_draw_funcs_set_close_path_func (hb_draw_funcs_t *funcs, - hb_draw_close_path_func_t close_path); +hb_draw_funcs_set_close_path_func (hb_draw_funcs_t *dfuncs, + hb_draw_close_path_func_t func, + void *user_data, hb_destroy_func_t destroy); + HB_EXTERN hb_draw_funcs_t * hb_draw_funcs_create (void); HB_EXTERN hb_draw_funcs_t * -hb_draw_funcs_reference (hb_draw_funcs_t *funcs); +hb_draw_funcs_reference (hb_draw_funcs_t *dfuncs); HB_EXTERN void -hb_draw_funcs_destroy (hb_draw_funcs_t *funcs); +hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs); HB_EXTERN void -hb_draw_funcs_make_immutable (hb_draw_funcs_t *funcs); +hb_draw_funcs_make_immutable (hb_draw_funcs_t *dfuncs); HB_EXTERN hb_bool_t -hb_draw_funcs_is_immutable (hb_draw_funcs_t *funcs); -#endif +hb_draw_funcs_is_immutable (hb_draw_funcs_t *dfuncs); + + +HB_EXTERN void +hb_draw_move_to (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float to_x, float to_y); + +HB_EXTERN void +hb_draw_line_to (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float to_x, float to_y); + +HB_EXTERN void +hb_draw_quadratic_to (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float control_x, float control_y, + float to_x, float to_y); + +HB_EXTERN void +hb_draw_cubic_to (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st, + float control1_x, float control1_y, + float control2_x, float control2_y, + float to_x, float to_y); + +HB_EXTERN void +hb_draw_close_path (hb_draw_funcs_t *dfuncs, void *draw_data, + hb_draw_state_t *st); + HB_END_DECLS diff --git a/thirdparty/harfbuzz/src/hb-draw.hh b/thirdparty/harfbuzz/src/hb-draw.hh index 2aa0a5b4db..28bc9218e1 100644 --- a/thirdparty/harfbuzz/src/hb-draw.hh +++ b/thirdparty/harfbuzz/src/hb-draw.hh @@ -27,113 +27,205 @@ #include "hb.hh" -#ifdef HB_EXPERIMENTAL_API -struct hb_draw_funcs_t -{ - hb_object_header_t header; - hb_draw_move_to_func_t move_to; - hb_draw_line_to_func_t line_to; - hb_draw_quadratic_to_func_t quadratic_to; - bool is_quadratic_to_set; - hb_draw_cubic_to_func_t cubic_to; - hb_draw_close_path_func_t close_path; -}; +/* + * hb_draw_funcs_t + */ + +#define HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS \ + HB_DRAW_FUNC_IMPLEMENT (move_to) \ + HB_DRAW_FUNC_IMPLEMENT (line_to) \ + HB_DRAW_FUNC_IMPLEMENT (quadratic_to) \ + HB_DRAW_FUNC_IMPLEMENT (cubic_to) \ + HB_DRAW_FUNC_IMPLEMENT (close_path) \ + /* ^--- Add new callbacks here */ -struct draw_helper_t +struct hb_draw_funcs_t { - draw_helper_t (const hb_draw_funcs_t *funcs_, void *user_data_) - { - funcs = funcs_; - user_data = user_data_; - path_open = false; - path_start_x = current_x = path_start_y = current_y = 0; - } - ~draw_helper_t () { end_path (); } + hb_object_header_t header; - void move_to (hb_position_t x, hb_position_t y) + struct { +#define HB_DRAW_FUNC_IMPLEMENT(name) hb_draw_##name##_func_t name; + HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_DRAW_FUNC_IMPLEMENT + } func; + + struct { +#define HB_DRAW_FUNC_IMPLEMENT(name) void *name; + HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_DRAW_FUNC_IMPLEMENT + } user_data; + + struct { +#define HB_DRAW_FUNC_IMPLEMENT(name) hb_destroy_func_t name; + HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_DRAW_FUNC_IMPLEMENT + } destroy; + + void emit_move_to (void *draw_data, hb_draw_state_t &st, + float to_x, float to_y) + { func.move_to (this, draw_data, &st, + to_x, to_y, + user_data.move_to); } + void emit_line_to (void *draw_data, hb_draw_state_t &st, + float to_x, float to_y) + { func.line_to (this, draw_data, &st, + to_x, to_y, + user_data.line_to); } + void emit_quadratic_to (void *draw_data, hb_draw_state_t &st, + float control_x, float control_y, + float to_x, float to_y) + { func.quadratic_to (this, draw_data, &st, + control_x, control_y, + to_x, to_y, + user_data.quadratic_to); } + void emit_cubic_to (void *draw_data, hb_draw_state_t &st, + float control1_x, float control1_y, + float control2_x, float control2_y, + float to_x, float to_y) + { func.cubic_to (this, draw_data, &st, + control1_x, control1_y, + control2_x, control2_y, + to_x, to_y, + user_data.cubic_to); } + void emit_close_path (void *draw_data, hb_draw_state_t &st) + { func.close_path (this, draw_data, &st, + user_data.close_path); } + + + void move_to (void *draw_data, hb_draw_state_t &st, + float to_x, float to_y) { - if (path_open) end_path (); - current_x = path_start_x = x; - current_y = path_start_y = y; + if (st.path_open) close_path (draw_data, st); + st.current_x = to_x; + st.current_y = to_y; } - void line_to (hb_position_t x, hb_position_t y) + void line_to (void *draw_data, hb_draw_state_t &st, + float to_x, float to_y) { - if (equal_to_current (x, y)) return; - if (!path_open) start_path (); - funcs->line_to (x, y, user_data); - current_x = x; - current_y = y; + if (!st.path_open) start_path (draw_data, st); + emit_line_to (draw_data, st, to_x, to_y); + st.current_x = to_x; + st.current_y = to_y; } void - quadratic_to (hb_position_t control_x, hb_position_t control_y, - hb_position_t to_x, hb_position_t to_y) + quadratic_to (void *draw_data, hb_draw_state_t &st, + float control_x, float control_y, + float to_x, float to_y) { - if (equal_to_current (control_x, control_y) && equal_to_current (to_x, to_y)) - return; - if (!path_open) start_path (); - if (funcs->is_quadratic_to_set) - funcs->quadratic_to (control_x, control_y, to_x, to_y, user_data); - else - funcs->cubic_to (roundf ((current_x + 2.f * control_x) / 3.f), - roundf ((current_y + 2.f * control_y) / 3.f), - roundf ((to_x + 2.f * control_x) / 3.f), - roundf ((to_y + 2.f * control_y) / 3.f), - to_x, to_y, user_data); - current_x = to_x; - current_y = to_y; + if (!st.path_open) start_path (draw_data, st); + emit_quadratic_to (draw_data, st, control_x, control_y, to_x, to_y); + st.current_x = to_x; + st.current_y = to_y; } void - cubic_to (hb_position_t control1_x, hb_position_t control1_y, - hb_position_t control2_x, hb_position_t control2_y, - hb_position_t to_x, hb_position_t to_y) + cubic_to (void *draw_data, hb_draw_state_t &st, + float control1_x, float control1_y, + float control2_x, float control2_y, + float to_x, float to_y) { - if (equal_to_current (control1_x, control1_y) && - equal_to_current (control2_x, control2_y) && - equal_to_current (to_x, to_y)) - return; - if (!path_open) start_path (); - funcs->cubic_to (control1_x, control1_y, control2_x, control2_y, to_x, to_y, user_data); - current_x = to_x; - current_y = to_y; + if (!st.path_open) start_path (draw_data, st); + emit_cubic_to (draw_data, st, control1_x, control1_y, control2_x, control2_y, to_x, to_y); + st.current_x = to_x; + st.current_y = to_y; } - void end_path () + void + close_path (void *draw_data, hb_draw_state_t &st) { - if (path_open) + if (st.path_open) { - if ((path_start_x != current_x) || (path_start_y != current_y)) - funcs->line_to (path_start_x, path_start_y, user_data); - funcs->close_path (user_data); + if ((st.path_start_x != st.current_x) || (st.path_start_y != st.current_y)) + emit_line_to (draw_data, st, st.path_start_x, st.path_start_y); + emit_close_path (draw_data, st); } - path_open = false; - path_start_x = current_x = path_start_y = current_y = 0; + st.path_open = false; + st.path_start_x = st.current_x = st.path_start_y = st.current_y = 0; } protected: - bool equal_to_current (hb_position_t x, hb_position_t y) - { return current_x == x && current_y == y; } - void start_path () + void start_path (void *draw_data, hb_draw_state_t &st) { - if (path_open) end_path (); - path_open = true; - funcs->move_to (path_start_x, path_start_y, user_data); + assert (!st.path_open); + emit_move_to (draw_data, st, st.current_x, st.current_y); + st.path_open = true; + st.path_start_x = st.current_x; + st.path_start_y = st.current_y; } +}; +DECLARE_NULL_INSTANCE (hb_draw_funcs_t); - hb_position_t path_start_x; - hb_position_t path_start_y; +struct hb_draw_session_t +{ + hb_draw_session_t (hb_draw_funcs_t *funcs_, void *draw_data_, float slant_ = 0.f) + : slant {slant_}, not_slanted {slant == 0.f}, + funcs {funcs_}, draw_data {draw_data_}, st HB_DRAW_STATE_DEFAULT + {} - hb_position_t current_x; - hb_position_t current_y; + ~hb_draw_session_t () { close_path (); } - bool path_open; - const hb_draw_funcs_t *funcs; - void *user_data; + void move_to (float to_x, float to_y) + { + if (likely (not_slanted)) + funcs->move_to (draw_data, st, + to_x, to_y); + else + funcs->move_to (draw_data, st, + to_x + to_y * slant, to_y); + } + void line_to (float to_x, float to_y) + { + if (likely (not_slanted)) + funcs->line_to (draw_data, st, + to_x, to_y); + else + funcs->line_to (draw_data, st, + to_x + to_y * slant, to_y); + } + void + quadratic_to (float control_x, float control_y, + float to_x, float to_y) + { + if (likely (not_slanted)) + funcs->quadratic_to (draw_data, st, + control_x, control_y, + to_x, to_y); + else + funcs->quadratic_to (draw_data, st, + control_x + control_y * slant, control_y, + to_x + to_y * slant, to_y); + } + void + cubic_to (float control1_x, float control1_y, + float control2_x, float control2_y, + float to_x, float to_y) + { + if (likely (not_slanted)) + funcs->cubic_to (draw_data, st, + control1_x, control1_y, + control2_x, control2_y, + to_x, to_y); + else + funcs->cubic_to (draw_data, st, + control1_x + control1_y * slant, control1_y, + control2_x + control2_y * slant, control2_y, + to_x + to_y * slant, to_y); + } + void close_path () + { + funcs->close_path (draw_data, st); + } + + protected: + float slant; + bool not_slanted; + hb_draw_funcs_t *funcs; + void *draw_data; + hb_draw_state_t st; }; -#endif #endif /* HB_DRAW_HH */ diff --git a/thirdparty/harfbuzz/src/hb-face.cc b/thirdparty/harfbuzz/src/hb-face.cc index 2c0087370c..5365598636 100644 --- a/thirdparty/harfbuzz/src/hb-face.cc +++ b/thirdparty/harfbuzz/src/hb-face.cc @@ -143,7 +143,7 @@ hb_face_create_for_tables (hb_reference_table_func_t reference_table_func, typedef struct hb_face_for_data_closure_t { hb_blob_t *blob; - unsigned int index; + uint16_t index; } hb_face_for_data_closure_t; static hb_face_for_data_closure_t * @@ -156,7 +156,7 @@ _hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index) return nullptr; closure->blob = blob; - closure->index = index; + closure->index = (uint16_t) (index & 0xFFFFu); return closure; } @@ -195,9 +195,19 @@ _hb_face_for_data_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void * @index: The index of the face within @blob * * Constructs a new face object from the specified blob and - * a face index into that blob. This is used for blobs of - * file formats such as Dfont and TTC that can contain more - * than one face. + * a face index into that blob. + * + * The face index is used for blobs of file formats such as TTC and + * and DFont that can contain more than one face. Face indices within + * such collections are zero-based. + * + * <note>Note: If the blob font format is not a collection, @index + * is ignored. Otherwise, only the lower 16-bits of @index are used. + * The unmodified @index can be accessed via hb_face_get_index().</note> + * + * <note>Note: The high 16-bits of @index, if non-zero, are used by + * hb_font_create() to load named-instances in variable fonts. See + * hb_font_create() for details.</note> * * Return value: (transfer full): The new face object * @@ -420,7 +430,8 @@ hb_face_reference_blob (hb_face_t *face) * Assigns the specified face-index to @face. Fails if the * face is immutable. * - * <note>Note: face indices within a collection are zero-based.</note> + * <note>Note: changing the index has no effect on the face itself + * This only changes the value returned by hb_face_get_index().</note> * * Since: 0.9.2 **/ diff --git a/thirdparty/harfbuzz/src/hb-fallback-shape.cc b/thirdparty/harfbuzz/src/hb-fallback-shape.cc index c5b7c2c230..f8524ecc8e 100644 --- a/thirdparty/harfbuzz/src/hb-fallback-shape.cc +++ b/thirdparty/harfbuzz/src/hb-fallback-shape.cc @@ -117,7 +117,7 @@ _hb_fallback_shape (hb_shape_plan_t *shape_plan HB_UNUSED, if (HB_DIRECTION_IS_BACKWARD (direction)) hb_buffer_reverse (buffer); - buffer->safe_to_break_all (); + buffer->clear_glyph_flags (); return true; } diff --git a/thirdparty/harfbuzz/src/hb-font.cc b/thirdparty/harfbuzz/src/hb-font.cc index fa8da96395..db05f017a5 100644 --- a/thirdparty/harfbuzz/src/hb-font.cc +++ b/thirdparty/harfbuzz/src/hb-font.cc @@ -29,6 +29,7 @@ #include "hb.hh" #include "hb-font.hh" +#include "hb-draw.hh" #include "hb-machinery.hh" #include "hb-ot.h" @@ -501,6 +502,136 @@ hb_font_get_glyph_from_name_default (hb_font_t *font, return font->parent->get_glyph_from_name (name, len, glyph); } +static void +hb_font_get_glyph_shape_nil (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, + void *draw_data, + void *user_data HB_UNUSED) +{ +} + + +typedef struct hb_font_get_glyph_shape_default_adaptor_t { + hb_draw_funcs_t *draw_funcs; + void *draw_data; + float x_scale; + float y_scale; +} hb_font_get_glyph_shape_default_adaptor_t; + +static void +hb_draw_move_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, + void *draw_data, + hb_draw_state_t *st, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data; + float x_scale = adaptor->x_scale; + float y_scale = adaptor->y_scale; + + adaptor->draw_funcs->emit_move_to (adaptor->draw_data, *st, + x_scale * to_x, y_scale * to_y); +} + +static void +hb_draw_line_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data, + hb_draw_state_t *st, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data; + float x_scale = adaptor->x_scale; + float y_scale = adaptor->y_scale; + + st->current_x *= x_scale; + st->current_y *= y_scale; + + adaptor->draw_funcs->emit_line_to (adaptor->draw_data, *st, + x_scale * to_x, y_scale * to_y); +} + +static void +hb_draw_quadratic_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data, + hb_draw_state_t *st, + float control_x, float control_y, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data; + float x_scale = adaptor->x_scale; + float y_scale = adaptor->y_scale; + + st->current_x *= x_scale; + st->current_y *= y_scale; + + adaptor->draw_funcs->emit_quadratic_to (adaptor->draw_data, *st, + x_scale * control_x, y_scale * control_y, + x_scale * to_x, y_scale * to_y); +} + +static void +hb_draw_cubic_to_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data, + hb_draw_state_t *st, + float control1_x, float control1_y, + float control2_x, float control2_y, + float to_x, float to_y, + void *user_data HB_UNUSED) +{ + hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data; + float x_scale = adaptor->x_scale; + float y_scale = adaptor->y_scale; + + st->current_x *= x_scale; + st->current_y *= y_scale; + + adaptor->draw_funcs->emit_cubic_to (adaptor->draw_data, *st, + x_scale * control1_x, y_scale * control1_y, + x_scale * control2_x, y_scale * control2_y, + x_scale * to_x, y_scale * to_y); +} + +static void +hb_draw_close_path_default (hb_draw_funcs_t *dfuncs HB_UNUSED, void *draw_data, + hb_draw_state_t *st, + void *user_data HB_UNUSED) +{ + hb_font_get_glyph_shape_default_adaptor_t *adaptor = (hb_font_get_glyph_shape_default_adaptor_t *) draw_data; + + adaptor->draw_funcs->emit_close_path (adaptor->draw_data, *st); +} + +static const hb_draw_funcs_t _hb_draw_funcs_default = { + HB_OBJECT_HEADER_STATIC, + + { +#define HB_DRAW_FUNC_IMPLEMENT(name) hb_draw_##name##_default, + HB_DRAW_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_DRAW_FUNC_IMPLEMENT + } +}; + +static void +hb_font_get_glyph_shape_default (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, + void *draw_data, + void *user_data HB_UNUSED) +{ + hb_font_get_glyph_shape_default_adaptor_t adaptor = { + draw_funcs, + draw_data, + (float) font->x_scale / (float) font->parent->x_scale, + (float) font->y_scale / (float) font->parent->y_scale + }; + + font->parent->get_glyph_shape (glyph, + const_cast<hb_draw_funcs_t *> (&_hb_draw_funcs_default), + &adaptor); +} + DEFINE_NULL_INSTANCE (hb_font_funcs_t) = { HB_OBJECT_HEADER_STATIC, @@ -631,7 +762,7 @@ hb_font_funcs_destroy (hb_font_funcs_t *ffuncs) * @destroy: (nullable): A callback to call when @data is not needed anymore * @replace: Whether to replace an existing data with the same key * - * Attaches a user-data key/data pair to the specified font-functions structure. + * Attaches a user-data key/data pair to the specified font-functions structure. * * Return value: %true if success, %false otherwise * @@ -821,7 +952,7 @@ hb_font_get_glyph (hb_font_t *font, * @glyph: (out): The glyph ID retrieved * * Fetches the nominal glyph ID for a Unicode code point in the - * specified font. + * specified font. * * This version of the function should not be used to fetch glyph IDs * for code points modified by variation selectors. For variation-selector @@ -940,7 +1071,7 @@ hb_font_get_glyph_v_advance (hb_font_t *font, * @advance_stride: The stride between successive advances * * Fetches the advances for a sequence of glyph IDs in the specified - * font, for horizontal text segments. + * font, for horizontal text segments. * * Since: 1.8.6 **/ @@ -964,7 +1095,7 @@ hb_font_get_glyph_h_advances (hb_font_t* font, * @advance_stride: (out): The stride between successive advances * * Fetches the advances for a sequence of glyph IDs in the specified - * font, for vertical text segments. + * font, for vertical text segments. * * Since: 1.8.6 **/ @@ -1168,6 +1299,26 @@ hb_font_get_glyph_from_name (hb_font_t *font, return font->get_glyph_from_name (name, len, glyph); } +/** + * hb_font_get_glyph_shape: + * @font: #hb_font_t to work upon + * @glyph: : The glyph ID + * @dfuncs: #hb_draw_funcs_t to draw to + * @draw_data: User data to pass to draw callbacks + * + * Fetches the glyph shape that corresponds to a glyph in the specified @font. + * The shape is returned by way of calls to the callsbacks of the @dfuncs + * objects, with @draw_data passed to them. + * + * Since: 4.0.0 + **/ +void +hb_font_get_glyph_shape (hb_font_t *font, + hb_codepoint_t glyph, + hb_draw_funcs_t *dfuncs, void *draw_data) +{ + font->get_glyph_shape (glyph, dfuncs, draw_data); +} /* A bit higher-level, and with fallback */ @@ -1190,7 +1341,7 @@ hb_font_get_extents_for_direction (hb_font_t *font, hb_direction_t direction, hb_font_extents_t *extents) { - return font->get_extents_for_direction (direction, extents); + font->get_extents_for_direction (direction, extents); } /** * hb_font_get_glyph_advance_for_direction: @@ -1215,7 +1366,7 @@ hb_font_get_glyph_advance_for_direction (hb_font_t *font, hb_position_t *x, hb_position_t *y) { - return font->get_glyph_advance_for_direction (glyph, direction, x, y); + font->get_glyph_advance_for_direction (glyph, direction, x, y); } /** * hb_font_get_glyph_advances_for_direction: @@ -1278,7 +1429,7 @@ hb_font_get_glyph_origin_for_direction (hb_font_t *font, * @font: #hb_font_t to work upon * @glyph: The glyph ID to query * @direction: The direction of the text segment - * @x: (inout): Input = The original X coordinate + * @x: (inout): Input = The original X coordinate * Output = The X coordinate plus the X-coordinate of the origin * @y: (inout): Input = The original Y coordinate * Output = The Y coordinate plus the Y-coordinate of the origin @@ -1306,7 +1457,7 @@ hb_font_add_glyph_origin_for_direction (hb_font_t *font, * @font: #hb_font_t to work upon * @glyph: The glyph ID to query * @direction: The direction of the text segment - * @x: (inout): Input = The original X coordinate + * @x: (inout): Input = The original X coordinate * Output = The X coordinate minus the X-coordinate of the origin * @y: (inout): Input = The original Y coordinate * Output = The Y coordinate minus the Y-coordinate of the origin @@ -1477,6 +1628,8 @@ DEFINE_NULL_INSTANCE (hb_font_t) = 1000, /* x_scale */ 1000, /* y_scale */ + 0., /* slant */ + 0., /* slant_xy; */ 1<<16, /* x_mult */ 1<<16, /* y_mult */ @@ -1521,6 +1674,13 @@ _hb_font_create (hb_face_t *face) * * Constructs a new font object from the specified face. * + * <note>Note: If @face's index value (as passed to hb_face_create() + * has non-zero top 16-bits, those bits minus one are passed to + * hb_font_set_var_named_instance(), effectively loading a named-instance + * of a variable font, instead of the default-instance. This allows + * specifying which named-instance to load by default when creating the + * face.</note> + * * Return value: (transfer full): The new font object * * Since: 0.9.2 @@ -1535,6 +1695,11 @@ hb_font_create (hb_face_t *face) hb_ot_font_set_funcs (font); #endif +#ifndef HB_NO_VAR + if (face && face->index >> 16) + hb_font_set_var_named_instance (font, (face->index >> 16) - 1); +#endif + return font; } @@ -1578,6 +1743,7 @@ hb_font_create_sub_font (hb_font_t *parent) font->x_scale = parent->x_scale; font->y_scale = parent->y_scale; + font->slant = parent->slant; font->mults_changed (); font->x_ppem = parent->x_ppem; font->y_ppem = parent->y_ppem; @@ -1668,12 +1834,12 @@ hb_font_destroy (hb_font_t *font) /** * hb_font_set_user_data: (skip) * @font: #hb_font_t to work upon - * @key: The user-data key + * @key: The user-data key * @data: A pointer to the user data * @destroy: (nullable): A callback to call when @data is not needed anymore * @replace: Whether to replace an existing data with the same key * - * Attaches a user-data key/data pair to the specified font object. + * Attaches a user-data key/data pair to the specified font object. * * Return value: %true if success, %false otherwise * @@ -1875,7 +2041,7 @@ hb_font_set_funcs (hb_font_t *font, * @font_data: (destroy destroy) (scope notified): Data to attach to @font * @destroy: (nullable): The function to call when @font_data is not needed anymore * - * Replaces the user data attached to a font, updating the font's + * Replaces the user data attached to a font, updating the font's * @destroy callback. * * Since: 0.9.2 @@ -1949,7 +2115,7 @@ hb_font_get_scale (hb_font_t *font, * @x_ppem: Horizontal ppem value to assign * @y_ppem: Vertical ppem value to assign * - * Sets the horizontal and vertical pixels-per-em (ppem) of a font. + * Sets the horizontal and vertical pixels-per-em (ppem) of a font. * * Since: 0.9.2 **/ @@ -1971,7 +2137,7 @@ hb_font_set_ppem (hb_font_t *font, * @x_ppem: (out): Horizontal ppem value * @y_ppem: (out): Vertical ppem value * - * Fetches the horizontal and vertical points-per-em (ppem) of a font. + * Fetches the horizontal and vertical points-per-em (ppem) of a font. * * Since: 0.9.2 **/ @@ -2015,7 +2181,7 @@ hb_font_set_ptem (hb_font_t *font, * * Return value: Point size. A value of zero means "not set." * - * Since: 0.9.2 + * Since: 1.6.0 **/ float hb_font_get_ptem (hb_font_t *font) @@ -2023,6 +2189,53 @@ hb_font_get_ptem (hb_font_t *font) return font->ptem; } +/** + * hb_font_set_synthetic_slant: + * @font: #hb_font_t to work upon + * @slant: synthetic slant value. + * + * Sets the "synthetic slant" of a font. By default is zero. + * Synthetic slant is the graphical skew applied to the font + * at rendering time. + * + * HarfBuzz needs to know this value to adjust shaping results, + * metrics, and style values to match the slanted rendering. + * + * <note>Note: The glyph shape fetched via the + * hb_font_get_glyph_shape() is slanted to reflect this value + * as well.</note> + * + * <note>Note: The slant value is a ratio. For example, a + * 20% slant would be represented as a 0.2 value.</note> + * + * Since: 3.3.0 + **/ +HB_EXTERN void +hb_font_set_synthetic_slant (hb_font_t *font, float slant) +{ + if (hb_object_is_immutable (font)) + return; + + font->slant = slant; + font->mults_changed (); +} + +/** + * hb_font_get_synthetic_slant: + * @font: #hb_font_t to work upon + * + * Fetches the "synthetic slant" of a font. + * + * Return value: Synthetic slant. By default is zero. + * + * Since: 3.3.0 + **/ +HB_EXTERN float +hb_font_get_synthetic_slant (hb_font_t *font) +{ + return font->slant; +} + #ifndef HB_NO_VAR /* * Variations @@ -2036,6 +2249,10 @@ hb_font_get_ptem (hb_font_t *font) * * Applies a list of font-variation settings to a font. * + * Note that this overrides all existing variations set on @font. + * Axes not included in @variations will be effectively set to their + * default values. + * * Since: 1.4.2 */ void @@ -2091,6 +2308,10 @@ hb_font_set_variations (hb_font_t *font, * Applies a list of variation coordinates (in design-space units) * to a font. * + * Note that this overrides all existing variations set on @font. + * Axes not included in @coords will be effectively set to their + * default values. + * * Since: 1.4.2 */ void @@ -2154,6 +2375,10 @@ hb_font_set_var_named_instance (hb_font_t *font, * Applies a list of variation coordinates (in normalized units) * to a font. * + * Note that this overrides all existing variations set on @font. + * Axes not included in @coords will be effectively set to their + * default values. + * * <note>Note: Coordinates should be normalized to 2.14.</note> * * Since: 1.4.2 @@ -2196,14 +2421,19 @@ hb_font_set_var_coords_normalized (hb_font_t *font, /** * hb_font_get_var_coords_normalized: * @font: #hb_font_t to work upon - * @length: Number of coordinates retrieved + * @length: (out): Number of coordinates retrieved * * Fetches the list of normalized variation coordinates currently * set on a font. * + * Note that this returned array may only contain values for some + * (or none) of the axes; omitted axes effectively have zero values. + * * Return value is valid as long as variation coordinates of the font * are not modified. * + * Return value: coordinates array + * * Since: 1.4.2 */ const int * @@ -2216,18 +2446,24 @@ hb_font_get_var_coords_normalized (hb_font_t *font, return font->coords; } -#ifdef HB_EXPERIMENTAL_API /** * hb_font_get_var_coords_design: * @font: #hb_font_t to work upon - * @length: (out): number of coordinates + * @length: (out): Number of coordinates retrieved + * + * Fetches the list of variation coordinates (in design-space units) currently + * set on a font. + * + * Note that this returned array may only contain values for some + * (or none) of the axes; omitted axes effectively have their default + * values. * * Return value is valid as long as variation coordinates of the font * are not modified. * * Return value: coordinates array * - * Since: EXPERIMENTAL + * Since: 3.3.0 */ const float * hb_font_get_var_coords_design (hb_font_t *font, @@ -2239,7 +2475,6 @@ hb_font_get_var_coords_design (hb_font_t *font, return font->design_coords; } #endif -#endif #ifndef HB_DISABLE_DEPRECATED /* diff --git a/thirdparty/harfbuzz/src/hb-font.h b/thirdparty/harfbuzz/src/hb-font.h index 15dc126523..9548857535 100644 --- a/thirdparty/harfbuzz/src/hb-font.h +++ b/thirdparty/harfbuzz/src/hb-font.h @@ -511,6 +511,25 @@ typedef hb_bool_t (*hb_font_get_glyph_from_name_func_t) (hb_font_t *font, void * hb_codepoint_t *glyph, void *user_data); +/** + * hb_font_get_glyph_shape_func_t: + * @font: #hb_font_t to work upon + * @font_data: @font user data pointer + * @glyph: The glyph ID to query + * @draw_funcs: The draw functions to send the shape data to + * @draw_data: The data accompanying the draw functions + * @user_data: User data pointer passed by the caller + * + * A virtual method for the #hb_font_funcs_t of an #hb_font_t object. + * + * Since: 4.0.0 + * + **/ +typedef void (*hb_font_get_glyph_shape_func_t) (hb_font_t *font, void *font_data, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, void *draw_data, + void *user_data); + /* func setters */ @@ -770,6 +789,22 @@ hb_font_funcs_set_glyph_from_name_func (hb_font_funcs_t *ffuncs, hb_font_get_glyph_from_name_func_t func, void *user_data, hb_destroy_func_t destroy); +/** + * hb_font_funcs_set_glyph_shape_func: + * @ffuncs: A font-function structure + * @func: (closure user_data) (destroy destroy) (scope notified): The callback function to assign + * @user_data: Data to pass to @func + * @destroy: (nullable): The function to call when @user_data is not needed anymore + * + * Sets the implementation function for #hb_font_get_glyph_shape_func_t. + * + * Since: 4.0.0 + **/ +HB_EXTERN void +hb_font_funcs_set_glyph_shape_func (hb_font_funcs_t *ffuncs, + hb_font_get_glyph_shape_func_t func, + void *user_data, hb_destroy_func_t destroy); + /* func dispatch */ HB_EXTERN hb_bool_t @@ -850,6 +885,11 @@ hb_font_get_glyph_from_name (hb_font_t *font, const char *name, int len, /* -1 means nul-terminated */ hb_codepoint_t *glyph); +HB_EXTERN void +hb_font_get_glyph_shape (hb_font_t *font, + hb_codepoint_t glyph, + hb_draw_funcs_t *dfuncs, void *draw_data); + /* high-level funcs, with fallback */ @@ -1024,6 +1064,12 @@ HB_EXTERN float hb_font_get_ptem (hb_font_t *font); HB_EXTERN void +hb_font_set_synthetic_slant (hb_font_t *font, float slant); + +HB_EXTERN float +hb_font_get_synthetic_slant (hb_font_t *font); + +HB_EXTERN void hb_font_set_variations (hb_font_t *font, const hb_variation_t *variations, unsigned int variations_length); @@ -1033,11 +1079,9 @@ hb_font_set_var_coords_design (hb_font_t *font, const float *coords, unsigned int coords_length); -#ifdef HB_EXPERIMENTAL_API HB_EXTERN const float * hb_font_get_var_coords_design (hb_font_t *font, unsigned int *length); -#endif HB_EXTERN void hb_font_set_var_coords_normalized (hb_font_t *font, @@ -1052,11 +1096,6 @@ HB_EXTERN void hb_font_set_var_named_instance (hb_font_t *font, unsigned instance_index); -#ifdef HB_EXPERIMENTAL_API -HB_EXTERN hb_bool_t -hb_font_draw_glyph (hb_font_t *font, hb_codepoint_t glyph, - const hb_draw_funcs_t *funcs, void *user_data); -#endif HB_END_DECLS diff --git a/thirdparty/harfbuzz/src/hb-font.hh b/thirdparty/harfbuzz/src/hb-font.hh index 1b7f445e8b..70311b4a85 100644 --- a/thirdparty/harfbuzz/src/hb-font.hh +++ b/thirdparty/harfbuzz/src/hb-font.hh @@ -57,6 +57,7 @@ HB_FONT_FUNC_IMPLEMENT (glyph_contour_point) \ HB_FONT_FUNC_IMPLEMENT (glyph_name) \ HB_FONT_FUNC_IMPLEMENT (glyph_from_name) \ + HB_FONT_FUNC_IMPLEMENT (glyph_shape) \ /* ^--- Add new callbacks here */ struct hb_font_funcs_t @@ -109,6 +110,8 @@ struct hb_font_t int32_t x_scale; int32_t y_scale; + float slant; + float slant_xy; int64_t x_mult; int64_t y_mult; @@ -138,6 +141,8 @@ struct hb_font_t hb_position_t em_scalef_y (float v) { return em_scalef (v, y_scale); } float em_fscale_x (int16_t v) { return em_fscale (v, x_scale); } float em_fscale_y (int16_t v) { return em_fscale (v, y_scale); } + float em_fscalef_x (float v) { return em_fscalef (v, x_scale); } + float em_fscalef_y (float v) { return em_fscalef (v, y_scale); } hb_position_t em_scale_dir (int16_t v, hb_direction_t direction) { return em_mult (v, dir_mult (direction)); } @@ -371,6 +376,15 @@ struct hb_font_t klass->user_data.glyph_from_name); } + void get_glyph_shape (hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, void *draw_data) + { + klass->get.f.glyph_shape (this, user_data, + glyph, + draw_funcs, draw_data, + klass->user_data.glyph_shape); + } + /* A bit higher-level, and with fallback */ @@ -617,12 +631,15 @@ struct hb_font_t signed upem = face->get_upem (); x_mult = ((int64_t) x_scale << 16) / upem; y_mult = ((int64_t) y_scale << 16) / upem; + slant_xy = y_scale ? slant * x_scale / y_scale : 0.f; } hb_position_t em_mult (int16_t v, int64_t mult) { return (hb_position_t) ((v * mult + 32768) >> 16); } hb_position_t em_scalef (float v, int scale) - { return (hb_position_t) roundf (v * scale / face->get_upem ()); } + { return (hb_position_t) roundf (em_fscalef (v, scale)); } + float em_fscalef (float v, int scale) + { return v * scale / face->get_upem (); } float em_fscale (int16_t v, int scale) { return (float) v * scale / face->get_upem (); } }; diff --git a/thirdparty/harfbuzz/src/hb-ft.cc b/thirdparty/harfbuzz/src/hb-ft.cc index 97a2c82e68..40311e1b91 100644 --- a/thirdparty/harfbuzz/src/hb-ft.cc +++ b/thirdparty/harfbuzz/src/hb-ft.cc @@ -33,12 +33,14 @@ #include "hb-ft.h" +#include "hb-draw.hh" #include "hb-font.hh" #include "hb-machinery.hh" #include "hb-cache.hh" #include FT_ADVANCES_H #include FT_MULTIPLE_MASTERS_H +#include FT_OUTLINE_H #include FT_TRUETYPE_TABLES_H @@ -361,6 +363,7 @@ hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data, } } +#ifndef HB_NO_VERTICAL static hb_position_t hb_ft_get_glyph_v_advance (hb_font_t *font, void *font_data, @@ -381,7 +384,9 @@ hb_ft_get_glyph_v_advance (hb_font_t *font, * have a Y growing upward. Hence the extra negation. */ return (-v + (1<<9)) >> 10; } +#endif +#ifndef HB_NO_VERTICAL static hb_bool_t hb_ft_get_glyph_v_origin (hb_font_t *font, void *font_data, @@ -409,6 +414,7 @@ hb_ft_get_glyph_v_origin (hb_font_t *font, return true; } +#endif #ifndef HB_NO_OT_SHAPE_FALLBACK static hb_position_t @@ -561,6 +567,82 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED, return true; } +#ifndef HB_NO_DRAW + +static int +_hb_ft_move_to (const FT_Vector *to, + hb_draw_session_t *drawing) +{ + drawing->move_to (to->x, to->y); + return FT_Err_Ok; +} + +static int +_hb_ft_line_to (const FT_Vector *to, + hb_draw_session_t *drawing) +{ + drawing->line_to (to->x, to->y); + return FT_Err_Ok; +} + +static int +_hb_ft_conic_to (const FT_Vector *control, + const FT_Vector *to, + hb_draw_session_t *drawing) +{ + drawing->quadratic_to (control->x, control->y, + to->x, to->y); + return FT_Err_Ok; +} + +static int +_hb_ft_cubic_to (const FT_Vector *control1, + const FT_Vector *control2, + const FT_Vector *to, + hb_draw_session_t *drawing) +{ + drawing->cubic_to (control1->x, control1->y, + control2->x, control2->y, + to->x, to->y); + return FT_Err_Ok; +} + +static void +hb_ft_get_glyph_shape (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, void *draw_data, + void *user_data HB_UNUSED) +{ + const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data; + hb_lock_t lock (ft_font->lock); + FT_Face ft_face = ft_font->ft_face; + + if (unlikely (FT_Load_Glyph (ft_face, glyph, + FT_LOAD_NO_BITMAP | ft_font->load_flags))) + return; + + if (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE) + return; + + const FT_Outline_Funcs outline_funcs = { + (FT_Outline_MoveToFunc) _hb_ft_move_to, + (FT_Outline_LineToFunc) _hb_ft_line_to, + (FT_Outline_ConicToFunc) _hb_ft_conic_to, + (FT_Outline_CubicToFunc) _hb_ft_cubic_to, + 0, /* shift */ + 0, /* delta */ + }; + + hb_draw_session_t draw_session (draw_funcs, draw_data, font->slant_xy); + + FT_Outline_Decompose (&ft_face->glyph->outline, + &outline_funcs, + &draw_session); +} +#endif + + static inline void free_static_ft_funcs (); static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft_font_funcs_lazy_loader_t> @@ -569,15 +651,20 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft { hb_font_funcs_t *funcs = hb_font_funcs_create (); - hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr); - //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr); hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, nullptr, nullptr); hb_font_funcs_set_nominal_glyphs_func (funcs, hb_ft_get_nominal_glyphs, nullptr, nullptr); hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, nullptr, nullptr); + + hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr); hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ft_get_glyph_h_advances, nullptr, nullptr); - hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr); //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr); + +#ifndef HB_NO_VERTICAL + //hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr); + hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr); hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr); +#endif + #ifndef HB_NO_OT_SHAPE_FALLBACK hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr); #endif @@ -587,6 +674,10 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr); hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, nullptr, nullptr); +#ifndef HB_NO_DRAW + hb_font_funcs_set_glyph_shape_func (funcs, hb_ft_get_glyph_shape, nullptr, nullptr); +#endif + hb_font_funcs_make_immutable (funcs); hb_atexit (free_static_ft_funcs); diff --git a/thirdparty/harfbuzz/src/hb-gobject-structs.cc b/thirdparty/harfbuzz/src/hb-gobject-structs.cc index 540b11f911..ef13f1e966 100644 --- a/thirdparty/harfbuzz/src/hb-gobject-structs.cc +++ b/thirdparty/harfbuzz/src/hb-gobject-structs.cc @@ -90,6 +90,7 @@ hb_gobject_##name##_get_type () \ HB_DEFINE_OBJECT_TYPE (buffer) HB_DEFINE_OBJECT_TYPE (blob) +HB_DEFINE_OBJECT_TYPE (draw_funcs) HB_DEFINE_OBJECT_TYPE (face) HB_DEFINE_OBJECT_TYPE (font) HB_DEFINE_OBJECT_TYPE (font_funcs) diff --git a/thirdparty/harfbuzz/src/hb-gobject-structs.h b/thirdparty/harfbuzz/src/hb-gobject-structs.h index 63467f80df..3914a2431a 100644 --- a/thirdparty/harfbuzz/src/hb-gobject-structs.h +++ b/thirdparty/harfbuzz/src/hb-gobject-structs.h @@ -49,6 +49,10 @@ hb_gobject_buffer_get_type (void); #define HB_GOBJECT_TYPE_BUFFER (hb_gobject_buffer_get_type ()) HB_EXTERN GType +hb_gobject_draw_funcs_get_type (void); +#define HB_GOBJECT_TYPE_DRAW_FUNCS (hb_gobject_draw_funcs_get_type ()) + +HB_EXTERN GType hb_gobject_face_get_type (void); #define HB_GOBJECT_TYPE_FACE (hb_gobject_face_get_type ()) diff --git a/thirdparty/harfbuzz/src/hb-graphite2.cc b/thirdparty/harfbuzz/src/hb-graphite2.cc index 209207f1e5..63dc18b466 100644 --- a/thirdparty/harfbuzz/src/hb-graphite2.cc +++ b/thirdparty/harfbuzz/src/hb-graphite2.cc @@ -439,7 +439,8 @@ _hb_graphite2_shape (hb_shape_plan_t *shape_plan HB_UNUSED, if (feats) gr_featureval_destroy (feats); gr_seg_destroy (seg); - buffer->unsafe_to_break_all (); + buffer->clear_glyph_flags (); + buffer->unsafe_to_break (); return true; } diff --git a/thirdparty/harfbuzz/src/hb-iter.hh b/thirdparty/harfbuzz/src/hb-iter.hh index 87b8ed880d..43a3098f65 100644 --- a/thirdparty/harfbuzz/src/hb-iter.hh +++ b/thirdparty/harfbuzz/src/hb-iter.hh @@ -90,8 +90,8 @@ struct hb_iter_t * it will be returning pointer to temporary rvalue. * TODO Use a wrapper return type to fix for non-reference type. */ template <typename T = item_t, - hb_enable_if (hb_is_reference (T))> - hb_remove_reference<item_t>* operator -> () const { return hb_addressof (**thiz()); } + hb_enable_if (std::is_reference<T>::value)> + hb_remove_reference<item_t>* operator -> () const { return std::addressof (**thiz()); } item_t operator * () const { return thiz()->__item__ (); } item_t operator * () { return thiz()->__item__ (); } item_t operator [] (unsigned i) const { return thiz()->__item_at__ (i); } @@ -289,7 +289,7 @@ struct hb_is_source_of { private: template <typename Iter2 = Iter, - hb_enable_if (hb_is_convertible (typename Iter2::item_t, hb_add_lvalue_reference<hb_add_const<Item>>))> + hb_enable_if (hb_is_convertible (typename Iter2::item_t, hb_add_lvalue_reference<const Item>))> static hb_true_type impl (hb_priority<2>); template <typename Iter2 = Iter> static auto impl (hb_priority<1>) -> decltype (hb_declval (Iter2) >> hb_declval (Item &), hb_true_type ()); @@ -581,6 +581,91 @@ struct } HB_FUNCOBJ (hb_zip); +/* hb_concat() */ + +template <typename A, typename B> +struct hb_concat_iter_t : + hb_iter_t<hb_concat_iter_t<A, B>, typename A::item_t> +{ + hb_concat_iter_t () {} + hb_concat_iter_t (A& a, B& b) : a (a), b (b) {} + hb_concat_iter_t (const A& a, const B& b) : a (a), b (b) {} + + + typedef typename A::item_t __item_t__; + static constexpr bool is_random_access_iterator = + A::is_random_access_iterator && + B::is_random_access_iterator; + static constexpr bool is_sorted_iterator = false; + + __item_t__ __item__ () const + { + if (!a) + return *b; + return *a; + } + + __item_t__ __item_at__ (unsigned i) const + { + unsigned a_len = a.len (); + if (i < a_len) + return a[i]; + return b[i - a_len]; + } + + bool __more__ () const { return bool (a) || bool (b); } + + unsigned __len__ () const { return a.len () + b.len (); } + + void __next__ () + { + if (a) + ++a; + else + ++b; + } + + void __forward__ (unsigned n) + { + if (!n) return; + if (!is_random_access_iterator) { + while (n-- && *this) { + (*this)++; + } + return; + } + + unsigned a_len = a.len (); + if (n > a_len) { + n -= a_len; + a.__forward__ (a_len); + b.__forward__ (n); + } else { + a.__forward__ (n); + } + } + + hb_concat_iter_t __end__ () const { return hb_concat_iter_t (a.end (), b.end ()); } + bool operator != (const hb_concat_iter_t& o) const + { + return a != o.a + || b != o.b; + } + + private: + A a; + B b; +}; +struct +{ HB_PARTIALIZE(2); + template <typename A, typename B, + hb_requires (hb_is_iterable (A) && hb_is_iterable (B))> + hb_concat_iter_t<hb_iter_type<A>, hb_iter_type<B>> + operator () (A&& a, B&& b) const + { return hb_concat_iter_t<hb_iter_type<A>, hb_iter_type<B>> (hb_iter (a), hb_iter (b)); } +} +HB_FUNCOBJ (hb_concat); + /* hb_apply() */ template <typename Appl> diff --git a/thirdparty/harfbuzz/src/hb-kern.hh b/thirdparty/harfbuzz/src/hb-kern.hh index 3f952fe7fc..9ea945caed 100644 --- a/thirdparty/harfbuzz/src/hb-kern.hh +++ b/thirdparty/harfbuzz/src/hb-kern.hh @@ -49,6 +49,10 @@ struct hb_kern_machine_t hb_mask_t kern_mask, bool scale = true) const { + if (!buffer->message (font, "start kern")) + return; + + buffer->unsafe_to_concat (); OT::hb_ot_apply_context_t c (1, font, buffer); c.set_lookup_mask (kern_mask); c.set_lookup_props (OT::LookupFlag::IgnoreMarks); @@ -67,7 +71,8 @@ struct hb_kern_machine_t } skippy_iter.reset (idx, 1); - if (!skippy_iter.next ()) + unsigned unsafe_to; + if (!skippy_iter.next (&unsafe_to)) { idx++; continue; @@ -125,6 +130,8 @@ struct hb_kern_machine_t skip: idx = skippy_iter.idx; } + + (void) buffer->message (font, "end kern"); } const Driver &driver; diff --git a/thirdparty/harfbuzz/src/hb-machinery.hh b/thirdparty/harfbuzz/src/hb-machinery.hh index 010c2570d7..e52a6a4124 100644 --- a/thirdparty/harfbuzz/src/hb-machinery.hh +++ b/thirdparty/harfbuzz/src/hb-machinery.hh @@ -194,7 +194,8 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData> } const Returned * operator -> () const { return get (); } - const Returned & operator * () const { return *get (); } + template <typename U = Returned, hb_enable_if (!hb_is_same (U, void))> + const U & operator * () const { return *get (); } explicit operator bool () const { return get_stored () != Funcs::get_null (); } template <typename C> operator const C * () const { return get (); } @@ -244,19 +245,19 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData> { Stored *p = (Stored *) hb_calloc (1, sizeof (Stored)); if (likely (p)) - p->init (data); + p = new (p) Stored (data); return p; } static Stored *create () { Stored *p = (Stored *) hb_calloc (1, sizeof (Stored)); if (likely (p)) - p->init (); + p = new (p) Stored (); return p; } static void destroy (Stored *p) { - p->fini (); + p->~Stored (); hb_free (p); } @@ -272,14 +273,19 @@ struct hb_face_lazy_loader_t : hb_lazy_loader_t<T, hb_face_lazy_loader_t<T, WheresFace>, hb_face_t, WheresFace> {}; -template <typename T, unsigned int WheresFace> +template <typename T, unsigned int WheresFace, bool core=false> struct hb_table_lazy_loader_t : hb_lazy_loader_t<T, - hb_table_lazy_loader_t<T, WheresFace>, + hb_table_lazy_loader_t<T, WheresFace, core>, hb_face_t, WheresFace, hb_blob_t> { static hb_blob_t *create (hb_face_t *face) - { return hb_sanitize_context_t ().reference_table<T> (face); } + { + auto c = hb_sanitize_context_t (); + if (core) + c.set_num_glyphs (0); // So we don't recurse ad infinitum... + return c.reference_table<T> (face); + } static void destroy (hb_blob_t *p) { hb_blob_destroy (p); } static const hb_blob_t *get_null () diff --git a/thirdparty/harfbuzz/src/hb-map.hh b/thirdparty/harfbuzz/src/hb-map.hh index bb4a0eb5d1..9341637eac 100644 --- a/thirdparty/harfbuzz/src/hb-map.hh +++ b/thirdparty/harfbuzz/src/hb-map.hh @@ -35,13 +35,12 @@ */ template <typename K, typename V, - K kINVALID = hb_is_pointer (K) ? 0 : std::is_signed<K>::value ? hb_int_min (K) : (K) -1, - V vINVALID = hb_is_pointer (V) ? 0 : std::is_signed<V>::value ? hb_int_min (V) : (V) -1> + typename k_invalid_t = K, + typename v_invalid_t = V, + k_invalid_t kINVALID = std::is_pointer<K>::value ? 0 : std::is_signed<K>::value ? hb_int_min (K) : (K) -1, + v_invalid_t vINVALID = std::is_pointer<V>::value ? 0 : std::is_signed<V>::value ? hb_int_min (V) : (V) -1> struct hb_hashmap_t { - static constexpr K INVALID_KEY = kINVALID; - static constexpr V INVALID_VALUE = vINVALID; - hb_hashmap_t () { init (); } ~hb_hashmap_t () { fini (); } @@ -62,22 +61,40 @@ struct hb_hashmap_t hb_copy (o, *this); } - static_assert (std::is_integral<K>::value || hb_is_pointer (K), ""); - static_assert (std::is_integral<V>::value || hb_is_pointer (V), ""); - struct item_t { K key; V value; uint32_t hash; - void clear () { key = kINVALID; value = vINVALID; hash = 0; } + void clear () + { + new (std::addressof (key)) K (); + key = hb_coerce<K> (kINVALID); + new (std::addressof (value)) V (); + value = hb_coerce<V> (vINVALID); + hash = 0; + } bool operator == (const K &o) { return hb_deref (key) == hb_deref (o); } bool operator == (const item_t &o) { return *this == o.key; } - bool is_unused () const { return key == kINVALID; } - bool is_tombstone () const { return key != kINVALID && value == vINVALID; } - bool is_real () const { return key != kINVALID && value != vINVALID; } + bool is_unused () const + { + const K inv = hb_coerce<K> (kINVALID); + return key == inv; + } + bool is_tombstone () const + { + const K kinv = hb_coerce<K> (kINVALID); + const V vinv = hb_coerce<V> (vINVALID); + return key != kinv && value == vinv; + } + bool is_real () const + { + const K kinv = hb_coerce<K> (kINVALID); + const V vinv = hb_coerce<V> (vINVALID); + return key != kinv && value != vinv; + } hb_pair_t<K, V> get_pair() const { return hb_pair_t<K, V> (key, value); } }; @@ -114,8 +131,13 @@ struct hb_hashmap_t } void fini_shallow () { - hb_free (items); - items = nullptr; + if (likely (items)) { + unsigned size = mask + 1; + for (unsigned i = 0; i < size; i++) + items[i].~item_t (); + hb_free (items); + items = nullptr; + } population = occupancy = 0; } void fini () @@ -159,10 +181,15 @@ struct hb_hashmap_t /* Insert back old items. */ if (old_items) for (unsigned int i = 0; i < old_size; i++) + { if (old_items[i].is_real ()) + { set_with_hash (old_items[i].key, old_items[i].hash, std::move (old_items[i].value)); + } + old_items[i].~item_t (); + } hb_free (old_items); @@ -174,22 +201,22 @@ struct hb_hashmap_t V get (K key) const { - if (unlikely (!items)) return vINVALID; + if (unlikely (!items)) return hb_coerce<V> (vINVALID); unsigned int i = bucket_for (key); - return items[i].is_real () && items[i] == key ? items[i].value : vINVALID; + return items[i].is_real () && items[i] == key ? items[i].value : hb_coerce<V> (vINVALID); } - void del (K key) { set (key, vINVALID); } + void del (K key) { set (key, hb_coerce<V> (vINVALID)); } /* Has interface. */ - static constexpr V SENTINEL = vINVALID; typedef V value_t; value_t operator [] (K k) const { return get (k); } bool has (K k, V *vp = nullptr) const { V v = (*this)[k]; if (vp) *vp = v; - return v != SENTINEL; + const V vinv = hb_coerce<V> (vINVALID); + return v != vinv; } /* Projection. */ V operator () (K k) const { return get (k); } @@ -244,11 +271,13 @@ struct hb_hashmap_t bool set_with_hash (K key, uint32_t hash, VV&& value) { if (unlikely (!successful)) return false; - if (unlikely (key == kINVALID)) return true; + const K kinv = hb_coerce<K> (kINVALID); + if (unlikely (key == kinv)) return true; if (unlikely ((occupancy + occupancy / 2) >= mask && !resize ())) return false; unsigned int i = bucket_for_hash (key, hash); - if (value == vINVALID && items[i].key != key) + const V vinv = hb_coerce<V> (vINVALID); + if (value == vinv && items[i].key != key) return true; /* Trying to delete non-existent key. */ if (!items[i].is_unused ()) @@ -348,19 +377,23 @@ struct hb_hashmap_t struct hb_map_t : hb_hashmap_t<hb_codepoint_t, hb_codepoint_t, + hb_codepoint_t, + hb_codepoint_t, HB_MAP_VALUE_INVALID, HB_MAP_VALUE_INVALID> { using hashmap = hb_hashmap_t<hb_codepoint_t, hb_codepoint_t, + hb_codepoint_t, + hb_codepoint_t, HB_MAP_VALUE_INVALID, HB_MAP_VALUE_INVALID>; hb_map_t () = default; ~hb_map_t () = default; - hb_map_t (hb_map_t& o) = default; - hb_map_t& operator= (const hb_map_t& other) = default; - hb_map_t& operator= (hb_map_t&& other) = default; + hb_map_t (hb_map_t&) = default; + hb_map_t& operator= (const hb_map_t&) = default; + hb_map_t& operator= (hb_map_t&&) = default; hb_map_t (std::initializer_list<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> lst) : hashmap (lst) {} template <typename Iterable, hb_requires (hb_is_iterable (Iterable))> diff --git a/thirdparty/harfbuzz/src/hb-meta.hh b/thirdparty/harfbuzz/src/hb-meta.hh index 0ea5774a9f..3fea5d995e 100644 --- a/thirdparty/harfbuzz/src/hb-meta.hh +++ b/thirdparty/harfbuzz/src/hb-meta.hh @@ -29,6 +29,7 @@ #include "hb.hh" +#include <memory> #include <type_traits> #include <utility> @@ -85,30 +86,13 @@ template <> struct hb_priority<0> {}; template <typename T> struct hb_type_identity_t { typedef T type; }; template <typename T> using hb_type_identity = typename hb_type_identity_t<T>::type; -struct -{ - template <typename T> constexpr T* - operator () (T& arg) const - { -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-align" - /* https://en.cppreference.com/w/cpp/memory/addressof */ - return reinterpret_cast<T*> ( - &const_cast<char&> ( - reinterpret_cast<const volatile char&> (arg))); -#pragma GCC diagnostic pop - } -} -HB_FUNCOBJ (hb_addressof); - template <typename T> static inline T hb_declval (); #define hb_declval(T) (hb_declval<T> ()) template <typename T> struct hb_match_const : hb_type_identity_t<T>, hb_false_type {}; template <typename T> struct hb_match_const<const T> : hb_type_identity_t<T>, hb_true_type {}; template <typename T> using hb_remove_const = typename hb_match_const<T>::type; -template <typename T> using hb_add_const = const T; -#define hb_is_const(T) hb_match_const<T>::value + template <typename T> struct hb_match_reference : hb_type_identity_t<T>, hb_false_type {}; template <typename T> struct hb_match_reference<T &> : hb_type_identity_t<T>, hb_true_type {}; template <typename T> struct hb_match_reference<T &&> : hb_type_identity_t<T>, hb_true_type {}; @@ -119,14 +103,13 @@ template <typename T> using hb_add_lvalue_reference = decltype (_hb_try_add_lval template <typename T> auto _hb_try_add_rvalue_reference (hb_priority<1>) -> hb_type_identity<T&&>; template <typename T> auto _hb_try_add_rvalue_reference (hb_priority<0>) -> hb_type_identity<T>; template <typename T> using hb_add_rvalue_reference = decltype (_hb_try_add_rvalue_reference<T> (hb_prioritize)); -#define hb_is_reference(T) hb_match_reference<T>::value + template <typename T> struct hb_match_pointer : hb_type_identity_t<T>, hb_false_type {}; template <typename T> struct hb_match_pointer<T *> : hb_type_identity_t<T>, hb_true_type {}; template <typename T> using hb_remove_pointer = typename hb_match_pointer<T>::type; template <typename T> auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_identity<hb_remove_reference<T>*>; template <typename T> auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_identity<T>; template <typename T> using hb_add_pointer = decltype (_hb_try_add_pointer<T> (hb_prioritize)); -#define hb_is_pointer(T) hb_match_pointer<T>::value /* TODO Add feature-parity to std::decay. */ @@ -137,8 +120,8 @@ template <typename T> using hb_decay = hb_remove_const<hb_remove_reference<T>>; template <typename From, typename To> using hb_is_cr_convertible = hb_bool_constant< hb_is_same (hb_decay<From>, hb_decay<To>) && - (!hb_is_const (From) || hb_is_const (To)) && - (!hb_is_reference (To) || hb_is_const (To) || hb_is_reference (To)) + (!std::is_const<From>::value || std::is_const<To>::value) && + (!std::is_reference<To>::value || std::is_const<To>::value || std::is_reference<To>::value) >; #define hb_is_cr_convertible(From,To) hb_is_cr_convertible<From, To>::value @@ -153,16 +136,6 @@ struct } HB_FUNCOBJ (hb_deref); -struct -{ - template <typename T> constexpr auto - operator () (T&& v) const HB_AUTO_RETURN (std::forward<T> (v)) - - template <typename T> constexpr auto - operator () (T& v) const HB_AUTO_RETURN (hb_addressof (v)) -} -HB_FUNCOBJ (hb_ref); - template <typename T> struct hb_reference_wrapper { @@ -176,7 +149,7 @@ struct hb_reference_wrapper template <typename T> struct hb_reference_wrapper<T&> { - hb_reference_wrapper (T& v) : v (hb_addressof (v)) {} + hb_reference_wrapper (T& v) : v (std::addressof (v)) {} bool operator == (const hb_reference_wrapper& o) const { return v == o.v; } bool operator != (const hb_reference_wrapper& o) const { return v != o.v; } operator T& () const { return *v; } diff --git a/thirdparty/harfbuzz/src/hb-ms-feature-ranges.cc b/thirdparty/harfbuzz/src/hb-ms-feature-ranges.cc deleted file mode 100644 index 6d09b252d8..0000000000 --- a/thirdparty/harfbuzz/src/hb-ms-feature-ranges.cc +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright © 2011,2012,2013 Google, Inc. - * Copyright © 2021 Khaled Hosny - * - * This is part of HarfBuzz, a text shaping library. - * - * Permission is hereby granted, without written agreement and without - * license or royalty fees, to use, copy, modify, and distribute this - * software and its documentation for any purpose, provided that the - * above copyright notice and the following two paragraphs appear in - * all copies of this software. - * - * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR - * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES - * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN - * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH - * DAMAGE. - * - * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND - * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS - * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO - * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. - * - * Google Author(s): Behdad Esfahbod - */ - -#include "hb-ms-feature-ranges.hh" - -bool -hb_ms_setup_features (const hb_feature_t *features, - unsigned int num_features, - hb_vector_t<hb_ms_feature_t> &feature_records, /* OUT */ - hb_vector_t<hb_ms_range_record_t> &range_records /* OUT */) -{ - feature_records.shrink(0); - range_records.shrink(0); - - /* Sort features by start/end events. */ - hb_vector_t<hb_ms_feature_event_t> feature_events; - for (unsigned int i = 0; i < num_features; i++) - { - hb_ms_active_feature_t feature; - feature.fea.tag_le = hb_uint32_swap (features[i].tag); - feature.fea.value = features[i].value; - feature.order = i; - - hb_ms_feature_event_t *event; - - event = feature_events.push (); - event->index = features[i].start; - event->start = true; - event->feature = feature; - - event = feature_events.push (); - event->index = features[i].end; - event->start = false; - event->feature = feature; - } - feature_events.qsort (); - /* Add a strategic final event. */ - { - hb_ms_active_feature_t feature; - feature.fea.tag_le = 0; - feature.fea.value = 0; - feature.order = num_features + 1; - - auto *event = feature_events.push (); - event->index = 0; /* This value does magic. */ - event->start = false; - event->feature = feature; - } - - /* Scan events and save features for each range. */ - hb_vector_t<hb_ms_active_feature_t> active_features; - unsigned int last_index = 0; - for (unsigned int i = 0; i < feature_events.length; i++) - { - auto *event = &feature_events[i]; - - if (event->index != last_index) - { - /* Save a snapshot of active features and the range. */ - auto *range = range_records.push (); - auto offset = feature_records.length; - - active_features.qsort (); - for (unsigned int j = 0; j < active_features.length; j++) - { - if (!j || active_features[j].fea.tag_le != feature_records[feature_records.length - 1].tag_le) - { - feature_records.push (active_features[j].fea); - } - else - { - /* Overrides value for existing feature. */ - feature_records[feature_records.length - 1].value = active_features[j].fea.value; - } - } - - /* Will convert to pointer after all is ready, since feature_records.array - * may move as we grow it. */ - range->features.features = reinterpret_cast<hb_ms_feature_t *> (offset); - range->features.num_features = feature_records.length - offset; - range->index_first = last_index; - range->index_last = event->index - 1; - - last_index = event->index; - } - - if (event->start) - { - active_features.push (event->feature); - } - else - { - auto *feature = active_features.find (&event->feature); - if (feature) - active_features.remove (feature - active_features.arrayZ); - } - } - - if (!range_records.length) /* No active feature found. */ - num_features = 0; - - /* Fixup the pointers. */ - for (unsigned int i = 0; i < range_records.length; i++) - { - auto *range = &range_records[i]; - range->features.features = (hb_ms_feature_t *) feature_records + reinterpret_cast<uintptr_t> (range->features.features); - } - - return !!num_features; -} - -void -hb_ms_make_feature_ranges (hb_vector_t<hb_ms_feature_t> &feature_records, - hb_vector_t<hb_ms_range_record_t> &range_records, - unsigned int chars_offset, - unsigned int chars_len, - uint16_t *log_clusters, - hb_vector_t<hb_ms_features_t*> &range_features, /* OUT */ - hb_vector_t<uint32_t> &range_counts /* OUT */) -{ - range_features.shrink (0); - range_counts.shrink (0); - - auto *last_range = &range_records[0]; - for (unsigned int i = chars_offset; i < chars_len; i++) - { - auto *range = last_range; - while (log_clusters[i] < range->index_first) - range--; - while (log_clusters[i] > range->index_last) - range++; - if (!range_features.length || - &range->features != range_features[range_features.length - 1]) - { - auto **features = range_features.push (); - auto *c = range_counts.push (); - if (unlikely (!features || !c)) - { - range_features.shrink (0); - range_counts.shrink (0); - break; - } - *features = &range->features; - *c = 1; - } - else - { - range_counts[range_counts.length - 1]++; - } - - last_range = range; - } -} diff --git a/thirdparty/harfbuzz/src/hb-ms-feature-ranges.hh b/thirdparty/harfbuzz/src/hb-ms-feature-ranges.hh index 401d1e1d97..d40fdeaa82 100644 --- a/thirdparty/harfbuzz/src/hb-ms-feature-ranges.hh +++ b/thirdparty/harfbuzz/src/hb-ms-feature-ranges.hh @@ -52,8 +52,8 @@ struct hb_ms_active_feature_t { a->fea.value < b->fea.value ? -1 : a->fea.value > b->fea.value ? 1 : 0; } - bool operator== (const hb_ms_active_feature_t *f) - { return cmp (this, f) == 0; } + bool operator== (const hb_ms_active_feature_t& f) const + { return cmp (this, &f) == 0; } }; struct hb_ms_feature_event_t { @@ -77,20 +77,153 @@ struct hb_ms_range_record_t { unsigned int index_last; /* == end - 1 */ }; -HB_INTERNAL bool +static inline bool hb_ms_setup_features (const hb_feature_t *features, unsigned int num_features, hb_vector_t<hb_ms_feature_t> &feature_records, /* OUT */ - hb_vector_t<hb_ms_range_record_t> &range_records /* OUT */); + hb_vector_t<hb_ms_range_record_t> &range_records /* OUT */) +{ + feature_records.shrink(0); + range_records.shrink(0); + /* Sort features by start/end events. */ + hb_vector_t<hb_ms_feature_event_t> feature_events; + for (unsigned int i = 0; i < num_features; i++) + { + hb_ms_active_feature_t feature; + feature.fea.tag_le = hb_uint32_swap (features[i].tag); + feature.fea.value = features[i].value; + feature.order = i; + + hb_ms_feature_event_t *event; + + event = feature_events.push (); + event->index = features[i].start; + event->start = true; + event->feature = feature; + + event = feature_events.push (); + event->index = features[i].end; + event->start = false; + event->feature = feature; + } + feature_events.qsort (); + /* Add a strategic final event. */ + { + hb_ms_active_feature_t feature; + feature.fea.tag_le = 0; + feature.fea.value = 0; + feature.order = num_features + 1; + + auto *event = feature_events.push (); + event->index = 0; /* This value does magic. */ + event->start = false; + event->feature = feature; + } + + /* Scan events and save features for each range. */ + hb_vector_t<hb_ms_active_feature_t> active_features; + unsigned int last_index = 0; + for (unsigned int i = 0; i < feature_events.length; i++) + { + auto *event = &feature_events[i]; + + if (event->index != last_index) + { + /* Save a snapshot of active features and the range. */ + auto *range = range_records.push (); + auto offset = feature_records.length; + + active_features.qsort (); + for (unsigned int j = 0; j < active_features.length; j++) + { + if (!j || active_features[j].fea.tag_le != feature_records[feature_records.length - 1].tag_le) + { + feature_records.push (active_features[j].fea); + } + else + { + /* Overrides value for existing feature. */ + feature_records[feature_records.length - 1].value = active_features[j].fea.value; + } + } + + /* Will convert to pointer after all is ready, since feature_records.array + * may move as we grow it. */ + range->features.features = reinterpret_cast<hb_ms_feature_t *> (offset); + range->features.num_features = feature_records.length - offset; + range->index_first = last_index; + range->index_last = event->index - 1; -HB_INTERNAL void + last_index = event->index; + } + + if (event->start) + { + active_features.push (event->feature); + } + else + { + auto *feature = active_features.lsearch (event->feature); + if (feature) + active_features.remove (feature - active_features.arrayZ); + } + } + + if (!range_records.length) /* No active feature found. */ + num_features = 0; + + /* Fixup the pointers. */ + for (unsigned int i = 0; i < range_records.length; i++) + { + auto *range = &range_records[i]; + range->features.features = (hb_ms_feature_t *) feature_records + reinterpret_cast<uintptr_t> (range->features.features); + } + + return !!num_features; +} + +static inline void hb_ms_make_feature_ranges (hb_vector_t<hb_ms_feature_t> &feature_records, hb_vector_t<hb_ms_range_record_t> &range_records, unsigned int chars_offset, unsigned int chars_len, uint16_t *log_clusters, hb_vector_t<hb_ms_features_t*> &range_features, /* OUT */ - hb_vector_t<uint32_t> &range_counts /* OUT */); + hb_vector_t<uint32_t> &range_counts /* OUT */) +{ + range_features.shrink (0); + range_counts.shrink (0); + + auto *last_range = &range_records[0]; + for (unsigned int i = chars_offset; i < chars_len; i++) + { + auto *range = last_range; + while (log_clusters[i] < range->index_first) + range--; + while (log_clusters[i] > range->index_last) + range++; + if (!range_features.length || + &range->features != range_features[range_features.length - 1]) + { + auto **features = range_features.push (); + auto *c = range_counts.push (); + if (unlikely (!features || !c)) + { + range_features.shrink (0); + range_counts.shrink (0); + break; + } + *features = &range->features; + *c = 1; + } + else + { + range_counts[range_counts.length - 1]++; + } + + last_range = range; + } +} #endif /* HB_MS_FEATURE_RANGES_HH */ diff --git a/thirdparty/harfbuzz/src/hb-object.hh b/thirdparty/harfbuzz/src/hb-object.hh index 0e15cb12c4..4b5bc32ade 100644 --- a/thirdparty/harfbuzz/src/hb-object.hh +++ b/thirdparty/harfbuzz/src/hb-object.hh @@ -53,7 +53,7 @@ struct hb_lockable_set_t item_t *replace_or_insert (T v, lock_t &l, bool replace) { l.lock (); - item_t *item = items.find (v); + item_t *item = items.lsearch (v); if (item) { if (replace) { item_t old = *item; @@ -76,7 +76,7 @@ struct hb_lockable_set_t void remove (T v, lock_t &l) { l.lock (); - item_t *item = items.find (v); + item_t *item = items.lsearch (v); if (item) { item_t old = *item; @@ -93,7 +93,7 @@ struct hb_lockable_set_t bool find (T v, item_t *i, lock_t &l) { l.lock (); - item_t *item = items.find (v); + item_t *item = items.lsearch (v); if (item) *i = *item; l.unlock (); diff --git a/thirdparty/harfbuzz/src/hb-ot-cff-common.hh b/thirdparty/harfbuzz/src/hb-ot-cff-common.hh index 180c87cb89..c102c15173 100644 --- a/thirdparty/harfbuzz/src/hb-ot-cff-common.hh +++ b/thirdparty/harfbuzz/src/hb-ot-cff-common.hh @@ -68,8 +68,6 @@ struct code_pair_t typedef hb_vector_t<unsigned char> str_buff_t; struct str_buff_vec_t : hb_vector_t<str_buff_t> { - void fini () { SUPER::fini_deep (); } - unsigned int total_size () const { unsigned int size = 0; diff --git a/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc b/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc index 3298fa35ae..df4554ac00 100644 --- a/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc +++ b/thirdparty/harfbuzz/src/hb-ot-cff1-table.cc @@ -442,13 +442,12 @@ bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph return true; } -#ifdef HB_EXPERIMENTAL_API struct cff1_path_param_t { cff1_path_param_t (const OT::cff1::accelerator_t *cff_, hb_font_t *font_, - draw_helper_t &draw_helper_, point_t *delta_) + hb_draw_session_t &draw_session_, point_t *delta_) { - draw_helper = &draw_helper_; + draw_session = &draw_session_; cff = cff_; font = font_; delta = delta_; @@ -458,14 +457,14 @@ struct cff1_path_param_t { point_t point = p; if (delta) point.move (*delta); - draw_helper->move_to (font->em_scalef_x (point.x.to_real ()), font->em_scalef_y (point.y.to_real ())); + draw_session->move_to (font->em_fscalef_x (point.x.to_real ()), font->em_fscalef_y (point.y.to_real ())); } void line_to (const point_t &p) { point_t point = p; if (delta) point.move (*delta); - draw_helper->line_to (font->em_scalef_x (point.x.to_real ()), font->em_scalef_y (point.y.to_real ())); + draw_session->line_to (font->em_fscalef_x (point.x.to_real ()), font->em_fscalef_y (point.y.to_real ())); } void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3) @@ -477,15 +476,15 @@ struct cff1_path_param_t point2.move (*delta); point3.move (*delta); } - draw_helper->cubic_to (font->em_scalef_x (point1.x.to_real ()), font->em_scalef_y (point1.y.to_real ()), - font->em_scalef_x (point2.x.to_real ()), font->em_scalef_y (point2.y.to_real ()), - font->em_scalef_x (point3.x.to_real ()), font->em_scalef_y (point3.y.to_real ())); + draw_session->cubic_to (font->em_fscalef_x (point1.x.to_real ()), font->em_fscalef_y (point1.y.to_real ()), + font->em_fscalef_x (point2.x.to_real ()), font->em_fscalef_y (point2.y.to_real ()), + font->em_fscalef_x (point3.x.to_real ()), font->em_fscalef_y (point3.y.to_real ())); } - void end_path () { draw_helper->end_path (); } + void end_path () { draw_session->close_path (); } hb_font_t *font; - draw_helper_t *draw_helper; + hb_draw_session_t *draw_session; point_t *delta; const OT::cff1::accelerator_t *cff; @@ -513,7 +512,7 @@ struct cff1_path_procs_path_t : path_procs_t<cff1_path_procs_path_t, cff1_cs_int }; static bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph, - draw_helper_t &draw_helper, bool in_seac = false, point_t *delta = nullptr); + hb_draw_session_t &draw_session, bool in_seac = false, point_t *delta = nullptr); struct cff1_cs_opset_path_t : cff1_cs_opset_t<cff1_cs_opset_path_t, cff1_path_param_t, cff1_path_procs_path_t> { @@ -530,14 +529,14 @@ struct cff1_cs_opset_path_t : cff1_cs_opset_t<cff1_cs_opset_path_t, cff1_path_pa hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ()); if (unlikely (!(!env.in_seac && base && accent - && _get_path (param.cff, param.font, base, *param.draw_helper, true) - && _get_path (param.cff, param.font, accent, *param.draw_helper, true, &delta)))) + && _get_path (param.cff, param.font, base, *param.draw_session, true) + && _get_path (param.cff, param.font, accent, *param.draw_session, true, &delta)))) env.set_error (); } }; bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph, - draw_helper_t &draw_helper, bool in_seac, point_t *delta) + hb_draw_session_t &draw_session, bool in_seac, point_t *delta) { if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false; @@ -546,7 +545,7 @@ bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoin const byte_str_t str = (*cff->charStrings)[glyph]; interp.env.init (str, *cff, fd); interp.env.set_in_seac (in_seac); - cff1_path_param_t param (cff, font, draw_helper, delta); + cff1_path_param_t param (cff, font, draw_session, delta); if (unlikely (!interp.interpret (param))) return false; /* Let's end the path specially since it is called inside seac also */ @@ -555,16 +554,15 @@ bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoin return true; } -bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const +bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const { #ifdef HB_NO_OT_FONT_CFF /* XXX Remove check when this code moves to .hh file. */ return true; #endif - return _get_path (this, font, glyph, draw_helper); + return _get_path (this, font, glyph, draw_session); } -#endif struct get_seac_param_t { diff --git a/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh b/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh index 5dd183e3a0..542e3f4de3 100644 --- a/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-cff1-table.hh @@ -1144,8 +1144,8 @@ struct cff1 { sc.end_processing (); topDict.fini (); - fontDicts.fini_deep (); - privateDicts.fini_deep (); + fontDicts.fini (); + privateDicts.fini (); hb_blob_destroy (blob); blob = nullptr; } @@ -1245,32 +1245,32 @@ struct cff1 } protected: - hb_blob_t *blob; + hb_blob_t *blob = nullptr; hb_sanitize_context_t sc; public: - const Encoding *encoding; - const Charset *charset; - const CFF1NameIndex *nameIndex; - const CFF1TopDictIndex *topDictIndex; - const CFF1StringIndex *stringIndex; - const CFF1Subrs *globalSubrs; - const CFF1CharStrings *charStrings; - const CFF1FDArray *fdArray; - const CFF1FDSelect *fdSelect; - unsigned int fdCount; + const Encoding *encoding = nullptr; + const Charset *charset = nullptr; + const CFF1NameIndex *nameIndex = nullptr; + const CFF1TopDictIndex *topDictIndex = nullptr; + const CFF1StringIndex *stringIndex = nullptr; + const CFF1Subrs *globalSubrs = nullptr; + const CFF1CharStrings *charStrings = nullptr; + const CFF1FDArray *fdArray = nullptr; + const CFF1FDSelect *fdSelect = nullptr; + unsigned int fdCount = 0; cff1_top_dict_values_t topDict; hb_vector_t<cff1_font_dict_values_t> fontDicts; hb_vector_t<PRIVDICTVAL> privateDicts; - unsigned int num_glyphs; + unsigned int num_glyphs = 0; }; struct accelerator_t : accelerator_templ_t<cff1_private_dict_opset_t, cff1_private_dict_values_t> { - void init (hb_face_t *face) + accelerator_t (hb_face_t *face) { SUPER::init (face); @@ -1295,8 +1295,7 @@ struct cff1 } glyph_names.qsort (); } - - void fini () + ~accelerator_t () { glyph_names.fini (); @@ -1348,9 +1347,7 @@ struct cff1 HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const; -#ifdef HB_EXPERIMENTAL_API - HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const; -#endif + HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const; private: struct gname_t @@ -1398,7 +1395,10 @@ struct cff1 DEFINE_SIZE_STATIC (4); }; -struct cff1_accelerator_t : cff1::accelerator_t {}; +struct cff1_accelerator_t : cff1::accelerator_t { + cff1_accelerator_t (hb_face_t *face) : cff1::accelerator_t (face) {} +}; + } /* namespace OT */ #endif /* HB_OT_CFF1_TABLE_HH */ diff --git a/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc b/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc index 879b7cdb23..817fe064ce 100644 --- a/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc +++ b/thirdparty/harfbuzz/src/hb-ot-cff2-table.cc @@ -143,30 +143,29 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font, return true; } -#ifdef HB_EXPERIMENTAL_API struct cff2_path_param_t { - cff2_path_param_t (hb_font_t *font_, draw_helper_t &draw_helper_) + cff2_path_param_t (hb_font_t *font_, hb_draw_session_t &draw_session_) { - draw_helper = &draw_helper_; + draw_session = &draw_session_; font = font_; } void move_to (const point_t &p) - { draw_helper->move_to (font->em_scalef_x (p.x.to_real ()), font->em_scalef_y (p.y.to_real ())); } + { draw_session->move_to (font->em_fscalef_x (p.x.to_real ()), font->em_fscalef_y (p.y.to_real ())); } void line_to (const point_t &p) - { draw_helper->line_to (font->em_scalef_x (p.x.to_real ()), font->em_scalef_y (p.y.to_real ())); } + { draw_session->line_to (font->em_fscalef_x (p.x.to_real ()), font->em_fscalef_y (p.y.to_real ())); } void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3) { - draw_helper->cubic_to (font->em_scalef_x (p1.x.to_real ()), font->em_scalef_y (p1.y.to_real ()), - font->em_scalef_x (p2.x.to_real ()), font->em_scalef_y (p2.y.to_real ()), - font->em_scalef_x (p3.x.to_real ()), font->em_scalef_y (p3.y.to_real ())); + draw_session->cubic_to (font->em_fscalef_x (p1.x.to_real ()), font->em_fscalef_y (p1.y.to_real ()), + font->em_fscalef_x (p2.x.to_real ()), font->em_fscalef_y (p2.y.to_real ()), + font->em_fscalef_x (p3.x.to_real ()), font->em_fscalef_y (p3.y.to_real ())); } protected: - draw_helper_t *draw_helper; + hb_draw_session_t *draw_session; hb_font_t *font; }; @@ -193,7 +192,7 @@ struct cff2_path_procs_path_t : path_procs_t<cff2_path_procs_path_t, cff2_cs_int struct cff2_cs_opset_path_t : cff2_cs_opset_t<cff2_cs_opset_path_t, cff2_path_param_t, cff2_path_procs_path_t> {}; -bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const +bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const { #ifdef HB_NO_OT_FONT_CFF /* XXX Remove check when this code moves to .hh file. */ @@ -206,10 +205,9 @@ bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, d cff2_cs_interpreter_t<cff2_cs_opset_path_t, cff2_path_param_t> interp; const byte_str_t str = (*charStrings)[glyph]; interp.env.init (str, *this, fd, font->coords, font->num_coords); - cff2_path_param_t param (font, draw_helper); + cff2_path_param_t param (font, draw_session); if (unlikely (!interp.interpret (param))) return false; return true; } -#endif #endif diff --git a/thirdparty/harfbuzz/src/hb-ot-cff2-table.hh b/thirdparty/harfbuzz/src/hb-ot-cff2-table.hh index 829217feaa..b77e7f53fa 100644 --- a/thirdparty/harfbuzz/src/hb-ot-cff2-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-cff2-table.hh @@ -397,7 +397,7 @@ struct cff2 template <typename PRIVOPSET, typename PRIVDICTVAL> struct accelerator_templ_t { - void init (hb_face_t *face) + accelerator_templ_t (hb_face_t *face) { topDict.init (); fontDicts.init (); @@ -412,15 +412,15 @@ struct cff2 const OT::cff2 *cff2 = this->blob->template as<OT::cff2> (); if (cff2 == &Null (OT::cff2)) - { fini (); return; } + goto fail; { /* parse top dict */ byte_str_t topDictStr (cff2 + cff2->topDict, cff2->topDictSize); - if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; } + if (unlikely (!topDictStr.sanitize (&sc))) goto fail; cff2_top_dict_interpreter_t top_interp; top_interp.env.init (topDictStr); topDict.init (); - if (unlikely (!top_interp.interpret (topDict))) { fini (); return; } + if (unlikely (!top_interp.interpret (topDict))) goto fail; } globalSubrs = &StructAtOffset<CFF2Subrs> (cff2, cff2->topDict + cff2->topDictSize); @@ -434,49 +434,55 @@ struct cff2 (globalSubrs == &Null (CFF2Subrs)) || unlikely (!globalSubrs->sanitize (&sc)) || (fdArray == &Null (CFF2FDArray)) || unlikely (!fdArray->sanitize (&sc)) || (((fdSelect != &Null (CFF2FDSelect)) && unlikely (!fdSelect->sanitize (&sc, fdArray->count))))) - { fini (); return; } + goto fail; num_glyphs = charStrings->count; if (num_glyphs != sc.get_num_glyphs ()) - { fini (); return; } + goto fail; fdCount = fdArray->count; if (!privateDicts.resize (fdCount)) - { fini (); return; } + goto fail; /* parse font dicts and gather private dicts */ for (unsigned int i = 0; i < fdCount; i++) { const byte_str_t fontDictStr = (*fdArray)[i]; - if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; } + if (unlikely (!fontDictStr.sanitize (&sc))) goto fail; cff2_font_dict_values_t *font; cff2_font_dict_interpreter_t font_interp; font_interp.env.init (fontDictStr); font = fontDicts.push (); - if (unlikely (font == &Crap (cff2_font_dict_values_t))) { fini (); return; } + if (unlikely (font == &Crap (cff2_font_dict_values_t))) goto fail; font->init (); - if (unlikely (!font_interp.interpret (*font))) { fini (); return; } + if (unlikely (!font_interp.interpret (*font))) goto fail; const byte_str_t privDictStr (StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset), font->privateDictInfo.size); - if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; } + if (unlikely (!privDictStr.sanitize (&sc))) goto fail; dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t> priv_interp; priv_interp.env.init(privDictStr); privateDicts[i].init (); - if (unlikely (!priv_interp.interpret (privateDicts[i]))) { fini (); return; } + if (unlikely (!priv_interp.interpret (privateDicts[i]))) goto fail; privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (&privDictStr[0], privateDicts[i].subrsOffset); if (privateDicts[i].localSubrs != &Null (CFF2Subrs) && unlikely (!privateDicts[i].localSubrs->sanitize (&sc))) - { fini (); return; } + goto fail; } - } - void fini () + + return; + + fail: + _fini (); + } + ~accelerator_templ_t () { _fini (); } + void _fini () { sc.end_processing (); topDict.fini (); - fontDicts.fini_deep (); - privateDicts.fini_deep (); + fontDicts.fini (); + privateDicts.fini (); hb_blob_destroy (blob); blob = nullptr; } @@ -484,32 +490,32 @@ struct cff2 bool is_valid () const { return blob; } protected: - hb_blob_t *blob; + hb_blob_t *blob = nullptr; hb_sanitize_context_t sc; public: cff2_top_dict_values_t topDict; - const CFF2Subrs *globalSubrs; - const CFF2VariationStore *varStore; - const CFF2CharStrings *charStrings; - const CFF2FDArray *fdArray; - const CFF2FDSelect *fdSelect; - unsigned int fdCount; + const CFF2Subrs *globalSubrs = nullptr; + const CFF2VariationStore *varStore = nullptr; + const CFF2CharStrings *charStrings = nullptr; + const CFF2FDArray *fdArray = nullptr; + const CFF2FDSelect *fdSelect = nullptr; + unsigned int fdCount = 0; hb_vector_t<cff2_font_dict_values_t> fontDicts; hb_vector_t<PRIVDICTVAL> privateDicts; - unsigned int num_glyphs; + unsigned int num_glyphs = 0; }; struct accelerator_t : accelerator_templ_t<cff2_private_dict_opset_t, cff2_private_dict_values_t> { + accelerator_t (hb_face_t *face) : accelerator_templ_t (face) {} + HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const; -#ifdef HB_EXPERIMENTAL_API - HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const; -#endif + HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const; }; typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> accelerator_subset_t; @@ -525,7 +531,10 @@ struct cff2 DEFINE_SIZE_STATIC (5); }; -struct cff2_accelerator_t : cff2::accelerator_t {}; +struct cff2_accelerator_t : cff2::accelerator_t { + cff2_accelerator_t (hb_face_t *face) : cff2::accelerator_t (face) {} +}; + } /* namespace OT */ #endif /* HB_OT_CFF2_TABLE_HH */ diff --git a/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh b/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh index c8a2af1e82..fde57cdc5b 100644 --- a/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-cmap-table.hh @@ -93,120 +93,192 @@ struct CmapSubtableFormat0 struct CmapSubtableFormat4 { + template<typename Iterator, + typename Writer, hb_requires (hb_is_iterator (Iterator))> - HBUINT16* serialize_endcode_array (hb_serialize_context_t *c, - Iterator it) - { - HBUINT16 *endCode = c->start_embed<HBUINT16> (); - hb_codepoint_t prev_endcp = 0xFFFF; + void to_ranges (Iterator it, Writer& range_writer) + { + hb_codepoint_t start_cp = 0, prev_run_start_cp = 0, run_start_cp = 0, end_cp = 0, last_gid = 0; + int run_length = 0 , delta = 0, prev_delta = 0; + + enum { + FIRST_SUB_RANGE, + FOLLOWING_SUB_RANGE, + } mode; + + while (it) { + // Start a new range + start_cp = (*it).first; + prev_run_start_cp = (*it).first; + run_start_cp = (*it).first; + end_cp = (*it).first; + last_gid = (*it).second; + run_length = 1; + prev_delta = 0; + + delta = (*it).second - (*it).first; + mode = FIRST_SUB_RANGE; + it++; + + while (it) { + // Process range + hb_codepoint_t next_cp = (*it).first; + hb_codepoint_t next_gid = (*it).second; + if (next_cp != end_cp + 1) { + // Current range is over, stop processing. + break; + } - for (const auto& _ : +it) - { - if (prev_endcp != 0xFFFF && prev_endcp + 1u != _.first) - { - HBUINT16 end_code; - end_code = prev_endcp; - c->copy<HBUINT16> (end_code); - } - prev_endcp = _.first; - } + if (next_gid == last_gid + 1) { + // The current run continues. + end_cp = next_cp; + run_length++; + last_gid = next_gid; + it++; + continue; + } - { - // last endCode - HBUINT16 endcode; - endcode = prev_endcp; - if (unlikely (!c->copy<HBUINT16> (endcode))) return nullptr; - // There must be a final entry with end_code == 0xFFFF. - if (prev_endcp != 0xFFFF) - { - HBUINT16 finalcode; - finalcode = 0xFFFF; - if (unlikely (!c->copy<HBUINT16> (finalcode))) return nullptr; + // A new run is starting, decide if we want to commit the current run. + int split_cost = (mode == FIRST_SUB_RANGE) ? 8 : 16; + int run_cost = run_length * 2; + if (run_cost >= split_cost) { + commit_current_range(start_cp, + prev_run_start_cp, + run_start_cp, + end_cp, + delta, + prev_delta, + split_cost, + range_writer); + start_cp = next_cp; + } + + // Start the new run + mode = FOLLOWING_SUB_RANGE; + prev_run_start_cp = run_start_cp; + run_start_cp = next_cp; + end_cp = next_cp; + prev_delta = delta; + delta = next_gid - run_start_cp; + run_length = 1; + last_gid = next_gid; + it++; } + + // Finalize range + commit_current_range (start_cp, + prev_run_start_cp, + run_start_cp, + end_cp, + delta, + prev_delta, + 8, + range_writer); } - return endCode; + if (likely (end_cp != 0xFFFF)) { + range_writer (0xFFFF, 0xFFFF, 1); + } } - template<typename Iterator, - hb_requires (hb_is_iterator (Iterator))> - HBUINT16* serialize_startcode_array (hb_serialize_context_t *c, - Iterator it) - { - HBUINT16 *startCode = c->start_embed<HBUINT16> (); - hb_codepoint_t prev_cp = 0xFFFF; - - for (const auto& _ : +it) - { - if (prev_cp == 0xFFFF || prev_cp + 1u != _.first) - { - HBUINT16 start_code; - start_code = _.first; - c->copy<HBUINT16> (start_code); + /* + * Writes the current range as either one or two ranges depending on what is most efficient. + */ + template<typename Writer> + void commit_current_range (hb_codepoint_t start, + hb_codepoint_t prev_run_start, + hb_codepoint_t run_start, + hb_codepoint_t end, + int run_delta, + int previous_run_delta, + int split_cost, + Writer& range_writer) { + bool should_split = false; + if (start < run_start && run_start < end) { + int run_cost = (end - run_start + 1) * 2; + if (run_cost >= split_cost) { + should_split = true; } + } - prev_cp = _.first; + // TODO(grieger): handle case where delta is legitimately 0, mark range offset array instead? + if (should_split) { + if (start == prev_run_start) + range_writer (start, run_start - 1, previous_run_delta); + else + range_writer (start, run_start - 1, 0); + range_writer (run_start, end, run_delta); + return; } - // There must be a final entry with end_code == 0xFFFF. - if (it.len () == 0 || prev_cp != 0xFFFF) - { - HBUINT16 finalcode; - finalcode = 0xFFFF; - if (unlikely (!c->copy<HBUINT16> (finalcode))) return nullptr; + + if (start == run_start) { + // Range is only a run + range_writer (start, end, run_delta); + return; } - return startCode; + // Write only a single non-run range. + range_writer (start, end, 0); } template<typename Iterator, hb_requires (hb_is_iterator (Iterator))> - HBINT16* serialize_idDelta_array (hb_serialize_context_t *c, - Iterator it, - HBUINT16 *endCode, - HBUINT16 *startCode, - unsigned segcount) - { - unsigned i = 0; - hb_codepoint_t last_gid = 0, start_gid = 0, last_cp = 0xFFFF; - bool use_delta = true; - - HBINT16 *idDelta = c->start_embed<HBINT16> (); - if ((char *)idDelta - (char *)startCode != (int) segcount * (int) HBINT16::static_size) - return nullptr; - - for (const auto& _ : +it) - { - if (_.first == startCode[i]) - { - use_delta = true; - start_gid = _.second; + unsigned serialize_find_segcount (Iterator it) { + struct Counter { + unsigned segcount = 0; + + void operator() (hb_codepoint_t start, + hb_codepoint_t end, + int delta) { + segcount++; } - else if (_.second != last_gid + 1) use_delta = false; + } counter; + + to_ranges (+it, counter); + return counter.segcount; + } - if (_.first == endCode[i]) - { - HBINT16 delta; - if (use_delta) delta = (int)start_gid - (int)startCode[i]; - else delta = 0; - c->copy<HBINT16> (delta); - i++; + template<typename Iterator, + hb_requires (hb_is_iterator (Iterator))> + bool serialize_start_end_delta_arrays (hb_serialize_context_t *c, + Iterator it, + int segcount) + { + struct Writer { + hb_serialize_context_t *serializer_; + HBUINT16* end_code_; + HBUINT16* start_code_; + HBINT16* id_delta_; + int index_; + + Writer(hb_serialize_context_t *serializer) + : serializer_(serializer), + end_code_(nullptr), + start_code_(nullptr), + id_delta_(nullptr), + index_ (0) {} + void operator() (hb_codepoint_t start, + hb_codepoint_t end, + int delta) { + start_code_[index_] = start; + end_code_[index_] = end; + id_delta_[index_] = delta; + index_++; } + } writer(c); - last_gid = _.second; - last_cp = _.first; - } + writer.end_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount); + c->allocate_size<HBUINT16> (2); // padding + writer.start_code_ = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount); + writer.id_delta_ = c->allocate_size<HBINT16> (HBINT16::static_size * segcount); - if (it.len () == 0 || last_cp != 0xFFFF) - { - HBINT16 delta; - delta = 1; - if (unlikely (!c->copy<HBINT16> (delta))) return nullptr; - } + if (unlikely (!writer.end_code_ || !writer.start_code_ || !writer.id_delta_)) return false; - return idDelta; + to_ranges (+it, writer); + return true; } template<typename Iterator, @@ -257,22 +329,14 @@ struct CmapSubtableFormat4 if (unlikely (!c->extend_min (this))) return; this->format = 4; - //serialize endCode[] - HBUINT16 *endCode = serialize_endcode_array (c, format4_iter); - if (unlikely (!endCode)) return; - - unsigned segcount = (c->length () - min_size) / HBUINT16::static_size; - - // 2 bytes of padding. - if (unlikely (!c->allocate_size<HBUINT16> (HBUINT16::static_size))) return; // 2 bytes of padding. - - // serialize startCode[] - HBUINT16 *startCode = serialize_startcode_array (c, format4_iter); - if (unlikely (!startCode)) return; + //serialize endCode[], startCode[], idDelta[] + HBUINT16* endCode = c->start_embed<HBUINT16> (); + unsigned segcount = serialize_find_segcount (format4_iter); + if (unlikely (!serialize_start_end_delta_arrays (c, format4_iter, segcount))) + return; - //serialize idDelta[] - HBINT16 *idDelta = serialize_idDelta_array (c, format4_iter, endCode, startCode, segcount); - if (unlikely (!idDelta)) return; + HBUINT16 *startCode = endCode + segcount + 1; + HBINT16 *idDelta = ((HBINT16*)startCode) + segcount; HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c, format4_iter, endCode, startCode, idDelta, segcount); if (unlikely (!c->check_success (idRangeOffset))) return; @@ -305,7 +369,6 @@ struct CmapSubtableFormat4 { accelerator_t () {} accelerator_t (const CmapSubtableFormat4 *subtable) { init (subtable); } - ~accelerator_t () { fini (); } void init (const CmapSubtableFormat4 *subtable) { @@ -317,7 +380,6 @@ struct CmapSubtableFormat4 glyphIdArray = idRangeOffset + segCount; glyphIdArrayLength = (subtable->length - 16 - 8 * segCount) / 2; } - void fini () {} bool get_glyph (hb_codepoint_t codepoint, hb_codepoint_t *glyph) const { @@ -1543,7 +1605,7 @@ struct cmap unsigned format = (this + _.subtable).u.format; if (format == 12) has_format12 = true; - const EncodingRecord *table = hb_addressof (_); + const EncodingRecord *table = std::addressof (_); if (_.platformID == 0 && _.encodingID == 3) unicode_bmp = table; else if (_.platformID == 0 && _.encodingID == 4) unicode_ucs4 = table; else if (_.platformID == 3 && _.encodingID == 1) ms_bmp = table; @@ -1601,7 +1663,7 @@ struct cmap struct accelerator_t { - void init (hb_face_t *face) + accelerator_t (hb_face_t *face) { this->table = hb_sanitize_context_t ().reference_table<cmap> (face); bool symbol; @@ -1636,8 +1698,7 @@ struct cmap } } } - - void fini () { this->table.destroy (); } + ~accelerator_t () { this->table.destroy (); } bool get_nominal_glyph (hb_codepoint_t unicode, hb_codepoint_t *glyph) const @@ -1799,7 +1860,9 @@ struct cmap DEFINE_SIZE_ARRAY (4, encodingRecord); }; -struct cmap_accelerator_t : cmap::accelerator_t {}; +struct cmap_accelerator_t : cmap::accelerator_t { + cmap_accelerator_t (hb_face_t *face) : cmap::accelerator_t (face) {} +}; } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/hb-ot-color-cbdt-table.hh b/thirdparty/harfbuzz/src/hb-ot-color-cbdt-table.hh index 14459914ee..23fa56c4f6 100644 --- a/thirdparty/harfbuzz/src/hb-ot-color-cbdt-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-color-cbdt-table.hh @@ -360,6 +360,16 @@ struct IndexSubtable struct IndexSubtableRecord { + /* XXX Remove this and fix by not inserting it into vector. */ + IndexSubtableRecord& operator = (const IndexSubtableRecord &o) + { + firstGlyphIndex = o.firstGlyphIndex; + lastGlyphIndex = o.lastGlyphIndex; + offsetToSubtable = (unsigned) o.offsetToSubtable; + assert (offsetToSubtable.is_null ()); + return *this; + } + bool sanitize (hb_sanitize_context_t *c, const void *base) const { TRACE_SANITIZE (this); @@ -809,15 +819,14 @@ struct CBDT struct accelerator_t { - void init (hb_face_t *face) + accelerator_t (hb_face_t *face) { - cblc = hb_sanitize_context_t ().reference_table<CBLC> (face); - cbdt = hb_sanitize_context_t ().reference_table<CBDT> (face); + this->cblc = hb_sanitize_context_t ().reference_table<CBLC> (face); + this->cbdt = hb_sanitize_context_t ().reference_table<CBDT> (face); upem = hb_face_get_upem (face); } - - void fini () + ~accelerator_t () { this->cblc.destroy (); this->cbdt.destroy (); @@ -978,7 +987,10 @@ CBLC::subset (hb_subset_context_t *c) const return_trace (CBLC::sink_cbdt (c, &cbdt_prime)); } -struct CBDT_accelerator_t : CBDT::accelerator_t {}; +struct CBDT_accelerator_t : CBDT::accelerator_t { + CBDT_accelerator_t (hb_face_t *face) : CBDT::accelerator_t (face) {} +}; + } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh b/thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh index 03476faba7..dac755c02c 100644 --- a/thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh @@ -38,8 +38,8 @@ */ #define HB_OT_TAG_COLR HB_TAG('C','O','L','R') -#ifndef COLRV1_MAX_NESTING_LEVEL -#define COLRV1_MAX_NESTING_LEVEL 100 +#ifndef HB_COLRV1_MAX_NESTING_LEVEL +#define HB_COLRV1_MAX_NESTING_LEVEL 100 #endif #ifndef COLRV1_ENABLE_SUBSETTING @@ -71,7 +71,7 @@ struct hb_colrv1_closure_context_t : bool paint_visited (const void *paint) { hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) paint - (uintptr_t) base); - if (visited_paint.has (delta)) + if (visited_paint.in_error() || visited_paint.has (delta)) return true; visited_paint.add (delta); @@ -102,7 +102,7 @@ struct hb_colrv1_closure_context_t : hb_set_t *glyphs_, hb_set_t *layer_indices_, hb_set_t *palette_indices_, - unsigned nesting_level_left_ = COLRV1_MAX_NESTING_LEVEL) : + unsigned nesting_level_left_ = HB_COLRV1_MAX_NESTING_LEVEL) : base (base_), glyphs (glyphs_), layer_indices (layer_indices_), @@ -985,7 +985,7 @@ struct ClipList for (const hb_codepoint_t _ : gids.iter ()) { if (_ == start_gid) continue; - + offset = gid_offset_map.get (_); if (_ == prev_gid + 1 && offset == prev_offset) { @@ -1025,9 +1025,9 @@ struct ClipList if (unlikely (!c->serializer->extend_min (out))) return_trace (false); if (!c->serializer->check_assign (out->format, format, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false); - const hb_set_t& glyphset = *c->plan->_glyphset; + const hb_set_t& glyphset = *c->plan->_glyphset_colred; const hb_map_t &glyph_map = *c->plan->glyph_map; - + hb_map_t new_gid_offset_map; hb_set_t new_gids; for (const ClipRecord& record : clips.iter ()) @@ -1062,6 +1062,18 @@ struct ClipList struct Paint { + + template <typename ...Ts> + bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const + { + TRACE_SANITIZE (this); + + if (unlikely (!c->check_start_recursion (HB_COLRV1_MAX_NESTING_LEVEL))) + return_trace (c->no_dispatch_return_value ()); + + return_trace (c->end_recursion (this->dispatch (c, std::forward<Ts> (ds)...))); + } + template <typename context_t, typename ...Ts> typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const { @@ -1181,7 +1193,7 @@ struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord> TRACE_SUBSET (this); auto *out = c->serializer->start_embed (this); if (unlikely (!c->serializer->extend_min (out))) return_trace (false); - const hb_set_t* glyphset = c->plan->_glyphset; + const hb_set_t* glyphset = c->plan->_glyphset_colred; for (const auto& _ : as_array ()) { @@ -1258,13 +1270,9 @@ struct COLR struct accelerator_t { - accelerator_t () {} - ~accelerator_t () { fini (); } - - void init (hb_face_t *face) + accelerator_t (hb_face_t *face) { colr = hb_sanitize_context_t ().reference_table<COLR> (face); } - - void fini () { this->colr.destroy (); } + ~accelerator_t () { this->colr.destroy (); } bool is_valid () { return colr.get_blob ()->length; } @@ -1399,10 +1407,9 @@ struct COLR const BaseGlyphRecord* get_base_glyph_record (hb_codepoint_t gid) const { - if ((unsigned int) gid == 0) // Ignore notdef. - return nullptr; const BaseGlyphRecord* record = &(this+baseGlyphsZ).bsearch (numBaseGlyphs, (unsigned int) gid); - if ((record && (hb_codepoint_t) record->glyphId != gid)) + if (record == &Null (BaseGlyphRecord) || + (record && (hb_codepoint_t) record->glyphId != gid)) record = nullptr; return record; } @@ -1420,9 +1427,16 @@ struct COLR TRACE_SUBSET (this); const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map; + const hb_set_t& glyphset = *c->plan->_glyphset_colred; auto base_it = + hb_range (c->plan->num_output_glyphs ()) + | hb_filter ([&](hb_codepoint_t new_gid) + { + hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid); + if (glyphset.has (old_gid)) return true; + return false; + }) | hb_map_retains_sorting ([&](hb_codepoint_t new_gid) { hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid); @@ -1430,7 +1444,6 @@ struct COLR const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid); if (unlikely (!old_record)) return hb_pair_t<bool, BaseGlyphRecord> (false, Null (BaseGlyphRecord)); - BaseGlyphRecord new_record = {}; new_record.glyphId = new_gid; new_record.numLayers = old_record->numLayers; @@ -1443,6 +1456,7 @@ struct COLR auto layer_it = + hb_range (c->plan->num_output_glyphs ()) | hb_map (reverse_glyph_map) + | hb_filter (glyphset) | hb_map_retains_sorting ([&](hb_codepoint_t old_gid) { const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid); @@ -1517,6 +1531,10 @@ struct COLR DEFINE_SIZE_MIN (14); }; +struct COLR_accelerator_t : COLR::accelerator_t { + COLR_accelerator_t (hb_face_t *face) : COLR::accelerator_t (face) {} +}; + } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/hb-ot-color-colrv1-closure.hh b/thirdparty/harfbuzz/src/hb-ot-color-colrv1-closure.hh index ca85ba6ad6..fbaf2ec26b 100644 --- a/thirdparty/harfbuzz/src/hb-ot-color-colrv1-closure.hh +++ b/thirdparty/harfbuzz/src/hb-ot-color-colrv1-closure.hh @@ -43,7 +43,7 @@ HB_INTERNAL void PaintColrLayers::closurev1 (hb_colrv1_closure_context_t* c) con const LayerList &paint_offset_lists = c->get_colr_table ()->get_layerList (); for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++) { - const Paint &paint = hb_addressof (paint_offset_lists) + paint_offset_lists[i]; + const Paint &paint = std::addressof (paint_offset_lists) + paint_offset_lists[i]; paint.dispatch (c); } } diff --git a/thirdparty/harfbuzz/src/hb-ot-color-sbix-table.hh b/thirdparty/harfbuzz/src/hb-ot-color-sbix-table.hh index d2911f19e6..9741ebd450 100644 --- a/thirdparty/harfbuzz/src/hb-ot-color-sbix-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-color-sbix-table.hh @@ -202,12 +202,12 @@ struct sbix struct accelerator_t { - void init (hb_face_t *face) + accelerator_t (hb_face_t *face) { table = hb_sanitize_context_t ().reference_table<sbix> (face); num_glyphs = face->get_num_glyphs (); } - void fini () { table.destroy (); } + ~accelerator_t () { table.destroy (); } bool has_data () const { return table->has_data (); } @@ -407,7 +407,10 @@ struct sbix DEFINE_SIZE_ARRAY (8, strikes); }; -struct sbix_accelerator_t : sbix::accelerator_t {}; +struct sbix_accelerator_t : sbix::accelerator_t { + sbix_accelerator_t (hb_face_t *face) : sbix::accelerator_t (face) {} +}; + } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/hb-ot-color-svg-table.hh b/thirdparty/harfbuzz/src/hb-ot-color-svg-table.hh index e022ef43b7..fc649f1006 100644 --- a/thirdparty/harfbuzz/src/hb-ot-color-svg-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-color-svg-table.hh @@ -79,9 +79,9 @@ struct SVG struct accelerator_t { - void init (hb_face_t *face) + accelerator_t (hb_face_t *face) { table = hb_sanitize_context_t ().reference_table<SVG> (face); } - void fini () { table.destroy (); } + ~accelerator_t () { table.destroy (); } hb_blob_t *reference_blob_for_glyph (hb_codepoint_t glyph_id) const { @@ -116,7 +116,9 @@ struct SVG DEFINE_SIZE_STATIC (10); }; -struct SVG_accelerator_t : SVG::accelerator_t {}; +struct SVG_accelerator_t : SVG::accelerator_t { + SVG_accelerator_t (hb_face_t *face) : SVG::accelerator_t (face) {} +}; } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/hb-ot-color.cc b/thirdparty/harfbuzz/src/hb-ot-color.cc index 4170b71317..16077765bd 100644 --- a/thirdparty/harfbuzz/src/hb-ot-color.cc +++ b/thirdparty/harfbuzz/src/hb-ot-color.cc @@ -90,15 +90,15 @@ hb_ot_color_palette_get_count (hb_face_t *face) /** * hb_ot_color_palette_get_name_id: * @face: #hb_face_t to work upon - * @palette_index: The index of the color palette + * @palette_index: The index of the color palette * * Fetches the `name` table Name ID that provides display names for - * a `CPAL` color palette. + * a `CPAL` color palette. * * Palette display names can be generic (e.g., "Default") or provide * specific, themed names (e.g., "Spring", "Summer", "Fall", and "Winter"). * - * Return value: the Named ID found for the palette. + * Return value: the Named ID found for the palette. * If the requested palette has no name the result is #HB_OT_NAME_ID_INVALID. * * Since: 2.1.0 @@ -116,7 +116,7 @@ hb_ot_color_palette_get_name_id (hb_face_t *face, * @color_index: The index of the color * * Fetches the `name` table Name ID that provides display names for - * the specificed color in a face's `CPAL` color palette. + * the specified color in a face's `CPAL` color palette. * * Display names can be generic (e.g., "Background") or specific * (e.g., "Eye color"). @@ -256,6 +256,8 @@ hb_ot_color_has_svg (hb_face_t *face) * * Fetches the SVG document for a glyph. The blob may be either plain text or gzip-encoded. * + * If the glyph has no SVG document, the singleton empty blob is returned. + * * Return value: (transfer full): An #hb_blob_t containing the SVG document of the glyph, if available * * Since: 2.1.0 @@ -296,6 +298,8 @@ hb_ot_color_has_png (hb_face_t *face) * as input. To get an optimally sized PNG blob, the UPEM value must be set on the @font * object. If UPEM is unset, the blob returned will be the largest PNG available. * + * If the glyph has no PNG image, the singleton empty blob is returned. + * * Return value: (transfer full): An #hb_blob_t containing the PNG image for the glyph, if available * * Since: 2.1.0 diff --git a/thirdparty/harfbuzz/src/hb-ot-deprecated.h b/thirdparty/harfbuzz/src/hb-ot-deprecated.h index ce6b6fef11..5192ff73e3 100644 --- a/thirdparty/harfbuzz/src/hb-ot-deprecated.h +++ b/thirdparty/harfbuzz/src/hb-ot-deprecated.h @@ -50,6 +50,21 @@ HB_BEGIN_DECLS */ #define HB_MATH_GLYPH_PART_FLAG_EXTENDER HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER +/* https://github.com/harfbuzz/harfbuzz/pull/3417 */ +/** + * HB_OT_MATH_SCRIPT: + * + * Use #HB_SCRIPT_MATH or #HB_OT_TAG_MATH_SCRIPT instead. + * + * <note>Previous versions of this documentation recommended passing + * #HB_OT_MATH_SCRIPT to hb_buffer_set_script() to enable math shaping, but this + * usage is no longer supported. Use #HB_SCRIPT_MATH instead.</note> + * + * Since: 1.3.3 + * Deprecated: 3.4.0 + */ +#define HB_OT_MATH_SCRIPT HB_OT_TAG_MATH_SCRIPT + /* Like hb_ot_layout_table_find_script, but takes zero-terminated array of scripts to test */ HB_EXTERN HB_DEPRECATED_FOR (hb_ot_layout_table_select_script) hb_bool_t diff --git a/thirdparty/harfbuzz/src/hb-ot-face-table-list.hh b/thirdparty/harfbuzz/src/hb-ot-face-table-list.hh index ffbbb1bc53..c05034b3bb 100644 --- a/thirdparty/harfbuzz/src/hb-ot-face-table-list.hh +++ b/thirdparty/harfbuzz/src/hb-ot-face-table-list.hh @@ -32,6 +32,11 @@ #define HB_OT_FACE_TABLE_LIST_HH #endif /* HB_OT_FACE_TABLE_LIST_HH */ /* Dummy header guards */ +#ifndef HB_OT_CORE_TABLE +#define HB_OT_CORE_TABLE(Namespace, Type) HB_OT_TABLE (Namespace, Type) +#define _HB_OT_CORE_TABLE_UNDEF +#endif + #ifndef HB_OT_ACCELERATOR #define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type) #define _HB_OT_ACCELERATOR_UNDEF @@ -46,7 +51,8 @@ /* OpenType fundamentals. */ -HB_OT_TABLE (OT, head) +HB_OT_CORE_TABLE (OT, head) +HB_OT_CORE_TABLE (OT, maxp) #if !defined(HB_NO_FACE_COLLECT_UNICODES) || !defined(HB_NO_OT_FONT) HB_OT_ACCELERATOR (OT, cmap) #endif @@ -67,17 +73,20 @@ HB_OT_ACCELERATOR (OT, meta) #endif /* Vertical layout. */ +#ifndef HB_NO_VERTICAL HB_OT_TABLE (OT, vhea) HB_OT_ACCELERATOR (OT, vmtx) +HB_OT_TABLE (OT, VORG) +#endif /* TrueType outlines. */ +HB_OT_CORE_TABLE (OT, loca) // Also used to determine number of glyphs HB_OT_ACCELERATOR (OT, glyf) /* CFF outlines. */ #ifndef HB_NO_CFF HB_OT_ACCELERATOR (OT, cff1) HB_OT_ACCELERATOR (OT, cff2) -HB_OT_TABLE (OT, VORG) #endif /* OpenType variations. */ @@ -136,3 +145,7 @@ HB_OT_TABLE (OT, MATH) #ifdef _HB_OT_ACCELERATOR_UNDEF #undef HB_OT_ACCELERATOR #endif + +#ifdef _HB_OT_CORE_TABLE_UNDEF +#undef HB_OT_CORE_TABLE +#endif diff --git a/thirdparty/harfbuzz/src/hb-ot-face.hh b/thirdparty/harfbuzz/src/hb-ot-face.hh index e24d380bca..415dae8e20 100644 --- a/thirdparty/harfbuzz/src/hb-ot-face.hh +++ b/thirdparty/harfbuzz/src/hb-ot-face.hh @@ -63,10 +63,13 @@ struct hb_ot_face_t hb_face_t *face; /* MUST be JUST before the lazy loaders. */ #define HB_OT_TABLE(Namespace, Type) \ hb_table_lazy_loader_t<Namespace::Type, HB_OT_TABLE_ORDER (Namespace, Type)> Type; +#define HB_OT_CORE_TABLE(Namespace, Type) \ + hb_table_lazy_loader_t<Namespace::Type, HB_OT_TABLE_ORDER (Namespace, Type), true> Type; #define HB_OT_ACCELERATOR(Namespace, Type) \ hb_face_lazy_loader_t<Namespace::Type##_accelerator_t, HB_OT_TABLE_ORDER (Namespace, Type)> Type; #include "hb-ot-face-table-list.hh" #undef HB_OT_ACCELERATOR +#undef HB_OT_CORE_TABLE #undef HB_OT_TABLE }; diff --git a/thirdparty/harfbuzz/src/hb-ot-font.cc b/thirdparty/harfbuzz/src/hb-ot-font.cc index 5c044c1c4f..77d3f639db 100644 --- a/thirdparty/harfbuzz/src/hb-ot-font.cc +++ b/thirdparty/harfbuzz/src/hb-ot-font.cc @@ -118,6 +118,7 @@ hb_ot_get_glyph_h_advances (hb_font_t* font, void* font_data, } } +#ifndef HB_NO_VERTICAL static void hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data, unsigned count, @@ -137,7 +138,9 @@ hb_ot_get_glyph_v_advances (hb_font_t* font, void* font_data, first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride); } } +#endif +#ifndef HB_NO_VERTICAL static hb_bool_t hb_ot_get_glyph_v_origin (hb_font_t *font, void *font_data, @@ -150,14 +153,12 @@ hb_ot_get_glyph_v_origin (hb_font_t *font, *x = font->get_glyph_h_advance (glyph) / 2; -#ifndef HB_NO_OT_FONT_CFF const OT::VORG &VORG = *ot_face->VORG; if (VORG.has_data ()) { *y = font->em_scale_y (VORG.get_y_origin (glyph)); return true; } -#endif hb_glyph_extents_t extents = {0}; if (ot_face->glyf->get_extents (font, glyph, &extents)) @@ -174,6 +175,7 @@ hb_ot_get_glyph_v_origin (hb_font_t *font, return true; } +#endif static hb_bool_t hb_ot_get_glyph_extents (hb_font_t *font, @@ -242,6 +244,7 @@ hb_ot_get_font_h_extents (hb_font_t *font, _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, &metrics->line_gap); } +#ifndef HB_NO_VERTICAL static hb_bool_t hb_ot_get_font_v_extents (hb_font_t *font, void *font_data HB_UNUSED, @@ -252,6 +255,24 @@ hb_ot_get_font_v_extents (hb_font_t *font, _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_DESCENDER, &metrics->descender) && _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_LINE_GAP, &metrics->line_gap); } +#endif + +#ifndef HB_NO_DRAW +static void +hb_ot_get_glyph_shape (hb_font_t *font, + void *font_data HB_UNUSED, + hb_codepoint_t glyph, + hb_draw_funcs_t *draw_funcs, void *draw_data, + void *user_data) +{ + hb_draw_session_t draw_session (draw_funcs, draw_data, font->slant_xy); + if (font->face->table.glyf->get_path (font, glyph, draw_session)) return; +#ifndef HB_NO_CFF + if (font->face->table.cff1->get_path (font, glyph, draw_session)) return; + if (font->face->table.cff2->get_path (font, glyph, draw_session)) return; +#endif +} +#endif static inline void free_static_ot_funcs (); @@ -261,17 +282,27 @@ static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot { hb_font_funcs_t *funcs = hb_font_funcs_create (); - hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, nullptr, nullptr); - hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, nullptr, nullptr); hb_font_funcs_set_nominal_glyph_func (funcs, hb_ot_get_nominal_glyph, nullptr, nullptr); hb_font_funcs_set_nominal_glyphs_func (funcs, hb_ot_get_nominal_glyphs, nullptr, nullptr); hb_font_funcs_set_variation_glyph_func (funcs, hb_ot_get_variation_glyph, nullptr, nullptr); + + hb_font_funcs_set_font_h_extents_func (funcs, hb_ot_get_font_h_extents, nullptr, nullptr); hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ot_get_glyph_h_advances, nullptr, nullptr); - hb_font_funcs_set_glyph_v_advances_func (funcs, hb_ot_get_glyph_v_advances, nullptr, nullptr); //hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ot_get_glyph_h_origin, nullptr, nullptr); + +#ifndef HB_NO_VERTICAL + hb_font_funcs_set_font_v_extents_func (funcs, hb_ot_get_font_v_extents, nullptr, nullptr); + hb_font_funcs_set_glyph_v_advances_func (funcs, hb_ot_get_glyph_v_advances, nullptr, nullptr); hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, nullptr, nullptr); +#endif + +#ifndef HB_NO_DRAW + hb_font_funcs_set_glyph_shape_func (funcs, hb_ot_get_glyph_shape, nullptr, nullptr); +#endif + hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, nullptr, nullptr); //hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, nullptr, nullptr); + #ifndef HB_NO_OT_FONT_GLYPH_NAMES hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, nullptr, nullptr); hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, nullptr, nullptr); diff --git a/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh b/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh index 6b419ea1ac..066e152da3 100644 --- a/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-glyf-table.hh @@ -93,22 +93,16 @@ struct glyf template<typename Iterator, hb_requires (hb_is_source_of (Iterator, unsigned int))> static bool - _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets) + _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_short_loca) { - unsigned max_offset = - + padded_offsets - | hb_reduce (hb_add, 0) - ; unsigned num_offsets = padded_offsets.len () + 1; - bool use_short_loca = max_offset < 0x1FFFF; unsigned entry_size = use_short_loca ? 2 : 4; char *loca_prime_data = (char *) hb_calloc (entry_size, num_offsets); if (unlikely (!loca_prime_data)) return false; - DEBUG_MSG (SUBSET, nullptr, "loca entry_size %d num_offsets %d " - "max_offset %d size %d", - entry_size, num_offsets, max_offset, entry_size * num_offsets); + DEBUG_MSG (SUBSET, nullptr, "loca entry_size %d num_offsets %d size %d", + entry_size, num_offsets, entry_size * num_offsets); if (use_short_loca) _write_loca (padded_offsets, 1, hb_array ((HBUINT16 *) loca_prime_data, num_offsets)); @@ -151,11 +145,12 @@ struct glyf template <typename Iterator> bool serialize (hb_serialize_context_t *c, Iterator it, + bool use_short_loca, const hb_subset_plan_t *plan) { TRACE_SERIALIZE (this); unsigned init_len = c->length (); - for (const auto &_ : it) _.serialize (c, plan); + for (const auto &_ : it) _.serialize (c, use_short_loca, plan); /* As a special case when all glyph in the font are empty, add a zero byte * to the table, so that OTS doesn’t reject it, and to make the table work @@ -183,16 +178,28 @@ struct glyf hb_vector_t<SubsetGlyph> glyphs; _populate_subset_glyphs (c->plan, &glyphs); - glyf_prime->serialize (c->serializer, hb_iter (glyphs), c->plan); - auto padded_offsets = + hb_iter (glyphs) | hb_map (&SubsetGlyph::padded_size) ; + unsigned max_offset = + padded_offsets | hb_reduce (hb_add, 0); + bool use_short_loca = max_offset < 0x1FFFF; + + + glyf_prime->serialize (c->serializer, hb_iter (glyphs), use_short_loca, c->plan); + if (!use_short_loca) { + padded_offsets = + + hb_iter (glyphs) + | hb_map (&SubsetGlyph::length) + ; + } + + if (unlikely (c->serializer->in_error ())) return_trace (false); return_trace (c->serializer->check_success (_add_loca_and_head (c->plan, - padded_offsets))); + padded_offsets, + use_short_loca))); } template <typename SubsetGlyph> @@ -200,8 +207,7 @@ struct glyf _populate_subset_glyphs (const hb_subset_plan_t *plan, hb_vector_t<SubsetGlyph> *glyphs /* OUT */) const { - OT::glyf::accelerator_t glyf; - glyf.init (plan->source); + OT::glyf::accelerator_t glyf (plan->source); + hb_range (plan->num_output_glyphs ()) | hb_map ([&] (hb_codepoint_t new_gid) @@ -226,8 +232,6 @@ struct glyf }) | hb_sink (glyphs) ; - - glyf.fini (); } static bool @@ -588,7 +592,7 @@ struct glyf if (unlikely (!header.numberOfContours)) return; unsigned flags_offset = length (instructions_length ()); - if (unlikely (length (flags_offset + 1) > bytes.length)) return; + if (unlikely (flags_offset + 1 > bytes.length)) return; HBUINT8 &first_flag = (HBUINT8 &) StructAtOffset<HBUINT16> (&bytes, flags_offset); first_flag = (uint8_t) first_flag | FLAG_OVERLAP_SIMPLE; @@ -792,10 +796,23 @@ struct glyf hb_array_t<contour_point_t> phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT); { for (unsigned i = 0; i < PHANTOM_COUNT; ++i) phantoms[i].init (); - int h_delta = (int) header->xMin - glyf_accelerator.hmtx->get_side_bearing (gid); - int v_orig = (int) header->yMax + glyf_accelerator.vmtx->get_side_bearing (gid); + int h_delta = (int) header->xMin - + glyf_accelerator.hmtx->get_side_bearing (gid); + int v_orig = (int) header->yMax + +#ifndef HB_NO_VERTICAL + glyf_accelerator.vmtx->get_side_bearing (gid) +#else + 0 +#endif + ; unsigned h_adv = glyf_accelerator.hmtx->get_advance (gid); - unsigned v_adv = glyf_accelerator.vmtx->get_advance (gid); + unsigned v_adv = +#ifndef HB_NO_VERTICAL + glyf_accelerator.vmtx->get_advance (gid) +#else + - font->face->get_upem () +#endif + ; phantoms[PHANTOM_LEFT].x = h_delta; phantoms[PHANTOM_RIGHT].x = h_adv + h_delta; phantoms[PHANTOM_TOP].y = v_orig; @@ -900,7 +917,7 @@ struct glyf struct accelerator_t { - void init (hb_face_t *face_) + accelerator_t (hb_face_t *face) { short_offset = false; num_glyphs = 0; @@ -910,29 +927,30 @@ struct glyf gvar = nullptr; #endif hmtx = nullptr; +#ifndef HB_NO_VERTICAL vmtx = nullptr; - face = face_; +#endif const OT::head &head = *face->table.head; if (head.indexToLocFormat > 1 || head.glyphDataFormat > 0) /* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */ return; short_offset = 0 == head.indexToLocFormat; - loca_table = hb_sanitize_context_t ().reference_table<loca> (face); + loca_table = face->table.loca.get_blob (); // Needs no destruct! glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face); #ifndef HB_NO_VAR gvar = face->table.gvar; #endif hmtx = face->table.hmtx; +#ifndef HB_NO_VERTICAL vmtx = face->table.vmtx; +#endif num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1; num_glyphs = hb_min (num_glyphs, face->get_num_glyphs ()); } - - void fini () + ~accelerator_t () { - loca_table.destroy (); glyf_table.destroy (); } @@ -1037,7 +1055,11 @@ struct glyf success = get_points (font, gid, points_aggregator_t (font, nullptr, phantoms)); if (unlikely (!success)) - return is_vertical ? vmtx->get_advance (gid) : hmtx->get_advance (gid); + return +#ifndef HB_NO_VERTICAL + is_vertical ? vmtx->get_advance (gid) : +#endif + hmtx->get_advance (gid); float result = is_vertical ? phantoms[PHANTOM_TOP].y - phantoms[PHANTOM_BOTTOM].y @@ -1053,7 +1075,11 @@ struct glyf contour_point_t phantoms[PHANTOM_COUNT]; if (unlikely (!get_points (font, gid, points_aggregator_t (font, &extents, phantoms)))) - return is_vertical ? vmtx->get_side_bearing (gid) : hmtx->get_side_bearing (gid); + return +#ifndef HB_NO_VERTICAL + is_vertical ? vmtx->get_side_bearing (gid) : +#endif + hmtx->get_side_bearing (gid); return is_vertical ? ceilf (phantoms[PHANTOM_TOP].y) - extents.y_bearing @@ -1125,11 +1151,10 @@ struct glyf return operation_count; } -#ifdef HB_EXPERIMENTAL_API struct path_builder_t { hb_font_t *font; - draw_helper_t *draw_helper; + hb_draw_session_t *draw_session; struct optional_point_t { @@ -1144,10 +1169,10 @@ struct glyf { return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); } } first_oncurve, first_offcurve, last_offcurve; - path_builder_t (hb_font_t *font_, draw_helper_t &draw_helper_) + path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_) { font = font_; - draw_helper = &draw_helper_; + draw_session = &draw_session_; first_oncurve = first_offcurve = last_offcurve = optional_point_t (); } @@ -1157,10 +1182,6 @@ struct glyf * https://stackoverflow.com/a/20772557 */ void consume_point (const contour_point_t &point) { - /* Skip empty contours */ - if (unlikely (point.is_end_point && !first_oncurve.has_data && !first_offcurve.has_data)) - return; - bool is_on_curve = point.flag & Glyph::FLAG_ON_CURVE; optional_point_t p (point.x, point.y); if (!first_oncurve.has_data) @@ -1168,7 +1189,7 @@ struct glyf if (is_on_curve) { first_oncurve = p; - draw_helper->move_to (font->em_scalef_x (p.x), font->em_scalef_y (p.y)); + draw_session->move_to (font->em_fscalef_x (p.x), font->em_fscalef_y (p.y)); } else { @@ -1177,7 +1198,7 @@ struct glyf optional_point_t mid = first_offcurve.lerp (p, .5f); first_oncurve = mid; last_offcurve = p; - draw_helper->move_to (font->em_scalef_x (mid.x), font->em_scalef_y (mid.y)); + draw_session->move_to (font->em_fscalef_x (mid.x), font->em_fscalef_y (mid.y)); } else first_offcurve = p; @@ -1189,22 +1210,22 @@ struct glyf { if (is_on_curve) { - draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y), - font->em_scalef_x (p.x), font->em_scalef_y (p.y)); + draw_session->quadratic_to (font->em_fscalef_x (last_offcurve.x), font->em_fscalef_y (last_offcurve.y), + font->em_fscalef_x (p.x), font->em_fscalef_y (p.y)); last_offcurve = optional_point_t (); } else { optional_point_t mid = last_offcurve.lerp (p, .5f); - draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y), - font->em_scalef_x (mid.x), font->em_scalef_y (mid.y)); + draw_session->quadratic_to (font->em_fscalef_x (last_offcurve.x), font->em_fscalef_y (last_offcurve.y), + font->em_fscalef_x (mid.x), font->em_fscalef_y (mid.y)); last_offcurve = p; } } else { if (is_on_curve) - draw_helper->line_to (font->em_scalef_x (p.x), font->em_scalef_y (p.y)); + draw_session->line_to (font->em_fscalef_x (p.x), font->em_fscalef_y (p.y)); else last_offcurve = p; } @@ -1215,24 +1236,30 @@ struct glyf if (first_offcurve.has_data && last_offcurve.has_data) { optional_point_t mid = last_offcurve.lerp (first_offcurve, .5f); - draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y), - font->em_scalef_x (mid.x), font->em_scalef_y (mid.y)); + draw_session->quadratic_to (font->em_fscalef_x (last_offcurve.x), font->em_fscalef_y (last_offcurve.y), + font->em_fscalef_x (mid.x), font->em_fscalef_y (mid.y)); last_offcurve = optional_point_t (); /* now check the rest */ } if (first_offcurve.has_data && first_oncurve.has_data) - draw_helper->quadratic_to (font->em_scalef_x (first_offcurve.x), font->em_scalef_y (first_offcurve.y), - font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y)); + draw_session->quadratic_to (font->em_fscalef_x (first_offcurve.x), font->em_fscalef_y (first_offcurve.y), + font->em_fscalef_x (first_oncurve.x), font->em_fscalef_y (first_oncurve.y)); else if (last_offcurve.has_data && first_oncurve.has_data) - draw_helper->quadratic_to (font->em_scalef_x (last_offcurve.x), font->em_scalef_y (last_offcurve.y), - font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y)); + draw_session->quadratic_to (font->em_fscalef_x (last_offcurve.x), font->em_fscalef_y (last_offcurve.y), + font->em_fscalef_x (first_oncurve.x), font->em_fscalef_y (first_oncurve.y)); else if (first_oncurve.has_data) - draw_helper->line_to (font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y)); + draw_session->line_to (font->em_fscalef_x (first_oncurve.x), font->em_fscalef_y (first_oncurve.y)); + else if (first_offcurve.has_data) + { + float x = font->em_fscalef_x (first_offcurve.x), y = font->em_fscalef_x (first_offcurve.y); + draw_session->move_to (x, y); + draw_session->quadratic_to (x, y, x, y); + } /* Getting ready for the next contour */ first_oncurve = first_offcurve = last_offcurve = optional_point_t (); - draw_helper->end_path (); + draw_session->close_path (); } } void points_end () {} @@ -1242,22 +1269,22 @@ struct glyf }; bool - get_path (hb_font_t *font, hb_codepoint_t gid, draw_helper_t &draw_helper) const - { return get_points (font, gid, path_builder_t (font, draw_helper)); } -#endif + get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const + { return get_points (font, gid, path_builder_t (font, draw_session)); } #ifndef HB_NO_VAR const gvar_accelerator_t *gvar; #endif const hmtx_accelerator_t *hmtx; +#ifndef HB_NO_VERTICAL const vmtx_accelerator_t *vmtx; +#endif private: bool short_offset; unsigned int num_glyphs; hb_blob_ptr_t<loca> loca_table; hb_blob_ptr_t<glyf> glyf_table; - hb_face_t *face; }; struct SubsetGlyph @@ -1269,13 +1296,14 @@ struct glyf hb_bytes_t dest_end; /* region of source_glyph to copy second */ bool serialize (hb_serialize_context_t *c, + bool use_short_loca, const hb_subset_plan_t *plan) const { TRACE_SERIALIZE (this); hb_bytes_t dest_glyph = dest_start.copy (c); dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length); - unsigned int pad_length = padding (); + unsigned int pad_length = use_short_loca ? padding () : 0; DEBUG_MSG (SUBSET, nullptr, "serialize %d byte glyph, width %d pad %d", dest_glyph.length, dest_glyph.length + pad_length, pad_length); HBUINT8 pad; @@ -1323,7 +1351,10 @@ struct glyf * defining it _MIN instead. */ }; -struct glyf_accelerator_t : glyf::accelerator_t {}; +struct glyf_accelerator_t : glyf::accelerator_t { + glyf_accelerator_t (hb_face_t *face) : glyf::accelerator_t (face) {} +}; + } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh b/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh index 4038329938..7487e40e6d 100644 --- a/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh @@ -28,6 +28,7 @@ #define HB_OT_HMTX_TABLE_HH #include "hb-open-type.hh" +#include "hb-ot-maxp-table.hh" #include "hb-ot-hhea-table.hh" #include "hb-ot-var-hvar-table.hh" #include "hb-ot-metrics.hh" @@ -98,12 +99,12 @@ struct hmtxvmtx hb_requires (hb_is_iterator (Iterator))> void serialize (hb_serialize_context_t *c, Iterator it, - unsigned num_advances) + unsigned num_long_metrics) { unsigned idx = 0; for (auto _ : it) { - if (idx < num_advances) + if (idx < num_long_metrics) { LongMetric lm; lm.advance = _.first; @@ -127,9 +128,20 @@ struct hmtxvmtx T *table_prime = c->serializer->start_embed <T> (); if (unlikely (!table_prime)) return_trace (false); - accelerator_t _mtx; - _mtx.init (c->plan->source); - unsigned num_advances = _mtx.num_advances_for_subset (c->plan); + accelerator_t _mtx (c->plan->source); + unsigned num_long_metrics; + { + /* Determine num_long_metrics to encode. */ + auto& plan = c->plan; + num_long_metrics = plan->num_output_glyphs (); + hb_codepoint_t old_gid = 0; + unsigned int last_advance = plan->old_gid_for_new_gid (num_long_metrics - 1, &old_gid) ? _mtx.get_advance (old_gid) : 0; + while (num_long_metrics > 1 && + last_advance == (plan->old_gid_for_new_gid (num_long_metrics - 2, &old_gid) ? _mtx.get_advance (old_gid) : 0)) + { + num_long_metrics--; + } + } auto it = + hb_range (c->plan->num_output_glyphs ()) @@ -142,15 +154,13 @@ struct hmtxvmtx }) ; - table_prime->serialize (c->serializer, it, num_advances); - - _mtx.fini (); + table_prime->serialize (c->serializer, it, num_long_metrics); if (unlikely (c->serializer->in_error ())) return_trace (false); // Amend header num hmetrics - if (unlikely (!subset_update_header (c->plan, num_advances))) + if (unlikely (!subset_update_header (c->plan, num_long_metrics))) return_trace (false); return_trace (true); @@ -160,34 +170,51 @@ struct hmtxvmtx { friend struct hmtxvmtx; - void init (hb_face_t *face, - unsigned int default_advance_ = 0) + accelerator_t (hb_face_t *face, + unsigned int default_advance_ = 0) { - default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face); + table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag); + var_table = hb_sanitize_context_t ().reference_table<HVARVVAR> (face, T::variationsTag); - num_advances = T::is_horizontal ? face->table.hhea->numberOfLongMetrics : face->table.vhea->numberOfLongMetrics; + default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face); - table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag); + /* Populate count variables and sort them out as we go */ - /* Cap num_metrics() and num_advances() based on table length. */ unsigned int len = table.get_length (); - if (unlikely (num_advances * 4 > len)) - num_advances = len / 4; - num_metrics = num_advances + (len - 4 * num_advances) / 2; + if (len & 1) + len--; - /* We MUST set num_metrics to zero if num_advances is zero. + num_long_metrics = T::is_horizontal ? + face->table.hhea->numberOfLongMetrics : +#ifndef HB_NO_VERTICAL + face->table.vhea->numberOfLongMetrics +#else + 0 +#endif + ; + if (unlikely (num_long_metrics * 4 > len)) + num_long_metrics = len / 4; + len -= num_long_metrics * 4; + + num_bearings = face->table.maxp->get_num_glyphs (); + + if (unlikely (num_bearings < num_long_metrics)) + num_bearings = num_long_metrics; + if (unlikely ((num_bearings - num_long_metrics) * 2 > len)) + num_bearings = num_long_metrics + len / 2; + len -= (num_bearings - num_long_metrics) * 2; + + /* We MUST set num_bearings to zero if num_long_metrics is zero. * Our get_advance() depends on that. */ - if (unlikely (!num_advances)) - { - num_metrics = num_advances = 0; - table.destroy (); - table = hb_blob_get_empty (); - } + if (unlikely (!num_long_metrics)) + num_bearings = num_long_metrics = 0; - var_table = hb_sanitize_context_t ().reference_table<HVARVVAR> (face, T::variationsTag); + num_advances = num_bearings + len / 2; + num_glyphs = face->get_num_glyphs (); + if (num_glyphs < num_advances) + num_glyphs = num_advances; } - - void fini () + ~accelerator_t () { table.destroy (); var_table.destroy (); @@ -195,14 +222,14 @@ struct hmtxvmtx int get_side_bearing (hb_codepoint_t glyph) const { - if (glyph < num_advances) + if (glyph < num_long_metrics) return table->longMetricZ[glyph].sb; - if (unlikely (glyph >= num_metrics)) + if (unlikely (glyph >= num_bearings)) return 0; - const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_advances]; - return bearings[glyph - num_advances]; + const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics]; + return bearings[glyph - num_long_metrics]; } int get_side_bearing (hb_font_t *font, hb_codepoint_t glyph) const @@ -210,7 +237,7 @@ struct hmtxvmtx int side_bearing = get_side_bearing (glyph); #ifndef HB_NO_VAR - if (unlikely (glyph >= num_metrics) || !font->num_coords) + if (unlikely (glyph >= num_bearings) || !font->num_coords) return side_bearing; if (var_table.get_length ()) @@ -224,18 +251,35 @@ struct hmtxvmtx unsigned int get_advance (hb_codepoint_t glyph) const { - if (unlikely (glyph >= num_metrics)) - { - /* If num_metrics is zero, it means we don't have the metrics table - * for this direction: return default advance. Otherwise, it means that the - * glyph index is out of bound: return zero. */ - if (num_metrics) - return 0; - else - return default_advance; - } + /* OpenType case. */ + if (glyph < num_bearings) + return table->longMetricZ[hb_min (glyph, (uint32_t) num_long_metrics - 1)].advance; + + /* If num_advances is zero, it means we don't have the metrics table + * for this direction: return default advance. Otherwise, there's a + * well-defined answer. */ + if (unlikely (!num_advances)) + return default_advance; + +#ifdef HB_NO_BORING_EXPANSION + return 0; +#endif + + if (unlikely (glyph >= num_glyphs)) + return 0; + + /* num_bearings <= glyph < num_glyphs; + * num_bearings <= num_advances */ + + /* TODO Optimize */ - return table->longMetricZ[hb_min (glyph, (uint32_t) num_advances - 1)].advance; + if (num_bearings == num_advances) + return get_advance (num_bearings - 1); + + const FWORD *bearings = (const FWORD *) &table->longMetricZ[num_long_metrics]; + const UFWORD *advances = (const UFWORD *) &bearings[num_bearings - num_long_metrics]; + + return advances[hb_min (glyph - num_bearings, num_advances - num_bearings - 1)]; } unsigned int get_advance (hb_codepoint_t glyph, @@ -244,7 +288,7 @@ struct hmtxvmtx unsigned int advance = get_advance (glyph); #ifndef HB_NO_VAR - if (unlikely (glyph >= num_metrics) || !font->num_coords) + if (unlikely (glyph >= num_bearings) || !font->num_coords) return advance; if (var_table.get_length ()) @@ -256,35 +300,13 @@ struct hmtxvmtx #endif } - unsigned int num_advances_for_subset (const hb_subset_plan_t *plan) const - { - unsigned int num_advances = plan->num_output_glyphs (); - unsigned int last_advance = _advance_for_new_gid (plan, - num_advances - 1); - while (num_advances > 1 && - last_advance == _advance_for_new_gid (plan, - num_advances - 2)) - { - num_advances--; - } - - return num_advances; - } - - private: - unsigned int _advance_for_new_gid (const hb_subset_plan_t *plan, - hb_codepoint_t new_gid) const - { - hb_codepoint_t old_gid; - if (!plan->old_gid_for_new_gid (new_gid, &old_gid)) - return 0; - - return get_advance (old_gid); - } - protected: - unsigned int num_metrics; - unsigned int num_advances; + // 0 <= num_long_metrics <= num_bearings <= num_advances <= num_glyphs + unsigned num_long_metrics; + unsigned num_bearings; + unsigned num_advances; + unsigned num_glyphs; + unsigned int default_advance; private: @@ -316,6 +338,8 @@ struct hmtxvmtx * the end. This allows a monospaced * font to vary the side bearing * values for each glyph. */ +/*UnsizedArrayOf<UFWORD>advancesX;*/ + /* TODO Document. */ public: DEFINE_SIZE_ARRAY (0, longMetricZ); }; @@ -331,8 +355,12 @@ struct vmtx : hmtxvmtx<vmtx, vhea> { static constexpr bool is_horizontal = false; }; -struct hmtx_accelerator_t : hmtx::accelerator_t {}; -struct vmtx_accelerator_t : vmtx::accelerator_t {}; +struct hmtx_accelerator_t : hmtx::accelerator_t { + hmtx_accelerator_t (hb_face_t *face) : hmtx::accelerator_t (face) {} +}; +struct vmtx_accelerator_t : vmtx::accelerator_t { + vmtx_accelerator_t (hb_face_t *face) : vmtx::accelerator_t (face) {} +}; } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh index 5d98278bed..60a1906155 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout-common.hh +++ b/thirdparty/harfbuzz/src/hb-ot-layout-common.hh @@ -68,8 +68,8 @@ #define HB_MAX_FEATURE_INDICES 1500 #endif -#ifndef HB_MAX_LOOKUP_INDICES -#define HB_MAX_LOOKUP_INDICES 20000 +#ifndef HB_MAX_LOOKUP_VISIT_COUNT +#define HB_MAX_LOOKUP_VISIT_COUNT 35000 #endif @@ -98,7 +98,7 @@ static void ClassDef_remap_and_serialize (hb_serialize_context_t *c, struct hb_prune_langsys_context_t { hb_prune_langsys_context_t (const void *table_, - hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *script_langsys_map_, + hb_hashmap_t<unsigned, hb_set_t *> *script_langsys_map_, const hb_map_t *duplicate_feature_map_, hb_set_t *new_collected_feature_indexes_) :table (table_), @@ -128,7 +128,7 @@ struct hb_prune_langsys_context_t bool visited (const T *p, hb_set_t &visited_set) { hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) p - (uintptr_t) table); - if (visited_set.has (delta)) + if (visited_set.in_error () || visited_set.has (delta)) return true; visited_set.add (delta); @@ -137,7 +137,7 @@ struct hb_prune_langsys_context_t public: const void *table; - hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *script_langsys_map; + hb_hashmap_t<unsigned, hb_set_t *> *script_langsys_map; const hb_map_t *duplicate_feature_map; hb_set_t *new_feature_indexes; @@ -173,20 +173,20 @@ struct hb_subset_layout_context_t : bool visitLookupIndex() { lookup_index_count++; - return lookup_index_count < HB_MAX_LOOKUP_INDICES; + return lookup_index_count < HB_MAX_LOOKUP_VISIT_COUNT; } hb_subset_context_t *subset_context; const hb_tag_t table_tag; const hb_map_t *lookup_index_map; - const hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *script_langsys_map; + const hb_hashmap_t<unsigned, hb_set_t *> *script_langsys_map; const hb_map_t *feature_index_map; unsigned cur_script_index; hb_subset_layout_context_t (hb_subset_context_t *c_, hb_tag_t tag_, hb_map_t *lookup_map_, - hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *script_langsys_map_, + hb_hashmap_t<unsigned, hb_set_t *> *script_langsys_map_, hb_map_t *feature_index_map_) : subset_context (c_), table_tag (tag_), @@ -655,7 +655,6 @@ struct LangSys void collect_features (hb_prune_langsys_context_t *c) const { if (!has_required_feature () && !get_feature_count ()) return; - if (c->visitedLangsys (this)) return; if (has_required_feature () && c->duplicate_feature_map->has (reqFeatureIndex)) c->new_feature_indexes->add (get_required_feature_index ()); @@ -750,11 +749,15 @@ struct Script { //only collect features from non-redundant langsys const LangSys& d = get_default_lang_sys (); - d.collect_features (c); + if (!c->visitedLangsys (&d)) { + d.collect_features (c); + } for (auto _ : + hb_zip (langSys, hb_range (langsys_count))) { + const LangSys& l = this+_.first.offset; + if (c->visitedLangsys (&l)) continue; if (l.compare (d, c->duplicate_feature_map)) continue; l.collect_features (c); @@ -766,6 +769,7 @@ struct Script for (auto _ : + hb_zip (langSys, hb_range (langsys_count))) { const LangSys& l = this+_.first.offset; + if (c->visitedLangsys (&l)) continue; l.collect_features (c); c->script_langsys_map->get (script_index)->add (_.second); } @@ -845,7 +849,7 @@ struct FeatureParamsSize if (unlikely (!c->check_struct (this))) return_trace (false); /* This subtable has some "history", if you will. Some earlier versions of - * Adobe tools calculated the offset of the FeatureParams sutable from the + * Adobe tools calculated the offset of the FeatureParams subtable from the * beginning of the FeatureList table! Now, that is dealt with in the * Feature implementation. But we still need to be able to tell junk from * real data. Note: We don't check that the nameID actually exists. @@ -1357,7 +1361,7 @@ struct Lookup if (unlikely (!get_subtables<TSubTable> ().sanitize (c, this, get_type ()))) return_trace (false); - if (unlikely (get_type () == TSubTable::Extension && !c->get_edit_count ())) + if (unlikely (get_type () == TSubTable::Extension && subtables && !c->get_edit_count ())) { /* The spec says all subtables of an Extension lookup should * have the same type, which shall not be the Extension type @@ -2926,8 +2930,6 @@ struct VariationStore hb_vector_t<hb_inc_bimap_t> inner_maps; inner_maps.resize ((unsigned) dataSets.len); - for (unsigned i = 0; i < inner_maps.length; i++) - inner_maps[i].init (); for (unsigned idx : c->plan->layout_variation_indices->iter ()) { @@ -2935,18 +2937,11 @@ struct VariationStore uint16_t minor = idx & 0xFFFF; if (major >= inner_maps.length) - { - for (unsigned i = 0; i < inner_maps.length; i++) - inner_maps[i].fini (); return_trace (false); - } inner_maps[major].add (minor); } varstore_prime->serialize (c->serializer, this, inner_maps.as_array ()); - for (unsigned i = 0; i < inner_maps.length; i++) - inner_maps[i].fini (); - return_trace ( !c->serializer->in_error() && varstore_prime->dataSets); diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh index aea644f3e1..a76d644c4b 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh @@ -585,17 +585,16 @@ struct GDEF struct accelerator_t { - void init (hb_face_t *face) + accelerator_t (hb_face_t *face) { - this->table = hb_sanitize_context_t ().reference_table<GDEF> (face); - if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face))) + table = hb_sanitize_context_t ().reference_table<GDEF> (face); + if (unlikely (table->is_blocklisted (table.get_blob (), face))) { - hb_blob_destroy (this->table.get_blob ()); - this->table = hb_blob_get_empty (); + hb_blob_destroy (table.get_blob ()); + table = hb_blob_get_empty (); } } - - void fini () { this->table.destroy (); } + ~accelerator_t () { table.destroy (); } hb_blob_ptr_t<GDEF> table; }; @@ -715,7 +714,9 @@ struct GDEF DEFINE_SIZE_MIN (12); }; -struct GDEF_accelerator_t : GDEF::accelerator_t {}; +struct GDEF_accelerator_t : GDEF::accelerator_t { + GDEF_accelerator_t (hb_face_t *face) : GDEF::accelerator_t (face) {} +}; } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh index a8fb5c7acb..2f9186a2a7 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh @@ -118,7 +118,13 @@ struct ValueFormat : HBUINT16 if (!format) return ret; hb_font_t *font = c->font; - bool horizontal = HB_DIRECTION_IS_HORIZONTAL (c->direction); + bool horizontal = +#ifndef HB_NO_VERTICAL + HB_DIRECTION_IS_HORIZONTAL (c->direction) +#else + true +#endif + ; if (format & xPlacement) glyph_pos.x_offset += font->em_scale_x (get_short (values++, &ret)); if (format & yPlacement) glyph_pos.y_offset += font->em_scale_y (get_short (values++, &ret)); @@ -700,7 +706,7 @@ struct MarkArray : Array16Of<MarkRecord> /* Array of MarkRecords--in Coverage or float mark_x, mark_y, base_x, base_y; - buffer->unsafe_to_break (glyph_pos, buffer->idx); + buffer->unsafe_to_break (glyph_pos, buffer->idx + 1); mark_anchor.get_anchor (c, buffer->cur().codepoint, &mark_x, &mark_y); glyph_anchor.get_anchor (c, buffer->info[glyph_pos].codepoint, &base_x, &base_y); @@ -1229,6 +1235,7 @@ struct PairSet buffer->idx = pos; return_trace (true); } + buffer->unsafe_to_concat (buffer->idx, pos + 1); return_trace (false); } @@ -1356,7 +1363,12 @@ struct PairPosFormat1 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; skippy_iter.reset (buffer->idx, 1); - if (!skippy_iter.next ()) return_trace (false); + unsigned unsafe_to; + if (!skippy_iter.next (&unsafe_to)) + { + buffer->unsafe_to_concat (buffer->idx, unsafe_to); + return_trace (false); + } return_trace ((this+pairSet[index]).apply (c, valueFormat, skippy_iter.idx)); } @@ -1549,7 +1561,12 @@ struct PairPosFormat2 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; skippy_iter.reset (buffer->idx, 1); - if (!skippy_iter.next ()) return_trace (false); + unsigned unsafe_to; + if (!skippy_iter.next (&unsafe_to)) + { + buffer->unsafe_to_concat (buffer->idx, unsafe_to); + return_trace (false); + } unsigned int len1 = valueFormat1.get_len (); unsigned int len2 = valueFormat2.get_len (); @@ -1557,13 +1574,89 @@ struct PairPosFormat2 unsigned int klass1 = (this+classDef1).get_class (buffer->cur().codepoint); unsigned int klass2 = (this+classDef2).get_class (buffer->info[skippy_iter.idx].codepoint); - if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) return_trace (false); + if (unlikely (klass1 >= class1Count || klass2 >= class2Count)) + { + buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1); + return_trace (false); + } const Value *v = &values[record_len * (klass1 * class2Count + klass2)]; - bool applied_first = valueFormat1.apply_value (c, this, v, buffer->cur_pos()); - bool applied_second = valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]); + + bool applied_first = false, applied_second = false; + + + /* Isolate simple kerning and apply it half to each side. + * Results in better cursor positinoing / underline drawing. + * + * Disabled, because causes issues... :-( + * https://github.com/harfbuzz/harfbuzz/issues/3408 + * https://github.com/harfbuzz/harfbuzz/pull/3235#issuecomment-1029814978 + */ +#ifndef HB_SPLIT_KERN + if (0) +#endif + { + if (!len2) + { + const hb_direction_t dir = buffer->props.direction; + const bool horizontal = HB_DIRECTION_IS_HORIZONTAL (dir); + const bool backward = HB_DIRECTION_IS_BACKWARD (dir); + unsigned mask = horizontal ? ValueFormat::xAdvance : ValueFormat::yAdvance; + if (backward) + mask |= mask >> 2; /* Add eg. xPlacement in RTL. */ + /* Add Devices. */ + mask |= mask << 4; + + if (valueFormat1 & ~mask) + goto bail; + + /* Is simple kern. Apply value on an empty position slot, + * then split it between sides. */ + + hb_glyph_position_t pos{}; + if (valueFormat1.apply_value (c, this, v, pos)) + { + hb_position_t *src = &pos.x_advance; + hb_position_t *dst1 = &buffer->cur_pos().x_advance; + hb_position_t *dst2 = &buffer->pos[skippy_iter.idx].x_advance; + unsigned i = horizontal ? 0 : 1; + + hb_position_t kern = src[i]; + hb_position_t kern1 = kern >> 1; + hb_position_t kern2 = kern - kern1; + + if (!backward) + { + dst1[i] += kern1; + dst2[i] += kern2; + dst2[i + 2] += kern2; + } + else + { + dst1[i] += kern1; + dst1[i + 2] += src[i + 2] - kern2; + dst2[i] += kern2; + } + + applied_first = applied_second = kern != 0; + goto success; + } + goto boring; + } + } + bail: + + + applied_first = valueFormat1.apply_value (c, this, v, buffer->cur_pos()); + applied_second = valueFormat2.apply_value (c, this, v + len1, buffer->pos[skippy_iter.idx]); + + success: if (applied_first || applied_second) buffer->unsafe_to_break (buffer->idx, skippy_iter.idx + 1); + else + boring: + buffer->unsafe_to_concat (buffer->idx, skippy_iter.idx + 1); + buffer->idx = skippy_iter.idx; if (len2) @@ -1793,10 +1886,19 @@ struct CursivePosFormat1 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; skippy_iter.reset (buffer->idx, 1); - if (!skippy_iter.prev ()) return_trace (false); + unsigned unsafe_from; + if (!skippy_iter.prev (&unsafe_from)) + { + buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); + return_trace (false); + } const EntryExitRecord &prev_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)]; - if (!prev_record.exitAnchor) return_trace (false); + if (!prev_record.exitAnchor) + { + buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + return_trace (false); + } unsigned int i = skippy_iter.idx; unsigned int j = buffer->idx; @@ -2060,7 +2162,13 @@ struct MarkBasePosFormat1 skippy_iter.reset (buffer->idx, 1); skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); do { - if (!skippy_iter.prev ()) return_trace (false); + unsigned unsafe_from; + if (!skippy_iter.prev (&unsafe_from)) + { + buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); + return_trace (false); + } + /* We only want to attach to the first of a MultipleSubst sequence. * https://github.com/harfbuzz/harfbuzz/issues/740 * Reject others... @@ -2083,7 +2191,11 @@ struct MarkBasePosFormat1 //if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); } unsigned int base_index = (this+baseCoverage).get_coverage (buffer->info[skippy_iter.idx].codepoint); - if (base_index == NOT_COVERED) return_trace (false); + if (base_index == NOT_COVERED) + { + buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + return_trace (false); + } return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx)); } @@ -2314,21 +2426,34 @@ struct MarkLigPosFormat1 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; skippy_iter.reset (buffer->idx, 1); skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks); - if (!skippy_iter.prev ()) return_trace (false); + unsigned unsafe_from; + if (!skippy_iter.prev (&unsafe_from)) + { + buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); + return_trace (false); + } /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */ //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); } unsigned int j = skippy_iter.idx; unsigned int lig_index = (this+ligatureCoverage).get_coverage (buffer->info[j].codepoint); - if (lig_index == NOT_COVERED) return_trace (false); + if (lig_index == NOT_COVERED) + { + buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + return_trace (false); + } const LigatureArray& lig_array = this+ligatureArray; const LigatureAttach& lig_attach = lig_array[lig_index]; /* Find component to attach to */ unsigned int comp_count = lig_attach.rows; - if (unlikely (!comp_count)) return_trace (false); + if (unlikely (!comp_count)) + { + buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + return_trace (false); + } /* We must now check whether the ligature ID of the current mark glyph * is identical to the ligature ID of the found ligature. If yes, we @@ -2511,9 +2636,18 @@ struct MarkMarkPosFormat1 hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input; skippy_iter.reset (buffer->idx, 1); skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags); - if (!skippy_iter.prev ()) return_trace (false); + unsigned unsafe_from; + if (!skippy_iter.prev (&unsafe_from)) + { + buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1); + return_trace (false); + } - if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) { return_trace (false); } + if (!_hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx])) + { + buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + return_trace (false); + } unsigned int j = skippy_iter.idx; @@ -2538,11 +2672,16 @@ struct MarkMarkPosFormat1 } /* Didn't match. */ + buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); return_trace (false); good: unsigned int mark2_index = (this+mark2Coverage).get_coverage (buffer->info[j].codepoint); - if (mark2_index == NOT_COVERED) return_trace (false); + if (mark2_index == NOT_COVERED) + { + buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1); + return_trace (false); + } return_trace ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j)); } @@ -2945,7 +3084,7 @@ GPOS::position_finish_advances (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer H } void -GPOS::position_finish_offsets (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) +GPOS::position_finish_offsets (hb_font_t *font, hb_buffer_t *buffer) { _hb_buffer_assert_gsubgpos_vars (buffer); @@ -2955,12 +3094,21 @@ GPOS::position_finish_offsets (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer) /* Handle attachments */ if (buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT) - for (unsigned int i = 0; i < len; i++) + for (unsigned i = 0; i < len; i++) propagate_attachment_offsets (pos, len, i, direction); + + if (unlikely (font->slant)) + { + for (unsigned i = 0; i < len; i++) + if (unlikely (pos[i].y_offset)) + pos[i].x_offset += _hb_roundf (font->slant_xy * pos[i].y_offset); + } } -struct GPOS_accelerator_t : GPOS::accelerator_t {}; +struct GPOS_accelerator_t : GPOS::accelerator_t { + GPOS_accelerator_t (hb_face_t *face) : GPOS::accelerator_t (face) {} +}; /* Out-of-class implementation for methods recursing */ diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh index 710c5fbbb9..0b0bc547bd 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh @@ -566,7 +566,7 @@ struct AlternateSet { /* Maybe we can do better than unsafe-to-break all; but since we are * changing random state, it would be hard to track that. Good 'nough. */ - c->buffer->unsafe_to_break_all (); + c->buffer->unsafe_to_break (0, c->buffer->len); alt_index = c->random_number () % count + 1; } @@ -826,22 +826,25 @@ struct Ligature unsigned int total_component_count = 0; - unsigned int match_length = 0; + unsigned int match_end = 0; unsigned int match_positions[HB_MAX_CONTEXT_LENGTH]; if (likely (!match_input (c, count, &component[1], match_glyph, nullptr, - &match_length, + &match_end, match_positions, &total_component_count))) + { + c->buffer->unsafe_to_concat (c->buffer->idx, match_end); return_trace (false); + } ligate_input (c, count, match_positions, - match_length, + match_end, ligGlyph, total_component_count); @@ -1296,7 +1299,7 @@ struct ReverseChainSingleSubstFormat1 match_lookahead (c, lookahead.len, (HBUINT16 *) lookahead.arrayZ, match_coverage, this, - 1, &end_index)) + c->buffer->idx + 1, &end_index)) { c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index); c->replace_glyph_inplace (substitute[index]); @@ -1305,8 +1308,11 @@ struct ReverseChainSingleSubstFormat1 * calls us through a Context lookup. */ return_trace (true); } - - return_trace (false); + else + { + c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index); + return_trace (false); + } } template<typename Iterator, @@ -1739,7 +1745,9 @@ struct GSUB : GSUBGPOS }; -struct GSUB_accelerator_t : GSUB::accelerator_t {}; +struct GSUB_accelerator_t : GSUB::accelerator_t { + GSUB_accelerator_t (hb_face_t *face) : GSUB::accelerator_t (face) {} +}; /* Out-of-class implementation for methods recursing */ diff --git a/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh b/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh index c0ed2bcc03..65de131f85 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh +++ b/thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh @@ -81,12 +81,15 @@ struct hb_closure_context_t : nesting_level_left++; } + void reset_lookup_visit_count () + { lookup_count = 0; } + bool lookup_limit_exceeded () - { return lookup_count > HB_MAX_LOOKUP_INDICES; } + { return lookup_count > HB_MAX_LOOKUP_VISIT_COUNT; } bool should_visit_lookup (unsigned int lookup_index) { - if (lookup_count++ > HB_MAX_LOOKUP_INDICES) + if (lookup_count++ > HB_MAX_LOOKUP_VISIT_COUNT) return false; if (is_lookup_done (lookup_index)) @@ -122,24 +125,31 @@ struct hb_closure_context_t : hb_set_t *covered_glyph_set = done_lookups_glyph_set->get (lookup_index); if (unlikely (covered_glyph_set->in_error ())) return true; - if (parent_active_glyphs ()->is_subset (*covered_glyph_set)) + if (parent_active_glyphs ().is_subset (*covered_glyph_set)) return true; - hb_set_union (covered_glyph_set, parent_active_glyphs ()); + covered_glyph_set->union_ (parent_active_glyphs ()); return false; } - hb_set_t* parent_active_glyphs () + const hb_set_t& previous_parent_active_glyphs () { + if (active_glyphs_stack.length <= 1) + return *glyphs; + + return active_glyphs_stack[active_glyphs_stack.length - 2]; + } + + const hb_set_t& parent_active_glyphs () { - if (active_glyphs_stack.length < 1) - return glyphs; + if (!active_glyphs_stack) + return *glyphs; return active_glyphs_stack.tail (); } - void push_cur_active_glyphs (hb_set_t* cur_active_glyph_set) + hb_set_t& push_cur_active_glyphs () { - active_glyphs_stack.push (cur_active_glyph_set); + return *active_glyphs_stack.push (); } bool pop_cur_done_glyphs () @@ -153,29 +163,24 @@ struct hb_closure_context_t : hb_face_t *face; hb_set_t *glyphs; - hb_set_t *cur_intersected_glyphs; hb_set_t output[1]; - hb_vector_t<hb_set_t *> active_glyphs_stack; + hb_vector_t<hb_set_t> active_glyphs_stack; recurse_func_t recurse_func; unsigned int nesting_level_left; hb_closure_context_t (hb_face_t *face_, hb_set_t *glyphs_, - hb_set_t *cur_intersected_glyphs_, hb_map_t *done_lookups_glyph_count_, - hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *done_lookups_glyph_set_, + hb_hashmap_t<unsigned, hb_set_t *> *done_lookups_glyph_set_, unsigned int nesting_level_left_ = HB_MAX_NESTING_LEVEL) : face (face_), glyphs (glyphs_), - cur_intersected_glyphs (cur_intersected_glyphs_), recurse_func (nullptr), nesting_level_left (nesting_level_left_), done_lookups_glyph_count (done_lookups_glyph_count_), done_lookups_glyph_set (done_lookups_glyph_set_), lookup_count (0) - { - push_cur_active_glyphs (glyphs_); - } + {} ~hb_closure_context_t () { flush (); } @@ -183,16 +188,16 @@ struct hb_closure_context_t : void flush () { - hb_set_del_range (output, face->get_num_glyphs (), HB_SET_VALUE_INVALID); /* Remove invalid glyphs. */ - hb_set_union (glyphs, output); - hb_set_clear (output); + output->del_range (face->get_num_glyphs (), HB_SET_VALUE_INVALID); /* Remove invalid glyphs. */ + glyphs->union_ (*output); + output->clear (); active_glyphs_stack.pop (); - active_glyphs_stack.fini (); + active_glyphs_stack.reset (); } private: hb_map_t *done_lookups_glyph_count; - hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *done_lookups_glyph_set; + hb_hashmap_t<unsigned, hb_set_t *> *done_lookups_glyph_set; unsigned int lookup_count; }; @@ -211,7 +216,11 @@ struct hb_closure_lookups_context_t : return; /* Return if new lookup was recursed to before. */ - if (is_lookup_visited (lookup_index)) + if (lookup_limit_exceeded () + || visited_lookups->in_error () + || visited_lookups->has (lookup_index)) + // Don't increment lookup count here, that will be done in the call to closure_lookups() + // made by recurse_func. return; nesting_level_left--; @@ -226,12 +235,20 @@ struct hb_closure_lookups_context_t : { inactive_lookups->add (lookup_index); } bool lookup_limit_exceeded () - { return lookup_count > HB_MAX_LOOKUP_INDICES; } + { + bool ret = lookup_count > HB_MAX_LOOKUP_VISIT_COUNT; + if (ret) + DEBUG_MSG (SUBSET, nullptr, "lookup visit count limit exceeded in lookup closure!"); + return ret; } bool is_lookup_visited (unsigned lookup_index) { - if (unlikely (lookup_count++ > HB_MAX_LOOKUP_INDICES)) + if (unlikely (lookup_count++ > HB_MAX_LOOKUP_VISIT_COUNT)) + { + DEBUG_MSG (SUBSET, nullptr, "total visited lookup count %u exceeds max limit, lookup %u is dropped.", + lookup_count, lookup_index); return true; + } if (unlikely (visited_lookups->in_error ())) return true; @@ -505,7 +522,7 @@ struct hb_ot_apply_context_t : may_skip (const hb_glyph_info_t &info) const { return matcher.may_skip (c, info); } - bool next () + bool next (unsigned *unsafe_to = nullptr) { assert (num_items > 0); while (idx + num_items < end) @@ -528,11 +545,17 @@ struct hb_ot_apply_context_t : } if (skip == matcher_t::SKIP_NO) + { + if (unsafe_to) + *unsafe_to = idx + 1; return false; + } } + if (unsafe_to) + *unsafe_to = end; return false; } - bool prev () + bool prev (unsigned *unsafe_from = nullptr) { assert (num_items > 0); while (idx > num_items - 1) @@ -555,8 +578,14 @@ struct hb_ot_apply_context_t : } if (skip == matcher_t::SKIP_NO) + { + if (unsafe_from) + *unsafe_from = hb_max (1u, idx) - 1u; return false; + } } + if (unsafe_from) + *unsafe_from = 0; return false; } @@ -697,53 +726,60 @@ struct hb_ot_apply_context_t : return true; } - void _set_glyph_props (hb_codepoint_t glyph_index, + void _set_glyph_class (hb_codepoint_t glyph_index, unsigned int class_guess = 0, bool ligature = false, bool component = false) const { - unsigned int add_in = _hb_glyph_info_get_glyph_props (&buffer->cur()) & - HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE; - add_in |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED; + unsigned int props = _hb_glyph_info_get_glyph_props (&buffer->cur()); + props |= HB_OT_LAYOUT_GLYPH_PROPS_SUBSTITUTED; if (ligature) { - add_in |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED; + props |= HB_OT_LAYOUT_GLYPH_PROPS_LIGATED; /* In the only place that the MULTIPLIED bit is used, Uniscribe * seems to only care about the "last" transformation between * Ligature and Multiple substitutions. Ie. if you ligate, expand, * and ligate again, it forgives the multiplication and acts as * if only ligation happened. As such, clear MULTIPLIED bit. */ - add_in &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED; + props &= ~HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED; } if (component) - add_in |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED; + props |= HB_OT_LAYOUT_GLYPH_PROPS_MULTIPLIED; if (likely (has_glyph_classes)) - _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | gdef.get_glyph_props (glyph_index)); + { + props &= HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE; + _hb_glyph_info_set_glyph_props (&buffer->cur(), props | gdef.get_glyph_props (glyph_index)); + } else if (class_guess) - _hb_glyph_info_set_glyph_props (&buffer->cur(), add_in | class_guess); + { + props &= HB_OT_LAYOUT_GLYPH_PROPS_PRESERVE; + _hb_glyph_info_set_glyph_props (&buffer->cur(), props | class_guess); + } + else + _hb_glyph_info_set_glyph_props (&buffer->cur(), props); } void replace_glyph (hb_codepoint_t glyph_index) const { - _set_glyph_props (glyph_index); + _set_glyph_class (glyph_index); (void) buffer->replace_glyph (glyph_index); } void replace_glyph_inplace (hb_codepoint_t glyph_index) const { - _set_glyph_props (glyph_index); + _set_glyph_class (glyph_index); buffer->cur().codepoint = glyph_index; } void replace_glyph_with_ligature (hb_codepoint_t glyph_index, unsigned int class_guess) const { - _set_glyph_props (glyph_index, class_guess, true); + _set_glyph_class (glyph_index, class_guess, true); (void) buffer->replace_glyph (glyph_index); } void output_glyph_for_component (hb_codepoint_t glyph_index, unsigned int class_guess) const { - _set_glyph_props (glyph_index, class_guess, false, true); + _set_glyph_class (glyph_index, class_guess, false, true); (void) buffer->output_glyph (glyph_index); } }; @@ -933,7 +969,7 @@ static inline bool match_input (hb_ot_apply_context_t *c, const HBUINT16 input[], /* Array of input values--start with second glyph */ match_func_t match_func, const void *match_data, - unsigned int *end_offset, + unsigned int *end_position, unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], unsigned int *p_total_component_count = nullptr) { @@ -986,7 +1022,12 @@ static inline bool match_input (hb_ot_apply_context_t *c, match_positions[0] = buffer->idx; for (unsigned int i = 1; i < count; i++) { - if (!skippy_iter.next ()) return_trace (false); + unsigned unsafe_to; + if (!skippy_iter.next (&unsafe_to)) + { + *end_position = unsafe_to; + return_trace (false); + } match_positions[i] = skippy_iter.idx; @@ -1040,7 +1081,7 @@ static inline bool match_input (hb_ot_apply_context_t *c, total_component_count += _hb_glyph_info_get_lig_num_comps (&buffer->info[skippy_iter.idx]); } - *end_offset = skippy_iter.idx - buffer->idx + 1; + *end_position = skippy_iter.idx + 1; if (p_total_component_count) *p_total_component_count = total_component_count; @@ -1050,7 +1091,7 @@ static inline bool match_input (hb_ot_apply_context_t *c, static inline bool ligate_input (hb_ot_apply_context_t *c, unsigned int count, /* Including the first glyph */ const unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */ - unsigned int match_length, + unsigned int match_end, hb_codepoint_t lig_glyph, unsigned int total_component_count) { @@ -1058,7 +1099,7 @@ static inline bool ligate_input (hb_ot_apply_context_t *c, hb_buffer_t *buffer = c->buffer; - buffer->merge_clusters (buffer->idx, buffer->idx + match_length); + buffer->merge_clusters (buffer->idx, match_end); /* - If a base and one or more marks ligate, consider that as a base, NOT * ligature, such that all following marks can still attach to it. @@ -1175,11 +1216,16 @@ static inline bool match_backtrack (hb_ot_apply_context_t *c, skippy_iter.set_match_func (match_func, match_data, backtrack); for (unsigned int i = 0; i < count; i++) - if (!skippy_iter.prev ()) + { + unsigned unsafe_from; + if (!skippy_iter.prev (&unsafe_from)) + { + *match_start = unsafe_from; return_trace (false); + } + } *match_start = skippy_iter.idx; - return_trace (true); } @@ -1188,21 +1234,26 @@ static inline bool match_lookahead (hb_ot_apply_context_t *c, const HBUINT16 lookahead[], match_func_t match_func, const void *match_data, - unsigned int offset, + unsigned int start_index, unsigned int *end_index) { TRACE_APPLY (nullptr); hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context; - skippy_iter.reset (c->buffer->idx + offset - 1, count); + skippy_iter.reset (start_index - 1, count); skippy_iter.set_match_func (match_func, match_data, lookahead); for (unsigned int i = 0; i < count; i++) - if (!skippy_iter.next ()) + { + unsigned unsafe_to; + if (!skippy_iter.next (&unsafe_to)) + { + *end_index = unsafe_to; return_trace (false); + } + } *end_index = skippy_iter.idx + 1; - return_trace (true); } @@ -1269,22 +1320,23 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c, unsigned seqIndex = lookupRecord[i].sequenceIndex; if (seqIndex >= inputCount) continue; - hb_set_t *pos_glyphs = nullptr; + bool has_pos_glyphs = false; + hb_set_t pos_glyphs; if (hb_set_is_empty (covered_seq_indicies) || !hb_set_has (covered_seq_indicies, seqIndex)) { - pos_glyphs = hb_set_create (); + has_pos_glyphs = true; if (seqIndex == 0) { switch (context_format) { case ContextFormat::SimpleContext: - pos_glyphs->add (value); + pos_glyphs.add (value); break; case ContextFormat::ClassBasedContext: - intersected_glyphs_func (c->cur_intersected_glyphs, data, value, pos_glyphs); + intersected_glyphs_func (&c->parent_active_glyphs (), data, value, &pos_glyphs); break; case ContextFormat::CoverageBasedContext: - hb_set_set (pos_glyphs, c->cur_intersected_glyphs); + pos_glyphs.set (c->parent_active_glyphs ()); break; } } @@ -1298,13 +1350,16 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c, input_value = input[seqIndex - 1]; } - intersected_glyphs_func (c->glyphs, input_data, input_value, pos_glyphs); + intersected_glyphs_func (c->glyphs, input_data, input_value, &pos_glyphs); } } - hb_set_add (covered_seq_indicies, seqIndex); - if (pos_glyphs) - c->push_cur_active_glyphs (pos_glyphs); + covered_seq_indicies->add (seqIndex); + if (has_pos_glyphs) { + c->push_cur_active_glyphs () = pos_glyphs; + } else { + c->push_cur_active_glyphs ().set (*c->glyphs); + } unsigned endIndex = inputCount; if (context_format == ContextFormat::CoverageBasedContext) @@ -1312,10 +1367,7 @@ static void context_closure_recurse_lookups (hb_closure_context_t *c, c->recurse (lookupRecord[i].lookupListIndex, covered_seq_indicies, seqIndex, endIndex); - if (pos_glyphs) { - c->pop_cur_done_glyphs (); - hb_set_destroy (pos_glyphs); - } + c->pop_cur_done_glyphs (); } hb_set_destroy (covered_seq_indicies); @@ -1330,15 +1382,13 @@ static inline void recurse_lookups (context_t *c, c->recurse (lookupRecord[i].lookupListIndex); } -static inline bool apply_lookup (hb_ot_apply_context_t *c, +static inline void apply_lookup (hb_ot_apply_context_t *c, unsigned int count, /* Including the first glyph */ unsigned int match_positions[HB_MAX_CONTEXT_LENGTH], /* Including the first glyph */ unsigned int lookupCount, const LookupRecord lookupRecord[], /* Array of LookupRecords--in design order */ - unsigned int match_length) + unsigned int match_end) { - TRACE_APPLY (nullptr); - hb_buffer_t *buffer = c->buffer; int end; @@ -1346,7 +1396,7 @@ static inline bool apply_lookup (hb_ot_apply_context_t *c, * Adjust. */ { unsigned int bl = buffer->backtrack_len (); - end = bl + match_length; + end = bl + match_end - buffer->idx; int delta = bl - buffer->idx; /* Convert positions to new indexing. */ @@ -1448,8 +1498,6 @@ static inline bool apply_lookup (hb_ot_apply_context_t *c, } (void) buffer->move_to (end); - - return_trace (true); } @@ -1537,17 +1585,25 @@ static inline bool context_apply_lookup (hb_ot_apply_context_t *c, const LookupRecord lookupRecord[], ContextApplyLookupContext &lookup_context) { - unsigned int match_length = 0; - unsigned int match_positions[HB_MAX_CONTEXT_LENGTH]; - return match_input (c, - inputCount, input, - lookup_context.funcs.match, lookup_context.match_data, - &match_length, match_positions) - && (c->buffer->unsafe_to_break (c->buffer->idx, c->buffer->idx + match_length), - apply_lookup (c, - inputCount, match_positions, - lookupCount, lookupRecord, - match_length)); + unsigned match_end = 0; + unsigned match_positions[HB_MAX_CONTEXT_LENGTH]; + if (match_input (c, + inputCount, input, + lookup_context.funcs.match, lookup_context.match_data, + &match_end, match_positions)) + { + c->buffer->unsafe_to_break (c->buffer->idx, match_end); + apply_lookup (c, + inputCount, match_positions, + lookupCount, lookupRecord, + match_end); + return true; + } + else + { + c->buffer->unsafe_to_concat (c->buffer->idx, match_end); + return false; + } } struct Rule @@ -1642,9 +1698,8 @@ struct Rule const hb_map_t *klass_map = nullptr) const { TRACE_SUBSET (this); - - const hb_array_t<const HBUINT16> input = inputZ.as_array ((inputCount ? inputCount - 1 : 0)); - if (!input.length) return_trace (false); + if (unlikely (!inputCount)) return_trace (false); + const hb_array_t<const HBUINT16> input = inputZ.as_array (inputCount - 1); const hb_map_t *mapping = klass_map == nullptr ? c->plan->glyph_map : klass_map; if (!hb_all (input, mapping)) return_trace (false); @@ -1816,8 +1871,9 @@ struct ContextFormat1 void closure (hb_closure_context_t *c) const { - c->cur_intersected_glyphs->clear (); - get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs); + hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs (); + get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (), + cur_active_glyphs); struct ContextClosureLookupContext lookup_context = { {intersects_glyph, intersected_glyph}, @@ -1826,10 +1882,14 @@ struct ContextFormat1 }; + hb_zip (this+coverage, hb_range ((unsigned) ruleSet.len)) - | hb_filter (c->parent_active_glyphs (), hb_first) + | hb_filter ([&] (hb_codepoint_t _) { + return c->previous_parent_active_glyphs ().has (_); + }, hb_first) | hb_map ([&](const hb_pair_t<hb_codepoint_t, unsigned> _) { return hb_pair_t<unsigned, const RuleSet&> (_.first, this+ruleSet[_.second]); }) | hb_apply ([&] (const hb_pair_t<unsigned, const RuleSet&>& _) { _.second.closure (c, _.first, lookup_context); }) ; + + c->pop_cur_done_glyphs (); } void closure_lookups (hb_closure_lookups_context_t *c) const @@ -1977,8 +2037,9 @@ struct ContextFormat2 if (!(this+coverage).intersects (c->glyphs)) return; - c->cur_intersected_glyphs->clear (); - get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs); + hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs (); + get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (), + cur_active_glyphs); const ClassDef &class_def = this+classDef; @@ -1988,10 +2049,9 @@ struct ContextFormat2 &class_def }; - return + hb_enumerate (ruleSet) | hb_filter ([&] (unsigned _) - { return class_def.intersects_class (c->cur_intersected_glyphs, _); }, + { return class_def.intersects_class (&c->parent_active_glyphs (), _); }, hb_first) | hb_apply ([&] (const hb_pair_t<unsigned, const Offset16To<RuleSet>&> _) { @@ -1999,6 +2059,8 @@ struct ContextFormat2 rule_set.closure (c, _.first, lookup_context); }) ; + + c->pop_cur_done_glyphs (); } void closure_lookups (hb_closure_lookups_context_t *c) const @@ -2171,8 +2233,10 @@ struct ContextFormat3 if (!(this+coverageZ[0]).intersects (c->glyphs)) return; - c->cur_intersected_glyphs->clear (); - get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs); + hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs (); + get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (), + cur_active_glyphs); + const LookupRecord *lookupRecord = &StructAfter<LookupRecord> (coverageZ.as_array (glyphCount)); struct ContextClosureLookupContext lookup_context = { @@ -2184,6 +2248,8 @@ struct ContextFormat3 glyphCount, (const HBUINT16 *) (coverageZ.arrayZ + 1), lookupCount, lookupRecord, 0, lookup_context); + + c->pop_cur_done_glyphs (); } void closure_lookups (hb_closure_lookups_context_t *c) const @@ -2440,25 +2506,38 @@ static inline bool chain_context_apply_lookup (hb_ot_apply_context_t *c, const LookupRecord lookupRecord[], ChainContextApplyLookupContext &lookup_context) { - unsigned int start_index = 0, match_length = 0, end_index = 0; - unsigned int match_positions[HB_MAX_CONTEXT_LENGTH]; - return match_input (c, - inputCount, input, - lookup_context.funcs.match, lookup_context.match_data[1], - &match_length, match_positions) - && match_backtrack (c, - backtrackCount, backtrack, - lookup_context.funcs.match, lookup_context.match_data[0], - &start_index) - && match_lookahead (c, - lookaheadCount, lookahead, - lookup_context.funcs.match, lookup_context.match_data[2], - match_length, &end_index) - && (c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index), - apply_lookup (c, - inputCount, match_positions, - lookupCount, lookupRecord, - match_length)); + unsigned end_index = c->buffer->idx; + unsigned match_end = 0; + unsigned match_positions[HB_MAX_CONTEXT_LENGTH]; + if (!(match_input (c, + inputCount, input, + lookup_context.funcs.match, lookup_context.match_data[1], + &match_end, match_positions) && (end_index = match_end) + && match_lookahead (c, + lookaheadCount, lookahead, + lookup_context.funcs.match, lookup_context.match_data[2], + match_end, &end_index))) + { + c->buffer->unsafe_to_concat (c->buffer->idx, end_index); + return false; + } + + unsigned start_index = c->buffer->out_len; + if (!match_backtrack (c, + backtrackCount, backtrack, + lookup_context.funcs.match, lookup_context.match_data[0], + &start_index)) + { + c->buffer->unsafe_to_concat_from_outbuffer (start_index, end_index); + return false; + } + + c->buffer->unsafe_to_break_from_outbuffer (start_index, end_index); + apply_lookup (c, + inputCount, match_positions, + lookupCount, lookupRecord, + match_end); + return true; } struct ChainRule @@ -2790,8 +2869,9 @@ struct ChainContextFormat1 void closure (hb_closure_context_t *c) const { - c->cur_intersected_glyphs->clear (); - get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs); + hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs (); + get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (), + cur_active_glyphs); struct ChainContextClosureLookupContext lookup_context = { {intersects_glyph, intersected_glyph}, @@ -2800,10 +2880,14 @@ struct ChainContextFormat1 }; + hb_zip (this+coverage, hb_range ((unsigned) ruleSet.len)) - | hb_filter (c->parent_active_glyphs (), hb_first) + | hb_filter ([&] (hb_codepoint_t _) { + return c->previous_parent_active_glyphs ().has (_); + }, hb_first) | hb_map ([&](const hb_pair_t<hb_codepoint_t, unsigned> _) { return hb_pair_t<unsigned, const ChainRuleSet&> (_.first, this+ruleSet[_.second]); }) | hb_apply ([&] (const hb_pair_t<unsigned, const ChainRuleSet&>& _) { _.second.closure (c, _.first, lookup_context); }) ; + + c->pop_cur_done_glyphs (); } void closure_lookups (hb_closure_lookups_context_t *c) const @@ -2952,8 +3036,10 @@ struct ChainContextFormat2 if (!(this+coverage).intersects (c->glyphs)) return; - c->cur_intersected_glyphs->clear (); - get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs); + hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs (); + get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (), + cur_active_glyphs); + const ClassDef &backtrack_class_def = this+backtrackClassDef; const ClassDef &input_class_def = this+inputClassDef; @@ -2967,10 +3053,9 @@ struct ChainContextFormat2 &lookahead_class_def} }; - return + hb_enumerate (ruleSet) | hb_filter ([&] (unsigned _) - { return input_class_def.intersects_class (c->cur_intersected_glyphs, _); }, + { return input_class_def.intersects_class (&c->parent_active_glyphs (), _); }, hb_first) | hb_apply ([&] (const hb_pair_t<unsigned, const Offset16To<ChainRuleSet>&> _) { @@ -2978,6 +3063,8 @@ struct ChainContextFormat2 chainrule_set.closure (c, _.first, lookup_context); }) ; + + c->pop_cur_done_glyphs (); } void closure_lookups (hb_closure_lookups_context_t *c) const @@ -3204,8 +3291,10 @@ struct ChainContextFormat3 if (!(this+input[0]).intersects (c->glyphs)) return; - c->cur_intersected_glyphs->clear (); - get_coverage ().intersected_coverage_glyphs (c->parent_active_glyphs (), c->cur_intersected_glyphs); + hb_set_t* cur_active_glyphs = &c->push_cur_active_glyphs (); + get_coverage ().intersected_coverage_glyphs (&c->previous_parent_active_glyphs (), + cur_active_glyphs); + const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (input); const Array16Of<LookupRecord> &lookup = StructAfter<Array16Of<LookupRecord>> (lookahead); @@ -3220,6 +3309,8 @@ struct ChainContextFormat3 lookahead.len, (const HBUINT16 *) lookahead.arrayZ, lookup.len, lookup.arrayZ, 0, lookup_context); + + c->pop_cur_done_glyphs (); } void closure_lookups (hb_closure_lookups_context_t *c) const @@ -3631,7 +3722,7 @@ struct GSUBGPOS } void prune_langsys (const hb_map_t *duplicate_feature_map, - hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *script_langsys_map, + hb_hashmap_t<unsigned, hb_set_t *> *script_langsys_map, hb_set_t *new_feature_indexes /* OUT */) const { hb_prune_langsys_context_t c (this, script_langsys_map, duplicate_feature_map, new_feature_indexes); @@ -3689,12 +3780,12 @@ struct GSUBGPOS hb_map_t *duplicate_feature_map /* OUT */) const { if (feature_indices->is_empty ()) return; - hb_hashmap_t<hb_tag_t, hb_set_t *, (unsigned)-1, nullptr> unique_features; + hb_hashmap_t<hb_tag_t, hb_set_t *> unique_features; //find out duplicate features after subset for (unsigned i : feature_indices->iter ()) { hb_tag_t t = get_feature_tag (i); - if (t == unique_features.INVALID_KEY) continue; + if (t == HB_MAP_VALUE_INVALID) continue; if (!unique_features.has (t)) { hb_set_t* indices = hb_set_create (); @@ -3784,8 +3875,12 @@ struct GSUBGPOS // http://lists.freedesktop.org/archives/harfbuzz/2012-November/002660.html continue; - if (f.featureParams.is_null () - && !f.intersects_lookup_indexes (lookup_indices) + + if (!f.featureParams.is_null () && + tag == HB_TAG ('s', 'i', 'z', 'e')) + continue; + + if (!f.intersects_lookup_indexes (lookup_indices) #ifndef HB_NO_VAR && !alternate_feature_indices.has (i) #endif @@ -3823,7 +3918,7 @@ struct GSUBGPOS template <typename T> struct accelerator_t { - void init (hb_face_t *face) + accelerator_t (hb_face_t *face) { this->table = hb_sanitize_context_t ().reference_table<T> (face); if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face))) @@ -3845,8 +3940,7 @@ struct GSUBGPOS for (unsigned int i = 0; i < this->lookup_count; i++) this->accels[i].init (table->get_lookup (i)); } - - void fini () + ~accelerator_t () { for (unsigned int i = 0; i < this->lookup_count; i++) this->accels[i].fini (); diff --git a/thirdparty/harfbuzz/src/hb-ot-layout.cc b/thirdparty/harfbuzz/src/hb-ot-layout.cc index fbdedd0e20..07bbe3bc84 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout.cc +++ b/thirdparty/harfbuzz/src/hb-ot-layout.cc @@ -361,6 +361,13 @@ hb_ot_layout_get_attach_points (hb_face_t *face, * Fetches a list of the caret positions defined for a ligature glyph in the GDEF * table of the font. The list returned will begin at the offset provided. * + * Note that a ligature that is formed from n characters will have n-1 + * caret positions. The first character is not represented in the array, + * since its caret position is the glyph position. + * + * The positions returned by this function are 'unshaped', and will have to + * be fixed up for kerning that may be applied to the ligature glyph. + * * Return value: Total number of ligature caret positions for @glyph. * **/ @@ -1491,10 +1498,9 @@ hb_ot_layout_lookup_substitute_closure (hb_face_t *face, unsigned int lookup_index, hb_set_t *glyphs /* OUT */) { - hb_set_t cur_intersected_glyphs; hb_map_t done_lookups_glyph_count; - hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> done_lookups_glyph_set; - OT::hb_closure_context_t c (face, glyphs, &cur_intersected_glyphs, &done_lookups_glyph_count, &done_lookups_glyph_set); + hb_hashmap_t<unsigned, hb_set_t *> done_lookups_glyph_set; + OT::hb_closure_context_t c (face, glyphs, &done_lookups_glyph_count, &done_lookups_glyph_set); const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index); @@ -1520,16 +1526,16 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face, const hb_set_t *lookups, hb_set_t *glyphs /* OUT */) { - hb_set_t cur_intersected_glyphs; hb_map_t done_lookups_glyph_count; - hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> done_lookups_glyph_set; - OT::hb_closure_context_t c (face, glyphs, &cur_intersected_glyphs, &done_lookups_glyph_count, &done_lookups_glyph_set); + hb_hashmap_t<unsigned, hb_set_t *> done_lookups_glyph_set; + OT::hb_closure_context_t c (face, glyphs, &done_lookups_glyph_count, &done_lookups_glyph_set); const OT::GSUB& gsub = *face->table.GSUB->table; unsigned int iteration_count = 0; unsigned int glyphs_length; do { + c.reset_lookup_visit_count (); glyphs_length = glyphs->get_population (); if (lookups) { @@ -1889,7 +1895,7 @@ apply_string (OT::hb_ot_apply_context_t *c, apply_forward (c, accel); if (!Proxy::inplace) - buffer->swap_buffers (); + buffer->sync (); } else { @@ -1961,13 +1967,84 @@ hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c, #ifndef HB_NO_BASE /** + * hb_ot_layout_get_horizontal_baseline_tag_for_script: + * @script: a script tag. + * + * Fetches the dominant horizontal baseline tag used by @script. + * + * Return value: dominant baseline tag for the @script. + * + * Since: 4.0.0 + **/ +hb_ot_layout_baseline_tag_t +hb_ot_layout_get_horizontal_baseline_tag_for_script (hb_script_t script) +{ + /* Keep in sync with hb_ot_layout_get_baseline_with_fallback */ + switch ((int) script) + { + /* Unicode-1.1 additions */ + case HB_SCRIPT_BENGALI: + case HB_SCRIPT_DEVANAGARI: + case HB_SCRIPT_GUJARATI: + case HB_SCRIPT_GURMUKHI: + /* Unicode-2.0 additions */ + case HB_SCRIPT_TIBETAN: + /* Unicode-4.0 additions */ + case HB_SCRIPT_LIMBU: + /* Unicode-4.1 additions */ + case HB_SCRIPT_SYLOTI_NAGRI: + /* Unicode-5.0 additions */ + case HB_SCRIPT_PHAGS_PA: + /* Unicode-5.2 additions */ + case HB_SCRIPT_MEETEI_MAYEK: + /* Unicode-6.1 additions */ + case HB_SCRIPT_SHARADA: + case HB_SCRIPT_TAKRI: + /* Unicode-7.0 additions */ + case HB_SCRIPT_MODI: + case HB_SCRIPT_SIDDHAM: + case HB_SCRIPT_TIRHUTA: + /* Unicode-9.0 additions */ + case HB_SCRIPT_MARCHEN: + case HB_SCRIPT_NEWA: + /* Unicode-10.0 additions */ + case HB_SCRIPT_SOYOMBO: + case HB_SCRIPT_ZANABAZAR_SQUARE: + /* Unicode-11.0 additions */ + case HB_SCRIPT_DOGRA: + case HB_SCRIPT_GUNJALA_GONDI: + /* Unicode-12.0 additions */ + case HB_SCRIPT_NANDINAGARI: + return HB_OT_LAYOUT_BASELINE_TAG_HANGING; + + /* Unicode-1.1 additions */ + case HB_SCRIPT_HANGUL: + case HB_SCRIPT_HAN: + case HB_SCRIPT_HIRAGANA: + case HB_SCRIPT_KATAKANA: + /* Unicode-3.0 additions */ + case HB_SCRIPT_BOPOMOFO: + /* Unicode-9.0 additions */ + case HB_SCRIPT_TANGUT: + /* Unicode-10.0 additions */ + case HB_SCRIPT_NUSHU: + /* Unicode-13.0 additions */ + case HB_SCRIPT_KHITAN_SMALL_SCRIPT: + return HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT; + + default: + return HB_OT_LAYOUT_BASELINE_TAG_ROMAN; + } +} + +/** * hb_ot_layout_get_baseline: * @font: a font * @baseline_tag: a baseline tag * @direction: text direction. * @script_tag: script tag. * @language_tag: language tag, currently unused. - * @coord: (out): baseline value if found. + * @coord: (out) (nullable): baseline value if found. * * Fetches a baseline value from the face. * @@ -1990,6 +2067,227 @@ hb_ot_layout_get_baseline (hb_font_t *font, return result; } + +/** + * hb_ot_layout_get_baseline_with_fallback: + * @font: a font + * @baseline_tag: a baseline tag + * @direction: text direction. + * @script_tag: script tag. + * @language_tag: language tag, currently unused. + * @coord: (out): baseline value if found. + * + * Fetches a baseline value from the face, and synthesizes + * it if the font does not have it. + * + * Since: 4.0.0 + **/ +void +hb_ot_layout_get_baseline_with_fallback (hb_font_t *font, + hb_ot_layout_baseline_tag_t baseline_tag, + hb_direction_t direction, + hb_tag_t script_tag, + hb_tag_t language_tag, + hb_position_t *coord /* OUT */) +{ + if (hb_ot_layout_get_baseline (font, + baseline_tag, + direction, + script_tag, + language_tag, + coord)) + return; + + /* Synthesize missing baselines. + * See https://www.w3.org/TR/css-inline-3/#baseline-synthesis-fonts + */ + switch (baseline_tag) + { + case HB_OT_LAYOUT_BASELINE_TAG_ROMAN: + *coord = 0; // FIXME origin ? + break; + + case HB_OT_LAYOUT_BASELINE_TAG_MATH: + { + hb_codepoint_t glyph; + hb_glyph_extents_t extents; + if (HB_DIRECTION_IS_HORIZONTAL (direction) && + (hb_font_get_nominal_glyph (font, 0x2212u, &glyph) || + hb_font_get_nominal_glyph (font, '-', &glyph)) && + hb_font_get_glyph_extents (font, glyph, &extents)) + { + *coord = extents.y_bearing + extents.height / 2; + } + else + { + hb_position_t x_height = 0; + hb_ot_metrics_get_position (font, HB_OT_METRICS_TAG_X_HEIGHT, &x_height); + *coord = x_height / 2; + } + } + break; + + case HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT: + case HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT: + { + hb_position_t embox_top, embox_bottom; + + hb_ot_layout_get_baseline_with_fallback (font, + HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT, + direction, + script_tag, + language_tag, + &embox_top); + hb_ot_layout_get_baseline_with_fallback (font, + HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT, + direction, + script_tag, + language_tag, + &embox_bottom); + + if (baseline_tag == HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT) + *coord = embox_top + (embox_bottom - embox_top) / 10; + else + *coord = embox_bottom + (embox_top - embox_bottom) / 10; + } + break; + + case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT: + if (hb_ot_layout_get_baseline (font, + HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT, + direction, + script_tag, + language_tag, + coord)) + *coord += HB_DIRECTION_IS_HORIZONTAL (direction) ? font->y_scale : font->x_scale; + else + { + hb_font_extents_t font_extents; + hb_font_get_extents_for_direction (font, direction, &font_extents); + *coord = font_extents.ascender; + } + break; + + case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT: + if (hb_ot_layout_get_baseline (font, + HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT, + direction, + script_tag, + language_tag, + coord)) + *coord -= HB_DIRECTION_IS_HORIZONTAL (direction) ? font->y_scale : font->x_scale; + else + { + hb_font_extents_t font_extents; + hb_font_get_extents_for_direction (font, direction, &font_extents); + *coord = font_extents.descender; + } + break; + + case HB_OT_LAYOUT_BASELINE_TAG_HANGING: + if (HB_DIRECTION_IS_HORIZONTAL (direction)) + { + hb_codepoint_t ch; + hb_codepoint_t glyph; + hb_glyph_extents_t extents; + + /* Keep in sync with hb_ot_layout_get_horizontal_baseline_for_script */ + switch ((int) script_tag) + { + /* Unicode-1.1 additions */ + case HB_SCRIPT_BENGALI: ch = 0x0995u; break; + case HB_SCRIPT_DEVANAGARI: ch = 0x0915u; break; + case HB_SCRIPT_GUJARATI: ch = 0x0a95u; break; + case HB_SCRIPT_GURMUKHI: ch = 0x0a15u; break; + /* Unicode-2.0 additions */ + case HB_SCRIPT_TIBETAN: ch = 0x0f40u; break; + /* Unicode-4.0 additions */ + case HB_SCRIPT_LIMBU: ch = 0x1901u; break; + /* Unicode-4.1 additions */ + case HB_SCRIPT_SYLOTI_NAGRI: ch = 0xa807u; break; + /* Unicode-5.0 additions */ + case HB_SCRIPT_PHAGS_PA: ch = 0xa840u; break; + /* Unicode-5.2 additions */ + case HB_SCRIPT_MEETEI_MAYEK: ch = 0xabc0u; break; + /* Unicode-6.1 additions */ + case HB_SCRIPT_SHARADA: ch = 0x11191u; break; + case HB_SCRIPT_TAKRI: ch = 0x1168cu; break; + /* Unicode-7.0 additions */ + case HB_SCRIPT_MODI: ch = 0x1160eu;break; + case HB_SCRIPT_SIDDHAM: ch = 0x11590u; break; + case HB_SCRIPT_TIRHUTA: ch = 0x1148fu; break; + /* Unicode-9.0 additions */ + case HB_SCRIPT_MARCHEN: ch = 0x11c72u; break; + case HB_SCRIPT_NEWA: ch = 0x1140eu; break; + /* Unicode-10.0 additions */ + case HB_SCRIPT_SOYOMBO: ch = 0x11a5cu; break; + case HB_SCRIPT_ZANABAZAR_SQUARE: ch = 0x11a0bu; break; + /* Unicode-11.0 additions */ + case HB_SCRIPT_DOGRA: ch = 0x1180au; break; + case HB_SCRIPT_GUNJALA_GONDI: ch = 0x11d6cu; break; + /* Unicode-12.0 additions */ + case HB_SCRIPT_NANDINAGARI: ch = 0x119b0u; break; + default: ch = 0; break; + } + + if (ch && + hb_font_get_nominal_glyph (font, ch, &glyph) && + hb_font_get_glyph_extents (font, glyph, &extents)) + *coord = extents.y_bearing; + else + *coord = font->y_scale * 6 / 10; // FIXME makes assumptions about origin + } + else + *coord = font->x_scale * 6 / 10; // FIXME makes assumptions about origin + break; + + case HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL: + { + hb_position_t top, bottom; + hb_ot_layout_get_baseline_with_fallback (font, + HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT, + direction, + script_tag, + language_tag, + &top); + hb_ot_layout_get_baseline_with_fallback (font, + HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT, + direction, + script_tag, + language_tag, + &bottom); + *coord = (top + bottom) / 2; + + } + break; + + case HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_CENTRAL: + { + hb_position_t top, bottom; + hb_ot_layout_get_baseline_with_fallback (font, + HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT, + direction, + script_tag, + language_tag, + &top); + hb_ot_layout_get_baseline_with_fallback (font, + HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT, + direction, + script_tag, + language_tag, + &bottom); + *coord = (top + bottom) / 2; + + } + break; + + case _HB_OT_LAYOUT_BASELINE_TAG_MAX_VALUE: + default: + *coord = 0; + break; + } +} + #endif diff --git a/thirdparty/harfbuzz/src/hb-ot-layout.h b/thirdparty/harfbuzz/src/hb-ot-layout.h index d47ba0fc92..4edddd9e0d 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout.h +++ b/thirdparty/harfbuzz/src/hb-ot-layout.h @@ -332,31 +332,6 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t *face, hb_set_t *glyphs_after, /* OUT. May be NULL */ hb_set_t *glyphs_output /* OUT. May be NULL */); -#ifdef HB_NOT_IMPLEMENTED -typedef struct -{ - const hb_codepoint_t *before, - unsigned int before_length, - const hb_codepoint_t *input, - unsigned int input_length, - const hb_codepoint_t *after, - unsigned int after_length, -} hb_ot_layout_glyph_sequence_t; - -typedef hb_bool_t -(*hb_ot_layout_glyph_sequence_func_t) (hb_font_t *font, - hb_tag_t table_tag, - unsigned int lookup_index, - const hb_ot_layout_glyph_sequence_t *sequence, - void *user_data); - -HB_EXTERN void -Xhb_ot_layout_lookup_enumerate_sequences (hb_face_t *face, - hb_tag_t table_tag, - unsigned int lookup_index, - hb_ot_layout_glyph_sequence_func_t callback, - void *user_data); -#endif /* Variations support */ @@ -411,19 +386,6 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face, hb_set_t *glyphs); -#ifdef HB_NOT_IMPLEMENTED -/* Note: You better have GDEF when using this API, or marks won't do much. */ -HB_EXTERN hb_bool_t -Xhb_ot_layout_lookup_substitute (hb_font_t *font, - unsigned int lookup_index, - const hb_ot_layout_glyph_sequence_t *sequence, - unsigned int out_size, - hb_codepoint_t *glyphs_out, /* OUT */ - unsigned int *clusters_out, /* OUT */ - unsigned int *out_length /* OUT */); -#endif - - /* * GPOS */ @@ -431,15 +393,6 @@ Xhb_ot_layout_lookup_substitute (hb_font_t *font, HB_EXTERN hb_bool_t hb_ot_layout_has_positioning (hb_face_t *face); -#ifdef HB_NOT_IMPLEMENTED -/* Note: You better have GDEF when using this API, or marks won't do much. */ -HB_EXTERN hb_bool_t -Xhb_ot_layout_lookup_position (hb_font_t *font, - unsigned int lookup_index, - const hb_ot_layout_glyph_sequence_t *sequence, - hb_glyph_position_t *positions /* IN / OUT */); -#endif - /* Optical 'size' feature info. Returns true if found. * https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */ HB_EXTERN hb_bool_t @@ -487,9 +440,11 @@ hb_ot_layout_feature_get_characters (hb_face_t *face, * if the direction is horizontal or vertical, respectively. * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT: Ideographic character face top or right edge, * if the direction is horizontal or vertical, respectively. + * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_CENTRAL: The center of the ideographic character face. Since: 4.0.0 * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT: Ideographic em-box bottom or left edge, * if the direction is horizontal or vertical, respectively. * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT: Ideographic em-box top or right edge baseline, + * @HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL: The center of the ideographic em-box. Since: 4.0.0 * if the direction is horizontal or vertical, respectively. * @HB_OT_LAYOUT_BASELINE_TAG_MATH: The baseline about which mathematical characters are centered. * In vertical writing mode when mathematical characters rotated 90 degrees clockwise, are centered. @@ -503,14 +458,19 @@ typedef enum { HB_OT_LAYOUT_BASELINE_TAG_HANGING = HB_TAG ('h','a','n','g'), HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_BOTTOM_OR_LEFT = HB_TAG ('i','c','f','b'), HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_TOP_OR_RIGHT = HB_TAG ('i','c','f','t'), + HB_OT_LAYOUT_BASELINE_TAG_IDEO_FACE_CENTRAL = HB_TAG ('I','c','f','c'), HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_BOTTOM_OR_LEFT = HB_TAG ('i','d','e','o'), HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_TOP_OR_RIGHT = HB_TAG ('i','d','t','p'), + HB_OT_LAYOUT_BASELINE_TAG_IDEO_EMBOX_CENTRAL = HB_TAG ('I','d','c','e'), HB_OT_LAYOUT_BASELINE_TAG_MATH = HB_TAG ('m','a','t','h'), /*< private >*/ _HB_OT_LAYOUT_BASELINE_TAG_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/ } hb_ot_layout_baseline_tag_t; +HB_EXTERN hb_ot_layout_baseline_tag_t +hb_ot_layout_get_horizontal_baseline_tag_for_script (hb_script_t script); + HB_EXTERN hb_bool_t hb_ot_layout_get_baseline (hb_font_t *font, hb_ot_layout_baseline_tag_t baseline_tag, @@ -519,6 +479,14 @@ hb_ot_layout_get_baseline (hb_font_t *font, hb_tag_t language_tag, hb_position_t *coord /* OUT. May be NULL. */); +HB_EXTERN void +hb_ot_layout_get_baseline_with_fallback (hb_font_t *font, + hb_ot_layout_baseline_tag_t baseline_tag, + hb_direction_t direction, + hb_tag_t script_tag, + hb_tag_t language_tag, + hb_position_t *coord /* OUT */); + HB_END_DECLS #endif /* HB_OT_LAYOUT_H */ diff --git a/thirdparty/harfbuzz/src/hb-ot-layout.hh b/thirdparty/harfbuzz/src/hb-ot-layout.hh index b15d053835..ede8f007db 100644 --- a/thirdparty/harfbuzz/src/hb-ot-layout.hh +++ b/thirdparty/harfbuzz/src/hb-ot-layout.hh @@ -350,24 +350,20 @@ _hb_glyph_info_is_continuation (const hb_glyph_info_t *info) { return info->unicode_props() & UPROPS_MASK_CONTINUATION; } -/* Loop over grapheme. Based on foreach_cluster(). */ -#define foreach_grapheme(buffer, start, end) \ - for (unsigned int \ - _count = buffer->len, \ - start = 0, end = _count ? _hb_next_grapheme (buffer, 0) : 0; \ - start < _count; \ - start = end, end = _hb_next_grapheme (buffer, start)) -static inline unsigned int -_hb_next_grapheme (hb_buffer_t *buffer, unsigned int start) -{ - hb_glyph_info_t *info = buffer->info; - unsigned int count = buffer->len; +static inline bool +_hb_grapheme_group_func (const hb_glyph_info_t& a HB_UNUSED, + const hb_glyph_info_t& b) +{ return _hb_glyph_info_is_continuation (&b); } - while (++start < count && _hb_glyph_info_is_continuation (&info[start])) - ; +#define foreach_grapheme(buffer, start, end) \ + foreach_group (buffer, start, end, _hb_grapheme_group_func) - return start; +static inline void +_hb_ot_layout_reverse_graphemes (hb_buffer_t *buffer) +{ + buffer->reverse_groups (_hb_grapheme_group_func, + buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS); } static inline bool @@ -486,10 +482,9 @@ _hb_glyph_info_get_lig_num_comps (const hb_glyph_info_t *info) } static inline uint8_t -_hb_allocate_lig_id (hb_buffer_t *buffer) { +_hb_allocate_lig_id (hb_buffer_t *buffer) +{ uint8_t lig_id = buffer->next_serial () & 0x07; - if (unlikely (!lig_id)) - lig_id = _hb_allocate_lig_id (buffer); /* in case of overflow */ return lig_id; } diff --git a/thirdparty/harfbuzz/src/hb-ot-math-table.hh b/thirdparty/harfbuzz/src/hb-ot-math-table.hh index c2e365dbd6..d834d94371 100644 --- a/thirdparty/harfbuzz/src/hb-ot-math-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-math-table.hh @@ -369,6 +369,37 @@ struct MathKern return kernValue[i].get_x_value (font, this); } + unsigned int get_entries (unsigned int start_offset, + unsigned int *entries_count, /* IN/OUT */ + hb_ot_math_kern_entry_t *kern_entries, /* OUT */ + hb_font_t *font) const + { + const MathValueRecord* correctionHeight = mathValueRecordsZ.arrayZ; + const MathValueRecord* kernValue = mathValueRecordsZ.arrayZ + heightCount; + const unsigned int entriesCount = heightCount + 1; + + if (entries_count) + { + unsigned int start = hb_min (start_offset, entriesCount); + unsigned int end = hb_min (start + *entries_count, entriesCount); + *entries_count = end - start; + + for (unsigned int i = 0; i < *entries_count; i++) { + unsigned int j = start + i; + + hb_position_t max_height; + if (j == heightCount) { + max_height = INT32_MAX; + } else { + max_height = correctionHeight[j].get_y_value (font, this); + } + + kern_entries[i] = {max_height, kernValue[j].get_x_value (font, this)}; + } + } + return entriesCount; + } + protected: HBUINT16 heightCount; UnsizedArrayOf<MathValueRecord> @@ -423,6 +454,24 @@ struct MathKernInfoRecord return (base+mathKern[idx]).get_value (correction_height, font); } + unsigned int get_kernings (hb_ot_math_kern_t kern, + unsigned int start_offset, + unsigned int *entries_count, /* IN/OUT */ + hb_ot_math_kern_entry_t *kern_entries, /* OUT */ + hb_font_t *font, + const void *base) const + { + unsigned int idx = kern; + if (unlikely (idx >= ARRAY_LENGTH (mathKern)) || !mathKern[idx]) { + if (entries_count) *entries_count = 0; + return 0; + } + return (base+mathKern[idx]).get_entries (start_offset, + entries_count, + kern_entries, + font); + } + protected: /* Offset to MathKern table for each corner - * from the beginning of MathKernInfo table. May be NULL. */ @@ -473,6 +522,22 @@ struct MathKernInfo return mathKernInfoRecords[index].get_kerning (kern, correction_height, font, this); } + unsigned int get_kernings (hb_codepoint_t glyph, + hb_ot_math_kern_t kern, + unsigned int start_offset, + unsigned int *entries_count, /* IN/OUT */ + hb_ot_math_kern_entry_t *kern_entries, /* OUT */ + hb_font_t *font) const + { + unsigned int index = (this+mathKernCoverage).get_coverage (glyph); + return mathKernInfoRecords[index].get_kernings (kern, + start_offset, + entries_count, + kern_entries, + font, + this); + } + protected: Offset16To<Coverage> mathKernCoverage; @@ -511,7 +576,8 @@ struct MathGlyphInfo | hb_map_retains_sorting (glyph_map) ; - out->extendedShapeCoverage.serialize_serialize (c->serializer, it); + if (it) out->extendedShapeCoverage.serialize_serialize (c->serializer, it); + else out->extendedShapeCoverage = 0; out->mathKernInfo.serialize_subset (c, mathKernInfo, this); return_trace (true); @@ -544,6 +610,19 @@ struct MathGlyphInfo hb_font_t *font) const { return (this+mathKernInfo).get_kerning (glyph, kern, correction_height, font); } + hb_position_t get_kernings (hb_codepoint_t glyph, + hb_ot_math_kern_t kern, + unsigned int start_offset, + unsigned int *entries_count, /* IN/OUT */ + hb_ot_math_kern_entry_t *kern_entries, /* OUT */ + hb_font_t *font) const + { return (this+mathKernInfo).get_kernings (glyph, + kern, + start_offset, + entries_count, + kern_entries, + font); } + protected: /* Offset to MathItalicsCorrectionInfo table - * from the beginning of MathGlyphInfo table. */ @@ -884,8 +963,11 @@ struct MathVariants if (!o) return_trace (false); o->serialize_subset (c, glyphConstruction[i], this); } - - out->vertGlyphCoverage.serialize_serialize (c->serializer, new_vert_coverage.iter ()); + + if (new_vert_coverage) + out->vertGlyphCoverage.serialize_serialize (c->serializer, new_vert_coverage.iter ()); + + if (new_hori_coverage) out->horizGlyphCoverage.serialize_serialize (c->serializer, new_hori_coverage.iter ()); return_trace (true); } diff --git a/thirdparty/harfbuzz/src/hb-ot-math.cc b/thirdparty/harfbuzz/src/hb-ot-math.cc index 5781d25f2a..f44ac35849 100644 --- a/thirdparty/harfbuzz/src/hb-ot-math.cc +++ b/thirdparty/harfbuzz/src/hb-ot-math.cc @@ -185,6 +185,51 @@ hb_ot_math_get_glyph_kerning (hb_font_t *font, } /** + * hb_ot_math_get_glyph_kernings: + * @font: #hb_font_t to work upon + * @glyph: The glyph index from which to retrieve the kernings + * @kern: The #hb_ot_math_kern_t from which to retrieve the kernings + * @start_offset: offset of the first kern entry to retrieve + * @entries_count: (inout) (optional): Input = the maximum number of kern entries to return; + * Output = the actual number of kern entries returned + * @kern_entries: (out caller-allocates) (array length=entries_count): array of kern entries returned + * + * Fetches the raw MathKern (cut-in) data for the specified font, glyph index, + * and @kern. The corresponding list of kern values and correction heights is + * returned as a list of #hb_ot_math_kern_entry_t structs. + * + * See also #hb_ot_math_get_glyph_kerning, which handles selecting the + * appropriate kern value for a given correction height. + * + * <note>For a glyph with @n defined kern values (where @n > 0), there are only + * @n−1 defined correction heights, as each correction height defines a boundary + * past which the next kern value should be selected. Therefore, only the + * #hb_ot_math_kern_entry_t.kern_value of the uppermost #hb_ot_math_kern_entry_t + * actually comes from the font; its corresponding + * #hb_ot_math_kern_entry_t.max_correction_height is always set to + * <code>INT32_MAX</code>.</note> + * + * Return value: the total number of kern values available or zero + * + * Since: 3.4.0 + **/ +unsigned int +hb_ot_math_get_glyph_kernings (hb_font_t *font, + hb_codepoint_t glyph, + hb_ot_math_kern_t kern, + unsigned int start_offset, + unsigned int *entries_count, /* IN/OUT */ + hb_ot_math_kern_entry_t *kern_entries /* OUT */) +{ + return font->face->table.MATH->get_glyph_info().get_kernings (glyph, + kern, + start_offset, + entries_count, + kern_entries, + font); +} + +/** * hb_ot_math_get_glyph_variants: * @font: #hb_font_t to work upon * @glyph: The index of the glyph to stretch diff --git a/thirdparty/harfbuzz/src/hb-ot-math.h b/thirdparty/harfbuzz/src/hb-ot-math.h index d3ffa19d85..1378a0639a 100644 --- a/thirdparty/harfbuzz/src/hb-ot-math.h +++ b/thirdparty/harfbuzz/src/hb-ot-math.h @@ -50,14 +50,18 @@ HB_BEGIN_DECLS #define HB_OT_TAG_MATH HB_TAG('M','A','T','H') /** - * HB_OT_MATH_SCRIPT: + * HB_OT_TAG_MATH_SCRIPT: * - * OpenType script tag for math shaping, for use with - * Use with hb_buffer_set_script(). + * OpenType script tag, `math`, for features specific to math shaping. * - * Since: 1.3.3 + * <note>#HB_OT_TAG_MATH_SCRIPT is not a valid #hb_script_t and should only be + * used with functions that accept raw OpenType script tags, such as + * #hb_ot_layout_collect_features. In other cases, #HB_SCRIPT_MATH should be + * used instead.</note> + * + * Since: 3.4.0 */ -#define HB_OT_MATH_SCRIPT HB_TAG('m','a','t','h') +#define HB_OT_TAG_MATH_SCRIPT HB_TAG('m','a','t','h') /* Types */ @@ -205,6 +209,20 @@ typedef enum { } hb_ot_math_kern_t; /** + * hb_ot_math_kern_entry_t: + * @max_correction_height: The maximum height at which this entry should be used + * @kern_value: The kern value of the entry + * + * Data type to hold math kerning (cut-in) information for a glyph. + * + * Since: 3.4.0 + */ +typedef struct { + hb_position_t max_correction_height; + hb_position_t kern_value; +} hb_ot_math_kern_entry_t; + +/** * hb_ot_math_glyph_variant_t: * @glyph: The glyph index of the variant * @advance: The advance width of the variant @@ -281,6 +299,14 @@ hb_ot_math_get_glyph_kerning (hb_font_t *font, hb_position_t correction_height); HB_EXTERN unsigned int +hb_ot_math_get_glyph_kernings (hb_font_t *font, + hb_codepoint_t glyph, + hb_ot_math_kern_t kern, + unsigned int start_offset, + unsigned int *entries_count, /* IN/OUT */ + hb_ot_math_kern_entry_t *kern_entries /* OUT */); + +HB_EXTERN unsigned int hb_ot_math_get_glyph_variants (hb_font_t *font, hb_codepoint_t glyph, hb_direction_t direction, diff --git a/thirdparty/harfbuzz/src/hb-ot-meta-table.hh b/thirdparty/harfbuzz/src/hb-ot-meta-table.hh index e31447f8fc..93e64c5327 100644 --- a/thirdparty/harfbuzz/src/hb-ot-meta-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-meta-table.hh @@ -71,9 +71,9 @@ struct meta struct accelerator_t { - void init (hb_face_t *face) + accelerator_t (hb_face_t *face) { table = hb_sanitize_context_t ().reference_table<meta> (face); } - void fini () { table.destroy (); } + ~accelerator_t () { table.destroy (); } hb_blob_t *reference_entry (hb_tag_t tag) const { return table->dataMaps.lsearch (tag).reference_entry (table.get_blob ()); } @@ -119,7 +119,9 @@ struct meta DEFINE_SIZE_ARRAY (16, dataMaps); }; -struct meta_accelerator_t : meta::accelerator_t {}; +struct meta_accelerator_t : meta::accelerator_t { + meta_accelerator_t (hb_face_t *face) : meta::accelerator_t (face) {} +}; } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/hb-ot-metrics.cc b/thirdparty/harfbuzz/src/hb-ot-metrics.cc index 72aeff82d6..43c3cbd41f 100644 --- a/thirdparty/harfbuzz/src/hb-ot-metrics.cc +++ b/thirdparty/harfbuzz/src/hb-ot-metrics.cc @@ -77,6 +77,7 @@ _hb_ot_metrics_get_position_common (hb_font_t *font, (face->table.TABLE->has_data () && \ (position && (*position = font->em_scalef_y (_fix_ascender_descender ( \ face->table.TABLE->ATTR + GET_VAR, metrics_tag))), true)) + case HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER: return (face->table.OS2->use_typo_metrics () && GET_METRIC_Y (OS2, sTypoAscender)) || GET_METRIC_Y (hhea, ascender); @@ -86,9 +87,13 @@ _hb_ot_metrics_get_position_common (hb_font_t *font, case HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP: return (face->table.OS2->use_typo_metrics () && GET_METRIC_Y (OS2, sTypoLineGap)) || GET_METRIC_Y (hhea, lineGap); + +#ifndef HB_NO_VERTICAL case HB_OT_METRICS_TAG_VERTICAL_ASCENDER: return GET_METRIC_X (vhea, ascender); case HB_OT_METRICS_TAG_VERTICAL_DESCENDER: return GET_METRIC_X (vhea, descender); case HB_OT_METRICS_TAG_VERTICAL_LINE_GAP: return GET_METRIC_X (vhea, lineGap); +#endif + #undef GET_METRIC_Y #undef GET_METRIC_X #undef GET_VAR @@ -155,12 +160,55 @@ hb_ot_metrics_get_position (hb_font_t *font, (position && (*position = font->em_scalef_y (face->table.TABLE->ATTR + GET_VAR)), true)) case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT: return GET_METRIC_Y (OS2, usWinAscent); case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT: return GET_METRIC_Y (OS2, usWinDescent); - case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE: return GET_METRIC_Y (hhea, caretSlopeRise); - case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN: return GET_METRIC_X (hhea, caretSlopeRun); + + case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE: + case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN: + { + unsigned mult = 1u; + + if (font->slant) + { + unsigned rise = face->table.hhea->caretSlopeRise; + unsigned upem = face->get_upem (); + mult = (rise && rise < upem) ? hb_min (upem / rise, 256u) : 1u; + } + + if (metrics_tag == HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE) + { + bool ret = GET_METRIC_Y (hhea, caretSlopeRise); + + if (position) + *position *= mult; + + return ret; + } + else + { + hb_position_t rise = 0; + + if (font->slant && position && GET_METRIC_Y (hhea, caretSlopeRise)) + rise = *position; + + bool ret = GET_METRIC_X (hhea, caretSlopeRun); + + if (position) + { + *position *= mult; + + if (font->slant) + *position += _hb_roundf (mult * font->slant_xy * rise); + } + + return ret; + } + } case HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET: return GET_METRIC_X (hhea, caretOffset); + +#ifndef HB_NO_VERTICAL case HB_OT_METRICS_TAG_VERTICAL_CARET_RISE: return GET_METRIC_X (vhea, caretSlopeRise); case HB_OT_METRICS_TAG_VERTICAL_CARET_RUN: return GET_METRIC_Y (vhea, caretSlopeRun); case HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET: return GET_METRIC_Y (vhea, caretOffset); +#endif case HB_OT_METRICS_TAG_X_HEIGHT: return GET_METRIC_Y (OS2->v2 (), sxHeight); case HB_OT_METRICS_TAG_CAP_HEIGHT: return GET_METRIC_Y (OS2->v2 (), sCapHeight); case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE: return GET_METRIC_X (OS2, ySubscriptXSize); @@ -190,6 +238,145 @@ hb_ot_metrics_get_position (hb_font_t *font, } } +/** + * hb_ot_metrics_get_position_with_fallback: + * @font: an #hb_font_t object. + * @metrics_tag: tag of metrics value you like to fetch. + * @position: (out) (optional): result of metrics value from the font. + * + * Fetches metrics value corresponding to @metrics_tag from @font, + * and synthesizes a value if it the value is missing in the font. + * + * Since: 4.0.0 + **/ +void +hb_ot_metrics_get_position_with_fallback (hb_font_t *font, + hb_ot_metrics_tag_t metrics_tag, + hb_position_t *position /* OUT */) +{ + hb_font_extents_t font_extents; + hb_codepoint_t glyph; + hb_glyph_extents_t extents; + + if (hb_ot_metrics_get_position (font, metrics_tag, position)) + { + if ((metrics_tag != HB_OT_METRICS_TAG_STRIKEOUT_SIZE && + metrics_tag != HB_OT_METRICS_TAG_UNDERLINE_SIZE) || + *position != 0) + return; + } + + switch (metrics_tag) + { + case HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER: + case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_ASCENT: + hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents); + *position = font_extents.ascender; + break; + + case HB_OT_METRICS_TAG_VERTICAL_ASCENDER: + hb_font_get_extents_for_direction (font, HB_DIRECTION_TTB, &font_extents); + *position = font_extents.ascender; + break; + + case HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER: + case HB_OT_METRICS_TAG_HORIZONTAL_CLIPPING_DESCENT: + hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents); + *position = font_extents.descender; + break; + + case HB_OT_METRICS_TAG_VERTICAL_DESCENDER: + hb_font_get_extents_for_direction (font, HB_DIRECTION_TTB, &font_extents); + *position = font_extents.ascender; + break; + + case HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP: + hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents); + *position = font_extents.line_gap; + break; + + case HB_OT_METRICS_TAG_VERTICAL_LINE_GAP: + hb_font_get_extents_for_direction (font, HB_DIRECTION_TTB, &font_extents); + *position = font_extents.line_gap; + break; + + case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RISE: + case HB_OT_METRICS_TAG_VERTICAL_CARET_RISE: + *position = 1; + break; + + case HB_OT_METRICS_TAG_HORIZONTAL_CARET_RUN: + case HB_OT_METRICS_TAG_VERTICAL_CARET_RUN: + *position = 0; + break; + + case HB_OT_METRICS_TAG_HORIZONTAL_CARET_OFFSET: + case HB_OT_METRICS_TAG_VERTICAL_CARET_OFFSET: + *position = 0; + break; + + case HB_OT_METRICS_TAG_X_HEIGHT: + if (hb_font_get_nominal_glyph (font, 'o', &glyph) && + hb_font_get_glyph_extents (font, glyph, &extents)) + *position = extents.height + 2 * extents.y_bearing; + else + *position = font->y_scale / 2; + break; + + case HB_OT_METRICS_TAG_CAP_HEIGHT: + if (hb_font_get_nominal_glyph (font, 'O', &glyph) && + hb_font_get_glyph_extents (font, glyph, &extents)) + *position = extents.height + 2 * extents.y_bearing; + else + *position = font->y_scale * 2 / 3; + break; + + case HB_OT_METRICS_TAG_STRIKEOUT_SIZE: + case HB_OT_METRICS_TAG_UNDERLINE_SIZE: + *position = font->y_scale / 18; + break; + + case HB_OT_METRICS_TAG_STRIKEOUT_OFFSET: + { + hb_position_t ascender; + hb_ot_metrics_get_position_with_fallback (font, + HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, + &ascender); + *position = ascender / 2; + } + break; + + case HB_OT_METRICS_TAG_UNDERLINE_OFFSET: + *position = - font->y_scale / 18; + break; + + case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_SIZE: + case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_SIZE: + *position = font->x_scale * 10 / 12; + break; + + case HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_SIZE: + case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_SIZE: + *position = font->y_scale * 10 / 12; + break; + + case HB_OT_METRICS_TAG_SUBSCRIPT_EM_X_OFFSET: + case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_X_OFFSET: + *position = 0; + break; + + case HB_OT_METRICS_TAG_SUBSCRIPT_EM_Y_OFFSET: + case HB_OT_METRICS_TAG_SUPERSCRIPT_EM_Y_OFFSET: + *position = font->y_scale / 5; + break; + + case _HB_OT_METRICS_TAG_MAX_VALUE: + default: + *position = 0; + break; + } +} + #ifndef HB_NO_VAR /** * hb_ot_metrics_get_variation: diff --git a/thirdparty/harfbuzz/src/hb-ot-metrics.h b/thirdparty/harfbuzz/src/hb-ot-metrics.h index 5841fc8b0f..30de500088 100644 --- a/thirdparty/harfbuzz/src/hb-ot-metrics.h +++ b/thirdparty/harfbuzz/src/hb-ot-metrics.h @@ -110,6 +110,11 @@ hb_ot_metrics_get_position (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag, hb_position_t *position /* OUT. May be NULL. */); +HB_EXTERN void +hb_ot_metrics_get_position_with_fallback (hb_font_t *font, + hb_ot_metrics_tag_t metrics_tag, + hb_position_t *position /* OUT */); + HB_EXTERN float hb_ot_metrics_get_variation (hb_font_t *font, hb_ot_metrics_tag_t metrics_tag); diff --git a/thirdparty/harfbuzz/src/hb-ot-name-table.hh b/thirdparty/harfbuzz/src/hb-ot-name-table.hh index c17bb4abb8..d52367e9b1 100644 --- a/thirdparty/harfbuzz/src/hb-ot-name-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-name-table.hh @@ -256,7 +256,7 @@ struct name }) ; - name_prime->serialize (c->serializer, it, hb_addressof (this + stringOffset)); + name_prime->serialize (c->serializer, it, std::addressof (this + stringOffset)); return_trace (name_prime->count); } @@ -279,7 +279,7 @@ struct name struct accelerator_t { - void init (hb_face_t *face) + accelerator_t (hb_face_t *face) { this->table = hb_sanitize_context_t ().reference_table<name> (face); assert (this->table.get_length () >= this->table->stringOffset); @@ -288,7 +288,6 @@ struct name const hb_array_t<const NameRecord> all_names (this->table->nameRecordZ.arrayZ, this->table->count); - this->names.init (); this->names.alloc (all_names.length); for (unsigned int i = 0; i < all_names.length; i++) @@ -318,10 +317,8 @@ struct name } this->names.resize (j); } - - void fini () + ~accelerator_t () { - this->names.fini (); this->table.destroy (); } @@ -373,7 +370,9 @@ struct name #undef entry_index #undef entry_score -struct name_accelerator_t : name::accelerator_t {}; +struct name_accelerator_t : name::accelerator_t { + name_accelerator_t (hb_face_t *face) : name::accelerator_t (face) {} +}; } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/hb-ot-name.cc b/thirdparty/harfbuzz/src/hb-ot-name.cc index eff46ef227..c35ac5b3dc 100644 --- a/thirdparty/harfbuzz/src/hb-ot-name.cc +++ b/thirdparty/harfbuzz/src/hb-ot-name.cc @@ -52,7 +52,7 @@ * array is owned by the @face and should not be modified. It can be * used as long as @face is alive. * - * Returns: (out) (transfer none) (array length=num_entries): Array of available name entries. + * Returns: (transfer none) (array length=num_entries): Array of available name entries. * Since: 2.1.0 **/ const hb_ot_name_entry_t * diff --git a/thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh b/thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh index 94450eb53a..0f3cd8e24f 100644 --- a/thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh +++ b/thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh @@ -76,9 +76,9 @@ HB_INTERNAL bool postV2Tail::subset (hb_subset_context_t *c) const hb_map_t old_new_index_map, old_gid_new_index_map; unsigned i = 0; - post::accelerator_t _post; - _post.init (c->plan->source); + post::accelerator_t _post (c->plan->source); + hb_hashmap_t<hb_bytes_t, unsigned, std::nullptr_t, unsigned, nullptr, (unsigned)-1> glyph_name_to_new_index; for (hb_codepoint_t new_gid = 0; new_gid < num_glyphs; new_gid++) { hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid); @@ -90,22 +90,28 @@ HB_INTERNAL bool postV2Tail::subset (hb_subset_context_t *c) const else { hb_bytes_t s = _post.find_glyph_name (old_gid); - int standard_glyph_index = -1; - for (unsigned i = 0; i < format1_names_length; i++) + new_index = glyph_name_to_new_index.get (s); + if (new_index == (unsigned)-1) { - if (s == format1_names (i)) + int standard_glyph_index = -1; + for (unsigned i = 0; i < format1_names_length; i++) { - standard_glyph_index = i; - break; + if (s == format1_names (i)) + { + standard_glyph_index = i; + break; + } } + + if (standard_glyph_index == -1) + { + new_index = 258 + i; + i++; + } + else + { new_index = standard_glyph_index; } + glyph_name_to_new_index.set (s, new_index); } - if (standard_glyph_index == -1) - { - new_index = 258 + i; - i++; - } - else - { new_index = standard_glyph_index; } old_new_index_map.set (old_index, new_index); } old_gid_new_index_map.set (old_gid, new_index); @@ -121,9 +127,7 @@ HB_INTERNAL bool postV2Tail::subset (hb_subset_context_t *c) const }) ; - bool ret = serialize (c->serializer, index_iter, &_post); - _post.fini (); - return_trace (ret); + return_trace (serialize (c->serializer, index_iter, &_post)); } } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/hb-ot-post-table.hh b/thirdparty/harfbuzz/src/hb-ot-post-table.hh index 39de671707..a4844e94bc 100644 --- a/thirdparty/harfbuzz/src/hb-ot-post-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-post-table.hh @@ -111,10 +111,9 @@ struct post struct accelerator_t { friend struct postV2Tail; - void init (hb_face_t *face) - { - index_to_offset.init (); + accelerator_t (hb_face_t *face) + { table = hb_sanitize_context_t ().reference_table<post> (face); unsigned int table_length = table.get_length (); @@ -132,9 +131,8 @@ struct post data += 1 + *data) index_to_offset.push (data - pool); } - void fini () + ~accelerator_t () { - index_to_offset.fini (); hb_free (gids_sorted_by_name.get ()); table.destroy (); } @@ -254,9 +252,9 @@ struct post private: uint32_t version; - const Array16Of<HBUINT16> *glyphNameIndex; + const Array16Of<HBUINT16> *glyphNameIndex = nullptr; hb_vector_t<uint32_t> index_to_offset; - const uint8_t *pool; + const uint8_t *pool = nullptr; hb_atomic_ptr_t<uint16_t *> gids_sorted_by_name; }; @@ -307,7 +305,10 @@ struct post DEFINE_SIZE_MIN (32); }; -struct post_accelerator_t : post::accelerator_t {}; +struct post_accelerator_t : post::accelerator_t { + post_accelerator_t (hb_face_t *face) : post::accelerator_t (face) {} +}; + } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-win1256.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-win1256.hh index 41e3dd38ab..429974d05b 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-win1256.hh +++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-win1256.hh @@ -87,6 +87,8 @@ #define OT_GLYPHID /* GlyphID */ \ OT_UINT16 +/* Shorthand. */ +#define G OT_GLYPHID #define OT_UARRAY(Name, Items) \ OT_LABEL_START(Name) \ @@ -183,8 +185,6 @@ Tag \ OT_OFFSET(manifest, Name) -/* Shorthand. */ -#define G OT_GLYPHID /* * Table Start @@ -300,14 +300,40 @@ OT_TABLE_END /* * Clean up */ + +#undef MANIFEST +#undef MANIFEST_LOOKUP + #undef OT_TABLE_START #undef OT_TABLE_END #undef OT_LABEL_START #undef OT_LABEL_END #undef OT_UINT8 #undef OT_UINT16 -#undef OT_DISTANCE #undef OT_COUNT +#undef OT_DISTANCE + +#undef OT_LABEL +#undef OT_LIST + +#undef OT_TAG +#undef OT_OFFSET +#undef OT_GLYPHID +#undef G +#undef OT_UARRAY +#undef OT_UHEADLESSARRAY + +#undef OT_LOOKUP_FLAG_IGNORE_MARKS +#undef OT_LOOKUP +#undef OT_SUBLOOKUP +#undef OT_COVERAGE1 +#undef OT_LOOKUP_TYPE_SUBST_SINGLE +#undef OT_LOOKUP_TYPE_SUBST_LIGATURE +#undef OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2 +#undef OT_SUBLOOKUP_LIGATURE_SUBST_FORMAT1 +#undef OT_LIGATURE_SET +#undef OT_LIGATURE + /* * Include a second time to get the table data... diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.cc index 222c5d6b71..224f8b842e 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.cc @@ -321,6 +321,20 @@ arabic_joining (hb_buffer_t *buffer) info[prev].arabic_shaping_action() = entry->prev_action; buffer->unsafe_to_break (prev, i + 1); } + else + { + if (prev == UINT_MAX) + { + if (this_type >= JOINING_TYPE_R) + buffer->unsafe_to_concat_from_outbuffer (0, i + 1); + } + else + { + if (this_type >= JOINING_TYPE_R || + (2 <= state && state <= 5) /* States that have a possible prev_action. */) + buffer->unsafe_to_concat (prev, i + 1); + } + } info[i].arabic_shaping_action() = entry->curr_action; @@ -337,7 +351,14 @@ arabic_joining (hb_buffer_t *buffer) const arabic_state_table_entry *entry = &arabic_state_table[state][this_type]; if (entry->prev_action != NONE && prev != UINT_MAX) + { info[prev].arabic_shaping_action() = entry->prev_action; + buffer->unsafe_to_break (prev, buffer->len); + } + else if (2 <= state && state <= 5) /* States that have a possible prev_action. */ + { + buffer->unsafe_to_concat (prev, buffer->len); + } break; } } @@ -614,6 +635,11 @@ modifier_combining_marks[] = 0x06E3u, /* ARABIC SMALL LOW SEEN */ 0x06E7u, /* ARABIC SMALL HIGH YEH */ 0x06E8u, /* ARABIC SMALL HIGH NOON */ + 0x08CAu, /* ARABIC SMALL HIGH FARSI YEH */ + 0x08CBu, /* ARABIC SMALL HIGH YEH BARREE WITH TWO DOTS BELOW */ + 0x08CDu, /* ARABIC SMALL HIGH ZAH */ + 0x08CEu, /* ARABIC LARGE ROUND DOT ABOVE */ + 0x08CFu, /* ARABIC LARGE ROUND DOT BELOW */ 0x08D3u, /* ARABIC SMALL LOW WAW */ 0x08F3u, /* ARABIC SMALL HIGH WAW */ }; diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-hangul.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-hangul.cc index 0d84a76b85..3bc9e9b961 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-hangul.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-hangul.cc @@ -140,7 +140,7 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED, * * - LV can be precomposed, or decomposed. Lets call those * <LV> and <L,V>, - * - LVT can be fully precomposed, partically precomposed, or + * - LVT can be fully precomposed, partially precomposed, or * fully decomposed. Ie. <LVT>, <LV,T>, or <L,V,T>. * * The composition / decomposition is mechanical. However, not @@ -392,7 +392,7 @@ preprocess_text_hangul (const hb_ot_shape_plan_t *plan HB_UNUSED, */ (void) buffer->next_glyph (); } - buffer->swap_buffers (); + buffer->sync (); } static void diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.cc index 5a08f878dc..76092c7f38 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-syllabic.cc @@ -96,7 +96,7 @@ hb_syllabic_insert_dotted_circles (hb_font_t *font, else (void) buffer->next_glyph (); } - buffer->swap_buffers (); + buffer->sync (); } diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-thai.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-thai.cc index 4c3068173b..a1e27a83be 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-thai.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-thai.cc @@ -364,7 +364,7 @@ preprocess_text_thai (const hb_ot_shape_plan_t *plan, buffer->merge_out_clusters (start - 1, end); } } - buffer->swap_buffers (); + buffer->sync (); /* If font has Thai GSUB, we are done. */ if (plan->props.script == HB_SCRIPT_THAI && !plan->map.found_script[0]) diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh b/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh index c3920b2cc6..fb9c60cce9 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh +++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-use-machine.hh @@ -385,7 +385,9 @@ struct machine_index_t : typename Iter::item_t> { machine_index_t (const Iter& it) : it (it) {} - machine_index_t (const machine_index_t& o) : it (o.it) {} + machine_index_t (const machine_index_t& o) : hb_iter_with_fallback_t<machine_index_t<Iter>, + typename Iter::item_t> (), + it (o.it) {} static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator; static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator; diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.cc b/thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.cc index 045731dfb4..d2cca105a4 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shape-complex-vowel-constraints.cc @@ -435,7 +435,7 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED, default: break; } - buffer->swap_buffers (); + buffer->sync (); } diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-fallback.cc b/thirdparty/harfbuzz/src/hb-ot-shape-fallback.cc index eb1bc79768..b2eedb027b 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-fallback.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shape-fallback.cc @@ -446,6 +446,9 @@ _hb_ot_shape_fallback_mark_position (const hb_ot_shape_plan_t *plan, return; #endif + if (!buffer->message (font, "start fallback mark")) + return; + _hb_buffer_assert_gsubgpos_vars (buffer); unsigned int start = 0; @@ -457,6 +460,8 @@ _hb_ot_shape_fallback_mark_position (const hb_ot_shape_plan_t *plan, start = i; } position_cluster (plan, font, buffer, start, count, adjust_offsets_when_zeroing); + + (void) buffer->message (font, "end fallback mark"); } @@ -497,6 +502,9 @@ _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan, !font->has_glyph_v_kerning_func ()) return; + if (!buffer->message (font, "start fallback kern")) + return; + bool reverse = HB_DIRECTION_IS_BACKWARD (buffer->props.direction); if (reverse) @@ -508,6 +516,8 @@ _hb_ot_shape_fallback_kern (const hb_ot_shape_plan_t *plan, if (reverse) buffer->reverse (); + + (void) buffer->message (font, "end fallback kern"); #endif } @@ -525,6 +535,15 @@ _hb_ot_shape_fallback_spaces (const hb_ot_shape_plan_t *plan HB_UNUSED, for (unsigned int i = 0; i < count; i++) if (_hb_glyph_info_is_unicode_space (&info[i]) && !_hb_glyph_info_ligated (&info[i])) { + /* If font had no ASCII space and we used the invisible glyph, give it a 1/4 EM default advance. */ + if (buffer->invisible && info[i].codepoint == buffer->invisible) + { + if (horizontal) + pos[i].x_advance = +font->x_scale / 4; + else + pos[i].y_advance = -font->y_scale / 4; + } + hb_unicode_funcs_t::space_t space_type = _hb_glyph_info_get_unicode_space_fallback_type (&info[i]); hb_codepoint_t glyph; typedef hb_unicode_funcs_t t; diff --git a/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc b/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc index 839cc9122c..aa5a8eeaa3 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shape-normalize.cc @@ -193,7 +193,8 @@ decompose_current_character (const hb_ot_shape_normalize_context_t *c, bool shor { hb_codepoint_t space_glyph; hb_unicode_funcs_t::space_t space_type = buffer->unicode->space_fallback_type (u); - if (space_type != hb_unicode_funcs_t::NOT_SPACE && c->font->get_nominal_glyph (0x0020u, &space_glyph)) + if (space_type != hb_unicode_funcs_t::NOT_SPACE && + (c->font->get_nominal_glyph (0x0020, &space_glyph) || (space_glyph = buffer->invisible))) { _hb_glyph_info_set_unicode_space_fallback_type (&buffer->cur(), space_type); next_char (buffer, space_glyph); @@ -374,7 +375,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, decompose_multi_char_cluster (&c, end, always_short_circuit); } while (buffer->idx < count && buffer->successful); - buffer->swap_buffers (); + buffer->sync (); } @@ -477,7 +478,7 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan, if (info_cc (buffer->prev()) == 0) starter = buffer->out_len - 1; } - buffer->swap_buffers (); + buffer->sync (); } } diff --git a/thirdparty/harfbuzz/src/hb-ot-shape.cc b/thirdparty/harfbuzz/src/hb-ot-shape.cc index 4e8a4bc3d1..4bd8aaf03b 100644 --- a/thirdparty/harfbuzz/src/hb-ot-shape.cc +++ b/thirdparty/harfbuzz/src/hb-ot-shape.cc @@ -566,7 +566,7 @@ hb_insert_dotted_circle (hb_buffer_t *buffer, hb_font_t *font) info.mask = buffer->cur().mask; (void) buffer->output_info (info); - buffer->swap_buffers (); + buffer->sync (); } static void @@ -628,20 +628,7 @@ hb_ensure_native_direction (hb_buffer_t *buffer) (HB_DIRECTION_IS_VERTICAL (direction) && direction != HB_DIRECTION_TTB)) { - - if (buffer->cluster_level == HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS) - foreach_grapheme (buffer, start, end) - { - buffer->merge_clusters (start, end); - buffer->reverse_range (start, end); - } - else - foreach_grapheme (buffer, start, end) - /* form_clusters() merged clusters already, we don't merge. */ - buffer->reverse_range (start, end); - - buffer->reverse (); - + _hb_ot_layout_reverse_graphemes (buffer); buffer->props.direction = HB_DIRECTION_REVERSE (buffer->props.direction); } } @@ -651,6 +638,7 @@ hb_ensure_native_direction (hb_buffer_t *buffer) * Substitute */ +#ifndef HB_NO_VERTICAL static hb_codepoint_t hb_vert_char_for (hb_codepoint_t u) { @@ -701,6 +689,7 @@ hb_vert_char_for (hb_codepoint_t u) return u; } +#endif static inline void hb_ot_rotate_chars (const hb_ot_shape_context_t *c) @@ -723,6 +712,7 @@ hb_ot_rotate_chars (const hb_ot_shape_context_t *c) } } +#ifndef HB_NO_VERTICAL if (HB_DIRECTION_IS_VERTICAL (c->target_direction) && !c->plan->has_vert) { for (unsigned int i = 0; i < count; i++) { @@ -731,6 +721,7 @@ hb_ot_rotate_chars (const hb_ot_shape_context_t *c) info[i].codepoint = codepoint; } } +#endif } static inline void @@ -1043,7 +1034,7 @@ hb_ot_position_complex (const hb_ot_shape_context_t *c) * hanging over the next glyph after the final reordering. * * Note: If fallback positinoing happens, we don't care about - * this as it will be overriden. + * this as it will be overridden. */ bool adjust_offsets_when_zeroing = c->plan->adjust_mark_positioning_when_zeroing && HB_DIRECTION_IS_FORWARD (c->buffer->props.direction); @@ -1129,7 +1120,7 @@ hb_propagate_flags (hb_buffer_t *buffer) /* Propagate cluster-level glyph flags to be the same on all cluster glyphs. * Simplifies using them. */ - if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_UNSAFE_TO_BREAK)) + if (!(buffer->scratch_flags & HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS)) return; hb_glyph_info_t *info = buffer->info; @@ -1138,11 +1129,7 @@ hb_propagate_flags (hb_buffer_t *buffer) { unsigned int mask = 0; for (unsigned int i = start; i < end; i++) - if (info[i].mask & HB_GLYPH_FLAG_UNSAFE_TO_BREAK) - { - mask = HB_GLYPH_FLAG_UNSAFE_TO_BREAK; - break; - } + mask |= info[i].mask & HB_GLYPH_FLAG_DEFINED; if (mask) for (unsigned int i = start; i < end; i++) info[i].mask |= mask; @@ -1154,18 +1141,7 @@ hb_propagate_flags (hb_buffer_t *buffer) static void hb_ot_shape_internal (hb_ot_shape_context_t *c) { - c->buffer->deallocate_var_all (); - c->buffer->scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT; - if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_LEN_FACTOR))) - { - c->buffer->max_len = hb_max (c->buffer->len * HB_BUFFER_MAX_LEN_FACTOR, - (unsigned) HB_BUFFER_MAX_LEN_MIN); - } - if (likely (!hb_unsigned_mul_overflows (c->buffer->len, HB_BUFFER_MAX_OPS_FACTOR))) - { - c->buffer->max_ops = hb_max (c->buffer->len * HB_BUFFER_MAX_OPS_FACTOR, - (unsigned) HB_BUFFER_MAX_OPS_MIN); - } + c->buffer->enter (); /* Save the original direction, we use it later. */ c->target_direction = c->buffer->props.direction; @@ -1197,9 +1173,7 @@ hb_ot_shape_internal (hb_ot_shape_context_t *c) c->buffer->props.direction = c->target_direction; - c->buffer->max_len = HB_BUFFER_MAX_LEN_DEFAULT; - c->buffer->max_ops = HB_BUFFER_MAX_OPS_DEFAULT; - c->buffer->deallocate_var_all (); + c->buffer->leave (); } diff --git a/thirdparty/harfbuzz/src/hb-ot-tag-table.hh b/thirdparty/harfbuzz/src/hb-ot-tag-table.hh index fc9bffc23f..61d2814e93 100644 --- a/thirdparty/harfbuzz/src/hb-ot-tag-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-tag-table.hh @@ -6,8 +6,8 @@ * * on files with these headers: * - * <meta name="updated_at" content="2021-09-02 09:40 PM" /> - * File-Date: 2021-08-06 + * <meta name="updated_at" content="2022-01-28 10:00 PM" /> + * File-Date: 2021-12-29 */ #ifndef HB_OT_TAG_TABLE_HH @@ -66,7 +66,7 @@ static const LangTag ot_languages[] = { {"an", HB_TAG('A','R','G',' ')}, /* Aragonese */ /*{"ang", HB_TAG('A','N','G',' ')},*/ /* Old English (ca. 450-1100) -> Anglo-Saxon */ {"aoa", HB_TAG('C','P','P',' ')}, /* Angolar -> Creoles */ - {"apa", HB_TAG('A','T','H',' ')}, /* Apache [family] -> Athapaskan */ + {"apa", HB_TAG('A','T','H',' ')}, /* Apache [collection] -> Athapaskan */ {"apc", HB_TAG('A','R','A',' ')}, /* North Levantine Arabic -> Arabic */ {"apd", HB_TAG('A','R','A',' ')}, /* Sudanese Arabic -> Arabic */ {"apj", HB_TAG('A','T','H',' ')}, /* Jicarilla Apache -> Athapaskan */ @@ -86,7 +86,7 @@ static const LangTag ot_languages[] = { {"arz", HB_TAG('A','R','A',' ')}, /* Egyptian Arabic -> Arabic */ {"as", HB_TAG('A','S','M',' ')}, /* Assamese */ /*{"ast", HB_TAG('A','S','T',' ')},*/ /* Asturian */ -/*{"ath", HB_TAG('A','T','H',' ')},*/ /* Athapascan [family] -> Athapaskan */ +/*{"ath", HB_TAG('A','T','H',' ')},*/ /* Athapascan [collection] -> Athapaskan */ {"atj", HB_TAG('R','C','R',' ')}, /* Atikamekw -> R-Cree */ {"atv", HB_TAG('A','L','T',' ')}, /* Northern Altai -> Altai */ {"auj", HB_TAG('B','B','R',' ')}, /* Awjilah -> Berber */ @@ -110,10 +110,10 @@ static const LangTag ot_languages[] = { {"azn", HB_TAG('N','A','H',' ')}, /* Western Durango Nahuatl -> Nahuatl */ {"azz", HB_TAG('N','A','H',' ')}, /* Highland Puebla Nahuatl -> Nahuatl */ {"ba", HB_TAG('B','S','H',' ')}, /* Bashkir */ - {"bad", HB_TAG('B','A','D','0')}, /* Banda [family] */ + {"bad", HB_TAG('B','A','D','0')}, /* Banda [collection] */ {"bag", HB_TAG_NONE }, /* Tuki != Baghelkhandi */ {"bah", HB_TAG('C','P','P',' ')}, /* Bahamas Creole English -> Creoles */ - {"bai", HB_TAG('B','M','L',' ')}, /* Bamileke [family] */ + {"bai", HB_TAG('B','M','L',' ')}, /* Bamileke [collection] */ {"bal", HB_TAG('B','L','I',' ')}, /* Baluchi [macrolanguage] */ /*{"ban", HB_TAG('B','A','N',' ')},*/ /* Balinese */ /*{"bar", HB_TAG('B','A','R',' ')},*/ /* Bavarian */ @@ -135,7 +135,7 @@ static const LangTag ot_languages[] = { {"bea", HB_TAG('A','T','H',' ')}, /* Beaver -> Athapaskan */ {"beb", HB_TAG('B','T','I',' ')}, /* Bebele -> Beti */ /*{"bem", HB_TAG('B','E','M',' ')},*/ /* Bemba (Zambia) */ - {"ber", HB_TAG('B','B','R',' ')}, /* Berber [family] */ + {"ber", HB_TAG('B','B','R',' ')}, /* Berber [collection] */ {"bew", HB_TAG('C','P','P',' ')}, /* Betawi -> Creoles */ {"bfl", HB_TAG('B','A','D','0')}, /* Banda-Ndélé -> Banda */ {"bfq", HB_TAG('B','A','D',' ')}, /* Badaga */ @@ -203,7 +203,7 @@ static const LangTag ot_languages[] = { {"btd", HB_TAG('B','T','K',' ')}, /* Batak Dairi -> Batak */ {"bti", HB_TAG_NONE }, /* Burate != Beti */ {"btj", HB_TAG('M','L','Y',' ')}, /* Bacanese Malay -> Malay */ -/*{"btk", HB_TAG('B','T','K',' ')},*/ /* Batak [family] */ +/*{"btk", HB_TAG('B','T','K',' ')},*/ /* Batak [collection] */ {"btm", HB_TAG('B','T','M',' ')}, /* Batak Mandailing */ {"btm", HB_TAG('B','T','K',' ')}, /* Batak Mandailing -> Batak */ {"bto", HB_TAG('B','I','K',' ')}, /* Rinconada Bikol -> Bikol */ @@ -256,6 +256,8 @@ static const LangTag ot_languages[] = { {"chh", HB_TAG_NONE }, /* Chinook != Chattisgarhi */ {"chj", HB_TAG('C','C','H','N')}, /* Ojitlán Chinantec -> Chinantec */ {"chk", HB_TAG('C','H','K','0')}, /* Chuukese */ + {"chm", HB_TAG('H','M','A',' ')}, /* Mari (Russia) [macrolanguage] -> High Mari */ + {"chm", HB_TAG('L','M','A',' ')}, /* Mari (Russia) [macrolanguage] -> Low Mari */ {"chn", HB_TAG('C','P','P',' ')}, /* Chinook jargon -> Creoles */ /*{"cho", HB_TAG('C','H','O',' ')},*/ /* Choctaw */ {"chp", HB_TAG('C','H','P',' ')}, /* Chipewyan */ @@ -297,10 +299,10 @@ static const LangTag ot_languages[] = { /*{"cop", HB_TAG('C','O','P',' ')},*/ /* Coptic */ {"coq", HB_TAG('A','T','H',' ')}, /* Coquille -> Athapaskan */ {"cpa", HB_TAG('C','C','H','N')}, /* Palantla Chinantec -> Chinantec */ - {"cpe", HB_TAG('C','P','P',' ')}, /* English-based creoles and pidgins [family] -> Creoles */ - {"cpf", HB_TAG('C','P','P',' ')}, /* French-based creoles and pidgins [family] -> Creoles */ + {"cpe", HB_TAG('C','P','P',' ')}, /* English-based creoles and pidgins [collection] -> Creoles */ + {"cpf", HB_TAG('C','P','P',' ')}, /* French-based creoles and pidgins [collection] -> Creoles */ {"cpi", HB_TAG('C','P','P',' ')}, /* Chinese Pidgin English -> Creoles */ -/*{"cpp", HB_TAG('C','P','P',' ')},*/ /* Portuguese-based creoles and pidgins [family] -> Creoles */ +/*{"cpp", HB_TAG('C','P','P',' ')},*/ /* Portuguese-based creoles and pidgins [collection] -> Creoles */ {"cpx", HB_TAG('Z','H','S',' ')}, /* Pu-Xian Chinese -> Chinese, Simplified */ {"cqd", HB_TAG('H','M','N',' ')}, /* Chuanqiandian Cluster Miao -> Hmong */ {"cqu", HB_TAG('Q','U','H',' ')}, /* Chilean Quechua (retired code) -> Quechua (Bolivia) */ @@ -320,7 +322,7 @@ static const LangTag ot_languages[] = { {"crm", HB_TAG('M','C','R',' ')}, /* Moose Cree */ {"crm", HB_TAG('L','C','R',' ')}, /* Moose Cree -> L-Cree */ {"crm", HB_TAG('C','R','E',' ')}, /* Moose Cree -> Cree */ - {"crp", HB_TAG('C','P','P',' ')}, /* Creoles and pidgins [family] -> Creoles */ + {"crp", HB_TAG('C','P','P',' ')}, /* Creoles and pidgins [collection] -> Creoles */ {"crr", HB_TAG_NONE }, /* Carolina Algonquian != Carrier */ {"crs", HB_TAG('C','P','P',' ')}, /* Seselwa Creole French -> Creoles */ {"crt", HB_TAG_NONE }, /* Iyojwa'ja Chorote != Crimean Tatar */ @@ -431,7 +433,7 @@ static const LangTag ot_languages[] = { {"et", HB_TAG('E','T','I',' ')}, /* Estonian [macrolanguage] */ {"eto", HB_TAG('B','T','I',' ')}, /* Eton (Cameroon) -> Beti */ {"eu", HB_TAG('E','U','Q',' ')}, /* Basque */ - {"euq", HB_TAG_NONE }, /* Basque [family] != Basque */ + {"euq", HB_TAG_NONE }, /* Basque [collection] != Basque */ {"eve", HB_TAG('E','V','N',' ')}, /* Even */ {"evn", HB_TAG('E','V','K',' ')}, /* Evenki */ {"ewo", HB_TAG('B','T','I',' ')}, /* Ewondo -> Beti */ @@ -620,10 +622,11 @@ static const LangTag ot_languages[] = { {"ijc", HB_TAG('I','J','O',' ')}, /* Izon -> Ijo */ {"ije", HB_TAG('I','J','O',' ')}, /* Biseni -> Ijo */ {"ijn", HB_TAG('I','J','O',' ')}, /* Kalabari -> Ijo */ -/*{"ijo", HB_TAG('I','J','O',' ')},*/ /* Ijo [family] */ +/*{"ijo", HB_TAG('I','J','O',' ')},*/ /* Ijo [collection] */ {"ijs", HB_TAG('I','J','O',' ')}, /* Southeast Ijo -> Ijo */ {"ik", HB_TAG('I','P','K',' ')}, /* Inupiaq [macrolanguage] -> Inupiat */ {"ike", HB_TAG('I','N','U',' ')}, /* Eastern Canadian Inuktitut -> Inuktitut */ + {"ike", HB_TAG('I','N','U','K')}, /* Eastern Canadian Inuktitut -> Nunavik Inuktitut */ {"ikt", HB_TAG('I','N','U',' ')}, /* Inuinnaqtun -> Inuktitut */ /*{"ilo", HB_TAG('I','L','O',' ')},*/ /* Iloko -> Ilokano */ {"in", HB_TAG('I','N','D',' ')}, /* Indonesian (retired code) */ @@ -638,6 +641,7 @@ static const LangTag ot_languages[] = { {"it", HB_TAG('I','T','A',' ')}, /* Italian */ {"itz", HB_TAG('M','Y','N',' ')}, /* Itzá -> Mayan */ {"iu", HB_TAG('I','N','U',' ')}, /* Inuktitut [macrolanguage] */ + {"iu", HB_TAG('I','N','U','K')}, /* Inuktitut [macrolanguage] -> Nunavik Inuktitut */ {"iw", HB_TAG('I','W','R',' ')}, /* Hebrew (retired code) */ {"ixl", HB_TAG('M','Y','N',' ')}, /* Ixil -> Mayan */ {"ja", HB_TAG('J','A','N',' ')}, /* Japanese */ @@ -667,7 +671,7 @@ static const LangTag ot_languages[] = { {"kab", HB_TAG('B','B','R',' ')}, /* Kabyle -> Berber */ {"kac", HB_TAG_NONE }, /* Kachin != Kachchi */ {"kam", HB_TAG('K','M','B',' ')}, /* Kamba (Kenya) */ - {"kar", HB_TAG('K','R','N',' ')}, /* Karen [family] */ + {"kar", HB_TAG('K','R','N',' ')}, /* Karen [collection] */ /*{"kaw", HB_TAG('K','A','W',' ')},*/ /* Kawi (Old Javanese) */ {"kbd", HB_TAG('K','A','B',' ')}, /* Kabardian */ {"kby", HB_TAG('K','N','R',' ')}, /* Manga Kanuri -> Kanuri */ @@ -876,7 +880,7 @@ static const LangTag ot_languages[] = { {"mam", HB_TAG('M','A','M',' ')}, /* Mam */ {"mam", HB_TAG('M','Y','N',' ')}, /* Mam -> Mayan */ {"man", HB_TAG('M','N','K',' ')}, /* Mandingo [macrolanguage] -> Maninka */ - {"map", HB_TAG_NONE }, /* Austronesian [family] != Mapudungun */ + {"map", HB_TAG_NONE }, /* Austronesian [collection] != Mapudungun */ {"maw", HB_TAG_NONE }, /* Mampruli != Marwari */ {"max", HB_TAG('M','L','Y',' ')}, /* North Moluccan Malay -> Malay */ {"max", HB_TAG('C','P','P',' ')}, /* North Moluccan Malay -> Creoles */ @@ -933,8 +937,10 @@ static const LangTag ot_languages[] = { {"mnp", HB_TAG('Z','H','S',' ')}, /* Min Bei Chinese -> Chinese, Simplified */ {"mns", HB_TAG('M','A','N',' ')}, /* Mansi */ {"mnw", HB_TAG('M','O','N',' ')}, /* Mon */ + {"mnw", HB_TAG('M','O','N','T')}, /* Mon -> Thailand Mon */ {"mnx", HB_TAG_NONE }, /* Manikion != Manx */ {"mo", HB_TAG('M','O','L',' ')}, /* Moldavian (retired code) */ + {"mo", HB_TAG('R','O','M',' ')}, /* Moldavian (retired code) -> Romanian */ {"mod", HB_TAG('C','P','P',' ')}, /* Mobilian -> Creoles */ /*{"moh", HB_TAG('M','O','H',' ')},*/ /* Mohawk */ {"mok", HB_TAG_NONE }, /* Morori != Moksha */ @@ -957,7 +963,7 @@ static const LangTag ot_languages[] = { {"mts", HB_TAG_NONE }, /* Yora != Maltese */ {"mud", HB_TAG('C','P','P',' ')}, /* Mednyj Aleut -> Creoles */ {"mui", HB_TAG('M','L','Y',' ')}, /* Musi -> Malay */ - {"mun", HB_TAG_NONE }, /* Munda [family] != Mundari */ + {"mun", HB_TAG_NONE }, /* Munda [collection] != Mundari */ {"mup", HB_TAG('R','A','J',' ')}, /* Malvi -> Rajasthani */ {"muq", HB_TAG('H','M','N',' ')}, /* Eastern Xiangxi Miao -> Hmong */ /*{"mus", HB_TAG('M','U','S',' ')},*/ /* Creek -> Muscogee */ @@ -972,7 +978,7 @@ static const LangTag ot_languages[] = { {"mww", HB_TAG('H','M','N',' ')}, /* Hmong Daw -> Hmong */ {"my", HB_TAG('B','R','M',' ')}, /* Burmese */ {"mym", HB_TAG('M','E','N',' ')}, /* Me’en */ -/*{"myn", HB_TAG('M','Y','N',' ')},*/ /* Mayan [family] */ +/*{"myn", HB_TAG('M','Y','N',' ')},*/ /* Mayan [collection] */ {"myq", HB_TAG('M','N','K',' ')}, /* Forest Maninka (retired code) -> Maninka */ {"myv", HB_TAG('E','R','Z',' ')}, /* Erzya */ {"mzb", HB_TAG('B','B','R',' ')}, /* Tumzabt -> Berber */ @@ -981,7 +987,7 @@ static const LangTag ot_languages[] = { {"na", HB_TAG('N','A','U',' ')}, /* Nauru -> Nauruan */ {"nag", HB_TAG('N','A','G',' ')}, /* Naga Pidgin -> Naga-Assamese */ {"nag", HB_TAG('C','P','P',' ')}, /* Naga Pidgin -> Creoles */ -/*{"nah", HB_TAG('N','A','H',' ')},*/ /* Nahuatl [family] */ +/*{"nah", HB_TAG('N','A','H',' ')},*/ /* Nahuatl [collection] */ {"nan", HB_TAG('Z','H','S',' ')}, /* Min Nan Chinese -> Chinese, Simplified */ /*{"nap", HB_TAG('N','A','P',' ')},*/ /* Neapolitan */ {"nas", HB_TAG_NONE }, /* Naasioi != Naskapi */ @@ -1038,7 +1044,6 @@ static const LangTag ot_languages[] = { {"nln", HB_TAG('N','A','H',' ')}, /* Durango Nahuatl (retired code) -> Nahuatl */ {"nlv", HB_TAG('N','A','H',' ')}, /* Orizaba Nahuatl -> Nahuatl */ {"nn", HB_TAG('N','Y','N',' ')}, /* Norwegian Nynorsk (Nynorsk, Norwegian) */ - {"nn", HB_TAG('N','O','R',' ')}, /* Norwegian Nynorsk -> Norwegian */ {"nnh", HB_TAG('B','M','L',' ')}, /* Ngiemboon -> Bamileke */ {"nnz", HB_TAG('B','M','L',' ')}, /* Nda'nda' -> Bamileke */ {"no", HB_TAG('N','O','R',' ')}, /* Norwegian [macrolanguage] */ @@ -1092,7 +1097,7 @@ static const LangTag ot_languages[] = { {"otw", HB_TAG('O','J','B',' ')}, /* Ottawa -> Ojibway */ {"oua", HB_TAG('B','B','R',' ')}, /* Tagargrent -> Berber */ {"pa", HB_TAG('P','A','N',' ')}, /* Punjabi */ - {"paa", HB_TAG_NONE }, /* Papuan [family] != Palestinian Aramaic */ + {"paa", HB_TAG_NONE }, /* Papuan [collection] != Palestinian Aramaic */ /*{"pag", HB_TAG('P','A','G',' ')},*/ /* Pangasinan */ {"pal", HB_TAG_NONE }, /* Pahlavi != Pali */ /*{"pam", HB_TAG('P','A','M',' ')},*/ /* Pampanga -> Pampangan */ @@ -1307,6 +1312,9 @@ static const LangTag ot_languages[] = { {"sgo", HB_TAG_NONE }, /* Songa (retired code) != Sango */ /*{"sgs", HB_TAG('S','G','S',' ')},*/ /* Samogitian */ {"sgw", HB_TAG('C','H','G',' ')}, /* Sebat Bet Gurage -> Chaha Gurage */ + {"sh", HB_TAG('B','O','S',' ')}, /* Serbo-Croatian [macrolanguage] -> Bosnian */ + {"sh", HB_TAG('H','R','V',' ')}, /* Serbo-Croatian [macrolanguage] -> Croatian */ + {"sh", HB_TAG('S','R','B',' ')}, /* Serbo-Croatian [macrolanguage] -> Serbian */ {"shi", HB_TAG('S','H','I',' ')}, /* Tachelhit */ {"shi", HB_TAG('B','B','R',' ')}, /* Tachelhit -> Berber */ {"shl", HB_TAG('Q','I','N',' ')}, /* Shendu -> Chin */ @@ -1328,7 +1336,7 @@ static const LangTag ot_languages[] = { {"skw", HB_TAG('C','P','P',' ')}, /* Skepi Creole Dutch -> Creoles */ {"sky", HB_TAG_NONE }, /* Sikaiana != Slovak */ {"sl", HB_TAG('S','L','V',' ')}, /* Slovenian */ - {"sla", HB_TAG_NONE }, /* Slavic [family] != Slavey */ + {"sla", HB_TAG_NONE }, /* Slavic [collection] != Slavey */ {"sm", HB_TAG('S','M','O',' ')}, /* Samoan */ {"sma", HB_TAG('S','S','M',' ')}, /* Southern Sami */ {"smj", HB_TAG('L','S','M',' ')}, /* Lule Sami */ @@ -1422,6 +1430,7 @@ static const LangTag ot_languages[] = { {"tia", HB_TAG('B','B','R',' ')}, /* Tidikelt Tamazight -> Berber */ {"tig", HB_TAG('T','G','R',' ')}, /* Tigre */ /*{"tiv", HB_TAG('T','I','V',' ')},*/ /* Tiv */ +/*{"tjl", HB_TAG('T','J','L',' ')},*/ /* Tai Laing */ {"tjo", HB_TAG('B','B','R',' ')}, /* Temacine Tamazight -> Berber */ {"tk", HB_TAG('T','K','M',' ')}, /* Turkmen */ {"tkg", HB_TAG('M','L','G',' ')}, /* Tesaka Malagasy -> Malagasy */ @@ -1449,7 +1458,7 @@ static const LangTag ot_languages[] = { {"tpi", HB_TAG('C','P','P',' ')}, /* Tok Pisin -> Creoles */ {"tr", HB_TAG('T','R','K',' ')}, /* Turkish */ {"trf", HB_TAG('C','P','P',' ')}, /* Trinidadian Creole English -> Creoles */ - {"trk", HB_TAG_NONE }, /* Turkic [family] != Turkish */ + {"trk", HB_TAG_NONE }, /* Turkic [collection] != Turkish */ {"tru", HB_TAG('T','U','A',' ')}, /* Turoyo -> Turoyo Aramaic */ {"tru", HB_TAG('S','Y','R',' ')}, /* Turoyo -> Syriac */ {"ts", HB_TAG('T','S','G',' ')}, /* Tsonga */ @@ -1591,7 +1600,7 @@ static const LangTag ot_languages[] = { {"zlq", HB_TAG('Z','H','A',' ')}, /* Liuqian Zhuang -> Zhuang */ {"zmi", HB_TAG('M','L','Y',' ')}, /* Negeri Sembilan Malay -> Malay */ {"zmz", HB_TAG('B','A','D','0')}, /* Mbandja -> Banda */ - {"znd", HB_TAG_NONE }, /* Zande [family] != Zande */ + {"znd", HB_TAG_NONE }, /* Zande [collection] != Zande */ {"zne", HB_TAG('Z','N','D',' ')}, /* Zande */ {"zom", HB_TAG('Q','I','N',' ')}, /* Zou -> Chin */ {"zqe", HB_TAG('Z','H','A',' ')}, /* Qiubei Zhuang -> Zhuang */ @@ -2521,6 +2530,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, *count = 1; return true; } + if (0 == strncmp (&lang_str[1], "nw-", 3) + && subtag_matches (lang_str, limit, "-th")) + { + /* Mon; Thailand */ + tags[0] = HB_TAG('M','O','N','T'); /* Thailand Mon */ + *count = 1; + return true; + } break; case 'n': if (lang_matches (&lang_str[1], "an-hant-hk")) @@ -2597,14 +2614,8 @@ hb_ot_tags_from_complex_language (const char *lang_str, if (0 == strcmp (&lang_str[1], "o-nyn")) { /* Norwegian Nynorsk (retired code) */ - unsigned int i; - hb_tag_t possible_tags[] = { - HB_TAG('N','Y','N',' '), /* Norwegian Nynorsk (Nynorsk, Norwegian) */ - HB_TAG('N','O','R',' '), /* Norwegian */ - }; - for (i = 0; i < 2 && i < *count; i++) - tags[i] = possible_tags[i]; - *count = i; + tags[0] = HB_TAG('N','Y','N',' '); /* Norwegian Nynorsk (Nynorsk, Norwegian) */ + *count = 1; return true; } break; @@ -2613,8 +2624,14 @@ hb_ot_tags_from_complex_language (const char *lang_str, && subtag_matches (lang_str, limit, "-md")) { /* Romanian; Moldova */ - tags[0] = HB_TAG('M','O','L',' '); /* Moldavian */ - *count = 1; + unsigned int i; + hb_tag_t possible_tags[] = { + HB_TAG('M','O','L',' '), /* Moldavian */ + HB_TAG('R','O','M',' '), /* Romanian */ + }; + for (i = 0; i < 2 && i < *count; i++) + tags[i] = possible_tags[i]; + *count = i; return true; } break; @@ -2803,15 +2820,15 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag) case HB_TAG('A','R','K',' '): /* Rakhine */ return hb_language_from_string ("rki", -1); /* Rakhine */ case HB_TAG('A','T','H',' '): /* Athapaskan */ - return hb_language_from_string ("ath", -1); /* Athapascan [family] */ + return hb_language_from_string ("ath", -1); /* Athapascan [collection] */ case HB_TAG('B','B','R',' '): /* Berber */ - return hb_language_from_string ("ber", -1); /* Berber [family] */ + return hb_language_from_string ("ber", -1); /* Berber [collection] */ case HB_TAG('B','I','K',' '): /* Bikol */ return hb_language_from_string ("bik", -1); /* Bikol [macrolanguage] */ case HB_TAG('B','T','K',' '): /* Batak */ - return hb_language_from_string ("btk", -1); /* Batak [family] */ + return hb_language_from_string ("btk", -1); /* Batak [collection] */ case HB_TAG('C','P','P',' '): /* Creoles */ - return hb_language_from_string ("crp", -1); /* Creoles and pidgins [family] */ + return hb_language_from_string ("crp", -1); /* Creoles and pidgins [collection] */ case HB_TAG('C','R','R',' '): /* Carrier */ return hb_language_from_string ("crx", -1); /* Carrier */ case HB_TAG('D','G','R',' '): /* Dogri (macrolanguage) */ @@ -2828,6 +2845,8 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag) return hb_language_from_string ("fa", -1); /* Persian [macrolanguage] */ case HB_TAG('G','O','N',' '): /* Gondi */ return hb_language_from_string ("gon", -1); /* Gondi [macrolanguage] */ + case HB_TAG('H','M','A',' '): /* High Mari */ + return hb_language_from_string ("mrj", -1); /* Western Mari */ case HB_TAG('H','M','N',' '): /* Hmong */ return hb_language_from_string ("hmn", -1); /* Hmong [macrolanguage] */ case HB_TAG('H','N','D',' '): /* Hindko */ @@ -2837,7 +2856,7 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag) case HB_TAG('I','B','A',' '): /* Iban */ return hb_language_from_string ("iba", -1); /* Iban */ case HB_TAG('I','J','O',' '): /* Ijo */ - return hb_language_from_string ("ijo", -1); /* Ijo [family] */ + return hb_language_from_string ("ijo", -1); /* Ijo [collection] */ case HB_TAG('I','N','U',' '): /* Inuktitut */ return hb_language_from_string ("iu", -1); /* Inuktitut [macrolanguage] */ case HB_TAG('I','P','K',' '): /* Inupiat */ @@ -2863,11 +2882,13 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag) case HB_TAG('K','P','L',' '): /* Kpelle */ return hb_language_from_string ("kpe", -1); /* Kpelle [macrolanguage] */ case HB_TAG('K','R','N',' '): /* Karen */ - return hb_language_from_string ("kar", -1); /* Karen [family] */ + return hb_language_from_string ("kar", -1); /* Karen [collection] */ case HB_TAG('K','U','I',' '): /* Kui */ return hb_language_from_string ("uki", -1); /* Kui (India) */ case HB_TAG('K','U','R',' '): /* Kurdish */ return hb_language_from_string ("ku", -1); /* Kurdish [macrolanguage] */ + case HB_TAG('L','M','A',' '): /* Low Mari */ + return hb_language_from_string ("mhr", -1); /* Eastern Mari */ case HB_TAG('L','U','H',' '): /* Luyia */ return hb_language_from_string ("luy", -1); /* Luyia [macrolanguage] */ case HB_TAG('L','V','I',' '): /* Latvian */ @@ -2884,10 +2905,12 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag) return hb_language_from_string ("man", -1); /* Mandingo [macrolanguage] */ case HB_TAG('M','O','L',' '): /* Moldavian */ return hb_language_from_string ("ro-MD", -1); /* Romanian; Moldova */ + case HB_TAG('M','O','N','T'): /* Thailand Mon */ + return hb_language_from_string ("mnw-TH", -1); /* Mon; Thailand */ case HB_TAG('M','Y','N',' '): /* Mayan */ - return hb_language_from_string ("myn", -1); /* Mayan [family] */ + return hb_language_from_string ("myn", -1); /* Mayan [collection] */ case HB_TAG('N','A','H',' '): /* Nahuatl */ - return hb_language_from_string ("nah", -1); /* Nahuatl [family] */ + return hb_language_from_string ("nah", -1); /* Nahuatl [collection] */ case HB_TAG('N','E','P',' '): /* Nepali */ return hb_language_from_string ("ne", -1); /* Nepali [macrolanguage] */ case HB_TAG('N','I','S',' '): /* Nisi */ @@ -2914,6 +2937,8 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag) return hb_language_from_string ("qwh", -1); /* Huaylas Ancash Quechua */ case HB_TAG('R','A','J',' '): /* Rajasthani */ return hb_language_from_string ("raj", -1); /* Rajasthani [macrolanguage] */ + case HB_TAG('R','O','M',' '): /* Romanian */ + return hb_language_from_string ("ro", -1); /* Romanian */ case HB_TAG('R','O','Y',' '): /* Romany */ return hb_language_from_string ("rom", -1); /* Romany [macrolanguage] */ case HB_TAG('S','Q','I',' '): /* Albanian */ diff --git a/thirdparty/harfbuzz/src/hb-ot-tag.cc b/thirdparty/harfbuzz/src/hb-ot-tag.cc index 1837063af8..f50be97ad3 100644 --- a/thirdparty/harfbuzz/src/hb-ot-tag.cc +++ b/thirdparty/harfbuzz/src/hb-ot-tag.cc @@ -41,6 +41,7 @@ hb_ot_old_tag_from_script (hb_script_t script) switch ((hb_tag_t) script) { case HB_SCRIPT_INVALID: return HB_OT_TAG_DEFAULT_SCRIPT; + case HB_SCRIPT_MATH: return HB_OT_TAG_MATH_SCRIPT; /* KATAKANA and HIRAGANA both map to 'kana' */ case HB_SCRIPT_HIRAGANA: return HB_TAG('k','a','n','a'); @@ -63,6 +64,8 @@ hb_ot_old_tag_to_script (hb_tag_t tag) { if (unlikely (tag == HB_OT_TAG_DEFAULT_SCRIPT)) return HB_SCRIPT_INVALID; + if (unlikely (tag == HB_OT_TAG_MATH_SCRIPT)) + return HB_SCRIPT_MATH; /* This side of the conversion is fully algorithmic. */ diff --git a/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh b/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh index 05f289db26..e066558683 100644 --- a/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-var-fvar-table.hh @@ -263,7 +263,7 @@ struct fvar if (coords_length && *coords_length) { hb_array_t<const HBFixed> instanceCoords = instance->get_coordinates (axisCount) - .sub_array (0, *coords_length); + .sub_array (0, coords_length); for (unsigned int i = 0; i < instanceCoords.length; i++) coords[i] = instanceCoords.arrayZ[i].to_float (); } diff --git a/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh b/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh index 49b5532d40..539213c339 100644 --- a/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-var-gvar-table.hh @@ -399,7 +399,7 @@ struct gvar get_offset (glyphCount) - get_offset (0))); } - /* GlyphVariationData not sanitized here; must be checked while accessing each glyph varation data */ + /* GlyphVariationData not sanitized here; must be checked while accessing each glyph variation data */ bool sanitize (hb_sanitize_context_t *c) const { return sanitize_shallow (c); } @@ -498,9 +498,9 @@ struct gvar public: struct accelerator_t { - void init (hb_face_t *face) + accelerator_t (hb_face_t *face) { table = hb_sanitize_context_t ().reference_table<gvar> (face); } - void fini () { table.destroy (); } + ~accelerator_t () { table.destroy (); } private: struct x_getter { static float get (const contour_point_t &p) { return p.x; } }; @@ -698,7 +698,9 @@ no_more_gaps: DEFINE_SIZE_MIN (20); }; -struct gvar_accelerator_t : gvar::accelerator_t {}; +struct gvar_accelerator_t : gvar::accelerator_t { + gvar_accelerator_t (hb_face_t *face) : gvar::accelerator_t (face) {} +}; } /* namespace OT */ diff --git a/thirdparty/harfbuzz/src/hb-ot-var-hvar-table.hh b/thirdparty/harfbuzz/src/hb-ot-var-hvar-table.hh index 074b6a3785..e9d90352f0 100644 --- a/thirdparty/harfbuzz/src/hb-ot-var-hvar-table.hh +++ b/thirdparty/harfbuzz/src/hb-ot-var-hvar-table.hh @@ -177,9 +177,6 @@ struct hvarvvar_subset_plan_t inner_maps.resize (var_store->get_sub_table_count ()); - for (unsigned int i = 0; i < inner_maps.length; i++) - inner_maps[i].init (); - if (unlikely (!index_map_plans.length || !inner_sets.length || !inner_maps.length)) return; bool retain_adv_map = false; @@ -229,8 +226,8 @@ struct hvarvvar_subset_plan_t for (unsigned int i = 0; i < inner_sets.length; i++) hb_set_destroy (inner_sets[i]); hb_set_destroy (adv_set); - inner_maps.fini_deep (); - index_map_plans.fini_deep (); + inner_maps.fini (); + index_map_plans.fini (); } hb_inc_bimap_t outer_map; diff --git a/thirdparty/harfbuzz/src/hb-ot-var.cc b/thirdparty/harfbuzz/src/hb-ot-var.cc index 6b42b45cd9..0376e26b4a 100644 --- a/thirdparty/harfbuzz/src/hb-ot-var.cc +++ b/thirdparty/harfbuzz/src/hb-ot-var.cc @@ -303,6 +303,9 @@ hb_ot_var_normalize_variations (hb_face_t *face, * values for the axis are mapped to the interval [-1,1], with the default * axis value mapped to 0. * + * The normalized values have 14 bits of fixed-point sub-integer precision as per + * OpenType specification. + * * Any additional scaling defined in the face's `avar` table is also * applied, as described at https://docs.microsoft.com/en-us/typography/opentype/spec/avar * diff --git a/thirdparty/harfbuzz/src/hb-ot-var.h b/thirdparty/harfbuzz/src/hb-ot-var.h index ce201d3b4f..05147cc25e 100644 --- a/thirdparty/harfbuzz/src/hb-ot-var.h +++ b/thirdparty/harfbuzz/src/hb-ot-var.h @@ -109,7 +109,7 @@ typedef enum { /*< flags >*/ * @tag: The #hb_tag_t tag identifying the design variation of the axis * @name_id: The `name` table Name ID that provides display names for the axis * @flags: The #hb_ot_var_axis_flags_t flags for the axis - * @min_value: The mininum value on the variation axis that the font covers + * @min_value: The minimum value on the variation axis that the font covers * @default_value: The position on the variation axis corresponding to the font's defaults * @max_value: The maximum value on the variation axis that the font covers * diff --git a/thirdparty/harfbuzz/src/hb-repacker.hh b/thirdparty/harfbuzz/src/hb-repacker.hh index 26faa56ea8..b1726d8beb 100644 --- a/thirdparty/harfbuzz/src/hb-repacker.hh +++ b/thirdparty/harfbuzz/src/hb-repacker.hh @@ -42,26 +42,13 @@ struct graph_t { struct vertex_t { - vertex_t () : - distance (0), - space (0), - parents (), - start (0), - end (0), - priority(0) {} - - void fini () { - obj.fini (); - parents.fini (); - } - hb_serialize_context_t::object_t obj; - int64_t distance; - int64_t space; + int64_t distance = 0 ; + int64_t space = 0 ; hb_vector_t<unsigned> parents; - unsigned start; - unsigned end; - unsigned priority; + unsigned start = 0; + unsigned end = 0; + unsigned priority = 0; bool is_shared () const { @@ -100,12 +87,18 @@ struct graph_t bool is_leaf () const { - return !obj.links.length; + return !obj.real_links.length && !obj.virtual_links.length; } - void raise_priority () + bool raise_priority () { + if (has_max_priority ()) return false; priority++; + return true; + } + + bool has_max_priority () const { + return priority >= 3; } int64_t modified_distance (unsigned order) const @@ -115,15 +108,22 @@ struct graph_t // it's parent where possible. int64_t modified_distance = - hb_min (hb_max(distance + distance_modifier (), 0), 0x7FFFFFFFFF); - return (modified_distance << 22) | (0x003FFFFF & order); + hb_min (hb_max(distance + distance_modifier (), 0), 0x7FFFFFFFFFF); + if (has_max_priority ()) { + modified_distance = 0; + } + return (modified_distance << 18) | (0x003FFFF & order); } int64_t distance_modifier () const { if (!priority) return 0; int64_t table_size = obj.tail - obj.head; - return -(table_size - table_size / (1 << hb_min(priority, 16u))); + + if (priority == 1) + return -table_size / 2; + + return -table_size; } }; @@ -164,15 +164,16 @@ struct graph_t if (check_success (!vertices_.in_error ())) v->obj = *objects[i]; if (!removed_nil) continue; - for (unsigned i = 0; i < v->obj.links.length; i++) - // Fix indices to account for removed nil object. - v->obj.links[i].objidx--; + // Fix indices to account for removed nil object. + for (auto& l : v->obj.all_links_writer ()) { + l.objidx--; + } } } ~graph_t () { - vertices_.fini_deep (); + vertices_.fini (); } bool in_error () const @@ -203,26 +204,46 @@ struct graph_t /* * serialize graph into the provided serialization buffer. */ - void serialize (hb_serialize_context_t* c) const + hb_blob_t* serialize () const { - c->start_serialize<void> (); + hb_vector_t<char> buffer; + size_t size = serialized_length (); + if (!buffer.alloc (size)) { + DEBUG_MSG (SUBSET_REPACK, nullptr, "Unable to allocate output buffer."); + return nullptr; + } + hb_serialize_context_t c((void *) buffer, size); + + c.start_serialize<void> (); for (unsigned i = 0; i < vertices_.length; i++) { - c->push (); + c.push (); size_t size = vertices_[i].obj.tail - vertices_[i].obj.head; - char* start = c->allocate_size <char> (size); - if (!start) return; + char* start = c.allocate_size <char> (size); + if (!start) { + DEBUG_MSG (SUBSET_REPACK, nullptr, "Buffer out of space."); + return nullptr; + } memcpy (start, vertices_[i].obj.head, size); - for (const auto& link : vertices_[i].obj.links) - serialize_link (link, start, c); + // Only real links needs to be serialized. + for (const auto& link : vertices_[i].obj.real_links) + serialize_link (link, start, &c); // All duplications are already encoded in the graph, so don't // enable sharing during packing. - c->pop_pack (false); + c.pop_pack (false); + } + c.end_serialize (); + + if (c.in_error ()) { + DEBUG_MSG (SUBSET_REPACK, nullptr, "Error during serialization. Err flag: %d", + c.errors); + return nullptr; } - c->end_serialize (); + + return c.copy_blob (); } /* @@ -260,7 +281,7 @@ struct graph_t sorted_graph[new_id] = next; id_map[next_id] = new_id--; - for (const auto& link : next.obj.links) { + for (const auto& link : next.obj.all_links ()) { removed_edges[link.objidx]++; if (!(vertices_[link.objidx].incoming_edges () - removed_edges[link.objidx])) queue.push (link.objidx); @@ -275,7 +296,7 @@ struct graph_t remap_all_obj_indices (id_map, &sorted_graph); hb_swap (vertices_, sorted_graph); - sorted_graph.fini_deep (); + sorted_graph.fini (); } /* @@ -314,7 +335,7 @@ struct graph_t sorted_graph[new_id] = next; id_map[next_id] = new_id--; - for (const auto& link : next.obj.links) { + for (const auto& link : next.obj.all_links ()) { removed_edges[link.objidx]++; if (!(vertices_[link.objidx].incoming_edges () - removed_edges[link.objidx])) // Add the order that the links were encountered to the priority. @@ -335,7 +356,7 @@ struct graph_t remap_all_obj_indices (id_map, &sorted_graph); hb_swap (vertices_, sorted_graph); - sorted_graph.fini_deep (); + sorted_graph.fini (); } /* @@ -348,7 +369,8 @@ struct graph_t hb_set_t roots; for (unsigned i = 0; i <= root_index; i++) { - for (auto& l : vertices_[i].obj.links) + // Only real links can form 32 bit spaces + for (auto& l : vertices_[i].obj.real_links) { if (l.width == 4 && !l.is_signed) { @@ -367,11 +389,15 @@ struct graph_t while (roots) { unsigned next = HB_SET_VALUE_INVALID; + if (unlikely (!check_success (!roots.in_error ()))) break; if (!roots.next (&next)) break; hb_set_t connected_roots; find_connected_nodes (next, roots, visited, connected_roots); + if (unlikely (!check_success (!connected_roots.in_error ()))) break; + isolate_subgraph (connected_roots); + if (unlikely (!check_success (!connected_roots.in_error ()))) break; unsigned next_space = this->next_space (); num_roots_for_space_.push (0); @@ -388,6 +414,8 @@ struct graph_t // into the 32 bit space as needed, instead of using isolation. } + + return true; } @@ -466,7 +494,7 @@ struct graph_t void find_subgraph (unsigned node_idx, hb_hashmap_t<unsigned, unsigned>& subgraph) { - for (const auto& link : vertices_[node_idx].obj.links) + for (const auto& link : vertices_[node_idx].obj.all_links ()) { if (subgraph.has (link.objidx)) { @@ -482,7 +510,7 @@ struct graph_t { if (subgraph.has (node_idx)) return; subgraph.add (node_idx); - for (const auto& link : vertices_[node_idx].obj.links) + for (const auto& link : vertices_[node_idx].obj.all_links ()) find_subgraph (link.objidx, subgraph); } @@ -497,7 +525,7 @@ struct graph_t return; index_map.set (node_idx, duplicate (node_idx)); - for (const auto& l : object (node_idx).links) { + for (const auto& l : object (node_idx).all_links ()) { duplicate_subgraph (l.objidx, index_map); } } @@ -523,13 +551,19 @@ struct graph_t clone->parents.reset (); unsigned clone_idx = vertices_.length - 2; - for (const auto& l : child.obj.links) + for (const auto& l : child.obj.real_links) { - clone->obj.links.push (l); + clone->obj.real_links.push (l); + vertices_[l.objidx].parents.push (clone_idx); + } + for (const auto& l : child.obj.virtual_links) + { + clone->obj.virtual_links.push (l); vertices_[l.objidx].parents.push (clone_idx); } - check_success (!clone->obj.links.in_error ()); + check_success (!clone->obj.real_links.in_error ()); + check_success (!clone->obj.virtual_links.in_error ()); // The last object is the root of the graph, so swap back the root to the end. // The root's obj idx does change, however since it's root nothing else refers to it. @@ -539,7 +573,7 @@ struct graph_t vertices_[vertices_.length - 1] = root; // Since the root moved, update the parents arrays of all children on the root. - for (const auto& l : root.obj.links) + for (const auto& l : root.obj.all_links ()) vertices_[l.objidx].remap_parent (root_idx () - 1, root_idx ()); return clone_idx; @@ -555,7 +589,7 @@ struct graph_t update_parents (); unsigned links_to_child = 0; - for (const auto& l : vertices_[parent_idx].obj.links) + for (const auto& l : vertices_[parent_idx].obj.all_links ()) { if (l.objidx == child_idx) links_to_child++; } @@ -578,9 +612,8 @@ struct graph_t if (parent_idx == clone_idx) parent_idx++; auto& parent = vertices_[parent_idx]; - for (unsigned i = 0; i < parent.obj.links.length; i++) + for (auto& l : parent.obj.all_links_writer ()) { - auto& l = parent.obj.links[i]; if (l.objidx != child_idx) continue; @@ -593,7 +626,7 @@ struct graph_t /* * Raises the sorting priority of all children. */ - void raise_childrens_priority (unsigned parent_idx) + bool raise_childrens_priority (unsigned parent_idx) { DEBUG_MSG (SUBSET_REPACK, nullptr, " Raising priority of all children of %d", parent_idx); @@ -601,8 +634,10 @@ struct graph_t // to invalidate positions. It does not change graph structure so no need // to update distances or edge counts. auto& parent = vertices_[parent_idx].obj; - for (unsigned i = 0; i < parent.links.length; i++) - vertices_[parent.links[i].objidx].raise_priority (); + bool made_change = false; + for (auto& l : parent.all_links_writer ()) + made_change |= vertices_[l.objidx].raise_priority (); + return made_change; } /* @@ -615,7 +650,8 @@ struct graph_t for (int parent_idx = vertices_.length - 1; parent_idx >= 0; parent_idx--) { - for (const auto& link : vertices_[parent_idx].obj.links) + // Don't need to check virtual links for overflow + for (const auto& link : vertices_[parent_idx].obj.real_links) { int64_t offset = compute_offset (parent_idx, link); if (is_valid_offset (offset, link)) @@ -655,8 +691,10 @@ struct graph_t if (!DEBUG_ENABLED(SUBSET_REPACK)) return; update_parents (); + int limit = 10; for (const auto& o : overflows) { + if (!limit--) break; const auto& parent = vertices_[o.parent]; const auto& child = vertices_[o.child]; DEBUG_MSG (SUBSET_REPACK, nullptr, @@ -665,13 +703,16 @@ struct graph_t "%4d (%4d in, %4d out, space %2d)", o.parent, parent.incoming_edges (), - parent.obj.links.length, + parent.obj.real_links.length + parent.obj.virtual_links.length, space_for (o.parent), o.child, child.incoming_edges (), - child.obj.links.length, + child.obj.real_links.length + child.obj.virtual_links.length, space_for (o.child)); } + if (overflows.length > 10) { + DEBUG_MSG (SUBSET_REPACK, nullptr, " ... plus %d more overflows.", overflows.length - 10); + } } unsigned num_roots_for_space (unsigned space) const @@ -684,12 +725,19 @@ struct graph_t return num_roots_for_space_.length; } - void move_to_new_space (unsigned index) + void move_to_new_space (const hb_set_t& indices) { - auto& node = vertices_[index]; - num_roots_for_space_.push (1); - num_roots_for_space_[node.space] = num_roots_for_space_[node.space] - 1; - node.space = num_roots_for_space_.length - 1; + num_roots_for_space_.push (0); + unsigned new_space = num_roots_for_space_.length - 1; + + for (unsigned index : indices) { + auto& node = vertices_[index]; + num_roots_for_space_[node.space] = num_roots_for_space_[node.space] - 1; + num_roots_for_space_[new_space] = num_roots_for_space_[new_space] + 1; + node.space = new_space; + distance_invalid = true; + positions_invalid = true; + } } unsigned space_for (unsigned index, unsigned* root = nullptr) const @@ -716,6 +764,15 @@ struct graph_t private: + size_t serialized_length () const { + size_t total_size = 0; + for (unsigned i = 0; i < vertices_.length; i++) { + size_t size = vertices_[i].obj.tail - vertices_[i].obj.head; + total_size += size; + } + return total_size; + } + /* * Returns the numbers of incoming edges that are 32bits wide. */ @@ -728,7 +785,8 @@ struct graph_t if (visited.has (p)) continue; visited.add (p); - for (const auto& l : vertices_[p].obj.links) + // Only real links can be wide + for (const auto& l : vertices_[p].obj.real_links) { if (l.objidx == node_idx && l.width == 4 && !l.is_signed) { @@ -755,7 +813,7 @@ struct graph_t for (unsigned p = 0; p < vertices_.length; p++) { - for (auto& l : vertices_[p].obj.links) + for (auto& l : vertices_[p].obj.all_links ()) { vertices_[l.objidx].parents.push (p); } @@ -800,7 +858,7 @@ struct graph_t // Redundant ones are filtered out later on by the visited set. // According to https://www3.cs.stonybrook.edu/~rezaul/papers/TR-07-54.pdf // for practical performance this is faster then using a more advanced queue - // (such as a fibonaacci queue) with a fast decrease priority. + // (such as a fibonacci queue) with a fast decrease priority. for (unsigned i = 0; i < vertices_.length; i++) { if (i == vertices_.length - 1) @@ -823,7 +881,7 @@ struct graph_t int64_t next_distance = vertices_[next_idx].distance; visited[next_idx] = true; - for (const auto& link : next.obj.links) + for (const auto& link : next.obj.all_links ()) { if (visited[link.objidx]) continue; @@ -922,9 +980,8 @@ struct graph_t if (!id_map) return; for (unsigned i : subgraph) { - for (unsigned j = 0; j < vertices_[i].obj.links.length; j++) + for (auto& link : vertices_[i].obj.all_links_writer ()) { - auto& link = vertices_[i].obj.links[j]; if (!id_map.has (link.objidx)) continue; if (only_wide && !(link.width == 4 && !link.is_signed)) continue; @@ -942,9 +999,8 @@ struct graph_t for (unsigned i = 0; i < sorted_graph->length; i++) { (*sorted_graph)[i].remap_parents (id_map); - for (unsigned j = 0; j < (*sorted_graph)[i].obj.links.length; j++) + for (auto& link : (*sorted_graph)[i].obj.all_links_writer ()) { - auto& link = (*sorted_graph)[i].obj.links[j]; link.objidx = id_map[link.objidx]; } } @@ -1011,6 +1067,7 @@ struct graph_t hb_set_t& visited, hb_set_t& connected) { + if (unlikely (!check_success (!visited.in_error ()))) return; if (visited.has (start_idx)) return; visited.add (start_idx); @@ -1023,7 +1080,7 @@ struct graph_t const auto& v = vertices_[start_idx]; // Graph is treated as undirected so search children and parents of start_idx - for (const auto& l : v.obj.links) + for (const auto& l : v.obj.all_links ()) find_connected_nodes (l.objidx, targets, visited, connected); for (unsigned p : v.parents) @@ -1044,27 +1101,50 @@ struct graph_t static bool _try_isolating_subgraphs (const hb_vector_t<graph_t::overflow_record_t>& overflows, graph_t& sorted_graph) { + unsigned space = 0; + hb_set_t roots_to_isolate; + for (int i = overflows.length - 1; i >= 0; i--) { const graph_t::overflow_record_t& r = overflows[i]; - unsigned root = 0; - unsigned space = sorted_graph.space_for (r.parent, &root); - if (!space) continue; - if (sorted_graph.num_roots_for_space (space) <= 1) continue; - DEBUG_MSG (SUBSET_REPACK, nullptr, "Overflow in space %d moving subgraph %d to space %d.", - space, - root, - sorted_graph.next_space ()); + unsigned root; + unsigned overflow_space = sorted_graph.space_for (r.parent, &root); + if (!overflow_space) continue; + if (sorted_graph.num_roots_for_space (overflow_space) <= 1) continue; - hb_set_t roots; - roots.add (root); - sorted_graph.isolate_subgraph (roots); - for (unsigned new_root : roots) - sorted_graph.move_to_new_space (new_root); - return true; + if (!space) { + space = overflow_space; + } + + if (space == overflow_space) + roots_to_isolate.add(root); + } + + if (!roots_to_isolate) return false; + + unsigned maximum_to_move = hb_max ((sorted_graph.num_roots_for_space (space) / 2u), 1u); + if (roots_to_isolate.get_population () > maximum_to_move) { + // Only move at most half of the roots in a space at a time. + unsigned extra = roots_to_isolate.get_population () - maximum_to_move; + while (extra--) { + unsigned root = HB_SET_VALUE_INVALID; + roots_to_isolate.previous (&root); + roots_to_isolate.del (root); + } } - return false; + + DEBUG_MSG (SUBSET_REPACK, nullptr, + "Overflow in space %d (%d roots). Moving %d roots to space %d.", + space, + sorted_graph.num_roots_for_space (space), + roots_to_isolate.get_population (), + sorted_graph.next_space ()); + + sorted_graph.isolate_subgraph (roots_to_isolate); + sorted_graph.move_to_new_space (roots_to_isolate); + + return true; } static bool _process_overflows (const hb_vector_t<graph_t::overflow_record_t>& overflows, @@ -1093,16 +1173,16 @@ static bool _process_overflows (const hb_vector_t<graph_t::overflow_record_t>& o // TODO(garretrieger): initially limiting this to leaf's since they can be // moved closer with fewer consequences. However, this can // likely can be used for non-leafs as well. - // TODO(garretrieger): add a maximum priority, don't try to raise past this. // TODO(garretrieger): also try lowering priority of the parent. Make it // get placed further up in the ordering, closer to it's children. // this is probably preferable if the total size of the parent object // is < then the total size of the children (and the parent can be moved). // Since in that case moving the parent will cause a smaller increase in // the length of other offsets. - sorted_graph.raise_childrens_priority (r.parent); - priority_bumped_parents.add (r.parent); - resolution_attempted = true; + if (sorted_graph.raise_childrens_priority (r.parent)) { + priority_bumped_parents.add (r.parent); + resolution_attempted = true; + } continue; } @@ -1127,19 +1207,17 @@ static bool _process_overflows (const hb_vector_t<graph_t::overflow_record_t>& o * For a detailed writeup describing how the algorithm operates see: * docs/repacker.md */ -inline void +inline hb_blob_t* hb_resolve_overflows (const hb_vector_t<hb_serialize_context_t::object_t *>& packed, hb_tag_t table_tag, - hb_serialize_context_t* c, - unsigned max_rounds = 10) { + unsigned max_rounds = 20) { // Kahn sort is ~twice as fast as shortest distance sort and works for many fonts // so try it first to save time. graph_t sorted_graph (packed); sorted_graph.sort_kahn (); if (!sorted_graph.will_overflow ()) { - sorted_graph.serialize (c); - return; + return sorted_graph.serialize (); } sorted_graph.sort_shortest_distance (); @@ -1178,17 +1256,17 @@ hb_resolve_overflows (const hb_vector_t<hb_serialize_context_t::object_t *>& pac if (sorted_graph.in_error ()) { - c->err (HB_SERIALIZE_ERROR_OTHER); - return; + DEBUG_MSG (SUBSET_REPACK, nullptr, "Sorted graph in error state."); + return nullptr; } if (sorted_graph.will_overflow ()) { - c->err (HB_SERIALIZE_ERROR_OFFSET_OVERFLOW); DEBUG_MSG (SUBSET_REPACK, nullptr, "Offset overflow resolution failed."); - return; + return nullptr; } - sorted_graph.serialize (c); + + return sorted_graph.serialize (); } #endif /* HB_REPACKER_HH */ diff --git a/thirdparty/harfbuzz/src/hb-sanitize.hh b/thirdparty/harfbuzz/src/hb-sanitize.hh index 2e536c7a81..65c2772201 100644 --- a/thirdparty/harfbuzz/src/hb-sanitize.hh +++ b/thirdparty/harfbuzz/src/hb-sanitize.hh @@ -123,6 +123,7 @@ struct hb_sanitize_context_t : hb_sanitize_context_t () : start (nullptr), end (nullptr), max_ops (0), max_subtables (0), + recursion_depth (0), writable (false), edit_count (0), blob (nullptr), num_glyphs (65536), @@ -205,6 +206,7 @@ struct hb_sanitize_context_t : (unsigned) HB_SANITIZE_MAX_OPS_MAX); this->edit_count = 0; this->debug_depth = 0; + this->recursion_depth = 0; DEBUG_MSG_LEVEL (SANITIZE, start, 0, +1, "start [%p..%p] (%lu bytes)", @@ -278,6 +280,18 @@ struct hb_sanitize_context_t : return this->check_range (base, a, b, hb_static_size (T)); } + bool check_start_recursion (int max_depth) + { + if (unlikely (recursion_depth >= max_depth)) return false; + return ++recursion_depth; + } + + bool end_recursion (bool result) + { + recursion_depth--; + return result; + } + template <typename Type> bool check_struct (const Type *obj) const { return likely (this->check_range (obj, obj->min_size)); } @@ -389,6 +403,7 @@ struct hb_sanitize_context_t : const char *start, *end; mutable int max_ops, max_subtables; private: + int recursion_depth; bool writable; unsigned int edit_count; hb_blob_t *blob; diff --git a/thirdparty/harfbuzz/src/hb-serialize.hh b/thirdparty/harfbuzz/src/hb-serialize.hh index 57689916f6..6615f033c5 100644 --- a/thirdparty/harfbuzz/src/hb-serialize.hh +++ b/thirdparty/harfbuzz/src/hb-serialize.hh @@ -65,19 +65,26 @@ struct hb_serialize_context_t struct object_t { - void fini () { links.fini (); } + void fini () { + real_links.fini (); + virtual_links.fini (); + } bool operator == (const object_t &o) const { + // Virtual links aren't considered for equality since they don't affect the functionality + // of the object. return (tail - head == o.tail - o.head) - && (links.length == o.links.length) + && (real_links.length == o.real_links.length) && 0 == hb_memcmp (head, o.head, tail - head) - && links.as_bytes () == o.links.as_bytes (); + && real_links.as_bytes () == o.real_links.as_bytes (); } uint32_t hash () const { + // Virtual links aren't considered for equality since they don't affect the functionality + // of the object. return hb_bytes_t (head, tail - head).hash () ^ - links.as_bytes ().hash (); + real_links.as_bytes ().hash (); } struct link_t @@ -92,8 +99,14 @@ struct hb_serialize_context_t char *head; char *tail; - hb_vector_t<link_t> links; + hb_vector_t<link_t> real_links; + hb_vector_t<link_t> virtual_links; object_t *next; + + auto all_links () const HB_AUTO_RETURN + (( hb_concat (this->real_links, this->virtual_links) )); + auto all_links_writer () HB_AUTO_RETURN + (( hb_concat (this->real_links.writer (), this->virtual_links.writer ()) )); }; struct snapshot_t @@ -101,12 +114,14 @@ struct hb_serialize_context_t char *head; char *tail; object_t *current; // Just for sanity check - unsigned num_links; + unsigned num_real_links; + unsigned num_virtual_links; hb_serialize_error_t errors; }; snapshot_t snapshot () - { return snapshot_t { head, tail, current, current->links.length, errors }; } + { return snapshot_t { + head, tail, current, current->real_links.length, current->virtual_links.length, errors }; } hb_serialize_context_t (void *start_, unsigned int size) : start ((char *) start_), @@ -264,7 +279,7 @@ struct hb_serialize_context_t object_pool.release (obj); } - /* Set share to false when an object is unlikely sharable with others + /* Set share to false when an object is unlikely shareable with others * so not worth an attempt, or a contiguous table is serialized as * multiple consecutive objects in the reverse order so can't be shared. */ @@ -282,7 +297,8 @@ struct hb_serialize_context_t if (!len) { - assert (!obj->links.length); + assert (!obj->real_links.length); + assert (!obj->virtual_links.length); return 0; } @@ -292,6 +308,7 @@ struct hb_serialize_context_t objidx = packed_map.get (obj); if (objidx) { + merge_virtual_links (obj, objidx); obj->fini (); return objidx; } @@ -327,7 +344,8 @@ struct hb_serialize_context_t // Overflows that happened after the snapshot will be erased by the revert. if (unlikely (in_error () && !only_overflow ())) return; assert (snap.current == current); - current->links.shrink (snap.num_links); + current->real_links.shrink (snap.num_real_links); + current->virtual_links.shrink (snap.num_virtual_links); errors = snap.errors; revert (snap.head, snap.tail); } @@ -363,7 +381,7 @@ struct hb_serialize_context_t // Adding a virtual link from object a to object b will ensure that object b is always packed after // object a in the final serialized order. // - // This is useful in certain situtations where there needs to be a specific ordering in the + // This is useful in certain situations where there needs to be a specific ordering in the // final serialization. Such as when platform bugs require certain orderings, or to provide // guidance to the repacker for better offset overflow resolution. void add_virtual_link (objidx_t objidx) @@ -375,8 +393,8 @@ struct hb_serialize_context_t assert (current); - auto& link = *current->links.push (); - if (current->links.in_error ()) + auto& link = *current->virtual_links.push (); + if (current->virtual_links.in_error ()) err (HB_SERIALIZE_ERROR_OTHER); link.width = 0; @@ -400,8 +418,8 @@ struct hb_serialize_context_t assert (current); assert (current->head <= (const char *) &ofs); - auto& link = *current->links.push (); - if (current->links.in_error ()) + auto& link = *current->real_links.push (); + if (current->real_links.in_error ()) err (HB_SERIALIZE_ERROR_OTHER); link.width = sizeof (T); @@ -440,10 +458,8 @@ struct hb_serialize_context_t assert (packed.length > 1); for (const object_t* parent : ++hb_iter (packed)) - for (const object_t::link_t &link : parent->links) + for (const object_t::link_t &link : parent->real_links) { - if (unlikely (!link.width)) continue; // Don't need to resolve virtual offsets - const object_t* child = packed[link.objidx]; if (unlikely (!child)) { err (HB_SERIALIZE_ERROR_OTHER); return; } unsigned offset = 0; @@ -494,7 +510,7 @@ struct hb_serialize_context_t { return reinterpret_cast<Type *> (this->head); } template <typename Type> Type *start_embed (const Type &obj) const - { return start_embed (hb_addressof (obj)); } + { return start_embed (std::addressof (obj)); } bool err (hb_serialize_error_t err_type) { @@ -532,7 +548,7 @@ struct hb_serialize_context_t } template <typename Type> Type *embed (const Type &obj) - { return embed (hb_addressof (obj)); } + { return embed (std::addressof (obj)); } template <typename Type, typename ...Ts> auto _copy (const Type &src, hb_priority<1>, Ts&&... ds) HB_RETURN @@ -579,19 +595,19 @@ struct hb_serialize_context_t } template <typename Type> Type *extend_size (Type &obj, size_t size) - { return extend_size (hb_addressof (obj), size); } + { return extend_size (std::addressof (obj), size); } template <typename Type> Type *extend_min (Type *obj) { return extend_size (obj, obj->min_size); } template <typename Type> - Type *extend_min (Type &obj) { return extend_min (hb_addressof (obj)); } + Type *extend_min (Type &obj) { return extend_min (std::addressof (obj)); } template <typename Type, typename ...Ts> Type *extend (Type *obj, Ts&&... ds) { return extend_size (obj, obj->get_size (std::forward<Ts> (ds)...)); } template <typename Type, typename ...Ts> Type *extend (Type &obj, Ts&&... ds) - { return extend (hb_addressof (obj), std::forward<Ts> (ds)...); } + { return extend (std::addressof (obj), std::forward<Ts> (ds)...); } /* Output routines. */ hb_bytes_t copy_bytes () const @@ -642,6 +658,13 @@ struct hb_serialize_context_t private: + void merge_virtual_links (const object_t* from, objidx_t to_idx) { + object_t* to = packed[to_idx]; + for (const auto& l : from->virtual_links) { + to->virtual_links.push (l); + } + } + /* Object memory pool. */ hb_pool_t<object_t> object_pool; @@ -652,7 +675,9 @@ struct hb_serialize_context_t hb_vector_t<object_t *> packed; /* Map view of packed objects. */ - hb_hashmap_t<const object_t *, objidx_t, nullptr, 0> packed_map; + hb_hashmap_t<const object_t *, objidx_t, + const object_t *, objidx_t, + nullptr, 0> packed_map; }; #endif /* HB_SERIALIZE_HH */ diff --git a/thirdparty/harfbuzz/src/hb-set.hh b/thirdparty/harfbuzz/src/hb-set.hh index 8841427189..af02e9e12b 100644 --- a/thirdparty/harfbuzz/src/hb-set.hh +++ b/thirdparty/harfbuzz/src/hb-set.hh @@ -157,9 +157,9 @@ struct hb_set_t : hb_sparseset_t<hb_bit_set_invertible_t> { hb_set_t () = default; ~hb_set_t () = default; - hb_set_t (hb_set_t& o) = default; - hb_set_t& operator= (const hb_set_t& other) = default; - hb_set_t& operator= (hb_set_t&& other) = default; + hb_set_t (hb_set_t&) = default; + hb_set_t& operator= (const hb_set_t&) = default; + hb_set_t& operator= (hb_set_t&&) = default; hb_set_t (std::initializer_list<hb_codepoint_t> lst) : hb_sparseset_t<hb_bit_set_invertible_t> (lst) {} template <typename Iterable, hb_requires (hb_is_iterable (Iterable))> diff --git a/thirdparty/harfbuzz/src/hb-shape.cc b/thirdparty/harfbuzz/src/hb-shape.cc index c1f619c81c..3407e1af42 100644 --- a/thirdparty/harfbuzz/src/hb-shape.cc +++ b/thirdparty/harfbuzz/src/hb-shape.cc @@ -126,6 +126,13 @@ hb_shape_full (hb_font_t *font, unsigned int num_features, const char * const *shaper_list) { + hb_buffer_t *text_buffer = nullptr; + if (buffer->flags & HB_BUFFER_FLAG_VERIFY) + { + text_buffer = hb_buffer_create (); + hb_buffer_append (text_buffer, buffer, 0, -1); + } + hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached2 (font->face, &buffer->props, features, num_features, font->coords, font->num_coords, @@ -133,6 +140,17 @@ hb_shape_full (hb_font_t *font, hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features); hb_shape_plan_destroy (shape_plan); + if (text_buffer) + { + if (res && !buffer->verify (text_buffer, + font, + features, + num_features, + shaper_list)) + res = false; + hb_buffer_destroy (text_buffer); + } + return res; } diff --git a/thirdparty/harfbuzz/src/hb-static.cc b/thirdparty/harfbuzz/src/hb-static.cc index ec4b241470..bd698814e8 100644 --- a/thirdparty/harfbuzz/src/hb-static.cc +++ b/thirdparty/harfbuzz/src/hb-static.cc @@ -33,6 +33,7 @@ #include "hb-aat-layout-feat-table.hh" #include "hb-ot-layout-common.hh" #include "hb-ot-cmap-table.hh" +#include "hb-ot-glyf-table.hh" #include "hb-ot-head-table.hh" #include "hb-ot-maxp-table.hh" @@ -55,17 +56,41 @@ const unsigned char _hb_Null_AAT_Lookup[2] = {0xFF, 0xFF}; /* hb_face_t */ +static inline unsigned +load_num_glyphs_from_loca (const hb_face_t *face) +{ + unsigned ret = 0; + + unsigned indexToLocFormat = face->table.head->indexToLocFormat; + + if (indexToLocFormat <= 1) + { + bool short_offset = 0 == indexToLocFormat; + hb_blob_t *loca_blob = face->table.loca.get_blob (); + ret = hb_max (1u, loca_blob->length / (short_offset ? 2 : 4)) - 1; + } + + return ret; +} + +static inline unsigned +load_num_glyphs_from_maxp (const hb_face_t *face) +{ + return face->table.maxp->get_num_glyphs (); +} + unsigned int hb_face_t::load_num_glyphs () const { - hb_sanitize_context_t c = hb_sanitize_context_t (); - c.set_num_glyphs (0); /* So we don't recurse ad infinitum. */ - hb_blob_t *maxp_blob = c.reference_table<OT::maxp> (this); - const OT::maxp *maxp_table = maxp_blob->as<OT::maxp> (); + unsigned ret = 0; + +#ifndef HB_NO_BORING_EXPANSION + ret = hb_max (ret, load_num_glyphs_from_loca (this)); +#endif + + ret = hb_max (ret, load_num_glyphs_from_maxp (this)); - unsigned int ret = maxp_table->get_num_glyphs (); num_glyphs.set_relaxed (ret); - hb_blob_destroy (maxp_blob); return ret; } diff --git a/thirdparty/harfbuzz/src/hb-style.cc b/thirdparty/harfbuzz/src/hb-style.cc index f1b44cea53..c7d7d713c2 100644 --- a/thirdparty/harfbuzz/src/hb-style.cc +++ b/thirdparty/harfbuzz/src/hb-style.cc @@ -46,15 +46,14 @@ static inline float _hb_angle_to_ratio (float a) { - return tanf (a * float (M_PI / 180.)); + return tanf (a * float (-M_PI / 180.)); } -#if 0 + static inline float _hb_ratio_to_angle (float r) { - return atanf (r) * float (180. / M_PI); + return atanf (r) * float (-180. / M_PI); } -#endif /** * hb_style_get_value: @@ -109,7 +108,14 @@ hb_style_get_value (hb_font_t *font, hb_style_tag_t style_tag) : 12.f; } case HB_STYLE_TAG_SLANT_ANGLE: - return face->table.post->table->italicAngle.to_float (); + { + float angle = face->table.post->table->italicAngle.to_float (); + + if (font->slant) + angle = _hb_ratio_to_angle (font->slant + _hb_angle_to_ratio (angle)); + + return angle; + } case HB_STYLE_TAG_WIDTH: return face->table.OS2->has_data () ? face->table.OS2->get_width () diff --git a/thirdparty/harfbuzz/src/hb-style.h b/thirdparty/harfbuzz/src/hb-style.h index 30a6f2b878..d17d2daa5f 100644 --- a/thirdparty/harfbuzz/src/hb-style.h +++ b/thirdparty/harfbuzz/src/hb-style.h @@ -43,8 +43,10 @@ HB_BEGIN_DECLS * @HB_STYLE_TAG_SLANT_ANGLE: Used to vary between upright and slanted text. Values * must be greater than -90 and less than +90. Values can be interpreted as * the angle, in counter-clockwise degrees, of oblique slant from whatever the - * designer considers to be upright for that font design. + * designer considers to be upright for that font design. Typical right-leaning + * Italic fonts have a negative slant angle (typically around -12) * @HB_STYLE_TAG_SLANT_RATIO: same as @HB_STYLE_TAG_SLANT_ANGLE expression as ratio. + * Typical right-leaning Italic fonts have a positive slant ratio (typically around 0.2) * @HB_STYLE_TAG_WIDTH: Used to vary width of text from narrower to wider. * Non-zero. Values can be interpreted as a percentage of whatever the font * designer considers “normal width” for that font design. diff --git a/thirdparty/harfbuzz/src/hb-subset-cff-common.hh b/thirdparty/harfbuzz/src/hb-subset-cff-common.hh index 7fd96ca86d..18657705fa 100644 --- a/thirdparty/harfbuzz/src/hb-subset-cff-common.hh +++ b/thirdparty/harfbuzz/src/hb-subset-cff-common.hh @@ -275,60 +275,36 @@ struct subr_flattener_t struct subr_closures_t { - subr_closures_t () : valid (false), global_closure (nullptr) - { local_closures.init (); } - - void init (unsigned int fd_count) + subr_closures_t (unsigned int fd_count) : valid (false), global_closure (), local_closures () { valid = true; - global_closure = hb_set_create (); - if (global_closure == hb_set_get_empty ()) - valid = false; if (!local_closures.resize (fd_count)) valid = false; - - for (unsigned int i = 0; i < local_closures.length; i++) - { - local_closures[i] = hb_set_create (); - if (local_closures[i] == hb_set_get_empty ()) - valid = false; - } - } - - void fini () - { - hb_set_destroy (global_closure); - for (unsigned int i = 0; i < local_closures.length; i++) - hb_set_destroy (local_closures[i]); - local_closures.fini (); } void reset () { - hb_set_clear (global_closure); + global_closure.clear(); for (unsigned int i = 0; i < local_closures.length; i++) - hb_set_clear (local_closures[i]); + local_closures[i].clear(); } bool is_valid () const { return valid; } bool valid; - hb_set_t *global_closure; - hb_vector_t<hb_set_t *> local_closures; + hb_set_t global_closure; + hb_vector_t<hb_set_t> local_closures; }; struct parsed_cs_op_t : op_str_t { void init (unsigned int subr_num_ = 0) { - op_str_t::init (); subr_num = subr_num_; drop_flag = false; keep_flag = false; skip_flag = false; } - void fini () { op_str_t::fini (); } - bool for_drop () const { return drop_flag; } void set_drop () { if (!for_keep ()) drop_flag = true; } @@ -416,16 +392,6 @@ struct parsed_cs_str_t : parsed_values_t<parsed_cs_op_t> struct parsed_cs_str_vec_t : hb_vector_t<parsed_cs_str_t> { - void init (unsigned int len_ = 0) - { - SUPER::init (); - if (unlikely (!resize (len_))) - return; - for (unsigned int i = 0; i < length; i++) - (*this)[i].init (); - } - void fini () { SUPER::fini_deep (); } - private: typedef hb_vector_t<parsed_cs_str_t> SUPER; }; @@ -496,7 +462,7 @@ struct subr_subset_param_t struct subr_remap_t : hb_inc_bimap_t { - void create (hb_set_t *closure) + void create (const hb_set_t *closure) { /* create a remapping of subroutine numbers from old to new. * no optimization based on usage counts. fonttools doesn't appear doing that either. @@ -526,19 +492,9 @@ struct subr_remap_t : hb_inc_bimap_t struct subr_remaps_t { - subr_remaps_t () + subr_remaps_t (unsigned int fdCount) { - global_remap.init (); - local_remaps.init (); - } - - ~subr_remaps_t () { fini (); } - - void init (unsigned int fdCount) - { - if (unlikely (!local_remaps.resize (fdCount))) return; - for (unsigned int i = 0; i < fdCount; i++) - local_remaps[i].init (); + local_remaps.resize (fdCount); } bool in_error() @@ -548,15 +504,9 @@ struct subr_remaps_t void create (subr_closures_t& closures) { - global_remap.create (closures.global_closure); + global_remap.create (&closures.global_closure); for (unsigned int i = 0; i < local_remaps.length; i++) - local_remaps[i].create (closures.local_closures[i]); - } - - void fini () - { - global_remap.fini (); - local_remaps.fini_deep (); + local_remaps[i].create (&closures.local_closures[i]); } subr_remap_t global_remap; @@ -567,21 +517,8 @@ template <typename SUBSETTER, typename SUBRS, typename ACC, typename ENV, typena struct subr_subsetter_t { subr_subsetter_t (ACC &acc_, const hb_subset_plan_t *plan_) - : acc (acc_), plan (plan_) - { - parsed_charstrings.init (); - parsed_global_subrs.init (); - parsed_local_subrs.init (); - } - - ~subr_subsetter_t () - { - closures.fini (); - remaps.fini (); - parsed_charstrings.fini_deep (); - parsed_global_subrs.fini_deep (); - parsed_local_subrs.fini_deep (); - } + : acc (acc_), plan (plan_), closures(acc_.fdCount), remaps(acc_.fdCount) + {} /* Subroutine subsetting with --no-desubroutinize runs in phases: * @@ -599,11 +536,8 @@ struct subr_subsetter_t */ bool subset (void) { - closures.init (acc.fdCount); - remaps.init (acc.fdCount); - - parsed_charstrings.init (plan->num_output_glyphs ()); - parsed_global_subrs.init (acc.globalSubrs->count); + parsed_charstrings.resize (plan->num_output_glyphs ()); + parsed_global_subrs.resize (acc.globalSubrs->count); if (unlikely (remaps.in_error() || parsed_charstrings.in_error () @@ -615,7 +549,7 @@ struct subr_subsetter_t for (unsigned int i = 0; i < acc.fdCount; i++) { - parsed_local_subrs[i].init (acc.privateDicts[i].localSubrs->count); + parsed_local_subrs[i].resize (acc.privateDicts[i].localSubrs->count); if (unlikely (parsed_local_subrs[i].in_error ())) return false; } if (unlikely (!closures.valid)) @@ -638,7 +572,7 @@ struct subr_subsetter_t subr_subset_param_t param; param.init (&parsed_charstrings[i], &parsed_global_subrs, &parsed_local_subrs[fd], - closures.global_closure, closures.local_closures[fd], + &closures.global_closure, &closures.local_closures[fd], plan->flags & HB_SUBSET_FLAGS_NO_HINTING); if (unlikely (!interp.interpret (param))) @@ -662,7 +596,7 @@ struct subr_subsetter_t subr_subset_param_t param; param.init (&parsed_charstrings[i], &parsed_global_subrs, &parsed_local_subrs[fd], - closures.global_closure, closures.local_closures[fd], + &closures.global_closure, &closures.local_closures[fd], plan->flags & HB_SUBSET_FLAGS_NO_HINTING); drop_hints_param_t drop; @@ -687,7 +621,7 @@ struct subr_subsetter_t subr_subset_param_t param; param.init (&parsed_charstrings[i], &parsed_global_subrs, &parsed_local_subrs[fd], - closures.global_closure, closures.local_closures[fd], + &closures.global_closure, &closures.local_closures[fd], plan->flags & HB_SUBSET_FLAGS_NO_HINTING); collect_subr_refs_in_str (parsed_charstrings[i], param); } diff --git a/thirdparty/harfbuzz/src/hb-subset-cff1.cc b/thirdparty/harfbuzz/src/hb-subset-cff1.cc index b4e24122c9..35fecd67bc 100644 --- a/thirdparty/harfbuzz/src/hb-subset-cff1.cc +++ b/thirdparty/harfbuzz/src/hb-subset-cff1.cc @@ -362,43 +362,11 @@ struct cff1_subr_subsetter_t : subr_subsetter_t<cff1_subr_subsetter_t, CFF1Subrs struct cff_subset_plan { cff_subset_plan () - : info (), - orig_fdcount (0), - subset_fdcount (1), - subset_fdselect_format (0), - drop_hints (false), - desubroutinize(false) { - topdict_mod.init (); - subset_fdselect_ranges.init (); - fdmap.init (); - subset_charstrings.init (); - subset_globalsubrs.init (); - subset_localsubrs.init (); - fontdicts_mod.init (); - subset_enc_code_ranges.init (); - subset_enc_supp_codes.init (); - subset_charset_ranges.init (); - sidmap.init (); for (unsigned int i = 0; i < name_dict_values_t::ValCount; i++) topDictModSIDs[i] = CFF_UNDEF_SID; } - ~cff_subset_plan () - { - topdict_mod.fini (); - subset_fdselect_ranges.fini (); - fdmap.fini (); - subset_charstrings.fini_deep (); - subset_globalsubrs.fini_deep (); - subset_localsubrs.fini_deep (); - fontdicts_mod.fini (); - subset_enc_code_ranges.fini (); - subset_enc_supp_codes.fini (); - subset_charset_ranges.fini (); - sidmap.fini (); - } - void plan_subset_encoding (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan) { const Encoding *encoding = acc.encoding; @@ -672,9 +640,9 @@ struct cff_subset_plan { cff1_sub_table_info_t info; unsigned int num_glyphs; - unsigned int orig_fdcount; - unsigned int subset_fdcount; - unsigned int subset_fdselect_format; + unsigned int orig_fdcount = 0; + unsigned int subset_fdcount = 1; + unsigned int subset_fdselect_format = 0; hb_vector_t<code_pair_t> subset_fdselect_ranges; /* font dict index remap table from fullset FDArray to subset FDArray. @@ -686,7 +654,7 @@ struct cff_subset_plan { hb_vector_t<str_buff_vec_t> subset_localsubrs; hb_vector_t<cff1_font_dict_values_mod_t> fontdicts_mod; - bool drop_hints; + bool drop_hints = false; bool gid_renum; bool subset_encoding; @@ -702,7 +670,7 @@ struct cff_subset_plan { remap_sid_t sidmap; unsigned int topDictModSIDs[name_dict_values_t::ValCount]; - bool desubroutinize; + bool desubroutinize = false; }; static bool _serialize_cff1 (hb_serialize_context_t *c, diff --git a/thirdparty/harfbuzz/src/hb-subset-cff2.cc b/thirdparty/harfbuzz/src/hb-subset-cff2.cc index 896ae64016..92dd6b1d2c 100644 --- a/thirdparty/harfbuzz/src/hb-subset-cff2.cc +++ b/thirdparty/harfbuzz/src/hb-subset-cff2.cc @@ -233,29 +233,6 @@ struct cff2_subr_subsetter_t : subr_subsetter_t<cff2_subr_subsetter_t, CFF2Subrs }; struct cff2_subset_plan { - cff2_subset_plan () - : orig_fdcount (0), - subset_fdcount(1), - subset_fdselect_size (0), - subset_fdselect_format (0), - drop_hints (false), - desubroutinize (false) - { - subset_fdselect_ranges.init (); - fdmap.init (); - subset_charstrings.init (); - subset_globalsubrs.init (); - subset_localsubrs.init (); - } - - ~cff2_subset_plan () - { - subset_fdselect_ranges.fini (); - fdmap.fini (); - subset_charstrings.fini_deep (); - subset_globalsubrs.fini_deep (); - subset_localsubrs.fini_deep (); - } bool create (const OT::cff2::accelerator_subset_t &acc, hb_subset_plan_t *plan) @@ -320,10 +297,10 @@ struct cff2_subset_plan { cff2_sub_table_info_t info; - unsigned int orig_fdcount; - unsigned int subset_fdcount; - unsigned int subset_fdselect_size; - unsigned int subset_fdselect_format; + unsigned int orig_fdcount = 0; + unsigned int subset_fdcount = 1; + unsigned int subset_fdselect_size = 0; + unsigned int subset_fdselect_format = 0; hb_vector_t<code_pair_t> subset_fdselect_ranges; hb_inc_bimap_t fdmap; @@ -332,8 +309,8 @@ struct cff2_subset_plan { str_buff_vec_t subset_globalsubrs; hb_vector_t<str_buff_vec_t> subset_localsubrs; - bool drop_hints; - bool desubroutinize; + bool drop_hints = false; + bool desubroutinize = false; }; static bool _serialize_cff2 (hb_serialize_context_t *c, @@ -473,12 +450,8 @@ _hb_subset_cff2 (const OT::cff2::accelerator_subset_t &acc, bool hb_subset_cff2 (hb_subset_context_t *c) { - OT::cff2::accelerator_subset_t acc; - acc.init (c->plan->source); - bool result = likely (acc.is_valid ()) && _hb_subset_cff2 (acc, c); - acc.fini (); - - return result; + OT::cff2::accelerator_subset_t acc (c->plan->source); + return acc.is_valid () && _hb_subset_cff2 (acc, c); } #endif diff --git a/thirdparty/harfbuzz/src/hb-subset-plan.cc b/thirdparty/harfbuzz/src/hb-subset-plan.cc index 1e195ff660..4481758415 100644 --- a/thirdparty/harfbuzz/src/hb-subset-plan.cc +++ b/thirdparty/harfbuzz/src/hb-subset-plan.cc @@ -41,7 +41,7 @@ #include "hb-ot-math-table.hh" -typedef hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> script_langsys_map; +typedef hb_hashmap_t<unsigned, hb_set_t *> script_langsys_map; #ifndef HB_NO_SUBSET_CFF static inline void _add_cff_seac_components (const OT::cff1::accelerator_t &cff, @@ -100,11 +100,23 @@ static void _collect_layout_indices (hb_face_t *face, if (!features.alloc (table.get_feature_count () + 1)) return; + hb_set_t visited_features; + bool retain_all_features = true; for (unsigned i = 0; i < table.get_feature_count (); i++) { hb_tag_t tag = table.get_feature_tag (i); - if (tag && layout_features_to_retain->has (tag)) - features.push (tag); + if (!tag) continue; + if (!layout_features_to_retain->has (tag)) + { + retain_all_features = false; + continue; + } + + if (visited_features.has (tag)) + continue; + + features.push (tag); + visited_features.add (tag); } if (!features) @@ -113,7 +125,7 @@ static void _collect_layout_indices (hb_face_t *face, // The collect function needs a null element to signal end of the array. features.push (0); - if (features.get_size () == table.get_feature_count () + 1) + if (retain_all_features) { // Looking for all features, trigger the faster collection method. layout_collect_func (face, @@ -216,10 +228,8 @@ _cmap_closure (hb_face_t *face, const hb_set_t *unicodes, hb_set_t *glyphset) { - OT::cmap::accelerator_t cmap; - cmap.init (face); + OT::cmap::accelerator_t cmap (face); cmap.table->closure_glyphs (unicodes, glyphset); - cmap.fini (); } static void _colr_closure (hb_face_t *face, @@ -227,8 +237,7 @@ static void _colr_closure (hb_face_t *face, hb_map_t *palettes_map, hb_set_t *glyphs_colred) { - OT::COLR::accelerator_t colr; - colr.init (face); + OT::COLR::accelerator_t colr (face); if (!colr.is_valid ()) return; unsigned iteration_count = 0; @@ -236,14 +245,13 @@ static void _colr_closure (hb_face_t *face, unsigned glyphs_num; { glyphs_num = glyphs_colred->get_population (); - // Collect all glyphs referenced by COLRv0 hb_set_t glyphset_colrv0; for (hb_codepoint_t gid : glyphs_colred->iter ()) colr.closure_glyphs (gid, &glyphset_colrv0); - + glyphs_colred->union_ (glyphset_colrv0); - + //closure for COLRv1 colr.closure_forV1 (glyphs_colred, &layer_indices, &palette_indices); } while (iteration_count++ <= HB_CLOSURE_MAX_STAGES && @@ -252,7 +260,6 @@ static void _colr_closure (hb_face_t *face, colr.closure_V0palette_indices (glyphs_colred, &palette_indices); _remap_indexes (&layer_indices, layers_map); _remap_palette_indexes (&palette_indices, palettes_map); - colr.fini (); } static inline void @@ -283,8 +290,7 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes, const hb_set_t *glyphs, hb_subset_plan_t *plan) { - OT::cmap::accelerator_t cmap; - cmap.init (plan->source); + OT::cmap::accelerator_t cmap (plan->source); constexpr static const int size_threshold = 4096; @@ -332,8 +338,6 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes, + plan->codepoint_to_glyph->keys () | hb_sink (plan->unicodes); + plan->codepoint_to_glyph->values () | hb_sink (plan->_glyphset_gsub); - - cmap.fini (); } static void @@ -342,13 +346,9 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, bool close_over_gpos, bool close_over_gdef) { - OT::glyf::accelerator_t glyf; -#ifndef HB_NO_SUBSET_CFF - OT::cff1::accelerator_t cff; -#endif - glyf.init (plan->source); + OT::glyf::accelerator_t glyf (plan->source); #ifndef HB_NO_SUBSET_CFF - cff.init (plan->source); + OT::cff1::accelerator_t cff (plan->source); #endif plan->_glyphset_gsub->add (0); // Not-def @@ -385,6 +385,7 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, _colr_closure (plan->source, plan->colrv1_layers, plan->colr_palettes, &cur_glyphset); _remove_invalid_gids (&cur_glyphset, plan->source->get_num_glyphs ()); + hb_set_set (plan->_glyphset_colred, &cur_glyphset); // Populate a full set of glyphs to retain by adding all referenced // composite glyphs. for (hb_codepoint_t gid : cur_glyphset.iter ()) @@ -407,11 +408,6 @@ _populate_gids_to_retain (hb_subset_plan_t* plan, plan->layout_variation_indices, plan->layout_variation_idx_map); #endif - -#ifndef HB_NO_SUBSET_CFF - cff.fini (); -#endif - glyf.fini (); } static void @@ -462,7 +458,7 @@ _nameid_closure (hb_face_t *face, } /** - * hb_subset_plan_create: + * hb_subset_plan_create_or_fail: * @face: font face to create the plan for. * @input: a #hb_subset_input_t input. * @@ -471,17 +467,18 @@ _nameid_closure (hb_face_t *face, * which tables and glyphs should be retained. * * Return value: (transfer full): New subset plan. Destroy with - * hb_subset_plan_destroy(). + * hb_subset_plan_destroy(). If there is a failure creating the plan + * nullptr will be returned. * - * Since: 1.7.5 + * Since: 4.0.0 **/ hb_subset_plan_t * -hb_subset_plan_create (hb_face_t *face, - const hb_subset_input_t *input) +hb_subset_plan_create_or_fail (hb_face_t *face, + const hb_subset_input_t *input) { hb_subset_plan_t *plan; if (unlikely (!(plan = hb_object_create<hb_subset_plan_t> ()))) - return const_cast<hb_subset_plan_t *> (&Null (hb_subset_plan_t)); + return nullptr; plan->successful = true; plan->flags = input->flags; @@ -499,6 +496,7 @@ hb_subset_plan_create (hb_face_t *face, plan->_glyphset = hb_set_create (); plan->_glyphset_gsub = hb_set_create (); plan->_glyphset_mathed = hb_set_create (); + plan->_glyphset_colred = hb_set_create (); plan->codepoint_to_glyph = hb_map_create (); plan->glyph_map = hb_map_create (); plan->reverse_glyph_map = hb_map_create (); @@ -517,8 +515,9 @@ hb_subset_plan_create (hb_face_t *face, plan->layout_variation_indices = hb_set_create (); plan->layout_variation_idx_map = hb_map_create (); - if (plan->in_error ()) { - return plan; + if (unlikely (plan->in_error ())) { + hb_subset_plan_destroy (plan); + return nullptr; } _populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, plan); @@ -535,6 +534,10 @@ hb_subset_plan_create (hb_face_t *face, plan->reverse_glyph_map, &plan->_num_output_glyphs); + if (unlikely (plan->in_error ())) { + hb_subset_plan_destroy (plan); + return nullptr; + } return plan; } @@ -545,7 +548,7 @@ hb_subset_plan_create (hb_face_t *face, * Decreases the reference count on @plan, and if it reaches zero, destroys * @plan, freeing all memory. * - * Since: 1.7.5 + * Since: 4.0.0 **/ void hb_subset_plan_destroy (hb_subset_plan_t *plan) @@ -567,6 +570,7 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan) hb_set_destroy (plan->_glyphset); hb_set_destroy (plan->_glyphset_gsub); hb_set_destroy (plan->_glyphset_mathed); + hb_set_destroy (plan->_glyphset_colred); hb_map_destroy (plan->gsub_lookups); hb_map_destroy (plan->gpos_lookups); hb_map_destroy (plan->gsub_features); @@ -598,3 +602,116 @@ hb_subset_plan_destroy (hb_subset_plan_t *plan) hb_free (plan); } + +/** + * hb_subset_plan_old_to_new_glyph_mapping: + * @plan: a subsetting plan. + * + * Returns the mapping between glyphs in the original font to glyphs in the + * subset that will be produced by @plan + * + * Return value: (transfer none): + * A pointer to the #hb_map_t of the mapping. + * + * Since: 4.0.0 + **/ +const hb_map_t* +hb_subset_plan_old_to_new_glyph_mapping (const hb_subset_plan_t *plan) +{ + return plan->glyph_map; +} + +/** + * hb_subset_plan_new_to_old_glyph_mapping: + * @plan: a subsetting plan. + * + * Returns the mapping between glyphs in the subset that will be produced by + * @plan and the glyph in the original font. + * + * Return value: (transfer none): + * A pointer to the #hb_map_t of the mapping. + * + * Since: 4.0.0 + **/ +const hb_map_t* +hb_subset_plan_new_to_old_glyph_mapping (const hb_subset_plan_t *plan) +{ + return plan->reverse_glyph_map; +} + +/** + * hb_subset_plan_unicode_to_old_glyph_mapping: + * @plan: a subsetting plan. + * + * Returns the mapping between codepoints in the original font and the + * associated glyph id in the original font. + * + * Return value: (transfer none): + * A pointer to the #hb_map_t of the mapping. + * + * Since: 4.0.0 + **/ +const hb_map_t* +hb_subset_plan_unicode_to_old_glyph_mapping (const hb_subset_plan_t *plan) +{ + return plan->codepoint_to_glyph; +} + +/** + * hb_subset_plan_reference: (skip) + * @plan: a #hb_subset_plan_t object. + * + * Increases the reference count on @plan. + * + * Return value: @plan. + * + * Since: 4.0.0 + **/ +hb_subset_plan_t * +hb_subset_plan_reference (hb_subset_plan_t *plan) +{ + return hb_object_reference (plan); +} + +/** + * hb_subset_plan_set_user_data: (skip) + * @plan: a #hb_subset_plan_t object. + * @key: The user-data key to set + * @data: A pointer to the user data + * @destroy: (nullable): A callback to call when @data is not needed anymore + * @replace: Whether to replace an existing data with the same key + * + * Attaches a user-data key/data pair to the given subset plan object. + * + * Return value: %true if success, %false otherwise + * + * Since: 4.0.0 + **/ +hb_bool_t +hb_subset_plan_set_user_data (hb_subset_plan_t *plan, + hb_user_data_key_t *key, + void *data, + hb_destroy_func_t destroy, + hb_bool_t replace) +{ + return hb_object_set_user_data (plan, key, data, destroy, replace); +} + +/** + * hb_subset_plan_get_user_data: (skip) + * @plan: a #hb_subset_plan_t object. + * @key: The user-data key to query + * + * Fetches the user data associated with the specified key, + * attached to the specified subset plan object. + * + * Return value: (transfer none): A pointer to the user data + * + * Since: 4.0.0 + **/ +void * +hb_subset_plan_get_user_data (const hb_subset_plan_t *plan, + hb_user_data_key_t *key) +{ + return hb_object_get_user_data (plan, key); +} diff --git a/thirdparty/harfbuzz/src/hb-subset-plan.hh b/thirdparty/harfbuzz/src/hb-subset-plan.hh index c30feeb42f..ab2c4c302c 100644 --- a/thirdparty/harfbuzz/src/hb-subset-plan.hh +++ b/thirdparty/harfbuzz/src/hb-subset-plan.hh @@ -78,14 +78,15 @@ struct hb_subset_plan_t hb_set_t *_glyphset; hb_set_t *_glyphset_gsub; hb_set_t *_glyphset_mathed; + hb_set_t *_glyphset_colred; //active lookups we'd like to retain hb_map_t *gsub_lookups; hb_map_t *gpos_lookups; //active langsys we'd like to retain - hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *gsub_langsys; - hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> *gpos_langsys; + hb_hashmap_t<unsigned, hb_set_t *> *gsub_langsys; + hb_hashmap_t<unsigned, hb_set_t *> *gpos_langsys; //active features after removing redundant langsys and prune_features hb_map_t *gsub_features; @@ -197,13 +198,4 @@ struct hb_subset_plan_t } }; -typedef struct hb_subset_plan_t hb_subset_plan_t; - -HB_INTERNAL hb_subset_plan_t * -hb_subset_plan_create (hb_face_t *face, - const hb_subset_input_t *input); - -HB_INTERNAL void -hb_subset_plan_destroy (hb_subset_plan_t *plan); - #endif /* HB_SUBSET_PLAN_HH */ diff --git a/thirdparty/harfbuzz/src/hb-subset.cc b/thirdparty/harfbuzz/src/hb-subset.cc index 048bdf1888..aa8f2c6fb0 100644 --- a/thirdparty/harfbuzz/src/hb-subset.cc +++ b/thirdparty/harfbuzz/src/hb-subset.cc @@ -104,20 +104,16 @@ _repack (hb_tag_t tag, const hb_serialize_context_t& c) if (!c.offset_overflow ()) return c.copy_blob (); - hb_vector_t<char> buf; - int buf_size = c.end - c.start; - if (unlikely (!buf.alloc (buf_size))) - return nullptr; - - hb_serialize_context_t repacked ((void *) buf, buf_size); - hb_resolve_overflows (c.object_graph (), tag, &repacked); + hb_blob_t* result = hb_resolve_overflows (c.object_graph (), tag); - if (unlikely (repacked.in_error ())) - // TODO(garretrieger): refactor so we can share the resize/retry logic with the subset - // portion. + if (unlikely (!result)) + { + DEBUG_MSG (SUBSET, nullptr, "OT::%c%c%c%c offset overflow resolution failed.", + HB_UNTAG (tag)); return nullptr; + } - return repacked.copy_blob (); + return result; } template<typename TableType> @@ -347,9 +343,33 @@ hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input) { if (unlikely (!input || !source)) return hb_face_get_empty (); - hb_subset_plan_t *plan = hb_subset_plan_create (source, input); - if (unlikely (plan->in_error ())) { - hb_subset_plan_destroy (plan); + hb_subset_plan_t *plan = hb_subset_plan_create_or_fail (source, input); + if (unlikely (!plan)) { + return nullptr; + } + + hb_face_t * result = hb_subset_plan_execute_or_fail (plan); + hb_subset_plan_destroy (plan); + return result; +} + + +/** + * hb_subset_plan_execute_or_fail: + * @plan: a subsetting plan. + * + * Executes the provided subsetting @plan. + * + * Return value: + * on success returns a reference to generated font subset. If the subsetting operation fails + * returns nullptr. + * + * Since: 4.0.0 + **/ +hb_face_t * +hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan) +{ + if (unlikely (!plan || plan->in_error ())) { return nullptr; } @@ -357,7 +377,7 @@ hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input) bool success = true; hb_tag_t table_tags[32]; unsigned offset = 0, num_tables = ARRAY_LENGTH (table_tags); - while ((hb_face_get_table_tags (source, offset, &num_tables, table_tags), num_tables)) + while ((hb_face_get_table_tags (plan->source, offset, &num_tables, table_tags), num_tables)) { for (unsigned i = 0; i < num_tables; ++i) { @@ -371,8 +391,5 @@ hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input) } end: - hb_face_t *result = success ? hb_face_reference (plan->dest) : nullptr; - - hb_subset_plan_destroy (plan); - return result; + return success ? hb_face_reference (plan->dest) : nullptr; } diff --git a/thirdparty/harfbuzz/src/hb-subset.h b/thirdparty/harfbuzz/src/hb-subset.h index 1c65a4da1c..a2799d91e8 100644 --- a/thirdparty/harfbuzz/src/hb-subset.h +++ b/thirdparty/harfbuzz/src/hb-subset.h @@ -40,6 +40,15 @@ HB_BEGIN_DECLS typedef struct hb_subset_input_t hb_subset_input_t; /** + * hb_subset_plan_t: + * + * Contains information about how the subset operation will be executed. + * Such as mappings from the old glyph ids to the new ones in the subset. + */ + +typedef struct hb_subset_plan_t hb_subset_plan_t; + +/** * hb_subset_flags_t: * @HB_SUBSET_FLAGS_DEFAULT: all flags at their default value of false. * @HB_SUBSET_FLAGS_NO_HINTING: If set hinting instructions will be dropped in @@ -124,7 +133,7 @@ hb_subset_input_set_user_data (hb_subset_input_t *input, HB_EXTERN void * hb_subset_input_get_user_data (const hb_subset_input_t *input, - hb_user_data_key_t *key); + hb_user_data_key_t *key); HB_EXTERN hb_set_t * hb_subset_input_unicode_set (hb_subset_input_t *input); @@ -145,6 +154,41 @@ hb_subset_input_set_flags (hb_subset_input_t *input, HB_EXTERN hb_face_t * hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input); +HB_EXTERN hb_face_t * +hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan); + +HB_EXTERN hb_subset_plan_t * +hb_subset_plan_create_or_fail (hb_face_t *face, + const hb_subset_input_t *input); + +HB_EXTERN void +hb_subset_plan_destroy (hb_subset_plan_t *plan); + +HB_EXTERN const hb_map_t* +hb_subset_plan_old_to_new_glyph_mapping (const hb_subset_plan_t *plan); + +HB_EXTERN const hb_map_t* +hb_subset_plan_new_to_old_glyph_mapping (const hb_subset_plan_t *plan); + +HB_EXTERN const hb_map_t* +hb_subset_plan_unicode_to_old_glyph_mapping (const hb_subset_plan_t *plan); + + +HB_EXTERN hb_subset_plan_t * +hb_subset_plan_reference (hb_subset_plan_t *plan); + +HB_EXTERN hb_bool_t +hb_subset_plan_set_user_data (hb_subset_plan_t *plan, + hb_user_data_key_t *key, + void *data, + hb_destroy_func_t destroy, + hb_bool_t replace); + +HB_EXTERN void * +hb_subset_plan_get_user_data (const hb_subset_plan_t *plan, + hb_user_data_key_t *key); + + HB_END_DECLS #endif /* HB_SUBSET_H */ diff --git a/thirdparty/harfbuzz/src/hb-uniscribe.cc b/thirdparty/harfbuzz/src/hb-uniscribe.cc index 3dc4c0937d..50f71ce9ce 100644 --- a/thirdparty/harfbuzz/src/hb-uniscribe.cc +++ b/thirdparty/harfbuzz/src/hb-uniscribe.cc @@ -878,7 +878,8 @@ retry: if (backward) hb_buffer_reverse (buffer); - buffer->unsafe_to_break_all (); + buffer->clear_glyph_flags (); + buffer->unsafe_to_break (); /* Wow, done! */ return true; diff --git a/thirdparty/harfbuzz/src/hb-vector.hh b/thirdparty/harfbuzz/src/hb-vector.hh index b0a1e5e966..6c7d32e49d 100644 --- a/thirdparty/harfbuzz/src/hb-vector.hh +++ b/thirdparty/harfbuzz/src/hb-vector.hh @@ -32,11 +32,14 @@ #include "hb-null.hh" -template <typename Type> -struct hb_vector_t +template <typename Type, + bool sorted=false> +struct hb_vector_t : std::conditional<sorted, hb_vector_t<Type, false>, hb_empty_t>::type { typedef Type item_t; static constexpr unsigned item_size = hb_static_size (Type); + using array_t = typename std::conditional<sorted, hb_sorted_array_t<Type>, hb_array_t<Type>>::type; + using c_array_t = typename std::conditional<sorted, hb_sorted_array_t<const Type>, hb_array_t<const Type>>::type; hb_vector_t () = default; hb_vector_t (std::initializer_list<Type> lst) : hb_vector_t () @@ -82,16 +85,10 @@ struct hb_vector_t void fini () { + shrink_vector (0); hb_free (arrayZ); init (); } - void fini_deep () - { - unsigned int count = length; - for (unsigned int i = 0; i < count; i++) - arrayZ[i].fini (); - fini (); - } void reset () { @@ -152,24 +149,24 @@ struct hb_vector_t template <typename T> hb_vector_t& operator << (T&& v) { push (std::forward<T> (v)); return *this; } - hb_array_t< Type> as_array () { return hb_array (arrayZ, length); } - hb_array_t<const Type> as_array () const { return hb_array (arrayZ, length); } + array_t as_array () { return hb_array (arrayZ, length); } + c_array_t as_array () const { return hb_array (arrayZ, length); } /* Iterator. */ - typedef hb_array_t<const Type> iter_t; - typedef hb_array_t< Type> writer_t; + typedef c_array_t iter_t; + typedef array_t writer_t; iter_t iter () const { return as_array (); } writer_t writer () { return as_array (); } operator iter_t () const { return iter (); } operator writer_t () { return writer (); } - hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const + c_array_t sub_array (unsigned int start_offset, unsigned int count) const { return as_array ().sub_array (start_offset, count); } - hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const + c_array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const { return as_array ().sub_array (start_offset, count); } - hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count) + array_t sub_array (unsigned int start_offset, unsigned int count) { return as_array ().sub_array (start_offset, count); } - hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) + array_t sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) { return as_array ().sub_array (start_offset, count); } hb_sorted_array_t<Type> as_sorted_array () @@ -192,6 +189,7 @@ struct hb_vector_t template <typename T> Type *push (T&& v) { + /* TODO Emplace? */ Type *p = push (); if (p == &Crap (Type)) // If push failed to allocate then don't copy v, since this may cause @@ -204,6 +202,92 @@ struct hb_vector_t bool in_error () const { return allocated < 0; } + template <typename T = Type, + hb_enable_if (std::is_trivially_copy_assignable<T>::value)> + Type * + realloc_vector (unsigned new_allocated) + { + return (Type *) hb_realloc (arrayZ, new_allocated * sizeof (Type)); + } + template <typename T = Type, + hb_enable_if (!std::is_trivially_copy_assignable<T>::value)> + Type * + realloc_vector (unsigned new_allocated) + { + Type *new_array = (Type *) hb_malloc (new_allocated * sizeof (Type)); + if (likely (new_array)) + { + for (unsigned i = 0; i < length; i++) + new (std::addressof (new_array[i])) Type (); + for (unsigned i = 0; i < (unsigned) length; i++) + new_array[i] = std::move (arrayZ[i]); + unsigned old_length = length; + shrink_vector (0); + length = old_length; + hb_free (arrayZ); + } + return new_array; + } + + template <typename T = Type, + hb_enable_if (std::is_trivially_constructible<T>::value || + !std::is_default_constructible<T>::value)> + void + grow_vector (unsigned size) + { + memset (arrayZ + length, 0, (size - length) * sizeof (*arrayZ)); + length = size; + } + template <typename T = Type, + hb_enable_if (!std::is_trivially_constructible<T>::value && + std::is_default_constructible<T>::value)> + void + grow_vector (unsigned size) + { + while (length < size) + { + length++; + new (std::addressof (arrayZ[length - 1])) Type (); + } + } + + template <typename T = Type, + hb_enable_if (std::is_trivially_destructible<T>::value)> + void + shrink_vector (unsigned size) + { + length = size; + } + template <typename T = Type, + hb_enable_if (!std::is_trivially_destructible<T>::value)> + void + shrink_vector (unsigned size) + { + while ((unsigned) length > size) + { + arrayZ[(unsigned) length - 1].~Type (); + length--; + } + } + + template <typename T = Type, + hb_enable_if (std::is_trivially_copy_assignable<T>::value)> + void + shift_down_vector (unsigned i) + { + memmove (static_cast<void *> (&arrayZ[i - 1]), + static_cast<void *> (&arrayZ[i]), + (length - i) * sizeof (Type)); + } + template <typename T = Type, + hb_enable_if (!std::is_trivially_copy_assignable<T>::value)> + void + shift_down_vector (unsigned i) + { + for (; i < length; i++) + arrayZ[i - 1] = std::move (arrayZ[i]); + } + /* Allocate for size but don't adjust length. */ bool alloc (unsigned int size) { @@ -225,7 +309,7 @@ struct hb_vector_t (new_allocated < (unsigned) allocated) || hb_unsigned_mul_overflows (new_allocated, sizeof (Type)); if (likely (!overflows)) - new_array = (Type *) hb_realloc (arrayZ, new_allocated * sizeof (Type)); + new_array = realloc_vector (new_allocated); if (unlikely (!new_array)) { @@ -246,7 +330,9 @@ struct hb_vector_t return false; if (size > length) - memset (arrayZ + length, 0, (size - length) * sizeof (*arrayZ)); + grow_vector (size); + else if (size < length) + shrink_vector (size); length = size; return true; @@ -255,48 +341,38 @@ struct hb_vector_t Type pop () { if (!length) return Null (Type); - return std::move (arrayZ[--length]); /* Does this move actually work? */ + Type v = std::move (arrayZ[length - 1]); + arrayZ[length - 1].~Type (); + length--; + return v; } void remove (unsigned int i) { if (unlikely (i >= length)) return; - memmove (static_cast<void *> (&arrayZ[i]), - static_cast<void *> (&arrayZ[i + 1]), - (length - i - 1) * sizeof (Type)); + arrayZ[i].~Type (); + shift_down_vector (i + 1); length--; } void shrink (int size_) { unsigned int size = size_ < 0 ? 0u : (unsigned int) size_; - if (size < length) - length = size; - } + if (size >= length) + return; - template <typename T> - Type *find (T v) - { - for (unsigned int i = 0; i < length; i++) - if (arrayZ[i] == v) - return &arrayZ[i]; - return nullptr; - } - template <typename T> - const Type *find (T v) const - { - for (unsigned int i = 0; i < length; i++) - if (arrayZ[i] == v) - return &arrayZ[i]; - return nullptr; + shrink_vector (size); } + + /* Sorting API. */ void qsort (int (*cmp)(const void*, const void*)) { as_array ().qsort (cmp); } void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1) { as_array ().qsort (start, end); } + /* Unsorted search API. */ template <typename T> Type *lsearch (const T &x, Type *not_found = nullptr) { return as_array ().lsearch (x, not_found); } @@ -306,47 +382,25 @@ struct hb_vector_t template <typename T> bool lfind (const T &x, unsigned *pos = nullptr) const { return as_array ().lfind (x, pos); } -}; -template <typename Type> -struct hb_sorted_vector_t : hb_vector_t<Type> -{ - hb_sorted_vector_t () = default; - ~hb_sorted_vector_t () = default; - hb_sorted_vector_t (hb_sorted_vector_t& o) = default; - hb_sorted_vector_t (hb_sorted_vector_t &&o) = default; - hb_sorted_vector_t (std::initializer_list<Type> lst) : hb_vector_t<Type> (lst) {} - template <typename Iterable, - hb_requires (hb_is_iterable (Iterable))> - hb_sorted_vector_t (const Iterable &o) : hb_vector_t<Type> (o) {} - hb_sorted_vector_t& operator = (const hb_sorted_vector_t &o) = default; - hb_sorted_vector_t& operator = (hb_sorted_vector_t &&o) = default; - friend void swap (hb_sorted_vector_t& a, hb_sorted_vector_t& b) - { hb_swap ((hb_vector_t<Type>&) (a), (hb_vector_t<Type>&) (b)); } - - hb_sorted_array_t< Type> as_array () { return hb_sorted_array (this->arrayZ, this->length); } - hb_sorted_array_t<const Type> as_array () const { return hb_sorted_array (this->arrayZ, this->length); } - - /* Iterator. */ - typedef hb_sorted_array_t<const Type> const_iter_t; - typedef hb_sorted_array_t< Type> iter_t; - const_iter_t iter () const { return as_array (); } - const_iter_t citer () const { return as_array (); } - iter_t iter () { return as_array (); } - operator iter_t () { return iter (); } - operator const_iter_t () const { return iter (); } - - template <typename T> + /* Sorted search API. */ + template <typename T, + bool Sorted=sorted, hb_enable_if (Sorted)> Type *bsearch (const T &x, Type *not_found = nullptr) { return as_array ().bsearch (x, not_found); } - template <typename T> + template <typename T, + bool Sorted=sorted, hb_enable_if (Sorted)> const Type *bsearch (const T &x, const Type *not_found = nullptr) const { return as_array ().bsearch (x, not_found); } - template <typename T> + template <typename T, + bool Sorted=sorted, hb_enable_if (Sorted)> bool bfind (const T &x, unsigned int *i = nullptr, hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE, unsigned int to_store = (unsigned int) -1) const { return as_array ().bfind (x, i, not_found, to_store); } }; +template <typename Type> +using hb_sorted_vector_t = hb_vector_t<Type, true>; + #endif /* HB_VECTOR_HH */ diff --git a/thirdparty/harfbuzz/src/hb-version.h b/thirdparty/harfbuzz/src/hb-version.h index 1a4f0bf62a..dd2c5288cc 100644 --- a/thirdparty/harfbuzz/src/hb-version.h +++ b/thirdparty/harfbuzz/src/hb-version.h @@ -41,26 +41,26 @@ HB_BEGIN_DECLS * * The major component of the library version available at compile-time. */ -#define HB_VERSION_MAJOR 3 +#define HB_VERSION_MAJOR 4 /** * HB_VERSION_MINOR: * * The minor component of the library version available at compile-time. */ -#define HB_VERSION_MINOR 1 +#define HB_VERSION_MINOR 0 /** * HB_VERSION_MICRO: * * The micro component of the library version available at compile-time. */ -#define HB_VERSION_MICRO 1 +#define HB_VERSION_MICRO 0 /** * HB_VERSION_STRING: * * A string literal containing the library version available at compile-time. */ -#define HB_VERSION_STRING "3.1.1" +#define HB_VERSION_STRING "4.0.0" /** * HB_VERSION_ATLEAST: diff --git a/thirdparty/harfbuzz/src/hb.hh b/thirdparty/harfbuzz/src/hb.hh index 1f14267525..b9f5f71415 100644 --- a/thirdparty/harfbuzz/src/hb.hh +++ b/thirdparty/harfbuzz/src/hb.hh @@ -447,6 +447,7 @@ static int HB_UNUSED _hb_errno = 0; #ifndef HB_USE_ATEXIT # define HB_USE_ATEXIT 0 #endif +#ifndef hb_atexit #if !HB_USE_ATEXIT # define hb_atexit(_) HB_STMT_START { if (0) (_) (); } HB_STMT_END #else /* HB_USE_ATEXIT */ @@ -457,6 +458,7 @@ static int HB_UNUSED _hb_errno = 0; # define hb_atexit(f) static hb_atexit_t<f> _hb_atexit_##__LINE__; # endif #endif +#endif /* Lets assert int types. Saves trouble down the road. */ static_assert ((sizeof (hb_codepoint_t) == 4), ""); |