added CFF2 get_extents

added source hb-ot-cff2-table.cc
augmented VariationData to return scalars
misc bug fixes, renaming, cleanup
This commit is contained in:
Michiharu Ariza 2018-10-08 15:05:36 -07:00
parent 55942ad5c1
commit b51418f596
15 changed files with 426 additions and 141 deletions

View File

@ -30,6 +30,7 @@ HB_BASE_sources = \
hb-ot-cff1-table.hh \
hb-ot-cff1-table.cc \
hb-ot-cff2-table.hh \
hb-ot-cff2-table.cc \
hb-ot-vorg-table.hh \
hb-ot-hdmx-table.hh \
hb-ot-head-table.hh \
@ -227,6 +228,7 @@ HB_SUBSET_sources = \
hb-subset-cff2.cc \
hb-subset-cff-common.cc \
hb-ot-cff1-table.cc \
hb-ot-cff2-table.cc \
hb-subset-input.cc \
hb-subset-input.hh \
hb-subset-plan.cc \

View File

@ -298,19 +298,13 @@ struct Number
inline const Number &operator += (const Number &n)
{
switch (format)
{
default:
case NumInt:
u.int_val += n.to_int ();
break;
case NumFixed:
u.fixed_val += n.to_fixed ();
break;
case NumReal:
u.real_val += n.to_real ();
break;
}
if (format == NumReal || n.format == NumReal)
set_real (to_real () + n.to_real ());
else if (format == NumFixed || n.format == NumFixed)
set_fixed (to_fixed () + n.to_fixed ());
else
set_int (to_int () + n.to_int ());
return *this;
}
@ -453,8 +447,7 @@ struct Stack
inline void fini (void)
{
for (unsigned int i = 0; i < elements.len; i++)
elements[i].fini ();
elements.fini_deep ();
}
inline const ELEM& operator [] (unsigned int i) const
@ -477,12 +470,12 @@ struct Stack
return Crap(ELEM);
}
inline const ELEM& pop (void)
inline ELEM& pop (void)
{
if (likely (count > 0))
return elements[--count];
else
return Null(ELEM);
return Crap(ELEM);
}
inline void pop (unsigned int n)
@ -678,6 +671,16 @@ struct InterpEnv
return true;
}
inline const ARG& eval_arg (unsigned int i)
{
return argStack[i];
}
inline ARG& pop_arg (void)
{
return argStack.pop ();
}
inline void pop_n_args (unsigned int n)
{
assert (n <= argStack.get_count ());

View File

@ -154,19 +154,19 @@ struct CSInterpEnv : InterpEnv<ARG>
inline unsigned int move_x_with_arg (unsigned int i)
{
pt.move_x (SUPER::argStack[i]);
pt.move_x (SUPER::eval_arg (i));
return i + 1;
}
inline unsigned int move_y_with_arg (unsigned int i)
{
pt.move_y (SUPER::argStack[i]);
pt.move_y (SUPER::eval_arg (i));
return i + 1;
}
inline unsigned int move_xy_with_arg (unsigned int i)
{
pt.move (SUPER::argStack[i], SUPER::argStack[i+1]);
pt.move (SUPER::eval_arg (i), SUPER::eval_arg (i+1));
return i + 2;
}
@ -382,8 +382,8 @@ struct PathProcs
static inline void rmoveto (ENV &env, PARAM& param)
{
Point pt1 = env.get_pt ();
const Number &dy = env.argStack.pop ();
const Number &dx = env.argStack.pop ();
const Number &dy = env.pop_arg ();
const Number &dx = env.pop_arg ();
pt1.move (dx, dy);
PATH::moveto (env, param, pt1);
}
@ -391,14 +391,14 @@ struct PathProcs
static inline void hmoveto (ENV &env, PARAM& param)
{
Point pt1 = env.get_pt ();
pt1.move_x (env.argStack.pop ());
pt1.move_x (env.pop_arg ());
PATH::moveto (env, param, pt1);
}
static inline void vmoveto (ENV &env, PARAM& param)
{
Point pt1 = env.get_pt ();
pt1.move_y (env.argStack.pop ());
pt1.move_y (env.pop_arg ());
PATH::moveto (env, param, pt1);
}
@ -407,7 +407,7 @@ struct PathProcs
for (unsigned int i = 0; i + 2 <= env.argStack.get_count (); i += 2)
{
Point pt1 = env.get_pt ();
pt1.move (env.argStack[i], env.argStack[i+1]);
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
PATH::line (env, param, pt1);
}
}
@ -419,15 +419,15 @@ struct PathProcs
for (; i + 2 <= env.argStack.get_count (); i += 2)
{
pt1 = env.get_pt ();
pt1.move_x (env.argStack[i]);
pt1.move_x (env.eval_arg (i));
PATH::line (env, param, pt1);
pt1.move_y (env.argStack[i+1]);
pt1.move_y (env.eval_arg (i+1));
PATH::line (env, param, pt1);
}
if (i < env.argStack.get_count ())
{
pt1 = env.get_pt ();
pt1.move_x (env.argStack[i]);
pt1.move_x (env.eval_arg (i));
PATH::line (env, param, pt1);
}
}
@ -439,15 +439,15 @@ struct PathProcs
for (; i + 2 <= env.argStack.get_count (); i += 2)
{
pt1 = env.get_pt ();
pt1.move_y (env.argStack[i]);
pt1.move_y (env.eval_arg (i));
PATH::line (env, param, pt1);
pt1.move_x (env.argStack[i+1]);
pt1.move_x (env.eval_arg (i+1));
PATH::line (env, param, pt1);
}
if (i < env.argStack.get_count ())
{
pt1 = env.get_pt ();
pt1.move_y (env.argStack[i]);
pt1.move_y (env.eval_arg (i));
PATH::line (env, param, pt1);
}
}
@ -457,11 +457,11 @@ struct PathProcs
for (unsigned int i = 0; i + 6 <= env.argStack.get_count (); i += 6)
{
Point pt1 = env.get_pt ();
pt1.move (env.argStack[i], env.argStack[i+1]);
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
Point pt2 = pt1;
pt2.move (env.argStack[i+2], env.argStack[i+3]);
pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
Point pt3 = pt2;
pt3.move (env.argStack[i+4], env.argStack[i+5]);
pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
PATH::curve (env, param, pt1, pt2, pt3);
}
}
@ -472,17 +472,17 @@ struct PathProcs
for (; i + 6 <= env.argStack.get_count (); i += 6)
{
Point pt1 = env.get_pt ();
pt1.move (env.argStack[i], env.argStack[i+1]);
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
Point pt2 = pt1;
pt2.move (env.argStack[i+2], env.argStack[i+3]);
pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
Point pt3 = pt2;
pt3.move (env.argStack[i+4], env.argStack[i+5]);
pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
PATH::curve (env, param, pt1, pt2, pt3);
}
for (; i + 2 <= env.argStack.get_count (); i += 2)
{
Point pt1 = env.get_pt ();
pt1.move (env.argStack[i], env.argStack[i+1]);
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
PATH::line (env, param, pt1);
}
}
@ -494,17 +494,17 @@ struct PathProcs
for (; i + 2 <= line_limit; i += 2)
{
Point pt1 = env.get_pt ();
pt1.move (env.argStack[i], env.argStack[i+1]);
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
PATH::line (env, param, pt1);
}
for (; i + 6 <= env.argStack.get_count (); i += 6)
{
Point pt1 = env.get_pt ();
pt1.move (env.argStack[i], env.argStack[i+1]);
pt1.move (env.eval_arg (i), env.eval_arg (i+1));
Point pt2 = pt1;
pt2.move (env.argStack[i+2], env.argStack[i+3]);
pt2.move (env.eval_arg (i+2), env.eval_arg (i+3));
Point pt3 = pt2;
pt3.move (env.argStack[i+4], env.argStack[i+5]);
pt3.move (env.eval_arg (i+4), env.eval_arg (i+5));
PATH::curve (env, param, pt1, pt2, pt3);
}
}
@ -514,14 +514,14 @@ struct PathProcs
unsigned int i = 0;
Point pt1 = env.get_pt ();
if ((env.argStack.get_count () & 1) != 0)
pt1.move_x (env.argStack[i++]);
pt1.move_x (env.eval_arg (i++));
for (; i + 4 <= env.argStack.get_count (); i += 4)
{
pt1.move_y (env.argStack[i]);
pt1.move_y (env.eval_arg (i));
Point pt2 = pt1;
pt2.move (env.argStack[i+1], env.argStack[i+2]);
pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
Point pt3 = pt2;
pt3.move_y (env.argStack[i+3]);
pt3.move_y (env.eval_arg (i+3));
PATH::curve (env, param, pt1, pt2, pt3);
pt1 = env.get_pt ();
}
@ -532,14 +532,14 @@ struct PathProcs
unsigned int i = 0;
Point pt1 = env.get_pt ();
if ((env.argStack.get_count () & 1) != 0)
pt1.move_y (env.argStack[i++]);
pt1.move_y (env.eval_arg (i++));
for (; i + 4 <= env.argStack.get_count (); i += 4)
{
pt1.move_x (env.argStack[i]);
pt1.move_x (env.eval_arg (i));
Point pt2 = pt1;
pt2.move (env.argStack[i+1], env.argStack[i+2]);
pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
Point pt3 = pt2;
pt3.move_x (env.argStack[i+3]);
pt3.move_x (env.eval_arg (i+3));
PATH::curve (env, param, pt1, pt2, pt3);
pt1 = env.get_pt ();
}
@ -552,33 +552,33 @@ struct PathProcs
if ((env.argStack.get_count () % 8) >= 4)
{
Point pt1 = env.get_pt ();
pt1.move_y (env.argStack[i]);
pt1.move_y (env.eval_arg (i));
Point pt2 = pt1;
pt2.move (env.argStack[i+1], env.argStack[i+2]);
pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
Point pt3 = pt2;
pt3.move_x (env.argStack[i+3]);
pt3.move_x (env.eval_arg (i+3));
i += 4;
for (; i + 8 <= env.argStack.get_count (); i += 8)
{
PATH::curve (env, param, pt1, pt2, pt3);
pt1 = env.get_pt ();
pt1.move_x (env.argStack[i]);
pt1.move_x (env.eval_arg (i));
pt2 = pt1;
pt2.move (env.argStack[i+1], env.argStack[i+2]);
pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
pt3 = pt2;
pt3.move_y (env.argStack[i+3]);
pt3.move_y (env.eval_arg (i+3));
PATH::curve (env, param, pt1, pt2, pt3);
pt1 = pt3;
pt1.move_y (env.argStack[i+4]);
pt1.move_y (env.eval_arg (i+4));
pt2 = pt1;
pt2.move (env.argStack[i+5], env.argStack[i+6]);
pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
pt3 = pt2;
pt3.move_x (env.argStack[i+7]);
pt3.move_x (env.eval_arg (i+7));
}
if (i < env.argStack.get_count ())
pt3.move_y (env.argStack[i]);
pt3.move_y (env.eval_arg (i));
PATH::curve (env, param, pt1, pt2, pt3);
}
else
@ -586,21 +586,21 @@ struct PathProcs
for (; i + 8 <= env.argStack.get_count (); i += 8)
{
pt1 = env.get_pt ();
pt1.move_y (env.argStack[i]);
pt1.move_y (env.eval_arg (i));
pt2 = pt1;
pt2.move (env.argStack[i+1], env.argStack[i+2]);
pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
pt3 = pt2;
pt3.move_x (env.argStack[i+3]);
pt3.move_x (env.eval_arg (i+3));
PATH::curve (env, param, pt1, pt2, pt3);
pt1 = pt3;
pt1.move_x (env.argStack[i+4]);
pt1.move_x (env.eval_arg (i+4));
pt2 = pt1;
pt2.move (env.argStack[i+5], env.argStack[i+6]);
pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
pt3 = pt2;
pt3.move_y (env.argStack[i+7]);
pt3.move_y (env.eval_arg (i+7));
if ((env.argStack.get_count () - i < 16) && ((env.argStack.get_count () & 1) != 0))
pt3.move_x (env.argStack[i+8]);
pt3.move_x (env.eval_arg (i+8));
PATH::curve (env, param, pt1, pt2, pt3);
}
}
@ -613,33 +613,33 @@ struct PathProcs
if ((env.argStack.get_count () % 8) >= 4)
{
Point pt1 = env.get_pt ();
pt1.move_x (env.argStack[i]);
pt1.move_x (env.eval_arg (i));
Point pt2 = pt1;
pt2.move (env.argStack[i+1], env.argStack[i+2]);
pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
Point pt3 = pt2;
pt3.move_y (env.argStack[i+3]);
pt3.move_y (env.eval_arg (i+3));
i += 4;
for (; i + 8 <= env.argStack.get_count (); i += 8)
{
PATH::curve (env, param, pt1, pt2, pt3);
pt1 = env.get_pt ();
pt1.move_y (env.argStack[i]);
pt1.move_y (env.eval_arg (i));
pt2 = pt1;
pt2.move (env.argStack[i+1], env.argStack[i+2]);
pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
pt3 = pt2;
pt3.move_x (env.argStack[i+3]);
pt3.move_x (env.eval_arg (i+3));
PATH::curve (env, param, pt1, pt2, pt3);
pt1 = pt3;
pt1.move_x (env.argStack[i+4]);
pt1.move_x (env.eval_arg (i+4));
pt2 = pt1;
pt2.move (env.argStack[i+5], env.argStack[i+6]);
pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
pt3 = pt2;
pt3.move_y (env.argStack[i+7]);
pt3.move_y (env.eval_arg (i+7));
}
if (i < env.argStack.get_count ())
pt3.move_x (env.argStack[i]);
pt3.move_x (env.eval_arg (i));
PATH::curve (env, param, pt1, pt2, pt3);
}
else
@ -647,21 +647,21 @@ struct PathProcs
for (; i + 8 <= env.argStack.get_count (); i += 8)
{
pt1 = env.get_pt ();
pt1.move_x (env.argStack[i]);
pt1.move_x (env.eval_arg (i));
pt2 = pt1;
pt2.move (env.argStack[i+1], env.argStack[i+2]);
pt2.move (env.eval_arg (i+1), env.eval_arg (i+2));
pt3 = pt2;
pt3.move_y (env.argStack[i+3]);
pt3.move_y (env.eval_arg (i+3));
PATH::curve (env, param, pt1, pt2, pt3);
pt1 = pt3;
pt1.move_y (env.argStack[i+4]);
pt1.move_y (env.eval_arg (i+4));
pt2 = pt1;
pt2.move (env.argStack[i+5], env.argStack[i+6]);
pt2.move (env.eval_arg (i+5), env.eval_arg (i+6));
pt3 = pt2;
pt3.move_x (env.argStack[i+7]);
pt3.move_x (env.eval_arg (i+7));
if ((env.argStack.get_count () - i < 16) && ((env.argStack.get_count () & 1) != 0))
pt3.move_y (env.argStack[i+8]);
pt3.move_y (env.eval_arg (i+8));
PATH::curve (env, param, pt1, pt2, pt3);
}
}

