[ot-glyphs] Move CFF glyph decompose logic to their tables

Thus making path decompose zero alloc on CFF/CFF2
This commit is contained in:
Ebrahim Byagowi 2020-01-10 22:14:46 +03:30
parent 6118523502
commit 084a8182fb
6 changed files with 93 additions and 118 deletions

View File

@ -522,14 +522,12 @@ hb_ot_font_set_funcs
<SECTION>
<FILE>hb-ot-glyph</FILE>
hb_ot_glyph_path_t
hb_ot_glyph_path_create
hb_ot_glyph_path_create_from_font
hb_ot_glyph_path_destroy
hb_ot_glyph_path_empty
hb_ot_glyph_path_get_commands
hb_ot_glyph_path_get_coords
hb_ot_glyph_path_reference
hb_ot_glyph_decompose_funcs_t
hb_ot_glyph_decompose_move_to_func_t
hb_ot_glyph_decompose_line_to_func_t
hb_ot_glyph_decompose_conic_to_func_t
hb_ot_glyph_decompose_cubic_to_func_t
hb_ot_glyph_decompose
</SECTION>
<SECTION>

View File

@ -344,33 +344,57 @@ bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph
struct cff1_path_param_t
{
void init (const OT::cff1::accelerator_t *cff_, hb_font_t *font_, hb_vector_t<hb_position_t> *points_, hb_vector_t<uint8_t> *commands_, point_t *delta_)
void init (const OT::cff1::accelerator_t *cff_, hb_font_t *font_,
hb_ot_glyph_decompose_funcs_t *funcs_, void *user_data_,
point_t *delta_)
{
path_open = false;
cff = cff_;
font = font_;
points = points_;
commands = commands_;
funcs = funcs_;
user_data = user_data_;
delta = delta_;
}
void start_path () { path_open = true; }
void end_path () { if (path_open) push_command ('Z'); path_open = false; }
void end_path () { /* funcs->end_path (); */ path_open = false; }
bool is_path_open () const { return path_open; }
void push_point (const point_t &p)
void move_to (const point_t &p)
{
point_t point = p;
if (delta) point.move (*delta);
points->push (font->em_scalef_x (point.x.to_real ()));
points->push (font->em_scalef_y (point.y.to_real ()));
funcs->move_to (font->em_scalef_x (point.x.to_real ()), font->em_scalef_y (point.y.to_real ()),
user_data);
}
void line_to (const point_t &p)
{
point_t point = p;
if (delta) point.move (*delta);
funcs->line_to (font->em_scalef_x (point.x.to_real ()), font->em_scalef_y (point.y.to_real ()),
user_data);
}
void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3)
{
point_t point1 = p1, point2 = p2, point3 = p3;
if (delta)
{
point1.move (*delta);
point2.move (*delta);
point3.move (*delta);
}
funcs->cubic_to (font->em_scalef_x (point1.x.to_real ()), font->em_scalef_y (point1.y.to_real ()),
font->em_scalef_x (point2.x.to_real ()), font->em_scalef_y (point2.y.to_real ()),
font->em_scalef_x (point3.x.to_real ()), font->em_scalef_y (point3.y.to_real ()),
user_data);
}
void push_command (uint8_t c) { commands->push (c); }
bool path_open;
hb_font_t *font;
hb_vector_t<hb_position_t> *points;
hb_vector_t<uint8_t> *commands;
hb_ot_glyph_decompose_funcs_t *funcs;
void *user_data;
point_t *delta;
const OT::cff1::accelerator_t *cff;
@ -381,39 +405,28 @@ struct cff1_path_procs_path_t : path_procs_t<cff1_path_procs_path_t, cff1_cs_int
static void moveto (cff1_cs_interp_env_t &env, cff1_path_param_t& param, const point_t &pt)
{
param.end_path ();
param.move_to (pt);
env.moveto (pt);
param.push_command ('M');
}
static void line (cff1_cs_interp_env_t &env, cff1_path_param_t& param, const point_t &pt1)
{
if (!param.is_path_open ())
{
param.start_path ();
param.push_point (env.get_pt ());
}
if (!param.is_path_open ()) param.start_path ();
param.line_to (pt1);
env.moveto (pt1);
param.push_point (env.get_pt ());
param.push_command ('L');
}
static void curve (cff1_cs_interp_env_t &env, cff1_path_param_t& param, const point_t &pt1, const point_t &pt2, const point_t &pt3)
{
if (!param.is_path_open ())
{
param.start_path ();
param.push_point (env.get_pt ());
}
/* include control points */
param.push_point (pt1);
param.push_point (pt2);
if (!param.is_path_open ()) param.start_path ();
param.cubic_to (pt1, pt2, pt3);
env.moveto (pt3);
param.push_point (env.get_pt ());
param.push_command ('C');
}
};
static bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph, hb_vector_t<hb_position_t> *points, hb_vector_t<uint8_t> *commands, bool in_seac=false, point_t *delta = nullptr);
static bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph,
hb_ot_glyph_decompose_funcs_t *funcs, void *user_data,
bool in_seac = false, point_t *delta = nullptr);
struct cff1_cs_opset_path_t : cff1_cs_opset_t<cff1_cs_opset_path_t, cff1_path_param_t, cff1_path_procs_path_t>
{
@ -427,13 +440,14 @@ struct cff1_cs_opset_path_t : cff1_cs_opset_t<cff1_cs_opset_path_t, cff1_path_pa
hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ());
if (unlikely (!(!env.in_seac && base && accent
&& _get_path (param.cff, param.font, base, param.points, param.commands, true)
&& _get_path (param.cff, param.font, accent, param.points, param.commands, true, &delta))))
&& _get_path (param.cff, param.font, base, param.funcs, param.user_data, true)
&& _get_path (param.cff, param.font, accent, param.funcs, param.user_data, true, &delta))))
env.set_error ();
}
};
bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph, hb_vector_t<hb_position_t> *points, hb_vector_t<uint8_t> *commands, bool in_seac, point_t *delta)
bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph,
hb_ot_glyph_decompose_funcs_t *funcs, void *user_data, bool in_seac, point_t *delta)
{
if (unlikely (!cff->is_valid () || (glyph >= cff->num_glyphs))) return false;
@ -443,19 +457,20 @@ bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoin
interp.env.init (str, *cff, fd);
interp.env.set_in_seac (in_seac);
cff1_path_param_t param;
param.init (cff, font, points, commands, delta);
param.init (cff, font, funcs, user_data, delta);
if (unlikely (!interp.interpret (param))) return false;
return true;
}
bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph, hb_vector_t<hb_position_t> *points, hb_vector_t<uint8_t> *commands) const
bool OT::cff1::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph,
hb_ot_glyph_decompose_funcs_t *funcs, void *user_data) const
{
#ifdef HB_NO_OT_FONT_CFF
/* XXX Remove check when this code moves to .hh file. */
return true;
#endif
return _get_path (this, font, glyph, points, commands);
return _get_path (this, font, glyph, funcs, user_data);
}
struct get_seac_param_t

