Merge pull request #2016 from ebraminio/glyf
Implement glyph outline path API
This commit is contained in:
commit
7633b7695e
|
@ -520,6 +520,25 @@ hb_ot_color_palette_get_name_id
|
|||
hb_ot_font_set_funcs
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-ot-glyph</FILE>
|
||||
hb_ot_glyph_decompose_funcs_t
|
||||
hb_ot_glyph_decompose_close_path_func_t
|
||||
hb_ot_glyph_decompose_conic_to_func_t
|
||||
hb_ot_glyph_decompose_cubic_to_func_t
|
||||
hb_ot_glyph_decompose_line_to_func_t
|
||||
hb_ot_glyph_decompose_move_to_func_t
|
||||
hb_ot_glyph_decompose
|
||||
hb_ot_glyph_decompose_funcs_create
|
||||
hb_ot_glyph_decompose_funcs_destroy
|
||||
hb_ot_glyph_decompose_funcs_reference
|
||||
hb_ot_glyph_decompose_funcs_set_close_path_func
|
||||
hb_ot_glyph_decompose_funcs_set_conic_to_func
|
||||
hb_ot_glyph_decompose_funcs_set_cubic_to_func
|
||||
hb_ot_glyph_decompose_funcs_set_line_to_func
|
||||
hb_ot_glyph_decompose_funcs_set_move_to_func
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>hb-ot-name</FILE>
|
||||
hb_ot_name_id_t
|
||||
|
|
|
@ -334,6 +334,7 @@ noinst_PROGRAMS = \
|
|||
test-buffer-serialize \
|
||||
test-ot-meta \
|
||||
test-ot-name \
|
||||
test-ot-glyph \
|
||||
test-ot-glyphname \
|
||||
test-gpos-size-params \
|
||||
test-gsub-would-substitute \
|
||||
|
@ -360,6 +361,10 @@ test_ot_name_SOURCES = test-ot-name.cc
|
|||
test_ot_name_CPPFLAGS = $(HBCFLAGS)
|
||||
test_ot_name_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
||||
test_ot_glyph_SOURCES = test-ot-glyph.cc
|
||||
test_ot_glyph_CPPFLAGS = $(HBCFLAGS)
|
||||
test_ot_glyph_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
||||
test_ot_glyphname_SOURCES = test-ot-glyphname.cc
|
||||
test_ot_glyphname_CPPFLAGS = $(HBCFLAGS)
|
||||
test_ot_glyphname_LDADD = libharfbuzz.la $(HBLIBS)
|
||||
|
|
|
@ -73,6 +73,8 @@ HB_BASE_sources = \
|
|||
hb-ot-font.cc \
|
||||
hb-ot-gasp-table.hh \
|
||||
hb-ot-glyf-table.hh \
|
||||
hb-ot-glyph.cc \
|
||||
hb-ot-glyph.hh \
|
||||
hb-ot-hdmx-table.hh \
|
||||
hb-ot-head-table.hh \
|
||||
hb-ot-hhea-table.hh \
|
||||
|
@ -199,6 +201,7 @@ HB_BASE_headers = \
|
|||
hb-ot-color.h \
|
||||
hb-ot-deprecated.h \
|
||||
hb-ot-font.h \
|
||||
hb-ot-glyph.h \
|
||||
hb-ot-layout.h \
|
||||
hb-ot-math.h \
|
||||
hb-ot-meta.h \
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "hb-ot-color.cc"
|
||||
#include "hb-ot-face.cc"
|
||||
#include "hb-ot-font.cc"
|
||||
#include "hb-ot-glyph.cc"
|
||||
#include "hb-ot-layout.cc"
|
||||
#include "hb-ot-map.cc"
|
||||
#include "hb-ot-math.cc"
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "hb-ot-cff1-table.hh"
|
||||
#include "hb-cff1-interp-cs.hh"
|
||||
#include "hb-ot-glyph.hh"
|
||||
|
||||
using namespace CFF;
|
||||
|
||||
|
@ -342,6 +343,137 @@ bool OT::cff1::accelerator_t::get_extents (hb_font_t *font, hb_codepoint_t glyph
|
|||
return true;
|
||||
}
|
||||
|
||||
struct cff1_path_param_t
|
||||
{
|
||||
cff1_path_param_t (const OT::cff1::accelerator_t *cff_, hb_font_t *font_,
|
||||
const hb_ot_glyph_decompose_funcs_t *funcs_, void *user_data_,
|
||||
point_t *delta_)
|
||||
{
|
||||
path_open = false;
|
||||
cff = cff_;
|
||||
font = font_;
|
||||
funcs = funcs_;
|
||||
user_data = user_data_;
|
||||
delta = delta_;
|
||||
}
|
||||
~cff1_path_param_t () { end_path (); }
|
||||
|
||||
void start_path () { path_open = true; }
|
||||
void end_path () { if (path_open) funcs->close_path (user_data); path_open = false; }
|
||||
bool is_path_open () const { return path_open; }
|
||||
|
||||
void move_to (const point_t &p)
|
||||
{
|
||||
point_t point = p;
|
||||
if (delta) point.move (*delta);
|
||||
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);
|
||||
}
|
||||
|
||||
bool path_open;
|
||||
hb_font_t *font;
|
||||
const hb_ot_glyph_decompose_funcs_t *funcs;
|
||||
void *user_data;
|
||||
point_t *delta;
|
||||
|
||||
const OT::cff1::accelerator_t *cff;
|
||||
};
|
||||
|
||||
struct cff1_path_procs_path_t : path_procs_t<cff1_path_procs_path_t, cff1_cs_interp_env_t, cff1_path_param_t>
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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.line_to (pt1);
|
||||
env.moveto (pt1);
|
||||
}
|
||||
|
||||
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.cubic_to (pt1, pt2, pt3);
|
||||
env.moveto (pt3);
|
||||
}
|
||||
};
|
||||
|
||||
static bool _get_path (const OT::cff1::accelerator_t *cff, hb_font_t *font, hb_codepoint_t glyph,
|
||||
const 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>
|
||||
{
|
||||
static void process_seac (cff1_cs_interp_env_t &env, cff1_path_param_t& param)
|
||||
{
|
||||
unsigned int n = env.argStack.get_count ();
|
||||
point_t delta;
|
||||
delta.x = env.argStack[n-4];
|
||||
delta.y = env.argStack[n-3];
|
||||
hb_codepoint_t base = param.cff->std_code_to_glyph (env.argStack[n-2].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
|
||||
&& _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,
|
||||
const 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;
|
||||
|
||||
unsigned int fd = cff->fdSelect->get_fd (glyph);
|
||||
cff1_cs_interpreter_t<cff1_cs_opset_path_t, cff1_path_param_t> interp;
|
||||
const byte_str_t str = (*cff->charStrings)[glyph];
|
||||
interp.env.init (str, *cff, fd);
|
||||
interp.env.set_in_seac (in_seac);
|
||||
cff1_path_param_t param (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,
|
||||
const 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, funcs, user_data);
|
||||
}
|
||||
|
||||
struct get_seac_param_t
|
||||
{
|
||||
void init (const OT::cff1::accelerator_t *_cff)
|
||||
|
|
|
@ -1347,6 +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,
|
||||
const hb_ot_glyph_decompose_funcs_t *funcs, void *user_data) const;
|
||||
|
||||
private:
|
||||
struct gname_t
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "hb-ot-cff2-table.hh"
|
||||
#include "hb-cff2-interp-cs.hh"
|
||||
#include "hb-ot-glyph.hh"
|
||||
|
||||
using namespace CFF;
|
||||
|
||||
|
@ -142,5 +143,90 @@ bool OT::cff2::accelerator_t::get_extents (hb_font_t *font,
|
|||
return true;
|
||||
}
|
||||
|
||||
struct cff2_path_param_t
|
||||
{
|
||||
cff2_path_param_t (hb_font_t *font_, const hb_ot_glyph_decompose_funcs_t *funcs_, void *user_data_)
|
||||
{
|
||||
path_open = false;
|
||||
font = font_;
|
||||
funcs = funcs_;
|
||||
user_data = user_data_;
|
||||
}
|
||||
~cff2_path_param_t () { end_path (); }
|
||||
|
||||
void start_path () { path_open = true; }
|
||||
void end_path () { if (path_open) funcs->close_path (user_data); path_open = false; }
|
||||
bool is_path_open () const { return path_open; }
|
||||
|
||||
void move_to (const point_t &p)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
bool path_open;
|
||||
hb_font_t *font;
|
||||
const 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>
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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.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)
|
||||
{
|
||||
if (!param.is_path_open ()) param.start_path ();
|
||||
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> {};
|
||||
|
||||
bool OT::cff2::accelerator_t::get_path (hb_font_t *font, hb_codepoint_t glyph,
|
||||
const 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
|
||||
|
||||
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;
|
||||
const byte_str_t str = (*charStrings)[glyph];
|
||||
interp.env.init (str, *this, fd, font->coords, font->num_coords);
|
||||
cff2_path_param_t param (font, funcs, user_data);
|
||||
if (unlikely (!interp.interpret (param))) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -533,6 +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,
|
||||
const 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;
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "hb-ot-head-table.hh"
|
||||
#include "hb-ot-hmtx-table.hh"
|
||||
#include "hb-ot-var-gvar-table.hh"
|
||||
#include "hb-ot-glyph.hh"
|
||||
|
||||
#include <float.h>
|
||||
|
||||
|
@ -391,6 +392,18 @@ struct glyf
|
|||
|
||||
struct Glyph
|
||||
{
|
||||
enum simple_glyph_flag_t
|
||||
{
|
||||
FLAG_ON_CURVE = 0x01,
|
||||
FLAG_X_SHORT = 0x02,
|
||||
FLAG_Y_SHORT = 0x04,
|
||||
FLAG_REPEAT = 0x08,
|
||||
FLAG_X_SAME = 0x10,
|
||||
FLAG_Y_SAME = 0x20,
|
||||
FLAG_RESERVED1 = 0x40,
|
||||
FLAG_RESERVED2 = 0x80
|
||||
};
|
||||
|
||||
private:
|
||||
struct GlyphHeader
|
||||
{
|
||||
|
@ -445,18 +458,6 @@ struct glyf
|
|||
return instructionLength;
|
||||
}
|
||||
|
||||
enum simple_glyph_flag_t
|
||||
{
|
||||
FLAG_ON_CURVE = 0x01,
|
||||
FLAG_X_SHORT = 0x02,
|
||||
FLAG_Y_SHORT = 0x04,
|
||||
FLAG_REPEAT = 0x08,
|
||||
FLAG_X_SAME = 0x10,
|
||||
FLAG_Y_SAME = 0x20,
|
||||
FLAG_RESERVED1 = 0x40,
|
||||
FLAG_RESERVED2 = 0x80
|
||||
};
|
||||
|
||||
const Glyph trim_padding () const
|
||||
{
|
||||
/* based on FontTools _g_l_y_f.py::trim */
|
||||
|
@ -582,7 +583,10 @@ struct glyf
|
|||
end_points_.resize (num_contours);
|
||||
|
||||
for (int i = 0; i < num_contours; i++)
|
||||
{
|
||||
end_points_[i] = endPtsOfContours[i];
|
||||
points_[end_points_[i]].is_end_point = true;
|
||||
}
|
||||
|
||||
/* Skip instructions */
|
||||
const HBUINT8 *p = &StructAtOffset<HBUINT8> (&endPtsOfContours[num_contours + 1],
|
||||
|
@ -838,11 +842,10 @@ struct glyf
|
|||
float min_x, min_y, max_x, max_y;
|
||||
};
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
/* Note: Recursively calls itself.
|
||||
* all_points includes phantom points
|
||||
*/
|
||||
bool get_points_var (hb_codepoint_t gid,
|
||||
bool _get_points (hb_codepoint_t gid,
|
||||
const int *coords, unsigned int coord_count,
|
||||
contour_point_vector_t &all_points /* OUT */,
|
||||
unsigned int depth = 0) const
|
||||
|
@ -854,17 +857,19 @@ struct glyf
|
|||
if (unlikely (!glyph.get_contour_points (points, end_points))) return false;
|
||||
hb_array_t<contour_point_t> phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
|
||||
init_phantom_points (gid, phantoms);
|
||||
#ifndef HB_NO_VAR
|
||||
if (unlikely (!face->table.gvar->apply_deltas_to_points (gid, coords, coord_count, points.as_array (), end_points.as_array ()))) return false;
|
||||
#endif
|
||||
|
||||
unsigned int comp_index = 0;
|
||||
if (glyph.is_simple_glyph ())
|
||||
all_points.extend (points.as_array ());
|
||||
else if (glyph.is_composite_glyph ())
|
||||
{
|
||||
unsigned int comp_index = 0;
|
||||
for (auto &item : glyph.get_composite_iterator ())
|
||||
{
|
||||
contour_point_vector_t comp_points;
|
||||
if (unlikely (!get_points_var (item.glyphIndex, coords, coord_count,
|
||||
if (unlikely (!_get_points (item.glyphIndex, coords, coord_count,
|
||||
comp_points, depth))
|
||||
|| comp_points.length < PHANTOM_COUNT)
|
||||
return false;
|
||||
|
@ -906,9 +911,9 @@ struct glyf
|
|||
return true;
|
||||
}
|
||||
|
||||
bool get_points_bearing_applied (hb_font_t *font, hb_codepoint_t gid, contour_point_vector_t &all_points) const
|
||||
bool get_points (hb_font_t *font, hb_codepoint_t gid, contour_point_vector_t &all_points) const
|
||||
{
|
||||
if (unlikely (!get_points_var (gid, font->coords, font->num_coords, all_points) ||
|
||||
if (unlikely (!_get_points (gid, font->coords, font->num_coords, all_points) ||
|
||||
all_points.length < PHANTOM_COUNT)) return false;
|
||||
|
||||
/* Undocumented rasterizer behavior:
|
||||
|
@ -920,14 +925,13 @@ struct glyf
|
|||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
#ifndef HB_NO_VAR
|
||||
bool get_var_extents_and_phantoms (hb_font_t *font, hb_codepoint_t gid,
|
||||
hb_glyph_extents_t *extents=nullptr /* OUT */,
|
||||
contour_point_vector_t *phantoms=nullptr /* OUT */) const
|
||||
hb_glyph_extents_t *extents /* OUT */,
|
||||
contour_point_vector_t *phantoms /* OUT */) const
|
||||
{
|
||||
contour_point_vector_t all_points;
|
||||
if (unlikely (!get_points_bearing_applied (font, gid, all_points))) return false;
|
||||
if (unlikely (!get_points (font, gid, all_points))) return false;
|
||||
if (extents)
|
||||
{
|
||||
contour_bounds_t bounds;
|
||||
|
@ -947,7 +951,7 @@ struct glyf
|
|||
|
||||
bool get_extents_var (hb_font_t *font, hb_codepoint_t gid,
|
||||
hb_glyph_extents_t *extents) const
|
||||
{ return get_var_extents_and_phantoms (font, gid, extents); }
|
||||
{ return get_var_extents_and_phantoms (font, gid, extents, nullptr); }
|
||||
#endif
|
||||
|
||||
public:
|
||||
|
@ -1039,6 +1043,66 @@ struct glyf
|
|||
add_gid_and_children (item.glyphIndex, gids_to_retain, depth);
|
||||
}
|
||||
|
||||
bool
|
||||
get_path (hb_font_t *font, hb_codepoint_t gid,
|
||||
const hb_ot_glyph_decompose_funcs_t *funcs, void *user_data) const
|
||||
{
|
||||
/* Making this completely alloc free is not that easy
|
||||
https://github.com/harfbuzz/harfbuzz/issues/2095
|
||||
mostly because of gvar handling in VF fonts,
|
||||
perhaps a separate path can be considered */
|
||||
contour_point_vector_t all_points;
|
||||
if (unlikely (!get_points (font, gid, all_points))) return false;
|
||||
hb_array_t<contour_point_t> points = all_points.sub_array (0, all_points.length - 4);
|
||||
|
||||
unsigned contour_start = 0;
|
||||
/* Learnt from https://github.com/opentypejs/opentype.js/blob/4e0bb99/src/tables/glyf.js#L222 */
|
||||
while (contour_start < points.length)
|
||||
{
|
||||
unsigned contour_length = 0;
|
||||
for (unsigned i = contour_start; i < points.length; ++i)
|
||||
{
|
||||
contour_length++;
|
||||
if (points[i].is_end_point)
|
||||
break;
|
||||
}
|
||||
contour_point_t *curr = &points[contour_start + contour_length - 1];
|
||||
contour_point_t *next = &points[contour_start];
|
||||
|
||||
if (curr->flag & Glyph::FLAG_ON_CURVE)
|
||||
funcs->move_to (font->em_scalef_x (curr->x), font->em_scalef_y (curr->y), user_data);
|
||||
else
|
||||
{
|
||||
if (next->flag & Glyph::FLAG_ON_CURVE)
|
||||
funcs->move_to (font->em_scalef_x (next->x), font->em_scalef_y (next->y), user_data);
|
||||
else
|
||||
/* If both first and last points are off-curve, start at their middle. */
|
||||
funcs->move_to (font->em_scalef_x ((curr->x + next->x) / 2.f),
|
||||
font->em_scalef_y ((curr->y + next->y) / 2.f), user_data);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < contour_length; ++i)
|
||||
{
|
||||
curr = next;
|
||||
next = &points[contour_start + ((i + 1) % contour_length)];
|
||||
|
||||
if (curr->flag & Glyph::FLAG_ON_CURVE)
|
||||
funcs->line_to (font->em_scalef_x (curr->x), font->em_scalef_y (curr->y), user_data);
|
||||
else
|
||||
{
|
||||
float to_x, to_y;
|
||||
if (next->flag & Glyph::FLAG_ON_CURVE) { to_x = next->x; to_y = next->y; }
|
||||
else { to_x = (curr->x + next->x) / 2.f; to_y = (curr->y + next->y) / 2.f; }
|
||||
funcs->conic_to (font->em_scalef_x (curr->x), font->em_scalef_y (curr->y),
|
||||
font->em_scalef_x (to_x), font->em_scalef_y (to_y), user_data);
|
||||
}
|
||||
}
|
||||
contour_start += contour_length;
|
||||
funcs->close_path (user_data);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool short_offset;
|
||||
unsigned int num_glyphs;
|
||||
|
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* Copyright © 2019-2020 Ebrahim Byagowi
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
#ifndef HB_NO_OT_GLYPH
|
||||
|
||||
#include "hb-ot.h"
|
||||
#include "hb-ot-glyf-table.hh"
|
||||
#include "hb-ot-cff1-table.hh"
|
||||
#include "hb-ot-cff2-table.hh"
|
||||
#include "hb-ot-glyph.hh"
|
||||
|
||||
/**
|
||||
* hb_ot_glyph_decompose_funcs_set_move_to_func:
|
||||
* @funcs: decompose functions object
|
||||
* @move_to: move-to callback
|
||||
*
|
||||
* Sets move-to callback to the decompose functions object.
|
||||
*
|
||||
* Since: REPLACEME
|
||||
**/
|
||||
void
|
||||
hb_ot_glyph_decompose_funcs_set_move_to_func (hb_ot_glyph_decompose_funcs_t *funcs,
|
||||
hb_ot_glyph_decompose_move_to_func_t move_to)
|
||||
{
|
||||
if (unlikely (funcs == &Null (hb_ot_glyph_decompose_funcs_t))) return;
|
||||
funcs->move_to = move_to;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ot_glyph_decompose_funcs_set_line_to_func:
|
||||
* @funcs: decompose functions object
|
||||
* @line_to: line-to callback
|
||||
*
|
||||
* Sets line-to callback to the decompose functions object.
|
||||
*
|
||||
* Since: REPLACEME
|
||||
**/
|
||||
void
|
||||
hb_ot_glyph_decompose_funcs_set_line_to_func (hb_ot_glyph_decompose_funcs_t *funcs,
|
||||
hb_ot_glyph_decompose_line_to_func_t line_to)
|
||||
{
|
||||
if (unlikely (funcs == &Null (hb_ot_glyph_decompose_funcs_t))) return;
|
||||
funcs->line_to = line_to;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ot_glyph_decompose_funcs_set_conic_to_func:
|
||||
* @funcs: decompose functions object
|
||||
* @move_to: conic-to callback
|
||||
*
|
||||
* Sets conic-to callback to the decompose functions object.
|
||||
*
|
||||
* Since: REPLACEME
|
||||
**/
|
||||
void
|
||||
hb_ot_glyph_decompose_funcs_set_conic_to_func (hb_ot_glyph_decompose_funcs_t *funcs,
|
||||
hb_ot_glyph_decompose_conic_to_func_t conic_to)
|
||||
{
|
||||
if (unlikely (funcs == &Null (hb_ot_glyph_decompose_funcs_t))) return;
|
||||
funcs->conic_to = conic_to;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ot_glyph_decompose_funcs_set_cubic_to_func:
|
||||
* @funcs: decompose functions
|
||||
* @cubic_to: cubic-to callback
|
||||
*
|
||||
* Sets cubic-to callback to the decompose functions object.
|
||||
*
|
||||
* Since: REPLACEME
|
||||
**/
|
||||
void
|
||||
hb_ot_glyph_decompose_funcs_set_cubic_to_func (hb_ot_glyph_decompose_funcs_t *funcs,
|
||||
hb_ot_glyph_decompose_cubic_to_func_t cubic_to)
|
||||
{
|
||||
if (unlikely (funcs == &Null (hb_ot_glyph_decompose_funcs_t))) return;
|
||||
funcs->cubic_to = cubic_to;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ot_glyph_decompose_funcs_set_close_path_func:
|
||||
* @funcs: decompose functions object
|
||||
* @close_path: close-path callback
|
||||
*
|
||||
* Sets close-path callback to the decompose functions object.
|
||||
*
|
||||
* Since: REPLACEME
|
||||
**/
|
||||
void
|
||||
hb_ot_glyph_decompose_funcs_set_close_path_func (hb_ot_glyph_decompose_funcs_t *funcs,
|
||||
hb_ot_glyph_decompose_close_path_func_t close_path)
|
||||
{
|
||||
if (unlikely (funcs == &Null (hb_ot_glyph_decompose_funcs_t))) return;
|
||||
funcs->close_path = close_path;
|
||||
}
|
||||
|
||||
static void
|
||||
_move_to_nil (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {}
|
||||
|
||||
static void
|
||||
_line_to_nil (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {}
|
||||
|
||||
static void
|
||||
_conic_to_nil (hb_position_t control_x HB_UNUSED, hb_position_t control_y HB_UNUSED,
|
||||
hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED,
|
||||
void *user_data HB_UNUSED) {}
|
||||
static void
|
||||
_cubic_to_nil (hb_position_t control1_x HB_UNUSED, hb_position_t control1_y HB_UNUSED,
|
||||
hb_position_t control2_x HB_UNUSED, hb_position_t control2_y HB_UNUSED,
|
||||
hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED,
|
||||
void *user_data HB_UNUSED) {}
|
||||
|
||||
static void
|
||||
_close_path_nil (void *user_data HB_UNUSED) {}
|
||||
|
||||
/**
|
||||
* hb_ot_glyph_decompose_funcs_create:
|
||||
*
|
||||
* Creates a new decompose callbacks object.
|
||||
*
|
||||
* Since: REPLACEME
|
||||
**/
|
||||
hb_ot_glyph_decompose_funcs_t *
|
||||
hb_ot_glyph_decompose_funcs_create ()
|
||||
{
|
||||
hb_ot_glyph_decompose_funcs_t *funcs;
|
||||
if (unlikely (!(funcs = hb_object_create<hb_ot_glyph_decompose_funcs_t> ())))
|
||||
return const_cast<hb_ot_glyph_decompose_funcs_t *> (&Null (hb_ot_glyph_decompose_funcs_t));
|
||||
|
||||
funcs->move_to = (hb_ot_glyph_decompose_move_to_func_t) _move_to_nil;
|
||||
funcs->line_to = (hb_ot_glyph_decompose_line_to_func_t) _line_to_nil;
|
||||
funcs->conic_to = (hb_ot_glyph_decompose_conic_to_func_t) _conic_to_nil;
|
||||
funcs->cubic_to = (hb_ot_glyph_decompose_cubic_to_func_t) _cubic_to_nil;
|
||||
funcs->close_path = (hb_ot_glyph_decompose_close_path_func_t) _close_path_nil;
|
||||
return funcs;
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ot_glyph_decompose_funcs_reference:
|
||||
* @funcs: decompose functions
|
||||
*
|
||||
* Add to callbacks object refcount.
|
||||
*
|
||||
* Returns: The same object.
|
||||
* Since: REPLACEME
|
||||
**/
|
||||
hb_ot_glyph_decompose_funcs_t *
|
||||
hb_ot_glyph_decompose_funcs_reference (hb_ot_glyph_decompose_funcs_t *funcs)
|
||||
{
|
||||
return hb_object_reference (funcs);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ot_glyph_decompose_funcs_destroy:
|
||||
* @funcs: decompose functions
|
||||
*
|
||||
* Decreases refcount of callbacks object and deletes the object if it reaches
|
||||
* to zero.
|
||||
*
|
||||
* Since: REPLACEME
|
||||
**/
|
||||
void
|
||||
hb_ot_glyph_decompose_funcs_destroy (hb_ot_glyph_decompose_funcs_t *funcs)
|
||||
{
|
||||
if (!hb_object_destroy (funcs)) return;
|
||||
|
||||
free (funcs);
|
||||
}
|
||||
|
||||
/**
|
||||
* hb_ot_glyph_decompose:
|
||||
* @font: a font object
|
||||
* @glyph: a glyph id
|
||||
* @funcs: decompose callbacks object
|
||||
* @user_data: parameter you like be passed to the callbacks when are called
|
||||
*
|
||||
* Decomposes a glyph.
|
||||
*
|
||||
* Returns: Whether the font had the glyph and the operation completed successfully.
|
||||
* Since: REPLACEME
|
||||
**/
|
||||
hb_bool_t
|
||||
hb_ot_glyph_decompose (hb_font_t *font, hb_codepoint_t glyph,
|
||||
const hb_ot_glyph_decompose_funcs_t *funcs,
|
||||
void *user_data)
|
||||
{
|
||||
if (unlikely (!funcs || funcs == &Null (hb_ot_glyph_decompose_funcs_t) ||
|
||||
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_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;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
* Copyright © 2019-2020 Ebrahim Byagowi
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef HB_OT_H_IN
|
||||
#error "Include <hb-ot.h> instead."
|
||||
#endif
|
||||
|
||||
#ifndef HB_OT_GLYPH_H
|
||||
#define HB_OT_GLYPH_H
|
||||
|
||||
#include "hb.h"
|
||||
|
||||
HB_BEGIN_DECLS
|
||||
|
||||
typedef void (*hb_ot_glyph_decompose_move_to_func_t) (hb_position_t to_x, hb_position_t to_y, void *user_data);
|
||||
typedef void (*hb_ot_glyph_decompose_line_to_func_t) (hb_position_t to_x, hb_position_t to_y, void *user_data);
|
||||
typedef void (*hb_ot_glyph_decompose_conic_to_func_t) (hb_position_t control_x, hb_position_t control_y,
|
||||
hb_position_t to_x, hb_position_t to_y,
|
||||
void *user_data);
|
||||
typedef void (*hb_ot_glyph_decompose_cubic_to_func_t) (hb_position_t control1_x, hb_position_t control1_y,
|
||||
hb_position_t control2_x, hb_position_t control2_y,
|
||||
hb_position_t to_x, hb_position_t to_y,
|
||||
void *user_data);
|
||||
typedef void (*hb_ot_glyph_decompose_close_path_func_t) (void *user_data);
|
||||
|
||||
/**
|
||||
* hb_ot_glyph_decompose_funcs_t:
|
||||
*
|
||||
* Glyph decompose callbacks.
|
||||
*
|
||||
* Since: REPLACEME
|
||||
**/
|
||||
typedef struct hb_ot_glyph_decompose_funcs_t hb_ot_glyph_decompose_funcs_t;
|
||||
|
||||
HB_EXTERN void
|
||||
hb_ot_glyph_decompose_funcs_set_move_to_func (hb_ot_glyph_decompose_funcs_t *funcs,
|
||||
hb_ot_glyph_decompose_move_to_func_t move_to);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_ot_glyph_decompose_funcs_set_line_to_func (hb_ot_glyph_decompose_funcs_t *funcs,
|
||||
hb_ot_glyph_decompose_move_to_func_t line_to);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_ot_glyph_decompose_funcs_set_conic_to_func (hb_ot_glyph_decompose_funcs_t *funcs,
|
||||
hb_ot_glyph_decompose_conic_to_func_t conic_to);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_ot_glyph_decompose_funcs_set_cubic_to_func (hb_ot_glyph_decompose_funcs_t *funcs,
|
||||
hb_ot_glyph_decompose_cubic_to_func_t cubic_to);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_ot_glyph_decompose_funcs_set_close_path_func (hb_ot_glyph_decompose_funcs_t *funcs,
|
||||
hb_ot_glyph_decompose_close_path_func_t close_path);
|
||||
|
||||
HB_EXTERN hb_ot_glyph_decompose_funcs_t *
|
||||
hb_ot_glyph_decompose_funcs_create (void);
|
||||
|
||||
HB_EXTERN hb_ot_glyph_decompose_funcs_t *
|
||||
hb_ot_glyph_decompose_funcs_reference (hb_ot_glyph_decompose_funcs_t *funcs);
|
||||
|
||||
HB_EXTERN void
|
||||
hb_ot_glyph_decompose_funcs_destroy (hb_ot_glyph_decompose_funcs_t *funcs);
|
||||
|
||||
HB_EXTERN hb_bool_t
|
||||
hb_ot_glyph_decompose (hb_font_t *font, hb_codepoint_t glyph,
|
||||
const hb_ot_glyph_decompose_funcs_t *funcs,
|
||||
void *user_data);
|
||||
|
||||
HB_END_DECLS
|
||||
|
||||
#endif /* HB_OT_GLYPH_H */
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright © 2020 Ebrahim Byagowi
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* Red Hat Author(s): Behdad Esfahbod
|
||||
* Google Author(s): Behdad Esfahbod
|
||||
*/
|
||||
|
||||
#ifndef HB_OT_GLYPH_HH
|
||||
#define HB_OT_GLYPH_HH
|
||||
|
||||
#include "hb.hh"
|
||||
|
||||
struct hb_ot_glyph_decompose_funcs_t
|
||||
{
|
||||
hb_object_header_t header;
|
||||
|
||||
hb_ot_glyph_decompose_move_to_func_t move_to;
|
||||
hb_ot_glyph_decompose_line_to_func_t line_to;
|
||||
hb_ot_glyph_decompose_conic_to_func_t conic_to;
|
||||
hb_ot_glyph_decompose_cubic_to_func_t cubic_to;
|
||||
hb_ot_glyph_decompose_close_path_func_t close_path;
|
||||
};
|
||||
|
||||
|
||||
#endif /* HB_OT_GLYPH_HH */
|
|
@ -41,12 +41,14 @@ namespace OT {
|
|||
|
||||
struct contour_point_t
|
||||
{
|
||||
void init (float x_=0.f, float y_=0.f) { flag = 0; x = x_; y = y_; }
|
||||
void init (float x_ = 0.f, float y_ = 0.f, bool is_end_point_ = false)
|
||||
{ flag = 0; x = x_; y = y_; is_end_point = is_end_point_; }
|
||||
|
||||
void translate (const contour_point_t &p) { x += p.x; y += p.y; }
|
||||
|
||||
uint8_t flag;
|
||||
float x, y;
|
||||
bool is_end_point;
|
||||
};
|
||||
|
||||
struct contour_point_vector_t : hb_vector_t<contour_point_t>
|
||||
|
@ -562,6 +564,7 @@ struct gvar
|
|||
const hb_array_t<contour_point_t> points,
|
||||
const hb_array_t<unsigned int> end_points) const
|
||||
{
|
||||
if (!coord_count) return true;
|
||||
if (unlikely (coord_count != gvar_table->axisCount)) return false;
|
||||
|
||||
const GlyphVarData *var_data = gvar_table->get_glyph_var_data (glyph);
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "hb-ot-color.h"
|
||||
#include "hb-ot-deprecated.h"
|
||||
#include "hb-ot-font.h"
|
||||
#include "hb-ot-glyph.h"
|
||||
#include "hb-ot-layout.h"
|
||||
#include "hb-ot-math.h"
|
||||
#include "hb-ot-meta.h"
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
/*
|
||||
* Copyright © 2019 Ebrahim Byagowi
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "hb-ot.h"
|
||||
|
||||
#ifdef HB_NO_OPEN
|
||||
#define hb_blob_create_from_file(x) hb_blob_get_empty ()
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
struct user_data_t
|
||||
{
|
||||
FILE *f;
|
||||
hb_position_t ascender;
|
||||
};
|
||||
|
||||
static void
|
||||
move_to (hb_position_t to_x, hb_position_t to_y, user_data_t &user_data)
|
||||
{
|
||||
fprintf (user_data.f, "M%d,%d", to_x, user_data.ascender - to_y);
|
||||
}
|
||||
|
||||
static void
|
||||
line_to (hb_position_t to_x, hb_position_t to_y, user_data_t &user_data)
|
||||
{
|
||||
fprintf (user_data.f, "L%d,%d", to_x, user_data.ascender - to_y);
|
||||
}
|
||||
|
||||
static void
|
||||
conic_to (hb_position_t control_x, hb_position_t control_y,
|
||||
hb_position_t to_x, hb_position_t to_y,
|
||||
user_data_t &user_data)
|
||||
{
|
||||
fprintf (user_data.f, "Q%d,%d %d,%d", control_x, user_data.ascender - control_y,
|
||||
to_x, user_data.ascender - to_y);
|
||||
}
|
||||
|
||||
static void
|
||||
cubic_to (hb_position_t control1_x, hb_position_t control1_y,
|
||||
hb_position_t control2_x, hb_position_t control2_y,
|
||||
hb_position_t to_x, hb_position_t to_y,
|
||||
user_data_t &user_data)
|
||||
{
|
||||
fprintf (user_data.f, "C%d,%d %d,%d %d,%d", control1_x, user_data.ascender - control1_y,
|
||||
control2_x, user_data.ascender - control2_y,
|
||||
to_x, user_data.ascender - to_y);
|
||||
}
|
||||
|
||||
static void
|
||||
close_path (user_data_t &user_data)
|
||||
{
|
||||
fprintf (user_data.f, "Z");
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
fprintf (stderr, "usage: %s font-file.ttf\n", argv[0]);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
|
||||
unsigned int num_faces = hb_face_count (blob);
|
||||
if (num_faces == 0)
|
||||
{
|
||||
fprintf (stderr, "error: The file (%s) was corrupted, empty or not found", argv[1]);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
hb_ot_glyph_decompose_funcs_t *funcs = hb_ot_glyph_decompose_funcs_create ();
|
||||
hb_ot_glyph_decompose_funcs_set_move_to_func (funcs, (hb_ot_glyph_decompose_move_to_func_t) move_to);
|
||||
hb_ot_glyph_decompose_funcs_set_line_to_func (funcs, (hb_ot_glyph_decompose_line_to_func_t) line_to);
|
||||
hb_ot_glyph_decompose_funcs_set_conic_to_func (funcs, (hb_ot_glyph_decompose_conic_to_func_t) conic_to);
|
||||
hb_ot_glyph_decompose_funcs_set_cubic_to_func (funcs, (hb_ot_glyph_decompose_cubic_to_func_t) cubic_to);
|
||||
hb_ot_glyph_decompose_funcs_set_close_path_func (funcs, (hb_ot_glyph_decompose_close_path_func_t) close_path);
|
||||
|
||||
for (unsigned int face_index = 0; face_index < hb_face_count (blob); face_index++)
|
||||
{
|
||||
hb_face_t *face = hb_face_create (blob, face_index);
|
||||
hb_font_t *font = hb_font_create (face);
|
||||
unsigned int glyph_count = hb_face_get_glyph_count (face);
|
||||
for (unsigned int gid = 0; gid < glyph_count; ++gid)
|
||||
{
|
||||
hb_font_extents_t font_extents;
|
||||
hb_font_get_extents_for_direction (font, HB_DIRECTION_LTR, &font_extents);
|
||||
hb_glyph_extents_t extents = {0};
|
||||
if (!hb_font_get_glyph_extents (font, gid, &extents))
|
||||
{
|
||||
printf ("Skip gid: %d\n", gid);
|
||||
continue;
|
||||
}
|
||||
|
||||
char name[100];
|
||||
sprintf (name, "%d.svg", gid);
|
||||
FILE *f = fopen (name, "wb");
|
||||
fprintf (f, "<svg xmlns=\"http://www.w3.org/2000/svg\""
|
||||
" viewBox=\"%d %d %d %d\"><path d=\"",
|
||||
extents.x_bearing, 0,
|
||||
extents.x_bearing + extents.width, font_extents.ascender - font_extents.descender); //-extents.height);
|
||||
user_data_t user_data;
|
||||
user_data.ascender = font_extents.ascender;
|
||||
user_data.f = f;
|
||||
if (!hb_ot_glyph_decompose (font, gid, funcs, &user_data))
|
||||
printf ("Failed to decompose gid: %d\n", gid);
|
||||
fprintf (f, "\"/></svg>");
|
||||
fclose (f);
|
||||
}
|
||||
hb_font_destroy (font);
|
||||
hb_face_destroy (face);
|
||||
}
|
||||
|
||||
hb_ot_glyph_decompose_funcs_destroy (funcs);
|
||||
|
||||
hb_blob_destroy (blob);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -38,6 +38,7 @@ TEST_PROGS = \
|
|||
test-map \
|
||||
test-object \
|
||||
test-ot-face \
|
||||
test-ot-glyph \
|
||||
test-ot-glyphname \
|
||||
test-set \
|
||||
test-shape \
|
||||
|
|
|
@ -121,6 +121,11 @@ test_face (hb_face_t *face,
|
|||
hb_ot_var_normalize_variations (face, NULL, 0, NULL, 0);
|
||||
hb_ot_var_normalize_coords (face, 0, NULL, NULL);
|
||||
|
||||
hb_ot_glyph_decompose_funcs_t *funcs = hb_ot_glyph_decompose_funcs_create ();
|
||||
for (unsigned gid = 0; gid < 10; ++gid)
|
||||
hb_ot_glyph_decompose (font, gid, funcs, NULL);
|
||||
hb_ot_glyph_decompose_funcs_destroy (funcs);
|
||||
|
||||
hb_set_destroy (set);
|
||||
hb_font_destroy (font);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,223 @@
|
|||
/*
|
||||
* Copyright © 2020 Ebrahim Byagowi
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "hb-test.h"
|
||||
|
||||
#include <hb-ot.h>
|
||||
|
||||
typedef struct user_data_t {
|
||||
char *str;
|
||||
unsigned size;
|
||||
unsigned consumed;
|
||||
} user_data_t;
|
||||
|
||||
static void
|
||||
move_to (hb_position_t to_x, hb_position_t to_y, user_data_t *user_data)
|
||||
{
|
||||
user_data->consumed += snprintf (user_data->str + user_data->consumed,
|
||||
user_data->size - user_data->consumed,
|
||||
"M%d,%d", to_x, to_y);
|
||||
}
|
||||
|
||||
static void
|
||||
line_to (hb_position_t to_x, hb_position_t to_y, user_data_t *user_data)
|
||||
{
|
||||
user_data->consumed += snprintf (user_data->str + user_data->consumed,
|
||||
user_data->size - user_data->consumed,
|
||||
"L%d,%d", to_x, to_y);
|
||||
}
|
||||
|
||||
static void
|
||||
conic_to (hb_position_t control_x, hb_position_t control_y,
|
||||
hb_position_t to_x, hb_position_t to_y,
|
||||
user_data_t *user_data)
|
||||
{
|
||||
user_data->consumed += snprintf (user_data->str + user_data->consumed,
|
||||
user_data->size - user_data->consumed,
|
||||
"Q%d,%d %d,%d",
|
||||
control_x, control_y,
|
||||
to_x, to_y);
|
||||
}
|
||||
|
||||
static void
|
||||
cubic_to (hb_position_t control1_x, hb_position_t control1_y,
|
||||
hb_position_t control2_x, hb_position_t control2_y,
|
||||
hb_position_t to_x, hb_position_t to_y,
|
||||
user_data_t *user_data)
|
||||
{
|
||||
user_data->consumed += snprintf (user_data->str + user_data->consumed,
|
||||
user_data->size - user_data->consumed,
|
||||
"C%d,%d %d,%d %d,%d",
|
||||
control1_x, control1_y,
|
||||
control2_x, control2_y,
|
||||
to_x, to_y);
|
||||
}
|
||||
|
||||
static void
|
||||
close_path (user_data_t *user_data)
|
||||
{
|
||||
user_data->consumed += snprintf (user_data->str + user_data->consumed,
|
||||
user_data->size - user_data->consumed,
|
||||
"Z");
|
||||
}
|
||||
|
||||
static hb_ot_glyph_decompose_funcs_t *funcs;
|
||||
|
||||
static void
|
||||
test_hb_ot_glyph_empty (void)
|
||||
{
|
||||
g_assert (!hb_ot_glyph_decompose (hb_font_get_empty (), 3, funcs, NULL));
|
||||
}
|
||||
|
||||
static void
|
||||
test_hb_ot_glyph_glyf (void)
|
||||
{
|
||||
hb_face_t *face = hb_test_open_font_file ("fonts/SourceSerifVariable-Roman-VVAR.abc.ttf");
|
||||
hb_font_t *font = hb_font_create (face);
|
||||
hb_face_destroy (face);
|
||||
|
||||
char str[1024] = {0};
|
||||
user_data_t user_data = {
|
||||
.str = str,
|
||||
.size = sizeof (str),
|
||||
.consumed = 0
|
||||
};
|
||||
g_assert (!hb_ot_glyph_decompose (font, 4, funcs, &user_data));
|
||||
g_assert (hb_ot_glyph_decompose (font, 3, funcs, &user_data));
|
||||
char expected[] = "M275,442L275,442Q232,442 198,420Q164,397 145,353Q126,309 126,245L126,245"
|
||||
"Q126,182 147,139Q167,95 204,73Q240,50 287,50L287,50Q330,50 367,70"
|
||||
"Q404,90 427,128L427,128L451,116Q431,54 384,21Q336,-13 266,-13L266,-13Q198,-13 148,18"
|
||||
"Q97,48 70,104Q43,160 43,236L43,236Q43,314 76,371Q108,427 160,457Q212,487 272,487L272,487"
|
||||
"Q316,487 354,470Q392,453 417,424Q442,395 448,358L448,358Q441,321 403,321L403,321"
|
||||
"Q378,321 367,334Q355,347 350,366L350,366L325,454L371,417Q346,430 321,436Q296,442 275,442Z";
|
||||
g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
|
||||
|
||||
hb_variation_t var;
|
||||
var.tag = HB_TAG ('w','g','h','t');
|
||||
var.value = 800;
|
||||
hb_font_set_variations (font, &var, 1);
|
||||
|
||||
char str2[1024] = {0};
|
||||
user_data_t user_data2 = {
|
||||
.str = str2,
|
||||
.size = sizeof (str2),
|
||||
.consumed = 0
|
||||
};
|
||||
g_assert (hb_ot_glyph_decompose (font, 3, funcs, &user_data2));
|
||||
char expected2[] = "M323,448L323,448Q297,448 271,430Q244,412 227,371"
|
||||
"Q209,330 209,261L209,261Q209,204 226,166Q242,127 273,107Q303,86 344,86L344,86Q378,86 404,101"
|
||||
"Q430,115 451,137L451,137L488,103Q458,42 404,13Q350,-16 279,-16L279,-16Q211,-16 153,13Q95,41 60,99"
|
||||
"Q25,156 25,241L25,241Q25,323 62,382Q99,440 163,471Q226,501 303,501L303,501Q357,501 399,481"
|
||||
"Q440,460 464,426Q488,392 492,352L492,352Q475,297 420,297L420,297Q390,297 366,320"
|
||||
"Q342,342 339,401L339,401L333,469L411,427Q387,438 368,443Q348,448 323,448Z";
|
||||
g_assert_cmpmem (str2, user_data2.consumed, expected2, sizeof (expected2) - 1);
|
||||
|
||||
hb_font_destroy (font);
|
||||
}
|
||||
|
||||
static void
|
||||
test_hb_ot_glyph_cff1 (void)
|
||||
{
|
||||
hb_face_t *face = hb_test_open_font_file ("fonts/cff1_seac.otf");
|
||||
hb_font_t *font = hb_font_create (face);
|
||||
hb_face_destroy (face);
|
||||
|
||||
char str[1024] = {0};
|
||||
user_data_t user_data = {
|
||||
.str = str,
|
||||
.size = sizeof (str),
|
||||
.consumed = 0
|
||||
};
|
||||
g_assert (hb_ot_glyph_decompose (font, 3, funcs, &user_data));
|
||||
char expected[] = "M203,367C227,440 248,512 268,588L272,588C293,512 314,440 338,367L369,267L172,267Z"
|
||||
"M3,0L88,0L151,200L390,200L452,0L541,0L319,656L225,656Z"
|
||||
"M300,653L342,694L201,861L143,806Z";
|
||||
g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
|
||||
|
||||
hb_font_destroy (font);
|
||||
}
|
||||
|
||||
static void
|
||||
test_hb_ot_glyph_cff2 (void)
|
||||
{
|
||||
hb_face_t *face = hb_test_open_font_file ("fonts/AdobeVFPrototype.abc.otf");
|
||||
hb_font_t *font = hb_font_create (face);
|
||||
hb_face_destroy (face);
|
||||
|
||||
char str[1024] = {0};
|
||||
user_data_t user_data = {
|
||||
.str = str,
|
||||
.size = sizeof (str),
|
||||
.consumed = 0
|
||||
};
|
||||
g_assert (hb_ot_glyph_decompose (font, 3, funcs, &user_data));
|
||||
char expected[] = "M275,442C303,442 337,435 371,417L325,454L350,366"
|
||||
"C357,341 370,321 403,321C428,321 443,333 448,358"
|
||||
"C435,432 361,487 272,487C153,487 43,393 43,236"
|
||||
"C43,83 129,-13 266,-13C360,-13 424,33 451,116L427,128"
|
||||
"C396,78 345,50 287,50C193,50 126,119 126,245C126,373 188,442 275,442Z";
|
||||
g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
|
||||
|
||||
hb_variation_t var;
|
||||
var.tag = HB_TAG ('w','g','h','t');
|
||||
var.value = 800;
|
||||
hb_font_set_variations (font, &var, 1);
|
||||
|
||||
char str2[1024] = {0};
|
||||
user_data_t user_data2 = {
|
||||
.str = str2,
|
||||
.size = sizeof (str2),
|
||||
.consumed = 0
|
||||
};
|
||||
g_assert (hb_ot_glyph_decompose (font, 3, funcs, &user_data2));
|
||||
char expected2[] = "M323,448C356,448 380,441 411,427L333,469L339,401"
|
||||
"C343,322 379,297 420,297C458,297 480,314 492,352"
|
||||
"C486,433 412,501 303,501C148,501 25,406 25,241"
|
||||
"C25,70 143,-16 279,-16C374,-16 447,22 488,103L451,137"
|
||||
"C423,107 390,86 344,86C262,86 209,148 209,261C209,398 271,448 323,448Z";
|
||||
g_assert_cmpmem (str2, user_data2.consumed, expected2, sizeof (expected2) - 1);
|
||||
|
||||
hb_font_destroy (font);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
funcs = hb_ot_glyph_decompose_funcs_create ();
|
||||
hb_ot_glyph_decompose_funcs_set_move_to_func (funcs, (hb_ot_glyph_decompose_move_to_func_t) move_to);
|
||||
hb_ot_glyph_decompose_funcs_set_line_to_func (funcs, (hb_ot_glyph_decompose_line_to_func_t) line_to);
|
||||
hb_ot_glyph_decompose_funcs_set_conic_to_func (funcs, (hb_ot_glyph_decompose_conic_to_func_t) conic_to);
|
||||
hb_ot_glyph_decompose_funcs_set_cubic_to_func (funcs, (hb_ot_glyph_decompose_cubic_to_func_t) cubic_to);
|
||||
hb_ot_glyph_decompose_funcs_set_close_path_func (funcs, (hb_ot_glyph_decompose_close_path_func_t) close_path);
|
||||
|
||||
hb_test_init (&argc, &argv);
|
||||
hb_test_add (test_hb_ot_glyph_empty);
|
||||
hb_test_add (test_hb_ot_glyph_glyf);
|
||||
hb_test_add (test_hb_ot_glyph_cff1);
|
||||
hb_test_add (test_hb_ot_glyph_cff2);
|
||||
unsigned result = hb_test_run ();
|
||||
|
||||
hb_ot_glyph_decompose_funcs_destroy (funcs);
|
||||
return result;
|
||||
}
|
Loading…
Reference in New Issue