[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> <SECTION>
<FILE>hb-ot-glyph</FILE> <FILE>hb-ot-glyph</FILE>
hb_ot_glyph_path_t hb_ot_glyph_decompose_funcs_t
hb_ot_glyph_path_create hb_ot_glyph_decompose_move_to_func_t
hb_ot_glyph_path_create_from_font hb_ot_glyph_decompose_line_to_func_t
hb_ot_glyph_path_destroy hb_ot_glyph_decompose_conic_to_func_t
hb_ot_glyph_path_empty hb_ot_glyph_decompose_cubic_to_func_t
hb_ot_glyph_path_get_commands hb_ot_glyph_decompose
hb_ot_glyph_path_get_coords
hb_ot_glyph_path_reference
</SECTION> </SECTION>
<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 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; path_open = false;
cff = cff_; cff = cff_;
font = font_; font = font_;
points = points_; funcs = funcs_;
commands = commands_; user_data = user_data_;
delta = delta_; delta = delta_;
} }
void start_path () { path_open = true; } 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; } 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; point_t point = p;
if (delta) point.move (*delta); if (delta) point.move (*delta);
points->push (font->em_scalef_x (point.x.to_real ())); funcs->move_to (font->em_scalef_x (point.x.to_real ()), font->em_scalef_y (point.y.to_real ()),
points->push (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; bool path_open;
hb_font_t *font; hb_font_t *font;
hb_vector_t<hb_position_t> *points; hb_ot_glyph_decompose_funcs_t *funcs;
hb_vector_t<uint8_t> *commands; void *user_data;
point_t *delta; point_t *delta;
const OT::cff1::accelerator_t *cff; 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) static void moveto (cff1_cs_interp_env_t &env, cff1_path_param_t& param, const point_t &pt)
{ {
param.end_path (); param.end_path ();
param.move_to (pt);
env.moveto (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) static void line (cff1_cs_interp_env_t &env, cff1_path_param_t& param, const point_t &pt1)
{ {
if (!param.is_path_open ()) if (!param.is_path_open ()) param.start_path ();
{ param.line_to (pt1);
param.start_path ();
param.push_point (env.get_pt ());
}
env.moveto (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) 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 ()) if (!param.is_path_open ()) param.start_path ();
{ param.cubic_to (pt1, pt2, pt3);
param.start_path ();
param.push_point (env.get_pt ());
}
/* include control points */
param.push_point (pt1);
param.push_point (pt2);
env.moveto (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> 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 ()); hb_codepoint_t accent = param.cff->std_code_to_glyph (env.argStack[n-1].to_int ());
if (unlikely (!(!env.in_seac && base && accent 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, base, param.funcs, param.user_data, true)
&& _get_path (param.cff, param.font, accent, param.points, param.commands, true, &delta)))) && _get_path (param.cff, param.font, accent, param.funcs, param.user_data, true, &delta))))
env.set_error (); 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; 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.init (str, *cff, fd);
interp.env.set_in_seac (in_seac); interp.env.set_in_seac (in_seac);
cff1_path_param_t param; 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; if (unlikely (!interp.interpret (param))) return false;
return true; 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 #ifdef HB_NO_OT_FONT_CFF
/* XXX Remove check when this code moves to .hh file. */ /* XXX Remove check when this code moves to .hh file. */
return true; return true;
#endif #endif
return _get_path (this, font, glyph, points, commands); return _get_path (this, font, glyph, funcs, user_data);
} }
struct get_seac_param_t 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_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_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: private:
struct gname_t 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 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; path_open = false;
font = font_; font = font_;
points = points_; funcs = funcs_;
commands = commands_; user_data = user_data_;
} }
void start_path () { path_open = true; } void start_path () { path_open = true; }
void end_path () { path_open = false; } void end_path () { path_open = false; }
bool is_path_open () const { return path_open; } 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 ())); funcs->move_to (font->em_scalef_x (p.x.to_real ()), font->em_scalef_y (p.y.to_real ()),
points->push (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; bool path_open;
hb_font_t *font; hb_font_t *font;
hb_vector_t<hb_position_t> *points; hb_ot_glyph_decompose_funcs_t *funcs;
hb_vector_t<uint8_t> *commands; 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> 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) static void moveto (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt)
{ {
param.end_path (); param.end_path ();
param.move_to (pt);
env.moveto (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) static void line (cff2_cs_interp_env_t &env, cff2_path_param_t& param, const point_t &pt1)
{ {
if (!param.is_path_open ()) if (!param.is_path_open ()) param.start_path ();
{ param.line_to (pt1);
param.start_path ();
param.push_point (env.get_pt ());
}
env.moveto (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) 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 ()) if (!param.is_path_open ()) param.start_path ();
{ param.cubic_to (pt1, pt2, pt3);
param.start_path ();
param.push_point (env.get_pt ());
}
/* include control points */
param.push_point (pt1);
param.push_point (pt2);
env.moveto (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> {}; 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, bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph,
hb_codepoint_t glyph, hb_ot_glyph_decompose_funcs_t *funcs, void *user_data) const
hb_vector_t<hb_position_t> *points,
hb_vector_t<uint8_t> *commands) const
{ {
#ifdef HB_NO_OT_FONT_CFF #ifdef HB_NO_OT_FONT_CFF
/* XXX Remove check when this code moves to .hh file. */ /* 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]; const byte_str_t str = (*charStrings)[glyph];
interp.env.init (str, *this, fd, font->coords, font->num_coords); interp.env.init (str, *this, fd, font->coords, font->num_coords);
cff2_path_param_t param; cff2_path_param_t param;
param.init (font, points, commands); param.init (font, funcs, user_data);
if (unlikely (!interp.interpret (param))) return false; if (unlikely (!interp.interpret (param))) return false;
return true; return true;
} }

View File

@ -533,10 +533,8 @@ struct cff2
HB_INTERNAL bool get_extents (hb_font_t *font, HB_INTERNAL bool get_extents (hb_font_t *font,
hb_codepoint_t glyph, hb_codepoint_t glyph,
hb_glyph_extents_t *extents) const; hb_glyph_extents_t *extents) const;
HB_INTERNAL bool get_path (hb_font_t *font, HB_INTERNAL bool get_path (hb_font_t *font, hb_codepoint_t glyph,
hb_codepoint_t glyph, hb_ot_glyph_decompose_funcs_t *funcs, void *user_data) const;
hb_vector_t<hb_position_t> *points,
hb_vector_t<uint8_t> *commands) const;
}; };
typedef accelerator_templ_t<cff2_private_dict_opset_subset_t, cff2_private_dict_values_subset_t> accelerator_subset_t; 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 (unlikely (!funcs || glyph >= font->face->get_num_glyphs ())) return false;
if (font->face->table.glyf->get_path (font, glyph, funcs, user_data)) return true; if (font->face->table.glyf->get_path (font, glyph, funcs, user_data)) return true;
#ifndef HB_NO_CFF
#ifndef HB_NO_OT_FONT_CFF if (font->face->table.cff1->get_path (font, glyph, funcs, user_data)) return true;
hb_vector_t<hb_position_t> coords; if (font->face->table.cff2->get_path (font, glyph, funcs, user_data)) return true;
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;
#endif #endif
return false; return false;