Update to Harfbuzz 9.0.0

This includes a compilation fix for Integrity which is also
stored as a patch file under harfbuzz-ng/patches.

[ChangeLog][Third-Party Code] Updated Harfbuzz to 9.0.0.

Pick-to: 6.7 6.7.3 6.5 6.2 5.15
Fixes: QTBUG-128763
Change-Id: I84156d38cf131e78e4f0d0d1716aa4e79a8c3a45
Reviewed-by: Tatiana Borisova <tatiana.borisova@qt.io>
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
(cherry picked from commit 0d83d8bbb15e3f481b1d8abed4cd29a08499c37f)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Eskil Abrahamsen Blomfeldt 2024-09-09 11:30:54 +02:00 committed by Qt Cherry-pick Bot
parent a0cf2c384d
commit 7e70f3293a
51 changed files with 2917 additions and 1682 deletions

View File

@ -30,6 +30,7 @@ qt_internal_add_3rdparty_library(BundledHarfbuzz
src/hb-fallback-shape.cc
src/hb-font.cc src/hb-font.h src/hb-font.hh
src/hb-ft-colr.hh
src/hb-geometry.hh
src/hb-limits.hh
src/hb-map.cc
src/hb-mutex.hh
@ -169,6 +170,7 @@ qt_internal_extend_target(BundledHarfbuzz CONDITION TRUE
src/hb-ot-var-fvar-table.hh
src/hb-ot-var-hvar-table.hh
src/hb-ot-var-mvar-table.hh
src/hb-ot-var-varc-table.hh
src/OT/Color/CBDT/CBDT.hh
src/OT/Color/COLR/COLR.hh
src/OT/Color/COLR/colrv1-closure.hh
@ -177,6 +179,8 @@ qt_internal_extend_target(BundledHarfbuzz CONDITION TRUE
src/OT/Color/svg/svg.hh
src/OT/Layout/GDEF/GDEF.hh
src/OT/name/name.hh
src/OT/Var/VARC/coord-setter.hh
src/OT/Var/VARC/VARC.cc src/OT/Var/VARC/VARC.hh
DEFINES
HAVE_OT
)

View File

@ -0,0 +1,34 @@
From c3c113a4ec9b0c41cf096fe832e6420eac29122e Mon Sep 17 00:00:00 2001
From: Tatiana Borisova <tatiana.borisova@qt.io>
Date: Wed, 11 Sep 2024 11:16:07 +0200
Subject: [PATCH] Harfbuzz: Fix Integrity compilation error
Add Condition pre-declaration before _hb_recurse_condition_evaluate
The patch is fixing the following compilation error:
"/home/qt/work/qt/qtbase/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh", line 3805: error #1201:
typedef "Condition" may not be used in an elaborated type specifier
_hb_recurse_condition_evaluate (const struct Condition &condition.
Follows-up bec7f5ffe0bbe75d4bc2128cfa52f17f821a0820
Change-Id: I5bc87b34169799ff25d6dd513436b71827e52a0d
---
src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh
index 66274534b0..1f38923c61 100644
--- a/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh
+++ b/src/3rdparty/harfbuzz-ng/src/hb-ot-layout-common.hh
@@ -3799,6 +3799,7 @@ enum Cond_with_Var_flag_t
DROP_RECORD_WITH_VAR = 3,
};
+struct Condition;
template <typename Instancer>
static bool
--
2.40.0.windows.1

View File

@ -7,8 +7,8 @@
"Description": "HarfBuzz is an OpenType text shaping engine.",
"Homepage": "http://harfbuzz.org",
"Version": "8.5.0",
"DownloadLocation": "https://github.com/harfbuzz/harfbuzz/releases/tag/8.5.0",
"Version": "9.0.0",
"DownloadLocation": "https://github.com/harfbuzz/harfbuzz/releases/tag/9.0.0",
"License": "MIT License",
"LicenseId": "MIT",

View File

@ -72,7 +72,7 @@ public:
hb_map_t current_glyphs;
hb_map_t current_layers;
int depth_left = HB_MAX_NESTING_LEVEL;
int edge_count = HB_COLRV1_MAX_EDGE_COUNT;
int edge_count = HB_MAX_GRAPH_EDGE_COUNT;
hb_paint_context_t (const void *base_,
hb_paint_funcs_t *funcs_,
@ -2579,10 +2579,6 @@ struct COLR
{
// COLRv1 glyph
ItemVarStoreInstancer instancer (&(this+varStore),
&(this+varIdxMap),
hb_array (font->coords, font->num_coords));
bool is_bounded = true;
if (clip)
{

View File

@ -0,0 +1,346 @@
#include "VARC.hh"
#ifndef HB_NO_VAR_COMPOSITES
#include "../../../hb-draw.hh"
#include "../../../hb-geometry.hh"
#include "../../../hb-ot-layout-common.hh"
#include "../../../hb-ot-layout-gdef-table.hh"
namespace OT {
//namespace Var {
struct hb_transforming_pen_context_t
{
hb_transform_t transform;
hb_draw_funcs_t *dfuncs;
void *data;
hb_draw_state_t *st;
};
static void
hb_transforming_pen_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
void *data,
hb_draw_state_t *st,
float to_x, float to_y,
void *user_data HB_UNUSED)
{
hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;
c->transform.transform_point (to_x, to_y);
c->dfuncs->move_to (c->data, *c->st, to_x, to_y);
}
static void
hb_transforming_pen_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
void *data,
hb_draw_state_t *st,
float to_x, float to_y,
void *user_data HB_UNUSED)
{
hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;
c->transform.transform_point (to_x, to_y);
c->dfuncs->line_to (c->data, *c->st, to_x, to_y);
}
static void
hb_transforming_pen_quadratic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
void *data,
hb_draw_state_t *st,
float control_x, float control_y,
float to_x, float to_y,
void *user_data HB_UNUSED)
{
hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;
c->transform.transform_point (control_x, control_y);
c->transform.transform_point (to_x, to_y);
c->dfuncs->quadratic_to (c->data, *c->st, control_x, control_y, to_x, to_y);
}
static void
hb_transforming_pen_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
void *data,
hb_draw_state_t *st,
float control1_x, float control1_y,
float control2_x, float control2_y,
float to_x, float to_y,
void *user_data HB_UNUSED)
{
hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;
c->transform.transform_point (control1_x, control1_y);
c->transform.transform_point (control2_x, control2_y);
c->transform.transform_point (to_x, to_y);
c->dfuncs->cubic_to (c->data, *c->st, control1_x, control1_y, control2_x, control2_y, to_x, to_y);
}
static void
hb_transforming_pen_close_path (hb_draw_funcs_t *dfuncs HB_UNUSED,
void *data,
hb_draw_state_t *st,
void *user_data HB_UNUSED)
{
hb_transforming_pen_context_t *c = (hb_transforming_pen_context_t *) data;
c->dfuncs->close_path (c->data, *c->st);
}
static inline void free_static_transforming_pen_funcs ();
static struct hb_transforming_pen_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t<hb_transforming_pen_funcs_lazy_loader_t>
{
static hb_draw_funcs_t *create ()
{
hb_draw_funcs_t *funcs = hb_draw_funcs_create ();
hb_draw_funcs_set_move_to_func (funcs, hb_transforming_pen_move_to, nullptr, nullptr);
hb_draw_funcs_set_line_to_func (funcs, hb_transforming_pen_line_to, nullptr, nullptr);
hb_draw_funcs_set_quadratic_to_func (funcs, hb_transforming_pen_quadratic_to, nullptr, nullptr);
hb_draw_funcs_set_cubic_to_func (funcs, hb_transforming_pen_cubic_to, nullptr, nullptr);
hb_draw_funcs_set_close_path_func (funcs, hb_transforming_pen_close_path, nullptr, nullptr);
hb_draw_funcs_make_immutable (funcs);
hb_atexit (free_static_transforming_pen_funcs);
return funcs;
}
} static_transforming_pen_funcs;
static inline
void free_static_transforming_pen_funcs ()
{
static_transforming_pen_funcs.free_instance ();
}
static hb_draw_funcs_t *
hb_transforming_pen_get_funcs ()
{
return static_transforming_pen_funcs.get_unconst ();
}
hb_ubytes_t
VarComponent::get_path_at (hb_font_t *font,
hb_codepoint_t parent_gid,
hb_draw_session_t &draw_session,
hb_array_t<const int> coords,
hb_ubytes_t total_record,
hb_set_t *visited,
signed *edges_left,
signed depth_left,
VarRegionList::cache_t *cache) const
{
const unsigned char *end = total_record.arrayZ + total_record.length;
const unsigned char *record = total_record.arrayZ;
auto &VARC = *font->face->table.VARC;
auto &varStore = &VARC+VARC.varStore;
auto instancer = MultiItemVarStoreInstancer(&varStore, nullptr, coords, cache);
#define READ_UINT32VAR(name) \
HB_STMT_START { \
if (unlikely (unsigned (end - record) < HBUINT32VAR::min_size)) return hb_ubytes_t (); \
hb_barrier (); \
auto &varint = * (const HBUINT32VAR *) record; \
unsigned size = varint.get_size (); \
if (unlikely (unsigned (end - record) < size)) return hb_ubytes_t (); \
name = (uint32_t) varint; \
record += size; \
} HB_STMT_END
uint32_t flags;
READ_UINT32VAR (flags);
// gid
hb_codepoint_t gid = 0;
if (flags & (unsigned) flags_t::GID_IS_24BIT)
{
if (unlikely (unsigned (end - record) < HBGlyphID24::static_size))
return hb_ubytes_t ();
hb_barrier ();
gid = * (const HBGlyphID24 *) record;
record += HBGlyphID24::static_size;
}
else
{
if (unlikely (unsigned (end - record) < HBGlyphID16::static_size))
return hb_ubytes_t ();
hb_barrier ();
gid = * (const HBGlyphID16 *) record;
record += HBGlyphID16::static_size;
}
// Condition
bool show = true;
if (flags & (unsigned) flags_t::HAVE_CONDITION)
{
unsigned conditionIndex;
READ_UINT32VAR (conditionIndex);
const auto &condition = (&VARC+VARC.conditionList)[conditionIndex];
show = condition.evaluate (coords.arrayZ, coords.length, &instancer);
}
// Axis values
hb_vector_t<unsigned> axisIndices;
hb_vector_t<float> axisValues;
if (flags & (unsigned) flags_t::HAVE_AXES)
{
unsigned axisIndicesIndex;
READ_UINT32VAR (axisIndicesIndex);
axisIndices = (&VARC+VARC.axisIndicesList)[axisIndicesIndex];
axisValues.resize (axisIndices.length);
const HBUINT8 *p = (const HBUINT8 *) record;
TupleValues::decompile (p, axisValues, (const HBUINT8 *) end);
record += (const unsigned char *) p - record;
}
// Apply variations if any
if (flags & (unsigned) flags_t::AXIS_VALUES_HAVE_VARIATION)
{
uint32_t axisValuesVarIdx;
READ_UINT32VAR (axisValuesVarIdx);
if (show && coords && !axisValues.in_error ())
varStore.get_delta (axisValuesVarIdx, coords, axisValues.as_array (), cache);
}
auto component_coords = coords;
/* Copying coords is expensive; so we have put an arbitrary
* limit on the max number of coords for now. */
if ((flags & (unsigned) flags_t::RESET_UNSPECIFIED_AXES) ||
coords.length > HB_VAR_COMPOSITE_MAX_AXES)
component_coords = hb_array<int> (font->coords, font->num_coords);
// Transform
uint32_t transformVarIdx = VarIdx::NO_VARIATION;
if (flags & (unsigned) flags_t::TRANSFORM_HAS_VARIATION)
READ_UINT32VAR (transformVarIdx);
#define PROCESS_TRANSFORM_COMPONENTS \
HB_STMT_START { \
PROCESS_TRANSFORM_COMPONENT (FWORD, HAVE_TRANSLATE_X, translateX); \
PROCESS_TRANSFORM_COMPONENT (FWORD, HAVE_TRANSLATE_Y, translateY); \
PROCESS_TRANSFORM_COMPONENT (F4DOT12, HAVE_ROTATION, rotation); \
PROCESS_TRANSFORM_COMPONENT (F6DOT10, HAVE_SCALE_X, scaleX); \
PROCESS_TRANSFORM_COMPONENT (F6DOT10, HAVE_SCALE_Y, scaleY); \
PROCESS_TRANSFORM_COMPONENT (F4DOT12, HAVE_SKEW_X, skewX); \
PROCESS_TRANSFORM_COMPONENT (F4DOT12, HAVE_SKEW_Y, skewY); \
PROCESS_TRANSFORM_COMPONENT (FWORD, HAVE_TCENTER_X, tCenterX); \
PROCESS_TRANSFORM_COMPONENT (FWORD, HAVE_TCENTER_Y, tCenterY); \
} HB_STMT_END
hb_transform_decomposed_t transform;
// Read transform components
#define PROCESS_TRANSFORM_COMPONENT(type, flag, name) \
if (flags & (unsigned) flags_t::flag) \
{ \
static_assert (type::static_size == HBINT16::static_size, ""); \
if (unlikely (unsigned (end - record) < HBINT16::static_size)) \
return hb_ubytes_t (); \
hb_barrier (); \
transform.name = * (const HBINT16 *) record; \
record += HBINT16::static_size; \
}
PROCESS_TRANSFORM_COMPONENTS;
#undef PROCESS_TRANSFORM_COMPONENT
// Read reserved records
unsigned i = flags & (unsigned) flags_t::RESERVED_MASK;
while (i)
{
HB_UNUSED uint32_t discard;
READ_UINT32VAR (discard);
i &= i - 1;
}
/* Parsing is over now. */
if (show)
{
// Only use coord_setter if there's actually any axis overrides.
coord_setter_t coord_setter (axisIndices ? component_coords : hb_array<int> ());
// Go backwards, to reduce coord_setter vector reallocations.
for (unsigned i = axisIndices.length; i; i--)
coord_setter[axisIndices[i - 1]] = axisValues[i - 1];
if (axisIndices)
component_coords = coord_setter.get_coords ();
// Apply transform variations if any
if (transformVarIdx != VarIdx::NO_VARIATION && coords)
{
float transformValues[9];
unsigned numTransformValues = 0;
#define PROCESS_TRANSFORM_COMPONENT(type, flag, name) \
if (flags & (unsigned) flags_t::flag) \
transformValues[numTransformValues++] = transform.name;
PROCESS_TRANSFORM_COMPONENTS;
#undef PROCESS_TRANSFORM_COMPONENT
varStore.get_delta (transformVarIdx, coords, hb_array (transformValues, numTransformValues), cache);
numTransformValues = 0;
#define PROCESS_TRANSFORM_COMPONENT(type, flag, name) \
if (flags & (unsigned) flags_t::flag) \
transform.name = transformValues[numTransformValues++];
PROCESS_TRANSFORM_COMPONENTS;
#undef PROCESS_TRANSFORM_COMPONENT
}
// Divide them by their divisors
#define PROCESS_TRANSFORM_COMPONENT(type, flag, name) \
if (flags & (unsigned) flags_t::flag) \
{ \
HBINT16 int_v; \
int_v = roundf (transform.name); \
type typed_v = * (const type *) &int_v; \
float float_v = (float) typed_v; \
transform.name = float_v; \
}
PROCESS_TRANSFORM_COMPONENTS;
#undef PROCESS_TRANSFORM_COMPONENT
if (!(flags & (unsigned) flags_t::HAVE_SCALE_Y))
transform.scaleY = transform.scaleX;
// Scale the transform by the font's scale
float x_scale = font->x_multf;
float y_scale = font->y_multf;
transform.translateX *= x_scale;
transform.translateY *= y_scale;
transform.tCenterX *= x_scale;
transform.tCenterY *= y_scale;
// Build a transforming pen to apply the transform.
hb_draw_funcs_t *transformer_funcs = hb_transforming_pen_get_funcs ();
hb_transforming_pen_context_t context {transform.to_transform (),
draw_session.funcs,
draw_session.draw_data,
&draw_session.st};
hb_draw_session_t transformer_session {transformer_funcs, &context};
VARC.get_path_at (font, gid,
transformer_session, component_coords,
parent_gid,
visited, edges_left, depth_left - 1);
}
#undef PROCESS_TRANSFORM_COMPONENTS
#undef READ_UINT32VAR
return hb_ubytes_t (record, end - record);
}
//} // namespace Var
} // namespace OT
#endif

View File

@ -0,0 +1,193 @@
#ifndef OT_VAR_VARC_VARC_HH
#define OT_VAR_VARC_VARC_HH
#include "../../../hb-ot-layout-common.hh"
#include "../../../hb-ot-glyf-table.hh"
#include "../../../hb-ot-cff2-table.hh"
#include "../../../hb-ot-cff1-table.hh"
#include "coord-setter.hh"
namespace OT {
//namespace Var {
/*
* VARC -- Variable Composites
* https://github.com/harfbuzz/boring-expansion-spec/blob/main/VARC.md
*/
#ifndef HB_NO_VAR_COMPOSITES
struct VarComponent
{
enum class flags_t : uint32_t
{
RESET_UNSPECIFIED_AXES = 1u << 0,
HAVE_AXES = 1u << 1,
AXIS_VALUES_HAVE_VARIATION = 1u << 2,
TRANSFORM_HAS_VARIATION = 1u << 3,
HAVE_TRANSLATE_X = 1u << 4,
HAVE_TRANSLATE_Y = 1u << 5,
HAVE_ROTATION = 1u << 6,
HAVE_CONDITION = 1u << 7,
HAVE_SCALE_X = 1u << 8,
HAVE_SCALE_Y = 1u << 9,
HAVE_TCENTER_X = 1u << 10,
HAVE_TCENTER_Y = 1u << 11,
GID_IS_24BIT = 1u << 12,
HAVE_SKEW_X = 1u << 13,
HAVE_SKEW_Y = 1u << 14,
RESERVED_MASK = ~((1u << 15) - 1),
};
HB_INTERNAL hb_ubytes_t
get_path_at (hb_font_t *font,
hb_codepoint_t parent_gid,
hb_draw_session_t &draw_session,
hb_array_t<const int> coords,
hb_ubytes_t record,
hb_set_t *visited,
signed *edges_left,
signed depth_left,
VarRegionList::cache_t *cache = nullptr) const;
};
struct VarCompositeGlyph
{
static void
get_path_at (hb_font_t *font,
hb_codepoint_t glyph,
hb_draw_session_t &draw_session,
hb_array_t<const int> coords,
hb_ubytes_t record,
hb_set_t *visited,
signed *edges_left,
signed depth_left,
VarRegionList::cache_t *cache = nullptr)
{
while (record)
{
const VarComponent &comp = * (const VarComponent *) (record.arrayZ);
record = comp.get_path_at (font, glyph,
draw_session, coords,
record,
visited, edges_left, depth_left, cache);
}
}
};
HB_MARK_AS_FLAG_T (VarComponent::flags_t);
struct VARC
{
friend struct VarComponent;
static constexpr hb_tag_t tableTag = HB_TAG ('V', 'A', 'R', 'C');
bool
get_path_at (hb_font_t *font,
hb_codepoint_t glyph,
hb_draw_session_t &draw_session,
hb_array_t<const int> coords,
hb_codepoint_t parent_glyph = HB_CODEPOINT_INVALID,
hb_set_t *visited = nullptr,
signed *edges_left = nullptr,
signed depth_left = HB_MAX_NESTING_LEVEL) const
{
hb_set_t stack_set;
if (visited == nullptr)
visited = &stack_set;
signed stack_edges = HB_MAX_GRAPH_EDGE_COUNT;
if (edges_left == nullptr)
edges_left = &stack_edges;
// Don't recurse on the same glyph.
unsigned idx = glyph == parent_glyph ?
NOT_COVERED :
(this+coverage).get_coverage (glyph);
if (idx == NOT_COVERED)
{
if (!font->face->table.glyf->get_path_at (font, glyph, draw_session, coords))
#ifndef HB_NO_CFF
if (!font->face->table.cff2->get_path_at (font, glyph, draw_session, coords))
if (!font->face->table.cff1->get_path (font, glyph, draw_session)) // Doesn't have variations
#endif
return false;
return true;
}
if (depth_left <= 0)
return true;
if (*edges_left <= 0)
return true;
(*edges_left)--;
if (visited->has (glyph) || visited->in_error ())
return true;
visited->add (glyph);
hb_ubytes_t record = (this+glyphRecords)[idx];
VarRegionList::cache_t *cache = record.length >= 64 ? // Heuristic
(this+varStore).create_cache ()
: nullptr;
VarCompositeGlyph::get_path_at (font, glyph,
draw_session, coords,
record,
visited, edges_left, depth_left,
cache);
(this+varStore).destroy_cache (cache);
visited->del (glyph);
return true;
}
bool
get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const
{ return get_path_at (font, gid, draw_session, hb_array (font->coords, font->num_coords)); }
bool paint_glyph (hb_font_t *font, hb_codepoint_t gid, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const
{
funcs->push_clip_glyph (data, gid, font);
funcs->color (data, true, foreground);
funcs->pop_clip (data);
return true;
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (version.sanitize (c) &&
hb_barrier () &&
version.major == 1 &&
coverage.sanitize (c, this) &&
varStore.sanitize (c, this) &&
conditionList.sanitize (c, this) &&
axisIndicesList.sanitize (c, this) &&
glyphRecords.sanitize (c, this));
}
protected:
FixedVersion<> version; /* Version identifier */
Offset32To<Coverage> coverage;
Offset32To<MultiItemVariationStore> varStore;
Offset32To<ConditionList> conditionList;
Offset32To<TupleList> axisIndicesList;
Offset32To<CFF2Index/*Of<VarCompositeGlyph>*/> glyphRecords;
public:
DEFINE_SIZE_STATIC (24);
};
#endif
//}
}
#endif /* OT_VAR_VARC_VARC_HH */

View File

@ -1,22 +1,22 @@
#ifndef OT_GLYF_COORD_SETTER_HH
#define OT_GLYF_COORD_SETTER_HH
#ifndef OT_VAR_VARC_COORD_SETTER_HH
#define OT_VAR_VARC_COORD_SETTER_HH
#include "../../hb.hh"
#include "../../../hb.hh"
namespace OT {
namespace glyf_impl {
//namespace Var {
struct coord_setter_t
{
coord_setter_t (hb_array_t<int> coords) :
coord_setter_t (hb_array_t<const int> coords) :
coords (coords) {}
int& operator [] (unsigned idx)
{
if (unlikely (idx >= HB_GLYF_VAR_COMPOSITE_MAX_AXES))
if (unlikely (idx >= HB_VAR_COMPOSITE_MAX_AXES))
return Crap(int);
if (coords.length < idx + 1)
coords.resize (idx + 1);
@ -30,7 +30,8 @@ struct coord_setter_t
};
} /* namespace glyf_impl */
} /* namespace OT */
//} // namespace Var
#endif /* OT_GLYF_COORD_SETTER_HH */
} // namespace OT
#endif /* OT_VAR_VARC_COORD_SETTER_HH */

View File

@ -7,8 +7,6 @@
#include "GlyphHeader.hh"
#include "SimpleGlyph.hh"
#include "CompositeGlyph.hh"
#include "VarCompositeGlyph.hh"
#include "coord-setter.hh"
namespace OT {
@ -33,9 +31,6 @@ struct Glyph
EMPTY,
SIMPLE,
COMPOSITE,
#ifndef HB_NO_VAR_COMPOSITES
VAR_COMPOSITE,
#endif
};
public:
@ -44,22 +39,10 @@ struct Glyph
if (type != COMPOSITE) return composite_iter_t ();
return CompositeGlyph (*header, bytes).iter ();
}
var_composite_iter_t get_var_composite_iterator () const
{
#ifndef HB_NO_VAR_COMPOSITES
if (type != VAR_COMPOSITE) return var_composite_iter_t ();
return VarCompositeGlyph (*header, bytes).iter ();
#else
return var_composite_iter_t ();
#endif
}
const hb_bytes_t trim_padding () const
{
switch (type) {
#ifndef HB_NO_VAR_COMPOSITES
case VAR_COMPOSITE: return VarCompositeGlyph (*header, bytes).trim_padding ();
#endif
case COMPOSITE: return CompositeGlyph (*header, bytes).trim_padding ();
case SIMPLE: return SimpleGlyph (*header, bytes).trim_padding ();
case EMPTY: return bytes;
@ -70,9 +53,6 @@ struct Glyph
void drop_hints ()
{
switch (type) {
#ifndef HB_NO_VAR_COMPOSITES
case VAR_COMPOSITE: return; // No hinting
#endif
case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints (); return;
case SIMPLE: SimpleGlyph (*header, bytes).drop_hints (); return;
case EMPTY: return;
@ -82,9 +62,6 @@ struct Glyph
void set_overlaps_flag ()
{
switch (type) {
#ifndef HB_NO_VAR_COMPOSITES
case VAR_COMPOSITE: return; // No overlaps flag
#endif
case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return;
case SIMPLE: SimpleGlyph (*header, bytes).set_overlaps_flag (); return;
case EMPTY: return;
@ -94,9 +71,6 @@ struct Glyph
void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
{
switch (type) {
#ifndef HB_NO_VAR_COMPOSITES
case VAR_COMPOSITE: return; // No hinting
#endif
case COMPOSITE: CompositeGlyph (*header, bytes).drop_hints_bytes (dest_start); return;
case SIMPLE: SimpleGlyph (*header, bytes).drop_hints_bytes (dest_start, dest_end); return;
case EMPTY: return;
@ -120,14 +94,6 @@ struct Glyph
if (unlikely (!item.get_points (points))) return false;
break;
}
#ifndef HB_NO_VAR_COMPOSITES
case VAR_COMPOSITE:
{
for (auto &item : get_var_composite_iterator ())
if (unlikely (!item.get_points (points))) return false;
break;
}
#endif
case EMPTY:
break;
}
@ -303,13 +269,6 @@ struct Glyph
{
switch (type)
{
#ifndef HB_NO_VAR_COMPOSITES
case VAR_COMPOSITE:
// TODO
dest_end = hb_bytes_t ();
break;
#endif
case COMPOSITE:
if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start,
points_with_deltas,
@ -352,7 +311,7 @@ struct Glyph
bool shift_points_hori = true,
bool use_my_metrics = true,
bool phantom_only = false,
hb_array_t<int> coords = hb_array_t<int> (),
hb_array_t<const int> coords = hb_array_t<const int> (),
hb_map_t *current_glyphs = nullptr,
unsigned int depth = 0,
unsigned *edge_count = nullptr) const
@ -360,7 +319,7 @@ struct Glyph
if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false;
unsigned stack_edge_count = 0;
if (!edge_count) edge_count = &stack_edge_count;
if (unlikely (*edge_count > HB_GLYF_MAX_EDGE_COUNT)) return false;
if (unlikely (*edge_count > HB_MAX_GRAPH_EDGE_COUNT)) return false;
(*edge_count)++;
hb_map_t current_glyphs_stack;
@ -394,14 +353,6 @@ struct Glyph
if (unlikely (!item.get_points (points))) return false;
break;
}
#ifndef HB_NO_VAR_COMPOSITES
case VAR_COMPOSITE:
{
for (auto &item : get_var_composite_iterator ())
if (unlikely (!item.get_points (points))) return false;
break;
}
#endif
case EMPTY:
break;
}
@ -542,81 +493,6 @@ struct Glyph
}
all_points.extend (phantoms);
} break;
#ifndef HB_NO_VAR_COMPOSITES
case VAR_COMPOSITE:
{
hb_array_t<contour_point_t> points_left = points.as_array ();
for (auto &item : get_var_composite_iterator ())
{
hb_codepoint_t item_gid = item.get_gid ();
if (unlikely (current_glyphs->has (item_gid)))
continue;
current_glyphs->add (item_gid);
unsigned item_num_points = item.get_num_points ();
hb_array_t<contour_point_t> record_points = points_left.sub_array (0, item_num_points);
assert (record_points.length == item_num_points);
auto component_coords = coords;
/* Copying coords is expensive; so we have put an arbitrary
* limit on the max number of coords for now. */
if (item.is_reset_unspecified_axes () ||
coords.length > HB_GLYF_VAR_COMPOSITE_MAX_AXES)
component_coords = hb_array<int> ();
coord_setter_t coord_setter (component_coords);
item.set_variations (coord_setter, record_points);
unsigned old_count = all_points.length;
if (unlikely ((!phantom_only || (use_my_metrics && item.is_use_my_metrics ())) &&
!glyf_accelerator.glyph_for_gid (item_gid)
.get_points (font,
glyf_accelerator,
all_points,
points_with_deltas,
head_maxp_info,
nullptr,
shift_points_hori,
use_my_metrics,
phantom_only,
coord_setter.get_coords (),
current_glyphs,
depth + 1,
edge_count)))
{
current_glyphs->del (item_gid);
return false;
}
auto comp_points = all_points.as_array ().sub_array (old_count);
/* Apply component transformation */
if (comp_points) // Empty in case of phantom_only
item.transform_points (record_points, comp_points);
/* 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];
all_points.resize (all_points.length - PHANTOM_COUNT);
if (all_points.length > HB_GLYF_MAX_POINTS)
{
current_glyphs->del (item_gid);
return false;
}
points_left += item_num_points;
current_glyphs->del (item_gid);
}
all_points.extend (phantoms);
} break;
#endif
case EMPTY:
all_points.extend (phantoms);
break;
@ -627,7 +503,7 @@ struct Glyph
/* Undocumented rasterizer behavior:
* Shift points horizontally by the updated left side bearing
*/
int v = -phantoms[PHANTOM_LEFT].x;
float v = -phantoms[PHANTOM_LEFT].x;
if (v)
for (auto &point : all_points)
point.x += v;
@ -661,10 +537,7 @@ struct Glyph
int num_contours = header->numberOfContours;
if (unlikely (num_contours == 0)) type = EMPTY;
else if (num_contours > 0) type = SIMPLE;
else if (num_contours == -1) type = COMPOSITE;
#ifndef HB_NO_VAR_COMPOSITES
else if (num_contours == -2) type = VAR_COMPOSITE;
#endif
else if (num_contours <= -1) type = COMPOSITE;
else type = EMPTY; // Spec deviation; Spec says COMPOSITE, but not seen in the wild.
}

View File

@ -53,23 +53,12 @@ struct SubsetGlyph
if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid))
const_cast<CompositeGlyphRecord &> (_).set_gid (new_gid);
}
#ifndef HB_NO_VAR_COMPOSITES
for (auto &_ : Glyph (dest_glyph).get_var_composite_iterator ())
{
hb_codepoint_t new_gid;
if (plan->new_gid_for_old_gid (_.get_gid(), &new_gid))
const_cast<VarCompositeGlyphRecord &> (_).set_gid (new_gid);
}
#endif
#ifndef HB_NO_BEYOND_64K
auto it = Glyph (dest_glyph).get_composite_iterator ();
if (it)
{
/* lower GID24 to GID16 in components if possible.
*
* TODO: VarComposite. Not as critical, since VarComposite supports
* gid24 from the first version. */
/* lower GID24 to GID16 in components if possible. */
char *p = it ? (char *) &*it : nullptr;
char *q = p;
const char *end = dest_glyph.arrayZ + dest_glyph.length;

View File

@ -1,401 +0,0 @@
#ifndef OT_GLYF_VARCOMPOSITEGLYPH_HH
#define OT_GLYF_VARCOMPOSITEGLYPH_HH
#include "../../hb-open-type.hh"
#include "coord-setter.hh"
namespace OT {
namespace glyf_impl {
struct VarCompositeGlyphRecord
{
protected:
enum var_composite_glyph_flag_t
{
USE_MY_METRICS = 0x0001,
AXIS_INDICES_ARE_SHORT = 0x0002,
UNIFORM_SCALE = 0x0004,
HAVE_TRANSLATE_X = 0x0008,
HAVE_TRANSLATE_Y = 0x0010,
HAVE_ROTATION = 0x0020,
HAVE_SCALE_X = 0x0040,
HAVE_SCALE_Y = 0x0080,
HAVE_SKEW_X = 0x0100,
HAVE_SKEW_Y = 0x0200,
HAVE_TCENTER_X = 0x0400,
HAVE_TCENTER_Y = 0x0800,
GID_IS_24BIT = 0x1000,
AXES_HAVE_VARIATION = 0x2000,
RESET_UNSPECIFIED_AXES = 0x4000,
};
public:
unsigned int get_size () const
{
unsigned fl = flags;
unsigned int size = min_size;
unsigned axis_width = (fl & AXIS_INDICES_ARE_SHORT) ? 4 : 3;
size += numAxes * axis_width;
if (fl & GID_IS_24BIT) size += 1;
// 2 bytes each for the following flags
fl = fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y |
HAVE_ROTATION |
HAVE_SCALE_X | HAVE_SCALE_Y |
HAVE_SKEW_X | HAVE_SKEW_Y |
HAVE_TCENTER_X | HAVE_TCENTER_Y);
size += hb_popcount (fl) * 2;
return size;
}
bool has_more () const { return true; }
bool is_use_my_metrics () const { return flags & USE_MY_METRICS; }
bool is_reset_unspecified_axes () const { return flags & RESET_UNSPECIFIED_AXES; }
hb_codepoint_t get_gid () const
{
if (flags & GID_IS_24BIT)
return * (const HBGlyphID24 *) &pad;
else
return * (const HBGlyphID16 *) &pad;
}
void set_gid (hb_codepoint_t gid)
{
if (flags & GID_IS_24BIT)
* (HBGlyphID24 *) &pad = gid;
else
* (HBGlyphID16 *) &pad = gid;
}
unsigned get_numAxes () const
{
return numAxes;
}
unsigned get_num_points () const
{
unsigned fl = flags;
unsigned num = 0;
if (fl & AXES_HAVE_VARIATION) num += numAxes;
/* Hopefully faster code, relying on the value of the flags. */
fl = (((fl & (HAVE_TRANSLATE_Y | HAVE_SCALE_Y | HAVE_SKEW_Y | HAVE_TCENTER_Y)) >> 1) | fl) &
(HAVE_TRANSLATE_X | HAVE_ROTATION | HAVE_SCALE_X | HAVE_SKEW_X | HAVE_TCENTER_X);
num += hb_popcount (fl);
return num;
/* Slower but more readable code. */
if (fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y)) num++;
if (fl & HAVE_ROTATION) num++;
if (fl & (HAVE_SCALE_X | HAVE_SCALE_Y)) num++;
if (fl & (HAVE_SKEW_X | HAVE_SKEW_Y)) num++;
if (fl & (HAVE_TCENTER_X | HAVE_TCENTER_Y)) num++;
return num;
}
void transform_points (hb_array_t<const contour_point_t> record_points,
hb_array_t<contour_point_t> points) const
{
float matrix[4];
contour_point_t trans;
get_transformation_from_points (record_points.arrayZ, matrix, trans);
auto arrayZ = points.arrayZ;
unsigned count = points.length;
if (matrix[0] != 1.f || matrix[1] != 0.f ||
matrix[2] != 0.f || matrix[3] != 1.f)
for (unsigned i = 0; i < count; i++)
arrayZ[i].transform (matrix);
if (trans.x != 0.f || trans.y != 0.f)
for (unsigned i = 0; i < count; i++)
arrayZ[i].translate (trans);
}
static inline void transform (float (&matrix)[4], contour_point_t &trans,
float (other)[6])
{
// https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L268
float xx1 = other[0];
float xy1 = other[1];
float yx1 = other[2];
float yy1 = other[3];
float dx1 = other[4];
float dy1 = other[5];
float xx2 = matrix[0];
float xy2 = matrix[1];
float yx2 = matrix[2];
float yy2 = matrix[3];
float dx2 = trans.x;
float dy2 = trans.y;
matrix[0] = xx1*xx2 + xy1*yx2;
matrix[1] = xx1*xy2 + xy1*yy2;
matrix[2] = yx1*xx2 + yy1*yx2;
matrix[3] = yx1*xy2 + yy1*yy2;
trans.x = xx2*dx1 + yx2*dy1 + dx2;
trans.y = xy2*dx1 + yy2*dy1 + dy2;
}
static void translate (float (&matrix)[4], contour_point_t &trans,
float translateX, float translateY)
{
if (!translateX && !translateY)
return;
trans.x += matrix[0] * translateX + matrix[2] * translateY;
trans.y += matrix[1] * translateX + matrix[3] * translateY;
}
static void scale (float (&matrix)[4], contour_point_t &trans,
float scaleX, float scaleY)
{
if (scaleX == 1.f && scaleY == 1.f)
return;
matrix[0] *= scaleX;
matrix[1] *= scaleX;
matrix[2] *= scaleY;
matrix[3] *= scaleY;
}
static void rotate (float (&matrix)[4], contour_point_t &trans,
float rotation)
{
if (!rotation)
return;
// https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L240
rotation = rotation * HB_PI;
float c;
float s;
#ifdef HAVE_SINCOSF
sincosf (rotation, &s, &c);
#else
c = cosf (rotation);
s = sinf (rotation);
#endif
float other[6] = {c, s, -s, c, 0.f, 0.f};
transform (matrix, trans, other);
}
static void skew (float (&matrix)[4], contour_point_t &trans,
float skewX, float skewY)
{
if (!skewX && !skewY)
return;
// https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L255
skewX = skewX * HB_PI;
skewY = skewY * HB_PI;
float other[6] = {1.f,
skewY ? tanf (skewY) : 0.f,
skewX ? tanf (skewX) : 0.f,
1.f,
0.f, 0.f};
transform (matrix, trans, other);
}
bool get_points (contour_point_vector_t &points) const
{
unsigned num_points = get_num_points ();
points.alloc (points.length + num_points + 4); // For phantom points
if (unlikely (!points.resize (points.length + num_points, false))) return false;
contour_point_t *rec_points = points.arrayZ + (points.length - num_points);
hb_memset (rec_points, 0, num_points * sizeof (rec_points[0]));
unsigned fl = flags;
unsigned num_axes = numAxes;
unsigned axis_width = (fl & AXIS_INDICES_ARE_SHORT) ? 2 : 1;
unsigned axes_size = num_axes * axis_width;
const F2DOT14 *q = (const F2DOT14 *) (axes_size +
(fl & GID_IS_24BIT ? 3 : 2) +
(const HBUINT8 *) &pad);
unsigned count = num_axes;
if (fl & AXES_HAVE_VARIATION)
{
for (unsigned i = 0; i < count; i++)
rec_points++->x = q++->to_int ();
}
else
q += count;
const HBUINT16 *p = (const HBUINT16 *) q;
if (fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y))
{
int translateX = (fl & HAVE_TRANSLATE_X) ? * (const FWORD *) p++ : 0;
int translateY = (fl & HAVE_TRANSLATE_Y) ? * (const FWORD *) p++ : 0;
rec_points->x = translateX;
rec_points->y = translateY;
rec_points++;
}
if (fl & HAVE_ROTATION)
{
int rotation = (fl & HAVE_ROTATION) ? ((const F4DOT12 *) p++)->to_int () : 0;
rec_points->x = rotation;
rec_points++;
}
if (fl & (HAVE_SCALE_X | HAVE_SCALE_Y))
{
int scaleX = (fl & HAVE_SCALE_X) ? ((const F6DOT10 *) p++)->to_int () : 1 << 10;
int scaleY = (fl & HAVE_SCALE_Y) ? ((const F6DOT10 *) p++)->to_int () : 1 << 10;
if ((fl & UNIFORM_SCALE) && !(fl & HAVE_SCALE_Y))
scaleY = scaleX;
rec_points->x = scaleX;
rec_points->y = scaleY;
rec_points++;
}
if (fl & (HAVE_SKEW_X | HAVE_SKEW_Y))
{
int skewX = (fl & HAVE_SKEW_X) ? ((const F4DOT12 *) p++)->to_int () : 0;
int skewY = (fl & HAVE_SKEW_Y) ? ((const F4DOT12 *) p++)->to_int () : 0;
rec_points->x = skewX;
rec_points->y = skewY;
rec_points++;
}
if (fl & (HAVE_TCENTER_X | HAVE_TCENTER_Y))
{
int tCenterX = (fl & HAVE_TCENTER_X) ? * (const FWORD *) p++ : 0;
int tCenterY = (fl & HAVE_TCENTER_Y) ? * (const FWORD *) p++ : 0;
rec_points->x = tCenterX;
rec_points->y = tCenterY;
rec_points++;
}
return true;
}
void get_transformation_from_points (const contour_point_t *rec_points,
float (&matrix)[4], contour_point_t &trans) const
{
unsigned fl = flags;
if (fl & AXES_HAVE_VARIATION)
rec_points += numAxes;
matrix[0] = matrix[3] = 1.f;
matrix[1] = matrix[2] = 0.f;
trans.init (0.f, 0.f);
float translateX = 0.f;
float translateY = 0.f;
float rotation = 0.f;
float scaleX = 1.f;
float scaleY = 1.f;
float skewX = 0.f;
float skewY = 0.f;
float tCenterX = 0.f;
float tCenterY = 0.f;
if (fl & (HAVE_TRANSLATE_X | HAVE_TRANSLATE_Y))
{
translateX = rec_points->x;
translateY = rec_points->y;
rec_points++;
}
if (fl & HAVE_ROTATION)
{
rotation = rec_points->x / (1 << 12);
rec_points++;
}
if (fl & (HAVE_SCALE_X | HAVE_SCALE_Y))
{
scaleX = rec_points->x / (1 << 10);
scaleY = rec_points->y / (1 << 10);
rec_points++;
}
if (fl & (HAVE_SKEW_X | HAVE_SKEW_Y))
{
skewX = rec_points->x / (1 << 12);
skewY = rec_points->y / (1 << 12);
rec_points++;
}
if (fl & (HAVE_TCENTER_X | HAVE_TCENTER_Y))
{
tCenterX = rec_points->x;
tCenterY = rec_points->y;
rec_points++;
}
translate (matrix, trans, translateX + tCenterX, translateY + tCenterY);
rotate (matrix, trans, rotation);
scale (matrix, trans, scaleX, scaleY);
skew (matrix, trans, -skewX, skewY);
translate (matrix, trans, -tCenterX, -tCenterY);
}
void set_variations (coord_setter_t &setter,
hb_array_t<contour_point_t> rec_points) const
{
bool have_variations = flags & AXES_HAVE_VARIATION;
unsigned axis_width = (flags & AXIS_INDICES_ARE_SHORT) ? 2 : 1;
unsigned num_axes = numAxes;
const HBUINT8 *p = (const HBUINT8 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24BIT ? 3 : 2));
const HBUINT16 *q = (const HBUINT16 *) (((HBUINT8 *) &numAxes) + numAxes.static_size + (flags & GID_IS_24BIT ? 3 : 2));
const F2DOT14 *a = (const F2DOT14 *) ((HBUINT8 *) (axis_width == 1 ? (p + num_axes) : (HBUINT8 *) (q + num_axes)));
unsigned count = num_axes;
for (unsigned i = 0; i < count; i++)
{
unsigned axis_index = axis_width == 1 ? (unsigned) *p++ : (unsigned) *q++;
signed v = have_variations ? rec_points.arrayZ[i].x : a++->to_int ();
v = hb_clamp (v, -(1<<14), (1<<14));
setter[axis_index] = v;
}
}
protected:
HBUINT16 flags;
HBUINT8 numAxes;
HBUINT16 pad;
public:
DEFINE_SIZE_MIN (5);
};
using var_composite_iter_t = composite_iter_tmpl<VarCompositeGlyphRecord>;
struct VarCompositeGlyph
{
const GlyphHeader &header;
hb_bytes_t bytes;
VarCompositeGlyph (const GlyphHeader &header_, hb_bytes_t bytes_) :
header (header_), bytes (bytes_) {}
var_composite_iter_t iter () const
{ return var_composite_iter_t (bytes, &StructAfter<VarCompositeGlyphRecord, GlyphHeader> (header)); }
const hb_bytes_t trim_padding () const
{
unsigned length = GlyphHeader::static_size;
for (auto &comp : iter ())
length += comp.get_size ();
return bytes.sub_array (0, length);
}
};
} /* namespace glyf_impl */
} /* namespace OT */
#endif /* OT_GLYF_VARCOMPOSITEGLYPH_HH */

