subset CFF1 String Index

Repurposed FDMap as Remap then subclassed for remapping SIDs
misc code cleanup
This commit is contained in:
Michiharu Ariza 2018-09-10 16:00:20 -07:00
parent 1e88b1755c
commit 1666b89e30
9 changed files with 569 additions and 198 deletions

View File

@ -562,8 +562,6 @@ struct ArgStack : Stack<ARG, 513>
/* an operator prefixed by its operands in a byte string */ /* an operator prefixed by its operands in a byte string */
struct OpStr struct OpStr
{ {
inline void init (void) {}
OpCode op; OpCode op;
ByteStr str; ByteStr str;
}; };

View File

@ -97,21 +97,22 @@ struct DictValues
hb_vector_t<VAL> values; hb_vector_t<VAL> values;
}; };
struct TopDictValues : DictValues<OpStr> template <typename OPSTR=OpStr>
struct TopDictValues : DictValues<OPSTR>
{ {
inline void init (void) inline void init (void)
{ {
DictValues<OpStr>::init (); DictValues<OPSTR>::init ();
charStringsOffset = 0; charStringsOffset = 0;
FDArrayOffset = 0; FDArrayOffset = 0;
} }
inline void fini (void) inline void fini (void)
{ {
DictValues<OpStr>::fini (); DictValues<OPSTR>::fini ();
} }
inline unsigned int calculate_serialized_op_size (const OpStr& opstr) const inline unsigned int calculate_serialized_op_size (const OPSTR& opstr) const
{ {
switch (opstr.op) switch (opstr.op)
{ {
@ -174,9 +175,10 @@ struct DictOpSet : OpSet<Number>
} }
}; };
template <typename VAL=OpStr>
struct TopDictOpSet : DictOpSet struct TopDictOpSet : DictOpSet
{ {
static inline bool process_op (OpCode op, InterpEnv<Number>& env, TopDictValues& dictval) static inline bool process_op (OpCode op, InterpEnv<Number>& env, TopDictValues<VAL> & dictval)
{ {
switch (op) { switch (op) {
case OpCode_CharStrings: case OpCode_CharStrings:

View File

@ -35,6 +35,8 @@ namespace CFF {
using namespace OT; using namespace OT;
#define CFF_UNDEF_CODE 0xFFFFFFFF
/* utility macro */ /* utility macro */
template<typename Type> template<typename Type>
static inline const Type& StructAtOffsetOrNull(const void *P, unsigned int offset) static inline const Type& StructAtOffsetOrNull(const void *P, unsigned int offset)
@ -291,10 +293,8 @@ struct Dict : UnsizedByteStr
} }
template <typename INTTYPE, int minVal, int maxVal> template <typename INTTYPE, int minVal, int maxVal>
inline static bool serialize_offset_op (hb_serialize_context_t *c, OpCode op, int value, OpCode intOp) inline static bool serialize_int_op (hb_serialize_context_t *c, OpCode op, int value, OpCode intOp)
{ {
if (value == 0)
return true;
// XXX: not sure why but LLVM fails to compile the following 'unlikely' macro invocation // XXX: not sure why but LLVM fails to compile the following 'unlikely' macro invocation
if (/*unlikely*/ (!serialize_int<INTTYPE, minVal, maxVal> (c, intOp, value))) if (/*unlikely*/ (!serialize_int<INTTYPE, minVal, maxVal> (c, intOp, value)))
return false; return false;
@ -313,11 +313,23 @@ struct Dict : UnsizedByteStr
return_trace (true); return_trace (true);
} }
inline static bool serialize_uint4_op (hb_serialize_context_t *c, OpCode op, int value)
{ return serialize_int_op<HBUINT32, 0, 0x7FFFFFFF> (c, op, value, OpCode_longintdict); }
inline static bool serialize_uint2_op (hb_serialize_context_t *c, OpCode op, int value)
{ return serialize_int_op<HBUINT16, 0, 0x7FFF> (c, op, value, OpCode_shortint); }
inline static bool serialize_offset4_op (hb_serialize_context_t *c, OpCode op, int value) inline static bool serialize_offset4_op (hb_serialize_context_t *c, OpCode op, int value)
{ return serialize_offset_op<HBUINT32, 0, 0x7FFFFFFF> (c, op, value, OpCode_longintdict); } {
if (value == 0) return true;
return serialize_uint4_op (c, op, value);
}
inline static bool serialize_offset2_op (hb_serialize_context_t *c, OpCode op, int value) inline static bool serialize_offset2_op (hb_serialize_context_t *c, OpCode op, int value)
{ return serialize_offset_op<HBUINT16, 0, 0x7FFF> (c, op, value, OpCode_shortint); } {
if (value == 0) return true;
return serialize_uint2_op (c, op, value);
}
}; };
struct TopDict : Dict {}; struct TopDict : Dict {};
@ -333,9 +345,9 @@ struct TableInfo
unsigned int offSize; unsigned int offSize;
}; };
/* font dict index remap table from fullset FDArray to subset FDArray. /* used to remap font index or SID from fullset to subset.
* set to HB_SET_VALUE_INVALID if excluded from subset */ * set to CFF_UNDEF_CODE if excluded from subset */
struct FDMap : hb_vector_t<hb_codepoint_t> struct Remap : hb_vector_t<hb_codepoint_t>
{ {
inline void init (void) inline void init (void)
{ hb_vector_t<hb_codepoint_t>::init (); } { hb_vector_t<hb_codepoint_t>::init (); }
@ -343,16 +355,26 @@ struct FDMap : hb_vector_t<hb_codepoint_t>
inline void fini (void) inline void fini (void)
{ hb_vector_t<hb_codepoint_t>::fini (); } { hb_vector_t<hb_codepoint_t>::fini (); }
inline bool reset (unsigned int count)
{
if (unlikely (!hb_vector_t<hb_codepoint_t>::resize (count)))
return false;
for (unsigned int i = 0; i < len; i++)
(*this)[i] = CFF_UNDEF_CODE;
count = 0;
return true;
}
inline bool fullset (void) const inline bool fullset (void) const
{ {
for (unsigned int i = 0; i < len; i++) for (unsigned int i = 0; i < len; i++)
if (hb_vector_t<hb_codepoint_t>::operator[] (i) == HB_SET_VALUE_INVALID) if (hb_vector_t<hb_codepoint_t>::operator[] (i) == CFF_UNDEF_CODE)
return false; return false;
return true; return true;
} }
inline bool excludes (hb_codepoint_t fd) const inline bool excludes (hb_codepoint_t id) const
{ return (fd < len) && ((*this)[fd] == HB_SET_VALUE_INVALID); } { return (id < len) && ((*this)[id] == CFF_UNDEF_CODE); }
inline hb_codepoint_t operator[] (hb_codepoint_t i) const inline hb_codepoint_t operator[] (hb_codepoint_t i) const
{ {
@ -367,17 +389,65 @@ struct FDMap : hb_vector_t<hb_codepoint_t>
assert (i < len); assert (i < len);
return hb_vector_t<hb_codepoint_t>::operator[] (i); return hb_vector_t<hb_codepoint_t>::operator[] (i);
} }
inline unsigned int add (unsigned int i)
{
if ((*this)[i] == CFF_UNDEF_CODE)
(*this)[i] = count++;
return (*this)[i];
}
inline hb_codepoint_t get_count (void) const
{ return count; }
protected:
hb_codepoint_t count;
}; };
template <typename COUNT> template <typename COUNT>
struct FDArray : CFFIndexOf<COUNT, FontDict> struct FDArray : CFFIndexOf<COUNT, FontDict>
{ {
/* used by CFF1 */
template <typename DICTVAL, typename OP_SERIALIZER>
inline bool serialize (hb_serialize_context_t *c,
unsigned int offSize_,
const hb_vector_t<DICTVAL> &fontDicts,
OP_SERIALIZER& opszr)
{
TRACE_SERIALIZE (this);
if (unlikely (!c->extend_min (*this))) return_trace (false);
this->count.set (fontDicts.len);
this->offSize.set (offSize_);
if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (fontDicts.len + 1))))
return_trace (false);
/* serialize font dict offsets */
unsigned int offset = 1;
unsigned int fid = 0;
for (; fid < fontDicts.len; fid++)
{
CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset);
offset += FontDict::calculate_serialized_size (fontDicts[fid], opszr);
}
CFFIndexOf<COUNT, FontDict>::set_offset_at (fid, offset);
/* serialize font dicts */
for (unsigned int i = 0; i < fontDicts.len; i++)
{
FontDict *dict = c->start_embed<FontDict> ();
if (unlikely (!dict->serialize (c, fontDicts[i], opszr, fontDicts[i])))
return_trace (false);
}
return_trace (true);
}
/* used by CFF2 */
template <typename DICTVAL, typename OP_SERIALIZER> template <typename DICTVAL, typename OP_SERIALIZER>
inline bool serialize (hb_serialize_context_t *c, inline bool serialize (hb_serialize_context_t *c,
unsigned int offSize_, unsigned int offSize_,
const hb_vector_t<DICTVAL> &fontDicts, const hb_vector_t<DICTVAL> &fontDicts,
unsigned int fdCount, unsigned int fdCount,
const FDMap &fdmap, const Remap &fdmap,
OP_SERIALIZER& opszr, OP_SERIALIZER& opszr,
const hb_vector_t<TableInfo> &privateInfos) const hb_vector_t<TableInfo> &privateInfos)
{ {
@ -415,7 +485,7 @@ struct FDArray : CFFIndexOf<COUNT, FontDict>
inline static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */, inline static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */,
const hb_vector_t<DICTVAL> &fontDicts, const hb_vector_t<DICTVAL> &fontDicts,
unsigned int fdCount, unsigned int fdCount,
const FDMap &fdmap, const Remap &fdmap,
OP_SERIALIZER& opszr) OP_SERIALIZER& opszr)
{ {
unsigned int dictsSize = 0; unsigned int dictsSize = 0;

View File

@ -38,7 +38,7 @@ namespace CFF {
*/ */
#define HB_OT_TAG_cff1 HB_TAG('C','F','F',' ') #define HB_OT_TAG_cff1 HB_TAG('C','F','F',' ')
#define CFF_UNDEF_CODE 0xFFFFFFFF #define CFF_UNDEF_SID CFF_UNDEF_CODE
enum EncodingID { StandardEncoding = 0, ExpertEncoding = 1 }; enum EncodingID { StandardEncoding = 0, ExpertEncoding = 1 };
enum CharsetID { ISOAdobeCharset = 0, ExpertCharset = 1, ExpertSubsetCharset = 2 }; enum CharsetID { ISOAdobeCharset = 0, ExpertCharset = 1, ExpertSubsetCharset = 2 };
@ -529,13 +529,132 @@ struct Charset {
DEFINE_SIZE_MIN (1); DEFINE_SIZE_MIN (1);
}; };
struct CFF1TopDictValues : TopDictValues struct CFF1StringIndex : CFF1Index
{
inline bool serialize (hb_serialize_context_t *c, const CFF1StringIndex &strings, unsigned int offSize_, const Remap &sidmap)
{
TRACE_SERIALIZE (this);
if (unlikely ((strings.count == 0) || (sidmap.get_count () == 0)))
{
if (!unlikely (c->extend_min (*this)))
return_trace (false);
count.set (0);
return_trace (true);
}
hb_vector_t<ByteStr> bytesArray;
bytesArray.init ();
if (!bytesArray.resize (sidmap.get_count ()))
return_trace (false);
for (unsigned int i = 0; i < strings.count; i++)
{
hb_codepoint_t j = sidmap[i];
if (j != CFF_UNDEF_CODE)
bytesArray[j] = strings[i];
}
bool result = CFF1Index::serialize (c, offSize_, bytesArray);
bytesArray.fini ();
return_trace (result);
}
/* in parallel to above */
inline unsigned int calculate_serialized_size (unsigned int &offSize /*OUT*/, const Remap &sidmap) const
{
offSize = 0;
if ((count == 0) || (sidmap.get_count () == 0))
return count.static_size;
unsigned int dataSize = 0;
for (unsigned int i = 0; i < count; i++)
if (sidmap[i] != CFF_UNDEF_CODE)
dataSize += length_at (i);
offSize = calcOffSize(dataSize);
return CFF1Index::calculate_serialized_size (offSize, sidmap.get_count (), dataSize);
}
};
struct CFF1TopDictInterpEnv : NumInterpEnv
{
inline CFF1TopDictInterpEnv (void)
: NumInterpEnv(), prev_offset(0), last_offset(0) {}
unsigned int prev_offset;
unsigned int last_offset;
};
enum NameDictValIndex
{
version,
notice,
copyright,
fullName,
familyName,
weight,
postscript,
fontName,
baseFontName,
registry,
ordering,
NameDictValCount
};
struct NameDictValues
{
inline void init (void)
{
for (unsigned int i = 0; i < NameDictValCount; i++)
values[i] = CFF_UNDEF_SID;
}
inline unsigned int& operator[] (unsigned int i)
{ assert (i < NameDictValCount); return values[i]; }
inline unsigned int operator[] (unsigned int i) const
{ assert (i < NameDictValCount); return values[i]; }
static inline enum NameDictValIndex name_op_to_index (OpCode op)
{
switch (op) {
case OpCode_version:
return NameDictValIndex::version;
case OpCode_Notice:
return NameDictValIndex::notice;
case OpCode_Copyright:
return NameDictValIndex::copyright;
case OpCode_FullName:
return NameDictValIndex::fullName;
case OpCode_FamilyName:
return NameDictValIndex::familyName;
case OpCode_Weight:
return NameDictValIndex::weight;
case OpCode_PostScript:
return NameDictValIndex::postscript;
case OpCode_FontName:
return NameDictValIndex::fontName;
default:
assert (0);
}
}
unsigned int values[NameDictValCount];
};
struct CFF1TopDictVal : OpStr
{
unsigned int last_arg_offset;
};
struct CFF1TopDictValues : TopDictValues<CFF1TopDictVal>
{ {
inline void init (void) inline void init (void)
{ {
TopDictValues::init (); TopDictValues::init ();
ros[0] = ros[1] = ros[2] = 0; nameSIDs.init ();
ros_supplement = 0;
cidCount = 8720; cidCount = 8720;
EncodingOffset = 0; EncodingOffset = 0;
CharsetOffset = 0; CharsetOffset = 0;
@ -549,73 +668,26 @@ struct CFF1TopDictValues : TopDictValues
} }
inline bool is_CID (void) const inline bool is_CID (void) const
{ return ros[0] != 0; } { return nameSIDs[NameDictValIndex::registry] != CFF_UNDEF_SID; }
inline unsigned int calculate_serialized_size (void) const NameDictValues nameSIDs;
{ unsigned int ros_supplement_offset;
unsigned int size = 0; unsigned int ros_supplement;
for (unsigned int i = 0; i < getNumValues (); i++) unsigned int cidCount;
{
OpCode op = getValue (i).op;
switch (op)
{
case OpCode_FDSelect:
size += OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op);
break;
default:
size += TopDictValues::calculate_serialized_op_size (getValue (i));
break;
}
}
return size;
}
unsigned int ros[3]; /* registry, ordering, supplement */ unsigned int EncodingOffset;
unsigned int cidCount; unsigned int CharsetOffset;
unsigned int FDSelectOffset;
unsigned int EncodingOffset; TableInfo privateDictInfo;
unsigned int CharsetOffset;
unsigned int FDSelectOffset;
TableInfo privateDictInfo;
}; };
/* a copy of a parsed out CFF1TopDictValues augmented with additional operators */ struct CFF1TopDictOpSet : TopDictOpSet<CFF1TopDictVal>
struct CFF1TopDictValuesMod : CFF1TopDictValues
{ {
inline void init (const CFF1TopDictValues *base_= &Null(CFF1TopDictValues)) static inline bool process_op (OpCode op, CFF1TopDictInterpEnv& env, CFF1TopDictValues& dictval)
{ {
SUPER::init (); CFF1TopDictVal val;
base = base_; val.last_arg_offset = (env.last_offset-1) - dictval.opStart; /* offset to the last argument */
}
inline void fini (void)
{
SUPER::fini ();
}
inline unsigned getNumValues (void) const
{
return base->getNumValues () + SUPER::getNumValues ();
}
inline const OpStr &getValue (unsigned int i) const
{
if (i < base->getNumValues ())
return (*base)[i];
else
return SUPER::values[i - base->getNumValues ()];
}
inline const OpStr &operator [] (unsigned int i) const { return getValue (i); }
protected:
typedef CFF1TopDictValues SUPER;
const CFF1TopDictValues *base;
};
struct CFF1TopDictOpSet : TopDictOpSet
{
static inline bool process_op (OpCode op, NumInterpEnv& env, CFF1TopDictValues& dictval)
{
switch (op) { switch (op) {
case OpCode_version: case OpCode_version:
case OpCode_Notice: case OpCode_Notice:
@ -623,6 +695,12 @@ struct CFF1TopDictOpSet : TopDictOpSet
case OpCode_FullName: case OpCode_FullName:
case OpCode_FamilyName: case OpCode_FamilyName:
case OpCode_Weight: case OpCode_Weight:
case OpCode_PostScript:
case OpCode_BaseFontName:
if (unlikely (!env.argStack.check_pop_uint (dictval.nameSIDs[NameDictValues::name_op_to_index (op)])))
return false;
env.clear_args ();
break;
case OpCode_isFixedPitch: case OpCode_isFixedPitch:
case OpCode_ItalicAngle: case OpCode_ItalicAngle:
case OpCode_UnderlinePosition: case OpCode_UnderlinePosition:
@ -632,8 +710,6 @@ struct CFF1TopDictOpSet : TopDictOpSet
case OpCode_UniqueID: case OpCode_UniqueID:
case OpCode_StrokeWidth: case OpCode_StrokeWidth:
case OpCode_SyntheticBase: case OpCode_SyntheticBase:
case OpCode_PostScript:
case OpCode_BaseFontName:
case OpCode_CIDFontVersion: case OpCode_CIDFontVersion:
case OpCode_CIDFontRevision: case OpCode_CIDFontRevision:
case OpCode_CIDFontType: case OpCode_CIDFontType:
@ -651,9 +727,9 @@ struct CFF1TopDictOpSet : TopDictOpSet
break; break;
case OpCode_ROS: case OpCode_ROS:
if (unlikely (!env.argStack.check_pop_uint (dictval.ros[2]) || if (unlikely (!env.argStack.check_pop_uint (dictval.ros_supplement) ||
!env.argStack.check_pop_uint (dictval.ros[1]) || !env.argStack.check_pop_uint (dictval.nameSIDs[NameDictValIndex::ordering]) ||
!env.argStack.check_pop_uint (dictval.ros[0]))) !env.argStack.check_pop_uint (dictval.nameSIDs[NameDictValIndex::registry])))
return false; return false;
env.clear_args (); env.clear_args ();
break; break;
@ -685,6 +761,7 @@ struct CFF1TopDictOpSet : TopDictOpSet
break; break;
default: default:
env.last_offset = env.substr.offset;
if (unlikely (!TopDictOpSet::process_op (op, env, dictval))) if (unlikely (!TopDictOpSet::process_op (op, env, dictval)))
return false; return false;
/* Record this operand below if stack is empty, otherwise done */ /* Record this operand below if stack is empty, otherwise done */
@ -692,7 +769,7 @@ struct CFF1TopDictOpSet : TopDictOpSet
break; break;
} }
dictval.addOp (op, env.substr); dictval.addOp (op, env.substr, val);
return true; return true;
} }
}; };
@ -703,6 +780,7 @@ struct CFF1FontDictValues : DictValues<OpStr>
{ {
DictValues<OpStr>::init (); DictValues<OpStr>::init ();
privateDictInfo.init (); privateDictInfo.init ();
fontName = CFF_UNDEF_SID;
} }
inline void fini (void) inline void fini (void)
@ -710,7 +788,8 @@ struct CFF1FontDictValues : DictValues<OpStr>
DictValues<OpStr>::fini (); DictValues<OpStr>::fini ();
} }
TableInfo privateDictInfo; TableInfo privateDictInfo;
unsigned int fontName;
}; };
struct CFF1FontDictOpSet : DictOpSet struct CFF1FontDictOpSet : DictOpSet
@ -719,6 +798,10 @@ struct CFF1FontDictOpSet : DictOpSet
{ {
switch (op) { switch (op) {
case OpCode_FontName: case OpCode_FontName:
if (unlikely (!env.argStack.check_pop_uint (dictval.fontName)))
return false;
env.clear_args ();
break;
case OpCode_FontMatrix: case OpCode_FontMatrix:
case OpCode_PaintType: case OpCode_PaintType:
env.clear_args (); env.clear_args ();
@ -869,13 +952,12 @@ struct CFF1PrivateDictOpSet_Subset : DictOpSet
} }
}; };
typedef DictInterpreter<CFF1TopDictOpSet, CFF1TopDictValues> CFF1TopDict_Interpreter; typedef DictInterpreter<CFF1TopDictOpSet, CFF1TopDictValues, CFF1TopDictInterpEnv> CFF1TopDict_Interpreter;
typedef DictInterpreter<CFF1FontDictOpSet, CFF1FontDictValues> CFF1FontDict_Interpreter; typedef DictInterpreter<CFF1FontDictOpSet, CFF1FontDictValues> CFF1FontDict_Interpreter;
typedef DictInterpreter<CFF1PrivateDictOpSet, CFF1PrivateDictValues> CFF1PrivateDict_Interpreter; typedef DictInterpreter<CFF1PrivateDictOpSet, CFF1PrivateDictValues> CFF1PrivateDict_Interpreter;
typedef CFF1Index CFF1NameIndex; typedef CFF1Index CFF1NameIndex;
typedef CFF1IndexOf<TopDict> CFF1TopDictIndex; typedef CFF1IndexOf<TopDict> CFF1TopDictIndex;
typedef CFF1Index CFF1StringIndex;
}; /* namespace CFF */ }; /* namespace CFF */
@ -899,9 +981,7 @@ struct cff1
{ {
inline void init (hb_face_t *face) inline void init (hb_face_t *face)
{ {
topDicts.init (); topDict.init ();
topDicts.resize (1);
topDicts[0].init ();
fontDicts.init (); fontDicts.init ();
privateDicts.init (); privateDicts.init ();
@ -929,19 +1009,19 @@ struct cff1
if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; } if (unlikely (!topDictStr.sanitize (&sc))) { fini (); return; }
CFF1TopDict_Interpreter top_interp; CFF1TopDict_Interpreter top_interp;
top_interp.env.init (topDictStr); top_interp.env.init (topDictStr);
if (unlikely (!top_interp.interpret (topDicts[0]))) { fini (); return; } if (unlikely (!top_interp.interpret (topDict))) { fini (); return; }
} }
encoding = &Null(Encoding); encoding = &Null(Encoding);
charset = &StructAtOffsetOrNull<Charset> (cff, topDicts[0].CharsetOffset); charset = &StructAtOffsetOrNull<Charset> (cff, topDict.CharsetOffset);
if (unlikely (is_CID () && (charset == &Null(Charset)))) if (unlikely (is_CID () && (charset == &Null(Charset))))
{ fini (); return; } { fini (); return; }
fdCount = 1; fdCount = 1;
if (is_CID ()) if (is_CID ())
{ {
fdArray = &StructAtOffsetOrNull<CFF1FDArray> (cff, topDicts[0].FDArrayOffset); fdArray = &StructAtOffsetOrNull<CFF1FDArray> (cff, topDict.FDArrayOffset);
fdSelect = &StructAtOffsetOrNull<CFF1FDSelect> (cff, topDicts[0].FDSelectOffset); fdSelect = &StructAtOffsetOrNull<CFF1FDSelect> (cff, topDict.FDSelectOffset);
if (unlikely ((fdArray == &Null(CFF1FDArray)) || !fdArray->sanitize (&sc) || if (unlikely ((fdArray == &Null(CFF1FDArray)) || !fdArray->sanitize (&sc) ||
(fdSelect == &Null(CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count))) (fdSelect == &Null(CFF1FDSelect)) || !fdSelect->sanitize (&sc, fdArray->count)))
{ fini (); return; } { fini (); return; }
@ -954,7 +1034,7 @@ struct cff1
fdSelect = &Null(CFF1FDSelect); fdSelect = &Null(CFF1FDSelect);
if (!is_predef_encoding ()) if (!is_predef_encoding ())
{ {
encoding = &StructAtOffsetOrNull<Encoding> (cff, topDicts[0].EncodingOffset); encoding = &StructAtOffsetOrNull<Encoding> (cff, topDict.EncodingOffset);
if ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc)) if ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))
{ fini (); return; } { fini (); return; }
} }
@ -968,7 +1048,7 @@ struct cff1
if ((globalSubrs != &Null (CFF1Subrs)) && !stringIndex->sanitize (&sc)) if ((globalSubrs != &Null (CFF1Subrs)) && !stringIndex->sanitize (&sc))
{ fini (); return; } { fini (); return; }
charStrings = &StructAtOffsetOrNull<CFF1CharStrings> (cff, topDicts[0].charStringsOffset); charStrings = &StructAtOffsetOrNull<CFF1CharStrings> (cff, topDict.charStringsOffset);
if ((charStrings == &Null(CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc))) if ((charStrings == &Null(CFF1CharStrings)) || unlikely (!charStrings->sanitize (&sc)))
{ fini (); return; } { fini (); return; }
@ -1008,7 +1088,7 @@ struct cff1
} }
else /* non-CID */ else /* non-CID */
{ {
CFF1TopDictValues *font = &topDicts[0]; CFF1TopDictValues *font = &topDict;
PRIVDICTVAL *priv = &privateDicts[0]; PRIVDICTVAL *priv = &privateDicts[0];
const ByteStr privDictStr (StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size); const ByteStr privDictStr (StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size);
@ -1027,8 +1107,7 @@ struct cff1
inline void fini (void) inline void fini (void)
{ {
sc.end_processing (); sc.end_processing ();
topDicts[0].fini (); topDict.fini ();
topDicts.fini ();
fontDicts.fini (); fontDicts.fini ();
privateDicts.fini (); privateDicts.fini ();
hb_blob_destroy (blob); hb_blob_destroy (blob);
@ -1036,10 +1115,10 @@ struct cff1
} }
inline bool is_valid (void) const { return blob != nullptr; } inline bool is_valid (void) const { return blob != nullptr; }
inline bool is_CID (void) const { return topDicts[0].is_CID (); } inline bool is_CID (void) const { return topDict.is_CID (); }
inline bool is_predef_encoding (void) const { return topDicts[0].EncodingOffset <= ExpertEncoding; } inline bool is_predef_encoding (void) const { return topDict.EncodingOffset <= ExpertEncoding; }
inline bool is_predef_charset (void) const { return topDicts[0].CharsetOffset <= ExpertSubsetCharset; } inline bool is_predef_charset (void) const { return topDict.CharsetOffset <= ExpertSubsetCharset; }
inline hb_codepoint_t glyph_to_code (hb_codepoint_t glyph) const inline hb_codepoint_t glyph_to_code (hb_codepoint_t glyph) const
{ {
@ -1050,7 +1129,7 @@ struct cff1
hb_codepoint_t sid = glyph_to_sid (glyph); hb_codepoint_t sid = glyph_to_sid (glyph);
if (sid == 0) return 0; if (sid == 0) return 0;
hb_codepoint_t code = 0; hb_codepoint_t code = 0;
switch (topDicts[0].EncodingOffset) switch (topDict.EncodingOffset)
{ {
case StandardEncoding: case StandardEncoding:
code = lookup_standard_encoding (sid); code = lookup_standard_encoding (sid);
@ -1072,7 +1151,7 @@ struct cff1
else else
{ {
hb_codepoint_t sid = 0; hb_codepoint_t sid = 0;
switch (topDicts[0].CharsetOffset) switch (topDict.CharsetOffset)
{ {
case ISOAdobeCharset: case ISOAdobeCharset:
if (glyph <= 228 /*zcaron*/) sid = glyph; if (glyph <= 228 /*zcaron*/) sid = glyph;
@ -1116,7 +1195,7 @@ struct cff1
const CFF1FDSelect *fdSelect; const CFF1FDSelect *fdSelect;
unsigned int fdCount; unsigned int fdCount;
hb_vector_t<CFF1TopDictValues> topDicts; CFF1TopDictValues topDict;
hb_vector_t<CFF1FontDictValues> fontDicts; hb_vector_t<CFF1FontDictValues> fontDicts;
hb_vector_t<PRIVDICTVAL> privateDicts; hb_vector_t<PRIVDICTVAL> privateDicts;

View File

@ -135,18 +135,18 @@ struct CFF2VariationStore
DEFINE_SIZE_MIN (2 + VariationStore::min_size); DEFINE_SIZE_MIN (2 + VariationStore::min_size);
}; };
struct CFF2TopDictValues : TopDictValues struct CFF2TopDictValues : TopDictValues<>
{ {
inline void init (void) inline void init (void)
{ {
TopDictValues::init (); TopDictValues<>::init ();
vstoreOffset = 0; vstoreOffset = 0;
FDSelectOffset = 0; FDSelectOffset = 0;
} }
inline void fini (void) inline void fini (void)
{ {
TopDictValues::fini (); TopDictValues<>::fini ();
} }
inline unsigned int calculate_serialized_size (void) const inline unsigned int calculate_serialized_size (void) const
@ -162,7 +162,7 @@ struct CFF2TopDictValues : TopDictValues
size += OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op); size += OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op);
break; break;
default: default:
size += TopDictValues::calculate_serialized_op_size (getValue (i)); size += TopDictValues<>::calculate_serialized_op_size (getValue (i));
break; break;
} }
} }
@ -173,7 +173,7 @@ struct CFF2TopDictValues : TopDictValues
unsigned int FDSelectOffset; unsigned int FDSelectOffset;
}; };
struct CFF2TopDictOpSet : TopDictOpSet struct CFF2TopDictOpSet : TopDictOpSet<>
{ {
static inline bool process_op (OpCode op, NumInterpEnv& env, CFF2TopDictValues& dictval) static inline bool process_op (OpCode op, NumInterpEnv& env, CFF2TopDictValues& dictval)
{ {
@ -209,7 +209,7 @@ struct CFF2TopDictOpSet : TopDictOpSet
return true; return true;
} }
typedef TopDictOpSet SUPER; typedef TopDictOpSet<> SUPER;
}; };
struct CFF2FontDictValues : DictValues<OpStr> struct CFF2FontDictValues : DictValues<OpStr>

View File

@ -46,7 +46,7 @@ hb_plan_subset_cff_fdselect (const hb_vector_t<hb_codepoint_t> &glyphs,
unsigned int &subst_fdselect_size /* OUT */, unsigned int &subst_fdselect_size /* OUT */,
unsigned int &subst_fdselect_format /* OUT */, unsigned int &subst_fdselect_format /* OUT */,
hb_vector_t<hb_codepoint_t> &subst_first_glyphs /* OUT */, hb_vector_t<hb_codepoint_t> &subst_first_glyphs /* OUT */,
FDMap &fdmap /* OUT */) Remap &fdmap /* OUT */)
{ {
subset_fd_count = 0; subset_fd_count = 0;
subst_fdselect_size = 0; subst_fdselect_size = 0;
@ -62,7 +62,7 @@ hb_plan_subset_cff_fdselect (const hb_vector_t<hb_codepoint_t> &glyphs,
hb_set_t *set = hb_set_create (); hb_set_t *set = hb_set_create ();
if (set == &Null (hb_set_t)) if (set == &Null (hb_set_t))
return false; return false;
hb_codepoint_t prev_fd = HB_SET_VALUE_INVALID; hb_codepoint_t prev_fd = CFF_UNDEF_CODE;
for (hb_codepoint_t i = 0; i < subset_num_glyphs; i++) for (hb_codepoint_t i = 0; i < subset_num_glyphs; i++)
{ {
hb_codepoint_t fd = src.get_fd (glyphs[i]); hb_codepoint_t fd = src.get_fd (glyphs[i]);
@ -85,14 +85,16 @@ hb_plan_subset_cff_fdselect (const hb_vector_t<hb_codepoint_t> &glyphs,
} }
/* create a fdmap */ /* create a fdmap */
fdmap.resize (fdCount); if (!fdmap.reset (fdCount))
for (unsigned int i = 0; i < fdmap.len; i++) {
fdmap[i] = HB_SET_VALUE_INVALID; hb_set_destroy (set);
hb_codepoint_t fd = HB_SET_VALUE_INVALID; return false;
unsigned int fdindex = 0; }
hb_codepoint_t fd = CFF_UNDEF_CODE;
while (set->next (&fd)) while (set->next (&fd))
fdmap[fd] = fdindex++; fdmap.add (fd);
assert (fdindex == subset_fd_count); assert (fdmap.get_count () == subset_fd_count);
hb_set_destroy (set); hb_set_destroy (set);
} }
@ -131,7 +133,7 @@ serialize_fdselect_3_4 (hb_serialize_context_t *c,
const FDSelect &src, const FDSelect &src,
unsigned int size, unsigned int size,
const hb_vector_t<hb_codepoint_t> &first_glyphs, const hb_vector_t<hb_codepoint_t> &first_glyphs,
const FDMap &fdmap) const Remap &fdmap)
{ {
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
FDSELECT3_4 *p = c->allocate_size<FDSELECT3_4> (size); FDSELECT3_4 *p = c->allocate_size<FDSELECT3_4> (size);
@ -159,7 +161,7 @@ hb_serialize_cff_fdselect (hb_serialize_context_t *c,
unsigned int fdselect_format, unsigned int fdselect_format,
unsigned int size, unsigned int size,
const hb_vector_t<hb_codepoint_t> &first_glyphs, const hb_vector_t<hb_codepoint_t> &first_glyphs,
const FDMap &fdmap) const Remap &fdmap)
{ {
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
FDSelect *p = c->allocate_min<FDSelect> (); FDSelect *p = c->allocate_min<FDSelect> ();

View File

@ -129,10 +129,11 @@ struct CFFSubTableOffsets {
hb_vector_t<TableInfo> localSubrsInfos; hb_vector_t<TableInfo> localSubrsInfos;
}; };
template <typename OPSTR=OpStr>
struct CFFTopDict_OpSerializer : OpSerializer struct CFFTopDict_OpSerializer : OpSerializer
{ {
inline bool serialize (hb_serialize_context_t *c, inline bool serialize (hb_serialize_context_t *c,
const OpStr &opstr, const OPSTR &opstr,
const CFFSubTableOffsets &offsets) const const CFFSubTableOffsets &offsets) const
{ {
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
@ -154,7 +155,7 @@ struct CFFTopDict_OpSerializer : OpSerializer
return_trace (true); return_trace (true);
} }
inline unsigned int calculate_serialized_size (const OpStr &opstr) const inline unsigned int calculate_serialized_size (const OPSTR &opstr) const
{ {
switch (opstr.op) switch (opstr.op)
{ {
@ -162,7 +163,7 @@ struct CFFTopDict_OpSerializer : OpSerializer
case OpCode_FDArray: case OpCode_FDArray:
case OpCode_FDSelect: case OpCode_FDSelect:
return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op); return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op);
default: default:
return opstr.str.len; return opstr.str.len;
} }
@ -179,12 +180,9 @@ struct CFFFontDict_OpSerializer : OpSerializer
if (opstr.op == OpCode_Private) if (opstr.op == OpCode_Private)
{ {
/* serialize the private dict size as a 2-byte integer */ /* serialize the private dict size & offset as 2-byte & 4-byte integers */
if (unlikely (!UnsizedByteStr::serialize_int2 (c, privateDictInfo.size))) if (unlikely (!UnsizedByteStr::serialize_int2 (c, privateDictInfo.size) ||
return_trace (false); !UnsizedByteStr::serialize_int4 (c, privateDictInfo.offset)))
/* serialize the private dict offset as a 4-byte integer */
if (unlikely (!UnsizedByteStr::serialize_int4 (c, privateDictInfo.offset)))
return_trace (false); return_trace (false);
/* serialize the opcode */ /* serialize the opcode */
@ -386,7 +384,7 @@ hb_plan_subset_cff_fdselect (const hb_vector_t<hb_codepoint_t> &glyphs,
unsigned int &subst_fdselect_size /* OUT */, unsigned int &subst_fdselect_size /* OUT */,
unsigned int &subst_fdselect_format /* OUT */, unsigned int &subst_fdselect_format /* OUT */,
hb_vector_t<hb_codepoint_t> &subst_first_glyphs /* OUT */, hb_vector_t<hb_codepoint_t> &subst_first_glyphs /* OUT */,
CFF::FDMap &fdmap /* OUT */); CFF::Remap &fdmap /* OUT */);
HB_INTERNAL bool HB_INTERNAL bool
hb_serialize_cff_fdselect (hb_serialize_context_t *c, hb_serialize_cff_fdselect (hb_serialize_context_t *c,
@ -396,6 +394,6 @@ hb_serialize_cff_fdselect (hb_serialize_context_t *c,
unsigned int fdselect_format, unsigned int fdselect_format,
unsigned int size, unsigned int size,
const hb_vector_t<hb_codepoint_t> &first_glyphs, const hb_vector_t<hb_codepoint_t> &first_glyphs,
const CFF::FDMap &fdmap); const CFF::Remap &fdmap);
#endif /* HB_SUBSET_CFF_COMMON_HH */ #endif /* HB_SUBSET_CFF_COMMON_HH */

View File

@ -34,46 +34,122 @@
using namespace CFF; using namespace CFF;
struct RemapSID : Remap
{
inline unsigned int add (unsigned int sid)
{
if ((sid != CFF_UNDEF_SID) && !is_std_std (sid))
return offset_sid (Remap::add (unoffset_sid (sid)));
else
return sid;
}
inline unsigned int operator[] (unsigned int sid) const
{
if (is_std_std (sid))
return sid;
else
return offset_sid (Remap::operator [] (unoffset_sid (sid)));
}
static const unsigned int num_std_strings = 391;
static inline bool is_std_std (unsigned int sid) { return sid < num_std_strings; }
static inline unsigned int offset_sid (unsigned int sid) { return sid + num_std_strings; }
static inline unsigned int unoffset_sid (unsigned int sid) { return sid - num_std_strings; }
};
struct CFF1SubTableOffsets : CFFSubTableOffsets struct CFF1SubTableOffsets : CFFSubTableOffsets
{ {
inline CFF1SubTableOffsets (void) inline CFF1SubTableOffsets (void)
: CFFSubTableOffsets (), : CFFSubTableOffsets (),
nameIndexOffset (0), nameIndexOffset (0),
stringIndexOffset (0), encodingOffset (0)
encodingOffset (0),
charsetOffset (0)
{ {
stringIndexInfo.init ();
charsetInfo.init ();
privateDictInfo.init (); privateDictInfo.init ();
} }
unsigned int nameIndexOffset; unsigned int nameIndexOffset;
unsigned int stringIndexOffset; TableInfo stringIndexInfo;
unsigned int encodingOffset; unsigned int encodingOffset;
unsigned int charsetOffset; TableInfo charsetInfo;
TableInfo privateDictInfo; TableInfo privateDictInfo;
}; };
struct CFF1TopDict_OpSerializer : CFFTopDict_OpSerializer /* a copy of a parsed out CFF1TopDictValues augmented with additional operators */
struct CFF1TopDictValuesMod : CFF1TopDictValues
{
inline void init (const CFF1TopDictValues *base_= &Null(CFF1TopDictValues))
{
SUPER::init ();
base = base_;
}
inline void fini (void)
{
SUPER::fini ();
}
inline unsigned getNumValues (void) const
{
return base->getNumValues () + SUPER::getNumValues ();
}
inline const CFF1TopDictVal &getValue (unsigned int i) const
{
if (i < base->getNumValues ())
return (*base)[i];
else
return SUPER::values[i - base->getNumValues ()];
}
inline const CFF1TopDictVal &operator [] (unsigned int i) const { return getValue (i); }
inline void reassignSIDs (const RemapSID& sidmap)
{
for (unsigned int i = 0; i < NameDictValCount; i++)
nameSIDs[i] = sidmap[base->nameSIDs[i]];
}
protected:
typedef CFF1TopDictValues SUPER;
const CFF1TopDictValues *base;
};
struct TopDictModifiers
{
inline TopDictModifiers (const CFF1SubTableOffsets &offsets_,
const unsigned int (&nameSIDs_)[NameDictValCount])
: offsets (offsets_),
nameSIDs (nameSIDs_)
{}
const CFF1SubTableOffsets &offsets;
const unsigned int (&nameSIDs)[NameDictValCount];
};
struct CFF1TopDict_OpSerializer : CFFTopDict_OpSerializer<CFF1TopDictVal>
{ {
inline bool serialize (hb_serialize_context_t *c, inline bool serialize (hb_serialize_context_t *c,
const OpStr &opstr, const CFF1TopDictVal &opstr,
const CFF1SubTableOffsets &offsets) const const TopDictModifiers &mod) const
{ {
TRACE_SERIALIZE (this); TRACE_SERIALIZE (this);
switch (opstr.op) OpCode op = opstr.op;
switch (op)
{ {
case OpCode_charset: case OpCode_charset:
return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.charsetOffset)); return_trace (FontDict::serialize_offset4_op(c, op, mod.offsets.charsetInfo.offset));
case OpCode_Encoding: case OpCode_Encoding:
return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.encodingOffset)); return_trace (FontDict::serialize_offset4_op(c, op, mod.offsets.encodingOffset));
case OpCode_Private: case OpCode_Private:
{ {
if (unlikely (!UnsizedByteStr::serialize_int2 (c, offsets.privateDictInfo.size))) if (unlikely (!UnsizedByteStr::serialize_int2 (c, mod.offsets.privateDictInfo.size)))
return_trace (false); return_trace (false);
if (unlikely (!UnsizedByteStr::serialize_int4 (c, offsets.privateDictInfo.offset))) if (unlikely (!UnsizedByteStr::serialize_int4 (c, mod.offsets.privateDictInfo.offset)))
return_trace (false); return_trace (false);
HBUINT8 *p = c->allocate_size<HBUINT8> (1); HBUINT8 *p = c->allocate_size<HBUINT8> (1);
if (unlikely (p == nullptr)) return_trace (false); if (unlikely (p == nullptr)) return_trace (false);
@ -81,29 +157,117 @@ struct CFF1TopDict_OpSerializer : CFFTopDict_OpSerializer
} }
break; break;
case OpCode_version:
case OpCode_Notice:
case OpCode_Copyright:
case OpCode_FullName:
case OpCode_FamilyName:
case OpCode_Weight:
case OpCode_PostScript:
case OpCode_BaseFontName:
case OpCode_FontName:
return_trace (FontDict::serialize_offset2_op(c, op, mod.nameSIDs[NameDictValues::name_op_to_index (op)]));
case OpCode_ROS:
{
/* for registry & ordering, reassigned SIDs are serialized
* for supplement, the original byte string is copied along with the op code */
OpStr supp_op;
supp_op.op = op;
supp_op.str.str = opstr.str.str + opstr.last_arg_offset;
assert (opstr.str.len >= opstr.last_arg_offset + 3);
supp_op.str.len = opstr.str.len - opstr.last_arg_offset;
return_trace (UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[NameDictValIndex::registry]) &&
UnsizedByteStr::serialize_int2 (c, mod.nameSIDs[NameDictValIndex::ordering]) &&
copy_opstr (c, supp_op));
}
default: default:
return_trace (CFFTopDict_OpSerializer::serialize (c, opstr, offsets)); return_trace (CFFTopDict_OpSerializer<CFF1TopDictVal>::serialize (c, opstr, mod.offsets));
} }
return_trace (true); return_trace (true);
} }
inline unsigned int calculate_serialized_size (const OpStr &opstr) const inline unsigned int calculate_serialized_size (const CFF1TopDictVal &opstr) const
{ {
switch (opstr.op) OpCode op = opstr.op;
switch (op)
{ {
case OpCode_charset: case OpCode_charset:
case OpCode_Encoding: case OpCode_Encoding:
return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op); return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (op);
case OpCode_Private: case OpCode_Private:
return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private); return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private);
case OpCode_version:
case OpCode_Notice:
case OpCode_Copyright:
case OpCode_FullName:
case OpCode_FamilyName:
case OpCode_Weight:
case OpCode_PostScript:
case OpCode_BaseFontName:
case OpCode_FontName:
return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (op);
case OpCode_ROS:
return ((OpCode_Size (OpCode_shortint) + 2) * 2) + (opstr.str.len - opstr.last_arg_offset)/* supplement + op */;
default: default:
return CFFTopDict_OpSerializer::calculate_serialized_size (opstr); return CFFTopDict_OpSerializer<CFF1TopDictVal>::calculate_serialized_size (opstr);
} }
} }
}; };
struct FontDictValuesMod
{
inline void init (const CFF1FontDictValues *base_,
unsigned int fontName_,
const TableInfo &privateDictInfo_)
{
base = base_;
fontName = fontName_;
privateDictInfo = privateDictInfo_;
}
inline unsigned getNumValues (void) const
{
return base->getNumValues ();
}
inline const OpStr &operator [] (unsigned int i) const { return (*base)[i]; }
const CFF1FontDictValues *base;
TableInfo privateDictInfo;
unsigned int fontName;
};
struct CFF1FontDict_OpSerializer : CFFFontDict_OpSerializer
{
inline bool serialize (hb_serialize_context_t *c,
const OpStr &opstr,
const FontDictValuesMod &mod) const
{
TRACE_SERIALIZE (this);
if (opstr.op == OpCode_FontName)
return_trace (FontDict::serialize_uint2_op (c, opstr.op, mod.fontName));
else
return_trace (SUPER::serialize (c, opstr, mod.privateDictInfo));
}
inline unsigned int calculate_serialized_size (const OpStr &opstr) const
{
if (opstr.op == OpCode_FontName)
return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_FontName);
else
return SUPER::calculate_serialized_size (opstr);
}
private:
typedef CFFFontDict_OpSerializer SUPER;
};
struct CFF1CSOpSet_Flatten : CFF1CSOpSet<CFF1CSOpSet_Flatten, FlattenParam> struct CFF1CSOpSet_Flatten : CFF1CSOpSet<CFF1CSOpSet_Flatten, FlattenParam>
{ {
static inline void flush_args_and_op (OpCode op, CFF1CSInterpEnv &env, FlattenParam& param) static inline void flush_args_and_op (OpCode op, CFF1CSInterpEnv &env, FlattenParam& param)
@ -199,11 +363,14 @@ struct cff_subset_plan {
fdmap.init (); fdmap.init ();
subset_charstrings.init (); subset_charstrings.init ();
flat_charstrings.init (); flat_charstrings.init ();
privateDictInfos.init (); fontdicts_mod.init ();
subrRefMaps.init (); subrRefMaps.init ();
subset_enc_code_ranges.init (); subset_enc_code_ranges.init ();
subset_enc_supp_codes.init (); subset_enc_supp_codes.init ();
subset_charset_ranges.init (); subset_charset_ranges.init ();
sidmap.init ();
for (unsigned int i = 0; i < NameDictValCount; i++)
topDictModSIDs[i] = CFF_UNDEF_SID;
} }
inline ~cff_subset_plan (void) inline ~cff_subset_plan (void)
@ -214,11 +381,13 @@ struct cff_subset_plan {
fdmap.fini (); fdmap.fini ();
subset_charstrings.fini (); subset_charstrings.fini ();
flat_charstrings.fini (); flat_charstrings.fini ();
privateDictInfos.fini (); fontdicts_mod.fini ();
subrRefMaps.fini (); subrRefMaps.fini ();
subset_enc_code_ranges.fini (); subset_enc_code_ranges.fini ();
subset_enc_supp_codes.init (); subset_enc_supp_codes.init ();
subset_charset_ranges.fini (); subset_charset_ranges.fini ();
sidmap.fini ();
fontdicts_mod.fini ();
} }
inline unsigned int plan_subset_encoding (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan) inline unsigned int plan_subset_encoding (const OT::cff1::accelerator_subset_t &acc, hb_subset_plan_t *plan)
@ -303,6 +472,9 @@ struct cff_subset_plan {
hb_codepoint_t orig_glyph = plan->glyphs[glyph]; hb_codepoint_t orig_glyph = plan->glyphs[glyph];
sid = acc.glyph_to_sid (orig_glyph); sid = acc.glyph_to_sid (orig_glyph);
if (!acc.is_CID ())
sid = sidmap.add (sid);
if (sid != last_sid + 1) if (sid != last_sid + 1)
{ {
if (subset_charset_ranges.len > 0) if (subset_charset_ranges.len > 0)
@ -342,6 +514,29 @@ struct cff_subset_plan {
subset_charset_format? subset_charset_ranges.len: plan->glyphs.len); subset_charset_format? subset_charset_ranges.len: plan->glyphs.len);
} }
inline bool collect_sids_in_dicts (const OT::cff1::accelerator_subset_t &acc)
{
if (unlikely (!sidmap.reset (acc.stringIndex->count)))
return false;
for (unsigned int i = 0; i < NameDictValCount; i++)
{
unsigned int sid = acc.topDict.nameSIDs[i];
if (sid != CFF_UNDEF_SID)
{
(void)sidmap.add (sid);
topDictModSIDs[i] = sidmap[sid];
}
}
if (acc.fdArray != &Null(CFF1FDArray))
for (unsigned int fd = 0; fd < orig_fdcount; fd++)
if (!fdmap.excludes (fd))
(void)sidmap.add (acc.fontDicts[fd].fontName);
return true;
}
inline bool create (const OT::cff1::accelerator_subset_t &acc, inline bool create (const OT::cff1::accelerator_subset_t &acc,
hb_subset_plan_t *plan) hb_subset_plan_t *plan)
{ {
@ -376,9 +571,9 @@ struct cff_subset_plan {
/* top dict INDEX */ /* top dict INDEX */
{ {
/* Add encoding/charset to a (copy of) top dict as necessary */ /* Add encoding/charset to a (copy of) top dict as necessary */
topdict_mod.init (&acc.topDicts[0]); topdict_mod.init (&acc.topDict);
bool need_to_add_enc = (subset_encoding && !acc.topDicts[0].hasOp (OpCode_Encoding)); bool need_to_add_enc = (subset_encoding && !acc.topDict.hasOp (OpCode_Encoding));
bool need_to_add_set = (subset_charset && !acc.topDicts[0].hasOp (OpCode_charset)); bool need_to_add_set = (subset_charset && !acc.topDict.hasOp (OpCode_charset));
if (need_to_add_enc || need_to_add_set) if (need_to_add_enc || need_to_add_set)
{ {
if (need_to_add_enc) if (need_to_add_enc)
@ -395,9 +590,36 @@ struct cff_subset_plan {
&topdict_mod, 1, topdict_sizes, topSzr); &topdict_mod, 1, topdict_sizes, topSzr);
} }
/* Determine re-mapping of font index as fdmap among other info */
if (acc.fdSelect != &Null(CFF1FDSelect)
&& unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs,
orig_fdcount,
*acc.fdSelect,
subset_fdcount,
offsets.FDSelectInfo.size,
subset_fdselect_format,
subset_fdselect_first_glyphs,
fdmap)))
return false;
/* remove unused SIDs & reassign SIDs */
{
/* SIDs for name strings in dicts are added before glyph names so they fit in 16-bit int range */
if (unlikely (!collect_sids_in_dicts (acc)))
return false;
assert (sidmap.get_count () <= 0x8000);
if (subset_charset)
offsets.charsetInfo.size = plan_subset_charset (acc, plan);
topdict_mod.reassignSIDs (sidmap);
}
/* String INDEX */ /* String INDEX */
offsets.stringIndexOffset = final_size; {
final_size += acc.stringIndex->get_size (); offsets.stringIndexInfo.offset = final_size;
offsets.stringIndexInfo.size = acc.stringIndex->calculate_serialized_size (offsets.stringIndexInfo.offSize, sidmap);
final_size += offsets.stringIndexInfo.size;
}
if (flatten_subrs) if (flatten_subrs)
{ {
@ -433,24 +655,13 @@ struct cff_subset_plan {
final_size += plan_subset_encoding (acc, plan); final_size += plan_subset_encoding (acc, plan);
/* Charset */ /* Charset */
offsets.charsetOffset = final_size; offsets.charsetInfo.offset = final_size;
if (subset_charset) final_size += offsets.charsetInfo.size;
final_size += plan_subset_charset (acc, plan);
/* FDSelect */ /* FDSelect */
if (acc.fdSelect != &Null(CFF1FDSelect)) if (acc.fdSelect != &Null(CFF1FDSelect))
{ {
offsets.FDSelectInfo.offset = final_size; offsets.FDSelectInfo.offset = final_size;
if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs,
orig_fdcount,
*acc.fdSelect,
subset_fdcount,
offsets.FDSelectInfo.size,
subset_fdselect_format,
subset_fdselect_first_glyphs,
fdmap)))
return false;
if (!is_fds_subsetted ()) if (!is_fds_subsetted ())
offsets.FDSelectInfo.size = acc.fdSelect->calculate_serialized_size (acc.num_glyphs); offsets.FDSelectInfo.size = acc.fdSelect->calculate_serialized_size (acc.num_glyphs);
final_size += offsets.FDSelectInfo.size; final_size += offsets.FDSelectInfo.size;
@ -459,8 +670,14 @@ struct cff_subset_plan {
/* FDArray (FDIndex) */ /* FDArray (FDIndex) */
if (acc.fdArray != &Null(CFF1FDArray)) { if (acc.fdArray != &Null(CFF1FDArray)) {
offsets.FDArrayInfo.offset = final_size; offsets.FDArrayInfo.offset = final_size;
CFFFontDict_OpSerializer fontSzr; CFF1FontDict_OpSerializer fontSzr;
final_size += CFF1FDArray::calculate_serialized_size(offsets.FDArrayInfo.offSize/*OUT*/, acc.fontDicts, subset_fdcount, fdmap, fontSzr); unsigned int dictsSize = 0;
for (unsigned int i = 0; i < acc.fontDicts.len; i++)
if (!fdmap.excludes (i))
dictsSize += FontDict::calculate_serialized_size (acc.fontDicts[i], fontSzr);
offsets.FDArrayInfo.offSize = calcOffSize (dictsSize + 1);
final_size += CFF1Index::calculate_serialized_size (offsets.FDArrayInfo.offSize, subset_fdcount, dictsSize);
} }
/* CharStrings */ /* CharStrings */
@ -493,11 +710,12 @@ struct cff_subset_plan {
{ {
if (!fdmap.excludes (i)) if (!fdmap.excludes (i))
{ {
unsigned int priv_size;
CFFPrivateDict_OpSerializer privSzr (plan->drop_hints, flatten_subrs); CFFPrivateDict_OpSerializer privSzr (plan->drop_hints, flatten_subrs);
priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr); unsigned int priv_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr);
TableInfo privInfo = { final_size, priv_size, 0 }; TableInfo privInfo = { final_size, priv_size, 0 };
privateDictInfos.push (privInfo); FontDictValuesMod fontdict_mod;
fontdict_mod.init ( &acc.fontDicts[i], sidmap[acc.fontDicts[i].fontName], privInfo );
fontdicts_mod.push (fontdict_mod);
final_size += privInfo.size; final_size += privInfo.size;
if (!flatten_subrs) if (!flatten_subrs)
final_size += offsets.localSubrsInfos[i].size; final_size += offsets.localSubrsInfos[i].size;
@ -505,10 +723,10 @@ struct cff_subset_plan {
} }
if (!acc.is_CID ()) if (!acc.is_CID ())
offsets.privateDictInfo = privateDictInfos[0]; offsets.privateDictInfo = fontdicts_mod[0].privateDictInfo;
return ((subset_charstrings.len == plan->glyphs.len) && return ((subset_charstrings.len == plan->glyphs.len) &&
(privateDictInfos.len == subset_fdcount)); (fontdicts_mod.len == subset_fdcount));
} }
inline unsigned int get_final_size (void) const { return final_size; } inline unsigned int get_final_size (void) const { return final_size; }
@ -526,12 +744,12 @@ struct cff_subset_plan {
hb_vector_t<hb_codepoint_t> subset_fdselect_first_glyphs; hb_vector_t<hb_codepoint_t> subset_fdselect_first_glyphs;
/* font dict index remap table from fullset FDArray to subset FDArray. /* font dict index remap table from fullset FDArray to subset FDArray.
* set to HB_SET_VALUE_INVALID if excluded from subset */ * set to CFF_UNDEF_CODE if excluded from subset */
FDMap fdmap; Remap fdmap;
hb_vector_t<ByteStr> subset_charstrings; hb_vector_t<ByteStr> subset_charstrings;
ByteStrBuffArray flat_charstrings; ByteStrBuffArray flat_charstrings;
hb_vector_t<TableInfo> privateDictInfos; hb_vector_t<FontDictValuesMod> fontdicts_mod;
SubrRefMaps subrRefMaps; SubrRefMaps subrRefMaps;
@ -548,6 +766,9 @@ struct cff_subset_plan {
uint8_t subset_charset_format; uint8_t subset_charset_format;
hb_vector_t<code_pair> subset_charset_ranges; hb_vector_t<code_pair> subset_charset_ranges;
bool subset_charset; bool subset_charset;
RemapSID sidmap;
unsigned int topDictModSIDs[NameDictValCount];
}; };
static inline bool _write_cff1 (const cff_subset_plan &plan, static inline bool _write_cff1 (const cff_subset_plan &plan,
@ -589,9 +810,10 @@ static inline bool _write_cff1 (const cff_subset_plan &plan,
CFF1IndexOf<TopDict> *dest = c.start_embed< CFF1IndexOf<TopDict> > (); CFF1IndexOf<TopDict> *dest = c.start_embed< CFF1IndexOf<TopDict> > ();
if (dest == nullptr) return false; if (dest == nullptr) return false;
CFF1TopDict_OpSerializer topSzr; CFF1TopDict_OpSerializer topSzr;
TopDictModifiers modifier (plan.offsets, plan.topDictModSIDs);
if (unlikely (!dest->serialize (&c, plan.offsets.topDictInfo.offSize, if (unlikely (!dest->serialize (&c, plan.offsets.topDictInfo.offSize,
&plan.topdict_mod, 1, &plan.topdict_mod, 1,
plan.topdict_sizes, topSzr, plan.offsets))) plan.topdict_sizes, topSzr, modifier)))
{ {
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF top dict"); DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF top dict");
return false; return false;
@ -600,10 +822,10 @@ static inline bool _write_cff1 (const cff_subset_plan &plan,
/* String INDEX */ /* String INDEX */
{ {
assert (plan.offsets.stringIndexOffset == c.head - c.start); assert (plan.offsets.stringIndexInfo.offset == c.head - c.start);
CFF1StringIndex *dest = c.start_embed<CFF1StringIndex> (); CFF1StringIndex *dest = c.start_embed<CFF1StringIndex> ();
if (unlikely (dest == nullptr)) return false; if (unlikely (dest == nullptr)) return false;
if (unlikely (!dest->serialize (&c, *acc.stringIndex))) if (unlikely (!dest->serialize (&c, *acc.stringIndex, plan.offsets.stringIndexInfo.offSize, plan.sidmap)))
{ {
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF string INDEX"); DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF string INDEX");
return false; return false;
@ -643,7 +865,7 @@ static inline bool _write_cff1 (const cff_subset_plan &plan,
/* Charset */ /* Charset */
if (plan.subset_charset) if (plan.subset_charset)
{ {
assert (plan.offsets.charsetOffset == c.head - c.start); assert (plan.offsets.charsetInfo.offset == c.head - c.start);
Charset *dest = c.start_embed<Charset> (); Charset *dest = c.start_embed<Charset> ();
if (unlikely (dest == nullptr)) return false; if (unlikely (dest == nullptr)) return false;
if (unlikely (!dest->serialize (&c, if (unlikely (!dest->serialize (&c,
@ -689,10 +911,10 @@ static inline bool _write_cff1 (const cff_subset_plan &plan,
assert (plan.offsets.FDArrayInfo.offset == c.head - c.start); assert (plan.offsets.FDArrayInfo.offset == c.head - c.start);
CFF1FDArray *fda = c.start_embed<CFF1FDArray> (); CFF1FDArray *fda = c.start_embed<CFF1FDArray> ();
if (unlikely (fda == nullptr)) return false; if (unlikely (fda == nullptr)) return false;
CFFFontDict_OpSerializer fontSzr; CFF1FontDict_OpSerializer fontSzr;
if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize, if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayInfo.offSize,
acc.fontDicts, plan.subset_fdcount, plan.fdmap, plan.fontdicts_mod,
fontSzr, plan.privateDictInfos))) fontSzr)))
{ {
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF FDArray"); DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF FDArray");
return false; return false;
@ -719,7 +941,7 @@ static inline bool _write_cff1 (const cff_subset_plan &plan,
{ {
PrivateDict *pd = c.start_embed<PrivateDict> (); PrivateDict *pd = c.start_embed<PrivateDict> ();
if (unlikely (pd == nullptr)) return false; if (unlikely (pd == nullptr)) return false;
unsigned int priv_size = plan.flatten_subrs? 0: plan.privateDictInfos[plan.fdmap[i]].size; unsigned int priv_size = plan.flatten_subrs? 0: plan.fontdicts_mod[plan.fdmap[i]].privateDictInfo.size;
bool result; bool result;
CFFPrivateDict_OpSerializer privSzr (plan.drop_hints, plan.flatten_subrs); CFFPrivateDict_OpSerializer privSzr (plan.drop_hints, plan.flatten_subrs);
/* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */ /* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */

View File

@ -44,7 +44,7 @@ struct CFF2SubTableOffsets : CFFSubTableOffsets
unsigned int varStoreOffset; unsigned int varStoreOffset;
}; };
struct CFF2TopDict_OpSerializer : CFFTopDict_OpSerializer struct CFF2TopDict_OpSerializer : CFFTopDict_OpSerializer<>
{ {
inline bool serialize (hb_serialize_context_t *c, inline bool serialize (hb_serialize_context_t *c,
const OpStr &opstr, const OpStr &opstr,
@ -58,7 +58,7 @@ struct CFF2TopDict_OpSerializer : CFFTopDict_OpSerializer
return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.varStoreOffset)); return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.varStoreOffset));
default: default:
return_trace (CFFTopDict_OpSerializer::serialize (c, opstr, offsets)); return_trace (CFFTopDict_OpSerializer<>::serialize (c, opstr, offsets));
} }
} }
@ -70,7 +70,7 @@ struct CFF2TopDict_OpSerializer : CFFTopDict_OpSerializer
return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op); return OpCode_Size (OpCode_longintdict) + 4 + OpCode_Size (opstr.op);
default: default:
return CFFTopDict_OpSerializer::calculate_serialized_size (opstr); return CFFTopDict_OpSerializer<>::calculate_serialized_size (opstr);
} }
} }
}; };
@ -355,7 +355,7 @@ struct cff2_subset_plan {
unsigned int subset_fdselect_format; unsigned int subset_fdselect_format;
hb_vector_t<hb_codepoint_t> subset_fdselect_first_glyphs; hb_vector_t<hb_codepoint_t> subset_fdselect_first_glyphs;
FDMap fdmap; Remap fdmap;
hb_vector_t<ByteStr> subset_charstrings; hb_vector_t<ByteStr> subset_charstrings;
ByteStrBuffArray flat_charstrings; ByteStrBuffArray flat_charstrings;