View File

@ -1347,7 +1347,8 @@ struct cff1
HB_INTERNAL bool get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const;
HB_INTERNAL bool get_seac_components (hb_codepoint_t glyph, hb_codepoint_t *base, hb_codepoint_t *accent) const;
HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph, hb_vector_t<hb_position_t> *points, hb_vector_t<uint8_t> *commands) const;
HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph,
hb_ot_glyph_decompose_funcs_t *funcs, void *user_data) const;
private:
struct gname_t

View File

@ -144,29 +144,42 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
struct cff2_path_param_t
{
void init (hb_font_t *font_, hb_vector_t<hb_position_t> *points_, hb_vector_t<uint8_t> *commands_)
void init (hb_font_t *font_, hb_ot_glyph_decompose_funcs_t *funcs_, void *user_data_)
{
path_open = false;
font = font_;
points = points_;
commands = commands_;
funcs = funcs_;
user_data = user_data_;
}
void start_path () { path_open = true; }
void end_path () { path_open = false; }
bool is_path_open () const { return path_open; }
void push_point (const point_t &p)
void move_to (const point_t &p)
{
points->push (font->em_scalef_x (p.x.to_real ()));
points->push (font->em_scalef_y (p.y.to_real ()));
funcs->move_to (font->em_scalef_x (p.x.to_real ()), font->em_scalef_y (p.y.to_real ()),
user_data);
}
void line_to (const point_t &p)
{
funcs->line_to (font->em_scalef_x (p.x.to_real ()), font->em_scalef_y (p.y.to_real ()),
user_data);
}
void cubic_to (const point_t &p1, const point_t &p2, const point_t &p3)
{
funcs->cubic_to (font->em_scalef_x (p1.x.to_real ()), font->em_scalef_y (p1.y.to_real ()),
font->em_scalef_x (p2.x.to_real ()), font->em_scalef_y (p2.y.to_real ()),
font->em_scalef_x (p3.x.to_real ()), font->em_scalef_y (p3.y.to_real ()),
user_data);
}
void push_command (uint8_t c) { commands->push (c); }
bool path_open;
hb_font_t *font;
hb_vector_t<hb_position_t> *points;
hb_vector_t<uint8_t> *commands;
hb_ot_glyph_decompose_funcs_t *funcs;
void *user_data;
};
struct cff2_path_procs_path_t : path_procs_t<cff2_path_procs_path_t, cff2_cs_interp_env_t, cff2_path_param_t>
@ -174,44 +187,29 @@ struct cff2_path_procs_path_t : path_procs_t<cff2_path_procs_path_t, cff2_cs_int
static void moveto (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt)
{
param.end_path ();
param.move_to (pt);
env.moveto (pt);
param.push_command ('M');
}
static void line (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt1)
{
if (!param.is_path_open ())
{
param.start_path ();
param.push_point (env.get_pt ());
}
if (!param.is_path_open ()) param.start_path ();
param.line_to (pt1);
env.moveto (pt1);
param.push_point (env.get_pt ());
param.push_command ('L');
}
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)
{
if (!param.is_path_open ())
{
param.start_path ();
param.push_point (env.get_pt ());
}
/* include control points */
param.push_point (pt1);
param.push_point (pt2);
if (!param.is_path_open ()) param.start_path ();
param.cubic_to (pt1, pt2, pt3);
env.moveto (pt3);
param.push_point (env.get_pt ());
param.push_command ('C');
}
};
struct cff2_cs_opset_path_t : cff2_cs_opset_t<cff2_cs_opset_path_t, cff2_path_param_t, cff2_path_procs_path_t> {};
bool OT::cff2::accelerator_t::get_path (hb_font_t *font,
hb_codepoint_t glyph,
hb_vector_t<hb_position_t> *points,
hb_vector_t<uint8_t> *commands) const
bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph,
hb_ot_glyph_decompose_funcs_t *funcs, void *user_data) const
{
#ifdef HB_NO_OT_FONT_CFF
/* XXX Remove check when this code moves to .hh file. */
@ -225,7 +223,7 @@ bool OT::cff2::accelerator_t::get_path (hb_font_t *font,
const byte_str_t str = (*charStrings)[glyph];
interp.env.init (str, *this, fd, font->coords, font->num_coords);
cff2_path_param_t param;
param.init (font, points, commands);
param.init (font, funcs, user_data);
if (unlikely (!interp.interpret (param))) return false;
return true;
}

View File

@ -533,10 +533,8 @@ struct cff2
HB_INTERNAL bool get_extents (hb_font_t *font,
hb_codepoint_t glyph,
hb_glyph_extents_t *extents) const;
HB_INTERNAL bool get_path (hb_font_t *font,
hb_codepoint_t glyph,
hb_vector_t<hb_position_t> *points,
hb_vector_t<uint8_t> *commands) const;
HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph,
hb_ot_glyph_decompose_funcs_t *funcs, void *user_data) const;
};
typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> accelerator_subset_t;

