[glyf] Refactor, move get_points inside Glyph

This commit is contained in:
Ebrahim Byagowi 2020-02-25 10:30:59 +03:30
parent 96b71e802f
commit b59eb54f70
1 changed files with 126 additions and 143 deletions

View File

@ -402,6 +402,15 @@ struct glyf
__item_t__ current;
};
enum phantom_point_index_t
{
PHANTOM_LEFT = 0,
PHANTOM_RIGHT = 1,
PHANTOM_TOP = 2,
PHANTOM_BOTTOM = 3,
PHANTOM_COUNT = 4
};
struct Glyph
{
enum simple_glyph_flag_t
@ -539,7 +548,7 @@ struct glyf
const simple_glyph_flag_t same_flag)
{
float v = 0;
for (unsigned int i = 0; i < points_.length - PHANTOM_COUNT; i++)
for (unsigned i = 0; i < points_.length; i++)
{
uint8_t flag = points_[i].flag;
if (flag & short_flag)
@ -571,7 +580,7 @@ struct glyf
if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours + 1]))) return false;
unsigned int num_points = endPtsOfContours[num_contours - 1] + 1;
points_.resize (num_points + PHANTOM_COUNT);
points_.resize (num_points);
for (unsigned int i = 0; i < points_.length; i++) points_[i].init ();
if (phantom_only) return true;
@ -644,28 +653,10 @@ struct glyf
/* Chop instructions off the end */
void drop_hints_bytes (hb_bytes_t &dest_start) const
{ dest_start = bytes.sub_array (0, bytes.length - instructions_length (bytes)); }
bool get_contour_points (contour_point_vector_t &points_ /* OUT */) const
{
/* add one pseudo point for each component in composite glyph */
unsigned int num_points = hb_len (get_iterator ());
points_.resize (num_points + PHANTOM_COUNT);
for (unsigned int i = 0; i < points_.length; i++) points_[i].init ();
return true;
}
};
enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE };
enum phantom_point_index_t
{
PHANTOM_LEFT = 0,
PHANTOM_RIGHT = 1,
PHANTOM_TOP = 2,
PHANTOM_BOTTOM = 3,
PHANTOM_COUNT = 4
};
public:
composite_iter_t get_composite_iterator () const
{
@ -700,132 +691,67 @@ struct glyf
}
}
/* for a simple glyph, return contour end points, flags, along with coordinate points
* for a composite glyph, return pseudo component points
* in both cases points trailed with four phantom points
*/
bool get_contour_points (contour_point_vector_t &points_ /* OUT */, bool phantom_only = false) const
{
switch (type) {
case COMPOSITE: return CompositeGlyph (*header, bytes).get_contour_points (points_);
case SIMPLE: return SimpleGlyph (*header, bytes).get_contour_points (points_, phantom_only);
default:
/* empty glyph */
points_.resize (PHANTOM_COUNT);
for (unsigned int i = 0; i < points_.length; i++) points_[i].init ();
return true;
}
}
bool is_simple_glyph () const { return type == SIMPLE; }
bool is_composite_glyph () const { return type == COMPOSITE; }
bool get_extents (hb_font_t *font, hb_codepoint_t gid, hb_glyph_extents_t *extents) const
{
if (type == EMPTY) return true; /* Empty glyph; zero extents. */
return header->get_extents (font, gid, extents);
}
hb_bytes_t get_bytes () const { return bytes; }
const GlyphHeader &get_header () const { return *header; }
Glyph (hb_bytes_t bytes_ = hb_bytes_t ()) :
bytes (bytes_), header (bytes.as<GlyphHeader> ())
{
int num_contours = header->numberOfContours;
if (unlikely (num_contours == 0)) type = EMPTY;
else if (num_contours > 0) type = SIMPLE;
else type = COMPOSITE; /* negative numbers */
}
protected:
hb_bytes_t bytes;
const GlyphHeader *header;
unsigned type;
};
struct accelerator_t
{
void init (hb_face_t *face_)
{
short_offset = false;
num_glyphs = 0;
loca_table = nullptr;
glyf_table = nullptr;
face = face_;
const OT::head &head = *face->table.head;
if (head.indexToLocFormat > 1 || head.glyphDataFormat > 0)
/* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */
return;
short_offset = 0 == head.indexToLocFormat;
loca_table = hb_sanitize_context_t ().reference_table<loca> (face);
glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face);
num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1;
}
void fini ()
{
loca_table.destroy ();
glyf_table.destroy ();
}
enum phantom_point_index_t
{
PHANTOM_LEFT = 0,
PHANTOM_RIGHT = 1,
PHANTOM_TOP = 2,
PHANTOM_BOTTOM = 3,
PHANTOM_COUNT = 4
};
protected:
void init_phantom_points (hb_codepoint_t gid, hb_array_t<contour_point_t> &phantoms /* IN/OUT */) const
{
const Glyph &glyph = glyph_for_gid (gid);
int h_delta = (int) glyph.get_header ().xMin - face->table.hmtx->get_side_bearing (gid);
int v_orig = (int) glyph.get_header ().yMax + face->table.vmtx->get_side_bearing (gid);
unsigned int h_adv = face->table.hmtx->get_advance (gid);
unsigned int v_adv = face->table.vmtx->get_advance (gid);
phantoms[PHANTOM_LEFT].x = h_delta;
phantoms[PHANTOM_RIGHT].x = h_adv + h_delta;
phantoms[PHANTOM_TOP].y = v_orig;
phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
}
/* Note: Recursively calls itself.
* all_points includes phantom points
*/
bool _get_points (hb_codepoint_t gid,
const int *coords, unsigned int coord_count,
contour_point_vector_t &all_points /* OUT */,
bool phantom_only = false,
unsigned int depth = 0) const
template<typename T>
bool get_points (T glyph_for_gid, hb_font_t *font,
contour_point_vector_t &all_points /* OUT */,
bool phantom_only = false,
unsigned int depth = 0) const
{
if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return false;
if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false;
contour_point_vector_t points;
const Glyph &glyph = glyph_for_gid (gid);
if (unlikely (!glyph.get_contour_points (points, phantom_only))) return false;
switch (type) {
case COMPOSITE:
{
/* pseudo component points for each component in composite glyph */
unsigned num_points = hb_len (CompositeGlyph (*header, bytes).get_iterator ());
if (unlikely (!points.resize (num_points))) return false;
for (unsigned i = 0; i < points.length; i++)
points[i].init ();
break;
}
case SIMPLE:
if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only)))
return false;
break;
default: return false; /* empty glyph */
}
hb_face_t *face = font->face;
/* Init phantom points */
if (unlikely (!points.resize (points.length + PHANTOM_COUNT))) return false;
hb_array_t<contour_point_t> phantoms = points.sub_array (points.length - PHANTOM_COUNT, PHANTOM_COUNT);
init_phantom_points (gid, phantoms);
{
for (unsigned i = 0; i < PHANTOM_COUNT; ++i) phantoms[i].init ();
int h_delta = (int) header->xMin - face->table.hmtx->get_side_bearing (gid);
int v_orig = (int) header->yMax + face->table.vmtx->get_side_bearing (gid);
unsigned h_adv = face->table.hmtx->get_advance (gid);
unsigned v_adv = face->table.vmtx->get_advance (gid);
phantoms[PHANTOM_LEFT].x = h_delta;
phantoms[PHANTOM_RIGHT].x = h_adv + h_delta;
phantoms[PHANTOM_TOP].y = v_orig;
phantoms[PHANTOM_BOTTOM].y = v_orig - (int) v_adv;
}
#ifndef HB_NO_VAR
if (unlikely (!face->table.gvar->apply_deltas_to_points (gid, coords, coord_count, points.as_array ()))) return false;
if (unlikely (!face->table.gvar->apply_deltas_to_points (gid, font->coords, font->num_coords, points.as_array ()))) return false;
#endif
if (glyph.is_simple_glyph ())
switch (type) {
case SIMPLE:
all_points.extend (points.as_array ());
else if (glyph.is_composite_glyph ())
break;
case COMPOSITE:
{
unsigned int comp_index = 0;
for (auto &item : glyph.get_composite_iterator ())
for (auto &item : get_composite_iterator ())
{
contour_point_vector_t comp_points;
if (unlikely (!_get_points (item.glyphIndex, coords, coord_count,
comp_points, phantom_only, depth))
if (unlikely (!glyph_for_gid (item.glyphIndex).get_points (glyph_for_gid, font, comp_points, phantom_only, depth + 1))
|| comp_points.length < PHANTOM_COUNT)
return false;
@ -860,12 +786,76 @@ struct glyf
}
all_points.extend (phantoms);
} break;
default: return false;
}
if (depth == 0) /* Apply at top level */
{
/* Undocumented rasterizer behavior:
* Shift points horizontally by the updated left side bearing
*/
contour_point_t delta;
delta.init (-phantoms[PHANTOM_LEFT].x, 0.f);
if (delta.x) all_points.translate (delta);
}
else return false;
return true;
}
bool get_extents (hb_font_t *font, hb_glyph_extents_t *extents) const
{
if (type == EMPTY) return true; /* Empty glyph; zero extents. */
return header->get_extents (font, gid, extents);
}
hb_bytes_t get_bytes () const { return bytes; }
Glyph (hb_bytes_t bytes_ = hb_bytes_t (),
hb_codepoint_t gid_ = (hb_codepoint_t) -1) : bytes (bytes_), gid (gid_),
header (bytes.as<GlyphHeader> ())
{
int num_contours = header->numberOfContours;
if (unlikely (num_contours == 0)) type = EMPTY;
else if (num_contours > 0) type = SIMPLE;
else type = COMPOSITE; /* negative numbers */
}
protected:
hb_bytes_t bytes;
hb_codepoint_t gid;
const GlyphHeader *header;
unsigned type;
};
struct accelerator_t
{
void init (hb_face_t *face_)
{
short_offset = false;
num_glyphs = 0;
loca_table = nullptr;
glyf_table = nullptr;
face = face_;
const OT::head &head = *face->table.head;
if (head.indexToLocFormat > 1 || head.glyphDataFormat > 0)
/* Unknown format. Leave num_glyphs=0, that takes care of disabling us. */
return;
short_offset = 0 == head.indexToLocFormat;
loca_table = hb_sanitize_context_t ().reference_table<loca> (face);
glyf_table = hb_sanitize_context_t ().reference_table<glyf> (face);
num_glyphs = hb_max (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1;
}
void fini ()
{
loca_table.destroy ();
glyf_table.destroy ();
}
protected:
template<typename T>
bool get_points (hb_font_t *font, hb_codepoint_t gid, T consumer) const
{
@ -876,17 +866,10 @@ struct glyf
contour_point_vector_t all_points;
bool phantom_only = !consumer.is_consuming_contour_points ();
if (unlikely (!_get_points (gid, font->coords, font->num_coords, all_points, phantom_only) ||
all_points.length < PHANTOM_COUNT))
if (unlikely (!glyph_for_gid (gid).get_points ([this] (hb_codepoint_t gid) -> const Glyph { return this->glyph_for_gid (gid); },
font, all_points, phantom_only)))
return false;
/* Undocumented rasterizer behavior:
* Shift points horizontally by the updated left side bearing
*/
contour_point_t delta;
delta.init (-all_points[all_points.length - PHANTOM_COUNT + PHANTOM_LEFT].x, 0.f);
if (delta.x) all_points.translate (delta);
if (consumer.is_consuming_contour_points ())
{
for (unsigned point_index = 0; point_index + 4 < all_points.length; ++point_index)
@ -1002,7 +985,7 @@ struct glyf
if (font->num_coords && font->num_coords == face->table.gvar->get_axis_count ())
return get_points (font, gid, points_aggregator_t (font, extents, nullptr));
#endif
return glyph_for_gid (gid).get_extents (font, gid, extents);
return glyph_for_gid (gid).get_extents (font, extents);
}
const Glyph
@ -1028,7 +1011,7 @@ struct glyf
return Glyph ();
Glyph glyph (hb_bytes_t ((const char *) this->glyf_table + start_offset,
end_offset - start_offset));
end_offset - start_offset), gid);
return needs_padding_removal ? glyph.trim_padding () : glyph;
}