commit
e215e4b51d
|
@ -0,0 +1,25 @@
|
||||||
|
name: arm
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ main ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ main ]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
arm-none-eabi:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
container:
|
||||||
|
image: devkitpro/devkitarm:latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Configure CMake
|
||||||
|
run: |
|
||||||
|
cmake -S . -B build \
|
||||||
|
-DCMAKE_TOOLCHAIN_FILE=${DEVKITPRO}/cmake/3DS.cmake
|
||||||
|
- name: Build
|
||||||
|
run: make CXX_FLAGS="-w -DHB_NO_MT"
|
||||||
|
working-directory: build
|
47
NEWS
47
NEWS
|
@ -1,3 +1,50 @@
|
||||||
|
Overview of changes leading to 5.3.1
|
||||||
|
Wednesday, October 19, 2022
|
||||||
|
====================================
|
||||||
|
- Subsetter repacker fixes. (Garret Rieger)
|
||||||
|
- Adjust Grapheme clusters for Katakana voiced sound marks. (Behdad Esfahbod)
|
||||||
|
- New “hb-subset” option “--preprocess-face”. (Garret Rieger)
|
||||||
|
|
||||||
|
|
||||||
|
Overview of changes leading to 5.3.0
|
||||||
|
Saturday, October 8, 2022
|
||||||
|
"Women, Life, Freedom" #MahsaAmini
|
||||||
|
====================================
|
||||||
|
- Don’t add glyphs from dropped MATH or COLR tables to the subset glyphs.
|
||||||
|
(Khaled Hosny)
|
||||||
|
- Map “rlig” to appropriate AAT feature selectors. (Jonathan Kew)
|
||||||
|
- Update USE data files to latest version. (David Corbett)
|
||||||
|
- Check “CBDT” extents first before outline tables, to help with fonts that
|
||||||
|
also include an empty “glyf” table. (Khaled Hosny)
|
||||||
|
- More work towards variable font instancing in the subsetter. (Qunxin Liu)
|
||||||
|
- Subsetter repacker improvements. (Garret Rieger)
|
||||||
|
- New API:
|
||||||
|
+hb_ot_layout_lookup_get_optical_bound()
|
||||||
|
+hb_face_builder_sort_tables()
|
||||||
|
|
||||||
|
|
||||||
|
Overview of changes leading to 5.2.0
|
||||||
|
Saturday, September 17, 2022
|
||||||
|
====================================
|
||||||
|
- Fix regressions in hb-ft font functions for FT_Face’s with transformation
|
||||||
|
matrix. (Behdad Esfahbod)
|
||||||
|
- The experimental hb-repacker API now supports splitting several GPOS subtable
|
||||||
|
types when needed. (Garret Rieger)
|
||||||
|
- The HarfBuzz extensions to OpenType font format are now opt-in behind
|
||||||
|
build-time flags. (Behdad Esfahbod)
|
||||||
|
- The experimental hb-subset variable fonts instantiation API can now
|
||||||
|
instantiate more font tables and arbitrary axis locations. (Qunxin Liu)
|
||||||
|
- Unicode 15 support. (David Corbett)
|
||||||
|
- Various documentation improvements. (Behdad Esfahbod, Matthias Clasen)
|
||||||
|
- The hb-view command line tool now detects WezTerm inline images support.
|
||||||
|
(Wez Furlong)
|
||||||
|
- Fix FreeType and ICU dependency lookup with meson. (Xavier Claessens)
|
||||||
|
|
||||||
|
- New API:
|
||||||
|
+HB_SCRIPT_KAWI
|
||||||
|
+HB_SCRIPT_NAG_MUNDARI
|
||||||
|
|
||||||
|
|
||||||
Overview of changes leading to 5.1.0
|
Overview of changes leading to 5.1.0
|
||||||
Sunday, July 31, 2022
|
Sunday, July 31, 2022
|
||||||
====================================
|
====================================
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
AC_PREREQ([2.64])
|
AC_PREREQ([2.64])
|
||||||
AC_INIT([HarfBuzz],
|
AC_INIT([HarfBuzz],
|
||||||
[5.1.0],
|
[5.3.1],
|
||||||
[https://github.com/harfbuzz/harfbuzz/issues/new],
|
[https://github.com/harfbuzz/harfbuzz/issues/new],
|
||||||
[harfbuzz],
|
[harfbuzz],
|
||||||
[http://harfbuzz.org/])
|
[http://harfbuzz.org/])
|
||||||
|
|
|
@ -117,6 +117,7 @@
|
||||||
<index id="api-index-full"><title>API Index</title><xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include></index>
|
<index id="api-index-full"><title>API Index</title><xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include></index>
|
||||||
<index id="deprecated-api-index" role="deprecated"><title>Index of deprecated API</title><xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include></index>
|
<index id="deprecated-api-index" role="deprecated"><title>Index of deprecated API</title><xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include></index>
|
||||||
|
|
||||||
|
<index id="api-index-5-3-0" role="5.3.0"><title>Index of new symbols in 5.3.0</title><xi:include href="xml/api-index-5.3.0.xml"><xi:fallback /></xi:include></index>
|
||||||
<index id="api-index-5-0-0" role="5.0.0"><title>Index of new symbols in 5.0.0</title><xi:include href="xml/api-index-5.0.0.xml"><xi:fallback /></xi:include></index>
|
<index id="api-index-5-0-0" role="5.0.0"><title>Index of new symbols in 5.0.0</title><xi:include href="xml/api-index-5.0.0.xml"><xi:fallback /></xi:include></index>
|
||||||
<index id="api-index-4-4-0" role="4.4.0"><title>Index of new symbols in 4.4.0</title><xi:include href="xml/api-index-4.4.0.xml"><xi:fallback /></xi:include></index>
|
<index id="api-index-4-4-0" role="4.4.0"><title>Index of new symbols in 4.4.0</title><xi:include href="xml/api-index-4.4.0.xml"><xi:fallback /></xi:include></index>
|
||||||
<index id="api-index-4-3-0" role="4.3.0"><title>Index of new symbols in 4.3.0</title><xi:include href="xml/api-index-4.3.0.xml"><xi:fallback /></xi:include></index>
|
<index id="api-index-4-3-0" role="4.3.0"><title>Index of new symbols in 4.3.0</title><xi:include href="xml/api-index-4.3.0.xml"><xi:fallback /></xi:include></index>
|
||||||
|
|
|
@ -285,6 +285,7 @@ hb_face_collect_variation_selectors
|
||||||
hb_face_collect_variation_unicodes
|
hb_face_collect_variation_unicodes
|
||||||
hb_face_builder_create
|
hb_face_builder_create
|
||||||
hb_face_builder_add_table
|
hb_face_builder_add_table
|
||||||
|
hb_face_builder_sort_tables
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
||||||
<SECTION>
|
<SECTION>
|
||||||
|
@ -554,6 +555,7 @@ hb_ot_layout_language_get_feature_tags
|
||||||
hb_ot_layout_language_get_required_feature
|
hb_ot_layout_language_get_required_feature
|
||||||
hb_ot_layout_lookup_collect_glyphs
|
hb_ot_layout_lookup_collect_glyphs
|
||||||
hb_ot_layout_lookup_get_glyph_alternates
|
hb_ot_layout_lookup_get_glyph_alternates
|
||||||
|
hb_ot_layout_lookup_get_optical_bound
|
||||||
hb_ot_layout_lookup_substitute_closure
|
hb_ot_layout_lookup_substitute_closure
|
||||||
hb_ot_layout_lookups_substitute_closure
|
hb_ot_layout_lookups_substitute_closure
|
||||||
hb_ot_layout_lookup_would_substitute
|
hb_ot_layout_lookup_would_substitute
|
||||||
|
@ -786,4 +788,7 @@ hb_subset_plan_old_to_new_glyph_mapping
|
||||||
hb_link_t
|
hb_link_t
|
||||||
hb_object_t
|
hb_object_t
|
||||||
hb_subset_repack_or_fail
|
hb_subset_repack_or_fail
|
||||||
|
hb_subset_preprocess
|
||||||
|
hb_subset_input_pin_axis_location
|
||||||
|
hb_subset_input_pin_axis_to_default
|
||||||
</SECTION>
|
</SECTION>
|
||||||
|
|
|
@ -54,6 +54,12 @@ There's four key pieces to the harfbuzz approach:
|
||||||
to calculate the final position of each subtable and then check if any offsets to it will
|
to calculate the final position of each subtable and then check if any offsets to it will
|
||||||
overflow.
|
overflow.
|
||||||
|
|
||||||
|
* Content Aware Preprocessing: if the overflow resolver is aware of the format of the underlying
|
||||||
|
tables (eg. GSUB, GPOS) then in some cases preprocessing can be done to increase the chance of
|
||||||
|
successfully packing the graph. For example for GSUB and GPOS we can preprocess the graph and
|
||||||
|
promote lookups to extension lookups (upgrades a 16 bit offset to 32 bits) or split large lookup
|
||||||
|
subtables into two or more pieces.
|
||||||
|
|
||||||
* Offset resolution strategies: given a particular occurrence of an overflow these strategies
|
* Offset resolution strategies: given a particular occurrence of an overflow these strategies
|
||||||
modify the graph to attempt to resolve the overflow.
|
modify the graph to attempt to resolve the overflow.
|
||||||
|
|
||||||
|
@ -64,6 +70,7 @@ def repack(graph):
|
||||||
graph.topological_sort()
|
graph.topological_sort()
|
||||||
|
|
||||||
if (graph.will_overflow())
|
if (graph.will_overflow())
|
||||||
|
preprocess(graph)
|
||||||
assign_spaces(graph)
|
assign_spaces(graph)
|
||||||
graph.topological_sort()
|
graph.topological_sort()
|
||||||
|
|
||||||
|
@ -185,6 +192,37 @@ The assign_spaces() step in the high level algorithm is responsible for identify
|
||||||
subgraphs and assigning unique spaces to each one. More information on the space assignment can be
|
subgraphs and assigning unique spaces to each one. More information on the space assignment can be
|
||||||
found in the next section.
|
found in the next section.
|
||||||
|
|
||||||
|
# Graph Preprocessing
|
||||||
|
|
||||||
|
For certain table types we can preprocess and modify the graph structure to reduce the occurences
|
||||||
|
of overflows. Currently the repacker implements preprocessing only for GPOS and GSUB tables.
|
||||||
|
|
||||||
|
## GSUB/GPOS Table Splitting
|
||||||
|
|
||||||
|
The GSUB/GPOS preprocessor scans each lookup subtable and determines if the subtable's children are
|
||||||
|
so large that no overflow resolution is possible (for example a single subtable that exceeds 65kb
|
||||||
|
cannot be pointed over). When such cases are detected table splitting is invoked:
|
||||||
|
|
||||||
|
* The subtable is first analyzed to determine the smallest number of split points that will allow
|
||||||
|
for successful offset overflow resolution.
|
||||||
|
|
||||||
|
* Then the subtable in the graph representation is modified to actually perform the split at the
|
||||||
|
previously computed split points. At a high level splits are done by inserting new subtables
|
||||||
|
which contain a subset of the data of the original subtable and then shrinking the original subtable.
|
||||||
|
|
||||||
|
Table splitting must be aware of the underlying format of each subtable type and thus needs custom
|
||||||
|
code for each subtable type. Currently subtable splitting is only supported for GPOS subtable types.
|
||||||
|
|
||||||
|
## GSUB/GPOS Extension Lookup Promotion
|
||||||
|
|
||||||
|
In GSUB/GPOS tables lookups can be regular lookups which use 16 bit offsets to the children subtables
|
||||||
|
or extension lookups which use 32 bit offsets to the children subtables. If the sub graph of all
|
||||||
|
regular lookups is too large then it can be difficult to find an overflow free configuration. This
|
||||||
|
can be remedied by promoting one or more regular lookups to extension lookups.
|
||||||
|
|
||||||
|
During preprocessing the graph is scanned to determine the size of the subgraph of regular lookups.
|
||||||
|
If the graph is found to be too big then the analysis finds a set of lookups to promote to reduce
|
||||||
|
the subgraph size. Lastly the graph is modified to convert those lookups to extension lookups.
|
||||||
|
|
||||||
# Offset Resolution Strategies
|
# Offset Resolution Strategies
|
||||||
|
|
||||||
|
@ -237,29 +275,20 @@ The harfbuzz repacker has tests defined using generic graphs: https://github.com
|
||||||
|
|
||||||
# Future Improvements
|
# Future Improvements
|
||||||
|
|
||||||
The above resolution strategies are not sufficient to resolve all overflows. For example consider
|
Currently for GPOS tables the repacker implementation is sufficient to handle both subsetting and the
|
||||||
the case where a single subtable is 65k and the graph structure requires an offset to point over it.
|
general case of font compilation repacking. However for GSUB the repacker is only sufficient for
|
||||||
|
subsetting related overflows. To enable general case repacking of GSUB, support for splitting of
|
||||||
|
GSUB subtables will need to be added. Other table types such as COLRv1 shouldn't require table
|
||||||
|
splitting due to the wide use of 24 bit offsets throughout the table.
|
||||||
|
|
||||||
The current harfbuzz implementation is suitable for the vast majority of subsetting related overflows.
|
Beyond subtable splitting there are a couple of "nice to have" improvements, but these are not required
|
||||||
Subsetting related overflows are typically easy to solve since all subsets are derived from a font
|
to support the general case:
|
||||||
that was originally overflow free. A more general purpose version of the algorithm suitable for font
|
|
||||||
creation purposes will likely need some additional offset resolution strategies:
|
* Extension demotion: currently extension promotion is supported but in some cases if the non-extension
|
||||||
|
subgraph is underfilled then packed size can be reduced by demoting extension lookups back to regular
|
||||||
|
lookups.
|
||||||
|
|
||||||
* Currently only children nodes are moved to resolve offsets. However, in many cases moving a parent
|
* Currently only children nodes are moved to resolve offsets. However, in many cases moving a parent
|
||||||
node closer to it's children will have less impact on the size of other offsets. Thus the algorithm
|
node closer to it's children will have less impact on the size of other offsets. Thus the algorithm
|
||||||
should use a heuristic (based on parent and child subtable sizes) to decide if the children's
|
should use a heuristic (based on parent and child subtable sizes) to decide if the children's
|
||||||
priority should be increased or the parent's priority decreased.
|
priority should be increased or the parent's priority decreased.
|
||||||
|
|
||||||
* Many subtables can be split into two smaller subtables without impacting the overall functionality.
|
|
||||||
This should be done when an overflow is the result of a very large table which can't be moved
|
|
||||||
to avoid offsets pointing over it.
|
|
||||||
|
|
||||||
* Lookup subtables in GSUB/GPOS can be upgraded to extension lookups which uses a 32 bit offset.
|
|
||||||
Overflows from a Lookup subtable to it's child should be resolved by converting to an extension
|
|
||||||
lookup.
|
|
||||||
|
|
||||||
Once additional resolution strategies are added to the algorithm it's likely that we'll need to
|
|
||||||
switch to using a [backtracking algorithm](https://en.wikipedia.org/wiki/Backtracking) to explore
|
|
||||||
the various combinations of resolution strategies until a non-overflowing combination is found. This
|
|
||||||
will require the ability to restore the graph to an earlier state. It's likely that using a stack
|
|
||||||
of undoable resolution commands could be used to accomplish this.
|
|
||||||
|
|
34
meson.build
34
meson.build
|
@ -1,6 +1,6 @@
|
||||||
project('harfbuzz', 'c', 'cpp',
|
project('harfbuzz', 'c', 'cpp',
|
||||||
meson_version: '>= 0.55.0',
|
meson_version: '>= 0.55.0',
|
||||||
version: '5.1.0',
|
version: '5.3.1',
|
||||||
default_options: [
|
default_options: [
|
||||||
'cpp_rtti=false', # Just to support msvc, we are passing -fno-exceptions also anyway
|
'cpp_rtti=false', # Just to support msvc, we are passing -fno-exceptions also anyway
|
||||||
'cpp_std=c++11',
|
'cpp_std=c++11',
|
||||||
|
@ -83,25 +83,39 @@ check_funcs = [
|
||||||
|
|
||||||
m_dep = cpp.find_library('m', required: false)
|
m_dep = cpp.find_library('m', required: false)
|
||||||
|
|
||||||
# https://github.com/harfbuzz/harfbuzz/pull/2498
|
|
||||||
freetype_dep = dependency(cpp.get_argument_syntax() == 'msvc' ? 'freetype' : 'freetype2',
|
# Try pkgconfig name
|
||||||
|
freetype_dep = dependency('freetype2', required: false)
|
||||||
|
if not freetype_dep.found()
|
||||||
|
# Try cmake name
|
||||||
|
freetype_dep = dependency('freetype', required: false)
|
||||||
|
endif
|
||||||
|
if not freetype_dep.found()
|
||||||
|
# Subproject fallback, `allow_fallback: true` means the fallback will be
|
||||||
|
# tried even if the freetype option is set to `auto`.
|
||||||
|
freetype_dep = dependency('freetype2',
|
||||||
required: get_option('freetype'),
|
required: get_option('freetype'),
|
||||||
default_options: ['harfbuzz=disabled'])
|
default_options: ['harfbuzz=disabled'],
|
||||||
|
allow_fallback: true)
|
||||||
|
endif
|
||||||
|
|
||||||
glib_dep = dependency('glib-2.0', required: get_option('glib'))
|
glib_dep = dependency('glib-2.0', required: get_option('glib'))
|
||||||
gobject_dep = dependency('gobject-2.0', required: get_option('gobject'))
|
gobject_dep = dependency('gobject-2.0', required: get_option('gobject'))
|
||||||
graphite2_dep = dependency('graphite2', required: get_option('graphite2'))
|
graphite2_dep = dependency('graphite2', required: get_option('graphite2'))
|
||||||
graphite_dep = dependency('graphite2', required: get_option('graphite'))
|
graphite_dep = dependency('graphite2', required: get_option('graphite'))
|
||||||
|
|
||||||
if cpp.get_argument_syntax() == 'msvc'
|
# Try pkgconfig name
|
||||||
|
icu_dep = dependency('icu-uc', required: false)
|
||||||
|
if not icu_dep.found()
|
||||||
|
# Try cmake name
|
||||||
icu_dep = dependency('ICU',
|
icu_dep = dependency('ICU',
|
||||||
required: get_option('icu'),
|
required: false,
|
||||||
components: 'uc',
|
components: 'uc',
|
||||||
method: 'cmake')
|
method: 'cmake')
|
||||||
else
|
endif
|
||||||
icu_dep = dependency('icu-uc',
|
if not icu_dep.found()
|
||||||
required: get_option('icu'),
|
# Subproject fallback if icu option is enabled
|
||||||
method: 'pkg-config')
|
icu_dep = dependency('icu-uc', required: get_option('icu'))
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if icu_dep.found() and icu_dep.type_name() == 'pkgconfig'
|
if icu_dep.found() and icu_dep.type_name() == 'pkgconfig'
|
||||||
|
|
|
@ -97,6 +97,19 @@ void AddGlyphs(unsigned num_glyphs_in_font,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Preprocess face and populate the subset accelerator on it to speed up
|
||||||
|
// the subsetting operations.
|
||||||
|
static hb_face_t* preprocess_face(hb_face_t* face)
|
||||||
|
{
|
||||||
|
#ifdef HB_EXPERIMENTAL_API
|
||||||
|
hb_face_t* new_face = hb_subset_preprocess(face);
|
||||||
|
hb_face_destroy(face);
|
||||||
|
return new_face;
|
||||||
|
#else
|
||||||
|
return face;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/* benchmark for subsetting a font */
|
/* benchmark for subsetting a font */
|
||||||
static void BM_subset (benchmark::State &state,
|
static void BM_subset (benchmark::State &state,
|
||||||
operation_t operation,
|
operation_t operation,
|
||||||
|
@ -110,6 +123,8 @@ static void BM_subset (benchmark::State &state,
|
||||||
assert (blob);
|
assert (blob);
|
||||||
face = hb_face_create (blob, 0);
|
face = hb_face_create (blob, 0);
|
||||||
hb_blob_destroy (blob);
|
hb_blob_destroy (blob);
|
||||||
|
|
||||||
|
face = preprocess_face (face);
|
||||||
}
|
}
|
||||||
|
|
||||||
hb_subset_input_t* input = hb_subset_input_create_or_fail ();
|
hb_subset_input_t* input = hb_subset_input_create_or_fail ();
|
||||||
|
|
|
@ -341,6 +341,7 @@ HB_SUBSET_sources = \
|
||||||
hb-subset-cff2.hh \
|
hb-subset-cff2.hh \
|
||||||
hb-subset-input.cc \
|
hb-subset-input.cc \
|
||||||
hb-subset-input.hh \
|
hb-subset-input.hh \
|
||||||
|
hb-subset-accelerator.hh \
|
||||||
hb-subset-plan.cc \
|
hb-subset-plan.cc \
|
||||||
hb-subset-plan.hh \
|
hb-subset-plan.hh \
|
||||||
hb-subset-repacker.cc \
|
hb-subset-repacker.cc \
|
||||||
|
|
|
@ -39,7 +39,7 @@ struct GPOS : GSUBGPOS
|
||||||
|
|
||||||
bool subset (hb_subset_context_t *c) const
|
bool subset (hb_subset_context_t *c) const
|
||||||
{
|
{
|
||||||
hb_subset_layout_context_t l (c, tableTag, c->plan->gpos_lookups, c->plan->gpos_langsys, c->plan->gpos_features);
|
hb_subset_layout_context_t l (c, tableTag);
|
||||||
return GSUBGPOS::subset<PosLookup> (&l);
|
return GSUBGPOS::subset<PosLookup> (&l);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -80,6 +80,24 @@ struct SinglePosFormat1
|
||||||
return_trace (true);
|
return_trace (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
position_single (hb_font_t *font,
|
||||||
|
hb_direction_t direction,
|
||||||
|
hb_codepoint_t gid,
|
||||||
|
hb_glyph_position_t &pos) const
|
||||||
|
{
|
||||||
|
unsigned int index = (this+coverage).get_coverage (gid);
|
||||||
|
if (likely (index == NOT_COVERED)) return false;
|
||||||
|
|
||||||
|
/* This is ugly... */
|
||||||
|
hb_buffer_t buffer;
|
||||||
|
buffer.props.direction = direction;
|
||||||
|
OT::hb_ot_apply_context_t c (1, font, &buffer);
|
||||||
|
|
||||||
|
valueFormat.apply_value (&c, this, values, pos);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Iterator,
|
template<typename Iterator,
|
||||||
typename SrcLookup,
|
typename SrcLookup,
|
||||||
hb_requires (hb_is_iterator (Iterator))>
|
hb_requires (hb_is_iterator (Iterator))>
|
||||||
|
|
|
@ -68,7 +68,7 @@ struct SinglePosFormat2
|
||||||
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
|
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
|
||||||
if (likely (index == NOT_COVERED)) return_trace (false);
|
if (likely (index == NOT_COVERED)) return_trace (false);
|
||||||
|
|
||||||
if (likely (index >= valueCount)) return_trace (false);
|
if (unlikely (index >= valueCount)) return_trace (false);
|
||||||
|
|
||||||
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
|
if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
|
||||||
{
|
{
|
||||||
|
@ -92,6 +92,28 @@ struct SinglePosFormat2
|
||||||
return_trace (true);
|
return_trace (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
position_single (hb_font_t *font,
|
||||||
|
hb_direction_t direction,
|
||||||
|
hb_codepoint_t gid,
|
||||||
|
hb_glyph_position_t &pos) const
|
||||||
|
{
|
||||||
|
unsigned int index = (this+coverage).get_coverage (gid);
|
||||||
|
if (likely (index == NOT_COVERED)) return false;
|
||||||
|
if (unlikely (index >= valueCount)) return false;
|
||||||
|
|
||||||
|
/* This is ugly... */
|
||||||
|
hb_buffer_t buffer;
|
||||||
|
buffer.props.direction = direction;
|
||||||
|
OT::hb_ot_apply_context_t c (1, font, &buffer);
|
||||||
|
|
||||||
|
valueFormat.apply_value (&c, this,
|
||||||
|
&values[index * valueFormat.get_len ()],
|
||||||
|
pos);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename Iterator,
|
template<typename Iterator,
|
||||||
typename SrcLookup,
|
typename SrcLookup,
|
||||||
hb_requires (hb_is_iterator (Iterator))>
|
hb_requires (hb_is_iterator (Iterator))>
|
||||||
|
|
|
@ -27,7 +27,7 @@ struct GSUB : GSUBGPOS
|
||||||
|
|
||||||
bool subset (hb_subset_context_t *c) const
|
bool subset (hb_subset_context_t *c) const
|
||||||
{
|
{
|
||||||
hb_subset_layout_context_t l (c, tableTag, c->plan->gsub_lookups, c->plan->gsub_langsys, c->plan->gsub_features);
|
hb_subset_layout_context_t l (c, tableTag);
|
||||||
return GSUBGPOS::subset<SubstLookup> (&l);
|
return GSUBGPOS::subset<SubstLookup> (&l);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -118,7 +118,7 @@ struct Ligature
|
||||||
match_positions[i] += delta;
|
match_positions[i] += delta;
|
||||||
if (i)
|
if (i)
|
||||||
*p++ = ',';
|
*p++ = ',';
|
||||||
sprintf (p, "%u", match_positions[i]);
|
snprintf (p, sizeof(buf), "%u", match_positions[i]);
|
||||||
p += strlen(p);
|
p += strlen(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,7 +117,7 @@ struct Sequence
|
||||||
{
|
{
|
||||||
if (buf < p)
|
if (buf < p)
|
||||||
*p++ = ',';
|
*p++ = ',';
|
||||||
sprintf (p, "%u", i);
|
snprintf (p, sizeof(buf), "%u", i);
|
||||||
p += strlen(p);
|
p += strlen(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -57,7 +57,7 @@ struct SingleSubstFormat1_3
|
||||||
hb_codepoint_t max_before = intersection.get_max ();
|
hb_codepoint_t max_before = intersection.get_max ();
|
||||||
hb_codepoint_t min_after = (min_before + d) & mask;
|
hb_codepoint_t min_after = (min_before + d) & mask;
|
||||||
hb_codepoint_t max_after = (max_before + d) & mask;
|
hb_codepoint_t max_after = (max_before + d) & mask;
|
||||||
if (pop >= max_before - min_before &&
|
if (intersection.get_population () == max_before - min_before + 1 &&
|
||||||
((min_before <= min_after && min_after <= max_before) ||
|
((min_before <= min_after && min_after <= max_before) ||
|
||||||
(min_before <= max_after && max_after <= max_before)))
|
(min_before <= max_after && max_after <= max_before)))
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -16,6 +16,11 @@ struct glyf_accelerator_t;
|
||||||
namespace glyf_impl {
|
namespace glyf_impl {
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef HB_GLYF_MAX_POINTS
|
||||||
|
#define HB_GLYF_MAX_POINTS 10000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
enum phantom_point_index_t
|
enum phantom_point_index_t
|
||||||
{
|
{
|
||||||
PHANTOM_LEFT = 0,
|
PHANTOM_LEFT = 0,
|
||||||
|
@ -102,17 +107,19 @@ struct Glyph
|
||||||
hb_bytes_t &dest_bytes /* OUT */) const
|
hb_bytes_t &dest_bytes /* OUT */) const
|
||||||
{
|
{
|
||||||
GlyphHeader *glyph_header = nullptr;
|
GlyphHeader *glyph_header = nullptr;
|
||||||
if (all_points.length > 4)
|
if (type != EMPTY && all_points.length > 4)
|
||||||
{
|
{
|
||||||
glyph_header = (GlyphHeader *) hb_calloc (1, GlyphHeader::static_size);
|
glyph_header = (GlyphHeader *) hb_calloc (1, GlyphHeader::static_size);
|
||||||
if (unlikely (!glyph_header)) return false;
|
if (unlikely (!glyph_header)) return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int xMin, xMax;
|
int xMin = 0, xMax = 0;
|
||||||
|
int yMin = 0, yMax = 0;
|
||||||
|
if (all_points.length > 4)
|
||||||
|
{
|
||||||
xMin = xMax = roundf (all_points[0].x);
|
xMin = xMax = roundf (all_points[0].x);
|
||||||
|
|
||||||
int yMin, yMax;
|
|
||||||
yMin = yMax = roundf (all_points[0].y);
|
yMin = yMax = roundf (all_points[0].y);
|
||||||
|
}
|
||||||
|
|
||||||
for (unsigned i = 1; i < all_points.length - 4; i++)
|
for (unsigned i = 1; i < all_points.length - 4; i++)
|
||||||
{
|
{
|
||||||
|
@ -128,7 +135,7 @@ struct Glyph
|
||||||
|
|
||||||
/*for empty glyphs: all_points only include phantom points.
|
/*for empty glyphs: all_points only include phantom points.
|
||||||
*just update metrics and then return */
|
*just update metrics and then return */
|
||||||
if (all_points.length == 4)
|
if (!glyph_header)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
glyph_header->numberOfContours = header->numberOfContours;
|
glyph_header->numberOfContours = header->numberOfContours;
|
||||||
|
@ -145,10 +152,17 @@ struct Glyph
|
||||||
hb_font_t *font,
|
hb_font_t *font,
|
||||||
const glyf_accelerator_t &glyf,
|
const glyf_accelerator_t &glyf,
|
||||||
hb_bytes_t &dest_start, /* IN/OUT */
|
hb_bytes_t &dest_start, /* IN/OUT */
|
||||||
hb_bytes_t &dest_end /* OUT */) const
|
hb_bytes_t &dest_end /* OUT */)
|
||||||
{
|
{
|
||||||
contour_point_vector_t all_points, deltas;
|
contour_point_vector_t all_points, deltas;
|
||||||
get_points (font, glyf, all_points, &deltas, false);
|
if (!get_points (font, glyf, all_points, &deltas, false, false))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// .notdef, set type to empty so we only update metrics and don't compile bytes for
|
||||||
|
// it
|
||||||
|
if (gid == 0 &&
|
||||||
|
!(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
|
||||||
|
type = EMPTY;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case COMPOSITE:
|
case COMPOSITE:
|
||||||
|
@ -171,7 +185,12 @@ struct Glyph
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return compile_header_bytes (plan, all_points, dest_start);
|
if (!compile_header_bytes (plan, all_points, dest_start))
|
||||||
|
{
|
||||||
|
dest_end.fini ();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -182,6 +201,7 @@ struct Glyph
|
||||||
bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
|
bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
|
||||||
contour_point_vector_t &all_points /* OUT */,
|
contour_point_vector_t &all_points /* OUT */,
|
||||||
contour_point_vector_t *deltas = nullptr, /* OUT */
|
contour_point_vector_t *deltas = nullptr, /* OUT */
|
||||||
|
bool shift_points_hori = true,
|
||||||
bool use_my_metrics = true,
|
bool use_my_metrics = true,
|
||||||
bool phantom_only = false,
|
bool phantom_only = false,
|
||||||
unsigned int depth = 0) const
|
unsigned int depth = 0) const
|
||||||
|
@ -238,8 +258,7 @@ struct Glyph
|
||||||
if (deltas != nullptr && depth == 0 && type == COMPOSITE)
|
if (deltas != nullptr && depth == 0 && type == COMPOSITE)
|
||||||
{
|
{
|
||||||
if (unlikely (!deltas->resize (points.length))) return false;
|
if (unlikely (!deltas->resize (points.length))) return false;
|
||||||
for (unsigned i = 0 ; i < points.length; i++)
|
deltas->copy_vector (points);
|
||||||
deltas->arrayZ[i] = points.arrayZ[i];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef HB_NO_VAR
|
#ifndef HB_NO_VAR
|
||||||
|
@ -271,14 +290,9 @@ struct Glyph
|
||||||
comp_points.reset ();
|
comp_points.reset ();
|
||||||
if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
|
if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
|
||||||
.get_points (font, glyf_accelerator, comp_points,
|
.get_points (font, glyf_accelerator, comp_points,
|
||||||
deltas, use_my_metrics, phantom_only, depth + 1)))
|
deltas, shift_points_hori, use_my_metrics, phantom_only, depth + 1)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/* Copy phantom points from component if USE_MY_METRICS flag set */
|
|
||||||
if (use_my_metrics && item.is_use_my_metrics ())
|
|
||||||
for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
|
|
||||||
phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
|
|
||||||
|
|
||||||
/* Apply component transformation & translation */
|
/* Apply component transformation & translation */
|
||||||
item.transform_points (comp_points);
|
item.transform_points (comp_points);
|
||||||
|
|
||||||
|
@ -299,6 +313,14 @@ struct Glyph
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Copy phantom points from component if USE_MY_METRICS flag set */
|
||||||
|
if (use_my_metrics && item.is_use_my_metrics ())
|
||||||
|
for (unsigned int i = 0; i < PHANTOM_COUNT; i++)
|
||||||
|
phantoms[i] = comp_points[comp_points.length - PHANTOM_COUNT + i];
|
||||||
|
|
||||||
|
if (all_points.length > HB_GLYF_MAX_POINTS)
|
||||||
|
return false;
|
||||||
|
|
||||||
all_points.extend (comp_points.sub_array (0, comp_points.length - PHANTOM_COUNT));
|
all_points.extend (comp_points.sub_array (0, comp_points.length - PHANTOM_COUNT));
|
||||||
|
|
||||||
comp_index++;
|
comp_index++;
|
||||||
|
@ -310,7 +332,7 @@ struct Glyph
|
||||||
all_points.extend (phantoms);
|
all_points.extend (phantoms);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (depth == 0) /* Apply at top level */
|
if (depth == 0 && shift_points_hori) /* Apply at top level */
|
||||||
{
|
{
|
||||||
/* Undocumented rasterizer behavior:
|
/* Undocumented rasterizer behavior:
|
||||||
* Shift points horizontally by the updated left side bearing
|
* Shift points horizontally by the updated left side bearing
|
||||||
|
@ -332,8 +354,14 @@ struct Glyph
|
||||||
|
|
||||||
hb_bytes_t get_bytes () const { return bytes; }
|
hb_bytes_t get_bytes () const { return bytes; }
|
||||||
|
|
||||||
Glyph (hb_bytes_t bytes_ = hb_bytes_t (),
|
Glyph () : bytes (),
|
||||||
hb_codepoint_t gid_ = (hb_codepoint_t) -1) : bytes (bytes_),
|
header (bytes.as<GlyphHeader> ()),
|
||||||
|
gid (-1),
|
||||||
|
type(EMPTY)
|
||||||
|
{}
|
||||||
|
|
||||||
|
Glyph (hb_bytes_t bytes_,
|
||||||
|
hb_codepoint_t gid_ = (unsigned) -1) : bytes (bytes_),
|
||||||
header (bytes.as<GlyphHeader> ()),
|
header (bytes.as<GlyphHeader> ()),
|
||||||
gid (gid_)
|
gid (gid_)
|
||||||
{
|
{
|
||||||
|
|
|
@ -271,31 +271,29 @@ struct SimpleGlyph
|
||||||
}
|
}
|
||||||
//convert absolute values to relative values
|
//convert absolute values to relative values
|
||||||
unsigned num_points = all_points.length - 4;
|
unsigned num_points = all_points.length - 4;
|
||||||
hb_vector_t<hb_pair_t<int, int>> deltas;
|
|
||||||
deltas.resize (num_points);
|
|
||||||
|
|
||||||
for (unsigned i = 0; i < num_points; i++)
|
|
||||||
{
|
|
||||||
deltas[i].first = i == 0 ? roundf (all_points[i].x) : roundf (all_points[i].x) - roundf (all_points[i-1].x);
|
|
||||||
deltas[i].second = i == 0 ? roundf (all_points[i].y) : roundf (all_points[i].y) - roundf (all_points[i-1].y);
|
|
||||||
}
|
|
||||||
|
|
||||||
hb_vector_t<uint8_t> flags, x_coords, y_coords;
|
hb_vector_t<uint8_t> flags, x_coords, y_coords;
|
||||||
flags.alloc (num_points);
|
if (unlikely (!flags.alloc (num_points))) return false;
|
||||||
x_coords.alloc (2*num_points);
|
if (unlikely (!x_coords.alloc (2*num_points))) return false;
|
||||||
y_coords.alloc (2*num_points);
|
if (unlikely (!y_coords.alloc (2*num_points))) return false;
|
||||||
|
|
||||||
uint8_t lastflag = 0, repeat = 0;
|
uint8_t lastflag = 0, repeat = 0;
|
||||||
|
int prev_x = 0.f, prev_y = 0.f;
|
||||||
|
|
||||||
for (unsigned i = 0; i < num_points; i++)
|
for (unsigned i = 0; i < num_points; i++)
|
||||||
{
|
{
|
||||||
uint8_t flag = all_points[i].flag;
|
uint8_t flag = all_points[i].flag;
|
||||||
flag &= FLAG_ON_CURVE + FLAG_OVERLAP_SIMPLE;
|
flag &= FLAG_ON_CURVE + FLAG_OVERLAP_SIMPLE;
|
||||||
|
|
||||||
encode_coord (deltas[i].first, flag, FLAG_X_SHORT, FLAG_X_SAME, x_coords);
|
float cur_x = roundf (all_points[i].x);
|
||||||
encode_coord (deltas[i].second, flag, FLAG_Y_SHORT, FLAG_Y_SAME, y_coords);
|
float cur_y = roundf (all_points[i].y);
|
||||||
|
encode_coord (cur_x - prev_x, flag, FLAG_X_SHORT, FLAG_X_SAME, x_coords);
|
||||||
|
encode_coord (cur_y - prev_y, flag, FLAG_Y_SHORT, FLAG_Y_SAME, y_coords);
|
||||||
if (i == 0) lastflag = flag + 1; //make lastflag != flag for the first point
|
if (i == 0) lastflag = flag + 1; //make lastflag != flag for the first point
|
||||||
encode_flag (flag, repeat, lastflag, flags);
|
encode_flag (flag, repeat, lastflag, flags);
|
||||||
|
|
||||||
|
prev_x = cur_x;
|
||||||
|
prev_y = cur_y;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned len_before_instrs = 2 * header.numberOfContours + 2;
|
unsigned len_before_instrs = 2 * header.numberOfContours + 2;
|
||||||
|
|
|
@ -14,7 +14,6 @@ namespace glyf_impl {
|
||||||
|
|
||||||
struct SubsetGlyph
|
struct SubsetGlyph
|
||||||
{
|
{
|
||||||
hb_codepoint_t new_gid;
|
|
||||||
hb_codepoint_t old_gid;
|
hb_codepoint_t old_gid;
|
||||||
Glyph source_glyph;
|
Glyph source_glyph;
|
||||||
hb_bytes_t dest_start; /* region of source_glyph to copy first */
|
hb_bytes_t dest_start; /* region of source_glyph to copy first */
|
||||||
|
|
|
@ -72,10 +72,13 @@ struct glyf
|
||||||
if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false);
|
if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false);
|
||||||
|
|
||||||
hb_vector_t<glyf_impl::SubsetGlyph> glyphs;
|
hb_vector_t<glyf_impl::SubsetGlyph> glyphs;
|
||||||
_populate_subset_glyphs (c->plan, &glyphs);
|
_populate_subset_glyphs (c->plan, glyphs);
|
||||||
|
|
||||||
if (!c->plan->pinned_at_default)
|
if (!c->plan->pinned_at_default)
|
||||||
_compile_subset_glyphs_with_deltas (c->plan, &glyphs);
|
{
|
||||||
|
if (!_compile_subset_glyphs_with_deltas (c->plan, &glyphs))
|
||||||
|
return_trace (false);
|
||||||
|
}
|
||||||
|
|
||||||
auto padded_offsets =
|
auto padded_offsets =
|
||||||
+ hb_iter (glyphs)
|
+ hb_iter (glyphs)
|
||||||
|
@ -105,9 +108,9 @@ struct glyf
|
||||||
|
|
||||||
void
|
void
|
||||||
_populate_subset_glyphs (const hb_subset_plan_t *plan,
|
_populate_subset_glyphs (const hb_subset_plan_t *plan,
|
||||||
hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const;
|
hb_vector_t<glyf_impl::SubsetGlyph> &glyphs /* OUT */) const;
|
||||||
|
|
||||||
void
|
bool
|
||||||
_compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan,
|
_compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan,
|
||||||
hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const;
|
hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const;
|
||||||
|
|
||||||
|
@ -180,7 +183,7 @@ struct glyf_accelerator_t
|
||||||
contour_point_vector_t all_points;
|
contour_point_vector_t all_points;
|
||||||
|
|
||||||
bool phantom_only = !consumer.is_consuming_contour_points ();
|
bool phantom_only = !consumer.is_consuming_contour_points ();
|
||||||
if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, true, phantom_only)))
|
if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, true, true, phantom_only)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (consumer.is_consuming_contour_points ())
|
if (consumer.is_consuming_contour_points ())
|
||||||
|
@ -374,44 +377,43 @@ struct glyf_accelerator_t
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan,
|
glyf::_populate_subset_glyphs (const hb_subset_plan_t *plan,
|
||||||
hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const
|
hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const
|
||||||
{
|
{
|
||||||
OT::glyf_accelerator_t glyf (plan->source);
|
OT::glyf_accelerator_t glyf (plan->source);
|
||||||
|
unsigned num_glyphs = plan->num_output_glyphs ();
|
||||||
|
if (!glyphs.resize (num_glyphs)) return;
|
||||||
|
|
||||||
+ hb_range (plan->num_output_glyphs ())
|
for (auto p : plan->glyph_map->iter ())
|
||||||
| hb_map ([&] (hb_codepoint_t new_gid)
|
|
||||||
{
|
{
|
||||||
glyf_impl::SubsetGlyph subset_glyph = {0};
|
unsigned new_gid = p.second;
|
||||||
subset_glyph.new_gid = new_gid;
|
glyf_impl::SubsetGlyph& subset_glyph = glyphs.arrayZ[new_gid];
|
||||||
|
subset_glyph.old_gid = p.first;
|
||||||
|
|
||||||
/* should never fail: all old gids should be mapped */
|
if (unlikely (new_gid == 0 &&
|
||||||
if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid))
|
!(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) &&
|
||||||
return subset_glyph;
|
plan->pinned_at_default)
|
||||||
|
|
||||||
if (new_gid == 0 &&
|
|
||||||
!(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
|
|
||||||
subset_glyph.source_glyph = glyf_impl::Glyph ();
|
subset_glyph.source_glyph = glyf_impl::Glyph ();
|
||||||
else
|
else
|
||||||
subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true);
|
subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true);
|
||||||
|
|
||||||
if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
|
if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
|
||||||
subset_glyph.drop_hints_bytes ();
|
subset_glyph.drop_hints_bytes ();
|
||||||
else
|
else
|
||||||
subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
|
subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
|
||||||
return subset_glyph;
|
}
|
||||||
})
|
|
||||||
| hb_sink (glyphs)
|
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void
|
inline bool
|
||||||
glyf::_compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan,
|
glyf::_compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan,
|
||||||
hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const
|
hb_vector_t<glyf_impl::SubsetGlyph> *glyphs /* OUT */) const
|
||||||
{
|
{
|
||||||
OT::glyf_accelerator_t glyf (plan->source);
|
OT::glyf_accelerator_t glyf (plan->source);
|
||||||
hb_font_t *font = hb_font_create (plan->source);
|
hb_font_t *font = hb_font_create (plan->source);
|
||||||
|
if (unlikely (!font)) return false;
|
||||||
|
|
||||||
hb_vector_t<hb_variation_t> vars;
|
hb_vector_t<hb_variation_t> vars;
|
||||||
vars.alloc (plan->user_axes_location->get_population ());
|
if (unlikely (!vars.alloc (plan->user_axes_location->get_population ())))
|
||||||
|
return false;
|
||||||
|
|
||||||
for (auto _ : *plan->user_axes_location)
|
for (auto _ : *plan->user_axes_location)
|
||||||
{
|
{
|
||||||
|
@ -423,9 +425,16 @@ glyf::_compile_subset_glyphs_with_deltas (const hb_subset_plan_t *plan,
|
||||||
|
|
||||||
hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location->get_population ());
|
hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location->get_population ());
|
||||||
for (auto& subset_glyph : *glyphs)
|
for (auto& subset_glyph : *glyphs)
|
||||||
const_cast<glyf_impl::SubsetGlyph &> (subset_glyph).compile_bytes_with_deltas (plan, font, glyf);
|
{
|
||||||
|
if (!const_cast<glyf_impl::SubsetGlyph &> (subset_glyph).compile_bytes_with_deltas (plan, font, glyf))
|
||||||
|
{
|
||||||
|
hb_font_destroy (font);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hb_font_destroy (font);
|
hb_font_destroy (font);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ for soname in ['harfbuzz', 'harfbuzz-subset', 'harfbuzz-icu', 'harfbuzz-gobject'
|
||||||
symprefix = '_' if suffix == 'dylib' else ''
|
symprefix = '_' if suffix == 'dylib' else ''
|
||||||
|
|
||||||
EXPORTED_SYMBOLS = [s.split ()[2]
|
EXPORTED_SYMBOLS = [s.split ()[2]
|
||||||
for s in re.findall (r'^.+ [BCDGIRST] .+$', subprocess.check_output (nm.split() + [so]).decode ('utf-8'), re.MULTILINE)
|
for s in re.findall (r'^.+ [BCDGIRSTu] .+$', subprocess.check_output (nm.split() + [so]).decode ('utf-8'), re.MULTILINE)
|
||||||
if not re.match (r'.* %s(%s)\b' % (symprefix, IGNORED_SYMBOLS), s)]
|
if not re.match (r'.* %s(%s)\b' % (symprefix, IGNORED_SYMBOLS), s)]
|
||||||
|
|
||||||
# run again c++filt also if is available
|
# run again c++filt also if is available
|
||||||
|
|
|
@ -21,7 +21,9 @@ if '--experimental-api' not in sys.argv:
|
||||||
experimental_symbols = \
|
experimental_symbols = \
|
||||||
"""hb_subset_repack_or_fail
|
"""hb_subset_repack_or_fail
|
||||||
hb_subset_input_pin_axis_location
|
hb_subset_input_pin_axis_location
|
||||||
hb_subset_input_pin_axis_to_default""".splitlines ()
|
hb_subset_input_pin_axis_to_default
|
||||||
|
hb_subset_preprocess
|
||||||
|
""".splitlines ()
|
||||||
symbols = [x for x in symbols if x not in experimental_symbols]
|
symbols = [x for x in symbols if x not in experimental_symbols]
|
||||||
symbols = "\n".join (symbols)
|
symbols = "\n".join (symbols)
|
||||||
|
|
||||||
|
|
|
@ -134,6 +134,7 @@ property_names = [
|
||||||
'Number_Joiner',
|
'Number_Joiner',
|
||||||
'Number',
|
'Number',
|
||||||
'Brahmi_Joining_Number',
|
'Brahmi_Joining_Number',
|
||||||
|
'Symbol_Modifier',
|
||||||
'Hieroglyph',
|
'Hieroglyph',
|
||||||
'Hieroglyph_Joiner',
|
'Hieroglyph_Joiner',
|
||||||
'Hieroglyph_Segment_Begin',
|
'Hieroglyph_Segment_Begin',
|
||||||
|
@ -214,8 +215,7 @@ def is_CONS_MED(U, UISC, UDI, UGC, AJT):
|
||||||
return (UISC == Consonant_Medial and UGC != Lo or
|
return (UISC == Consonant_Medial and UGC != Lo or
|
||||||
UISC == Consonant_Initial_Postfixed)
|
UISC == Consonant_Initial_Postfixed)
|
||||||
def is_CONS_MOD(U, UISC, UDI, UGC, AJT):
|
def is_CONS_MOD(U, UISC, UDI, UGC, AJT):
|
||||||
return (UISC in [Nukta, Gemination_Mark, Consonant_Killer] and
|
return UISC in [Nukta, Gemination_Mark, Consonant_Killer]
|
||||||
not is_SYM_MOD(U, UISC, UDI, UGC, AJT))
|
|
||||||
def is_CONS_SUB(U, UISC, UDI, UGC, AJT):
|
def is_CONS_SUB(U, UISC, UDI, UGC, AJT):
|
||||||
return UISC == Consonant_Subjoined and UGC != Lo
|
return UISC == Consonant_Subjoined and UGC != Lo
|
||||||
def is_CONS_WITH_STACKER(U, UISC, UDI, UGC, AJT):
|
def is_CONS_WITH_STACKER(U, UISC, UDI, UGC, AJT):
|
||||||
|
@ -257,7 +257,7 @@ def is_SAKOT(U, UISC, UDI, UGC, AJT):
|
||||||
# Split off of HALANT
|
# Split off of HALANT
|
||||||
return U == 0x1A60
|
return U == 0x1A60
|
||||||
def is_SYM_MOD(U, UISC, UDI, UGC, AJT):
|
def is_SYM_MOD(U, UISC, UDI, UGC, AJT):
|
||||||
return U in [0x1B6B, 0x1B6C, 0x1B6D, 0x1B6E, 0x1B6F, 0x1B70, 0x1B71, 0x1B72, 0x1B73]
|
return UISC == Symbol_Modifier
|
||||||
def is_VOWEL(U, UISC, UDI, UGC, AJT):
|
def is_VOWEL(U, UISC, UDI, UGC, AJT):
|
||||||
return (UISC == Pure_Killer or
|
return (UISC == Pure_Killer or
|
||||||
UGC != Lo and UISC in [Vowel, Vowel_Dependent])
|
UGC != Lo and UISC in [Vowel, Vowel_Dependent])
|
||||||
|
@ -359,9 +359,6 @@ def map_to_use(data):
|
||||||
# TODO: These don't have UISC assigned in Unicode 13.0.0, but have UIPC
|
# TODO: These don't have UISC assigned in Unicode 13.0.0, but have UIPC
|
||||||
if 0x0F18 <= U <= 0x0F19 or 0x0F3E <= U <= 0x0F3F: UISC = Vowel_Dependent
|
if 0x0F18 <= U <= 0x0F19 or 0x0F3E <= U <= 0x0F3F: UISC = Vowel_Dependent
|
||||||
|
|
||||||
# TODO: https://github.com/harfbuzz/harfbuzz/pull/627
|
|
||||||
if 0x1BF2 <= U <= 0x1BF3: UISC = Nukta; UIPC = Bottom
|
|
||||||
|
|
||||||
# TODO: U+1CED should only be allowed after some of
|
# TODO: U+1CED should only be allowed after some of
|
||||||
# the nasalization marks, maybe only for U+1CE9..U+1CF1.
|
# the nasalization marks, maybe only for U+1CE9..U+1CF1.
|
||||||
if U == 0x1CED: UISC = Tone_Mark
|
if U == 0x1CED: UISC = Tone_Mark
|
||||||
|
@ -372,23 +369,9 @@ def map_to_use(data):
|
||||||
|
|
||||||
# Resolve Indic_Positional_Category
|
# Resolve Indic_Positional_Category
|
||||||
|
|
||||||
# TODO: These should die, but have UIPC in Unicode 13.0.0
|
|
||||||
if U in [0x953, 0x954]: UIPC = Not_Applicable
|
|
||||||
|
|
||||||
# TODO: These are not in USE's override list that we have, nor are they in Unicode 13.0.0
|
|
||||||
if 0xA926 <= U <= 0xA92A: UIPC = Top
|
|
||||||
# TODO: https://github.com/harfbuzz/harfbuzz/pull/1037
|
# TODO: https://github.com/harfbuzz/harfbuzz/pull/1037
|
||||||
# and https://github.com/harfbuzz/harfbuzz/issues/1631
|
# and https://github.com/harfbuzz/harfbuzz/issues/1631
|
||||||
if U in [0x11302, 0x11303, 0x114C1]: UIPC = Top
|
if U in [0x11302, 0x11303, 0x114C1]: UIPC = Top
|
||||||
if 0x1CF8 <= U <= 0x1CF9: UIPC = Top
|
|
||||||
|
|
||||||
# TODO: https://github.com/harfbuzz/harfbuzz/issues/3550
|
|
||||||
if U == 0x10A38: UIPC = Bottom
|
|
||||||
|
|
||||||
# TODO: https://github.com/harfbuzz/harfbuzz/pull/982
|
|
||||||
# also https://github.com/harfbuzz/harfbuzz/issues/1012
|
|
||||||
if 0x1112A <= U <= 0x1112B: UIPC = Top
|
|
||||||
if 0x11131 <= U <= 0x11132: UIPC = Top
|
|
||||||
|
|
||||||
assert (UIPC in [Not_Applicable, Visual_Order_Left] or U == 0x0F7F or
|
assert (UIPC in [Not_Applicable, Visual_Order_Left] or U == 0x0F7F or
|
||||||
USE in use_positions), "%s %s %s %s %s %s %s" % (hex(U), UIPC, USE, UISC, UDI, UGC, AJT)
|
USE in use_positions), "%s %s %s %s %s %s %s" % (hex(U), UIPC, USE, UISC, UDI, UGC, AJT)
|
||||||
|
|
|
@ -70,8 +70,8 @@ struct graph_t
|
||||||
{
|
{
|
||||||
DEBUG_MSG (SUBSET_REPACK, nullptr,
|
DEBUG_MSG (SUBSET_REPACK, nullptr,
|
||||||
"vertex [%lu] bytes != [%lu] bytes, depth = %u",
|
"vertex [%lu] bytes != [%lu] bytes, depth = %u",
|
||||||
table_size (),
|
(unsigned long) table_size (),
|
||||||
other.table_size (),
|
(unsigned long) other.table_size (),
|
||||||
depth);
|
depth);
|
||||||
|
|
||||||
auto a = as_bytes ();
|
auto a = as_bytes ();
|
||||||
|
@ -495,6 +495,12 @@ struct graph_t
|
||||||
return as_table_from_index<T> (index_for_offset (parent, offset), std::forward<Ts>(ds)...);
|
return as_table_from_index<T> (index_for_offset (parent, offset), std::forward<Ts>(ds)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T, typename ...Ts>
|
||||||
|
vertex_and_table_t<T> as_mutable_table (unsigned parent, const void* offset, Ts... ds)
|
||||||
|
{
|
||||||
|
return as_table_from_index<T> (mutable_index_for_offset (parent, offset), std::forward<Ts>(ds)...);
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T, typename ...Ts>
|
template <typename T, typename ...Ts>
|
||||||
vertex_and_table_t<T> as_table_from_index (unsigned index, Ts... ds)
|
vertex_and_table_t<T> as_table_from_index (unsigned index, Ts... ds)
|
||||||
{
|
{
|
||||||
|
@ -574,7 +580,7 @@ struct graph_t
|
||||||
|
|
||||||
while (roots)
|
while (roots)
|
||||||
{
|
{
|
||||||
unsigned next = HB_SET_VALUE_INVALID;
|
uint32_t next = HB_SET_VALUE_INVALID;
|
||||||
if (unlikely (!check_success (!roots.in_error ()))) break;
|
if (unlikely (!check_success (!roots.in_error ()))) break;
|
||||||
if (!roots.next (&next)) break;
|
if (!roots.next (&next)) break;
|
||||||
|
|
||||||
|
@ -655,8 +661,8 @@ struct graph_t
|
||||||
|
|
||||||
auto new_subgraph =
|
auto new_subgraph =
|
||||||
+ subgraph.keys ()
|
+ subgraph.keys ()
|
||||||
| hb_map([&] (unsigned node_idx) {
|
| hb_map([&] (uint32_t node_idx) {
|
||||||
const unsigned *v;
|
const uint32_t *v;
|
||||||
if (index_map.has (node_idx, &v)) return *v;
|
if (index_map.has (node_idx, &v)) return *v;
|
||||||
return node_idx;
|
return node_idx;
|
||||||
})
|
})
|
||||||
|
@ -666,10 +672,10 @@ struct graph_t
|
||||||
remap_obj_indices (index_map, parents.iter (), true);
|
remap_obj_indices (index_map, parents.iter (), true);
|
||||||
|
|
||||||
// Update roots set with new indices as needed.
|
// Update roots set with new indices as needed.
|
||||||
unsigned next = HB_SET_VALUE_INVALID;
|
uint32_t next = HB_SET_VALUE_INVALID;
|
||||||
while (roots.next (&next))
|
while (roots.next (&next))
|
||||||
{
|
{
|
||||||
const unsigned *v;
|
const uint32_t *v;
|
||||||
if (index_map.has (next, &v))
|
if (index_map.has (next, &v))
|
||||||
{
|
{
|
||||||
roots.del (next);
|
roots.del (next);
|
||||||
|
@ -684,7 +690,7 @@ struct graph_t
|
||||||
{
|
{
|
||||||
for (const auto& link : vertices_[node_idx].obj.all_links ())
|
for (const auto& link : vertices_[node_idx].obj.all_links ())
|
||||||
{
|
{
|
||||||
const unsigned *v;
|
const uint32_t *v;
|
||||||
if (subgraph.has (link.objidx, &v))
|
if (subgraph.has (link.objidx, &v))
|
||||||
{
|
{
|
||||||
subgraph.set (link.objidx, *v + 1);
|
subgraph.set (link.objidx, *v + 1);
|
||||||
|
@ -833,7 +839,20 @@ struct graph_t
|
||||||
* parent to the clone. The copy is a shallow copy, objects
|
* parent to the clone. The copy is a shallow copy, objects
|
||||||
* linked from child are not duplicated.
|
* linked from child are not duplicated.
|
||||||
*/
|
*/
|
||||||
bool duplicate (unsigned parent_idx, unsigned child_idx)
|
unsigned duplicate_if_shared (unsigned parent_idx, unsigned child_idx)
|
||||||
|
{
|
||||||
|
unsigned new_idx = duplicate (parent_idx, child_idx);
|
||||||
|
if (new_idx == (unsigned) -1) return child_idx;
|
||||||
|
return new_idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Creates a copy of child and re-assigns the link from
|
||||||
|
* parent to the clone. The copy is a shallow copy, objects
|
||||||
|
* linked from child are not duplicated.
|
||||||
|
*/
|
||||||
|
unsigned duplicate (unsigned parent_idx, unsigned child_idx)
|
||||||
{
|
{
|
||||||
update_parents ();
|
update_parents ();
|
||||||
|
|
||||||
|
@ -849,7 +868,7 @@ struct graph_t
|
||||||
// to child are from parent.
|
// to child are from parent.
|
||||||
DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %d => %d",
|
DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %d => %d",
|
||||||
parent_idx, child_idx);
|
parent_idx, child_idx);
|
||||||
return false;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %d => %d",
|
DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %d => %d",
|
||||||
|
@ -869,7 +888,7 @@ struct graph_t
|
||||||
reassign_link (l, parent_idx, clone_idx);
|
reassign_link (l, parent_idx, clone_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return clone_idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1164,7 +1183,7 @@ struct graph_t
|
||||||
{
|
{
|
||||||
for (auto& link : vertices_[i].obj.all_links_writer ())
|
for (auto& link : vertices_[i].obj.all_links_writer ())
|
||||||
{
|
{
|
||||||
const unsigned *v;
|
const uint32_t *v;
|
||||||
if (!id_map.has (link.objidx, &v)) continue;
|
if (!id_map.has (link.objidx, &v)) continue;
|
||||||
if (only_wide && !(link.width == 4 && !link.is_signed)) continue;
|
if (only_wide && !(link.width == 4 && !link.is_signed)) continue;
|
||||||
|
|
||||||
|
|
|
@ -131,8 +131,10 @@ struct Lookup : public OT::Lookup
|
||||||
for (unsigned i = 0; i < subTable.len; i++)
|
for (unsigned i = 0; i < subTable.len; i++)
|
||||||
{
|
{
|
||||||
unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]);
|
unsigned subtable_index = c.graph.index_for_offset (this_index, &subTable[i]);
|
||||||
|
unsigned parent_index = this_index;
|
||||||
if (is_ext) {
|
if (is_ext) {
|
||||||
unsigned ext_subtable_index = subtable_index;
|
unsigned ext_subtable_index = subtable_index;
|
||||||
|
parent_index = ext_subtable_index;
|
||||||
ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>* extension =
|
ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>* extension =
|
||||||
(ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>*)
|
(ExtensionFormat1<OT::Layout::GSUB_impl::ExtensionSubst>*)
|
||||||
c.graph.object (ext_subtable_index).head;
|
c.graph.object (ext_subtable_index).head;
|
||||||
|
@ -150,9 +152,9 @@ struct Lookup : public OT::Lookup
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case 2:
|
case 2:
|
||||||
new_sub_tables = split_subtable<PairPos> (c, subtable_index); break;
|
new_sub_tables = split_subtable<PairPos> (c, parent_index, subtable_index); break;
|
||||||
case 4:
|
case 4:
|
||||||
new_sub_tables = split_subtable<MarkBasePos> (c, subtable_index); break;
|
new_sub_tables = split_subtable<MarkBasePos> (c, parent_index, subtable_index); break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -172,13 +174,14 @@ struct Lookup : public OT::Lookup
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
hb_vector_t<unsigned> split_subtable (gsubgpos_graph_context_t& c,
|
hb_vector_t<unsigned> split_subtable (gsubgpos_graph_context_t& c,
|
||||||
|
unsigned parent_idx,
|
||||||
unsigned objidx)
|
unsigned objidx)
|
||||||
{
|
{
|
||||||
T* sub_table = (T*) c.graph.object (objidx).head;
|
T* sub_table = (T*) c.graph.object (objidx).head;
|
||||||
if (!sub_table || !sub_table->sanitize (c.graph.vertices_[objidx]))
|
if (!sub_table || !sub_table->sanitize (c.graph.vertices_[objidx]))
|
||||||
return hb_vector_t<unsigned> ();
|
return hb_vector_t<unsigned> ();
|
||||||
|
|
||||||
return sub_table->split_subtables (c, objidx);
|
return sub_table->split_subtables (c, parent_idx, objidx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_sub_tables (gsubgpos_graph_context_t& c,
|
void add_sub_tables (gsubgpos_graph_context_t& c,
|
||||||
|
|
|
@ -209,7 +209,9 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
|
||||||
return vertex_len >= MarkBasePosFormat1::static_size;
|
return vertex_len >= MarkBasePosFormat1::static_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index)
|
hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
|
||||||
|
unsigned parent_index,
|
||||||
|
unsigned this_index)
|
||||||
{
|
{
|
||||||
hb_set_t visited;
|
hb_set_t visited;
|
||||||
|
|
||||||
|
@ -261,7 +263,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
|
||||||
split_context_t split_context {
|
split_context_t split_context {
|
||||||
c,
|
c,
|
||||||
this,
|
this,
|
||||||
this_index,
|
c.graph.duplicate_if_shared (parent_index, this_index),
|
||||||
std::move (class_to_info),
|
std::move (class_to_info),
|
||||||
c.graph.vertices_[mark_array_id].position_to_index_map (),
|
c.graph.vertices_[mark_array_id].position_to_index_map (),
|
||||||
};
|
};
|
||||||
|
@ -365,7 +367,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
|
||||||
|
|
||||||
classCount = count;
|
classCount = count;
|
||||||
|
|
||||||
auto mark_coverage = sc.c.graph.as_table<Coverage> (this_index,
|
auto mark_coverage = sc.c.graph.as_mutable_table<Coverage> (this_index,
|
||||||
&markCoverage);
|
&markCoverage);
|
||||||
if (!mark_coverage) return false;
|
if (!mark_coverage) return false;
|
||||||
hb_set_t marks = sc.marks_for (0, count);
|
hb_set_t marks = sc.marks_for (0, count);
|
||||||
|
@ -380,7 +382,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
||||||
auto base_array = sc.c.graph.as_table<AnchorMatrix> (this_index,
|
auto base_array = sc.c.graph.as_mutable_table<AnchorMatrix> (this_index,
|
||||||
&baseArray,
|
&baseArray,
|
||||||
old_count);
|
old_count);
|
||||||
if (!base_array || !base_array.table->shrink (sc.c,
|
if (!base_array || !base_array.table->shrink (sc.c,
|
||||||
|
@ -389,7 +391,7 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
|
||||||
count))
|
count))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
auto mark_array = sc.c.graph.as_table<MarkArray> (this_index,
|
auto mark_array = sc.c.graph.as_mutable_table<MarkArray> (this_index,
|
||||||
&markArray);
|
&markArray);
|
||||||
if (!mark_array || !mark_array.table->shrink (sc.c,
|
if (!mark_array || !mark_array.table->shrink (sc.c,
|
||||||
sc.mark_array_links,
|
sc.mark_array_links,
|
||||||
|
@ -469,11 +471,12 @@ struct MarkBasePosFormat1 : public OT::Layout::GPOS_impl::MarkBasePosFormat1_2<S
|
||||||
struct MarkBasePos : public OT::Layout::GPOS_impl::MarkBasePos
|
struct MarkBasePos : public OT::Layout::GPOS_impl::MarkBasePos
|
||||||
{
|
{
|
||||||
hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
|
hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
|
||||||
|
unsigned parent_index,
|
||||||
unsigned this_index)
|
unsigned this_index)
|
||||||
{
|
{
|
||||||
switch (u.format) {
|
switch (u.format) {
|
||||||
case 1:
|
case 1:
|
||||||
return ((MarkBasePosFormat1*)(&u.format1))->split_subtables (c, this_index);
|
return ((MarkBasePosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index);
|
||||||
#ifndef HB_NO_BORING_EXPANSION
|
#ifndef HB_NO_BORING_EXPANSION
|
||||||
case 2: HB_FALLTHROUGH;
|
case 2: HB_FALLTHROUGH;
|
||||||
// Don't split 24bit PairPos's.
|
// Don't split 24bit PairPos's.
|
||||||
|
|
|
@ -47,7 +47,9 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallType
|
||||||
min_size + pairSet.get_size () - pairSet.len.get_size();
|
min_size + pairSet.get_size () - pairSet.len.get_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index)
|
hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
|
||||||
|
unsigned parent_index,
|
||||||
|
unsigned this_index)
|
||||||
{
|
{
|
||||||
hb_set_t visited;
|
hb_set_t visited;
|
||||||
|
|
||||||
|
@ -81,7 +83,7 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallType
|
||||||
split_context_t split_context {
|
split_context_t split_context {
|
||||||
c,
|
c,
|
||||||
this,
|
this,
|
||||||
this_index,
|
c.graph.duplicate_if_shared (parent_index, this_index),
|
||||||
};
|
};
|
||||||
|
|
||||||
return actuate_subtable_split<split_context_t> (split_context, split_points);
|
return actuate_subtable_split<split_context_t> (split_context, split_points);
|
||||||
|
@ -125,23 +127,19 @@ struct PairPosFormat1 : public OT::Layout::GPOS_impl::PairPosFormat1_3<SmallType
|
||||||
pairSet.len = count;
|
pairSet.len = count;
|
||||||
c.graph.vertices_[this_index].obj.tail -= (old_count - count) * SmallTypes::size;
|
c.graph.vertices_[this_index].obj.tail -= (old_count - count) * SmallTypes::size;
|
||||||
|
|
||||||
unsigned coverage_id = c.graph.mutable_index_for_offset (this_index, &coverage);
|
auto coverage = c.graph.as_mutable_table<Coverage> (this_index, &this->coverage);
|
||||||
unsigned coverage_size = c.graph.vertices_[coverage_id].table_size ();
|
if (!coverage) return false;
|
||||||
auto& coverage_v = c.graph.vertices_[coverage_id];
|
|
||||||
|
|
||||||
Coverage* coverage_table = (Coverage*) coverage_v.obj.head;
|
|
||||||
if (!coverage_table || !coverage_table->sanitize (coverage_v))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
|
unsigned coverage_size = coverage.vertex->table_size ();
|
||||||
auto new_coverage =
|
auto new_coverage =
|
||||||
+ hb_zip (coverage_table->iter (), hb_range ())
|
+ hb_zip (coverage.table->iter (), hb_range ())
|
||||||
| hb_filter ([&] (hb_pair_t<unsigned, unsigned> p) {
|
| hb_filter ([&] (hb_pair_t<unsigned, unsigned> p) {
|
||||||
return p.second < count;
|
return p.second < count;
|
||||||
})
|
})
|
||||||
| hb_map_retains_sorting (hb_first)
|
| hb_map_retains_sorting (hb_first)
|
||||||
;
|
;
|
||||||
|
|
||||||
return Coverage::make_coverage (c, new_coverage, coverage_id, coverage_size);
|
return Coverage::make_coverage (c, new_coverage, coverage.index, coverage_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new PairPos including PairSet's from start (inclusive) to end (exclusive).
|
// Create a new PairPos including PairSet's from start (inclusive) to end (exclusive).
|
||||||
|
@ -206,7 +204,9 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
|
||||||
min_size + class1_count * get_class1_record_size ();
|
min_size + class1_count * get_class1_record_size ();
|
||||||
}
|
}
|
||||||
|
|
||||||
hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index)
|
hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
|
||||||
|
unsigned parent_index,
|
||||||
|
unsigned this_index)
|
||||||
{
|
{
|
||||||
const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size;
|
const unsigned base_size = OT::Layout::GPOS_impl::PairPosFormat2_4<SmallTypes>::min_size;
|
||||||
const unsigned class_def_2_size = size_of (c, this_index, &classDef2);
|
const unsigned class_def_2_size = size_of (c, this_index, &classDef2);
|
||||||
|
@ -287,7 +287,7 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
|
||||||
split_context_t split_context {
|
split_context_t split_context {
|
||||||
c,
|
c,
|
||||||
this,
|
this,
|
||||||
this_index,
|
c.graph.duplicate_if_shared (parent_index, this_index),
|
||||||
class1_record_size,
|
class1_record_size,
|
||||||
total_value_len,
|
total_value_len,
|
||||||
value_1_len,
|
value_1_len,
|
||||||
|
@ -508,40 +508,37 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
|
||||||
graph.vertices_[split_context.this_index].obj.tail -=
|
graph.vertices_[split_context.this_index].obj.tail -=
|
||||||
(old_count - count) * split_context.class1_record_size;
|
(old_count - count) * split_context.class1_record_size;
|
||||||
|
|
||||||
unsigned coverage_id =
|
auto coverage =
|
||||||
graph.mutable_index_for_offset (split_context.this_index, &coverage);
|
graph.as_mutable_table<Coverage> (split_context.this_index, &this->coverage);
|
||||||
unsigned class_def_1_id =
|
if (!coverage) return false;
|
||||||
graph.mutable_index_for_offset (split_context.this_index, &classDef1);
|
|
||||||
auto& coverage_v = graph.vertices_[coverage_id];
|
auto class_def_1 =
|
||||||
auto& class_def_1_v = graph.vertices_[class_def_1_id];
|
graph.as_mutable_table<ClassDef> (split_context.this_index, &classDef1);
|
||||||
Coverage* coverage_table = (Coverage*) coverage_v.obj.head;
|
if (!class_def_1) return false;
|
||||||
ClassDef* class_def_1_table = (ClassDef*) class_def_1_v.obj.head;
|
|
||||||
if (!coverage_table
|
|
||||||
|| !coverage_table->sanitize (coverage_v)
|
|
||||||
|| !class_def_1_table
|
|
||||||
|| !class_def_1_table->sanitize (class_def_1_v))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto klass_map =
|
auto klass_map =
|
||||||
+ coverage_table->iter ()
|
+ coverage.table->iter ()
|
||||||
| hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
|
| hb_map_retains_sorting ([&] (hb_codepoint_t gid) {
|
||||||
return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, class_def_1_table->get_class (gid));
|
return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (gid, class_def_1.table->get_class (gid));
|
||||||
})
|
})
|
||||||
| hb_filter ([&] (hb_codepoint_t klass) {
|
| hb_filter ([&] (hb_codepoint_t klass) {
|
||||||
return klass < count;
|
return klass < count;
|
||||||
}, hb_second)
|
}, hb_second)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
auto new_coverage = + klass_map | hb_map_retains_sorting (hb_first);
|
||||||
if (!Coverage::make_coverage (split_context.c,
|
if (!Coverage::make_coverage (split_context.c,
|
||||||
+ klass_map | hb_map_retains_sorting (hb_first),
|
+ new_coverage,
|
||||||
coverage_id,
|
coverage.index,
|
||||||
coverage_v.table_size ()))
|
// existing ranges my not be kept, worst case size is a format 1
|
||||||
|
// coverage table.
|
||||||
|
4 + new_coverage.len() * 2))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return ClassDef::make_class_def (split_context.c,
|
return ClassDef::make_class_def (split_context.c,
|
||||||
+ klass_map,
|
+ klass_map,
|
||||||
class_def_1_id,
|
class_def_1.index,
|
||||||
class_def_1_v.table_size ());
|
class_def_1.vertex->table_size ());
|
||||||
}
|
}
|
||||||
|
|
||||||
hb_hashmap_t<unsigned, unsigned>
|
hb_hashmap_t<unsigned, unsigned>
|
||||||
|
@ -605,13 +602,15 @@ struct PairPosFormat2 : public OT::Layout::GPOS_impl::PairPosFormat2_4<SmallType
|
||||||
|
|
||||||
struct PairPos : public OT::Layout::GPOS_impl::PairPos
|
struct PairPos : public OT::Layout::GPOS_impl::PairPos
|
||||||
{
|
{
|
||||||
hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c, unsigned this_index)
|
hb_vector_t<unsigned> split_subtables (gsubgpos_graph_context_t& c,
|
||||||
|
unsigned parent_index,
|
||||||
|
unsigned this_index)
|
||||||
{
|
{
|
||||||
switch (u.format) {
|
switch (u.format) {
|
||||||
case 1:
|
case 1:
|
||||||
return ((PairPosFormat1*)(&u.format1))->split_subtables (c, this_index);
|
return ((PairPosFormat1*)(&u.format1))->split_subtables (c, parent_index, this_index);
|
||||||
case 2:
|
case 2:
|
||||||
return ((PairPosFormat2*)(&u.format2))->split_subtables (c, this_index);
|
return ((PairPosFormat2*)(&u.format2))->split_subtables (c, parent_index, this_index);
|
||||||
#ifndef HB_NO_BORING_EXPANSION
|
#ifndef HB_NO_BORING_EXPANSION
|
||||||
case 3: HB_FALLTHROUGH;
|
case 3: HB_FALLTHROUGH;
|
||||||
case 4: HB_FALLTHROUGH;
|
case 4: HB_FALLTHROUGH;
|
||||||
|
|
|
@ -1,29 +1,5 @@
|
||||||
# Set these variables so that the `${prefix}/lib` expands to something we can
|
|
||||||
# remove.
|
|
||||||
set(_harfbuzz_remove_string "REMOVE_ME")
|
|
||||||
set(exec_prefix "${_harfbuzz_remove_string}")
|
|
||||||
set(prefix "${_harfbuzz_remove_string}")
|
|
||||||
|
|
||||||
# Compute the installation prefix by stripping components from our current
|
|
||||||
# location.
|
|
||||||
get_filename_component(_harfbuzz_prefix "${CMAKE_CURRENT_LIST_DIR}" DIRECTORY)
|
|
||||||
get_filename_component(_harfbuzz_prefix "${_harfbuzz_prefix}" DIRECTORY)
|
|
||||||
set(_harfbuzz_libdir "@libdir@")
|
set(_harfbuzz_libdir "@libdir@")
|
||||||
string(REPLACE "${_harfbuzz_remove_string}/" "" _harfbuzz_libdir "${_harfbuzz_libdir}")
|
|
||||||
set(_harfbuzz_libdir_iter "${_harfbuzz_libdir}")
|
|
||||||
while (_harfbuzz_libdir_iter)
|
|
||||||
set(_harfbuzz_libdir_prev_iter "${_harfbuzz_libdir_iter}")
|
|
||||||
get_filename_component(_harfbuzz_libdir_iter "${_harfbuzz_libdir_iter}" DIRECTORY)
|
|
||||||
if (_harfbuzz_libdir_prev_iter STREQUAL _harfbuzz_libdir_iter)
|
|
||||||
break()
|
|
||||||
endif ()
|
|
||||||
get_filename_component(_harfbuzz_prefix "${_harfbuzz_prefix}" DIRECTORY)
|
|
||||||
endwhile ()
|
|
||||||
unset(_harfbuzz_libdir_iter)
|
|
||||||
|
|
||||||
# Get the include subdir.
|
|
||||||
set(_harfbuzz_includedir "@includedir@")
|
set(_harfbuzz_includedir "@includedir@")
|
||||||
string(REPLACE "${_harfbuzz_remove_string}/" "" _harfbuzz_includedir "${_harfbuzz_includedir}")
|
|
||||||
|
|
||||||
# Extract version information from libtool.
|
# Extract version information from libtool.
|
||||||
set(_harfbuzz_version_info "@HB_LIBTOOL_VERSION_INFO@")
|
set(_harfbuzz_version_info "@HB_LIBTOOL_VERSION_INFO@")
|
||||||
|
@ -48,29 +24,29 @@ endif ()
|
||||||
# Add the libraries.
|
# Add the libraries.
|
||||||
add_library(harfbuzz::harfbuzz SHARED IMPORTED)
|
add_library(harfbuzz::harfbuzz SHARED IMPORTED)
|
||||||
set_target_properties(harfbuzz::harfbuzz PROPERTIES
|
set_target_properties(harfbuzz::harfbuzz PROPERTIES
|
||||||
INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_prefix}/${_harfbuzz_includedir}/harfbuzz"
|
INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_includedir}/harfbuzz"
|
||||||
IMPORTED_LOCATION "${_harfbuzz_prefix}/${_harfbuzz_libdir}/libharfbuzz${_harfbuzz_lib_suffix}")
|
IMPORTED_LOCATION "${_harfbuzz_libdir}/libharfbuzz${_harfbuzz_lib_suffix}")
|
||||||
|
|
||||||
add_library(harfbuzz::icu SHARED IMPORTED)
|
add_library(harfbuzz::icu SHARED IMPORTED)
|
||||||
set_target_properties(harfbuzz::icu PROPERTIES
|
set_target_properties(harfbuzz::icu PROPERTIES
|
||||||
INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_prefix}/${_harfbuzz_includedir}/harfbuzz"
|
INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_includedir}/harfbuzz"
|
||||||
INTERFACE_LINK_LIBRARIES "harfbuzz::harfbuzz"
|
INTERFACE_LINK_LIBRARIES "harfbuzz::harfbuzz"
|
||||||
IMPORTED_LOCATION "${_harfbuzz_prefix}/${_harfbuzz_libdir}/libharfbuzz-icu${_harfbuzz_lib_suffix}")
|
IMPORTED_LOCATION "${_harfbuzz_libdir}/libharfbuzz-icu${_harfbuzz_lib_suffix}")
|
||||||
|
|
||||||
add_library(harfbuzz::subset SHARED IMPORTED)
|
add_library(harfbuzz::subset SHARED IMPORTED)
|
||||||
set_target_properties(harfbuzz::subset PROPERTIES
|
set_target_properties(harfbuzz::subset PROPERTIES
|
||||||
INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_prefix}/${_harfbuzz_includedir}/harfbuzz"
|
INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_includedir}/harfbuzz"
|
||||||
INTERFACE_LINK_LIBRARIES "harfbuzz::harfbuzz"
|
INTERFACE_LINK_LIBRARIES "harfbuzz::harfbuzz"
|
||||||
IMPORTED_LOCATION "${_harfbuzz_prefix}/${_harfbuzz_libdir}/libharfbuzz-subset${_harfbuzz_lib_suffix}")
|
IMPORTED_LOCATION "${_harfbuzz_libdir}/libharfbuzz-subset${_harfbuzz_lib_suffix}")
|
||||||
|
|
||||||
# Only add the gobject library if it was built.
|
# Only add the gobject library if it was built.
|
||||||
set(_harfbuzz_have_gobject "@have_gobject@")
|
set(_harfbuzz_have_gobject "@have_gobject@")
|
||||||
if (_harfbuzz_have_gobject)
|
if (_harfbuzz_have_gobject)
|
||||||
add_library(harfbuzz::gobject SHARED IMPORTED)
|
add_library(harfbuzz::gobject SHARED IMPORTED)
|
||||||
set_target_properties(harfbuzz::gobject PROPERTIES
|
set_target_properties(harfbuzz::gobject PROPERTIES
|
||||||
INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_prefix}/${_harfbuzz_includedir}/harfbuzz"
|
INTERFACE_INCLUDE_DIRECTORIES "${_harfbuzz_includedir}/harfbuzz"
|
||||||
INTERFACE_LINK_LIBRARIES "harfbuzz::harfbuzz"
|
INTERFACE_LINK_LIBRARIES "harfbuzz::harfbuzz"
|
||||||
IMPORTED_LOCATION "${_harfbuzz_prefix}/${_harfbuzz_libdir}/libharfbuzz-gobject${_harfbuzz_lib_suffix}")
|
IMPORTED_LOCATION "${_harfbuzz_libdir}/libharfbuzz-gobject${_harfbuzz_lib_suffix}")
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
# Clean out variables we used in our scope.
|
# Clean out variables we used in our scope.
|
||||||
|
@ -80,7 +56,3 @@ unset(_harfbuzz_revision)
|
||||||
unset(_harfbuzz_age)
|
unset(_harfbuzz_age)
|
||||||
unset(_harfbuzz_includedir)
|
unset(_harfbuzz_includedir)
|
||||||
unset(_harfbuzz_libdir)
|
unset(_harfbuzz_libdir)
|
||||||
unset(_harfbuzz_prefix)
|
|
||||||
unset(exec_prefix)
|
|
||||||
unset(prefix)
|
|
||||||
unset(_harfbuzz_remove_string)
|
|
||||||
|
|
|
@ -70,9 +70,9 @@ struct DecompositionAction
|
||||||
|
|
||||||
ActionSubrecordHeader
|
ActionSubrecordHeader
|
||||||
header;
|
header;
|
||||||
HBFixed lowerLimit; /* If the distance factor is less than this value,
|
F16DOT16 lowerLimit; /* If the distance factor is less than this value,
|
||||||
* then the ligature is decomposed. */
|
* then the ligature is decomposed. */
|
||||||
HBFixed upperLimit; /* If the distance factor is greater than this value,
|
F16DOT16 upperLimit; /* If the distance factor is greater than this value,
|
||||||
* then the ligature is decomposed. */
|
* then the ligature is decomposed. */
|
||||||
HBUINT16 order; /* Numerical order in which this ligature will
|
HBUINT16 order; /* Numerical order in which this ligature will
|
||||||
* be decomposed; you may want infrequent ligatures
|
* be decomposed; you may want infrequent ligatures
|
||||||
|
@ -118,7 +118,7 @@ struct ConditionalAddGlyphAction
|
||||||
protected:
|
protected:
|
||||||
ActionSubrecordHeader
|
ActionSubrecordHeader
|
||||||
header;
|
header;
|
||||||
HBFixed substThreshold; /* Distance growth factor (in ems) at which
|
F16DOT16 substThreshold; /* Distance growth factor (in ems) at which
|
||||||
* this glyph is replaced and the growth factor
|
* this glyph is replaced and the growth factor
|
||||||
* recalculated. */
|
* recalculated. */
|
||||||
HBGlyphID16 addGlyph; /* Glyph to be added as kashida. If this value is
|
HBGlyphID16 addGlyph; /* Glyph to be added as kashida. If this value is
|
||||||
|
@ -146,13 +146,13 @@ struct DuctileGlyphAction
|
||||||
HBUINT32 variationAxis; /* The 4-byte tag identifying the ductile axis.
|
HBUINT32 variationAxis; /* The 4-byte tag identifying the ductile axis.
|
||||||
* This would normally be 0x64756374 ('duct'),
|
* This would normally be 0x64756374 ('duct'),
|
||||||
* but you may use any axis the font contains. */
|
* but you may use any axis the font contains. */
|
||||||
HBFixed minimumLimit; /* The lowest value for the ductility axis that
|
F16DOT16 minimumLimit; /* The lowest value for the ductility axis that
|
||||||
* still yields an acceptable appearance. Normally
|
* still yields an acceptable appearance. Normally
|
||||||
* this will be 1.0. */
|
* this will be 1.0. */
|
||||||
HBFixed noStretchValue; /* This is the default value that corresponds to
|
F16DOT16 noStretchValue; /* This is the default value that corresponds to
|
||||||
* no change in appearance. Normally, this will
|
* no change in appearance. Normally, this will
|
||||||
* be 1.0. */
|
* be 1.0. */
|
||||||
HBFixed maximumLimit; /* The highest value for the ductility axis that
|
F16DOT16 maximumLimit; /* The highest value for the ductility axis that
|
||||||
* still yields an acceptable appearance. */
|
* still yields an acceptable appearance. */
|
||||||
public:
|
public:
|
||||||
DEFINE_SIZE_STATIC (22);
|
DEFINE_SIZE_STATIC (22);
|
||||||
|
@ -271,14 +271,14 @@ struct JustWidthDeltaEntry
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
HBFixed beforeGrowLimit;/* The ratio by which the advance width of the
|
F16DOT16 beforeGrowLimit;/* The ratio by which the advance width of the
|
||||||
* glyph is permitted to grow on the left or top side. */
|
* glyph is permitted to grow on the left or top side. */
|
||||||
HBFixed beforeShrinkLimit;
|
F16DOT16 beforeShrinkLimit;
|
||||||
/* The ratio by which the advance width of the
|
/* The ratio by which the advance width of the
|
||||||
* glyph is permitted to shrink on the left or top side. */
|
* glyph is permitted to shrink on the left or top side. */
|
||||||
HBFixed afterGrowLimit; /* The ratio by which the advance width of the glyph
|
F16DOT16 afterGrowLimit; /* The ratio by which the advance width of the glyph
|
||||||
* is permitted to shrink on the left or top side. */
|
* is permitted to shrink on the left or top side. */
|
||||||
HBFixed afterShrinkLimit;
|
F16DOT16 afterShrinkLimit;
|
||||||
/* The ratio by which the advance width of the glyph
|
/* The ratio by which the advance width of the glyph
|
||||||
* is at most permitted to shrink on the right or
|
* is at most permitted to shrink on the right or
|
||||||
* bottom side. */
|
* bottom side. */
|
||||||
|
|
|
@ -62,7 +62,7 @@ struct TrackTableEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
HBFixed track; /* Track value for this record. */
|
F16DOT16 track; /* Track value for this record. */
|
||||||
NameID trackNameID; /* The 'name' table index for this track.
|
NameID trackNameID; /* The 'name' table index for this track.
|
||||||
* (a short word or phrase like "loose"
|
* (a short word or phrase like "loose"
|
||||||
* or "very tight") */
|
* or "very tight") */
|
||||||
|
@ -82,7 +82,7 @@ struct TrackData
|
||||||
const void *base) const
|
const void *base) const
|
||||||
{
|
{
|
||||||
unsigned int sizes = nSizes;
|
unsigned int sizes = nSizes;
|
||||||
hb_array_t<const HBFixed> size_table ((base+sizeTable).arrayZ, sizes);
|
hb_array_t<const F16DOT16> size_table ((base+sizeTable).arrayZ, sizes);
|
||||||
|
|
||||||
float s0 = size_table[idx].to_float ();
|
float s0 = size_table[idx].to_float ();
|
||||||
float s1 = size_table[idx + 1].to_float ();
|
float s1 = size_table[idx + 1].to_float ();
|
||||||
|
@ -120,7 +120,7 @@ struct TrackData
|
||||||
if (!sizes) return 0.;
|
if (!sizes) return 0.;
|
||||||
if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes);
|
if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes);
|
||||||
|
|
||||||
hb_array_t<const HBFixed> size_table ((base+sizeTable).arrayZ, sizes);
|
hb_array_t<const F16DOT16> size_table ((base+sizeTable).arrayZ, sizes);
|
||||||
unsigned int size_index;
|
unsigned int size_index;
|
||||||
for (size_index = 0; size_index < sizes - 1; size_index++)
|
for (size_index = 0; size_index < sizes - 1; size_index++)
|
||||||
if (size_table[size_index].to_float () >= ptem)
|
if (size_table[size_index].to_float () >= ptem)
|
||||||
|
@ -141,7 +141,7 @@ struct TrackData
|
||||||
protected:
|
protected:
|
||||||
HBUINT16 nTracks; /* Number of separate tracks included in this table. */
|
HBUINT16 nTracks; /* Number of separate tracks included in this table. */
|
||||||
HBUINT16 nSizes; /* Number of point sizes included in this table. */
|
HBUINT16 nSizes; /* Number of point sizes included in this table. */
|
||||||
NNOffset32To<UnsizedArrayOf<HBFixed>>
|
NNOffset32To<UnsizedArrayOf<F16DOT16>>
|
||||||
sizeTable; /* Offset from start of the tracking table to
|
sizeTable; /* Offset from start of the tracking table to
|
||||||
* Array[nSizes] of size values.. */
|
* Array[nSizes] of size values.. */
|
||||||
UnsizedArrayOf<TrackTableEntry>
|
UnsizedArrayOf<TrackTableEntry>
|
||||||
|
|
|
@ -131,6 +131,7 @@ static const hb_aat_feature_mapping_t feature_mappings[] =
|
||||||
{HB_TAG ('p','n','u','m'), HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_NUMBERS, (hb_aat_layout_feature_selector_t) 4},
|
{HB_TAG ('p','n','u','m'), HB_AAT_LAYOUT_FEATURE_TYPE_NUMBER_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_NUMBERS, (hb_aat_layout_feature_selector_t) 4},
|
||||||
{HB_TAG ('p','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7},
|
{HB_TAG ('p','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_PROPORTIONAL_TEXT, (hb_aat_layout_feature_selector_t) 7},
|
||||||
{HB_TAG ('q','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7},
|
{HB_TAG ('q','w','i','d'), HB_AAT_LAYOUT_FEATURE_TYPE_TEXT_SPACING, HB_AAT_LAYOUT_FEATURE_SELECTOR_QUARTER_WIDTH_TEXT, (hb_aat_layout_feature_selector_t) 7},
|
||||||
|
{HB_TAG ('r','l','i','g'), HB_AAT_LAYOUT_FEATURE_TYPE_LIGATURES, HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_REQUIRED_LIGATURES_OFF},
|
||||||
{HB_TAG ('r','u','b','y'), HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA, HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF},
|
{HB_TAG ('r','u','b','y'), HB_AAT_LAYOUT_FEATURE_TYPE_RUBY_KANA, HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_RUBY_KANA_OFF},
|
||||||
{HB_TAG ('s','i','n','f'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SCIENTIFIC_INFERIORS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION},
|
{HB_TAG ('s','i','n','f'), HB_AAT_LAYOUT_FEATURE_TYPE_VERTICAL_POSITION, HB_AAT_LAYOUT_FEATURE_SELECTOR_SCIENTIFIC_INFERIORS, HB_AAT_LAYOUT_FEATURE_SELECTOR_NORMAL_POSITION},
|
||||||
{HB_TAG ('s','m','c','p'), HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE},
|
{HB_TAG ('s','m','c','p'), HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE, HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS, HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_LOWER_CASE},
|
||||||
|
|
|
@ -495,8 +495,8 @@ hb_language_matches (hb_language_t language,
|
||||||
* @HB_SCRIPT_TOTO: `Toto`, Since: 3.0.0
|
* @HB_SCRIPT_TOTO: `Toto`, Since: 3.0.0
|
||||||
* @HB_SCRIPT_VITHKUQI: `Vith`, Since: 3.0.0
|
* @HB_SCRIPT_VITHKUQI: `Vith`, Since: 3.0.0
|
||||||
* @HB_SCRIPT_MATH: `Zmth`, Since: 3.4.0
|
* @HB_SCRIPT_MATH: `Zmth`, Since: 3.4.0
|
||||||
* @HB_SCRIPT_KAWI: `Kawi`, Since: REPLACEME
|
* @HB_SCRIPT_KAWI: `Kawi`, Since: 5.2.0
|
||||||
* @HB_SCRIPT_NAG_MUNDARI: `Nagm`, Since: REPLACEME
|
* @HB_SCRIPT_NAG_MUNDARI: `Nagm`, Since: 5.2.0
|
||||||
* @HB_SCRIPT_INVALID: No script set
|
* @HB_SCRIPT_INVALID: No script set
|
||||||
*
|
*
|
||||||
* Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding
|
* Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding
|
||||||
|
@ -719,7 +719,7 @@ typedef enum
|
||||||
HB_SCRIPT_MATH = HB_TAG ('Z','m','t','h'),
|
HB_SCRIPT_MATH = HB_TAG ('Z','m','t','h'),
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since REPLACEME
|
* Since 5.2.0
|
||||||
*/
|
*/
|
||||||
HB_SCRIPT_KAWI = HB_TAG ('K','a','w','i'), /*15.0*/
|
HB_SCRIPT_KAWI = HB_TAG ('K','a','w','i'), /*15.0*/
|
||||||
HB_SCRIPT_NAG_MUNDARI = HB_TAG ('N','a','g','m'), /*15.0*/
|
HB_SCRIPT_NAG_MUNDARI = HB_TAG ('N','a','g','m'), /*15.0*/
|
||||||
|
|
|
@ -71,6 +71,7 @@
|
||||||
#define HB_NO_LANGUAGE_PRIVATE_SUBTAG
|
#define HB_NO_LANGUAGE_PRIVATE_SUBTAG
|
||||||
#define HB_NO_LAYOUT_FEATURE_PARAMS
|
#define HB_NO_LAYOUT_FEATURE_PARAMS
|
||||||
#define HB_NO_LAYOUT_COLLECT_GLYPHS
|
#define HB_NO_LAYOUT_COLLECT_GLYPHS
|
||||||
|
#define HB_NO_LAYOUT_RARELY_USED
|
||||||
#define HB_NO_LAYOUT_UNUSED
|
#define HB_NO_LAYOUT_UNUSED
|
||||||
#define HB_NO_MATH
|
#define HB_NO_MATH
|
||||||
#define HB_NO_META
|
#define HB_NO_META
|
||||||
|
|
|
@ -69,9 +69,9 @@ struct shared_ptr
|
||||||
operator T * () const { return p; }
|
operator T * () const { return p; }
|
||||||
T& operator * () const { return *get (); }
|
T& operator * () const { return *get (); }
|
||||||
T* operator -> () const { return get (); }
|
T* operator -> () const { return get (); }
|
||||||
operator bool () { return p; }
|
operator bool () const { return p; }
|
||||||
bool operator == (const shared_ptr &o) { return p == o.p; }
|
bool operator == (const shared_ptr &o) const { return p == o.p; }
|
||||||
bool operator != (const shared_ptr &o) { return p != o.p; }
|
bool operator != (const shared_ptr &o) const { return p != o.p; }
|
||||||
|
|
||||||
static T* get_empty() { return v::get_empty (); }
|
static T* get_empty() { return v::get_empty (); }
|
||||||
T* reference() { return v::reference (p); }
|
T* reference() { return v::reference (p); }
|
||||||
|
|
|
@ -633,20 +633,29 @@ hb_face_collect_variation_unicodes (hb_face_t *face,
|
||||||
* face-builder: A face that has add_table().
|
* face-builder: A face that has add_table().
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
struct face_table_info_t
|
||||||
|
{
|
||||||
|
hb_blob_t* data;
|
||||||
|
unsigned order;
|
||||||
|
};
|
||||||
|
|
||||||
struct hb_face_builder_data_t
|
struct hb_face_builder_data_t
|
||||||
{
|
{
|
||||||
hb_hashmap_t<hb_tag_t, hb_blob_t *> tables;
|
hb_hashmap_t<hb_tag_t, face_table_info_t> tables;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int compare_entries (const void* pa, const void* pb)
|
static int compare_entries (const void* pa, const void* pb)
|
||||||
{
|
{
|
||||||
const auto& a = * (const hb_pair_t<hb_tag_t, hb_blob_t*> *) pa;
|
const auto& a = * (const hb_pair_t<hb_tag_t, face_table_info_t> *) pa;
|
||||||
const auto& b = * (const hb_pair_t<hb_tag_t, hb_blob_t*> *) pb;
|
const auto& b = * (const hb_pair_t<hb_tag_t, face_table_info_t> *) pb;
|
||||||
|
|
||||||
/* Order by blob size first (smallest to largest) and then table tag */
|
/* Order by blob size first (smallest to largest) and then table tag */
|
||||||
|
|
||||||
if (a.second->length != b.second->length)
|
if (a.second.order != b.second.order)
|
||||||
return a.second->length < b.second->length ? -1 : +1;
|
return a.second.order < b.second.order ? -1 : +1;
|
||||||
|
|
||||||
|
if (a.second.data->length != b.second.data->length)
|
||||||
|
return a.second.data->length < b.second.data->length ? -1 : +1;
|
||||||
|
|
||||||
return a.first < b.first ? -1 : a.first == b.first ? 0 : +1;
|
return a.first < b.first ? -1 : a.first == b.first ? 0 : +1;
|
||||||
}
|
}
|
||||||
|
@ -668,8 +677,8 @@ _hb_face_builder_data_destroy (void *user_data)
|
||||||
{
|
{
|
||||||
hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
|
hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
|
||||||
|
|
||||||
for (hb_blob_t* b : data->tables.values())
|
for (auto info : data->tables.values())
|
||||||
hb_blob_destroy (b);
|
hb_blob_destroy (info.data);
|
||||||
|
|
||||||
data->tables.fini ();
|
data->tables.fini ();
|
||||||
|
|
||||||
|
@ -683,8 +692,8 @@ _hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
|
||||||
unsigned int table_count = data->tables.get_population ();
|
unsigned int table_count = data->tables.get_population ();
|
||||||
unsigned int face_length = table_count * 16 + 12;
|
unsigned int face_length = table_count * 16 + 12;
|
||||||
|
|
||||||
for (hb_blob_t* b : data->tables.values())
|
for (auto info : data->tables.values())
|
||||||
face_length += hb_ceil_to_4 (hb_blob_get_length (b));
|
face_length += hb_ceil_to_4 (hb_blob_get_length (info.data));
|
||||||
|
|
||||||
char *buf = (char *) hb_malloc (face_length);
|
char *buf = (char *) hb_malloc (face_length);
|
||||||
if (unlikely (!buf))
|
if (unlikely (!buf))
|
||||||
|
@ -699,7 +708,7 @@ _hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
|
||||||
hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;
|
hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;
|
||||||
|
|
||||||
// Sort the tags so that produced face is deterministic.
|
// Sort the tags so that produced face is deterministic.
|
||||||
hb_vector_t<hb_pair_t <hb_tag_t, hb_blob_t*>> sorted_entries;
|
hb_vector_t<hb_pair_t <hb_tag_t, face_table_info_t>> sorted_entries;
|
||||||
data->tables.iter () | hb_sink (sorted_entries);
|
data->tables.iter () | hb_sink (sorted_entries);
|
||||||
if (unlikely (sorted_entries.in_error ()))
|
if (unlikely (sorted_entries.in_error ()))
|
||||||
{
|
{
|
||||||
|
@ -708,7 +717,13 @@ _hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
sorted_entries.qsort (compare_entries);
|
sorted_entries.qsort (compare_entries);
|
||||||
bool ret = f->serialize_single (&c, sfnt_tag, + sorted_entries.iter());
|
|
||||||
|
bool ret = f->serialize_single (&c,
|
||||||
|
sfnt_tag,
|
||||||
|
+ sorted_entries.iter()
|
||||||
|
| hb_map ([&] (hb_pair_t<hb_tag_t, face_table_info_t> _) {
|
||||||
|
return hb_pair_t<hb_tag_t, hb_blob_t*> (_.first, _.second.data);
|
||||||
|
}));
|
||||||
|
|
||||||
c.end_serialize ();
|
c.end_serialize ();
|
||||||
|
|
||||||
|
@ -729,7 +744,7 @@ _hb_face_builder_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void
|
||||||
if (!tag)
|
if (!tag)
|
||||||
return _hb_face_builder_data_reference_blob (data);
|
return _hb_face_builder_data_reference_blob (data);
|
||||||
|
|
||||||
return hb_blob_reference (data->tables[tag]);
|
return hb_blob_reference (data->tables[tag].data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -777,8 +792,8 @@ hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
|
||||||
|
|
||||||
hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
|
hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
|
||||||
|
|
||||||
hb_blob_t* previous = data->tables.get (tag);
|
hb_blob_t* previous = data->tables.get (tag).data;
|
||||||
if (!data->tables.set (tag, hb_blob_reference (blob)))
|
if (!data->tables.set (tag, face_table_info_t {hb_blob_reference (blob), 0}))
|
||||||
{
|
{
|
||||||
hb_blob_destroy (blob);
|
hb_blob_destroy (blob);
|
||||||
return false;
|
return false;
|
||||||
|
@ -787,3 +802,36 @@ hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
|
||||||
hb_blob_destroy (previous);
|
hb_blob_destroy (previous);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hb_face_builder_sort_tables:
|
||||||
|
* @face: A face object created with hb_face_builder_create()
|
||||||
|
* @tags: (array zero-terminated=1): ordered list of table tags terminated by
|
||||||
|
* %HB_TAG_NONE
|
||||||
|
*
|
||||||
|
* Set the ordering of tables for serialization. Any tables not
|
||||||
|
* specified in the tags list will be ordered after the tables in
|
||||||
|
* tags, ordered by the default sort ordering.
|
||||||
|
*
|
||||||
|
* Since: 5.3.0
|
||||||
|
**/
|
||||||
|
void
|
||||||
|
hb_face_builder_sort_tables (hb_face_t *face,
|
||||||
|
const hb_tag_t *tags)
|
||||||
|
{
|
||||||
|
hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
|
||||||
|
|
||||||
|
// Sort all unspecified tables after any specified tables.
|
||||||
|
for (auto& info : data->tables.values_ref())
|
||||||
|
info.order = -1;
|
||||||
|
|
||||||
|
unsigned order = 0;
|
||||||
|
for (const hb_tag_t* tag = tags;
|
||||||
|
*tag;
|
||||||
|
tag++)
|
||||||
|
{
|
||||||
|
face_table_info_t* info;
|
||||||
|
if (!data->tables.has (*tag, &info)) continue;
|
||||||
|
info->order = order++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -171,6 +171,10 @@ hb_face_builder_add_table (hb_face_t *face,
|
||||||
hb_tag_t tag,
|
hb_tag_t tag,
|
||||||
hb_blob_t *blob);
|
hb_blob_t *blob);
|
||||||
|
|
||||||
|
HB_EXTERN void
|
||||||
|
hb_face_builder_sort_tables (hb_face_t *face,
|
||||||
|
const hb_tag_t *tags);
|
||||||
|
|
||||||
|
|
||||||
HB_END_DECLS
|
HB_END_DECLS
|
||||||
|
|
||||||
|
|
|
@ -133,6 +133,18 @@ struct
|
||||||
|
|
||||||
template <typename T> constexpr auto
|
template <typename T> constexpr auto
|
||||||
operator () (T *v) const HB_AUTO_RETURN (*v)
|
operator () (T *v) const HB_AUTO_RETURN (*v)
|
||||||
|
|
||||||
|
template <typename T> constexpr auto
|
||||||
|
operator () (const hb::shared_ptr<T>& v) const HB_AUTO_RETURN (*v)
|
||||||
|
|
||||||
|
template <typename T> constexpr auto
|
||||||
|
operator () (hb::shared_ptr<T>& v) const HB_AUTO_RETURN (*v)
|
||||||
|
|
||||||
|
template <typename T> constexpr auto
|
||||||
|
operator () (const hb::unique_ptr<T>& v) const HB_AUTO_RETURN (*v)
|
||||||
|
|
||||||
|
template <typename T> constexpr auto
|
||||||
|
operator () (hb::unique_ptr<T>& v) const HB_AUTO_RETURN (*v)
|
||||||
}
|
}
|
||||||
HB_FUNCOBJ (hb_deref);
|
HB_FUNCOBJ (hb_deref);
|
||||||
|
|
||||||
|
|
|
@ -141,27 +141,24 @@ typedef HBINT32 FWORD32;
|
||||||
/* 16-bit unsigned integer (HBUINT16) that describes a quantity in FUnits. */
|
/* 16-bit unsigned integer (HBUINT16) that describes a quantity in FUnits. */
|
||||||
typedef HBUINT16 UFWORD;
|
typedef HBUINT16 UFWORD;
|
||||||
|
|
||||||
/* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
|
template <typename Type, unsigned fraction_bits>
|
||||||
struct F2DOT14 : HBINT16
|
struct HBFixed : Type
|
||||||
{
|
{
|
||||||
F2DOT14& operator = (uint16_t i ) { HBINT16::operator= (i); return *this; }
|
static constexpr float shift = (float) (1 << fraction_bits);
|
||||||
// 16384 means 1<<14
|
static_assert (Type::static_size * 8 > fraction_bits, "");
|
||||||
float to_float () const { return ((int32_t) v) / 16384.f; }
|
|
||||||
void set_float (float f) { v = roundf (f * 16384.f); }
|
HBFixed& operator = (typename Type::type i ) { Type::operator= (i); return *this; }
|
||||||
|
float to_float () const { return ((int32_t) Type::v) / shift; }
|
||||||
|
void set_float (float f) { Type::v = roundf (f * shift); }
|
||||||
public:
|
public:
|
||||||
DEFINE_SIZE_STATIC (2);
|
DEFINE_SIZE_STATIC (Type::static_size);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
|
||||||
|
using F2DOT14 = HBFixed<HBINT16, 14>;
|
||||||
|
|
||||||
/* 32-bit signed fixed-point number (16.16). */
|
/* 32-bit signed fixed-point number (16.16). */
|
||||||
struct HBFixed : HBINT32
|
using F16DOT16 = HBFixed<HBINT32, 16>;
|
||||||
{
|
|
||||||
HBFixed& operator = (uint32_t i) { HBINT32::operator= (i); return *this; }
|
|
||||||
// 65536 means 1<<16
|
|
||||||
float to_float () const { return ((int32_t) v) / 65536.f; }
|
|
||||||
void set_float (float f) { v = roundf (f * 65536.f); }
|
|
||||||
public:
|
|
||||||
DEFINE_SIZE_STATIC (4);
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Date represented in number of seconds since 12:00 midnight, January 1,
|
/* Date represented in number of seconds since 12:00 midnight, January 1,
|
||||||
* 1904. The value is represented as a signed 64-bit integer. */
|
* 1904. The value is represented as a signed 64-bit integer. */
|
||||||
|
|
|
@ -358,14 +358,14 @@ struct Affine2x3
|
||||||
return_trace (c->check_struct (this));
|
return_trace (c->check_struct (this));
|
||||||
}
|
}
|
||||||
|
|
||||||
HBFixed xx;
|
F16DOT16 xx;
|
||||||
HBFixed yx;
|
F16DOT16 yx;
|
||||||
HBFixed xy;
|
F16DOT16 xy;
|
||||||
HBFixed yy;
|
F16DOT16 yy;
|
||||||
HBFixed dx;
|
F16DOT16 dx;
|
||||||
HBFixed dy;
|
F16DOT16 dy;
|
||||||
public:
|
public:
|
||||||
DEFINE_SIZE_STATIC (6 * HBFixed::static_size);
|
DEFINE_SIZE_STATIC (6 * F16DOT16::static_size);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PaintColrLayers
|
struct PaintColrLayers
|
||||||
|
|
|
@ -295,8 +295,8 @@ hb_ot_color_has_png (hb_face_t *face)
|
||||||
* @glyph: a glyph index
|
* @glyph: a glyph index
|
||||||
*
|
*
|
||||||
* Fetches the PNG image for a glyph. This function takes a font object, not a face object,
|
* Fetches the PNG image for a glyph. This function takes a font object, not a face object,
|
||||||
* as input. To get an optimally sized PNG blob, the UPEM value must be set on the @font
|
* as input. To get an optimally sized PNG blob, the PPEM values must be set on the @font
|
||||||
* object. If UPEM is unset, the blob returned will be the largest PNG available.
|
* object. If PPEM is unset, the blob returned will be the largest PNG available.
|
||||||
*
|
*
|
||||||
* If the glyph has no PNG image, the singleton empty blob is returned.
|
* If the glyph has no PNG image, the singleton empty blob is returned.
|
||||||
*
|
*
|
||||||
|
|
|
@ -40,7 +40,6 @@
|
||||||
#include "hb-ot-cff1-table.hh"
|
#include "hb-ot-cff1-table.hh"
|
||||||
#include "hb-ot-cff2-table.hh"
|
#include "hb-ot-cff2-table.hh"
|
||||||
#include "hb-ot-hmtx-table.hh"
|
#include "hb-ot-hmtx-table.hh"
|
||||||
#include "hb-ot-os2-table.hh"
|
|
||||||
#include "hb-ot-post-table.hh"
|
#include "hb-ot-post-table.hh"
|
||||||
#include "hb-ot-stat-table.hh" // Just so we compile it; unused otherwise.
|
#include "hb-ot-stat-table.hh" // Just so we compile it; unused otherwise.
|
||||||
#include "hb-ot-vorg-table.hh"
|
#include "hb-ot-vorg-table.hh"
|
||||||
|
@ -349,15 +348,13 @@ hb_ot_get_glyph_extents (hb_font_t *font,
|
||||||
|
|
||||||
#if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
|
#if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
|
||||||
if (ot_face->sbix->get_extents (font, glyph, extents)) return true;
|
if (ot_face->sbix->get_extents (font, glyph, extents)) return true;
|
||||||
|
if (ot_face->CBDT->get_extents (font, glyph, extents)) return true;
|
||||||
#endif
|
#endif
|
||||||
if (ot_face->glyf->get_extents (font, glyph, extents)) return true;
|
if (ot_face->glyf->get_extents (font, glyph, extents)) return true;
|
||||||
#ifndef HB_NO_OT_FONT_CFF
|
#ifndef HB_NO_OT_FONT_CFF
|
||||||
if (ot_face->cff1->get_extents (font, glyph, extents)) return true;
|
if (ot_face->cff1->get_extents (font, glyph, extents)) return true;
|
||||||
if (ot_face->cff2->get_extents (font, glyph, extents)) return true;
|
if (ot_face->cff2->get_extents (font, glyph, extents)) return true;
|
||||||
#endif
|
#endif
|
||||||
#if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
|
|
||||||
if (ot_face->CBDT->get_extents (font, glyph, extents)) return true;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// TODO Hook up side-bearings variations.
|
// TODO Hook up side-bearings variations.
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -94,6 +94,19 @@ static bool ClassDef_remap_and_serialize (
|
||||||
hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> &glyph_and_klass, /* IN/OUT */
|
hb_sorted_vector_t<hb_pair_t<hb_codepoint_t, hb_codepoint_t>> &glyph_and_klass, /* IN/OUT */
|
||||||
hb_map_t *klass_map /*IN/OUT*/);
|
hb_map_t *klass_map /*IN/OUT*/);
|
||||||
|
|
||||||
|
struct hb_collect_feature_substitutes_with_var_context_t
|
||||||
|
{
|
||||||
|
const hb_map_t *axes_index_tag_map;
|
||||||
|
const hb_hashmap_t<hb_tag_t, int> *axes_location;
|
||||||
|
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *record_cond_idx_map;
|
||||||
|
hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map;
|
||||||
|
|
||||||
|
// not stored in subset_plan
|
||||||
|
hb_set_t *feature_indices;
|
||||||
|
bool apply;
|
||||||
|
unsigned cur_record_idx;
|
||||||
|
hb_hashmap_t<hb::shared_ptr<hb_map_t>, unsigned> *conditionset_map;
|
||||||
|
};
|
||||||
|
|
||||||
struct hb_prune_langsys_context_t
|
struct hb_prune_langsys_context_t
|
||||||
{
|
{
|
||||||
|
@ -160,24 +173,40 @@ struct hb_subset_layout_context_t :
|
||||||
const hb_map_t *lookup_index_map;
|
const hb_map_t *lookup_index_map;
|
||||||
const hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map;
|
const hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map;
|
||||||
const hb_map_t *feature_index_map;
|
const hb_map_t *feature_index_map;
|
||||||
|
const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map;
|
||||||
|
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map;
|
||||||
|
|
||||||
unsigned cur_script_index;
|
unsigned cur_script_index;
|
||||||
|
unsigned cur_feature_var_record_idx;
|
||||||
|
|
||||||
hb_subset_layout_context_t (hb_subset_context_t *c_,
|
hb_subset_layout_context_t (hb_subset_context_t *c_,
|
||||||
hb_tag_t tag_,
|
hb_tag_t tag_) :
|
||||||
hb_map_t *lookup_map_,
|
|
||||||
hb_hashmap_t<unsigned, hb::unique_ptr<hb_set_t>> *script_langsys_map_,
|
|
||||||
hb_map_t *feature_index_map_) :
|
|
||||||
subset_context (c_),
|
subset_context (c_),
|
||||||
table_tag (tag_),
|
table_tag (tag_),
|
||||||
lookup_index_map (lookup_map_),
|
|
||||||
script_langsys_map (script_langsys_map_),
|
|
||||||
feature_index_map (feature_index_map_),
|
|
||||||
cur_script_index (0xFFFFu),
|
cur_script_index (0xFFFFu),
|
||||||
|
cur_feature_var_record_idx (0u),
|
||||||
script_count (0),
|
script_count (0),
|
||||||
langsys_count (0),
|
langsys_count (0),
|
||||||
feature_index_count (0),
|
feature_index_count (0),
|
||||||
lookup_index_count (0)
|
lookup_index_count (0)
|
||||||
{}
|
{
|
||||||
|
if (tag_ == HB_OT_TAG_GSUB)
|
||||||
|
{
|
||||||
|
lookup_index_map = c_->plan->gsub_lookups;
|
||||||
|
script_langsys_map = c_->plan->gsub_langsys;
|
||||||
|
feature_index_map = c_->plan->gsub_features;
|
||||||
|
feature_substitutes_map = c_->plan->gsub_feature_substitutes_map;
|
||||||
|
feature_record_cond_idx_map = c_->plan->user_axes_location->is_empty () ? nullptr : c_->plan->gsub_feature_record_cond_idx_map;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lookup_index_map = c_->plan->gpos_lookups;
|
||||||
|
script_langsys_map = c_->plan->gpos_langsys;
|
||||||
|
feature_index_map = c_->plan->gpos_features;
|
||||||
|
feature_substitutes_map = c_->plan->gpos_feature_substitutes_map;
|
||||||
|
feature_record_cond_idx_map = c_->plan->user_axes_location->is_empty () ? nullptr : c_->plan->gpos_feature_record_cond_idx_map;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned script_count;
|
unsigned script_count;
|
||||||
|
@ -324,6 +353,31 @@ struct subset_record_array_t
|
||||||
const void *base;
|
const void *base;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename OutputArray, typename Arg>
|
||||||
|
struct subset_record_array_arg_t
|
||||||
|
{
|
||||||
|
subset_record_array_arg_t (hb_subset_layout_context_t *c_, OutputArray* out_,
|
||||||
|
const void *base_,
|
||||||
|
Arg &&arg_) : subset_layout_context (c_),
|
||||||
|
out (out_), base (base_), arg (arg_) {}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void
|
||||||
|
operator () (T&& record)
|
||||||
|
{
|
||||||
|
auto snap = subset_layout_context->subset_context->serializer->snapshot ();
|
||||||
|
bool ret = record.subset (subset_layout_context, base, arg);
|
||||||
|
if (!ret) subset_layout_context->subset_context->serializer->revert (snap);
|
||||||
|
else out->len++;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
hb_subset_layout_context_t *subset_layout_context;
|
||||||
|
OutputArray *out;
|
||||||
|
const void *base;
|
||||||
|
Arg &&arg;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Helper to subset a RecordList/record array. Subsets each Record in the array and
|
* Helper to subset a RecordList/record array. Subsets each Record in the array and
|
||||||
* discards the record if the subset operation returns false.
|
* discards the record if the subset operation returns false.
|
||||||
|
@ -335,6 +389,13 @@ struct
|
||||||
operator () (hb_subset_layout_context_t *c, OutputArray* out,
|
operator () (hb_subset_layout_context_t *c, OutputArray* out,
|
||||||
const void *base) const
|
const void *base) const
|
||||||
{ return subset_record_array_t<OutputArray> (c, out, base); }
|
{ return subset_record_array_t<OutputArray> (c, out, base); }
|
||||||
|
|
||||||
|
/* Variant with one extra argument passed to subset */
|
||||||
|
template<typename OutputArray, typename Arg>
|
||||||
|
subset_record_array_arg_t<OutputArray, Arg>
|
||||||
|
operator () (hb_subset_layout_context_t *c, OutputArray* out,
|
||||||
|
const void *base, Arg &&arg) const
|
||||||
|
{ return subset_record_array_arg_t<OutputArray, Arg> (c, out, base, arg); }
|
||||||
}
|
}
|
||||||
HB_FUNCOBJ (subset_record_array);
|
HB_FUNCOBJ (subset_record_array);
|
||||||
|
|
||||||
|
@ -431,94 +492,6 @@ struct IndexArray : Array16Of<Index>
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct Record_sanitize_closure_t {
|
|
||||||
hb_tag_t tag;
|
|
||||||
const void *list_base;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Type>
|
|
||||||
struct Record
|
|
||||||
{
|
|
||||||
int cmp (hb_tag_t a) const { return tag.cmp (a); }
|
|
||||||
|
|
||||||
bool subset (hb_subset_layout_context_t *c, const void *base) const
|
|
||||||
{
|
|
||||||
TRACE_SUBSET (this);
|
|
||||||
auto *out = c->subset_context->serializer->embed (this);
|
|
||||||
if (unlikely (!out)) return_trace (false);
|
|
||||||
bool ret = out->offset.serialize_subset (c->subset_context, offset, base, c, &tag);
|
|
||||||
return_trace (ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
|
||||||
{
|
|
||||||
TRACE_SANITIZE (this);
|
|
||||||
const Record_sanitize_closure_t closure = {tag, base};
|
|
||||||
return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure));
|
|
||||||
}
|
|
||||||
|
|
||||||
Tag tag; /* 4-byte Tag identifier */
|
|
||||||
Offset16To<Type>
|
|
||||||
offset; /* Offset from beginning of object holding
|
|
||||||
* the Record */
|
|
||||||
public:
|
|
||||||
DEFINE_SIZE_STATIC (6);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Type>
|
|
||||||
struct RecordArrayOf : SortedArray16Of<Record<Type>>
|
|
||||||
{
|
|
||||||
const Offset16To<Type>& get_offset (unsigned int i) const
|
|
||||||
{ return (*this)[i].offset; }
|
|
||||||
Offset16To<Type>& get_offset (unsigned int i)
|
|
||||||
{ return (*this)[i].offset; }
|
|
||||||
const Tag& get_tag (unsigned int i) const
|
|
||||||
{ return (*this)[i].tag; }
|
|
||||||
unsigned int get_tags (unsigned int start_offset,
|
|
||||||
unsigned int *record_count /* IN/OUT */,
|
|
||||||
hb_tag_t *record_tags /* OUT */) const
|
|
||||||
{
|
|
||||||
if (record_count)
|
|
||||||
{
|
|
||||||
+ this->sub_array (start_offset, record_count)
|
|
||||||
| hb_map (&Record<Type>::tag)
|
|
||||||
| hb_sink (hb_array (record_tags, *record_count))
|
|
||||||
;
|
|
||||||
}
|
|
||||||
return this->len;
|
|
||||||
}
|
|
||||||
bool find_index (hb_tag_t tag, unsigned int *index) const
|
|
||||||
{
|
|
||||||
return this->bfind (tag, index, HB_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Type>
|
|
||||||
struct RecordListOf : RecordArrayOf<Type>
|
|
||||||
{
|
|
||||||
const Type& operator [] (unsigned int i) const
|
|
||||||
{ return this+this->get_offset (i); }
|
|
||||||
|
|
||||||
bool subset (hb_subset_context_t *c,
|
|
||||||
hb_subset_layout_context_t *l) const
|
|
||||||
{
|
|
||||||
TRACE_SUBSET (this);
|
|
||||||
auto *out = c->serializer->start_embed (*this);
|
|
||||||
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
|
|
||||||
|
|
||||||
+ this->iter ()
|
|
||||||
| hb_apply (subset_record_array (l, out, this))
|
|
||||||
;
|
|
||||||
return_trace (true);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool sanitize (hb_sanitize_context_t *c) const
|
|
||||||
{
|
|
||||||
TRACE_SANITIZE (this);
|
|
||||||
return_trace (RecordArrayOf<Type>::sanitize (c, this));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */
|
/* https://docs.microsoft.com/en-us/typography/opentype/spec/features_pt#size */
|
||||||
struct FeatureParamsSize
|
struct FeatureParamsSize
|
||||||
{
|
{
|
||||||
|
@ -801,6 +774,10 @@ struct FeatureParams
|
||||||
DEFINE_SIZE_MIN (0);
|
DEFINE_SIZE_MIN (0);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Record_sanitize_closure_t {
|
||||||
|
hb_tag_t tag;
|
||||||
|
const void *list_base;
|
||||||
|
};
|
||||||
|
|
||||||
struct Feature
|
struct Feature
|
||||||
{
|
{
|
||||||
|
@ -897,6 +874,103 @@ struct Feature
|
||||||
DEFINE_SIZE_ARRAY_SIZED (4, lookupIndex);
|
DEFINE_SIZE_ARRAY_SIZED (4, lookupIndex);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
struct Record
|
||||||
|
{
|
||||||
|
int cmp (hb_tag_t a) const { return tag.cmp (a); }
|
||||||
|
|
||||||
|
bool subset (hb_subset_layout_context_t *c, const void *base, const void *f_sub = nullptr) const
|
||||||
|
{
|
||||||
|
TRACE_SUBSET (this);
|
||||||
|
auto *out = c->subset_context->serializer->embed (this);
|
||||||
|
if (unlikely (!out)) return_trace (false);
|
||||||
|
|
||||||
|
if (!f_sub)
|
||||||
|
return_trace (out->offset.serialize_subset (c->subset_context, offset, base, c, &tag));
|
||||||
|
|
||||||
|
const Feature& f = *reinterpret_cast<const Feature *> (f_sub);
|
||||||
|
auto *s = c->subset_context->serializer;
|
||||||
|
s->push ();
|
||||||
|
|
||||||
|
out->offset = 0;
|
||||||
|
bool ret = f.subset (c->subset_context, c, &tag);
|
||||||
|
if (ret)
|
||||||
|
s->add_link (out->offset, s->pop_pack ());
|
||||||
|
else
|
||||||
|
s->pop_discard ();
|
||||||
|
|
||||||
|
return_trace (ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||||
|
{
|
||||||
|
TRACE_SANITIZE (this);
|
||||||
|
const Record_sanitize_closure_t closure = {tag, base};
|
||||||
|
return_trace (c->check_struct (this) && offset.sanitize (c, base, &closure));
|
||||||
|
}
|
||||||
|
|
||||||
|
Tag tag; /* 4-byte Tag identifier */
|
||||||
|
Offset16To<Type>
|
||||||
|
offset; /* Offset from beginning of object holding
|
||||||
|
* the Record */
|
||||||
|
public:
|
||||||
|
DEFINE_SIZE_STATIC (6);
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
struct RecordArrayOf : SortedArray16Of<Record<Type>>
|
||||||
|
{
|
||||||
|
const Offset16To<Type>& get_offset (unsigned int i) const
|
||||||
|
{ return (*this)[i].offset; }
|
||||||
|
Offset16To<Type>& get_offset (unsigned int i)
|
||||||
|
{ return (*this)[i].offset; }
|
||||||
|
const Tag& get_tag (unsigned int i) const
|
||||||
|
{ return (*this)[i].tag; }
|
||||||
|
unsigned int get_tags (unsigned int start_offset,
|
||||||
|
unsigned int *record_count /* IN/OUT */,
|
||||||
|
hb_tag_t *record_tags /* OUT */) const
|
||||||
|
{
|
||||||
|
if (record_count)
|
||||||
|
{
|
||||||
|
+ this->sub_array (start_offset, record_count)
|
||||||
|
| hb_map (&Record<Type>::tag)
|
||||||
|
| hb_sink (hb_array (record_tags, *record_count))
|
||||||
|
;
|
||||||
|
}
|
||||||
|
return this->len;
|
||||||
|
}
|
||||||
|
bool find_index (hb_tag_t tag, unsigned int *index) const
|
||||||
|
{
|
||||||
|
return this->bfind (tag, index, HB_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
struct RecordListOf : RecordArrayOf<Type>
|
||||||
|
{
|
||||||
|
const Type& operator [] (unsigned int i) const
|
||||||
|
{ return this+this->get_offset (i); }
|
||||||
|
|
||||||
|
bool subset (hb_subset_context_t *c,
|
||||||
|
hb_subset_layout_context_t *l) const
|
||||||
|
{
|
||||||
|
TRACE_SUBSET (this);
|
||||||
|
auto *out = c->serializer->start_embed (*this);
|
||||||
|
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
|
||||||
|
|
||||||
|
+ this->iter ()
|
||||||
|
| hb_apply (subset_record_array (l, out, this))
|
||||||
|
;
|
||||||
|
return_trace (true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sanitize (hb_sanitize_context_t *c) const
|
||||||
|
{
|
||||||
|
TRACE_SANITIZE (this);
|
||||||
|
return_trace (RecordArrayOf<Type>::sanitize (c, this));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct RecordListOfFeature : RecordListOf<Feature>
|
struct RecordListOfFeature : RecordListOf<Feature>
|
||||||
{
|
{
|
||||||
bool subset (hb_subset_context_t *c,
|
bool subset (hb_subset_context_t *c,
|
||||||
|
@ -907,11 +981,20 @@ struct RecordListOfFeature : RecordListOf<Feature>
|
||||||
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
|
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
|
||||||
|
|
||||||
unsigned count = this->len;
|
unsigned count = this->len;
|
||||||
|
|
||||||
+ hb_zip (*this, hb_range (count))
|
+ hb_zip (*this, hb_range (count))
|
||||||
| hb_filter (l->feature_index_map, hb_second)
|
| hb_filter (l->feature_index_map, hb_second)
|
||||||
| hb_map (hb_first)
|
| hb_apply ([l, out, this] (const hb_pair_t<const Record<Feature>&, unsigned>& _)
|
||||||
| hb_apply (subset_record_array (l, out, this))
|
{
|
||||||
|
const Feature *f_sub = nullptr;
|
||||||
|
const Feature **f = nullptr;
|
||||||
|
if (l->feature_substitutes_map->has (_.second, &f))
|
||||||
|
f_sub = *f;
|
||||||
|
|
||||||
|
subset_record_array (l, out, this, f_sub) (_.first);
|
||||||
|
})
|
||||||
;
|
;
|
||||||
|
|
||||||
return_trace (true);
|
return_trace (true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -996,7 +1079,7 @@ struct LangSys
|
||||||
auto *out = c->serializer->start_embed (*this);
|
auto *out = c->serializer->start_embed (*this);
|
||||||
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
|
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
|
||||||
|
|
||||||
const unsigned *v;
|
const uint32_t *v;
|
||||||
out->reqFeatureIndex = l->feature_index_map->has (reqFeatureIndex, &v) ? *v : 0xFFFFu;
|
out->reqFeatureIndex = l->feature_index_map->has (reqFeatureIndex, &v) ? *v : 0xFFFFu;
|
||||||
|
|
||||||
if (!l->visitFeatureIndex (featureIndex.len))
|
if (!l->visitFeatureIndex (featureIndex.len))
|
||||||
|
@ -1305,7 +1388,13 @@ struct Lookup
|
||||||
outMarkFilteringSet = markFilteringSet;
|
outMarkFilteringSet = markFilteringSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
return_trace (out->subTable.len);
|
// Always keep the lookup even if it's empty. The rest of layout subsetting depends on lookup
|
||||||
|
// indices being consistent with those computed during planning. So if an empty lookup is
|
||||||
|
// discarded during the subset phase it will invalidate all subsequent lookup indices.
|
||||||
|
// Generally we shouldn't end up with an empty lookup as we pre-prune them during the planning
|
||||||
|
// phase, but it can happen in rare cases such as when during closure subtable is considered
|
||||||
|
// degenerate (see: https://github.com/harfbuzz/harfbuzz/issues/3853)
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename TSubTable>
|
template <typename TSubTable>
|
||||||
|
@ -1465,7 +1554,7 @@ struct ClassDefFormat1_3
|
||||||
|
|
||||||
startGlyph = glyph_min;
|
startGlyph = glyph_min;
|
||||||
if (unlikely (!classValue.serialize (c, glyph_count))) return_trace (false);
|
if (unlikely (!classValue.serialize (c, glyph_count))) return_trace (false);
|
||||||
for (const hb_pair_t<hb_codepoint_t, unsigned> gid_klass_pair : + it)
|
for (const hb_pair_t<hb_codepoint_t, uint32_t> gid_klass_pair : + it)
|
||||||
{
|
{
|
||||||
unsigned idx = gid_klass_pair.first - glyph_min;
|
unsigned idx = gid_klass_pair.first - glyph_min;
|
||||||
classValue[idx] = gid_klass_pair.second;
|
classValue[idx] = gid_klass_pair.second;
|
||||||
|
@ -1592,11 +1681,11 @@ struct ClassDefFormat1_3
|
||||||
if (klass == 0)
|
if (klass == 0)
|
||||||
{
|
{
|
||||||
unsigned start_glyph = startGlyph;
|
unsigned start_glyph = startGlyph;
|
||||||
for (unsigned g = HB_SET_VALUE_INVALID;
|
for (uint32_t g = HB_SET_VALUE_INVALID;
|
||||||
hb_set_next (glyphs, &g) && g < start_glyph;)
|
hb_set_next (glyphs, &g) && g < start_glyph;)
|
||||||
intersect_glyphs->add (g);
|
intersect_glyphs->add (g);
|
||||||
|
|
||||||
for (unsigned g = startGlyph + count - 1;
|
for (uint32_t g = startGlyph + count - 1;
|
||||||
hb_set_next (glyphs, &g);)
|
hb_set_next (glyphs, &g);)
|
||||||
intersect_glyphs->add (g);
|
intersect_glyphs->add (g);
|
||||||
|
|
||||||
|
@ -2692,6 +2781,13 @@ struct VariationStore
|
||||||
/*
|
/*
|
||||||
* Feature Variations
|
* Feature Variations
|
||||||
*/
|
*/
|
||||||
|
enum Cond_with_Var_flag_t
|
||||||
|
{
|
||||||
|
KEEP_COND_WITH_VAR = 0,
|
||||||
|
DROP_COND_WITH_VAR = 1,
|
||||||
|
DROP_RECORD_WITH_VAR = 2,
|
||||||
|
MEM_ERR_WITH_VAR = 3,
|
||||||
|
};
|
||||||
|
|
||||||
struct ConditionFormat1
|
struct ConditionFormat1
|
||||||
{
|
{
|
||||||
|
@ -2702,10 +2798,52 @@ struct ConditionFormat1
|
||||||
TRACE_SUBSET (this);
|
TRACE_SUBSET (this);
|
||||||
auto *out = c->serializer->embed (this);
|
auto *out = c->serializer->embed (this);
|
||||||
if (unlikely (!out)) return_trace (false);
|
if (unlikely (!out)) return_trace (false);
|
||||||
return_trace (true);
|
|
||||||
|
const hb_map_t *index_map = c->plan->axes_index_map;
|
||||||
|
if (index_map->is_empty ()) return_trace (true);
|
||||||
|
|
||||||
|
if (!index_map->has (axisIndex))
|
||||||
|
return_trace (false);
|
||||||
|
|
||||||
|
return_trace (c->serializer->check_assign (out->axisIndex, index_map->get (axisIndex),
|
||||||
|
HB_SERIALIZE_ERROR_INT_OVERFLOW));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c,
|
||||||
|
hb_map_t *condition_map /* OUT */) const
|
||||||
|
{
|
||||||
|
//invalid axis index, drop the entire record
|
||||||
|
if (!c->axes_index_tag_map->has (axisIndex))
|
||||||
|
return DROP_RECORD_WITH_VAR;
|
||||||
|
|
||||||
|
hb_tag_t axis_tag = c->axes_index_tag_map->get (axisIndex);
|
||||||
|
|
||||||
|
//axis not pinned, keep the condition
|
||||||
|
if (!c->axes_location->has (axis_tag))
|
||||||
|
{
|
||||||
|
// add axisIndex->value into the hashmap so we can check if the record is
|
||||||
|
// unique with variations
|
||||||
|
int16_t min_val = filterRangeMinValue;
|
||||||
|
int16_t max_val = filterRangeMaxValue;
|
||||||
|
hb_codepoint_t val = (max_val << 16) + min_val;
|
||||||
|
|
||||||
|
condition_map->set (axisIndex, val);
|
||||||
|
return KEEP_COND_WITH_VAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
//axis pinned, check if condition is met
|
||||||
|
//TODO: add check for axis Ranges
|
||||||
|
int v = c->axes_location->get (axis_tag);
|
||||||
|
|
||||||
|
//condition not met, drop the entire record
|
||||||
|
if (v < filterRangeMinValue || v > filterRangeMaxValue)
|
||||||
|
return DROP_RECORD_WITH_VAR;
|
||||||
|
|
||||||
|
//axis pinned and condition met, drop the condition
|
||||||
|
return DROP_COND_WITH_VAR;
|
||||||
|
}
|
||||||
|
|
||||||
bool evaluate (const int *coords, unsigned int coord_len) const
|
bool evaluate (const int *coords, unsigned int coord_len) const
|
||||||
{
|
{
|
||||||
int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
|
int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
|
||||||
|
@ -2737,6 +2875,15 @@ struct Condition
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c,
|
||||||
|
hb_map_t *condition_map /* OUT */) const
|
||||||
|
{
|
||||||
|
switch (u.format) {
|
||||||
|
case 1: return u.format1.keep_with_variations (c, condition_map);
|
||||||
|
default:return KEEP_COND_WITH_VAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <typename context_t, typename ...Ts>
|
template <typename context_t, typename ...Ts>
|
||||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||||
{
|
{
|
||||||
|
@ -2778,15 +2925,65 @@ struct ConditionSet
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool subset (hb_subset_context_t *c) const
|
Cond_with_Var_flag_t keep_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
|
||||||
|
{
|
||||||
|
hb_map_t *condition_map = hb_map_create ();
|
||||||
|
if (unlikely (!condition_map)) return MEM_ERR_WITH_VAR;
|
||||||
|
hb::shared_ptr<hb_map_t> p {condition_map};
|
||||||
|
|
||||||
|
hb_set_t *cond_set = hb_set_create ();
|
||||||
|
if (unlikely (!cond_set)) return MEM_ERR_WITH_VAR;
|
||||||
|
hb::shared_ptr<hb_set_t> s {cond_set};
|
||||||
|
|
||||||
|
unsigned num_kept_cond = 0, cond_idx = 0;
|
||||||
|
for (const auto& offset : conditions)
|
||||||
|
{
|
||||||
|
Cond_with_Var_flag_t ret = (this+offset).keep_with_variations (c, condition_map);
|
||||||
|
// one condition is not met, drop the entire record
|
||||||
|
if (ret == DROP_RECORD_WITH_VAR)
|
||||||
|
return DROP_RECORD_WITH_VAR;
|
||||||
|
|
||||||
|
// axis not pinned, keep this condition
|
||||||
|
if (ret == KEEP_COND_WITH_VAR)
|
||||||
|
{
|
||||||
|
cond_set->add (cond_idx);
|
||||||
|
num_kept_cond++;
|
||||||
|
}
|
||||||
|
cond_idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// all conditions met
|
||||||
|
if (num_kept_cond == 0) return DROP_COND_WITH_VAR;
|
||||||
|
|
||||||
|
//check if condition_set is unique with variations
|
||||||
|
if (c->conditionset_map->has (p))
|
||||||
|
//duplicate found, drop the entire record
|
||||||
|
return DROP_RECORD_WITH_VAR;
|
||||||
|
|
||||||
|
c->conditionset_map->set (p, 1);
|
||||||
|
c->record_cond_idx_map->set (c->cur_record_idx, s);
|
||||||
|
|
||||||
|
return KEEP_COND_WITH_VAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool subset (hb_subset_context_t *c,
|
||||||
|
hb_subset_layout_context_t *l) const
|
||||||
{
|
{
|
||||||
TRACE_SUBSET (this);
|
TRACE_SUBSET (this);
|
||||||
auto *out = c->serializer->start_embed (this);
|
auto *out = c->serializer->start_embed (this);
|
||||||
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
|
if (unlikely (!out || !c->serializer->extend_min (out))) return_trace (false);
|
||||||
|
|
||||||
+ conditions.iter ()
|
hb_set_t *retained_cond_set = nullptr;
|
||||||
| hb_apply (subset_offset_array (c, out->conditions, this))
|
if (l->feature_record_cond_idx_map != nullptr)
|
||||||
;
|
retained_cond_set = l->feature_record_cond_idx_map->get (l->cur_feature_var_record_idx);
|
||||||
|
|
||||||
|
unsigned int count = conditions.len;
|
||||||
|
for (unsigned int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
if (retained_cond_set != nullptr && !retained_cond_set->has (i))
|
||||||
|
continue;
|
||||||
|
subset_offset_array (c, out->conditions, this) (conditions[i]);
|
||||||
|
}
|
||||||
|
|
||||||
return_trace (bool (out->conditions));
|
return_trace (bool (out->conditions));
|
||||||
}
|
}
|
||||||
|
@ -2820,10 +3017,19 @@ struct FeatureTableSubstitutionRecord
|
||||||
feature_indexes->add (featureIndex);
|
feature_indexes->add (featureIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void collect_feature_substitutes_with_variations (hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
|
||||||
|
const hb_set_t *feature_indices,
|
||||||
|
const void *base) const
|
||||||
|
{
|
||||||
|
if (feature_indices->has (featureIndex))
|
||||||
|
feature_substitutes_map->set (featureIndex, &(base+feature));
|
||||||
|
}
|
||||||
|
|
||||||
bool subset (hb_subset_layout_context_t *c, const void *base) const
|
bool subset (hb_subset_layout_context_t *c, const void *base) const
|
||||||
{
|
{
|
||||||
TRACE_SUBSET (this);
|
TRACE_SUBSET (this);
|
||||||
if (!c->feature_index_map->has (featureIndex)) {
|
if (!c->feature_index_map->has (featureIndex) ||
|
||||||
|
c->feature_substitutes_map->has (featureIndex)) {
|
||||||
// Feature that is being substituted is not being retained, so we don't
|
// Feature that is being substituted is not being retained, so we don't
|
||||||
// need this.
|
// need this.
|
||||||
return_trace (false);
|
return_trace (false);
|
||||||
|
@ -2865,10 +3071,16 @@ struct FeatureTableSubstitution
|
||||||
}
|
}
|
||||||
|
|
||||||
void collect_lookups (const hb_set_t *feature_indexes,
|
void collect_lookups (const hb_set_t *feature_indexes,
|
||||||
|
const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
|
||||||
hb_set_t *lookup_indexes /* OUT */) const
|
hb_set_t *lookup_indexes /* OUT */) const
|
||||||
{
|
{
|
||||||
+ hb_iter (substitutions)
|
+ hb_iter (substitutions)
|
||||||
| hb_filter (feature_indexes, &FeatureTableSubstitutionRecord::featureIndex)
|
| hb_filter (feature_indexes, &FeatureTableSubstitutionRecord::featureIndex)
|
||||||
|
| hb_filter ([feature_substitutes_map] (const FeatureTableSubstitutionRecord& record)
|
||||||
|
{
|
||||||
|
if (feature_substitutes_map == nullptr) return true;
|
||||||
|
return !feature_substitutes_map->has (record.featureIndex);
|
||||||
|
})
|
||||||
| hb_apply ([this, lookup_indexes] (const FeatureTableSubstitutionRecord& r)
|
| hb_apply ([this, lookup_indexes] (const FeatureTableSubstitutionRecord& r)
|
||||||
{ r.collect_lookups (this, lookup_indexes); })
|
{ r.collect_lookups (this, lookup_indexes); })
|
||||||
;
|
;
|
||||||
|
@ -2890,6 +3102,12 @@ struct FeatureTableSubstitution
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
|
||||||
|
{
|
||||||
|
for (const FeatureTableSubstitutionRecord& record : substitutions)
|
||||||
|
record.collect_feature_substitutes_with_variations (c->feature_substitutes_map, c->feature_indices, this);
|
||||||
|
}
|
||||||
|
|
||||||
bool subset (hb_subset_context_t *c,
|
bool subset (hb_subset_context_t *c,
|
||||||
hb_subset_layout_context_t *l) const
|
hb_subset_layout_context_t *l) const
|
||||||
{
|
{
|
||||||
|
@ -2929,9 +3147,10 @@ struct FeatureVariationRecord
|
||||||
|
|
||||||
void collect_lookups (const void *base,
|
void collect_lookups (const void *base,
|
||||||
const hb_set_t *feature_indexes,
|
const hb_set_t *feature_indexes,
|
||||||
|
const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
|
||||||
hb_set_t *lookup_indexes /* OUT */) const
|
hb_set_t *lookup_indexes /* OUT */) const
|
||||||
{
|
{
|
||||||
return (base+substitutions).collect_lookups (feature_indexes, lookup_indexes);
|
return (base+substitutions).collect_lookups (feature_indexes, feature_substitutes_map, lookup_indexes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void closure_features (const void *base,
|
void closure_features (const void *base,
|
||||||
|
@ -2946,13 +3165,25 @@ struct FeatureVariationRecord
|
||||||
return (base+substitutions).intersects_features (feature_index_map);
|
return (base+substitutions).intersects_features (feature_index_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c,
|
||||||
|
const void *base) const
|
||||||
|
{
|
||||||
|
// ret == 1, all conditions met
|
||||||
|
if ((base+conditions).keep_with_variations (c) == DROP_COND_WITH_VAR &&
|
||||||
|
c->apply)
|
||||||
|
{
|
||||||
|
(base+substitutions).collect_feature_substitutes_with_variations (c);
|
||||||
|
c->apply = false; // set variations only once
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool subset (hb_subset_layout_context_t *c, const void *base) const
|
bool subset (hb_subset_layout_context_t *c, const void *base) const
|
||||||
{
|
{
|
||||||
TRACE_SUBSET (this);
|
TRACE_SUBSET (this);
|
||||||
auto *out = c->subset_context->serializer->embed (this);
|
auto *out = c->subset_context->serializer->embed (this);
|
||||||
if (unlikely (!out)) return_trace (false);
|
if (unlikely (!out)) return_trace (false);
|
||||||
|
|
||||||
out->conditions.serialize_subset (c->subset_context, conditions, base);
|
out->conditions.serialize_subset (c->subset_context, conditions, base, c);
|
||||||
out->substitutions.serialize_subset (c->subset_context, substitutions, base, c);
|
out->substitutions.serialize_subset (c->subset_context, substitutions, base, c);
|
||||||
|
|
||||||
return_trace (true);
|
return_trace (true);
|
||||||
|
@ -3002,6 +3233,16 @@ struct FeatureVariations
|
||||||
return (this+record.substitutions).find_substitute (feature_index);
|
return (this+record.substitutions).find_substitute (feature_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
|
||||||
|
{
|
||||||
|
unsigned int count = varRecords.len;
|
||||||
|
for (unsigned int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
c->cur_record_idx = i;
|
||||||
|
varRecords[i].collect_feature_substitutes_with_variations (c, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FeatureVariations* copy (hb_serialize_context_t *c) const
|
FeatureVariations* copy (hb_serialize_context_t *c) const
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
|
@ -3009,17 +3250,25 @@ struct FeatureVariations
|
||||||
}
|
}
|
||||||
|
|
||||||
void collect_lookups (const hb_set_t *feature_indexes,
|
void collect_lookups (const hb_set_t *feature_indexes,
|
||||||
|
const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
|
||||||
hb_set_t *lookup_indexes /* OUT */) const
|
hb_set_t *lookup_indexes /* OUT */) const
|
||||||
{
|
{
|
||||||
for (const FeatureVariationRecord& r : varRecords)
|
for (const FeatureVariationRecord& r : varRecords)
|
||||||
r.collect_lookups (this, feature_indexes, lookup_indexes);
|
r.collect_lookups (this, feature_indexes, feature_substitutes_map, lookup_indexes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void closure_features (const hb_map_t *lookup_indexes,
|
void closure_features (const hb_map_t *lookup_indexes,
|
||||||
|
const hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
|
||||||
hb_set_t *feature_indexes /* OUT */) const
|
hb_set_t *feature_indexes /* OUT */) const
|
||||||
{
|
{
|
||||||
for (const FeatureVariationRecord& record : varRecords)
|
unsigned int count = varRecords.len;
|
||||||
record.closure_features (this, lookup_indexes, feature_indexes);
|
for (unsigned int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
if (feature_record_cond_idx_map != nullptr &&
|
||||||
|
!feature_record_cond_idx_map->has (i))
|
||||||
|
continue;
|
||||||
|
varRecords[i].closure_features (this, lookup_indexes, feature_indexes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool subset (hb_subset_context_t *c,
|
bool subset (hb_subset_context_t *c,
|
||||||
|
@ -3041,7 +3290,13 @@ struct FeatureVariations
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned count = (unsigned) (keep_up_to + 1);
|
unsigned count = (unsigned) (keep_up_to + 1);
|
||||||
for (unsigned i = 0; i < count; i++) {
|
for (unsigned i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
if (l->feature_record_cond_idx_map != nullptr &&
|
||||||
|
!l->feature_record_cond_idx_map->has (i))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
l->cur_feature_var_record_idx = i;
|
||||||
subset_record_array (l, &(out->varRecords), this) (varRecords[i]);
|
subset_record_array (l, &(out->varRecords), this) (varRecords[i]);
|
||||||
}
|
}
|
||||||
return_trace (bool (out->varRecords));
|
return_trace (bool (out->varRecords));
|
||||||
|
|
|
@ -4236,13 +4236,19 @@ struct GSUBGPOS
|
||||||
}
|
}
|
||||||
|
|
||||||
void feature_variation_collect_lookups (const hb_set_t *feature_indexes,
|
void feature_variation_collect_lookups (const hb_set_t *feature_indexes,
|
||||||
|
const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map,
|
||||||
hb_set_t *lookup_indexes /* OUT */) const
|
hb_set_t *lookup_indexes /* OUT */) const
|
||||||
{
|
{
|
||||||
#ifndef HB_NO_VAR
|
#ifndef HB_NO_VAR
|
||||||
get_feature_variations ().collect_lookups (feature_indexes, lookup_indexes);
|
get_feature_variations ().collect_lookups (feature_indexes, feature_substitutes_map, lookup_indexes);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef HB_NO_VAR
|
||||||
|
void collect_feature_substitutes_with_variations (hb_collect_feature_substitutes_with_var_context_t *c) const
|
||||||
|
{ get_feature_variations ().collect_feature_substitutes_with_variations (c); }
|
||||||
|
#endif
|
||||||
|
|
||||||
template <typename TLookup>
|
template <typename TLookup>
|
||||||
void closure_lookups (hb_face_t *face,
|
void closure_lookups (hb_face_t *face,
|
||||||
const hb_set_t *glyphs,
|
const hb_set_t *glyphs,
|
||||||
|
@ -4278,6 +4284,8 @@ struct GSUBGPOS
|
||||||
}
|
}
|
||||||
|
|
||||||
void prune_features (const hb_map_t *lookup_indices, /* IN */
|
void prune_features (const hb_map_t *lookup_indices, /* IN */
|
||||||
|
const hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map, /* IN */
|
||||||
|
const hb_hashmap_t<unsigned, const Feature*> *feature_substitutes_map, /* IN */
|
||||||
hb_set_t *feature_indices /* IN/OUT */) const
|
hb_set_t *feature_indices /* IN/OUT */) const
|
||||||
{
|
{
|
||||||
#ifndef HB_NO_VAR
|
#ifndef HB_NO_VAR
|
||||||
|
@ -4285,7 +4293,7 @@ struct GSUBGPOS
|
||||||
// if the FeatureVariation's table and the alternate version(s) intersect the
|
// if the FeatureVariation's table and the alternate version(s) intersect the
|
||||||
// set of lookup indices.
|
// set of lookup indices.
|
||||||
hb_set_t alternate_feature_indices;
|
hb_set_t alternate_feature_indices;
|
||||||
get_feature_variations ().closure_features (lookup_indices, &alternate_feature_indices);
|
get_feature_variations ().closure_features (lookup_indices, feature_record_cond_idx_map, &alternate_feature_indices);
|
||||||
if (unlikely (alternate_feature_indices.in_error()))
|
if (unlikely (alternate_feature_indices.in_error()))
|
||||||
{
|
{
|
||||||
feature_indices->err ();
|
feature_indices->err ();
|
||||||
|
@ -4295,7 +4303,6 @@ struct GSUBGPOS
|
||||||
|
|
||||||
for (unsigned i : feature_indices->iter())
|
for (unsigned i : feature_indices->iter())
|
||||||
{
|
{
|
||||||
const Feature& f = get_feature (i);
|
|
||||||
hb_tag_t tag = get_feature_tag (i);
|
hb_tag_t tag = get_feature_tag (i);
|
||||||
if (tag == HB_TAG ('p', 'r', 'e', 'f'))
|
if (tag == HB_TAG ('p', 'r', 'e', 'f'))
|
||||||
// Note: Never ever drop feature 'pref', even if it's empty.
|
// Note: Never ever drop feature 'pref', even if it's empty.
|
||||||
|
@ -4305,11 +4312,16 @@ struct GSUBGPOS
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
||||||
if (!f.featureParams.is_null () &&
|
const Feature *f = &(get_feature (i));
|
||||||
|
const Feature** p = nullptr;
|
||||||
|
if (feature_substitutes_map->has (i, &p))
|
||||||
|
f = *p;
|
||||||
|
|
||||||
|
if (!f->featureParams.is_null () &&
|
||||||
tag == HB_TAG ('s', 'i', 'z', 'e'))
|
tag == HB_TAG ('s', 'i', 'z', 'e'))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!f.intersects_lookup_indexes (lookup_indices)
|
if (!f->intersects_lookup_indexes (lookup_indices)
|
||||||
#ifndef HB_NO_VAR
|
#ifndef HB_NO_VAR
|
||||||
&& !alternate_feature_indices.has (i)
|
&& !alternate_feature_indices.has (i)
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1271,7 +1271,7 @@ hb_ot_layout_collect_lookups (hb_face_t *face,
|
||||||
hb_set_next (&feature_indexes, &feature_index);)
|
hb_set_next (&feature_indexes, &feature_index);)
|
||||||
g.get_feature (feature_index).add_lookup_indexes_to (lookup_indexes);
|
g.get_feature (feature_index).add_lookup_indexes_to (lookup_indexes);
|
||||||
|
|
||||||
g.feature_variation_collect_lookups (&feature_indexes, lookup_indexes);
|
g.feature_variation_collect_lookups (&feature_indexes, nullptr, lookup_indexes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1709,6 +1709,8 @@ hb_ot_layout_get_size_params (hb_face_t *face,
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hb_ot_layout_feature_get_name_ids:
|
* hb_ot_layout_feature_get_name_ids:
|
||||||
* @face: #hb_face_t to work upon
|
* @face: #hb_face_t to work upon
|
||||||
|
@ -2341,6 +2343,7 @@ struct hb_get_glyph_alternates_dispatch_t :
|
||||||
( _dispatch (obj, hb_prioritize, std::forward<Ts> (ds)...) )
|
( _dispatch (obj, hb_prioritize, std::forward<Ts> (ds)...) )
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifndef HB_NO_LAYOUT_RARELY_USED
|
||||||
/**
|
/**
|
||||||
* hb_ot_layout_lookup_get_glyph_alternates:
|
* hb_ot_layout_lookup_get_glyph_alternates:
|
||||||
* @face: a face.
|
* @face: a face.
|
||||||
|
@ -2373,4 +2376,72 @@ hb_ot_layout_lookup_get_glyph_alternates (hb_face_t *face,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
struct hb_position_single_dispatch_t :
|
||||||
|
hb_dispatch_context_t<hb_position_single_dispatch_t, bool>
|
||||||
|
{
|
||||||
|
static return_t default_return_value () { return false; }
|
||||||
|
bool stop_sublookup_iteration (return_t r) const { return r; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename T, typename ...Ts> auto
|
||||||
|
_dispatch (const T &obj, hb_priority<1>, Ts&&... ds) HB_AUTO_RETURN
|
||||||
|
( obj.position_single (std::forward<Ts> (ds)...) )
|
||||||
|
template <typename T, typename ...Ts> auto
|
||||||
|
_dispatch (const T &obj, hb_priority<0>, Ts&&... ds) HB_AUTO_RETURN
|
||||||
|
( default_return_value () )
|
||||||
|
public:
|
||||||
|
template <typename T, typename ...Ts> auto
|
||||||
|
dispatch (const T &obj, Ts&&... ds) HB_AUTO_RETURN
|
||||||
|
( _dispatch (obj, hb_prioritize, std::forward<Ts> (ds)...) )
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* hb_ot_layout_lookup_get_optical_bound:
|
||||||
|
* @font: a font.
|
||||||
|
* @lookup_index: index of the feature lookup to query.
|
||||||
|
* @direction: edge of the glyph to query.
|
||||||
|
* @glyph: a glyph id.
|
||||||
|
*
|
||||||
|
* Fetches the optical bound of a glyph positioned at the margin of text.
|
||||||
|
* The direction identifies which edge of the glyph to query.
|
||||||
|
*
|
||||||
|
* Return value: Adjustment value. Negative values mean the glyph will stick out of the margin.
|
||||||
|
*
|
||||||
|
* Since: 5.3.0
|
||||||
|
**/
|
||||||
|
hb_position_t
|
||||||
|
hb_ot_layout_lookup_get_optical_bound (hb_font_t *font,
|
||||||
|
unsigned lookup_index,
|
||||||
|
hb_direction_t direction,
|
||||||
|
hb_codepoint_t glyph)
|
||||||
|
{
|
||||||
|
const OT::PosLookup &lookup = font->face->table.GPOS->table->get_lookup (lookup_index);
|
||||||
|
hb_glyph_position_t pos = {0};
|
||||||
|
hb_position_single_dispatch_t c;
|
||||||
|
lookup.dispatch (&c, font, direction, glyph, pos);
|
||||||
|
hb_position_t ret = 0;
|
||||||
|
switch (direction)
|
||||||
|
{
|
||||||
|
case HB_DIRECTION_LTR:
|
||||||
|
ret = pos.x_offset;
|
||||||
|
break;
|
||||||
|
case HB_DIRECTION_RTL:
|
||||||
|
ret = pos.x_advance - pos.x_offset;
|
||||||
|
break;
|
||||||
|
case HB_DIRECTION_TTB:
|
||||||
|
ret = pos.y_offset;
|
||||||
|
break;
|
||||||
|
case HB_DIRECTION_BTT:
|
||||||
|
ret = pos.y_advance - pos.y_offset;
|
||||||
|
break;
|
||||||
|
case HB_DIRECTION_INVALID:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -403,6 +403,16 @@ hb_ot_layout_get_size_params (hb_face_t *face,
|
||||||
unsigned int *range_start, /* OUT. May be NULL */
|
unsigned int *range_start, /* OUT. May be NULL */
|
||||||
unsigned int *range_end /* OUT. May be NULL */);
|
unsigned int *range_end /* OUT. May be NULL */);
|
||||||
|
|
||||||
|
HB_EXTERN hb_position_t
|
||||||
|
hb_ot_layout_lookup_get_optical_bound (hb_font_t *font,
|
||||||
|
unsigned lookup_index,
|
||||||
|
hb_direction_t direction,
|
||||||
|
hb_codepoint_t glyph);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GSUB/GPOS
|
||||||
|
*/
|
||||||
|
|
||||||
HB_EXTERN hb_bool_t
|
HB_EXTERN hb_bool_t
|
||||||
hb_ot_layout_feature_get_name_ids (hb_face_t *face,
|
hb_ot_layout_feature_get_name_ids (hb_face_t *face,
|
||||||
|
@ -423,6 +433,7 @@ hb_ot_layout_feature_get_characters (hb_face_t *face,
|
||||||
unsigned int *char_count /* IN/OUT. May be NULL */,
|
unsigned int *char_count /* IN/OUT. May be NULL */,
|
||||||
hb_codepoint_t *characters /* OUT. May be NULL */);
|
hb_codepoint_t *characters /* OUT. May be NULL */);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* BASE
|
* BASE
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -78,14 +78,14 @@ HB_INTERNAL bool postV2Tail::subset (hb_subset_context_t *c) const
|
||||||
|
|
||||||
post::accelerator_t _post (c->plan->source);
|
post::accelerator_t _post (c->plan->source);
|
||||||
|
|
||||||
hb_hashmap_t<hb_bytes_t, unsigned, true> glyph_name_to_new_index;
|
hb_hashmap_t<hb_bytes_t, uint32_t, true> glyph_name_to_new_index;
|
||||||
for (hb_codepoint_t new_gid = 0; new_gid < num_glyphs; new_gid++)
|
for (hb_codepoint_t new_gid = 0; new_gid < num_glyphs; new_gid++)
|
||||||
{
|
{
|
||||||
hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
|
hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
|
||||||
unsigned old_index = glyphNameIndex[old_gid];
|
unsigned old_index = glyphNameIndex[old_gid];
|
||||||
|
|
||||||
unsigned new_index;
|
unsigned new_index;
|
||||||
const unsigned *new_index2;
|
const uint32_t *new_index2;
|
||||||
if (old_index <= 257) new_index = old_index;
|
if (old_index <= 257) new_index = old_index;
|
||||||
else if (old_new_index_map.has (old_index, &new_index2))
|
else if (old_new_index_map.has (old_index, &new_index2))
|
||||||
{
|
{
|
||||||
|
|
|
@ -282,7 +282,7 @@ struct post
|
||||||
* 0x00020000 for version 2.0
|
* 0x00020000 for version 2.0
|
||||||
* 0x00025000 for version 2.5 (deprecated)
|
* 0x00025000 for version 2.5 (deprecated)
|
||||||
* 0x00030000 for version 3.0 */
|
* 0x00030000 for version 3.0 */
|
||||||
HBFixed italicAngle; /* Italic angle in counter-clockwise degrees
|
F16DOT16 italicAngle; /* Italic angle in counter-clockwise degrees
|
||||||
* from the vertical. Zero for upright text,
|
* from the vertical. Zero for upright text,
|
||||||
* negative for text that leans to the right
|
* negative for text that leans to the right
|
||||||
* (forward). */
|
* (forward). */
|
||||||
|
|
|
@ -527,18 +527,20 @@ hb_set_unicode_props (hb_buffer_t *buffer)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
/* Or part of the Other_Grapheme_Extend that is not marks.
|
/* Or part of the Other_Grapheme_Extend that is not marks.
|
||||||
* As of Unicode 11 that is just:
|
* As of Unicode 15 that is just:
|
||||||
*
|
*
|
||||||
* 200C ; Other_Grapheme_Extend # Cf ZERO WIDTH NON-JOINER
|
* 200C ; Other_Grapheme_Extend # Cf ZERO WIDTH NON-JOINER
|
||||||
* FF9E..FF9F ; Other_Grapheme_Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
|
* FF9E..FF9F ; Other_Grapheme_Extend # Lm [2] HALFWIDTH KATAKANA VOICED SOUND MARK..HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK
|
||||||
* E0020..E007F ; Other_Grapheme_Extend # Cf [96] TAG SPACE..CANCEL TAG
|
* E0020..E007F ; Other_Grapheme_Extend # Cf [96] TAG SPACE..CANCEL TAG
|
||||||
*
|
*
|
||||||
* ZWNJ is special, we don't want to merge it as there's no need, and keeping
|
* ZWNJ is special, we don't want to merge it as there's no need, and keeping
|
||||||
* it separate results in more granular clusters. Ignore Katakana for now.
|
* it separate results in more granular clusters.
|
||||||
* Tags are used for Emoji sub-region flag sequences:
|
* Tags are used for Emoji sub-region flag sequences:
|
||||||
* https://github.com/harfbuzz/harfbuzz/issues/1556
|
* https://github.com/harfbuzz/harfbuzz/issues/1556
|
||||||
|
* Katakana ones were requested:
|
||||||
|
* https://github.com/harfbuzz/harfbuzz/issues/3844
|
||||||
*/
|
*/
|
||||||
else if (unlikely (hb_in_range<hb_codepoint_t> (info[i].codepoint, 0xE0020u, 0xE007Fu)))
|
else if (unlikely (hb_in_ranges<hb_codepoint_t> (info[i].codepoint, 0xFF9Eu, 0xFF9Fu, 0xE0020u, 0xE007Fu)))
|
||||||
_hb_glyph_info_set_continuation (&info[i]);
|
_hb_glyph_info_set_continuation (&info[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
* # Updated for Unicode 12.1 by Andrew Glass 2019-05-24
|
* # Updated for Unicode 12.1 by Andrew Glass 2019-05-24
|
||||||
* # Updated for Unicode 13.0 by Andrew Glass 2020-07-28
|
* # Updated for Unicode 13.0 by Andrew Glass 2020-07-28
|
||||||
* # Updated for Unicode 14.0 by Andrew Glass 2021-09-25
|
* # Updated for Unicode 14.0 by Andrew Glass 2021-09-25
|
||||||
|
* # Updated for Unicode 15.0 by Andrew Glass 2022-09-16
|
||||||
* # Override values For Indic_Positional_Category
|
* # Override values For Indic_Positional_Category
|
||||||
* # Not derivable
|
* # Not derivable
|
||||||
* # Initial version based on Unicode 7.0 by Andrew Glass 2014-03-17
|
* # Initial version based on Unicode 7.0 by Andrew Glass 2014-03-17
|
||||||
|
@ -34,6 +35,7 @@
|
||||||
* # Updated for Unicode 12.1 by Andrew Glass 2019-05-30
|
* # Updated for Unicode 12.1 by Andrew Glass 2019-05-30
|
||||||
* # Updated for Unicode 13.0 by Andrew Glass 2020-07-28
|
* # Updated for Unicode 13.0 by Andrew Glass 2020-07-28
|
||||||
* # Updated for Unicode 14.0 by Andrew Glass 2021-09-28
|
* # Updated for Unicode 14.0 by Andrew Glass 2021-09-28
|
||||||
|
* # Updated for Unicode 15.0 by Andrew Glass 2022-09-16
|
||||||
* UnicodeData.txt does not have a header.
|
* UnicodeData.txt does not have a header.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -90,7 +92,7 @@
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
static const uint8_t
|
static const uint8_t
|
||||||
hb_use_u8[3115] =
|
hb_use_u8[3141] =
|
||||||
{
|
{
|
||||||
16, 50, 51, 51, 51, 52, 51, 83, 118, 131, 51, 57, 58, 179, 195, 61,
|
16, 50, 51, 51, 51, 52, 51, 83, 118, 131, 51, 57, 58, 179, 195, 61,
|
||||||
51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
|
51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
|
||||||
|
@ -125,11 +127,11 @@ hb_use_u8[3115] =
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 88, 89, 2, 2, 2, 2, 2,
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 88, 89, 2, 2, 2, 2, 2,
|
||||||
2, 2, 2, 90, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
2, 2, 2, 90, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
2, 2, 2, 91, 2, 2, 92, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
2, 2, 2, 91, 2, 2, 92, 2, 2, 2, 93, 2, 2, 2, 2, 2,
|
||||||
2, 2, 2, 93, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
2, 2, 2, 94, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
2, 94, 94, 95, 96, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
|
2, 95, 95, 96, 97, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
|
||||||
94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94, 94,
|
95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
|
||||||
94, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
|
95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
|
||||||
0, 2, 2, 2, 2, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 4,
|
0, 2, 2, 2, 2, 2, 0, 0, 0, 3, 0, 0, 0, 0, 0, 4,
|
||||||
0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
|
0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 6, 7, 0, 0, 0, 0, 0, 0,
|
||||||
|
@ -226,70 +228,72 @@ hb_use_u8[3115] =
|
||||||
0, 9, 47, 2, 2, 2, 2, 2, 2, 2, 2, 2, 125, 18, 20, 151,
|
0, 9, 47, 2, 2, 2, 2, 2, 2, 2, 2, 2, 125, 18, 20, 151,
|
||||||
20, 19, 152, 153, 2, 2, 2, 2, 2, 0, 0, 63, 154, 0, 0, 0,
|
20, 19, 152, 153, 2, 2, 2, 2, 2, 0, 0, 63, 154, 0, 0, 0,
|
||||||
0, 2, 11, 0, 0, 0, 0, 0, 0, 2, 63, 23, 18, 18, 18, 20,
|
0, 2, 11, 0, 0, 0, 0, 0, 0, 2, 63, 23, 18, 18, 18, 20,
|
||||||
20, 106, 155, 0, 0, 156, 157, 29, 158, 28, 2, 2, 2, 2, 2, 2,
|
20, 106, 155, 0, 0, 54, 156, 29, 157, 28, 2, 2, 2, 2, 2, 2,
|
||||||
2, 2, 2, 2, 2, 2, 2, 21, 17, 20, 20, 159, 42, 0, 0, 0,
|
2, 2, 2, 2, 2, 2, 2, 21, 17, 20, 20, 158, 42, 0, 0, 0,
|
||||||
47, 125, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 7, 7, 2, 2,
|
47, 125, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 7, 7, 2, 2,
|
||||||
28, 2, 2, 2, 2, 2, 2, 2, 28, 2, 2, 2, 2, 2, 2, 2,
|
28, 2, 2, 2, 2, 2, 2, 2, 28, 2, 2, 2, 2, 2, 2, 2,
|
||||||
8, 16, 17, 19, 20, 160, 29, 0, 0, 9, 9, 28, 2, 2, 2, 7,
|
8, 16, 17, 19, 20, 159, 29, 0, 0, 9, 9, 28, 2, 2, 2, 7,
|
||||||
28, 7, 2, 28, 2, 2, 56, 15, 21, 14, 21, 45, 30, 31, 30, 32,
|
28, 7, 2, 28, 2, 2, 56, 15, 21, 14, 21, 45, 30, 31, 30, 32,
|
||||||
0, 0, 0, 0, 33, 0, 0, 0, 2, 2, 21, 0, 9, 9, 9, 44,
|
0, 0, 0, 0, 33, 0, 0, 0, 2, 2, 21, 0, 9, 9, 9, 44,
|
||||||
0, 9, 9, 44, 0, 0, 0, 0, 0, 2, 2, 63, 23, 18, 18, 18,
|
0, 9, 9, 44, 0, 0, 0, 0, 0, 2, 2, 63, 23, 18, 18, 18,
|
||||||
20, 21, 123, 13, 15, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0,
|
20, 21, 123, 13, 15, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0,
|
||||||
161, 162, 0, 0, 0, 0, 0, 0, 0, 16, 17, 18, 18, 64, 97, 23,
|
160, 161, 0, 0, 0, 0, 0, 0, 0, 16, 17, 18, 18, 64, 97, 23,
|
||||||
158, 9, 163, 7, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2,
|
157, 9, 162, 7, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2,
|
||||||
63, 23, 18, 18, 0, 46, 46, 9, 164, 35, 0, 0, 0, 0, 0, 0,
|
63, 23, 18, 18, 0, 46, 46, 9, 163, 35, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 2, 2, 18, 0, 21, 17, 18, 18, 19, 14, 80,
|
0, 0, 0, 0, 0, 2, 2, 18, 0, 21, 17, 18, 18, 19, 14, 80,
|
||||||
164, 36, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 8, 165,
|
163, 36, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 8, 164,
|
||||||
23, 18, 20, 20, 163, 7, 0, 0, 0, 2, 2, 2, 2, 2, 7, 41,
|
23, 18, 20, 20, 162, 7, 0, 0, 0, 2, 2, 2, 2, 2, 7, 41,
|
||||||
133, 21, 20, 18, 74, 19, 20, 0, 0, 2, 2, 2, 7, 0, 0, 0,
|
133, 21, 20, 18, 74, 19, 20, 0, 0, 2, 2, 2, 7, 0, 0, 0,
|
||||||
0, 2, 2, 2, 2, 2, 2, 16, 17, 18, 19, 20, 103, 164, 35, 0,
|
0, 2, 2, 2, 2, 2, 2, 16, 17, 18, 19, 20, 103, 163, 35, 0,
|
||||||
0, 2, 2, 2, 7, 28, 0, 2, 2, 2, 2, 28, 7, 2, 2, 2,
|
0, 2, 2, 2, 7, 28, 0, 2, 2, 2, 2, 28, 7, 2, 2, 2,
|
||||||
2, 21, 21, 16, 30, 31, 10, 166, 167, 168, 169, 0, 0, 0, 0, 0,
|
2, 21, 21, 16, 30, 31, 10, 165, 166, 167, 168, 0, 0, 0, 0, 0,
|
||||||
0, 2, 2, 2, 2, 0, 2, 2, 2, 63, 23, 18, 18, 0, 20, 21,
|
0, 2, 2, 2, 2, 0, 2, 2, 2, 63, 23, 18, 18, 0, 20, 21,
|
||||||
27, 106, 0, 31, 0, 0, 0, 0, 0, 50, 18, 20, 20, 20, 137, 2,
|
27, 106, 0, 31, 0, 0, 0, 0, 0, 50, 18, 20, 20, 20, 137, 2,
|
||||||
2, 2, 170, 171, 9, 13, 172, 70, 173, 0, 0, 1, 144, 0, 0, 0,
|
2, 2, 169, 170, 9, 13, 171, 70, 172, 0, 0, 1, 144, 0, 0, 0,
|
||||||
0, 50, 18, 20, 14, 17, 18, 2, 2, 2, 2, 155, 155, 155, 174, 174,
|
0, 50, 18, 20, 14, 17, 18, 2, 2, 2, 2, 155, 155, 155, 173, 173,
|
||||||
174, 174, 174, 174, 13, 175, 0, 28, 0, 20, 18, 18, 29, 20, 20, 9,
|
173, 173, 173, 173, 13, 174, 0, 28, 0, 20, 18, 18, 29, 20, 20, 9,
|
||||||
164, 0, 59, 59, 59, 59, 59, 59, 59, 64, 19, 80, 44, 0, 0, 0,
|
163, 0, 59, 59, 59, 59, 59, 59, 59, 64, 19, 80, 44, 0, 0, 0,
|
||||||
0, 2, 2, 2, 7, 2, 28, 2, 2, 50, 20, 20, 29, 0, 36, 20,
|
0, 2, 2, 2, 7, 2, 28, 2, 2, 50, 20, 20, 29, 0, 36, 20,
|
||||||
25, 9, 157, 176, 172, 0, 0, 0, 0, 2, 2, 2, 28, 7, 2, 2,
|
25, 9, 156, 175, 171, 0, 0, 0, 0, 2, 2, 2, 28, 7, 2, 2,
|
||||||
2, 2, 2, 2, 2, 2, 21, 21, 45, 20, 33, 80, 66, 0, 0, 0,
|
2, 2, 2, 2, 2, 2, 21, 21, 45, 20, 33, 80, 66, 0, 0, 0,
|
||||||
0, 2, 177, 64, 45, 0, 0, 0, 0, 9, 178, 2, 2, 2, 2, 2,
|
0, 2, 176, 64, 45, 0, 0, 0, 0, 9, 177, 2, 2, 2, 2, 2,
|
||||||
2, 2, 2, 21, 20, 18, 29, 0, 46, 14, 140, 0, 0, 0, 0, 0,
|
2, 2, 2, 21, 20, 18, 29, 0, 46, 14, 140, 0, 0, 0, 0, 0,
|
||||||
0, 179, 179, 179, 106, 7, 0, 0, 0, 9, 9, 9, 44, 0, 0, 0,
|
0, 178, 178, 178, 106, 179, 178, 0, 0, 145, 2, 2, 180, 114, 114, 114,
|
||||||
0, 2, 2, 2, 2, 2, 7, 0, 56, 180, 18, 18, 18, 18, 18, 18,
|
114, 114, 114, 114, 0, 0, 0, 0, 0, 9, 9, 9, 44, 0, 0, 0,
|
||||||
|
0, 2, 2, 2, 2, 2, 7, 0, 56, 181, 18, 18, 18, 18, 18, 18,
|
||||||
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0,
|
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 0, 0, 0,
|
||||||
38, 114, 24, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0,
|
38, 114, 24, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0,
|
||||||
0, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 56,
|
0, 2, 2, 2, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 56,
|
||||||
35, 0, 4, 118, 118, 118, 119, 0, 0, 9, 9, 9, 47, 2, 2, 2,
|
35, 0, 4, 118, 118, 118, 119, 0, 0, 9, 9, 9, 47, 2, 2, 2,
|
||||||
0, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2,
|
0, 2, 2, 2, 2, 2, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||||
44, 2, 2, 2, 2, 2, 2, 9, 9, 2, 2, 42, 42, 42, 90, 0,
|
44, 2, 2, 2, 2, 2, 2, 9, 9, 2, 2, 2, 2, 2, 2, 20,
|
||||||
0, O, O, O, GB, B, B, GB, O, O, WJ,FMPst,FMPst, O, CGJ, B,
|
20, 2, 2, 42, 42, 42, 90, 0, 0, O, O, O, GB, B, B, GB,
|
||||||
O, B,VMAbv,VMAbv,VMAbv, O,VMAbv, B,CMBlw,CMBlw,CMBlw,VMAbv,VMPst, VAbv, VPst,CMBlw,
|
O, O, WJ,FMPst,FMPst, O, CGJ, B, O, B,VMAbv,VMAbv,VMAbv, O,VMAbv, B,
|
||||||
B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw, VAbv, VAbv, VAbv, VPst, VPst, VPst, H, VPre,
|
CMBlw,CMBlw,CMBlw,VMAbv,VMPst, VAbv, VPst,CMBlw, B, VPst, VPre, VPst, VBlw, VBlw, VBlw, VBlw,
|
||||||
VPst,VMBlw, O, O, VAbv, GB,VMAbv,VMPst,VMPst, O, B, VBlw, O, O, VPre, VPre,
|
VAbv, VAbv, VAbv, VPst, VPst, VPst, H, VPre, VPst,VMBlw, O, O, VAbv, GB,VMAbv,VMPst,
|
||||||
O, VPre, H, O, VPst,FMAbv, O,CMBlw, O, VAbv, O, VAbv, H, O,VMBlw,VMAbv,
|
VMPst, O, B, VBlw, O, O, VPre, VPre, O, VPre, H, O, VPst,FMAbv, O,CMBlw,
|
||||||
CMAbv, GB, GB, O, MBlw,CMAbv,CMAbv, VPst, VAbv,VMAbv, O, VPst, O, VPre, VPre,VMAbv,
|
O, VAbv, O, VAbv, H, O,VMBlw,VMAbv,CMAbv, GB, GB, O, MBlw,CMAbv,CMAbv, VPst,
|
||||||
B, O, CS, CS,VMPst, B, VAbv, VAbv, B, R, O, HVM, O, O, FBlw, O,
|
VAbv,VMAbv, O, VPst, O, VPre, VPre,VMAbv, B, O, CS, CS,VMPst, B, VAbv, VAbv,
|
||||||
CMAbv, O,CMBlw, VAbv, VBlw, B, SUB, SUB, SUB, O, SUB, SUB, O, FBlw, O, B,
|
B, R, O, HVM, O, O,FMBlw, O,CMAbv, O,CMBlw, VAbv, VBlw, B, SUB, SUB,
|
||||||
VPst, VBlw, VPre,VMAbv,VMBlw,VMPst, IS, VAbv, MPst, MPre, MBlw, MBlw, B, MBlw, MBlw, VPst,
|
SUB, O, SUB, SUB, O,FMBlw, O, B, VPst, VBlw, VPre,VMAbv,VMBlw,VMPst, IS, VAbv,
|
||||||
VMPst,VMPst, B, MBlw, VPst, VPre, VAbv, VAbv,VMPst,VMPst,VMBlw, B,VMPst, VBlw, VPst, CGJ,
|
MPst, MPre, MBlw, MBlw, B, MBlw, MBlw, VPst,VMPst,VMPst, B, MBlw, VPst, VPre, VAbv, VAbv,
|
||||||
CGJ, VPst,VMAbv,VMAbv,FMAbv, FAbv,CMAbv,FMAbv,VMAbv,FMAbv, VAbv, IS,FMAbv, B,FMAbv, B,
|
VMPst,VMPst,VMBlw, B,VMPst, VBlw, VPst, CGJ, CGJ, VPst,VMAbv,VMAbv,FMAbv, FAbv,CMAbv,FMAbv,
|
||||||
CGJ, WJ, CGJ, GB,CMAbv,CMAbv, B, GB, B, VAbv, SUB, FPst, FPst,VMBlw, FPst, FPst,
|
VMAbv,FMAbv, VAbv, IS,FMAbv, B,FMAbv, B, CGJ, WJ, CGJ, GB,CMAbv,CMAbv, B, GB,
|
||||||
FBlw,VMAbv,FMBlw, VAbv, VPre, B, MPre, MBlw, SUB, FAbv, FAbv, MAbv, SUB, Sk, VPst, VAbv,
|
B, VAbv, SUB, FPst, FPst,VMBlw, FPst, FPst, FBlw,VMAbv,FMBlw, VAbv, VPre, B, MPre, MBlw,
|
||||||
VMAbv,VMAbv, FAbv,CMAbv, VPst, H, B, O,SMAbv,SMBlw,SMAbv,SMAbv,SMAbv, VPst, IS, VBlw,
|
SUB, FAbv, FAbv, MAbv, SUB, Sk, VPst, VAbv,VMAbv,VMAbv, FAbv,CMAbv, VPst, H, B, O,
|
||||||
FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,VMBlw,VMAbv, CS, O,FMAbv, ZWNJ, CGJ, WJ, WJ, WJ,
|
SMAbv,SMBlw,SMAbv,SMAbv,SMAbv, VPst, IS, VBlw, FAbv,VMPre,VMPre,FMAbv,CMBlw,VMBlw,VMBlw,VMAbv,
|
||||||
O,FMPst, O, O, H, MPst, VPst, H,VMAbv, VAbv,VMBlw, B, VBlw, FPst, VPst, FAbv,
|
CS, O,FMAbv, ZWNJ, CGJ, WJ, WJ, WJ, O,FMPst, O, O, H, MPst, VPst, H,
|
||||||
VMPst, B,CMAbv, VAbv, MBlw, MPst, MBlw, H, O, VBlw, MPst, MPre, MAbv, MBlw, O, B,
|
VMAbv, VAbv,VMBlw, B, VBlw, FPst, VPst, FAbv,VMPst, B,CMAbv, VAbv, MBlw, MPst, MBlw, H,
|
||||||
FAbv, FAbv, FPst, VBlw, B, B, VPre, O,VMPst, IS, O,VMPst, VBlw, VPst,VMBlw,VMBlw,
|
O, VBlw, MPst, MPre, MAbv, MBlw, O, B, FAbv, FAbv, FPst, VBlw, B, B, VPre, O,
|
||||||
VMAbv, O, IS,VMBlw, B,VMPst,VMAbv,VMPst, CS, CS, B, N, N, O, HN, VPre,
|
VMPst, IS, O,VMPst, VBlw, VPst,VMBlw,VMBlw,VMAbv, O, IS,VMBlw, B,VMPst,VMAbv,VMPst,
|
||||||
VBlw, VAbv, IS,CMAbv, O, VPst, B, R, R, O,FMBlw,CMBlw, VAbv, VPre,VMAbv,VMAbv,
|
CS, CS, B, N, N, O, HN, VPre, VBlw, VAbv, IS,CMAbv, O, VPst, B, R,
|
||||||
H, VAbv,CMBlw,FMAbv, B, CS, CS, H,CMBlw,VMPst, H,VMPst, VAbv,VMAbv, VPst, IS,
|
R,CMBlw, VAbv, VPre,VMAbv,VMAbv, H, VAbv,CMBlw,FMAbv, B, CS, CS, H,CMBlw,VMPst,
|
||||||
R, MPst, R, MPst,CMBlw, B,FMBlw, VBlw,VMAbv, R, MBlw, MBlw, GB, FBlw, FBlw,CMAbv,
|
H,VMPst, VAbv,VMAbv, VPst, IS, R, MPst, R, MPst,CMBlw, B,FMBlw, VBlw,VMAbv, R,
|
||||||
IS, VBlw, IS, GB, VAbv, R,VMPst, H, H, O, VBlw,
|
MBlw, MBlw, GB, FBlw, FBlw,CMAbv, IS, VBlw, IS, GB, VAbv, R,VMPst, H, H, B,
|
||||||
|
H, B,VMBlw, O, VBlw,
|
||||||
};
|
};
|
||||||
static const uint16_t
|
static const uint16_t
|
||||||
hb_use_u16[776] =
|
hb_use_u16[784] =
|
||||||
{
|
{
|
||||||
0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 5, 0, 0,
|
0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 3, 4, 0, 5, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0,
|
||||||
|
@ -332,14 +336,14 @@ hb_use_u16[776] =
|
||||||
9,242, 73,243, 0, 0, 0, 0,244, 9, 9,245,246, 2,247, 9,
|
9,242, 73,243, 0, 0, 0, 0,244, 9, 9,245,246, 2,247, 9,
|
||||||
248,249, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,250,
|
248,249, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9,250,
|
||||||
251, 48, 9,252,253, 2, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9,
|
251, 48, 9,252,253, 2, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||||
9, 9, 98,254, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
|
9, 9, 9,254,255,256, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
|
||||||
9, 9, 9,255, 0, 0, 0, 0, 9, 9, 9, 9,256,257,258,258,
|
9, 9, 9,257, 0, 0, 0, 0, 9, 9, 9, 9,258,259,260,260,
|
||||||
259,260, 0, 0, 0, 0,261, 0, 9, 9, 9, 9, 9,262, 0, 0,
|
261,262, 0, 0, 0, 0,263, 0, 9, 9, 9, 9, 9,264, 0, 0,
|
||||||
9, 9, 9, 9, 9, 9,105, 70, 94,263, 0, 0, 0, 0, 0, 0,
|
9, 9, 9, 9, 9, 9,105, 70, 94,265, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0,264, 9, 9, 70,265,266, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0,266, 9, 9, 70,267,268, 0, 0, 0,
|
||||||
0, 9,267, 0, 9, 9,268, 2, 9, 9, 9, 9,269, 2, 0, 0,
|
0, 9,269, 0, 9, 9,270, 2, 0, 0, 0, 0, 0, 9,271, 2,
|
||||||
129,129,129,129,129,129,129,129,160,160,160,160,160,160,160,160,
|
9, 9, 9, 9,272, 2, 0, 0,129,129,129,129,129,129,129,129,
|
||||||
160,160,160,160,160,160,160,129,
|
160,160,160,160,160,160,160,160,160,160,160,160,160,160,160,129,
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline unsigned
|
static inline unsigned
|
||||||
|
@ -350,7 +354,7 @@ hb_use_b4 (const uint8_t* a, unsigned i)
|
||||||
static inline uint_fast8_t
|
static inline uint_fast8_t
|
||||||
hb_use_get_category (unsigned u)
|
hb_use_get_category (unsigned u)
|
||||||
{
|
{
|
||||||
return u<921600u?hb_use_u8[2753+(((hb_use_u8[593+(((hb_use_u16[((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>3>>5))<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O;
|
return u<921600u?hb_use_u8[2777+(((hb_use_u8[593+(((hb_use_u16[((hb_use_u8[113+(((hb_use_b4(hb_use_u8,u>>1>>3>>3>>5))<<5)+((u>>1>>3>>3)&31u))])<<3)+((u>>1>>3)&7u)])<<3)+((u>>1)&7u))])<<1)+((u)&1u))]:O;
|
||||||
}
|
}
|
||||||
|
|
||||||
#undef B
|
#undef B
|
||||||
|
|
|
@ -342,6 +342,40 @@ _hb_preprocess_text_vowel_constraints (const hb_ot_shape_plan_t *plan HB_UNUSED,
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case HB_SCRIPT_KHOJKI:
|
||||||
|
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
|
||||||
|
{
|
||||||
|
bool matched = false;
|
||||||
|
switch (buffer->cur ().codepoint)
|
||||||
|
{
|
||||||
|
case 0x11200u:
|
||||||
|
switch (buffer->cur (1).codepoint)
|
||||||
|
{
|
||||||
|
case 0x1122Cu: case 0x11231u: case 0x11233u:
|
||||||
|
matched = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x11206u:
|
||||||
|
matched = 0x1122Cu == buffer->cur (1).codepoint;
|
||||||
|
break;
|
||||||
|
case 0x1122Cu:
|
||||||
|
switch (buffer->cur (1).codepoint)
|
||||||
|
{
|
||||||
|
case 0x11230u: case 0x11231u:
|
||||||
|
matched = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x11240u:
|
||||||
|
matched = 0x1122Eu == buffer->cur (1).codepoint;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
(void) buffer->next_glyph ();
|
||||||
|
if (matched) _output_with_dotted_circle (buffer);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case HB_SCRIPT_KHUDAWADI:
|
case HB_SCRIPT_KHUDAWADI:
|
||||||
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
|
for (buffer->idx = 0; buffer->idx + 1 < count && buffer->successful;)
|
||||||
{
|
{
|
||||||
|
|
|
@ -136,7 +136,7 @@ struct AxisValueFormat1
|
||||||
NameID valueNameID; /* The name ID for entries in the 'name' table
|
NameID valueNameID; /* The name ID for entries in the 'name' table
|
||||||
* that provide a display string for this
|
* that provide a display string for this
|
||||||
* attribute value. */
|
* attribute value. */
|
||||||
HBFixed value; /* A numeric value for this attribute value. */
|
F16DOT16 value; /* A numeric value for this attribute value. */
|
||||||
public:
|
public:
|
||||||
DEFINE_SIZE_STATIC (12);
|
DEFINE_SIZE_STATIC (12);
|
||||||
};
|
};
|
||||||
|
@ -195,10 +195,10 @@ struct AxisValueFormat2
|
||||||
NameID valueNameID; /* The name ID for entries in the 'name' table
|
NameID valueNameID; /* The name ID for entries in the 'name' table
|
||||||
* that provide a display string for this
|
* that provide a display string for this
|
||||||
* attribute value. */
|
* attribute value. */
|
||||||
HBFixed nominalValue; /* A numeric value for this attribute value. */
|
F16DOT16 nominalValue; /* A numeric value for this attribute value. */
|
||||||
HBFixed rangeMinValue; /* The minimum value for a range associated
|
F16DOT16 rangeMinValue; /* The minimum value for a range associated
|
||||||
* with the specified name ID. */
|
* with the specified name ID. */
|
||||||
HBFixed rangeMaxValue; /* The maximum value for a range associated
|
F16DOT16 rangeMaxValue; /* The maximum value for a range associated
|
||||||
* with the specified name ID. */
|
* with the specified name ID. */
|
||||||
public:
|
public:
|
||||||
DEFINE_SIZE_STATIC (20);
|
DEFINE_SIZE_STATIC (20);
|
||||||
|
@ -258,8 +258,8 @@ struct AxisValueFormat3
|
||||||
NameID valueNameID; /* The name ID for entries in the 'name' table
|
NameID valueNameID; /* The name ID for entries in the 'name' table
|
||||||
* that provide a display string for this
|
* that provide a display string for this
|
||||||
* attribute value. */
|
* attribute value. */
|
||||||
HBFixed value; /* A numeric value for this attribute value. */
|
F16DOT16 value; /* A numeric value for this attribute value. */
|
||||||
HBFixed linkedValue; /* The numeric value for a style-linked mapping
|
F16DOT16 linkedValue; /* The numeric value for a style-linked mapping
|
||||||
* from this value. */
|
* from this value. */
|
||||||
public:
|
public:
|
||||||
DEFINE_SIZE_STATIC (16);
|
DEFINE_SIZE_STATIC (16);
|
||||||
|
@ -280,7 +280,7 @@ struct AxisValueRecord
|
||||||
HBUINT16 axisIndex; /* Zero-base index into the axis record array
|
HBUINT16 axisIndex; /* Zero-base index into the axis record array
|
||||||
* identifying the axis to which this value
|
* identifying the axis to which this value
|
||||||
* applies. Must be less than designAxisCount. */
|
* applies. Must be less than designAxisCount. */
|
||||||
HBFixed value; /* A numeric value for this attribute value. */
|
F16DOT16 value; /* A numeric value for this attribute value. */
|
||||||
public:
|
public:
|
||||||
DEFINE_SIZE_STATIC (6);
|
DEFINE_SIZE_STATIC (6);
|
||||||
};
|
};
|
||||||
|
|
|
@ -44,9 +44,47 @@ struct InstanceRecord
|
||||||
{
|
{
|
||||||
friend struct fvar;
|
friend struct fvar;
|
||||||
|
|
||||||
hb_array_t<const HBFixed> get_coordinates (unsigned int axis_count) const
|
hb_array_t<const F16DOT16> get_coordinates (unsigned int axis_count) const
|
||||||
{ return coordinatesZ.as_array (axis_count); }
|
{ return coordinatesZ.as_array (axis_count); }
|
||||||
|
|
||||||
|
bool subset (hb_subset_context_t *c,
|
||||||
|
unsigned axis_count,
|
||||||
|
bool has_postscript_nameid) const
|
||||||
|
{
|
||||||
|
TRACE_SUBSET (this);
|
||||||
|
if (unlikely (!c->serializer->embed (subfamilyNameID))) return_trace (false);
|
||||||
|
if (unlikely (!c->serializer->embed (flags))) return_trace (false);
|
||||||
|
|
||||||
|
const hb_array_t<const F16DOT16> coords = get_coordinates (axis_count);
|
||||||
|
const hb_hashmap_t<hb_tag_t, float> *axes_location = c->plan->user_axes_location;
|
||||||
|
for (unsigned i = 0 ; i < axis_count; i++)
|
||||||
|
{
|
||||||
|
uint32_t *axis_tag;
|
||||||
|
// only keep instances whose coordinates == pinned axis location
|
||||||
|
if (!c->plan->axes_old_index_tag_map->has (i, &axis_tag)) continue;
|
||||||
|
|
||||||
|
if (axes_location->has (*axis_tag) &&
|
||||||
|
fabsf (axes_location->get (*axis_tag) - coords[i].to_float ()) > 0.001f)
|
||||||
|
return_trace (false);
|
||||||
|
|
||||||
|
if (!c->plan->axes_index_map->has (i))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!c->serializer->embed (coords[i]))
|
||||||
|
return_trace (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_postscript_nameid)
|
||||||
|
{
|
||||||
|
NameID name_id;
|
||||||
|
name_id = StructAfter<NameID> (coords);
|
||||||
|
if (!c->serializer->embed (name_id))
|
||||||
|
return_trace (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return_trace (true);
|
||||||
|
}
|
||||||
|
|
||||||
bool sanitize (hb_sanitize_context_t *c, unsigned int axis_count) const
|
bool sanitize (hb_sanitize_context_t *c, unsigned int axis_count) const
|
||||||
{
|
{
|
||||||
TRACE_SANITIZE (this);
|
TRACE_SANITIZE (this);
|
||||||
|
@ -58,7 +96,7 @@ struct InstanceRecord
|
||||||
NameID subfamilyNameID;/* The name ID for entries in the 'name' table
|
NameID subfamilyNameID;/* The name ID for entries in the 'name' table
|
||||||
* that provide subfamily names for this instance. */
|
* that provide subfamily names for this instance. */
|
||||||
HBUINT16 flags; /* Reserved for future use — set to 0. */
|
HBUINT16 flags; /* Reserved for future use — set to 0. */
|
||||||
UnsizedArrayOf<HBFixed>
|
UnsizedArrayOf<F16DOT16>
|
||||||
coordinatesZ; /* The coordinates array for this instance. */
|
coordinatesZ; /* The coordinates array for this instance. */
|
||||||
//NameID postScriptNameIDX;/*Optional. The name ID for entries in the 'name'
|
//NameID postScriptNameIDX;/*Optional. The name ID for entries in the 'name'
|
||||||
// * table that provide PostScript names for this
|
// * table that provide PostScript names for this
|
||||||
|
@ -151,9 +189,9 @@ struct AxisRecord
|
||||||
public:
|
public:
|
||||||
Tag axisTag; /* Tag identifying the design variation for the axis. */
|
Tag axisTag; /* Tag identifying the design variation for the axis. */
|
||||||
protected:
|
protected:
|
||||||
HBFixed minValue; /* The minimum coordinate value for the axis. */
|
F16DOT16 minValue; /* The minimum coordinate value for the axis. */
|
||||||
HBFixed defaultValue; /* The default coordinate value for the axis. */
|
F16DOT16 defaultValue; /* The default coordinate value for the axis. */
|
||||||
HBFixed maxValue; /* The maximum coordinate value for the axis. */
|
F16DOT16 maxValue; /* The maximum coordinate value for the axis. */
|
||||||
public:
|
public:
|
||||||
HBUINT16 flags; /* Axis flags. */
|
HBUINT16 flags; /* Axis flags. */
|
||||||
NameID axisNameID; /* The name ID for entries in the 'name' table that
|
NameID axisNameID; /* The name ID for entries in the 'name' table that
|
||||||
|
@ -268,7 +306,7 @@ struct fvar
|
||||||
|
|
||||||
if (coords_length && *coords_length)
|
if (coords_length && *coords_length)
|
||||||
{
|
{
|
||||||
hb_array_t<const HBFixed> instanceCoords = instance->get_coordinates (axisCount)
|
hb_array_t<const F16DOT16> instanceCoords = instance->get_coordinates (axisCount)
|
||||||
.sub_array (0, coords_length);
|
.sub_array (0, coords_length);
|
||||||
for (unsigned int i = 0; i < instanceCoords.length; i++)
|
for (unsigned int i = 0; i < instanceCoords.length; i++)
|
||||||
coords[i] = instanceCoords.arrayZ[i].to_float ();
|
coords[i] = instanceCoords.arrayZ[i].to_float ();
|
||||||
|
@ -301,7 +339,7 @@ struct fvar
|
||||||
|
|
||||||
if (hb_any (+ hb_zip (instance->get_coordinates (axisCount), hb_range ((unsigned)axisCount))
|
if (hb_any (+ hb_zip (instance->get_coordinates (axisCount), hb_range ((unsigned)axisCount))
|
||||||
| hb_filter (pinned_axes, hb_second)
|
| hb_filter (pinned_axes, hb_second)
|
||||||
| hb_map ([&] (const hb_pair_t<const HBFixed&, unsigned>& _)
|
| hb_map ([&] (const hb_pair_t<const F16DOT16&, unsigned>& _)
|
||||||
{
|
{
|
||||||
hb_tag_t axis_tag = pinned_axes.get (_.second);
|
hb_tag_t axis_tag = pinned_axes.get (_.second);
|
||||||
float location = user_axes_location->get (axis_tag);
|
float location = user_axes_location->get (axis_tag);
|
||||||
|
@ -321,6 +359,48 @@ struct fvar
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool subset (hb_subset_context_t *c) const
|
||||||
|
{
|
||||||
|
TRACE_SUBSET (this);
|
||||||
|
unsigned retained_axis_count = c->plan->axes_index_map->get_population ();
|
||||||
|
if (!retained_axis_count) //all axes are pinned
|
||||||
|
return_trace (false);
|
||||||
|
|
||||||
|
fvar *out = c->serializer->embed (this);
|
||||||
|
if (unlikely (!out)) return_trace (false);
|
||||||
|
|
||||||
|
if (!c->serializer->check_assign (out->axisCount, retained_axis_count, HB_SERIALIZE_ERROR_INT_OVERFLOW))
|
||||||
|
return_trace (false);
|
||||||
|
|
||||||
|
bool has_postscript_nameid = false;
|
||||||
|
if (instanceSize >= axisCount * 4 + 6)
|
||||||
|
has_postscript_nameid = true;
|
||||||
|
|
||||||
|
if (!c->serializer->check_assign (out->instanceSize, retained_axis_count * 4 + (has_postscript_nameid ? 6 : 4),
|
||||||
|
HB_SERIALIZE_ERROR_INT_OVERFLOW))
|
||||||
|
return_trace (false);
|
||||||
|
|
||||||
|
auto axes_records = get_axes ();
|
||||||
|
for (unsigned i = 0 ; i < (unsigned)axisCount; i++)
|
||||||
|
{
|
||||||
|
if (!c->plan->axes_index_map->has (i)) continue;
|
||||||
|
if (unlikely (!c->serializer->embed (axes_records[i])))
|
||||||
|
return_trace (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!c->serializer->check_assign (out->firstAxis, get_size (), HB_SERIALIZE_ERROR_INT_OVERFLOW))
|
||||||
|
return_trace (false);
|
||||||
|
|
||||||
|
for (unsigned i = 0 ; i < (unsigned)instanceCount; i++)
|
||||||
|
{
|
||||||
|
const InstanceRecord *instance = get_instance (i);
|
||||||
|
auto snap = c->serializer->snapshot ();
|
||||||
|
if (!instance->subset (c, axisCount, has_postscript_nameid))
|
||||||
|
c->serializer->revert (snap);
|
||||||
|
}
|
||||||
|
return_trace (true);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
hb_array_t<const AxisRecord> get_axes () const
|
hb_array_t<const AxisRecord> get_axes () const
|
||||||
{ return hb_array (&(this+firstAxis), axisCount); }
|
{ return hb_array (&(this+firstAxis), axisCount); }
|
||||||
|
@ -346,8 +426,8 @@ struct fvar
|
||||||
HBUINT16 instanceCount; /* The number of named instances defined in the font
|
HBUINT16 instanceCount; /* The number of named instances defined in the font
|
||||||
* (the number of records in the instances array). */
|
* (the number of records in the instances array). */
|
||||||
HBUINT16 instanceSize; /* The size in bytes of each InstanceRecord — set
|
HBUINT16 instanceSize; /* The size in bytes of each InstanceRecord — set
|
||||||
* to either axisCount * sizeof(HBFixed) + 4, or to
|
* to either axisCount * sizeof(F16DOT16) + 4, or to
|
||||||
* axisCount * sizeof(HBFixed) + 6. */
|
* axisCount * sizeof(F16DOT16) + 6. */
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DEFINE_SIZE_STATIC (16);
|
DEFINE_SIZE_STATIC (16);
|
||||||
|
|
|
@ -209,7 +209,7 @@ bool _try_isolating_subgraphs (const hb_vector_t<graph::overflow_record_t>& over
|
||||||
// Only move at most half of the roots in a space at a time.
|
// Only move at most half of the roots in a space at a time.
|
||||||
unsigned extra = roots_to_isolate.get_population () - maximum_to_move;
|
unsigned extra = roots_to_isolate.get_population () - maximum_to_move;
|
||||||
while (extra--) {
|
while (extra--) {
|
||||||
unsigned root = HB_SET_VALUE_INVALID;
|
uint32_t root = HB_SET_VALUE_INVALID;
|
||||||
roots_to_isolate.previous (&root);
|
roots_to_isolate.previous (&root);
|
||||||
roots_to_isolate.del (root);
|
roots_to_isolate.del (root);
|
||||||
}
|
}
|
||||||
|
@ -244,7 +244,7 @@ bool _process_overflows (const hb_vector_t<graph::overflow_record_t>& overflows,
|
||||||
{
|
{
|
||||||
// The child object is shared, we may be able to eliminate the overflow
|
// The child object is shared, we may be able to eliminate the overflow
|
||||||
// by duplicating it.
|
// by duplicating it.
|
||||||
if (!sorted_graph.duplicate (r.parent, r.child)) continue;
|
if (sorted_graph.duplicate (r.parent, r.child) == (unsigned) -1) continue;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* Copyright © 2022 Google, Inc.
|
||||||
|
*
|
||||||
|
* This is part of HarfBuzz, a text shaping library.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, without written agreement and without
|
||||||
|
* license or royalty fees, to use, copy, modify, and distribute this
|
||||||
|
* software and its documentation for any purpose, provided that the
|
||||||
|
* above copyright notice and the following two paragraphs appear in
|
||||||
|
* all copies of this software.
|
||||||
|
*
|
||||||
|
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||||
|
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||||
|
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||||
|
* DAMAGE.
|
||||||
|
*
|
||||||
|
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||||
|
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||||
|
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||||
|
*
|
||||||
|
* Google Author(s): Garret Rieger
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HB_SUBSET_ACCELERATOR_HH
|
||||||
|
#define HB_SUBSET_ACCELERATOR_HH
|
||||||
|
|
||||||
|
|
||||||
|
#include "hb.hh"
|
||||||
|
|
||||||
|
#include "hb-map.hh"
|
||||||
|
#include "hb-set.hh"
|
||||||
|
|
||||||
|
extern HB_INTERNAL hb_user_data_key_t _hb_subset_accelerator_user_data_key;
|
||||||
|
|
||||||
|
struct hb_subset_accelerator_t
|
||||||
|
{
|
||||||
|
static hb_user_data_key_t* user_data_key()
|
||||||
|
{
|
||||||
|
return &_hb_subset_accelerator_user_data_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
static hb_subset_accelerator_t* create(const hb_map_t& unicode_to_gid_,
|
||||||
|
const hb_set_t& unicodes_) {
|
||||||
|
hb_subset_accelerator_t* accel =
|
||||||
|
(hb_subset_accelerator_t*) hb_malloc (sizeof(hb_subset_accelerator_t));
|
||||||
|
new (accel) hb_subset_accelerator_t (unicode_to_gid_, unicodes_);
|
||||||
|
return accel;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void destroy(void* value) {
|
||||||
|
if (!value) return;
|
||||||
|
|
||||||
|
hb_subset_accelerator_t* accel = (hb_subset_accelerator_t*) value;
|
||||||
|
accel->~hb_subset_accelerator_t ();
|
||||||
|
hb_free (accel);
|
||||||
|
}
|
||||||
|
|
||||||
|
hb_subset_accelerator_t(const hb_map_t& unicode_to_gid_,
|
||||||
|
const hb_set_t& unicodes_)
|
||||||
|
: unicode_to_gid(unicode_to_gid_), unicodes(unicodes_) {}
|
||||||
|
|
||||||
|
const hb_map_t unicode_to_gid;
|
||||||
|
const hb_set_t unicodes;
|
||||||
|
// TODO(garretrieger): cumulative glyf checksum map
|
||||||
|
// TODO(garretrieger): sanitized table cache.
|
||||||
|
|
||||||
|
bool in_error () const
|
||||||
|
{
|
||||||
|
return unicode_to_gid.in_error() || unicodes.in_error ();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* HB_SUBSET_ACCELERATOR_HH */
|
|
@ -89,7 +89,6 @@ hb_subset_input_create_or_fail (void)
|
||||||
|
|
||||||
hb_tag_t default_no_subset_tables[] = {
|
hb_tag_t default_no_subset_tables[] = {
|
||||||
HB_TAG ('a', 'v', 'a', 'r'),
|
HB_TAG ('a', 'v', 'a', 'r'),
|
||||||
HB_TAG ('f', 'v', 'a', 'r'),
|
|
||||||
HB_TAG ('g', 'a', 's', 'p'),
|
HB_TAG ('g', 'a', 's', 'p'),
|
||||||
HB_TAG ('c', 'v', 't', ' '),
|
HB_TAG ('c', 'v', 't', ' '),
|
||||||
HB_TAG ('f', 'p', 'g', 'm'),
|
HB_TAG ('f', 'p', 'g', 'm'),
|
||||||
|
@ -391,9 +390,9 @@ hb_subset_input_get_user_data (const hb_subset_input_t *input,
|
||||||
*
|
*
|
||||||
* Return value: `true` if success, `false` otherwise
|
* Return value: `true` if success, `false` otherwise
|
||||||
*
|
*
|
||||||
* Since: REPLACEME
|
* Since: EXPERIMENTAL
|
||||||
**/
|
**/
|
||||||
hb_bool_t
|
HB_EXTERN hb_bool_t
|
||||||
hb_subset_input_pin_axis_to_default (hb_subset_input_t *input,
|
hb_subset_input_pin_axis_to_default (hb_subset_input_t *input,
|
||||||
hb_face_t *face,
|
hb_face_t *face,
|
||||||
hb_tag_t axis_tag)
|
hb_tag_t axis_tag)
|
||||||
|
@ -415,9 +414,9 @@ hb_subset_input_pin_axis_to_default (hb_subset_input_t *input,
|
||||||
*
|
*
|
||||||
* Return value: `true` if success, `false` otherwise
|
* Return value: `true` if success, `false` otherwise
|
||||||
*
|
*
|
||||||
* Since: REPLACEME
|
* Since: EXPERIMENTAL
|
||||||
**/
|
**/
|
||||||
hb_bool_t
|
HB_EXTERN hb_bool_t
|
||||||
hb_subset_input_pin_axis_location (hb_subset_input_t *input,
|
hb_subset_input_pin_axis_location (hb_subset_input_t *input,
|
||||||
hb_face_t *face,
|
hb_face_t *face,
|
||||||
hb_tag_t axis_tag,
|
hb_tag_t axis_tag,
|
||||||
|
@ -432,3 +431,51 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HB_EXPERIMENTAL_API
|
||||||
|
/**
|
||||||
|
* hb_subset_preprocess
|
||||||
|
* @input: a #hb_face_t object.
|
||||||
|
*
|
||||||
|
* Preprocesses the face and attaches data that will be needed by the
|
||||||
|
* subsetter. Future subsetting operations can then use the precomputed data
|
||||||
|
* to speed up the subsetting operation.
|
||||||
|
*
|
||||||
|
* Since: EXPERIMENTAL
|
||||||
|
**/
|
||||||
|
|
||||||
|
HB_EXTERN hb_face_t *
|
||||||
|
hb_subset_preprocess (hb_face_t *source)
|
||||||
|
{
|
||||||
|
hb_subset_input_t* input = hb_subset_input_create_or_fail ();
|
||||||
|
|
||||||
|
hb_set_clear (hb_subset_input_set(input, HB_SUBSET_SETS_UNICODE));
|
||||||
|
hb_set_invert (hb_subset_input_set(input, HB_SUBSET_SETS_UNICODE));
|
||||||
|
|
||||||
|
hb_set_clear (hb_subset_input_set(input,
|
||||||
|
HB_SUBSET_SETS_LAYOUT_FEATURE_TAG));
|
||||||
|
hb_set_invert (hb_subset_input_set(input,
|
||||||
|
HB_SUBSET_SETS_LAYOUT_FEATURE_TAG));
|
||||||
|
|
||||||
|
hb_set_clear (hb_subset_input_set(input,
|
||||||
|
HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG));
|
||||||
|
hb_set_invert (hb_subset_input_set(input,
|
||||||
|
HB_SUBSET_SETS_LAYOUT_SCRIPT_TAG));
|
||||||
|
|
||||||
|
hb_set_clear (hb_subset_input_set(input,
|
||||||
|
HB_SUBSET_SETS_NAME_ID));
|
||||||
|
hb_set_invert (hb_subset_input_set(input,
|
||||||
|
HB_SUBSET_SETS_NAME_ID));
|
||||||
|
|
||||||
|
hb_subset_input_set_flags(input,
|
||||||
|
HB_SUBSET_FLAGS_NOTDEF_OUTLINE |
|
||||||
|
HB_SUBSET_FLAGS_GLYPH_NAMES |
|
||||||
|
HB_SUBSET_FLAGS_RETAIN_GIDS);
|
||||||
|
input->attach_accelerator_data = true;
|
||||||
|
|
||||||
|
hb_face_t* new_source = hb_subset_or_fail (source, input);
|
||||||
|
hb_subset_input_destroy (input);
|
||||||
|
|
||||||
|
return new_source;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -59,6 +59,7 @@ struct hb_subset_input_t
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned flags;
|
unsigned flags;
|
||||||
|
bool attach_accelerator_data = false;
|
||||||
hb_hashmap_t<hb_tag_t, float> *axes_location;
|
hb_hashmap_t<hb_tag_t, float> *axes_location;
|
||||||
|
|
||||||
inline unsigned num_sets () const
|
inline unsigned num_sets () const
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "hb-subset-plan.hh"
|
#include "hb-subset-plan.hh"
|
||||||
|
#include "hb-subset-accelerator.hh"
|
||||||
#include "hb-map.hh"
|
#include "hb-map.hh"
|
||||||
#include "hb-set.hh"
|
#include "hb-set.hh"
|
||||||
|
|
||||||
|
@ -129,7 +130,9 @@ template <typename T>
|
||||||
static void _collect_layout_indices (hb_subset_plan_t *plan,
|
static void _collect_layout_indices (hb_subset_plan_t *plan,
|
||||||
const T& table,
|
const T& table,
|
||||||
hb_set_t *lookup_indices, /* OUT */
|
hb_set_t *lookup_indices, /* OUT */
|
||||||
hb_set_t *feature_indices /* OUT */)
|
hb_set_t *feature_indices, /* OUT */
|
||||||
|
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map, /* OUT */
|
||||||
|
hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map /* OUT */)
|
||||||
{
|
{
|
||||||
unsigned num_features = table.get_feature_count ();
|
unsigned num_features = table.get_feature_count ();
|
||||||
hb_vector_t<hb_tag_t> features;
|
hb_vector_t<hb_tag_t> features;
|
||||||
|
@ -154,16 +157,37 @@ static void _collect_layout_indices (hb_subset_plan_t *plan,
|
||||||
retain_all_features ? nullptr : features.arrayZ,
|
retain_all_features ? nullptr : features.arrayZ,
|
||||||
feature_indices);
|
feature_indices);
|
||||||
|
|
||||||
|
#ifndef HB_NO_VAR
|
||||||
|
// collect feature substitutes with variations
|
||||||
|
if (!plan->user_axes_location->is_empty ())
|
||||||
|
{
|
||||||
|
hb_hashmap_t<hb::shared_ptr<hb_map_t>, unsigned> conditionset_map;
|
||||||
|
OT::hb_collect_feature_substitutes_with_var_context_t c =
|
||||||
|
{
|
||||||
|
plan->axes_old_index_tag_map,
|
||||||
|
plan->axes_location,
|
||||||
|
feature_record_cond_idx_map,
|
||||||
|
feature_substitutes_map,
|
||||||
|
feature_indices,
|
||||||
|
true,
|
||||||
|
0,
|
||||||
|
&conditionset_map
|
||||||
|
};
|
||||||
|
table.collect_feature_substitutes_with_variations (&c);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
for (unsigned feature_index : *feature_indices)
|
for (unsigned feature_index : *feature_indices)
|
||||||
{
|
{
|
||||||
//TODO: replace HB_OT_LAYOUT_NO_VARIATIONS_INDEX with variation_index for
|
const OT::Feature* f = &(table.get_feature (feature_index));
|
||||||
//instancing
|
const OT::Feature **p = nullptr;
|
||||||
const OT::Feature &f = table.get_feature_variation (feature_index, HB_OT_LAYOUT_NO_VARIATIONS_INDEX);
|
if (feature_substitutes_map->has (feature_index, &p))
|
||||||
f.add_lookup_indexes_to (lookup_indices);
|
f = *p;
|
||||||
|
|
||||||
|
f->add_lookup_indexes_to (lookup_indices);
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: update for instancing: only collect lookups from feature_indexes that have no variations
|
table.feature_variation_collect_lookups (feature_indices, feature_substitutes_map, lookup_indices);
|
||||||
table.feature_variation_collect_lookups (feature_indices, lookup_indices);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -171,6 +195,7 @@ static inline void
|
||||||
_GSUBGPOS_find_duplicate_features (const OT::GSUBGPOS &g,
|
_GSUBGPOS_find_duplicate_features (const OT::GSUBGPOS &g,
|
||||||
const hb_map_t *lookup_indices,
|
const hb_map_t *lookup_indices,
|
||||||
const hb_set_t *feature_indices,
|
const hb_set_t *feature_indices,
|
||||||
|
const hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map,
|
||||||
hb_map_t *duplicate_feature_map /* OUT */)
|
hb_map_t *duplicate_feature_map /* OUT */)
|
||||||
{
|
{
|
||||||
if (feature_indices->is_empty ()) return;
|
if (feature_indices->is_empty ()) return;
|
||||||
|
@ -195,16 +220,22 @@ _GSUBGPOS_find_duplicate_features (const OT::GSUBGPOS &g,
|
||||||
hb_set_t* same_tag_features = unique_features.get (t);
|
hb_set_t* same_tag_features = unique_features.get (t);
|
||||||
for (unsigned other_f_index : same_tag_features->iter ())
|
for (unsigned other_f_index : same_tag_features->iter ())
|
||||||
{
|
{
|
||||||
const OT::Feature& f = g.get_feature (i);
|
const OT::Feature* f = &(g.get_feature (i));
|
||||||
const OT::Feature& other_f = g.get_feature (other_f_index);
|
const OT::Feature **p = nullptr;
|
||||||
|
if (feature_substitutes_map->has (i, &p))
|
||||||
|
f = *p;
|
||||||
|
|
||||||
|
const OT::Feature* other_f = &(g.get_feature (other_f_index));
|
||||||
|
if (feature_substitutes_map->has (other_f_index, &p))
|
||||||
|
f = *p;
|
||||||
|
|
||||||
auto f_iter =
|
auto f_iter =
|
||||||
+ hb_iter (f.lookupIndex)
|
+ hb_iter (f->lookupIndex)
|
||||||
| hb_filter (lookup_indices)
|
| hb_filter (lookup_indices)
|
||||||
;
|
;
|
||||||
|
|
||||||
auto other_f_iter =
|
auto other_f_iter =
|
||||||
+ hb_iter (other_f.lookupIndex)
|
+ hb_iter (other_f->lookupIndex)
|
||||||
| hb_filter (lookup_indices)
|
| hb_filter (lookup_indices)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -237,7 +268,9 @@ _closure_glyphs_lookups_features (hb_subset_plan_t *plan,
|
||||||
hb_set_t *gids_to_retain,
|
hb_set_t *gids_to_retain,
|
||||||
hb_map_t *lookups,
|
hb_map_t *lookups,
|
||||||
hb_map_t *features,
|
hb_map_t *features,
|
||||||
script_langsys_map *langsys_map)
|
script_langsys_map *langsys_map,
|
||||||
|
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *feature_record_cond_idx_map,
|
||||||
|
hb_hashmap_t<unsigned, const OT::Feature*> *feature_substitutes_map)
|
||||||
{
|
{
|
||||||
hb_blob_ptr_t<T> table = plan->source_table<T> ();
|
hb_blob_ptr_t<T> table = plan->source_table<T> ();
|
||||||
hb_tag_t table_tag = table->tableTag;
|
hb_tag_t table_tag = table->tableTag;
|
||||||
|
@ -245,7 +278,9 @@ _closure_glyphs_lookups_features (hb_subset_plan_t *plan,
|
||||||
_collect_layout_indices<T> (plan,
|
_collect_layout_indices<T> (plan,
|
||||||
*table,
|
*table,
|
||||||
&lookup_indices,
|
&lookup_indices,
|
||||||
&feature_indices);
|
&feature_indices,
|
||||||
|
feature_record_cond_idx_map,
|
||||||
|
feature_substitutes_map);
|
||||||
|
|
||||||
if (table_tag == HB_OT_TAG_GSUB)
|
if (table_tag == HB_OT_TAG_GSUB)
|
||||||
hb_ot_layout_lookups_substitute_closure (plan->source,
|
hb_ot_layout_lookups_substitute_closure (plan->source,
|
||||||
|
@ -257,9 +292,12 @@ _closure_glyphs_lookups_features (hb_subset_plan_t *plan,
|
||||||
_remap_indexes (&lookup_indices, lookups);
|
_remap_indexes (&lookup_indices, lookups);
|
||||||
|
|
||||||
// prune features
|
// prune features
|
||||||
table->prune_features (lookups, &feature_indices);
|
table->prune_features (lookups,
|
||||||
|
plan->user_axes_location->is_empty () ? nullptr : feature_record_cond_idx_map,
|
||||||
|
feature_substitutes_map,
|
||||||
|
&feature_indices);
|
||||||
hb_map_t duplicate_feature_map;
|
hb_map_t duplicate_feature_map;
|
||||||
_GSUBGPOS_find_duplicate_features (*table, lookups, &feature_indices, &duplicate_feature_map);
|
_GSUBGPOS_find_duplicate_features (*table, lookups, &feature_indices, feature_substitutes_map, &duplicate_feature_map);
|
||||||
|
|
||||||
feature_indices.clear ();
|
feature_indices.clear ();
|
||||||
table->prune_langsys (&duplicate_feature_map, plan->layout_scripts, langsys_map, &feature_indices);
|
table->prune_langsys (&duplicate_feature_map, plan->layout_scripts, langsys_map, &feature_indices);
|
||||||
|
@ -419,14 +457,19 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes,
|
||||||
hb_subset_plan_t *plan)
|
hb_subset_plan_t *plan)
|
||||||
{
|
{
|
||||||
OT::cmap::accelerator_t cmap (plan->source);
|
OT::cmap::accelerator_t cmap (plan->source);
|
||||||
|
|
||||||
unsigned size_threshold = plan->source->get_num_glyphs ();
|
unsigned size_threshold = plan->source->get_num_glyphs ();
|
||||||
if (glyphs->is_empty () && unicodes->get_population () < size_threshold)
|
if (glyphs->is_empty () && unicodes->get_population () < size_threshold)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
const hb_map_t* unicode_to_gid = nullptr;
|
||||||
|
if (plan->accelerator)
|
||||||
|
unicode_to_gid = &plan->accelerator->unicode_to_gid;
|
||||||
|
|
||||||
// This is approach to collection is faster, but can only be used if glyphs
|
// This is approach to collection is faster, but can only be used if glyphs
|
||||||
// are not being explicitly added to the subset and the input unicodes set is
|
// are not being explicitly added to the subset and the input unicodes set is
|
||||||
// not excessively large (eg. an inverted set).
|
// not excessively large (eg. an inverted set).
|
||||||
plan->unicode_to_new_gid_list.alloc (unicodes->get_population ());
|
plan->unicode_to_new_gid_list.alloc (unicodes->get_population ());
|
||||||
|
if (!unicode_to_gid) {
|
||||||
for (hb_codepoint_t cp : *unicodes)
|
for (hb_codepoint_t cp : *unicodes)
|
||||||
{
|
{
|
||||||
hb_codepoint_t gid;
|
hb_codepoint_t gid;
|
||||||
|
@ -439,21 +482,48 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes,
|
||||||
plan->codepoint_to_glyph->set (cp, gid);
|
plan->codepoint_to_glyph->set (cp, gid);
|
||||||
plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
|
plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// Use in memory unicode to gid map it's faster then looking up from
|
||||||
|
// the map. This code is mostly duplicated from above to avoid doing
|
||||||
|
// conditionals on the presence of the unicode_to_gid map each
|
||||||
|
// iteration.
|
||||||
|
for (hb_codepoint_t cp : *unicodes)
|
||||||
|
{
|
||||||
|
hb_codepoint_t gid = unicode_to_gid->get (cp);
|
||||||
|
if (gid == HB_MAP_VALUE_INVALID)
|
||||||
|
{
|
||||||
|
DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
plan->codepoint_to_glyph->set (cp, gid);
|
||||||
|
plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// This approach is slower, but can handle adding in glyphs to the subset and will match
|
// This approach is slower, but can handle adding in glyphs to the subset and will match
|
||||||
// them with cmap entries.
|
// them with cmap entries.
|
||||||
hb_map_t unicode_glyphid_map;
|
|
||||||
hb_set_t cmap_unicodes;
|
hb_map_t unicode_glyphid_map_storage;
|
||||||
cmap.collect_mapping (&cmap_unicodes, &unicode_glyphid_map);
|
hb_set_t cmap_unicodes_storage;
|
||||||
|
const hb_map_t* unicode_glyphid_map = &unicode_glyphid_map_storage;
|
||||||
|
const hb_set_t* cmap_unicodes = &cmap_unicodes_storage;
|
||||||
|
|
||||||
|
if (!plan->accelerator) {
|
||||||
|
cmap.collect_mapping (&cmap_unicodes_storage, &unicode_glyphid_map_storage);
|
||||||
plan->unicode_to_new_gid_list.alloc (hb_min(unicodes->get_population ()
|
plan->unicode_to_new_gid_list.alloc (hb_min(unicodes->get_population ()
|
||||||
+ glyphs->get_population (),
|
+ glyphs->get_population (),
|
||||||
cmap_unicodes.get_population ()));
|
cmap_unicodes->get_population ()));
|
||||||
|
} else {
|
||||||
|
unicode_glyphid_map = &plan->accelerator->unicode_to_gid;
|
||||||
|
cmap_unicodes = &plan->accelerator->unicodes;
|
||||||
|
}
|
||||||
|
|
||||||
for (hb_codepoint_t cp : cmap_unicodes)
|
for (hb_codepoint_t cp : *cmap_unicodes)
|
||||||
{
|
{
|
||||||
hb_codepoint_t gid = unicode_glyphid_map[cp];
|
hb_codepoint_t gid = (*unicode_glyphid_map)[cp];
|
||||||
if (!unicodes->has (cp) && !glyphs->has (gid))
|
if (!unicodes->has (cp) && !glyphs->has (gid))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -509,9 +579,7 @@ _glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf,
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_populate_gids_to_retain (hb_subset_plan_t* plan,
|
_populate_gids_to_retain (hb_subset_plan_t* plan,
|
||||||
bool close_over_gsub,
|
hb_set_t* drop_tables)
|
||||||
bool close_over_gpos,
|
|
||||||
bool close_over_gdef)
|
|
||||||
{
|
{
|
||||||
OT::glyf_accelerator_t glyf (plan->source);
|
OT::glyf_accelerator_t glyf (plan->source);
|
||||||
#ifndef HB_NO_SUBSET_CFF
|
#ifndef HB_NO_SUBSET_CFF
|
||||||
|
@ -523,32 +591,42 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
|
||||||
_cmap_closure (plan->source, plan->unicodes, plan->_glyphset_gsub);
|
_cmap_closure (plan->source, plan->unicodes, plan->_glyphset_gsub);
|
||||||
|
|
||||||
#ifndef HB_NO_SUBSET_LAYOUT
|
#ifndef HB_NO_SUBSET_LAYOUT
|
||||||
if (close_over_gsub)
|
if (!drop_tables->has (HB_OT_TAG_GSUB))
|
||||||
// closure all glyphs/lookups/features needed for GSUB substitutions.
|
// closure all glyphs/lookups/features needed for GSUB substitutions.
|
||||||
_closure_glyphs_lookups_features<GSUB> (
|
_closure_glyphs_lookups_features<GSUB> (
|
||||||
plan,
|
plan,
|
||||||
plan->_glyphset_gsub,
|
plan->_glyphset_gsub,
|
||||||
plan->gsub_lookups,
|
plan->gsub_lookups,
|
||||||
plan->gsub_features,
|
plan->gsub_features,
|
||||||
plan->gsub_langsys);
|
plan->gsub_langsys,
|
||||||
|
plan->gsub_feature_record_cond_idx_map,
|
||||||
|
plan->gsub_feature_substitutes_map);
|
||||||
|
|
||||||
if (close_over_gpos)
|
if (!drop_tables->has (HB_OT_TAG_GPOS))
|
||||||
_closure_glyphs_lookups_features<GPOS> (
|
_closure_glyphs_lookups_features<GPOS> (
|
||||||
plan,
|
plan,
|
||||||
plan->_glyphset_gsub,
|
plan->_glyphset_gsub,
|
||||||
plan->gpos_lookups,
|
plan->gpos_lookups,
|
||||||
plan->gpos_features,
|
plan->gpos_features,
|
||||||
plan->gpos_langsys);
|
plan->gpos_langsys,
|
||||||
|
plan->gpos_feature_record_cond_idx_map,
|
||||||
|
plan->gpos_feature_substitutes_map);
|
||||||
#endif
|
#endif
|
||||||
_remove_invalid_gids (plan->_glyphset_gsub, plan->source->get_num_glyphs ());
|
_remove_invalid_gids (plan->_glyphset_gsub, plan->source->get_num_glyphs ());
|
||||||
|
|
||||||
hb_set_set (plan->_glyphset_mathed, plan->_glyphset_gsub);
|
hb_set_set (plan->_glyphset_mathed, plan->_glyphset_gsub);
|
||||||
|
if (!drop_tables->has (HB_OT_TAG_MATH))
|
||||||
|
{
|
||||||
_math_closure (plan, plan->_glyphset_mathed);
|
_math_closure (plan, plan->_glyphset_mathed);
|
||||||
_remove_invalid_gids (plan->_glyphset_mathed, plan->source->get_num_glyphs ());
|
_remove_invalid_gids (plan->_glyphset_mathed, plan->source->get_num_glyphs ());
|
||||||
|
}
|
||||||
|
|
||||||
hb_set_t cur_glyphset = *plan->_glyphset_mathed;
|
hb_set_t cur_glyphset = *plan->_glyphset_mathed;
|
||||||
|
if (!drop_tables->has (HB_OT_TAG_COLR))
|
||||||
|
{
|
||||||
_colr_closure (plan->source, plan->colrv1_layers, plan->colr_palettes, &cur_glyphset);
|
_colr_closure (plan->source, plan->colrv1_layers, plan->colr_palettes, &cur_glyphset);
|
||||||
_remove_invalid_gids (&cur_glyphset, plan->source->get_num_glyphs ());
|
_remove_invalid_gids (&cur_glyphset, plan->source->get_num_glyphs ());
|
||||||
|
}
|
||||||
|
|
||||||
hb_set_set (plan->_glyphset_colred, &cur_glyphset);
|
hb_set_set (plan->_glyphset_colred, &cur_glyphset);
|
||||||
|
|
||||||
|
@ -570,7 +648,7 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
|
||||||
|
|
||||||
|
|
||||||
#ifndef HB_NO_VAR
|
#ifndef HB_NO_VAR
|
||||||
if (close_over_gdef)
|
if (!drop_tables->has (HB_OT_TAG_GDEF))
|
||||||
_collect_layout_variation_indices (plan);
|
_collect_layout_variation_indices (plan);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -659,18 +737,22 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
|
||||||
seg_maps = face->table.avar->get_segment_maps ();
|
seg_maps = face->table.avar->get_segment_maps ();
|
||||||
|
|
||||||
bool axis_not_pinned = false;
|
bool axis_not_pinned = false;
|
||||||
unsigned axis_count = 0;
|
unsigned old_axis_idx = 0, new_axis_idx = 0;
|
||||||
for (const auto& axis : axes)
|
for (const auto& axis : axes)
|
||||||
{
|
{
|
||||||
hb_tag_t axis_tag = axis.get_axis_tag ();
|
hb_tag_t axis_tag = axis.get_axis_tag ();
|
||||||
|
plan->axes_old_index_tag_map->set (old_axis_idx, axis_tag);
|
||||||
|
|
||||||
if (!plan->user_axes_location->has (axis_tag))
|
if (!plan->user_axes_location->has (axis_tag))
|
||||||
{
|
{
|
||||||
axis_not_pinned = true;
|
axis_not_pinned = true;
|
||||||
|
plan->axes_index_map->set (old_axis_idx, new_axis_idx);
|
||||||
|
new_axis_idx++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int normalized_v = axis.normalize_axis_value (plan->user_axes_location->get (axis_tag));
|
int normalized_v = axis.normalize_axis_value (plan->user_axes_location->get (axis_tag));
|
||||||
if (has_avar && axis_count < face->table.avar->get_axis_count ())
|
if (has_avar && old_axis_idx < face->table.avar->get_axis_count ())
|
||||||
{
|
{
|
||||||
normalized_v = seg_maps->map (normalized_v);
|
normalized_v = seg_maps->map (normalized_v);
|
||||||
}
|
}
|
||||||
|
@ -681,7 +763,7 @@ _normalize_axes_location (hb_face_t *face, hb_subset_plan_t *plan)
|
||||||
if (has_avar)
|
if (has_avar)
|
||||||
seg_maps = &StructAfter<OT::SegmentMaps> (*seg_maps);
|
seg_maps = &StructAfter<OT::SegmentMaps> (*seg_maps);
|
||||||
|
|
||||||
axis_count++;
|
old_axis_idx++;
|
||||||
}
|
}
|
||||||
plan->all_axes_pinned = !axis_not_pinned;
|
plan->all_axes_pinned = !axis_not_pinned;
|
||||||
}
|
}
|
||||||
|
@ -741,6 +823,13 @@ hb_subset_plan_create_or_fail (hb_face_t *face,
|
||||||
|
|
||||||
plan->gsub_features = hb_map_create ();
|
plan->gsub_features = hb_map_create ();
|
||||||
plan->gpos_features = hb_map_create ();
|
plan->gpos_features = hb_map_create ();
|
||||||
|
|
||||||
|
plan->check_success (plan->gsub_feature_record_cond_idx_map = hb_hashmap_create<unsigned, hb::shared_ptr<hb_set_t>> ());
|
||||||
|
plan->check_success (plan->gpos_feature_record_cond_idx_map = hb_hashmap_create<unsigned, hb::shared_ptr<hb_set_t>> ());
|
||||||
|
|
||||||
|
plan->check_success (plan->gsub_feature_substitutes_map = hb_hashmap_create<unsigned, const OT::Feature*> ());
|
||||||
|
plan->check_success (plan->gpos_feature_substitutes_map = hb_hashmap_create<unsigned, const OT::Feature*> ());
|
||||||
|
|
||||||
plan->colrv1_layers = hb_map_create ();
|
plan->colrv1_layers = hb_map_create ();
|
||||||
plan->colr_palettes = hb_map_create ();
|
plan->colr_palettes = hb_map_create ();
|
||||||
plan->check_success (plan->layout_variation_idx_delta_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ());
|
plan->check_success (plan->layout_variation_idx_delta_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ());
|
||||||
|
@ -751,12 +840,21 @@ hb_subset_plan_create_or_fail (hb_face_t *face,
|
||||||
plan->check_success (plan->user_axes_location = hb_hashmap_create<hb_tag_t, float> ());
|
plan->check_success (plan->user_axes_location = hb_hashmap_create<hb_tag_t, float> ());
|
||||||
if (plan->user_axes_location && input->axes_location)
|
if (plan->user_axes_location && input->axes_location)
|
||||||
*plan->user_axes_location = *input->axes_location;
|
*plan->user_axes_location = *input->axes_location;
|
||||||
|
plan->check_success (plan->axes_index_map = hb_map_create ());
|
||||||
|
plan->check_success (plan->axes_old_index_tag_map = hb_map_create ());
|
||||||
plan->all_axes_pinned = false;
|
plan->all_axes_pinned = false;
|
||||||
plan->pinned_at_default = true;
|
plan->pinned_at_default = true;
|
||||||
|
|
||||||
plan->check_success (plan->vmtx_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ());
|
plan->check_success (plan->vmtx_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ());
|
||||||
plan->check_success (plan->hmtx_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ());
|
plan->check_success (plan->hmtx_map = hb_hashmap_create<unsigned, hb_pair_t<unsigned, int>> ());
|
||||||
|
|
||||||
|
void* accel = hb_face_get_user_data(face, hb_subset_accelerator_t::user_data_key());
|
||||||
|
|
||||||
|
plan->attach_accelerator_data = input->attach_accelerator_data;
|
||||||
|
if (accel)
|
||||||
|
plan->accelerator = (hb_subset_accelerator_t*) accel;
|
||||||
|
|
||||||
|
|
||||||
if (unlikely (plan->in_error ())) {
|
if (unlikely (plan->in_error ())) {
|
||||||
hb_subset_plan_destroy (plan);
|
hb_subset_plan_destroy (plan);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -768,10 +866,7 @@ hb_subset_plan_create_or_fail (hb_face_t *face,
|
||||||
|
|
||||||
_populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, plan);
|
_populate_unicodes_to_retain (input->sets.unicodes, input->sets.glyphs, plan);
|
||||||
|
|
||||||
_populate_gids_to_retain (plan,
|
_populate_gids_to_retain (plan, input->sets.drop_tables);
|
||||||
!input->sets.drop_tables->has (HB_OT_TAG_GSUB),
|
|
||||||
!input->sets.drop_tables->has (HB_OT_TAG_GPOS),
|
|
||||||
!input->sets.drop_tables->has (HB_OT_TAG_GDEF));
|
|
||||||
|
|
||||||
_create_old_gid_to_new_gid_map (face,
|
_create_old_gid_to_new_gid_map (face,
|
||||||
input->flags & HB_SUBSET_FLAGS_RETAIN_GIDS,
|
input->flags & HB_SUBSET_FLAGS_RETAIN_GIDS,
|
||||||
|
|
|
@ -31,11 +31,16 @@
|
||||||
|
|
||||||
#include "hb-subset.h"
|
#include "hb-subset.h"
|
||||||
#include "hb-subset-input.hh"
|
#include "hb-subset-input.hh"
|
||||||
|
#include "hb-subset-accelerator.hh"
|
||||||
|
|
||||||
#include "hb-map.hh"
|
#include "hb-map.hh"
|
||||||
#include "hb-bimap.hh"
|
#include "hb-bimap.hh"
|
||||||
#include "hb-set.hh"
|
#include "hb-set.hh"
|
||||||
|
|
||||||
|
namespace OT {
|
||||||
|
struct Feature;
|
||||||
|
}
|
||||||
|
|
||||||
struct hb_subset_plan_t
|
struct hb_subset_plan_t
|
||||||
{
|
{
|
||||||
hb_subset_plan_t ()
|
hb_subset_plan_t ()
|
||||||
|
@ -67,9 +72,15 @@ struct hb_subset_plan_t
|
||||||
hb_map_destroy (gpos_features);
|
hb_map_destroy (gpos_features);
|
||||||
hb_map_destroy (colrv1_layers);
|
hb_map_destroy (colrv1_layers);
|
||||||
hb_map_destroy (colr_palettes);
|
hb_map_destroy (colr_palettes);
|
||||||
|
hb_map_destroy (axes_index_map);
|
||||||
|
hb_map_destroy (axes_old_index_tag_map);
|
||||||
|
|
||||||
hb_hashmap_destroy (gsub_langsys);
|
hb_hashmap_destroy (gsub_langsys);
|
||||||
hb_hashmap_destroy (gpos_langsys);
|
hb_hashmap_destroy (gpos_langsys);
|
||||||
|
hb_hashmap_destroy (gsub_feature_record_cond_idx_map);
|
||||||
|
hb_hashmap_destroy (gpos_feature_record_cond_idx_map);
|
||||||
|
hb_hashmap_destroy (gsub_feature_substitutes_map);
|
||||||
|
hb_hashmap_destroy (gpos_feature_substitutes_map);
|
||||||
hb_hashmap_destroy (axes_location);
|
hb_hashmap_destroy (axes_location);
|
||||||
hb_hashmap_destroy (sanitized_table_cache);
|
hb_hashmap_destroy (sanitized_table_cache);
|
||||||
hb_hashmap_destroy (hmtx_map);
|
hb_hashmap_destroy (hmtx_map);
|
||||||
|
@ -87,6 +98,7 @@ struct hb_subset_plan_t
|
||||||
|
|
||||||
bool successful;
|
bool successful;
|
||||||
unsigned flags;
|
unsigned flags;
|
||||||
|
bool attach_accelerator_data = false;
|
||||||
|
|
||||||
// For each cp that we'd like to retain maps to the corresponding gid.
|
// For each cp that we'd like to retain maps to the corresponding gid.
|
||||||
hb_set_t *unicodes;
|
hb_set_t *unicodes;
|
||||||
|
@ -143,6 +155,15 @@ struct hb_subset_plan_t
|
||||||
hb_map_t *gsub_features;
|
hb_map_t *gsub_features;
|
||||||
hb_map_t *gpos_features;
|
hb_map_t *gpos_features;
|
||||||
|
|
||||||
|
//active feature variation records/condition index with variations
|
||||||
|
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *gsub_feature_record_cond_idx_map;
|
||||||
|
hb_hashmap_t<unsigned, hb::shared_ptr<hb_set_t>> *gpos_feature_record_cond_idx_map;
|
||||||
|
|
||||||
|
//feature index-> address of substituation feature table mapping with
|
||||||
|
//variations
|
||||||
|
hb_hashmap_t<unsigned, const OT::Feature*> *gsub_feature_substitutes_map;
|
||||||
|
hb_hashmap_t<unsigned, const OT::Feature*> *gpos_feature_substitutes_map;
|
||||||
|
|
||||||
//active layers/palettes we'd like to retain
|
//active layers/palettes we'd like to retain
|
||||||
hb_map_t *colrv1_layers;
|
hb_map_t *colrv1_layers;
|
||||||
hb_map_t *colr_palettes;
|
hb_map_t *colr_palettes;
|
||||||
|
@ -158,6 +179,10 @@ struct hb_subset_plan_t
|
||||||
hb_hashmap_t<hb_tag_t, int> *axes_location;
|
hb_hashmap_t<hb_tag_t, int> *axes_location;
|
||||||
//user specified axes location map
|
//user specified axes location map
|
||||||
hb_hashmap_t<hb_tag_t, float> *user_axes_location;
|
hb_hashmap_t<hb_tag_t, float> *user_axes_location;
|
||||||
|
//retained old axis index -> new axis index mapping in fvar axis array
|
||||||
|
hb_map_t *axes_index_map;
|
||||||
|
//axis_index->axis_tag mapping in fvar axis array
|
||||||
|
hb_map_t *axes_old_index_tag_map;
|
||||||
bool all_axes_pinned;
|
bool all_axes_pinned;
|
||||||
bool pinned_at_default;
|
bool pinned_at_default;
|
||||||
|
|
||||||
|
@ -166,6 +191,8 @@ struct hb_subset_plan_t
|
||||||
//vmtx metrics map: new gid->(advance, lsb)
|
//vmtx metrics map: new gid->(advance, lsb)
|
||||||
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *vmtx_map;
|
hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *vmtx_map;
|
||||||
|
|
||||||
|
const hb_subset_accelerator_t* accelerator;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|
|
@ -50,11 +50,13 @@
|
||||||
#include "hb-ot-color-cbdt-table.hh"
|
#include "hb-ot-color-cbdt-table.hh"
|
||||||
#include "hb-ot-layout-gsub-table.hh"
|
#include "hb-ot-layout-gsub-table.hh"
|
||||||
#include "hb-ot-layout-gpos-table.hh"
|
#include "hb-ot-layout-gpos-table.hh"
|
||||||
|
#include "hb-ot-var-fvar-table.hh"
|
||||||
#include "hb-ot-var-gvar-table.hh"
|
#include "hb-ot-var-gvar-table.hh"
|
||||||
#include "hb-ot-var-hvar-table.hh"
|
#include "hb-ot-var-hvar-table.hh"
|
||||||
#include "hb-ot-math-table.hh"
|
#include "hb-ot-math-table.hh"
|
||||||
#include "hb-ot-stat-table.hh"
|
#include "hb-ot-stat-table.hh"
|
||||||
#include "hb-repacker.hh"
|
#include "hb-repacker.hh"
|
||||||
|
#include "hb-subset-accelerator.hh"
|
||||||
|
|
||||||
using OT::Layout::GSUB;
|
using OT::Layout::GSUB;
|
||||||
using OT::Layout::GPOS;
|
using OT::Layout::GPOS;
|
||||||
|
@ -80,6 +82,10 @@ using OT::Layout::GPOS;
|
||||||
* retain glyph ids option and configure the subset to pass through the layout tables untouched.
|
* retain glyph ids option and configure the subset to pass through the layout tables untouched.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
hb_user_data_key_t _hb_subset_accelerator_user_data_key = {};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The list of tables in the open type spec. Used to check for tables that may need handling
|
* The list of tables in the open type spec. Used to check for tables that may need handling
|
||||||
* if we are unable to list the tables in a face.
|
* if we are unable to list the tables in a face.
|
||||||
|
@ -475,6 +481,9 @@ _subset_table (hb_subset_plan_t *plan,
|
||||||
case HB_OT_TAG_HVAR: return _subset<const OT::HVAR> (plan, buf);
|
case HB_OT_TAG_HVAR: return _subset<const OT::HVAR> (plan, buf);
|
||||||
case HB_OT_TAG_VVAR: return _subset<const OT::VVAR> (plan, buf);
|
case HB_OT_TAG_VVAR: return _subset<const OT::VVAR> (plan, buf);
|
||||||
#endif
|
#endif
|
||||||
|
case HB_OT_TAG_fvar:
|
||||||
|
if (plan->user_axes_location->is_empty ()) return _passthrough (plan, tag);
|
||||||
|
return _subset<const OT::fvar> (plan, buf);
|
||||||
case HB_OT_TAG_STAT:
|
case HB_OT_TAG_STAT:
|
||||||
/*TODO(qxliu): change the condition as we support more complex
|
/*TODO(qxliu): change the condition as we support more complex
|
||||||
* instancing operation*/
|
* instancing operation*/
|
||||||
|
@ -490,6 +499,27 @@ _subset_table (hb_subset_plan_t *plan,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _attach_accelerator_data (const hb_subset_plan_t* plan,
|
||||||
|
hb_face_t* face /* IN/OUT */)
|
||||||
|
{
|
||||||
|
hb_subset_accelerator_t* accel =
|
||||||
|
hb_subset_accelerator_t::create (*plan->codepoint_to_glyph,
|
||||||
|
*plan->unicodes);
|
||||||
|
|
||||||
|
if (accel->in_error ())
|
||||||
|
{
|
||||||
|
hb_subset_accelerator_t::destroy (accel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hb_face_set_user_data(face,
|
||||||
|
hb_subset_accelerator_t::user_data_key(),
|
||||||
|
accel,
|
||||||
|
hb_subset_accelerator_t::destroy,
|
||||||
|
true))
|
||||||
|
hb_subset_accelerator_t::destroy (accel);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* hb_subset_or_fail:
|
* hb_subset_or_fail:
|
||||||
* @source: font face data to be subset.
|
* @source: font face data to be subset.
|
||||||
|
@ -572,6 +602,10 @@ hb_subset_plan_execute_or_fail (hb_subset_plan_t *plan)
|
||||||
offset += num_tables;
|
offset += num_tables;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (success && plan->attach_accelerator_data) {
|
||||||
|
_attach_accelerator_data (plan, plan->dest);
|
||||||
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
return success ? hb_face_reference (plan->dest) : nullptr;
|
return success ? hb_face_reference (plan->dest) : nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,14 @@ typedef struct hb_subset_plan_t hb_subset_plan_t;
|
||||||
* in the final subset.
|
* in the final subset.
|
||||||
* @HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES: If set then the unicode ranges in
|
* @HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES: If set then the unicode ranges in
|
||||||
* OS/2 will not be recalculated.
|
* OS/2 will not be recalculated.
|
||||||
|
* @HB_SUBSET_FLAGS_PATCH_MODE: If set the subsetter behaviour will be modified
|
||||||
|
* to produce a subset that is better suited to patching. For example cmap
|
||||||
|
* subtable format will be kept stable.
|
||||||
|
* @HB_SUBSET_FLAGS_OMIT_GLYF: If set the subsetter won't actually produce the final
|
||||||
|
* glyf table bytes. The table directory will include and entry as if the table was
|
||||||
|
* there but the actual final font blob will be truncated prior to the glyf data. This
|
||||||
|
* is a useful performance optimization when a font aware binary patching algorithm
|
||||||
|
* is being used to diff two subsets.
|
||||||
*
|
*
|
||||||
* List of boolean properties that can be configured on the subset input.
|
* List of boolean properties that can be configured on the subset input.
|
||||||
*
|
*
|
||||||
|
@ -86,6 +94,8 @@ typedef enum { /*< flags >*/
|
||||||
HB_SUBSET_FLAGS_NOTDEF_OUTLINE = 0x00000040u,
|
HB_SUBSET_FLAGS_NOTDEF_OUTLINE = 0x00000040u,
|
||||||
HB_SUBSET_FLAGS_GLYPH_NAMES = 0x00000080u,
|
HB_SUBSET_FLAGS_GLYPH_NAMES = 0x00000080u,
|
||||||
HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES = 0x00000100u,
|
HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES = 0x00000100u,
|
||||||
|
// Not supported yet: HB_SUBSET_FLAGS_PATCH_MODE = 0x00000200u,
|
||||||
|
// Not supported yet: HB_SUBSET_FLAGS_OMIT_GLYF = 0x00000400u,
|
||||||
} hb_subset_flags_t;
|
} hb_subset_flags_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -169,6 +179,13 @@ hb_subset_input_pin_axis_location (hb_subset_input_t *input,
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HB_EXPERIMENTAL_API
|
||||||
|
|
||||||
|
HB_EXTERN hb_face_t *
|
||||||
|
hb_subset_preprocess (hb_face_t *source);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
HB_EXTERN hb_face_t *
|
HB_EXTERN hb_face_t *
|
||||||
hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input);
|
hb_subset_or_fail (hb_face_t *source, const hb_subset_input_t *input);
|
||||||
|
|
||||||
|
|
|
@ -47,20 +47,20 @@ HB_BEGIN_DECLS
|
||||||
*
|
*
|
||||||
* The minor component of the library version available at compile-time.
|
* The minor component of the library version available at compile-time.
|
||||||
*/
|
*/
|
||||||
#define HB_VERSION_MINOR 1
|
#define HB_VERSION_MINOR 3
|
||||||
/**
|
/**
|
||||||
* HB_VERSION_MICRO:
|
* HB_VERSION_MICRO:
|
||||||
*
|
*
|
||||||
* The micro component of the library version available at compile-time.
|
* The micro component of the library version available at compile-time.
|
||||||
*/
|
*/
|
||||||
#define HB_VERSION_MICRO 0
|
#define HB_VERSION_MICRO 1
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HB_VERSION_STRING:
|
* HB_VERSION_STRING:
|
||||||
*
|
*
|
||||||
* A string literal containing the library version available at compile-time.
|
* A string literal containing the library version available at compile-time.
|
||||||
*/
|
*/
|
||||||
#define HB_VERSION_STRING "5.1.0"
|
#define HB_VERSION_STRING "5.3.1"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HB_VERSION_ATLEAST:
|
* HB_VERSION_ATLEAST:
|
||||||
|
|
|
@ -334,6 +334,7 @@ hb_subset_sources = files(
|
||||||
'hb-ot-cff1-table.cc',
|
'hb-ot-cff1-table.cc',
|
||||||
'hb-ot-cff2-table.cc',
|
'hb-ot-cff2-table.cc',
|
||||||
'hb-static.cc',
|
'hb-static.cc',
|
||||||
|
'hb-subset-accelerator.hh',
|
||||||
'hb-subset-cff-common.cc',
|
'hb-subset-cff-common.cc',
|
||||||
'hb-subset-cff-common.hh',
|
'hb-subset-cff-common.hh',
|
||||||
'hb-subset-cff1.cc',
|
'hb-subset-cff1.cc',
|
||||||
|
@ -656,8 +657,8 @@ endif
|
||||||
have_gobject = conf.get('HAVE_GOBJECT', 0) == 1
|
have_gobject = conf.get('HAVE_GOBJECT', 0) == 1
|
||||||
|
|
||||||
cmake_config = configuration_data()
|
cmake_config = configuration_data()
|
||||||
cmake_config.set('libdir', '${prefix}/@0@'.format(get_option('libdir')))
|
cmake_config.set('libdir', get_option('prefix') / get_option('libdir'))
|
||||||
cmake_config.set('includedir', '${prefix}/@0@'.format(get_option('includedir')))
|
cmake_config.set('includedir', get_option('prefix') / get_option('includedir'))
|
||||||
cmake_config.set('HB_LIBTOOL_VERSION_INFO', hb_libtool_version_info)
|
cmake_config.set('HB_LIBTOOL_VERSION_INFO', hb_libtool_version_info)
|
||||||
cmake_config.set('have_gobject', '@0@'.format(have_gobject))
|
cmake_config.set('have_gobject', '@0@'.format(have_gobject))
|
||||||
configure_file(input: 'harfbuzz-config.cmake.in',
|
configure_file(input: 'harfbuzz-config.cmake.in',
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
# Updated for Unicode 12.1 by Andrew Glass 2019-05-30
|
# Updated for Unicode 12.1 by Andrew Glass 2019-05-30
|
||||||
# Updated for Unicode 13.0 by Andrew Glass 2020-07-28
|
# Updated for Unicode 13.0 by Andrew Glass 2020-07-28
|
||||||
# Updated for Unicode 14.0 by Andrew Glass 2021-09-28
|
# Updated for Unicode 14.0 by Andrew Glass 2021-09-28
|
||||||
|
# Updated for Unicode 15.0 by Andrew Glass 2022-09-16
|
||||||
|
|
||||||
# ================================================
|
# ================================================
|
||||||
# ================================================
|
# ================================================
|
||||||
|
@ -19,9 +20,12 @@
|
||||||
0F7A..0F7D ; Bottom # Mn [4] TIBETAN VOWEL SIGN E..TIBETAN VOWEL SIGN OO # Not really below, but need to override to fit into Universal model
|
0F7A..0F7D ; Bottom # Mn [4] TIBETAN VOWEL SIGN E..TIBETAN VOWEL SIGN OO # Not really below, but need to override to fit into Universal model
|
||||||
0F80 ; Bottom # Mn TIBETAN VOWEL SIGN REVERSED I # Not really below, but need to override to fit into Universal model
|
0F80 ; Bottom # Mn TIBETAN VOWEL SIGN REVERSED I # Not really below, but need to override to fit into Universal model
|
||||||
A9BF ; Bottom # Mc JAVANESE CONSONANT SIGN CAKRA
|
A9BF ; Bottom # Mc JAVANESE CONSONANT SIGN CAKRA
|
||||||
|
10A38 ; Bottom # Mn KHAROSHTHI SIGN BAR ABOVE # Overriden, ccc controls order USE issue #26
|
||||||
11127..11129 ; Bottom # Mn [3] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN II
|
11127..11129 ; Bottom # Mn [3] CHAKMA VOWEL SIGN A..CHAKMA VOWEL SIGN II
|
||||||
1112D ; Bottom # Mn CHAKMA VOWEL SIGN AI
|
1112D ; Bottom # Mn CHAKMA VOWEL SIGN AI
|
||||||
11130 ; Bottom # Mn CHAKMA VOWEL SIGN OI
|
11130 ; Bottom # Mn CHAKMA VOWEL SIGN OI
|
||||||
|
1BF2..1BF3 ; Bottom # Mc [2] BATAK PANGOLAT..BATAK PANONGONAN # see USE issue #20
|
||||||
|
|
||||||
|
|
||||||
# ================================================
|
# ================================================
|
||||||
|
|
||||||
|
@ -42,12 +46,15 @@ A9BE ; Right # Mc JAVANESE CONSONANT SIGN PENGKAL # Reduced from
|
||||||
0F74 ; Top # Mn TIBETAN VOWEL SIGN U # Not really above, but need to override to fit into Universal model
|
0F74 ; Top # Mn TIBETAN VOWEL SIGN U # Not really above, but need to override to fit into Universal model
|
||||||
1A18 ; Top # Mn BUGINESE VOWEL SIGN U # Workaround to allow below to occur before above by treating all below marks as above
|
1A18 ; Top # Mn BUGINESE VOWEL SIGN U # Workaround to allow below to occur before above by treating all below marks as above
|
||||||
AA35 ; Top # Mn CHAM CONSONANT SIGN
|
AA35 ; Top # Mn CHAM CONSONANT SIGN
|
||||||
|
1112A..1112B ; Top # Mn [2] CHAKMA VOWEL SIGN U..CHAKMA VOWEL SIGN UU # see USE issue #25
|
||||||
|
11131..11132 ; Top # Mn [2] CHAKMA O MARK..CHAKMA AU MARK # see USE issue #25
|
||||||
|
1E4EC..1E4EF ; Top # Mn [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH # 1E4EE is below, but made to for ccc
|
||||||
|
|
||||||
# ================================================
|
# ================================================
|
||||||
|
|
||||||
# Indic_Positional_Category=Top_And_Right
|
# Indic_Positional_Category=Top_And_Right
|
||||||
0E33 ; Top_And_Right # Lo THAI CHARACTER SARA AM # IMC has Right, which seems to be a mistake.
|
0E33 ; Top_And_Right # Lo THAI CHARACTER SARA AM # IPC has Right, which seems to be a mistake.
|
||||||
0EB3 ; Top_And_Right # Lo LAO VOWEL SIGN AM # IMC has Right, which seems to be a mistake.
|
0EB3 ; Top_And_Right # Lo LAO VOWEL SIGN AM # IPC has Right, which seems to be a mistake.
|
||||||
|
|
||||||
# ================================================
|
# ================================================
|
||||||
# ================================================
|
# ================================================
|
||||||
|
@ -72,6 +79,9 @@ AA35 ; Top # Mn CHAM CONSONANT SIGN
|
||||||
16F4F ; Bottom # Mn MIAO SIGN CONSONANT MODIFIER BAR
|
16F4F ; Bottom # Mn MIAO SIGN CONSONANT MODIFIER BAR
|
||||||
16F51..16F87 ; Bottom # Mc [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI
|
16F51..16F87 ; Bottom # Mc [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI
|
||||||
16F8F..16F92 ; Bottom # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW
|
16F8F..16F92 ; Bottom # Mn [4] MIAO TONE RIGHT..MIAO TONE BELOW
|
||||||
|
#HIEROGLYPHS defined here while ISC is being used as a proxy for dedicated Hieroglyph cluster
|
||||||
|
13440 ; Bottom # Mn EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY
|
||||||
|
13447..13455 ; Bottom # Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED
|
||||||
|
|
||||||
# ================================================
|
# ================================================
|
||||||
|
|
||||||
|
@ -84,6 +94,7 @@ AA35 ; Top # Mn CHAM CONSONANT SIGN
|
||||||
07EB..07F3 ; Top # Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE
|
07EB..07F3 ; Top # Mn [9] NKO COMBINING SHORT HIGH TONE..NKO COMBINING DOUBLE DOT ABOVE
|
||||||
07FD ; Top # Mn NKO DANTAYALAN # Not really top, but assigned here to allow ccc to control mark order
|
07FD ; Top # Mn NKO DANTAYALAN # Not really top, but assigned here to allow ccc to control mark order
|
||||||
1885..1886 ; Top # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA
|
1885..1886 ; Top # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA
|
||||||
|
1CF8..1CF9 ; Top # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE
|
||||||
10D24..10D27 ; Top # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI
|
10D24..10D27 ; Top # Mn [4] HANIFI ROHINGYA SIGN HARBAHAY..HANIFI ROHINGYA SIGN TASSI
|
||||||
10EAB..10EAC ; Top # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK
|
10EAB..10EAC ; Top # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK
|
||||||
16B30..16B36 ; Top # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM
|
16B30..16B36 ; Top # Mn [7] PAHAWH HMONG MARK CIM TUB..PAHAWH HMONG MARK CIM TAUM
|
||||||
|
|
|
@ -89,6 +89,14 @@
|
||||||
11686 116B2 ; # TAKRI LETTER E, TAKRI VOWEL SIGN E
|
11686 116B2 ; # TAKRI LETTER E, TAKRI VOWEL SIGN E
|
||||||
11680 116B4 ; # TAKRI LETTER A, TAKRI VOWEL SIGN O
|
11680 116B4 ; # TAKRI LETTER A, TAKRI VOWEL SIGN O
|
||||||
11680 116B5 ; # TAKRI LETTER A, TAKRI VOWEL SIGN AU
|
11680 116B5 ; # TAKRI LETTER A, TAKRI VOWEL SIGN AU
|
||||||
|
11200 1122C ; # KHOJKI LETTER A, KHOJKI VOWEL SIGN AA
|
||||||
|
11240 1122E ; # KHOJKI LETTER SHORT I, KHOJKI VOWEL SIGN II
|
||||||
|
11206 1122C ; # KHOJKI LETTER O, KHOJKI VOWEL SIGN AA
|
||||||
|
11200 11231 ; # KHOJKI LETTER A, KHOJKI VOWEL SIGN AI
|
||||||
|
11200 11233 ; # KHOJKI LETTER A, KHOJKI VOWEL SIGN AU
|
||||||
|
11200 1122C 11231 ; # KHOJKI LETTER A, KHOJKI VOWEL SIGN AA, KHOJKI VOWEL SIGN AI
|
||||||
|
1122C 11230 ; # KHOJKI VOWEL SIGN AA, KHOJKI VOWEL SIGN E
|
||||||
|
1122C 11231 ; # KHOJKI VOWEL SIGN AA, KHOJKI VOWEL SIGN AI
|
||||||
112B0 112E0 ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN AA
|
112B0 112E0 ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN AA
|
||||||
112B0 112E5 ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN E
|
112B0 112E5 ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN E
|
||||||
112B0 112E6 ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN AI
|
112B0 112E6 ; # KHUDAWADI LETTER A, KHUDAWADI VOWEL SIGN AI
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
# Updated for Unicode 12.1 by Andrew Glass 2019-05-24
|
# Updated for Unicode 12.1 by Andrew Glass 2019-05-24
|
||||||
# Updated for Unicode 13.0 by Andrew Glass 2020-07-28
|
# Updated for Unicode 13.0 by Andrew Glass 2020-07-28
|
||||||
# Updated for Unicode 14.0 by Andrew Glass 2021-09-25
|
# Updated for Unicode 14.0 by Andrew Glass 2021-09-25
|
||||||
|
# Updated for Unicode 15.0 by Andrew Glass 2022-09-16
|
||||||
|
|
||||||
# ================================================
|
# ================================================
|
||||||
# OVERRIDES TO ASSIGNED VALUES
|
# OVERRIDES TO ASSIGNED VALUES
|
||||||
|
@ -18,23 +19,13 @@ AA29 ; Bindu # Mn CHAM VOWEL SIGN AA
|
||||||
# ================================================
|
# ================================================
|
||||||
|
|
||||||
# Indic_Syllabic_Category=Consonant
|
# Indic_Syllabic_Category=Consonant
|
||||||
0840..0858 ; Consonant # Lo [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN
|
|
||||||
0F00..0F01 ; Consonant # Lo [2] TIBETAN SYLLABLE OM..TIBETAN MARK GTER YIG MGO TRUNCATED
|
|
||||||
0F04..0F06 ; Consonant # Po TIBETAN MARK INITIAL YIG MGO MDUN MA..TIBETAN MARK CARET YIG MGO PHUR SHAD MA
|
|
||||||
19C1..19C7 ; Consonant # Lo [7] NEW TAI LUE LETTER FINAL V..NEW TAI LUE LETTER FINAL B # Reassigned to avoid clustering with a base consonant
|
19C1..19C7 ; Consonant # Lo [7] NEW TAI LUE LETTER FINAL V..NEW TAI LUE LETTER FINAL B # Reassigned to avoid clustering with a base consonant
|
||||||
25CC ; Consonant # So DOTTED CIRCLE
|
25CC ; Consonant # So DOTTED CIRCLE #Reassigned to allow it to cluster as a generic base
|
||||||
|
|
||||||
# ================================================
|
# ================================================
|
||||||
|
|
||||||
# Indic_Syllabic_Category=Consonant_Dead
|
# Indic_Syllabic_Category=Consonant_Dead
|
||||||
0F7F ; Consonant_Dead # Mc TIBETAN SIGN RNAM BCAD # reassigned so that visarga will form an independent cluster
|
0F7F ; Consonant_Dead # Mc TIBETAN SIGN RNAM BCAD # reassigned so that visarga can form an independent cluster, but see #19
|
||||||
|
|
||||||
# ================================================
|
|
||||||
|
|
||||||
# Indic_Syllabic_Category=Consonant_Final
|
|
||||||
0F35 ; Consonant_Final # Mn TIBETAN MARK NGAS BZUNG NYI ZLA
|
|
||||||
0F37 ; Consonant_Final # Mn TIBETAN MARK NGAS BZUNG SGOR RTAGS
|
|
||||||
0FC6 ; Consonant_Final # Mn TIBETAN SYMBOL PADMA GDAN
|
|
||||||
|
|
||||||
# ================================================
|
# ================================================
|
||||||
|
|
||||||
|
@ -49,8 +40,8 @@ AA29 ; Bindu # Mn CHAM VOWEL SIGN AA
|
||||||
# ================================================
|
# ================================================
|
||||||
|
|
||||||
# Indic_Syllabic_Category=Nukta
|
# Indic_Syllabic_Category=Nukta
|
||||||
0F71 ; Nukta # Mn TIBETAN VOWEL SIGN AA # Reassigned to get this before an above vowel
|
0F71 ; Nukta # Mn TIBETAN VOWEL SIGN AA # Reassigned to get this before an above vowel, but see #22
|
||||||
10A38..10A3A ; Nukta # Mn [3] KHAROSHTHI SIGN BAR ABOVE..KHAROSHTHI SIGN DOT BELOW
|
1BF2..1BF3 ; Nukta # Mc [2] BATAK PANGOLAT..BATAK PANONGONAN # see USE issue #20
|
||||||
|
|
||||||
# ================================================
|
# ================================================
|
||||||
|
|
||||||
|
@ -73,6 +64,9 @@ AABD ; Vowel_Independent # Lo TAI VIET VOWEL AN
|
||||||
|
|
||||||
# Indic_Syllabic_Category=Consonant
|
# Indic_Syllabic_Category=Consonant
|
||||||
0800..0815 ; Consonant # Lo [22] SAMARITAN LETTER ALAF..SAMARITAN LETTER TAAF
|
0800..0815 ; Consonant # Lo [22] SAMARITAN LETTER ALAF..SAMARITAN LETTER TAAF
|
||||||
|
0840..0858 ; Consonant # Lo [25] MANDAIC LETTER HALQA..MANDAIC LETTER AIN
|
||||||
|
0F00..0F01 ; Consonant # Lo [2] TIBETAN SYLLABLE OM..TIBETAN MARK GTER YIG MGO TRUNCATED
|
||||||
|
0F04..0F06 ; Consonant # Po TIBETAN MARK INITIAL YIG MGO MDUN MA..TIBETAN MARK CARET YIG MGO PHUR SHAD MA
|
||||||
1800 ; Consonant # Po MONGOLIAN BIRGA # Reassigned so that legacy Birga + MFVS sequences still work
|
1800 ; Consonant # Po MONGOLIAN BIRGA # Reassigned so that legacy Birga + MFVS sequences still work
|
||||||
1807 ; Consonant # Po MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER
|
1807 ; Consonant # Po MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER
|
||||||
180A ; Consonant # Po MONGOLIAN NIRUGU
|
180A ; Consonant # Po MONGOLIAN NIRUGU
|
||||||
|
@ -94,11 +88,13 @@ AABD ; Vowel_Independent # Lo TAI VIET VOWEL AN
|
||||||
10E80..10EA9 ; Consonant # Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET
|
10E80..10EA9 ; Consonant # Lo [42] YEZIDI LETTER ELIF..YEZIDI LETTER ET
|
||||||
10EB0..10EB1 ; Consonant # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE
|
10EB0..10EB1 ; Consonant # Lo [2] YEZIDI LETTER LAM WITH DOT ABOVE..YEZIDI LETTER YOT WITH CIRCUMFLEX ABOVE
|
||||||
10F30..10F45 ; Consonant # Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN
|
10F30..10F45 ; Consonant # Lo [22] SOGDIAN LETTER ALEPH..SOGDIAN INDEPENDENT SHIN
|
||||||
|
10F70..10F81 ; Consonant # Lo [18] OLD UYGHUR LETTER ALEPH..OLD UYGHUR LETTER LESH
|
||||||
111DA ; Consonant # Lo SHARADA EKAM
|
111DA ; Consonant # Lo SHARADA EKAM
|
||||||
#HIEROGLYPHS to be moved to new category
|
#HIEROGLYPHS to be moved to new category
|
||||||
13000..1342E ; Consonant # Lo [1071] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH AA032
|
13000..1342F ; Consonant # Lo [1071] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH V011D
|
||||||
#For the Begin and End segment to be handled fully correctly, the cluster model needs to be modified.
|
#For the Begin and End segment to be handled fully correctly, the cluster model needs to be modified.
|
||||||
13437..13438 ; Consonant # Lo [2] EGYPTIAN HIEROGLYPH BEGIN SEGMENT..EGYPTIAN HIEROGLYPH END SEGMENT
|
13437..13438 ; Consonant # Lo [2] EGYPTIAN HIEROGLYPH BEGIN SEGMENT..EGYPTIAN HIEROGLYPH END SEGMENT
|
||||||
|
13441..13446 ; Consonant # Lo [6] EGYPTIAN HIEROGLYPH FULL BLANK..HIEROGLYPH WIDE LOST SIGN
|
||||||
16B00..16B2F ; Consonant # Lo [48] PAHAWH HMONG VOWEL KEEB..PAHAWH HMONG CONSONANT CAU
|
16B00..16B2F ; Consonant # Lo [48] PAHAWH HMONG VOWEL KEEB..PAHAWH HMONG CONSONANT CAU
|
||||||
16F00..16F4A ; Consonant # Lo [75] MIAO LETTER PA..MIAO LETTER RTE
|
16F00..16F4A ; Consonant # Lo [75] MIAO LETTER PA..MIAO LETTER RTE
|
||||||
16FE4 ; Consonant # Mn KHITAN SMALL SCRIPT FILLER # Avoids Mn pushing this into VOWEL class
|
16FE4 ; Consonant # Mn KHITAN SMALL SCRIPT FILLER # Avoids Mn pushing this into VOWEL class
|
||||||
|
@ -113,6 +109,8 @@ AABD ; Vowel_Independent # Lo TAI VIET VOWEL AN
|
||||||
1E14F ; Consonant # So NYIAKENG PUACHUE HMONG CIRCLED CA
|
1E14F ; Consonant # So NYIAKENG PUACHUE HMONG CIRCLED CA
|
||||||
1E290..1E2AD ; Consonant # Lo [30] TOTO LETTER PA..TOTO LETTER A
|
1E290..1E2AD ; Consonant # Lo [30] TOTO LETTER PA..TOTO LETTER A
|
||||||
1E2C0..1E2EB ; Consonant # Lo [44] WANCHO LETTER AA..WANCHO LETTER YIH
|
1E2C0..1E2EB ; Consonant # Lo [44] WANCHO LETTER AA..WANCHO LETTER YIH
|
||||||
|
1E4D0..1E4EA ; Consonant # Lo [27] NAG MUNDARI LETTER O..NAG MUNDARI LETTER ELL
|
||||||
|
1E4EB ; Consonant # Lm NAG MUNDARI SIGN OJOD
|
||||||
1E900..1E921 ; Consonant # Lu [34] ADLAM CAPITAL LETTER ALIF..ADLAM CAPITAL LETTER SHA
|
1E900..1E921 ; Consonant # Lu [34] ADLAM CAPITAL LETTER ALIF..ADLAM CAPITAL LETTER SHA
|
||||||
1E922..1E943 ; Consonant # Ll [34] ADLAM SMALL LETTER ALIF..ADLAM SMALL LETTER SHA
|
1E922..1E943 ; Consonant # Ll [34] ADLAM SMALL LETTER ALIF..ADLAM SMALL LETTER SHA
|
||||||
1E94B ; Consonant # Lm ADLAM NASALIZATION MARK
|
1E94B ; Consonant # Lm ADLAM NASALIZATION MARK
|
||||||
|
@ -140,7 +138,6 @@ FE00..FE0F ; Modifying_Letter # Mn [16] VARIATION SELECTOR-1..VARIATION SEL
|
||||||
0F39 ; Nukta # Mn TIBETAN MARK TSA -PHRU # NOW IN UNICODE 10.0
|
0F39 ; Nukta # Mn TIBETAN MARK TSA -PHRU # NOW IN UNICODE 10.0
|
||||||
1885..1886 ; Nukta # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA
|
1885..1886 ; Nukta # Mn [2] MONGOLIAN LETTER ALI GALI BALUDA..MONGOLIAN LETTER ALI GALI THREE BALUDA
|
||||||
18A9 ; Nukta # Mn MONGOLIAN LETTER ALI GALI DAGALGA
|
18A9 ; Nukta # Mn MONGOLIAN LETTER ALI GALI DAGALGA
|
||||||
1B6B..1B73 ; Nukta # Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG
|
|
||||||
10AE5..10AE6 ; Nukta # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW
|
10AE5..10AE6 ; Nukta # Mn [2] MANICHAEAN ABBREVIATION MARK ABOVE..MANICHAEAN ABBREVIATION MARK BELOW
|
||||||
16F4F ; Nukta # Mn MIAO SIGN CONSONANT MODIFIER BAR
|
16F4F ; Nukta # Mn MIAO SIGN CONSONANT MODIFIER BAR
|
||||||
1BC9D..1BC9E ; Nukta # Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK
|
1BC9D..1BC9E ; Nukta # Mn [2] DUPLOYAN THICK LETTER SELECTOR..DUPLOYAN DOUBLE MARK
|
||||||
|
@ -155,6 +152,7 @@ FE00..FE0F ; Modifying_Letter # Mn [16] VARIATION SELECTOR-1..VARIATION SEL
|
||||||
16AC0..16AC9 ; Number # Nd [10] TANGSA DIGIT ZERO..TANGSA DIGIT NINE
|
16AC0..16AC9 ; Number # Nd [10] TANGSA DIGIT ZERO..TANGSA DIGIT NINE
|
||||||
1E140..1E149 ; Number # Nd [10] NYIAKENG PUACHUE HMONG DIGIT ZERO..NYIAKENG PUACHUE HMONG DIGIT NINE
|
1E140..1E149 ; Number # Nd [10] NYIAKENG PUACHUE HMONG DIGIT ZERO..NYIAKENG PUACHUE HMONG DIGIT NINE
|
||||||
1E2F0..1E2F9 ; Number # Nd [10] WANCHO DIGIT ZERO..WANCHO DIGIT NINE
|
1E2F0..1E2F9 ; Number # Nd [10] WANCHO DIGIT ZERO..WANCHO DIGIT NINE
|
||||||
|
1E4F0..1E4F9 ; Number # Nd [10] NAG MUNDARI DIGIT ZERO..NAG MUNDARI DIGIT NINE
|
||||||
1E950..1E959 ; Number # Nd [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE
|
1E950..1E959 ; Number # Nd [10] ADLAM DIGIT ZERO..ADLAM DIGIT NINE
|
||||||
|
|
||||||
# ================================================
|
# ================================================
|
||||||
|
@ -176,7 +174,9 @@ FE00..FE0F ; Modifying_Letter # Mn [16] VARIATION SELECTOR-1..VARIATION SEL
|
||||||
|
|
||||||
# Indic_Syllabic_Category=Virama
|
# Indic_Syllabic_Category=Virama
|
||||||
2D7F ; Virama # Mn TIFINAGH CONSONANT JOINER
|
2D7F ; Virama # Mn TIFINAGH CONSONANT JOINER
|
||||||
|
#HIEROGLYPHS to be moved to new category
|
||||||
13430..13436 ; Virama # Cf [7] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH OVERLAY MIDDLE
|
13430..13436 ; Virama # Cf [7] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH OVERLAY MIDDLE
|
||||||
|
13439..1343B ; Virama # Cf [3] EGYPTIAN HIEROGLYPH INSERT AT MIDDLE..EGYPTIAN HIEROGLYPH INSERT AT BOTTOM
|
||||||
|
|
||||||
# ================================================
|
# ================================================
|
||||||
|
|
||||||
|
@ -191,6 +191,21 @@ AABD ; Vowel_Independent # Lo TAI VIET VOWEL AN
|
||||||
0B55 ; Vowel_Dependent # Mn ORIYA SIGN OVERLINE
|
0B55 ; Vowel_Dependent # Mn ORIYA SIGN OVERLINE
|
||||||
10EAB..10EAC ; Vowel_Dependent # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK
|
10EAB..10EAC ; Vowel_Dependent # Mn [2] YEZIDI COMBINING HAMZA MARK..YEZIDI COMBINING MADDA MARK
|
||||||
16F51..16F87 ; Vowel_Dependent # Mc [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI
|
16F51..16F87 ; Vowel_Dependent # Mc [55] MIAO SIGN ASPIRATION..MIAO VOWEL SIGN UI
|
||||||
|
1E4EC..1E4EF ; Vowel_Dependent # Mn [4] NAG MUNDARI SIGN MUHOR..NAG MUNDARI SIGN SUTUH
|
||||||
|
|
||||||
|
# ================================================
|
||||||
|
|
||||||
|
# Indic_Syllabic_Category=Cantillation_Mark
|
||||||
|
|
||||||
|
1CF8..1CF9 ; Cantillation_Mark # Mn [2] VEDIC TONE RING ABOVE..VEDIC TONE DOUBLE RING ABOVE
|
||||||
|
#HIEROGLYPHS to be moved to new category
|
||||||
|
13440 ; Cantillation_Mark # Mn EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY
|
||||||
|
13447..13455 ; Cantillation_Mark # Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED
|
||||||
|
|
||||||
|
# ================================================
|
||||||
|
|
||||||
|
# Indic_Syllabic_Category=Symbol_Modifier
|
||||||
|
1B6B..1B73 ; Symbol_Modifier # Mn [9] BALINESE MUSICAL SYMBOL COMBINING TEGEH..BALINESE MUSICAL SYMBOL COMBINING GONG
|
||||||
|
|
||||||
# ================================================
|
# ================================================
|
||||||
# ================================================
|
# ================================================
|
||||||
|
@ -198,24 +213,56 @@ AABD ; Vowel_Independent # Lo TAI VIET VOWEL AN
|
||||||
# ================================================
|
# ================================================
|
||||||
# ================================================
|
# ================================================
|
||||||
|
|
||||||
# USE_Syllabic_Category=Hieroglyph
|
# USE, Extended_Syllabic_Category=Hieroglyph
|
||||||
# 13000..1342E ; Hieroglyph # Lo [1071] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH AA032
|
# 13000..1342F ; Hieroglyph # Lo [1072] EGYPTIAN HIEROGLYPH A001..EGYPTIAN HIEROGLYPH V011D
|
||||||
|
# 13441..13446 ; Hieroglyph # Lo [6] EGYPTIAN HIEROGLYPH FULL BLANK..HIEROGLYPH WIDE LOST SIGN
|
||||||
|
|
||||||
# ================================================
|
# ================================================
|
||||||
|
|
||||||
# USE_Syllabic_Category=Hieroglyph_Joiner
|
# USE, Extended_Syllabic_Category=Hieroglyph_Joiner
|
||||||
# 13430..13436 ; Hieroglyph_Joiner # Cf EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH OVERLAY MIDDLE
|
# 13430..13436 ; Hieroglyph_Joiner # Cf [7] EGYPTIAN HIEROGLYPH VERTICAL JOINER..EGYPTIAN HIEROGLYPH OVERLAY MIDDLE
|
||||||
|
# 13439..1343B ; Hieroglyph_Joiner # Cf [3] EGYPTIAN HIEROGLYPH INSERT AT MIDDLE..EGYPTIAN HIEROGLYPH INSERT AT BOTTOM
|
||||||
|
|
||||||
# ================================================
|
# ================================================
|
||||||
|
|
||||||
# USE_Syllabic_Category= Hieroglyph_Segment_Begin
|
# USE, Extended_Syllabic_Category=Hieroglyph_Mark_Begin
|
||||||
|
# 005B ; Hieroglyph_Mark_Begin # Ps LEFT SQUARE BRACKET
|
||||||
|
# 007B ; Hieroglyph_Mark_Begin # Ps LEFT CURLY BRACKET
|
||||||
|
# 27E6 ; Hieroglyph_Mark_Begin # Ps MATHEMATICAL LEFT WHITE SQUARE BRACKET
|
||||||
|
# 27E8 ; Hieroglyph_Mark_Begin # Ps MATHEMATICAL LEFT ANGLE BRACKET
|
||||||
|
# 2E22 ; Hieroglyph_Mark_Begin # Ps TOP LEFT HALF BRACKET
|
||||||
|
# 2E24 ; Hieroglyph_Mark_Begin # Ps BOTTOM LEFT HALF BRACKET
|
||||||
|
|
||||||
|
# ================================================
|
||||||
|
|
||||||
|
# USE, Extended_Syllabic_Category=Hieroglyph_Mark_End
|
||||||
|
# 005D ; Hieroglyph_Mark_Begin # Pe RIGHT SQUARE BRACKET
|
||||||
|
# 007D ; Hieroglyph_Mark_Begin # Pe RIGHT CURLY BRACKET
|
||||||
|
# 27E7 ; Hieroglyph_Mark_Begin # Pe MATHEMATICAL RIGHT WHITE SQUARE BRACKET
|
||||||
|
# 27E9 ; Hieroglyph_Mark_Begin # Pe MATHEMATICAL RIGHT ANGLE BRACKET
|
||||||
|
# 2E23 ; Hieroglyph_Mark_Begin # Pe TOP RIGHT HALF BRACKET
|
||||||
|
# 2E25 ; Hieroglyph_Mark_Begin # Pe BOTTOM RIGHT HALF BRACKET
|
||||||
|
|
||||||
|
# ================================================
|
||||||
|
|
||||||
|
# USE, Extended_Syllabic_Category=Hieroglyph_Segment_Begin
|
||||||
# 13437 ; Hieroglyph_Segment_Begin # Cf EGYPTIAN HIEROGLYPH BEGIN SEGMENT
|
# 13437 ; Hieroglyph_Segment_Begin # Cf EGYPTIAN HIEROGLYPH BEGIN SEGMENT
|
||||||
|
|
||||||
# ================================================
|
# ================================================
|
||||||
|
|
||||||
# USE_Syllabic_Category= Hieroglyph_Segment_End
|
# USE, Extended_Syllabic_Category=Hieroglyph_Segment_End
|
||||||
# 13438 ; Hieroglyph_Segment_End # Cf EGYPTIAN HIEROGLYPH END SEGMENT
|
# 13438 ; Hieroglyph_Segment_End # Cf EGYPTIAN HIEROGLYPH END SEGMENT
|
||||||
|
|
||||||
# ================================================
|
# ================================================
|
||||||
|
|
||||||
|
# USE, Extended_Syllabic_Category=Hieroglyph_Mirror
|
||||||
|
# 13440 ; Hieroglyph_Mirror # Mn EGYPTIAN HIEROGLYPH MIRROR HORIZONTALLY
|
||||||
|
|
||||||
|
# ================================================
|
||||||
|
|
||||||
|
# USE, Extended_Syllabic_Category=Hieroglyph_Modifier
|
||||||
|
# 13447..13455 ; Hieroglyph_Modifier # Mn [15] EGYPTIAN HIEROGLYPH MODIFIER DAMAGED AT TOP START..EGYPTIAN HIEROGLYPH MODIFIER DAMAGED
|
||||||
|
|
||||||
|
# ================================================
|
||||||
|
|
||||||
# eof
|
# eof
|
||||||
|
|
|
@ -222,6 +222,23 @@ main (int argc, char **argv)
|
||||||
hb::unique_ptr<hb_hashmap_t<int, int>> *v2;
|
hb::unique_ptr<hb_hashmap_t<int, int>> *v2;
|
||||||
m.has (0, &v2);
|
m.has (0, &v2);
|
||||||
}
|
}
|
||||||
|
/* Test hashmap with complex shared_ptrs as keys. */
|
||||||
|
{
|
||||||
|
hb_hashmap_t<hb::shared_ptr<hb_map_t>, unsigned> m;
|
||||||
|
|
||||||
|
hb_map_t *m1 = hb_map_create ();
|
||||||
|
hb_map_t *m2 = hb_map_create ();
|
||||||
|
m1->set (1,3);
|
||||||
|
m2->set (1,3);
|
||||||
|
|
||||||
|
hb::shared_ptr<hb_map_t> p1 {m1};
|
||||||
|
hb::shared_ptr<hb_map_t> p2 {m2};
|
||||||
|
m.set (p1,1);
|
||||||
|
|
||||||
|
assert (m.has (p2));
|
||||||
|
|
||||||
|
m1->set (2,4);
|
||||||
|
assert (!m.has (p2));
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ emoji-data.txt:
|
||||||
emoji-test.txt:
|
emoji-test.txt:
|
||||||
curl -O https://www.unicode.org/Public/emoji/latest/emoji-test.txt
|
curl -O https://www.unicode.org/Public/emoji/latest/emoji-test.txt
|
||||||
languagetags:
|
languagetags:
|
||||||
curl -O https://docs.microsoft.com/en-us/typography/opentype/spec/languagetags
|
curl -O https://learn.microsoft.com/en-us/typography/opentype/spec/languagetags
|
||||||
language-subtag-registry:
|
language-subtag-registry:
|
||||||
curl -O https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry
|
curl -O https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry
|
||||||
ucd.nounihan.grouped.zip:
|
ucd.nounihan.grouped.zip:
|
||||||
|
|
Binary file not shown.
|
@ -129,6 +129,8 @@
|
||||||
/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334;--font-funcs ot;U+0631,U+0628;[u0628.beh=1+1415|u0631.reh=0@-202,0+700]
|
/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334;--font-funcs ot;U+0631,U+0628;[u0628.beh=1+1415|u0631.reh=0@-202,0+700]
|
||||||
/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334;--font-funcs ot;U+0628,U+064F;[u064f.damma=0@250,-250+250|u0628.beh=0@-250,0+1165]
|
/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334;--font-funcs ot;U+0628,U+064F;[u064f.damma=0@250,-250+250|u0628.beh=0@-250,0+1165]
|
||||||
/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334;--font-funcs ot;U+0644,U+064E,U+0645,U+064E,U+0651,U+0627;[u0627.final.alef=5+647|u064e.fatha=0@-80,160+-80|u064e_u0651.shaddaFatha=0@490,250+490|u0644_u0645.initial.lamMeem=0@-410,0+415]
|
/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334;--font-funcs ot;U+0644,U+064E,U+0645,U+064E,U+0651,U+0627;[u0627.final.alef=5+647|u064e.fatha=0@-80,160+-80|u064e_u0651.shaddaFatha=0@490,250+490|u0644_u0645.initial.lamMeem=0@-410,0+415]
|
||||||
|
/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334;--font-funcs ot;U+0644,U+0627;[u0644_u0627.isolated.lamAlef=0+1162]
|
||||||
|
/System/Library/Fonts/GeezaPro.ttc@ab26ea45dcaa5e1c5a958e42af10e10d330e7334;--font-funcs ot --features rlig=0;U+0644,U+0627;[u0627.final.alef=1+647|u0644.initial.lam=0+515]
|
||||||
# SFNS uses opsz variation axis which isn't invoked here, see https;//crbug.com/1005969#c37
|
# SFNS uses opsz variation axis which isn't invoked here, see https;//crbug.com/1005969#c37
|
||||||
/System/Library/Fonts/SFNS.ttf@253b4b28662acc1de4a86350fd2b26d620ea213c;--font-funcs ot;U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064;[T=0+920|e=1+1049|space=2+420|A=3+1162|V=4+1292|space=5+420|T=6+960|r=7+631|space=8+420|V=9+1142|a=10+1028|space=11+420|r=12+461|T=13+1190|space=14+420|e=15+779|T=16+1190|space=17+420|T=18+920|d=19+1134]
|
/System/Library/Fonts/SFNS.ttf@253b4b28662acc1de4a86350fd2b26d620ea213c;--font-funcs ot;U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064;[T=0+920|e=1+1049|space=2+420|A=3+1162|V=4+1292|space=5+420|T=6+960|r=7+631|space=8+420|V=9+1142|a=10+1028|space=11+420|r=12+461|T=13+1190|space=14+420|e=15+779|T=16+1190|space=17+420|T=18+920|d=19+1134]
|
||||||
/System/Library/Fonts/SFNS.ttf@253b4b28662acc1de4a86350fd2b26d620ea213c;--font-ptem 9 --font-funcs ot;U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064;[T=0@19,0+958|e=1@19,0+1087|space=2@19,0+458|A=3@19,0+1200|V=4@19,0+1330|space=5@19,0+458|T=6@19,0+998|r=7@19,0+669|space=8@19,0+458|V=9@19,0+1180|a=10@19,0+1066|space=11@19,0+458|r=12@19,0+499|T=13@19,0+1228|space=14@19,0+458|e=15@19,0+817|T=16@19,0+1228|space=17@19,0+458|T=18@19,0+958|d=19@19,0+1172]
|
/System/Library/Fonts/SFNS.ttf@253b4b28662acc1de4a86350fd2b26d620ea213c;--font-ptem 9 --font-funcs ot;U+0054,U+0065,U+0020,U+0041,U+0056,U+0020,U+0054,U+0072,U+0020,U+0056,U+0061,U+0020,U+0072,U+0054,U+0020,U+0065,U+0054,U+0020,U+0054,U+0064;[T=0@19,0+958|e=1@19,0+1087|space=2@19,0+458|A=3@19,0+1200|V=4@19,0+1330|space=5@19,0+458|T=6@19,0+998|r=7@19,0+669|space=8@19,0+458|V=9@19,0+1180|a=10@19,0+1066|space=11@19,0+458|r=12@19,0+499|T=13@19,0+1228|space=14@19,0+458|e=15@19,0+817|T=16@19,0+1228|space=17@19,0+458|T=18@19,0+958|d=19@19,0+1172]
|
||||||
|
|
|
@ -39,7 +39,6 @@ EXTRA_DIST += \
|
||||||
expected/layout.gdef-attachlist \
|
expected/layout.gdef-attachlist \
|
||||||
expected/layout.notonastaliqurdu \
|
expected/layout.notonastaliqurdu \
|
||||||
expected/layout.tinos \
|
expected/layout.tinos \
|
||||||
expected/layout.default_features \
|
|
||||||
expected/layout.duplicate_features \
|
expected/layout.duplicate_features \
|
||||||
expected/layout.unsorted_featurelist \
|
expected/layout.unsorted_featurelist \
|
||||||
expected/layout.drop_feature \
|
expected/layout.drop_feature \
|
||||||
|
|
|
@ -38,7 +38,6 @@ TESTS = \
|
||||||
tests/layout.notonastaliqurdu.tests \
|
tests/layout.notonastaliqurdu.tests \
|
||||||
tests/layout.tests \
|
tests/layout.tests \
|
||||||
tests/layout.tinos.tests \
|
tests/layout.tinos.tests \
|
||||||
tests/layout.default_features.tests \
|
|
||||||
tests/layout.duplicate_features.tests \
|
tests/layout.duplicate_features.tests \
|
||||||
tests/layout.unsorted_featurelist.tests \
|
tests/layout.unsorted_featurelist.tests \
|
||||||
tests/layout.drop_feature.tests \
|
tests/layout.drop_feature.tests \
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,12 @@
|
||||||
|
FONTS:
|
||||||
|
MPLUS1-Variable.ttf
|
||||||
|
|
||||||
|
PROFILES:
|
||||||
|
default.txt
|
||||||
|
notdef-outline.txt
|
||||||
|
|
||||||
|
SUBSETS:
|
||||||
|
*
|
||||||
|
|
||||||
|
INSTANCES:
|
||||||
|
wght=400
|
|
@ -1,11 +0,0 @@
|
||||||
FONTS:
|
|
||||||
FranklinGothic-Regular.ttf
|
|
||||||
|
|
||||||
PROFILES:
|
|
||||||
layout-test.txt
|
|
||||||
default.txt
|
|
||||||
retain-gids.txt
|
|
||||||
|
|
||||||
SUBSETS:
|
|
||||||
achi
|
|
||||||
*
|
|
|
@ -28,15 +28,7 @@ def strip_check_sum (ttx_string):
|
||||||
|
|
||||||
|
|
||||||
def generate_expected_output(input_file, unicodes, profile_flags, instance_flags, output_directory, font_name):
|
def generate_expected_output(input_file, unicodes, profile_flags, instance_flags, output_directory, font_name):
|
||||||
fonttools_path = os.path.join(tempfile.mkdtemp (), font_name)
|
input_path = input_file
|
||||||
args = ["fonttools", "subset", input_file]
|
|
||||||
args.extend(["--drop-tables+=DSIG",
|
|
||||||
"--drop-tables-=sbix",
|
|
||||||
"--unicodes=%s" % unicodes,
|
|
||||||
"--output-file=%s" % fonttools_path])
|
|
||||||
args.extend(profile_flags)
|
|
||||||
check_call(args)
|
|
||||||
|
|
||||||
if instance_flags:
|
if instance_flags:
|
||||||
instance_path = os.path.join(tempfile.mkdtemp (), font_name)
|
instance_path = os.path.join(tempfile.mkdtemp (), font_name)
|
||||||
args = ["fonttools", "varLib.instancer",
|
args = ["fonttools", "varLib.instancer",
|
||||||
|
@ -44,10 +36,19 @@ def generate_expected_output(input_file, unicodes, profile_flags, instance_flags
|
||||||
"--no-recalc-bounds",
|
"--no-recalc-bounds",
|
||||||
"--no-recalc-timestamp",
|
"--no-recalc-timestamp",
|
||||||
"--output=%s" % instance_path,
|
"--output=%s" % instance_path,
|
||||||
fonttools_path]
|
input_file]
|
||||||
args.extend(instance_flags)
|
args.extend(instance_flags)
|
||||||
check_call(args)
|
check_call(args)
|
||||||
fonttools_path = instance_path
|
input_path = instance_path
|
||||||
|
|
||||||
|
fonttools_path = os.path.join(tempfile.mkdtemp (), font_name)
|
||||||
|
args = ["fonttools", "subset", input_path]
|
||||||
|
args.extend(["--drop-tables+=DSIG",
|
||||||
|
"--drop-tables-=sbix",
|
||||||
|
"--unicodes=%s" % unicodes,
|
||||||
|
"--output-file=%s" % fonttools_path])
|
||||||
|
args.extend(profile_flags)
|
||||||
|
check_call(args)
|
||||||
|
|
||||||
with io.StringIO () as fp:
|
with io.StringIO () as fp:
|
||||||
with TTFont (fonttools_path) as font:
|
with TTFont (fonttools_path) as font:
|
||||||
|
|
|
@ -33,7 +33,6 @@ tests = [
|
||||||
'layout.duplicate_features',
|
'layout.duplicate_features',
|
||||||
'layout.unsorted_featurelist',
|
'layout.unsorted_featurelist',
|
||||||
'layout.drop_feature',
|
'layout.drop_feature',
|
||||||
'layout.default_features',
|
|
||||||
'cmap',
|
'cmap',
|
||||||
'cmap14',
|
'cmap14',
|
||||||
'sbix',
|
'sbix',
|
||||||
|
@ -54,6 +53,7 @@ tests = [
|
||||||
# 'pin_all_at_default',
|
# 'pin_all_at_default',
|
||||||
# 'instantiate_glyf',
|
# 'instantiate_glyf',
|
||||||
# 'full_instance',
|
# 'full_instance',
|
||||||
|
# 'instance_feature_variations',
|
||||||
]
|
]
|
||||||
|
|
||||||
repack_tests = [
|
repack_tests = [
|
||||||
|
|
|
@ -52,6 +52,7 @@ def run_test (test, should_check_ots):
|
||||||
cli_args = ["--font-file=" + test.font_path,
|
cli_args = ["--font-file=" + test.font_path,
|
||||||
"--output-file=" + out_file,
|
"--output-file=" + out_file,
|
||||||
"--unicodes=%s" % test.unicodes (),
|
"--unicodes=%s" % test.unicodes (),
|
||||||
|
"--preprocess-face",
|
||||||
"--drop-tables+=DSIG",
|
"--drop-tables+=DSIG",
|
||||||
"--drop-tables-=sbix"]
|
"--drop-tables-=sbix"]
|
||||||
cli_args.extend (test.get_profile_flags ())
|
cli_args.extend (test.get_profile_flags ())
|
||||||
|
|
|
@ -32,6 +32,15 @@
|
||||||
|
|
||||||
#include <hb-subset.h>
|
#include <hb-subset.h>
|
||||||
|
|
||||||
|
static hb_face_t* preprocess_face(hb_face_t* face)
|
||||||
|
{
|
||||||
|
#ifdef HB_EXPERIMENTAL_API
|
||||||
|
return hb_subset_preprocess (face);
|
||||||
|
#else
|
||||||
|
return hb_face_reference(face);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Command line interface to the harfbuzz font subsetter.
|
* Command line interface to the harfbuzz font subsetter.
|
||||||
*/
|
*/
|
||||||
|
@ -103,6 +112,10 @@ struct subset_main_t : option_parser_t, face_options_t, output_options_t<false>
|
||||||
{
|
{
|
||||||
parse (argc, argv);
|
parse (argc, argv);
|
||||||
|
|
||||||
|
hb_face_t* orig_face = face;
|
||||||
|
if (preprocess)
|
||||||
|
orig_face = preprocess_face (face);
|
||||||
|
|
||||||
hb_face_t *new_face = nullptr;
|
hb_face_t *new_face = nullptr;
|
||||||
for (unsigned i = 0; i < num_iterations; i++)
|
for (unsigned i = 0; i < num_iterations; i++)
|
||||||
{
|
{
|
||||||
|
@ -119,6 +132,8 @@ struct subset_main_t : option_parser_t, face_options_t, output_options_t<false>
|
||||||
}
|
}
|
||||||
|
|
||||||
hb_face_destroy (new_face);
|
hb_face_destroy (new_face);
|
||||||
|
if (preprocess)
|
||||||
|
hb_face_destroy (orig_face);
|
||||||
|
|
||||||
return success ? 0 : 1;
|
return success ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
@ -160,6 +175,7 @@ struct subset_main_t : option_parser_t, face_options_t, output_options_t<false>
|
||||||
public:
|
public:
|
||||||
|
|
||||||
unsigned num_iterations = 1;
|
unsigned num_iterations = 1;
|
||||||
|
gboolean preprocess;
|
||||||
hb_subset_input_t *input = nullptr;
|
hb_subset_input_t *input = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -915,6 +931,8 @@ subset_main_t::add_options ()
|
||||||
{"no-prune-unicode-ranges", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES>, "Don't change the 'OS/2 ulUnicodeRange*' bits.", nullptr},
|
{"no-prune-unicode-ranges", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES>, "Don't change the 'OS/2 ulUnicodeRange*' bits.", nullptr},
|
||||||
{"glyph-names", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_GLYPH_NAMES>, "Keep PS glyph names in TT-flavored fonts. ", nullptr},
|
{"glyph-names", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_GLYPH_NAMES>, "Keep PS glyph names in TT-flavored fonts. ", nullptr},
|
||||||
{"passthrough-tables", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED>, "Do not drop tables that the tool does not know how to subset.", nullptr},
|
{"passthrough-tables", 0, G_OPTION_FLAG_NO_ARG, G_OPTION_ARG_CALLBACK, (gpointer) &set_flag<HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED>, "Do not drop tables that the tool does not know how to subset.", nullptr},
|
||||||
|
{"preprocess-face", 0, 0, G_OPTION_ARG_NONE, &this->preprocess,
|
||||||
|
"If set preprocesses the face with the add accelerator option before actually subsetting.", nullptr},
|
||||||
{nullptr}
|
{nullptr}
|
||||||
};
|
};
|
||||||
add_group (flag_entries,
|
add_group (flag_entries,
|
||||||
|
|
Loading…
Reference in New Issue