Index, Dict structs hooked up to hb-subset (takes CFF2, outputs empty CFF2)pull/1113/head
parent
3654d9be6b
commit
3a61c3e935
7 changed files with 1030 additions and 0 deletions
@ -0,0 +1,475 @@ |
||||
/*
|
||||
* 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_COMMON_HH |
||||
#define HB_OT_CFF_COMMON_HH |
||||
|
||||
#include "hb-open-type-private.hh" |
||||
#include "hb-ot-layout-common-private.hh" |
||||
|
||||
namespace CFF { |
||||
|
||||
using namespace OT; |
||||
|
||||
const float UNSET_REAL_VALUE = -1.0f; |
||||
|
||||
enum OpCode { |
||||
/* One byte operators (0-31) */ |
||||
OpCode_version, /* 0 CFF Top */ |
||||
OpCode_Notice, /* 1 CFF Top */ |
||||
OpCode_FullName, /* 2 CFF Top */ |
||||
OpCode_FamilyName, /* 3 CFF Top */ |
||||
OpCode_Weight, /* 4 CFF Top */ |
||||
OpCode_FontBBox, /* 5 CFF Top */ |
||||
OpCode_BlueValues, /* 6 CFF Private, CFF2 Private */ |
||||
OpCode_OtherBlues, /* 7 CFF Private, CFF2 Private */ |
||||
OpCode_FamilyBlues, /* 8 CFF Private, CFF2 Private */ |
||||
OpCode_FamilyOtherBlues, /* 9 CFF Private, CFF2 Private */ |
||||
OpCode_StdHW, /* 10 CFF Private, CFF2 Private */ |
||||
OpCode_StdVW, /* 11 CFF Private, CFF2 Private */ |
||||
OpCode_escape, /* 12 All. Shared with CS */ |
||||
OpCode_UniqueID, /* 13 CFF Top */ |
||||
OpCode_XUID, /* 14 CFF Top */ |
||||
OpCode_charset, /* 15 CFF Top (0) */ |
||||
OpCode_Encoding, /* 16 CFF Top (0) */ |
||||
OpCode_CharStrings, /* 17 CFF Top, CFF2 Top */ |
||||
OpCode_Private, /* 18 CFF Top, CFF2 FD */ |
||||
OpCode_Subrs, /* 19 CFF Private, CFF2 Private */ |
||||
OpCode_defaultWidthX, /* 20 CFF Private (0) */ |
||||
OpCode_nominalWidthX, /* 21 CFF Private (0) */ |
||||
OpCode_vsindex, /* 22 CFF2 Private/CS */ |
||||
OpCode_blend, /* 23 CFF2 Private/CS */ |
||||
OpCode_vstore, /* 24 CFF2 Top */ |
||||
OpCode_reserved25, /* 25 */ |
||||
OpCode_reserved26, /* 26 */ |
||||
OpCode_reserved27, /* 27 */ |
||||
|
||||
/* Numbers */ |
||||
OpCode_shortint, /* 28 All */ |
||||
OpCode_longint, /* 29 All */ |
||||
OpCode_BCD, /* 30 CFF2 Top/FD */ |
||||
OpCode_reserved31, /* 31 */ |
||||
|
||||
/* 1-byte integers */ |
||||
OpCode_OneByteIntFirst = 32, /* All. beginning of the range of first byte ints */ |
||||
OpCode_OneByteIntLast = 246, /* All. ending of the range of first byte int */ |
||||
|
||||
/* 2-byte integers */ |
||||
OpCode_TwoBytePosInt0, /* 247 All. first byte of two byte positive int (+108 to +1131) */ |
||||
OpCode_TwoBytePosInt1, |
||||
OpCode_TwoBytePosInt2, |
||||
OpCode_TwoBytePosInt3, |
||||
|
||||
OpCode_TwoByteNegInt0, /* 251 All. first byte of two byte negative int (-1131 to -108) */ |
||||
OpCode_TwoByteNegInt1, |
||||
OpCode_TwoByteNegInt2, |
||||
OpCode_TwoByteNegInt3, |
||||
|
||||
/* Two byte escape operators 12, (0-41) */ |
||||
OpCode_ESC_Base = 32, |
||||
OpCode_Copyright = OpCode_ESC_Base, /* OpCode_ESC(0) CFF Top */ |
||||
OpCode_isFixedPitch, /* OpCode_ESC(1) CFF Top (false) */ |
||||
OpCode_ItalicAngle, /* OpCode_ESC(2) CFF Top (0) */ |
||||
OpCode_UnderlinePosition, /* OpCode_ESC(3) CFF Top (-100) */ |
||||
OpCode_UnderlineThickness, /* OpCode_ESC(4) CFF Top (50) */ |
||||
OpCode_PaintType, /* OpCode_ESC(5) CFF Top (0) */ |
||||
OpCode_CharstringType, /* OpCode_ESC(6) CFF Top (2) */ |
||||
OpCode_FontMatrix, /* OpCode_ESC(7) CFF Top, CFF2 Top (.001 0 0 .001 0 0)*/ |
||||
OpCode_StrokeWidth, /* OpCode_ESC(8) CFF Top (0) */ |
||||
OpCode_BlueScale, /* OpCode_ESC(9) CFF Private, CFF2 Private (0.039625) */ |
||||
OpCode_BlueShift, /* OpCode_ESC(10) CFF Private, CFF2 Private (7) */ |
||||
OpCode_BlueFuzz, /* OpCode_ESC(11) CFF Private, CFF2 Private (1) */ |
||||
OpCode_StemSnapH, /* OpCode_ESC(12) CFF Private, CFF2 Private */ |
||||
OpCode_StemSnapV, /* OpCode_ESC(13) CFF Private, CFF2 Private */ |
||||
OpCode_ForceBold, /* OpCode_ESC(14) CFF Private (false) */ |
||||
OpCode_reservedESC15, /* OpCode_ESC(15) */ |
||||
OpCode_reservedESC16, /* OpCode_ESC(16) */ |
||||
OpCode_LanguageGroup, /* OpCode_ESC(17) CFF Private, CFF2 Private (0) */ |
||||
OpCode_ExpansionFactor, /* OpCode_ESC(18) CFF Private, CFF2 Private (0.06) */ |
||||
OpCode_initialRandomSeed, /* OpCode_ESC(19) CFF Private (0) */ |
||||
OpCode_SyntheticBase, /* OpCode_ESC(20) CFF Top */ |
||||
OpCode_PostScript, /* OpCode_ESC(21) CFF Top */ |
||||
OpCode_BaseFontName, /* OpCode_ESC(22) CFF Top */ |
||||
OpCode_BaseFontBlend, /* OpCode_ESC(23) CFF Top */ |
||||
OpCode_reservedESC24, /* OpCode_ESC(24) */ |
||||
OpCode_reservedESC25, /* OpCode_ESC(25) */ |
||||
OpCode_reservedESC26, /* OpCode_ESC(26) */ |
||||
OpCode_reservedESC27, /* OpCode_ESC(27) */ |
||||
OpCode_reservedESC28, /* OpCode_ESC(28) */ |
||||
OpCode_reservedESC29, /* OpCode_ESC(29) */ |
||||
OpCode_ROS, /* OpCode_ESC(30) CFF Top_CID */ |
||||
OpCode_CIDFontVersion, /* OpCode_ESC(31) CFF Top_CID (0) */ |
||||
OpCode_CIDFontRevision, /* OpCode_ESC(32) CFF Top_CID (0) */ |
||||
OpCode_CIDFontType, /* OpCode_ESC(33) CFF Top_CID (0) */ |
||||
OpCode_CIDCount, /* OpCode_ESC(34) CFF Top_CID (8720) */ |
||||
OpCode_UIDBase, /* OpCode_ESC(35) CFF Top_CID */ |
||||
OpCode_FDArray, /* OpCode_ESC(36) CFF Top_CID, CFF2 Top */ |
||||
OpCode_FDSelect, /* OpCode_ESC(37) CFF Top_CID, CFF2 Top */ |
||||
OpCode_FontName, /* OpCode_ESC(38) CFF Top_CID */ |
||||
|
||||
OpCode_reserved255 = 255 |
||||
}; |
||||
|
||||
inline OpCode Make_OpCode_ESC(unsigned char byte2) { return (OpCode)(OpCode_ESC_Base + byte2); } |
||||
|
||||
/* CFF INDEX */ |
||||
struct Index |
||||
{ |
||||
inline bool sanitize (hb_sanitize_context_t *c) const |
||||
{ |
||||
TRACE_SANITIZE (this); |
||||
return_trace (c->check_struct (this) && offSize >= 1 && offSize <= 4 && |
||||
c->check_array (offsets, offSize, count + 1) && |
||||
c->check_array (data_base (), 1, offset_at (count))); |
||||
} |
||||
|
||||
inline unsigned int offset_array_size (void) const |
||||
{ return offSize * (count + 1); } |
||||
|
||||
inline const unsigned int offset_at (unsigned int index) const |
||||
{ |
||||
const HBUINT8 *p = offsets + offSize * index; |
||||
unsigned int size = offSize; |
||||
unsigned int offset = 0; |
||||
for (; size; size--) |
||||
offset = (offset << 8) + *p++; |
||||
return offset; |
||||
} |
||||
|
||||
inline const unsigned int length_at (unsigned int index) const |
||||
{ return offset_at (index + 1) - offset_at (index); } |
||||
|
||||
inline const char *data_base (void) const |
||||
{ return (const char *)this + 5 + offset_array_size (); } |
||||
|
||||
inline unsigned int data_size (void) const |
||||
{ return HBINT8::static_size; }; |
||||
|
||||
inline hb_bytes_t operator [] (unsigned int index) const |
||||
{ |
||||
if (likely (index < count)) |
||||
{ |
||||
hb_bytes_t b; |
||||
b.bytes = data_base () + offset_at (index) - 1; |
||||
b.len = offset_at (index + 1) - offset_at (index); |
||||
return b; |
||||
} |
||||
return Null(hb_bytes_t); |
||||
} |
||||
|
||||
inline unsigned int get_size (void) const |
||||
{ return count.static_size + offSize.static_size + offset_array_size () + (offset_at (count) - 1); } |
||||
|
||||
HBUINT32 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_MIN (6); |
||||
}; |
||||
|
||||
template <typename Type> |
||||
struct IndexOf : Index |
||||
{ |
||||
inline bool sanitize (hb_sanitize_context_t *c) const |
||||
{ |
||||
TRACE_SANITIZE (this); |
||||
return_trace (c->check_struct (this) && offSize >= 1 && offSize <= 4 && |
||||
c->check_array (offsets, offSize, count + 1) && |
||||
c->check_array (data_base (), sizeof (Type), offset_at (count))); |
||||
} |
||||
|
||||
inline const Type& operator [] (unsigned int index) const |
||||
{ |
||||
if (likely (index < count)) |
||||
return StructAtOffset<Type>(data_base (), offset_at (index) - 1); |
||||
return Null(Type); |
||||
} |
||||
}; |
||||
|
||||
struct UnsizedByteStr : UnsizedArrayOf <HBUINT8> {}; |
||||
|
||||
struct ByteStr { |
||||
ByteStr (const UnsizedByteStr& s, unsigned int l) |
||||
: str (s), len (l) {} |
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const { return str.sanitize (c, len); } |
||||
|
||||
inline const HBUINT8& operator [] (unsigned int i) const { return str[i]; } |
||||
|
||||
inline bool check_limit (unsigned int offset, unsigned int count) const |
||||
{ return (offset + count <= len); } |
||||
|
||||
const UnsizedByteStr& str; |
||||
const unsigned int len; |
||||
}; |
||||
|
||||
/* Top Dict, Font Dict, Private Dict */ |
||||
typedef UnsizedByteStr Dict; |
||||
|
||||
typedef Index CharStrings; |
||||
typedef Index Subrs; |
||||
typedef IndexOf<Dict> FDArray; |
||||
|
||||
/* FDSelect */ |
||||
struct FDSelect0 { |
||||
HBUINT8 fds[VAR]; |
||||
}; |
||||
|
||||
struct FDSelect3_Range { |
||||
HBUINT16 first; |
||||
HBUINT8 fd; |
||||
}; |
||||
|
||||
struct FDSelect3 { |
||||
HBUINT16 nRanges; |
||||
FDSelect3_Range ranges[VAR]; |
||||
/* HBUINT16 sentinel */ |
||||
}; |
||||
|
||||
struct FDSelect { |
||||
// XXX: need to sanitize at run time
|
||||
HBUINT8 format; |
||||
union { |
||||
FDSelect0 format0; |
||||
FDSelect3 format3; |
||||
} u; |
||||
}; |
||||
|
||||
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; |
||||
} |
||||
|
||||
struct Number |
||||
{ |
||||
Number (int v = 0) { set_int (v); } |
||||
Number (float v) { set_real (v); } |
||||
|
||||
inline void set_int (int v) { is_real = false; u.int_val = v; }; |
||||
inline int to_int (void) const { return is_real? (int)u.real_val: u.int_val; } |
||||
inline void set_real (float v) { is_real = true; u.real_val = v; }; |
||||
inline float to_real (void) const { return is_real? u.real_val: (float)u.int_val; } |
||||
|
||||
protected: |
||||
bool is_real; |
||||
union { |
||||
int int_val; |
||||
float real_val; |
||||
} u; |
||||
}; |
||||
|
||||
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 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_int (int& v) |
||||
{ |
||||
if (unlikely (!this->check_underflow (1))) |
||||
return false; |
||||
v = this->pop ().to_int (); |
||||
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_real (float& v) |
||||
{ |
||||
if (unlikely (!this->check_underflow (1))) |
||||
return false; |
||||
v = this->pop ().to_real (); |
||||
return true; |
||||
} |
||||
|
||||
inline bool check_pop_delta (hb_vector_t<float>& 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 (); |
||||
vec.push (val); |
||||
} |
||||
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]; |
||||
}; |
||||
|
||||
template <typename Offset> |
||||
inline bool check_pop_offset (Stack& stack, Offset& offset) |
||||
{ |
||||
unsigned int v; |
||||
if (unlikely (!stack.check_pop_uint (v))) |
||||
return false; |
||||
offset.set (v); |
||||
return true; |
||||
} |
||||
|
||||
template <typename OpSet, typename Param> |
||||
struct Interpreter { |
||||
|
||||
inline void init () |
||||
{ |
||||
stack.init (); |
||||
} |
||||
|
||||
inline void fini () |
||||
{ |
||||
stack.fini (); |
||||
} |
||||
|
||||
inline bool interpret (const ByteStr& str, Param& param) |
||||
{ |
||||
param.init(); |
||||
|
||||
for (unsigned int i = 0; i < str.len; i++) |
||||
{ |
||||
unsigned char byte = str[i]; |
||||
if ((OpCode_shortint == byte) || |
||||
(OpCode_OneByteIntFirst <= byte && OpCode_TwoByteNegInt3 >= byte)) |
||||
{ |
||||
if (unlikely (!process_intop (str, i, byte))) |
||||
return false; |
||||
} else { |
||||
if (byte == OpCode_escape) { |
||||
if (unlikely (!str.check_limit (i, 1))) |
||||
return false; |
||||
byte = Make_OpCode_ESC(str[++i]); |
||||
} |
||||
|
||||
if (unlikely (!OpSet::process_op (str, i, byte, stack, param))) |
||||
return false; |
||||
} |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
inline bool process_intop (const ByteStr& str, unsigned int& offset, unsigned char byte) |
||||
{ |
||||
switch (byte) { |
||||
case OpCode_TwoBytePosInt0: case OpCode_TwoBytePosInt1: |
||||
case OpCode_TwoBytePosInt2: case OpCode_TwoBytePosInt3: |
||||
if (unlikely (str.check_limit (offset, 2) || !stack.check_overflow (1))) |
||||
return false; |
||||
stack.push ((int16_t)((byte - OpCode_TwoBytePosInt0) * 256 + str[offset + 1] + 108)); |
||||
break; |
||||
|
||||
case OpCode_TwoByteNegInt0: case OpCode_TwoByteNegInt1: |
||||
case OpCode_TwoByteNegInt2: case OpCode_TwoByteNegInt3: |
||||
if (unlikely (!str.check_limit (offset, 2) || !stack.check_overflow (1))) |
||||
return false; |
||||
stack.push ((int16_t)(-(byte - OpCode_TwoByteNegInt0) * 256 - str[offset + 1] - 108)); |
||||
break; |
||||
|
||||
case OpCode_shortint: /* 3-byte integer */ |
||||
if (unlikely (!str.check_limit (offset, 3) || !stack.check_overflow (1))) |
||||
return false; |
||||
stack.push ((int16_t)((str[offset + 1] << 8) | str[offset + 2])); |
||||
break; |
||||
|
||||
default: |
||||
/* 1-byte integer */ |
||||
if (likely ((OpCode_OneByteIntFirst <= byte) && (byte <= OpCode_OneByteIntLast)) && |
||||
likely (stack.check_overflow (1))) |
||||
{ |
||||
stack.push ((int)byte - 139); |
||||
} else { |
||||
return false; |
||||
} |
||||
break; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
protected: |
||||
Stack stack; |
||||
}; |
||||
|
||||
} /* namespace CFF */ |
||||
|
||||
#endif /* HB_OT_CFF_COMMON_HH */ |
||||
|
@ -0,0 +1,386 @@ |
||||
/*
|
||||
* 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_CFF2_TABLE_HH |
||||
#define HB_OT_CFF2_TABLE_HH |
||||
|
||||
#include "hb-ot-cff-common-private.hh" |
||||
#include "hb-subset-cff2.hh" |
||||
|
||||
namespace CFF { |
||||
|
||||
/*
|
||||
* CFF2 -- Compact Font Format (CFF) Version 2 |
||||
* https://docs.microsoft.com/en-us/typography/opentype/spec/cff2
|
||||
*/ |
||||
#define HB_OT_TAG_cff2 HB_TAG('C','F','F','2') |
||||
|
||||
struct CFF2TopDictValues |
||||
{ |
||||
inline void init () |
||||
{ |
||||
charStringsOffset.set (0); |
||||
vstoreOffset.set (0); |
||||
FDArrayOffset.set (0); |
||||
FDSelectOffset.set (0); |
||||
FontMatrix[0] = FontMatrix[3] = 0.001f; |
||||
FontMatrix[1] = FontMatrix[2] = FontMatrix[4] = FontMatrix[5] = 0.0f; |
||||
} |
||||
|
||||
LOffsetTo<CharStrings> charStringsOffset; |
||||
LOffsetTo<VariationStore> vstoreOffset; |
||||
LOffsetTo<FDArray> FDArrayOffset; |
||||
LOffsetTo<FDSelect> FDSelectOffset; |
||||
float FontMatrix[6]; |
||||
}; |
||||
|
||||
struct CFF2TopDictOpSet |
||||
{ |
||||
static inline bool process_op (const ByteStr& str, unsigned int& offset, unsigned char byte, Stack& stack, CFF2TopDictValues& val) |
||||
{ |
||||
switch (byte) { |
||||
case OpCode_CharStrings: |
||||
if (unlikely (!check_pop_offset (stack, val.charStringsOffset))) |
||||
return false; |
||||
break; |
||||
case OpCode_vstore: |
||||
if (unlikely (!check_pop_offset (stack, val.vstoreOffset))) |
||||
return false; |
||||
break; |
||||
case OpCode_FDArray: |
||||
if (unlikely (!check_pop_offset (stack, val.FDArrayOffset))) |
||||
return false; |
||||
break; |
||||
case OpCode_FDSelect: |
||||
if (unlikely (!check_pop_offset (stack, val.FDSelectOffset))) |
||||
return false; |
||||
break; |
||||
case OpCode_FontMatrix: |
||||
if (unlikely (!stack.check_underflow (6))) |
||||
return false; |
||||
for (int i = 0; i < 6; i++) |
||||
val.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 ((int32_t)((str[offset + 1] << 24) | (str[offset + 2] << 16) | (str[offset + 3] << 8) | str[offset + 4])); |
||||
offset += 4; |
||||
break; |
||||
|
||||
case OpCode_BCD: /* real number */ |
||||
float v; |
||||
if (unlikely (stack.check_overflow (1) || !parse_bcd (str, offset, v))) |
||||
return false; |
||||
stack.push (v); |
||||
break; |
||||
|
||||
default: |
||||
/* XXX: invalid */ |
||||
stack.clear (); |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
}; |
||||
|
||||
struct CFF2FontDictValues |
||||
{ |
||||
inline void init () |
||||
{ |
||||
privateDictSize = 0; |
||||
privateDictOffset.set (0); |
||||
} |
||||
|
||||
unsigned int privateDictSize; |
||||
OffsetTo<Dict> privateDictOffset; |
||||
}; |
||||
|
||||
struct CFF2FontDictOpSet |
||||
{ |
||||
static inline bool process_op (const ByteStr& str, unsigned int& offset, unsigned char byte, Stack& stack, CFF2FontDictValues& val) |
||||
{ |
||||
switch (byte) { |
||||
case OpCode_Private: |
||||
if (unlikely (!stack.check_pop_uint (val.privateDictSize))) |
||||
return false; |
||||
if (unlikely (!check_pop_offset (stack, val.privateDictOffset))) |
||||
return false; |
||||
break; |
||||
case OpCode_longint: /* 5-byte integer */ |
||||
if (unlikely (!str.check_limit (offset, 5) || !stack.check_overflow (1))) |
||||
return false; |
||||
stack.push ((int32_t)((str[offset + 1] << 24) | (str[offset + 2] << 16) || (str[offset + 3] << 8) || str[offset + 4])); |
||||
break; |
||||
case OpCode_BCD: /* real number */ |
||||
float v; |
||||
if (unlikely (stack.check_overflow (1) || !parse_bcd (str, offset, v))) |
||||
return false; |
||||
stack.push (v); |
||||
break; |
||||
|
||||
default: |
||||
/* XXX: invalid */ |
||||
stack.clear (); |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
}; |
||||
|
||||
struct CFF2PrivateDictValues |
||||
{ |
||||
inline void init () |
||||
{ |
||||
languageGroup = 0; |
||||
expansionFactor = 0.06f; |
||||
vsIndex = 0; |
||||
subrsOffset.set (0); |
||||
blueScale = 0.039625f; |
||||
blueShift = 7.0f; |
||||
blueFuzz = 1.0f; |
||||
stdHW = UNSET_REAL_VALUE; |
||||
stdVW = UNSET_REAL_VALUE; |
||||
blueValues.init (); |
||||
otherBlues.init (); |
||||
familyBlues.init (); |
||||
familyOtherBlues.init (); |
||||
stemSnapH.init (); |
||||
stemSnapV.init (); |
||||
} |
||||
|
||||
inline void fini () |
||||
{ |
||||
blueValues.fini (); |
||||
otherBlues.fini (); |
||||
familyBlues.fini (); |
||||
familyOtherBlues.fini (); |
||||
stemSnapH.fini (); |
||||
stemSnapV.fini (); |
||||
} |
||||
|
||||
int languageGroup; |
||||
float expansionFactor; |
||||
int vsIndex; |
||||
OffsetTo<Subrs> subrsOffset; |
||||
float blueScale; |
||||
float blueShift; |
||||
float blueFuzz; |
||||
float stdHW; |
||||
float stdVW; |
||||
hb_vector_t <float> blueValues; |
||||
hb_vector_t <float> otherBlues; |
||||
hb_vector_t <float> familyBlues; |
||||
hb_vector_t <float> familyOtherBlues; |
||||
hb_vector_t <float> stemSnapH; |
||||
hb_vector_t <float> stemSnapV; |
||||
}; |
||||
|
||||
struct CFF2PrivateDictOpSet |
||||
{ |
||||
static inline bool process_op (const ByteStr& str, unsigned int& offset, unsigned char byte, Stack& stack, CFF2PrivateDictValues& val) |
||||
{ |
||||
switch (byte) { |
||||
case OpCode_BlueValues: |
||||
if (unlikely (!stack.check_pop_delta (val.blueValues, true))) |
||||
return false; |
||||
break; |
||||
case OpCode_OtherBlues: |
||||
if (unlikely (!stack.check_pop_delta (val.otherBlues, true))) |
||||
return false; |
||||
break; |
||||
case OpCode_FamilyBlues: |
||||
if (unlikely (!stack.check_pop_delta (val.familyBlues, true))) |
||||
return false; |
||||
break; |
||||
case OpCode_FamilyOtherBlues: |
||||
if (unlikely (!stack.check_pop_delta (val.familyOtherBlues, true))) |
||||
return false; |
||||
break; |
||||
case OpCode_StdHW: |
||||
if (unlikely (!stack.check_pop_real (val.stdHW))) |
||||
return false; |
||||
break; |
||||
case OpCode_StdVW: |
||||
if (unlikely (!stack.check_pop_real (val.stdVW))) |
||||
return false; |
||||
break; |
||||
case OpCode_BlueScale: |
||||
if (unlikely (!stack.check_pop_real (val.blueScale))) |
||||
return false; |
||||
break; |
||||
case OpCode_BlueShift: |
||||
if (unlikely (!stack.check_pop_real (val.blueShift))) |
||||
return false; |
||||
break; |
||||
case OpCode_BlueFuzz: |
||||
if (unlikely (!stack.check_pop_real (val.blueFuzz))) |
||||
return false; |
||||
break; |
||||
case OpCode_StemSnapH: |
||||
if (unlikely (!stack.check_pop_delta (val.stemSnapH))) |
||||
return false; |
||||
break; |
||||
case OpCode_StemSnapV: |
||||
if (unlikely (!stack.check_pop_delta (val.stemSnapV))) |
||||
return false; |
||||
break; |
||||
case OpCode_LanguageGroup: |
||||
if (unlikely (!stack.check_pop_int (val.languageGroup))) |
||||
return false; |
||||
break; |
||||
case OpCode_ExpansionFactor: |
||||
if (unlikely (!stack.check_pop_real (val.expansionFactor))) |
||||
return false; |
||||
break; |
||||
case OpCode_Subrs: |
||||
if (unlikely (!check_pop_offset (stack, val.subrsOffset))) |
||||
return false; |
||||
break; |
||||
case OpCode_blend: |
||||
// XXX: TODO
|
||||
break; |
||||
|
||||
default: |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
}; |
||||
|
||||
typedef Interpreter<CFF2TopDictOpSet, CFF2TopDictValues> CFF2TopDict_Interpreter; |
||||
typedef Interpreter<CFF2FontDictOpSet, CFF2FontDictValues> CFF2FontDict_Interpreter; |
||||
typedef Interpreter<CFF2PrivateDictOpSet, CFF2PrivateDictValues> CFF2PrivateDict_Interpreter; |
||||
|
||||
}; /* namespace CFF */ |
||||
|
||||
namespace OT { |
||||
|
||||
using namespace CFF; |
||||
|
||||
struct cff2 |
||||
{ |
||||
static const hb_tag_t tableTag = HB_OT_TAG_cff2; |
||||
|
||||
inline bool sanitize (hb_sanitize_context_t *c) const |
||||
{ |
||||
TRACE_SANITIZE (this); |
||||
return_trace (c->check_struct (this) && |
||||
version.sanitize (c) && |
||||
likely (version.major == 2)); |
||||
} |
||||
|
||||
struct accelerator_t |
||||
{ |
||||
inline void init (hb_face_t *face) |
||||
{ |
||||
this->blob = OT::Sanitizer<OT::cff2>().sanitize (face->reference_table (HB_OT_TAG_cff2)); |
||||
const OT::cff2 *cff2 = this->blob->as<OT::cff2> (); |
||||
|
||||
if (cff2 == &Null(OT::cff2)) |
||||
{ |
||||
hb_blob_destroy (blob); |
||||
return; |
||||
} |
||||
|
||||
{ /* parse top dict */ |
||||
ByteStr topDictStr (cff2 + cff2->topDict, cff2->topDictSize); |
||||
CFF2TopDict_Interpreter top_interp; |
||||
top_interp.init (); |
||||
top_interp.interpret (topDictStr, top); |
||||
top_interp.fini (); |
||||
} |
||||
|
||||
varStore = &OT::StructAtOffset<VariationStore>(cff2, top.vstoreOffset); |
||||
charStrings = &OT::StructAtOffset<CharStrings>(cff2, top.charStringsOffset); |
||||
fdArray = &OT::StructAtOffset<FDArray>(cff2, top.FDArrayOffset); |
||||
fdSelect = &OT::StructAtOffset<FDSelect>(cff2, top.FDSelectOffset); |
||||
|
||||
// XXX: sanitize above?
|
||||
if ((charStrings == &Null(CharStrings)) || |
||||
(fdArray == &Null(FDArray))) |
||||
{ |
||||
hb_blob_destroy (blob); |
||||
return; |
||||
} |
||||
|
||||
num_glyphs = charStrings->count; |
||||
} |
||||
|
||||
inline void fini (void) |
||||
{ |
||||
hb_blob_destroy (blob); |
||||
} |
||||
|
||||
inline bool get_extents (hb_codepoint_t glyph, |
||||
hb_glyph_extents_t *extents) const |
||||
{ |
||||
// XXX: TODO
|
||||
if (glyph >= num_glyphs) |
||||
return false; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
private: |
||||
hb_blob_t *blob; |
||||
|
||||
CFF2TopDictValues top; |
||||
const VariationStore *varStore; |
||||
const CharStrings *charStrings; |
||||
const FDArray *fdArray; |
||||
const FDSelect *fdSelect; |
||||
|
||||
unsigned int num_glyphs; |
||||
}; |
||||
|
||||
inline bool subset (hb_subset_plan_t *plan) const |
||||
{ |
||||
hb_blob_t *cff2_prime = nullptr; |
||||
|
||||
bool success = true; |
||||
if (hb_subset_cff2 (plan, &cff2_prime)) { |
||||
success = success && plan->add_table (HB_OT_TAG_cff2, cff2_prime); |
||||
} else { |
||||
success = false; |
||||
} |
||||
hb_blob_destroy (cff2_prime); |
||||
|
||||
return success; |
||||
} |
||||
|
||||
protected: |
||||
FixedVersion<HBUINT8> version; /* Version of CFF2 table. set to 0x0200u */ |
||||
OffsetTo<Dict, HBUINT8> topDict; /* headerSize = Offset to Top DICT. */ |
||||
HBUINT16 topDictSize; /* Top DICT size */ |
||||
|
||||
public: |
||||
DEFINE_SIZE_STATIC (5); |
||||
}; |
||||
|
||||
} /* namespace OT */ |
||||
|
||||
#endif /* HB_OT_CFF2_TABLE_HH */ |
@ -0,0 +1,121 @@ |
||||
/*
|
||||
* 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-cff2-table.hh" |
||||
#include "hb-set.h" |
||||
#include "hb-subset-cff2.hh" |
||||
#include "hb-subset-plan.hh" |
||||
|
||||
static bool |
||||
_calculate_cff2_prime_size (const OT::cff2::accelerator_t &cff2, |
||||
hb_vector_t<hb_codepoint_t> &glyph_ids, |
||||
hb_bool_t drop_hints, |
||||
unsigned int *cff2_size /* OUT */, |
||||
hb_vector_t<unsigned int> *instruction_ranges /* OUT */) |
||||
{ |
||||
// XXX: TODO
|
||||
*cff2_size = 0; |
||||
return true; |
||||
} |
||||
|
||||
static bool |
||||
_write_cff2_prime (hb_subset_plan_t *plan, |
||||
const OT::cff2::accelerator_t &cff2, |
||||
const char *cff2_data, |
||||
hb_vector_t<unsigned int> &instruction_ranges, |
||||
unsigned int cff2_prime_size, |
||||
char *cff2_prime_data /* OUT */) |
||||
{ |
||||
// XXX: TODO
|
||||
return true; |
||||
} |
||||
|
||||
static bool |
||||
_hb_subset_cff2 (const OT::cff2::accelerator_t &cff2, |
||||
const char *cff2_data, |
||||
hb_subset_plan_t *plan, |
||||
hb_blob_t **cff2_prime /* OUT */) |
||||
{ |
||||
hb_vector_t<hb_codepoint_t> &glyphs_to_retain = plan->glyphs; |
||||
|
||||
unsigned int cff2_prime_size; |
||||
hb_vector_t<unsigned int> instruction_ranges; |
||||
instruction_ranges.init(); |
||||
|
||||
if (unlikely (!_calculate_cff2_prime_size (cff2, |
||||
glyphs_to_retain, |
||||
plan->drop_hints, |
||||
&cff2_prime_size, |
||||
&instruction_ranges))) { |
||||
instruction_ranges.fini(); |
||||
return false; |
||||
} |
||||
|
||||
char *cff2_prime_data = (char *) calloc (1, cff2_prime_size); |
||||
if (unlikely (!_write_cff2_prime (plan, cff2, cff2_data, |
||||
instruction_ranges, |
||||
cff2_prime_size, cff2_prime_data))) { |
||||
free (cff2_prime_data); |
||||
instruction_ranges.fini(); |
||||
return false; |
||||
} |
||||
instruction_ranges.fini(); |
||||
|
||||
*cff2_prime = hb_blob_create (cff2_prime_data, |
||||
cff2_prime_size, |
||||
HB_MEMORY_MODE_READONLY, |
||||
cff2_prime_data, |
||||
free); |
||||
// XXX: TODO
|
||||
return true; |
||||
} |
||||
|
||||
/**
|
||||
* hb_subset_cff2: |
||||
* Subsets the CFF2 table according to a provided plan. |
||||
* |
||||
* Return value: subsetted cff2 table. |
||||
**/ |
||||
bool |
||||
hb_subset_cff2 (hb_subset_plan_t *plan, |
||||
hb_blob_t **cff2_prime /* OUT */) |
||||
{ |
||||
hb_blob_t *cff2_blob = OT::Sanitizer<OT::cff2>().sanitize (plan->source->reference_table (HB_OT_TAG_cff2)); |
||||
const char *cff2_data = hb_blob_get_data(cff2_blob, nullptr); |
||||
|
||||
OT::cff2::accelerator_t cff2; |
||||
cff2.init(plan->source); |
||||
bool result = _hb_subset_cff2 (cff2, |
||||
cff2_data, |
||||
plan, |
||||
cff2_prime); |
||||
|
||||
hb_blob_destroy (cff2_blob); |
||||
cff2.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_CFF2_HH |
||||
#define HB_SUBSET_CFF2_HH |
||||
|
||||
#include "hb-private.hh" |
||||
|
||||
#include "hb-subset-plan.hh" |
||||
|
||||
HB_INTERNAL bool |
||||
hb_subset_cff2 (hb_subset_plan_t *plan, |
||||
hb_blob_t **cff2_prime /* OUT */); |
||||
|
||||
#endif /* HB_SUBSET_CFF2_HH */ |
Loading…
Reference in new issue