View File

@ -205,8 +205,12 @@ struct glyf_accelerator_t
protected:
template<typename T>
bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer) const
bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer,
hb_array_t<const int> coords = hb_array_t<const int> ()) const
{
if (!coords)
coords = hb_array (font->coords, font->num_coords);
if (gid >= num_glyphs) return false;
/* Making this allocfree is not that easy
@ -216,7 +220,7 @@ struct glyf_accelerator_t
contour_point_vector_t all_points;
bool phantom_only = !consumer.is_consuming_contour_points ();
if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, nullptr, nullptr, true, true, phantom_only)))
if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, nullptr, nullptr, true, true, phantom_only, coords)))
return false;
unsigned count = all_points.length;
@ -408,6 +412,11 @@ struct glyf_accelerator_t
get_path (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session) const
{ return get_points (font, gid, glyf_impl::path_builder_t (font, draw_session)); }
bool
get_path_at (hb_font_t *font, hb_codepoint_t gid, hb_draw_session_t &draw_session,
hb_array_t<const int> coords) const
{ return get_points (font, gid, glyf_impl::path_builder_t (font, draw_session), coords); }
#ifndef HB_NO_VAR
const gvar_accelerator_t *gvar;
#endif

View File

@ -0,0 +1,65 @@
/*
* Copyright © 2020 Ebrahim Byagowi
*
* 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.
*/
#include <stdlib.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
int alloc_state = 0;
__attribute__((no_sanitize("integer")))
static int fastrand ()
{
if (!alloc_state) return 1;
/* Based on https://software.intel.com/content/www/us/en/develop/articles/fast-random-number-generator-on-the-intel-pentiumr-4-processor.html */
alloc_state = (214013 * alloc_state + 2531011);
return (alloc_state >> 16) & 0x7FFF;
}
void* hb_malloc_impl (size_t size)
{
return (fastrand () % 16) ? malloc (size) : NULL;
}
void* hb_calloc_impl (size_t nmemb, size_t size)
{
return (fastrand () % 16) ? calloc (nmemb, size) : NULL;
}
void* hb_realloc_impl (void *ptr, size_t size)
{
return (fastrand () % 16) ? realloc (ptr, size) : NULL;
}
void hb_free_impl (void *ptr)
{
return free (ptr);
}
#ifdef __cplusplus
}
#endif

View File

@ -1,3 +1,4 @@
#include "OT/Var/VARC/VARC.cc"
#include "graph/gsubgpos-context.cc"
#include "hb-aat-layout.cc"
#include "hb-aat-map.cc"

View File

@ -1,3 +1,4 @@
#include "OT/Var/VARC/VARC.cc"
#include "hb-aat-layout.cc"
#include "hb-aat-map.cc"
#include "hb-blob.cc"

View File

@ -39,6 +39,7 @@ namespace AAT {
using namespace OT;
#define HB_AAT_BUFFER_DIGEST_THRESHOLD 32
struct ankr;
@ -60,6 +61,7 @@ struct hb_aat_apply_context_t :
const ankr *ankr_table;
const OT::GDEF *gdef_table;
const hb_sorted_vector_t<hb_aat_map_t::range_flags_t> *range_flags = nullptr;
hb_set_digest_t buffer_digest = hb_set_digest_t::full ();
hb_set_digest_t machine_glyph_set = hb_set_digest_t::full ();
hb_set_digest_t left_set = hb_set_digest_t::full ();
hb_set_digest_t right_set = hb_set_digest_t::full ();
@ -927,7 +929,15 @@ struct StateTableDriver
machine (machine_),
num_glyphs (face_->get_num_glyphs ()) {}
template <typename context_t, typename set_t = hb_set_digest_t>
template <typename context_t>
bool is_idempotent_on_all_out_of_bounds (context_t *c, hb_aat_apply_context_t *ac)
{
const auto entry = machine.get_entry (StateTableT::STATE_START_OF_TEXT, CLASS_OUT_OF_BOUNDS);
return !c->is_actionable (ac->buffer, this, entry) &&
machine.new_state (entry.newState) == StateTableT::STATE_START_OF_TEXT;
}
template <typename context_t>
void drive (context_t *c, hb_aat_apply_context_t *ac)
{
hb_buffer_t *buffer = ac->buffer;
@ -1005,7 +1015,7 @@ struct StateTableDriver
const auto is_safe_to_break_extra = [&]()
{
/* 2c. */
const auto wouldbe_entry = machine.get_entry(StateTableT::STATE_START_OF_TEXT, klass);
const auto &wouldbe_entry = machine.get_entry(StateTableT::STATE_START_OF_TEXT, klass);
/* 2c'. */
if (c->is_actionable (buffer, this, wouldbe_entry))

View File

@ -107,10 +107,14 @@ struct KerxSubTableFormat0
TRACE_APPLY (this);
if (!c->plan->requested_kerning)
return false;
return_trace (false);
if (header.coverage & header.Backwards)
return false;
return_trace (false);
if (!(c->buffer_digest.may_have (c->left_set) &&
c->buffer_digest.may_have (c->right_set)))
return_trace (false);
accelerator_t accel (*this, c);
hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream);
@ -367,6 +371,12 @@ struct KerxSubTableFormat1
driver_context_t dc (this, c);
StateTableDriver<Types, EntryData> driver (machine, c->font->face);
if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
!(c->buffer_digest.may_have (c->left_set) &&
c->buffer_digest.may_have (c->right_set)))
return_trace (false);
driver.drive (&dc, c);
return_trace (true);
@ -425,10 +435,14 @@ struct KerxSubTableFormat2
TRACE_APPLY (this);
if (!c->plan->requested_kerning)
return false;
return_trace (false);
if (header.coverage & header.Backwards)
return false;
return_trace (false);
if (!(c->buffer_digest.may_have (c->left_set) &&
c->buffer_digest.may_have (c->right_set)))
return_trace (false);
accelerator_t accel (*this, c);
hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream);
@ -635,6 +649,12 @@ struct KerxSubTableFormat4
driver_context_t dc (this, c);
StateTableDriver<Types, EntryData> driver (machine, c->font->face);
if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
!(c->buffer_digest.may_have (c->left_set) &&
c->buffer_digest.may_have (c->right_set)))
return_trace (false);
driver.drive (&dc, c);
return_trace (true);
@ -710,10 +730,14 @@ struct KerxSubTableFormat6
TRACE_APPLY (this);
if (!c->plan->requested_kerning)
return false;
return_trace (false);
if (header.coverage & header.Backwards)
return false;
return_trace (false);
if (!(c->buffer_digest.may_have (c->left_set) &&
c->buffer_digest.may_have (c->right_set)))
return_trace (false);
accelerator_t accel (*this, c);
hb_kern_machine_t<accelerator_t> machine (accel, header.coverage & header.CrossStream);
@ -919,6 +943,9 @@ struct KerxTable
{
if (st->get_type () == 1)
return true;
// TODO: What about format 4? What's this API used for anyway?
st = &StructAfter<SubTable> (*st);
}
return false;
@ -962,6 +989,11 @@ struct KerxTable
{
c->buffer->unsafe_to_concat ();
if (c->buffer->len < HB_AAT_BUFFER_DIGEST_THRESHOLD)
c->buffer_digest = c->buffer->digest ();
else
c->buffer_digest = hb_set_digest_t::full ();
typedef typename T::SubTable SubTable;
bool ret = false;

View File

@ -170,6 +170,11 @@ struct RearrangementSubtable
driver_context_t dc (this);
StateTableDriver<Types, EntryData> driver (machine, c->face);
if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
!c->buffer_digest.may_have (c->machine_glyph_set))
return_trace (false);
driver.drive (&dc, c);
return_trace (dc.ret);
@ -267,6 +272,7 @@ struct ContextualSubtable
{
buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
buffer->info[mark].codepoint = *replacement;
c->buffer_digest.add (*replacement);
if (has_glyph_classes)
_hb_glyph_info_set_glyph_props (&buffer->info[mark],
gdef.get_glyph_props (*replacement));
@ -296,6 +302,7 @@ struct ContextualSubtable
if (replacement)
{
buffer->info[idx].codepoint = *replacement;
c->buffer_digest.add (*replacement);
if (has_glyph_classes)
_hb_glyph_info_set_glyph_props (&buffer->info[idx],
gdef.get_glyph_props (*replacement));
@ -328,6 +335,11 @@ struct ContextualSubtable
driver_context_t dc (this, c);
StateTableDriver<Types, EntryData> driver (machine, c->face);
if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
!c->buffer_digest.may_have (c->machine_glyph_set))
return_trace (false);
driver.drive (&dc, c);
return_trace (dc.ret);
@ -586,6 +598,11 @@ struct LigatureSubtable
driver_context_t dc (this, c);
StateTableDriver<Types, EntryData> driver (machine, c->face);
if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
!c->buffer_digest.may_have (c->machine_glyph_set))
return_trace (false);
driver.drive (&dc, c);
return_trace (dc.ret);
@ -654,6 +671,7 @@ struct NoncontextualSubtable
if (replacement)
{
info[i].codepoint = *replacement;
c->buffer_digest.add (*replacement);
if (has_glyph_classes)
_hb_glyph_info_set_glyph_props (&info[i],
gdef.get_glyph_props (*replacement));
@ -788,6 +806,9 @@ struct InsertionSubtable
if (unlikely (!buffer->copy_glyph ())) return;
/* TODO We ignore KashidaLike setting. */
if (unlikely (!buffer->replace_glyphs (0, count, glyphs))) return;
for (unsigned int i = 0; i < count; i++)
c->buffer_digest.add (glyphs[i]);
ret = true;
if (buffer->idx < buffer->len && !before)
buffer->skip_glyph ();
@ -853,6 +874,11 @@ struct InsertionSubtable
driver_context_t dc (this, c);
StateTableDriver<Types, EntryData> driver (machine, c->face);
if (driver.is_idempotent_on_all_out_of_bounds (&dc, c) &&
!c->buffer_digest.may_have (c->machine_glyph_set))
return_trace (false);
driver.drive (&dc, c);
return_trace (dc.ret);
@ -1348,6 +1374,11 @@ struct mortmorx
c->buffer->unsafe_to_concat ();
if (c->buffer->len < HB_AAT_BUFFER_DIGEST_THRESHOLD)
c->buffer_digest = c->buffer->digest ();
else
c->buffer_digest = hb_set_digest_t::full ();
c->set_lookup_index (0);
const Chain<Types> *chain = &firstChain;
unsigned int count = chainCount;

View File

@ -624,7 +624,6 @@ struct opset_t
} else {
/* invalid unknown operator */
env.clear_args ();
env.set_error ();
}
break;
}

