Added CFF support
Added sources hb-ot-cff-table.hh, hb-subset-cff.cc & hh Templatized Index because CFF uses 16-bit count while CFF2 uses 32-bit Misc code cleanup & bug fixes
This commit is contained in:
parent
161ece4c30
commit
64c5412264
|
@ -26,7 +26,8 @@ HB_BASE_sources = \
|
|||
hb-ot-color-cbdt-table.hh \
|
||||
hb-ot-cmap-table.hh \
|
||||
hb-ot-glyf-table.hh \
|
||||
hb-ot-cff2-table.hh \
|
||||
hb-ot-cff-table.hh \
|
||||
hb-ot-cff2-table.hh \
|
||||
hb-ot-hdmx-table.hh \
|
||||
hb-ot-head-table.hh \
|
||||
hb-ot-hhea-table.hh \
|
||||
|
@ -210,7 +211,8 @@ HB_SUBSET_sources = \
|
|||
hb-static.cc \
|
||||
hb-subset.cc \
|
||||
hb-subset-glyf.cc \
|
||||
hb-subset-cff2.cc \
|
||||
hb-subset-cff.cc \
|
||||
hb-subset-cff2.cc \
|
||||
hb-subset-cff-common-private.cc \
|
||||
hb-subset-input.cc \
|
||||
hb-subset-plan.cc \
|
||||
|
@ -219,7 +221,8 @@ HB_SUBSET_sources = \
|
|||
HB_SUBSET_headers = \
|
||||
hb-subset.h \
|
||||
hb-subset-glyf.hh \
|
||||
hb-subset-cff2.hh \
|
||||
hb-subset-cff.hh \
|
||||
hb-subset-cff2.hh \
|
||||
hb-subset-cff-common-private.hh \
|
||||
hb-subset-plan.hh \
|
||||
hb-subset-private.hh \
|
||||
|
|
|
@ -34,6 +34,11 @@ namespace CFF {
|
|||
|
||||
using namespace OT;
|
||||
|
||||
/* utility macro */
|
||||
template<typename Type>
|
||||
static inline const Type& StructAtOffsetOrNull(const void *P, unsigned int offset)
|
||||
{ return offset? (* reinterpret_cast<const Type*> ((const char *) P + offset)): Null(Type); }
|
||||
|
||||
const float UNSET_REAL_VALUE = -1.0f;
|
||||
|
||||
enum OpCode {
|
||||
|
@ -153,12 +158,6 @@ protected:
|
|||
} u;
|
||||
};
|
||||
|
||||
/* pair of table offset and length */
|
||||
struct offset_size_pair {
|
||||
unsigned int offset;
|
||||
unsigned int size;
|
||||
};
|
||||
|
||||
/* byte string */
|
||||
struct UnsizedByteStr : UnsizedArrayOf <HBUINT8>
|
||||
{
|
||||
|
@ -209,6 +208,18 @@ struct ByteStr
|
|||
return (*str)[i];
|
||||
}
|
||||
|
||||
inline bool serialize (hb_serialize_context_t *c, const ByteStr &src)
|
||||
{
|
||||
TRACE_SANITIZE (this);
|
||||
HBUINT8 *dest = c->allocate_size<HBUINT8> (src.len);
|
||||
if (unlikely (dest == nullptr))
|
||||
return_trace (false);
|
||||
memcpy (dest, src.str, src.len);
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
inline unsigned int get_size (void) const { return len; }
|
||||
|
||||
inline bool check_limit (unsigned int offset, unsigned int count) const
|
||||
{ return (offset + count <= len); }
|
||||
|
||||
|
@ -229,6 +240,7 @@ inline unsigned int calcOffSize(unsigned int offset)
|
|||
}
|
||||
|
||||
/* CFF INDEX */
|
||||
template <typename COUNT>
|
||||
struct Index
|
||||
{
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const
|
||||
|
@ -259,35 +271,34 @@ struct Index
|
|||
}
|
||||
|
||||
inline bool serialize (hb_serialize_context_t *c,
|
||||
unsigned int offSize,
|
||||
const hb_vector_t<ByteStr> &bytesArray)
|
||||
unsigned int offSize_,
|
||||
const hb_vector_t<ByteStr> &byteArray)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
||||
/* serialize Index header */
|
||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||
this->count.set (bytesArray.len);
|
||||
this->offSize.set (offSize);
|
||||
if (!unlikely (c->allocate_size<HBUINT8> (offSize * (bytesArray.len + 1))))
|
||||
this->count.set (byteArray.len);
|
||||
this->offSize.set (offSize_);
|
||||
if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (byteArray.len + 1))))
|
||||
return_trace (false);
|
||||
|
||||
/* serialize indices */
|
||||
unsigned int offset = 1;
|
||||
unsigned int i = 0;
|
||||
for (; i < bytesArray.len; i++)
|
||||
for (; i < byteArray.len; i++)
|
||||
{
|
||||
set_offset_at (i, offset);
|
||||
offset += bytesArray[i].len;
|
||||
offset += byteArray[i].get_size ();
|
||||
}
|
||||
set_offset_at (i, offset);
|
||||
|
||||
/* serialize data */
|
||||
for (unsigned int i = 0; i < bytesArray.len; i++)
|
||||
for (unsigned int i = 0; i < byteArray.len; i++)
|
||||
{
|
||||
HBUINT8 *dest = c->allocate_size<HBUINT8> (bytesArray[i].len);
|
||||
if (dest == nullptr)
|
||||
ByteStr *dest = c->start_embed<ByteStr> ();
|
||||
if (unlikely (dest == nullptr ||
|
||||
!dest->serialize (c, byteArray[i])))
|
||||
return_trace (false);
|
||||
memcpy (dest, &bytesArray[i].str[0], bytesArray[i].len);
|
||||
}
|
||||
return_trace (true);
|
||||
}
|
||||
|
@ -319,12 +330,12 @@ struct Index
|
|||
{ return offset_at (index + 1) - offset_at (index); }
|
||||
|
||||
inline const char *data_base (void) const
|
||||
{ return (const char *)this + 5 + offset_array_size (); }
|
||||
{ return (const char *)this + min_size + offset_array_size (); }
|
||||
|
||||
inline unsigned int data_size (void) const
|
||||
{ return HBINT8::static_size; };
|
||||
|
||||
inline ByteStr operator [] (unsigned int index) const
|
||||
ByteStr operator [] (unsigned int index) const
|
||||
{
|
||||
if (likely (index < count))
|
||||
return ByteStr (data_base () + offset_at (index) - 1, offset_at (index + 1) - offset_at (index));
|
||||
|
@ -358,23 +369,203 @@ struct Index
|
|||
}
|
||||
|
||||
public:
|
||||
HBUINT32 count; /* Number of object data. Note there are (count+1) offsets */
|
||||
COUNT count; /* Number of object data. Note there are (count+1) offsets */
|
||||
HBUINT8 offSize; /* The byte size of each offset in the offsets array. */
|
||||
HBUINT8 offsets[VAR]; /* The array of (count + 1) offsets into objects array (1-base). */
|
||||
/* HBUINT8 data[VAR]; Object data */
|
||||
public:
|
||||
DEFINE_SIZE_ARRAY (5, offsets);
|
||||
DEFINE_SIZE_ARRAY (COUNT::static_size + HBUINT8::static_size, offsets);
|
||||
};
|
||||
|
||||
template <typename Type>
|
||||
struct IndexOf : Index
|
||||
template <typename COUNT, typename TYPE>
|
||||
struct IndexOf : Index<COUNT>
|
||||
{
|
||||
inline ByteStr operator [] (unsigned int index) const
|
||||
inline const ByteStr operator [] (unsigned int index) const
|
||||
{
|
||||
if (likely (index < count))
|
||||
return ByteStr (data_base () + offset_at (index) - 1, length_at (index));
|
||||
if (likely (index < Index<COUNT>::count))
|
||||
return ByteStr (Index<COUNT>::data_base () + Index<COUNT>::offset_at (index) - 1, Index<COUNT>::length_at (index));
|
||||
return Null(ByteStr);
|
||||
}
|
||||
|
||||
template <typename DATA, typename PARAM1, typename PARAM2>
|
||||
inline bool serialize (hb_serialize_context_t *c,
|
||||
unsigned int offSize_,
|
||||
const hb_vector_t<DATA> &dataArray,
|
||||
const hb_vector_t<unsigned int> &dataSizeArray,
|
||||
const PARAM1 ¶m1,
|
||||
const PARAM2 ¶m2)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
/* serialize Index header */
|
||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||
this->count.set (dataArray.len);
|
||||
this->offSize.set (offSize_);
|
||||
if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (dataArray.len + 1))))
|
||||
return_trace (false);
|
||||
|
||||
/* serialize indices */
|
||||
unsigned int offset = 1;
|
||||
unsigned int i = 0;
|
||||
for (; i < dataArray.len; i++)
|
||||
{
|
||||
Index<COUNT>::set_offset_at (i, offset);
|
||||
offset += dataSizeArray[i];
|
||||
}
|
||||
Index<COUNT>::set_offset_at (i, offset);
|
||||
|
||||
/* serialize data */
|
||||
for (unsigned int i = 0; i < dataArray.len; i++)
|
||||
{
|
||||
TYPE *dest = c->start_embed<TYPE> ();
|
||||
if (unlikely (dest == nullptr ||
|
||||
!dest->serialize (c, dataArray[i], param1, param2)))
|
||||
return_trace (false);
|
||||
}
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
/* in parallel to above */
|
||||
template <typename DATA, typename PARAM>
|
||||
inline static unsigned int calculate_serialized_size (unsigned int &offSize_ /* OUT */,
|
||||
const hb_vector_t<DATA> &dataArray,
|
||||
hb_vector_t<unsigned int> &dataSizeArray, /* OUT */
|
||||
const PARAM ¶m)
|
||||
{
|
||||
/* determine offset size */
|
||||
unsigned int totalDataSize = 0;
|
||||
for (unsigned int i = 0; i < dataArray.len; i++)
|
||||
{
|
||||
unsigned int dataSize = TYPE::calculate_serialized_size (dataArray[i], param);
|
||||
dataSizeArray[i] = dataSize;
|
||||
totalDataSize += dataSize;
|
||||
}
|
||||
offSize_ = calcOffSize (totalDataSize);
|
||||
|
||||
return Index<COUNT>::calculate_serialized_size (offSize_, dataArray.len, totalDataSize);
|
||||
}
|
||||
};
|
||||
|
||||
inline float parse_bcd (const ByteStr& str, unsigned int& offset, float& v)
|
||||
{
|
||||
// XXX: TODO
|
||||
v = 0;
|
||||
for (;;) {
|
||||
if (++offset >= str.len)
|
||||
return false;
|
||||
unsigned char byte = str[offset];
|
||||
if (((byte & 0xF0) == 0xF0) || ((byte & 0x0F) == 0x0F))
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* operand stack */
|
||||
struct Stack
|
||||
{
|
||||
inline void init (void) { size = 0; }
|
||||
inline void fini (void) { }
|
||||
|
||||
inline void push (const Number &v)
|
||||
{
|
||||
if (likely (size < kSizeLimit))
|
||||
numbers[size++] = v;
|
||||
}
|
||||
|
||||
inline void push_int (int v)
|
||||
{
|
||||
Number n;
|
||||
n.set_int (v);
|
||||
push (n);
|
||||
}
|
||||
|
||||
inline void push_real (float v)
|
||||
{
|
||||
Number n;
|
||||
n.set_real (v);
|
||||
push (n);
|
||||
}
|
||||
|
||||
inline const Number& pop (void)
|
||||
{
|
||||
if (likely (size > 0))
|
||||
return numbers[--size];
|
||||
else
|
||||
return Null(Number);
|
||||
}
|
||||
|
||||
inline bool check_push (void)
|
||||
{
|
||||
if (likely (size < kSizeLimit)) {
|
||||
size++;
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool check_pop (void)
|
||||
{
|
||||
if (likely (0 < size)) {
|
||||
size--;
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool check_pop_num (Number& n)
|
||||
{
|
||||
if (unlikely (!this->check_underflow (1)))
|
||||
return false;
|
||||
n = this->pop ();
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool check_pop_uint (unsigned int& v)
|
||||
{
|
||||
uint32_t i;
|
||||
if (unlikely (!this->check_underflow (1)))
|
||||
return false;
|
||||
i = this->pop ().to_int ();
|
||||
if (unlikely (i < 0))
|
||||
return false;
|
||||
v = (uint32_t)i;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool check_pop_delta (hb_vector_t<Number>& vec, bool even=false)
|
||||
{
|
||||
if (even && unlikely ((this->size & 1) != 0))
|
||||
return false;
|
||||
|
||||
float val = 0.0f;
|
||||
for (unsigned int i = 0; i < size; i++) {
|
||||
val += numbers[i].to_real ();
|
||||
Number *n = vec.push ();
|
||||
n->set_real (val);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool push_longint_from_str (const ByteStr& str, unsigned int& offset)
|
||||
{
|
||||
if (unlikely (!str.check_limit (offset, 5) || !check_overflow (1)))
|
||||
return false;
|
||||
push_int ((int32_t)*(const HBUINT32*)&str[offset + 1]);
|
||||
offset += 4;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void clear (void) { size = 0; }
|
||||
|
||||
inline bool check_overflow (unsigned int count) const { return (count <= kSizeLimit) && (count + size <= kSizeLimit); }
|
||||
inline bool check_underflow (unsigned int count) const { return (count <= size); }
|
||||
|
||||
inline unsigned int get_size (void) const { return size; }
|
||||
inline bool is_empty (void) const { return size == 0; }
|
||||
|
||||
static const unsigned int kSizeLimit = 513;
|
||||
|
||||
unsigned int size;
|
||||
Number numbers[kSizeLimit];
|
||||
};
|
||||
|
||||
/* an operator prefixed by its operands in a byte string */
|
||||
|
@ -438,21 +629,6 @@ struct DictValues
|
|||
hb_vector_t<VAL> values;
|
||||
};
|
||||
|
||||
/* base of OP_SERIALIZER */
|
||||
struct OpSerializer
|
||||
{
|
||||
protected:
|
||||
inline bool copy_opstr (hb_serialize_context_t *c, const OpStr& opstr) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
||||
HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.len);
|
||||
if (unlikely (d == nullptr)) return_trace (false);
|
||||
memcpy (d, &opstr.str.str[0], opstr.str.len);
|
||||
return_trace (true);
|
||||
}
|
||||
};
|
||||
|
||||
/* Top Dict, Font Dict, Private Dict */
|
||||
struct Dict : UnsizedByteStr
|
||||
{
|
||||
|
@ -516,22 +692,31 @@ struct TopDict : Dict {};
|
|||
struct FontDict : Dict {};
|
||||
struct PrivateDict : Dict {};
|
||||
|
||||
struct FDArray : IndexOf<FontDict>
|
||||
struct TableInfo
|
||||
{
|
||||
void init (void) { offset = size = 0; }
|
||||
|
||||
unsigned int offset;
|
||||
unsigned int size;
|
||||
};
|
||||
|
||||
template <typename COUNT>
|
||||
struct FDArray : IndexOf<COUNT, FontDict>
|
||||
{
|
||||
template <typename DICTVAL, typename OP_SERIALIZER>
|
||||
inline bool serialize (hb_serialize_context_t *c,
|
||||
unsigned int offSize,
|
||||
unsigned int offSize_,
|
||||
const hb_vector_t<DICTVAL> &fontDicts,
|
||||
unsigned int fdCount,
|
||||
const hb_vector_t<hb_codepoint_t> &fdmap,
|
||||
OP_SERIALIZER& opszr,
|
||||
const hb_vector_t<offset_size_pair> &privatePairs)
|
||||
const hb_vector_t<TableInfo> &privateInfos)
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
if (unlikely (!c->extend_min (*this))) return_trace (false);
|
||||
this->count.set (fdCount);
|
||||
this->offSize.set (offSize);
|
||||
if (!unlikely (c->allocate_size<HBUINT8> (offSize * (fdCount + 1))))
|
||||
this->offSize.set (offSize_);
|
||||
if (!unlikely (c->allocate_size<HBUINT8> (offSize_ * (fdCount + 1))))
|
||||
return_trace (false);
|
||||
|
||||
/* serialize font dict offsets */
|
||||
|
@ -540,17 +725,17 @@ struct FDArray : IndexOf<FontDict>
|
|||
for (unsigned i = 0; i < fontDicts.len; i++)
|
||||
if (!fdmap.len || fdmap[i] != HB_SET_VALUE_INVALID)
|
||||
{
|
||||
set_offset_at (fid++, offset);
|
||||
IndexOf<COUNT, FontDict>::set_offset_at (fid++, offset);
|
||||
offset += FontDict::calculate_serialized_size (fontDicts[i], opszr);
|
||||
}
|
||||
set_offset_at (fid, offset);
|
||||
IndexOf<COUNT, FontDict>::set_offset_at (fid, offset);
|
||||
|
||||
/* serialize font dicts */
|
||||
for (unsigned int i = 0; i < fontDicts.len; i++)
|
||||
if (fdmap[i] != HB_SET_VALUE_INVALID)
|
||||
{
|
||||
FontDict *dict = c->start_embed<FontDict> ();
|
||||
if (unlikely (!dict->serialize (c, fontDicts[i], opszr, privatePairs[i])))
|
||||
if (unlikely (!dict->serialize (c, fontDicts[i], opszr, privateInfos[i])))
|
||||
return_trace (false);
|
||||
}
|
||||
return_trace (true);
|
||||
|
@ -558,7 +743,7 @@ struct FDArray : IndexOf<FontDict>
|
|||
|
||||
/* in parallel to above */
|
||||
template <typename OP_SERIALIZER, typename DICTVAL>
|
||||
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,
|
||||
unsigned int fdCount,
|
||||
const hb_vector_t<hb_codepoint_t> &fdmap,
|
||||
|
@ -569,8 +754,8 @@ struct FDArray : IndexOf<FontDict>
|
|||
if (!fdmap.len || fdmap[i] != HB_SET_VALUE_INVALID)
|
||||
dictsSize += FontDict::calculate_serialized_size (fontDicts[i], opszr);
|
||||
|
||||
offSize = calcOffSize (dictsSize + 1);
|
||||
return Index::calculate_serialized_size (offSize, fdCount, dictsSize);
|
||||
offSize_ = calcOffSize (dictsSize + 1);
|
||||
return Index<COUNT>::calculate_serialized_size (offSize_, fdCount, dictsSize);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -641,9 +826,9 @@ struct FDSelect3_4 {
|
|||
|
||||
inline hb_codepoint_t get_fd (hb_codepoint_t glyph) const
|
||||
{
|
||||
for (unsigned int i = 0; i < nRanges; i++)
|
||||
if (glyph < ranges[i + 1].first)
|
||||
return (hb_codepoint_t)ranges[i].fd;
|
||||
for (unsigned int i = 1; i < nRanges; i++)
|
||||
if (glyph < ranges[i].first)
|
||||
return (hb_codepoint_t)ranges[i - 1].fd;
|
||||
|
||||
assert (false);
|
||||
}
|
||||
|
@ -709,131 +894,89 @@ struct FDSelect {
|
|||
FDSelect3 format3;
|
||||
} u;
|
||||
|
||||
DEFINE_SIZE_MIN (2);
|
||||
DEFINE_SIZE_MIN (1);
|
||||
};
|
||||
|
||||
typedef Index CharStrings;
|
||||
typedef Index Subrs;
|
||||
|
||||
inline float parse_bcd (const ByteStr& str, unsigned int& offset, float& v)
|
||||
struct TopDictValues : DictValues<OpStr>
|
||||
{
|
||||
// XXX: TODO
|
||||
v = 0;
|
||||
for (;;) {
|
||||
if (++offset >= str.len)
|
||||
return false;
|
||||
unsigned char byte = str[offset];
|
||||
if (((byte & 0xF0) == 0xF0) || ((byte & 0x0F) == 0x0F))
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
struct Stack
|
||||
{
|
||||
inline void init (void) { size = 0; }
|
||||
inline void fini (void) { }
|
||||
|
||||
inline void push (const Number &v)
|
||||
inline void init (void)
|
||||
{
|
||||
if (likely (size < kSizeLimit))
|
||||
numbers[size++] = v;
|
||||
DictValues<OpStr>::init ();
|
||||
charStringsOffset = 0;
|
||||
FDArrayOffset = 0;
|
||||
}
|
||||
|
||||
inline void push_int (int v)
|
||||
inline void fini (void)
|
||||
{
|
||||
Number n;
|
||||
n.set_int (v);
|
||||
push (n);
|
||||
DictValues<OpStr>::fini ();
|
||||
}
|
||||
|
||||
inline void push_real (float v)
|
||||
inline unsigned int calculate_serialized_op_size (const OpStr& opstr) const
|
||||
{
|
||||
Number n;
|
||||
n.set_real (v);
|
||||
push (n);
|
||||
}
|
||||
switch (opstr.op)
|
||||
{
|
||||
case OpCode_CharStrings:
|
||||
case OpCode_FDArray:
|
||||
return OpCode_Size (OpCode_longint) + 4 + OpCode_Size (opstr.op);
|
||||
|
||||
inline const Number& pop (void)
|
||||
{
|
||||
if (likely (size > 0))
|
||||
return numbers[--size];
|
||||
else
|
||||
return Null(Number);
|
||||
}
|
||||
|
||||
inline bool check_push (void)
|
||||
{
|
||||
if (likely (size < kSizeLimit)) {
|
||||
size++;
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool check_pop (void)
|
||||
{
|
||||
if (likely (0 < size)) {
|
||||
size--;
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool check_pop_num (Number& n)
|
||||
{
|
||||
if (unlikely (!this->check_underflow (1)))
|
||||
return false;
|
||||
n = this->pop ();
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool check_pop_uint (unsigned int& v)
|
||||
{
|
||||
uint32_t i;
|
||||
if (unlikely (!this->check_underflow (1)))
|
||||
return false;
|
||||
i = this->pop ().to_int ();
|
||||
if (unlikely (i <= 0))
|
||||
return false;
|
||||
v = (uint32_t)i;
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool check_pop_delta (hb_vector_t<Number>& vec, bool even=false)
|
||||
{
|
||||
if (even && unlikely ((this->size & 1) != 0))
|
||||
return false;
|
||||
|
||||
float val = 0.0f;
|
||||
for (unsigned int i = 0; i < size; i++) {
|
||||
val += numbers[i].to_real ();
|
||||
Number *n = vec.push ();
|
||||
n->set_real (val);
|
||||
default:
|
||||
return opstr.str.len;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void clear (void) { size = 0; }
|
||||
|
||||
inline bool check_overflow (unsigned int count) { return (count <= kSizeLimit) && (count + size <= kSizeLimit); }
|
||||
inline bool check_underflow (unsigned int count) { return (count <= size); }
|
||||
|
||||
static const unsigned int kSizeLimit = 513;
|
||||
|
||||
unsigned int size;
|
||||
Number numbers[kSizeLimit];
|
||||
unsigned int charStringsOffset;
|
||||
unsigned int FDArrayOffset;
|
||||
};
|
||||
|
||||
template <typename Offset>
|
||||
inline bool check_pop_offset (Stack& stack, Offset& offset)
|
||||
struct TopDictOpSet
|
||||
{
|
||||
unsigned int v;
|
||||
if (unlikely (!stack.check_pop_uint (v)))
|
||||
return false;
|
||||
offset.set (v);
|
||||
return true;
|
||||
}
|
||||
static inline bool process_op (const ByteStr& str, unsigned int& offset, OpCode op, Stack& stack, TopDictValues& dictval)
|
||||
{
|
||||
switch (op) {
|
||||
case OpCode_CharStrings:
|
||||
if (unlikely (!stack.check_pop_uint (dictval.charStringsOffset)))
|
||||
return false;
|
||||
stack.clear ();
|
||||
break;
|
||||
case OpCode_FDArray:
|
||||
if (unlikely (!stack.check_pop_uint (dictval.FDArrayOffset)))
|
||||
return false;
|
||||
stack.clear ();
|
||||
break;
|
||||
case OpCode_longint: /* 5-byte integer */
|
||||
return stack.push_longint_from_str (str, offset);
|
||||
|
||||
case OpCode_BCD: /* real number */
|
||||
float v;
|
||||
if (unlikely (stack.check_overflow (1) || !parse_bcd (str, offset, v)))
|
||||
return false;
|
||||
stack.push_real (v);
|
||||
return true;
|
||||
|
||||
default:
|
||||
/* XXX: invalid */
|
||||
stack.clear ();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
/* base of OP_SERIALIZER */
|
||||
struct OpSerializer
|
||||
{
|
||||
protected:
|
||||
inline bool copy_opstr (hb_serialize_context_t *c, const OpStr& opstr) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
||||
HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.len);
|
||||
if (unlikely (d == nullptr)) return_trace (false);
|
||||
memcpy (d, &opstr.str.str[0], opstr.str.len);
|
||||
return_trace (true);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename OpSet, typename Param>
|
||||
struct Interpreter {
|
||||
|
@ -919,24 +1062,6 @@ struct Interpreter {
|
|||
Stack stack;
|
||||
};
|
||||
|
||||
/* used by subsettter */
|
||||
struct SubTableOffsets {
|
||||
inline SubTableOffsets (void)
|
||||
{
|
||||
memset (this, 0, sizeof(*this));
|
||||
}
|
||||
|
||||
unsigned int topDictSize;
|
||||
unsigned int varStoreOffset;
|
||||
unsigned int FDSelectOffset;
|
||||
unsigned int FDSelectSize;
|
||||
unsigned int FDArrayOffset;
|
||||
unsigned int FDArrayOffSize;
|
||||
unsigned int charStringsOffset;
|
||||
unsigned int charStringsOffSize;
|
||||
unsigned int privateDictsOffset;
|
||||
};
|
||||
|
||||
} /* namespace CFF */
|
||||
|
||||
#endif /* HB_OT_CFF_COMMON_PRIVATE_HH */
|
||||
|
|
|
@ -0,0 +1,919 @@
|
|||
/*
|
||||
* 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_CFF_TABLE_HH
|
||||
#define HB_OT_CFF_TABLE_HH
|
||||
|
||||
#include "hb-ot-cff-common-private.hh"
|
||||
#include "hb-subset-cff.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_cff HB_TAG('C','F','F',' ')
|
||||
|
||||
typedef Index<HBUINT16> CFFIndex;
|
||||
template <typename Type> struct CFFIndexOf : IndexOf<HBUINT16, Type> {};
|
||||
|
||||
typedef Index<HBUINT16> CFFIndex;
|
||||
typedef CFFIndex CFFCharStrings;
|
||||
typedef FDArray<HBUINT16> CFFFDArray;
|
||||
typedef CFFIndex CFFSubrs;
|
||||
|
||||
struct CFFFDSelect : 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 CFFSuppEncData {
|
||||
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 CFFSuppEncData &suppEncData (void) const
|
||||
{
|
||||
if ((format & 0x7F) == 0)
|
||||
return StructAfter<CFFSuppEncData> (u.format0.codes[u.format0.nCodes-1]);
|
||||
else
|
||||
return StructAfter<CFFSuppEncData> (u.format1.ranges[u.format1.nRanges-1]);
|
||||
}
|
||||
|
||||
HBUINT8 format;
|
||||
union {
|
||||
Encoding0 format0;
|
||||
Encoding1 format1;
|
||||
} u;
|
||||
/* CFFSuppEncData 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 CFFTopDictValues : 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_longint) + 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 CFFTopDictOpSet : TopDictOpSet
|
||||
{
|
||||
static inline bool process_op (const ByteStr& str, unsigned int& offset,
|
||||
OpCode op, Stack& stack, CFFTopDictValues& 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:
|
||||
stack.clear ();
|
||||
break;
|
||||
|
||||
case OpCode_CIDCount:
|
||||
if (unlikely (!stack.check_pop_uint (dictval.cidCount)))
|
||||
return false;
|
||||
stack.clear ();
|
||||
break;
|
||||
|
||||
case OpCode_ROS:
|
||||
if (unlikely (!stack.check_pop_uint (dictval.ros[2]) ||
|
||||
!stack.check_pop_uint (dictval.ros[1]) ||
|
||||
!stack.check_pop_uint (dictval.ros[0])))
|
||||
return false;
|
||||
stack.clear ();
|
||||
break;
|
||||
|
||||
case OpCode_Encoding:
|
||||
if (unlikely (!stack.check_pop_uint (dictval.EncodingOffset)))
|
||||
return false;
|
||||
stack.clear ();
|
||||
break;
|
||||
|
||||
case OpCode_charset:
|
||||
if (unlikely (!stack.check_pop_uint (dictval.CharsetOffset)))
|
||||
return false;
|
||||
stack.clear ();
|
||||
break;
|
||||
|
||||
case OpCode_FDSelect:
|
||||
if (unlikely (!stack.check_pop_uint (dictval.FDSelectOffset)))
|
||||
return false;
|
||||
stack.clear ();
|
||||
break;
|
||||
|
||||
case OpCode_Private:
|
||||
if (unlikely (!stack.check_pop_uint (dictval.privateDictInfo.offset)))
|
||||
return false;
|
||||
if (unlikely (!stack.check_pop_uint (dictval.privateDictInfo.size)))
|
||||
return false;
|
||||
stack.clear ();
|
||||
break;
|
||||
|
||||
default:
|
||||
if (unlikely (!TopDictOpSet::process_op (str, offset, op, stack, dictval)))
|
||||
return false;
|
||||
/* Record this operand below if stack is empty, otherwise done */
|
||||
if (!stack.is_empty ()) return true;
|
||||
break;
|
||||
}
|
||||
|
||||
dictval.pushVal (op, str, offset + 1);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct CFFFontDictValues : DictValues<OpStr>
|
||||
{
|
||||
inline void init (void)
|
||||
{
|
||||
DictValues<OpStr>::init ();
|
||||
privateDictInfo.init ();
|
||||
}
|
||||
|
||||
inline void fini (void)
|
||||
{
|
||||
DictValues<OpStr>::fini ();
|
||||
}
|
||||
|
||||
TableInfo privateDictInfo;
|
||||
};
|
||||
|
||||
struct CFFFontDictOpSet
|
||||
{
|
||||
static inline bool process_op (const ByteStr& str, unsigned int& offset,
|
||||
OpCode op, Stack& stack, CFFFontDictValues& dictval)
|
||||
{
|
||||
switch (op) {
|
||||
case OpCode_FontName:
|
||||
case OpCode_FontMatrix:
|
||||
case OpCode_PaintType:
|
||||
stack.clear ();
|
||||
break;
|
||||
case OpCode_Private:
|
||||
if (unlikely (!stack.check_pop_uint (dictval.privateDictInfo.offset)))
|
||||
return false;
|
||||
if (unlikely (!stack.check_pop_uint (dictval.privateDictInfo.size)))
|
||||
return false;
|
||||
stack.clear ();
|
||||
break;
|
||||
case OpCode_longint: /* 5-byte integer */
|
||||
return stack.push_longint_from_str (str, offset);
|
||||
case OpCode_BCD: /* real number */
|
||||
float v;
|
||||
if (unlikely (stack.check_overflow (1) || !parse_bcd (str, offset, v)))
|
||||
return false;
|
||||
stack.push_real (v);
|
||||
return true;
|
||||
|
||||
default:
|
||||
/* XXX: invalid */
|
||||
stack.clear ();
|
||||
return false;
|
||||
}
|
||||
|
||||
dictval.pushVal (op, str, offset + 1);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename VAL>
|
||||
struct CFFPrivateDictValues_Base : DictValues<VAL>
|
||||
{
|
||||
inline void init (void)
|
||||
{
|
||||
DictValues<VAL>::init ();
|
||||
subrsOffset = 0;
|
||||
localSubrs = &Null(CFFSubrs);
|
||||
}
|
||||
|
||||
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 CFFSubrs *localSubrs;
|
||||
};
|
||||
|
||||
typedef CFFPrivateDictValues_Base<OpStr> CFFPrivateDictValues_Subset;
|
||||
typedef CFFPrivateDictValues_Base<DictVal> CFFPrivateDictValues;
|
||||
|
||||
struct CFFPrivateDictOpSet
|
||||
{
|
||||
static inline bool process_op (const ByteStr& str, unsigned int& offset,
|
||||
OpCode op, Stack& stack, CFFPrivateDictValues& 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 (!stack.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 (!stack.check_pop_num (val.single_val)))
|
||||
return false;
|
||||
stack.clear ();
|
||||
break;
|
||||
case OpCode_Subrs:
|
||||
if (unlikely (!stack.check_pop_uint (dictval.subrsOffset)))
|
||||
return false;
|
||||
stack.clear ();
|
||||
break;
|
||||
case OpCode_longint: /* 5-byte integer */
|
||||
return stack.push_longint_from_str (str, offset);
|
||||
case OpCode_BCD: /* real number */
|
||||
float v;
|
||||
if (unlikely (!stack.check_overflow (1) || !parse_bcd (str, offset, v)))
|
||||
return false;
|
||||
stack.push_real (v);
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
dictval.pushVal (op, str, offset + 1, val);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct CFFPrivateDictOpSet_Subset
|
||||
{
|
||||
static inline bool process_op (const ByteStr& str, unsigned int& offset,
|
||||
OpCode op, Stack& stack, CFFPrivateDictValues_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:
|
||||
stack.clear ();
|
||||
break;
|
||||
|
||||
case OpCode_BCD:
|
||||
{
|
||||
float v;
|
||||
return parse_bcd (str, offset, v);
|
||||
}
|
||||
|
||||
case OpCode_Subrs:
|
||||
if (unlikely (!stack.check_pop_uint (dictval.subrsOffset)))
|
||||
return false;
|
||||
stack.clear ();
|
||||
break;
|
||||
case OpCode_longint: /* 5-byte integer */
|
||||
return stack.push_longint_from_str (str, offset);
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
dictval.pushVal (op, str, offset + 1);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
typedef Interpreter<CFFTopDictOpSet, CFFTopDictValues> CFFTopDict_Interpreter;
|
||||
typedef Interpreter<CFFFontDictOpSet, CFFFontDictValues> CFFFontDict_Interpreter;
|
||||
typedef Interpreter<CFFPrivateDictOpSet, CFFPrivateDictValues> CFFPrivateDict_Interpreter;
|
||||
|
||||
typedef CFFIndex NameIndex;
|
||||
typedef CFFIndexOf<TopDict> TopDictIndex;
|
||||
typedef CFFIndex StringIndex;
|
||||
|
||||
}; /* namespace CFF */
|
||||
|
||||
namespace OT {
|
||||
|
||||
using namespace CFF;
|
||||
|
||||
struct cff
|
||||
{
|
||||
static const hb_tag_t tableTag = HB_OT_TAG_cff;
|
||||
|
||||
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<cff> (face);
|
||||
|
||||
/* setup for run-time santization */
|
||||
sc.init (this->blob);
|
||||
sc.start_processing ();
|
||||
|
||||
const OT::cff *cff = this->blob->template as<OT::cff> ();
|
||||
|
||||
if (cff == &Null(OT::cff))
|
||||
{ fini (); return; }
|
||||
|
||||
nameIndex = &cff->nameIndex (cff);
|
||||
if ((nameIndex == &Null (NameIndex)) || !nameIndex->sanitize (&sc))
|
||||
{ fini (); return; }
|
||||
|
||||
topDictIndex = &StructAtOffset<TopDictIndex> (nameIndex, nameIndex->get_size ());
|
||||
if ((topDictIndex == &Null (TopDictIndex)) || !topDictIndex->sanitize (&sc) || (topDictIndex->count == 0))
|
||||
{ fini (); return; }
|
||||
|
||||
{ /* parse top dict */
|
||||
const ByteStr topDictStr = (*topDictIndex)[0];
|
||||
CFFTopDict_Interpreter top_interp;
|
||||
if (unlikely (!topDictStr.sanitize (&sc) ||
|
||||
!top_interp.interpret (topDictStr, topDicts[0])))
|
||||
{ fini (); return; }
|
||||
}
|
||||
|
||||
encoding = &Null(Encoding);
|
||||
charset = &StructAtOffsetOrNull<Charset> (cff, topDicts[0].CharsetOffset);
|
||||
|
||||
fdCount = 1;
|
||||
if (is_CID ())
|
||||
{
|
||||
fdArray = &StructAtOffsetOrNull<CFFFDArray> (cff, topDicts[0].FDArrayOffset);
|
||||
fdSelect = &StructAtOffsetOrNull<CFFFDSelect> (cff, topDicts[0].FDSelectOffset);
|
||||
if (unlikely ((fdArray == &Null(CFFFDArray)) || !fdArray->sanitize (&sc) ||
|
||||
(fdSelect == &Null(CFFFDSelect)) || !fdSelect->sanitize (&sc, fdArray->count)))
|
||||
{ fini (); return; }
|
||||
|
||||
fdCount = fdArray->count;
|
||||
}
|
||||
else
|
||||
{
|
||||
fdArray = &Null(CFFFDArray);
|
||||
fdSelect = &Null(CFFFDSelect);
|
||||
if (topDicts[0].EncodingOffset != CFFTopDictValues::StandardEncoding &&
|
||||
topDicts[0].EncodingOffset != CFFTopDictValues::ExpertEncoding)
|
||||
{
|
||||
encoding = &StructAtOffsetOrNull<Encoding> (cff, topDicts[0].EncodingOffset);
|
||||
if ((encoding == &Null (Encoding)) || !encoding->sanitize (&sc))
|
||||
{ fini (); return; }
|
||||
}
|
||||
}
|
||||
|
||||
stringIndex = &StructAtOffset<StringIndex> (topDictIndex, topDictIndex->get_size ());
|
||||
if ((stringIndex == &Null (StringIndex)) || !stringIndex->sanitize (&sc))
|
||||
{ fini (); return; }
|
||||
|
||||
globalSubrs = &StructAtOffset<CFFSubrs> (stringIndex, stringIndex->get_size ());
|
||||
if ((globalSubrs != &Null (CFFSubrs)) && !stringIndex->sanitize (&sc))
|
||||
{ fini (); return; }
|
||||
|
||||
charStrings = &StructAtOffsetOrNull<CFFCharStrings> (cff, topDicts[0].charStringsOffset);
|
||||
|
||||
if ((charStrings == &Null(CFFCharStrings)) || 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];
|
||||
CFFFontDictValues *font;
|
||||
CFFFontDict_Interpreter font_interp;
|
||||
font = fontDicts.push ();
|
||||
if (unlikely (!fontDictStr.sanitize (&sc) ||
|
||||
!font_interp.interpret (fontDictStr, *font)))
|
||||
{ fini (); return; }
|
||||
PrivDictVal *priv = &privateDicts[i];
|
||||
const ByteStr privDictStr (StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size);
|
||||
Interpreter<PrivOpSet, PrivDictVal> priv_interp;
|
||||
if (unlikely (!privDictStr.sanitize (&sc) ||
|
||||
!priv_interp.interpret (privDictStr, *priv)))
|
||||
{ fini (); return; }
|
||||
|
||||
priv->localSubrs = &StructAtOffsetOrNull<CFFSubrs> (privDictStr.str, priv->subrsOffset);
|
||||
if (priv->localSubrs != &Null(CFFSubrs) &&
|
||||
unlikely (!priv->localSubrs->sanitize (&sc)))
|
||||
{ fini (); return; }
|
||||
}
|
||||
}
|
||||
else /* non-CID */
|
||||
{
|
||||
CFFTopDictValues *font = &topDicts[0];
|
||||
PrivDictVal *priv = &privateDicts[0];
|
||||
|
||||
const ByteStr privDictStr (StructAtOffset<UnsizedByteStr> (cff, font->privateDictInfo.offset), font->privateDictInfo.size);
|
||||
Interpreter<PrivOpSet, PrivDictVal> priv_interp;
|
||||
if (unlikely (!privDictStr.sanitize (&sc) ||
|
||||
!priv_interp.interpret (privDictStr, *priv)))
|
||||
{ fini (); return; }
|
||||
|
||||
priv->localSubrs = &StructAtOffsetOrNull<CFFSubrs> (privDictStr.str, priv->subrsOffset);
|
||||
if (priv->localSubrs != &Null(CFFSubrs) &&
|
||||
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 NameIndex *nameIndex;
|
||||
const TopDictIndex *topDictIndex;
|
||||
const StringIndex *stringIndex;
|
||||
const Encoding *encoding;
|
||||
const Charset *charset;
|
||||
const CFFSubrs *globalSubrs;
|
||||
const CFFCharStrings *charStrings;
|
||||
const CFFFDArray *fdArray;
|
||||
const CFFFDSelect *fdSelect;
|
||||
unsigned int fdCount;
|
||||
|
||||
hb_vector_t<CFFTopDictValues> topDicts;
|
||||
hb_vector_t<CFFFontDictValues> fontDicts;
|
||||
hb_vector_t<PrivDictVal> privateDicts;
|
||||
|
||||
unsigned int num_glyphs;
|
||||
};
|
||||
|
||||
typedef accelerator_templ_t<CFFPrivateDictOpSet, CFFPrivateDictValues> accelerator_t;
|
||||
typedef accelerator_templ_t<CFFPrivateDictOpSet_Subset, CFFPrivateDictValues_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_cff (plan, &cff_prime)) {
|
||||
success = success && plan->add_table (HB_OT_TAG_cff, cff_prime);
|
||||
} else {
|
||||
success = false;
|
||||
}
|
||||
hb_blob_destroy (cff_prime);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
public:
|
||||
FixedVersion<HBUINT8> version; /* Version of CFF table. set to 0x0100u */
|
||||
OffsetTo<NameIndex, HBUINT8> nameIndex; /* headerSize = Offset to Name INDEX. */
|
||||
HBUINT8 offSize; /* offset size (unused?) */
|
||||
|
||||
public:
|
||||
DEFINE_SIZE_STATIC (4);
|
||||
};
|
||||
|
||||
} /* namespace OT */
|
||||
|
||||
#endif /* HB_OT_CFF_TABLE_HH */
|
|
@ -38,6 +38,13 @@ namespace CFF {
|
|||
*/
|
||||
#define HB_OT_TAG_cff2 HB_TAG('C','F','F','2')
|
||||
|
||||
typedef Index<HBUINT32> CFF2Index;
|
||||
template <typename Type> struct CFF2IndexOf : IndexOf<HBUINT32, Type> {};
|
||||
|
||||
typedef CFF2Index CFF2CharStrings;
|
||||
typedef FDArray<HBUINT32> CFF2FDArray;
|
||||
typedef CFF2Index CFF2Subrs;
|
||||
|
||||
typedef FDSelect3_4<HBUINT32, HBUINT16> FDSelect4;
|
||||
typedef FDSelect3_4_Range<HBUINT32, HBUINT16> FDSelect4_Range;
|
||||
|
||||
|
@ -126,22 +133,18 @@ struct CFF2VariationStore
|
|||
DEFINE_SIZE_MIN (2 + VariationStore::min_size);
|
||||
};
|
||||
|
||||
struct CFF2TopDictValues : DictValues<OpStr>
|
||||
struct CFF2TopDictValues : TopDictValues
|
||||
{
|
||||
inline void init (void)
|
||||
{
|
||||
DictValues<OpStr>::init ();
|
||||
charStringsOffset.set (0);
|
||||
vstoreOffset.set (0);
|
||||
FDArrayOffset.set (0);
|
||||
FDSelectOffset.set (0);
|
||||
TopDictValues::init ();
|
||||
vstoreOffset = 0;
|
||||
FDSelectOffset = 0;
|
||||
}
|
||||
|
||||
inline void fini (void)
|
||||
{
|
||||
DictValues<OpStr>::fini ();
|
||||
FontMatrix[0] = FontMatrix[3] = 0.001f;
|
||||
FontMatrix[1] = FontMatrix[2] = FontMatrix[4] = FontMatrix[5] = 0.0f;
|
||||
TopDictValues::fini ();
|
||||
}
|
||||
|
||||
inline unsigned int calculate_serialized_size (void) const
|
||||
|
@ -150,66 +153,55 @@ struct CFF2TopDictValues : DictValues<OpStr>
|
|||
for (unsigned int i = 0; i < values.len; i++)
|
||||
{
|
||||
OpCode op = values[i].op;
|
||||
if (op == OpCode_FontMatrix)
|
||||
size += values[i].str.len;
|
||||
else
|
||||
size += OpCode_Size (OpCode_longint) + 4 + OpCode_Size (op);
|
||||
switch (op)
|
||||
{
|
||||
case OpCode_vstore:
|
||||
case OpCode_FDSelect:
|
||||
size += OpCode_Size (OpCode_longint) + 4 + OpCode_Size (op);
|
||||
break;
|
||||
default:
|
||||
size += TopDictValues::calculate_serialized_op_size (values[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
float FontMatrix[6];
|
||||
LOffsetTo<CharStrings> charStringsOffset;
|
||||
LOffsetTo<CFF2VariationStore> vstoreOffset;
|
||||
LOffsetTo<FDArray> FDArrayOffset;
|
||||
LOffsetTo<CFF2FDSelect> FDSelectOffset;
|
||||
unsigned int vstoreOffset;
|
||||
unsigned int FDSelectOffset;
|
||||
};
|
||||
|
||||
struct CFF2TopDictOpSet
|
||||
struct CFF2TopDictOpSet : TopDictOpSet
|
||||
{
|
||||
static inline bool process_op (const ByteStr& str, unsigned int& offset, OpCode op, Stack& stack, CFF2TopDictValues& dictval)
|
||||
static inline bool process_op (const ByteStr& str, unsigned int& offset,
|
||||
OpCode op, Stack& stack, CFF2TopDictValues& dictval)
|
||||
{
|
||||
switch (op) {
|
||||
case OpCode_CharStrings:
|
||||
if (unlikely (!check_pop_offset (stack, dictval.charStringsOffset)))
|
||||
return false;
|
||||
case OpCode_FontMatrix:
|
||||
{
|
||||
DictVal val;
|
||||
val.init ();
|
||||
dictval.pushVal (op, str, offset + 1);
|
||||
stack.clear ();
|
||||
}
|
||||
break;
|
||||
|
||||
case OpCode_vstore:
|
||||
if (unlikely (!check_pop_offset (stack, dictval.vstoreOffset)))
|
||||
return false;
|
||||
break;
|
||||
case OpCode_FDArray:
|
||||
if (unlikely (!check_pop_offset (stack, dictval.FDArrayOffset)))
|
||||
if (unlikely (!stack.check_pop_uint (dictval.vstoreOffset)))
|
||||
return false;
|
||||
stack.clear ();
|
||||
break;
|
||||
case OpCode_FDSelect:
|
||||
if (unlikely (!check_pop_offset (stack, dictval.FDSelectOffset)))
|
||||
if (unlikely (!stack.check_pop_uint (dictval.FDSelectOffset)))
|
||||
return false;
|
||||
stack.clear ();
|
||||
break;
|
||||
case OpCode_FontMatrix:
|
||||
if (unlikely (!stack.check_underflow (6)))
|
||||
return false;
|
||||
for (int i = 0; i < 6; i++)
|
||||
dictval.FontMatrix[i] = stack.pop ().to_real ();
|
||||
break;
|
||||
case OpCode_longint: /* 5-byte integer */
|
||||
if (unlikely (!str.check_limit (offset, 5) || !stack.check_overflow (1)))
|
||||
return false;
|
||||
stack.push_int ((int32_t)*(const HBUINT32*)&str[offset + 1]);
|
||||
offset += 4;
|
||||
return true;
|
||||
|
||||
case OpCode_BCD: /* real number */
|
||||
float v;
|
||||
if (unlikely (stack.check_overflow (1) || !parse_bcd (str, offset, v)))
|
||||
return false;
|
||||
stack.push_real (v);
|
||||
return true;
|
||||
|
||||
default:
|
||||
/* XXX: invalid */
|
||||
stack.clear ();
|
||||
return false;
|
||||
if (unlikely (!TopDictOpSet::process_op (str, offset, op, stack, dictval)))
|
||||
return false;
|
||||
/* Record this operand below if stack is empty, otherwise done */
|
||||
if (!stack.is_empty ()) return true;
|
||||
}
|
||||
|
||||
dictval.pushVal (op, str, offset + 1);
|
||||
|
@ -222,8 +214,7 @@ struct CFF2FontDictValues : DictValues<OpStr>
|
|||
inline void init (void)
|
||||
{
|
||||
DictValues<OpStr>::init ();
|
||||
privateDictSize = 0;
|
||||
privateDictOffset.set (0);
|
||||
privateDictInfo.init ();
|
||||
}
|
||||
|
||||
inline void fini (void)
|
||||
|
@ -231,27 +222,24 @@ struct CFF2FontDictValues : DictValues<OpStr>
|
|||
DictValues<OpStr>::fini ();
|
||||
}
|
||||
|
||||
unsigned int privateDictSize;
|
||||
LOffsetTo<PrivateDict> privateDictOffset;
|
||||
TableInfo privateDictInfo;
|
||||
};
|
||||
|
||||
struct CFF2FontDictOpSet
|
||||
{
|
||||
static inline bool process_op (const ByteStr& str, unsigned int& offset, OpCode op, Stack& stack, CFF2FontDictValues& dictval)
|
||||
static inline bool process_op (const ByteStr& str, unsigned int& offset,
|
||||
OpCode op, Stack& stack, CFF2FontDictValues& dictval)
|
||||
{
|
||||
switch (op) {
|
||||
case OpCode_Private:
|
||||
if (unlikely (!check_pop_offset (stack, dictval.privateDictOffset)))
|
||||
if (unlikely (!stack.check_pop_uint (dictval.privateDictInfo.offset)))
|
||||
return false;
|
||||
if (unlikely (!stack.check_pop_uint (dictval.privateDictSize)))
|
||||
if (unlikely (!stack.check_pop_uint (dictval.privateDictInfo.size)))
|
||||
return false;
|
||||
stack.clear ();
|
||||
break;
|
||||
case OpCode_longint: /* 5-byte integer */
|
||||
if (unlikely (!str.check_limit (offset, 5) || !stack.check_overflow (1)))
|
||||
return false;
|
||||
stack.push_int ((int32_t)((str[offset + 1] << 24) | ((uint32_t)str[offset + 2] << 16) | ((uint32_t)str[offset + 3] << 8) | str[offset + 4]));
|
||||
offset += 4;
|
||||
return true;
|
||||
return stack.push_longint_from_str (str, offset);
|
||||
case OpCode_BCD: /* real number */
|
||||
float v;
|
||||
if (unlikely (stack.check_overflow (1) || !parse_bcd (str, offset, v)))
|
||||
|
@ -276,8 +264,8 @@ struct CFF2PrivateDictValues_Base : DictValues<VAL>
|
|||
inline void init (void)
|
||||
{
|
||||
DictValues<VAL>::init ();
|
||||
subrsOffset.set (0);
|
||||
localSubrs = &Null(Subrs);
|
||||
subrsOffset = 0;
|
||||
localSubrs = &Null(CFF2Subrs);
|
||||
}
|
||||
|
||||
inline void fini (void)
|
||||
|
@ -296,8 +284,8 @@ struct CFF2PrivateDictValues_Base : DictValues<VAL>
|
|||
return size;
|
||||
}
|
||||
|
||||
LOffsetTo<Subrs> subrsOffset;
|
||||
const Subrs *localSubrs;
|
||||
unsigned int subrsOffset;
|
||||
const CFF2Subrs *localSubrs;
|
||||
};
|
||||
|
||||
typedef CFF2PrivateDictValues_Base<OpStr> CFF2PrivateDictValues_Subset;
|
||||
|
@ -305,12 +293,24 @@ typedef CFF2PrivateDictValues_Base<DictVal> CFF2PrivateDictValues;
|
|||
|
||||
struct CFF2PrivateDictOpSet
|
||||
{
|
||||
static inline bool process_op (const ByteStr& str, unsigned int& offset, OpCode op, Stack& stack, CFF2PrivateDictValues& dictval)
|
||||
static inline bool process_op (const ByteStr& str, unsigned int& offset,
|
||||
OpCode op, Stack& stack, CFF2PrivateDictValues& dictval)
|
||||
{
|
||||
DictVal val;
|
||||
val.init ();
|
||||
|
||||
switch (op) {
|
||||
case OpCode_StdHW:
|
||||
case OpCode_StdVW:
|
||||
case OpCode_BlueScale:
|
||||
case OpCode_BlueShift:
|
||||
case OpCode_BlueFuzz:
|
||||
case OpCode_ExpansionFactor:
|
||||
case OpCode_LanguageGroup:
|
||||
if (unlikely (!stack.check_pop_num (val.single_val)))
|
||||
return false;
|
||||
stack.clear ();
|
||||
break;
|
||||
case OpCode_BlueValues:
|
||||
case OpCode_OtherBlues:
|
||||
case OpCode_FamilyBlues:
|
||||
|
@ -319,33 +319,18 @@ struct CFF2PrivateDictOpSet
|
|||
case OpCode_StemSnapV:
|
||||
if (unlikely (!stack.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_ExpansionFactor:
|
||||
if (unlikely (!stack.check_pop_num (val.single_val)))
|
||||
return false;
|
||||
break;
|
||||
case OpCode_LanguageGroup:
|
||||
if (unlikely (!stack.check_pop_num (val.single_val)))
|
||||
return false;
|
||||
stack.clear ();
|
||||
break;
|
||||
case OpCode_Subrs:
|
||||
if (unlikely (!check_pop_offset (stack, dictval.subrsOffset)))
|
||||
if (unlikely (!stack.check_pop_uint (dictval.subrsOffset)))
|
||||
return false;
|
||||
stack.clear ();
|
||||
break;
|
||||
case OpCode_blend:
|
||||
// XXX: TODO
|
||||
return true;
|
||||
case OpCode_longint: /* 5-byte integer */
|
||||
if (unlikely (!str.check_limit (offset, 5) || !stack.check_overflow (1)))
|
||||
return false;
|
||||
stack.push_int ((int32_t)((str[offset + 1] << 24) | (str[offset + 2] << 16) || (str[offset + 3] << 8) || str[offset + 4]));
|
||||
offset += 4;
|
||||
return true;
|
||||
return stack.push_longint_from_str (str, offset);
|
||||
case OpCode_BCD: /* real number */
|
||||
float v;
|
||||
if (unlikely (!stack.check_overflow (1) || !parse_bcd (str, offset, v)))
|
||||
|
@ -364,7 +349,8 @@ struct CFF2PrivateDictOpSet
|
|||
|
||||
struct CFF2PrivateDictOpSet_Subset
|
||||
{
|
||||
static inline bool process_op (const ByteStr& str, unsigned int& offset, OpCode op, Stack& stack, CFF2PrivateDictValues_Subset& dictval)
|
||||
static inline bool process_op (const ByteStr& str, unsigned int& offset,
|
||||
OpCode op, Stack& stack, CFF2PrivateDictValues_Subset& dictval)
|
||||
{
|
||||
switch (op) {
|
||||
case OpCode_BlueValues:
|
||||
|
@ -394,15 +380,12 @@ struct CFF2PrivateDictOpSet_Subset
|
|||
}
|
||||
|
||||
case OpCode_Subrs:
|
||||
if (unlikely (!check_pop_offset (stack, dictval.subrsOffset)))
|
||||
if (unlikely (!stack.check_pop_uint (dictval.subrsOffset)))
|
||||
return false;
|
||||
stack.clear ();
|
||||
break;
|
||||
case OpCode_longint: /* 5-byte integer */
|
||||
if (unlikely (!str.check_limit (offset, 5) || !stack.check_overflow (1)))
|
||||
return false;
|
||||
stack.push_int ((int32_t)((str[offset + 1] << 24) | (str[offset + 2] << 16) || (str[offset + 3] << 8) || str[offset + 4]));
|
||||
offset += 4;
|
||||
return true;
|
||||
return stack.push_longint_from_str (str, offset);
|
||||
|
||||
default:
|
||||
return false;
|
||||
|
@ -439,6 +422,7 @@ struct cff2
|
|||
{
|
||||
inline void init (hb_face_t *face)
|
||||
{
|
||||
topDict.init ();
|
||||
fontDicts.init ();
|
||||
privateDicts.init ();
|
||||
|
||||
|
@ -451,43 +435,31 @@ struct cff2
|
|||
const OT::cff2 *cff2 = this->blob->template as<OT::cff2> ();
|
||||
|
||||
if (cff2 == &Null(OT::cff2))
|
||||
{
|
||||
fini ();
|
||||
return;
|
||||
}
|
||||
{ fini (); return; }
|
||||
|
||||
{ /* parse top dict */
|
||||
ByteStr topDictStr (cff2 + cff2->topDict, cff2->topDictSize);
|
||||
CFF2TopDict_Interpreter top_interp;
|
||||
if (unlikely (!topDictStr.sanitize (&sc) ||
|
||||
!top_interp.interpret (topDictStr, top)))
|
||||
{
|
||||
fini ();
|
||||
return;
|
||||
}
|
||||
!top_interp.interpret (topDictStr, topDict)))
|
||||
{ fini (); return; }
|
||||
}
|
||||
|
||||
globalSubrs = &StructAtOffset<Subrs> (cff2, cff2->topDict + cff2->topDictSize);
|
||||
varStore = &top.vstoreOffset (cff2);
|
||||
charStrings = &top.charStringsOffset (cff2);
|
||||
fdArray = &top.FDArrayOffset (cff2);
|
||||
fdSelect = &top.FDSelectOffset (cff2);
|
||||
globalSubrs = &StructAtOffset<CFF2Subrs> (cff2, cff2->topDict + cff2->topDictSize);
|
||||
varStore = &StructAtOffsetOrNull<CFF2VariationStore> (cff2, topDict.vstoreOffset);
|
||||
charStrings = &StructAtOffsetOrNull<CFF2CharStrings> (cff2, topDict.charStringsOffset);
|
||||
fdArray = &StructAtOffsetOrNull<CFF2FDArray> (cff2, topDict.FDArrayOffset);
|
||||
fdSelect = &StructAtOffsetOrNull<CFF2FDSelect> (cff2, topDict.FDSelectOffset);
|
||||
|
||||
if (((varStore != &Null(CFF2VariationStore)) && unlikely (!varStore->sanitize (&sc))) ||
|
||||
((charStrings == &Null(CharStrings)) || unlikely (!charStrings->sanitize (&sc))) ||
|
||||
((fdArray == &Null(FDArray)) || unlikely (!fdArray->sanitize (&sc))) ||
|
||||
((fdSelect != &Null(CFF2FDSelect)) && unlikely (!fdSelect->sanitize (&sc, fdArray->count))))
|
||||
{
|
||||
fini ();
|
||||
return;
|
||||
}
|
||||
(charStrings == &Null(CFF2CharStrings)) || unlikely (!charStrings->sanitize (&sc)) ||
|
||||
(fdArray == &Null(CFF2FDArray)) || unlikely (!fdArray->sanitize (&sc)) ||
|
||||
(((fdSelect != &Null(CFF2FDSelect)) && unlikely (!fdSelect->sanitize (&sc, fdArray->count)))))
|
||||
{ fini (); return; }
|
||||
|
||||
num_glyphs = charStrings->count;
|
||||
if (num_glyphs != sc.get_num_glyphs ())
|
||||
{
|
||||
fini ();
|
||||
return;
|
||||
}
|
||||
{ fini (); return; }
|
||||
|
||||
privateDicts.resize (fdArray->count);
|
||||
|
||||
|
@ -500,27 +472,18 @@ struct cff2
|
|||
font = fontDicts.push ();
|
||||
if (unlikely (!fontDictStr.sanitize (&sc) ||
|
||||
!font_interp.interpret (fontDictStr, *font)))
|
||||
{
|
||||
fini ();
|
||||
return;
|
||||
}
|
||||
{ fini (); return; }
|
||||
|
||||
const ByteStr privDictStr (font->privateDictOffset (cff2), font->privateDictSize);
|
||||
const ByteStr privDictStr (StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset), font->privateDictInfo.size);
|
||||
Interpreter<PrivOpSet, PrivDictVal> priv_interp;
|
||||
if (unlikely (!privDictStr.sanitize (&sc) ||
|
||||
!priv_interp.interpret (privDictStr, privateDicts[i])))
|
||||
{
|
||||
fini ();
|
||||
return;
|
||||
}
|
||||
{ fini (); return; }
|
||||
|
||||
privateDicts[i].localSubrs = &privateDicts[i].subrsOffset (privDictStr.str);
|
||||
if (privateDicts[i].localSubrs != &Null(Subrs) &&
|
||||
privateDicts[i].localSubrs = &StructAtOffsetOrNull<CFF2Subrs> (privDictStr.str, privateDicts[i].subrsOffset);
|
||||
if (privateDicts[i].localSubrs != &Null(CFF2Subrs) &&
|
||||
unlikely (!privateDicts[i].localSubrs->sanitize (&sc)))
|
||||
{
|
||||
fini ();
|
||||
return;
|
||||
}
|
||||
{ fini (); return; }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -550,11 +513,11 @@ struct cff2
|
|||
hb_sanitize_context_t sc;
|
||||
|
||||
public:
|
||||
CFF2TopDictValues top;
|
||||
const Subrs *globalSubrs;
|
||||
CFF2TopDictValues topDict;
|
||||
const CFF2Subrs *globalSubrs;
|
||||
const CFF2VariationStore *varStore;
|
||||
const CharStrings *charStrings;
|
||||
const FDArray *fdArray;
|
||||
const CFF2CharStrings *charStrings;
|
||||
const CFF2FDArray *fdArray;
|
||||
const CFF2FDSelect *fdSelect;
|
||||
|
||||
hb_vector_t<CFF2FontDictValues> fontDicts;
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#include "hb-ot-cmap-table.hh"
|
||||
#include "hb-ot-glyf-table.hh"
|
||||
#include "hb-ot-cff-table.hh"
|
||||
#include "hb-ot-cff2-table.hh"
|
||||
#include "hb-ot-hmtx-table.hh"
|
||||
#include "hb-ot-kern-table.hh"
|
||||
|
|
|
@ -41,7 +41,7 @@ using namespace CFF;
|
|||
bool
|
||||
hb_plan_subset_cff_fdselect (const hb_vector_t<hb_codepoint_t> &glyphs,
|
||||
unsigned int fdCount,
|
||||
const CFF2FDSelect &src, /* IN */
|
||||
const FDSelect &src, /* IN */
|
||||
unsigned int &subset_fd_count /* OUT */,
|
||||
unsigned int &subst_fdselect_size /* OUT */,
|
||||
unsigned int &subst_fdselect_format /* OUT */,
|
||||
|
@ -128,7 +128,7 @@ template <typename FDSELECT3_4>
|
|||
static inline bool
|
||||
serialize_fdselect_3_4 (hb_serialize_context_t *c,
|
||||
unsigned int num_glyphs,
|
||||
const CFF2FDSelect &src,
|
||||
const FDSelect &src,
|
||||
unsigned int size,
|
||||
const hb_vector_t<hb_codepoint_t> &first_glyphs,
|
||||
const hb_vector_t<hb_codepoint_t> &fdmap)
|
||||
|
@ -154,7 +154,7 @@ serialize_fdselect_3_4 (hb_serialize_context_t *c,
|
|||
bool
|
||||
hb_serialize_cff_fdselect (hb_serialize_context_t *c,
|
||||
const hb_vector_t<hb_codepoint_t> &glyphs,
|
||||
const CFF2FDSelect &src,
|
||||
const FDSelect &src,
|
||||
unsigned int fd_count,
|
||||
unsigned int fdselect_format,
|
||||
unsigned int size,
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
HB_INTERNAL bool
|
||||
hb_plan_subset_cff_fdselect (const hb_vector_t<hb_codepoint_t> &glyphs,
|
||||
unsigned int fdCount,
|
||||
const CFF::CFF2FDSelect &src, /* IN */
|
||||
const CFF::FDSelect &src, /* IN */
|
||||
unsigned int &subset_fd_count /* OUT */,
|
||||
unsigned int &subst_fdselect_size /* OUT */,
|
||||
unsigned int &subst_fdselect_format /* OUT */,
|
||||
|
@ -44,7 +44,7 @@ hb_plan_subset_cff_fdselect (const hb_vector_t<hb_codepoint_t> &glyphs,
|
|||
HB_INTERNAL bool
|
||||
hb_serialize_cff_fdselect (hb_serialize_context_t *c,
|
||||
const hb_vector_t<hb_codepoint_t> &glyphs,
|
||||
const CFF::CFF2FDSelect &src,
|
||||
const CFF::FDSelect &src,
|
||||
unsigned int fd_count,
|
||||
unsigned int fdselect_format,
|
||||
unsigned int size,
|
||||
|
|
|
@ -0,0 +1,560 @@
|
|||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "hb-open-type-private.hh"
|
||||
#include "hb-ot-cff-table.hh"
|
||||
#include "hb-set.h"
|
||||
#include "hb-subset-cff.hh"
|
||||
#include "hb-subset-plan.hh"
|
||||
#include "hb-subset-cff-common-private.hh"
|
||||
|
||||
using namespace CFF;
|
||||
|
||||
struct CFFSubTableOffsets {
|
||||
inline CFFSubTableOffsets (void)
|
||||
{
|
||||
memset (this, 0, sizeof(*this));
|
||||
}
|
||||
|
||||
unsigned int nameIndexOffset;
|
||||
unsigned int topDictOffset;
|
||||
unsigned int topDictOffSize;
|
||||
unsigned int stringIndexOffset;
|
||||
unsigned int globalSubrsOffset;
|
||||
unsigned int encodingOffset;
|
||||
unsigned int charsetOffset;
|
||||
TableInfo FDSelectInfo;
|
||||
unsigned int FDArrayOffset;
|
||||
unsigned int FDArrayOffSize;
|
||||
unsigned int charStringsOffset;
|
||||
unsigned int charStringsOffSize;
|
||||
TableInfo privateDictInfo;
|
||||
};
|
||||
|
||||
struct CFFTopDict_OpSerializer : OpSerializer
|
||||
{
|
||||
inline bool serialize (hb_serialize_context_t *c,
|
||||
const OpStr &opstr,
|
||||
const CFFSubTableOffsets &offsets) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
||||
switch (opstr.op)
|
||||
{
|
||||
case OpCode_charset:
|
||||
return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.charsetOffset));
|
||||
|
||||
case OpCode_Encoding:
|
||||
return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.encodingOffset));
|
||||
|
||||
case OpCode_CharStrings:
|
||||
return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.charStringsOffset));
|
||||
|
||||
case OpCode_FDArray:
|
||||
return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDArrayOffset));
|
||||
|
||||
case OpCode_FDSelect:
|
||||
return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDSelectInfo.offset));
|
||||
|
||||
case OpCode_Private:
|
||||
{
|
||||
if (unlikely (!UnsizedByteStr::serialize_int2 (c, offsets.privateDictInfo.size)))
|
||||
return_trace (false);
|
||||
if (unlikely (!UnsizedByteStr::serialize_int4 (c, offsets.privateDictInfo.offset)))
|
||||
return_trace (false);
|
||||
HBUINT8 *p = c->allocate_size<HBUINT8> (1);
|
||||
if (unlikely (p == nullptr)) return_trace (false);
|
||||
p->set (OpCode_Private);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return_trace (copy_opstr (c, opstr));
|
||||
}
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
inline unsigned int calculate_serialized_size (const OpStr &opstr) const
|
||||
{
|
||||
switch (opstr.op)
|
||||
{
|
||||
case OpCode_charset:
|
||||
case OpCode_Encoding:
|
||||
case OpCode_CharStrings:
|
||||
case OpCode_FDArray:
|
||||
case OpCode_FDSelect:
|
||||
return OpCode_Size (OpCode_longint) + 4 + OpCode_Size (opstr.op);
|
||||
|
||||
case OpCode_Private:
|
||||
return OpCode_Size (OpCode_longint) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private);
|
||||
|
||||
default:
|
||||
return opstr.str.len;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct CFFFontDict_OpSerializer : OpSerializer
|
||||
{
|
||||
inline bool serialize (hb_serialize_context_t *c,
|
||||
const OpStr &opstr,
|
||||
const TableInfo &privateDictInfo) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
||||
if (opstr.op == OpCode_Private)
|
||||
{
|
||||
/* serialize the private dict size as a 2-byte integer */
|
||||
if (unlikely (!UnsizedByteStr::serialize_int2 (c, privateDictInfo.size)))
|
||||
return_trace (false);
|
||||
|
||||
/* serialize the private dict offset as a 4-byte integer */
|
||||
if (unlikely (!UnsizedByteStr::serialize_int4 (c, privateDictInfo.offset)))
|
||||
return_trace (false);
|
||||
|
||||
/* serialize the opcode */
|
||||
HBUINT8 *p = c->allocate_size<HBUINT8> (1);
|
||||
if (unlikely (p == nullptr)) return_trace (false);
|
||||
p->set (OpCode_Private);
|
||||
|
||||
return_trace (true);
|
||||
}
|
||||
else
|
||||
{
|
||||
HBUINT8 *d = c->allocate_size<HBUINT8> (opstr.str.len);
|
||||
if (unlikely (d == nullptr)) return_trace (false);
|
||||
memcpy (d, &opstr.str.str[0], opstr.str.len);
|
||||
}
|
||||
return_trace (true);
|
||||
}
|
||||
|
||||
inline unsigned int calculate_serialized_size (const OpStr &opstr) const
|
||||
{
|
||||
if (opstr.op == OpCode_Private)
|
||||
return OpCode_Size (OpCode_longint) + 4 + OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Private);
|
||||
else
|
||||
return opstr.str.len;
|
||||
}
|
||||
};
|
||||
|
||||
struct CFFPrivateDict_OpSerializer : OpSerializer
|
||||
{
|
||||
inline bool serialize (hb_serialize_context_t *c,
|
||||
const OpStr &opstr,
|
||||
const unsigned int subrsOffset) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
||||
if (opstr.op == OpCode_Subrs)
|
||||
return_trace (FontDict::serialize_offset2_op(c, OpCode_Subrs, subrsOffset));
|
||||
else
|
||||
return_trace (copy_opstr (c, opstr));
|
||||
}
|
||||
|
||||
inline unsigned int calculate_serialized_size (const OpStr &opstr) const
|
||||
{
|
||||
if (opstr.op == OpCode_Subrs)
|
||||
return OpCode_Size (OpCode_shortint) + 2 + OpCode_Size (OpCode_Subrs);
|
||||
else
|
||||
return opstr.str.len;
|
||||
}
|
||||
};
|
||||
|
||||
struct cff_subset_plan {
|
||||
inline cff_subset_plan (void)
|
||||
: final_size (0),
|
||||
orig_fdcount (0),
|
||||
subst_fdcount(1),
|
||||
subst_fdselect_format (0)
|
||||
{
|
||||
topdict_sizes.init ();
|
||||
topdict_sizes.resize (1);
|
||||
subst_fdselect_first_glyphs.init ();
|
||||
fdmap.init ();
|
||||
subset_charstrings.init ();
|
||||
privateDictInfos.init ();
|
||||
}
|
||||
|
||||
inline ~cff_subset_plan (void)
|
||||
{
|
||||
topdict_sizes.fini ();
|
||||
subst_fdselect_first_glyphs.fini ();
|
||||
fdmap.fini ();
|
||||
subset_charstrings.fini ();
|
||||
privateDictInfos.fini ();
|
||||
}
|
||||
|
||||
inline bool create (const OT::cff::accelerator_subset_t &acc,
|
||||
hb_subset_plan_t *plan)
|
||||
{
|
||||
final_size = 0;
|
||||
orig_fdcount = acc.fdCount;
|
||||
|
||||
/* CFF header */
|
||||
final_size += OT::cff::static_size;
|
||||
|
||||
/* Name INDEX */
|
||||
offsets.nameIndexOffset = final_size;
|
||||
final_size += acc.nameIndex->get_size ();
|
||||
|
||||
/* top dict INDEX */
|
||||
{
|
||||
offsets.topDictOffset = final_size;
|
||||
CFFTopDict_OpSerializer topSzr;
|
||||
unsigned int topDictSize = TopDict::calculate_serialized_size (acc.topDicts[0], topSzr);
|
||||
offsets.topDictOffSize = calcOffSize(topDictSize);
|
||||
final_size += CFFIndexOf<TopDict>::calculate_serialized_size<CFFTopDictValues> (offsets.topDictOffSize, acc.topDicts, topdict_sizes, topSzr);
|
||||
}
|
||||
|
||||
/* String INDEX */
|
||||
offsets.stringIndexOffset = final_size;
|
||||
final_size += acc.stringIndex->get_size ();
|
||||
|
||||
/* global subrs */
|
||||
offsets.globalSubrsOffset = final_size;
|
||||
final_size += acc.globalSubrs->get_size ();
|
||||
|
||||
/* Encoding */
|
||||
offsets.encodingOffset = final_size;
|
||||
if (acc.encoding != &Null(Encoding))
|
||||
final_size += acc.encoding->get_size ();
|
||||
|
||||
/* Charset */
|
||||
offsets.charsetOffset = final_size;
|
||||
if (acc.charset != &Null(Charset))
|
||||
final_size += acc.charset->get_size (acc.num_glyphs);
|
||||
|
||||
/* FDSelect */
|
||||
if (acc.fdSelect != &Null(CFFFDSelect))
|
||||
{
|
||||
offsets.FDSelectInfo.offset = final_size;
|
||||
if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs,
|
||||
orig_fdcount,
|
||||
*acc.fdSelect,
|
||||
subst_fdcount,
|
||||
offsets.FDSelectInfo.size,
|
||||
subst_fdselect_format,
|
||||
subst_fdselect_first_glyphs,
|
||||
fdmap)))
|
||||
return false;
|
||||
|
||||
if (!is_fds_subsetted ())
|
||||
offsets.FDSelectInfo.size = acc.fdSelect->calculate_serialized_size (acc.num_glyphs);
|
||||
final_size += offsets.FDSelectInfo.size;
|
||||
}
|
||||
|
||||
/* FDArray (FDIndex) */
|
||||
if (acc.fdArray != &Null(CFFFDArray)) {
|
||||
offsets.FDArrayOffset = final_size;
|
||||
CFFFontDict_OpSerializer fontSzr;
|
||||
final_size += CFFFDArray::calculate_serialized_size(offsets.FDArrayOffSize/*OUT*/, acc.fontDicts, subst_fdcount, fdmap, fontSzr);
|
||||
}
|
||||
|
||||
/* CharStrings */
|
||||
{
|
||||
offsets.charStringsOffset = final_size;
|
||||
unsigned int dataSize = 0;
|
||||
for (unsigned int i = 0; i < plan->glyphs.len; i++)
|
||||
{
|
||||
const ByteStr str = (*acc.charStrings)[plan->glyphs[i]];
|
||||
subset_charstrings.push (str);
|
||||
dataSize += str.len;
|
||||
}
|
||||
offsets.charStringsOffSize = calcOffSize (dataSize + 1);
|
||||
final_size += CFFCharStrings::calculate_serialized_size (offsets.charStringsOffSize, plan->glyphs.len, dataSize);
|
||||
}
|
||||
|
||||
/* private dicts & local subrs */
|
||||
offsets.privateDictInfo.offset = final_size;
|
||||
for (unsigned int i = 0; i < orig_fdcount; i++)
|
||||
{
|
||||
CFFPrivateDict_OpSerializer privSzr;
|
||||
TableInfo privInfo = { final_size, PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr) };
|
||||
privateDictInfos.push (privInfo);
|
||||
final_size += privInfo.size + acc.privateDicts[i].localSubrs->get_size ();
|
||||
}
|
||||
|
||||
if (!acc.is_CID ())
|
||||
offsets.privateDictInfo = privateDictInfos[0];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline unsigned int get_final_size (void) const { return final_size; }
|
||||
|
||||
unsigned int final_size;
|
||||
hb_vector_t<unsigned int> topdict_sizes;
|
||||
CFFSubTableOffsets offsets;
|
||||
|
||||
unsigned int orig_fdcount;
|
||||
unsigned int subst_fdcount;
|
||||
inline bool is_fds_subsetted (void) const { return subst_fdcount < orig_fdcount; }
|
||||
unsigned int subst_fdselect_format;
|
||||
hb_vector_t<hb_codepoint_t> subst_fdselect_first_glyphs;
|
||||
|
||||
/* font dict index remap table from fullset FDArray to subset FDArray.
|
||||
* set to HB_SET_VALUE_INVALID if excluded from subset */
|
||||
hb_vector_t<hb_codepoint_t> fdmap;
|
||||
|
||||
hb_vector_t<ByteStr> subset_charstrings;
|
||||
hb_vector_t<TableInfo> privateDictInfos;
|
||||
};
|
||||
|
||||
static inline bool _write_cff (const cff_subset_plan &plan,
|
||||
const OT::cff::accelerator_subset_t &acc,
|
||||
const hb_vector_t<hb_codepoint_t>& glyphs,
|
||||
unsigned int dest_sz,
|
||||
void *dest)
|
||||
{
|
||||
hb_serialize_context_t c (dest, dest_sz);
|
||||
|
||||
OT::cff *cff = c.start_serialize<OT::cff> ();
|
||||
if (unlikely (!c.extend_min (*cff)))
|
||||
return false;
|
||||
|
||||
/* header */
|
||||
cff->version.major.set (0x01);
|
||||
cff->version.minor.set (0x00);
|
||||
cff->nameIndex.set (cff->min_size);
|
||||
cff->offSize.set (4); /* unused? */
|
||||
|
||||
/* name INDEX */
|
||||
{
|
||||
assert (cff->nameIndex == c.head - c.start);
|
||||
NameIndex *dest = c.start_embed<NameIndex> ();
|
||||
if (unlikely (dest == nullptr)) return false;
|
||||
if (unlikely (!dest->serialize (&c, *acc.nameIndex)))
|
||||
{
|
||||
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF name INDEX");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* top dict INDEX */
|
||||
{
|
||||
assert (plan.offsets.topDictOffset == c.head - c.start);
|
||||
CFFIndexOf<TopDict> *dest = c.start_embed< CFFIndexOf<TopDict> > ();
|
||||
if (dest == nullptr) return false;
|
||||
CFFTopDict_OpSerializer topSzr;
|
||||
if (unlikely (!dest->serialize (&c, plan.offsets.topDictOffSize, acc.topDicts, plan.topdict_sizes, topSzr, plan.offsets)))
|
||||
{
|
||||
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF top dict");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* String INDEX */
|
||||
{
|
||||
assert (plan.offsets.stringIndexOffset == c.head - c.start);
|
||||
StringIndex *dest = c.start_embed<StringIndex> ();
|
||||
if (unlikely (dest == nullptr)) return false;
|
||||
if (unlikely (!dest->serialize (&c, *acc.stringIndex)))
|
||||
{
|
||||
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF string INDEX");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* global subrs */
|
||||
{
|
||||
assert (plan.offsets.globalSubrsOffset == c.head - c.start);
|
||||
CFFSubrs *dest = c.start_embed<CFFSubrs> ();
|
||||
if (unlikely (dest == nullptr)) return false;
|
||||
if (unlikely (!dest->serialize (&c, *acc.globalSubrs)))
|
||||
{
|
||||
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF global subrs");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Encoding */
|
||||
if (acc.encoding != &Null(Encoding)){
|
||||
assert (plan.offsets.encodingOffset == c.head - c.start);
|
||||
Encoding *dest = c.start_embed<Encoding> ();
|
||||
if (unlikely (dest == nullptr)) return false;
|
||||
if (unlikely (!dest->serialize (&c, *acc.encoding, acc.num_glyphs))) // XXX: TODO
|
||||
{
|
||||
DEBUG_MSG (SUBSET, nullptr, "failed to serialize Encoding");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Charset */
|
||||
if (acc.charset != &Null(Charset))
|
||||
{
|
||||
assert (plan.offsets.charsetOffset == c.head - c.start);
|
||||
Charset *dest = c.start_embed<Charset> ();
|
||||
if (unlikely (dest == nullptr)) return false;
|
||||
if (unlikely (!dest->serialize (&c, *acc.charset, acc.num_glyphs))) // XXX: TODO
|
||||
{
|
||||
DEBUG_MSG (SUBSET, nullptr, "failed to serialize Charset");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* FDSelect */
|
||||
if (acc.fdSelect != &Null(CFFFDSelect))
|
||||
{
|
||||
assert (plan.offsets.FDSelectInfo.offset == c.head - c.start);
|
||||
|
||||
if (plan.is_fds_subsetted ())
|
||||
{
|
||||
if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs, *acc.fdSelect, acc.fdCount,
|
||||
plan.subst_fdselect_format, plan.offsets.FDSelectInfo.size,
|
||||
plan.subst_fdselect_first_glyphs,
|
||||
plan.fdmap)))
|
||||
{
|
||||
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF subset FDSelect");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CFFFDSelect *dest = c.start_embed<CFFFDSelect> ();
|
||||
if (unlikely (!dest->serialize (&c, *acc.fdSelect, acc.num_glyphs)))
|
||||
{
|
||||
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF FDSelect");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* FDArray (FD Index) */
|
||||
if (acc.fdArray != &Null(CFFFDArray))
|
||||
{
|
||||
assert (plan.offsets.FDArrayOffset == c.head - c.start);
|
||||
CFFFDArray *fda = c.start_embed<CFFFDArray> ();
|
||||
if (unlikely (fda == nullptr)) return false;
|
||||
CFFFontDict_OpSerializer fontSzr;
|
||||
if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayOffSize,
|
||||
acc.fontDicts, plan.subst_fdcount, plan.fdmap,
|
||||
fontSzr, plan.privateDictInfos)))
|
||||
{
|
||||
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF FDArray");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* CharStrings */
|
||||
{
|
||||
assert (plan.offsets.charStringsOffset == c.head - c.start);
|
||||
CFFCharStrings *cs = c.start_embed<CFFCharStrings> ();
|
||||
if (unlikely (cs == nullptr)) return false;
|
||||
if (unlikely (!cs->serialize (&c, plan.offsets.charStringsOffSize, plan.subset_charstrings)))
|
||||
{
|
||||
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF CharStrings");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* private dicts & local subrs */
|
||||
assert (plan.offsets.privateDictInfo.offset == c.head - c.start);
|
||||
for (unsigned int i = 0; i < acc.privateDicts.len; i++)
|
||||
{
|
||||
PrivateDict *pd = c.start_embed<PrivateDict> ();
|
||||
if (unlikely (pd == nullptr)) return false;
|
||||
CFFPrivateDict_OpSerializer privSzr;
|
||||
/* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */
|
||||
if (unlikely (!pd->serialize (&c, acc.privateDicts[i], privSzr, plan.privateDictInfos[i].size)))
|
||||
{
|
||||
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF Private Dict[%d]", i);
|
||||
return false;
|
||||
}
|
||||
if (acc.privateDicts[i].subrsOffset != 0)
|
||||
{
|
||||
CFFSubrs *subrs = c.start_embed<CFFSubrs> ();
|
||||
if (unlikely (subrs == nullptr) || acc.privateDicts[i].localSubrs == &Null(CFFSubrs))
|
||||
{
|
||||
DEBUG_MSG (SUBSET, nullptr, "CFF subset: local subrs unexpectedly null [%d]", i);
|
||||
return false;
|
||||
}
|
||||
if (unlikely (!subrs->serialize (&c, *acc.privateDicts[i].localSubrs)))
|
||||
{
|
||||
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF local subrs [%d]", i);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
c.end_serialize ();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_hb_subset_cff (const OT::cff::accelerator_subset_t &acc,
|
||||
const char *data,
|
||||
hb_subset_plan_t *plan,
|
||||
hb_blob_t **prime /* OUT */)
|
||||
{
|
||||
cff_subset_plan cff_plan;
|
||||
|
||||
if (unlikely (!cff_plan.create (acc, plan)))
|
||||
{
|
||||
DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff subsetting plan.");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int cff_prime_size = cff_plan.get_final_size ();
|
||||
char *cff_prime_data = (char *) calloc (1, cff_prime_size);
|
||||
|
||||
if (unlikely (!_write_cff (cff_plan, acc, plan->glyphs,
|
||||
cff_prime_size, cff_prime_data))) {
|
||||
DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff.");
|
||||
free (cff_prime_data);
|
||||
return false;
|
||||
}
|
||||
|
||||
*prime = hb_blob_create (cff_prime_data,
|
||||
cff_prime_size,
|
||||
HB_MEMORY_MODE_READONLY,
|
||||
cff_prime_data,
|
||||
free);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_subset_cff:
|
||||
* Subsets the CFF table according to a provided plan.
|
||||
*
|
||||
* Return value: subsetted cff table.
|
||||
**/
|
||||
bool
|
||||
hb_subset_cff (hb_subset_plan_t *plan,
|
||||
hb_blob_t **prime /* OUT */)
|
||||
{
|
||||
hb_blob_t *cff_blob = hb_sanitize_context_t().reference_table<CFF::cff> (plan->source);
|
||||
const char *data = hb_blob_get_data(cff_blob, nullptr);
|
||||
|
||||
OT::cff::accelerator_subset_t acc;
|
||||
acc.init(plan->source);
|
||||
bool result = likely (acc.is_valid ()) &&
|
||||
_hb_subset_cff (acc, data, plan, prime);
|
||||
hb_blob_destroy (cff_blob);
|
||||
acc.fini ();
|
||||
|
||||
return result;
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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_SUBSET_CFF_HH
|
||||
#define HB_SUBSET_CFF_HH
|
||||
|
||||
#include "hb-private.hh"
|
||||
|
||||
#include "hb-subset-plan.hh"
|
||||
|
||||
HB_INTERNAL bool
|
||||
hb_subset_cff (hb_subset_plan_t *plan,
|
||||
hb_blob_t **cff_prime /* OUT */);
|
||||
|
||||
#endif /* HB_SUBSET_CFF_HH */
|
|
@ -33,11 +33,27 @@
|
|||
|
||||
using namespace CFF;
|
||||
|
||||
struct CFF2SubTableOffsets {
|
||||
inline CFF2SubTableOffsets (void)
|
||||
{
|
||||
memset (this, 0, sizeof(*this));
|
||||
}
|
||||
|
||||
unsigned int topDictSize;
|
||||
unsigned int varStoreOffset;
|
||||
TableInfo FDSelectInfo;
|
||||
unsigned int FDArrayOffset;
|
||||
unsigned int FDArrayOffSize;
|
||||
unsigned int charStringsOffset;
|
||||
unsigned int charStringsOffSize;
|
||||
unsigned int privateDictsOffset;
|
||||
};
|
||||
|
||||
struct CFF2TopDict_OpSerializer : OpSerializer
|
||||
{
|
||||
inline bool serialize (hb_serialize_context_t *c,
|
||||
const OpStr &opstr,
|
||||
const SubTableOffsets &offsets) const
|
||||
const CFF2SubTableOffsets &offsets) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
||||
|
@ -53,7 +69,7 @@ struct CFF2TopDict_OpSerializer : OpSerializer
|
|||
return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDArrayOffset));
|
||||
|
||||
case OpCode_FDSelect:
|
||||
return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDSelectOffset));
|
||||
return_trace (FontDict::serialize_offset4_op(c, opstr.op, offsets.FDSelectInfo.offset));
|
||||
|
||||
default:
|
||||
return_trace (copy_opstr (c, opstr));
|
||||
|
@ -81,18 +97,18 @@ struct CFF2FontDict_OpSerializer : OpSerializer
|
|||
{
|
||||
inline bool serialize (hb_serialize_context_t *c,
|
||||
const OpStr &opstr,
|
||||
const offset_size_pair& privOffSize) const
|
||||
const TableInfo& privDictInfo) const
|
||||
{
|
||||
TRACE_SERIALIZE (this);
|
||||
|
||||
if (opstr.op == OpCode_Private)
|
||||
{
|
||||
/* serialize the private dict size as a 2-byte integer */
|
||||
if (unlikely (!UnsizedByteStr::serialize_int2 (c, privOffSize.size)))
|
||||
if (unlikely (!UnsizedByteStr::serialize_int2 (c, privDictInfo.size)))
|
||||
return_trace (false);
|
||||
|
||||
/* serialize the private dict offset as a 4-byte integer */
|
||||
if (unlikely (!UnsizedByteStr::serialize_int4 (c, privOffSize.offset)))
|
||||
if (unlikely (!UnsizedByteStr::serialize_int4 (c, privDictInfo.offset)))
|
||||
return_trace (false);
|
||||
|
||||
/* serialize the opcode */
|
||||
|
@ -143,8 +159,8 @@ struct CFF2PrivateDict_OpSerializer : OpSerializer
|
|||
}
|
||||
};
|
||||
|
||||
struct subset_plan {
|
||||
inline subset_plan (void)
|
||||
struct cff2_subset_plan {
|
||||
inline cff2_subset_plan (void)
|
||||
: final_size (0),
|
||||
orig_fdcount (0),
|
||||
subst_fdcount(1),
|
||||
|
@ -153,15 +169,15 @@ struct subset_plan {
|
|||
subst_fdselect_first_glyphs.init ();
|
||||
fdmap.init ();
|
||||
subset_charstrings.init ();
|
||||
private_off_and_size_pairs.init ();
|
||||
privateDictInfos.init ();
|
||||
}
|
||||
|
||||
inline ~subset_plan (void)
|
||||
inline ~cff2_subset_plan (void)
|
||||
{
|
||||
subst_fdselect_first_glyphs.fini ();
|
||||
fdmap.fini ();
|
||||
subset_charstrings.fini ();
|
||||
private_off_and_size_pairs.fini ();
|
||||
privateDictInfos.fini ();
|
||||
}
|
||||
|
||||
inline bool create (const OT::cff2::accelerator_subset_t &acc,
|
||||
|
@ -176,7 +192,7 @@ struct subset_plan {
|
|||
/* top dict */
|
||||
{
|
||||
CFF2TopDict_OpSerializer topSzr;
|
||||
offsets.topDictSize = TopDict::calculate_serialized_size (acc.top, topSzr);
|
||||
offsets.topDictSize = TopDict::calculate_serialized_size (acc.topDict, topSzr);
|
||||
final_size += offsets.topDictSize;
|
||||
}
|
||||
|
||||
|
@ -193,27 +209,27 @@ struct subset_plan {
|
|||
/* FDSelect */
|
||||
if (acc.fdSelect != &Null(CFF2FDSelect))
|
||||
{
|
||||
offsets.FDSelectOffset = final_size;
|
||||
offsets.FDSelectInfo.offset = final_size;
|
||||
if (unlikely (!hb_plan_subset_cff_fdselect (plan->glyphs,
|
||||
orig_fdcount,
|
||||
*acc.fdSelect,
|
||||
*(const FDSelect *)acc.fdSelect,
|
||||
subst_fdcount,
|
||||
offsets.FDSelectSize,
|
||||
offsets.FDSelectInfo.size,
|
||||
subst_fdselect_format,
|
||||
subst_fdselect_first_glyphs,
|
||||
fdmap)))
|
||||
return false;
|
||||
|
||||
if (!is_fds_subsetted ())
|
||||
offsets.FDSelectSize = acc.fdSelect->calculate_serialized_size (acc.num_glyphs);
|
||||
final_size += offsets.FDSelectSize;
|
||||
offsets.FDSelectInfo.size = acc.fdSelect->calculate_serialized_size (acc.num_glyphs);
|
||||
final_size += offsets.FDSelectInfo.size;
|
||||
}
|
||||
|
||||
/* FDArray (FDIndex) */
|
||||
{
|
||||
offsets.FDArrayOffset = final_size;
|
||||
CFF2FontDict_OpSerializer fontSzr;
|
||||
final_size += FDArray::calculate_serialized_size(offsets.FDArrayOffSize/*OUT*/, acc.fontDicts, subst_fdcount, fdmap, fontSzr);
|
||||
final_size += CFF2FDArray::calculate_serialized_size(offsets.FDArrayOffSize/*OUT*/, acc.fontDicts, subst_fdcount, fdmap, fontSzr);
|
||||
}
|
||||
|
||||
/* CharStrings */
|
||||
|
@ -227,7 +243,7 @@ struct subset_plan {
|
|||
dataSize += str.len;
|
||||
}
|
||||
offsets.charStringsOffSize = calcOffSize (dataSize + 1);
|
||||
final_size += CharStrings::calculate_serialized_size (offsets.charStringsOffSize, plan->glyphs.len, dataSize);
|
||||
final_size += CFF2CharStrings::calculate_serialized_size (offsets.charStringsOffSize, plan->glyphs.len, dataSize);
|
||||
}
|
||||
|
||||
/* private dicts & local subrs */
|
||||
|
@ -235,10 +251,9 @@ struct subset_plan {
|
|||
for (unsigned int i = 0; i < orig_fdcount; i++)
|
||||
{
|
||||
CFF2PrivateDict_OpSerializer privSzr;
|
||||
unsigned int private_size = PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr);
|
||||
offset_size_pair pair = { final_size, private_size };
|
||||
private_off_and_size_pairs.push (pair);
|
||||
final_size += private_size + acc.privateDicts[i].localSubrs->get_size ();
|
||||
TableInfo privInfo = { final_size, PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr) };
|
||||
privateDictInfos.push (privInfo);
|
||||
final_size += privInfo.size + acc.privateDicts[i].localSubrs->get_size ();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -246,8 +261,8 @@ struct subset_plan {
|
|||
|
||||
inline unsigned int get_final_size (void) const { return final_size; }
|
||||
|
||||
unsigned int final_size;
|
||||
SubTableOffsets offsets;
|
||||
unsigned int final_size;
|
||||
CFF2SubTableOffsets offsets;
|
||||
|
||||
unsigned int orig_fdcount;
|
||||
unsigned int subst_fdcount;
|
||||
|
@ -260,10 +275,10 @@ struct subset_plan {
|
|||
hb_vector_t<hb_codepoint_t> fdmap;
|
||||
|
||||
hb_vector_t<ByteStr> subset_charstrings;
|
||||
hb_vector_t<offset_size_pair> private_off_and_size_pairs;
|
||||
hb_vector_t<TableInfo> privateDictInfos;
|
||||
};
|
||||
|
||||
static inline bool _write_cff2 (const subset_plan &plan,
|
||||
static inline bool _write_cff2 (const cff2_subset_plan &plan,
|
||||
const OT::cff2::accelerator_subset_t &acc,
|
||||
const hb_vector_t<hb_codepoint_t>& glyphs,
|
||||
unsigned int dest_sz,
|
||||
|
@ -286,7 +301,7 @@ static inline bool _write_cff2 (const subset_plan &plan,
|
|||
cff2->topDictSize.set (plan.offsets.topDictSize);
|
||||
TopDict &dict = cff2 + cff2->topDict;
|
||||
CFF2TopDict_OpSerializer topSzr;
|
||||
if (unlikely (!dict.serialize (&c, acc.top, topSzr, plan.offsets)))
|
||||
if (unlikely (!dict.serialize (&c, acc.topDict, topSzr, plan.offsets)))
|
||||
{
|
||||
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 top dict");
|
||||
return false;
|
||||
|
@ -296,7 +311,7 @@ static inline bool _write_cff2 (const subset_plan &plan,
|
|||
/* global subrs */
|
||||
{
|
||||
assert (cff2->topDict + plan.offsets.topDictSize == c.head - c.start);
|
||||
Subrs *dest = c.start_embed<Subrs> ();
|
||||
CFF2Subrs *dest = c.start_embed<CFF2Subrs> ();
|
||||
if (unlikely (dest == nullptr)) return false;
|
||||
if (unlikely (!dest->serialize (&c, *acc.globalSubrs)))
|
||||
{
|
||||
|
@ -320,12 +335,12 @@ static inline bool _write_cff2 (const subset_plan &plan,
|
|||
/* FDSelect */
|
||||
if (acc.fdSelect != &Null(CFF2FDSelect))
|
||||
{
|
||||
assert (plan.offsets.FDSelectOffset == c.head - c.start);
|
||||
assert (plan.offsets.FDSelectInfo.offset == c.head - c.start);
|
||||
|
||||
if (plan.is_fds_subsetted ())
|
||||
{
|
||||
if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs, *acc.fdSelect, acc.fdArray->count,
|
||||
plan.subst_fdselect_format, plan.offsets.FDSelectSize,
|
||||
if (unlikely (!hb_serialize_cff_fdselect (&c, glyphs, *(const FDSelect *)acc.fdSelect, acc.fdArray->count,
|
||||
plan.subst_fdselect_format, plan.offsets.FDSelectInfo.size,
|
||||
plan.subst_fdselect_first_glyphs,
|
||||
plan.fdmap)))
|
||||
{
|
||||
|
@ -347,12 +362,12 @@ static inline bool _write_cff2 (const subset_plan &plan,
|
|||
/* FDArray (FD Index) */
|
||||
{
|
||||
assert (plan.offsets.FDArrayOffset == c.head - c.start);
|
||||
FDArray *fda = c.start_embed<FDArray> ();
|
||||
CFF2FDArray *fda = c.start_embed<CFF2FDArray> ();
|
||||
if (unlikely (fda == nullptr)) return false;
|
||||
CFF2FontDict_OpSerializer fontSzr;
|
||||
if (unlikely (!fda->serialize (&c, plan.offsets.FDArrayOffSize,
|
||||
acc.fontDicts, plan.subst_fdcount, plan.fdmap,
|
||||
fontSzr, plan.private_off_and_size_pairs)))
|
||||
fontSzr, plan.privateDictInfos)))
|
||||
{
|
||||
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 FDArray");
|
||||
return false;
|
||||
|
@ -362,7 +377,7 @@ static inline bool _write_cff2 (const subset_plan &plan,
|
|||
/* CharStrings */
|
||||
{
|
||||
assert (plan.offsets.charStringsOffset == c.head - c.start);
|
||||
CharStrings *cs = c.start_embed<CharStrings> ();
|
||||
CFF2CharStrings *cs = c.start_embed<CFF2CharStrings> ();
|
||||
if (unlikely (cs == nullptr)) return false;
|
||||
if (unlikely (!cs->serialize (&c, plan.offsets.charStringsOffSize, plan.subset_charstrings)))
|
||||
{
|
||||
|
@ -379,15 +394,15 @@ static inline bool _write_cff2 (const subset_plan &plan,
|
|||
if (unlikely (pd == nullptr)) return false;
|
||||
CFF2PrivateDict_OpSerializer privSzr;
|
||||
/* N.B. local subrs immediately follows its corresponding private dict. i.e., subr offset == private dict size */
|
||||
if (unlikely (!pd->serialize (&c, acc.privateDicts[i], privSzr, plan.private_off_and_size_pairs[i].size)))
|
||||
if (unlikely (!pd->serialize (&c, acc.privateDicts[i], privSzr, plan.privateDictInfos[i].size)))
|
||||
{
|
||||
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 Private Dict[%d]", i);
|
||||
return false;
|
||||
}
|
||||
if (acc.privateDicts[i].subrsOffset != 0)
|
||||
{
|
||||
Subrs *subrs = c.start_embed<Subrs> ();
|
||||
if (unlikely (subrs == nullptr) || acc.privateDicts[i].localSubrs == &Null(Subrs))
|
||||
CFF2Subrs *subrs = c.start_embed<CFF2Subrs> ();
|
||||
if (unlikely (subrs == nullptr) || acc.privateDicts[i].localSubrs == &Null(CFF2Subrs))
|
||||
{
|
||||
DEBUG_MSG (SUBSET, nullptr, "CFF2 subset: local subrs unexpectedly null [%d]", i);
|
||||
return false;
|
||||
|
@ -411,18 +426,18 @@ _hb_subset_cff2 (const OT::cff2::accelerator_subset_t &acc,
|
|||
hb_subset_plan_t *plan,
|
||||
hb_blob_t **prime /* OUT */)
|
||||
{
|
||||
subset_plan cff2_subset_plan;
|
||||
cff2_subset_plan cff2_plan;
|
||||
|
||||
if (unlikely (!cff2_subset_plan.create (acc, plan)))
|
||||
if (unlikely (!cff2_plan.create (acc, plan)))
|
||||
{
|
||||
DEBUG_MSG(SUBSET, nullptr, "Failed to generate a cff2 subsetting plan.");
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int cff2_prime_size = cff2_subset_plan.get_final_size ();
|
||||
unsigned int cff2_prime_size = cff2_plan.get_final_size ();
|
||||
char *cff2_prime_data = (char *) calloc (1, cff2_prime_size);
|
||||
|
||||
if (unlikely (!_write_cff2 (cff2_subset_plan, acc, plan->glyphs,
|
||||
if (unlikely (!_write_cff2 (cff2_plan, acc, plan->glyphs,
|
||||
cff2_prime_size, cff2_prime_data))) {
|
||||
DEBUG_MSG(SUBSET, nullptr, "Failed to write a subset cff2.");
|
||||
free (cff2_prime_data);
|
||||
|
@ -453,13 +468,10 @@ hb_subset_cff2 (hb_subset_plan_t *plan,
|
|||
OT::cff2::accelerator_subset_t acc;
|
||||
acc.init(plan->source);
|
||||
bool result = likely (acc.is_valid ()) &&
|
||||
_hb_subset_cff2 (acc,
|
||||
data,
|
||||
plan,
|
||||
prime);
|
||||
_hb_subset_cff2 (acc, data, plan, prime);
|
||||
|
||||
hb_blob_destroy (cff2_blob);
|
||||
acc.fini();
|
||||
acc.fini ();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "hb-ot-maxp-table.hh"
|
||||
#include "hb-ot-os2-table.hh"
|
||||
#include "hb-ot-post-table.hh"
|
||||
#include "hb-ot-cff-table.hh"
|
||||
#include "hb-ot-cff2-table.hh"
|
||||
|
||||
|
||||
|
@ -271,6 +272,9 @@ _subset_table (hb_subset_plan_t *plan,
|
|||
case HB_OT_TAG_post:
|
||||
result = _subset<const OT::post> (plan);
|
||||
break;
|
||||
case HB_OT_TAG_cff:
|
||||
result = _subset<const OT::cff> (plan);
|
||||
break;
|
||||
case HB_OT_TAG_cff2:
|
||||
result = _subset<const OT::cff2> (plan);
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue