зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1476334 - Update HarfBuzz to version 1.8.7. r=jfkthame
--HG-- extra : rebase_source : 48d8469644e5fbb52757f3dcf3e9c3bd4c212142
This commit is contained in:
Родитель
a9fe7d83f0
Коммит
783ccf6975
|
@ -1,3 +1,39 @@
|
|||
Overview of changes leading to 1.8.7
|
||||
Wednesday, August 8, 2018
|
||||
====================================
|
||||
- Fix assertion failure with GDEF-blacklisted fonts.
|
||||
|
||||
|
||||
Overview of changes leading to 1.8.6
|
||||
Tuesday, August 7, 2018
|
||||
====================================
|
||||
- Internal code shuffling.
|
||||
- New API to speed up getting advance widths for implementations
|
||||
that have heavy overhead in get_h_advance callback:
|
||||
+hb_font_funcs_set_glyph_h_advances_func
|
||||
+hb_font_funcs_set_glyph_v_advances_func
|
||||
+hb_font_get_glyph_advances_for_direction
|
||||
+hb_font_get_glyph_h_advances
|
||||
+hb_font_get_glyph_h_advances_func_t
|
||||
+hb_font_get_glyph_v_advances
|
||||
+hb_font_get_glyph_v_advances_func_t
|
||||
|
||||
|
||||
Overview of changes leading to 1.8.5
|
||||
Wednesday, August 1, 2018
|
||||
====================================
|
||||
- Major Khmer shaper improvements to better match Microsoft.
|
||||
- Indic bug fixes.
|
||||
- Internal improvements to atomic operations.
|
||||
|
||||
|
||||
Overview of changes leading to 1.8.4
|
||||
Tuesday, July 17, 2018
|
||||
====================================
|
||||
- Fix build on non-C++11.
|
||||
- Use C++-style GCC atomics and C++11 atomics.
|
||||
|
||||
|
||||
Overview of changes leading to 1.8.3
|
||||
Wednesday, July 11, 2018
|
||||
====================================
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
This directory contains the HarfBuzz source from the upstream repo:
|
||||
https://github.com/harfbuzz/harfbuzz
|
||||
|
||||
Current version: 1.8.3 [commit 2b76767bf572364d3d647cdd139f2044a7ad06b2]
|
||||
Current version: 1.8.7 [commit b6fdcf4f8bd09e065c767939125861c9dc8ff18f]
|
||||
|
||||
UPDATING:
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
AC_PREREQ([2.64])
|
||||
AC_INIT([HarfBuzz],
|
||||
[1.8.3],
|
||||
[1.8.7],
|
||||
[https://github.com/harfbuzz/harfbuzz/issues/new],
|
||||
[harfbuzz],
|
||||
[http://harfbuzz.org/])
|
||||
|
|
|
@ -14,6 +14,7 @@ check_PROGRAMS =
|
|||
|
||||
# Convenience targets:
|
||||
lib: $(BUILT_SOURCES) libharfbuzz.la libharfbuzz-subset.la
|
||||
libs: $(BUILT_SOURCES) $(lib_LTLIBRARIES)
|
||||
fuzzing: $(BUILT_SOURCES) libharfbuzz-fuzzing.la libharfbuzz-subset-fuzzing.la
|
||||
|
||||
lib_LTLIBRARIES = libharfbuzz.la
|
||||
|
@ -373,15 +374,11 @@ dist_check_SCRIPTS += \
|
|||
endif
|
||||
|
||||
check_PROGRAMS += \
|
||||
dump-fon \
|
||||
dump-indic-data \
|
||||
dump-khmer-data \
|
||||
dump-myanmar-data \
|
||||
dump-use-data \
|
||||
$(NULL)
|
||||
dump_fon_SOURCES = dump-fon.cc
|
||||
dump_fon_CPPFLAGS = $(HBCFLAGS)
|
||||
dump_fon_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
dump_indic_data_SOURCES = dump-indic-data.cc hb-ot-shape-complex-indic-table.cc
|
||||
dump_indic_data_CPPFLAGS = $(HBCFLAGS)
|
||||
dump_indic_data_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
|
|
@ -14,9 +14,12 @@ HB_BASE_sources = \
|
|||
hb-face.cc \
|
||||
hb-font-private.hh \
|
||||
hb-font.cc \
|
||||
hb-iter-private.hh \
|
||||
hb-map-private.hh \
|
||||
hb-map.cc \
|
||||
hb-machinery-private.hh \
|
||||
hb-mutex-private.hh \
|
||||
hb-null.hh \
|
||||
hb-object-private.hh \
|
||||
hb-open-file-private.hh \
|
||||
hb-open-type-private.hh \
|
||||
|
@ -50,6 +53,7 @@ HB_BASE_sources = \
|
|||
hb-string-array.hh \
|
||||
hb-unicode-private.hh \
|
||||
hb-unicode.cc \
|
||||
hb-vector-private.hh \
|
||||
hb-utf-private.hh \
|
||||
hb-warning.cc \
|
||||
$(NULL)
|
||||
|
@ -93,8 +97,6 @@ HB_OT_sources = \
|
|||
hb-aat-layout-morx-table.hh \
|
||||
hb-aat-layout-trak-table.hh \
|
||||
hb-aat-layout-private.hh \
|
||||
hb-aat-fmtx-table.hh \
|
||||
hb-aat-gcid-table.hh \
|
||||
hb-aat-ltag-table.hh \
|
||||
hb-ot-font.cc \
|
||||
hb-ot-layout.cc \
|
||||
|
|
|
@ -233,12 +233,10 @@ int main (int argc, char **argv)
|
|||
svg.dump (svg_callback);
|
||||
svg.fini ();
|
||||
|
||||
OT::Sanitizer<OT::COLR> sanitizerCOLR;
|
||||
hb_blob_t* colr_blob = sanitizerCOLR.sanitize (face->reference_table (HB_OT_TAG_COLR));
|
||||
hb_blob_t* colr_blob = hb_sanitize_context_t ().reference_table<OT::COLR> (face);
|
||||
const OT::COLR *colr = colr_blob->as<OT::COLR> ();
|
||||
|
||||
OT::Sanitizer<OT::CPAL> sanitizerCPAL;
|
||||
hb_blob_t* cpal_blob = sanitizerCPAL.sanitize (face->reference_table (HB_OT_TAG_CPAL));
|
||||
hb_blob_t* cpal_blob = hb_sanitize_context_t ().reference_table<OT::CPAL> (face);
|
||||
const OT::CPAL *cpal = cpal_blob->as<OT::CPAL> ();
|
||||
|
||||
cairo_font_face_t *cairo_face;
|
||||
|
|
|
@ -1,555 +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.
|
||||
*/
|
||||
|
||||
#include "hb-static.cc"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "hb-open-type-private.hh"
|
||||
|
||||
template <typename Type, int Bytes> struct LEInt;
|
||||
|
||||
template <typename Type>
|
||||
struct LEInt<Type, 1>
|
||||
{
|
||||
public:
|
||||
inline void set (Type V)
|
||||
{
|
||||
v = V;
|
||||
}
|
||||
inline operator Type (void) const
|
||||
{
|
||||
return v;
|
||||
}
|
||||
private: uint8_t v;
|
||||
};
|
||||
template <typename Type>
|
||||
struct LEInt<Type, 2>
|
||||
{
|
||||
public:
|
||||
inline void set (Type V)
|
||||
{
|
||||
v[1] = (V >> 8) & 0xFF;
|
||||
v[0] = (V ) & 0xFF;
|
||||
}
|
||||
inline operator Type (void) const
|
||||
{
|
||||
return (v[1] << 8)
|
||||
+ (v[0] );
|
||||
}
|
||||
private: uint8_t v[2];
|
||||
};
|
||||
template <typename Type>
|
||||
struct LEInt<Type, 3>
|
||||
{
|
||||
public:
|
||||
inline void set (Type V)
|
||||
{
|
||||
v[2] = (V >> 16) & 0xFF;
|
||||
v[1] = (V >> 8) & 0xFF;
|
||||
v[0] = (V ) & 0xFF;
|
||||
}
|
||||
inline operator Type (void) const
|
||||
{
|
||||
return (v[2] << 16)
|
||||
+ (v[1] << 8)
|
||||
+ (v[0] );
|
||||
}
|
||||
private: uint8_t v[3];
|
||||
};
|
||||
template <typename Type>
|
||||
struct LEInt<Type, 4>
|
||||
{
|
||||
public:
|
||||
inline void set (Type V)
|
||||
{
|
||||
v[3] = (V >> 24) & 0xFF;
|
||||
v[2] = (V >> 16) & 0xFF;
|
||||
v[1] = (V >> 8) & 0xFF;
|
||||
v[0] = (V ) & 0xFF;
|
||||
}
|
||||
inline operator Type (void) const
|
||||
{
|
||||
return (v[3] << 24)
|
||||
+ (v[2] << 16)
|
||||
+ (v[1] << 8)
|
||||
+ (v[0] );
|
||||
}
|
||||
private: uint8_t v[4];
|
||||
};
|
||||
|
||||
template <typename Type, unsigned int Size>
|
||||
struct LEIntType
|
||||
{
|
||||
inline void set (Type i) { v.set (i); }
|
||||
inline operator Type(void) const { return v; }
|
||||
inline bool sanitize (OT::hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this)));
|
||||
}
|
||||
protected:
|
||||
LEInt<Type, Size> v;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (Size);
|
||||
};
|
||||
|
||||
typedef LEIntType<uint8_t, 1> LEUINT8; /* 8-bit unsigned integer. */
|
||||
typedef LEIntType<int8_t, 1> LEINT8; /* 8-bit signed integer. */
|
||||
typedef LEIntType<uint16_t, 2> LEUINT16; /* 16-bit unsigned integer. */
|
||||
typedef LEIntType<int16_t, 2> LEINT16; /* 16-bit signed integer. */
|
||||
typedef LEIntType<uint32_t, 4> LEUINT32; /* 32-bit unsigned integer. */
|
||||
typedef LEIntType<int32_t, 4> LEINT32; /* 32-bit signed integer. */
|
||||
typedef LEIntType<uint32_t, 3> LEUINT24; /* 24-bit unsigned integer. */
|
||||
|
||||
|
||||
struct LE_FONTINFO16
|
||||
{
|
||||
inline bool sanitize (OT::hb_sanitize_context_t *c, unsigned int length) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) && c->check_range (this, length)));
|
||||
}
|
||||
|
||||
// https://msdn.microsoft.com/en-us/library/cc194829.aspx
|
||||
enum charset_t
|
||||
{
|
||||
// dfCharSet possible values and the codepage they are indicating to
|
||||
ANSI = 0x00, // 1252
|
||||
DEFAULT = 0x01, //
|
||||
SYMBOL = 0x02, //
|
||||
SHIFTJIS = 0x80, // 932
|
||||
HANGUL = 0x81, // 949
|
||||
GB2312 = 0x86, // 936
|
||||
CHINESEBIG5 = 0x88, // 950
|
||||
GREEK = 0xA1, // 1253
|
||||
TURKISH = 0xA2, // 1254
|
||||
HEBREW = 0xB1, // 1255
|
||||
ARABIC = 0xB2, // 1256
|
||||
BALTIC = 0xBA, // 1257
|
||||
RUSSIAN = 0xCC, // 1251
|
||||
THAI = 0xDE, // 874
|
||||
EE = 0xEE, // 1250
|
||||
OEM = 0xFF //
|
||||
};
|
||||
|
||||
inline const char* get_charset() const
|
||||
{
|
||||
switch (dfCharSet) {
|
||||
case ANSI: return "ISO8859";
|
||||
case DEFAULT: return "WinDefault";
|
||||
case SYMBOL: return "Symbol";
|
||||
case SHIFTJIS: return "JISX0208.1983";
|
||||
case HANGUL: return "MSHangul";
|
||||
case GB2312: return "GB2312.1980";
|
||||
case CHINESEBIG5: return "Big5";
|
||||
case GREEK: return "CP1253";
|
||||
case TURKISH: return "CP1254";
|
||||
case HEBREW: return "CP1255";
|
||||
case ARABIC: return "CP1256";
|
||||
case BALTIC: return "CP1257";
|
||||
case RUSSIAN: return "CP1251";
|
||||
case THAI: return "CP874";
|
||||
case EE: return "CP1250";
|
||||
case OEM: return "OEM";
|
||||
default: return "Unknown";
|
||||
}
|
||||
}
|
||||
|
||||
inline unsigned int get_version () const
|
||||
{
|
||||
return dfVersion;
|
||||
}
|
||||
|
||||
inline unsigned int get_weight () const
|
||||
{
|
||||
return dfWeight;
|
||||
}
|
||||
|
||||
enum weight_t {
|
||||
DONTCARE = 0,
|
||||
THIN = 100,
|
||||
EXTRALIGHT = 200,
|
||||
ULTRALIGHT = 200,
|
||||
LIGHT = 300,
|
||||
NORMAL = 400,
|
||||
REGULAR = 400,
|
||||
MEDIUM = 500,
|
||||
SEMIBOLD = 600,
|
||||
DEMIBOLD = 600,
|
||||
BOLD = 700,
|
||||
EXTRABOLD = 800,
|
||||
ULTRABOLD = 800,
|
||||
HEAVY = 900,
|
||||
BLACK = 900
|
||||
};
|
||||
|
||||
inline void dump () const
|
||||
{
|
||||
// With https://github.com/juanitogan/mkwinfont/blob/master/python/dewinfont.py help
|
||||
// Should be implemented differently eventually, but for now
|
||||
unsigned int ctstart;
|
||||
unsigned int ctsize;
|
||||
if (dfVersion == 0x200)
|
||||
{
|
||||
ctstart = 0x76;
|
||||
ctsize = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
return; // must of ".fon"s are version 2 and even dewinfont V1 implmentation doesn't seem correct
|
||||
ctstart = 0x94;
|
||||
ctsize = 6;
|
||||
}
|
||||
// unsigned int maxwidth = 0;
|
||||
for (unsigned int i = dfFirstChar; i < dfLastChar; ++i)
|
||||
{
|
||||
unsigned int entry = ctstart + ctsize * (i-dfFirstChar);
|
||||
unsigned int w = (uint16_t) OT::StructAtOffset<LEUINT16> (this, entry);
|
||||
|
||||
unsigned int off;
|
||||
if (ctsize == 4)
|
||||
off = (uint16_t) OT::StructAtOffset<LEUINT16> (this, entry+2);
|
||||
else
|
||||
off = (uint32_t) OT::StructAtOffset<LEUINT32> (this, entry+2);
|
||||
|
||||
unsigned int widthbytes = (w + 7) / 8;
|
||||
for (unsigned int j = 0; j < dfPixHeight; ++j)
|
||||
{
|
||||
for (unsigned int k = 0; k < widthbytes; ++k)
|
||||
{
|
||||
unsigned int bytepos = off + k * dfPixHeight + j;
|
||||
const uint8_t b = (uint8_t) OT::StructAtOffset<LEINT8> (this, bytepos);
|
||||
for (unsigned int a = 128; a > 0; a >>= 1)
|
||||
printf (b & a ? "x" : ".");
|
||||
}
|
||||
printf ("\n");
|
||||
}
|
||||
printf ("\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
LEUINT16 dfVersion;
|
||||
LEUINT32 dfSize;
|
||||
LEUINT8 dfCopyright[60];
|
||||
LEUINT16 dfType;
|
||||
LEUINT16 dfPoints;
|
||||
LEUINT16 dfVertRes;
|
||||
LEUINT16 dfHorizRes;
|
||||
LEUINT16 dfAscent;
|
||||
LEUINT16 dfInternalLeading;
|
||||
LEUINT16 dfExternalLeading;
|
||||
LEUINT8 dfItalic;
|
||||
LEUINT8 dfUnderline;
|
||||
LEUINT8 dfStrikeOut;
|
||||
LEUINT16 dfWeight; // see weight_t
|
||||
LEUINT8 dfCharSet; // see charset_t
|
||||
LEUINT16 dfPixWidth;
|
||||
LEUINT16 dfPixHeight;
|
||||
LEUINT8 dfPitchAndFamily;
|
||||
LEUINT16 dfAvgWidth;
|
||||
LEUINT16 dfMaxWidth;
|
||||
LEUINT8 dfFirstChar;
|
||||
LEUINT8 dfLastChar;
|
||||
LEUINT8 dfDefaultChar;
|
||||
LEUINT8 dfBreakChar;
|
||||
LEUINT16 dfWidthBytes;
|
||||
LEUINT32 dfDevice;
|
||||
LEUINT32 dfFace;
|
||||
LEUINT32 dfBitsPointer;
|
||||
LEUINT32 dfBitsOffset;
|
||||
LEUINT8 dfReserved;
|
||||
// LEUINT32 dfFlags;
|
||||
// LEUINT16 dfAspace;
|
||||
// LEUINT16 dfBspace;
|
||||
// LEUINT16 dfCspace;
|
||||
// LEUINT32 dfColorPointer;
|
||||
// LEUINT32 dfReserved1[4];
|
||||
OT::UnsizedArrayOf<LEUINT8>
|
||||
dataZ;
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (118, dataZ);
|
||||
};
|
||||
|
||||
struct NE_NAMEINFO
|
||||
{
|
||||
friend struct NE_TYPEINFO;
|
||||
|
||||
inline bool sanitize (OT::hb_sanitize_context_t *c, const void *base, unsigned int shift) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
get_font (base, shift).sanitize (c, length << shift)));
|
||||
}
|
||||
|
||||
inline const LE_FONTINFO16& get_font (const void *base, int shift) const
|
||||
{
|
||||
return OT::StructAtOffset<LE_FONTINFO16> (base, offset << shift);
|
||||
}
|
||||
|
||||
enum resource_type_flag_t {
|
||||
NONE = 0x0000,
|
||||
MOVEABLE = 0x0010,
|
||||
PURE = 0x0020,
|
||||
PRELOAD = 0x0040
|
||||
};
|
||||
|
||||
protected:
|
||||
LEUINT16 offset; // Should be shifted with alignmentShiftCount before use
|
||||
LEUINT16 length; // Should be shifted with alignmentShiftCount before use
|
||||
LEUINT16 flags; // resource_type_flag_t
|
||||
LEUINT16 id;
|
||||
LEUINT16 handle;
|
||||
LEUINT16 usage;
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (12);
|
||||
};
|
||||
|
||||
struct NE_TYPEINFO
|
||||
{
|
||||
inline bool sanitize (OT::hb_sanitize_context_t *c, const void *base, unsigned int shift) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) && resources.sanitize (c, count, base, shift));
|
||||
}
|
||||
|
||||
inline unsigned int get_size (void) const
|
||||
{ return 8 + count * NE_NAMEINFO::static_size; }
|
||||
|
||||
inline const NE_TYPEINFO& next () const
|
||||
{
|
||||
const NE_TYPEINFO& next = OT::StructAfter<NE_TYPEINFO> (*this);
|
||||
if (type_id == 0)
|
||||
return Null(NE_TYPEINFO);
|
||||
return next;
|
||||
}
|
||||
|
||||
inline const LE_FONTINFO16& get_font (unsigned int idx, const void *base, int shift) const
|
||||
{
|
||||
if (idx < count)
|
||||
return resources[idx].get_font (base, shift);
|
||||
return Null(LE_FONTINFO16);
|
||||
}
|
||||
|
||||
inline unsigned int get_count () const
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
inline unsigned int get_type_id () const
|
||||
{
|
||||
return type_id;
|
||||
}
|
||||
|
||||
enum type_id_t {
|
||||
CURSOR = 0x8001,
|
||||
BITMAP = 0x8002,
|
||||
ICON = 0x8003,
|
||||
MENU = 0x8004,
|
||||
DIALOG = 0x8005,
|
||||
STRING = 0x8006,
|
||||
FONT_DIRECTORY = 0x8007,
|
||||
FONT = 0x8008,
|
||||
ACCELERATOR_TABLE = 0x8009,
|
||||
RESOURCE_DATA = 0x800a,
|
||||
GROUP_CURSOR = 0x800c,
|
||||
GROUP_ICON = 0x800e,
|
||||
VERSION = 0x8010
|
||||
};
|
||||
|
||||
protected:
|
||||
LEUINT16 type_id; // see type_id_t
|
||||
LEUINT16 count;
|
||||
LEUINT32 resloader;
|
||||
OT::UnsizedArrayOf<NE_NAMEINFO>
|
||||
resources;
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (8, resources);
|
||||
};
|
||||
|
||||
struct NE_RESOURCE_TABLE
|
||||
{
|
||||
inline bool sanitize (OT::hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
||||
if (!c->check_struct (this))
|
||||
return_trace (false);
|
||||
|
||||
const NE_TYPEINFO* n = &chain;
|
||||
while (n != &Null(NE_TYPEINFO) && c->check_struct (n) && n->get_type_id () != 0)
|
||||
{
|
||||
if (n->get_type_id () == NE_TYPEINFO::FONT)
|
||||
return_trace (n->sanitize (c, base, alignmentShiftCount));
|
||||
n = &n->next();
|
||||
}
|
||||
return_trace (false);
|
||||
}
|
||||
|
||||
inline unsigned int get_shift_value () const
|
||||
{
|
||||
return alignmentShiftCount;
|
||||
}
|
||||
|
||||
inline const NE_TYPEINFO& get_fonts_entry () const
|
||||
{
|
||||
const NE_TYPEINFO* n = &chain;
|
||||
while (n != &Null(NE_TYPEINFO) && n->get_type_id () != 0)
|
||||
{
|
||||
if (n->get_type_id () == NE_TYPEINFO::FONT)
|
||||
return *n;
|
||||
n = &n->next();
|
||||
}
|
||||
return Null(NE_TYPEINFO);
|
||||
}
|
||||
|
||||
protected:
|
||||
LEUINT16 alignmentShiftCount;
|
||||
NE_TYPEINFO chain;
|
||||
// It is followed by an array of OT::ArrayOf<LEUINT8, LEUINT8> chars;
|
||||
public:
|
||||
DEFINE_SIZE_MIN (2);
|
||||
};
|
||||
|
||||
// https://github.com/wine-mirror/wine/blob/master/include/winnt.h#L2467
|
||||
struct LE_IMAGE_OS2_HEADER
|
||||
{
|
||||
inline bool sanitize (OT::hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) && (this+rsrctab).sanitize (c, base)));
|
||||
}
|
||||
|
||||
inline const NE_RESOURCE_TABLE& get_resource_table () const
|
||||
{
|
||||
if (magic != 0x454E) // Only NE containers are support for now, NE == 0x454E
|
||||
return Null(NE_RESOURCE_TABLE);
|
||||
return this+rsrctab;
|
||||
}
|
||||
|
||||
protected:
|
||||
LEUINT16 magic; /* 00 NE signature 'NE' */
|
||||
LEUINT8 ver; /* 02 Linker version number */
|
||||
LEUINT8 rev; /* 03 Linker revision number */
|
||||
LEUINT16 enttab; /* 04 Offset to entry table relative to NE */
|
||||
LEUINT16 cbenttab; /* 06 Length of entry table in bytes */
|
||||
LEUINT32 crc; /* 08 Checksum */
|
||||
LEUINT16 flags; /* 0c Flags about segments in this file */
|
||||
LEUINT16 autodata; /* 0e Automatic data segment number */
|
||||
LEUINT16 heap; /* 10 Initial size of local heap */
|
||||
LEUINT16 stack; /* 12 Initial size of stack */
|
||||
LEUINT32 csip; /* 14 Initial CS:IP */
|
||||
LEUINT32 sssp; /* 18 Initial SS:SP */
|
||||
LEUINT16 cseg; /* 1c # of entries in segment table */
|
||||
LEUINT16 cmod; /* 1e # of entries in module reference tab. */
|
||||
LEUINT16 cbnrestab; /* 20 Length of nonresident-name table */
|
||||
LEUINT16 segtab; /* 22 Offset to segment table */
|
||||
OT::OffsetTo<NE_RESOURCE_TABLE, LEUINT16>
|
||||
rsrctab; /* 24 Offset to resource table */
|
||||
LEUINT16 restab; /* 26 Offset to resident-name table */
|
||||
LEUINT16 modtab; /* 28 Offset to module reference table */
|
||||
LEUINT16 imptab; /* 2a Offset to imported name table */
|
||||
LEUINT32 nrestab; /* 2c Offset to nonresident-name table */
|
||||
LEUINT16 cmovent; /* 30 # of movable entry points */
|
||||
LEUINT16 align; /* 32 Logical sector alignment shift count */
|
||||
LEUINT16 cres; /* 34 # of resource segments */
|
||||
LEUINT8 exetyp; /* 36 Flags indicating target OS */
|
||||
LEUINT8 flagsothers; /* 37 Additional information flags */
|
||||
LEUINT16 pretthunks; /* 38 Offset to return thunks */
|
||||
LEUINT16 psegrefbytes; /* 3a Offset to segment ref. bytes */
|
||||
LEUINT16 swaparea; /* 3c Reserved by Microsoft */
|
||||
LEUINT16 expver; /* 3e Expected Windows version number */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (64);
|
||||
};
|
||||
|
||||
struct LE_IMAGE_DOS_HEADER {
|
||||
inline bool sanitize (OT::hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) &&
|
||||
get_os2_header ().sanitize (c, this)));
|
||||
}
|
||||
|
||||
inline const LE_IMAGE_OS2_HEADER& get_os2_header () const
|
||||
{
|
||||
return this+e_lfanew;
|
||||
}
|
||||
|
||||
protected:
|
||||
LEUINT16 e_magic; // Magic number
|
||||
LEUINT16 e_cblp; // Bytes on last page of file
|
||||
LEUINT16 e_cp; // Pages in file
|
||||
LEUINT16 e_crlc; // Relocations
|
||||
LEUINT16 e_cparhdr; // Size of header in paragraphs
|
||||
LEUINT16 e_minalloc; // Minimum extra paragraphs needed
|
||||
LEUINT16 e_maxalloc; // Maximum extra paragraphs needed
|
||||
LEUINT16 e_ss; // Initial (relative) SS value
|
||||
LEUINT16 e_sp; // Initial SP value
|
||||
LEUINT16 e_csum; // Checksum
|
||||
LEUINT16 e_ip; // Initial IP value
|
||||
LEUINT16 e_cs; // Initial (relative) CS value
|
||||
LEUINT16 e_lfarlc; // File address of relocation table
|
||||
LEUINT16 e_ovno; // Overlay number
|
||||
LEUINT16 e_res_0; // Reserved words
|
||||
LEUINT16 e_res_1; // Reserved words
|
||||
LEUINT16 e_res_2; // Reserved words
|
||||
LEUINT16 e_res_3; // Reserved words
|
||||
LEUINT16 e_oemid; // OEM identifier (for e_oeminfo)
|
||||
LEUINT16 e_oeminfo; // OEM information; e_oemid specific
|
||||
LEUINT16 e_res2_0; // Reserved words
|
||||
LEUINT16 e_res2_1; // Reserved words
|
||||
LEUINT16 e_res2_2; // Reserved words
|
||||
LEUINT16 e_res2_3; // Reserved words
|
||||
LEUINT16 e_res2_4; // Reserved words
|
||||
LEUINT16 e_res2_5; // Reserved words
|
||||
LEUINT16 e_res2_6; // Reserved words
|
||||
LEUINT16 e_res2_7; // Reserved words
|
||||
LEUINT16 e_res2_8; // Reserved words
|
||||
LEUINT16 e_res2_9; // Reserved words
|
||||
OT::OffsetTo<LE_IMAGE_OS2_HEADER, LEUINT32>
|
||||
e_lfanew; // File address of new exe header
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (64);
|
||||
};
|
||||
|
||||
int main (int argc, char** argv) {
|
||||
hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
|
||||
|
||||
OT::Sanitizer<LE_IMAGE_DOS_HEADER> sanitizer;
|
||||
hb_blob_t *font_blob = sanitizer.sanitize (blob);
|
||||
const LE_IMAGE_DOS_HEADER* dos_header = font_blob->as<LE_IMAGE_DOS_HEADER> ();
|
||||
|
||||
const NE_RESOURCE_TABLE &rtable = dos_header->get_os2_header ().get_resource_table ();
|
||||
int shift = rtable.get_shift_value ();
|
||||
const NE_TYPEINFO& entry = rtable.get_fonts_entry ();
|
||||
for (unsigned int i = 0; i < entry.get_count (); ++i)
|
||||
{
|
||||
const LE_FONTINFO16& font = entry.get_font (i, dos_header, shift);
|
||||
printf ("version: %x, weight: %d, charset: %s\n", font.get_version (),
|
||||
font.get_weight (), font.get_charset ());
|
||||
// font.dump ();
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -328,6 +328,9 @@ def map_to_use(data):
|
|||
# TODO: https://github.com/harfbuzz/harfbuzz/pull/626
|
||||
if U == 0xA8B4: UISC = Consonant_Medial
|
||||
|
||||
# TODO: https://github.com/harfbuzz/harfbuzz/issues/1105
|
||||
if U == 0x11134: UISC = Gemination_Mark
|
||||
|
||||
values = [k for k,v in items if v(U,UISC,UGC)]
|
||||
assert len(values) == 1, "%s %s %s %s" % (hex(U), UISC, UGC, values)
|
||||
USE = values[0]
|
||||
|
@ -356,6 +359,13 @@ def map_to_use(data):
|
|||
# https://github.com/roozbehp/unicode-data/issues/8
|
||||
if U == 0x0A51: UIPC = Bottom
|
||||
|
||||
# TODO: https://github.com/harfbuzz/harfbuzz/pull/982
|
||||
if UBlock == 'Chakma' and is_VOWEL (U, UISC, UGC):
|
||||
if UIPC == Top:
|
||||
UIPC = Bottom
|
||||
elif UIPC == Bottom:
|
||||
UIPC = Top
|
||||
|
||||
assert (UIPC in [Not_Applicable, Visual_Order_Left] or
|
||||
USE in use_positions), "%s %s %s %s %s" % (hex(U), UIPC, USE, UISC, UGC)
|
||||
|
||||
|
|
|
@ -1,67 +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_FMTX_TABLE_HH
|
||||
#define HB_AAT_FMTX_TABLE_HH
|
||||
|
||||
#include "hb-aat-layout-common-private.hh"
|
||||
|
||||
/*
|
||||
* fmtx -- Font Metrics
|
||||
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6fmtx.html
|
||||
*/
|
||||
#define HB_AAT_TAG_fmtx HB_TAG('f','m','t','x')
|
||||
|
||||
|
||||
namespace AAT {
|
||||
|
||||
|
||||
struct fmtx
|
||||
{
|
||||
static const hb_tag_t tableTag = HB_AAT_TAG_fmtx;
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this)));
|
||||
}
|
||||
|
||||
FixedVersion<>version; /* Version (set to 0x00020000). */
|
||||
HBUINT32 glyphIndex; /* The glyph whose points represent the metrics. */
|
||||
HBUINT8 horizontalBefore; /* Point number for the horizontal ascent. */
|
||||
HBUINT8 horizontalAfter; /* Point number for the horizontal descent. */
|
||||
HBUINT8 horizontalCaretHead; /* Point number for the horizontal caret head. */
|
||||
HBUINT8 horizontalCaretBase; /* Point number for the horizontal caret base. */
|
||||
HBUINT8 verticalBefore; /* Point number for the vertical ascent. */
|
||||
HBUINT8 verticalAfter; /* Point number for the vertical descent. */
|
||||
HBUINT8 verticalCaretHead; /* Point number for the vertical caret head. */
|
||||
HBUINT8 verticalCaretBase; /* Point number for the vertical caret base. */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (16);
|
||||
};
|
||||
|
||||
} /* namespace AAT */
|
||||
|
||||
|
||||
#endif /* HB_AAT_FMTX_TABLE_HH */
|
|
@ -1,73 +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_GCID_TABLE_HH
|
||||
#define HB_AAT_GCID_TABLE_HH
|
||||
|
||||
#include "hb-aat-layout-common-private.hh"
|
||||
|
||||
/*
|
||||
* gcid -- Glyphs CIDs
|
||||
* https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6gcid.html
|
||||
*/
|
||||
#define HB_AAT_TAG_gcid HB_TAG('g','c','i','d')
|
||||
|
||||
|
||||
namespace AAT {
|
||||
|
||||
|
||||
struct gcid
|
||||
{
|
||||
static const hb_tag_t tableTag = HB_AAT_TAG_gcid;
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (likely (c->check_struct (this) && CIDs.sanitize (c)));
|
||||
}
|
||||
|
||||
protected:
|
||||
HBUINT16 version; /* Version number (set to 0) */
|
||||
HBUINT16 format; /* Data format (set to 0) */
|
||||
HBUINT32 size; /* Size of the table, including header */
|
||||
HBUINT16 registry; /* The registry ID */
|
||||
HBUINT8 registryName[64];
|
||||
/* The registry name in ASCII */
|
||||
HBUINT16 order; /* The order ID */
|
||||
HBUINT8 orderName[64]; /* The order name in ASCII */
|
||||
HBUINT16 supplementVersion;
|
||||
/* The supplement version */
|
||||
ArrayOf<HBUINT16>
|
||||
CIDs; /* The CIDs for the glyphs in the font,
|
||||
* starting with glyph 0. If a glyph does not correspond
|
||||
* to a CID in the identified collection, 0xFFFF is used.
|
||||
* This should not exceed the number of glyphs in the font. */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (144, CIDs);
|
||||
};
|
||||
|
||||
} /* namespace AAT */
|
||||
|
||||
|
||||
#endif /* HB_AAT_GCID_TABLE_HH */
|
|
@ -161,7 +161,7 @@ struct LookupFormat0
|
|||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (arrayZ.sanitize (c, c->num_glyphs));
|
||||
return_trace (arrayZ.sanitize (c, c->get_num_glyphs ()));
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -625,7 +625,7 @@ struct hb_aat_apply_context_t :
|
|||
sanitizer (), lookup_index (0), debug_depth (0)
|
||||
{
|
||||
sanitizer.init (table);
|
||||
sanitizer.num_glyphs = face->get_num_glyphs ();
|
||||
sanitizer.set_num_glyphs (face->get_num_glyphs ());
|
||||
sanitizer.start_processing ();
|
||||
}
|
||||
|
||||
|
|
|
@ -36,48 +36,12 @@
|
|||
#include "hb-aat-layout-kerx-table.hh"
|
||||
#include "hb-aat-layout-morx-table.hh"
|
||||
#include "hb-aat-layout-trak-table.hh"
|
||||
#include "hb-aat-fmtx-table.hh" // Just so we compile it; unused otherwise.
|
||||
#include "hb-aat-gcid-table.hh" // Just so we compile it; unused otherwise.
|
||||
#include "hb-aat-ltag-table.hh" // Just so we compile it; unused otherwise.
|
||||
|
||||
/*
|
||||
* morx/kerx/trak
|
||||
* morx/kerx/trak/ankr
|
||||
*/
|
||||
|
||||
#if 0
|
||||
static inline const AAT::ankr&
|
||||
_get_ankr (hb_face_t *face, hb_blob_t **blob = nullptr)
|
||||
{
|
||||
if (unlikely (!hb_ot_shaper_face_data_ensure (face)))
|
||||
{
|
||||
if (blob)
|
||||
*blob = hb_blob_get_empty ();
|
||||
return Null(AAT::ankr);
|
||||
}
|
||||
hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
|
||||
const AAT::ankr& ankr = *(layout->ankr.get ());
|
||||
if (blob)
|
||||
*blob = layout->ankr.blob;
|
||||
return ankr;
|
||||
}
|
||||
|
||||
static inline const AAT::kerx&
|
||||
_get_kerx (hb_face_t *face, hb_blob_t **blob = nullptr)
|
||||
{
|
||||
if (unlikely (!hb_ot_shaper_face_data_ensure (face)))
|
||||
{
|
||||
if (blob)
|
||||
*blob = hb_blob_get_empty ();
|
||||
return Null(AAT::kerx);
|
||||
}
|
||||
hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
|
||||
/* XXX this doesn't call set_num_glyphs on sanitizer. */
|
||||
const AAT::kerx& kerx = *(layout->kerx.get ());
|
||||
if (blob)
|
||||
*blob = layout->kerx.blob;
|
||||
return kerx;
|
||||
}
|
||||
|
||||
static inline const AAT::morx&
|
||||
_get_morx (hb_face_t *face, hb_blob_t **blob = nullptr)
|
||||
{
|
||||
|
@ -88,36 +52,16 @@ _get_morx (hb_face_t *face, hb_blob_t **blob = nullptr)
|
|||
return Null(AAT::morx);
|
||||
}
|
||||
hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
|
||||
/* XXX this doesn't call set_num_glyphs on sanitizer. */
|
||||
const AAT::morx& morx = *(layout->morx.get ());
|
||||
const AAT::morx& morx = *(layout->table.morx.get ());
|
||||
if (blob)
|
||||
*blob = layout->morx.blob;
|
||||
*blob = layout->table.morx.get_blob ();
|
||||
return morx;
|
||||
}
|
||||
|
||||
static inline const AAT::trak&
|
||||
_get_trak (hb_face_t *face, hb_blob_t **blob = nullptr)
|
||||
{
|
||||
if (unlikely (!hb_ot_shaper_face_data_ensure (face)))
|
||||
{
|
||||
if (blob)
|
||||
*blob = hb_blob_get_empty ();
|
||||
return Null(AAT::trak);
|
||||
}
|
||||
hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
|
||||
const AAT::trak& trak = *(layout->trak.get ());
|
||||
if (blob)
|
||||
*blob = layout->trak.blob;
|
||||
return trak;
|
||||
}
|
||||
#endif
|
||||
|
||||
// static inline void
|
||||
// _hb_aat_layout_create (hb_face_t *face)
|
||||
// {
|
||||
// OT::Sanitizer<AAT::morx> sanitizer;
|
||||
// sanitizer.set_num_glyphs (face->get_num_glyphs ());
|
||||
// hb_blob_t *morx_blob = sanitizer.sanitize (face->reference_table (HB_AAT_TAG_morx));
|
||||
// hb_blob_t *morx_blob = hb_sanitize_context_t ().reference_table<AAT::morx> (face);
|
||||
// morx_blob->as<AAT::morx> ();
|
||||
|
||||
// if (0)
|
||||
|
@ -129,13 +73,11 @@ _get_trak (hb_face_t *face, hb_blob_t **blob = nullptr)
|
|||
void
|
||||
hb_aat_layout_substitute (hb_font_t *font, hb_buffer_t *buffer)
|
||||
{
|
||||
#if 0
|
||||
hb_blob_t *blob;
|
||||
const AAT::morx& morx = _get_morx (font->face, &blob);
|
||||
|
||||
AAT::hb_aat_apply_context_t c (font, buffer, blob);
|
||||
morx.apply (&c);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -46,35 +46,74 @@
|
|||
/* Defined externally, i.e. in config.h; must have typedef'ed hb_atomic_int_impl_t as well. */
|
||||
|
||||
|
||||
#elif !defined(HB_NO_MT) && defined(__ATOMIC_CONSUME)
|
||||
|
||||
/* C++11-style GCC primitives. */
|
||||
|
||||
typedef int hb_atomic_int_impl_t;
|
||||
#define hb_atomic_int_impl_add(AI, V) __atomic_fetch_add ((AI), (V), __ATOMIC_ACQ_REL)
|
||||
#define hb_atomic_int_impl_set_relaxed(AI, V) __atomic_store_n ((AI), (V), __ATOMIC_RELAXED)
|
||||
#define hb_atomic_int_impl_get_relaxed(AI) __atomic_load_n ((AI), __ATOMIC_RELAXED)
|
||||
|
||||
#define hb_atomic_ptr_impl_get(P) __atomic_load_n ((P), __ATOMIC_CONSUME)
|
||||
static inline bool
|
||||
_hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
|
||||
{
|
||||
const void *O = O_; // Need lvalue
|
||||
return __atomic_compare_exchange_n ((void **) P, (void **) &O, (void *) N, true, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED);
|
||||
}
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N))
|
||||
|
||||
#elif !defined(HB_NO_MT) && __cplusplus >= 201103L
|
||||
|
||||
/* C++11 atomics. */
|
||||
|
||||
#include <atomic>
|
||||
|
||||
typedef int hb_atomic_int_impl_t;
|
||||
#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_get_relaxed(AI) (reinterpret_cast<std::atomic<int> *> (AI)->load (std::memory_order_relaxed))
|
||||
|
||||
#define hb_atomic_ptr_impl_get(P) (reinterpret_cast<std::atomic<void*> *> (P)->load (std::memory_order_consume))
|
||||
static inline bool
|
||||
_hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
|
||||
{
|
||||
const void *O = O_; // Need lvalue
|
||||
return reinterpret_cast<std::atomic<const void*> *> (P)->compare_exchange_weak (O, N, std::memory_order_acq_rel, std::memory_order_relaxed);
|
||||
}
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_atomic_ptr_impl_cmplexch ((const void **) (P), (O), (N))
|
||||
|
||||
|
||||
#elif !defined(HB_NO_MT) && (defined(_WIN32) || defined(__CYGWIN__))
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
/* MinGW has a convoluted history of supporting MemoryBarrier
|
||||
* properly. As such, define a function to wrap the whole
|
||||
* thing. */
|
||||
static inline void _HBMemoryBarrier (void) {
|
||||
static inline void _hb_memory_barrier (void)
|
||||
{
|
||||
#if !defined(MemoryBarrier)
|
||||
/* MinGW has a convoluted history of supporting MemoryBarrier. */
|
||||
long dummy = 0;
|
||||
InterlockedExchange (&dummy, 1);
|
||||
#else
|
||||
MemoryBarrier ();
|
||||
#endif
|
||||
}
|
||||
#define _hb_memory_barrier() _hb_memory_barrier ()
|
||||
|
||||
typedef LONG hb_atomic_int_impl_t;
|
||||
#define hb_atomic_int_impl_add(AI, V) InterlockedExchangeAdd (&(AI), (V))
|
||||
#define hb_atomic_int_impl_add(AI, V) InterlockedExchangeAdd ((AI), (V))
|
||||
|
||||
#define hb_atomic_ptr_impl_get(P) (_HBMemoryBarrier (), (void *) *(P))
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) (InterlockedCompareExchangePointer ((void **) (P), (void *) (N), (void *) (O)) == (void *) (O))
|
||||
|
||||
|
||||
#elif !defined(HB_NO_MT) && defined(HAVE_INTEL_ATOMIC_PRIMITIVES)
|
||||
|
||||
typedef int hb_atomic_int_impl_t;
|
||||
#define hb_atomic_int_impl_add(AI, V) __sync_fetch_and_add (&(AI), (V))
|
||||
#define _hb_memory_barrier() __sync_synchronize ()
|
||||
|
||||
typedef int hb_atomic_int_impl_t;
|
||||
#define hb_atomic_int_impl_add(AI, V) __sync_fetch_and_add ((AI), (V))
|
||||
|
||||
#define hb_atomic_ptr_impl_get(P) (void *) (__sync_synchronize (), *(P))
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) __sync_bool_compare_and_swap ((P), (O), (N))
|
||||
|
||||
|
||||
|
@ -83,11 +122,30 @@ typedef int hb_atomic_int_impl_t;
|
|||
#include <atomic.h>
|
||||
#include <mbarrier.h>
|
||||
|
||||
typedef unsigned int hb_atomic_int_impl_t;
|
||||
#define hb_atomic_int_impl_add(AI, V) ( ({__machine_rw_barrier ();}), atomic_add_int_nv (&(AI), (V)) - (V))
|
||||
#define _hb_memory_r_barrier() __machine_r_barrier ()
|
||||
#define _hb_memory_w_barrier() __machine_w_barrier ()
|
||||
#define _hb_memory_barrier() __machine_rw_barrier ()
|
||||
|
||||
#define hb_atomic_ptr_impl_get(P) ( ({__machine_rw_barrier ();}), (void *) *(P))
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) ( ({__machine_rw_barrier ();}), atomic_cas_ptr ((void **) (P), (void *) (O), (void *) (N)) == (void *) (O) ? true : false)
|
||||
typedef unsigned int hb_atomic_int_impl_t;
|
||||
|
||||
static inline int _hb_fetch_and_add (hb_atomic_int_impl_t *AI, int V)
|
||||
{
|
||||
_hb_memory_w_barrier ();
|
||||
int result = atomic_add_int_nv (AI, V);
|
||||
_hb_memory_r_barrier ();
|
||||
return result;
|
||||
}
|
||||
static inline bool _hb_compare_and_swap_ptr (const void **P, const void *O, const void *N)
|
||||
{
|
||||
_hb_memory_w_barrier ();
|
||||
int result = atomic_cas_ptr ((void **) P, (void *) O, (void *) N) == (void *) O;
|
||||
_hb_memory_r_barrier ();
|
||||
return result;
|
||||
}
|
||||
|
||||
#define hb_atomic_int_impl_add(AI, V) _hb_fetch_and_add ((AI), (V))
|
||||
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_compare_and_swap_ptr ((const void **) (P), (O), (N))
|
||||
|
||||
|
||||
#elif !defined(HB_NO_MT) && defined(__APPLE__)
|
||||
|
@ -99,11 +157,11 @@ typedef unsigned int hb_atomic_int_impl_t;
|
|||
#include <Availability.h>
|
||||
#endif
|
||||
|
||||
#define _hb_memory_barrier() OSMemoryBarrier ()
|
||||
|
||||
typedef int32_t hb_atomic_int_impl_t;
|
||||
#define hb_atomic_int_impl_add(AI, V) (OSAtomicAdd32Barrier ((V), &(AI)) - (V))
|
||||
#define hb_atomic_int_impl_add(AI, V) (OSAtomicAdd32Barrier ((V), (AI)) - (V))
|
||||
|
||||
#define hb_atomic_ptr_impl_get(P) (OSMemoryBarrier (), (void *) *(P))
|
||||
#if (MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_4 || __IPHONE_VERSION_MIN_REQUIRED >= 20100)
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) OSAtomicCompareAndSwapPtrBarrier ((void *) (O), (void *) (N), (void **) (P))
|
||||
#else
|
||||
|
@ -119,63 +177,88 @@ typedef int32_t hb_atomic_int_impl_t;
|
|||
|
||||
#include <builtins.h>
|
||||
|
||||
|
||||
static inline int _hb_fetch_and_add(volatile int* AI, unsigned int V) {
|
||||
__lwsync();
|
||||
int result = __fetch_and_add(AI, V);
|
||||
__isync();
|
||||
return result;
|
||||
}
|
||||
static inline int _hb_compare_and_swaplp(volatile long* P, long O, long N) {
|
||||
__sync();
|
||||
int result = __compare_and_swaplp (P, &O, N);
|
||||
__sync();
|
||||
return result;
|
||||
}
|
||||
#define _hb_memory_barrier() __lwsync ()
|
||||
|
||||
typedef int hb_atomic_int_impl_t;
|
||||
#define hb_atomic_int_impl_add(AI, V) _hb_fetch_and_add (&(AI), (V))
|
||||
|
||||
#define hb_atomic_ptr_impl_get(P) (__sync(), (void *) *(P))
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) _hb_compare_and_swaplp ((long*)(P), (long)(O), (long)(N))
|
||||
static inline int _hb_fetch_and_add (hb_atomic_int_impl_t *AI, int V)
|
||||
{
|
||||
_hb_memory_barrier ();
|
||||
int result = __fetch_and_add (AI, V);
|
||||
_hb_memory_barrier ();
|
||||
return result;
|
||||
}
|
||||
static inline bool _hb_compare_and_swaplp (long *P, long O, long N)
|
||||
{
|
||||
_hb_memory_barrier ();
|
||||
bool result = __compare_and_swaplp (P, &O, N);
|
||||
_hb_memory_barrier ();
|
||||
return result;
|
||||
}
|
||||
|
||||
#define hb_atomic_int_impl_add(AI, V) _hb_fetch_and_add ((AI), (V))
|
||||
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) _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. */
|
||||
|
||||
typedef volatile int hb_atomic_int_impl_t;
|
||||
#define hb_atomic_int_impl_add(AI, V) (((AI) += (V)) - (V))
|
||||
#define _hb_memory_barrier()
|
||||
|
||||
typedef volatile int hb_atomic_int_impl_t;
|
||||
#define hb_atomic_int_impl_add(AI, V) ((*(AI) += (V)) - (V))
|
||||
|
||||
#define hb_atomic_ptr_impl_get(P) ((void *) *(P))
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) (* (void * volatile *) (P) == (void *) (O) ? (* (void * volatile *) (P) = (void *) (N), true) : false)
|
||||
|
||||
|
||||
#else /* HB_NO_MT */
|
||||
|
||||
typedef int hb_atomic_int_impl_t;
|
||||
#define hb_atomic_int_impl_add(AI, V) (((AI) += (V)) - (V))
|
||||
#define hb_atomic_int_impl_add(AI, V) ((*(AI) += (V)) - (V))
|
||||
|
||||
#define _hb_memory_barrier()
|
||||
|
||||
#define hb_atomic_ptr_impl_get(P) ((void *) *(P))
|
||||
#define hb_atomic_ptr_impl_cmpexch(P,O,N) (* (void **) (P) == (void *) (O) ? (* (void **) (P) = (void *) (N), true) : false)
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef _hb_memory_r_barrier
|
||||
#define _hb_memory_r_barrier() _hb_memory_barrier ()
|
||||
#endif
|
||||
#ifndef _hb_memory_w_barrier
|
||||
#define _hb_memory_w_barrier() _hb_memory_barrier ()
|
||||
#endif
|
||||
#ifndef HB_ATOMIC_INT_INIT
|
||||
#define HB_ATOMIC_INT_INIT(V) {V}
|
||||
#endif
|
||||
#ifndef hb_atomic_int_impl_set_relaxed
|
||||
#define hb_atomic_int_impl_set_relaxed(AI, V) (*(AI) = (V))
|
||||
#endif
|
||||
#ifndef hb_atomic_int_impl_get_relaxed
|
||||
#define hb_atomic_int_impl_get_relaxed(AI) (*(AI))
|
||||
#endif
|
||||
#ifndef hb_atomic_ptr_impl_get
|
||||
inline void *hb_atomic_ptr_impl_get (void **P) { void *v = *P; _hb_memory_r_barrier (); return v; }
|
||||
#endif
|
||||
|
||||
|
||||
struct hb_atomic_int_t
|
||||
{
|
||||
hb_atomic_int_impl_t v;
|
||||
mutable hb_atomic_int_impl_t v;
|
||||
|
||||
inline void set_unsafe (int v_) { v = v_; }
|
||||
inline int get_unsafe (void) const { return v; }
|
||||
inline int inc (void) { return hb_atomic_int_impl_add (const_cast<hb_atomic_int_impl_t &> (v), 1); }
|
||||
inline int dec (void) { return hb_atomic_int_impl_add (const_cast<hb_atomic_int_impl_t &> (v), -1); }
|
||||
inline void set_relaxed (int v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
|
||||
inline int get_relaxed (void) const { return hb_atomic_int_impl_get_relaxed (&v); }
|
||||
inline int inc (void) { return hb_atomic_int_impl_add (&v, 1); }
|
||||
inline int dec (void) { return hb_atomic_int_impl_add (&v, -1); }
|
||||
};
|
||||
|
||||
|
||||
#define hb_atomic_ptr_get(P) hb_atomic_ptr_impl_get(P)
|
||||
#define hb_atomic_ptr_get(P) hb_atomic_ptr_impl_get((void **) P)
|
||||
#define hb_atomic_ptr_cmpexch(P,O,N) hb_atomic_ptr_impl_cmpexch((P),(O),(N))
|
||||
|
||||
|
||||
|
|
|
@ -57,11 +57,6 @@ struct hb_blob_t
|
|||
HB_INTERNAL bool try_make_writable_inplace (void);
|
||||
HB_INTERNAL bool try_make_writable_inplace_unix (void);
|
||||
|
||||
inline void lock (void)
|
||||
{
|
||||
hb_blob_make_immutable (this);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline const Type* as (void) const
|
||||
{
|
||||
|
@ -81,6 +76,7 @@ struct hb_blob_t
|
|||
void *user_data;
|
||||
hb_destroy_func_t destroy;
|
||||
};
|
||||
DECLARE_NULL_INSTANCE (hb_blob_t);
|
||||
|
||||
|
||||
#endif /* HB_BLOB_PRIVATE_HH */
|
||||
|
|
|
@ -45,6 +45,20 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
|
||||
DEFINE_NULL_INSTANCE (hb_blob_t) =
|
||||
{
|
||||
HB_OBJECT_HEADER_STATIC,
|
||||
|
||||
true, /* immutable */
|
||||
|
||||
nullptr, /* data */
|
||||
0, /* length */
|
||||
HB_MEMORY_MODE_READONLY, /* mode */
|
||||
|
||||
nullptr, /* user_data */
|
||||
nullptr /* destroy */
|
||||
};
|
||||
|
||||
/**
|
||||
* hb_blob_create: (skip)
|
||||
* @data: Pointer to blob data.
|
||||
|
@ -182,20 +196,7 @@ hb_blob_copy_writable_or_fail (hb_blob_t *blob)
|
|||
hb_blob_t *
|
||||
hb_blob_get_empty (void)
|
||||
{
|
||||
static const hb_blob_t _hb_blob_nil = {
|
||||
HB_OBJECT_HEADER_STATIC,
|
||||
|
||||
true, /* immutable */
|
||||
|
||||
nullptr, /* data */
|
||||
0, /* length */
|
||||
HB_MEMORY_MODE_READONLY, /* mode */
|
||||
|
||||
nullptr, /* user_data */
|
||||
nullptr /* destroy */
|
||||
};
|
||||
|
||||
return const_cast<hb_blob_t *> (&_hb_blob_nil);
|
||||
return const_cast<hb_blob_t *> (&Null(hb_blob_t));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -83,7 +83,8 @@ HB_MARK_AS_FLAG_T (hb_buffer_scratch_flags_t);
|
|||
* hb_buffer_t
|
||||
*/
|
||||
|
||||
struct hb_buffer_t {
|
||||
struct hb_buffer_t
|
||||
{
|
||||
hb_object_header_t header;
|
||||
ASSERT_POD ();
|
||||
|
||||
|
@ -352,6 +353,7 @@ struct hb_buffer_t {
|
|||
info[i].mask &= ~HB_GLYPH_FLAG_UNSAFE_TO_BREAK;
|
||||
}
|
||||
};
|
||||
DECLARE_NULL_INSTANCE (hb_buffer_t);
|
||||
|
||||
|
||||
/* Loop over clusters. Duplicated in foreach_syllable(). */
|
||||
|
|
|
@ -701,6 +701,28 @@ hb_buffer_t::guess_segment_properties (void)
|
|||
|
||||
/* Public API */
|
||||
|
||||
DEFINE_NULL_INSTANCE (hb_buffer_t) =
|
||||
{
|
||||
HB_OBJECT_HEADER_STATIC,
|
||||
|
||||
const_cast<hb_unicode_funcs_t *> (&_hb_Null_hb_unicode_funcs_t),
|
||||
HB_BUFFER_FLAG_DEFAULT,
|
||||
HB_BUFFER_CLUSTER_LEVEL_DEFAULT,
|
||||
HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
|
||||
HB_BUFFER_SCRATCH_FLAG_DEFAULT,
|
||||
HB_BUFFER_MAX_LEN_DEFAULT,
|
||||
HB_BUFFER_MAX_OPS_DEFAULT,
|
||||
|
||||
HB_BUFFER_CONTENT_TYPE_INVALID,
|
||||
HB_SEGMENT_PROPERTIES_DEFAULT,
|
||||
false, /* successful */
|
||||
true, /* have_output */
|
||||
true /* have_positions */
|
||||
|
||||
/* Zero is good enough for everything else. */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* hb_buffer_create: (Xconstructor)
|
||||
*
|
||||
|
@ -743,27 +765,7 @@ hb_buffer_create (void)
|
|||
hb_buffer_t *
|
||||
hb_buffer_get_empty (void)
|
||||
{
|
||||
static const hb_buffer_t _hb_buffer_nil = {
|
||||
HB_OBJECT_HEADER_STATIC,
|
||||
|
||||
const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil),
|
||||
HB_BUFFER_FLAG_DEFAULT,
|
||||
HB_BUFFER_CLUSTER_LEVEL_DEFAULT,
|
||||
HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT,
|
||||
HB_BUFFER_SCRATCH_FLAG_DEFAULT,
|
||||
HB_BUFFER_MAX_LEN_DEFAULT,
|
||||
HB_BUFFER_MAX_OPS_DEFAULT,
|
||||
|
||||
HB_BUFFER_CONTENT_TYPE_INVALID,
|
||||
HB_SEGMENT_PROPERTIES_DEFAULT,
|
||||
false, /* successful */
|
||||
true, /* have_output */
|
||||
true /* have_positions */
|
||||
|
||||
/* Zero is good enough for everything else. */
|
||||
};
|
||||
|
||||
return const_cast<hb_buffer_t *> (&_hb_buffer_nil);
|
||||
return const_cast<hb_buffer_t *> (&Null(hb_buffer_t));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
/* hb_options_t */
|
||||
|
||||
hb_options_union_t _hb_options;
|
||||
hb_atomic_int_t _hb_options;
|
||||
|
||||
void
|
||||
_hb_options_init (void)
|
||||
|
@ -50,7 +50,7 @@ _hb_options_init (void)
|
|||
u.opts.uniscribe_bug_compatible = c && strstr (c, "uniscribe-bug-compatible");
|
||||
|
||||
/* This is idempotent and threadsafe. */
|
||||
_hb_options = u;
|
||||
_hb_options.set_relaxed (u.i);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1069,3 +1069,12 @@ hb_variation_to_string (hb_variation_t *variation,
|
|||
memcpy (buf, s, len);
|
||||
buf[len] = '\0';
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
#ifdef HB_NO_VISIBILITY
|
||||
#undef HB_NO_VISIBILITY
|
||||
#include "hb-static.cc"
|
||||
#define HB_NO_VISIBILITY 1
|
||||
#endif
|
||||
|
|
|
@ -269,7 +269,7 @@ create_ct_font (CGFontRef cg_font, CGFloat font_size)
|
|||
return ct_font;
|
||||
}
|
||||
|
||||
hb_coretext_shaper_face_data_t *
|
||||
hb_coretext_face_data_t *
|
||||
_hb_coretext_shaper_face_data_create (hb_face_t *face)
|
||||
{
|
||||
CGFontRef cg_font = create_cg_font (face);
|
||||
|
@ -280,11 +280,11 @@ _hb_coretext_shaper_face_data_create (hb_face_t *face)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
return (hb_coretext_shaper_face_data_t *) cg_font;
|
||||
return (hb_coretext_face_data_t *) cg_font;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_coretext_shaper_face_data_destroy (hb_coretext_shaper_face_data_t *data)
|
||||
_hb_coretext_shaper_face_data_destroy (hb_coretext_face_data_t *data)
|
||||
{
|
||||
CFRelease ((CGFontRef) data);
|
||||
}
|
||||
|
@ -306,7 +306,7 @@ hb_coretext_face_get_cg_font (hb_face_t *face)
|
|||
}
|
||||
|
||||
|
||||
hb_coretext_shaper_font_data_t *
|
||||
hb_coretext_font_data_t *
|
||||
_hb_coretext_shaper_font_data_create (hb_font_t *font)
|
||||
{
|
||||
hb_face_t *face = font->face;
|
||||
|
@ -321,11 +321,11 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
return (hb_coretext_shaper_font_data_t *) ct_font;
|
||||
return (hb_coretext_font_data_t *) ct_font;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_coretext_shaper_font_data_destroy (hb_coretext_shaper_font_data_t *data)
|
||||
_hb_coretext_shaper_font_data_destroy (hb_coretext_font_data_t *data)
|
||||
{
|
||||
CFRelease ((CTFontRef) data);
|
||||
}
|
||||
|
@ -348,7 +348,7 @@ hb_coretext_font_create (CTFontRef ct_font)
|
|||
hb_font_set_ptem (font, coretext_font_size_to_ptem (CTFontGetSize(ct_font)));
|
||||
|
||||
/* Let there be dragons here... */
|
||||
HB_SHAPER_DATA_GET (font) = (hb_coretext_shaper_font_data_t *) CFRetain (ct_font);
|
||||
HB_SHAPER_DATA_GET (font) = (hb_coretext_font_data_t *) CFRetain (ct_font);
|
||||
|
||||
return font;
|
||||
}
|
||||
|
@ -366,20 +366,20 @@ hb_coretext_font_get_ct_font (hb_font_t *font)
|
|||
* shaper shape_plan data
|
||||
*/
|
||||
|
||||
struct hb_coretext_shaper_shape_plan_data_t {};
|
||||
struct hb_coretext_shape_plan_data_t {};
|
||||
|
||||
hb_coretext_shaper_shape_plan_data_t *
|
||||
hb_coretext_shape_plan_data_t *
|
||||
_hb_coretext_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
|
||||
const hb_feature_t *user_features HB_UNUSED,
|
||||
unsigned int num_user_features HB_UNUSED,
|
||||
const int *coords HB_UNUSED,
|
||||
unsigned int num_coords HB_UNUSED)
|
||||
{
|
||||
return (hb_coretext_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
return (hb_coretext_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shaper_shape_plan_data_t *data HB_UNUSED)
|
||||
_hb_coretext_shaper_shape_plan_data_destroy (hb_coretext_shape_plan_data_t *data HB_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1329,9 +1329,9 @@ HB_SHAPER_DATA_ENSURE_DEFINE(coretext_aat, font)
|
|||
* shaper face data
|
||||
*/
|
||||
|
||||
struct hb_coretext_aat_shaper_face_data_t {};
|
||||
struct hb_coretext_aat_face_data_t {};
|
||||
|
||||
hb_coretext_aat_shaper_face_data_t *
|
||||
hb_coretext_aat_face_data_t *
|
||||
_hb_coretext_aat_shaper_face_data_create (hb_face_t *face)
|
||||
{
|
||||
static const hb_tag_t tags[] = {HB_CORETEXT_TAG_MORX, HB_CORETEXT_TAG_MORT, HB_CORETEXT_TAG_KERX};
|
||||
|
@ -1342,7 +1342,7 @@ _hb_coretext_aat_shaper_face_data_create (hb_face_t *face)
|
|||
if (hb_blob_get_length (blob))
|
||||
{
|
||||
hb_blob_destroy (blob);
|
||||
return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
|
||||
return hb_coretext_shaper_face_data_ensure (face) ? (hb_coretext_aat_face_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
|
||||
}
|
||||
hb_blob_destroy (blob);
|
||||
}
|
||||
|
@ -1351,7 +1351,7 @@ _hb_coretext_aat_shaper_face_data_create (hb_face_t *face)
|
|||
}
|
||||
|
||||
void
|
||||
_hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_shaper_face_data_t *data HB_UNUSED)
|
||||
_hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_face_data_t *data HB_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1360,16 +1360,16 @@ _hb_coretext_aat_shaper_face_data_destroy (hb_coretext_aat_shaper_face_data_t *d
|
|||
* shaper font data
|
||||
*/
|
||||
|
||||
struct hb_coretext_aat_shaper_font_data_t {};
|
||||
struct hb_coretext_aat_font_data_t {};
|
||||
|
||||
hb_coretext_aat_shaper_font_data_t *
|
||||
hb_coretext_aat_font_data_t *
|
||||
_hb_coretext_aat_shaper_font_data_create (hb_font_t *font)
|
||||
{
|
||||
return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
|
||||
return hb_coretext_shaper_font_data_ensure (font) ? (hb_coretext_aat_font_data_t *) HB_SHAPER_DATA_SUCCEEDED : nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_shaper_font_data_t *data HB_UNUSED)
|
||||
_hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_font_data_t *data HB_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1378,20 +1378,20 @@ _hb_coretext_aat_shaper_font_data_destroy (hb_coretext_aat_shaper_font_data_t *d
|
|||
* shaper shape_plan data
|
||||
*/
|
||||
|
||||
struct hb_coretext_aat_shaper_shape_plan_data_t {};
|
||||
struct hb_coretext_aat_shape_plan_data_t {};
|
||||
|
||||
hb_coretext_aat_shaper_shape_plan_data_t *
|
||||
hb_coretext_aat_shape_plan_data_t *
|
||||
_hb_coretext_aat_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
|
||||
const hb_feature_t *user_features HB_UNUSED,
|
||||
unsigned int num_user_features HB_UNUSED,
|
||||
const int *coords HB_UNUSED,
|
||||
unsigned int num_coords HB_UNUSED)
|
||||
{
|
||||
return (hb_coretext_aat_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
return (hb_coretext_aat_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_coretext_aat_shaper_shape_plan_data_destroy (hb_coretext_aat_shaper_shape_plan_data_t *data HB_UNUSED)
|
||||
_hb_coretext_aat_shaper_shape_plan_data_destroy (hb_coretext_aat_shape_plan_data_t *data HB_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#define HB_DEBUG_HH
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb-atomic-private.hh"
|
||||
#include "hb-dsalgs.hh"
|
||||
|
||||
|
||||
|
@ -35,6 +36,47 @@
|
|||
#define HB_DEBUG 0
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Global runtime options.
|
||||
*/
|
||||
|
||||
struct hb_options_t
|
||||
{
|
||||
unsigned int unused : 1; /* In-case sign bit is here. */
|
||||
unsigned int initialized : 1;
|
||||
unsigned int uniscribe_bug_compatible : 1;
|
||||
};
|
||||
|
||||
union hb_options_union_t {
|
||||
int i;
|
||||
hb_options_t opts;
|
||||
};
|
||||
static_assert ((sizeof (hb_atomic_int_t) >= sizeof (hb_options_union_t)), "");
|
||||
|
||||
HB_INTERNAL void
|
||||
_hb_options_init (void);
|
||||
|
||||
extern HB_INTERNAL hb_atomic_int_t _hb_options;
|
||||
|
||||
static inline hb_options_t
|
||||
hb_options (void)
|
||||
{
|
||||
/* Make a local copy, so we can access bitfield threadsafely. */
|
||||
hb_options_union_t u;
|
||||
u.i = _hb_options.get_relaxed ();
|
||||
|
||||
if (unlikely (!u.i))
|
||||
_hb_options_init ();
|
||||
|
||||
return u.opts;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Debug output (needs enabling at compile time.)
|
||||
*/
|
||||
|
||||
static inline bool
|
||||
_hb_debug (unsigned int level,
|
||||
unsigned int max_level)
|
||||
|
|
|
@ -133,7 +133,7 @@ public:
|
|||
* shaper face data
|
||||
*/
|
||||
|
||||
struct hb_directwrite_shaper_face_data_t
|
||||
struct hb_directwrite_face_data_t
|
||||
{
|
||||
IDWriteFactory *dwriteFactory;
|
||||
IDWriteFontFile *fontFile;
|
||||
|
@ -143,10 +143,10 @@ struct hb_directwrite_shaper_face_data_t
|
|||
hb_blob_t *faceBlob;
|
||||
};
|
||||
|
||||
hb_directwrite_shaper_face_data_t *
|
||||
hb_directwrite_face_data_t *
|
||||
_hb_directwrite_shaper_face_data_create (hb_face_t *face)
|
||||
{
|
||||
hb_directwrite_shaper_face_data_t *data = new hb_directwrite_shaper_face_data_t;
|
||||
hb_directwrite_face_data_t *data = new hb_directwrite_face_data_t;
|
||||
if (unlikely (!data))
|
||||
return nullptr;
|
||||
|
||||
|
@ -206,7 +206,7 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face)
|
|||
}
|
||||
|
||||
void
|
||||
_hb_directwrite_shaper_face_data_destroy (hb_directwrite_shaper_face_data_t *data)
|
||||
_hb_directwrite_shaper_face_data_destroy (hb_directwrite_face_data_t *data)
|
||||
{
|
||||
if (data->fontFace)
|
||||
data->fontFace->Release ();
|
||||
|
@ -233,16 +233,16 @@ _hb_directwrite_shaper_face_data_destroy (hb_directwrite_shaper_face_data_t *dat
|
|||
* shaper font data
|
||||
*/
|
||||
|
||||
struct hb_directwrite_shaper_font_data_t
|
||||
struct hb_directwrite_font_data_t
|
||||
{
|
||||
};
|
||||
|
||||
hb_directwrite_shaper_font_data_t *
|
||||
hb_directwrite_font_data_t *
|
||||
_hb_directwrite_shaper_font_data_create (hb_font_t *font)
|
||||
{
|
||||
if (unlikely (!hb_directwrite_shaper_face_data_ensure (font->face))) return nullptr;
|
||||
|
||||
hb_directwrite_shaper_font_data_t *data = new hb_directwrite_shaper_font_data_t;
|
||||
hb_directwrite_font_data_t *data = new hb_directwrite_font_data_t;
|
||||
if (unlikely (!data))
|
||||
return nullptr;
|
||||
|
||||
|
@ -250,7 +250,7 @@ _hb_directwrite_shaper_font_data_create (hb_font_t *font)
|
|||
}
|
||||
|
||||
void
|
||||
_hb_directwrite_shaper_font_data_destroy (hb_directwrite_shaper_font_data_t *data)
|
||||
_hb_directwrite_shaper_font_data_destroy (hb_directwrite_font_data_t *data)
|
||||
{
|
||||
delete data;
|
||||
}
|
||||
|
@ -260,20 +260,20 @@ _hb_directwrite_shaper_font_data_destroy (hb_directwrite_shaper_font_data_t *dat
|
|||
* shaper shape_plan data
|
||||
*/
|
||||
|
||||
struct hb_directwrite_shaper_shape_plan_data_t {};
|
||||
struct hb_directwrite_shape_plan_data_t {};
|
||||
|
||||
hb_directwrite_shaper_shape_plan_data_t *
|
||||
hb_directwrite_shape_plan_data_t *
|
||||
_hb_directwrite_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
|
||||
const hb_feature_t *user_features HB_UNUSED,
|
||||
unsigned int num_user_features HB_UNUSED,
|
||||
const int *coords HB_UNUSED,
|
||||
unsigned int num_coords HB_UNUSED)
|
||||
{
|
||||
return (hb_directwrite_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
return (hb_directwrite_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_directwrite_shaper_shape_plan_data_destroy (hb_directwrite_shaper_shape_plan_data_t *data HB_UNUSED)
|
||||
_hb_directwrite_shaper_shape_plan_data_destroy (hb_directwrite_shape_plan_data_t *data HB_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -555,8 +555,8 @@ _hb_directwrite_shape_full (hb_shape_plan_t *shape_plan,
|
|||
float lineWidth)
|
||||
{
|
||||
hb_face_t *face = font->face;
|
||||
hb_directwrite_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
|
||||
hb_directwrite_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
|
||||
hb_directwrite_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
|
||||
hb_directwrite_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
|
||||
IDWriteFactory *dwriteFactory = face_data->dwriteFactory;
|
||||
IDWriteFontFace *fontFace = face_data->fontFace;
|
||||
|
||||
|
|
|
@ -232,6 +232,18 @@ hb_ctz (T v)
|
|||
* Tiny stuff.
|
||||
*/
|
||||
|
||||
/* 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; }
|
||||
|
@ -262,6 +274,37 @@ hb_ceil_to_4 (unsigned int v)
|
|||
return ((v - 1) | 3) + 1;
|
||||
}
|
||||
|
||||
template <typename T> class hb_assert_unsigned_t;
|
||||
template <> class hb_assert_unsigned_t<unsigned char> {};
|
||||
template <> class hb_assert_unsigned_t<unsigned short> {};
|
||||
template <> class hb_assert_unsigned_t<unsigned int> {};
|
||||
template <> class hb_assert_unsigned_t<unsigned long> {};
|
||||
|
||||
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 ((sizeof (hb_assert_unsigned_t<T>) >= 0), "");
|
||||
|
||||
/* 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.
|
||||
|
@ -445,305 +488,6 @@ hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *o
|
|||
}
|
||||
|
||||
|
||||
#define HB_VECTOR_INIT {0, 0, false, nullptr}
|
||||
template <typename Type, unsigned int StaticSize=8>
|
||||
struct hb_vector_t
|
||||
{
|
||||
unsigned int len;
|
||||
unsigned int allocated;
|
||||
bool successful;
|
||||
Type *arrayZ;
|
||||
Type static_array[StaticSize];
|
||||
|
||||
void init (void)
|
||||
{
|
||||
len = 0;
|
||||
allocated = ARRAY_LENGTH (static_array);
|
||||
successful = true;
|
||||
arrayZ = static_array;
|
||||
}
|
||||
|
||||
inline Type& operator [] (unsigned int i)
|
||||
{
|
||||
if (unlikely (i >= len))
|
||||
return Crap (Type);
|
||||
return arrayZ[i];
|
||||
}
|
||||
inline const Type& operator [] (unsigned int i) const
|
||||
{
|
||||
if (unlikely (i >= len))
|
||||
return Null(Type);
|
||||
return arrayZ[i];
|
||||
}
|
||||
|
||||
inline Type *push (void)
|
||||
{
|
||||
if (unlikely (!resize (len + 1)))
|
||||
return &Crap(Type);
|
||||
return &arrayZ[len - 1];
|
||||
}
|
||||
inline Type *push (const Type& v)
|
||||
{
|
||||
Type *p = push ();
|
||||
*p = v;
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Allocate for size but don't adjust len. */
|
||||
inline bool alloc (unsigned int size)
|
||||
{
|
||||
if (unlikely (!successful))
|
||||
return false;
|
||||
|
||||
if (likely (size <= allocated))
|
||||
return true;
|
||||
|
||||
/* Reallocate */
|
||||
|
||||
unsigned int new_allocated = allocated;
|
||||
while (size >= new_allocated)
|
||||
new_allocated += (new_allocated >> 1) + 8;
|
||||
|
||||
Type *new_array = nullptr;
|
||||
|
||||
if (arrayZ == static_array)
|
||||
{
|
||||
new_array = (Type *) calloc (new_allocated, sizeof (Type));
|
||||
if (new_array)
|
||||
memcpy (new_array, arrayZ, len * sizeof (Type));
|
||||
}
|
||||
else
|
||||
{
|
||||
bool overflows = (new_allocated < allocated) || hb_unsigned_mul_overflows (new_allocated, sizeof (Type));
|
||||
if (likely (!overflows))
|
||||
new_array = (Type *) realloc (arrayZ, new_allocated * sizeof (Type));
|
||||
}
|
||||
|
||||
if (unlikely (!new_array))
|
||||
{
|
||||
successful = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
arrayZ = new_array;
|
||||
allocated = new_allocated;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool resize (int size_)
|
||||
{
|
||||
unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
|
||||
if (!alloc (size))
|
||||
return false;
|
||||
|
||||
if (size > len)
|
||||
memset (arrayZ + len, 0, (size - len) * sizeof (*arrayZ));
|
||||
|
||||
len = size;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void pop (void)
|
||||
{
|
||||
if (!len) return;
|
||||
len--;
|
||||
}
|
||||
|
||||
inline void remove (unsigned int i)
|
||||
{
|
||||
if (unlikely (i >= len))
|
||||
return;
|
||||
memmove (static_cast<void *> (&arrayZ[i]),
|
||||
static_cast<void *> (&arrayZ[i + 1]),
|
||||
(len - i - 1) * sizeof (Type));
|
||||
len--;
|
||||
}
|
||||
|
||||
inline void shrink (int size_)
|
||||
{
|
||||
unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
|
||||
if (size < len)
|
||||
len = size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Type *find (T v) {
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
if (arrayZ[i] == v)
|
||||
return &arrayZ[i];
|
||||
return nullptr;
|
||||
}
|
||||
template <typename T>
|
||||
inline const Type *find (T v) const {
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
if (arrayZ[i] == v)
|
||||
return &arrayZ[i];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline void qsort (int (*cmp)(const void*, const void*))
|
||||
{
|
||||
::qsort (arrayZ, len, sizeof (Type), cmp);
|
||||
}
|
||||
|
||||
inline void qsort (void)
|
||||
{
|
||||
::qsort (arrayZ, len, sizeof (Type), Type::cmp);
|
||||
}
|
||||
|
||||
inline void qsort (unsigned int start, unsigned int end)
|
||||
{
|
||||
::qsort (arrayZ + start, end - start, sizeof (Type), Type::cmp);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Type *lsearch (const T &x)
|
||||
{
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
if (0 == this->arrayZ[i].cmp (&x))
|
||||
return &arrayZ[i];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Type *bsearch (const T &x)
|
||||
{
|
||||
unsigned int i;
|
||||
return bfind (x, &i) ? &arrayZ[i] : nullptr;
|
||||
}
|
||||
template <typename T>
|
||||
inline const Type *bsearch (const T &x) const
|
||||
{
|
||||
unsigned int i;
|
||||
return bfind (x, &i) ? &arrayZ[i] : nullptr;
|
||||
}
|
||||
template <typename T>
|
||||
inline bool bfind (const T &x, unsigned int *i) const
|
||||
{
|
||||
int min = 0, max = (int) this->len - 1;
|
||||
while (min <= max)
|
||||
{
|
||||
int mid = (min + max) / 2;
|
||||
int c = this->arrayZ[mid].cmp (&x);
|
||||
if (c < 0)
|
||||
max = mid - 1;
|
||||
else if (c > 0)
|
||||
min = mid + 1;
|
||||
else
|
||||
{
|
||||
*i = mid;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (max < 0 || (max < (int) this->len && this->arrayZ[max].cmp (&x) > 0))
|
||||
max++;
|
||||
*i = max;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void fini (void)
|
||||
{
|
||||
if (arrayZ != static_array)
|
||||
free (arrayZ);
|
||||
arrayZ = nullptr;
|
||||
allocated = len = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#define HB_LOCKABLE_SET_INIT {HB_VECTOR_INIT}
|
||||
template <typename item_t, typename lock_t>
|
||||
struct hb_lockable_set_t
|
||||
{
|
||||
hb_vector_t <item_t, 1> items;
|
||||
|
||||
inline void init (void) { items.init (); }
|
||||
|
||||
template <typename T>
|
||||
inline item_t *replace_or_insert (T v, lock_t &l, bool replace)
|
||||
{
|
||||
l.lock ();
|
||||
item_t *item = items.find (v);
|
||||
if (item) {
|
||||
if (replace) {
|
||||
item_t old = *item;
|
||||
*item = v;
|
||||
l.unlock ();
|
||||
old.fini ();
|
||||
}
|
||||
else {
|
||||
item = nullptr;
|
||||
l.unlock ();
|
||||
}
|
||||
} else {
|
||||
item = items.push (v);
|
||||
l.unlock ();
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void remove (T v, lock_t &l)
|
||||
{
|
||||
l.lock ();
|
||||
item_t *item = items.find (v);
|
||||
if (item) {
|
||||
item_t old = *item;
|
||||
*item = items[items.len - 1];
|
||||
items.pop ();
|
||||
l.unlock ();
|
||||
old.fini ();
|
||||
} else {
|
||||
l.unlock ();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool find (T v, item_t *i, lock_t &l)
|
||||
{
|
||||
l.lock ();
|
||||
item_t *item = items.find (v);
|
||||
if (item)
|
||||
*i = *item;
|
||||
l.unlock ();
|
||||
return !!item;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline item_t *find_or_insert (T v, lock_t &l)
|
||||
{
|
||||
l.lock ();
|
||||
item_t *item = items.find (v);
|
||||
if (!item) {
|
||||
item = items.push (v);
|
||||
}
|
||||
l.unlock ();
|
||||
return item;
|
||||
}
|
||||
|
||||
inline void fini (lock_t &l)
|
||||
{
|
||||
if (!items.len) {
|
||||
/* No need for locking. */
|
||||
items.fini ();
|
||||
return;
|
||||
}
|
||||
l.lock ();
|
||||
while (items.len) {
|
||||
item_t old = items[items.len - 1];
|
||||
items.pop ();
|
||||
l.unlock ();
|
||||
old.fini ();
|
||||
l.lock ();
|
||||
}
|
||||
items.fini ();
|
||||
l.unlock ();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
template <typename Type>
|
||||
struct hb_auto_t : Type
|
||||
{
|
||||
|
@ -854,8 +598,7 @@ struct hb_vector_size_t
|
|||
union {
|
||||
elt_t v[byte_size / sizeof (elt_t)];
|
||||
#if HB_VECTOR_SIZE
|
||||
typedef unsigned long vec_t __attribute__((vector_size (HB_VECTOR_SIZE / 8)));
|
||||
vec_t vec[byte_size / sizeof (vec_t)];
|
||||
hb_vector_size_impl_t vec[byte_size / sizeof (hb_vector_size_impl_t)];
|
||||
#endif
|
||||
} u;
|
||||
};
|
||||
|
|
|
@ -39,7 +39,8 @@
|
|||
* hb_face_t
|
||||
*/
|
||||
|
||||
struct hb_face_t {
|
||||
struct hb_face_t
|
||||
{
|
||||
hb_object_header_t header;
|
||||
ASSERT_POD ();
|
||||
|
||||
|
@ -55,16 +56,13 @@ struct hb_face_t {
|
|||
|
||||
struct hb_shaper_data_t shaper_data; /* Various shaper data. */
|
||||
|
||||
/* Various non-shaping data. */
|
||||
/* ... */
|
||||
|
||||
/* Cache */
|
||||
struct plan_node_t {
|
||||
struct plan_node_t
|
||||
{
|
||||
hb_shape_plan_t *shape_plan;
|
||||
plan_node_t *next;
|
||||
} *shape_plans;
|
||||
|
||||
|
||||
inline hb_blob_t *reference_table (hb_tag_t tag) const
|
||||
{
|
||||
hb_blob_t *blob;
|
||||
|
@ -97,8 +95,7 @@ struct hb_face_t {
|
|||
HB_INTERNAL void load_upem (void) const;
|
||||
HB_INTERNAL void load_num_glyphs (void) const;
|
||||
};
|
||||
|
||||
extern HB_INTERNAL const hb_face_t _hb_face_nil;
|
||||
DECLARE_NULL_INSTANCE (hb_face_t);
|
||||
|
||||
#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
|
||||
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, face);
|
||||
|
|
|
@ -31,9 +31,6 @@
|
|||
#include "hb-face-private.hh"
|
||||
#include "hb-blob-private.hh"
|
||||
#include "hb-open-file-private.hh"
|
||||
#include "hb-ot-head-table.hh"
|
||||
#include "hb-ot-maxp-table.hh"
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
@ -52,17 +49,22 @@ hb_face_count (hb_blob_t *blob)
|
|||
if (unlikely (!blob))
|
||||
return 0;
|
||||
|
||||
hb_blob_t *sanitized = OT::Sanitizer<OT::OpenTypeFontFile> ().sanitize (blob);
|
||||
/* TODO We shouldn't be sanitizing blob. Port to run sanitizer and return if not sane. */
|
||||
/* Make API signature const after. */
|
||||
hb_blob_t *sanitized = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (hb_blob_reference (blob));
|
||||
const OT::OpenTypeFontFile& ot = *sanitized->as<OT::OpenTypeFontFile> ();
|
||||
unsigned int ret = ot.get_face_count ();
|
||||
hb_blob_destroy (sanitized);
|
||||
|
||||
return ot.get_face_count ();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* hb_face_t
|
||||
*/
|
||||
|
||||
const hb_face_t _hb_face_nil = {
|
||||
DEFINE_NULL_INSTANCE (hb_face_t) =
|
||||
{
|
||||
HB_OBJECT_HEADER_STATIC,
|
||||
|
||||
true, /* immutable */
|
||||
|
@ -188,7 +190,7 @@ 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 (OT::Sanitizer<OT::OpenTypeFontFile>().sanitize (hb_blob_reference (blob)), index);
|
||||
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);
|
||||
|
||||
if (unlikely (!closure))
|
||||
return hb_face_get_empty ();
|
||||
|
@ -214,7 +216,7 @@ hb_face_create (hb_blob_t *blob,
|
|||
hb_face_t *
|
||||
hb_face_get_empty (void)
|
||||
{
|
||||
return const_cast<hb_face_t *> (&_hb_face_nil);
|
||||
return const_cast<hb_face_t *> (&Null(hb_face_t));
|
||||
}
|
||||
|
||||
|
||||
|
@ -301,7 +303,7 @@ hb_face_set_user_data (hb_face_t *face,
|
|||
* Since: 0.9.2
|
||||
**/
|
||||
void *
|
||||
hb_face_get_user_data (hb_face_t *face,
|
||||
hb_face_get_user_data (const hb_face_t *face,
|
||||
hb_user_data_key_t *key)
|
||||
{
|
||||
return hb_object_get_user_data (face, key);
|
||||
|
@ -335,7 +337,7 @@ hb_face_make_immutable (hb_face_t *face)
|
|||
* Since: 0.9.2
|
||||
**/
|
||||
hb_bool_t
|
||||
hb_face_is_immutable (hb_face_t *face)
|
||||
hb_face_is_immutable (const hb_face_t *face)
|
||||
{
|
||||
return face->immutable;
|
||||
}
|
||||
|
@ -353,8 +355,8 @@ hb_face_is_immutable (hb_face_t *face)
|
|||
* Since: 0.9.2
|
||||
**/
|
||||
hb_blob_t *
|
||||
hb_face_reference_table (hb_face_t *face,
|
||||
hb_tag_t tag)
|
||||
hb_face_reference_table (const hb_face_t *face,
|
||||
hb_tag_t tag)
|
||||
{
|
||||
return face->reference_table (tag);
|
||||
}
|
||||
|
@ -405,7 +407,7 @@ hb_face_set_index (hb_face_t *face,
|
|||
* Since: 0.9.2
|
||||
**/
|
||||
unsigned int
|
||||
hb_face_get_index (hb_face_t *face)
|
||||
hb_face_get_index (const hb_face_t *face)
|
||||
{
|
||||
return face->index;
|
||||
}
|
||||
|
@ -440,20 +442,11 @@ hb_face_set_upem (hb_face_t *face,
|
|||
* Since: 0.9.2
|
||||
**/
|
||||
unsigned int
|
||||
hb_face_get_upem (hb_face_t *face)
|
||||
hb_face_get_upem (const hb_face_t *face)
|
||||
{
|
||||
return face->get_upem ();
|
||||
}
|
||||
|
||||
void
|
||||
hb_face_t::load_upem (void) const
|
||||
{
|
||||
hb_blob_t *head_blob = OT::Sanitizer<OT::head>().sanitize (reference_table (HB_OT_TAG_head));
|
||||
const OT::head *head_table = head_blob->as<OT::head> ();
|
||||
upem = head_table->get_upem ();
|
||||
hb_blob_destroy (head_blob);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_face_set_glyph_count:
|
||||
* @face: a face.
|
||||
|
@ -484,20 +477,11 @@ hb_face_set_glyph_count (hb_face_t *face,
|
|||
* Since: 0.9.7
|
||||
**/
|
||||
unsigned int
|
||||
hb_face_get_glyph_count (hb_face_t *face)
|
||||
hb_face_get_glyph_count (const hb_face_t *face)
|
||||
{
|
||||
return face->get_num_glyphs ();
|
||||
}
|
||||
|
||||
void
|
||||
hb_face_t::load_num_glyphs (void) const
|
||||
{
|
||||
hb_blob_t *maxp_blob = OT::Sanitizer<OT::maxp>().sanitize (reference_table (HB_OT_TAG_maxp));
|
||||
const OT::maxp *maxp_table = maxp_blob->as<OT::maxp> ();
|
||||
num_glyphs = maxp_table->get_num_glyphs ();
|
||||
hb_blob_destroy (maxp_blob);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_face_get_table_tags:
|
||||
* @face: a face.
|
||||
|
@ -509,7 +493,7 @@ hb_face_t::load_num_glyphs (void) const
|
|||
* Since: 1.6.0
|
||||
**/
|
||||
unsigned int
|
||||
hb_face_get_table_tags (hb_face_t *face,
|
||||
hb_face_get_table_tags (const hb_face_t *face,
|
||||
unsigned int start_offset,
|
||||
unsigned int *table_count, /* IN/OUT */
|
||||
hb_tag_t *table_tags /* OUT */)
|
||||
|
|
|
@ -76,19 +76,19 @@ hb_face_set_user_data (hb_face_t *face,
|
|||
hb_bool_t replace);
|
||||
|
||||
HB_EXTERN void *
|
||||
hb_face_get_user_data (hb_face_t *face,
|
||||
hb_face_get_user_data (const hb_face_t *face,
|
||||
hb_user_data_key_t *key);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_face_make_immutable (hb_face_t *face);
|
||||
|
||||
HB_EXTERN hb_bool_t
|
||||
hb_face_is_immutable (hb_face_t *face);
|
||||
hb_face_is_immutable (const hb_face_t *face);
|
||||
|
||||
|
||||
HB_EXTERN hb_blob_t *
|
||||
hb_face_reference_table (hb_face_t *face,
|
||||
hb_tag_t tag);
|
||||
hb_face_reference_table (const hb_face_t *face,
|
||||
hb_tag_t tag);
|
||||
|
||||
HB_EXTERN hb_blob_t *
|
||||
hb_face_reference_blob (hb_face_t *face);
|
||||
|
@ -98,24 +98,24 @@ hb_face_set_index (hb_face_t *face,
|
|||
unsigned int index);
|
||||
|
||||
HB_EXTERN unsigned int
|
||||
hb_face_get_index (hb_face_t *face);
|
||||
hb_face_get_index (const hb_face_t *face);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_face_set_upem (hb_face_t *face,
|
||||
unsigned int upem);
|
||||
|
||||
HB_EXTERN unsigned int
|
||||
hb_face_get_upem (hb_face_t *face);
|
||||
hb_face_get_upem (const hb_face_t *face);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_face_set_glyph_count (hb_face_t *face,
|
||||
unsigned int glyph_count);
|
||||
|
||||
HB_EXTERN unsigned int
|
||||
hb_face_get_glyph_count (hb_face_t *face);
|
||||
hb_face_get_glyph_count (const hb_face_t *face);
|
||||
|
||||
HB_EXTERN unsigned int
|
||||
hb_face_get_table_tags (hb_face_t *face,
|
||||
hb_face_get_table_tags (const hb_face_t *face,
|
||||
unsigned int start_offset,
|
||||
unsigned int *table_count, /* IN/OUT */
|
||||
hb_tag_t *table_tags /* OUT */);
|
||||
|
|
|
@ -36,16 +36,16 @@ HB_SHAPER_DATA_ENSURE_DEFINE(fallback, font)
|
|||
* shaper face data
|
||||
*/
|
||||
|
||||
struct hb_fallback_shaper_face_data_t {};
|
||||
struct hb_fallback_face_data_t {};
|
||||
|
||||
hb_fallback_shaper_face_data_t *
|
||||
hb_fallback_face_data_t *
|
||||
_hb_fallback_shaper_face_data_create (hb_face_t *face HB_UNUSED)
|
||||
{
|
||||
return (hb_fallback_shaper_face_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
return (hb_fallback_face_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_fallback_shaper_face_data_destroy (hb_fallback_shaper_face_data_t *data HB_UNUSED)
|
||||
_hb_fallback_shaper_face_data_destroy (hb_fallback_face_data_t *data HB_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -54,16 +54,16 @@ _hb_fallback_shaper_face_data_destroy (hb_fallback_shaper_face_data_t *data HB_U
|
|||
* shaper font data
|
||||
*/
|
||||
|
||||
struct hb_fallback_shaper_font_data_t {};
|
||||
struct hb_fallback_font_data_t {};
|
||||
|
||||
hb_fallback_shaper_font_data_t *
|
||||
hb_fallback_font_data_t *
|
||||
_hb_fallback_shaper_font_data_create (hb_font_t *font HB_UNUSED)
|
||||
{
|
||||
return (hb_fallback_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
return (hb_fallback_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_fallback_shaper_font_data_destroy (hb_fallback_shaper_font_data_t *data HB_UNUSED)
|
||||
_hb_fallback_shaper_font_data_destroy (hb_fallback_font_data_t *data HB_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -72,20 +72,20 @@ _hb_fallback_shaper_font_data_destroy (hb_fallback_shaper_font_data_t *data HB_U
|
|||
* shaper shape_plan data
|
||||
*/
|
||||
|
||||
struct hb_fallback_shaper_shape_plan_data_t {};
|
||||
struct hb_fallback_shape_plan_data_t {};
|
||||
|
||||
hb_fallback_shaper_shape_plan_data_t *
|
||||
hb_fallback_shape_plan_data_t *
|
||||
_hb_fallback_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
|
||||
const hb_feature_t *user_features HB_UNUSED,
|
||||
unsigned int num_user_features HB_UNUSED,
|
||||
const int *coords HB_UNUSED,
|
||||
unsigned int num_coords HB_UNUSED)
|
||||
{
|
||||
return (hb_fallback_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
return (hb_fallback_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_fallback_shaper_shape_plan_data_destroy (hb_fallback_shaper_shape_plan_data_t *data HB_UNUSED)
|
||||
_hb_fallback_shaper_shape_plan_data_destroy (hb_fallback_shape_plan_data_t *data HB_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
#include "hb-shaper-private.hh"
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* hb_font_funcs_t
|
||||
*/
|
||||
|
@ -47,6 +46,8 @@
|
|||
HB_FONT_FUNC_IMPLEMENT (variation_glyph) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_h_advance) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_v_advance) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_h_advances) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_v_advances) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_h_origin) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_v_origin) \
|
||||
HB_FONT_FUNC_IMPLEMENT (glyph_h_kerning) \
|
||||
|
@ -57,7 +58,8 @@
|
|||
HB_FONT_FUNC_IMPLEMENT (glyph_from_name) \
|
||||
/* ^--- Add new callbacks here */
|
||||
|
||||
struct hb_font_funcs_t {
|
||||
struct hb_font_funcs_t
|
||||
{
|
||||
hb_object_header_t header;
|
||||
ASSERT_POD ();
|
||||
|
||||
|
@ -89,14 +91,15 @@ struct hb_font_funcs_t {
|
|||
]) (void);
|
||||
} get;
|
||||
};
|
||||
|
||||
DECLARE_NULL_INSTANCE (hb_font_funcs_t);
|
||||
|
||||
|
||||
/*
|
||||
* hb_font_t
|
||||
*/
|
||||
|
||||
struct hb_font_t {
|
||||
struct hb_font_t
|
||||
{
|
||||
hb_object_header_t header;
|
||||
ASSERT_POD ();
|
||||
|
||||
|
@ -233,6 +236,32 @@ struct hb_font_t {
|
|||
klass->user_data.glyph_v_advance);
|
||||
}
|
||||
|
||||
inline void get_glyph_h_advances (unsigned int count,
|
||||
hb_codepoint_t *first_glyph,
|
||||
unsigned int glyph_stride,
|
||||
hb_position_t *first_advance,
|
||||
unsigned int advance_stride)
|
||||
{
|
||||
return klass->get.f.glyph_h_advances (this, user_data,
|
||||
count,
|
||||
first_glyph, glyph_stride,
|
||||
first_advance, advance_stride,
|
||||
klass->user_data.glyph_h_advances);
|
||||
}
|
||||
|
||||
inline void get_glyph_v_advances (unsigned int count,
|
||||
hb_codepoint_t *first_glyph,
|
||||
unsigned int glyph_stride,
|
||||
hb_position_t *first_advance,
|
||||
unsigned int advance_stride)
|
||||
{
|
||||
return klass->get.f.glyph_v_advances (this, user_data,
|
||||
count,
|
||||
first_glyph, glyph_stride,
|
||||
first_advance, advance_stride,
|
||||
klass->user_data.glyph_v_advances);
|
||||
}
|
||||
|
||||
inline hb_bool_t get_glyph_h_origin (hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
{
|
||||
|
@ -341,13 +370,23 @@ struct hb_font_t {
|
|||
hb_direction_t direction,
|
||||
hb_position_t *x, hb_position_t *y)
|
||||
{
|
||||
if (likely (HB_DIRECTION_IS_HORIZONTAL (direction))) {
|
||||
*x = *y = 0;
|
||||
if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
|
||||
*x = get_glyph_h_advance (glyph);
|
||||
*y = 0;
|
||||
} else {
|
||||
*x = 0;
|
||||
else
|
||||
*y = get_glyph_v_advance (glyph);
|
||||
}
|
||||
}
|
||||
inline void get_glyph_advances_for_direction (hb_direction_t direction,
|
||||
unsigned count,
|
||||
hb_codepoint_t *first_glyph,
|
||||
unsigned glyph_stride,
|
||||
hb_position_t *first_advance,
|
||||
unsigned advance_stride)
|
||||
{
|
||||
if (likely (HB_DIRECTION_IS_HORIZONTAL (direction)))
|
||||
get_glyph_h_advances (count, first_glyph, glyph_stride, first_advance, advance_stride);
|
||||
else
|
||||
get_glyph_v_advances (count, first_glyph, glyph_stride, first_advance, advance_stride);
|
||||
}
|
||||
|
||||
inline void guess_v_origin_minus_h_origin (hb_codepoint_t glyph,
|
||||
|
@ -553,6 +592,7 @@ struct hb_font_t {
|
|||
return (float) v * scale / face->get_upem ();
|
||||
}
|
||||
};
|
||||
DECLARE_NULL_INSTANCE (hb_font_t);
|
||||
|
||||
#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS
|
||||
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_PROTOTYPE(shaper, font);
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "hb-private.hh"
|
||||
|
||||
#include "hb-font-private.hh"
|
||||
#include "hb-machinery-private.hh"
|
||||
|
||||
|
||||
/*
|
||||
|
@ -45,10 +46,10 @@ hb_font_get_font_h_extents_nil (hb_font_t *font HB_UNUSED,
|
|||
return false;
|
||||
}
|
||||
static hb_bool_t
|
||||
hb_font_get_font_h_extents_parent (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_font_extents_t *metrics,
|
||||
void *user_data HB_UNUSED)
|
||||
hb_font_get_font_h_extents_default (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_font_extents_t *metrics,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
hb_bool_t ret = font->parent->get_font_h_extents (metrics);
|
||||
if (ret) {
|
||||
|
@ -69,10 +70,10 @@ hb_font_get_font_v_extents_nil (hb_font_t *font HB_UNUSED,
|
|||
return false;
|
||||
}
|
||||
static hb_bool_t
|
||||
hb_font_get_font_v_extents_parent (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_font_extents_t *metrics,
|
||||
void *user_data HB_UNUSED)
|
||||
hb_font_get_font_v_extents_default (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_font_extents_t *metrics,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
hb_bool_t ret = font->parent->get_font_v_extents (metrics);
|
||||
if (ret) {
|
||||
|
@ -94,11 +95,11 @@ hb_font_get_nominal_glyph_nil (hb_font_t *font HB_UNUSED,
|
|||
return false;
|
||||
}
|
||||
static hb_bool_t
|
||||
hb_font_get_nominal_glyph_parent (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t unicode,
|
||||
hb_codepoint_t *glyph,
|
||||
void *user_data HB_UNUSED)
|
||||
hb_font_get_nominal_glyph_default (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t unicode,
|
||||
hb_codepoint_t *glyph,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
return font->parent->get_nominal_glyph (unicode, glyph);
|
||||
}
|
||||
|
@ -115,12 +116,12 @@ hb_font_get_variation_glyph_nil (hb_font_t *font HB_UNUSED,
|
|||
return false;
|
||||
}
|
||||
static hb_bool_t
|
||||
hb_font_get_variation_glyph_parent (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t unicode,
|
||||
hb_codepoint_t variation_selector,
|
||||
hb_codepoint_t *glyph,
|
||||
void *user_data HB_UNUSED)
|
||||
hb_font_get_variation_glyph_default (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t unicode,
|
||||
hb_codepoint_t variation_selector,
|
||||
hb_codepoint_t *glyph,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
return font->parent->get_variation_glyph (unicode, variation_selector, glyph);
|
||||
}
|
||||
|
@ -129,16 +130,16 @@ hb_font_get_variation_glyph_parent (hb_font_t *font,
|
|||
static hb_position_t
|
||||
hb_font_get_glyph_h_advance_nil (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t glyph,
|
||||
hb_codepoint_t glyph HB_UNUSED,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
return font->x_scale;
|
||||
}
|
||||
static hb_position_t
|
||||
hb_font_get_glyph_h_advance_parent (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t glyph,
|
||||
void *user_data HB_UNUSED)
|
||||
hb_font_get_glyph_h_advance_default (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t glyph,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
return font->parent_scale_x_distance (font->parent->get_glyph_h_advance (glyph));
|
||||
}
|
||||
|
@ -146,21 +147,85 @@ hb_font_get_glyph_h_advance_parent (hb_font_t *font,
|
|||
static hb_position_t
|
||||
hb_font_get_glyph_v_advance_nil (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t glyph,
|
||||
hb_codepoint_t glyph HB_UNUSED,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
/* TODO use font_extents.ascender+descender */
|
||||
return font->y_scale;
|
||||
}
|
||||
static hb_position_t
|
||||
hb_font_get_glyph_v_advance_parent (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t glyph,
|
||||
void *user_data HB_UNUSED)
|
||||
hb_font_get_glyph_v_advance_default (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t glyph,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
return font->parent_scale_y_distance (font->parent->get_glyph_v_advance (glyph));
|
||||
}
|
||||
|
||||
#define hb_font_get_glyph_h_advances_nil hb_font_get_glyph_h_advances_default
|
||||
static void
|
||||
hb_font_get_glyph_h_advances_default (hb_font_t* font,
|
||||
void* font_data HB_UNUSED,
|
||||
unsigned int count,
|
||||
hb_codepoint_t *first_glyph,
|
||||
unsigned int glyph_stride,
|
||||
hb_position_t *first_advance,
|
||||
unsigned int advance_stride,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
if (font->has_glyph_h_advance_func ())
|
||||
{
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
*first_advance = font->get_glyph_h_advance (*first_glyph);
|
||||
first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
|
||||
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
font->parent->get_glyph_h_advances (count,
|
||||
first_glyph, glyph_stride,
|
||||
first_advance, advance_stride);
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
*first_advance = font->parent_scale_x_distance (*first_advance);
|
||||
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
|
||||
}
|
||||
}
|
||||
|
||||
#define hb_font_get_glyph_v_advances_nil hb_font_get_glyph_v_advances_default
|
||||
static void
|
||||
hb_font_get_glyph_v_advances_default (hb_font_t* font,
|
||||
void* font_data HB_UNUSED,
|
||||
unsigned int count,
|
||||
hb_codepoint_t *first_glyph,
|
||||
unsigned int glyph_stride,
|
||||
hb_position_t *first_advance,
|
||||
unsigned int advance_stride,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
if (font->has_glyph_v_advance_func ())
|
||||
{
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
*first_advance = font->get_glyph_v_advance (*first_glyph);
|
||||
first_glyph = &StructAtOffset<hb_codepoint_t> (first_glyph, glyph_stride);
|
||||
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
font->parent->get_glyph_v_advances (count,
|
||||
first_glyph, glyph_stride,
|
||||
first_advance, advance_stride);
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
*first_advance = font->parent_scale_y_distance (*first_advance);
|
||||
first_advance = &StructAtOffset<hb_position_t> (first_advance, advance_stride);
|
||||
}
|
||||
}
|
||||
|
||||
static hb_bool_t
|
||||
hb_font_get_glyph_h_origin_nil (hb_font_t *font HB_UNUSED,
|
||||
void *font_data HB_UNUSED,
|
||||
|
@ -173,12 +238,12 @@ hb_font_get_glyph_h_origin_nil (hb_font_t *font HB_UNUSED,
|
|||
return true;
|
||||
}
|
||||
static hb_bool_t
|
||||
hb_font_get_glyph_h_origin_parent (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t glyph,
|
||||
hb_position_t *x,
|
||||
hb_position_t *y,
|
||||
void *user_data HB_UNUSED)
|
||||
hb_font_get_glyph_h_origin_default (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t glyph,
|
||||
hb_position_t *x,
|
||||
hb_position_t *y,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
hb_bool_t ret = font->parent->get_glyph_h_origin (glyph, x, y);
|
||||
if (ret)
|
||||
|
@ -198,12 +263,12 @@ hb_font_get_glyph_v_origin_nil (hb_font_t *font HB_UNUSED,
|
|||
return false;
|
||||
}
|
||||
static hb_bool_t
|
||||
hb_font_get_glyph_v_origin_parent (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t glyph,
|
||||
hb_position_t *x,
|
||||
hb_position_t *y,
|
||||
void *user_data HB_UNUSED)
|
||||
hb_font_get_glyph_v_origin_default (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t glyph,
|
||||
hb_position_t *x,
|
||||
hb_position_t *y,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
hb_bool_t ret = font->parent->get_glyph_v_origin (glyph, x, y);
|
||||
if (ret)
|
||||
|
@ -221,11 +286,11 @@ hb_font_get_glyph_h_kerning_nil (hb_font_t *font HB_UNUSED,
|
|||
return 0;
|
||||
}
|
||||
static hb_position_t
|
||||
hb_font_get_glyph_h_kerning_parent (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t left_glyph,
|
||||
hb_codepoint_t right_glyph,
|
||||
void *user_data HB_UNUSED)
|
||||
hb_font_get_glyph_h_kerning_default (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t left_glyph,
|
||||
hb_codepoint_t right_glyph,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
return font->parent_scale_x_distance (font->parent->get_glyph_h_kerning (left_glyph, right_glyph));
|
||||
}
|
||||
|
@ -240,11 +305,11 @@ hb_font_get_glyph_v_kerning_nil (hb_font_t *font HB_UNUSED,
|
|||
return 0;
|
||||
}
|
||||
static hb_position_t
|
||||
hb_font_get_glyph_v_kerning_parent (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t top_glyph,
|
||||
hb_codepoint_t bottom_glyph,
|
||||
void *user_data HB_UNUSED)
|
||||
hb_font_get_glyph_v_kerning_default (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t top_glyph,
|
||||
hb_codepoint_t bottom_glyph,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
return font->parent_scale_y_distance (font->parent->get_glyph_v_kerning (top_glyph, bottom_glyph));
|
||||
}
|
||||
|
@ -260,11 +325,11 @@ hb_font_get_glyph_extents_nil (hb_font_t *font HB_UNUSED,
|
|||
return false;
|
||||
}
|
||||
static hb_bool_t
|
||||
hb_font_get_glyph_extents_parent (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t glyph,
|
||||
hb_glyph_extents_t *extents,
|
||||
void *user_data HB_UNUSED)
|
||||
hb_font_get_glyph_extents_default (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t glyph,
|
||||
hb_glyph_extents_t *extents,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
hb_bool_t ret = font->parent->get_glyph_extents (glyph, extents);
|
||||
if (ret) {
|
||||
|
@ -287,13 +352,13 @@ hb_font_get_glyph_contour_point_nil (hb_font_t *font HB_UNUSED,
|
|||
return false;
|
||||
}
|
||||
static hb_bool_t
|
||||
hb_font_get_glyph_contour_point_parent (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t glyph,
|
||||
unsigned int point_index,
|
||||
hb_position_t *x,
|
||||
hb_position_t *y,
|
||||
void *user_data HB_UNUSED)
|
||||
hb_font_get_glyph_contour_point_default (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t glyph,
|
||||
unsigned int point_index,
|
||||
hb_position_t *x,
|
||||
hb_position_t *y,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
hb_bool_t ret = font->parent->get_glyph_contour_point (glyph, point_index, x, y);
|
||||
if (ret)
|
||||
|
@ -312,11 +377,11 @@ hb_font_get_glyph_name_nil (hb_font_t *font HB_UNUSED,
|
|||
return false;
|
||||
}
|
||||
static hb_bool_t
|
||||
hb_font_get_glyph_name_parent (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t glyph,
|
||||
char *name, unsigned int size,
|
||||
void *user_data HB_UNUSED)
|
||||
hb_font_get_glyph_name_default (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
hb_codepoint_t glyph,
|
||||
char *name, unsigned int size,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
return font->parent->get_glyph_name (glyph, name, size);
|
||||
}
|
||||
|
@ -332,16 +397,17 @@ hb_font_get_glyph_from_name_nil (hb_font_t *font HB_UNUSED,
|
|||
return false;
|
||||
}
|
||||
static hb_bool_t
|
||||
hb_font_get_glyph_from_name_parent (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
const char *name, int len, /* -1 means nul-terminated */
|
||||
hb_codepoint_t *glyph,
|
||||
void *user_data HB_UNUSED)
|
||||
hb_font_get_glyph_from_name_default (hb_font_t *font,
|
||||
void *font_data HB_UNUSED,
|
||||
const char *name, int len, /* -1 means nul-terminated */
|
||||
hb_codepoint_t *glyph,
|
||||
void *user_data HB_UNUSED)
|
||||
{
|
||||
return font->parent->get_glyph_from_name (name, len, glyph);
|
||||
}
|
||||
|
||||
static const hb_font_funcs_t _hb_font_funcs_nil = {
|
||||
DEFINE_NULL_INSTANCE (hb_font_funcs_t) =
|
||||
{
|
||||
HB_OBJECT_HEADER_STATIC,
|
||||
|
||||
true, /* immutable */
|
||||
|
@ -364,7 +430,8 @@ static const hb_font_funcs_t _hb_font_funcs_nil = {
|
|||
}
|
||||
}
|
||||
};
|
||||
static const hb_font_funcs_t _hb_font_funcs_parent = {
|
||||
|
||||
static const hb_font_funcs_t _hb_font_funcs_default = {
|
||||
HB_OBJECT_HEADER_STATIC,
|
||||
|
||||
true, /* immutable */
|
||||
|
@ -381,7 +448,7 @@ static const hb_font_funcs_t _hb_font_funcs_parent = {
|
|||
},
|
||||
{
|
||||
{
|
||||
#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_parent,
|
||||
#define HB_FONT_FUNC_IMPLEMENT(name) hb_font_get_##name##_default,
|
||||
HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
|
||||
#undef HB_FONT_FUNC_IMPLEMENT
|
||||
}
|
||||
|
@ -406,7 +473,7 @@ hb_font_funcs_create (void)
|
|||
if (!(ffuncs = hb_object_create<hb_font_funcs_t> ()))
|
||||
return hb_font_funcs_get_empty ();
|
||||
|
||||
ffuncs->get = _hb_font_funcs_parent.get;
|
||||
ffuncs->get = _hb_font_funcs_default.get;
|
||||
|
||||
return ffuncs;
|
||||
}
|
||||
|
@ -423,7 +490,7 @@ hb_font_funcs_create (void)
|
|||
hb_font_funcs_t *
|
||||
hb_font_funcs_get_empty (void)
|
||||
{
|
||||
return const_cast<hb_font_funcs_t *> (&_hb_font_funcs_parent);
|
||||
return const_cast<hb_font_funcs_t *> (&_hb_font_funcs_default);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -562,9 +629,9 @@ hb_font_funcs_set_##name##_func (hb_font_funcs_t *ffuncs, \
|
|||
ffuncs->user_data.name = user_data; \
|
||||
ffuncs->destroy.name = destroy; \
|
||||
} else { \
|
||||
ffuncs->get.f.name = hb_font_get_##name##_parent; \
|
||||
ffuncs->user_data.name = nullptr; \
|
||||
ffuncs->destroy.name = nullptr; \
|
||||
ffuncs->get.f.name = hb_font_get_##name##_default; \
|
||||
ffuncs->user_data.name = nullptr; \
|
||||
ffuncs->destroy.name = nullptr; \
|
||||
} \
|
||||
}
|
||||
|
||||
|
@ -574,9 +641,8 @@ HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
|
|||
bool
|
||||
hb_font_t::has_func (unsigned int i)
|
||||
{
|
||||
if (parent && parent != hb_font_get_empty () && parent->has_func (i))
|
||||
return true;
|
||||
return this->klass->get.array[i] != _hb_font_funcs_parent.get.array[i];
|
||||
return (this->klass->get.array[i] != _hb_font_funcs_default.get.array[i]) ||
|
||||
(parent && parent != &_hb_Null_hb_font_t && parent->has_func (i));
|
||||
}
|
||||
|
||||
/* Public getters */
|
||||
|
@ -717,6 +783,43 @@ hb_font_get_glyph_v_advance (hb_font_t *font,
|
|||
return font->get_glyph_v_advance (glyph);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_font_get_glyph_h_advances:
|
||||
* @font: a font.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 1.8.6
|
||||
**/
|
||||
void
|
||||
hb_font_get_glyph_h_advances (hb_font_t* font,
|
||||
unsigned count,
|
||||
hb_codepoint_t *first_glyph,
|
||||
unsigned glyph_stride,
|
||||
hb_position_t *first_advance,
|
||||
unsigned advance_stride)
|
||||
{
|
||||
font->get_glyph_h_advances (count, first_glyph, glyph_stride, first_advance, advance_stride);
|
||||
}
|
||||
/**
|
||||
* hb_font_get_glyph_v_advances:
|
||||
* @font: a font.
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 1.8.6
|
||||
**/
|
||||
void
|
||||
hb_font_get_glyph_v_advances (hb_font_t* font,
|
||||
unsigned count,
|
||||
hb_codepoint_t *first_glyph,
|
||||
unsigned glyph_stride,
|
||||
hb_position_t *first_advance,
|
||||
unsigned advance_stride)
|
||||
{
|
||||
font->get_glyph_v_advances (count, first_glyph, glyph_stride, first_advance, advance_stride);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_font_get_glyph_h_origin:
|
||||
* @font: a font.
|
||||
|
@ -921,6 +1024,26 @@ hb_font_get_glyph_advance_for_direction (hb_font_t *font,
|
|||
{
|
||||
return font->get_glyph_advance_for_direction (glyph, direction, x, y);
|
||||
}
|
||||
/**
|
||||
* hb_font_get_glyph_advances_for_direction:
|
||||
* @font: a font.
|
||||
* @direction:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 1.8.6
|
||||
**/
|
||||
HB_EXTERN void
|
||||
hb_font_get_glyph_advances_for_direction (hb_font_t* font,
|
||||
hb_direction_t direction,
|
||||
unsigned count,
|
||||
hb_codepoint_t *first_glyph,
|
||||
unsigned glyph_stride,
|
||||
hb_position_t *first_advance,
|
||||
unsigned advance_stride)
|
||||
{
|
||||
font->get_glyph_advances_for_direction (direction, count, first_glyph, glyph_stride, first_advance, advance_stride);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_font_get_glyph_origin_for_direction:
|
||||
|
@ -1100,6 +1223,37 @@ hb_font_glyph_from_string (hb_font_t *font,
|
|||
* hb_font_t
|
||||
*/
|
||||
|
||||
DEFINE_NULL_INSTANCE (hb_font_t) =
|
||||
{
|
||||
HB_OBJECT_HEADER_STATIC,
|
||||
|
||||
true, /* immutable */
|
||||
|
||||
nullptr, /* parent */
|
||||
const_cast<hb_face_t *> (&_hb_Null_hb_face_t),
|
||||
|
||||
1000, /* x_scale */
|
||||
1000, /* y_scale */
|
||||
|
||||
0, /* x_ppem */
|
||||
0, /* y_ppem */
|
||||
0, /* ptem */
|
||||
|
||||
0, /* num_coords */
|
||||
nullptr, /* coords */
|
||||
|
||||
const_cast<hb_font_funcs_t *> (&_hb_Null_hb_font_funcs_t), /* klass */
|
||||
nullptr, /* user_data */
|
||||
nullptr, /* destroy */
|
||||
|
||||
{
|
||||
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
|
||||
#include "hb-shaper-list.hh"
|
||||
#undef HB_SHAPER_IMPLEMENT
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* hb_font_create: (Xconstructor)
|
||||
* @face: a face.
|
||||
|
@ -1187,36 +1341,7 @@ hb_font_create_sub_font (hb_font_t *parent)
|
|||
hb_font_t *
|
||||
hb_font_get_empty (void)
|
||||
{
|
||||
static const hb_font_t _hb_font_nil = {
|
||||
HB_OBJECT_HEADER_STATIC,
|
||||
|
||||
true, /* immutable */
|
||||
|
||||
nullptr, /* parent */
|
||||
const_cast<hb_face_t *> (&_hb_face_nil),
|
||||
|
||||
1000, /* x_scale */
|
||||
1000, /* y_scale */
|
||||
|
||||
0, /* x_ppem */
|
||||
0, /* y_ppem */
|
||||
0, /* ptem */
|
||||
|
||||
0, /* num_coords */
|
||||
nullptr, /* coords */
|
||||
|
||||
const_cast<hb_font_funcs_t *> (&_hb_font_funcs_nil), /* klass */
|
||||
nullptr, /* user_data */
|
||||
nullptr, /* destroy */
|
||||
|
||||
{
|
||||
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
|
||||
#include "hb-shaper-list.hh"
|
||||
#undef HB_SHAPER_IMPLEMENT
|
||||
}
|
||||
};
|
||||
|
||||
return const_cast<hb_font_t *> (&_hb_font_nil);
|
||||
return const_cast<hb_font_t *> (&Null(hb_font_t));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -132,6 +132,16 @@ typedef hb_position_t (*hb_font_get_glyph_advance_func_t) (hb_font_t *font, void
|
|||
typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_h_advance_func_t;
|
||||
typedef hb_font_get_glyph_advance_func_t hb_font_get_glyph_v_advance_func_t;
|
||||
|
||||
typedef void (*hb_font_get_glyph_advances_func_t) (hb_font_t* font, void* font_data,
|
||||
unsigned count,
|
||||
hb_codepoint_t *first_glyph,
|
||||
unsigned glyph_stride,
|
||||
hb_position_t *first_advance,
|
||||
unsigned advance_stride,
|
||||
void *user_data);
|
||||
typedef hb_font_get_glyph_advances_func_t hb_font_get_glyph_h_advances_func_t;
|
||||
typedef hb_font_get_glyph_advances_func_t hb_font_get_glyph_v_advances_func_t;
|
||||
|
||||
typedef hb_bool_t (*hb_font_get_glyph_origin_func_t) (hb_font_t *font, void *font_data,
|
||||
hb_codepoint_t glyph,
|
||||
hb_position_t *x, hb_position_t *y,
|
||||
|
@ -264,6 +274,38 @@ hb_font_funcs_set_glyph_v_advance_func (hb_font_funcs_t *ffuncs,
|
|||
hb_font_get_glyph_v_advance_func_t func,
|
||||
void *user_data, hb_destroy_func_t destroy);
|
||||
|
||||
/**
|
||||
* hb_font_funcs_set_glyph_h_advances_func:
|
||||
* @ffuncs: font functions.
|
||||
* @func: (closure user_data) (destroy destroy) (scope notified):
|
||||
* @user_data:
|
||||
* @destroy:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 1.8.6
|
||||
**/
|
||||
HB_EXTERN void
|
||||
hb_font_funcs_set_glyph_h_advances_func (hb_font_funcs_t *ffuncs,
|
||||
hb_font_get_glyph_h_advances_func_t func,
|
||||
void *user_data, hb_destroy_func_t destroy);
|
||||
|
||||
/**
|
||||
* hb_font_funcs_set_glyph_v_advances_func:
|
||||
* @ffuncs: font functions.
|
||||
* @func: (closure user_data) (destroy destroy) (scope notified):
|
||||
* @user_data:
|
||||
* @destroy:
|
||||
*
|
||||
*
|
||||
*
|
||||
* Since: 1.8.6
|
||||
**/
|
||||
HB_EXTERN void
|
||||
hb_font_funcs_set_glyph_v_advances_func (hb_font_funcs_t *ffuncs,
|
||||
hb_font_get_glyph_v_advances_func_t func,
|
||||
void *user_data, hb_destroy_func_t destroy);
|
||||
|
||||
/**
|
||||
* hb_font_funcs_set_glyph_h_origin_func:
|
||||
* @ffuncs: font functions.
|
||||
|
@ -417,6 +459,21 @@ HB_EXTERN hb_position_t
|
|||
hb_font_get_glyph_v_advance (hb_font_t *font,
|
||||
hb_codepoint_t glyph);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_font_get_glyph_h_advances (hb_font_t* font,
|
||||
unsigned count,
|
||||
hb_codepoint_t *first_glyph,
|
||||
unsigned glyph_stride,
|
||||
hb_position_t *first_advance,
|
||||
unsigned advance_stride);
|
||||
HB_EXTERN void
|
||||
hb_font_get_glyph_v_advances (hb_font_t* font,
|
||||
unsigned count,
|
||||
hb_codepoint_t *first_glyph,
|
||||
unsigned glyph_stride,
|
||||
hb_position_t *first_advance,
|
||||
unsigned advance_stride);
|
||||
|
||||
HB_EXTERN hb_bool_t
|
||||
hb_font_get_glyph_h_origin (hb_font_t *font,
|
||||
hb_codepoint_t glyph,
|
||||
|
@ -472,6 +529,14 @@ hb_font_get_glyph_advance_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_advances_for_direction (hb_font_t* font,
|
||||
hb_direction_t direction,
|
||||
unsigned count,
|
||||
hb_codepoint_t *first_glyph,
|
||||
unsigned glyph_stride,
|
||||
hb_position_t *first_advance,
|
||||
unsigned advance_stride);
|
||||
HB_EXTERN void
|
||||
hb_font_get_glyph_origin_for_direction (hb_font_t *font,
|
||||
hb_codepoint_t glyph,
|
||||
hb_direction_t direction,
|
||||
|
|
|
@ -497,7 +497,10 @@ reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
|
|||
|
||||
error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
|
||||
if (error)
|
||||
{
|
||||
free (buffer);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return hb_blob_create ((const char *) buffer, length,
|
||||
HB_MEMORY_MODE_WRITABLE,
|
||||
|
|
|
@ -71,6 +71,7 @@ HB_DEFINE_OBJECT_TYPE (face)
|
|||
HB_DEFINE_OBJECT_TYPE (font)
|
||||
HB_DEFINE_OBJECT_TYPE (font_funcs)
|
||||
HB_DEFINE_OBJECT_TYPE (set)
|
||||
HB_DEFINE_OBJECT_TYPE (map)
|
||||
HB_DEFINE_OBJECT_TYPE (shape_plan)
|
||||
HB_DEFINE_OBJECT_TYPE (unicode_funcs)
|
||||
HB_DEFINE_VALUE_TYPE (feature)
|
||||
|
|
|
@ -89,6 +89,10 @@ HB_EXTERN GType
|
|||
hb_gobject_set_get_type (void);
|
||||
#define HB_GOBJECT_TYPE_SET (hb_gobject_set_get_type ())
|
||||
|
||||
HB_EXTERN GType
|
||||
hb_gobject_map_get_type (void);
|
||||
#define HB_GOBJECT_TYPE_MAP (hb_gobject_map_get_type ())
|
||||
|
||||
HB_EXTERN GType
|
||||
hb_gobject_shape_plan_get_type (void);
|
||||
#define HB_GOBJECT_TYPE_SHAPE_PLAN (hb_gobject_shape_plan_get_type ())
|
||||
|
|
|
@ -48,7 +48,7 @@ typedef struct hb_graphite2_tablelist_t {
|
|||
unsigned int tag;
|
||||
} hb_graphite2_tablelist_t;
|
||||
|
||||
struct hb_graphite2_shaper_face_data_t {
|
||||
struct hb_graphite2_face_data_t {
|
||||
hb_face_t *face;
|
||||
gr_face *grface;
|
||||
hb_graphite2_tablelist_t *tlist;
|
||||
|
@ -56,7 +56,7 @@ struct hb_graphite2_shaper_face_data_t {
|
|||
|
||||
static const void *hb_graphite2_get_table (const void *data, unsigned int tag, size_t *len)
|
||||
{
|
||||
hb_graphite2_shaper_face_data_t *face_data = (hb_graphite2_shaper_face_data_t *) data;
|
||||
hb_graphite2_face_data_t *face_data = (hb_graphite2_face_data_t *) data;
|
||||
hb_graphite2_tablelist_t *tlist = face_data->tlist;
|
||||
|
||||
hb_blob_t *blob = nullptr;
|
||||
|
@ -93,7 +93,7 @@ retry:
|
|||
return d;
|
||||
}
|
||||
|
||||
hb_graphite2_shaper_face_data_t *
|
||||
hb_graphite2_face_data_t *
|
||||
_hb_graphite2_shaper_face_data_create (hb_face_t *face)
|
||||
{
|
||||
hb_blob_t *silf_blob = face->reference_table (HB_GRAPHITE2_TAG_SILF);
|
||||
|
@ -106,7 +106,7 @@ _hb_graphite2_shaper_face_data_create (hb_face_t *face)
|
|||
}
|
||||
hb_blob_destroy (silf_blob);
|
||||
|
||||
hb_graphite2_shaper_face_data_t *data = (hb_graphite2_shaper_face_data_t *) calloc (1, sizeof (hb_graphite2_shaper_face_data_t));
|
||||
hb_graphite2_face_data_t *data = (hb_graphite2_face_data_t *) calloc (1, sizeof (hb_graphite2_face_data_t));
|
||||
if (unlikely (!data))
|
||||
return nullptr;
|
||||
|
||||
|
@ -122,7 +122,7 @@ _hb_graphite2_shaper_face_data_create (hb_face_t *face)
|
|||
}
|
||||
|
||||
void
|
||||
_hb_graphite2_shaper_face_data_destroy (hb_graphite2_shaper_face_data_t *data)
|
||||
_hb_graphite2_shaper_face_data_destroy (hb_graphite2_face_data_t *data)
|
||||
{
|
||||
hb_graphite2_tablelist_t *tlist = data->tlist;
|
||||
|
||||
|
@ -154,16 +154,16 @@ hb_graphite2_face_get_gr_face (hb_face_t *face)
|
|||
* shaper font data
|
||||
*/
|
||||
|
||||
struct hb_graphite2_shaper_font_data_t {};
|
||||
struct hb_graphite2_font_data_t {};
|
||||
|
||||
hb_graphite2_shaper_font_data_t *
|
||||
hb_graphite2_font_data_t *
|
||||
_hb_graphite2_shaper_font_data_create (hb_font_t *font HB_UNUSED)
|
||||
{
|
||||
return (hb_graphite2_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
return (hb_graphite2_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_graphite2_shaper_font_data_destroy (hb_graphite2_shaper_font_data_t *data HB_UNUSED)
|
||||
_hb_graphite2_shaper_font_data_destroy (hb_graphite2_font_data_t *data HB_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -181,20 +181,20 @@ hb_graphite2_font_get_gr_font (hb_font_t *font)
|
|||
* shaper shape_plan data
|
||||
*/
|
||||
|
||||
struct hb_graphite2_shaper_shape_plan_data_t {};
|
||||
struct hb_graphite2_shape_plan_data_t {};
|
||||
|
||||
hb_graphite2_shaper_shape_plan_data_t *
|
||||
hb_graphite2_shape_plan_data_t *
|
||||
_hb_graphite2_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
|
||||
const hb_feature_t *user_features HB_UNUSED,
|
||||
unsigned int num_user_features HB_UNUSED,
|
||||
const int *coords HB_UNUSED,
|
||||
unsigned int num_coords HB_UNUSED)
|
||||
{
|
||||
return (hb_graphite2_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
return (hb_graphite2_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_graphite2_shaper_shape_plan_data_destroy (hb_graphite2_shaper_shape_plan_data_t *data HB_UNUSED)
|
||||
_hb_graphite2_shaper_shape_plan_data_destroy (hb_graphite2_shape_plan_data_t *data HB_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
/*
|
||||
* 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_ITER_PRIVATE_HH
|
||||
#define HB_ITER_PRIVATE_HH
|
||||
|
||||
#include "hb-private.hh"
|
||||
|
||||
|
||||
/* Unified iterator object.
|
||||
*
|
||||
* The goal of this template is to make the same iterator interface
|
||||
* available to all types, and make it very easy and compact to use.
|
||||
* Iterator objects are small, light-weight, objects that can be
|
||||
* copied by value. If the collection / object being iterated on
|
||||
* is writable, then the iterator points to lvalues, otherwise it
|
||||
* returns rvalues.
|
||||
*
|
||||
* The way to declare, initialize, and use iterators, eg.:
|
||||
*
|
||||
* Iter<const int *> s (src);
|
||||
* Iter<int *> t (dst);
|
||||
* for (; s && t; s++, t++)
|
||||
* *s = *t;
|
||||
*/
|
||||
|
||||
template <typename T>
|
||||
struct Iter;
|
||||
|
||||
#if 0
|
||||
template <typename T>
|
||||
struct Iter
|
||||
{
|
||||
explicit inline Iter (const T &c);
|
||||
};
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
struct Iter<T *>
|
||||
{
|
||||
/* Type of items. */
|
||||
typedef T Value;
|
||||
|
||||
/* Constructors. */
|
||||
inline Iter (T *array_, int length_) :
|
||||
array (array_), length (MAX (length_, 0)) {}
|
||||
template <unsigned int length_>
|
||||
explicit inline Iter (T (&array_)[length_]) :
|
||||
array (array_), length (length_) {}
|
||||
|
||||
/* Emptiness. */
|
||||
explicit inline operator bool (void) const { return bool (length); }
|
||||
|
||||
/* Current item. */
|
||||
inline T &operator * (void)
|
||||
{
|
||||
if (unlikely (!length)) return CrapOrNull(T);
|
||||
return *array;
|
||||
}
|
||||
inline T &operator -> (void)
|
||||
{
|
||||
return (operator *);
|
||||
}
|
||||
|
||||
/* Next. */
|
||||
inline Iter<T *> & operator ++ (void)
|
||||
{
|
||||
if (unlikely (!length)) return *this;
|
||||
array++;
|
||||
length--;
|
||||
return *this;
|
||||
}
|
||||
/* Might return void, or a copy of pre-increment iterator. */
|
||||
inline void operator ++ (int)
|
||||
{
|
||||
if (unlikely (!length)) return;
|
||||
array++;
|
||||
length--;
|
||||
}
|
||||
|
||||
/* Some iterators might implement len(). */
|
||||
inline unsigned int len (void) const { return length; }
|
||||
|
||||
/* Some iterators might implement fast-forward.
|
||||
* Only implement it if it's constant-time. */
|
||||
inline void operator += (unsigned int n)
|
||||
{
|
||||
n = MIN (n, length);
|
||||
array += n;
|
||||
length -= n;
|
||||
}
|
||||
|
||||
/* Some iterators might implement random-access.
|
||||
* Only implement it if it's constant-time. */
|
||||
inline Iter<T *> & operator [] (unsigned int i)
|
||||
{
|
||||
if (unlikely (i >= length)) return CrapOrNull(T);
|
||||
return array[i];
|
||||
}
|
||||
|
||||
private:
|
||||
T *array;
|
||||
unsigned int length;
|
||||
};
|
||||
|
||||
/* XXX Remove
|
||||
* Just to test these compile. */
|
||||
static inline void
|
||||
m (void)
|
||||
{
|
||||
const int src[10] = {};
|
||||
int dst[20];
|
||||
|
||||
Iter<const int *> s (src);
|
||||
Iter<const int *> s2 (src, 5);
|
||||
Iter<int *> t (dst);
|
||||
|
||||
s2 = s;
|
||||
|
||||
for (; s && t; ++s, ++t)
|
||||
{
|
||||
*t = *s;
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HB_ITER_PRIVATE_HH */
|
|
@ -0,0 +1,720 @@
|
|||
/*
|
||||
* 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_MACHINERY_PRIVATE_HH
|
||||
#define HB_MACHINERY_PRIVATE_HH
|
||||
|
||||
#include "hb-private.hh"
|
||||
#include "hb-blob-private.hh"
|
||||
|
||||
#include "hb-iter-private.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>
|
||||
static inline const Type& StructAtOffset(const void *P, unsigned int offset)
|
||||
{ return * reinterpret_cast<const Type*> ((const char *) P + offset); }
|
||||
template<typename Type>
|
||||
static inline Type& StructAtOffset(void *P, unsigned int offset)
|
||||
{ return * reinterpret_cast<Type*> ((char *) P + offset); }
|
||||
|
||||
/* StructAfter<T>(X) returns the struct T& that is placed after X.
|
||||
* Works with X of variable size also. X must implement get_size() */
|
||||
template<typename Type, typename TObject>
|
||||
static inline const Type& StructAfter(const TObject &X)
|
||||
{ return StructAtOffset<Type>(&X, X.get_size()); }
|
||||
template<typename Type, typename TObject>
|
||||
static inline Type& StructAfter(TObject &X)
|
||||
{ return StructAtOffset<Type>(&X, X.get_size()); }
|
||||
|
||||
|
||||
/*
|
||||
* Size checking
|
||||
*/
|
||||
|
||||
/* Check _assertion in a method environment */
|
||||
#define _DEFINE_INSTANCE_ASSERTION1(_line, _assertion) \
|
||||
inline void _instance_assertion_on_line_##_line (void) const \
|
||||
{ \
|
||||
static_assert ((_assertion), ""); \
|
||||
ASSERT_INSTANCE_POD (*this); /* Make sure it's POD. */ \
|
||||
}
|
||||
# define _DEFINE_INSTANCE_ASSERTION0(_line, _assertion) _DEFINE_INSTANCE_ASSERTION1 (_line, _assertion)
|
||||
# define DEFINE_INSTANCE_ASSERTION(_assertion) _DEFINE_INSTANCE_ASSERTION0 (__LINE__, _assertion)
|
||||
|
||||
/* Check that _code compiles in a method environment */
|
||||
#define _DEFINE_COMPILES_ASSERTION1(_line, _code) \
|
||||
inline void _compiles_assertion_on_line_##_line (void) const \
|
||||
{ _code; }
|
||||
# define _DEFINE_COMPILES_ASSERTION0(_line, _code) _DEFINE_COMPILES_ASSERTION1 (_line, _code)
|
||||
# define DEFINE_COMPILES_ASSERTION(_code) _DEFINE_COMPILES_ASSERTION0 (__LINE__, _code)
|
||||
|
||||
|
||||
#define DEFINE_SIZE_STATIC(size) \
|
||||
DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)); \
|
||||
static const unsigned int static_size = (size); \
|
||||
static const unsigned int min_size = (size); \
|
||||
inline unsigned int get_size (void) const { return (size); }
|
||||
|
||||
#define DEFINE_SIZE_UNION(size, _member) \
|
||||
DEFINE_INSTANCE_ASSERTION (0*sizeof(this->u._member.static_size) + sizeof(this->u._member) == (size)); \
|
||||
static const unsigned int min_size = (size)
|
||||
|
||||
#define DEFINE_SIZE_MIN(size) \
|
||||
DEFINE_INSTANCE_ASSERTION (sizeof (*this) >= (size)); \
|
||||
static const unsigned int min_size = (size)
|
||||
|
||||
#define DEFINE_SIZE_ARRAY(size, array) \
|
||||
DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (array[0])); \
|
||||
DEFINE_COMPILES_ASSERTION ((void) array[0].static_size) \
|
||||
static const unsigned int min_size = (size)
|
||||
|
||||
#define DEFINE_SIZE_ARRAY2(size, array1, array2) \
|
||||
DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (this->array1[0]) + sizeof (this->array2[0])); \
|
||||
DEFINE_COMPILES_ASSERTION ((void) array1[0].static_size; (void) array2[0].static_size) \
|
||||
static const unsigned int min_size = (size)
|
||||
|
||||
|
||||
/*
|
||||
* Dispatch
|
||||
*/
|
||||
|
||||
template <typename Context, typename Return, unsigned int MaxDebugDepth>
|
||||
struct hb_dispatch_context_t
|
||||
{
|
||||
static const unsigned int max_debug_depth = MaxDebugDepth;
|
||||
typedef Return return_t;
|
||||
template <typename T, typename F>
|
||||
inline bool may_dispatch (const T *obj, const F *format) { return true; }
|
||||
static return_t no_dispatch_return_value (void) { return Context::default_return_value (); }
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Sanitize
|
||||
*/
|
||||
|
||||
/* 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
|
||||
|
||||
struct hb_sanitize_context_t :
|
||||
hb_dispatch_context_t<hb_sanitize_context_t, bool, HB_DEBUG_SANITIZE>
|
||||
{
|
||||
inline hb_sanitize_context_t (void) :
|
||||
debug_depth (0),
|
||||
start (nullptr), end (nullptr),
|
||||
writable (false), edit_count (0), max_ops (0),
|
||||
blob (nullptr),
|
||||
num_glyphs (65536),
|
||||
num_glyphs_set (false) {}
|
||||
|
||||
inline const char *get_name (void) { return "SANITIZE"; }
|
||||
template <typename T, typename F>
|
||||
inline bool may_dispatch (const T *obj, const F *format)
|
||||
{ return format->sanitize (this); }
|
||||
template <typename T>
|
||||
inline return_t dispatch (const T &obj) { return obj.sanitize (this); }
|
||||
static return_t default_return_value (void) { return true; }
|
||||
static return_t no_dispatch_return_value (void) { return false; }
|
||||
bool stop_sublookup_iteration (const return_t r) const { return !r; }
|
||||
|
||||
inline void init (hb_blob_t *b)
|
||||
{
|
||||
this->blob = hb_blob_reference (b);
|
||||
this->writable = false;
|
||||
}
|
||||
|
||||
inline void set_num_glyphs (unsigned int num_glyphs_)
|
||||
{
|
||||
num_glyphs = num_glyphs_;
|
||||
num_glyphs_set = true;
|
||||
}
|
||||
inline unsigned int get_num_glyphs (void) { return num_glyphs; }
|
||||
|
||||
inline void start_processing (void)
|
||||
{
|
||||
this->start = this->blob->data;
|
||||
this->end = this->start + this->blob->length;
|
||||
assert (this->start <= this->end); /* Must not overflow. */
|
||||
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));
|
||||
}
|
||||
|
||||
inline void end_processing (void)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
inline bool check_range (const void *base, unsigned int len) const
|
||||
{
|
||||
const char *p = (const char *) base;
|
||||
bool ok = this->max_ops-- > 0 &&
|
||||
this->start <= p &&
|
||||
p <= this->end &&
|
||||
(unsigned int) (this->end - p) >= len;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
inline bool check_array (const void *base, unsigned int record_size, unsigned int len) const
|
||||
{
|
||||
const char *p = (const char *) base;
|
||||
bool overflows = hb_unsigned_mul_overflows (len, record_size);
|
||||
unsigned int array_size = record_size * len;
|
||||
bool ok = !overflows && this->check_range (base, array_size);
|
||||
|
||||
DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
|
||||
"check_array [%p..%p] (%d*%d=%d bytes) in [%p..%p] -> %s",
|
||||
p, p + (record_size * len), record_size, len, (unsigned int) array_size,
|
||||
this->start, this->end,
|
||||
overflows ? "OVERFLOWS" : ok ? "OK" : "OUT-OF-RANGE");
|
||||
|
||||
return likely (ok);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline bool check_struct (const Type *obj) const
|
||||
{
|
||||
return likely (this->check_range (obj, obj->min_size));
|
||||
}
|
||||
|
||||
inline 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>
|
||||
inline bool try_set (const Type *obj, const ValueType &v) {
|
||||
if (this->may_edit (obj, obj->static_size)) {
|
||||
const_cast<Type *> (obj)->set (v);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline 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>
|
||||
inline 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;
|
||||
private:
|
||||
bool writable;
|
||||
unsigned int edit_count;
|
||||
mutable int max_ops;
|
||||
hb_blob_t *blob;
|
||||
unsigned int num_glyphs;
|
||||
bool num_glyphs_set;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Serialize
|
||||
*/
|
||||
|
||||
struct hb_serialize_context_t
|
||||
{
|
||||
inline hb_serialize_context_t (void *start_, unsigned int size)
|
||||
{
|
||||
this->start = (char *) start_;
|
||||
this->end = this->start + size;
|
||||
|
||||
this->ran_out_of_room = false;
|
||||
this->head = this->start;
|
||||
this->debug_depth = 0;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type *start_serialize (void)
|
||||
{
|
||||
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> ();
|
||||
}
|
||||
|
||||
inline void end_serialize (void)
|
||||
{
|
||||
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->ran_out_of_room ? "RAN OUT OF ROOM" : "did not ran out of room");
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type *copy (void)
|
||||
{
|
||||
assert (!this->ran_out_of_room);
|
||||
unsigned int len = this->head - this->start;
|
||||
void *p = malloc (len);
|
||||
if (p)
|
||||
memcpy (p, this->start, len);
|
||||
return reinterpret_cast<Type *> (p);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type *allocate_size (unsigned int size)
|
||||
{
|
||||
if (unlikely (this->ran_out_of_room || this->end - this->head < ptrdiff_t (size))) {
|
||||
this->ran_out_of_room = true;
|
||||
return nullptr;
|
||||
}
|
||||
memset (this->head, 0, size);
|
||||
char *ret = this->head;
|
||||
this->head += size;
|
||||
return reinterpret_cast<Type *> (ret);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type *allocate_min (void)
|
||||
{
|
||||
return this->allocate_size<Type> (Type::min_size);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type *start_embed (void)
|
||||
{
|
||||
Type *ret = reinterpret_cast<Type *> (this->head);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline 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>
|
||||
inline Type *extend_min (Type &obj)
|
||||
{
|
||||
unsigned int size = obj.min_size;
|
||||
assert (this->start <= (char *) &obj && (char *) &obj <= this->head && (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>
|
||||
inline Type *extend (Type &obj)
|
||||
{
|
||||
unsigned int size = obj.get_size ();
|
||||
assert (this->start < (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head);
|
||||
if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return nullptr;
|
||||
return reinterpret_cast<Type *> (&obj);
|
||||
}
|
||||
|
||||
unsigned int debug_depth;
|
||||
char *start, *end, *head;
|
||||
bool ran_out_of_room;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Supplier
|
||||
*/
|
||||
|
||||
template <typename Type>
|
||||
struct Supplier
|
||||
{
|
||||
inline Supplier (const Type *array, unsigned int len_, unsigned int stride_=sizeof(Type))
|
||||
{
|
||||
head = array;
|
||||
len = len_;
|
||||
stride = stride_;
|
||||
}
|
||||
inline const Type operator [] (unsigned int i) const
|
||||
{
|
||||
if (unlikely (i >= len)) return Type ();
|
||||
return * (const Type *) (const void *) ((const char *) head + stride * i);
|
||||
}
|
||||
|
||||
inline Supplier<Type> & operator += (unsigned int count)
|
||||
{
|
||||
if (unlikely (count > len))
|
||||
count = len;
|
||||
len -= count;
|
||||
head = (const Type *) (const void *) ((const char *) head + stride * count);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
inline Supplier (const Supplier<Type> &); /* Disallow copy */
|
||||
inline Supplier<Type>& operator= (const Supplier<Type> &); /* Disallow copy */
|
||||
|
||||
unsigned int len;
|
||||
unsigned int stride;
|
||||
const Type *head;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Big-endian integers.
|
||||
*/
|
||||
|
||||
template <typename Type, int Bytes> struct BEInt;
|
||||
|
||||
template <typename Type>
|
||||
struct BEInt<Type, 1>
|
||||
{
|
||||
public:
|
||||
inline void set (Type V)
|
||||
{
|
||||
v = V;
|
||||
}
|
||||
inline operator Type (void) const
|
||||
{
|
||||
return v;
|
||||
}
|
||||
private: uint8_t v;
|
||||
};
|
||||
template <typename Type>
|
||||
struct BEInt<Type, 2>
|
||||
{
|
||||
public:
|
||||
inline void set (Type V)
|
||||
{
|
||||
v[0] = (V >> 8) & 0xFF;
|
||||
v[1] = (V ) & 0xFF;
|
||||
}
|
||||
inline operator Type (void) const
|
||||
{
|
||||
return (v[0] << 8)
|
||||
+ (v[1] );
|
||||
}
|
||||
private: uint8_t v[2];
|
||||
};
|
||||
template <typename Type>
|
||||
struct BEInt<Type, 3>
|
||||
{
|
||||
public:
|
||||
inline void set (Type V)
|
||||
{
|
||||
v[0] = (V >> 16) & 0xFF;
|
||||
v[1] = (V >> 8) & 0xFF;
|
||||
v[2] = (V ) & 0xFF;
|
||||
}
|
||||
inline operator Type (void) const
|
||||
{
|
||||
return (v[0] << 16)
|
||||
+ (v[1] << 8)
|
||||
+ (v[2] );
|
||||
}
|
||||
private: uint8_t v[3];
|
||||
};
|
||||
template <typename Type>
|
||||
struct BEInt<Type, 4>
|
||||
{
|
||||
public:
|
||||
inline void set (Type V)
|
||||
{
|
||||
v[0] = (V >> 24) & 0xFF;
|
||||
v[1] = (V >> 16) & 0xFF;
|
||||
v[2] = (V >> 8) & 0xFF;
|
||||
v[3] = (V ) & 0xFF;
|
||||
}
|
||||
inline operator Type (void) const
|
||||
{
|
||||
return (v[0] << 24)
|
||||
+ (v[1] << 16)
|
||||
+ (v[2] << 8)
|
||||
+ (v[3] );
|
||||
}
|
||||
private: uint8_t v[4];
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Lazy loaders.
|
||||
*/
|
||||
|
||||
template <unsigned int WheresFace,
|
||||
typename Subclass,
|
||||
typename Returned,
|
||||
typename Stored = Returned>
|
||||
struct hb_lazy_loader_t
|
||||
{
|
||||
static_assert (WheresFace > 0, "");
|
||||
|
||||
/* https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern */
|
||||
inline const Subclass* thiz (void) const { return static_cast<const Subclass *> (this); }
|
||||
inline Subclass* thiz (void) { return static_cast<Subclass *> (this); }
|
||||
|
||||
inline void init0 (void) {} /* Init, when memory is already set to 0. No-op for us. */
|
||||
inline void init (void)
|
||||
{
|
||||
instance = nullptr;
|
||||
}
|
||||
inline void fini (void)
|
||||
{
|
||||
if (instance)
|
||||
thiz ()->destroy (instance);
|
||||
}
|
||||
|
||||
inline const Returned * operator -> (void) const { return thiz ()->get (); }
|
||||
inline const Returned & operator * (void) const { return *thiz ()->get (); }
|
||||
|
||||
inline Stored * get_stored (void) const
|
||||
{
|
||||
retry:
|
||||
Stored *p = (Stored *) hb_atomic_ptr_get (&this->instance);
|
||||
if (unlikely (!p))
|
||||
{
|
||||
hb_face_t *face = *(((hb_face_t **) this) - WheresFace);
|
||||
if (likely (!p))
|
||||
p = thiz ()->create (face);
|
||||
if (unlikely (!p))
|
||||
p = thiz ()->create (nullptr); /* Produce nil object. */
|
||||
assert (p);
|
||||
if (unlikely (!hb_atomic_ptr_cmpexch (const_cast<Stored **>(&this->instance), nullptr, p)))
|
||||
{
|
||||
thiz ()->destroy (p);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
inline void set_stored (Stored *instance_)
|
||||
{
|
||||
/* This *must* be called when there are no other threads accessing.
|
||||
* However, to make TSan, etc, happy, we using cmpexch. */
|
||||
retry:
|
||||
Stored *p = (Stored *) hb_atomic_ptr_get (&this->instance);
|
||||
if (p)
|
||||
{
|
||||
if (unlikely (!hb_atomic_ptr_cmpexch (const_cast<Stored **>(&this->instance), p, instance_)))
|
||||
goto retry;
|
||||
thiz ()->destroy (p);
|
||||
}
|
||||
}
|
||||
|
||||
inline const Returned * get (void) const
|
||||
{
|
||||
return thiz ()->convert (get_stored ());
|
||||
}
|
||||
|
||||
static inline const Returned* convert (const Stored *p)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
private:
|
||||
/* Must only have one pointer. */
|
||||
mutable Stored *instance;
|
||||
};
|
||||
|
||||
/* Specializations. */
|
||||
|
||||
template <unsigned int WheresFace, typename T>
|
||||
struct hb_object_lazy_loader_t : hb_lazy_loader_t<WheresFace, hb_object_lazy_loader_t<WheresFace, T>, T>
|
||||
{
|
||||
static inline T *create (hb_face_t *face)
|
||||
{
|
||||
if (unlikely (!face))
|
||||
return const_cast<T *> (&Null(T));
|
||||
T *p = (T *) calloc (1, sizeof (T));
|
||||
if (unlikely (!p))
|
||||
p = const_cast<T *> (&Null(T));
|
||||
else
|
||||
p->init (face);
|
||||
return p;
|
||||
}
|
||||
static inline void destroy (T *p)
|
||||
{
|
||||
if (p != &Null(T))
|
||||
{
|
||||
p->fini();
|
||||
free (p);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <unsigned int WheresFace, typename T>
|
||||
struct hb_table_lazy_loader_t : hb_lazy_loader_t<WheresFace, hb_table_lazy_loader_t<WheresFace, T>, T, hb_blob_t>
|
||||
{
|
||||
static inline hb_blob_t *create (hb_face_t *face)
|
||||
{
|
||||
if (unlikely (!face))
|
||||
return hb_blob_get_empty ();
|
||||
return hb_sanitize_context_t ().reference_table<T> (face);
|
||||
}
|
||||
static inline void destroy (hb_blob_t *p)
|
||||
{
|
||||
hb_blob_destroy (p);
|
||||
}
|
||||
static inline const T* convert (const hb_blob_t *blob)
|
||||
{
|
||||
return blob->as<T> ();
|
||||
}
|
||||
|
||||
inline hb_blob_t* get_blob (void) const
|
||||
{
|
||||
return this->get_stored ();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif /* HB_MACHINERY_PRIVATE_HH */
|
|
@ -157,8 +157,6 @@ hb_map_allocation_successful (const hb_map_t *map)
|
|||
*
|
||||
*
|
||||
*
|
||||
* Return value:
|
||||
*
|
||||
* Since: 1.7.7
|
||||
**/
|
||||
void
|
||||
|
@ -188,7 +186,7 @@ hb_map_get (const hb_map_t *map,
|
|||
/**
|
||||
* hb_map_del:
|
||||
* @map: a map.
|
||||
* @codepoint:
|
||||
* @key:
|
||||
*
|
||||
*
|
||||
*
|
||||
|
@ -204,7 +202,7 @@ hb_map_del (hb_map_t *map,
|
|||
/**
|
||||
* hb_map_has:
|
||||
* @map: a map.
|
||||
* @codepoint:
|
||||
* @key:
|
||||
*
|
||||
*
|
||||
*
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* 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_NULL_HH
|
||||
#define HB_NULL_HH
|
||||
|
||||
#include "hb-private.hh"
|
||||
|
||||
|
||||
/*
|
||||
* Static pools
|
||||
*/
|
||||
|
||||
/* Global nul-content Null pool. Enlarge as necessary. */
|
||||
|
||||
#define HB_NULL_POOL_SIZE 264
|
||||
|
||||
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)];
|
||||
|
||||
/* Generic nul-content Null objects. */
|
||||
template <typename Type>
|
||||
static inline Type const & Null (void) {
|
||||
static_assert (sizeof (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
|
||||
return *reinterpret_cast<Type const *> (_hb_NullPool);
|
||||
}
|
||||
#define Null(Type) Null<Type>()
|
||||
|
||||
/* Specializaitons for arbitrary-content Null objects expressed in bytes. */
|
||||
#define DECLARE_NULL_NAMESPACE_BYTES(Namespace, Type) \
|
||||
} /* Close namespace. */ \
|
||||
extern HB_INTERNAL const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::min_size]; \
|
||||
template <> \
|
||||
/*static*/ inline const Namespace::Type& Null<Namespace::Type> (void) { \
|
||||
return *reinterpret_cast<const Namespace::Type *> (_hb_Null_##Namespace##_##Type); \
|
||||
} \
|
||||
namespace Namespace { \
|
||||
static_assert (true, "Just so we take semicolon after.")
|
||||
#define DEFINE_NULL_NAMESPACE_BYTES(Namespace, Type) \
|
||||
const unsigned char _hb_Null_##Namespace##_##Type[Namespace::Type::min_size]
|
||||
|
||||
/* Specializaitons for arbitrary-content Null objects expressed as struct initializer. */
|
||||
#define DECLARE_NULL_INSTANCE(Type) \
|
||||
extern HB_INTERNAL const Type _hb_Null_##Type; \
|
||||
template <> \
|
||||
/*static*/ inline const Type& Null<Type> (void) { \
|
||||
return _hb_Null_##Type; \
|
||||
} \
|
||||
static_assert (true, "Just so we take semicolon after.")
|
||||
#define DEFINE_NULL_INSTANCE(Type) \
|
||||
const Type _hb_Null_##Type
|
||||
|
||||
/* Global writable pool. Enlarge as necessary. */
|
||||
|
||||
/* To be fully correct, CrapPool must be thread_local. However, we do not rely on CrapPool
|
||||
* for correct operation. It only exist to catch and divert program logic bugs instead of
|
||||
* 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)];
|
||||
|
||||
/* CRAP pool: Common Region for Access Protection. */
|
||||
template <typename Type>
|
||||
static inline Type& Crap (void) {
|
||||
static_assert (sizeof (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
|
||||
Type *obj = reinterpret_cast<Type *> (_hb_CrapPool);
|
||||
*obj = Null(Type);
|
||||
return *obj;
|
||||
}
|
||||
#define Crap(Type) Crap<Type>()
|
||||
|
||||
template <typename Type>
|
||||
struct CrapOrNull {
|
||||
static inline Type & get (void) { return Crap(Type); }
|
||||
};
|
||||
template <typename Type>
|
||||
struct CrapOrNull<const Type> {
|
||||
static inline Type const & get (void) { return Null(Type); }
|
||||
};
|
||||
#define CrapOrNull(Type) CrapOrNull<Type>::get ()
|
||||
|
||||
|
||||
#endif /* HB_NULL_HH */
|
|
@ -35,9 +35,107 @@
|
|||
#include "hb-private.hh"
|
||||
#include "hb-atomic-private.hh"
|
||||
#include "hb-mutex-private.hh"
|
||||
#include "hb-vector-private.hh"
|
||||
|
||||
|
||||
/* reference_count */
|
||||
/*
|
||||
* Lockable set
|
||||
*/
|
||||
|
||||
template <typename item_t, typename lock_t>
|
||||
struct hb_lockable_set_t
|
||||
{
|
||||
hb_vector_t <item_t, 1> items;
|
||||
|
||||
inline void init (void) { items.init (); }
|
||||
|
||||
template <typename T>
|
||||
inline item_t *replace_or_insert (T v, lock_t &l, bool replace)
|
||||
{
|
||||
l.lock ();
|
||||
item_t *item = items.find (v);
|
||||
if (item) {
|
||||
if (replace) {
|
||||
item_t old = *item;
|
||||
*item = v;
|
||||
l.unlock ();
|
||||
old.fini ();
|
||||
}
|
||||
else {
|
||||
item = nullptr;
|
||||
l.unlock ();
|
||||
}
|
||||
} else {
|
||||
item = items.push (v);
|
||||
l.unlock ();
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void remove (T v, lock_t &l)
|
||||
{
|
||||
l.lock ();
|
||||
item_t *item = items.find (v);
|
||||
if (item) {
|
||||
item_t old = *item;
|
||||
*item = items[items.len - 1];
|
||||
items.pop ();
|
||||
l.unlock ();
|
||||
old.fini ();
|
||||
} else {
|
||||
l.unlock ();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool find (T v, item_t *i, lock_t &l)
|
||||
{
|
||||
l.lock ();
|
||||
item_t *item = items.find (v);
|
||||
if (item)
|
||||
*i = *item;
|
||||
l.unlock ();
|
||||
return !!item;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline item_t *find_or_insert (T v, lock_t &l)
|
||||
{
|
||||
l.lock ();
|
||||
item_t *item = items.find (v);
|
||||
if (!item) {
|
||||
item = items.push (v);
|
||||
}
|
||||
l.unlock ();
|
||||
return item;
|
||||
}
|
||||
|
||||
inline void fini (lock_t &l)
|
||||
{
|
||||
if (!items.len) {
|
||||
/* No need for locking. */
|
||||
items.fini ();
|
||||
return;
|
||||
}
|
||||
l.lock ();
|
||||
while (items.len) {
|
||||
item_t old = items[items.len - 1];
|
||||
items.pop ();
|
||||
l.unlock ();
|
||||
old.fini ();
|
||||
l.lock ();
|
||||
}
|
||||
items.fini ();
|
||||
l.unlock ();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Reference-count.
|
||||
*/
|
||||
|
||||
#define HB_REFERENCE_COUNT_INERT_VALUE 0
|
||||
#define HB_REFERENCE_COUNT_POISON_VALUE -0x0000DEAD
|
||||
|
@ -47,14 +145,14 @@ struct hb_reference_count_t
|
|||
{
|
||||
hb_atomic_int_t ref_count;
|
||||
|
||||
inline void init (int v) { ref_count.set_unsafe (v); }
|
||||
inline int get_unsafe (void) const { return ref_count.get_unsafe (); }
|
||||
inline void init (int v) { ref_count.set_relaxed (v); }
|
||||
inline int get_relaxed (void) const { return ref_count.get_relaxed (); }
|
||||
inline int inc (void) { return ref_count.inc (); }
|
||||
inline int dec (void) { return ref_count.dec (); }
|
||||
inline void fini (void) { ref_count.set_unsafe (HB_REFERENCE_COUNT_POISON_VALUE); }
|
||||
inline void fini (void) { ref_count.set_relaxed (HB_REFERENCE_COUNT_POISON_VALUE); }
|
||||
|
||||
inline bool is_inert (void) const { return ref_count.get_unsafe () == HB_REFERENCE_COUNT_INERT_VALUE; }
|
||||
inline bool is_valid (void) const { return ref_count.get_unsafe () > 0; }
|
||||
inline bool is_inert (void) const { return ref_count.get_relaxed () == HB_REFERENCE_COUNT_INERT_VALUE; }
|
||||
inline bool is_valid (void) const { return ref_count.get_relaxed () > 0; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -89,12 +187,14 @@ struct hb_user_data_array_t
|
|||
};
|
||||
|
||||
|
||||
/* object_header */
|
||||
/*
|
||||
* Object header
|
||||
*/
|
||||
|
||||
struct hb_object_header_t
|
||||
{
|
||||
hb_reference_count_t ref_count;
|
||||
hb_user_data_array_t *user_data;
|
||||
mutable hb_user_data_array_t *user_data;
|
||||
|
||||
#define HB_OBJECT_HEADER_STATIC {HB_REFERENCE_COUNT_INIT, nullptr}
|
||||
|
||||
|
@ -103,7 +203,9 @@ struct hb_object_header_t
|
|||
};
|
||||
|
||||
|
||||
/* object */
|
||||
/*
|
||||
* Object
|
||||
*/
|
||||
|
||||
template <typename Type>
|
||||
static inline void hb_object_trace (const Type *obj, const char *function)
|
||||
|
@ -111,7 +213,7 @@ static inline void hb_object_trace (const Type *obj, const char *function)
|
|||
DEBUG_MSG (OBJECT, (void *) obj,
|
||||
"%s refcount=%d",
|
||||
function,
|
||||
obj ? obj->header.ref_count.get_unsafe () : 0);
|
||||
obj ? obj->header.ref_count.get_relaxed () : 0);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
|
|
|
@ -484,8 +484,6 @@ struct ResourceForkHeader
|
|||
|
||||
struct OpenTypeFontFile
|
||||
{
|
||||
static const hb_tag_t tableTag = HB_TAG ('_','_','_','_'); /* Sanitizer needs this. */
|
||||
|
||||
enum {
|
||||
CFFTag = HB_TAG ('O','T','T','O'), /* OpenType with Postscript outlines */
|
||||
TrueTypeTag = HB_TAG ( 0 , 1 , 0 , 0 ), /* OpenType with TrueType outlines */
|
||||
|
|
|
@ -32,484 +32,12 @@
|
|||
#include "hb-private.hh"
|
||||
#include "hb-blob-private.hh"
|
||||
#include "hb-face-private.hh"
|
||||
#include "hb-machinery-private.hh"
|
||||
|
||||
|
||||
namespace OT {
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* 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>
|
||||
static inline const Type& StructAtOffset(const void *P, unsigned int offset)
|
||||
{ return * reinterpret_cast<const Type*> ((const char *) P + offset); }
|
||||
template<typename Type>
|
||||
static inline Type& StructAtOffset(void *P, unsigned int offset)
|
||||
{ return * reinterpret_cast<Type*> ((char *) P + offset); }
|
||||
|
||||
/* StructAfter<T>(X) returns the struct T& that is placed after X.
|
||||
* Works with X of variable size also. X must implement get_size() */
|
||||
template<typename Type, typename TObject>
|
||||
static inline const Type& StructAfter(const TObject &X)
|
||||
{ return StructAtOffset<Type>(&X, X.get_size()); }
|
||||
template<typename Type, typename TObject>
|
||||
static inline Type& StructAfter(TObject &X)
|
||||
{ return StructAtOffset<Type>(&X, X.get_size()); }
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Size checking
|
||||
*/
|
||||
|
||||
/* Check _assertion in a method environment */
|
||||
#define _DEFINE_INSTANCE_ASSERTION1(_line, _assertion) \
|
||||
inline void _instance_assertion_on_line_##_line (void) const \
|
||||
{ \
|
||||
static_assert ((_assertion), ""); \
|
||||
ASSERT_INSTANCE_POD (*this); /* Make sure it's POD. */ \
|
||||
}
|
||||
# define _DEFINE_INSTANCE_ASSERTION0(_line, _assertion) _DEFINE_INSTANCE_ASSERTION1 (_line, _assertion)
|
||||
# define DEFINE_INSTANCE_ASSERTION(_assertion) _DEFINE_INSTANCE_ASSERTION0 (__LINE__, _assertion)
|
||||
|
||||
/* Check that _code compiles in a method environment */
|
||||
#define _DEFINE_COMPILES_ASSERTION1(_line, _code) \
|
||||
inline void _compiles_assertion_on_line_##_line (void) const \
|
||||
{ _code; }
|
||||
# define _DEFINE_COMPILES_ASSERTION0(_line, _code) _DEFINE_COMPILES_ASSERTION1 (_line, _code)
|
||||
# define DEFINE_COMPILES_ASSERTION(_code) _DEFINE_COMPILES_ASSERTION0 (__LINE__, _code)
|
||||
|
||||
|
||||
#define DEFINE_SIZE_STATIC(size) \
|
||||
DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size)); \
|
||||
static const unsigned int static_size = (size); \
|
||||
static const unsigned int min_size = (size); \
|
||||
inline unsigned int get_size (void) const { return (size); }
|
||||
|
||||
#define DEFINE_SIZE_UNION(size, _member) \
|
||||
DEFINE_INSTANCE_ASSERTION (0*sizeof(this->u._member.static_size) + sizeof(this->u._member) == (size)); \
|
||||
static const unsigned int min_size = (size)
|
||||
|
||||
#define DEFINE_SIZE_MIN(size) \
|
||||
DEFINE_INSTANCE_ASSERTION (sizeof (*this) >= (size)); \
|
||||
static const unsigned int min_size = (size)
|
||||
|
||||
#define DEFINE_SIZE_ARRAY(size, array) \
|
||||
DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (array[0])); \
|
||||
DEFINE_COMPILES_ASSERTION ((void) array[0].static_size) \
|
||||
static const unsigned int min_size = (size)
|
||||
|
||||
#define DEFINE_SIZE_ARRAY2(size, array1, array2) \
|
||||
DEFINE_INSTANCE_ASSERTION (sizeof (*this) == (size) + sizeof (this->array1[0]) + sizeof (this->array2[0])); \
|
||||
DEFINE_COMPILES_ASSERTION ((void) array1[0].static_size; (void) array2[0].static_size) \
|
||||
static const unsigned int min_size = (size)
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Dispatch
|
||||
*/
|
||||
|
||||
template <typename Context, typename Return, unsigned int MaxDebugDepth>
|
||||
struct hb_dispatch_context_t
|
||||
{
|
||||
static const unsigned int max_debug_depth = MaxDebugDepth;
|
||||
typedef Return return_t;
|
||||
template <typename T, typename F>
|
||||
inline bool may_dispatch (const T *obj, const F *format) { return true; }
|
||||
static return_t no_dispatch_return_value (void) { return Context::default_return_value (); }
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Sanitize
|
||||
*/
|
||||
|
||||
/* 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
|
||||
|
||||
struct hb_sanitize_context_t :
|
||||
hb_dispatch_context_t<hb_sanitize_context_t, bool, HB_DEBUG_SANITIZE>
|
||||
{
|
||||
inline hb_sanitize_context_t (void) :
|
||||
debug_depth (0),
|
||||
start (nullptr), end (nullptr),
|
||||
writable (false), edit_count (0), max_ops (0),
|
||||
blob (nullptr),
|
||||
num_glyphs (0) {}
|
||||
|
||||
inline const char *get_name (void) { return "SANITIZE"; }
|
||||
template <typename T, typename F>
|
||||
inline bool may_dispatch (const T *obj, const F *format)
|
||||
{ return format->sanitize (this); }
|
||||
template <typename T>
|
||||
inline return_t dispatch (const T &obj) { return obj.sanitize (this); }
|
||||
static return_t default_return_value (void) { return true; }
|
||||
static return_t no_dispatch_return_value (void) { return false; }
|
||||
bool stop_sublookup_iteration (const return_t r) const { return !r; }
|
||||
|
||||
inline void init (hb_blob_t *b)
|
||||
{
|
||||
this->blob = hb_blob_reference (b);
|
||||
this->writable = false;
|
||||
}
|
||||
|
||||
inline void start_processing (void)
|
||||
{
|
||||
this->start = hb_blob_get_data (this->blob, nullptr);
|
||||
this->end = this->start + this->blob->length;
|
||||
assert (this->start <= this->end); /* Must not overflow. */
|
||||
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));
|
||||
}
|
||||
|
||||
inline void end_processing (void)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
inline bool check_range (const void *base, unsigned int len) const
|
||||
{
|
||||
const char *p = (const char *) base;
|
||||
bool ok = this->max_ops-- > 0 &&
|
||||
this->start <= p &&
|
||||
p <= this->end &&
|
||||
(unsigned int) (this->end - p) >= len;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
inline bool check_array (const void *base, unsigned int record_size, unsigned int len) const
|
||||
{
|
||||
const char *p = (const char *) base;
|
||||
bool overflows = hb_unsigned_mul_overflows (len, record_size);
|
||||
unsigned int array_size = record_size * len;
|
||||
bool ok = !overflows && this->check_range (base, array_size);
|
||||
|
||||
DEBUG_MSG_LEVEL (SANITIZE, p, this->debug_depth+1, 0,
|
||||
"check_array [%p..%p] (%d*%d=%d bytes) in [%p..%p] -> %s",
|
||||
p, p + (record_size * len), record_size, len, (unsigned int) array_size,
|
||||
this->start, this->end,
|
||||
overflows ? "OVERFLOWS" : ok ? "OK" : "OUT-OF-RANGE");
|
||||
|
||||
return likely (ok);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline bool check_struct (const Type *obj) const
|
||||
{
|
||||
return likely (this->check_range (obj, obj->min_size));
|
||||
}
|
||||
|
||||
inline 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>
|
||||
inline bool try_set (const Type *obj, const ValueType &v) {
|
||||
if (this->may_edit (obj, obj->static_size)) {
|
||||
const_cast<Type *> (obj)->set (v);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
mutable unsigned int debug_depth;
|
||||
const char *start, *end;
|
||||
bool writable;
|
||||
unsigned int edit_count;
|
||||
mutable int max_ops;
|
||||
hb_blob_t *blob;
|
||||
unsigned int num_glyphs;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* Template to sanitize an object. */
|
||||
template <typename Type>
|
||||
struct Sanitizer
|
||||
{
|
||||
inline Sanitizer (void) {}
|
||||
|
||||
inline hb_blob_t *sanitize (hb_blob_t *blob) {
|
||||
bool sane;
|
||||
|
||||
/* TODO is_sane() stuff */
|
||||
|
||||
c->init (blob);
|
||||
|
||||
retry:
|
||||
DEBUG_MSG_FUNC (SANITIZE, c->start, "start");
|
||||
|
||||
c->start_processing ();
|
||||
|
||||
if (unlikely (!c->start)) {
|
||||
c->end_processing ();
|
||||
return blob;
|
||||
}
|
||||
|
||||
Type *t = CastP<Type> (const_cast<char *> (c->start));
|
||||
|
||||
sane = t->sanitize (c);
|
||||
if (sane) {
|
||||
if (c->edit_count) {
|
||||
DEBUG_MSG_FUNC (SANITIZE, c->start, "passed first round with %d edits; going for second round", c->edit_count);
|
||||
|
||||
/* sanitize again to ensure no toe-stepping */
|
||||
c->edit_count = 0;
|
||||
sane = t->sanitize (c);
|
||||
if (c->edit_count) {
|
||||
DEBUG_MSG_FUNC (SANITIZE, c->start, "requested %d edits in second round; FAILLING", c->edit_count);
|
||||
sane = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unsigned int edit_count = c->edit_count;
|
||||
if (edit_count && !c->writable) {
|
||||
c->start = hb_blob_get_data_writable (blob, nullptr);
|
||||
c->end = c->start + blob->length;
|
||||
|
||||
if (c->start) {
|
||||
c->writable = true;
|
||||
/* ok, we made it writable by relocating. try again */
|
||||
DEBUG_MSG_FUNC (SANITIZE, c->start, "retry");
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c->end_processing ();
|
||||
|
||||
DEBUG_MSG_FUNC (SANITIZE, c->start, sane ? "PASSED" : "FAILED");
|
||||
if (sane)
|
||||
{
|
||||
blob->lock ();
|
||||
return blob;
|
||||
}
|
||||
else
|
||||
{
|
||||
hb_blob_destroy (blob);
|
||||
return hb_blob_get_empty ();
|
||||
}
|
||||
}
|
||||
|
||||
inline void set_num_glyphs (unsigned int num_glyphs) { c->num_glyphs = num_glyphs; }
|
||||
|
||||
private:
|
||||
hb_sanitize_context_t c[1];
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Serialize
|
||||
*/
|
||||
|
||||
|
||||
struct hb_serialize_context_t
|
||||
{
|
||||
inline hb_serialize_context_t (void *start_, unsigned int size)
|
||||
{
|
||||
this->start = (char *) start_;
|
||||
this->end = this->start + size;
|
||||
|
||||
this->ran_out_of_room = false;
|
||||
this->head = this->start;
|
||||
this->debug_depth = 0;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type *start_serialize (void)
|
||||
{
|
||||
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> ();
|
||||
}
|
||||
|
||||
inline void end_serialize (void)
|
||||
{
|
||||
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->ran_out_of_room ? "RAN OUT OF ROOM" : "did not ran out of room");
|
||||
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type *copy (void)
|
||||
{
|
||||
assert (!this->ran_out_of_room);
|
||||
unsigned int len = this->head - this->start;
|
||||
void *p = malloc (len);
|
||||
if (p)
|
||||
memcpy (p, this->start, len);
|
||||
return reinterpret_cast<Type *> (p);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type *allocate_size (unsigned int size)
|
||||
{
|
||||
if (unlikely (this->ran_out_of_room || this->end - this->head < ptrdiff_t (size))) {
|
||||
this->ran_out_of_room = true;
|
||||
return nullptr;
|
||||
}
|
||||
memset (this->head, 0, size);
|
||||
char *ret = this->head;
|
||||
this->head += size;
|
||||
return reinterpret_cast<Type *> (ret);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type *allocate_min (void)
|
||||
{
|
||||
return this->allocate_size<Type> (Type::min_size);
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline Type *start_embed (void)
|
||||
{
|
||||
Type *ret = reinterpret_cast<Type *> (this->head);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename Type>
|
||||
inline 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>
|
||||
inline Type *extend_min (Type &obj)
|
||||
{
|
||||
unsigned int size = obj.min_size;
|
||||
assert (this->start <= (char *) &obj && (char *) &obj <= this->head && (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>
|
||||
inline Type *extend (Type &obj)
|
||||
{
|
||||
unsigned int size = obj.get_size ();
|
||||
assert (this->start < (char *) &obj && (char *) &obj <= this->head && (char *) &obj + size >= this->head);
|
||||
if (unlikely (!this->allocate_size<Type> (((char *) &obj) + size - this->head))) return nullptr;
|
||||
return reinterpret_cast<Type *> (&obj);
|
||||
}
|
||||
|
||||
inline void truncate (void *new_head)
|
||||
{
|
||||
assert (this->start < new_head && new_head <= this->head);
|
||||
this->head = (char *) new_head;
|
||||
}
|
||||
|
||||
unsigned int debug_depth;
|
||||
char *start, *end, *head;
|
||||
bool ran_out_of_room;
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
struct Supplier
|
||||
{
|
||||
inline Supplier (const Type *array, unsigned int len_, unsigned int stride_=sizeof(Type))
|
||||
{
|
||||
head = array;
|
||||
len = len_;
|
||||
stride = stride_;
|
||||
}
|
||||
inline const Type operator [] (unsigned int i) const
|
||||
{
|
||||
if (unlikely (i >= len)) return Type ();
|
||||
return * (const Type *) (const void *) ((const char *) head + stride * i);
|
||||
}
|
||||
|
||||
inline Supplier<Type> & operator += (unsigned int count)
|
||||
{
|
||||
if (unlikely (count > len))
|
||||
count = len;
|
||||
len -= count;
|
||||
head = (const Type *) (const void *) ((const char *) head + stride * count);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
inline Supplier (const Supplier<Type> &); /* Disallow copy */
|
||||
inline Supplier<Type>& operator= (const Supplier<Type> &); /* Disallow copy */
|
||||
|
||||
unsigned int len;
|
||||
unsigned int stride;
|
||||
const Type *head;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* The OpenType Font File: Data Types
|
||||
|
@ -523,78 +51,6 @@ struct Supplier
|
|||
* Int types
|
||||
*/
|
||||
|
||||
|
||||
template <typename Type, int Bytes> struct BEInt;
|
||||
|
||||
template <typename Type>
|
||||
struct BEInt<Type, 1>
|
||||
{
|
||||
public:
|
||||
inline void set (Type V)
|
||||
{
|
||||
v = V;
|
||||
}
|
||||
inline operator Type (void) const
|
||||
{
|
||||
return v;
|
||||
}
|
||||
private: uint8_t v;
|
||||
};
|
||||
template <typename Type>
|
||||
struct BEInt<Type, 2>
|
||||
{
|
||||
public:
|
||||
inline void set (Type V)
|
||||
{
|
||||
v[0] = (V >> 8) & 0xFF;
|
||||
v[1] = (V ) & 0xFF;
|
||||
}
|
||||
inline operator Type (void) const
|
||||
{
|
||||
return (v[0] << 8)
|
||||
+ (v[1] );
|
||||
}
|
||||
private: uint8_t v[2];
|
||||
};
|
||||
template <typename Type>
|
||||
struct BEInt<Type, 3>
|
||||
{
|
||||
public:
|
||||
inline void set (Type V)
|
||||
{
|
||||
v[0] = (V >> 16) & 0xFF;
|
||||
v[1] = (V >> 8) & 0xFF;
|
||||
v[2] = (V ) & 0xFF;
|
||||
}
|
||||
inline operator Type (void) const
|
||||
{
|
||||
return (v[0] << 16)
|
||||
+ (v[1] << 8)
|
||||
+ (v[2] );
|
||||
}
|
||||
private: uint8_t v[3];
|
||||
};
|
||||
template <typename Type>
|
||||
struct BEInt<Type, 4>
|
||||
{
|
||||
public:
|
||||
inline void set (Type V)
|
||||
{
|
||||
v[0] = (V >> 24) & 0xFF;
|
||||
v[1] = (V >> 16) & 0xFF;
|
||||
v[2] = (V >> 8) & 0xFF;
|
||||
v[3] = (V ) & 0xFF;
|
||||
}
|
||||
inline operator Type (void) const
|
||||
{
|
||||
return (v[0] << 24)
|
||||
+ (v[1] << 16)
|
||||
+ (v[2] << 8)
|
||||
+ (v[3] );
|
||||
}
|
||||
private: uint8_t v[4];
|
||||
};
|
||||
|
||||
/* Integer types in big-endian order and no alignment requirement */
|
||||
template <typename Type, unsigned int Size>
|
||||
struct IntType
|
||||
|
@ -684,7 +140,6 @@ struct Tag : HBUINT32
|
|||
public:
|
||||
DEFINE_SIZE_STATIC (4);
|
||||
};
|
||||
DEFINE_NULL_DATA (OT, Tag, " ");
|
||||
|
||||
/* Glyph index number, same as uint16 (length = 16 bits) */
|
||||
typedef HBUINT16 GlyphID;
|
||||
|
@ -696,7 +151,7 @@ typedef HBUINT16 NameID;
|
|||
struct Index : HBUINT16 {
|
||||
static const unsigned int NOT_FOUND_INDEX = 0xFFFFu;
|
||||
};
|
||||
DEFINE_NULL_DATA (OT, Index, "\xff\xff");
|
||||
DECLARE_NULL_NAMESPACE_BYTES (OT, Index);
|
||||
|
||||
/* Offset, Null offset = 0 */
|
||||
template <typename Type>
|
||||
|
@ -765,7 +220,6 @@ struct FixedVersion
|
|||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Template subclasses of Offset that do the dereferencing.
|
||||
* Use: (base+offset)
|
||||
|
@ -831,7 +285,6 @@ static inline Type& operator + (Base &base, OffsetTo<Type, OffsetType> &offset)
|
|||
* Array Types
|
||||
*/
|
||||
|
||||
|
||||
/* TODO Use it in ArrayOf, HeadlessArrayOf, and other places around the code base?? */
|
||||
template <typename Type>
|
||||
struct UnsizedArrayOf
|
||||
|
@ -913,7 +366,6 @@ struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType>
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
/* An array with a number of elements. */
|
||||
template <typename Type, typename LenType=HBUINT16>
|
||||
struct ArrayOf
|
||||
|
@ -1066,7 +518,6 @@ struct OffsetListOf : OffsetArrayOf<Type>
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
/* An array starting at second element. */
|
||||
template <typename Type, typename LenType=HBUINT16>
|
||||
struct HeadlessArrayOf
|
||||
|
@ -1131,10 +582,7 @@ struct HeadlessArrayOf
|
|||
DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* An array with sorted elements. Supports binary searching.
|
||||
*/
|
||||
/* An array with sorted elements. Supports binary searching. */
|
||||
template <typename Type, typename LenType=HBUINT16>
|
||||
struct SortedArrayOf : ArrayOf<Type, LenType>
|
||||
{
|
||||
|
@ -1159,10 +607,7 @@ struct SortedArrayOf : ArrayOf<Type, LenType>
|
|||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Binary-search arrays
|
||||
*/
|
||||
|
||||
/* Binary-search arrays */
|
||||
struct BinSearchHeader
|
||||
{
|
||||
inline operator uint32_t (void) const { return len; }
|
||||
|
@ -1198,101 +643,6 @@ template <typename Type>
|
|||
struct BinSearchArrayOf : SortedArrayOf<Type, BinSearchHeader> {};
|
||||
|
||||
|
||||
/* Lazy struct and blob loaders. */
|
||||
|
||||
/* Logic is shared between hb_lazy_loader_t and hb_table_lazy_loader_t */
|
||||
template <typename T>
|
||||
struct hb_lazy_loader_t
|
||||
{
|
||||
inline void init (hb_face_t *face_)
|
||||
{
|
||||
face = face_;
|
||||
instance = nullptr;
|
||||
}
|
||||
|
||||
inline void fini (void)
|
||||
{
|
||||
if (instance && instance != &Null(T))
|
||||
{
|
||||
instance->fini();
|
||||
free (instance);
|
||||
}
|
||||
}
|
||||
|
||||
inline const T* get (void) const
|
||||
{
|
||||
retry:
|
||||
T *p = (T *) hb_atomic_ptr_get (&instance);
|
||||
if (unlikely (!p))
|
||||
{
|
||||
p = (T *) calloc (1, sizeof (T));
|
||||
if (unlikely (!p))
|
||||
p = const_cast<T *> (&Null(T));
|
||||
else
|
||||
p->init (face);
|
||||
if (unlikely (!hb_atomic_ptr_cmpexch (const_cast<T **>(&instance), nullptr, p)))
|
||||
{
|
||||
if (p != &Null(T))
|
||||
p->fini ();
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
inline const T* operator-> (void) const
|
||||
{
|
||||
return get ();
|
||||
}
|
||||
|
||||
private:
|
||||
hb_face_t *face;
|
||||
T *instance;
|
||||
};
|
||||
|
||||
/* Logic is shared between hb_lazy_loader_t and hb_table_lazy_loader_t */
|
||||
template <typename T>
|
||||
struct hb_table_lazy_loader_t
|
||||
{
|
||||
inline void init (hb_face_t *face_)
|
||||
{
|
||||
face = face_;
|
||||
blob = nullptr;
|
||||
}
|
||||
|
||||
inline void fini (void)
|
||||
{
|
||||
hb_blob_destroy (blob);
|
||||
}
|
||||
|
||||
inline const T* get (void) const
|
||||
{
|
||||
retry:
|
||||
hb_blob_t *blob_ = (hb_blob_t *) hb_atomic_ptr_get (&blob);
|
||||
if (unlikely (!blob_))
|
||||
{
|
||||
blob_ = OT::Sanitizer<T>().sanitize (face->reference_table (T::tableTag));
|
||||
if (!hb_atomic_ptr_cmpexch (&blob, nullptr, blob_))
|
||||
{
|
||||
hb_blob_destroy (blob_);
|
||||
goto retry;
|
||||
}
|
||||
blob = blob_;
|
||||
}
|
||||
return blob_->as<T> ();
|
||||
}
|
||||
|
||||
inline const T* operator-> (void) const
|
||||
{
|
||||
return get();
|
||||
}
|
||||
|
||||
private:
|
||||
hb_face_t *face;
|
||||
mutable hb_blob_t *blob;
|
||||
};
|
||||
|
||||
|
||||
} /* namespace OT */
|
||||
|
||||
|
||||
|
|
|
@ -37,6 +37,9 @@
|
|||
*/
|
||||
#define HB_OT_TAG_cmap HB_TAG('c','m','a','p')
|
||||
|
||||
#ifndef HB_MAX_UNICODE_CODEPOINT_VALUE
|
||||
#define HB_MAX_UNICODE_CODEPOINT_VALUE 0x10FFFF
|
||||
#endif
|
||||
|
||||
namespace OT {
|
||||
|
||||
|
@ -437,8 +440,10 @@ struct CmapSubtableLongSegmented
|
|||
{
|
||||
for (unsigned int i = 0; i < this->groups.len; i++) {
|
||||
hb_set_add_range (out,
|
||||
this->groups[i].startCharCode,
|
||||
this->groups[i].endCharCode);
|
||||
MIN ((unsigned int) this->groups[i].startCharCode,
|
||||
(unsigned int) HB_MAX_UNICODE_CODEPOINT_VALUE),
|
||||
MIN ((unsigned int) this->groups[i].endCharCode,
|
||||
(unsigned int) HB_MAX_UNICODE_CODEPOINT_VALUE));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -800,37 +805,37 @@ struct cmap
|
|||
{
|
||||
hb_serialize_context_t c (dest, dest_sz);
|
||||
|
||||
OT::cmap *cmap = c.start_serialize<OT::cmap> ();
|
||||
if (unlikely (!c.extend_min (*cmap)))
|
||||
cmap *table = c.start_serialize<cmap> ();
|
||||
if (unlikely (!c.extend_min (*table)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
cmap->version.set (0);
|
||||
table->version.set (0);
|
||||
|
||||
if (unlikely (!cmap->encodingRecord.serialize (&c, /* numTables */ 3)))
|
||||
if (unlikely (!table->encodingRecord.serialize (&c, /* numTables */ 3)))
|
||||
return false;
|
||||
|
||||
// TODO(grieger): Convert the below to a for loop
|
||||
|
||||
// Format 4, Plat 0 Encoding Record
|
||||
EncodingRecord &format4_plat0_rec = cmap->encodingRecord[0];
|
||||
EncodingRecord &format4_plat0_rec = table->encodingRecord[0];
|
||||
format4_plat0_rec.platformID.set (0); // Unicode
|
||||
format4_plat0_rec.encodingID.set (3);
|
||||
|
||||
// Format 4, Plat 3 Encoding Record
|
||||
EncodingRecord &format4_plat3_rec = cmap->encodingRecord[1];
|
||||
EncodingRecord &format4_plat3_rec = table->encodingRecord[1];
|
||||
format4_plat3_rec.platformID.set (3); // Windows
|
||||
format4_plat3_rec.encodingID.set (1); // Unicode BMP
|
||||
|
||||
// Format 12 Encoding Record
|
||||
EncodingRecord &format12_rec = cmap->encodingRecord[2];
|
||||
EncodingRecord &format12_rec = table->encodingRecord[2];
|
||||
format12_rec.platformID.set (3); // Windows
|
||||
format12_rec.encodingID.set (10); // Unicode UCS-4
|
||||
|
||||
// Write out format 4 sub table
|
||||
{
|
||||
CmapSubtable &subtable = format4_plat0_rec.subtable.serialize (&c, cmap);
|
||||
CmapSubtable &subtable = format4_plat0_rec.subtable.serialize (&c, table);
|
||||
format4_plat3_rec.subtable.set (format4_plat0_rec.subtable);
|
||||
subtable.u.format.set (4);
|
||||
|
||||
|
@ -841,7 +846,7 @@ struct cmap
|
|||
|
||||
// Write out format 12 sub table.
|
||||
{
|
||||
CmapSubtable &subtable = format12_rec.subtable.serialize (&c, cmap);
|
||||
CmapSubtable &subtable = format12_rec.subtable.serialize (&c, table);
|
||||
subtable.u.format.set (12);
|
||||
|
||||
CmapSubtableFormat12 &format12 = subtable.u.format12;
|
||||
|
@ -894,57 +899,57 @@ struct cmap
|
|||
{
|
||||
inline void init (hb_face_t *face)
|
||||
{
|
||||
this->blob = OT::Sanitizer<OT::cmap>().sanitize (face->reference_table (HB_OT_TAG_cmap));
|
||||
const OT::cmap *cmap = this->blob->as<OT::cmap> ();
|
||||
const OT::CmapSubtable *subtable = nullptr;
|
||||
const OT::CmapSubtableFormat14 *subtable_uvs = nullptr;
|
||||
this->blob = hb_sanitize_context_t().reference_table<cmap> (face);
|
||||
const cmap *table = this->blob->as<cmap> ();
|
||||
const CmapSubtable *subtable = nullptr;
|
||||
const CmapSubtableFormat14 *subtable_uvs = nullptr;
|
||||
|
||||
bool symbol = false;
|
||||
/* 32-bit subtables. */
|
||||
if (!subtable) subtable = cmap->find_subtable (3, 10);
|
||||
if (!subtable) subtable = cmap->find_subtable (0, 6);
|
||||
if (!subtable) subtable = cmap->find_subtable (0, 4);
|
||||
if (!subtable) subtable = table->find_subtable (3, 10);
|
||||
if (!subtable) subtable = table->find_subtable (0, 6);
|
||||
if (!subtable) subtable = table->find_subtable (0, 4);
|
||||
/* 16-bit subtables. */
|
||||
if (!subtable) subtable = cmap->find_subtable (3, 1);
|
||||
if (!subtable) subtable = cmap->find_subtable (0, 3);
|
||||
if (!subtable) subtable = cmap->find_subtable (0, 2);
|
||||
if (!subtable) subtable = cmap->find_subtable (0, 1);
|
||||
if (!subtable) subtable = cmap->find_subtable (0, 0);
|
||||
if (!subtable) subtable = table->find_subtable (3, 1);
|
||||
if (!subtable) subtable = table->find_subtable (0, 3);
|
||||
if (!subtable) subtable = table->find_subtable (0, 2);
|
||||
if (!subtable) subtable = table->find_subtable (0, 1);
|
||||
if (!subtable) subtable = table->find_subtable (0, 0);
|
||||
if (!subtable)
|
||||
{
|
||||
subtable = cmap->find_subtable (3, 0);
|
||||
subtable = table->find_subtable (3, 0);
|
||||
if (subtable) symbol = true;
|
||||
}
|
||||
/* Meh. */
|
||||
if (!subtable) subtable = &Null(OT::CmapSubtable);
|
||||
if (!subtable) subtable = &Null(CmapSubtable);
|
||||
|
||||
/* UVS subtable. */
|
||||
if (!subtable_uvs)
|
||||
{
|
||||
const OT::CmapSubtable *st = cmap->find_subtable (0, 5);
|
||||
const CmapSubtable *st = table->find_subtable (0, 5);
|
||||
if (st && st->u.format == 14)
|
||||
subtable_uvs = &st->u.format14;
|
||||
}
|
||||
/* Meh. */
|
||||
if (!subtable_uvs) subtable_uvs = &Null(OT::CmapSubtableFormat14);
|
||||
if (!subtable_uvs) subtable_uvs = &Null(CmapSubtableFormat14);
|
||||
|
||||
this->uvs_table = subtable_uvs;
|
||||
|
||||
this->get_glyph_data = subtable;
|
||||
if (unlikely (symbol))
|
||||
{
|
||||
this->get_glyph_func = get_glyph_from_symbol<OT::CmapSubtable>;
|
||||
this->get_glyph_func = get_glyph_from_symbol<CmapSubtable>;
|
||||
this->get_all_codepoints_func = null_get_all_codepoints_func;
|
||||
} else {
|
||||
switch (subtable->u.format) {
|
||||
/* Accelerate format 4 and format 12. */
|
||||
default:
|
||||
this->get_glyph_func = get_glyph_from<OT::CmapSubtable>;
|
||||
this->get_glyph_func = get_glyph_from<CmapSubtable>;
|
||||
this->get_all_codepoints_func = null_get_all_codepoints_func;
|
||||
break;
|
||||
case 12:
|
||||
this->get_glyph_func = get_glyph_from<OT::CmapSubtableFormat12>;
|
||||
this->get_all_codepoints_func = get_all_codepoints_from<OT::CmapSubtableFormat12>;
|
||||
this->get_glyph_func = get_glyph_from<CmapSubtableFormat12>;
|
||||
this->get_all_codepoints_func = get_all_codepoints_from<CmapSubtableFormat12>;
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
|
@ -977,9 +982,9 @@ struct cmap
|
|||
variation_selector,
|
||||
glyph))
|
||||
{
|
||||
case OT::GLYPH_VARIANT_NOT_FOUND: return false;
|
||||
case OT::GLYPH_VARIANT_FOUND: return true;
|
||||
case OT::GLYPH_VARIANT_USE_DEFAULT: break;
|
||||
case GLYPH_VARIANT_NOT_FOUND: return false;
|
||||
case GLYPH_VARIANT_FOUND: return true;
|
||||
case GLYPH_VARIANT_USE_DEFAULT: break;
|
||||
}
|
||||
|
||||
return get_nominal_glyph (unicode, glyph);
|
||||
|
@ -1046,9 +1051,9 @@ struct cmap
|
|||
const void *get_glyph_data;
|
||||
hb_cmap_get_all_codepoints_func_t get_all_codepoints_func;
|
||||
|
||||
OT::CmapSubtableFormat4::accelerator_t format4_accel;
|
||||
CmapSubtableFormat4::accelerator_t format4_accel;
|
||||
|
||||
const OT::CmapSubtableFormat14 *uvs_table;
|
||||
const CmapSubtableFormat14 *uvs_table;
|
||||
hb_blob_t *blob;
|
||||
};
|
||||
|
||||
|
|
|
@ -394,8 +394,8 @@ struct CBDT
|
|||
{
|
||||
upem = hb_face_get_upem (face);
|
||||
|
||||
cblc_blob = Sanitizer<CBLC>().sanitize (face->reference_table (HB_OT_TAG_CBLC));
|
||||
cbdt_blob = Sanitizer<CBDT>().sanitize (face->reference_table (HB_OT_TAG_CBDT));
|
||||
cblc_blob = hb_sanitize_context_t().reference_table<CBLC> (face);
|
||||
cbdt_blob = hb_sanitize_context_t().reference_table<CBDT> (face);
|
||||
cbdt_len = hb_blob_get_length (cbdt_blob);
|
||||
|
||||
if (hb_blob_get_length (cblc_blob) == 0) {
|
||||
|
|
|
@ -68,7 +68,7 @@ struct SBIXStrike
|
|||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
imageOffsetsZ.sanitize_shallow (c, c->num_glyphs + 1));
|
||||
imageOffsetsZ.sanitize_shallow (c, c->get_num_glyphs () + 1));
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -96,14 +96,9 @@ struct sbix
|
|||
{
|
||||
inline void init (hb_face_t *face)
|
||||
{
|
||||
num_glyphs = hb_face_get_glyph_count (face);
|
||||
|
||||
OT::Sanitizer<OT::sbix> sanitizer;
|
||||
sanitizer.set_num_glyphs (num_glyphs);
|
||||
sbix_blob = sanitizer.sanitize (face->reference_table (HB_OT_TAG_sbix));
|
||||
sbix_blob = hb_sanitize_context_t().reference_table<sbix> (face);
|
||||
sbix_len = hb_blob_get_length (sbix_blob);
|
||||
sbix_table = sbix_blob->as<OT::sbix> ();
|
||||
|
||||
sbix_table = sbix_blob->as<sbix> ();
|
||||
}
|
||||
|
||||
inline void fini (void)
|
||||
|
@ -134,7 +129,6 @@ struct sbix
|
|||
|
||||
unsigned int sbix_len;
|
||||
unsigned int num_glyphs;
|
||||
|
||||
};
|
||||
|
||||
protected:
|
||||
|
|
|
@ -96,11 +96,9 @@ struct SVG
|
|||
{
|
||||
inline void init (hb_face_t *face)
|
||||
{
|
||||
OT::Sanitizer<OT::SVG> sanitizer;
|
||||
svg_blob = sanitizer.sanitize (face->reference_table (HB_OT_TAG_SVG));
|
||||
svg_blob = hb_sanitize_context_t().reference_table<SVG> (face);
|
||||
svg_len = hb_blob_get_length (svg_blob);
|
||||
svg = svg_blob->as<OT::SVG> ();
|
||||
|
||||
svg = svg_blob->as<SVG> ();
|
||||
}
|
||||
|
||||
inline void fini (void)
|
||||
|
|
|
@ -41,13 +41,39 @@
|
|||
|
||||
struct hb_ot_font_t
|
||||
{
|
||||
inline void init (hb_face_t *face)
|
||||
{
|
||||
cmap.init (face);
|
||||
h_metrics.init (face);
|
||||
v_metrics.init (face, h_metrics.ascender - h_metrics.descender); /* TODO Can we do this lazily? */
|
||||
|
||||
this->face = face;
|
||||
glyf.init ();
|
||||
cbdt.init ();
|
||||
post.init ();
|
||||
kern.init ();
|
||||
}
|
||||
inline void fini (void)
|
||||
{
|
||||
cmap.fini ();
|
||||
h_metrics.fini ();
|
||||
v_metrics.fini ();
|
||||
|
||||
glyf.fini ();
|
||||
cbdt.fini ();
|
||||
post.fini ();
|
||||
kern.fini ();
|
||||
}
|
||||
|
||||
OT::cmap::accelerator_t cmap;
|
||||
OT::hmtx::accelerator_t h_metrics;
|
||||
OT::vmtx::accelerator_t v_metrics;
|
||||
OT::hb_lazy_loader_t<OT::glyf::accelerator_t> glyf;
|
||||
OT::hb_lazy_loader_t<OT::CBDT::accelerator_t> cbdt;
|
||||
OT::hb_lazy_loader_t<OT::post::accelerator_t> post;
|
||||
OT::hb_lazy_loader_t<OT::kern::accelerator_t> kern;
|
||||
|
||||
hb_face_t *face; /* MUST be JUST before the lazy loaders. */
|
||||
hb_object_lazy_loader_t<1, OT::glyf::accelerator_t> glyf;
|
||||
hb_object_lazy_loader_t<2, OT::CBDT::accelerator_t> cbdt;
|
||||
hb_object_lazy_loader_t<3, OT::post::accelerator_t> post;
|
||||
hb_object_lazy_loader_t<4, OT::kern::accelerator_t> kern;
|
||||
};
|
||||
|
||||
|
||||
|
@ -59,13 +85,7 @@ _hb_ot_font_create (hb_face_t *face)
|
|||
if (unlikely (!ot_font))
|
||||
return nullptr;
|
||||
|
||||
ot_font->cmap.init (face);
|
||||
ot_font->h_metrics.init (face);
|
||||
ot_font->v_metrics.init (face, ot_font->h_metrics.ascender - ot_font->h_metrics.descender); /* TODO Can we do this lazily? */
|
||||
ot_font->glyf.init (face);
|
||||
ot_font->cbdt.init (face);
|
||||
ot_font->post.init (face);
|
||||
ot_font->kern.init (face);
|
||||
ot_font->init (face);
|
||||
|
||||
return ot_font;
|
||||
}
|
||||
|
@ -75,13 +95,7 @@ _hb_ot_font_destroy (void *data)
|
|||
{
|
||||
hb_ot_font_t *ot_font = (hb_ot_font_t *) data;
|
||||
|
||||
ot_font->cmap.fini ();
|
||||
ot_font->h_metrics.fini ();
|
||||
ot_font->v_metrics.fini ();
|
||||
ot_font->glyf.fini ();
|
||||
ot_font->cbdt.fini ();
|
||||
ot_font->post.fini ();
|
||||
ot_font->kern.fini ();
|
||||
ot_font->fini ();
|
||||
|
||||
free (ot_font);
|
||||
}
|
||||
|
|
|
@ -103,14 +103,14 @@ struct glyf
|
|||
static bool
|
||||
_add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca)
|
||||
{
|
||||
hb_blob_t *head_blob = OT::Sanitizer<OT::head>().sanitize (hb_face_reference_table (plan->source, HB_OT_TAG_head));
|
||||
hb_blob_t *head_blob = hb_sanitize_context_t().reference_table<head> (plan->source);
|
||||
hb_blob_t *head_prime_blob = hb_blob_copy_writable_or_fail (head_blob);
|
||||
hb_blob_destroy (head_blob);
|
||||
|
||||
if (unlikely (!head_prime_blob))
|
||||
return false;
|
||||
|
||||
OT::head *head_prime = (OT::head *) hb_blob_get_data_writable (head_prime_blob, nullptr);
|
||||
head *head_prime = (head *) hb_blob_get_data_writable (head_prime_blob, nullptr);
|
||||
head_prime->indexToLocFormat.set (use_short_loca ? 0 : 1);
|
||||
bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob);
|
||||
|
||||
|
@ -236,20 +236,20 @@ struct glyf
|
|||
{
|
||||
memset (this, 0, sizeof (accelerator_t));
|
||||
|
||||
hb_blob_t *head_blob = Sanitizer<head>().sanitize (face->reference_table (HB_OT_TAG_head));
|
||||
hb_blob_t *head_blob = hb_sanitize_context_t().reference_table<head> (face);
|
||||
const head *head_table = head_blob->as<head> ();
|
||||
if (head_table == &Null(head) || (unsigned int) head_table->indexToLocFormat > 1 || head_table->glyphDataFormat != 0)
|
||||
if (head_table->indexToLocFormat > 1 || head_table->glyphDataFormat != 0)
|
||||
{
|
||||
/* head table is not present, or in an unknown format. Leave num_glyphs=0, that takes care of disabling us. */
|
||||
/* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */
|
||||
hb_blob_destroy (head_blob);
|
||||
return;
|
||||
}
|
||||
short_offset = 0 == head_table->indexToLocFormat;
|
||||
hb_blob_destroy (head_blob);
|
||||
|
||||
loca_blob = Sanitizer<loca>().sanitize (face->reference_table (HB_OT_TAG_loca));
|
||||
loca_blob = hb_sanitize_context_t().reference_table<loca> (face);
|
||||
loca_table = loca_blob->as<loca> ();
|
||||
glyf_blob = Sanitizer<glyf>().sanitize (face->reference_table (HB_OT_TAG_glyf));
|
||||
glyf_blob = hb_sanitize_context_t().reference_table<glyf> (face);
|
||||
glyf_table = glyf_blob->as<glyf> ();
|
||||
|
||||
num_glyphs = MAX (1u, hb_blob_get_length (loca_blob) / (short_offset ? 2 : 4)) - 1;
|
||||
|
@ -270,7 +270,7 @@ struct glyf
|
|||
inline bool get_composite (hb_codepoint_t glyph,
|
||||
CompositeGlyphHeader::Iterator *composite /* OUT */) const
|
||||
{
|
||||
if (this->glyf_table == &Null(glyf) || !num_glyphs)
|
||||
if (unlikely (!num_glyphs))
|
||||
return false;
|
||||
|
||||
unsigned int start_offset, end_offset;
|
||||
|
|
|
@ -141,8 +141,8 @@ struct head
|
|||
* -1: Only strongly right to left;
|
||||
* -2: Like -1 but also contains neutrals. */
|
||||
public:
|
||||
HBINT16 indexToLocFormat; /* 0 for short offsets, 1 for long. */
|
||||
HBINT16 glyphDataFormat; /* 0 for current format. */
|
||||
HBUINT16 indexToLocFormat; /* 0 for short offsets, 1 for long. */
|
||||
HBUINT16 glyphDataFormat; /* 0 for current format. */
|
||||
|
||||
DEFINE_SIZE_STATIC (54);
|
||||
};
|
||||
|
|
|
@ -69,7 +69,7 @@ struct hmtxvmtx
|
|||
inline bool subset_update_header (hb_subset_plan_t *plan,
|
||||
unsigned int num_hmetrics) const
|
||||
{
|
||||
hb_blob_t *src_blob = OT::Sanitizer<H> ().sanitize (plan->source->reference_table (H::tableTag));
|
||||
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);
|
||||
hb_blob_destroy (src_blob);
|
||||
|
||||
|
@ -195,7 +195,7 @@ struct hmtxvmtx
|
|||
bool got_font_extents = false;
|
||||
if (T::os2Tag)
|
||||
{
|
||||
hb_blob_t *os2_blob = Sanitizer<os2> ().sanitize (face->reference_table (T::os2Tag));
|
||||
hb_blob_t *os2_blob = hb_sanitize_context_t().reference_table<os2> (face);
|
||||
const os2 *os2_table = os2_blob->as<os2> ();
|
||||
#define USE_TYPO_METRICS (1u<<7)
|
||||
if (0 != (os2_table->fsSelection & USE_TYPO_METRICS))
|
||||
|
@ -208,7 +208,7 @@ struct hmtxvmtx
|
|||
hb_blob_destroy (os2_blob);
|
||||
}
|
||||
|
||||
hb_blob_t *_hea_blob = Sanitizer<H> ().sanitize (face->reference_table (H::tableTag));
|
||||
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)
|
||||
|
@ -222,7 +222,7 @@ struct hmtxvmtx
|
|||
|
||||
has_font_extents = got_font_extents;
|
||||
|
||||
blob = Sanitizer<hmtxvmtx> ().sanitize (face->reference_table (T::tableTag));
|
||||
blob = hb_sanitize_context_t().reference_table<hmtxvmtx> (face, T::tableTag);
|
||||
|
||||
/* Cap num_metrics() and num_advances() based on table length. */
|
||||
unsigned int len = hb_blob_get_length (blob);
|
||||
|
@ -240,7 +240,7 @@ struct hmtxvmtx
|
|||
}
|
||||
table = blob->as<hmtxvmtx> ();
|
||||
|
||||
var_blob = Sanitizer<HVARVVAR> ().sanitize (face->reference_table (T::variationsTag));
|
||||
var_blob = hb_sanitize_context_t().reference_table<HVARVVAR> (face, T::variationsTag);
|
||||
var_table = var_blob->as<HVARVVAR> ();
|
||||
}
|
||||
|
||||
|
|
|
@ -362,7 +362,7 @@ struct kern
|
|||
{
|
||||
inline void init (hb_face_t *face)
|
||||
{
|
||||
blob = Sanitizer<kern>().sanitize (face->reference_table (HB_OT_TAG_kern));
|
||||
blob = hb_sanitize_context_t().reference_table<kern> (face);
|
||||
table = blob->as<kern> ();
|
||||
table_length = blob->length;
|
||||
}
|
||||
|
|
|
@ -33,13 +33,16 @@
|
|||
|
||||
namespace OT {
|
||||
|
||||
#define NOT_INDEXED ((unsigned int) -1)
|
||||
|
||||
/*
|
||||
* BASE -- Baseline
|
||||
* https://docs.microsoft.com/en-us/typography/opentype/spec/base
|
||||
*/
|
||||
|
||||
|
||||
/* XXX Review this. */
|
||||
#define NOT_INDEXED ((unsigned int) -1)
|
||||
|
||||
|
||||
struct BaseCoordFormat1
|
||||
{
|
||||
inline int get_coord (void) const { return coordinate; }
|
||||
|
@ -52,7 +55,7 @@ struct BaseCoordFormat1
|
|||
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 1 */
|
||||
HBINT16 coordinate; /* X or Y value, in design units */
|
||||
FWORD coordinate; /* X or Y value, in design units */
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (4);
|
||||
};
|
||||
|
@ -73,7 +76,7 @@ struct BaseCoordFormat2
|
|||
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 2 */
|
||||
HBINT16 coordinate; /* X or Y value, in design units */
|
||||
FWORD coordinate; /* X or Y value, in design units */
|
||||
GlyphID referenceGlyph; /* Glyph ID of control glyph */
|
||||
HBUINT16 coordPoint; /* Index of contour point on the
|
||||
* reference glyph */
|
||||
|
@ -97,7 +100,7 @@ struct BaseCoordFormat3
|
|||
|
||||
protected:
|
||||
HBUINT16 format; /* Format identifier--format = 3 */
|
||||
HBINT16 coordinate; /* X or Y value, in design units */
|
||||
FWORD coordinate; /* X or Y value, in design units */
|
||||
OffsetTo<Device> deviceTable; /* Offset to Device table for X or
|
||||
* Y value, from beginning of
|
||||
* BaseCoord table (may be NULL). */
|
||||
|
@ -109,6 +112,7 @@ struct BaseCoord
|
|||
{
|
||||
inline int get_coord (void) const
|
||||
{
|
||||
/* XXX wire up direction and font. */
|
||||
switch (u.format) {
|
||||
case 1: return u.format1.get_coord ();
|
||||
case 2: return u.format2.get_coord ();
|
||||
|
@ -142,14 +146,10 @@ struct BaseCoord
|
|||
|
||||
struct FeatMinMaxRecord
|
||||
{
|
||||
inline int get_min_value (void) const
|
||||
{ return (this+minCoord).get_coord(); }
|
||||
inline int get_min_value (void) const { return (this+minCoord).get_coord(); }
|
||||
inline int get_max_value (void) const { return (this+maxCoord).get_coord(); }
|
||||
|
||||
inline int get_max_value (void) const
|
||||
{ return (this+maxCoord).get_coord(); }
|
||||
|
||||
inline const Tag &get_tag () const
|
||||
{ return tag; }
|
||||
inline const Tag& get_tag () const { return tag; }
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
|
@ -181,7 +181,7 @@ struct MinMax
|
|||
unsigned int count = featMinMaxRecords.len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
Tag tag = featMinMaxRecords[i].get_tag();
|
||||
Tag tag = featMinMaxRecords[i].get_tag ();
|
||||
int cmp = tag.cmp(featureTableTag);
|
||||
if (cmp == 0) return i;
|
||||
if (cmp > 0) return NOT_INDEXED;
|
||||
|
@ -233,13 +233,13 @@ struct BaseLangSysRecord
|
|||
{ return baseLangSysTag; }
|
||||
|
||||
inline unsigned int get_feature_tag_index (Tag featureTableTag) const
|
||||
{ return (this+minMax).get_feature_tag_index(featureTableTag); }
|
||||
{ return (this+minMax).get_feature_tag_index( featureTableTag); }
|
||||
|
||||
inline int get_min_value (unsigned int featureTableTagIndex) const
|
||||
{ return (this+minMax).get_min_value(featureTableTagIndex); }
|
||||
{ return (this+minMax).get_min_value( featureTableTagIndex); }
|
||||
|
||||
inline int get_max_value (unsigned int featureTableTagIndex) const
|
||||
{ return (this+minMax).get_max_value(featureTableTagIndex); }
|
||||
{ return (this+minMax).get_max_value (featureTableTagIndex); }
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
|
@ -263,34 +263,34 @@ struct BaseValues
|
|||
|
||||
inline int get_base_coord (unsigned int baselineTagIndex) const
|
||||
{
|
||||
return (this+baseCoords[baselineTagIndex]).get_coord();
|
||||
return (this+baseCoords[baselineTagIndex]).get_coord ();
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
defaultIndex <= baseCoordCount &&
|
||||
baseCoords.sanitize (c, this));
|
||||
baseCoords.sanitize (c, this));
|
||||
}
|
||||
|
||||
protected:
|
||||
Index defaultIndex;
|
||||
HBUINT16 baseCoordCount;
|
||||
OffsetArrayOf<BaseCoord> baseCoords;
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (6, baseCoords);
|
||||
|
||||
DEFINE_SIZE_ARRAY (4, baseCoords);
|
||||
};
|
||||
|
||||
struct BaseScript {
|
||||
|
||||
inline unsigned int get_lang_tag_index (Tag baseLangSysTag) const
|
||||
{
|
||||
/* XXX bsearch */
|
||||
Tag tag;
|
||||
int cmp;
|
||||
for (unsigned int i = 0; i < baseLangSysCount; i++) {
|
||||
tag = baseLangSysRecords[i].get_tag();
|
||||
unsigned int count = baseLangSysRecords.len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
tag = baseLangSysRecords[i].get_tag ();
|
||||
// taking advantage of alphabetical order
|
||||
cmp = tag.cmp(baseLangSysTag);
|
||||
if (cmp == 0) return i;
|
||||
|
@ -301,51 +301,50 @@ struct BaseScript {
|
|||
|
||||
inline unsigned int get_feature_tag_index (unsigned int baseLangSysIndex, Tag featureTableTag) const
|
||||
{
|
||||
if (baseLangSysIndex == NOT_INDEXED) {
|
||||
if (baseLangSysIndex == NOT_INDEXED)
|
||||
{
|
||||
if (unlikely(defaultMinMax)) return NOT_INDEXED;
|
||||
return (this+defaultMinMax).get_feature_tag_index(featureTableTag);
|
||||
return (this+defaultMinMax).get_feature_tag_index (featureTableTag);
|
||||
}
|
||||
if (unlikely(baseLangSysIndex >= baseLangSysCount)) return NOT_INDEXED;
|
||||
return baseLangSysRecords[baseLangSysIndex].get_feature_tag_index(featureTableTag);
|
||||
return baseLangSysRecords[baseLangSysIndex].get_feature_tag_index (featureTableTag);
|
||||
}
|
||||
|
||||
inline int get_min_value (unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
|
||||
{
|
||||
if (baseLangSysIndex == NOT_INDEXED)
|
||||
return (this+defaultMinMax).get_min_value(featureTableTagIndex);
|
||||
return baseLangSysRecords[baseLangSysIndex].get_max_value(featureTableTagIndex);
|
||||
return (this+defaultMinMax).get_min_value (featureTableTagIndex);
|
||||
return baseLangSysRecords[baseLangSysIndex].get_max_value (featureTableTagIndex);
|
||||
}
|
||||
|
||||
inline int get_max_value (unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
|
||||
{
|
||||
if (baseLangSysIndex == NOT_INDEXED)
|
||||
return (this+defaultMinMax).get_min_value(featureTableTagIndex);
|
||||
return baseLangSysRecords[baseLangSysIndex].get_max_value(featureTableTagIndex);
|
||||
return (this+defaultMinMax).get_min_value (featureTableTagIndex);
|
||||
return baseLangSysRecords[baseLangSysIndex].get_max_value (featureTableTagIndex);
|
||||
}
|
||||
|
||||
inline unsigned int get_default_base_tag_index (void) const
|
||||
{ return (this+baseValues).get_default_base_tag_index(); }
|
||||
{ return (this+baseValues).get_default_base_tag_index (); }
|
||||
|
||||
inline int get_base_coord (unsigned int baselineTagIndex) const
|
||||
{ return (this+baseValues).get_base_coord(baselineTagIndex); }
|
||||
{ return (this+baseValues).get_base_coord (baselineTagIndex); }
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
baseValues.sanitize (c, this) &&
|
||||
defaultMinMax.sanitize (c, this) &&
|
||||
baseLangSysRecords.sanitize (c, this));
|
||||
baseValues.sanitize (c, this) &&
|
||||
defaultMinMax.sanitize (c, this) &&
|
||||
baseLangSysRecords.sanitize (c, this));
|
||||
}
|
||||
|
||||
protected:
|
||||
OffsetTo<BaseValues> baseValues;
|
||||
OffsetTo<MinMax> defaultMinMax;
|
||||
HBUINT16 baseLangSysCount;
|
||||
ArrayOf<BaseLangSysRecord> baseLangSysRecords;
|
||||
OffsetTo<BaseValues> baseValues;
|
||||
OffsetTo<MinMax> defaultMinMax;
|
||||
ArrayOf<BaseLangSysRecord> baseLangSysRecords;
|
||||
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (8, baseLangSysRecords);
|
||||
DEFINE_SIZE_ARRAY (6, baseLangSysRecords);
|
||||
};
|
||||
|
||||
|
||||
|
@ -355,29 +354,28 @@ struct BaseScriptRecord {
|
|||
{ return baseScriptTag; }
|
||||
|
||||
inline unsigned int get_default_base_tag_index(void) const
|
||||
{ return (this+baseScript).get_default_base_tag_index(); }
|
||||
{ return (this+baseScript).get_default_base_tag_index (); }
|
||||
|
||||
inline int get_base_coord(unsigned int baselineTagIndex) const
|
||||
{ return (this+baseScript).get_base_coord(baselineTagIndex); }
|
||||
{ return (this+baseScript).get_base_coord (baselineTagIndex); }
|
||||
|
||||
inline unsigned int get_lang_tag_index (Tag baseLangSysTag) const
|
||||
{ return (this+baseScript).get_lang_tag_index(baseLangSysTag); }
|
||||
{ return (this+baseScript).get_lang_tag_index (baseLangSysTag); }
|
||||
|
||||
inline unsigned int get_feature_tag_index (unsigned int baseLangSysIndex, Tag featureTableTag) const
|
||||
{ return (this+baseScript).get_feature_tag_index(baseLangSysIndex, featureTableTag); }
|
||||
{ return (this+baseScript).get_feature_tag_index (baseLangSysIndex, featureTableTag); }
|
||||
|
||||
inline int get_max_value (unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
|
||||
{ return (this+baseScript).get_max_value(baseLangSysIndex, featureTableTagIndex); }
|
||||
{ return (this+baseScript).get_max_value (baseLangSysIndex, featureTableTagIndex); }
|
||||
|
||||
inline int get_min_value (unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
|
||||
{ return (this+baseScript).get_min_value(baseLangSysIndex, featureTableTagIndex); }
|
||||
{ return (this+baseScript).get_min_value (baseLangSysIndex, featureTableTagIndex); }
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
baseScript != Null(OffsetTo<BaseScript>) &&
|
||||
baseScript.sanitize (c, base));
|
||||
baseScript.sanitize (c, base));
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -392,7 +390,9 @@ struct BaseScriptList {
|
|||
|
||||
inline unsigned int get_base_script_index (Tag baseScriptTag) const
|
||||
{
|
||||
for (unsigned int i = 0; i < baseScriptCount; i++)
|
||||
/* XXX bsearch? */
|
||||
unsigned int count = baseScriptRecords.len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (baseScriptRecords[i].get_tag() == baseScriptTag)
|
||||
return i;
|
||||
return NOT_INDEXED;
|
||||
|
@ -400,7 +400,6 @@ struct BaseScriptList {
|
|||
|
||||
inline unsigned int get_default_base_tag_index (unsigned int baseScriptIndex) const
|
||||
{
|
||||
if (unlikely(baseScriptIndex >= baseScriptCount)) return NOT_INDEXED;
|
||||
return baseScriptRecords[baseScriptIndex].get_default_base_tag_index();
|
||||
}
|
||||
|
||||
|
@ -411,13 +410,11 @@ struct BaseScriptList {
|
|||
|
||||
inline unsigned int get_lang_tag_index (unsigned int baseScriptIndex, Tag baseLangSysTag) const
|
||||
{
|
||||
if (unlikely(baseScriptIndex >= baseScriptCount)) return NOT_INDEXED;
|
||||
return baseScriptRecords[baseScriptIndex].get_lang_tag_index(baseLangSysTag);
|
||||
}
|
||||
|
||||
inline unsigned int get_feature_tag_index (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, Tag featureTableTag) const
|
||||
{
|
||||
if (unlikely(baseScriptIndex >= baseScriptCount)) return NOT_INDEXED;
|
||||
return baseScriptRecords[baseScriptIndex].get_feature_tag_index(baseLangSysIndex, featureTableTag);
|
||||
}
|
||||
|
||||
|
@ -435,24 +432,23 @@ struct BaseScriptList {
|
|||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
baseScriptRecords.sanitize (c, this));
|
||||
baseScriptRecords.sanitize (c, this));
|
||||
}
|
||||
|
||||
protected:
|
||||
HBUINT16 baseScriptCount;
|
||||
ArrayOf<BaseScriptRecord> baseScriptRecords;
|
||||
ArrayOf<BaseScriptRecord> baseScriptRecords;
|
||||
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (4, baseScriptRecords);
|
||||
|
||||
DEFINE_SIZE_ARRAY (2, baseScriptRecords);
|
||||
};
|
||||
|
||||
struct BaseTagList
|
||||
{
|
||||
|
||||
inline unsigned int get_tag_index(Tag baselineTag) const
|
||||
inline unsigned int get_tag_index (Tag baselineTag) const
|
||||
{
|
||||
for (unsigned int i = 0; i < baseTagCount; i++)
|
||||
/* TODO bsearch? */
|
||||
unsigned int count = baselineTags.len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
if (baselineTags[i] == baselineTag)
|
||||
return i;
|
||||
return NOT_INDEXED;
|
||||
|
@ -465,42 +461,37 @@ struct BaseTagList
|
|||
}
|
||||
|
||||
protected:
|
||||
HBUINT16 baseTagCount;
|
||||
SortedArrayOf<Tag> baselineTags;
|
||||
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (4, baselineTags);
|
||||
DEFINE_SIZE_ARRAY (2, baselineTags);
|
||||
};
|
||||
|
||||
struct Axis
|
||||
{
|
||||
|
||||
inline unsigned int get_base_tag_index(Tag baselineTag) const
|
||||
inline unsigned int get_base_tag_index (Tag baselineTag) const
|
||||
{
|
||||
if (unlikely(baseTagList == Null(OffsetTo<BaseTagList>))) return NOT_INDEXED;
|
||||
return (this+baseTagList).get_tag_index(baselineTag);
|
||||
}
|
||||
|
||||
inline unsigned int get_default_base_tag_index_for_script_index (unsigned int baseScriptIndex) const
|
||||
{
|
||||
if (unlikely(baseScriptList == Null(OffsetTo<BaseScriptList>))) return NOT_INDEXED;
|
||||
return (this+baseScriptList).get_default_base_tag_index(baseScriptIndex);
|
||||
}
|
||||
|
||||
inline int get_base_coord(unsigned int baseScriptIndex, unsigned int baselineTagIndex) const
|
||||
inline int get_base_coord (unsigned int baseScriptIndex, unsigned int baselineTagIndex) const
|
||||
{
|
||||
return (this+baseScriptList).get_base_coord(baseScriptIndex, baselineTagIndex);
|
||||
}
|
||||
|
||||
inline unsigned int get_lang_tag_index (unsigned int baseScriptIndex, Tag baseLangSysTag) const
|
||||
{
|
||||
if (unlikely(baseScriptList == Null(OffsetTo<BaseScriptList>))) return NOT_INDEXED;
|
||||
return (this+baseScriptList).get_lang_tag_index(baseScriptIndex, baseLangSysTag);
|
||||
}
|
||||
|
||||
inline unsigned int get_feature_tag_index (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, Tag featureTableTag) const
|
||||
{
|
||||
if (unlikely(baseScriptList == Null(OffsetTo<BaseScriptList>))) return NOT_INDEXED;
|
||||
return (this+baseScriptList).get_feature_tag_index(baseScriptIndex, baseLangSysIndex, featureTableTag);
|
||||
}
|
||||
|
||||
|
@ -518,13 +509,13 @@ struct Axis
|
|||
{
|
||||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
baseTagList.sanitize (c, this) &&
|
||||
baseScriptList.sanitize (c, this));
|
||||
baseTagList.sanitize (c, this) &&
|
||||
baseScriptList.sanitize (c, this));
|
||||
}
|
||||
|
||||
protected:
|
||||
OffsetTo<BaseTagList> baseTagList;
|
||||
OffsetTo<BaseScriptList> baseScriptList;
|
||||
OffsetTo<BaseTagList> baseTagList;
|
||||
OffsetTo<BaseScriptList> baseScriptList;
|
||||
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (4);
|
||||
|
@ -534,96 +525,78 @@ struct BASE
|
|||
{
|
||||
static const hb_tag_t tableTag = HB_OT_TAG_BASE;
|
||||
|
||||
inline bool has_vert_axis(void)
|
||||
{ return vertAxis != Null(OffsetTo<Axis>); }
|
||||
inline bool has_v_axis(void) { return vAxis != 0; }
|
||||
|
||||
inline bool has_horiz_axis(void)
|
||||
{ return horizAxis != Null(OffsetTo<Axis>); }
|
||||
inline bool has_h_axis(void) { return hAxis != 0; }
|
||||
|
||||
// horizontal axis base coords:
|
||||
|
||||
inline unsigned int get_horiz_base_tag_index(Tag baselineTag) const
|
||||
inline unsigned int get_h_base_tag_index (Tag baselineTag) const
|
||||
{
|
||||
if (unlikely(horizAxis == Null(OffsetTo<Axis>))) return NOT_INDEXED;
|
||||
return (this+horizAxis).get_base_tag_index(baselineTag);
|
||||
return (this+hAxis).get_base_tag_index(baselineTag);
|
||||
}
|
||||
|
||||
inline unsigned int get_horiz_default_base_tag_index_for_script_index (unsigned int baseScriptIndex) const
|
||||
inline unsigned int get_h_default_base_tag_index_for_script_index (unsigned int baseScriptIndex) const
|
||||
{
|
||||
if (unlikely(horizAxis == Null(OffsetTo<Axis>))) return NOT_INDEXED;
|
||||
return (this+horizAxis).get_default_base_tag_index_for_script_index(baseScriptIndex);
|
||||
return (this+hAxis).get_default_base_tag_index_for_script_index(baseScriptIndex);
|
||||
}
|
||||
|
||||
inline int get_horiz_base_coord(unsigned int baseScriptIndex, unsigned int baselineTagIndex) const
|
||||
inline int get_h_base_coord(unsigned int baseScriptIndex, unsigned int baselineTagIndex) const
|
||||
{
|
||||
return (this+horizAxis).get_base_coord(baseScriptIndex, baselineTagIndex);
|
||||
return (this+hAxis).get_base_coord(baseScriptIndex, baselineTagIndex);
|
||||
}
|
||||
|
||||
// vertical axis base coords:
|
||||
|
||||
inline unsigned int get_vert_base_tag_index(Tag baselineTag) const
|
||||
inline unsigned int get_v_base_tag_index(Tag baselineTag) const
|
||||
{
|
||||
if (unlikely(vertAxis == Null(OffsetTo<Axis>))) return NOT_INDEXED;
|
||||
return (this+vertAxis).get_base_tag_index(baselineTag);
|
||||
return (this+vAxis).get_base_tag_index(baselineTag);
|
||||
}
|
||||
|
||||
inline unsigned int get_vert_default_base_tag_index_for_script_index (unsigned int baseScriptIndex) const
|
||||
inline unsigned int get_v_default_base_tag_index_for_script_index (unsigned int baseScriptIndex) const
|
||||
{
|
||||
if (unlikely(vertAxis == Null(OffsetTo<Axis>))) return NOT_INDEXED;
|
||||
return (this+vertAxis).get_default_base_tag_index_for_script_index(baseScriptIndex);
|
||||
return (this+vAxis).get_default_base_tag_index_for_script_index(baseScriptIndex);
|
||||
}
|
||||
|
||||
inline int get_vert_base_coord(unsigned int baseScriptIndex, unsigned int baselineTagIndex) const
|
||||
inline int get_v_base_coord(unsigned int baseScriptIndex, unsigned int baselineTagIndex) const
|
||||
{
|
||||
return (this+vertAxis).get_base_coord(baseScriptIndex, baselineTagIndex);
|
||||
return (this+vAxis).get_base_coord(baseScriptIndex, baselineTagIndex);
|
||||
}
|
||||
|
||||
// horizontal axis min/max coords:
|
||||
|
||||
inline unsigned int get_horiz_lang_tag_index (unsigned int baseScriptIndex, Tag baseLangSysTag) const
|
||||
inline unsigned int get_h_lang_tag_index (unsigned int baseScriptIndex, Tag baseLangSysTag) const
|
||||
{
|
||||
if (unlikely(horizAxis == Null(OffsetTo<Axis>))) return NOT_INDEXED;
|
||||
return (this+horizAxis).get_lang_tag_index (baseScriptIndex, baseLangSysTag);
|
||||
return (this+hAxis).get_lang_tag_index (baseScriptIndex, baseLangSysTag);
|
||||
}
|
||||
|
||||
inline unsigned int get_horiz_feature_tag_index (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, Tag featureTableTag) const
|
||||
inline unsigned int get_h_feature_tag_index (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, Tag featureTableTag) const
|
||||
{
|
||||
if (unlikely(horizAxis == Null(OffsetTo<Axis>))) return NOT_INDEXED;
|
||||
return (this+horizAxis).get_feature_tag_index (baseScriptIndex, baseLangSysIndex, featureTableTag);
|
||||
return (this+hAxis).get_feature_tag_index (baseScriptIndex, baseLangSysIndex, featureTableTag);
|
||||
}
|
||||
|
||||
inline int get_horiz_max_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
|
||||
inline int get_h_max_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
|
||||
{
|
||||
return (this+horizAxis).get_max_value (baseScriptIndex, baseLangSysIndex, featureTableTagIndex);
|
||||
return (this+hAxis).get_max_value (baseScriptIndex, baseLangSysIndex, featureTableTagIndex);
|
||||
}
|
||||
|
||||
inline int get_horiz_min_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
|
||||
inline int get_h_min_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
|
||||
{
|
||||
return (this+horizAxis).get_min_value (baseScriptIndex, baseLangSysIndex, featureTableTagIndex);
|
||||
return (this+hAxis).get_min_value (baseScriptIndex, baseLangSysIndex, featureTableTagIndex);
|
||||
}
|
||||
|
||||
// vertical axis min/max coords:
|
||||
|
||||
inline unsigned int get_vert_lang_tag_index (unsigned int baseScriptIndex, Tag baseLangSysTag) const
|
||||
inline unsigned int get_v_lang_tag_index (unsigned int baseScriptIndex, Tag baseLangSysTag) const
|
||||
{
|
||||
if (unlikely(vertAxis == Null(OffsetTo<Axis>))) return NOT_INDEXED;
|
||||
return (this+vertAxis).get_lang_tag_index (baseScriptIndex, baseLangSysTag);
|
||||
return (this+vAxis).get_lang_tag_index (baseScriptIndex, baseLangSysTag);
|
||||
}
|
||||
|
||||
inline unsigned int get_vert_feature_tag_index (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, Tag featureTableTag) const
|
||||
inline unsigned int get_v_feature_tag_index (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, Tag featureTableTag) const
|
||||
{
|
||||
if (unlikely(vertAxis == Null(OffsetTo<Axis>))) return NOT_INDEXED;
|
||||
return (this+vertAxis).get_feature_tag_index (baseScriptIndex, baseLangSysIndex, featureTableTag);
|
||||
return (this+vAxis).get_feature_tag_index (baseScriptIndex, baseLangSysIndex, featureTableTag);
|
||||
}
|
||||
|
||||
inline int get_vert_max_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
|
||||
inline int get_v_max_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
|
||||
{
|
||||
return (this+vertAxis).get_max_value (baseScriptIndex, baseLangSysIndex, featureTableTagIndex);
|
||||
return (this+vAxis).get_max_value (baseScriptIndex, baseLangSysIndex, featureTableTagIndex);
|
||||
}
|
||||
|
||||
inline int get_vert_min_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
|
||||
inline int get_v_min_value (unsigned int baseScriptIndex, unsigned int baseLangSysIndex, unsigned int featureTableTagIndex) const
|
||||
{
|
||||
return (this+vertAxis).get_min_value (baseScriptIndex, baseLangSysIndex, featureTableTagIndex);
|
||||
return (this+vAxis).get_min_value (baseScriptIndex, baseLangSysIndex, featureTableTagIndex);
|
||||
}
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
|
@ -631,15 +604,15 @@ struct BASE
|
|||
TRACE_SANITIZE (this);
|
||||
return_trace (c->check_struct (this) &&
|
||||
likely (version.major == 1) &&
|
||||
horizAxis.sanitize (c, this) &&
|
||||
vertAxis.sanitize (c, this) &&
|
||||
hAxis.sanitize (c, this) &&
|
||||
vAxis.sanitize (c, this) &&
|
||||
(version.to_int () < 0x00010001u || varStore.sanitize (c, this)));
|
||||
}
|
||||
|
||||
protected:
|
||||
FixedVersion<> version;
|
||||
OffsetTo<Axis> horizAxis;
|
||||
OffsetTo<Axis> vertAxis;
|
||||
OffsetTo<Axis> hAxis;
|
||||
OffsetTo<Axis> vAxis;
|
||||
LOffsetTo<VariationStore>
|
||||
varStore; /* Offset to the table of Item Variation
|
||||
* Store--from beginning of BASE
|
||||
|
|
|
@ -41,6 +41,15 @@
|
|||
#ifndef HB_MAX_CONTEXT_LENGTH
|
||||
#define HB_MAX_CONTEXT_LENGTH 64
|
||||
#endif
|
||||
#ifndef HB_CLOSURE_MAX_STAGES
|
||||
/*
|
||||
* The maximum number of times a lookup can be applied during shaping.
|
||||
* Used to limit the number of iterations of the closure algorithm.
|
||||
* This must be larger than the number of times add_pause() is
|
||||
* called in a collect_features call of any shaper.
|
||||
*/
|
||||
#define HB_CLOSURE_MAX_STAGES 32
|
||||
#endif
|
||||
|
||||
|
||||
namespace OT {
|
||||
|
@ -164,7 +173,7 @@ struct RangeRecord
|
|||
public:
|
||||
DEFINE_SIZE_STATIC (6);
|
||||
};
|
||||
DEFINE_NULL_DATA (OT, RangeRecord, "\000\001");
|
||||
DECLARE_NULL_NAMESPACE_BYTES (OT, RangeRecord);
|
||||
|
||||
|
||||
struct IndexArray : ArrayOf<Index>
|
||||
|
@ -181,6 +190,11 @@ struct IndexArray : ArrayOf<Index>
|
|||
}
|
||||
return this->len;
|
||||
}
|
||||
|
||||
inline void add_indexes_to (hb_set_t* output /* OUT */) const
|
||||
{
|
||||
output->add_array (arrayZ, len);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -199,6 +213,8 @@ struct LangSys
|
|||
unsigned int *feature_count /* IN/OUT */,
|
||||
unsigned int *feature_indexes /* OUT */) const
|
||||
{ return featureIndex.get_indexes (start_offset, feature_count, feature_indexes); }
|
||||
inline void add_feature_indexes_to (hb_set_t *feature_indexes) const
|
||||
{ featureIndex.add_indexes_to (feature_indexes); }
|
||||
|
||||
inline bool has_required_feature (void) const { return reqFeatureIndex != 0xFFFFu; }
|
||||
inline unsigned int get_required_feature_index (void) const
|
||||
|
@ -224,8 +240,7 @@ struct LangSys
|
|||
public:
|
||||
DEFINE_SIZE_ARRAY (6, featureIndex);
|
||||
};
|
||||
DEFINE_NULL_DATA (OT, LangSys, "\0\0\xFF\xFF");
|
||||
|
||||
DECLARE_NULL_NAMESPACE_BYTES (OT, LangSys);
|
||||
|
||||
struct Script
|
||||
{
|
||||
|
@ -540,9 +555,6 @@ struct Feature
|
|||
c->try_set (&featureParams, new_offset) &&
|
||||
!featureParams.sanitize (c, this, closure ? closure->tag : HB_TAG_NONE))
|
||||
return_trace (false);
|
||||
|
||||
if (c->edit_count > 1)
|
||||
c->edit_count--; /* This was a "legitimate" edit; don't contribute to error count. */
|
||||
}
|
||||
|
||||
return_trace (true);
|
||||
|
@ -597,6 +609,14 @@ struct Lookup
|
|||
inline OffsetArrayOf<SubTableType>& get_subtables (void)
|
||||
{ return CastR<OffsetArrayOf<SubTableType> > (subTable); }
|
||||
|
||||
inline unsigned int get_size (void) const
|
||||
{
|
||||
const HBUINT16 &markFilteringSet = StructAfter<const HBUINT16> (subTable);
|
||||
if (lookupFlag & LookupFlag::UseMarkFilteringSet)
|
||||
return (const char *) &StructAfter<const char> (markFilteringSet) - (const char *) this;
|
||||
return (const char *) &markFilteringSet - (const char *) this;
|
||||
}
|
||||
|
||||
inline unsigned int get_type (void) const { return lookupType; }
|
||||
|
||||
/* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
|
||||
|
@ -639,6 +659,7 @@ struct Lookup
|
|||
if (unlikely (!subTable.serialize (c, num_subtables))) return_trace (false);
|
||||
if (lookupFlag & LookupFlag::UseMarkFilteringSet)
|
||||
{
|
||||
if (unlikely (!c->extend (*this))) return_trace (false);
|
||||
HBUINT16 &markFilteringSet = StructAfter<HBUINT16> (subTable);
|
||||
markFilteringSet.set (lookup_props >> 16);
|
||||
}
|
||||
|
|
|
@ -349,6 +349,7 @@ struct GDEF
|
|||
ComponentGlyph = 4
|
||||
};
|
||||
|
||||
inline bool has_data (void) const { return version.to_int () != 0; }
|
||||
inline bool has_glyph_classes (void) const { return glyphClassDef != 0; }
|
||||
inline unsigned int get_glyph_class (hb_codepoint_t glyph) const
|
||||
{ return (this+glyphClassDef).get_class (glyph); }
|
||||
|
|
|
@ -1628,14 +1628,14 @@ GPOS::position_finish_offsets (hb_font_t *font HB_UNUSED, hb_buffer_t *buffer)
|
|||
template <typename context_t>
|
||||
/*static*/ inline typename context_t::return_t PosLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
|
||||
{
|
||||
const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
|
||||
const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->table.GPOS);
|
||||
const PosLookup &l = gpos.get_lookup (lookup_index);
|
||||
return l.dispatch (c);
|
||||
}
|
||||
|
||||
/*static*/ inline bool PosLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
|
||||
{
|
||||
const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->gpos);
|
||||
const GPOS &gpos = *(hb_ot_layout_from_face (c->face)->table.GPOS);
|
||||
const PosLookup &l = gpos.get_lookup (lookup_index);
|
||||
unsigned int saved_lookup_props = c->lookup_props;
|
||||
unsigned int saved_lookup_index = c->lookup_index;
|
||||
|
|
|
@ -47,7 +47,7 @@ struct SingleSubstFormat1
|
|||
* https://github.com/harfbuzz/harfbuzz/issues/363 */
|
||||
hb_codepoint_t glyph_id = iter.get_glyph ();
|
||||
if (c->glyphs->has (glyph_id))
|
||||
c->glyphs->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
|
||||
c->out->add ((glyph_id + deltaGlyphID) & 0xFFFFu);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,7 +132,7 @@ struct SingleSubstFormat2
|
|||
if (unlikely (iter.get_coverage () >= count))
|
||||
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
|
||||
if (c->glyphs->has (iter.get_glyph ()))
|
||||
c->glyphs->add (substitute[iter.get_coverage ()]);
|
||||
c->out->add (substitute[iter.get_coverage ()]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -263,7 +263,7 @@ struct Sequence
|
|||
TRACE_CLOSURE (this);
|
||||
unsigned int count = substitute.len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
c->glyphs->add (substitute[i]);
|
||||
c->out->add (substitute[i]);
|
||||
}
|
||||
|
||||
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
||||
|
@ -464,7 +464,7 @@ struct AlternateSubstFormat1
|
|||
const AlternateSet &alt_set = this+alternateSet[iter.get_coverage ()];
|
||||
unsigned int count = alt_set.len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
c->glyphs->add (alt_set[i]);
|
||||
c->out->add (alt_set[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -605,7 +605,7 @@ struct Ligature
|
|||
for (unsigned int i = 1; i < count; i++)
|
||||
if (!c->glyphs->has (component[i]))
|
||||
return;
|
||||
c->glyphs->add (ligGlyph);
|
||||
c->out->add (ligGlyph);
|
||||
}
|
||||
|
||||
inline void collect_glyphs (hb_collect_glyphs_context_t *c) const
|
||||
|
@ -957,7 +957,7 @@ struct ReverseChainSingleSubstFormat1
|
|||
if (unlikely (iter.get_coverage () >= count))
|
||||
break; /* Work around malicious fonts. https://github.com/harfbuzz/harfbuzz/issues/363 */
|
||||
if (c->glyphs->has (iter.get_glyph ()))
|
||||
c->glyphs->add (substitute[iter.get_coverage ()]);
|
||||
c->out->add (substitute[iter.get_coverage ()]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1163,7 +1163,12 @@ struct SubstLookup : Lookup
|
|||
return_trace (HB_VOID);
|
||||
|
||||
c->set_recurse_func (dispatch_closure_recurse_func);
|
||||
return_trace (dispatch (c));
|
||||
|
||||
hb_closure_context_t::return_t ret = dispatch (c);
|
||||
|
||||
c->flush ();
|
||||
|
||||
return_trace (ret);
|
||||
}
|
||||
|
||||
inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
|
||||
|
@ -1265,7 +1270,12 @@ struct SubstLookup : Lookup
|
|||
{
|
||||
if (!c->should_visit_lookup (lookup_index))
|
||||
return HB_VOID;
|
||||
return dispatch_recurse_func (c, lookup_index);
|
||||
|
||||
hb_closure_context_t::return_t ret = dispatch_recurse_func (c, lookup_index);
|
||||
|
||||
c->flush ();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename context_t>
|
||||
|
@ -1325,7 +1335,7 @@ GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
|
|||
{
|
||||
_hb_buffer_assert_gsubgpos_vars (buffer);
|
||||
|
||||
const GDEF &gdef = *hb_ot_layout_from_face (font->face)->gdef;
|
||||
const GDEF &gdef = *hb_ot_layout_from_face (font->face)->table.GDEF;
|
||||
unsigned int count = buffer->len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
|
@ -1349,14 +1359,14 @@ GSUB::substitute_start (hb_font_t *font, hb_buffer_t *buffer)
|
|||
template <typename context_t>
|
||||
/*static*/ inline typename context_t::return_t SubstLookup::dispatch_recurse_func (context_t *c, unsigned int lookup_index)
|
||||
{
|
||||
const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
|
||||
const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->table.GSUB);
|
||||
const SubstLookup &l = gsub.get_lookup (lookup_index);
|
||||
return l.dispatch (c);
|
||||
}
|
||||
|
||||
/*static*/ inline bool SubstLookup::apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index)
|
||||
{
|
||||
const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->gsub);
|
||||
const GSUB &gsub = *(hb_ot_layout_from_face (c->face)->table.GSUB);
|
||||
const SubstLookup &l = gsub.get_lookup (lookup_index);
|
||||
unsigned int saved_lookup_props = c->lookup_props;
|
||||
unsigned int saved_lookup_index = c->lookup_index;
|
||||
|
|
|
@ -69,12 +69,13 @@ struct hb_closure_context_t :
|
|||
|
||||
bool is_lookup_done (unsigned int lookup_index)
|
||||
{
|
||||
// Have we visited this lookup with the current set of glyphs?
|
||||
/* Have we visited this lookup with the current set of glyphs? */
|
||||
return done_lookups->get (lookup_index) == glyphs->get_population ();
|
||||
}
|
||||
|
||||
hb_face_t *face;
|
||||
hb_set_t *glyphs;
|
||||
hb_auto_t<hb_set_t> out[1];
|
||||
recurse_func_t recurse_func;
|
||||
unsigned int nesting_level_left;
|
||||
unsigned int debug_depth;
|
||||
|
@ -90,8 +91,19 @@ struct hb_closure_context_t :
|
|||
debug_depth (0),
|
||||
done_lookups (done_lookups_) {}
|
||||
|
||||
~hb_closure_context_t (void)
|
||||
{
|
||||
flush ();
|
||||
}
|
||||
|
||||
void set_recurse_func (recurse_func_t func) { recurse_func = func; }
|
||||
|
||||
void flush (void)
|
||||
{
|
||||
hb_set_union (glyphs, out);
|
||||
hb_set_clear (out);
|
||||
}
|
||||
|
||||
private:
|
||||
hb_map_t *done_lookups;
|
||||
};
|
||||
|
@ -468,7 +480,7 @@ struct hb_ot_apply_context_t :
|
|||
iter_input (), iter_context (),
|
||||
font (font_), face (font->face), buffer (buffer_),
|
||||
recurse_func (nullptr),
|
||||
gdef (*hb_ot_layout_from_face (face)->gdef),
|
||||
gdef (*hb_ot_layout_from_face (face)->table.GDEF),
|
||||
var_store (gdef.get_var_store ()),
|
||||
direction (buffer_->props.direction),
|
||||
lookup_mask (1),
|
||||
|
@ -2308,6 +2320,7 @@ struct Extension
|
|||
|
||||
struct GSUBGPOS
|
||||
{
|
||||
inline bool has_data (void) const { return version.to_int () != 0; }
|
||||
inline unsigned int get_script_count (void) const
|
||||
{ return (this+scriptList).len; }
|
||||
inline const Tag& get_script_tag (unsigned int i) const
|
||||
|
|
|
@ -121,25 +121,6 @@ hb_ot_layout_position_finish_offsets (hb_font_t *font,
|
|||
* hb_ot_layout_t
|
||||
*/
|
||||
|
||||
namespace OT {
|
||||
struct BASE;
|
||||
struct COLR;
|
||||
struct CPAL;
|
||||
struct GDEF;
|
||||
struct GSUB;
|
||||
struct GPOS;
|
||||
struct MATH;
|
||||
struct fvar;
|
||||
struct avar;
|
||||
}
|
||||
|
||||
namespace AAT {
|
||||
struct ankr;
|
||||
struct kerx;
|
||||
struct morx;
|
||||
struct trak;
|
||||
}
|
||||
|
||||
struct hb_ot_layout_lookup_accelerator_t
|
||||
{
|
||||
template <typename TLookup>
|
||||
|
@ -161,27 +142,73 @@ struct hb_ot_layout_lookup_accelerator_t
|
|||
hb_set_digest_t digest;
|
||||
};
|
||||
|
||||
/* Most of these tables are NOT needed for shaping. But we need to hook them *somewhere*.
|
||||
* This is as good as any place. */
|
||||
#define HB_OT_LAYOUT_TABLES \
|
||||
/* OpenType shaping. */ \
|
||||
HB_OT_LAYOUT_TABLE(OT, GDEF) \
|
||||
HB_OT_LAYOUT_TABLE(OT, GSUB) \
|
||||
HB_OT_LAYOUT_TABLE(OT, GPOS) \
|
||||
HB_OT_LAYOUT_TABLE(OT, JSTF) \
|
||||
HB_OT_LAYOUT_TABLE(OT, BASE) \
|
||||
/* AAT shaping. */ \
|
||||
HB_OT_LAYOUT_TABLE(AAT, morx) \
|
||||
HB_OT_LAYOUT_TABLE(AAT, kerx) \
|
||||
HB_OT_LAYOUT_TABLE(AAT, ankr) \
|
||||
HB_OT_LAYOUT_TABLE(AAT, trak) \
|
||||
/* OpenType variations. */ \
|
||||
HB_OT_LAYOUT_TABLE(OT, fvar) \
|
||||
HB_OT_LAYOUT_TABLE(OT, avar) \
|
||||
HB_OT_LAYOUT_TABLE(OT, MVAR) \
|
||||
/* OpenType color. */ \
|
||||
HB_OT_LAYOUT_TABLE(OT, COLR) \
|
||||
HB_OT_LAYOUT_TABLE(OT, CPAL) \
|
||||
HB_OT_LAYOUT_TABLE(OT, CBDT) \
|
||||
HB_OT_LAYOUT_TABLE(OT, CBLC) \
|
||||
HB_OT_LAYOUT_TABLE(OT, sbix) \
|
||||
HB_OT_LAYOUT_TABLE(OT, svg) \
|
||||
/* OpenType math. */ \
|
||||
HB_OT_LAYOUT_TABLE(OT, MATH) \
|
||||
/* OpenType fundamentals. */ \
|
||||
HB_OT_LAYOUT_TABLE(OT, post) \
|
||||
/* */
|
||||
|
||||
/* Declare tables. */
|
||||
#define HB_OT_LAYOUT_TABLE(Namespace, Type) namespace Namespace { struct Type; }
|
||||
HB_OT_LAYOUT_TABLES
|
||||
#undef HB_OT_LAYOUT_TABLE
|
||||
|
||||
struct hb_ot_layout_t
|
||||
{
|
||||
hb_blob_t *gdef_blob;
|
||||
hb_blob_t *gsub_blob;
|
||||
hb_blob_t *gpos_blob;
|
||||
|
||||
const struct OT::GDEF *gdef;
|
||||
const struct OT::GSUB *gsub;
|
||||
const struct OT::GPOS *gpos;
|
||||
|
||||
/* TODO Move the following out of this struct. */
|
||||
OT::hb_table_lazy_loader_t<struct OT::BASE> base;
|
||||
OT::hb_table_lazy_loader_t<struct OT::MATH> math;
|
||||
OT::hb_table_lazy_loader_t<struct OT::fvar> fvar;
|
||||
OT::hb_table_lazy_loader_t<struct OT::avar> avar;
|
||||
|
||||
unsigned int gsub_lookup_count;
|
||||
unsigned int gpos_lookup_count;
|
||||
|
||||
hb_ot_layout_lookup_accelerator_t *gsub_accels;
|
||||
hb_ot_layout_lookup_accelerator_t *gpos_accels;
|
||||
|
||||
/* Various non-shaping tables. */
|
||||
struct tables_t
|
||||
{
|
||||
HB_INTERNAL void init0 (hb_face_t *face);
|
||||
HB_INTERNAL void fini (void);
|
||||
|
||||
#define HB_OT_LAYOUT_TABLE_ORDER(Namespace, Type) \
|
||||
HB_PASTE (ORDER_, HB_PASTE (Namespace, HB_PASTE (_, Type)))
|
||||
enum order_t
|
||||
{
|
||||
ORDER_ZERO,
|
||||
#define HB_OT_LAYOUT_TABLE(Namespace, Type) \
|
||||
HB_OT_LAYOUT_TABLE_ORDER (Namespace, Type),
|
||||
HB_OT_LAYOUT_TABLES
|
||||
#undef HB_OT_LAYOUT_TABLE
|
||||
};
|
||||
|
||||
hb_face_t *face; /* MUST be JUST before the lazy loaders. */
|
||||
#define HB_OT_LAYOUT_TABLE(Namespace, Type) \
|
||||
hb_table_lazy_loader_t<HB_OT_LAYOUT_TABLE_ORDER (Namespace, Type), struct Namespace::Type> Type;
|
||||
HB_OT_LAYOUT_TABLES
|
||||
#undef HB_OT_LAYOUT_TABLE
|
||||
} table;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "hb-open-type-private.hh"
|
||||
#include "hb-ot-layout-private.hh"
|
||||
#include "hb-ot-map-private.hh"
|
||||
#include "hb-map-private.hh"
|
||||
|
||||
#include "hb-ot-layout-gdef-table.hh"
|
||||
#include "hb-ot-layout-gsub-table.hh"
|
||||
|
@ -44,9 +45,124 @@
|
|||
#include "hb-ot-color-sbix-table.hh"
|
||||
#include "hb-ot-color-svg-table.hh"
|
||||
#include "hb-ot-name-table.hh"
|
||||
#include "hb-map-private.hh"
|
||||
|
||||
|
||||
static bool
|
||||
_hb_ot_blacklist_gdef (unsigned int gdef_len,
|
||||
unsigned int gsub_len,
|
||||
unsigned int gpos_len)
|
||||
{
|
||||
/* The ugly business of blacklisting individual fonts' tables happen here!
|
||||
* See this thread for why we finally had to bend in and do this:
|
||||
* https://lists.freedesktop.org/archives/harfbuzz/2016-February/005489.html
|
||||
*
|
||||
* In certain versions of Times New Roman Italic and Bold Italic,
|
||||
* ASCII double quotation mark U+0022 has wrong glyph class 3 (mark)
|
||||
* in GDEF. Many versions of Tahoma have bad GDEF tables that
|
||||
* incorrectly classify some spacing marks such as certain IPA
|
||||
* symbols as glyph class 3. So do older versions of Microsoft
|
||||
* Himalaya, and the version of Cantarell shipped by Ubuntu 16.04.
|
||||
*
|
||||
* Nuke the GDEF tables of to avoid unwanted width-zeroing.
|
||||
*
|
||||
* See https://bugzilla.mozilla.org/show_bug.cgi?id=1279925
|
||||
* https://bugzilla.mozilla.org/show_bug.cgi?id=1279693
|
||||
* https://bugzilla.mozilla.org/show_bug.cgi?id=1279875
|
||||
*/
|
||||
#define ENCODE(x,y,z) ((int64_t) (x) << 32 | (int64_t) (y) << 16 | (z))
|
||||
switch ENCODE(gdef_len, gsub_len, gpos_len)
|
||||
{
|
||||
/* sha1sum:c5ee92f0bca4bfb7d06c4d03e8cf9f9cf75d2e8a Windows 7? timesi.ttf */
|
||||
case ENCODE (442, 2874, 42038):
|
||||
/* sha1sum:37fc8c16a0894ab7b749e35579856c73c840867b Windows 7? timesbi.ttf */
|
||||
case ENCODE (430, 2874, 40662):
|
||||
/* sha1sum:19fc45110ea6cd3cdd0a5faca256a3797a069a80 Windows 7 timesi.ttf */
|
||||
case ENCODE (442, 2874, 39116):
|
||||
/* sha1sum:6d2d3c9ed5b7de87bc84eae0df95ee5232ecde26 Windows 7 timesbi.ttf */
|
||||
case ENCODE (430, 2874, 39374):
|
||||
/* sha1sum:8583225a8b49667c077b3525333f84af08c6bcd8 OS X 10.11.3 Times New Roman Italic.ttf */
|
||||
case ENCODE (490, 3046, 41638):
|
||||
/* sha1sum:ec0f5a8751845355b7c3271d11f9918a966cb8c9 OS X 10.11.3 Times New Roman Bold Italic.ttf */
|
||||
case ENCODE (478, 3046, 41902):
|
||||
/* sha1sum:96eda93f7d33e79962451c6c39a6b51ee893ce8c tahoma.ttf from Windows 8 */
|
||||
case ENCODE (898, 12554, 46470):
|
||||
/* sha1sum:20928dc06014e0cd120b6fc942d0c3b1a46ac2bc tahomabd.ttf from Windows 8 */
|
||||
case ENCODE (910, 12566, 47732):
|
||||
/* sha1sum:4f95b7e4878f60fa3a39ca269618dfde9721a79e tahoma.ttf from Windows 8.1 */
|
||||
case ENCODE (928, 23298, 59332):
|
||||
/* sha1sum:6d400781948517c3c0441ba42acb309584b73033 tahomabd.ttf from Windows 8.1 */
|
||||
case ENCODE (940, 23310, 60732):
|
||||
/* tahoma.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
|
||||
case ENCODE (964, 23836, 60072):
|
||||
/* tahomabd.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
|
||||
case ENCODE (976, 23832, 61456):
|
||||
/* sha1sum:e55fa2dfe957a9f7ec26be516a0e30b0c925f846 tahoma.ttf from Windows 10 */
|
||||
case ENCODE (994, 24474, 60336):
|
||||
/* sha1sum:7199385abb4c2cc81c83a151a7599b6368e92343 tahomabd.ttf from Windows 10 */
|
||||
case ENCODE (1006, 24470, 61740):
|
||||
/* tahoma.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
|
||||
case ENCODE (1006, 24576, 61346):
|
||||
/* tahomabd.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
|
||||
case ENCODE (1018, 24572, 62828):
|
||||
/* sha1sum:b9c84d820c49850d3d27ec498be93955b82772b5 tahoma.ttf from Windows 10 AU */
|
||||
case ENCODE (1006, 24576, 61352):
|
||||
/* sha1sum:2bdfaab28174bdadd2f3d4200a30a7ae31db79d2 tahomabd.ttf from Windows 10 AU */
|
||||
case ENCODE (1018, 24572, 62834):
|
||||
/* sha1sum:b0d36cf5a2fbe746a3dd277bffc6756a820807a7 Tahoma.ttf from Mac OS X 10.9 */
|
||||
case ENCODE (832, 7324, 47162):
|
||||
/* sha1sum:12fc4538e84d461771b30c18b5eb6bd434e30fba Tahoma Bold.ttf from Mac OS X 10.9 */
|
||||
case ENCODE (844, 7302, 45474):
|
||||
/* sha1sum:eb8afadd28e9cf963e886b23a30b44ab4fd83acc himalaya.ttf from Windows 7 */
|
||||
case ENCODE (180, 13054, 7254):
|
||||
/* sha1sum:73da7f025b238a3f737aa1fde22577a6370f77b0 himalaya.ttf from Windows 8 */
|
||||
case ENCODE (192, 12638, 7254):
|
||||
/* sha1sum:6e80fd1c0b059bbee49272401583160dc1e6a427 himalaya.ttf from Windows 8.1 */
|
||||
case ENCODE (192, 12690, 7254):
|
||||
/* 8d9267aea9cd2c852ecfb9f12a6e834bfaeafe44 cantarell-fonts-0.0.21/otf/Cantarell-Regular.otf */
|
||||
/* 983988ff7b47439ab79aeaf9a45bd4a2c5b9d371 cantarell-fonts-0.0.21/otf/Cantarell-Oblique.otf */
|
||||
case ENCODE (188, 248, 3852):
|
||||
/* 2c0c90c6f6087ffbfea76589c93113a9cbb0e75f cantarell-fonts-0.0.21/otf/Cantarell-Bold.otf */
|
||||
/* 55461f5b853c6da88069ffcdf7f4dd3f8d7e3e6b cantarell-fonts-0.0.21/otf/Cantarell-Bold-Oblique.otf */
|
||||
case ENCODE (188, 264, 3426):
|
||||
/* d125afa82a77a6475ac0e74e7c207914af84b37a padauk-2.80/Padauk.ttf RHEL 7.2 */
|
||||
case ENCODE (1058, 47032, 11818):
|
||||
/* 0f7b80437227b90a577cc078c0216160ae61b031 padauk-2.80/Padauk-Bold.ttf RHEL 7.2*/
|
||||
case ENCODE (1046, 47030, 12600):
|
||||
/* d3dde9aa0a6b7f8f6a89ef1002e9aaa11b882290 padauk-2.80/Padauk.ttf Ubuntu 16.04 */
|
||||
case ENCODE (1058, 71796, 16770):
|
||||
/* 5f3c98ccccae8a953be2d122c1b3a77fd805093f padauk-2.80/Padauk-Bold.ttf Ubuntu 16.04 */
|
||||
case ENCODE (1046, 71790, 17862):
|
||||
/* 6c93b63b64e8b2c93f5e824e78caca555dc887c7 padauk-2.80/Padauk-book.ttf */
|
||||
case ENCODE (1046, 71788, 17112):
|
||||
/* d89b1664058359b8ec82e35d3531931125991fb9 padauk-2.80/Padauk-bookbold.ttf */
|
||||
case ENCODE (1058, 71794, 17514):
|
||||
/* 824cfd193aaf6234b2b4dc0cf3c6ef576c0d00ef padauk-3.0/Padauk-book.ttf */
|
||||
case ENCODE (1330, 109904, 57938):
|
||||
/* 91fcc10cf15e012d27571e075b3b4dfe31754a8a padauk-3.0/Padauk-bookbold.ttf */
|
||||
case ENCODE (1330, 109904, 58972):
|
||||
/* sha1sum: c26e41d567ed821bed997e937bc0c41435689e85 Padauk.ttf
|
||||
* "Padauk Regular" "Version 2.5", see https://crbug.com/681813 */
|
||||
case ENCODE (1004, 59092, 14836):
|
||||
return true;
|
||||
#undef ENCODE
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void hb_ot_layout_t::tables_t::init0 (hb_face_t *face)
|
||||
{
|
||||
this->face = face;
|
||||
#define HB_OT_LAYOUT_TABLE(Namespace, Type) Type.init0 ();
|
||||
HB_OT_LAYOUT_TABLES
|
||||
#undef HB_OT_LAYOUT_TABLE
|
||||
}
|
||||
void hb_ot_layout_t::tables_t::fini (void)
|
||||
{
|
||||
#define HB_OT_LAYOUT_TABLE(Namespace, Type) Type.fini ();
|
||||
HB_OT_LAYOUT_TABLES
|
||||
#undef HB_OT_LAYOUT_TABLE
|
||||
}
|
||||
|
||||
hb_ot_layout_t *
|
||||
_hb_ot_layout_create (hb_face_t *face)
|
||||
{
|
||||
|
@ -54,143 +170,33 @@ _hb_ot_layout_create (hb_face_t *face)
|
|||
if (unlikely (!layout))
|
||||
return nullptr;
|
||||
|
||||
layout->gdef_blob = OT::Sanitizer<OT::GDEF>().sanitize (face->reference_table (HB_OT_TAG_GDEF));
|
||||
layout->gdef = layout->gdef_blob->as<OT::GDEF> ();
|
||||
layout->table.init0 (face);
|
||||
|
||||
layout->gsub_blob = OT::Sanitizer<OT::GSUB>().sanitize (face->reference_table (HB_OT_TAG_GSUB));
|
||||
layout->gsub = layout->gsub_blob->as<OT::GSUB> ();
|
||||
const OT::GSUB &gsub = *layout->table.GSUB;
|
||||
const OT::GPOS &gpos = *layout->table.GPOS;
|
||||
|
||||
layout->gpos_blob = OT::Sanitizer<OT::GPOS>().sanitize (face->reference_table (HB_OT_TAG_GPOS));
|
||||
layout->gpos = layout->gpos_blob->as<OT::GPOS> ();
|
||||
if (unlikely (_hb_ot_blacklist_gdef (layout->table.GDEF.get_blob ()->length,
|
||||
layout->table.GSUB.get_blob ()->length,
|
||||
layout->table.GPOS.get_blob ()->length)))
|
||||
layout->table.GDEF.set_stored (hb_blob_get_empty ());
|
||||
|
||||
layout->math.init (face);
|
||||
layout->fvar.init (face);
|
||||
layout->avar.init (face);
|
||||
unsigned int gsub_lookup_count = layout->gsub_lookup_count = gsub.get_lookup_count ();
|
||||
unsigned int gpos_lookup_count = layout->gpos_lookup_count = gpos.get_lookup_count ();
|
||||
|
||||
{
|
||||
/*
|
||||
* The ugly business of blacklisting individual fonts' tables happen here!
|
||||
* See this thread for why we finally had to bend in and do this:
|
||||
* https://lists.freedesktop.org/archives/harfbuzz/2016-February/005489.html
|
||||
*/
|
||||
unsigned int gdef_len = layout->gdef_blob->length;
|
||||
unsigned int gsub_len = layout->gsub_blob->length;
|
||||
unsigned int gpos_len = layout->gpos_blob->length;
|
||||
if (0
|
||||
/* sha1sum:c5ee92f0bca4bfb7d06c4d03e8cf9f9cf75d2e8a Windows 7? timesi.ttf */
|
||||
|| (442 == gdef_len && 42038 == gpos_len && 2874 == gsub_len)
|
||||
/* sha1sum:37fc8c16a0894ab7b749e35579856c73c840867b Windows 7? timesbi.ttf */
|
||||
|| (430 == gdef_len && 40662 == gpos_len && 2874 == gsub_len)
|
||||
/* sha1sum:19fc45110ea6cd3cdd0a5faca256a3797a069a80 Windows 7 timesi.ttf */
|
||||
|| (442 == gdef_len && 39116 == gpos_len && 2874 == gsub_len)
|
||||
/* sha1sum:6d2d3c9ed5b7de87bc84eae0df95ee5232ecde26 Windows 7 timesbi.ttf */
|
||||
|| (430 == gdef_len && 39374 == gpos_len && 2874 == gsub_len)
|
||||
/* sha1sum:8583225a8b49667c077b3525333f84af08c6bcd8 OS X 10.11.3 Times New Roman Italic.ttf */
|
||||
|| (490 == gdef_len && 41638 == gpos_len && 3046 == gsub_len)
|
||||
/* sha1sum:ec0f5a8751845355b7c3271d11f9918a966cb8c9 OS X 10.11.3 Times New Roman Bold Italic.ttf */
|
||||
|| (478 == gdef_len && 41902 == gpos_len && 3046 == gsub_len)
|
||||
)
|
||||
{
|
||||
/* In certain versions of Times New Roman Italic and Bold Italic,
|
||||
* ASCII double quotation mark U+0022, mapped to glyph 5, has wrong
|
||||
* glyph class 3 (mark) in GDEF. Nuke the GDEF to avoid zero-width
|
||||
* double-quote. See:
|
||||
* https://lists.freedesktop.org/archives/harfbuzz/2016-February/005489.html
|
||||
*/
|
||||
if (3 == layout->gdef->get_glyph_class (5))
|
||||
layout->gdef = &Null(OT::GDEF);
|
||||
}
|
||||
else if (0
|
||||
/* sha1sum:96eda93f7d33e79962451c6c39a6b51ee893ce8c tahoma.ttf from Windows 8 */
|
||||
|| (898 == gdef_len && 46470 == gpos_len && 12554 == gsub_len)
|
||||
/* sha1sum:20928dc06014e0cd120b6fc942d0c3b1a46ac2bc tahomabd.ttf from Windows 8 */
|
||||
|| (910 == gdef_len && 47732 == gpos_len && 12566 == gsub_len)
|
||||
/* sha1sum:4f95b7e4878f60fa3a39ca269618dfde9721a79e tahoma.ttf from Windows 8.1 */
|
||||
|| (928 == gdef_len && 59332 == gpos_len && 23298 == gsub_len)
|
||||
/* sha1sum:6d400781948517c3c0441ba42acb309584b73033 tahomabd.ttf from Windows 8.1 */
|
||||
|| (940 == gdef_len && 60732 == gpos_len && 23310 == gsub_len)
|
||||
/* tahoma.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
|
||||
|| (964 == gdef_len && 60072 == gpos_len && 23836 == gsub_len)
|
||||
/* tahomabd.ttf v6.04 from Windows 8.1 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
|
||||
|| (976 == gdef_len && 61456 == gpos_len && 23832 == gsub_len)
|
||||
/* sha1sum:e55fa2dfe957a9f7ec26be516a0e30b0c925f846 tahoma.ttf from Windows 10 */
|
||||
|| (994 == gdef_len && 60336 == gpos_len && 24474 == gsub_len)
|
||||
/* sha1sum:7199385abb4c2cc81c83a151a7599b6368e92343 tahomabd.ttf from Windows 10 */
|
||||
|| (1006 == gdef_len && 61740 == gpos_len && 24470 == gsub_len)
|
||||
/* tahoma.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
|
||||
|| (1006 == gdef_len && 61346 == gpos_len && 24576 == gsub_len)
|
||||
/* tahomabd.ttf v6.91 from Windows 10 x64, see https://bugzilla.mozilla.org/show_bug.cgi?id=1279925 */
|
||||
|| (1018 == gdef_len && 62828 == gpos_len && 24572 == gsub_len)
|
||||
/* sha1sum:b9c84d820c49850d3d27ec498be93955b82772b5 tahoma.ttf from Windows 10 AU */
|
||||
|| (1006 == gdef_len && 61352 == gpos_len && 24576 == gsub_len)
|
||||
/* sha1sum:2bdfaab28174bdadd2f3d4200a30a7ae31db79d2 tahomabd.ttf from Windows 10 AU */
|
||||
|| (1018 == gdef_len && 62834 == gpos_len && 24572 == gsub_len)
|
||||
/* sha1sum:b0d36cf5a2fbe746a3dd277bffc6756a820807a7 Tahoma.ttf from Mac OS X 10.9 */
|
||||
|| (832 == gdef_len && 47162 == gpos_len && 7324 == gsub_len)
|
||||
/* sha1sum:12fc4538e84d461771b30c18b5eb6bd434e30fba Tahoma Bold.ttf from Mac OS X 10.9 */
|
||||
|| (844 == gdef_len && 45474 == gpos_len && 7302 == gsub_len)
|
||||
/* sha1sum:eb8afadd28e9cf963e886b23a30b44ab4fd83acc himalaya.ttf from Windows 7 */
|
||||
|| (180 == gdef_len && 7254 == gpos_len && 13054 == gsub_len)
|
||||
/* sha1sum:73da7f025b238a3f737aa1fde22577a6370f77b0 himalaya.ttf from Windows 8 */
|
||||
|| (192 == gdef_len && 7254 == gpos_len && 12638 == gsub_len)
|
||||
/* sha1sum:6e80fd1c0b059bbee49272401583160dc1e6a427 himalaya.ttf from Windows 8.1 */
|
||||
|| (192 == gdef_len && 7254 == gpos_len && 12690 == gsub_len)
|
||||
/* 8d9267aea9cd2c852ecfb9f12a6e834bfaeafe44 cantarell-fonts-0.0.21/otf/Cantarell-Regular.otf */
|
||||
/* 983988ff7b47439ab79aeaf9a45bd4a2c5b9d371 cantarell-fonts-0.0.21/otf/Cantarell-Oblique.otf */
|
||||
|| (188 == gdef_len && 3852 == gpos_len && 248 == gsub_len)
|
||||
/* 2c0c90c6f6087ffbfea76589c93113a9cbb0e75f cantarell-fonts-0.0.21/otf/Cantarell-Bold.otf */
|
||||
/* 55461f5b853c6da88069ffcdf7f4dd3f8d7e3e6b cantarell-fonts-0.0.21/otf/Cantarell-Bold-Oblique.otf */
|
||||
|| (188 == gdef_len && 3426 == gpos_len && 264 == gsub_len)
|
||||
/* d125afa82a77a6475ac0e74e7c207914af84b37a padauk-2.80/Padauk.ttf RHEL 7.2 */
|
||||
|| (1058 == gdef_len && 11818 == gpos_len && 47032 == gsub_len)
|
||||
/* 0f7b80437227b90a577cc078c0216160ae61b031 padauk-2.80/Padauk-Bold.ttf RHEL 7.2*/
|
||||
|| (1046 == gdef_len && 12600 == gpos_len && 47030 == gsub_len)
|
||||
/* d3dde9aa0a6b7f8f6a89ef1002e9aaa11b882290 padauk-2.80/Padauk.ttf Ubuntu 16.04 */
|
||||
|| (1058 == gdef_len && 16770 == gpos_len && 71796 == gsub_len)
|
||||
/* 5f3c98ccccae8a953be2d122c1b3a77fd805093f padauk-2.80/Padauk-Bold.ttf Ubuntu 16.04 */
|
||||
|| (1046 == gdef_len && 17862 == gpos_len && 71790 == gsub_len)
|
||||
/* 6c93b63b64e8b2c93f5e824e78caca555dc887c7 padauk-2.80/Padauk-book.ttf */
|
||||
|| (1046 == gdef_len && 17112 == gpos_len && 71788 == gsub_len)
|
||||
/* d89b1664058359b8ec82e35d3531931125991fb9 padauk-2.80/Padauk-bookbold.ttf */
|
||||
|| (1058 == gdef_len && 17514 == gpos_len && 71794 == gsub_len)
|
||||
/* 824cfd193aaf6234b2b4dc0cf3c6ef576c0d00ef padauk-3.0/Padauk-book.ttf */
|
||||
|| (1330 == gdef_len && 57938 == gpos_len && 109904 == gsub_len)
|
||||
/* 91fcc10cf15e012d27571e075b3b4dfe31754a8a padauk-3.0/Padauk-bookbold.ttf */
|
||||
|| (1330 == gdef_len && 58972 == gpos_len && 109904 == gsub_len)
|
||||
/* sha1sum: c26e41d567ed821bed997e937bc0c41435689e85 Padauk.ttf
|
||||
* "Padauk Regular" "Version 2.5", see https://crbug.com/681813 */
|
||||
|| (1004 == gdef_len && 14836 == gpos_len && 59092 == gsub_len)
|
||||
)
|
||||
{
|
||||
/* Many versions of Tahoma have bad GDEF tables that incorrectly classify some spacing marks
|
||||
* such as certain IPA symbols as glyph class 3. So do older versions of Microsoft Himalaya,
|
||||
* and the version of Cantarell shipped by Ubuntu 16.04.
|
||||
* Nuke the GDEF tables of these fonts to avoid unwanted width-zeroing.
|
||||
* See https://bugzilla.mozilla.org/show_bug.cgi?id=1279925
|
||||
* https://bugzilla.mozilla.org/show_bug.cgi?id=1279693
|
||||
* https://bugzilla.mozilla.org/show_bug.cgi?id=1279875
|
||||
*/
|
||||
layout->gdef = &Null(OT::GDEF);
|
||||
}
|
||||
}
|
||||
layout->gsub_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (gsub_lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t));
|
||||
layout->gpos_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (gpos_lookup_count, sizeof (hb_ot_layout_lookup_accelerator_t));
|
||||
|
||||
layout->gsub_lookup_count = layout->gsub->get_lookup_count ();
|
||||
layout->gpos_lookup_count = layout->gpos->get_lookup_count ();
|
||||
|
||||
layout->gsub_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gsub->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
|
||||
layout->gpos_accels = (hb_ot_layout_lookup_accelerator_t *) calloc (layout->gpos->get_lookup_count (), sizeof (hb_ot_layout_lookup_accelerator_t));
|
||||
|
||||
if (unlikely ((layout->gsub_lookup_count && !layout->gsub_accels) ||
|
||||
(layout->gpos_lookup_count && !layout->gpos_accels)))
|
||||
if (unlikely ((gsub_lookup_count && !layout->gsub_accels) ||
|
||||
(gpos_lookup_count && !layout->gpos_accels)))
|
||||
{
|
||||
_hb_ot_layout_destroy (layout);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < layout->gsub_lookup_count; i++)
|
||||
layout->gsub_accels[i].init (layout->gsub->get_lookup (i));
|
||||
for (unsigned int i = 0; i < layout->gpos_lookup_count; i++)
|
||||
layout->gpos_accels[i].init (layout->gpos->get_lookup (i));
|
||||
for (unsigned int i = 0; i < gsub_lookup_count; i++)
|
||||
layout->gsub_accels[i].init (gsub.get_lookup (i));
|
||||
for (unsigned int i = 0; i < gpos_lookup_count; i++)
|
||||
layout->gpos_accels[i].init (gpos.get_lookup (i));
|
||||
|
||||
return layout;
|
||||
}
|
||||
|
@ -208,13 +214,7 @@ _hb_ot_layout_destroy (hb_ot_layout_t *layout)
|
|||
free (layout->gsub_accels);
|
||||
free (layout->gpos_accels);
|
||||
|
||||
hb_blob_destroy (layout->gdef_blob);
|
||||
hb_blob_destroy (layout->gsub_blob);
|
||||
hb_blob_destroy (layout->gpos_blob);
|
||||
|
||||
layout->math.fini ();
|
||||
layout->fvar.fini ();
|
||||
layout->avar.fini ();
|
||||
layout->table.fini ();
|
||||
|
||||
free (layout);
|
||||
}
|
||||
|
@ -231,19 +231,19 @@ static inline const OT::GDEF&
|
|||
_get_gdef (hb_face_t *face)
|
||||
{
|
||||
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::GDEF);
|
||||
return *hb_ot_layout_from_face (face)->gdef;
|
||||
return *hb_ot_layout_from_face (face)->table.GDEF;
|
||||
}
|
||||
static inline const OT::GSUB&
|
||||
_get_gsub (hb_face_t *face)
|
||||
{
|
||||
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::GSUB);
|
||||
return *hb_ot_layout_from_face (face)->gsub;
|
||||
return *hb_ot_layout_from_face (face)->table.GSUB;
|
||||
}
|
||||
static inline const OT::GPOS&
|
||||
_get_gpos (hb_face_t *face)
|
||||
{
|
||||
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::GPOS);
|
||||
return *hb_ot_layout_from_face (face)->gpos;
|
||||
return *hb_ot_layout_from_face (face)->table.GPOS;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -518,6 +518,19 @@ hb_ot_layout_language_get_required_feature (hb_face_t *face,
|
|||
return l.has_required_feature ();
|
||||
}
|
||||
|
||||
static void
|
||||
_hb_ot_layout_language_add_feature_indexes_to (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int script_index,
|
||||
unsigned int language_index,
|
||||
hb_set_t *feature_indexes /* OUT */)
|
||||
{
|
||||
const OT::GSUBGPOS &g = get_gsubgpos_table (face, table_tag);
|
||||
const OT::LangSys &l = g.get_script (script_index).get_lang_sys (language_index);
|
||||
l.add_feature_indexes_to (feature_indexes);
|
||||
}
|
||||
|
||||
|
||||
unsigned int
|
||||
hb_ot_layout_language_get_feature_indexes (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
|
@ -656,12 +669,12 @@ _hb_ot_layout_collect_lookups_lookups (hb_face_t *face,
|
|||
}
|
||||
|
||||
static void
|
||||
_hb_ot_layout_collect_lookups_features (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int script_index,
|
||||
unsigned int language_index,
|
||||
const hb_tag_t *features,
|
||||
hb_set_t *lookup_indexes /* OUT */)
|
||||
_hb_ot_layout_collect_features_features (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int script_index,
|
||||
unsigned int language_index,
|
||||
const hb_tag_t *features,
|
||||
hb_set_t *feature_indexes /* OUT */)
|
||||
{
|
||||
if (!features)
|
||||
{
|
||||
|
@ -672,33 +685,14 @@ _hb_ot_layout_collect_lookups_features (hb_face_t *face,
|
|||
language_index,
|
||||
&required_feature_index,
|
||||
nullptr))
|
||||
_hb_ot_layout_collect_lookups_lookups (face,
|
||||
table_tag,
|
||||
required_feature_index,
|
||||
lookup_indexes);
|
||||
feature_indexes->add (required_feature_index);
|
||||
|
||||
/* All features */
|
||||
unsigned int feature_indices[32];
|
||||
unsigned int offset, len;
|
||||
|
||||
offset = 0;
|
||||
do {
|
||||
len = ARRAY_LENGTH (feature_indices);
|
||||
hb_ot_layout_language_get_feature_indexes (face,
|
||||
table_tag,
|
||||
script_index,
|
||||
language_index,
|
||||
offset, &len,
|
||||
feature_indices);
|
||||
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
_hb_ot_layout_collect_lookups_lookups (face,
|
||||
table_tag,
|
||||
feature_indices[i],
|
||||
lookup_indexes);
|
||||
|
||||
offset += len;
|
||||
} while (len == ARRAY_LENGTH (feature_indices));
|
||||
_hb_ot_layout_language_add_feature_indexes_to (face,
|
||||
table_tag,
|
||||
script_index,
|
||||
language_index,
|
||||
feature_indexes);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -711,28 +705,25 @@ _hb_ot_layout_collect_lookups_features (hb_face_t *face,
|
|||
language_index,
|
||||
*features,
|
||||
&feature_index))
|
||||
_hb_ot_layout_collect_lookups_lookups (face,
|
||||
table_tag,
|
||||
feature_index,
|
||||
lookup_indexes);
|
||||
feature_indexes->add (feature_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_hb_ot_layout_collect_lookups_languages (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int script_index,
|
||||
const hb_tag_t *languages,
|
||||
const hb_tag_t *features,
|
||||
hb_set_t *lookup_indexes /* OUT */)
|
||||
_hb_ot_layout_collect_features_languages (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
unsigned int script_index,
|
||||
const hb_tag_t *languages,
|
||||
const hb_tag_t *features,
|
||||
hb_set_t *feature_indexes /* OUT */)
|
||||
{
|
||||
_hb_ot_layout_collect_lookups_features (face,
|
||||
table_tag,
|
||||
script_index,
|
||||
HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
|
||||
features,
|
||||
lookup_indexes);
|
||||
_hb_ot_layout_collect_features_features (face,
|
||||
table_tag,
|
||||
script_index,
|
||||
HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX,
|
||||
features,
|
||||
feature_indexes);
|
||||
|
||||
if (!languages)
|
||||
{
|
||||
|
@ -742,12 +733,12 @@ _hb_ot_layout_collect_lookups_languages (hb_face_t *face,
|
|||
script_index,
|
||||
0, nullptr, nullptr);
|
||||
for (unsigned int language_index = 0; language_index < count; language_index++)
|
||||
_hb_ot_layout_collect_lookups_features (face,
|
||||
table_tag,
|
||||
script_index,
|
||||
language_index,
|
||||
features,
|
||||
lookup_indexes);
|
||||
_hb_ot_layout_collect_features_features (face,
|
||||
table_tag,
|
||||
script_index,
|
||||
language_index,
|
||||
features,
|
||||
feature_indexes);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -759,12 +750,58 @@ _hb_ot_layout_collect_lookups_languages (hb_face_t *face,
|
|||
script_index,
|
||||
*languages,
|
||||
&language_index))
|
||||
_hb_ot_layout_collect_lookups_features (face,
|
||||
table_tag,
|
||||
script_index,
|
||||
language_index,
|
||||
features,
|
||||
lookup_indexes);
|
||||
_hb_ot_layout_collect_features_features (face,
|
||||
table_tag,
|
||||
script_index,
|
||||
language_index,
|
||||
features,
|
||||
feature_indexes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ot_layout_collect_features:
|
||||
*
|
||||
* Since: 1.8.5
|
||||
**/
|
||||
void
|
||||
hb_ot_layout_collect_features (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
const hb_tag_t *scripts,
|
||||
const hb_tag_t *languages,
|
||||
const hb_tag_t *features,
|
||||
hb_set_t *feature_indexes /* OUT */)
|
||||
{
|
||||
if (!scripts)
|
||||
{
|
||||
/* All scripts */
|
||||
unsigned int count = hb_ot_layout_table_get_script_tags (face,
|
||||
table_tag,
|
||||
0, nullptr, nullptr);
|
||||
for (unsigned int script_index = 0; script_index < count; script_index++)
|
||||
_hb_ot_layout_collect_features_languages (face,
|
||||
table_tag,
|
||||
script_index,
|
||||
languages,
|
||||
features,
|
||||
feature_indexes);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; *scripts; scripts++)
|
||||
{
|
||||
unsigned int script_index;
|
||||
if (hb_ot_layout_table_find_script (face,
|
||||
table_tag,
|
||||
*scripts,
|
||||
&script_index))
|
||||
_hb_ot_layout_collect_features_languages (face,
|
||||
table_tag,
|
||||
script_index,
|
||||
languages,
|
||||
features,
|
||||
feature_indexes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -782,37 +819,10 @@ hb_ot_layout_collect_lookups (hb_face_t *face,
|
|||
const hb_tag_t *features,
|
||||
hb_set_t *lookup_indexes /* OUT */)
|
||||
{
|
||||
if (!scripts)
|
||||
{
|
||||
/* All scripts */
|
||||
unsigned int count = hb_ot_layout_table_get_script_tags (face,
|
||||
table_tag,
|
||||
0, nullptr, nullptr);
|
||||
for (unsigned int script_index = 0; script_index < count; script_index++)
|
||||
_hb_ot_layout_collect_lookups_languages (face,
|
||||
table_tag,
|
||||
script_index,
|
||||
languages,
|
||||
features,
|
||||
lookup_indexes);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; *scripts; scripts++)
|
||||
{
|
||||
unsigned int script_index;
|
||||
if (hb_ot_layout_table_find_script (face,
|
||||
table_tag,
|
||||
*scripts,
|
||||
&script_index))
|
||||
_hb_ot_layout_collect_lookups_languages (face,
|
||||
table_tag,
|
||||
script_index,
|
||||
languages,
|
||||
features,
|
||||
lookup_indexes);
|
||||
}
|
||||
}
|
||||
hb_auto_t<hb_set_t> feature_indexes;
|
||||
hb_ot_layout_collect_features (face, table_tag, scripts, languages, features, &feature_indexes);
|
||||
for (hb_codepoint_t feature_index = HB_SET_VALUE_INVALID; hb_set_next (&feature_indexes, &feature_index);)
|
||||
_hb_ot_layout_collect_lookups_lookups (face, table_tag, feature_index, lookup_indexes);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -841,13 +851,13 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t *face,
|
|||
{
|
||||
case HB_OT_TAG_GSUB:
|
||||
{
|
||||
const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
|
||||
const OT::SubstLookup& l = hb_ot_layout_from_face (face)->table.GSUB->get_lookup (lookup_index);
|
||||
l.collect_glyphs (&c);
|
||||
return;
|
||||
}
|
||||
case HB_OT_TAG_GPOS:
|
||||
{
|
||||
const OT::PosLookup& l = hb_ot_layout_from_face (face)->gpos->get_lookup (lookup_index);
|
||||
const OT::PosLookup& l = hb_ot_layout_from_face (face)->table.GPOS->get_lookup (lookup_index);
|
||||
l.collect_glyphs (&c);
|
||||
return;
|
||||
}
|
||||
|
@ -894,7 +904,7 @@ hb_ot_layout_feature_with_variations_get_lookups (hb_face_t *face,
|
|||
hb_bool_t
|
||||
hb_ot_layout_has_substitution (hb_face_t *face)
|
||||
{
|
||||
return &_get_gsub (face) != &Null(OT::GSUB);
|
||||
return _get_gsub (face).has_data ();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -923,7 +933,7 @@ hb_ot_layout_lookup_would_substitute_fast (hb_face_t *face,
|
|||
if (unlikely (lookup_index >= hb_ot_layout_from_face (face)->gsub_lookup_count)) return false;
|
||||
OT::hb_would_apply_context_t c (face, glyphs, glyphs_length, (bool) zero_context);
|
||||
|
||||
const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
|
||||
const OT::SubstLookup& l = hb_ot_layout_from_face (face)->table.GSUB->get_lookup (lookup_index);
|
||||
|
||||
return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index]);
|
||||
}
|
||||
|
@ -969,6 +979,7 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face,
|
|||
OT::hb_closure_context_t c (face, glyphs, &done_lookups);
|
||||
const OT::GSUB& gsub = _get_gsub (face);
|
||||
|
||||
unsigned int iteration_count = 0;
|
||||
unsigned int glyphs_length;
|
||||
do
|
||||
{
|
||||
|
@ -983,7 +994,9 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face,
|
|||
for (unsigned int i = 0; i < gsub.get_lookup_count (); i++)
|
||||
gsub.get_lookup (i).closure (&c, i);
|
||||
}
|
||||
} while (glyphs_length != glyphs->get_population ());
|
||||
iteration_count++;
|
||||
} while (iteration_count <= HB_CLOSURE_MAX_STAGES
|
||||
&& glyphs_length != glyphs->get_population ());
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -993,7 +1006,7 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t *face,
|
|||
hb_bool_t
|
||||
hb_ot_layout_has_positioning (hb_face_t *face)
|
||||
{
|
||||
return &_get_gpos (face) != &Null(OT::GPOS);
|
||||
return _get_gpos (face).has_data ();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1078,7 +1091,7 @@ struct GSUBProxy
|
|||
typedef OT::SubstLookup Lookup;
|
||||
|
||||
GSUBProxy (hb_face_t *face) :
|
||||
table (*hb_ot_layout_from_face (face)->gsub),
|
||||
table (*hb_ot_layout_from_face (face)->table.GSUB),
|
||||
accels (hb_ot_layout_from_face (face)->gsub_accels) {}
|
||||
|
||||
const OT::GSUB &table;
|
||||
|
@ -1092,7 +1105,7 @@ struct GPOSProxy
|
|||
typedef OT::PosLookup Lookup;
|
||||
|
||||
GPOSProxy (hb_face_t *face) :
|
||||
table (*hb_ot_layout_from_face (face)->gpos),
|
||||
table (*hb_ot_layout_from_face (face)->table.GPOS),
|
||||
accels (hb_ot_layout_from_face (face)->gpos_accels) {}
|
||||
|
||||
const OT::GPOS &table;
|
||||
|
@ -1101,7 +1114,7 @@ struct GPOSProxy
|
|||
|
||||
|
||||
struct hb_get_subtables_context_t :
|
||||
OT::hb_dispatch_context_t<hb_get_subtables_context_t, hb_void_t, HB_DEBUG_APPLY>
|
||||
hb_dispatch_context_t<hb_get_subtables_context_t, hb_void_t, HB_DEBUG_APPLY>
|
||||
{
|
||||
template <typename Type>
|
||||
static inline bool apply_to (const void *obj, OT::hb_ot_apply_context_t *c)
|
||||
|
@ -1328,5 +1341,5 @@ hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
|
|||
// hb_bool_t
|
||||
// hb_ot_base_has_data (hb_face_t *face)
|
||||
// {
|
||||
// return &_get_base (face) != &Null(OT::BASE);
|
||||
// return _get_base (face).has_data ();
|
||||
// }
|
||||
|
|
|
@ -194,6 +194,13 @@ HB_EXTERN unsigned int
|
|||
hb_ot_layout_table_get_lookup_count (hb_face_t *face,
|
||||
hb_tag_t table_tag);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_ot_layout_collect_features (hb_face_t *face,
|
||||
hb_tag_t table_tag,
|
||||
const hb_tag_t *scripts,
|
||||
const hb_tag_t *languages,
|
||||
const hb_tag_t *features,
|
||||
hb_set_t *feature_indexes /* OUT */);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_ot_layout_collect_lookups (hb_face_t *face,
|
||||
|
|
|
@ -686,6 +686,8 @@ struct MATH
|
|||
{
|
||||
static const hb_tag_t tableTag = HB_OT_TAG_MATH;
|
||||
|
||||
inline bool has_data (void) const { return version.to_int () != 0; }
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
|
|
@ -34,7 +34,7 @@ _get_math (hb_face_t *face)
|
|||
{
|
||||
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::MATH);
|
||||
hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
|
||||
return *(layout->math.get ());
|
||||
return *(layout->table.MATH.get ());
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -55,7 +55,7 @@ _get_math (hb_face_t *face)
|
|||
hb_bool_t
|
||||
hb_ot_math_has_data (hb_face_t *face)
|
||||
{
|
||||
return &_get_math (face) != &Null(OT::MATH);
|
||||
return _get_math (face).has_data ();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -100,14 +100,14 @@ struct maxp
|
|||
|
||||
inline bool subset (hb_subset_plan_t *plan) const
|
||||
{
|
||||
hb_blob_t *maxp_blob = OT::Sanitizer<OT::maxp>().sanitize (hb_face_reference_table (plan->source, HB_OT_TAG_maxp));
|
||||
hb_blob_t *maxp_blob = hb_sanitize_context_t().reference_table<maxp> (plan->source);
|
||||
hb_blob_t *maxp_prime_blob = hb_blob_copy_writable_or_fail (maxp_blob);
|
||||
hb_blob_destroy (maxp_blob);
|
||||
|
||||
if (unlikely (!maxp_prime_blob)) {
|
||||
return false;
|
||||
}
|
||||
OT::maxp *maxp_prime = (OT::maxp *) hb_blob_get_data (maxp_prime_blob, nullptr);
|
||||
maxp *maxp_prime = (maxp *) hb_blob_get_data (maxp_prime_blob, nullptr);
|
||||
|
||||
maxp_prime->set_num_glyphs (plan->glyphs.len);
|
||||
if (plan->drop_hints)
|
||||
|
@ -118,7 +118,7 @@ struct maxp
|
|||
return result;
|
||||
}
|
||||
|
||||
static inline void drop_hint_fields (hb_subset_plan_t *plan, OT::maxp *maxp_prime)
|
||||
static inline void drop_hint_fields (hb_subset_plan_t *plan, maxp *maxp_prime)
|
||||
{
|
||||
if (maxp_prime->version.major == 1)
|
||||
{
|
||||
|
|
|
@ -51,12 +51,12 @@ struct os2
|
|||
|
||||
inline bool subset (hb_subset_plan_t *plan) const
|
||||
{
|
||||
hb_blob_t *os2_blob = OT::Sanitizer<OT::os2>().sanitize (hb_face_reference_table (plan->source, HB_OT_TAG_os2));
|
||||
hb_blob_t *os2_blob = hb_sanitize_context_t().reference_table<os2> (plan->source);
|
||||
hb_blob_t *os2_prime_blob = hb_blob_create_sub_blob (os2_blob, 0, -1);
|
||||
// TODO(grieger): move to hb_blob_copy_writable_or_fail
|
||||
hb_blob_destroy (os2_blob);
|
||||
|
||||
OT::os2 *os2_prime = (OT::os2 *) hb_blob_get_data_writable (os2_prime_blob, nullptr);
|
||||
os2 *os2_prime = (os2 *) hb_blob_get_data_writable (os2_prime_blob, nullptr);
|
||||
if (unlikely (!os2_prime)) {
|
||||
hb_blob_destroy (os2_prime_blob);
|
||||
return false;
|
||||
|
|
|
@ -85,7 +85,7 @@ struct post
|
|||
inline bool subset (hb_subset_plan_t *plan) const
|
||||
{
|
||||
unsigned int post_prime_length;
|
||||
hb_blob_t *post_blob = OT::Sanitizer<post>().sanitize (hb_face_reference_table (plan->source, HB_OT_TAG_post));
|
||||
hb_blob_t *post_blob = hb_sanitize_context_t().reference_table<post>(plan->source);
|
||||
hb_blob_t *post_prime_blob = hb_blob_create_sub_blob (post_blob, 0, post::static_size);
|
||||
post *post_prime = (post *) hb_blob_get_data_writable (post_prime_blob, &post_prime_length);
|
||||
hb_blob_destroy (post_blob);
|
||||
|
@ -110,7 +110,7 @@ struct post
|
|||
{
|
||||
index_to_offset.init ();
|
||||
|
||||
blob = Sanitizer<post>().sanitize (face->reference_table (HB_OT_TAG_post));
|
||||
blob = hb_sanitize_context_t().reference_table<post> (face);
|
||||
const post *table = blob->as<post> ();
|
||||
unsigned int table_length = blob->length;
|
||||
|
||||
|
|
|
@ -79,12 +79,12 @@ arabic_fallback_synthesize_lookup_single (const hb_ot_shape_plan_t *plan HB_UNUS
|
|||
* May not be good-enough for presidential candidate interviews, but good-enough for us... */
|
||||
hb_stable_sort (&glyphs[0], num_glyphs, (int(*)(const OT::GlyphID*, const OT::GlyphID *)) OT::GlyphID::cmp, &substitutes[0]);
|
||||
|
||||
OT::Supplier<OT::GlyphID> glyphs_supplier (glyphs, num_glyphs);
|
||||
OT::Supplier<OT::GlyphID> substitutes_supplier (substitutes, num_glyphs);
|
||||
Supplier<OT::GlyphID> glyphs_supplier (glyphs, num_glyphs);
|
||||
Supplier<OT::GlyphID> substitutes_supplier (substitutes, num_glyphs);
|
||||
|
||||
/* Each glyph takes four bytes max, and there's some overhead. */
|
||||
char buf[(SHAPING_TABLE_LAST - SHAPING_TABLE_FIRST + 1) * 4 + 128];
|
||||
OT::hb_serialize_context_t c (buf, sizeof (buf));
|
||||
hb_serialize_context_t c (buf, sizeof (buf));
|
||||
OT::SubstLookup *lookup = c.start_serialize<OT::SubstLookup> ();
|
||||
bool ret = lookup->serialize_single (&c,
|
||||
OT::LookupFlag::IgnoreMarks,
|
||||
|
@ -155,15 +155,15 @@ arabic_fallback_synthesize_lookup_ligature (const hb_ot_shape_plan_t *plan HB_UN
|
|||
if (!num_ligatures)
|
||||
return nullptr;
|
||||
|
||||
OT::Supplier<OT::GlyphID> first_glyphs_supplier (first_glyphs, num_first_glyphs);
|
||||
OT::Supplier<unsigned int > ligature_per_first_glyph_count_supplier (ligature_per_first_glyph_count_list, num_first_glyphs);
|
||||
OT::Supplier<OT::GlyphID> ligatures_supplier (ligature_list, num_ligatures);
|
||||
OT::Supplier<unsigned int > component_count_supplier (component_count_list, num_ligatures);
|
||||
OT::Supplier<OT::GlyphID> component_supplier (component_list, num_ligatures);
|
||||
Supplier<OT::GlyphID> first_glyphs_supplier (first_glyphs, num_first_glyphs);
|
||||
Supplier<unsigned int > ligature_per_first_glyph_count_supplier (ligature_per_first_glyph_count_list, num_first_glyphs);
|
||||
Supplier<OT::GlyphID> ligatures_supplier (ligature_list, num_ligatures);
|
||||
Supplier<unsigned int > component_count_supplier (component_count_list, num_ligatures);
|
||||
Supplier<OT::GlyphID> component_supplier (component_list, num_ligatures);
|
||||
|
||||
/* 16 bytes per ligature ought to be enough... */
|
||||
char buf[ARRAY_LENGTH_CONST (ligature_list) * 16 + 128];
|
||||
OT::hb_serialize_context_t c (buf, sizeof (buf));
|
||||
hb_serialize_context_t c (buf, sizeof (buf));
|
||||
OT::SubstLookup *lookup = c.start_serialize<OT::SubstLookup> ();
|
||||
bool ret = lookup->serialize_ligature (&c,
|
||||
OT::LookupFlag::IgnoreMarks,
|
||||
|
@ -205,8 +205,6 @@ struct arabic_fallback_plan_t
|
|||
hb_ot_layout_lookup_accelerator_t accel_array[ARABIC_FALLBACK_MAX_LOOKUPS];
|
||||
};
|
||||
|
||||
static const arabic_fallback_plan_t arabic_fallback_plan_nil = {};
|
||||
|
||||
#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(HB_NO_WIN1256)
|
||||
#define HB_WITH_WIN1256
|
||||
#endif
|
||||
|
@ -215,7 +213,8 @@ static const arabic_fallback_plan_t arabic_fallback_plan_nil = {};
|
|||
#include "hb-ot-shape-complex-arabic-win1256.hh"
|
||||
#endif
|
||||
|
||||
struct ManifestLookup {
|
||||
struct ManifestLookup
|
||||
{
|
||||
OT::Tag tag;
|
||||
OT::OffsetTo<OT::SubstLookup> lookupOffset;
|
||||
};
|
||||
|
@ -299,7 +298,7 @@ arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan,
|
|||
{
|
||||
arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) calloc (1, sizeof (arabic_fallback_plan_t));
|
||||
if (unlikely (!fallback_plan))
|
||||
return const_cast<arabic_fallback_plan_t *> (&arabic_fallback_plan_nil);
|
||||
return const_cast<arabic_fallback_plan_t *> (&Null(arabic_fallback_plan_t));
|
||||
|
||||
fallback_plan->num_lookups = 0;
|
||||
fallback_plan->free_lookups = false;
|
||||
|
@ -314,14 +313,15 @@ arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan,
|
|||
if (arabic_fallback_plan_init_win1256 (fallback_plan, plan, font))
|
||||
return fallback_plan;
|
||||
|
||||
assert (fallback_plan->num_lookups == 0);
|
||||
free (fallback_plan);
|
||||
return const_cast<arabic_fallback_plan_t *> (&arabic_fallback_plan_nil);
|
||||
return const_cast<arabic_fallback_plan_t *> (&Null(arabic_fallback_plan_t));
|
||||
}
|
||||
|
||||
static void
|
||||
arabic_fallback_plan_destroy (arabic_fallback_plan_t *fallback_plan)
|
||||
{
|
||||
if (!fallback_plan || fallback_plan == &arabic_fallback_plan_nil)
|
||||
if (!fallback_plan || fallback_plan->num_lookups == 0)
|
||||
return;
|
||||
|
||||
for (unsigned int i = 0; i < fallback_plan->num_lookups; i++)
|
||||
|
|
|
@ -250,7 +250,7 @@ struct arabic_shape_plan_t
|
|||
* mask_array[NONE] == 0. */
|
||||
hb_mask_t mask_array[ARABIC_NUM_FEATURES + 1];
|
||||
|
||||
arabic_fallback_plan_t *fallback_plan;
|
||||
mutable arabic_fallback_plan_t *fallback_plan;
|
||||
|
||||
unsigned int do_fallback : 1;
|
||||
unsigned int has_stch : 1;
|
||||
|
|
|
@ -300,7 +300,9 @@ static const hb_codepoint_t ra_chars[] = {
|
|||
0x0CB0u, /* Kannada */
|
||||
0x0D30u, /* Malayalam */ /* No Reph, Logical Repha */
|
||||
|
||||
0x0DBBu, /* Sinhala */ /* Reph formed only with ZWJ */
|
||||
0x0DBBu, /* Sinhala */ /* Reph formed only with ZWJ */
|
||||
|
||||
0x179Au, /* Khmer */
|
||||
};
|
||||
|
||||
static inline bool
|
||||
|
|
|
@ -251,10 +251,10 @@ struct indic_shape_plan_t
|
|||
{
|
||||
ASSERT_POD ();
|
||||
|
||||
inline bool get_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const
|
||||
inline bool load_virama_glyph (hb_font_t *font, hb_codepoint_t *pglyph) const
|
||||
{
|
||||
hb_codepoint_t glyph = virama_glyph;
|
||||
if (unlikely (virama_glyph == (hb_codepoint_t) -1))
|
||||
hb_codepoint_t glyph = virama_glyph.get_relaxed ();
|
||||
if (unlikely (glyph == (hb_codepoint_t) -1))
|
||||
{
|
||||
if (!config->virama || !font->get_nominal_glyph (config->virama, &glyph))
|
||||
glyph = 0;
|
||||
|
@ -262,8 +262,8 @@ struct indic_shape_plan_t
|
|||
* Maybe one day... */
|
||||
|
||||
/* Our get_nominal_glyph() function needs a font, so we can't get the virama glyph
|
||||
* during shape planning... Instead, overwrite it here. It's safe. Don't worry! */
|
||||
virama_glyph = glyph;
|
||||
* during shape planning... Instead, overwrite it here. */
|
||||
virama_glyph.set_relaxed ((int) glyph);
|
||||
}
|
||||
|
||||
*pglyph = glyph;
|
||||
|
@ -273,7 +273,7 @@ struct indic_shape_plan_t
|
|||
const indic_config_t *config;
|
||||
|
||||
bool is_old_spec;
|
||||
mutable hb_codepoint_t virama_glyph;
|
||||
mutable hb_atomic_int_t virama_glyph;
|
||||
|
||||
would_substitute_feature_t rphf;
|
||||
would_substitute_feature_t pref;
|
||||
|
@ -298,7 +298,7 @@ data_create_indic (const hb_ot_shape_plan_t *plan)
|
|||
}
|
||||
|
||||
indic_plan->is_old_spec = indic_plan->config->has_old_spec && ((plan->map.chosen_script[0] & 0x000000FFu) != '2');
|
||||
indic_plan->virama_glyph = (hb_codepoint_t) -1;
|
||||
indic_plan->virama_glyph.set_relaxed (-1);
|
||||
|
||||
/* Use zero-context would_substitute() matching for new-spec of the main
|
||||
* Indic scripts, and scripts with one spec only, but not for old-specs.
|
||||
|
@ -419,7 +419,7 @@ update_consonant_positions (const hb_ot_shape_plan_t *plan,
|
|||
return;
|
||||
|
||||
hb_codepoint_t virama;
|
||||
if (indic_plan->get_virama_glyph (font, &virama))
|
||||
if (indic_plan->load_virama_glyph (font, &virama))
|
||||
{
|
||||
hb_face_t *face = font->face;
|
||||
unsigned int count = buffer->len;
|
||||
|
@ -667,10 +667,10 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
|
|||
* last consonant.
|
||||
*
|
||||
* Reports suggest that in some scripts Uniscribe does this only if there
|
||||
* is *not* a Halant after last consonant already (eg. Kannada), while it
|
||||
* does it unconditionally in other scripts (eg. Malayalam, Bengali). We
|
||||
* don't currently know about other scripts, so we whitelist Malayalam and
|
||||
* Bengali for now.
|
||||
* is *not* a Halant after last consonant already. We know that is the
|
||||
* case for Kannada, while it reorders unconditionally in other scripts,
|
||||
* eg. Malayalam, Bengali, and Devanagari. We don't currently know about
|
||||
* other scripts, so we blacklist Kannada.
|
||||
*
|
||||
* Kannada test case:
|
||||
* U+0C9A,U+0CCD,U+0C9A,U+0CCD
|
||||
|
@ -681,15 +681,19 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
|
|||
* U+0D38,U+0D4D,U+0D31,U+0D4D,U+0D31,U+0D4D
|
||||
* With lohit-ttf-20121122/Lohit-Malayalam.ttf
|
||||
*
|
||||
* Bengali test case
|
||||
* Bengali test case:
|
||||
* U+0998,U+09CD,U+09AF,U+09CD
|
||||
* With Windows XP vrinda.ttf
|
||||
* https://github.com/harfbuzz/harfbuzz/issues/1073
|
||||
*
|
||||
* Devanagari test case:
|
||||
* U+091F,U+094D,U+0930,U+094D
|
||||
* With chandas.ttf
|
||||
* https://github.com/harfbuzz/harfbuzz/issues/1071
|
||||
*/
|
||||
if (indic_plan->is_old_spec)
|
||||
{
|
||||
bool disallow_double_halants = buffer->props.script != HB_SCRIPT_MALAYALAM &&
|
||||
buffer->props.script != HB_SCRIPT_BENGALI;
|
||||
bool disallow_double_halants = buffer->props.script == HB_SCRIPT_KANNADA;
|
||||
for (unsigned int i = base + 1; i < end; i++)
|
||||
if (info[i].indic_category() == OT_H)
|
||||
{
|
||||
|
@ -1036,9 +1040,11 @@ final_reordering_syllable (const hb_ot_shape_plan_t *plan,
|
|||
* phase, and that might have messed up our properties. Recover
|
||||
* from a particular case of that where we're fairly sure that a
|
||||
* class of OT_H is desired but has been lost. */
|
||||
if (indic_plan->virama_glyph)
|
||||
/* We don't call load_virama_glyph(), since we know it's already
|
||||
* loaded. */
|
||||
hb_codepoint_t virama_glyph = indic_plan->virama_glyph.get_relaxed ();
|
||||
if (virama_glyph)
|
||||
{
|
||||
unsigned int virama_glyph = indic_plan->virama_glyph;
|
||||
for (unsigned int i = start; i < end; i++)
|
||||
if (info[i].codepoint == virama_glyph &&
|
||||
_hb_glyph_info_ligated (&info[i]) &&
|
||||
|
|
|
@ -42,7 +42,7 @@ khmer_features[] =
|
|||
{
|
||||
/*
|
||||
* Basic features.
|
||||
* These features are applied in order, one at a time, after initial_reordering.
|
||||
* These features are applied in order, one at a time, after reordering.
|
||||
*/
|
||||
{HB_TAG('p','r','e','f'), F_NONE},
|
||||
{HB_TAG('b','l','w','f'), F_NONE},
|
||||
|
@ -51,9 +51,7 @@ khmer_features[] =
|
|||
{HB_TAG('c','f','a','r'), F_NONE},
|
||||
/*
|
||||
* Other features.
|
||||
* These features are applied all at once, after final_reordering.
|
||||
* Default Bengali font in Windows for example has intermixed
|
||||
* lookups for init,pres,abvs,blws features.
|
||||
* These features are applied all at once.
|
||||
*/
|
||||
{HB_TAG('p','r','e','s'), F_GLOBAL},
|
||||
{HB_TAG('a','b','v','s'), F_GLOBAL},
|
||||
|
@ -92,13 +90,9 @@ setup_syllables (const hb_ot_shape_plan_t *plan,
|
|||
hb_font_t *font,
|
||||
hb_buffer_t *buffer);
|
||||
static void
|
||||
initial_reordering (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer);
|
||||
static void
|
||||
final_reordering (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer);
|
||||
reorder (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer);
|
||||
static void
|
||||
clear_syllables (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
|
@ -111,20 +105,28 @@ collect_features_khmer (hb_ot_shape_planner_t *plan)
|
|||
|
||||
/* Do this before any lookups have been applied. */
|
||||
map->add_gsub_pause (setup_syllables);
|
||||
map->add_gsub_pause (reorder);
|
||||
|
||||
/* Testing suggests that Uniscribe does NOT pause between basic
|
||||
* features. Test with KhmerUI.ttf and the following three
|
||||
* sequences:
|
||||
*
|
||||
* U+1789,U+17BC
|
||||
* U+1789,U+17D2,U+1789
|
||||
* U+1789,U+17D2,U+1789,U+17BC
|
||||
*
|
||||
* https://github.com/harfbuzz/harfbuzz/issues/974
|
||||
*/
|
||||
map->add_global_bool_feature (HB_TAG('l','o','c','l'));
|
||||
/* The Indic specs do not require ccmp, but we apply it here since if
|
||||
* there is a use of it, it's typically at the beginning. */
|
||||
map->add_global_bool_feature (HB_TAG('c','c','m','p'));
|
||||
|
||||
|
||||
unsigned int i = 0;
|
||||
map->add_gsub_pause (initial_reordering);
|
||||
for (; i < KHMER_BASIC_FEATURES; i++) {
|
||||
map->add_feature (khmer_features[i].tag, 1, khmer_features[i].flags | F_MANUAL_ZWJ | F_MANUAL_ZWNJ);
|
||||
map->add_gsub_pause (nullptr);
|
||||
}
|
||||
map->add_gsub_pause (final_reordering);
|
||||
|
||||
map->add_gsub_pause (clear_syllables);
|
||||
|
||||
for (; i < KHMER_NUM_FEATURES; i++) {
|
||||
map->add_feature (khmer_features[i].tag, 1, khmer_features[i].flags | F_MANUAL_ZWJ | F_MANUAL_ZWNJ);
|
||||
}
|
||||
|
@ -132,7 +134,6 @@ collect_features_khmer (hb_ot_shape_planner_t *plan)
|
|||
map->add_global_bool_feature (HB_TAG('c','a','l','t'));
|
||||
map->add_global_bool_feature (HB_TAG('c','l','i','g'));
|
||||
|
||||
map->add_gsub_pause (clear_syllables);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -264,162 +265,58 @@ setup_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
|
|||
buffer->unsafe_to_break (start, end);
|
||||
}
|
||||
|
||||
static int
|
||||
compare_khmer_order (const hb_glyph_info_t *pa, const hb_glyph_info_t *pb)
|
||||
{
|
||||
int a = pa->khmer_position();
|
||||
int b = pb->khmer_position();
|
||||
|
||||
return a < b ? -1 : a == b ? 0 : +1;
|
||||
}
|
||||
|
||||
|
||||
/* Rules from:
|
||||
* https://docs.microsoft.com/en-us/typography/script-development/devanagari */
|
||||
|
||||
static void
|
||||
initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
|
||||
hb_face_t *face,
|
||||
hb_buffer_t *buffer,
|
||||
unsigned int start, unsigned int end)
|
||||
reorder_consonant_syllable (const hb_ot_shape_plan_t *plan,
|
||||
hb_face_t *face,
|
||||
hb_buffer_t *buffer,
|
||||
unsigned int start, unsigned int end)
|
||||
{
|
||||
const khmer_shape_plan_t *khmer_plan = (const khmer_shape_plan_t *) plan->data;
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
|
||||
/* 1. Khmer shaping assumes that a syllable will begin with a Cons, IndV, or Number. */
|
||||
|
||||
/* The first consonant is always the base. */
|
||||
unsigned int base = start;
|
||||
info[base].khmer_position() = POS_BASE_C;
|
||||
|
||||
/* Mark all subsequent consonants as below. */
|
||||
for (unsigned int i = base + 1; i < end; i++)
|
||||
if (is_consonant_or_vowel (info[i]))
|
||||
info[i].khmer_position() = POS_BELOW_C;
|
||||
|
||||
/* Mark final consonants. A final consonant is one appearing after a matra,
|
||||
* like in Khmer. */
|
||||
for (unsigned int i = base + 1; i < end; i++)
|
||||
if (info[i].khmer_category() == OT_M) {
|
||||
for (unsigned int j = i + 1; j < end; j++)
|
||||
if (is_consonant_or_vowel (info[j])) {
|
||||
info[j].khmer_position() = POS_FINAL_C;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Attach misc marks to previous char to move with them. */
|
||||
/* Setup masks. */
|
||||
{
|
||||
khmer_position_t last_pos = POS_START;
|
||||
for (unsigned int i = start; i < end; i++)
|
||||
{
|
||||
if ((FLAG_UNSAFE (info[i].khmer_category()) & (JOINER_FLAGS | FLAG (OT_N) | FLAG (OT_RS) | MEDIAL_FLAGS | FLAG (OT_Coeng))))
|
||||
{
|
||||
info[i].khmer_position() = last_pos;
|
||||
if (unlikely (info[i].khmer_category() == OT_Coeng &&
|
||||
info[i].khmer_position() == POS_PRE_M))
|
||||
{
|
||||
/*
|
||||
* Uniscribe doesn't move the Halant with Left Matra.
|
||||
* TEST: U+092B,U+093F,U+094DE
|
||||
* We follow. This is important for the Sinhala
|
||||
* U+0DDA split matra since it decomposes to U+0DD9,U+0DCA
|
||||
* where U+0DD9 is a left matra and U+0DCA is the virama.
|
||||
* We don't want to move the virama with the left matra.
|
||||
* TEST: U+0D9A,U+0DDA
|
||||
*/
|
||||
for (unsigned int j = i; j > start; j--)
|
||||
if (info[j - 1].khmer_position() != POS_PRE_M) {
|
||||
info[i].khmer_position() = info[j - 1].khmer_position();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else if (info[i].khmer_position() != POS_SMVD) {
|
||||
last_pos = (khmer_position_t) info[i].khmer_position();
|
||||
}
|
||||
}
|
||||
}
|
||||
/* For post-base consonants let them own anything before them
|
||||
* since the last consonant or matra. */
|
||||
{
|
||||
unsigned int last = base;
|
||||
for (unsigned int i = base + 1; i < end; i++)
|
||||
if (is_consonant_or_vowel (info[i]))
|
||||
{
|
||||
for (unsigned int j = last + 1; j < i; j++)
|
||||
if (info[j].khmer_position() < POS_SMVD)
|
||||
info[j].khmer_position() = info[i].khmer_position();
|
||||
last = i;
|
||||
} else if (info[i].khmer_category() == OT_M)
|
||||
last = i;
|
||||
}
|
||||
|
||||
{
|
||||
/* Use syllable() for sort accounting temporarily. */
|
||||
unsigned int syllable = info[start].syllable();
|
||||
for (unsigned int i = start; i < end; i++)
|
||||
info[i].syllable() = i - start;
|
||||
|
||||
/* Sit tight, rock 'n roll! */
|
||||
hb_stable_sort (info + start, end - start, compare_khmer_order);
|
||||
/* Find base again */
|
||||
base = end;
|
||||
for (unsigned int i = start; i < end; i++)
|
||||
if (info[i].khmer_position() == POS_BASE_C)
|
||||
{
|
||||
base = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (unlikely (end - start >= 127))
|
||||
buffer->merge_clusters (start, end);
|
||||
else
|
||||
/* Note! syllable() is a one-byte field. */
|
||||
for (unsigned int i = base; i < end; i++)
|
||||
if (info[i].syllable() != 255)
|
||||
{
|
||||
unsigned int max = i;
|
||||
unsigned int j = start + info[i].syllable();
|
||||
while (j != i)
|
||||
{
|
||||
max = MAX (max, j);
|
||||
unsigned int next = start + info[j].syllable();
|
||||
info[j].syllable() = 255; /* So we don't process j later again. */
|
||||
j = next;
|
||||
}
|
||||
if (i != max)
|
||||
buffer->merge_clusters (i, max + 1);
|
||||
}
|
||||
|
||||
/* Put syllable back in. */
|
||||
for (unsigned int i = start; i < end; i++)
|
||||
info[i].syllable() = syllable;
|
||||
}
|
||||
|
||||
/* Setup masks now */
|
||||
|
||||
{
|
||||
hb_mask_t mask;
|
||||
|
||||
/* Post-base */
|
||||
mask = khmer_plan->mask_array[BLWF] | khmer_plan->mask_array[ABVF] | khmer_plan->mask_array[PSTF];
|
||||
for (unsigned int i = base + 1; i < end; i++)
|
||||
hb_mask_t mask = khmer_plan->mask_array[BLWF] | khmer_plan->mask_array[ABVF] | khmer_plan->mask_array[PSTF];
|
||||
for (unsigned int i = start + 1; i < end; i++)
|
||||
info[i].mask |= mask;
|
||||
}
|
||||
|
||||
unsigned int pref_len = 2;
|
||||
if (khmer_plan->mask_array[PREF] && base + pref_len < end)
|
||||
unsigned int num_coengs = 0;
|
||||
for (unsigned int i = start + 1; i < end; i++)
|
||||
{
|
||||
/* Find a Halant,Ra sequence and mark it for pre-base-reordering processing. */
|
||||
for (unsigned int i = base + 1; i + pref_len - 1 < end; i++) {
|
||||
hb_codepoint_t glyphs[2];
|
||||
for (unsigned int j = 0; j < pref_len; j++)
|
||||
glyphs[j] = info[i + j].codepoint;
|
||||
if (khmer_plan->pref.would_substitute (glyphs, pref_len, face))
|
||||
/* """
|
||||
* When a COENG + (Cons | IndV) combination are found (and subscript count
|
||||
* is less than two) the character combination is handled according to the
|
||||
* subscript type of the character following the COENG.
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* Subscript Type 2 - The COENG + RO characters are reordered to immediately
|
||||
* before the base glyph. Then the COENG + RO characters are assigned to have
|
||||
* the 'pref' OpenType feature applied to them.
|
||||
* """
|
||||
*/
|
||||
if (info[i].khmer_category() == OT_Coeng && num_coengs <= 2 && i + 1 < end)
|
||||
{
|
||||
num_coengs++;
|
||||
|
||||
if (info[i + 1].khmer_category() == OT_Ra)
|
||||
{
|
||||
for (unsigned int j = 0; j < pref_len; j++)
|
||||
info[i++].mask |= khmer_plan->mask_array[PREF];
|
||||
for (unsigned int j = 0; j < 2; j++)
|
||||
info[i + j].mask |= khmer_plan->mask_array[PREF];
|
||||
|
||||
/* Move the Coeng,Ro sequence to the start. */
|
||||
buffer->merge_clusters (start, i + 2);
|
||||
hb_glyph_info_t t0 = info[i];
|
||||
hb_glyph_info_t t1 = info[i + 1];
|
||||
memmove (&info[start + 2], &info[start], (i - start) * sizeof (info[0]));
|
||||
info[start] = t0;
|
||||
info[start + 1] = t1;
|
||||
|
||||
/* Mark the subsequent stuff with 'cfar'. Used in Khmer.
|
||||
* Read the feature spec.
|
||||
|
@ -428,12 +325,22 @@ initial_reordering_consonant_syllable (const hb_ot_shape_plan_t *plan,
|
|||
* U+1784,U+17D2,U+1782,U+17D2,U+179A
|
||||
*/
|
||||
if (khmer_plan->mask_array[CFAR])
|
||||
for (; i < end; i++)
|
||||
info[i].mask |= khmer_plan->mask_array[CFAR];
|
||||
for (unsigned int j = i + 2; j < end; j++)
|
||||
info[j].mask |= khmer_plan->mask_array[CFAR];
|
||||
|
||||
break;
|
||||
num_coengs = 2; /* Done. */
|
||||
}
|
||||
}
|
||||
|
||||
/* Reorder left matra piece. */
|
||||
else if (info[i].khmer_position() == POS_PRE_M)
|
||||
{
|
||||
/* Move to the start. */
|
||||
buffer->merge_clusters (start, i + 1);
|
||||
hb_glyph_info_t t = info[i];
|
||||
memmove (&info[start + 1], &info[start], (i - start) * sizeof (info[0]));
|
||||
info[start] = t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -448,7 +355,7 @@ initial_reordering_syllable (const hb_ot_shape_plan_t *plan,
|
|||
{
|
||||
case broken_cluster: /* We already inserted dotted-circles, so just call the consonant_syllable. */
|
||||
case consonant_syllable:
|
||||
initial_reordering_consonant_syllable (plan, face, buffer, start, end);
|
||||
reorder_consonant_syllable (plan, face, buffer, start, end);
|
||||
break;
|
||||
|
||||
case non_khmer_cluster:
|
||||
|
@ -518,263 +425,26 @@ insert_dotted_circles (const hb_ot_shape_plan_t *plan HB_UNUSED,
|
|||
}
|
||||
|
||||
static void
|
||||
initial_reordering (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer)
|
||||
reorder (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font,
|
||||
hb_buffer_t *buffer)
|
||||
{
|
||||
insert_dotted_circles (plan, font, buffer);
|
||||
|
||||
foreach_syllable (buffer, start, end)
|
||||
initial_reordering_syllable (plan, font->face, buffer, start, end);
|
||||
}
|
||||
|
||||
static void
|
||||
final_reordering_syllable (const hb_ot_shape_plan_t *plan,
|
||||
hb_buffer_t *buffer,
|
||||
unsigned int start, unsigned int end)
|
||||
{
|
||||
const khmer_shape_plan_t *khmer_plan = (const khmer_shape_plan_t *) plan->data;
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
|
||||
|
||||
/* This function relies heavily on halant glyphs. Lots of ligation
|
||||
* and possibly multiple substitutions happened prior to this
|
||||
* phase, and that might have messed up our properties. Recover
|
||||
* from a particular case of that where we're fairly sure that a
|
||||
* class of OT_Coeng is desired but has been lost. */
|
||||
if (khmer_plan->virama_glyph)
|
||||
{
|
||||
unsigned int virama_glyph = khmer_plan->virama_glyph;
|
||||
for (unsigned int i = start; i < end; i++)
|
||||
if (info[i].codepoint == virama_glyph &&
|
||||
_hb_glyph_info_ligated (&info[i]) &&
|
||||
_hb_glyph_info_multiplied (&info[i]))
|
||||
{
|
||||
/* This will make sure that this glyph passes is_coeng() test. */
|
||||
info[i].khmer_category() = OT_Coeng;
|
||||
_hb_glyph_info_clear_ligated_and_multiplied (&info[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* 4. Final reordering:
|
||||
*
|
||||
* After the localized forms and basic shaping forms GSUB features have been
|
||||
* applied (see below), the shaping engine performs some final glyph
|
||||
* reordering before applying all the remaining font features to the entire
|
||||
* syllable.
|
||||
*/
|
||||
|
||||
bool try_pref = !!khmer_plan->mask_array[PREF];
|
||||
|
||||
/* Find base again */
|
||||
unsigned int base;
|
||||
for (base = start; base < end; base++)
|
||||
if (info[base].khmer_position() >= POS_BASE_C)
|
||||
{
|
||||
if (try_pref && base + 1 < end)
|
||||
{
|
||||
for (unsigned int i = base + 1; i < end; i++)
|
||||
if ((info[i].mask & khmer_plan->mask_array[PREF]) != 0)
|
||||
{
|
||||
if (!(_hb_glyph_info_substituted (&info[i]) &&
|
||||
_hb_glyph_info_ligated_and_didnt_multiply (&info[i])))
|
||||
{
|
||||
/* Ok, this was a 'pref' candidate but didn't form any.
|
||||
* Base is around here... */
|
||||
base = i;
|
||||
while (base < end && is_coeng (info[base]))
|
||||
base++;
|
||||
info[base].khmer_position() = POS_BASE_C;
|
||||
|
||||
try_pref = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (start < base && info[base].khmer_position() > POS_BASE_C)
|
||||
base--;
|
||||
break;
|
||||
}
|
||||
if (base == end && start < base &&
|
||||
is_one_of (info[base - 1], FLAG (OT_ZWJ)))
|
||||
base--;
|
||||
if (base < end)
|
||||
while (start < base &&
|
||||
is_one_of (info[base], (FLAG (OT_N) | FLAG (OT_Coeng))))
|
||||
base--;
|
||||
|
||||
|
||||
/* o Reorder matras:
|
||||
*
|
||||
* If a pre-base matra character had been reordered before applying basic
|
||||
* features, the glyph can be moved closer to the main consonant based on
|
||||
* whether half-forms had been formed. Actual position for the matra is
|
||||
* defined as “after last standalone halant glyph, after initial matra
|
||||
* position and before the main consonant”. If ZWJ or ZWNJ follow this
|
||||
* halant, position is moved after it.
|
||||
*/
|
||||
|
||||
if (start + 1 < end && start < base) /* Otherwise there can't be any pre-base matra characters. */
|
||||
{
|
||||
/* If we lost track of base, alas, position before last thingy. */
|
||||
unsigned int new_pos = base == end ? base - 2 : base - 1;
|
||||
|
||||
while (new_pos > start &&
|
||||
!(is_one_of (info[new_pos], (FLAG (OT_M) | FLAG (OT_Coeng)))))
|
||||
new_pos--;
|
||||
|
||||
/* If we found no Halant we are done.
|
||||
* Otherwise only proceed if the Halant does
|
||||
* not belong to the Matra itself! */
|
||||
if (is_coeng (info[new_pos]) &&
|
||||
info[new_pos].khmer_position() != POS_PRE_M)
|
||||
{
|
||||
/* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */
|
||||
if (new_pos + 1 < end && is_joiner (info[new_pos + 1]))
|
||||
new_pos++;
|
||||
}
|
||||
else
|
||||
new_pos = start; /* No move. */
|
||||
|
||||
if (start < new_pos && info[new_pos].khmer_position () != POS_PRE_M)
|
||||
{
|
||||
/* Now go see if there's actually any matras... */
|
||||
for (unsigned int i = new_pos; i > start; i--)
|
||||
if (info[i - 1].khmer_position () == POS_PRE_M)
|
||||
{
|
||||
unsigned int old_pos = i - 1;
|
||||
if (old_pos < base && base <= new_pos) /* Shouldn't actually happen. */
|
||||
base--;
|
||||
|
||||
hb_glyph_info_t tmp = info[old_pos];
|
||||
memmove (&info[old_pos], &info[old_pos + 1], (new_pos - old_pos) * sizeof (info[0]));
|
||||
info[new_pos] = tmp;
|
||||
|
||||
/* Note: this merge_clusters() is intentionally *after* the reordering.
|
||||
* Indic matra reordering is special and tricky... */
|
||||
buffer->merge_clusters (new_pos, MIN (end, base + 1));
|
||||
|
||||
new_pos--;
|
||||
}
|
||||
} else {
|
||||
for (unsigned int i = start; i < base; i++)
|
||||
if (info[i].khmer_position () == POS_PRE_M) {
|
||||
buffer->merge_clusters (i, MIN (end, base + 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* o Reorder pre-base-reordering consonants:
|
||||
*
|
||||
* If a pre-base-reordering consonant is found, reorder it according to
|
||||
* the following rules:
|
||||
*/
|
||||
|
||||
if (try_pref && base + 1 < end) /* Otherwise there can't be any pre-base-reordering Ra. */
|
||||
{
|
||||
for (unsigned int i = base + 1; i < end; i++)
|
||||
if ((info[i].mask & khmer_plan->mask_array[PREF]) != 0)
|
||||
{
|
||||
/* 1. Only reorder a glyph produced by substitution during application
|
||||
* of the <pref> feature. (Note that a font may shape a Ra consonant with
|
||||
* the feature generally but block it in certain contexts.)
|
||||
*/
|
||||
/* Note: We just check that something got substituted. We don't check that
|
||||
* the <pref> feature actually did it...
|
||||
*
|
||||
* Reorder pref only if it ligated. */
|
||||
if (_hb_glyph_info_ligated_and_didnt_multiply (&info[i]))
|
||||
{
|
||||
/*
|
||||
* 2. Try to find a target position the same way as for pre-base matra.
|
||||
* If it is found, reorder pre-base consonant glyph.
|
||||
*
|
||||
* 3. If position is not found, reorder immediately before main
|
||||
* consonant.
|
||||
*/
|
||||
|
||||
unsigned int new_pos = base;
|
||||
while (new_pos > start &&
|
||||
!(is_one_of (info[new_pos - 1], FLAG(OT_M) | FLAG (OT_Coeng))))
|
||||
new_pos--;
|
||||
|
||||
/* In Khmer coeng model, a H,Ra can go *after* matras. If it goes after a
|
||||
* split matra, it should be reordered to *before* the left part of such matra. */
|
||||
if (new_pos > start && info[new_pos - 1].khmer_category() == OT_M)
|
||||
{
|
||||
unsigned int old_pos = i;
|
||||
for (unsigned int j = base + 1; j < old_pos; j++)
|
||||
if (info[j].khmer_category() == OT_M)
|
||||
{
|
||||
new_pos--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (new_pos > start && is_coeng (info[new_pos - 1]))
|
||||
{
|
||||
/* -> If ZWJ or ZWNJ follow this halant, position is moved after it. */
|
||||
if (new_pos < end && is_joiner (info[new_pos]))
|
||||
new_pos++;
|
||||
}
|
||||
|
||||
{
|
||||
unsigned int old_pos = i;
|
||||
|
||||
buffer->merge_clusters (new_pos, old_pos + 1);
|
||||
hb_glyph_info_t tmp = info[old_pos];
|
||||
memmove (&info[new_pos + 1], &info[new_pos], (old_pos - new_pos) * sizeof (info[0]));
|
||||
info[new_pos] = tmp;
|
||||
|
||||
if (new_pos <= base && base < old_pos)
|
||||
base++;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Finish off the clusters and go home!
|
||||
*/
|
||||
if (hb_options ().uniscribe_bug_compatible)
|
||||
{
|
||||
/* Uniscribe merges the entire syllable into a single cluster... Except for Tamil & Sinhala.
|
||||
* This means, half forms are submerged into the main consonant's cluster.
|
||||
* This is unnecessary, and makes cursor positioning harder, but that's what
|
||||
* Uniscribe does. */
|
||||
buffer->merge_clusters (start, end);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
final_reordering (const hb_ot_shape_plan_t *plan,
|
||||
hb_font_t *font HB_UNUSED,
|
||||
hb_buffer_t *buffer)
|
||||
{
|
||||
unsigned int count = buffer->len;
|
||||
if (unlikely (!count)) return;
|
||||
|
||||
foreach_syllable (buffer, start, end)
|
||||
final_reordering_syllable (plan, buffer, start, end);
|
||||
|
||||
HB_BUFFER_DEALLOCATE_VAR (buffer, khmer_category);
|
||||
HB_BUFFER_DEALLOCATE_VAR (buffer, khmer_position);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
clear_syllables (const hb_ot_shape_plan_t *plan HB_UNUSED,
|
||||
hb_font_t *font HB_UNUSED,
|
||||
hb_buffer_t *buffer)
|
||||
{
|
||||
/* TODO: In USE, we clear syllables right after reorder. Figure out
|
||||
* what Uniscribe does. */
|
||||
hb_glyph_info_t *info = buffer->info;
|
||||
unsigned int count = buffer->len;
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
|
|
|
@ -279,20 +279,7 @@ hb_ot_shape_complex_categorize (const hb_ot_shape_planner_t *planner)
|
|||
return &_hb_ot_complex_shaper_indic;
|
||||
|
||||
case HB_SCRIPT_KHMER:
|
||||
/* A number of Khmer fonts in the wild don't have a 'pref' feature,
|
||||
* and as such won't shape properly via the Indic shaper;
|
||||
* however, they typically have 'liga' / 'clig' features that implement
|
||||
* the necessary "reordering" by means of ligature substitutions.
|
||||
* So we send such pref-less fonts through the generic shaper instead. */
|
||||
if (planner->map.found_script[0] &&
|
||||
hb_ot_layout_language_find_feature (planner->face, HB_OT_TAG_GSUB,
|
||||
planner->map.script_index[0],
|
||||
planner->map.language_index[0],
|
||||
HB_TAG ('p','r','e','f'),
|
||||
nullptr))
|
||||
return &_hb_ot_complex_shaper_khmer;
|
||||
else
|
||||
return &_hb_ot_complex_shaper_default;
|
||||
|
||||
case HB_SCRIPT_MYANMAR:
|
||||
if (planner->map.chosen_script[0] == HB_TAG ('m','y','m','2'))
|
||||
|
|
|
@ -510,8 +510,8 @@ static const USE_TABLE_ELEMENT_TYPE use_table[] = {
|
|||
|
||||
/* 11100 */ VMAbv, VMAbv, VMAbv, B, B, B, B, B, B, B, B, B, B, B, B, B,
|
||||
/* 11110 */ B, B, B, B, B, B, B, B, B, B, B, B, B, B, B, B,
|
||||
/* 11120 */ B, B, B, B, B, B, B, VAbv, VAbv, VAbv, VBlw, VBlw, VPre, VAbv, VAbv, VAbv,
|
||||
/* 11130 */ VAbv, VBlw, VBlw, H, VAbv, O, B, B, B, B, B, B, B, B, B, B,
|
||||
/* 11120 */ B, B, B, B, B, B, B, VBlw, VBlw, VBlw, VAbv, VAbv, VPre, VBlw, VAbv, VAbv,
|
||||
/* 11130 */ VBlw, VAbv, VAbv, H, CMAbv, O, B, B, B, B, B, B, B, B, B, B,
|
||||
/* 11140 */ O, O, O, O, B, VPst, VPst, O, O, O, O, O, O, O, O, O,
|
||||
|
||||
/* Mahajani */
|
||||
|
|
|
@ -560,25 +560,6 @@ reorder (const hb_ot_shape_plan_t *plan,
|
|||
HB_BUFFER_DEALLOCATE_VAR (buffer, use_category);
|
||||
}
|
||||
|
||||
static bool
|
||||
decompose_use (const hb_ot_shape_normalize_context_t *c,
|
||||
hb_codepoint_t ab,
|
||||
hb_codepoint_t *a,
|
||||
hb_codepoint_t *b)
|
||||
{
|
||||
switch (ab)
|
||||
{
|
||||
/* Chakma:
|
||||
* Special case where the Unicode decomp gives matras in the wrong order
|
||||
* for cluster validation.
|
||||
*/
|
||||
case 0x1112Eu : *a = 0x11127u; *b= 0x11131u; return true;
|
||||
case 0x1112Fu : *a = 0x11127u; *b= 0x11132u; return true;
|
||||
}
|
||||
|
||||
return (bool) c->unicode->decompose (ab, a, b);
|
||||
}
|
||||
|
||||
static bool
|
||||
compose_use (const hb_ot_shape_normalize_context_t *c,
|
||||
hb_codepoint_t a,
|
||||
|
@ -602,7 +583,7 @@ const hb_ot_complex_shaper_t _hb_ot_complex_shaper_use =
|
|||
nullptr, /* preprocess_text */
|
||||
nullptr, /* postprocess_glyphs */
|
||||
HB_OT_SHAPE_NORMALIZATION_MODE_COMPOSED_DIACRITICS_NO_SHORT_CIRCUIT,
|
||||
decompose_use,
|
||||
nullptr, /* decompose */
|
||||
compose_use,
|
||||
setup_masks_use,
|
||||
nullptr, /* disable_otl */
|
||||
|
|
|
@ -27,8 +27,8 @@
|
|||
*/
|
||||
|
||||
#define HB_SHAPER ot
|
||||
#define hb_ot_shaper_face_data_t hb_ot_layout_t
|
||||
#define hb_ot_shaper_shape_plan_data_t hb_ot_shape_plan_t
|
||||
#define hb_ot_face_data_t hb_ot_layout_t
|
||||
#define hb_ot_shape_plan_data_t hb_ot_shape_plan_t
|
||||
#include "hb-shaper-impl-private.hh"
|
||||
|
||||
#include "hb-ot-shape-private.hh"
|
||||
|
@ -41,7 +41,7 @@
|
|||
#include "hb-set-private.hh"
|
||||
|
||||
#include "hb-ot-layout-gsubgpos-private.hh"
|
||||
//#include "hb-aat-layout-private.hh"
|
||||
#include "hb-aat-layout-private.hh"
|
||||
|
||||
static hb_tag_t common_features[] = {
|
||||
HB_TAG('c','c','m','p'),
|
||||
|
@ -132,14 +132,14 @@ hb_ot_shape_collect_features (hb_ot_shape_planner_t *planner,
|
|||
|
||||
HB_SHAPER_DATA_ENSURE_DEFINE(ot, face)
|
||||
|
||||
hb_ot_shaper_face_data_t *
|
||||
hb_ot_face_data_t *
|
||||
_hb_ot_shaper_face_data_create (hb_face_t *face)
|
||||
{
|
||||
return _hb_ot_layout_create (face);
|
||||
}
|
||||
|
||||
void
|
||||
_hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t *data)
|
||||
_hb_ot_shaper_face_data_destroy (hb_ot_face_data_t *data)
|
||||
{
|
||||
_hb_ot_layout_destroy (data);
|
||||
}
|
||||
|
@ -151,16 +151,16 @@ _hb_ot_shaper_face_data_destroy (hb_ot_shaper_face_data_t *data)
|
|||
|
||||
HB_SHAPER_DATA_ENSURE_DEFINE(ot, font)
|
||||
|
||||
struct hb_ot_shaper_font_data_t {};
|
||||
struct hb_ot_font_data_t {};
|
||||
|
||||
hb_ot_shaper_font_data_t *
|
||||
hb_ot_font_data_t *
|
||||
_hb_ot_shaper_font_data_create (hb_font_t *font HB_UNUSED)
|
||||
{
|
||||
return (hb_ot_shaper_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
return (hb_ot_font_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_ot_shaper_font_data_destroy (hb_ot_shaper_font_data_t *data)
|
||||
_hb_ot_shaper_font_data_destroy (hb_ot_font_data_t *data)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -169,7 +169,7 @@ _hb_ot_shaper_font_data_destroy (hb_ot_shaper_font_data_t *data)
|
|||
* shaper shape_plan data
|
||||
*/
|
||||
|
||||
hb_ot_shaper_shape_plan_data_t *
|
||||
hb_ot_shape_plan_data_t *
|
||||
_hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan,
|
||||
const hb_feature_t *user_features,
|
||||
unsigned int num_user_features,
|
||||
|
@ -194,14 +194,17 @@ _hb_ot_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan,
|
|||
if (plan->shaper->data_create) {
|
||||
plan->data = plan->shaper->data_create (plan);
|
||||
if (unlikely (!plan->data))
|
||||
{
|
||||
free (plan);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return plan;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_ot_shaper_shape_plan_data_destroy (hb_ot_shaper_shape_plan_data_t *plan)
|
||||
_hb_ot_shaper_shape_plan_data_destroy (hb_ot_shape_plan_data_t *plan)
|
||||
{
|
||||
if (plan->shaper->data_destroy)
|
||||
plan->shaper->data_destroy (const_cast<void *> (plan->data));
|
||||
|
@ -623,8 +626,8 @@ hb_ot_substitute_complex (hb_ot_shape_context_t *c)
|
|||
|
||||
c->plan->substitute (c->font, buffer);
|
||||
|
||||
/* XXX Call morx instead. */
|
||||
//hb_aat_layout_substitute (c->font, c->buffer);
|
||||
if (0) /* XXX Call morx instead. */
|
||||
hb_aat_layout_substitute (c->font, c->buffer);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
@ -677,8 +680,8 @@ hb_ot_position_default (hb_ot_shape_context_t *c)
|
|||
|
||||
if (HB_DIRECTION_IS_HORIZONTAL (direction))
|
||||
{
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
pos[i].x_advance = c->font->get_glyph_h_advance (info[i].codepoint);
|
||||
c->font->get_glyph_h_advances (count, &info[0].codepoint, sizeof(info[0]),
|
||||
&pos[0].x_advance, sizeof(pos[0]));
|
||||
/* The nil glyph_h_origin() func returns 0, so no need to apply it. */
|
||||
if (c->font->has_glyph_h_origin_func ())
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
|
@ -688,9 +691,10 @@ hb_ot_position_default (hb_ot_shape_context_t *c)
|
|||
}
|
||||
else
|
||||
{
|
||||
c->font->get_glyph_v_advances (count, &info[0].codepoint, sizeof(info[0]),
|
||||
&pos[0].y_advance, sizeof(pos[0]));
|
||||
for (unsigned int i = 0; i < count; i++)
|
||||
{
|
||||
pos[i].y_advance = c->font->get_glyph_v_advance (info[i].codepoint);
|
||||
c->font->subtract_glyph_v_origin (info[i].codepoint,
|
||||
&pos[i].x_offset,
|
||||
&pos[i].y_offset);
|
||||
|
|
|
@ -87,6 +87,8 @@ struct fvar
|
|||
{
|
||||
static const hb_tag_t tableTag = HB_OT_TAG_fvar;
|
||||
|
||||
inline bool has_data (void) const { return version.to_int () != 0; }
|
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
|
|
|
@ -41,14 +41,14 @@ _get_fvar (hb_face_t *face)
|
|||
{
|
||||
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::fvar);
|
||||
hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
|
||||
return *(layout->fvar.get ());
|
||||
return *(layout->table.fvar.get ());
|
||||
}
|
||||
static inline const OT::avar&
|
||||
_get_avar (hb_face_t *face)
|
||||
{
|
||||
if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return Null(OT::avar);
|
||||
hb_ot_layout_t * layout = hb_ot_layout_from_face (face);
|
||||
return *(layout->avar.get ());
|
||||
return *(layout->table.avar.get ());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,7 +65,7 @@ _get_avar (hb_face_t *face)
|
|||
hb_bool_t
|
||||
hb_ot_var_has_data (hb_face_t *face)
|
||||
{
|
||||
return &_get_fvar (face) != &Null(OT::fvar);
|
||||
return _get_fvar (face).has_data ();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -84,19 +84,9 @@ extern "C" int hb_memalign_impl(void **memptr, size_t alignment, size_t size);
|
|||
#endif
|
||||
|
||||
|
||||
/* Compiler attributes */
|
||||
|
||||
|
||||
template <typename T>
|
||||
struct _hb_alignof
|
||||
{
|
||||
struct s
|
||||
{
|
||||
char c;
|
||||
T t;
|
||||
};
|
||||
static constexpr unsigned int value = offsetof (s, t);
|
||||
};
|
||||
/*
|
||||
* Compiler attributes
|
||||
*/
|
||||
|
||||
#if __cplusplus < 201103L
|
||||
|
||||
|
@ -108,7 +98,6 @@ struct _hb_alignof
|
|||
#define constexpr const
|
||||
#endif
|
||||
|
||||
// Static assertions
|
||||
#ifndef static_assert
|
||||
#define static_assert(e, msg) \
|
||||
HB_UNUSED typedef int HB_PASTE(static_assertion_failed_at_line_, __LINE__) [(e) ? 1 : -1]
|
||||
|
@ -122,9 +111,19 @@ struct _hb_alignof
|
|||
#define thread_local
|
||||
#endif
|
||||
|
||||
template <typename T>
|
||||
struct _hb_alignof
|
||||
{
|
||||
struct s
|
||||
{
|
||||
char c;
|
||||
T t;
|
||||
};
|
||||
static constexpr size_t value = offsetof (s, t);
|
||||
};
|
||||
#ifndef alignof
|
||||
#define alignof(x) (_hb_alignof<x>::value)
|
||||
#endif // alignof
|
||||
#endif
|
||||
|
||||
#endif // __cplusplus < 201103L
|
||||
|
||||
|
@ -161,7 +160,11 @@ struct _hb_alignof
|
|||
#ifndef HB_INTERNAL
|
||||
# if !defined(HB_NO_VISIBILITY) && !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(_MSC_VER) && !defined(__SUNPRO_CC)
|
||||
# define HB_INTERNAL __attribute__((__visibility__("hidden")))
|
||||
# else
|
||||
# elif defined(__MINGW32__)
|
||||
/* We use -export-symbols on mingw32, since it does not support visibility
|
||||
* attribute. */
|
||||
# define HB_INTERNAL
|
||||
#else
|
||||
# define HB_INTERNAL
|
||||
# define HB_NO_VISIBILITY 1
|
||||
# endif
|
||||
|
@ -282,13 +285,12 @@ static int errno = 0; /* Use something better? */
|
|||
#define HB_STMT_START do
|
||||
#define HB_STMT_END while (0)
|
||||
|
||||
/* Static-assert as expression. */
|
||||
template <unsigned int cond> class hb_assert_constant_t;
|
||||
template <> class hb_assert_constant_t<1> {};
|
||||
|
||||
#define ASSERT_STATIC_EXPR_ZERO(_cond) (0 * (unsigned int) sizeof (hb_assert_constant_t<_cond>))
|
||||
|
||||
/* Lets assert int types. Saves trouble down the road. */
|
||||
|
||||
static_assert ((sizeof (int8_t) == 1), "");
|
||||
static_assert ((sizeof (uint8_t) == 1), "");
|
||||
static_assert ((sizeof (int16_t) == 2), "");
|
||||
|
@ -297,7 +299,6 @@ static_assert ((sizeof (int32_t) == 4), "");
|
|||
static_assert ((sizeof (uint32_t) == 4), "");
|
||||
static_assert ((sizeof (int64_t) == 8), "");
|
||||
static_assert ((sizeof (uint64_t) == 8), "");
|
||||
|
||||
static_assert ((sizeof (hb_codepoint_t) == 4), "");
|
||||
static_assert ((sizeof (hb_position_t) == 4), "");
|
||||
static_assert ((sizeof (hb_mask_t) == 4), "");
|
||||
|
@ -334,95 +335,37 @@ static_assert ((sizeof (hb_var_int_t) == 4), "");
|
|||
TypeName(const TypeName&); \
|
||||
void operator=(const TypeName&)
|
||||
|
||||
|
||||
/*
|
||||
* Static pools
|
||||
* Compiler-assisted vectorization parameters.
|
||||
*/
|
||||
|
||||
/* Global nul-content Null pool. Enlarge as necessary. */
|
||||
/*
|
||||
* Disable vectorization for now. To correctly use them, we should
|
||||
* use posix_memalign() to allocate in hb_vector_t. Otherwise, can
|
||||
* cause misaligned access.
|
||||
*
|
||||
* https://bugs.chromium.org/p/chromium/issues/detail?id=860184
|
||||
*/
|
||||
#if !defined(HB_VECTOR_SIZE)
|
||||
# define HB_VECTOR_SIZE 0
|
||||
#endif
|
||||
|
||||
#define HB_NULL_POOL_SIZE 264
|
||||
static_assert (HB_NULL_POOL_SIZE % sizeof (void *) == 0, "Align HB_NULL_POOL_SIZE.");
|
||||
|
||||
#ifdef HB_NO_VISIBILITY
|
||||
static
|
||||
/* The `vector_size' attribute was introduced in gcc 3.1. */
|
||||
#if !defined(HB_VECTOR_SIZE)
|
||||
# if defined( __GNUC__ ) && ( __GNUC__ >= 4 )
|
||||
# define HB_VECTOR_SIZE 128
|
||||
# else
|
||||
# define HB_VECTOR_SIZE 0
|
||||
# endif
|
||||
#endif
|
||||
static_assert (0 == (HB_VECTOR_SIZE & (HB_VECTOR_SIZE - 1)), "HB_VECTOR_SIZE is not power of 2.");
|
||||
static_assert (0 == (HB_VECTOR_SIZE % 64), "HB_VECTOR_SIZE is not multiple of 64.");
|
||||
#if HB_VECTOR_SIZE
|
||||
typedef uint64_t hb_vector_size_impl_t __attribute__((vector_size (HB_VECTOR_SIZE / 8)));
|
||||
#else
|
||||
extern HB_INTERNAL
|
||||
typedef uint64_t hb_vector_size_impl_t;
|
||||
#endif
|
||||
void * const _hb_NullPool[HB_NULL_POOL_SIZE / sizeof (void *)]
|
||||
#ifdef HB_NO_VISIBILITY
|
||||
= {}
|
||||
#endif
|
||||
;
|
||||
/* Generic nul-content Null objects. */
|
||||
template <typename Type>
|
||||
static inline Type const & Null (void) {
|
||||
static_assert (sizeof (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
|
||||
return *reinterpret_cast<Type const *> (_hb_NullPool);
|
||||
}
|
||||
#define Null(Type) Null<Type>()
|
||||
|
||||
/* Specializaiton for arbitrary-content arbitrary-sized Null objects. */
|
||||
#define DEFINE_NULL_DATA(Namespace, Type, data) \
|
||||
} /* Close namespace. */ \
|
||||
static const char _Null##Type[sizeof (Namespace::Type) + 1] = data; /* +1 is for nul-termination in data */ \
|
||||
template <> \
|
||||
/*static*/ inline const Namespace::Type& Null<Namespace::Type> (void) { \
|
||||
return *reinterpret_cast<const Namespace::Type *> (_Null##Type); \
|
||||
} \
|
||||
namespace Namespace { \
|
||||
/* The following line really exists such that we end in a place needing semicolon */ \
|
||||
static_assert (Namespace::Type::min_size + 1 <= sizeof (_Null##Type), "Null pool too small. Enlarge.")
|
||||
|
||||
|
||||
/* Global writable pool. Enlarge as necessary. */
|
||||
|
||||
/* To be fully correct, CrapPool must be thread_local. However, we do not rely on CrapPool
|
||||
* for correct operation. It only exist to catch and divert program logic bugs instead of
|
||||
* 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. */
|
||||
#ifdef HB_NO_VISIBILITY
|
||||
static
|
||||
#else
|
||||
extern HB_INTERNAL
|
||||
#endif
|
||||
/*thread_local*/ void * _hb_CrapPool[HB_NULL_POOL_SIZE / sizeof (void *)]
|
||||
#ifdef HB_NO_VISIBILITY
|
||||
= {}
|
||||
#endif
|
||||
;
|
||||
/* CRAP pool: Common Region for Access Protection. */
|
||||
template <typename Type>
|
||||
static inline Type& Crap (void) {
|
||||
static_assert (sizeof (Type) <= HB_NULL_POOL_SIZE, "Increase HB_NULL_POOL_SIZE.");
|
||||
Type *obj = reinterpret_cast<Type *> (_hb_CrapPool);
|
||||
*obj = Null(Type);
|
||||
return *obj;
|
||||
}
|
||||
#define Crap(Type) Crap<Type>()
|
||||
|
||||
template <typename Type>
|
||||
struct CrapOrNull {
|
||||
static inline Type & get (void) { return Crap(Type); }
|
||||
};
|
||||
template <typename Type>
|
||||
struct CrapOrNull<const Type> {
|
||||
static inline Type const & get (void) { return Null(Type); }
|
||||
};
|
||||
#define CrapOrNull(Type) CrapOrNull<Type>::get ()
|
||||
|
||||
|
||||
/* 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; }
|
||||
|
||||
|
||||
/* HB_NDEBUG disables some sanity checks that are very safe to disable and
|
||||
|
@ -435,41 +378,7 @@ static inline unsigned char TOLOWER (unsigned char c)
|
|||
#endif
|
||||
|
||||
|
||||
/* Misc */
|
||||
|
||||
template <typename T> class hb_assert_unsigned_t;
|
||||
template <> class hb_assert_unsigned_t<unsigned char> {};
|
||||
template <> class hb_assert_unsigned_t<unsigned short> {};
|
||||
template <> class hb_assert_unsigned_t<unsigned int> {};
|
||||
template <> class hb_assert_unsigned_t<unsigned long> {};
|
||||
|
||||
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 ((sizeof (hb_assert_unsigned_t<T>) >= 0), "");
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* Flags */
|
||||
|
||||
/* Enable bitwise ops on enums marked as flags_t */
|
||||
/* To my surprise, looks like the function resolver is happy to silently cast
|
||||
|
@ -493,7 +402,6 @@ hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
|
|||
static inline T& operator ^= (T& l, T r) { l = l ^ r; return l; } \
|
||||
}
|
||||
|
||||
|
||||
/* Useful for set-operations on small enums.
|
||||
* For example, for testing "x ∈ {x1, x2, x3}" use:
|
||||
* (FLAG_UNSAFE(x) & (FLAG(x1) | FLAG(x2) | FLAG(x3)))
|
||||
|
@ -503,58 +411,6 @@ hb_in_ranges (T u, T lo1, T hi1, T lo2, T hi2, T lo3, T hi3)
|
|||
#define FLAG_RANGE(x,y) (ASSERT_STATIC_EXPR_ZERO ((x) < (y)) + FLAG(y+1) - FLAG(x))
|
||||
|
||||
|
||||
|
||||
/* Compiler-assisted vectorization. */
|
||||
|
||||
/*
|
||||
* Disable vectorization for now. To correctly use them, we should
|
||||
* use posix_memalign() to allocate them. Otherwise, can cause
|
||||
* misaligned access.
|
||||
*
|
||||
* https://bugs.chromium.org/p/chromium/issues/detail?id=860184
|
||||
*/
|
||||
#if !defined(HB_VECTOR_SIZE)
|
||||
# define HB_VECTOR_SIZE 0
|
||||
#endif
|
||||
|
||||
/* The `vector_size' attribute was introduced in gcc 3.1. */
|
||||
#if !defined(HB_VECTOR_SIZE)
|
||||
# if defined( __GNUC__ ) && ( __GNUC__ >= 4 )
|
||||
# define HB_VECTOR_SIZE 128
|
||||
# else
|
||||
# define HB_VECTOR_SIZE 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
/* Global runtime options. */
|
||||
|
||||
struct hb_options_t
|
||||
{
|
||||
unsigned int initialized : 1;
|
||||
unsigned int uniscribe_bug_compatible : 1;
|
||||
};
|
||||
|
||||
union hb_options_union_t {
|
||||
unsigned int i;
|
||||
hb_options_t opts;
|
||||
};
|
||||
static_assert ((sizeof (int) == sizeof (hb_options_union_t)), "");
|
||||
|
||||
HB_INTERNAL void
|
||||
_hb_options_init (void);
|
||||
|
||||
extern HB_INTERNAL hb_options_union_t _hb_options;
|
||||
|
||||
static inline hb_options_t
|
||||
hb_options (void)
|
||||
{
|
||||
if (unlikely (!_hb_options.i))
|
||||
_hb_options_init ();
|
||||
|
||||
return _hb_options.opts;
|
||||
}
|
||||
|
||||
/* Size signifying variable-sized array */
|
||||
#define VAR 1
|
||||
|
||||
|
@ -605,6 +461,7 @@ _hb_memalign(void **memptr, size_t alignment, size_t size)
|
|||
#include "hb-debug.hh"
|
||||
#include "hb-dsalgs.hh"
|
||||
#include "hb-mutex-private.hh"
|
||||
#include "hb-null.hh"
|
||||
#include "hb-object-private.hh"
|
||||
|
||||
#endif /* HB_PRIVATE_HH */
|
||||
|
|
|
@ -51,6 +51,7 @@ struct hb_shape_plan_t
|
|||
|
||||
struct hb_shaper_data_t shaper_data;
|
||||
};
|
||||
DECLARE_NULL_INSTANCE (hb_shape_plan_t);
|
||||
|
||||
#define HB_SHAPER_DATA_CREATE_FUNC_EXTRA_ARGS \
|
||||
, const hb_feature_t *user_features \
|
||||
|
|
|
@ -88,6 +88,31 @@ hb_shape_plan_plan (hb_shape_plan_t *shape_plan,
|
|||
* hb_shape_plan_t
|
||||
*/
|
||||
|
||||
DEFINE_NULL_INSTANCE (hb_shape_plan_t) =
|
||||
{
|
||||
HB_OBJECT_HEADER_STATIC,
|
||||
|
||||
true, /* default_shaper_list */
|
||||
nullptr, /* face */
|
||||
HB_SEGMENT_PROPERTIES_DEFAULT, /* props */
|
||||
|
||||
nullptr, /* shaper_func */
|
||||
nullptr, /* shaper_name */
|
||||
|
||||
nullptr, /* user_features */
|
||||
0, /* num_user_featurs */
|
||||
|
||||
nullptr, /* coords */
|
||||
0, /* num_coords */
|
||||
|
||||
{
|
||||
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
|
||||
#include "hb-shaper-list.hh"
|
||||
#undef HB_SHAPER_IMPLEMENT
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* hb_shape_plan_create: (Xconstructor)
|
||||
* @face:
|
||||
|
@ -188,30 +213,7 @@ hb_shape_plan_create2 (hb_face_t *face,
|
|||
hb_shape_plan_t *
|
||||
hb_shape_plan_get_empty (void)
|
||||
{
|
||||
static const hb_shape_plan_t _hb_shape_plan_nil = {
|
||||
HB_OBJECT_HEADER_STATIC,
|
||||
|
||||
true, /* default_shaper_list */
|
||||
nullptr, /* face */
|
||||
HB_SEGMENT_PROPERTIES_DEFAULT, /* props */
|
||||
|
||||
nullptr, /* shaper_func */
|
||||
nullptr, /* shaper_name */
|
||||
|
||||
nullptr, /* user_features */
|
||||
0, /* num_user_featurs */
|
||||
|
||||
nullptr, /* coords */
|
||||
0, /* num_coords */
|
||||
|
||||
{
|
||||
#define HB_SHAPER_IMPLEMENT(shaper) HB_SHAPER_DATA_INVALID,
|
||||
#include "hb-shaper-list.hh"
|
||||
#undef HB_SHAPER_IMPLEMENT
|
||||
}
|
||||
};
|
||||
|
||||
return const_cast<hb_shape_plan_t *> (&_hb_shape_plan_nil);
|
||||
return const_cast<hb_shape_plan_t *> (&Null(hb_shape_plan_t));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -49,23 +49,12 @@ HB_INTERNAL const hb_shaper_pair_t *
|
|||
_hb_shapers_get (void);
|
||||
|
||||
|
||||
/* For embedding in face / font / ... */
|
||||
struct hb_shaper_data_t {
|
||||
#define HB_SHAPER_IMPLEMENT(shaper) void *shaper;
|
||||
#include "hb-shaper-list.hh"
|
||||
#undef HB_SHAPER_IMPLEMENT
|
||||
};
|
||||
|
||||
#define HB_SHAPERS_COUNT (sizeof (hb_shaper_data_t) / sizeof (void *))
|
||||
|
||||
/* Means: succeeded, but don't need to keep any data. */
|
||||
#define HB_SHAPER_DATA_SUCCEEDED ((void *) +1)
|
||||
|
||||
/* Means: tried but failed to create. */
|
||||
#define HB_SHAPER_DATA_INVALID ((void *) -1)
|
||||
#define HB_SHAPER_DATA_IS_INVALID(data) ((void *) (data) == HB_SHAPER_DATA_INVALID)
|
||||
|
||||
#define HB_SHAPER_DATA_TYPE_NAME(shaper, object) hb_##shaper##_shaper_##object##_data_t
|
||||
#define HB_SHAPER_DATA_TYPE_NAME(shaper, object) hb_##shaper##_##object##_data_t
|
||||
#define HB_SHAPER_DATA_TYPE(shaper, object) struct HB_SHAPER_DATA_TYPE_NAME(shaper, object)
|
||||
#define HB_SHAPER_DATA_INSTANCE(shaper, object, instance) (* (HB_SHAPER_DATA_TYPE(shaper, object) **) &(instance)->shaper_data.shaper)
|
||||
#define HB_SHAPER_DATA(shaper, object) HB_SHAPER_DATA_INSTANCE(shaper, object, object)
|
||||
|
@ -97,6 +86,16 @@ HB_SHAPER_DATA_ENSURE_FUNC(shaper, object) (hb_##object##_t *object) \
|
|||
retry: \
|
||||
HB_SHAPER_DATA_TYPE (shaper, object) *data = (HB_SHAPER_DATA_TYPE (shaper, object) *) hb_atomic_ptr_get (&HB_SHAPER_DATA (shaper, object)); \
|
||||
if (likely (data) && !(condition)) { \
|
||||
/* Note that evaluating condition above can be dangerous if another thread \
|
||||
* got here first and destructed data. That's, as always, bad use pattern. \
|
||||
* If you modify the font (change font size), other threads must not be \
|
||||
* using it at the same time. However, since this check is delayed to \
|
||||
* when one actually tries to shape something, this is a XXX race condition \
|
||||
* (and the only know we have that I know of) right now. Ie. you modify the \
|
||||
* font size in one thread, then (supposedly safely) try to use it from two \
|
||||
* or more threads and BOOM! I'm not sure how to fix this. We want RCU. \
|
||||
* Maybe when it doesn't matter when we finally implement AAT shaping, as
|
||||
* this (condition) is currently only used by hb-coretext. */ \
|
||||
/* Drop and recreate. */ \
|
||||
/* If someone dropped it in the mean time, throw it away and don't touch it. \
|
||||
* Otherwise, destruct it. */ \
|
||||
|
@ -117,8 +116,17 @@ HB_SHAPER_DATA_ENSURE_FUNC(shaper, object) (hb_##object##_t *object) \
|
|||
goto retry; \
|
||||
} \
|
||||
} \
|
||||
return data != nullptr && !HB_SHAPER_DATA_IS_INVALID (data); \
|
||||
return data != nullptr && (void *) data != HB_SHAPER_DATA_INVALID; \
|
||||
}
|
||||
|
||||
|
||||
/* For embedding in face / font / ... */
|
||||
struct hb_shaper_data_t {
|
||||
#define HB_SHAPER_IMPLEMENT(shaper) void *shaper;
|
||||
#include "hb-shaper-list.hh"
|
||||
#undef HB_SHAPER_IMPLEMENT
|
||||
};
|
||||
#define HB_SHAPERS_COUNT (sizeof (hb_shaper_data_t) / sizeof (void *))
|
||||
|
||||
|
||||
#endif /* HB_SHAPER_PRIVATE_HH */
|
||||
|
|
|
@ -26,7 +26,41 @@
|
|||
|
||||
#include "hb-private.hh"
|
||||
|
||||
#include "hb-open-type-private.hh"
|
||||
#include "hb-ot-layout-common-private.hh"
|
||||
|
||||
#include "hb-face-private.hh"
|
||||
#include "hb-ot-head-table.hh"
|
||||
#include "hb-ot-maxp-table.hh"
|
||||
|
||||
#ifndef HB_NO_VISIBILITY
|
||||
void * const _hb_NullPool[HB_NULL_POOL_SIZE / sizeof (void *)] = {};
|
||||
/*thread_local*/ void * _hb_CrapPool[HB_NULL_POOL_SIZE / sizeof (void *)] = {};
|
||||
|
||||
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)] = {};
|
||||
/*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)] = {};
|
||||
|
||||
DEFINE_NULL_NAMESPACE_BYTES (OT, Index) = {0xFF,0xFF};
|
||||
DEFINE_NULL_NAMESPACE_BYTES (OT, LangSys) = {0x00,0x00, 0xFF,0xFF, 0x00,0x00};
|
||||
DEFINE_NULL_NAMESPACE_BYTES (OT, RangeRecord) = {0x00,0x01, 0x00,0x00, 0x00, 0x00};
|
||||
|
||||
|
||||
void
|
||||
hb_face_t::load_num_glyphs (void) const
|
||||
{
|
||||
hb_sanitize_context_t c = hb_sanitize_context_t ();
|
||||
c.set_num_glyphs (0); /* So we don't recurse ad infinitum. */
|
||||
hb_blob_t *maxp_blob = c.reference_table<OT::maxp> (this);
|
||||
const OT::maxp *maxp_table = maxp_blob->as<OT::maxp> ();
|
||||
num_glyphs = maxp_table->get_num_glyphs ();
|
||||
hb_blob_destroy (maxp_blob);
|
||||
}
|
||||
|
||||
void
|
||||
hb_face_t::load_upem (void) const
|
||||
{
|
||||
hb_blob_t *head_blob = hb_sanitize_context_t ().reference_table<OT::head> (this);
|
||||
const OT::head *head_table = head_blob->as<OT::head> ();
|
||||
upem = head_table->get_upem ();
|
||||
hb_blob_destroy (head_blob);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -292,7 +292,7 @@ hb_subset_glyf_and_loca (hb_subset_plan_t *plan,
|
|||
hb_blob_t **glyf_prime, /* OUT */
|
||||
hb_blob_t **loca_prime /* OUT */)
|
||||
{
|
||||
hb_blob_t *glyf_blob = OT::Sanitizer<OT::glyf>().sanitize (plan->source->reference_table (HB_OT_TAG_glyf));
|
||||
hb_blob_t *glyf_blob = hb_sanitize_context_t ().reference_table<OT::glyf> (plan->source);
|
||||
const char *glyf_data = hb_blob_get_data(glyf_blob, nullptr);
|
||||
|
||||
OT::glyf::accelerator_t glyf;
|
||||
|
|
|
@ -56,11 +56,15 @@ _add_gid_and_children (const OT::glyf::accelerator_t &glyf,
|
|||
static void
|
||||
_gsub_closure (hb_face_t *face, hb_set_t *gids_to_retain)
|
||||
{
|
||||
// TODO(grieger): This uses all lookups, instead collect
|
||||
// the set of lookups that are relevant.
|
||||
// See fontTools implementation.
|
||||
hb_auto_t<hb_set_t> lookup_indices;
|
||||
hb_ot_layout_collect_lookups (face,
|
||||
HB_OT_TAG_GSUB,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
&lookup_indices);
|
||||
hb_ot_layout_lookups_substitute_closure (face,
|
||||
nullptr,
|
||||
&lookup_indices,
|
||||
gids_to_retain);
|
||||
}
|
||||
|
||||
|
|
|
@ -78,14 +78,12 @@ template<typename TableType>
|
|||
static bool
|
||||
_subset (hb_subset_plan_t *plan)
|
||||
{
|
||||
OT::Sanitizer<TableType> sanitizer;
|
||||
|
||||
hb_blob_t *source_blob = sanitizer.sanitize (plan->source->reference_table (TableType::tableTag));
|
||||
hb_blob_t *source_blob = hb_sanitize_context_t ().reference_table<TableType> (plan->source);
|
||||
const TableType *table = source_blob->as<TableType> ();
|
||||
|
||||
hb_tag_t tag = TableType::tableTag;
|
||||
hb_bool_t result = false;
|
||||
if (table != &Null(TableType))
|
||||
if (source_blob->data)
|
||||
{
|
||||
result = table->subset(plan);
|
||||
} else {
|
||||
|
@ -159,14 +157,14 @@ _hb_subset_face_data_reference_blob (hb_subset_face_data_t *data)
|
|||
if (unlikely (!buf))
|
||||
return nullptr;
|
||||
|
||||
OT::hb_serialize_context_t c (buf, face_length);
|
||||
hb_serialize_context_t c (buf, face_length);
|
||||
OT::OpenTypeFontFile *f = c.start_serialize<OT::OpenTypeFontFile> ();
|
||||
|
||||
bool is_cff = data->tables.lsearch (HB_TAG ('C','F','F',' ')) || data->tables.lsearch (HB_TAG ('C','F','F','2'));
|
||||
hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;
|
||||
|
||||
OT::Supplier<hb_tag_t> tags_supplier (&data->tables[0].tag, table_count, sizeof (data->tables[0]));
|
||||
OT::Supplier<hb_blob_t *> blobs_supplier (&data->tables[0].blob, table_count, sizeof (data->tables[0]));
|
||||
Supplier<hb_tag_t> tags_supplier (&data->tables[0].tag, table_count, sizeof (data->tables[0]));
|
||||
Supplier<hb_blob_t *> blobs_supplier (&data->tables[0].blob, table_count, sizeof (data->tables[0]));
|
||||
bool ret = f->serialize_single (&c,
|
||||
sfnt_tag,
|
||||
tags_supplier,
|
||||
|
|
|
@ -60,7 +60,8 @@ extern HB_INTERNAL const uint8_t _hb_modified_combining_class[256];
|
|||
HB_UNICODE_FUNC_IMPLEMENT (hb_script_t, script) \
|
||||
/* ^--- Add new simple callbacks here */
|
||||
|
||||
struct hb_unicode_funcs_t {
|
||||
struct hb_unicode_funcs_t
|
||||
{
|
||||
hb_object_header_t header;
|
||||
ASSERT_POD ();
|
||||
|
||||
|
@ -263,9 +264,7 @@ HB_UNICODE_FUNCS_IMPLEMENT_CALLBACKS_SIMPLE
|
|||
#undef HB_UNICODE_FUNC_IMPLEMENT
|
||||
} destroy;
|
||||
};
|
||||
|
||||
|
||||
extern HB_INTERNAL const hb_unicode_funcs_t _hb_unicode_funcs_nil;
|
||||
DECLARE_NULL_INSTANCE (hb_unicode_funcs_t);
|
||||
|
||||
|
||||
/* Modified combining marks */
|
||||
|
|
|
@ -185,7 +185,8 @@ hb_unicode_funcs_create (hb_unicode_funcs_t *parent)
|
|||
}
|
||||
|
||||
|
||||
const hb_unicode_funcs_t _hb_unicode_funcs_nil = {
|
||||
DEFINE_NULL_INSTANCE (hb_unicode_funcs_t) =
|
||||
{
|
||||
HB_OBJECT_HEADER_STATIC,
|
||||
|
||||
nullptr, /* parent */
|
||||
|
@ -209,7 +210,7 @@ const hb_unicode_funcs_t _hb_unicode_funcs_nil = {
|
|||
hb_unicode_funcs_t *
|
||||
hb_unicode_funcs_get_empty (void)
|
||||
{
|
||||
return const_cast<hb_unicode_funcs_t *> (&_hb_unicode_funcs_nil);
|
||||
return const_cast<hb_unicode_funcs_t *> (&Null(hb_unicode_funcs_t));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -309,7 +309,7 @@ HB_SHAPER_DATA_ENSURE_DEFINE(uniscribe, font)
|
|||
* shaper face data
|
||||
*/
|
||||
|
||||
struct hb_uniscribe_shaper_face_data_t {
|
||||
struct hb_uniscribe_face_data_t {
|
||||
HANDLE fh;
|
||||
hb_uniscribe_shaper_funcs_t *funcs;
|
||||
wchar_t face_name[LF_FACESIZE];
|
||||
|
@ -358,7 +358,7 @@ _hb_rename_font (hb_blob_t *blob, wchar_t *new_name)
|
|||
* full, PS. All of them point to the same name data with our unique name.
|
||||
*/
|
||||
|
||||
blob = OT::Sanitizer<OT::OpenTypeFontFile>().sanitize (blob);
|
||||
blob = hb_sanitize_context_t ().sanitize_blob<OT::OpenTypeFontFile> (blob);
|
||||
|
||||
unsigned int length, new_length, name_str_len;
|
||||
const char *orig_sfnt_data = hb_blob_get_data (blob, &length);
|
||||
|
@ -383,7 +383,7 @@ _hb_rename_font (hb_blob_t *blob, wchar_t *new_name)
|
|||
|
||||
memcpy(new_sfnt_data, orig_sfnt_data, length);
|
||||
|
||||
OT::name &name = OT::StructAtOffset<OT::name> (new_sfnt_data, name_table_offset);
|
||||
OT::name &name = StructAtOffset<OT::name> (new_sfnt_data, name_table_offset);
|
||||
name.format.set (0);
|
||||
name.count.set (ARRAY_LENGTH (name_IDs));
|
||||
name.stringOffset.set (name.get_size ());
|
||||
|
@ -399,7 +399,7 @@ _hb_rename_font (hb_blob_t *blob, wchar_t *new_name)
|
|||
}
|
||||
|
||||
/* Copy string data from new_name, converting wchar_t to UTF16BE. */
|
||||
unsigned char *p = &OT::StructAfter<unsigned char> (name);
|
||||
unsigned char *p = &StructAfter<unsigned char> (name);
|
||||
for (unsigned int i = 0; i < name_str_len; i++)
|
||||
{
|
||||
*p++ = new_name[i] >> 8;
|
||||
|
@ -439,10 +439,10 @@ _hb_rename_font (hb_blob_t *blob, wchar_t *new_name)
|
|||
HB_MEMORY_MODE_WRITABLE, nullptr, free);
|
||||
}
|
||||
|
||||
hb_uniscribe_shaper_face_data_t *
|
||||
hb_uniscribe_face_data_t *
|
||||
_hb_uniscribe_shaper_face_data_create (hb_face_t *face)
|
||||
{
|
||||
hb_uniscribe_shaper_face_data_t *data = (hb_uniscribe_shaper_face_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_face_data_t));
|
||||
hb_uniscribe_face_data_t *data = (hb_uniscribe_face_data_t *) calloc (1, sizeof (hb_uniscribe_face_data_t));
|
||||
if (unlikely (!data))
|
||||
return nullptr;
|
||||
|
||||
|
@ -479,7 +479,7 @@ _hb_uniscribe_shaper_face_data_create (hb_face_t *face)
|
|||
}
|
||||
|
||||
void
|
||||
_hb_uniscribe_shaper_face_data_destroy (hb_uniscribe_shaper_face_data_t *data)
|
||||
_hb_uniscribe_shaper_face_data_destroy (hb_uniscribe_face_data_t *data)
|
||||
{
|
||||
RemoveFontMemResourceEx (data->fh);
|
||||
free (data);
|
||||
|
@ -490,7 +490,7 @@ _hb_uniscribe_shaper_face_data_destroy (hb_uniscribe_shaper_face_data_t *data)
|
|||
* shaper font data
|
||||
*/
|
||||
|
||||
struct hb_uniscribe_shaper_font_data_t {
|
||||
struct hb_uniscribe_font_data_t {
|
||||
HDC hdc;
|
||||
LOGFONTW log_font;
|
||||
HFONT hfont;
|
||||
|
@ -508,19 +508,19 @@ populate_log_font (LOGFONTW *lf,
|
|||
lf->lfCharSet = DEFAULT_CHARSET;
|
||||
|
||||
hb_face_t *face = font->face;
|
||||
hb_uniscribe_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
|
||||
hb_uniscribe_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
|
||||
|
||||
memcpy (lf->lfFaceName, face_data->face_name, sizeof (lf->lfFaceName));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
hb_uniscribe_shaper_font_data_t *
|
||||
hb_uniscribe_font_data_t *
|
||||
_hb_uniscribe_shaper_font_data_create (hb_font_t *font)
|
||||
{
|
||||
if (unlikely (!hb_uniscribe_shaper_face_data_ensure (font->face))) return nullptr;
|
||||
|
||||
hb_uniscribe_shaper_font_data_t *data = (hb_uniscribe_shaper_font_data_t *) calloc (1, sizeof (hb_uniscribe_shaper_font_data_t));
|
||||
hb_uniscribe_font_data_t *data = (hb_uniscribe_font_data_t *) calloc (1, sizeof (hb_uniscribe_font_data_t));
|
||||
if (unlikely (!data))
|
||||
return nullptr;
|
||||
|
||||
|
@ -559,7 +559,7 @@ _hb_uniscribe_shaper_font_data_create (hb_font_t *font)
|
|||
}
|
||||
|
||||
void
|
||||
_hb_uniscribe_shaper_font_data_destroy (hb_uniscribe_shaper_font_data_t *data)
|
||||
_hb_uniscribe_shaper_font_data_destroy (hb_uniscribe_font_data_t *data)
|
||||
{
|
||||
if (data->hdc)
|
||||
ReleaseDC (nullptr, data->hdc);
|
||||
|
@ -574,7 +574,7 @@ LOGFONTW *
|
|||
hb_uniscribe_font_get_logfontw (hb_font_t *font)
|
||||
{
|
||||
if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return nullptr;
|
||||
hb_uniscribe_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
|
||||
hb_uniscribe_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
|
||||
return &font_data->log_font;
|
||||
}
|
||||
|
||||
|
@ -582,7 +582,7 @@ HFONT
|
|||
hb_uniscribe_font_get_hfont (hb_font_t *font)
|
||||
{
|
||||
if (unlikely (!hb_uniscribe_shaper_font_data_ensure (font))) return nullptr;
|
||||
hb_uniscribe_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
|
||||
hb_uniscribe_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
|
||||
return font_data->hfont;
|
||||
}
|
||||
|
||||
|
@ -591,20 +591,20 @@ hb_uniscribe_font_get_hfont (hb_font_t *font)
|
|||
* shaper shape_plan data
|
||||
*/
|
||||
|
||||
struct hb_uniscribe_shaper_shape_plan_data_t {};
|
||||
struct hb_uniscribe_shape_plan_data_t {};
|
||||
|
||||
hb_uniscribe_shaper_shape_plan_data_t *
|
||||
hb_uniscribe_shape_plan_data_t *
|
||||
_hb_uniscribe_shaper_shape_plan_data_create (hb_shape_plan_t *shape_plan HB_UNUSED,
|
||||
const hb_feature_t *user_features HB_UNUSED,
|
||||
unsigned int num_user_features HB_UNUSED,
|
||||
const int *coords HB_UNUSED,
|
||||
unsigned int num_coords HB_UNUSED)
|
||||
{
|
||||
return (hb_uniscribe_shaper_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
return (hb_uniscribe_shape_plan_data_t *) HB_SHAPER_DATA_SUCCEEDED;
|
||||
}
|
||||
|
||||
void
|
||||
_hb_uniscribe_shaper_shape_plan_data_destroy (hb_uniscribe_shaper_shape_plan_data_t *data HB_UNUSED)
|
||||
_hb_uniscribe_shaper_shape_plan_data_destroy (hb_uniscribe_shape_plan_data_t *data HB_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -622,8 +622,8 @@ _hb_uniscribe_shape (hb_shape_plan_t *shape_plan,
|
|||
unsigned int num_features)
|
||||
{
|
||||
hb_face_t *face = font->face;
|
||||
hb_uniscribe_shaper_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
|
||||
hb_uniscribe_shaper_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
|
||||
hb_uniscribe_face_data_t *face_data = HB_SHAPER_DATA_GET (face);
|
||||
hb_uniscribe_font_data_t *font_data = HB_SHAPER_DATA_GET (font);
|
||||
hb_uniscribe_shaper_funcs_t *funcs = face_data->funcs;
|
||||
|
||||
/*
|
||||
|
|
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
* Copyright © 2017,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_VECTOR_PRIVATE_HH
|
||||
#define HB_VECTOR_PRIVATE_HH
|
||||
|
||||
#include "hb-private.hh"
|
||||
|
||||
|
||||
template <typename Type, unsigned int StaticSize=8>
|
||||
struct hb_vector_t
|
||||
{
|
||||
unsigned int len;
|
||||
unsigned int allocated; /* == 0 means allocation failed. */
|
||||
Type *arrayZ;
|
||||
Type static_array[StaticSize];
|
||||
|
||||
void init (void)
|
||||
{
|
||||
len = 0;
|
||||
allocated = ARRAY_LENGTH (static_array);
|
||||
arrayZ = static_array;
|
||||
}
|
||||
|
||||
inline Type& operator [] (unsigned int i)
|
||||
{
|
||||
if (unlikely (i >= len))
|
||||
return Crap (Type);
|
||||
return arrayZ[i];
|
||||
}
|
||||
inline const Type& operator [] (unsigned int i) const
|
||||
{
|
||||
if (unlikely (i >= len))
|
||||
return Null(Type);
|
||||
return arrayZ[i];
|
||||
}
|
||||
|
||||
inline Type *push (void)
|
||||
{
|
||||
if (unlikely (!resize (len + 1)))
|
||||
return &Crap(Type);
|
||||
return &arrayZ[len - 1];
|
||||
}
|
||||
inline Type *push (const Type& v)
|
||||
{
|
||||
Type *p = push ();
|
||||
*p = v;
|
||||
return p;
|
||||
}
|
||||
|
||||
/* Allocate for size but don't adjust len. */
|
||||
inline bool alloc (unsigned int size)
|
||||
{
|
||||
if (unlikely (!allocated))
|
||||
return false;
|
||||
|
||||
if (likely (size <= allocated))
|
||||
return true;
|
||||
|
||||
/* Reallocate */
|
||||
|
||||
unsigned int new_allocated = allocated;
|
||||
while (size >= new_allocated)
|
||||
new_allocated += (new_allocated >> 1) + 8;
|
||||
|
||||
Type *new_array = nullptr;
|
||||
|
||||
if (arrayZ == static_array)
|
||||
{
|
||||
new_array = (Type *) calloc (new_allocated, sizeof (Type));
|
||||
if (new_array)
|
||||
memcpy (new_array, arrayZ, len * sizeof (Type));
|
||||
}
|
||||
else
|
||||
{
|
||||
bool overflows = (new_allocated < allocated) || hb_unsigned_mul_overflows (new_allocated, sizeof (Type));
|
||||
if (likely (!overflows))
|
||||
new_array = (Type *) realloc (arrayZ, new_allocated * sizeof (Type));
|
||||
}
|
||||
|
||||
if (unlikely (!new_array))
|
||||
{
|
||||
allocated = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
arrayZ = new_array;
|
||||
allocated = new_allocated;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool resize (int size_)
|
||||
{
|
||||
unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
|
||||
if (!alloc (size))
|
||||
return false;
|
||||
|
||||
if (size > len)
|
||||
memset (arrayZ + len, 0, (size - len) * sizeof (*arrayZ));
|
||||
|
||||
len = size;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void pop (void)
|
||||
{
|
||||
if (!len) return;
|
||||
len--;
|
||||
}
|
||||
|
||||
inline void remove (unsigned int i)
|
||||
{
|
||||
if (unlikely (i >= len))
|
||||
return;
|
||||
memmove (static_cast<void *> (&arrayZ[i]),
|
||||
static_cast<void *> (&arrayZ[i + 1]),
|
||||
(len - i - 1) * sizeof (Type));
|
||||
len--;
|
||||
}
|
||||
|
||||
inline void shrink (int size_)
|
||||
{
|
||||
unsigned int size = size_ < 0 ? 0u : (unsigned int) size_;
|
||||
if (size < len)
|
||||
len = size;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Type *find (T v) {
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
if (arrayZ[i] == v)
|
||||
return &arrayZ[i];
|
||||
return nullptr;
|
||||
}
|
||||
template <typename T>
|
||||
inline const Type *find (T v) const {
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
if (arrayZ[i] == v)
|
||||
return &arrayZ[i];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
inline void qsort (int (*cmp)(const void*, const void*))
|
||||
{
|
||||
::qsort (arrayZ, len, sizeof (Type), cmp);
|
||||
}
|
||||
|
||||
inline void qsort (void)
|
||||
{
|
||||
::qsort (arrayZ, len, sizeof (Type), Type::cmp);
|
||||
}
|
||||
|
||||
inline void qsort (unsigned int start, unsigned int end)
|
||||
{
|
||||
::qsort (arrayZ + start, end - start, sizeof (Type), Type::cmp);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Type *lsearch (const T &x)
|
||||
{
|
||||
for (unsigned int i = 0; i < len; i++)
|
||||
if (0 == this->arrayZ[i].cmp (&x))
|
||||
return &arrayZ[i];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Type *bsearch (const T &x)
|
||||
{
|
||||
unsigned int i;
|
||||
return bfind (x, &i) ? &arrayZ[i] : nullptr;
|
||||
}
|
||||
template <typename T>
|
||||
inline const Type *bsearch (const T &x) const
|
||||
{
|
||||
unsigned int i;
|
||||
return bfind (x, &i) ? &arrayZ[i] : nullptr;
|
||||
}
|
||||
template <typename T>
|
||||
inline bool bfind (const T &x, unsigned int *i) const
|
||||
{
|
||||
int min = 0, max = (int) this->len - 1;
|
||||
while (min <= max)
|
||||
{
|
||||
int mid = (min + max) / 2;
|
||||
int c = this->arrayZ[mid].cmp (&x);
|
||||
if (c < 0)
|
||||
max = mid - 1;
|
||||
else if (c > 0)
|
||||
min = mid + 1;
|
||||
else
|
||||
{
|
||||
*i = mid;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (max < 0 || (max < (int) this->len && this->arrayZ[max].cmp (&x) > 0))
|
||||
max++;
|
||||
*i = max;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void fini (void)
|
||||
{
|
||||
if (arrayZ != static_array)
|
||||
free (arrayZ);
|
||||
arrayZ = nullptr;
|
||||
allocated = len = 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif /* HB_VECTOR_PRIVATE_HH */
|
|
@ -38,9 +38,9 @@ HB_BEGIN_DECLS
|
|||
|
||||
#define HB_VERSION_MAJOR 1
|
||||
#define HB_VERSION_MINOR 8
|
||||
#define HB_VERSION_MICRO 3
|
||||
#define HB_VERSION_MICRO 7
|
||||
|
||||
#define HB_VERSION_STRING "1.8.3"
|
||||
#define HB_VERSION_STRING "1.8.7"
|
||||
|
||||
#define HB_VERSION_ATLEAST(major,minor,micro) \
|
||||
((major)*10000+(minor)*100+(micro) <= \
|
||||
|
|
|
@ -51,10 +51,9 @@ main (int argc, char **argv)
|
|||
const char *font_data = hb_blob_get_data (blob, &len);
|
||||
printf ("Opened font file %s: %d bytes long\n", argv[1], len);
|
||||
|
||||
Sanitizer<OpenTypeFontFile> sanitizer;
|
||||
hb_blob_t *font_blob = sanitizer.sanitize (blob);
|
||||
hb_blob_t *font_blob = hb_sanitize_context_t().sanitize_blob<OpenTypeFontFile> (blob);
|
||||
const OpenTypeFontFile* sanitized = font_blob->as<OpenTypeFontFile> ();
|
||||
if (sanitized == &Null(OpenTypeFontFile))
|
||||
if (!font_blob->data)
|
||||
{
|
||||
printf ("Sanitization of the file wasn't successful. Exit");
|
||||
return 1;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
MY_TEMP_DIR=`mktemp -d -t harfbuzz_update.XXXXXX` || exit 1
|
||||
|
||||
VERSION=1.8.3
|
||||
VERSION=1.8.7
|
||||
|
||||
git clone https://github.com/harfbuzz/harfbuzz ${MY_TEMP_DIR}/harfbuzz
|
||||
git -C ${MY_TEMP_DIR}/harfbuzz checkout ${VERSION}
|
||||
|
|
Загрузка…
Ссылка в новой задаче