View File

@ -118,6 +118,10 @@
#define HB_NO_VAR_COMPOSITES
#endif
#ifdef HB_NO_VAR
#define HB_NO_VAR_COMPOSITES
#endif
#ifdef HB_DISABLE_DEPRECATED
#define HB_IF_NOT_DEPRECATED(x)
#else

View File

@ -232,7 +232,7 @@ struct hb_draw_session_t
funcs->close_path (draw_data, st);
}
protected:
public:
float slant;
bool not_slanted;
hb_draw_funcs_t *funcs;

View File

@ -1,119 +0,0 @@
/*
* Copyright © 2022 Red Hat, 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.
*/
#ifndef HB_FEATURES_H
#define HB_FEATURES_H
HB_BEGIN_DECLS
/**
* SECTION: hb-features
* @title: hb-features
* @short_description: Feature detection
* @include: hb-features.h
*
* Macros for detecting optional HarfBuzz features at build time.
**/
/**
* HB_HAS_CAIRO:
*
* Defined if Harfbuzz has been built with cairo support.
*/
#
/**
* HB_HAS_CORETEXT:
*
* Defined if Harfbuzz has been built with CoreText support.
*/
#undef HB_HAS_CORETEXT
/**
* HB_HAS_DIRECTWRITE:
*
* Defined if Harfbuzz has been built with DirectWrite support.
*/
#undef HB_HAS_DIRECTWRITE
/**
* HB_HAS_FREETYPE:
*
* Defined if Harfbuzz has been built with Freetype support.
*/
#define HB_HAS_FREETYPE 1
/**
* HB_HAS_GDI:
*
* Defined if Harfbuzz has been built with GDI support.
*/
#undef HB_HAS_GDI
/**
* HB_HAS_GLIB:
*
* Defined if Harfbuzz has been built with GLib support.
*/
#define HB_HAS_GLIB 1
/**
* HB_HAS_GOBJECT:
*
* Defined if Harfbuzz has been built with GObject support.
*/
#undef HB_HAS_GOBJECT
/**
* HB_HAS_GRAPHITE:
*
* Defined if Harfbuzz has been built with Graphite support.
*/
#undef HB_HAS_GRAPHITE
/**
* HB_HAS_ICU:
*
* Defined if Harfbuzz has been built with ICU support.
*/
#undef HB_HAS_ICU
/**
* HB_HAS_UNISCRIBE:
*
* Defined if Harfbuzz has been built with Uniscribe support.
*/
#undef HB_HAS_UNISCRIBE
/**
* HB_HAS_WASM:
*
* Defined if Harfbuzz has been built with WebAssembly support.
*/
#undef HB_HAS_WASM
HB_END_DECLS
#endif /* HB_FEATURES_H */

View File

@ -108,7 +108,7 @@ struct hb_ft_paint_context_t
hb_map_t current_glyphs;
hb_map_t current_layers;
int depth_left = HB_MAX_NESTING_LEVEL;
int edge_count = HB_COLRV1_MAX_EDGE_COUNT;
int edge_count = HB_MAX_GRAPH_EDGE_COUNT;
};
static unsigned

View File

@ -0,0 +1,284 @@
/*
* Copyright © 2022 Behdad Esfahbod
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#ifndef HB_GEOMETRY_HH
#define HB_GEOMETRY_HH
#include "hb.hh"
struct hb_extents_t
{
hb_extents_t () {}
hb_extents_t (float xmin, float ymin, float xmax, float ymax) :
xmin (xmin), ymin (ymin), xmax (xmax), ymax (ymax) {}
bool is_empty () const { return xmin >= xmax || ymin >= ymax; }
bool is_void () const { return xmin > xmax; }
void union_ (const hb_extents_t &o)
{
xmin = hb_min (xmin, o.xmin);
ymin = hb_min (ymin, o.ymin);
xmax = hb_max (xmax, o.xmax);
ymax = hb_max (ymax, o.ymax);
}
void intersect (const hb_extents_t &o)
{
xmin = hb_max (xmin, o.xmin);
ymin = hb_max (ymin, o.ymin);
xmax = hb_min (xmax, o.xmax);
ymax = hb_min (ymax, o.ymax);
}
void
add_point (float x, float y)
{
if (unlikely (is_void ()))
{
xmin = xmax = x;
ymin = ymax = y;
}
else
{
xmin = hb_min (xmin, x);
ymin = hb_min (ymin, y);
xmax = hb_max (xmax, x);
ymax = hb_max (ymax, y);
}
}
float xmin = 0.f;
float ymin = 0.f;
float xmax = -1.f;
float ymax = -1.f;
};
struct hb_transform_t
{
hb_transform_t () {}
hb_transform_t (float xx, float yx,
float xy, float yy,
float x0, float y0) :
xx (xx), yx (yx), xy (xy), yy (yy), x0 (x0), y0 (y0) {}
void multiply (const hb_transform_t &o)
{
/* Copied from cairo, with "o" being "a" there and "this" being "b" there. */
hb_transform_t r;
r.xx = o.xx * xx + o.yx * xy;
r.yx = o.xx * yx + o.yx * yy;
r.xy = o.xy * xx + o.yy * xy;
r.yy = o.xy * yx + o.yy * yy;
r.x0 = o.x0 * xx + o.y0 * xy + x0;
r.y0 = o.x0 * yx + o.y0 * yy + y0;
*this = r;
}
void transform_distance (float &dx, float &dy) const
{
float new_x = xx * dx + xy * dy;
float new_y = yx * dx + yy * dy;
dx = new_x;
dy = new_y;
}
void transform_point (float &x, float &y) const
{
transform_distance (x, y);
x += x0;
y += y0;
}
void transform_extents (hb_extents_t &extents) const
{
float quad_x[4], quad_y[4];
quad_x[0] = extents.xmin;
quad_y[0] = extents.ymin;
quad_x[1] = extents.xmin;
quad_y[1] = extents.ymax;
quad_x[2] = extents.xmax;
quad_y[2] = extents.ymin;
quad_x[3] = extents.xmax;
quad_y[3] = extents.ymax;
extents = hb_extents_t {};
for (unsigned i = 0; i < 4; i++)
{
transform_point (quad_x[i], quad_y[i]);
extents.add_point (quad_x[i], quad_y[i]);
}
}
void transform (const hb_transform_t &o) { multiply (o); }
void translate (float x, float y)
{
if (x == 0.f && y == 0.f)
return;
x0 += xx * x + xy * y;
y0 += yx * x + yy * y;
}
void scale (float scaleX, float scaleY)
{
if (scaleX == 1.f && scaleY == 1.f)
return;
xx *= scaleX;
yx *= scaleX;
xy *= scaleY;
yy *= scaleY;
}
void rotate (float rotation)
{
if (rotation == 0.f)
return;
// https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L240
rotation = rotation * HB_PI;
float c;
float s;
#ifdef HAVE_SINCOSF
sincosf (rotation, &s, &c);
#else
c = cosf (rotation);
s = sinf (rotation);
#endif
auto other = hb_transform_t{c, s, -s, c, 0.f, 0.f};
transform (other);
}
void skew (float skewX, float skewY)
{
if (skewX == 0.f && skewY == 0.f)
return;
// https://github.com/fonttools/fonttools/blob/f66ee05f71c8b57b5f519ee975e95edcd1466e14/Lib/fontTools/misc/transform.py#L255
skewX = skewX * HB_PI;
skewY = skewY * HB_PI;
auto other = hb_transform_t{1.f,
skewY ? tanf (skewY) : 0.f,
skewX ? tanf (skewX) : 0.f,
1.f,
0.f, 0.f};
transform (other);
}
float xx = 1.f;
float yx = 0.f;
float xy = 0.f;
float yy = 1.f;
float x0 = 0.f;
float y0 = 0.f;
};
struct hb_bounds_t
{
enum status_t {
UNBOUNDED,
BOUNDED,
EMPTY,
};
hb_bounds_t (status_t status) : status (status) {}
hb_bounds_t (const hb_extents_t &extents) :
status (extents.is_empty () ? EMPTY : BOUNDED), extents (extents) {}
void union_ (const hb_bounds_t &o)
{
if (o.status == UNBOUNDED)
status = UNBOUNDED;
else if (o.status == BOUNDED)
{
if (status == EMPTY)
*this = o;
else if (status == BOUNDED)
extents.union_ (o.extents);
}
}
void intersect (const hb_bounds_t &o)
{
if (o.status == EMPTY)
status = EMPTY;
else if (o.status == BOUNDED)
{
if (status == UNBOUNDED)
*this = o;
else if (status == BOUNDED)
{
extents.intersect (o.extents);
if (extents.is_empty ())
status = EMPTY;
}
}
}
status_t status;
hb_extents_t extents;
};
struct hb_transform_decomposed_t
{
float translateX = 0;
float translateY = 0;
float rotation = 0; // in degrees, counter-clockwise
float scaleX = 1;
float scaleY = 1;
float skewX = 0; // in degrees, counter-clockwise
float skewY = 0; // in degrees, counter-clockwise
float tCenterX = 0;
float tCenterY = 0;
operator bool () const
{
return translateX || translateY ||
rotation ||
scaleX != 1 || scaleY != 1 ||
skewX || skewY ||
tCenterX || tCenterY;
}
hb_transform_t to_transform () const
{
hb_transform_t t;
t.translate (translateX + tCenterX, translateY + tCenterY);
t.rotate (rotation);
t.scale (scaleX, scaleY);
t.skew (-skewX, skewY);
t.translate (-tCenterX, -tCenterY);
return t;
}
};
#endif /* HB_GEOMETRY_HH */

View File

@ -324,6 +324,16 @@ struct hb_is_sink_of
(hb_is_source_of(Iter, Item) && Iter::is_sorted_iterator)
struct
{
template <typename Iterable,
hb_requires (hb_is_iterable (Iterable))>
unsigned operator () (const Iterable &_) const { return hb_len (hb_iter (_)); }
unsigned operator () (unsigned _) const { return _; }
}
HB_FUNCOBJ (hb_len_of);
/* Range-based 'for' for iterables. */
template <typename Iterable,

View File

@ -88,25 +88,24 @@
#define HB_MAX_LOOKUP_VISIT_COUNT 35000
#endif
#ifndef HB_MAX_GRAPH_EDGE_COUNT
#define HB_MAX_GRAPH_EDGE_COUNT 2048
#endif
#ifndef HB_GLYF_VAR_COMPOSITE_MAX_AXES
#define HB_GLYF_VAR_COMPOSITE_MAX_AXES 4096
#ifndef HB_VAR_COMPOSITE_MAX_AXES
#define HB_VAR_COMPOSITE_MAX_AXES 4096
#endif
#ifndef HB_GLYF_MAX_POINTS
#define HB_GLYF_MAX_POINTS 20000
#endif
#ifndef HB_GLYF_MAX_EDGE_COUNT
#define HB_GLYF_MAX_EDGE_COUNT 1024
#define HB_GLYF_MAX_POINTS 200000
#endif
#ifndef HB_CFF_MAX_OPS
#define HB_CFF_MAX_OPS 10000
#endif
#ifndef HB_COLRV1_MAX_EDGE_COUNT
#define HB_COLRV1_MAX_EDGE_COUNT 2048
#ifndef HB_MAX_COMPOSITE_OPERATIONS_PER_GLYPH
#define HB_MAX_COMPOSITE_OPERATIONS_PER_GLYPH 64
#endif

View File

@ -132,6 +132,89 @@ struct HBUINT15 : HBUINT16
DEFINE_SIZE_STATIC (2);
};
/* 32-bit unsigned integer with variable encoding. */
struct HBUINT32VAR
{
unsigned get_size () const
{
unsigned b0 = v[0];
if (b0 < 0x80)
return 1;
else if (b0 < 0xC0)
return 2;
else if (b0 < 0xE0)
return 3;
else if (b0 < 0xF0)
return 4;
else
return 5;
}
static unsigned get_size (uint32_t v)
{
if (v < 0x80)
return 1;
else if (v < 0x4000)
return 2;
else if (v < 0x200000)
return 3;
else if (v < 0x10000000)
return 4;
else
return 5;
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_range (v, 1) &&
hb_barrier () &&
c->check_range (v, get_size ()));
}
operator uint32_t () const
{
unsigned b0 = v[0];
if (b0 < 0x80)
return b0;
else if (b0 < 0xC0)
return ((b0 & 0x3F) << 8) | v[1];
else if (b0 < 0xE0)
return ((b0 & 0x1F) << 16) | (v[1] << 8) | v[2];
else if (b0 < 0xF0)
return ((b0 & 0x0F) << 24) | (v[1] << 16) | (v[2] << 8) | v[3];
else
return (v[1] << 24) | (v[2] << 16) | (v[3] << 8) | v[4];
}
static bool serialize (hb_serialize_context_t *c, uint32_t v)
{
unsigned len = get_size (v);
unsigned char *buf = c->allocate_size<unsigned char> (len, false);
if (unlikely (!buf))
return false;
unsigned char *p = buf + len;
for (unsigned i = 0; i < len; i++)
{
*--p = v & 0xFF;
v >>= 8;
}
if (len > 1)
buf[0] |= ((1 << (len - 1)) - 1) << (9 - len);
return true;
}
protected:
unsigned char v[1];
public:
DEFINE_SIZE_MIN (1);
};
/* 16-bit signed integer (HBINT16) that describes a quantity in FUnits. */
typedef HBINT16 FWORD;
@ -149,6 +232,7 @@ struct HBFixed : Type
operator signed () const = delete;
operator unsigned () const = delete;
explicit operator float () const { return to_float (); }
typename Type::type to_int () const { return Type::v; }
void set_int (typename Type::type i ) { Type::v = i; }
float to_float (float offset = 0) const { return ((int32_t) Type::v + offset) / shift; }
@ -756,6 +840,7 @@ template <typename Type> using Array32Of = ArrayOf<Type, HBUINT32>;
using PString = ArrayOf<HBUINT8, HBUINT8>;
/* Array of Offset's */
template <typename Type> using Array8OfOffset24To = ArrayOf<OffsetTo<Type, HBUINT24>, HBUINT8>;
template <typename Type> using Array16OfOffset16To = ArrayOf<OffsetTo<Type, HBUINT16>, HBUINT16>;
template <typename Type> using Array16OfOffset32To = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT16>;
template <typename Type> using Array32OfOffset32To = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32>;
@ -1163,6 +1248,638 @@ struct VarSizedBinSearchArrayOf
};
/* CFF INDEX */
template <typename COUNT>
struct CFFIndex
{
unsigned int offset_array_size () const
{ return offSize * (count + 1); }
template <typename Iterable,
hb_requires (hb_is_iterable (Iterable))>
bool serialize (hb_serialize_context_t *c,
const Iterable &iterable,
const unsigned *p_data_size = nullptr,
unsigned min_off_size = 0)
{
TRACE_SERIALIZE (this);
unsigned data_size;
if (p_data_size)
data_size = *p_data_size;
else
total_size (iterable, &data_size);
auto it = hb_iter (iterable);
if (unlikely (!serialize_header (c, +it, data_size, min_off_size))) return_trace (false);
unsigned char *ret = c->allocate_size<unsigned char> (data_size, false);
if (unlikely (!ret)) return_trace (false);
for (const auto &_ : +it)
{
unsigned len = _.length;
if (!len)
continue;
if (len <= 1)
{
*ret++ = *_.arrayZ;
continue;
}
hb_memcpy (ret, _.arrayZ, len);
ret += len;
}
return_trace (true);
}
template <typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
bool serialize_header (hb_serialize_context_t *c,
Iterator it,
unsigned data_size,
unsigned min_off_size = 0)
{
TRACE_SERIALIZE (this);
unsigned off_size = (hb_bit_storage (data_size + 1) + 7) / 8;
off_size = hb_max(min_off_size, off_size);
/* serialize CFFIndex header */
if (unlikely (!c->extend_min (this))) return_trace (false);
this->count = hb_len (it);
if (!this->count) return_trace (true);
if (unlikely (!c->extend (this->offSize))) return_trace (false);
this->offSize = off_size;
if (unlikely (!c->allocate_size<HBUINT8> (off_size * (this->count + 1), false)))
return_trace (false);
/* serialize indices */
unsigned int offset = 1;
if (HB_OPTIMIZE_SIZE_VAL)
{
unsigned int i = 0;
for (const auto &_ : +it)
{
set_offset_at (i++, offset);
offset += hb_len_of (_);
}
set_offset_at (i, offset);
}
else
switch (off_size)
{
case 1:
{
HBUINT8 *p = (HBUINT8 *) offsets;
for (const auto &_ : +it)
{
*p++ = offset;
offset += hb_len_of (_);
}
*p = offset;
}
break;
case 2:
{
HBUINT16 *p = (HBUINT16 *) offsets;
for (const auto &_ : +it)
{
*p++ = offset;
offset += hb_len_of (_);
}
*p = offset;
}
break;
case 3:
{
HBUINT24 *p = (HBUINT24 *) offsets;
for (const auto &_ : +it)
{
*p++ = offset;
offset += hb_len_of (_);
}
*p = offset;
}
break;
case 4:
{
HBUINT32 *p = (HBUINT32 *) offsets;
for (const auto &_ : +it)
{
*p++ = offset;
offset += hb_len_of (_);
}
*p = offset;
}
break;
default:
break;
}
assert (offset == data_size + 1);
return_trace (true);
}
template <typename Iterable,
hb_requires (hb_is_iterable (Iterable))>
static unsigned total_size (const Iterable &iterable, unsigned *data_size = nullptr, unsigned min_off_size = 0)
{
auto it = + hb_iter (iterable);
if (!it)
{
if (data_size) *data_size = 0;
return min_size;
}
unsigned total = 0;
for (const auto &_ : +it)
total += hb_len_of (_);
if (data_size) *data_size = total;
unsigned off_size = (hb_bit_storage (total + 1) + 7) / 8;
off_size = hb_max(min_off_size, off_size);
return min_size + HBUINT8::static_size + (hb_len (it) + 1) * off_size + total;
}
void set_offset_at (unsigned int index, unsigned int offset)
{
assert (index <= count);
unsigned int size = offSize;
const HBUINT8 *p = offsets;
switch (size)
{
case 1: ((HBUINT8 *) p)[index] = offset; break;
case 2: ((HBUINT16 *) p)[index] = offset; break;
case 3: ((HBUINT24 *) p)[index] = offset; break;
case 4: ((HBUINT32 *) p)[index] = offset; break;
default: return;
}
}
private:
unsigned int offset_at (unsigned int index) const
{
assert (index <= count);
unsigned int size = offSize;
const HBUINT8 *p = offsets;
switch (size)
{
case 1: return ((HBUINT8 *) p)[index];
case 2: return ((HBUINT16 *) p)[index];
case 3: return ((HBUINT24 *) p)[index];
case 4: return ((HBUINT32 *) p)[index];
default: return 0;
}
}
const unsigned char *data_base () const
{ return (const unsigned char *) this + min_size + offSize.static_size - 1 + offset_array_size (); }
public:
hb_ubytes_t operator [] (unsigned int index) const
{
if (unlikely (index >= count)) return hb_ubytes_t ();
_hb_compiler_memory_r_barrier ();
unsigned offset0 = offset_at (index);
unsigned offset1 = offset_at (index + 1);
if (unlikely (offset1 < offset0 || offset1 > offset_at (count)))
return hb_ubytes_t ();
return hb_ubytes_t (data_base () + offset0, offset1 - offset0);
}
unsigned int get_size () const
{
if (count)
return min_size + offSize.static_size + offset_array_size () + (offset_at (count) - 1);
return min_size; /* empty CFFIndex contains count only */
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
hb_barrier () &&
(count == 0 || /* empty INDEX */
(count < count + 1u &&
c->check_struct (&offSize) && offSize >= 1 && offSize <= 4 &&
c->check_array (offsets, offSize, count + 1u) &&
c->check_range (data_base (), offset_at (count))))));
}
public:
COUNT count; /* Number of object data. Note there are (count+1) offsets */
private:
HBUINT8 offSize; /* The byte size of each offset in the offsets array. */
HBUINT8 offsets[HB_VAR_ARRAY];
/* The array of (count + 1) offsets into objects array (1-base). */
/* HBUINT8 data[HB_VAR_ARRAY]; Object data */
public:
DEFINE_SIZE_MIN (COUNT::static_size);
};
typedef CFFIndex<HBUINT16> CFF1Index;
typedef CFFIndex<HBUINT32> CFF2Index;
/* TupleValues */
struct TupleValues
{
enum packed_value_flag_t
{
VALUES_ARE_ZEROS = 0x80,
VALUES_ARE_BYTES = 0x00,
VALUES_ARE_WORDS = 0x40,
VALUES_ARE_LONGS = 0xC0,
VALUES_SIZE_MASK = 0xC0,
VALUE_RUN_COUNT_MASK = 0x3F
};
static unsigned compile (hb_array_t<const int> values, /* IN */
hb_array_t<char> encoded_bytes /* OUT */)
{
unsigned num_values = values.length;
unsigned encoded_len = 0;
unsigned i = 0;
while (i < num_values)
{
int val = values.arrayZ[i];
if (val == 0)
encoded_len += encode_value_run_as_zeroes (i, encoded_bytes.sub_array (encoded_len), values);
else if (val >= -128 && val <= 127)
encoded_len += encode_value_run_as_bytes (i, encoded_bytes.sub_array (encoded_len), values);
else if (val >= -32768 && val <= 32767)
encoded_len += encode_value_run_as_words (i, encoded_bytes.sub_array (encoded_len), values);
else
encoded_len += encode_value_run_as_longs (i, encoded_bytes.sub_array (encoded_len), values);
}
return encoded_len;
}
static unsigned encode_value_run_as_zeroes (unsigned& i,
hb_array_t<char> encoded_bytes,
hb_array_t<const int> values)
{
unsigned num_values = values.length;
unsigned run_length = 0;
auto it = encoded_bytes.iter ();
unsigned encoded_len = 0;
while (i < num_values && values.arrayZ[i] == 0)
{
i++;
run_length++;
}
while (run_length >= 64)
{
*it++ = char (VALUES_ARE_ZEROS | 63);
run_length -= 64;
encoded_len++;
}
if (run_length)
{
*it++ = char (VALUES_ARE_ZEROS | (run_length - 1));
encoded_len++;
}
return encoded_len;
}
static unsigned encode_value_run_as_bytes (unsigned &i,
hb_array_t<char> encoded_bytes,
hb_array_t<const int> values)
{
unsigned start = i;
unsigned num_values = values.length;
while (i < num_values)
{
int val = values.arrayZ[i];
if (val > 127 || val < -128)
break;
/* from fonttools: if there're 2 or more zeros in a sequence,
* it is better to start a new run to save bytes. */
if (val == 0 && i + 1 < num_values && values.arrayZ[i+1] == 0)
break;
i++;
}
unsigned run_length = i - start;
unsigned encoded_len = 0;
auto it = encoded_bytes.iter ();
while (run_length >= 64)
{
*it++ = (VALUES_ARE_BYTES | 63);
encoded_len++;
for (unsigned j = 0; j < 64; j++)
{
*it++ = static_cast<char> (values.arrayZ[start + j]);
encoded_len++;
}
start += 64;
run_length -= 64;
}
if (run_length)
{
*it++ = (VALUES_ARE_BYTES | (run_length - 1));
encoded_len++;
while (start < i)
{
*it++ = static_cast<char> (values.arrayZ[start++]);
encoded_len++;
}
}
return encoded_len;
}
static unsigned encode_value_run_as_words (unsigned &i,
hb_array_t<char> encoded_bytes,
hb_array_t<const int> values)
{
unsigned start = i;
unsigned num_values = values.length;
while (i < num_values)
{
int val = values.arrayZ[i];
/* start a new run for a single zero value*/
if (val == 0) break;
/* from fonttools: continue word-encoded run if there's only one
* single value in the range [-128, 127] because it is more compact.
* Only start a new run when there're 2 continuous such values. */
if (val >= -128 && val <= 127 &&
i + 1 < num_values &&
values.arrayZ[i+1] >= -128 && values.arrayZ[i+1] <= 127)
break;
i++;
}
unsigned run_length = i - start;
auto it = encoded_bytes.iter ();
unsigned encoded_len = 0;
while (run_length >= 64)
{
*it++ = (VALUES_ARE_WORDS | 63);
encoded_len++;
for (unsigned j = 0; j < 64; j++)
{
int16_t value_val = values.arrayZ[start + j];
*it++ = static_cast<char> (value_val >> 8);
*it++ = static_cast<char> (value_val & 0xFF);
encoded_len += 2;
}
start += 64;
run_length -= 64;
}
if (run_length)
{
*it++ = (VALUES_ARE_WORDS | (run_length - 1));
encoded_len++;
while (start < i)
{
int16_t value_val = values.arrayZ[start++];
*it++ = static_cast<char> (value_val >> 8);
*it++ = static_cast<char> (value_val & 0xFF);
encoded_len += 2;
}
}
return encoded_len;
}
static unsigned encode_value_run_as_longs (unsigned &i,
hb_array_t<char> encoded_bytes,
hb_array_t<const int> values)
{
unsigned start = i;
unsigned num_values = values.length;
while (i < num_values)
{
int val = values.arrayZ[i];
if (val >= -32768 && val <= 32767)
break;
i++;
}
unsigned run_length = i - start;
auto it = encoded_bytes.iter ();
unsigned encoded_len = 0;
while (run_length >= 64)
{
*it++ = (VALUES_ARE_LONGS | 63);
encoded_len++;
for (unsigned j = 0; j < 64; j++)
{
int32_t value_val = values.arrayZ[start + j];
*it++ = static_cast<char> (value_val >> 24);
*it++ = static_cast<char> (value_val >> 16);
*it++ = static_cast<char> (value_val >> 8);
*it++ = static_cast<char> (value_val & 0xFF);
encoded_len += 4;
}
start += 64;
run_length -= 64;
}
if (run_length)
{
*it++ = (VALUES_ARE_LONGS | (run_length - 1));
encoded_len++;
while (start < i)
{
int32_t value_val = values.arrayZ[start++];
*it++ = static_cast<char> (value_val >> 24);
*it++ = static_cast<char> (value_val >> 16);
*it++ = static_cast<char> (value_val >> 8);
*it++ = static_cast<char> (value_val & 0xFF);
encoded_len += 4;
}
}
return encoded_len;
}
template <typename T>
static bool decompile (const HBUINT8 *&p /* IN/OUT */,
hb_vector_t<T> &values /* IN/OUT */,
const HBUINT8 *end,
bool consume_all = false)
{
unsigned i = 0;
unsigned count = consume_all ? UINT_MAX : values.length;
if (consume_all)
values.alloc ((end - p) / 2);
while (i < count)
{
if (unlikely (p + 1 > end)) return consume_all;
unsigned control = *p++;
unsigned run_count = (control & VALUE_RUN_COUNT_MASK) + 1;
if (consume_all)
{
if (unlikely (!values.resize (values.length + run_count, false)))
return false;
}
unsigned stop = i + run_count;
if (unlikely (stop > count)) return false;
if ((control & VALUES_SIZE_MASK) == VALUES_ARE_ZEROS)
{
for (; i < stop; i++)
values.arrayZ[i] = 0;
}
else if ((control & VALUES_SIZE_MASK) == VALUES_ARE_WORDS)
{
if (unlikely (p + run_count * HBINT16::static_size > end)) return false;
for (; i < stop; i++)
{
values.arrayZ[i] = * (const HBINT16 *) p;
p += HBINT16::static_size;
}
}
else if ((control & VALUES_SIZE_MASK) == VALUES_ARE_LONGS)
{
if (unlikely (p + run_count * HBINT32::static_size > end)) return false;
for (; i < stop; i++)
{
values.arrayZ[i] = * (const HBINT32 *) p;
p += HBINT32::static_size;
}
}
else if ((control & VALUES_SIZE_MASK) == VALUES_ARE_BYTES)
{
if (unlikely (p + run_count > end)) return false;
for (; i < stop; i++)
{
values.arrayZ[i] = * (const HBINT8 *) p++;
}
}
}
return true;
}
struct iter_t : hb_iter_with_fallback_t<iter_t, int>
{
iter_t (const unsigned char *p_, unsigned len_)
: p (p_), end (p_ + len_)
{ if (ensure_run ()) read_value (); }
private:
const unsigned char *p;
const unsigned char * const end;
int current_value = 0;
signed run_count = 0;
unsigned width = 0;
bool ensure_run ()
{
if (likely (run_count > 0)) return true;
if (unlikely (p >= end))
{
run_count = 0;
current_value = 0;
return false;
}
unsigned control = *p++;
run_count = (control & VALUE_RUN_COUNT_MASK) + 1;
width = control & VALUES_SIZE_MASK;
switch (width)
{
case VALUES_ARE_ZEROS: width = 0; break;
case VALUES_ARE_BYTES: width = HBINT8::static_size; break;
case VALUES_ARE_WORDS: width = HBINT16::static_size; break;
case VALUES_ARE_LONGS: width = HBINT32::static_size; break;
default: assert (false);
}
if (unlikely (p + run_count * width > end))
{
run_count = 0;
current_value = 0;
return false;
}
return true;
}
void read_value ()
{
switch (width)
{
case 0: current_value = 0; break;
case 1: current_value = * (const HBINT8 *) p; break;
case 2: current_value = * (const HBINT16 *) p; break;
case 4: current_value = * (const HBINT32 *) p; break;
}
p += width;
}
public:
typedef int __item_t__;
__item_t__ __item__ () const
{ return current_value; }
bool __more__ () const { return run_count || p < end; }
void __next__ ()
{
run_count--;
if (unlikely (!ensure_run ()))
return;
read_value ();
}
void __forward__ (unsigned n)
{
if (unlikely (!ensure_run ()))
return;
while (n)
{
unsigned i = hb_min (n, (unsigned) run_count);
run_count -= i;
n -= i;
p += (i - 1) * width;
if (unlikely (!ensure_run ()))
return;
read_value ();
}
}
bool operator != (const iter_t& o) const
{ return p != o.p || run_count != o.run_count; }
iter_t __end__ () const
{
iter_t it (end, 0);
return it;
}
};
};
struct TupleList : CFF2Index
{
TupleValues::iter_t operator [] (unsigned i) const
{
auto bytes = CFF2Index::operator [] (i);
return TupleValues::iter_t (bytes.arrayZ, bytes.length);
}
};
} /* namespace OT */