View File

@ -64,11 +64,7 @@ struct DictValues
inline void fini (void)
{
for (unsigned int i = 0; i < values.len; i++)
{
values[i].fini ();
}
values.fini ();
values.fini_deep ();
}
inline void addOp (OpCode op, const SubByteStr& substr = SubByteStr ())

View File

@ -44,10 +44,7 @@ struct BlendArg : Number
inline void fini (void)
{
Number::fini ();
for (unsigned int i = 0; i < deltas.len; i++)
deltas[i].fini ();
deltas.fini ();
deltas.fini_deep ();
}
inline void set_int (int v) { reset_blends (); Number::set_int (v); }
@ -64,7 +61,7 @@ struct BlendArg : Number
deltas[i] = blends_[i];
}
inline bool blended (void) const { return deltas.len > 0; }
inline bool blending (void) const { return deltas.len > 0; }
inline void reset_blends (void)
{
numValues = valueIndex = 0;
@ -81,11 +78,26 @@ typedef InterpEnv<BlendArg> BlendInterpEnv;
struct CFF2CSInterpEnv : CSInterpEnv<BlendArg, CFF2Subrs>
{
template <typename ACC>
inline void init (const ByteStr &str, ACC &acc, unsigned int fd)
inline void init (const ByteStr &str, ACC &acc, unsigned int fd,
const int *coords_=nullptr, unsigned int coords_count_=0,
const CFF2VariationStore *varStore_=nullptr)
{
SUPER::init (str, *acc.globalSubrs, *acc.privateDicts[fd].localSubrs);
set_region_count (acc.region_count);
set_vsindex (acc.privateDicts[fd].vsindex);
coords = coords_;
num_coords = coords_count_;
varStore = varStore_;
seen_blend = false;
seen_vsindex = false;
scalars.init ();
do_blend = (coords != nullptr) && num_coords && (varStore != &Null(CFF2VariationStore));
set_ivs (acc.privateDicts[fd].ivs);
}
inline void fini (void)
{
scalars.fini ();
SUPER::fini ();
}
inline bool fetch_op (OpCode &op)
@ -101,25 +113,80 @@ struct CFF2CSInterpEnv : CSInterpEnv<BlendArg, CFF2Subrs>
return true;
}
inline const BlendArg& eval_arg (unsigned int i)
{
return blend_arg (argStack[i]);
}
inline const BlendArg& pop_arg (void)
{
return blend_arg (argStack.pop ());
}
inline void process_blend (void)
{
if (!seen_blend)
{
region_count = varStore->varStore.get_region_index_count (get_ivs ());
if (do_blend)
{
scalars.resize (region_count);
varStore->varStore.get_scalars (get_ivs (),
(int *)coords, num_coords,
&scalars[0], region_count);
}
seen_blend = true;
}
}
inline void process_vsindex (void)
{
unsigned int index;
if (likely (argStack.check_pop_uint (index)))
set_vsindex (argStack.check_pop_uint (index));
if (do_blend)
{
unsigned int index;
if (likely (!seen_vsindex && !seen_blend && argStack.check_pop_uint (index)))
set_ivs (argStack.check_pop_uint (index));
}
seen_vsindex = true;
}
inline unsigned int get_region_count (void) const { return region_count; }
inline void set_region_count (unsigned int region_count_) { region_count = region_count_; }
inline unsigned int get_vsindex (void) const { return vsindex; }
inline void set_vsindex (unsigned int vsindex_) { vsindex = vsindex_; }
inline unsigned int get_ivs (void) const { return ivs; }
inline void set_ivs (unsigned int ivs_) { ivs = ivs_; }
protected:
inline BlendArg& blend_arg (BlendArg &arg)
{
if (do_blend && arg.blending ())
{
if (likely (scalars.len == arg.deltas.len))
{
float v = arg.to_real ();
for (unsigned int i = 0; i < scalars.len; i++)
{
v += scalars[i] * arg.deltas[i].to_real ();
}
arg.set_real (v);
arg.deltas.resize (0);
}
}
return arg;
}
protected:
const int *coords;
unsigned int num_coords;
const CFF2VariationStore *varStore;
unsigned int region_count;
unsigned int vsindex;
unsigned int ivs;
hb_vector_t<float> scalars;
bool do_blend;
bool seen_vsindex;
bool seen_blend;
typedef CSInterpEnv<BlendArg, CFF2Subrs> SUPER;
};
template <typename OPSET, typename PARAM, typename PATH=PathProcsNull<CFF2CSInterpEnv, PARAM> >
struct CFF2CSOpSet : CSOpSet<BlendArg, OPSET, CFF2CSInterpEnv, PARAM, PATH>
{
@ -129,7 +196,7 @@ struct CFF2CSOpSet : CSOpSet<BlendArg, OPSET, CFF2CSInterpEnv, PARAM, PATH>
case OpCode_callsubr:
case OpCode_callgsubr:
/* a subroutine number shoudln't be a blended value */
if (unlikely (env.argStack.peek ().blended ()))
if (unlikely (env.argStack.peek ().blending ()))
return false;
return SUPER::process_op (op, env, param);
@ -137,7 +204,7 @@ struct CFF2CSOpSet : CSOpSet<BlendArg, OPSET, CFF2CSInterpEnv, PARAM, PATH>
return OPSET::process_blend (env, param);
case OpCode_vsindexcs:
if (unlikely (env.argStack.peek ().blended ()))
if (unlikely (env.argStack.peek ().blending ()))
return false;
OPSET::process_vsindex (env, param);
break;
@ -152,6 +219,7 @@ struct CFF2CSOpSet : CSOpSet<BlendArg, OPSET, CFF2CSInterpEnv, PARAM, PATH>
{
unsigned int n, k;
env.process_blend ();
k = env.get_region_count ();
if (unlikely (!env.argStack.check_pop_uint (n) ||
(k+1) * n > env.argStack.get_count ()))

View File

@ -1093,9 +1093,7 @@ struct cff1
sc.end_processing ();
topDict.fini ();
fontDicts.fini ();
for (unsigned int i = 0; i < privateDicts.len; i++)
privateDicts[i].fini ();
privateDicts.fini ();
privateDicts.fini_deep ();
hb_blob_destroy (blob);
blob = nullptr;
}

135
src/hb-ot-cff2-table.cc Normal file
View File

@ -0,0 +1,135 @@
/*
* 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-ot-cff2-table.hh"
#include "hb-cff2-interp-cs.hh"
using namespace CFF;
struct ExtentsParam
{
inline void init (void)
{
path_open = false;
min_x.set_int (0x7FFFFFFF);
min_y.set_int (0x7FFFFFFF);
max_x.set_int (-0x80000000);
max_y.set_int (-0x80000000);
}
inline void start_path (void) { path_open = true; }
inline void end_path (void) { path_open = false; }
inline bool is_path_open (void) const { return path_open; }
inline void update_bounds (const Point &pt)
{
if (pt.x < min_x) min_x = pt.x;
if (pt.x > max_x) max_x = pt.x;
if (pt.y < min_y) min_y = pt.y;
if (pt.y > max_y) max_y = pt.y;
}
bool path_open;
Number min_x;
Number min_y;
Number max_x;
Number max_y;
};
struct CFF2PathProcs_Extents : PathProcs<CFF2PathProcs_Extents, CFF2CSInterpEnv, ExtentsParam>
{
static inline void moveto (CFF2CSInterpEnv &env, ExtentsParam& param, const Point &pt)
{
param.end_path ();
env.moveto (pt);
}
static inline void line (CFF2CSInterpEnv &env, ExtentsParam& param, const Point &pt1)
{
if (!param.is_path_open ())
{
param.start_path ();
param.update_bounds (env.get_pt ());
}
env.moveto (pt1);
param.update_bounds (env.get_pt ());
}
static inline void curve (CFF2CSInterpEnv &env, ExtentsParam& param, const Point &pt1, const Point &pt2, const Point &pt3)
{
if (!param.is_path_open ())
{
param.start_path ();
param.update_bounds (env.get_pt ());
}
/* include control points */
param.update_bounds (pt1);
param.update_bounds (pt2);
env.moveto (pt3);
param.update_bounds (env.get_pt ());
}
};
struct CFF2CSOpSet_Extents : CFF2CSOpSet<CFF2CSOpSet_Extents, ExtentsParam, CFF2PathProcs_Extents> {};
bool OT::cff2::accelerator_t::get_extents (hb_codepoint_t glyph,
hb_glyph_extents_t *extents,
const int *coords,
unsigned int num_coords) const
{
if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false;
unsigned int fd = fdSelect->get_fd (glyph);
CFF2CSInterpreter<CFF2CSOpSet_Extents, ExtentsParam> interp;
const ByteStr str = (*charStrings)[glyph];
interp.env.init (str, *this, fd, coords, num_coords, varStore);
ExtentsParam param;
param.init ();
if (unlikely (!interp.interpret (param))) return false;
if (param.min_x >= param.max_x)
{
extents->width = 0;
extents->x_bearing = 0;
}
else
{
extents->x_bearing = (int32_t)param.min_x.floor ();
extents->width = (int32_t)param.max_x.ceil () - extents->x_bearing;
}
if (param.min_y >= param.max_y)
{
extents->height = 0;
extents->y_bearing = 0;
}
else
{
extents->y_bearing = (int32_t)param.max_y.ceil ();
extents->height = (int32_t)param.min_y.floor () - extents->y_bearing;
}
return true;
}

