HarfBuzz: Update to version 3.0.0

This commit is contained in:
bruvzg 2021-09-19 23:31:36 +03:00
parent 0e5b0c025c
commit 3061e3859d
156 changed files with 13941 additions and 11369 deletions

View File

@ -1379,7 +1379,7 @@ License: HarfBuzz
Copyright (C) 2009 Keith Stribley
Copyright (C) 2009 Martin Hosken and SIL International
Copyright (C) 2007 Chris Wilson
Copyright (C) 2006 Behdad Esfahbod
Copyright (C) 2005,2006,2020,2021 Behdad Esfahbod
Copyright (C) 2005 David Turner
Copyright (C) 2004,2007,2008,2009,2010 Red Hat, Inc.
Copyright (C) 1998-2004 David Turner and Werner Lemberg

View File

@ -64,6 +64,7 @@ if env["builtin_harfbuzz"]:
#'src/hb-gobject-structs.cc',
"src/hb-icu.cc",
"src/hb-map.cc",
"src/hb-ms-feature-ranges.cc",
"src/hb-number.cc",
"src/hb-ot-cff1-table.cc",
"src/hb-ot-cff2-table.cc",

View File

@ -192,13 +192,13 @@ Files extracted from upstream source:
## harfbuzz
- Upstream: https://github.com/harfbuzz/harfbuzz
- Version: 2.8.0 (03538e872a0610a65fad692b33d3646f387cf578, 2021)
- Version: 3.0.0 (9c387e20d65a7a366ac270d789f6ad266014c9e0, 2021)
- License: MIT
Files extracted from upstream source:
- the `src` folder
- `AUTHORS`, `COPYING`, `NEWS`, `THANKS`
- `AUTHORS`, `COPYING`, `THANKS`
## icu4c

View File

@ -4,14 +4,14 @@ files names COPYING in subdirectories where applicable.
Copyright © 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020 Google, Inc.
Copyright © 2018,2019,2020 Ebrahim Byagowi
Copyright © 2019,2020 Facebook, Inc.
Copyright © 2019,2020 Facebook, Inc.
Copyright © 2012 Mozilla Foundation
Copyright © 2011 Codethink Limited
Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies)
Copyright © 2009 Keith Stribley
Copyright © 2009 Martin Hosken and SIL International
Copyright © 2007 Chris Wilson
Copyright © 2006 Behdad Esfahbod
Copyright © 2005,2006,2020,2021 Behdad Esfahbod
Copyright © 2005 David Turner
Copyright © 2004,2007,2008,2009,2010 Red Hat, Inc.
Copyright © 1998-2004 David Turner and Werner Lemberg

2457
thirdparty/harfbuzz/NEWS vendored

File diff suppressed because it is too large Load Diff

View File

@ -54,7 +54,7 @@ struct Anchor
DEFINE_SIZE_STATIC (4);
};
typedef LArrayOf<Anchor> GlyphAnchors;
typedef Array32Of<Anchor> GlyphAnchors;
struct ankr
{
@ -64,7 +64,7 @@ struct ankr
unsigned int i,
unsigned int num_glyphs) const
{
const NNOffsetTo<GlyphAnchors> *offset = (this+lookupTable).get_value (glyph_id, num_glyphs);
const NNOffset16To<GlyphAnchors> *offset = (this+lookupTable).get_value (glyph_id, num_glyphs);
if (!offset)
return Null (Anchor);
const GlyphAnchors &anchors = &(this+anchorData) + *offset;
@ -83,9 +83,9 @@ struct ankr
protected:
HBUINT16 version; /* Version number (set to zero) */
HBUINT16 flags; /* Flags (currently unused; set to zero) */
LOffsetTo<Lookup<NNOffsetTo<GlyphAnchors>>>
Offset32To<Lookup<NNOffset16To<GlyphAnchors>>>
lookupTable; /* Offset to the table's lookup table */
LNNOffsetTo<HBUINT8>
NNOffset32To<HBUINT8>
anchorData; /* Offset to the glyph data table */
public:

View File

@ -30,6 +30,9 @@
#include "hb-aat-layout.hh"
#include "hb-open-type.hh"
namespace OT {
struct GDEF;
};
namespace AAT {
@ -164,7 +167,7 @@ struct LookupSegmentArray
HBGlyphID last; /* Last GlyphID in this segment */
HBGlyphID first; /* First GlyphID in this segment */
NNOffsetTo<UnsizedArrayOf<T>>
NNOffset16To<UnsizedArrayOf<T>>
valuesZ; /* A 16-bit offset from the start of
* the table to the data. */
public:
@ -659,7 +662,7 @@ struct ClassTable
}
protected:
HBGlyphID firstGlyph; /* First glyph index included in the trimmed array. */
ArrayOf<HBUCHAR> classArray; /* The class codes (indexed by glyph index minus
Array16Of<HBUCHAR> classArray; /* The class codes (indexed by glyph index minus
* firstGlyph). */
public:
DEFINE_SIZE_ARRAY (4, classArray);
@ -678,7 +681,8 @@ struct ObsoleteTypes
const void *base,
const T *array)
{
return (offset - ((const char *) array - (const char *) base)) / T::static_size;
/* https://github.com/harfbuzz/harfbuzz/issues/2816 */
return (offset - unsigned ((const char *) array - (const char *) base)) / T::static_size;
}
template <typename T>
static unsigned int byteOffsetToIndex (unsigned int offset,
@ -862,6 +866,7 @@ struct hb_aat_apply_context_t :
hb_buffer_t *buffer;
hb_sanitize_context_t sanitizer;
const ankr *ankr_table;
const OT::GDEF *gdef_table;
/* Unused. For debug tracing only. */
unsigned int lookup_index;

View File

@ -144,7 +144,7 @@ struct FeatureName
protected:
HBUINT16 feature; /* Feature type. */
HBUINT16 nSettings; /* The number of records in the setting name array. */
LNNOffsetTo<UnsizedArrayOf<SettingName>>
NNOffset32To<UnsizedArrayOf<SettingName>>
settingTableZ; /* Offset in bytes from the beginning of this table to
* this feature's setting name array. The actual type of
* record this offset refers to will depend on the

View File

@ -79,7 +79,7 @@ struct DecompositionAction
* to decompose before more frequent ones. The ligatures
* on the line of text will decompose in increasing
* value of this field. */
ArrayOf<HBUINT16>
Array16Of<HBUINT16>
decomposedglyphs;
/* Number of 16-bit glyph indexes that follow;
* the ligature will be decomposed into these glyphs.
@ -310,7 +310,7 @@ struct WidthDeltaPair
DEFINE_SIZE_STATIC (24);
};
typedef OT::LArrayOf<WidthDeltaPair> WidthDeltaCluster;
typedef OT::Array32Of<WidthDeltaPair> WidthDeltaCluster;
struct JustificationCategory
{
@ -358,20 +358,20 @@ struct JustificationHeader
}
protected:
OffsetTo<JustificationCategory>
Offset16To<JustificationCategory>
justClassTable; /* Offset to the justification category state table. */
OffsetTo<WidthDeltaCluster>
Offset16To<WidthDeltaCluster>
wdcTable; /* Offset from start of justification table to start
* of the subtable containing the width delta factors
* for the glyphs in your font.
*
* The width delta clusters table. */
OffsetTo<PostcompensationActionChain>
Offset16To<PostcompensationActionChain>
pcTable; /* Offset from start of justification table to start
* of postcompensation subtable (set to zero if none).
*
* The postcompensation subtable, if present in the font. */
Lookup<OffsetTo<WidthDeltaCluster>>
Lookup<Offset16To<WidthDeltaCluster>>
lookupTable; /* Lookup table associating glyphs with width delta
* clusters. See the description of Width Delta Clusters
* table for details on how to interpret the lookup values. */
@ -398,13 +398,13 @@ struct just
FixedVersion<>version; /* Version of the justification table
* (0x00010000u for version 1.0). */
HBUINT16 format; /* Format of the justification table (set to 0). */
OffsetTo<JustificationHeader>
Offset16To<JustificationHeader>
horizData; /* Byte offset from the start of the justification table
* to the header for tables that contain justification
* information for horizontal text.
* If you are not including this information,
* store 0. */
OffsetTo<JustificationHeader>
Offset16To<JustificationHeader>
vertData; /* ditto, vertical */
public:

View File

@ -710,18 +710,18 @@ struct KerxSubTableFormat6
{
struct Long
{
LNNOffsetTo<Lookup<HBUINT32>> rowIndexTable;
LNNOffsetTo<Lookup<HBUINT32>> columnIndexTable;
LNNOffsetTo<UnsizedArrayOf<FWORD32>> array;
NNOffset32To<Lookup<HBUINT32>> rowIndexTable;
NNOffset32To<Lookup<HBUINT32>> columnIndexTable;
NNOffset32To<UnsizedArrayOf<FWORD32>> array;
} l;
struct Short
{
LNNOffsetTo<Lookup<HBUINT16>> rowIndexTable;
LNNOffsetTo<Lookup<HBUINT16>> columnIndexTable;
LNNOffsetTo<UnsizedArrayOf<FWORD>> array;
NNOffset32To<Lookup<HBUINT16>> rowIndexTable;
NNOffset32To<Lookup<HBUINT16>> columnIndexTable;
NNOffset32To<UnsizedArrayOf<FWORD>> array;
} s;
} u;
LNNOffsetTo<UnsizedArrayOf<FWORD>> vector;
NNOffset32To<UnsizedArrayOf<FWORD>> vector;
public:
DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 24);
};

View File

@ -30,6 +30,7 @@
#include "hb-open-type.hh"
#include "hb-aat-layout-common.hh"
#include "hb-ot-layout-common.hh"
#include "hb-ot-layout-gdef-table.hh"
#include "hb-aat-map.hh"
/*
@ -215,7 +216,9 @@ struct ContextualSubtable
hb_aat_apply_context_t *c_) :
ret (false),
c (c_),
gdef (*c->gdef_table),
mark_set (false),
has_glyph_classes (gdef.has_glyph_classes ()),
mark (0),
table (table_),
subs (table+table->substitutionTables) {}
@ -263,6 +266,9 @@ struct ContextualSubtable
{
buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
buffer->info[mark].codepoint = *replacement;
if (has_glyph_classes)
_hb_glyph_info_set_glyph_props (&buffer->info[mark],
gdef.get_glyph_props (*replacement));
ret = true;
}
@ -287,6 +293,9 @@ struct ContextualSubtable
if (replacement)
{
buffer->info[idx].codepoint = *replacement;
if (has_glyph_classes)
_hb_glyph_info_set_glyph_props (&buffer->info[idx],
gdef.get_glyph_props (*replacement));
ret = true;
}
@ -301,10 +310,12 @@ struct ContextualSubtable
bool ret;
private:
hb_aat_apply_context_t *c;
const OT::GDEF &gdef;
bool mark_set;
bool has_glyph_classes;
unsigned int mark;
const ContextualSubtable *table;
const UnsizedOffsetListOf<Lookup<HBGlyphID>, HBUINT, false> &subs;
const UnsizedListOfOffset16To<Lookup<HBGlyphID>, HBUINT, false> &subs;
};
bool apply (hb_aat_apply_context_t *c) const
@ -348,7 +359,7 @@ struct ContextualSubtable
protected:
StateTable<Types, EntryData>
machine;
NNOffsetTo<UnsizedOffsetListOf<Lookup<HBGlyphID>, HBUINT, false>, HBUINT>
NNOffsetTo<UnsizedListOfOffset16To<Lookup<HBGlyphID>, HBUINT, false>, HBUINT>
substitutionTables;
public:
DEFINE_SIZE_STATIC (20);
@ -599,6 +610,9 @@ struct NoncontextualSubtable
{
TRACE_APPLY (this);
const OT::GDEF &gdef (*c->gdef_table);
bool has_glyph_classes = gdef.has_glyph_classes ();
bool ret = false;
unsigned int num_glyphs = c->face->get_num_glyphs ();
@ -610,6 +624,9 @@ struct NoncontextualSubtable
if (replacement)
{
info[i].codepoint = *replacement;
if (has_glyph_classes)
_hb_glyph_info_set_glyph_props (&info[i],
gdef.get_glyph_props (*replacement));
ret = true;
}
}

View File

@ -58,7 +58,7 @@ struct opbdFormat0
bool get_bounds (hb_font_t *font, hb_codepoint_t glyph_id,
hb_glyph_extents_t *extents, const void *base) const
{
const OffsetTo<OpticalBounds> *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ());
const Offset16To<OpticalBounds> *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ());
if (!bounds_offset) return false;
const OpticalBounds &bounds = base+*bounds_offset;
@ -79,7 +79,7 @@ struct opbdFormat0
}
protected:
Lookup<OffsetTo<OpticalBounds>>
Lookup<Offset16To<OpticalBounds>>
lookupTable; /* Lookup table associating glyphs with the four
* int16 values for the left-side, top-side,
* right-side, and bottom-side optical bounds. */
@ -92,7 +92,7 @@ struct opbdFormat1
bool get_bounds (hb_font_t *font, hb_codepoint_t glyph_id,
hb_glyph_extents_t *extents, const void *base) const
{
const OffsetTo<OpticalBounds> *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ());
const Offset16To<OpticalBounds> *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ());
if (!bounds_offset) return false;
const OpticalBounds &bounds = base+*bounds_offset;
@ -116,7 +116,7 @@ struct opbdFormat1
}
protected:
Lookup<OffsetTo<OpticalBounds>>
Lookup<Offset16To<OpticalBounds>>
lookupTable; /* Lookup table associating glyphs with the four
* int16 values for the left-side, top-side,
* right-side, and bottom-side optical bounds. */

View File

@ -66,7 +66,7 @@ struct TrackTableEntry
NameID trackNameID; /* The 'name' table index for this track.
* (a short word or phrase like "loose"
* or "very tight") */
NNOffsetTo<UnsizedArrayOf<FWORD>>
NNOffset16To<UnsizedArrayOf<FWORD>>
valuesZ; /* Offset from start of tracking table to
* per-size tracking values for this track. */
@ -141,7 +141,7 @@ struct TrackData
protected:
HBUINT16 nTracks; /* Number of separate tracks included in this table. */
HBUINT16 nSizes; /* Number of point sizes included in this table. */
LNNOffsetTo<UnsizedArrayOf<HBFixed>>
NNOffset32To<UnsizedArrayOf<HBFixed>>
sizeTable; /* Offset from start of the tracking table to
* Array[nSizes] of size values.. */
UnsizedArrayOf<TrackTableEntry>
@ -212,10 +212,10 @@ struct trak
FixedVersion<>version; /* Version of the tracking table
* (0x00010000u for version 1.0). */
HBUINT16 format; /* Format of the tracking table (set to 0). */
OffsetTo<TrackData>
Offset16To<TrackData>
horizData; /* Offset from start of tracking table to TrackData
* for horizontal text (or 0 if none). */
OffsetTo<TrackData>
Offset16To<TrackData>
vertData; /* Offset from start of tracking table to TrackData
* for vertical text (or 0 if none). */
HBUINT16 reserved; /* Reserved. Set to 0. */

View File

@ -55,6 +55,7 @@ AAT::hb_aat_apply_context_t::hb_aat_apply_context_t (const hb_ot_shape_plan_t *p
buffer (buffer_),
sanitizer (),
ankr_table (&Null (AAT::ankr)),
gdef_table (face->table.GDEF->table),
lookup_index (0)
{
sanitizer.init (blob);
@ -79,7 +80,7 @@ AAT::hb_aat_apply_context_t::set_ankr_table (const AAT::ankr *ankr_table_)
* @short_description: Apple Advanced Typography Layout
* @include: hb-aat.h
*
* Functions for querying AAT Layout features in the font face.
* Functions for querying AAT Layout features in the font face.
*
* HarfBuzz supports all of the AAT tables used to implement shaping. Other
* AAT tables and their associated features are not supported.
@ -172,13 +173,13 @@ static const hb_aat_feature_mapping_t feature_mappings[] =
{HB_TAG ('z','e','r','o'), HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS, HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_ON, HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_OFF},
};
/**
/**
* hb_aat_layout_find_feature_mapping:
* @tag: The requested #hb_tag_t feature tag
*
* Fetches the AAT feature-and-selector combination that corresponds
* to a given OpenType feature tag.
*
*
* Return value: the AAT features and selectors corresponding to the
* OpenType feature tag queried
*
@ -248,7 +249,9 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
if (morx.has_data ())
{
AAT::hb_aat_apply_context_t c (plan, font, buffer, morx_blob);
if (!buffer->message (font, "start table morx")) return;
morx.apply (&c);
(void) buffer->message (font, "end table morx");
return;
}
@ -257,7 +260,9 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
if (mort.has_data ())
{
AAT::hb_aat_apply_context_t c (plan, font, buffer, mort_blob);
if (!buffer->message (font, "start table mort")) return;
mort.apply (&c);
(void) buffer->message (font, "end table mort");
return;
}
}
@ -313,8 +318,10 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
const AAT::kerx& kerx = *kerx_blob->as<AAT::kerx> ();
AAT::hb_aat_apply_context_t c (plan, font, buffer, kerx_blob);
if (!buffer->message (font, "start table kerx")) return;
c.set_ankr_table (font->face->table.ankr.get ());
kerx.apply (&c);
(void) buffer->message (font, "end table kerx");
}

View File

@ -50,7 +50,7 @@ struct FTStringRange
}
protected:
NNOffsetTo<UnsizedArrayOf<HBUINT8>>
NNOffset16To<UnsizedArrayOf<HBUINT8>>
tag; /* Offset from the start of the table to
* the beginning of the string */
HBUINT16 length; /* String length (in bytes) */
@ -80,7 +80,7 @@ struct ltag
protected:
HBUINT32 version; /* Table version; currently 1 */
HBUINT32 flags; /* Table flags; currently none defined */
LArrayOf<FTStringRange>
Array32Of<FTStringRange>
tagRanges; /* Range for each tag's string */
public:
DEFINE_SIZE_ARRAY (12, tagRanges);

View File

@ -760,6 +760,14 @@ static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
#define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
static inline void *
hb_memcpy (void *__restrict dst, const void *__restrict src, size_t len)
{
/* It's illegal to pass 0 as size to memcpy. */
if (unlikely (!len)) return dst;
return memcpy (dst, src, len);
}
static inline int
hb_memcmp (const void *a, const void *b, unsigned int len)
{
@ -1151,30 +1159,48 @@ hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *o
/* Operators. */
struct hb_bitwise_and
struct
{ HB_PARTIALIZE(2);
template <typename T> constexpr auto
operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & b)
}
HB_FUNCOBJ (hb_bitwise_and);
struct hb_bitwise_or
struct
{ HB_PARTIALIZE(2);
template <typename T> constexpr auto
operator () (const T &a, const T &b) const HB_AUTO_RETURN (a | b)
}
HB_FUNCOBJ (hb_bitwise_or);
struct hb_bitwise_xor
struct
{ HB_PARTIALIZE(2);
template <typename T> constexpr auto
operator () (const T &a, const T &b) const HB_AUTO_RETURN (a ^ b)
}
HB_FUNCOBJ (hb_bitwise_xor);
struct hb_bitwise_sub
struct
{ HB_PARTIALIZE(2);
template <typename T> constexpr auto
operator () (const T &a, const T &b) const HB_AUTO_RETURN (~a & b)
}
HB_FUNCOBJ (hb_bitwise_lt);
struct
{ HB_PARTIALIZE(2);
template <typename T> constexpr auto
operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & ~b)
}
HB_FUNCOBJ (hb_bitwise_sub);
HB_FUNCOBJ (hb_bitwise_gt); // aka sub
struct
{ HB_PARTIALIZE(2);
template <typename T> constexpr auto
operator () (const T &a, const T &b) const HB_AUTO_RETURN (~a | b)
}
HB_FUNCOBJ (hb_bitwise_le);
struct
{ HB_PARTIALIZE(2);
template <typename T> constexpr auto
operator () (const T &a, const T &b) const HB_AUTO_RETURN (a | ~b)
}
HB_FUNCOBJ (hb_bitwise_ge);
struct
{
template <typename T> constexpr auto
@ -1195,6 +1221,12 @@ struct
}
HB_FUNCOBJ (hb_sub);
struct
{ HB_PARTIALIZE(2);
template <typename T, typename T2> constexpr auto
operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (b - a)
}
HB_FUNCOBJ (hb_rsub);
struct
{ HB_PARTIALIZE(2);
template <typename T, typename T2> constexpr auto
operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a * b)

View File

@ -36,6 +36,14 @@
template <typename Type>
struct hb_sorted_array_t;
enum hb_not_found_t
{
HB_NOT_FOUND_DONT_STORE,
HB_NOT_FOUND_STORE,
HB_NOT_FOUND_STORE_CLOSEST,
};
template <typename Type>
struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
{
@ -139,7 +147,9 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
return lfind (x, &i) ? &this->arrayZ[i] : not_found;
}
template <typename T>
bool lfind (const T &x, unsigned *pos = nullptr) const
bool lfind (const T &x, unsigned *pos = nullptr,
hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
unsigned int to_store = (unsigned int) -1) const
{
for (unsigned i = 0; i < length; ++i)
if (hb_equal (x, this->arrayZ[i]))
@ -149,6 +159,22 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
return true;
}
if (pos)
{
switch (not_found)
{
case HB_NOT_FOUND_DONT_STORE:
break;
case HB_NOT_FOUND_STORE:
*pos = to_store;
break;
case HB_NOT_FOUND_STORE_CLOSEST:
*pos = length;
break;
}
}
return false;
}
@ -219,7 +245,7 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
unsigned P = sizeof (Type),
hb_enable_if (P == 1)>
const T *as () const
{ return length < hb_null_size (T) ? &Null (T) : reinterpret_cast<const T *> (arrayZ); }
{ return length < hb_min_size (T) ? &Null (T) : reinterpret_cast<const T *> (arrayZ); }
template <typename T,
unsigned P = sizeof (Type),
@ -231,9 +257,9 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
&& (unsigned int) (arrayZ + length - (const char *) p) >= size;
}
/* Only call if you allocated the underlying array using malloc() or similar. */
void free ()
{ ::free ((void *) arrayZ); arrayZ = nullptr; length = 0; }
/* Only call if you allocated the underlying array using hb_malloc() or similar. */
void fini ()
{ hb_free ((void *) arrayZ); arrayZ = nullptr; length = 0; }
template <typename hb_serialize_context_t>
hb_array_t copy (hb_serialize_context_t *c) const
@ -266,13 +292,6 @@ template <typename T, unsigned int length_> inline hb_array_t<T>
hb_array (T (&array_)[length_])
{ return hb_array_t<T> (array_); }
enum hb_bfind_not_found_t
{
HB_BFIND_NOT_FOUND_DONT_STORE,
HB_BFIND_NOT_FOUND_STORE,
HB_BFIND_NOT_FOUND_STORE_CLOSEST,
};
template <typename Type>
struct hb_sorted_array_t :
hb_iter_t<hb_sorted_array_t<Type>, Type&>,
@ -323,7 +342,7 @@ struct hb_sorted_array_t :
}
template <typename T>
bool bfind (const T &x, unsigned int *i = nullptr,
hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
unsigned int to_store = (unsigned int) -1) const
{
unsigned pos;
@ -339,14 +358,14 @@ struct hb_sorted_array_t :
{
switch (not_found)
{
case HB_BFIND_NOT_FOUND_DONT_STORE:
case HB_NOT_FOUND_DONT_STORE:
break;
case HB_BFIND_NOT_FOUND_STORE:
case HB_NOT_FOUND_STORE:
*i = to_store;
break;
case HB_BFIND_NOT_FOUND_STORE_CLOSEST:
case HB_NOT_FOUND_STORE_CLOSEST:
*i = pos;
break;
}

View File

@ -58,10 +58,15 @@ struct hb_bimap_t
void set (hb_codepoint_t lhs, hb_codepoint_t rhs)
{
if (in_error ()) return;
if (unlikely (lhs == HB_MAP_VALUE_INVALID)) return;
if (unlikely (rhs == HB_MAP_VALUE_INVALID)) { del (lhs); return; }
forw_map.set (lhs, rhs);
if (in_error ()) return;
back_map.set (rhs, lhs);
if (in_error ()) forw_map.del (lhs);
}
hb_codepoint_t get (hb_codepoint_t lhs) const { return forw_map.get (lhs); }

203
thirdparty/harfbuzz/src/hb-bit-page.hh vendored Normal file
View File

@ -0,0 +1,203 @@
/*
* Copyright © 2012,2017 Google, Inc.
* Copyright © 2021 Behdad Esfahbod
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_BIT_PAGE_HH
#define HB_BIT_PAGE_HH
#include "hb.hh"
struct hb_bit_page_t
{
void init0 () { v.clear (); }
void init1 () { v.clear (0xFF); }
constexpr unsigned len () const
{ return ARRAY_LENGTH_CONST (v); }
bool is_empty () const
{
for (unsigned int i = 0; i < len (); i++)
if (v[i])
return false;
return true;
}
void add (hb_codepoint_t g) { elt (g) |= mask (g); }
void del (hb_codepoint_t g) { elt (g) &= ~mask (g); }
void set (hb_codepoint_t g, bool v) { if (v) add (g); else del (g); }
bool get (hb_codepoint_t g) const { return elt (g) & mask (g); }
void add_range (hb_codepoint_t a, hb_codepoint_t b)
{
elt_t *la = &elt (a);
elt_t *lb = &elt (b);
if (la == lb)
*la |= (mask (b) << 1) - mask(a);
else
{
*la |= ~(mask (a) - 1);
la++;
memset (la, 0xff, (char *) lb - (char *) la);
*lb |= ((mask (b) << 1) - 1);
}
}
void del_range (hb_codepoint_t a, hb_codepoint_t b)
{
elt_t *la = &elt (a);
elt_t *lb = &elt (b);
if (la == lb)
*la &= ~((mask (b) << 1) - mask(a));
else
{
*la &= mask (a) - 1;
la++;
memset (la, 0, (char *) lb - (char *) la);
*lb &= ~((mask (b) << 1) - 1);
}
}
void set_range (hb_codepoint_t a, hb_codepoint_t b, bool v)
{ if (v) add_range (a, b); else del_range (a, b); }
bool is_equal (const hb_bit_page_t &other) const
{
return 0 == hb_memcmp (&v, &other.v, sizeof (v));
}
bool is_subset (const hb_bit_page_t &larger_page) const
{
for (unsigned i = 0; i < len (); i++)
if (~larger_page.v[i] & v[i])
return false;
return true;
}
unsigned int get_population () const
{
unsigned int pop = 0;
for (unsigned int i = 0; i < len (); i++)
pop += hb_popcount (v[i]);
return pop;
}
bool next (hb_codepoint_t *codepoint) const
{
unsigned int m = (*codepoint + 1) & MASK;
if (!m)
{
*codepoint = INVALID;
return false;
}
unsigned int i = m / ELT_BITS;
unsigned int j = m & ELT_MASK;
const elt_t vv = v[i] & ~((elt_t (1) << j) - 1);
for (const elt_t *p = &vv; i < len (); p = &v[++i])
if (*p)
{
*codepoint = i * ELT_BITS + elt_get_min (*p);
return true;
}
*codepoint = INVALID;
return false;
}
bool previous (hb_codepoint_t *codepoint) const
{
unsigned int m = (*codepoint - 1) & MASK;
if (m == MASK)
{
*codepoint = INVALID;
return false;
}
unsigned int i = m / ELT_BITS;
unsigned int j = m & ELT_MASK;
/* Fancy mask to avoid shifting by elt_t bitsize, which is undefined. */
const elt_t mask = j < 8 * sizeof (elt_t) - 1 ?
((elt_t (1) << (j + 1)) - 1) :
(elt_t) -1;
const elt_t vv = v[i] & mask;
const elt_t *p = &vv;
while (true)
{
if (*p)
{
*codepoint = i * ELT_BITS + elt_get_max (*p);
return true;
}
if ((int) i <= 0) break;
p = &v[--i];
}
*codepoint = INVALID;
return false;
}
hb_codepoint_t get_min () const
{
for (unsigned int i = 0; i < len (); i++)
if (v[i])
return i * ELT_BITS + elt_get_min (v[i]);
return INVALID;
}
hb_codepoint_t get_max () const
{
for (int i = len () - 1; i >= 0; i--)
if (v[i])
return i * ELT_BITS + elt_get_max (v[i]);
return 0;
}
static constexpr hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
typedef unsigned long long elt_t;
static constexpr unsigned PAGE_BITS = 512;
static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");
static unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); }
static unsigned int elt_get_max (const elt_t &elt) { return hb_bit_storage (elt) - 1; }
typedef hb_vector_size_t<elt_t, PAGE_BITS / 8> vector_t;
static constexpr unsigned ELT_BITS = sizeof (elt_t) * 8;
static constexpr unsigned ELT_MASK = ELT_BITS - 1;
static constexpr unsigned BITS = sizeof (vector_t) * 8;
static constexpr unsigned MASK = BITS - 1;
static_assert ((unsigned) PAGE_BITS == (unsigned) BITS, "");
elt_t &elt (hb_codepoint_t g) { return v[(g & MASK) / ELT_BITS]; }
const elt_t& elt (hb_codepoint_t g) const { return v[(g & MASK) / ELT_BITS]; }
static constexpr elt_t mask (hb_codepoint_t g) { return elt_t (1) << (g & ELT_MASK); }
vector_t v;
};
static_assert (hb_bit_page_t::PAGE_BITS == sizeof (hb_bit_page_t) * 8, "");
#endif /* HB_BIT_PAGE_HH */

View File

@ -0,0 +1,354 @@
/*
* Copyright © 2012,2017 Google, Inc.
* Copyright © 2021 Behdad Esfahbod
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_BIT_SET_INVERTIBLE_HH
#define HB_BIT_SET_INVERTIBLE_HH
#include "hb.hh"
#include "hb-bit-set.hh"
struct hb_bit_set_invertible_t
{
hb_bit_set_t s;
bool inverted;
hb_bit_set_invertible_t () { init (); }
~hb_bit_set_invertible_t () { fini (); }
void init () { s.init (); inverted = false; }
void fini () { s.fini (); }
void err () { s.err (); }
bool in_error () const { return s.in_error (); }
explicit operator bool () const { return !is_empty (); }
void reset ()
{
s.reset ();
inverted = false;
}
void clear ()
{
s.clear ();
if (likely (s.successful))
inverted = false;
}
void invert ()
{
if (likely (s.successful))
inverted = !inverted;
}
bool is_empty () const
{
hb_codepoint_t v = INVALID;
next (&v);
return v == INVALID;
}
hb_codepoint_t get_min () const
{
hb_codepoint_t v = INVALID;
next (&v);
return v;
}
hb_codepoint_t get_max () const
{
hb_codepoint_t v = INVALID;
previous (&v);
return v;
}
unsigned int get_population () const
{ return inverted ? INVALID - s.get_population () : s.get_population (); }
void add (hb_codepoint_t g) { unlikely (inverted) ? s.del (g) : s.add (g); }
bool add_range (hb_codepoint_t a, hb_codepoint_t b)
{ return unlikely (inverted) ? (s.del_range (a, b), true) : s.add_range (a, b); }
template <typename T>
void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
{ inverted ? s.del_array (array, count, stride) : s.add_array (array, count, stride); }
template <typename T>
void add_array (const hb_array_t<const T>& arr) { add_array (&arr, arr.len ()); }
/* Might return false if array looks unsorted.
* Used for faster rejection of corrupt data. */
template <typename T>
bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
{ return inverted ? s.del_sorted_array (array, count, stride) : s.add_sorted_array (array, count, stride); }
template <typename T>
bool add_sorted_array (const hb_sorted_array_t<const T>& arr) { return add_sorted_array (&arr, arr.len ()); }
void del (hb_codepoint_t g) { unlikely (inverted) ? s.add (g) : s.del (g); }
void del_range (hb_codepoint_t a, hb_codepoint_t b)
{ unlikely (inverted) ? (void) s.add_range (a, b) : s.del_range (a, b); }
bool get (hb_codepoint_t g) const { return s.get (g) ^ inverted; }
/* Has interface. */
static constexpr bool SENTINEL = false;
typedef bool value_t;
value_t operator [] (hb_codepoint_t k) const { return get (k); }
bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
/* Predicate. */
bool operator () (hb_codepoint_t k) const { return has (k); }
/* Sink interface. */
hb_bit_set_invertible_t& operator << (hb_codepoint_t v)
{ add (v); return *this; }
hb_bit_set_invertible_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range)
{ add_range (range.first, range.second); return *this; }
bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
{
hb_codepoint_t c = first - 1;
return next (&c) && c <= last;
}
void set (const hb_bit_set_invertible_t &other)
{
s.set (other.s);
if (likely (s.successful))
inverted = other.inverted;
}
bool is_equal (const hb_bit_set_invertible_t &other) const
{
if (likely (inverted == other.inverted))
return s.is_equal (other.s);
else
{
/* TODO Add iter_ranges() and use here. */
auto it1 = iter ();
auto it2 = other.iter ();
return hb_all (+ hb_zip (it1, it2)
| hb_map ([](hb_pair_t<hb_codepoint_t, hb_codepoint_t> _) { return _.first == _.second; }));
}
}
bool is_subset (const hb_bit_set_invertible_t &larger_set) const
{
if (unlikely (inverted != larger_set.inverted))
return hb_all (hb_iter (s) | hb_map (larger_set.s));
else
return unlikely (inverted) ? larger_set.s.is_subset (s) : s.is_subset (larger_set.s);
}
protected:
template <typename Op>
void process (const Op& op, const hb_bit_set_invertible_t &other)
{ s.process (op, other.s); }
public:
void union_ (const hb_bit_set_invertible_t &other)
{
if (likely (inverted == other.inverted))
{
if (unlikely (inverted))
process (hb_bitwise_and, other);
else
process (hb_bitwise_or, other); /* Main branch. */
}
else
{
if (unlikely (inverted))
process (hb_bitwise_gt, other);
else
process (hb_bitwise_lt, other);
}
if (likely (s.successful))
inverted = inverted || other.inverted;
}
void intersect (const hb_bit_set_invertible_t &other)
{
if (likely (inverted == other.inverted))
{
if (unlikely (inverted))
process (hb_bitwise_or, other);
else
process (hb_bitwise_and, other); /* Main branch. */
}
else
{
if (unlikely (inverted))
process (hb_bitwise_lt, other);
else
process (hb_bitwise_gt, other);
}
if (likely (s.successful))
inverted = inverted && other.inverted;
}
void subtract (const hb_bit_set_invertible_t &other)
{
if (likely (inverted == other.inverted))
{
if (unlikely (inverted))
process (hb_bitwise_lt, other);
else
process (hb_bitwise_gt, other); /* Main branch. */
}
else
{
if (unlikely (inverted))
process (hb_bitwise_or, other);
else
process (hb_bitwise_and, other);
}
if (likely (s.successful))
inverted = inverted && !other.inverted;
}
void symmetric_difference (const hb_bit_set_invertible_t &other)
{
process (hb_bitwise_xor, other);
if (likely (s.successful))
inverted = inverted ^ other.inverted;
}
bool next (hb_codepoint_t *codepoint) const
{
if (likely (!inverted))
return s.next (codepoint);
auto old = *codepoint;
if (unlikely (old + 1 == INVALID))
{
*codepoint = INVALID;
return false;
}
auto v = old;
s.next (&v);
if (old + 1 < v)
{
*codepoint = old + 1;
return true;
}
v = old;
s.next_range (&old, &v);
*codepoint = v + 1;
return *codepoint != INVALID;
}
bool previous (hb_codepoint_t *codepoint) const
{
if (likely (!inverted))
return s.previous (codepoint);
auto old = *codepoint;
if (unlikely (old - 1 == INVALID))
{
*codepoint = INVALID;
return false;
}
auto v = old;
s.previous (&v);
if (old - 1 > v || v == INVALID)
{
*codepoint = old - 1;
return true;
}
v = old;
s.previous_range (&v, &old);
*codepoint = v - 1;
return *codepoint != INVALID;
}
bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
{
if (likely (!inverted))
return s.next_range (first, last);
if (!next (last))
{
*last = *first = INVALID;
return false;
}
*first = *last;
s.next (last);
--*last;
return true;
}
bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const
{
if (likely (!inverted))
return s.previous_range (first, last);
if (!previous (first))
{
*last = *first = INVALID;
return false;
}
*last = *first;
s.previous (first);
++*first;
return true;
}
static constexpr hb_codepoint_t INVALID = hb_bit_set_t::INVALID;
/*
* Iterator implementation.
*/
struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
{
static constexpr bool is_sorted_iterator = true;
iter_t (const hb_bit_set_invertible_t &s_ = Null (hb_bit_set_invertible_t),
bool init = true) : s (&s_), v (INVALID), l(0)
{
if (init)
{
l = s->get_population () + 1;
__next__ ();
}
}
typedef hb_codepoint_t __item_t__;
hb_codepoint_t __item__ () const { return v; }
bool __more__ () const { return v != INVALID; }
void __next__ () { s->next (&v); if (l) l--; }
void __prev__ () { s->previous (&v); }
unsigned __len__ () const { return l; }
iter_t end () const { return iter_t (*s, false); }
bool operator != (const iter_t& o) const
{ return s != o.s || v != o.v; }
protected:
const hb_bit_set_invertible_t *s;
hb_codepoint_t v;
unsigned l;
};
iter_t iter () const { return iter_t (*this); }
operator iter_t () const { return iter (); }
};
#endif /* HB_BIT_SET_INVERTIBLE_HH */

808
thirdparty/harfbuzz/src/hb-bit-set.hh vendored Normal file
View File

@ -0,0 +1,808 @@
/*
* Copyright © 2012,2017 Google, Inc.
* Copyright © 2021 Behdad Esfahbod
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_BIT_SET_HH
#define HB_BIT_SET_HH
#include "hb.hh"
#include "hb-bit-page.hh"
#include "hb-machinery.hh"
struct hb_bit_set_t
{
hb_bit_set_t () { init (); }
~hb_bit_set_t () { fini (); }
hb_bit_set_t (const hb_bit_set_t& other) : hb_bit_set_t () { set (other); }
void operator= (const hb_bit_set_t& other) { set (other); }
// TODO Add move construtor/assign
// TODO Add constructor for Iterator; with specialization for (sorted) vector / array?
void init ()
{
successful = true;
population = 0;
last_page_lookup = 0;
page_map.init ();
pages.init ();
}
void fini ()
{
page_map.fini ();
pages.fini ();
}
using page_t = hb_bit_page_t;
struct page_map_t
{
int cmp (const page_map_t &o) const { return cmp (o.major); }
int cmp (uint32_t o_major) const { return (int) o_major - (int) major; }
uint32_t major;
uint32_t index;
};
bool successful; /* Allocations successful */
mutable unsigned int population;
mutable unsigned int last_page_lookup;
hb_sorted_vector_t<page_map_t> page_map;
hb_vector_t<page_t> pages;
void err () { if (successful) successful = false; } /* TODO Remove */
bool in_error () const { return !successful; }
bool resize (unsigned int count)
{
if (unlikely (!successful)) return false;
if (unlikely (!pages.resize (count) || !page_map.resize (count)))
{
pages.resize (page_map.length);
successful = false;
return false;
}
return true;
}
void reset ()
{
successful = true;
clear ();
}
void clear ()
{
resize (0);
if (likely (successful))
population = 0;
}
bool is_empty () const
{
unsigned int count = pages.length;
for (unsigned int i = 0; i < count; i++)
if (!pages[i].is_empty ())
return false;
return true;
}
explicit operator bool () const { return !is_empty (); }
private:
void dirty () { population = UINT_MAX; }
public:
void add (hb_codepoint_t g)
{
if (unlikely (!successful)) return;
if (unlikely (g == INVALID)) return;
dirty ();
page_t *page = page_for (g, true); if (unlikely (!page)) return;
page->add (g);
}
bool add_range (hb_codepoint_t a, hb_codepoint_t b)
{
if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
if (unlikely (a > b || a == INVALID || b == INVALID)) return false;
dirty ();
unsigned int ma = get_major (a);
unsigned int mb = get_major (b);
if (ma == mb)
{
page_t *page = page_for (a, true); if (unlikely (!page)) return false;
page->add_range (a, b);
}
else
{
page_t *page = page_for (a, true); if (unlikely (!page)) return false;
page->add_range (a, major_start (ma + 1) - 1);
for (unsigned int m = ma + 1; m < mb; m++)
{
page = page_for (major_start (m), true); if (unlikely (!page)) return false;
page->init1 ();
}
page = page_for (b, true); if (unlikely (!page)) return false;
page->add_range (major_start (mb), b);
}
return true;
}
template <typename T>
void set_array (bool v, const T *array, unsigned int count, unsigned int stride=sizeof(T))
{
if (unlikely (!successful)) return;
if (!count) return;
dirty ();
hb_codepoint_t g = *array;
while (count)
{
unsigned int m = get_major (g);
page_t *page = page_for (g, v); if (unlikely (v && !page)) return;
unsigned int start = major_start (m);
unsigned int end = major_start (m + 1);
do
{
if (v || page) /* The v check is to optimize out the page check if v is true. */
page->set (g, v);
array = &StructAtOffsetUnaligned<T> (array, stride);
count--;
}
while (count && (g = *array, start <= g && g < end));
}
}
template <typename T>
void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
{ set_array (true, array, count, stride); }
template <typename T>
void add_array (const hb_array_t<const T>& arr) { add_array (&arr, arr.len ()); }
template <typename T>
void del_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
{ set_array (false, array, count, stride); }
template <typename T>
void del_array (const hb_array_t<const T>& arr) { del_array (&arr, arr.len ()); }
/* Might return false if array looks unsorted.
* Used for faster rejection of corrupt data. */
template <typename T>
bool set_sorted_array (bool v, const T *array, unsigned int count, unsigned int stride=sizeof(T))
{
if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
if (!count) return true;
dirty ();
hb_codepoint_t g = *array;
hb_codepoint_t last_g = g;
while (count)
{
unsigned int m = get_major (g);
page_t *page = page_for (g, v); if (unlikely (v && !page)) return false;
unsigned int end = major_start (m + 1);
do
{
/* If we try harder we can change the following comparison to <=;
* Not sure if it's worth it. */
if (g < last_g) return false;
last_g = g;
if (v || page) /* The v check is to optimize out the page check if v is true. */
page->add (g);
array = (const T *) ((const char *) array + stride);
count--;
}
while (count && (g = *array, g < end));
}
return true;
}
template <typename T>
bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
{ return set_sorted_array (true, array, count, stride); }
template <typename T>
bool add_sorted_array (const hb_sorted_array_t<const T>& arr) { return add_sorted_array (&arr, arr.len ()); }
template <typename T>
bool del_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
{ return set_sorted_array (false, array, count, stride); }
template <typename T>
bool del_sorted_array (const hb_sorted_array_t<const T>& arr) { return del_sorted_array (&arr, arr.len ()); }
void del (hb_codepoint_t g)
{
if (unlikely (!successful)) return;
page_t *page = page_for (g);
if (!page)
return;
dirty ();
page->del (g);
}
private:
void del_pages (int ds, int de)
{
if (ds <= de)
{
// Pre-allocate the workspace that compact() will need so we can bail on allocation failure
// before attempting to rewrite the page map.
hb_vector_t<unsigned> compact_workspace;
if (unlikely (!allocate_compact_workspace (compact_workspace))) return;
unsigned int write_index = 0;
for (unsigned int i = 0; i < page_map.length; i++)
{
int m = (int) page_map[i].major;
if (m < ds || de < m)
page_map[write_index++] = page_map[i];
}
compact (compact_workspace, write_index);
resize (write_index);
}
}
public:
void del_range (hb_codepoint_t a, hb_codepoint_t b)
{
if (unlikely (!successful)) return;
if (unlikely (a > b || a == INVALID)) return;
dirty ();
unsigned int ma = get_major (a);
unsigned int mb = get_major (b);
/* Delete pages from ds through de if ds <= de. */
int ds = (a == major_start (ma))? (int) ma: (int) (ma + 1);
int de = (b + 1 == major_start (mb + 1))? (int) mb: ((int) mb - 1);
if (ds > de || (int) ma < ds)
{
page_t *page = page_for (a);
if (page)
{
if (ma == mb)
page->del_range (a, b);
else
page->del_range (a, major_start (ma + 1) - 1);
}
}
if (de < (int) mb && ma != mb)
{
page_t *page = page_for (b);
if (page)
page->del_range (major_start (mb), b);
}
del_pages (ds, de);
}
bool get (hb_codepoint_t g) const
{
const page_t *page = page_for (g);
if (!page)
return false;
return page->get (g);
}
/* Has interface. */
static constexpr bool SENTINEL = false;
typedef bool value_t;
value_t operator [] (hb_codepoint_t k) const { return get (k); }
bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
/* Predicate. */
bool operator () (hb_codepoint_t k) const { return has (k); }
/* Sink interface. */
hb_bit_set_t& operator << (hb_codepoint_t v)
{ add (v); return *this; }
hb_bit_set_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range)
{ add_range (range.first, range.second); return *this; }
bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
{
hb_codepoint_t c = first - 1;
return next (&c) && c <= last;
}
void set (const hb_bit_set_t &other)
{
if (unlikely (!successful)) return;
unsigned int count = other.pages.length;
if (unlikely (!resize (count)))
return;
population = other.population;
/* TODO switch to vector operator =. */
hb_memcpy ((void *) pages, (const void *) other.pages, count * pages.item_size);
hb_memcpy ((void *) page_map, (const void *) other.page_map, count * page_map.item_size);
}
bool is_equal (const hb_bit_set_t &other) const
{
if (has_population () && other.has_population () &&
get_population () != other.get_population ())
return false;
unsigned int na = pages.length;
unsigned int nb = other.pages.length;
unsigned int a = 0, b = 0;
for (; a < na && b < nb; )
{
if (page_at (a).is_empty ()) { a++; continue; }
if (other.page_at (b).is_empty ()) { b++; continue; }
if (page_map[a].major != other.page_map[b].major ||
!page_at (a).is_equal (other.page_at (b)))
return false;
a++;
b++;
}
for (; a < na; a++)
if (!page_at (a).is_empty ()) { return false; }
for (; b < nb; b++)
if (!other.page_at (b).is_empty ()) { return false; }
return true;
}
bool is_subset (const hb_bit_set_t &larger_set) const
{
if (has_population () && larger_set.has_population () &&
get_population () != larger_set.get_population ())
return false;
uint32_t spi = 0;
for (uint32_t lpi = 0; spi < page_map.length && lpi < larger_set.page_map.length; lpi++)
{
uint32_t spm = page_map[spi].major;
uint32_t lpm = larger_set.page_map[lpi].major;
auto sp = page_at (spi);
auto lp = larger_set.page_at (lpi);
if (spm < lpm && !sp.is_empty ())
return false;
if (lpm < spm)
continue;
if (!sp.is_subset (lp))
return false;
spi++;
}
while (spi < page_map.length)
if (!page_at (spi++).is_empty ())
return false;
return true;
}
private:
bool allocate_compact_workspace (hb_vector_t<unsigned>& workspace)
{
if (unlikely (!workspace.resize (pages.length)))
{
successful = false;
return false;
}
return true;
}
/*
* workspace should be a pre-sized vector allocated to hold at exactly pages.length
* elements.
*/
void compact (hb_vector_t<unsigned>& workspace,
unsigned int length)
{
assert(workspace.length == pages.length);
hb_vector_t<unsigned>& old_index_to_page_map_index = workspace;
hb_fill (old_index_to_page_map_index.writer(), 0xFFFFFFFF);
for (unsigned i = 0; i < length; i++)
old_index_to_page_map_index[page_map[i].index] = i;
compact_pages (old_index_to_page_map_index);
}
void compact_pages (const hb_vector_t<unsigned>& old_index_to_page_map_index)
{
unsigned int write_index = 0;
for (unsigned int i = 0; i < pages.length; i++)
{
if (old_index_to_page_map_index[i] == 0xFFFFFFFF) continue;
if (write_index < i)
pages[write_index] = pages[i];
page_map[old_index_to_page_map_index[i]].index = write_index;
write_index++;
}
}
public:
template <typename Op>
void process (const Op& op, const hb_bit_set_t &other)
{
const bool passthru_left = op (1, 0);
const bool passthru_right = op (0, 1);
if (unlikely (!successful)) return;
dirty ();
unsigned int na = pages.length;
unsigned int nb = other.pages.length;
unsigned int next_page = na;
unsigned int count = 0, newCount = 0;
unsigned int a = 0, b = 0;
unsigned int write_index = 0;
// Pre-allocate the workspace that compact() will need so we can bail on allocation failure
// before attempting to rewrite the page map.
hb_vector_t<unsigned> compact_workspace;
if (!passthru_left && unlikely (!allocate_compact_workspace (compact_workspace))) return;
for (; a < na && b < nb; )
{
if (page_map[a].major == other.page_map[b].major)
{
if (!passthru_left)
{
// Move page_map entries that we're keeping from the left side set
// to the front of the page_map vector. This isn't necessary if
// passthru_left is set since no left side pages will be removed
// in that case.
if (write_index < a)
page_map[write_index] = page_map[a];
write_index++;
}
count++;
a++;
b++;
}
else if (page_map[a].major < other.page_map[b].major)
{
if (passthru_left)
count++;
a++;
}
else
{
if (passthru_right)
count++;
b++;
}
}
if (passthru_left)
count += na - a;
if (passthru_right)
count += nb - b;
if (!passthru_left)
{
na = write_index;
next_page = write_index;
compact (compact_workspace, write_index);
}
if (unlikely (!resize (count)))
return;
newCount = count;
/* Process in-place backward. */
a = na;
b = nb;
for (; a && b; )
{
if (page_map[a - 1].major == other.page_map[b - 1].major)
{
a--;
b--;
count--;
page_map[count] = page_map[a];
page_at (count).v = op (page_at (a).v, other.page_at (b).v);
}
else if (page_map[a - 1].major > other.page_map[b - 1].major)
{
a--;
if (passthru_left)
{
count--;
page_map[count] = page_map[a];
}
}
else
{
b--;
if (passthru_right)
{
count--;
page_map[count].major = other.page_map[b].major;
page_map[count].index = next_page++;
page_at (count).v = other.page_at (b).v;
}
}
}
if (passthru_left)
while (a)
{
a--;
count--;
page_map[count] = page_map [a];
}
if (passthru_right)
while (b)
{
b--;
count--;
page_map[count].major = other.page_map[b].major;
page_map[count].index = next_page++;
page_at (count).v = other.page_at (b).v;
}
assert (!count);
resize (newCount);
}
void union_ (const hb_bit_set_t &other) { process (hb_bitwise_or, other); }
void intersect (const hb_bit_set_t &other) { process (hb_bitwise_and, other); }
void subtract (const hb_bit_set_t &other) { process (hb_bitwise_gt, other); }
void symmetric_difference (const hb_bit_set_t &other) { process (hb_bitwise_xor, other); }
bool next (hb_codepoint_t *codepoint) const
{
// TODO: this should be merged with prev() as both implementations
// are very similar.
if (unlikely (*codepoint == INVALID)) {
*codepoint = get_min ();
return *codepoint != INVALID;
}
const auto* page_map_array = page_map.arrayZ;
unsigned int major = get_major (*codepoint);
unsigned int i = last_page_lookup;
if (unlikely (i >= page_map.length || page_map_array[i].major != major))
{
page_map.bfind (major, &i, HB_NOT_FOUND_STORE_CLOSEST);
if (i >= page_map.length) {
*codepoint = INVALID;
return false;
}
}
const auto* pages_array = pages.arrayZ;
const page_map_t &current = page_map_array[i];
if (likely (current.major == major))
{
if (pages_array[current.index].next (codepoint))
{
*codepoint += current.major * page_t::PAGE_BITS;
last_page_lookup = i;
return true;
}
i++;
}
for (; i < page_map.length; i++)
{
const page_map_t &current = page_map.arrayZ[i];
hb_codepoint_t m = pages_array[current.index].get_min ();
if (m != INVALID)
{
*codepoint = current.major * page_t::PAGE_BITS + m;
last_page_lookup = i;
return true;
}
}
last_page_lookup = 0;
*codepoint = INVALID;
return false;
}
bool previous (hb_codepoint_t *codepoint) const
{
if (unlikely (*codepoint == INVALID)) {
*codepoint = get_max ();
return *codepoint != INVALID;
}
page_map_t map = {get_major (*codepoint), 0};
unsigned int i;
page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST);
if (i < page_map.length && page_map[i].major == map.major)
{
if (pages[page_map[i].index].previous (codepoint))
{
*codepoint += page_map[i].major * page_t::PAGE_BITS;
return true;
}
}
i--;
for (; (int) i >= 0; i--)
{
hb_codepoint_t m = pages[page_map[i].index].get_max ();
if (m != INVALID)
{
*codepoint = page_map[i].major * page_t::PAGE_BITS + m;
return true;
}
}
*codepoint = INVALID;
return false;
}
bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
{
hb_codepoint_t i;
i = *last;
if (!next (&i))
{
*last = *first = INVALID;
return false;
}
/* TODO Speed up. */
*last = *first = i;
while (next (&i) && i == *last + 1)
(*last)++;
return true;
}
bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const
{
hb_codepoint_t i;
i = *first;
if (!previous (&i))
{
*last = *first = INVALID;
return false;
}
/* TODO Speed up. */
*last = *first = i;
while (previous (&i) && i == *first - 1)
(*first)--;
return true;
}
bool has_population () const { return population != UINT_MAX; }
unsigned int get_population () const
{
if (has_population ())
return population;
unsigned int pop = 0;
unsigned int count = pages.length;
for (unsigned int i = 0; i < count; i++)
pop += pages[i].get_population ();
population = pop;
return pop;
}
hb_codepoint_t get_min () const
{
unsigned count = pages.length;
for (unsigned i = 0; i < count; i++)
{
const auto& map = page_map[i];
const auto& page = pages[map.index];
if (!page.is_empty ())
return map.major * page_t::PAGE_BITS + page.get_min ();
}
return INVALID;
}
hb_codepoint_t get_max () const
{
unsigned count = pages.length;
for (signed i = count - 1; i >= 0; i--)
{
const auto& map = page_map[(unsigned) i];
const auto& page = pages[map.index];
if (!page.is_empty ())
return map.major * page_t::PAGE_BITS + page.get_max ();
}
return INVALID;
}
static constexpr hb_codepoint_t INVALID = page_t::INVALID;
/*
* Iterator implementation.
*/
struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
{
static constexpr bool is_sorted_iterator = true;
iter_t (const hb_bit_set_t &s_ = Null (hb_bit_set_t),
bool init = true) : s (&s_), v (INVALID), l(0)
{
if (init)
{
l = s->get_population () + 1;
__next__ ();
}
}
typedef hb_codepoint_t __item_t__;
hb_codepoint_t __item__ () const { return v; }
bool __more__ () const { return v != INVALID; }
void __next__ () { s->next (&v); if (l) l--; }
void __prev__ () { s->previous (&v); }
unsigned __len__ () const { return l; }
iter_t end () const { return iter_t (*s, false); }
bool operator != (const iter_t& o) const
{ return s != o.s || v != o.v; }
protected:
const hb_bit_set_t *s;
hb_codepoint_t v;
unsigned l;
};
iter_t iter () const { return iter_t (*this); }
operator iter_t () const { return iter (); }
protected:
page_t *page_for (hb_codepoint_t g, bool insert = false)
{
page_map_t map = {get_major (g), pages.length};
unsigned int i;
if (!page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST))
{
if (!insert)
return nullptr;
if (unlikely (!resize (pages.length + 1)))
return nullptr;
pages[map.index].init0 ();
memmove (page_map + i + 1,
page_map + i,
(page_map.length - 1 - i) * page_map.item_size);
page_map[i] = map;
}
return &pages[page_map[i].index];
}
const page_t *page_for (hb_codepoint_t g) const
{
page_map_t key = {get_major (g)};
const page_map_t *found = page_map.bsearch (key);
if (found)
return &pages[found->index];
return nullptr;
}
page_t &page_at (unsigned int i) { return pages[page_map[i].index]; }
const page_t &page_at (unsigned int i) const { return pages[page_map[i].index]; }
unsigned int get_major (hb_codepoint_t g) const { return g / page_t::PAGE_BITS; }
hb_codepoint_t major_start (unsigned int major) const { return major * page_t::PAGE_BITS; }
};
#endif /* HB_BIT_SET_HH */

View File

@ -72,16 +72,54 @@ hb_blob_create (const char *data,
void *user_data,
hb_destroy_func_t destroy)
{
hb_blob_t *blob;
if (!length ||
length >= 1u << 31 ||
!(blob = hb_object_create<hb_blob_t> ())) {
if (!length)
{
if (destroy)
destroy (user_data);
return hb_blob_get_empty ();
}
hb_blob_t *blob = hb_blob_create_or_fail (data, length, mode,
user_data, destroy);
return likely (blob) ? blob : hb_blob_get_empty ();
}
/**
* hb_blob_create_or_fail: (skip)
* @data: Pointer to blob data.
* @length: Length of @data in bytes.
* @mode: Memory mode for @data.
* @user_data: Data parameter to pass to @destroy.
* @destroy: (nullable): Callback to call when @data is not needed anymore.
*
* Creates a new "blob" object wrapping @data. The @mode parameter is used
* to negotiate ownership and lifecycle of @data.
*
* Note that this function returns a freshly-allocated empty blob even if @length
* is zero. This is in contrast to hb_blob_create(), which returns the singleton
* empty blob (as returned by hb_blob_get_empty()) if @length is zero.
*
* Return value: New blob, or %NULL if failed. Destroy with hb_blob_destroy().
*
* Since: 2.8.2
**/
hb_blob_t *
hb_blob_create_or_fail (const char *data,
unsigned int length,
hb_memory_mode_t mode,
void *user_data,
hb_destroy_func_t destroy)
{
hb_blob_t *blob;
if (length >= 1u << 31 ||
!(blob = hb_object_create<hb_blob_t> ()))
{
if (destroy)
destroy (user_data);
return nullptr;
}
blob->data = data;
blob->length = length;
blob->mode = mode;
@ -91,9 +129,10 @@ hb_blob_create (const char *data,
if (blob->mode == HB_MEMORY_MODE_DUPLICATE) {
blob->mode = HB_MEMORY_MODE_READONLY;
if (!blob->try_make_writable ()) {
if (!blob->try_make_writable ())
{
hb_blob_destroy (blob);
return hb_blob_get_empty ();
return nullptr;
}
}
@ -226,7 +265,7 @@ hb_blob_destroy (hb_blob_t *blob)
blob->fini_shallow ();
free (blob);
hb_free (blob);
}
/**
@ -452,7 +491,7 @@ hb_blob_t::try_make_writable ()
char *new_data;
new_data = (char *) malloc (this->length);
new_data = (char *) hb_malloc (this->length);
if (unlikely (!new_data))
return false;
@ -463,7 +502,7 @@ hb_blob_t::try_make_writable ()
this->mode = HB_MEMORY_MODE_WRITABLE;
this->data = new_data;
this->user_data = new_data;
this->destroy = free;
this->destroy = hb_free;
return true;
}
@ -517,7 +556,7 @@ _hb_mapped_file_destroy (void *file_)
assert (0); // If we don't have mmap we shouldn't reach here
#endif
free (file);
hb_free (file);
}
#endif
@ -528,7 +567,7 @@ _open_resource_fork (const char *file_name, hb_mapped_file_t *file)
size_t name_len = strlen (file_name);
size_t len = name_len + sizeof (_PATH_RSRCFORKSPEC);
char *rsrc_name = (char *) malloc (len);
char *rsrc_name = (char *) hb_malloc (len);
if (unlikely (!rsrc_name)) return -1;
strncpy (rsrc_name, file_name, name_len);
@ -536,7 +575,7 @@ _open_resource_fork (const char *file_name, hb_mapped_file_t *file)
sizeof (_PATH_RSRCFORKSPEC) - 1);
int fd = open (rsrc_name, O_RDONLY | O_BINARY, 0);
free (rsrc_name);
hb_free (rsrc_name);
if (fd != -1)
{
@ -561,17 +600,37 @@ _open_resource_fork (const char *file_name, hb_mapped_file_t *file)
* Creates a new blob containing the data from the
* specified binary font file.
*
* Returns: An #hb_blob_t pointer with the content of the file
* Returns: An #hb_blob_t pointer with the content of the file,
* or hb_blob_get_empty() if failed.
*
* Since: 1.7.7
**/
hb_blob_t *
hb_blob_create_from_file (const char *file_name)
{
hb_blob_t *blob = hb_blob_create_from_file_or_fail (file_name);
return likely (blob) ? blob : hb_blob_get_empty ();
}
/**
* hb_blob_create_from_file_or_fail:
* @file_name: A font filename
*
* Creates a new blob containing the data from the
* specified binary font file.
*
* Returns: An #hb_blob_t pointer with the content of the file,
* or %NULL if failed.
*
* Since: 2.8.2
**/
hb_blob_t *
hb_blob_create_from_file_or_fail (const char *file_name)
{
/* Adopted from glib's gmappedfile.c with Matthias Clasen and
Allison Lortie permission but changed a lot to suit our need. */
#if defined(HAVE_MMAP) && !defined(HB_NO_MMAP)
hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t));
hb_mapped_file_t *file = (hb_mapped_file_t *) hb_calloc (1, sizeof (hb_mapped_file_t));
if (unlikely (!file)) return hb_blob_get_empty ();
int fd = open (file_name, O_RDONLY | O_BINARY, 0);
@ -601,22 +660,22 @@ hb_blob_create_from_file (const char *file_name)
close (fd);
return hb_blob_create (file->contents, file->length,
HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
(hb_destroy_func_t) _hb_mapped_file_destroy);
return hb_blob_create_or_fail (file->contents, file->length,
HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
(hb_destroy_func_t) _hb_mapped_file_destroy);
fail:
close (fd);
fail_without_close:
free (file);
hb_free (file);
#elif defined(_WIN32) && !defined(HB_NO_MMAP)
hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t));
hb_mapped_file_t *file = (hb_mapped_file_t *) hb_calloc (1, sizeof (hb_mapped_file_t));
if (unlikely (!file)) return hb_blob_get_empty ();
HANDLE fd;
unsigned int size = strlen (file_name) + 1;
wchar_t * wchar_file_name = (wchar_t *) malloc (sizeof (wchar_t) * size);
wchar_t * wchar_file_name = (wchar_t *) hb_malloc (sizeof (wchar_t) * size);
if (unlikely (!wchar_file_name)) goto fail_without_close;
mbstowcs (wchar_file_name, file_name, size);
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
@ -636,7 +695,7 @@ fail_without_close:
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
nullptr);
#endif
free (wchar_file_name);
hb_free (wchar_file_name);
if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close;
@ -661,22 +720,22 @@ fail_without_close:
if (unlikely (!file->contents)) goto fail;
CloseHandle (fd);
return hb_blob_create (file->contents, file->length,
HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
(hb_destroy_func_t) _hb_mapped_file_destroy);
return hb_blob_create_or_fail (file->contents, file->length,
HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
(hb_destroy_func_t) _hb_mapped_file_destroy);
fail:
CloseHandle (fd);
fail_without_close:
free (file);
hb_free (file);
#endif
/* The following tries to read a file without knowing its size beforehand
It's used as a fallback for systems without mmap or to read from pipes */
unsigned long len = 0, allocated = BUFSIZ * 16;
char *data = (char *) malloc (allocated);
if (unlikely (!data)) return hb_blob_get_empty ();
char *data = (char *) hb_malloc (allocated);
if (unlikely (!data)) return nullptr;
FILE *fp = fopen (file_name, "rb");
if (unlikely (!fp)) goto fread_fail_without_close;
@ -689,7 +748,7 @@ fail_without_close:
/* Don't allocate and go more than ~536MB, our mmap reader still
can cover files like that but lets limit our fallback reader */
if (unlikely (allocated > (2 << 28))) goto fread_fail;
char *new_data = (char *) realloc (data, allocated);
char *new_data = (char *) hb_realloc (data, allocated);
if (unlikely (!new_data)) goto fread_fail;
data = new_data;
}
@ -706,13 +765,13 @@ fail_without_close:
}
fclose (fp);
return hb_blob_create (data, len, HB_MEMORY_MODE_WRITABLE, data,
(hb_destroy_func_t) free);
return hb_blob_create_or_fail (data, len, HB_MEMORY_MODE_WRITABLE, data,
(hb_destroy_func_t) hb_free);
fread_fail:
fclose (fp);
fread_fail_without_close:
free (data);
return hb_blob_get_empty ();
hb_free (data);
return nullptr;
}
#endif /* !HB_NO_OPEN */

View File

@ -90,9 +90,19 @@ hb_blob_create (const char *data,
void *user_data,
hb_destroy_func_t destroy);
HB_EXTERN hb_blob_t *
hb_blob_create_or_fail (const char *data,
unsigned int length,
hb_memory_mode_t mode,
void *user_data,
hb_destroy_func_t destroy);
HB_EXTERN hb_blob_t *
hb_blob_create_from_file (const char *file_name);
HB_EXTERN hb_blob_t *
hb_blob_create_from_file_or_fail (const char *file_name);
/* Always creates with MEMORY_MODE_READONLY.
* Even if the parent blob is writable, we don't
* want the user of the sub-blob to be able to

View File

@ -88,7 +88,7 @@ struct hb_blob_ptr_t
const T * get () const { return b->as<T> (); }
hb_blob_t * get_blob () const { return b.get_raw (); }
unsigned int get_length () const { return b.get ()->length; }
void destroy () { hb_blob_destroy (b.get ()); b = nullptr; }
void destroy () { hb_blob_destroy (b.get_raw ()); b = nullptr; }
private:
hb_nonnull_ptr_t<hb_blob_t> b;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -96,14 +96,15 @@ hb_segment_properties_hash (const hb_segment_properties_t *p)
* As an optimization, both info and out_info may point to the
* same piece of memory, which is owned by info. This remains the
* case as long as out_len doesn't exceed i at any time.
* In that case, swap_buffers() is no-op and the glyph operations operate
* mostly in-place.
* In that case, swap_buffers() is mostly no-op and the glyph operations
* operate mostly in-place.
*
* As soon as out_info gets longer than info, out_info is moved over
* to an alternate buffer (which we reuse the pos buffer for!), and its
* to an alternate buffer (which we reuse the pos buffer for), and its
* current contents (out_len entries) are copied to the new place.
*
* This should all remain transparent to the user. swap_buffers() then
* switches info and out_info.
* switches info over to out_info and does housekeeping.
*/
@ -136,8 +137,8 @@ hb_buffer_t::enlarge (unsigned int size)
if (unlikely (hb_unsigned_mul_overflows (new_allocated, sizeof (info[0]))))
goto done;
new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0]));
new_info = (hb_glyph_info_t *) realloc (info, new_allocated * sizeof (info[0]));
new_pos = (hb_glyph_position_t *) hb_realloc (pos, new_allocated * sizeof (pos[0]));
new_info = (hb_glyph_info_t *) hb_realloc (info, new_allocated * sizeof (info[0]));
done:
if (unlikely (!new_pos || !new_info))
@ -281,22 +282,13 @@ hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info)
}
void
hb_buffer_t::remove_output ()
{
have_output = false;
have_positions = false;
out_len = 0;
out_info = info;
}
void
hb_buffer_t::clear_output ()
{
have_output = true;
have_positions = false;
idx = 0;
out_len = 0;
out_info = info;
}
@ -316,29 +308,23 @@ hb_buffer_t::clear_positions ()
void
hb_buffer_t::swap_buffers ()
{
if (unlikely (!successful)) return;
assert (have_output);
assert (idx <= len);
if (unlikely (!next_glyphs (len - idx))) return;
assert (have_output);
have_output = false;
if (unlikely (!successful || !next_glyphs (len - idx)))
goto reset;
if (out_info != info)
{
hb_glyph_info_t *tmp;
tmp = info;
pos = (hb_glyph_position_t *) info;
info = out_info;
out_info = tmp;
pos = (hb_glyph_position_t *) out_info;
}
unsigned int tmp;
tmp = len;
len = out_len;
out_len = tmp;
reset:
have_output = false;
out_len = 0;
idx = 0;
}
@ -373,12 +359,11 @@ hb_buffer_t::move_to (unsigned int i)
/* This will blow in our face if memory allocation fails later
* in this same lookup...
*
* We used to shift with extra 32 items, instead of the 0 below.
* We used to shift with extra 32 items.
* But that would leave empty slots in the buffer in case of allocation
* failures. Setting to zero for now to avoid other problems (see
* comments in shift_forward(). This can cause O(N^2) behavior more
* severely than adding 32 empty slots can... */
if (unlikely (idx < count && !shift_forward (count + 0))) return false;
* failures. See comments in shift_forward(). This can cause O(N^2)
* behavior more severely than adding 32 empty slots can... */
if (unlikely (idx < count && !shift_forward (count - idx))) return false;
assert (idx >= count);
@ -630,7 +615,7 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) =
HB_BUFFER_CONTENT_TYPE_INVALID,
HB_SEGMENT_PROPERTIES_DEFAULT,
false, /* successful */
true, /* have_output */
false, /* have_output */
true /* have_positions */
/* Zero is good enough for everything else. */
@ -717,14 +702,14 @@ hb_buffer_destroy (hb_buffer_t *buffer)
hb_unicode_funcs_destroy (buffer->unicode);
free (buffer->info);
free (buffer->pos);
hb_free (buffer->info);
hb_free (buffer->pos);
#ifndef HB_NO_BUFFER_MESSAGE
if (buffer->message_destroy)
buffer->message_destroy (buffer->message_data);
#endif
free (buffer);
hb_free (buffer);
}
/**
@ -1363,6 +1348,11 @@ hb_buffer_get_glyph_infos (hb_buffer_t *buffer,
* Returns @buffer glyph position array. Returned pointer
* is valid as long as @buffer contents are not modified.
*
* If buffer did not have positions before, the positions will be
* initialized to zeros, unless this function is called from
* within a buffer message callback (see hb_buffer_set_message_func()),
* in which case %NULL is returned.
*
* Return value: (transfer none) (array length=length):
* The @buffer glyph position array.
* The value valid as long as buffer has not been modified.
@ -1373,12 +1363,17 @@ hb_glyph_position_t *
hb_buffer_get_glyph_positions (hb_buffer_t *buffer,
unsigned int *length)
{
if (!buffer->have_positions)
buffer->clear_positions ();
if (length)
*length = buffer->len;
if (!buffer->have_positions)
{
if (unlikely (buffer->message_depth))
return nullptr;
buffer->clear_positions ();
}
return (hb_glyph_position_t *) buffer->pos;
}
@ -1760,6 +1755,28 @@ hb_buffer_append (hb_buffer_t *buffer,
memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0]));
if (buffer->have_positions)
memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0]));
if (source->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE)
{
/* See similar logic in add_utf. */
/* pre-context */
if (!orig_len && start + source->context_len[0] > 0)
{
buffer->clear_context (0);
while (start > 0 && buffer->context_len[0] < buffer->CONTEXT_LENGTH)
buffer->context[0][buffer->context_len[0]++] = source->info[--start].codepoint;
for (auto i = 0u; i < source->context_len[0] && buffer->context_len[0] < buffer->CONTEXT_LENGTH; i++)
buffer->context[0][buffer->context_len[0]++] = source->context[0][i];
}
/* post-context */
buffer->clear_context (1);
while (end < source->len && buffer->context_len[1] < buffer->CONTEXT_LENGTH)
buffer->context[1][buffer->context_len[1]++] = source->info[end++].codepoint;
for (auto i = 0u; i < source->context_len[1] && buffer->context_len[1] < buffer->CONTEXT_LENGTH; i++)
buffer->context[1][buffer->context_len[1]++] = source->context[1][i];
}
}

View File

@ -107,7 +107,7 @@ struct hb_buffer_t
unsigned int idx; /* Cursor into ->info and ->pos arrays */
unsigned int len; /* Length of ->info and ->pos arrays */
unsigned int out_len; /* Length of ->out array if have_output */
unsigned int out_len; /* Length of ->out_info array if have_output */
unsigned int allocated; /* Length of allocated arrays */
hb_glyph_info_t *info;
@ -128,6 +128,9 @@ struct hb_buffer_t
hb_buffer_message_func_t message_func;
void *message_data;
hb_destroy_func_t message_destroy;
unsigned message_depth; /* How deeply are we inside a message callback? */
#else
static constexpr unsigned message_depth = 0u;
#endif
/* Internal debugging. */
@ -186,13 +189,10 @@ struct hb_buffer_t
hb_glyph_info_t &prev () { return out_info[out_len ? out_len - 1 : 0]; }
hb_glyph_info_t prev () const { return out_info[out_len ? out_len - 1 : 0]; }
HB_NODISCARD bool has_separate_output () const { return info != out_info; }
HB_INTERNAL void reset ();
HB_INTERNAL void clear ();
unsigned int backtrack_len () const { return have_output? out_len : idx; }
unsigned int backtrack_len () const { return have_output ? out_len : idx; }
unsigned int lookahead_len () const { return len - idx; }
unsigned int next_serial () { return serial++; }
@ -206,7 +206,6 @@ struct hb_buffer_t
HB_INTERNAL void guess_segment_properties ();
HB_INTERNAL void swap_buffers ();
HB_INTERNAL void remove_output ();
HB_INTERNAL void clear_output ();
HB_INTERNAL void clear_positions ();
@ -400,10 +399,16 @@ struct hb_buffer_t
#else
if (!messaging ())
return true;
message_depth++;
va_list ap;
va_start (ap, fmt);
bool ret = message_impl (font, fmt, ap);
va_end (ap);
message_depth--;
return ret;
#endif
}

View File

@ -30,7 +30,7 @@
#include "hb.hh"
/* Implements a lock-free cache for int->int functions. */
/* Implements a lockfree cache for int->int functions. */
template <unsigned int key_bits, unsigned int value_bits, unsigned int cache_bits>
struct hb_cache_t

View File

@ -263,7 +263,7 @@ struct UnsizedByteStr : UnsizedArrayOf <HBUINT8>
T *ip = c->allocate_size<T> (T::static_size);
if (unlikely (!ip)) return_trace (false);
return_trace (c->check_assign (*ip, value));
return_trace (c->check_assign (*ip, value, HB_SERIALIZE_ERROR_INT_OVERFLOW));
}
template <typename V>

View File

@ -136,8 +136,8 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
if (unlikely (!scalars.resize (region_count)))
set_error ();
else
varStore->varStore.get_scalars (get_ivs (), coords, num_coords,
&scalars[0], region_count);
varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords,
&scalars[0], region_count);
}
seen_blend = true;
}

View File

@ -257,13 +257,11 @@ struct hb_language_item_t {
bool operator == (const char *s) const
{ return lang_equal (lang, s); }
hb_language_item_t & operator = (const char *s) {
/* If a custom allocated is used calling strdup() pairs
badly with a call to the custom free() in fini() below.
Therefore don't call strdup(), implement its behavior.
*/
hb_language_item_t & operator = (const char *s)
{
/* We can't call strdup(), because we allow custom allocators. */
size_t len = strlen(s) + 1;
lang = (hb_language_t) malloc(len);
lang = (hb_language_t) hb_malloc(len);
if (likely (lang))
{
memcpy((unsigned char *) lang, s, len);
@ -274,16 +272,15 @@ struct hb_language_item_t {
return *this;
}
void fini () { free ((void *) lang); }
void fini () { hb_free ((void *) lang); }
};
/* Thread-safe lock-free language list */
/* Thread-safe lockfree language list */
static hb_atomic_ptr_t <hb_language_item_t> langs;
#if HB_USE_ATEXIT
static void
static inline void
free_langs ()
{
retry:
@ -294,11 +291,10 @@ retry:
while (first_lang) {
hb_language_item_t *next = first_lang->next;
first_lang->fini ();
free (first_lang);
hb_free (first_lang);
first_lang = next;
}
}
#endif
static hb_language_item_t *
lang_find_or_insert (const char *key)
@ -311,28 +307,26 @@ retry:
return lang;
/* Not found; allocate one. */
hb_language_item_t *lang = (hb_language_item_t *) calloc (1, sizeof (hb_language_item_t));
hb_language_item_t *lang = (hb_language_item_t *) hb_calloc (1, sizeof (hb_language_item_t));
if (unlikely (!lang))
return nullptr;
lang->next = first_lang;
*lang = key;
if (unlikely (!lang->lang))
{
free (lang);
hb_free (lang);
return nullptr;
}
if (unlikely (!langs.cmpexch (first_lang, lang)))
{
lang->fini ();
free (lang);
hb_free (lang);
goto retry;
}
#if HB_USE_ATEXIT
if (!first_lang)
atexit (free_langs); /* First person registers atexit() callback. */
#endif
hb_atexit (free_langs); /* First person registers atexit() callback. */
return lang;
}
@ -601,6 +595,9 @@ hb_script_get_horizontal_direction (hb_script_t script)
case HB_SCRIPT_CHORASMIAN:
case HB_SCRIPT_YEZIDI:
/* Unicode-14.0 additions */
case HB_SCRIPT_OLD_UYGHUR:
return HB_DIRECTION_RTL;

View File

@ -476,6 +476,11 @@ hb_language_get_default (void);
* @HB_SCRIPT_DIVES_AKURU: `Diak`, Since: 2.6.7
* @HB_SCRIPT_KHITAN_SMALL_SCRIPT: `Kits`, Since: 2.6.7
* @HB_SCRIPT_YEZIDI: `Yezi`, Since: 2.6.7
* @HB_SCRIPT_CYPRO_MINOAN: `Cpmn`, Since: 3.0.0
* @HB_SCRIPT_OLD_UYGHUR: `Ougr`, Since: 3.0.0
* @HB_SCRIPT_TANGSA: `Tnsa`, Since: 3.0.0
* @HB_SCRIPT_TOTO: `Toto`, Since: 3.0.0
* @HB_SCRIPT_VITHKUQI: `Vith`, Since: 3.0.0
* @HB_SCRIPT_INVALID: No script set
*
* Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding
@ -683,6 +688,15 @@ typedef enum
HB_SCRIPT_KHITAN_SMALL_SCRIPT = HB_TAG ('K','i','t','s'), /*13.0*/
HB_SCRIPT_YEZIDI = HB_TAG ('Y','e','z','i'), /*13.0*/
/*
* Since 3.0.0
*/
HB_SCRIPT_CYPRO_MINOAN = HB_TAG ('C','p','m','n'), /*14.0*/
HB_SCRIPT_OLD_UYGHUR = HB_TAG ('O','u','g','r'), /*14.0*/
HB_SCRIPT_TANGSA = HB_TAG ('T','n','s','a'), /*14.0*/
HB_SCRIPT_TOTO = HB_TAG ('T','o','t','o'), /*14.0*/
HB_SCRIPT_VITHKUQI = HB_TAG ('V','i','t','h'), /*14.0*/
/* No script set. */
HB_SCRIPT_INVALID = HB_TAG_NONE,

View File

@ -86,6 +86,9 @@
#define HB_NO_LEGACY
#endif
#ifdef HAVE_CONFIG_OVERRIDE_H
#include "config-override.h"
#endif
/* Closure of options. */
@ -117,7 +120,7 @@
#define HB_NO_CMAP_LEGACY_SUBTABLES
#define HB_NO_FALLBACK_SHAPE
#define HB_NO_OT_KERN
#define HB_NO_OT_LAYOUT_BLACKLIST
#define HB_NO_OT_LAYOUT_BLOCKLIST
#define HB_NO_OT_SHAPE_FALLBACK
#endif
@ -155,9 +158,5 @@
#endif
#endif
#ifdef HAVE_CONFIG_OVERRIDE_H
#include "config-override.h"
#endif
#endif /* HB_CONFIG_HH */

View File

@ -332,6 +332,44 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font)
return nullptr;
}
if (font->coords)
{
CFMutableDictionaryRef variations =
CFDictionaryCreateMutable (kCFAllocatorDefault,
font->num_coords,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
for (unsigned i = 0; i < font->num_coords; i++)
{
if (font->coords[i] == 0.) continue;
hb_ot_var_axis_info_t info;
unsigned int c = 1;
hb_ot_var_get_axis_infos (font->face, i, &c, &info);
CFDictionarySetValue (variations,
CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &info.tag),
CFNumberCreate (kCFAllocatorDefault, kCFNumberFloatType, &font->design_coords[i])
);
}
CFDictionaryRef attributes =
CFDictionaryCreate (kCFAllocatorDefault,
(const void **) &kCTFontVariationAttribute,
(const void **) &variations,
1,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
CTFontDescriptorRef varDesc = CTFontDescriptorCreateWithAttributes (attributes);
CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0, nullptr, varDesc);
CFRelease (ct_font);
CFRelease (attributes);
CFRelease (variations);
ct_font = new_ct_font;
}
return (hb_coretext_font_data_t *) ct_font;
}
@ -1061,7 +1099,7 @@ resize_and_retry:
hb_glyph_info_t *info = run_info;
if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
{
hb_position_t x_offset = (positions[0].x - advances_so_far) * x_mult;
hb_position_t x_offset = round ((positions[0].x - advances_so_far) * x_mult);
for (unsigned int j = 0; j < num_glyphs; j++)
{
CGFloat advance;
@ -1069,15 +1107,15 @@ resize_and_retry:
advance = positions[j + 1].x - positions[j].x;
else /* last glyph */
advance = run_advance - (positions[j].x - positions[0].x);
info->mask = advance * x_mult;
info->mask = round (advance * x_mult);
info->var1.i32 = x_offset;
info->var2.i32 = positions[j].y * y_mult;
info->var2.i32 = round (positions[j].y * y_mult);
info++;
}
}
else
{
hb_position_t y_offset = (positions[0].y - advances_so_far) * y_mult;
hb_position_t y_offset = round ((positions[0].y - advances_so_far) * y_mult);
for (unsigned int j = 0; j < num_glyphs; j++)
{
CGFloat advance;
@ -1085,8 +1123,8 @@ resize_and_retry:
advance = positions[j + 1].y - positions[j].y;
else /* last glyph */
advance = run_advance - (positions[j].y - positions[0].y);
info->mask = advance * y_mult;
info->var1.i32 = positions[j].x * x_mult;
info->mask = round (advance * y_mult);
info->var1.i32 = round (positions[j].x * x_mult);
info->var2.i32 = y_offset;
info++;
}

View File

@ -307,7 +307,7 @@ struct hb_auto_trace_t
_hb_debug_msg<max_level> (what, obj, func, true, plevel ? *plevel : 1, -1,
"return %s (line %d)",
hb_printer_t<decltype (v)>().print (v), line);
hb_printer_t<hb_decay<decltype (v)>>().print (v), line);
if (plevel) --*plevel;
plevel = nullptr;
returned = true;
@ -438,6 +438,10 @@ struct hb_no_trace_t {
#define TRACE_SUBSET(this) hb_no_trace_t<bool> trace
#endif
#ifndef HB_DEBUG_SUBSET_REPACK
#define HB_DEBUG_SUBSET_REPACK (HB_DEBUG+0)
#endif
#ifndef HB_DEBUG_DISPATCH
#define HB_DEBUG_DISPATCH ( \
HB_DEBUG_APPLY + \

View File

@ -107,9 +107,6 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
hb_font_get_glyph_func_t func,
void *user_data, hb_destroy_func_t destroy);
HB_EXTERN HB_DEPRECATED void
hb_set_invert (hb_set_t *set);
/**
* hb_unicode_eastasian_width_func_t:
* @ufuncs: A Unicode-functions structure

View File

@ -32,6 +32,7 @@
#include "hb-directwrite.h"
#include "hb-ms-feature-ranges.hh"
/**
* SECTION:hb-directwrite
@ -42,24 +43,6 @@
* Functions for using HarfBuzz with DirectWrite fonts.
**/
/* Declare object creator for dynamic support of DWRITE */
typedef HRESULT (* WINAPI t_DWriteCreateFactory)(
DWRITE_FACTORY_TYPE factoryType,
REFIID iid,
IUnknown **factory
);
/*
* hb-directwrite uses new/delete syntatically but as we let users
* to override malloc/free, we will redefine new/delete so users
* won't need to do that by their own.
*/
void* operator new (size_t size) { return malloc (size); }
void* operator new [] (size_t size) { return malloc (size); }
void operator delete (void* pointer) { free (pointer); }
void operator delete [] (void* pointer) { free (pointer); }
/*
* DirectWrite font stream helpers
*/
@ -154,7 +137,6 @@ public:
struct hb_directwrite_face_data_t
{
HMODULE dwrite_dll;
IDWriteFactory *dwriteFactory;
IDWriteFontFile *fontFile;
DWriteFontFileStream *fontFileStream;
@ -176,33 +158,12 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face)
return nullptr; \
} HB_STMT_END
data->dwrite_dll = LoadLibrary (TEXT ("DWRITE"));
if (unlikely (!data->dwrite_dll))
FAIL ("Cannot find DWrite.DLL");
t_DWriteCreateFactory p_DWriteCreateFactory;
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-function-type"
#endif
p_DWriteCreateFactory = (t_DWriteCreateFactory)
GetProcAddress (data->dwrite_dll, "DWriteCreateFactory");
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
if (unlikely (!p_DWriteCreateFactory))
FAIL ("Cannot find DWriteCreateFactory().");
HRESULT hr;
// TODO: factory and fontFileLoader should be cached separately
IDWriteFactory* dwriteFactory;
hr = p_DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
(IUnknown**) &dwriteFactory);
hr = DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
(IUnknown**) &dwriteFactory);
if (unlikely (hr != S_OK))
FAIL ("Failed to run DWriteCreateFactory().");
@ -266,8 +227,6 @@ _hb_directwrite_shaper_face_data_destroy (hb_directwrite_face_data_t *data)
delete data->fontFileStream;
if (data->faceBlob)
hb_blob_destroy (data->faceBlob);
if (data->dwrite_dll)
FreeLibrary (data->dwrite_dll);
if (data)
delete data;
}
@ -552,13 +511,12 @@ protected:
* shaper
*/
static hb_bool_t
_hb_directwrite_shape_full (hb_shape_plan_t *shape_plan,
hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features,
float lineWidth)
hb_bool_t
_hb_directwrite_shape (hb_shape_plan_t *shape_plan,
hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features)
{
hb_face_t *face = font->face;
const hb_directwrite_face_data_t *face_data = face->data.directwrite;
@ -611,8 +569,6 @@ _hb_directwrite_shape_full (hb_shape_plan_t *shape_plan,
log_clusters[chars_len++] = cluster; /* Surrogates. */
}
// TODO: Handle TEST_DISABLE_OPTIONAL_LIGATURES
DWRITE_READING_DIRECTION readingDirection;
readingDirection = buffer->props.direction ?
DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
@ -623,7 +579,7 @@ _hb_directwrite_shape_full (hb_shape_plan_t *shape_plan,
* but we never attempt to shape a word longer than 64K characters
* in a single gfxShapedWord, so we cannot exceed that limit.
*/
uint32_t textLength = buffer->len;
uint32_t textLength = chars_len;
TextAnalysis analysis (textString, textLength, nullptr, readingDirection);
TextAnalysis::Run *runHead;
@ -648,38 +604,54 @@ _hb_directwrite_shape_full (hb_shape_plan_t *shape_plan,
mbstowcs ((wchar_t*) localeName,
hb_language_to_string (buffer->props.language), 20);
// TODO: it does work but doesn't care about ranges
DWRITE_TYPOGRAPHIC_FEATURES typographic_features;
typographic_features.featureCount = num_features;
/*
* Set up features.
*/
static_assert ((sizeof (DWRITE_TYPOGRAPHIC_FEATURES) == sizeof (hb_ms_features_t)), "");
static_assert ((sizeof (DWRITE_FONT_FEATURE) == sizeof (hb_ms_feature_t)), "");
hb_vector_t<hb_ms_features_t *> range_features;
hb_vector_t<uint32_t> range_char_counts;
if (num_features)
{
typographic_features.features = new DWRITE_FONT_FEATURE[num_features];
for (unsigned int i = 0; i < num_features; ++i)
{
typographic_features.features[i].nameTag = (DWRITE_FONT_FEATURE_TAG)
hb_uint32_swap (features[i].tag);
typographic_features.features[i].parameter = features[i].value;
}
hb_vector_t<hb_ms_feature_t> feature_records;
hb_vector_t<hb_ms_range_record_t> range_records;
if (hb_ms_setup_features (features, num_features, feature_records, range_records))
hb_ms_make_feature_ranges (feature_records,
range_records,
0,
chars_len,
log_clusters,
range_features,
range_char_counts);
}
const DWRITE_TYPOGRAPHIC_FEATURES* dwFeatures;
dwFeatures = (const DWRITE_TYPOGRAPHIC_FEATURES*) &typographic_features;
const uint32_t featureRangeLengths[] = { textLength };
//
uint16_t* clusterMap;
clusterMap = new uint16_t[textLength];
DWRITE_SHAPING_TEXT_PROPERTIES* textProperties;
textProperties = new DWRITE_SHAPING_TEXT_PROPERTIES[textLength];
retry_getglyphs:
uint16_t* glyphIndices = new uint16_t[maxGlyphCount];
DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties;
glyphProperties = new DWRITE_SHAPING_GLYPH_PROPERTIES[maxGlyphCount];
hr = analyzer->GetGlyphs (textString, textLength, fontFace, false,
isRightToLeft, &runHead->mScript, localeName,
nullptr, &dwFeatures, featureRangeLengths, 1,
maxGlyphCount, clusterMap, textProperties,
glyphIndices, glyphProperties, &glyphCount);
hr = analyzer->GetGlyphs (textString,
chars_len,
fontFace,
false,
isRightToLeft,
&runHead->mScript,
localeName,
nullptr,
(const DWRITE_TYPOGRAPHIC_FEATURES**) range_features.arrayZ,
range_char_counts.arrayZ,
range_features.length,
maxGlyphCount,
clusterMap,
textProperties,
glyphIndices,
glyphProperties,
&glyphCount);
if (unlikely (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER)))
{
@ -715,101 +687,28 @@ retry_getglyphs:
double x_mult = (double) font->x_scale / fontEmSize;
double y_mult = (double) font->y_scale / fontEmSize;
hr = analyzer->GetGlyphPlacements (textString, clusterMap, textProperties,
textLength, glyphIndices, glyphProperties,
glyphCount, fontFace, fontEmSize,
false, isRightToLeft, &runHead->mScript, localeName,
&dwFeatures, featureRangeLengths, 1,
glyphAdvances, glyphOffsets);
hr = analyzer->GetGlyphPlacements (textString,
clusterMap,
textProperties,
chars_len,
glyphIndices,
glyphProperties,
glyphCount,
fontFace,
fontEmSize,
false,
isRightToLeft,
&runHead->mScript,
localeName,
(const DWRITE_TYPOGRAPHIC_FEATURES**) range_features.arrayZ,
range_char_counts.arrayZ,
range_features.length,
glyphAdvances,
glyphOffsets);
if (FAILED (hr))
FAIL ("Analyzer failed to get glyph placements.");
IDWriteTextAnalyzer1* analyzer1;
analyzer->QueryInterface (&analyzer1);
if (analyzer1 && lineWidth)
{
DWRITE_JUSTIFICATION_OPPORTUNITY* justificationOpportunities =
new DWRITE_JUSTIFICATION_OPPORTUNITY[maxGlyphCount];
hr = analyzer1->GetJustificationOpportunities (fontFace, fontEmSize, runHead->mScript,
textLength, glyphCount, textString,
clusterMap, glyphProperties,
justificationOpportunities);
if (FAILED (hr))
FAIL ("Analyzer failed to get justification opportunities.");
float* justifiedGlyphAdvances = new float[maxGlyphCount];
DWRITE_GLYPH_OFFSET* justifiedGlyphOffsets = new DWRITE_GLYPH_OFFSET[glyphCount];
hr = analyzer1->JustifyGlyphAdvances (lineWidth, glyphCount, justificationOpportunities,
glyphAdvances, glyphOffsets, justifiedGlyphAdvances,
justifiedGlyphOffsets);
if (FAILED (hr)) FAIL ("Analyzer failed to get justify glyph advances.");
DWRITE_SCRIPT_PROPERTIES scriptProperties;
hr = analyzer1->GetScriptProperties (runHead->mScript, &scriptProperties);
if (FAILED (hr)) FAIL ("Analyzer failed to get script properties.");
uint32_t justificationCharacter = scriptProperties.justificationCharacter;
// if a script justificationCharacter is not space, it can have GetJustifiedGlyphs
if (justificationCharacter != 32)
{
uint16_t* modifiedClusterMap = new uint16_t[textLength];
retry_getjustifiedglyphs:
uint16_t* modifiedGlyphIndices = new uint16_t[maxGlyphCount];
float* modifiedGlyphAdvances = new float[maxGlyphCount];
DWRITE_GLYPH_OFFSET* modifiedGlyphOffsets = new DWRITE_GLYPH_OFFSET[maxGlyphCount];
uint32_t actualGlyphsCount;
hr = analyzer1->GetJustifiedGlyphs (fontFace, fontEmSize, runHead->mScript,
textLength, glyphCount, maxGlyphCount,
clusterMap, glyphIndices, glyphAdvances,
justifiedGlyphAdvances, justifiedGlyphOffsets,
glyphProperties, &actualGlyphsCount,
modifiedClusterMap, modifiedGlyphIndices,
modifiedGlyphAdvances, modifiedGlyphOffsets);
if (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER))
{
maxGlyphCount = actualGlyphsCount;
delete [] modifiedGlyphIndices;
delete [] modifiedGlyphAdvances;
delete [] modifiedGlyphOffsets;
maxGlyphCount = actualGlyphsCount;
goto retry_getjustifiedglyphs;
}
if (FAILED (hr))
FAIL ("Analyzer failed to get justified glyphs.");
delete [] clusterMap;
delete [] glyphIndices;
delete [] glyphAdvances;
delete [] glyphOffsets;
glyphCount = actualGlyphsCount;
clusterMap = modifiedClusterMap;
glyphIndices = modifiedGlyphIndices;
glyphAdvances = modifiedGlyphAdvances;
glyphOffsets = modifiedGlyphOffsets;
delete [] justifiedGlyphAdvances;
delete [] justifiedGlyphOffsets;
}
else
{
delete [] glyphAdvances;
delete [] glyphOffsets;
glyphAdvances = justifiedGlyphAdvances;
glyphOffsets = justifiedGlyphOffsets;
}
delete [] justificationOpportunities;
}
/* Ok, we've got everything we need, now compose output buffer,
* very, *very*, carefully! */
@ -870,43 +769,10 @@ retry_getglyphs:
delete [] glyphAdvances;
delete [] glyphOffsets;
if (num_features)
delete [] typographic_features.features;
/* Wow, done! */
return true;
}
hb_bool_t
_hb_directwrite_shape (hb_shape_plan_t *shape_plan,
hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features)
{
return _hb_directwrite_shape_full (shape_plan, font, buffer,
features, num_features, 0);
}
HB_UNUSED static bool
_hb_directwrite_shape_experimental_width (hb_font_t *font,
hb_buffer_t *buffer,
const hb_feature_t *features,
unsigned int num_features,
float width)
{
static const char *shapers = "directwrite";
hb_shape_plan_t *shape_plan;
shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props,
features, num_features, &shapers);
hb_bool_t res = _hb_directwrite_shape_full (shape_plan, font, buffer,
features, num_features, width);
buffer->unsafe_to_break_all ();
return res;
}
struct _hb_directwrite_font_table_context {
IDWriteFontFace *face;
void *table_context;
@ -917,7 +783,7 @@ _hb_directwrite_table_data_release (void *data)
{
_hb_directwrite_font_table_context *context = (_hb_directwrite_font_table_context *) data;
context->face->ReleaseFontTable (context->table_context);
delete context;
hb_free (context);
}
static hb_blob_t *
@ -938,7 +804,7 @@ _hb_directwrite_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *
return nullptr;
}
_hb_directwrite_font_table_context *context = new _hb_directwrite_font_table_context;
_hb_directwrite_font_table_context *context = (_hb_directwrite_font_table_context *) hb_malloc (sizeof (_hb_directwrite_font_table_context));
context->face = dw_face;
context->table_context = table_context;

View File

@ -191,7 +191,7 @@ hb_draw_funcs_destroy (hb_draw_funcs_t *funcs)
{
if (!hb_object_destroy (funcs)) return;
free (funcs);
hb_free (funcs);
}
/**

View File

@ -33,6 +33,7 @@
#include "hb-open-file.hh"
#include "hb-ot-face.hh"
#include "hb-ot-cmap-table.hh"
#include "hb-map.hh"
/**
@ -106,9 +107,9 @@ DEFINE_NULL_INSTANCE (hb_face_t) =
* convenient to provide data for individual tables instead of the whole font
* data. With the caveat that hb_face_get_table_tags() does not currently work
* with faces created this way.
*
*
* Creates a new face object from the specified @user_data and @reference_table_func,
* with the @destroy callback.
* with the @destroy callback.
*
* Return value: (transfer full): The new face object
*
@ -150,7 +151,7 @@ _hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index)
{
hb_face_for_data_closure_t *closure;
closure = (hb_face_for_data_closure_t *) calloc (1, sizeof (hb_face_for_data_closure_t));
closure = (hb_face_for_data_closure_t *) hb_calloc (1, sizeof (hb_face_for_data_closure_t));
if (unlikely (!closure))
return nullptr;
@ -166,7 +167,7 @@ _hb_face_for_data_closure_destroy (void *data)
hb_face_for_data_closure_t *closure = (hb_face_for_data_closure_t *) data;
hb_blob_destroy (closure->blob);
free (closure);
hb_free (closure);
}
static hb_blob_t *
@ -265,7 +266,7 @@ hb_face_reference (hb_face_t *face)
/**
* hb_face_destroy: (skip)
* @face: A face object
*
*
* Decreases the reference count on a face object. When the
* reference count reaches zero, the face is destroyed,
* freeing all memory.
@ -281,7 +282,7 @@ hb_face_destroy (hb_face_t *face)
{
hb_face_t::plan_node_t *next = node->next;
hb_shape_plan_destroy (node->shape_plan);
free (node);
hb_free (node);
node = next;
}
@ -291,7 +292,7 @@ hb_face_destroy (hb_face_t *face)
if (face->destroy)
face->destroy (face->user_data);
free (face);
hb_free (face);
}
/**
@ -302,7 +303,7 @@ hb_face_destroy (hb_face_t *face)
* @destroy: (nullable): A callback to call when @data is not needed anymore
* @replace: Whether to replace an existing data with the same key
*
* Attaches a user-data key/data pair to the given face object.
* Attaches a user-data key/data pair to the given face object.
*
* Return value: %true if success, %false otherwise
*
@ -441,7 +442,7 @@ hb_face_set_index (hb_face_t *face,
*
* <note>Note: face indices within a collection are zero-based.</note>
*
* Return value: The index of @face.
* Return value: The index of @face.
*
* Since: 0.9.2
**/
@ -623,26 +624,26 @@ hb_face_collect_variation_unicodes (hb_face_t *face,
struct hb_face_builder_data_t
{
struct table_entry_t
{
int cmp (hb_tag_t t) const
{
if (t < tag) return -1;
if (t > tag) return -1;
return 0;
}
hb_tag_t tag;
hb_blob_t *blob;
};
hb_vector_t<table_entry_t> tables;
hb_hashmap_t<hb_tag_t, hb_blob_t *> tables;
};
static int compare_entries (const void* pa, const void* pb)
{
const auto& a = * (const hb_pair_t<hb_tag_t, hb_blob_t*> *) pa;
const auto& b = * (const hb_pair_t<hb_tag_t, hb_blob_t*> *) pb;
/* Order by blob size first (smallest to largest) and then table tag */
if (a.second->length != b.second->length)
return a.second->length < b.second->length ? -1 : +1;
return a.first < b.first ? -1 : a.first == b.first ? 0 : +1;
}
static hb_face_builder_data_t *
_hb_face_builder_data_create ()
{
hb_face_builder_data_t *data = (hb_face_builder_data_t *) calloc (1, sizeof (hb_face_builder_data_t));
hb_face_builder_data_t *data = (hb_face_builder_data_t *) hb_calloc (1, sizeof (hb_face_builder_data_t));
if (unlikely (!data))
return nullptr;
@ -656,25 +657,25 @@ _hb_face_builder_data_destroy (void *user_data)
{
hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
for (unsigned int i = 0; i < data->tables.length; i++)
hb_blob_destroy (data->tables[i].blob);
for (hb_blob_t* b : data->tables.values())
hb_blob_destroy (b);
data->tables.fini ();
free (data);
hb_free (data);
}
static hb_blob_t *
_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
{
unsigned int table_count = data->tables.length;
unsigned int table_count = data->tables.get_population ();
unsigned int face_length = table_count * 16 + 12;
for (unsigned int i = 0; i < table_count; i++)
face_length += hb_ceil_to_4 (hb_blob_get_length (data->tables[i].blob));
for (hb_blob_t* b : data->tables.values())
face_length += hb_ceil_to_4 (hb_blob_get_length (b));
char *buf = (char *) malloc (face_length);
char *buf = (char *) hb_malloc (face_length);
if (unlikely (!buf))
return nullptr;
@ -682,20 +683,31 @@ _hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
c.propagate_error (data->tables);
OT::OpenTypeFontFile *f = c.start_serialize<OT::OpenTypeFontFile> ();
bool is_cff = data->tables.lsearch (HB_TAG ('C','F','F',' ')) || data->tables.lsearch (HB_TAG ('C','F','F','2'));
bool is_cff = (data->tables.has (HB_TAG ('C','F','F',' '))
|| data->tables.has (HB_TAG ('C','F','F','2')));
hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;
bool ret = f->serialize_single (&c, sfnt_tag, data->tables.as_array ());
// Sort the tags so that produced face is deterministic.
hb_vector_t<hb_pair_t <hb_tag_t, hb_blob_t*>> sorted_entries;
data->tables.iter () | hb_sink (sorted_entries);
if (unlikely (sorted_entries.in_error ()))
{
hb_free (buf);
return nullptr;
}
sorted_entries.qsort (compare_entries);
bool ret = f->serialize_single (&c, sfnt_tag, + sorted_entries.iter());
c.end_serialize ();
if (unlikely (!ret))
{
free (buf);
hb_free (buf);
return nullptr;
}
return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, free);
return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, hb_free);
}
static hb_blob_t *
@ -706,11 +718,7 @@ _hb_face_builder_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void
if (!tag)
return _hb_face_builder_data_reference_blob (data);
hb_face_builder_data_t::table_entry_t *entry = data->tables.lsearch (tag);
if (entry)
return hb_blob_reference (entry->blob);
return nullptr;
return hb_blob_reference (data->tables[tag]);
}
@ -750,17 +758,21 @@ hb_face_builder_create ()
hb_bool_t
hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
{
if (tag == HB_MAP_VALUE_INVALID)
return false;
if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))
return false;
hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
hb_face_builder_data_t::table_entry_t *entry = data->tables.push ();
if (unlikely (data->tables.in_error()))
hb_blob_t* previous = data->tables.get (tag);
if (!data->tables.set (tag, hb_blob_reference (blob)))
{
hb_blob_destroy (blob);
return false;
}
entry->tag = tag;
entry->blob = hb_blob_reference (blob);
hb_blob_destroy (previous);
return true;
}

View File

@ -620,7 +620,7 @@ hb_font_funcs_destroy (hb_font_funcs_t *ffuncs)
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
#undef HB_FONT_FUNC_IMPLEMENT
free (ffuncs);
hb_free (ffuncs);
}
/**
@ -1544,8 +1544,8 @@ _hb_font_adopt_var_coords (hb_font_t *font,
float *design_coords,
unsigned int coords_length)
{
free (font->coords);
free (font->design_coords);
hb_free (font->coords);
hb_free (font->design_coords);
font->coords = coords;
font->design_coords = design_coords;
@ -1586,8 +1586,8 @@ hb_font_create_sub_font (hb_font_t *parent)
unsigned int num_coords = parent->num_coords;
if (num_coords)
{
int *coords = (int *) calloc (num_coords, sizeof (parent->coords[0]));
float *design_coords = (float *) calloc (num_coords, sizeof (parent->design_coords[0]));
int *coords = (int *) hb_calloc (num_coords, sizeof (parent->coords[0]));
float *design_coords = (float *) hb_calloc (num_coords, sizeof (parent->design_coords[0]));
if (likely (coords && design_coords))
{
memcpy (coords, parent->coords, num_coords * sizeof (parent->coords[0]));
@ -1596,8 +1596,8 @@ hb_font_create_sub_font (hb_font_t *parent)
}
else
{
free (coords);
free (design_coords);
hb_free (coords);
hb_free (design_coords);
}
}
@ -1659,10 +1659,10 @@ hb_font_destroy (hb_font_t *font)
hb_face_destroy (font->face);
hb_font_funcs_destroy (font->klass);
free (font->coords);
free (font->design_coords);
hb_free (font->coords);
hb_free (font->design_coords);
free (font);
hb_free (font);
}
/**
@ -2052,29 +2052,30 @@ hb_font_set_variations (hb_font_t *font,
return;
}
unsigned int coords_length = hb_ot_var_get_axis_count (font->face);
const OT::fvar &fvar = *font->face->table.fvar;
auto axes = fvar.get_axes ();
const unsigned coords_length = axes.length;
int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : nullptr;
float *design_coords = coords_length ? (float *) calloc (coords_length, sizeof (float)) : nullptr;
int *normalized = coords_length ? (int *) hb_calloc (coords_length, sizeof (int)) : nullptr;
float *design_coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr;
if (unlikely (coords_length && !(normalized && design_coords)))
{
free (normalized);
free (design_coords);
hb_free (normalized);
hb_free (design_coords);
return;
}
const OT::fvar &fvar = *font->face->table.fvar;
for (unsigned int i = 0; i < variations_length; i++)
{
hb_ot_var_axis_info_t info;
if (hb_ot_var_find_axis_info (font->face, variations[i].tag, &info) &&
info.axis_index < coords_length)
{
float v = variations[i].value;
design_coords[info.axis_index] = v;
normalized[info.axis_index] = fvar.normalize_axis_value (info.axis_index, v);
}
const auto tag = variations[i].tag;
const auto v = variations[i].value;
for (unsigned axis_index = 0; axis_index < coords_length; axis_index++)
if (axes[axis_index].axisTag == tag)
{
design_coords[axis_index] = v;
normalized[axis_index] = fvar.normalize_axis_value (axis_index, v);
}
}
font->face->table.avar->map_coords (normalized, coords_length);
@ -2100,13 +2101,13 @@ hb_font_set_var_coords_design (hb_font_t *font,
if (hb_object_is_immutable (font))
return;
int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : nullptr;
float *design_coords = coords_length ? (float *) calloc (coords_length, sizeof (float)) : nullptr;
int *normalized = coords_length ? (int *) hb_calloc (coords_length, sizeof (int)) : nullptr;
float *design_coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr;
if (unlikely (coords_length && !(normalized && design_coords)))
{
free (normalized);
free (design_coords);
hb_free (normalized);
hb_free (design_coords);
return;
}
@ -2135,13 +2136,13 @@ hb_font_set_var_named_instance (hb_font_t *font,
unsigned int coords_length = hb_ot_var_named_instance_get_design_coords (font->face, instance_index, nullptr, nullptr);
float *coords = coords_length ? (float *) calloc (coords_length, sizeof (float)) : nullptr;
float *coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr;
if (unlikely (coords_length && !coords))
return;
hb_ot_var_named_instance_get_design_coords (font->face, instance_index, &coords_length, coords);
hb_font_set_var_coords_design (font, coords, coords_length);
free (coords);
hb_free (coords);
}
/**
@ -2165,15 +2166,15 @@ hb_font_set_var_coords_normalized (hb_font_t *font,
if (hb_object_is_immutable (font))
return;
int *copy = coords_length ? (int *) calloc (coords_length, sizeof (coords[0])) : nullptr;
int *unmapped = coords_length ? (int *) calloc (coords_length, sizeof (coords[0])) : nullptr;
float *design_coords = coords_length ? (float *) calloc (coords_length, sizeof (design_coords[0])) : nullptr;
int *copy = coords_length ? (int *) hb_calloc (coords_length, sizeof (coords[0])) : nullptr;
int *unmapped = coords_length ? (int *) hb_calloc (coords_length, sizeof (coords[0])) : nullptr;
float *design_coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (design_coords[0])) : nullptr;
if (unlikely (coords_length && !(copy && unmapped && design_coords)))
{
free (copy);
free (unmapped);
free (design_coords);
hb_free (copy);
hb_free (unmapped);
hb_free (design_coords);
return;
}
@ -2187,7 +2188,7 @@ hb_font_set_var_coords_normalized (hb_font_t *font,
font->face->table.avar->unmap_coords (unmapped, coords_length);
for (unsigned int i = 0; i < coords_length; ++i)
design_coords[i] = font->face->table.fvar->unnormalize_axis_value (i, unmapped[i]);
free (unmapped);
hb_free (unmapped);
_hb_font_adopt_var_coords (font, copy, design_coords, coords_length);
}
@ -2267,7 +2268,7 @@ trampoline_create (FuncType func,
{
typedef hb_trampoline_t<FuncType> trampoline_t;
trampoline_t *trampoline = (trampoline_t *) calloc (1, sizeof (trampoline_t));
trampoline_t *trampoline = (trampoline_t *) hb_calloc (1, sizeof (trampoline_t));
if (unlikely (!trampoline))
return nullptr;
@ -2296,7 +2297,7 @@ trampoline_destroy (void *user_data)
if (closure->destroy)
closure->destroy (closure->user_data);
free (closure);
hb_free (closure);
}
typedef hb_trampoline_t<hb_font_get_glyph_func_t> hb_font_get_glyph_trampoline_t;

View File

@ -91,7 +91,7 @@ struct hb_ft_font_t
static hb_ft_font_t *
_hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
{
hb_ft_font_t *ft_font = (hb_ft_font_t *) calloc (1, sizeof (hb_ft_font_t));
hb_ft_font_t *ft_font = (hb_ft_font_t *) hb_calloc (1, sizeof (hb_ft_font_t));
if (unlikely (!ft_font)) return nullptr;
ft_font->lock.init ();
@ -125,7 +125,7 @@ _hb_ft_font_destroy (void *data)
ft_font->lock.fini ();
free (ft_font);
hb_free (ft_font);
}
/**
@ -561,9 +561,7 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
return true;
}
#if HB_USE_ATEXIT
static void free_static_ft_funcs ();
#endif
static inline void free_static_ft_funcs ();
static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft_font_funcs_lazy_loader_t>
{
@ -591,21 +589,17 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft
hb_font_funcs_make_immutable (funcs);
#if HB_USE_ATEXIT
atexit (free_static_ft_funcs);
#endif
hb_atexit (free_static_ft_funcs);
return funcs;
}
} static_ft_funcs;
#if HB_USE_ATEXIT
static
static inline
void free_static_ft_funcs ()
{
static_ft_funcs.free_instance ();
}
#endif
static hb_font_funcs_t *
_hb_ft_get_font_funcs ()
@ -642,20 +636,20 @@ _hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data
if (error)
return nullptr;
buffer = (FT_Byte *) malloc (length);
buffer = (FT_Byte *) hb_malloc (length);
if (!buffer)
return nullptr;
error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
if (error)
{
free (buffer);
hb_free (buffer);
return nullptr;
}
return hb_blob_create ((const char *) buffer, length,
HB_MEMORY_MODE_WRITABLE,
buffer, free);
buffer, hb_free);
}
/**
@ -846,8 +840,8 @@ hb_ft_font_changed (hb_font_t *font)
FT_MM_Var *mm_var = nullptr;
if (!FT_Get_MM_Var (ft_face, &mm_var))
{
FT_Fixed *ft_coords = (FT_Fixed *) calloc (mm_var->num_axis, sizeof (FT_Fixed));
int *coords = (int *) calloc (mm_var->num_axis, sizeof (int));
FT_Fixed *ft_coords = (FT_Fixed *) hb_calloc (mm_var->num_axis, sizeof (FT_Fixed));
int *coords = (int *) hb_calloc (mm_var->num_axis, sizeof (int));
if (coords && ft_coords)
{
if (!FT_Get_Var_Blend_Coordinates (ft_face, mm_var->num_axis, ft_coords))
@ -866,12 +860,12 @@ hb_ft_font_changed (hb_font_t *font)
hb_font_set_var_coords_normalized (font, nullptr, 0);
}
}
free (coords);
free (ft_coords);
hb_free (coords);
hb_free (ft_coords);
#ifdef HAVE_FT_DONE_MM_VAR
FT_Done_MM_Var (ft_face->glyph->library, mm_var);
#else
free (mm_var);
hb_free (mm_var);
#endif
}
#endif
@ -905,9 +899,7 @@ hb_ft_font_create_referenced (FT_Face ft_face)
return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
}
#if HB_USE_ATEXIT
static void free_static_ft_library ();
#endif
static inline void free_static_ft_library ();
static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<FT_Library>,
hb_ft_library_lazy_loader_t>
@ -918,9 +910,7 @@ static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<F
if (FT_Init_FreeType (&l))
return nullptr;
#if HB_USE_ATEXIT
atexit (free_static_ft_library);
#endif
hb_atexit (free_static_ft_library);
return l;
}
@ -934,13 +924,11 @@ static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<F
}
} static_ft_library;
#if HB_USE_ATEXIT
static
static inline
void free_static_ft_library ()
{
static_ft_library.free_instance ();
}
#endif
static FT_Library
get_ft_library ()
@ -1020,13 +1008,13 @@ hb_ft_font_set_funcs (hb_font_t *font)
const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
if (num_coords)
{
FT_Fixed *ft_coords = (FT_Fixed *) calloc (num_coords, sizeof (FT_Fixed));
FT_Fixed *ft_coords = (FT_Fixed *) hb_calloc (num_coords, sizeof (FT_Fixed));
if (ft_coords)
{
for (unsigned int i = 0; i < num_coords; i++)
ft_coords[i] = coords[i] * 4;
FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords);
free (ft_coords);
hb_free (ft_coords);
}
}
#endif

View File

@ -50,16 +50,16 @@ _hb_gdi_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_dat
length = GetFontData (hdc, hb_uint32_swap (tag), 0, buffer, length);
if (unlikely (length == GDI_ERROR)) goto fail_with_releasedc;
buffer = (char *) malloc (length);
buffer = (char *) hb_malloc (length);
if (unlikely (!buffer)) goto fail_with_releasedc;
length = GetFontData (hdc, hb_uint32_swap (tag), 0, buffer, length);
if (unlikely (length == GDI_ERROR)) goto fail_with_releasedc_and_free;
ReleaseDC (nullptr, hdc);
return hb_blob_create ((const char *) buffer, length, HB_MEMORY_MODE_WRITABLE, buffer, free);
return hb_blob_create ((const char *) buffer, length, HB_MEMORY_MODE_WRITABLE, buffer, hb_free);
fail_with_releasedc_and_free:
free (buffer);
hb_free (buffer);
fail_with_releasedc:
ReleaseDC (nullptr, hdc);
fail:

View File

@ -218,9 +218,7 @@ hb_glib_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
}
#if HB_USE_ATEXIT
static void free_static_glib_funcs ();
#endif
static inline void free_static_glib_funcs ();
static struct hb_glib_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_glib_unicode_funcs_lazy_loader_t>
{
@ -237,21 +235,17 @@ static struct hb_glib_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader
hb_unicode_funcs_make_immutable (funcs);
#if HB_USE_ATEXIT
atexit (free_static_glib_funcs);
#endif
hb_atexit (free_static_glib_funcs);
return funcs;
}
} static_glib_funcs;
#if HB_USE_ATEXIT
static
static inline
void free_static_glib_funcs ()
{
static_glib_funcs.free_instance ();
}
#endif
/**
* hb_glib_get_unicode_funcs:

View File

@ -80,12 +80,12 @@ hb_gobject_##name##_get_type () \
#define HB_DEFINE_VALUE_TYPE(name) \
static hb_##name##_t *_hb_##name##_reference (const hb_##name##_t *l) \
{ \
hb_##name##_t *c = (hb_##name##_t *) calloc (1, sizeof (hb_##name##_t)); \
hb_##name##_t *c = (hb_##name##_t *) hb_calloc (1, sizeof (hb_##name##_t)); \
if (unlikely (!c)) return nullptr; \
*c = *l; \
return c; \
} \
static void _hb_##name##_destroy (hb_##name##_t *l) { free (l); } \
static void _hb_##name##_destroy (hb_##name##_t *l) { hb_free (l); } \
HB_DEFINE_BOXED_TYPE (name, _hb_##name##_reference, _hb_##name##_destroy)
HB_DEFINE_OBJECT_TYPE (buffer)

View File

@ -88,7 +88,7 @@ static const void *hb_graphite2_get_table (const void *data, unsigned int tag, s
{
blob = face_data->face->reference_table (tag);
hb_graphite2_tablelist_t *p = (hb_graphite2_tablelist_t *) calloc (1, sizeof (hb_graphite2_tablelist_t));
hb_graphite2_tablelist_t *p = (hb_graphite2_tablelist_t *) hb_calloc (1, sizeof (hb_graphite2_tablelist_t));
if (unlikely (!p)) {
hb_blob_destroy (blob);
return nullptr;
@ -123,15 +123,16 @@ _hb_graphite2_shaper_face_data_create (hb_face_t *face)
}
hb_blob_destroy (silf_blob);
hb_graphite2_face_data_t *data = (hb_graphite2_face_data_t *) calloc (1, sizeof (hb_graphite2_face_data_t));
hb_graphite2_face_data_t *data = (hb_graphite2_face_data_t *) hb_calloc (1, sizeof (hb_graphite2_face_data_t));
if (unlikely (!data))
return nullptr;
data->face = face;
data->grface = gr_make_face (data, &hb_graphite2_get_table, gr_face_preloadAll);
const gr_face_ops ops = {sizeof(gr_face_ops), &hb_graphite2_get_table, NULL};
data->grface = gr_make_face_with_ops (data, &ops, gr_face_preloadAll);
if (unlikely (!data->grface)) {
free (data);
hb_free (data);
return nullptr;
}
@ -148,12 +149,12 @@ _hb_graphite2_shaper_face_data_destroy (hb_graphite2_face_data_t *data)
hb_graphite2_tablelist_t *old = tlist;
hb_blob_destroy (tlist->blob);
tlist = tlist->next;
free (old);
hb_free (old);
}
gr_face_destroy (data->grface);
free (data);
hb_free (data);
}
/**

View File

@ -233,9 +233,7 @@ hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
}
#if HB_USE_ATEXIT
static void free_static_icu_funcs ();
#endif
static inline void free_static_icu_funcs ();
static struct hb_icu_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_icu_unicode_funcs_lazy_loader_t>
{
@ -257,21 +255,17 @@ static struct hb_icu_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_
hb_unicode_funcs_make_immutable (funcs);
#if HB_USE_ATEXIT
atexit (free_static_icu_funcs);
#endif
hb_atexit (free_static_icu_funcs);
return funcs;
}
} static_icu_funcs;
#if HB_USE_ATEXIT
static
static inline
void free_static_icu_funcs ()
{
static_icu_funcs.free_instance ();
}
#endif
/**
* hb_icu_get_unicode_funcs:

View File

@ -46,7 +46,7 @@
* TODO Document more.
*
* If iterator implementation implements operator!=, then can be
* used in range-based for loop. That comes free if the iterator
* used in range-based for loop. That already happens if the iterator
* is random-access. Otherwise, the range-based for loop incurs
* one traversal to find end(), which can be avoided if written
* as a while-style for loop, or if iterator implements a faster

View File

@ -242,14 +242,14 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
static const Stored* get_null () { return &Null (Stored); }
static Stored *create (Data *data)
{
Stored *p = (Stored *) calloc (1, sizeof (Stored));
Stored *p = (Stored *) hb_calloc (1, sizeof (Stored));
if (likely (p))
p->init (data);
return p;
}
static Stored *create ()
{
Stored *p = (Stored *) calloc (1, sizeof (Stored));
Stored *p = (Stored *) hb_calloc (1, sizeof (Stored));
if (likely (p))
p->init ();
return p;
@ -257,7 +257,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
static void destroy (Stored *p)
{
p->fini ();
free (p);
hb_free (p);
}
// private:

View File

@ -109,7 +109,7 @@ hb_map_destroy (hb_map_t *map)
map->fini_shallow ();
free (map);
hb_free (map);
}
/**
@ -188,6 +188,7 @@ hb_map_set (hb_map_t *map,
hb_codepoint_t key,
hb_codepoint_t value)
{
/* Immutable-safe. */
map->set (key, value);
}
@ -220,6 +221,7 @@ void
hb_map_del (hb_map_t *map,
hb_codepoint_t key)
{
/* Immutable-safe. */
map->del (key);
}
@ -253,9 +255,6 @@ hb_map_has (const hb_map_t *map,
void
hb_map_clear (hb_map_t *map)
{
if (unlikely (hb_object_is_immutable (map)))
return;
return map->clear ();
}

View File

@ -85,7 +85,7 @@ struct hb_hashmap_t
}
void fini_shallow ()
{
free (items);
hb_free (items);
items = nullptr;
population = occupancy = 0;
}
@ -109,7 +109,7 @@ struct hb_hashmap_t
unsigned int power = hb_bit_storage (population * 2 + 8);
unsigned int new_size = 1u << power;
item_t *new_items = (item_t *) malloc ((size_t) new_size * sizeof (item_t));
item_t *new_items = (item_t *) hb_malloc ((size_t) new_size * sizeof (item_t));
if (unlikely (!new_items))
{
successful = false;
@ -135,14 +135,14 @@ struct hb_hashmap_t
old_items[i].hash,
old_items[i].value);
free (old_items);
hb_free (old_items);
return true;
}
void set (K key, V value)
bool set (K key, V value)
{
set_with_hash (key, hb_hash (key), value);
return set_with_hash (key, hb_hash (key), value);
}
V get (K key) const
@ -169,6 +169,8 @@ struct hb_hashmap_t
void clear ()
{
if (unlikely (!successful)) return;
if (items)
for (auto &_ : hb_iter (items, mask + 1))
_.clear ();
@ -211,20 +213,20 @@ struct hb_hashmap_t
protected:
void set_with_hash (K key, uint32_t hash, V value)
bool set_with_hash (K key, uint32_t hash, V value)
{
if (unlikely (!successful)) return;
if (unlikely (key == kINVALID)) return;
if ((occupancy + occupancy / 2) >= mask && !resize ()) return;
if (unlikely (!successful)) return false;
if (unlikely (key == kINVALID)) return true;
if (unlikely ((occupancy + occupancy / 2) >= mask && !resize ())) return false;
unsigned int i = bucket_for_hash (key, hash);
if (value == vINVALID && items[i].key != key)
return; /* Trying to delete non-existent key. */
return true; /* Trying to delete non-existent key. */
if (!items[i].is_unused ())
{
occupancy--;
if (items[i].is_tombstone ())
if (!items[i].is_tombstone ())
population--;
}
@ -235,6 +237,8 @@ struct hb_hashmap_t
occupancy++;
if (!items[i].is_tombstone ())
population++;
return true;
}
unsigned int bucket_for (K key) const

View File

@ -101,14 +101,14 @@ HB_FUNCOBJ (hb_addressof);
template <typename T> static inline T hb_declval ();
#define hb_declval(T) (hb_declval<T> ())
template <typename T> struct hb_match_const : hb_type_identity_t<T>, hb_bool_constant<false>{};
template <typename T> struct hb_match_const<const T> : hb_type_identity_t<T>, hb_bool_constant<true> {};
template <typename T> struct hb_match_const : hb_type_identity_t<T>, hb_false_type {};
template <typename T> struct hb_match_const<const T> : hb_type_identity_t<T>, hb_true_type {};
template <typename T> using hb_remove_const = typename hb_match_const<T>::type;
template <typename T> using hb_add_const = const T;
#define hb_is_const(T) hb_match_const<T>::value
template <typename T> struct hb_match_reference : hb_type_identity_t<T>, hb_bool_constant<false>{};
template <typename T> struct hb_match_reference<T &> : hb_type_identity_t<T>, hb_bool_constant<true> {};
template <typename T> struct hb_match_reference<T &&> : hb_type_identity_t<T>, hb_bool_constant<true> {};
template <typename T> struct hb_match_reference : hb_type_identity_t<T>, hb_false_type {};
template <typename T> struct hb_match_reference<T &> : hb_type_identity_t<T>, hb_true_type {};
template <typename T> struct hb_match_reference<T &&> : hb_type_identity_t<T>, hb_true_type {};
template <typename T> using hb_remove_reference = typename hb_match_reference<T>::type;
template <typename T> auto _hb_try_add_lvalue_reference (hb_priority<1>) -> hb_type_identity<T&>;
template <typename T> auto _hb_try_add_lvalue_reference (hb_priority<0>) -> hb_type_identity<T>;
@ -117,8 +117,8 @@ template <typename T> auto _hb_try_add_rvalue_reference (hb_priority<1>) -> hb_t
template <typename T> auto _hb_try_add_rvalue_reference (hb_priority<0>) -> hb_type_identity<T>;
template <typename T> using hb_add_rvalue_reference = decltype (_hb_try_add_rvalue_reference<T> (hb_prioritize));
#define hb_is_reference(T) hb_match_reference<T>::value
template <typename T> struct hb_match_pointer : hb_type_identity_t<T>, hb_bool_constant<false>{};
template <typename T> struct hb_match_pointer<T *> : hb_type_identity_t<T>, hb_bool_constant<true> {};
template <typename T> struct hb_match_pointer : hb_type_identity_t<T>, hb_false_type {};
template <typename T> struct hb_match_pointer<T *> : hb_type_identity_t<T>, hb_true_type {};
template <typename T> using hb_remove_pointer = typename hb_match_pointer<T>::type;
template <typename T> auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_identity<hb_remove_reference<T>*>;
template <typename T> auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_identity<T>;
@ -259,15 +259,15 @@ using hb_is_arithmetic = hb_bool_constant<
#define hb_is_arithmetic(T) hb_is_arithmetic<T>::value
template <typename T>
using hb_is_signed = hb_conditional<hb_is_arithmetic (T),
hb_bool_constant<(T) -1 < (T) 0>,
hb_false_type>;
template <typename T, bool is_arithmetic> struct hb_is_signed_;
template <typename T> struct hb_is_signed_<T, false> : hb_false_type {};
template <typename T> struct hb_is_signed_<T, true> : hb_bool_constant<(T) -1 < (T) 0> {};
template <typename T> struct hb_is_signed : hb_is_signed_<T, hb_is_arithmetic (T)> {};
#define hb_is_signed(T) hb_is_signed<T>::value
template <typename T>
using hb_is_unsigned = hb_conditional<hb_is_arithmetic (T),
hb_bool_constant<(T) 0 < (T) -1>,
hb_false_type>;
template <typename T, bool is_arithmetic> struct hb_is_unsigned_;
template <typename T> struct hb_is_unsigned_<T, false> : hb_false_type {};
template <typename T> struct hb_is_unsigned_<T, true> : hb_bool_constant<(T) 0 < (T) -1> {};
template <typename T> struct hb_is_unsigned : hb_is_unsigned_<T, hb_is_arithmetic (T)> {};
#define hb_is_unsigned(T) hb_is_unsigned<T>::value
template <typename T> struct hb_int_min;
@ -282,6 +282,7 @@ template <> struct hb_int_min<signed long> : hb_integral_constant<signed long,
template <> struct hb_int_min<unsigned long> : hb_integral_constant<unsigned long, 0> {};
template <> struct hb_int_min<signed long long> : hb_integral_constant<signed long long, LLONG_MIN> {};
template <> struct hb_int_min<unsigned long long> : hb_integral_constant<unsigned long long, 0> {};
template <typename T> struct hb_int_min<T *> : hb_integral_constant<T *, nullptr> {};
#define hb_int_min(T) hb_int_min<T>::value
template <typename T> struct hb_int_max;
template <> struct hb_int_max<char> : hb_integral_constant<char, CHAR_MAX> {};

View File

@ -0,0 +1,177 @@
/*
* Copyright © 2011,2012,2013 Google, Inc.
* Copyright © 2021 Khaled Hosny
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#include "hb-ms-feature-ranges.hh"
bool
hb_ms_setup_features (const hb_feature_t *features,
unsigned int num_features,
hb_vector_t<hb_ms_feature_t> &feature_records, /* OUT */
hb_vector_t<hb_ms_range_record_t> &range_records /* OUT */)
{
feature_records.shrink(0);
range_records.shrink(0);
/* Sort features by start/end events. */
hb_vector_t<hb_ms_feature_event_t> feature_events;
for (unsigned int i = 0; i < num_features; i++)
{
hb_ms_active_feature_t feature;
feature.fea.tag_le = hb_uint32_swap (features[i].tag);
feature.fea.value = features[i].value;
feature.order = i;
hb_ms_feature_event_t *event;
event = feature_events.push ();
event->index = features[i].start;
event->start = true;
event->feature = feature;
event = feature_events.push ();
event->index = features[i].end;
event->start = false;
event->feature = feature;
}
feature_events.qsort ();
/* Add a strategic final event. */
{
hb_ms_active_feature_t feature;
feature.fea.tag_le = 0;
feature.fea.value = 0;
feature.order = num_features + 1;
auto *event = feature_events.push ();
event->index = 0; /* This value does magic. */
event->start = false;
event->feature = feature;
}
/* Scan events and save features for each range. */
hb_vector_t<hb_ms_active_feature_t> active_features;
unsigned int last_index = 0;
for (unsigned int i = 0; i < feature_events.length; i++)
{
auto *event = &feature_events[i];
if (event->index != last_index)
{
/* Save a snapshot of active features and the range. */
auto *range = range_records.push ();
auto offset = feature_records.length;
active_features.qsort ();
for (unsigned int j = 0; j < active_features.length; j++)
{
if (!j || active_features[j].fea.tag_le != feature_records[feature_records.length - 1].tag_le)
{
feature_records.push (active_features[j].fea);
}
else
{
/* Overrides value for existing feature. */
feature_records[feature_records.length - 1].value = active_features[j].fea.value;
}
}
/* Will convert to pointer after all is ready, since feature_records.array
* may move as we grow it. */
range->features.features = reinterpret_cast<hb_ms_feature_t *> (offset);
range->features.num_features = feature_records.length - offset;
range->index_first = last_index;
range->index_last = event->index - 1;
last_index = event->index;
}
if (event->start)
{
active_features.push (event->feature);
}
else
{
auto *feature = active_features.find (&event->feature);
if (feature)
active_features.remove (feature - active_features.arrayZ);
}
}
if (!range_records.length) /* No active feature found. */
num_features = 0;
/* Fixup the pointers. */
for (unsigned int i = 0; i < range_records.length; i++)
{
auto *range = &range_records[i];
range->features.features = (hb_ms_feature_t *) feature_records + reinterpret_cast<uintptr_t> (range->features.features);
}
return !!num_features;
}
void
hb_ms_make_feature_ranges (hb_vector_t<hb_ms_feature_t> &feature_records,
hb_vector_t<hb_ms_range_record_t> &range_records,
unsigned int chars_offset,
unsigned int chars_len,
uint16_t *log_clusters,
hb_vector_t<hb_ms_features_t*> &range_features, /* OUT */
hb_vector_t<uint32_t> &range_counts /* OUT */)
{
range_features.shrink (0);
range_counts.shrink (0);
auto *last_range = &range_records[0];
for (unsigned int i = chars_offset; i < chars_len; i++)
{
auto *range = last_range;
while (log_clusters[i] < range->index_first)
range--;
while (log_clusters[i] > range->index_last)
range++;
if (!range_features.length ||
&range->features != range_features[range_features.length - 1])
{
auto **features = range_features.push ();
auto *c = range_counts.push ();
if (unlikely (!features || !c))
{
range_features.shrink (0);
range_counts.shrink (0);
break;
}
*features = &range->features;
*c = 1;
}
else
{
range_counts[range_counts.length - 1]++;
}
last_range = range;
}
}

View File

@ -0,0 +1,96 @@
/*
* Copyright © 2011,2012,2013 Google, Inc.
* Copyright © 2021 Khaled Hosny
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Google Author(s): Behdad Esfahbod
*/
#ifndef HB_MS_FEATURE_RANGES_HH
#define HB_MS_FEATURE_RANGES_HH
#include "hb.hh"
typedef struct hb_ms_feature_t {
uint32_t tag_le;
uint32_t value;
} hb_ms_feature_t;
typedef struct hb_ms_features_t {
hb_ms_feature_t *features;
uint32_t num_features;
} hb_ms_features_t;
struct hb_ms_active_feature_t {
hb_ms_feature_t fea;
unsigned int order;
HB_INTERNAL static int cmp (const void *pa, const void *pb) {
const auto *a = (const hb_ms_active_feature_t *) pa;
const auto *b = (const hb_ms_active_feature_t *) pb;
return a->fea.tag_le < b->fea.tag_le ? -1 : a->fea.tag_le > b->fea.tag_le ? 1 :
a->order < b->order ? -1 : a->order > b->order ? 1 :
a->fea.value < b->fea.value ? -1 : a->fea.value > b->fea.value ? 1 :
0;
}
bool operator== (const hb_ms_active_feature_t *f)
{ return cmp (this, f) == 0; }
};
struct hb_ms_feature_event_t {
unsigned int index;
bool start;
hb_ms_active_feature_t feature;
HB_INTERNAL static int cmp (const void *pa, const void *pb)
{
const auto *a = (const hb_ms_feature_event_t *) pa;
const auto *b = (const hb_ms_feature_event_t *) pb;
return a->index < b->index ? -1 : a->index > b->index ? 1 :
a->start < b->start ? -1 : a->start > b->start ? 1 :
hb_ms_active_feature_t::cmp (&a->feature, &b->feature);
}
};
struct hb_ms_range_record_t {
hb_ms_features_t features;
unsigned int index_first; /* == start */
unsigned int index_last; /* == end - 1 */
};
HB_INTERNAL bool
hb_ms_setup_features (const hb_feature_t *features,
unsigned int num_features,
hb_vector_t<hb_ms_feature_t> &feature_records, /* OUT */
hb_vector_t<hb_ms_range_record_t> &range_records /* OUT */);
HB_INTERNAL void
hb_ms_make_feature_ranges (hb_vector_t<hb_ms_feature_t> &feature_records,
hb_vector_t<hb_ms_range_record_t> &range_records,
unsigned int chars_offset,
unsigned int chars_len,
uint16_t *log_clusters,
hb_vector_t<hb_ms_features_t*> &range_features, /* OUT */
hb_vector_t<uint32_t> &range_counts /* OUT */);
#endif /* HB_MS_FEATURE_RANGES_HH */

View File

@ -39,8 +39,7 @@
/* We need external help for these */
#if defined(HB_MUTEX_IMPL_INIT) \
&& defined(hb_mutex_impl_init) \
#if defined(hb_mutex_impl_init) \
&& defined(hb_mutex_impl_lock) \
&& defined(hb_mutex_impl_unlock) \
&& defined(hb_mutex_impl_finish)
@ -52,7 +51,6 @@
#include <pthread.h>
typedef pthread_mutex_t hb_mutex_impl_t;
#define HB_MUTEX_IMPL_INIT PTHREAD_MUTEX_INITIALIZER
#define hb_mutex_impl_init(M) pthread_mutex_init (M, nullptr)
#define hb_mutex_impl_lock(M) pthread_mutex_lock (M)
#define hb_mutex_impl_unlock(M) pthread_mutex_unlock (M)
@ -62,7 +60,6 @@ typedef pthread_mutex_t hb_mutex_impl_t;
#elif !defined(HB_NO_MT) && defined(_WIN32)
typedef CRITICAL_SECTION hb_mutex_impl_t;
#define HB_MUTEX_IMPL_INIT {0}
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
#define hb_mutex_impl_init(M) InitializeCriticalSectionEx (M, 0, 0)
#else
@ -76,7 +73,6 @@ typedef CRITICAL_SECTION hb_mutex_impl_t;
#elif defined(HB_NO_MT)
typedef int hb_mutex_impl_t;
#define HB_MUTEX_IMPL_INIT 0
#define hb_mutex_impl_init(M) HB_STMT_START {} HB_STMT_END
#define hb_mutex_impl_lock(M) HB_STMT_START {} HB_STMT_END
#define hb_mutex_impl_unlock(M) HB_STMT_START {} HB_STMT_END
@ -91,8 +87,6 @@ typedef int hb_mutex_impl_t;
#endif
#define HB_MUTEX_INIT {HB_MUTEX_IMPL_INIT}
struct hb_mutex_t
{
hb_mutex_impl_t m;

View File

@ -39,8 +39,11 @@
#define HB_NULL_POOL_SIZE 384
/* Use SFINAE to sniff whether T has min_size; in which case return T::null_size,
* otherwise return sizeof(T). */
/* Use SFINAE to sniff whether T has min_size; in which case return the larger
* of sizeof(T) and T::null_size, otherwise return sizeof(T).
*
* The main purpose of this is to let structs communicate that they are not nullable,
* by defining min_size but *not* null_size. */
/* The hard way...
* https://stackoverflow.com/questions/7776448/sfinae-tried-with-bool-gives-compiler-error-template-argument-tvalue-invol
@ -49,8 +52,9 @@
template <typename T, typename>
struct _hb_null_size : hb_integral_constant<unsigned, sizeof (T)> {};
template <typename T>
struct _hb_null_size<T, hb_void_t<decltype (T::min_size)>> : hb_integral_constant<unsigned, T::null_size> {};
struct _hb_null_size<T, hb_void_t<decltype (T::min_size)>>
: hb_integral_constant<unsigned,
(sizeof (T) > T::null_size ? sizeof (T) : T::null_size)> {};
template <typename T>
using hb_null_size = _hb_null_size<T, void>;
#define hb_null_size(T) hb_null_size<T>::value
@ -68,6 +72,14 @@ template <typename T>
using hb_static_size = _hb_static_size<T, void>;
#define hb_static_size(T) hb_static_size<T>::value
template <typename T, typename>
struct _hb_min_size : hb_integral_constant<unsigned, sizeof (T)> {};
template <typename T>
struct _hb_min_size<T, hb_void_t<decltype (T::min_size)>> : hb_integral_constant<unsigned, T::min_size> {};
template <typename T>
using hb_min_size = _hb_min_size<T, void>;
#define hb_min_size(T) hb_min_size<T>::value
/*
* Null()

View File

@ -140,8 +140,6 @@ struct hb_lockable_set_t
* Reference-count.
*/
#define HB_REFERENCE_COUNT_INIT {0}
struct hb_reference_count_t
{
mutable hb_atomic_int_t ref_count;
@ -197,6 +195,8 @@ struct hb_object_header_t
hb_reference_count_t ref_count;
mutable hb_atomic_int_t writable = 0;
hb_atomic_ptr_t<hb_user_data_array_t> user_data;
bool is_inert () const { return !ref_count.get_relaxed (); }
};
#define HB_OBJECT_HEADER_STATIC {}
@ -217,7 +217,7 @@ static inline void hb_object_trace (const Type *obj, const char *function)
template <typename Type>
static inline Type *hb_object_create ()
{
Type *obj = (Type *) calloc (1, sizeof (Type));
Type *obj = (Type *) hb_calloc (1, sizeof (Type));
if (unlikely (!obj))
return obj;
@ -234,11 +234,6 @@ static inline void hb_object_init (Type *obj)
obj->header.user_data.init ();
}
template <typename Type>
static inline bool hb_object_is_inert (const Type *obj)
{
return unlikely (obj->header.ref_count.is_inert ());
}
template <typename Type>
static inline bool hb_object_is_valid (const Type *obj)
{
return likely (obj->header.ref_count.is_valid ());
@ -257,7 +252,7 @@ template <typename Type>
static inline Type *hb_object_reference (Type *obj)
{
hb_object_trace (obj, HB_FUNC);
if (unlikely (!obj || hb_object_is_inert (obj)))
if (unlikely (!obj || obj->header.is_inert ()))
return obj;
assert (hb_object_is_valid (obj));
obj->header.ref_count.inc ();
@ -267,7 +262,7 @@ template <typename Type>
static inline bool hb_object_destroy (Type *obj)
{
hb_object_trace (obj, HB_FUNC);
if (unlikely (!obj || hb_object_is_inert (obj)))
if (unlikely (!obj || obj->header.is_inert ()))
return false;
assert (hb_object_is_valid (obj));
if (obj->header.ref_count.dec () != 1)
@ -284,7 +279,7 @@ static inline void hb_object_fini (Type *obj)
if (user_data)
{
user_data->fini ();
free (user_data);
hb_free (user_data);
user_data = nullptr;
}
}
@ -295,7 +290,7 @@ static inline bool hb_object_set_user_data (Type *obj,
hb_destroy_func_t destroy,
hb_bool_t replace)
{
if (unlikely (!obj || hb_object_is_inert (obj)))
if (unlikely (!obj || obj->header.is_inert ()))
return false;
assert (hb_object_is_valid (obj));
@ -303,14 +298,14 @@ retry:
hb_user_data_array_t *user_data = obj->header.user_data.get ();
if (unlikely (!user_data))
{
user_data = (hb_user_data_array_t *) calloc (sizeof (hb_user_data_array_t), 1);
user_data = (hb_user_data_array_t *) hb_calloc (sizeof (hb_user_data_array_t), 1);
if (unlikely (!user_data))
return false;
user_data->init ();
if (unlikely (!obj->header.user_data.cmpexch (nullptr, user_data)))
{
user_data->fini ();
free (user_data);
hb_free (user_data);
goto retry;
}
}
@ -322,7 +317,7 @@ template <typename Type>
static inline void *hb_object_get_user_data (Type *obj,
hb_user_data_key_t *key)
{
if (unlikely (!obj || hb_object_is_inert (obj)))
if (unlikely (!obj || obj->header.is_inert ()))
return nullptr;
assert (hb_object_is_valid (obj));
hb_user_data_array_t *user_data = obj->header.user_data.get ();

View File

@ -35,7 +35,6 @@
namespace OT {
/*
*
* The OpenType Font File
@ -102,7 +101,13 @@ typedef struct OpenTypeOffsetTable
{
Tag t;
t = tag;
return tables.bfind (t, table_index, HB_BFIND_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
/* Use lfind for small fonts; there are fonts that have unsorted table entries;
* those tend to work in other tools, so tolerate them.
* https://github.com/harfbuzz/harfbuzz/issues/3065 */
if (tables.len < 16)
return tables.lfind (t, table_index, HB_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
else
return tables.bfind (t, table_index, HB_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
}
const TableRecord& get_table_by_tag (hb_tag_t tag) const
{
@ -113,44 +118,53 @@ typedef struct OpenTypeOffsetTable
public:
template <typename item_t>
template <typename Iterator,
hb_requires ((hb_is_source_of<Iterator, hb_pair_t<hb_tag_t, hb_blob_t *>>::value))>
bool serialize (hb_serialize_context_t *c,
hb_tag_t sfnt_tag,
hb_array_t<item_t> items)
Iterator it)
{
TRACE_SERIALIZE (this);
/* Alloc 12 for the OTHeader. */
if (unlikely (!c->extend_min (*this))) return_trace (false);
if (unlikely (!c->extend_min (this))) return_trace (false);
/* Write sfntVersion (bytes 0..3). */
sfnt_version = sfnt_tag;
/* Take space for numTables, searchRange, entrySelector, RangeShift
* and the TableRecords themselves. */
if (unlikely (!tables.serialize (c, items.length))) return_trace (false);
unsigned num_items = it.len ();
if (unlikely (!tables.serialize (c, num_items))) return_trace (false);
const char *dir_end = (const char *) c->head;
HBUINT32 *checksum_adjustment = nullptr;
/* Write OffsetTables, alloc for and write actual table blobs. */
for (unsigned int i = 0; i < tables.len; i++)
unsigned i = 0;
for (hb_pair_t<hb_tag_t, hb_blob_t*> entry : it)
{
TableRecord &rec = tables.arrayZ[i];
hb_blob_t *blob = items[i].blob;
rec.tag = items[i].tag;
rec.length = blob->length;
rec.offset.serialize (c, this);
hb_blob_t *blob = entry.second;
unsigned len = blob->length;
/* Allocate room for the table and copy it. */
char *start = (char *) c->allocate_size<void> (rec.length);
char *start = (char *) c->allocate_size<void> (len);
if (unlikely (!start)) return false;
if (likely (rec.length))
memcpy (start, blob->data, rec.length);
TableRecord &rec = tables.arrayZ[i];
rec.tag = entry.first;
rec.length = len;
rec.offset = 0;
if (unlikely (!c->check_assign (rec.offset,
(unsigned) ((char *) start - (char *) this),
HB_SERIALIZE_ERROR_OFFSET_OVERFLOW)))
return_trace (false);
if (likely (len))
memcpy (start, blob->data, len);
/* 4-byte alignment. */
c->align (4);
const char *end = (const char *) c->head;
if (items[i].tag == HB_OT_TAG_head &&
if (entry.first == HB_OT_TAG_head &&
(unsigned) (end - start) >= head::static_size)
{
head *h = (head *) start;
@ -159,6 +173,7 @@ typedef struct OpenTypeOffsetTable
}
rec.checkSum.set_for_data (start, end - start);
i++;
}
tables.qsort ();
@ -170,7 +185,7 @@ typedef struct OpenTypeOffsetTable
/* The following line is a slower version of the following block. */
//checksum.set_for_data (this, (const char *) c->head - (const char *) this);
checksum.set_for_data (this, dir_end - (const char *) this);
for (unsigned int i = 0; i < items.length; i++)
for (unsigned int i = 0; i < num_items; i++)
{
TableRecord &rec = tables.arrayZ[i];
checksum = checksum + rec.checkSum;
@ -218,7 +233,7 @@ struct TTCHeaderVersion1
Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */
FixedVersion<>version; /* Version of the TTC Header (1.0),
* 0x00010000u */
LArrayOf<LOffsetTo<OpenTypeOffsetTable>>
Array32Of<Offset32To<OpenTypeOffsetTable>>
table; /* Array of offsets to the OffsetTable for each font
* from the beginning of the file */
public:
@ -295,7 +310,7 @@ struct ResourceRecord
HBINT16 nameOffset; /* Offset from beginning of resource name list
* to resource name, -1 means there is none. */
HBUINT8 attrs; /* Resource attributes */
NNOffsetTo<LArrayOf<HBUINT8>, HBUINT24>
NNOffset24To<Array32Of<HBUINT8>>
offset; /* Offset from beginning of data block to
* data for this resource */
HBUINT32 reserved; /* Reserved for handle to resource */
@ -330,7 +345,7 @@ struct ResourceTypeRecord
protected:
Tag tag; /* Resource type. */
HBUINT16 resCountM1; /* Number of resources minus 1. */
NNOffsetTo<UnsizedArrayOf<ResourceRecord>>
NNOffset16To<UnsizedArrayOf<ResourceRecord>>
resourcesZ; /* Offset from beginning of resource type list
* to reference item list for this type. */
public:
@ -386,7 +401,7 @@ struct ResourceMap
HBUINT32 reserved1; /* Reserved for handle to next resource map */
HBUINT16 resreved2; /* Reserved for file reference number */
HBUINT16 attrs; /* Resource fork attribute */
NNOffsetTo<ArrayOfM1<ResourceTypeRecord>>
NNOffset16To<ArrayOfM1<ResourceTypeRecord>>
typeList; /* Offset from beginning of map to
* resource type list */
Offset16 nameList; /* Offset from beginning of map to
@ -418,10 +433,10 @@ struct ResourceForkHeader
}
protected:
LNNOffsetTo<UnsizedArrayOf<HBUINT8>>
NNOffset32To<UnsizedArrayOf<HBUINT8>>
data; /* Offset from beginning of resource fork
* to resource data */
LNNOffsetTo<ResourceMap >
NNOffset32To<ResourceMap >
map; /* Offset from beginning of resource fork
* to resource map */
HBUINT32 dataLen; /* Length of resource data */
@ -477,14 +492,15 @@ struct OpenTypeFontFile
}
}
template <typename item_t>
template <typename Iterator,
hb_requires ((hb_is_source_of<Iterator, hb_pair_t<hb_tag_t, hb_blob_t *>>::value))>
bool serialize_single (hb_serialize_context_t *c,
hb_tag_t sfnt_tag,
hb_array_t<item_t> items)
Iterator items)
{
TRACE_SERIALIZE (this);
assert (sfnt_tag != TTCTag);
if (unlikely (!c->extend_min (*this))) return_trace (false);
if (unlikely (!c->extend_min (this))) return_trace (false);
return_trace (u.fontFace.serialize (c, sfnt_tag, items));
}

View File

@ -196,6 +196,12 @@ DECLARE_NULL_NAMESPACE_BYTES (OT, Index);
typedef Index NameID;
struct VarIdx : HBUINT32 {
static constexpr unsigned NO_VARIATION = 0xFFFFFFFFu;
VarIdx& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; }
};
DECLARE_NULL_NAMESPACE_BYTES (OT, VarIdx);
/* Offset, Null offset = 0 */
template <typename Type, bool has_null=true>
struct Offset : Type
@ -206,18 +212,12 @@ struct Offset : Type
bool is_null () const { return has_null && 0 == *this; }
void *serialize (hb_serialize_context_t *c, const void *base)
{
void *t = c->start_embed<void> ();
c->check_assign (*this, (unsigned) ((char *) t - (char *) base));
return t;
}
public:
DEFINE_SIZE_STATIC (sizeof (Type));
};
typedef Offset<HBUINT16> Offset16;
typedef Offset<HBUINT24> Offset24;
typedef Offset<HBUINT32> Offset32;
@ -287,7 +287,7 @@ struct _hb_has_null<Type, true>
static Type *get_crap () { return &Crap (Type); }
};
template <typename Type, typename OffsetType=HBUINT16, bool has_null=true>
template <typename Type, typename OffsetType, bool has_null=true>
struct OffsetTo : Offset<OffsetType, has_null>
{
HB_DELETE_COPY_ASSIGN (OffsetTo);
@ -319,10 +319,6 @@ struct OffsetTo : Offset<OffsetType, has_null>
hb_enable_if (hb_is_convertible (Base, void *))>
friend Type& operator + (OffsetTo &offset, Base &&base) { return offset ((void *) base); }
Type& serialize (hb_serialize_context_t *c, const void *base)
{
return * (Type *) Offset<OffsetType>::serialize (c, base);
}
template <typename ...Ts>
bool serialize_subset (hb_subset_context_t *c, const OffsetTo& src,
@ -346,6 +342,23 @@ struct OffsetTo : Offset<OffsetType, has_null>
return ret;
}
template <typename ...Ts>
bool serialize_serialize (hb_serialize_context_t *c, Ts&&... ds)
{
*this = 0;
Type* obj = c->push<Type> ();
bool ret = obj->serialize (c, hb_forward<Ts> (ds)...);
if (ret)
c->add_link (*this, c->pop_pack ());
else
c->pop_discard ();
return ret;
}
/* TODO: Somehow merge this with previous function into a serialize_dispatch(). */
/* Workaround clang bug: https://bugs.llvm.org/show_bug.cgi?id=23029
* Can't compile: whence = hb_serialize_context_t::Head followed by Ts&&...
@ -378,7 +391,7 @@ struct OffsetTo : Offset<OffsetType, has_null>
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this))) return_trace (false);
if (unlikely (this->is_null ())) return_trace (true);
if (unlikely (!c->check_range (base, *this))) return_trace (false);
if (unlikely ((const char *) base + (unsigned) *this < (const char *) base)) return_trace (false);
return_trace (true);
}
@ -401,12 +414,14 @@ struct OffsetTo : Offset<OffsetType, has_null>
DEFINE_SIZE_STATIC (sizeof (OffsetType));
};
/* Partial specializations. */
template <typename Type, bool has_null=true>
using LOffsetTo = OffsetTo<Type, HBUINT32, has_null>;
template <typename Type, typename OffsetType=HBUINT16>
using NNOffsetTo = OffsetTo<Type, OffsetType, false>;
template <typename Type>
using LNNOffsetTo = LOffsetTo<Type, false>;
template <typename Type, bool has_null=true> using Offset16To = OffsetTo<Type, HBUINT16, has_null>;
template <typename Type, bool has_null=true> using Offset24To = OffsetTo<Type, HBUINT24, has_null>;
template <typename Type, bool has_null=true> using Offset32To = OffsetTo<Type, HBUINT32, has_null>;
template <typename Type, typename OffsetType> using NNOffsetTo = OffsetTo<Type, OffsetType, false>;
template <typename Type> using NNOffset16To = Offset16To<Type, false>;
template <typename Type> using NNOffset24To = Offset24To<Type, false>;
template <typename Type> using NNOffset32To = Offset32To<Type, false>;
/*
@ -453,8 +468,10 @@ struct UnsizedArrayOf
const Type &lsearch (unsigned int len, const T &x, const Type &not_found = Null (Type)) const
{ return *as_array (len).lsearch (x, &not_found); }
template <typename T>
bool lfind (unsigned int len, const T &x, unsigned *pos = nullptr) const
{ return as_array (len).lfind (x, pos); }
bool lfind (unsigned int len, const T &x, unsigned int *i = nullptr,
hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
unsigned int to_store = (unsigned int) -1) const
{ return as_array (len).lfind (x, i, not_found, to_store); }
void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1)
{ as_array (len).qsort (start, end); }
@ -462,7 +479,7 @@ struct UnsizedArrayOf
bool serialize (hb_serialize_context_t *c, unsigned int items_len)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend (*this, items_len))) return_trace (false);
if (unlikely (!c->extend (this, items_len))) return_trace (false);
return_trace (true);
}
template <typename Iterator,
@ -513,11 +530,11 @@ struct UnsizedArrayOf
/* Unsized array of offset's */
template <typename Type, typename OffsetType, bool has_null=true>
using UnsizedOffsetArrayOf = UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null>>;
using UnsizedArray16OfOffsetTo = UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null>>;
/* Unsized array of offsets relative to the beginning of the array itself. */
template <typename Type, typename OffsetType, bool has_null=true>
struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType, has_null>
struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo<Type, OffsetType, has_null>
{
const Type& operator [] (int i_) const
{
@ -538,7 +555,7 @@ struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType, has_null>
bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const
{
TRACE_SANITIZE (this);
return_trace ((UnsizedOffsetArrayOf<Type, OffsetType, has_null>
return_trace ((UnsizedArray16OfOffsetTo<Type, OffsetType, has_null>
::sanitize (c, count, this, hb_forward<Ts> (ds)...)));
}
};
@ -562,14 +579,14 @@ struct SortedUnsizedArrayOf : UnsizedArrayOf<Type>
{ return *as_array (len).bsearch (x, &not_found); }
template <typename T>
bool bfind (unsigned int len, const T &x, unsigned int *i = nullptr,
hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
unsigned int to_store = (unsigned int) -1) const
{ return as_array (len).bfind (x, i, not_found, to_store); }
};
/* An array with a number of elements. */
template <typename Type, typename LenType=HBUINT16>
template <typename Type, typename LenType>
struct ArrayOf
{
typedef Type item_t;
@ -617,17 +634,32 @@ struct ArrayOf
hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
{ return as_array ().sub_array (start_offset, count); }
hb_success_t serialize (hb_serialize_context_t *c, unsigned items_len)
template <typename T>
Type &lsearch (const T &x, Type &not_found = Crap (Type))
{ return *as_array ().lsearch (x, &not_found); }
template <typename T>
const Type &lsearch (const T &x, const Type &not_found = Null (Type)) const
{ return *as_array ().lsearch (x, &not_found); }
template <typename T>
bool lfind (const T &x, unsigned int *i = nullptr,
hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
unsigned int to_store = (unsigned int) -1) const
{ return as_array ().lfind (x, i, not_found, to_store); }
void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1)
{ as_array ().qsort (start, end); }
HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned items_len)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (*this))) return_trace (false);
c->check_assign (len, items_len);
if (unlikely (!c->extend (*this))) return_trace (false);
if (unlikely (!c->extend_min (this))) return_trace (false);
c->check_assign (len, items_len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW);
if (unlikely (!c->extend (this))) return_trace (false);
return_trace (true);
}
template <typename Iterator,
hb_requires (hb_is_source_of (Iterator, Type))>
hb_success_t serialize (hb_serialize_context_t *c, Iterator items)
HB_NODISCARD bool serialize (hb_serialize_context_t *c, Iterator items)
{
TRACE_SERIALIZE (this);
unsigned count = items.len ();
@ -643,7 +675,7 @@ struct ArrayOf
{
TRACE_SERIALIZE (this);
len++;
if (unlikely (!len || !c->extend (*this)))
if (unlikely (!len || !c->extend (this)))
{
len--;
return_trace (nullptr);
@ -656,7 +688,7 @@ struct ArrayOf
TRACE_SERIALIZE (this);
auto *out = c->start_embed (this);
if (unlikely (!c->extend_min (out))) return_trace (nullptr);
c->check_assign (out->len, len);
c->check_assign (out->len, len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW);
if (unlikely (!as_array ().copy (c))) return_trace (nullptr);
return_trace (out);
}
@ -674,19 +706,6 @@ struct ArrayOf
return_trace (true);
}
template <typename T>
Type &lsearch (const T &x, Type &not_found = Crap (Type))
{ return *as_array ().lsearch (x, &not_found); }
template <typename T>
const Type &lsearch (const T &x, const Type &not_found = Null (Type)) const
{ return *as_array ().lsearch (x, &not_found); }
template <typename T>
bool lfind (const T &x, unsigned *pos = nullptr) const
{ return as_array ().lfind (x, pos); }
void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1)
{ as_array ().qsort (start, end); }
bool sanitize_shallow (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@ -699,21 +718,18 @@ struct ArrayOf
public:
DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
};
template <typename Type>
using LArrayOf = ArrayOf<Type, HBUINT32>;
template <typename Type> using Array16Of = ArrayOf<Type, HBUINT16>;
template <typename Type> using Array32Of = ArrayOf<Type, HBUINT32>;
using PString = ArrayOf<HBUINT8, HBUINT8>;
/* Array of Offset's */
template <typename Type>
using OffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT16>>;
template <typename Type>
using LOffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT32>>;
template <typename Type>
using LOffsetLArrayOf = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32>;
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>;
/* Array of offsets relative to the beginning of the array itself. */
template <typename Type>
struct OffsetListOf : OffsetArrayOf<Type>
struct List16OfOffset16To : Array16OfOffset16To<Type>
{
const Type& operator [] (int i_) const
{
@ -731,7 +747,7 @@ struct OffsetListOf : OffsetArrayOf<Type>
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
struct OffsetListOf<Type> *out = c->serializer->embed (*this);
struct List16OfOffset16To<Type> *out = c->serializer->embed (*this);
if (unlikely (!out)) return_trace (false);
unsigned int count = this->len;
for (unsigned int i = 0; i < count; i++)
@ -743,7 +759,7 @@ struct OffsetListOf : OffsetArrayOf<Type>
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
{
TRACE_SANITIZE (this);
return_trace (OffsetArrayOf<Type>::sanitize (c, this, hb_forward<Ts> (ds)...));
return_trace (Array16OfOffset16To<Type>::sanitize (c, this, hb_forward<Ts> (ds)...));
}
};
@ -786,9 +802,9 @@ struct HeadlessArrayOf
bool serialize (hb_serialize_context_t *c, unsigned int items_len)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (*this))) return_trace (false);
c->check_assign (lenP1, items_len + 1);
if (unlikely (!c->extend (*this))) return_trace (false);
if (unlikely (!c->extend_min (this))) return_trace (false);
c->check_assign (lenP1, items_len + 1, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW);
if (unlikely (!c->extend (this))) return_trace (false);
return_trace (true);
}
template <typename Iterator,
@ -859,6 +875,7 @@ struct ArrayOfM1
{
TRACE_SANITIZE (this);
if (unlikely (!sanitize_shallow (c))) return_trace (false);
if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true);
unsigned int count = lenM1 + 1;
for (unsigned int i = 0; i < count; i++)
if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
@ -882,7 +899,7 @@ struct ArrayOfM1
};
/* An array with sorted elements. Supports binary searching. */
template <typename Type, typename LenType=HBUINT16>
template <typename Type, typename LenType>
struct SortedArrayOf : ArrayOf<Type, LenType>
{
hb_sorted_array_t< Type> as_array () { return hb_sorted_array (this->arrayZ, this->len); }
@ -928,11 +945,14 @@ struct SortedArrayOf : ArrayOf<Type, LenType>
{ return *as_array ().bsearch (x, &not_found); }
template <typename T>
bool bfind (const T &x, unsigned int *i = nullptr,
hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
unsigned int to_store = (unsigned int) -1) const
{ return as_array ().bfind (x, i, not_found, to_store); }
};
template <typename Type> using SortedArray16Of = SortedArrayOf<Type, HBUINT16>;
template <typename Type> using SortedArray32Of = SortedArrayOf<Type, HBUINT32>;
/*
* Binary-search arrays
*/

View File

@ -126,7 +126,7 @@ struct CFFIndex
else
{
/* serialize CFFIndex header */
if (unlikely (!c->extend_min (*this))) return_trace (false);
if (unlikely (!c->extend_min (this))) return_trace (false);
this->count = byteArray.length;
this->offSize = offSize_;
if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (byteArray.length + 1))))
@ -214,7 +214,7 @@ struct CFFIndex
unsigned off_size = calcOffSize (total);
/* serialize CFFIndex header */
if (unlikely (!c->extend_min (*this))) return_trace (false);
if (unlikely (!c->extend_min (this))) return_trace (false);
this->count = it.len ();
this->offSize = off_size;
if (unlikely (!c->allocate_size<HBUINT8> (off_size * (it.len () + 1))))
@ -335,7 +335,7 @@ struct CFFIndexOf : CFFIndex<COUNT>
{
TRACE_SERIALIZE (this);
/* serialize CFFIndex header */
if (unlikely (!c->extend_min (*this))) return_trace (false);
if (unlikely (!c->extend_min (this))) return_trace (false);
this->count = dataArrayLen;
this->offSize = offSize_;
if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1))))

View File

@ -187,7 +187,7 @@ struct Encoding
const hb_vector_t<code_pair_t>& supp_codes)
{
TRACE_SERIALIZE (this);
Encoding *dest = c->extend_min (*this);
Encoding *dest = c->extend_min (this);
if (unlikely (!dest)) return_trace (false);
dest->format = format | ((supp_codes.length > 0) ? 0x80 : 0);
switch (format) {
@ -457,7 +457,7 @@ struct Charset
const hb_vector_t<code_pair_t>& sid_ranges)
{
TRACE_SERIALIZE (this);
Charset *dest = c->extend_min (*this);
Charset *dest = c->extend_min (this);
if (unlikely (!dest)) return_trace (false);
dest->format = format;
switch (format)
@ -713,6 +713,7 @@ struct cff1_top_dict_opset_t : top_dict_opset_t<cff1_top_dict_val_t>
case OpCode_Notice:
case OpCode_Copyright:
case OpCode_FullName:
case OpCode_FontName:
case OpCode_FamilyName:
case OpCode_Weight:
case OpCode_PostScript:
@ -1390,7 +1391,7 @@ struct cff1
public:
FixedVersion<HBUINT8> version; /* Version of CFF table. set to 0x0100u */
OffsetTo<CFF1NameIndex, HBUINT8> nameIndex; /* headerSize = Offset to Name INDEX. */
NNOffsetTo<CFF1NameIndex, HBUINT8> nameIndex; /* headerSize = Offset to Name INDEX. */
HBUINT8 offSize; /* offset size (unused?) */
public:

View File

@ -49,6 +49,12 @@ struct CmapSubtableFormat0
*glyph = gid;
return true;
}
unsigned get_language () const
{
return language;
}
void collect_unicodes (hb_set_t *out) const
{
for (unsigned int i = 0; i < 256; i++)
@ -212,29 +218,24 @@ struct CmapSubtableFormat4
HBINT16 *idDelta,
unsigned segcount)
{
hb_hashmap_t<hb_codepoint_t, hb_codepoint_t> cp_to_gid;
+ it | hb_sink (cp_to_gid);
HBUINT16 *idRangeOffset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
if (unlikely (!c->check_success (idRangeOffset))) return nullptr;
if (unlikely ((char *)idRangeOffset - (char *)idDelta != (int) segcount * (int) HBINT16::static_size)) return nullptr;
+ hb_range (segcount)
| hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; })
| hb_apply ([&] (const unsigned i)
{
idRangeOffset[i] = 2 * (c->start_embed<HBUINT16> () - idRangeOffset - i);
+ it
| hb_filter ([&] (const hb_item_type<Iterator> _) { return _.first >= startCode[i] && _.first <= endCode[i]; })
| hb_apply ([&] (const hb_item_type<Iterator> _)
{
HBUINT16 glyID;
glyID = _.second;
c->copy<HBUINT16> (glyID);
})
;
})
;
for (unsigned i : + hb_range (segcount)
| hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; }))
{
idRangeOffset[i] = 2 * (c->start_embed<HBUINT16> () - idRangeOffset - i);
for (hb_codepoint_t cp = startCode[i]; cp <= endCode[i]; cp++)
{
HBUINT16 gid;
gid = cp_to_gid[cp];
c->copy<HBUINT16> (gid);
}
}
return idRangeOffset;
}
@ -253,7 +254,7 @@ struct CmapSubtableFormat4
if (format4_iter.len () == 0) return;
unsigned table_initpos = c->length ();
if (unlikely (!c->extend_min (*this))) return;
if (unlikely (!c->extend_min (this))) return;
this->format = 4;
//serialize endCode[]
@ -276,7 +277,17 @@ struct CmapSubtableFormat4
HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c, format4_iter, endCode, startCode, idDelta, segcount);
if (unlikely (!c->check_success (idRangeOffset))) return;
if (unlikely (!c->check_assign(this->length, c->length () - table_initpos))) return;
this->length = c->length () - table_initpos;
if ((long long) this->length != (long long) c->length () - table_initpos)
{
// Length overflowed. Discard the current object before setting the error condition, otherwise
// discard is a noop which prevents the higher level code from reverting the serializer to the
// pre-error state in cmap4 overflow handling code.
c->pop_discard ();
c->err (HB_SERIALIZE_ERROR_INT_OVERFLOW);
return;
}
this->segCountX2 = segcount * 2;
this->entrySelector = hb_max (1u, hb_bit_storage (segcount)) - 1;
this->searchRange = 2 * (1u << this->entrySelector);
@ -285,6 +296,11 @@ struct CmapSubtableFormat4
: 0;
}
unsigned get_language () const
{
return language;
}
struct accelerator_t
{
accelerator_t () {}
@ -547,6 +563,12 @@ struct CmapSubtableTrimmed
*glyph = gid;
return true;
}
unsigned get_language () const
{
return language;
}
void collect_unicodes (hb_set_t *out) const
{
hb_codepoint_t start = startCharCode;
@ -606,6 +628,11 @@ struct CmapSubtableLongSegmented
return true;
}
unsigned get_language () const
{
return language;
}
void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const
{
for (unsigned int i = 0; i < this->groups.len; i++)
@ -670,7 +697,7 @@ struct CmapSubtableLongSegmented
HBUINT16 reserved; /* Reserved; set to 0. */
HBUINT32 length; /* Byte length of this subtable. */
HBUINT32 language; /* Ignore. */
SortedArrayOf<CmapSubtableLongGroup, HBUINT32>
SortedArray32Of<CmapSubtableLongGroup>
groups; /* Groupings. */
public:
DEFINE_SIZE_ARRAY (16, groups);
@ -691,7 +718,7 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
{
if (it.len () == 0) return;
unsigned table_initpos = c->length ();
if (unlikely (!c->extend_min (*this))) return;
if (unlikely (!c->extend_min (this))) return;
hb_codepoint_t startCharCode = 0xFFFF, endCharCode = 0xFFFF;
hb_codepoint_t glyphID = 0;
@ -784,7 +811,7 @@ struct UnicodeValueRange
DEFINE_SIZE_STATIC (4);
};
struct DefaultUVS : SortedArrayOf<UnicodeValueRange, HBUINT32>
struct DefaultUVS : SortedArray32Of<UnicodeValueRange>
{
void collect_unicodes (hb_set_t *out) const
{
@ -850,7 +877,9 @@ struct DefaultUVS : SortedArrayOf<UnicodeValueRange, HBUINT32>
}
else
{
if (unlikely (!c->check_assign (out->len, (c->length () - init_len) / UnicodeValueRange::static_size))) return nullptr;
if (unlikely (!c->check_assign (out->len,
(c->length () - init_len) / UnicodeValueRange::static_size,
HB_SERIALIZE_ERROR_INT_OVERFLOW))) return nullptr;
return out;
}
}
@ -876,23 +905,21 @@ struct UVSMapping
DEFINE_SIZE_STATIC (5);
};
struct NonDefaultUVS : SortedArrayOf<UVSMapping, HBUINT32>
struct NonDefaultUVS : SortedArray32Of<UVSMapping>
{
void collect_unicodes (hb_set_t *out) const
{
unsigned int count = len;
for (unsigned int i = 0; i < count; i++)
out->add (arrayZ[i].unicodeValue);
for (const auto& a : as_array ())
out->add (a.unicodeValue);
}
void collect_mapping (hb_set_t *unicodes, /* OUT */
hb_map_t *mapping /* OUT */) const
{
unsigned count = len;
for (unsigned i = 0; i < count; i++)
for (const auto& a : as_array ())
{
hb_codepoint_t unicode = arrayZ[i].unicodeValue;
hb_codepoint_t glyphid = arrayZ[i].glyphID;
hb_codepoint_t unicode = a.unicodeValue;
hb_codepoint_t glyphid = a.glyphID;
unicodes->add (unicode);
mapping->set (unicode, glyphid);
}
@ -1041,9 +1068,9 @@ struct VariationSelectorRecord
}
HBUINT24 varSelector; /* Variation selector. */
LOffsetTo<DefaultUVS>
Offset32To<DefaultUVS>
defaultUVS; /* Offset to Default UVS Table. May be 0. */
LOffsetTo<NonDefaultUVS>
Offset32To<NonDefaultUVS>
nonDefaultUVS; /* Offset to Non-Default UVS Table. May be 0. */
public:
DEFINE_SIZE_STATIC (11);
@ -1058,9 +1085,8 @@ struct CmapSubtableFormat14
void collect_variation_selectors (hb_set_t *out) const
{
unsigned int count = record.len;
for (unsigned int i = 0; i < count; i++)
out->add (record.arrayZ[i].varSelector);
for (const auto& a : record.as_array ())
out->add (a.varSelector);
}
void collect_variation_unicodes (hb_codepoint_t variation_selector,
hb_set_t *out) const
@ -1076,7 +1102,7 @@ struct CmapSubtableFormat14
unsigned table_initpos = c->length ();
const char* init_tail = c->tail;
if (unlikely (!c->extend_min (*this))) return;
if (unlikely (!c->extend_min (this))) return;
this->format = 14;
auto src_tbl = reinterpret_cast<const CmapSubtableFormat14*> (base);
@ -1112,10 +1138,12 @@ struct CmapSubtableFormat14
return;
int tail_len = init_tail - c->tail;
c->check_assign (this->length, c->length () - table_initpos + tail_len);
c->check_assign (this->length, c->length () - table_initpos + tail_len,
HB_SERIALIZE_ERROR_INT_OVERFLOW);
c->check_assign (this->record.len,
(c->length () - table_initpos - CmapSubtableFormat14::min_size) /
VariationSelectorRecord::static_size);
VariationSelectorRecord::static_size,
HB_SERIALIZE_ERROR_INT_OVERFLOW);
/* Correct the incorrect write order by reversing the order of the variation
records array. */
@ -1180,7 +1208,7 @@ struct CmapSubtableFormat14
protected:
HBUINT16 format; /* Format number is set to 14. */
HBUINT32 length; /* Byte length of this subtable. */
SortedArrayOf<VariationSelectorRecord, HBUINT32>
SortedArray32Of<VariationSelectorRecord>
record; /* Variation selector records; sorted
* in increasing order of `varSelector'. */
public:
@ -1235,6 +1263,20 @@ struct CmapSubtable
}
}
unsigned get_language () const
{
switch (u.format) {
case 0: return u.format0 .get_language ();
case 4: return u.format4 .get_language ();
case 6: return u.format6 .get_language ();
case 10: return u.format10.get_language ();
case 12: return u.format12.get_language ();
case 13: return u.format13.get_language ();
case 14:
default: return 0;
}
}
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
void serialize (hb_serialize_context_t *c,
@ -1338,7 +1380,7 @@ struct EncodingRecord
HBUINT16 platformID; /* Platform ID. */
HBUINT16 encodingID; /* Platform-specific encoding ID. */
LOffsetTo<CmapSubtable>
Offset32To<CmapSubtable>
subtable; /* Byte offset from beginning of table to the subtable for this encoding. */
public:
DEFINE_SIZE_STATIC (8);
@ -1350,58 +1392,112 @@ struct cmap
template<typename Iterator, typename EncodingRecIter,
hb_requires (hb_is_iterator (EncodingRecIter))>
void serialize (hb_serialize_context_t *c,
bool serialize (hb_serialize_context_t *c,
Iterator it,
EncodingRecIter encodingrec_iter,
const void *base,
const hb_subset_plan_t *plan)
const hb_subset_plan_t *plan,
bool drop_format_4 = false)
{
if (unlikely (!c->extend_min ((*this)))) return;
if (unlikely (!c->extend_min ((*this)))) return false;
this->version = 0;
unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0;
auto snap = c->snapshot ();
for (const EncodingRecord& _ : encodingrec_iter)
{
if (c->in_error ())
return false;
unsigned format = (base+_.subtable).u.format;
if (!plan->glyphs_requested->is_empty ())
if (format != 4 && format != 12 && format != 14) continue;
hb_set_t unicodes_set;
(base+_.subtable).collect_unicodes (&unicodes_set);
if (!drop_format_4 && format == 4)
{
hb_set_t unicodes_set;
hb_map_t cp_glyphid_map;
(base+_.subtable).collect_mapping (&unicodes_set, &cp_glyphid_map);
auto table_iter =
+ hb_zip (unicodes_set.iter(), unicodes_set.iter() | hb_map(cp_glyphid_map))
| hb_filter (plan->_glyphset, hb_second)
| hb_filter ([plan] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& p)
{
return plan->unicodes->has (p.first) ||
plan->glyphs_requested->has (p.second);
})
| hb_map ([plan] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& p_org)
{
return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (p_org.first, plan->glyph_map->get(p_org.second));
})
;
if (format == 4) c->copy (_, table_iter, 4u, base, plan, &format4objidx);
else if (format == 12) c->copy (_, table_iter, 12u, base, plan, &format12objidx);
else if (format == 14) c->copy (_, table_iter, 14u, base, plan, &format14objidx);
c->copy (_, + it | hb_filter (unicodes_set, hb_first), 4u, base, plan, &format4objidx);
if (c->in_error () && c->only_overflow ())
{
// cmap4 overflowed, reset and retry serialization without format 4 subtables.
c->revert (snap);
return serialize (c, it,
encodingrec_iter,
base,
plan,
true);
}
}
/* when --gids option is not used, we iterate input unicodes instead of
* all codepoints in each subtable, which is more efficient */
else
else if (format == 12)
{
hb_set_t unicodes_set;
(base+_.subtable).collect_unicodes (&unicodes_set);
if (format == 4) c->copy (_, + it | hb_filter (unicodes_set, hb_first), 4u, base, plan, &format4objidx);
else if (format == 12) c->copy (_, + it | hb_filter (unicodes_set, hb_first), 12u, base, plan, &format12objidx);
else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx);
if (_can_drop (_, unicodes_set, base, + it | hb_map (hb_first), encodingrec_iter)) continue;
c->copy (_, + it | hb_filter (unicodes_set, hb_first), 12u, base, plan, &format12objidx);
}
else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx);
}
c->check_assign(this->encodingRecord.len,
(c->length () - cmap::min_size)/EncodingRecord::static_size,
HB_SERIALIZE_ERROR_INT_OVERFLOW);
// Fail if format 4 was dropped and there is no cmap12.
return !drop_format_4 || format12objidx;
}
template<typename Iterator, typename EncodingRecordIterator,
hb_requires (hb_is_iterator (Iterator)),
hb_requires (hb_is_iterator (EncodingRecordIterator))>
bool _can_drop (const EncodingRecord& cmap12,
const hb_set_t& cmap12_unicodes,
const void* base,
Iterator subset_unicodes,
EncodingRecordIterator encoding_records)
{
for (auto cp : + subset_unicodes | hb_filter (cmap12_unicodes))
{
if (cp >= 0x10000) return false;
}
c->check_assign(this->encodingRecord.len, (c->length () - cmap::min_size)/EncodingRecord::static_size);
unsigned target_platform;
unsigned target_encoding;
unsigned target_language = (base+cmap12.subtable).get_language ();
if (cmap12.platformID == 0 && cmap12.encodingID == 4)
{
target_platform = 0;
target_encoding = 3;
} else if (cmap12.platformID == 3 && cmap12.encodingID == 10) {
target_platform = 3;
target_encoding = 1;
} else {
return false;
}
for (const auto& _ : encoding_records)
{
if (_.platformID != target_platform
|| _.encodingID != target_encoding
|| (base+_.subtable).get_language() != target_language)
continue;
hb_set_t sibling_unicodes;
(base+_.subtable).collect_unicodes (&sibling_unicodes);
auto cmap12 = + subset_unicodes | hb_filter (cmap12_unicodes);
auto sibling = + subset_unicodes | hb_filter (sibling_unicodes);
for (; cmap12 && sibling; cmap12++, sibling++)
{
unsigned a = *cmap12;
unsigned b = *sibling;
if (a != b) return false;
}
return !cmap12 && !sibling;
}
return false;
}
void closure_glyphs (const hb_set_t *unicodes,
@ -1468,8 +1564,8 @@ struct cmap
| hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> _)
{ return (_.second != HB_MAP_VALUE_INVALID); })
;
cmap_prime->serialize (c->serializer, it, encodingrec_iter, this, c->plan);
return_trace (true);
return_trace (cmap_prime->serialize (c->serializer, it, encodingrec_iter, this, c->plan));
}
const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const
@ -1697,7 +1793,7 @@ struct cmap
protected:
HBUINT16 version; /* Table version number (0). */
SortedArrayOf<EncodingRecord>
SortedArray16Of<EncodingRecord>
encodingRecord; /* Encoding tables. */
public:
DEFINE_SIZE_ARRAY (4, encodingRecord);

View File

@ -510,7 +510,7 @@ struct IndexSubtableRecord
HBGlyphID firstGlyphIndex;
HBGlyphID lastGlyphIndex;
LOffsetTo<IndexSubtable> offsetToSubtable;
Offset32To<IndexSubtable> offsetToSubtable;
public:
DEFINE_SIZE_STATIC (8);
};
@ -672,7 +672,7 @@ struct BitmapSizeTable
}
protected:
LNNOffsetTo<IndexSubtableArray>
NNOffset32To<IndexSubtableArray>
indexSubtableArrayOffset;
HBUINT32 indexTablesSize;
HBUINT32 numberOfIndexSubtables;
@ -697,7 +697,7 @@ struct BitmapSizeTable
struct GlyphBitmapDataFormat17
{
SmallGlyphMetrics glyphMetrics;
LArrayOf<HBUINT8> data;
Array32Of<HBUINT8> data;
public:
DEFINE_SIZE_ARRAY (9, data);
};
@ -705,14 +705,14 @@ struct GlyphBitmapDataFormat17
struct GlyphBitmapDataFormat18
{
BigGlyphMetrics glyphMetrics;
LArrayOf<HBUINT8> data;
Array32Of<HBUINT8> data;
public:
DEFINE_SIZE_ARRAY (12, data);
};
struct GlyphBitmapDataFormat19
{
LArrayOf<HBUINT8> data;
Array32Of<HBUINT8> data;
public:
DEFINE_SIZE_ARRAY (4, data);
};
@ -738,7 +738,7 @@ struct CBLC
cbdt_prime->length,
HB_MEMORY_MODE_WRITABLE,
cbdt_prime->arrayZ,
free);
hb_free);
cbdt_prime->init (); // Leak arrayZ to the blob.
bool ret = c->plan->add_table (HB_OT_TAG_CBDT, cbdt_prime_blob);
hb_blob_destroy (cbdt_prime_blob);
@ -798,7 +798,7 @@ struct CBLC
protected:
FixedVersion<> version;
LArrayOf<BitmapSizeTable> sizeTables;
Array32Of<BitmapSizeTable> sizeTables;
public:
DEFINE_SIZE_ARRAY (8, sizeTables);
};

View File

@ -29,6 +29,7 @@
#define HB_OT_COLOR_COLR_TABLE_HH
#include "hb-open-type.hh"
#include "hb-ot-layout-common.hh"
/*
* COLR -- Color
@ -36,9 +37,78 @@
*/
#define HB_OT_TAG_COLR HB_TAG('C','O','L','R')
#ifndef COLRV1_MAX_NESTING_LEVEL
#define COLRV1_MAX_NESTING_LEVEL 100
#endif
#ifndef COLRV1_ENABLE_SUBSETTING
#define COLRV1_ENABLE_SUBSETTING 0
#endif
namespace OT {
struct COLR;
struct hb_colrv1_closure_context_t :
hb_dispatch_context_t<hb_colrv1_closure_context_t>
{
template <typename T>
return_t dispatch (const T &obj)
{
if (unlikely (nesting_level_left == 0))
return hb_empty_t ();
if (paint_visited (&obj))
return hb_empty_t ();
nesting_level_left--;
obj.closurev1 (this);
nesting_level_left++;
return hb_empty_t ();
}
static return_t default_return_value () { return hb_empty_t (); }
bool paint_visited (const void *paint)
{
hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) paint - (uintptr_t) base);
if (visited_paint.has (delta))
return true;
visited_paint.add (delta);
return false;
}
const COLR* get_colr_table () const
{ return reinterpret_cast<const COLR *> (base); }
void add_glyph (unsigned glyph_id)
{ glyphs->add (glyph_id); }
void add_layer_indices (unsigned first_layer_index, unsigned num_of_layers)
{ layer_indices->add_range (first_layer_index, first_layer_index + num_of_layers - 1); }
void add_palette_index (unsigned palette_index)
{ palette_indices->add (palette_index); }
public:
const void *base;
hb_set_t visited_paint;
hb_set_t *glyphs;
hb_set_t *layer_indices;
hb_set_t *palette_indices;
unsigned nesting_level_left;
hb_colrv1_closure_context_t (const void *base_,
hb_set_t *glyphs_,
hb_set_t *layer_indices_,
hb_set_t *palette_indices_,
unsigned nesting_level_left_ = COLRV1_MAX_NESTING_LEVEL) :
base (base_),
glyphs (glyphs_),
layer_indices (layer_indices_),
palette_indices (palette_indices_),
nesting_level_left (nesting_level_left_)
{}
};
struct LayerRecord
{
@ -90,6 +160,707 @@ struct BaseGlyphRecord
DEFINE_SIZE_STATIC (6);
};
template <typename T>
struct Variable
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
protected:
T value;
VarIdx varIdx;
public:
DEFINE_SIZE_STATIC (4 + T::static_size);
};
template <typename T>
struct NoVariable
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
T value;
public:
DEFINE_SIZE_STATIC (T::static_size);
};
// Color structures
template <template<typename> class Var>
struct ColorIndex
{
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (*this);
if (unlikely (!out)) return_trace (false);
return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes->get (paletteIndex),
HB_SERIALIZE_ERROR_INT_OVERFLOW));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
HBUINT16 paletteIndex;
Var<F2DOT14> alpha;
public:
DEFINE_SIZE_STATIC (2 + Var<F2DOT14>::static_size);
};
template <template<typename> class Var>
struct ColorStop
{
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
if (unlikely (!c->serializer->embed (stopOffset))) return_trace (false);
return_trace (color.subset (c));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
Var<F2DOT14> stopOffset;
ColorIndex<Var> color;
public:
DEFINE_SIZE_STATIC (Var<F2DOT14>::static_size + ColorIndex<Var>::static_size);
};
struct Extend : HBUINT8
{
enum {
EXTEND_PAD = 0,
EXTEND_REPEAT = 1,
EXTEND_REFLECT = 2,
};
public:
DEFINE_SIZE_STATIC (1);
};
template <template<typename> class Var>
struct ColorLine
{
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this);
if (unlikely (!out)) return_trace (false);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
if (!c->serializer->check_assign (out->extend, extend, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
if (!c->serializer->check_assign (out->stops.len, stops.len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)) return_trace (false);
for (const auto& stop : stops.iter ())
{
if (!stop.subset (c)) return_trace (false);
}
return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
stops.sanitize (c));
}
Extend extend;
Array16Of<ColorStop<Var>> stops;
public:
DEFINE_SIZE_ARRAY_SIZED (3, stops);
};
// Composition modes
// Compositing modes are taken from https://www.w3.org/TR/compositing-1/
// NOTE: a brief audit of major implementations suggests most support most
// or all of the specified modes.
struct CompositeMode : HBUINT8
{
enum {
// Porter-Duff modes
// https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators
COMPOSITE_CLEAR = 0, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_clear
COMPOSITE_SRC = 1, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_src
COMPOSITE_DEST = 2, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dst
COMPOSITE_SRC_OVER = 3, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcover
COMPOSITE_DEST_OVER = 4, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstover
COMPOSITE_SRC_IN = 5, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcin
COMPOSITE_DEST_IN = 6, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstin
COMPOSITE_SRC_OUT = 7, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcout
COMPOSITE_DEST_OUT = 8, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstout
COMPOSITE_SRC_ATOP = 9, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcatop
COMPOSITE_DEST_ATOP = 10, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstatop
COMPOSITE_XOR = 11, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_xor
COMPOSITE_PLUS = 12, // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_plus
// Blend modes
// https://www.w3.org/TR/compositing-1/#blending
COMPOSITE_SCREEN = 13, // https://www.w3.org/TR/compositing-1/#blendingscreen
COMPOSITE_OVERLAY = 14, // https://www.w3.org/TR/compositing-1/#blendingoverlay
COMPOSITE_DARKEN = 15, // https://www.w3.org/TR/compositing-1/#blendingdarken
COMPOSITE_LIGHTEN = 16, // https://www.w3.org/TR/compositing-1/#blendinglighten
COMPOSITE_COLOR_DODGE = 17, // https://www.w3.org/TR/compositing-1/#blendingcolordodge
COMPOSITE_COLOR_BURN = 18, // https://www.w3.org/TR/compositing-1/#blendingcolorburn
COMPOSITE_HARD_LIGHT = 19, // https://www.w3.org/TR/compositing-1/#blendinghardlight
COMPOSITE_SOFT_LIGHT = 20, // https://www.w3.org/TR/compositing-1/#blendingsoftlight
COMPOSITE_DIFFERENCE = 21, // https://www.w3.org/TR/compositing-1/#blendingdifference
COMPOSITE_EXCLUSION = 22, // https://www.w3.org/TR/compositing-1/#blendingexclusion
COMPOSITE_MULTIPLY = 23, // https://www.w3.org/TR/compositing-1/#blendingmultiply
// Modes that, uniquely, do not operate on components
// https://www.w3.org/TR/compositing-1/#blendingnonseparable
COMPOSITE_HSL_HUE = 24, // https://www.w3.org/TR/compositing-1/#blendinghue
COMPOSITE_HSL_SATURATION = 25, // https://www.w3.org/TR/compositing-1/#blendingsaturation
COMPOSITE_HSL_COLOR = 26, // https://www.w3.org/TR/compositing-1/#blendingcolor
COMPOSITE_HSL_LUMINOSITY = 27, // https://www.w3.org/TR/compositing-1/#blendingluminosity
};
public:
DEFINE_SIZE_STATIC (1);
};
template <template<typename> class Var>
struct Affine2x3
{
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
Var<HBFixed> xx;
Var<HBFixed> yx;
Var<HBFixed> xy;
Var<HBFixed> yy;
Var<HBFixed> dx;
Var<HBFixed> dy;
public:
DEFINE_SIZE_STATIC (6 * Var<HBFixed>::static_size);
};
struct PaintColrLayers
{
void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
return_trace (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers->get (firstLayerIndex),
HB_SERIALIZE_ERROR_INT_OVERFLOW));
return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
HBUINT8 format; /* format = 1 */
HBUINT8 numLayers;
HBUINT32 firstLayerIndex; /* index into COLRv1::layersV1 */
public:
DEFINE_SIZE_STATIC (6);
};
template <template<typename> class Var>
struct PaintSolid
{
void closurev1 (hb_colrv1_closure_context_t* c) const
{ c->add_palette_index (color.paletteIndex); }
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
if (unlikely (!c->serializer->embed (format))) return_trace (false);
return_trace (color.subset (c));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
HBUINT8 format; /* format = 2(noVar) or 3(Var)*/
ColorIndex<Var> color;
public:
DEFINE_SIZE_STATIC (1 + ColorIndex<Var>::static_size);
};
template <template<typename> class Var>
struct PaintLinearGradient
{
void closurev1 (hb_colrv1_closure_context_t* c) const
{
for (const auto &stop : (this+colorLine).stops.iter ())
c->add_palette_index (stop.color.paletteIndex);
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
return_trace (out->colorLine.serialize_subset (c, colorLine, this));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
}
HBUINT8 format; /* format = 4(noVar) or 5 (Var) */
Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintLinearGradient
* table) to ColorLine subtable. */
Var<FWORD> x0;
Var<FWORD> y0;
Var<FWORD> x1;
Var<FWORD> y1;
Var<FWORD> x2;
Var<FWORD> y2;
public:
DEFINE_SIZE_STATIC (4 + 6 * Var<FWORD>::static_size);
};
template <template<typename> class Var>
struct PaintRadialGradient
{
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
return_trace (out->colorLine.serialize_subset (c, colorLine, this));
}
void closurev1 (hb_colrv1_closure_context_t* c) const
{
for (const auto &stop : (this+colorLine).stops.iter ())
c->add_palette_index (stop.color.paletteIndex);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
}
HBUINT8 format; /* format = 6(noVar) or 7 (Var) */
Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintRadialGradient
* table) to ColorLine subtable. */
Var<FWORD> x0;
Var<FWORD> y0;
Var<UFWORD> radius0;
Var<FWORD> x1;
Var<FWORD> y1;
Var<UFWORD> radius1;
public:
DEFINE_SIZE_STATIC (4 + 6 * Var<FWORD>::static_size);
};
template <template<typename> class Var>
struct PaintSweepGradient
{
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
return_trace (out->colorLine.serialize_subset (c, colorLine, this));
}
void closurev1 (hb_colrv1_closure_context_t* c) const
{
for (const auto &stop : (this+colorLine).stops.iter ())
c->add_palette_index (stop.color.paletteIndex);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
}
HBUINT8 format; /* format = 8(noVar) or 9 (Var) */
Offset24To<ColorLine<Var>> colorLine; /* Offset (from beginning of PaintSweepGradient
* table) to ColorLine subtable. */
Var<FWORD> centerX;
Var<FWORD> centerY;
Var<HBFixed> startAngle;
Var<HBFixed> endAngle;
public:
DEFINE_SIZE_STATIC (2 * Var<FWORD>::static_size + 2 * Var<HBFixed>::static_size);
};
struct Paint;
// Paint a non-COLR glyph, filled as indicated by paint.
struct PaintGlyph
{
void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
if (! c->serializer->check_assign (out->gid, c->plan->glyph_map->get (gid),
HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false);
return_trace (out->paint.serialize_subset (c, paint, this));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && paint.sanitize (c, this));
}
HBUINT8 format; /* format = 10 */
Offset24To<Paint> paint; /* Offset (from beginning of PaintGlyph table) to Paint subtable. */
HBUINT16 gid;
public:
DEFINE_SIZE_STATIC (6);
};
struct PaintColrGlyph
{
void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
return_trace (c->serializer->check_assign (out->gid, c->plan->glyph_map->get (gid),
HB_SERIALIZE_ERROR_INT_OVERFLOW));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
HBUINT8 format; /* format = 11 */
HBUINT16 gid;
public:
DEFINE_SIZE_STATIC (3);
};
template <template<typename> class Var>
struct PaintTransform
{
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
return_trace (out->src.serialize_subset (c, src, this));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && src.sanitize (c, this));
}
HBUINT8 format; /* format = 12(noVar) or 13 (Var) */
Offset24To<Paint> src; /* Offset (from beginning of PaintTransform table) to Paint subtable. */
Affine2x3<Var> transform;
public:
DEFINE_SIZE_STATIC (4 + Affine2x3<Var>::static_size);
};
template <template<typename> class Var>
struct PaintTranslate
{
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
return_trace (out->src.serialize_subset (c, src, this));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && src.sanitize (c, this));
}
HBUINT8 format; /* format = 14(noVar) or 15 (Var) */
Offset24To<Paint> src; /* Offset (from beginning of PaintTranslate table) to Paint subtable. */
Var<HBFixed> dx;
Var<HBFixed> dy;
public:
DEFINE_SIZE_STATIC (4 + Var<HBFixed>::static_size);
};
template <template<typename> class Var>
struct PaintRotate
{
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
return_trace (out->src.serialize_subset (c, src, this));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && src.sanitize (c, this));
}
HBUINT8 format; /* format = 16 (noVar) or 17(Var) */
Offset24To<Paint> src; /* Offset (from beginning of PaintRotate table) to Paint subtable. */
Var<HBFixed> angle;
Var<HBFixed> centerX;
Var<HBFixed> centerY;
public:
DEFINE_SIZE_STATIC (4 + 3 * Var<HBFixed>::static_size);
};
template <template<typename> class Var>
struct PaintSkew
{
HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
return_trace (out->src.serialize_subset (c, src, this));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && src.sanitize (c, this));
}
HBUINT8 format; /* format = 18(noVar) or 19 (Var) */
Offset24To<Paint> src; /* Offset (from beginning of PaintSkew table) to Paint subtable. */
Var<HBFixed> xSkewAngle;
Var<HBFixed> ySkewAngle;
Var<HBFixed> centerX;
Var<HBFixed> centerY;
public:
DEFINE_SIZE_STATIC (4 + 4 * Var<HBFixed>::static_size);
};
struct PaintComposite
{
void closurev1 (hb_colrv1_closure_context_t* c) const;
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->embed (this);
if (unlikely (!out)) return_trace (false);
if (!out->src.serialize_subset (c, src, this)) return_trace (false);
return_trace (out->backdrop.serialize_subset (c, backdrop, this));
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
src.sanitize (c, this) &&
backdrop.sanitize (c, this));
}
HBUINT8 format; /* format = 20 */
Offset24To<Paint> src; /* Offset (from beginning of PaintComposite table) to source Paint subtable. */
CompositeMode mode; /* If mode is unrecognized use COMPOSITE_CLEAR */
Offset24To<Paint> backdrop; /* Offset (from beginning of PaintComposite table) to backdrop Paint subtable. */
public:
DEFINE_SIZE_STATIC (8);
};
struct Paint
{
template <typename context_t, typename ...Ts>
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
{
TRACE_DISPATCH (this, u.format);
if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
switch (u.format) {
case 1: return_trace (c->dispatch (u.paintformat1, hb_forward<Ts> (ds)...));
case 2: return_trace (c->dispatch (u.paintformat2, hb_forward<Ts> (ds)...));
case 3: return_trace (c->dispatch (u.paintformat3, hb_forward<Ts> (ds)...));
case 4: return_trace (c->dispatch (u.paintformat4, hb_forward<Ts> (ds)...));
case 5: return_trace (c->dispatch (u.paintformat5, hb_forward<Ts> (ds)...));
case 6: return_trace (c->dispatch (u.paintformat6, hb_forward<Ts> (ds)...));
case 7: return_trace (c->dispatch (u.paintformat7, hb_forward<Ts> (ds)...));
case 8: return_trace (c->dispatch (u.paintformat8, hb_forward<Ts> (ds)...));
case 9: return_trace (c->dispatch (u.paintformat9, hb_forward<Ts> (ds)...));
case 10: return_trace (c->dispatch (u.paintformat10, hb_forward<Ts> (ds)...));
case 11: return_trace (c->dispatch (u.paintformat11, hb_forward<Ts> (ds)...));
case 12: return_trace (c->dispatch (u.paintformat12, hb_forward<Ts> (ds)...));
case 13: return_trace (c->dispatch (u.paintformat13, hb_forward<Ts> (ds)...));
case 14: return_trace (c->dispatch (u.paintformat14, hb_forward<Ts> (ds)...));
case 15: return_trace (c->dispatch (u.paintformat15, hb_forward<Ts> (ds)...));
case 16: return_trace (c->dispatch (u.paintformat16, hb_forward<Ts> (ds)...));
case 17: return_trace (c->dispatch (u.paintformat17, hb_forward<Ts> (ds)...));
case 18: return_trace (c->dispatch (u.paintformat18, hb_forward<Ts> (ds)...));
case 19: return_trace (c->dispatch (u.paintformat19, hb_forward<Ts> (ds)...));
case 20: return_trace (c->dispatch (u.paintformat20, hb_forward<Ts> (ds)...));
default:return_trace (c->default_return_value ());
}
}
protected:
union {
HBUINT8 format;
PaintColrLayers paintformat1;
PaintSolid<NoVariable> paintformat2;
PaintSolid<Variable> paintformat3;
PaintLinearGradient<NoVariable> paintformat4;
PaintLinearGradient<Variable> paintformat5;
PaintRadialGradient<NoVariable> paintformat6;
PaintRadialGradient<Variable> paintformat7;
PaintSweepGradient<NoVariable> paintformat8;
PaintSweepGradient<Variable> paintformat9;
PaintGlyph paintformat10;
PaintColrGlyph paintformat11;
PaintTransform<NoVariable> paintformat12;
PaintTransform<Variable> paintformat13;
PaintTranslate<NoVariable> paintformat14;
PaintTranslate<Variable> paintformat15;
PaintRotate<NoVariable> paintformat16;
PaintRotate<Variable> paintformat17;
PaintSkew<NoVariable> paintformat18;
PaintSkew<Variable> paintformat19;
PaintComposite paintformat20;
} u;
};
struct BaseGlyphV1Record
{
int cmp (hb_codepoint_t g) const
{ return g < glyphId ? -1 : g > glyphId ? 1 : 0; }
bool serialize (hb_serialize_context_t *s, const hb_map_t* glyph_map,
const void* src_base, hb_subset_context_t *c) const
{
TRACE_SERIALIZE (this);
auto *out = s->embed (this);
if (unlikely (!out)) return_trace (false);
if (!s->check_assign (out->glyphId, glyph_map->get (glyphId),
HB_SERIALIZE_ERROR_INT_OVERFLOW))
return_trace (false);
return_trace (out->paint.serialize_subset (c, paint, src_base));
}
bool sanitize (hb_sanitize_context_t *c, const void *base) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) && paint.sanitize (c, base)));
}
public:
HBGlyphID glyphId; /* Glyph ID of reference glyph */
Offset32To<Paint> paint; /* Offset (from beginning of BaseGlyphV1Record array) to Paint,
* Typically PaintColrLayers */
public:
DEFINE_SIZE_STATIC (6);
};
struct BaseGlyphV1List : SortedArray32Of<BaseGlyphV1Record>
{
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
const hb_set_t* glyphset = c->plan->_glyphset;
for (const auto& _ : as_array ())
{
unsigned gid = _.glyphId;
if (!glyphset->has (gid)) continue;
if (_.serialize (c->serializer, c->plan->glyph_map, this, c)) out->len++;
else return_trace (false);
}
return_trace (out->len != 0);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (SortedArray32Of<BaseGlyphV1Record>::sanitize (c, this));
}
};
struct LayerV1List : Array32OfOffset32To<Paint>
{
const Paint& get_paint (unsigned i) const
{ return this+(*this)[i]; }
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
auto *out = c->serializer->start_embed (this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
for (const auto& _ : + hb_enumerate (*this)
| hb_filter (c->plan->colrv1_layers, hb_first))
{
auto *o = out->serialize_append (c->serializer);
if (unlikely (!o) || !o->serialize_subset (c, _.second, this))
return_trace (false);
}
return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (Array32OfOffset32To<Paint>::sanitize (c, this));
}
};
struct COLR
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
@ -131,6 +902,15 @@ struct COLR
hb_set_t *related_ids /* OUT */) const
{ colr->closure_glyphs (glyph, related_ids); }
void closure_V0palette_indices (const hb_set_t *glyphs,
hb_set_t *palettes /* OUT */) const
{ colr->closure_V0palette_indices (glyphs, palettes); }
void closure_forV1 (hb_set_t *glyphset,
hb_set_t *layer_indices,
hb_set_t *palette_indices) const
{ colr->closure_forV1 (glyphset, layer_indices, palette_indices); }
private:
hb_blob_ptr_t<COLR> colr;
};
@ -147,21 +927,70 @@ struct COLR
related_ids->add_array (&glyph_layers[0].glyphId, glyph_layers.length, LayerRecord::min_size);
}
void closure_V0palette_indices (const hb_set_t *glyphs,
hb_set_t *palettes /* OUT */) const
{
if (!numBaseGlyphs || !numLayers) return;
hb_array_t<const BaseGlyphRecord> baseGlyphs = (this+baseGlyphsZ).as_array (numBaseGlyphs);
hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers);
for (const BaseGlyphRecord record : baseGlyphs)
{
if (!glyphs->has (record.glyphId)) continue;
hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx,
record.numLayers);
for (const LayerRecord layer : glyph_layers)
palettes->add (layer.colorIdx);
}
}
void closure_forV1 (hb_set_t *glyphset,
hb_set_t *layer_indices,
hb_set_t *palette_indices) const
{
if (version != 1) return;
hb_set_t visited_glyphs;
hb_colrv1_closure_context_t c (this, &visited_glyphs, layer_indices, palette_indices);
const BaseGlyphV1List &baseglyphV1_records = this+baseGlyphsV1List;
for (const BaseGlyphV1Record &baseglyphV1record: baseglyphV1_records.iter ())
{
unsigned gid = baseglyphV1record.glyphId;
if (!glyphset->has (gid)) continue;
const Paint &paint = &baseglyphV1_records+baseglyphV1record.paint;
paint.dispatch (&c);
}
hb_set_union (glyphset, &visited_glyphs);
}
const LayerV1List& get_layerV1List () const
{ return (this+layersV1); }
const BaseGlyphV1List& get_baseglyphV1List () const
{ return (this+baseGlyphsV1List); }
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (likely (c->check_struct (this) &&
(this+baseGlyphsZ).sanitize (c, numBaseGlyphs) &&
(this+layersZ).sanitize (c, numLayers)));
return_trace (c->check_struct (this) &&
(this+baseGlyphsZ).sanitize (c, numBaseGlyphs) &&
(this+layersZ).sanitize (c, numLayers) &&
(version == 0 ||
(COLRV1_ENABLE_SUBSETTING && version == 1 &&
baseGlyphsV1List.sanitize (c, this) &&
layersV1.sanitize (c, this) &&
varStore.sanitize (c, this))));
}
template<typename BaseIterator, typename LayerIterator,
hb_requires (hb_is_iterator (BaseIterator)),
hb_requires (hb_is_iterator (LayerIterator))>
bool serialize (hb_serialize_context_t *c,
unsigned version,
BaseIterator base_it,
LayerIterator layer_it)
bool serialize_V0 (hb_serialize_context_t *c,
unsigned version,
BaseIterator base_it,
LayerIterator layer_it)
{
TRACE_SERIALIZE (this);
if (unlikely (base_it.len () != layer_it.len ()))
@ -171,6 +1000,12 @@ struct COLR
this->version = version;
numLayers = 0;
numBaseGlyphs = base_it.len ();
if (base_it.len () == 0)
{
baseGlyphsZ = 0;
layersZ = 0;
return_trace (true);
}
baseGlyphsZ = COLR::min_size;
layersZ = COLR::min_size + numBaseGlyphs * BaseGlyphRecord::min_size;
@ -198,6 +1033,14 @@ struct COLR
return record;
}
const BaseGlyphV1Record* get_base_glyphV1_record (hb_codepoint_t gid) const
{
const BaseGlyphV1Record* record = &(this+baseGlyphsV1List).bsearch ((unsigned) gid);
if ((record && (hb_codepoint_t) record->glyphId != gid))
record = nullptr;
return record;
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
@ -245,6 +1088,7 @@ struct COLR
if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid)))
return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
out_layers[i].glyphId = new_gid;
out_layers[i].colorIdx = c->plan->colr_palettes->get (layers[i].colorIdx);
}
return hb_pair_t<bool, hb_vector_t<LayerRecord>> (true, out_layers);
@ -253,23 +1097,45 @@ struct COLR
| hb_map_retains_sorting (hb_second)
;
if (unlikely (!base_it || !layer_it || base_it.len () != layer_it.len ()))
if (version == 0 && (!base_it || !layer_it))
return_trace (false);
COLR *colr_prime = c->serializer->start_embed<COLR> ();
return_trace (colr_prime->serialize (c->serializer, version, base_it, layer_it));
bool ret = colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it);
if (version == 0) return_trace (ret);
auto snap = c->serializer->snapshot ();
if (!c->serializer->allocate_size<void> (3 * HBUINT32::static_size)) return_trace (false);
if (!colr_prime->baseGlyphsV1List.serialize_subset (c, baseGlyphsV1List, this))
{
if (c->serializer->in_error ()) return_trace (false);
//no more COLRv1 glyphs: downgrade to version 0
c->serializer->revert (snap);
colr_prime->version = 0;
return_trace (true);
}
if (!colr_prime->layersV1.serialize_subset (c, layersV1, this)) return_trace (false);
colr_prime->varStore = 0;
//TODO: subset varStore once it's implemented in fonttools
return_trace (true);
}
protected:
HBUINT16 version; /* Table version number (starts at 0). */
HBUINT16 numBaseGlyphs; /* Number of Base Glyph Records. */
LNNOffsetTo<SortedUnsizedArrayOf<BaseGlyphRecord>>
NNOffset32To<SortedUnsizedArrayOf<BaseGlyphRecord>>
baseGlyphsZ; /* Offset to Base Glyph records. */
LNNOffsetTo<UnsizedArrayOf<LayerRecord>>
NNOffset32To<UnsizedArrayOf<LayerRecord>>
layersZ; /* Offset to Layer Records. */
HBUINT16 numLayers; /* Number of Layer Records. */
// Version-1 additions
Offset32To<BaseGlyphV1List> baseGlyphsV1List;
Offset32To<LayerV1List> layersV1;
Offset32To<VariationStore> varStore;
public:
DEFINE_SIZE_STATIC (14);
DEFINE_SIZE_MIN (14);
};
} /* namespace OT */

View File

@ -0,0 +1,101 @@
/*
* Copyright © 2018 Ebrahim Byagowi
* Copyright © 2020 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.
*
*/
#ifndef HB_OT_COLR_COLRV1_CLOSURE_HH
#define HB_OT_COLR_COLRV1_CLOSURE_HH
#include "hb-open-type.hh"
#include "hb-ot-layout-common.hh"
#include "hb-ot-color-colr-table.hh"
/*
* COLR -- Color
* https://docs.microsoft.com/en-us/typography/opentype/spec/colr
*/
namespace OT {
HB_INTERNAL void PaintColrLayers::closurev1 (hb_colrv1_closure_context_t* c) const
{
c->add_layer_indices (firstLayerIndex, numLayers);
const LayerV1List &paint_offset_lists = c->get_colr_table ()->get_layerV1List ();
for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++)
{
const Paint &paint = hb_addressof (paint_offset_lists) + paint_offset_lists[i];
paint.dispatch (c);
}
}
HB_INTERNAL void PaintGlyph::closurev1 (hb_colrv1_closure_context_t* c) const
{
c->add_glyph (gid);
(this+paint).dispatch (c);
}
HB_INTERNAL void PaintColrGlyph::closurev1 (hb_colrv1_closure_context_t* c) const
{
const COLR *colr_table = c->get_colr_table ();
const BaseGlyphV1Record* baseglyphV1_record = colr_table->get_base_glyphV1_record (gid);
if (!baseglyphV1_record) return;
c->add_glyph (gid);
const BaseGlyphV1List &baseglyphV1_list = colr_table->get_baseglyphV1List ();
(&baseglyphV1_list+baseglyphV1_record->paint).dispatch (c);
}
template <template<typename> class Var>
HB_INTERNAL void PaintTransform<Var>::closurev1 (hb_colrv1_closure_context_t* c) const
{
(this+src).dispatch (c);
}
template <template<typename> class Var>
HB_INTERNAL void PaintTranslate<Var>::closurev1 (hb_colrv1_closure_context_t* c) const
{
(this+src).dispatch (c);
}
template <template<typename> class Var>
HB_INTERNAL void PaintRotate<Var>::closurev1 (hb_colrv1_closure_context_t* c) const
{
(this+src).dispatch (c);
}
template <template<typename> class Var>
HB_INTERNAL void PaintSkew<Var>::closurev1 (hb_colrv1_closure_context_t* c) const
{
(this+src).dispatch (c);
}
HB_INTERNAL void PaintComposite::closurev1 (hb_colrv1_closure_context_t* c) const
{
(this+src).dispatch (c);
(this+backdrop).dispatch (c);
}
} /* namespace OT */
#endif /* HB_OT_COLR_COLRV1_CLOSURE_HH */

View File

@ -39,7 +39,6 @@
*/
#define HB_OT_TAG_CPAL HB_TAG('C','P','A','L')
namespace OT {
@ -74,6 +73,44 @@ struct CPALV1Tail
}
public:
bool serialize (hb_serialize_context_t *c,
unsigned palette_count,
unsigned color_count,
const void *base,
const hb_map_t *color_index_map) const
{
TRACE_SERIALIZE (this);
auto *out = c->allocate_size<CPALV1Tail> (static_size);
if (unlikely (!out)) return_trace (false);
out->paletteFlagsZ = 0;
if (paletteFlagsZ)
out->paletteFlagsZ.serialize_copy (c, paletteFlagsZ, base, 0, hb_serialize_context_t::Head, palette_count);
out->paletteLabelsZ = 0;
if (paletteLabelsZ)
out->paletteLabelsZ.serialize_copy (c, paletteLabelsZ, base, 0, hb_serialize_context_t::Head, palette_count);
const hb_array_t<const NameID> colorLabels = (base+colorLabelsZ).as_array (color_count);
if (colorLabelsZ)
{
c->push ();
for (const auto _ : colorLabels)
{
if (!color_index_map->has (_)) continue;
NameID new_color_idx;
new_color_idx = color_index_map->get (_);
if (!c->copy<NameID> (new_color_idx))
{
c->pop_discard ();
return_trace (false);
}
}
c->add_link (out->colorLabelsZ, c->pop_pack ());
}
return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c,
const void *base,
unsigned int palette_count,
@ -87,15 +124,17 @@ struct CPALV1Tail
}
protected:
LNNOffsetTo<UnsizedArrayOf<HBUINT32>>
// TODO(garretrieger): these offsets can hold nulls so we should not be using non-null offsets
// here. Currently they are needed since UnsizedArrayOf doesn't define null_size
NNOffset32To<UnsizedArrayOf<HBUINT32>>
paletteFlagsZ; /* Offset from the beginning of CPAL table to
* the Palette Type Array. Set to 0 if no array
* is provided. */
LNNOffsetTo<UnsizedArrayOf<NameID>>
NNOffset32To<UnsizedArrayOf<NameID>>
paletteLabelsZ; /* Offset from the beginning of CPAL table to
* the palette labels array. Set to 0 if no
* array is provided. */
LNNOffsetTo<UnsizedArrayOf<NameID>>
NNOffset32To<UnsizedArrayOf<NameID>>
colorLabelsZ; /* Offset from the beginning of CPAL table to
* the color labels array. Set to 0
* if no array is provided. */
@ -157,6 +196,84 @@ struct CPAL
}
public:
bool serialize (hb_serialize_context_t *c,
const hb_array_t<const BGRAColor> &color_records,
const hb_array_t<const HBUINT16> &color_record_indices,
const hb_map_t &color_record_index_map,
const hb_set_t &retained_color_record_indices) const
{
TRACE_SERIALIZE (this);
for (const auto idx : color_record_indices)
{
HBUINT16 new_idx;
if (idx == 0) new_idx = 0;
else new_idx = color_record_index_map.get (idx);
if (!c->copy<HBUINT16> (new_idx)) return_trace (false);
}
c->push ();
for (const auto _ : retained_color_record_indices.iter ())
{
if (!c->copy<BGRAColor> (color_records[_]))
{
c->pop_discard ();
return_trace (false);
}
}
c->add_link (colorRecordsZ, c->pop_pack ());
return_trace (true);
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
const hb_map_t *color_index_map = c->plan->colr_palettes;
if (color_index_map->is_empty ()) return_trace (false);
hb_set_t retained_color_indices;
for (const auto _ : color_index_map->keys ())
{
if (_ == 0xFFFF) continue;
retained_color_indices.add (_);
}
if (retained_color_indices.is_empty ()) return_trace (false);
auto *out = c->serializer->start_embed (*this);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
out->version = version;
out->numColors = retained_color_indices.get_population ();
out->numPalettes = numPalettes;
const hb_array_t<const HBUINT16> colorRecordIndices = colorRecordIndicesZ.as_array (numPalettes);
hb_map_t color_record_index_map;
hb_set_t retained_color_record_indices;
unsigned record_count = 0;
for (const auto first_color_record_idx : colorRecordIndices)
{
for (unsigned retained_color_idx : retained_color_indices.iter ())
{
unsigned color_record_idx = first_color_record_idx + retained_color_idx;
if (color_record_index_map.has (color_record_idx)) continue;
color_record_index_map.set (color_record_idx, record_count);
retained_color_record_indices.add (color_record_idx);
record_count++;
}
}
out->numColorRecords = record_count;
const hb_array_t<const BGRAColor> color_records = (this+colorRecordsZ).as_array (numColorRecords);
if (!out->serialize (c->serializer, color_records, colorRecordIndices, color_record_index_map, retained_color_record_indices))
return_trace (false);
if (version == 1)
return_trace (v1 ().serialize (c->serializer, numPalettes, numColors, this, color_index_map));
return_trace (true);
}
bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@ -173,7 +290,7 @@ struct CPAL
HBUINT16 numPalettes; /* Number of palettes in the table. */
HBUINT16 numColorRecords; /* Total number of color records, combined for
* all palettes. */
LNNOffsetTo<UnsizedArrayOf<BGRAColor>>
NNOffset32To<UnsizedArrayOf<BGRAColor>>
colorRecordsZ; /* Offset from the beginning of CPAL table to
* the first ColorRecord. */
UnsizedArrayOf<HBUINT16>

View File

@ -145,7 +145,7 @@ struct SBIXStrike
auto* out = c->serializer->start_embed<SBIXStrike> ();
if (unlikely (!out)) return_trace (false);
auto snap = c->serializer->snapshot ();
if (unlikely (!c->serializer->extend (*out, num_output_glyphs + 1))) return_trace (false);
if (unlikely (!c->serializer->extend (out, num_output_glyphs + 1))) return_trace (false);
out->ppem = ppem;
out->resolution = resolution;
HBUINT32 head;
@ -185,7 +185,7 @@ struct SBIXStrike
HBUINT16 resolution; /* The device pixel density (in PPI) for which this
* strike was designed. (E.g., 96 PPI, 192 PPI.) */
protected:
UnsizedArrayOf<LOffsetTo<SBIXGlyph>>
UnsizedArrayOf<Offset32To<SBIXGlyph>>
imageOffsetsZ; /* Offset from the beginning of the strike data header
* to bitmap data for an individual glyph ID. */
public:
@ -352,11 +352,11 @@ struct sbix
{
TRACE_SERIALIZE (this);
auto *out = c->serializer->start_embed<LOffsetLArrayOf<SBIXStrike>> ();
auto *out = c->serializer->start_embed<Array32OfOffset32To<SBIXStrike>> ();
if (unlikely (!out)) return_trace (false);
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
hb_vector_t<LOffsetTo<SBIXStrike>*> new_strikes;
hb_vector_t<Offset32To<SBIXStrike>*> new_strikes;
hb_vector_t<hb_serialize_context_t::objidx_t> objidxs;
for (int i = strikes.len - 1; i >= 0; --i)
{
@ -400,7 +400,7 @@ struct sbix
HBUINT16 version; /* Table version number — set to 1 */
HBUINT16 flags; /* Bit 0: Set to 1. Bit 1: Draw outlines.
* Bits 2 to 15: reserved (set to 0). */
LOffsetLArrayOf<SBIXStrike>
Array32OfOffset32To<SBIXStrike>
strikes; /* Offsets from the beginning of the 'sbix'
* table to data for each individual bitmap strike. */
public:

View File

@ -62,7 +62,7 @@ struct SVGDocumentIndexEntry
* this index entry. */
HBUINT16 endGlyphID; /* The last glyph ID in the range described by
* this index entry. Must be >= startGlyphID. */
LNNOffsetTo<UnsizedArrayOf<HBUINT8>>
NNOffset32To<UnsizedArrayOf<HBUINT8>>
svgDoc; /* Offset from the beginning of the SVG Document Index
* to an SVG document. Must be non-zero. */
HBUINT32 svgDocLength; /* Length of the SVG document.
@ -107,7 +107,7 @@ struct SVG
protected:
HBUINT16 version; /* Table version (starting at 0). */
LOffsetTo<SortedArrayOf<SVGDocumentIndexEntry>>
Offset32To<SortedArray16Of<SVGDocumentIndexEntry>>
svgDocEntries; /* Offset (relative to the start of the SVG table) to the
* SVG Documents Index. Must be non-zero. */
/* Array of SVG Document Index Entries. */

View File

@ -40,7 +40,7 @@
/* This lists font tables that the hb_face_t will contain and lazily
* load. Don't add a table unless it's used though. This is not
* exactly free. */
* exactly zero-cost. */
/* v--- Add new tables in the right place here. */

View File

@ -253,9 +253,7 @@ hb_ot_get_font_v_extents (hb_font_t *font,
_hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_LINE_GAP, &metrics->line_gap);
}
#if HB_USE_ATEXIT
static void free_static_ot_funcs ();
#endif
static inline void free_static_ot_funcs ();
static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot_font_funcs_lazy_loader_t>
{
@ -281,21 +279,17 @@ static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot
hb_font_funcs_make_immutable (funcs);
#if HB_USE_ATEXIT
atexit (free_static_ot_funcs);
#endif
hb_atexit (free_static_ot_funcs);
return funcs;
}
} static_ot_funcs;
#if HB_USE_ATEXIT
static
static inline
void free_static_ot_funcs ()
{
static_ot_funcs.free_instance ();
}
#endif
static hb_font_funcs_t *
_hb_ot_get_font_funcs ()

View File

@ -71,7 +71,7 @@ struct gasp
protected:
HBUINT16 version; /* Version number (set to 1) */
ArrayOf<GaspRange>
Array16Of<GaspRange>
gaspRanges; /* Number of records to follow
* Sorted by ppem */
public:

View File

@ -45,6 +45,10 @@ namespace OT {
*/
#define HB_OT_TAG_loca HB_TAG('l','o','c','a')
#ifndef HB_MAX_COMPOSITE_OPERATIONS
#define HB_MAX_COMPOSITE_OPERATIONS 100000
#endif
struct loca
{
@ -98,7 +102,7 @@ struct glyf
unsigned num_offsets = padded_offsets.len () + 1;
bool use_short_loca = max_offset < 0x1FFFF;
unsigned entry_size = use_short_loca ? 2 : 4;
char *loca_prime_data = (char *) calloc (entry_size, num_offsets);
char *loca_prime_data = (char *) hb_calloc (entry_size, num_offsets);
if (unlikely (!loca_prime_data)) return false;
@ -115,7 +119,7 @@ struct glyf
entry_size * num_offsets,
HB_MEMORY_MODE_WRITABLE,
loca_prime_data,
free);
hb_free);
bool result = plan->add_table (HB_OT_TAG_loca, loca_blob)
&& _add_head_and_set_loca_version (plan, use_short_loca);
@ -209,10 +213,15 @@ struct glyf
if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid))
return subset_glyph;
subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true);
if (plan->drop_hints) subset_glyph.drop_hints_bytes ();
else subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
if (new_gid == 0 &&
!(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
subset_glyph.source_glyph = Glyph ();
else
subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true);
if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
subset_glyph.drop_hints_bytes ();
else
subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
return subset_glyph;
})
| hb_sink (glyphs)
@ -281,6 +290,11 @@ struct glyf
hb_codepoint_t get_glyph_index () const { return glyphIndex; }
void drop_instructions_flag () { flags = (uint16_t) flags & ~WE_HAVE_INSTRUCTIONS; }
void set_overlaps_flag ()
{
flags = (uint16_t) flags | OVERLAP_COMPOUND;
}
bool has_instructions () const { return flags & WE_HAVE_INSTRUCTIONS; }
bool has_more () const { return flags & MORE_COMPONENTS; }
@ -383,9 +397,12 @@ struct glyf
{
typedef const CompositeGlyphChain *__item_t__;
composite_iter_t (hb_bytes_t glyph_, __item_t__ current_) :
glyph (glyph_), current (current_)
{ if (!check_range (current)) current = nullptr; }
composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr) {}
glyph (glyph_), current (nullptr), current_size (0)
{
set_next (current_);
}
composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr), current_size (0) {}
const CompositeGlyphChain &__item__ () const { return *current; }
bool __more__ () const { return current; }
@ -393,23 +410,36 @@ struct glyf
{
if (!current->has_more ()) { current = nullptr; return; }
const CompositeGlyphChain *possible = &StructAfter<CompositeGlyphChain,
CompositeGlyphChain> (*current);
if (!check_range (possible)) { current = nullptr; return; }
current = possible;
set_next (&StructAtOffset<CompositeGlyphChain> (current, current_size));
}
bool operator != (const composite_iter_t& o) const
{ return glyph != o.glyph || current != o.current; }
bool check_range (const CompositeGlyphChain *composite) const
void set_next (const CompositeGlyphChain *composite)
{
return glyph.check_range (composite, CompositeGlyphChain::min_size)
&& glyph.check_range (composite, composite->get_size ());
if (!glyph.check_range (composite, CompositeGlyphChain::min_size))
{
current = nullptr;
current_size = 0;
return;
}
unsigned size = composite->get_size ();
if (!glyph.check_range (composite, size))
{
current = nullptr;
current_size = 0;
return;
}
current = composite;
current_size = size;
}
private:
hb_bytes_t glyph;
__item_t__ current;
unsigned current_size;
};
enum phantom_point_index_t
@ -427,14 +457,14 @@ struct glyf
{
enum simple_glyph_flag_t
{
FLAG_ON_CURVE = 0x01,
FLAG_X_SHORT = 0x02,
FLAG_Y_SHORT = 0x04,
FLAG_REPEAT = 0x08,
FLAG_X_SAME = 0x10,
FLAG_Y_SAME = 0x20,
FLAG_RESERVED1 = 0x40,
FLAG_RESERVED2 = 0x80
FLAG_ON_CURVE = 0x01,
FLAG_X_SHORT = 0x02,
FLAG_Y_SHORT = 0x04,
FLAG_REPEAT = 0x08,
FLAG_X_SAME = 0x10,
FLAG_Y_SAME = 0x20,
FLAG_OVERLAP_SIMPLE = 0x40,
FLAG_RESERVED2 = 0x80
};
private:
@ -495,8 +525,8 @@ struct glyf
const Glyph trim_padding () const
{
/* based on FontTools _g_l_y_f.py::trim */
const char *glyph = bytes.arrayZ;
const char *glyph_end = glyph + bytes.length;
const uint8_t *glyph = (uint8_t*) bytes.arrayZ;
const uint8_t *glyph_end = glyph + bytes.length;
/* simple glyph w/contours, possibly trimmable */
glyph += instruction_len_offset ();
@ -553,6 +583,17 @@ struct glyf
dest_end = bytes.sub_array (glyph_length, bytes.length - glyph_length);
}
void set_overlaps_flag ()
{
if (unlikely (!header.numberOfContours)) return;
unsigned flags_offset = length (instructions_length ());
if (unlikely (length (flags_offset + 1) > bytes.length)) return;
HBUINT8 &first_flag = (HBUINT8 &) StructAtOffset<HBUINT16> (&bytes, flags_offset);
first_flag = (uint8_t) first_flag | FLAG_OVERLAP_SIMPLE;
}
static bool read_points (const HBUINT8 *&p /* IN/OUT */,
contour_point_vector_t &points_ /* IN/OUT */,
const hb_bytes_t &bytes,
@ -666,6 +707,12 @@ struct glyf
/* Chop instructions off the end */
void drop_hints_bytes (hb_bytes_t &dest_start) const
{ dest_start = bytes.sub_array (0, bytes.length - instructions_length (bytes)); }
void set_overlaps_flag ()
{
const_cast<CompositeGlyphChain &> (StructAfter<CompositeGlyphChain, GlyphHeader> (header))
.set_overlaps_flag ();
}
};
enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE };
@ -695,6 +742,15 @@ struct glyf
}
}
void set_overlaps_flag ()
{
switch (type) {
case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return;
case SIMPLE: SimpleGlyph (*header, bytes).set_overlaps_flag (); return;
default: return;
}
}
void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
{
switch (type) {
@ -886,7 +942,7 @@ struct glyf
{
if (gid >= num_glyphs) return false;
/* Making this alloc free is not that easy
/* Making this allocfree is not that easy
https://github.com/harfbuzz/harfbuzz/issues/2095
mostly because of gvar handling in VF fonts,
perhaps a separate path for non-VF fonts can be considered */
@ -1045,18 +1101,28 @@ struct glyf
return needs_padding_removal ? glyph.trim_padding () : glyph;
}
void
add_gid_and_children (hb_codepoint_t gid, hb_set_t *gids_to_retain,
unsigned int depth = 0) const
unsigned
add_gid_and_children (hb_codepoint_t gid,
hb_set_t *gids_to_retain,
unsigned depth = 0,
unsigned operation_count = 0) const
{
if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return;
if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return operation_count;
if (unlikely (operation_count++ > HB_MAX_COMPOSITE_OPERATIONS)) return operation_count;
/* Check if is already visited */
if (gids_to_retain->has (gid)) return;
if (gids_to_retain->has (gid)) return operation_count;
gids_to_retain->add (gid);
for (auto &item : glyph_for_gid (gid).get_composite_iterator ())
add_gid_and_children (item.get_glyph_index (), gids_to_retain, depth);
auto it = glyph_for_gid (gid).get_composite_iterator ();
while (it)
{
auto item = *(it++);
operation_count +=
add_gid_and_children (item.get_glyph_index (), gids_to_retain, depth, operation_count);
}
return operation_count;
}
#ifdef HB_EXPERIMENTAL_API
@ -1230,7 +1296,11 @@ struct glyf
const_cast<CompositeGlyphChain &> (_).set_glyph_index (new_gid);
}
if (plan->drop_hints) Glyph (dest_glyph).drop_hints ();
if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
Glyph (dest_glyph).drop_hints ();
if (plan->flags & HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG)
Glyph (dest_glyph).set_overlaps_flag ();
return_trace (true);
}

View File

@ -52,7 +52,7 @@ struct DeviceRecord
unsigned length = it.len ();
if (unlikely (!c->extend (*this, length))) return_trace (false);
if (unlikely (!c->extend (this, length))) return_trace (false);
this->pixelSize = pixelSize;
this->maxWidth =
@ -110,7 +110,7 @@ struct hdmx
for (const hb_item_type<Iterator>& _ : +it)
c->start_embed<DeviceRecord> ()->serialize (c, _.first, _.second);
return_trace (c->successful);
return_trace (c->successful ());
}

View File

@ -146,7 +146,7 @@ struct hmtxvmtx
_mtx.fini ();
if (unlikely (c->serializer->ran_out_of_room || c->serializer->in_error ()))
if (unlikely (c->serializer->in_error ()))
return_trace (false);
// Amend header num hmetrics

View File

@ -103,7 +103,7 @@ struct BaseCoordFormat3
protected:
HBUINT16 format; /* Format identifier--format = 3 */
FWORD coordinate; /* X or Y value, in design units */
OffsetTo<Device>
Offset16To<Device>
deviceTable; /* Offset to Device table for X or
* Y value, from beginning of
* BaseCoord table (may be NULL). */
@ -173,11 +173,11 @@ struct FeatMinMaxRecord
protected:
Tag tag; /* 4-byte feature identification tag--must
* match feature tag in FeatureList */
OffsetTo<BaseCoord>
Offset16To<BaseCoord>
minCoord; /* Offset to BaseCoord table that defines
* the minimum extent value, from beginning
* of MinMax table (may be NULL) */
OffsetTo<BaseCoord>
Offset16To<BaseCoord>
maxCoord; /* Offset to BaseCoord table that defines
* the maximum extent value, from beginning
* of MinMax table (may be NULL) */
@ -212,15 +212,15 @@ struct MinMax
}
protected:
OffsetTo<BaseCoord>
Offset16To<BaseCoord>
minCoord; /* Offset to BaseCoord table that defines
* minimum extent value, from the beginning
* of MinMax table (may be NULL) */
OffsetTo<BaseCoord>
Offset16To<BaseCoord>
maxCoord; /* Offset to BaseCoord table that defines
* maximum extent value, from the beginning
* of MinMax table (may be NULL) */
SortedArrayOf<FeatMinMaxRecord>
SortedArray16Of<FeatMinMaxRecord>
featMinMaxRecords;
/* Array of FeatMinMaxRecords, in alphabetical
* order by featureTableTag */
@ -247,7 +247,7 @@ struct BaseValues
Index defaultIndex; /* Index number of default baseline for this
* script equals index position of baseline tag
* in baselineTags array of the BaseTagList */
OffsetArrayOf<BaseCoord>
Array16OfOffset16To<BaseCoord>
baseCoords; /* Number of BaseCoord tables defined — should equal
* baseTagCount in the BaseTagList
*
@ -275,7 +275,7 @@ struct BaseLangSysRecord
protected:
Tag baseLangSysTag; /* 4-byte language system identification tag */
OffsetTo<MinMax>
Offset16To<MinMax>
minMax; /* Offset to MinMax table, from beginning
* of BaseScript table */
public:
@ -305,13 +305,13 @@ struct BaseScript
}
protected:
OffsetTo<BaseValues>
Offset16To<BaseValues>
baseValues; /* Offset to BaseValues table, from beginning
* of BaseScript table (may be NULL) */
OffsetTo<MinMax>
Offset16To<MinMax>
defaultMinMax; /* Offset to MinMax table, from beginning of
* BaseScript table (may be NULL) */
SortedArrayOf<BaseLangSysRecord>
SortedArray16Of<BaseLangSysRecord>
baseLangSysRecords;
/* Number of BaseLangSysRecords
* defined may be zero (0) */
@ -339,7 +339,7 @@ struct BaseScriptRecord
protected:
Tag baseScriptTag; /* 4-byte script identification tag */
OffsetTo<BaseScript>
Offset16To<BaseScript>
baseScript; /* Offset to BaseScript table, from beginning
* of BaseScriptList */
@ -364,7 +364,7 @@ struct BaseScriptList
}
protected:
SortedArrayOf<BaseScriptRecord>
SortedArray16Of<BaseScriptRecord>
baseScriptRecords;
public:
@ -426,12 +426,12 @@ struct Axis
}
protected:
OffsetTo<SortedArrayOf<Tag>>
Offset16To<SortedArray16Of<Tag>>
baseTagList; /* Offset to BaseTagList table, from beginning
* of Axis table (may be NULL)
* Array of 4-byte baseline identification tags must
* be in alphabetical order */
OffsetTo<BaseScriptList>
Offset16To<BaseScriptList>
baseScriptList; /* Offset to BaseScriptList table, from beginning
* of Axis table
* Array of BaseScriptRecords, in alphabetical order
@ -501,11 +501,11 @@ struct BASE
protected:
FixedVersion<>version; /* Version of the BASE table */
OffsetTo<Axis>hAxis; /* Offset to horizontal Axis table, from beginning
Offset16To<Axis>hAxis; /* Offset to horizontal Axis table, from beginning
* of BASE table (may be NULL) */
OffsetTo<Axis>vAxis; /* Offset to vertical Axis table, from beginning
Offset16To<Axis>vAxis; /* Offset to vertical Axis table, from beginning
* of BASE table (may be NULL) */
LOffsetTo<VariationStore>
Offset32To<VariationStore>
varStore; /* Offset to the table of Item Variation
* Store--from beginning of BASE
* header (may be NULL). Introduced

File diff suppressed because it is too large Load Diff

View File

@ -42,7 +42,7 @@ namespace OT {
*/
/* Array of contour point indices--in increasing numerical order */
struct AttachPoint : ArrayOf<HBUINT16>
struct AttachPoint : Array16Of<HBUINT16>
{
bool subset (hb_subset_context_t *c) const
{
@ -98,8 +98,7 @@ struct AttachList
| hb_map (glyph_map)
| hb_sink (new_coverage)
;
out->coverage.serialize (c->serializer, out)
.serialize (c->serializer, new_coverage.iter ());
out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
return_trace (bool (new_coverage));
}
@ -110,10 +109,10 @@ struct AttachList
}
protected:
OffsetTo<Coverage>
Offset16To<Coverage>
coverage; /* Offset to Coverage table -- from
* beginning of AttachList table */
OffsetArrayOf<AttachPoint>
Array16OfOffset16To<AttachPoint>
attachPoint; /* Array of AttachPoint tables
* in Coverage Index order */
public:
@ -220,7 +219,7 @@ struct CaretValueFormat3
protected:
HBUINT16 caretValueFormat; /* Format identifier--format = 3 */
FWORD coordinate; /* X or Y value, in design units */
OffsetTo<Device>
Offset16To<Device>
deviceTable; /* Offset to Device table for X or Y
* value--from beginning of CaretValue
* table */
@ -329,7 +328,7 @@ struct LigGlyph
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
{
for (const OffsetTo<CaretValue>& offset : carets.iter ())
for (const Offset16To<CaretValue>& offset : carets.iter ())
(this+offset).collect_variation_indices (c->layout_variation_indices);
}
@ -340,7 +339,7 @@ struct LigGlyph
}
protected:
OffsetArrayOf<CaretValue>
Array16OfOffset16To<CaretValue>
carets; /* Offset array of CaretValue tables
* --from beginning of LigGlyph table
* --in increasing coordinate order */
@ -386,8 +385,7 @@ struct LigCaretList
| hb_map (glyph_map)
| hb_sink (new_coverage)
;
out->coverage.serialize (c->serializer, out)
.serialize (c->serializer, new_coverage.iter ());
out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
return_trace (bool (new_coverage));
}
@ -408,10 +406,10 @@ struct LigCaretList
}
protected:
OffsetTo<Coverage>
Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of LigCaretList table */
OffsetArrayOf<LigGlyph>
Array16OfOffset16To<LigGlyph>
ligGlyph; /* Array of LigGlyph tables
* in Coverage Index order */
public:
@ -432,7 +430,7 @@ struct MarkGlyphSetsFormat1
out->format = format;
bool ret = true;
for (const LOffsetTo<Coverage>& offset : coverage.iter ())
for (const Offset32To<Coverage>& offset : coverage.iter ())
{
auto *o = out->coverage.serialize_append (c->serializer);
if (unlikely (!o))
@ -460,7 +458,7 @@ struct MarkGlyphSetsFormat1
protected:
HBUINT16 format; /* Format identifier--format = 1 */
ArrayOf<LOffsetTo<Coverage>>
Array16Of<Offset32To<Coverage>>
coverage; /* Array of long offsets to mark set
* coverage tables */
public:
@ -643,10 +641,10 @@ struct GDEF
auto *out = c->serializer->embed (*this);
if (unlikely (!out)) return_trace (false);
bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this);
bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this);
bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
bool subset_markglyphsetsdef = true;
if (version.to_int () >= 0x00010002u)
@ -687,28 +685,28 @@ struct GDEF
protected:
FixedVersion<>version; /* Version of the GDEF table--currently
* 0x00010003u */
OffsetTo<ClassDef>
Offset16To<ClassDef>
glyphClassDef; /* Offset to class definition table
* for glyph type--from beginning of
* GDEF header (may be Null) */
OffsetTo<AttachList>
Offset16To<AttachList>
attachList; /* Offset to list of glyphs with
* attachment points--from beginning
* of GDEF header (may be Null) */
OffsetTo<LigCaretList>
Offset16To<LigCaretList>
ligCaretList; /* Offset to list of positioning points
* for ligature carets--from beginning
* of GDEF header (may be Null) */
OffsetTo<ClassDef>
Offset16To<ClassDef>
markAttachClassDef; /* Offset to class definition table for
* mark attachment type--from beginning
* of GDEF header (may be Null) */
OffsetTo<MarkGlyphSets>
Offset16To<MarkGlyphSets>
markGlyphSetsDef; /* Offset to the table of mark set
* definitions--from beginning of GDEF
* header (may be NULL). Introduced
* in version 0x00010002. */
LOffsetTo<VariationStore>
Offset32To<VariationStore>
varStore; /* Offset to the table of Item Variation
* Store--from beginning of GDEF
* header (may be NULL). Introduced

File diff suppressed because it is too large Load Diff

View File

@ -46,14 +46,19 @@ struct SingleSubstFormat1
bool intersects (const hb_set_t *glyphs) const
{ return (this+coverage).intersects (glyphs); }
bool may_have_non_1to1 () const
{ return false; }
void closure (hb_closure_context_t *c) const
{
unsigned d = deltaGlyphID;
+ hb_iter (this+coverage)
| hb_filter (*c->glyphs)
| hb_filter (c->parent_active_glyphs ())
| hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
| hb_sink (c->output)
;
}
void closure_lookups (hb_closure_lookups_context_t *c) const {}
@ -95,9 +100,9 @@ struct SingleSubstFormat1
unsigned delta)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (*this))) return_trace (false);
if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false);
c->check_assign (deltaGlyphID, delta);
if (unlikely (!c->extend_min (this))) return_trace (false);
if (unlikely (!coverage.serialize_serialize (c, glyphs))) return_trace (false);
c->check_assign (deltaGlyphID, delta, HB_SERIALIZE_ERROR_INT_OVERFLOW);
return_trace (true);
}
@ -133,7 +138,7 @@ struct SingleSubstFormat1
protected:
HBUINT16 format; /* Format identifier--format = 1 */
OffsetTo<Coverage>
Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of Substitution table */
HBUINT16 deltaGlyphID; /* Add to original GlyphID to get
@ -147,13 +152,17 @@ struct SingleSubstFormat2
bool intersects (const hb_set_t *glyphs) const
{ return (this+coverage).intersects (glyphs); }
bool may_have_non_1to1 () const
{ return false; }
void closure (hb_closure_context_t *c) const
{
+ hb_zip (this+coverage, substitute)
| hb_filter (*c->glyphs, hb_first)
| hb_filter (c->parent_active_glyphs (), hb_first)
| hb_map (hb_second)
| hb_sink (c->output)
;
}
void closure_lookups (hb_closure_lookups_context_t *c) const {}
@ -200,9 +209,9 @@ struct SingleSubstFormat2
+ it
| hb_map_retains_sorting (hb_first)
;
if (unlikely (!c->extend_min (*this))) return_trace (false);
if (unlikely (!c->extend_min (this))) return_trace (false);
if (unlikely (!substitute.serialize (c, substitutes))) return_trace (false);
if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false);
if (unlikely (!coverage.serialize_serialize (c, glyphs))) return_trace (false);
return_trace (true);
}
@ -233,10 +242,10 @@ struct SingleSubstFormat2
protected:
HBUINT16 format; /* Format identifier--format = 2 */
OffsetTo<Coverage>
Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of Substitution table */
ArrayOf<HBGlyphID>
Array16Of<HBGlyphID>
substitute; /* Array of substitute
* GlyphIDs--ordered by Coverage Index */
public:
@ -334,9 +343,14 @@ struct Sequence
unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
unsigned lig_id = _hb_glyph_info_get_lig_id (&c->buffer->cur());
for (unsigned int i = 0; i < count; i++) {
_hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
for (unsigned int i = 0; i < count; i++)
{
/* If is attached to a ligature, don't disturb that.
* https://github.com/harfbuzz/harfbuzz/issues/3069 */
if (!lig_id)
_hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
c->output_glyph_for_component (substitute.arrayZ[i], klass);
}
c->buffer->skip_glyph ();
@ -377,7 +391,7 @@ struct Sequence
}
protected:
ArrayOf<HBGlyphID>
Array16Of<HBGlyphID>
substitute; /* String of GlyphIDs to substitute */
public:
DEFINE_SIZE_ARRAY (2, substitute);
@ -388,10 +402,13 @@ struct MultipleSubstFormat1
bool intersects (const hb_set_t *glyphs) const
{ return (this+coverage).intersects (glyphs); }
bool may_have_non_1to1 () const
{ return true; }
void closure (hb_closure_context_t *c) const
{
+ hb_zip (this+coverage, sequence)
| hb_filter (*c->glyphs, hb_first)
| hb_filter (c->parent_active_glyphs (), hb_first)
| hb_map (hb_second)
| hb_map (hb_add (this))
| hb_apply ([c] (const Sequence &_) { _.closure (c); })
@ -431,17 +448,17 @@ struct MultipleSubstFormat1
hb_array_t<const HBGlyphID> substitute_glyphs_list)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (*this))) return_trace (false);
if (unlikely (!c->extend_min (this))) return_trace (false);
if (unlikely (!sequence.serialize (c, glyphs.length))) return_trace (false);
for (unsigned int i = 0; i < glyphs.length; i++)
{
unsigned int substitute_len = substitute_len_list[i];
if (unlikely (!sequence[i].serialize (c, this)
.serialize (c, substitute_glyphs_list.sub_array (0, substitute_len))))
if (unlikely (!sequence[i]
.serialize_serialize (c, substitute_glyphs_list.sub_array (0, substitute_len))))
return_trace (false);
substitute_glyphs_list += substitute_len;
}
return_trace (coverage.serialize (c, this).serialize (c, glyphs));
return_trace (coverage.serialize_serialize (c, glyphs));
}
bool subset (hb_subset_context_t *c) const
@ -462,8 +479,7 @@ struct MultipleSubstFormat1
| hb_map (glyph_map)
| hb_sink (new_coverage)
;
out->coverage.serialize (c->serializer, out)
.serialize (c->serializer, new_coverage.iter ());
out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
return_trace (bool (new_coverage));
}
@ -475,10 +491,10 @@ struct MultipleSubstFormat1
protected:
HBUINT16 format; /* Format identifier--format = 1 */
OffsetTo<Coverage>
Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of Substitution table */
OffsetArrayOf<Sequence>
Array16OfOffset16To<Sequence>
sequence; /* Array of Sequence tables
* ordered by Coverage Index */
public:
@ -547,7 +563,12 @@ struct AlternateSet
/* If alt_index is MAX_VALUE, randomize feature if it is the rand feature. */
if (alt_index == HB_OT_MAP_MAX_VALUE && c->random)
{
/* Maybe we can do better than unsafe-to-break all; but since we are
* changing random state, it would be hard to track that. Good 'nough. */
c->buffer->unsafe_to_break_all ();
alt_index = c->random_number () % count + 1;
}
if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
@ -603,7 +624,7 @@ struct AlternateSet
}
protected:
ArrayOf<HBGlyphID>
Array16Of<HBGlyphID>
alternates; /* Array of alternate GlyphIDs--in
* arbitrary order */
public:
@ -615,14 +636,18 @@ struct AlternateSubstFormat1
bool intersects (const hb_set_t *glyphs) const
{ return (this+coverage).intersects (glyphs); }
bool may_have_non_1to1 () const
{ return false; }
void closure (hb_closure_context_t *c) const
{
+ hb_zip (this+coverage, alternateSet)
| hb_filter (c->glyphs, hb_first)
| hb_filter (c->parent_active_glyphs (), hb_first)
| hb_map (hb_second)
| hb_map (hb_add (this))
| hb_apply ([c] (const AlternateSet &_) { _.closure (c); })
;
}
void closure_lookups (hb_closure_lookups_context_t *c) const {}
@ -666,17 +691,17 @@ struct AlternateSubstFormat1
hb_array_t<const HBGlyphID> alternate_glyphs_list)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (*this))) return_trace (false);
if (unlikely (!c->extend_min (this))) return_trace (false);
if (unlikely (!alternateSet.serialize (c, glyphs.length))) return_trace (false);
for (unsigned int i = 0; i < glyphs.length; i++)
{
unsigned int alternate_len = alternate_len_list[i];
if (unlikely (!alternateSet[i].serialize (c, this)
.serialize (c, alternate_glyphs_list.sub_array (0, alternate_len))))
if (unlikely (!alternateSet[i]
.serialize_serialize (c, alternate_glyphs_list.sub_array (0, alternate_len))))
return_trace (false);
alternate_glyphs_list += alternate_len;
}
return_trace (coverage.serialize (c, this).serialize (c, glyphs));
return_trace (coverage.serialize_serialize (c, glyphs));
}
bool subset (hb_subset_context_t *c) const
@ -697,8 +722,7 @@ struct AlternateSubstFormat1
| hb_map (glyph_map)
| hb_sink (new_coverage)
;
out->coverage.serialize (c->serializer, out)
.serialize (c->serializer, new_coverage.iter ());
out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
return_trace (bool (new_coverage));
}
@ -710,10 +734,10 @@ struct AlternateSubstFormat1
protected:
HBUINT16 format; /* Format identifier--format = 1 */
OffsetTo<Coverage>
Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of Substitution table */
OffsetArrayOf<AlternateSet>
Array16OfOffset16To<AlternateSet>
alternateSet; /* Array of AlternateSet tables
* ordered by Coverage Index */
public:
@ -831,7 +855,7 @@ struct Ligature
Iterator components /* Starting from second */)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (*this))) return_trace (false);
if (unlikely (!c->extend_min (this))) return_trace (false);
ligGlyph = ligature;
if (unlikely (!component.serialize (c, components))) return_trace (false);
return_trace (true);
@ -930,15 +954,14 @@ struct LigatureSet
hb_array_t<const HBGlyphID> &component_list /* Starting from second for each ligature */)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (*this))) return_trace (false);
if (unlikely (!c->extend_min (this))) return_trace (false);
if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false);
for (unsigned int i = 0; i < ligatures.length; i++)
{
unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0);
if (unlikely (!ligature[i].serialize (c, this)
.serialize (c,
ligatures[i],
component_list.sub_array (0, component_count))))
if (unlikely (!ligature[i].serialize_serialize (c,
ligatures[i],
component_list.sub_array (0, component_count))))
return_trace (false);
component_list += component_count;
}
@ -965,7 +988,7 @@ struct LigatureSet
}
protected:
OffsetArrayOf<Ligature>
Array16OfOffset16To<Ligature>
ligature; /* Array LigatureSet tables
* ordered by preference */
public:
@ -980,20 +1003,24 @@ struct LigatureSubstFormat1
+ hb_zip (this+coverage, ligatureSet)
| hb_filter (*glyphs, hb_first)
| hb_map (hb_second)
| hb_map ([this, glyphs] (const OffsetTo<LigatureSet> &_)
| hb_map ([this, glyphs] (const Offset16To<LigatureSet> &_)
{ return (this+_).intersects (glyphs); })
| hb_any
;
}
bool may_have_non_1to1 () const
{ return true; }
void closure (hb_closure_context_t *c) const
{
+ hb_zip (this+coverage, ligatureSet)
| hb_filter (*c->glyphs, hb_first)
| hb_filter (c->parent_active_glyphs (), hb_first)
| hb_map (hb_second)
| hb_map (hb_add (this))
| hb_apply ([c] (const LigatureSet &_) { _.closure (c); })
;
}
void closure_lookups (hb_closure_lookups_context_t *c) const {}
@ -1039,20 +1066,20 @@ struct LigatureSubstFormat1
hb_array_t<const HBGlyphID> component_list /* Starting from second for each ligature */)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (*this))) return_trace (false);
if (unlikely (!c->extend_min (this))) return_trace (false);
if (unlikely (!ligatureSet.serialize (c, first_glyphs.length))) return_trace (false);
for (unsigned int i = 0; i < first_glyphs.length; i++)
{
unsigned int ligature_count = ligature_per_first_glyph_count_list[i];
if (unlikely (!ligatureSet[i].serialize (c, this)
.serialize (c,
ligatures_list.sub_array (0, ligature_count),
component_count_list.sub_array (0, ligature_count),
component_list))) return_trace (false);
if (unlikely (!ligatureSet[i]
.serialize_serialize (c,
ligatures_list.sub_array (0, ligature_count),
component_count_list.sub_array (0, ligature_count),
component_list))) return_trace (false);
ligatures_list += ligature_count;
component_count_list += ligature_count;
}
return_trace (coverage.serialize (c, this).serialize (c, first_glyphs));
return_trace (coverage.serialize_serialize (c, first_glyphs));
}
bool subset (hb_subset_context_t *c) const
@ -1073,8 +1100,7 @@ struct LigatureSubstFormat1
| hb_map (glyph_map)
| hb_sink (new_coverage)
;
out->coverage.serialize (c->serializer, out)
.serialize (c->serializer, new_coverage.iter ());
out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
return_trace (bool (new_coverage));
}
@ -1086,10 +1112,10 @@ struct LigatureSubstFormat1
protected:
HBUINT16 format; /* Format identifier--format = 1 */
OffsetTo<Coverage>
Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of Substitution table */
OffsetArrayOf<LigatureSet>
Array16OfOffset16To<LigatureSet>
ligatureSet; /* Array LigatureSet tables
* ordered by Coverage Index */
public:
@ -1157,7 +1183,7 @@ struct ReverseChainSingleSubstFormat1
if (!(this+coverage).intersects (glyphs))
return false;
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
unsigned int count;
@ -1174,15 +1200,18 @@ struct ReverseChainSingleSubstFormat1
return true;
}
bool may_have_non_1to1 () const
{ return false; }
void closure (hb_closure_context_t *c) const
{
if (!intersects (c->glyphs)) return;
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
const ArrayOf<HBGlyphID> &substitute = StructAfter<ArrayOf<HBGlyphID>> (lookahead);
const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
const Array16Of<HBGlyphID> &substitute = StructAfter<Array16Of<HBGlyphID>> (lookahead);
+ hb_zip (this+coverage, substitute)
| hb_filter (*c->glyphs, hb_first)
| hb_filter (c->parent_active_glyphs (), hb_first)
| hb_map (hb_second)
| hb_sink (c->output)
;
@ -1200,12 +1229,12 @@ struct ReverseChainSingleSubstFormat1
for (unsigned int i = 0; i < count; i++)
if (unlikely (!(this+backtrack[i]).collect_coverage (c->before))) return;
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
count = lookahead.len;
for (unsigned int i = 0; i < count; i++)
if (unlikely (!(this+lookahead[i]).collect_coverage (c->after))) return;
const ArrayOf<HBGlyphID> &substitute = StructAfter<ArrayOf<HBGlyphID>> (lookahead);
const Array16Of<HBGlyphID> &substitute = StructAfter<Array16Of<HBGlyphID>> (lookahead);
count = substitute.len;
c->output->add_array (substitute.arrayZ, substitute.len);
}
@ -1224,8 +1253,8 @@ struct ReverseChainSingleSubstFormat1
unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
if (likely (index == NOT_COVERED)) return_trace (false);
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
const ArrayOf<HBGlyphID> &substitute = StructAfter<ArrayOf<HBGlyphID>> (lookahead);
const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
const Array16Of<HBGlyphID> &substitute = StructAfter<Array16Of<HBGlyphID>> (lookahead);
if (unlikely (index >= substitute.len)) return_trace (false);
@ -1250,11 +1279,80 @@ struct ReverseChainSingleSubstFormat1
return_trace (false);
}
template<typename Iterator,
hb_requires (hb_is_iterator (Iterator))>
bool serialize_coverage_offset_array (hb_subset_context_t *c, Iterator it) const
{
TRACE_SERIALIZE (this);
auto *out = c->serializer->start_embed<Array16OfOffset16To<Coverage>> ();
if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size)))
return_trace (false);
for (auto& offset : it) {
auto *o = out->serialize_append (c->serializer);
if (unlikely (!o) || !o->serialize_subset (c, offset, this))
return_trace (false);
}
return_trace (true);
}
template<typename Iterator, typename BacktrackIterator, typename LookaheadIterator,
hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_pair_t)),
hb_requires (hb_is_iterator (BacktrackIterator)),
hb_requires (hb_is_iterator (LookaheadIterator))>
bool serialize (hb_subset_context_t *c,
Iterator coverage_subst_iter,
BacktrackIterator backtrack_iter,
LookaheadIterator lookahead_iter) const
{
TRACE_SERIALIZE (this);
auto *out = c->serializer->start_embed (this);
if (unlikely (!c->serializer->check_success (out))) return_trace (false);
if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
if (unlikely (!c->serializer->embed (this->coverage))) return_trace (false);
if (!serialize_coverage_offset_array (c, backtrack_iter)) return_trace (false);
if (!serialize_coverage_offset_array (c, lookahead_iter)) return_trace (false);
auto *substitute_out = c->serializer->start_embed<Array16Of<HBGlyphID>> ();
auto substitutes =
+ coverage_subst_iter
| hb_map (hb_second)
;
auto glyphs =
+ coverage_subst_iter
| hb_map_retains_sorting (hb_first)
;
if (unlikely (! c->serializer->check_success (substitute_out->serialize (c->serializer, substitutes))))
return_trace (false);
if (unlikely (!out->coverage.serialize_serialize (c->serializer, glyphs)))
return_trace (false);
return_trace (true);
}
bool subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
// TODO(subset)
return_trace (false);
const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
const hb_map_t &glyph_map = *c->plan->glyph_map;
const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
const Array16Of<HBGlyphID> &substitute = StructAfter<Array16Of<HBGlyphID>> (lookahead);
auto it =
+ hb_zip (this+coverage, substitute)
| hb_filter (glyphset, hb_first)
| hb_filter (glyphset, hb_second)
| hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const HBGlyphID &> p) -> hb_codepoint_pair_t
{ return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
;
return_trace (bool (it) && serialize (c, it, backtrack.iter (), lookahead.iter ()));
}
bool sanitize (hb_sanitize_context_t *c) const
@ -1262,27 +1360,27 @@ struct ReverseChainSingleSubstFormat1
TRACE_SANITIZE (this);
if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
return_trace (false);
const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
if (!lookahead.sanitize (c, this))
return_trace (false);
const ArrayOf<HBGlyphID> &substitute = StructAfter<ArrayOf<HBGlyphID>> (lookahead);
const Array16Of<HBGlyphID> &substitute = StructAfter<Array16Of<HBGlyphID>> (lookahead);
return_trace (substitute.sanitize (c));
}
protected:
HBUINT16 format; /* Format identifier--format = 1 */
OffsetTo<Coverage>
Offset16To<Coverage>
coverage; /* Offset to Coverage table--from
* beginning of table */
OffsetArrayOf<Coverage>
Array16OfOffset16To<Coverage>
backtrack; /* Array of coverage tables
* in backtracking sequence, in glyph
* sequence order */
OffsetArrayOf<Coverage>
Array16OfOffset16To<Coverage>
lookaheadX; /* Array of coverage tables
* in lookahead sequence, in glyph
* sequence order */
ArrayOf<HBGlyphID>
Array16Of<HBGlyphID>
substituteX; /* Array of substitute
* GlyphIDs--ordered by Coverage Index */
public:
@ -1388,6 +1486,12 @@ struct SubstLookup : Lookup
return lookup_type_is_reverse (type);
}
bool may_have_non_1to1 () const
{
hb_have_non_1to1_context_t c;
return dispatch (&c);
}
bool apply (hb_ot_apply_context_t *c) const
{
TRACE_APPLY (this);
@ -1455,10 +1559,6 @@ struct SubstLookup : Lookup
static inline bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
SubTable& serialize_subtable (hb_serialize_context_t *c,
unsigned int i)
{ return get_subtables<SubTable> ()[i].serialize (c, this); }
bool serialize_single (hb_serialize_context_t *c,
uint32_t lookup_props,
hb_sorted_array_t<const HBGlyphID> glyphs,
@ -1466,8 +1566,13 @@ struct SubstLookup : Lookup
{
TRACE_SERIALIZE (this);
if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
return_trace (serialize_subtable (c, 0).u.single.
serialize (c, hb_zip (glyphs, substitutes)));
if (c->push<SubTable> ()->u.single.serialize (c, hb_zip (glyphs, substitutes)))
{
c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
return_trace (true);
}
c->pop_discard ();
return_trace (false);
}
bool serialize_multiple (hb_serialize_context_t *c,
@ -1478,11 +1583,17 @@ struct SubstLookup : Lookup
{
TRACE_SERIALIZE (this);
if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
return_trace (serialize_subtable (c, 0).u.multiple.
serialize (c,
glyphs,
substitute_len_list,
substitute_glyphs_list));
if (c->push<SubTable> ()->u.multiple.
serialize (c,
glyphs,
substitute_len_list,
substitute_glyphs_list))
{
c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
return_trace (true);
}
c->pop_discard ();
return_trace (false);
}
bool serialize_alternate (hb_serialize_context_t *c,
@ -1493,11 +1604,18 @@ struct SubstLookup : Lookup
{
TRACE_SERIALIZE (this);
if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
return_trace (serialize_subtable (c, 0).u.alternate.
serialize (c,
glyphs,
alternate_len_list,
alternate_glyphs_list));
if (c->push<SubTable> ()->u.alternate.
serialize (c,
glyphs,
alternate_len_list,
alternate_glyphs_list))
{
c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
return_trace (true);
}
c->pop_discard ();
return_trace (false);
}
bool serialize_ligature (hb_serialize_context_t *c,
@ -1510,24 +1628,32 @@ struct SubstLookup : Lookup
{
TRACE_SERIALIZE (this);
if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
return_trace (serialize_subtable (c, 0).u.ligature.
serialize (c,
first_glyphs,
ligature_per_first_glyph_count_list,
ligatures_list,
component_count_list,
component_list));
if (c->push<SubTable> ()->u.ligature.
serialize (c,
first_glyphs,
ligature_per_first_glyph_count_list,
ligatures_list,
component_count_list,
component_list))
{
c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
return_trace (true);
}
c->pop_discard ();
return_trace (false);
}
template <typename context_t>
static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
static inline typename hb_closure_context_t::return_t closure_glyphs_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index);
static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index)
{
if (!c->should_visit_lookup (lookup_index))
return hb_empty_t ();
hb_closure_context_t::return_t ret = dispatch_recurse_func (c, lookup_index);
hb_closure_context_t::return_t ret = closure_glyphs_recurse_func (c, lookup_index, covered_seq_indices, seq_index, end_index);
/* While in theory we should flush here, it will cause timeouts because a recursive
* lookup can keep growing the glyph set. Skip, and outer loop will retry up to
@ -1564,7 +1690,7 @@ struct GSUB : GSUBGPOS
bool subset (hb_subset_context_t *c) const
{
hb_subset_layout_context_t l (c, tableTag, c->plan->gsub_lookups, c->plan->gsub_features);
hb_subset_layout_context_t l (c, tableTag, c->plan->gsub_lookups, c->plan->gsub_langsys, c->plan->gsub_features);
return GSUBGPOS::subset<SubstLookup> (&l);
}
@ -1600,6 +1726,14 @@ template <typename context_t>
return l.dispatch (c);
}
/*static*/ typename hb_closure_context_t::return_t SubstLookup::closure_glyphs_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index)
{
const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
if (l.may_have_non_1to1 ())
hb_set_add_range (covered_seq_indices, seq_index, end_index);
return l.dispatch (c);
}
/*static*/ inline hb_closure_lookups_context_t::return_t SubstLookup::dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned this_index)
{
const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (this_index);

File diff suppressed because it is too large Load Diff

View File

@ -45,7 +45,7 @@ typedef IndexArray JstfModList;
* JstfMax -- Justification Maximum Table
*/
typedef OffsetListOf<PosLookup> JstfMax;
typedef List16OfOffset16To<PosLookup> JstfMax;
/*
@ -71,43 +71,43 @@ struct JstfPriority
}
protected:
OffsetTo<JstfModList>
Offset16To<JstfModList>
shrinkageEnableGSUB; /* Offset to Shrinkage Enable GSUB
* JstfModList table--from beginning of
* JstfPriority table--may be NULL */
OffsetTo<JstfModList>
Offset16To<JstfModList>
shrinkageDisableGSUB; /* Offset to Shrinkage Disable GSUB
* JstfModList table--from beginning of
* JstfPriority table--may be NULL */
OffsetTo<JstfModList>
Offset16To<JstfModList>
shrinkageEnableGPOS; /* Offset to Shrinkage Enable GPOS
* JstfModList table--from beginning of
* JstfPriority table--may be NULL */
OffsetTo<JstfModList>
Offset16To<JstfModList>
shrinkageDisableGPOS; /* Offset to Shrinkage Disable GPOS
* JstfModList table--from beginning of
* JstfPriority table--may be NULL */
OffsetTo<JstfMax>
Offset16To<JstfMax>
shrinkageJstfMax; /* Offset to Shrinkage JstfMax table--
* from beginning of JstfPriority table
* --may be NULL */
OffsetTo<JstfModList>
Offset16To<JstfModList>
extensionEnableGSUB; /* Offset to Extension Enable GSUB
* JstfModList table--from beginning of
* JstfPriority table--may be NULL */
OffsetTo<JstfModList>
Offset16To<JstfModList>
extensionDisableGSUB; /* Offset to Extension Disable GSUB
* JstfModList table--from beginning of
* JstfPriority table--may be NULL */
OffsetTo<JstfModList>
Offset16To<JstfModList>
extensionEnableGPOS; /* Offset to Extension Enable GPOS
* JstfModList table--from beginning of
* JstfPriority table--may be NULL */
OffsetTo<JstfModList>
Offset16To<JstfModList>
extensionDisableGPOS; /* Offset to Extension Disable GPOS
* JstfModList table--from beginning of
* JstfPriority table--may be NULL */
OffsetTo<JstfMax>
Offset16To<JstfMax>
extensionJstfMax; /* Offset to Extension JstfMax table--
* from beginning of JstfPriority table
* --may be NULL */
@ -121,13 +121,13 @@ struct JstfPriority
* JstfLangSys -- Justification Language System Table
*/
struct JstfLangSys : OffsetListOf<JstfPriority>
struct JstfLangSys : List16OfOffset16To<JstfPriority>
{
bool sanitize (hb_sanitize_context_t *c,
const Record_sanitize_closure_t * = nullptr) const
{
TRACE_SANITIZE (this);
return_trace (OffsetListOf<JstfPriority>::sanitize (c));
return_trace (List16OfOffset16To<JstfPriority>::sanitize (c));
}
};
@ -136,7 +136,7 @@ struct JstfLangSys : OffsetListOf<JstfPriority>
* ExtenderGlyphs -- Extender Glyph Table
*/
typedef SortedArrayOf<HBGlyphID> ExtenderGlyphs;
typedef SortedArray16Of<HBGlyphID> ExtenderGlyphs;
/*
@ -174,10 +174,10 @@ struct JstfScript
}
protected:
OffsetTo<ExtenderGlyphs>
Offset16To<ExtenderGlyphs>
extenderGlyphs; /* Offset to ExtenderGlyph table--from beginning
* of JstfScript table-may be NULL */
OffsetTo<JstfLangSys>
Offset16To<JstfLangSys>
defaultLangSys; /* Offset to DefaultJstfLangSys table--from
* beginning of JstfScript table--may be Null */
RecordArrayOf<JstfLangSys>

View File

@ -131,7 +131,9 @@ hb_ot_layout_kern (const hb_ot_shape_plan_t *plan,
AAT::hb_aat_apply_context_t c (plan, font, buffer, blob);
if (!buffer->message (font, "start table kern")) return;
kern.apply (&c);
(void) buffer->message (font, "end table kern");
}
#endif
@ -144,7 +146,7 @@ bool
OT::GDEF::is_blocklisted (hb_blob_t *blob,
hb_face_t *face) const
{
#ifdef HB_NO_OT_LAYOUT_BLACKLIST
#ifdef HB_NO_OT_LAYOUT_BLOCKLIST
return false;
#endif
/* The ugly business of blocklisting individual fonts' tables happen here!
@ -331,6 +333,8 @@ hb_ot_layout_get_glyphs_in_class (hb_face_t *face,
*
* Useful if the client program wishes to cache the list.
*
* Return value: Total number of attachment points for @glyph.
*
**/
unsigned int
hb_ot_layout_get_attach_points (hb_face_t *face,
@ -357,6 +361,8 @@ hb_ot_layout_get_attach_points (hb_face_t *face,
* Fetches a list of the caret positions defined for a ligature glyph in the GDEF
* table of the font. The list returned will begin at the offset provided.
*
* Return value: Total number of ligature caret positions for @glyph.
*
**/
unsigned int
hb_ot_layout_get_ligature_carets (hb_font_t *font,
@ -379,7 +385,7 @@ bool
OT::GSUB::is_blocklisted (hb_blob_t *blob HB_UNUSED,
hb_face_t *face) const
{
#ifdef HB_NO_OT_LAYOUT_BLACKLIST
#ifdef HB_NO_OT_LAYOUT_BLOCKLIST
return false;
#endif
return false;
@ -389,7 +395,7 @@ bool
OT::GPOS::is_blocklisted (hb_blob_t *blob HB_UNUSED,
hb_face_t *face HB_UNUSED) const
{
#ifdef HB_NO_OT_LAYOUT_BLACKLIST
#ifdef HB_NO_OT_LAYOUT_BLOCKLIST
return false;
#endif
return false;
@ -419,6 +425,8 @@ get_gsubgpos_table (hb_face_t *face,
* Fetches a list of all scripts enumerated in the specified face's GSUB table
* or GPOS table. The list returned will begin at the offset provided.
*
* Return value: Total number of script tags.
*
**/
unsigned int
hb_ot_layout_table_get_script_tags (hb_face_t *face,
@ -585,6 +593,8 @@ hb_ot_layout_table_select_script (hb_face_t *face,
*
* Fetches a list of all feature tags in the given face's GSUB or GPOS table.
*
* Return value: Total number of feature tags.
*
**/
unsigned int
hb_ot_layout_table_get_feature_tags (hb_face_t *face,
@ -647,6 +657,8 @@ hb_ot_layout_table_find_feature (hb_face_t *face,
* Fetches a list of language tags in the given face's GSUB or GPOS table, underneath
* the specified script index. The list returned will begin at the offset provided.
*
* Return value: Total number of language tags.
*
**/
unsigned int
hb_ot_layout_script_get_language_tags (hb_face_t *face,
@ -818,6 +830,8 @@ hb_ot_layout_language_get_required_feature (hb_face_t *face,
* Fetches a list of all features in the specified face's GSUB table
* or GPOS table, underneath the specified script and language. The list
* returned will begin at the offset provided.
*
* Return value: Total number of features.
**/
unsigned int
hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
@ -850,6 +864,7 @@ hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
* or GPOS table, underneath the specified script and language. The list
* returned will begin at the offset provided.
*
* Return value: Total number of feature tags.
**/
unsigned int
hb_ot_layout_language_get_feature_tags (hb_face_t *face,
@ -932,6 +947,8 @@ hb_ot_layout_language_find_feature (hb_face_t *face,
* the specified face's GSUB table or GPOS table. The list returned will
* begin at the offset provided.
*
* Return value: Total number of lookups.
*
* Since: 0.9.7
**/
unsigned int
@ -960,6 +977,8 @@ hb_ot_layout_feature_get_lookups (hb_face_t *face,
* Fetches the total number of lookups enumerated in the specified
* face's GSUB table or GPOS table.
*
* Return value: Total number of lookups.
*
* Since: 0.9.22
**/
unsigned int
@ -974,10 +993,46 @@ struct hb_collect_features_context_t
{
hb_collect_features_context_t (hb_face_t *face,
hb_tag_t table_tag,
hb_set_t *feature_indexes_)
hb_set_t *feature_indices_,
const hb_tag_t *features)
: g (get_gsubgpos_table (face, table_tag)),
feature_indexes (feature_indexes_),
script_count (0),langsys_count (0), feature_index_count (0) {}
feature_indices (feature_indices_),
has_feature_filter (false),
script_count (0),langsys_count (0), feature_index_count (0)
{
compute_feature_filter (features);
}
void compute_feature_filter (const hb_tag_t *features)
{
if (features == nullptr)
{
has_feature_filter = false;
return;
}
has_feature_filter = true;
for (; *features; features++)
{
hb_tag_t tag = *features;
unsigned index;
g.find_feature_index (tag, &index);
if (index == OT::Index::NOT_FOUND_INDEX) continue;
feature_indices_filter.add(index);
for (int i = (int) index - 1; i >= 0; i--)
{
if (g.get_feature_tag (i) != tag) break;
feature_indices_filter.add(i);
}
for (unsigned i = index + 1; i < g.get_feature_count (); i++)
{
if (g.get_feature_tag (i) != tag) break;
feature_indices_filter.add(i);
}
}
}
bool visited (const OT::Script &s)
{
@ -1026,7 +1081,9 @@ struct hb_collect_features_context_t
public:
const OT::GSUBGPOS &g;
hb_set_t *feature_indexes;
hb_set_t *feature_indices;
hb_set_t feature_indices_filter;
bool has_feature_filter;
private:
hb_set_t visited_script;
@ -1038,37 +1095,31 @@ struct hb_collect_features_context_t
static void
langsys_collect_features (hb_collect_features_context_t *c,
const OT::LangSys &l,
const hb_tag_t *features)
const OT::LangSys &l)
{
if (c->visited (l)) return;
if (!features)
if (!c->has_feature_filter)
{
/* All features. */
if (l.has_required_feature () && !c->visited_feature_indices (1))
c->feature_indexes->add (l.get_required_feature_index ());
c->feature_indices->add (l.get_required_feature_index ());
// TODO(garretrieger): filter out indices >= feature count?
if (!c->visited_feature_indices (l.featureIndex.len))
l.add_feature_indexes_to (c->feature_indexes);
l.add_feature_indexes_to (c->feature_indices);
}
else
{
/* Ugh. Any faster way? */
for (; *features; features++)
if (c->feature_indices_filter.is_empty()) return;
unsigned int num_features = l.get_feature_count ();
for (unsigned int i = 0; i < num_features; i++)
{
hb_tag_t feature_tag = *features;
unsigned int num_features = l.get_feature_count ();
for (unsigned int i = 0; i < num_features; i++)
{
unsigned int feature_index = l.get_feature_index (i);
unsigned int feature_index = l.get_feature_index (i);
if (!c->feature_indices_filter.has (feature_index)) continue;
if (feature_tag == c->g.get_feature_tag (feature_index))
{
c->feature_indexes->add (feature_index);
break;
}
}
c->feature_indices->add (feature_index);
c->feature_indices_filter.del (feature_index);
}
}
}
@ -1076,8 +1127,7 @@ langsys_collect_features (hb_collect_features_context_t *c,
static void
script_collect_features (hb_collect_features_context_t *c,
const OT::Script &s,
const hb_tag_t *languages,
const hb_tag_t *features)
const hb_tag_t *languages)
{
if (c->visited (s)) return;
@ -1086,14 +1136,13 @@ script_collect_features (hb_collect_features_context_t *c,
/* All languages. */
if (s.has_default_lang_sys ())
langsys_collect_features (c,
s.get_default_lang_sys (),
features);
s.get_default_lang_sys ());
unsigned int count = s.get_lang_sys_count ();
for (unsigned int language_index = 0; language_index < count; language_index++)
langsys_collect_features (c,
s.get_lang_sys (language_index),
features);
s.get_lang_sys (language_index));
}
else
{
@ -1102,8 +1151,8 @@ script_collect_features (hb_collect_features_context_t *c,
unsigned int language_index;
if (s.find_lang_sys_index (*languages, &language_index))
langsys_collect_features (c,
s.get_lang_sys (language_index),
features);
s.get_lang_sys (language_index));
}
}
}
@ -1134,7 +1183,7 @@ hb_ot_layout_collect_features (hb_face_t *face,
const hb_tag_t *features,
hb_set_t *feature_indexes /* OUT */)
{
hb_collect_features_context_t c (face, table_tag, feature_indexes);
hb_collect_features_context_t c (face, table_tag, feature_indexes, features);
if (!scripts)
{
/* All scripts. */
@ -1142,8 +1191,7 @@ hb_ot_layout_collect_features (hb_face_t *face,
for (unsigned int script_index = 0; script_index < count; script_index++)
script_collect_features (&c,
c.g.get_script (script_index),
languages,
features);
languages);
}
else
{
@ -1153,8 +1201,7 @@ hb_ot_layout_collect_features (hb_face_t *face,
if (c.g.find_script_index (*scripts, &script_index))
script_collect_features (&c,
c.g.get_script (script_index),
languages,
features);
languages);
}
}
}
@ -1262,6 +1309,8 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
* Fetches a list of feature variations in the specified face's GSUB table
* or GPOS table, at the specified variation coordinates.
*
* Return value: %true if feature variations were found, %false otherwise.
*
**/
hb_bool_t
hb_ot_layout_table_find_feature_variations (hb_face_t *face,
@ -1291,6 +1340,8 @@ hb_ot_layout_table_find_feature_variations (hb_face_t *face,
* the specified face's GSUB table or GPOS table, enabled at the specified
* variations index. The list returned will begin at the offset provided.
*
* Return value: Total number of lookups.
*
**/
unsigned int
hb_ot_layout_feature_with_variations_get_lookups (hb_face_t *face,
@ -1337,7 +1388,8 @@ hb_ot_layout_has_substitution (hb_face_t *face)
* @lookup_index: The index of the lookup to query
* @glyphs: The sequence of glyphs to query for substitution
* @glyphs_length: The length of the glyph sequence
* @zero_context: #hb_bool_t indicating whether substitutions should be context-free
* @zero_context: #hb_bool_t indicating whether pre-/post-context are disallowed
* in substitutions
*
* Tests whether a specified lookup in the specified face would
* trigger a substitution on the given glyph sequence.
@ -1443,12 +1495,17 @@ hb_ot_layout_lookup_substitute_closure (hb_face_t *face,
unsigned int lookup_index,
hb_set_t *glyphs /* OUT */)
{
hb_map_t done_lookups;
OT::hb_closure_context_t c (face, glyphs, &done_lookups);
hb_set_t cur_intersected_glyphs;
hb_map_t done_lookups_glyph_count;
hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> done_lookups_glyph_set;
OT::hb_closure_context_t c (face, glyphs, &cur_intersected_glyphs, &done_lookups_glyph_count, &done_lookups_glyph_set);
const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index);
l.closure (&c, lookup_index);
for (auto _ : done_lookups_glyph_set.iter ())
hb_set_destroy (_.second);
}
/**
@ -1467,8 +1524,10 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face,
const hb_set_t *lookups,
hb_set_t *glyphs /* OUT */)
{
hb_map_t done_lookups;
OT::hb_closure_context_t c (face, glyphs, &done_lookups);
hb_set_t cur_intersected_glyphs;
hb_map_t done_lookups_glyph_count;
hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> done_lookups_glyph_set;
OT::hb_closure_context_t c (face, glyphs, &cur_intersected_glyphs, &done_lookups_glyph_count, &done_lookups_glyph_set);
const OT::GSUB& gsub = *face->table.GSUB->table;
unsigned int iteration_count = 0;
@ -1488,6 +1547,9 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face,
}
} while (iteration_count++ <= HB_CLOSURE_MAX_STAGES &&
glyphs_length != glyphs->get_population ());
for (auto _ : done_lookups_glyph_set.iter ())
hb_set_destroy (_.second);
}
/*
@ -1824,27 +1886,20 @@ apply_string (OT::hb_ot_apply_context_t *c,
if (likely (!lookup.is_reverse ()))
{
/* in/out forward substitution/positioning */
if (Proxy::table_index == 0u)
if (!Proxy::inplace)
buffer->clear_output ();
buffer->idx = 0;
bool ret;
ret = apply_forward (c, accel);
if (ret)
{
if (!Proxy::inplace)
buffer->swap_buffers ();
else
assert (!buffer->has_separate_output ());
}
buffer->idx = 0;
apply_forward (c, accel);
if (!Proxy::inplace)
buffer->swap_buffers ();
}
else
{
/* in-place backward substitution/positioning */
if (Proxy::table_index == 0u)
buffer->remove_output ();
assert (!buffer->have_output);
buffer->idx = buffer->len - 1;
apply_backward (c, accel);
}
}
@ -1860,7 +1915,8 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
OT::hb_ot_apply_context_t c (table_index, font, buffer);
c.set_recurse_func (Proxy::Lookup::apply_recurse_func);
for (unsigned int stage_index = 0; stage_index < stages[table_index].length; stage_index++) {
for (unsigned int stage_index = 0; stage_index < stages[table_index].length; stage_index++)
{
const stage_map_t *stage = &stages[table_index][stage_index];
for (; i < stage->last_lookup; i++)
{
@ -1870,11 +1926,8 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
c.set_lookup_mask (lookups[table_index][i].mask);
c.set_auto_zwj (lookups[table_index][i].auto_zwj);
c.set_auto_zwnj (lookups[table_index][i].auto_zwnj);
if (lookups[table_index][i].random)
{
c.set_random (true);
buffer->unsafe_to_break_all ();
}
c.set_random (lookups[table_index][i].random);
apply_string<Proxy> (&c,
proxy.table.get_lookup (lookup_index),
proxy.accels[lookup_index]);
@ -1882,10 +1935,7 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
}
if (stage->pause_func)
{
buffer->clear_output ();
stage->pause_func (plan, font, buffer);
}
}
}
@ -1925,7 +1975,7 @@ hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
*
* Fetches a baseline value from the face.
*
* Return value: if found baseline value in the font.
* Return value: %true if found baseline value in the font.
*
* Since: 2.6.0
**/
@ -1984,7 +2034,7 @@ struct hb_get_glyph_alternates_dispatch_t :
*
* Fetches alternates of a glyph from a given GSUB lookup index.
*
* Return value: total number of alternates found in the specific lookup index for the given glyph id.
* Return value: Total number of alternates found in the specific lookup index for the given glyph id.
*
* Since: 2.6.8
**/

View File

@ -314,7 +314,6 @@ _hb_glyph_info_get_unicode_space_fallback_type (const hb_glyph_info_t *info)
hb_unicode_funcs_t::NOT_SPACE;
}
static inline bool _hb_glyph_info_ligated (const hb_glyph_info_t *info);
static inline bool _hb_glyph_info_substituted (const hb_glyph_info_t *info);
static inline bool
@ -328,7 +327,7 @@ _hb_glyph_info_is_default_ignorable_and_not_hidden (const hb_glyph_info_t *info)
{
return ((info->unicode_props() & (UPROPS_MASK_IGNORABLE|UPROPS_MASK_HIDDEN))
== UPROPS_MASK_IGNORABLE) &&
!_hb_glyph_info_ligated (info);
!_hb_glyph_info_substituted (info);
}
static inline void
_hb_glyph_info_unhide (hb_glyph_info_t *info)

View File

@ -54,7 +54,6 @@ hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_,
face = face_;
props = *props_;
/* Fetch script/language indices for GSUB/GPOS. We need these later to skip
* features not available in either table and not waste precious bits for them. */
@ -63,12 +62,28 @@ hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_,
hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT];
hb_tag_t language_tags[HB_OT_MAX_TAGS_PER_LANGUAGE];
hb_ot_tags_from_script_and_language (props.script, props.language, &script_count, script_tags, &language_count, language_tags);
hb_ot_tags_from_script_and_language (props.script,
props.language,
&script_count,
script_tags,
&language_count,
language_tags);
for (unsigned int table_index = 0; table_index < 2; table_index++) {
for (unsigned int table_index = 0; table_index < 2; table_index++)
{
hb_tag_t table_tag = table_tags[table_index];
found_script[table_index] = (bool) hb_ot_layout_table_select_script (face, table_tag, script_count, script_tags, &script_index[table_index], &chosen_script[table_index]);
hb_ot_layout_script_select_language (face, table_tag, script_index[table_index], language_count, language_tags, &language_index[table_index]);
found_script[table_index] = (bool) hb_ot_layout_table_select_script (face,
table_tag,
script_count,
script_tags,
&script_index[table_index],
&chosen_script[table_index]);
hb_ot_layout_script_select_language (face,
table_tag,
script_index[table_index],
language_count,
language_tags,
&language_index[table_index]);
}
}
@ -150,9 +165,8 @@ void
hb_ot_map_builder_t::compile (hb_ot_map_t &m,
const hb_ot_shape_plan_key_t &key)
{
static_assert ((!(HB_GLYPH_FLAG_DEFINED & (HB_GLYPH_FLAG_DEFINED + 1))), "");
unsigned int global_bit_mask = HB_GLYPH_FLAG_DEFINED + 1;
unsigned int global_bit_shift = hb_popcount (HB_GLYPH_FLAG_DEFINED);
unsigned int global_bit_shift = 8 * sizeof (hb_mask_t) - 1;
unsigned int global_bit_mask = 1u << global_bit_shift;
m.global_mask = global_bit_mask;
@ -205,7 +219,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
/* Allocate bits now */
unsigned int next_bit = global_bit_shift + 1;
static_assert ((!(HB_GLYPH_FLAG_DEFINED & (HB_GLYPH_FLAG_DEFINED + 1))), "");
unsigned int next_bit = hb_popcount (HB_GLYPH_FLAG_DEFINED) + 1;
for (unsigned int i = 0; i < feature_infos.length; i++)
{
@ -220,7 +235,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
/* Limit bits per feature. */
bits_needed = hb_min (HB_OT_MAP_MAX_BITS, hb_bit_storage (info->max_value));
if (!info->max_value || next_bit + bits_needed > 8 * sizeof (hb_mask_t))
if (!info->max_value || next_bit + bits_needed >= global_bit_shift)
continue; /* Feature disabled, or not enough bits. */
@ -274,7 +289,6 @@ hb_ot_map_builder_t::compile (hb_ot_map_t &m,
}
map->_1_mask = (1u << map->shift) & map->mask;
map->needs_fallback = !found;
}
feature_infos.shrink (0); /* Done with these */

View File

@ -49,7 +49,7 @@ struct MathValueRecord
protected:
HBINT16 value; /* The X or Y value in design units */
OffsetTo<Device> deviceTable; /* Offset to the device table - from the
Offset16To<Device> deviceTable; /* Offset to the device table - from the
* beginning of parent table. May be NULL.
* Suggested format for device table is 1. */
@ -181,11 +181,11 @@ struct MathItalicsCorrectionInfo
}
protected:
OffsetTo<Coverage> coverage; /* Offset to Coverage table -
Offset16To<Coverage> coverage; /* Offset to Coverage table -
* from the beginning of
* MathItalicsCorrectionInfo
* table. */
ArrayOf<MathValueRecord> italicsCorrection; /* Array of MathValueRecords
Array16Of<MathValueRecord> italicsCorrection; /* Array of MathValueRecords
* defining italics correction
* values for each
* covered glyph. */
@ -214,11 +214,11 @@ struct MathTopAccentAttachment
}
protected:
OffsetTo<Coverage> topAccentCoverage; /* Offset to Coverage table -
Offset16To<Coverage> topAccentCoverage; /* Offset to Coverage table -
* from the beginning of
* MathTopAccentAttachment
* table. */
ArrayOf<MathValueRecord> topAccentAttachment; /* Array of MathValueRecords
Array16Of<MathValueRecord> topAccentAttachment; /* Array of MathValueRecords
* defining top accent
* attachment points for each
* covered glyph. */
@ -320,7 +320,7 @@ struct MathKernInfoRecord
protected:
/* Offset to MathKern table for each corner -
* from the beginning of MathKernInfo table. May be NULL. */
OffsetTo<MathKern> mathKern[4];
Offset16To<MathKern> mathKern[4];
public:
DEFINE_SIZE_STATIC (8);
@ -346,12 +346,12 @@ struct MathKernInfo
}
protected:
OffsetTo<Coverage>
Offset16To<Coverage>
mathKernCoverage;
/* Offset to Coverage table -
* from the beginning of the
* MathKernInfo table. */
ArrayOf<MathKernInfoRecord>
Array16Of<MathKernInfoRecord>
mathKernInfoRecords;
/* Array of MathKernInfoRecords,
* per-glyph information for
@ -395,22 +395,22 @@ struct MathGlyphInfo
protected:
/* Offset to MathItalicsCorrectionInfo table -
* from the beginning of MathGlyphInfo table. */
OffsetTo<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo;
Offset16To<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo;
/* Offset to MathTopAccentAttachment table -
* from the beginning of MathGlyphInfo table. */
OffsetTo<MathTopAccentAttachment> mathTopAccentAttachment;
Offset16To<MathTopAccentAttachment> mathTopAccentAttachment;
/* Offset to coverage table for Extended Shape glyphs -
* from the beginning of MathGlyphInfo table. When the left or right glyph of
* a box is an extended shape variant, the (ink) box (and not the default
* position defined by values in MathConstants table) should be used for
* vertical positioning purposes. May be NULL.. */
OffsetTo<Coverage> extendedShapeCoverage;
Offset16To<Coverage> extendedShapeCoverage;
/* Offset to MathKernInfo table -
* from the beginning of MathGlyphInfo table. */
OffsetTo<MathKernInfo> mathKernInfo;
Offset16To<MathKernInfo> mathKernInfo;
public:
DEFINE_SIZE_STATIC (8);
@ -532,7 +532,7 @@ struct MathGlyphAssembly
/* Italics correction of this
* MathGlyphAssembly. Should not
* depend on the assembly size. */
ArrayOf<MathGlyphPartRecord>
Array16Of<MathGlyphPartRecord>
partRecords; /* Array of part records, from
* left to right and bottom to
* top. */
@ -572,10 +572,10 @@ struct MathGlyphConstruction
protected:
/* Offset to MathGlyphAssembly table for this shape - from the beginning of
MathGlyphConstruction table. May be NULL. */
OffsetTo<MathGlyphAssembly> glyphAssembly;
Offset16To<MathGlyphAssembly> glyphAssembly;
/* MathGlyphVariantRecords for alternative variants of the glyphs. */
ArrayOf<MathGlyphVariantRecord> mathGlyphVariantRecord;
Array16Of<MathGlyphVariantRecord> mathGlyphVariantRecord;
public:
DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord);
@ -636,7 +636,7 @@ struct MathVariants
{
bool vertical = HB_DIRECTION_IS_VERTICAL (direction);
unsigned int count = vertical ? vertGlyphCount : horizGlyphCount;
const OffsetTo<Coverage> &coverage = vertical ? vertGlyphCoverage
const Offset16To<Coverage> &coverage = vertical ? vertGlyphCoverage
: horizGlyphCoverage;
unsigned int index = (this+coverage).get_coverage (glyph);
@ -653,11 +653,11 @@ struct MathVariants
/* Minimum overlap of connecting
* glyphs during glyph construction,
* in design units. */
OffsetTo<Coverage> vertGlyphCoverage;
Offset16To<Coverage> vertGlyphCoverage;
/* Offset to Coverage table -
* from the beginning of MathVariants
* table. */
OffsetTo<Coverage> horizGlyphCoverage;
Offset16To<Coverage> horizGlyphCoverage;
/* Offset to Coverage table -
* from the beginning of MathVariants
* table. */
@ -671,7 +671,7 @@ struct MathVariants
/* Array of offsets to MathGlyphConstruction tables - from the beginning of
the MathVariants table, for shapes growing in vertical/horizontal
direction. */
UnsizedArrayOf<OffsetTo<MathGlyphConstruction>>
UnsizedArrayOf<Offset16To<MathGlyphConstruction>>
glyphConstruction;
public:
@ -711,11 +711,11 @@ struct MATH
protected:
FixedVersion<>version; /* Version of the MATH table
* initially set to 0x00010000u */
OffsetTo<MathConstants>
Offset16To<MathConstants>
mathConstants; /* MathConstants table */
OffsetTo<MathGlyphInfo>
Offset16To<MathGlyphInfo>
mathGlyphInfo; /* MathGlyphInfo table */
OffsetTo<MathVariants>
Offset16To<MathVariants>
mathVariants; /* MathVariants table */
public:

View File

@ -107,7 +107,7 @@ struct maxp
maxpV1Tail *dest_v1 = c->serializer->embed<maxpV1Tail> (src_v1);
if (unlikely (!dest_v1)) return_trace (false);
if (c->plan->drop_hints)
if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
drop_hint_fields (dest_v1);
}

View File

@ -56,7 +56,7 @@ struct DataMap
protected:
Tag tag; /* A tag indicating the type of metadata. */
LNNOffsetTo<UnsizedArrayOf<HBUINT8>>
NNOffset32To<UnsizedArrayOf<HBUINT8>>
dataZ; /* Offset in bytes from the beginning of the
* metadata table to the data for this tag. */
HBUINT32 dataLength; /* Length of the data. The data is not required to
@ -113,7 +113,7 @@ struct meta
* Offset from the beginning of the table to the data.
* Per OT specification:
* Reserved. Not used; should be set to 0. */
LArrayOf<DataMap>
Array32Of<DataMap>
dataMaps;/* Array of data map records. */
public:
DEFINE_SIZE_ARRAY (16, dataMaps);

View File

@ -149,7 +149,7 @@ struct NameRecord
HBUINT16 languageID; /* Language ID. */
HBUINT16 nameID; /* Name ID. */
HBUINT16 length; /* String length (in bytes). */
NNOffsetTo<UnsizedArrayOf<HBUINT8>>
NNOffset16To<UnsizedArrayOf<HBUINT8>>
offset; /* String offset from start of storage area (in bytes). */
public:
DEFINE_SIZE_STATIC (12);
@ -214,7 +214,7 @@ struct name
this->format = 0;
this->count = it.len ();
NameRecord *name_records = (NameRecord *) calloc (it.len (), NameRecord::static_size);
NameRecord *name_records = (NameRecord *) hb_calloc (it.len (), NameRecord::static_size);
if (unlikely (!name_records)) return_trace (false);
hb_array_t<NameRecord> records (name_records, it.len ());
@ -228,9 +228,10 @@ struct name
records.qsort ();
c->copy_all (records, src_string_pool);
free (records.arrayZ);
hb_free (records.arrayZ);
if (unlikely (c->ran_out_of_room)) return_trace (false);
if (unlikely (c->ran_out_of_room ())) return_trace (false);
this->stringOffset = c->length ();
@ -248,7 +249,11 @@ struct name
+ nameRecordZ.as_array (count)
| hb_filter (c->plan->name_ids, &NameRecord::nameID)
| hb_filter (c->plan->name_languages, &NameRecord::languageID)
| hb_filter ([&] (const NameRecord& namerecord) { return c->plan->name_legacy || namerecord.isUnicode (); })
| hb_filter ([&] (const NameRecord& namerecord) {
return
(c->plan->flags & HB_SUBSET_FLAGS_NAME_LEGACY)
|| namerecord.isUnicode ();
})
;
name_prime->serialize (c->serializer, it, hb_addressof (this + stringOffset));
@ -357,7 +362,7 @@ struct name
/* We only implement format 0 for now. */
HBUINT16 format; /* Format selector (=0/1). */
HBUINT16 count; /* Number of name records. */
NNOffsetTo<UnsizedArrayOf<HBUINT8>>
NNOffset16To<UnsizedArrayOf<HBUINT8>>
stringOffset; /* Offset to start of string storage (from start of table). */
UnsizedArrayOf<NameRecord>
nameRecordZ; /* The name records where count is the number of records. */

View File

@ -156,7 +156,8 @@ hb_ot_name_get_utf (hb_face_t *face,
*
* Fetches a font name from the OpenType 'name' table.
* If @language is #HB_LANGUAGE_INVALID, English ("en") is assumed.
* Returns string in UTF-8 encoding.
* Returns string in UTF-8 encoding. A NUL terminator is always written
* for convenience, and isn't included in the output @text_size.
*
* Returns: full length of the requested string, or 0 if not found.
* Since: 2.1.0
@ -183,7 +184,8 @@ hb_ot_name_get_utf8 (hb_face_t *face,
*
* Fetches a font name from the OpenType 'name' table.
* If @language is #HB_LANGUAGE_INVALID, English ("en") is assumed.
* Returns string in UTF-16 encoding.
* Returns string in UTF-16 encoding. A NUL terminator is always written
* for convenience, and isn't included in the output @text_size.
*
* Returns: full length of the requested string, or 0 if not found.
* Since: 2.1.0
@ -209,7 +211,8 @@ hb_ot_name_get_utf16 (hb_face_t *face,
*
* Fetches a font name from the OpenType 'name' table.
* If @language is #HB_LANGUAGE_INVALID, English ("en") is assumed.
* Returns string in UTF-32 encoding.
* Returns string in UTF-32 encoding. A NUL terminator is always written
* for convenience, and isn't included in the output @text_size.
*
* Returns: full length of the requested string, or 0 if not found.
* Since: 2.1.0

View File

@ -30,7 +30,6 @@
#include "hb-open-type.hh"
#include "hb-ot-os2-unicode-ranges.hh"
#include "hb-ot-cmap-table.hh"
#include "hb-set.hh"
@ -172,33 +171,17 @@ struct OS2
TRACE_SUBSET (this);
OS2 *os2_prime = c->serializer->embed (this);
if (unlikely (!os2_prime)) return_trace (false);
if (c->plan->flags & HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES)
return_trace (true);
hb_set_t unicodes;
if (!c->plan->glyphs_requested->is_empty ())
{
hb_map_t unicode_glyphid_map;
OT::cmap::accelerator_t cmap;
cmap.init (c->plan->source);
cmap.collect_mapping (&unicodes, &unicode_glyphid_map);
cmap.fini ();
hb_set_set (&unicodes, c->plan->unicodes);
+ unicode_glyphid_map.iter ()
| hb_filter (c->plan->glyphs_requested, hb_second)
| hb_map (hb_first)
| hb_sink (unicodes)
;
}
/* when --gids option is not used, no need to do collect_mapping that is
* iterating all codepoints in each subtable, which is not efficient */
uint16_t min_cp, max_cp;
find_min_and_max_codepoint (unicodes.is_empty () ? c->plan->unicodes : &unicodes, &min_cp, &max_cp);
find_min_and_max_codepoint (c->plan->unicodes, &min_cp, &max_cp);
os2_prime->usFirstCharIndex = min_cp;
os2_prime->usLastCharIndex = max_cp;
_update_unicode_ranges (unicodes.is_empty () ? c->plan->unicodes : &unicodes, os2_prime->ulUnicodeRange);
_update_unicode_ranges (c->plan->unicodes, os2_prime->ulUnicodeRange);
return_trace (true);
}

View File

@ -0,0 +1,130 @@
/*
* Copyright © 2021 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.
*
*/
#ifndef HB_OT_POST_TABLE_V2SUBSET_HH
#define HB_OT_POST_TABLE_V2SUBSET_HH
#include "hb-open-type.hh"
#include "hb-ot-post-table.hh"
/*
* post -- PostScript
* https://docs.microsoft.com/en-us/typography/opentype/spec/post
*/
namespace OT {
template<typename Iterator>
HB_INTERNAL bool postV2Tail::serialize (hb_serialize_context_t *c,
Iterator it,
const void* _post) const
{
TRACE_SERIALIZE (this);
auto *out = c->start_embed (this);
if (unlikely (!c->check_success (out))) return_trace (false);
if (!out->glyphNameIndex.serialize (c, + it
| hb_map (hb_second)))
return_trace (false);
hb_set_t copied_indices;
for (const auto& _ : + it )
{
unsigned glyph_id = _.first;
unsigned new_index = _.second;
if (new_index < 258) continue;
if (copied_indices.has (new_index)) continue;
copied_indices.add (new_index);
hb_bytes_t s = reinterpret_cast<const post::accelerator_t*> (_post)->find_glyph_name (glyph_id);
HBUINT8 *o = c->allocate_size<HBUINT8> (HBUINT8::static_size * (s.length + 1));
if (unlikely (!o)) return_trace (false);
if (!c->check_assign (o[0], s.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
memcpy (o+1, s.arrayZ, HBUINT8::static_size * s.length);
}
return_trace (true);
}
HB_INTERNAL bool postV2Tail::subset (hb_subset_context_t *c) const
{
TRACE_SUBSET (this);
const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map;
unsigned num_glyphs = c->plan->num_output_glyphs ();
hb_map_t old_new_index_map, old_gid_new_index_map;
unsigned i = 0;
post::accelerator_t _post;
_post.init (c->plan->source);
for (hb_codepoint_t new_gid = 0; new_gid < num_glyphs; new_gid++)
{
hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
unsigned old_index = glyphNameIndex[old_gid];
unsigned new_index;
if (old_index <= 257) new_index = old_index;
else if (old_new_index_map.has (old_index)) new_index = old_new_index_map.get (old_index);
else
{
hb_bytes_t s = _post.find_glyph_name (old_gid);
int standard_glyph_index = -1;
for (unsigned i = 0; i < format1_names_length; i++)
{
if (s == format1_names (i))
{
standard_glyph_index = i;
break;
}
}
if (standard_glyph_index == -1)
{
new_index = 258 + i;
i++;
}
else
{ new_index = standard_glyph_index; }
old_new_index_map.set (old_index, new_index);
}
old_gid_new_index_map.set (old_gid, new_index);
}
auto index_iter =
+ hb_range (num_glyphs)
| hb_map (reverse_glyph_map)
| hb_map_retains_sorting ([&](hb_codepoint_t old_gid)
{
unsigned new_index = old_gid_new_index_map.get (old_gid);
return hb_pair_t<unsigned, unsigned> (old_gid, new_index);
})
;
bool ret = serialize (c->serializer, index_iter, &_post);
_post.fini ();
return_trace (ret);
}
} /* namespace OT */
#endif /* HB_OT_POST_TABLE_V2SUBSET_HH */

View File

@ -55,8 +55,15 @@ struct postV2Tail
return_trace (glyphNameIndex.sanitize (c));
}
template<typename Iterator>
bool serialize (hb_serialize_context_t *c,
Iterator it,
const void* _post) const;
bool subset (hb_subset_context_t *c) const;
protected:
ArrayOf<HBUINT16> glyphNameIndex; /* This is not an offset, but is the
Array16Of<HBUINT16> glyphNameIndex; /* This is not an offset, but is the
* ordinal number of the glyph in 'post'
* string tables. */
/*UnsizedArrayOf<HBUINT8>
@ -71,13 +78,18 @@ struct post
{
static constexpr hb_tag_t tableTag = HB_OT_TAG_post;
void serialize (hb_serialize_context_t *c) const
bool serialize (hb_serialize_context_t *c, bool glyph_names) const
{
TRACE_SERIALIZE (this);
post *post_prime = c->allocate_min<post> ();
if (unlikely (!post_prime)) return;
if (unlikely (!post_prime)) return_trace (false);
memcpy (post_prime, this, post::min_size);
post_prime->version.major = 3; // Version 3 does not have any glyph names.
if (!glyph_names)
return_trace (c->check_assign (post_prime->version.major, 3,
HB_SERIALIZE_ERROR_INT_OVERFLOW)); // Version 3 does not have any glyph names.
return_trace (true);
}
bool subset (hb_subset_context_t *c) const
@ -86,13 +98,19 @@ struct post
post *post_prime = c->serializer->start_embed<post> ();
if (unlikely (!post_prime)) return_trace (false);
serialize (c->serializer);
bool glyph_names = c->plan->flags & HB_SUBSET_FLAGS_GLYPH_NAMES;
if (!serialize (c->serializer, glyph_names))
return_trace (false);
if (glyph_names && version.major == 2)
return_trace (v2X.subset (c));
return_trace (true);
}
struct accelerator_t
{
friend struct postV2Tail;
void init (hb_face_t *face)
{
index_to_offset.init ();
@ -117,7 +135,7 @@ struct post
void fini ()
{
index_to_offset.fini ();
free (gids_sorted_by_name.get ());
hb_free (gids_sorted_by_name.get ());
table.destroy ();
}
@ -148,7 +166,7 @@ struct post
if (unlikely (!gids))
{
gids = (uint16_t *) malloc (count * sizeof (gids[0]));
gids = (uint16_t *) hb_malloc (count * sizeof (gids[0]));
if (unlikely (!gids))
return false; /* Anything better?! */
@ -158,7 +176,7 @@ struct post
if (unlikely (!gids_sorted_by_name.cmpexch (nullptr, gids)))
{
free (gids);
hb_free (gids);
goto retry;
}
}
@ -236,7 +254,7 @@ struct post
private:
uint32_t version;
const ArrayOf<HBUINT16> *glyphNameIndex;
const Array16Of<HBUINT16> *glyphNameIndex;
hb_vector_t<uint32_t> index_to_offset;
const uint8_t *pool;
hb_atomic_ptr_t<uint16_t *> gids_sorted_by_name;

View File

@ -208,11 +208,11 @@ struct ManifestLookup
{
public:
OT::Tag tag;
OT::OffsetTo<OT::SubstLookup> lookupOffset;
OT::Offset16To<OT::SubstLookup> lookupOffset;
public:
DEFINE_SIZE_STATIC (6);
};
typedef OT::ArrayOf<ManifestLookup> Manifest;
typedef OT::Array16Of<ManifestLookup> Manifest;
static bool
arabic_fallback_plan_init_win1256 (arabic_fallback_plan_t *fallback_plan HB_UNUSED,
@ -290,7 +290,7 @@ static arabic_fallback_plan_t *
arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan,
hb_font_t *font)
{
arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) calloc (1, sizeof (arabic_fallback_plan_t));
arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) hb_calloc (1, sizeof (arabic_fallback_plan_t));
if (unlikely (!fallback_plan))
return const_cast<arabic_fallback_plan_t *> (&Null (arabic_fallback_plan_t));
@ -308,7 +308,7 @@ arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan,
return fallback_plan;
assert (fallback_plan->num_lookups == 0);
free (fallback_plan);
hb_free (fallback_plan);
return const_cast<arabic_fallback_plan_t *> (&Null (arabic_fallback_plan_t));
}
@ -323,10 +323,10 @@ arabic_fallback_plan_destroy (arabic_fallback_plan_t *fallback_plan)
{
fallback_plan->accel_array[i].fini ();
if (fallback_plan->free_lookups)
free (fallback_plan->lookup_array[i]);
hb_free (fallback_plan->lookup_array[i]);
}
free (fallback_plan);
hb_free (fallback_plan);
}
static void

View File

@ -6,10 +6,10 @@
*
* on files with these headers:
*
* # ArabicShaping-13.0.0.txt
* # Date: 2020-01-31, 23:55:00 GMT [KW, RP]
* # Scripts-13.0.0.txt
* # Date: 2020-01-22, 00:07:43 GMT
* # ArabicShaping-14.0.0.txt
* # Date: 2021-05-21, 01:54:00 GMT [KW, RP]
* # Scripts-14.0.0.txt
* # Date: 2021-07-10, 00:35:31 GMT
*/
#ifndef HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH
@ -29,6 +29,7 @@ has_arabic_joining (hb_script_t script)
case HB_SCRIPT_MANICHAEAN:
case HB_SCRIPT_MONGOLIAN:
case HB_SCRIPT_NKO:
case HB_SCRIPT_OLD_UYGHUR:
case HB_SCRIPT_PHAGS_PA:
case HB_SCRIPT_PSALTER_PAHLAVI:
case HB_SCRIPT_SOGDIAN:

View File

@ -6,10 +6,10 @@
*
* on files with these headers:
*
* # ArabicShaping-13.0.0.txt
* # Date: 2020-01-31, 23:55:00 GMT [KW, RP]
* # Blocks-13.0.0.txt
* # Date: 2019-07-10, 19:06:00 GMT [KW]
* # ArabicShaping-14.0.0.txt
* # Date: 2021-05-21, 01:54:00 GMT [KW, RP]
* # Blocks-14.0.0.txt
* # Date: 2021-01-22, 23:29:00 GMT [KW]
* UnicodeData.txt does not have a header.
*/
@ -75,13 +75,17 @@ static const uint8_t joining_table[] =
/* Syriac Supplement */
/* 0860 */ D,U,D,D,D,D,U,R,D,R,R,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
/* 0880 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
/* 0860 */ D,U,D,D,D,D,U,R,D,R,R,X,X,X,X,X,
/* Arabic Extended-B */
/* 0860 */ R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,
/* 0880 */ R,R,R,C,C,C,D,U,U,D,D,D,D,D,R,X,U,U,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
/* Arabic Extended-A */
/* 08A0 */ D,D,D,D,D,D,D,D,D,D,R,R,R,U,R,D,D,R,R,D,D,X,D,D,D,R,D,D,D,D,D,D,
/* 08C0 */ D,D,D,D,D,D,D,D,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
/* 08A0 */ D,D,D,D,D,D,D,D,D,D,R,R,R,U,R,D,D,R,R,D,D,D,D,D,D,R,D,D,D,D,D,D,
/* 08C0 */ D,D,D,D,D,D,D,D,D,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
/* 08E0 */ X,X,U,
#define joining_offset_0x1806u 739
@ -137,23 +141,28 @@ static const uint8_t joining_table[] =
/* Sogdian */
/* 10F20 */ D,D,D,R,D,D,D,D,D,D,D,D,D,D,D,D,
/* 10F40 */ D,D,D,D,D,U,X,X,X,X,X,X,X,X,X,X,X,D,D,D,R,
/* 10F40 */ D,D,D,D,D,U,X,X,X,X,X,X,X,X,X,X,X,D,D,D,R,X,X,X,X,X,X,X,X,X,X,X,
/* 10F60 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
#define joining_offset_0x10fb0u 1219
/* Old Uyghur */
/* 10F60 */ D,D,D,D,R,R,D,D,D,D,D,D,D,D,D,D,
/* 10F80 */ D,D,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
/* 10FA0 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
/* Chorasmian */
/* 10FA0 */ D,U,D,D,R,R,R,U,D,R,R,D,D,R,D,D,
/* 10FC0 */ U,D,R,R,D,U,U,U,U,R,D,L,
#define joining_offset_0x110bdu 1247
#define joining_offset_0x110bdu 1338
/* Kaithi */
/* 110A0 */ U,X,X,
/* 110C0 */ X,X,X,X,X,X,X,X,X,X,X,X,X,U,
#define joining_offset_0x1e900u 1264
#define joining_offset_0x1e900u 1355
/* Adlam */
@ -161,7 +170,7 @@ static const uint8_t joining_table[] =
/* 1E920 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
/* 1E940 */ D,D,D,D,X,X,X,X,X,X,X,T,
}; /* Table items: 1340; occupancy: 57% */
}; /* Table items: 1431; occupancy: 57% */
static unsigned int
@ -189,8 +198,7 @@ joining_type (hb_codepoint_t u)
if (hb_in_range<hb_codepoint_t> (u, 0x10AC0u, 0x10AEFu)) return joining_table[u - 0x10AC0u + joining_offset_0x10ac0u];
if (hb_in_range<hb_codepoint_t> (u, 0x10B80u, 0x10BAFu)) return joining_table[u - 0x10B80u + joining_offset_0x10b80u];
if (hb_in_range<hb_codepoint_t> (u, 0x10D00u, 0x10D23u)) return joining_table[u - 0x10D00u + joining_offset_0x10d00u];
if (hb_in_range<hb_codepoint_t> (u, 0x10F30u, 0x10F54u)) return joining_table[u - 0x10F30u + joining_offset_0x10f30u];
if (hb_in_range<hb_codepoint_t> (u, 0x10FB0u, 0x10FCBu)) return joining_table[u - 0x10FB0u + joining_offset_0x10fb0u];
if (hb_in_range<hb_codepoint_t> (u, 0x10F30u, 0x10FCBu)) return joining_table[u - 0x10F30u + joining_offset_0x10f30u];
break;
case 0x11u:

View File

@ -259,7 +259,7 @@ struct arabic_shape_plan_t
void *
data_create_arabic (const hb_ot_shape_plan_t *plan)
{
arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) calloc (1, sizeof (arabic_shape_plan_t));
arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) hb_calloc (1, sizeof (arabic_shape_plan_t));
if (unlikely (!arabic_plan))
return nullptr;
@ -282,7 +282,7 @@ data_destroy_arabic (void *data)
arabic_fallback_plan_destroy (arabic_plan->fallback_plan);
free (data);
hb_free (data);
}
static void

View File

@ -80,7 +80,7 @@ struct hangul_shape_plan_t
static void *
data_create_hangul (const hb_ot_shape_plan_t *plan)
{
hangul_shape_plan_t *hangul_plan = (hangul_shape_plan_t *) calloc (1, sizeof (hangul_shape_plan_t));
hangul_shape_plan_t *hangul_plan = (hangul_shape_plan_t *) hb_calloc (1, sizeof (hangul_shape_plan_t));
if (unlikely (!hangul_plan))
return nullptr;
@ -93,7 +93,7 @@ data_create_hangul (const hb_ot_shape_plan_t *plan)
static void
data_destroy_hangul (void *data)
{
free (data);
hb_free (data);
}
/* Constants for algorithmic hangul syllable [de]composition. */

View File

@ -6,12 +6,12 @@
*
* on files with these headers:
*
* # IndicSyllabicCategory-13.0.0.txt
* # Date: 2019-07-22, 19:55:00 GMT [KW, RP]
* # IndicPositionalCategory-13.0.0.txt
* # Date: 2019-07-23, 00:01:00 GMT [KW, RP]
* # Blocks-13.0.0.txt
* # Date: 2019-07-10, 19:06:00 GMT [KW]
* # IndicSyllabicCategory-14.0.0.txt
* # Date: 2021-05-22, 01:01:00 GMT [KW, RP]
* # IndicPositionalCategory-14.0.0.txt
* # Date: 2021-05-22, 01:01:00 GMT [KW, RP]
* # Blocks-14.0.0.txt
* # Date: 2021-01-22, 23:29:00 GMT [KW]
*/
#include "hb.hh"
@ -27,9 +27,9 @@
#define ISC_Bi INDIC_SYLLABIC_CATEGORY_BINDU /* 91 chars; Bindu */
#define ISC_BJN INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER /* 20 chars; Brahmi_Joining_Number */
#define ISC_Ca INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK /* 59 chars; Cantillation_Mark */
#define ISC_C INDIC_SYLLABIC_CATEGORY_CONSONANT /* 2195 chars; Consonant */
#define ISC_CD INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD /* 12 chars; Consonant_Dead */
#define ISC_CF INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL /* 67 chars; Consonant_Final */
#define ISC_C INDIC_SYLLABIC_CATEGORY_CONSONANT /* 2206 chars; Consonant */
#define ISC_CD INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD /* 14 chars; Consonant_Dead */
#define ISC_CF INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL /* 70 chars; Consonant_Final */
#define ISC_CHL INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER /* 5 chars; Consonant_Head_Letter */
#define ISC_CIP INDIC_SYLLABIC_CATEGORY_CONSONANT_INITIAL_POSTFIXED /* 1 chars; Consonant_Initial_Postfixed */
#define ISC_CK INDIC_SYLLABIC_CATEGORY_CONSONANT_KILLER /* 2 chars; Consonant_Killer */
@ -38,18 +38,18 @@
#define ISC_CPR INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA /* 3 chars; Consonant_Preceding_Repha */
#define ISC_CPrf INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED /* 10 chars; Consonant_Prefixed */
#define ISC_CS INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED /* 94 chars; Consonant_Subjoined */
#define ISC_CSR INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA /* 4 chars; Consonant_Succeeding_Repha */
#define ISC_CSR INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA /* 1 chars; Consonant_Succeeding_Repha */
#define ISC_CWS INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER /* 8 chars; Consonant_With_Stacker */
#define ISC_GM INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK /* 3 chars; Gemination_Mark */
#define ISC_IS INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER /* 12 chars; Invisible_Stacker */
#define ISC_ZWJ INDIC_SYLLABIC_CATEGORY_JOINER /* 1 chars; Joiner */
#define ISC_ML INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER /* 1 chars; Modifying_Letter */
#define ISC_ZWNJ INDIC_SYLLABIC_CATEGORY_NON_JOINER /* 1 chars; Non_Joiner */
#define ISC_N INDIC_SYLLABIC_CATEGORY_NUKTA /* 31 chars; Nukta */
#define ISC_N INDIC_SYLLABIC_CATEGORY_NUKTA /* 32 chars; Nukta */
#define ISC_Nd INDIC_SYLLABIC_CATEGORY_NUMBER /* 491 chars; Number */
#define ISC_NJ INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER /* 1 chars; Number_Joiner */
#define ISC_x INDIC_SYLLABIC_CATEGORY_OTHER /* 1 chars; Other */
#define ISC_PK INDIC_SYLLABIC_CATEGORY_PURE_KILLER /* 23 chars; Pure_Killer */
#define ISC_PK INDIC_SYLLABIC_CATEGORY_PURE_KILLER /* 25 chars; Pure_Killer */
#define ISC_RS INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER /* 2 chars; Register_Shifter */
#define ISC_SM INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER /* 25 chars; Syllable_Modifier */
#define ISC_TL INDIC_SYLLABIC_CATEGORY_TONE_LETTER /* 7 chars; Tone_Letter */
@ -57,18 +57,18 @@
#define ISC_V INDIC_SYLLABIC_CATEGORY_VIRAMA /* 27 chars; Virama */
#define ISC_Vs INDIC_SYLLABIC_CATEGORY_VISARGA /* 35 chars; Visarga */
#define ISC_Vo INDIC_SYLLABIC_CATEGORY_VOWEL /* 30 chars; Vowel */
#define ISC_M INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT /* 683 chars; Vowel_Dependent */
#define ISC_VI INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT /* 484 chars; Vowel_Independent */
#define ISC_M INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT /* 686 chars; Vowel_Dependent */
#define ISC_VI INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT /* 486 chars; Vowel_Independent */
#define IMC_B INDIC_MATRA_CATEGORY_BOTTOM /* 351 chars; Bottom */
#define IMC_B INDIC_MATRA_CATEGORY_BOTTOM /* 352 chars; Bottom */
#define IMC_BL INDIC_MATRA_CATEGORY_BOTTOM_AND_LEFT /* 1 chars; Bottom_And_Left */
#define IMC_BR INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT /* 4 chars; Bottom_And_Right */
#define IMC_L INDIC_MATRA_CATEGORY_LEFT /* 64 chars; Left */
#define IMC_LR INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT /* 22 chars; Left_And_Right */
#define IMC_x INDIC_MATRA_CATEGORY_NOT_APPLICABLE /* 1 chars; Not_Applicable */
#define IMC_O INDIC_MATRA_CATEGORY_OVERSTRUCK /* 10 chars; Overstruck */
#define IMC_R INDIC_MATRA_CATEGORY_RIGHT /* 288 chars; Right */
#define IMC_T INDIC_MATRA_CATEGORY_TOP /* 415 chars; Top */
#define IMC_R INDIC_MATRA_CATEGORY_RIGHT /* 290 chars; Right */
#define IMC_T INDIC_MATRA_CATEGORY_TOP /* 418 chars; Top */
#define IMC_TB INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM /* 10 chars; Top_And_Bottom */
#define IMC_TBL INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_LEFT /* 2 chars; Top_And_Bottom_And_Left */
#define IMC_TBR INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT /* 1 chars; Top_And_Bottom_And_Right */
@ -231,11 +231,11 @@ static const uint16_t indic_table[] = {
/* 0C20 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0C28 */ _(C,x), _(x,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0C30 */ _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x), _(C,x),
/* 0C38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(A,x), _(M,T), _(M,T),
/* 0C38 */ _(C,x), _(C,x), _(x,x), _(x,x), _(N,B), _(A,x), _(M,T), _(M,T),
/* 0C40 */ _(M,T), _(M,R), _(M,R), _(M,R), _(M,R), _(x,x), _(M,T), _(M,T),
/* 0C48 */ _(M,TB), _(x,x), _(M,T), _(M,T), _(M,T), _(V,T), _(x,x), _(x,x),
/* 0C50 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,T), _(M,B), _(x,x),
/* 0C58 */ _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
/* 0C58 */ _(C,x), _(C,x), _(C,x), _(x,x), _(x,x), _(CD,x), _(x,x), _(x,x),
/* 0C60 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
/* 0C68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 0C70 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
@ -254,7 +254,7 @@ static const uint16_t indic_table[] = {
/* 0CC0 */ _(M,TR), _(M,R), _(M,R), _(M,R), _(M,R), _(x,x), _(M,T), _(M,TR),
/* 0CC8 */ _(M,TR), _(x,x), _(M,TR), _(M,TR), _(M,T), _(V,T), _(x,x), _(x,x),
/* 0CD0 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(M,R), _(M,R), _(x,x),
/* 0CD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(C,x), _(x,x),
/* 0CD8 */ _(x,x), _(x,x), _(x,x), _(x,x), _(x,x), _(CD,x), _(C,x), _(x,x),
/* 0CE0 */ _(VI,x), _(VI,x), _(M,B), _(M,B), _(x,x), _(x,x), _(Nd,x), _(Nd,x),
/* 0CE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
/* 0CF0 */ _(x,x),_(CWS,x),_(CWS,x), _(x,x), _(x,x), _(x,x), _(x,x), _(x,x),
@ -402,7 +402,7 @@ static const uint16_t indic_table[] = {
/* AA70 */ _(x,x), _(C,x), _(C,x), _(C,x), _(CP,x), _(CP,x), _(CP,x), _(x,x),
/* AA78 */ _(x,x), _(x,x), _(C,x), _(TM,R), _(TM,T), _(TM,R), _(C,x), _(C,x),
}; /* Table items: 1792; occupancy: 70% */
}; /* Table items: 1792; occupancy: 71% */
uint16_t
hb_indic_get_categories (hb_codepoint_t u)

View File

@ -106,7 +106,8 @@ indic_features[] =
{
/*
* Basic features.
* These features are applied in order, one at a time, after initial_reordering.
* These features are applied in order, one at a time, after initial_reordering,
* constrained to the syllable.
*/
{HB_TAG('n','u','k','t'), F_GLOBAL_MANUAL_JOINERS},
{HB_TAG('a','k','h','n'), F_GLOBAL_MANUAL_JOINERS},
@ -121,8 +122,8 @@ indic_features[] =
{HB_TAG('c','j','c','t'), F_GLOBAL_MANUAL_JOINERS},
/*
* Other features.
* These features are applied all at once, after final_reordering
* but before clearing syllables.
* These features are applied all at once, after final_reordering, constrained
* to the syllable.
* Default Bengali font in Windows for example has intermixed
* lookups for init,pres,abvs,blws features.
*/
@ -257,7 +258,7 @@ struct indic_shape_plan_t
static void *
data_create_indic (const hb_ot_shape_plan_t *plan)
{
indic_shape_plan_t *indic_plan = (indic_shape_plan_t *) calloc (1, sizeof (indic_shape_plan_t));
indic_shape_plan_t *indic_plan = (indic_shape_plan_t *) hb_calloc (1, sizeof (indic_shape_plan_t));
if (unlikely (!indic_plan))
return nullptr;
@ -300,7 +301,7 @@ data_create_indic (const hb_ot_shape_plan_t *plan)
static void
data_destroy_indic (void *data)
{
free (data);
hb_free (data);
}
static indic_position_t
@ -960,7 +961,8 @@ initial_reordering_indic (const hb_ot_shape_plan_t *plan,
hb_syllabic_insert_dotted_circles (font, buffer,
indic_broken_cluster,
OT_DOTTEDCIRCLE,
OT_Repha);
OT_Repha,
POS_END);
foreach_syllable (buffer, start, end)
initial_reordering_syllable_indic (plan, font->face, buffer, start, end);

View File

@ -1,29 +1,30 @@
#line 1 "hb-ot-shape-complex-khmer-machine.rl"
/*
* Copyright © 2011,2012 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
*/
* Copyright © 2011,2012 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_SHAPE_COMPLEX_KHMER_MACHINE_HH
#define HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH
@ -31,13 +32,13 @@
#include "hb.hh"
enum khmer_syllable_type_t {
khmer_consonant_syllable,
khmer_broken_cluster,
khmer_non_khmer_cluster,
khmer_consonant_syllable,
khmer_broken_cluster,
khmer_non_khmer_cluster,
};
#line 41 "hb-ot-shape-complex-khmer-machine.hh"
#line 42 "hb-ot-shape-complex-khmer-machine.hh"
#define khmer_syllable_machine_ex_C 1u
#define khmer_syllable_machine_ex_Coeng 14u
#define khmer_syllable_machine_ex_DOTTEDCIRCLE 12u
@ -55,125 +56,180 @@ enum khmer_syllable_type_t {
#define khmer_syllable_machine_ex_ZWNJ 5u
#line 59 "hb-ot-shape-complex-khmer-machine.hh"
#line 60 "hb-ot-shape-complex-khmer-machine.hh"
static const unsigned char _khmer_syllable_machine_trans_keys[] = {
2u, 8u, 2u, 6u, 2u, 8u, 2u, 6u,
0u, 0u, 2u, 6u, 2u, 8u, 2u, 6u,
2u, 8u, 2u, 6u, 2u, 6u, 2u, 8u,
2u, 6u, 0u, 0u, 2u, 6u, 2u, 8u,
2u, 6u, 2u, 8u, 2u, 6u, 2u, 8u,
0u, 11u, 2u, 11u, 2u, 11u, 2u, 11u,
7u, 7u, 2u, 7u, 2u, 11u, 2u, 11u,
2u, 11u, 0u, 0u, 2u, 8u, 2u, 11u,
2u, 11u, 7u, 7u, 2u, 7u, 2u, 11u,
2u, 11u, 0u, 0u, 2u, 11u, 2u, 11u,
0u
5u, 26u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u, 5u, 21u,
5u, 26u, 5u, 21u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u,
5u, 21u, 5u, 26u, 5u, 21u, 5u, 26u, 1u, 29u, 5u, 29u, 5u, 29u, 5u, 29u,
22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 5u, 29u, 1u, 16u, 5u, 26u, 5u, 29u,
5u, 29u, 22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 1u, 16u, 5u, 29u, 5u, 29u,
0
};
static const signed char _khmer_syllable_machine_char_class[] = {
0, 0, 1, 1, 2, 2, 1, 1,
1, 1, 3, 3, 1, 4, 1, 0,
1, 1, 1, 5, 6, 7, 1, 1,
1, 8, 9, 10, 11, 0
static const char _khmer_syllable_machine_key_spans[] = {
22, 17, 22, 17, 16, 17, 22, 17,
22, 17, 17, 22, 17, 16, 17, 22,
17, 22, 17, 22, 29, 25, 25, 25,
1, 18, 25, 25, 25, 16, 22, 25,
25, 1, 18, 25, 25, 16, 25, 25
};
static const short _khmer_syllable_machine_index_offsets[] = {
0, 7, 12, 19, 24, 25, 30, 37,
42, 49, 54, 59, 66, 71, 72, 77,
84, 89, 96, 101, 108, 120, 130, 140,
150, 151, 157, 167, 177, 187, 188, 195,
205, 215, 216, 222, 232, 242, 243, 253,
0
0, 23, 41, 64, 82, 99, 117, 140,
158, 181, 199, 217, 240, 258, 275, 293,
316, 334, 357, 375, 398, 428, 454, 480,
506, 508, 527, 553, 579, 605, 622, 645,
671, 697, 699, 718, 744, 770, 787, 813
};
static const signed char _khmer_syllable_machine_indicies[] = {
1, 0, 0, 2, 3, 0, 4, 1,
0, 0, 0, 3, 1, 0, 0, 0,
3, 0, 4, 5, 0, 0, 0, 4,
6, 7, 0, 0, 0, 8, 9, 0,
0, 0, 10, 0, 4, 9, 0, 0,
0, 10, 11, 0, 0, 0, 12, 0,
4, 11, 0, 0, 0, 12, 14, 13,
13, 13, 15, 14, 16, 16, 16, 15,
16, 17, 18, 16, 16, 16, 17, 19,
20, 16, 16, 16, 21, 22, 16, 16,
16, 23, 16, 17, 22, 16, 16, 16,
23, 24, 16, 16, 16, 25, 16, 17,
24, 16, 16, 16, 25, 14, 16, 16,
26, 15, 16, 17, 29, 28, 30, 2,
31, 28, 15, 19, 17, 23, 25, 21,
33, 32, 34, 2, 3, 6, 4, 10,
12, 8, 35, 32, 36, 32, 3, 6,
4, 10, 12, 8, 5, 32, 36, 32,
4, 6, 32, 32, 32, 8, 6, 7,
32, 36, 32, 8, 6, 37, 32, 36,
32, 10, 6, 4, 32, 32, 8, 38,
32, 36, 32, 12, 6, 4, 10, 32,
8, 35, 32, 34, 32, 3, 6, 4,
10, 12, 8, 29, 14, 39, 39, 39,
15, 39, 17, 41, 40, 42, 40, 15,
19, 17, 23, 25, 21, 18, 40, 42,
40, 17, 19, 40, 40, 40, 21, 19,
20, 40, 42, 40, 21, 19, 43, 40,
42, 40, 23, 19, 17, 40, 40, 21,
44, 40, 42, 40, 25, 19, 17, 23,
40, 21, 45, 46, 40, 31, 26, 15,
19, 17, 23, 25, 21, 41, 40, 31,
40, 15, 19, 17, 23, 25, 21, 0
static const char _khmer_syllable_machine_indicies[] = {
1, 1, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 2,
3, 0, 0, 0, 0, 4, 0, 1,
1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 3,
0, 1, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 3, 0, 0, 0, 0, 4, 0,
5, 5, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
4, 0, 6, 6, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 6, 0, 7, 7, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 8, 0, 9, 9, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 10, 0, 0,
0, 0, 4, 0, 9, 9, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 10, 0, 11, 11,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 12, 0,
0, 0, 0, 4, 0, 11, 11, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 12, 0, 14,
14, 13, 13, 13, 13, 13, 13, 13,
13, 13, 13, 13, 13, 13, 13, 15,
13, 14, 14, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 15, 16, 16, 16, 16, 17, 16,
18, 18, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
17, 16, 19, 19, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 19, 16, 20, 20, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 21, 16, 22, 22, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 23, 16, 16,
16, 16, 17, 16, 22, 22, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 23, 16, 24, 24,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 25, 16,
16, 16, 16, 17, 16, 24, 24, 16,
16, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 25, 16, 14,
14, 16, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 26, 15,
16, 16, 16, 16, 17, 16, 28, 28,
27, 27, 29, 29, 27, 27, 27, 27,
2, 2, 27, 30, 27, 28, 27, 27,
27, 27, 15, 19, 27, 27, 27, 17,
23, 25, 21, 27, 32, 32, 31, 31,
31, 31, 31, 31, 31, 33, 31, 31,
31, 31, 31, 2, 3, 6, 31, 31,
31, 4, 10, 12, 8, 31, 34, 34,
31, 31, 31, 31, 31, 31, 31, 35,
31, 31, 31, 31, 31, 31, 3, 6,
31, 31, 31, 4, 10, 12, 8, 31,
5, 5, 31, 31, 31, 31, 31, 31,
31, 35, 31, 31, 31, 31, 31, 31,
4, 6, 31, 31, 31, 31, 31, 31,
8, 31, 6, 31, 7, 7, 31, 31,
31, 31, 31, 31, 31, 35, 31, 31,
31, 31, 31, 31, 8, 6, 31, 36,
36, 31, 31, 31, 31, 31, 31, 31,
35, 31, 31, 31, 31, 31, 31, 10,
6, 31, 31, 31, 4, 31, 31, 8,
31, 37, 37, 31, 31, 31, 31, 31,
31, 31, 35, 31, 31, 31, 31, 31,
31, 12, 6, 31, 31, 31, 4, 10,
31, 8, 31, 34, 34, 31, 31, 31,
31, 31, 31, 31, 33, 31, 31, 31,
31, 31, 31, 3, 6, 31, 31, 31,
4, 10, 12, 8, 31, 28, 28, 31,
31, 31, 31, 31, 31, 31, 31, 31,
31, 31, 31, 31, 28, 31, 14, 14,
38, 38, 38, 38, 38, 38, 38, 38,
38, 38, 38, 38, 38, 38, 15, 38,
38, 38, 38, 17, 38, 40, 40, 39,
39, 39, 39, 39, 39, 39, 41, 39,
39, 39, 39, 39, 39, 15, 19, 39,
39, 39, 17, 23, 25, 21, 39, 18,
18, 39, 39, 39, 39, 39, 39, 39,
41, 39, 39, 39, 39, 39, 39, 17,
19, 39, 39, 39, 39, 39, 39, 21,
39, 19, 39, 20, 20, 39, 39, 39,
39, 39, 39, 39, 41, 39, 39, 39,
39, 39, 39, 21, 19, 39, 42, 42,
39, 39, 39, 39, 39, 39, 39, 41,
39, 39, 39, 39, 39, 39, 23, 19,
39, 39, 39, 17, 39, 39, 21, 39,
43, 43, 39, 39, 39, 39, 39, 39,
39, 41, 39, 39, 39, 39, 39, 39,
25, 19, 39, 39, 39, 17, 23, 39,
21, 39, 44, 44, 39, 39, 39, 39,
39, 39, 39, 39, 39, 39, 39, 39,
39, 44, 39, 45, 45, 39, 39, 39,
39, 39, 39, 39, 30, 39, 39, 39,
39, 39, 26, 15, 19, 39, 39, 39,
17, 23, 25, 21, 39, 40, 40, 39,
39, 39, 39, 39, 39, 39, 30, 39,
39, 39, 39, 39, 39, 15, 19, 39,
39, 39, 17, 23, 25, 21, 39, 0
};
static const signed char _khmer_syllable_machine_index_defaults[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 13, 16, 16, 16, 16, 16,
16, 16, 16, 16, 28, 32, 32, 32,
32, 32, 32, 32, 32, 32, 39, 40,
40, 40, 40, 40, 40, 40, 40, 40,
0
static const char _khmer_syllable_machine_trans_targs[] = {
20, 1, 28, 22, 23, 3, 24, 5,
25, 7, 26, 9, 27, 20, 10, 31,
20, 32, 12, 33, 14, 34, 16, 35,
18, 36, 39, 20, 21, 30, 37, 20,
0, 29, 2, 4, 6, 8, 20, 20,
11, 13, 15, 17, 38, 19
};
static const signed char _khmer_syllable_machine_cond_targs[] = {
20, 1, 28, 22, 23, 3, 24, 5,
25, 7, 26, 9, 27, 20, 10, 31,
20, 32, 12, 33, 14, 34, 16, 35,
18, 36, 39, 20, 20, 21, 30, 37,
20, 0, 29, 2, 4, 6, 8, 20,
20, 11, 13, 15, 17, 38, 19, 0
static const char _khmer_syllable_machine_trans_actions[] = {
1, 0, 2, 2, 2, 0, 0, 0,
2, 0, 2, 0, 2, 3, 0, 4,
5, 2, 0, 0, 0, 2, 0, 2,
0, 2, 4, 8, 2, 9, 0, 10,
0, 0, 0, 0, 0, 0, 11, 12,
0, 0, 0, 0, 4, 0
};
static const signed char _khmer_syllable_machine_cond_actions[] = {
1, 0, 2, 2, 2, 0, 0, 0,
2, 0, 2, 0, 2, 3, 0, 4,
5, 2, 0, 0, 0, 2, 0, 2,
0, 2, 4, 0, 8, 2, 9, 0,
10, 0, 0, 0, 0, 0, 0, 11,
12, 0, 0, 0, 0, 4, 0, 0
static const char _khmer_syllable_machine_to_state_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 6, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
static const signed char _khmer_syllable_machine_to_state_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 6, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0
static const char _khmer_syllable_machine_from_state_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 7, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
static const signed char _khmer_syllable_machine_from_state_actions[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 7, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0
};
static const signed char _khmer_syllable_machine_eof_trans[] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 14, 17, 17, 17, 17, 17,
17, 17, 17, 17, 28, 33, 33, 33,
33, 33, 33, 33, 33, 33, 40, 41,
41, 41, 41, 41, 41, 41, 41, 41,
0
static const unsigned char _khmer_syllable_machine_eof_trans[] = {
1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 14, 17, 17, 17, 17, 17,
17, 17, 17, 17, 0, 32, 32, 32,
32, 32, 32, 32, 32, 32, 39, 40,
40, 40, 40, 40, 40, 40, 40, 40
};
static const int khmer_syllable_machine_start = 20;
@ -191,263 +247,148 @@ static const int khmer_syllable_machine_en_main = 20;
#define found_syllable(syllable_type) \
HB_STMT_START { \
if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
for (unsigned int i = ts; i < te; i++) \
info[i].syllable() = (syllable_serial << 4) | syllable_type; \
syllable_serial++; \
if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
} HB_STMT_END
HB_STMT_START { \
if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
for (unsigned int i = ts; i < te; i++) \
info[i].syllable() = (syllable_serial << 4) | syllable_type; \
syllable_serial++; \
if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
} HB_STMT_END
static void
find_syllables_khmer (hb_buffer_t *buffer)
{
unsigned int p, pe, eof, ts, te, act HB_UNUSED;
int cs;
hb_glyph_info_t *info = buffer->info;
#line 210 "hb-ot-shape-complex-khmer-machine.hh"
unsigned int p, pe, eof, ts, te, act HB_UNUSED;
int cs;
hb_glyph_info_t *info = buffer->info;
#line 266 "hb-ot-shape-complex-khmer-machine.hh"
{
cs = (int)khmer_syllable_machine_start;
ts = 0;
te = 0;
act = 0;
cs = khmer_syllable_machine_start;
ts = 0;
te = 0;
act = 0;
}
#line 106 "hb-ot-shape-complex-khmer-machine.rl"
p = 0;
pe = eof = buffer->len;
unsigned int syllable_serial = 1;
#line 226 "hb-ot-shape-complex-khmer-machine.hh"
p = 0;
pe = eof = buffer->len;
unsigned int syllable_serial = 1;
#line 282 "hb-ot-shape-complex-khmer-machine.hh"
{
unsigned int _trans = 0;
const unsigned char * _keys;
const signed char * _inds;
int _ic;
_resume: {}
if ( p == pe && p != eof )
goto _out;
switch ( _khmer_syllable_machine_from_state_actions[cs] ) {
case 7: {
{
int _slen;
int _trans;
const unsigned char *_keys;
const char *_inds;
if ( p == pe )
goto _test_eof;
_resume:
switch ( _khmer_syllable_machine_from_state_actions[cs] ) {
case 7:
#line 1 "NONE"
{ts = p;}}
#line 241 "hb-ot-shape-complex-khmer-machine.hh"
break;
}
}
if ( p == eof ) {
if ( _khmer_syllable_machine_eof_trans[cs] > 0 ) {
_trans = (unsigned int)_khmer_syllable_machine_eof_trans[cs] - 1;
}
}
else {
_keys = ( _khmer_syllable_machine_trans_keys + ((cs<<1)));
_inds = ( _khmer_syllable_machine_indicies + (_khmer_syllable_machine_index_offsets[cs]));
if ( (info[p].khmer_category()) <= 29 && (info[p].khmer_category()) >= 1 ) {
_ic = (int)_khmer_syllable_machine_char_class[(int)(info[p].khmer_category()) - 1];
if ( _ic <= (int)(*( _keys+1)) && _ic >= (int)(*( _keys)) )
_trans = (unsigned int)(*( _inds + (int)( _ic - (int)(*( _keys)) ) ));
else
_trans = (unsigned int)_khmer_syllable_machine_index_defaults[cs];
}
else {
_trans = (unsigned int)_khmer_syllable_machine_index_defaults[cs];
}
}
cs = (int)_khmer_syllable_machine_cond_targs[_trans];
if ( _khmer_syllable_machine_cond_actions[_trans] != 0 ) {
switch ( _khmer_syllable_machine_cond_actions[_trans] ) {
case 2: {
{
#line 1 "NONE"
{te = p+1;}}
#line 279 "hb-ot-shape-complex-khmer-machine.hh"
break;
}
case 8: {
{
#line 82 "hb-ot-shape-complex-khmer-machine.rl"
{te = p+1;{
#line 82 "hb-ot-shape-complex-khmer-machine.rl"
found_syllable (khmer_non_khmer_cluster); }
}}
#line 292 "hb-ot-shape-complex-khmer-machine.hh"
break;
}
case 10: {
{
#line 80 "hb-ot-shape-complex-khmer-machine.rl"
{te = p;p = p - 1;{
#line 80 "hb-ot-shape-complex-khmer-machine.rl"
found_syllable (khmer_consonant_syllable); }
}}
#line 305 "hb-ot-shape-complex-khmer-machine.hh"
break;
}
case 12: {
{
#line 81 "hb-ot-shape-complex-khmer-machine.rl"
{te = p;p = p - 1;{
#line 81 "hb-ot-shape-complex-khmer-machine.rl"
found_syllable (khmer_broken_cluster); }
}}
#line 318 "hb-ot-shape-complex-khmer-machine.hh"
break;
}
case 11: {
{
#line 82 "hb-ot-shape-complex-khmer-machine.rl"
{te = p;p = p - 1;{
#line 82 "hb-ot-shape-complex-khmer-machine.rl"
found_syllable (khmer_non_khmer_cluster); }
}}
#line 331 "hb-ot-shape-complex-khmer-machine.hh"
break;
}
case 1: {
{
#line 80 "hb-ot-shape-complex-khmer-machine.rl"
{p = ((te))-1;
{
#line 80 "hb-ot-shape-complex-khmer-machine.rl"
found_syllable (khmer_consonant_syllable); }
}}
#line 345 "hb-ot-shape-complex-khmer-machine.hh"
break;
}
case 5: {
{
#line 81 "hb-ot-shape-complex-khmer-machine.rl"
{p = ((te))-1;
{
#line 81 "hb-ot-shape-complex-khmer-machine.rl"
found_syllable (khmer_broken_cluster); }
}}
#line 359 "hb-ot-shape-complex-khmer-machine.hh"
break;
}
case 3: {
{
#line 1 "NONE"
{switch( act ) {
case 2: {
p = ((te))-1;
{
#line 81 "hb-ot-shape-complex-khmer-machine.rl"
found_syllable (khmer_broken_cluster); }
break;
}
case 3: {
p = ((te))-1;
{
#line 82 "hb-ot-shape-complex-khmer-machine.rl"
found_syllable (khmer_non_khmer_cluster); }
break;
}
}}
}
#line 385 "hb-ot-shape-complex-khmer-machine.hh"
break;
}
case 4: {
{
#line 1 "NONE"
{te = p+1;}}
#line 395 "hb-ot-shape-complex-khmer-machine.hh"
{
#line 81 "hb-ot-shape-complex-khmer-machine.rl"
{act = 2;}}
#line 401 "hb-ot-shape-complex-khmer-machine.hh"
break;
}
case 9: {
{
#line 1 "NONE"
{te = p+1;}}
#line 411 "hb-ot-shape-complex-khmer-machine.hh"
{
#line 82 "hb-ot-shape-complex-khmer-machine.rl"
{act = 3;}}
#line 417 "hb-ot-shape-complex-khmer-machine.hh"
break;
}
}
}
if ( p == eof ) {
if ( cs >= 20 )
goto _out;
}
else {
switch ( _khmer_syllable_machine_to_state_actions[cs] ) {
case 6: {
{
#line 1 "NONE"
{ts = 0;}}
#line 437 "hb-ot-shape-complex-khmer-machine.hh"
break;
}
}
p += 1;
goto _resume;
}
_out: {}
{ts = p;}
break;
#line 296 "hb-ot-shape-complex-khmer-machine.hh"
}
_keys = _khmer_syllable_machine_trans_keys + (cs<<1);
_inds = _khmer_syllable_machine_indicies + _khmer_syllable_machine_index_offsets[cs];
_slen = _khmer_syllable_machine_key_spans[cs];
_trans = _inds[ _slen > 0 && _keys[0] <=( info[p].khmer_category()) &&
( info[p].khmer_category()) <= _keys[1] ?
( info[p].khmer_category()) - _keys[0] : _slen ];
_eof_trans:
cs = _khmer_syllable_machine_trans_targs[_trans];
if ( _khmer_syllable_machine_trans_actions[_trans] == 0 )
goto _again;
switch ( _khmer_syllable_machine_trans_actions[_trans] ) {
case 2:
#line 1 "NONE"
{te = p+1;}
break;
case 8:
#line 82 "hb-ot-shape-complex-khmer-machine.rl"
{te = p+1;{ found_syllable (khmer_non_khmer_cluster); }}
break;
case 10:
#line 80 "hb-ot-shape-complex-khmer-machine.rl"
{te = p;p--;{ found_syllable (khmer_consonant_syllable); }}
break;
case 12:
#line 81 "hb-ot-shape-complex-khmer-machine.rl"
{te = p;p--;{ found_syllable (khmer_broken_cluster); }}
break;
case 11:
#line 82 "hb-ot-shape-complex-khmer-machine.rl"
{te = p;p--;{ found_syllable (khmer_non_khmer_cluster); }}
break;
case 1:
#line 80 "hb-ot-shape-complex-khmer-machine.rl"
{{p = ((te))-1;}{ found_syllable (khmer_consonant_syllable); }}
break;
case 5:
#line 81 "hb-ot-shape-complex-khmer-machine.rl"
{{p = ((te))-1;}{ found_syllable (khmer_broken_cluster); }}
break;
case 3:
#line 1 "NONE"
{ switch( act ) {
case 2:
{{p = ((te))-1;} found_syllable (khmer_broken_cluster); }
break;
case 3:
{{p = ((te))-1;} found_syllable (khmer_non_khmer_cluster); }
break;
}
}
break;
case 4:
#line 1 "NONE"
{te = p+1;}
#line 81 "hb-ot-shape-complex-khmer-machine.rl"
{act = 2;}
break;
case 9:
#line 1 "NONE"
{te = p+1;}
#line 82 "hb-ot-shape-complex-khmer-machine.rl"
{act = 3;}
break;
#line 366 "hb-ot-shape-complex-khmer-machine.hh"
}
_again:
switch ( _khmer_syllable_machine_to_state_actions[cs] ) {
case 6:
#line 1 "NONE"
{ts = 0;}
break;
#line 375 "hb-ot-shape-complex-khmer-machine.hh"
}
if ( ++p != pe )
goto _resume;
_test_eof: {}
if ( p == eof )
{
if ( _khmer_syllable_machine_eof_trans[cs] > 0 ) {
_trans = _khmer_syllable_machine_eof_trans[cs] - 1;
goto _eof_trans;
}
}
}
#line 114 "hb-ot-shape-complex-khmer-machine.rl"
}
#undef found_syllable

Some files were not shown because too many files have changed in this diff Show More