View File

@ -39,44 +39,9 @@ hb_ot_glyph_decompose (hb_font_t *font, hb_codepoint_t glyph,
if (unlikely (!funcs || glyph >= font->face->get_num_glyphs ())) return false;
if (font->face->table.glyf->get_path (font, glyph, funcs, user_data)) return true;
#ifndef HB_NO_OT_FONT_CFF
hb_vector_t<hb_position_t> coords;
hb_vector_t<uint8_t> commands;
bool ret = false;
if (!ret) ret = font->face->table.cff1->get_path (font, glyph, &coords, &commands);
if (!ret) ret = font->face->table.cff2->get_path (font, glyph, &coords, &commands);
if (unlikely (!ret || coords.length % 2 != 0)) return false;
/* FIXME: We should do all these memory O(1) without hb_vector_t
by moving the logic to the tables */
unsigned int coords_idx = 0;
for (unsigned int i = 0; i < commands.length; ++i)
switch (commands[i])
{
case 'Z': break;
case 'M':
if (unlikely (coords.length < coords_idx + 2)) return false;
funcs->move_to (coords[coords_idx + 0], coords[coords_idx + 1], user_data);
coords_idx += 2;
break;
case 'L':
if (unlikely (coords.length < coords_idx + 2)) return false;
funcs->line_to (coords[coords_idx + 0], coords[coords_idx + 1], user_data);
coords_idx += 2;
break;
case 'C':
if (unlikely (coords.length >= coords_idx + 6)) return false;
funcs->cubic_to (coords[coords_idx + 0], coords[coords_idx + 1],
coords[coords_idx + 2], coords[coords_idx + 3],
coords[coords_idx + 4], coords[coords_idx + 5], user_data);
coords_idx += 6;
break;
}
return true;
#ifndef HB_NO_CFF
if (font->face->table.cff1->get_path (font, glyph, funcs, user_data)) return true;
if (font->face->table.cff2->get_path (font, glyph, funcs, user_data)) return true;
#endif
return false;