mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 12:09:14 +00:00
8247872: Upgrade HarfBuzz to the latest 2.7.2
Reviewed-by: serb
This commit is contained in:
parent
6a183fbbc3
commit
ed7526a66c
@ -435,7 +435,6 @@ endif
|
||||
ifeq ($(USE_EXTERNAL_HARFBUZZ), true)
|
||||
LIBHARFBUZZ_LIBS := $(HARFBUZZ_LIBS)
|
||||
else
|
||||
HARFBUZZ_CFLAGS := -DHAVE_OT -DHAVE_FALLBACK -DHAVE_UCDN -DHAVE_ROUND
|
||||
|
||||
# This is better than adding EXPORT_ALL_SYMBOLS
|
||||
ifneq ($(filter $(TOOLCHAIN_TYPE), gcc clang), )
|
||||
@ -493,7 +492,7 @@ else
|
||||
maybe-uninitialized class-memaccess, \
|
||||
DISABLED_WARNINGS_clang := unused-value incompatible-pointer-types \
|
||||
tautological-constant-out-of-range-compare int-to-pointer-cast \
|
||||
undef missing-field-initializers, \
|
||||
undef missing-field-initializers range-loop-analysis, \
|
||||
DISABLED_WARNINGS_microsoft := 4267 4244 4090 4146 4334 4819 4101 4068 4805 4138, \
|
||||
LDFLAGS := $(LDFLAGS_JDKLIB) \
|
||||
$(call SET_SHARED_LIBRARY_ORIGIN), \
|
||||
|
||||
@ -1,16 +1,18 @@
|
||||
## Harfbuzz v2.3.1
|
||||
## Harfbuzz v2.7.2
|
||||
|
||||
### Harfbuzz License
|
||||
|
||||
http://cgit.freedesktop.org/harfbuzz/tree/COPYING
|
||||
https://github.com/harfbuzz/harfbuzz/blob/master/COPYING
|
||||
|
||||
<pre>
|
||||
|
||||
HarfBuzz is licensed under the so-called "Old MIT" license. Details follow.
|
||||
HarfBuzz is licensed under the so-called "Old MIT" license. Details follow.
|
||||
For parts of HarfBuzz that are licensed under different licenses see individual
|
||||
files names COPYING in subdirectories where applicable.
|
||||
|
||||
Copyright © 2010,2011,2012 Google, Inc.
|
||||
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 © 2012 Mozilla Foundation
|
||||
Copyright © 2011 Codethink Limited
|
||||
Copyright © 2008,2010 Nokia Corporation and/or its subsidiary(-ies)
|
||||
|
||||
@ -1,126 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2018 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#ifndef HB_AAT_FDSC_TABLE_HH
|
||||
#define HB_AAT_FDSC_TABLE_HH
|
||||
|
||||
#include "hb-aat-layout-common.hh"
|
||||
#include "hb-open-type.hh"
|
||||
|
||||
/*
|
||||
* fdsc -- Font descriptors
|
||||
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6fdsc.html
|
||||
*/
|
||||
#define HB_AAT_TAG_fdsc HB_TAG('f','d','s','c')
|
||||
|
||||
|
||||
namespace AAT {
|
||||
|
||||
|
||||
struct FontDescriptor
|
||||
{
|
||||
bool has_data () const { return tag; }
|
||||
|
||||
int cmp (hb_tag_t a) const { return tag.cmp (a); }
|
||||
|
||||
float get_value () const { return u.value.to_float (); }
|
||||
|
||||
enum non_alphabetic_value_t {
|
||||
Alphabetic = 0,
|
||||
Dingbats = 1,
|
||||
PiCharacters = 2,
|
||||
Fleurons = 3,
|
||||
DecorativeBorders = 4,
|
||||
InternationalSymbols= 5,
|
||||
MathSymbols = 6
|
||||
};
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this));
|
||||
}
|
||||
|
||||
protected:
|
||||
Tag tag; /* The 4-byte table tag name. */
|
||||
union {
|
||||
Fixed value; /* The value for the descriptor tag. */
|
||||
HBUINT32 nalfType; /* If the tag is `nalf`, see non_alphabetic_value_t */
|
||||
} u;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (8);
|
||||
};
|
||||
|
||||
struct fdsc
|
||||
{
|
||||
static constexpr hb_tag_t tableTag = HB_AAT_TAG_fdsc;
|
||||
|
||||
enum {
|
||||
Weight = HB_TAG ('w','g','h','t'),
|
||||
/* Percent weight relative to regular weight.
|
||||
* (defaul value: 1.0) */
|
||||
Width = HB_TAG ('w','d','t','h'),
|
||||
/* Percent width relative to regular width.
|
||||
* (default value: 1.0) */
|
||||
Slant = HB_TAG ('s','l','n','t'),
|
||||
/* Angle of slant in degrees, where positive
|
||||
* is clockwise from straight up.
|
||||
* (default value: 0.0) */
|
||||
OpticalSize = HB_TAG ('o','p','s','z'),
|
||||
/* Point size the font was designed for.
|
||||
* (default value: 12.0) */
|
||||
NonAlphabetic= HB_TAG ('n','a','l','f')
|
||||
/* These values are treated as integers,
|
||||
* not fixed32s. 0 means alphabetic, and greater
|
||||
* integers mean the font is non-alphabetic (e.g. symbols).
|
||||
* (default value: 0) */
|
||||
};
|
||||
|
||||
const FontDescriptor &get_descriptor (hb_tag_t style) const
|
||||
{ return descriptors.lsearch (style); }
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
descriptors.sanitize (c));
|
||||
}
|
||||
|
||||
protected:
|
||||
Fixed version; /* Version number of the font descriptors
|
||||
* table (0x00010000 for the current version). */
|
||||
LArrayOf<FontDescriptor>
|
||||
descriptors; /* List of tagged-coordinate pairs style descriptors
|
||||
* that will be included to characterize this font.
|
||||
* Each descriptor consists of a <tag, value> pair.
|
||||
* These pairs are located in the gxFontDescriptor
|
||||
* array that follows. */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (8, descriptors);
|
||||
};
|
||||
|
||||
} /* namespace AAT */
|
||||
|
||||
|
||||
#endif /* HB_AAT_FDSC_TABLE_HH */
|
||||
@ -66,7 +66,7 @@ struct ankr
|
||||
{
|
||||
const NNOffsetTo<GlyphAnchors> *offset = (this+lookupTable).get_value (glyph_id, num_glyphs);
|
||||
if (!offset)
|
||||
return Null(Anchor);
|
||||
return Null (Anchor);
|
||||
const GlyphAnchors &anchors = &(this+anchorData) + *offset;
|
||||
return anchors[i];
|
||||
}
|
||||
@ -76,13 +76,14 @@ struct ankr
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
version == 0 &&
|
||||
c->check_range (this, anchorData) &&
|
||||
lookupTable.sanitize (c, this, &(this+anchorData))));
|
||||
}
|
||||
|
||||
protected:
|
||||
HBUINT16 version; /* Version number (set to zero) */
|
||||
HBUINT16 flags; /* Flags (currently unused; set to zero) */
|
||||
LOffsetTo<Lookup<NNOffsetTo<GlyphAnchors> > >
|
||||
LOffsetTo<Lookup<NNOffsetTo<GlyphAnchors>>>
|
||||
lookupTable; /* Offset to the table's lookup table */
|
||||
LNNOffsetTo<HBUINT8>
|
||||
anchorData; /* Offset to the glyph data table */
|
||||
|
||||
@ -82,7 +82,7 @@ struct BaselineTableFormat2Part
|
||||
}
|
||||
|
||||
protected:
|
||||
GlyphID stdGlyph; /* The specific glyph index number in this
|
||||
HBGlyphID stdGlyph; /* The specific glyph index number in this
|
||||
* font that is used to set the baseline values.
|
||||
* This is the standard glyph.
|
||||
* This glyph must contain a set of control points
|
||||
@ -101,11 +101,11 @@ struct BaselineTableFormat3Part
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) && lookupTable.sanitize (c));
|
||||
return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c)));
|
||||
}
|
||||
|
||||
protected:
|
||||
GlyphID stdGlyph; /* ditto */
|
||||
HBGlyphID stdGlyph; /* ditto */
|
||||
HBUINT16 ctlPoints[32]; /* ditto */
|
||||
Lookup<HBUINT16>
|
||||
lookupTable; /* Lookup table that maps glyphs to their
|
||||
|
||||
@ -93,8 +93,8 @@ struct LookupSegmentSingle
|
||||
return_trace (c->check_struct (this) && value.sanitize (c, base));
|
||||
}
|
||||
|
||||
GlyphID last; /* Last GlyphID in this segment */
|
||||
GlyphID first; /* First GlyphID in this segment */
|
||||
HBGlyphID last; /* Last GlyphID in this segment */
|
||||
HBGlyphID first; /* First GlyphID in this segment */
|
||||
T value; /* The lookup value (only one) */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (4 + T::static_size);
|
||||
@ -125,7 +125,7 @@ struct LookupFormat2
|
||||
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 2 */
|
||||
VarSizedBinSearchArrayOf<LookupSegmentSingle<T> >
|
||||
VarSizedBinSearchArrayOf<LookupSegmentSingle<T>>
|
||||
segments; /* The actual segments. These must already be sorted,
|
||||
* according to the first word in each one (the last
|
||||
* glyph in each segment). */
|
||||
@ -153,18 +153,18 @@ struct LookupSegmentArray
|
||||
first <= last &&
|
||||
valuesZ.sanitize (c, base, last - first + 1));
|
||||
}
|
||||
template <typename T2>
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base, T2 user_data) const
|
||||
template <typename ...Ts>
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
first <= last &&
|
||||
valuesZ.sanitize (c, base, last - first + 1, user_data));
|
||||
valuesZ.sanitize (c, base, last - first + 1, hb_forward<Ts> (ds)...));
|
||||
}
|
||||
|
||||
GlyphID last; /* Last GlyphID in this segment */
|
||||
GlyphID first; /* First GlyphID in this segment */
|
||||
NNOffsetTo<UnsizedArrayOf<T> >
|
||||
HBGlyphID last; /* Last GlyphID in this segment */
|
||||
HBGlyphID first; /* First GlyphID in this segment */
|
||||
NNOffsetTo<UnsizedArrayOf<T>>
|
||||
valuesZ; /* A 16-bit offset from the start of
|
||||
* the table to the data. */
|
||||
public:
|
||||
@ -196,7 +196,7 @@ struct LookupFormat4
|
||||
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 4 */
|
||||
VarSizedBinSearchArrayOf<LookupSegmentArray<T> >
|
||||
VarSizedBinSearchArrayOf<LookupSegmentArray<T>>
|
||||
segments; /* The actual segments. These must already be sorted,
|
||||
* according to the first word in each one (the last
|
||||
* glyph in each segment). */
|
||||
@ -222,7 +222,7 @@ struct LookupSingle
|
||||
return_trace (c->check_struct (this) && value.sanitize (c, base));
|
||||
}
|
||||
|
||||
GlyphID glyph; /* Last GlyphID */
|
||||
HBGlyphID glyph; /* Last GlyphID */
|
||||
T value; /* The lookup value (only one) */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (2 + T::static_size);
|
||||
@ -253,7 +253,7 @@ struct LookupFormat6
|
||||
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 6 */
|
||||
VarSizedBinSearchArrayOf<LookupSingle<T> >
|
||||
VarSizedBinSearchArrayOf<LookupSingle<T>>
|
||||
entries; /* The actual entries, sorted by glyph index. */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (8, entries);
|
||||
@ -284,7 +284,7 @@ struct LookupFormat8
|
||||
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 8 */
|
||||
GlyphID firstGlyph; /* First glyph index included in the trimmed array. */
|
||||
HBGlyphID firstGlyph; /* First glyph index included in the trimmed array. */
|
||||
HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last
|
||||
* glyph minus the value of firstGlyph plus 1). */
|
||||
UnsizedArrayOf<T>
|
||||
@ -303,7 +303,7 @@ struct LookupFormat10
|
||||
const typename T::type get_value_or_null (hb_codepoint_t glyph_id) const
|
||||
{
|
||||
if (!(firstGlyph <= glyph_id && glyph_id - firstGlyph < glyphCount))
|
||||
return Null(T);
|
||||
return Null (T);
|
||||
|
||||
const HBUINT8 *p = &valueArrayZ[(glyph_id - firstGlyph) * valueSize];
|
||||
|
||||
@ -326,7 +326,7 @@ struct LookupFormat10
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 8 */
|
||||
HBUINT16 valueSize; /* Byte size of each value. */
|
||||
GlyphID firstGlyph; /* First glyph index included in the trimmed array. */
|
||||
HBGlyphID firstGlyph; /* First glyph index included in the trimmed array. */
|
||||
HBUINT16 glyphCount; /* Total number of glyphs (equivalent to the last
|
||||
* glyph minus the value of firstGlyph plus 1). */
|
||||
UnsizedArrayOf<HBUINT8>
|
||||
@ -358,7 +358,7 @@ struct Lookup
|
||||
case 10: return u.format10.get_value_or_null (glyph_id);
|
||||
default:
|
||||
const T *v = get_value (glyph_id, num_glyphs);
|
||||
return v ? *v : Null(T);
|
||||
return v ? *v : Null (T);
|
||||
}
|
||||
}
|
||||
|
||||
@ -418,15 +418,11 @@ struct Lookup
|
||||
} /* Close namespace. */
|
||||
/* Ugly hand-coded null objects for template Lookup<> :(. */
|
||||
extern HB_INTERNAL const unsigned char _hb_Null_AAT_Lookup[2];
|
||||
template <>
|
||||
/*static*/ inline const AAT::Lookup<OT::HBUINT16>& Null<AAT::Lookup<OT::HBUINT16> > ()
|
||||
{ return *reinterpret_cast<const AAT::Lookup<OT::HBUINT16> *> (_hb_Null_AAT_Lookup); }
|
||||
template <>
|
||||
/*static*/ inline const AAT::Lookup<OT::HBUINT32>& Null<AAT::Lookup<OT::HBUINT32> > ()
|
||||
{ return *reinterpret_cast<const AAT::Lookup<OT::HBUINT32> *> (_hb_Null_AAT_Lookup); }
|
||||
template <>
|
||||
/*static*/ inline const AAT::Lookup<OT::Offset<OT::HBUINT16, false> >& Null<AAT::Lookup<OT::Offset<OT::HBUINT16, false> > > ()
|
||||
{ return *reinterpret_cast<const AAT::Lookup<OT::Offset<OT::HBUINT16, false> > *> (_hb_Null_AAT_Lookup); }
|
||||
template <typename T>
|
||||
struct Null<AAT::Lookup<T>> {
|
||||
static AAT::Lookup<T> const & get_null ()
|
||||
{ return *reinterpret_cast<const AAT::Lookup<T> *> (_hb_Null_AAT_Lookup); }
|
||||
};
|
||||
namespace AAT {
|
||||
|
||||
enum { DELETED_GLYPH = 0xFFFF };
|
||||
@ -514,7 +510,7 @@ struct StateTable
|
||||
const Entry<Extra> &get_entry (int state, unsigned int klass) const
|
||||
{
|
||||
if (unlikely (klass >= nClasses))
|
||||
klass = StateTable<Types, Entry<Extra> >::CLASS_OUT_OF_BOUNDS;
|
||||
klass = StateTable<Types, Entry<Extra>>::CLASS_OUT_OF_BOUNDS;
|
||||
|
||||
const HBUSHORT *states = (this+stateArrayTable).arrayZ;
|
||||
const Entry<Extra> *entries = (this+entryTable).arrayZ;
|
||||
@ -580,7 +576,7 @@ struct StateTable
|
||||
if (unlikely (stop > states))
|
||||
return_trace (false);
|
||||
for (const HBUSHORT *p = states; stop < p; p--)
|
||||
num_entries = MAX<unsigned int> (num_entries, *(p - 1) + 1);
|
||||
num_entries = hb_max (num_entries, *(p - 1) + 1);
|
||||
state_neg = min_state;
|
||||
}
|
||||
}
|
||||
@ -601,7 +597,7 @@ struct StateTable
|
||||
if (unlikely (stop < states))
|
||||
return_trace (false);
|
||||
for (const HBUSHORT *p = &states[state_pos * num_classes]; p < stop; p++)
|
||||
num_entries = MAX<unsigned int> (num_entries, *p + 1);
|
||||
num_entries = hb_max (num_entries, *p + 1);
|
||||
state_pos = max_state + 1;
|
||||
}
|
||||
}
|
||||
@ -615,8 +611,8 @@ struct StateTable
|
||||
for (const Entry<Extra> *p = &entries[entry]; p < stop; p++)
|
||||
{
|
||||
int newState = new_state (p->newState);
|
||||
min_state = MIN (min_state, newState);
|
||||
max_state = MAX (max_state, newState);
|
||||
min_state = hb_min (min_state, newState);
|
||||
max_state = hb_max (max_state, newState);
|
||||
}
|
||||
entry = num_entries;
|
||||
}
|
||||
@ -635,7 +631,7 @@ struct StateTable
|
||||
classTable; /* Offset to the class table. */
|
||||
NNOffsetTo<UnsizedArrayOf<HBUSHORT>, HBUINT>
|
||||
stateArrayTable;/* Offset to the state array. */
|
||||
NNOffsetTo<UnsizedArrayOf<Entry<Extra> >, HBUINT>
|
||||
NNOffsetTo<UnsizedArrayOf<Entry<Extra>>, HBUINT>
|
||||
entryTable; /* Offset to the entry array. */
|
||||
|
||||
public:
|
||||
@ -662,7 +658,7 @@ struct ClassTable
|
||||
return_trace (c->check_struct (this) && classArray.sanitize (c));
|
||||
}
|
||||
protected:
|
||||
GlyphID firstGlyph; /* First glyph index included in the trimmed array. */
|
||||
HBGlyphID firstGlyph; /* First glyph index included in the trimmed array. */
|
||||
ArrayOf<HBUCHAR> classArray; /* The class codes (indexed by glyph index minus
|
||||
* firstGlyph). */
|
||||
public:
|
||||
@ -682,7 +678,7 @@ struct ObsoleteTypes
|
||||
const void *base,
|
||||
const T *array)
|
||||
{
|
||||
return (offset - ((const char *) array - (const char *) base)) / sizeof (T);
|
||||
return (offset - ((const char *) array - (const char *) base)) / T::static_size;
|
||||
}
|
||||
template <typename T>
|
||||
static unsigned int byteOffsetToIndex (unsigned int offset,
|
||||
@ -824,12 +820,11 @@ struct hb_aat_apply_context_t :
|
||||
|
||||
/* Unused. For debug tracing only. */
|
||||
unsigned int lookup_index;
|
||||
unsigned int debug_depth;
|
||||
|
||||
HB_INTERNAL hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
|
||||
hb_font_t *font_,
|
||||
hb_buffer_t *buffer_,
|
||||
hb_blob_t *blob = const_cast<hb_blob_t *> (&Null(hb_blob_t)));
|
||||
hb_blob_t *blob = const_cast<hb_blob_t *> (&Null (hb_blob_t)));
|
||||
|
||||
HB_INTERNAL ~hb_aat_apply_context_t ();
|
||||
|
||||
|
||||
@ -47,17 +47,16 @@ struct SettingName
|
||||
hb_aat_layout_feature_selector_t get_selector () const
|
||||
{ return (hb_aat_layout_feature_selector_t) (unsigned) setting; }
|
||||
|
||||
void get_info (hb_aat_layout_feature_selector_info_t *s,
|
||||
hb_aat_layout_feature_selector_t default_selector) const
|
||||
hb_aat_layout_feature_selector_info_t get_info (hb_aat_layout_feature_selector_t default_selector) const
|
||||
{
|
||||
s->name_id = nameIndex;
|
||||
|
||||
s->enable = (hb_aat_layout_feature_selector_t) (unsigned int) setting;
|
||||
s->disable = default_selector == HB_AAT_LAYOUT_FEATURE_SELECTOR_INVALID ?
|
||||
(hb_aat_layout_feature_selector_t) (s->enable + 1) :
|
||||
default_selector;
|
||||
|
||||
s->reserved = 0;
|
||||
return {
|
||||
nameIndex,
|
||||
(hb_aat_layout_feature_selector_t) (unsigned int) setting,
|
||||
default_selector == HB_AAT_LAYOUT_FEATURE_SELECTOR_INVALID
|
||||
? (hb_aat_layout_feature_selector_t) (setting + 1)
|
||||
: default_selector,
|
||||
0
|
||||
};
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
@ -117,9 +116,10 @@ struct FeatureName
|
||||
|
||||
if (selectors_count)
|
||||
{
|
||||
hb_array_t<const SettingName> arr = settings_table.sub_array (start_offset, selectors_count);
|
||||
for (unsigned int i = 0; i < arr.length; i++)
|
||||
settings_table[start_offset + i].get_info (&selectors[i], default_selector);
|
||||
+ settings_table.sub_array (start_offset, selectors_count)
|
||||
| hb_map ([=] (const SettingName& setting) { return setting.get_info (default_selector); })
|
||||
| hb_sink (hb_array (selectors, *selectors_count))
|
||||
;
|
||||
}
|
||||
return settings_table.length;
|
||||
}
|
||||
@ -129,6 +129,11 @@ struct FeatureName
|
||||
|
||||
hb_ot_name_id_t get_feature_name_id () const { return nameIndex; }
|
||||
|
||||
bool is_exclusive () const { return featureFlags & Exclusive; }
|
||||
|
||||
/* A FeatureName with no settings is meaningless */
|
||||
bool has_data () const { return nSettings; }
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
@ -139,7 +144,7 @@ struct FeatureName
|
||||
protected:
|
||||
HBUINT16 feature; /* Feature type. */
|
||||
HBUINT16 nSettings; /* The number of records in the setting name array. */
|
||||
LOffsetTo<UnsizedArrayOf<SettingName>, false>
|
||||
LNNOffsetTo<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
|
||||
@ -162,21 +167,21 @@ struct feat
|
||||
unsigned int *count,
|
||||
hb_aat_layout_feature_type_t *features) const
|
||||
{
|
||||
unsigned int feature_count = featureNameCount;
|
||||
if (count && *count)
|
||||
if (count)
|
||||
{
|
||||
unsigned int len = MIN (feature_count - start_offset, *count);
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
features[i] = namesZ[i + start_offset].get_feature_type ();
|
||||
*count = len;
|
||||
+ namesZ.as_array (featureNameCount).sub_array (start_offset, count)
|
||||
| hb_map (&FeatureName::get_feature_type)
|
||||
| hb_sink (hb_array (features, *count))
|
||||
;
|
||||
}
|
||||
return featureNameCount;
|
||||
}
|
||||
|
||||
bool exposes_feature (hb_aat_layout_feature_type_t feature_type) const
|
||||
{ return get_feature (feature_type).has_data (); }
|
||||
|
||||
const FeatureName& get_feature (hb_aat_layout_feature_type_t feature_type) const
|
||||
{
|
||||
return namesZ.bsearch (featureNameCount, feature_type);
|
||||
}
|
||||
{ return namesZ.bsearch (featureNameCount, feature_type); }
|
||||
|
||||
hb_ot_name_id_t get_feature_name_id (hb_aat_layout_feature_type_t feature) const
|
||||
{ return get_feature (feature).get_feature_name_id (); }
|
||||
@ -209,7 +214,7 @@ struct feat
|
||||
SortedUnsizedArrayOf<FeatureName>
|
||||
namesZ; /* The feature name array. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (24);
|
||||
DEFINE_SIZE_ARRAY (12, namesZ);
|
||||
};
|
||||
|
||||
} /* namespace AAT */
|
||||
|
||||
@ -70,9 +70,9 @@ struct DecompositionAction
|
||||
|
||||
ActionSubrecordHeader
|
||||
header;
|
||||
Fixed lowerLimit; /* If the distance factor is less than this value,
|
||||
HBFixed lowerLimit; /* If the distance factor is less than this value,
|
||||
* then the ligature is decomposed. */
|
||||
Fixed upperLimit; /* If the distance factor is greater than this value,
|
||||
HBFixed upperLimit; /* If the distance factor is greater than this value,
|
||||
* then the ligature is decomposed. */
|
||||
HBUINT16 order; /* Numerical order in which this ligature will
|
||||
* be decomposed; you may want infrequent ligatures
|
||||
@ -100,7 +100,7 @@ struct UnconditionalAddGlyphAction
|
||||
protected:
|
||||
ActionSubrecordHeader
|
||||
header;
|
||||
GlyphID addGlyph; /* Glyph that should be added if the distance factor
|
||||
HBGlyphID addGlyph; /* Glyph that should be added if the distance factor
|
||||
* is growing. */
|
||||
|
||||
public:
|
||||
@ -118,14 +118,14 @@ struct ConditionalAddGlyphAction
|
||||
protected:
|
||||
ActionSubrecordHeader
|
||||
header;
|
||||
Fixed substThreshold; /* Distance growth factor (in ems) at which
|
||||
HBFixed substThreshold; /* Distance growth factor (in ems) at which
|
||||
* this glyph is replaced and the growth factor
|
||||
* recalculated. */
|
||||
GlyphID addGlyph; /* Glyph to be added as kashida. If this value is
|
||||
HBGlyphID addGlyph; /* Glyph to be added as kashida. If this value is
|
||||
* 0xFFFF, no extra glyph will be added. Note that
|
||||
* generally when a glyph is added, justification
|
||||
* will need to be redone. */
|
||||
GlyphID substGlyph; /* Glyph to be substituted for this glyph if the
|
||||
HBGlyphID substGlyph; /* Glyph to be substituted for this glyph if the
|
||||
* growth factor equals or exceeds the value of
|
||||
* substThreshold. */
|
||||
public:
|
||||
@ -146,13 +146,13 @@ struct DuctileGlyphAction
|
||||
HBUINT32 variationAxis; /* The 4-byte tag identifying the ductile axis.
|
||||
* This would normally be 0x64756374 ('duct'),
|
||||
* but you may use any axis the font contains. */
|
||||
Fixed minimumLimit; /* The lowest value for the ductility axis tha
|
||||
HBFixed minimumLimit; /* The lowest value for the ductility axis tha
|
||||
* still yields an acceptable appearance. Normally
|
||||
* this will be 1.0. */
|
||||
Fixed noStretchValue; /* This is the default value that corresponds to
|
||||
HBFixed noStretchValue; /* This is the default value that corresponds to
|
||||
* no change in appearance. Normally, this will
|
||||
* be 1.0. */
|
||||
Fixed maximumLimit; /* The highest value for the ductility axis that
|
||||
HBFixed maximumLimit; /* The highest value for the ductility axis that
|
||||
* still yields an acceptable appearance. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (22);
|
||||
@ -170,7 +170,7 @@ struct RepeatedAddGlyphAction
|
||||
ActionSubrecordHeader
|
||||
header;
|
||||
HBUINT16 flags; /* Currently unused; set to 0. */
|
||||
GlyphID glyph; /* Glyph that should be added if the distance factor
|
||||
HBGlyphID glyph; /* Glyph that should be added if the distance factor
|
||||
* is growing. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (10);
|
||||
@ -271,14 +271,14 @@ struct JustWidthDeltaEntry
|
||||
};
|
||||
|
||||
protected:
|
||||
Fixed beforeGrowLimit;/* The ratio by which the advance width of the
|
||||
HBFixed beforeGrowLimit;/* The ratio by which the advance width of the
|
||||
* glyph is permitted to grow on the left or top side. */
|
||||
Fixed beforeShrinkLimit;
|
||||
HBFixed beforeShrinkLimit;
|
||||
/* The ratio by which the advance width of the
|
||||
* glyph is permitted to shrink on the left or top side. */
|
||||
Fixed afterGrowLimit; /* The ratio by which the advance width of the glyph
|
||||
HBFixed afterGrowLimit; /* The ratio by which the advance width of the glyph
|
||||
* is permitted to shrink on the left or top side. */
|
||||
Fixed afterShrinkLimit;
|
||||
HBFixed afterShrinkLimit;
|
||||
/* The ratio by which the advance width of the glyph
|
||||
* is at most permitted to shrink on the right or
|
||||
* bottom side. */
|
||||
@ -371,7 +371,7 @@ struct JustificationHeader
|
||||
* of postcompensation subtable (set to zero if none).
|
||||
*
|
||||
* The postcompensation subtable, if present in the font. */
|
||||
Lookup<OffsetTo<WidthDeltaCluster> >
|
||||
Lookup<OffsetTo<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. */
|
||||
|
||||
@ -82,8 +82,8 @@ struct KernPair
|
||||
}
|
||||
|
||||
protected:
|
||||
GlyphID left;
|
||||
GlyphID right;
|
||||
HBGlyphID left;
|
||||
HBGlyphID right;
|
||||
FWORD value;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (6);
|
||||
@ -229,9 +229,7 @@ struct KerxSubTableFormat1
|
||||
|
||||
bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
|
||||
const Entry<EntryData> &entry)
|
||||
{
|
||||
return Format1EntryT::performAction (entry);
|
||||
}
|
||||
{ return Format1EntryT::performAction (entry); }
|
||||
void transition (StateTableDriver<Types, EntryData> *driver,
|
||||
const Entry<EntryData> &entry)
|
||||
{
|
||||
@ -251,7 +249,7 @@ struct KerxSubTableFormat1
|
||||
|
||||
if (Format1EntryT::performAction (entry) && depth)
|
||||
{
|
||||
unsigned int tuple_count = MAX (1u, table->header.tuple_count ());
|
||||
unsigned int tuple_count = hb_max (1u, table->header.tuple_count ());
|
||||
|
||||
unsigned int kern_idx = Format1EntryT::kernActionIndex (entry);
|
||||
kern_idx = Types::byteOffsetToIndex (kern_idx, &table->machine, kernAction.arrayZ);
|
||||
@ -281,35 +279,28 @@ struct KerxSubTableFormat1
|
||||
|
||||
hb_glyph_position_t &o = buffer->pos[idx];
|
||||
|
||||
/* Testing shows that CoreText only applies kern (cross-stream or not)
|
||||
* if none has been applied by previous subtables. That is, it does
|
||||
* NOT seem to accumulate as otherwise implied by specs. */
|
||||
|
||||
/* The following flag is undocumented in the spec, but described
|
||||
* in the 'kern' table example. */
|
||||
if (v == -0x8000)
|
||||
{
|
||||
o.attach_type() = ATTACH_TYPE_NONE;
|
||||
o.attach_chain() = 0;
|
||||
o.x_offset = o.y_offset = 0;
|
||||
}
|
||||
else if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
|
||||
if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
|
||||
{
|
||||
if (crossStream)
|
||||
{
|
||||
if (buffer->pos[idx].attach_type() && !buffer->pos[idx].y_offset)
|
||||
/* The following flag is undocumented in the spec, but described
|
||||
* in the 'kern' table example. */
|
||||
if (v == -0x8000)
|
||||
{
|
||||
o.y_offset = c->font->em_scale_y (v);
|
||||
o.attach_type() = ATTACH_TYPE_NONE;
|
||||
o.attach_chain() = 0;
|
||||
o.y_offset = 0;
|
||||
}
|
||||
else if (o.attach_type())
|
||||
{
|
||||
o.y_offset += c->font->em_scale_y (v);
|
||||
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
|
||||
}
|
||||
}
|
||||
else if (buffer->info[idx].mask & kern_mask)
|
||||
{
|
||||
if (!buffer->pos[idx].x_offset)
|
||||
{
|
||||
buffer->pos[idx].x_advance += c->font->em_scale_x (v);
|
||||
buffer->pos[idx].x_offset += c->font->em_scale_x (v);
|
||||
}
|
||||
o.x_advance += c->font->em_scale_x (v);
|
||||
o.x_offset += c->font->em_scale_x (v);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -317,19 +308,22 @@ struct KerxSubTableFormat1
|
||||
if (crossStream)
|
||||
{
|
||||
/* CoreText doesn't do crossStream kerning in vertical. We do. */
|
||||
if (buffer->pos[idx].attach_type() && !buffer->pos[idx].x_offset)
|
||||
if (v == -0x8000)
|
||||
{
|
||||
o.x_offset = c->font->em_scale_x (v);
|
||||
o.attach_type() = ATTACH_TYPE_NONE;
|
||||
o.attach_chain() = 0;
|
||||
o.x_offset = 0;
|
||||
}
|
||||
else if (o.attach_type())
|
||||
{
|
||||
o.x_offset += c->font->em_scale_x (v);
|
||||
buffer->scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GPOS_ATTACHMENT;
|
||||
}
|
||||
}
|
||||
else if (buffer->info[idx].mask & kern_mask)
|
||||
{
|
||||
if (!buffer->pos[idx].y_offset)
|
||||
{
|
||||
buffer->pos[idx].y_advance += c->font->em_scale_y (v);
|
||||
buffer->pos[idx].y_offset += c->font->em_scale_y (v);
|
||||
}
|
||||
o.y_advance += c->font->em_scale_y (v);
|
||||
o.y_offset += c->font->em_scale_y (v);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -392,7 +386,7 @@ struct KerxSubTableFormat2
|
||||
|
||||
const UnsizedArrayOf<FWORD> &arrayZ = this+array;
|
||||
unsigned int kern_idx = l + r;
|
||||
kern_idx = Types::offsetToIndex (kern_idx, this, &arrayZ);
|
||||
kern_idx = Types::offsetToIndex (kern_idx, this, arrayZ.arrayZ);
|
||||
const FWORD *v = &arrayZ[kern_idx];
|
||||
if (unlikely (!v->sanitize (&c->sanitizer))) return 0;
|
||||
|
||||
@ -488,7 +482,7 @@ struct KerxSubTableFormat4
|
||||
};
|
||||
|
||||
driver_context_t (const KerxSubTableFormat4 *table,
|
||||
hb_aat_apply_context_t *c_) :
|
||||
hb_aat_apply_context_t *c_) :
|
||||
c (c_),
|
||||
action_type ((table->flags & ActionType) >> 30),
|
||||
ankrData ((HBUINT16 *) ((const char *) &table->machine + (table->flags & Offset))),
|
||||
@ -497,9 +491,7 @@ struct KerxSubTableFormat4
|
||||
|
||||
bool is_actionable (StateTableDriver<Types, EntryData> *driver HB_UNUSED,
|
||||
const Entry<EntryData> &entry)
|
||||
{
|
||||
return entry.data.ankrActionIndex != 0xFFFF;
|
||||
}
|
||||
{ return entry.data.ankrActionIndex != 0xFFFF; }
|
||||
void transition (StateTableDriver<Types, EntryData> *driver,
|
||||
const Entry<EntryData> &entry)
|
||||
{
|
||||
@ -512,11 +504,13 @@ struct KerxSubTableFormat4
|
||||
{
|
||||
case 0: /* Control Point Actions.*/
|
||||
{
|
||||
/* indexed into glyph outline. */
|
||||
const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex];
|
||||
/* Indexed into glyph outline. */
|
||||
/* Each action (record in ankrData) contains two 16-bit fields, so we must
|
||||
double the ankrActionIndex to get the correct offset here. */
|
||||
const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2];
|
||||
if (!c->sanitizer.check_array (data, 2)) return;
|
||||
HB_UNUSED unsigned int markControlPoint = *data++;
|
||||
HB_UNUSED unsigned int currControlPoint = *data++;
|
||||
unsigned int markControlPoint = *data++;
|
||||
unsigned int currControlPoint = *data++;
|
||||
hb_position_t markX = 0;
|
||||
hb_position_t markY = 0;
|
||||
hb_position_t currX = 0;
|
||||
@ -538,8 +532,10 @@ struct KerxSubTableFormat4
|
||||
|
||||
case 1: /* Anchor Point Actions. */
|
||||
{
|
||||
/* Indexed into 'ankr' table. */
|
||||
const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex];
|
||||
/* Indexed into 'ankr' table. */
|
||||
/* Each action (record in ankrData) contains two 16-bit fields, so we must
|
||||
double the ankrActionIndex to get the correct offset here. */
|
||||
const HBUINT16 *data = &ankrData[entry.data.ankrActionIndex * 2];
|
||||
if (!c->sanitizer.check_array (data, 2)) return;
|
||||
unsigned int markAnchorPoint = *data++;
|
||||
unsigned int currAnchorPoint = *data++;
|
||||
@ -557,7 +553,9 @@ struct KerxSubTableFormat4
|
||||
|
||||
case 2: /* Control Point Coordinate Actions. */
|
||||
{
|
||||
const FWORD *data = (const FWORD *) &ankrData[entry.data.ankrActionIndex];
|
||||
/* Each action contains four 16-bit fields, so we multiply the ankrActionIndex
|
||||
by 4 to get the correct offset for the given action. */
|
||||
const FWORD *data = (const FWORD *) &ankrData[entry.data.ankrActionIndex * 4];
|
||||
if (!c->sanitizer.check_array (data, 4)) return;
|
||||
int markX = *data++;
|
||||
int markY = *data++;
|
||||
@ -628,7 +626,7 @@ struct KerxSubTableFormat6
|
||||
bool is_long () const { return flags & ValuesAreLong; }
|
||||
|
||||
int get_kerning (hb_codepoint_t left, hb_codepoint_t right,
|
||||
hb_aat_apply_context_t *c) const
|
||||
hb_aat_apply_context_t *c) const
|
||||
{
|
||||
unsigned int num_glyphs = c->sanitizer.get_num_glyphs ();
|
||||
if (is_long ())
|
||||
@ -712,18 +710,18 @@ struct KerxSubTableFormat6
|
||||
{
|
||||
struct Long
|
||||
{
|
||||
LNNOffsetTo<Lookup<HBUINT32> > rowIndexTable;
|
||||
LNNOffsetTo<Lookup<HBUINT32> > columnIndexTable;
|
||||
LNNOffsetTo<UnsizedArrayOf<FWORD32> > array;
|
||||
LNNOffsetTo<Lookup<HBUINT32>> rowIndexTable;
|
||||
LNNOffsetTo<Lookup<HBUINT32>> columnIndexTable;
|
||||
LNNOffsetTo<UnsizedArrayOf<FWORD32>> array;
|
||||
} l;
|
||||
struct Short
|
||||
{
|
||||
LNNOffsetTo<Lookup<HBUINT16> > rowIndexTable;
|
||||
LNNOffsetTo<Lookup<HBUINT16> > columnIndexTable;
|
||||
LNNOffsetTo<UnsizedArrayOf<FWORD> > array;
|
||||
LNNOffsetTo<Lookup<HBUINT16>> rowIndexTable;
|
||||
LNNOffsetTo<Lookup<HBUINT16>> columnIndexTable;
|
||||
LNNOffsetTo<UnsizedArrayOf<FWORD>> array;
|
||||
} s;
|
||||
} u;
|
||||
LNNOffsetTo<UnsizedArrayOf<FWORD> > vector;
|
||||
LNNOffsetTo<UnsizedArrayOf<FWORD>> vector;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 24);
|
||||
};
|
||||
@ -733,8 +731,8 @@ struct KerxSubTableHeader
|
||||
{
|
||||
typedef ExtendedTypes Types;
|
||||
|
||||
unsigned int tuple_count () const { return tupleCount; }
|
||||
bool is_horizontal () const { return !(coverage & Vertical); }
|
||||
unsigned tuple_count () const { return tupleCount; }
|
||||
bool is_horizontal () const { return !(coverage & Vertical); }
|
||||
|
||||
enum Coverage
|
||||
{
|
||||
@ -771,17 +769,17 @@ struct KerxSubTable
|
||||
unsigned int get_size () const { return u.header.length; }
|
||||
unsigned int get_type () const { return u.header.coverage & u.header.SubtableType; }
|
||||
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
unsigned int subtable_type = get_type ();
|
||||
TRACE_DISPATCH (this, subtable_type);
|
||||
switch (subtable_type) {
|
||||
case 0: return_trace (c->dispatch (u.format0));
|
||||
case 1: return_trace (c->dispatch (u.format1));
|
||||
case 2: return_trace (c->dispatch (u.format2));
|
||||
case 4: return_trace (c->dispatch (u.format4));
|
||||
case 6: return_trace (c->dispatch (u.format6));
|
||||
case 0: return_trace (c->dispatch (u.format0, hb_forward<Ts> (ds)...));
|
||||
case 1: return_trace (c->dispatch (u.format1, hb_forward<Ts> (ds)...));
|
||||
case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
|
||||
case 4: return_trace (c->dispatch (u.format4, hb_forward<Ts> (ds)...));
|
||||
case 6: return_trace (c->dispatch (u.format6, hb_forward<Ts> (ds)...));
|
||||
default: return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
@ -891,7 +889,7 @@ struct KerxTable
|
||||
reverse = bool (st->u.header.coverage & st->u.header.Backwards) !=
|
||||
HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
|
||||
|
||||
if (!c->buffer->message (c->font, "start %c%c%c%c subtable %d", HB_UNTAG (thiz()->tableTag), c->lookup_index))
|
||||
if (!c->buffer->message (c->font, "start subtable %d", c->lookup_index))
|
||||
goto skip;
|
||||
|
||||
if (!seenCrossStream &&
|
||||
@ -923,7 +921,7 @@ struct KerxTable
|
||||
if (reverse)
|
||||
c->buffer->reverse ();
|
||||
|
||||
(void) c->buffer->message (c->font, "end %c%c%c%c subtable %d", HB_UNTAG (thiz()->tableTag), c->lookup_index);
|
||||
(void) c->buffer->message (c->font, "end subtable %d", c->lookup_index);
|
||||
|
||||
skip:
|
||||
st = &StructAfter<SubTable> (*st);
|
||||
|
||||
@ -1,93 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2018 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
#ifndef HB_AAT_LAYOUT_LCAR_TABLE_HH
|
||||
#define HB_AAT_LAYOUT_LCAR_TABLE_HH
|
||||
|
||||
#include "hb-open-type.hh"
|
||||
#include "hb-aat-layout-common.hh"
|
||||
|
||||
/*
|
||||
* lcar -- Ligature caret
|
||||
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6lcar.html
|
||||
*/
|
||||
#define HB_AAT_TAG_lcar HB_TAG('l','c','a','r')
|
||||
|
||||
|
||||
namespace AAT {
|
||||
|
||||
typedef ArrayOf<HBINT16> LigCaretClassEntry;
|
||||
|
||||
struct lcar
|
||||
{
|
||||
static constexpr hb_tag_t tableTag = HB_AAT_TAG_lcar;
|
||||
|
||||
unsigned int get_lig_carets (hb_font_t *font,
|
||||
hb_direction_t direction,
|
||||
hb_codepoint_t glyph,
|
||||
unsigned int start_offset,
|
||||
unsigned int *caret_count /* IN/OUT */,
|
||||
hb_position_t *caret_array /* OUT */) const
|
||||
{
|
||||
const OffsetTo<LigCaretClassEntry>* entry_offset = lookup.get_value (glyph,
|
||||
font->face->get_num_glyphs ());
|
||||
const LigCaretClassEntry& array = entry_offset ? this+*entry_offset : Null (LigCaretClassEntry);
|
||||
if (caret_count)
|
||||
{
|
||||
hb_array_t<const HBINT16> arr = array.sub_array (start_offset, caret_count);
|
||||
unsigned int count = arr.length;
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
switch (format)
|
||||
{
|
||||
case 0: caret_array[i] = font->em_scale_dir (arr[i], direction); break;
|
||||
case 1:
|
||||
hb_position_t x, y;
|
||||
font->get_glyph_contour_point_for_origin (glyph, arr[i], direction, &x, &y);
|
||||
caret_array[i] = HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return array.len;
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
version.major == 1 &&
|
||||
lookup.sanitize (c, this)));
|
||||
}
|
||||
|
||||
protected:
|
||||
FixedVersion<>version; /* Version number of the ligature caret table */
|
||||
HBUINT16 format; /* Format of the ligature caret table. */
|
||||
Lookup<OffsetTo<LigCaretClassEntry> >
|
||||
lookup; /* data Lookup table associating glyphs */
|
||||
|
||||
public:
|
||||
DEFINE_SIZE_MIN (8);
|
||||
};
|
||||
|
||||
} /* namespace AAT */
|
||||
|
||||
#endif /* HB_AAT_LAYOUT_LCAR_TABLE_HH */
|
||||
@ -88,7 +88,7 @@ struct RearrangementSubtable
|
||||
start = buffer->idx;
|
||||
|
||||
if (flags & MarkLast)
|
||||
end = MIN (buffer->idx + 1, buffer->len);
|
||||
end = hb_min (buffer->idx + 1, buffer->len);
|
||||
|
||||
if ((flags & Verb) && start < end)
|
||||
{
|
||||
@ -117,14 +117,14 @@ struct RearrangementSubtable
|
||||
};
|
||||
|
||||
unsigned int m = map[flags & Verb];
|
||||
unsigned int l = MIN<unsigned int> (2, m >> 4);
|
||||
unsigned int r = MIN<unsigned int> (2, m & 0x0F);
|
||||
unsigned int l = hb_min (2u, m >> 4);
|
||||
unsigned int r = hb_min (2u, m & 0x0F);
|
||||
bool reverse_l = 3 == (m >> 4);
|
||||
bool reverse_r = 3 == (m & 0x0F);
|
||||
|
||||
if (end - start >= l + r)
|
||||
{
|
||||
buffer->merge_clusters (start, MIN (buffer->idx + 1, buffer->len));
|
||||
buffer->merge_clusters (start, hb_min (buffer->idx + 1, buffer->len));
|
||||
buffer->merge_clusters (start, end);
|
||||
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
@ -240,46 +240,46 @@ struct ContextualSubtable
|
||||
if (buffer->idx == buffer->len && !mark_set)
|
||||
return;
|
||||
|
||||
const GlyphID *replacement;
|
||||
const HBGlyphID *replacement;
|
||||
|
||||
replacement = nullptr;
|
||||
if (Types::extended)
|
||||
{
|
||||
if (entry.data.markIndex != 0xFFFF)
|
||||
{
|
||||
const Lookup<GlyphID> &lookup = subs[entry.data.markIndex];
|
||||
const Lookup<HBGlyphID> &lookup = subs[entry.data.markIndex];
|
||||
replacement = lookup.get_value (buffer->info[mark].codepoint, driver->num_glyphs);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int offset = entry.data.markIndex + buffer->info[mark].codepoint;
|
||||
const UnsizedArrayOf<GlyphID> &subs_old = (const UnsizedArrayOf<GlyphID> &) subs;
|
||||
const UnsizedArrayOf<HBGlyphID> &subs_old = (const UnsizedArrayOf<HBGlyphID> &) subs;
|
||||
replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
|
||||
if (!replacement->sanitize (&c->sanitizer) || !*replacement)
|
||||
replacement = nullptr;
|
||||
}
|
||||
if (replacement)
|
||||
{
|
||||
buffer->unsafe_to_break (mark, MIN (buffer->idx + 1, buffer->len));
|
||||
buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
|
||||
buffer->info[mark].codepoint = *replacement;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
replacement = nullptr;
|
||||
unsigned int idx = MIN (buffer->idx, buffer->len - 1);
|
||||
unsigned int idx = hb_min (buffer->idx, buffer->len - 1);
|
||||
if (Types::extended)
|
||||
{
|
||||
if (entry.data.currentIndex != 0xFFFF)
|
||||
{
|
||||
const Lookup<GlyphID> &lookup = subs[entry.data.currentIndex];
|
||||
const Lookup<HBGlyphID> &lookup = subs[entry.data.currentIndex];
|
||||
replacement = lookup.get_value (buffer->info[idx].codepoint, driver->num_glyphs);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned int offset = entry.data.currentIndex + buffer->info[idx].codepoint;
|
||||
const UnsizedArrayOf<GlyphID> &subs_old = (const UnsizedArrayOf<GlyphID> &) subs;
|
||||
const UnsizedArrayOf<HBGlyphID> &subs_old = (const UnsizedArrayOf<HBGlyphID> &) subs;
|
||||
replacement = &subs_old[Types::wordOffsetToIndex (offset, table, subs_old.arrayZ)];
|
||||
if (!replacement->sanitize (&c->sanitizer) || !*replacement)
|
||||
replacement = nullptr;
|
||||
@ -304,7 +304,7 @@ struct ContextualSubtable
|
||||
bool mark_set;
|
||||
unsigned int mark;
|
||||
const ContextualSubtable *table;
|
||||
const UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT, false> &subs;
|
||||
const UnsizedOffsetListOf<Lookup<HBGlyphID>, HBUINT, false> &subs;
|
||||
};
|
||||
|
||||
bool apply (hb_aat_apply_context_t *c) const
|
||||
@ -337,9 +337,9 @@ struct ContextualSubtable
|
||||
const EntryData &data = entries[i].data;
|
||||
|
||||
if (data.markIndex != 0xFFFF)
|
||||
num_lookups = MAX<unsigned int> (num_lookups, 1 + data.markIndex);
|
||||
num_lookups = hb_max (num_lookups, 1 + data.markIndex);
|
||||
if (data.currentIndex != 0xFFFF)
|
||||
num_lookups = MAX<unsigned int> (num_lookups, 1 + data.currentIndex);
|
||||
num_lookups = hb_max (num_lookups, 1 + data.currentIndex);
|
||||
}
|
||||
|
||||
return_trace (substitutionTables.sanitize (c, this, num_lookups));
|
||||
@ -348,7 +348,7 @@ struct ContextualSubtable
|
||||
protected:
|
||||
StateTable<Types, EntryData>
|
||||
machine;
|
||||
NNOffsetTo<UnsizedOffsetListOf<Lookup<GlyphID>, HBUINT, false>, HBUINT>
|
||||
NNOffsetTo<UnsizedOffsetListOf<Lookup<HBGlyphID>, HBUINT, false>, HBUINT>
|
||||
substitutionTables;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (20);
|
||||
@ -520,7 +520,7 @@ struct LigatureSubtable
|
||||
if (action & (LigActionStore | LigActionLast))
|
||||
{
|
||||
ligature_idx = Types::offsetToIndex (ligature_idx, table, ligature.arrayZ);
|
||||
const GlyphID &ligatureData = ligature[ligature_idx];
|
||||
const HBGlyphID &ligatureData = ligature[ligature_idx];
|
||||
if (unlikely (!ligatureData.sanitize (&c->sanitizer))) break;
|
||||
hb_codepoint_t lig = ligatureData;
|
||||
|
||||
@ -554,7 +554,7 @@ struct LigatureSubtable
|
||||
const LigatureSubtable *table;
|
||||
const UnsizedArrayOf<HBUINT32> &ligAction;
|
||||
const UnsizedArrayOf<HBUINT16> &component;
|
||||
const UnsizedArrayOf<GlyphID> &ligature;
|
||||
const UnsizedArrayOf<HBGlyphID> &ligature;
|
||||
unsigned int match_length;
|
||||
unsigned int match_positions[HB_MAX_CONTEXT_LENGTH];
|
||||
};
|
||||
@ -586,7 +586,7 @@ struct LigatureSubtable
|
||||
ligAction; /* Offset to the ligature action table. */
|
||||
NNOffsetTo<UnsizedArrayOf<HBUINT16>, HBUINT>
|
||||
component; /* Offset to the component table. */
|
||||
NNOffsetTo<UnsizedArrayOf<GlyphID>, HBUINT>
|
||||
NNOffsetTo<UnsizedArrayOf<HBGlyphID>, HBUINT>
|
||||
ligature; /* Offset to the actual ligature lists. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (28);
|
||||
@ -606,7 +606,7 @@ struct NoncontextualSubtable
|
||||
unsigned int count = c->buffer->len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
const GlyphID *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
|
||||
const HBGlyphID *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
|
||||
if (replacement)
|
||||
{
|
||||
info[i].codepoint = *replacement;
|
||||
@ -624,7 +624,7 @@ struct NoncontextualSubtable
|
||||
}
|
||||
|
||||
protected:
|
||||
Lookup<GlyphID> substitute;
|
||||
Lookup<HBGlyphID> substitute;
|
||||
public:
|
||||
DEFINE_SIZE_MIN (2);
|
||||
};
|
||||
@ -725,8 +725,9 @@ struct InsertionSubtable
|
||||
if (entry.data.markedInsertIndex != 0xFFFF)
|
||||
{
|
||||
unsigned int count = (flags & MarkedInsertCount);
|
||||
if (unlikely ((buffer->max_ops -= count) <= 0)) return;
|
||||
unsigned int start = entry.data.markedInsertIndex;
|
||||
const GlyphID *glyphs = &insertionAction[start];
|
||||
const HBGlyphID *glyphs = &insertionAction[start];
|
||||
if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
|
||||
|
||||
bool before = flags & MarkedInsertBefore;
|
||||
@ -744,7 +745,7 @@ struct InsertionSubtable
|
||||
|
||||
buffer->move_to (end + count);
|
||||
|
||||
buffer->unsafe_to_break_from_outbuffer (mark, MIN (buffer->idx + 1, buffer->len));
|
||||
buffer->unsafe_to_break_from_outbuffer (mark, hb_min (buffer->idx + 1, buffer->len));
|
||||
}
|
||||
|
||||
if (flags & SetMark)
|
||||
@ -753,8 +754,9 @@ struct InsertionSubtable
|
||||
if (entry.data.currentInsertIndex != 0xFFFF)
|
||||
{
|
||||
unsigned int count = (flags & CurrentInsertCount) >> 5;
|
||||
if (unlikely ((buffer->max_ops -= count) <= 0)) return;
|
||||
unsigned int start = entry.data.currentInsertIndex;
|
||||
const GlyphID *glyphs = &insertionAction[start];
|
||||
const HBGlyphID *glyphs = &insertionAction[start];
|
||||
if (unlikely (!c->sanitizer.check_array (glyphs, count))) count = 0;
|
||||
|
||||
bool before = flags & CurrentInsertBefore;
|
||||
@ -793,7 +795,7 @@ struct InsertionSubtable
|
||||
private:
|
||||
hb_aat_apply_context_t *c;
|
||||
unsigned int mark;
|
||||
const UnsizedArrayOf<GlyphID> &insertionAction;
|
||||
const UnsizedArrayOf<HBGlyphID> &insertionAction;
|
||||
};
|
||||
|
||||
bool apply (hb_aat_apply_context_t *c) const
|
||||
@ -819,7 +821,7 @@ struct InsertionSubtable
|
||||
protected:
|
||||
StateTable<Types, EntryData>
|
||||
machine;
|
||||
NNOffsetTo<UnsizedArrayOf<GlyphID>, HBUINT>
|
||||
NNOffsetTo<UnsizedArrayOf<HBGlyphID>, HBUINT>
|
||||
insertionAction; /* Byte offset from stateHeader to the start of
|
||||
* the insertion glyph table. */
|
||||
public:
|
||||
@ -883,17 +885,17 @@ struct ChainSubtable
|
||||
Insertion = 5
|
||||
};
|
||||
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
unsigned int subtable_type = get_type ();
|
||||
TRACE_DISPATCH (this, subtable_type);
|
||||
switch (subtable_type) {
|
||||
case Rearrangement: return_trace (c->dispatch (u.rearrangement));
|
||||
case Contextual: return_trace (c->dispatch (u.contextual));
|
||||
case Ligature: return_trace (c->dispatch (u.ligature));
|
||||
case Noncontextual: return_trace (c->dispatch (u.noncontextual));
|
||||
case Insertion: return_trace (c->dispatch (u.insertion));
|
||||
case Rearrangement: return_trace (c->dispatch (u.rearrangement, hb_forward<Ts> (ds)...));
|
||||
case Contextual: return_trace (c->dispatch (u.contextual, hb_forward<Ts> (ds)...));
|
||||
case Ligature: return_trace (c->dispatch (u.ligature, hb_forward<Ts> (ds)...));
|
||||
case Noncontextual: return_trace (c->dispatch (u.noncontextual, hb_forward<Ts> (ds)...));
|
||||
case Insertion: return_trace (c->dispatch (u.insertion, hb_forward<Ts> (ds)...));
|
||||
default: return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
@ -948,8 +950,10 @@ struct Chain
|
||||
hb_aat_layout_feature_type_t type = (hb_aat_layout_feature_type_t) (unsigned int) feature.featureType;
|
||||
hb_aat_layout_feature_selector_t setting = (hb_aat_layout_feature_selector_t) (unsigned int) feature.featureSetting;
|
||||
retry:
|
||||
const hb_aat_map_builder_t::feature_info_t *info = map->features.bsearch (type);
|
||||
if (info && info->setting == setting)
|
||||
// Check whether this type/setting pair was requested in the map, and if so, apply its flags.
|
||||
// (The search here only looks at the type and setting fields of feature_info_t.)
|
||||
hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 };
|
||||
if (map->features.bsearch (info))
|
||||
{
|
||||
flags &= feature.disableFlags;
|
||||
flags |= feature.enableFlags;
|
||||
@ -967,9 +971,9 @@ struct Chain
|
||||
}
|
||||
|
||||
void apply (hb_aat_apply_context_t *c,
|
||||
hb_mask_t flags) const
|
||||
hb_mask_t flags) const
|
||||
{
|
||||
const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types> > (featureZ.as_array (featureCount));
|
||||
const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
|
||||
unsigned int count = subtableCount;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
@ -1015,7 +1019,7 @@ struct Chain
|
||||
bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) !=
|
||||
HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
|
||||
|
||||
if (!c->buffer->message (c->font, "start chain subtable %d", c->lookup_index))
|
||||
if (!c->buffer->message (c->font, "start chainsubtable %d", c->lookup_index))
|
||||
goto skip;
|
||||
|
||||
if (reverse)
|
||||
@ -1026,12 +1030,12 @@ struct Chain
|
||||
if (reverse)
|
||||
c->buffer->reverse ();
|
||||
|
||||
(void) c->buffer->message (c->font, "end chain subtable %d", c->lookup_index);
|
||||
(void) c->buffer->message (c->font, "end chainsubtable %d", c->lookup_index);
|
||||
|
||||
if (unlikely (!c->buffer->successful)) return;
|
||||
|
||||
skip:
|
||||
subtable = &StructAfter<ChainSubtable<Types> > (*subtable);
|
||||
subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
|
||||
c->set_lookup_index (c->lookup_index + 1);
|
||||
}
|
||||
}
|
||||
@ -1049,13 +1053,13 @@ struct Chain
|
||||
if (!c->check_array (featureZ.arrayZ, featureCount))
|
||||
return_trace (false);
|
||||
|
||||
const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types> > (featureZ.as_array (featureCount));
|
||||
const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
|
||||
unsigned int count = subtableCount;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
if (!subtable->sanitize (c))
|
||||
return_trace (false);
|
||||
subtable = &StructAfter<ChainSubtable<Types> > (*subtable);
|
||||
subtable = &StructAfter<ChainSubtable<Types>> (*subtable);
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
@ -1080,10 +1084,10 @@ struct Chain
|
||||
* The 'mort'/'morx' Table
|
||||
*/
|
||||
|
||||
template <typename Types>
|
||||
template <typename Types, hb_tag_t TAG>
|
||||
struct mortmorx
|
||||
{
|
||||
static constexpr hb_tag_t tableTag = HB_AAT_TAG_morx;
|
||||
static constexpr hb_tag_t tableTag = TAG;
|
||||
|
||||
bool has_data () const { return version != 0; }
|
||||
|
||||
@ -1095,7 +1099,7 @@ struct mortmorx
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
map->chain_flags.push (chain->compile_flags (mapper));
|
||||
chain = &StructAfter<Chain<Types> > (*chain);
|
||||
chain = &StructAfter<Chain<Types>> (*chain);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1109,7 +1113,7 @@ struct mortmorx
|
||||
{
|
||||
chain->apply (c, c->plan->aat_map.chain_flags[i]);
|
||||
if (unlikely (!c->buffer->successful)) return;
|
||||
chain = &StructAfter<Chain<Types> > (*chain);
|
||||
chain = &StructAfter<Chain<Types>> (*chain);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1125,7 +1129,7 @@ struct mortmorx
|
||||
{
|
||||
if (!chain->sanitize (c, version))
|
||||
return_trace (false);
|
||||
chain = &StructAfter<Chain<Types> > (*chain);
|
||||
chain = &StructAfter<Chain<Types>> (*chain);
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
@ -1143,14 +1147,8 @@ struct mortmorx
|
||||
DEFINE_SIZE_MIN (8);
|
||||
};
|
||||
|
||||
struct morx : mortmorx<ExtendedTypes>
|
||||
{
|
||||
static constexpr hb_tag_t tableTag = HB_AAT_TAG_morx;
|
||||
};
|
||||
struct mort : mortmorx<ObsoleteTypes>
|
||||
{
|
||||
static constexpr hb_tag_t tableTag = HB_AAT_TAG_mort;
|
||||
};
|
||||
struct morx : mortmorx<ExtendedTypes, HB_AAT_TAG_morx> {};
|
||||
struct mort : mortmorx<ObsoleteTypes, HB_AAT_TAG_mort> {};
|
||||
|
||||
|
||||
} /* namespace AAT */
|
||||
|
||||
@ -0,0 +1,173 @@
|
||||
/*
|
||||
* Copyright © 2019 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#ifndef HB_AAT_LAYOUT_OPBD_TABLE_HH
|
||||
#define HB_AAT_LAYOUT_OPBD_TABLE_HH
|
||||
|
||||
#include "hb-aat-layout-common.hh"
|
||||
#include "hb-open-type.hh"
|
||||
|
||||
/*
|
||||
* opbd -- Optical Bounds
|
||||
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6opbd.html
|
||||
*/
|
||||
#define HB_AAT_TAG_opbd HB_TAG('o','p','b','d')
|
||||
|
||||
|
||||
namespace AAT {
|
||||
|
||||
struct OpticalBounds
|
||||
{
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this)));
|
||||
}
|
||||
|
||||
FWORD leftSide;
|
||||
FWORD topSide;
|
||||
FWORD rightSide;
|
||||
FWORD bottomSide;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (8);
|
||||
};
|
||||
|
||||
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 ());
|
||||
if (!bounds_offset) return false;
|
||||
const OpticalBounds &bounds = base+*bounds_offset;
|
||||
|
||||
if (extents)
|
||||
*extents = {
|
||||
font->em_scale_x (bounds.leftSide),
|
||||
font->em_scale_y (bounds.topSide),
|
||||
font->em_scale_x (bounds.rightSide),
|
||||
font->em_scale_y (bounds.bottomSide)
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c, base)));
|
||||
}
|
||||
|
||||
protected:
|
||||
Lookup<OffsetTo<OpticalBounds>>
|
||||
lookupTable; /* Lookup table associating glyphs with the four
|
||||
* int16 values for the left-side, top-side,
|
||||
* right-side, and bottom-side optical bounds. */
|
||||
public:
|
||||
DEFINE_SIZE_MIN (2);
|
||||
};
|
||||
|
||||
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 ());
|
||||
if (!bounds_offset) return false;
|
||||
const OpticalBounds &bounds = base+*bounds_offset;
|
||||
|
||||
hb_position_t left = 0, top = 0, right = 0, bottom = 0, ignore;
|
||||
if (font->get_glyph_contour_point (glyph_id, bounds.leftSide, &left, &ignore) ||
|
||||
font->get_glyph_contour_point (glyph_id, bounds.topSide, &ignore, &top) ||
|
||||
font->get_glyph_contour_point (glyph_id, bounds.rightSide, &right, &ignore) ||
|
||||
font->get_glyph_contour_point (glyph_id, bounds.bottomSide, &ignore, &bottom))
|
||||
{
|
||||
if (extents)
|
||||
*extents = {left, top, right, bottom};
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) && lookupTable.sanitize (c, base)));
|
||||
}
|
||||
|
||||
protected:
|
||||
Lookup<OffsetTo<OpticalBounds>>
|
||||
lookupTable; /* Lookup table associating glyphs with the four
|
||||
* int16 values for the left-side, top-side,
|
||||
* right-side, and bottom-side optical bounds. */
|
||||
public:
|
||||
DEFINE_SIZE_MIN (2);
|
||||
};
|
||||
|
||||
struct opbd
|
||||
{
|
||||
static constexpr hb_tag_t tableTag = HB_AAT_TAG_opbd;
|
||||
|
||||
bool get_bounds (hb_font_t *font, hb_codepoint_t glyph_id,
|
||||
hb_glyph_extents_t *extents) const
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case 0: return u.format0.get_bounds (font, glyph_id, extents, this);
|
||||
case 1: return u.format1.get_bounds (font, glyph_id, extents, this);
|
||||
default:return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!c->check_struct (this) || version.major != 1))
|
||||
return_trace (false);
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case 0: return_trace (u.format0.sanitize (c, this));
|
||||
case 1: return_trace (u.format1.sanitize (c, this));
|
||||
default:return_trace (true);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
FixedVersion<>version; /* Version number of the optical bounds
|
||||
* table (0x00010000 for the current version). */
|
||||
HBUINT16 format; /* Format of the optical bounds table.
|
||||
* Format 0 indicates distance and Format 1 indicates
|
||||
* control point. */
|
||||
union {
|
||||
opbdFormat0 format0;
|
||||
opbdFormat1 format1;
|
||||
} u;
|
||||
public:
|
||||
DEFINE_SIZE_MIN (8);
|
||||
};
|
||||
|
||||
} /* namespace AAT */
|
||||
|
||||
|
||||
#endif /* HB_AAT_LAYOUT_OPBD_TABLE_HH */
|
||||
@ -62,11 +62,11 @@ struct TrackTableEntry
|
||||
}
|
||||
|
||||
protected:
|
||||
Fixed track; /* Track value for this record. */
|
||||
HBFixed track; /* Track value for this record. */
|
||||
NameID trackNameID; /* The 'name' table index for this track.
|
||||
* (a short word or phrase like "loose"
|
||||
* or "very tight") */
|
||||
NNOffsetTo<UnsizedArrayOf<FWORD> >
|
||||
NNOffsetTo<UnsizedArrayOf<FWORD>>
|
||||
valuesZ; /* Offset from start of tracking table to
|
||||
* per-size tracking values for this track. */
|
||||
|
||||
@ -82,7 +82,7 @@ struct TrackData
|
||||
const void *base) const
|
||||
{
|
||||
unsigned int sizes = nSizes;
|
||||
hb_array_t<const Fixed> size_table ((base+sizeTable).arrayZ, sizes);
|
||||
hb_array_t<const HBFixed> size_table ((base+sizeTable).arrayZ, sizes);
|
||||
|
||||
float s0 = size_table[idx].to_float ();
|
||||
float s1 = size_table[idx + 1].to_float ();
|
||||
@ -93,13 +93,6 @@ struct TrackData
|
||||
|
||||
int get_tracking (const void *base, float ptem) const
|
||||
{
|
||||
/* CoreText points are CSS pixels (96 per inch),
|
||||
* NOT typographic points (72 per inch).
|
||||
*
|
||||
* https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html
|
||||
*/
|
||||
float csspx = ptem * 96.f / 72.f;
|
||||
|
||||
/*
|
||||
* Choose track.
|
||||
*/
|
||||
@ -127,14 +120,14 @@ struct TrackData
|
||||
if (!sizes) return 0.;
|
||||
if (sizes == 1) return trackTableEntry->get_value (base, 0, sizes);
|
||||
|
||||
hb_array_t<const Fixed> size_table ((base+sizeTable).arrayZ, sizes);
|
||||
hb_array_t<const HBFixed> size_table ((base+sizeTable).arrayZ, sizes);
|
||||
unsigned int size_index;
|
||||
for (size_index = 0; size_index < sizes - 1; size_index++)
|
||||
if (size_table[size_index].to_float () >= csspx)
|
||||
if (size_table[size_index].to_float () >= ptem)
|
||||
break;
|
||||
|
||||
return round (interpolate_at (size_index ? size_index - 1 : 0, csspx,
|
||||
*trackTableEntry, base));
|
||||
return roundf (interpolate_at (size_index ? size_index - 1 : 0, ptem,
|
||||
*trackTableEntry, base));
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
@ -148,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. */
|
||||
LOffsetTo<UnsizedArrayOf<Fixed>, false>
|
||||
LNNOffsetTo<UnsizedArrayOf<HBFixed>>
|
||||
sizeTable; /* Offset from start of the tracking table to
|
||||
* Array[nSizes] of size values.. */
|
||||
UnsizedArrayOf<TrackTableEntry>
|
||||
@ -217,7 +210,7 @@ struct trak
|
||||
|
||||
protected:
|
||||
FixedVersion<>version; /* Version of the tracking table
|
||||
* (0x00010000u for version 1.0). */
|
||||
* (0x00010000u for version 1.0). */
|
||||
HBUINT16 format; /* Format of the tracking table (set to 0). */
|
||||
OffsetTo<TrackData>
|
||||
horizData; /* Offset from start of tracking table to TrackData
|
||||
|
||||
@ -25,11 +25,9 @@
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb-open-type.hh"
|
||||
#include "hb.hh"
|
||||
|
||||
#include "hb-ot-face.hh"
|
||||
#include "hb-aat-layout.hh"
|
||||
#include "hb-aat-fdsc-table.hh" // Just so we compile it; unused otherwise.
|
||||
#include "hb-aat-layout-ankr-table.hh"
|
||||
#include "hb-aat-layout-bsln-table.hh" // Just so we compile it; unused otherwise.
|
||||
#include "hb-aat-layout-feat-table.hh"
|
||||
@ -40,6 +38,41 @@
|
||||
#include "hb-aat-ltag-table.hh"
|
||||
|
||||
|
||||
/*
|
||||
* hb_aat_apply_context_t
|
||||
*/
|
||||
|
||||
/* Note: This context is used for kerning, even without AAT, hence the condition. */
|
||||
#if !defined(HB_NO_AAT) || !defined(HB_NO_OT_KERN)
|
||||
|
||||
AAT::hb_aat_apply_context_t::hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
|
||||
hb_font_t *font_,
|
||||
hb_buffer_t *buffer_,
|
||||
hb_blob_t *blob) :
|
||||
plan (plan_),
|
||||
font (font_),
|
||||
face (font->face),
|
||||
buffer (buffer_),
|
||||
sanitizer (),
|
||||
ankr_table (&Null (AAT::ankr)),
|
||||
lookup_index (0)
|
||||
{
|
||||
sanitizer.init (blob);
|
||||
sanitizer.set_num_glyphs (face->get_num_glyphs ());
|
||||
sanitizer.start_processing ();
|
||||
sanitizer.set_max_ops (HB_SANITIZE_MAX_OPS_MAX);
|
||||
}
|
||||
|
||||
AAT::hb_aat_apply_context_t::~hb_aat_apply_context_t ()
|
||||
{ sanitizer.end_processing (); }
|
||||
|
||||
void
|
||||
AAT::hb_aat_apply_context_t::set_ankr_table (const AAT::ankr *ankr_table_)
|
||||
{ ankr_table = ankr_table_; }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-aat-layout
|
||||
* @title: hb-aat-layout
|
||||
@ -50,6 +83,8 @@
|
||||
**/
|
||||
|
||||
|
||||
#if !defined(HB_NO_AAT) || defined(HAVE_CORETEXT)
|
||||
|
||||
/* Table data courtesy of Apple. Converted from mnemonics to integers
|
||||
* when moving to this file. */
|
||||
static const hb_aat_feature_mapping_t feature_mappings[] =
|
||||
@ -135,44 +170,12 @@ static const hb_aat_feature_mapping_t feature_mappings[] =
|
||||
const hb_aat_feature_mapping_t *
|
||||
hb_aat_layout_find_feature_mapping (hb_tag_t tag)
|
||||
{
|
||||
return (const hb_aat_feature_mapping_t *) bsearch (&tag,
|
||||
feature_mappings,
|
||||
ARRAY_LENGTH (feature_mappings),
|
||||
sizeof (feature_mappings[0]),
|
||||
hb_aat_feature_mapping_t::cmp);
|
||||
return hb_sorted_array (feature_mappings).bsearch (tag);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* hb_aat_apply_context_t
|
||||
*/
|
||||
|
||||
AAT::hb_aat_apply_context_t::hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
|
||||
hb_font_t *font_,
|
||||
hb_buffer_t *buffer_,
|
||||
hb_blob_t *blob) :
|
||||
plan (plan_),
|
||||
font (font_),
|
||||
face (font->face),
|
||||
buffer (buffer_),
|
||||
sanitizer (),
|
||||
ankr_table (&Null(AAT::ankr)),
|
||||
lookup_index (0),
|
||||
debug_depth (0)
|
||||
{
|
||||
sanitizer.init (blob);
|
||||
sanitizer.set_num_glyphs (face->get_num_glyphs ());
|
||||
sanitizer.start_processing ();
|
||||
sanitizer.set_max_ops (HB_SANITIZE_MAX_OPS_MAX);
|
||||
}
|
||||
|
||||
AAT::hb_aat_apply_context_t::~hb_aat_apply_context_t ()
|
||||
{ sanitizer.end_processing (); }
|
||||
|
||||
void
|
||||
AAT::hb_aat_apply_context_t::set_ankr_table (const AAT::ankr *ankr_table_)
|
||||
{ ankr_table = ankr_table_; }
|
||||
|
||||
#ifndef HB_NO_AAT
|
||||
|
||||
/*
|
||||
* mort/morx/kerx/trak
|
||||
@ -311,14 +314,6 @@ hb_aat_layout_track (const hb_ot_shape_plan_t *plan,
|
||||
trak.apply (&c);
|
||||
}
|
||||
|
||||
|
||||
hb_language_t
|
||||
_hb_aat_language_get (hb_face_t *face,
|
||||
unsigned int i)
|
||||
{
|
||||
return face->table.ltag->get_language (i);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_aat_layout_get_feature_types:
|
||||
* @face: a face object
|
||||
@ -382,3 +377,6 @@ hb_aat_layout_feature_type_get_selector_infos (hb_face_t
|
||||
{
|
||||
return face->table.feat->get_selector_infos (feature_type, start_offset, selector_count, selectors, default_index);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@ -85,7 +85,7 @@ typedef enum
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_LANGUAGE_TAG_TYPE = 39,
|
||||
HB_AAT_LAYOUT_FEATURE_TYPE_CJK_ROMAN_SPACING_TYPE = 103,
|
||||
|
||||
_HB_AAT_LAYOUT_FEATURE_TYPE_MAX_VALUE= 0x7FFFFFFFu, /*< skip >*/
|
||||
_HB_AAT_LAYOUT_FEATURE_TYPE_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
|
||||
} hb_aat_layout_feature_type_t;
|
||||
|
||||
/**
|
||||
@ -424,7 +424,7 @@ typedef enum
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_DEFAULT_CJK_ROMAN = 2,
|
||||
HB_AAT_LAYOUT_FEATURE_SELECTOR_FULL_WIDTH_CJK_ROMAN = 3,
|
||||
|
||||
_HB_AAT_LAYOUT_FEATURE_SELECTOR_MAX_VALUE= 0x7FFFFFFFu, /*< skip >*/
|
||||
_HB_AAT_LAYOUT_FEATURE_SELECTOR_MAX_VALUE = HB_TAG_MAX_SIGNED /*< skip >*/
|
||||
} hb_aat_layout_feature_selector_t;
|
||||
|
||||
HB_EXTERN unsigned int
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
#include "hb.hh"
|
||||
|
||||
#include "hb-ot-shape.hh"
|
||||
|
||||
#include "hb-aat-ltag-table.hh"
|
||||
|
||||
struct hb_aat_feature_mapping_t
|
||||
{
|
||||
@ -39,14 +39,8 @@ struct hb_aat_feature_mapping_t
|
||||
hb_aat_layout_feature_selector_t selectorToEnable;
|
||||
hb_aat_layout_feature_selector_t selectorToDisable;
|
||||
|
||||
static int cmp (const void *key_, const void *entry_)
|
||||
{
|
||||
hb_tag_t key = * (unsigned int *) key_;
|
||||
const hb_aat_feature_mapping_t * entry = (const hb_aat_feature_mapping_t *) entry_;
|
||||
return key < entry->otFeatureTag ? -1 :
|
||||
key > entry->otFeatureTag ? 1 :
|
||||
0;
|
||||
}
|
||||
int cmp (hb_tag_t key) const
|
||||
{ return key < otFeatureTag ? -1 : key > otFeatureTag ? 1 : 0; }
|
||||
};
|
||||
|
||||
HB_INTERNAL const hb_aat_feature_mapping_t *
|
||||
@ -77,9 +71,5 @@ hb_aat_layout_track (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer);
|
||||
|
||||
HB_INTERNAL hb_language_t
|
||||
_hb_aat_language_get (hb_face_t *face,
|
||||
unsigned int i);
|
||||
|
||||
|
||||
#endif /* HB_AAT_LAYOUT_HH */
|
||||
|
||||
@ -50,7 +50,7 @@ struct FTStringRange
|
||||
}
|
||||
|
||||
protected:
|
||||
NNOffsetTo<UnsizedArrayOf<HBUINT8> >
|
||||
NNOffsetTo<UnsizedArrayOf<HBUINT8>>
|
||||
tag; /* Offset from the start of the table to
|
||||
* the beginning of the string */
|
||||
HBUINT16 length; /* String length (in bytes) */
|
||||
|
||||
@ -26,28 +26,55 @@
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#ifndef HB_NO_AAT_SHAPE
|
||||
|
||||
#include "hb-aat-map.hh"
|
||||
|
||||
#include "hb-aat-layout.hh"
|
||||
#include "hb-aat-layout-feat-table.hh"
|
||||
|
||||
|
||||
void hb_aat_map_builder_t::add_feature (hb_tag_t tag,
|
||||
unsigned int value)
|
||||
void hb_aat_map_builder_t::add_feature (hb_tag_t tag, unsigned value)
|
||||
{
|
||||
if (!face->table.feat->has_data ()) return;
|
||||
|
||||
if (tag == HB_TAG ('a','a','l','t'))
|
||||
{
|
||||
if (!face->table.feat->exposes_feature (HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES))
|
||||
return;
|
||||
feature_info_t *info = features.push();
|
||||
info->type = HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES;
|
||||
info->setting = (hb_aat_layout_feature_selector_t) value;
|
||||
info->seq = features.length;
|
||||
info->is_exclusive = true;
|
||||
return;
|
||||
}
|
||||
|
||||
const hb_aat_feature_mapping_t *mapping = hb_aat_layout_find_feature_mapping (tag);
|
||||
if (!mapping) return;
|
||||
|
||||
const AAT::FeatureName* feature = &face->table.feat->get_feature (mapping->aatFeatureType);
|
||||
if (!feature->has_data ())
|
||||
{
|
||||
/* Special case: Chain::compile_flags will fall back to the deprecated version of
|
||||
* small-caps if necessary, so we need to check for that possibility.
|
||||
* https://github.com/harfbuzz/harfbuzz/issues/2307 */
|
||||
if (mapping->aatFeatureType == HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE &&
|
||||
mapping->selectorToEnable == HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS)
|
||||
{
|
||||
feature = &face->table.feat->get_feature (HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE);
|
||||
if (!feature->has_data ()) return;
|
||||
}
|
||||
else return;
|
||||
}
|
||||
|
||||
feature_info_t *info = features.push();
|
||||
info->type = mapping->aatFeatureType;
|
||||
info->setting = value ? mapping->selectorToEnable : mapping->selectorToDisable;
|
||||
info->seq = features.length;
|
||||
info->is_exclusive = feature->is_exclusive ();
|
||||
}
|
||||
|
||||
void
|
||||
@ -59,10 +86,17 @@ hb_aat_map_builder_t::compile (hb_aat_map_t &m)
|
||||
features.qsort ();
|
||||
unsigned int j = 0;
|
||||
for (unsigned int i = 1; i < features.length; i++)
|
||||
if (features[i].type != features[j].type)
|
||||
if (features[i].type != features[j].type ||
|
||||
/* Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off
|
||||
* respectively, so we mask out the low-order bit when checking for "duplicates"
|
||||
* (selectors referring to the same feature setting) here. */
|
||||
(!features[i].is_exclusive && ((features[i].setting & ~1) != (features[j].setting & ~1))))
|
||||
features[++j] = features[i];
|
||||
features.shrink (j + 1);
|
||||
}
|
||||
|
||||
hb_aat_layout_compile_map (this, &m);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@ -64,19 +64,24 @@ struct hb_aat_map_builder_t
|
||||
{
|
||||
hb_aat_layout_feature_type_t type;
|
||||
hb_aat_layout_feature_selector_t setting;
|
||||
bool is_exclusive;
|
||||
unsigned seq; /* For stable sorting only. */
|
||||
|
||||
static int cmp (const void *pa, const void *pb)
|
||||
HB_INTERNAL static int cmp (const void *pa, const void *pb)
|
||||
{
|
||||
const feature_info_t *a = (const feature_info_t *) pa;
|
||||
const feature_info_t *b = (const feature_info_t *) pb;
|
||||
return (a->type != b->type) ? (a->type < b->type ? -1 : 1) :
|
||||
(a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0);
|
||||
if (a->type != b->type) return (a->type < b->type ? -1 : 1);
|
||||
if (!a->is_exclusive &&
|
||||
(a->setting & ~1) != (b->setting & ~1)) return (a->setting < b->setting ? -1 : 1);
|
||||
return (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0);
|
||||
}
|
||||
|
||||
int cmp (hb_aat_layout_feature_type_t ty) const
|
||||
/* compares type & setting only, not is_exclusive flag or seq number */
|
||||
int cmp (const feature_info_t& f) const
|
||||
{
|
||||
return (type != ty) ? (type < ty ? -1 : 1) : 0;
|
||||
return (f.type != type) ? (f.type < type ? -1 : 1) :
|
||||
(f.setting != setting) ? (f.setting < setting ? -1 : 1) : 0;
|
||||
}
|
||||
};
|
||||
|
||||
@ -84,7 +89,7 @@ struct hb_aat_map_builder_t
|
||||
hb_face_t *face;
|
||||
|
||||
public:
|
||||
hb_vector_t<feature_info_t> features;
|
||||
hb_sorted_vector_t<feature_info_t> features;
|
||||
};
|
||||
|
||||
|
||||
|
||||
1127
src/java.desktop/share/native/libharfbuzz/hb-algs.hh
Normal file
1127
src/java.desktop/share/native/libharfbuzz/hb-algs.hh
Normal file
File diff suppressed because it is too large
Load Diff
@ -28,7 +28,7 @@
|
||||
#define HB_ARRAY_HH
|
||||
|
||||
#include "hb.hh"
|
||||
#include "hb-dsalgs.hh"
|
||||
#include "hb-algs.hh"
|
||||
#include "hb-iter.hh"
|
||||
#include "hb-null.hh"
|
||||
|
||||
@ -37,22 +37,31 @@ template <typename Type>
|
||||
struct hb_sorted_array_t;
|
||||
|
||||
template <typename Type>
|
||||
struct hb_array_t :
|
||||
hb_iter_t<hb_array_t<Type>, Type>,
|
||||
hb_iter_mixin_t<hb_array_t<Type>, Type>
|
||||
struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
|
||||
{
|
||||
/*
|
||||
* Constructors.
|
||||
*/
|
||||
hb_array_t () : arrayZ (nullptr), length (0) {}
|
||||
hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_) {}
|
||||
template <unsigned int length_> hb_array_t (Type (&array_)[length_]) : arrayZ (array_), length (length_) {}
|
||||
hb_array_t () : arrayZ (nullptr), length (0), backwards_length (0) {}
|
||||
hb_array_t (Type *array_, unsigned int length_) : arrayZ (array_), length (length_), backwards_length (0) {}
|
||||
template <unsigned int length_>
|
||||
hb_array_t (Type (&array_)[length_]) : arrayZ (array_), length (length_), backwards_length (0) {}
|
||||
|
||||
template <typename U,
|
||||
hb_enable_if (hb_is_cr_convertible(U, Type))>
|
||||
hb_array_t (const hb_array_t<U> &o) :
|
||||
hb_iter_with_fallback_t<hb_array_t, Type&> (),
|
||||
arrayZ (o.arrayZ), length (o.length), backwards_length (o.backwards_length) {}
|
||||
template <typename U,
|
||||
hb_enable_if (hb_is_cr_convertible(U, Type))>
|
||||
hb_array_t& operator = (const hb_array_t<U> &o)
|
||||
{ arrayZ = o.arrayZ; length = o.length; backwards_length = o.backwards_length; return *this; }
|
||||
|
||||
/*
|
||||
* Iterator implementation.
|
||||
*/
|
||||
typedef Type __item_type__;
|
||||
typedef Type& __item_t__;
|
||||
static constexpr bool is_random_access_iterator = true;
|
||||
Type& __item_at__ (unsigned i) const
|
||||
{
|
||||
if (unlikely (i >= length)) return CrapOrNull (Type);
|
||||
@ -63,16 +72,25 @@ struct hb_array_t :
|
||||
if (unlikely (n > length))
|
||||
n = length;
|
||||
length -= n;
|
||||
backwards_length += n;
|
||||
arrayZ += n;
|
||||
}
|
||||
void __rewind__ (unsigned n)
|
||||
{
|
||||
if (unlikely (n > length))
|
||||
n = length;
|
||||
length -= n;
|
||||
if (unlikely (n > backwards_length))
|
||||
n = backwards_length;
|
||||
length += n;
|
||||
backwards_length -= n;
|
||||
arrayZ -= n;
|
||||
}
|
||||
unsigned __len__ () const { return length; }
|
||||
bool __random_access__ () const { return true; }
|
||||
/* Ouch. The operator== compares the contents of the array. For range-based for loops,
|
||||
* it's best if we can just compare arrayZ, though comparing contents is still fast,
|
||||
* but also would require that Type has operator==. As such, we optimize this operator
|
||||
* for range-based for loop and just compare arrayZ. No need to compare length, as we
|
||||
* assume we're only compared to .end(). */
|
||||
bool operator != (const hb_array_t& o) const
|
||||
{ return arrayZ != o.arrayZ; }
|
||||
|
||||
/* Extra operators.
|
||||
*/
|
||||
@ -80,70 +98,105 @@ struct hb_array_t :
|
||||
operator hb_array_t<const Type> () { return hb_array_t<const Type> (arrayZ, length); }
|
||||
template <typename T> operator T * () const { return arrayZ; }
|
||||
|
||||
HB_INTERNAL bool operator == (const hb_array_t &o) const;
|
||||
|
||||
uint32_t hash () const {
|
||||
uint32_t current = 0;
|
||||
for (unsigned int i = 0; i < this->length; i++) {
|
||||
current = current * 31 + hb_hash (this->arrayZ[i]);
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare, Sort, and Search.
|
||||
*/
|
||||
|
||||
/* Note: our compare is NOT lexicographic; it also does NOT call Type::cmp. */
|
||||
int cmp (const hb_array_t<Type> &a) const
|
||||
int cmp (const hb_array_t &a) const
|
||||
{
|
||||
if (length != a.length)
|
||||
return (int) a.length - (int) length;
|
||||
return hb_memcmp (a.arrayZ, arrayZ, get_size ());
|
||||
}
|
||||
static int cmp (const void *pa, const void *pb)
|
||||
HB_INTERNAL static int cmp (const void *pa, const void *pb)
|
||||
{
|
||||
hb_array_t<Type> *a = (hb_array_t<Type> *) pa;
|
||||
hb_array_t<Type> *b = (hb_array_t<Type> *) pb;
|
||||
hb_array_t *a = (hb_array_t *) pa;
|
||||
hb_array_t *b = (hb_array_t *) pb;
|
||||
return b->cmp (*a);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Type *lsearch (const T &x, Type *not_found = nullptr)
|
||||
{
|
||||
unsigned int count = length;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (!this->arrayZ[i].cmp (x))
|
||||
return &this->arrayZ[i];
|
||||
return not_found;
|
||||
unsigned i;
|
||||
return lfind (x, &i) ? &this->arrayZ[i] : not_found;
|
||||
}
|
||||
template <typename T>
|
||||
const Type *lsearch (const T &x, const Type *not_found = nullptr) const
|
||||
{
|
||||
unsigned int count = length;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
unsigned i;
|
||||
return lfind (x, &i) ? &this->arrayZ[i] : not_found;
|
||||
}
|
||||
template <typename T>
|
||||
bool lfind (const T &x, unsigned *pos = nullptr) const
|
||||
{
|
||||
for (unsigned i = 0; i < length; ++i)
|
||||
if (!this->arrayZ[i].cmp (x))
|
||||
return &this->arrayZ[i];
|
||||
return not_found;
|
||||
{
|
||||
if (pos)
|
||||
*pos = i;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
hb_sorted_array_t<Type> qsort (int (*cmp_)(const void*, const void*))
|
||||
{
|
||||
if (likely (length))
|
||||
::qsort (arrayZ, length, this->item_size, cmp_);
|
||||
hb_qsort (arrayZ, length, this->get_item_size (), cmp_);
|
||||
return hb_sorted_array_t<Type> (*this);
|
||||
}
|
||||
hb_sorted_array_t<Type> qsort ()
|
||||
{
|
||||
if (likely (length))
|
||||
::qsort (arrayZ, length, this->item_size, Type::cmp);
|
||||
hb_qsort (arrayZ, length, this->get_item_size (), Type::cmp);
|
||||
return hb_sorted_array_t<Type> (*this);
|
||||
}
|
||||
void qsort (unsigned int start, unsigned int end)
|
||||
{
|
||||
end = MIN (end, length);
|
||||
end = hb_min (end, length);
|
||||
assert (start <= end);
|
||||
if (likely (start < end))
|
||||
::qsort (arrayZ + start, end - start, this->item_size, Type::cmp);
|
||||
hb_qsort (arrayZ + start, end - start, this->get_item_size (), Type::cmp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Other methods.
|
||||
*/
|
||||
|
||||
unsigned int get_size () const { return length * this->item_size; }
|
||||
unsigned int get_size () const { return length * this->get_item_size (); }
|
||||
|
||||
hb_array_t<Type> sub_array (unsigned int start_offset = 0, unsigned int *seg_count = nullptr /* IN/OUT */) const
|
||||
/*
|
||||
* Reverse the order of items in this array in the range [start, end).
|
||||
*/
|
||||
void reverse (unsigned start = 0, unsigned end = -1)
|
||||
{
|
||||
start = hb_min (start, length);
|
||||
end = hb_min (end, length);
|
||||
|
||||
if (end < start + 2)
|
||||
return;
|
||||
|
||||
for (unsigned lhs = start, rhs = end - 1; lhs < rhs; lhs++, rhs--) {
|
||||
Type temp = arrayZ[rhs];
|
||||
arrayZ[rhs] = arrayZ[lhs];
|
||||
arrayZ[lhs] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
hb_array_t sub_array (unsigned int start_offset = 0, unsigned int *seg_count = nullptr /* IN/OUT */) const
|
||||
{
|
||||
if (!start_offset && !seg_count)
|
||||
return *this;
|
||||
@ -154,16 +207,45 @@ struct hb_array_t :
|
||||
else
|
||||
count -= start_offset;
|
||||
if (seg_count)
|
||||
count = *seg_count = MIN (count, *seg_count);
|
||||
return hb_array_t<Type> (arrayZ + start_offset, count);
|
||||
count = *seg_count = hb_min (count, *seg_count);
|
||||
return hb_array_t (arrayZ + start_offset, count);
|
||||
}
|
||||
hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int seg_count) const
|
||||
hb_array_t sub_array (unsigned int start_offset, unsigned int seg_count) const
|
||||
{ return sub_array (start_offset, &seg_count); }
|
||||
|
||||
hb_array_t truncate (unsigned length) const { return sub_array (0, length); }
|
||||
|
||||
template <typename T,
|
||||
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); }
|
||||
|
||||
template <typename T,
|
||||
unsigned P = sizeof (Type),
|
||||
hb_enable_if (P == 1)>
|
||||
bool check_range (const T *p, unsigned int size = T::static_size) const
|
||||
{
|
||||
return arrayZ <= ((const char *) p)
|
||||
&& ((const char *) p) <= arrayZ + length
|
||||
&& (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; }
|
||||
|
||||
template <typename hb_serialize_context_t>
|
||||
hb_array_t copy (hb_serialize_context_t *c) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
auto* out = c->start_embed (arrayZ);
|
||||
if (unlikely (!c->extend_size (out, get_size ()))) return_trace (hb_array_t ());
|
||||
for (unsigned i = 0; i < length; i++)
|
||||
out[i] = arrayZ[i]; /* TODO: add version that calls c->copy() */
|
||||
return_trace (hb_array_t (out, length));
|
||||
}
|
||||
|
||||
template <typename hb_sanitize_context_t>
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{ return c->check_array (arrayZ, length); }
|
||||
@ -175,6 +257,7 @@ struct hb_array_t :
|
||||
public:
|
||||
Type *arrayZ;
|
||||
unsigned int length;
|
||||
unsigned int backwards_length;
|
||||
};
|
||||
template <typename T> inline hb_array_t<T>
|
||||
hb_array (T *array, unsigned int length)
|
||||
@ -183,7 +266,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,
|
||||
@ -193,20 +275,40 @@ enum hb_bfind_not_found_t
|
||||
|
||||
template <typename Type>
|
||||
struct hb_sorted_array_t :
|
||||
hb_sorted_iter_t<hb_sorted_array_t<Type>, Type>,
|
||||
hb_array_t<Type>,
|
||||
hb_iter_mixin_t<hb_sorted_array_t<Type>, Type>
|
||||
hb_iter_t<hb_sorted_array_t<Type>, Type&>,
|
||||
hb_array_t<Type>
|
||||
{
|
||||
hb_sorted_array_t () : hb_array_t<Type> () {}
|
||||
hb_sorted_array_t (const hb_array_t<Type> &o) : hb_array_t<Type> (o) {}
|
||||
hb_sorted_array_t (Type *array_, unsigned int length_) : hb_array_t<Type> (array_, length_) {}
|
||||
template <unsigned int length_> hb_sorted_array_t (Type (&array_)[length_]) : hb_array_t<Type> (array_) {}
|
||||
typedef hb_iter_t<hb_sorted_array_t, Type&> iter_base_t;
|
||||
HB_ITER_USING (iter_base_t);
|
||||
static constexpr bool is_random_access_iterator = true;
|
||||
static constexpr bool is_sorted_iterator = true;
|
||||
|
||||
hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const
|
||||
{ return hb_sorted_array_t<Type> (((const hb_array_t<Type> *) (this))->sub_array (start_offset, seg_count)); }
|
||||
hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int seg_count) const
|
||||
hb_sorted_array_t () : hb_array_t<Type> () {}
|
||||
hb_sorted_array_t (Type *array_, unsigned int length_) : hb_array_t<Type> (array_, length_) {}
|
||||
template <unsigned int length_>
|
||||
hb_sorted_array_t (Type (&array_)[length_]) : hb_array_t<Type> (array_) {}
|
||||
|
||||
template <typename U,
|
||||
hb_enable_if (hb_is_cr_convertible(U, Type))>
|
||||
hb_sorted_array_t (const hb_array_t<U> &o) :
|
||||
hb_iter_t<hb_sorted_array_t, Type&> (),
|
||||
hb_array_t<Type> (o) {}
|
||||
template <typename U,
|
||||
hb_enable_if (hb_is_cr_convertible(U, Type))>
|
||||
hb_sorted_array_t& operator = (const hb_array_t<U> &o)
|
||||
{ hb_array_t<Type> (*this) = o; return *this; }
|
||||
|
||||
/* Iterator implementation. */
|
||||
bool operator != (const hb_sorted_array_t& o) const
|
||||
{ return this->arrayZ != o.arrayZ || this->length != o.length; }
|
||||
|
||||
hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int *seg_count /* IN/OUT */) const
|
||||
{ return hb_sorted_array_t (((const hb_array_t<Type> *) (this))->sub_array (start_offset, seg_count)); }
|
||||
hb_sorted_array_t sub_array (unsigned int start_offset, unsigned int seg_count) const
|
||||
{ return sub_array (start_offset, &seg_count); }
|
||||
|
||||
hb_sorted_array_t truncate (unsigned length) const { return sub_array (0, length); }
|
||||
|
||||
template <typename T>
|
||||
Type *bsearch (const T &x, Type *not_found = nullptr)
|
||||
{
|
||||
@ -221,26 +323,18 @@ 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,
|
||||
unsigned int to_store = (unsigned int) -1) const
|
||||
hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
|
||||
unsigned int to_store = (unsigned int) -1) const
|
||||
{
|
||||
int min = 0, max = (int) this->length - 1;
|
||||
const Type *array = this->arrayZ;
|
||||
while (min <= max)
|
||||
unsigned pos;
|
||||
|
||||
if (bsearch_impl (x, &pos))
|
||||
{
|
||||
int mid = ((unsigned int) min + (unsigned int) max) / 2;
|
||||
int c = array[mid].cmp (x);
|
||||
if (c < 0)
|
||||
max = mid - 1;
|
||||
else if (c > 0)
|
||||
min = mid + 1;
|
||||
else
|
||||
{
|
||||
if (i)
|
||||
*i = mid;
|
||||
return true;
|
||||
}
|
||||
if (i)
|
||||
*i = pos;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (i)
|
||||
{
|
||||
switch (not_found)
|
||||
@ -253,14 +347,22 @@ struct hb_sorted_array_t :
|
||||
break;
|
||||
|
||||
case HB_BFIND_NOT_FOUND_STORE_CLOSEST:
|
||||
if (max < 0 || (max < (int) this->length && array[max].cmp (x) > 0))
|
||||
max++;
|
||||
*i = max;
|
||||
*i = pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
template <typename T>
|
||||
bool bsearch_impl (const T &x, unsigned *pos) const
|
||||
{
|
||||
return hb_bsearch_impl (pos,
|
||||
x,
|
||||
this->arrayZ,
|
||||
this->length,
|
||||
sizeof (Type),
|
||||
_hb_cmp_method<T, Type>);
|
||||
}
|
||||
};
|
||||
template <typename T> inline hb_sorted_array_t<T>
|
||||
hb_sorted_array (T *array, unsigned int length)
|
||||
@ -269,9 +371,38 @@ template <typename T, unsigned int length_> inline hb_sorted_array_t<T>
|
||||
hb_sorted_array (T (&array_)[length_])
|
||||
{ return hb_sorted_array_t<T> (array_); }
|
||||
|
||||
template <typename T>
|
||||
bool hb_array_t<T>::operator == (const hb_array_t<T> &o) const
|
||||
{
|
||||
if (o.length != this->length) return false;
|
||||
for (unsigned int i = 0; i < this->length; i++) {
|
||||
if (this->arrayZ[i] != o.arrayZ[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* TODO Specialize opeator== for hb_bytes_t and hb_ubytes_t. */
|
||||
|
||||
template <>
|
||||
inline uint32_t hb_array_t<const char>::hash () const {
|
||||
uint32_t current = 0;
|
||||
for (unsigned int i = 0; i < this->length; i++)
|
||||
current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u);
|
||||
return current;
|
||||
}
|
||||
|
||||
template <>
|
||||
inline uint32_t hb_array_t<const unsigned char>::hash () const {
|
||||
uint32_t current = 0;
|
||||
for (unsigned int i = 0; i < this->length; i++)
|
||||
current = current * 31 + (uint32_t) (this->arrayZ[i] * 2654435761u);
|
||||
return current;
|
||||
}
|
||||
|
||||
|
||||
typedef hb_array_t<const char> hb_bytes_t;
|
||||
typedef hb_array_t<const unsigned char> hb_ubytes_t;
|
||||
|
||||
|
||||
|
||||
#endif /* HB_ARRAY_HH */
|
||||
|
||||
@ -33,6 +33,7 @@
|
||||
#define HB_ATOMIC_HH
|
||||
|
||||
#include "hb.hh"
|
||||
#include "hb-meta.hh"
|
||||
|
||||
|
||||
/*
|
||||
@ -85,11 +86,11 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
|
||||
#define hb_atomic_int_impl_add(AI, V) (reinterpret_cast<std::atomic<int> *> (AI)->fetch_add ((V), std::memory_order_acq_rel))
|
||||
#define hb_atomic_int_impl_set_relaxed(AI, V) (reinterpret_cast<std::atomic<int> *> (AI)->store ((V), std::memory_order_relaxed))
|
||||
#define hb_atomic_int_impl_set(AI, V) (reinterpret_cast<std::atomic<int> *> (AI)->store ((V), std::memory_order_release))
|
||||
#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast<std::atomic<int> *> (AI)->load (std::memory_order_relaxed))
|
||||
#define hb_atomic_int_impl_get(AI) (reinterpret_cast<std::atomic<int> *> (AI)->load (std::memory_order_acquire))
|
||||
#define hb_atomic_int_impl_get_relaxed(AI) (reinterpret_cast<std::atomic<int> const *> (AI)->load (std::memory_order_relaxed))
|
||||
#define hb_atomic_int_impl_get(AI) (reinterpret_cast<std::atomic<int> const *> (AI)->load (std::memory_order_acquire))
|
||||
|
||||
#define hb_atomic_ptr_impl_set_relaxed(P, V) (reinterpret_cast<std::atomic<void*> *> (P)->store ((V), std::memory_order_relaxed))
|
||||
#define hb_atomic_ptr_impl_get_relaxed(P) (reinterpret_cast<std::atomic<void*> *> (P)->load (std::memory_order_relaxed))
|
||||
#define hb_atomic_ptr_impl_get_relaxed(P) (reinterpret_cast<std::atomic<void*> const *> (P)->load (std::memory_order_relaxed))
|
||||
#define hb_atomic_ptr_impl_get(P) (reinterpret_cast<std::atomic<void*> *> (P)->load (std::memory_order_acquire))
|
||||
static inline bool
|
||||
_hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
|
||||
@ -106,7 +107,7 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
|
||||
|
||||
static inline void _hb_memory_barrier ()
|
||||
{
|
||||
#if !defined(MemoryBarrier)
|
||||
#if !defined(MemoryBarrier) && !defined(__MINGW32_VERSION)
|
||||
/* MinGW has a convoluted history of supporting MemoryBarrier. */
|
||||
LONG dummy = 0;
|
||||
InterlockedExchange (&dummy, 1);
|
||||
@ -211,25 +212,19 @@ static inline bool _hb_compare_and_swaplp (long *P, long O, long N)
|
||||
static_assert ((sizeof (long) == sizeof (void *)), "");
|
||||
|
||||
|
||||
#elif !defined(HB_NO_MT)
|
||||
|
||||
#define HB_ATOMIC_INT_NIL 1 /* Warn that fallback implementation is in use. */
|
||||
|
||||
#define _hb_memory_barrier()
|
||||
#elif defined(HB_NO_MT)
|
||||
|
||||
#define hb_atomic_int_impl_add(AI, V) ((*(AI) += (V)) - (V))
|
||||
|
||||
#define _hb_memory_barrier() do {} while (0)
|
||||
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
|
||||
|
||||
|
||||
#else /* HB_NO_MT */
|
||||
|
||||
#define hb_atomic_int_impl_add(AI, V) ((*(AI) += (V)) - (V))
|
||||
|
||||
#define _hb_memory_barrier()
|
||||
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
|
||||
#else
|
||||
|
||||
#error "Could not find any system to define atomic_int macros."
|
||||
#error "Check hb-atomic.hh for possible resolutions."
|
||||
|
||||
#endif
|
||||
|
||||
@ -282,7 +277,7 @@ struct hb_atomic_int_t
|
||||
template <typename P>
|
||||
struct hb_atomic_ptr_t
|
||||
{
|
||||
typedef typename hb_remove_pointer (P) T;
|
||||
typedef hb_remove_pointer<P> T;
|
||||
|
||||
void init (T* v_ = nullptr) { set_relaxed (v_); }
|
||||
void set_relaxed (T* v_) { hb_atomic_ptr_impl_set_relaxed (&v, v_); }
|
||||
|
||||
166
src/java.desktop/share/native/libharfbuzz/hb-bimap.hh
Normal file
166
src/java.desktop/share/native/libharfbuzz/hb-bimap.hh
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* Copyright © 2019 Adobe 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.
|
||||
*
|
||||
* Adobe Author(s): Michiharu Ariza
|
||||
*/
|
||||
|
||||
#ifndef HB_BIMAP_HH
|
||||
#define HB_BIMAP_HH
|
||||
|
||||
#include "hb.hh"
|
||||
#include "hb-map.hh"
|
||||
|
||||
/* Bi-directional map */
|
||||
struct hb_bimap_t
|
||||
{
|
||||
hb_bimap_t () { init (); }
|
||||
~hb_bimap_t () { fini (); }
|
||||
|
||||
void init ()
|
||||
{
|
||||
forw_map.init ();
|
||||
back_map.init ();
|
||||
}
|
||||
|
||||
void fini ()
|
||||
{
|
||||
forw_map.fini ();
|
||||
back_map.fini ();
|
||||
}
|
||||
|
||||
void reset ()
|
||||
{
|
||||
forw_map.reset ();
|
||||
back_map.reset ();
|
||||
}
|
||||
|
||||
bool in_error () const { return forw_map.in_error () || back_map.in_error (); }
|
||||
|
||||
void set (hb_codepoint_t lhs, hb_codepoint_t rhs)
|
||||
{
|
||||
if (unlikely (lhs == HB_MAP_VALUE_INVALID)) return;
|
||||
if (unlikely (rhs == HB_MAP_VALUE_INVALID)) { del (lhs); return; }
|
||||
forw_map.set (lhs, rhs);
|
||||
back_map.set (rhs, lhs);
|
||||
}
|
||||
|
||||
hb_codepoint_t get (hb_codepoint_t lhs) const { return forw_map.get (lhs); }
|
||||
hb_codepoint_t backward (hb_codepoint_t rhs) const { return back_map.get (rhs); }
|
||||
|
||||
hb_codepoint_t operator [] (hb_codepoint_t lhs) const { return get (lhs); }
|
||||
bool has (hb_codepoint_t lhs, hb_codepoint_t *vp = nullptr) const { return forw_map.has (lhs, vp); }
|
||||
|
||||
void del (hb_codepoint_t lhs)
|
||||
{
|
||||
back_map.del (get (lhs));
|
||||
forw_map.del (lhs);
|
||||
}
|
||||
|
||||
void clear ()
|
||||
{
|
||||
forw_map.clear ();
|
||||
back_map.clear ();
|
||||
}
|
||||
|
||||
bool is_empty () const { return get_population () == 0; }
|
||||
|
||||
unsigned int get_population () const { return forw_map.get_population (); }
|
||||
|
||||
protected:
|
||||
hb_map_t forw_map;
|
||||
hb_map_t back_map;
|
||||
};
|
||||
|
||||
/* Inremental bimap: only lhs is given, rhs is incrementally assigned */
|
||||
struct hb_inc_bimap_t : hb_bimap_t
|
||||
{
|
||||
hb_inc_bimap_t () { init (); }
|
||||
|
||||
void init ()
|
||||
{
|
||||
hb_bimap_t::init ();
|
||||
next_value = 0;
|
||||
}
|
||||
|
||||
/* Add a mapping from lhs to rhs with a unique value if lhs is unknown.
|
||||
* Return the rhs value as the result.
|
||||
*/
|
||||
hb_codepoint_t add (hb_codepoint_t lhs)
|
||||
{
|
||||
hb_codepoint_t rhs = forw_map[lhs];
|
||||
if (rhs == HB_MAP_VALUE_INVALID)
|
||||
{
|
||||
rhs = next_value++;
|
||||
set (lhs, rhs);
|
||||
}
|
||||
return rhs;
|
||||
}
|
||||
|
||||
hb_codepoint_t skip ()
|
||||
{ return next_value++; }
|
||||
|
||||
hb_codepoint_t get_next_value () const
|
||||
{ return next_value; }
|
||||
|
||||
void add_set (const hb_set_t *set)
|
||||
{
|
||||
hb_codepoint_t i = HB_SET_VALUE_INVALID;
|
||||
while (hb_set_next (set, &i)) add (i);
|
||||
}
|
||||
|
||||
/* Create an identity map. */
|
||||
bool identity (unsigned int size)
|
||||
{
|
||||
clear ();
|
||||
for (hb_codepoint_t i = 0; i < size; i++) set (i, i);
|
||||
return !in_error ();
|
||||
}
|
||||
|
||||
protected:
|
||||
static int cmp_id (const void* a, const void* b)
|
||||
{ return (int)*(const hb_codepoint_t *)a - (int)*(const hb_codepoint_t *)b; }
|
||||
|
||||
public:
|
||||
/* Optional: after finished adding all mappings in a random order,
|
||||
* reassign rhs to lhs so that they are in the same order. */
|
||||
void sort ()
|
||||
{
|
||||
hb_codepoint_t count = get_population ();
|
||||
hb_vector_t <hb_codepoint_t> work;
|
||||
work.resize (count);
|
||||
|
||||
for (hb_codepoint_t rhs = 0; rhs < count; rhs++)
|
||||
work[rhs] = back_map[rhs];
|
||||
|
||||
work.qsort (cmp_id);
|
||||
|
||||
clear ();
|
||||
for (hb_codepoint_t rhs = 0; rhs < count; rhs++)
|
||||
set (work[rhs], rhs);
|
||||
}
|
||||
|
||||
protected:
|
||||
unsigned int next_value;
|
||||
};
|
||||
|
||||
#endif /* HB_BIMAP_HH */
|
||||
@ -25,18 +25,6 @@
|
||||
* Red Hat Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
|
||||
/* https://github.com/harfbuzz/harfbuzz/issues/1308
|
||||
* http://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html
|
||||
* https://www.oracle.com/technetwork/articles/servers-storage-dev/standardheaderfiles-453865.html
|
||||
*/
|
||||
#ifndef _POSIX_C_SOURCE
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wunused-macros"
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#include "hb.hh"
|
||||
#include "hb-blob.hh"
|
||||
|
||||
@ -48,7 +36,6 @@
|
||||
#endif /* HAVE_SYS_MMAN_H */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
@ -155,7 +142,7 @@ hb_blob_create_sub_blob (hb_blob_t *parent,
|
||||
hb_blob_make_immutable (parent);
|
||||
|
||||
blob = hb_blob_create (parent->data + offset,
|
||||
MIN (length, parent->length - offset),
|
||||
hb_min (length, parent->length - offset),
|
||||
HB_MEMORY_MODE_READONLY,
|
||||
hb_blob_reference (parent),
|
||||
_hb_blob_destroy);
|
||||
@ -202,7 +189,7 @@ hb_blob_copy_writable_or_fail (hb_blob_t *blob)
|
||||
hb_blob_t *
|
||||
hb_blob_get_empty ()
|
||||
{
|
||||
return const_cast<hb_blob_t *> (&Null(hb_blob_t));
|
||||
return const_cast<hb_blob_t *> (&Null (hb_blob_t));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -487,7 +474,11 @@ hb_blob_t::try_make_writable ()
|
||||
* Mmap
|
||||
*/
|
||||
|
||||
#ifndef HB_NO_OPEN
|
||||
#ifdef HAVE_MMAP
|
||||
# if !defined(HB_NO_RESOURCE_FORK) && defined(__APPLE__)
|
||||
# include <sys/paths.h>
|
||||
# endif
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
# include <fcntl.h>
|
||||
@ -532,6 +523,39 @@ _hb_mapped_file_destroy (void *file_)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _PATH_RSRCFORKSPEC
|
||||
static int
|
||||
_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);
|
||||
if (unlikely (!rsrc_name)) return -1;
|
||||
|
||||
strncpy (rsrc_name, file_name, name_len);
|
||||
strncpy (rsrc_name + name_len, _PATH_RSRCFORKSPEC,
|
||||
sizeof (_PATH_RSRCFORKSPEC) - 1);
|
||||
|
||||
int fd = open (rsrc_name, O_RDONLY | O_BINARY, 0);
|
||||
free (rsrc_name);
|
||||
|
||||
if (fd != -1)
|
||||
{
|
||||
struct stat st;
|
||||
if (fstat (fd, &st) != -1)
|
||||
file->length = (unsigned long) st.st_size;
|
||||
else
|
||||
{
|
||||
close (fd);
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* hb_blob_create_from_file:
|
||||
* @file_name: font filename.
|
||||
@ -556,6 +580,19 @@ hb_blob_create_from_file (const char *file_name)
|
||||
if (unlikely (fstat (fd, &st) == -1)) goto fail;
|
||||
|
||||
file->length = (unsigned long) st.st_size;
|
||||
|
||||
#ifdef _PATH_RSRCFORKSPEC
|
||||
if (unlikely (file->length == 0))
|
||||
{
|
||||
int rfd = _open_resource_fork (file_name, file);
|
||||
if (rfd != -1)
|
||||
{
|
||||
close (fd);
|
||||
fd = rfd;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
file->contents = (char *) mmap (nullptr, file->length, PROT_READ,
|
||||
MAP_PRIVATE | MAP_NORESERVE, fd, 0);
|
||||
|
||||
@ -579,9 +616,9 @@ fail_without_close:
|
||||
HANDLE fd;
|
||||
unsigned int size = strlen (file_name) + 1;
|
||||
wchar_t * wchar_file_name = (wchar_t *) malloc (sizeof (wchar_t) * size);
|
||||
if (unlikely (wchar_file_name == nullptr)) goto fail_without_close;
|
||||
if (unlikely (!wchar_file_name)) goto fail_without_close;
|
||||
mbstowcs (wchar_file_name, file_name, size);
|
||||
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
|
||||
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
|
||||
{
|
||||
CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 };
|
||||
ceparams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
|
||||
@ -602,7 +639,7 @@ fail_without_close:
|
||||
|
||||
if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close;
|
||||
|
||||
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
|
||||
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
|
||||
{
|
||||
LARGE_INTEGER length;
|
||||
GetFileSizeEx (fd, &length);
|
||||
@ -613,14 +650,14 @@ fail_without_close:
|
||||
file->length = (unsigned long) GetFileSize (fd, nullptr);
|
||||
file->mapping = CreateFileMapping (fd, nullptr, PAGE_READONLY, 0, 0, nullptr);
|
||||
#endif
|
||||
if (unlikely (file->mapping == nullptr)) goto fail;
|
||||
if (unlikely (!file->mapping)) goto fail;
|
||||
|
||||
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
|
||||
#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
|
||||
file->contents = (char *) MapViewOfFileFromApp (file->mapping, FILE_MAP_READ, 0, 0);
|
||||
#else
|
||||
file->contents = (char *) MapViewOfFile (file->mapping, FILE_MAP_READ, 0, 0, 0);
|
||||
#endif
|
||||
if (unlikely (file->contents == nullptr)) goto fail;
|
||||
if (unlikely (!file->contents)) goto fail;
|
||||
|
||||
CloseHandle (fd);
|
||||
return hb_blob_create (file->contents, file->length,
|
||||
@ -638,10 +675,10 @@ fail_without_close:
|
||||
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 == nullptr)) return hb_blob_get_empty ();
|
||||
if (unlikely (!data)) return hb_blob_get_empty ();
|
||||
|
||||
FILE *fp = fopen (file_name, "rb");
|
||||
if (unlikely (fp == nullptr)) goto fread_fail_without_close;
|
||||
if (unlikely (!fp)) goto fread_fail_without_close;
|
||||
|
||||
while (!feof (fp))
|
||||
{
|
||||
@ -652,7 +689,7 @@ fail_without_close:
|
||||
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);
|
||||
if (unlikely (new_data == nullptr)) goto fread_fail;
|
||||
if (unlikely (!new_data)) goto fread_fail;
|
||||
data = new_data;
|
||||
}
|
||||
|
||||
@ -666,6 +703,7 @@ fail_without_close:
|
||||
|
||||
len += addition;
|
||||
}
|
||||
fclose (fp);
|
||||
|
||||
return hb_blob_create (data, len, HB_MEMORY_MODE_WRITABLE, data,
|
||||
(hb_destroy_func_t) free);
|
||||
@ -676,3 +714,4 @@ fread_fail_without_close:
|
||||
free (data);
|
||||
return hb_blob_get_empty ();
|
||||
}
|
||||
#endif /* !HB_NO_OPEN */
|
||||
|
||||
@ -71,6 +71,9 @@ hb_blob_create (const char *data,
|
||||
void *user_data,
|
||||
hb_destroy_func_t destroy);
|
||||
|
||||
HB_EXTERN hb_blob_t *
|
||||
hb_blob_create_from_file (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
|
||||
@ -123,9 +126,6 @@ hb_blob_get_data (hb_blob_t *blob, unsigned int *length);
|
||||
HB_EXTERN char *
|
||||
hb_blob_get_data_writable (hb_blob_t *blob, unsigned int *length);
|
||||
|
||||
HB_EXTERN hb_blob_t *
|
||||
hb_blob_create_from_file (const char *file_name);
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
#endif /* HB_BLOB_H */
|
||||
|
||||
@ -54,13 +54,9 @@ struct hb_blob_t
|
||||
HB_INTERNAL bool try_make_writable_inplace ();
|
||||
HB_INTERNAL bool try_make_writable_inplace_unix ();
|
||||
|
||||
hb_bytes_t as_bytes () const { return hb_bytes_t (data, length); }
|
||||
template <typename Type>
|
||||
const Type* as () const
|
||||
{
|
||||
return length < hb_null_size (Type) ? &Null(Type) : reinterpret_cast<const Type *> (data);
|
||||
}
|
||||
hb_bytes_t as_bytes () const
|
||||
{ return hb_bytes_t (data, length); }
|
||||
const Type* as () const { return as_bytes ().as<Type> (); }
|
||||
|
||||
public:
|
||||
hb_object_header_t header;
|
||||
@ -81,7 +77,7 @@ struct hb_blob_t
|
||||
template <typename P>
|
||||
struct hb_blob_ptr_t
|
||||
{
|
||||
typedef typename hb_remove_pointer (P) T;
|
||||
typedef hb_remove_pointer<P> T;
|
||||
|
||||
hb_blob_ptr_t (hb_blob_t *b_ = nullptr) : b (b_) {}
|
||||
hb_blob_t * operator = (hb_blob_t *b_) { return b = b_; }
|
||||
|
||||
@ -24,6 +24,10 @@
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#ifndef HB_NO_BUFFER_SERIALIZE
|
||||
|
||||
#include "hb-buffer.hh"
|
||||
|
||||
|
||||
@ -85,7 +89,7 @@ hb_buffer_serialize_format_from_string (const char *str, int len)
|
||||
const char *
|
||||
hb_buffer_serialize_format_to_string (hb_buffer_serialize_format_t format)
|
||||
{
|
||||
switch (format)
|
||||
switch ((unsigned) format)
|
||||
{
|
||||
case HB_BUFFER_SERIALIZE_FORMAT_TEXT: return serialize_formats[0];
|
||||
case HB_BUFFER_SERIALIZE_FORMAT_JSON: return serialize_formats[1];
|
||||
@ -138,34 +142,34 @@ _hb_buffer_serialize_glyphs_json (hb_buffer_t *buffer,
|
||||
*p++ = '"';
|
||||
}
|
||||
else
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
|
||||
|
||||
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"cl\":%u", info[i].cluster));
|
||||
}
|
||||
|
||||
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
|
||||
{
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"dx\":%d,\"dy\":%d",
|
||||
x+pos[i].x_offset, y+pos[i].y_offset));
|
||||
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"ax\":%d,\"ay\":%d",
|
||||
pos[i].x_advance, pos[i].y_advance));
|
||||
}
|
||||
|
||||
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
|
||||
{
|
||||
if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"fl\":%u", info[i].mask & HB_GLYPH_FLAG_DEFINED));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"fl\":%u", info[i].mask & HB_GLYPH_FLAG_DEFINED));
|
||||
}
|
||||
|
||||
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
|
||||
{
|
||||
hb_glyph_extents_t extents;
|
||||
hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"xb\":%d,\"yb\":%d",
|
||||
extents.x_bearing, extents.y_bearing));
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",\"w\":%d,\"h\":%d",
|
||||
extents.width, extents.height));
|
||||
}
|
||||
|
||||
@ -224,37 +228,37 @@ _hb_buffer_serialize_glyphs_text (hb_buffer_t *buffer,
|
||||
p += strlen (p);
|
||||
}
|
||||
else
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%u", info[i].codepoint));
|
||||
|
||||
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS)) {
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "=%u", info[i].cluster));
|
||||
}
|
||||
|
||||
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS))
|
||||
{
|
||||
if (x+pos[i].x_offset || y+pos[i].y_offset)
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", x+pos[i].x_offset, y+pos[i].y_offset));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "@%d,%d", x+pos[i].x_offset, y+pos[i].y_offset));
|
||||
|
||||
if (!(flags & HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES))
|
||||
{
|
||||
*p++ = '+';
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "%d", pos[i].x_advance));
|
||||
if (pos[i].y_advance)
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), ",%d", pos[i].y_advance));
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS)
|
||||
{
|
||||
if (info[i].mask & HB_GLYPH_FLAG_DEFINED)
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X", info[i].mask &HB_GLYPH_FLAG_DEFINED));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "#%X", info[i].mask &HB_GLYPH_FLAG_DEFINED));
|
||||
}
|
||||
|
||||
if (flags & HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS)
|
||||
{
|
||||
hb_glyph_extents_t extents;
|
||||
hb_font_get_glyph_extents(font, info[i].codepoint, &extents);
|
||||
p += MAX (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
|
||||
p += hb_max (0, snprintf (p, ARRAY_LENGTH (b) - (p - b), "<%d,%d,%d,%d>", extents.x_bearing, extents.y_bearing, extents.width, extents.height));
|
||||
}
|
||||
|
||||
unsigned int l = p - b;
|
||||
@ -344,8 +348,8 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
|
||||
if (buf_size)
|
||||
*buf = '\0';
|
||||
|
||||
assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
|
||||
buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
|
||||
assert ((!buffer->len && (buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID)) ||
|
||||
(buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS));
|
||||
|
||||
if (!buffer->have_positions)
|
||||
flags |= HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS;
|
||||
@ -375,43 +379,24 @@ hb_buffer_serialize_glyphs (hb_buffer_t *buffer,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static hb_bool_t
|
||||
parse_uint (const char *pp, const char *end, uint32_t *pv)
|
||||
static bool
|
||||
parse_int (const char *pp, const char *end, int32_t *pv)
|
||||
{
|
||||
char buf[32];
|
||||
unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
|
||||
strncpy (buf, pp, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
char *p = buf;
|
||||
char *pend = p;
|
||||
uint32_t v;
|
||||
|
||||
errno = 0;
|
||||
v = strtol (p, &pend, 10);
|
||||
if (errno || p == pend || pend - p != end - pp)
|
||||
int v;
|
||||
const char *p = pp;
|
||||
if (unlikely (!hb_parse_int (&p, end, &v, true/* whole buffer */)))
|
||||
return false;
|
||||
|
||||
*pv = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
parse_int (const char *pp, const char *end, int32_t *pv)
|
||||
static bool
|
||||
parse_uint (const char *pp, const char *end, uint32_t *pv)
|
||||
{
|
||||
char buf[32];
|
||||
unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - pp));
|
||||
strncpy (buf, pp, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
char *p = buf;
|
||||
char *pend = p;
|
||||
int32_t v;
|
||||
|
||||
errno = 0;
|
||||
v = strtol (p, &pend, 10);
|
||||
if (errno || p == pend || pend - p != end - pp)
|
||||
unsigned int v;
|
||||
const char *p = pp;
|
||||
if (unlikely (!hb_parse_uint (&p, end, &v, true/* whole buffer */)))
|
||||
return false;
|
||||
|
||||
*pv = v;
|
||||
@ -449,8 +434,8 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
|
||||
end_ptr = &end;
|
||||
*end_ptr = buf;
|
||||
|
||||
assert ((!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID) ||
|
||||
buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS);
|
||||
assert ((!buffer->len && (buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID)) ||
|
||||
(buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS));
|
||||
|
||||
if (buf_len == -1)
|
||||
buf_len = strlen (buf);
|
||||
@ -484,3 +469,6 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@ -324,7 +324,7 @@ hb_buffer_t::clear_positions ()
|
||||
out_len = 0;
|
||||
out_info = info;
|
||||
|
||||
memset (pos, 0, sizeof (pos[0]) * len);
|
||||
hb_memset (pos, 0, sizeof (pos[0]) * len);
|
||||
}
|
||||
|
||||
void
|
||||
@ -438,13 +438,6 @@ hb_buffer_t::set_masks (hb_mask_t value,
|
||||
if (!mask)
|
||||
return;
|
||||
|
||||
if (cluster_start == 0 && cluster_end == (unsigned int)-1) {
|
||||
unsigned int count = len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
info[i].mask = (info[i].mask & not_mask) | value;
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int count = len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (cluster_start <= info[i].cluster && info[i].cluster < cluster_end)
|
||||
@ -455,27 +448,13 @@ void
|
||||
hb_buffer_t::reverse_range (unsigned int start,
|
||||
unsigned int end)
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
if (end - start < 2)
|
||||
return;
|
||||
|
||||
for (i = start, j = end - 1; i < j; i++, j--) {
|
||||
hb_glyph_info_t t;
|
||||
|
||||
t = info[i];
|
||||
info[i] = info[j];
|
||||
info[j] = t;
|
||||
}
|
||||
hb_array_t<hb_glyph_info_t> (info, len).reverse (start, end);
|
||||
|
||||
if (have_positions) {
|
||||
for (i = start, j = end - 1; i < j; i++, j--) {
|
||||
hb_glyph_position_t t;
|
||||
|
||||
t = pos[i];
|
||||
pos[i] = pos[j];
|
||||
pos[j] = t;
|
||||
}
|
||||
hb_array_t<hb_glyph_position_t> (pos, len).reverse (start, end);
|
||||
}
|
||||
}
|
||||
|
||||
@ -524,7 +503,7 @@ hb_buffer_t::merge_clusters_impl (unsigned int start,
|
||||
unsigned int cluster = info[start].cluster;
|
||||
|
||||
for (unsigned int i = start + 1; i < end; i++)
|
||||
cluster = MIN<unsigned int> (cluster, info[i].cluster);
|
||||
cluster = hb_min (cluster, info[i].cluster);
|
||||
|
||||
/* Extend end */
|
||||
while (end < len && info[end - 1].cluster == info[end].cluster)
|
||||
@ -555,7 +534,7 @@ hb_buffer_t::merge_out_clusters (unsigned int start,
|
||||
unsigned int cluster = out_info[start].cluster;
|
||||
|
||||
for (unsigned int i = start + 1; i < end; i++)
|
||||
cluster = MIN<unsigned int> (cluster, out_info[i].cluster);
|
||||
cluster = hb_min (cluster, out_info[i].cluster);
|
||||
|
||||
/* Extend start */
|
||||
while (start && out_info[start - 1].cluster == out_info[start].cluster)
|
||||
@ -612,7 +591,7 @@ done:
|
||||
void
|
||||
hb_buffer_t::unsafe_to_break_impl (unsigned int start, unsigned int end)
|
||||
{
|
||||
unsigned int cluster = (unsigned int) -1;
|
||||
unsigned int cluster = UINT_MAX;
|
||||
cluster = _unsafe_to_break_find_min_cluster (info, start, end, cluster);
|
||||
_unsafe_to_break_set_mask (info, start, end, cluster);
|
||||
}
|
||||
@ -628,7 +607,7 @@ hb_buffer_t::unsafe_to_break_from_outbuffer (unsigned int start, unsigned int en
|
||||
assert (start <= out_len);
|
||||
assert (idx <= end);
|
||||
|
||||
unsigned int cluster = (unsigned int) -1;
|
||||
unsigned int cluster = UINT_MAX;
|
||||
cluster = _unsafe_to_break_find_min_cluster (out_info, start, out_len, cluster);
|
||||
cluster = _unsafe_to_break_find_min_cluster (info, idx, end, cluster);
|
||||
_unsafe_to_break_set_mask (out_info, start, out_len, cluster);
|
||||
@ -638,8 +617,8 @@ hb_buffer_t::unsafe_to_break_from_outbuffer (unsigned int start, unsigned int en
|
||||
void
|
||||
hb_buffer_t::guess_segment_properties ()
|
||||
{
|
||||
assert (content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
|
||||
(!len && content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
|
||||
assert ((content_type == HB_BUFFER_CONTENT_TYPE_UNICODE) ||
|
||||
(!len && (content_type == HB_BUFFER_CONTENT_TYPE_INVALID)));
|
||||
|
||||
/* If script is set to INVALID, guess from buffer contents */
|
||||
if (props.script == HB_SCRIPT_INVALID) {
|
||||
@ -736,7 +715,7 @@ hb_buffer_create ()
|
||||
hb_buffer_t *
|
||||
hb_buffer_get_empty ()
|
||||
{
|
||||
return const_cast<hb_buffer_t *> (&Null(hb_buffer_t));
|
||||
return const_cast<hb_buffer_t *> (&Null (hb_buffer_t));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -776,8 +755,10 @@ hb_buffer_destroy (hb_buffer_t *buffer)
|
||||
|
||||
free (buffer->info);
|
||||
free (buffer->pos);
|
||||
#ifndef HB_NO_BUFFER_MESSAGE
|
||||
if (buffer->message_destroy)
|
||||
buffer->message_destroy (buffer->message_data);
|
||||
#endif
|
||||
|
||||
free (buffer);
|
||||
}
|
||||
@ -956,7 +937,7 @@ hb_buffer_get_direction (hb_buffer_t *buffer)
|
||||
*
|
||||
* You can pass one of the predefined #hb_script_t values, or use
|
||||
* hb_script_from_string() or hb_script_from_iso15924_tag() to get the
|
||||
* corresponding script from an ISO 15924 script tag.
|
||||
* corresponding script from an ISO 15924 script tag.
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
@ -999,7 +980,7 @@ hb_buffer_get_script (hb_buffer_t *buffer)
|
||||
* are orthogonal to the scripts, and though they are related, they are
|
||||
* different concepts and should not be confused with each other.
|
||||
*
|
||||
* Use hb_language_from_string() to convert from BCP 47 language tags to
|
||||
* Use hb_language_from_string() to convert from BCP 47 language tags to
|
||||
* #hb_language_t.
|
||||
*
|
||||
* Since: 0.9.2
|
||||
@ -1115,8 +1096,8 @@ hb_buffer_get_flags (hb_buffer_t *buffer)
|
||||
* Since: 0.9.42
|
||||
**/
|
||||
void
|
||||
hb_buffer_set_cluster_level (hb_buffer_t *buffer,
|
||||
hb_buffer_cluster_level_t cluster_level)
|
||||
hb_buffer_set_cluster_level (hb_buffer_t *buffer,
|
||||
hb_buffer_cluster_level_t cluster_level)
|
||||
{
|
||||
if (unlikely (hb_object_is_immutable (buffer)))
|
||||
return;
|
||||
@ -1532,8 +1513,8 @@ hb_buffer_add_utf (hb_buffer_t *buffer,
|
||||
typedef typename utf_t::codepoint_t T;
|
||||
const hb_codepoint_t replacement = buffer->replacement;
|
||||
|
||||
assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE ||
|
||||
(!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
|
||||
assert ((buffer->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE) ||
|
||||
(!buffer->len && (buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID)));
|
||||
|
||||
if (unlikely (hb_object_is_immutable (buffer)))
|
||||
return;
|
||||
@ -1736,7 +1717,7 @@ hb_buffer_add_codepoints (hb_buffer_t *buffer,
|
||||
* @buffer: an #hb_buffer_t.
|
||||
* @source: source #hb_buffer_t.
|
||||
* @start: start index into source buffer to copy. Use 0 to copy from start of buffer.
|
||||
* @end: end index into source buffer to copy. Use (unsigned int) -1 to copy to end of buffer.
|
||||
* @end: end index into source buffer to copy. Use @HB_FEATURE_GLOBAL_END to copy to end of buffer.
|
||||
*
|
||||
* Append (part of) contents of another buffer to this buffer.
|
||||
*
|
||||
@ -1853,23 +1834,13 @@ void
|
||||
hb_buffer_normalize_glyphs (hb_buffer_t *buffer)
|
||||
{
|
||||
assert (buffer->have_positions);
|
||||
assert (buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS ||
|
||||
(!buffer->len && buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID));
|
||||
assert ((buffer->content_type == HB_BUFFER_CONTENT_TYPE_GLYPHS) ||
|
||||
(!buffer->len && (buffer->content_type == HB_BUFFER_CONTENT_TYPE_INVALID)));
|
||||
|
||||
bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
|
||||
|
||||
unsigned int count = buffer->len;
|
||||
if (unlikely (!count)) return;
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
|
||||
unsigned int start = 0;
|
||||
unsigned int end;
|
||||
for (end = start + 1; end < count; end++)
|
||||
if (info[start].cluster != info[end].cluster) {
|
||||
normalize_glyphs_cluster (buffer, start, end, backward);
|
||||
start = end;
|
||||
}
|
||||
normalize_glyphs_cluster (buffer, start, end, backward);
|
||||
foreach_cluster (buffer, start, end)
|
||||
normalize_glyphs_cluster (buffer, start, end, backward);
|
||||
}
|
||||
|
||||
void
|
||||
@ -1993,6 +1964,7 @@ hb_buffer_diff (hb_buffer_t *buffer,
|
||||
* Debugging.
|
||||
*/
|
||||
|
||||
#ifndef HB_NO_BUFFER_MESSAGE
|
||||
/**
|
||||
* hb_buffer_set_message_func:
|
||||
* @buffer: an #hb_buffer_t.
|
||||
@ -2022,11 +1994,11 @@ hb_buffer_set_message_func (hb_buffer_t *buffer,
|
||||
buffer->message_destroy = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
hb_buffer_t::message_impl (hb_font_t *font, const char *fmt, va_list ap)
|
||||
{
|
||||
char buf[100];
|
||||
vsnprintf (buf, sizeof (buf), fmt, ap);
|
||||
vsnprintf (buf, sizeof (buf), fmt, ap);
|
||||
return (bool) this->message_func (this, font, buf, this->message_data);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -284,6 +284,10 @@ hb_buffer_guess_segment_properties (hb_buffer_t *buffer);
|
||||
* space glyph and zeroing the advance width.)
|
||||
* @HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES takes
|
||||
* precedence over this flag. Since: 1.8.0
|
||||
* @HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE:
|
||||
* flag indicating that a dotted circle should
|
||||
* not be inserted in the rendering of incorrect
|
||||
* character sequences (such at <0905 093E>). Since: 2.4
|
||||
*
|
||||
* Since: 0.9.20
|
||||
*/
|
||||
@ -292,7 +296,8 @@ typedef enum { /*< flags >*/
|
||||
HB_BUFFER_FLAG_BOT = 0x00000001u, /* Beginning-of-text */
|
||||
HB_BUFFER_FLAG_EOT = 0x00000002u, /* End-of-text */
|
||||
HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES = 0x00000004u,
|
||||
HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES = 0x00000008u
|
||||
HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES = 0x00000008u,
|
||||
HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE = 0x00000010u
|
||||
} hb_buffer_flags_t;
|
||||
|
||||
HB_EXTERN void
|
||||
|
||||
@ -124,9 +124,11 @@ struct hb_buffer_t
|
||||
unsigned int context_len[2];
|
||||
|
||||
/* Debugging API */
|
||||
#ifndef HB_NO_BUFFER_MESSAGE
|
||||
hb_buffer_message_func_t message_func;
|
||||
void *message_data;
|
||||
hb_destroy_func_t message_destroy;
|
||||
#endif
|
||||
|
||||
/* Internal debugging. */
|
||||
/* The bits here reflect current allocations of the bytes in glyph_info_t's var1 and var2. */
|
||||
@ -226,10 +228,10 @@ struct hb_buffer_t
|
||||
/* Makes a copy of the glyph at idx to output and replace glyph_index */
|
||||
hb_glyph_info_t & output_glyph (hb_codepoint_t glyph_index)
|
||||
{
|
||||
if (unlikely (!make_room_for (0, 1))) return Crap(hb_glyph_info_t);
|
||||
if (unlikely (!make_room_for (0, 1))) return Crap (hb_glyph_info_t);
|
||||
|
||||
if (unlikely (idx == len && !out_len))
|
||||
return Crap(hb_glyph_info_t);
|
||||
return Crap (hb_glyph_info_t);
|
||||
|
||||
out_info[out_len] = idx < len ? info[idx] : out_info[out_len - 1];
|
||||
out_info[out_len].codepoint = glyph_index;
|
||||
@ -316,7 +318,7 @@ struct hb_buffer_t
|
||||
HB_INTERNAL void delete_glyph ();
|
||||
|
||||
void unsafe_to_break (unsigned int start,
|
||||
unsigned int end)
|
||||
unsigned int end)
|
||||
{
|
||||
if (end - start < 2)
|
||||
return;
|
||||
@ -347,9 +349,19 @@ struct hb_buffer_t
|
||||
|
||||
HB_INTERNAL void sort (unsigned int start, unsigned int end, int(*compar)(const hb_glyph_info_t *, const hb_glyph_info_t *));
|
||||
|
||||
bool messaging () { return unlikely (message_func); }
|
||||
bool messaging ()
|
||||
{
|
||||
#ifdef HB_NO_BUFFER_MESSAGE
|
||||
return false;
|
||||
#else
|
||||
return unlikely (message_func);
|
||||
#endif
|
||||
}
|
||||
bool message (hb_font_t *font, const char *fmt, ...) HB_PRINTF_FUNC(3, 4)
|
||||
{
|
||||
#ifdef HB_NO_BUFFER_MESSAGE
|
||||
return true;
|
||||
#else
|
||||
if (!messaging ())
|
||||
return true;
|
||||
va_list ap;
|
||||
@ -357,6 +369,7 @@ struct hb_buffer_t
|
||||
bool ret = message_impl (font, fmt, ap);
|
||||
va_end (ap);
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
HB_INTERNAL bool message_impl (hb_font_t *font, const char *fmt, va_list ap) HB_PRINTF_FUNC(3, 0);
|
||||
|
||||
@ -373,13 +386,13 @@ struct hb_buffer_t
|
||||
inf.cluster = cluster;
|
||||
}
|
||||
|
||||
int
|
||||
unsigned int
|
||||
_unsafe_to_break_find_min_cluster (const hb_glyph_info_t *infos,
|
||||
unsigned int start, unsigned int end,
|
||||
unsigned int cluster) const
|
||||
{
|
||||
for (unsigned int i = start; i < end; i++)
|
||||
cluster = MIN<unsigned int> (cluster, infos[i].cluster);
|
||||
cluster = hb_min (cluster, infos[i].cluster);
|
||||
return cluster;
|
||||
}
|
||||
void
|
||||
@ -395,8 +408,7 @@ struct hb_buffer_t
|
||||
}
|
||||
}
|
||||
|
||||
void unsafe_to_break_all ()
|
||||
{ unsafe_to_break_impl (0, len); }
|
||||
void unsafe_to_break_all () { unsafe_to_break_impl (0, len); }
|
||||
void safe_to_break_all ()
|
||||
{
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
|
||||
@ -220,32 +220,22 @@ struct number_t
|
||||
void init () { set_real (0.0); }
|
||||
void fini () {}
|
||||
|
||||
void set_int (int v) { value = (double) v; }
|
||||
int to_int () const { return (int) value; }
|
||||
void set_int (int v) { value = v; }
|
||||
int to_int () const { return value; }
|
||||
|
||||
void set_fixed (int32_t v) { value = v / 65536.0; }
|
||||
int32_t to_fixed () const { return (int32_t) (value * 65536.0); }
|
||||
int32_t to_fixed () const { return value * 65536.0; }
|
||||
|
||||
void set_real (double v) { value = v; }
|
||||
void set_real (double v) { value = v; }
|
||||
double to_real () const { return value; }
|
||||
|
||||
int ceil () const { return (int) ::ceil (value); }
|
||||
int floor () const { return (int) ::floor (value); }
|
||||
|
||||
bool in_int_range () const
|
||||
{ return ((double) (int16_t) to_int () == value); }
|
||||
|
||||
bool operator > (const number_t &n) const
|
||||
{ return value > n.to_real (); }
|
||||
|
||||
bool operator < (const number_t &n) const
|
||||
{ return n > *this; }
|
||||
|
||||
bool operator >= (const number_t &n) const
|
||||
{ return !(*this < n); }
|
||||
|
||||
bool operator <= (const number_t &n) const
|
||||
{ return !(*this > n); }
|
||||
bool operator > (const number_t &n) const { return value > n.to_real (); }
|
||||
bool operator < (const number_t &n) const { return n > *this; }
|
||||
bool operator >= (const number_t &n) const { return !(*this < n); }
|
||||
bool operator <= (const number_t &n) const { return !(*this > n); }
|
||||
|
||||
const number_t &operator += (const number_t &n)
|
||||
{
|
||||
@ -255,37 +245,34 @@ struct number_t
|
||||
}
|
||||
|
||||
protected:
|
||||
double value;
|
||||
double value;
|
||||
};
|
||||
|
||||
/* byte string */
|
||||
struct UnsizedByteStr : UnsizedArrayOf <HBUINT8>
|
||||
{
|
||||
// encode 2-byte int (Dict/CharString) or 4-byte int (Dict)
|
||||
template <typename INTTYPE, int minVal, int maxVal>
|
||||
static bool serialize_int (hb_serialize_context_t *c, op_code_t intOp, int value)
|
||||
template <typename T, typename V>
|
||||
static bool serialize_int (hb_serialize_context_t *c, op_code_t intOp, V value)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
||||
if (unlikely ((value < minVal || value > maxVal)))
|
||||
return_trace (false);
|
||||
|
||||
HBUINT8 *p = c->allocate_size<HBUINT8> (1);
|
||||
if (unlikely (p == nullptr)) return_trace (false);
|
||||
p->set (intOp);
|
||||
if (unlikely (!p)) return_trace (false);
|
||||
*p = intOp;
|
||||
|
||||
INTTYPE *ip = c->allocate_size<INTTYPE> (INTTYPE::static_size);
|
||||
if (unlikely (ip == nullptr)) return_trace (false);
|
||||
ip->set ((unsigned int)value);
|
||||
|
||||
return_trace (true);
|
||||
T *ip = c->allocate_size<T> (T::static_size);
|
||||
if (unlikely (!ip)) return_trace (false);
|
||||
return_trace (c->check_assign (*ip, value));
|
||||
}
|
||||
|
||||
static bool serialize_int4 (hb_serialize_context_t *c, int value)
|
||||
{ return serialize_int<HBUINT32, 0, 0x7FFFFFFF> (c, OpCode_longintdict, value); }
|
||||
template <typename V>
|
||||
static bool serialize_int4 (hb_serialize_context_t *c, V value)
|
||||
{ return serialize_int<HBINT32> (c, OpCode_longintdict, value); }
|
||||
|
||||
static bool serialize_int2 (hb_serialize_context_t *c, int value)
|
||||
{ return serialize_int<HBUINT16, 0, 0x7FFF> (c, OpCode_shortint, value); }
|
||||
template <typename V>
|
||||
static bool serialize_int2 (hb_serialize_context_t *c, V value)
|
||||
{ return serialize_int<HBINT16> (c, OpCode_shortint, value); }
|
||||
|
||||
/* Defining null_size allows a Null object may be created. Should be safe because:
|
||||
* A descendent struct Dict uses a Null pointer to indicate a missing table,
|
||||
@ -320,8 +307,7 @@ struct byte_str_t : hb_ubytes_t
|
||||
/* A byte string associated with the current offset and an error condition */
|
||||
struct byte_str_ref_t
|
||||
{
|
||||
byte_str_ref_t ()
|
||||
{ init (); }
|
||||
byte_str_ref_t () { init (); }
|
||||
|
||||
void init ()
|
||||
{
|
||||
@ -343,13 +329,12 @@ struct byte_str_ref_t
|
||||
}
|
||||
|
||||
const unsigned char& operator [] (int i) {
|
||||
if (unlikely ((unsigned int)(offset + i) >= str.length))
|
||||
if (unlikely ((unsigned int) (offset + i) >= str.length))
|
||||
{
|
||||
set_error ();
|
||||
return Null(unsigned char);
|
||||
return Null (unsigned char);
|
||||
}
|
||||
else
|
||||
return str[offset + i];
|
||||
return str[offset + i];
|
||||
}
|
||||
|
||||
/* Conversion to byte_str_t */
|
||||
@ -359,9 +344,7 @@ struct byte_str_ref_t
|
||||
{ return str.sub_str (offset_, len_); }
|
||||
|
||||
bool avail (unsigned int count=1) const
|
||||
{
|
||||
return (!in_error () && str.check_limit (offset, count));
|
||||
}
|
||||
{ return (!in_error () && str.check_limit (offset, count)); }
|
||||
void inc (unsigned int count=1)
|
||||
{
|
||||
if (likely (!in_error () && (offset <= str.length) && (offset + count <= str.length)))
|
||||
@ -389,7 +372,7 @@ typedef hb_vector_t<byte_str_t> byte_str_array_t;
|
||||
|
||||
/* stack */
|
||||
template <typename ELEM, int LIMIT>
|
||||
struct stack_t
|
||||
struct cff_stack_t
|
||||
{
|
||||
void init ()
|
||||
{
|
||||
@ -400,11 +383,7 @@ struct stack_t
|
||||
for (unsigned int i = 0; i < elements.length; i++)
|
||||
elements[i].init ();
|
||||
}
|
||||
|
||||
void fini ()
|
||||
{
|
||||
elements.fini_deep ();
|
||||
}
|
||||
void fini () { elements.fini_deep (); }
|
||||
|
||||
ELEM& operator [] (unsigned int i)
|
||||
{
|
||||
@ -419,7 +398,6 @@ struct stack_t
|
||||
else
|
||||
set_error ();
|
||||
}
|
||||
|
||||
ELEM &push ()
|
||||
{
|
||||
if (likely (count < elements.length))
|
||||
@ -427,7 +405,7 @@ struct stack_t
|
||||
else
|
||||
{
|
||||
set_error ();
|
||||
return Crap(ELEM);
|
||||
return Crap (ELEM);
|
||||
}
|
||||
}
|
||||
|
||||
@ -438,10 +416,9 @@ struct stack_t
|
||||
else
|
||||
{
|
||||
set_error ();
|
||||
return Crap(ELEM);
|
||||
return Crap (ELEM);
|
||||
}
|
||||
}
|
||||
|
||||
void pop (unsigned int n)
|
||||
{
|
||||
if (likely (count >= n))
|
||||
@ -452,13 +429,12 @@ struct stack_t
|
||||
|
||||
const ELEM& peek ()
|
||||
{
|
||||
if (likely (count > 0))
|
||||
return elements[count-1];
|
||||
else
|
||||
if (unlikely (count < 0))
|
||||
{
|
||||
set_error ();
|
||||
return Null(ELEM);
|
||||
return Null (ELEM);
|
||||
}
|
||||
return elements[count - 1];
|
||||
}
|
||||
|
||||
void unpop ()
|
||||
@ -475,7 +451,7 @@ struct stack_t
|
||||
void set_error () { error = true; }
|
||||
|
||||
unsigned int get_count () const { return count; }
|
||||
bool is_empty () const { return count == 0; }
|
||||
bool is_empty () const { return !count; }
|
||||
|
||||
static constexpr unsigned kSizeLimit = LIMIT;
|
||||
|
||||
@ -487,7 +463,7 @@ struct stack_t
|
||||
|
||||
/* argument stack */
|
||||
template <typename ARG=number_t>
|
||||
struct arg_stack_t : stack_t<ARG, 513>
|
||||
struct arg_stack_t : cff_stack_t<ARG, 513>
|
||||
{
|
||||
void push_int (int v)
|
||||
{
|
||||
@ -519,7 +495,7 @@ struct arg_stack_t : stack_t<ARG, 513>
|
||||
i = 0;
|
||||
S::set_error ();
|
||||
}
|
||||
return (unsigned)i;
|
||||
return (unsigned) i;
|
||||
}
|
||||
|
||||
void push_longint_from_substr (byte_str_ref_t& str_ref)
|
||||
@ -538,12 +514,10 @@ struct arg_stack_t : stack_t<ARG, 513>
|
||||
}
|
||||
|
||||
hb_array_t<const ARG> get_subarray (unsigned int start) const
|
||||
{
|
||||
return S::elements.sub_array (start);
|
||||
}
|
||||
{ return S::elements.sub_array (start); }
|
||||
|
||||
private:
|
||||
typedef stack_t<ARG, 513> S;
|
||||
typedef cff_stack_t<ARG, 513> S;
|
||||
};
|
||||
|
||||
/* an operator prefixed by its operands in a byte string */
|
||||
@ -565,7 +539,7 @@ struct op_serializer_t
|
||||
TRACE_SERIALIZE (this);
|
||||
|
||||
HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.length);
|
||||
if (unlikely (d == nullptr)) return_trace (false);
|
||||
if (unlikely (!d)) return_trace (false);
|
||||
memcpy (d, &opstr.str[0], opstr.str.length);
|
||||
return_trace (true);
|
||||
}
|
||||
@ -605,7 +579,7 @@ struct parsed_values_t
|
||||
}
|
||||
|
||||
unsigned get_count () const { return values.length; }
|
||||
const VAL &get_value (unsigned int i) const { return values[i]; }
|
||||
const VAL &get_value (unsigned int i) const { return values[i]; }
|
||||
const VAL &operator [] (unsigned int i) const { return get_value (i); }
|
||||
|
||||
unsigned int opStart;
|
||||
@ -644,30 +618,19 @@ struct interp_env_t
|
||||
return op;
|
||||
}
|
||||
|
||||
const ARG& eval_arg (unsigned int i)
|
||||
{
|
||||
return argStack[i];
|
||||
}
|
||||
const ARG& eval_arg (unsigned int i) { return argStack[i]; }
|
||||
|
||||
ARG& pop_arg ()
|
||||
{
|
||||
return argStack.pop ();
|
||||
}
|
||||
ARG& pop_arg () { return argStack.pop (); }
|
||||
void pop_n_args (unsigned int n) { argStack.pop (n); }
|
||||
|
||||
void pop_n_args (unsigned int n)
|
||||
{
|
||||
argStack.pop (n);
|
||||
}
|
||||
void clear_args () { pop_n_args (argStack.get_count ()); }
|
||||
|
||||
void clear_args ()
|
||||
{
|
||||
pop_n_args (argStack.get_count ());
|
||||
}
|
||||
|
||||
byte_str_ref_t str_ref;
|
||||
arg_stack_t<ARG> argStack;
|
||||
byte_str_ref_t
|
||||
str_ref;
|
||||
arg_stack_t<ARG>
|
||||
argStack;
|
||||
protected:
|
||||
bool error;
|
||||
bool error;
|
||||
};
|
||||
|
||||
typedef interp_env_t<> num_interp_env_t;
|
||||
@ -691,7 +654,7 @@ struct opset_t
|
||||
|
||||
case OpCode_TwoByteNegInt0: case OpCode_TwoByteNegInt1:
|
||||
case OpCode_TwoByteNegInt2: case OpCode_TwoByteNegInt3:
|
||||
env.argStack.push_int ((int16_t)(-(op - OpCode_TwoByteNegInt0) * 256 - env.str_ref[0] - 108));
|
||||
env.argStack.push_int ((-(int16_t)(op - OpCode_TwoByteNegInt0) * 256 - env.str_ref[0] - 108));
|
||||
env.str_ref.inc ();
|
||||
break;
|
||||
|
||||
@ -711,8 +674,8 @@ struct opset_t
|
||||
};
|
||||
|
||||
template <typename ENV>
|
||||
struct interpreter_t {
|
||||
|
||||
struct interpreter_t
|
||||
{
|
||||
~interpreter_t() { fini (); }
|
||||
|
||||
void fini () { env.fini (); }
|
||||
|
||||
@ -57,14 +57,14 @@ struct call_context_t
|
||||
|
||||
/* call stack */
|
||||
const unsigned int kMaxCallLimit = 10;
|
||||
struct call_stack_t : stack_t<call_context_t, kMaxCallLimit> {};
|
||||
struct call_stack_t : cff_stack_t<call_context_t, kMaxCallLimit> {};
|
||||
|
||||
template <typename SUBRS>
|
||||
struct biased_subrs_t
|
||||
{
|
||||
void init (const SUBRS &subrs_)
|
||||
void init (const SUBRS *subrs_)
|
||||
{
|
||||
subrs = &subrs_;
|
||||
subrs = subrs_;
|
||||
unsigned int nSubrs = get_count ();
|
||||
if (nSubrs < 1240)
|
||||
bias = 107;
|
||||
@ -76,13 +76,13 @@ struct biased_subrs_t
|
||||
|
||||
void fini () {}
|
||||
|
||||
unsigned int get_count () const { return (subrs == nullptr)? 0: subrs->count; }
|
||||
unsigned int get_bias () const { return bias; }
|
||||
unsigned int get_count () const { return subrs ? subrs->count : 0; }
|
||||
unsigned int get_bias () const { return bias; }
|
||||
|
||||
byte_str_t operator [] (unsigned int index) const
|
||||
{
|
||||
if (unlikely ((subrs == nullptr) || index >= subrs->count))
|
||||
return Null(byte_str_t);
|
||||
if (unlikely (!subrs || index >= subrs->count))
|
||||
return Null (byte_str_t);
|
||||
else
|
||||
return (*subrs)[index];
|
||||
}
|
||||
@ -118,7 +118,7 @@ struct point_t
|
||||
template <typename ARG, typename SUBRS>
|
||||
struct cs_interp_env_t : interp_env_t<ARG>
|
||||
{
|
||||
void init (const byte_str_t &str, const SUBRS &globalSubrs_, const SUBRS &localSubrs_)
|
||||
void init (const byte_str_t &str, const SUBRS *globalSubrs_, const SUBRS *localSubrs_)
|
||||
{
|
||||
interp_env_t<ARG>::init (str);
|
||||
|
||||
@ -147,8 +147,9 @@ struct cs_interp_env_t : interp_env_t<ARG>
|
||||
return callStack.in_error () || SUPER::in_error ();
|
||||
}
|
||||
|
||||
bool popSubrNum (const biased_subrs_t<SUBRS>& biasedSubrs, unsigned int &subr_num)
|
||||
bool pop_subr_num (const biased_subrs_t<SUBRS>& biasedSubrs, unsigned int &subr_num)
|
||||
{
|
||||
subr_num = 0;
|
||||
int n = SUPER::argStack.pop_int ();
|
||||
n += biasedSubrs.get_bias ();
|
||||
if (unlikely ((n < 0) || ((unsigned int)n >= biasedSubrs.get_count ())))
|
||||
@ -158,11 +159,11 @@ struct cs_interp_env_t : interp_env_t<ARG>
|
||||
return true;
|
||||
}
|
||||
|
||||
void callSubr (const biased_subrs_t<SUBRS>& biasedSubrs, cs_type_t type)
|
||||
void call_subr (const biased_subrs_t<SUBRS>& biasedSubrs, cs_type_t type)
|
||||
{
|
||||
unsigned int subr_num;
|
||||
unsigned int subr_num = 0;
|
||||
|
||||
if (unlikely (!popSubrNum (biasedSubrs, subr_num)
|
||||
if (unlikely (!pop_subr_num (biasedSubrs, subr_num)
|
||||
|| callStack.get_count () >= kMaxCallLimit))
|
||||
{
|
||||
SUPER::set_error ();
|
||||
@ -175,7 +176,7 @@ struct cs_interp_env_t : interp_env_t<ARG>
|
||||
SUPER::str_ref = context.str_ref;
|
||||
}
|
||||
|
||||
void returnFromSubr ()
|
||||
void return_from_subr ()
|
||||
{
|
||||
if (unlikely (SUPER::str_ref.in_error ()))
|
||||
SUPER::set_error ();
|
||||
@ -246,7 +247,7 @@ struct path_procs_null_t
|
||||
static void flex1 (ENV &env, PARAM& param) {}
|
||||
};
|
||||
|
||||
template <typename ARG, typename OPSET, typename ENV, typename PARAM, typename PATH=path_procs_null_t<ENV, PARAM> >
|
||||
template <typename ARG, typename OPSET, typename ENV, typename PARAM, typename PATH=path_procs_null_t<ENV, PARAM>>
|
||||
struct cs_opset_t : opset_t<ARG>
|
||||
{
|
||||
static void process_op (op_code_t op, ENV &env, PARAM& param)
|
||||
@ -254,7 +255,7 @@ struct cs_opset_t : opset_t<ARG>
|
||||
switch (op) {
|
||||
|
||||
case OpCode_return:
|
||||
env.returnFromSubr ();
|
||||
env.return_from_subr ();
|
||||
break;
|
||||
case OpCode_endchar:
|
||||
OPSET::check_width (op, env, param);
|
||||
@ -267,11 +268,11 @@ struct cs_opset_t : opset_t<ARG>
|
||||
break;
|
||||
|
||||
case OpCode_callsubr:
|
||||
env.callSubr (env.localSubrs, CSType_LocalSubr);
|
||||
env.call_subr (env.localSubrs, CSType_LocalSubr);
|
||||
break;
|
||||
|
||||
case OpCode_callgsubr:
|
||||
env.callSubr (env.globalSubrs, CSType_GlobalSubr);
|
||||
env.call_subr (env.globalSubrs, CSType_GlobalSubr);
|
||||
break;
|
||||
|
||||
case OpCode_hstem:
|
||||
@ -550,8 +551,13 @@ struct path_procs_t
|
||||
|
||||
static void rcurveline (ENV &env, PARAM& param)
|
||||
{
|
||||
unsigned int arg_count = env.argStack.get_count ();
|
||||
if (unlikely (arg_count < 8))
|
||||
return;
|
||||
|
||||
unsigned int i = 0;
|
||||
for (; i + 6 <= env.argStack.get_count (); i += 6)
|
||||
unsigned int curve_limit = arg_count - 2;
|
||||
for (; i + 6 <= curve_limit; i += 6)
|
||||
{
|
||||
point_t pt1 = env.get_pt ();
|
||||
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
|
||||
@ -561,34 +567,34 @@ struct path_procs_t
|
||||
pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
|
||||
PATH::curve (env, param, pt1, pt2, pt3);
|
||||
}
|
||||
for (; i + 2 <= env.argStack.get_count (); i += 2)
|
||||
{
|
||||
point_t pt1 = env.get_pt ();
|
||||
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
|
||||
PATH::line (env, param, pt1);
|
||||
}
|
||||
|
||||
point_t pt1 = env.get_pt ();
|
||||
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
|
||||
PATH::line (env, param, pt1);
|
||||
}
|
||||
|
||||
static void rlinecurve (ENV &env, PARAM& param)
|
||||
{
|
||||
unsigned int arg_count = env.argStack.get_count ();
|
||||
if (unlikely (arg_count < 8))
|
||||
return;
|
||||
|
||||
unsigned int i = 0;
|
||||
unsigned int line_limit = (env.argStack.get_count () % 6);
|
||||
unsigned int line_limit = arg_count - 6;
|
||||
for (; i + 2 <= line_limit; i += 2)
|
||||
{
|
||||
point_t pt1 = env.get_pt ();
|
||||
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
|
||||
PATH::line (env, param, pt1);
|
||||
}
|
||||
for (; i + 6 <= env.argStack.get_count (); i += 6)
|
||||
{
|
||||
point_t pt1 = env.get_pt ();
|
||||
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
|
||||
point_t pt2 = pt1;
|
||||
pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
|
||||
point_t pt3 = pt2;
|
||||
pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
|
||||
PATH::curve (env, param, pt1, pt2, pt3);
|
||||
}
|
||||
|
||||
point_t pt1 = env.get_pt ();
|
||||
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
|
||||
point_t pt2 = pt1;
|
||||
pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
|
||||
point_t pt3 = pt2;
|
||||
pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
|
||||
PATH::curve (env, param, pt1, pt2, pt3);
|
||||
}
|
||||
|
||||
static void vvcurveto (ENV &env, PARAM& param)
|
||||
|
||||
@ -27,8 +27,6 @@
|
||||
#define HB_CFF_INTERP_DICT_COMMON_HH
|
||||
|
||||
#include "hb-cff-interp-common.hh"
|
||||
#include <math.h>
|
||||
#include <float.h>
|
||||
|
||||
namespace CFF {
|
||||
|
||||
@ -58,19 +56,6 @@ struct top_dict_values_t : dict_values_t<OPSTR>
|
||||
}
|
||||
void fini () { dict_values_t<OPSTR>::fini (); }
|
||||
|
||||
unsigned int calculate_serialized_op_size (const OPSTR& opstr) const
|
||||
{
|
||||
switch (opstr.op)
|
||||
{
|
||||
case OpCode_CharStrings:
|
||||
case OpCode_FDArray:
|
||||
return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op);
|
||||
|
||||
default:
|
||||
return opstr.str.length;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int charStringsOffset;
|
||||
unsigned int FDArrayOffset;
|
||||
};
|
||||
@ -94,130 +79,52 @@ struct dict_opset_t : opset_t<number_t>
|
||||
}
|
||||
}
|
||||
|
||||
/* Turns CFF's BCD format into strtod understandable string */
|
||||
static double parse_bcd (byte_str_ref_t& str_ref)
|
||||
{
|
||||
bool neg = false;
|
||||
double int_part = 0;
|
||||
uint64_t frac_part = 0;
|
||||
uint32_t frac_count = 0;
|
||||
bool exp_neg = false;
|
||||
uint32_t exp_part = 0;
|
||||
bool exp_overflow = false;
|
||||
enum Part { INT_PART=0, FRAC_PART, EXP_PART } part = INT_PART;
|
||||
enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END };
|
||||
const uint64_t MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 1^52-1 */
|
||||
const uint32_t MAX_EXP = 0x7FFu; /* 1^11-1 */
|
||||
if (unlikely (str_ref.in_error ())) return .0;
|
||||
|
||||
double value = 0.0;
|
||||
enum Nibble { DECIMAL=10, EXP_POS, EXP_NEG, RESERVED, NEG, END };
|
||||
|
||||
char buf[32];
|
||||
unsigned char byte = 0;
|
||||
for (uint32_t i = 0;; i++)
|
||||
for (unsigned i = 0, count = 0; count < ARRAY_LENGTH (buf); ++i, ++count)
|
||||
{
|
||||
char d;
|
||||
if ((i & 1) == 0)
|
||||
unsigned nibble;
|
||||
if (!(i & 1))
|
||||
{
|
||||
if (!str_ref.avail ())
|
||||
{
|
||||
str_ref.set_error ();
|
||||
return 0.0;
|
||||
}
|
||||
if (unlikely (!str_ref.avail ())) break;
|
||||
|
||||
byte = str_ref[0];
|
||||
str_ref.inc ();
|
||||
d = byte >> 4;
|
||||
nibble = byte >> 4;
|
||||
}
|
||||
else
|
||||
d = byte & 0x0F;
|
||||
nibble = byte & 0x0F;
|
||||
|
||||
switch (d)
|
||||
if (unlikely (nibble == RESERVED)) break;
|
||||
else if (nibble == END)
|
||||
{
|
||||
case RESERVED:
|
||||
str_ref.set_error ();
|
||||
return value;
|
||||
|
||||
case END:
|
||||
value = (double)(neg? -int_part: int_part);
|
||||
if (frac_count > 0)
|
||||
{
|
||||
double frac = (frac_part / pow (10.0, (double)frac_count));
|
||||
if (neg) frac = -frac;
|
||||
value += frac;
|
||||
}
|
||||
if (unlikely (exp_overflow))
|
||||
{
|
||||
if (value == 0.0)
|
||||
return value;
|
||||
if (exp_neg)
|
||||
return neg? -DBL_MIN: DBL_MIN;
|
||||
else
|
||||
return neg? -DBL_MAX: DBL_MAX;
|
||||
}
|
||||
if (exp_part != 0)
|
||||
{
|
||||
if (exp_neg)
|
||||
value /= pow (10.0, (double)exp_part);
|
||||
else
|
||||
value *= pow (10.0, (double)exp_part);
|
||||
}
|
||||
return value;
|
||||
|
||||
case NEG:
|
||||
if (i != 0)
|
||||
{
|
||||
str_ref.set_error ();
|
||||
return 0.0;
|
||||
}
|
||||
neg = true;
|
||||
const char *p = buf;
|
||||
double pv;
|
||||
if (unlikely (!hb_parse_double (&p, p + count, &pv, true/* whole buffer */)))
|
||||
break;
|
||||
|
||||
case DECIMAL:
|
||||
if (part != INT_PART)
|
||||
{
|
||||
str_ref.set_error ();
|
||||
return value;
|
||||
}
|
||||
part = FRAC_PART;
|
||||
break;
|
||||
|
||||
case EXP_NEG:
|
||||
exp_neg = true;
|
||||
HB_FALLTHROUGH;
|
||||
|
||||
case EXP_POS:
|
||||
if (part == EXP_PART)
|
||||
{
|
||||
str_ref.set_error ();
|
||||
return value;
|
||||
}
|
||||
part = EXP_PART;
|
||||
break;
|
||||
|
||||
default:
|
||||
switch (part) {
|
||||
default:
|
||||
case INT_PART:
|
||||
int_part = (int_part * 10) + d;
|
||||
break;
|
||||
|
||||
case FRAC_PART:
|
||||
if (likely (frac_part <= MAX_FRACT / 10))
|
||||
{
|
||||
frac_part = (frac_part * 10) + (unsigned)d;
|
||||
frac_count++;
|
||||
}
|
||||
break;
|
||||
|
||||
case EXP_PART:
|
||||
if (likely (exp_part * 10 + d <= MAX_EXP))
|
||||
{
|
||||
exp_part = (exp_part * 10) + d;
|
||||
}
|
||||
else
|
||||
exp_overflow = true;
|
||||
break;
|
||||
}
|
||||
return pv;
|
||||
}
|
||||
else
|
||||
{
|
||||
buf[count] = "0123456789.EE?-?"[nibble];
|
||||
if (nibble == EXP_NEG)
|
||||
{
|
||||
++count;
|
||||
if (unlikely (count == ARRAY_LENGTH (buf))) break;
|
||||
buf[count] = '-';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
str_ref.set_error ();
|
||||
return .0;
|
||||
}
|
||||
|
||||
static bool is_hint_op (op_code_t op)
|
||||
|
||||
@ -40,7 +40,7 @@ struct cff1_cs_interp_env_t : cs_interp_env_t<number_t, CFF1Subrs>
|
||||
template <typename ACC>
|
||||
void init (const byte_str_t &str, ACC &acc, unsigned int fd)
|
||||
{
|
||||
SUPER::init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs);
|
||||
SUPER::init (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs);
|
||||
processed_width = false;
|
||||
has_width = false;
|
||||
arg_start = 0;
|
||||
@ -81,7 +81,7 @@ struct cff1_cs_interp_env_t : cs_interp_env_t<number_t, CFF1Subrs>
|
||||
typedef cs_interp_env_t<number_t, CFF1Subrs> SUPER;
|
||||
};
|
||||
|
||||
template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff1_cs_interp_env_t, PARAM> >
|
||||
template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff1_cs_interp_env_t, PARAM>>
|
||||
struct cff1_cs_opset_t : cs_opset_t<number_t, OPSET, cff1_cs_interp_env_t, PARAM, PATH>
|
||||
{
|
||||
/* PostScript-originated legacy opcodes (OpCode_add etc) are unsupported */
|
||||
|
||||
@ -52,7 +52,7 @@ struct blend_arg_t : number_t
|
||||
void set_real (double v) { reset_blends (); number_t::set_real (v); }
|
||||
|
||||
void set_blends (unsigned int numValues_, unsigned int valueIndex_,
|
||||
unsigned int numBlends, hb_array_t<const blend_arg_t> blends_)
|
||||
unsigned int numBlends, hb_array_t<const blend_arg_t> blends_)
|
||||
{
|
||||
numValues = numValues_;
|
||||
valueIndex = valueIndex_;
|
||||
@ -80,9 +80,9 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
|
||||
{
|
||||
template <typename ACC>
|
||||
void init (const byte_str_t &str, ACC &acc, unsigned int fd,
|
||||
const int *coords_=nullptr, unsigned int num_coords_=0)
|
||||
const int *coords_=nullptr, unsigned int num_coords_=0)
|
||||
{
|
||||
SUPER::init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs);
|
||||
SUPER::init (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs);
|
||||
|
||||
coords = coords_;
|
||||
num_coords = num_coords_;
|
||||
@ -90,7 +90,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
|
||||
seen_blend = false;
|
||||
seen_vsindex_ = false;
|
||||
scalars.init ();
|
||||
do_blend = (coords != nullptr) && num_coords && (varStore != &Null(CFF2VariationStore));
|
||||
do_blend = num_coords && coords && varStore->size;
|
||||
set_ivs (acc.privateDicts[fd].ivs);
|
||||
}
|
||||
|
||||
@ -133,10 +133,11 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
|
||||
region_count = varStore->varStore.get_region_index_count (get_ivs ());
|
||||
if (do_blend)
|
||||
{
|
||||
scalars.resize (region_count);
|
||||
varStore->varStore.get_scalars (get_ivs (),
|
||||
(int *)coords, num_coords,
|
||||
&scalars[0], region_count);
|
||||
if (unlikely (!scalars.resize (region_count)))
|
||||
set_error ();
|
||||
else
|
||||
varStore->varStore.get_scalars (get_ivs (), coords, num_coords,
|
||||
&scalars[0], region_count);
|
||||
}
|
||||
seen_blend = true;
|
||||
}
|
||||
@ -193,7 +194,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
|
||||
|
||||
typedef cs_interp_env_t<blend_arg_t, CFF2Subrs> SUPER;
|
||||
};
|
||||
template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t, PARAM> >
|
||||
template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t, PARAM>>
|
||||
struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH>
|
||||
{
|
||||
static void process_op (op_code_t op, cff2_cs_interp_env_t &env, PARAM& param)
|
||||
|
||||
@ -27,14 +27,13 @@
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#include "hb-machinery.hh"
|
||||
|
||||
#include <locale.h>
|
||||
#ifdef HAVE_XLOCALE_H
|
||||
#include <xlocale.h>
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_SETLOCALE
|
||||
#define setlocale(Category, Locale) "C"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* SECTION:hb-common
|
||||
@ -67,10 +66,9 @@ _hb_options_init ()
|
||||
p = c + strlen (c);
|
||||
|
||||
#define OPTION(name, symbol) \
|
||||
if (0 == strncmp (c, name, p - c) && strlen (name) == p - c) u.opts.symbol = true;
|
||||
if (0 == strncmp (c, name, p - c) && strlen (name) == static_cast<size_t>(p - c)) do { u.opts.symbol = true; } while (0)
|
||||
|
||||
OPTION ("uniscribe-bug-compatible", uniscribe_bug_compatible);
|
||||
OPTION ("aat", aat);
|
||||
|
||||
#undef OPTION
|
||||
|
||||
@ -334,14 +332,14 @@ retry:
|
||||
/**
|
||||
* hb_language_from_string:
|
||||
* @str: (array length=len) (element-type uint8_t): a string representing
|
||||
* a BCP 47 language tag
|
||||
* a BCP 47 language tag
|
||||
* @len: length of the @str, or -1 if it is %NULL-terminated.
|
||||
*
|
||||
* Converts @str representing a BCP 47 language tag to the corresponding
|
||||
* Converts @str representing a BCP 47 language tag to the corresponding
|
||||
* #hb_language_t.
|
||||
*
|
||||
* Return value: (transfer none):
|
||||
* The #hb_language_t corresponding to the BCP 47 language tag.
|
||||
* The #hb_language_t corresponding to the BCP 47 language tag.
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
@ -356,7 +354,7 @@ hb_language_from_string (const char *str, int len)
|
||||
{
|
||||
/* NUL-terminate it. */
|
||||
char strbuf[64];
|
||||
len = MIN (len, (int) sizeof (strbuf) - 1);
|
||||
len = hb_min (len, (int) sizeof (strbuf) - 1);
|
||||
memcpy (strbuf, str, len);
|
||||
strbuf[len] = '\0';
|
||||
item = lang_find_or_insert (strbuf);
|
||||
@ -382,7 +380,8 @@ hb_language_from_string (const char *str, int len)
|
||||
const char *
|
||||
hb_language_to_string (hb_language_t language)
|
||||
{
|
||||
/* This is actually nullptr-safe! */
|
||||
if (unlikely (!language)) return nullptr;
|
||||
|
||||
return language->s;
|
||||
}
|
||||
|
||||
@ -422,12 +421,12 @@ hb_language_get_default ()
|
||||
|
||||
/**
|
||||
* hb_script_from_iso15924_tag:
|
||||
* @tag: an #hb_tag_t representing an ISO 15924 tag.
|
||||
* @tag: an #hb_tag_t representing an ISO 15924 tag.
|
||||
*
|
||||
* Converts an ISO 15924 script tag to a corresponding #hb_script_t.
|
||||
* Converts an ISO 15924 script tag to a corresponding #hb_script_t.
|
||||
*
|
||||
* Return value:
|
||||
* An #hb_script_t corresponding to the ISO 15924 tag.
|
||||
* An #hb_script_t corresponding to the ISO 15924 tag.
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
@ -468,15 +467,15 @@ hb_script_from_iso15924_tag (hb_tag_t tag)
|
||||
/**
|
||||
* hb_script_from_string:
|
||||
* @str: (array length=len) (element-type uint8_t): a string representing an
|
||||
* ISO 15924 tag.
|
||||
* ISO 15924 tag.
|
||||
* @len: length of the @str, or -1 if it is %NULL-terminated.
|
||||
*
|
||||
* Converts a string @str representing an ISO 15924 script tag to a
|
||||
* Converts a string @str representing an ISO 15924 script tag to a
|
||||
* corresponding #hb_script_t. Shorthand for hb_tag_from_string() then
|
||||
* hb_script_from_iso15924_tag().
|
||||
*
|
||||
* Return value:
|
||||
* An #hb_script_t corresponding to the ISO 15924 tag.
|
||||
* An #hb_script_t corresponding to the ISO 15924 tag.
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
@ -488,12 +487,12 @@ hb_script_from_string (const char *str, int len)
|
||||
|
||||
/**
|
||||
* hb_script_to_iso15924_tag:
|
||||
* @script: an #hb_script_ to convert.
|
||||
* @script: an #hb_script_t to convert.
|
||||
*
|
||||
* See hb_script_from_iso15924_tag().
|
||||
*
|
||||
* Return value:
|
||||
* An #hb_tag_t representing an ISO 15924 script tag.
|
||||
* An #hb_tag_t representing an ISO 15924 script tag.
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
@ -575,6 +574,13 @@ hb_script_get_horizontal_direction (hb_script_t script)
|
||||
case HB_SCRIPT_OLD_SOGDIAN:
|
||||
case HB_SCRIPT_SOGDIAN:
|
||||
|
||||
/* Unicode-12.0 additions */
|
||||
case HB_SCRIPT_ELYMAIC:
|
||||
|
||||
/* Unicode-13.0 additions */
|
||||
case HB_SCRIPT_CHORASMIAN:
|
||||
case HB_SCRIPT_YEZIDI:
|
||||
|
||||
return HB_DIRECTION_RTL;
|
||||
|
||||
|
||||
@ -590,38 +596,6 @@ hb_script_get_horizontal_direction (hb_script_t script)
|
||||
}
|
||||
|
||||
|
||||
/* hb_user_data_array_t */
|
||||
|
||||
bool
|
||||
hb_user_data_array_t::set (hb_user_data_key_t *key,
|
||||
void * data,
|
||||
hb_destroy_func_t destroy,
|
||||
hb_bool_t replace)
|
||||
{
|
||||
if (!key)
|
||||
return false;
|
||||
|
||||
if (replace) {
|
||||
if (!data && !destroy) {
|
||||
items.remove (key, lock);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
hb_user_data_item_t item = {key, data, destroy};
|
||||
bool ret = !!items.replace_or_insert (item, lock, (bool) replace);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *
|
||||
hb_user_data_array_t::get (hb_user_data_key_t *key)
|
||||
{
|
||||
hb_user_data_item_t item = {nullptr, nullptr, nullptr};
|
||||
|
||||
return items.find (key, &item, lock) ? item.data : nullptr;
|
||||
}
|
||||
|
||||
|
||||
/* hb_version */
|
||||
|
||||
|
||||
@ -719,131 +693,24 @@ parse_char (const char **pp, const char *end, char c)
|
||||
static bool
|
||||
parse_uint (const char **pp, const char *end, unsigned int *pv)
|
||||
{
|
||||
char buf[32];
|
||||
unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
|
||||
strncpy (buf, *pp, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
char *p = buf;
|
||||
char *pend = p;
|
||||
unsigned int v;
|
||||
|
||||
/* Intentionally use strtol instead of strtoul, such that
|
||||
* -1 turns into "big number"... */
|
||||
errno = 0;
|
||||
v = strtol (p, &pend, 0);
|
||||
if (errno || p == pend)
|
||||
return false;
|
||||
/* Intentionally use hb_parse_int inside instead of hb_parse_uint,
|
||||
* such that -1 turns into "big number"... */
|
||||
int v;
|
||||
if (unlikely (!hb_parse_int (pp, end, &v))) return false;
|
||||
|
||||
*pv = v;
|
||||
*pp += pend - p;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
parse_uint32 (const char **pp, const char *end, uint32_t *pv)
|
||||
{
|
||||
char buf[32];
|
||||
unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
|
||||
strncpy (buf, *pp, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
char *p = buf;
|
||||
char *pend = p;
|
||||
unsigned int v;
|
||||
|
||||
/* Intentionally use strtol instead of strtoul, such that
|
||||
* -1 turns into "big number"... */
|
||||
errno = 0;
|
||||
v = strtol (p, &pend, 0);
|
||||
if (errno || p == pend)
|
||||
return false;
|
||||
/* Intentionally use hb_parse_int inside instead of hb_parse_uint,
|
||||
* such that -1 turns into "big number"... */
|
||||
int v;
|
||||
if (unlikely (!hb_parse_int (pp, end, &v))) return false;
|
||||
|
||||
*pv = v;
|
||||
*pp += pend - p;
|
||||
return true;
|
||||
}
|
||||
|
||||
#if defined (HAVE_NEWLOCALE) && defined (HAVE_STRTOD_L)
|
||||
#define USE_XLOCALE 1
|
||||
#define HB_LOCALE_T locale_t
|
||||
#define HB_CREATE_LOCALE(locName) newlocale (LC_ALL_MASK, locName, nullptr)
|
||||
#define HB_FREE_LOCALE(loc) freelocale (loc)
|
||||
#elif defined(_MSC_VER)
|
||||
#define USE_XLOCALE 1
|
||||
#define HB_LOCALE_T _locale_t
|
||||
#define HB_CREATE_LOCALE(locName) _create_locale (LC_ALL, locName)
|
||||
#define HB_FREE_LOCALE(loc) _free_locale (loc)
|
||||
#define strtod_l(a, b, c) _strtod_l ((a), (b), (c))
|
||||
#endif
|
||||
|
||||
#ifdef USE_XLOCALE
|
||||
|
||||
#if HB_USE_ATEXIT
|
||||
static void free_static_C_locale ();
|
||||
#endif
|
||||
|
||||
static struct hb_C_locale_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer (HB_LOCALE_T),
|
||||
hb_C_locale_lazy_loader_t>
|
||||
{
|
||||
static HB_LOCALE_T create ()
|
||||
{
|
||||
HB_LOCALE_T C_locale = HB_CREATE_LOCALE ("C");
|
||||
|
||||
#if HB_USE_ATEXIT
|
||||
atexit (free_static_C_locale);
|
||||
#endif
|
||||
|
||||
return C_locale;
|
||||
}
|
||||
static void destroy (HB_LOCALE_T p)
|
||||
{
|
||||
HB_FREE_LOCALE (p);
|
||||
}
|
||||
static HB_LOCALE_T get_null ()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
} static_C_locale;
|
||||
|
||||
#if HB_USE_ATEXIT
|
||||
static
|
||||
void free_static_C_locale ()
|
||||
{
|
||||
static_C_locale.free_instance ();
|
||||
}
|
||||
#endif
|
||||
|
||||
static HB_LOCALE_T
|
||||
get_C_locale ()
|
||||
{
|
||||
return static_C_locale.get_unconst ();
|
||||
}
|
||||
#endif /* USE_XLOCALE */
|
||||
|
||||
static bool
|
||||
parse_float (const char **pp, const char *end, float *pv)
|
||||
{
|
||||
char buf[32];
|
||||
unsigned int len = MIN (ARRAY_LENGTH (buf) - 1, (unsigned int) (end - *pp));
|
||||
strncpy (buf, *pp, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
char *p = buf;
|
||||
char *pend = p;
|
||||
float v;
|
||||
|
||||
errno = 0;
|
||||
#ifdef USE_XLOCALE
|
||||
v = strtod_l (p, &pend, get_C_locale ());
|
||||
#else
|
||||
v = strtod (p, &pend);
|
||||
#endif
|
||||
if (errno || p == pend)
|
||||
return false;
|
||||
|
||||
*pv = v;
|
||||
*pp += pend - p;
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -857,9 +724,14 @@ parse_bool (const char **pp, const char *end, uint32_t *pv)
|
||||
(*pp)++;
|
||||
|
||||
/* CSS allows on/off as aliases 1/0. */
|
||||
if (*pp - p == 2 && 0 == strncmp (p, "on", 2))
|
||||
if (*pp - p == 2
|
||||
&& TOLOWER (p[0]) == 'o'
|
||||
&& TOLOWER (p[1]) == 'n')
|
||||
*pv = 1;
|
||||
else if (*pp - p == 3 && 0 == strncmp (p, "off", 3))
|
||||
else if (*pp - p == 3
|
||||
&& TOLOWER (p[0]) == 'o'
|
||||
&& TOLOWER (p[1]) == 'f'
|
||||
&& TOLOWER (p[2]) == 'f')
|
||||
*pv = 0;
|
||||
else
|
||||
return false;
|
||||
@ -974,7 +846,41 @@ parse_one_feature (const char **pp, const char *end, hb_feature_t *feature)
|
||||
*
|
||||
* Parses a string into a #hb_feature_t.
|
||||
*
|
||||
* TODO: document the syntax here.
|
||||
* The format for specifying feature strings follows. All valid CSS
|
||||
* font-feature-settings values other than 'normal' and the global values are
|
||||
* also accepted, though not documented below. CSS string escapes are not
|
||||
* supported.
|
||||
*
|
||||
* The range indices refer to the positions between Unicode characters. The
|
||||
* position before the first character is always 0.
|
||||
*
|
||||
* The format is Python-esque. Here is how it all works:
|
||||
*
|
||||
* <informaltable pgwide='1' align='left' frame='none'>
|
||||
* <tgroup cols='5'>
|
||||
* <thead>
|
||||
* <row><entry>Syntax</entry> <entry>Value</entry> <entry>Start</entry> <entry>End</entry></row>
|
||||
* </thead>
|
||||
* <tbody>
|
||||
* <row><entry>Setting value:</entry></row>
|
||||
* <row><entry>kern</entry> <entry>1</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature on</entry></row>
|
||||
* <row><entry>+kern</entry> <entry>1</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature on</entry></row>
|
||||
* <row><entry>-kern</entry> <entry>0</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature off</entry></row>
|
||||
* <row><entry>kern=0</entry> <entry>0</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature off</entry></row>
|
||||
* <row><entry>kern=1</entry> <entry>1</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature on</entry></row>
|
||||
* <row><entry>aalt=2</entry> <entry>2</entry> <entry>0</entry> <entry>∞</entry> <entry>Choose 2nd alternate</entry></row>
|
||||
* <row><entry>Setting index:</entry></row>
|
||||
* <row><entry>kern[]</entry> <entry>1</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature on</entry></row>
|
||||
* <row><entry>kern[:]</entry> <entry>1</entry> <entry>0</entry> <entry>∞</entry> <entry>Turn feature on</entry></row>
|
||||
* <row><entry>kern[5:]</entry> <entry>1</entry> <entry>5</entry> <entry>∞</entry> <entry>Turn feature on, partial</entry></row>
|
||||
* <row><entry>kern[:5]</entry> <entry>1</entry> <entry>0</entry> <entry>5</entry> <entry>Turn feature on, partial</entry></row>
|
||||
* <row><entry>kern[3:5]</entry> <entry>1</entry> <entry>3</entry> <entry>5</entry> <entry>Turn feature on, range</entry></row>
|
||||
* <row><entry>kern[3]</entry> <entry>1</entry> <entry>3</entry> <entry>3+1</entry> <entry>Turn feature on, single char</entry></row>
|
||||
* <row><entry>Mixing it all:</entry></row>
|
||||
* <row><entry>aalt[3:5]=2</entry> <entry>2</entry> <entry>3</entry> <entry>5</entry> <entry>Turn 2nd alternate on for range</entry></row>
|
||||
* </tbody>
|
||||
* </tgroup>
|
||||
* </informaltable>
|
||||
*
|
||||
* Return value:
|
||||
* %true if @str is successfully parsed, %false otherwise.
|
||||
@ -1028,25 +934,25 @@ hb_feature_to_string (hb_feature_t *feature,
|
||||
len += 4;
|
||||
while (len && s[len - 1] == ' ')
|
||||
len--;
|
||||
if (feature->start != 0 || feature->end != (unsigned int) -1)
|
||||
if (feature->start != HB_FEATURE_GLOBAL_START || feature->end != HB_FEATURE_GLOBAL_END)
|
||||
{
|
||||
s[len++] = '[';
|
||||
if (feature->start)
|
||||
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
|
||||
len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->start));
|
||||
if (feature->end != feature->start + 1) {
|
||||
s[len++] = ':';
|
||||
if (feature->end != (unsigned int) -1)
|
||||
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end));
|
||||
if (feature->end != HB_FEATURE_GLOBAL_END)
|
||||
len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->end));
|
||||
}
|
||||
s[len++] = ']';
|
||||
}
|
||||
if (feature->value > 1)
|
||||
{
|
||||
s[len++] = '=';
|
||||
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
|
||||
len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%u", feature->value));
|
||||
}
|
||||
assert (len < ARRAY_LENGTH (s));
|
||||
len = MIN (len, size - 1);
|
||||
len = hb_min (len, size - 1);
|
||||
memcpy (buf, s, len);
|
||||
buf[len] = '\0';
|
||||
}
|
||||
@ -1057,7 +963,11 @@ static bool
|
||||
parse_variation_value (const char **pp, const char *end, hb_variation_t *variation)
|
||||
{
|
||||
parse_char (pp, end, '='); /* Optional. */
|
||||
return parse_float (pp, end, &variation->value);
|
||||
double v;
|
||||
if (unlikely (!hb_parse_double (pp, end, &v))) return false;
|
||||
|
||||
variation->value = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -1113,14 +1023,71 @@ hb_variation_to_string (hb_variation_t *variation,
|
||||
while (len && s[len - 1] == ' ')
|
||||
len--;
|
||||
s[len++] = '=';
|
||||
len += MAX (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) variation->value));
|
||||
len += hb_max (0, snprintf (s + len, ARRAY_LENGTH (s) - len, "%g", (double) variation->value));
|
||||
|
||||
assert (len < ARRAY_LENGTH (s));
|
||||
len = MIN (len, size - 1);
|
||||
len = hb_min (len, size - 1);
|
||||
memcpy (buf, s, len);
|
||||
buf[len] = '\0';
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_color_get_alpha:
|
||||
* color: a #hb_color_t we are interested in its channels.
|
||||
*
|
||||
* Return value: Alpha channel value of the given color
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
uint8_t
|
||||
(hb_color_get_alpha) (hb_color_t color)
|
||||
{
|
||||
return hb_color_get_alpha (color);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_color_get_red:
|
||||
* color: a #hb_color_t we are interested in its channels.
|
||||
*
|
||||
* Return value: Red channel value of the given color
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
uint8_t
|
||||
(hb_color_get_red) (hb_color_t color)
|
||||
{
|
||||
return hb_color_get_red (color);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_color_get_green:
|
||||
* color: a #hb_color_t we are interested in its channels.
|
||||
*
|
||||
* Return value: Green channel value of the given color
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
uint8_t
|
||||
(hb_color_get_green) (hb_color_t color)
|
||||
{
|
||||
return hb_color_get_green (color);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_color_get_blue:
|
||||
* color: a #hb_color_t we are interested in its channels.
|
||||
*
|
||||
* Return value: Blue channel value of the given color
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
uint8_t
|
||||
(hb_color_get_blue) (hb_color_t color)
|
||||
{
|
||||
return hb_color_get_blue (color);
|
||||
}
|
||||
|
||||
|
||||
/* If there is no visibility control, then hb-static.cc will NOT
|
||||
* define anything. Instead, we get it to define one set in here
|
||||
* only, so only libharfbuzz.so defines them, not other libs. */
|
||||
|
||||
@ -63,6 +63,8 @@ typedef __int32 int32_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef __int64 int64_t;
|
||||
typedef unsigned __int64 uint64_t;
|
||||
#elif defined (__KERNEL__)
|
||||
# include <linux/types.h>
|
||||
#else
|
||||
# include <stdint.h>
|
||||
#endif
|
||||
@ -357,6 +359,22 @@ typedef enum
|
||||
/*11.0*/HB_SCRIPT_OLD_SOGDIAN = HB_TAG ('S','o','g','o'),
|
||||
/*11.0*/HB_SCRIPT_SOGDIAN = HB_TAG ('S','o','g','d'),
|
||||
|
||||
/*
|
||||
* Since 2.4.0
|
||||
*/
|
||||
/*12.0*/HB_SCRIPT_ELYMAIC = HB_TAG ('E','l','y','m'),
|
||||
/*12.0*/HB_SCRIPT_NANDINAGARI = HB_TAG ('N','a','n','d'),
|
||||
/*12.0*/HB_SCRIPT_NYIAKENG_PUACHUE_HMONG = HB_TAG ('H','m','n','p'),
|
||||
/*12.0*/HB_SCRIPT_WANCHO = HB_TAG ('W','c','h','o'),
|
||||
|
||||
/*
|
||||
* Since 2.6.7
|
||||
*/
|
||||
/*13.0*/HB_SCRIPT_CHORASMIAN = HB_TAG ('C','h','r','s'),
|
||||
/*13.0*/HB_SCRIPT_DIVES_AKURU = HB_TAG ('D','i','a','k'),
|
||||
/*13.0*/HB_SCRIPT_KHITAN_SMALL_SCRIPT = HB_TAG ('K','i','t','s'),
|
||||
/*13.0*/HB_SCRIPT_YEZIDI = HB_TAG ('Y','e','z','i'),
|
||||
|
||||
/* No script set. */
|
||||
HB_SCRIPT_INVALID = HB_TAG_NONE,
|
||||
|
||||
@ -415,6 +433,21 @@ typedef void (*hb_destroy_func_t) (void *user_data);
|
||||
*/
|
||||
#define HB_FEATURE_GLOBAL_END ((unsigned int) -1)
|
||||
|
||||
/**
|
||||
* hb_feature_t:
|
||||
* @tag: a feature tag
|
||||
* @value: 0 disables the feature, non-zero (usually 1) enables the feature.
|
||||
* For features implemented as lookup type 3 (like 'salt') the @value is a one
|
||||
* based index into the alternates.
|
||||
* @start: the cluster to start applying this feature setting (inclusive).
|
||||
* @end: the cluster to end applying this feature setting (exclusive).
|
||||
*
|
||||
* The #hb_feature_t is the structure that holds information about requested
|
||||
* feature application. The feature will be applied with the given value to all
|
||||
* glyphs which are in clusters between @start (inclusive) and @end (exclusive).
|
||||
* Setting start to @HB_FEATURE_GLOBAL_START and end to @HB_FEATURE_GLOBAL_END
|
||||
* specifies that the feature always applies to the entire buffer.
|
||||
*/
|
||||
typedef struct hb_feature_t {
|
||||
hb_tag_t tag;
|
||||
uint32_t value;
|
||||
@ -459,39 +492,21 @@ typedef uint32_t hb_color_t;
|
||||
|
||||
#define HB_COLOR(b,g,r,a) ((hb_color_t) HB_TAG ((b),(g),(r),(a)))
|
||||
|
||||
/**
|
||||
* hb_color_get_alpha:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
HB_EXTERN uint8_t
|
||||
hb_color_get_alpha (hb_color_t color);
|
||||
#define hb_color_get_alpha(color) ((color) & 0xFF)
|
||||
/**
|
||||
* hb_color_get_red:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
#define hb_color_get_red(color) (((color) >> 8) & 0xFF)
|
||||
/**
|
||||
* hb_color_get_green:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
#define hb_color_get_green(color) (((color) >> 16) & 0xFF)
|
||||
/**
|
||||
* hb_color_get_blue:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
#define hb_color_get_blue(color) (((color) >> 24) & 0xFF)
|
||||
|
||||
HB_EXTERN uint8_t
|
||||
hb_color_get_red (hb_color_t color);
|
||||
#define hb_color_get_red(color) (((color) >> 8) & 0xFF)
|
||||
|
||||
HB_EXTERN uint8_t
|
||||
hb_color_get_green (hb_color_t color);
|
||||
#define hb_color_get_green(color) (((color) >> 16) & 0xFF)
|
||||
|
||||
HB_EXTERN uint8_t
|
||||
hb_color_get_blue (hb_color_t color);
|
||||
#define hb_color_get_blue(color) (((color) >> 24) & 0xFF)
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
|
||||
163
src/java.desktop/share/native/libharfbuzz/hb-config.hh
Normal file
163
src/java.desktop/share/native/libharfbuzz/hb-config.hh
Normal file
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright © 2019 Facebook, 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.
|
||||
*
|
||||
* Facebook Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_CONFIG_HH
|
||||
#define HB_CONFIG_HH
|
||||
|
||||
#if 0 /* Make test happy. */
|
||||
#include "hb.hh"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HB_TINY
|
||||
#define HB_LEAN
|
||||
#define HB_MINI
|
||||
#define HB_NO_MT
|
||||
#define HB_NO_UCD_UNASSIGNED
|
||||
#ifndef NDEBUG
|
||||
#define NDEBUG
|
||||
#endif
|
||||
#ifndef __OPTIMIZE_SIZE__
|
||||
#define __OPTIMIZE_SIZE__
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HB_LEAN
|
||||
#define HB_DISABLE_DEPRECATED
|
||||
#define HB_NDEBUG
|
||||
#define HB_NO_ATEXIT
|
||||
#define HB_NO_BUFFER_MESSAGE
|
||||
#define HB_NO_BUFFER_SERIALIZE
|
||||
#define HB_NO_BITMAP
|
||||
#define HB_NO_CFF
|
||||
#define HB_NO_COLOR
|
||||
#define HB_NO_DRAW
|
||||
#define HB_NO_ERRNO
|
||||
#define HB_NO_FACE_COLLECT_UNICODES
|
||||
#define HB_NO_GETENV
|
||||
#define HB_NO_HINTING
|
||||
#define HB_NO_LANGUAGE_PRIVATE_SUBTAG
|
||||
#define HB_NO_LAYOUT_FEATURE_PARAMS
|
||||
#define HB_NO_LAYOUT_COLLECT_GLYPHS
|
||||
#define HB_NO_LAYOUT_UNUSED
|
||||
#define HB_NO_MATH
|
||||
#define HB_NO_META
|
||||
#define HB_NO_METRICS
|
||||
#define HB_NO_MMAP
|
||||
#define HB_NO_NAME
|
||||
#define HB_NO_OPEN
|
||||
#define HB_NO_SETLOCALE
|
||||
#define HB_NO_OT_FONT_GLYPH_NAMES
|
||||
#define HB_NO_OT_SHAPE_FRACTIONS
|
||||
#define HB_NO_STYLE
|
||||
#define HB_NO_SUBSET_LAYOUT
|
||||
#define HB_NO_VAR
|
||||
#endif
|
||||
|
||||
#ifdef HB_MINI
|
||||
#define HB_NO_AAT
|
||||
#define HB_NO_LEGACY
|
||||
#endif
|
||||
|
||||
|
||||
/* Closure of options. */
|
||||
|
||||
#ifdef HB_DISABLE_DEPRECATED
|
||||
#define HB_IF_NOT_DEPRECATED(x)
|
||||
#else
|
||||
#define HB_IF_NOT_DEPRECATED(x) x
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_AAT
|
||||
#define HB_NO_OT_NAME_LANGUAGE_AAT
|
||||
#define HB_NO_AAT_SHAPE
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_BITMAP
|
||||
#define HB_NO_OT_FONT_BITMAP
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_CFF
|
||||
#define HB_NO_OT_FONT_CFF
|
||||
#define HB_NO_SUBSET_CFF
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_GETENV
|
||||
#define HB_NO_UNISCRIBE_BUG_COMPATIBLE
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_LEGACY
|
||||
#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_SHAPE_FALLBACK
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_NAME
|
||||
#define HB_NO_OT_NAME_LANGUAGE
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_OT
|
||||
#define HB_NO_OT_FONT
|
||||
#define HB_NO_OT_LAYOUT
|
||||
#define HB_NO_OT_TAG
|
||||
#define HB_NO_OT_SHAPE
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_OT_SHAPE
|
||||
#define HB_NO_AAT_SHAPE
|
||||
#endif
|
||||
|
||||
#ifdef HB_NO_OT_SHAPE_FALLBACK
|
||||
#define HB_NO_OT_SHAPE_COMPLEX_ARABIC_FALLBACK
|
||||
#define HB_NO_OT_SHAPE_COMPLEX_HEBREW_FALLBACK
|
||||
#define HB_NO_OT_SHAPE_COMPLEX_THAI_FALLBACK
|
||||
#define HB_NO_OT_SHAPE_COMPLEX_VOWEL_CONSTRAINTS
|
||||
#endif
|
||||
|
||||
#ifdef NDEBUG
|
||||
#ifndef HB_NDEBUG
|
||||
#define HB_NDEBUG
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __OPTIMIZE_SIZE__
|
||||
#ifndef HB_OPTIMIZE_SIZE
|
||||
#define HB_OPTIMIZE_SIZE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_CONFIG_OVERRIDE_H
|
||||
#include "config-override.h"
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* HB_CONFIG_HH */
|
||||
@ -27,6 +27,9 @@
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#ifdef HAVE_CORETEXT
|
||||
|
||||
#include "hb-shaper-impl.hh"
|
||||
|
||||
#include "hb-coretext.h"
|
||||
@ -46,24 +49,6 @@
|
||||
/* https://developer.apple.com/documentation/coretext/1508745-ctfontcreatewithgraphicsfont */
|
||||
#define HB_CORETEXT_DEFAULT_FONT_SIZE 12.f
|
||||
|
||||
static CGFloat
|
||||
coretext_font_size_from_ptem (float ptem)
|
||||
{
|
||||
/* CoreText points are CSS pixels (96 per inch),
|
||||
* NOT typographic points (72 per inch).
|
||||
*
|
||||
* https://developer.apple.com/library/content/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html
|
||||
*/
|
||||
ptem *= 96.f / 72.f;
|
||||
return ptem <= 0.f ? HB_CORETEXT_DEFAULT_FONT_SIZE : ptem;
|
||||
}
|
||||
static float
|
||||
coretext_font_size_to_ptem (CGFloat size)
|
||||
{
|
||||
size *= 72.f / 96.f;
|
||||
return size <= 0.f ? 0 : size;
|
||||
}
|
||||
|
||||
static void
|
||||
release_table_data (void *user_data)
|
||||
{
|
||||
@ -72,7 +57,7 @@ release_table_data (void *user_data)
|
||||
}
|
||||
|
||||
static hb_blob_t *
|
||||
reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
|
||||
_hb_cg_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
|
||||
{
|
||||
CGFontRef cg_font = reinterpret_cast<CGFontRef> (user_data);
|
||||
CFDataRef cf_data = CGFontCopyTableForTag (cg_font, tag);
|
||||
@ -171,7 +156,7 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size)
|
||||
if (CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSText")) ||
|
||||
CFStringHasPrefix (cg_postscript_name, CFSTR (".SFNSDisplay")))
|
||||
{
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
|
||||
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1080
|
||||
# define kCTFontUIFontSystem kCTFontSystemFontType
|
||||
# define kCTFontUIFontEmphasizedSystem kCTFontEmphasizedSystemFontType
|
||||
#endif
|
||||
@ -214,7 +199,7 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size)
|
||||
}
|
||||
|
||||
CFURLRef original_url = nullptr;
|
||||
#if TARGET_OS_OSX && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
|
||||
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
|
||||
ATSFontRef atsFont;
|
||||
FSRef fsref;
|
||||
OSStatus status;
|
||||
@ -244,7 +229,7 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size)
|
||||
* process in Blink. This can be detected by the new file URL location
|
||||
* that the newly found font points to. */
|
||||
CFURLRef new_url = nullptr;
|
||||
#if TARGET_OS_OSX && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
|
||||
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
|
||||
atsFont = CTFontGetPlatformFont (new_ct_font, NULL);
|
||||
status = ATSFontGetFileReference (atsFont, &fsref);
|
||||
if (status == noErr)
|
||||
@ -293,13 +278,32 @@ _hb_coretext_shaper_face_data_destroy (hb_coretext_face_data_t *data)
|
||||
CFRelease ((CGFontRef) data);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_coretext_face_create:
|
||||
* @cg_font: The CGFontRef to work upon
|
||||
*
|
||||
* Creates an #hb_face_t face object from the specified
|
||||
* CGFontRef.
|
||||
*
|
||||
* Return value: the new #hb_face_t face object
|
||||
*
|
||||
* Since: 0.9.10
|
||||
*/
|
||||
hb_face_t *
|
||||
hb_coretext_face_create (CGFontRef cg_font)
|
||||
{
|
||||
return hb_face_create_for_tables (reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
|
||||
return hb_face_create_for_tables (_hb_cg_reference_table, CGFontRetain (cg_font), _hb_cg_font_release);
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* hb_coretext_face_get_cg_font:
|
||||
* @face: The #hb_face_t to work upon
|
||||
*
|
||||
* Fetches the CGFontRef associated with an #hb_face_t
|
||||
* face object
|
||||
*
|
||||
* Return value: the CGFontRef found
|
||||
*
|
||||
* Since: 0.9.10
|
||||
*/
|
||||
CGFontRef
|
||||
@ -317,7 +321,8 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font)
|
||||
if (unlikely (!face_data)) return nullptr;
|
||||
CGFontRef cg_font = (CGFontRef) (const void *) face->data.coretext;
|
||||
|
||||
CTFontRef ct_font = create_ct_font (cg_font, coretext_font_size_from_ptem (font->ptem));
|
||||
CGFloat font_size = (CGFloat) (font->ptem <= 0.f ? HB_CORETEXT_DEFAULT_FONT_SIZE : font->ptem);
|
||||
CTFontRef ct_font = create_ct_font (cg_font, font_size);
|
||||
|
||||
if (unlikely (!ct_font))
|
||||
{
|
||||
@ -341,7 +346,7 @@ retry:
|
||||
const hb_coretext_font_data_t *data = font->data.coretext;
|
||||
if (unlikely (!data)) return nullptr;
|
||||
|
||||
if (fabs (CTFontGetSize((CTFontRef) data) - coretext_font_size_from_ptem (font->ptem)) > .5)
|
||||
if (fabs (CTFontGetSize ((CTFontRef) data) - (CGFloat) font->ptem) > .5)
|
||||
{
|
||||
/* XXX-MT-bug
|
||||
* Note that evaluating condition above can be dangerous if another thread
|
||||
@ -365,10 +370,17 @@ retry:
|
||||
return font->data.coretext;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
/**
|
||||
* hb_coretext_font_create:
|
||||
* @ct_font: The CTFontRef to work upon
|
||||
*
|
||||
* Creates an #hb_font_t font object from the specified
|
||||
* CTFontRef.
|
||||
*
|
||||
* Return value: the new #hb_font_t font object
|
||||
*
|
||||
* Since: 1.7.2
|
||||
*/
|
||||
**/
|
||||
hb_font_t *
|
||||
hb_coretext_font_create (CTFontRef ct_font)
|
||||
{
|
||||
@ -381,7 +393,7 @@ hb_coretext_font_create (CTFontRef ct_font)
|
||||
if (unlikely (hb_object_is_immutable (font)))
|
||||
return font;
|
||||
|
||||
hb_font_set_ptem (font, coretext_font_size_to_ptem (CTFontGetSize(ct_font)));
|
||||
hb_font_set_ptem (font, CTFontGetSize (ct_font));
|
||||
|
||||
/* Let there be dragons here... */
|
||||
font->data.coretext.cmpexch (nullptr, (hb_coretext_font_data_t *) CFRetain (ct_font));
|
||||
@ -389,6 +401,17 @@ hb_coretext_font_create (CTFontRef ct_font)
|
||||
return font;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_coretext_face_get_ct_font:
|
||||
* @font: #hb_font_t to work upon
|
||||
*
|
||||
* Fetches the CTFontRef associated with the specified
|
||||
* #hb_font_t font object.
|
||||
*
|
||||
* Return value: the CTFontRef found
|
||||
*
|
||||
* Since: 0.9.10
|
||||
*/
|
||||
CTFontRef
|
||||
hb_coretext_font_get_ct_font (hb_font_t *font)
|
||||
{
|
||||
@ -410,7 +433,7 @@ struct active_feature_t {
|
||||
feature_record_t rec;
|
||||
unsigned int order;
|
||||
|
||||
static int cmp (const void *pa, const void *pb) {
|
||||
HB_INTERNAL static int cmp (const void *pa, const void *pb) {
|
||||
const active_feature_t *a = (const active_feature_t *) pa;
|
||||
const active_feature_t *b = (const active_feature_t *) pb;
|
||||
return a->rec.feature < b->rec.feature ? -1 : a->rec.feature > b->rec.feature ? 1 :
|
||||
@ -428,7 +451,7 @@ struct feature_event_t {
|
||||
bool start;
|
||||
active_feature_t feature;
|
||||
|
||||
static int cmp (const void *pa, const void *pb) {
|
||||
HB_INTERNAL static int cmp (const void *pa, const void *pb) {
|
||||
const feature_event_t *a = (const feature_event_t *) pa;
|
||||
const feature_event_t *b = (const feature_event_t *) pb;
|
||||
return a->index < b->index ? -1 : a->index > b->index ? 1 :
|
||||
@ -489,13 +512,19 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
|
||||
hb_vector_t<feature_event_t> feature_events;
|
||||
for (unsigned int i = 0; i < num_features; i++)
|
||||
{
|
||||
active_feature_t feature;
|
||||
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000
|
||||
const hb_aat_feature_mapping_t * mapping = hb_aat_layout_find_feature_mapping (features[i].tag);
|
||||
if (!mapping)
|
||||
continue;
|
||||
|
||||
active_feature_t feature;
|
||||
feature.rec.feature = mapping->aatFeatureType;
|
||||
feature.rec.setting = features[i].value ? mapping->selectorToEnable : mapping->selectorToDisable;
|
||||
#else
|
||||
feature.rec.feature = features[i].tag;
|
||||
feature.rec.setting = features[i].value;
|
||||
#endif
|
||||
feature.order = i;
|
||||
|
||||
feature_event_t *event;
|
||||
@ -544,6 +573,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
|
||||
/* active_features.qsort (); */
|
||||
for (unsigned int j = 0; j < active_features.length; j++)
|
||||
{
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000
|
||||
CFStringRef keys[] = {
|
||||
kCTFontFeatureTypeIdentifierKey,
|
||||
kCTFontFeatureSelectorIdentifierKey
|
||||
@ -552,6 +582,17 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
|
||||
CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.feature),
|
||||
CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting)
|
||||
};
|
||||
#else
|
||||
char tag[5] = {HB_UNTAG (active_features[j].rec.feature)};
|
||||
CFTypeRef keys[] = {
|
||||
kCTFontOpenTypeFeatureTag,
|
||||
kCTFontOpenTypeFeatureValue
|
||||
};
|
||||
CFTypeRef values[] = {
|
||||
CFStringCreateWithCString (kCFAllocatorDefault, tag, kCFStringEncodingASCII),
|
||||
CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &active_features[j].rec.setting)
|
||||
};
|
||||
#endif
|
||||
static_assert ((ARRAY_LENGTH_CONST (keys) == ARRAY_LENGTH_CONST (values)), "");
|
||||
CFDictionaryRef dict = CFDictionaryCreate (kCFAllocatorDefault,
|
||||
(const void **) keys,
|
||||
@ -598,7 +639,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
|
||||
} else {
|
||||
active_feature_t *feature = active_features.find (&event->feature);
|
||||
if (feature)
|
||||
active_features.remove (feature - active_features.arrayZ ());
|
||||
active_features.remove (feature - active_features.arrayZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -608,7 +649,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
|
||||
|
||||
#define ALLOCATE_ARRAY(Type, name, len, on_no_room) \
|
||||
Type *name = (Type *) scratch; \
|
||||
{ \
|
||||
do { \
|
||||
unsigned int _consumed = DIV_CEIL ((len) * sizeof (Type), sizeof (*scratch)); \
|
||||
if (unlikely (_consumed > scratch_size)) \
|
||||
{ \
|
||||
@ -617,9 +658,9 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
|
||||
} \
|
||||
scratch += _consumed; \
|
||||
scratch_size -= _consumed; \
|
||||
}
|
||||
} while (0)
|
||||
|
||||
ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2, /*nothing*/);
|
||||
ALLOCATE_ARRAY (UniChar, pchars, buffer->len * 2, ((void)nullptr) /*nothing*/);
|
||||
unsigned int chars_len = 0;
|
||||
for (unsigned int i = 0; i < buffer->len; i++) {
|
||||
hb_codepoint_t c = buffer->info[i].codepoint;
|
||||
@ -633,7 +674,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
|
||||
}
|
||||
}
|
||||
|
||||
ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len, /*nothing*/);
|
||||
ALLOCATE_ARRAY (unsigned int, log_clusters, chars_len, ((void)nullptr) /*nothing*/);
|
||||
chars_len = 0;
|
||||
for (unsigned int i = 0; i < buffer->len; i++)
|
||||
{
|
||||
@ -649,7 +690,7 @@ _hb_coretext_shape (hb_shape_plan_t *shape_plan,
|
||||
DEBUG_MSG (CORETEXT, nullptr, __VA_ARGS__); \
|
||||
ret = false; \
|
||||
goto fail; \
|
||||
} HB_STMT_END;
|
||||
} HB_STMT_END
|
||||
|
||||
bool ret = true;
|
||||
CFStringRef string_ref = nullptr;
|
||||
@ -711,7 +752,7 @@ resize_and_retry:
|
||||
/* What's the iOS equivalent of this check?
|
||||
* The symbols was introduced in iOS 7.0.
|
||||
* At any rate, our fallback is safe and works fine. */
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1090
|
||||
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1090
|
||||
# define kCTLanguageAttributeName CFSTR ("NSLanguage")
|
||||
#endif
|
||||
CFStringRef lang = CFStringCreateWithCStringNoCopy (kCFAllocatorDefault,
|
||||
@ -771,7 +812,7 @@ resize_and_retry:
|
||||
feature.start < chars_len && feature.start < feature.end)
|
||||
{
|
||||
CFRange feature_range = CFRangeMake (feature.start,
|
||||
MIN (feature.end, chars_len) - feature.start);
|
||||
hb_min (feature.end, chars_len) - feature.start);
|
||||
if (feature.value)
|
||||
CFAttributedStringRemoveAttribute (attr_string, feature_range, kCTKernAttributeName);
|
||||
else
|
||||
@ -783,7 +824,7 @@ resize_and_retry:
|
||||
|
||||
int level = HB_DIRECTION_IS_FORWARD (buffer->props.direction) ? 0 : 1;
|
||||
CFNumberRef level_number = CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &level);
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
|
||||
#if !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && MAC_OS_X_VERSION_MIN_REQUIRED < 1060
|
||||
extern const CFStringRef kCTTypesetterOptionForcedEmbeddingLevel;
|
||||
#endif
|
||||
CFDictionaryRef options = CFDictionaryCreate (kCFAllocatorDefault,
|
||||
@ -977,7 +1018,7 @@ resize_and_retry:
|
||||
|
||||
#define SCRATCH_RESTORE() \
|
||||
scratch_size = scratch_size_saved; \
|
||||
scratch = scratch_saved;
|
||||
scratch = scratch_saved
|
||||
|
||||
{ /* Setup glyphs */
|
||||
SCRATCH_SAVE();
|
||||
@ -1069,7 +1110,7 @@ resize_and_retry:
|
||||
if (false)
|
||||
{
|
||||
/* Make sure all runs had the expected direction. */
|
||||
bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
|
||||
HB_UNUSED bool backward = HB_DIRECTION_IS_BACKWARD (buffer->props.direction);
|
||||
assert (bool (status_and & kCTRunStatusRightToLeft) == backward);
|
||||
assert (bool (status_or & kCTRunStatusRightToLeft) == backward);
|
||||
}
|
||||
@ -1116,7 +1157,7 @@ resize_and_retry:
|
||||
unsigned int cluster = info[count - 1].cluster;
|
||||
for (unsigned int i = count - 1; i > 0; i--)
|
||||
{
|
||||
cluster = MIN (cluster, info[i - 1].cluster);
|
||||
cluster = hb_min (cluster, info[i - 1].cluster);
|
||||
info[i - 1].cluster = cluster;
|
||||
}
|
||||
}
|
||||
@ -1125,7 +1166,7 @@ resize_and_retry:
|
||||
unsigned int cluster = info[0].cluster;
|
||||
for (unsigned int i = 1; i < count; i++)
|
||||
{
|
||||
cluster = MIN (cluster, info[i].cluster);
|
||||
cluster = hb_min (cluster, info[i].cluster);
|
||||
info[i].cluster = cluster;
|
||||
}
|
||||
}
|
||||
@ -1150,57 +1191,4 @@ fail:
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* AAT shaper
|
||||
*/
|
||||
|
||||
/*
|
||||
* shaper face data
|
||||
*/
|
||||
|
||||
struct hb_coretext_aat_face_data_t {};
|
||||
|
||||
hb_coretext_aat_face_data_t *
|
||||
_hb_coretext_aat_shaper_face_data_create (hb_face_t *face)
|
||||
{
|
||||
return hb_aat_layout_has_substitution (face) || hb_aat_layout_has_positioning (face) ?
|
||||
(hb_coretext_aat_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_face_data_t *data HB_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* shaper font data
|
||||
*/
|
||||
|
||||
struct hb_coretext_aat_font_data_t {};
|
||||
|
||||
hb_coretext_aat_font_data_t *
|
||||
_hb_coretext_aat_shaper_font_data_create (hb_font_t *font)
|
||||
{
|
||||
return font->data.coretext ? (hb_coretext_aat_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_font_data_t *data HB_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* shaper
|
||||
*/
|
||||
|
||||
hb_bool_t
|
||||
_hb_coretext_aat_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_coretext_shape (shape_plan, font, buffer, features, num_features);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -40,8 +40,40 @@
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
|
||||
/**
|
||||
* HB_CORETEXT_TAG_MORT:
|
||||
*
|
||||
* The #hb_tag_t tag for the `mort` (glyph metamorphosis) table,
|
||||
* which holds AAT features.
|
||||
*
|
||||
* For more information, see
|
||||
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6mort.html
|
||||
*
|
||||
**/
|
||||
#define HB_CORETEXT_TAG_MORT HB_TAG('m','o','r','t')
|
||||
|
||||
/**
|
||||
* HB_CORETEXT_TAG_MORX:
|
||||
*
|
||||
* The #hb_tag_t tag for the `morx` (extended glyph metamorphosis)
|
||||
* table, which holds AAT features.
|
||||
*
|
||||
* For more information, see
|
||||
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6morx.html
|
||||
*
|
||||
**/
|
||||
#define HB_CORETEXT_TAG_MORX HB_TAG('m','o','r','x')
|
||||
|
||||
/**
|
||||
* HB_CORETEXT_TAG_KERX:
|
||||
*
|
||||
* The #hb_tag_t tag for the `kerx` (extended kerning) table, which
|
||||
* holds AAT kerning information.
|
||||
*
|
||||
* For more information, see
|
||||
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6kerx.html
|
||||
*
|
||||
**/
|
||||
#define HB_CORETEXT_TAG_KERX HB_TAG('k','e','r','x')
|
||||
|
||||
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
|
||||
#include "hb.hh"
|
||||
#include "hb-atomic.hh"
|
||||
#include "hb-dsalgs.hh"
|
||||
#include "hb-algs.hh"
|
||||
|
||||
|
||||
#ifndef HB_DEBUG
|
||||
@ -46,7 +46,6 @@ struct hb_options_t
|
||||
bool unused : 1; /* In-case sign bit is here. */
|
||||
bool initialized : 1;
|
||||
bool uniscribe_bug_compatible : 1;
|
||||
bool aat : 1;
|
||||
};
|
||||
|
||||
union hb_options_union_t {
|
||||
@ -63,6 +62,9 @@ extern HB_INTERNAL hb_atomic_int_t _hb_options;
|
||||
static inline hb_options_t
|
||||
hb_options ()
|
||||
{
|
||||
#ifdef HB_NO_GETENV
|
||||
return hb_options_t ();
|
||||
#endif
|
||||
/* Make a local copy, so we can access bitfield threadsafely. */
|
||||
hb_options_union_t u;
|
||||
u.i = _hb_options.get_relaxed ();
|
||||
@ -158,7 +160,7 @@ _hb_debug_msg_va (const char *what,
|
||||
VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR VBAR;
|
||||
fprintf (stderr, "%2u %s" VRBAR "%s",
|
||||
level,
|
||||
bars + sizeof (bars) - 1 - MIN ((unsigned int) sizeof (bars) - 1, (unsigned int) (sizeof (VBAR) - 1) * level),
|
||||
bars + sizeof (bars) - 1 - hb_min ((unsigned int) sizeof (bars) - 1, (unsigned int) (sizeof (VBAR) - 1) * level),
|
||||
level_dir ? (level_dir > 0 ? DLBAR : ULBAR) : LBAR);
|
||||
} else
|
||||
fprintf (stderr, " " VRBAR LBAR);
|
||||
@ -246,8 +248,8 @@ struct hb_printer_t<bool> {
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hb_printer_t<hb_void_t> {
|
||||
const char *print (hb_void_t) { return ""; }
|
||||
struct hb_printer_t<hb_empty_t> {
|
||||
const char *print (hb_empty_t) { return ""; }
|
||||
};
|
||||
|
||||
|
||||
@ -263,7 +265,7 @@ static inline void _hb_warn_no_return (bool returned)
|
||||
}
|
||||
}
|
||||
template <>
|
||||
/*static*/ inline void _hb_warn_no_return<hb_void_t> (bool returned HB_UNUSED)
|
||||
/*static*/ inline void _hb_warn_no_return<hb_empty_t> (bool returned HB_UNUSED)
|
||||
{}
|
||||
|
||||
template <int max_level, typename ret_t>
|
||||
@ -293,22 +295,23 @@ struct hb_auto_trace_t
|
||||
if (plevel) --*plevel;
|
||||
}
|
||||
|
||||
ret_t ret (ret_t v,
|
||||
const char *func = "",
|
||||
unsigned int line = 0)
|
||||
template <typename T>
|
||||
T ret (T&& v,
|
||||
const char *func = "",
|
||||
unsigned int line = 0)
|
||||
{
|
||||
if (unlikely (returned)) {
|
||||
fprintf (stderr, "OUCH, double calls to return_trace(). This is a bug, please report.\n");
|
||||
return v;
|
||||
return hb_forward<T> (v);
|
||||
}
|
||||
|
||||
_hb_debug_msg<max_level> (what, obj, func, true, plevel ? *plevel : 1, -1,
|
||||
"return %s (line %d)",
|
||||
hb_printer_t<ret_t>().print (v), line);
|
||||
hb_printer_t<decltype (v)>().print (v), line);
|
||||
if (plevel) --*plevel;
|
||||
plevel = nullptr;
|
||||
returned = true;
|
||||
return v;
|
||||
return hb_forward<T> (v);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -327,18 +330,20 @@ struct hb_auto_trace_t<0, ret_t>
|
||||
const char *message,
|
||||
...) HB_PRINTF_FUNC(6, 7) {}
|
||||
|
||||
ret_t ret (ret_t v,
|
||||
const char *func HB_UNUSED = nullptr,
|
||||
unsigned int line HB_UNUSED = 0) { return v; }
|
||||
template <typename T>
|
||||
T ret (T&& v,
|
||||
const char *func HB_UNUSED = nullptr,
|
||||
unsigned int line HB_UNUSED = 0) { return hb_forward<T> (v); }
|
||||
};
|
||||
|
||||
/* For disabled tracing; optimize out everything.
|
||||
* https://github.com/harfbuzz/harfbuzz/pull/605 */
|
||||
template <typename ret_t>
|
||||
struct hb_no_trace_t {
|
||||
ret_t ret (ret_t v,
|
||||
const char *func HB_UNUSED = "",
|
||||
unsigned int line HB_UNUSED = 0) { return v; }
|
||||
template <typename T>
|
||||
T ret (T&& v,
|
||||
const char *func HB_UNUSED = nullptr,
|
||||
unsigned int line HB_UNUSED = 0) { return hb_forward<T> (v); }
|
||||
};
|
||||
|
||||
#define return_trace(RET) return trace.ret (RET, HB_FUNC, __LINE__)
|
||||
@ -368,10 +373,6 @@ struct hb_no_trace_t {
|
||||
#define HB_DEBUG_FT (HB_DEBUG+0)
|
||||
#endif
|
||||
|
||||
#ifndef HB_DEBUG_GET_COVERAGE
|
||||
#define HB_DEBUG_GET_COVERAGE (HB_DEBUG+0)
|
||||
#endif
|
||||
|
||||
#ifndef HB_DEBUG_OBJECT
|
||||
#define HB_DEBUG_OBJECT (HB_DEBUG+0)
|
||||
#endif
|
||||
@ -408,7 +409,7 @@ struct hb_no_trace_t {
|
||||
#define TRACE_SANITIZE(this) \
|
||||
hb_auto_trace_t<HB_DEBUG_SANITIZE, bool> trace \
|
||||
(&c->debug_depth, c->get_name (), this, HB_FUNC, \
|
||||
" ");
|
||||
" ")
|
||||
#else
|
||||
#define TRACE_SANITIZE(this) hb_no_trace_t<bool> trace
|
||||
#endif
|
||||
@ -420,7 +421,7 @@ struct hb_no_trace_t {
|
||||
#define TRACE_SERIALIZE(this) \
|
||||
hb_auto_trace_t<HB_DEBUG_SERIALIZE, bool> trace \
|
||||
(&c->debug_depth, "SERIALIZE", c, HB_FUNC, \
|
||||
" ");
|
||||
" ")
|
||||
#else
|
||||
#define TRACE_SERIALIZE(this) hb_no_trace_t<bool> trace
|
||||
#endif
|
||||
@ -432,37 +433,24 @@ struct hb_no_trace_t {
|
||||
#define TRACE_SUBSET(this) \
|
||||
hb_auto_trace_t<HB_DEBUG_SUBSET, bool> trace \
|
||||
(&c->debug_depth, c->get_name (), this, HB_FUNC, \
|
||||
" ");
|
||||
" ")
|
||||
#else
|
||||
#define TRACE_SUBSET(this) hb_no_trace_t<bool> trace
|
||||
#endif
|
||||
|
||||
#ifndef HB_DEBUG_WOULD_APPLY
|
||||
#define HB_DEBUG_WOULD_APPLY (HB_DEBUG+0)
|
||||
#endif
|
||||
#if HB_DEBUG_WOULD_APPLY
|
||||
#define TRACE_WOULD_APPLY(this) \
|
||||
hb_auto_trace_t<HB_DEBUG_WOULD_APPLY, bool> trace \
|
||||
(&c->debug_depth, c->get_name (), this, HB_FUNC, \
|
||||
"%d glyphs", c->len);
|
||||
#else
|
||||
#define TRACE_WOULD_APPLY(this) hb_no_trace_t<bool> trace
|
||||
#endif
|
||||
|
||||
#ifndef HB_DEBUG_DISPATCH
|
||||
#define HB_DEBUG_DISPATCH ( \
|
||||
HB_DEBUG_APPLY + \
|
||||
HB_DEBUG_SANITIZE + \
|
||||
HB_DEBUG_SERIALIZE + \
|
||||
HB_DEBUG_SUBSET + \
|
||||
HB_DEBUG_WOULD_APPLY + \
|
||||
HB_DEBUG_SUBSET + \
|
||||
0)
|
||||
#endif
|
||||
#if HB_DEBUG_DISPATCH
|
||||
#define TRACE_DISPATCH(this, format) \
|
||||
hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
|
||||
(&c->debug_depth, c->get_name (), this, HB_FUNC, \
|
||||
"format %d", (int) format);
|
||||
"format %d", (int) format)
|
||||
#else
|
||||
#define TRACE_DISPATCH(this, format) hb_no_trace_t<typename context_t::return_t> trace
|
||||
#endif
|
||||
|
||||
@ -63,7 +63,7 @@ typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data,
|
||||
hb_codepoint_t *glyph,
|
||||
void *user_data);
|
||||
|
||||
HB_EXTERN HB_DEPRECATED_FOR(hb_font_funcs_set_nominal_glyph_func or hb_font_funcs_set_variation_glyph_func) void
|
||||
HB_EXTERN HB_DEPRECATED_FOR(hb_font_funcs_set_nominal_glyph_func and hb_font_funcs_set_variation_glyph_func) void
|
||||
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);
|
||||
@ -165,29 +165,8 @@ hb_unicode_decompose_compatibility (hb_unicode_funcs_t *ufuncs,
|
||||
hb_codepoint_t *decomposed);
|
||||
|
||||
|
||||
typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void *font_data,
|
||||
hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
|
||||
void *user_data);
|
||||
typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t;
|
||||
typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_v_kerning_func_t;
|
||||
|
||||
/**
|
||||
* hb_font_funcs_set_glyph_h_kerning_func:
|
||||
* @ffuncs: font functions.
|
||||
* @func: (closure user_data) (destroy destroy) (scope notified):
|
||||
* @user_data:
|
||||
* @destroy:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 0.9.2
|
||||
* Deprecated: 2.0.0
|
||||
**/
|
||||
HB_EXTERN void
|
||||
hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs,
|
||||
hb_font_get_glyph_h_kerning_func_t func,
|
||||
void *user_data, hb_destroy_func_t destroy);
|
||||
|
||||
/**
|
||||
* hb_font_funcs_set_glyph_v_kerning_func:
|
||||
* @ffuncs: font functions.
|
||||
@ -206,19 +185,9 @@ hb_font_funcs_set_glyph_v_kerning_func (hb_font_funcs_t *ffuncs,
|
||||
void *user_data, hb_destroy_func_t destroy);
|
||||
|
||||
HB_EXTERN hb_position_t
|
||||
hb_font_get_glyph_h_kerning (hb_font_t *font,
|
||||
hb_codepoint_t left_glyph, hb_codepoint_t right_glyph);
|
||||
HB_EXTERN hb_position_t
|
||||
hb_font_get_glyph_v_kerning (hb_font_t *font,
|
||||
hb_codepoint_t top_glyph, hb_codepoint_t bottom_glyph);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
|
||||
hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
|
||||
hb_direction_t direction,
|
||||
hb_position_t *x, hb_position_t *y);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
61
src/java.desktop/share/native/libharfbuzz/hb-dispatch.hh
Normal file
61
src/java.desktop/share/native/libharfbuzz/hb-dispatch.hh
Normal file
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright © 2007,2008,2009,2010 Red Hat, Inc.
|
||||
* Copyright © 2012,2018 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.
|
||||
*
|
||||
* Red Hat Author(s): Behdad Esfahbod
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_DISPATCH_HH
|
||||
#define HB_DISPATCH_HH
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
/*
|
||||
* Dispatch
|
||||
*/
|
||||
|
||||
template <typename Context, typename Return=hb_empty_t, unsigned int MaxDebugDepth=0>
|
||||
struct hb_dispatch_context_t
|
||||
{
|
||||
hb_dispatch_context_t () : debug_depth (0) {}
|
||||
private:
|
||||
/* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
|
||||
const Context* thiz () const { return static_cast<const Context *> (this); }
|
||||
Context* thiz () { return static_cast< Context *> (this); }
|
||||
public:
|
||||
const char *get_name () { return "UNKNOWN"; }
|
||||
static constexpr unsigned max_debug_depth = MaxDebugDepth;
|
||||
typedef Return return_t;
|
||||
template <typename T, typename F>
|
||||
bool may_dispatch (const T *obj HB_UNUSED, const F *format HB_UNUSED) { return true; }
|
||||
template <typename T, typename ...Ts>
|
||||
return_t dispatch (const T &obj, Ts&&... ds)
|
||||
{ return obj.dispatch (thiz (), hb_forward<Ts> (ds)...); }
|
||||
static return_t no_dispatch_return_value () { return Context::default_return_value (); }
|
||||
static bool stop_sublookup_iteration (const return_t r HB_UNUSED) { return false; }
|
||||
unsigned debug_depth;
|
||||
};
|
||||
|
||||
|
||||
#endif /* HB_DISPATCH_HH */
|
||||
261
src/java.desktop/share/native/libharfbuzz/hb-draw.cc
Normal file
261
src/java.desktop/share/native/libharfbuzz/hb-draw.cc
Normal file
@ -0,0 +1,261 @@
|
||||
/*
|
||||
* Copyright © 2019-2020 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#ifndef HB_NO_DRAW
|
||||
#ifdef HB_EXPERIMENTAL_API
|
||||
|
||||
#include "hb-draw.hh"
|
||||
#include "hb-ot.h"
|
||||
#include "hb-ot-glyf-table.hh"
|
||||
#include "hb-ot-cff1-table.hh"
|
||||
#include "hb-ot-cff2-table.hh"
|
||||
|
||||
/**
|
||||
* hb_draw_funcs_set_move_to_func:
|
||||
* @funcs: draw functions object
|
||||
* @move_to: move-to callback
|
||||
*
|
||||
* Sets move-to callback to the draw functions object.
|
||||
*
|
||||
* Since: EXPERIMENTAL
|
||||
**/
|
||||
void
|
||||
hb_draw_funcs_set_move_to_func (hb_draw_funcs_t *funcs,
|
||||
hb_draw_move_to_func_t move_to)
|
||||
{
|
||||
if (unlikely (hb_object_is_immutable (funcs))) return;
|
||||
funcs->move_to = move_to;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_draw_funcs_set_line_to_func:
|
||||
* @funcs: draw functions object
|
||||
* @line_to: line-to callback
|
||||
*
|
||||
* Sets line-to callback to the draw functions object.
|
||||
*
|
||||
* Since: EXPERIMENTAL
|
||||
**/
|
||||
void
|
||||
hb_draw_funcs_set_line_to_func (hb_draw_funcs_t *funcs,
|
||||
hb_draw_line_to_func_t line_to)
|
||||
{
|
||||
if (unlikely (hb_object_is_immutable (funcs))) return;
|
||||
funcs->line_to = line_to;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_draw_funcs_set_quadratic_to_func:
|
||||
* @funcs: draw functions object
|
||||
* @move_to: quadratic-to callback
|
||||
*
|
||||
* Sets quadratic-to callback to the draw functions object.
|
||||
*
|
||||
* Since: EXPERIMENTAL
|
||||
**/
|
||||
void
|
||||
hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t *funcs,
|
||||
hb_draw_quadratic_to_func_t quadratic_to)
|
||||
{
|
||||
if (unlikely (hb_object_is_immutable (funcs))) return;
|
||||
funcs->quadratic_to = quadratic_to;
|
||||
funcs->is_quadratic_to_set = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_draw_funcs_set_cubic_to_func:
|
||||
* @funcs: draw functions
|
||||
* @cubic_to: cubic-to callback
|
||||
*
|
||||
* Sets cubic-to callback to the draw functions object.
|
||||
*
|
||||
* Since: EXPERIMENTAL
|
||||
**/
|
||||
void
|
||||
hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t *funcs,
|
||||
hb_draw_cubic_to_func_t cubic_to)
|
||||
{
|
||||
if (unlikely (hb_object_is_immutable (funcs))) return;
|
||||
funcs->cubic_to = cubic_to;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_draw_funcs_set_close_path_func:
|
||||
* @funcs: draw functions object
|
||||
* @close_path: close-path callback
|
||||
*
|
||||
* Sets close-path callback to the draw functions object.
|
||||
*
|
||||
* Since: EXPERIMENTAL
|
||||
**/
|
||||
void
|
||||
hb_draw_funcs_set_close_path_func (hb_draw_funcs_t *funcs,
|
||||
hb_draw_close_path_func_t close_path)
|
||||
{
|
||||
if (unlikely (hb_object_is_immutable (funcs))) return;
|
||||
funcs->close_path = close_path;
|
||||
}
|
||||
|
||||
static void
|
||||
_move_to_nil (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {}
|
||||
|
||||
static void
|
||||
_line_to_nil (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {}
|
||||
|
||||
static void
|
||||
_quadratic_to_nil (hb_position_t control_x HB_UNUSED, hb_position_t control_y HB_UNUSED,
|
||||
hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED,
|
||||
void *user_data HB_UNUSED) {}
|
||||
|
||||
static void
|
||||
_cubic_to_nil (hb_position_t control1_x HB_UNUSED, hb_position_t control1_y HB_UNUSED,
|
||||
hb_position_t control2_x HB_UNUSED, hb_position_t control2_y HB_UNUSED,
|
||||
hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED,
|
||||
void *user_data HB_UNUSED) {}
|
||||
|
||||
static void
|
||||
_close_path_nil (void *user_data HB_UNUSED) {}
|
||||
|
||||
/**
|
||||
* hb_draw_funcs_create:
|
||||
*
|
||||
* Creates a new draw callbacks object.
|
||||
*
|
||||
* Since: EXPERIMENTAL
|
||||
**/
|
||||
hb_draw_funcs_t *
|
||||
hb_draw_funcs_create ()
|
||||
{
|
||||
hb_draw_funcs_t *funcs;
|
||||
if (unlikely (!(funcs = hb_object_create<hb_draw_funcs_t> ())))
|
||||
return const_cast<hb_draw_funcs_t *> (&Null (hb_draw_funcs_t));
|
||||
|
||||
funcs->move_to = (hb_draw_move_to_func_t) _move_to_nil;
|
||||
funcs->line_to = (hb_draw_line_to_func_t) _line_to_nil;
|
||||
funcs->quadratic_to = (hb_draw_quadratic_to_func_t) _quadratic_to_nil;
|
||||
funcs->is_quadratic_to_set = false;
|
||||
funcs->cubic_to = (hb_draw_cubic_to_func_t) _cubic_to_nil;
|
||||
funcs->close_path = (hb_draw_close_path_func_t) _close_path_nil;
|
||||
return funcs;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_draw_funcs_reference:
|
||||
* @funcs: draw functions
|
||||
*
|
||||
* Add to callbacks object refcount.
|
||||
*
|
||||
* Returns: The same object.
|
||||
* Since: EXPERIMENTAL
|
||||
**/
|
||||
hb_draw_funcs_t *
|
||||
hb_draw_funcs_reference (hb_draw_funcs_t *funcs)
|
||||
{
|
||||
return hb_object_reference (funcs);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_draw_funcs_destroy:
|
||||
* @funcs: draw functions
|
||||
*
|
||||
* Decreases refcount of callbacks object and deletes the object if it reaches
|
||||
* to zero.
|
||||
*
|
||||
* Since: EXPERIMENTAL
|
||||
**/
|
||||
void
|
||||
hb_draw_funcs_destroy (hb_draw_funcs_t *funcs)
|
||||
{
|
||||
if (!hb_object_destroy (funcs)) return;
|
||||
|
||||
free (funcs);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_draw_funcs_make_immutable:
|
||||
* @funcs: draw functions
|
||||
*
|
||||
* Makes funcs object immutable.
|
||||
*
|
||||
* Since: EXPERIMENTAL
|
||||
**/
|
||||
void
|
||||
hb_draw_funcs_make_immutable (hb_draw_funcs_t *funcs)
|
||||
{
|
||||
if (hb_object_is_immutable (funcs))
|
||||
return;
|
||||
|
||||
hb_object_make_immutable (funcs);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_draw_funcs_is_immutable:
|
||||
* @funcs: draw functions
|
||||
*
|
||||
* Checks whether funcs is immutable.
|
||||
*
|
||||
* Returns: If is immutable.
|
||||
* Since: EXPERIMENTAL
|
||||
**/
|
||||
hb_bool_t
|
||||
hb_draw_funcs_is_immutable (hb_draw_funcs_t *funcs)
|
||||
{
|
||||
return hb_object_is_immutable (funcs);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_font_draw_glyph:
|
||||
* @font: a font object
|
||||
* @glyph: a glyph id
|
||||
* @funcs: draw callbacks object
|
||||
* @user_data: parameter you like be passed to the callbacks when are called
|
||||
*
|
||||
* Draw a glyph.
|
||||
*
|
||||
* Returns: Whether the font had the glyph and the operation completed successfully.
|
||||
* Since: EXPERIMENTAL
|
||||
**/
|
||||
hb_bool_t
|
||||
hb_font_draw_glyph (hb_font_t *font, hb_codepoint_t glyph,
|
||||
const hb_draw_funcs_t *funcs,
|
||||
void *user_data)
|
||||
{
|
||||
if (unlikely (funcs == &Null (hb_draw_funcs_t) ||
|
||||
glyph >= font->face->get_num_glyphs ()))
|
||||
return false;
|
||||
|
||||
draw_helper_t draw_helper (funcs, user_data);
|
||||
if (font->face->table.glyf->get_path (font, glyph, draw_helper)) return true;
|
||||
#ifndef HB_NO_CFF
|
||||
if (font->face->table.cff1->get_path (font, glyph, draw_helper)) return true;
|
||||
if (font->face->table.cff2->get_path (font, glyph, draw_helper)) return true;
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
98
src/java.desktop/share/native/libharfbuzz/hb-draw.h
Normal file
98
src/java.desktop/share/native/libharfbuzz/hb-draw.h
Normal file
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright © 2019-2020 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#ifndef HB_H_IN
|
||||
#error "Include <hb.h> instead."
|
||||
#endif
|
||||
|
||||
#ifndef HB_DRAW_H
|
||||
#define HB_DRAW_H
|
||||
|
||||
#include "hb.h"
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
#ifdef HB_EXPERIMENTAL_API
|
||||
typedef void (*hb_draw_move_to_func_t) (hb_position_t to_x, hb_position_t to_y, void *user_data);
|
||||
typedef void (*hb_draw_line_to_func_t) (hb_position_t to_x, hb_position_t to_y, void *user_data);
|
||||
typedef void (*hb_draw_quadratic_to_func_t) (hb_position_t control_x, hb_position_t control_y,
|
||||
hb_position_t to_x, hb_position_t to_y,
|
||||
void *user_data);
|
||||
typedef void (*hb_draw_cubic_to_func_t) (hb_position_t control1_x, hb_position_t control1_y,
|
||||
hb_position_t control2_x, hb_position_t control2_y,
|
||||
hb_position_t to_x, hb_position_t to_y,
|
||||
void *user_data);
|
||||
typedef void (*hb_draw_close_path_func_t) (void *user_data);
|
||||
|
||||
/**
|
||||
* hb_draw_funcs_t:
|
||||
*
|
||||
* Glyph draw callbacks.
|
||||
*
|
||||
* _move_to, _line_to and _cubic_to calls are nessecary to be defined but we
|
||||
* translate _quadratic_to calls to _cubic_to if the callback isn't defined.
|
||||
*
|
||||
* Since: EXPERIMENTAL
|
||||
**/
|
||||
typedef struct hb_draw_funcs_t hb_draw_funcs_t;
|
||||
|
||||
HB_EXTERN void
|
||||
hb_draw_funcs_set_move_to_func (hb_draw_funcs_t *funcs,
|
||||
hb_draw_move_to_func_t move_to);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_draw_funcs_set_line_to_func (hb_draw_funcs_t *funcs,
|
||||
hb_draw_line_to_func_t line_to);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_draw_funcs_set_quadratic_to_func (hb_draw_funcs_t *funcs,
|
||||
hb_draw_quadratic_to_func_t quadratic_to);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_draw_funcs_set_cubic_to_func (hb_draw_funcs_t *funcs,
|
||||
hb_draw_cubic_to_func_t cubic_to);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_draw_funcs_set_close_path_func (hb_draw_funcs_t *funcs,
|
||||
hb_draw_close_path_func_t close_path);
|
||||
|
||||
HB_EXTERN hb_draw_funcs_t *
|
||||
hb_draw_funcs_create (void);
|
||||
|
||||
HB_EXTERN hb_draw_funcs_t *
|
||||
hb_draw_funcs_reference (hb_draw_funcs_t *funcs);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_draw_funcs_destroy (hb_draw_funcs_t *funcs);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_draw_funcs_make_immutable (hb_draw_funcs_t *funcs);
|
||||
|
||||
HB_EXTERN hb_bool_t
|
||||
hb_draw_funcs_is_immutable (hb_draw_funcs_t *funcs);
|
||||
#endif
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
#endif /* HB_DRAW_H */
|
||||
139
src/java.desktop/share/native/libharfbuzz/hb-draw.hh
Normal file
139
src/java.desktop/share/native/libharfbuzz/hb-draw.hh
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright © 2020 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*/
|
||||
|
||||
#ifndef HB_DRAW_HH
|
||||
#define HB_DRAW_HH
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#ifdef HB_EXPERIMENTAL_API
|
||||
struct hb_draw_funcs_t
|
||||
{
|
||||
hb_object_header_t header;
|
||||
|
||||
hb_draw_move_to_func_t move_to;
|
||||
hb_draw_line_to_func_t line_to;
|
||||
hb_draw_quadratic_to_func_t quadratic_to;
|
||||
bool is_quadratic_to_set;
|
||||
hb_draw_cubic_to_func_t cubic_to;
|
||||
hb_draw_close_path_func_t close_path;
|
||||
};
|
||||
|
||||
struct draw_helper_t
|
||||
{
|
||||
draw_helper_t (const hb_draw_funcs_t *funcs_, void *user_data_)
|
||||
{
|
||||
funcs = funcs_;
|
||||
user_data = user_data_;
|
||||
path_open = false;
|
||||
path_start_x = current_x = path_start_y = current_y = 0;
|
||||
}
|
||||
~draw_helper_t () { end_path (); }
|
||||
|
||||
void move_to (hb_position_t x, hb_position_t y)
|
||||
{
|
||||
if (path_open) end_path ();
|
||||
current_x = path_start_x = x;
|
||||
current_y = path_start_y = y;
|
||||
}
|
||||
|
||||
void line_to (hb_position_t x, hb_position_t y)
|
||||
{
|
||||
if (equal_to_current (x, y)) return;
|
||||
if (!path_open) start_path ();
|
||||
funcs->line_to (x, y, user_data);
|
||||
current_x = x;
|
||||
current_y = y;
|
||||
}
|
||||
|
||||
void
|
||||
quadratic_to (hb_position_t control_x, hb_position_t control_y,
|
||||
hb_position_t to_x, hb_position_t to_y)
|
||||
{
|
||||
if (equal_to_current (control_x, control_y) && equal_to_current (to_x, to_y))
|
||||
return;
|
||||
if (!path_open) start_path ();
|
||||
if (funcs->is_quadratic_to_set)
|
||||
funcs->quadratic_to (control_x, control_y, to_x, to_y, user_data);
|
||||
else
|
||||
funcs->cubic_to (roundf ((current_x + 2.f * control_x) / 3.f),
|
||||
roundf ((current_y + 2.f * control_y) / 3.f),
|
||||
roundf ((to_x + 2.f * control_x) / 3.f),
|
||||
roundf ((to_y + 2.f * control_y) / 3.f),
|
||||
to_x, to_y, user_data);
|
||||
current_x = to_x;
|
||||
current_y = to_y;
|
||||
}
|
||||
|
||||
void
|
||||
cubic_to (hb_position_t control1_x, hb_position_t control1_y,
|
||||
hb_position_t control2_x, hb_position_t control2_y,
|
||||
hb_position_t to_x, hb_position_t to_y)
|
||||
{
|
||||
if (equal_to_current (control1_x, control1_y) &&
|
||||
equal_to_current (control2_x, control2_y) &&
|
||||
equal_to_current (to_x, to_y))
|
||||
return;
|
||||
if (!path_open) start_path ();
|
||||
funcs->cubic_to (control1_x, control1_y, control2_x, control2_y, to_x, to_y, user_data);
|
||||
current_x = to_x;
|
||||
current_y = to_y;
|
||||
}
|
||||
|
||||
void end_path ()
|
||||
{
|
||||
if (path_open)
|
||||
{
|
||||
if ((path_start_x != current_x) || (path_start_y != current_y))
|
||||
funcs->line_to (path_start_x, path_start_y, user_data);
|
||||
funcs->close_path (user_data);
|
||||
}
|
||||
path_open = false;
|
||||
path_start_x = current_x = path_start_y = current_y = 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool equal_to_current (hb_position_t x, hb_position_t y)
|
||||
{ return current_x == x && current_y == y; }
|
||||
|
||||
void start_path ()
|
||||
{
|
||||
if (path_open) end_path ();
|
||||
path_open = true;
|
||||
funcs->move_to (path_start_x, path_start_y, user_data);
|
||||
}
|
||||
|
||||
hb_position_t path_start_x;
|
||||
hb_position_t path_start_y;
|
||||
|
||||
hb_position_t current_x;
|
||||
hb_position_t current_y;
|
||||
|
||||
bool path_open;
|
||||
const hb_draw_funcs_t *funcs;
|
||||
void *user_data;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* HB_DRAW_HH */
|
||||
@ -1,632 +0,0 @@
|
||||
/*
|
||||
* Copyright © 2017 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_DSALGS_HH
|
||||
#define HB_DSALGS_HH
|
||||
|
||||
#include "hb.hh"
|
||||
#include "hb-null.hh"
|
||||
|
||||
|
||||
/* Void! For when we need a expression-type of void. */
|
||||
typedef const struct _hb_void_t *hb_void_t;
|
||||
#define HB_VOID ((const _hb_void_t *) nullptr)
|
||||
|
||||
|
||||
/*
|
||||
* Bithacks.
|
||||
*/
|
||||
|
||||
/* Return the number of 1 bits in v. */
|
||||
template <typename T>
|
||||
static inline HB_CONST_FUNC unsigned int
|
||||
hb_popcount (T v)
|
||||
{
|
||||
#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
|
||||
if (sizeof (T) <= sizeof (unsigned int))
|
||||
return __builtin_popcount (v);
|
||||
|
||||
if (sizeof (T) <= sizeof (unsigned long))
|
||||
return __builtin_popcountl (v);
|
||||
|
||||
if (sizeof (T) <= sizeof (unsigned long long))
|
||||
return __builtin_popcountll (v);
|
||||
#endif
|
||||
|
||||
if (sizeof (T) <= 4)
|
||||
{
|
||||
/* "HACKMEM 169" */
|
||||
uint32_t y;
|
||||
y = (v >> 1) &033333333333;
|
||||
y = v - y - ((y >>1) & 033333333333);
|
||||
return (((y + (y >> 3)) & 030707070707) % 077);
|
||||
}
|
||||
|
||||
if (sizeof (T) == 8)
|
||||
{
|
||||
unsigned int shift = 32;
|
||||
return hb_popcount<uint32_t> ((uint32_t) v) + hb_popcount ((uint32_t) (v >> shift));
|
||||
}
|
||||
|
||||
if (sizeof (T) == 16)
|
||||
{
|
||||
unsigned int shift = 64;
|
||||
return hb_popcount<uint64_t> ((uint64_t) v) + hb_popcount ((uint64_t) (v >> shift));
|
||||
}
|
||||
|
||||
assert (0);
|
||||
return 0; /* Shut up stupid compiler. */
|
||||
}
|
||||
|
||||
/* Returns the number of bits needed to store number */
|
||||
template <typename T>
|
||||
static inline HB_CONST_FUNC unsigned int
|
||||
hb_bit_storage (T v)
|
||||
{
|
||||
if (unlikely (!v)) return 0;
|
||||
|
||||
#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
|
||||
if (sizeof (T) <= sizeof (unsigned int))
|
||||
return sizeof (unsigned int) * 8 - __builtin_clz (v);
|
||||
|
||||
if (sizeof (T) <= sizeof (unsigned long))
|
||||
return sizeof (unsigned long) * 8 - __builtin_clzl (v);
|
||||
|
||||
if (sizeof (T) <= sizeof (unsigned long long))
|
||||
return sizeof (unsigned long long) * 8 - __builtin_clzll (v);
|
||||
#endif
|
||||
|
||||
#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
|
||||
if (sizeof (T) <= sizeof (unsigned int))
|
||||
{
|
||||
unsigned long where;
|
||||
_BitScanReverse (&where, v);
|
||||
return 1 + where;
|
||||
}
|
||||
# if defined(_WIN64)
|
||||
if (sizeof (T) <= 8)
|
||||
{
|
||||
unsigned long where;
|
||||
_BitScanReverse64 (&where, v);
|
||||
return 1 + where;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
if (sizeof (T) <= 4)
|
||||
{
|
||||
/* "bithacks" */
|
||||
const unsigned int b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
|
||||
const unsigned int S[] = {1, 2, 4, 8, 16};
|
||||
unsigned int r = 0;
|
||||
for (int i = 4; i >= 0; i--)
|
||||
if (v & b[i])
|
||||
{
|
||||
v >>= S[i];
|
||||
r |= S[i];
|
||||
}
|
||||
return r + 1;
|
||||
}
|
||||
if (sizeof (T) <= 8)
|
||||
{
|
||||
/* "bithacks" */
|
||||
const uint64_t b[] = {0x2ULL, 0xCULL, 0xF0ULL, 0xFF00ULL, 0xFFFF0000ULL, 0xFFFFFFFF00000000ULL};
|
||||
const unsigned int S[] = {1, 2, 4, 8, 16, 32};
|
||||
unsigned int r = 0;
|
||||
for (int i = 5; i >= 0; i--)
|
||||
if (v & b[i])
|
||||
{
|
||||
v >>= S[i];
|
||||
r |= S[i];
|
||||
}
|
||||
return r + 1;
|
||||
}
|
||||
if (sizeof (T) == 16)
|
||||
{
|
||||
unsigned int shift = 64;
|
||||
return (v >> shift) ? hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift :
|
||||
hb_bit_storage<uint64_t> ((uint64_t) v);
|
||||
}
|
||||
|
||||
assert (0);
|
||||
return 0; /* Shut up stupid compiler. */
|
||||
}
|
||||
|
||||
/* Returns the number of zero bits in the least significant side of v */
|
||||
template <typename T>
|
||||
static inline HB_CONST_FUNC unsigned int
|
||||
hb_ctz (T v)
|
||||
{
|
||||
if (unlikely (!v)) return 0;
|
||||
|
||||
#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
|
||||
if (sizeof (T) <= sizeof (unsigned int))
|
||||
return __builtin_ctz (v);
|
||||
|
||||
if (sizeof (T) <= sizeof (unsigned long))
|
||||
return __builtin_ctzl (v);
|
||||
|
||||
if (sizeof (T) <= sizeof (unsigned long long))
|
||||
return __builtin_ctzll (v);
|
||||
#endif
|
||||
|
||||
#if (defined(_MSC_VER) && _MSC_VER >= 1500) || defined(__MINGW32__)
|
||||
if (sizeof (T) <= sizeof (unsigned int))
|
||||
{
|
||||
unsigned long where;
|
||||
_BitScanForward (&where, v);
|
||||
return where;
|
||||
}
|
||||
# if defined(_WIN64)
|
||||
if (sizeof (T) <= 8)
|
||||
{
|
||||
unsigned long where;
|
||||
_BitScanForward64 (&where, v);
|
||||
return where;
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
if (sizeof (T) <= 4)
|
||||
{
|
||||
/* "bithacks" */
|
||||
unsigned int c = 32;
|
||||
v &= - (int32_t) v;
|
||||
if (v) c--;
|
||||
if (v & 0x0000FFFF) c -= 16;
|
||||
if (v & 0x00FF00FF) c -= 8;
|
||||
if (v & 0x0F0F0F0F) c -= 4;
|
||||
if (v & 0x33333333) c -= 2;
|
||||
if (v & 0x55555555) c -= 1;
|
||||
return c;
|
||||
}
|
||||
if (sizeof (T) <= 8)
|
||||
{
|
||||
/* "bithacks" */
|
||||
unsigned int c = 64;
|
||||
v &= - (int64_t) (v);
|
||||
if (v) c--;
|
||||
if (v & 0x00000000FFFFFFFFULL) c -= 32;
|
||||
if (v & 0x0000FFFF0000FFFFULL) c -= 16;
|
||||
if (v & 0x00FF00FF00FF00FFULL) c -= 8;
|
||||
if (v & 0x0F0F0F0F0F0F0F0FULL) c -= 4;
|
||||
if (v & 0x3333333333333333ULL) c -= 2;
|
||||
if (v & 0x5555555555555555ULL) c -= 1;
|
||||
return c;
|
||||
}
|
||||
if (sizeof (T) == 16)
|
||||
{
|
||||
unsigned int shift = 64;
|
||||
return (uint64_t) v ? hb_bit_storage<uint64_t> ((uint64_t) v) :
|
||||
hb_bit_storage<uint64_t> ((uint64_t) (v >> shift)) + shift;
|
||||
}
|
||||
|
||||
assert (0);
|
||||
return 0; /* Shut up stupid compiler. */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Tiny stuff.
|
||||
*/
|
||||
|
||||
template <typename T>
|
||||
static inline T* hb_addressof (T& arg)
|
||||
{
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wcast-align"
|
||||
/* https://en.cppreference.com/w/cpp/memory/addressof */
|
||||
return reinterpret_cast<T*>(
|
||||
&const_cast<char&>(
|
||||
reinterpret_cast<const volatile char&>(arg)));
|
||||
#pragma GCC diagnostic pop
|
||||
}
|
||||
|
||||
/* ASCII tag/character handling */
|
||||
static inline bool ISALPHA (unsigned char c)
|
||||
{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); }
|
||||
static inline bool ISALNUM (unsigned char c)
|
||||
{ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); }
|
||||
static inline bool ISSPACE (unsigned char c)
|
||||
{ return c == ' ' || c =='\f'|| c =='\n'|| c =='\r'|| c =='\t'|| c =='\v'; }
|
||||
static inline unsigned char TOUPPER (unsigned char c)
|
||||
{ return (c >= 'a' && c <= 'z') ? c - 'a' + 'A' : c; }
|
||||
static inline unsigned char TOLOWER (unsigned char c)
|
||||
{ return (c >= 'A' && c <= 'Z') ? c - 'A' + 'a' : c; }
|
||||
|
||||
#undef MIN
|
||||
template <typename Type>
|
||||
static inline Type MIN (const Type &a, const Type &b) { return a < b ? a : b; }
|
||||
|
||||
#undef MAX
|
||||
template <typename Type>
|
||||
static inline Type MAX (const Type &a, const Type &b) { return a > b ? a : b; }
|
||||
|
||||
static inline unsigned int DIV_CEIL (const unsigned int a, unsigned int b)
|
||||
{ return (a + (b - 1)) / b; }
|
||||
|
||||
|
||||
#undef ARRAY_LENGTH
|
||||
template <typename Type, unsigned int n>
|
||||
static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
|
||||
/* A const version, but does not detect erratically being called on pointers. */
|
||||
#define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
|
||||
|
||||
|
||||
static inline int
|
||||
hb_memcmp (const void *a, const void *b, unsigned int len)
|
||||
{
|
||||
/* It's illegal to pass NULL to memcmp(), even if len is zero.
|
||||
* So, wrap it.
|
||||
* https://sourceware.org/bugzilla/show_bug.cgi?id=23878 */
|
||||
if (!len) return 0;
|
||||
return memcmp (a, b, len);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
hb_unsigned_mul_overflows (unsigned int count, unsigned int size)
|
||||
{
|
||||
return (size > 0) && (count >= ((unsigned int) -1) / size);
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
hb_ceil_to_4 (unsigned int v)
|
||||
{
|
||||
return ((v - 1) | 3) + 1;
|
||||
}
|
||||
|
||||
template <typename T> struct hb_is_signed;
|
||||
/* https://github.com/harfbuzz/harfbuzz/issues/1535 */
|
||||
template <> struct hb_is_signed<int8_t> { enum { value = true }; };
|
||||
template <> struct hb_is_signed<int16_t> { enum { value = true }; };
|
||||
template <> struct hb_is_signed<int32_t> { enum { value = true }; };
|
||||
template <> struct hb_is_signed<int64_t> { enum { value = true }; };
|
||||
template <> struct hb_is_signed<uint8_t> { enum { value = false }; };
|
||||
template <> struct hb_is_signed<uint16_t> { enum { value = false }; };
|
||||
template <> struct hb_is_signed<uint32_t> { enum { value = false }; };
|
||||
template <> struct hb_is_signed<uint64_t> { enum { value = false }; };
|
||||
|
||||
template <typename T> static inline bool
|
||||
hb_in_range (T u, T lo, T hi)
|
||||
{
|
||||
/* The sizeof() is here to force template instantiation.
|
||||
* I'm sure there are better ways to do this but can't think of
|
||||
* one right now. Declaring a variable won't work as HB_UNUSED
|
||||
* is unusable on some platforms and unused types are less likely
|
||||
* to generate a warning than unused variables. */
|
||||
static_assert (!hb_is_signed<T>::value, "");
|
||||
|
||||
/* The casts below are important as if T is smaller than int,
|
||||
* the subtract results will become a signed int! */
|
||||
return (T)(u - lo) <= (T)(hi - lo);
|
||||
}
|
||||
template <typename T> static inline bool
|
||||
hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2)
|
||||
{
|
||||
return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2);
|
||||
}
|
||||
template <typename T> static inline bool
|
||||
hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
|
||||
{
|
||||
return hb_in_range (u, lo1, hi1) || hb_in_range (u, lo2, hi2) || hb_in_range (u, lo3, hi3);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Sort and search.
|
||||
*/
|
||||
|
||||
static inline void *
|
||||
hb_bsearch (const void *key, const void *base,
|
||||
size_t nmemb, size_t size,
|
||||
int (*compar)(const void *_key, const void *_item))
|
||||
{
|
||||
int min = 0, max = (int) nmemb - 1;
|
||||
while (min <= max)
|
||||
{
|
||||
int mid = (min + max) / 2;
|
||||
const void *p = (const void *) (((const char *) base) + (mid * size));
|
||||
int c = compar (key, p);
|
||||
if (c < 0)
|
||||
max = mid - 1;
|
||||
else if (c > 0)
|
||||
min = mid + 1;
|
||||
else
|
||||
return (void *) p;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
hb_bsearch_r (const void *key, const void *base,
|
||||
size_t nmemb, size_t size,
|
||||
int (*compar)(const void *_key, const void *_item, void *_arg),
|
||||
void *arg)
|
||||
{
|
||||
int min = 0, max = (int) nmemb - 1;
|
||||
while (min <= max)
|
||||
{
|
||||
int mid = ((unsigned int) min + (unsigned int) max) / 2;
|
||||
const void *p = (const void *) (((const char *) base) + (mid * size));
|
||||
int c = compar (key, p, arg);
|
||||
if (c < 0)
|
||||
max = mid - 1;
|
||||
else if (c > 0)
|
||||
min = mid + 1;
|
||||
else
|
||||
return (void *) p;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
/* From https://github.com/noporpoise/sort_r
|
||||
* With following modifications:
|
||||
*
|
||||
* 10 November 2018:
|
||||
* https://github.com/noporpoise/sort_r/issues/7
|
||||
*/
|
||||
|
||||
/* Isaac Turner 29 April 2014 Public Domain */
|
||||
|
||||
/*
|
||||
|
||||
hb_sort_r function to be exported.
|
||||
|
||||
Parameters:
|
||||
base is the array to be sorted
|
||||
nel is the number of elements in the array
|
||||
width is the size in bytes of each element of the array
|
||||
compar is the comparison function
|
||||
arg is a pointer to be passed to the comparison function
|
||||
|
||||
void hb_sort_r(void *base, size_t nel, size_t width,
|
||||
int (*compar)(const void *_a, const void *_b, void *_arg),
|
||||
void *arg);
|
||||
*/
|
||||
|
||||
|
||||
/* swap a, b iff a>b */
|
||||
/* __restrict is same as restrict but better support on old machines */
|
||||
static int sort_r_cmpswap(char *__restrict a, char *__restrict b, size_t w,
|
||||
int (*compar)(const void *_a, const void *_b,
|
||||
void *_arg),
|
||||
void *arg)
|
||||
{
|
||||
char tmp, *end = a+w;
|
||||
if(compar(a, b, arg) > 0) {
|
||||
for(; a < end; a++, b++) { tmp = *a; *a = *b; *b = tmp; }
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Note: quicksort is not stable, equivalent values may be swapped */
|
||||
static inline void sort_r_simple(void *base, size_t nel, size_t w,
|
||||
int (*compar)(const void *_a, const void *_b,
|
||||
void *_arg),
|
||||
void *arg)
|
||||
{
|
||||
char *b = (char *)base, *end = b + nel*w;
|
||||
if(nel < 7) {
|
||||
/* Insertion sort for arbitrarily small inputs */
|
||||
char *pi, *pj;
|
||||
for(pi = b+w; pi < end; pi += w) {
|
||||
for(pj = pi; pj > b && sort_r_cmpswap(pj-w,pj,w,compar,arg); pj -= w) {}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* nel > 6; Quicksort */
|
||||
|
||||
/* Use median of first, middle and last items as pivot */
|
||||
char *x, *y, *xend, ch;
|
||||
char *pl, *pm, *pr;
|
||||
char *last = b+w*(nel-1), *tmp;
|
||||
char *l[3];
|
||||
l[0] = b;
|
||||
l[1] = b+w*(nel/2);
|
||||
l[2] = last;
|
||||
|
||||
if(compar(l[0],l[1],arg) > 0) { tmp=l[0]; l[0]=l[1]; l[1]=tmp; }
|
||||
if(compar(l[1],l[2],arg) > 0) {
|
||||
tmp=l[1]; l[1]=l[2]; l[2]=tmp; /* swap(l[1],l[2]) */
|
||||
if(compar(l[0],l[1],arg) > 0) { tmp=l[0]; l[0]=l[1]; l[1]=tmp; }
|
||||
}
|
||||
|
||||
/* swap l[id], l[2] to put pivot as last element */
|
||||
for(x = l[1], y = last, xend = x+w; x<xend; x++, y++) {
|
||||
ch = *x; *x = *y; *y = ch;
|
||||
}
|
||||
|
||||
pl = b;
|
||||
pr = last;
|
||||
|
||||
while(pl < pr) {
|
||||
pm = pl+((pr-pl+1)>>1);
|
||||
for(; pl < pm; pl += w) {
|
||||
if(sort_r_cmpswap(pl, pr, w, compar, arg)) {
|
||||
pr -= w; /* pivot now at pl */
|
||||
break;
|
||||
}
|
||||
}
|
||||
pm = pl+((pr-pl)>>1);
|
||||
for(; pm < pr; pr -= w) {
|
||||
if(sort_r_cmpswap(pl, pr, w, compar, arg)) {
|
||||
pl += w; /* pivot now at pr */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sort_r_simple(b, (pl-b)/w, w, compar, arg);
|
||||
sort_r_simple(pl+w, (end-(pl+w))/w, w, compar, arg);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void hb_sort_r(void *base, size_t nel, size_t width,
|
||||
int (*compar)(const void *_a, const void *_b, void *_arg),
|
||||
void *arg)
|
||||
{
|
||||
sort_r_simple(base, nel, width, compar, arg);
|
||||
}
|
||||
|
||||
|
||||
template <typename T, typename T2> static inline void
|
||||
hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *), T2 *array2)
|
||||
{
|
||||
for (unsigned int i = 1; i < len; i++)
|
||||
{
|
||||
unsigned int j = i;
|
||||
while (j && compar (&array[j - 1], &array[i]) > 0)
|
||||
j--;
|
||||
if (i == j)
|
||||
continue;
|
||||
/* Move item i to occupy place for item j, shift what's in between. */
|
||||
{
|
||||
T t = array[i];
|
||||
memmove (&array[j + 1], &array[j], (i - j) * sizeof (T));
|
||||
array[j] = t;
|
||||
}
|
||||
if (array2)
|
||||
{
|
||||
T2 t = array2[i];
|
||||
memmove (&array2[j + 1], &array2[j], (i - j) * sizeof (T2));
|
||||
array2[j] = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T> static inline void
|
||||
hb_stable_sort (T *array, unsigned int len, int(*compar)(const T *, const T *))
|
||||
{
|
||||
hb_stable_sort (array, len, compar, (int *) nullptr);
|
||||
}
|
||||
|
||||
static inline hb_bool_t
|
||||
hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *out)
|
||||
{
|
||||
/* Pain because we don't know whether s is nul-terminated. */
|
||||
char buf[64];
|
||||
len = MIN (ARRAY_LENGTH (buf) - 1, len);
|
||||
strncpy (buf, s, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
char *end;
|
||||
errno = 0;
|
||||
unsigned long v = strtoul (buf, &end, base);
|
||||
if (errno) return false;
|
||||
if (*end) return false;
|
||||
*out = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
struct HbOpOr
|
||||
{
|
||||
static constexpr bool passthru_left = true;
|
||||
static constexpr bool passthru_right = true;
|
||||
template <typename T> static void process (T &o, const T &a, const T &b) { o = a | b; }
|
||||
};
|
||||
struct HbOpAnd
|
||||
{
|
||||
static constexpr bool passthru_left = false;
|
||||
static constexpr bool passthru_right = false;
|
||||
template <typename T> static void process (T &o, const T &a, const T &b) { o = a & b; }
|
||||
};
|
||||
struct HbOpMinus
|
||||
{
|
||||
static constexpr bool passthru_left = true;
|
||||
static constexpr bool passthru_right = false;
|
||||
template <typename T> static void process (T &o, const T &a, const T &b) { o = a & ~b; }
|
||||
};
|
||||
struct HbOpXor
|
||||
{
|
||||
static constexpr bool passthru_left = true;
|
||||
static constexpr bool passthru_right = true;
|
||||
template <typename T> static void process (T &o, const T &a, const T &b) { o = a ^ b; }
|
||||
};
|
||||
|
||||
|
||||
/* Compiler-assisted vectorization. */
|
||||
|
||||
/* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))),
|
||||
* using vectorized operations if HB_VECTOR_SIZE is set to **bit** numbers (eg 128).
|
||||
* Define that to 0 to disable. */
|
||||
template <typename elt_t, unsigned int byte_size>
|
||||
struct hb_vector_size_t
|
||||
{
|
||||
elt_t& operator [] (unsigned int i) { return u.v[i]; }
|
||||
const elt_t& operator [] (unsigned int i) const { return u.v[i]; }
|
||||
|
||||
void clear (unsigned char v = 0) { memset (this, v, sizeof (*this)); }
|
||||
|
||||
template <class Op>
|
||||
hb_vector_size_t process (const hb_vector_size_t &o) const
|
||||
{
|
||||
hb_vector_size_t r;
|
||||
#if HB_VECTOR_SIZE
|
||||
if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
|
||||
Op::process (r.u.vec[i], u.vec[i], o.u.vec[i]);
|
||||
else
|
||||
#endif
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
|
||||
Op::process (r.u.v[i], u.v[i], o.u.v[i]);
|
||||
return r;
|
||||
}
|
||||
hb_vector_size_t operator | (const hb_vector_size_t &o) const
|
||||
{ return process<HbOpOr> (o); }
|
||||
hb_vector_size_t operator & (const hb_vector_size_t &o) const
|
||||
{ return process<HbOpAnd> (o); }
|
||||
hb_vector_size_t operator ^ (const hb_vector_size_t &o) const
|
||||
{ return process<HbOpXor> (o); }
|
||||
hb_vector_size_t operator ~ () const
|
||||
{
|
||||
hb_vector_size_t r;
|
||||
#if HB_VECTOR_SIZE && 0
|
||||
if (HB_VECTOR_SIZE && 0 == (byte_size * 8) % HB_VECTOR_SIZE)
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH (u.vec); i++)
|
||||
r.u.vec[i] = ~u.vec[i];
|
||||
else
|
||||
#endif
|
||||
for (unsigned int i = 0; i < ARRAY_LENGTH (u.v); i++)
|
||||
r.u.v[i] = ~u.v[i];
|
||||
return r;
|
||||
}
|
||||
|
||||
private:
|
||||
static_assert (byte_size / sizeof (elt_t) * sizeof (elt_t) == byte_size, "");
|
||||
union {
|
||||
elt_t v[byte_size / sizeof (elt_t)];
|
||||
#if HB_VECTOR_SIZE
|
||||
hb_vector_size_impl_t vec[byte_size / sizeof (hb_vector_size_impl_t)];
|
||||
#endif
|
||||
} u;
|
||||
};
|
||||
|
||||
|
||||
#endif /* HB_DSALGS_HH */
|
||||
@ -200,10 +200,15 @@ hb_face_create (hb_blob_t *blob,
|
||||
if (unlikely (!blob))
|
||||
blob = hb_blob_get_empty ();
|
||||
|
||||
hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob)), index);
|
||||
blob = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob));
|
||||
|
||||
hb_face_for_data_closure_t *closure = _hb_face_for_data_closure_create (blob, index);
|
||||
|
||||
if (unlikely (!closure))
|
||||
{
|
||||
hb_blob_destroy (blob);
|
||||
return hb_face_get_empty ();
|
||||
}
|
||||
|
||||
face = hb_face_create_for_tables (_hb_face_for_data_reference_table,
|
||||
closure,
|
||||
@ -226,7 +231,7 @@ hb_face_create (hb_blob_t *blob,
|
||||
hb_face_t *
|
||||
hb_face_get_empty ()
|
||||
{
|
||||
return const_cast<hb_face_t *> (&Null(hb_face_t));
|
||||
return const_cast<hb_face_t *> (&Null (hb_face_t));
|
||||
}
|
||||
|
||||
|
||||
@ -367,6 +372,9 @@ hb_blob_t *
|
||||
hb_face_reference_table (const hb_face_t *face,
|
||||
hb_tag_t tag)
|
||||
{
|
||||
if (unlikely (tag == HB_TAG_NONE))
|
||||
return hb_blob_get_empty ();
|
||||
|
||||
return face->reference_table (tag);
|
||||
}
|
||||
|
||||
@ -531,6 +539,7 @@ hb_face_get_table_tags (const hb_face_t *face,
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HB_NO_FACE_COLLECT_UNICODES
|
||||
/**
|
||||
* hb_face_collect_unicodes:
|
||||
* @face: font face.
|
||||
@ -542,9 +551,8 @@ void
|
||||
hb_face_collect_unicodes (hb_face_t *face,
|
||||
hb_set_t *out)
|
||||
{
|
||||
face->table.cmap->collect_unicodes (out);
|
||||
face->table.cmap->collect_unicodes (out, face->get_num_glyphs ());
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_face_collect_variation_selectors:
|
||||
* @face: font face.
|
||||
@ -560,7 +568,6 @@ hb_face_collect_variation_selectors (hb_face_t *face,
|
||||
{
|
||||
face->table.cmap->collect_variation_selectors (out);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_face_collect_variation_unicodes:
|
||||
* @face: font face.
|
||||
@ -577,7 +584,7 @@ hb_face_collect_variation_unicodes (hb_face_t *face,
|
||||
{
|
||||
face->table.cmap->collect_variation_unicodes (variation_selector, out);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
@ -714,7 +721,10 @@ hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
|
||||
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 (data->tables.in_error())
|
||||
return false;
|
||||
|
||||
entry->tag = tag;
|
||||
entry->blob = hb_blob_reference (blob);
|
||||
|
||||
@ -94,7 +94,7 @@ struct hb_face_t
|
||||
unsigned int get_num_glyphs () const
|
||||
{
|
||||
unsigned int ret = num_glyphs.get_relaxed ();
|
||||
if (unlikely (ret == (unsigned int) -1))
|
||||
if (unlikely (ret == UINT_MAX))
|
||||
return load_num_glyphs ();
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
|
||||
#include "hb-shaper-impl.hh"
|
||||
|
||||
#ifndef HB_NO_FALLBACK_SHAPE
|
||||
|
||||
/*
|
||||
* shaper face data
|
||||
@ -120,3 +121,5 @@ _hb_fallback_shape (hb_shape_plan_t *shape_plan HB_UNUSED,
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -33,6 +33,9 @@
|
||||
|
||||
#include "hb-ot.h"
|
||||
|
||||
#include "hb-ot-var-avar-table.hh"
|
||||
#include "hb-ot-var-fvar-table.hh"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-font
|
||||
@ -355,6 +358,7 @@ hb_font_get_glyph_h_kerning_default (hb_font_t *font,
|
||||
return font->parent_scale_x_distance (font->parent->get_glyph_h_kerning (left_glyph, right_glyph));
|
||||
}
|
||||
|
||||
#ifndef HB_DISABLE_DEPRECATED
|
||||
static hb_position_t
|
||||
hb_font_get_glyph_v_kerning_nil (hb_font_t *font HB_UNUSED,
|
||||
void *font_data HB_UNUSED,
|
||||
@ -373,6 +377,7 @@ hb_font_get_glyph_v_kerning_default (hb_font_t *font,
|
||||
{
|
||||
return font->parent_scale_y_distance (font->parent->get_glyph_v_kerning (top_glyph, bottom_glyph));
|
||||
}
|
||||
#endif
|
||||
|
||||
static hb_bool_t
|
||||
hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED,
|
||||
@ -672,7 +677,8 @@ hb_font_funcs_set_##name##_func (hb_font_funcs_t *ffuncs, \
|
||||
void *user_data, \
|
||||
hb_destroy_func_t destroy) \
|
||||
{ \
|
||||
if (hb_object_is_immutable (ffuncs)) { \
|
||||
if (hb_object_is_immutable (ffuncs)) \
|
||||
{ \
|
||||
if (destroy) \
|
||||
destroy (user_data); \
|
||||
return; \
|
||||
@ -789,6 +795,29 @@ hb_font_get_nominal_glyph (hb_font_t *font,
|
||||
return font->get_nominal_glyph (unicode, glyph);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_font_get_nominal_glyphs:
|
||||
* @font: a font.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Since: 2.6.3
|
||||
**/
|
||||
unsigned int
|
||||
hb_font_get_nominal_glyphs (hb_font_t *font,
|
||||
unsigned int count,
|
||||
const hb_codepoint_t *first_unicode,
|
||||
unsigned int unicode_stride,
|
||||
hb_codepoint_t *first_glyph,
|
||||
unsigned int glyph_stride)
|
||||
{
|
||||
return font->get_nominal_glyphs (count,
|
||||
first_unicode, unicode_stride,
|
||||
first_glyph, glyph_stride);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_font_get_variation_glyph:
|
||||
* @font: a font.
|
||||
@ -936,7 +965,6 @@ hb_font_get_glyph_v_origin (hb_font_t *font,
|
||||
* Return value:
|
||||
*
|
||||
* Since: 0.9.2
|
||||
* Deprecated: 2.0.0
|
||||
**/
|
||||
hb_position_t
|
||||
hb_font_get_glyph_h_kerning (hb_font_t *font,
|
||||
@ -945,6 +973,7 @@ hb_font_get_glyph_h_kerning (hb_font_t *font,
|
||||
return font->get_glyph_h_kerning (left_glyph, right_glyph);
|
||||
}
|
||||
|
||||
#ifndef HB_DISABLE_DEPRECATED
|
||||
/**
|
||||
* hb_font_get_glyph_v_kerning:
|
||||
* @font: a font.
|
||||
@ -964,6 +993,7 @@ hb_font_get_glyph_v_kerning (hb_font_t *font,
|
||||
{
|
||||
return font->get_glyph_v_kerning (top_glyph, bottom_glyph);
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* hb_font_get_glyph_extents:
|
||||
@ -1185,7 +1215,6 @@ hb_font_subtract_glyph_origin_for_direction (hb_font_t *font,
|
||||
*
|
||||
*
|
||||
* Since: 0.9.2
|
||||
* Deprecated: 2.0.0
|
||||
**/
|
||||
void
|
||||
hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
|
||||
@ -1298,6 +1327,8 @@ DEFINE_NULL_INSTANCE (hb_font_t) =
|
||||
|
||||
1000, /* x_scale */
|
||||
1000, /* y_scale */
|
||||
1<<16, /* x_mult */
|
||||
1<<16, /* y_mult */
|
||||
|
||||
0, /* x_ppem */
|
||||
0, /* y_ppem */
|
||||
@ -1305,6 +1336,7 @@ DEFINE_NULL_INSTANCE (hb_font_t) =
|
||||
|
||||
0, /* num_coords */
|
||||
nullptr, /* coords */
|
||||
nullptr, /* design_coords */
|
||||
|
||||
const_cast<hb_font_funcs_t *> (&_hb_Null_hb_font_funcs_t),
|
||||
|
||||
@ -1328,6 +1360,7 @@ _hb_font_create (hb_face_t *face)
|
||||
font->klass = hb_font_funcs_get_empty ();
|
||||
font->data.init0 (font);
|
||||
font->x_scale = font->y_scale = hb_face_get_upem (face);
|
||||
font->x_mult = font->y_mult = 1 << 16;
|
||||
|
||||
return font;
|
||||
}
|
||||
@ -1347,12 +1380,28 @@ hb_font_create (hb_face_t *face)
|
||||
{
|
||||
hb_font_t *font = _hb_font_create (face);
|
||||
|
||||
#ifndef HB_NO_OT_FONT
|
||||
/* Install our in-house, very lightweight, funcs. */
|
||||
hb_ot_font_set_funcs (font);
|
||||
#endif
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
static void
|
||||
_hb_font_adopt_var_coords (hb_font_t *font,
|
||||
int *coords, /* 2.14 normalized */
|
||||
float *design_coords,
|
||||
unsigned int coords_length)
|
||||
{
|
||||
free (font->coords);
|
||||
free (font->design_coords);
|
||||
|
||||
font->coords = coords;
|
||||
font->design_coords = design_coords;
|
||||
font->num_coords = coords_length;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_font_create_sub_font:
|
||||
* @parent: parent font.
|
||||
@ -1378,21 +1427,27 @@ hb_font_create_sub_font (hb_font_t *parent)
|
||||
|
||||
font->x_scale = parent->x_scale;
|
||||
font->y_scale = parent->y_scale;
|
||||
font->mults_changed ();
|
||||
font->x_ppem = parent->x_ppem;
|
||||
font->y_ppem = parent->y_ppem;
|
||||
font->ptem = parent->ptem;
|
||||
|
||||
font->num_coords = parent->num_coords;
|
||||
if (!font->num_coords)
|
||||
font->coords = nullptr;
|
||||
else
|
||||
unsigned int num_coords = parent->num_coords;
|
||||
if (num_coords)
|
||||
{
|
||||
unsigned int size = parent->num_coords * sizeof (parent->coords[0]);
|
||||
font->coords = (int *) malloc (size);
|
||||
if (unlikely (!font->coords))
|
||||
font->num_coords = 0;
|
||||
int *coords = (int *) calloc (num_coords, sizeof (parent->coords[0]));
|
||||
float *design_coords = (float *) calloc (num_coords, sizeof (parent->design_coords[0]));
|
||||
if (likely (coords && design_coords))
|
||||
{
|
||||
memcpy (coords, parent->coords, num_coords * sizeof (parent->coords[0]));
|
||||
memcpy (design_coords, parent->design_coords, num_coords * sizeof (parent->design_coords[0]));
|
||||
_hb_font_adopt_var_coords (font, coords, design_coords, num_coords);
|
||||
}
|
||||
else
|
||||
memcpy (font->coords, parent->coords, size);
|
||||
{
|
||||
free (coords);
|
||||
free (design_coords);
|
||||
}
|
||||
}
|
||||
|
||||
return font;
|
||||
@ -1410,7 +1465,7 @@ hb_font_create_sub_font (hb_font_t *parent)
|
||||
hb_font_t *
|
||||
hb_font_get_empty ()
|
||||
{
|
||||
return const_cast<hb_font_t *> (&Null(hb_font_t));
|
||||
return const_cast<hb_font_t *> (&Null (hb_font_t));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1452,6 +1507,7 @@ hb_font_destroy (hb_font_t *font)
|
||||
hb_font_funcs_destroy (font->klass);
|
||||
|
||||
free (font->coords);
|
||||
free (font->design_coords);
|
||||
|
||||
free (font);
|
||||
}
|
||||
@ -1597,7 +1653,9 @@ hb_font_set_face (hb_font_t *font,
|
||||
|
||||
hb_face_t *old = font->face;
|
||||
|
||||
hb_face_make_immutable (face);
|
||||
font->face = hb_face_reference (face);
|
||||
font->mults_changed ();
|
||||
|
||||
hb_face_destroy (old);
|
||||
}
|
||||
@ -1707,6 +1765,7 @@ hb_font_set_scale (hb_font_t *font,
|
||||
|
||||
font->x_scale = x_scale;
|
||||
font->y_scale = y_scale;
|
||||
font->mults_changed ();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1805,21 +1864,11 @@ hb_font_get_ptem (hb_font_t *font)
|
||||
return font->ptem;
|
||||
}
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
/*
|
||||
* Variations
|
||||
*/
|
||||
|
||||
static void
|
||||
_hb_font_adopt_var_coords_normalized (hb_font_t *font,
|
||||
int *coords, /* 2.14 normalized */
|
||||
unsigned int coords_length)
|
||||
{
|
||||
free (font->coords);
|
||||
|
||||
font->coords = coords;
|
||||
font->num_coords = coords_length;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_font_set_variations:
|
||||
*
|
||||
@ -1842,13 +1891,30 @@ hb_font_set_variations (hb_font_t *font,
|
||||
unsigned int coords_length = hb_ot_var_get_axis_count (font->face);
|
||||
|
||||
int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : nullptr;
|
||||
if (unlikely (coords_length && !normalized))
|
||||
return;
|
||||
float *design_coords = coords_length ? (float *) calloc (coords_length, sizeof (float)) : nullptr;
|
||||
|
||||
hb_ot_var_normalize_variations (font->face,
|
||||
variations, variations_length,
|
||||
normalized, coords_length);
|
||||
_hb_font_adopt_var_coords_normalized (font, normalized, coords_length);
|
||||
if (unlikely (coords_length && !(normalized && design_coords)))
|
||||
{
|
||||
free (normalized);
|
||||
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);
|
||||
}
|
||||
}
|
||||
font->face->table.avar->map_coords (normalized, coords_length);
|
||||
|
||||
_hb_font_adopt_var_coords (font, normalized, design_coords, coords_length);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1865,11 +1931,47 @@ hb_font_set_var_coords_design (hb_font_t *font,
|
||||
return;
|
||||
|
||||
int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : nullptr;
|
||||
if (unlikely (coords_length && !normalized))
|
||||
float *design_coords = coords_length ? (float *) calloc (coords_length, sizeof (float)) : nullptr;
|
||||
|
||||
if (unlikely (coords_length && !(normalized && design_coords)))
|
||||
{
|
||||
free (normalized);
|
||||
free (design_coords);
|
||||
return;
|
||||
}
|
||||
|
||||
if (coords_length)
|
||||
memcpy (design_coords, coords, coords_length * sizeof (font->design_coords[0]));
|
||||
|
||||
hb_ot_var_normalize_coords (font->face, coords_length, coords, normalized);
|
||||
_hb_font_adopt_var_coords_normalized (font, normalized, coords_length);
|
||||
_hb_font_adopt_var_coords (font, normalized, design_coords, coords_length);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_font_set_var_named_instance:
|
||||
* @font: a font.
|
||||
* @instance_index: named instance index.
|
||||
*
|
||||
* Sets design coords of a font from a named instance index.
|
||||
*
|
||||
* Since: 2.6.0
|
||||
*/
|
||||
void
|
||||
hb_font_set_var_named_instance (hb_font_t *font,
|
||||
unsigned instance_index)
|
||||
{
|
||||
if (hb_object_is_immutable (font))
|
||||
return;
|
||||
|
||||
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;
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1886,13 +1988,30 @@ hb_font_set_var_coords_normalized (hb_font_t *font,
|
||||
return;
|
||||
|
||||
int *copy = coords_length ? (int *) calloc (coords_length, sizeof (coords[0])) : nullptr;
|
||||
if (unlikely (coords_length && !copy))
|
||||
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;
|
||||
|
||||
if (unlikely (coords_length && !(copy && unmapped && design_coords)))
|
||||
{
|
||||
free (copy);
|
||||
free (unmapped);
|
||||
free (design_coords);
|
||||
return;
|
||||
}
|
||||
|
||||
if (coords_length)
|
||||
{
|
||||
memcpy (copy, coords, coords_length * sizeof (coords[0]));
|
||||
memcpy (unmapped, coords, coords_length * sizeof (coords[0]));
|
||||
}
|
||||
|
||||
_hb_font_adopt_var_coords_normalized (font, copy, coords_length);
|
||||
/* Best effort design coords simulation */
|
||||
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_font_adopt_var_coords (font, copy, design_coords, coords_length);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1913,7 +2032,28 @@ hb_font_get_var_coords_normalized (hb_font_t *font,
|
||||
return font->coords;
|
||||
}
|
||||
|
||||
#ifdef HB_EXPERIMENTAL_API
|
||||
/**
|
||||
* hb_font_get_var_coords_design:
|
||||
*
|
||||
* Return value is valid as long as variation coordinates of the font
|
||||
* are not modified.
|
||||
*
|
||||
* Since: EXPERIMENTAL
|
||||
*/
|
||||
const float *
|
||||
hb_font_get_var_coords_design (hb_font_t *font,
|
||||
unsigned int *length)
|
||||
{
|
||||
if (length)
|
||||
*length = font->num_coords;
|
||||
|
||||
return font->design_coords;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef HB_DISABLE_DEPRECATED
|
||||
/*
|
||||
* Deprecated get_glyph_func():
|
||||
*/
|
||||
@ -2015,6 +2155,13 @@ 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)
|
||||
{
|
||||
if (hb_object_is_immutable (ffuncs))
|
||||
{
|
||||
if (destroy)
|
||||
destroy (user_data);
|
||||
return;
|
||||
}
|
||||
|
||||
hb_font_get_glyph_trampoline_t *trampoline;
|
||||
|
||||
trampoline = trampoline_create (func, user_data, destroy);
|
||||
@ -2036,3 +2183,4 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
|
||||
trampoline,
|
||||
trampoline_destroy);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -33,6 +33,7 @@
|
||||
|
||||
#include "hb-common.h"
|
||||
#include "hb-face.h"
|
||||
#include "hb-draw.h"
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
@ -157,6 +158,11 @@ typedef hb_bool_t (*hb_font_get_glyph_origin_func_t) (hb_font_t *font, void *fon
|
||||
typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_h_origin_func_t;
|
||||
typedef hb_font_get_glyph_origin_func_t hb_font_get_glyph_v_origin_func_t;
|
||||
|
||||
typedef hb_position_t (*hb_font_get_glyph_kerning_func_t) (hb_font_t *font, void *font_data,
|
||||
hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
|
||||
void *user_data);
|
||||
typedef hb_font_get_glyph_kerning_func_t hb_font_get_glyph_h_kerning_func_t;
|
||||
|
||||
|
||||
typedef hb_bool_t (*hb_font_get_glyph_extents_func_t) (hb_font_t *font, void *font_data,
|
||||
hb_codepoint_t glyph,
|
||||
@ -356,6 +362,22 @@ hb_font_funcs_set_glyph_v_origin_func (hb_font_funcs_t *ffuncs,
|
||||
hb_font_get_glyph_v_origin_func_t func,
|
||||
void *user_data, hb_destroy_func_t destroy);
|
||||
|
||||
/**
|
||||
* hb_font_funcs_set_glyph_h_kerning_func:
|
||||
* @ffuncs: font functions.
|
||||
* @func: (closure user_data) (destroy destroy) (scope notified):
|
||||
* @user_data:
|
||||
* @destroy:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
HB_EXTERN void
|
||||
hb_font_funcs_set_glyph_h_kerning_func (hb_font_funcs_t *ffuncs,
|
||||
hb_font_get_glyph_h_kerning_func_t func,
|
||||
void *user_data, hb_destroy_func_t destroy);
|
||||
|
||||
/**
|
||||
* hb_font_funcs_set_glyph_extents_func:
|
||||
* @ffuncs: font functions.
|
||||
@ -438,6 +460,14 @@ hb_font_get_variation_glyph (hb_font_t *font,
|
||||
hb_codepoint_t unicode, hb_codepoint_t variation_selector,
|
||||
hb_codepoint_t *glyph);
|
||||
|
||||
HB_EXTERN unsigned int
|
||||
hb_font_get_nominal_glyphs (hb_font_t *font,
|
||||
unsigned int count,
|
||||
const hb_codepoint_t *first_unicode,
|
||||
unsigned int unicode_stride,
|
||||
hb_codepoint_t *first_glyph,
|
||||
unsigned int glyph_stride);
|
||||
|
||||
HB_EXTERN hb_position_t
|
||||
hb_font_get_glyph_h_advance (hb_font_t *font,
|
||||
hb_codepoint_t glyph);
|
||||
@ -469,6 +499,10 @@ hb_font_get_glyph_v_origin (hb_font_t *font,
|
||||
hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y);
|
||||
|
||||
HB_EXTERN hb_position_t
|
||||
hb_font_get_glyph_h_kerning (hb_font_t *font,
|
||||
hb_codepoint_t left_glyph, hb_codepoint_t right_glyph);
|
||||
|
||||
HB_EXTERN hb_bool_t
|
||||
hb_font_get_glyph_extents (hb_font_t *font,
|
||||
hb_codepoint_t glyph,
|
||||
@ -531,6 +565,12 @@ hb_font_subtract_glyph_origin_for_direction (hb_font_t *font,
|
||||
hb_direction_t direction,
|
||||
hb_position_t *x, hb_position_t *y);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_font_get_glyph_kerning_for_direction (hb_font_t *font,
|
||||
hb_codepoint_t first_glyph, hb_codepoint_t second_glyph,
|
||||
hb_direction_t direction,
|
||||
hb_position_t *x, hb_position_t *y);
|
||||
|
||||
HB_EXTERN hb_bool_t
|
||||
hb_font_get_glyph_extents_for_origin (hb_font_t *font,
|
||||
hb_codepoint_t glyph,
|
||||
@ -665,6 +705,12 @@ hb_font_set_var_coords_design (hb_font_t *font,
|
||||
const float *coords,
|
||||
unsigned int coords_length);
|
||||
|
||||
#ifdef HB_EXPERIMENTAL_API
|
||||
HB_EXTERN const float *
|
||||
hb_font_get_var_coords_design (hb_font_t *font,
|
||||
unsigned int *length);
|
||||
#endif
|
||||
|
||||
HB_EXTERN void
|
||||
hb_font_set_var_coords_normalized (hb_font_t *font,
|
||||
const int *coords, /* 2.14 normalized */
|
||||
@ -674,6 +720,16 @@ HB_EXTERN const int *
|
||||
hb_font_get_var_coords_normalized (hb_font_t *font,
|
||||
unsigned int *length);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_font_set_var_named_instance (hb_font_t *font,
|
||||
unsigned instance_index);
|
||||
|
||||
#ifdef HB_EXPERIMENTAL_API
|
||||
HB_EXTERN hb_bool_t
|
||||
hb_font_draw_glyph (hb_font_t *font, hb_codepoint_t glyph,
|
||||
const hb_draw_funcs_t *funcs, void *user_data);
|
||||
#endif
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
#endif /* HB_FONT_H */
|
||||
|
||||
@ -52,7 +52,7 @@
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_h_origin) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_v_origin) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_h_kerning) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning) \
|
||||
HB_IF_NOT_DEPRECATED (HB_FONT_FUNC_IMPLEMENT (glyph_v_kerning)) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_extents) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_contour_point) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_name) \
|
||||
@ -107,8 +107,10 @@ struct hb_font_t
|
||||
hb_font_t *parent;
|
||||
hb_face_t *face;
|
||||
|
||||
int x_scale;
|
||||
int y_scale;
|
||||
int32_t x_scale;
|
||||
int32_t y_scale;
|
||||
int64_t x_mult;
|
||||
int64_t y_mult;
|
||||
|
||||
unsigned int x_ppem;
|
||||
unsigned int y_ppem;
|
||||
@ -118,6 +120,7 @@ struct hb_font_t
|
||||
/* Font variation coordinates. */
|
||||
unsigned int num_coords;
|
||||
int *coords;
|
||||
float *design_coords;
|
||||
|
||||
hb_font_funcs_t *klass;
|
||||
void *user_data;
|
||||
@ -127,16 +130,16 @@ struct hb_font_t
|
||||
|
||||
|
||||
/* Convert from font-space to user-space */
|
||||
int dir_scale (hb_direction_t direction)
|
||||
{ return HB_DIRECTION_IS_VERTICAL(direction) ? y_scale : x_scale; }
|
||||
hb_position_t em_scale_x (int16_t v) { return em_scale (v, x_scale); }
|
||||
hb_position_t em_scale_y (int16_t v) { return em_scale (v, y_scale); }
|
||||
hb_position_t em_scalef_x (float v) { return em_scalef (v, this->x_scale); }
|
||||
hb_position_t em_scalef_y (float v) { return em_scalef (v, this->y_scale); }
|
||||
int64_t dir_mult (hb_direction_t direction)
|
||||
{ return HB_DIRECTION_IS_VERTICAL(direction) ? y_mult : x_mult; }
|
||||
hb_position_t em_scale_x (int16_t v) { return em_mult (v, x_mult); }
|
||||
hb_position_t em_scale_y (int16_t v) { return em_mult (v, y_mult); }
|
||||
hb_position_t em_scalef_x (float v) { return em_scalef (v, x_scale); }
|
||||
hb_position_t em_scalef_y (float v) { return em_scalef (v, y_scale); }
|
||||
float em_fscale_x (int16_t v) { return em_fscale (v, x_scale); }
|
||||
float em_fscale_y (int16_t v) { return em_fscale (v, y_scale); }
|
||||
hb_position_t em_scale_dir (int16_t v, hb_direction_t direction)
|
||||
{ return em_scale (v, dir_scale (direction)); }
|
||||
{ return em_mult (v, dir_mult (direction)); }
|
||||
|
||||
/* Convert from parent-font user-space to our user-space */
|
||||
hb_position_t parent_scale_x_distance (hb_position_t v)
|
||||
@ -214,7 +217,7 @@ struct hb_font_t
|
||||
}
|
||||
|
||||
hb_bool_t get_nominal_glyph (hb_codepoint_t unicode,
|
||||
hb_codepoint_t *glyph)
|
||||
hb_codepoint_t *glyph)
|
||||
{
|
||||
*glyph = 0;
|
||||
return klass->get.f.nominal_glyph (this, user_data,
|
||||
@ -284,7 +287,7 @@ struct hb_font_t
|
||||
}
|
||||
|
||||
hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
{
|
||||
*x = *y = 0;
|
||||
return klass->get.f.glyph_h_origin (this, user_data,
|
||||
@ -304,21 +307,29 @@ struct hb_font_t
|
||||
hb_position_t get_glyph_h_kerning (hb_codepoint_t left_glyph,
|
||||
hb_codepoint_t right_glyph)
|
||||
{
|
||||
#ifdef HB_DISABLE_DEPRECATED
|
||||
return 0;
|
||||
#else
|
||||
return klass->get.f.glyph_h_kerning (this, user_data,
|
||||
left_glyph, right_glyph,
|
||||
klass->user_data.glyph_h_kerning);
|
||||
#endif
|
||||
}
|
||||
|
||||
hb_position_t get_glyph_v_kerning (hb_codepoint_t top_glyph,
|
||||
hb_codepoint_t bottom_glyph)
|
||||
{
|
||||
#ifdef HB_DISABLE_DEPRECATED
|
||||
return 0;
|
||||
#else
|
||||
return klass->get.f.glyph_v_kerning (this, user_data,
|
||||
top_glyph, bottom_glyph,
|
||||
klass->user_data.glyph_v_kerning);
|
||||
#endif
|
||||
}
|
||||
|
||||
hb_bool_t get_glyph_extents (hb_codepoint_t glyph,
|
||||
hb_glyph_extents_t *extents)
|
||||
hb_glyph_extents_t *extents)
|
||||
{
|
||||
memset (extents, 0, sizeof (*extents));
|
||||
return klass->get.f.glyph_extents (this, user_data,
|
||||
@ -328,7 +339,7 @@ struct hb_font_t
|
||||
}
|
||||
|
||||
hb_bool_t get_glyph_contour_point (hb_codepoint_t glyph, unsigned int point_index,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
{
|
||||
*x = *y = 0;
|
||||
return klass->get.f.glyph_contour_point (this, user_data,
|
||||
@ -599,15 +610,19 @@ struct hb_font_t
|
||||
return false;
|
||||
}
|
||||
|
||||
hb_position_t em_scale (int16_t v, int scale)
|
||||
void mults_changed ()
|
||||
{
|
||||
int upem = face->get_upem ();
|
||||
int64_t scaled = v * (int64_t) scale;
|
||||
scaled += scaled >= 0 ? upem/2 : -upem/2; /* Round. */
|
||||
return (hb_position_t) (scaled / upem);
|
||||
signed upem = face->get_upem ();
|
||||
x_mult = ((int64_t) x_scale << 16) / upem;
|
||||
y_mult = ((int64_t) y_scale << 16) / upem;
|
||||
}
|
||||
|
||||
hb_position_t em_mult (int16_t v, int64_t mult)
|
||||
{
|
||||
return (hb_position_t) ((v * mult) >> 16);
|
||||
}
|
||||
hb_position_t em_scalef (float v, int scale)
|
||||
{ return (hb_position_t) round (v * scale / face->get_upem ()); }
|
||||
{ return (hb_position_t) roundf (v * scale / face->get_upem ()); }
|
||||
float em_fscale (int16_t v, int scale)
|
||||
{ return (float) v * scale / face->get_upem (); }
|
||||
};
|
||||
|
||||
@ -29,6 +29,8 @@
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#ifdef HAVE_FREETYPE
|
||||
|
||||
#include "hb-ft.h"
|
||||
|
||||
#include "hb-font.hh"
|
||||
@ -46,8 +48,13 @@
|
||||
* @short_description: FreeType integration
|
||||
* @include: hb-ft.h
|
||||
*
|
||||
* Functions for using HarfBuzz with the FreeType library to provide face and
|
||||
* Functions for using HarfBuzz with the FreeType library.
|
||||
*
|
||||
* HarfBuzz supports using FreeType to provide face and
|
||||
* font data.
|
||||
*
|
||||
* <note>Note that FreeType is not thread-safe, therefore these
|
||||
* functions are not thread-safe either.</note>
|
||||
**/
|
||||
|
||||
|
||||
@ -85,9 +92,7 @@ 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));
|
||||
|
||||
if (unlikely (!ft_font))
|
||||
return nullptr;
|
||||
if (unlikely (!ft_font)) return nullptr;
|
||||
|
||||
ft_font->lock.init ();
|
||||
ft_font->ft_face = ft_face;
|
||||
@ -96,7 +101,7 @@ _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
|
||||
|
||||
ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
|
||||
|
||||
ft_font->cached_x_scale.set (0);
|
||||
ft_font->cached_x_scale.set_relaxed (0);
|
||||
ft_font->advance_cache.init ();
|
||||
|
||||
return ft_font;
|
||||
@ -125,10 +130,13 @@ _hb_ft_font_destroy (void *data)
|
||||
|
||||
/**
|
||||
* hb_ft_font_set_load_flags:
|
||||
* @font:
|
||||
* @load_flags:
|
||||
* @font: #hb_font_t to work upon
|
||||
* @load_flags: The FreeType load flags to set
|
||||
*
|
||||
* Sets the FT_Load_Glyph load flags for the specified #hb_font_t.
|
||||
*
|
||||
* For more information, see
|
||||
* https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_load_xxx
|
||||
*
|
||||
* Since: 1.0.5
|
||||
**/
|
||||
@ -138,7 +146,7 @@ hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
|
||||
if (hb_object_is_immutable (font))
|
||||
return;
|
||||
|
||||
if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
|
||||
if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy))
|
||||
return;
|
||||
|
||||
hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
|
||||
@ -148,17 +156,21 @@ hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
|
||||
|
||||
/**
|
||||
* hb_ft_font_get_load_flags:
|
||||
* @font:
|
||||
* @font: #hb_font_t to work upon
|
||||
*
|
||||
* Fetches the FT_Load_Glyph load flags of the specified #hb_font_t.
|
||||
*
|
||||
* For more information, see
|
||||
* https://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#ft_load_xxx
|
||||
*
|
||||
* Return value: FT_Load_Glyph flags found
|
||||
*
|
||||
* Return value:
|
||||
* Since: 1.0.5
|
||||
**/
|
||||
int
|
||||
hb_ft_font_get_load_flags (hb_font_t *font)
|
||||
{
|
||||
if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
|
||||
if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy))
|
||||
return 0;
|
||||
|
||||
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
|
||||
@ -166,10 +178,21 @@ hb_ft_font_get_load_flags (hb_font_t *font)
|
||||
return ft_font->load_flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ft_get_face:
|
||||
* @font: #hb_font_t to work upon
|
||||
*
|
||||
* Fetches the FT_Face associated with the specified #hb_font_t
|
||||
* font object.
|
||||
*
|
||||
* Return value: the FT_Face found
|
||||
*
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
FT_Face
|
||||
hb_ft_font_get_face (hb_font_t *font)
|
||||
{
|
||||
if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
|
||||
if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy))
|
||||
return nullptr;
|
||||
|
||||
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
|
||||
@ -177,6 +200,47 @@ hb_ft_font_get_face (hb_font_t *font)
|
||||
return ft_font->ft_face;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ft_font_lock_face:
|
||||
* @font:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value:
|
||||
* Since: 2.6.5
|
||||
**/
|
||||
FT_Face
|
||||
hb_ft_font_lock_face (hb_font_t *font)
|
||||
{
|
||||
if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy))
|
||||
return nullptr;
|
||||
|
||||
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
|
||||
|
||||
ft_font->lock.lock ();
|
||||
|
||||
return ft_font->ft_face;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ft_font_unlock_face:
|
||||
* @font:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Return value:
|
||||
* Since: 2.6.5
|
||||
**/
|
||||
void
|
||||
hb_ft_font_unlock_face (hb_font_t *font)
|
||||
{
|
||||
if (unlikely (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy))
|
||||
return;
|
||||
|
||||
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font->user_data;
|
||||
|
||||
ft_font->lock.unlock ();
|
||||
}
|
||||
|
||||
|
||||
static hb_bool_t
|
||||
@ -346,6 +410,25 @@ hb_ft_get_glyph_v_origin (hb_font_t *font,
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef HB_NO_OT_SHAPE_FALLBACK
|
||||
static hb_position_t
|
||||
hb_ft_get_glyph_h_kerning (hb_font_t *font,
|
||||
void *font_data,
|
||||
hb_codepoint_t left_glyph,
|
||||
hb_codepoint_t right_glyph,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
|
||||
FT_Vector kerningv;
|
||||
|
||||
FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED;
|
||||
if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv))
|
||||
return 0;
|
||||
|
||||
return kerningv.x;
|
||||
}
|
||||
#endif
|
||||
|
||||
static hb_bool_t
|
||||
hb_ft_get_glyph_extents (hb_font_t *font,
|
||||
void *font_data,
|
||||
@ -439,7 +522,7 @@ hb_ft_get_glyph_from_name (hb_font_t *font HB_UNUSED,
|
||||
else {
|
||||
/* Make a nul-terminated version. */
|
||||
char buf[128];
|
||||
len = MIN (len, (int) sizeof (buf) - 1);
|
||||
len = hb_min (len, (int) sizeof (buf) - 1);
|
||||
strncpy (buf, name, len);
|
||||
buf[len] = '\0';
|
||||
*glyph = FT_Get_Name_Index (ft_face, buf);
|
||||
@ -497,6 +580,10 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft
|
||||
hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
|
||||
//hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr);
|
||||
hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr);
|
||||
#ifndef HB_NO_OT_SHAPE_FALLBACK
|
||||
hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr);
|
||||
#endif
|
||||
//hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, nullptr, nullptr);
|
||||
hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr);
|
||||
hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr);
|
||||
hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
|
||||
@ -531,15 +618,18 @@ _hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
|
||||
{
|
||||
bool symbol = ft_face->charmap && ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL;
|
||||
|
||||
hb_ft_font_t *ft_font = _hb_ft_font_create (ft_face, symbol, unref);
|
||||
if (unlikely (!ft_font)) return;
|
||||
|
||||
hb_font_set_funcs (font,
|
||||
_hb_ft_get_font_funcs (),
|
||||
_hb_ft_font_create (ft_face, symbol, unref),
|
||||
ft_font,
|
||||
_hb_ft_font_destroy);
|
||||
}
|
||||
|
||||
|
||||
static hb_blob_t *
|
||||
reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
|
||||
_hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
|
||||
{
|
||||
FT_Face ft_face = (FT_Face) user_data;
|
||||
FT_Byte *buffer;
|
||||
@ -570,12 +660,22 @@ reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
|
||||
|
||||
/**
|
||||
* hb_ft_face_create:
|
||||
* @ft_face: (destroy destroy) (scope notified):
|
||||
* @destroy:
|
||||
* @ft_face: (destroy destroy) (scope notified): FT_Face to work upon
|
||||
* @destroy: A callback to call when the face object is not needed anymore
|
||||
*
|
||||
* Creates an #hb_face_t face object from the specified FT_Face.
|
||||
*
|
||||
* This variant of the function does not provide any life-cycle management.
|
||||
*
|
||||
* Most client programs should use hb_ft_face_create_referenced()
|
||||
* (or, perhaps, hb_ft_face_create_cached()) instead.
|
||||
*
|
||||
* If you know you have valid reasons not to use hb_ft_face_create_referenced(),
|
||||
* then it is the client program's responsibility to destroy @ft_face
|
||||
* after the #hb_face_t face object has been destroyed.
|
||||
*
|
||||
* Return value: (transfer full): the new #hb_face_t face object
|
||||
*
|
||||
* Return value: (transfer full):
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
hb_face_t *
|
||||
@ -594,7 +694,7 @@ hb_ft_face_create (FT_Face ft_face,
|
||||
face = hb_face_create (blob, ft_face->face_index);
|
||||
hb_blob_destroy (blob);
|
||||
} else {
|
||||
face = hb_face_create_for_tables (reference_table, ft_face, destroy);
|
||||
face = hb_face_create_for_tables (_hb_ft_reference_table, ft_face, destroy);
|
||||
}
|
||||
|
||||
hb_face_set_index (face, ft_face->face_index);
|
||||
@ -605,11 +705,20 @@ hb_ft_face_create (FT_Face ft_face,
|
||||
|
||||
/**
|
||||
* hb_ft_face_create_referenced:
|
||||
* @ft_face:
|
||||
* @ft_face: FT_Face to work upon
|
||||
*
|
||||
* Creates an #hb_face_t face object from the specified FT_Face.
|
||||
*
|
||||
* This is the preferred variant of the hb_ft_face_create*
|
||||
* function family, because it calls FT_Reference_Face() on @ft_face,
|
||||
* ensuring that @ft_face remains alive as long as the resulting
|
||||
* #hb_face_t face object remains alive. Also calls FT_Done_Face()
|
||||
* when the #hb_face_t face object is destroyed.
|
||||
*
|
||||
* Use this version unless you know you have good reasons not to.
|
||||
*
|
||||
* Return value: (transfer full): the new #hb_face_t face object
|
||||
*
|
||||
* Return value: (transfer full):
|
||||
* Since: 0.9.38
|
||||
**/
|
||||
hb_face_t *
|
||||
@ -627,11 +736,21 @@ hb_ft_face_finalize (FT_Face ft_face)
|
||||
|
||||
/**
|
||||
* hb_ft_face_create_cached:
|
||||
* @ft_face:
|
||||
* @ft_face: FT_Face to work upon
|
||||
*
|
||||
* Creates an #hb_face_t face object from the specified FT_Face.
|
||||
*
|
||||
* This variant of the function caches the newly created #hb_face_t
|
||||
* face object, using the @generic pointer of @ft_face. Subsequent function
|
||||
* calls that are passed the same @ft_face parameter will have the same
|
||||
* #hb_face_t returned to them, and that #hb_face_t will be correctly
|
||||
* reference counted.
|
||||
*
|
||||
* However, client programs are still responsible for destroying
|
||||
* @ft_face after the last #hb_face_t face object has been destroyed.
|
||||
*
|
||||
* Return value: (transfer full): the new #hb_face_t face object
|
||||
*
|
||||
* Return value: (transfer full):
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
hb_face_t *
|
||||
@ -649,15 +768,34 @@ hb_ft_face_create_cached (FT_Face ft_face)
|
||||
return hb_face_reference ((hb_face_t *) ft_face->generic.data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* hb_ft_font_create:
|
||||
* @ft_face: (destroy destroy) (scope notified):
|
||||
* @destroy:
|
||||
* @ft_face: (destroy destroy) (scope notified): FT_Face to work upon
|
||||
* @destroy: (optional): A callback to call when the font object is not needed anymore
|
||||
*
|
||||
* Creates an #hb_font_t font object from the specified FT_Face.
|
||||
*
|
||||
* <note>Note: You must set the face size on @ft_face before calling
|
||||
* hb_ft_font_create() on it. Otherwise, HarfBuzz will not pick up
|
||||
* the face size.</note>
|
||||
*
|
||||
* This variant of the function does not provide any life-cycle management.
|
||||
*
|
||||
* Most client programs should use hb_ft_font_create_referenced()
|
||||
* instead.
|
||||
*
|
||||
* If you know you have valid reasons not to use hb_ft_font_create_referenced(),
|
||||
* then it is the client program's responsibility to destroy @ft_face
|
||||
* after the #hb_font_t font object has been destroyed.
|
||||
*
|
||||
* HarfBuzz will use the @destroy callback on the #hb_font_t font object
|
||||
* if it is supplied when you use this function. However, even if @destroy
|
||||
* is provided, it is the client program's responsibility to destroy @ft_face,
|
||||
* and it is the client program's responsibility to ensure that @ft_face is
|
||||
* destroyed only after the #hb_font_t font object has been destroyed.
|
||||
*
|
||||
* Return value: (transfer full): the new #hb_font_t font object
|
||||
*
|
||||
* Return value: (transfer full):
|
||||
* Since: 0.9.2
|
||||
**/
|
||||
hb_font_t *
|
||||
@ -675,6 +813,16 @@ hb_ft_font_create (FT_Face ft_face,
|
||||
return font;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ft_font_has_changed:
|
||||
* @font: #hb_font_t to work upon
|
||||
*
|
||||
* Refreshes the state of @font when the underlying FT_Face has changed.
|
||||
* This function should be called after changing the size or
|
||||
* variation-axis settings on the FT_Face.
|
||||
*
|
||||
* Since: 1.0.5
|
||||
**/
|
||||
void
|
||||
hb_ft_font_changed (hb_font_t *font)
|
||||
{
|
||||
@ -682,6 +830,7 @@ hb_ft_font_changed (hb_font_t *font)
|
||||
return;
|
||||
|
||||
hb_ft_font_t *ft_font = (hb_ft_font_t *) font->user_data;
|
||||
|
||||
FT_Face ft_face = ft_font->ft_face;
|
||||
|
||||
hb_font_set_scale (font,
|
||||
@ -693,7 +842,7 @@ hb_ft_font_changed (hb_font_t *font)
|
||||
ft_face->size->metrics.y_ppem);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_FT_GET_VAR_BLEND_COORDINATES
|
||||
#if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR)
|
||||
FT_MM_Var *mm_var = nullptr;
|
||||
if (!FT_Get_MM_Var (ft_face, &mm_var))
|
||||
{
|
||||
@ -730,11 +879,23 @@ hb_ft_font_changed (hb_font_t *font)
|
||||
|
||||
/**
|
||||
* hb_ft_font_create_referenced:
|
||||
* @ft_face:
|
||||
* @ft_face: FT_Face to work upon
|
||||
*
|
||||
* Creates an #hb_font_t font object from the specified FT_Face.
|
||||
*
|
||||
* <note>Note: You must set the face size on @ft_face before calling
|
||||
* hb_ft_font_create_references() on it. Otherwise, HarfBuzz will not pick up
|
||||
* the face size.</note>
|
||||
*
|
||||
* This is the preferred variant of the hb_ft_font_create*
|
||||
* function family, because it calls FT_Reference_Face() on @ft_face,
|
||||
* ensuring that @ft_face remains alive as long as the resulting
|
||||
* #hb_font_t font object remains alive.
|
||||
*
|
||||
* Use this version unless you know you have good reasons not to.
|
||||
*
|
||||
* Return value: (transfer full): the new #hb_font_t font object
|
||||
*
|
||||
* Return value: (transfer full):
|
||||
* Since: 0.9.38
|
||||
**/
|
||||
hb_font_t *
|
||||
@ -748,7 +909,7 @@ hb_ft_font_create_referenced (FT_Face ft_face)
|
||||
static void free_static_ft_library ();
|
||||
#endif
|
||||
|
||||
static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer (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>
|
||||
{
|
||||
static FT_Library create ()
|
||||
@ -793,6 +954,28 @@ _release_blob (FT_Face ft_face)
|
||||
hb_blob_destroy ((hb_blob_t *) ft_face->generic.data);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ft_font_set_funcs:
|
||||
* @font: #hb_font_t to work upon
|
||||
*
|
||||
* Configures the font-functions structure of the specified
|
||||
* #hb_font_t font object to use FreeType font functions.
|
||||
*
|
||||
* In particular, you can use this function to configure an
|
||||
* existing #hb_face_t face object for use with FreeType font
|
||||
* functions even if that #hb_face_t face object was initially
|
||||
* created with hb_face_create(), and therefore was not
|
||||
* initially configured to use FreeType font functions.
|
||||
*
|
||||
* An #hb_face_t face object created with hb_ft_face_create()
|
||||
* is preconfigured for FreeType font functions and does not
|
||||
* require this function to be used.
|
||||
*
|
||||
* <note>Note: Internally, this function creates an FT_Face.
|
||||
* </note>
|
||||
*
|
||||
* Since: 1.0.5
|
||||
**/
|
||||
void
|
||||
hb_ft_font_set_funcs (hb_font_t *font)
|
||||
{
|
||||
@ -815,8 +998,8 @@ hb_ft_font_set_funcs (hb_font_t *font)
|
||||
return;
|
||||
}
|
||||
|
||||
if (FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE))
|
||||
FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL);
|
||||
if (FT_Select_Charmap (ft_face, FT_ENCODING_MS_SYMBOL))
|
||||
FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE);
|
||||
|
||||
FT_Set_Char_Size (ft_face,
|
||||
abs (font->x_scale), abs (font->y_scale),
|
||||
@ -832,7 +1015,7 @@ hb_ft_font_set_funcs (hb_font_t *font)
|
||||
FT_Set_Transform (ft_face, &matrix, nullptr);
|
||||
}
|
||||
|
||||
#ifdef HAVE_FT_SET_VAR_BLEND_COORDINATES
|
||||
#if defined(HAVE_FT_GET_VAR_BLEND_COORDINATES) && !defined(HB_NO_VAR)
|
||||
unsigned int num_coords;
|
||||
const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
|
||||
if (num_coords)
|
||||
@ -841,7 +1024,7 @@ hb_ft_font_set_funcs (hb_font_t *font)
|
||||
if (ft_coords)
|
||||
{
|
||||
for (unsigned int i = 0; i < num_coords; i++)
|
||||
ft_coords[i] = coords[i] << 2;
|
||||
ft_coords[i] = coords[i] * 4;
|
||||
FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords);
|
||||
free (ft_coords);
|
||||
}
|
||||
@ -854,3 +1037,6 @@ hb_ft_font_set_funcs (hb_font_t *font)
|
||||
_hb_ft_font_set_funcs (font, ft_face, true);
|
||||
hb_ft_font_set_load_flags (font, FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@ -110,6 +110,12 @@ hb_ft_font_create_referenced (FT_Face ft_face);
|
||||
HB_EXTERN FT_Face
|
||||
hb_ft_font_get_face (hb_font_t *font);
|
||||
|
||||
HB_EXTERN FT_Face
|
||||
hb_ft_font_lock_face (hb_font_t *font);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_ft_font_unlock_face (hb_font_t *font);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_ft_font_set_load_flags (hb_font_t *font, int load_flags);
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright © 2018 Google, Inc.
|
||||
* Copyright © 2019 Facebook, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
@ -22,13 +23,15 @@
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
* Facebook Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_ITER_HH
|
||||
#define HB_ITER_HH
|
||||
|
||||
#include "hb.hh"
|
||||
#include "hb-null.hh"
|
||||
#include "hb-algs.hh"
|
||||
#include "hb-meta.hh"
|
||||
|
||||
|
||||
/* Unified iterator object.
|
||||
@ -39,16 +42,32 @@
|
||||
* copied by value. If the collection / object being iterated on
|
||||
* is writable, then the iterator returns lvalues, otherwise it
|
||||
* returns rvalues.
|
||||
*
|
||||
* TODO Document more.
|
||||
*
|
||||
* If iterator implementation implements operator!=, then can be
|
||||
* used in range-based for loop. That comes free 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
|
||||
* __end__() method.
|
||||
* TODO When opting in for C++17, address this by changing return
|
||||
* type of .end()?
|
||||
*/
|
||||
|
||||
/*
|
||||
* Base classes for iterators.
|
||||
*/
|
||||
|
||||
/* Base class for all iterators. */
|
||||
template <typename Iter, typename Item = typename Iter::__item_type__>
|
||||
template <typename iter_t, typename Item = typename iter_t::__item_t__>
|
||||
struct hb_iter_t
|
||||
{
|
||||
typedef Iter iter_t;
|
||||
typedef iter_t const_iter_t;
|
||||
typedef Item item_t;
|
||||
static constexpr unsigned item_size = hb_static_size (Item);
|
||||
constexpr unsigned get_item_size () const { return hb_static_size (Item); }
|
||||
static constexpr bool is_iterator = true;
|
||||
static constexpr bool is_random_access_iterator = false;
|
||||
static constexpr bool is_sorted_iterator = false;
|
||||
|
||||
private:
|
||||
/* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
|
||||
@ -56,53 +75,119 @@ struct hb_iter_t
|
||||
iter_t* thiz () { return static_cast< iter_t *> (this); }
|
||||
public:
|
||||
|
||||
/* TODO:
|
||||
* Port operators below to use hb_enable_if to sniff which method implements
|
||||
* an operator and use it, and remove hb_iter_fallback_mixin_t completely. */
|
||||
|
||||
/* Operators. */
|
||||
operator iter_t () { return iter(); }
|
||||
explicit_operator bool () const { return more (); }
|
||||
item_t& operator * () const { return item (); }
|
||||
item_t& operator [] (signed i) const { return item_at ((unsigned) i); }
|
||||
iter_t& operator += (unsigned count) { forward (count); return *thiz(); }
|
||||
iter_t& operator ++ () { next (); return *thiz(); }
|
||||
iter_t& operator -= (unsigned count) { rewind (count); return *thiz(); }
|
||||
iter_t& operator -- () { prev (); return *thiz(); }
|
||||
iter_t operator + (unsigned count) { iter_t c (*thiz()); c += count; return c; }
|
||||
iter_t operator ++ (int) { iter_t c (*thiz()); ++*thiz(); return c; }
|
||||
iter_t operator - (unsigned count) { iter_t c (*thiz()); c -= count; return c; }
|
||||
iter_t operator -- (int) { iter_t c (*thiz()); --*thiz(); return c; }
|
||||
|
||||
/* Methods. */
|
||||
iter_t iter () const { return *thiz(); }
|
||||
const_iter_t const_iter () const { return iter (); }
|
||||
item_t& item () const { return thiz()->__item__ (); }
|
||||
item_t& item_at (unsigned i) const { return thiz()->__item_at__ (i); }
|
||||
bool more () const { return thiz()->__more__ (); }
|
||||
iter_t operator + () const { return *thiz(); }
|
||||
iter_t begin () const { return *thiz(); }
|
||||
iter_t end () const { return thiz()->__end__ (); }
|
||||
explicit operator bool () const { return thiz()->__more__ (); }
|
||||
unsigned len () const { return thiz()->__len__ (); }
|
||||
void next () { thiz()->__next__ (); }
|
||||
void forward (unsigned n) { thiz()->__forward__ (n); }
|
||||
void prev () { thiz()->__prev__ (); }
|
||||
void rewind (unsigned n) { thiz()->__rewind__ (n); }
|
||||
bool random_access () const { return thiz()->__random_access__ (); }
|
||||
/* The following can only be enabled if item_t is reference type. Otherwise
|
||||
* it will be returning pointer to temporary rvalue.
|
||||
* TODO Use a wrapper return type to fix for non-reference type. */
|
||||
template <typename T = item_t,
|
||||
hb_enable_if (hb_is_reference (T))>
|
||||
hb_remove_reference<item_t>* operator -> () const { return hb_addressof (**thiz()); }
|
||||
item_t operator * () const { return thiz()->__item__ (); }
|
||||
item_t operator * () { return thiz()->__item__ (); }
|
||||
item_t operator [] (unsigned i) const { return thiz()->__item_at__ (i); }
|
||||
item_t operator [] (unsigned i) { return thiz()->__item_at__ (i); }
|
||||
iter_t& operator += (unsigned count) & { thiz()->__forward__ (count); return *thiz(); }
|
||||
iter_t operator += (unsigned count) && { thiz()->__forward__ (count); return *thiz(); }
|
||||
iter_t& operator ++ () & { thiz()->__next__ (); return *thiz(); }
|
||||
iter_t operator ++ () && { thiz()->__next__ (); return *thiz(); }
|
||||
iter_t& operator -= (unsigned count) & { thiz()->__rewind__ (count); return *thiz(); }
|
||||
iter_t operator -= (unsigned count) && { thiz()->__rewind__ (count); return *thiz(); }
|
||||
iter_t& operator -- () & { thiz()->__prev__ (); return *thiz(); }
|
||||
iter_t operator -- () && { thiz()->__prev__ (); return *thiz(); }
|
||||
iter_t operator + (unsigned count) const { auto c = thiz()->iter (); c += count; return c; }
|
||||
friend iter_t operator + (unsigned count, const iter_t &it) { return it + count; }
|
||||
iter_t operator ++ (int) { iter_t c (*thiz()); ++*thiz(); return c; }
|
||||
iter_t operator - (unsigned count) const { auto c = thiz()->iter (); c -= count; return c; }
|
||||
iter_t operator -- (int) { iter_t c (*thiz()); --*thiz(); return c; }
|
||||
template <typename T>
|
||||
iter_t& operator >> (T &v) & { v = **thiz(); ++*thiz(); return *thiz(); }
|
||||
template <typename T>
|
||||
iter_t operator >> (T &v) && { v = **thiz(); ++*thiz(); return *thiz(); }
|
||||
template <typename T>
|
||||
iter_t& operator << (const T v) & { **thiz() = v; ++*thiz(); return *thiz(); }
|
||||
template <typename T>
|
||||
iter_t operator << (const T v) && { **thiz() = v; ++*thiz(); return *thiz(); }
|
||||
|
||||
protected:
|
||||
hb_iter_t () {}
|
||||
hb_iter_t (const hb_iter_t &o HB_UNUSED) {}
|
||||
void operator = (const hb_iter_t &o HB_UNUSED) {}
|
||||
hb_iter_t () = default;
|
||||
hb_iter_t (const hb_iter_t &o HB_UNUSED) = default;
|
||||
hb_iter_t (hb_iter_t &&o HB_UNUSED) = default;
|
||||
hb_iter_t& operator = (const hb_iter_t &o HB_UNUSED) = default;
|
||||
hb_iter_t& operator = (hb_iter_t &&o HB_UNUSED) = default;
|
||||
};
|
||||
|
||||
/* Base class for sorted iterators. Does not enforce anything.
|
||||
* Just for class taxonomy and requirements. */
|
||||
template <typename Iter, typename Item = typename Iter::__item_type__>
|
||||
struct hb_sorted_iter_t : hb_iter_t<Iter, Item>
|
||||
#define HB_ITER_USING(Name) \
|
||||
using item_t = typename Name::item_t; \
|
||||
using Name::begin; \
|
||||
using Name::end; \
|
||||
using Name::get_item_size; \
|
||||
using Name::is_iterator; \
|
||||
using Name::iter; \
|
||||
using Name::operator bool; \
|
||||
using Name::len; \
|
||||
using Name::operator ->; \
|
||||
using Name::operator *; \
|
||||
using Name::operator []; \
|
||||
using Name::operator +=; \
|
||||
using Name::operator ++; \
|
||||
using Name::operator -=; \
|
||||
using Name::operator --; \
|
||||
using Name::operator +; \
|
||||
using Name::operator -; \
|
||||
using Name::operator >>; \
|
||||
using Name::operator <<; \
|
||||
static_assert (true, "")
|
||||
|
||||
/* Returns iterator / item type of a type. */
|
||||
template <typename Iterable>
|
||||
using hb_iter_type = decltype (hb_deref (hb_declval (Iterable)).iter ());
|
||||
template <typename Iterable>
|
||||
using hb_item_type = decltype (*hb_deref (hb_declval (Iterable)).iter ());
|
||||
|
||||
|
||||
template <typename> struct hb_array_t;
|
||||
template <typename> struct hb_sorted_array_t;
|
||||
|
||||
struct
|
||||
{
|
||||
protected:
|
||||
hb_sorted_iter_t () {}
|
||||
hb_sorted_iter_t (const hb_sorted_iter_t &o) : hb_iter_t<Iter, Item> (o) {}
|
||||
void operator = (const hb_sorted_iter_t &o HB_UNUSED) {}
|
||||
};
|
||||
template <typename T> hb_iter_type<T>
|
||||
operator () (T&& c) const
|
||||
{ return hb_deref (hb_forward<T> (c)).iter (); }
|
||||
|
||||
/* Specialization for C arrays. */
|
||||
|
||||
template <typename Type> inline hb_array_t<Type>
|
||||
operator () (Type *array, unsigned int length) const
|
||||
{ return hb_array_t<Type> (array, length); }
|
||||
|
||||
template <typename Type, unsigned int length> hb_array_t<Type>
|
||||
operator () (Type (&array)[length]) const
|
||||
{ return hb_array_t<Type> (array, length); }
|
||||
|
||||
}
|
||||
HB_FUNCOBJ (hb_iter);
|
||||
struct
|
||||
{
|
||||
template <typename T> unsigned
|
||||
operator () (T&& c) const
|
||||
{ return c.len (); }
|
||||
|
||||
}
|
||||
HB_FUNCOBJ (hb_len);
|
||||
|
||||
/* Mixin to fill in what the subclass doesn't provide. */
|
||||
template <typename iter_t, typename item_t = typename iter_t::__item_type__>
|
||||
struct hb_iter_mixin_t
|
||||
template <typename iter_t, typename item_t = typename iter_t::__item_t__>
|
||||
struct hb_iter_fallback_mixin_t
|
||||
{
|
||||
private:
|
||||
/* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
|
||||
@ -111,42 +196,743 @@ struct hb_iter_mixin_t
|
||||
public:
|
||||
|
||||
/* Access: Implement __item__(), or __item_at__() if random-access. */
|
||||
item_t& __item__ () const { return thiz()->item_at (0); }
|
||||
item_t& __item_at__ (unsigned i) const { return *(thiz() + i); }
|
||||
item_t __item__ () const { return (*thiz())[0]; }
|
||||
item_t __item_at__ (unsigned i) const { return *(*thiz() + i); }
|
||||
|
||||
/* Termination: Implement __more__(), or __len__() if random-access. */
|
||||
bool __more__ () const { return thiz()->__len__ (); }
|
||||
bool __more__ () const { return bool (thiz()->len ()); }
|
||||
unsigned __len__ () const
|
||||
{ iter_t c (*thiz()); unsigned l = 0; while (c) { c++; l++; }; return l; }
|
||||
{ iter_t c (*thiz()); unsigned l = 0; while (c) { c++; l++; } return l; }
|
||||
|
||||
/* Advancing: Implement __next__(), or __forward__() if random-access. */
|
||||
void __next__ () { thiz()->forward (1); }
|
||||
void __forward__ (unsigned n) { while (n--) thiz()->next (); }
|
||||
void __next__ () { *thiz() += 1; }
|
||||
void __forward__ (unsigned n) { while (*thiz() && n--) ++*thiz(); }
|
||||
|
||||
/* Rewinding: Implement __prev__() or __rewind__() if bidirectional. */
|
||||
void __prev__ () { thiz()->rewind (1); }
|
||||
void __rewind__ (unsigned n) { while (n--) thiz()->prev (); }
|
||||
void __prev__ () { *thiz() -= 1; }
|
||||
void __rewind__ (unsigned n) { while (*thiz() && n--) --*thiz(); }
|
||||
|
||||
/* Random access: Return true if item_at(), len(), forward() are fast. */
|
||||
bool __random_access__ () const { return false; }
|
||||
/* Range-based for: Implement __end__() if can be done faster,
|
||||
* and operator!=. */
|
||||
iter_t __end__ () const
|
||||
{
|
||||
if (thiz()->is_random_access_iterator)
|
||||
return *thiz() + thiz()->len ();
|
||||
/* Above expression loops twice. Following loops once. */
|
||||
auto it = *thiz();
|
||||
while (it) ++it;
|
||||
return it;
|
||||
}
|
||||
|
||||
protected:
|
||||
hb_iter_fallback_mixin_t () = default;
|
||||
hb_iter_fallback_mixin_t (const hb_iter_fallback_mixin_t &o HB_UNUSED) = default;
|
||||
hb_iter_fallback_mixin_t (hb_iter_fallback_mixin_t &&o HB_UNUSED) = default;
|
||||
hb_iter_fallback_mixin_t& operator = (const hb_iter_fallback_mixin_t &o HB_UNUSED) = default;
|
||||
hb_iter_fallback_mixin_t& operator = (hb_iter_fallback_mixin_t &&o HB_UNUSED) = default;
|
||||
};
|
||||
|
||||
|
||||
/* Functions operating on iterators or iteratables. */
|
||||
|
||||
template <typename C, typename V> inline void
|
||||
hb_fill (const C& c, const V &v)
|
||||
template <typename iter_t, typename item_t = typename iter_t::__item_t__>
|
||||
struct hb_iter_with_fallback_t :
|
||||
hb_iter_t<iter_t, item_t>,
|
||||
hb_iter_fallback_mixin_t<iter_t, item_t>
|
||||
{
|
||||
for (typename C::iter_t i (c); i; i++)
|
||||
hb_assign (*i, v);
|
||||
protected:
|
||||
hb_iter_with_fallback_t () = default;
|
||||
hb_iter_with_fallback_t (const hb_iter_with_fallback_t &o HB_UNUSED) = default;
|
||||
hb_iter_with_fallback_t (hb_iter_with_fallback_t &&o HB_UNUSED) = default;
|
||||
hb_iter_with_fallback_t& operator = (const hb_iter_with_fallback_t &o HB_UNUSED) = default;
|
||||
hb_iter_with_fallback_t& operator = (hb_iter_with_fallback_t &&o HB_UNUSED) = default;
|
||||
};
|
||||
|
||||
/*
|
||||
* Meta-programming predicates.
|
||||
*/
|
||||
|
||||
/* hb_is_iterator() / hb_is_iterator_of() */
|
||||
|
||||
template<typename Iter, typename Item>
|
||||
struct hb_is_iterator_of
|
||||
{
|
||||
template <typename Item2 = Item>
|
||||
static hb_true_type impl (hb_priority<2>, hb_iter_t<Iter, hb_type_identity<Item2>> *);
|
||||
static hb_false_type impl (hb_priority<0>, const void *);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype (impl (hb_prioritize, hb_declval (Iter*)))::value;
|
||||
};
|
||||
#define hb_is_iterator_of(Iter, Item) hb_is_iterator_of<Iter, Item>::value
|
||||
#define hb_is_iterator(Iter) hb_is_iterator_of (Iter, typename Iter::item_t)
|
||||
|
||||
/* hb_is_iterable() */
|
||||
|
||||
template <typename T>
|
||||
struct hb_is_iterable
|
||||
{
|
||||
private:
|
||||
|
||||
template <typename U>
|
||||
static auto impl (hb_priority<1>) -> decltype (hb_declval (U).iter (), hb_true_type ());
|
||||
|
||||
template <typename>
|
||||
static hb_false_type impl (hb_priority<0>);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype (impl<T> (hb_prioritize))::value;
|
||||
};
|
||||
#define hb_is_iterable(Iterable) hb_is_iterable<Iterable>::value
|
||||
|
||||
/* hb_is_source_of() / hb_is_sink_of() */
|
||||
|
||||
template<typename Iter, typename Item>
|
||||
struct hb_is_source_of
|
||||
{
|
||||
private:
|
||||
template <typename Iter2 = Iter,
|
||||
hb_enable_if (hb_is_convertible (typename Iter2::item_t, hb_add_lvalue_reference<hb_add_const<Item>>))>
|
||||
static hb_true_type impl (hb_priority<2>);
|
||||
template <typename Iter2 = Iter>
|
||||
static auto impl (hb_priority<1>) -> decltype (hb_declval (Iter2) >> hb_declval (Item &), hb_true_type ());
|
||||
static hb_false_type impl (hb_priority<0>);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype (impl (hb_prioritize))::value;
|
||||
};
|
||||
#define hb_is_source_of(Iter, Item) hb_is_source_of<Iter, Item>::value
|
||||
|
||||
template<typename Iter, typename Item>
|
||||
struct hb_is_sink_of
|
||||
{
|
||||
private:
|
||||
template <typename Iter2 = Iter,
|
||||
hb_enable_if (hb_is_convertible (typename Iter2::item_t, hb_add_lvalue_reference<Item>))>
|
||||
static hb_true_type impl (hb_priority<2>);
|
||||
template <typename Iter2 = Iter>
|
||||
static auto impl (hb_priority<1>) -> decltype (hb_declval (Iter2) << hb_declval (Item), hb_true_type ());
|
||||
static hb_false_type impl (hb_priority<0>);
|
||||
|
||||
public:
|
||||
static constexpr bool value = decltype (impl (hb_prioritize))::value;
|
||||
};
|
||||
#define hb_is_sink_of(Iter, Item) hb_is_sink_of<Iter, Item>::value
|
||||
|
||||
/* This is commonly used, so define: */
|
||||
#define hb_is_sorted_source_of(Iter, Item) \
|
||||
(hb_is_source_of(Iter, Item) && Iter::is_sorted_iterator)
|
||||
|
||||
|
||||
/* Range-based 'for' for iterables. */
|
||||
|
||||
template <typename Iterable,
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
static inline auto begin (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).begin ())
|
||||
|
||||
template <typename Iterable,
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
static inline auto end (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).end ())
|
||||
|
||||
/* begin()/end() are NOT looked up non-ADL. So each namespace must declare them.
|
||||
* Do it for namespace OT. */
|
||||
namespace OT {
|
||||
|
||||
template <typename Iterable,
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
static inline auto begin (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).begin ())
|
||||
|
||||
template <typename Iterable,
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
static inline auto end (Iterable&& iterable) HB_AUTO_RETURN (hb_iter (iterable).end ())
|
||||
|
||||
}
|
||||
|
||||
template <typename S, typename D> inline bool
|
||||
hb_copy (hb_iter_t<D> &id, hb_iter_t<S> &is)
|
||||
|
||||
/*
|
||||
* Adaptors, combiners, etc.
|
||||
*/
|
||||
|
||||
template <typename Lhs, typename Rhs,
|
||||
hb_requires (hb_is_iterator (Lhs))>
|
||||
static inline auto
|
||||
operator | (Lhs&& lhs, Rhs&& rhs) HB_AUTO_RETURN (hb_forward<Rhs> (rhs) (hb_forward<Lhs> (lhs)))
|
||||
|
||||
/* hb_map(), hb_filter(), hb_reduce() */
|
||||
|
||||
enum class hb_function_sortedness_t {
|
||||
NOT_SORTED,
|
||||
RETAINS_SORTING,
|
||||
SORTED,
|
||||
};
|
||||
|
||||
template <typename Iter, typename Proj, hb_function_sortedness_t Sorted,
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
struct hb_map_iter_t :
|
||||
hb_iter_t<hb_map_iter_t<Iter, Proj, Sorted>,
|
||||
decltype (hb_get (hb_declval (Proj), *hb_declval (Iter)))>
|
||||
{
|
||||
for (; id && is; ++id, ++is)
|
||||
*id = *is;
|
||||
return !is;
|
||||
hb_map_iter_t (const Iter& it, Proj f_) : it (it), f (f_) {}
|
||||
|
||||
typedef decltype (hb_get (hb_declval (Proj), *hb_declval (Iter))) __item_t__;
|
||||
static constexpr bool is_random_access_iterator = Iter::is_random_access_iterator;
|
||||
static constexpr bool is_sorted_iterator =
|
||||
Sorted == hb_function_sortedness_t::SORTED ? true :
|
||||
Sorted == hb_function_sortedness_t::RETAINS_SORTING ? Iter::is_sorted_iterator :
|
||||
false;
|
||||
__item_t__ __item__ () const { return hb_get (f.get (), *it); }
|
||||
__item_t__ __item_at__ (unsigned i) const { return hb_get (f.get (), it[i]); }
|
||||
bool __more__ () const { return bool (it); }
|
||||
unsigned __len__ () const { return it.len (); }
|
||||
void __next__ () { ++it; }
|
||||
void __forward__ (unsigned n) { it += n; }
|
||||
void __prev__ () { --it; }
|
||||
void __rewind__ (unsigned n) { it -= n; }
|
||||
hb_map_iter_t __end__ () const { return hb_map_iter_t (it.end (), f); }
|
||||
bool operator != (const hb_map_iter_t& o) const
|
||||
{ return it != o.it; }
|
||||
|
||||
private:
|
||||
Iter it;
|
||||
hb_reference_wrapper<Proj> f;
|
||||
};
|
||||
|
||||
template <typename Proj, hb_function_sortedness_t Sorted>
|
||||
struct hb_map_iter_factory_t
|
||||
{
|
||||
hb_map_iter_factory_t (Proj f) : f (f) {}
|
||||
|
||||
template <typename Iter,
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
hb_map_iter_t<Iter, Proj, Sorted>
|
||||
operator () (Iter it)
|
||||
{ return hb_map_iter_t<Iter, Proj, Sorted> (it, f); }
|
||||
|
||||
private:
|
||||
Proj f;
|
||||
};
|
||||
struct
|
||||
{
|
||||
template <typename Proj>
|
||||
hb_map_iter_factory_t<Proj, hb_function_sortedness_t::NOT_SORTED>
|
||||
operator () (Proj&& f) const
|
||||
{ return hb_map_iter_factory_t<Proj, hb_function_sortedness_t::NOT_SORTED> (f); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_map);
|
||||
struct
|
||||
{
|
||||
template <typename Proj>
|
||||
hb_map_iter_factory_t<Proj, hb_function_sortedness_t::RETAINS_SORTING>
|
||||
operator () (Proj&& f) const
|
||||
{ return hb_map_iter_factory_t<Proj, hb_function_sortedness_t::RETAINS_SORTING> (f); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_map_retains_sorting);
|
||||
struct
|
||||
{
|
||||
template <typename Proj>
|
||||
hb_map_iter_factory_t<Proj, hb_function_sortedness_t::SORTED>
|
||||
operator () (Proj&& f) const
|
||||
{ return hb_map_iter_factory_t<Proj, hb_function_sortedness_t::SORTED> (f); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_map_sorted);
|
||||
|
||||
template <typename Iter, typename Pred, typename Proj,
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
struct hb_filter_iter_t :
|
||||
hb_iter_with_fallback_t<hb_filter_iter_t<Iter, Pred, Proj>,
|
||||
typename Iter::item_t>
|
||||
{
|
||||
hb_filter_iter_t (const Iter& it_, Pred p_, Proj f_) : it (it_), p (p_), f (f_)
|
||||
{ while (it && !hb_has (p.get (), hb_get (f.get (), *it))) ++it; }
|
||||
|
||||
typedef typename Iter::item_t __item_t__;
|
||||
static constexpr bool is_sorted_iterator = Iter::is_sorted_iterator;
|
||||
__item_t__ __item__ () const { return *it; }
|
||||
bool __more__ () const { return bool (it); }
|
||||
void __next__ () { do ++it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); }
|
||||
void __prev__ () { do --it; while (it && !hb_has (p.get (), hb_get (f.get (), *it))); }
|
||||
hb_filter_iter_t __end__ () const { return hb_filter_iter_t (it.end (), p, f); }
|
||||
bool operator != (const hb_filter_iter_t& o) const
|
||||
{ return it != o.it; }
|
||||
|
||||
private:
|
||||
Iter it;
|
||||
hb_reference_wrapper<Pred> p;
|
||||
hb_reference_wrapper<Proj> f;
|
||||
};
|
||||
template <typename Pred, typename Proj>
|
||||
struct hb_filter_iter_factory_t
|
||||
{
|
||||
hb_filter_iter_factory_t (Pred p, Proj f) : p (p), f (f) {}
|
||||
|
||||
template <typename Iter,
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
hb_filter_iter_t<Iter, Pred, Proj>
|
||||
operator () (Iter it)
|
||||
{ return hb_filter_iter_t<Iter, Pred, Proj> (it, p, f); }
|
||||
|
||||
private:
|
||||
Pred p;
|
||||
Proj f;
|
||||
};
|
||||
struct
|
||||
{
|
||||
template <typename Pred = decltype ((hb_identity)),
|
||||
typename Proj = decltype ((hb_identity))>
|
||||
hb_filter_iter_factory_t<Pred, Proj>
|
||||
operator () (Pred&& p = hb_identity, Proj&& f = hb_identity) const
|
||||
{ return hb_filter_iter_factory_t<Pred, Proj> (p, f); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_filter);
|
||||
|
||||
template <typename Redu, typename InitT>
|
||||
struct hb_reduce_t
|
||||
{
|
||||
hb_reduce_t (Redu r, InitT init_value) : r (r), init_value (init_value) {}
|
||||
|
||||
template <typename Iter,
|
||||
hb_requires (hb_is_iterator (Iter)),
|
||||
typename AccuT = hb_decay<decltype (hb_declval (Redu) (hb_declval (InitT), hb_declval (typename Iter::item_t)))>>
|
||||
AccuT
|
||||
operator () (Iter it)
|
||||
{
|
||||
AccuT value = init_value;
|
||||
for (; it; ++it)
|
||||
value = r (value, *it);
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
Redu r;
|
||||
InitT init_value;
|
||||
};
|
||||
struct
|
||||
{
|
||||
template <typename Redu, typename InitT>
|
||||
hb_reduce_t<Redu, InitT>
|
||||
operator () (Redu&& r, InitT init_value) const
|
||||
{ return hb_reduce_t<Redu, InitT> (r, init_value); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_reduce);
|
||||
|
||||
|
||||
/* hb_zip() */
|
||||
|
||||
template <typename A, typename B>
|
||||
struct hb_zip_iter_t :
|
||||
hb_iter_t<hb_zip_iter_t<A, B>,
|
||||
hb_pair_t<typename A::item_t, typename B::item_t>>
|
||||
{
|
||||
hb_zip_iter_t () {}
|
||||
hb_zip_iter_t (const A& a, const B& b) : a (a), b (b) {}
|
||||
|
||||
typedef hb_pair_t<typename A::item_t, typename B::item_t> __item_t__;
|
||||
static constexpr bool is_random_access_iterator =
|
||||
A::is_random_access_iterator &&
|
||||
B::is_random_access_iterator;
|
||||
/* Note. The following categorization is only valid if A is strictly sorted,
|
||||
* ie. does NOT have duplicates. Previously I tried to categorize sortedness
|
||||
* more granularly, see commits:
|
||||
*
|
||||
* 513762849a683914fc266a17ddf38f133cccf072
|
||||
* 4d3cf2adb669c345cc43832d11689271995e160a
|
||||
*
|
||||
* However, that was not enough, since hb_sorted_array_t, hb_sorted_vector_t,
|
||||
* SortedArrayOf, etc all needed to be updated to add more variants. At that
|
||||
* point I saw it not worth the effort, and instead we now deem all sorted
|
||||
* collections as essentially strictly-sorted for the purposes of zip.
|
||||
*
|
||||
* The above assumption is not as bad as it sounds. Our "sorted" comes with
|
||||
* no guarantees. It's just a contract, put in place to help you remember,
|
||||
* and think about, whether an iterator you receive is expected to be
|
||||
* sorted or not. As such, it's not perfect by definition, and should not
|
||||
* be treated so. The inaccuracy here just errs in the direction of being
|
||||
* more permissive, so your code compiles instead of erring on the side of
|
||||
* marking your zipped iterator unsorted in which case your code won't
|
||||
* compile.
|
||||
*
|
||||
* This semantical limitation does NOT affect logic in any other place I
|
||||
* know of as of this writing.
|
||||
*/
|
||||
static constexpr bool is_sorted_iterator = A::is_sorted_iterator;
|
||||
|
||||
__item_t__ __item__ () const { return __item_t__ (*a, *b); }
|
||||
__item_t__ __item_at__ (unsigned i) const { return __item_t__ (a[i], b[i]); }
|
||||
bool __more__ () const { return bool (a) && bool (b); }
|
||||
unsigned __len__ () const { return hb_min (a.len (), b.len ()); }
|
||||
void __next__ () { ++a; ++b; }
|
||||
void __forward__ (unsigned n) { a += n; b += n; }
|
||||
void __prev__ () { --a; --b; }
|
||||
void __rewind__ (unsigned n) { a -= n; b -= n; }
|
||||
hb_zip_iter_t __end__ () const { return hb_zip_iter_t (a.end (), b.end ()); }
|
||||
/* Note, we should stop if ANY of the iters reaches end. As such two compare
|
||||
* unequal if both items are unequal, NOT if either is unequal. */
|
||||
bool operator != (const hb_zip_iter_t& o) const
|
||||
{ return a != o.a && b != o.b; }
|
||||
|
||||
private:
|
||||
A a;
|
||||
B b;
|
||||
};
|
||||
struct
|
||||
{ HB_PARTIALIZE(2);
|
||||
template <typename A, typename B,
|
||||
hb_requires (hb_is_iterable (A) && hb_is_iterable (B))>
|
||||
hb_zip_iter_t<hb_iter_type<A>, hb_iter_type<B>>
|
||||
operator () (A&& a, B&& b) const
|
||||
{ return hb_zip_iter_t<hb_iter_type<A>, hb_iter_type<B>> (hb_iter (a), hb_iter (b)); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_zip);
|
||||
|
||||
/* hb_apply() */
|
||||
|
||||
template <typename Appl>
|
||||
struct hb_apply_t
|
||||
{
|
||||
hb_apply_t (Appl a) : a (a) {}
|
||||
|
||||
template <typename Iter,
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
void operator () (Iter it)
|
||||
{
|
||||
for (; it; ++it)
|
||||
(void) hb_invoke (a, *it);
|
||||
}
|
||||
|
||||
private:
|
||||
Appl a;
|
||||
};
|
||||
struct
|
||||
{
|
||||
template <typename Appl> hb_apply_t<Appl>
|
||||
operator () (Appl&& a) const
|
||||
{ return hb_apply_t<Appl> (a); }
|
||||
|
||||
template <typename Appl> hb_apply_t<Appl&>
|
||||
operator () (Appl *a) const
|
||||
{ return hb_apply_t<Appl&> (*a); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_apply);
|
||||
|
||||
/* hb_range()/hb_iota()/hb_repeat() */
|
||||
|
||||
template <typename T, typename S>
|
||||
struct hb_range_iter_t :
|
||||
hb_iter_t<hb_range_iter_t<T, S>, T>
|
||||
{
|
||||
hb_range_iter_t (T start, T end_, S step) : v (start), end_ (end_for (start, end_, step)), step (step) {}
|
||||
|
||||
typedef T __item_t__;
|
||||
static constexpr bool is_random_access_iterator = true;
|
||||
static constexpr bool is_sorted_iterator = true;
|
||||
__item_t__ __item__ () const { return hb_ridentity (v); }
|
||||
__item_t__ __item_at__ (unsigned j) const { return v + j * step; }
|
||||
bool __more__ () const { return v != end_; }
|
||||
unsigned __len__ () const { return !step ? UINT_MAX : (end_ - v) / step; }
|
||||
void __next__ () { v += step; }
|
||||
void __forward__ (unsigned n) { v += n * step; }
|
||||
void __prev__ () { v -= step; }
|
||||
void __rewind__ (unsigned n) { v -= n * step; }
|
||||
hb_range_iter_t __end__ () const { return hb_range_iter_t (end_, end_, step); }
|
||||
bool operator != (const hb_range_iter_t& o) const
|
||||
{ return v != o.v; }
|
||||
|
||||
private:
|
||||
static inline T end_for (T start, T end_, S step)
|
||||
{
|
||||
if (!step)
|
||||
return end_;
|
||||
auto res = (end_ - start) % step;
|
||||
if (!res)
|
||||
return end_;
|
||||
end_ += step - res;
|
||||
return end_;
|
||||
}
|
||||
|
||||
private:
|
||||
T v;
|
||||
T end_;
|
||||
S step;
|
||||
};
|
||||
struct
|
||||
{
|
||||
template <typename T = unsigned> hb_range_iter_t<T, unsigned>
|
||||
operator () (T end = (unsigned) -1) const
|
||||
{ return hb_range_iter_t<T, unsigned> (0, end, 1u); }
|
||||
|
||||
template <typename T, typename S = unsigned> hb_range_iter_t<T, S>
|
||||
operator () (T start, T end, S step = 1u) const
|
||||
{ return hb_range_iter_t<T, S> (start, end, step); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_range);
|
||||
|
||||
template <typename T, typename S>
|
||||
struct hb_iota_iter_t :
|
||||
hb_iter_with_fallback_t<hb_iota_iter_t<T, S>, T>
|
||||
{
|
||||
hb_iota_iter_t (T start, S step) : v (start), step (step) {}
|
||||
|
||||
private:
|
||||
|
||||
template <typename S2 = S>
|
||||
auto
|
||||
inc (hb_type_identity<S2> s, hb_priority<1>)
|
||||
-> hb_void_t<decltype (hb_invoke (hb_forward<S2> (s), hb_declval<T&> ()))>
|
||||
{ v = hb_invoke (hb_forward<S2> (s), v); }
|
||||
|
||||
void
|
||||
inc (S s, hb_priority<0>)
|
||||
{ v += s; }
|
||||
|
||||
public:
|
||||
|
||||
typedef T __item_t__;
|
||||
static constexpr bool is_random_access_iterator = true;
|
||||
static constexpr bool is_sorted_iterator = true;
|
||||
__item_t__ __item__ () const { return hb_ridentity (v); }
|
||||
bool __more__ () const { return true; }
|
||||
unsigned __len__ () const { return UINT_MAX; }
|
||||
void __next__ () { inc (step, hb_prioritize); }
|
||||
void __prev__ () { v -= step; }
|
||||
hb_iota_iter_t __end__ () const { return *this; }
|
||||
bool operator != (const hb_iota_iter_t& o) const { return true; }
|
||||
|
||||
private:
|
||||
T v;
|
||||
S step;
|
||||
};
|
||||
struct
|
||||
{
|
||||
template <typename T = unsigned, typename S = unsigned> hb_iota_iter_t<T, S>
|
||||
operator () (T start = 0u, S step = 1u) const
|
||||
{ return hb_iota_iter_t<T, S> (start, step); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_iota);
|
||||
|
||||
template <typename T>
|
||||
struct hb_repeat_iter_t :
|
||||
hb_iter_t<hb_repeat_iter_t<T>, T>
|
||||
{
|
||||
hb_repeat_iter_t (T value) : v (value) {}
|
||||
|
||||
typedef T __item_t__;
|
||||
static constexpr bool is_random_access_iterator = true;
|
||||
static constexpr bool is_sorted_iterator = true;
|
||||
__item_t__ __item__ () const { return v; }
|
||||
__item_t__ __item_at__ (unsigned j) const { return v; }
|
||||
bool __more__ () const { return true; }
|
||||
unsigned __len__ () const { return UINT_MAX; }
|
||||
void __next__ () {}
|
||||
void __forward__ (unsigned) {}
|
||||
void __prev__ () {}
|
||||
void __rewind__ (unsigned) {}
|
||||
hb_repeat_iter_t __end__ () const { return *this; }
|
||||
bool operator != (const hb_repeat_iter_t& o) const { return true; }
|
||||
|
||||
private:
|
||||
T v;
|
||||
};
|
||||
struct
|
||||
{
|
||||
template <typename T> hb_repeat_iter_t<T>
|
||||
operator () (T value) const
|
||||
{ return hb_repeat_iter_t<T> (value); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_repeat);
|
||||
|
||||
/* hb_enumerate()/hb_take() */
|
||||
|
||||
struct
|
||||
{
|
||||
template <typename Iterable,
|
||||
typename Index = unsigned,
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
auto operator () (Iterable&& it, Index start = 0u) const HB_AUTO_RETURN
|
||||
( hb_zip (hb_iota (start), it) )
|
||||
}
|
||||
HB_FUNCOBJ (hb_enumerate);
|
||||
|
||||
struct
|
||||
{ HB_PARTIALIZE(2);
|
||||
template <typename Iterable,
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
auto operator () (Iterable&& it, unsigned count) const HB_AUTO_RETURN
|
||||
( hb_zip (hb_range (count), it) | hb_map (hb_second) )
|
||||
|
||||
/* Specialization arrays. */
|
||||
|
||||
template <typename Type> inline hb_array_t<Type>
|
||||
operator () (hb_array_t<Type> array, unsigned count) const
|
||||
{ return array.sub_array (0, count); }
|
||||
|
||||
template <typename Type> inline hb_sorted_array_t<Type>
|
||||
operator () (hb_sorted_array_t<Type> array, unsigned count) const
|
||||
{ return array.sub_array (0, count); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_take);
|
||||
|
||||
struct
|
||||
{ HB_PARTIALIZE(2);
|
||||
template <typename Iter,
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
auto operator () (Iter it, unsigned count) const HB_AUTO_RETURN
|
||||
(
|
||||
+ hb_iota (it, hb_add (count))
|
||||
| hb_map (hb_take (count))
|
||||
| hb_take ((hb_len (it) + count - 1) / count)
|
||||
)
|
||||
}
|
||||
HB_FUNCOBJ (hb_chop);
|
||||
|
||||
/* hb_sink() */
|
||||
|
||||
template <typename Sink>
|
||||
struct hb_sink_t
|
||||
{
|
||||
hb_sink_t (Sink s) : s (s) {}
|
||||
|
||||
template <typename Iter,
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
void operator () (Iter it)
|
||||
{
|
||||
for (; it; ++it)
|
||||
s << *it;
|
||||
}
|
||||
|
||||
private:
|
||||
Sink s;
|
||||
};
|
||||
struct
|
||||
{
|
||||
template <typename Sink> hb_sink_t<Sink>
|
||||
operator () (Sink&& s) const
|
||||
{ return hb_sink_t<Sink> (s); }
|
||||
|
||||
template <typename Sink> hb_sink_t<Sink&>
|
||||
operator () (Sink *s) const
|
||||
{ return hb_sink_t<Sink&> (*s); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_sink);
|
||||
|
||||
/* hb-drain: hb_sink to void / blackhole / /dev/null. */
|
||||
|
||||
struct
|
||||
{
|
||||
template <typename Iter,
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
void operator () (Iter it) const
|
||||
{
|
||||
for (; it; ++it)
|
||||
(void) *it;
|
||||
}
|
||||
}
|
||||
HB_FUNCOBJ (hb_drain);
|
||||
|
||||
/* hb_unzip(): unzip and sink to two sinks. */
|
||||
|
||||
template <typename Sink1, typename Sink2>
|
||||
struct hb_unzip_t
|
||||
{
|
||||
hb_unzip_t (Sink1 s1, Sink2 s2) : s1 (s1), s2 (s2) {}
|
||||
|
||||
template <typename Iter,
|
||||
hb_requires (hb_is_iterator (Iter))>
|
||||
void operator () (Iter it)
|
||||
{
|
||||
for (; it; ++it)
|
||||
{
|
||||
const auto &v = *it;
|
||||
s1 << v.first;
|
||||
s2 << v.second;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Sink1 s1;
|
||||
Sink2 s2;
|
||||
};
|
||||
struct
|
||||
{
|
||||
template <typename Sink1, typename Sink2> hb_unzip_t<Sink1, Sink2>
|
||||
operator () (Sink1&& s1, Sink2&& s2) const
|
||||
{ return hb_unzip_t<Sink1, Sink2> (s1, s2); }
|
||||
|
||||
template <typename Sink1, typename Sink2> hb_unzip_t<Sink1&, Sink2&>
|
||||
operator () (Sink1 *s1, Sink2 *s2) const
|
||||
{ return hb_unzip_t<Sink1&, Sink2&> (*s1, *s2); }
|
||||
}
|
||||
HB_FUNCOBJ (hb_unzip);
|
||||
|
||||
|
||||
/* hb-all, hb-any, hb-none. */
|
||||
|
||||
struct
|
||||
{
|
||||
template <typename Iterable,
|
||||
typename Pred = decltype ((hb_identity)),
|
||||
typename Proj = decltype ((hb_identity)),
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
bool operator () (Iterable&& c,
|
||||
Pred&& p = hb_identity,
|
||||
Proj&& f = hb_identity) const
|
||||
{
|
||||
for (auto it = hb_iter (c); it; ++it)
|
||||
if (!hb_match (hb_forward<Pred> (p), hb_get (hb_forward<Proj> (f), *it)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
HB_FUNCOBJ (hb_all);
|
||||
struct
|
||||
{
|
||||
template <typename Iterable,
|
||||
typename Pred = decltype ((hb_identity)),
|
||||
typename Proj = decltype ((hb_identity)),
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
bool operator () (Iterable&& c,
|
||||
Pred&& p = hb_identity,
|
||||
Proj&& f = hb_identity) const
|
||||
{
|
||||
for (auto it = hb_iter (c); it; ++it)
|
||||
if (hb_match (hb_forward<Pred> (p), hb_get (hb_forward<Proj> (f), *it)))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
HB_FUNCOBJ (hb_any);
|
||||
struct
|
||||
{
|
||||
template <typename Iterable,
|
||||
typename Pred = decltype ((hb_identity)),
|
||||
typename Proj = decltype ((hb_identity)),
|
||||
hb_requires (hb_is_iterable (Iterable))>
|
||||
bool operator () (Iterable&& c,
|
||||
Pred&& p = hb_identity,
|
||||
Proj&& f = hb_identity) const
|
||||
{
|
||||
for (auto it = hb_iter (c); it; ++it)
|
||||
if (hb_match (hb_forward<Pred> (p), hb_get (hb_forward<Proj> (f), *it)))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
HB_FUNCOBJ (hb_none);
|
||||
|
||||
/*
|
||||
* Algorithms operating on iterators.
|
||||
*/
|
||||
|
||||
template <typename C, typename V,
|
||||
hb_requires (hb_is_iterable (C))>
|
||||
inline void
|
||||
hb_fill (C& c, const V &v)
|
||||
{
|
||||
for (auto i = hb_iter (c); i; i++)
|
||||
*i = v;
|
||||
}
|
||||
|
||||
template <typename S, typename D>
|
||||
inline void
|
||||
hb_copy (S&& is, D&& id)
|
||||
{
|
||||
hb_iter (is) | hb_sink (id);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -52,8 +52,7 @@ struct hb_kern_machine_t
|
||||
OT::hb_ot_apply_context_t c (1, font, buffer);
|
||||
c.set_lookup_mask (kern_mask);
|
||||
c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
|
||||
OT::hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c.iter_input;
|
||||
skippy_iter.init (&c);
|
||||
auto &skippy_iter = c.iter_input;
|
||||
|
||||
bool horizontal = HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction);
|
||||
unsigned int count = buffer->len;
|
||||
|
||||
@ -32,30 +32,15 @@
|
||||
#include "hb.hh"
|
||||
#include "hb-blob.hh"
|
||||
|
||||
#include "hb-array.hh"
|
||||
#include "hb-vector.hh"
|
||||
#include "hb-dispatch.hh"
|
||||
#include "hb-sanitize.hh"
|
||||
#include "hb-serialize.hh"
|
||||
|
||||
|
||||
/*
|
||||
* Casts
|
||||
*/
|
||||
|
||||
/* Cast to struct T, reference to reference */
|
||||
template<typename Type, typename TObject>
|
||||
static inline const Type& CastR(const TObject &X)
|
||||
{ return reinterpret_cast<const Type&> (X); }
|
||||
template<typename Type, typename TObject>
|
||||
static inline Type& CastR(TObject &X)
|
||||
{ return reinterpret_cast<Type&> (X); }
|
||||
|
||||
/* Cast to struct T, pointer to pointer */
|
||||
template<typename Type, typename TObject>
|
||||
static inline const Type* CastP(const TObject *X)
|
||||
{ return reinterpret_cast<const Type*> (X); }
|
||||
template<typename Type, typename TObject>
|
||||
static inline Type* CastP(TObject *X)
|
||||
{ return reinterpret_cast<Type*> (X); }
|
||||
|
||||
/* StructAtOffset<T>(P,Ofs) returns the struct T& that is placed at memory
|
||||
* location pointed to by P plus Ofs bytes. */
|
||||
template<typename Type>
|
||||
@ -69,7 +54,7 @@ static inline const Type& StructAtOffsetUnaligned(const void *P, unsigned int of
|
||||
{
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wcast-align"
|
||||
return * reinterpret_cast<Type*> ((char *) P + offset);
|
||||
return * reinterpret_cast<const Type*> ((const char *) P + offset);
|
||||
#pragma GCC diagnostic pop
|
||||
}
|
||||
template<typename Type>
|
||||
@ -134,7 +119,7 @@ static inline Type& StructAfter(TObject &X)
|
||||
|
||||
#define DEFINE_SIZE_ARRAY(size, array) \
|
||||
DEFINE_COMPILES_ASSERTION ((void) (array)[0].static_size) \
|
||||
DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + VAR * sizeof ((array)[0])) \
|
||||
DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + (HB_VAR_ARRAY+0) * sizeof ((array)[0])) \
|
||||
static constexpr unsigned null_size = (size); \
|
||||
static constexpr unsigned min_size = (size)
|
||||
|
||||
@ -143,615 +128,6 @@ static inline Type& StructAfter(TObject &X)
|
||||
DEFINE_SIZE_ARRAY(size, array)
|
||||
|
||||
|
||||
/*
|
||||
* Dispatch
|
||||
*/
|
||||
|
||||
template <typename Context, typename Return, unsigned int MaxDebugDepth>
|
||||
struct hb_dispatch_context_t
|
||||
{
|
||||
static constexpr unsigned max_debug_depth = MaxDebugDepth;
|
||||
typedef Return return_t;
|
||||
template <typename T, typename F>
|
||||
bool may_dispatch (const T *obj HB_UNUSED, const F *format HB_UNUSED) { return true; }
|
||||
static return_t no_dispatch_return_value () { return Context::default_return_value (); }
|
||||
static bool stop_sublookup_iteration (const return_t r HB_UNUSED) { return false; }
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Sanitize
|
||||
*
|
||||
*
|
||||
* === Introduction ===
|
||||
*
|
||||
* The sanitize machinery is at the core of our zero-cost font loading. We
|
||||
* mmap() font file into memory and create a blob out of it. Font subtables
|
||||
* are returned as a readonly sub-blob of the main font blob. These table
|
||||
* blobs are then sanitized before use, to ensure invalid memory access does
|
||||
* not happen. The toplevel sanitize API use is like, eg. to load the 'head'
|
||||
* table:
|
||||
*
|
||||
* hb_blob_t *head_blob = hb_sanitize_context_t ().reference_table<OT::head> (face);
|
||||
*
|
||||
* The blob then can be converted to a head table struct with:
|
||||
*
|
||||
* const head *head_table = head_blob->as<head> ();
|
||||
*
|
||||
* What the reference_table does is, to call hb_face_reference_table() to load
|
||||
* the table blob, sanitize it and return either the sanitized blob, or empty
|
||||
* blob if sanitization failed. The blob->as() function returns the null
|
||||
* object of its template type argument if the blob is empty. Otherwise, it
|
||||
* just casts the blob contents to the desired type.
|
||||
*
|
||||
* Sanitizing a blob of data with a type T works as follows (with minor
|
||||
* simplification):
|
||||
*
|
||||
* - Cast blob content to T*, call sanitize() method of it,
|
||||
* - If sanitize succeeded, return blob.
|
||||
* - Otherwise, if blob is not writable, try making it writable,
|
||||
* or copy if cannot be made writable in-place,
|
||||
* - Call sanitize() again. Return blob if sanitize succeeded.
|
||||
* - Return empty blob otherwise.
|
||||
*
|
||||
*
|
||||
* === The sanitize() contract ===
|
||||
*
|
||||
* The sanitize() method of each object type shall return true if it's safe to
|
||||
* call other methods of the object, and false otherwise.
|
||||
*
|
||||
* Note that what sanitize() checks for might align with what the specification
|
||||
* describes as valid table data, but does not have to be. In particular, we
|
||||
* do NOT want to be pedantic and concern ourselves with validity checks that
|
||||
* are irrelevant to our use of the table. On the contrary, we want to be
|
||||
* lenient with error handling and accept invalid data to the extent that it
|
||||
* does not impose extra burden on us.
|
||||
*
|
||||
* Based on the sanitize contract, one can see that what we check for depends
|
||||
* on how we use the data in other table methods. Ie. if other table methods
|
||||
* assume that offsets do NOT point out of the table data block, then that's
|
||||
* something sanitize() must check for (GSUB/GPOS/GDEF/etc work this way). On
|
||||
* the other hand, if other methods do such checks themselves, then sanitize()
|
||||
* does not have to bother with them (glyf/local work this way). The choice
|
||||
* depends on the table structure and sanitize() performance. For example, to
|
||||
* check glyf/loca offsets in sanitize() would cost O(num-glyphs). We try hard
|
||||
* to avoid such costs during font loading. By postponing such checks to the
|
||||
* actual glyph loading, we reduce the sanitize cost to O(1) and total runtime
|
||||
* cost to O(used-glyphs). As such, this is preferred.
|
||||
*
|
||||
* The same argument can be made re GSUB/GPOS/GDEF, but there, the table
|
||||
* structure is so complicated that by checking all offsets at sanitize() time,
|
||||
* we make the code much simpler in other methods, as offsets and referenced
|
||||
* objects do not need to be validated at each use site.
|
||||
*/
|
||||
|
||||
/* This limits sanitizing time on really broken fonts. */
|
||||
#ifndef HB_SANITIZE_MAX_EDITS
|
||||
#define HB_SANITIZE_MAX_EDITS 32
|
||||
#endif
|
||||
#ifndef HB_SANITIZE_MAX_OPS_FACTOR
|
||||
#define HB_SANITIZE_MAX_OPS_FACTOR 8
|
||||
#endif
|
||||
#ifndef HB_SANITIZE_MAX_OPS_MIN
|
||||
#define HB_SANITIZE_MAX_OPS_MIN 16384
|
||||
#endif
|
||||
#ifndef HB_SANITIZE_MAX_OPS_MAX
|
||||
#define HB_SANITIZE_MAX_OPS_MAX 0x3FFFFFFF
|
||||
#endif
|
||||
|
||||
struct hb_sanitize_context_t :
|
||||
hb_dispatch_context_t<hb_sanitize_context_t, bool, HB_DEBUG_SANITIZE>
|
||||
{
|
||||
hb_sanitize_context_t () :
|
||||
debug_depth (0),
|
||||
start (nullptr), end (nullptr),
|
||||
max_ops (0),
|
||||
writable (false), edit_count (0),
|
||||
blob (nullptr),
|
||||
num_glyphs (65536),
|
||||
num_glyphs_set (false) {}
|
||||
|
||||
const char *get_name () { return "SANITIZE"; }
|
||||
template <typename T, typename F>
|
||||
bool may_dispatch (const T *obj HB_UNUSED, const F *format)
|
||||
{ return format->sanitize (this); }
|
||||
template <typename T>
|
||||
return_t dispatch (const T &obj) { return obj.sanitize (this); }
|
||||
static return_t default_return_value () { return true; }
|
||||
static return_t no_dispatch_return_value () { return false; }
|
||||
bool stop_sublookup_iteration (const return_t r) const { return !r; }
|
||||
|
||||
void init (hb_blob_t *b)
|
||||
{
|
||||
this->blob = hb_blob_reference (b);
|
||||
this->writable = false;
|
||||
}
|
||||
|
||||
void set_num_glyphs (unsigned int num_glyphs_)
|
||||
{
|
||||
num_glyphs = num_glyphs_;
|
||||
num_glyphs_set = true;
|
||||
}
|
||||
unsigned int get_num_glyphs () { return num_glyphs; }
|
||||
|
||||
void set_max_ops (int max_ops_) { max_ops = max_ops_; }
|
||||
|
||||
template <typename T>
|
||||
void set_object (const T *obj)
|
||||
{
|
||||
reset_object ();
|
||||
|
||||
if (!obj) return;
|
||||
|
||||
const char *obj_start = (const char *) obj;
|
||||
if (unlikely (obj_start < this->start || this->end <= obj_start))
|
||||
this->start = this->end = nullptr;
|
||||
else
|
||||
{
|
||||
this->start = obj_start;
|
||||
this->end = obj_start + MIN<uintptr_t> (this->end - obj_start, obj->get_size ());
|
||||
}
|
||||
}
|
||||
|
||||
void reset_object ()
|
||||
{
|
||||
this->start = this->blob->data;
|
||||
this->end = this->start + this->blob->length;
|
||||
assert (this->start <= this->end); /* Must not overflow. */
|
||||
}
|
||||
|
||||
void start_processing ()
|
||||
{
|
||||
reset_object ();
|
||||
this->max_ops = MAX ((unsigned int) (this->end - this->start) * HB_SANITIZE_MAX_OPS_FACTOR,
|
||||
(unsigned) HB_SANITIZE_MAX_OPS_MIN);
|
||||
this->edit_count = 0;
|
||||
this->debug_depth = 0;
|
||||
|
||||
DEBUG_MSG_LEVEL (SANITIZE, start, 0, +1,
|
||||
"start [%p..%p] (%lu bytes)",
|
||||
this->start, this->end,
|
||||
(unsigned long) (this->end - this->start));
|
||||
}
|
||||
|
||||
void end_processing ()
|
||||
{
|
||||
DEBUG_MSG_LEVEL (SANITIZE, this->start, 0, -1,
|
||||
"end [%p..%p] %u edit requests",
|
||||
this->start, this->end, this->edit_count);
|
||||
|
||||
hb_blob_destroy (this->blob);
|
||||
this->blob = nullptr;
|
||||
this->start = this->end = nullptr;
|
||||
}
|
||||
|
||||
bool check_range (const void *base,
|
||||
unsigned int len) const
|
||||
{
|
||||
const char *p = (const char *) base;
|
||||
bool ok = this->start <= p &&
|
||||
p <= this->end &&
|
||||
(unsigned int) (this->end - p) >= len &&
|
||||
this->max_ops-- > 0;
|
||||
|
||||
DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
|
||||
"check_range [%p..%p] (%d bytes) in [%p..%p] -> %s",
|
||||
p, p + len, len,
|
||||
this->start, this->end,
|
||||
ok ? "OK" : "OUT-OF-RANGE");
|
||||
|
||||
return likely (ok);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool check_range (const T *base,
|
||||
unsigned int a,
|
||||
unsigned int b) const
|
||||
{
|
||||
return !hb_unsigned_mul_overflows (a, b) &&
|
||||
this->check_range (base, a * b);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool check_range (const T *base,
|
||||
unsigned int a,
|
||||
unsigned int b,
|
||||
unsigned int c) const
|
||||
{
|
||||
return !hb_unsigned_mul_overflows (a, b) &&
|
||||
this->check_range (base, a * b, c);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool check_array (const T *base, unsigned int len) const
|
||||
{
|
||||
return this->check_range (base, len, hb_static_size (T));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool check_array (const T *base,
|
||||
unsigned int a,
|
||||
unsigned int b) const
|
||||
{
|
||||
return this->check_range (base, a, b, hb_static_size (T));
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
bool check_struct (const Type *obj) const
|
||||
{ return likely (this->check_range (obj, obj->min_size)); }
|
||||
|
||||
bool may_edit (const void *base, unsigned int len)
|
||||
{
|
||||
if (this->edit_count >= HB_SANITIZE_MAX_EDITS)
|
||||
return false;
|
||||
|
||||
const char *p = (const char *) base;
|
||||
this->edit_count++;
|
||||
|
||||
DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
|
||||
"may_edit(%u) [%p..%p] (%d bytes) in [%p..%p] -> %s",
|
||||
this->edit_count,
|
||||
p, p + len, len,
|
||||
this->start, this->end,
|
||||
this->writable ? "GRANTED" : "DENIED");
|
||||
|
||||
return this->writable;
|
||||
}
|
||||
|
||||
template <typename Type, typename ValueType>
|
||||
bool try_set (const Type *obj, const ValueType &v)
|
||||
{
|
||||
if (this->may_edit (obj, hb_static_size (Type)))
|
||||
{
|
||||
hb_assign (* const_cast<Type *> (obj), v);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
hb_blob_t *sanitize_blob (hb_blob_t *blob)
|
||||
{
|
||||
bool sane;
|
||||
|
||||
init (blob);
|
||||
|
||||
retry:
|
||||
DEBUG_MSG_FUNC (SANITIZE, start, "start");
|
||||
|
||||
start_processing ();
|
||||
|
||||
if (unlikely (!start))
|
||||
{
|
||||
end_processing ();
|
||||
return blob;
|
||||
}
|
||||
|
||||
Type *t = CastP<Type> (const_cast<char *> (start));
|
||||
|
||||
sane = t->sanitize (this);
|
||||
if (sane)
|
||||
{
|
||||
if (edit_count)
|
||||
{
|
||||
DEBUG_MSG_FUNC (SANITIZE, start, "passed first round with %d edits; going for second round", edit_count);
|
||||
|
||||
/* sanitize again to ensure no toe-stepping */
|
||||
edit_count = 0;
|
||||
sane = t->sanitize (this);
|
||||
if (edit_count) {
|
||||
DEBUG_MSG_FUNC (SANITIZE, start, "requested %d edits in second round; FAILLING", edit_count);
|
||||
sane = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (edit_count && !writable) {
|
||||
start = hb_blob_get_data_writable (blob, nullptr);
|
||||
end = start + blob->length;
|
||||
|
||||
if (start)
|
||||
{
|
||||
writable = true;
|
||||
/* ok, we made it writable by relocating. try again */
|
||||
DEBUG_MSG_FUNC (SANITIZE, start, "retry");
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end_processing ();
|
||||
|
||||
DEBUG_MSG_FUNC (SANITIZE, start, sane ? "PASSED" : "FAILED");
|
||||
if (sane)
|
||||
{
|
||||
hb_blob_make_immutable (blob);
|
||||
return blob;
|
||||
}
|
||||
else
|
||||
{
|
||||
hb_blob_destroy (blob);
|
||||
return hb_blob_get_empty ();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
hb_blob_t *reference_table (const hb_face_t *face, hb_tag_t tableTag = Type::tableTag)
|
||||
{
|
||||
if (!num_glyphs_set)
|
||||
set_num_glyphs (hb_face_get_glyph_count (face));
|
||||
return sanitize_blob<Type> (hb_face_reference_table (face, tableTag));
|
||||
}
|
||||
|
||||
mutable unsigned int debug_depth;
|
||||
const char *start, *end;
|
||||
mutable int max_ops;
|
||||
private:
|
||||
bool writable;
|
||||
unsigned int edit_count;
|
||||
hb_blob_t *blob;
|
||||
unsigned int num_glyphs;
|
||||
bool num_glyphs_set;
|
||||
};
|
||||
|
||||
struct hb_sanitize_with_object_t
|
||||
{
|
||||
template <typename T>
|
||||
hb_sanitize_with_object_t (hb_sanitize_context_t *c,
|
||||
const T& obj) : c (c)
|
||||
{ c->set_object (obj); }
|
||||
~hb_sanitize_with_object_t ()
|
||||
{ c->reset_object (); }
|
||||
|
||||
private:
|
||||
hb_sanitize_context_t *c;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Serialize
|
||||
*/
|
||||
|
||||
struct hb_serialize_context_t
|
||||
{
|
||||
hb_serialize_context_t (void *start_, unsigned int size)
|
||||
{
|
||||
this->start = (char *) start_;
|
||||
this->end = this->start + size;
|
||||
reset ();
|
||||
}
|
||||
|
||||
bool in_error () const { return !this->successful; }
|
||||
|
||||
void reset ()
|
||||
{
|
||||
this->successful = true;
|
||||
this->head = this->start;
|
||||
this->debug_depth = 0;
|
||||
}
|
||||
|
||||
bool propagate_error (bool e)
|
||||
{ return this->successful = this->successful && e; }
|
||||
template <typename T> bool propagate_error (const T &obj)
|
||||
{ return this->successful = this->successful && !obj.in_error (); }
|
||||
template <typename T> bool propagate_error (const T *obj)
|
||||
{ return this->successful = this->successful && !obj->in_error (); }
|
||||
template <typename T1, typename T2> bool propagate_error (T1 &o1, T2 &o2)
|
||||
{ return propagate_error (o1) && propagate_error (o2); }
|
||||
template <typename T1, typename T2> bool propagate_error (T1 *o1, T2 *o2)
|
||||
{ return propagate_error (o1) && propagate_error (o2); }
|
||||
template <typename T1, typename T2, typename T3>
|
||||
bool propagate_error (T1 &o1, T2 &o2, T3 &o3)
|
||||
{ return propagate_error (o1) && propagate_error (o2, o3); }
|
||||
template <typename T1, typename T2, typename T3>
|
||||
bool propagate_error (T1 *o1, T2 *o2, T3 *o3)
|
||||
{ return propagate_error (o1) && propagate_error (o2, o3); }
|
||||
|
||||
/* To be called around main operation. */
|
||||
template <typename Type>
|
||||
Type *start_serialize ()
|
||||
{
|
||||
DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, +1,
|
||||
"start [%p..%p] (%lu bytes)",
|
||||
this->start, this->end,
|
||||
(unsigned long) (this->end - this->start));
|
||||
|
||||
return start_embed<Type> ();
|
||||
}
|
||||
void end_serialize ()
|
||||
{
|
||||
DEBUG_MSG_LEVEL (SERIALIZE, this->start, 0, -1,
|
||||
"end [%p..%p] serialized %d bytes; %s",
|
||||
this->start, this->end,
|
||||
(int) (this->head - this->start),
|
||||
this->successful ? "successful" : "UNSUCCESSFUL");
|
||||
}
|
||||
|
||||
unsigned int length () const { return this->head - this->start; }
|
||||
|
||||
void align (unsigned int alignment)
|
||||
{
|
||||
unsigned int l = length () % alignment;
|
||||
if (l)
|
||||
allocate_size<void> (alignment - l);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
Type *start_embed (const Type *_ HB_UNUSED = nullptr) const
|
||||
{
|
||||
Type *ret = reinterpret_cast<Type *> (this->head);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
Type *allocate_size (unsigned int size)
|
||||
{
|
||||
if (unlikely (!this->successful || this->end - this->head < ptrdiff_t (size))) {
|
||||
this->successful = false;
|
||||
return nullptr;
|
||||
}
|
||||
memset (this->head, 0, size);
|
||||
char *ret = this->head;
|
||||
this->head += size;
|
||||
return reinterpret_cast<Type *> (ret);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
Type *allocate_min ()
|
||||
{
|
||||
return this->allocate_size<Type> (Type::min_size);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
Type *embed (const Type &obj)
|
||||
{
|
||||
unsigned int size = obj.get_size ();
|
||||
Type *ret = this->allocate_size<Type> (size);
|
||||
if (unlikely (!ret)) return nullptr;
|
||||
memcpy (ret, &obj, size);
|
||||
return ret;
|
||||
}
|
||||
template <typename Type>
|
||||
hb_serialize_context_t &operator << (const Type &obj) { embed (obj); return *this; }
|
||||
|
||||
template <typename Type>
|
||||
Type *extend_size (Type &obj, unsigned int size)
|
||||
{
|
||||
assert (this->start <= (char *) &obj);
|
||||
assert ((char *) &obj <= this->head);
|
||||
assert ((char *) &obj + size >= this->head);
|
||||
if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return nullptr;
|
||||
return reinterpret_cast<Type *> (&obj);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
Type *extend_min (Type &obj) { return extend_size (obj, obj.min_size); }
|
||||
|
||||
template <typename Type>
|
||||
Type *extend (Type &obj) { return extend_size (obj, obj.get_size ()); }
|
||||
|
||||
/* Output routines. */
|
||||
template <typename Type>
|
||||
Type *copy () const
|
||||
{
|
||||
assert (this->successful);
|
||||
unsigned int len = this->head - this->start;
|
||||
void *p = malloc (len);
|
||||
if (p)
|
||||
memcpy (p, this->start, len);
|
||||
return reinterpret_cast<Type *> (p);
|
||||
}
|
||||
hb_bytes_t copy_bytes () const
|
||||
{
|
||||
assert (this->successful);
|
||||
unsigned int len = this->head - this->start;
|
||||
void *p = malloc (len);
|
||||
if (p)
|
||||
memcpy (p, this->start, len);
|
||||
else
|
||||
return hb_bytes_t ();
|
||||
return hb_bytes_t ((char *) p, len);
|
||||
}
|
||||
hb_blob_t *copy_blob () const
|
||||
{
|
||||
assert (this->successful);
|
||||
return hb_blob_create (this->start,
|
||||
this->head - this->start,
|
||||
HB_MEMORY_MODE_DUPLICATE,
|
||||
nullptr, nullptr);
|
||||
}
|
||||
|
||||
public:
|
||||
unsigned int debug_depth;
|
||||
char *start, *end, *head;
|
||||
bool successful;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Big-endian integers.
|
||||
*/
|
||||
|
||||
template <typename Type, int Bytes> struct BEInt;
|
||||
|
||||
template <typename Type>
|
||||
struct BEInt<Type, 1>
|
||||
{
|
||||
public:
|
||||
void set (Type V) { v = V; }
|
||||
operator Type () const { return v; }
|
||||
private: uint8_t v;
|
||||
};
|
||||
template <typename Type>
|
||||
struct BEInt<Type, 2>
|
||||
{
|
||||
public:
|
||||
void set (Type V)
|
||||
{
|
||||
v[0] = (V >> 8) & 0xFF;
|
||||
v[1] = (V ) & 0xFF;
|
||||
}
|
||||
operator Type () const
|
||||
{
|
||||
#if ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
|
||||
defined(__BYTE_ORDER) && \
|
||||
(__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN)
|
||||
/* Spoon-feed the compiler a big-endian integer with alignment 1.
|
||||
* https://github.com/harfbuzz/harfbuzz/pull/1398 */
|
||||
struct __attribute__((packed)) packed_uint16_t { uint16_t v; };
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
return __builtin_bswap16 (((packed_uint16_t *) this)->v);
|
||||
#else /* __BYTE_ORDER == __BIG_ENDIAN */
|
||||
return ((packed_uint16_t *) this)->v;
|
||||
#endif
|
||||
#endif
|
||||
return (v[0] << 8)
|
||||
+ (v[1] );
|
||||
}
|
||||
private: uint8_t v[2];
|
||||
};
|
||||
template <typename Type>
|
||||
struct BEInt<Type, 3>
|
||||
{
|
||||
public:
|
||||
void set (Type V)
|
||||
{
|
||||
v[0] = (V >> 16) & 0xFF;
|
||||
v[1] = (V >> 8) & 0xFF;
|
||||
v[2] = (V ) & 0xFF;
|
||||
}
|
||||
operator Type () const
|
||||
{
|
||||
return (v[0] << 16)
|
||||
+ (v[1] << 8)
|
||||
+ (v[2] );
|
||||
}
|
||||
private: uint8_t v[3];
|
||||
};
|
||||
template <typename Type>
|
||||
struct BEInt<Type, 4>
|
||||
{
|
||||
public:
|
||||
typedef Type type;
|
||||
void set (Type V)
|
||||
{
|
||||
v[0] = (V >> 24) & 0xFF;
|
||||
v[1] = (V >> 16) & 0xFF;
|
||||
v[2] = (V >> 8) & 0xFF;
|
||||
v[3] = (V ) & 0xFF;
|
||||
}
|
||||
operator Type () const
|
||||
{
|
||||
return (v[0] << 24)
|
||||
+ (v[1] << 16)
|
||||
+ (v[2] << 8)
|
||||
+ (v[3] );
|
||||
}
|
||||
private: uint8_t v[4];
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Lazy loaders.
|
||||
@ -814,7 +190,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
|
||||
|
||||
const Returned * operator -> () const { return get (); }
|
||||
const Returned & operator * () const { return *get (); }
|
||||
explicit_operator bool () const
|
||||
explicit operator bool () const
|
||||
{ return get_stored () != Funcs::get_null (); }
|
||||
template <typename C> operator const C * () const { return get (); }
|
||||
|
||||
@ -858,7 +234,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
|
||||
static Returned* convert (Stored *p) { return p; }
|
||||
|
||||
/* By default null/init/fini the object. */
|
||||
static const Stored* get_null () { return &Null(Stored); }
|
||||
static const Stored* get_null () { return &Null (Stored); }
|
||||
static Stored *create (Data *data)
|
||||
{
|
||||
Stored *p = (Stored *) calloc (1, sizeof (Stored));
|
||||
|
||||
@ -69,7 +69,7 @@ hb_map_create ()
|
||||
hb_map_t *
|
||||
hb_map_get_empty ()
|
||||
{
|
||||
return const_cast<hb_map_t *> (&Null(hb_map_t));
|
||||
return const_cast<hb_map_t *> (&Null (hb_map_t));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -30,31 +30,36 @@
|
||||
#include "hb.hh"
|
||||
|
||||
|
||||
template <typename T>
|
||||
inline uint32_t Hash (const T &v)
|
||||
{
|
||||
/* Knuth's multiplicative method: */
|
||||
return (uint32_t) v * 2654435761u;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* hb_map_t
|
||||
* hb_hashmap_t
|
||||
*/
|
||||
|
||||
struct hb_map_t
|
||||
template <typename K, typename V,
|
||||
K kINVALID = hb_is_pointer (K) ? 0 : hb_is_signed (K) ? hb_int_min (K) : (K) -1,
|
||||
V vINVALID = hb_is_pointer (V) ? 0 : hb_is_signed (V) ? hb_int_min (V) : (V) -1>
|
||||
struct hb_hashmap_t
|
||||
{
|
||||
HB_NO_COPY_ASSIGN (hb_map_t);
|
||||
hb_map_t () { init (); }
|
||||
~hb_map_t () { fini (); }
|
||||
HB_DELETE_COPY_ASSIGN (hb_hashmap_t);
|
||||
hb_hashmap_t () { init (); }
|
||||
~hb_hashmap_t () { fini (); }
|
||||
|
||||
static_assert (hb_is_integral (K) || hb_is_pointer (K), "");
|
||||
static_assert (hb_is_integral (V) || hb_is_pointer (V), "");
|
||||
|
||||
struct item_t
|
||||
{
|
||||
hb_codepoint_t key;
|
||||
hb_codepoint_t value;
|
||||
K key;
|
||||
V value;
|
||||
uint32_t hash;
|
||||
|
||||
bool is_unused () const { return key == INVALID; }
|
||||
bool is_tombstone () const { return key != INVALID && value == INVALID; }
|
||||
void clear () { key = kINVALID; value = vINVALID; hash = 0; }
|
||||
|
||||
bool operator == (const K &o) { return hb_deref (key) == hb_deref (o); }
|
||||
bool operator == (const item_t &o) { return *this == o.key; }
|
||||
bool is_unused () const { return key == kINVALID; }
|
||||
bool is_tombstone () const { return key != kINVALID && value == vINVALID; }
|
||||
bool is_real () const { return key != kINVALID && value != vINVALID; }
|
||||
hb_pair_t<K, V> get_pair() const { return hb_pair_t<K, V> (key, value); }
|
||||
};
|
||||
|
||||
hb_object_header_t header;
|
||||
@ -82,14 +87,22 @@ struct hb_map_t
|
||||
{
|
||||
free (items);
|
||||
items = nullptr;
|
||||
population = occupancy = 0;
|
||||
}
|
||||
void fini ()
|
||||
{
|
||||
population = occupancy = 0;
|
||||
hb_object_fini (this);
|
||||
fini_shallow ();
|
||||
}
|
||||
|
||||
void reset ()
|
||||
{
|
||||
if (unlikely (hb_object_is_immutable (this)))
|
||||
return;
|
||||
successful = true;
|
||||
clear ();
|
||||
}
|
||||
|
||||
bool in_error () const { return !successful; }
|
||||
|
||||
bool resize ()
|
||||
@ -104,7 +117,8 @@ struct hb_map_t
|
||||
successful = false;
|
||||
return false;
|
||||
}
|
||||
memset (new_items, 0xFF, (size_t) new_size * sizeof (item_t));
|
||||
for (auto &_ : hb_iter (new_items, new_size))
|
||||
_.clear ();
|
||||
|
||||
unsigned int old_size = mask + 1;
|
||||
item_t *old_items = items;
|
||||
@ -118,22 +132,96 @@ struct hb_map_t
|
||||
/* Insert back old items. */
|
||||
if (old_items)
|
||||
for (unsigned int i = 0; i < old_size; i++)
|
||||
if (old_items[i].key != INVALID && old_items[i].value != INVALID)
|
||||
set (old_items[i].key, old_items[i].value);
|
||||
if (old_items[i].is_real ())
|
||||
set_with_hash (old_items[i].key,
|
||||
old_items[i].hash,
|
||||
old_items[i].value);
|
||||
|
||||
free (old_items);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void set (hb_codepoint_t key, hb_codepoint_t value)
|
||||
void set (K key, V value)
|
||||
{
|
||||
set_with_hash (key, hb_hash (key), value);
|
||||
}
|
||||
|
||||
V get (K key) const
|
||||
{
|
||||
if (unlikely (!items)) return vINVALID;
|
||||
unsigned int i = bucket_for (key);
|
||||
return items[i].is_real () && items[i] == key ? items[i].value : vINVALID;
|
||||
}
|
||||
|
||||
void del (K key) { set (key, vINVALID); }
|
||||
|
||||
/* Has interface. */
|
||||
static constexpr V SENTINEL = vINVALID;
|
||||
typedef V value_t;
|
||||
value_t operator [] (K k) const { return get (k); }
|
||||
bool has (K k, V *vp = nullptr) const
|
||||
{
|
||||
V v = (*this)[k];
|
||||
if (vp) *vp = v;
|
||||
return v != SENTINEL;
|
||||
}
|
||||
/* Projection. */
|
||||
V operator () (K k) const { return get (k); }
|
||||
|
||||
void clear ()
|
||||
{
|
||||
if (unlikely (hb_object_is_immutable (this)))
|
||||
return;
|
||||
if (items)
|
||||
for (auto &_ : hb_iter (items, mask + 1))
|
||||
_.clear ();
|
||||
|
||||
population = occupancy = 0;
|
||||
}
|
||||
|
||||
bool is_empty () const { return population == 0; }
|
||||
|
||||
unsigned int get_population () const { return population; }
|
||||
|
||||
/*
|
||||
* Iterator
|
||||
*/
|
||||
auto iter () const HB_AUTO_RETURN
|
||||
(
|
||||
+ hb_array (items, mask ? mask + 1 : 0)
|
||||
| hb_filter (&item_t::is_real)
|
||||
| hb_map (&item_t::get_pair)
|
||||
)
|
||||
auto keys () const HB_AUTO_RETURN
|
||||
(
|
||||
+ hb_array (items, mask ? mask + 1 : 0)
|
||||
| hb_filter (&item_t::is_real)
|
||||
| hb_map (&item_t::key)
|
||||
| hb_map (hb_ridentity)
|
||||
)
|
||||
auto values () const HB_AUTO_RETURN
|
||||
(
|
||||
+ hb_array (items, mask ? mask + 1 : 0)
|
||||
| hb_filter (&item_t::is_real)
|
||||
| hb_map (&item_t::value)
|
||||
| hb_map (hb_ridentity)
|
||||
)
|
||||
|
||||
/* Sink interface. */
|
||||
hb_hashmap_t& operator << (const hb_pair_t<K, V>& v)
|
||||
{ set (v.first, v.second); return *this; }
|
||||
|
||||
protected:
|
||||
|
||||
void set_with_hash (K key, uint32_t hash, V value)
|
||||
{
|
||||
if (unlikely (!successful)) return;
|
||||
if (unlikely (key == INVALID)) return;
|
||||
if (unlikely (key == kINVALID)) return;
|
||||
if ((occupancy + occupancy / 2) >= mask && !resize ()) return;
|
||||
unsigned int i = bucket_for (key);
|
||||
unsigned int i = bucket_for_hash (key, hash);
|
||||
|
||||
if (value == INVALID && items[i].key != key)
|
||||
if (value == vINVALID && items[i].key != key)
|
||||
return; /* Trying to delete non-existent key. */
|
||||
|
||||
if (!items[i].is_unused ())
|
||||
@ -145,55 +233,32 @@ struct hb_map_t
|
||||
|
||||
items[i].key = key;
|
||||
items[i].value = value;
|
||||
items[i].hash = hash;
|
||||
|
||||
occupancy++;
|
||||
if (!items[i].is_tombstone ())
|
||||
population++;
|
||||
|
||||
}
|
||||
hb_codepoint_t get (hb_codepoint_t key) const
|
||||
{
|
||||
if (unlikely (!items)) return INVALID;
|
||||
unsigned int i = bucket_for (key);
|
||||
return items[i].key == key ? items[i].value : INVALID;
|
||||
}
|
||||
|
||||
void del (hb_codepoint_t key) { set (key, INVALID); }
|
||||
|
||||
bool has (hb_codepoint_t key) const
|
||||
{ return get (key) != INVALID; }
|
||||
|
||||
hb_codepoint_t operator [] (unsigned int key) const
|
||||
{ return get (key); }
|
||||
|
||||
static constexpr hb_codepoint_t INVALID = HB_MAP_VALUE_INVALID;
|
||||
|
||||
void clear ()
|
||||
unsigned int bucket_for (K key) const
|
||||
{
|
||||
memset (items, 0xFF, ((size_t) mask + 1) * sizeof (item_t));
|
||||
population = occupancy = 0;
|
||||
return bucket_for_hash (key, hb_hash (key));
|
||||
}
|
||||
|
||||
bool is_empty () const { return population == 0; }
|
||||
|
||||
unsigned int get_population () const { return population; }
|
||||
|
||||
protected:
|
||||
|
||||
unsigned int bucket_for (hb_codepoint_t key) const
|
||||
unsigned int bucket_for_hash (K key, uint32_t hash) const
|
||||
{
|
||||
unsigned int i = Hash (key) % prime;
|
||||
unsigned int i = hash % prime;
|
||||
unsigned int step = 0;
|
||||
unsigned int tombstone = INVALID;
|
||||
unsigned int tombstone = (unsigned) -1;
|
||||
while (!items[i].is_unused ())
|
||||
{
|
||||
if (items[i].key == key)
|
||||
if (items[i].hash == hash && items[i] == key)
|
||||
return i;
|
||||
if (tombstone == INVALID && items[i].is_tombstone ())
|
||||
if (tombstone == (unsigned) -1 && items[i].is_tombstone ())
|
||||
tombstone = i;
|
||||
i = (i + ++step) & mask;
|
||||
}
|
||||
return tombstone == INVALID ? i : tombstone;
|
||||
return tombstone == (unsigned) -1 ? i : tombstone;
|
||||
}
|
||||
|
||||
static unsigned int prime_for (unsigned int shift)
|
||||
@ -248,5 +313,14 @@ struct hb_map_t
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* hb_map_t
|
||||
*/
|
||||
|
||||
struct hb_map_t : hb_hashmap_t<hb_codepoint_t,
|
||||
hb_codepoint_t,
|
||||
HB_MAP_VALUE_INVALID,
|
||||
HB_MAP_VALUE_INVALID> {};
|
||||
|
||||
|
||||
#endif /* HB_MAP_HH */
|
||||
|
||||
410
src/java.desktop/share/native/libharfbuzz/hb-meta.hh
Normal file
410
src/java.desktop/share/native/libharfbuzz/hb-meta.hh
Normal file
@ -0,0 +1,410 @@
|
||||
/*
|
||||
* Copyright © 2018 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_META_HH
|
||||
#define HB_META_HH
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
|
||||
/*
|
||||
* C++ template meta-programming & fundamentals used with them.
|
||||
*/
|
||||
|
||||
/* Void! For when we need a expression-type of void. */
|
||||
struct hb_empty_t {};
|
||||
|
||||
/* https://en.cppreference.com/w/cpp/types/void_t */
|
||||
template<typename... Ts> struct _hb_void_t { typedef void type; };
|
||||
template<typename... Ts> using hb_void_t = typename _hb_void_t<Ts...>::type;
|
||||
|
||||
template<typename Head, typename... Ts> struct _hb_head_t { typedef Head type; };
|
||||
template<typename... Ts> using hb_head_t = typename _hb_head_t<Ts...>::type;
|
||||
|
||||
template <typename T, T v> struct hb_integral_constant { static constexpr T value = v; };
|
||||
template <bool b> using hb_bool_constant = hb_integral_constant<bool, b>;
|
||||
using hb_true_type = hb_bool_constant<true>;
|
||||
using hb_false_type = hb_bool_constant<false>;
|
||||
|
||||
|
||||
/* Basic type SFINAE. */
|
||||
|
||||
template <bool B, typename T = void> struct hb_enable_if {};
|
||||
template <typename T> struct hb_enable_if<true, T> { typedef T type; };
|
||||
#define hb_enable_if(Cond) typename hb_enable_if<(Cond)>::type* = nullptr
|
||||
/* Concepts/Requires alias: */
|
||||
#define hb_requires(Cond) hb_enable_if((Cond))
|
||||
|
||||
template <typename T, typename T2> struct hb_is_same : hb_false_type {};
|
||||
template <typename T> struct hb_is_same<T, T> : hb_true_type {};
|
||||
#define hb_is_same(T, T2) hb_is_same<T, T2>::value
|
||||
|
||||
/* Function overloading SFINAE and priority. */
|
||||
|
||||
#define HB_RETURN(Ret, E) -> hb_head_t<Ret, decltype ((E))> { return (E); }
|
||||
#define HB_AUTO_RETURN(E) -> decltype ((E)) { return (E); }
|
||||
#define HB_VOID_RETURN(E) -> hb_void_t<decltype ((E))> { (E); }
|
||||
|
||||
template <unsigned Pri> struct hb_priority : hb_priority<Pri - 1> {};
|
||||
template <> struct hb_priority<0> {};
|
||||
#define hb_prioritize hb_priority<16> ()
|
||||
|
||||
#define HB_FUNCOBJ(x) static_const x HB_UNUSED
|
||||
|
||||
|
||||
template <typename T> struct hb_type_identity_t { typedef T type; };
|
||||
template <typename T> using hb_type_identity = typename hb_type_identity_t<T>::type;
|
||||
|
||||
struct
|
||||
{
|
||||
template <typename T> constexpr T*
|
||||
operator () (T& arg) const
|
||||
{
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wcast-align"
|
||||
/* https://en.cppreference.com/w/cpp/memory/addressof */
|
||||
return reinterpret_cast<T*> (
|
||||
&const_cast<char&> (
|
||||
reinterpret_cast<const volatile char&> (arg)));
|
||||
#pragma GCC diagnostic pop
|
||||
}
|
||||
}
|
||||
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> 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> 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>;
|
||||
template <typename T> using hb_add_lvalue_reference = decltype (_hb_try_add_lvalue_reference<T> (hb_prioritize));
|
||||
template <typename T> auto _hb_try_add_rvalue_reference (hb_priority<1>) -> hb_type_identity<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> 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>;
|
||||
template <typename T> using hb_add_pointer = decltype (_hb_try_add_pointer<T> (hb_prioritize));
|
||||
#define hb_is_pointer(T) hb_match_pointer<T>::value
|
||||
|
||||
|
||||
/* TODO Add feature-parity to std::decay. */
|
||||
template <typename T> using hb_decay = hb_remove_const<hb_remove_reference<T>>;
|
||||
|
||||
|
||||
template<bool B, class T, class F>
|
||||
struct _hb_conditional { typedef T type; };
|
||||
template<class T, class F>
|
||||
struct _hb_conditional<false, T, F> { typedef F type; };
|
||||
template<bool B, class T, class F>
|
||||
using hb_conditional = typename _hb_conditional<B, T, F>::type;
|
||||
|
||||
|
||||
template <typename From, typename To>
|
||||
struct hb_is_convertible
|
||||
{
|
||||
private:
|
||||
static constexpr bool from_void = hb_is_same (void, hb_decay<From>);
|
||||
static constexpr bool to_void = hb_is_same (void, hb_decay<To> );
|
||||
static constexpr bool either_void = from_void || to_void;
|
||||
static constexpr bool both_void = from_void && to_void;
|
||||
|
||||
static hb_true_type impl2 (hb_conditional<to_void, int, To>);
|
||||
|
||||
template <typename T>
|
||||
static auto impl (hb_priority<1>) -> decltype (impl2 (hb_declval (T)));
|
||||
template <typename T>
|
||||
static hb_false_type impl (hb_priority<0>);
|
||||
public:
|
||||
static constexpr bool value = both_void ||
|
||||
(!either_void &&
|
||||
decltype (impl<hb_conditional<from_void, int, From>> (hb_prioritize))::value);
|
||||
};
|
||||
#define hb_is_convertible(From,To) hb_is_convertible<From, To>::value
|
||||
|
||||
template <typename Base, typename Derived>
|
||||
using hb_is_base_of = hb_is_convertible<hb_decay<Derived> *, hb_decay<Base> *>;
|
||||
#define hb_is_base_of(Base,Derived) hb_is_base_of<Base, Derived>::value
|
||||
|
||||
template <typename From, typename To>
|
||||
using hb_is_cr_convertible = hb_bool_constant<
|
||||
hb_is_same (hb_decay<From>, hb_decay<To>) &&
|
||||
(!hb_is_const (From) || hb_is_const (To)) &&
|
||||
(!hb_is_reference (To) || hb_is_const (To) || hb_is_reference (To))
|
||||
>;
|
||||
#define hb_is_cr_convertible(From,To) hb_is_cr_convertible<From, To>::value
|
||||
|
||||
/* std::move and std::forward */
|
||||
|
||||
template <typename T>
|
||||
static constexpr hb_remove_reference<T>&& hb_move (T&& t) { return (hb_remove_reference<T>&&) (t); }
|
||||
|
||||
template <typename T>
|
||||
static constexpr T&& hb_forward (hb_remove_reference<T>& t) { return (T&&) t; }
|
||||
template <typename T>
|
||||
static constexpr T&& hb_forward (hb_remove_reference<T>&& t) { return (T&&) t; }
|
||||
|
||||
struct
|
||||
{
|
||||
template <typename T> constexpr auto
|
||||
operator () (T&& v) const HB_AUTO_RETURN (hb_forward<T> (v))
|
||||
|
||||
template <typename T> constexpr auto
|
||||
operator () (T *v) const HB_AUTO_RETURN (*v)
|
||||
}
|
||||
HB_FUNCOBJ (hb_deref);
|
||||
|
||||
struct
|
||||
{
|
||||
template <typename T> constexpr auto
|
||||
operator () (T&& v) const HB_AUTO_RETURN (hb_forward<T> (v))
|
||||
|
||||
template <typename T> constexpr auto
|
||||
operator () (T& v) const HB_AUTO_RETURN (hb_addressof (v))
|
||||
}
|
||||
HB_FUNCOBJ (hb_ref);
|
||||
|
||||
template <typename T>
|
||||
struct hb_reference_wrapper
|
||||
{
|
||||
hb_reference_wrapper (T v) : v (v) {}
|
||||
bool operator == (const hb_reference_wrapper& o) const { return v == o.v; }
|
||||
bool operator != (const hb_reference_wrapper& o) const { return v != o.v; }
|
||||
operator T () const { return v; }
|
||||
T get () const { return v; }
|
||||
T v;
|
||||
};
|
||||
template <typename T>
|
||||
struct hb_reference_wrapper<T&>
|
||||
{
|
||||
hb_reference_wrapper (T& v) : v (hb_addressof (v)) {}
|
||||
bool operator == (const hb_reference_wrapper& o) const { return v == o.v; }
|
||||
bool operator != (const hb_reference_wrapper& o) const { return v != o.v; }
|
||||
operator T& () const { return *v; }
|
||||
T& get () const { return *v; }
|
||||
T* v;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
using hb_is_integral = hb_bool_constant<
|
||||
hb_is_same (hb_decay<T>, char) ||
|
||||
hb_is_same (hb_decay<T>, signed char) ||
|
||||
hb_is_same (hb_decay<T>, unsigned char) ||
|
||||
hb_is_same (hb_decay<T>, signed int) ||
|
||||
hb_is_same (hb_decay<T>, unsigned int) ||
|
||||
hb_is_same (hb_decay<T>, signed short) ||
|
||||
hb_is_same (hb_decay<T>, unsigned short) ||
|
||||
hb_is_same (hb_decay<T>, signed long) ||
|
||||
hb_is_same (hb_decay<T>, unsigned long) ||
|
||||
hb_is_same (hb_decay<T>, signed long long) ||
|
||||
hb_is_same (hb_decay<T>, unsigned long long) ||
|
||||
false
|
||||
>;
|
||||
#define hb_is_integral(T) hb_is_integral<T>::value
|
||||
template <typename T>
|
||||
using hb_is_floating_point = hb_bool_constant<
|
||||
hb_is_same (hb_decay<T>, float) ||
|
||||
hb_is_same (hb_decay<T>, double) ||
|
||||
hb_is_same (hb_decay<T>, long double) ||
|
||||
false
|
||||
>;
|
||||
#define hb_is_floating_point(T) hb_is_floating_point<T>::value
|
||||
template <typename T>
|
||||
using hb_is_arithmetic = hb_bool_constant<
|
||||
hb_is_integral (T) ||
|
||||
hb_is_floating_point (T) ||
|
||||
false
|
||||
>;
|
||||
#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>;
|
||||
#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>;
|
||||
#define hb_is_unsigned(T) hb_is_unsigned<T>::value
|
||||
|
||||
template <typename T> struct hb_int_min;
|
||||
template <> struct hb_int_min<char> : hb_integral_constant<char, CHAR_MIN> {};
|
||||
template <> struct hb_int_min<signed char> : hb_integral_constant<signed char, SCHAR_MIN> {};
|
||||
template <> struct hb_int_min<unsigned char> : hb_integral_constant<unsigned char, 0> {};
|
||||
template <> struct hb_int_min<signed short> : hb_integral_constant<signed short, SHRT_MIN> {};
|
||||
template <> struct hb_int_min<unsigned short> : hb_integral_constant<unsigned short, 0> {};
|
||||
template <> struct hb_int_min<signed int> : hb_integral_constant<signed int, INT_MIN> {};
|
||||
template <> struct hb_int_min<unsigned int> : hb_integral_constant<unsigned int, 0> {};
|
||||
template <> struct hb_int_min<signed long> : hb_integral_constant<signed long, LONG_MIN> {};
|
||||
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> {};
|
||||
#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> {};
|
||||
template <> struct hb_int_max<signed char> : hb_integral_constant<signed char, SCHAR_MAX> {};
|
||||
template <> struct hb_int_max<unsigned char> : hb_integral_constant<unsigned char, UCHAR_MAX> {};
|
||||
template <> struct hb_int_max<signed short> : hb_integral_constant<signed short, SHRT_MAX> {};
|
||||
template <> struct hb_int_max<unsigned short> : hb_integral_constant<unsigned short, USHRT_MAX> {};
|
||||
template <> struct hb_int_max<signed int> : hb_integral_constant<signed int, INT_MAX> {};
|
||||
template <> struct hb_int_max<unsigned int> : hb_integral_constant<unsigned int, UINT_MAX> {};
|
||||
template <> struct hb_int_max<signed long> : hb_integral_constant<signed long, LONG_MAX> {};
|
||||
template <> struct hb_int_max<unsigned long> : hb_integral_constant<unsigned long, ULONG_MAX> {};
|
||||
template <> struct hb_int_max<signed long long> : hb_integral_constant<signed long long, LLONG_MAX> {};
|
||||
template <> struct hb_int_max<unsigned long long> : hb_integral_constant<unsigned long long, ULLONG_MAX> {};
|
||||
#define hb_int_max(T) hb_int_max<T>::value
|
||||
|
||||
|
||||
|
||||
template <typename T, typename>
|
||||
struct _hb_is_destructible : hb_false_type {};
|
||||
template <typename T>
|
||||
struct _hb_is_destructible<T, hb_void_t<decltype (hb_declval (T).~T ())>> : hb_true_type {};
|
||||
template <typename T>
|
||||
using hb_is_destructible = _hb_is_destructible<T, void>;
|
||||
#define hb_is_destructible(T) hb_is_destructible<T>::value
|
||||
|
||||
template <typename T, typename, typename ...Ts>
|
||||
struct _hb_is_constructible : hb_false_type {};
|
||||
template <typename T, typename ...Ts>
|
||||
struct _hb_is_constructible<T, hb_void_t<decltype (T (hb_declval (Ts)...))>, Ts...> : hb_true_type {};
|
||||
template <typename T, typename ...Ts>
|
||||
using hb_is_constructible = _hb_is_constructible<T, void, Ts...>;
|
||||
#define hb_is_constructible(...) hb_is_constructible<__VA_ARGS__>::value
|
||||
|
||||
template <typename T>
|
||||
using hb_is_default_constructible = hb_is_constructible<T>;
|
||||
#define hb_is_default_constructible(T) hb_is_default_constructible<T>::value
|
||||
|
||||
template <typename T>
|
||||
using hb_is_copy_constructible = hb_is_constructible<T, hb_add_lvalue_reference<hb_add_const<T>>>;
|
||||
#define hb_is_copy_constructible(T) hb_is_copy_constructible<T>::value
|
||||
|
||||
template <typename T>
|
||||
using hb_is_move_constructible = hb_is_constructible<T, hb_add_rvalue_reference<hb_add_const<T>>>;
|
||||
#define hb_is_move_constructible(T) hb_is_move_constructible<T>::value
|
||||
|
||||
template <typename T, typename U, typename>
|
||||
struct _hb_is_assignable : hb_false_type {};
|
||||
template <typename T, typename U>
|
||||
struct _hb_is_assignable<T, U, hb_void_t<decltype (hb_declval (T) = hb_declval (U))>> : hb_true_type {};
|
||||
template <typename T, typename U>
|
||||
using hb_is_assignable = _hb_is_assignable<T, U, void>;
|
||||
#define hb_is_assignable(T,U) hb_is_assignable<T, U>::value
|
||||
|
||||
template <typename T>
|
||||
using hb_is_copy_assignable = hb_is_assignable<hb_add_lvalue_reference<T>,
|
||||
hb_add_lvalue_reference<hb_add_const<T>>>;
|
||||
#define hb_is_copy_assignable(T) hb_is_copy_assignable<T>::value
|
||||
|
||||
template <typename T>
|
||||
using hb_is_move_assignable = hb_is_assignable<hb_add_lvalue_reference<T>,
|
||||
hb_add_rvalue_reference<T>>;
|
||||
#define hb_is_move_assignable(T) hb_is_move_assignable<T>::value
|
||||
|
||||
/* Trivial versions. */
|
||||
|
||||
template <typename T> union hb_trivial { T value; };
|
||||
|
||||
template <typename T>
|
||||
using hb_is_trivially_destructible= hb_is_destructible<hb_trivial<T>>;
|
||||
#define hb_is_trivially_destructible(T) hb_is_trivially_destructible<T>::value
|
||||
|
||||
/* Don't know how to do the following. */
|
||||
//template <typename T, typename ...Ts>
|
||||
//using hb_is_trivially_constructible= hb_is_constructible<hb_trivial<T>, hb_trivial<Ts>...>;
|
||||
//#define hb_is_trivially_constructible(...) hb_is_trivially_constructible<__VA_ARGS__>::value
|
||||
|
||||
template <typename T>
|
||||
using hb_is_trivially_default_constructible= hb_is_default_constructible<hb_trivial<T>>;
|
||||
#define hb_is_trivially_default_constructible(T) hb_is_trivially_default_constructible<T>::value
|
||||
|
||||
template <typename T>
|
||||
using hb_is_trivially_copy_constructible= hb_is_copy_constructible<hb_trivial<T>>;
|
||||
#define hb_is_trivially_copy_constructible(T) hb_is_trivially_copy_constructible<T>::value
|
||||
|
||||
template <typename T>
|
||||
using hb_is_trivially_move_constructible= hb_is_move_constructible<hb_trivial<T>>;
|
||||
#define hb_is_trivially_move_constructible(T) hb_is_trivially_move_constructible<T>::value
|
||||
|
||||
/* Don't know how to do the following. */
|
||||
//template <typename T, typename U>
|
||||
//using hb_is_trivially_assignable= hb_is_assignable<hb_trivial<T>, hb_trivial<U>>;
|
||||
//#define hb_is_trivially_assignable(T,U) hb_is_trivially_assignable<T, U>::value
|
||||
|
||||
template <typename T>
|
||||
using hb_is_trivially_copy_assignable= hb_is_copy_assignable<hb_trivial<T>>;
|
||||
#define hb_is_trivially_copy_assignable(T) hb_is_trivially_copy_assignable<T>::value
|
||||
|
||||
template <typename T>
|
||||
using hb_is_trivially_move_assignable= hb_is_move_assignable<hb_trivial<T>>;
|
||||
#define hb_is_trivially_move_assignable(T) hb_is_trivially_move_assignable<T>::value
|
||||
|
||||
template <typename T>
|
||||
using hb_is_trivially_copyable= hb_bool_constant<
|
||||
hb_is_trivially_destructible (T) &&
|
||||
(!hb_is_move_assignable (T) || hb_is_trivially_move_assignable (T)) &&
|
||||
(!hb_is_move_constructible (T) || hb_is_trivially_move_constructible (T)) &&
|
||||
(!hb_is_copy_assignable (T) || hb_is_trivially_copy_assignable (T)) &&
|
||||
(!hb_is_copy_constructible (T) || hb_is_trivially_copy_constructible (T)) &&
|
||||
true
|
||||
>;
|
||||
#define hb_is_trivially_copyable(T) hb_is_trivially_copyable<T>::value
|
||||
|
||||
template <typename T>
|
||||
using hb_is_trivial= hb_bool_constant<
|
||||
hb_is_trivially_copyable (T) &&
|
||||
hb_is_trivially_default_constructible (T)
|
||||
>;
|
||||
#define hb_is_trivial(T) hb_is_trivial<T>::value
|
||||
|
||||
/* hb_unwrap_type (T)
|
||||
* If T has no T::type, returns T. Otherwise calls itself on T::type recursively.
|
||||
*/
|
||||
|
||||
template <typename T, typename>
|
||||
struct _hb_unwrap_type : hb_type_identity_t<T> {};
|
||||
template <typename T>
|
||||
struct _hb_unwrap_type<T, hb_void_t<typename T::type>> : _hb_unwrap_type<typename T::type, void> {};
|
||||
template <typename T>
|
||||
using hb_unwrap_type = _hb_unwrap_type<T, void>;
|
||||
#define hb_unwrap_type(T) typename hb_unwrap_type<T>::type
|
||||
|
||||
#endif /* HB_META_HH */
|
||||
@ -48,21 +48,6 @@
|
||||
/* Defined externally, i.e. in config.h; must have typedef'ed hb_mutex_impl_t as well. */
|
||||
|
||||
|
||||
#elif !defined(HB_NO_MT) && defined(_WIN32)
|
||||
|
||||
#include <windows.h>
|
||||
typedef CRITICAL_SECTION hb_mutex_impl_t;
|
||||
#define HB_MUTEX_IMPL_INIT {0}
|
||||
#if defined(WINAPI_FAMILY) && (WINAPI_FAMILY==WINAPI_FAMILY_PC_APP || WINAPI_FAMILY==WINAPI_FAMILY_PHONE_APP)
|
||||
#define hb_mutex_impl_init(M) InitializeCriticalSectionEx (M, 0, 0)
|
||||
#else
|
||||
#define hb_mutex_impl_init(M) InitializeCriticalSection (M)
|
||||
#endif
|
||||
#define hb_mutex_impl_lock(M) EnterCriticalSection (M)
|
||||
#define hb_mutex_impl_unlock(M) LeaveCriticalSection (M)
|
||||
#define hb_mutex_impl_finish(M) DeleteCriticalSection (M)
|
||||
|
||||
|
||||
#elif !defined(HB_NO_MT) && (defined(HAVE_PTHREAD) || defined(__APPLE__))
|
||||
|
||||
#include <pthread.h>
|
||||
@ -74,6 +59,20 @@ typedef pthread_mutex_t hb_mutex_impl_t;
|
||||
#define hb_mutex_impl_finish(M) pthread_mutex_destroy (M)
|
||||
|
||||
|
||||
#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
|
||||
#define hb_mutex_impl_init(M) InitializeCriticalSection (M)
|
||||
#endif
|
||||
#define hb_mutex_impl_lock(M) EnterCriticalSection (M)
|
||||
#define hb_mutex_impl_unlock(M) LeaveCriticalSection (M)
|
||||
#define hb_mutex_impl_finish(M) DeleteCriticalSection (M)
|
||||
|
||||
|
||||
#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
|
||||
|
||||
#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD)
|
||||
@ -92,25 +91,7 @@ typedef volatile int hb_mutex_impl_t;
|
||||
#define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END
|
||||
|
||||
|
||||
#elif !defined(HB_NO_MT)
|
||||
|
||||
#if defined(HAVE_SCHED_H) && defined(HAVE_SCHED_YIELD)
|
||||
# include <sched.h>
|
||||
# define HB_SCHED_YIELD() sched_yield ()
|
||||
#else
|
||||
# define HB_SCHED_YIELD() HB_STMT_START {} HB_STMT_END
|
||||
#endif
|
||||
|
||||
#define HB_MUTEX_INT_NIL 1 /* Warn that fallback implementation is in use. */
|
||||
typedef volatile int hb_mutex_impl_t;
|
||||
#define HB_MUTEX_IMPL_INIT 0
|
||||
#define hb_mutex_impl_init(M) *(M) = 0
|
||||
#define hb_mutex_impl_lock(M) HB_STMT_START { while (*(M)) HB_SCHED_YIELD (); (*(M))++; } HB_STMT_END
|
||||
#define hb_mutex_impl_unlock(M) (*(M))--;
|
||||
#define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END
|
||||
|
||||
|
||||
#else /* HB_NO_MT */
|
||||
#elif defined(HB_NO_MT)
|
||||
|
||||
typedef int hb_mutex_impl_t;
|
||||
#define HB_MUTEX_IMPL_INIT 0
|
||||
@ -120,6 +101,11 @@ typedef int hb_mutex_impl_t;
|
||||
#define hb_mutex_impl_finish(M) HB_STMT_START {} HB_STMT_END
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#error "Could not find any system to define mutex macros."
|
||||
#error "Check hb-mutex.hh for possible resolutions."
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@ -127,8 +113,6 @@ typedef int hb_mutex_impl_t;
|
||||
|
||||
struct hb_mutex_t
|
||||
{
|
||||
/* TODO Add tracing. */
|
||||
|
||||
hb_mutex_impl_t m;
|
||||
|
||||
void init () { hb_mutex_impl_init (&m); }
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
#define HB_NULL_HH
|
||||
|
||||
#include "hb.hh"
|
||||
#include "hb-meta.hh"
|
||||
|
||||
|
||||
/*
|
||||
@ -36,7 +37,7 @@
|
||||
|
||||
/* Global nul-content Null pool. Enlarge as necessary. */
|
||||
|
||||
#define HB_NULL_POOL_SIZE 9880
|
||||
#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). */
|
||||
@ -45,18 +46,13 @@
|
||||
* https://stackoverflow.com/questions/7776448/sfinae-tried-with-bool-gives-compiler-error-template-argument-tvalue-invol
|
||||
*/
|
||||
|
||||
template<bool> struct _hb_bool_type {};
|
||||
|
||||
template <typename T, typename B>
|
||||
struct _hb_null_size
|
||||
{ enum { value = sizeof (T) }; };
|
||||
template <typename T, typename>
|
||||
struct _hb_null_size : hb_integral_constant<unsigned, sizeof (T)> {};
|
||||
template <typename T>
|
||||
struct _hb_null_size<T, _hb_bool_type<(bool) (1 + (unsigned int) T::min_size)> >
|
||||
{ enum { value = T::null_size }; };
|
||||
struct _hb_null_size<T, hb_void_t<decltype (T::min_size)>> : hb_integral_constant<unsigned, T::null_size> {};
|
||||
|
||||
template <typename T>
|
||||
struct hb_null_size
|
||||
{ enum { value = _hb_null_size<T, _hb_bool_type<true> >::value }; };
|
||||
using hb_null_size = _hb_null_size<T, void>;
|
||||
#define hb_null_size(T) hb_null_size<T>::value
|
||||
|
||||
/* These doesn't belong here, but since is copy/paste from above, put it here. */
|
||||
@ -64,56 +60,36 @@ struct hb_null_size
|
||||
/* hb_static_size (T)
|
||||
* Returns T::static_size if T::min_size is defined, or sizeof (T) otherwise. */
|
||||
|
||||
template <typename T, typename B>
|
||||
struct _hb_static_size
|
||||
{ enum { value = sizeof (T) }; };
|
||||
template <typename T, typename>
|
||||
struct _hb_static_size : hb_integral_constant<unsigned, sizeof (T)> {};
|
||||
template <typename T>
|
||||
struct _hb_static_size<T, _hb_bool_type<(bool) (1 + (unsigned int) T::min_size)> >
|
||||
{ enum { value = T::static_size }; };
|
||||
|
||||
struct _hb_static_size<T, hb_void_t<decltype (T::min_size)>> : hb_integral_constant<unsigned, T::static_size> {};
|
||||
template <typename T>
|
||||
struct hb_static_size
|
||||
{ enum { value = _hb_static_size<T, _hb_bool_type<true> >::value }; };
|
||||
using hb_static_size = _hb_static_size<T, void>;
|
||||
#define hb_static_size(T) hb_static_size<T>::value
|
||||
|
||||
|
||||
/* hb_assign (obj, value)
|
||||
* Calls obj.set (value) if obj.min_size is defined and value has different type
|
||||
* from obj, or obj = v otherwise. */
|
||||
|
||||
template <typename T, typename V, typename B>
|
||||
struct _hb_assign
|
||||
{ static inline void value (T &o, const V v) { o = v; } };
|
||||
template <typename T, typename V>
|
||||
struct _hb_assign<T, V, _hb_bool_type<(bool) (1 + (unsigned int) T::min_size)> >
|
||||
{ static inline void value (T &o, const V v) { o.set (v); } };
|
||||
template <typename T>
|
||||
struct _hb_assign<T, T, _hb_bool_type<(bool) (1 + (unsigned int) T::min_size)> >
|
||||
{ static inline void value (T &o, const T v) { o = v; } };
|
||||
|
||||
template <typename T, typename V>
|
||||
static inline void hb_assign (T &o, const V v)
|
||||
{ _hb_assign<T, V, _hb_bool_type<true> >::value (o, v); }
|
||||
|
||||
|
||||
/*
|
||||
* Null()
|
||||
*/
|
||||
|
||||
extern HB_INTERNAL
|
||||
hb_vector_size_impl_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (hb_vector_size_impl_t) - 1) / sizeof (hb_vector_size_impl_t)];
|
||||
uint64_t const _hb_NullPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)];
|
||||
|
||||
/* Generic nul-content Null objects. */
|
||||
template <typename Type>
|
||||
static inline Type const & Null () {
|
||||
static_assert (hb_null_size (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
|
||||
return *reinterpret_cast<Type const *> (_hb_NullPool);
|
||||
}
|
||||
struct Null {
|
||||
static Type const & get_null ()
|
||||
{
|
||||
static_assert (hb_null_size (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
|
||||
return *reinterpret_cast<Type const *> (_hb_NullPool);
|
||||
}
|
||||
};
|
||||
template <typename QType>
|
||||
struct NullHelper
|
||||
{
|
||||
typedef typename hb_remove_const (typename hb_remove_reference (QType)) Type;
|
||||
static const Type & get_null () { return Null<Type> (); }
|
||||
typedef hb_remove_const<hb_remove_reference<QType>> Type;
|
||||
static const Type & get_null () { return Null<Type>::get_null (); }
|
||||
};
|
||||
#define Null(Type) NullHelper<Type>::get_null ()
|
||||
|
||||
@ -122,11 +98,13 @@ struct NullHelper
|
||||
} /* Close namespace. */ \
|
||||
extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::null_size]; \
|
||||
template <> \
|
||||
/*static*/ inline const Namespace::Type& Null<Namespace::Type> () { \
|
||||
return *reinterpret_cast<const Namespace::Type *> (_hb_Null_##Namespace##_##Type); \
|
||||
} \
|
||||
struct Null<Namespace::Type> { \
|
||||
static Namespace::Type const & get_null () { \
|
||||
return *reinterpret_cast<const Namespace::Type *> (_hb_Null_##Namespace##_##Type); \
|
||||
} \
|
||||
}; \
|
||||
namespace Namespace { \
|
||||
static_assert (true, "Just so we take semicolon after.")
|
||||
static_assert (true, "") /* Require semicolon after. */
|
||||
#define DEFINE_NULL_NAMESPACE_BYTES(Namespace, Type) \
|
||||
const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::null_size]
|
||||
|
||||
@ -134,10 +112,12 @@ struct NullHelper
|
||||
#define DECLARE_NULL_INSTANCE(Type) \
|
||||
extern HB_INTERNAL const Type _hb_Null_##Type; \
|
||||
template <> \
|
||||
/*static*/ inline const Type& Null<Type> () { \
|
||||
return _hb_Null_##Type; \
|
||||
} \
|
||||
static_assert (true, "Just so we take semicolon after.")
|
||||
struct Null<Type> { \
|
||||
static Type const & get_null () { \
|
||||
return _hb_Null_##Type; \
|
||||
} \
|
||||
}; \
|
||||
static_assert (true, "") /* Require semicolon after. */
|
||||
#define DEFINE_NULL_INSTANCE(Type) \
|
||||
const Type _hb_Null_##Type
|
||||
|
||||
@ -148,31 +128,31 @@ static_assert (true, "Just so we take semicolon after.")
|
||||
* causing bad memory access. So, races there are not actually introducing incorrectness
|
||||
* in the code. Has ~12kb binary size overhead to have it, also clang build fails with it. */
|
||||
extern HB_INTERNAL
|
||||
/*thread_local*/ hb_vector_size_impl_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (hb_vector_size_impl_t) - 1) / sizeof (hb_vector_size_impl_t)];
|
||||
/*thread_local*/ uint64_t _hb_CrapPool[(HB_NULL_POOL_SIZE + sizeof (uint64_t) - 1) / sizeof (uint64_t)];
|
||||
|
||||
/* CRAP pool: Common Region for Access Protection. */
|
||||
template <typename Type>
|
||||
static inline Type& Crap () {
|
||||
static_assert (hb_null_size (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
|
||||
Type *obj = reinterpret_cast<Type *> (_hb_CrapPool);
|
||||
memcpy (obj, &Null(Type), sizeof (*obj));
|
||||
memcpy (obj, &Null (Type), sizeof (*obj));
|
||||
return *obj;
|
||||
}
|
||||
template <typename QType>
|
||||
struct CrapHelper
|
||||
{
|
||||
typedef typename hb_remove_const (typename hb_remove_reference (QType)) Type;
|
||||
typedef hb_remove_const<hb_remove_reference<QType>> Type;
|
||||
static Type & get_crap () { return Crap<Type> (); }
|
||||
};
|
||||
#define Crap(Type) CrapHelper<Type>::get_crap ()
|
||||
|
||||
template <typename Type>
|
||||
struct CrapOrNullHelper {
|
||||
static Type & get () { return Crap(Type); }
|
||||
static Type & get () { return Crap (Type); }
|
||||
};
|
||||
template <typename Type>
|
||||
struct CrapOrNullHelper<const Type> {
|
||||
static const Type & get () { return Null(Type); }
|
||||
static const Type & get () { return Null (Type); }
|
||||
};
|
||||
#define CrapOrNull(Type) CrapOrNullHelper<Type>::get ()
|
||||
|
||||
@ -184,7 +164,7 @@ struct CrapOrNullHelper<const Type> {
|
||||
template <typename P>
|
||||
struct hb_nonnull_ptr_t
|
||||
{
|
||||
typedef typename hb_remove_pointer (P) T;
|
||||
typedef hb_remove_pointer<P> T;
|
||||
|
||||
hb_nonnull_ptr_t (T *v_ = nullptr) : v (v_) {}
|
||||
T * operator = (T *v_) { return v = v_; }
|
||||
@ -194,7 +174,7 @@ struct hb_nonnull_ptr_t
|
||||
/* Only auto-cast to const types. */
|
||||
template <typename C> operator const C * () const { return get (); }
|
||||
operator const char * () const { return (const char *) get (); }
|
||||
T * get () const { return v ? v : const_cast<T *> (&Null(T)); }
|
||||
T * get () const { return v ? v : const_cast<T *> (&Null (T)); }
|
||||
T * get_raw () const { return v; }
|
||||
|
||||
T *v;
|
||||
|
||||
237
src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh
Normal file
237
src/java.desktop/share/native/libharfbuzz/hb-number-parser.hh
Normal file
@ -0,0 +1,237 @@
|
||||
|
||||
#line 1 "hb-number-parser.rl"
|
||||
/*
|
||||
* Copyright © 2019 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HB_NUMBER_PARSER_HH
|
||||
#define HB_NUMBER_PARSER_HH
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
|
||||
#line 35 "hb-number-parser.hh"
|
||||
static const unsigned char _double_parser_trans_keys[] = {
|
||||
0u, 0u, 43u, 57u, 46u, 57u, 48u, 57u, 43u, 57u, 48u, 57u, 48u, 101u, 48u, 57u,
|
||||
46u, 101u, 0
|
||||
};
|
||||
|
||||
static const char _double_parser_key_spans[] = {
|
||||
0, 15, 12, 10, 15, 10, 54, 10,
|
||||
56
|
||||
};
|
||||
|
||||
static const unsigned char _double_parser_index_offsets[] = {
|
||||
0, 0, 16, 29, 40, 56, 67, 122,
|
||||
133
|
||||
};
|
||||
|
||||
static const char _double_parser_indicies[] = {
|
||||
0, 1, 2, 3, 1, 4, 4,
|
||||
4, 4, 4, 4, 4, 4, 4, 4,
|
||||
1, 3, 1, 4, 4, 4, 4, 4,
|
||||
4, 4, 4, 4, 4, 1, 5, 5,
|
||||
5, 5, 5, 5, 5, 5, 5, 5,
|
||||
1, 6, 1, 7, 1, 1, 8, 8,
|
||||
8, 8, 8, 8, 8, 8, 8, 8,
|
||||
1, 8, 8, 8, 8, 8, 8, 8,
|
||||
8, 8, 8, 1, 5, 5, 5, 5,
|
||||
5, 5, 5, 5, 5, 5, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 9, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 9, 1, 8, 8, 8, 8, 8,
|
||||
8, 8, 8, 8, 8, 1, 3, 1,
|
||||
4, 4, 4, 4, 4, 4, 4, 4,
|
||||
4, 4, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 9, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 9, 1, 0
|
||||
};
|
||||
|
||||
static const char _double_parser_trans_targs[] = {
|
||||
2, 0, 2, 3, 8, 6, 5, 5,
|
||||
7, 4
|
||||
};
|
||||
|
||||
static const char _double_parser_trans_actions[] = {
|
||||
0, 0, 1, 0, 2, 3, 0, 4,
|
||||
5, 0
|
||||
};
|
||||
|
||||
static const int double_parser_start = 1;
|
||||
static const int double_parser_first_final = 6;
|
||||
static const int double_parser_error = 0;
|
||||
|
||||
static const int double_parser_en_main = 1;
|
||||
|
||||
|
||||
#line 68 "hb-number-parser.rl"
|
||||
|
||||
|
||||
/* Works only for n < 512 */
|
||||
static inline double
|
||||
_pow10 (unsigned exponent)
|
||||
{
|
||||
static const double _powers_of_10[] =
|
||||
{
|
||||
1.0e+256,
|
||||
1.0e+128,
|
||||
1.0e+64,
|
||||
1.0e+32,
|
||||
1.0e+16,
|
||||
1.0e+8,
|
||||
10000.,
|
||||
100.,
|
||||
10.
|
||||
};
|
||||
unsigned mask = 1 << (ARRAY_LENGTH (_powers_of_10) - 1);
|
||||
double result = 1;
|
||||
for (const double *power = _powers_of_10; mask; ++power, mask >>= 1)
|
||||
if (exponent & mask) result *= *power;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* a variant of strtod that also gets end of buffer in its second argument */
|
||||
static inline double
|
||||
strtod_rl (const char *p, const char **end_ptr /* IN/OUT */)
|
||||
{
|
||||
double value = 0;
|
||||
double frac = 0;
|
||||
double frac_count = 0;
|
||||
unsigned exp = 0;
|
||||
bool neg = false, exp_neg = false, exp_overflow = false;
|
||||
const unsigned long long MAX_FRACT = 0xFFFFFFFFFFFFFull; /* 2^52-1 */
|
||||
const unsigned MAX_EXP = 0x7FFu; /* 2^11-1 */
|
||||
|
||||
const char *pe = *end_ptr;
|
||||
while (p < pe && ISSPACE (*p))
|
||||
p++;
|
||||
|
||||
int cs;
|
||||
|
||||
#line 139 "hb-number-parser.hh"
|
||||
{
|
||||
cs = double_parser_start;
|
||||
}
|
||||
|
||||
#line 144 "hb-number-parser.hh"
|
||||
{
|
||||
int _slen;
|
||||
int _trans;
|
||||
const unsigned char *_keys;
|
||||
const char *_inds;
|
||||
if ( p == pe )
|
||||
goto _test_eof;
|
||||
if ( cs == 0 )
|
||||
goto _out;
|
||||
_resume:
|
||||
_keys = _double_parser_trans_keys + (cs<<1);
|
||||
_inds = _double_parser_indicies + _double_parser_index_offsets[cs];
|
||||
|
||||
_slen = _double_parser_key_spans[cs];
|
||||
_trans = _inds[ _slen > 0 && _keys[0] <=(*p) &&
|
||||
(*p) <= _keys[1] ?
|
||||
(*p) - _keys[0] : _slen ];
|
||||
|
||||
cs = _double_parser_trans_targs[_trans];
|
||||
|
||||
if ( _double_parser_trans_actions[_trans] == 0 )
|
||||
goto _again;
|
||||
|
||||
switch ( _double_parser_trans_actions[_trans] ) {
|
||||
case 1:
|
||||
#line 37 "hb-number-parser.rl"
|
||||
{ neg = true; }
|
||||
break;
|
||||
case 4:
|
||||
#line 38 "hb-number-parser.rl"
|
||||
{ exp_neg = true; }
|
||||
break;
|
||||
case 2:
|
||||
#line 40 "hb-number-parser.rl"
|
||||
{
|
||||
value = value * 10. + ((*p) - '0');
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
#line 43 "hb-number-parser.rl"
|
||||
{
|
||||
if (likely (frac <= MAX_FRACT / 10))
|
||||
{
|
||||
frac = frac * 10. + ((*p) - '0');
|
||||
++frac_count;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
#line 50 "hb-number-parser.rl"
|
||||
{
|
||||
if (likely (exp * 10 + ((*p) - '0') <= MAX_EXP))
|
||||
exp = exp * 10 + ((*p) - '0');
|
||||
else
|
||||
exp_overflow = true;
|
||||
}
|
||||
break;
|
||||
#line 202 "hb-number-parser.hh"
|
||||
}
|
||||
|
||||
_again:
|
||||
if ( cs == 0 )
|
||||
goto _out;
|
||||
if ( ++p != pe )
|
||||
goto _resume;
|
||||
_test_eof: {}
|
||||
_out: {}
|
||||
}
|
||||
|
||||
#line 113 "hb-number-parser.rl"
|
||||
|
||||
|
||||
*end_ptr = p;
|
||||
|
||||
if (frac_count) value += frac / _pow10 (frac_count);
|
||||
if (neg) value *= -1.;
|
||||
|
||||
if (unlikely (exp_overflow))
|
||||
{
|
||||
if (value == 0) return value;
|
||||
if (exp_neg) return neg ? -DBL_MIN : DBL_MIN;
|
||||
else return neg ? -DBL_MAX : DBL_MAX;
|
||||
}
|
||||
|
||||
if (exp)
|
||||
{
|
||||
if (exp_neg) value /= _pow10 (exp);
|
||||
else value *= _pow10 (exp);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
#endif /* HB_NUMBER_PARSER_HH */
|
||||
80
src/java.desktop/share/native/libharfbuzz/hb-number.cc
Normal file
80
src/java.desktop/share/native/libharfbuzz/hb-number.cc
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright © 2019 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
#include "hb-machinery.hh"
|
||||
#include "hb-number.hh"
|
||||
#include "hb-number-parser.hh"
|
||||
|
||||
template<typename T, typename Func>
|
||||
static bool
|
||||
_parse_number (const char **pp, const char *end, T *pv,
|
||||
bool whole_buffer, Func f)
|
||||
{
|
||||
char buf[32];
|
||||
unsigned len = hb_min (ARRAY_LENGTH (buf) - 1, (unsigned) (end - *pp));
|
||||
strncpy (buf, *pp, len);
|
||||
buf[len] = '\0';
|
||||
|
||||
char *p = buf;
|
||||
char *pend = p;
|
||||
|
||||
errno = 0;
|
||||
*pv = f (p, &pend);
|
||||
if (unlikely (errno || p == pend ||
|
||||
/* Check if consumed whole buffer if is requested */
|
||||
(whole_buffer && pend - p != end - *pp)))
|
||||
return false;
|
||||
|
||||
*pp += pend - p;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
hb_parse_int (const char **pp, const char *end, int *pv, bool whole_buffer)
|
||||
{
|
||||
return _parse_number<int> (pp, end, pv, whole_buffer,
|
||||
[] (const char *p, char **end)
|
||||
{ return strtol (p, end, 10); });
|
||||
}
|
||||
|
||||
bool
|
||||
hb_parse_uint (const char **pp, const char *end, unsigned *pv,
|
||||
bool whole_buffer, int base)
|
||||
{
|
||||
return _parse_number<unsigned> (pp, end, pv, whole_buffer,
|
||||
[base] (const char *p, char **end)
|
||||
{ return strtoul (p, end, base); });
|
||||
}
|
||||
|
||||
bool
|
||||
hb_parse_double (const char **pp, const char *end, double *pv, bool whole_buffer)
|
||||
{
|
||||
const char *pend = end;
|
||||
*pv = strtod_rl (*pp, &pend);
|
||||
if (unlikely (*pp == pend)) return false;
|
||||
*pp = pend;
|
||||
return !whole_buffer || end == pend;
|
||||
}
|
||||
41
src/java.desktop/share/native/libharfbuzz/hb-number.hh
Normal file
41
src/java.desktop/share/native/libharfbuzz/hb-number.hh
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright © 2019 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
* Permission is hereby granted, without written agreement and without
|
||||
* license or royalty fees, to use, copy, modify, and distribute this
|
||||
* software and its documentation for any purpose, provided that the
|
||||
* above copyright notice and the following two paragraphs appear in
|
||||
* all copies of this software.
|
||||
*
|
||||
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
|
||||
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
|
||||
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
|
||||
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HB_NUMBER_HH
|
||||
#define HB_NUMBER_HH
|
||||
|
||||
HB_INTERNAL bool
|
||||
hb_parse_int (const char **pp, const char *end, int *pv,
|
||||
bool whole_buffer = false);
|
||||
|
||||
HB_INTERNAL bool
|
||||
hb_parse_uint (const char **pp, const char *end, unsigned int *pv,
|
||||
bool whole_buffer = false, int base = 10);
|
||||
|
||||
HB_INTERNAL bool
|
||||
hb_parse_double (const char **pp, const char *end, double *pv,
|
||||
bool whole_buffer = false);
|
||||
|
||||
#endif /* HB_NUMBER_HH */
|
||||
@ -168,8 +168,8 @@ struct hb_user_data_array_t
|
||||
void *data;
|
||||
hb_destroy_func_t destroy;
|
||||
|
||||
bool operator == (hb_user_data_key_t *other_key) const { return key == other_key; }
|
||||
bool operator == (hb_user_data_item_t &other) const { return key == other.key; }
|
||||
bool operator == (const hb_user_data_key_t *other_key) const { return key == other_key; }
|
||||
bool operator == (const hb_user_data_item_t &other) const { return key == other.key; }
|
||||
|
||||
void fini () { if (destroy) destroy (data); }
|
||||
};
|
||||
|
||||
@ -56,7 +56,7 @@ typedef struct TableRecord
|
||||
{
|
||||
int cmp (Tag t) const { return -t.cmp (tag); }
|
||||
|
||||
static int cmp (const void *pa, const void *pb)
|
||||
HB_INTERNAL static int cmp (const void *pa, const void *pb)
|
||||
{
|
||||
const TableRecord *a = (const TableRecord *) pa;
|
||||
const TableRecord *b = (const TableRecord *) pb;
|
||||
@ -86,27 +86,22 @@ typedef struct OffsetTable
|
||||
const TableRecord& get_table (unsigned int i) const
|
||||
{ return tables[i]; }
|
||||
unsigned int get_table_tags (unsigned int start_offset,
|
||||
unsigned int *table_count, /* IN/OUT */
|
||||
hb_tag_t *table_tags /* OUT */) const
|
||||
unsigned int *table_count, /* IN/OUT */
|
||||
hb_tag_t *table_tags /* OUT */) const
|
||||
{
|
||||
if (table_count)
|
||||
{
|
||||
if (start_offset >= tables.len)
|
||||
*table_count = 0;
|
||||
else
|
||||
*table_count = MIN<unsigned int> (*table_count, tables.len - start_offset);
|
||||
|
||||
const TableRecord *sub_tables = tables.arrayZ + start_offset;
|
||||
unsigned int count = *table_count;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
table_tags[i] = sub_tables[i].tag;
|
||||
+ tables.sub_array (start_offset, table_count)
|
||||
| hb_map (&TableRecord::tag)
|
||||
| hb_sink (hb_array (table_tags, *table_count))
|
||||
;
|
||||
}
|
||||
return tables.len;
|
||||
}
|
||||
bool find_table_index (hb_tag_t tag, unsigned int *table_index) const
|
||||
{
|
||||
Tag t;
|
||||
t.set (tag);
|
||||
t = tag;
|
||||
return tables.bfind (t, table_index, HB_BFIND_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
|
||||
}
|
||||
const TableRecord& get_table_by_tag (hb_tag_t tag) const
|
||||
@ -127,7 +122,7 @@ typedef struct OffsetTable
|
||||
/* Alloc 12 for the OTHeader. */
|
||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||
/* Write sfntVersion (bytes 0..3). */
|
||||
sfnt_version.set (sfnt_tag);
|
||||
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);
|
||||
@ -140,15 +135,16 @@ typedef struct OffsetTable
|
||||
{
|
||||
TableRecord &rec = tables.arrayZ[i];
|
||||
hb_blob_t *blob = items[i].blob;
|
||||
rec.tag.set (items[i].tag);
|
||||
rec.length.set (hb_blob_get_length (blob));
|
||||
rec.tag = items[i].tag;
|
||||
rec.length = blob->length;
|
||||
rec.offset.serialize (c, this);
|
||||
|
||||
/* Allocate room for the table and copy it. */
|
||||
char *start = (char *) c->allocate_size<void> (rec.length);
|
||||
if (unlikely (!start)) {return false;}
|
||||
if (unlikely (!start)) return false;
|
||||
|
||||
memcpy (start, hb_blob_get_data (blob, nullptr), rec.length);
|
||||
if (likely (rec.length))
|
||||
memcpy (start, blob->data, rec.length);
|
||||
|
||||
/* 4-byte alignment. */
|
||||
c->align (4);
|
||||
@ -159,7 +155,7 @@ typedef struct OffsetTable
|
||||
{
|
||||
head *h = (head *) start;
|
||||
checksum_adjustment = &h->checkSumAdjustment;
|
||||
checksum_adjustment->set (0);
|
||||
*checksum_adjustment = 0;
|
||||
}
|
||||
|
||||
rec.checkSum.set_for_data (start, end - start);
|
||||
@ -177,10 +173,10 @@ typedef struct OffsetTable
|
||||
for (unsigned int i = 0; i < items.length; i++)
|
||||
{
|
||||
TableRecord &rec = tables.arrayZ[i];
|
||||
checksum.set (checksum + rec.checkSum);
|
||||
checksum = checksum + rec.checkSum;
|
||||
}
|
||||
|
||||
checksum_adjustment->set (0xB1B0AFBAu - checksum);
|
||||
*checksum_adjustment = 0xB1B0AFBAu - checksum;
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
@ -222,7 +218,7 @@ struct TTCHeaderVersion1
|
||||
Tag ttcTag; /* TrueType Collection ID string: 'ttcf' */
|
||||
FixedVersion<>version; /* Version of the TTC Header (1.0),
|
||||
* 0x00010000u */
|
||||
LArrayOf<LOffsetTo<OffsetTable> >
|
||||
LArrayOf<LOffsetTo<OffsetTable>>
|
||||
table; /* Array of offsets to the OffsetTable for each font
|
||||
* from the beginning of the file */
|
||||
public:
|
||||
@ -248,7 +244,7 @@ struct TTCHeader
|
||||
switch (u.header.version.major) {
|
||||
case 2: /* version 2 is compatible with version 1 */
|
||||
case 1: return u.version1.get_face (i);
|
||||
default:return Null(OpenTypeFontFace);
|
||||
default:return Null (OpenTypeFontFace);
|
||||
}
|
||||
}
|
||||
|
||||
@ -283,10 +279,10 @@ struct TTCHeader
|
||||
struct ResourceRecord
|
||||
{
|
||||
const OpenTypeFontFace & get_face (const void *data_base) const
|
||||
{ return CastR<OpenTypeFontFace> ((data_base+offset).arrayZ); }
|
||||
{ return * reinterpret_cast<const OpenTypeFontFace *> ((data_base+offset).arrayZ); }
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c,
|
||||
const void *data_base) const
|
||||
const void *data_base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
@ -334,7 +330,7 @@ struct ResourceTypeRecord
|
||||
protected:
|
||||
Tag tag; /* Resource type. */
|
||||
HBUINT16 resCountM1; /* Number of resources minus 1. */
|
||||
NNOffsetTo<UnsizedArrayOf<ResourceRecord> >
|
||||
NNOffsetTo<UnsizedArrayOf<ResourceRecord>>
|
||||
resourcesZ; /* Offset from beginning of resource type list
|
||||
* to reference item list for this type. */
|
||||
public:
|
||||
@ -390,7 +386,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> >
|
||||
NNOffsetTo<ArrayOfM1<ResourceTypeRecord>>
|
||||
typeList; /* Offset from beginning of map to
|
||||
* resource type list */
|
||||
Offset16 nameList; /* Offset from beginning of map to
|
||||
@ -422,7 +418,7 @@ struct ResourceForkHeader
|
||||
}
|
||||
|
||||
protected:
|
||||
LNNOffsetTo<UnsizedArrayOf<HBUINT8> >
|
||||
LNNOffsetTo<UnsizedArrayOf<HBUINT8>>
|
||||
data; /* Offset from beginning of resource fork
|
||||
* to resource data */
|
||||
LNNOffsetTo<ResourceMap >
|
||||
@ -477,7 +473,7 @@ struct OpenTypeFontFile
|
||||
case TrueTypeTag: return u.fontFace;
|
||||
case TTCTag: return u.ttcHeader.get_face (i);
|
||||
case DFontTag: return u.rfHeader.get_face (i, base_offset);
|
||||
default: return Null(OpenTypeFontFace);
|
||||
default: return Null (OpenTypeFontFace);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -52,22 +52,34 @@ namespace OT {
|
||||
* Int types
|
||||
*/
|
||||
|
||||
template <bool is_signed> struct hb_signedness_int;
|
||||
template <> struct hb_signedness_int<false> { typedef unsigned int value; };
|
||||
template <> struct hb_signedness_int<true> { typedef signed int value; };
|
||||
|
||||
/* Integer types in big-endian order and no alignment requirement */
|
||||
template <typename Type, unsigned int Size>
|
||||
struct IntType
|
||||
{
|
||||
typedef Type type;
|
||||
typedef typename hb_signedness_int<hb_is_signed<Type>::value>::value wide_type;
|
||||
typedef hb_conditional<hb_is_signed (Type), signed, unsigned> wide_type;
|
||||
|
||||
void set (wide_type i) { v.set (i); }
|
||||
IntType& operator = (wide_type i) { v = i; return *this; }
|
||||
operator wide_type () const { return v; }
|
||||
bool operator == (const IntType<Type,Size> &o) const { return (Type) v == (Type) o.v; }
|
||||
bool operator != (const IntType<Type,Size> &o) const { return !(*this == o); }
|
||||
static int cmp (const IntType<Type,Size> *a, const IntType<Type,Size> *b) { return b->cmp (*a); }
|
||||
bool operator == (const IntType &o) const { return (Type) v == (Type) o.v; }
|
||||
bool operator != (const IntType &o) const { return !(*this == o); }
|
||||
|
||||
IntType& operator += (unsigned count) { *this = *this + count; return *this; }
|
||||
IntType& operator -= (unsigned count) { *this = *this - count; return *this; }
|
||||
IntType& operator ++ () { *this += 1; return *this; }
|
||||
IntType& operator -- () { *this -= 1; return *this; }
|
||||
IntType operator ++ (int) { IntType c (*this); ++*this; return c; }
|
||||
IntType operator -- (int) { IntType c (*this); --*this; return c; }
|
||||
|
||||
HB_INTERNAL static int cmp (const IntType *a, const IntType *b)
|
||||
{ return b->cmp (*a); }
|
||||
HB_INTERNAL static int cmp (const void *a, const void *b)
|
||||
{
|
||||
IntType *pa = (IntType *) a;
|
||||
IntType *pb = (IntType *) b;
|
||||
|
||||
return pb->cmp (*pa);
|
||||
}
|
||||
template <typename Type2>
|
||||
int cmp (Type2 a) const
|
||||
{
|
||||
@ -110,19 +122,21 @@ typedef HBUINT16 UFWORD;
|
||||
/* 16-bit signed fixed number with the low 14 bits of fraction (2.14). */
|
||||
struct F2DOT14 : HBINT16
|
||||
{
|
||||
F2DOT14& operator = (uint16_t i ) { HBINT16::operator= (i); return *this; }
|
||||
// 16384 means 1<<14
|
||||
float to_float () const { return ((int32_t) v) / 16384.f; }
|
||||
void set_float (float f) { v.set (round (f * 16384.f)); }
|
||||
void set_float (float f) { v = roundf (f * 16384.f); }
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (2);
|
||||
};
|
||||
|
||||
/* 32-bit signed fixed-point number (16.16). */
|
||||
struct Fixed : HBINT32
|
||||
struct HBFixed : HBINT32
|
||||
{
|
||||
HBFixed& operator = (uint32_t i) { HBINT32::operator= (i); return *this; }
|
||||
// 65536 means 1<<16
|
||||
float to_float () const { return ((int32_t) v) / 65536.f; }
|
||||
void set_float (float f) { v.set (round (f * 65536.f)); }
|
||||
void set_float (float f) { v = roundf (f * 65536.f); }
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (4);
|
||||
};
|
||||
@ -147,6 +161,7 @@ struct LONGDATETIME
|
||||
* system, feature, or baseline */
|
||||
struct Tag : HBUINT32
|
||||
{
|
||||
Tag& operator = (hb_tag_t i) { HBUINT32::operator= (i); return *this; }
|
||||
/* What the char* converters return is NOT nul-terminated. Print using "%.4s" */
|
||||
operator const char* () const { return reinterpret_cast<const char *> (&this->v); }
|
||||
operator char* () { return reinterpret_cast<char *> (&this->v); }
|
||||
@ -155,11 +170,15 @@ struct Tag : HBUINT32
|
||||
};
|
||||
|
||||
/* Glyph index number, same as uint16 (length = 16 bits) */
|
||||
typedef HBUINT16 GlyphID;
|
||||
struct HBGlyphID : HBUINT16
|
||||
{
|
||||
HBGlyphID& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
|
||||
};
|
||||
|
||||
/* Script/language-system/feature index */
|
||||
struct Index : HBUINT16 {
|
||||
static constexpr unsigned NOT_FOUND_INDEX = 0xFFFFu;
|
||||
Index& operator = (uint16_t i) { HBUINT16::operator= (i); return *this; }
|
||||
};
|
||||
DECLARE_NULL_NAMESPACE_BYTES (OT, Index);
|
||||
|
||||
@ -169,6 +188,8 @@ typedef Index NameID;
|
||||
template <typename Type, bool has_null=true>
|
||||
struct Offset : Type
|
||||
{
|
||||
Offset& operator = (typename Type::type i) { Type::operator= (i); return *this; }
|
||||
|
||||
typedef Type type;
|
||||
|
||||
bool is_null () const { return has_null && 0 == *this; }
|
||||
@ -176,7 +197,7 @@ struct Offset : Type
|
||||
void *serialize (hb_serialize_context_t *c, const void *base)
|
||||
{
|
||||
void *t = c->start_embed<void> ();
|
||||
this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */
|
||||
c->check_assign (*this, (unsigned) ((char *) t - (char *) base));
|
||||
return t;
|
||||
}
|
||||
|
||||
@ -191,6 +212,8 @@ typedef Offset<HBUINT32> Offset32;
|
||||
/* CheckSum */
|
||||
struct CheckSum : HBUINT32
|
||||
{
|
||||
CheckSum& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; }
|
||||
|
||||
/* This is reference implementation from the spec. */
|
||||
static uint32_t CalcTableChecksum (const HBUINT32 *Table, uint32_t Length)
|
||||
{
|
||||
@ -205,7 +228,7 @@ struct CheckSum : HBUINT32
|
||||
|
||||
/* Note: data should be 4byte aligned and have 4byte padding at the end. */
|
||||
void set_for_data (const void *data, unsigned int length)
|
||||
{ set (CalcTableChecksum ((const HBUINT32 *) data, length)); }
|
||||
{ *this = CalcTableChecksum ((const HBUINT32 *) data, length); }
|
||||
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (4);
|
||||
@ -248,13 +271,18 @@ struct _hb_has_null
|
||||
template <typename Type>
|
||||
struct _hb_has_null<Type, true>
|
||||
{
|
||||
static const Type *get_null () { return &Null(Type); }
|
||||
static Type *get_crap () { return &Crap(Type); }
|
||||
static const Type *get_null () { return &Null (Type); }
|
||||
static Type *get_crap () { return &Crap (Type); }
|
||||
};
|
||||
|
||||
template <typename Type, typename OffsetType=HBUINT16, bool has_null=true>
|
||||
struct OffsetTo : Offset<OffsetType, has_null>
|
||||
{
|
||||
HB_DELETE_COPY_ASSIGN (OffsetTo);
|
||||
OffsetTo () = default;
|
||||
|
||||
OffsetTo& operator = (typename OffsetType::type i) { OffsetType::operator= (i); return *this; }
|
||||
|
||||
const Type& operator () (const void *base) const
|
||||
{
|
||||
if (unlikely (this->is_null ())) return *_hb_has_null<Type, has_null>::get_null ();
|
||||
@ -266,24 +294,73 @@ struct OffsetTo : Offset<OffsetType, has_null>
|
||||
return StructAtOffset<Type> (base, *this);
|
||||
}
|
||||
|
||||
template <typename Base,
|
||||
hb_enable_if (hb_is_convertible (const Base, const void *))>
|
||||
friend const Type& operator + (const Base &base, const OffsetTo &offset) { return offset ((const void *) base); }
|
||||
template <typename Base,
|
||||
hb_enable_if (hb_is_convertible (const Base, const void *))>
|
||||
friend const Type& operator + (const OffsetTo &offset, const Base &base) { return offset ((const void *) base); }
|
||||
template <typename Base,
|
||||
hb_enable_if (hb_is_convertible (Base, void *))>
|
||||
friend Type& operator + (Base &&base, OffsetTo &offset) { return offset ((void *) base); }
|
||||
template <typename Base,
|
||||
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 T>
|
||||
void serialize_subset (hb_subset_context_t *c, const T &src, const void *base)
|
||||
template <typename ...Ts>
|
||||
bool serialize_subset (hb_subset_context_t *c, const OffsetTo& src,
|
||||
const void *src_base, Ts&&... ds)
|
||||
{
|
||||
if (&src == &Null (T))
|
||||
{
|
||||
this->set (0);
|
||||
return;
|
||||
}
|
||||
serialize (c->serializer, base);
|
||||
if (!src.subset (c))
|
||||
this->set (0);
|
||||
*this = 0;
|
||||
if (src.is_null ())
|
||||
return false;
|
||||
|
||||
auto *s = c->serializer;
|
||||
|
||||
s->push ();
|
||||
|
||||
bool ret = c->dispatch (src_base+src, hb_forward<Ts> (ds)...);
|
||||
|
||||
if (ret || !has_null)
|
||||
s->add_link (*this, s->pop_pack ());
|
||||
else
|
||||
s->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&&...
|
||||
*/
|
||||
template <typename ...Ts>
|
||||
bool serialize_copy (hb_serialize_context_t *c, const OffsetTo& src,
|
||||
const void *src_base, unsigned dst_bias,
|
||||
hb_serialize_context_t::whence_t whence,
|
||||
Ts&&... ds)
|
||||
{
|
||||
*this = 0;
|
||||
if (src.is_null ())
|
||||
return false;
|
||||
|
||||
c->push ();
|
||||
|
||||
bool ret = c->copy (src_base+src, hb_forward<Ts> (ds)...);
|
||||
|
||||
c->add_link (*this, c->pop_pack (), whence, dst_bias);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool serialize_copy (hb_serialize_context_t *c, const OffsetTo& src,
|
||||
const void *src_base, unsigned dst_bias = 0)
|
||||
{ return serialize_copy (c, src, src_base, dst_bias, hb_serialize_context_t::Head); }
|
||||
|
||||
bool sanitize_shallow (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
@ -293,39 +370,13 @@ struct OffsetTo : Offset<OffsetType, has_null>
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
template <typename ...Ts>
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base, Ts&&... ds) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (sanitize_shallow (c, base) &&
|
||||
(this->is_null () ||
|
||||
StructAtOffset<Type> (base, *this).sanitize (c) ||
|
||||
neuter (c)));
|
||||
}
|
||||
template <typename T1>
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (sanitize_shallow (c, base) &&
|
||||
(this->is_null () ||
|
||||
StructAtOffset<Type> (base, *this).sanitize (c, d1) ||
|
||||
neuter (c)));
|
||||
}
|
||||
template <typename T1, typename T2>
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1, T2 d2) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (sanitize_shallow (c, base) &&
|
||||
(this->is_null () ||
|
||||
StructAtOffset<Type> (base, *this).sanitize (c, d1, d2) ||
|
||||
neuter (c)));
|
||||
}
|
||||
template <typename T1, typename T2, typename T3>
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base, T1 d1, T2 d2, T3 d3) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (sanitize_shallow (c, base) &&
|
||||
(this->is_null () ||
|
||||
StructAtOffset<Type> (base, *this).sanitize (c, d1, d2, d3) ||
|
||||
c->dispatch (StructAtOffset<Type> (base, *this), hb_forward<Ts> (ds)...) ||
|
||||
neuter (c)));
|
||||
}
|
||||
|
||||
@ -338,14 +389,12 @@ struct OffsetTo : Offset<OffsetType, has_null>
|
||||
DEFINE_SIZE_STATIC (sizeof (OffsetType));
|
||||
};
|
||||
/* Partial specializations. */
|
||||
template <typename Type, bool has_null=true> struct LOffsetTo : OffsetTo<Type, HBUINT32, has_null> {};
|
||||
template <typename Type, typename OffsetType=HBUINT16 > struct NNOffsetTo : OffsetTo<Type, OffsetType, false> {};
|
||||
template <typename Type > struct LNNOffsetTo : OffsetTo<Type, HBUINT32, false> {};
|
||||
|
||||
template <typename Base, typename OffsetType, bool has_null, typename Type>
|
||||
static inline const Type& operator + (const Base &base, const OffsetTo<Type, OffsetType, has_null> &offset) { return offset (base); }
|
||||
template <typename Base, typename OffsetType, bool has_null, typename Type>
|
||||
static inline Type& operator + (Base &base, OffsetTo<Type, OffsetType, has_null> &offset) { return offset (base); }
|
||||
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>;
|
||||
|
||||
|
||||
/*
|
||||
@ -358,7 +407,7 @@ struct UnsizedArrayOf
|
||||
typedef Type item_t;
|
||||
static constexpr unsigned item_size = hb_static_size (Type);
|
||||
|
||||
HB_NO_CREATE_COPY_ASSIGN_TEMPLATE (UnsizedArrayOf, Type);
|
||||
HB_DELETE_CREATE_COPY_ASSIGN (UnsizedArrayOf);
|
||||
|
||||
const Type& operator [] (int i_) const
|
||||
{
|
||||
@ -384,7 +433,7 @@ struct UnsizedArrayOf
|
||||
{ return hb_array (arrayZ, len); }
|
||||
hb_array_t<const Type> as_array (unsigned int len) const
|
||||
{ return hb_array (arrayZ, len); }
|
||||
operator hb_array_t<Type> () { return as_array (); }
|
||||
operator hb_array_t< Type> () { return as_array (); }
|
||||
operator hb_array_t<const Type> () const { return as_array (); }
|
||||
|
||||
template <typename T>
|
||||
@ -393,42 +442,49 @@ struct UnsizedArrayOf
|
||||
template <typename T>
|
||||
const Type &lsearch (unsigned int len, const T &x, const Type ¬_found = Null (Type)) const
|
||||
{ return *as_array (len).lsearch (x, ¬_found); }
|
||||
template <typename T>
|
||||
bool lfind (unsigned int len, const T &x, unsigned *pos = nullptr) const
|
||||
{ return as_array (len).lfind (x, pos); }
|
||||
|
||||
void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1)
|
||||
{ as_array (len).qsort (start, end); }
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
|
||||
bool serialize (hb_serialize_context_t *c, unsigned int items_len)
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
|
||||
|
||||
/* Note: for structs that do not reference other structs,
|
||||
* we do not need to call their sanitize() as we already did
|
||||
* a bound check on the aggregate array size. We just include
|
||||
* a small unreachable expression to make sure the structs
|
||||
* pointed to do have a simple sanitize(), ie. they do not
|
||||
* reference other structs via offsets.
|
||||
*/
|
||||
(void) (false && arrayZ[0].sanitize (c));
|
||||
|
||||
TRACE_SERIALIZE (this);
|
||||
if (unlikely (!c->extend (*this, items_len))) return_trace (false);
|
||||
return_trace (true);
|
||||
}
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base) const
|
||||
template <typename Iterator,
|
||||
hb_requires (hb_is_source_of (Iterator, Type))>
|
||||
bool serialize (hb_serialize_context_t *c, Iterator items)
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (unlikely (!arrayZ[i].sanitize (c, base)))
|
||||
return_trace (false);
|
||||
TRACE_SERIALIZE (this);
|
||||
unsigned count = items.len ();
|
||||
if (unlikely (!serialize (c, count))) return_trace (false);
|
||||
/* TODO Umm. Just exhaust the iterator instead? Being extra
|
||||
* cautious right now.. */
|
||||
for (unsigned i = 0; i < count; i++, ++items)
|
||||
arrayZ[i] = *items;
|
||||
return_trace (true);
|
||||
}
|
||||
template <typename T>
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned int count, const void *base, T user_data) const
|
||||
|
||||
UnsizedArrayOf* copy (hb_serialize_context_t *c, unsigned count) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
auto *out = c->start_embed (this);
|
||||
if (unlikely (!as_array (count).copy (c))) return_trace (nullptr);
|
||||
return_trace (out);
|
||||
}
|
||||
|
||||
template <typename ...Ts>
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!sanitize_shallow (c, count))) return_trace (false);
|
||||
if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true);
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (unlikely (!arrayZ[i].sanitize (c, base, user_data)))
|
||||
if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
|
||||
return_trace (false);
|
||||
return_trace (true);
|
||||
}
|
||||
@ -440,14 +496,14 @@ struct UnsizedArrayOf
|
||||
}
|
||||
|
||||
public:
|
||||
Type arrayZ[VAR];
|
||||
Type arrayZ[HB_VAR_ARRAY];
|
||||
public:
|
||||
DEFINE_SIZE_UNBOUNDED (0);
|
||||
};
|
||||
|
||||
/* Unsized array of offset's */
|
||||
template <typename Type, typename OffsetType, bool has_null=true>
|
||||
struct UnsizedOffsetArrayOf : UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null> > {};
|
||||
using UnsizedOffsetArrayOf = 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>
|
||||
@ -468,17 +524,12 @@ struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType, has_null>
|
||||
return this+*p;
|
||||
}
|
||||
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned int count) const
|
||||
template <typename ...Ts>
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace ((UnsizedOffsetArrayOf<Type, OffsetType, has_null>::sanitize (c, count, this)));
|
||||
}
|
||||
template <typename T>
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned int count, T user_data) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace ((UnsizedOffsetArrayOf<Type, OffsetType, has_null>::sanitize (c, count, this, user_data)));
|
||||
return_trace ((UnsizedOffsetArrayOf<Type, OffsetType, has_null>
|
||||
::sanitize (c, count, this, hb_forward<Ts> (ds)...)));
|
||||
}
|
||||
};
|
||||
|
||||
@ -501,8 +552,8 @@ struct SortedUnsizedArrayOf : UnsizedArrayOf<Type>
|
||||
{ return *as_array (len).bsearch (x, ¬_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,
|
||||
unsigned int to_store = (unsigned int) -1) const
|
||||
hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
|
||||
unsigned int to_store = (unsigned int) -1) const
|
||||
{ return as_array (len).bfind (x, i, not_found, to_store); }
|
||||
};
|
||||
|
||||
@ -514,7 +565,7 @@ struct ArrayOf
|
||||
typedef Type item_t;
|
||||
static constexpr unsigned item_size = hb_static_size (Type);
|
||||
|
||||
HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (ArrayOf, Type, LenType);
|
||||
HB_DELETE_CREATE_COPY_ASSIGN (ArrayOf);
|
||||
|
||||
const Type& operator [] (int i_) const
|
||||
{
|
||||
@ -532,74 +583,83 @@ struct ArrayOf
|
||||
unsigned int get_size () const
|
||||
{ return len.static_size + len * Type::static_size; }
|
||||
|
||||
hb_array_t<Type> as_array ()
|
||||
{ return hb_array (arrayZ, len); }
|
||||
hb_array_t<const Type> as_array () const
|
||||
{ return hb_array (arrayZ, len); }
|
||||
operator hb_array_t<Type> (void) { return as_array (); }
|
||||
operator hb_array_t<const Type> (void) const { return as_array (); }
|
||||
explicit operator bool () const { return len; }
|
||||
|
||||
void pop () { len--; }
|
||||
|
||||
hb_array_t< Type> as_array () { return hb_array (arrayZ, len); }
|
||||
hb_array_t<const Type> as_array () const { return hb_array (arrayZ, len); }
|
||||
|
||||
/* Iterator. */
|
||||
typedef hb_array_t<const Type> iter_t;
|
||||
typedef hb_array_t< Type> writer_t;
|
||||
iter_t iter () const { return as_array (); }
|
||||
writer_t writer () { return as_array (); }
|
||||
operator iter_t () const { return iter (); }
|
||||
operator writer_t () { return writer (); }
|
||||
|
||||
hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
|
||||
{ return as_array ().sub_array (start_offset, count);}
|
||||
{ return as_array ().sub_array (start_offset, count); }
|
||||
hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
|
||||
{ return as_array ().sub_array (start_offset, count);}
|
||||
{ return as_array ().sub_array (start_offset, count); }
|
||||
hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
|
||||
{ return as_array ().sub_array (start_offset, count);}
|
||||
{ return as_array ().sub_array (start_offset, count); }
|
||||
hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
|
||||
{ return as_array ().sub_array (start_offset, count);}
|
||||
{ return as_array ().sub_array (start_offset, count); }
|
||||
|
||||
bool serialize (hb_serialize_context_t *c, unsigned int items_len)
|
||||
hb_success_t serialize (hb_serialize_context_t *c, unsigned items_len)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||
len.set (items_len); /* TODO(serialize) Overflow? */
|
||||
c->check_assign (len, items_len);
|
||||
if (unlikely (!c->extend (*this))) return_trace (false);
|
||||
return_trace (true);
|
||||
}
|
||||
template <typename T>
|
||||
bool serialize (hb_serialize_context_t *c, hb_array_t<const T> items)
|
||||
template <typename Iterator,
|
||||
hb_requires (hb_is_source_of (Iterator, Type))>
|
||||
hb_success_t serialize (hb_serialize_context_t *c, Iterator items)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
if (unlikely (!serialize (c, items.length))) return_trace (false);
|
||||
for (unsigned int i = 0; i < items.length; i++)
|
||||
hb_assign (arrayZ[i], items[i]);
|
||||
unsigned count = items.len ();
|
||||
if (unlikely (!serialize (c, count))) return_trace (false);
|
||||
/* TODO Umm. Just exhaust the iterator instead? Being extra
|
||||
* cautious right now.. */
|
||||
for (unsigned i = 0; i < count; i++, ++items)
|
||||
arrayZ[i] = *items;
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
Type* serialize_append (hb_serialize_context_t *c)
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!sanitize_shallow (c))) return_trace (false);
|
||||
|
||||
/* Note: for structs that do not reference other structs,
|
||||
* we do not need to call their sanitize() as we already did
|
||||
* a bound check on the aggregate array size. We just include
|
||||
* a small unreachable expression to make sure the structs
|
||||
* pointed to do have a simple sanitize(), ie. they do not
|
||||
* reference other structs via offsets.
|
||||
*/
|
||||
(void) (false && arrayZ[0].sanitize (c));
|
||||
|
||||
return_trace (true);
|
||||
TRACE_SERIALIZE (this);
|
||||
len++;
|
||||
if (unlikely (!len || !c->extend (*this)))
|
||||
{
|
||||
len--;
|
||||
return_trace (nullptr);
|
||||
}
|
||||
return_trace (&arrayZ[len - 1]);
|
||||
}
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
|
||||
ArrayOf* copy (hb_serialize_context_t *c) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
auto *out = c->start_embed (this);
|
||||
if (unlikely (!c->extend_min (out))) return_trace (nullptr);
|
||||
c->check_assign (out->len, len);
|
||||
if (unlikely (!as_array ().copy (c))) return_trace (nullptr);
|
||||
return_trace (out);
|
||||
}
|
||||
|
||||
template <typename ...Ts>
|
||||
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
|
||||
{
|
||||
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 = len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (unlikely (!arrayZ[i].sanitize (c, base)))
|
||||
return_trace (false);
|
||||
return_trace (true);
|
||||
}
|
||||
template <typename T>
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!sanitize_shallow (c))) return_trace (false);
|
||||
unsigned int count = len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (unlikely (!arrayZ[i].sanitize (c, base, user_data)))
|
||||
if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
|
||||
return_trace (false);
|
||||
return_trace (true);
|
||||
}
|
||||
@ -610,6 +670,9 @@ struct ArrayOf
|
||||
template <typename T>
|
||||
const Type &lsearch (const T &x, const Type ¬_found = Null (Type)) const
|
||||
{ return *as_array ().lsearch (x, ¬_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); }
|
||||
@ -622,20 +685,21 @@ struct ArrayOf
|
||||
|
||||
public:
|
||||
LenType len;
|
||||
Type arrayZ[VAR];
|
||||
Type arrayZ[HB_VAR_ARRAY];
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
|
||||
};
|
||||
template <typename Type> struct LArrayOf : ArrayOf<Type, HBUINT32> {};
|
||||
typedef ArrayOf<HBUINT8, HBUINT8> PString;
|
||||
template <typename Type>
|
||||
using LArrayOf = ArrayOf<Type, HBUINT32>;
|
||||
using PString = ArrayOf<HBUINT8, HBUINT8>;
|
||||
|
||||
/* Array of Offset's */
|
||||
template <typename Type>
|
||||
struct OffsetArrayOf : ArrayOf<OffsetTo<Type, HBUINT16> > {};
|
||||
using OffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT16>>;
|
||||
template <typename Type>
|
||||
struct LOffsetArrayOf : ArrayOf<OffsetTo<Type, HBUINT32> > {};
|
||||
using LOffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT32>>;
|
||||
template <typename Type>
|
||||
struct LOffsetLArrayOf : ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32> {};
|
||||
using LOffsetLArrayOf = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32>;
|
||||
|
||||
/* Array of offsets relative to the beginning of the array itself. */
|
||||
template <typename Type>
|
||||
@ -661,20 +725,15 @@ struct OffsetListOf : OffsetArrayOf<Type>
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
unsigned int count = this->len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
out->arrayZ[i].serialize_subset (c, (*this)[i], out);
|
||||
out->arrayZ[i].serialize_subset (c, this->arrayZ[i], this, out);
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
template <typename ...Ts>
|
||||
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (OffsetArrayOf<Type>::sanitize (c, this));
|
||||
}
|
||||
template <typename T>
|
||||
bool sanitize (hb_sanitize_context_t *c, T user_data) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (OffsetArrayOf<Type>::sanitize (c, this, user_data));
|
||||
return_trace (OffsetArrayOf<Type>::sanitize (c, this, hb_forward<Ts> (ds)...));
|
||||
}
|
||||
};
|
||||
|
||||
@ -684,7 +743,7 @@ struct HeadlessArrayOf
|
||||
{
|
||||
static constexpr unsigned item_size = Type::static_size;
|
||||
|
||||
HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (HeadlessArrayOf, Type, LenType);
|
||||
HB_DELETE_CREATE_COPY_ASSIGN (HeadlessArrayOf);
|
||||
|
||||
const Type& operator [] (int i_) const
|
||||
{
|
||||
@ -699,34 +758,53 @@ struct HeadlessArrayOf
|
||||
return arrayZ[i-1];
|
||||
}
|
||||
unsigned int get_size () const
|
||||
{ return lenP1.static_size + (lenP1 ? lenP1 - 1 : 0) * Type::static_size; }
|
||||
{ return lenP1.static_size + get_length () * Type::static_size; }
|
||||
|
||||
bool serialize (hb_serialize_context_t *c,
|
||||
hb_array_t<const Type> items)
|
||||
unsigned get_length () const { return lenP1 ? lenP1 - 1 : 0; }
|
||||
|
||||
hb_array_t< Type> as_array () { return hb_array (arrayZ, get_length ()); }
|
||||
hb_array_t<const Type> as_array () const { return hb_array (arrayZ, get_length ()); }
|
||||
|
||||
/* Iterator. */
|
||||
typedef hb_array_t<const Type> iter_t;
|
||||
typedef hb_array_t< Type> writer_t;
|
||||
iter_t iter () const { return as_array (); }
|
||||
writer_t writer () { return as_array (); }
|
||||
operator iter_t () const { return iter (); }
|
||||
operator writer_t () { return writer (); }
|
||||
|
||||
bool serialize (hb_serialize_context_t *c, unsigned int items_len)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||
lenP1.set (items.length + 1); /* TODO(serialize) Overflow? */
|
||||
c->check_assign (lenP1, items_len + 1);
|
||||
if (unlikely (!c->extend (*this))) return_trace (false);
|
||||
for (unsigned int i = 0; i < items.length; i++)
|
||||
arrayZ[i] = items[i];
|
||||
return_trace (true);
|
||||
}
|
||||
template <typename Iterator,
|
||||
hb_requires (hb_is_source_of (Iterator, Type))>
|
||||
bool serialize (hb_serialize_context_t *c, Iterator items)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
unsigned count = items.len ();
|
||||
if (unlikely (!serialize (c, count))) return_trace (false);
|
||||
/* TODO Umm. Just exhaust the iterator instead? Being extra
|
||||
* cautious right now.. */
|
||||
for (unsigned i = 0; i < count; i++, ++items)
|
||||
arrayZ[i] = *items;
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
template <typename ...Ts>
|
||||
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!sanitize_shallow (c))) return_trace (false);
|
||||
|
||||
/* Note: for structs that do not reference other structs,
|
||||
* we do not need to call their sanitize() as we already did
|
||||
* a bound check on the aggregate array size. We just include
|
||||
* a small unreachable expression to make sure the structs
|
||||
* pointed to do have a simple sanitize(), ie. they do not
|
||||
* reference other structs via offsets.
|
||||
*/
|
||||
(void) (false && arrayZ[0].sanitize (c));
|
||||
|
||||
if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true);
|
||||
unsigned int count = get_length ();
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
|
||||
return_trace (false);
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
@ -740,7 +818,7 @@ struct HeadlessArrayOf
|
||||
|
||||
public:
|
||||
LenType lenP1;
|
||||
Type arrayZ[VAR];
|
||||
Type arrayZ[HB_VAR_ARRAY];
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
|
||||
};
|
||||
@ -749,7 +827,7 @@ struct HeadlessArrayOf
|
||||
template <typename Type, typename LenType=HBUINT16>
|
||||
struct ArrayOfM1
|
||||
{
|
||||
HB_NO_CREATE_COPY_ASSIGN_TEMPLATE2 (ArrayOfM1, Type, LenType);
|
||||
HB_DELETE_CREATE_COPY_ASSIGN (ArrayOfM1);
|
||||
|
||||
const Type& operator [] (int i_) const
|
||||
{
|
||||
@ -766,14 +844,14 @@ struct ArrayOfM1
|
||||
unsigned int get_size () const
|
||||
{ return lenM1.static_size + (lenM1 + 1) * Type::static_size; }
|
||||
|
||||
template <typename T>
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
|
||||
template <typename ...Ts>
|
||||
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!sanitize_shallow (c))) return_trace (false);
|
||||
unsigned int count = lenM1 + 1;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (unlikely (!arrayZ[i].sanitize (c, base, user_data)))
|
||||
if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
|
||||
return_trace (false);
|
||||
return_trace (true);
|
||||
}
|
||||
@ -788,7 +866,7 @@ struct ArrayOfM1
|
||||
|
||||
public:
|
||||
LenType lenM1;
|
||||
Type arrayZ[VAR];
|
||||
Type arrayZ[HB_VAR_ARRAY];
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
|
||||
};
|
||||
@ -797,21 +875,40 @@ struct ArrayOfM1
|
||||
template <typename Type, typename LenType=HBUINT16>
|
||||
struct SortedArrayOf : ArrayOf<Type, LenType>
|
||||
{
|
||||
hb_sorted_array_t<Type> as_array ()
|
||||
{ return hb_sorted_array (this->arrayZ, this->len); }
|
||||
hb_sorted_array_t<const Type> as_array () const
|
||||
{ return hb_sorted_array (this->arrayZ, this->len); }
|
||||
operator hb_sorted_array_t<Type> () { return as_array (); }
|
||||
operator hb_sorted_array_t<const Type> () const { return as_array (); }
|
||||
hb_sorted_array_t< Type> as_array () { return hb_sorted_array (this->arrayZ, this->len); }
|
||||
hb_sorted_array_t<const Type> as_array () const { return hb_sorted_array (this->arrayZ, this->len); }
|
||||
|
||||
hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
|
||||
{ return as_array ().sub_array (start_offset, count);}
|
||||
hb_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
|
||||
{ return as_array ().sub_array (start_offset, count);}
|
||||
hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
|
||||
{ return as_array ().sub_array (start_offset, count);}
|
||||
hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
|
||||
{ return as_array ().sub_array (start_offset, count);}
|
||||
/* Iterator. */
|
||||
typedef hb_sorted_array_t<const Type> iter_t;
|
||||
typedef hb_sorted_array_t< Type> writer_t;
|
||||
iter_t iter () const { return as_array (); }
|
||||
writer_t writer () { return as_array (); }
|
||||
operator iter_t () const { return iter (); }
|
||||
operator writer_t () { return writer (); }
|
||||
|
||||
hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int count) const
|
||||
{ return as_array ().sub_array (start_offset, count); }
|
||||
hb_sorted_array_t<const Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */) const
|
||||
{ return as_array ().sub_array (start_offset, count); }
|
||||
hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int count)
|
||||
{ return as_array ().sub_array (start_offset, count); }
|
||||
hb_sorted_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
|
||||
{ return as_array ().sub_array (start_offset, count); }
|
||||
|
||||
bool serialize (hb_serialize_context_t *c, unsigned int items_len)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
bool ret = ArrayOf<Type, LenType>::serialize (c, items_len);
|
||||
return_trace (ret);
|
||||
}
|
||||
template <typename Iterator,
|
||||
hb_requires (hb_is_sorted_source_of (Iterator, Type))>
|
||||
bool serialize (hb_serialize_context_t *c, Iterator items)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
bool ret = ArrayOf<Type, LenType>::serialize (c, items);
|
||||
return_trace (ret);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Type &bsearch (const T &x, Type ¬_found = Crap (Type))
|
||||
@ -821,8 +918,8 @@ struct SortedArrayOf : ArrayOf<Type, LenType>
|
||||
{ return *as_array ().bsearch (x, ¬_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,
|
||||
unsigned int to_store = (unsigned int) -1) const
|
||||
hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
|
||||
unsigned int to_store = (unsigned int) -1) const
|
||||
{ return as_array ().bfind (x, i, not_found, to_store); }
|
||||
};
|
||||
|
||||
@ -841,15 +938,16 @@ struct BinSearchHeader
|
||||
return_trace (c->check_struct (this));
|
||||
}
|
||||
|
||||
void set (unsigned int v)
|
||||
BinSearchHeader& operator = (unsigned int v)
|
||||
{
|
||||
len.set (v);
|
||||
len = v;
|
||||
assert (len == v);
|
||||
entrySelector.set (MAX (1u, hb_bit_storage (v)) - 1);
|
||||
searchRange.set (16 * (1u << entrySelector));
|
||||
rangeShift.set (v * 16 > searchRange
|
||||
? 16 * v - searchRange
|
||||
: 0);
|
||||
entrySelector = hb_max (1u, hb_bit_storage (v)) - 1;
|
||||
searchRange = 16 * (1u << entrySelector);
|
||||
rangeShift = v * 16 > searchRange
|
||||
? 16 * v - searchRange
|
||||
: 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -863,7 +961,7 @@ struct BinSearchHeader
|
||||
};
|
||||
|
||||
template <typename Type, typename LenType=HBUINT16>
|
||||
struct BinSearchArrayOf : SortedArrayOf<Type, BinSearchHeader<LenType> > {};
|
||||
using BinSearchArrayOf = SortedArrayOf<Type, BinSearchHeader<LenType>>;
|
||||
|
||||
|
||||
struct VarSizedBinSearchHeader
|
||||
@ -893,7 +991,7 @@ struct VarSizedBinSearchArrayOf
|
||||
{
|
||||
static constexpr unsigned item_size = Type::static_size;
|
||||
|
||||
HB_NO_CREATE_COPY_ASSIGN_TEMPLATE (VarSizedBinSearchArrayOf, Type);
|
||||
HB_DELETE_CREATE_COPY_ASSIGN (VarSizedBinSearchArrayOf);
|
||||
|
||||
bool last_is_terminator () const
|
||||
{
|
||||
@ -928,40 +1026,15 @@ struct VarSizedBinSearchArrayOf
|
||||
unsigned int get_size () const
|
||||
{ return header.static_size + header.nUnits * header.unitSize; }
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!sanitize_shallow (c))) return_trace (false);
|
||||
|
||||
/* Note: for structs that do not reference other structs,
|
||||
* we do not need to call their sanitize() as we already did
|
||||
* a bound check on the aggregate array size. We just include
|
||||
* a small unreachable expression to make sure the structs
|
||||
* pointed to do have a simple sanitize(), ie. they do not
|
||||
* reference other structs via offsets.
|
||||
*/
|
||||
(void) (false && StructAtOffset<Type> (&bytesZ, 0).sanitize (c));
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
template <typename ...Ts>
|
||||
bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
|
||||
{
|
||||
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 = get_length ();
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (unlikely (!(*this)[i].sanitize (c, base)))
|
||||
return_trace (false);
|
||||
return_trace (true);
|
||||
}
|
||||
template <typename T>
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!sanitize_shallow (c))) return_trace (false);
|
||||
unsigned int count = get_length ();
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (unlikely (!(*this)[i].sanitize (c, base, user_data)))
|
||||
if (unlikely (!(*this)[i].sanitize (c, hb_forward<Ts> (ds)...)))
|
||||
return_trace (false);
|
||||
return_trace (true);
|
||||
}
|
||||
@ -969,18 +1042,15 @@ struct VarSizedBinSearchArrayOf
|
||||
template <typename T>
|
||||
const Type *bsearch (const T &key) const
|
||||
{
|
||||
unsigned int size = header.unitSize;
|
||||
int min = 0, max = (int) get_length () - 1;
|
||||
while (min <= max)
|
||||
{
|
||||
int mid = ((unsigned int) min + (unsigned int) max) / 2;
|
||||
const Type *p = (const Type *) (((const char *) &bytesZ) + (mid * size));
|
||||
int c = p->cmp (key);
|
||||
if (c < 0) max = mid - 1;
|
||||
else if (c > 0) min = mid + 1;
|
||||
else return p;
|
||||
}
|
||||
return nullptr;
|
||||
unsigned pos;
|
||||
return hb_bsearch_impl (&pos,
|
||||
key,
|
||||
(const void *) bytesZ,
|
||||
get_length (),
|
||||
header.unitSize,
|
||||
_hb_cmp_method<T, Type>)
|
||||
? (const Type *) (((const char *) &bytesZ) + (pos * header.unitSize))
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
#define HB_OT_CFF_COMMON_HH
|
||||
|
||||
#include "hb-open-type.hh"
|
||||
#include "hb-bimap.hh"
|
||||
#include "hb-ot-layout-common.hh"
|
||||
#include "hb-cff-interp-dict-common.hh"
|
||||
#include "hb-subset-plan.hh"
|
||||
@ -37,16 +38,19 @@ using namespace OT;
|
||||
|
||||
#define CFF_UNDEF_CODE 0xFFFFFFFF
|
||||
|
||||
using objidx_t = hb_serialize_context_t::objidx_t;
|
||||
using whence_t = hb_serialize_context_t::whence_t;
|
||||
|
||||
/* utility macro */
|
||||
template<typename Type>
|
||||
static inline const Type& StructAtOffsetOrNull(const void *P, unsigned int offset)
|
||||
{ return offset? (* reinterpret_cast<const Type*> ((const char *) P + offset)): Null(Type); }
|
||||
static inline const Type& StructAtOffsetOrNull (const void *P, unsigned int offset)
|
||||
{ return offset ? StructAtOffset<Type> (P, offset) : Null (Type); }
|
||||
|
||||
inline unsigned int calcOffSize(unsigned int dataSize)
|
||||
inline unsigned int calcOffSize (unsigned int dataSize)
|
||||
{
|
||||
unsigned int size = 1;
|
||||
unsigned int offset = dataSize + 1;
|
||||
while ((offset & ~0xFF) != 0)
|
||||
while (offset & ~0xFF)
|
||||
{
|
||||
size++;
|
||||
offset >>= 8;
|
||||
@ -57,8 +61,8 @@ inline unsigned int calcOffSize(unsigned int dataSize)
|
||||
|
||||
struct code_pair_t
|
||||
{
|
||||
hb_codepoint_t code;
|
||||
hb_codepoint_t glyph;
|
||||
hb_codepoint_t code;
|
||||
hb_codepoint_t glyph;
|
||||
};
|
||||
|
||||
typedef hb_vector_t<unsigned char> str_buff_t;
|
||||
@ -82,27 +86,20 @@ struct str_buff_vec_t : hb_vector_t<str_buff_t>
|
||||
template <typename COUNT>
|
||||
struct CFFIndex
|
||||
{
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely ((count.sanitize (c) && count == 0) || /* empty INDEX */
|
||||
(c->check_struct (this) && offSize >= 1 && offSize <= 4 &&
|
||||
c->check_array (offsets, offSize, count + 1) &&
|
||||
c->check_array ((const HBUINT8*)data_base (), 1, max_offset () - 1))));
|
||||
}
|
||||
|
||||
static unsigned int calculate_offset_array_size (unsigned int offSize, unsigned int count)
|
||||
{ return offSize * (count + 1); }
|
||||
|
||||
unsigned int offset_array_size () const
|
||||
{ return calculate_offset_array_size (offSize, count); }
|
||||
|
||||
static unsigned int calculate_serialized_size (unsigned int offSize, unsigned int count, unsigned int dataSize)
|
||||
CFFIndex *copy (hb_serialize_context_t *c) const
|
||||
{
|
||||
if (count == 0)
|
||||
return COUNT::static_size;
|
||||
else
|
||||
return min_size + calculate_offset_array_size (offSize, count) + dataSize;
|
||||
TRACE_SERIALIZE (this);
|
||||
unsigned int size = get_size ();
|
||||
CFFIndex *out = c->allocate_size<CFFIndex> (size);
|
||||
if (likely (out))
|
||||
memcpy (out, this, size);
|
||||
return_trace (out);
|
||||
}
|
||||
|
||||
bool serialize (hb_serialize_context_t *c, const CFFIndex &src)
|
||||
@ -110,7 +107,7 @@ struct CFFIndex
|
||||
TRACE_SERIALIZE (this);
|
||||
unsigned int size = src.get_size ();
|
||||
CFFIndex *dest = c->allocate_size<CFFIndex> (size);
|
||||
if (unlikely (dest == nullptr)) return_trace (false);
|
||||
if (unlikely (!dest)) return_trace (false);
|
||||
memcpy (dest, &src, size);
|
||||
return_trace (true);
|
||||
}
|
||||
@ -123,16 +120,16 @@ struct CFFIndex
|
||||
if (byteArray.length == 0)
|
||||
{
|
||||
COUNT *dest = c->allocate_min<COUNT> ();
|
||||
if (unlikely (dest == nullptr)) return_trace (false);
|
||||
dest->set (0);
|
||||
if (unlikely (!dest)) return_trace (false);
|
||||
*dest = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* serialize CFFIndex header */
|
||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||
this->count.set (byteArray.length);
|
||||
this->offSize.set (offSize_);
|
||||
if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (byteArray.length + 1))))
|
||||
this->count = byteArray.length;
|
||||
this->offSize = offSize_;
|
||||
if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (byteArray.length + 1))))
|
||||
return_trace (false);
|
||||
|
||||
/* serialize indices */
|
||||
@ -149,9 +146,8 @@ struct CFFIndex
|
||||
for (unsigned int i = 0; i < byteArray.length; i++)
|
||||
{
|
||||
const byte_str_t &bs = byteArray[i];
|
||||
unsigned char *dest = c->allocate_size<unsigned char> (bs.length);
|
||||
if (unlikely (dest == nullptr))
|
||||
return_trace (false);
|
||||
unsigned char *dest = c->allocate_size<unsigned char> (bs.length);
|
||||
if (unlikely (!dest)) return_trace (false);
|
||||
memcpy (dest, &bs[0], bs.length);
|
||||
}
|
||||
}
|
||||
@ -166,14 +162,77 @@ struct CFFIndex
|
||||
byteArray.init ();
|
||||
byteArray.resize (buffArray.length);
|
||||
for (unsigned int i = 0; i < byteArray.length; i++)
|
||||
{
|
||||
byteArray[i] = byte_str_t (buffArray[i].arrayZ (), buffArray[i].length);
|
||||
}
|
||||
byteArray[i] = byte_str_t (buffArray[i].arrayZ, buffArray[i].length);
|
||||
bool result = this->serialize (c, offSize_, byteArray);
|
||||
byteArray.fini ();
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename Iterator,
|
||||
hb_requires (hb_is_iterator (Iterator))>
|
||||
bool serialize (hb_serialize_context_t *c,
|
||||
Iterator it)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
if (it.len () == 0)
|
||||
{
|
||||
COUNT *dest = c->allocate_min<COUNT> ();
|
||||
if (unlikely (!dest)) return_trace (false);
|
||||
*dest = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
serialize_header(c, + it | hb_map ([] (const byte_str_t &_) { return _.length; }));
|
||||
for (const byte_str_t &_ : +it)
|
||||
_.copy (c);
|
||||
}
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
bool serialize (hb_serialize_context_t *c,
|
||||
const byte_str_array_t &byteArray)
|
||||
{ return serialize (c, + hb_iter (byteArray)); }
|
||||
|
||||
bool serialize (hb_serialize_context_t *c,
|
||||
const str_buff_vec_t &buffArray)
|
||||
{
|
||||
auto it =
|
||||
+ hb_iter (buffArray)
|
||||
| hb_map ([] (const str_buff_t &_) { return byte_str_t (_.arrayZ, _.length); })
|
||||
;
|
||||
return serialize (c, it);
|
||||
}
|
||||
|
||||
template <typename Iterator,
|
||||
hb_requires (hb_is_iterator (Iterator))>
|
||||
bool serialize_header (hb_serialize_context_t *c,
|
||||
Iterator it)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
||||
unsigned total = + it | hb_reduce (hb_add, 0);
|
||||
unsigned off_size = calcOffSize (total);
|
||||
|
||||
/* serialize CFFIndex header */
|
||||
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))))
|
||||
return_trace (false);
|
||||
|
||||
/* serialize indices */
|
||||
unsigned int offset = 1;
|
||||
unsigned int i = 0;
|
||||
for (unsigned _ : +it)
|
||||
{
|
||||
CFFIndex<COUNT>::set_offset_at (i++, offset);
|
||||
offset += _;
|
||||
}
|
||||
CFFIndex<COUNT>::set_offset_at (i, offset);
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
void set_offset_at (unsigned int index, unsigned int offset)
|
||||
{
|
||||
HBUINT8 *p = offsets + offSize * index + offSize;
|
||||
@ -181,7 +240,7 @@ struct CFFIndex
|
||||
for (; size; size--)
|
||||
{
|
||||
--p;
|
||||
p->set (offset & 0xFF);
|
||||
*p = offset & 0xFF;
|
||||
offset >>= 8;
|
||||
}
|
||||
}
|
||||
@ -199,37 +258,38 @@ struct CFFIndex
|
||||
|
||||
unsigned int length_at (unsigned int index) const
|
||||
{
|
||||
if (likely ((offset_at (index + 1) >= offset_at (index)) &&
|
||||
(offset_at (index + 1) <= offset_at (count))))
|
||||
return offset_at (index + 1) - offset_at (index);
|
||||
else
|
||||
return 0;
|
||||
if (unlikely ((offset_at (index + 1) < offset_at (index)) ||
|
||||
(offset_at (index + 1) > offset_at (count))))
|
||||
return 0;
|
||||
return offset_at (index + 1) - offset_at (index);
|
||||
}
|
||||
|
||||
const unsigned char *data_base () const
|
||||
{ return (const unsigned char *)this + min_size + offset_array_size (); }
|
||||
{ return (const unsigned char *) this + min_size + offset_array_size (); }
|
||||
|
||||
unsigned int data_size () const { return HBINT8::static_size; }
|
||||
|
||||
byte_str_t operator [] (unsigned int index) const
|
||||
{
|
||||
if (likely (index < count))
|
||||
return byte_str_t (data_base () + offset_at (index) - 1, length_at (index));
|
||||
else
|
||||
return Null(byte_str_t);
|
||||
if (unlikely (index >= count)) return Null (byte_str_t);
|
||||
return byte_str_t (data_base () + offset_at (index) - 1, length_at (index));
|
||||
}
|
||||
|
||||
unsigned int get_size () const
|
||||
{
|
||||
if (this != &Null(CFFIndex))
|
||||
{
|
||||
if (count > 0)
|
||||
return min_size + offset_array_size () + (offset_at (count) - 1);
|
||||
else
|
||||
return count.static_size; /* empty CFFIndex contains count only */
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
if (this == &Null (CFFIndex)) return 0;
|
||||
if (count > 0)
|
||||
return min_size + offset_array_size () + (offset_at (count) - 1);
|
||||
return count.static_size; /* empty CFFIndex contains count only */
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely ((c->check_struct (this) && count == 0) || /* empty INDEX */
|
||||
(c->check_struct (this) && offSize >= 1 && offSize <= 4 &&
|
||||
c->check_array (offsets, offSize, count + 1) &&
|
||||
c->check_array ((const HBUINT8*) data_base (), 1, max_offset () - 1))));
|
||||
}
|
||||
|
||||
protected:
|
||||
@ -245,10 +305,11 @@ struct CFFIndex
|
||||
}
|
||||
|
||||
public:
|
||||
COUNT count; /* Number of object data. Note there are (count+1) offsets */
|
||||
HBUINT8 offSize; /* The byte size of each offset in the offsets array. */
|
||||
HBUINT8 offsets[VAR]; /* The array of (count + 1) offsets into objects array (1-base). */
|
||||
/* HBUINT8 data[VAR]; Object data */
|
||||
COUNT count; /* Number of object data. Note there are (count+1) offsets */
|
||||
HBUINT8 offSize; /* The byte size of each offset in the offsets array. */
|
||||
HBUINT8 offsets[HB_VAR_ARRAY];
|
||||
/* The array of (count + 1) offsets into objects array (1-base). */
|
||||
/* HBUINT8 data[HB_VAR_ARRAY]; Object data */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (COUNT::static_size + HBUINT8::static_size, offsets);
|
||||
};
|
||||
@ -260,7 +321,7 @@ struct CFFIndexOf : CFFIndex<COUNT>
|
||||
{
|
||||
if (likely (index < CFFIndex<COUNT>::count))
|
||||
return byte_str_t (CFFIndex<COUNT>::data_base () + CFFIndex<COUNT>::offset_at (index) - 1, CFFIndex<COUNT>::length_at (index));
|
||||
return Null(byte_str_t);
|
||||
return Null (byte_str_t);
|
||||
}
|
||||
|
||||
template <typename DATA, typename PARAM1, typename PARAM2>
|
||||
@ -275,9 +336,9 @@ struct CFFIndexOf : CFFIndex<COUNT>
|
||||
TRACE_SERIALIZE (this);
|
||||
/* serialize CFFIndex header */
|
||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||
this->count.set (dataArrayLen);
|
||||
this->offSize.set (offSize_);
|
||||
if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1))))
|
||||
this->count = dataArrayLen;
|
||||
this->offSize = offSize_;
|
||||
if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1))))
|
||||
return_trace (false);
|
||||
|
||||
/* serialize indices */
|
||||
@ -293,112 +354,74 @@ struct CFFIndexOf : CFFIndex<COUNT>
|
||||
/* serialize data */
|
||||
for (unsigned int i = 0; i < dataArrayLen; i++)
|
||||
{
|
||||
TYPE *dest = c->start_embed<TYPE> ();
|
||||
if (unlikely (dest == nullptr ||
|
||||
!dest->serialize (c, dataArray[i], param1, param2)))
|
||||
TYPE *dest = c->start_embed<TYPE> ();
|
||||
if (unlikely (!dest || !dest->serialize (c, dataArray[i], param1, param2)))
|
||||
return_trace (false);
|
||||
}
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
/* in parallel to above */
|
||||
template <typename DATA, typename PARAM>
|
||||
static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */,
|
||||
const DATA *dataArray,
|
||||
unsigned int dataArrayLen,
|
||||
hb_vector_t<unsigned int> &dataSizeArray, /* OUT */
|
||||
const PARAM ¶m)
|
||||
{
|
||||
/* determine offset size */
|
||||
unsigned int totalDataSize = 0;
|
||||
for (unsigned int i = 0; i < dataArrayLen; i++)
|
||||
{
|
||||
unsigned int dataSize = TYPE::calculate_serialized_size (dataArray[i], param);
|
||||
dataSizeArray[i] = dataSize;
|
||||
totalDataSize += dataSize;
|
||||
}
|
||||
offSize_ = calcOffSize (totalDataSize);
|
||||
|
||||
return CFFIndex<COUNT>::calculate_serialized_size (offSize_, dataArrayLen, totalDataSize);
|
||||
}
|
||||
};
|
||||
|
||||
/* Top Dict, Font Dict, Private Dict */
|
||||
struct Dict : UnsizedByteStr
|
||||
{
|
||||
template <typename DICTVAL, typename OP_SERIALIZER, typename PARAM>
|
||||
template <typename DICTVAL, typename OP_SERIALIZER, typename ...Ts>
|
||||
bool serialize (hb_serialize_context_t *c,
|
||||
const DICTVAL &dictval,
|
||||
OP_SERIALIZER& opszr,
|
||||
PARAM& param)
|
||||
Ts&&... ds)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
for (unsigned int i = 0; i < dictval.get_count (); i++)
|
||||
{
|
||||
if (unlikely (!opszr.serialize (c, dictval[i], param)))
|
||||
if (unlikely (!opszr.serialize (c, dictval[i], hb_forward<Ts> (ds)...)))
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
/* in parallel to above */
|
||||
template <typename DICTVAL, typename OP_SERIALIZER, typename PARAM>
|
||||
static unsigned int calculate_serialized_size (const DICTVAL &dictval,
|
||||
OP_SERIALIZER& opszr,
|
||||
PARAM& param)
|
||||
{
|
||||
unsigned int size = 0;
|
||||
for (unsigned int i = 0; i < dictval.get_count (); i++)
|
||||
size += opszr.calculate_serialized_size (dictval[i], param);
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename DICTVAL, typename OP_SERIALIZER>
|
||||
static unsigned int calculate_serialized_size (const DICTVAL &dictval,
|
||||
OP_SERIALIZER& opszr)
|
||||
{
|
||||
unsigned int size = 0;
|
||||
for (unsigned int i = 0; i < dictval.get_count (); i++)
|
||||
size += opszr.calculate_serialized_size (dictval[i]);
|
||||
return size;
|
||||
}
|
||||
|
||||
template <typename INTTYPE, int minVal, int maxVal>
|
||||
static bool serialize_int_op (hb_serialize_context_t *c, op_code_t op, int value, op_code_t intOp)
|
||||
template <typename T, typename V>
|
||||
static bool serialize_int_op (hb_serialize_context_t *c, op_code_t op, V value, op_code_t intOp)
|
||||
{
|
||||
// XXX: not sure why but LLVM fails to compile the following 'unlikely' macro invocation
|
||||
if (/*unlikely*/ (!serialize_int<INTTYPE, minVal, maxVal> (c, intOp, value)))
|
||||
if (/*unlikely*/ (!serialize_int<T, V> (c, intOp, value)))
|
||||
return false;
|
||||
|
||||
TRACE_SERIALIZE (this);
|
||||
/* serialize the opcode */
|
||||
HBUINT8 *p = c->allocate_size<HBUINT8> (OpCode_Size (op));
|
||||
if (unlikely (p == nullptr)) return_trace (false);
|
||||
if (unlikely (!p)) return_trace (false);
|
||||
if (Is_OpCode_ESC (op))
|
||||
{
|
||||
p->set (OpCode_escape);
|
||||
*p = OpCode_escape;
|
||||
op = Unmake_OpCode_ESC (op);
|
||||
p++;
|
||||
}
|
||||
p->set (op);
|
||||
*p = op;
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
static bool serialize_uint4_op (hb_serialize_context_t *c, op_code_t op, int value)
|
||||
{ return serialize_int_op<HBUINT32, 0, 0x7FFFFFFF> (c, op, value, OpCode_longintdict); }
|
||||
template <typename V>
|
||||
static bool serialize_int4_op (hb_serialize_context_t *c, op_code_t op, V value)
|
||||
{ return serialize_int_op<HBINT32> (c, op, value, OpCode_longintdict); }
|
||||
|
||||
static bool serialize_uint2_op (hb_serialize_context_t *c, op_code_t op, int value)
|
||||
{ return serialize_int_op<HBUINT16, 0, 0x7FFF> (c, op, value, OpCode_shortint); }
|
||||
template <typename V>
|
||||
static bool serialize_int2_op (hb_serialize_context_t *c, op_code_t op, V value)
|
||||
{ return serialize_int_op<HBINT16> (c, op, value, OpCode_shortint); }
|
||||
|
||||
static bool serialize_offset4_op (hb_serialize_context_t *c, op_code_t op, int value)
|
||||
template <typename T, int int_op>
|
||||
static bool serialize_link_op (hb_serialize_context_t *c, op_code_t op, objidx_t link, whence_t whence)
|
||||
{
|
||||
return serialize_uint4_op (c, op, value);
|
||||
T &ofs = *(T *) (c->head + OpCode_Size (int_op));
|
||||
if (unlikely (!serialize_int_op<T> (c, op, 0, int_op))) return false;
|
||||
c->add_link (ofs, link, whence);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool serialize_offset2_op (hb_serialize_context_t *c, op_code_t op, int value)
|
||||
{
|
||||
return serialize_uint2_op (c, op, value);
|
||||
}
|
||||
static bool serialize_link4_op (hb_serialize_context_t *c, op_code_t op, objidx_t link, whence_t whence = whence_t::Head)
|
||||
{ return serialize_link_op<HBINT32, OpCode_longintdict> (c, op, link, whence); }
|
||||
|
||||
static bool serialize_link2_op (hb_serialize_context_t *c, op_code_t op, objidx_t link, whence_t whence = whence_t::Head)
|
||||
{ return serialize_link_op<HBINT16, OpCode_shortint> (c, op, link, whence); }
|
||||
};
|
||||
|
||||
struct TopDict : Dict {};
|
||||
@ -407,155 +430,39 @@ struct PrivateDict : Dict {};
|
||||
|
||||
struct table_info_t
|
||||
{
|
||||
void init () { offSize = offset = size = 0; }
|
||||
void init () { offset = size = 0; link = 0; }
|
||||
|
||||
unsigned int offset;
|
||||
unsigned int size;
|
||||
unsigned int offSize;
|
||||
};
|
||||
|
||||
/* used to remap font index or SID from fullset to subset.
|
||||
* set to CFF_UNDEF_CODE if excluded from subset */
|
||||
struct remap_t : hb_vector_t<hb_codepoint_t>
|
||||
{
|
||||
void init () { SUPER::init (); }
|
||||
|
||||
void fini () { SUPER::fini (); }
|
||||
|
||||
bool reset (unsigned int size)
|
||||
{
|
||||
if (unlikely (!SUPER::resize (size)))
|
||||
return false;
|
||||
for (unsigned int i = 0; i < length; i++)
|
||||
(*this)[i] = CFF_UNDEF_CODE;
|
||||
count = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool identity (unsigned int size)
|
||||
{
|
||||
if (unlikely (!SUPER::resize (size)))
|
||||
return false;
|
||||
unsigned int i;
|
||||
for (i = 0; i < length; i++)
|
||||
(*this)[i] = i;
|
||||
count = i;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool excludes (hb_codepoint_t id) const
|
||||
{ return (id < length) && ((*this)[id] == CFF_UNDEF_CODE); }
|
||||
|
||||
bool includes (hb_codepoint_t id) const
|
||||
{ return !excludes (id); }
|
||||
|
||||
unsigned int add (unsigned int i)
|
||||
{
|
||||
if ((*this)[i] == CFF_UNDEF_CODE)
|
||||
(*this)[i] = count++;
|
||||
return (*this)[i];
|
||||
}
|
||||
|
||||
hb_codepoint_t get_count () const { return count; }
|
||||
|
||||
protected:
|
||||
hb_codepoint_t count;
|
||||
|
||||
private:
|
||||
typedef hb_vector_t<hb_codepoint_t> SUPER;
|
||||
objidx_t link;
|
||||
};
|
||||
|
||||
template <typename COUNT>
|
||||
struct FDArray : CFFIndexOf<COUNT, FontDict>
|
||||
{
|
||||
/* used by CFF1 */
|
||||
template <typename DICTVAL, typename OP_SERIALIZER>
|
||||
template <typename DICTVAL, typename INFO, typename Iterator, typename OP_SERIALIZER>
|
||||
bool serialize (hb_serialize_context_t *c,
|
||||
unsigned int offSize_,
|
||||
const hb_vector_t<DICTVAL> &fontDicts,
|
||||
Iterator it,
|
||||
OP_SERIALIZER& opszr)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||
this->count.set (fontDicts.length);
|
||||
this->offSize.set (offSize_);
|
||||
if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (fontDicts.length + 1))))
|
||||
return_trace (false);
|
||||
|
||||
/* serialize font dict offsets */
|
||||
unsigned int offset = 1;
|
||||
unsigned int fid = 0;
|
||||
for (; fid < fontDicts.length; fid++)
|
||||
{
|
||||
CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset);
|
||||
offset += FontDict::calculate_serialized_size (fontDicts[fid], opszr);
|
||||
}
|
||||
CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset);
|
||||
|
||||
/* serialize font dicts */
|
||||
for (unsigned int i = 0; i < fontDicts.length; i++)
|
||||
/* serialize INDEX data */
|
||||
hb_vector_t<unsigned> sizes;
|
||||
c->push ();
|
||||
+ it
|
||||
| hb_map ([&] (const hb_pair_t<const DICTVAL&, const INFO&> &_)
|
||||
{
|
||||
FontDict *dict = c->start_embed<FontDict> ();
|
||||
if (unlikely (!dict->serialize (c, fontDicts[i], opszr, fontDicts[i])))
|
||||
return_trace (false);
|
||||
}
|
||||
return_trace (true);
|
||||
}
|
||||
dict->serialize (c, _.first, opszr, _.second);
|
||||
return c->head - (const char*)dict;
|
||||
})
|
||||
| hb_sink (sizes)
|
||||
;
|
||||
c->pop_pack (false);
|
||||
|
||||
/* used by CFF2 */
|
||||
template <typename DICTVAL, typename OP_SERIALIZER>
|
||||
bool serialize (hb_serialize_context_t *c,
|
||||
unsigned int offSize_,
|
||||
const hb_vector_t<DICTVAL> &fontDicts,
|
||||
unsigned int fdCount,
|
||||
const remap_t &fdmap,
|
||||
OP_SERIALIZER& opszr,
|
||||
const hb_vector_t<table_info_t> &privateInfos)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||
this->count.set (fdCount);
|
||||
this->offSize.set (offSize_);
|
||||
if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (fdCount + 1))))
|
||||
return_trace (false);
|
||||
|
||||
/* serialize font dict offsets */
|
||||
unsigned int offset = 1;
|
||||
unsigned int fid = 0;
|
||||
for (unsigned i = 0; i < fontDicts.length; i++)
|
||||
if (fdmap.includes (i))
|
||||
{
|
||||
CFFIndexOf<COUNT, FontDict>::set_offset_at (fid++, offset);
|
||||
offset += FontDict::calculate_serialized_size (fontDicts[i], opszr);
|
||||
}
|
||||
CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset);
|
||||
|
||||
/* serialize font dicts */
|
||||
for (unsigned int i = 0; i < fontDicts.length; i++)
|
||||
if (fdmap.includes (i))
|
||||
{
|
||||
FontDict *dict = c->start_embed<FontDict> ();
|
||||
if (unlikely (!dict->serialize (c, fontDicts[i], opszr, privateInfos[fdmap[i]])))
|
||||
return_trace (false);
|
||||
}
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
/* in parallel to above */
|
||||
template <typename OP_SERIALIZER, typename DICTVAL>
|
||||
static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */,
|
||||
const hb_vector_t<DICTVAL> &fontDicts,
|
||||
unsigned int fdCount,
|
||||
const remap_t &fdmap,
|
||||
OP_SERIALIZER& opszr)
|
||||
{
|
||||
unsigned int dictsSize = 0;
|
||||
for (unsigned int i = 0; i < fontDicts.len; i++)
|
||||
if (fdmap.includes (i))
|
||||
dictsSize += FontDict::calculate_serialized_size (fontDicts[i], opszr);
|
||||
|
||||
offSize_ = calcOffSize (dictsSize);
|
||||
return CFFIndex<COUNT>::calculate_serialized_size (offSize_, fdCount, dictsSize);
|
||||
/* serialize INDEX header */
|
||||
return_trace (CFFIndex<COUNT>::serialize_header (c, hb_iter (sizes)));
|
||||
}
|
||||
};
|
||||
|
||||
@ -574,21 +481,20 @@ struct FDSelect0 {
|
||||
}
|
||||
|
||||
hb_codepoint_t get_fd (hb_codepoint_t glyph) const
|
||||
{
|
||||
return (hb_codepoint_t)fds[glyph];
|
||||
}
|
||||
{ return (hb_codepoint_t) fds[glyph]; }
|
||||
|
||||
unsigned int get_size (unsigned int num_glyphs) const
|
||||
{ return HBUINT8::static_size * num_glyphs; }
|
||||
|
||||
HBUINT8 fds[VAR];
|
||||
HBUINT8 fds[HB_VAR_ARRAY];
|
||||
|
||||
DEFINE_SIZE_MIN (1);
|
||||
DEFINE_SIZE_MIN (0);
|
||||
};
|
||||
|
||||
template <typename GID_TYPE, typename FD_TYPE>
|
||||
struct FDSelect3_4_Range {
|
||||
bool sanitize (hb_sanitize_context_t *c, const void */*nullptr*/, unsigned int fdcount) const
|
||||
struct FDSelect3_4_Range
|
||||
{
|
||||
bool sanitize (hb_sanitize_context_t *c, const void * /*nullptr*/, unsigned int fdcount) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (first < c->get_num_glyphs () && (fd < fdcount));
|
||||
@ -596,12 +502,13 @@ struct FDSelect3_4_Range {
|
||||
|
||||
GID_TYPE first;
|
||||
FD_TYPE fd;
|
||||
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (GID_TYPE::static_size + FD_TYPE::static_size);
|
||||
};
|
||||
|
||||
template <typename GID_TYPE, typename FD_TYPE>
|
||||
struct FDSelect3_4 {
|
||||
struct FDSelect3_4
|
||||
{
|
||||
unsigned int get_size () const
|
||||
{ return GID_TYPE::static_size * 2 + ranges.get_size (); }
|
||||
|
||||
@ -613,10 +520,8 @@ struct FDSelect3_4 {
|
||||
return_trace (false);
|
||||
|
||||
for (unsigned int i = 1; i < nRanges (); i++)
|
||||
{
|
||||
if (unlikely (ranges[i - 1].first >= ranges[i].first))
|
||||
return_trace (false);
|
||||
}
|
||||
return_trace (false);
|
||||
|
||||
if (unlikely (!sentinel().sanitize (c) || (sentinel() != c->get_num_glyphs ())))
|
||||
return_trace (false);
|
||||
@ -631,13 +536,13 @@ struct FDSelect3_4 {
|
||||
if (glyph < ranges[i].first)
|
||||
break;
|
||||
|
||||
return (hb_codepoint_t)ranges[i - 1].fd;
|
||||
return (hb_codepoint_t) ranges[i - 1].fd;
|
||||
}
|
||||
|
||||
GID_TYPE &nRanges () { return ranges.len; }
|
||||
GID_TYPE nRanges () const { return ranges.len; }
|
||||
GID_TYPE &sentinel () { return StructAfter<GID_TYPE> (ranges[nRanges () - 1]); }
|
||||
const GID_TYPE &sentinel () const { return StructAfter<GID_TYPE> (ranges[nRanges () - 1]); }
|
||||
GID_TYPE &nRanges () { return ranges.len; }
|
||||
GID_TYPE nRanges () const { return ranges.len; }
|
||||
GID_TYPE &sentinel () { return StructAfter<GID_TYPE> (ranges[nRanges () - 1]); }
|
||||
const GID_TYPE &sentinel () const { return StructAfter<GID_TYPE> (ranges[nRanges () - 1]); }
|
||||
|
||||
ArrayOf<FDSelect3_4_Range<GID_TYPE, FD_TYPE>, GID_TYPE> ranges;
|
||||
/* GID_TYPE sentinel */
|
||||
@ -648,56 +553,60 @@ struct FDSelect3_4 {
|
||||
typedef FDSelect3_4<HBUINT16, HBUINT8> FDSelect3;
|
||||
typedef FDSelect3_4_Range<HBUINT16, HBUINT8> FDSelect3_Range;
|
||||
|
||||
struct FDSelect {
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
||||
return_trace (likely (c->check_struct (this) && (format == 0 || format == 3) &&
|
||||
(format == 0)?
|
||||
u.format0.sanitize (c, fdcount):
|
||||
u.format3.sanitize (c, fdcount)));
|
||||
}
|
||||
|
||||
struct FDSelect
|
||||
{
|
||||
bool serialize (hb_serialize_context_t *c, const FDSelect &src, unsigned int num_glyphs)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
unsigned int size = src.get_size (num_glyphs);
|
||||
FDSelect *dest = c->allocate_size<FDSelect> (size);
|
||||
if (unlikely (dest == nullptr)) return_trace (false);
|
||||
if (unlikely (!dest)) return_trace (false);
|
||||
memcpy (dest, &src, size);
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
unsigned int calculate_serialized_size (unsigned int num_glyphs) const
|
||||
{ return get_size (num_glyphs); }
|
||||
|
||||
unsigned int get_size (unsigned int num_glyphs) const
|
||||
{
|
||||
unsigned int size = format.static_size;
|
||||
if (format == 0)
|
||||
size += u.format0.get_size (num_glyphs);
|
||||
else
|
||||
size += u.format3.get_size ();
|
||||
return size;
|
||||
switch (format)
|
||||
{
|
||||
case 0: return format.static_size + u.format0.get_size (num_glyphs);
|
||||
case 3: return format.static_size + u.format3.get_size ();
|
||||
default:return 0;
|
||||
}
|
||||
}
|
||||
|
||||
hb_codepoint_t get_fd (hb_codepoint_t glyph) const
|
||||
{
|
||||
if (this == &Null(FDSelect))
|
||||
return 0;
|
||||
if (format == 0)
|
||||
return u.format0.get_fd (glyph);
|
||||
else
|
||||
return u.format3.get_fd (glyph);
|
||||
if (this == &Null (FDSelect)) return 0;
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case 0: return u.format0.get_fd (glyph);
|
||||
case 3: return u.format3.get_fd (glyph);
|
||||
default:return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!c->check_struct (this)))
|
||||
return_trace (false);
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case 0: return_trace (u.format0.sanitize (c, fdcount));
|
||||
case 3: return_trace (u.format3.sanitize (c, fdcount));
|
||||
default:return_trace (false);
|
||||
}
|
||||
}
|
||||
|
||||
HBUINT8 format;
|
||||
union {
|
||||
FDSelect0 format0;
|
||||
FDSelect3 format3;
|
||||
FDSelect0 format0;
|
||||
FDSelect3 format3;
|
||||
} u;
|
||||
|
||||
public:
|
||||
DEFINE_SIZE_MIN (1);
|
||||
};
|
||||
|
||||
|
||||
425
src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-std-str.hh
Normal file
425
src/java.desktop/share/native/libharfbuzz/hb-ot-cff1-std-str.hh
Normal file
@ -0,0 +1,425 @@
|
||||
/*
|
||||
* Copyright © 2019 Adobe, 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.
|
||||
*
|
||||
* Adobe Author(s): Michiharu Ariza
|
||||
*/
|
||||
|
||||
#ifndef HB_OT_CFF1_STD_STR_HH
|
||||
#if 0 /* Make checks happy. */
|
||||
#define HB_OT_CFF1_STD_STR_HH
|
||||
#include "hb.hh"
|
||||
#endif
|
||||
|
||||
_S(".notdef")
|
||||
_S("space")
|
||||
_S("exclam")
|
||||
_S("quotedbl")
|
||||
_S("numbersign")
|
||||
_S("dollar")
|
||||
_S("percent")
|
||||
_S("ampersand")
|
||||
_S("quoteright")
|
||||
_S("parenleft")
|
||||
_S("parenright")
|
||||
_S("asterisk")
|
||||
_S("plus")
|
||||
_S("comma")
|
||||
_S("hyphen")
|
||||
_S("period")
|
||||
_S("slash")
|
||||
_S("zero")
|
||||
_S("one")
|
||||
_S("two")
|
||||
_S("three")
|
||||
_S("four")
|
||||
_S("five")
|
||||
_S("six")
|
||||
_S("seven")
|
||||
_S("eight")
|
||||
_S("nine")
|
||||
_S("colon")
|
||||
_S("semicolon")
|
||||
_S("less")
|
||||
_S("equal")
|
||||
_S("greater")
|
||||
_S("question")
|
||||
_S("at")
|
||||
_S("A")
|
||||
_S("B")
|
||||
_S("C")
|
||||
_S("D")
|
||||
_S("E")
|
||||
_S("F")
|
||||
_S("G")
|
||||
_S("H")
|
||||
_S("I")
|
||||
_S("J")
|
||||
_S("K")
|
||||
_S("L")
|
||||
_S("M")
|
||||
_S("N")
|
||||
_S("O")
|
||||
_S("P")
|
||||
_S("Q")
|
||||
_S("R")
|
||||
_S("S")
|
||||
_S("T")
|
||||
_S("U")
|
||||
_S("V")
|
||||
_S("W")
|
||||
_S("X")
|
||||
_S("Y")
|
||||
_S("Z")
|
||||
_S("bracketleft")
|
||||
_S("backslash")
|
||||
_S("bracketright")
|
||||
_S("asciicircum")
|
||||
_S("underscore")
|
||||
_S("quoteleft")
|
||||
_S("a")
|
||||
_S("b")
|
||||
_S("c")
|
||||
_S("d")
|
||||
_S("e")
|
||||
_S("f")
|
||||
_S("g")
|
||||
_S("h")
|
||||
_S("i")
|
||||
_S("j")
|
||||
_S("k")
|
||||
_S("l")
|
||||
_S("m")
|
||||
_S("n")
|
||||
_S("o")
|
||||
_S("p")
|
||||
_S("q")
|
||||
_S("r")
|
||||
_S("s")
|
||||
_S("t")
|
||||
_S("u")
|
||||
_S("v")
|
||||
_S("w")
|
||||
_S("x")
|
||||
_S("y")
|
||||
_S("z")
|
||||
_S("braceleft")
|
||||
_S("bar")
|
||||
_S("braceright")
|
||||
_S("asciitilde")
|
||||
_S("exclamdown")
|
||||
_S("cent")
|
||||
_S("sterling")
|
||||
_S("fraction")
|
||||
_S("yen")
|
||||
_S("florin")
|
||||
_S("section")
|
||||
_S("currency")
|
||||
_S("quotesingle")
|
||||
_S("quotedblleft")
|
||||
_S("guillemotleft")
|
||||
_S("guilsinglleft")
|
||||
_S("guilsinglright")
|
||||
_S("fi")
|
||||
_S("fl")
|
||||
_S("endash")
|
||||
_S("dagger")
|
||||
_S("daggerdbl")
|
||||
_S("periodcentered")
|
||||
_S("paragraph")
|
||||
_S("bullet")
|
||||
_S("quotesinglbase")
|
||||
_S("quotedblbase")
|
||||
_S("quotedblright")
|
||||
_S("guillemotright")
|
||||
_S("ellipsis")
|
||||
_S("perthousand")
|
||||
_S("questiondown")
|
||||
_S("grave")
|
||||
_S("acute")
|
||||
_S("circumflex")
|
||||
_S("tilde")
|
||||
_S("macron")
|
||||
_S("breve")
|
||||
_S("dotaccent")
|
||||
_S("dieresis")
|
||||
_S("ring")
|
||||
_S("cedilla")
|
||||
_S("hungarumlaut")
|
||||
_S("ogonek")
|
||||
_S("caron")
|
||||
_S("emdash")
|
||||
_S("AE")
|
||||
_S("ordfeminine")
|
||||
_S("Lslash")
|
||||
_S("Oslash")
|
||||
_S("OE")
|
||||
_S("ordmasculine")
|
||||
_S("ae")
|
||||
_S("dotlessi")
|
||||
_S("lslash")
|
||||
_S("oslash")
|
||||
_S("oe")
|
||||
_S("germandbls")
|
||||
_S("onesuperior")
|
||||
_S("logicalnot")
|
||||
_S("mu")
|
||||
_S("trademark")
|
||||
_S("Eth")
|
||||
_S("onehalf")
|
||||
_S("plusminus")
|
||||
_S("Thorn")
|
||||
_S("onequarter")
|
||||
_S("divide")
|
||||
_S("brokenbar")
|
||||
_S("degree")
|
||||
_S("thorn")
|
||||
_S("threequarters")
|
||||
_S("twosuperior")
|
||||
_S("registered")
|
||||
_S("minus")
|
||||
_S("eth")
|
||||
_S("multiply")
|
||||
_S("threesuperior")
|
||||
_S("copyright")
|
||||
_S("Aacute")
|
||||
_S("Acircumflex")
|
||||
_S("Adieresis")
|
||||
_S("Agrave")
|
||||
_S("Aring")
|
||||
_S("Atilde")
|
||||
_S("Ccedilla")
|
||||
_S("Eacute")
|
||||
_S("Ecircumflex")
|
||||
_S("Edieresis")
|
||||
_S("Egrave")
|
||||
_S("Iacute")
|
||||
_S("Icircumflex")
|
||||
_S("Idieresis")
|
||||
_S("Igrave")
|
||||
_S("Ntilde")
|
||||
_S("Oacute")
|
||||
_S("Ocircumflex")
|
||||
_S("Odieresis")
|
||||
_S("Ograve")
|
||||
_S("Otilde")
|
||||
_S("Scaron")
|
||||
_S("Uacute")
|
||||
_S("Ucircumflex")
|
||||
_S("Udieresis")
|
||||
_S("Ugrave")
|
||||
_S("Yacute")
|
||||
_S("Ydieresis")
|
||||
_S("Zcaron")
|
||||
_S("aacute")
|
||||
_S("acircumflex")
|
||||
_S("adieresis")
|
||||
_S("agrave")
|
||||
_S("aring")
|
||||
_S("atilde")
|
||||
_S("ccedilla")
|
||||
_S("eacute")
|
||||
_S("ecircumflex")
|
||||
_S("edieresis")
|
||||
_S("egrave")
|
||||
_S("iacute")
|
||||
_S("icircumflex")
|
||||
_S("idieresis")
|
||||
_S("igrave")
|
||||
_S("ntilde")
|
||||
_S("oacute")
|
||||
_S("ocircumflex")
|
||||
_S("odieresis")
|
||||
_S("ograve")
|
||||
_S("otilde")
|
||||
_S("scaron")
|
||||
_S("uacute")
|
||||
_S("ucircumflex")
|
||||
_S("udieresis")
|
||||
_S("ugrave")
|
||||
_S("yacute")
|
||||
_S("ydieresis")
|
||||
_S("zcaron")
|
||||
_S("exclamsmall")
|
||||
_S("Hungarumlautsmall")
|
||||
_S("dollaroldstyle")
|
||||
_S("dollarsuperior")
|
||||
_S("ampersandsmall")
|
||||
_S("Acutesmall")
|
||||
_S("parenleftsuperior")
|
||||
_S("parenrightsuperior")
|
||||
_S("twodotenleader")
|
||||
_S("onedotenleader")
|
||||
_S("zerooldstyle")
|
||||
_S("oneoldstyle")
|
||||
_S("twooldstyle")
|
||||
_S("threeoldstyle")
|
||||
_S("fouroldstyle")
|
||||
_S("fiveoldstyle")
|
||||
_S("sixoldstyle")
|
||||
_S("sevenoldstyle")
|
||||
_S("eightoldstyle")
|
||||
_S("nineoldstyle")
|
||||
_S("commasuperior")
|
||||
_S("threequartersemdash")
|
||||
_S("periodsuperior")
|
||||
_S("questionsmall")
|
||||
_S("asuperior")
|
||||
_S("bsuperior")
|
||||
_S("centsuperior")
|
||||
_S("dsuperior")
|
||||
_S("esuperior")
|
||||
_S("isuperior")
|
||||
_S("lsuperior")
|
||||
_S("msuperior")
|
||||
_S("nsuperior")
|
||||
_S("osuperior")
|
||||
_S("rsuperior")
|
||||
_S("ssuperior")
|
||||
_S("tsuperior")
|
||||
_S("ff")
|
||||
_S("ffi")
|
||||
_S("ffl")
|
||||
_S("parenleftinferior")
|
||||
_S("parenrightinferior")
|
||||
_S("Circumflexsmall")
|
||||
_S("hyphensuperior")
|
||||
_S("Gravesmall")
|
||||
_S("Asmall")
|
||||
_S("Bsmall")
|
||||
_S("Csmall")
|
||||
_S("Dsmall")
|
||||
_S("Esmall")
|
||||
_S("Fsmall")
|
||||
_S("Gsmall")
|
||||
_S("Hsmall")
|
||||
_S("Ismall")
|
||||
_S("Jsmall")
|
||||
_S("Ksmall")
|
||||
_S("Lsmall")
|
||||
_S("Msmall")
|
||||
_S("Nsmall")
|
||||
_S("Osmall")
|
||||
_S("Psmall")
|
||||
_S("Qsmall")
|
||||
_S("Rsmall")
|
||||
_S("Ssmall")
|
||||
_S("Tsmall")
|
||||
_S("Usmall")
|
||||
_S("Vsmall")
|
||||
_S("Wsmall")
|
||||
_S("Xsmall")
|
||||
_S("Ysmall")
|
||||
_S("Zsmall")
|
||||
_S("colonmonetary")
|
||||
_S("onefitted")
|
||||
_S("rupiah")
|
||||
_S("Tildesmall")
|
||||
_S("exclamdownsmall")
|
||||
_S("centoldstyle")
|
||||
_S("Lslashsmall")
|
||||
_S("Scaronsmall")
|
||||
_S("Zcaronsmall")
|
||||
_S("Dieresissmall")
|
||||
_S("Brevesmall")
|
||||
_S("Caronsmall")
|
||||
_S("Dotaccentsmall")
|
||||
_S("Macronsmall")
|
||||
_S("figuredash")
|
||||
_S("hypheninferior")
|
||||
_S("Ogoneksmall")
|
||||
_S("Ringsmall")
|
||||
_S("Cedillasmall")
|
||||
_S("questiondownsmall")
|
||||
_S("oneeighth")
|
||||
_S("threeeighths")
|
||||
_S("fiveeighths")
|
||||
_S("seveneighths")
|
||||
_S("onethird")
|
||||
_S("twothirds")
|
||||
_S("zerosuperior")
|
||||
_S("foursuperior")
|
||||
_S("fivesuperior")
|
||||
_S("sixsuperior")
|
||||
_S("sevensuperior")
|
||||
_S("eightsuperior")
|
||||
_S("ninesuperior")
|
||||
_S("zeroinferior")
|
||||
_S("oneinferior")
|
||||
_S("twoinferior")
|
||||
_S("threeinferior")
|
||||
_S("fourinferior")
|
||||
_S("fiveinferior")
|
||||
_S("sixinferior")
|
||||
_S("seveninferior")
|
||||
_S("eightinferior")
|
||||
_S("nineinferior")
|
||||
_S("centinferior")
|
||||
_S("dollarinferior")
|
||||
_S("periodinferior")
|
||||
_S("commainferior")
|
||||
_S("Agravesmall")
|
||||
_S("Aacutesmall")
|
||||
_S("Acircumflexsmall")
|
||||
_S("Atildesmall")
|
||||
_S("Adieresissmall")
|
||||
_S("Aringsmall")
|
||||
_S("AEsmall")
|
||||
_S("Ccedillasmall")
|
||||
_S("Egravesmall")
|
||||
_S("Eacutesmall")
|
||||
_S("Ecircumflexsmall")
|
||||
_S("Edieresissmall")
|
||||
_S("Igravesmall")
|
||||
_S("Iacutesmall")
|
||||
_S("Icircumflexsmall")
|
||||
_S("Idieresissmall")
|
||||
_S("Ethsmall")
|
||||
_S("Ntildesmall")
|
||||
_S("Ogravesmall")
|
||||
_S("Oacutesmall")
|
||||
_S("Ocircumflexsmall")
|
||||
_S("Otildesmall")
|
||||
_S("Odieresissmall")
|
||||
_S("OEsmall")
|
||||
_S("Oslashsmall")
|
||||
_S("Ugravesmall")
|
||||
_S("Uacutesmall")
|
||||
_S("Ucircumflexsmall")
|
||||
_S("Udieresissmall")
|
||||
_S("Yacutesmall")
|
||||
_S("Thornsmall")
|
||||
_S("Ydieresissmall")
|
||||
_S("001.000")
|
||||
_S("001.001")
|
||||
_S("001.002")
|
||||
_S("001.003")
|
||||
_S("Black")
|
||||
_S("Bold")
|
||||
_S("Book")
|
||||
_S("Light")
|
||||
_S("Medium")
|
||||
_S("Regular")
|
||||
_S("Roman")
|
||||
_S("Semibold")
|
||||
|
||||
#endif /* HB_OT_CFF1_STD_STR_HH */
|
||||
@ -24,11 +24,29 @@
|
||||
* Adobe Author(s): Michiharu Ariza
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#ifndef HB_NO_CFF
|
||||
|
||||
#include "hb-draw.hh"
|
||||
#include "hb-algs.hh"
|
||||
#include "hb-ot-cff1-table.hh"
|
||||
#include "hb-cff1-interp-cs.hh"
|
||||
|
||||
using namespace CFF;
|
||||
|
||||
struct sid_to_gid_t
|
||||
{
|
||||
uint16_t sid;
|
||||
uint8_t gid;
|
||||
|
||||
int cmp (uint16_t a) const
|
||||
{
|
||||
if (a == sid) return 0;
|
||||
return (a < sid) ? -1 : 1;
|
||||
}
|
||||
};
|
||||
|
||||
/* SID to code */
|
||||
static const uint8_t standard_encoding_to_code [] =
|
||||
{
|
||||
@ -100,6 +118,80 @@ static const uint16_t expert_subset_charset_to_sid [] =
|
||||
340, 341, 342, 343, 344, 345, 346
|
||||
};
|
||||
|
||||
/* SID to glyph ID */
|
||||
static const sid_to_gid_t expert_charset_sid_to_gid [] =
|
||||
{
|
||||
{ 1, 1 }, { 13, 12 }, { 14, 13 }, { 15, 14 },
|
||||
{ 27, 26 }, { 28, 27 }, { 99, 15 }, { 109, 46 },
|
||||
{ 110, 47 }, { 150, 111 }, { 155, 101 }, { 158, 100 },
|
||||
{ 163, 102 }, { 164, 112 }, { 169, 113 }, { 229, 2 },
|
||||
{ 230, 3 }, { 231, 4 }, { 232, 5 }, { 233, 6 },
|
||||
{ 234, 7 }, { 235, 8 }, { 236, 9 }, { 237, 10 },
|
||||
{ 238, 11 }, { 239, 16 }, { 240, 17 }, { 241, 18 },
|
||||
{ 242, 19 }, { 243, 20 }, { 244, 21 }, { 245, 22 },
|
||||
{ 246, 23 }, { 247, 24 }, { 248, 25 }, { 249, 28 },
|
||||
{ 250, 29 }, { 251, 30 }, { 252, 31 }, { 253, 32 },
|
||||
{ 254, 33 }, { 255, 34 }, { 256, 35 }, { 257, 36 },
|
||||
{ 258, 37 }, { 259, 38 }, { 260, 39 }, { 261, 40 },
|
||||
{ 262, 41 }, { 263, 42 }, { 264, 43 }, { 265, 44 },
|
||||
{ 266, 45 }, { 267, 48 }, { 268, 49 }, { 269, 50 },
|
||||
{ 270, 51 }, { 271, 52 }, { 272, 53 }, { 273, 54 },
|
||||
{ 274, 55 }, { 275, 56 }, { 276, 57 }, { 277, 58 },
|
||||
{ 278, 59 }, { 279, 60 }, { 280, 61 }, { 281, 62 },
|
||||
{ 282, 63 }, { 283, 64 }, { 284, 65 }, { 285, 66 },
|
||||
{ 286, 67 }, { 287, 68 }, { 288, 69 }, { 289, 70 },
|
||||
{ 290, 71 }, { 291, 72 }, { 292, 73 }, { 293, 74 },
|
||||
{ 294, 75 }, { 295, 76 }, { 296, 77 }, { 297, 78 },
|
||||
{ 298, 79 }, { 299, 80 }, { 300, 81 }, { 301, 82 },
|
||||
{ 302, 83 }, { 303, 84 }, { 304, 85 }, { 305, 86 },
|
||||
{ 306, 87 }, { 307, 88 }, { 308, 89 }, { 309, 90 },
|
||||
{ 310, 91 }, { 311, 92 }, { 312, 93 }, { 313, 94 },
|
||||
{ 314, 95 }, { 315, 96 }, { 316, 97 }, { 317, 98 },
|
||||
{ 318, 99 }, { 319, 103 }, { 320, 104 }, { 321, 105 },
|
||||
{ 322, 106 }, { 323, 107 }, { 324, 108 }, { 325, 109 },
|
||||
{ 326, 110 }, { 327, 114 }, { 328, 115 }, { 329, 116 },
|
||||
{ 330, 117 }, { 331, 118 }, { 332, 119 }, { 333, 120 },
|
||||
{ 334, 121 }, { 335, 122 }, { 336, 123 }, { 337, 124 },
|
||||
{ 338, 125 }, { 339, 126 }, { 340, 127 }, { 341, 128 },
|
||||
{ 342, 129 }, { 343, 130 }, { 344, 131 }, { 345, 132 },
|
||||
{ 346, 133 }, { 347, 134 }, { 348, 135 }, { 349, 136 },
|
||||
{ 350, 137 }, { 351, 138 }, { 352, 139 }, { 353, 140 },
|
||||
{ 354, 141 }, { 355, 142 }, { 356, 143 }, { 357, 144 },
|
||||
{ 358, 145 }, { 359, 146 }, { 360, 147 }, { 361, 148 },
|
||||
{ 362, 149 }, { 363, 150 }, { 364, 151 }, { 365, 152 },
|
||||
{ 366, 153 }, { 367, 154 }, { 368, 155 }, { 369, 156 },
|
||||
{ 370, 157 }, { 371, 158 }, { 372, 159 }, { 373, 160 },
|
||||
{ 374, 161 }, { 375, 162 }, { 376, 163 }, { 377, 164 },
|
||||
{ 378, 165 }
|
||||
};
|
||||
|
||||
/* SID to glyph ID */
|
||||
static const sid_to_gid_t expert_subset_charset_sid_to_gid [] =
|
||||
{
|
||||
{ 1, 1 }, { 13, 8 }, { 14, 9 }, { 15, 10 },
|
||||
{ 27, 22 }, { 28, 23 }, { 99, 11 }, { 109, 41 },
|
||||
{ 110, 42 }, { 150, 64 }, { 155, 55 }, { 158, 54 },
|
||||
{ 163, 56 }, { 164, 65 }, { 169, 66 }, { 231, 2 },
|
||||
{ 232, 3 }, { 235, 4 }, { 236, 5 }, { 237, 6 },
|
||||
{ 238, 7 }, { 239, 12 }, { 240, 13 }, { 241, 14 },
|
||||
{ 242, 15 }, { 243, 16 }, { 244, 17 }, { 245, 18 },
|
||||
{ 246, 19 }, { 247, 20 }, { 248, 21 }, { 249, 24 },
|
||||
{ 250, 25 }, { 251, 26 }, { 253, 27 }, { 254, 28 },
|
||||
{ 255, 29 }, { 256, 30 }, { 257, 31 }, { 258, 32 },
|
||||
{ 259, 33 }, { 260, 34 }, { 261, 35 }, { 262, 36 },
|
||||
{ 263, 37 }, { 264, 38 }, { 265, 39 }, { 266, 40 },
|
||||
{ 267, 43 }, { 268, 44 }, { 269, 45 }, { 270, 46 },
|
||||
{ 272, 47 }, { 300, 48 }, { 301, 49 }, { 302, 50 },
|
||||
{ 305, 51 }, { 314, 52 }, { 315, 53 }, { 320, 57 },
|
||||
{ 321, 58 }, { 322, 59 }, { 323, 60 }, { 324, 61 },
|
||||
{ 325, 62 }, { 326, 63 }, { 327, 67 }, { 328, 68 },
|
||||
{ 329, 69 }, { 330, 70 }, { 331, 71 }, { 332, 72 },
|
||||
{ 333, 73 }, { 334, 74 }, { 335, 75 }, { 336, 76 },
|
||||
{ 337, 77 }, { 338, 78 }, { 339, 79 }, { 340, 80 },
|
||||
{ 341, 81 }, { 342, 82 }, { 343, 83 }, { 344, 84 },
|
||||
{ 345, 85 }, { 346, 86 }
|
||||
};
|
||||
|
||||
/* code to SID */
|
||||
static const uint8_t standard_encoding_to_sid [] =
|
||||
{
|
||||
@ -153,6 +245,18 @@ hb_codepoint_t OT::cff1::lookup_expert_subset_charset_for_sid (hb_codepoint_t gl
|
||||
return 0;
|
||||
}
|
||||
|
||||
hb_codepoint_t OT::cff1::lookup_expert_charset_for_glyph (hb_codepoint_t sid)
|
||||
{
|
||||
const auto *pair = hb_sorted_array (expert_charset_sid_to_gid).bsearch (sid);
|
||||
return pair ? pair->gid : 0;
|
||||
}
|
||||
|
||||
hb_codepoint_t OT::cff1::lookup_expert_subset_charset_for_glyph (hb_codepoint_t sid)
|
||||
{
|
||||
const auto *pair = hb_sorted_array (expert_subset_charset_sid_to_gid).bsearch (sid);
|
||||
return pair ? pair->gid : 0;
|
||||
}
|
||||
|
||||
hb_codepoint_t OT::cff1::lookup_standard_encoding_for_sid (hb_codepoint_t code)
|
||||
{
|
||||
if (code < ARRAY_LENGTH (standard_encoding_to_sid))
|
||||
@ -165,8 +269,8 @@ struct bounds_t
|
||||
{
|
||||
void init ()
|
||||
{
|
||||
min.set_int (0x7FFFFFFF, 0x7FFFFFFF);
|
||||
max.set_int (-0x80000000, -0x80000000);
|
||||
min.set_int (INT_MAX, INT_MAX);
|
||||
max.set_int (INT_MIN, INT_MIN);
|
||||
}
|
||||
|
||||
void update (const point_t &pt)
|
||||
@ -199,14 +303,13 @@ struct bounds_t
|
||||
}
|
||||
}
|
||||
|
||||
bool empty () const
|
||||
{ return (min.x >= max.x) || (min.y >= max.y); }
|
||||
bool empty () const { return (min.x >= max.x) || (min.y >= max.y); }
|
||||
|
||||
point_t min;
|
||||
point_t max;
|
||||
};
|
||||
|
||||
struct extents_param_t
|
||||
struct cff1_extents_param_t
|
||||
{
|
||||
void init (const OT::cff1::accelerator_t *_cff)
|
||||
{
|
||||
@ -215,25 +318,25 @@ struct extents_param_t
|
||||
bounds.init ();
|
||||
}
|
||||
|
||||
void start_path () { path_open = true; }
|
||||
void end_path () { path_open = false; }
|
||||
void start_path () { path_open = true; }
|
||||
void end_path () { path_open = false; }
|
||||
bool is_path_open () const { return path_open; }
|
||||
|
||||
bool path_open;
|
||||
bounds_t bounds;
|
||||
bool path_open;
|
||||
bounds_t bounds;
|
||||
|
||||
const OT::cff1::accelerator_t *cff;
|
||||
};
|
||||
|
||||
struct cff1_path_procs_extents_t : path_procs_t<cff1_path_procs_extents_t, cff1_cs_interp_env_t, extents_param_t>
|
||||
struct cff1_path_procs_extents_t : path_procs_t<cff1_path_procs_extents_t, cff1_cs_interp_env_t, cff1_extents_param_t>
|
||||
{
|
||||
static void moveto (cff1_cs_interp_env_t &env, extents_param_t& param, const point_t &pt)
|
||||
static void moveto (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt)
|
||||
{
|
||||
param.end_path ();
|
||||
env.moveto (pt);
|
||||
}
|
||||
|
||||
static void line (cff1_cs_interp_env_t &env, extents_param_t& param, const point_t &pt1)
|
||||
static void line (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt1)
|
||||
{
|
||||
if (!param.is_path_open ())
|
||||
{
|
||||
@ -244,7 +347,7 @@ struct cff1_path_procs_extents_t : path_procs_t<cff1_path_procs_extents_t, cff1_
|
||||
param.bounds.update (env.get_pt ());
|
||||
}
|
||||
|
||||
static void curve (cff1_cs_interp_env_t &env, extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
|
||||
static void curve (cff1_cs_interp_env_t &env, cff1_extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
|
||||
{
|
||||
if (!param.is_path_open ())
|
||||
{
|
||||
@ -261,9 +364,9 @@ struct cff1_path_procs_extents_t : path_procs_t<cff1_path_procs_extents_t, cff1_
|
||||
|
||||
static bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, bounds_t &bounds, bool in_seac=false);
|
||||
|
||||
struct cff1_cs_opset_extents_t : cff1_cs_opset_t<cff1_cs_opset_extents_t, extents_param_t, cff1_path_procs_extents_t>
|
||||
struct cff1_cs_opset_extents_t : cff1_cs_opset_t<cff1_cs_opset_extents_t, cff1_extents_param_t, cff1_path_procs_extents_t>
|
||||
{
|
||||
static void process_seac (cff1_cs_interp_env_t &env, extents_param_t& param)
|
||||
static void process_seac (cff1_cs_interp_env_t &env, cff1_extents_param_t& param)
|
||||
{
|
||||
unsigned int n = env.argStack.get_count ();
|
||||
point_t delta;
|
||||
@ -292,20 +395,25 @@ bool _get_bounds (const OT::cff1::accelerator_t *cff, hb_codepoint_t glyph, boun
|
||||
if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false;
|
||||
|
||||
unsigned int fd = cff->fdSelect->get_fd (glyph);
|
||||
cff1_cs_interpreter_t<cff1_cs_opset_extents_t, extents_param_t> interp;
|
||||
cff1_cs_interpreter_t<cff1_cs_opset_extents_t, cff1_extents_param_t> interp;
|
||||
const byte_str_t str = (*cff->charStrings)[glyph];
|
||||
interp.env.init (str, *cff, fd);
|
||||
interp.env.set_in_seac (in_seac);
|
||||
extents_param_t param;
|
||||
cff1_extents_param_t param;
|
||||
param.init (cff);
|
||||
if (unlikely (!interp.interpret (param))) return false;
|
||||
bounds = param.bounds;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OT::cff1::accelerator_t::get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
|
||||
bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
|
||||
{
|
||||
bounds_t bounds;
|
||||
#ifdef HB_NO_OT_FONT_CFF
|
||||
/* XXX Remove check when this code moves to .hh file. */
|
||||
return true;
|
||||
#endif
|
||||
|
||||
bounds_t bounds;
|
||||
|
||||
if (!_get_bounds (this, glyph, bounds))
|
||||
return false;
|
||||
@ -317,8 +425,8 @@ bool OT::cff1::accelerator_t::get_extents (hb_codepoint_t glyph, hb_glyph_extent
|
||||
}
|
||||
else
|
||||
{
|
||||
extents->x_bearing = (int32_t)bounds.min.x.floor ();
|
||||
extents->width = (int32_t)bounds.max.x.ceil () - extents->x_bearing;
|
||||
extents->x_bearing = font->em_scalef_x (bounds.min.x.to_real ());
|
||||
extents->width = font->em_scalef_x (bounds.max.x.to_real () - bounds.min.x.to_real ());
|
||||
}
|
||||
if (bounds.min.y >= bounds.max.y)
|
||||
{
|
||||
@ -327,13 +435,137 @@ bool OT::cff1::accelerator_t::get_extents (hb_codepoint_t glyph, hb_glyph_extent
|
||||
}
|
||||
else
|
||||
{
|
||||
extents->y_bearing = (int32_t)bounds.max.y.ceil ();
|
||||
extents->height = (int32_t)bounds.min.y.floor () - extents->y_bearing;
|
||||
extents->y_bearing = font->em_scalef_y (bounds.max.y.to_real ());
|
||||
extents->height = font->em_scalef_y (bounds.min.y.to_real () - bounds.max.y.to_real ());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef HB_EXPERIMENTAL_API
|
||||
struct cff1_path_param_t
|
||||
{
|
||||
cff1_path_param_t (const OT::cff1::accelerator_t *cff_, hb_font_t *font_,
|
||||
draw_helper_t &draw_helper_, point_t *delta_)
|
||||
{
|
||||
draw_helper = &draw_helper_;
|
||||
cff = cff_;
|
||||
font = font_;
|
||||
delta = delta_;
|
||||
}
|
||||
|
||||
void move_to (const point_t &p)
|
||||
{
|
||||
point_t point = p;
|
||||
if (delta) point.move (*delta);
|
||||
draw_helper->move_to (font->em_scalef_x (point.x.to_real ()), font->em_scalef_y (point.y.to_real ()));
|
||||
}
|
||||
|
||||
void line_to (const point_t &p)
|
||||
{
|
||||
point_t point = p;
|
||||
if (delta) point.move (*delta);
|
||||
draw_helper->line_to (font->em_scalef_x (point.x.to_real ()), font->em_scalef_y (point.y.to_real ()));
|
||||
}
|
||||
|
||||
void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3)
|
||||
{
|
||||
point_t point1 = p1, point2 = p2, point3 = p3;
|
||||
if (delta)
|
||||
{
|
||||
point1.move (*delta);
|
||||
point2.move (*delta);
|
||||
point3.move (*delta);
|
||||
}
|
||||
draw_helper->cubic_to (font->em_scalef_x (point1.x.to_real ()), font->em_scalef_y (point1.y.to_real ()),
|
||||
font->em_scalef_x (point2.x.to_real ()), font->em_scalef_y (point2.y.to_real ()),
|
||||
font->em_scalef_x (point3.x.to_real ()), font->em_scalef_y (point3.y.to_real ()));
|
||||
}
|
||||
|
||||
void end_path () { draw_helper->end_path (); }
|
||||
|
||||
hb_font_t *font;
|
||||
draw_helper_t *draw_helper;
|
||||
point_t *delta;
|
||||
|
||||
const OT::cff1::accelerator_t *cff;
|
||||
};
|
||||
|
||||
struct cff1_path_procs_path_t : path_procs_t<cff1_path_procs_path_t, cff1_cs_interp_env_t, cff1_path_param_t>
|
||||
{
|
||||
static void moveto (cff1_cs_interp_env_t &env, cff1_path_param_t& param, const point_t &pt)
|
||||
{
|
||||
param.move_to (pt);
|
||||
env.moveto (pt);
|
||||
}
|
||||
|
||||
static void line (cff1_cs_interp_env_t &env, cff1_path_param_t ¶m, const point_t &pt1)
|
||||
{
|
||||
param.line_to (pt1);
|
||||
env.moveto (pt1);
|
||||
}
|
||||
|
||||
static void curve (cff1_cs_interp_env_t &env, cff1_path_param_t ¶m, const point_t &pt1, const point_t &pt2, const point_t &pt3)
|
||||
{
|
||||
param.cubic_to (pt1, pt2, pt3);
|
||||
env.moveto (pt3);
|
||||
}
|
||||
};
|
||||
|
||||
static bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph,
|
||||
draw_helper_t &draw_helper, bool in_seac = false, point_t *delta = nullptr);
|
||||
|
||||
struct cff1_cs_opset_path_t : cff1_cs_opset_t<cff1_cs_opset_path_t, cff1_path_param_t, cff1_path_procs_path_t>
|
||||
{
|
||||
static void process_seac (cff1_cs_interp_env_t &env, cff1_path_param_t& param)
|
||||
{
|
||||
/* End previous path */
|
||||
param.end_path ();
|
||||
|
||||
unsigned int n = env.argStack.get_count ();
|
||||
point_t delta;
|
||||
delta.x = env.argStack[n-4];
|
||||
delta.y = env.argStack[n-3];
|
||||
hb_codepoint_t base = param.cff->std_code_to_glyph (env.argStack[n-2].to_int ());
|
||||
hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ());
|
||||
|
||||
if (unlikely (!(!env.in_seac && base && accent
|
||||
&& _get_path (param.cff, param.font, base, *param.draw_helper, true)
|
||||
&& _get_path (param.cff, param.font, accent, *param.draw_helper, true, &delta))))
|
||||
env.set_error ();
|
||||
}
|
||||
};
|
||||
|
||||
bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph,
|
||||
draw_helper_t &draw_helper, bool in_seac, point_t *delta)
|
||||
{
|
||||
if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false;
|
||||
|
||||
unsigned int fd = cff->fdSelect->get_fd (glyph);
|
||||
cff1_cs_interpreter_t<cff1_cs_opset_path_t, cff1_path_param_t> interp;
|
||||
const byte_str_t str = (*cff->charStrings)[glyph];
|
||||
interp.env.init (str, *cff, fd);
|
||||
interp.env.set_in_seac (in_seac);
|
||||
cff1_path_param_t param (cff, font, draw_helper, delta);
|
||||
if (unlikely (!interp.interpret (param))) return false;
|
||||
|
||||
/* Let's end the path specially since it is called inside seac also */
|
||||
param.end_path ();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const
|
||||
{
|
||||
#ifdef HB_NO_OT_FONT_CFF
|
||||
/* XXX Remove check when this code moves to .hh file. */
|
||||
return true;
|
||||
#endif
|
||||
|
||||
return _get_path (this, font, glyph, draw_helper);
|
||||
}
|
||||
#endif
|
||||
|
||||
struct get_seac_param_t
|
||||
{
|
||||
void init (const OT::cff1::accelerator_t *_cff)
|
||||
@ -383,3 +615,6 @@ bool OT::cff1::accelerator_t::get_seac_components (hb_codepoint_t glyph, hb_code
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -24,24 +24,29 @@
|
||||
* Adobe Author(s): Michiharu Ariza
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#ifndef HB_NO_OT_FONT_CFF
|
||||
|
||||
#include "hb-ot-cff2-table.hh"
|
||||
#include "hb-cff2-interp-cs.hh"
|
||||
#include "hb-draw.hh"
|
||||
|
||||
using namespace CFF;
|
||||
|
||||
struct extents_param_t
|
||||
struct cff2_extents_param_t
|
||||
{
|
||||
void init ()
|
||||
{
|
||||
path_open = false;
|
||||
min_x.set_int (0x7FFFFFFF);
|
||||
min_y.set_int (0x7FFFFFFF);
|
||||
max_x.set_int (-0x80000000);
|
||||
max_y.set_int (-0x80000000);
|
||||
min_x.set_int (INT_MAX);
|
||||
min_y.set_int (INT_MAX);
|
||||
max_x.set_int (INT_MIN);
|
||||
max_y.set_int (INT_MIN);
|
||||
}
|
||||
|
||||
void start_path () { path_open = true; }
|
||||
void end_path () { path_open = false; }
|
||||
void start_path () { path_open = true; }
|
||||
void end_path () { path_open = false; }
|
||||
bool is_path_open () const { return path_open; }
|
||||
|
||||
void update_bounds (const point_t &pt)
|
||||
@ -59,15 +64,15 @@ struct extents_param_t
|
||||
number_t max_y;
|
||||
};
|
||||
|
||||
struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_cs_interp_env_t, extents_param_t>
|
||||
struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_cs_interp_env_t, cff2_extents_param_t>
|
||||
{
|
||||
static void moveto (cff2_cs_interp_env_t &env, extents_param_t& param, const point_t &pt)
|
||||
static void moveto (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt)
|
||||
{
|
||||
param.end_path ();
|
||||
env.moveto (pt);
|
||||
}
|
||||
|
||||
static void line (cff2_cs_interp_env_t &env, extents_param_t& param, const point_t &pt1)
|
||||
static void line (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt1)
|
||||
{
|
||||
if (!param.is_path_open ())
|
||||
{
|
||||
@ -78,7 +83,7 @@ struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_
|
||||
param.update_bounds (env.get_pt ());
|
||||
}
|
||||
|
||||
static void curve (cff2_cs_interp_env_t &env, extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
|
||||
static void curve (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
|
||||
{
|
||||
if (!param.is_path_open ())
|
||||
{
|
||||
@ -93,21 +98,24 @@ struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_
|
||||
}
|
||||
};
|
||||
|
||||
struct cff2_cs_opset_extents_t : cff2_cs_opset_t<cff2_cs_opset_extents_t, extents_param_t, cff2_path_procs_extents_t> {};
|
||||
struct cff2_cs_opset_extents_t : cff2_cs_opset_t<cff2_cs_opset_extents_t, cff2_extents_param_t, cff2_path_procs_extents_t> {};
|
||||
|
||||
bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
|
||||
hb_codepoint_t glyph,
|
||||
hb_glyph_extents_t *extents) const
|
||||
{
|
||||
#ifdef HB_NO_OT_FONT_CFF
|
||||
/* XXX Remove check when this code moves to .hh file. */
|
||||
return true;
|
||||
#endif
|
||||
|
||||
if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false;
|
||||
|
||||
unsigned int num_coords;
|
||||
const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
|
||||
unsigned int fd = fdSelect->get_fd (glyph);
|
||||
cff2_cs_interpreter_t<cff2_cs_opset_extents_t, extents_param_t> interp;
|
||||
cff2_cs_interpreter_t<cff2_cs_opset_extents_t, cff2_extents_param_t> interp;
|
||||
const byte_str_t str = (*charStrings)[glyph];
|
||||
interp.env.init (str, *this, fd, coords, num_coords);
|
||||
extents_param_t param;
|
||||
interp.env.init (str, *this, fd, font->coords, font->num_coords);
|
||||
cff2_extents_param_t param;
|
||||
param.init ();
|
||||
if (unlikely (!interp.interpret (param))) return false;
|
||||
|
||||
@ -118,8 +126,8 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
|
||||
}
|
||||
else
|
||||
{
|
||||
extents->x_bearing = (int32_t)param.min_x.floor ();
|
||||
extents->width = (int32_t)param.max_x.ceil () - extents->x_bearing;
|
||||
extents->x_bearing = font->em_scalef_x (param.min_x.to_real ());
|
||||
extents->width = font->em_scalef_x (param.max_x.to_real () - param.min_x.to_real ());
|
||||
}
|
||||
if (param.min_y >= param.max_y)
|
||||
{
|
||||
@ -128,9 +136,80 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
|
||||
}
|
||||
else
|
||||
{
|
||||
extents->y_bearing = (int32_t)param.max_y.ceil ();
|
||||
extents->height = (int32_t)param.min_y.floor () - extents->y_bearing;
|
||||
extents->y_bearing = font->em_scalef_y (param.max_y.to_real ());
|
||||
extents->height = font->em_scalef_y (param.min_y.to_real () - param.max_y.to_real ());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef HB_EXPERIMENTAL_API
|
||||
struct cff2_path_param_t
|
||||
{
|
||||
cff2_path_param_t (hb_font_t *font_, draw_helper_t &draw_helper_)
|
||||
{
|
||||
draw_helper = &draw_helper_;
|
||||
font = font_;
|
||||
}
|
||||
|
||||
void move_to (const point_t &p)
|
||||
{ draw_helper->move_to (font->em_scalef_x (p.x.to_real ()), font->em_scalef_y (p.y.to_real ())); }
|
||||
|
||||
void line_to (const point_t &p)
|
||||
{ draw_helper->line_to (font->em_scalef_x (p.x.to_real ()), font->em_scalef_y (p.y.to_real ())); }
|
||||
|
||||
void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3)
|
||||
{
|
||||
draw_helper->cubic_to (font->em_scalef_x (p1.x.to_real ()), font->em_scalef_y (p1.y.to_real ()),
|
||||
font->em_scalef_x (p2.x.to_real ()), font->em_scalef_y (p2.y.to_real ()),
|
||||
font->em_scalef_x (p3.x.to_real ()), font->em_scalef_y (p3.y.to_real ()));
|
||||
}
|
||||
|
||||
protected:
|
||||
draw_helper_t *draw_helper;
|
||||
hb_font_t *font;
|
||||
};
|
||||
|
||||
struct cff2_path_procs_path_t : path_procs_t<cff2_path_procs_path_t, cff2_cs_interp_env_t, cff2_path_param_t>
|
||||
{
|
||||
static void moveto (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt)
|
||||
{
|
||||
param.move_to (pt);
|
||||
env.moveto (pt);
|
||||
}
|
||||
|
||||
static void line (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt1)
|
||||
{
|
||||
param.line_to (pt1);
|
||||
env.moveto (pt1);
|
||||
}
|
||||
|
||||
static void curve (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
|
||||
{
|
||||
param.cubic_to (pt1, pt2, pt3);
|
||||
env.moveto (pt3);
|
||||
}
|
||||
};
|
||||
|
||||
struct cff2_cs_opset_path_t : cff2_cs_opset_t<cff2_cs_opset_path_t, cff2_path_param_t, cff2_path_procs_path_t> {};
|
||||
|
||||
bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const
|
||||
{
|
||||
#ifdef HB_NO_OT_FONT_CFF
|
||||
/* XXX Remove check when this code moves to .hh file. */
|
||||
return true;
|
||||
#endif
|
||||
|
||||
if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false;
|
||||
|
||||
unsigned int fd = fdSelect->get_fd (glyph);
|
||||
cff2_cs_interpreter_t<cff2_cs_opset_path_t, cff2_path_param_t> interp;
|
||||
const byte_str_t str = (*charStrings)[glyph];
|
||||
interp.env.init (str, *this, fd, font->coords, font->num_coords);
|
||||
cff2_path_param_t param (font, draw_helper);
|
||||
if (unlikely (!interp.interpret (param))) return false;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@ -27,9 +27,9 @@
|
||||
#ifndef HB_OT_CFF2_TABLE_HH
|
||||
#define HB_OT_CFF2_TABLE_HH
|
||||
|
||||
#include "hb-ot-head-table.hh"
|
||||
#include "hb-ot-cff-common.hh"
|
||||
#include "hb-subset-cff2.hh"
|
||||
#include "hb-draw.hh"
|
||||
|
||||
namespace CFF {
|
||||
|
||||
@ -43,7 +43,6 @@ typedef CFFIndex<HBUINT32> CFF2Index;
|
||||
template <typename Type> struct CFF2IndexOf : CFFIndexOf<HBUINT32, Type> {};
|
||||
|
||||
typedef CFF2Index CFF2CharStrings;
|
||||
typedef FDArray<HBUINT32> CFF2FDArray;
|
||||
typedef Subrs<HBUINT32> CFF2Subrs;
|
||||
|
||||
typedef FDSelect3_4<HBUINT32, HBUINT16> FDSelect4;
|
||||
@ -51,62 +50,63 @@ typedef FDSelect3_4_Range<HBUINT32, HBUINT16> FDSelect4_Range;
|
||||
|
||||
struct CFF2FDSelect
|
||||
{
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
||||
return_trace (likely (c->check_struct (this) && (format == 0 || format == 3 || format == 4) &&
|
||||
(format == 0)?
|
||||
u.format0.sanitize (c, fdcount):
|
||||
((format == 3)?
|
||||
u.format3.sanitize (c, fdcount):
|
||||
u.format4.sanitize (c, fdcount))));
|
||||
}
|
||||
|
||||
bool serialize (hb_serialize_context_t *c, const CFF2FDSelect &src, unsigned int num_glyphs)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
unsigned int size = src.get_size (num_glyphs);
|
||||
CFF2FDSelect *dest = c->allocate_size<CFF2FDSelect> (size);
|
||||
if (unlikely (dest == nullptr)) return_trace (false);
|
||||
if (unlikely (!dest)) return_trace (false);
|
||||
memcpy (dest, &src, size);
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
unsigned int calculate_serialized_size (unsigned int num_glyphs) const
|
||||
{ return get_size (num_glyphs); }
|
||||
|
||||
unsigned int get_size (unsigned int num_glyphs) const
|
||||
{
|
||||
unsigned int size = format.static_size;
|
||||
if (format == 0)
|
||||
size += u.format0.get_size (num_glyphs);
|
||||
else if (format == 3)
|
||||
size += u.format3.get_size ();
|
||||
else
|
||||
size += u.format4.get_size ();
|
||||
return size;
|
||||
switch (format)
|
||||
{
|
||||
case 0: return format.static_size + u.format0.get_size (num_glyphs);
|
||||
case 3: return format.static_size + u.format3.get_size ();
|
||||
case 4: return format.static_size + u.format4.get_size ();
|
||||
default:return 0;
|
||||
}
|
||||
}
|
||||
|
||||
hb_codepoint_t get_fd (hb_codepoint_t glyph) const
|
||||
{
|
||||
if (this == &Null(CFF2FDSelect))
|
||||
if (this == &Null (CFF2FDSelect))
|
||||
return 0;
|
||||
if (format == 0)
|
||||
return u.format0.get_fd (glyph);
|
||||
else if (format == 3)
|
||||
return u.format3.get_fd (glyph);
|
||||
else
|
||||
return u.format4.get_fd (glyph);
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case 0: return u.format0.get_fd (glyph);
|
||||
case 3: return u.format3.get_fd (glyph);
|
||||
case 4: return u.format4.get_fd (glyph);
|
||||
default:return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned int fdcount) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (unlikely (!c->check_struct (this)))
|
||||
return_trace (false);
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case 0: return_trace (u.format0.sanitize (c, fdcount));
|
||||
case 3: return_trace (u.format3.sanitize (c, fdcount));
|
||||
case 4: return_trace (u.format4.sanitize (c, fdcount));
|
||||
default:return_trace (false);
|
||||
}
|
||||
}
|
||||
|
||||
HBUINT8 format;
|
||||
union {
|
||||
FDSelect0 format0;
|
||||
FDSelect3 format3;
|
||||
FDSelect4 format4;
|
||||
FDSelect0 format0;
|
||||
FDSelect3 format3;
|
||||
FDSelect4 format4;
|
||||
} u;
|
||||
|
||||
public:
|
||||
DEFINE_SIZE_MIN (2);
|
||||
};
|
||||
|
||||
@ -123,7 +123,7 @@ struct CFF2VariationStore
|
||||
TRACE_SERIALIZE (this);
|
||||
unsigned int size_ = varStore->get_size ();
|
||||
CFF2VariationStore *dest = c->allocate_size<CFF2VariationStore> (size_);
|
||||
if (unlikely (dest == nullptr)) return_trace (false);
|
||||
if (unlikely (!dest)) return_trace (false);
|
||||
memcpy (dest, varStore, size_);
|
||||
return_trace (true);
|
||||
}
|
||||
@ -146,26 +146,6 @@ struct cff2_top_dict_values_t : top_dict_values_t<>
|
||||
}
|
||||
void fini () { top_dict_values_t<>::fini (); }
|
||||
|
||||
unsigned int calculate_serialized_size () const
|
||||
{
|
||||
unsigned int size = 0;
|
||||
for (unsigned int i = 0; i < get_count (); i++)
|
||||
{
|
||||
op_code_t op = get_value (i).op;
|
||||
switch (op)
|
||||
{
|
||||
case OpCode_vstore:
|
||||
case OpCode_FDSelect:
|
||||
size += OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op);
|
||||
break;
|
||||
default:
|
||||
size += top_dict_values_t<>::calculate_serialized_op_size (get_value (i));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
unsigned int vstoreOffset;
|
||||
unsigned int FDSelectOffset;
|
||||
};
|
||||
@ -252,22 +232,11 @@ struct cff2_private_dict_values_base_t : dict_values_t<VAL>
|
||||
{
|
||||
dict_values_t<VAL>::init ();
|
||||
subrsOffset = 0;
|
||||
localSubrs = &Null(CFF2Subrs);
|
||||
localSubrs = &Null (CFF2Subrs);
|
||||
ivs = 0;
|
||||
}
|
||||
void fini () { dict_values_t<VAL>::fini (); }
|
||||
|
||||
unsigned int calculate_serialized_size () const
|
||||
{
|
||||
unsigned int size = 0;
|
||||
for (unsigned int i = 0; i < dict_values_t<VAL>::get_count; i++)
|
||||
if (dict_values_t<VAL>::get_value (i).op == OpCode_Subrs)
|
||||
size += OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs);
|
||||
else
|
||||
size += dict_values_t<VAL>::get_value (i).str.length;
|
||||
return size;
|
||||
}
|
||||
|
||||
unsigned int subrsOffset;
|
||||
const CFF2Subrs *localSubrs;
|
||||
unsigned int ivs;
|
||||
@ -400,6 +369,14 @@ struct cff2_private_dict_opset_subset_t : dict_opset_t
|
||||
typedef dict_interpreter_t<cff2_top_dict_opset_t, cff2_top_dict_values_t> cff2_top_dict_interpreter_t;
|
||||
typedef dict_interpreter_t<cff2_font_dict_opset_t, cff2_font_dict_values_t> cff2_font_dict_interpreter_t;
|
||||
|
||||
struct CFF2FDArray : FDArray<HBUINT32>
|
||||
{
|
||||
/* FDArray::serialize does not compile without this partial specialization */
|
||||
template <typename ITER, typename OP_SERIALIZER>
|
||||
bool serialize (hb_serialize_context_t *c, ITER it, OP_SERIALIZER& opszr)
|
||||
{ return FDArray<HBUINT32>::serialize<cff2_font_dict_values_t, table_info_t> (c, it, opszr); }
|
||||
};
|
||||
|
||||
} /* namespace CFF */
|
||||
|
||||
namespace OT {
|
||||
@ -434,7 +411,7 @@ struct cff2
|
||||
|
||||
const OT::cff2 *cff2 = this->blob->template as<OT::cff2> ();
|
||||
|
||||
if (cff2 == &Null(OT::cff2))
|
||||
if (cff2 == &Null (OT::cff2))
|
||||
{ fini (); return; }
|
||||
|
||||
{ /* parse top dict */
|
||||
@ -452,11 +429,11 @@ struct cff2
|
||||
fdArray = &StructAtOffsetOrNull<CFF2FDArray> (cff2, topDict.FDArrayOffset);
|
||||
fdSelect = &StructAtOffsetOrNull<CFF2FDSelect> (cff2, topDict.FDSelectOffset);
|
||||
|
||||
if (((varStore != &Null(CFF2VariationStore)) && unlikely (!varStore->sanitize (&sc))) ||
|
||||
(charStrings == &Null(CFF2CharStrings)) || unlikely (!charStrings->sanitize (&sc)) ||
|
||||
(globalSubrs == &Null(CFF2Subrs)) || unlikely (!globalSubrs->sanitize (&sc)) ||
|
||||
(fdArray == &Null(CFF2FDArray)) || unlikely (!fdArray->sanitize (&sc)) ||
|
||||
(((fdSelect != &Null(CFF2FDSelect)) && unlikely (!fdSelect->sanitize (&sc, fdArray->count)))))
|
||||
if (((varStore != &Null (CFF2VariationStore)) && unlikely (!varStore->sanitize (&sc))) ||
|
||||
(charStrings == &Null (CFF2CharStrings)) || unlikely (!charStrings->sanitize (&sc)) ||
|
||||
(globalSubrs == &Null (CFF2Subrs)) || unlikely (!globalSubrs->sanitize (&sc)) ||
|
||||
(fdArray == &Null (CFF2FDArray)) || unlikely (!fdArray->sanitize (&sc)) ||
|
||||
(((fdSelect != &Null (CFF2FDSelect)) && unlikely (!fdSelect->sanitize (&sc, fdArray->count)))))
|
||||
{ fini (); return; }
|
||||
|
||||
num_glyphs = charStrings->count;
|
||||
@ -464,7 +441,8 @@ struct cff2
|
||||
{ fini (); return; }
|
||||
|
||||
fdCount = fdArray->count;
|
||||
privateDicts.resize (fdCount);
|
||||
if (!privateDicts.resize (fdCount))
|
||||
{ fini (); return; }
|
||||
|
||||
/* parse font dicts and gather private dicts */
|
||||
for (unsigned int i = 0; i < fdCount; i++)
|
||||
@ -475,7 +453,7 @@ struct cff2
|
||||
cff2_font_dict_interpreter_t font_interp;
|
||||
font_interp.env.init (fontDictStr);
|
||||
font = fontDicts.push ();
|
||||
if (unlikely (font == &Crap(cff2_font_dict_values_t))) { fini (); return; }
|
||||
if (unlikely (font == &Crap (cff2_font_dict_values_t))) { fini (); return; }
|
||||
font->init ();
|
||||
if (unlikely (!font_interp.interpret (*font))) { fini (); return; }
|
||||
|
||||
@ -487,7 +465,7 @@ struct cff2
|
||||
if (unlikely (!priv_interp.interpret (privateDicts[i]))) { fini (); return; }
|
||||
|
||||
privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (&privDictStr[0], privateDicts[i].subrsOffset);
|
||||
if (privateDicts[i].localSubrs != &Null(CFF2Subrs) &&
|
||||
if (privateDicts[i].localSubrs != &Null (CFF2Subrs) &&
|
||||
unlikely (!privateDicts[i].localSubrs->sanitize (&sc)))
|
||||
{ fini (); return; }
|
||||
}
|
||||
@ -503,7 +481,7 @@ struct cff2
|
||||
blob = nullptr;
|
||||
}
|
||||
|
||||
bool is_valid () const { return blob != nullptr; }
|
||||
bool is_valid () const { return blob; }
|
||||
|
||||
protected:
|
||||
hb_blob_t *blob;
|
||||
@ -529,27 +507,14 @@ struct cff2
|
||||
HB_INTERNAL bool get_extents (hb_font_t *font,
|
||||
hb_codepoint_t glyph,
|
||||
hb_glyph_extents_t *extents) const;
|
||||
#ifdef HB_EXPERIMENTAL_API
|
||||
HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, draw_helper_t &draw_helper) const;
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> accelerator_subset_t;
|
||||
|
||||
bool subset (hb_subset_plan_t *plan) const
|
||||
{
|
||||
hb_blob_t *cff2_prime = nullptr;
|
||||
|
||||
bool success = true;
|
||||
if (hb_subset_cff2 (plan, &cff2_prime)) {
|
||||
success = success && plan->add_table (HB_OT_TAG_cff2, cff2_prime);
|
||||
hb_blob_t *head_blob = hb_sanitize_context_t().reference_table<head> (plan->source);
|
||||
success = success && head_blob && plan->add_table (HB_OT_TAG_head, head_blob);
|
||||
hb_blob_destroy (head_blob);
|
||||
} else {
|
||||
success = false;
|
||||
}
|
||||
hb_blob_destroy (cff2_prime);
|
||||
|
||||
return success;
|
||||
}
|
||||
bool subset (hb_subset_context_t *c) const { return hb_subset_cff2 (c); }
|
||||
|
||||
public:
|
||||
FixedVersion<HBUINT8> version; /* Version of CFF2 table. set to 0x0200u */
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -21,7 +21,7 @@
|
||||
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
|
||||
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Google Author(s): Seigo Nonaka
|
||||
* Google Author(s): Seigo Nonaka, Calder Kitagawa
|
||||
*/
|
||||
|
||||
#ifndef HB_OT_COLOR_CBDT_TABLE_HH
|
||||
@ -43,6 +43,35 @@
|
||||
|
||||
namespace OT {
|
||||
|
||||
struct cblc_bitmap_size_subset_context_t
|
||||
{
|
||||
const char *cbdt;
|
||||
unsigned int cbdt_length;
|
||||
hb_vector_t<char> *cbdt_prime;
|
||||
unsigned int size; /* INOUT
|
||||
* Input: old size of IndexSubtable
|
||||
* Output: new size of IndexSubtable
|
||||
*/
|
||||
unsigned int num_tables; /* INOUT
|
||||
* Input: old number of subtables.
|
||||
* Output: new number of subtables.
|
||||
*/
|
||||
hb_codepoint_t start_glyph; /* OUT */
|
||||
hb_codepoint_t end_glyph; /* OUT */
|
||||
};
|
||||
|
||||
static inline bool
|
||||
_copy_data_to_cbdt (hb_vector_t<char> *cbdt_prime,
|
||||
const void *data,
|
||||
unsigned length)
|
||||
{
|
||||
unsigned int new_len = cbdt_prime->length + length;
|
||||
if (unlikely (!cbdt_prime->alloc (new_len))) return false;
|
||||
memcpy (cbdt_prime->arrayZ + cbdt_prime->length, data, length);
|
||||
cbdt_prime->length = new_len;
|
||||
return true;
|
||||
}
|
||||
|
||||
struct SmallGlyphMetrics
|
||||
{
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
@ -51,12 +80,12 @@ struct SmallGlyphMetrics
|
||||
return_trace (c->check_struct (this));
|
||||
}
|
||||
|
||||
void get_extents (hb_glyph_extents_t *extents) const
|
||||
void get_extents (hb_font_t *font, hb_glyph_extents_t *extents) const
|
||||
{
|
||||
extents->x_bearing = bearingX;
|
||||
extents->y_bearing = bearingY;
|
||||
extents->width = width;
|
||||
extents->height = - (hb_position_t) height;
|
||||
extents->x_bearing = font->em_scale_x (bearingX);
|
||||
extents->y_bearing = font->em_scale_y (bearingY);
|
||||
extents->width = font->em_scale_x (width);
|
||||
extents->height = font->em_scale_y (-static_cast<int>(height));
|
||||
}
|
||||
|
||||
HBUINT8 height;
|
||||
@ -65,7 +94,7 @@ struct SmallGlyphMetrics
|
||||
HBINT8 bearingY;
|
||||
HBUINT8 advance;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC(5);
|
||||
DEFINE_SIZE_STATIC (5);
|
||||
};
|
||||
|
||||
struct BigGlyphMetrics : SmallGlyphMetrics
|
||||
@ -74,7 +103,7 @@ struct BigGlyphMetrics : SmallGlyphMetrics
|
||||
HBINT8 vertBearingY;
|
||||
HBUINT8 vertAdvance;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC(8);
|
||||
DEFINE_SIZE_STATIC (8);
|
||||
};
|
||||
|
||||
struct SBitLineMetrics
|
||||
@ -98,7 +127,7 @@ struct SBitLineMetrics
|
||||
HBINT8 padding1;
|
||||
HBINT8 padding2;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC(12);
|
||||
DEFINE_SIZE_STATIC (12);
|
||||
};
|
||||
|
||||
|
||||
@ -118,7 +147,7 @@ struct IndexSubtableHeader
|
||||
HBUINT16 imageFormat;
|
||||
HBUINT32 imageDataOffset;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC(8);
|
||||
DEFINE_SIZE_STATIC (8);
|
||||
};
|
||||
|
||||
template <typename OffsetType>
|
||||
@ -143,11 +172,23 @@ struct IndexSubtableFormat1Or3
|
||||
return true;
|
||||
}
|
||||
|
||||
bool add_offset (hb_serialize_context_t *c,
|
||||
unsigned int offset,
|
||||
unsigned int *size /* OUT (accumulated) */)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
Offset<OffsetType> embedded_offset;
|
||||
embedded_offset = offset;
|
||||
*size += sizeof (OffsetType);
|
||||
auto *o = c->embed (embedded_offset);
|
||||
return_trace ((bool) o);
|
||||
}
|
||||
|
||||
IndexSubtableHeader header;
|
||||
UnsizedArrayOf<Offset<OffsetType> >
|
||||
UnsizedArrayOf<Offset<OffsetType>>
|
||||
offsetArrayZ;
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY(8, offsetArrayZ);
|
||||
DEFINE_SIZE_ARRAY (8, offsetArrayZ);
|
||||
};
|
||||
|
||||
struct IndexSubtableFormat1 : IndexSubtableFormat1Or3<HBUINT32> {};
|
||||
@ -159,35 +200,153 @@ struct IndexSubtable
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
if (!u.header.sanitize (c)) return_trace (false);
|
||||
switch (u.header.indexFormat) {
|
||||
switch (u.header.indexFormat)
|
||||
{
|
||||
case 1: return_trace (u.format1.sanitize (c, glyph_count));
|
||||
case 3: return_trace (u.format3.sanitize (c, glyph_count));
|
||||
default:return_trace (true);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
finish_subtable (hb_serialize_context_t *c,
|
||||
unsigned int cbdt_prime_len,
|
||||
unsigned int num_glyphs,
|
||||
unsigned int *size /* OUT (accumulated) */)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
||||
unsigned int local_offset = cbdt_prime_len - u.header.imageDataOffset;
|
||||
switch (u.header.indexFormat)
|
||||
{
|
||||
case 1: return_trace (u.format1.add_offset (c, local_offset, size));
|
||||
case 3: {
|
||||
if (!u.format3.add_offset (c, local_offset, size))
|
||||
return_trace (false);
|
||||
if (!(num_glyphs & 0x01)) // Pad to 32-bit alignment if needed.
|
||||
return_trace (u.format3.add_offset (c, 0, size));
|
||||
return_trace (true);
|
||||
}
|
||||
// TODO: implement 2, 4, 5.
|
||||
case 2: case 4: // No-op.
|
||||
case 5: // Pad to 32-bit aligned.
|
||||
default: return_trace (false);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
fill_missing_glyphs (hb_serialize_context_t *c,
|
||||
unsigned int cbdt_prime_len,
|
||||
unsigned int num_missing,
|
||||
unsigned int *size /* OUT (accumulated) */,
|
||||
unsigned int *num_glyphs /* OUT (accumulated) */)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
||||
unsigned int local_offset = cbdt_prime_len - u.header.imageDataOffset;
|
||||
switch (u.header.indexFormat)
|
||||
{
|
||||
case 1: {
|
||||
for (unsigned int i = 0; i < num_missing; i++)
|
||||
{
|
||||
if (unlikely (!u.format1.add_offset (c, local_offset, size)))
|
||||
return_trace (false);
|
||||
*num_glyphs += 1;
|
||||
}
|
||||
return_trace (true);
|
||||
}
|
||||
case 3: {
|
||||
for (unsigned int i = 0; i < num_missing; i++)
|
||||
{
|
||||
if (unlikely (!u.format3.add_offset (c, local_offset, size)))
|
||||
return_trace (false);
|
||||
*num_glyphs += 1;
|
||||
}
|
||||
return_trace (true);
|
||||
}
|
||||
// TODO: implement 2, 4, 5.
|
||||
case 2: // Add empty space in cbdt_prime?.
|
||||
case 4: case 5: // No-op as sparse is supported.
|
||||
default: return_trace (false);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
copy_glyph_at_idx (hb_serialize_context_t *c, unsigned int idx,
|
||||
const char *cbdt, unsigned int cbdt_length,
|
||||
hb_vector_t<char> *cbdt_prime /* INOUT */,
|
||||
IndexSubtable *subtable_prime /* INOUT */,
|
||||
unsigned int *size /* OUT (accumulated) */) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
||||
unsigned int offset, length, format;
|
||||
if (unlikely (!get_image_data (idx, &offset, &length, &format))) return_trace (false);
|
||||
if (unlikely (offset > cbdt_length || cbdt_length - offset < length)) return_trace (false);
|
||||
|
||||
auto *header_prime = subtable_prime->get_header ();
|
||||
unsigned int new_local_offset = cbdt_prime->length - (unsigned int) header_prime->imageDataOffset;
|
||||
if (unlikely (!_copy_data_to_cbdt (cbdt_prime, cbdt + offset, length))) return_trace (false);
|
||||
|
||||
return_trace (subtable_prime->add_offset (c, new_local_offset, size));
|
||||
}
|
||||
|
||||
bool
|
||||
add_offset (hb_serialize_context_t *c, unsigned int local_offset,
|
||||
unsigned int *size /* OUT (accumulated) */)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
switch (u.header.indexFormat)
|
||||
{
|
||||
case 1: return_trace (u.format1.add_offset (c, local_offset, size));
|
||||
case 3: return_trace (u.format3.add_offset (c, local_offset, size));
|
||||
// TODO: Implement tables 2, 4, 5
|
||||
case 2: // Should be a no-op.
|
||||
case 4: case 5: // Handle sparse cases.
|
||||
default: return_trace (false);
|
||||
}
|
||||
}
|
||||
|
||||
bool get_extents (hb_glyph_extents_t *extents HB_UNUSED) const
|
||||
{
|
||||
switch (u.header.indexFormat) {
|
||||
switch (u.header.indexFormat)
|
||||
{
|
||||
case 2: case 5: /* TODO */
|
||||
case 1: case 3: case 4: /* Variable-metrics formats do not have metrics here. */
|
||||
default:return (false);
|
||||
}
|
||||
}
|
||||
|
||||
bool get_image_data (unsigned int idx,
|
||||
unsigned int *offset,
|
||||
unsigned int *length,
|
||||
unsigned int *format) const
|
||||
bool
|
||||
get_image_data (unsigned int idx, unsigned int *offset,
|
||||
unsigned int *length, unsigned int *format) const
|
||||
{
|
||||
*format = u.header.imageFormat;
|
||||
switch (u.header.indexFormat) {
|
||||
switch (u.header.indexFormat)
|
||||
{
|
||||
case 1: return u.format1.get_image_data (idx, offset, length);
|
||||
case 3: return u.format3.get_image_data (idx, offset, length);
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
const IndexSubtableHeader* get_header () const { return &u.header; }
|
||||
|
||||
void populate_header (unsigned index_format,
|
||||
unsigned image_format,
|
||||
unsigned int image_data_offset,
|
||||
unsigned int *size)
|
||||
{
|
||||
u.header.indexFormat = index_format;
|
||||
u.header.imageFormat = image_format;
|
||||
u.header.imageDataOffset = image_data_offset;
|
||||
switch (u.header.indexFormat)
|
||||
{
|
||||
case 1: *size += IndexSubtableFormat1::min_size; break;
|
||||
case 3: *size += IndexSubtableFormat3::min_size; break;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
union {
|
||||
IndexSubtableHeader header;
|
||||
@ -209,12 +368,135 @@ struct IndexSubtableRecord
|
||||
offsetToSubtable.sanitize (c, base, lastGlyphIndex - firstGlyphIndex + 1));
|
||||
}
|
||||
|
||||
bool get_extents (hb_glyph_extents_t *extents,
|
||||
const void *base) const
|
||||
const IndexSubtable* get_subtable (const void *base) const
|
||||
{
|
||||
return (base+offsetToSubtable).get_extents (extents);
|
||||
return &(base+offsetToSubtable);
|
||||
}
|
||||
|
||||
bool add_new_subtable (hb_subset_context_t* c,
|
||||
cblc_bitmap_size_subset_context_t *bitmap_size_context,
|
||||
IndexSubtableRecord *record,
|
||||
const hb_vector_t<hb_pair_t<hb_codepoint_t, const IndexSubtableRecord*>> *lookup, /* IN */
|
||||
const void *base,
|
||||
unsigned int *start /* INOUT */) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
||||
auto *subtable = c->serializer->start_embed<IndexSubtable> ();
|
||||
if (unlikely (!subtable)) return_trace (false);
|
||||
if (unlikely (!c->serializer->extend_min (subtable))) return_trace (false);
|
||||
|
||||
auto *old_subtable = get_subtable (base);
|
||||
auto *old_header = old_subtable->get_header ();
|
||||
|
||||
subtable->populate_header (old_header->indexFormat,
|
||||
old_header->imageFormat,
|
||||
bitmap_size_context->cbdt_prime->length,
|
||||
&bitmap_size_context->size);
|
||||
|
||||
unsigned int num_glyphs = 0;
|
||||
bool early_exit = false;
|
||||
for (unsigned int i = *start; i < lookup->length; i++)
|
||||
{
|
||||
hb_codepoint_t new_gid = (*lookup)[i].first;
|
||||
const IndexSubtableRecord *next_record = (*lookup)[i].second;
|
||||
const IndexSubtable *next_subtable = next_record->get_subtable (base);
|
||||
auto *next_header = next_subtable->get_header ();
|
||||
if (next_header != old_header)
|
||||
{
|
||||
*start = i;
|
||||
early_exit = true;
|
||||
break;
|
||||
}
|
||||
unsigned int num_missing = record->add_glyph_for_subset (new_gid);
|
||||
if (unlikely (!subtable->fill_missing_glyphs (c->serializer,
|
||||
bitmap_size_context->cbdt_prime->length,
|
||||
num_missing,
|
||||
&bitmap_size_context->size,
|
||||
&num_glyphs)))
|
||||
return_trace (false);
|
||||
|
||||
hb_codepoint_t old_gid = 0;
|
||||
c->plan->old_gid_for_new_gid (new_gid, &old_gid);
|
||||
if (old_gid < next_record->firstGlyphIndex)
|
||||
return_trace (false);
|
||||
|
||||
unsigned int old_idx = (unsigned int) old_gid - next_record->firstGlyphIndex;
|
||||
if (unlikely (!next_subtable->copy_glyph_at_idx (c->serializer,
|
||||
old_idx,
|
||||
bitmap_size_context->cbdt,
|
||||
bitmap_size_context->cbdt_length,
|
||||
bitmap_size_context->cbdt_prime,
|
||||
subtable,
|
||||
&bitmap_size_context->size)))
|
||||
return_trace (false);
|
||||
num_glyphs += 1;
|
||||
}
|
||||
if (!early_exit)
|
||||
*start = lookup->length;
|
||||
if (unlikely (!subtable->finish_subtable (c->serializer,
|
||||
bitmap_size_context->cbdt_prime->length,
|
||||
num_glyphs,
|
||||
&bitmap_size_context->size)))
|
||||
return_trace (false);
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
bool add_new_record (hb_subset_context_t *c,
|
||||
cblc_bitmap_size_subset_context_t *bitmap_size_context,
|
||||
const hb_vector_t<hb_pair_t<hb_codepoint_t, const IndexSubtableRecord*>> *lookup, /* IN */
|
||||
const void *base,
|
||||
unsigned int *start, /* INOUT */
|
||||
hb_vector_t<IndexSubtableRecord>* records /* INOUT */) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
auto snap = c->serializer->snapshot ();
|
||||
unsigned int old_size = bitmap_size_context->size;
|
||||
unsigned int old_cbdt_prime_length = bitmap_size_context->cbdt_prime->length;
|
||||
|
||||
// Set to invalid state to indicate filling glyphs is not yet started.
|
||||
if (unlikely (!records->resize (records->length + 1)))
|
||||
return_trace (c->serializer->check_success (false));
|
||||
|
||||
(*records)[records->length - 1].firstGlyphIndex = 1;
|
||||
(*records)[records->length - 1].lastGlyphIndex = 0;
|
||||
bitmap_size_context->size += IndexSubtableRecord::min_size;
|
||||
|
||||
c->serializer->push ();
|
||||
|
||||
if (unlikely (!add_new_subtable (c, bitmap_size_context, &((*records)[records->length - 1]), lookup, base, start)))
|
||||
{
|
||||
c->serializer->pop_discard ();
|
||||
c->serializer->revert (snap);
|
||||
bitmap_size_context->cbdt_prime->shrink (old_cbdt_prime_length);
|
||||
bitmap_size_context->size = old_size;
|
||||
records->resize (records->length - 1);
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
bitmap_size_context->num_tables += 1;
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
unsigned int add_glyph_for_subset (hb_codepoint_t gid)
|
||||
{
|
||||
if (firstGlyphIndex > lastGlyphIndex)
|
||||
{
|
||||
firstGlyphIndex = gid;
|
||||
lastGlyphIndex = gid;
|
||||
return 0;
|
||||
}
|
||||
// TODO maybe assert? this shouldn't occur.
|
||||
if (lastGlyphIndex > gid)
|
||||
return 0;
|
||||
unsigned int num_missing = (unsigned int) (gid - lastGlyphIndex - 1);
|
||||
lastGlyphIndex = gid;
|
||||
return num_missing;
|
||||
}
|
||||
|
||||
bool get_extents (hb_glyph_extents_t *extents, const void *base) const
|
||||
{ return (base+offsetToSubtable).get_extents (extents); }
|
||||
|
||||
bool get_image_data (unsigned int gid,
|
||||
const void *base,
|
||||
unsigned int *offset,
|
||||
@ -226,11 +508,11 @@ struct IndexSubtableRecord
|
||||
offset, length, format);
|
||||
}
|
||||
|
||||
GlyphID firstGlyphIndex;
|
||||
GlyphID lastGlyphIndex;
|
||||
HBGlyphID firstGlyphIndex;
|
||||
HBGlyphID lastGlyphIndex;
|
||||
LOffsetTo<IndexSubtable> offsetToSubtable;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC(8);
|
||||
DEFINE_SIZE_STATIC (8);
|
||||
};
|
||||
|
||||
struct IndexSubtableArray
|
||||
@ -243,6 +525,79 @@ struct IndexSubtableArray
|
||||
return_trace (indexSubtablesZ.sanitize (c, count, this));
|
||||
}
|
||||
|
||||
void
|
||||
build_lookup (hb_subset_context_t *c, cblc_bitmap_size_subset_context_t *bitmap_size_context,
|
||||
hb_vector_t<hb_pair_t<hb_codepoint_t,
|
||||
const IndexSubtableRecord*>> *lookup /* OUT */) const
|
||||
{
|
||||
bool start_glyph_is_set = false;
|
||||
for (hb_codepoint_t new_gid = 0; new_gid < c->plan->num_output_glyphs (); new_gid++)
|
||||
{
|
||||
hb_codepoint_t old_gid;
|
||||
if (unlikely (!c->plan->old_gid_for_new_gid (new_gid, &old_gid))) continue;
|
||||
|
||||
const IndexSubtableRecord* record = find_table (old_gid, bitmap_size_context->num_tables);
|
||||
if (unlikely (!record)) continue;
|
||||
|
||||
// Don't add gaps to the lookup. The best way to determine if a glyph is a
|
||||
// gap is that it has no image data.
|
||||
unsigned int offset, length, format;
|
||||
if (unlikely (!record->get_image_data (old_gid, this, &offset, &length, &format))) continue;
|
||||
|
||||
lookup->push (hb_pair_t<hb_codepoint_t, const IndexSubtableRecord*> (new_gid, record));
|
||||
|
||||
if (!start_glyph_is_set)
|
||||
{
|
||||
bitmap_size_context->start_glyph = new_gid;
|
||||
start_glyph_is_set = true;
|
||||
}
|
||||
|
||||
bitmap_size_context->end_glyph = new_gid;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
subset (hb_subset_context_t *c,
|
||||
cblc_bitmap_size_subset_context_t *bitmap_size_context) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
|
||||
auto *dst = c->serializer->start_embed<IndexSubtableArray> ();
|
||||
if (unlikely (!dst)) return_trace (false);
|
||||
|
||||
hb_vector_t<hb_pair_t<hb_codepoint_t, const IndexSubtableRecord*>> lookup;
|
||||
build_lookup (c, bitmap_size_context, &lookup);
|
||||
if (unlikely (lookup.in_error ()))
|
||||
return c->serializer->check_success (false);
|
||||
|
||||
bitmap_size_context->size = 0;
|
||||
bitmap_size_context->num_tables = 0;
|
||||
hb_vector_t<IndexSubtableRecord> records;
|
||||
for (unsigned int start = 0; start < lookup.length;)
|
||||
{
|
||||
if (unlikely (!lookup[start].second->add_new_record (c, bitmap_size_context, &lookup, this, &start, &records)))
|
||||
{
|
||||
// Discard any leftover pushes to the serializer from successful records.
|
||||
for (unsigned int i = 0; i < records.length; i++)
|
||||
c->serializer->pop_discard ();
|
||||
return_trace (false);
|
||||
}
|
||||
}
|
||||
|
||||
/* Workaround to ensure offset ordering is from least to greatest when
|
||||
* resolving links. */
|
||||
hb_vector_t<hb_serialize_context_t::objidx_t> objidxs;
|
||||
for (unsigned int i = 0; i < records.length; i++)
|
||||
objidxs.push (c->serializer->pop_pack ());
|
||||
for (unsigned int i = 0; i < records.length; i++)
|
||||
{
|
||||
IndexSubtableRecord* record = c->serializer->embed (records[i]);
|
||||
if (unlikely (!record)) return_trace (false);
|
||||
c->serializer->add_link (record->offsetToSubtable, objidxs[records.length - 1 - i]);
|
||||
}
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
public:
|
||||
const IndexSubtableRecord* find_table (hb_codepoint_t glyph, unsigned int numTables) const
|
||||
{
|
||||
@ -274,14 +629,48 @@ struct BitmapSizeTable
|
||||
vertical.sanitize (c));
|
||||
}
|
||||
|
||||
const IndexSubtableRecord *find_table (hb_codepoint_t glyph,
|
||||
const void *base,
|
||||
const void **out_base) const
|
||||
const IndexSubtableRecord *
|
||||
find_table (hb_codepoint_t glyph, const void *base, const void **out_base) const
|
||||
{
|
||||
*out_base = &(base+indexSubtableArrayOffset);
|
||||
return (base+indexSubtableArrayOffset).find_table (glyph, numberOfIndexSubtables);
|
||||
}
|
||||
|
||||
bool
|
||||
subset (hb_subset_context_t *c, const void *base,
|
||||
const char *cbdt, unsigned int cbdt_length,
|
||||
hb_vector_t<char> *cbdt_prime /* INOUT */) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out_table = c->serializer->embed (this);
|
||||
if (unlikely (!out_table)) return_trace (false);
|
||||
|
||||
cblc_bitmap_size_subset_context_t bitmap_size_context;
|
||||
bitmap_size_context.cbdt = cbdt;
|
||||
bitmap_size_context.cbdt_length = cbdt_length;
|
||||
bitmap_size_context.cbdt_prime = cbdt_prime;
|
||||
bitmap_size_context.size = indexTablesSize;
|
||||
bitmap_size_context.num_tables = numberOfIndexSubtables;
|
||||
bitmap_size_context.start_glyph = 1;
|
||||
bitmap_size_context.end_glyph = 0;
|
||||
|
||||
if (!out_table->indexSubtableArrayOffset.serialize_subset (c,
|
||||
indexSubtableArrayOffset,
|
||||
base,
|
||||
&bitmap_size_context))
|
||||
return_trace (false);
|
||||
if (!bitmap_size_context.size ||
|
||||
!bitmap_size_context.num_tables ||
|
||||
bitmap_size_context.start_glyph > bitmap_size_context.end_glyph)
|
||||
return_trace (false);
|
||||
|
||||
out_table->indexTablesSize = bitmap_size_context.size;
|
||||
out_table->numberOfIndexSubtables = bitmap_size_context.num_tables;
|
||||
out_table->startGlyphIndex = bitmap_size_context.start_glyph;
|
||||
out_table->endGlyphIndex = bitmap_size_context.end_glyph;
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
protected:
|
||||
LNNOffsetTo<IndexSubtableArray>
|
||||
indexSubtableArrayOffset;
|
||||
@ -290,14 +679,14 @@ struct BitmapSizeTable
|
||||
HBUINT32 colorRef;
|
||||
SBitLineMetrics horizontal;
|
||||
SBitLineMetrics vertical;
|
||||
GlyphID startGlyphIndex;
|
||||
GlyphID endGlyphIndex;
|
||||
HBGlyphID startGlyphIndex;
|
||||
HBGlyphID endGlyphIndex;
|
||||
HBUINT8 ppemX;
|
||||
HBUINT8 ppemY;
|
||||
HBUINT8 bitDepth;
|
||||
HBINT8 flags;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC(48);
|
||||
DEFINE_SIZE_STATIC (48);
|
||||
};
|
||||
|
||||
|
||||
@ -310,7 +699,7 @@ struct GlyphBitmapDataFormat17
|
||||
SmallGlyphMetrics glyphMetrics;
|
||||
LArrayOf<HBUINT8> data;
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY(9, data);
|
||||
DEFINE_SIZE_ARRAY (9, data);
|
||||
};
|
||||
|
||||
struct GlyphBitmapDataFormat18
|
||||
@ -318,14 +707,14 @@ struct GlyphBitmapDataFormat18
|
||||
BigGlyphMetrics glyphMetrics;
|
||||
LArrayOf<HBUINT8> data;
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY(12, data);
|
||||
DEFINE_SIZE_ARRAY (12, data);
|
||||
};
|
||||
|
||||
struct GlyphBitmapDataFormat19
|
||||
{
|
||||
LArrayOf<HBUINT8> data;
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY(4, data);
|
||||
DEFINE_SIZE_ARRAY (4, data);
|
||||
};
|
||||
|
||||
struct CBLC
|
||||
@ -342,22 +731,60 @@ struct CBLC
|
||||
sizeTables.sanitize (c, this));
|
||||
}
|
||||
|
||||
static bool
|
||||
sink_cbdt (hb_subset_context_t *c, hb_vector_t<char>* cbdt_prime)
|
||||
{
|
||||
hb_blob_t *cbdt_prime_blob = hb_blob_create (cbdt_prime->arrayZ,
|
||||
cbdt_prime->length,
|
||||
HB_MEMORY_MODE_WRITABLE,
|
||||
cbdt_prime->arrayZ,
|
||||
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);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool
|
||||
subset_size_table (hb_subset_context_t *c, const BitmapSizeTable& table,
|
||||
const char *cbdt /* IN */, unsigned int cbdt_length,
|
||||
CBLC *cblc_prime /* INOUT */, hb_vector_t<char> *cbdt_prime /* INOUT */) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
cblc_prime->sizeTables.len++;
|
||||
|
||||
auto snap = c->serializer->snapshot ();
|
||||
auto cbdt_prime_len = cbdt_prime->length;
|
||||
|
||||
if (!table.subset (c, this, cbdt, cbdt_length, cbdt_prime))
|
||||
{
|
||||
cblc_prime->sizeTables.len--;
|
||||
c->serializer->revert (snap);
|
||||
cbdt_prime->shrink (cbdt_prime_len);
|
||||
return_trace (false);
|
||||
}
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
// Implemented in cc file as it depends on definition of CBDT.
|
||||
HB_INTERNAL bool subset (hb_subset_context_t *c) const;
|
||||
|
||||
protected:
|
||||
const BitmapSizeTable &choose_strike (hb_font_t *font) const
|
||||
{
|
||||
unsigned count = sizeTables.len;
|
||||
if (unlikely (!count))
|
||||
return Null(BitmapSizeTable);
|
||||
return Null (BitmapSizeTable);
|
||||
|
||||
unsigned int requested_ppem = MAX (font->x_ppem, font->y_ppem);
|
||||
unsigned int requested_ppem = hb_max (font->x_ppem, font->y_ppem);
|
||||
if (!requested_ppem)
|
||||
requested_ppem = 1<<30; /* Choose largest strike. */
|
||||
unsigned int best_i = 0;
|
||||
unsigned int best_ppem = MAX (sizeTables[0].ppemX, sizeTables[0].ppemY);
|
||||
unsigned int best_ppem = hb_max (sizeTables[0].ppemX, sizeTables[0].ppemY);
|
||||
|
||||
for (unsigned int i = 1; i < count; i++)
|
||||
{
|
||||
unsigned int ppem = MAX (sizeTables[i].ppemX, sizeTables[i].ppemY);
|
||||
unsigned int ppem = hb_max (sizeTables[i].ppemX, sizeTables[i].ppemY);
|
||||
if ((requested_ppem <= ppem && ppem < best_ppem) ||
|
||||
(requested_ppem > best_ppem && ppem > best_ppem))
|
||||
{
|
||||
@ -373,7 +800,7 @@ struct CBLC
|
||||
FixedVersion<> version;
|
||||
LArrayOf<BitmapSizeTable> sizeTables;
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY(8, sizeTables);
|
||||
DEFINE_SIZE_ARRAY (8, sizeTables);
|
||||
};
|
||||
|
||||
struct CBDT
|
||||
@ -384,8 +811,8 @@ struct CBDT
|
||||
{
|
||||
void init (hb_face_t *face)
|
||||
{
|
||||
cblc = hb_sanitize_context_t().reference_table<CBLC> (face);
|
||||
cbdt = hb_sanitize_context_t().reference_table<CBDT> (face);
|
||||
cblc = hb_sanitize_context_t ().reference_table<CBLC> (face);
|
||||
cbdt = hb_sanitize_context_t ().reference_table<CBDT> (face);
|
||||
|
||||
upem = hb_face_get_upem (face);
|
||||
}
|
||||
@ -396,8 +823,8 @@ struct CBDT
|
||||
this->cbdt.destroy ();
|
||||
}
|
||||
|
||||
bool get_extents (hb_font_t *font, hb_codepoint_t glyph,
|
||||
hb_glyph_extents_t *extents) const
|
||||
bool
|
||||
get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
|
||||
{
|
||||
const void *base;
|
||||
const BitmapSizeTable &strike = this->cblc->choose_strike (font);
|
||||
@ -412,48 +839,42 @@ struct CBDT
|
||||
if (!subtable_record->get_image_data (glyph, base, &image_offset, &image_length, &image_format))
|
||||
return false;
|
||||
|
||||
{
|
||||
unsigned int cbdt_len = cbdt.get_length ();
|
||||
if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
|
||||
return false;
|
||||
unsigned int cbdt_len = cbdt.get_length ();
|
||||
if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
|
||||
return false;
|
||||
|
||||
switch (image_format)
|
||||
{
|
||||
case 17: {
|
||||
if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
|
||||
return false;
|
||||
const GlyphBitmapDataFormat17& glyphFormat17 =
|
||||
StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
|
||||
glyphFormat17.glyphMetrics.get_extents (extents);
|
||||
break;
|
||||
}
|
||||
case 18: {
|
||||
if (unlikely (image_length < GlyphBitmapDataFormat18::min_size))
|
||||
return false;
|
||||
const GlyphBitmapDataFormat18& glyphFormat18 =
|
||||
StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
|
||||
glyphFormat18.glyphMetrics.get_extents (extents);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
// TODO: Support other image formats.
|
||||
return false;
|
||||
}
|
||||
switch (image_format)
|
||||
{
|
||||
case 17: {
|
||||
if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
|
||||
return false;
|
||||
auto &glyphFormat17 = StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
|
||||
glyphFormat17.glyphMetrics.get_extents (font, extents);
|
||||
break;
|
||||
}
|
||||
case 18: {
|
||||
if (unlikely (image_length < GlyphBitmapDataFormat18::min_size))
|
||||
return false;
|
||||
auto &glyphFormat18 = StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
|
||||
glyphFormat18.glyphMetrics.get_extents (font, extents);
|
||||
break;
|
||||
}
|
||||
default: return false; /* TODO: Support other image formats. */
|
||||
}
|
||||
|
||||
/* Convert to font units. */
|
||||
double x_scale = upem / (double) strike.ppemX;
|
||||
double y_scale = upem / (double) strike.ppemY;
|
||||
extents->x_bearing = round (extents->x_bearing * x_scale);
|
||||
extents->y_bearing = round (extents->y_bearing * y_scale);
|
||||
extents->width = round (extents->width * x_scale);
|
||||
extents->height = round (extents->height * y_scale);
|
||||
float x_scale = upem / (float) strike.ppemX;
|
||||
float y_scale = upem / (float) strike.ppemY;
|
||||
extents->x_bearing = roundf (extents->x_bearing * x_scale);
|
||||
extents->y_bearing = roundf (extents->y_bearing * y_scale);
|
||||
extents->width = roundf (extents->width * x_scale);
|
||||
extents->height = roundf (extents->height * y_scale);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
hb_blob_t* reference_png (hb_font_t *font,
|
||||
hb_codepoint_t glyph) const
|
||||
hb_blob_t*
|
||||
reference_png (hb_font_t *font, hb_codepoint_t glyph) const
|
||||
{
|
||||
const void *base;
|
||||
const BitmapSizeTable &strike = this->cblc->choose_strike (font);
|
||||
@ -465,44 +886,41 @@ struct CBDT
|
||||
if (!subtable_record->get_image_data (glyph, base, &image_offset, &image_length, &image_format))
|
||||
return hb_blob_get_empty ();
|
||||
|
||||
unsigned int cbdt_len = cbdt.get_length ();
|
||||
if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
|
||||
return hb_blob_get_empty ();
|
||||
|
||||
switch (image_format)
|
||||
{
|
||||
unsigned int cbdt_len = cbdt.get_length ();
|
||||
if (unlikely (image_offset > cbdt_len || cbdt_len - image_offset < image_length))
|
||||
case 17:
|
||||
{
|
||||
if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
|
||||
return hb_blob_get_empty ();
|
||||
|
||||
switch (image_format)
|
||||
{
|
||||
case 17: {
|
||||
if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
|
||||
return hb_blob_get_empty ();
|
||||
const GlyphBitmapDataFormat17& glyphFormat17 =
|
||||
StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
|
||||
return hb_blob_create_sub_blob (cbdt.get_blob (),
|
||||
image_offset + GlyphBitmapDataFormat17::min_size,
|
||||
glyphFormat17.data.len);
|
||||
}
|
||||
case 18: {
|
||||
if (unlikely (image_length < GlyphBitmapDataFormat18::min_size))
|
||||
return hb_blob_get_empty ();
|
||||
const GlyphBitmapDataFormat18& glyphFormat18 =
|
||||
StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
|
||||
return hb_blob_create_sub_blob (cbdt.get_blob (),
|
||||
image_offset + GlyphBitmapDataFormat18::min_size,
|
||||
glyphFormat18.data.len);
|
||||
}
|
||||
case 19: {
|
||||
if (unlikely (image_length < GlyphBitmapDataFormat19::min_size))
|
||||
return hb_blob_get_empty ();
|
||||
const GlyphBitmapDataFormat19& glyphFormat19 =
|
||||
StructAtOffset<GlyphBitmapDataFormat19> (this->cbdt, image_offset);
|
||||
return hb_blob_create_sub_blob (cbdt.get_blob (),
|
||||
image_offset + GlyphBitmapDataFormat19::min_size,
|
||||
glyphFormat19.data.len);
|
||||
}
|
||||
}
|
||||
auto &glyphFormat17 = StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
|
||||
return hb_blob_create_sub_blob (cbdt.get_blob (),
|
||||
image_offset + GlyphBitmapDataFormat17::min_size,
|
||||
glyphFormat17.data.len);
|
||||
}
|
||||
case 18:
|
||||
{
|
||||
if (unlikely (image_length < GlyphBitmapDataFormat18::min_size))
|
||||
return hb_blob_get_empty ();
|
||||
auto &glyphFormat18 = StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
|
||||
return hb_blob_create_sub_blob (cbdt.get_blob (),
|
||||
image_offset + GlyphBitmapDataFormat18::min_size,
|
||||
glyphFormat18.data.len);
|
||||
}
|
||||
case 19:
|
||||
{
|
||||
if (unlikely (image_length < GlyphBitmapDataFormat19::min_size))
|
||||
return hb_blob_get_empty ();
|
||||
auto &glyphFormat19 = StructAtOffset<GlyphBitmapDataFormat19> (this->cbdt, image_offset);
|
||||
return hb_blob_create_sub_blob (cbdt.get_blob (),
|
||||
image_offset + GlyphBitmapDataFormat19::min_size,
|
||||
glyphFormat19.data.len);
|
||||
}
|
||||
default: return hb_blob_get_empty (); /* TODO: Support other image formats. */
|
||||
}
|
||||
|
||||
return hb_blob_get_empty ();
|
||||
}
|
||||
|
||||
bool has_data () const { return cbdt.get_length (); }
|
||||
@ -525,9 +943,41 @@ struct CBDT
|
||||
FixedVersion<> version;
|
||||
UnsizedArrayOf<HBUINT8> dataZ;
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY(4, dataZ);
|
||||
DEFINE_SIZE_ARRAY (4, dataZ);
|
||||
};
|
||||
|
||||
inline bool
|
||||
CBLC::subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
|
||||
auto *cblc_prime = c->serializer->start_embed<CBLC> ();
|
||||
|
||||
// Use a vector as a secondary buffer as the tables need to be built in parallel.
|
||||
hb_vector_t<char> cbdt_prime;
|
||||
|
||||
if (unlikely (!cblc_prime)) return_trace (false);
|
||||
if (unlikely (!c->serializer->extend_min (cblc_prime))) return_trace (false);
|
||||
cblc_prime->version = version;
|
||||
|
||||
hb_blob_t* cbdt_blob = hb_sanitize_context_t ().reference_table<CBDT> (c->plan->source);
|
||||
unsigned int cbdt_length;
|
||||
CBDT* cbdt = (CBDT *) hb_blob_get_data (cbdt_blob, &cbdt_length);
|
||||
if (unlikely (cbdt_length < CBDT::min_size))
|
||||
{
|
||||
hb_blob_destroy (cbdt_blob);
|
||||
return_trace (false);
|
||||
}
|
||||
_copy_data_to_cbdt (&cbdt_prime, cbdt, CBDT::min_size);
|
||||
|
||||
for (const BitmapSizeTable& table : + sizeTables.iter ())
|
||||
subset_size_table (c, table, (const char *) cbdt, cbdt_length, cblc_prime, &cbdt_prime);
|
||||
|
||||
hb_blob_destroy (cbdt_blob);
|
||||
|
||||
return_trace (CBLC::sink_cbdt (c, &cbdt_prime));
|
||||
}
|
||||
|
||||
struct CBDT_accelerator_t : CBDT::accelerator_t {};
|
||||
|
||||
} /* namespace OT */
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright © 2018 Ebrahim Byagowi
|
||||
* Copyright © 2020 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
@ -20,6 +21,8 @@
|
||||
* 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): Calder Kitagawa
|
||||
*/
|
||||
|
||||
#ifndef HB_OT_COLOR_COLR_TABLE_HH
|
||||
@ -39,6 +42,8 @@ namespace OT {
|
||||
|
||||
struct LayerRecord
|
||||
{
|
||||
operator hb_ot_color_layer_t () const { return {glyphId, colorIdx}; }
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
@ -46,7 +51,7 @@ struct LayerRecord
|
||||
}
|
||||
|
||||
public:
|
||||
GlyphID glyphId; /* Glyph ID of layer glyph */
|
||||
HBGlyphID glyphId; /* Glyph ID of layer glyph */
|
||||
Index colorIdx; /* Index value to use with a
|
||||
* selected color palette.
|
||||
* An index value of 0xFFFF
|
||||
@ -73,7 +78,7 @@ struct BaseGlyphRecord
|
||||
}
|
||||
|
||||
public:
|
||||
GlyphID glyphId; /* Glyph ID of reference glyph */
|
||||
HBGlyphID glyphId; /* Glyph ID of reference glyph */
|
||||
HBUINT16 firstLayerIdx; /* Index (from beginning of
|
||||
* the Layer Records) to the
|
||||
* layer record. There will be
|
||||
@ -98,22 +103,50 @@ struct COLR
|
||||
{
|
||||
const BaseGlyphRecord &record = (this+baseGlyphsZ).bsearch (numBaseGlyphs, glyph);
|
||||
|
||||
hb_array_t<const LayerRecord> all_layers ((this+layersZ).arrayZ, numLayers);
|
||||
hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers);
|
||||
hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx,
|
||||
record.numLayers);
|
||||
if (count)
|
||||
{
|
||||
hb_array_t<const LayerRecord> segment_layers = glyph_layers.sub_array (start_offset, *count);
|
||||
*count = segment_layers.length;
|
||||
for (unsigned int i = 0; i < segment_layers.length; i++)
|
||||
{
|
||||
layers[i].glyph = segment_layers.arrayZ[i].glyphId;
|
||||
layers[i].color_index = segment_layers.arrayZ[i].colorIdx;
|
||||
}
|
||||
+ glyph_layers.sub_array (start_offset, count)
|
||||
| hb_sink (hb_array (layers, *count))
|
||||
;
|
||||
}
|
||||
return glyph_layers.length;
|
||||
}
|
||||
|
||||
struct accelerator_t
|
||||
{
|
||||
accelerator_t () {}
|
||||
~accelerator_t () { fini (); }
|
||||
|
||||
void init (hb_face_t *face)
|
||||
{ colr = hb_sanitize_context_t ().reference_table<COLR> (face); }
|
||||
|
||||
void fini () { this->colr.destroy (); }
|
||||
|
||||
bool is_valid () { return colr.get_blob ()->length; }
|
||||
|
||||
void closure_glyphs (hb_codepoint_t glyph,
|
||||
hb_set_t *related_ids /* OUT */) const
|
||||
{ colr->closure_glyphs (glyph, related_ids); }
|
||||
|
||||
private:
|
||||
hb_blob_ptr_t<COLR> colr;
|
||||
};
|
||||
|
||||
void closure_glyphs (hb_codepoint_t glyph,
|
||||
hb_set_t *related_ids /* OUT */) const
|
||||
{
|
||||
const BaseGlyphRecord *record = get_base_glyph_record (glyph);
|
||||
if (!record) return;
|
||||
|
||||
auto glyph_layers = (this+layersZ).as_array (numLayers).sub_array (record->firstLayerIdx,
|
||||
record->numLayers);
|
||||
if (!glyph_layers.length) return;
|
||||
related_ids->add_array (&glyph_layers[0].glyphId, glyph_layers.length, LayerRecord::min_size);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
@ -122,12 +155,117 @@ struct COLR
|
||||
(this+layersZ).sanitize (c, numLayers)));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
if (unlikely (base_it.len () != layer_it.len ()))
|
||||
return_trace (false);
|
||||
|
||||
if (unlikely (!c->extend_min (this))) return_trace (false);
|
||||
this->version = version;
|
||||
numLayers = 0;
|
||||
numBaseGlyphs = base_it.len ();
|
||||
baseGlyphsZ = COLR::min_size;
|
||||
layersZ = COLR::min_size + numBaseGlyphs * BaseGlyphRecord::min_size;
|
||||
|
||||
for (const hb_item_type<BaseIterator> _ : + base_it.iter ())
|
||||
{
|
||||
auto* record = c->embed (_);
|
||||
if (unlikely (!record)) return_trace (false);
|
||||
record->firstLayerIdx = numLayers;
|
||||
numLayers += record->numLayers;
|
||||
}
|
||||
|
||||
for (const hb_item_type<LayerIterator>& _ : + layer_it.iter ())
|
||||
_.as_array ().copy (c);
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
const BaseGlyphRecord* get_base_glyph_record (hb_codepoint_t gid) const
|
||||
{
|
||||
if ((unsigned int) gid == 0) // Ignore notdef.
|
||||
return nullptr;
|
||||
const BaseGlyphRecord* record = &(this+baseGlyphsZ).bsearch (numBaseGlyphs, (unsigned int) gid);
|
||||
if ((record && (hb_codepoint_t) record->glyphId != gid))
|
||||
record = nullptr;
|
||||
return record;
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
|
||||
const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map;
|
||||
|
||||
auto base_it =
|
||||
+ hb_range (c->plan->num_output_glyphs ())
|
||||
| hb_map_retains_sorting ([&](hb_codepoint_t new_gid)
|
||||
{
|
||||
hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
|
||||
|
||||
const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid);
|
||||
if (unlikely (!old_record))
|
||||
return hb_pair_t<bool, BaseGlyphRecord> (false, Null (BaseGlyphRecord));
|
||||
|
||||
BaseGlyphRecord new_record;
|
||||
new_record.glyphId = new_gid;
|
||||
new_record.numLayers = old_record->numLayers;
|
||||
return hb_pair_t<bool, BaseGlyphRecord> (true, new_record);
|
||||
})
|
||||
| hb_filter (hb_first)
|
||||
| hb_map_retains_sorting (hb_second)
|
||||
;
|
||||
|
||||
auto layer_it =
|
||||
+ hb_range (c->plan->num_output_glyphs ())
|
||||
| hb_map (reverse_glyph_map)
|
||||
| hb_map_retains_sorting ([&](hb_codepoint_t old_gid)
|
||||
{
|
||||
const BaseGlyphRecord* old_record = get_base_glyph_record (old_gid);
|
||||
hb_vector_t<LayerRecord> out_layers;
|
||||
|
||||
if (unlikely (!old_record ||
|
||||
old_record->firstLayerIdx >= numLayers ||
|
||||
old_record->firstLayerIdx + old_record->numLayers > numLayers))
|
||||
return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
|
||||
|
||||
auto layers = (this+layersZ).as_array (numLayers).sub_array (old_record->firstLayerIdx,
|
||||
old_record->numLayers);
|
||||
out_layers.resize (layers.length);
|
||||
for (unsigned int i = 0; i < layers.length; i++) {
|
||||
out_layers[i] = layers[i];
|
||||
hb_codepoint_t new_gid = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
return hb_pair_t<bool, hb_vector_t<LayerRecord>> (true, out_layers);
|
||||
})
|
||||
| hb_filter (hb_first)
|
||||
| hb_map_retains_sorting (hb_second)
|
||||
;
|
||||
|
||||
if (unlikely (!base_it || !layer_it || base_it.len () != layer_it.len ()))
|
||||
return_trace (false);
|
||||
|
||||
COLR *colr_prime = c->serializer->start_embed<COLR> ();
|
||||
return_trace (colr_prime->serialize (c->serializer, version, base_it, layer_it));
|
||||
}
|
||||
|
||||
protected:
|
||||
HBUINT16 version; /* Table version number (starts at 0). */
|
||||
HBUINT16 numBaseGlyphs; /* Number of Base Glyph Records. */
|
||||
LNNOffsetTo<SortedUnsizedArrayOf<BaseGlyphRecord> >
|
||||
LNNOffsetTo<SortedUnsizedArrayOf<BaseGlyphRecord>>
|
||||
baseGlyphsZ; /* Offset to Base Glyph records. */
|
||||
LNNOffsetTo<UnsizedArrayOf<LayerRecord> >
|
||||
LNNOffsetTo<UnsizedArrayOf<LayerRecord>>
|
||||
layersZ; /* Offset to Layer Records. */
|
||||
HBUINT16 numLayers; /* Number of Layer Records. */
|
||||
public:
|
||||
|
||||
@ -87,15 +87,15 @@ struct CPALV1Tail
|
||||
}
|
||||
|
||||
protected:
|
||||
LNNOffsetTo<UnsizedArrayOf<HBUINT32> >
|
||||
LNNOffsetTo<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> >
|
||||
LNNOffsetTo<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> >
|
||||
LNNOffsetTo<UnsizedArrayOf<NameID>>
|
||||
colorLabelsZ; /* Offset from the beginning of CPAL table to
|
||||
* the color labels array. Set to 0
|
||||
* if no array is provided. */
|
||||
@ -115,7 +115,7 @@ struct CPAL
|
||||
{ return min_size + numPalettes * sizeof (colorRecordIndicesZ[0]); }
|
||||
|
||||
unsigned int get_palette_count () const { return numPalettes; }
|
||||
unsigned int get_color_count () const { return numColors; }
|
||||
unsigned int get_color_count () const { return numColors; }
|
||||
|
||||
hb_ot_color_palette_flags_t get_palette_flags (unsigned int palette_index) const
|
||||
{ return v1 ().get_palette_flags (this, palette_index, numPalettes); }
|
||||
@ -142,12 +142,9 @@ struct CPAL
|
||||
numColors);
|
||||
if (color_count)
|
||||
{
|
||||
hb_array_t<const BGRAColor> segment_colors = palette_colors.sub_array (start_offset, *color_count);
|
||||
/* Always return numColors colors per palette even if it has out-of-bounds start index. */
|
||||
unsigned int count = MIN<unsigned int> (MAX<int> (numColors - start_offset, 0), *color_count);
|
||||
*color_count = count;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
colors[i] = segment_colors[i]; /* Bound-checked read. */
|
||||
+ palette_colors.sub_array (start_offset, color_count)
|
||||
| hb_sink (hb_array (colors, *color_count))
|
||||
;
|
||||
}
|
||||
return numColors;
|
||||
}
|
||||
@ -155,7 +152,7 @@ struct CPAL
|
||||
private:
|
||||
const CPALV1Tail& v1 () const
|
||||
{
|
||||
if (version == 0) return Null(CPALV1Tail);
|
||||
if (version == 0) return Null (CPALV1Tail);
|
||||
return StructAfter<CPALV1Tail> (*this);
|
||||
}
|
||||
|
||||
@ -176,7 +173,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> >
|
||||
LNNOffsetTo<UnsizedArrayOf<BGRAColor>>
|
||||
colorRecordsZ; /* Offset from the beginning of CPAL table to
|
||||
* the first ColorRecord. */
|
||||
UnsizedArrayOf<HBUINT16>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright © 2018 Ebrahim Byagowi
|
||||
* Copyright © 2020 Google, Inc.
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
@ -20,12 +21,15 @@
|
||||
* 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): Calder Kitagawa
|
||||
*/
|
||||
|
||||
#ifndef HB_OT_COLOR_SBIX_TABLE_HH
|
||||
#define HB_OT_COLOR_SBIX_TABLE_HH
|
||||
|
||||
#include "hb-open-type.hh"
|
||||
#include "hb-ot-layout-common.hh"
|
||||
|
||||
/*
|
||||
* sbix -- Standard Bitmap Graphics
|
||||
@ -40,6 +44,20 @@ namespace OT {
|
||||
|
||||
struct SBIXGlyph
|
||||
{
|
||||
SBIXGlyph* copy (hb_serialize_context_t *c, unsigned int data_length) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
SBIXGlyph* new_glyph = c->start_embed<SBIXGlyph> ();
|
||||
if (unlikely (!new_glyph)) return_trace (nullptr);
|
||||
if (unlikely (!c->extend_min (new_glyph))) return_trace (nullptr);
|
||||
|
||||
new_glyph->xOffset = xOffset;
|
||||
new_glyph->yOffset = yOffset;
|
||||
new_glyph->graphicType = graphicType;
|
||||
data.copy (c, data_length);
|
||||
return_trace (new_glyph);
|
||||
}
|
||||
|
||||
HBINT16 xOffset; /* The horizontal (x-axis) offset from the left
|
||||
* edge of the graphic to the glyph’s origin.
|
||||
* That is, the x-coordinate of the point on the
|
||||
@ -62,6 +80,9 @@ struct SBIXGlyph
|
||||
|
||||
struct SBIXStrike
|
||||
{
|
||||
static unsigned int get_size (unsigned num_glyphs)
|
||||
{ return min_size + num_glyphs * HBUINT32::static_size; }
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
@ -116,16 +137,59 @@ struct SBIXStrike
|
||||
return hb_blob_create_sub_blob (sbix_blob, glyph_offset, glyph_length);
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c, unsigned int available_len) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
unsigned int num_output_glyphs = c->plan->num_output_glyphs ();
|
||||
|
||||
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);
|
||||
out->ppem = ppem;
|
||||
out->resolution = resolution;
|
||||
HBUINT32 head;
|
||||
head = get_size (num_output_glyphs + 1);
|
||||
|
||||
bool has_glyphs = false;
|
||||
for (unsigned new_gid = 0; new_gid < num_output_glyphs; new_gid++)
|
||||
{
|
||||
hb_codepoint_t old_gid;
|
||||
if (!c->plan->old_gid_for_new_gid (new_gid, &old_gid) ||
|
||||
unlikely (imageOffsetsZ[old_gid].is_null () ||
|
||||
imageOffsetsZ[old_gid + 1].is_null () ||
|
||||
imageOffsetsZ[old_gid + 1] <= imageOffsetsZ[old_gid] ||
|
||||
imageOffsetsZ[old_gid + 1] - imageOffsetsZ[old_gid] <= SBIXGlyph::min_size) ||
|
||||
(unsigned int) imageOffsetsZ[old_gid + 1] > available_len)
|
||||
{
|
||||
out->imageOffsetsZ[new_gid] = head;
|
||||
continue;
|
||||
}
|
||||
has_glyphs = true;
|
||||
unsigned int delta = imageOffsetsZ[old_gid + 1] - imageOffsetsZ[old_gid];
|
||||
unsigned int glyph_data_length = delta - SBIXGlyph::min_size;
|
||||
if (!(this+imageOffsetsZ[old_gid]).copy (c->serializer, glyph_data_length))
|
||||
return_trace (false);
|
||||
out->imageOffsetsZ[new_gid] = head;
|
||||
head += delta;
|
||||
}
|
||||
if (has_glyphs)
|
||||
out->imageOffsetsZ[num_output_glyphs] = head;
|
||||
else
|
||||
c->serializer->revert (snap);
|
||||
return_trace (has_glyphs);
|
||||
}
|
||||
|
||||
public:
|
||||
HBUINT16 ppem; /* The PPEM size for which this strike was designed. */
|
||||
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<LOffsetTo<SBIXGlyph>>
|
||||
imageOffsetsZ; /* Offset from the beginning of the strike data header
|
||||
* to bitmap data for an individual glyph ID. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (8);
|
||||
DEFINE_SIZE_ARRAY (4, imageOffsetsZ);
|
||||
};
|
||||
|
||||
struct sbix
|
||||
@ -140,7 +204,7 @@ struct sbix
|
||||
{
|
||||
void init (hb_face_t *face)
|
||||
{
|
||||
table = hb_sanitize_context_t().reference_table<sbix> (face);
|
||||
table = hb_sanitize_context_t ().reference_table<sbix> (face);
|
||||
num_glyphs = face->get_num_glyphs ();
|
||||
}
|
||||
void fini () { table.destroy (); }
|
||||
@ -173,9 +237,9 @@ struct sbix
|
||||
{
|
||||
unsigned count = table->strikes.len;
|
||||
if (unlikely (!count))
|
||||
return Null(SBIXStrike);
|
||||
return Null (SBIXStrike);
|
||||
|
||||
unsigned int requested_ppem = MAX (font->x_ppem, font->y_ppem);
|
||||
unsigned int requested_ppem = hb_max (font->x_ppem, font->y_ppem);
|
||||
if (!requested_ppem)
|
||||
requested_ppem = 1<<30; /* Choose largest strike. */
|
||||
/* TODO Add DPI sensitivity as well? */
|
||||
@ -235,18 +299,25 @@ struct sbix
|
||||
const PNGHeader &png = *blob->as<PNGHeader>();
|
||||
|
||||
extents->x_bearing = x_offset;
|
||||
extents->y_bearing = y_offset;
|
||||
extents->y_bearing = png.IHDR.height + y_offset;
|
||||
extents->width = png.IHDR.width;
|
||||
extents->height = png.IHDR.height;
|
||||
extents->height = -1 * png.IHDR.height;
|
||||
|
||||
/* Convert to font units. */
|
||||
if (strike_ppem)
|
||||
{
|
||||
double scale = font->face->get_upem () / (double) strike_ppem;
|
||||
extents->x_bearing = round (extents->x_bearing * scale);
|
||||
extents->y_bearing = round (extents->y_bearing * scale);
|
||||
extents->width = round (extents->width * scale);
|
||||
extents->height = round (extents->height * scale);
|
||||
float scale = font->face->get_upem () / (float) strike_ppem;
|
||||
extents->x_bearing = font->em_scalef_x (extents->x_bearing * scale);
|
||||
extents->y_bearing = font->em_scalef_y (extents->y_bearing * scale);
|
||||
extents->width = font->em_scalef_x (extents->width * scale);
|
||||
extents->height = font->em_scalef_y (extents->height * scale);
|
||||
}
|
||||
else
|
||||
{
|
||||
extents->x_bearing = font->em_scale_x (extents->x_bearing);
|
||||
extents->y_bearing = font->em_scale_y (extents->y_bearing);
|
||||
extents->width = font->em_scale_x (extents->width);
|
||||
extents->height = font->em_scale_y (extents->height);
|
||||
}
|
||||
|
||||
hb_blob_destroy (blob);
|
||||
@ -268,6 +339,63 @@ struct sbix
|
||||
strikes.sanitize (c, this)));
|
||||
}
|
||||
|
||||
bool
|
||||
add_strike (hb_subset_context_t *c, unsigned i) const
|
||||
{
|
||||
if (strikes[i].is_null () || c->source_blob->length < (unsigned) strikes[i])
|
||||
return false;
|
||||
|
||||
return (this+strikes[i]).subset (c, c->source_blob->length - (unsigned) strikes[i]);
|
||||
}
|
||||
|
||||
bool serialize_strike_offsets (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
||||
auto *out = c->serializer->start_embed<LOffsetLArrayOf<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<hb_serialize_context_t::objidx_t> objidxs;
|
||||
for (int i = strikes.len - 1; i >= 0; --i)
|
||||
{
|
||||
auto* o = out->serialize_append (c->serializer);
|
||||
if (unlikely (!o)) return_trace (false);
|
||||
*o = 0;
|
||||
auto snap = c->serializer->snapshot ();
|
||||
c->serializer->push ();
|
||||
bool ret = add_strike (c, i);
|
||||
if (!ret)
|
||||
{
|
||||
c->serializer->pop_discard ();
|
||||
out->pop ();
|
||||
c->serializer->revert (snap);
|
||||
}
|
||||
else
|
||||
{
|
||||
objidxs.push (c->serializer->pop_pack ());
|
||||
new_strikes.push (o);
|
||||
}
|
||||
}
|
||||
for (unsigned int i = 0; i < new_strikes.length; ++i)
|
||||
c->serializer->add_link (*new_strikes[i], objidxs[new_strikes.length - 1 - i]);
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t* c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
|
||||
sbix *sbix_prime = c->serializer->start_embed<sbix> ();
|
||||
if (unlikely (!sbix_prime)) return_trace (false);
|
||||
if (unlikely (!c->serializer->embed (this->version))) return_trace (false);
|
||||
if (unlikely (!c->serializer->embed (this->flags))) return_trace (false);
|
||||
|
||||
return_trace (serialize_strike_offsets (c));
|
||||
}
|
||||
|
||||
protected:
|
||||
HBUINT16 version; /* Table version number — set to 1 */
|
||||
HBUINT16 flags; /* Bit 0: Set to 1. Bit 1: Draw outlines.
|
||||
|
||||
@ -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> >
|
||||
LNNOffsetTo<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.
|
||||
@ -80,7 +80,7 @@ struct SVG
|
||||
struct accelerator_t
|
||||
{
|
||||
void init (hb_face_t *face)
|
||||
{ table = hb_sanitize_context_t().reference_table<SVG> (face); }
|
||||
{ table = hb_sanitize_context_t ().reference_table<SVG> (face); }
|
||||
void fini () { table.destroy (); }
|
||||
|
||||
hb_blob_t *reference_blob_for_glyph (hb_codepoint_t glyph_id) const
|
||||
@ -107,7 +107,7 @@ struct SVG
|
||||
|
||||
protected:
|
||||
HBUINT16 version; /* Table version (starting at 0). */
|
||||
LOffsetTo<SortedArrayOf<SVGDocumentIndexEntry> >
|
||||
LOffsetTo<SortedArrayOf<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. */
|
||||
|
||||
@ -25,20 +25,21 @@
|
||||
* Google Author(s): Sascha Brawer, Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#include "hb-open-type.hh"
|
||||
#include "hb.hh"
|
||||
|
||||
#ifndef HB_NO_COLOR
|
||||
|
||||
#include "hb-ot.h"
|
||||
|
||||
#include "hb-ot-color-cbdt-table.hh"
|
||||
#include "hb-ot-color-colr-table.hh"
|
||||
#include "hb-ot-color-cpal-table.hh"
|
||||
#include "hb-ot-color-sbix-table.hh"
|
||||
#include "hb-ot-color-svg-table.hh"
|
||||
#include "hb-ot-face.hh"
|
||||
#include "hb-ot.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hb-ot-layout.hh"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:hb-ot-color
|
||||
@ -47,6 +48,8 @@
|
||||
* @include: hb-ot.h
|
||||
*
|
||||
* Functions for fetching color-font information from OpenType font faces.
|
||||
*
|
||||
* HarfBuzz supports `COLR`/`CPAL`, `sbix`, `CBDT`, and `SVG` color fonts.
|
||||
**/
|
||||
|
||||
|
||||
@ -57,9 +60,11 @@
|
||||
|
||||
/**
|
||||
* hb_ot_color_has_palettes:
|
||||
* @face: a font face.
|
||||
* @face: #hb_face_t to work upon
|
||||
*
|
||||
* Returns: whether CPAL table is available.
|
||||
* Tests whether a face includes a `CPAL` color-palette table.
|
||||
*
|
||||
* Return value: true if data found, false otherwise
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
@ -71,10 +76,11 @@ hb_ot_color_has_palettes (hb_face_t *face)
|
||||
|
||||
/**
|
||||
* hb_ot_color_palette_get_count:
|
||||
* @face: a font face.
|
||||
* @face: #hb_face_t to work upon
|
||||
*
|
||||
* Returns: the number of color palettes in @face, or zero if @face has
|
||||
* no colors.
|
||||
* Fetches the number of color palettes in a face.
|
||||
*
|
||||
* Return value: the number of palettes found
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
@ -86,13 +92,16 @@ hb_ot_color_palette_get_count (hb_face_t *face)
|
||||
|
||||
/**
|
||||
* hb_ot_color_palette_get_name_id:
|
||||
* @face: a font face.
|
||||
* @palette_index: the index of the color palette whose name is being requested.
|
||||
* @face: #hb_face_t to work upon
|
||||
* @palette_index: The index of the color palette
|
||||
*
|
||||
* Retrieves the name id of a color palette. For example, a color font can
|
||||
* have themed palettes like "Spring", "Summer", "Fall", and "Winter".
|
||||
* Fetches the `name` table Name ID that provides display names for
|
||||
* a `CPAL` color palette.
|
||||
*
|
||||
* Returns: an identifier within @face's `name` table.
|
||||
* Palette display names can be generic (e.g., "Default") or provide
|
||||
* specific, themed names (e.g., "Spring", "Summer", "Fall", and "Winter").
|
||||
*
|
||||
* Return value: the Named ID found for the palette.
|
||||
* If the requested palette has no name the result is #HB_OT_NAME_ID_INVALID.
|
||||
*
|
||||
* Since: 2.1.0
|
||||
@ -106,10 +115,16 @@ hb_ot_color_palette_get_name_id (hb_face_t *face,
|
||||
|
||||
/**
|
||||
* hb_ot_color_palette_color_get_name_id:
|
||||
* @face: a font face.
|
||||
* @color_index: palette entry index.
|
||||
* @face: #hb_face_t to work upon
|
||||
* @color_index: The index of the color
|
||||
*
|
||||
* Returns: Name ID associated with a palette entry, e.g. eye color
|
||||
* Fetches the `name` table Name ID that provides display names for
|
||||
* the specificed color in a face's `CPAL` color palette.
|
||||
*
|
||||
* Display names can be generic (e.g., "Background") or specific
|
||||
* (e.g., "Eye color").
|
||||
*
|
||||
* Return value: the Name ID found for the color.
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
@ -122,10 +137,12 @@ hb_ot_color_palette_color_get_name_id (hb_face_t *face,
|
||||
|
||||
/**
|
||||
* hb_ot_color_palette_get_flags:
|
||||
* @face: a font face
|
||||
* @palette_index: the index of the color palette whose flags are being requested
|
||||
* @face: #hb_face_t to work upon
|
||||
* @palette_index: The index of the color palette
|
||||
*
|
||||
* Returns: the flags for the requested color palette.
|
||||
* Fetches the flags defined for a color palette.
|
||||
*
|
||||
* Return value: the #hb_ot_color_palette_flags_t of the requested color palette
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
@ -138,25 +155,22 @@ hb_ot_color_palette_get_flags (hb_face_t *face,
|
||||
|
||||
/**
|
||||
* hb_ot_color_palette_get_colors:
|
||||
* @face: a font face.
|
||||
* @palette_index:the index of the color palette whose colors
|
||||
* are being requested.
|
||||
* @start_offset: the index of the first color being requested.
|
||||
* @color_count: (inout) (optional): on input, how many colors
|
||||
* can be maximally stored into the @colors array;
|
||||
* on output, how many colors were actually stored.
|
||||
* @colors: (array length=color_count) (out) (optional):
|
||||
* an array of #hb_color_t records. After calling
|
||||
* this function, @colors will be filled with
|
||||
* the palette colors. If @colors is NULL, the function
|
||||
* will just return the number of total colors
|
||||
* without storing any actual colors; this can be used
|
||||
* for allocating a buffer of suitable size before calling
|
||||
* hb_ot_color_palette_get_colors() a second time.
|
||||
* @face: #hb_face_t to work upon
|
||||
* @palette_index: the index of the color palette to query
|
||||
* @start_offset: offset of the first color to retrieve
|
||||
* @color_count: (inout) (optional): Input = the maximum number of colors to return;
|
||||
* Output = the actual number of colors returned (may be zero)
|
||||
* @colors: (out) (array length=color_count) (nullable): The array of #hb_color_t records found
|
||||
*
|
||||
* Retrieves the colors in a color palette.
|
||||
* Fetches a list of the colors in a color palette.
|
||||
*
|
||||
* Returns: the total number of colors in the palette.
|
||||
* After calling this function, @colors will be filled with the palette
|
||||
* colors. If @colors is NULL, the function will just return the number
|
||||
* of total colors without storing any actual colors; this can be used
|
||||
* for allocating a buffer of suitable size before calling
|
||||
* hb_ot_color_palette_get_colors() a second time.
|
||||
*
|
||||
* Return value: the total number of colors in the palette
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
@ -177,9 +191,11 @@ hb_ot_color_palette_get_colors (hb_face_t *face,
|
||||
|
||||
/**
|
||||
* hb_ot_color_has_layers:
|
||||
* @face: a font face.
|
||||
* @face: #hb_face_t to work upon
|
||||
*
|
||||
* Returns: whether COLR table is available.
|
||||
* Tests whether a face includes any `COLR` color layers.
|
||||
*
|
||||
* Return value: true if data found, false otherwise
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
@ -191,14 +207,17 @@ hb_ot_color_has_layers (hb_face_t *face)
|
||||
|
||||
/**
|
||||
* hb_ot_color_glyph_get_layers:
|
||||
* @face: a font face.
|
||||
* @glyph: a layered color glyph id.
|
||||
* @start_offset: starting offset of layers.
|
||||
* @count: (inout) (optional): gets number of layers available to be written on buffer
|
||||
* and returns number of written layers.
|
||||
* @layers: (array length=count) (out) (optional): layers buffer to buffer.
|
||||
* @face: #hb_face_t to work upon
|
||||
* @glyph: The glyph index to query
|
||||
* @start_offset: offset of the first layer to retrieve
|
||||
* @layer_count: (inout) (optional): Input = the maximum number of layers to return;
|
||||
* Output = the actual number of layers returned (may be zero)
|
||||
* @layers: (out) (array length=layer_count) (nullable): The array of layers found
|
||||
*
|
||||
* Returns: Total number of layers a layered color glyph have.
|
||||
* Fetches a list of all color layers for the specified glyph index in the specified
|
||||
* face. The list returned will begin at the offset provided.
|
||||
*
|
||||
* Return value: Total number of layers available for the glyph index queried
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
@ -206,10 +225,10 @@ unsigned int
|
||||
hb_ot_color_glyph_get_layers (hb_face_t *face,
|
||||
hb_codepoint_t glyph,
|
||||
unsigned int start_offset,
|
||||
unsigned int *count, /* IN/OUT. May be NULL. */
|
||||
unsigned int *layer_count, /* IN/OUT. May be NULL. */
|
||||
hb_ot_color_layer_t *layers /* OUT. May be NULL. */)
|
||||
{
|
||||
return face->table.COLR->get_glyph_layers (glyph, start_offset, count, layers);
|
||||
return face->table.COLR->get_glyph_layers (glyph, start_offset, layer_count, layers);
|
||||
}
|
||||
|
||||
|
||||
@ -219,11 +238,11 @@ hb_ot_color_glyph_get_layers (hb_face_t *face,
|
||||
|
||||
/**
|
||||
* hb_ot_color_has_svg:
|
||||
* @face: a font face.
|
||||
* @face: #hb_face_t to work upon.
|
||||
*
|
||||
* Check whether @face has SVG glyph images.
|
||||
* Tests whether a face includes any `SVG` glyph images.
|
||||
*
|
||||
* Returns true if available, false otherwise.
|
||||
* Return value: true if data found, false otherwise.
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
@ -235,12 +254,12 @@ hb_ot_color_has_svg (hb_face_t *face)
|
||||
|
||||
/**
|
||||
* hb_ot_color_glyph_reference_svg:
|
||||
* @face: a font face.
|
||||
* @glyph: a svg glyph index.
|
||||
* @face: #hb_face_t to work upon
|
||||
* @glyph: a svg glyph index
|
||||
*
|
||||
* Get SVG document for a glyph. The blob may be either plain text or gzip-encoded.
|
||||
* Fetches the SVG document for a glyph. The blob may be either plain text or gzip-encoded.
|
||||
*
|
||||
* Returns: (transfer full): respective svg blob of the glyph, if available.
|
||||
* Return value: (transfer full): An #hb_blob_t containing the SVG document of the glyph, if available
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
@ -257,11 +276,11 @@ hb_ot_color_glyph_reference_svg (hb_face_t *face, hb_codepoint_t glyph)
|
||||
|
||||
/**
|
||||
* hb_ot_color_has_png:
|
||||
* @face: a font face.
|
||||
* @face: #hb_face_t to work upon
|
||||
*
|
||||
* Check whether @face has PNG glyph images (either CBDT or sbix tables).
|
||||
* Tests whether a face has PNG glyph images (either in `CBDT` or `sbix` tables).
|
||||
*
|
||||
* Returns true if available, false otherwise.
|
||||
* Return value: true if data found, false otherwise
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
@ -273,14 +292,14 @@ hb_ot_color_has_png (hb_face_t *face)
|
||||
|
||||
/**
|
||||
* hb_ot_color_glyph_reference_png:
|
||||
* @font: a font object, not face. upem should be set on
|
||||
* that font object if one wants to get optimal png blob, otherwise
|
||||
* return the biggest one
|
||||
* @glyph: a glyph index.
|
||||
* @font: #hb_font_t to work upon
|
||||
* @glyph: a glyph index
|
||||
*
|
||||
* Get PNG image for a glyph.
|
||||
* Fetches the PNG image for a glyph. This function takes a font object, not a face object,
|
||||
* as input. To get an optimally sized PNG blob, the UPEM value must be set on the @font
|
||||
* object. If UPEM is unset, the blob returned will be the largest PNG available.
|
||||
*
|
||||
* Returns: (transfer full): respective PNG blob of the glyph, if available.
|
||||
* Return value: (transfer full): An #hb_blob_t containing the PNG image for the glyph, if available
|
||||
*
|
||||
* Since: 2.1.0
|
||||
*/
|
||||
@ -297,3 +316,6 @@ hb_ot_color_glyph_reference_png (hb_font_t *font, hb_codepoint_t glyph)
|
||||
|
||||
return blob;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@ -59,11 +59,11 @@ hb_ot_color_palette_color_get_name_id (hb_face_t *face,
|
||||
|
||||
/**
|
||||
* hb_ot_color_palette_flags_t:
|
||||
* @HB_OT_COLOR_PALETTE_FLAG_DEFAULT: default indicating that there is nothing special
|
||||
* @HB_OT_COLOR_PALETTE_FLAG_DEFAULT: Default indicating that there is nothing special
|
||||
* to note about a color palette.
|
||||
* @HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND: flag indicating that the color
|
||||
* @HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_LIGHT_BACKGROUND: Flag indicating that the color
|
||||
* palette is appropriate to use when displaying the font on a light background such as white.
|
||||
* @HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND: flag indicating that the color
|
||||
* @HB_OT_COLOR_PALETTE_FLAG_USABLE_WITH_DARK_BACKGROUND: Flag indicating that the color
|
||||
* palette is appropriate to use when displaying the font on a dark background such as black.
|
||||
*
|
||||
* Since: 2.1.0
|
||||
@ -110,7 +110,7 @@ HB_EXTERN unsigned int
|
||||
hb_ot_color_glyph_get_layers (hb_face_t *face,
|
||||
hb_codepoint_t glyph,
|
||||
unsigned int start_offset,
|
||||
unsigned int *count, /* IN/OUT. May be NULL. */
|
||||
unsigned int *layer_count, /* IN/OUT. May be NULL. */
|
||||
hb_ot_color_layer_t *layers /* OUT. May be NULL. */);
|
||||
|
||||
/*
|
||||
|
||||
@ -40,6 +40,10 @@ HB_BEGIN_DECLS
|
||||
#ifndef HB_DISABLE_DEPRECATED
|
||||
|
||||
|
||||
/* https://github.com/harfbuzz/harfbuzz/issues/1734 */
|
||||
#define HB_MATH_GLYPH_PART_FLAG_EXTENDER HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER
|
||||
|
||||
|
||||
/* Like hb_ot_layout_table_find_script, but takes zero-terminated array of scripts to test */
|
||||
HB_EXTERN HB_DEPRECATED_FOR (hb_ot_layout_table_select_script) hb_bool_t
|
||||
hb_ot_layout_table_choose_script (hb_face_t *face,
|
||||
|
||||
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright © 2007,2008,2009 Red Hat, Inc.
|
||||
* Copyright © 2012,2013 Google, Inc.
|
||||
* Copyright © 2019, Facebook 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.
|
||||
*
|
||||
* Red Hat Author(s): Behdad Esfahbod
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
* Facebook Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_OT_FACE_TABLE_LIST_HH
|
||||
#define HB_OT_FACE_TABLE_LIST_HH
|
||||
#endif /* HB_OT_FACE_TABLE_LIST_HH */ /* Dummy header guards */
|
||||
|
||||
#ifndef HB_OT_ACCELERATOR
|
||||
#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type)
|
||||
#define _HB_OT_ACCELERATOR_UNDEF
|
||||
#endif
|
||||
|
||||
|
||||
/* 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. */
|
||||
|
||||
/* v--- Add new tables in the right place here. */
|
||||
|
||||
|
||||
/* OpenType fundamentals. */
|
||||
HB_OT_TABLE (OT, head)
|
||||
#if !defined(HB_NO_FACE_COLLECT_UNICODES) || !defined(HB_NO_OT_FONT)
|
||||
HB_OT_ACCELERATOR (OT, cmap)
|
||||
#endif
|
||||
HB_OT_TABLE (OT, hhea)
|
||||
HB_OT_ACCELERATOR (OT, hmtx)
|
||||
HB_OT_TABLE (OT, OS2)
|
||||
#if !defined(HB_NO_OT_FONT_GLYPH_NAMES) || !defined(HB_NO_METRICS) || !defined(HB_NO_STYLE)
|
||||
HB_OT_ACCELERATOR (OT, post)
|
||||
#endif
|
||||
#ifndef HB_NO_NAME
|
||||
HB_OT_ACCELERATOR (OT, name)
|
||||
#endif
|
||||
#ifndef HB_NO_STYLE
|
||||
HB_OT_TABLE (OT, STAT)
|
||||
#endif
|
||||
#ifndef HB_NO_META
|
||||
HB_OT_ACCELERATOR (OT, meta)
|
||||
#endif
|
||||
|
||||
/* Vertical layout. */
|
||||
HB_OT_TABLE (OT, vhea)
|
||||
HB_OT_ACCELERATOR (OT, vmtx)
|
||||
|
||||
/* TrueType outlines. */
|
||||
HB_OT_ACCELERATOR (OT, glyf)
|
||||
|
||||
/* CFF outlines. */
|
||||
#ifndef HB_NO_CFF
|
||||
HB_OT_ACCELERATOR (OT, cff1)
|
||||
HB_OT_ACCELERATOR (OT, cff2)
|
||||
HB_OT_TABLE (OT, VORG)
|
||||
#endif
|
||||
|
||||
/* OpenType variations. */
|
||||
#ifndef HB_NO_VAR
|
||||
HB_OT_TABLE (OT, fvar)
|
||||
HB_OT_TABLE (OT, avar)
|
||||
HB_OT_ACCELERATOR (OT, gvar)
|
||||
HB_OT_TABLE (OT, MVAR)
|
||||
#endif
|
||||
|
||||
/* Legacy kern. */
|
||||
#ifndef HB_NO_OT_KERN
|
||||
HB_OT_TABLE (OT, kern)
|
||||
#endif
|
||||
|
||||
/* OpenType shaping. */
|
||||
#ifndef HB_NO_OT_LAYOUT
|
||||
HB_OT_ACCELERATOR (OT, GDEF)
|
||||
HB_OT_ACCELERATOR (OT, GSUB)
|
||||
HB_OT_ACCELERATOR (OT, GPOS)
|
||||
//HB_OT_TABLE (OT, JSTF)
|
||||
#endif
|
||||
|
||||
/* OpenType baseline. */
|
||||
#ifndef HB_NO_BASE
|
||||
HB_OT_TABLE (OT, BASE)
|
||||
#endif
|
||||
|
||||
/* AAT shaping. */
|
||||
#ifndef HB_NO_AAT
|
||||
HB_OT_TABLE (AAT, morx)
|
||||
HB_OT_TABLE (AAT, mort)
|
||||
HB_OT_TABLE (AAT, kerx)
|
||||
HB_OT_TABLE (AAT, ankr)
|
||||
HB_OT_TABLE (AAT, trak)
|
||||
HB_OT_TABLE (AAT, ltag)
|
||||
HB_OT_TABLE (AAT, feat)
|
||||
// HB_OT_TABLE (AAT, opbd)
|
||||
#endif
|
||||
|
||||
/* OpenType color fonts. */
|
||||
#ifndef HB_NO_COLOR
|
||||
HB_OT_TABLE (OT, COLR)
|
||||
HB_OT_TABLE (OT, CPAL)
|
||||
HB_OT_ACCELERATOR (OT, CBDT)
|
||||
HB_OT_ACCELERATOR (OT, sbix)
|
||||
HB_OT_ACCELERATOR (OT, SVG)
|
||||
#endif
|
||||
|
||||
/* OpenType math. */
|
||||
#ifndef HB_NO_MATH
|
||||
HB_OT_TABLE (OT, MATH)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef _HB_OT_ACCELERATOR_UNDEF
|
||||
#undef HB_OT_ACCELERATOR
|
||||
#endif
|
||||
@ -32,6 +32,7 @@
|
||||
#include "hb-ot-cff2-table.hh"
|
||||
#include "hb-ot-hmtx-table.hh"
|
||||
#include "hb-ot-kern-table.hh"
|
||||
#include "hb-ot-meta-table.hh"
|
||||
#include "hb-ot-name-table.hh"
|
||||
#include "hb-ot-post-table.hh"
|
||||
#include "hb-ot-color-cbdt-table.hh"
|
||||
@ -46,16 +47,12 @@ void hb_ot_face_t::init0 (hb_face_t *face)
|
||||
{
|
||||
this->face = face;
|
||||
#define HB_OT_TABLE(Namespace, Type) Type.init0 ();
|
||||
#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type)
|
||||
HB_OT_TABLES
|
||||
#undef HB_OT_ACCELERATOR
|
||||
#include "hb-ot-face-table-list.hh"
|
||||
#undef HB_OT_TABLE
|
||||
}
|
||||
void hb_ot_face_t::fini ()
|
||||
{
|
||||
#define HB_OT_TABLE(Namespace, Type) Type.fini ();
|
||||
#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type)
|
||||
HB_OT_TABLES
|
||||
#undef HB_OT_ACCELERATOR
|
||||
#include "hb-ot-face-table-list.hh"
|
||||
#undef HB_OT_TABLE
|
||||
}
|
||||
|
||||
@ -38,54 +38,10 @@
|
||||
* hb_ot_face_t
|
||||
*/
|
||||
|
||||
#define HB_OT_TABLES \
|
||||
/* OpenType fundamentals. */ \
|
||||
HB_OT_TABLE(OT, head) \
|
||||
HB_OT_ACCELERATOR(OT, cmap) \
|
||||
HB_OT_ACCELERATOR(OT, hmtx) \
|
||||
HB_OT_ACCELERATOR(OT, vmtx) \
|
||||
HB_OT_ACCELERATOR(OT, post) \
|
||||
HB_OT_TABLE(OT, kern) \
|
||||
HB_OT_ACCELERATOR(OT, glyf) \
|
||||
HB_OT_ACCELERATOR(OT, cff1) \
|
||||
HB_OT_ACCELERATOR(OT, cff2) \
|
||||
HB_OT_TABLE(OT, VORG) \
|
||||
HB_OT_ACCELERATOR(OT, name) \
|
||||
HB_OT_TABLE(OT, OS2) \
|
||||
HB_OT_TABLE(OT, STAT) \
|
||||
/* OpenType shaping. */ \
|
||||
HB_OT_ACCELERATOR(OT, GDEF) \
|
||||
HB_OT_ACCELERATOR(OT, GSUB) \
|
||||
HB_OT_ACCELERATOR(OT, GPOS) \
|
||||
HB_OT_TABLE(OT, BASE) \
|
||||
HB_OT_TABLE(OT, JSTF) \
|
||||
/* AAT shaping. */ \
|
||||
HB_OT_TABLE(AAT, mort) \
|
||||
HB_OT_TABLE(AAT, morx) \
|
||||
HB_OT_TABLE(AAT, kerx) \
|
||||
HB_OT_TABLE(AAT, ankr) \
|
||||
HB_OT_TABLE(AAT, trak) \
|
||||
HB_OT_TABLE(AAT, lcar) \
|
||||
HB_OT_TABLE(AAT, ltag) \
|
||||
HB_OT_TABLE(AAT, feat) \
|
||||
/* OpenType variations. */ \
|
||||
HB_OT_TABLE(OT, fvar) \
|
||||
HB_OT_TABLE(OT, avar) \
|
||||
HB_OT_TABLE(OT, MVAR) \
|
||||
/* OpenType math. */ \
|
||||
HB_OT_TABLE(OT, MATH) \
|
||||
/* OpenType color fonts. */ \
|
||||
HB_OT_TABLE(OT, COLR) \
|
||||
HB_OT_TABLE(OT, CPAL) \
|
||||
HB_OT_ACCELERATOR(OT, CBDT) \
|
||||
HB_OT_ACCELERATOR(OT, sbix) \
|
||||
HB_OT_ACCELERATOR(OT, SVG) \
|
||||
/* */
|
||||
|
||||
/* Declare tables. */
|
||||
#define HB_OT_TABLE(Namespace, Type) namespace Namespace { struct Type; }
|
||||
#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type##_accelerator_t)
|
||||
HB_OT_TABLES
|
||||
#include "hb-ot-face-table-list.hh"
|
||||
#undef HB_OT_ACCELERATOR
|
||||
#undef HB_OT_TABLE
|
||||
|
||||
@ -100,9 +56,7 @@ struct hb_ot_face_t
|
||||
{
|
||||
ORDER_ZERO,
|
||||
#define HB_OT_TABLE(Namespace, Type) HB_OT_TABLE_ORDER (Namespace, Type),
|
||||
#define HB_OT_ACCELERATOR(Namespace, Type) HB_OT_TABLE (Namespace, Type)
|
||||
HB_OT_TABLES
|
||||
#undef HB_OT_ACCELERATOR
|
||||
#include "hb-ot-face-table-list.hh"
|
||||
#undef HB_OT_TABLE
|
||||
};
|
||||
|
||||
@ -111,7 +65,7 @@ struct hb_ot_face_t
|
||||
hb_table_lazy_loader_t<Namespace::Type, HB_OT_TABLE_ORDER (Namespace, Type)> Type;
|
||||
#define HB_OT_ACCELERATOR(Namespace, Type) \
|
||||
hb_face_lazy_loader_t<Namespace::Type##_accelerator_t, HB_OT_TABLE_ORDER (Namespace, Type)> Type;
|
||||
HB_OT_TABLES
|
||||
#include "hb-ot-face-table-list.hh"
|
||||
#undef HB_OT_ACCELERATOR
|
||||
#undef HB_OT_TABLE
|
||||
};
|
||||
|
||||
@ -26,6 +26,8 @@
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#ifndef HB_NO_OT_FONT
|
||||
|
||||
#include "hb-ot.h"
|
||||
|
||||
#include "hb-font.hh"
|
||||
@ -37,7 +39,6 @@
|
||||
#include "hb-ot-cff1-table.hh"
|
||||
#include "hb-ot-cff2-table.hh"
|
||||
#include "hb-ot-hmtx-table.hh"
|
||||
#include "hb-ot-kern-table.hh"
|
||||
#include "hb-ot-os2-table.hh"
|
||||
#include "hb-ot-post-table.hh"
|
||||
#include "hb-ot-stat-table.hh" // Just so we compile it; unused otherwise.
|
||||
@ -52,7 +53,7 @@
|
||||
* @short_description: OpenType font implementation
|
||||
* @include: hb-ot.h
|
||||
*
|
||||
* Functions for using OpenType fonts with hb_shape(). Not that fonts returned
|
||||
* Functions for using OpenType fonts with hb_shape(). Note that fonts returned
|
||||
* by hb_font_create() default to using these functions, so most clients would
|
||||
* never need to call these functions directly.
|
||||
**/
|
||||
@ -149,19 +150,21 @@ hb_ot_get_glyph_v_origin (hb_font_t *font,
|
||||
|
||||
*x = font->get_glyph_h_advance (glyph) / 2;
|
||||
|
||||
#ifndef HB_NO_OT_FONT_CFF
|
||||
const OT::VORG &VORG = *ot_face->VORG;
|
||||
if (VORG.has_data ())
|
||||
{
|
||||
*y = font->em_scale_y (VORG.get_y_origin (glyph));
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
hb_glyph_extents_t extents = {0};
|
||||
if (ot_face->glyf->get_extents (glyph, &extents))
|
||||
if (ot_face->glyf->get_extents (font, glyph, &extents))
|
||||
{
|
||||
const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
|
||||
hb_position_t tsb = vmtx.get_side_bearing (glyph);
|
||||
*y = font->em_scale_y (extents.y_bearing + tsb);
|
||||
hb_position_t tsb = vmtx.get_side_bearing (font, glyph);
|
||||
*y = extents.y_bearing + font->em_scale_y (tsb);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -180,23 +183,24 @@ hb_ot_get_glyph_extents (hb_font_t *font,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
|
||||
bool ret = ot_face->sbix->get_extents (font, glyph, extents);
|
||||
if (!ret)
|
||||
ret = ot_face->glyf->get_extents (glyph, extents);
|
||||
if (!ret)
|
||||
ret = ot_face->cff1->get_extents (glyph, extents);
|
||||
if (!ret)
|
||||
ret = ot_face->cff2->get_extents (font, glyph, extents);
|
||||
if (!ret)
|
||||
ret = ot_face->CBDT->get_extents (font, glyph, extents);
|
||||
|
||||
#if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
|
||||
if (ot_face->sbix->get_extents (font, glyph, extents)) return true;
|
||||
#endif
|
||||
if (ot_face->glyf->get_extents (font, glyph, extents)) return true;
|
||||
#ifndef HB_NO_OT_FONT_CFF
|
||||
if (ot_face->cff1->get_extents (font, glyph, extents)) return true;
|
||||
if (ot_face->cff2->get_extents (font, glyph, extents)) return true;
|
||||
#endif
|
||||
#if !defined(HB_NO_OT_FONT_BITMAP) && !defined(HB_NO_COLOR)
|
||||
if (ot_face->CBDT->get_extents (font, glyph, extents)) return true;
|
||||
#endif
|
||||
|
||||
// TODO Hook up side-bearings variations.
|
||||
extents->x_bearing = font->em_scale_x (extents->x_bearing);
|
||||
extents->y_bearing = font->em_scale_y (extents->y_bearing);
|
||||
extents->width = font->em_scale_x (extents->width);
|
||||
extents->height = font->em_scale_y (extents->height);
|
||||
return ret;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef HB_NO_OT_FONT_GLYPH_NAMES
|
||||
static hb_bool_t
|
||||
hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED,
|
||||
void *font_data,
|
||||
@ -205,9 +209,12 @@ hb_ot_get_glyph_name (hb_font_t *font HB_UNUSED,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
|
||||
return ot_face->post->get_glyph_name (glyph, name, size);
|
||||
if (ot_face->post->get_glyph_name (glyph, name, size)) return true;
|
||||
#ifndef HB_NO_OT_FONT_CFF
|
||||
if (ot_face->cff1->get_glyph_name (glyph, name, size)) return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED,
|
||||
void *font_data,
|
||||
@ -216,37 +223,34 @@ hb_ot_get_glyph_from_name (hb_font_t *font HB_UNUSED,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
|
||||
return ot_face->post->get_glyph_from_name (name, len, glyph);
|
||||
if (ot_face->post->get_glyph_from_name (name, len, glyph)) return true;
|
||||
#ifndef HB_NO_OT_FONT_CFF
|
||||
if (ot_face->cff1->get_glyph_from_name (name, len, glyph)) return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
static hb_bool_t
|
||||
hb_ot_get_font_h_extents (hb_font_t *font,
|
||||
void *font_data,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_font_extents_t *metrics,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
|
||||
const OT::hmtx_accelerator_t &hmtx = *ot_face->hmtx;
|
||||
metrics->ascender = font->em_scale_y (hmtx.ascender);
|
||||
metrics->descender = font->em_scale_y (hmtx.descender);
|
||||
metrics->line_gap = font->em_scale_y (hmtx.line_gap);
|
||||
// TODO Hook up variations.
|
||||
return hmtx.has_font_extents;
|
||||
return _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_ASCENDER, &metrics->ascender) &&
|
||||
_hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_DESCENDER, &metrics->descender) &&
|
||||
_hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_HORIZONTAL_LINE_GAP, &metrics->line_gap);
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
hb_ot_get_font_v_extents (hb_font_t *font,
|
||||
void *font_data,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_font_extents_t *metrics,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data;
|
||||
const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx;
|
||||
metrics->ascender = font->em_scale_x (vmtx.ascender);
|
||||
metrics->descender = font->em_scale_x (vmtx.descender);
|
||||
metrics->line_gap = font->em_scale_x (vmtx.line_gap);
|
||||
// TODO Hook up variations.
|
||||
return vmtx.has_font_extents;
|
||||
return _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_ASCENDER, &metrics->ascender) &&
|
||||
_hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_DESCENDER, &metrics->descender) &&
|
||||
_hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_LINE_GAP, &metrics->line_gap);
|
||||
}
|
||||
|
||||
#if HB_USE_ATEXIT
|
||||
@ -270,8 +274,10 @@ static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot
|
||||
hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ot_get_glyph_v_origin, nullptr, nullptr);
|
||||
hb_font_funcs_set_glyph_extents_func (funcs, hb_ot_get_glyph_extents, nullptr, nullptr);
|
||||
//hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ot_get_glyph_contour_point, nullptr, nullptr);
|
||||
#ifndef HB_NO_OT_FONT_GLYPH_NAMES
|
||||
hb_font_funcs_set_glyph_name_func (funcs, hb_ot_get_glyph_name, nullptr, nullptr);
|
||||
hb_font_funcs_set_glyph_from_name_func (funcs, hb_ot_get_glyph_from_name, nullptr, nullptr);
|
||||
#endif
|
||||
|
||||
hb_font_funcs_make_immutable (funcs);
|
||||
|
||||
@ -311,3 +317,20 @@ hb_ot_font_set_funcs (hb_font_t *font)
|
||||
&font->face->table,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
int
|
||||
_glyf_get_side_bearing_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
|
||||
{
|
||||
return font->face->table.glyf->get_side_bearing_var (font, glyph, is_vertical);
|
||||
}
|
||||
|
||||
unsigned
|
||||
_glyf_get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical)
|
||||
{
|
||||
return font->face->table.glyf->get_advance_var (font, glyph, is_vertical);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -41,68 +41,31 @@ namespace OT {
|
||||
|
||||
struct DeviceRecord
|
||||
{
|
||||
struct SubsetView
|
||||
{
|
||||
const DeviceRecord *source_device_record;
|
||||
unsigned int sizeDeviceRecord;
|
||||
hb_subset_plan_t *subset_plan;
|
||||
|
||||
void init (const DeviceRecord *source_device_record,
|
||||
unsigned int sizeDeviceRecord,
|
||||
hb_subset_plan_t *subset_plan)
|
||||
{
|
||||
this->source_device_record = source_device_record;
|
||||
this->sizeDeviceRecord = sizeDeviceRecord;
|
||||
this->subset_plan = subset_plan;
|
||||
}
|
||||
|
||||
unsigned int len () const
|
||||
{ return this->subset_plan->glyphs.length; }
|
||||
|
||||
const HBUINT8* operator [] (unsigned int i) const
|
||||
{
|
||||
if (unlikely (i >= len ())) return nullptr;
|
||||
hb_codepoint_t gid = this->subset_plan->glyphs [i];
|
||||
|
||||
if (gid >= sizeDeviceRecord - DeviceRecord::min_size)
|
||||
return nullptr;
|
||||
return &(this->source_device_record->widthsZ[gid]);
|
||||
}
|
||||
};
|
||||
|
||||
static unsigned int get_size (unsigned int count)
|
||||
static unsigned int get_size (unsigned count)
|
||||
{ return hb_ceil_to_4 (min_size + count * HBUINT8::static_size); }
|
||||
|
||||
bool serialize (hb_serialize_context_t *c, const SubsetView &subset_view)
|
||||
template<typename Iterator,
|
||||
hb_requires (hb_is_iterator (Iterator))>
|
||||
bool serialize (hb_serialize_context_t *c, unsigned pixelSize, Iterator it)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
||||
unsigned int size = get_size (subset_view.len ());
|
||||
if (unlikely (!c->allocate_size<DeviceRecord> (size)))
|
||||
{
|
||||
DEBUG_MSG(SUBSET, nullptr, "Couldn't allocate enough space for DeviceRecord: %d.",
|
||||
size);
|
||||
return_trace (false);
|
||||
}
|
||||
unsigned length = it.len ();
|
||||
|
||||
this->pixelSize.set (subset_view.source_device_record->pixelSize);
|
||||
this->maxWidth.set (subset_view.source_device_record->maxWidth);
|
||||
if (unlikely (!c->extend (*this, length))) return_trace (false);
|
||||
|
||||
for (unsigned int i = 0; i < subset_view.len (); i++)
|
||||
{
|
||||
const HBUINT8 *width = subset_view[i];
|
||||
if (!width)
|
||||
{
|
||||
DEBUG_MSG(SUBSET, nullptr, "HDMX width for new gid %d is missing.", i);
|
||||
return_trace (false);
|
||||
}
|
||||
widthsZ[i].set (*width);
|
||||
}
|
||||
this->pixelSize = pixelSize;
|
||||
this->maxWidth =
|
||||
+ it
|
||||
| hb_reduce (hb_max, 0u);
|
||||
|
||||
+ it
|
||||
| hb_sink (widthsZ.as_array (length));
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned int sizeDeviceRecord) const
|
||||
bool sanitize (hb_sanitize_context_t *c, unsigned sizeDeviceRecord) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
@ -132,62 +95,60 @@ struct hdmx
|
||||
return StructAtOffset<DeviceRecord> (&this->firstDeviceRecord, i * sizeDeviceRecord);
|
||||
}
|
||||
|
||||
bool serialize (hb_serialize_context_t *c, const hdmx *source_hdmx, hb_subset_plan_t *plan)
|
||||
template<typename Iterator,
|
||||
hb_requires (hb_is_iterator (Iterator))>
|
||||
bool serialize (hb_serialize_context_t *c, unsigned version, Iterator it)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
||||
if (unlikely (!c->extend_min ((*this)))) return_trace (false);
|
||||
|
||||
this->version.set (source_hdmx->version);
|
||||
this->numRecords.set (source_hdmx->numRecords);
|
||||
this->sizeDeviceRecord.set (DeviceRecord::get_size (plan->glyphs.length));
|
||||
this->version = version;
|
||||
this->numRecords = it.len ();
|
||||
this->sizeDeviceRecord = DeviceRecord::get_size (it ? (*it).second.len () : 0);
|
||||
|
||||
for (unsigned int i = 0; i < source_hdmx->numRecords; i++)
|
||||
{
|
||||
DeviceRecord::SubsetView subset_view;
|
||||
subset_view.init (&(*source_hdmx)[i], source_hdmx->sizeDeviceRecord, plan);
|
||||
for (const hb_item_type<Iterator>& _ : +it)
|
||||
c->start_embed<DeviceRecord> ()->serialize (c, _.first, _.second);
|
||||
|
||||
if (!c->start_embed<DeviceRecord> ()->serialize (c, subset_view))
|
||||
return_trace (false);
|
||||
}
|
||||
return_trace (c->successful);
|
||||
}
|
||||
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
|
||||
hdmx *hdmx_prime = c->serializer->start_embed <hdmx> ();
|
||||
if (unlikely (!hdmx_prime)) return_trace (false);
|
||||
|
||||
auto it =
|
||||
+ hb_range ((unsigned) numRecords)
|
||||
| hb_map ([c, this] (unsigned _)
|
||||
{
|
||||
const DeviceRecord *device_record =
|
||||
&StructAtOffset<DeviceRecord> (&firstDeviceRecord,
|
||||
_ * sizeDeviceRecord);
|
||||
auto row =
|
||||
+ hb_range (c->plan->num_output_glyphs ())
|
||||
| hb_map (c->plan->reverse_glyph_map)
|
||||
| hb_map ([this, c, device_record] (hb_codepoint_t _)
|
||||
{
|
||||
if (c->plan->is_empty_glyph (_))
|
||||
return Null (HBUINT8);
|
||||
return device_record->widthsZ.as_array (get_num_glyphs ()) [_];
|
||||
})
|
||||
;
|
||||
return hb_pair ((unsigned) device_record->pixelSize, +row);
|
||||
})
|
||||
;
|
||||
|
||||
hdmx_prime->serialize (c->serializer, version, it);
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
static size_t get_subsetted_size (const hdmx *source_hdmx, hb_subset_plan_t *plan)
|
||||
unsigned get_num_glyphs () const
|
||||
{
|
||||
return min_size + source_hdmx->numRecords * DeviceRecord::get_size (plan->glyphs.length);
|
||||
}
|
||||
|
||||
bool subset (hb_subset_plan_t *plan) const
|
||||
{
|
||||
size_t dest_size = get_subsetted_size (this, plan);
|
||||
hdmx *dest = (hdmx *) malloc (dest_size);
|
||||
if (unlikely (!dest))
|
||||
{
|
||||
DEBUG_MSG(SUBSET, nullptr, "Unable to alloc %lu for hdmx subset output.", (unsigned long) dest_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
hb_serialize_context_t c (dest, dest_size);
|
||||
hdmx *hdmx_prime = c.start_serialize<hdmx> ();
|
||||
if (!hdmx_prime || !hdmx_prime->serialize (&c, this, plan))
|
||||
{
|
||||
free (dest);
|
||||
DEBUG_MSG(SUBSET, nullptr, "Failed to serialize write new hdmx.");
|
||||
return false;
|
||||
}
|
||||
c.end_serialize ();
|
||||
|
||||
hb_blob_t *hdmx_prime_blob = hb_blob_create ((const char *) dest,
|
||||
dest_size,
|
||||
HB_MEMORY_MODE_READONLY,
|
||||
dest,
|
||||
free);
|
||||
bool result = plan->add_table (HB_OT_TAG_hdmx, hdmx_prime_blob);
|
||||
hb_blob_destroy (hdmx_prime_blob);
|
||||
|
||||
return result;
|
||||
return sizeDeviceRecord - DeviceRecord::min_size;
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
@ -200,10 +161,12 @@ struct hdmx
|
||||
}
|
||||
|
||||
protected:
|
||||
HBUINT16 version; /* Table version number (0) */
|
||||
HBUINT16 numRecords; /* Number of device records. */
|
||||
HBUINT32 sizeDeviceRecord; /* Size of a device record, 32-bit aligned. */
|
||||
DeviceRecord firstDeviceRecord; /* Array of device records. */
|
||||
HBUINT16 version; /* Table version number (0) */
|
||||
HBUINT16 numRecords; /* Number of device records. */
|
||||
HBUINT32 sizeDeviceRecord;
|
||||
/* Size of a device record, 32-bit aligned. */
|
||||
DeviceRecord firstDeviceRecord;
|
||||
/* Array of device records. */
|
||||
public:
|
||||
DEFINE_SIZE_MIN (8);
|
||||
};
|
||||
|
||||
@ -54,6 +54,18 @@ struct head
|
||||
return 16 <= upem && upem <= 16384 ? upem : 1000;
|
||||
}
|
||||
|
||||
bool serialize (hb_serialize_context_t *c) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
return_trace ((bool) c->embed (this));
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
return_trace (serialize (c->serializer));
|
||||
}
|
||||
|
||||
enum mac_style_flag_t {
|
||||
BOLD = 1u<<0,
|
||||
ITALIC = 1u<<1,
|
||||
|
||||
@ -45,6 +45,8 @@ namespace OT {
|
||||
template <typename T>
|
||||
struct _hea
|
||||
{
|
||||
bool has_data () const { return version.major; }
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
@ -52,35 +54,38 @@ struct _hea
|
||||
}
|
||||
|
||||
public:
|
||||
FixedVersion<>version; /* 0x00010000u for version 1.0. */
|
||||
FWORD ascender; /* Typographic ascent. */
|
||||
FWORD descender; /* Typographic descent. */
|
||||
FWORD lineGap; /* Typographic line gap. */
|
||||
UFWORD advanceMax; /* Maximum advance width/height value in
|
||||
* metrics table. */
|
||||
FWORD minLeadingBearing; /* Minimum left/top sidebearing value in
|
||||
* metrics table. */
|
||||
FWORD minTrailingBearing; /* Minimum right/bottom sidebearing value;
|
||||
* calculated as Min(aw - lsb -
|
||||
* (xMax - xMin)) for horizontal. */
|
||||
FWORD maxExtent; /* horizontal: Max(lsb + (xMax - xMin)),
|
||||
* vertical: minLeadingBearing+(yMax-yMin). */
|
||||
HBINT16 caretSlopeRise; /* Used to calculate the slope of the
|
||||
* cursor (rise/run); 1 for vertical caret,
|
||||
* 0 for horizontal.*/
|
||||
HBINT16 caretSlopeRun; /* 0 for vertical caret, 1 for horizontal. */
|
||||
HBINT16 caretOffset; /* The amount by which a slanted
|
||||
* highlight on a glyph needs
|
||||
* to be shifted to produce the
|
||||
* best appearance. Set to 0 for
|
||||
* non-slanted fonts. */
|
||||
HBINT16 reserved1; /* Set to 0. */
|
||||
HBINT16 reserved2; /* Set to 0. */
|
||||
HBINT16 reserved3; /* Set to 0. */
|
||||
HBINT16 reserved4; /* Set to 0. */
|
||||
HBINT16 metricDataFormat; /* 0 for current format. */
|
||||
HBUINT16 numberOfLongMetrics; /* Number of LongMetric entries in metric
|
||||
* table. */
|
||||
FixedVersion<>version; /* 0x00010000u for version 1.0. */
|
||||
FWORD ascender; /* Typographic ascent. */
|
||||
FWORD descender; /* Typographic descent. */
|
||||
FWORD lineGap; /* Typographic line gap. */
|
||||
UFWORD advanceMax; /* Maximum advance width/height value in
|
||||
* metrics table. */
|
||||
FWORD minLeadingBearing;
|
||||
/* Minimum left/top sidebearing value in
|
||||
* metrics table. */
|
||||
FWORD minTrailingBearing;
|
||||
/* Minimum right/bottom sidebearing value;
|
||||
* calculated as Min(aw - lsb -
|
||||
* (xMax - xMin)) for horizontal. */
|
||||
FWORD maxExtent; /* horizontal: Max(lsb + (xMax - xMin)),
|
||||
* vertical: minLeadingBearing+(yMax-yMin). */
|
||||
HBINT16 caretSlopeRise; /* Used to calculate the slope of the
|
||||
* cursor (rise/run); 1 for vertical caret,
|
||||
* 0 for horizontal.*/
|
||||
HBINT16 caretSlopeRun; /* 0 for vertical caret, 1 for horizontal. */
|
||||
HBINT16 caretOffset; /* The amount by which a slanted
|
||||
* highlight on a glyph needs
|
||||
* to be shifted to produce the
|
||||
* best appearance. Set to 0 for
|
||||
* non-slanted fonts. */
|
||||
HBINT16 reserved1; /* Set to 0. */
|
||||
HBINT16 reserved2; /* Set to 0. */
|
||||
HBINT16 reserved3; /* Set to 0. */
|
||||
HBINT16 reserved4; /* Set to 0. */
|
||||
HBINT16 metricDataFormat;/* 0 for current format. */
|
||||
HBUINT16 numberOfLongMetrics;
|
||||
/* Number of LongMetric entries in metric
|
||||
* table. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (36);
|
||||
};
|
||||
|
||||
@ -29,8 +29,8 @@
|
||||
|
||||
#include "hb-open-type.hh"
|
||||
#include "hb-ot-hhea-table.hh"
|
||||
#include "hb-ot-os2-table.hh"
|
||||
#include "hb-ot-var-hvar-table.hh"
|
||||
#include "hb-ot-metrics.hh"
|
||||
|
||||
/*
|
||||
* hmtx -- Horizontal Metrics
|
||||
@ -42,6 +42,13 @@
|
||||
#define HB_OT_TAG_vmtx HB_TAG('v','m','t','x')
|
||||
|
||||
|
||||
HB_INTERNAL int
|
||||
_glyf_get_side_bearing_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical);
|
||||
|
||||
HB_INTERNAL unsigned
|
||||
_glyf_get_advance_var (hb_font_t *font, hb_codepoint_t glyph, bool is_vertical);
|
||||
|
||||
|
||||
namespace OT {
|
||||
|
||||
|
||||
@ -53,6 +60,7 @@ struct LongMetric
|
||||
DEFINE_SIZE_STATIC (4);
|
||||
};
|
||||
|
||||
|
||||
template <typename T, typename H>
|
||||
struct hmtxvmtx
|
||||
{
|
||||
@ -66,7 +74,7 @@ struct hmtxvmtx
|
||||
|
||||
|
||||
bool subset_update_header (hb_subset_plan_t *plan,
|
||||
unsigned int num_hmetrics) const
|
||||
unsigned int num_hmetrics) const
|
||||
{
|
||||
hb_blob_t *src_blob = hb_sanitize_context_t ().reference_table<H> (plan->source, H::tableTag);
|
||||
hb_blob_t *dest_blob = hb_blob_copy_writable_or_fail (src_blob);
|
||||
@ -78,7 +86,7 @@ struct hmtxvmtx
|
||||
|
||||
unsigned int length;
|
||||
H *table = (H *) hb_blob_get_data (dest_blob, &length);
|
||||
table->numberOfLongMetrics.set (num_hmetrics);
|
||||
table->numberOfLongMetrics = num_hmetrics;
|
||||
|
||||
bool result = plan->add_table (H::tableTag, dest_blob);
|
||||
hb_blob_destroy (dest_blob);
|
||||
@ -86,100 +94,66 @@ struct hmtxvmtx
|
||||
return result;
|
||||
}
|
||||
|
||||
bool subset (hb_subset_plan_t *plan) const
|
||||
template<typename Iterator,
|
||||
hb_requires (hb_is_iterator (Iterator))>
|
||||
void serialize (hb_serialize_context_t *c,
|
||||
Iterator it,
|
||||
unsigned num_advances)
|
||||
{
|
||||
typename T::accelerator_t _mtx;
|
||||
_mtx.init (plan->source);
|
||||
|
||||
/* All the trailing glyphs with the same advance can use one LongMetric
|
||||
* and just keep LSB */
|
||||
hb_vector_t<hb_codepoint_t> &gids = plan->glyphs;
|
||||
unsigned int num_advances = gids.length;
|
||||
unsigned int last_advance = _mtx.get_advance (gids[num_advances - 1]);
|
||||
while (num_advances > 1 &&
|
||||
last_advance == _mtx.get_advance (gids[num_advances - 2]))
|
||||
unsigned idx = 0;
|
||||
for (auto _ : it)
|
||||
{
|
||||
num_advances--;
|
||||
}
|
||||
|
||||
/* alloc the new table */
|
||||
size_t dest_sz = num_advances * 4
|
||||
+ (gids.length - num_advances) * 2;
|
||||
void *dest = (void *) malloc (dest_sz);
|
||||
if (unlikely (!dest))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
DEBUG_MSG(SUBSET, nullptr, "%c%c%c%c in src has %d advances, %d lsbs", HB_UNTAG(T::tableTag), _mtx.num_advances, _mtx.num_metrics - _mtx.num_advances);
|
||||
DEBUG_MSG(SUBSET, nullptr, "%c%c%c%c in dest has %d advances, %d lsbs, %u bytes", HB_UNTAG(T::tableTag), num_advances, gids.length - num_advances, (unsigned int) dest_sz);
|
||||
|
||||
const char *source_table = hb_blob_get_data (_mtx.table.get_blob (), nullptr);
|
||||
// Copy everything over
|
||||
LongMetric * old_metrics = (LongMetric *) source_table;
|
||||
FWORD *lsbs = (FWORD *) (old_metrics + _mtx.num_advances);
|
||||
char * dest_pos = (char *) dest;
|
||||
|
||||
bool failed = false;
|
||||
for (unsigned int i = 0; i < gids.length; i++)
|
||||
{
|
||||
/* the last metric or the one for gids[i] */
|
||||
LongMetric *src_metric = old_metrics + MIN ((hb_codepoint_t) _mtx.num_advances - 1, gids[i]);
|
||||
if (gids[i] < _mtx.num_advances)
|
||||
if (idx < num_advances)
|
||||
{
|
||||
/* src is a LongMetric */
|
||||
if (i < num_advances)
|
||||
{
|
||||
/* dest is a LongMetric, copy it */
|
||||
*((LongMetric *) dest_pos) = *src_metric;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* dest just sb */
|
||||
*((FWORD *) dest_pos) = src_metric->sb;
|
||||
}
|
||||
LongMetric lm;
|
||||
lm.advance = _.first;
|
||||
lm.sb = _.second;
|
||||
if (unlikely (!c->embed<LongMetric> (&lm))) return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gids[i] >= _mtx.num_metrics)
|
||||
{
|
||||
DEBUG_MSG(SUBSET, nullptr, "gid %d is >= number of source metrics %d",
|
||||
gids[i], _mtx.num_metrics);
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
FWORD src_sb = *(lsbs + gids[i] - _mtx.num_advances);
|
||||
if (i < num_advances)
|
||||
{
|
||||
/* dest needs a full LongMetric */
|
||||
LongMetric *metric = (LongMetric *)dest_pos;
|
||||
metric->advance = src_metric->advance;
|
||||
metric->sb = src_sb;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* dest just needs an sb */
|
||||
*((FWORD *) dest_pos) = src_sb;
|
||||
}
|
||||
FWORD *sb = c->allocate_size<FWORD> (FWORD::static_size);
|
||||
if (unlikely (!sb)) return;
|
||||
*sb = _.second;
|
||||
}
|
||||
dest_pos += (i < num_advances ? 4 : 2);
|
||||
idx++;
|
||||
}
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
|
||||
T *table_prime = c->serializer->start_embed <T> ();
|
||||
if (unlikely (!table_prime)) return_trace (false);
|
||||
|
||||
accelerator_t _mtx;
|
||||
_mtx.init (c->plan->source);
|
||||
unsigned num_advances = _mtx.num_advances_for_subset (c->plan);
|
||||
|
||||
auto it =
|
||||
+ hb_range (c->plan->num_output_glyphs ())
|
||||
| hb_map ([c, &_mtx] (unsigned _)
|
||||
{
|
||||
hb_codepoint_t old_gid;
|
||||
if (!c->plan->old_gid_for_new_gid (_, &old_gid))
|
||||
return hb_pair (0u, 0);
|
||||
return hb_pair (_mtx.get_advance (old_gid), _mtx.get_side_bearing (old_gid));
|
||||
})
|
||||
;
|
||||
|
||||
table_prime->serialize (c->serializer, it, num_advances);
|
||||
|
||||
_mtx.fini ();
|
||||
|
||||
// Amend header num hmetrics
|
||||
if (failed || unlikely (!subset_update_header (plan, num_advances)))
|
||||
{
|
||||
free (dest);
|
||||
return false;
|
||||
}
|
||||
if (unlikely (c->serializer->ran_out_of_room || c->serializer->in_error ()))
|
||||
return_trace (false);
|
||||
|
||||
hb_blob_t *result = hb_blob_create ((const char *)dest,
|
||||
dest_sz,
|
||||
HB_MEMORY_MODE_READONLY,
|
||||
dest,
|
||||
free);
|
||||
bool success = plan->add_table (T::tableTag, result);
|
||||
hb_blob_destroy (result);
|
||||
return success;
|
||||
// Amend header num hmetrics
|
||||
if (unlikely (!subset_update_header (c->plan, num_advances)))
|
||||
return_trace (false);
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
struct accelerator_t
|
||||
@ -187,34 +161,13 @@ struct hmtxvmtx
|
||||
friend struct hmtxvmtx;
|
||||
|
||||
void init (hb_face_t *face,
|
||||
unsigned int default_advance_ = 0)
|
||||
unsigned int default_advance_ = 0)
|
||||
{
|
||||
default_advance = default_advance_ ? default_advance_ : hb_face_get_upem (face);
|
||||
|
||||
bool got_font_extents = false;
|
||||
if (T::os2Tag != HB_TAG_NONE && face->table.OS2->is_typo_metrics ())
|
||||
{
|
||||
ascender = abs (face->table.OS2->sTypoAscender);
|
||||
descender = -abs (face->table.OS2->sTypoDescender);
|
||||
line_gap = face->table.OS2->sTypoLineGap;
|
||||
got_font_extents = (ascender | descender) != 0;
|
||||
}
|
||||
num_advances = T::is_horizontal ? face->table.hhea->numberOfLongMetrics : face->table.vhea->numberOfLongMetrics;
|
||||
|
||||
hb_blob_t *_hea_blob = hb_sanitize_context_t().reference_table<H> (face);
|
||||
const H *_hea_table = _hea_blob->as<H> ();
|
||||
num_advances = _hea_table->numberOfLongMetrics;
|
||||
if (!got_font_extents)
|
||||
{
|
||||
ascender = abs (_hea_table->ascender);
|
||||
descender = -abs (_hea_table->descender);
|
||||
line_gap = _hea_table->lineGap;
|
||||
got_font_extents = (ascender | descender) != 0;
|
||||
}
|
||||
hb_blob_destroy (_hea_blob);
|
||||
|
||||
has_font_extents = got_font_extents;
|
||||
|
||||
table = hb_sanitize_context_t().reference_table<hmtxvmtx> (face, T::tableTag);
|
||||
table = hb_sanitize_context_t ().reference_table<hmtxvmtx> (face, T::tableTag);
|
||||
|
||||
/* Cap num_metrics() and num_advances() based on table length. */
|
||||
unsigned int len = table.get_length ();
|
||||
@ -231,7 +184,7 @@ struct hmtxvmtx
|
||||
table = hb_blob_get_empty ();
|
||||
}
|
||||
|
||||
var_table = hb_sanitize_context_t().reference_table<HVARVVAR> (face, T::variationsTag);
|
||||
var_table = hb_sanitize_context_t ().reference_table<HVARVVAR> (face, T::variationsTag);
|
||||
}
|
||||
|
||||
void fini ()
|
||||
@ -240,8 +193,7 @@ struct hmtxvmtx
|
||||
var_table.destroy ();
|
||||
}
|
||||
|
||||
/* TODO Add variations version. */
|
||||
unsigned int get_side_bearing (hb_codepoint_t glyph) const
|
||||
int get_side_bearing (hb_codepoint_t glyph) const
|
||||
{
|
||||
if (glyph < num_advances)
|
||||
return table->longMetricZ[glyph].sb;
|
||||
@ -253,6 +205,23 @@ struct hmtxvmtx
|
||||
return bearings[glyph - num_advances];
|
||||
}
|
||||
|
||||
int get_side_bearing (hb_font_t *font, hb_codepoint_t glyph) const
|
||||
{
|
||||
int side_bearing = get_side_bearing (glyph);
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
if (unlikely (glyph >= num_metrics) || !font->num_coords)
|
||||
return side_bearing;
|
||||
|
||||
if (var_table.get_length ())
|
||||
return side_bearing + var_table->get_side_bearing_var (glyph, font->coords, font->num_coords); // TODO Optimize?!
|
||||
|
||||
return _glyf_get_side_bearing_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
|
||||
#else
|
||||
return side_bearing;
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned int get_advance (hb_codepoint_t glyph) const
|
||||
{
|
||||
if (unlikely (glyph >= num_metrics))
|
||||
@ -266,25 +235,52 @@ struct hmtxvmtx
|
||||
return default_advance;
|
||||
}
|
||||
|
||||
return table->longMetricZ[MIN (glyph, (uint32_t) num_advances - 1)].advance;
|
||||
return table->longMetricZ[hb_min (glyph, (uint32_t) num_advances - 1)].advance;
|
||||
}
|
||||
|
||||
unsigned int get_advance (hb_codepoint_t glyph,
|
||||
hb_font_t *font) const
|
||||
{
|
||||
unsigned int advance = get_advance (glyph);
|
||||
if (likely (glyph < num_metrics))
|
||||
{
|
||||
advance += (font->num_coords ? var_table->get_advance_var (glyph, font->coords, font->num_coords) : 0); // TODO Optimize?!
|
||||
}
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
if (unlikely (glyph >= num_metrics) || !font->num_coords)
|
||||
return advance;
|
||||
|
||||
if (var_table.get_length ())
|
||||
return advance + roundf (var_table->get_advance_var (glyph, font)); // TODO Optimize?!
|
||||
|
||||
return _glyf_get_advance_var (font, glyph, T::tableTag == HB_OT_TAG_vmtx);
|
||||
#else
|
||||
return advance;
|
||||
#endif
|
||||
}
|
||||
|
||||
public:
|
||||
bool has_font_extents;
|
||||
int ascender;
|
||||
int descender;
|
||||
int line_gap;
|
||||
unsigned int num_advances_for_subset (const hb_subset_plan_t *plan) const
|
||||
{
|
||||
unsigned int num_advances = plan->num_output_glyphs ();
|
||||
unsigned int last_advance = _advance_for_new_gid (plan,
|
||||
num_advances - 1);
|
||||
while (num_advances > 1 &&
|
||||
last_advance == _advance_for_new_gid (plan,
|
||||
num_advances - 2))
|
||||
{
|
||||
num_advances--;
|
||||
}
|
||||
|
||||
return num_advances;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned int _advance_for_new_gid (const hb_subset_plan_t *plan,
|
||||
hb_codepoint_t new_gid) const
|
||||
{
|
||||
hb_codepoint_t old_gid;
|
||||
if (!plan->old_gid_for_new_gid (new_gid, &old_gid))
|
||||
return 0;
|
||||
|
||||
return get_advance (old_gid);
|
||||
}
|
||||
|
||||
protected:
|
||||
unsigned int num_metrics;
|
||||
@ -297,27 +293,29 @@ struct hmtxvmtx
|
||||
};
|
||||
|
||||
protected:
|
||||
UnsizedArrayOf<LongMetric>longMetricZ;/* Paired advance width and leading
|
||||
* bearing values for each glyph. The
|
||||
* value numOfHMetrics comes from
|
||||
* the 'hhea' table. If the font is
|
||||
* monospaced, only one entry need
|
||||
* be in the array, but that entry is
|
||||
* required. The last entry applies to
|
||||
* all subsequent glyphs. */
|
||||
/*UnsizedArrayOf<FWORD> leadingBearingX;*//* Here the advance is assumed
|
||||
* to be the same as the advance
|
||||
* for the last entry above. The
|
||||
* number of entries in this array is
|
||||
* derived from numGlyphs (from 'maxp'
|
||||
* table) minus numberOfLongMetrics.
|
||||
* This generally is used with a run
|
||||
* of monospaced glyphs (e.g., Kanji
|
||||
* fonts or Courier fonts). Only one
|
||||
* run is allowed and it must be at
|
||||
* the end. This allows a monospaced
|
||||
* font to vary the side bearing
|
||||
* values for each glyph. */
|
||||
UnsizedArrayOf<LongMetric>
|
||||
longMetricZ; /* Paired advance width and leading
|
||||
* bearing values for each glyph. The
|
||||
* value numOfHMetrics comes from
|
||||
* the 'hhea' table. If the font is
|
||||
* monospaced, only one entry need
|
||||
* be in the array, but that entry is
|
||||
* required. The last entry applies to
|
||||
* all subsequent glyphs. */
|
||||
/*UnsizedArrayOf<FWORD> leadingBearingX;*/
|
||||
/* Here the advance is assumed
|
||||
* to be the same as the advance
|
||||
* for the last entry above. The
|
||||
* number of entries in this array is
|
||||
* derived from numGlyphs (from 'maxp'
|
||||
* table) minus numberOfLongMetrics.
|
||||
* This generally is used with a run
|
||||
* of monospaced glyphs (e.g., Kanji
|
||||
* fonts or Courier fonts). Only one
|
||||
* run is allowed and it must be at
|
||||
* the end. This allows a monospaced
|
||||
* font to vary the side bearing
|
||||
* values for each glyph. */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (0, longMetricZ);
|
||||
};
|
||||
@ -325,12 +323,12 @@ struct hmtxvmtx
|
||||
struct hmtx : hmtxvmtx<hmtx, hhea> {
|
||||
static constexpr hb_tag_t tableTag = HB_OT_TAG_hmtx;
|
||||
static constexpr hb_tag_t variationsTag = HB_OT_TAG_HVAR;
|
||||
static constexpr hb_tag_t os2Tag = HB_OT_TAG_OS2;
|
||||
static constexpr bool is_horizontal = true;
|
||||
};
|
||||
struct vmtx : hmtxvmtx<vmtx, vhea> {
|
||||
static constexpr hb_tag_t tableTag = HB_OT_TAG_vmtx;
|
||||
static constexpr hb_tag_t variationsTag = HB_OT_TAG_VVAR;
|
||||
static constexpr hb_tag_t os2Tag = HB_TAG_NONE;
|
||||
static constexpr bool is_horizontal = false;
|
||||
};
|
||||
|
||||
struct hmtx_accelerator_t : hmtx::accelerator_t {};
|
||||
|
||||
@ -47,9 +47,9 @@ struct KernSubTableFormat3
|
||||
int get_kerning (hb_codepoint_t left, hb_codepoint_t right) const
|
||||
{
|
||||
hb_array_t<const FWORD> kernValue = kernValueZ.as_array (kernValueCount);
|
||||
hb_array_t<const HBUINT8> leftClass = StructAfter<const UnsizedArrayOf<HBUINT8> > (kernValue).as_array (glyphCount);
|
||||
hb_array_t<const HBUINT8> rightClass = StructAfter<const UnsizedArrayOf<HBUINT8> > (leftClass).as_array (glyphCount);
|
||||
hb_array_t<const HBUINT8> kernIndex = StructAfter<const UnsizedArrayOf<HBUINT8> > (rightClass).as_array (leftClassCount * rightClassCount);
|
||||
hb_array_t<const HBUINT8> leftClass = StructAfter<const UnsizedArrayOf<HBUINT8>> (kernValue).as_array (glyphCount);
|
||||
hb_array_t<const HBUINT8> rightClass = StructAfter<const UnsizedArrayOf<HBUINT8>> (leftClass).as_array (glyphCount);
|
||||
hb_array_t<const HBUINT8> kernIndex = StructAfter<const UnsizedArrayOf<HBUINT8>> (rightClass).as_array (leftClassCount * rightClassCount);
|
||||
|
||||
unsigned int leftC = leftClass[left];
|
||||
unsigned int rightC = rightClass[right];
|
||||
@ -86,21 +86,26 @@ struct KernSubTableFormat3
|
||||
}
|
||||
|
||||
protected:
|
||||
KernSubTableHeader header;
|
||||
HBUINT16 glyphCount; /* The number of glyphs in this font. */
|
||||
HBUINT8 kernValueCount; /* The number of kerning values. */
|
||||
HBUINT8 leftClassCount; /* The number of left-hand classes. */
|
||||
HBUINT8 rightClassCount;/* The number of right-hand classes. */
|
||||
HBUINT8 flags; /* Set to zero (reserved for future use). */
|
||||
UnsizedArrayOf<FWORD> kernValueZ; /* The kerning values.
|
||||
* Length kernValueCount. */
|
||||
KernSubTableHeader
|
||||
header;
|
||||
HBUINT16 glyphCount; /* The number of glyphs in this font. */
|
||||
HBUINT8 kernValueCount; /* The number of kerning values. */
|
||||
HBUINT8 leftClassCount; /* The number of left-hand classes. */
|
||||
HBUINT8 rightClassCount;/* The number of right-hand classes. */
|
||||
HBUINT8 flags; /* Set to zero (reserved for future use). */
|
||||
UnsizedArrayOf<FWORD>
|
||||
kernValueZ; /* The kerning values.
|
||||
* Length kernValueCount. */
|
||||
#if 0
|
||||
UnsizedArrayOf<HBUINT8>leftClass; /* The left-hand classes.
|
||||
* Length glyphCount. */
|
||||
UnsizedArrayOf<HBUINT8>rightClass; /* The right-hand classes.
|
||||
* Length glyphCount. */
|
||||
UnsizedArrayOf<HBUINT8>kernIndex; /* The indices into the kernValue array.
|
||||
* Length leftClassCount * rightClassCount */
|
||||
UnsizedArrayOf<HBUINT8>
|
||||
leftClass; /* The left-hand classes.
|
||||
* Length glyphCount. */
|
||||
UnsizedArrayOf<HBUINT8>
|
||||
rightClass; /* The right-hand classes.
|
||||
* Length glyphCount. */
|
||||
UnsizedArrayOf<HBUINT8>kernIndex;
|
||||
/* The indices into the kernValue array.
|
||||
* Length leftClassCount * rightClassCount */
|
||||
#endif
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (KernSubTableHeader::static_size + 6, kernValueZ);
|
||||
@ -121,16 +126,20 @@ struct KernSubTable
|
||||
}
|
||||
}
|
||||
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
unsigned int subtable_type = get_type ();
|
||||
TRACE_DISPATCH (this, subtable_type);
|
||||
switch (subtable_type) {
|
||||
case 0: return_trace (c->dispatch (u.format0));
|
||||
case 1: return_trace (u.header.apple ? c->dispatch (u.format1) : c->default_return_value ());
|
||||
#ifndef HB_NO_AAT_SHAPE
|
||||
case 1: return_trace (u.header.apple ? c->dispatch (u.format1, hb_forward<Ts> (ds)...) : c->default_return_value ());
|
||||
#endif
|
||||
case 2: return_trace (c->dispatch (u.format2));
|
||||
case 3: return_trace (u.header.apple ? c->dispatch (u.format3) : c->default_return_value ());
|
||||
#ifndef HB_NO_AAT_SHAPE
|
||||
case 3: return_trace (u.header.apple ? c->dispatch (u.format3, hb_forward<Ts> (ds)...) : c->default_return_value ());
|
||||
#endif
|
||||
default: return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
@ -163,8 +172,8 @@ struct KernOTSubTableHeader
|
||||
static constexpr bool apple = false;
|
||||
typedef AAT::ObsoleteTypes Types;
|
||||
|
||||
unsigned int tuple_count () const { return 0; }
|
||||
bool is_horizontal () const { return (coverage & Horizontal); }
|
||||
unsigned tuple_count () const { return 0; }
|
||||
bool is_horizontal () const { return (coverage & Horizontal); }
|
||||
|
||||
enum Coverage
|
||||
{
|
||||
@ -218,8 +227,8 @@ struct KernAATSubTableHeader
|
||||
static constexpr bool apple = true;
|
||||
typedef AAT::ObsoleteTypes Types;
|
||||
|
||||
unsigned int tuple_count () const { return 0; }
|
||||
bool is_horizontal () const { return !(coverage & Vertical); }
|
||||
unsigned tuple_count () const { return 0; }
|
||||
bool is_horizontal () const { return !(coverage & Vertical); }
|
||||
|
||||
enum Coverage
|
||||
{
|
||||
@ -242,8 +251,8 @@ struct KernAATSubTableHeader
|
||||
HBUINT8 coverage; /* Coverage bits. */
|
||||
HBUINT8 format; /* Subtable format. */
|
||||
HBUINT16 tupleIndex; /* The tuple index (used for variations fonts).
|
||||
* This value specifies which tuple this subtable covers.
|
||||
* Note: We don't implement. */
|
||||
* This value specifies which tuple this subtable covers.
|
||||
* Note: We don't implement. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (8);
|
||||
};
|
||||
@ -271,14 +280,16 @@ struct kern
|
||||
{
|
||||
static constexpr hb_tag_t tableTag = HB_OT_TAG_kern;
|
||||
|
||||
bool has_data () const { return u.version32; }
|
||||
unsigned int get_type () const { return u.major; }
|
||||
bool has_data () const { return u.version32; }
|
||||
unsigned get_type () const { return u.major; }
|
||||
|
||||
bool has_state_machine () const
|
||||
{
|
||||
switch (get_type ()) {
|
||||
case 0: return u.ot.has_state_machine ();
|
||||
#ifndef HB_NO_AAT_SHAPE
|
||||
case 1: return u.aat.has_state_machine ();
|
||||
#endif
|
||||
default:return false;
|
||||
}
|
||||
}
|
||||
@ -287,7 +298,9 @@ struct kern
|
||||
{
|
||||
switch (get_type ()) {
|
||||
case 0: return u.ot.has_cross_stream ();
|
||||
#ifndef HB_NO_AAT_SHAPE
|
||||
case 1: return u.aat.has_cross_stream ();
|
||||
#endif
|
||||
default:return false;
|
||||
}
|
||||
}
|
||||
@ -296,7 +309,9 @@ struct kern
|
||||
{
|
||||
switch (get_type ()) {
|
||||
case 0: return u.ot.get_h_kerning (left, right);
|
||||
#ifndef HB_NO_AAT_SHAPE
|
||||
case 1: return u.aat.get_h_kerning (left, right);
|
||||
#endif
|
||||
default:return 0;
|
||||
}
|
||||
}
|
||||
@ -304,14 +319,16 @@ struct kern
|
||||
bool apply (AAT::hb_aat_apply_context_t *c) const
|
||||
{ return dispatch (c); }
|
||||
|
||||
template <typename context_t>
|
||||
typename context_t::return_t dispatch (context_t *c) const
|
||||
template <typename context_t, typename ...Ts>
|
||||
typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
|
||||
{
|
||||
unsigned int subtable_type = get_type ();
|
||||
TRACE_DISPATCH (this, subtable_type);
|
||||
switch (subtable_type) {
|
||||
case 0: return_trace (c->dispatch (u.ot));
|
||||
case 1: return_trace (c->dispatch (u.aat));
|
||||
case 0: return_trace (c->dispatch (u.ot, hb_forward<Ts> (ds)...));
|
||||
#ifndef HB_NO_AAT_SHAPE
|
||||
case 1: return_trace (c->dispatch (u.aat, hb_forward<Ts> (ds)...));
|
||||
#endif
|
||||
default: return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
@ -328,7 +345,9 @@ struct kern
|
||||
HBUINT32 version32;
|
||||
HBUINT16 major;
|
||||
KernOT ot;
|
||||
#ifndef HB_NO_AAT_SHAPE
|
||||
KernAAT aat;
|
||||
#endif
|
||||
} u;
|
||||
public:
|
||||
DEFINE_SIZE_UNION (4, version32);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Copyright © 2016 Elie Roux <elie.roux@telecom-bretagne.eu>
|
||||
* Copyright © 2016 Elie Roux <elie.roux@telecom-bretagne.eu>
|
||||
* Copyright © 2018 Google, Inc.
|
||||
* Copyright © 2018 Ebrahim Byagowi
|
||||
* Copyright © 2018-2019 Ebrahim Byagowi
|
||||
*
|
||||
* This is part of HarfBuzz, a text shaping library.
|
||||
*
|
||||
@ -32,9 +32,6 @@
|
||||
#include "hb-open-type.hh"
|
||||
#include "hb-ot-layout-common.hh"
|
||||
|
||||
/* To be removed */
|
||||
typedef hb_tag_t hb_ot_layout_baseline_t;
|
||||
|
||||
namespace OT {
|
||||
|
||||
/*
|
||||
@ -76,7 +73,7 @@ struct BaseCoordFormat2
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 2 */
|
||||
FWORD coordinate; /* X or Y value, in design units */
|
||||
GlyphID referenceGlyph; /* Glyph ID of control glyph */
|
||||
HBGlyphID referenceGlyph; /* Glyph ID of control glyph */
|
||||
HBUINT16 coordPoint; /* Index of contour point on the
|
||||
* reference glyph */
|
||||
public:
|
||||
@ -116,9 +113,11 @@ struct BaseCoordFormat3
|
||||
|
||||
struct BaseCoord
|
||||
{
|
||||
hb_position_t get_coord (hb_font_t *font,
|
||||
bool has_data () const { return u.format; }
|
||||
|
||||
hb_position_t get_coord (hb_font_t *font,
|
||||
const VariationStore &var_store,
|
||||
hb_direction_t direction) const
|
||||
hb_direction_t direction) const
|
||||
{
|
||||
switch (u.format) {
|
||||
case 1: return u.format1.get_coord ();
|
||||
@ -142,10 +141,10 @@ struct BaseCoord
|
||||
|
||||
protected:
|
||||
union {
|
||||
HBUINT16 format;
|
||||
BaseCoordFormat1 format1;
|
||||
BaseCoordFormat2 format2;
|
||||
BaseCoordFormat3 format3;
|
||||
HBUINT16 format;
|
||||
BaseCoordFormat1 format1;
|
||||
BaseCoordFormat2 format2;
|
||||
BaseCoordFormat3 format3;
|
||||
} u;
|
||||
public:
|
||||
DEFINE_SIZE_UNION (2, format);
|
||||
@ -153,14 +152,9 @@ struct BaseCoord
|
||||
|
||||
struct FeatMinMaxRecord
|
||||
{
|
||||
static int cmp (const void *key_, const void *entry_)
|
||||
{
|
||||
hb_tag_t key = * (hb_tag_t *) key_;
|
||||
const FeatMinMaxRecord &entry = * (const FeatMinMaxRecord *) entry_;
|
||||
return key < (unsigned int) entry.tag ? -1 :
|
||||
key > (unsigned int) entry.tag ? 1 :
|
||||
0;
|
||||
}
|
||||
int cmp (hb_tag_t key) const { return tag.cmp (key); }
|
||||
|
||||
bool has_data () const { return tag; }
|
||||
|
||||
void get_min_max (const BaseCoord **min, const BaseCoord **max) const
|
||||
{
|
||||
@ -195,17 +189,12 @@ struct FeatMinMaxRecord
|
||||
struct MinMax
|
||||
{
|
||||
void get_min_max (hb_tag_t feature_tag,
|
||||
const BaseCoord **min,
|
||||
const BaseCoord **max) const
|
||||
const BaseCoord **min,
|
||||
const BaseCoord **max) const
|
||||
{
|
||||
/* TODO Replace hb_bsearch() with .bsearch(). */
|
||||
const FeatMinMaxRecord *minMaxCoord = (const FeatMinMaxRecord *)
|
||||
hb_bsearch (&feature_tag, featMinMaxRecords.arrayZ,
|
||||
featMinMaxRecords.len,
|
||||
FeatMinMaxRecord::static_size,
|
||||
FeatMinMaxRecord::cmp);
|
||||
if (minMaxCoord)
|
||||
minMaxCoord->get_min_max (min, max);
|
||||
const FeatMinMaxRecord &minMaxCoord = featMinMaxRecords.bsearch (feature_tag);
|
||||
if (minMaxCoord.has_data ())
|
||||
minMaxCoord.get_min_max (min, max);
|
||||
else
|
||||
{
|
||||
if (likely (min)) *min = &(this+minCoord);
|
||||
@ -271,17 +260,11 @@ struct BaseValues
|
||||
|
||||
struct BaseLangSysRecord
|
||||
{
|
||||
static int cmp (const void *key_, const void *entry_)
|
||||
{
|
||||
hb_tag_t key = * (hb_tag_t *) key_;
|
||||
const BaseLangSysRecord &entry = * (const BaseLangSysRecord *) entry_;
|
||||
return key < (unsigned int) entry.baseLangSysTag ? -1 :
|
||||
key > (unsigned int) entry.baseLangSysTag ? 1 :
|
||||
0;
|
||||
}
|
||||
int cmp (hb_tag_t key) const { return baseLangSysTag.cmp (key); }
|
||||
|
||||
const MinMax &get_min_max () const
|
||||
{ return this+minMax; }
|
||||
bool has_data () const { return baseLangSysTag; }
|
||||
|
||||
const MinMax &get_min_max () const { return this+minMax; }
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
@ -303,19 +286,14 @@ struct BaseScript
|
||||
{
|
||||
const MinMax &get_min_max (hb_tag_t language_tag) const
|
||||
{
|
||||
/* TODO Replace hb_bsearch() with .bsearch(). */
|
||||
const BaseLangSysRecord* record = (const BaseLangSysRecord *)
|
||||
hb_bsearch (&language_tag, baseLangSysRecords.arrayZ,
|
||||
baseLangSysRecords.len,
|
||||
BaseLangSysRecord::static_size,
|
||||
BaseLangSysRecord::cmp);
|
||||
return record ? record->get_min_max () : this+defaultMinMax;
|
||||
const BaseLangSysRecord& record = baseLangSysRecords.bsearch (language_tag);
|
||||
return record.has_data () ? record.get_min_max () : this+defaultMinMax;
|
||||
}
|
||||
|
||||
const BaseCoord &get_base_coord (int baseline_tag_index) const
|
||||
{ return (this+baseValues).get_base_coord (baseline_tag_index); }
|
||||
|
||||
bool is_empty () const { return !baseValues; }
|
||||
bool has_data () const { return baseValues; }
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
@ -345,14 +323,9 @@ struct BaseScript
|
||||
struct BaseScriptList;
|
||||
struct BaseScriptRecord
|
||||
{
|
||||
static int cmp (const void *key_, const void *entry_)
|
||||
{
|
||||
hb_tag_t key = * (hb_tag_t *) key_;
|
||||
const BaseScriptRecord &entry = * (const BaseScriptRecord *) entry_;
|
||||
return key < (unsigned int) entry.baseScriptTag ? -1 :
|
||||
key > (unsigned int) entry.baseScriptTag ? 1 :
|
||||
0;
|
||||
}
|
||||
int cmp (hb_tag_t key) const { return baseScriptTag.cmp (key); }
|
||||
|
||||
bool has_data () const { return baseScriptTag; }
|
||||
|
||||
const BaseScript &get_base_script (const BaseScriptList *list) const
|
||||
{ return list+baseScript; }
|
||||
@ -376,22 +349,11 @@ struct BaseScriptRecord
|
||||
|
||||
struct BaseScriptList
|
||||
{
|
||||
const BaseScriptRecord *find_record (hb_tag_t script) const
|
||||
{
|
||||
/* TODO Replace hb_bsearch() with .bsearch(). */
|
||||
return (const BaseScriptRecord *) hb_bsearch (&script, baseScriptRecords.arrayZ,
|
||||
baseScriptRecords.len,
|
||||
BaseScriptRecord::static_size,
|
||||
BaseScriptRecord::cmp);
|
||||
}
|
||||
|
||||
/* TODO: Or client should handle fallback? */
|
||||
const BaseScript &get_base_script (hb_tag_t script) const
|
||||
{
|
||||
const BaseScriptRecord *record = find_record (script);
|
||||
if (!record) record = find_record ((hb_script_t) HB_TAG ('D','F','L','T'));
|
||||
|
||||
return record ? record->get_base_script (this) : Null (BaseScript);
|
||||
const BaseScriptRecord *record = &baseScriptRecords.bsearch (script);
|
||||
if (!record->has_data ()) record = &baseScriptRecords.bsearch (HB_TAG ('D','F','L','T'));
|
||||
return record->has_data () ? record->get_base_script (this) : Null (BaseScript);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
@ -411,15 +373,20 @@ struct BaseScriptList
|
||||
|
||||
struct Axis
|
||||
{
|
||||
bool get_baseline (hb_ot_layout_baseline_t baseline,
|
||||
hb_tag_t script_tag,
|
||||
hb_tag_t language_tag,
|
||||
const BaseCoord **coord) const
|
||||
bool get_baseline (hb_tag_t baseline_tag,
|
||||
hb_tag_t script_tag,
|
||||
hb_tag_t language_tag,
|
||||
const BaseCoord **coord) const
|
||||
{
|
||||
const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag);
|
||||
if (base_script.is_empty ()) return false;
|
||||
if (!base_script.has_data ()) return false;
|
||||
|
||||
if (likely (coord)) *coord = &base_script.get_base_coord ((this+baseTagList).bsearch (baseline));
|
||||
if (likely (coord))
|
||||
{
|
||||
unsigned int tag_index = 0;
|
||||
(this+baseTagList).bfind (baseline_tag, &tag_index);
|
||||
*coord = &base_script.get_base_coord (tag_index);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -431,7 +398,7 @@ struct Axis
|
||||
const BaseCoord **max_coord) const
|
||||
{
|
||||
const BaseScript &base_script = (this+baseScriptList).get_base_script (script_tag);
|
||||
if (base_script.is_empty ()) return false;
|
||||
if (!base_script.has_data ()) return false;
|
||||
|
||||
base_script.get_min_max (language_tag).get_min_max (feature_tag, min_coord, max_coord);
|
||||
|
||||
@ -447,7 +414,7 @@ struct Axis
|
||||
}
|
||||
|
||||
protected:
|
||||
OffsetTo<SortedArrayOf<Tag> >
|
||||
OffsetTo<SortedArrayOf<Tag>>
|
||||
baseTagList; /* Offset to BaseTagList table, from beginning
|
||||
* of Axis table (may be NULL)
|
||||
* Array of 4-byte baseline identification tags — must
|
||||
@ -472,20 +439,21 @@ struct BASE
|
||||
const VariationStore &get_var_store () const
|
||||
{ return version.to_int () < 0x00010001u ? Null (VariationStore) : this+varStore; }
|
||||
|
||||
bool get_baseline (hb_font_t *font,
|
||||
hb_ot_layout_baseline_t baseline,
|
||||
hb_direction_t direction,
|
||||
hb_tag_t script_tag,
|
||||
hb_tag_t language_tag,
|
||||
hb_position_t *base) const
|
||||
bool get_baseline (hb_font_t *font,
|
||||
hb_tag_t baseline_tag,
|
||||
hb_direction_t direction,
|
||||
hb_tag_t script_tag,
|
||||
hb_tag_t language_tag,
|
||||
hb_position_t *base) const
|
||||
{
|
||||
const BaseCoord *base_coord;
|
||||
if (!get_axis (direction).get_baseline (baseline, script_tag, language_tag, &base_coord))
|
||||
const BaseCoord *base_coord = nullptr;
|
||||
if (unlikely (!get_axis (direction).get_baseline (baseline_tag, script_tag, language_tag, &base_coord) ||
|
||||
!base_coord || !base_coord->has_data ()))
|
||||
return false;
|
||||
|
||||
if (likely (base && base_coord)) *base = base_coord->get_coord (font,
|
||||
get_var_store (),
|
||||
direction);
|
||||
if (likely (base))
|
||||
*base = base_coord->get_coord (font, get_var_store (), direction);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -41,8 +41,18 @@ namespace OT {
|
||||
* Attachment List Table
|
||||
*/
|
||||
|
||||
typedef ArrayOf<HBUINT16> AttachPoint; /* Array of contour point indices--in
|
||||
* increasing numerical order */
|
||||
/* Array of contour point indices--in increasing numerical order */
|
||||
struct AttachPoint : ArrayOf<HBUINT16>
|
||||
{
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
auto *out = c->serializer->start_embed (*this);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
|
||||
return_trace (out->serialize (c->serializer, + iter ()));
|
||||
}
|
||||
};
|
||||
|
||||
struct AttachList
|
||||
{
|
||||
@ -63,15 +73,36 @@ struct AttachList
|
||||
|
||||
if (point_count)
|
||||
{
|
||||
hb_array_t<const HBUINT16> array = points.sub_array (start_offset, point_count);
|
||||
unsigned int count = array.length;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
point_array[i] = array[i];
|
||||
+ points.sub_array (start_offset, point_count)
|
||||
| hb_sink (hb_array (point_array, *point_count))
|
||||
;
|
||||
}
|
||||
|
||||
return points.len;
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
const hb_set_t &glyphset = *c->plan->glyphset ();
|
||||
const hb_map_t &glyph_map = *c->plan->glyph_map;
|
||||
|
||||
auto *out = c->serializer->start_embed (*this);
|
||||
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
|
||||
|
||||
hb_sorted_vector_t<hb_codepoint_t> new_coverage;
|
||||
+ hb_zip (this+coverage, attachPoint)
|
||||
| hb_filter (glyphset, hb_first)
|
||||
| hb_filter (subset_offset_array (c, out->attachPoint, this), hb_second)
|
||||
| hb_map (hb_first)
|
||||
| hb_map (glyph_map)
|
||||
| hb_sink (new_coverage)
|
||||
;
|
||||
out->coverage.serialize (c->serializer, out)
|
||||
.serialize (c->serializer, new_coverage.iter ());
|
||||
return_trace (bool (new_coverage));
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
@ -96,6 +127,13 @@ struct AttachList
|
||||
struct CaretValueFormat1
|
||||
{
|
||||
friend struct CaretValue;
|
||||
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 (true);
|
||||
}
|
||||
|
||||
private:
|
||||
hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction) const
|
||||
@ -119,6 +157,13 @@ struct CaretValueFormat1
|
||||
struct CaretValueFormat2
|
||||
{
|
||||
friend struct CaretValue;
|
||||
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 (true);
|
||||
}
|
||||
|
||||
private:
|
||||
hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const
|
||||
@ -153,6 +198,19 @@ struct CaretValueFormat3
|
||||
font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store);
|
||||
}
|
||||
|
||||
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->deviceTable.serialize_copy (c->serializer, deviceTable, this, c->serializer->to_bias (out),
|
||||
hb_serialize_context_t::Head, c->plan->layout_variation_idx_map));
|
||||
}
|
||||
|
||||
void collect_variation_indices (hb_set_t *layout_variation_indices) const
|
||||
{ (this+deviceTable).collect_variation_indices (layout_variation_indices); }
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
@ -173,9 +231,9 @@ struct CaretValueFormat3
|
||||
struct CaretValue
|
||||
{
|
||||
hb_position_t get_caret_value (hb_font_t *font,
|
||||
hb_direction_t direction,
|
||||
hb_codepoint_t glyph_id,
|
||||
const VariationStore &var_store) const
|
||||
hb_direction_t direction,
|
||||
hb_codepoint_t glyph_id,
|
||||
const VariationStore &var_store) const
|
||||
{
|
||||
switch (u.format) {
|
||||
case 1: return u.format1.get_caret_value (font, direction);
|
||||
@ -185,6 +243,32 @@ struct CaretValue
|
||||
}
|
||||
}
|
||||
|
||||
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.format1, hb_forward<Ts> (ds)...));
|
||||
case 2: return_trace (c->dispatch (u.format2, hb_forward<Ts> (ds)...));
|
||||
case 3: return_trace (c->dispatch (u.format3, hb_forward<Ts> (ds)...));
|
||||
default:return_trace (c->default_return_value ());
|
||||
}
|
||||
}
|
||||
|
||||
void collect_variation_indices (hb_set_t *layout_variation_indices) const
|
||||
{
|
||||
switch (u.format) {
|
||||
case 1:
|
||||
case 2:
|
||||
return;
|
||||
case 3:
|
||||
u.format3.collect_variation_indices (layout_variation_indices);
|
||||
return;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
@ -210,25 +294,45 @@ struct CaretValue
|
||||
|
||||
struct LigGlyph
|
||||
{
|
||||
unsigned int get_lig_carets (hb_font_t *font,
|
||||
hb_direction_t direction,
|
||||
hb_codepoint_t glyph_id,
|
||||
const VariationStore &var_store,
|
||||
unsigned int start_offset,
|
||||
unsigned int *caret_count /* IN/OUT */,
|
||||
hb_position_t *caret_array /* OUT */) const
|
||||
unsigned get_lig_carets (hb_font_t *font,
|
||||
hb_direction_t direction,
|
||||
hb_codepoint_t glyph_id,
|
||||
const VariationStore &var_store,
|
||||
unsigned start_offset,
|
||||
unsigned *caret_count /* IN/OUT */,
|
||||
hb_position_t *caret_array /* OUT */) const
|
||||
{
|
||||
if (caret_count)
|
||||
{
|
||||
hb_array_t <const OffsetTo<CaretValue> > array = carets.sub_array (start_offset, caret_count);
|
||||
unsigned int count = array.length;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
caret_array[i] = (this+array[i]).get_caret_value (font, direction, glyph_id, var_store);
|
||||
+ carets.sub_array (start_offset, caret_count)
|
||||
| hb_map (hb_add (this))
|
||||
| hb_map ([&] (const CaretValue &value) { return value.get_caret_value (font, direction, glyph_id, var_store); })
|
||||
| hb_sink (hb_array (caret_array, *caret_count))
|
||||
;
|
||||
}
|
||||
|
||||
return carets.len;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
+ hb_iter (carets)
|
||||
| hb_apply (subset_offset_array (c, out->carets, this))
|
||||
;
|
||||
|
||||
return_trace (bool (out->carets));
|
||||
}
|
||||
|
||||
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
|
||||
{
|
||||
for (const OffsetTo<CaretValue>& offset : carets.iter ())
|
||||
(this+offset).collect_variation_indices (c->layout_variation_indices);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
@ -265,6 +369,38 @@ struct LigCaretList
|
||||
return lig_glyph.get_lig_carets (font, direction, glyph_id, var_store, start_offset, caret_count, caret_array);
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
const hb_set_t &glyphset = *c->plan->glyphset ();
|
||||
const hb_map_t &glyph_map = *c->plan->glyph_map;
|
||||
|
||||
auto *out = c->serializer->start_embed (*this);
|
||||
if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
|
||||
|
||||
hb_sorted_vector_t<hb_codepoint_t> new_coverage;
|
||||
+ hb_zip (this+coverage, ligGlyph)
|
||||
| hb_filter (glyphset, hb_first)
|
||||
| hb_filter (subset_offset_array (c, out->ligGlyph, this), hb_second)
|
||||
| hb_map (hb_first)
|
||||
| hb_map (glyph_map)
|
||||
| hb_sink (new_coverage)
|
||||
;
|
||||
out->coverage.serialize (c->serializer, out)
|
||||
.serialize (c->serializer, new_coverage.iter ());
|
||||
return_trace (bool (new_coverage));
|
||||
}
|
||||
|
||||
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
|
||||
{
|
||||
+ hb_zip (this+coverage, ligGlyph)
|
||||
| hb_filter (c->glyph_set, hb_first)
|
||||
| hb_map (hb_second)
|
||||
| hb_map (hb_add (this))
|
||||
| hb_apply ([c] (const LigGlyph& _) { _.collect_variation_indices (c); })
|
||||
;
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
@ -288,6 +424,34 @@ struct MarkGlyphSetsFormat1
|
||||
bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
|
||||
{ return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }
|
||||
|
||||
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);
|
||||
out->format = format;
|
||||
|
||||
bool ret = true;
|
||||
for (const LOffsetTo<Coverage>& offset : coverage.iter ())
|
||||
{
|
||||
auto *o = out->coverage.serialize_append (c->serializer);
|
||||
if (unlikely (!o))
|
||||
{
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
|
||||
//not using o->serialize_subset (c, offset, this, out) here because
|
||||
//OTS doesn't allow null offset.
|
||||
//See issue: https://github.com/khaledhosny/ots/issues/172
|
||||
c->serializer->push ();
|
||||
c->dispatch (this+offset);
|
||||
c->serializer->add_link (*o, c->serializer->pop_pack ());
|
||||
}
|
||||
|
||||
return_trace (ret && out->coverage.len);
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
@ -296,7 +460,7 @@ struct MarkGlyphSetsFormat1
|
||||
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 1 */
|
||||
ArrayOf<LOffsetTo<Coverage> >
|
||||
ArrayOf<LOffsetTo<Coverage>>
|
||||
coverage; /* Array of long offsets to mark set
|
||||
* coverage tables */
|
||||
public:
|
||||
@ -313,6 +477,15 @@ struct MarkGlyphSets
|
||||
}
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
switch (u.format) {
|
||||
case 1: return_trace (u.format1.subset (c));
|
||||
default:return_trace (false);
|
||||
}
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
@ -356,7 +529,7 @@ struct GDEF
|
||||
unsigned int get_glyph_class (hb_codepoint_t glyph) const
|
||||
{ return (this+glyphClassDef).get_class (glyph); }
|
||||
void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const
|
||||
{ (this+glyphClassDef).add_class (glyphs, klass); }
|
||||
{ (this+glyphClassDef).collect_class (glyphs, klass); }
|
||||
|
||||
bool has_mark_attachment_types () const { return markAttachClassDef != 0; }
|
||||
unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const
|
||||
@ -386,7 +559,7 @@ struct GDEF
|
||||
|
||||
bool has_var_store () const { return version.to_int () >= 0x00010003u && varStore != 0; }
|
||||
const VariationStore &get_var_store () const
|
||||
{ return version.to_int () >= 0x00010003u ? this+varStore : Null(VariationStore); }
|
||||
{ return version.to_int () >= 0x00010003u ? this+varStore : Null (VariationStore); }
|
||||
|
||||
/* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
|
||||
* glyph class and other bits, and high 8-bit the mark attachment type (if any).
|
||||
@ -409,15 +582,15 @@ struct GDEF
|
||||
}
|
||||
}
|
||||
|
||||
HB_INTERNAL bool is_blacklisted (hb_blob_t *blob,
|
||||
HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
|
||||
hb_face_t *face) const;
|
||||
|
||||
struct accelerator_t
|
||||
{
|
||||
void init (hb_face_t *face)
|
||||
{
|
||||
this->table = hb_sanitize_context_t().reference_table<GDEF> (face);
|
||||
if (unlikely (this->table->is_blacklisted (this->table.get_blob (), face)))
|
||||
this->table = hb_sanitize_context_t ().reference_table<GDEF> (face);
|
||||
if (unlikely (this->table->is_blocklisted (this->table.get_blob (), face)))
|
||||
{
|
||||
hb_blob_destroy (this->table.get_blob ());
|
||||
this->table = hb_blob_get_empty ();
|
||||
@ -436,24 +609,66 @@ struct GDEF
|
||||
(version.to_int () >= 0x00010003u ? varStore.static_size : 0);
|
||||
}
|
||||
|
||||
void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
|
||||
{ (this+ligCaretList).collect_variation_indices (c); }
|
||||
|
||||
void remap_layout_variation_indices (const hb_set_t *layout_variation_indices,
|
||||
hb_map_t *layout_variation_idx_map /* OUT */) const
|
||||
{
|
||||
if (version.to_int () < 0x00010003u || !varStore) return;
|
||||
if (layout_variation_indices->is_empty ()) return;
|
||||
|
||||
unsigned new_major = 0, new_minor = 0;
|
||||
unsigned last_major = (layout_variation_indices->get_min ()) >> 16;
|
||||
for (unsigned idx : layout_variation_indices->iter ())
|
||||
{
|
||||
uint16_t major = idx >> 16;
|
||||
if (major >= (this+varStore).get_sub_table_count ()) break;
|
||||
if (major != last_major)
|
||||
{
|
||||
new_minor = 0;
|
||||
++new_major;
|
||||
}
|
||||
|
||||
unsigned new_idx = (new_major << 16) + new_minor;
|
||||
layout_variation_idx_map->set (idx, new_idx);
|
||||
++new_minor;
|
||||
last_major = major;
|
||||
}
|
||||
}
|
||||
|
||||
bool subset (hb_subset_context_t *c) const
|
||||
{
|
||||
TRACE_SUBSET (this);
|
||||
struct GDEF *out = c->serializer->embed (*this);
|
||||
auto *out = c->serializer->embed (*this);
|
||||
if (unlikely (!out)) return_trace (false);
|
||||
|
||||
out->glyphClassDef.serialize_subset (c, this+glyphClassDef, out);
|
||||
out->attachList.set (0);//TODO(subset) serialize_subset (c, this+attachList, out);
|
||||
out->ligCaretList.set (0);//TODO(subset) serialize_subset (c, this+ligCaretList, out);
|
||||
out->markAttachClassDef.serialize_subset (c, this+markAttachClassDef, out);
|
||||
bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this);
|
||||
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_markglyphsetsdef = true;
|
||||
if (version.to_int () >= 0x00010002u)
|
||||
out->markGlyphSetsDef.set (0);// TODO(subset) serialize_subset (c, this+markGlyphSetsDef, out);
|
||||
{
|
||||
subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
|
||||
if (!subset_markglyphsetsdef &&
|
||||
version.to_int () == 0x00010002u)
|
||||
out->version.minor = 0;
|
||||
}
|
||||
|
||||
bool subset_varstore = true;
|
||||
if (version.to_int () >= 0x00010003u)
|
||||
out->varStore.set (0);// TODO(subset) serialize_subset (c, this+varStore, out);
|
||||
{
|
||||
subset_varstore = out->varStore.serialize_subset (c, varStore, this);
|
||||
if (!subset_varstore && version.to_int () == 0x00010003u)
|
||||
out->version.minor = 2;
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
return_trace (subset_glyphclassdef || subset_attachlist ||
|
||||
subset_ligcaretlist || subset_markattachclassdef ||
|
||||
(out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) ||
|
||||
(out->version.to_int () >= 0x00010003u && subset_varstore));
|
||||
}
|
||||
|
||||
bool sanitize (hb_sanitize_context_t *c) const
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user