View File

@ -68,247 +68,6 @@ using str_buff_t = hb_vector_t<unsigned char>;
using str_buff_vec_t = hb_vector_t<str_buff_t>;
using glyph_to_sid_map_t = hb_vector_t<code_pair_t>;
struct length_f_t
{
template <typename Iterable,
hb_requires (hb_is_iterable (Iterable))>
unsigned operator () (const Iterable &_) const { return hb_len (hb_iter (_)); }
unsigned operator () (unsigned _) const { return _; }
}
HB_FUNCOBJ (length_f);
/* CFF INDEX */
template <typename COUNT>
struct CFFIndex
{
unsigned int offset_array_size () const
{ return offSize * (count + 1); }
template <typename Iterable,
hb_requires (hb_is_iterable (Iterable))>
bool serialize (hb_serialize_context_t *c,
const Iterable &iterable,
const unsigned *p_data_size = nullptr,
unsigned min_off_size = 0)
{
TRACE_SERIALIZE (this);
unsigned data_size;
if (p_data_size)
data_size = *p_data_size;
else
total_size (iterable, &data_size);
auto it = hb_iter (iterable);
if (unlikely (!serialize_header (c, +it, data_size, min_off_size))) return_trace (false);
unsigned char *ret = c->allocate_size<unsigned char> (data_size, false);
if (unlikely (!ret)) return_trace (false);
for (const auto &_ : +it)
{
unsigned len = _.length;
if (!len)
continue;
if (len <= 1)
{
*ret++ = *_.arrayZ;
continue;
}
hb_memcpy (ret, _.arrayZ, len);
ret += len;
}
return_trace (true);
}
template <typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
bool serialize_header (hb_serialize_context_t *c,
Iterator it,
unsigned data_size,
unsigned min_off_size = 0)
{
TRACE_SERIALIZE (this);
unsigned off_size = (hb_bit_storage (data_size + 1) + 7) / 8;
off_size = hb_max(min_off_size, off_size);
/* serialize CFFIndex header */
if (unlikely (!c->extend_min (this))) return_trace (false);
this->count = hb_len (it);
if (!this->count) return_trace (true);
if (unlikely (!c->extend (this->offSize))) return_trace (false);
this->offSize = off_size;
if (unlikely (!c->allocate_size<HBUINT8> (off_size * (this->count + 1), false)))
return_trace (false);
/* serialize indices */
unsigned int offset = 1;
if (HB_OPTIMIZE_SIZE_VAL)
{
unsigned int i = 0;
for (const auto &_ : +it)
{
set_offset_at (i++, offset);
offset += length_f (_);
}
set_offset_at (i, offset);
}
else
switch (off_size)
{
case 1:
{
HBUINT8 *p = (HBUINT8 *) offsets;
for (const auto &_ : +it)
{
*p++ = offset;
offset += length_f (_);
}
*p = offset;
}
break;
case 2:
{
HBUINT16 *p = (HBUINT16 *) offsets;
for (const auto &_ : +it)
{
*p++ = offset;
offset += length_f (_);
}
*p = offset;
}
break;
case 3:
{
HBUINT24 *p = (HBUINT24 *) offsets;
for (const auto &_ : +it)
{
*p++ = offset;
offset += length_f (_);
}
*p = offset;
}
break;
case 4:
{
HBUINT32 *p = (HBUINT32 *) offsets;
for (const auto &_ : +it)
{
*p++ = offset;
offset += length_f (_);
}
*p = offset;
}
break;
default:
break;
}
assert (offset == data_size + 1);
return_trace (true);
}
template <typename Iterable,
hb_requires (hb_is_iterable (Iterable))>
static unsigned total_size (const Iterable &iterable, unsigned *data_size = nullptr, unsigned min_off_size = 0)
{
auto it = + hb_iter (iterable);
if (!it)
{
if (data_size) *data_size = 0;
return min_size;
}
unsigned total = 0;
for (const auto &_ : +it)
total += length_f (_);
if (data_size) *data_size = total;
unsigned off_size = (hb_bit_storage (total + 1) + 7) / 8;
off_size = hb_max(min_off_size, off_size);
return min_size + HBUINT8::static_size + (hb_len (it) + 1) * off_size + total;
}
void set_offset_at (unsigned int index, unsigned int offset)
{
assert (index <= count);
unsigned int size = offSize;
const HBUINT8 *p = offsets;
switch (size)
{
case 1: ((HBUINT8 *) p)[index] = offset; break;
case 2: ((HBUINT16 *) p)[index] = offset; break;
case 3: ((HBUINT24 *) p)[index] = offset; break;
case 4: ((HBUINT32 *) p)[index] = offset; break;
default: return;
}
}
private:
unsigned int offset_at (unsigned int index) const
{
assert (index <= count);
unsigned int size = offSize;
const HBUINT8 *p = offsets;
switch (size)
{
case 1: return ((HBUINT8 *) p)[index];
case 2: return ((HBUINT16 *) p)[index];
case 3: return ((HBUINT24 *) p)[index];
case 4: return ((HBUINT32 *) p)[index];
default: return 0;
}
}
const unsigned char *data_base () const
{ return (const unsigned char *) this + min_size + offSize.static_size - 1 + offset_array_size (); }
public:
hb_ubytes_t operator [] (unsigned int index) const
{
if (unlikely (index >= count)) return hb_ubytes_t ();
_hb_compiler_memory_r_barrier ();
unsigned offset0 = offset_at (index);
unsigned offset1 = offset_at (index + 1);
if (unlikely (offset1 < offset0 || offset1 > offset_at (count)))
return hb_ubytes_t ();
return hb_ubytes_t (data_base () + offset0, offset1 - offset0);
}
unsigned int get_size () const
{
if (count)
return min_size + offSize.static_size + offset_array_size () + (offset_at (count) - 1);
return min_size; /* empty CFFIndex contains count only */
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
hb_barrier () &&
(count == 0 || /* empty INDEX */
(count < count + 1u &&
hb_barrier () &&
c->check_struct (&offSize) && offSize >= 1 && offSize <= 4 &&
c->check_array (offsets, offSize, count + 1u) &&
c->check_array ((const HBUINT8*) data_base (), 1, offset_at (count))))));
}
public:
COUNT count; /* Number of object data. Note there are (count+1) offsets */
private:
HBUINT8 offSize; /* The byte size of each offset in the offsets array. */
HBUINT8 offsets[HB_VAR_ARRAY];
/* The array of (count + 1) offsets into objects array (1-base). */
/* HBUINT8 data[HB_VAR_ARRAY]; Object data */
public:
DEFINE_SIZE_MIN (COUNT::static_size);
};
/* Top Dict, Font Dict, Private Dict */
struct Dict : UnsizedByteStr
{

View File

@ -51,9 +51,6 @@ namespace CFF {
enum EncodingID { StandardEncoding = 0, ExpertEncoding = 1 };
enum CharsetID { ISOAdobeCharset = 0, ExpertCharset = 1, ExpertSubsetCharset = 2 };
typedef CFFIndex<HBUINT16> CFF1Index;
typedef CFFIndex<HBUINT16> CFF1Index;
typedef CFF1Index CFF1CharStrings;
typedef Subrs<HBUINT16> CFF1Subrs;
@ -1179,6 +1176,7 @@ struct cff1
if (unlikely (!font_interp.interpret (*font))) goto fail;
PRIVDICTVAL *priv = &privateDicts[i];
const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size);
if (unlikely (privDictStr == (const unsigned char *) &Null (UnsizedByteStr))) goto fail;
num_interp_env_t env2 (privDictStr);
dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env2);
priv->init ();
@ -1193,6 +1191,7 @@ struct cff1
PRIVDICTVAL *priv = &privateDicts[0];
const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size);
if (unlikely (privDictStr == (const unsigned char *) &Null (UnsizedByteStr))) goto fail;
num_interp_env_t env (privDictStr);
dict_interpreter_t<PRIVOPSET, PRIVDICTVAL> priv_interp (env);
priv->init ();

View File

@ -202,6 +202,11 @@ struct cff2_path_procs_path_t : path_procs_t<cff2_path_procs_path_t, cff2_cs_int
struct cff2_cs_opset_path_t : cff2_cs_opset_t<cff2_cs_opset_path_t, cff2_path_param_t, number_t, cff2_path_procs_path_t> {};
bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const
{
return get_path_at (font, glyph, draw_session, hb_array (font->coords, font->num_coords));
}
bool OT::cff2::accelerator_t::get_path_at (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session, hb_array_t<const int> coords) const
{
#ifdef HB_NO_OT_FONT_CFF
/* XXX Remove check when this code moves to .hh file. */
@ -212,7 +217,7 @@ bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, h
unsigned int fd = fdSelect->get_fd (glyph);
const hb_ubytes_t str = (*charStrings)[glyph];
cff2_cs_interp_env_t<number_t> env (str, *this, fd, font->coords, font->num_coords);
cff2_cs_interp_env_t<number_t> env (str, *this, fd, coords.arrayZ, coords.length);
cff2_cs_interpreter_t<cff2_cs_opset_path_t, cff2_path_param_t, number_t> interp (env);
cff2_path_param_t param (font, draw_session);
if (unlikely (!interp.interpret (param))) return false;

View File

@ -40,8 +40,6 @@ namespace CFF {
*/
#define HB_OT_TAG_CFF2 HB_TAG('C','F','F','2')
typedef CFFIndex<HBUINT32> CFF2Index;
typedef CFF2Index CFF2CharStrings;
typedef Subrs<HBUINT32> CFF2Subrs;
@ -460,6 +458,7 @@ struct cff2
if (unlikely (!font_interp.interpret (*font))) goto fail;
const hb_ubytes_t privDictStr = StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset, sc, font->privateDictInfo.size).as_ubytes (font->privateDictInfo.size);
if (unlikely (privDictStr == (const unsigned char *) &Null (UnsizedByteStr))) goto fail;
cff2_priv_dict_interp_env_t env2 (privDictStr);
dict_interpreter_t<PRIVOPSET, PRIVDICTVAL, cff2_priv_dict_interp_env_t> priv_interp (env2);
privateDicts[i].init ();
@ -521,6 +520,7 @@ struct cff2
hb_glyph_extents_t *extents) const;
HB_INTERNAL bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const;
HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const;
HB_INTERNAL bool get_path_at (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session, hb_array_t<const int> coords) const;
};
struct accelerator_subset_t : accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t>

View File

@ -96,6 +96,9 @@ HB_OT_CORE_TABLE (OT, avar)
HB_OT_CORE_TABLE (OT, cvar)
HB_OT_ACCELERATOR (OT, gvar)
HB_OT_CORE_TABLE (OT, MVAR)
#ifndef HB_NO_VAR_COMPOSITES
HB_OT_CORE_TABLE (OT, VARC)
#endif
#endif
/* Legacy kern. */

View File

