[cff2] Change extents/shape stack to be just a number
Do the blending immediately. Fixes https://github.com/harfbuzz/harfbuzz/issues/3559 Benchmark on AdobeVFPrototype shows 35% speedup. Now we're faster than FreeType: Benchmark Time CPU Time Old Time New CPU Old CPU New ------------------------------------------------------------------------------------------------------------------------------------------------ BM_Font/glyph_extents/AdobeVFPrototype.otf/hb -0.3792 -0.3792 1584 983 1581 982 BM_Font/glyph_extents/AdobeVFPrototype.otf/ft +0.0228 +0.0224 1220 1248 1218 1245 BM_Font/glyph_extents/AdobeVFPrototype.otf/var/hb -0.3513 -0.3518 1616 1048 1613 1046 BM_Font/glyph_extents/AdobeVFPrototype.otf/var/ft +0.0172 +0.0169 1232 1254 1230 1251
This commit is contained in:
parent
5277a5772b
commit
0a42410dc8
|
@ -430,8 +430,8 @@ struct cff_stack_t
|
|||
unsigned int get_count () const { return count; }
|
||||
bool is_empty () const { return !count; }
|
||||
|
||||
hb_array_t<const ELEM> get_subarray (unsigned int start) const
|
||||
{ return hb_array_t<const ELEM> (elements).sub_array (start); }
|
||||
hb_array_t<const ELEM> sub_array (unsigned start, unsigned length) const
|
||||
{ return hb_array_t<const ELEM> (elements).sub_array (start, length); }
|
||||
|
||||
private:
|
||||
bool error;
|
||||
|
|
|
@ -64,7 +64,8 @@ struct blend_arg_t : number_t
|
|||
typedef interp_env_t<blend_arg_t> BlendInterpEnv;
|
||||
typedef biased_subrs_t<CFF2Subrs> cff2_biased_subrs_t;
|
||||
|
||||
struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
|
||||
template <typename ELEM>
|
||||
struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
|
||||
{
|
||||
template <typename ACC>
|
||||
void init (const hb_ubytes_t &str, ACC &acc, unsigned int fd,
|
||||
|
@ -100,18 +101,14 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
|
|||
return OpCode_return;
|
||||
}
|
||||
|
||||
const blend_arg_t& eval_arg (unsigned int i)
|
||||
const ELEM& eval_arg (unsigned int i)
|
||||
{
|
||||
blend_arg_t &arg = argStack[i];
|
||||
blend_arg (arg);
|
||||
return arg;
|
||||
return SUPER::argStack[i];
|
||||
}
|
||||
|
||||
const blend_arg_t& pop_arg ()
|
||||
const ELEM& pop_arg ()
|
||||
{
|
||||
blend_arg_t &arg = argStack.pop ();
|
||||
blend_arg (arg);
|
||||
return arg;
|
||||
return SUPER::argStack.pop ();
|
||||
}
|
||||
|
||||
void process_blend ()
|
||||
|
@ -122,7 +119,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
|
|||
if (do_blend)
|
||||
{
|
||||
if (unlikely (!scalars.resize (region_count)))
|
||||
set_error ();
|
||||
SUPER::set_error ();
|
||||
else
|
||||
varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords,
|
||||
&scalars[0], region_count);
|
||||
|
@ -133,10 +130,10 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
|
|||
|
||||
void process_vsindex ()
|
||||
{
|
||||
unsigned int index = argStack.pop_uint ();
|
||||
unsigned int index = SUPER::argStack.pop_uint ();
|
||||
if (unlikely (seen_vsindex () || seen_blend))
|
||||
{
|
||||
set_error ();
|
||||
SUPER::set_error ();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -151,22 +148,18 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
|
|||
void set_ivs (unsigned int ivs_) { ivs = ivs_; }
|
||||
bool seen_vsindex () const { return seen_vsindex_; }
|
||||
|
||||
protected:
|
||||
void blend_arg (blend_arg_t &arg)
|
||||
double blend_deltas (hb_array_t<const ELEM> deltas) const
|
||||
{
|
||||
if (do_blend && arg.blending ())
|
||||
double v = 0;
|
||||
if (do_blend)
|
||||
{
|
||||
if (likely (scalars.length == arg.deltas.length))
|
||||
if (likely (scalars.length == deltas.length))
|
||||
{
|
||||
double v = arg.to_real ();
|
||||
for (unsigned int i = 0; i < scalars.length; i++)
|
||||
{
|
||||
v += (double)scalars[i] * arg.deltas[i].to_real ();
|
||||
}
|
||||
arg.set_real (v);
|
||||
arg.deltas.resize (0);
|
||||
v += (double) scalars[i] * deltas[i].to_real ();
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
@ -180,22 +173,24 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
|
|||
bool seen_vsindex_;
|
||||
bool seen_blend;
|
||||
|
||||
typedef cs_interp_env_t<blend_arg_t, CFF2Subrs> SUPER;
|
||||
typedef cs_interp_env_t<ELEM, CFF2Subrs> SUPER;
|
||||
};
|
||||
template <typename OPSET, typename PARAM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t, PARAM>>
|
||||
struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH>
|
||||
template <typename OPSET, typename PARAM, typename ELEM, typename PATH=path_procs_null_t<cff2_cs_interp_env_t<ELEM>, PARAM>>
|
||||
struct cff2_cs_opset_t : cs_opset_t<ELEM, OPSET, cff2_cs_interp_env_t<ELEM>, PARAM, PATH>
|
||||
{
|
||||
static void process_op (op_code_t op, cff2_cs_interp_env_t &env, PARAM& param)
|
||||
static void process_op (op_code_t op, cff2_cs_interp_env_t<ELEM> &env, PARAM& param)
|
||||
{
|
||||
switch (op) {
|
||||
case OpCode_callsubr:
|
||||
case OpCode_callgsubr:
|
||||
/* a subroutine number shouldn't be a blended value */
|
||||
#if 0
|
||||
if (unlikely (env.argStack.peek ().blending ()))
|
||||
{
|
||||
env.set_error ();
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
SUPER::process_op (op, env, param);
|
||||
break;
|
||||
|
||||
|
@ -204,11 +199,13 @@ struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PA
|
|||
break;
|
||||
|
||||
case OpCode_vsindexcs:
|
||||
#if 0
|
||||
if (unlikely (env.argStack.peek ().blending ()))
|
||||
{
|
||||
env.set_error ();
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
OPSET::process_vsindex (env, param);
|
||||
break;
|
||||
|
||||
|
@ -217,7 +214,26 @@ struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PA
|
|||
}
|
||||
}
|
||||
|
||||
static void process_blend (cff2_cs_interp_env_t &env, PARAM& param)
|
||||
template <typename T = ELEM,
|
||||
hb_enable_if (hb_is_same (T, blend_arg_t))>
|
||||
static void process_arg_blend (cff2_cs_interp_env_t<ELEM> &env,
|
||||
ELEM &arg,
|
||||
const hb_array_t<const ELEM> blends,
|
||||
unsigned n, unsigned i)
|
||||
{
|
||||
arg.set_blends (n, i, blends.length, blends);
|
||||
}
|
||||
template <typename T = ELEM,
|
||||
hb_enable_if (!hb_is_same (T, blend_arg_t))>
|
||||
static void process_arg_blend (cff2_cs_interp_env_t<ELEM> &env,
|
||||
ELEM &arg,
|
||||
const hb_array_t<const ELEM> blends,
|
||||
unsigned n, unsigned i)
|
||||
{
|
||||
arg.set_real (arg.to_real () + env.blend_deltas (blends));
|
||||
}
|
||||
|
||||
static void process_blend (cff2_cs_interp_env_t<ELEM> &env, PARAM& param)
|
||||
{
|
||||
unsigned int n, k;
|
||||
|
||||
|
@ -234,26 +250,26 @@ struct cff2_cs_opset_t : cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PA
|
|||
}
|
||||
for (unsigned int i = 0; i < n; i++)
|
||||
{
|
||||
const hb_array_t<const blend_arg_t> blends = env.argStack.get_subarray (start + n + (i * k));
|
||||
env.argStack[start + i].set_blends (n, i, k, blends);
|
||||
const hb_array_t<const ELEM> blends = env.argStack.sub_array (start + n + (i * k), k);
|
||||
process_arg_blend (env, env.argStack[start + i], blends, n, i);
|
||||
}
|
||||
|
||||
/* pop off blend values leaving default values now adorned with blend values */
|
||||
env.argStack.pop (k * n);
|
||||
}
|
||||
|
||||
static void process_vsindex (cff2_cs_interp_env_t &env, PARAM& param)
|
||||
static void process_vsindex (cff2_cs_interp_env_t<ELEM> &env, PARAM& param)
|
||||
{
|
||||
env.process_vsindex ();
|
||||
env.clear_args ();
|
||||
}
|
||||
|
||||
private:
|
||||
typedef cs_opset_t<blend_arg_t, OPSET, cff2_cs_interp_env_t, PARAM, PATH> SUPER;
|
||||
typedef cs_opset_t<ELEM, OPSET, cff2_cs_interp_env_t<ELEM>, PARAM, PATH> SUPER;
|
||||
};
|
||||
|
||||
template <typename OPSET, typename PARAM>
|
||||
struct cff2_cs_interpreter_t : cs_interpreter_t<cff2_cs_interp_env_t, OPSET, PARAM> {};
|
||||
template <typename OPSET, typename PARAM, typename ELEM>
|
||||
struct cff2_cs_interpreter_t : cs_interpreter_t<cff2_cs_interp_env_t<ELEM>, OPSET, PARAM> {};
|
||||
|
||||
} /* namespace CFF */
|
||||
|
||||
|
|
|
@ -64,15 +64,15 @@ struct cff2_extents_param_t
|
|||
number_t max_y;
|
||||
};
|
||||
|
||||
struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_cs_interp_env_t, cff2_extents_param_t>
|
||||
struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_cs_interp_env_t<number_t>, cff2_extents_param_t>
|
||||
{
|
||||
static void moveto (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt)
|
||||
static void moveto (cff2_cs_interp_env_t<number_t> &env, cff2_extents_param_t& param, const point_t &pt)
|
||||
{
|
||||
param.end_path ();
|
||||
env.moveto (pt);
|
||||
}
|
||||
|
||||
static void line (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt1)
|
||||
static void line (cff2_cs_interp_env_t<number_t> &env, cff2_extents_param_t& param, const point_t &pt1)
|
||||
{
|
||||
if (!param.is_path_open ())
|
||||
{
|
||||
|
@ -83,7 +83,7 @@ struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_
|
|||
param.update_bounds (env.get_pt ());
|
||||
}
|
||||
|
||||
static void curve (cff2_cs_interp_env_t &env, cff2_extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
|
||||
static void curve (cff2_cs_interp_env_t<number_t> &env, cff2_extents_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
|
||||
{
|
||||
if (!param.is_path_open ())
|
||||
{
|
||||
|
@ -98,7 +98,7 @@ struct cff2_path_procs_extents_t : path_procs_t<cff2_path_procs_extents_t, cff2_
|
|||
}
|
||||
};
|
||||
|
||||
struct cff2_cs_opset_extents_t : cff2_cs_opset_t<cff2_cs_opset_extents_t, cff2_extents_param_t, cff2_path_procs_extents_t> {};
|
||||
struct cff2_cs_opset_extents_t : cff2_cs_opset_t<cff2_cs_opset_extents_t, cff2_extents_param_t, number_t, cff2_path_procs_extents_t> {};
|
||||
|
||||
bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
|
||||
hb_codepoint_t glyph,
|
||||
|
@ -112,7 +112,7 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
|
|||
if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false;
|
||||
|
||||
unsigned int fd = fdSelect->get_fd (glyph);
|
||||
cff2_cs_interpreter_t<cff2_cs_opset_extents_t, cff2_extents_param_t> interp;
|
||||
cff2_cs_interpreter_t<cff2_cs_opset_extents_t, cff2_extents_param_t, number_t> interp;
|
||||
const hb_ubytes_t str = (*charStrings)[glyph];
|
||||
interp.env.init (str, *this, fd, font->coords, font->num_coords);
|
||||
cff2_extents_param_t param;
|
||||
|
@ -169,28 +169,28 @@ struct cff2_path_param_t
|
|||
hb_font_t *font;
|
||||
};
|
||||
|
||||
struct cff2_path_procs_path_t : path_procs_t<cff2_path_procs_path_t, cff2_cs_interp_env_t, cff2_path_param_t>
|
||||
struct cff2_path_procs_path_t : path_procs_t<cff2_path_procs_path_t, cff2_cs_interp_env_t<number_t>, cff2_path_param_t>
|
||||
{
|
||||
static void moveto (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt)
|
||||
static void moveto (cff2_cs_interp_env_t<number_t> &env, cff2_path_param_t& param, const point_t &pt)
|
||||
{
|
||||
param.move_to (pt);
|
||||
env.moveto (pt);
|
||||
}
|
||||
|
||||
static void line (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt1)
|
||||
static void line (cff2_cs_interp_env_t<number_t> &env, cff2_path_param_t& param, const point_t &pt1)
|
||||
{
|
||||
param.line_to (pt1);
|
||||
env.moveto (pt1);
|
||||
}
|
||||
|
||||
static void curve (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
|
||||
static void curve (cff2_cs_interp_env_t<number_t> &env, cff2_path_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
|
||||
{
|
||||
param.cubic_to (pt1, pt2, pt3);
|
||||
env.moveto (pt3);
|
||||
}
|
||||
};
|
||||
|
||||
struct cff2_cs_opset_path_t : cff2_cs_opset_t<cff2_cs_opset_path_t, cff2_path_param_t, cff2_path_procs_path_t> {};
|
||||
struct cff2_cs_opset_path_t : cff2_cs_opset_t<cff2_cs_opset_path_t, cff2_path_param_t, number_t, cff2_path_procs_path_t> {};
|
||||
|
||||
bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_draw_session_t &draw_session) const
|
||||
{
|
||||
|
@ -202,7 +202,7 @@ bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, h
|
|||
if (unlikely (!is_valid () || (glyph >= num_glyphs))) return false;
|
||||
|
||||
unsigned int fd = fdSelect->get_fd (glyph);
|
||||
cff2_cs_interpreter_t<cff2_cs_opset_path_t, cff2_path_param_t> interp;
|
||||
cff2_cs_interpreter_t<cff2_cs_opset_path_t, cff2_path_param_t, number_t> interp;
|
||||
const hb_ubytes_t str = (*charStrings)[glyph];
|
||||
interp.env.init (str, *this, fd, font->coords, font->num_coords);
|
||||
cff2_path_param_t param (font, draw_session);
|
||||
|
|
|
@ -67,9 +67,9 @@ struct cff2_top_dict_op_serializer_t : cff_top_dict_op_serializer_t<>
|
|||
}
|
||||
};
|
||||
|
||||
struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t>
|
||||
struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t, blend_arg_t>
|
||||
{
|
||||
static void flush_args_and_op (op_code_t op, cff2_cs_interp_env_t &env, flatten_param_t& param)
|
||||
static void flush_args_and_op (op_code_t op, cff2_cs_interp_env_t<blend_arg_t> &env, flatten_param_t& param)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
|
@ -97,7 +97,7 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatte
|
|||
}
|
||||
}
|
||||
|
||||
static void flush_args (cff2_cs_interp_env_t &env, flatten_param_t& param)
|
||||
static void flush_args (cff2_cs_interp_env_t<blend_arg_t> &env, flatten_param_t& param)
|
||||
{
|
||||
for (unsigned int i = 0; i < env.argStack.get_count ();)
|
||||
{
|
||||
|
@ -122,7 +122,7 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatte
|
|||
SUPER::flush_args (env, param);
|
||||
}
|
||||
|
||||
static void flatten_blends (const blend_arg_t &arg, unsigned int i, cff2_cs_interp_env_t &env, flatten_param_t& param)
|
||||
static void flatten_blends (const blend_arg_t &arg, unsigned int i, cff2_cs_interp_env_t<blend_arg_t> &env, flatten_param_t& param)
|
||||
{
|
||||
/* flatten the default values */
|
||||
str_encoder_t encoder (param.flatStr);
|
||||
|
@ -149,7 +149,7 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatte
|
|||
encoder.encode_op (OpCode_blendcs);
|
||||
}
|
||||
|
||||
static void flush_op (op_code_t op, cff2_cs_interp_env_t &env, flatten_param_t& param)
|
||||
static void flush_op (op_code_t op, cff2_cs_interp_env_t<blend_arg_t> &env, flatten_param_t& param)
|
||||
{
|
||||
switch (op)
|
||||
{
|
||||
|
@ -163,13 +163,13 @@ struct cff2_cs_opset_flatten_t : cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatte
|
|||
}
|
||||
|
||||
private:
|
||||
typedef cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t> SUPER;
|
||||
typedef cs_opset_t<blend_arg_t, cff2_cs_opset_flatten_t, cff2_cs_opset_flatten_t, cff2_cs_interp_env_t, flatten_param_t> CSOPSET;
|
||||
typedef cff2_cs_opset_t<cff2_cs_opset_flatten_t, flatten_param_t, blend_arg_t> SUPER;
|
||||
typedef cs_opset_t<blend_arg_t, cff2_cs_opset_flatten_t, cff2_cs_opset_flatten_t, cff2_cs_interp_env_t<blend_arg_t>, flatten_param_t> CSOPSET;
|
||||
};
|
||||
|
||||
struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t>
|
||||
struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t, blend_arg_t>
|
||||
{
|
||||
static void process_op (op_code_t op, cff2_cs_interp_env_t &env, subr_subset_param_t& param)
|
||||
static void process_op (op_code_t op, cff2_cs_interp_env_t<blend_arg_t> &env, subr_subset_param_t& param)
|
||||
{
|
||||
switch (op) {
|
||||
|
||||
|
@ -201,7 +201,7 @@ struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t<cff2_cs_opset_subr_subset_t
|
|||
|
||||
protected:
|
||||
static void process_call_subr (op_code_t op, cs_type_t type,
|
||||
cff2_cs_interp_env_t &env, subr_subset_param_t& param,
|
||||
cff2_cs_interp_env_t<blend_arg_t> &env, subr_subset_param_t& param,
|
||||
cff2_biased_subrs_t& subrs, hb_set_t *closure)
|
||||
{
|
||||
byte_str_ref_t str_ref = env.str_ref;
|
||||
|
@ -212,15 +212,15 @@ struct cff2_cs_opset_subr_subset_t : cff2_cs_opset_t<cff2_cs_opset_subr_subset_t
|
|||
}
|
||||
|
||||
private:
|
||||
typedef cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t> SUPER;
|
||||
typedef cff2_cs_opset_t<cff2_cs_opset_subr_subset_t, subr_subset_param_t, blend_arg_t> SUPER;
|
||||
};
|
||||
|
||||
struct cff2_subr_subsetter_t : subr_subsetter_t<cff2_subr_subsetter_t, CFF2Subrs, const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t, cff2_cs_opset_subr_subset_t>
|
||||
struct cff2_subr_subsetter_t : subr_subsetter_t<cff2_subr_subsetter_t, CFF2Subrs, const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t<blend_arg_t>, cff2_cs_opset_subr_subset_t>
|
||||
{
|
||||
cff2_subr_subsetter_t (const OT::cff2::accelerator_subset_t &acc_, const hb_subset_plan_t *plan_)
|
||||
: subr_subsetter_t (acc_, plan_) {}
|
||||
|
||||
static void complete_parsed_str (cff2_cs_interp_env_t &env, subr_subset_param_t& param, parsed_cs_str_t &charstring)
|
||||
static void complete_parsed_str (cff2_cs_interp_env_t<blend_arg_t> &env, subr_subset_param_t& param, parsed_cs_str_t &charstring)
|
||||
{
|
||||
/* vsindex is inserted at the beginning of the charstring as necessary */
|
||||
if (env.seen_vsindex ())
|
||||
|
@ -245,7 +245,7 @@ struct cff2_subset_plan {
|
|||
if (desubroutinize)
|
||||
{
|
||||
/* Flatten global & local subrs */
|
||||
subr_flattener_t<const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t, cff2_cs_opset_flatten_t>
|
||||
subr_flattener_t<const OT::cff2::accelerator_subset_t, cff2_cs_interp_env_t<blend_arg_t>, cff2_cs_opset_flatten_t>
|
||||
flattener(acc, plan);
|
||||
if (!flattener.flatten (subset_charstrings))
|
||||
return false;
|
||||
|
|
Loading…
Reference in New Issue