harfbuzz/src/hb-ot-cff1-table.hh

899 lines
25 KiB
C++
Raw Normal View History

/*
* Copyright © 2018 Adobe Systems Incorporated.
*
* This is part of HarfBuzz, a text shaping library.
*
* Permission is hereby granted, without written agreement and without
* license or royalty fees, to use, copy, modify, and distribute this
* software and its documentation for any purpose, provided that the
* above copyright notice and the following two paragraphs appear in
* all copies of this software.
*
* IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
* DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
* ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
* IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
* ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
* PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* Adobe Author(s): Michiharu Ariza
*/
#ifndef HB_OT_CFF1_TABLE_HH
#define HB_OT_CFF1_TABLE_HH
#include "hb-ot-cff-common.hh"
#include "hb-subset-cff1.hh"
namespace CFF {
/*
* CFF -- Compact Font Format (CFF)
* http://www.adobe.com/content/dam/acom/en/devnet/font/pdfs/5176.CFF.pdf
*/
#define HB_OT_TAG_cff1 HB_TAG('C','F','F',' ')
typedef CFFIndex<HBUINT16> CFF1Index;
template <typename Type> struct CFF1IndexOf : IndexOf<HBUINT16, Type> {};
typedef CFFIndex<HBUINT16> CFF1Index;
typedef CFF1Index CFF1CharStrings;
typedef FDArray<HBUINT16> CFF1FDArray;
typedef Subrs<HBUINT16> CFF1Subrs;
struct CFF1FDSelect : FDSelect {};
/* Encoding */
struct Encoding0 {
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && codes[nCodes - 1].sanitize (c));
}
inline bool get_code (hb_codepoint_t glyph, hb_codepoint_t &code) const
{
if (glyph < nCodes)
{
code = (hb_codepoint_t)codes[glyph];
return true;
}
else
return false;
}
inline unsigned int get_size (void) const
{ return HBUINT8::static_size * (nCodes + 1); }
HBUINT8 nCodes;
HBUINT8 codes[VAR];
DEFINE_SIZE_ARRAY(1, codes);
};
struct Encoding1_Range {
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
HBUINT8 first;
HBUINT8 nLeft;
DEFINE_SIZE_STATIC (2);
};
struct Encoding1 {
inline unsigned int get_size (void) const
{ return HBUINT8::static_size + Encoding1_Range::static_size * nRanges; }
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && ((nRanges == 0) || (ranges[nRanges - 1]).sanitize (c)));
}
inline bool get_code (hb_codepoint_t glyph, hb_codepoint_t &code) const
{
for (unsigned int i = 0; i < nRanges; i++)
{
if (glyph <= ranges[i].nLeft)
{
code = (hb_codepoint_t)ranges[i].first + glyph;
return true;
}
glyph -= (ranges[i].nLeft + 1);
}
return false;
}
HBUINT8 nRanges;
Encoding1_Range ranges[VAR];
DEFINE_SIZE_ARRAY (1, ranges);
};
struct EncSupplement {
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
HBUINT8 code;
HBUINT16 glyph;
DEFINE_SIZE_STATIC (3);
};
struct CFF1SuppEncData {
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && ((nSups == 0) || (supps[nSups - 1]).sanitize (c)));
}
inline bool get_code (hb_codepoint_t glyph, hb_codepoint_t &code) const
{
for (unsigned int i = 0; i < nSups; i++)
if (glyph == supps[i].glyph)
{
code = supps[i].code;
return true;
}
return false;
}
inline unsigned int get_size (void) const
{ return HBUINT8::static_size + EncSupplement::static_size * nSups; }
HBUINT8 nSups;
EncSupplement supps[VAR];
DEFINE_SIZE_ARRAY (1, supps);
};
struct Encoding {
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return_trace (false);
unsigned int fmt = format & 0x7F;
if (unlikely (fmt > 1))
return_trace (false);
if (unlikely (!((fmt == 0)? u.format0.sanitize (c): u.format1.sanitize (c))))
return_trace (false);
return_trace (((format & 0x80) == 0) || suppEncData ().sanitize (c));
}
inline bool serialize (hb_serialize_context_t *c, const Encoding &src, unsigned int num_glyphs)
{
TRACE_SERIALIZE (this);
unsigned int size = src.get_size ();
Encoding *dest = c->allocate_size<Encoding> (size);
if (unlikely (dest == nullptr)) return_trace (false);
memcpy (dest, &src, size);
return_trace (true);
}
inline unsigned int calculate_serialized_size (void) const
{ return get_size (); } // XXX: TODO
inline unsigned int get_size (void) const
{
unsigned int size = min_size;
if ((format & 0x7F) == 0)
size += u.format0.get_size ();
else
size += u.format1.get_size ();
if ((format & 0x80) != 0)
size += suppEncData ().get_size ();
return size;
}
inline bool get_code (hb_codepoint_t glyph, hb_codepoint_t &code) const
{
// XXX: TODO
return false;
}
inline const CFF1SuppEncData &suppEncData (void) const
{
if ((format & 0x7F) == 0)
return StructAfter<CFF1SuppEncData> (u.format0.codes[u.format0.nCodes-1]);
else
return StructAfter<CFF1SuppEncData> (u.format1.ranges[u.format1.nRanges-1]);
}
HBUINT8 format;
union {
Encoding0 format0;
Encoding1 format1;
} u;
/* CFF1SuppEncData suppEncData; */
DEFINE_SIZE_MIN (1);
};
/* Charset */
struct Charset0 {
inline bool sanitize (hb_sanitize_context_t *c, unsigned int num_glyphs) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && sids[num_glyphs - 1].sanitize (c));
}
inline unsigned int get_sid (hb_codepoint_t glyph)
{
if (glyph == 0)
return 0;
else
return sids[glyph - 1];
}
inline unsigned int get_size (unsigned int num_glyphs) const
{
assert (num_glyphs > 0);
return HBUINT16::static_size * (num_glyphs - 1);
}
HBUINT16 sids[VAR];
DEFINE_SIZE_ARRAY(0, sids);
};
template <typename TYPE>
struct Charset_Range {
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this));
}
HBUINT8 first;
TYPE nLeft;
DEFINE_SIZE_STATIC (1 + TYPE::static_size);
};
template <typename TYPE>
struct Charset1_2 {
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) && ((nRanges == 0) || (ranges[nRanges - 1]).sanitize (c)));
}
inline bool get_sid (hb_codepoint_t glyph, unsigned int &sid) const
{
for (unsigned int i = 0; i < nRanges; i++)
{
if (glyph <= ranges[i].nLeft)
{
sid = (hb_codepoint_t)ranges[i].first + glyph;
return true;
}
glyph -= (ranges[i].nLeft + 1);
}
return false;
}
inline unsigned int get_size (void) const
{ return HBUINT8::static_size + Charset_Range<TYPE>::static_size * nRanges; }
HBUINT8 nRanges;
Charset_Range<TYPE> ranges[VAR];
DEFINE_SIZE_ARRAY (1, ranges);
};
struct Charset {
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
return_trace (false);
if (format == 0)
return_trace (u.format0.sanitize (c, c->get_num_glyphs ()));
else if (format == 1)
return_trace (u.format1.sanitize (c));
else if (likely (format == 2))
return_trace (u.format2.sanitize (c));
else
return_trace (false);
}
inline bool serialize (hb_serialize_context_t *c, const Charset &src, unsigned int num_glyphs)
{
TRACE_SERIALIZE (this);
unsigned int size = src.get_size (num_glyphs);
Charset *dest = c->allocate_size<Charset> (size);
if (unlikely (dest == nullptr)) return_trace (false);
memcpy (dest, &src, size);
return_trace (true);
}
inline unsigned int calculate_serialized_size (unsigned int num_glyphs) const
{ return get_size (num_glyphs); } // XXX: TODO
inline unsigned int get_size (unsigned int num_glyphs) const
{
unsigned int size = min_size;
if (format == 0)
size += u.format0.get_size (num_glyphs);
else if (format == 1)
size += u.format1.get_size ();
else
size += u.format2.get_size ();
return size;
}
inline bool get_sid (hb_codepoint_t glyph, unsigned int &sid) const
{
// XXX: TODO
return false;
}
HBUINT8 format;
union {
Charset0 format0;
Charset1_2<HBUINT8> format1;
Charset1_2<HBUINT16> format2;
} u;
DEFINE_SIZE_MIN (1);
};
struct CFF1TopDictValues : TopDictValues
{
inline void init (void)
{
TopDictValues::init ();
ros[0] = ros[1] = ros[2] = 0;
cidCount = 8720;
EncodingOffset = 0;
CharsetOffset = 0;
FDSelectOffset = 0;
privateDictInfo.init ();
}
inline void fini (void)
{
TopDictValues::fini ();
}
inline bool is_CID (void) const
{ return ros[0] != 0; }
inline unsigned int calculate_serialized_size (void) const
{
unsigned int size = 0;
for (unsigned int i = 0; i < values.len; i++)
{
OpCode op = values[i].op;
switch (op)
{
case OpCode_FDSelect:
size += OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op);
break;
default:
size += TopDictValues::calculate_serialized_op_size (values[i]);
break;
}
}
return size;
}
unsigned int ros[3]; /* registry, ordering, supplement */
unsigned int cidCount;
enum EncodingID { StandardEncoding = 0, ExpertEncoding = 1 };
unsigned int EncodingOffset;
unsigned int CharsetOffset;
unsigned int FDSelectOffset;
TableInfo privateDictInfo;
};
struct CFF1TopDictOpSet : TopDictOpSet
{
static inline bool process_op (OpCode op, InterpEnv& env, CFF1TopDictValues& dictval)
{
switch (op) {
case OpCode_version:
case OpCode_Notice:
case OpCode_Copyright:
case OpCode_FullName:
case OpCode_FamilyName:
case OpCode_Weight:
case OpCode_isFixedPitch:
case OpCode_ItalicAngle:
case OpCode_UnderlinePosition:
case OpCode_UnderlineThickness:
case OpCode_PaintType:
case OpCode_CharstringType:
case OpCode_UniqueID:
case OpCode_StrokeWidth:
case OpCode_SyntheticBase:
case OpCode_PostScript:
case OpCode_BaseFontName:
case OpCode_CIDFontVersion:
case OpCode_CIDFontRevision:
case OpCode_CIDFontType:
case OpCode_UIDBase:
case OpCode_FontBBox:
case OpCode_XUID:
case OpCode_BaseFontBlend:
env.argStack.clear ();
break;
case OpCode_CIDCount:
if (unlikely (!env.argStack.check_pop_uint (dictval.cidCount)))
return false;
env.argStack.clear ();
break;
case OpCode_ROS:
if (unlikely (!env.argStack.check_pop_uint (dictval.ros[2]) ||
!env.argStack.check_pop_uint (dictval.ros[1]) ||
!env.argStack.check_pop_uint (dictval.ros[0])))
return false;
env.argStack.clear ();
break;
case OpCode_Encoding:
if (unlikely (!env.argStack.check_pop_uint (dictval.EncodingOffset)))
return false;
env.argStack.clear ();
break;
case OpCode_charset:
if (unlikely (!env.argStack.check_pop_uint (dictval.CharsetOffset)))
return false;
env.argStack.clear ();
break;
case OpCode_FDSelect:
if (unlikely (!env.argStack.check_pop_uint (dictval.FDSelectOffset)))
return false;
env.argStack.clear ();
break;
case OpCode_Private:
if (unlikely (!env.argStack.check_pop_uint (dictval.privateDictInfo.offset)))
return false;
if (unlikely (!env.argStack.check_pop_uint (dictval.privateDictInfo.size)))
return false;
env.argStack.clear ();
break;
default:
if (unlikely (!TopDictOpSet::process_op (op, env, dictval)))
return false;
/* Record this operand below if stack is empty, otherwise done */
if (!env.argStack.is_empty ()) return true;
break;
}
dictval.pushVal (op, env.substr);
return true;
}
};
struct CFF1FontDictValues : DictValues<OpStr>
{
inline void init (void)
{
DictValues<OpStr>::init ();
privateDictInfo.init ();
}
inline void fini (void)
{
DictValues<OpStr>::fini ();
}
TableInfo privateDictInfo;
};
struct CFF1FontDictOpSet : DictOpSet
{
static inline bool process_op (OpCode op, InterpEnv& env, CFF1FontDictValues& dictval)
{
switch (op) {
case OpCode_FontName:
case OpCode_FontMatrix:
case OpCode_PaintType:
env.argStack.clear ();
break;
case OpCode_Private:
if (unlikely (!env.argStack.check_pop_uint (dictval.privateDictInfo.offset)))
return false;
if (unlikely (!env.argStack.check_pop_uint (dictval.privateDictInfo.size)))
return false;
env.argStack.clear ();
break;
default:
if (unlikely (!DictOpSet::process_op (op, env)))
return false;
if (!env.argStack.is_empty ()) return true;
break;
}
dictval.pushVal (op, env.substr);
return true;
}
};
template <typename VAL>
struct CFF1PrivateDictValues_Base : DictValues<VAL>
{
inline void init (void)
{
DictValues<VAL>::init ();
subrsOffset = 0;
localSubrs = &Null(CFF1Subrs);
}
inline void fini (void)
{
DictValues<VAL>::fini ();
}
inline unsigned int calculate_serialized_size (void) const
{
unsigned int size = 0;
for (unsigned int i = 0; i < DictValues<VAL>::values.len; i++)
if (DictValues<VAL>::values[i].op == OpCode_Subrs)
size += OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs);
else
size += DictValues<VAL>::values[i].str.len;
return size;
}
unsigned int subrsOffset;
const CFF1Subrs *localSubrs;
};
typedef CFF1PrivateDictValues_Base<OpStr> CFF1PrivateDictValues_Subset;
typedef CFF1PrivateDictValues_Base<DictVal> CFF1PrivateDictValues;
struct CFF1PrivateDictOpSet : DictOpSet
{
static inline bool process_op (OpCode op, InterpEnv& env, CFF1PrivateDictValues& dictval)
{
DictVal val;
val.init ();
switch (op) {
case OpCode_BlueValues:
case OpCode_OtherBlues:
case OpCode_FamilyBlues:
case OpCode_FamilyOtherBlues:
case OpCode_StemSnapH:
case OpCode_StemSnapV:
if (unlikely (!env.argStack.check_pop_delta (val.multi_val)))
return false;
break;
case OpCode_StdHW:
case OpCode_StdVW:
case OpCode_BlueScale:
case OpCode_BlueShift:
case OpCode_BlueFuzz:
case OpCode_ForceBold:
case OpCode_LanguageGroup:
case OpCode_ExpansionFactor:
case OpCode_initialRandomSeed:
case OpCode_defaultWidthX:
case OpCode_nominalWidthX:
if (unlikely (!env.argStack.check_pop_num (val.single_val)))
return false;
env.argStack.clear ();
break;
case OpCode_Subrs:
if (unlikely (!env.argStack.check_pop_uint (dictval.subrsOffset)))
return false;
env.argStack.clear ();
break;
default:
if (unlikely (!DictOpSet::process_op (op, env)))
return false;
if (!env.argStack.is_empty ()) return true;
break;
}
dictval.pushVal (op, env.substr, val);
return true;
}
};
struct CFF1PrivateDictOpSet_Subset : DictOpSet
{
static inline bool process_op (OpCode op, InterpEnv& env, CFF1PrivateDictValues_Subset& dictval)
{
switch (op) {
case OpCode_BlueValues:
case OpCode_OtherBlues:
case OpCode_FamilyBlues:
case OpCode_FamilyOtherBlues:
case OpCode_StemSnapH:
case OpCode_StemSnapV:
case OpCode_StdHW:
case OpCode_StdVW:
case OpCode_BlueScale:
case OpCode_BlueShift:
case OpCode_BlueFuzz:
case OpCode_ForceBold:
case OpCode_LanguageGroup:
case OpCode_ExpansionFactor:
case OpCode_initialRandomSeed:
case OpCode_defaultWidthX:
case OpCode_nominalWidthX:
env.argStack.clear ();
break;
case OpCode_Subrs:
if (unlikely (!env.argStack.check_pop_uint (dictval.subrsOffset)))
return false;
env.argStack.clear ();
break;
default:
if (unlikely (!DictOpSet::process_op (op, env)))
return false;
if (!env.argStack.is_empty ()) return true;
break;
}
dictval.pushVal (op, env.substr);
return true;
}
};
typedef DictInterpreter<CFF1TopDictOpSet, CFF1TopDictValues> CFF1TopDict_Interpreter;
typedef DictInterpreter<CFF1FontDictOpSet, CFF1FontDictValues> CFF1FontDict_Interpreter;
typedef DictInterpreter<CFF1PrivateDictOpSet, CFF1PrivateDictValues> CFF1PrivateDict_Interpreter;
typedef CFF1Index CFF1NameIndex;
typedef CFF1IndexOf<TopDict> CFF1TopDictIndex;
typedef CFF1Index CFF1StringIndex;
}; /* namespace CFF */
namespace OT {
using namespace CFF;
struct cff1
{
static const hb_tag_t tableTag = HB_OT_TAG_cff1;
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
return_trace (c->check_struct (this) &&
likely (version.major == 1));
}
template <typename PrivOpSet, typename PrivDictVal>
struct accelerator_templ_t
{
inline void init (hb_face_t *face)
{
topDicts.init ();
topDicts.resize (1);
topDicts[0].init ();
fontDicts.init ();
privateDicts.init ();
this->blob = sc.reference_table<cff1> (face);
/* setup for run-time santization */
sc.init (this->blob);
sc.start_processing ();
const OT::cff1 *cff = this->blob->template as<OT::cff1> ();
if (cff == &Null(OT::cff1))
{ fini (); return; }
nameIndex = &cff->nameIndex (cff);
if ((nameIndex == &Null (CFF1NameIndex)) || !nameIndex->sanitize (&sc))
{ fini (); return; }
topDictIndex = &StructAtOffset<CFF1TopDictIndex> (nameIndex, nameIndex->get_size ());
if ((topDictIndex == &Null (CFF1TopDictIndex)) || !topDictIndex->sanitize (&sc) || (topDictIndex->count == 0))
{ fini (); return; }
{ /* parse top dict */
const ByteStr topDictStr = (*topDictIndex)[0];
if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; }
CFF1TopDict_Interpreter top_interp;
top_interp.env.init (topDictStr);
if (unlikely (!top_interp.interpret (topDicts[0]))) { fini (); return; }
}
encoding = &Null(Encoding);
charset = &StructAtOffsetOrNull<Charset> (cff, topDicts[0].CharsetOffset);
fdCount = 1;
if (is_CID ())
{
fdArray = &StructAtOffsetOrNull<CFF1FDArray> (cff, topDicts[0].FDArrayOffset);
fdSelect = &StructAtOffsetOrNull<CFF1FDSelect> (cff, topDicts[0].FDSelectOffset);
if (unlikely ((fdArray == &Null(CFF1FDArray)) || !fdArray->sanitize (&sc) ||
(fdSelect == &Null(CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count)))
{ fini (); return; }
fdCount = fdArray->count;
}
else
{
fdArray = &Null(CFF1FDArray);
fdSelect = &Null(CFF1FDSelect);
if (topDicts[0].EncodingOffset != CFF1TopDictValues::StandardEncoding &&
topDicts[0].EncodingOffset != CFF1TopDictValues::ExpertEncoding)
{
encoding = &StructAtOffsetOrNull<Encoding> (cff, topDicts[0].EncodingOffset);
if ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))
{ fini (); return; }
}
}
stringIndex = &StructAtOffset<CFF1StringIndex> (topDictIndex, topDictIndex->get_size ());
if ((stringIndex == &Null (CFF1StringIndex)) || !stringIndex->sanitize (&sc))
{ fini (); return; }
globalSubrs = &StructAtOffset<CFF1Subrs> (stringIndex, stringIndex->get_size ());
if ((globalSubrs != &Null (CFF1Subrs)) && !stringIndex->sanitize (&sc))
{ fini (); return; }
charStrings = &StructAtOffsetOrNull<CFF1CharStrings> (cff, topDicts[0].charStringsOffset);
if ((charStrings == &Null(CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc)))
{ fini (); return; }
num_glyphs = charStrings->count;
if (num_glyphs != sc.get_num_glyphs ())
{ fini (); return; }
privateDicts.resize (fdCount);
for (unsigned int i = 0; i < fdCount; i++)
privateDicts[i].init ();
// parse CID font dicts and gather private dicts
if (is_CID ())
{
for (unsigned int i = 0; i < fdCount; i++)
{
ByteStr fontDictStr = (*fdArray)[i];
if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; }
CFF1FontDictValues *font;
CFF1FontDict_Interpreter font_interp;
font_interp.env.init (fontDictStr);
font = fontDicts.push ();
if (unlikely (!font_interp.interpret (*font))) { fini (); return; }
PrivDictVal *priv = &privateDicts[i];
const ByteStr privDictStr (StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size);
if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; }
DictInterpreter<PrivOpSet, PrivDictVal> priv_interp;
priv_interp.env.init (privDictStr);
if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; }
priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (privDictStr.str, priv->subrsOffset);
if (priv->localSubrs != &Null(CFF1Subrs) &&
unlikely (!priv->localSubrs->sanitize (&sc)))
{ fini (); return; }
}
}
else /* non-CID */
{
CFF1TopDictValues *font = &topDicts[0];
PrivDictVal *priv = &privateDicts[0];
const ByteStr privDictStr (StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size);
if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; }
DictInterpreter<PrivOpSet, PrivDictVal> priv_interp;
priv_interp.env.init (privDictStr);
if (unlikely (!priv_interp.interpret (*priv))) { fini (); return; }
priv->localSubrs = &StructAtOffsetOrNull<CFF1Subrs> (privDictStr.str, priv->subrsOffset);
if (priv->localSubrs != &Null(CFF1Subrs) &&
unlikely (!priv->localSubrs->sanitize (&sc)))
{ fini (); return; }
}
}
inline void fini (void)
{
sc.end_processing ();
topDicts[0].fini ();
topDicts.fini ();
fontDicts.fini ();
privateDicts.fini ();
hb_blob_destroy (blob);
blob = nullptr;
}
inline bool is_valid (void) const { return blob != nullptr; }
inline bool is_CID (void) const { return topDicts[0].is_CID (); }
inline bool get_extents (hb_codepoint_t glyph,
hb_glyph_extents_t *extents) const
{
// XXX: TODO
if (glyph >= num_glyphs)
return false;
return true;
}
protected:
hb_blob_t *blob;
hb_sanitize_context_t sc;
public:
const CFF1NameIndex *nameIndex;
const CFF1TopDictIndex *topDictIndex;
const CFF1StringIndex *stringIndex;
const Encoding *encoding;
const Charset *charset;
const CFF1Subrs *globalSubrs;
const CFF1CharStrings *charStrings;
const CFF1FDArray *fdArray;
const CFF1FDSelect *fdSelect;
unsigned int fdCount;
hb_vector_t<CFF1TopDictValues> topDicts;
hb_vector_t<CFF1FontDictValues> fontDicts;
hb_vector_t<PrivDictVal> privateDicts;
unsigned int num_glyphs;
};
typedef accelerator_templ_t<CFF1PrivateDictOpSet, CFF1PrivateDictValues> accelerator_t;
typedef accelerator_templ_t<CFF1PrivateDictOpSet_Subset, CFF1PrivateDictValues_Subset> accelerator_subset_t;
inline bool subset (hb_subset_plan_t *plan) const
{
hb_blob_t *cff_prime = nullptr;
bool success = true;
if (hb_subset_cff1 (plan, &cff_prime)) {
success = success && plan->add_table (HB_OT_TAG_cff1, cff_prime);
} else {
success = false;
}
hb_blob_destroy (cff_prime);
return success;
}
public:
FixedVersion<HBUINT8> version; /* Version of CFF table. set to 0x0100u */
OffsetTo<CFF1NameIndex, HBUINT8> nameIndex; /* headerSize = Offset to Name INDEX. */
HBUINT8 offSize; /* offset size (unused?) */
public:
DEFINE_SIZE_STATIC (4);
};
} /* namespace OT */
#endif /* HB_OT_CFF1_TABLE_HH */