@ -43,6 +43,7 @@
#include "hb-ot-hmtx-table.hh"
#include "hb-ot-post-table.hh"
#include "hb-ot-stat-table.hh" // Just so we compile it; unused otherwise.
#include "hb-ot-var-varc-table.hh"
#include "hb-ot-vorg-table.hh"
#include "OT/Color/CBDT/CBDT.hh"
#include "OT/Color/COLR/COLR.hh"
@ -523,6 +524,10 @@ hb_ot_draw_glyph (hb_font_t *font,
{ // Need draw_session to be destructed before emboldening.
hb_draw_session_t draw_session (embolden ? hb_outline_recording_pen_get_funcs () : draw_funcs,
embolden ? &outline : draw_data, font->slant_xy);
#ifndef HB_NO_VAR_COMPOSITES
if (!font->face->table.VARC->get_path (font, glyph, draw_session))
#endif
// Keep the following in synch with VARC::get_path_at()
if (!font->face->table.glyf->get_path (font, glyph, draw_session))
#ifndef HB_NO_CFF
if (!font->face->table.cff2->get_path (font, glyph, draw_session))
@ -562,6 +567,9 @@ hb_ot_paint_glyph (hb_font_t *font,
if (font->face->table.CBDT->paint_glyph (font, glyph, paint_funcs, paint_data)) return;
if (font->face->table.sbix->paint_glyph (font, glyph, paint_funcs, paint_data)) return;
#endif
#endif
#ifndef HB_NO_VAR_COMPOSITES
if (font->face->table.VARC->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return;
#endif
if (font->face->table.glyf->paint_glyph (font, glyph, paint_funcs, paint_data, foreground)) return;
#ifndef HB_NO_CFF

View File

@ -30,6 +30,7 @@
#include "hb-open-type.hh"
#include "hb-ot-maxp-table.hh"
#include "hb-ot-hhea-table.hh"
#include "hb-ot-os2-table.hh"
#include "hb-ot-var-hvar-table.hh"
#include "hb-ot-var-mvar-table.hh"
#include "hb-ot-metrics.hh"

View File

@ -2471,6 +2471,8 @@ struct VarRegionAxis
int peak = peakCoord.to_int ();
if (peak == 0 || coord == peak)
return 1.f;
else if (coord == 0) // Faster
return 0.f;
int start = startCoord.to_int (), end = endCoord.to_int ();
@ -2494,8 +2496,6 @@ struct VarRegionAxis
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
/* TODO Handle invalid start/peak/end configs, so we don't
* have to do that at runtime. */
}
bool serialize (hb_serialize_context_t *c) const
@ -2511,6 +2511,33 @@ struct VarRegionAxis
public:
DEFINE_SIZE_STATIC (6);
};
struct SparseVarRegionAxis
{
float evaluate (const int *coords, unsigned int coord_len) const
{
unsigned i = axisIndex;
int coord = i < coord_len ? coords[i] : 0;
return axis.evaluate (coord);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
bool serialize (hb_serialize_context_t *c) const
{
TRACE_SERIALIZE (this);
return_trace (c->embed (this));
}
public:
HBUINT16 axisIndex;
VarRegionAxis axis;
public:
DEFINE_SIZE_STATIC (8);
};
#define REGION_CACHE_ITEM_CACHE_INVALID 2.f
@ -2675,6 +2702,65 @@ struct VarRegionList
DEFINE_SIZE_ARRAY (4, axesZ);
};
struct SparseVariationRegion : Array16Of<SparseVarRegionAxis>
{
float evaluate (const int *coords, unsigned int coord_len) const
{
float v = 1.f;
unsigned int count = len;
for (unsigned int i = 0; i < count; i++)
{
float factor = arrayZ[i].evaluate (coords, coord_len);
if (factor == 0.f)
return 0.;
v *= factor;
}
return v;
}
};
struct SparseVarRegionList
{
using cache_t = float;
float evaluate (unsigned int region_index,
const int *coords, unsigned int coord_len,
cache_t *cache = nullptr) const
{
if (unlikely (region_index >= regions.len))
return 0.;
float *cached_value = nullptr;
if (cache)
{
cached_value = &(cache[region_index]);
if (likely (*cached_value != REGION_CACHE_ITEM_CACHE_INVALID))
return *cached_value;
}
const SparseVariationRegion &region = this+regions[region_index];
float v = region.evaluate (coords, coord_len);
if (cache)
*cached_value = v;
return v;
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (regions.sanitize (c, this));
}
public:
Array16Of<Offset32To<SparseVariationRegion>>
regions;
public:
DEFINE_SIZE_ARRAY (2, regions);
};
struct VarData
{
unsigned int get_item_count () const
@ -3036,6 +3122,61 @@ struct VarData
DEFINE_SIZE_ARRAY (6, regionIndices);
};
struct MultiVarData
{
unsigned int get_size () const
{ return min_size
- regionIndices.min_size + regionIndices.get_size ()
+ StructAfter<CFF2Index> (regionIndices).get_size ();
}
void get_delta (unsigned int inner,
const int *coords, unsigned int coord_count,
const SparseVarRegionList &regions,
hb_array_t<float> out,
SparseVarRegionList::cache_t *cache = nullptr) const
{
auto &deltaSets = StructAfter<decltype (deltaSetsX)> (regionIndices);
auto values_iter = deltaSets[inner];
unsigned regionCount = regionIndices.len;
unsigned count = out.length;
for (unsigned regionIndex = 0; regionIndex < regionCount; regionIndex++)
{
float scalar = regions.evaluate (regionIndices.arrayZ[regionIndex],
coords, coord_count,
cache);
if (scalar == 1.f)
for (unsigned i = 0; i < count; i++)
out.arrayZ[i] += *values_iter++;
else if (scalar)
for (unsigned i = 0; i < count; i++)
out.arrayZ[i] += *values_iter++ * scalar;
else
values_iter += count;
}
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (format.sanitize (c) &&
hb_barrier () &&
format == 1 &&
regionIndices.sanitize (c) &&
hb_barrier () &&
StructAfter<decltype (deltaSetsX)> (regionIndices).sanitize (c));
}
protected:
HBUINT8 format; // 1
Array16Of<HBUINT16> regionIndices;
TupleList deltaSetsX;
public:
DEFINE_SIZE_MIN (8);
};
struct ItemVariationStore
{
friend struct item_variations_t;
@ -3088,7 +3229,7 @@ struct ItemVariationStore
return get_delta (outer, inner, coords, coord_count, cache);
}
float get_delta (unsigned int index,
hb_array_t<int> coords,
hb_array_t<const int> coords,
VarRegionList::cache_t *cache = nullptr) const
{
return get_delta (index,
@ -3295,8 +3436,358 @@ struct ItemVariationStore
DEFINE_SIZE_ARRAY_SIZED (8, dataSets);
};
struct MultiItemVariationStore
{
using cache_t = SparseVarRegionList::cache_t;
cache_t *create_cache () const
{
#ifdef HB_NO_VAR
return nullptr;
#endif
auto &r = this+regions;
unsigned count = r.regions.len;
float *cache = (float *) hb_malloc (sizeof (float) * count);
if (unlikely (!cache)) return nullptr;
for (unsigned i = 0; i < count; i++)
cache[i] = REGION_CACHE_ITEM_CACHE_INVALID;
return cache;
}
static void destroy_cache (cache_t *cache) { hb_free (cache); }
private:
void get_delta (unsigned int outer, unsigned int inner,
const int *coords, unsigned int coord_count,
hb_array_t<float> out,
VarRegionList::cache_t *cache = nullptr) const
{
#ifdef HB_NO_VAR
return;
#endif
if (unlikely (outer >= dataSets.len))
return;
return (this+dataSets[outer]).get_delta (inner,
coords, coord_count,
this+regions,
out,
cache);
}
public:
void get_delta (unsigned int index,
const int *coords, unsigned int coord_count,
hb_array_t<float> out,
VarRegionList::cache_t *cache = nullptr) const
{
unsigned int outer = index >> 16;
unsigned int inner = index & 0xFFFF;
get_delta (outer, inner, coords, coord_count, out, cache);
}
void get_delta (unsigned int index,
hb_array_t<const int> coords,
hb_array_t<float> out,
VarRegionList::cache_t *cache = nullptr) const
{
return get_delta (index,
coords.arrayZ, coords.length,
out,
cache);
}
bool sanitize (hb_sanitize_context_t *c) const
{
#ifdef HB_NO_VAR
return true;
#endif
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
hb_barrier () &&
format == 1 &&
regions.sanitize (c, this) &&
dataSets.sanitize (c, this));
}
protected:
HBUINT16 format; // 1
Offset32To<SparseVarRegionList> regions;
Array16OfOffset32To<MultiVarData> dataSets;
public:
DEFINE_SIZE_ARRAY_SIZED (8, dataSets);
};
#undef REGION_CACHE_ITEM_CACHE_INVALID
template <typename MapCountT>
struct DeltaSetIndexMapFormat01
{
friend struct DeltaSetIndexMap;
unsigned get_size () const
{ return min_size + mapCount * get_width (); }
private:
DeltaSetIndexMapFormat01* copy (hb_serialize_context_t *c) const
{
TRACE_SERIALIZE (this);
return_trace (c->embed (this));
}
template <typename T>
bool serialize (hb_serialize_context_t *c, const T &plan)
{
unsigned int width = plan.get_width ();
unsigned int inner_bit_count = plan.get_inner_bit_count ();
const hb_array_t<const uint32_t> output_map = plan.get_output_map ();
TRACE_SERIALIZE (this);
if (unlikely (output_map.length && ((((inner_bit_count-1)&~0xF)!=0) || (((width-1)&~0x3)!=0))))
return_trace (false);
if (unlikely (!c->extend_min (this))) return_trace (false);
entryFormat = ((width-1)<<4)|(inner_bit_count-1);
mapCount = output_map.length;
HBUINT8 *p = c->allocate_size<HBUINT8> (width * output_map.length);
if (unlikely (!p)) return_trace (false);
for (unsigned int i = 0; i < output_map.length; i++)
{
unsigned int v = output_map.arrayZ[i];
if (v)
{
unsigned int outer = v >> 16;
unsigned int inner = v & 0xFFFF;
unsigned int u = (outer << inner_bit_count) | inner;
for (unsigned int w = width; w > 0;)
{
p[--w] = u;
u >>= 8;
}
}
p += width;
}
return_trace (true);
}
uint32_t map (unsigned int v) const /* Returns 16.16 outer.inner. */
{
/* If count is zero, pass value unchanged. This takes
* care of direct mapping for advance map. */
if (!mapCount)
return v;
if (v >= mapCount)
v = mapCount - 1;
unsigned int u = 0;
{ /* Fetch it. */
unsigned int w = get_width ();
const HBUINT8 *p = mapDataZ.arrayZ + w * v;
for (; w; w--)
u = (u << 8) + *p++;
}
{ /* Repack it. */
unsigned int n = get_inner_bit_count ();
unsigned int outer = u >> n;
unsigned int inner = u & ((1 << n) - 1);
u = (outer<<16) | inner;
}
return u;
}
unsigned get_map_count () const { return mapCount; }
unsigned get_width () const { return ((entryFormat >> 4) & 3) + 1; }
unsigned get_inner_bit_count () const { return (entryFormat & 0xF) + 1; }
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
hb_barrier () &&
c->check_range (mapDataZ.arrayZ,
mapCount,
get_width ()));
}
protected:
HBUINT8 format; /* Format identifier--format = 0 */
HBUINT8 entryFormat; /* A packed field that describes the compressed
* representation of delta-set indices. */
MapCountT mapCount; /* The number of mapping entries. */
UnsizedArrayOf<HBUINT8>
mapDataZ; /* The delta-set index mapping data. */
public:
DEFINE_SIZE_ARRAY (2+MapCountT::static_size, mapDataZ);
};
struct DeltaSetIndexMap
{
template <typename T>
bool serialize (hb_serialize_context_t *c, const T &plan)
{
TRACE_SERIALIZE (this);
unsigned length = plan.get_output_map ().length;
u.format = length <= 0xFFFF ? 0 : 1;
switch (u.format) {
case 0: return_trace (u.format0.serialize (c, plan));
case 1: return_trace (u.format1.serialize (c, plan));
default:return_trace (false);
}
}
uint32_t map (unsigned v) const
{
switch (u.format) {
case 0: return (u.format0.map (v));
case 1: return (u.format1.map (v));
default:return v;
}
}
unsigned get_map_count () const
{
switch (u.format) {
case 0: return u.format0.get_map_count ();
case 1: return u.format1.get_map_count ();
default:return 0;
}
}
unsigned get_width () const
{
switch (u.format) {
case 0: return u.format0.get_width ();
case 1: return u.format1.get_width ();
default:return 0;
}
}
unsigned get_inner_bit_count () const
{
switch (u.format) {
case 0: return u.format0.get_inner_bit_count ();
case 1: return u.format1.get_inner_bit_count ();
default:return 0;
}
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
hb_barrier ();
switch (u.format) {
case 0: return_trace (u.format0.sanitize (c));
case 1: return_trace (u.format1.sanitize (c));
default:return_trace (true);
}
}
DeltaSetIndexMap* copy (hb_serialize_context_t *c) const
{
TRACE_SERIALIZE (this);
switch (u.format) {
case 0: return_trace (reinterpret_cast<DeltaSetIndexMap *> (u.format0.copy (c)));
case 1: return_trace (reinterpret_cast<DeltaSetIndexMap *> (u.format1.copy (c)));
default:return_trace (nullptr);
}
}
protected:
union {
HBUINT8 format; /* Format identifier */
DeltaSetIndexMapFormat01<HBUINT16> format0;
DeltaSetIndexMapFormat01<HBUINT32> format1;
} u;
public:
DEFINE_SIZE_UNION (1, format);
};
struct ItemVarStoreInstancer
{
ItemVarStoreInstancer (const ItemVariationStore *varStore,
const DeltaSetIndexMap *varIdxMap,
hb_array_t<const int> coords,
VarRegionList::cache_t *cache = nullptr) :
varStore (varStore), varIdxMap (varIdxMap), coords (coords), cache (cache)
{
if (!varStore)
varStore = &Null(ItemVariationStore);
}
operator bool () const { return varStore && bool (coords); }
float operator[] (uint32_t varIdx) const
{ return (*this) (varIdx); }
float operator() (uint32_t varIdx, unsigned short offset = 0) const
{
if (varIdxMap)
varIdx = varIdxMap->map (VarIdx::add (varIdx, offset));
else
varIdx += offset;
return coords ? varStore->get_delta (varIdx, coords, cache) : 0.f;
}
const ItemVariationStore *varStore;
const DeltaSetIndexMap *varIdxMap;
hb_array_t<const int> coords;
VarRegionList::cache_t *cache;
};
struct MultiItemVarStoreInstancer
{
MultiItemVarStoreInstancer (const MultiItemVariationStore *varStore,
const DeltaSetIndexMap *varIdxMap,
hb_array_t<const int> coords,
SparseVarRegionList::cache_t *cache = nullptr) :
varStore (varStore), varIdxMap (varIdxMap), coords (coords), cache (cache)
{
if (!varStore)
varStore = &Null(MultiItemVariationStore);
}
operator bool () const { return varStore && bool (coords); }
float operator[] (uint32_t varIdx) const
{
float v = 0;
(*this) (hb_array (&v, 1), varIdx);
return v;
}
void operator() (hb_array_t<float> out, uint32_t varIdx, unsigned short offset = 0) const
{
if (coords)
{
if (varIdxMap)
varIdx = varIdxMap->map (VarIdx::add (varIdx, offset));
else
varIdx += offset;
varStore->get_delta (varIdx, coords, out, cache);
}
else
for (unsigned i = 0; i < out.length; i++)
out.arrayZ[i] = 0.f;
}
const MultiItemVariationStore *varStore;
const DeltaSetIndexMap *varIdxMap;
hb_array_t<const int> coords;
SparseVarRegionList::cache_t *cache;
};
/*
* Feature Variations
*/
@ -3308,7 +3799,16 @@ enum Cond_with_Var_flag_t
DROP_RECORD_WITH_VAR = 3,
};
struct ConditionFormat1
struct Condition;
template <typename Instancer>
static bool
_hb_recurse_condition_evaluate (const struct Condition &condition,
const int *coords,
unsigned int coord_len,
Instancer *instancer);
struct ConditionAxisRange
{
friend struct Condition;
@ -3401,7 +3901,9 @@ struct ConditionFormat1
return KEEP_RECORD_WITH_VAR;
}
bool evaluate (const int *coords, unsigned int coord_len) const
template <typename Instancer>
bool evaluate (const int *coords, unsigned int coord_len,
Instancer *instancer HB_UNUSED) const
{
int coord = axisIndex < coord_len ? coords[axisIndex] : 0;
return filterRangeMinValue.to_int () <= coord && coord <= filterRangeMaxValue.to_int ();
@ -3422,12 +3924,199 @@ struct ConditionFormat1
DEFINE_SIZE_STATIC (8);
};
struct ConditionValue
{
friend struct Condition;
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
// TODO(subset)
return_trace (false);
}
private:
template <typename Instancer>
bool evaluate (const int *coords, unsigned int coord_len,
Instancer *instancer) const
{
signed value = defaultValue;
value += (*instancer)[varIdx];
return value > 0;
}
bool subset (hb_subset_context_t *c,
hb_subset_layout_context_t *l,
bool insert_catch_all) const
{
TRACE_SUBSET (this);
// TODO(subset)
return_trace (false);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
protected:
HBUINT16 format; /* Format identifier--format = 2 */
HBINT16 defaultValue; /* Value at default instance. */
VarIdx varIdx; /* Variation index */
public:
DEFINE_SIZE_STATIC (8);
};
struct ConditionAnd
{
friend struct Condition;
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
// TODO(subset)
return_trace (false);
}
private:
template <typename Instancer>
bool evaluate (const int *coords, unsigned int coord_len,
Instancer *instancer) const
{
unsigned int count = conditions.len;
for (unsigned int i = 0; i < count; i++)
if (!_hb_recurse_condition_evaluate (this+conditions.arrayZ[i],
coords, coord_len,
instancer))
return false;
return true;
}
bool subset (hb_subset_context_t *c,
hb_subset_layout_context_t *l,
bool insert_catch_all) const
{
TRACE_SUBSET (this);
// TODO(subset)
return_trace (false);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (conditions.sanitize (c, this));
}
protected:
HBUINT16 format; /* Format identifier--format = 3 */
Array8OfOffset24To<struct Condition> conditions;
public:
DEFINE_SIZE_ARRAY (3, conditions);
};
struct ConditionOr
{
friend struct Condition;
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
// TODO(subset)
return_trace (false);
}
private:
template <typename Instancer>
bool evaluate (const int *coords, unsigned int coord_len,
Instancer *instancer) const
{
unsigned int count = conditions.len;
for (unsigned int i = 0; i < count; i++)
if (_hb_recurse_condition_evaluate (this+conditions.arrayZ[i],
coords, coord_len,
instancer))
return true;
return false;
}
bool subset (hb_subset_context_t *c,
hb_subset_layout_context_t *l,
bool insert_catch_all) const
{
TRACE_SUBSET (this);
// TODO(subset)
return_trace (false);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (conditions.sanitize (c, this));
}
protected:
HBUINT16 format; /* Format identifier--format = 4 */
Array8OfOffset24To<struct Condition> conditions;
public:
DEFINE_SIZE_ARRAY (3, conditions);
};
struct ConditionNegate
{
friend struct Condition;
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
// TODO(subset)
return_trace (false);
}
private:
template <typename Instancer>
bool evaluate (const int *coords, unsigned int coord_len,
Instancer *instancer) const
{
return !_hb_recurse_condition_evaluate (this+condition,
coords, coord_len,
instancer);
}
bool subset (hb_subset_context_t *c,
hb_subset_layout_context_t *l,
bool insert_catch_all) const
{
TRACE_SUBSET (this);
// TODO(subset)
return_trace (false);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (condition.sanitize (c, this));
}
protected:
HBUINT16 format; /* Format identifier--format = 5 */
Offset24To<struct Condition> condition;
public:
DEFINE_SIZE_STATIC (5);
};
struct Condition
{
bool evaluate (const int *coords, unsigned int coord_len) const
template <typename Instancer>
bool evaluate (const int *coords, unsigned int coord_len,
Instancer *instancer) const
{
switch (u.format) {
case 1: return u.format1.evaluate (coords, coord_len);
case 1: return u.format1.evaluate (coords, coord_len, instancer);
case 2: return u.format2.evaluate (coords, coord_len, instancer);
case 3: return u.format3.evaluate (coords, coord_len, instancer);
case 4: return u.format4.evaluate (coords, coord_len, instancer);
case 5: return u.format5.evaluate (coords, coord_len, instancer);
default:return false;
}
}
@ -3437,6 +4126,7 @@ struct Condition
{
switch (u.format) {
case 1: return u.format1.keep_with_variations (c, condition_map);
// TODO(subset)
default: c->apply = false; return KEEP_COND_WITH_VAR;
}
}
@ -3448,6 +4138,10 @@ struct Condition
TRACE_DISPATCH (this, u.format);
switch (u.format) {
case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
case 4: return_trace (c->dispatch (u.format4, std::forward<Ts> (ds)...));
case 5: return_trace (c->dispatch (u.format5, std::forward<Ts> (ds)...));
default:return_trace (c->default_return_value ());
}
}
@ -3459,6 +4153,10 @@ struct Condition
hb_barrier ();
switch (u.format) {
case 1: return_trace (u.format1.sanitize (c));
case 2: return_trace (u.format2.sanitize (c));
case 3: return_trace (u.format3.sanitize (c));
case 4: return_trace (u.format4.sanitize (c));
case 5: return_trace (u.format5.sanitize (c));
default:return_trace (true);
}
}
@ -3466,19 +4164,51 @@ struct Condition
protected:
union {
HBUINT16 format; /* Format identifier */
ConditionFormat1 format1;
ConditionAxisRange format1;
ConditionValue format2;
ConditionAnd format3;
ConditionOr format4;
ConditionNegate format5;
} u;
public:
DEFINE_SIZE_UNION (2, format);
};
template <typename Instancer>
bool
_hb_recurse_condition_evaluate (const struct Condition &condition,
const int *coords,
unsigned int coord_len,
Instancer *instancer)
{
return condition.evaluate (coords, coord_len, instancer);
}
struct ConditionList
{
const Condition& operator[] (unsigned i) const
{ return this+conditions[i]; }
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (conditions.sanitize (c, this));
}
protected:
Array32OfOffset32To<Condition> conditions;
public:
DEFINE_SIZE_ARRAY (4, conditions);
};
struct ConditionSet
{
bool evaluate (const int *coords, unsigned int coord_len) const
bool evaluate (const int *coords, unsigned int coord_len,
ItemVarStoreInstancer *instancer) const
{
unsigned int count = conditions.len;
for (unsigned int i = 0; i < count; i++)
if (!(this+conditions.arrayZ[i]).evaluate (coords, coord_len))
if (!(this+conditions.arrayZ[i]).evaluate (coords, coord_len, instancer))
return false;
return true;
}
@ -3812,13 +4542,14 @@ struct FeatureVariations
static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFFFFFu;
bool find_index (const int *coords, unsigned int coord_len,
unsigned int *index) const
unsigned int *index,
ItemVarStoreInstancer *instancer) const
{
unsigned int count = varRecords.len;
for (unsigned int i = 0; i < count; i++)
{
const FeatureVariationRecord &record = varRecords.arrayZ[i];
if ((this+record.conditions).evaluate (coords, coord_len))
if ((this+record.conditions).evaluate (coords, coord_len, instancer))
{
*index = i;
return true;
@ -4079,7 +4810,7 @@ struct VariationDevice
}
protected:
VarIdx varIdx;
VarIdx varIdx; /* Variation index */
HBUINT16 deltaFormat; /* Format identifier for this table: 0x0x8000 */
public:
DEFINE_SIZE_STATIC (6);

View File

@ -4674,13 +4674,14 @@ struct GSUBGPOS
{ return get_feature_list ().find_index (tag, index); }
bool find_variations_index (const int *coords, unsigned int num_coords,
unsigned int *index) const
unsigned int *index,
ItemVarStoreInstancer *instancer) const
{
#ifdef HB_NO_VAR
*index = FeatureVariations::NOT_FOUND_INDEX;
return false;
#endif
return get_feature_variations ().find_index (coords, num_coords, index);
return get_feature_variations ().find_index (coords, num_coords, index, instancer);
}
const Feature& get_feature_variation (unsigned int feature_index,
unsigned int variations_index) const

View File

@ -1443,8 +1443,12 @@ hb_ot_layout_table_find_feature_variations (hb_face_t *face,
unsigned int *variations_index /* out */)
{
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
const OT::GDEF &gdef = *face->table.GDEF->table;
return g.find_variations_index (coords, num_coords, variations_index);
auto instancer = OT::ItemVarStoreInstancer(&gdef.get_var_store(), nullptr,
hb_array (coords, num_coords));
return g.find_variations_index (coords, num_coords, variations_index, &instancer);
}

View File

@ -74,23 +74,6 @@
* Indic shaper may want to disallow recomposing of two matras.
*/
static bool
decompose_unicode (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t ab,
hb_codepoint_t *a,
hb_codepoint_t *b)
{
return (bool) c->unicode->decompose (ab, a, b);
}
static bool
compose_unicode (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t a,
hb_codepoint_t b,
hb_codepoint_t *ab)
{
return (bool) c->unicode->compose (a, b, ab);
}
static inline void
set_glyph (hb_glyph_info_t &info, hb_font_t *font)
@ -307,15 +290,14 @@ _hb_ot_shape_normalize (const hb_ot_shape_plan_t *plan,
mode = HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS;
}
const hb_ot_shape_normalize_context_t c = {
hb_ot_shape_normalize_context_t c = {
plan,
buffer,
font,
buffer->unicode,
buffer->not_found,
plan->shaper->decompose ? plan->shaper->decompose : decompose_unicode,
plan->shaper->compose ? plan->shaper->compose : compose_unicode
};
c.override_decompose_and_compose (plan->shaper->decompose, plan->shaper->compose);
bool always_short_circuit = mode == HB_OT_SHAPE_NORMALIZATION_MODE_NONE;
bool might_short_circuit = always_short_circuit ||

View File

@ -28,6 +28,7 @@
#define HB_OT_SHAPE_NORMALIZE_HH
#include "hb.hh"
#include "hb-unicode.hh"
/* buffer var allocations, used during the normalization process */
@ -52,6 +53,38 @@ HB_INTERNAL void _hb_ot_shape_normalize (const hb_ot_shape_plan_t *shaper,
struct hb_ot_shape_normalize_context_t
{
static bool
decompose_unicode (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t ab,
hb_codepoint_t *a,
hb_codepoint_t *b)
{
return (bool) c->unicode->decompose (ab, a, b);
}
static bool
compose_unicode (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t a,
hb_codepoint_t b,
hb_codepoint_t *ab)
{
return (bool) c->unicode->compose (a, b, ab);
}
void
override_decompose_and_compose (bool (*decompose) (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t ab,
hb_codepoint_t *a,
hb_codepoint_t *b),
bool (*compose) (const hb_ot_shape_normalize_context_t *c,
hb_codepoint_t a,
hb_codepoint_t b,
hb_codepoint_t *ab))
{
this->decompose = decompose ? decompose : decompose_unicode;
this->compose = compose ? compose : compose_unicode;
}
const hb_ot_shape_plan_t *plan;
hb_buffer_t *buffer;
hb_font_t *font;

View File

@ -85,7 +85,7 @@ hb_ot_shape_planner_t::hb_ot_shape_planner_t (hb_face_t *fac
, apply_morx (_hb_apply_morx (face, props))
#endif
{
shaper = hb_ot_shaper_categorize (this);
shaper = hb_ot_shaper_categorize (props.script, props.direction, map.chosen_script[0]);
script_zero_marks = shaper->zero_width_marks != HB_OT_SHAPE_ZERO_WIDTH_MARKS_NONE;
script_fallback_mark_positioning = shaper->fallback_position;

View File

@ -78,7 +78,7 @@ compose_hebrew (const hb_ot_shape_normalize_context_t *c,
return found;
#endif
if (!found && !c->plan->has_gpos_mark)
if (!found && (c->plan && !c->plan->has_gpos_mark))
{
/* Special-case Hebrew presentation forms that are excluded from
* standard normalization, but wanted for old fonts. */

View File

@ -174,9 +174,11 @@ HB_OT_SHAPERS_IMPLEMENT_SHAPERS
static inline const hb_ot_shaper_t *
hb_ot_shaper_categorize (const hb_ot_shape_planner_t *planner)
hb_ot_shaper_categorize (hb_script_t script,
hb_direction_t direction,
hb_tag_t gsub_script)
{
switch ((hb_tag_t) planner->props.script)
switch ((hb_tag_t) script)
{
default:
return &_hb_ot_shaper_default;
@ -192,9 +194,8 @@ hb_ot_shaper_categorize (const hb_ot_shape_planner_t *planner)
* This is because we do fallback shaping for Arabic script (and not others).
* But note that Arabic shaping is applicable only to horizontal layout; for
* vertical text, just use the generic shaper instead. */
if ((planner->map.chosen_script[0] != HB_OT_TAG_DEFAULT_SCRIPT ||
planner->props.script == HB_SCRIPT_ARABIC) &&
HB_DIRECTION_IS_HORIZONTAL(planner->props.direction))
if ((gsub_script != HB_OT_TAG_DEFAULT_SCRIPT || script == HB_SCRIPT_ARABIC) &&
HB_DIRECTION_IS_HORIZONTAL (direction))
return &_hb_ot_shaper_arabic;
else
return &_hb_ot_shaper_default;
@ -235,10 +236,10 @@ hb_ot_shaper_categorize (const hb_ot_shape_planner_t *planner)
* Otherwise, use the specific shaper.
*
* If it's indy3 tag, send to USE. */
if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T') ||
planner->map.chosen_script[0] == HB_TAG ('l','a','t','n'))
if (gsub_script == HB_TAG ('D','F','L','T') ||
gsub_script == HB_TAG ('l','a','t','n'))
return &_hb_ot_shaper_default;
else if ((planner->map.chosen_script[0] & 0x000000FF) == '3')
else if ((gsub_script & 0x000000FF) == '3')
return &_hb_ot_shaper_use;
else
return &_hb_ot_shaper_indic;
@ -254,9 +255,9 @@ hb_ot_shaper_categorize (const hb_ot_shape_planner_t *planner)
* If designer designed for 'mymr' tag, also send to default
* shaper. That's tag used from before Myanmar shaping spec
* was developed. The shaping spec uses 'mym2' tag. */
if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T') ||
planner->map.chosen_script[0] == HB_TAG ('l','a','t','n') ||
planner->map.chosen_script[0] == HB_TAG ('m','y','m','r'))
if (gsub_script == HB_TAG ('D','F','L','T') ||
gsub_script == HB_TAG ('l','a','t','n') ||
gsub_script == HB_TAG ('m','y','m','r'))
return &_hb_ot_shaper_default;
else
return &_hb_ot_shaper_myanmar;
@ -391,8 +392,8 @@ hb_ot_shaper_categorize (const hb_ot_shape_planner_t *planner)
* Otherwise, use the specific shaper.
* Note that for some simple scripts, there may not be *any*
* GSUB/GPOS needed, so there may be no scripts found! */
if (planner->map.chosen_script[0] == HB_TAG ('D','F','L','T') ||
planner->map.chosen_script[0] == HB_TAG ('l','a','t','n'))
if (gsub_script == HB_TAG ('D','F','L','T') ||
gsub_script == HB_TAG ('l','a','t','n'))
return &_hb_ot_shaper_default;
else
return &_hb_ot_shaper_use;

View File

@ -6,8 +6,8 @@
*
* on files with these headers:
*
* <meta name="updated_at" content="2023-09-30 01:21 AM" />
* File-Date: 2024-03-07
* <meta name="updated_at" content="2024-05-31 05:41 PM" />
* File-Date: 2024-05-16
*/
#ifndef HB_OT_TAG_TABLE_HH
@ -26,7 +26,7 @@ static const LangTag ot_languages2[] = {
{HB_TAG('a','y',' ',' '), HB_TAG('A','Y','M',' ')}, /* Aymara [macrolanguage] */
{HB_TAG('a','z',' ',' '), HB_TAG('A','Z','E',' ')}, /* Azerbaijani [macrolanguage] */
{HB_TAG('b','a',' ',' '), HB_TAG('B','S','H',' ')}, /* Bashkir */
{HB_TAG('b','e',' ',' '), HB_TAG('B','E','L',' ')}, /* Belarusian -> Belarussian */
{HB_TAG('b','e',' ',' '), HB_TAG('B','E','L',' ')}, /* Belarusian */
{HB_TAG('b','g',' ',' '), HB_TAG('B','G','R',' ')}, /* Bulgarian */
{HB_TAG('b','i',' ',' '), HB_TAG('B','I','S',' ')}, /* Bislama */
{HB_TAG('b','i',' ',' '), HB_TAG('C','P','P',' ')}, /* Bislama -> Creoles */
@ -64,6 +64,7 @@ static const LangTag ot_languages2[] = {
{HB_TAG('f','r',' ',' '), HB_TAG('F','R','A',' ')}, /* French */
{HB_TAG('f','y',' ',' '), HB_TAG('F','R','I',' ')}, /* Western Frisian -> Frisian */
{HB_TAG('g','a',' ',' '), HB_TAG('I','R','I',' ')}, /* Irish */
{HB_TAG('g','a',' ',' '), HB_TAG('I','R','T',' ')}, /* Irish -> Irish Traditional */
{HB_TAG('g','d',' ',' '), HB_TAG('G','A','E',' ')}, /* Scottish Gaelic */
{HB_TAG('g','l',' ',' '), HB_TAG('G','A','L',' ')}, /* Galician */
{HB_TAG('g','n',' ',' '), HB_TAG('G','U','A',' ')}, /* Guarani [macrolanguage] */
@ -132,7 +133,7 @@ static const LangTag ot_languages2[] = {
{HB_TAG('m','l',' ',' '), HB_TAG('M','A','L',' ')}, /* Malayalam -> Malayalam Traditional */
{HB_TAG('m','l',' ',' '), HB_TAG('M','L','R',' ')}, /* Malayalam -> Malayalam Reformed */
{HB_TAG('m','n',' ',' '), HB_TAG('M','N','G',' ')}, /* Mongolian [macrolanguage] */
{HB_TAG('m','o',' ',' '), HB_TAG('M','O','L',' ')}, /* Moldavian (retired code) -> Romanian (Moldova) */
{HB_TAG('m','o',' ',' '), HB_TAG('M','O','L',' ')}, /* Moldavian (retired code) */
{HB_TAG('m','o',' ',' '), HB_TAG('R','O','M',' ')}, /* Moldavian (retired code) -> Romanian */
{HB_TAG('m','r',' ',' '), HB_TAG('M','A','R',' ')}, /* Marathi */
{HB_TAG('m','s',' ',' '), HB_TAG('M','L','Y',' ')}, /* Malay [macrolanguage] */
@ -223,6 +224,7 @@ static const LangTag ot_languages2[] = {
static const LangTag ot_languages3[] = {
{HB_TAG('a','a','e',' '), HB_TAG('S','Q','I',' ')}, /* Arbëreshë Albanian -> Albanian */
{HB_TAG('a','a','o',' '), HB_TAG('A','R','A',' ')}, /* Algerian Saharan Arabic -> Arabic */
/*{HB_TAG('a','a','q',' '), HB_TAG('A','A','Q',' ')},*/ /* Eastern Abnaki -> Eastern Abenaki */
{HB_TAG('a','a','t',' '), HB_TAG('S','Q','I',' ')}, /* Arvanitika Albanian -> Albanian */
{HB_TAG('a','b','a',' '), HB_TAG_NONE }, /* Abé != Abaza */
{HB_TAG('a','b','h',' '), HB_TAG('A','R','A',' ')}, /* Tajiki Arabic -> Arabic */
@ -238,6 +240,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('a','c','r',' '), HB_TAG('M','Y','N',' ')}, /* Achi -> Mayan */
{HB_TAG('a','c','w',' '), HB_TAG('A','R','A',' ')}, /* Hijazi Arabic -> Arabic */
{HB_TAG('a','c','x',' '), HB_TAG('A','R','A',' ')}, /* Omani Arabic -> Arabic */
{HB_TAG('a','c','y',' '), HB_TAG('A','C','Y',' ')}, /* Cypriot Arabic */
{HB_TAG('a','c','y',' '), HB_TAG('A','R','A',' ')}, /* Cypriot Arabic -> Arabic */
{HB_TAG('a','d','a',' '), HB_TAG('D','N','G',' ')}, /* Adangme -> Dangme */
{HB_TAG('a','d','f',' '), HB_TAG('A','R','A',' ')}, /* Dhofari Arabic -> Arabic */
@ -288,6 +291,7 @@ static const LangTag ot_languages3[] = {
/*{HB_TAG('a','s','t',' '), HB_TAG('A','S','T',' ')},*/ /* Asturian */
/*{HB_TAG('a','t','h',' '), HB_TAG('A','T','H',' ')},*/ /* Athapascan [collection] -> Athapaskan */
{HB_TAG('a','t','j',' '), HB_TAG('R','C','R',' ')}, /* Atikamekw -> R-Cree */
/*{HB_TAG('a','t','s',' '), HB_TAG('A','T','S',' ')},*/ /* Gros Ventre (Atsina) */
{HB_TAG('a','t','v',' '), HB_TAG('A','L','T',' ')}, /* Northern Altai -> Altai */
{HB_TAG('a','u','j',' '), HB_TAG('B','B','R',' ')}, /* Awjilah -> Berber */
{HB_TAG('a','u','z',' '), HB_TAG('A','R','A',' ')}, /* Uzbeki Arabic -> Arabic */
@ -326,6 +330,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('b','c','l',' '), HB_TAG('B','I','K',' ')}, /* Central Bikol -> Bikol */
{HB_TAG('b','c','q',' '), HB_TAG('B','C','H',' ')}, /* Bench */
{HB_TAG('b','c','r',' '), HB_TAG('A','T','H',' ')}, /* Babine -> Athapaskan */
/*{HB_TAG('b','d','c',' '), HB_TAG('B','D','C',' ')},*/ /* Emberá-Baudó */
/*{HB_TAG('b','d','y',' '), HB_TAG('B','D','Y',' ')},*/ /* Bandjalang */
{HB_TAG('b','e','a',' '), HB_TAG('A','T','H',' ')}, /* Beaver -> Athapaskan */
{HB_TAG('b','e','b',' '), HB_TAG('B','T','I',' ')}, /* Bebele -> Beti */
@ -421,6 +426,8 @@ static const LangTag ot_languages3[] = {
{HB_TAG('c','a','f',' '), HB_TAG('A','T','H',' ')}, /* Southern Carrier -> Athapaskan */
{HB_TAG('c','a','k',' '), HB_TAG('C','A','K',' ')}, /* Kaqchikel */
{HB_TAG('c','a','k',' '), HB_TAG('M','Y','N',' ')}, /* Kaqchikel -> Mayan */
/*{HB_TAG('c','a','y',' '), HB_TAG('C','A','Y',' ')},*/ /* Cayuga */
/*{HB_TAG('c','b','g',' '), HB_TAG('C','B','G',' ')},*/ /* Chimila */
{HB_TAG('c','b','k',' '), HB_TAG('C','B','K',' ')}, /* Chavacano -> Zamboanga Chavacano */
{HB_TAG('c','b','k',' '), HB_TAG('C','P','P',' ')}, /* Chavacano -> Creoles */
{HB_TAG('c','b','l',' '), HB_TAG('Q','I','N',' ')}, /* Bualkhaw Chin -> Chin */
@ -467,6 +474,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('c','l','j',' '), HB_TAG('Q','I','N',' ')}, /* Laitu Chin -> Chin */
{HB_TAG('c','l','s',' '), HB_TAG('S','A','N',' ')}, /* Classical Sanskrit -> Sanskrit */
{HB_TAG('c','l','t',' '), HB_TAG('Q','I','N',' ')}, /* Lautu Chin -> Chin */
/*{HB_TAG('c','m','i',' '), HB_TAG('C','M','I',' ')},*/ /* Emberá-Chamí */
{HB_TAG('c','m','n',' '), HB_TAG('Z','H','S',' ')}, /* Mandarin Chinese -> Chinese, Simplified */
{HB_TAG('c','m','r',' '), HB_TAG('Q','I','N',' ')}, /* Mro-Khimi Chin -> Chin */
{HB_TAG('c','n','b',' '), HB_TAG('Q','I','N',' ')}, /* Chinbon Chin -> Chin */
@ -480,6 +488,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('c','n','w',' '), HB_TAG('Q','I','N',' ')}, /* Ngawn Chin -> Chin */
{HB_TAG('c','o','a',' '), HB_TAG('M','L','Y',' ')}, /* Cocos Islands Malay -> Malay */
{HB_TAG('c','o','b',' '), HB_TAG('M','Y','N',' ')}, /* Chicomuceltec -> Mayan */
/*{HB_TAG('c','o','o',' '), HB_TAG('C','O','O',' ')},*/ /* Comox */
/*{HB_TAG('c','o','p',' '), HB_TAG('C','O','P',' ')},*/ /* Coptic */
{HB_TAG('c','o','q',' '), HB_TAG('A','T','H',' ')}, /* Coquille -> Athapaskan */
{HB_TAG('c','p','a',' '), HB_TAG('C','C','H','N')}, /* Palantla Chinantec -> Chinantec */
@ -529,6 +538,7 @@ static const LangTag ot_languages3[] = {
/*{HB_TAG('c','t','g',' '), HB_TAG('C','T','G',' ')},*/ /* Chittagonian */
{HB_TAG('c','t','h',' '), HB_TAG('Q','I','N',' ')}, /* Thaiphum Chin -> Chin */
{HB_TAG('c','t','l',' '), HB_TAG('C','C','H','N')}, /* Tlacoatzintepec Chinantec -> Chinantec */
/*{HB_TAG('c','t','o',' '), HB_TAG('C','T','O',' ')},*/ /* Emberá-Catío */
{HB_TAG('c','t','s',' '), HB_TAG('B','I','K',' ')}, /* Northern Catanduanes Bikol -> Bikol */
/*{HB_TAG('c','t','t',' '), HB_TAG('C','T','T',' ')},*/ /* Wayanad Chetti */
{HB_TAG('c','t','u',' '), HB_TAG('M','Y','N',' ')}, /* Chol -> Mayan */
@ -552,7 +562,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('d','e','p',' '), HB_TAG('C','P','P',' ')}, /* Pidgin Delaware -> Creoles */
{HB_TAG('d','g','o',' '), HB_TAG('D','G','O',' ')}, /* Dogri (individual language) */
{HB_TAG('d','g','o',' '), HB_TAG('D','G','R',' ')}, /* Dogri (macrolanguage) */
{HB_TAG('d','g','r',' '), HB_TAG('A','T','H',' ')}, /* Dogrib -> Athapaskan */
{HB_TAG('d','g','r',' '), HB_TAG('A','T','H',' ')}, /* Tlicho -> Athapaskan */
{HB_TAG('d','h','d',' '), HB_TAG('M','A','W',' ')}, /* Dhundari -> Marwari */
/*{HB_TAG('d','h','g',' '), HB_TAG('D','H','G',' ')},*/ /* Dhangu */
{HB_TAG('d','h','v',' '), HB_TAG_NONE }, /* Dehu != Divehi (Dhivehi, Maldivian) (deprecated) */
@ -591,6 +601,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('e','k','y',' '), HB_TAG('K','R','N',' ')}, /* Eastern Kayah -> Karen */
{HB_TAG('e','m','k',' '), HB_TAG('E','M','K',' ')}, /* Eastern Maninkakan */
{HB_TAG('e','m','k',' '), HB_TAG('M','N','K',' ')}, /* Eastern Maninkakan -> Maninka */
/*{HB_TAG('e','m','p',' '), HB_TAG('E','M','P',' ')},*/ /* Northern Emberá */
{HB_TAG('e','m','y',' '), HB_TAG('M','Y','N',' ')}, /* Epigraphic Mayan -> Mayan */
{HB_TAG('e','n','b',' '), HB_TAG('K','A','L',' ')}, /* Markweeta -> Kalenjin */
{HB_TAG('e','n','f',' '), HB_TAG('F','N','E',' ')}, /* Forest Enets */
@ -655,6 +666,7 @@ static const LangTag ot_languages3[] = {
/*{HB_TAG('g','e','z',' '), HB_TAG('G','E','Z',' ')},*/ /* Geez */
{HB_TAG('g','g','o',' '), HB_TAG('G','O','N',' ')}, /* Southern Gondi (retired code) -> Gondi */
{HB_TAG('g','h','a',' '), HB_TAG('B','B','R',' ')}, /* Ghadamès -> Berber */
{HB_TAG('g','h','c',' '), HB_TAG('I','R','T',' ')}, /* Hiberno-Scottish Gaelic -> Irish Traditional */
{HB_TAG('g','h','k',' '), HB_TAG('K','R','N',' ')}, /* Geko Karen -> Karen */
{HB_TAG('g','h','o',' '), HB_TAG('B','B','R',' ')}, /* Ghomara -> Berber */
{HB_TAG('g','i','b',' '), HB_TAG('C','P','P',' ')}, /* Gibanawa -> Creoles */
@ -744,6 +756,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('h','s','n',' '), HB_TAG('Z','H','S',' ')}, /* Xiang Chinese -> Chinese, Simplified */
{HB_TAG('h','u','j',' '), HB_TAG('H','M','N',' ')}, /* Northern Guiyang Hmong -> Hmong */
{HB_TAG('h','u','p',' '), HB_TAG('A','T','H',' ')}, /* Hupa -> Athapaskan */
/*{HB_TAG('h','u','r',' '), HB_TAG('H','U','R',' ')},*/ /* Halkomelem */
{HB_TAG('h','u','s',' '), HB_TAG('M','Y','N',' ')}, /* Huastec -> Mayan */
{HB_TAG('h','w','c',' '), HB_TAG('C','P','P',' ')}, /* Hawai'i Creole English -> Creoles */
{HB_TAG('h','y','w',' '), HB_TAG('H','Y','E',' ')}, /* Western Armenian -> Armenian */
@ -781,6 +794,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('j','b','n',' '), HB_TAG('B','B','R',' ')}, /* Nafusi -> Berber */
/*{HB_TAG('j','b','o',' '), HB_TAG('J','B','O',' ')},*/ /* Lojban */
/*{HB_TAG('j','c','t',' '), HB_TAG('J','C','T',' ')},*/ /* Krymchak */
/*{HB_TAG('j','d','t',' '), HB_TAG('J','D','T',' ')},*/ /* Judeo-Tat */
{HB_TAG('j','g','o',' '), HB_TAG('B','M','L',' ')}, /* Ngomba -> Bamileke */
{HB_TAG('j','i','i',' '), HB_TAG_NONE }, /* Jiiddu != Yiddish */
{HB_TAG('j','k','m',' '), HB_TAG('K','R','N',' ')}, /* Mobwa Karen -> Karen */
@ -795,6 +809,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('k','a','m',' '), HB_TAG('K','M','B',' ')}, /* Kamba (Kenya) */
{HB_TAG('k','a','r',' '), HB_TAG('K','R','N',' ')}, /* Karen [collection] */
/*{HB_TAG('k','a','w',' '), HB_TAG('K','A','W',' ')},*/ /* Kawi (Old Javanese) */
/*{HB_TAG('k','b','c',' '), HB_TAG('K','B','C',' ')},*/ /* Kadiwéu */
{HB_TAG('k','b','d',' '), HB_TAG('K','A','B',' ')}, /* Kabardian */
{HB_TAG('k','b','y',' '), HB_TAG('K','N','R',' ')}, /* Manga Kanuri -> Kanuri */
{HB_TAG('k','c','a',' '), HB_TAG('K','H','K',' ')}, /* Khanty -> Khanty-Kazim */
@ -830,6 +845,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('k','j','b',' '), HB_TAG('M','Y','N',' ')}, /* Q'anjob'al -> Mayan */
/*{HB_TAG('k','j','d',' '), HB_TAG('K','J','D',' ')},*/ /* Southern Kiwai */
{HB_TAG('k','j','h',' '), HB_TAG('K','H','A',' ')}, /* Khakas -> Khakass */
/*{HB_TAG('k','j','j',' '), HB_TAG('K','J','J',' ')},*/ /* Khinalugh -> Khinalug */
{HB_TAG('k','j','p',' '), HB_TAG('K','J','P',' ')}, /* Pwo Eastern Karen -> Eastern Pwo Karen */
{HB_TAG('k','j','p',' '), HB_TAG('K','R','N',' ')}, /* Pwo Eastern Karen -> Karen */
{HB_TAG('k','j','t',' '), HB_TAG('K','R','N',' ')}, /* Phrae Pwo Karen -> Karen */
@ -931,6 +947,7 @@ static const LangTag ot_languages3[] = {
/*{HB_TAG('l','i','j',' '), HB_TAG('L','I','J',' ')},*/ /* Ligurian */
{HB_TAG('l','i','r',' '), HB_TAG('C','P','P',' ')}, /* Liberian English -> Creoles */
/*{HB_TAG('l','i','s',' '), HB_TAG('L','I','S',' ')},*/ /* Lisu */
/*{HB_TAG('l','i','v',' '), HB_TAG('L','I','V',' ')},*/ /* Liv */
{HB_TAG('l','i','w',' '), HB_TAG('M','L','Y',' ')}, /* Col -> Malay */
{HB_TAG('l','i','y',' '), HB_TAG('B','A','D','0')}, /* Banda-Bambari -> Banda */
/*{HB_TAG('l','j','p',' '), HB_TAG('L','J','P',' ')},*/ /* Lampung Api -> Lampung */
@ -996,12 +1013,14 @@ static const LangTag ot_languages3[] = {
{HB_TAG('m','e','n',' '), HB_TAG('M','D','E',' ')}, /* Mende (Sierra Leone) */
{HB_TAG('m','e','o',' '), HB_TAG('M','L','Y',' ')}, /* Kedah Malay -> Malay */
/*{HB_TAG('m','e','r',' '), HB_TAG('M','E','R',' ')},*/ /* Meru */
/*{HB_TAG('m','e','v',' '), HB_TAG('M','E','V',' ')},*/ /* Mano */
{HB_TAG('m','f','a',' '), HB_TAG('M','F','A',' ')}, /* Pattani Malay */
{HB_TAG('m','f','a',' '), HB_TAG('M','L','Y',' ')}, /* Pattani Malay -> Malay */
{HB_TAG('m','f','b',' '), HB_TAG('M','L','Y',' ')}, /* Bangka -> Malay */
{HB_TAG('m','f','e',' '), HB_TAG('M','F','E',' ')}, /* Morisyen */
{HB_TAG('m','f','e',' '), HB_TAG('C','P','P',' ')}, /* Morisyen -> Creoles */
{HB_TAG('m','f','p',' '), HB_TAG('C','P','P',' ')}, /* Makassar Malay -> Creoles */
{HB_TAG('m','g','a',' '), HB_TAG('S','G','A',' ')}, /* Middle Irish (900-1200) -> Old Irish */
{HB_TAG('m','h','c',' '), HB_TAG('M','Y','N',' ')}, /* Mocho -> Mayan */
{HB_TAG('m','h','r',' '), HB_TAG('L','M','A',' ')}, /* Eastern Mari -> Low Mari */
{HB_TAG('m','h','v',' '), HB_TAG('A','R','K',' ')}, /* Arakanese (retired code) -> Rakhine */
@ -1154,6 +1173,8 @@ static const LangTag ot_languages3[] = {
{HB_TAG('o','k','i',' '), HB_TAG('K','A','L',' ')}, /* Okiek -> Kalenjin */
{HB_TAG('o','k','m',' '), HB_TAG('K','O','H',' ')}, /* Middle Korean (10th-16th cent.) -> Korean Old Hangul */
{HB_TAG('o','k','r',' '), HB_TAG('I','J','O',' ')}, /* Kirike -> Ijo */
/*{HB_TAG('o','n','e',' '), HB_TAG('O','N','E',' ')},*/ /* Oneida */
/*{HB_TAG('o','n','o',' '), HB_TAG('O','N','O',' ')},*/ /* Onondaga */
{HB_TAG('o','n','x',' '), HB_TAG('C','P','P',' ')}, /* Onin Based Pidgin -> Creoles */
{HB_TAG('o','o','r',' '), HB_TAG('C','P','P',' ')}, /* Oorlams -> Creoles */
{HB_TAG('o','r','c',' '), HB_TAG('O','R','O',' ')}, /* Orma -> Oromo */
@ -1194,7 +1215,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('p','i','s',' '), HB_TAG('C','P','P',' ')}, /* Pijin -> Creoles */
{HB_TAG('p','k','h',' '), HB_TAG('Q','I','N',' ')}, /* Pankhu -> Chin */
{HB_TAG('p','k','o',' '), HB_TAG('K','A','L',' ')}, /* Pökoot -> Kalenjin */
{HB_TAG('p','l','g',' '), HB_TAG_NONE }, /* Pilagá != Palaung */
{HB_TAG('p','l','g',' '), HB_TAG('P','L','G','0')}, /* Pilagá */
{HB_TAG('p','l','k',' '), HB_TAG_NONE }, /* Kohistani Shina != Polish */
{HB_TAG('p','l','l',' '), HB_TAG('P','L','G',' ')}, /* Shwe Palaung -> Palaung */
{HB_TAG('p','l','n',' '), HB_TAG('C','P','P',' ')}, /* Palenquero -> Creoles */
@ -1354,6 +1375,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('s','d','h',' '), HB_TAG('K','U','R',' ')}, /* Southern Kurdish -> Kurdish */
{HB_TAG('s','d','n',' '), HB_TAG('S','R','D',' ')}, /* Gallurese Sardinian -> Sardinian */
{HB_TAG('s','d','s',' '), HB_TAG('B','B','R',' ')}, /* Sened -> Berber */
/*{HB_TAG('s','e','e',' '), HB_TAG('S','E','E',' ')},*/ /* Seneca */
{HB_TAG('s','e','h',' '), HB_TAG('S','N','A',' ')}, /* Sena */
{HB_TAG('s','e','k',' '), HB_TAG('A','T','H',' ')}, /* Sekani -> Athapaskan */
/*{HB_TAG('s','e','l',' '), HB_TAG('S','E','L',' ')},*/ /* Selkup */
@ -1375,6 +1397,7 @@ static const LangTag ot_languages3[] = {
/*{HB_TAG('s','i','d',' '), HB_TAG('S','I','D',' ')},*/ /* Sidamo */
{HB_TAG('s','i','g',' '), HB_TAG_NONE }, /* Paasaal != Silte Gurage */
{HB_TAG('s','i','z',' '), HB_TAG('B','B','R',' ')}, /* Siwi -> Berber */
/*{HB_TAG('s','j','a',' '), HB_TAG('S','J','A',' ')},*/ /* Epena */
{HB_TAG('s','j','d',' '), HB_TAG('K','S','M',' ')}, /* Kildin Sami */
{HB_TAG('s','j','o',' '), HB_TAG('S','I','B',' ')}, /* Xibe -> Sibe */
{HB_TAG('s','j','s',' '), HB_TAG('B','B','R',' ')}, /* Senhaja De Srair -> Berber */
@ -1411,6 +1434,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('s','s','m',' '), HB_TAG_NONE }, /* Semnam != Southern Sami */
{HB_TAG('s','t','a',' '), HB_TAG('C','P','P',' ')}, /* Settla -> Creoles */
/*{HB_TAG('s','t','q',' '), HB_TAG('S','T','Q',' ')},*/ /* Saterfriesisch -> Saterland Frisian */
/*{HB_TAG('s','t','r',' '), HB_TAG('S','T','R',' ')},*/ /* Straits Salish */
{HB_TAG('s','t','v',' '), HB_TAG('S','I','G',' ')}, /* Silt'e -> Silte Gurage */
/*{HB_TAG('s','u','k',' '), HB_TAG('S','U','K',' ')},*/ /* Sukuma */
{HB_TAG('s','u','q',' '), HB_TAG('S','U','R',' ')}, /* Suri */
@ -1432,6 +1456,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('t','a','a',' '), HB_TAG('A','T','H',' ')}, /* Lower Tanana -> Athapaskan */
/*{HB_TAG('t','a','b',' '), HB_TAG('T','A','B',' ')},*/ /* Tabassaran -> Tabasaran */
{HB_TAG('t','a','j',' '), HB_TAG_NONE }, /* Eastern Tamang != Tajiki */
{HB_TAG('t','a','q',' '), HB_TAG('T','A','Q',' ')}, /* Tamasheq */
{HB_TAG('t','a','q',' '), HB_TAG('T','M','H',' ')}, /* Tamasheq -> Tamashek */
{HB_TAG('t','a','q',' '), HB_TAG('B','B','R',' ')}, /* Tamasheq -> Berber */
{HB_TAG('t','a','s',' '), HB_TAG('C','P','P',' ')}, /* Tay Boi -> Creoles */
@ -1443,6 +1468,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('t','c','s',' '), HB_TAG('C','P','P',' ')}, /* Torres Strait Creole -> Creoles */
{HB_TAG('t','c','y',' '), HB_TAG('T','U','L',' ')}, /* Tulu */
{HB_TAG('t','c','z',' '), HB_TAG('Q','I','N',' ')}, /* Thado Chin -> Chin */
/*{HB_TAG('t','d','c',' '), HB_TAG('T','D','C',' ')},*/ /* Emberá-Tadó */
/*{HB_TAG('t','d','d',' '), HB_TAG('T','D','D',' ')},*/ /* Tai Nüa -> Dehong Dai */
{HB_TAG('t','d','x',' '), HB_TAG('M','L','G',' ')}, /* Tandroy-Mahafaly Malagasy -> Malagasy */
{HB_TAG('t','e','c',' '), HB_TAG('K','A','L',' ')}, /* Terik -> Kalenjin */
@ -1456,9 +1482,12 @@ static const LangTag ot_languages3[] = {
{HB_TAG('t','g','r',' '), HB_TAG_NONE }, /* Tareng != Tigre */
{HB_TAG('t','g','x',' '), HB_TAG('A','T','H',' ')}, /* Tagish -> Athapaskan */
{HB_TAG('t','g','y',' '), HB_TAG_NONE }, /* Togoyo != Tigrinya */
/*{HB_TAG('t','h','p',' '), HB_TAG('T','H','P',' ')},*/ /* Thompson */
{HB_TAG('t','h','t',' '), HB_TAG('A','T','H',' ')}, /* Tahltan -> Athapaskan */
{HB_TAG('t','h','v',' '), HB_TAG('T','H','V',' ')}, /* Tahaggart Tamahaq */
{HB_TAG('t','h','v',' '), HB_TAG('T','M','H',' ')}, /* Tahaggart Tamahaq -> Tamashek */
{HB_TAG('t','h','v',' '), HB_TAG('B','B','R',' ')}, /* Tahaggart Tamahaq -> Berber */
{HB_TAG('t','h','z',' '), HB_TAG('T','H','Z',' ')}, /* Tayart Tamajeq */
{HB_TAG('t','h','z',' '), HB_TAG('T','M','H',' ')}, /* Tayart Tamajeq -> Tamashek */
{HB_TAG('t','h','z',' '), HB_TAG('B','B','R',' ')}, /* Tayart Tamajeq -> Berber */
{HB_TAG('t','i','a',' '), HB_TAG('B','B','R',' ')}, /* Tidikelt Tamazight -> Berber */
@ -1469,6 +1498,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('t','k','g',' '), HB_TAG('M','L','G',' ')}, /* Tesaka Malagasy -> Malagasy */
{HB_TAG('t','k','m',' '), HB_TAG_NONE }, /* Takelma != Turkmen */
/*{HB_TAG('t','l','i',' '), HB_TAG('T','L','I',' ')},*/ /* Tlingit */
/*{HB_TAG('t','l','y',' '), HB_TAG('T','L','Y',' ')},*/ /* Talysh */
{HB_TAG('t','m','g',' '), HB_TAG('C','P','P',' ')}, /* Ternateño -> Creoles */
{HB_TAG('t','m','h',' '), HB_TAG('T','M','H',' ')}, /* Tamashek [macrolanguage] */
{HB_TAG('t','m','h',' '), HB_TAG('B','B','R',' ')}, /* Tamashek [macrolanguage] -> Berber */
@ -1494,11 +1524,13 @@ static const LangTag ot_languages3[] = {
/*{HB_TAG('t','s','j',' '), HB_TAG('T','S','J',' ')},*/ /* Tshangla */
{HB_TAG('t','t','c',' '), HB_TAG('M','Y','N',' ')}, /* Tektiteko -> Mayan */
{HB_TAG('t','t','m',' '), HB_TAG('A','T','H',' ')}, /* Northern Tutchone -> Athapaskan */
{HB_TAG('t','t','q',' '), HB_TAG('T','T','Q',' ')}, /* Tawallammat Tamajaq */
{HB_TAG('t','t','q',' '), HB_TAG('T','M','H',' ')}, /* Tawallammat Tamajaq -> Tamashek */
{HB_TAG('t','t','q',' '), HB_TAG('B','B','R',' ')}, /* Tawallammat Tamajaq -> Berber */
{HB_TAG('t','u','a',' '), HB_TAG_NONE }, /* Wiarumus != Turoyo Aramaic */
{HB_TAG('t','u','l',' '), HB_TAG_NONE }, /* Tula != Tulu */
/*{HB_TAG('t','u','m',' '), HB_TAG('T','U','M',' ')},*/ /* Tumbuka */
/*{HB_TAG('t','u','s',' '), HB_TAG('T','U','S',' ')},*/ /* Tuscarora */
{HB_TAG('t','u','u',' '), HB_TAG('A','T','H',' ')}, /* Tututni -> Athapaskan */
{HB_TAG('t','u','v',' '), HB_TAG_NONE }, /* Turkana != Tuvin */
{HB_TAG('t','u','y',' '), HB_TAG('K','A','L',' ')}, /* Tugen -> Kalenjin */
@ -1515,6 +1547,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('t','z','o',' '), HB_TAG('T','Z','O',' ')}, /* Tzotzil */
{HB_TAG('t','z','o',' '), HB_TAG('M','Y','N',' ')}, /* Tzotzil -> Mayan */
{HB_TAG('u','b','l',' '), HB_TAG('B','I','K',' ')}, /* Buhi'non Bikol -> Bikol */
/*{HB_TAG('u','d','i',' '), HB_TAG('U','D','I',' ')},*/ /* Udi */
/*{HB_TAG('u','d','m',' '), HB_TAG('U','D','M',' ')},*/ /* Udmurt */
{HB_TAG('u','k','i',' '), HB_TAG('K','U','I',' ')}, /* Kui (India) */
{HB_TAG('u','l','n',' '), HB_TAG('C','P','P',' ')}, /* Unserdeutsch -> Creoles */
@ -1533,14 +1566,17 @@ static const LangTag ot_languages3[] = {
{HB_TAG('v','k','t',' '), HB_TAG('M','L','Y',' ')}, /* Tenggarong Kutai Malay -> Malay */
{HB_TAG('v','l','s',' '), HB_TAG('F','L','E',' ')}, /* Vlaams -> Dutch (Flemish) */
{HB_TAG('v','m','w',' '), HB_TAG('M','A','K',' ')}, /* Makhuwa */
/*{HB_TAG('v','r','o',' '), HB_TAG('V','R','O',' ')},*/ /* Võro */
{HB_TAG('v','r','o',' '), HB_TAG('V','R','O',' ')}, /* Võro */
{HB_TAG('v','r','o',' '), HB_TAG('E','T','I',' ')}, /* Võro -> Estonian */
{HB_TAG('v','s','n',' '), HB_TAG('S','A','N',' ')}, /* Vedic Sanskrit -> Sanskrit */
{HB_TAG('w','a','g',' '), HB_TAG_NONE }, /* Wa'ema != Wagdi */
/*{HB_TAG('w','a','r',' '), HB_TAG('W','A','R',' ')},*/ /* Waray (Philippines) -> Waray-Waray */
/*{HB_TAG('w','b','l',' '), HB_TAG('W','B','L',' ')},*/ /* Wakhi */
{HB_TAG('w','b','m',' '), HB_TAG('W','A',' ',' ')}, /* Wa */
{HB_TAG('w','b','r',' '), HB_TAG('W','A','G',' ')}, /* Wagdi */
{HB_TAG('w','b','r',' '), HB_TAG('R','A','J',' ')}, /* Wagdi -> Rajasthani */
/*{HB_TAG('w','c','i',' '), HB_TAG('W','C','I',' ')},*/ /* Waci Gbe */
/*{HB_TAG('w','d','t',' '), HB_TAG('W','D','T',' ')},*/ /* Wendat */
{HB_TAG('w','e','a',' '), HB_TAG('K','R','N',' ')}, /* Wewaw -> Karen */
{HB_TAG('w','e','s',' '), HB_TAG('C','P','P',' ')}, /* Cameroon Pidgin -> Creoles */
{HB_TAG('w','e','u',' '), HB_TAG('Q','I','N',' ')}, /* Rawngtu Chin -> Chin */
@ -1552,6 +1588,9 @@ static const LangTag ot_languages3[] = {
{HB_TAG('w','s','g',' '), HB_TAG('G','O','N',' ')}, /* Adilabad Gondi -> Gondi */
/*{HB_TAG('w','t','m',' '), HB_TAG('W','T','M',' ')},*/ /* Mewati */
{HB_TAG('w','u','u',' '), HB_TAG('Z','H','S',' ')}, /* Wu Chinese -> Chinese, Simplified */
{HB_TAG('w','y','a',' '), HB_TAG('W','D','T',' ')}, /* Wyandot (retired code) -> Wendat */
{HB_TAG('w','y','a',' '), HB_TAG('W','Y','N',' ')}, /* Wyandot (retired code) */
/*{HB_TAG('w','y','n',' '), HB_TAG('W','Y','N',' ')},*/ /* Wyandot */
{HB_TAG('x','a','l',' '), HB_TAG('K','L','M',' ')}, /* Kalmyk */
{HB_TAG('x','a','l',' '), HB_TAG('T','O','D',' ')}, /* Kalmyk -> Todo */
{HB_TAG('x','a','n',' '), HB_TAG('S','E','K',' ')}, /* Xamtanga -> Sekota */
@ -1593,6 +1632,7 @@ static const LangTag ot_languages3[] = {
{HB_TAG('y','o','s',' '), HB_TAG('Q','I','N',' ')}, /* Yos (retired code) -> Chin */
{HB_TAG('y','u','a',' '), HB_TAG('M','Y','N',' ')}, /* Yucateco -> Mayan */
{HB_TAG('y','u','e',' '), HB_TAG('Z','H','H',' ')}, /* Yue Chinese -> Chinese, Traditional, Hong Kong SAR */
/*{HB_TAG('y','u','f',' '), HB_TAG('Y','U','F',' ')},*/ /* Havasupai-Walapai-Yavapai */
/*{HB_TAG('y','w','q',' '), HB_TAG('Y','W','Q',' ')},*/ /* Wuding-Luquan Yi */
{HB_TAG('z','c','h',' '), HB_TAG('Z','H','A',' ')}, /* Central Hongshuihe Zhuang -> Zhuang */
{HB_TAG('z','d','j',' '), HB_TAG('C','M','R',' ')}, /* Ngazidja Comorian -> Comorian */
@ -2645,7 +2685,7 @@ out:
/* Romanian; Moldova */
unsigned int i;
hb_tag_t possible_tags[] = {
HB_TAG('M','O','L',' '), /* Romanian (Moldova) */
HB_TAG('M','O','L',' '), /* Moldavian */
HB_TAG('R','O','M',' '), /* Romanian */
};
for (i = 0; i < 2 && i < *count; i++)
@ -2872,7 +2912,7 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
case HB_TAG('I','P','P','H'): /* Phonetic transcription—IPA conventions */
return hb_language_from_string ("und-fonipa", -1); /* Undetermined; International Phonetic Alphabet */
case HB_TAG('I','R','T',' '): /* Irish Traditional */
return hb_language_from_string ("ga-Latg", -1); /* Irish; Latin (Gaelic variant) */
return hb_language_from_string ("ghc", -1); /* Hiberno-Scottish Gaelic */
case HB_TAG('J','I','I',' '): /* Yiddish */
return hb_language_from_string ("yi", -1); /* Yiddish [macrolanguage] */
case HB_TAG('K','A','L',' '): /* Kalenjin */
@ -2899,7 +2939,7 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
return hb_language_from_string ("ms", -1); /* Malay [macrolanguage] */
case HB_TAG('M','N','K',' '): /* Maninka */
return hb_language_from_string ("man", -1); /* Mandingo [macrolanguage] */
case HB_TAG('M','O','L',' '): /* Romanian (Moldova) */
case HB_TAG('M','O','L',' '): /* Moldavian */
return hb_language_from_string ("ro-MD", -1); /* Romanian; Moldova */
case HB_TAG('M','O','N','T'): /* Thailand Mon */
return hb_language_from_string ("mnw-TH", -1); /* Mon; Thailand */
@ -2927,6 +2967,8 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
return hb_language_from_string ("ro", -1); /* Romanian */
case HB_TAG('R','O','Y',' '): /* Romany */
return hb_language_from_string ("rom", -1); /* Romany [macrolanguage] */
case HB_TAG('S','G','A',' '): /* Old Irish */
return hb_language_from_string ("sga", -1); /* Old Irish (to 900) */
case HB_TAG('S','R','B',' '): /* Serbian */
return hb_language_from_string ("sr", -1); /* Serbian */
case HB_TAG('S','X','T',' '): /* Sutu */
@ -2943,6 +2985,10 @@ hb_ot_ambiguous_tag_to_language (hb_tag_t tag)
return hb_language_from_string ("tmh", -1); /* Tamashek [macrolanguage] */
case HB_TAG('T','O','D',' '): /* Todo */
return hb_language_from_string ("xwo", -1); /* Written Oirat */
case HB_TAG('W','D','T',' '): /* Wendat */
return hb_language_from_string ("wdt", -1); /* Wendat */
case HB_TAG('W','Y','N',' '): /* Wyandot */
return hb_language_from_string ("wyn", -1); /* Wyandot */
case HB_TAG('Z','H','H',' '): /* Chinese, Traditional, Hong Kong SAR */
return hb_language_from_string ("zh-HK", -1); /* Chinese [macrolanguage]; Hong Kong */
case HB_TAG('Z','H','S',' '): /* Chinese, Simplified */

View File

@ -33,213 +33,6 @@
namespace OT {
template <typename MapCountT>
struct DeltaSetIndexMapFormat01
{
friend struct DeltaSetIndexMap;
unsigned get_size () const
{ return min_size + mapCount * get_width (); }
private:
DeltaSetIndexMapFormat01* copy (hb_serialize_context_t *c) const
{
TRACE_SERIALIZE (this);
return_trace (c->embed (this));
}
template <typename T>
bool serialize (hb_serialize_context_t *c, const T &plan)
{
unsigned int width = plan.get_width ();
unsigned int inner_bit_count = plan.get_inner_bit_count ();
const hb_array_t<const uint32_t> output_map = plan.get_output_map ();
TRACE_SERIALIZE (this);
if (unlikely (output_map.length && ((((inner_bit_count-1)&~0xF)!=0) || (((width-1)&~0x3)!=0))))
return_trace (false);
if (unlikely (!c->extend_min (this))) return_trace (false);
entryFormat = ((width-1)<<4)|(inner_bit_count-1);
mapCount = output_map.length;
HBUINT8 *p = c->allocate_size<HBUINT8> (width * output_map.length);
if (unlikely (!p)) return_trace (false);
for (unsigned int i = 0; i < output_map.length; i++)
{
unsigned int v = output_map.arrayZ[i];
if (v)
{
unsigned int outer = v >> 16;
unsigned int inner = v & 0xFFFF;
unsigned int u = (outer << inner_bit_count) | inner;
for (unsigned int w = width; w > 0;)
{
p[--w] = u;
u >>= 8;
}
}
p += width;
}
return_trace (true);
}
uint32_t map (unsigned int v) const /* Returns 16.16 outer.inner. */
{
/* If count is zero, pass value unchanged. This takes
* care of direct mapping for advance map. */
if (!mapCount)
return v;
if (v >= mapCount)
v = mapCount - 1;
unsigned int u = 0;
{ /* Fetch it. */
unsigned int w = get_width ();
const HBUINT8 *p = mapDataZ.arrayZ + w * v;
for (; w; w--)
u = (u << 8) + *p++;
}
{ /* Repack it. */
unsigned int n = get_inner_bit_count ();
unsigned int outer = u >> n;
unsigned int inner = u & ((1 << n) - 1);
u = (outer<<16) | inner;
}
return u;
}
unsigned get_map_count () const { return mapCount; }
unsigned get_width () const { return ((entryFormat >> 4) & 3) + 1; }
unsigned get_inner_bit_count () const { return (entryFormat & 0xF) + 1; }
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
hb_barrier () &&
c->check_range (mapDataZ.arrayZ,
mapCount,
get_width ()));
}
protected:
HBUINT8 format; /* Format identifier--format = 0 */
HBUINT8 entryFormat; /* A packed field that describes the compressed
* representation of delta-set indices. */
MapCountT mapCount; /* The number of mapping entries. */
UnsizedArrayOf<HBUINT8>
mapDataZ; /* The delta-set index mapping data. */
public:
DEFINE_SIZE_ARRAY (2+MapCountT::static_size, mapDataZ);
};
struct DeltaSetIndexMap
{
template <typename T>
bool serialize (hb_serialize_context_t *c, const T &plan)
{
TRACE_SERIALIZE (this);
unsigned length = plan.get_output_map ().length;
u.format = length <= 0xFFFF ? 0 : 1;
switch (u.format) {
case 0: return_trace (u.format0.serialize (c, plan));
case 1: return_trace (u.format1.serialize (c, plan));
default:return_trace (false);
}
}
uint32_t map (unsigned v) const
{
switch (u.format) {
case 0: return (u.format0.map (v));
case 1: return (u.format1.map (v));
default:return v;
}
}
unsigned get_map_count () const
{
switch (u.format) {
case 0: return u.format0.get_map_count ();
case 1: return u.format1.get_map_count ();
default:return 0;
}
}
unsigned get_width () const
{
switch (u.format) {
case 0: return u.format0.get_width ();
case 1: return u.format1.get_width ();
default:return 0;
}
}
unsigned get_inner_bit_count () const
{
switch (u.format) {
case 0: return u.format0.get_inner_bit_count ();
case 1: return u.format1.get_inner_bit_count ();
default:return 0;
}
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return_trace (false);
hb_barrier ();
switch (u.format) {
case 0: return_trace (u.format0.sanitize (c));
case 1: return_trace (u.format1.sanitize (c));
default:return_trace (true);
}
}
DeltaSetIndexMap* copy (hb_serialize_context_t *c) const
{
TRACE_SERIALIZE (this);
switch (u.format) {
case 0: return_trace (reinterpret_cast<DeltaSetIndexMap *> (u.format0.copy (c)));
case 1: return_trace (reinterpret_cast<DeltaSetIndexMap *> (u.format1.copy (c)));
default:return_trace (nullptr);
}
}
protected:
union {
HBUINT8 format; /* Format identifier */
DeltaSetIndexMapFormat01<HBUINT16> format0;
DeltaSetIndexMapFormat01<HBUINT32> format1;
} u;
public:
DEFINE_SIZE_UNION (1, format);
};
struct ItemVarStoreInstancer
{
ItemVarStoreInstancer (const ItemVariationStore *varStore,
const DeltaSetIndexMap *varIdxMap,
hb_array_t<int> coords) :
varStore (varStore), varIdxMap (varIdxMap), coords (coords) {}
operator bool () const { return varStore && bool (coords); }
/* according to the spec, if colr table has varStore but does not have
* varIdxMap, then an implicit identity mapping is used */
float operator() (uint32_t varIdx, unsigned short offset = 0) const
{ return coords ? varStore->get_delta (varIdxMap ? varIdxMap->map (VarIdx::add (varIdx, offset)) : varIdx + offset, coords) : 0; }
const ItemVariationStore *varStore;
const DeltaSetIndexMap *varIdxMap;
hb_array_t<int> coords;
};
/* https://docs.microsoft.com/en-us/typography/opentype/spec/otvarcommonformats#tuplevariationheader */
struct TupleVariationHeader
@ -305,9 +98,9 @@ struct TupleVariationHeader
return true;
}
double calculate_scalar (hb_array_t<int> coords, unsigned int coord_count,
const hb_array_t<const F2DOT14> shared_tuples,
const hb_vector_t<hb_pair_t<int,int>> *shared_tuple_active_idx = nullptr) const
double calculate_scalar (hb_array_t<const int> coords, unsigned int coord_count,
const hb_array_t<const F2DOT14> shared_tuples,
const hb_vector_t<hb_pair_t<int,int>> *shared_tuple_active_idx = nullptr) const
{
const F2DOT14 *peak_tuple;
@ -428,13 +221,6 @@ struct TupleVariationHeader
DEFINE_SIZE_MIN (4);
};
enum packed_delta_flag_t
{
DELTAS_ARE_ZERO = 0x80,
DELTAS_ARE_WORDS = 0x40,
DELTA_RUN_COUNT_MASK = 0x3F
};
struct tuple_delta_t
{
static constexpr bool realloc_move = true; // Watch out when adding new members!
@ -728,10 +514,10 @@ struct tuple_delta_t
bool compile_deltas ()
{ return compile_deltas (indices, deltas_x, deltas_y, compiled_deltas); }
bool compile_deltas (const hb_vector_t<bool> &point_indices,
const hb_vector_t<double> &x_deltas,
const hb_vector_t<double> &y_deltas,
hb_vector_t<char> &compiled_deltas /* OUT */)
static bool compile_deltas (const hb_vector_t<bool> &point_indices,
const hb_vector_t<double> &x_deltas,
const hb_vector_t<double> &y_deltas,
hb_vector_t<char> &compiled_deltas /* OUT */)
{
hb_vector_t<int> rounded_deltas;
if (unlikely (!rounded_deltas.alloc (point_indices.length)))
@ -745,15 +531,14 @@ struct tuple_delta_t
}
if (!rounded_deltas) return true;
/* allocate enough memories 3 * num_deltas */
unsigned alloc_len = 3 * rounded_deltas.length;
/* allocate enough memories 5 * num_deltas */
unsigned alloc_len = 5 * rounded_deltas.length;
if (y_deltas)
alloc_len *= 2;
if (unlikely (!compiled_deltas.resize (alloc_len))) return false;
unsigned i = 0;
unsigned encoded_len = encode_delta_run (i, compiled_deltas.as_array (), rounded_deltas);
unsigned encoded_len = compile_deltas (compiled_deltas, rounded_deltas);
if (y_deltas)
{
@ -770,174 +555,15 @@ struct tuple_delta_t
}
if (j != rounded_deltas.length) return false;
/* reset i because we reuse rounded_deltas for y_deltas */
i = 0;
encoded_len += encode_delta_run (i, compiled_deltas.as_array ().sub_array (encoded_len), rounded_deltas);
encoded_len += compile_deltas (compiled_deltas.as_array ().sub_array (encoded_len), rounded_deltas);
}
return compiled_deltas.resize (encoded_len);
}
unsigned encode_delta_run (unsigned& i,
hb_array_t<char> encoded_bytes,
const hb_vector_t<int>& deltas) const
static unsigned compile_deltas (hb_array_t<char> encoded_bytes,
hb_array_t<const int> deltas)
{
unsigned num_deltas = deltas.length;
unsigned encoded_len = 0;
while (i < num_deltas)
{
int val = deltas.arrayZ[i];
if (val == 0)
encoded_len += encode_delta_run_as_zeroes (i, encoded_bytes.sub_array (encoded_len), deltas);
else if (val >= -128 && val <= 127)
encoded_len += encode_delta_run_as_bytes (i, encoded_bytes.sub_array (encoded_len), deltas);
else
encoded_len += encode_delta_run_as_words (i, encoded_bytes.sub_array (encoded_len), deltas);
}
return encoded_len;
}
unsigned encode_delta_run_as_zeroes (unsigned& i,
hb_array_t<char> encoded_bytes,
const hb_vector_t<int>& deltas) const
{
unsigned num_deltas = deltas.length;
unsigned run_length = 0;
auto it = encoded_bytes.iter ();
unsigned encoded_len = 0;
while (i < num_deltas && deltas.arrayZ[i] == 0)
{
i++;
run_length++;
}
while (run_length >= 64)
{
*it++ = char (DELTAS_ARE_ZERO | 63);
run_length -= 64;
encoded_len++;
}
if (run_length)
{
*it++ = char (DELTAS_ARE_ZERO | (run_length - 1));
encoded_len++;
}
return encoded_len;
}
unsigned encode_delta_run_as_bytes (unsigned &i,
hb_array_t<char> encoded_bytes,
const hb_vector_t<int>& deltas) const
{
unsigned start = i;
unsigned num_deltas = deltas.length;
while (i < num_deltas)
{
int val = deltas.arrayZ[i];
if (val > 127 || val < -128)
break;
/* from fonttools: if there're 2 or more zeros in a sequence,
* it is better to start a new run to save bytes. */
if (val == 0 && i + 1 < num_deltas && deltas.arrayZ[i+1] == 0)
break;
i++;
}
unsigned run_length = i - start;
unsigned encoded_len = 0;
auto it = encoded_bytes.iter ();
while (run_length >= 64)
{
*it++ = 63;
encoded_len++;
for (unsigned j = 0; j < 64; j++)
{
*it++ = static_cast<char> (deltas.arrayZ[start + j]);
encoded_len++;
}
start += 64;
run_length -= 64;
}
if (run_length)
{
*it++ = run_length - 1;
encoded_len++;
while (start < i)
{
*it++ = static_cast<char> (deltas.arrayZ[start++]);
encoded_len++;
}
}
return encoded_len;
}
unsigned encode_delta_run_as_words (unsigned &i,
hb_array_t<char> encoded_bytes,
const hb_vector_t<int>& deltas) const
{
unsigned start = i;
unsigned num_deltas = deltas.length;
while (i < num_deltas)
{
int val = deltas.arrayZ[i];
/* start a new run for a single zero value*/
if (val == 0) break;
/* from fonttools: continue word-encoded run if there's only one
* single value in the range [-128, 127] because it is more compact.
* Only start a new run when there're 2 continuous such values. */
if (val >= -128 && val <= 127 &&
i + 1 < num_deltas &&
deltas.arrayZ[i+1] >= -128 && deltas.arrayZ[i+1] <= 127)
break;
i++;
}
unsigned run_length = i - start;
auto it = encoded_bytes.iter ();
unsigned encoded_len = 0;
while (run_length >= 64)
{
*it++ = (DELTAS_ARE_WORDS | 63);
encoded_len++;
for (unsigned j = 0; j < 64; j++)
{
int16_t delta_val = deltas.arrayZ[start + j];
*it++ = static_cast<char> (delta_val >> 8);
*it++ = static_cast<char> (delta_val & 0xFF);
encoded_len += 2;
}
start += 64;
run_length -= 64;
}
if (run_length)
{
*it++ = (DELTAS_ARE_WORDS | (run_length - 1));
encoded_len++;
while (start < i)
{
int16_t delta_val = deltas.arrayZ[start++];
*it++ = static_cast<char> (delta_val >> 8);
*it++ = static_cast<char> (delta_val & 0xFF);
encoded_len += 2;
}
}
return encoded_len;
return TupleValues::compile (deltas, encoded_bytes);
}
bool calc_inferred_deltas (const contour_point_vector_t& orig_points)
@ -1316,7 +942,7 @@ struct TupleVariationData
bool has_private_points = iterator.current_tuple->has_private_points ();
const HBUINT8 *end = p + length;
if (has_private_points &&
!TupleVariationData::unpack_points (p, private_indices, end))
!TupleVariationData::decompile_points (p, private_indices, end))
return false;
const hb_vector_t<unsigned> &indices = has_private_points ? private_indices : shared_indices;
@ -1326,14 +952,14 @@ struct TupleVariationData
hb_vector_t<int> deltas_x;
if (unlikely (!deltas_x.resize (num_deltas, false) ||
!TupleVariationData::unpack_deltas (p, deltas_x, end)))
!TupleVariationData::decompile_deltas (p, deltas_x, end)))
return false;
hb_vector_t<int> deltas_y;
if (is_gvar)
{
if (unlikely (!deltas_y.resize (num_deltas, false) ||
!TupleVariationData::unpack_deltas (p, deltas_y, end)))
!TupleVariationData::decompile_deltas (p, deltas_y, end)))
return false;
}
@ -1700,7 +1326,7 @@ struct TupleVariationData
{
const HBUINT8 *base = &(table_base+var_data->data);
const HBUINT8 *p = base;
if (!unpack_points (p, shared_indices, (const HBUINT8 *) (var_data_bytes.arrayZ + var_data_bytes.length))) return false;
if (!decompile_points (p, shared_indices, (const HBUINT8 *) (var_data_bytes.arrayZ + var_data_bytes.length))) return false;
data_offset = p - base;
}
return true;
@ -1750,9 +1376,9 @@ struct TupleVariationData
bool has_shared_point_numbers () const { return tupleVarCount.has_shared_point_numbers (); }
static bool unpack_points (const HBUINT8 *&p /* IN/OUT */,
hb_vector_t<unsigned int> &points /* OUT */,
const HBUINT8 *end)
static bool decompile_points (const HBUINT8 *&p /* IN/OUT */,
hb_vector_t<unsigned int> &points /* OUT */,
const HBUINT8 *end)
{
enum packed_point_flag_t
{
@ -1802,43 +1428,13 @@ struct TupleVariationData
return true;
}
static bool unpack_deltas (const HBUINT8 *&p /* IN/OUT */,
hb_vector_t<int> &deltas /* IN/OUT */,
const HBUINT8 *end)
template <typename T>
static bool decompile_deltas (const HBUINT8 *&p /* IN/OUT */,
hb_vector_t<T> &deltas /* IN/OUT */,
const HBUINT8 *end,
bool consume_all = false)
{
unsigned i = 0;
unsigned count = deltas.length;
while (i < count)
{
if (unlikely (p + 1 > end)) return false;
unsigned control = *p++;
unsigned run_count = (control & DELTA_RUN_COUNT_MASK) + 1;
unsigned stop = i + run_count;
if (unlikely (stop > count)) return false;
if (control & DELTAS_ARE_ZERO)
{
for (; i < stop; i++)
deltas.arrayZ[i] = 0;
}
else if (control & DELTAS_ARE_WORDS)
{
if (unlikely (p + run_count * HBUINT16::static_size > end)) return false;
for (; i < stop; i++)
{
deltas.arrayZ[i] = * (const HBINT16 *) p;
p += HBUINT16::static_size;
}
}
else
{
if (unlikely (p + run_count > end)) return false;
for (; i < stop; i++)
{
deltas.arrayZ[i] = * (const HBINT8 *) p++;
}
}
}
return true;
return TupleValues::decompile (p, deltas, end, consume_all);
}
bool has_data () const { return tupleVarCount; }
@ -2382,6 +1978,7 @@ struct item_variations_t
}
};
} /* namespace OT */

