forked from mirrors/gecko-dev
Bug 1888698 - Update harfbuzz to 8.4.0 r=jfkthame
Differential Revision: https://phabricator.services.mozilla.com/D206139
This commit is contained in:
parent
37d28f9cf5
commit
af7a80a012
15 changed files with 181 additions and 52 deletions
|
|
@ -1,3 +1,16 @@
|
|||
Overview of changes leading to 8.4.0
|
||||
Saturday, March 29, 2024
|
||||
====================================
|
||||
- Add /bigobj to MSVC compiler flags in meson build, to fix building hb-subset.cc
|
||||
- Specify minimum versions of various dependencies in meson and autotools build.
|
||||
- When subsetting, place variation store at the end of “GDEF” table to fix
|
||||
shaping issues with some versions of Adobe InDesign.
|
||||
- Various build fixes.
|
||||
|
||||
- New API:
|
||||
+hb_buffer_set_random_state()
|
||||
+hb_buffer_get_random_state()
|
||||
|
||||
Overview of changes leading to 8.3.1
|
||||
Saturday, March 16, 2024
|
||||
====================================
|
||||
|
|
|
|||
|
|
@ -72,9 +72,9 @@ For a comparison of old vs new HarfBuzz memory consumption see [this][10].
|
|||
|
||||
## Name
|
||||
|
||||
HarfBuzz (حرفباز) is my Persian translation of “[OpenType][1]”,
|
||||
transliterated using the Latin script. It sports a second meaning, but that
|
||||
ain’t translatable.
|
||||
HarfBuzz (حرفباز) is the literal Persian translation of “[OpenType][1]”,
|
||||
transliterated using the Latin script. It also means "talkative" or
|
||||
"glib" (also a nod to the GNOME project where HarfBuzz originates from).
|
||||
|
||||
> Background: Originally there was this font format called TrueType. People and
|
||||
> companies started calling their type engines all things ending in Type:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
AC_PREREQ([2.64])
|
||||
AC_INIT([HarfBuzz],
|
||||
[8.3.1],
|
||||
[8.4.0],
|
||||
[https://github.com/harfbuzz/harfbuzz/issues/new],
|
||||
[harfbuzz],
|
||||
[http://harfbuzz.org/])
|
||||
|
|
@ -132,7 +132,7 @@ AC_ARG_WITH(glib,
|
|||
[Use glib @<:@default=auto@:>@])],,
|
||||
[with_glib=auto])
|
||||
have_glib=false
|
||||
GLIB_DEPS="glib-2.0 >= 2.19.1"
|
||||
GLIB_DEPS="glib-2.0 >= 2.30"
|
||||
AC_SUBST(GLIB_DEPS)
|
||||
if test "x$with_glib" = "xyes" -o "x$with_glib" = "xauto"; then
|
||||
PKG_CHECK_MODULES(GLIB, $GLIB_DEPS, have_glib=true, :)
|
||||
|
|
@ -193,7 +193,7 @@ AC_ARG_WITH(cairo,
|
|||
[with_cairo=auto])
|
||||
have_cairo=false
|
||||
if test "x$with_cairo" = "xyes" -o "x$with_cairo" = "xauto"; then
|
||||
PKG_CHECK_MODULES(CAIRO, cairo >= 1.8.0, have_cairo=true, :)
|
||||
PKG_CHECK_MODULES(CAIRO, cairo >= 1.10, have_cairo=true, :)
|
||||
save_libs=$LIBS
|
||||
LIBS="$LIBS $CAIRO_LIBS"
|
||||
AC_CHECK_FUNCS(cairo_user_font_face_set_render_color_glyph_func)
|
||||
|
|
@ -242,7 +242,7 @@ AC_ARG_WITH(icu,
|
|||
[with_icu=auto])
|
||||
have_icu=false
|
||||
if test "x$with_icu" = "xyes" -o "x$with_icu" = "xbuiltin" -o "x$with_icu" = "xauto"; then
|
||||
PKG_CHECK_MODULES(ICU, icu-uc, have_icu=true, :)
|
||||
PKG_CHECK_MODULES(ICU, icu-uc >= 49.0, have_icu=true, :)
|
||||
fi
|
||||
if test \( "x$with_icu" = "xyes" -o "x$with_icu" = "xbuiltin" \) -a "x$have_icu" != "xtrue"; then
|
||||
AC_MSG_ERROR([icu support requested but icu-uc not found])
|
||||
|
|
|
|||
|
|
@ -20,11 +20,11 @@ origin:
|
|||
|
||||
# Human-readable identifier for this version/release
|
||||
# Generally "version NNN", "tag SSS", "bookmark SSS"
|
||||
release: 8.3.1 (2024-03-17T07:50:59+02:00).
|
||||
release: 8.4.0 (2024-03-29T16:32:00+02:00).
|
||||
|
||||
# Revision to pull in
|
||||
# Must be a long or short commit SHA (long preferred)
|
||||
revision: 8.3.1
|
||||
revision: 8.4.0
|
||||
|
||||
# The package's license, where possible using the mnemonic from
|
||||
# https://spdx.org/licenses/
|
||||
|
|
|
|||
|
|
@ -663,21 +663,16 @@ struct GDEFVersion1_2
|
|||
auto *out = c->serializer->start_embed (*this);
|
||||
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
|
||||
|
||||
out->version.major = version.major;
|
||||
out->version.minor = version.minor;
|
||||
bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
|
||||
bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
|
||||
bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
|
||||
|
||||
bool subset_markglyphsetsdef = false;
|
||||
// Push var store first (if it's needed) so that it's last in the
|
||||
// serialization order. Some font consumers assume that varstore runs to
|
||||
// the end of the GDEF table.
|
||||
// See: https://github.com/harfbuzz/harfbuzz/issues/4636
|
||||
auto snapshot_version0 = c->serializer->snapshot ();
|
||||
if (version.to_int () >= 0x00010002u)
|
||||
{
|
||||
if (unlikely (!c->serializer->embed (markGlyphSetsDef))) return_trace (false);
|
||||
subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
|
||||
}
|
||||
if (unlikely (version.to_int () >= 0x00010002u && !c->serializer->embed (markGlyphSetsDef)))
|
||||
return_trace (false);
|
||||
|
||||
bool subset_varstore = false;
|
||||
unsigned varstore_index = (unsigned) -1;
|
||||
auto snapshot_version2 = c->serializer->snapshot ();
|
||||
if (version.to_int () >= 0x00010003u)
|
||||
{
|
||||
|
|
@ -690,35 +685,58 @@ struct GDEFVersion1_2
|
|||
{
|
||||
item_variations_t item_vars;
|
||||
if (item_vars.instantiate (this+varStore, c->plan, true, true,
|
||||
c->plan->gdef_varstore_inner_maps.as_array ()))
|
||||
c->plan->gdef_varstore_inner_maps.as_array ())) {
|
||||
subset_varstore = out->varStore.serialize_serialize (c->serializer,
|
||||
item_vars.has_long_word (),
|
||||
c->plan->axis_tags,
|
||||
item_vars.get_region_list (),
|
||||
item_vars.get_vardata_encodings ());
|
||||
varstore_index = c->serializer->last_added_child_index();
|
||||
}
|
||||
remap_varidx_after_instantiation (item_vars.get_varidx_map (),
|
||||
c->plan->layout_variation_idx_delta_map);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ());
|
||||
varstore_index = c->serializer->last_added_child_index();
|
||||
}
|
||||
}
|
||||
|
||||
out->version.major = version.major;
|
||||
out->version.minor = version.minor;
|
||||
|
||||
if (!subset_varstore && version.to_int () >= 0x00010002u) {
|
||||
c->serializer->revert (snapshot_version2);
|
||||
}
|
||||
|
||||
bool subset_markglyphsetsdef = false;
|
||||
if (version.to_int () >= 0x00010002u)
|
||||
{
|
||||
subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
|
||||
}
|
||||
|
||||
if (subset_varstore)
|
||||
{
|
||||
out->version.minor = 3;
|
||||
c->plan->has_gdef_varstore = true;
|
||||
} else if (subset_markglyphsetsdef) {
|
||||
out->version.minor = 2;
|
||||
c->serializer->revert (snapshot_version2);
|
||||
out->version.minor = 2;
|
||||
} else {
|
||||
out->version.minor = 0;
|
||||
c->serializer->revert (snapshot_version0);
|
||||
}
|
||||
|
||||
bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
|
||||
bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
|
||||
bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
|
||||
bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
|
||||
|
||||
if (subset_varstore && varstore_index != (unsigned) -1) {
|
||||
c->serializer->repack_last(varstore_index);
|
||||
}
|
||||
|
||||
return_trace (subset_glyphclassdef || subset_attachlist ||
|
||||
subset_ligcaretlist || subset_markattachclassdef ||
|
||||
(out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) ||
|
||||
|
|
@ -1013,7 +1031,7 @@ struct GDEF
|
|||
if (!has_var_store ()) return;
|
||||
const ItemVariationStore &var_store = get_var_store ();
|
||||
float *store_cache = var_store.create_cache ();
|
||||
|
||||
|
||||
unsigned new_major = 0, new_minor = 0;
|
||||
unsigned last_major = (layout_variation_indices->get_min ()) >> 16;
|
||||
for (unsigned idx : layout_variation_indices->iter ())
|
||||
|
|
|
|||
|
|
@ -309,6 +309,7 @@ hb_buffer_t::clear ()
|
|||
|
||||
deallocate_var_all ();
|
||||
serial = 0;
|
||||
random_state = 1;
|
||||
scratch_flags = HB_BUFFER_SCRATCH_FLAG_DEFAULT;
|
||||
}
|
||||
|
||||
|
|
@ -1359,6 +1360,49 @@ hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer)
|
|||
return buffer->not_found;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_buffer_set_random_state:
|
||||
* @buffer: An #hb_buffer_t
|
||||
* @state: the new random state
|
||||
*
|
||||
* Sets the random state of the buffer. The state changes
|
||||
* every time a glyph uses randomness (eg. the `rand`
|
||||
* OpenType feature). This function together with
|
||||
* hb_buffer_get_random_state() allow for transferring
|
||||
* the current random state to a subsequent buffer, to
|
||||
* get better randomness distribution.
|
||||
*
|
||||
* Defaults to 1 and when buffer contents are cleared.
|
||||
* A value of 0 disables randomness during shaping.
|
||||
*
|
||||
* Since: 8.4.0
|
||||
**/
|
||||
void
|
||||
hb_buffer_set_random_state (hb_buffer_t *buffer,
|
||||
unsigned state)
|
||||
{
|
||||
if (unlikely (hb_object_is_immutable (buffer)))
|
||||
return;
|
||||
|
||||
buffer->random_state = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_buffer_get_random_state:
|
||||
* @buffer: An #hb_buffer_t
|
||||
*
|
||||
* See hb_buffer_set_random_state().
|
||||
*
|
||||
* Return value:
|
||||
* The @buffer random state
|
||||
*
|
||||
* Since: 8.4.0
|
||||
**/
|
||||
unsigned
|
||||
hb_buffer_get_random_state (const hb_buffer_t *buffer)
|
||||
{
|
||||
return buffer->random_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_buffer_clear_contents:
|
||||
|
|
|
|||
|
|
@ -487,6 +487,12 @@ hb_buffer_set_not_found_glyph (hb_buffer_t *buffer,
|
|||
HB_EXTERN hb_codepoint_t
|
||||
hb_buffer_get_not_found_glyph (const hb_buffer_t *buffer);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_buffer_set_random_state (hb_buffer_t *buffer,
|
||||
unsigned state);
|
||||
|
||||
HB_EXTERN unsigned
|
||||
hb_buffer_get_random_state (const hb_buffer_t *buffer);
|
||||
|
||||
/*
|
||||
* Content API.
|
||||
|
|
|
|||
|
|
@ -116,6 +116,7 @@ struct hb_buffer_t
|
|||
|
||||
uint8_t allocated_var_bits;
|
||||
uint8_t serial;
|
||||
uint32_t random_state;
|
||||
hb_buffer_scratch_flags_t scratch_flags; /* Have space-fallback, etc. */
|
||||
unsigned int max_len; /* Maximum allowed len. */
|
||||
int max_ops; /* Maximum allowed operations. */
|
||||
|
|
|
|||
|
|
@ -49,8 +49,8 @@
|
|||
|
||||
#if defined (_AIX)
|
||||
# include <sys/inttypes.h>
|
||||
#elif defined (_MSC_VER) && _MSC_VER < 1800
|
||||
/* VS 2013 (_MSC_VER 1800) has inttypes.h */
|
||||
#elif defined (_MSC_VER) && _MSC_VER < 1600
|
||||
/* VS 2010 (_MSC_VER 1600) has stdint.h */
|
||||
typedef __int8 int8_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef __int16 int16_t;
|
||||
|
|
@ -59,6 +59,9 @@ typedef __int32 int32_t;
|
|||
typedef unsigned __int32 uint32_t;
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#elif defined (_MSC_VER) && _MSC_VER < 1800
|
||||
/* VS 2013 (_MSC_VER 1800) has inttypes.h */
|
||||
# include <stdint.h>
|
||||
#else
|
||||
# include <inttypes.h>
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -723,7 +723,6 @@ struct hb_ot_apply_context_t :
|
|||
bool auto_zwj = true;
|
||||
bool per_syllable = false;
|
||||
bool random = false;
|
||||
uint32_t random_state = 1;
|
||||
unsigned new_syllables = (unsigned) -1;
|
||||
|
||||
signed last_base = -1; // GPOS uses
|
||||
|
|
@ -788,8 +787,8 @@ struct hb_ot_apply_context_t :
|
|||
uint32_t random_number ()
|
||||
{
|
||||
/* http://www.cplusplus.com/reference/random/minstd_rand/ */
|
||||
random_state = random_state * 48271 % 2147483647;
|
||||
return random_state;
|
||||
buffer->random_state = buffer->random_state * 48271 % 2147483647;
|
||||
return buffer->random_state;
|
||||
}
|
||||
|
||||
bool match_properties_mark (hb_codepoint_t glyph,
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ struct OS2
|
|||
}
|
||||
}
|
||||
|
||||
return num ? (unsigned) roundf (total_width / num) : 0;
|
||||
return num ? (unsigned) roundf ((double) total_width / (double) num) : 0;
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
|
|
@ -284,12 +284,12 @@ struct OS2
|
|||
os2_prime->usWidthClass = width_class;
|
||||
}
|
||||
|
||||
if (c->plan->flags & HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES)
|
||||
return_trace (true);
|
||||
|
||||
os2_prime->usFirstCharIndex = hb_min (0xFFFFu, c->plan->unicodes.get_min ());
|
||||
os2_prime->usLastCharIndex = hb_min (0xFFFFu, c->plan->unicodes.get_max ());
|
||||
|
||||
if (c->plan->flags & HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES)
|
||||
return_trace (true);
|
||||
|
||||
_update_unicode_ranges (&c->plan->unicodes, os2_prime->ulUnicodeRange);
|
||||
|
||||
return_trace (true);
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
|
|||
#endif
|
||||
bool has_gpos = !disable_gpos && hb_ot_layout_has_positioning (face);
|
||||
if (false)
|
||||
;
|
||||
{}
|
||||
#ifndef HB_NO_AAT_SHAPE
|
||||
/* Prefer GPOS over kerx if GSUB is present;
|
||||
* https://github.com/harfbuzz/harfbuzz/issues/3008 */
|
||||
|
|
@ -167,15 +167,16 @@ hb_ot_shape_planner_t::compile (hb_ot_shape_plan_t &plan,
|
|||
|
||||
if (!plan.apply_kerx && (!has_gpos_kern || !plan.apply_gpos))
|
||||
{
|
||||
if (false) {}
|
||||
#ifndef HB_NO_AAT_SHAPE
|
||||
if (has_kerx)
|
||||
else if (has_kerx)
|
||||
plan.apply_kerx = true;
|
||||
else
|
||||
#endif
|
||||
#ifndef HB_NO_OT_KERN
|
||||
if (hb_ot_layout_has_kerning (face))
|
||||
else if (hb_ot_layout_has_kerning (face))
|
||||
plan.apply_kern = true;
|
||||
#endif
|
||||
else {}
|
||||
}
|
||||
|
||||
plan.apply_fallback_kern = !(plan.apply_gpos || plan.apply_kerx || plan.apply_kern);
|
||||
|
|
|
|||
|
|
@ -91,6 +91,26 @@ struct hb_serialize_context_t
|
|||
}
|
||||
#endif
|
||||
|
||||
bool add_virtual_link (objidx_t objidx)
|
||||
{
|
||||
if (!objidx)
|
||||
return false;
|
||||
|
||||
auto& link = *virtual_links.push ();
|
||||
if (virtual_links.in_error ())
|
||||
return false;
|
||||
|
||||
link.objidx = objidx;
|
||||
// Remaining fields were previously zero'd by push():
|
||||
// link.width = 0;
|
||||
// link.is_signed = 0;
|
||||
// link.whence = 0;
|
||||
// link.position = 0;
|
||||
// link.bias = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
friend void swap (object_t& a, object_t& b) noexcept
|
||||
{
|
||||
hb_swap (a.head, b.head);
|
||||
|
|
@ -469,16 +489,40 @@ struct hb_serialize_context_t
|
|||
|
||||
assert (current);
|
||||
|
||||
auto& link = *current->virtual_links.push ();
|
||||
if (current->virtual_links.in_error ())
|
||||
if (!current->add_virtual_link(objidx))
|
||||
err (HB_SERIALIZE_ERROR_OTHER);
|
||||
}
|
||||
|
||||
link.width = 0;
|
||||
link.objidx = objidx;
|
||||
link.is_signed = 0;
|
||||
link.whence = 0;
|
||||
link.position = 0;
|
||||
link.bias = 0;
|
||||
objidx_t last_added_child_index() const {
|
||||
if (unlikely (in_error ())) return (objidx_t) -1;
|
||||
|
||||
assert (current);
|
||||
if (!bool(current->real_links)) {
|
||||
return (objidx_t) -1;
|
||||
}
|
||||
|
||||
return current->real_links[current->real_links.length - 1].objidx;
|
||||
}
|
||||
|
||||
// For the current object ensure that the sub-table bytes for child objidx are always placed
|
||||
// after the subtable bytes for any other existing children. This only ensures that the
|
||||
// repacker will not move the target subtable before the other children
|
||||
// (by adding virtual links). It is up to the caller to ensure the initial serialization
|
||||
// order is correct.
|
||||
void repack_last(objidx_t objidx) {
|
||||
if (unlikely (in_error ())) return;
|
||||
|
||||
if (!objidx)
|
||||
return;
|
||||
|
||||
assert (current);
|
||||
for (auto& l : current->real_links) {
|
||||
if (l.objidx == objidx) {
|
||||
continue;
|
||||
}
|
||||
|
||||
packed[l.objidx]->add_virtual_link(objidx);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
|
|
|||
|
|
@ -47,20 +47,20 @@ HB_BEGIN_DECLS
|
|||
*
|
||||
* The minor component of the library version available at compile-time.
|
||||
*/
|
||||
#define HB_VERSION_MINOR 3
|
||||
#define HB_VERSION_MINOR 4
|
||||
/**
|
||||
* 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 "8.3.1"
|
||||
#define HB_VERSION_STRING "8.4.0"
|
||||
|
||||
/**
|
||||
* HB_VERSION_ATLEAST:
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ acquire_shape_plan (hb_face_t *face,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
func = wasm_runtime_lookup_function (module_inst, "shape_plan_create", nullptr);
|
||||
func = wasm_runtime_lookup_function (module_inst, "shape_plan_create");
|
||||
if (func)
|
||||
{
|
||||
wasm_val_t results[1];
|
||||
|
|
@ -297,7 +297,7 @@ release_shape_plan (const hb_wasm_face_data_t *face_data,
|
|||
if (plan->wasm_shape_planptr)
|
||||
{
|
||||
|
||||
auto *func = wasm_runtime_lookup_function (module_inst, "shape_plan_destroy", nullptr);
|
||||
auto *func = wasm_runtime_lookup_function (module_inst, "shape_plan_destroy");
|
||||
if (func)
|
||||
{
|
||||
wasm_val_t arguments[1];
|
||||
|
|
@ -395,7 +395,7 @@ retry:
|
|||
goto fail;
|
||||
}
|
||||
|
||||
func = wasm_runtime_lookup_function (module_inst, "shape", nullptr);
|
||||
func = wasm_runtime_lookup_function (module_inst, "shape");
|
||||
if (unlikely (!func))
|
||||
{
|
||||
DEBUG_MSG (WASM, module_inst, "Shape function not found.");
|
||||
|
|
|
|||
Loading…
Reference in a new issue