View File

@ -265,7 +265,7 @@ struct CFF2PrivateDictValues_Base : DictValues<VAL>
DictValues<VAL>::init ();
subrsOffset = 0;
localSubrs = &Null(CFF2Subrs);
vsindex = 0;
ivs = 0;
}
inline void fini (void)
@ -286,15 +286,42 @@ struct CFF2PrivateDictValues_Base : DictValues<VAL>
unsigned int subrsOffset;
const CFF2Subrs *localSubrs;
unsigned int vsindex;
unsigned int ivs;
};
typedef CFF2PrivateDictValues_Base<OpStr> CFF2PrivateDictValues_Subset;
typedef CFF2PrivateDictValues_Base<NumDictVal> CFF2PrivateDictValues;
struct CFF2PrivDictInterpEnv : NumInterpEnv
{
inline void init (const ByteStr &str)
{
NumInterpEnv::init (str);
ivs = 0;
seen_vsindex = false;
}
inline void process_vsindex (void)
{
unsigned int index;
if (likely (!seen_vsindex && argStack.check_pop_uint (index)))
{
set_ivs (argStack.check_pop_uint (index));
}
seen_vsindex = true;
}
inline unsigned int get_ivs (void) const { return ivs; }
inline void set_ivs (unsigned int ivs_) { ivs = ivs_; }
protected:
unsigned int ivs;
bool seen_vsindex;
};
struct CFF2PrivateDictOpSet : DictOpSet
{
static inline bool process_op (OpCode op, NumInterpEnv& env, CFF2PrivateDictValues& dictval)
static inline bool process_op (OpCode op, CFF2PrivDictInterpEnv& env, CFF2PrivateDictValues& dictval)
{
NumDictVal val;
val.init ();
@ -327,8 +354,8 @@ struct CFF2PrivateDictOpSet : DictOpSet
env.clear_args ();
break;
case OpCode_vsindexdict:
if (unlikely (!env.argStack.check_pop_uint (dictval.vsindex)))
return false;
env.process_vsindex ();
dictval.ivs = env.get_ivs ();
break;
case OpCode_blenddict:
break;
@ -347,7 +374,7 @@ struct CFF2PrivateDictOpSet : DictOpSet
struct CFF2PrivateDictOpSet_Subset : DictOpSet
{
static inline bool process_op (OpCode op, NumInterpEnv& env, CFF2PrivateDictValues_Subset& dictval)
static inline bool process_op (OpCode op, CFF2PrivDictInterpEnv& env, CFF2PrivateDictValues_Subset& dictval)
{
switch (op) {
case OpCode_BlueValues:
@ -455,11 +482,6 @@ struct cff2
if (num_glyphs != sc.get_num_glyphs ())
{ fini (); return; }
if (varStore != &Null(CFF2VariationStore))
region_count = varStore->varStore.get_region_count ();
else
region_count = 0;
fdCount = fdArray->count;
privateDicts.resize (fdCount);
@ -476,7 +498,7 @@ struct cff2
const ByteStr privDictStr (StructAtOffsetOrNull<UnsizedByteStr> (cff2, font->privateDictInfo.offset), font->privateDictInfo.size);
if (unlikely (!privDictStr.sanitize (&sc))) { fini (); return; }
DictInterpreter<PRIVOPSET, PRIVDICTVAL> priv_interp;
DictInterpreter<PRIVOPSET, PRIVDICTVAL, CFF2PrivDictInterpEnv> priv_interp;
priv_interp.env.init(privDictStr);
if (unlikely (!priv_interp.interpret (privateDicts[i]))) { fini (); return; }
@ -491,25 +513,13 @@ struct cff2
{
sc.end_processing ();
fontDicts.fini ();
for (unsigned int i = 0; i < privateDicts.len; i++)
privateDicts[i].fini ();
privateDicts.fini ();
privateDicts.fini_deep ();
hb_blob_destroy (blob);
blob = nullptr;
}
inline bool is_valid (void) const { return blob != nullptr; }
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;
@ -527,10 +537,16 @@ struct cff2
hb_vector_t<PRIVDICTVAL> privateDicts;
unsigned int num_glyphs;
unsigned int region_count;
};
typedef accelerator_templ_t<CFF2PrivateDictOpSet, CFF2PrivateDictValues> accelerator_t;
struct accelerator_t : accelerator_templ_t<CFF2PrivateDictOpSet, CFF2PrivateDictValues>
{
HB_INTERNAL bool get_extents (hb_codepoint_t glyph,
hb_glyph_extents_t *extents,
const int *coords,
unsigned int num_coords) const;
};
typedef accelerator_templ_t<CFF2PrivateDictOpSet_Subset, CFF2PrivateDictValues_Subset> accelerator_subset_t;
inline bool subset (hb_subset_plan_t *plan) const
@ -560,6 +576,7 @@ struct cff2
DEFINE_SIZE_STATIC (5);
};
struct cff2_accelerator_t : cff2::accelerator_t {};
} /* namespace OT */
#endif /* HB_OT_CFF2_TABLE_HH */

View File

@ -29,6 +29,7 @@
#include "hb-ot-cmap-table.hh"
#include "hb-ot-glyf-table.hh"
#include "hb-ot-cff1-table.hh"
#include "hb-ot-cff2-table.hh"
#include "hb-ot-hmtx-table.hh"
#include "hb-ot-kern-table.hh"
#include "hb-ot-post-table.hh"

View File

@ -69,6 +69,7 @@
HB_OT_ACCELERATOR(OT, kern) \
HB_OT_ACCELERATOR(OT, glyf) \
HB_OT_ACCELERATOR(OT, cff1) \
HB_OT_ACCELERATOR(OT, cff2) \
HB_OT_ACCELERATOR(OT, CBDT) \
/* */

View File

@ -124,9 +124,13 @@ hb_ot_get_glyph_extents (hb_font_t *font,
void *user_data HB_UNUSED)
{
const hb_ot_face_data_t *ot_face = (const hb_ot_face_data_t *) font_data;
unsigned int num_coords;
const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
bool ret = ot_face->glyf->get_extents (glyph, extents);
if (!ret)
ret = ot_face->cff1->get_extents (glyph, extents);
if (!ret)
ret = ot_face->cff2->get_extents (glyph, extents, coords, num_coords);
if (!ret)
ret = ot_face->CBDT->get_extents (glyph, extents);
// TODO Hook up side-bearings variations.

View File

@ -1502,6 +1502,9 @@ struct VarRegionList
struct VarData
{
inline unsigned int get_region_index_count (void) const
{ return regionIndices.len; }
inline unsigned int get_row_size (void) const
{ return shortCount + regionIndices.len; }
@ -1540,6 +1543,18 @@ struct VarData
return delta;
}
inline void get_scalars (int *coords, unsigned int coord_count,
const VarRegionList &regions,
float *scalars /*OUT */,
unsigned int num_scalars) const
{
assert (num_scalars == regionIndices.len);
for (unsigned int i = 0; i < num_scalars; i++)
{
scalars[i] = regions.evaluate (regionIndices.arrayZ[i], coords, coord_count);
}
}
inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
@ -1589,8 +1604,17 @@ struct VariationStore
dataSets.sanitize (c, this));
}
inline unsigned int get_region_count (void) const
{ return (this+regions).get_region_count (); }
inline unsigned int get_region_index_count (unsigned int ivs) const
{ return (this+dataSets[ivs]).get_region_index_count (); }
inline void get_scalars (unsigned int ivs,
int *coords, unsigned int coord_count,
float *scalars /*OUT*/,
unsigned int num_scalars) const
{
(this+dataSets[ivs]).get_scalars (coords, coord_count, this+regions,
&scalars[0], num_scalars);
}
protected:
HBUINT16 format;

View File

@ -304,7 +304,7 @@ struct CFF1CSOpSet_Flatten : CFF1CSOpSet<CFF1CSOpSet_Flatten, FlattenParam>
static inline void flush_args (CFF1CSInterpEnv &env, FlattenParam& param, unsigned int start_arg = 0)
{
for (unsigned int i = start_arg; i < env.argStack.get_count (); i++)
param.flatStr.encode_num (env.argStack[i]);
param.flatStr.encode_num (env.eval_arg (i));
SUPER::flush_args (env, param, start_arg);
}

View File

@ -114,7 +114,7 @@ struct CFF2CSOpSet_Flatten : CFF2CSOpSet<CFF2CSOpSet_Flatten, FlattenParam>
for (unsigned int i = start_arg; i < env.argStack.get_count ();)
{
const BlendArg &arg = env.argStack[i];
if (arg.blended ())
if (arg.blending ())
{
assert ((arg.numValues > 0) && (env.argStack.get_count () - start_arg >= arg.numValues));
flatten_blends (arg, i, env, param);
@ -135,7 +135,7 @@ struct CFF2CSOpSet_Flatten : CFF2CSOpSet<CFF2CSOpSet_Flatten, FlattenParam>
for (unsigned int j = 0; j < arg.numValues; j++)
{
const BlendArg &arg1 = env.argStack[i + j];
assert (arg1.blended () && (arg.numValues == arg1.numValues) && (arg1.valueIndex == j) &&
assert (arg1.blending () && (arg.numValues == arg1.numValues) && (arg1.valueIndex == j) &&
(arg1.deltas.len == env.get_region_count ()));
param.flatStr.encode_num (arg1);
}

View File

@ -54,12 +54,48 @@ test_extents_cff1 (void)
hb_font_destroy (font);
}
static void
test_extents_cff2 (void)
{
hb_blob_t *blob = hb_blob_create_from_file ("fonts/AdobeVFPrototype.abc.otf");
g_assert (blob);
hb_face_t *face = hb_face_create (blob, 0);
hb_blob_destroy (blob);
g_assert (face);
hb_font_t *font = hb_font_create (face);
hb_face_destroy (face);
g_assert (font);
hb_ot_font_set_funcs (font);
hb_glyph_extents_t extents;
hb_bool_t result = hb_font_get_glyph_extents (font, 1, &extents);
g_assert (result);
g_assert_cmpint (extents.x_bearing, ==, 46);
g_assert_cmpint (extents.y_bearing, ==, 487);
g_assert_cmpint (extents.width, ==, 455);
g_assert_cmpint (extents.height, ==, -500);
float coords[2] = { 600.0f, 50.0f };
hb_font_set_var_coords_design (font, coords, 2);
result = hb_font_get_glyph_extents (font, 1, &extents);
g_assert (result);
g_assert_cmpint (extents.x_bearing, ==, 38);
g_assert_cmpint (extents.y_bearing, ==, 493);
g_assert_cmpint (extents.width, ==, 481);
g_assert_cmpint (extents.height, ==, -508);
hb_font_destroy (font);
}
int
main (int argc, char **argv)
{
hb_test_init (&argc, &argv);
hb_test_add (test_extents_cff1);
hb_test_add (test_extents_cff2);
return hb_test_run ();
}