View File

@ -107,14 +107,14 @@ struct cvar
bool has_private_points = iterator.current_tuple->has_private_points ();
if (has_private_points &&
!TupleVariationData::unpack_points (p, private_indices, end))
!TupleVariationData::decompile_points (p, private_indices, end))
return false;
const hb_vector_t<unsigned int> &indices = has_private_points ? private_indices : shared_indices;
bool apply_to_all = (indices.length == 0);
unsigned num_deltas = apply_to_all ? num_cvt_item : indices.length;
if (unlikely (!unpacked_deltas.resize (num_deltas, false))) return false;
if (unlikely (!TupleVariationData::unpack_deltas (p, unpacked_deltas, end))) return false;
if (unlikely (!TupleVariationData::decompile_deltas (p, unpacked_deltas, end))) return false;
for (unsigned int i = 0; i < num_deltas; i++)
{

View File

@ -618,7 +618,7 @@ struct gvar
public:
bool apply_deltas_to_points (hb_codepoint_t glyph,
hb_array_t<int> coords,
hb_array_t<const int> coords,
const hb_array_t<contour_point_t> points,
bool phantom_only = false) const
{
@ -673,16 +673,16 @@ struct gvar
bool has_private_points = iterator.current_tuple->has_private_points ();
if (has_private_points &&
!GlyphVariationData::unpack_points (p, private_indices, end))
!GlyphVariationData::decompile_points (p, private_indices, end))
return false;
const hb_array_t<unsigned int> &indices = has_private_points ? private_indices : shared_indices;
bool apply_to_all = (indices.length == 0);
unsigned int num_deltas = apply_to_all ? points.length : indices.length;
if (unlikely (!x_deltas.resize (num_deltas, false))) return false;
if (unlikely (!GlyphVariationData::unpack_deltas (p, x_deltas, end))) return false;
if (unlikely (!GlyphVariationData::decompile_deltas (p, x_deltas, end))) return false;
if (unlikely (!y_deltas.resize (num_deltas, false))) return false;
if (unlikely (!GlyphVariationData::unpack_deltas (p, y_deltas, end))) return false;
if (unlikely (!GlyphVariationData::decompile_deltas (p, y_deltas, end))) return false;
if (!apply_to_all)
{

View File

@ -0,0 +1,32 @@
/*
* Copyright © 2024 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): Behdad Esfahbod
*/
#ifndef HB_OT_VAR_VARC_TABLE_HH
#define HB_OT_VAR_VARC_TABLE_HH
#include "OT/Var/VARC/VARC.hh"
#endif /* HB_OT_VAR_VARC_TABLE_HH */

View File

@ -28,169 +28,8 @@
#include "hb.hh"
#include "hb-paint.h"
#include "hb-geometry.hh"
typedef struct hb_extents_t
{
hb_extents_t () {}
hb_extents_t (float xmin, float ymin, float xmax, float ymax) :
xmin (xmin), ymin (ymin), xmax (xmax), ymax (ymax) {}
bool is_empty () const { return xmin >= xmax || ymin >= ymax; }
bool is_void () const { return xmin > xmax; }
void union_ (const hb_extents_t &o)
{
xmin = hb_min (xmin, o.xmin);
ymin = hb_min (ymin, o.ymin);
xmax = hb_max (xmax, o.xmax);
ymax = hb_max (ymax, o.ymax);
}
void intersect (const hb_extents_t &o)
{
xmin = hb_max (xmin, o.xmin);
ymin = hb_max (ymin, o.ymin);
xmax = hb_min (xmax, o.xmax);
ymax = hb_min (ymax, o.ymax);
}
void
add_point (float x, float y)
{
if (unlikely (is_void ()))
{
xmin = xmax = x;
ymin = ymax = y;
}
else
{
xmin = hb_min (xmin, x);
ymin = hb_min (ymin, y);
xmax = hb_max (xmax, x);
ymax = hb_max (ymax, y);
}
}
float xmin = 0.f;
float ymin = 0.f;
float xmax = -1.f;
float ymax = -1.f;
} hb_extents_t;
typedef struct hb_transform_t
{
hb_transform_t () {}
hb_transform_t (float xx, float yx,
float xy, float yy,
float x0, float y0) :
xx (xx), yx (yx), xy (xy), yy (yy), x0 (x0), y0 (y0) {}
void multiply (const hb_transform_t &o)
{
/* Copied from cairo, with "o" being "a" there and "this" being "b" there. */
hb_transform_t r;
r.xx = o.xx * xx + o.yx * xy;
r.yx = o.xx * yx + o.yx * yy;
r.xy = o.xy * xx + o.yy * xy;
r.yy = o.xy * yx + o.yy * yy;
r.x0 = o.x0 * xx + o.y0 * xy + x0;
r.y0 = o.x0 * yx + o.y0 * yy + y0;
*this = r;
}
void transform_distance (float &dx, float &dy) const
{
float new_x = xx * dx + xy * dy;
float new_y = yx * dx + yy * dy;
dx = new_x;
dy = new_y;
}
void transform_point (float &x, float &y) const
{
transform_distance (x, y);
x += x0;
y += y0;
}
void transform_extents (hb_extents_t &extents) const
{
float quad_x[4], quad_y[4];
quad_x[0] = extents.xmin;
quad_y[0] = extents.ymin;
quad_x[1] = extents.xmin;
quad_y[1] = extents.ymax;
quad_x[2] = extents.xmax;
quad_y[2] = extents.ymin;
quad_x[3] = extents.xmax;
quad_y[3] = extents.ymax;
extents = hb_extents_t {};
for (unsigned i = 0; i < 4; i++)
{
transform_point (quad_x[i], quad_y[i]);
extents.add_point (quad_x[i], quad_y[i]);
}
}
float xx = 1.f;
float yx = 0.f;
float xy = 0.f;
float yy = 1.f;
float x0 = 0.f;
float y0 = 0.f;
} hb_transform_t;
typedef struct hb_bounds_t
{
enum status_t {
UNBOUNDED,
BOUNDED,
EMPTY,
};
hb_bounds_t (status_t status) : status (status) {}
hb_bounds_t (const hb_extents_t &extents) :
status (extents.is_empty () ? EMPTY : BOUNDED), extents (extents) {}
void union_ (const hb_bounds_t &o)
{
if (o.status == UNBOUNDED)
status = UNBOUNDED;
else if (o.status == BOUNDED)
{
if (status == EMPTY)
*this = o;
else if (status == BOUNDED)
extents.union_ (o.extents);
}
}
void intersect (const hb_bounds_t &o)
{
if (o.status == EMPTY)
status = EMPTY;
else if (o.status == BOUNDED)
{
if (status == UNBOUNDED)
*this = o;
else if (status == BOUNDED)
{
extents.intersect (o.extents);
if (extents.is_empty ())
status = EMPTY;
}
}
}
status_t status;
hb_extents_t extents;
} hb_bounds_t;
typedef struct hb_paint_extents_context_t hb_paint_extents_context_t;

View File

@ -412,6 +412,7 @@ hb_subset_input_keep_everything (hb_subset_input_t *input)
hb_subset_input_set_flags (input,
HB_SUBSET_FLAGS_NOTDEF_OUTLINE |
HB_SUBSET_FLAGS_GLYPH_NAMES |
HB_SUBSET_FLAGS_NAME_LEGACY |
HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES |
HB_SUBSET_FLAGS_PASSTHROUGH_UNRECOGNIZED);
}
@ -730,7 +731,7 @@ hb_subset_input_override_name_table (hb_subset_input_t *input,
src = hb_utf8_t::next (src, src_end, &unicode, replacement);
if (unicode >= 0x0080u)
{
printf ("Non-ascii character detected, ignored...This API supports acsii characters only for mac platform\n");
printf ("Non-ascii character detected, ignored...This API supports ascii characters only for mac platform\n");
return false;
}
}

View File

@ -515,6 +515,7 @@ _cmap_closure (hb_face_t *face,
cmap.table->closure_glyphs (unicodes, glyphset);
}
#ifndef HB_NO_VAR
static void
_remap_colrv1_delta_set_index_indices (const OT::DeltaSetIndexMap &index_map,
const hb_set_t &delta_set_idxes,
@ -547,6 +548,7 @@ _remap_colrv1_delta_set_index_indices (const OT::DeltaSetIndexMap &index_map,
}
variation_idx_delta_map = std::move (delta_set_idx_delta_map);
}
#endif
static void _colr_closure (hb_subset_plan_t* plan,
hb_set_t *glyphs_colred)
@ -570,6 +572,7 @@ static void _colr_closure (hb_subset_plan_t* plan,
_remap_indexes (&layer_indices, &plan->colrv1_layers);
_remap_palette_indexes (&palette_indices, &plan->colr_palettes);
#ifndef HB_NO_VAR
if (!colr.has_var_store () || !variation_indices) return;
const OT::ItemVariationStore &var_store = colr.get_var_store ();
@ -600,6 +603,7 @@ static void _colr_closure (hb_subset_plan_t* plan,
plan->colrv1_variation_idx_delta_map,
plan->colrv1_new_deltaset_idx_varidx_map);
}
#endif
}
static inline void
@ -638,6 +642,36 @@ _remove_invalid_gids (hb_set_t *glyphs,
glyphs->del_range (num_glyphs, HB_SET_VALUE_INVALID);
}
template<bool GID_ALWAYS_EXISTS = false, typename I, typename F, typename G, hb_requires (hb_is_iterator (I))>
static void
_fill_unicode_and_glyph_map(hb_subset_plan_t *plan,
I unicode_iterator,
F unicode_to_gid_for_iterator,
G unicode_to_gid_general)
{
for (hb_codepoint_t cp : unicode_iterator)
{
hb_codepoint_t gid = unicode_to_gid_for_iterator(cp);
if (!GID_ALWAYS_EXISTS && 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));
}
}
template<bool GID_ALWAYS_EXISTS = false, typename I, typename F, hb_requires (hb_is_iterator (I))>
static void
_fill_unicode_and_glyph_map(hb_subset_plan_t *plan,
I unicode_iterator,
F unicode_to_gid_for_iterator)
{
_fill_unicode_and_glyph_map(plan, unicode_iterator, unicode_to_gid_for_iterator, unicode_to_gid_for_iterator);
}
static void
_populate_unicodes_to_retain (const hb_set_t *unicodes,
const hb_set_t *glyphs,
@ -657,35 +691,21 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes,
// not excessively large (eg. an inverted set).
plan->unicode_to_new_gid_list.alloc (unicodes->get_population ());
if (!unicode_to_gid) {
for (hb_codepoint_t cp : *unicodes)
{
_fill_unicode_and_glyph_map(plan, unicodes->iter(), [&] (hb_codepoint_t cp) {
hb_codepoint_t gid;
if (!cmap.get_nominal_glyph (cp, &gid))
{
DEBUG_MSG(SUBSET, nullptr, "Drop U+%04X; no gid", cp);
continue;
if (!cmap.get_nominal_glyph (cp, &gid)) {
return HB_MAP_VALUE_INVALID;
}
plan->codepoint_to_glyph->set (cp, gid);
plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
}
return 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));
}
_fill_unicode_and_glyph_map(plan, unicodes->iter(), [&] (hb_codepoint_t cp) {
return unicode_to_gid->get (cp);
});
}
}
else
@ -715,29 +735,29 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes,
plan->codepoint_to_glyph->alloc (unicodes->get_population () + glyphs->get_population ());
auto &gid_to_unicodes = plan->accelerator->gid_to_unicodes;
for (hb_codepoint_t gid : *glyphs)
{
auto unicodes = gid_to_unicodes.get (gid);
for (hb_codepoint_t cp : unicodes)
{
plan->codepoint_to_glyph->set (cp, gid);
plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
}
_fill_unicode_and_glyph_map<true>(plan, unicodes, [&] (hb_codepoint_t cp) {
return gid;
},
[&] (hb_codepoint_t cp) {
return unicode_glyphid_map->get(cp);
});
}
for (hb_codepoint_t cp : *unicodes)
{
/* Don't double-add entry. */
_fill_unicode_and_glyph_map(plan, unicodes->iter(), [&] (hb_codepoint_t cp) {
/* Don't double-add entry. */
if (plan->codepoint_to_glyph->has (cp))
continue;
return HB_MAP_VALUE_INVALID;
hb_codepoint_t *gid;
if (!unicode_glyphid_map->has(cp, &gid))
continue;
return unicode_glyphid_map->get(cp);
},
[&] (hb_codepoint_t cp) {
return unicode_glyphid_map->get(cp);
});
plan->codepoint_to_glyph->set (cp, *gid);
plan->unicode_to_new_gid_list.push (hb_pair (cp, *gid));
}
plan->unicode_to_new_gid_list.qsort ();
}
else
@ -746,15 +766,15 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes,
hb_codepoint_t first = HB_SET_VALUE_INVALID, last = HB_SET_VALUE_INVALID;
for (; cmap_unicodes->next_range (&first, &last); )
{
for (unsigned cp = first; cp <= last; cp++)
{
hb_codepoint_t gid = (*unicode_glyphid_map)[cp];
_fill_unicode_and_glyph_map(plan, hb_range(first, last + 1), [&] (hb_codepoint_t cp) {
hb_codepoint_t gid = (*unicode_glyphid_map)[cp];
if (!unicodes->has (cp) && !glyphs->has (gid))
continue;
plan->codepoint_to_glyph->set (cp, gid);
plan->unicode_to_new_gid_list.push (hb_pair (cp, gid));
}
return HB_MAP_VALUE_INVALID;
return gid;
},
[&] (hb_codepoint_t cp) {
return unicode_glyphid_map->get(cp);
});
}
}
@ -779,10 +799,6 @@ _populate_unicodes_to_retain (const hb_set_t *unicodes,
}
}
#ifndef HB_COMPOSITE_OPERATIONS_PER_GLYPH
#define HB_COMPOSITE_OPERATIONS_PER_GLYPH 64
#endif
static unsigned
_glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf,
hb_codepoint_t gid,
@ -808,18 +824,6 @@ _glyf_add_gid_and_children (const OT::glyf_accelerator_t &glyf,
operation_count,
depth);
#ifndef HB_NO_VAR_COMPOSITES
for (auto &item : glyph.get_var_composite_iterator ())
{
operation_count =
_glyf_add_gid_and_children (glyf,
item.get_gid (),
gids_to_retain,
operation_count,
depth);
}
#endif
return operation_count;
}
@ -916,13 +920,15 @@ _populate_gids_to_retain (hb_subset_plan_t* plan,
plan->_glyphset_colred = cur_glyphset;
// XXX TODO VARC closure / subset
_nameid_closure (plan, drop_tables);
/* Populate a full set of glyphs to retain by adding all referenced
* composite glyphs. */
if (glyf.has_data ())
for (hb_codepoint_t gid : cur_glyphset)
_glyf_add_gid_and_children (glyf, gid, &plan->_glyphset,
cur_glyphset.get_population () * HB_COMPOSITE_OPERATIONS_PER_GLYPH);
cur_glyphset.get_population () * HB_MAX_COMPOSITE_OPERATIONS_PER_GLYPH);
else
plan->_glyphset.union_ (cur_glyphset);
#ifndef HB_NO_SUBSET_CFF

