Added CFF2 Subr nullifier
along with CFF2 charstring interpreter factored out common code between CFF1 & CFF2 to CSInterpreter moved fetch_op from Interpreter to InterpEnv misc code clean up & bug fixes
This commit is contained in:
parent
f57d6bcbca
commit
cef75ea41a
|
@ -155,6 +155,7 @@ HB_OT_sources = \
|
||||||
hb-cff-interp-common-private.hh \
|
hb-cff-interp-common-private.hh \
|
||||||
hb-cff-interp-cs-common-private.hh \
|
hb-cff-interp-cs-common-private.hh \
|
||||||
hb-cff1-interp-cs.hh \
|
hb-cff1-interp-cs.hh \
|
||||||
|
hb-cff2-interp-cs.hh \
|
||||||
hb-cff-interp-dict-common-private.hh \
|
hb-cff-interp-dict-common-private.hh \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ enum OpCode {
|
||||||
OpCode_Subrs, /* 19 CFF Private, CFF2 Private */
|
OpCode_Subrs, /* 19 CFF Private, CFF2 Private */
|
||||||
OpCode_defaultWidthX, /* 20 CFF Private (0) */
|
OpCode_defaultWidthX, /* 20 CFF Private (0) */
|
||||||
OpCode_nominalWidthX, /* 21 CFF Private (0) */
|
OpCode_nominalWidthX, /* 21 CFF Private (0) */
|
||||||
OpCode_vsindex, /* 22 CFF2 Private/CS */
|
OpCode_vsindexdict, /* 22 CFF2 Private/CS */
|
||||||
OpCode_blenddict, /* 23 CFF2 Private/CS */
|
OpCode_blenddict, /* 23 CFF2 Private/CS */
|
||||||
OpCode_vstore, /* 24 CFF2 Top */
|
OpCode_vstore, /* 24 CFF2 Top */
|
||||||
OpCode_reserved25, /* 25 */
|
OpCode_reserved25, /* 25 */
|
||||||
|
@ -142,8 +142,8 @@ enum OpCode {
|
||||||
// OpCode_escape, /* 12 CFF, CFF2 */
|
// OpCode_escape, /* 12 CFF, CFF2 */
|
||||||
OpCode_Reserved13 = 13,
|
OpCode_Reserved13 = 13,
|
||||||
OpCode_endchar, /* 14 CFF */
|
OpCode_endchar, /* 14 CFF */
|
||||||
// OpCode_vsindex, /* 15 CFF2 */
|
OpCode_vsindexcs, /* 15 CFF2 */
|
||||||
OpCode_blendcs = 16, /* 16 CFF2 */
|
OpCode_blendcs, /* 16 CFF2 */
|
||||||
OpCode_Reserved17,
|
OpCode_Reserved17,
|
||||||
OpCode_hstemhm, /* 18 CFF, CFF2 */
|
OpCode_hstemhm, /* 18 CFF, CFF2 */
|
||||||
OpCode_hintmask, /* 19 CFF, CFF2 */
|
OpCode_hintmask, /* 19 CFF, CFF2 */
|
||||||
|
@ -365,8 +365,8 @@ struct Stack
|
||||||
|
|
||||||
inline void clear (void) { size = 0; }
|
inline void clear (void) { size = 0; }
|
||||||
|
|
||||||
inline bool check_overflow (unsigned int count) const { return (count <= kSizeLimit) && (count + size <= kSizeLimit); }
|
inline bool check_overflow (unsigned int count=1) const { return (count <= kSizeLimit) && (count + size <= kSizeLimit); }
|
||||||
inline bool check_underflow (unsigned int count) const { return (count <= size); }
|
inline bool check_underflow (unsigned int count=1) const { return (count <= size); }
|
||||||
|
|
||||||
inline unsigned int get_size (void) const { return size; }
|
inline unsigned int get_size (void) const { return size; }
|
||||||
inline bool is_empty (void) const { return size == 0; }
|
inline bool is_empty (void) const { return size == 0; }
|
||||||
|
@ -396,7 +396,7 @@ struct ArgStack : Stack<Number, 513>
|
||||||
|
|
||||||
inline bool check_pop_num (Number& n)
|
inline bool check_pop_num (Number& n)
|
||||||
{
|
{
|
||||||
if (unlikely (!this->check_underflow (1)))
|
if (unlikely (!this->check_underflow ()))
|
||||||
return false;
|
return false;
|
||||||
n = this->pop ();
|
n = this->pop ();
|
||||||
return true;
|
return true;
|
||||||
|
@ -413,7 +413,7 @@ struct ArgStack : Stack<Number, 513>
|
||||||
|
|
||||||
inline bool check_pop_int (int& v)
|
inline bool check_pop_int (int& v)
|
||||||
{
|
{
|
||||||
if (unlikely (!this->check_underflow (1)))
|
if (unlikely (!this->check_underflow ()))
|
||||||
return false;
|
return false;
|
||||||
v = this->pop ().to_int ();
|
v = this->pop ().to_int ();
|
||||||
return true;
|
return true;
|
||||||
|
@ -501,6 +501,21 @@ struct InterpEnv
|
||||||
argStack.fini ();
|
argStack.fini ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool fetch_op (OpCode &op)
|
||||||
|
{
|
||||||
|
if (unlikely (!substr.avail ()))
|
||||||
|
return false;
|
||||||
|
op = (OpCode)(unsigned char)substr[0];
|
||||||
|
if (op == OpCode_escape) {
|
||||||
|
if (unlikely (!substr.avail ()))
|
||||||
|
return false;
|
||||||
|
op = Make_OpCode_ESC (substr[1]);
|
||||||
|
substr.inc ();
|
||||||
|
}
|
||||||
|
substr.inc ();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
SubByteStr substr;
|
SubByteStr substr;
|
||||||
ArgStack argStack;
|
ArgStack argStack;
|
||||||
};
|
};
|
||||||
|
@ -558,21 +573,6 @@ struct Interpreter {
|
||||||
|
|
||||||
inline void fini (void) { env.fini (); }
|
inline void fini (void) { env.fini (); }
|
||||||
|
|
||||||
inline bool fetch_op (OpCode &op)
|
|
||||||
{
|
|
||||||
if (unlikely (!env.substr.avail ()))
|
|
||||||
return false;
|
|
||||||
op = (OpCode)(unsigned char)env.substr[0];
|
|
||||||
if (op == OpCode_escape) {
|
|
||||||
if (unlikely (!env.substr.avail ()))
|
|
||||||
return false;
|
|
||||||
op = Make_OpCode_ESC (env.substr[1]);
|
|
||||||
env.substr.inc ();
|
|
||||||
}
|
|
||||||
env.substr.inc ();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ENV env;
|
ENV env;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,11 @@ struct CSInterpEnv : InterpEnv
|
||||||
{
|
{
|
||||||
InterpEnv::init (str);
|
InterpEnv::init (str);
|
||||||
|
|
||||||
|
stack_cleared = false;
|
||||||
|
seen_moveto = true;
|
||||||
|
seen_hintmask = false;
|
||||||
|
hstem_count = 0;
|
||||||
|
vstem_count = 0;
|
||||||
callStack.init ();
|
callStack.init ();
|
||||||
globalSubrs.init (globalSubrs_);
|
globalSubrs.init (globalSubrs_);
|
||||||
localSubrs.init (localSubrs_);
|
localSubrs.init (localSubrs_);
|
||||||
|
@ -105,20 +110,55 @@ struct CSInterpEnv : InterpEnv
|
||||||
|
|
||||||
inline bool returnFromSubr (void)
|
inline bool returnFromSubr (void)
|
||||||
{
|
{
|
||||||
if (unlikely (!callStack.check_underflow (1)))
|
if (unlikely (!callStack.check_underflow ()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
substr = callStack.pop ();
|
substr = callStack.pop ();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void determine_hintmask_size (void)
|
||||||
|
{
|
||||||
|
if (!seen_hintmask)
|
||||||
|
{
|
||||||
|
vstem_count += argStack.size / 2;
|
||||||
|
hintmask_size = (hstem_count + vstem_count + 7) >> 3;
|
||||||
|
seen_hintmask = true;
|
||||||
|
}
|
||||||
|
clear_stack ();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void process_moveto (void)
|
||||||
|
{
|
||||||
|
clear_stack ();
|
||||||
|
|
||||||
|
if (!seen_moveto)
|
||||||
|
{
|
||||||
|
determine_hintmask_size ();
|
||||||
|
seen_moveto = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void clear_stack (void)
|
||||||
|
{
|
||||||
|
stack_cleared = true;
|
||||||
|
argStack.clear ();
|
||||||
|
}
|
||||||
|
|
||||||
inline void set_endchar (bool endchar_flag_) { endchar_flag = endchar_flag_; }
|
inline void set_endchar (bool endchar_flag_) { endchar_flag = endchar_flag_; }
|
||||||
inline bool is_endchar (void) const { return endchar_flag; }
|
inline bool is_endchar (void) const { return endchar_flag; }
|
||||||
|
inline bool is_stack_cleared (void) const { return stack_cleared; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool endchar_flag;
|
bool endchar_flag;
|
||||||
|
bool stack_cleared;
|
||||||
|
bool seen_moveto;
|
||||||
|
bool seen_hintmask;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
unsigned int hstem_count;
|
||||||
|
unsigned int vstem_count;
|
||||||
|
unsigned int hintmask_size;
|
||||||
CallStack callStack;
|
CallStack callStack;
|
||||||
BiasedSubrs<SUBRS> globalSubrs;
|
BiasedSubrs<SUBRS> globalSubrs;
|
||||||
BiasedSubrs<SUBRS> localSubrs;
|
BiasedSubrs<SUBRS> localSubrs;
|
||||||
|
@ -131,6 +171,12 @@ struct CSOpSet : OpSet
|
||||||
{
|
{
|
||||||
switch (op) {
|
switch (op) {
|
||||||
|
|
||||||
|
case OpCode_return:
|
||||||
|
return env.returnFromSubr ();
|
||||||
|
case OpCode_endchar:
|
||||||
|
env.set_endchar (true);
|
||||||
|
return true;
|
||||||
|
|
||||||
case OpCode_longintcs:
|
case OpCode_longintcs:
|
||||||
return env.argStack.push_longint_from_substr (env.substr);
|
return env.argStack.push_longint_from_substr (env.substr);
|
||||||
|
|
||||||
|
@ -140,9 +186,50 @@ struct CSOpSet : OpSet
|
||||||
case OpCode_callgsubr:
|
case OpCode_callgsubr:
|
||||||
return env.callSubr (env.globalSubrs);
|
return env.callSubr (env.globalSubrs);
|
||||||
|
|
||||||
|
case OpCode_hstem:
|
||||||
|
case OpCode_hstemhm:
|
||||||
|
env.hstem_count += env.argStack.size / 2;
|
||||||
|
env.clear_stack ();
|
||||||
|
break;
|
||||||
|
case OpCode_vstem:
|
||||||
|
case OpCode_vstemhm:
|
||||||
|
env.vstem_count += env.argStack.size / 2;
|
||||||
|
env.clear_stack ();
|
||||||
|
break;
|
||||||
|
case OpCode_hintmask:
|
||||||
|
case OpCode_cntrmask:
|
||||||
|
env.determine_hintmask_size ();
|
||||||
|
if (unlikely (!env.substr.avail (env.hintmask_size)))
|
||||||
|
return false;
|
||||||
|
env.substr.inc (env.hintmask_size);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OpCode_vmoveto:
|
||||||
|
case OpCode_rlineto:
|
||||||
|
case OpCode_hlineto:
|
||||||
|
case OpCode_vlineto:
|
||||||
|
case OpCode_rmoveto:
|
||||||
|
case OpCode_hmoveto:
|
||||||
|
env.process_moveto ();
|
||||||
|
break;
|
||||||
|
case OpCode_rrcurveto:
|
||||||
|
case OpCode_rcurveline:
|
||||||
|
case OpCode_rlinecurve:
|
||||||
|
case OpCode_vvcurveto:
|
||||||
|
case OpCode_hhcurveto:
|
||||||
|
case OpCode_vhcurveto:
|
||||||
|
case OpCode_hvcurveto:
|
||||||
|
case OpCode_hflex:
|
||||||
|
case OpCode_flex:
|
||||||
|
case OpCode_hflex1:
|
||||||
|
case OpCode_flex1:
|
||||||
|
env.clear_stack ();
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return OpSet::process_op (op, env);
|
return OpSet::process_op (op, env);
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -157,13 +244,11 @@ struct CSInterpreter : Interpreter<ENV>
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
OpCode op;
|
OpCode op;
|
||||||
if (unlikely (!super.fetch_op (op) ||
|
if (unlikely (!super.env.fetch_op (op) ||
|
||||||
!OPSET::process_op (op, super.env, param)))
|
!OPSET::process_op (op, super.env, param)))
|
||||||
return false;
|
return false;
|
||||||
if (super.env.is_endchar ())
|
if (super.env.is_endchar ())
|
||||||
break;
|
break;
|
||||||
if (!super.env.substr.avail ())
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -170,7 +170,8 @@ struct DictInterpreter : Interpreter<InterpEnv>
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
OpCode op;
|
OpCode op;
|
||||||
if (unlikely (!super.fetch_op (op) || !OPSET::process_op (op, super.env, param)))
|
if (unlikely (!super.env.fetch_op (op) ||
|
||||||
|
!OPSET::process_op (op, super.env, param)))
|
||||||
return false;
|
return false;
|
||||||
} while (super.env.substr.avail ());
|
} while (super.env.substr.avail ());
|
||||||
|
|
||||||
|
|
|
@ -38,11 +38,6 @@ struct CFF1CSInterpEnv : CSInterpEnv<CFF1Subrs>
|
||||||
inline void init (const ByteStr &str, const CFF1Subrs &globalSubrs, const CFF1Subrs &localSubrs)
|
inline void init (const ByteStr &str, const CFF1Subrs &globalSubrs, const CFF1Subrs &localSubrs)
|
||||||
{
|
{
|
||||||
CSInterpEnv<CFF1Subrs>::init (str, globalSubrs, localSubrs);
|
CSInterpEnv<CFF1Subrs>::init (str, globalSubrs, localSubrs);
|
||||||
seen_width = false;
|
|
||||||
seen_moveto = true;
|
|
||||||
seen_hintmask = false;
|
|
||||||
hstem_count = 0;
|
|
||||||
vstem_count = 0;
|
|
||||||
for (unsigned int i = 0; i < kTransientArraySize; i++)
|
for (unsigned int i = 0; i < kTransientArraySize; i++)
|
||||||
transient_array[i].set_int (0);
|
transient_array[i].set_int (0);
|
||||||
}
|
}
|
||||||
|
@ -50,34 +45,6 @@ struct CFF1CSInterpEnv : CSInterpEnv<CFF1Subrs>
|
||||||
bool check_transient_array_index (unsigned int i) const
|
bool check_transient_array_index (unsigned int i) const
|
||||||
{ return i < kTransientArraySize; }
|
{ return i < kTransientArraySize; }
|
||||||
|
|
||||||
inline void determine_hintmask_size (void)
|
|
||||||
{
|
|
||||||
if (!seen_hintmask)
|
|
||||||
{
|
|
||||||
vstem_count += argStack.size / 2;
|
|
||||||
hintmask_size = (hstem_count + vstem_count + 7) >> 3;
|
|
||||||
seen_hintmask = true;
|
|
||||||
}
|
|
||||||
clear_stack ();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void process_moveto (void)
|
|
||||||
{
|
|
||||||
clear_stack ();
|
|
||||||
|
|
||||||
if (!seen_moveto)
|
|
||||||
{
|
|
||||||
determine_hintmask_size ();
|
|
||||||
seen_moveto = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void clear_stack (void)
|
|
||||||
{
|
|
||||||
seen_width = true;
|
|
||||||
argStack.clear ();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void process_width (void)
|
inline void process_width (void)
|
||||||
{
|
{
|
||||||
if (!seen_width && (argStack.size > 0))
|
if (!seen_width && (argStack.size > 0))
|
||||||
|
@ -90,11 +57,6 @@ struct CFF1CSInterpEnv : CSInterpEnv<CFF1Subrs>
|
||||||
|
|
||||||
bool seen_width;
|
bool seen_width;
|
||||||
Number width;
|
Number width;
|
||||||
bool seen_moveto;
|
|
||||||
bool seen_hintmask;
|
|
||||||
unsigned int hintmask_size;
|
|
||||||
unsigned int hstem_count;
|
|
||||||
unsigned int vstem_count;
|
|
||||||
|
|
||||||
static const unsigned int kTransientArraySize = 32;
|
static const unsigned int kTransientArraySize = 32;
|
||||||
Number transient_array[kTransientArraySize];
|
Number transient_array[kTransientArraySize];
|
||||||
|
@ -109,11 +71,6 @@ struct CFF1CSOpSet : CSOpSet<CFF1Subrs, PARAM>
|
||||||
|
|
||||||
switch (op) {
|
switch (op) {
|
||||||
|
|
||||||
case OpCode_return:
|
|
||||||
return env.returnFromSubr ();
|
|
||||||
case OpCode_endchar:
|
|
||||||
env.set_endchar (true);
|
|
||||||
return true;
|
|
||||||
case OpCode_and:
|
case OpCode_and:
|
||||||
if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false;
|
if (unlikely (!env.argStack.check_pop_num2 (n1, n2))) return false;
|
||||||
env.argStack.push_int ((n1.to_real() != 0.0f) && (n2.to_real() != 0.0f));
|
env.argStack.push_int ((n1.to_real() != 0.0f) && (n2.to_real() != 0.0f));
|
||||||
|
@ -223,45 +180,6 @@ struct CFF1CSOpSet : CSOpSet<CFF1Subrs, PARAM>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OpCode_hstem:
|
|
||||||
case OpCode_hstemhm:
|
|
||||||
env.hstem_count += env.argStack.size / 2;
|
|
||||||
env.clear_stack ();
|
|
||||||
break;
|
|
||||||
case OpCode_vstem:
|
|
||||||
case OpCode_vstemhm:
|
|
||||||
env.vstem_count += env.argStack.size / 2;
|
|
||||||
env.clear_stack ();
|
|
||||||
break;
|
|
||||||
case OpCode_hintmask:
|
|
||||||
case OpCode_cntrmask:
|
|
||||||
env.determine_hintmask_size ();
|
|
||||||
if (unlikely (!env.substr.avail (env.hintmask_size)))
|
|
||||||
return false;
|
|
||||||
env.substr.inc (env.hintmask_size);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case OpCode_vmoveto:
|
|
||||||
case OpCode_rlineto:
|
|
||||||
case OpCode_hlineto:
|
|
||||||
case OpCode_vlineto:
|
|
||||||
case OpCode_rmoveto:
|
|
||||||
case OpCode_hmoveto:
|
|
||||||
env.process_moveto ();
|
|
||||||
break;
|
|
||||||
case OpCode_rrcurveto:
|
|
||||||
case OpCode_rcurveline:
|
|
||||||
case OpCode_rlinecurve:
|
|
||||||
case OpCode_vvcurveto:
|
|
||||||
case OpCode_hhcurveto:
|
|
||||||
case OpCode_vhcurveto:
|
|
||||||
case OpCode_hvcurveto:
|
|
||||||
case OpCode_hflex:
|
|
||||||
case OpCode_flex:
|
|
||||||
case OpCode_hflex1:
|
|
||||||
case OpCode_flex1:
|
|
||||||
env.clear_stack ();
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
typedef CSOpSet<CFF1Subrs, PARAM> SUPER;
|
typedef CSOpSet<CFF1Subrs, PARAM> SUPER;
|
||||||
if (unlikely (!SUPER::process_op (op, env, param)))
|
if (unlikely (!SUPER::process_op (op, env, param)))
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* 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_CFF2_INTERP_CS_HH
|
||||||
|
#define HB_CFF2_INTERP_CS_HH
|
||||||
|
|
||||||
|
#include "hb-private.hh"
|
||||||
|
#include "hb-cff-interp-cs-common-private.hh"
|
||||||
|
|
||||||
|
namespace CFF {
|
||||||
|
|
||||||
|
using namespace OT;
|
||||||
|
|
||||||
|
struct CFF2CSInterpEnv : CSInterpEnv<CFF2Subrs>
|
||||||
|
{
|
||||||
|
inline void init (const ByteStr &str, const CFF2Subrs &globalSubrs_, const CFF2Subrs &localSubrs_)
|
||||||
|
{
|
||||||
|
CSInterpEnv<CFF2Subrs>::init (str, globalSubrs_, localSubrs_);
|
||||||
|
ivs = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool fetch_op (OpCode &op)
|
||||||
|
{
|
||||||
|
if (unlikely (substr.avail ()))
|
||||||
|
return CSInterpEnv<CFF2Subrs>::fetch_op (op);
|
||||||
|
|
||||||
|
/* make up return or endchar op */
|
||||||
|
if (callStack.check_underflow ())
|
||||||
|
op = OpCode_return;
|
||||||
|
else
|
||||||
|
op = OpCode_endchar;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned int get_ivs (void) const { return ivs; }
|
||||||
|
inline void set_ivs (unsigned int ivs_) { ivs = ivs_; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
unsigned int ivs;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename PARAM>
|
||||||
|
struct CFF2CSOpSet : CSOpSet<CFF2Subrs, PARAM>
|
||||||
|
{
|
||||||
|
static inline bool process_op (OpCode op, CFF2CSInterpEnv &env, PARAM& param)
|
||||||
|
{
|
||||||
|
switch (op) {
|
||||||
|
|
||||||
|
case OpCode_blendcs:
|
||||||
|
env.clear_stack (); // XXX: TODO
|
||||||
|
break;
|
||||||
|
case OpCode_vsindexcs:
|
||||||
|
{
|
||||||
|
unsigned int ivs;
|
||||||
|
if (unlikely (!env.argStack.check_pop_uint (ivs))) return false;
|
||||||
|
env.set_ivs (ivs);
|
||||||
|
env.clear_stack ();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
typedef CSOpSet<CFF2Subrs, PARAM> SUPER;
|
||||||
|
if (unlikely (!SUPER::process_op (op, env, param)))
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename OPSET, typename PARAM>
|
||||||
|
struct CFF2CSInterpreter : CSInterpreter<CFF2CSInterpEnv, OPSET, PARAM> {};
|
||||||
|
|
||||||
|
} /* namespace CFF */
|
||||||
|
|
||||||
|
#endif /* HB_CFF2_INTERP_CS_HH */
|
|
@ -557,6 +557,8 @@ struct Subrs : CFFIndex<COUNT>
|
||||||
inline bool serialize (hb_serialize_context_t *c, const Subrs<COUNT> &subrs, unsigned int offSize, const hb_set_t *set, const ByteStr& nullStr = ByteStr())
|
inline bool serialize (hb_serialize_context_t *c, const Subrs<COUNT> &subrs, unsigned int offSize, const hb_set_t *set, const ByteStr& nullStr = ByteStr())
|
||||||
{
|
{
|
||||||
TRACE_SERIALIZE (this);
|
TRACE_SERIALIZE (this);
|
||||||
|
if (&subrs == &Null(Subrs<COUNT>))
|
||||||
|
return_trace (true);
|
||||||
if ((subrs.count == 0) || (hb_set_get_population (set) == 0))
|
if ((subrs.count == 0) || (hb_set_get_population (set) == 0))
|
||||||
{
|
{
|
||||||
if (!unlikely (c->allocate_size<COUNT> (COUNT::static_size)))
|
if (!unlikely (c->allocate_size<COUNT> (COUNT::static_size)))
|
||||||
|
@ -580,6 +582,8 @@ struct Subrs : CFFIndex<COUNT>
|
||||||
/* in parallel to above */
|
/* in parallel to above */
|
||||||
inline unsigned int calculate_serialized_size (unsigned int &offSize /*OUT*/, const hb_set_t *set, unsigned int nullStrSize = 0) const
|
inline unsigned int calculate_serialized_size (unsigned int &offSize /*OUT*/, const hb_set_t *set, unsigned int nullStrSize = 0) const
|
||||||
{
|
{
|
||||||
|
if (this == &Null(Subrs<COUNT>))
|
||||||
|
return 0;
|
||||||
unsigned int count_ = CFFIndex<COUNT>::count;
|
unsigned int count_ = CFFIndex<COUNT>::count;
|
||||||
offSize = 0;
|
offSize = 0;
|
||||||
if ((count_ == 0) || (hb_set_get_population (set) == 0))
|
if ((count_ == 0) || (hb_set_get_population (set) == 0))
|
||||||
|
|
|
@ -318,6 +318,7 @@ struct CFF2PrivateDictOpSet : DictOpSet
|
||||||
return false;
|
return false;
|
||||||
env.argStack.clear ();
|
env.argStack.clear ();
|
||||||
break;
|
break;
|
||||||
|
case OpCode_vsindexdict:
|
||||||
case OpCode_blenddict:
|
case OpCode_blenddict:
|
||||||
// XXX: TODO
|
// XXX: TODO
|
||||||
return true;
|
return true;
|
||||||
|
@ -442,10 +443,11 @@ struct cff2
|
||||||
if (num_glyphs != sc.get_num_glyphs ())
|
if (num_glyphs != sc.get_num_glyphs ())
|
||||||
{ fini (); return; }
|
{ fini (); return; }
|
||||||
|
|
||||||
privateDicts.resize (fdArray->count);
|
fdCount = fdArray->count;
|
||||||
|
privateDicts.resize (fdCount);
|
||||||
|
|
||||||
/* parse font dicts and gather private dicts */
|
/* parse font dicts and gather private dicts */
|
||||||
for (unsigned int i = 0; i < fdArray->count; i++)
|
for (unsigned int i = 0; i < fdCount; i++)
|
||||||
{
|
{
|
||||||
const ByteStr fontDictStr = (*fdArray)[i];
|
const ByteStr fontDictStr = (*fdArray)[i];
|
||||||
if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; }
|
if (unlikely (!fontDictStr.sanitize (&sc))) { fini (); return; }
|
||||||
|
@ -500,6 +502,7 @@ struct cff2
|
||||||
const CFF2CharStrings *charStrings;
|
const CFF2CharStrings *charStrings;
|
||||||
const CFF2FDArray *fdArray;
|
const CFF2FDArray *fdArray;
|
||||||
const CFF2FDSelect *fdSelect;
|
const CFF2FDSelect *fdSelect;
|
||||||
|
unsigned int fdCount;
|
||||||
|
|
||||||
hb_vector_t<CFF2FontDictValues> fontDicts;
|
hb_vector_t<CFF2FontDictValues> fontDicts;
|
||||||
hb_vector_t<PrivDictVal> privateDicts;
|
hb_vector_t<PrivDictVal> privateDicts;
|
||||||
|
|
|
@ -555,6 +555,7 @@ static inline bool _write_cff1 (const cff_subset_plan &plan,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert (c.head == c.end);
|
||||||
c.end_serialize ();
|
c.end_serialize ();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "hb-subset-cff2.hh"
|
#include "hb-subset-cff2.hh"
|
||||||
#include "hb-subset-plan.hh"
|
#include "hb-subset-plan.hh"
|
||||||
#include "hb-subset-cff-common-private.hh"
|
#include "hb-subset-cff-common-private.hh"
|
||||||
|
#include "hb-cff2-interp-cs.hh"
|
||||||
|
|
||||||
using namespace CFF;
|
using namespace CFF;
|
||||||
|
|
||||||
|
@ -37,6 +38,12 @@ struct CFF2SubTableOffsets {
|
||||||
inline CFF2SubTableOffsets (void)
|
inline CFF2SubTableOffsets (void)
|
||||||
{
|
{
|
||||||
memset (this, 0, sizeof(*this));
|
memset (this, 0, sizeof(*this));
|
||||||
|
localSubrsInfos.init ();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ~CFF2SubTableOffsets (void)
|
||||||
|
{
|
||||||
|
localSubrsInfos.fini ();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int topDictSize;
|
unsigned int topDictSize;
|
||||||
|
@ -45,6 +52,8 @@ struct CFF2SubTableOffsets {
|
||||||
TableInfo FDArrayInfo;
|
TableInfo FDArrayInfo;
|
||||||
TableInfo charStringsInfo;
|
TableInfo charStringsInfo;
|
||||||
unsigned int privateDictsOffset;
|
unsigned int privateDictsOffset;
|
||||||
|
TableInfo globalSubrsInfo;
|
||||||
|
hb_vector_t<TableInfo> localSubrsInfos;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CFF2TopDict_OpSerializer : OpSerializer
|
struct CFF2TopDict_OpSerializer : OpSerializer
|
||||||
|
@ -157,6 +166,31 @@ struct CFF2PrivateDict_OpSerializer : OpSerializer
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct CFF2CSOpSet_SubrSubset : CFF2CSOpSet<SubrRefMapPair>
|
||||||
|
{
|
||||||
|
static inline bool process_op (OpCode op, CFF2CSInterpEnv &env, SubrRefMapPair& refMapPair)
|
||||||
|
{
|
||||||
|
unsigned int subr_num;
|
||||||
|
switch (op) {
|
||||||
|
case OpCode_callsubr:
|
||||||
|
if (!unlikely (env.popSubrNum(env.localSubrs, subr_num)))
|
||||||
|
return false;
|
||||||
|
env.argStack.unpop ();
|
||||||
|
refMapPair.local_map->add (subr_num);
|
||||||
|
break;
|
||||||
|
case OpCode_callgsubr:
|
||||||
|
if (!unlikely (env.popSubrNum(env.globalSubrs, subr_num)))
|
||||||
|
return false;
|
||||||
|
env.argStack.unpop ();
|
||||||
|
refMapPair.global_map->add (subr_num);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return CFF2CSOpSet<SubrRefMapPair>::process_op (op, env, refMapPair);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct cff2_subset_plan {
|
struct cff2_subset_plan {
|
||||||
inline cff2_subset_plan (void)
|
inline cff2_subset_plan (void)
|
||||||
: final_size (0),
|
: final_size (0),
|
||||||
|
@ -176,6 +210,7 @@ struct cff2_subset_plan {
|
||||||
fdmap.fini ();
|
fdmap.fini ();
|
||||||
subset_charstrings.fini ();
|
subset_charstrings.fini ();
|
||||||
privateDictInfos.fini ();
|
privateDictInfos.fini ();
|
||||||
|
subrRefMaps.fini ();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool create (const OT::cff2::accelerator_subset_t &acc,
|
inline bool create (const OT::cff2::accelerator_subset_t &acc,
|
||||||
|
@ -194,8 +229,22 @@ struct cff2_subset_plan {
|
||||||
final_size += offsets.topDictSize;
|
final_size += offsets.topDictSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Subset global & local subrs */
|
||||||
|
{
|
||||||
|
SubrSubsetter<const OT::cff2::accelerator_subset_t, CFF2CSInterpEnv, CFF2CSOpSet_SubrSubset> subsetter(acc, plan->glyphs);
|
||||||
|
if (!subsetter.collect_refs (subrRefMaps))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
offsets.globalSubrsInfo.size = acc.globalSubrs->calculate_serialized_size (offsets.globalSubrsInfo.offSize, subrRefMaps.global_map);
|
||||||
|
if (!offsets.localSubrsInfos.resize (orig_fdcount))
|
||||||
|
return false;
|
||||||
|
for (unsigned int i = 0; i < orig_fdcount; i++)
|
||||||
|
offsets.localSubrsInfos[i].size = acc.privateDicts[i].localSubrs->calculate_serialized_size (offsets.localSubrsInfos[i].offSize, subrRefMaps.local_maps[i]);
|
||||||
|
}
|
||||||
|
|
||||||
/* global subrs */
|
/* global subrs */
|
||||||
final_size += acc.globalSubrs->get_size ();
|
offsets.globalSubrsInfo.offset = final_size;
|
||||||
|
final_size += offsets.globalSubrsInfo.size;
|
||||||
|
|
||||||
/* variation store */
|
/* variation store */
|
||||||
if (acc.varStore != &Null(CFF2VariationStore))
|
if (acc.varStore != &Null(CFF2VariationStore))
|
||||||
|
@ -253,7 +302,7 @@ struct cff2_subset_plan {
|
||||||
CFF2PrivateDict_OpSerializer privSzr;
|
CFF2PrivateDict_OpSerializer privSzr;
|
||||||
TableInfo privInfo = { final_size, PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr), 0 };
|
TableInfo privInfo = { final_size, PrivateDict::calculate_serialized_size (acc.privateDicts[i], privSzr), 0 };
|
||||||
privateDictInfos.push (privInfo);
|
privateDictInfos.push (privInfo);
|
||||||
final_size += privInfo.size + acc.privateDicts[i].localSubrs->get_size ();
|
final_size += privInfo.size + offsets.localSubrsInfos[i].size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,6 +324,8 @@ struct cff2_subset_plan {
|
||||||
|
|
||||||
hb_vector_t<ByteStr> subset_charstrings;
|
hb_vector_t<ByteStr> subset_charstrings;
|
||||||
hb_vector_t<TableInfo> privateDictInfos;
|
hb_vector_t<TableInfo> privateDictInfos;
|
||||||
|
|
||||||
|
SubrRefMaps subrRefMaps;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline bool _write_cff2 (const cff2_subset_plan &plan,
|
static inline bool _write_cff2 (const cff2_subset_plan &plan,
|
||||||
|
@ -312,8 +363,7 @@ static inline bool _write_cff2 (const cff2_subset_plan &plan,
|
||||||
assert (cff2->topDict + plan.offsets.topDictSize == c.head - c.start);
|
assert (cff2->topDict + plan.offsets.topDictSize == c.head - c.start);
|
||||||
CFF2Subrs *dest = c.start_embed<CFF2Subrs> ();
|
CFF2Subrs *dest = c.start_embed<CFF2Subrs> ();
|
||||||
if (unlikely (dest == nullptr)) return false;
|
if (unlikely (dest == nullptr)) return false;
|
||||||
CFFIndex<HBUINT32> *super = dest;
|
if (unlikely (!dest->serialize (&c, *acc.globalSubrs, plan.offsets.globalSubrsInfo.offSize, plan.subrRefMaps.global_map)))
|
||||||
if (unlikely (!super->serialize (&c, *acc.globalSubrs)))
|
|
||||||
{
|
{
|
||||||
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 global subrs");
|
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 global subrs");
|
||||||
return false;
|
return false;
|
||||||
|
@ -409,8 +459,7 @@ static inline bool _write_cff2 (const cff2_subset_plan &plan,
|
||||||
DEBUG_MSG (SUBSET, nullptr, "CFF2 subset: local subrs unexpectedly null [%d]", i);
|
DEBUG_MSG (SUBSET, nullptr, "CFF2 subset: local subrs unexpectedly null [%d]", i);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
CFFIndex<HBUINT32> *super = subrs;
|
if (unlikely (!subrs->serialize (&c, *acc.privateDicts[i].localSubrs, plan.offsets.localSubrsInfos[i].offSize, plan.subrRefMaps.local_maps[i])))
|
||||||
if (unlikely (!super->serialize (&c, *acc.privateDicts[i].localSubrs)))
|
|
||||||
{
|
{
|
||||||
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 local subrs [%d]", i);
|
DEBUG_MSG (SUBSET, nullptr, "failed to serialize CFF2 local subrs [%d]", i);
|
||||||
return false;
|
return false;
|
||||||
|
@ -419,6 +468,7 @@ static inline bool _write_cff2 (const cff2_subset_plan &plan,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert (c.head == c.end);
|
||||||
c.end_serialize ();
|
c.end_serialize ();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
Loading…
Reference in New Issue