зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1859681 - Update harfbuzz to 8.2.2 r=jfkthame
Differential Revision: https://phabricator.services.mozilla.com/D191257
This commit is contained in:
Родитель
8ed1af5cf8
Коммит
ef9968daf9
|
@ -1,3 +1,14 @@
|
|||
Overview of changes leading to 8.2.2
|
||||
Wednesday, October 18, 2023
|
||||
“From the river to the sea, Palestine will be free”
|
||||
====================================
|
||||
- Fix regression from 8.1.0 in shaping fonts with duplicate feature tags.
|
||||
- Fix regression from 8.2.0 in parsing CSS-style feature strings.
|
||||
- Variable fonts instanciation now handles more tables.
|
||||
- Various CMake build improvements.
|
||||
- various fixes to build without errors with gcc 4.9.2.
|
||||
|
||||
|
||||
Overview of changes leading to 8.2.1
|
||||
Monday, September 18, 2023
|
||||
====================================
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
AC_PREREQ([2.64])
|
||||
AC_INIT([HarfBuzz],
|
||||
[8.2.1],
|
||||
[8.2.2],
|
||||
[https://github.com/harfbuzz/harfbuzz/issues/new],
|
||||
[harfbuzz],
|
||||
[http://harfbuzz.org/])
|
||||
|
|
|
@ -20,11 +20,11 @@ origin:
|
|||
|
||||
# Human-readable identifier for this version/release
|
||||
# Generally "version NNN", "tag SSS", "bookmark SSS"
|
||||
release: 8.2.1 (2023-09-18T21:18:49+03:00).
|
||||
release: 8.2.2 (2023-10-18T01:18:14+03:00).
|
||||
|
||||
# Revision to pull in
|
||||
# Must be a long or short commit SHA (long preferred)
|
||||
revision: 8.2.1
|
||||
revision: 8.2.2
|
||||
|
||||
# The package's license, where possible using the mnemonic from
|
||||
# https://spdx.org/licenses/
|
||||
|
|
|
@ -14,7 +14,7 @@ check_PROGRAMS =
|
|||
|
||||
EXTRA_DIST += harfbuzz.cc harfbuzz-subset.cc
|
||||
EXTRA_DIST += meson.build
|
||||
EXTRA_DIST += fix_get_types.py
|
||||
EXTRA_DIST += fix_get_types.py relative_to.py
|
||||
|
||||
# Convenience targets:
|
||||
lib: $(BUILT_SOURCES) libharfbuzz.la
|
||||
|
@ -458,6 +458,7 @@ COMPILED_TESTS = \
|
|||
test-classdef-graph \
|
||||
test-instancer-solver \
|
||||
test-tuple-varstore \
|
||||
test-item-varstore \
|
||||
$(NULL)
|
||||
COMPILED_TESTS_CPPFLAGS = $(HBCFLAGS) -DMAIN -UNDEBUG
|
||||
COMPILED_TESTS_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
@ -536,6 +537,10 @@ test_tuple_varstore_SOURCES = test-tuple-varstore.cc hb-subset-instancer-solver.
|
|||
test_tuple_varstore_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
|
||||
test_tuple_varstore_LDADD = $(COMPILED_TESTS_LDADD)
|
||||
|
||||
test_item_varstore_SOURCES = test-item-varstore.cc hb-subset-instancer-solver.cc hb-static.cc
|
||||
test_item_varstore_CPPFLAGS = $(COMPILED_TESTS_CPPFLAGS)
|
||||
test_item_varstore_LDADD = $(COMPILED_TESTS_LDADD)
|
||||
|
||||
dist_check_SCRIPTS = \
|
||||
check-c-linkage-decls.py \
|
||||
check-externs.py \
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
#ifndef OT_LAYOUT_GDEF_GDEF_HH
|
||||
#define OT_LAYOUT_GDEF_GDEF_HH
|
||||
|
||||
#include "../../../hb-ot-layout-common.hh"
|
||||
#include "../../../hb-ot-var-common.hh"
|
||||
|
||||
#include "../../../hb-font.hh"
|
||||
#include "../../../hb-cache.hh"
|
||||
|
@ -204,17 +204,19 @@ struct CaretValueFormat3
|
|||
if (!c->serializer->embed (coordinate)) return_trace (false);
|
||||
|
||||
unsigned varidx = (this+deviceTable).get_variation_index ();
|
||||
if (c->plan->layout_variation_idx_delta_map.has (varidx))
|
||||
hb_pair_t<unsigned, int> *new_varidx_delta;
|
||||
if (!c->plan->layout_variation_idx_delta_map.has (varidx, &new_varidx_delta))
|
||||
return_trace (false);
|
||||
|
||||
uint32_t new_varidx = hb_first (*new_varidx_delta);
|
||||
int delta = hb_second (*new_varidx_delta);
|
||||
if (delta != 0)
|
||||
{
|
||||
int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (varidx));
|
||||
if (delta != 0)
|
||||
{
|
||||
if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW))
|
||||
return_trace (false);
|
||||
}
|
||||
if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW))
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
if (c->plan->all_axes_pinned)
|
||||
if (new_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
|
||||
return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
|
||||
|
||||
if (!c->serializer->embed (deviceTable))
|
||||
|
@ -602,6 +604,26 @@ struct GDEFVersion1_2
|
|||
(version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
|
||||
}
|
||||
|
||||
static void remap_varidx_after_instantiation (const hb_map_t& varidx_map,
|
||||
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>>& layout_variation_idx_delta_map /* IN/OUT */)
|
||||
{
|
||||
/* varidx_map is empty which means varstore is empty after instantiation,
|
||||
* no variations, map all varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX.
|
||||
* varidx_map doesn't have original varidx, indicating delta row is all
|
||||
* zeros, map varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX */
|
||||
for (auto _ : layout_variation_idx_delta_map.iter_ref ())
|
||||
{
|
||||
/* old_varidx->(varidx, delta) mapping generated for subsetting, then this
|
||||
* varidx is used as key of varidx_map during instantiation */
|
||||
uint32_t varidx = _.second.first;
|
||||
uint32_t *new_varidx;
|
||||
if (varidx_map.has (varidx, &new_varidx))
|
||||
_.second.first = *new_varidx;
|
||||
else
|
||||
_.second.first = HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
|
||||
}
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
|
@ -624,6 +646,22 @@ struct GDEFVersion1_2
|
|||
{
|
||||
if (c->plan->all_axes_pinned)
|
||||
out->varStore = 0;
|
||||
else if (c->plan->normalized_coords)
|
||||
{
|
||||
if (varStore)
|
||||
{
|
||||
item_variations_t item_vars;
|
||||
if (item_vars.instantiate (this+varStore, c->plan, true, true,
|
||||
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 ());
|
||||
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 ());
|
||||
}
|
||||
|
@ -922,17 +960,32 @@ struct GDEF
|
|||
{ get_lig_caret_list ().collect_variation_indices (c); }
|
||||
|
||||
void remap_layout_variation_indices (const hb_set_t *layout_variation_indices,
|
||||
const hb_vector_t<int>& normalized_coords,
|
||||
bool calculate_delta, /* not pinned at default */
|
||||
bool no_variations, /* all axes pinned */
|
||||
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map /* OUT */) const
|
||||
{
|
||||
if (!has_var_store ()) return;
|
||||
if (layout_variation_indices->is_empty ()) return;
|
||||
|
||||
const VariationStore &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 ())
|
||||
{
|
||||
int delta = 0;
|
||||
if (calculate_delta)
|
||||
delta = roundf (var_store.get_delta (idx, normalized_coords.arrayZ,
|
||||
normalized_coords.length, store_cache));
|
||||
|
||||
if (no_variations)
|
||||
{
|
||||
layout_variation_idx_delta_map->set (idx, hb_pair_t<unsigned, int> (HB_OT_LAYOUT_NO_VARIATIONS_INDEX, delta));
|
||||
continue;
|
||||
}
|
||||
|
||||
uint16_t major = idx >> 16;
|
||||
if (major >= get_var_store ().get_sub_table_count ()) break;
|
||||
if (major >= var_store.get_sub_table_count ()) break;
|
||||
if (major != last_major)
|
||||
{
|
||||
new_minor = 0;
|
||||
|
@ -940,14 +993,11 @@ struct GDEF
|
|||
}
|
||||
|
||||
unsigned new_idx = (new_major << 16) + new_minor;
|
||||
if (!layout_variation_idx_delta_map->has (idx))
|
||||
continue;
|
||||
int delta = hb_second (layout_variation_idx_delta_map->get (idx));
|
||||
|
||||
layout_variation_idx_delta_map->set (idx, hb_pair_t<unsigned, int> (new_idx, delta));
|
||||
++new_minor;
|
||||
last_major = major;
|
||||
}
|
||||
var_store.destroy_cache (store_cache);
|
||||
}
|
||||
|
||||
protected:
|
||||
|
|
|
@ -52,9 +52,14 @@ struct AnchorFormat3
|
|||
if (unlikely (!c->serializer->embed (yCoordinate))) return_trace (false);
|
||||
|
||||
unsigned x_varidx = xDeviceTable ? (this+xDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
|
||||
if (c->plan->layout_variation_idx_delta_map.has (x_varidx))
|
||||
if (x_varidx != HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
|
||||
{
|
||||
int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (x_varidx));
|
||||
hb_pair_t<unsigned, int> *new_varidx_delta;
|
||||
if (!c->plan->layout_variation_idx_delta_map.has (x_varidx, &new_varidx_delta))
|
||||
return_trace (false);
|
||||
|
||||
x_varidx = hb_first (*new_varidx_delta);
|
||||
int delta = hb_second (*new_varidx_delta);
|
||||
if (delta != 0)
|
||||
{
|
||||
if (!c->serializer->check_assign (out->xCoordinate, xCoordinate + delta,
|
||||
|
@ -64,9 +69,14 @@ struct AnchorFormat3
|
|||
}
|
||||
|
||||
unsigned y_varidx = yDeviceTable ? (this+yDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
|
||||
if (c->plan->layout_variation_idx_delta_map.has (y_varidx))
|
||||
if (y_varidx != HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
|
||||
{
|
||||
int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (y_varidx));
|
||||
hb_pair_t<unsigned, int> *new_varidx_delta;
|
||||
if (!c->plan->layout_variation_idx_delta_map.has (y_varidx, &new_varidx_delta))
|
||||
return_trace (false);
|
||||
|
||||
y_varidx = hb_first (*new_varidx_delta);
|
||||
int delta = hb_second (*new_varidx_delta);
|
||||
if (delta != 0)
|
||||
{
|
||||
if (!c->serializer->check_assign (out->yCoordinate, yCoordinate + delta,
|
||||
|
@ -75,7 +85,10 @@ struct AnchorFormat3
|
|||
}
|
||||
}
|
||||
|
||||
if (c->plan->all_axes_pinned)
|
||||
/* in case that all axes are pinned or no variations after instantiation,
|
||||
* both var_idxes will be mapped to HB_OT_LAYOUT_NO_VARIATIONS_INDEX */
|
||||
if (x_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX &&
|
||||
y_varidx == HB_OT_LAYOUT_NO_VARIATIONS_INDEX)
|
||||
return_trace (c->serializer->check_assign (out->format, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
|
||||
|
||||
if (!c->serializer->embed (xDeviceTable)) return_trace (false);
|
||||
|
|
|
@ -169,7 +169,7 @@ struct MarkLigPosFormat1_2
|
|||
{
|
||||
TRACE_SUBSET (this);
|
||||
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
|
||||
const hb_map_t &glyph_map = *c->plan->glyph_map;
|
||||
const hb_map_t &glyph_map = c->plan->glyph_map_gsub;
|
||||
|
||||
auto *out = c->serializer->start_embed (*this);
|
||||
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
|
||||
|
@ -202,8 +202,9 @@ struct MarkLigPosFormat1_2
|
|||
|
||||
auto new_ligature_coverage =
|
||||
+ hb_iter (this + ligatureCoverage)
|
||||
| hb_filter (glyphset)
|
||||
| hb_take ((this + ligatureArray).len)
|
||||
| hb_map_retains_sorting (glyph_map)
|
||||
| hb_filter ([] (hb_codepoint_t glyph) { return glyph != HB_MAP_VALUE_INVALID; })
|
||||
;
|
||||
|
||||
if (!out->ligatureCoverage.serialize_serialize (c->serializer, new_ligature_coverage))
|
||||
|
|
|
@ -566,7 +566,7 @@ struct graph_t
|
|||
|
||||
update_distances ();
|
||||
|
||||
hb_priority_queue_t queue;
|
||||
hb_priority_queue_t<int64_t> queue;
|
||||
hb_vector_t<vertex_t> &sorted_graph = vertices_scratch_;
|
||||
if (unlikely (!check_success (sorted_graph.resize (vertices_.length)))) return;
|
||||
hb_vector_t<unsigned> id_map;
|
||||
|
@ -1369,7 +1369,7 @@ struct graph_t
|
|||
vertices_.arrayZ[i].distance = hb_int_max (int64_t);
|
||||
vertices_.tail ().distance = 0;
|
||||
|
||||
hb_priority_queue_t queue;
|
||||
hb_priority_queue_t<int64_t> queue;
|
||||
queue.insert (0, vertices_.length - 1);
|
||||
|
||||
hb_vector_t<bool> visited;
|
||||
|
|
|
@ -217,7 +217,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
|
|||
|
||||
const unsigned base_coverage_id = c.graph.index_for_offset (this_index, &baseCoverage);
|
||||
const unsigned base_size =
|
||||
OT::Layout::GPOS_impl::PairPosFormat1_3<SmallTypes>::min_size +
|
||||
OT::Layout::GPOS_impl::MarkBasePosFormat1_2<SmallTypes>::min_size +
|
||||
MarkArray::min_size +
|
||||
AnchorMatrix::min_size +
|
||||
c.graph.vertices_[base_coverage_id].table_size ();
|
||||
|
@ -484,7 +484,7 @@ struct MarkBasePos : public OT::Layout::GPOS_impl::MarkBasePos
|
|||
return ((MarkBasePosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index);
|
||||
#ifndef HB_NO_BEYOND_64K
|
||||
case 2: HB_FALLTHROUGH;
|
||||
// Don't split 24bit PairPos's.
|
||||
// Don't split 24bit MarkBasePos's.
|
||||
#endif
|
||||
default:
|
||||
return hb_vector_t<unsigned> ();
|
||||
|
|
|
@ -1,69 +1,32 @@
|
|||
set(_harfbuzz_libdir "@libdir@")
|
||||
set(_harfbuzz_includedir "@includedir@")
|
||||
@PACKAGE_INIT@
|
||||
|
||||
# Extract version information from libtool.
|
||||
set(_harfbuzz_version_info "@HB_LIBTOOL_VERSION_INFO@")
|
||||
string(REPLACE ":" ";" _harfbuzz_version_info "${_harfbuzz_version_info}")
|
||||
list(GET _harfbuzz_version_info 0
|
||||
_harfbuzz_current)
|
||||
list(GET _harfbuzz_version_info 1
|
||||
_harfbuzz_revision)
|
||||
list(GET _harfbuzz_version_info 2
|
||||
_harfbuzz_age)
|
||||
unset(_harfbuzz_version_info)
|
||||
|
||||
if ("@default_library@" MATCHES "static")
|
||||
set(_harfbuzz_lib_prefix "lib")
|
||||
set(_harfbuzz_lib_suffix ".a")
|
||||
else ()
|
||||
if (APPLE)
|
||||
set(_harfbuzz_lib_prefix "${CMAKE_SHARED_LIBRARY_PREFIX}")
|
||||
set(_harfbuzz_lib_suffix ".0${CMAKE_SHARED_LIBRARY_SUFFIX}")
|
||||
elseif (UNIX)
|
||||
set(_harfbuzz_lib_prefix "${CMAKE_SHARED_LIBRARY_PREFIX}")
|
||||
set(_harfbuzz_lib_suffix "${CMAKE_SHARED_LIBRARY_SUFFIX}.0.${_harfbuzz_current}.${_harfbuzz_revision}")
|
||||
elseif (WIN32)
|
||||
set(_harfbuzz_lib_prefix "${CMAKE_IMPORT_LIBRARY_PREFIX}")
|
||||
set(_harfbuzz_lib_suffix "${CMAKE_IMPORT_LIBRARY_SUFFIX}")
|
||||
else ()
|
||||
# Unsupported.
|
||||
set(harfbuzz_FOUND 0)
|
||||
endif ()
|
||||
endif ()
|
||||
set_and_check(HARFBUZZ_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@")
|
||||
|
||||
# Add the libraries.
|
||||
add_library(harfbuzz::harfbuzz SHARED IMPORTED)
|
||||
add_library(harfbuzz::harfbuzz @HB_LIBRARY_TYPE@ IMPORTED)
|
||||
set_target_properties(harfbuzz::harfbuzz PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_includedir}/harfbuzz"
|
||||
IMPORTED_LOCATION "${_harfbuzz_libdir}/${_harfbuzz_lib_prefix}harfbuzz${_harfbuzz_lib_suffix}")
|
||||
INTERFACE_INCLUDE_DIRECTORIES "@PACKAGE_INCLUDE_INSTALL_DIR@"
|
||||
IMPORTED_LOCATION "@PACKAGE_CMAKE_INSTALL_LIBDIR@/@HB_LIB_PREFIX@harfbuzz@HB_LIB_SUFFIX@")
|
||||
|
||||
add_library(harfbuzz::icu SHARED IMPORTED)
|
||||
add_library(harfbuzz::icu @HB_LIBRARY_TYPE@ IMPORTED)
|
||||
set_target_properties(harfbuzz::icu PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_includedir}/harfbuzz"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "@PACKAGE_INCLUDE_INSTALL_DIR@"
|
||||
INTERFACE_LINK_LIBRARIES "harfbuzz::harfbuzz"
|
||||
IMPORTED_LOCATION "${_harfbuzz_libdir}/${_harfbuzz_lib_prefix}harfbuzz-icu${_harfbuzz_lib_suffix}")
|
||||
IMPORTED_LOCATION "@PACKAGE_CMAKE_INSTALL_LIBDIR@/@HB_LIB_PREFIX@harfbuzz-icu@HB_LIB_SUFFIX@")
|
||||
|
||||
add_library(harfbuzz::subset SHARED IMPORTED)
|
||||
add_library(harfbuzz::subset @HB_LIBRARY_TYPE@ IMPORTED)
|
||||
set_target_properties(harfbuzz::subset PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_includedir}/harfbuzz"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "@PACKAGE_INCLUDE_INSTALL_DIR@"
|
||||
INTERFACE_LINK_LIBRARIES "harfbuzz::harfbuzz"
|
||||
IMPORTED_LOCATION "${_harfbuzz_libdir}/${_harfbuzz_lib_prefix}harfbuzz-subset${_harfbuzz_lib_suffix}")
|
||||
IMPORTED_LOCATION "@PACKAGE_CMAKE_INSTALL_LIBDIR@/@HB_LIB_PREFIX@harfbuzz-subset@HB_LIB_SUFFIX@")
|
||||
|
||||
# Only add the gobject library if it was built.
|
||||
set(_harfbuzz_have_gobject "@have_gobject@")
|
||||
if (_harfbuzz_have_gobject)
|
||||
add_library(harfbuzz::gobject SHARED IMPORTED)
|
||||
if (@HB_HAVE_GOBJECT@)
|
||||
add_library(harfbuzz::gobject @HB_LIBRARY_TYPE@ IMPORTED)
|
||||
set_target_properties(harfbuzz::gobject PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_includedir}/harfbuzz"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "@PACKAGE_INCLUDE_INSTALL_DIR@"
|
||||
INTERFACE_LINK_LIBRARIES "harfbuzz::harfbuzz"
|
||||
IMPORTED_LOCATION "${_harfbuzz_libdir}/${_harfbuzz_lib_prefix}harfbuzz-gobject${_harfbuzz_lib_suffix}")
|
||||
IMPORTED_LOCATION "@PACKAGE_CMAKE_INSTALL_LIBDIR@/@HB_LIB_PREFIX@harfbuzz-gobject@HB_LIB_SUFFIX@")
|
||||
endif ()
|
||||
|
||||
# Clean out variables we used in our scope.
|
||||
unset(_harfbuzz_lib_prefix)
|
||||
unset(_harfbuzz_lib_suffix)
|
||||
unset(_harfbuzz_current)
|
||||
unset(_harfbuzz_revision)
|
||||
unset(_harfbuzz_age)
|
||||
unset(_harfbuzz_includedir)
|
||||
unset(_harfbuzz_libdir)
|
||||
check_required_components(harfbuzz)
|
||||
|
|
|
@ -815,7 +815,7 @@ parse_tag (const char **pp, const char *end, hb_tag_t *tag)
|
|||
}
|
||||
|
||||
const char *p = *pp;
|
||||
while (*pp < end && (**pp != ' ' && **pp != '=' && **pp != '['))
|
||||
while (*pp < end && (**pp != ' ' && **pp != '=' && **pp != '[' && **pp != quote))
|
||||
(*pp)++;
|
||||
|
||||
if (p == *pp || *pp - p > 4)
|
||||
|
|
|
@ -104,12 +104,12 @@ struct hb_hashmap_t
|
|||
hb_pair_t<const K &, V &> get_pair_ref() { return hb_pair_t<const K &, V &> (key, value); }
|
||||
|
||||
uint32_t total_hash () const
|
||||
{ return (hash * 31) + hb_hash (value); }
|
||||
{ return (hash * 31u) + hb_hash (value); }
|
||||
|
||||
static constexpr bool is_trivial = std::is_trivially_constructible<K>::value &&
|
||||
std::is_trivially_destructible<K>::value &&
|
||||
std::is_trivially_constructible<V>::value &&
|
||||
std::is_trivially_destructible<V>::value;
|
||||
static constexpr bool is_trivial = hb_is_trivially_constructible(K) &&
|
||||
hb_is_trivially_destructible(K) &&
|
||||
hb_is_trivially_constructible(V) &&
|
||||
hb_is_trivially_destructible(V);
|
||||
};
|
||||
|
||||
hb_object_header_t header;
|
||||
|
@ -398,37 +398,37 @@ struct hb_hashmap_t
|
|||
|
||||
auto iter_items () const HB_AUTO_RETURN
|
||||
(
|
||||
+ hb_iter (items, size ())
|
||||
+ hb_iter (items, this->size ())
|
||||
| hb_filter (&item_t::is_real)
|
||||
)
|
||||
auto iter_ref () const HB_AUTO_RETURN
|
||||
(
|
||||
+ iter_items ()
|
||||
+ this->iter_items ()
|
||||
| hb_map (&item_t::get_pair_ref)
|
||||
)
|
||||
auto iter () const HB_AUTO_RETURN
|
||||
(
|
||||
+ iter_items ()
|
||||
+ this->iter_items ()
|
||||
| hb_map (&item_t::get_pair)
|
||||
)
|
||||
auto keys_ref () const HB_AUTO_RETURN
|
||||
(
|
||||
+ iter_items ()
|
||||
+ this->iter_items ()
|
||||
| hb_map (&item_t::get_key)
|
||||
)
|
||||
auto keys () const HB_AUTO_RETURN
|
||||
(
|
||||
+ keys_ref ()
|
||||
+ this->keys_ref ()
|
||||
| hb_map (hb_ridentity)
|
||||
)
|
||||
auto values_ref () const HB_AUTO_RETURN
|
||||
(
|
||||
+ iter_items ()
|
||||
+ this->iter_items ()
|
||||
| hb_map (&item_t::get_value)
|
||||
)
|
||||
auto values () const HB_AUTO_RETURN
|
||||
(
|
||||
+ values_ref ()
|
||||
+ this->values_ref ()
|
||||
| hb_map (hb_ridentity)
|
||||
)
|
||||
|
||||
|
|
|
@ -191,27 +191,15 @@ struct hb_collect_variation_indices_context_t :
|
|||
static return_t default_return_value () { return hb_empty_t (); }
|
||||
|
||||
hb_set_t *layout_variation_indices;
|
||||
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map;
|
||||
hb_vector_t<int> *normalized_coords;
|
||||
const VariationStore *var_store;
|
||||
const hb_set_t *glyph_set;
|
||||
const hb_map_t *gpos_lookups;
|
||||
float *store_cache;
|
||||
|
||||
hb_collect_variation_indices_context_t (hb_set_t *layout_variation_indices_,
|
||||
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *varidx_delta_map_,
|
||||
hb_vector_t<int> *normalized_coords_,
|
||||
const VariationStore *var_store_,
|
||||
const hb_set_t *glyph_set_,
|
||||
const hb_map_t *gpos_lookups_,
|
||||
float *store_cache_) :
|
||||
const hb_map_t *gpos_lookups_) :
|
||||
layout_variation_indices (layout_variation_indices_),
|
||||
varidx_delta_map (varidx_delta_map_),
|
||||
normalized_coords (normalized_coords_),
|
||||
var_store (var_store_),
|
||||
glyph_set (glyph_set_),
|
||||
gpos_lookups (gpos_lookups_),
|
||||
store_cache (store_cache_) {}
|
||||
gpos_lookups (gpos_lookups_) {}
|
||||
};
|
||||
|
||||
template<typename OutputArray>
|
||||
|
@ -2300,6 +2288,158 @@ static inline bool ClassDef_serialize (hb_serialize_context_t *c,
|
|||
* Item Variation Store
|
||||
*/
|
||||
|
||||
/* ported from fonttools (class _Encoding) */
|
||||
struct delta_row_encoding_t
|
||||
{
|
||||
/* each byte represents a region, value is one of 0/1/2/4, which means bytes
|
||||
* needed for this region */
|
||||
hb_vector_t<uint8_t> chars;
|
||||
unsigned width = 0;
|
||||
hb_vector_t<uint8_t> columns;
|
||||
unsigned overhead = 0;
|
||||
hb_vector_t<const hb_vector_t<int>*> items;
|
||||
|
||||
delta_row_encoding_t () = default;
|
||||
delta_row_encoding_t (hb_vector_t<uint8_t>&& chars_,
|
||||
const hb_vector_t<int>* row = nullptr) :
|
||||
delta_row_encoding_t ()
|
||||
|
||||
{
|
||||
chars = std::move (chars_);
|
||||
width = get_width ();
|
||||
columns = get_columns ();
|
||||
overhead = get_chars_overhead (columns);
|
||||
if (row) items.push (row);
|
||||
}
|
||||
|
||||
bool is_empty () const
|
||||
{ return !items; }
|
||||
|
||||
static hb_vector_t<uint8_t> get_row_chars (const hb_vector_t<int>& row)
|
||||
{
|
||||
hb_vector_t<uint8_t> ret;
|
||||
if (!ret.alloc (row.length)) return ret;
|
||||
|
||||
bool long_words = false;
|
||||
|
||||
/* 0/1/2 byte encoding */
|
||||
for (int i = row.length - 1; i >= 0; i--)
|
||||
{
|
||||
int v = row.arrayZ[i];
|
||||
if (v == 0)
|
||||
ret.push (0);
|
||||
else if (v > 32767 || v < -32768)
|
||||
{
|
||||
long_words = true;
|
||||
break;
|
||||
}
|
||||
else if (v > 127 || v < -128)
|
||||
ret.push (2);
|
||||
else
|
||||
ret.push (1);
|
||||
}
|
||||
|
||||
if (!long_words)
|
||||
return ret;
|
||||
|
||||
/* redo, 0/2/4 bytes encoding */
|
||||
ret.reset ();
|
||||
for (int i = row.length - 1; i >= 0; i--)
|
||||
{
|
||||
int v = row.arrayZ[i];
|
||||
if (v == 0)
|
||||
ret.push (0);
|
||||
else if (v > 32767 || v < -32768)
|
||||
ret.push (4);
|
||||
else
|
||||
ret.push (2);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline unsigned get_width ()
|
||||
{
|
||||
unsigned ret = + hb_iter (chars)
|
||||
| hb_reduce (hb_add, 0u)
|
||||
;
|
||||
return ret;
|
||||
}
|
||||
|
||||
hb_vector_t<uint8_t> get_columns ()
|
||||
{
|
||||
hb_vector_t<uint8_t> cols;
|
||||
cols.alloc (chars.length);
|
||||
for (auto v : chars)
|
||||
{
|
||||
uint8_t flag = v ? 1 : 0;
|
||||
cols.push (flag);
|
||||
}
|
||||
return cols;
|
||||
}
|
||||
|
||||
static inline unsigned get_chars_overhead (const hb_vector_t<uint8_t>& cols)
|
||||
{
|
||||
unsigned c = 4 + 6; // 4 bytes for LOffset, 6 bytes for VarData header
|
||||
unsigned cols_bit_count = 0;
|
||||
for (auto v : cols)
|
||||
if (v) cols_bit_count++;
|
||||
return c + cols_bit_count * 2;
|
||||
}
|
||||
|
||||
unsigned get_gain () const
|
||||
{
|
||||
int count = items.length;
|
||||
return hb_max (0, (int) overhead - count);
|
||||
}
|
||||
|
||||
int gain_from_merging (const delta_row_encoding_t& other_encoding) const
|
||||
{
|
||||
int combined_width = 0;
|
||||
for (unsigned i = 0; i < chars.length; i++)
|
||||
combined_width += hb_max (chars.arrayZ[i], other_encoding.chars.arrayZ[i]);
|
||||
|
||||
hb_vector_t<uint8_t> combined_columns;
|
||||
combined_columns.alloc (columns.length);
|
||||
for (unsigned i = 0; i < columns.length; i++)
|
||||
combined_columns.push (columns.arrayZ[i] | other_encoding.columns.arrayZ[i]);
|
||||
|
||||
int combined_overhead = get_chars_overhead (combined_columns);
|
||||
int combined_gain = (int) overhead + (int) other_encoding.overhead - combined_overhead
|
||||
- (combined_width - (int) width) * items.length
|
||||
- (combined_width - (int) other_encoding.width) * other_encoding.items.length;
|
||||
|
||||
return combined_gain;
|
||||
}
|
||||
|
||||
static int cmp (const void *pa, const void *pb)
|
||||
{
|
||||
const delta_row_encoding_t *a = (const delta_row_encoding_t *)pa;
|
||||
const delta_row_encoding_t *b = (const delta_row_encoding_t *)pb;
|
||||
|
||||
int gain_a = a->get_gain ();
|
||||
int gain_b = b->get_gain ();
|
||||
|
||||
if (gain_a != gain_b)
|
||||
return gain_a - gain_b;
|
||||
|
||||
return (b->chars).as_array ().cmp ((a->chars).as_array ());
|
||||
}
|
||||
|
||||
static int cmp_width (const void *pa, const void *pb)
|
||||
{
|
||||
const delta_row_encoding_t *a = (const delta_row_encoding_t *)pa;
|
||||
const delta_row_encoding_t *b = (const delta_row_encoding_t *)pb;
|
||||
|
||||
if (a->width != b->width)
|
||||
return (int) a->width - (int) b->width;
|
||||
|
||||
return (b->chars).as_array ().cmp ((a->chars).as_array ());
|
||||
}
|
||||
|
||||
bool add_row (const hb_vector_t<int>* row)
|
||||
{ return items.push (row); }
|
||||
};
|
||||
|
||||
struct VarRegionAxis
|
||||
{
|
||||
float evaluate (int coord) const
|
||||
|
@ -2334,6 +2474,12 @@ struct VarRegionAxis
|
|||
* have to do that at runtime. */
|
||||
}
|
||||
|
||||
bool serialize (hb_serialize_context_t *c) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
return_trace (c->embed (this));
|
||||
}
|
||||
|
||||
public:
|
||||
F2DOT14 startCoord;
|
||||
F2DOT14 peakCoord;
|
||||
|
@ -2391,6 +2537,47 @@ struct VarRegionList
|
|||
return_trace (c->check_struct (this) && axesZ.sanitize (c, axisCount * regionCount));
|
||||
}
|
||||
|
||||
bool serialize (hb_serialize_context_t *c,
|
||||
const hb_vector_t<hb_tag_t>& axis_tags,
|
||||
const hb_vector_t<const hb_hashmap_t<hb_tag_t, Triple>*>& regions)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
unsigned axis_count = axis_tags.length;
|
||||
unsigned region_count = regions.length;
|
||||
if (!axis_count || !region_count) return_trace (false);
|
||||
if (unlikely (hb_unsigned_mul_overflows (axis_count * region_count,
|
||||
VarRegionAxis::static_size))) return_trace (false);
|
||||
if (unlikely (!c->extend_min (this))) return_trace (false);
|
||||
axisCount = axis_count;
|
||||
regionCount = region_count;
|
||||
|
||||
for (unsigned r = 0; r < region_count; r++)
|
||||
{
|
||||
const auto& region = regions[r];
|
||||
for (unsigned i = 0; i < axis_count; i++)
|
||||
{
|
||||
hb_tag_t tag = axis_tags.arrayZ[i];
|
||||
VarRegionAxis var_region_rec;
|
||||
Triple *coords;
|
||||
if (region->has (tag, &coords))
|
||||
{
|
||||
var_region_rec.startCoord.set_float (coords->minimum);
|
||||
var_region_rec.peakCoord.set_float (coords->middle);
|
||||
var_region_rec.endCoord.set_float (coords->maximum);
|
||||
}
|
||||
else
|
||||
{
|
||||
var_region_rec.startCoord.set_int (0);
|
||||
var_region_rec.peakCoord.set_int (0);
|
||||
var_region_rec.endCoord.set_int (0);
|
||||
}
|
||||
if (!var_region_rec.serialize (c))
|
||||
return_trace (false);
|
||||
}
|
||||
}
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
bool serialize (hb_serialize_context_t *c, const VarRegionList *src, const hb_inc_bimap_t ®ion_map)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
@ -2411,6 +2598,45 @@ struct VarRegionList
|
|||
return_trace (true);
|
||||
}
|
||||
|
||||
bool get_var_region (unsigned region_index,
|
||||
const hb_map_t& axes_old_index_tag_map,
|
||||
hb_hashmap_t<hb_tag_t, Triple>& axis_tuples /* OUT */) const
|
||||
{
|
||||
if (region_index >= regionCount) return false;
|
||||
const VarRegionAxis* axis_region = axesZ.arrayZ + (region_index * axisCount);
|
||||
for (unsigned i = 0; i < axisCount; i++)
|
||||
{
|
||||
hb_tag_t *axis_tag;
|
||||
if (!axes_old_index_tag_map.has (i, &axis_tag))
|
||||
return false;
|
||||
|
||||
float min_val = axis_region->startCoord.to_float ();
|
||||
float def_val = axis_region->peakCoord.to_float ();
|
||||
float max_val = axis_region->endCoord.to_float ();
|
||||
|
||||
if (def_val != 0.f)
|
||||
axis_tuples.set (*axis_tag, Triple (min_val, def_val, max_val));
|
||||
axis_region++;
|
||||
}
|
||||
return !axis_tuples.in_error ();
|
||||
}
|
||||
|
||||
bool get_var_regions (const hb_map_t& axes_old_index_tag_map,
|
||||
hb_vector_t<hb_hashmap_t<hb_tag_t, Triple>>& regions /* OUT */) const
|
||||
{
|
||||
if (!regions.alloc (regionCount))
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0; i < regionCount; i++)
|
||||
{
|
||||
hb_hashmap_t<hb_tag_t, Triple> axis_tuples;
|
||||
if (!get_var_region (i, axes_old_index_tag_map, axis_tuples))
|
||||
return false;
|
||||
regions.push (std::move (axis_tuples));
|
||||
}
|
||||
return !regions.in_error ();
|
||||
}
|
||||
|
||||
unsigned int get_size () const { return min_size + VarRegionAxis::static_size * axisCount * regionCount; }
|
||||
|
||||
public:
|
||||
|
@ -2430,6 +2656,9 @@ struct VarData
|
|||
|
||||
unsigned int get_region_index_count () const
|
||||
{ return regionIndices.len; }
|
||||
|
||||
unsigned get_region_index (unsigned i) const
|
||||
{ return i >= regionIndices.len ? -1 : regionIndices[i]; }
|
||||
|
||||
unsigned int get_row_size () const
|
||||
{ return (wordCount () + regionIndices.len) * (longWords () ? 2 : 1); }
|
||||
|
@ -2505,6 +2734,81 @@ struct VarData
|
|||
get_row_size ()));
|
||||
}
|
||||
|
||||
bool serialize (hb_serialize_context_t *c,
|
||||
bool has_long,
|
||||
const hb_vector_t<const hb_vector_t<int>*>& rows)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
if (unlikely (!c->extend_min (this))) return_trace (false);
|
||||
unsigned row_count = rows.length;
|
||||
itemCount = row_count;
|
||||
|
||||
int min_threshold = has_long ? -65536 : -128;
|
||||
int max_threshold = has_long ? +65535 : +127;
|
||||
enum delta_size_t { kZero=0, kNonWord, kWord };
|
||||
hb_vector_t<delta_size_t> delta_sz;
|
||||
unsigned num_regions = rows[0]->length;
|
||||
if (!delta_sz.resize (num_regions))
|
||||
return_trace (false);
|
||||
|
||||
unsigned word_count = 0;
|
||||
for (unsigned r = 0; r < num_regions; r++)
|
||||
{
|
||||
for (unsigned i = 0; i < row_count; i++)
|
||||
{
|
||||
int delta = rows[i]->arrayZ[r];
|
||||
if (delta < min_threshold || delta > max_threshold)
|
||||
{
|
||||
delta_sz[r] = kWord;
|
||||
word_count++;
|
||||
break;
|
||||
}
|
||||
else if (delta != 0)
|
||||
{
|
||||
delta_sz[r] = kNonWord;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* reorder regions: words and then non-words*/
|
||||
unsigned word_index = 0;
|
||||
unsigned non_word_index = word_count;
|
||||
hb_map_t ri_map;
|
||||
for (unsigned r = 0; r < num_regions; r++)
|
||||
{
|
||||
if (!delta_sz[r]) continue;
|
||||
unsigned new_r = (delta_sz[r] == kWord)? word_index++ : non_word_index++;
|
||||
if (!ri_map.set (new_r, r))
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
wordSizeCount = word_count | (has_long ? 0x8000u /* LONG_WORDS */ : 0);
|
||||
|
||||
unsigned ri_count = ri_map.get_population ();
|
||||
regionIndices.len = ri_count;
|
||||
if (unlikely (!c->extend (this))) return_trace (false);
|
||||
|
||||
for (unsigned r = 0; r < ri_count; r++)
|
||||
{
|
||||
hb_codepoint_t *idx;
|
||||
if (!ri_map.has (r, &idx))
|
||||
return_trace (false);
|
||||
regionIndices[r] = *idx;
|
||||
}
|
||||
|
||||
HBUINT8 *delta_bytes = get_delta_bytes ();
|
||||
unsigned row_size = get_row_size ();
|
||||
for (unsigned int i = 0; i < row_count; i++)
|
||||
{
|
||||
for (unsigned int r = 0; r < ri_count; r++)
|
||||
{
|
||||
int delta = rows[i]->arrayZ[ri_map[r]];
|
||||
set_item_delta_fast (i, r, delta, delta_bytes, row_size);
|
||||
}
|
||||
}
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
bool serialize (hb_serialize_context_t *c,
|
||||
const VarData *src,
|
||||
const hb_inc_bimap_t &inner_map,
|
||||
|
@ -2625,13 +2929,15 @@ struct VarData
|
|||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
public:
|
||||
const HBUINT8 *get_delta_bytes () const
|
||||
{ return &StructAfter<HBUINT8> (regionIndices); }
|
||||
|
||||
protected:
|
||||
HBUINT8 *get_delta_bytes ()
|
||||
{ return &StructAfter<HBUINT8> (regionIndices); }
|
||||
|
||||
public:
|
||||
int32_t get_item_delta_fast (unsigned int item, unsigned int region,
|
||||
const HBUINT8 *delta_bytes, unsigned row_size) const
|
||||
{
|
||||
|
@ -2662,6 +2968,7 @@ struct VarData
|
|||
get_row_size ());
|
||||
}
|
||||
|
||||
protected:
|
||||
void set_item_delta_fast (unsigned int item, unsigned int region, int32_t delta,
|
||||
HBUINT8 *delta_bytes, unsigned row_size)
|
||||
{
|
||||
|
@ -2704,6 +3011,7 @@ struct VarData
|
|||
|
||||
struct VariationStore
|
||||
{
|
||||
friend struct item_variations_t;
|
||||
using cache_t = VarRegionList::cache_t;
|
||||
|
||||
cache_t *create_cache () const
|
||||
|
@ -2774,6 +3082,36 @@ struct VariationStore
|
|||
dataSets.sanitize (c, this));
|
||||
}
|
||||
|
||||
bool serialize (hb_serialize_context_t *c,
|
||||
bool has_long,
|
||||
const hb_vector_t<hb_tag_t>& axis_tags,
|
||||
const hb_vector_t<const hb_hashmap_t<hb_tag_t, Triple>*>& region_list,
|
||||
const hb_vector_t<delta_row_encoding_t>& vardata_encodings)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
#ifdef HB_NO_VAR
|
||||
return_trace (false);
|
||||
#endif
|
||||
if (unlikely (!c->extend_min (this))) return_trace (false);
|
||||
|
||||
format = 1;
|
||||
if (!regions.serialize_serialize (c, axis_tags, region_list))
|
||||
return_trace (false);
|
||||
|
||||
unsigned num_var_data = vardata_encodings.length;
|
||||
if (!num_var_data) return_trace (false);
|
||||
if (unlikely (!c->check_assign (dataSets.len, num_var_data,
|
||||
HB_SERIALIZE_ERROR_INT_OVERFLOW)))
|
||||
return_trace (false);
|
||||
|
||||
if (unlikely (!c->extend (dataSets))) return_trace (false);
|
||||
for (unsigned i = 0; i < num_var_data; i++)
|
||||
if (!dataSets[i].serialize_serialize (c, has_long, vardata_encodings[i].items))
|
||||
return_trace (false);
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
bool serialize (hb_serialize_context_t *c,
|
||||
const VariationStore *src,
|
||||
const hb_array_t <const hb_inc_bimap_t> &inner_maps)
|
||||
|
@ -2903,6 +3241,22 @@ struct VariationStore
|
|||
return dataSets.len;
|
||||
}
|
||||
|
||||
const VarData& get_sub_table (unsigned i) const
|
||||
{
|
||||
#ifdef HB_NO_VAR
|
||||
return Null (VarData);
|
||||
#endif
|
||||
return this+dataSets[i];
|
||||
}
|
||||
|
||||
const VarRegionList& get_region_list () const
|
||||
{
|
||||
#ifdef HB_NO_VAR
|
||||
return Null (VarRegionList);
|
||||
#endif
|
||||
return this+regions;
|
||||
}
|
||||
|
||||
protected:
|
||||
HBUINT16 format;
|
||||
Offset32To<VarRegionList> regions;
|
||||
|
@ -3614,23 +3968,13 @@ struct VariationDevice
|
|||
auto *out = c->embed (this);
|
||||
if (unlikely (!out)) return_trace (nullptr);
|
||||
|
||||
unsigned new_idx = hb_first (*v);
|
||||
out->varIdx = new_idx;
|
||||
if (!c->check_assign (out->varIdx, hb_first (*v), HB_SERIALIZE_ERROR_INT_OVERFLOW))
|
||||
return_trace (nullptr);
|
||||
return_trace (out);
|
||||
}
|
||||
|
||||
void collect_variation_index (hb_collect_variation_indices_context_t *c) const
|
||||
{
|
||||
c->layout_variation_indices->add (varIdx);
|
||||
int delta = 0;
|
||||
if (c->normalized_coords && c->var_store)
|
||||
delta = roundf (c->var_store->get_delta (varIdx, c->normalized_coords->arrayZ,
|
||||
c->normalized_coords->length, c->store_cache));
|
||||
|
||||
/* set new varidx to HB_OT_LAYOUT_NO_VARIATIONS_INDEX here, will remap
|
||||
* varidx later*/
|
||||
c->varidx_delta_map->set (varIdx, hb_pair_t<unsigned, int> (HB_OT_LAYOUT_NO_VARIATIONS_INDEX, delta));
|
||||
}
|
||||
{ c->layout_variation_indices->add (varIdx); }
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
|
|
|
@ -1308,11 +1308,16 @@ hb_ot_layout_collect_features_map (hb_face_t *face,
|
|||
unsigned int count = l.get_feature_indexes (0, nullptr, nullptr);
|
||||
feature_map->alloc (count);
|
||||
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
/* Loop in reverse, such that earlier entries win. That emulates
|
||||
* a linear search, which seems to be what other implementations do.
|
||||
* We found that with arialuni_t.ttf, the "ur" language system has
|
||||
* duplicate features, and the earlier ones work but not later ones.
|
||||
*/
|
||||
for (unsigned int i = count; i; i--)
|
||||
{
|
||||
unsigned feature_index = 0;
|
||||
unsigned feature_count = 1;
|
||||
l.get_feature_indexes (i, &feature_count, &feature_index);
|
||||
l.get_feature_indexes (i - 1, &feature_count, &feature_index);
|
||||
if (!feature_count)
|
||||
break;
|
||||
hb_tag_t feature_tag = g.get_feature_tag (feature_index);
|
||||
|
|
|
@ -246,24 +246,19 @@ struct OS2
|
|||
}
|
||||
#endif
|
||||
|
||||
if (c->plan->user_axes_location.has (HB_TAG ('w','g','h','t')) &&
|
||||
!c->plan->pinned_at_default)
|
||||
Triple *axis_range;
|
||||
if (c->plan->user_axes_location.has (HB_TAG ('w','g','h','t'), &axis_range))
|
||||
{
|
||||
float weight_class = c->plan->user_axes_location.get (HB_TAG ('w','g','h','t')).middle;
|
||||
if (!c->serializer->check_assign (os2_prime->usWeightClass,
|
||||
roundf (hb_clamp (weight_class, 1.0f, 1000.0f)),
|
||||
HB_SERIALIZE_ERROR_INT_OVERFLOW))
|
||||
return_trace (false);
|
||||
unsigned weight_class = static_cast<unsigned> (roundf (hb_clamp (axis_range->middle, 1.0f, 1000.0f)));
|
||||
if (os2_prime->usWeightClass != weight_class)
|
||||
os2_prime->usWeightClass = weight_class;
|
||||
}
|
||||
|
||||
if (c->plan->user_axes_location.has (HB_TAG ('w','d','t','h')) &&
|
||||
!c->plan->pinned_at_default)
|
||||
if (c->plan->user_axes_location.has (HB_TAG ('w','d','t','h'), &axis_range))
|
||||
{
|
||||
float width = c->plan->user_axes_location.get (HB_TAG ('w','d','t','h')).middle;
|
||||
if (!c->serializer->check_assign (os2_prime->usWidthClass,
|
||||
roundf (map_wdth_to_widthclass (width)),
|
||||
HB_SERIALIZE_ERROR_INT_OVERFLOW))
|
||||
return_trace (false);
|
||||
unsigned width_class = static_cast<unsigned> (roundf (map_wdth_to_widthclass (axis_range->middle)));
|
||||
if (os2_prime->usWidthClass != width_class)
|
||||
os2_prime->usWidthClass = width_class;
|
||||
}
|
||||
|
||||
if (c->plan->flags & HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES)
|
||||
|
|
|
@ -113,12 +113,12 @@ struct post
|
|||
}
|
||||
#endif
|
||||
|
||||
if (c->plan->user_axes_location.has (HB_TAG ('s','l','n','t')) &&
|
||||
!c->plan->pinned_at_default)
|
||||
Triple *axis_range;
|
||||
if (c->plan->user_axes_location.has (HB_TAG ('s','l','n','t'), &axis_range))
|
||||
{
|
||||
float italic_angle = c->plan->user_axes_location.get (HB_TAG ('s','l','n','t')).middle;
|
||||
italic_angle = hb_max (-90.f, hb_min (italic_angle, 90.f));
|
||||
post_prime->italicAngle.set_float (italic_angle);
|
||||
float italic_angle = hb_max (-90.f, hb_min (axis_range->middle, 90.f));
|
||||
if (post_prime->italicAngle.to_float () != italic_angle)
|
||||
post_prime->italicAngle.set_float (italic_angle);
|
||||
}
|
||||
|
||||
if (glyph_names && version.major == 2)
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#define HB_OT_VAR_COMMON_HH
|
||||
|
||||
#include "hb-ot-layout-common.hh"
|
||||
#include "hb-priority-queue.hh"
|
||||
|
||||
|
||||
namespace OT {
|
||||
|
@ -1171,14 +1172,71 @@ struct TupleVariationData
|
|||
return true;
|
||||
}
|
||||
|
||||
bool create_from_item_var_data (const VarData &var_data,
|
||||
const hb_vector_t<hb_hashmap_t<hb_tag_t, Triple>>& regions,
|
||||
const hb_map_t& axes_old_index_tag_map,
|
||||
const hb_inc_bimap_t* inner_map = nullptr)
|
||||
{
|
||||
/* NULL offset, to keep original varidx valid, just return */
|
||||
if (&var_data == &Null (VarData))
|
||||
return true;
|
||||
|
||||
unsigned num_regions = var_data.get_region_index_count ();
|
||||
if (!tuple_vars.alloc (num_regions)) return false;
|
||||
|
||||
unsigned item_count = inner_map ? inner_map->get_population () : var_data.get_item_count ();
|
||||
unsigned row_size = var_data.get_row_size ();
|
||||
const HBUINT8 *delta_bytes = var_data.get_delta_bytes ();
|
||||
|
||||
for (unsigned r = 0; r < num_regions; r++)
|
||||
{
|
||||
/* In VarData, deltas are organized in rows, convert them into
|
||||
* column(region) based tuples, resize deltas_x first */
|
||||
tuple_delta_t tuple;
|
||||
if (!tuple.deltas_x.resize (item_count, false) ||
|
||||
!tuple.indices.resize (item_count, false))
|
||||
return false;
|
||||
|
||||
for (unsigned i = 0; i < item_count; i++)
|
||||
{
|
||||
tuple.indices.arrayZ[i] = true;
|
||||
tuple.deltas_x.arrayZ[i] = var_data.get_item_delta_fast (inner_map ? inner_map->backward (i) : i,
|
||||
r, delta_bytes, row_size);
|
||||
}
|
||||
|
||||
unsigned region_index = var_data.get_region_index (r);
|
||||
if (region_index >= regions.length) return false;
|
||||
tuple.axis_tuples = regions.arrayZ[region_index];
|
||||
|
||||
tuple_vars.push (std::move (tuple));
|
||||
}
|
||||
return !tuple_vars.in_error ();
|
||||
}
|
||||
|
||||
private:
|
||||
void change_tuple_variations_axis_limits (const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location,
|
||||
static int _cmp_axis_tag (const void *pa, const void *pb)
|
||||
{
|
||||
const hb_tag_t *a = (const hb_tag_t*) pa;
|
||||
const hb_tag_t *b = (const hb_tag_t*) pb;
|
||||
return (int)(*a) - (int)(*b);
|
||||
}
|
||||
|
||||
bool change_tuple_variations_axis_limits (const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location,
|
||||
const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances)
|
||||
{
|
||||
for (auto _ : normalized_axes_location)
|
||||
/* sort axis_tag/axis_limits, make result deterministic */
|
||||
hb_vector_t<hb_tag_t> axis_tags;
|
||||
if (!axis_tags.alloc (normalized_axes_location.get_population ()))
|
||||
return false;
|
||||
for (auto t : normalized_axes_location.keys ())
|
||||
axis_tags.push (t);
|
||||
|
||||
axis_tags.qsort (_cmp_axis_tag);
|
||||
for (auto axis_tag : axis_tags)
|
||||
{
|
||||
hb_tag_t axis_tag = _.first;
|
||||
Triple axis_limit = _.second;
|
||||
Triple *axis_limit;
|
||||
if (!normalized_axes_location.has (axis_tag, &axis_limit))
|
||||
return false;
|
||||
TripleDistances axis_triple_distances{1.f, 1.f};
|
||||
if (axes_triple_distances.has (axis_tag))
|
||||
axis_triple_distances = axes_triple_distances.get (axis_tag);
|
||||
|
@ -1186,12 +1244,13 @@ struct TupleVariationData
|
|||
hb_vector_t<tuple_delta_t> new_vars;
|
||||
for (const tuple_delta_t& var : tuple_vars)
|
||||
{
|
||||
hb_vector_t<tuple_delta_t> out = var.change_tuple_var_axis_limit (axis_tag, axis_limit, axis_triple_distances);
|
||||
hb_vector_t<tuple_delta_t> out = var.change_tuple_var_axis_limit (axis_tag, *axis_limit, axis_triple_distances);
|
||||
if (!out) continue;
|
||||
|
||||
unsigned new_len = new_vars.length + out.length;
|
||||
|
||||
if (unlikely (!new_vars.alloc (new_len, false)))
|
||||
{ fini (); return;}
|
||||
{ fini (); return false;}
|
||||
|
||||
for (unsigned i = 0; i < out.length; i++)
|
||||
new_vars.push (std::move (out[i]));
|
||||
|
@ -1199,6 +1258,7 @@ struct TupleVariationData
|
|||
tuple_vars.fini ();
|
||||
tuple_vars = std::move (new_vars);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* merge tuple variations with overlapping tents */
|
||||
|
@ -1382,7 +1442,8 @@ struct TupleVariationData
|
|||
contour_point_vector_t* contour_points = nullptr)
|
||||
{
|
||||
if (!tuple_vars) return true;
|
||||
change_tuple_variations_axis_limits (normalized_axes_location, axes_triple_distances);
|
||||
if (!change_tuple_variations_axis_limits (normalized_axes_location, axes_triple_distances))
|
||||
return false;
|
||||
/* compute inferred deltas only for gvar */
|
||||
if (contour_points)
|
||||
if (!calc_inferred_deltas (*contour_points))
|
||||
|
@ -1705,6 +1766,463 @@ struct TupleVariationData
|
|||
DEFINE_SIZE_MIN (4);
|
||||
};
|
||||
|
||||
using tuple_variations_t = TupleVariationData::tuple_variations_t;
|
||||
struct item_variations_t
|
||||
{
|
||||
using region_t = const hb_hashmap_t<hb_tag_t, Triple>*;
|
||||
private:
|
||||
/* each subtable is decompiled into a tuple_variations_t, in which all tuples
|
||||
* have the same num of deltas (rows) */
|
||||
hb_vector_t<tuple_variations_t> vars;
|
||||
|
||||
/* original region list, decompiled from item varstore, used when rebuilding
|
||||
* region list after instantiation */
|
||||
hb_vector_t<hb_hashmap_t<hb_tag_t, Triple>> orig_region_list;
|
||||
|
||||
/* region list: vector of Regions, maintain the original order for the regions
|
||||
* that existed before instantiate (), append the new regions at the end.
|
||||
* Regions are stored in each tuple already, save pointers only.
|
||||
* When converting back to item varstore, unused regions will be pruned */
|
||||
hb_vector_t<region_t> region_list;
|
||||
|
||||
/* region -> idx map after instantiation and pruning unused regions */
|
||||
hb_hashmap_t<region_t, unsigned> region_map;
|
||||
|
||||
/* all delta rows after instantiation */
|
||||
hb_vector_t<hb_vector_t<int>> delta_rows;
|
||||
/* final optimized vector of encoding objects used to assemble the varstore */
|
||||
hb_vector_t<delta_row_encoding_t> encodings;
|
||||
|
||||
/* old varidxes -> new var_idxes map */
|
||||
hb_map_t varidx_map;
|
||||
|
||||
/* has long words */
|
||||
bool has_long = false;
|
||||
|
||||
public:
|
||||
bool has_long_word () const
|
||||
{ return has_long; }
|
||||
|
||||
const hb_vector_t<region_t>& get_region_list () const
|
||||
{ return region_list; }
|
||||
|
||||
const hb_vector_t<delta_row_encoding_t>& get_vardata_encodings () const
|
||||
{ return encodings; }
|
||||
|
||||
const hb_map_t& get_varidx_map () const
|
||||
{ return varidx_map; }
|
||||
|
||||
bool instantiate (const VariationStore& varStore,
|
||||
const hb_subset_plan_t *plan,
|
||||
bool optimize=true,
|
||||
bool use_no_variation_idx=true,
|
||||
const hb_array_t <const hb_inc_bimap_t> inner_maps = hb_array_t<const hb_inc_bimap_t> ())
|
||||
{
|
||||
if (!create_from_item_varstore (varStore, plan->axes_old_index_tag_map, inner_maps))
|
||||
return false;
|
||||
if (!instantiate_tuple_vars (plan->axes_location, plan->axes_triple_distances))
|
||||
return false;
|
||||
return as_item_varstore (optimize, use_no_variation_idx);
|
||||
}
|
||||
|
||||
/* keep below APIs public only for unit test: test-item-varstore */
|
||||
bool create_from_item_varstore (const VariationStore& varStore,
|
||||
const hb_map_t& axes_old_index_tag_map,
|
||||
const hb_array_t <const hb_inc_bimap_t> inner_maps = hb_array_t<const hb_inc_bimap_t> ())
|
||||
{
|
||||
const VarRegionList& regionList = varStore.get_region_list ();
|
||||
if (!regionList.get_var_regions (axes_old_index_tag_map, orig_region_list))
|
||||
return false;
|
||||
|
||||
unsigned num_var_data = varStore.get_sub_table_count ();
|
||||
if (inner_maps && inner_maps.length != num_var_data) return false;
|
||||
if (!vars.alloc (num_var_data)) return false;
|
||||
|
||||
for (unsigned i = 0; i < num_var_data; i++)
|
||||
{
|
||||
if (inner_maps && !inner_maps.arrayZ[i].get_population ())
|
||||
continue;
|
||||
tuple_variations_t var_data_tuples;
|
||||
if (!var_data_tuples.create_from_item_var_data (varStore.get_sub_table (i),
|
||||
orig_region_list,
|
||||
axes_old_index_tag_map,
|
||||
inner_maps ? &(inner_maps.arrayZ[i]) : nullptr))
|
||||
return false;
|
||||
|
||||
vars.push (std::move (var_data_tuples));
|
||||
}
|
||||
return !vars.in_error ();
|
||||
}
|
||||
|
||||
bool instantiate_tuple_vars (const hb_hashmap_t<hb_tag_t, Triple>& normalized_axes_location,
|
||||
const hb_hashmap_t<hb_tag_t, TripleDistances>& axes_triple_distances)
|
||||
{
|
||||
for (tuple_variations_t& tuple_vars : vars)
|
||||
if (!tuple_vars.instantiate (normalized_axes_location, axes_triple_distances))
|
||||
return false;
|
||||
|
||||
if (!build_region_list ()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool build_region_list ()
|
||||
{
|
||||
/* scan all tuples and collect all unique regions, prune unused regions */
|
||||
hb_hashmap_t<region_t, unsigned> all_regions;
|
||||
hb_hashmap_t<region_t, unsigned> used_regions;
|
||||
|
||||
/* use a vector when inserting new regions, make result deterministic */
|
||||
hb_vector_t<region_t> all_unique_regions;
|
||||
for (const tuple_variations_t& sub_table : vars)
|
||||
{
|
||||
for (const tuple_delta_t& tuple : sub_table.tuple_vars)
|
||||
{
|
||||
region_t r = &(tuple.axis_tuples);
|
||||
if (!used_regions.has (r))
|
||||
{
|
||||
bool all_zeros = true;
|
||||
for (float d : tuple.deltas_x)
|
||||
{
|
||||
int delta = (int) roundf (d);
|
||||
if (delta != 0)
|
||||
{
|
||||
all_zeros = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!all_zeros)
|
||||
{
|
||||
if (!used_regions.set (r, 1))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (all_regions.has (r))
|
||||
continue;
|
||||
if (!all_regions.set (r, 1))
|
||||
return false;
|
||||
all_unique_regions.push (r);
|
||||
}
|
||||
}
|
||||
|
||||
if (!all_regions || !all_unique_regions) return false;
|
||||
if (!region_list.alloc (all_regions.get_population ()))
|
||||
return false;
|
||||
|
||||
unsigned idx = 0;
|
||||
/* append the original regions that pre-existed */
|
||||
for (const auto& r : orig_region_list)
|
||||
{
|
||||
if (!all_regions.has (&r) || !used_regions.has (&r))
|
||||
continue;
|
||||
|
||||
region_list.push (&r);
|
||||
if (!region_map.set (&r, idx))
|
||||
return false;
|
||||
all_regions.del (&r);
|
||||
idx++;
|
||||
}
|
||||
|
||||
/* append the new regions at the end */
|
||||
for (const auto& r: all_unique_regions)
|
||||
{
|
||||
if (!all_regions.has (r) || !used_regions.has (r))
|
||||
continue;
|
||||
region_list.push (r);
|
||||
if (!region_map.set (r, idx))
|
||||
return false;
|
||||
all_regions.del (r);
|
||||
idx++;
|
||||
}
|
||||
return (!region_list.in_error ()) && (!region_map.in_error ());
|
||||
}
|
||||
|
||||
/* main algorithm ported from fonttools VarStore_optimize() method, optimize
|
||||
* varstore by default */
|
||||
|
||||
struct combined_gain_idx_tuple_t
|
||||
{
|
||||
int gain;
|
||||
unsigned idx_1;
|
||||
unsigned idx_2;
|
||||
|
||||
combined_gain_idx_tuple_t () = default;
|
||||
combined_gain_idx_tuple_t (int gain_, unsigned i, unsigned j)
|
||||
:gain (gain_), idx_1 (i), idx_2 (j) {}
|
||||
|
||||
bool operator < (const combined_gain_idx_tuple_t& o)
|
||||
{
|
||||
if (gain != o.gain)
|
||||
return gain < o.gain;
|
||||
|
||||
if (idx_1 != o.idx_1)
|
||||
return idx_1 < o.idx_1;
|
||||
|
||||
return idx_2 < o.idx_2;
|
||||
}
|
||||
|
||||
bool operator <= (const combined_gain_idx_tuple_t& o)
|
||||
{
|
||||
if (*this < o) return true;
|
||||
return gain == o.gain && idx_1 == o.idx_1 && idx_2 == o.idx_2;
|
||||
}
|
||||
};
|
||||
|
||||
bool as_item_varstore (bool optimize=true, bool use_no_variation_idx=true)
|
||||
{
|
||||
if (!region_list) return false;
|
||||
unsigned num_cols = region_list.length;
|
||||
/* pre-alloc a 2D vector for all sub_table's VarData rows */
|
||||
unsigned total_rows = 0;
|
||||
for (unsigned major = 0; major < vars.length; major++)
|
||||
{
|
||||
const tuple_variations_t& tuples = vars[major];
|
||||
/* all tuples in each sub_table should have same num of deltas(num rows) */
|
||||
total_rows += tuples.tuple_vars[0].deltas_x.length;
|
||||
}
|
||||
|
||||
if (!delta_rows.resize (total_rows)) return false;
|
||||
/* init all rows to [0]*num_cols */
|
||||
for (unsigned i = 0; i < total_rows; i++)
|
||||
if (!(delta_rows[i].resize (num_cols))) return false;
|
||||
|
||||
/* old VarIdxes -> full encoding_row mapping */
|
||||
hb_hashmap_t<unsigned, const hb_vector_t<int>*> front_mapping;
|
||||
unsigned start_row = 0;
|
||||
hb_vector_t<delta_row_encoding_t> encoding_objs;
|
||||
hb_hashmap_t<hb_vector_t<uint8_t>, unsigned> chars_idx_map;
|
||||
|
||||
/* delta_rows map, used for filtering out duplicate rows */
|
||||
hb_hashmap_t<const hb_vector_t<int>*, unsigned> delta_rows_map;
|
||||
for (unsigned major = 0; major < vars.length; major++)
|
||||
{
|
||||
/* deltas are stored in tuples(column based), convert them back into items
|
||||
* (row based) delta */
|
||||
const tuple_variations_t& tuples = vars[major];
|
||||
unsigned num_rows = tuples.tuple_vars[0].deltas_x.length;
|
||||
for (const tuple_delta_t& tuple: tuples.tuple_vars)
|
||||
{
|
||||
if (tuple.deltas_x.length != num_rows)
|
||||
return false;
|
||||
|
||||
/* skip unused regions */
|
||||
unsigned *col_idx;
|
||||
if (!region_map.has (&(tuple.axis_tuples), &col_idx))
|
||||
continue;
|
||||
|
||||
for (unsigned i = 0; i < num_rows; i++)
|
||||
{
|
||||
int rounded_delta = roundf (tuple.deltas_x[i]);
|
||||
delta_rows[start_row + i][*col_idx] += rounded_delta;
|
||||
if ((!has_long) && (rounded_delta < -65536 || rounded_delta > 65535))
|
||||
has_long = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!optimize)
|
||||
{
|
||||
/* assemble a delta_row_encoding_t for this subtable, skip optimization so
|
||||
* chars is not initialized, we only need delta rows for serialization */
|
||||
delta_row_encoding_t obj;
|
||||
for (unsigned r = start_row; r < start_row + num_rows; r++)
|
||||
obj.add_row (&(delta_rows.arrayZ[r]));
|
||||
|
||||
encodings.push (std::move (obj));
|
||||
start_row += num_rows;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (unsigned minor = 0; minor < num_rows; minor++)
|
||||
{
|
||||
const hb_vector_t<int>& row = delta_rows[start_row + minor];
|
||||
if (use_no_variation_idx)
|
||||
{
|
||||
bool all_zeros = true;
|
||||
for (int delta : row)
|
||||
{
|
||||
if (delta != 0)
|
||||
{
|
||||
all_zeros = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (all_zeros)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!front_mapping.set ((major<<16) + minor, &row))
|
||||
return false;
|
||||
|
||||
hb_vector_t<uint8_t> chars = delta_row_encoding_t::get_row_chars (row);
|
||||
if (!chars) return false;
|
||||
|
||||
if (delta_rows_map.has (&row))
|
||||
continue;
|
||||
|
||||
delta_rows_map.set (&row, 1);
|
||||
unsigned *obj_idx;
|
||||
if (chars_idx_map.has (chars, &obj_idx))
|
||||
{
|
||||
delta_row_encoding_t& obj = encoding_objs[*obj_idx];
|
||||
if (!obj.add_row (&row))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!chars_idx_map.set (chars, encoding_objs.length))
|
||||
return false;
|
||||
delta_row_encoding_t obj (std::move (chars), &row);
|
||||
encoding_objs.push (std::move (obj));
|
||||
}
|
||||
}
|
||||
|
||||
start_row += num_rows;
|
||||
}
|
||||
|
||||
/* return directly if no optimization, maintain original VariationIndex so
|
||||
* varidx_map would be empty */
|
||||
if (!optimize) return !encodings.in_error ();
|
||||
|
||||
/* sort encoding_objs */
|
||||
encoding_objs.qsort ();
|
||||
|
||||
/* main algorithm: repeatedly pick 2 best encodings to combine, and combine
|
||||
* them */
|
||||
hb_priority_queue_t<combined_gain_idx_tuple_t> queue;
|
||||
unsigned num_todos = encoding_objs.length;
|
||||
for (unsigned i = 0; i < num_todos; i++)
|
||||
{
|
||||
for (unsigned j = i + 1; j < num_todos; j++)
|
||||
{
|
||||
int combining_gain = encoding_objs.arrayZ[i].gain_from_merging (encoding_objs.arrayZ[j]);
|
||||
if (combining_gain > 0)
|
||||
queue.insert (combined_gain_idx_tuple_t (-combining_gain, i, j), 0);
|
||||
}
|
||||
}
|
||||
|
||||
hb_set_t removed_todo_idxes;
|
||||
while (queue)
|
||||
{
|
||||
auto t = queue.pop_minimum ().first;
|
||||
unsigned i = t.idx_1;
|
||||
unsigned j = t.idx_2;
|
||||
|
||||
if (removed_todo_idxes.has (i) || removed_todo_idxes.has (j))
|
||||
continue;
|
||||
|
||||
delta_row_encoding_t& encoding = encoding_objs.arrayZ[i];
|
||||
delta_row_encoding_t& other_encoding = encoding_objs.arrayZ[j];
|
||||
|
||||
removed_todo_idxes.add (i);
|
||||
removed_todo_idxes.add (j);
|
||||
|
||||
hb_vector_t<uint8_t> combined_chars;
|
||||
if (!combined_chars.alloc (encoding.chars.length))
|
||||
return false;
|
||||
|
||||
for (unsigned idx = 0; idx < encoding.chars.length; idx++)
|
||||
{
|
||||
uint8_t v = hb_max (encoding.chars.arrayZ[idx], other_encoding.chars.arrayZ[idx]);
|
||||
combined_chars.push (v);
|
||||
}
|
||||
|
||||
delta_row_encoding_t combined_encoding_obj (std::move (combined_chars));
|
||||
for (const auto& row : hb_concat (encoding.items, other_encoding.items))
|
||||
combined_encoding_obj.add_row (row);
|
||||
|
||||
for (unsigned idx = 0; idx < encoding_objs.length; idx++)
|
||||
{
|
||||
if (removed_todo_idxes.has (idx)) continue;
|
||||
|
||||
const delta_row_encoding_t& obj = encoding_objs.arrayZ[idx];
|
||||
if (obj.chars == combined_chars)
|
||||
{
|
||||
for (const auto& row : obj.items)
|
||||
combined_encoding_obj.add_row (row);
|
||||
|
||||
removed_todo_idxes.add (idx);
|
||||
continue;
|
||||
}
|
||||
|
||||
int combined_gain = combined_encoding_obj.gain_from_merging (obj);
|
||||
if (combined_gain > 0)
|
||||
queue.insert (combined_gain_idx_tuple_t (-combined_gain, idx, encoding_objs.length), 0);
|
||||
}
|
||||
|
||||
encoding_objs.push (std::move (combined_encoding_obj));
|
||||
}
|
||||
|
||||
int num_final_encodings = (int) encoding_objs.length - (int) removed_todo_idxes.get_population ();
|
||||
if (num_final_encodings <= 0) return false;
|
||||
|
||||
if (!encodings.alloc (num_final_encodings)) return false;
|
||||
for (unsigned i = 0; i < encoding_objs.length; i++)
|
||||
{
|
||||
if (removed_todo_idxes.has (i)) continue;
|
||||
encodings.push (std::move (encoding_objs.arrayZ[i]));
|
||||
}
|
||||
|
||||
/* sort again based on width, make result deterministic */
|
||||
encodings.qsort (delta_row_encoding_t::cmp_width);
|
||||
|
||||
return compile_varidx_map (front_mapping);
|
||||
}
|
||||
|
||||
private:
|
||||
/* compile varidx_map for one VarData subtable (index specified by major) */
|
||||
bool compile_varidx_map (const hb_hashmap_t<unsigned, const hb_vector_t<int>*>& front_mapping)
|
||||
{
|
||||
/* full encoding_row -> new VarIdxes mapping */
|
||||
hb_hashmap_t<const hb_vector_t<int>*, unsigned> back_mapping;
|
||||
|
||||
for (unsigned major = 0; major < encodings.length; major++)
|
||||
{
|
||||
delta_row_encoding_t& encoding = encodings[major];
|
||||
/* just sanity check, this shouldn't happen */
|
||||
if (encoding.is_empty ())
|
||||
return false;
|
||||
|
||||
unsigned num_rows = encoding.items.length;
|
||||
|
||||
/* sort rows, make result deterministic */
|
||||
encoding.items.qsort (_cmp_row);
|
||||
|
||||
/* compile old to new var_idxes mapping */
|
||||
for (unsigned minor = 0; minor < num_rows; minor++)
|
||||
{
|
||||
unsigned new_varidx = (major << 16) + minor;
|
||||
back_mapping.set (encoding.items.arrayZ[minor], new_varidx);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto _ : front_mapping.iter ())
|
||||
{
|
||||
unsigned old_varidx = _.first;
|
||||
unsigned *new_varidx;
|
||||
if (back_mapping.has (_.second, &new_varidx))
|
||||
varidx_map.set (old_varidx, *new_varidx);
|
||||
else
|
||||
varidx_map.set (old_varidx, HB_OT_LAYOUT_NO_VARIATIONS_INDEX);
|
||||
}
|
||||
return !varidx_map.in_error ();
|
||||
}
|
||||
|
||||
static int _cmp_row (const void *pa, const void *pb)
|
||||
{
|
||||
/* compare pointers of vectors(const hb_vector_t<int>*) that represent a row */
|
||||
const hb_vector_t<int>** a = (const hb_vector_t<int>**) pa;
|
||||
const hb_vector_t<int>** b = (const hb_vector_t<int>**) pb;
|
||||
|
||||
for (unsigned i = 0; i < (*b)->length; i++)
|
||||
{
|
||||
int va = (*a)->arrayZ[i];
|
||||
int vb = (*b)->arrayZ[i];
|
||||
if (va != vb)
|
||||
return va < vb ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace OT */
|
||||
|
||||
|
||||
|
|
|
@ -54,14 +54,14 @@ struct cvar
|
|||
|
||||
bool decompile_tuple_variations (unsigned axis_count,
|
||||
unsigned point_count,
|
||||
hb_blob_t *blob,
|
||||
bool is_gvar,
|
||||
const hb_map_t *axes_old_index_tag_map,
|
||||
TupleVariationData::tuple_variations_t& tuple_variations /* OUT */) const
|
||||
{
|
||||
hb_vector_t<unsigned> shared_indices;
|
||||
TupleVariationData::tuple_iterator_t iterator;
|
||||
unsigned var_data_length = tupleVariationData.get_size (axis_count);
|
||||
hb_bytes_t var_data_bytes = hb_bytes_t (reinterpret_cast<const char*> (get_tuple_var_data ()), var_data_length);
|
||||
hb_bytes_t var_data_bytes = blob->as_bytes ().sub_array (4);
|
||||
if (!TupleVariationData::get_tuple_iterator (var_data_bytes, axis_count, this,
|
||||
shared_indices, &iterator))
|
||||
return false;
|
||||
|
@ -143,19 +143,6 @@ struct cvar
|
|||
if (c->plan->all_axes_pinned)
|
||||
return_trace (false);
|
||||
|
||||
/* subset() for cvar is called by partial instancing only, we always pass
|
||||
* through cvar table in other cases */
|
||||
if (!c->plan->normalized_coords)
|
||||
{
|
||||
unsigned axis_count = c->plan->source->table.fvar->get_axis_count ();
|
||||
unsigned total_size = min_size + tupleVariationData.get_size (axis_count);
|
||||
char *out = c->serializer->allocate_size<char> (total_size);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
|
||||
hb_memcpy (out, this, total_size);
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
OT::TupleVariationData::tuple_variations_t tuple_variations;
|
||||
unsigned axis_count = c->plan->axes_old_index_tag_map.get_population ();
|
||||
|
||||
|
@ -164,7 +151,8 @@ struct cvar
|
|||
unsigned point_count = hb_blob_get_length (cvt_blob) / FWORD::static_size;
|
||||
hb_blob_destroy (cvt_blob);
|
||||
|
||||
if (!decompile_tuple_variations (axis_count, point_count, false,
|
||||
if (!decompile_tuple_variations (axis_count, point_count,
|
||||
c->source_blob, false,
|
||||
&(c->plan->axes_old_index_tag_map),
|
||||
tuple_variations))
|
||||
return_trace (false);
|
||||
|
|
|
@ -134,6 +134,36 @@ struct index_map_subset_plan_t
|
|||
}
|
||||
}
|
||||
|
||||
bool remap_after_instantiation (const hb_subset_plan_t *plan,
|
||||
const hb_map_t& varidx_map)
|
||||
{
|
||||
/* recalculate bit_count after remapping */
|
||||
outer_bit_count = 1;
|
||||
inner_bit_count = 1;
|
||||
|
||||
for (const auto &_ : plan->new_to_old_gid_list)
|
||||
{
|
||||
hb_codepoint_t new_gid = _.first;
|
||||
if (unlikely (new_gid >= map_count)) break;
|
||||
|
||||
uint32_t v = output_map.arrayZ[new_gid];
|
||||
uint32_t *new_varidx;
|
||||
if (!varidx_map.has (v, &new_varidx))
|
||||
return false;
|
||||
|
||||
output_map.arrayZ[new_gid] = *new_varidx;
|
||||
|
||||
unsigned outer = (*new_varidx) >> 16;
|
||||
unsigned bit_count = (outer == 0) ? 1 : hb_bit_storage (outer);
|
||||
outer_bit_count = hb_max (bit_count, outer_bit_count);
|
||||
|
||||
unsigned inner = (*new_varidx) & 0xFFFF;
|
||||
bit_count = (inner == 0) ? 1 : hb_bit_storage (inner);
|
||||
inner_bit_count = hb_max (bit_count, inner_bit_count);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned int get_inner_bit_count () const { return inner_bit_count; }
|
||||
unsigned int get_width () const { return ((outer_bit_count + inner_bit_count + 7) / 8); }
|
||||
unsigned int get_map_count () const { return map_count; }
|
||||
|
@ -211,6 +241,16 @@ struct hvarvvar_subset_plan_t
|
|||
index_map_plans[i].remap (index_maps[i], outer_map, inner_maps, plan);
|
||||
}
|
||||
|
||||
/* remap */
|
||||
bool remap_index_map_plans (const hb_subset_plan_t *plan,
|
||||
const hb_map_t& varidx_map)
|
||||
{
|
||||
for (unsigned i = 0; i < index_map_plans.length; i++)
|
||||
if (!index_map_plans[i].remap_after_instantiation (plan, varidx_map))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void fini ()
|
||||
{
|
||||
for (unsigned int i = 0; i < inner_sets.length; i++)
|
||||
|
@ -289,6 +329,9 @@ struct HVARVVAR
|
|||
bool _subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
if (c->plan->all_axes_pinned)
|
||||
return_trace (false);
|
||||
|
||||
hvarvvar_subset_plan_t hvar_plan;
|
||||
hb_vector_t<const DeltaSetIndexMap *>
|
||||
index_maps;
|
||||
|
@ -302,11 +345,37 @@ struct HVARVVAR
|
|||
out->version.major = 1;
|
||||
out->version.minor = 0;
|
||||
|
||||
if (unlikely (!out->varStore
|
||||
.serialize_serialize (c->serializer,
|
||||
hvar_plan.var_store,
|
||||
hvar_plan.inner_maps.as_array ())))
|
||||
if (c->plan->normalized_coords)
|
||||
{
|
||||
item_variations_t item_vars;
|
||||
if (!item_vars.instantiate (this+varStore, c->plan,
|
||||
advMap == 0 ? false : true,
|
||||
false, /* use_no_variation_idx = false */
|
||||
hvar_plan.inner_maps.as_array ()))
|
||||
return_trace (false);
|
||||
|
||||
if (!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 ()))
|
||||
return_trace (false);
|
||||
|
||||
/* if varstore is optimized, remap output_map */
|
||||
if (advMap)
|
||||
{
|
||||
if (!hvar_plan.remap_index_map_plans (c->plan, item_vars.get_varidx_map ()))
|
||||
return_trace (false);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (unlikely (!out->varStore
|
||||
.serialize_serialize (c->serializer,
|
||||
hvar_plan.var_store,
|
||||
hvar_plan.inner_maps.as_array ())))
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
return_trace (out->T::serialize_index_maps (c->serializer,
|
||||
hvar_plan.index_map_plans.as_array ()));
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#ifndef HB_OT_VAR_MVAR_TABLE_HH
|
||||
#define HB_OT_VAR_MVAR_TABLE_HH
|
||||
|
||||
#include "hb-ot-layout-common.hh"
|
||||
#include "hb-ot-var-common.hh"
|
||||
|
||||
|
||||
namespace OT {
|
||||
|
@ -41,6 +41,19 @@ struct VariationValueRecord
|
|||
return_trace (c->check_struct (this));
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c,
|
||||
const hb_map_t& varidx_map) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out = c->serializer->embed (*this);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
|
||||
hb_codepoint_t *new_idx;
|
||||
return_trace (c->serializer->check_assign (out->varIdx,
|
||||
(varidx_map.has (varIdx, &new_idx)) ? *new_idx : HB_OT_LAYOUT_NO_VARIATIONS_INDEX,
|
||||
HB_SERIALIZE_ERROR_INT_OVERFLOW));
|
||||
}
|
||||
|
||||
public:
|
||||
Tag valueTag; /* Four-byte tag identifying a font-wide measure. */
|
||||
VarIdx varIdx; /* Outer/inner index into VariationStore item. */
|
||||
|
@ -73,6 +86,47 @@ struct MVAR
|
|||
valueRecordSize));
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
#ifdef HB_NO_VAR
|
||||
return_trace (false);
|
||||
#endif
|
||||
|
||||
if (c->plan->all_axes_pinned)
|
||||
return_trace (false);
|
||||
|
||||
MVAR *out = c->serializer->start_embed (*this);
|
||||
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
|
||||
out->version = version;
|
||||
out->reserved = reserved;
|
||||
out->valueRecordSize = valueRecordSize;
|
||||
out->valueRecordCount = valueRecordCount;
|
||||
|
||||
item_variations_t item_vars;
|
||||
const VariationStore& src_var_store = this+varStore;
|
||||
|
||||
if (!item_vars.instantiate (src_var_store, c->plan))
|
||||
return_trace (false);
|
||||
|
||||
/* serialize varstore */
|
||||
if (!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 ()))
|
||||
return_trace (false);
|
||||
|
||||
/* serialize value records array */
|
||||
unsigned value_rec_count = valueRecordCount;
|
||||
const VariationValueRecord *record = reinterpret_cast<const VariationValueRecord*> (valuesZ.arrayZ);
|
||||
for (unsigned i = 0; i < value_rec_count; i++)
|
||||
{
|
||||
if (!record->subset (c, item_vars.get_varidx_map ())) return_trace (false);
|
||||
record++;
|
||||
}
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
float get_var (hb_tag_t tag,
|
||||
const int *coords, unsigned int coord_count) const
|
||||
{
|
||||
|
|
|
@ -42,10 +42,11 @@
|
|||
* priority of its children. The heap is stored in an array, with the
|
||||
* children of node i stored at indices 2i + 1 and 2i + 2.
|
||||
*/
|
||||
template <typename K>
|
||||
struct hb_priority_queue_t
|
||||
{
|
||||
private:
|
||||
typedef hb_pair_t<int64_t, unsigned> item_t;
|
||||
typedef hb_pair_t<K, unsigned> item_t;
|
||||
hb_vector_t<item_t> heap;
|
||||
|
||||
public:
|
||||
|
@ -57,7 +58,7 @@ struct hb_priority_queue_t
|
|||
#ifndef HB_OPTIMIZE_SIZE
|
||||
HB_ALWAYS_INLINE
|
||||
#endif
|
||||
void insert (int64_t priority, unsigned value)
|
||||
void insert (K priority, unsigned value)
|
||||
{
|
||||
heap.push (item_t (priority, value));
|
||||
if (unlikely (heap.in_error ())) return;
|
||||
|
|
|
@ -74,7 +74,6 @@ hb_subset_input_t::hb_subset_input_t ()
|
|||
HB_TAG ('p', 'r', 'e', 'p'),
|
||||
HB_TAG ('V', 'D', 'M', 'X'),
|
||||
HB_TAG ('D', 'S', 'I', 'G'),
|
||||
HB_TAG ('M', 'V', 'A', 'R'),
|
||||
};
|
||||
sets.no_subset_tables->add_array (default_no_subset_tables,
|
||||
ARRAY_LENGTH (default_no_subset_tables));
|
||||
|
|
|
@ -92,7 +92,7 @@ HB_SUBSET_PLAN_MEMBER (hb_map_t, colrv1_layers)
|
|||
HB_SUBSET_PLAN_MEMBER (hb_map_t, colr_palettes)
|
||||
|
||||
//Old layout item variation index -> (New varidx, delta) mapping
|
||||
HB_SUBSET_PLAN_MEMBER (hb_hashmap_t E(<unsigned, hb_pair_t E(<unsigned, int>)>), layout_variation_idx_delta_map)
|
||||
HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<unsigned, hb_pair_t E(<unsigned, int>)>), layout_variation_idx_delta_map)
|
||||
|
||||
//gdef varstore retained varidx mapping
|
||||
HB_SUBSET_PLAN_MEMBER (hb_vector_t<hb_inc_bimap_t>, gdef_varstore_inner_maps)
|
||||
|
@ -113,6 +113,8 @@ HB_SUBSET_PLAN_MEMBER (hb_map_t, axes_index_map)
|
|||
|
||||
//axis_index->axis_tag mapping in fvar axis array
|
||||
HB_SUBSET_PLAN_MEMBER (hb_map_t, axes_old_index_tag_map)
|
||||
//vector of retained axis tags in the order of axes given in the 'fvar' table
|
||||
HB_SUBSET_PLAN_MEMBER (hb_vector_t<hb_tag_t>, axis_tags)
|
||||
|
||||
//hmtx metrics map: new gid->(advance, lsb)
|
||||
HB_SUBSET_PLAN_MEMBER (mutable hb_hashmap_t E(<hb_codepoint_t, hb_pair_t E(<unsigned, int>)>), hmtx_map)
|
||||
|
|
|
@ -399,34 +399,20 @@ _collect_layout_variation_indices (hb_subset_plan_t* plan)
|
|||
return;
|
||||
}
|
||||
|
||||
const OT::VariationStore *var_store = nullptr;
|
||||
hb_set_t varidx_set;
|
||||
float *store_cache = nullptr;
|
||||
bool collect_delta = plan->pinned_at_default ? false : true;
|
||||
if (collect_delta)
|
||||
{
|
||||
if (gdef->has_var_store ())
|
||||
{
|
||||
var_store = &(gdef->get_var_store ());
|
||||
store_cache = var_store->create_cache ();
|
||||
}
|
||||
}
|
||||
|
||||
OT::hb_collect_variation_indices_context_t c (&varidx_set,
|
||||
&plan->layout_variation_idx_delta_map,
|
||||
plan->normalized_coords ? &(plan->normalized_coords) : nullptr,
|
||||
var_store,
|
||||
&plan->_glyphset_gsub,
|
||||
&plan->gpos_lookups,
|
||||
store_cache);
|
||||
&plan->gpos_lookups);
|
||||
gdef->collect_variation_indices (&c);
|
||||
|
||||
if (hb_ot_layout_has_positioning (plan->source))
|
||||
gpos->collect_variation_indices (&c);
|
||||
|
||||
var_store->destroy_cache (store_cache);
|
||||
|
||||
gdef->remap_layout_variation_indices (&varidx_set, &plan->layout_variation_idx_delta_map);
|
||||
gdef->remap_layout_variation_indices (&varidx_set,
|
||||
plan->normalized_coords,
|
||||
!plan->pinned_at_default,
|
||||
plan->all_axes_pinned,
|
||||
&plan->layout_variation_idx_delta_map);
|
||||
|
||||
unsigned subtable_count = gdef->has_var_store () ? gdef->get_var_store ().get_sub_table_count () : 0;
|
||||
_generate_varstore_inner_maps (varidx_set, subtable_count, plan->gdef_varstore_inner_maps);
|
||||
|
@ -927,6 +913,7 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
|
|||
{
|
||||
axis_not_pinned = true;
|
||||
plan->axes_index_map.set (old_axis_idx, new_axis_idx);
|
||||
plan->axis_tags.push (axis_tag);
|
||||
new_axis_idx++;
|
||||
}
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@
|
|||
#include "hb-ot-var-fvar-table.hh"
|
||||
#include "hb-ot-var-gvar-table.hh"
|
||||
#include "hb-ot-var-hvar-table.hh"
|
||||
#include "hb-ot-var-mvar-table.hh"
|
||||
#include "hb-ot-math-table.hh"
|
||||
#include "hb-ot-stat-table.hh"
|
||||
#include "hb-repacker.hh"
|
||||
|
@ -460,6 +461,8 @@ _dependencies_satisfied (hb_subset_plan_t *plan, hb_tag_t tag,
|
|||
case HB_OT_TAG_vmtx:
|
||||
case HB_OT_TAG_maxp:
|
||||
return !plan->normalized_coords || !pending_subset_tags.has (HB_OT_TAG_glyf);
|
||||
case HB_OT_TAG_GPOS:
|
||||
return !plan->normalized_coords || plan->all_axes_pinned || !pending_subset_tags.has (HB_OT_TAG_GDEF);
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
@ -514,6 +517,8 @@ _subset_table (hb_subset_plan_t *plan,
|
|||
case HB_OT_TAG_HVAR: return _subset<const OT::HVAR> (plan, buf);
|
||||
case HB_OT_TAG_VVAR: return _subset<const OT::VVAR> (plan, buf);
|
||||
#endif
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
case HB_OT_TAG_fvar:
|
||||
if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag);
|
||||
return _subset<const OT::fvar> (plan, buf);
|
||||
|
@ -523,6 +528,11 @@ _subset_table (hb_subset_plan_t *plan,
|
|||
case HB_OT_TAG_cvar:
|
||||
if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag);
|
||||
return _subset<const OT::cvar> (plan, buf);
|
||||
case HB_OT_TAG_MVAR:
|
||||
if (plan->user_axes_location.is_empty ()) return _passthrough (plan, tag);
|
||||
return _subset<const OT::MVAR> (plan, buf);
|
||||
#endif
|
||||
|
||||
case HB_OT_TAG_STAT:
|
||||
if (!plan->user_axes_location.is_empty ()) return _subset<const OT::STAT> (plan, buf);
|
||||
else return _passthrough (plan, tag);
|
||||
|
|
|
@ -460,7 +460,7 @@ struct hb_vector_t
|
|||
Type pop ()
|
||||
{
|
||||
if (!length) return Null (Type);
|
||||
Type v {std::move (arrayZ[length - 1])};
|
||||
Type v (std::move (arrayZ[length - 1]));
|
||||
arrayZ[length - 1].~Type ();
|
||||
length--;
|
||||
return v;
|
||||
|
|
|
@ -53,14 +53,14 @@ HB_BEGIN_DECLS
|
|||
*
|
||||
* The micro component of the library version available at compile-time.
|
||||
*/
|
||||
#define HB_VERSION_MICRO 1
|
||||
#define HB_VERSION_MICRO 2
|
||||
|
||||
/**
|
||||
* HB_VERSION_STRING:
|
||||
*
|
||||
* A string literal containing the library version available at compile-time.
|
||||
*/
|
||||
#define HB_VERSION_STRING "8.2.1"
|
||||
#define HB_VERSION_STRING "8.2.2"
|
||||
|
||||
/**
|
||||
* HB_VERSION_ATLEAST:
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
fs = import('fs')
|
||||
|
||||
hb_version_h = configure_file(
|
||||
command: [find_program('gen-hb-version.py'), meson.project_version(), '@OUTPUT@', '@INPUT@'],
|
||||
input: 'hb-version.h.in',
|
||||
|
@ -703,13 +705,14 @@ if get_option('tests').enabled()
|
|||
'test-serialize': ['test-serialize.cc', 'hb-static.cc'],
|
||||
'test-set': ['test-set.cc', 'hb-static.cc'],
|
||||
'test-tuple-varstore': ['test-tuple-varstore.cc', 'hb-subset-instancer-solver.cc', 'hb-static.cc'],
|
||||
'test-item-varstore': ['test-item-varstore.cc', 'hb-subset-instancer-solver.cc', 'hb-static.cc'],
|
||||
'test-use-table': 'test-use-table.cc',
|
||||
'test-vector': ['test-vector.cc', 'hb-static.cc'],
|
||||
}
|
||||
foreach name, source : noinst_programs
|
||||
executable(name, source,
|
||||
include_directories: incconfig,
|
||||
cpp_args: cpp_args,
|
||||
cpp_args: cpp_args + ['-UNDEBUG'],
|
||||
dependencies: libharfbuzz_dep,
|
||||
install: false,
|
||||
)
|
||||
|
@ -789,15 +792,95 @@ endif
|
|||
|
||||
have_gobject = conf.get('HAVE_GOBJECT', 0) == 1
|
||||
|
||||
# This code (especially PACKAGE_INIT) kept similar to what CMake's own
|
||||
# configure_package_config_file() generates, see
|
||||
# https://cmake.org/cmake/help/latest/module/CMakePackageConfigHelpers.html#command:configure_package_config_file
|
||||
|
||||
cmake_config = configuration_data()
|
||||
cmake_config.set('libdir', get_option('prefix') / get_option('libdir'))
|
||||
cmake_config.set('includedir', get_option('prefix') / get_option('includedir'))
|
||||
cmake_config.set('HB_LIBTOOL_VERSION_INFO', hb_libtool_version_info)
|
||||
cmake_config.set('have_gobject', '@0@'.format(have_gobject))
|
||||
cmake_config_dir = cmake_package_install_dir / 'harfbuzz'
|
||||
|
||||
have_fs_relative_to = meson.version().version_compare('>=1.3.0')
|
||||
|
||||
if not have_fs_relative_to
|
||||
relative_to = find_program('relative_to.py')
|
||||
endif
|
||||
|
||||
if have_fs_relative_to
|
||||
cmake_package_prefix_dir = fs.relative_to(get_option('prefix'), get_option('prefix') / cmake_config_dir)
|
||||
else
|
||||
cmake_package_prefix_dir = run_command(relative_to, get_option('prefix'), get_option('prefix') / cmake_config_dir, check: true).stdout().strip()
|
||||
endif
|
||||
|
||||
cmake_package_prefix_dir = '${CMAKE_CURRENT_LIST_DIR}/@0@'.format(cmake_package_prefix_dir)
|
||||
|
||||
# Make all the relevant paths relative to our prefix, so we can later append
|
||||
# them onto ${PACKAGE_PREFIX_DIR} to get the correct paths.
|
||||
|
||||
cmake_install_includedir = get_option('includedir')
|
||||
|
||||
if fs.is_absolute(cmake_install_includedir)
|
||||
if have_fs_relative_to
|
||||
cmake_install_includedir = fs.relative_to(cmake_install_includedir, get_option('prefix'))
|
||||
else
|
||||
cmake_install_includedir = run_command(relative_to, cmake_install_includedir, get_option('prefix'), check: true).stdout().strip()
|
||||
endif
|
||||
endif
|
||||
|
||||
cmake_install_libdir = get_option('libdir')
|
||||
|
||||
if fs.is_absolute(cmake_install_libdir)
|
||||
if have_fs_relative_to
|
||||
cmake_install_libdir = fs.relative_to(cmake_install_libdir, get_option('prefix'))
|
||||
else
|
||||
cmake_install_libdir = run_command(relative_to, cmake_install_libdir, get_option('prefix'), check: true).stdout().strip()
|
||||
endif
|
||||
endif
|
||||
|
||||
cmake_config.set('PACKAGE_INIT', '''
|
||||
get_filename_component(PACKAGE_PREFIX_DIR "@0@" ABSOLUTE)
|
||||
|
||||
macro(set_and_check _var _file)
|
||||
set(${_var} "${_file}")
|
||||
if(NOT EXISTS "${_file}")
|
||||
message(FATAL_ERROR "File or directory ${_file} referenced by variable ${_var} does not exist !")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(check_required_components _NAME)
|
||||
foreach(comp ${${_NAME}_FIND_COMPONENTS})
|
||||
if(NOT ${_NAME}_${comp}_FOUND)
|
||||
if(${_NAME}_FIND_REQUIRED_${comp})
|
||||
set(${_NAME}_FOUND FALSE)
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
endmacro()
|
||||
'''.format(cmake_package_prefix_dir))
|
||||
|
||||
cmake_config.set('PACKAGE_CMAKE_INSTALL_INCLUDEDIR', '${PACKAGE_PREFIX_DIR}/@0@'.format(cmake_install_includedir))
|
||||
cmake_config.set('PACKAGE_CMAKE_INSTALL_LIBDIR', '${PACKAGE_PREFIX_DIR}/@0@'.format(cmake_install_libdir))
|
||||
cmake_config.set('PACKAGE_INCLUDE_INSTALL_DIR', '${PACKAGE_PREFIX_DIR}/@0@/@1@'.format(cmake_install_includedir, meson.project_name()))
|
||||
cmake_config.set('HB_HAVE_GOBJECT', have_gobject ? 'YES' : 'NO')
|
||||
cmake_config.set('HB_LIBRARY_TYPE', get_option('default_library') == 'static' ? 'STATIC' : 'SHARED')
|
||||
|
||||
if get_option('default_library') == 'static'
|
||||
cmake_config.set('HB_LIB_PREFIX', '${CMAKE_STATIC_LIBRARY_PREFIX}')
|
||||
cmake_config.set('HB_LIB_SUFFIX', '${CMAKE_STATIC_LIBRARY_SUFFIX}')
|
||||
elif host_machine.system() == 'darwin'
|
||||
cmake_config.set('HB_LIB_PREFIX', '${CMAKE_SHARED_LIBRARY_PREFIX}')
|
||||
cmake_config.set('HB_LIB_SUFFIX', '.@0@.${CMAKE_SHARED_LIBRARY_SUFFIX}'.format(hb_so_version))
|
||||
elif host_machine.system() == 'windows'
|
||||
cmake_config.set('HB_LIB_PREFIX', '${CMAKE_IMPORT_LIBRARY_PREFIX}')
|
||||
cmake_config.set('HB_LIB_SUFFIX', '${CMAKE_IMPORT_LIBRARY_SUFFIX}')
|
||||
else
|
||||
cmake_config.set('HB_LIB_PREFIX', '${CMAKE_SHARED_LIBRARY_PREFIX}')
|
||||
cmake_config.set('HB_LIB_SUFFIX', '${CMAKE_SHARED_LIBRARY_SUFFIX}.@0@'.format(version))
|
||||
endif
|
||||
|
||||
configure_file(input: 'harfbuzz-config.cmake.in',
|
||||
output: 'harfbuzz-config.cmake',
|
||||
configuration: cmake_config,
|
||||
install_dir: get_option('libdir') / 'cmake' / 'harfbuzz',
|
||||
install_dir: cmake_config_dir,
|
||||
)
|
||||
|
||||
gobject_enums_c = []
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import sys
|
||||
from os import path
|
||||
|
||||
print(path.relpath(sys.argv[1], sys.argv[2]))
|
Загрузка…
Ссылка в новой задаче