View File

@ -41,13 +41,13 @@ HB_BEGIN_DECLS
*
* The major component of the library version available at compile-time.
*/
#define HB_VERSION_MAJOR 8
#define HB_VERSION_MAJOR 9
/**
* HB_VERSION_MINOR:
*
* The minor component of the library version available at compile-time.
*/
#define HB_VERSION_MINOR 5
#define HB_VERSION_MINOR 0
/**
* HB_VERSION_MICRO:
*
@ -60,7 +60,7 @@ HB_BEGIN_DECLS
*
* A string literal containing the library version available at compile-time.
*/
#define HB_VERSION_STRING "8.5.0"
#define HB_VERSION_STRING "9.0.0"
/**
* HB_VERSION_ATLEAST:

View File

@ -0,0 +1,109 @@
/*
* Copyright © 2023 Behdad Esfahbod
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/
#ifndef HB_WASM_API_LIST_HH
#define HB_WASM_API_LIST_HH
#include "hb-wasm-api.hh"
#ifdef HB_DEBUG_WASM
namespace hb { namespace wasm {
static void debugprint (HB_WASM_EXEC_ENV char *str)
{ DEBUG_MSG (WASM, exec_env, "%s", str); }
static void debugprint1 (HB_WASM_EXEC_ENV char *str, int32_t i1)
{ DEBUG_MSG (WASM, exec_env, "%s: %d", str, i1); }
static void debugprint2 (HB_WASM_EXEC_ENV char *str, int32_t i1, int32_t i2)
{ DEBUG_MSG (WASM, exec_env, "%s: %d, %d", str, i1, i2); }
static void debugprint3 (HB_WASM_EXEC_ENV char *str, int32_t i1, int32_t i2, int32_t i3)
{ DEBUG_MSG (WASM, exec_env, "%s: %d, %d, %d", str, i1, i2, i3); }
static void debugprint4 (HB_WASM_EXEC_ENV char *str, int32_t i1, int32_t i2, int32_t i3, int32_t i4)
{ DEBUG_MSG (WASM, exec_env, "%s: %d, %d, %d, %d", str, i1, i2, i3, i4); }
}}
#endif
#define NATIVE_SYMBOL(signature, name) {#name, (void *) hb::wasm::name, signature, NULL}
/* Note: the array must be static defined since runtime will keep it after registration.
* Also not const, because it modifies it (sorts it).
* https://github.com/bytecodealliance/wasm-micro-runtime/blob/main/doc/export_native_api.md
*
* TODO Allocate this lazily in _hb_wasm_init(). */
static NativeSymbol _hb_wasm_native_symbols[] =
{
/* common */
NATIVE_SYMBOL ("(i)i", script_get_horizontal_direction),
/* blob */
NATIVE_SYMBOL ("(i)", blob_free),
/* buffer */
NATIVE_SYMBOL ("(i)", buffer_contents_free),
NATIVE_SYMBOL ("(ii)i", buffer_contents_realloc),
NATIVE_SYMBOL ("(ii)i", buffer_copy_contents),
NATIVE_SYMBOL ("(ii)i", buffer_set_contents),
NATIVE_SYMBOL ("(i)i", buffer_get_direction),
NATIVE_SYMBOL ("(i)i", buffer_get_script),
NATIVE_SYMBOL ("(i)", buffer_reverse),
NATIVE_SYMBOL ("(i)", buffer_reverse_clusters),
/* face */
NATIVE_SYMBOL ("(ii)i", face_create),
NATIVE_SYMBOL ("(iii)i", face_copy_table),
NATIVE_SYMBOL ("(i)i", face_get_upem),
/* font */
NATIVE_SYMBOL ("(i)i", font_create),
NATIVE_SYMBOL ("(i)i", font_get_face),
NATIVE_SYMBOL ("(iii)", font_get_scale),
NATIVE_SYMBOL ("(iii)i", font_get_glyph),
NATIVE_SYMBOL ("(ii)i", font_get_glyph_h_advance),
NATIVE_SYMBOL ("(ii)i", font_get_glyph_v_advance),
NATIVE_SYMBOL ("(iii)i", font_get_glyph_extents),
NATIVE_SYMBOL ("(ii$*)", font_glyph_to_string),
NATIVE_SYMBOL ("(iii)i", font_copy_glyph_outline),
NATIVE_SYMBOL ("(ii)i", font_copy_coords),
NATIVE_SYMBOL ("(ii)i", font_set_coords),
/* outline */
NATIVE_SYMBOL ("(i)", glyph_outline_free),
/* shape */
NATIVE_SYMBOL ("(iiii$)i", shape_with),
/* debug */
#ifdef HB_DEBUG_WASM
NATIVE_SYMBOL ("($)", debugprint),
NATIVE_SYMBOL ("($i)", debugprint1),
NATIVE_SYMBOL ("($ii)", debugprint2),
NATIVE_SYMBOL ("($iii)", debugprint3),
NATIVE_SYMBOL ("($iiii)", debugprint4),
#endif
};
#undef NATIVE_SYMBOL
#endif /* HB_WASM_API_LIST_HH */