From 99502b324dd6cb45d401bc5f6cc08d7a77677ba5 Mon Sep 17 00:00:00 2001 From: Michiharu Ariza Date: Tue, 12 Mar 2019 11:03:53 -0700 Subject: [PATCH] add gvar::get_extents --- src/hb-ot-face.hh | 1 + src/hb-ot-font.cc | 3 + src/hb-ot-glyf-table.hh | 21 +++-- src/hb-ot-var-gvar-table.hh | 164 ++++++++++++++++++++++++++++++++++-- 4 files changed, 175 insertions(+), 14 deletions(-) diff --git a/src/hb-ot-face.hh b/src/hb-ot-face.hh index 7f47ba6cb..9deb37798 100644 --- a/src/hb-ot-face.hh +++ b/src/hb-ot-face.hh @@ -72,6 +72,7 @@ HB_OT_TABLE(OT, fvar) \ HB_OT_TABLE(OT, avar) \ HB_OT_TABLE(OT, MVAR) \ + HB_OT_ACCELERATOR(OT, gvar) \ /* OpenType math. */ \ HB_OT_TABLE(OT, MATH) \ /* OpenType color fonts. */ \ diff --git a/src/hb-ot-font.cc b/src/hb-ot-font.cc index 94a9fdc47..742059ee7 100644 --- a/src/hb-ot-font.cc +++ b/src/hb-ot-font.cc @@ -42,6 +42,7 @@ #include "hb-ot-post-table.hh" #include "hb-ot-stat-table.hh" // Just so we compile it; unused otherwise. #include "hb-ot-vorg-table.hh" +#include "hb-ot-var-gvar-table.hh" #include "hb-ot-color-cbdt-table.hh" #include "hb-ot-color-sbix-table.hh" @@ -181,6 +182,8 @@ hb_ot_get_glyph_extents (hb_font_t *font, { const hb_ot_face_t *ot_face = (const hb_ot_face_t *) font_data; bool ret = ot_face->sbix->get_extents (font, glyph, extents); + if (!ret) + ret = ot_face->gvar->get_extents (font, glyph, extents); if (!ret) ret = ot_face->glyf->get_extents (glyph, extents); if (!ret) diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index bab06afbd..538577a1d 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -306,7 +306,7 @@ struct glyf bool in_range (const T *p) const { return ((const char *) p) >= table + start_offset - && ((const char *) (p + T::static_size)) <= table + end_offset; + && ((const char *) p + T::static_size) <= table + end_offset; } protected: @@ -366,9 +366,9 @@ struct glyf * in both cases points trailed with four phantom points */ bool get_contour_points (hb_codepoint_t glyph, - bool phantom_only, hb_vector_t &_points /* OUT */, - hb_vector_t &_end_points /* OUT */) const + hb_vector_t &_end_points /* OUT */, + const bool phantom_only=false) const { unsigned int num_points = 0; unsigned int start_offset, end_offset; @@ -377,8 +377,17 @@ struct glyf if (end_offset - start_offset < GlyphHeader::static_size) return false; + glyf::CompositeGlyphHeader::Iterator composite; + if (get_composite (glyph, &composite)) + { + /* For a composite glyph, add one pseudo point for each component */ + do { num_points++; } while (composite.move_to_next()); + _points.resize (num_points + PHANTOM_COUNT); + for (unsigned int i = 0; i < _points.length; i++) _points[i].init (); + return true; + } + const GlyphHeader &glyph_header = StructAtOffset (glyf_table, start_offset); - if (unlikely (glyph_header.numberOfContours < 0)) return false; int16_t num_contours = (int16_t) glyph_header.numberOfContours; const HBUINT16 *end_pts = &StructAfter (glyph_header); @@ -428,8 +437,8 @@ struct glyf } /* Read x & y coordinates */ - return (!read_points (p, _points, checker) && - !read_points (p, _points, checker)); + return (read_points (p, _points, checker) && + read_points (p, _points, checker)); } /* based on FontTools _g_l_y_f.py::trim */ diff --git a/src/hb-ot-var-gvar-table.hh b/src/hb-ot-var-gvar-table.hh index f81b269ba..5c157a1d5 100644 --- a/src/hb-ot-var-gvar-table.hh +++ b/src/hb-ot-var-gvar-table.hh @@ -31,6 +31,8 @@ #include "hb-ot-glyf-table.hh" #include "hb-ot-var-fvar-table.hh" +#include + /* * gvar -- Glyph Variation Table * https://docs.microsoft.com/en-us/typography/opentype/spec/gvar @@ -376,6 +378,24 @@ struct gvar glyf_accel.fini (); } + protected: + typedef glyf::accelerator_t glyf_acc_t; + + static float infer_delta (float target_val, float pre_val, float fol_val, + float pre_delta, float fol_delta) + { + if (pre_val == fol_val) + return (pre_delta == fol_delta)? pre_delta: 0.f; + else if (target_val <= MIN (pre_val, fol_val)) + return (pre_val < fol_val) ? pre_delta: fol_delta; + else if (target_val >= MAX (pre_val, fol_val)) + return (pre_val > fol_val)? pre_delta: fol_delta; + + /* linear interpolation */ + float r = (target_val - pre_val) / (fol_val - pre_val); + return (1.f - r) * pre_delta + r * fol_delta; + } + bool apply_deltas_to_points (hb_codepoint_t glyph, const int *coords, unsigned int coord_count, const hb_array_t points, @@ -391,6 +411,11 @@ struct gvar &iterator)) return false; + hb_vector_t deltas; /* flag is used to indicate referenced point */ + deltas.resize (points.length); + for (unsigned int i = 0; i < deltas.length; i++) + deltas[i].init (); + do { float scalar = iterator.current_tuple->calculate_scalar (coords, coord_count, shared_tuples.as_array ()); if (scalar == 0.f) continue; @@ -419,12 +444,49 @@ struct gvar for (unsigned int i = 0; i < num_deltas; i++) { unsigned int pt_index = apply_to_all? i: indices[i]; - points[pt_index].x += x_deltas[i] * scalar; - points[pt_index].y += y_deltas[i] * scalar; + deltas[pt_index].flag = 1; /* this point is referenced, i.e., explicit deltas specified */ + deltas[pt_index].x += x_deltas[i] * scalar; + deltas[pt_index].y += y_deltas[i] * scalar; } /* TODO: interpolate untouched points for glyph extents */ } while (iterator.move_to_next ()); + /* infer deltas for unreferenced points */ + unsigned int start_point = 0; + for (unsigned int c = 0; c < end_points.length; c++) + { + unsigned int end_point = end_points[c]; + for (unsigned int i = start_point; i < end_point; i++) + { + if (deltas[i].flag) continue; + /* search in both directions within the contour for a pair of referenced points */ + unsigned int pre; + for (pre = i;;) + { + if (pre-- <= start_point) pre = end_point; + if (pre == i || deltas[pre].flag) break; + } + if (pre == i) continue; /* no (preceeding) referenced point was found */ + unsigned int fol; + for (fol = i;;) + { + if (fol++ >= end_point) fol = start_point; + if (fol == i || deltas[fol].flag) break; + } + assert (fol != i); + deltas[i].x = infer_delta (points[i].x, points[pre].x, points[fol].x, deltas[pre].x, deltas[fol].x); + deltas[i].y = infer_delta (points[i].y, points[pre].y, points[fol].y, deltas[pre].y, deltas[fol].y); + } + start_point = end_point + 1; + } + + /* apply accumulated / inferred deltas to points */ + for (unsigned int i = 0; i < points.length; i++) + { + points[i].x += deltas[i].x; + points[i].y += deltas[i].y; + } + return true; } @@ -435,11 +497,11 @@ struct gvar { hb_vector_t points; hb_vector_t end_points; - if (!glyf_accel.get_contour_points (glyph, true, points, end_points)) return false; + if (!glyf_accel.get_contour_points (glyph, points, end_points, true/*phantom_only*/)) return false; if (!apply_deltas_to_points (glyph, coords, coord_count, points.as_array (), end_points.as_array ())) return false; - for (unsigned int i = 0; i < glyf::accelerator_t::PHANTOM_COUNT; i++) - phantoms[i] = points[points.length - glyf::accelerator_t::PHANTOM_COUNT + i]; + for (unsigned int i = 0; i < glyf_acc_t::PHANTOM_COUNT; i++) + phantoms[i] = points[points.length - glyf_acc_t::PHANTOM_COUNT + i]; glyf::CompositeGlyphHeader::Iterator composite; if (!glyf_accel.get_composite (glyph, &composite)) return true; /* simple glyph */ @@ -453,6 +515,57 @@ struct gvar return true; } + struct bounds_t + { + bounds_t () { min.x = min.y = FLT_MAX; max.x = max.y = FLT_MIN; } + + void add (const contour_point_t &p) + { + min.x = MIN (min.x, p.x); + min.y = MIN (min.y, p.y); + max.x = MAX (max.x, p.x); + max.y = MAX (max.y, p.y); + } + + void _union (const bounds_t &b) + { add (b.min); add (b.max); } + + contour_point_t min; + contour_point_t max; + }; + + /* Note: Recursively calls itself. Who's checking recursively nested composite glyph BTW? */ + bool get_bounds_var (hb_codepoint_t glyph, + const int *coords, unsigned int coord_count, + bounds_t &bounds) const + { + hb_vector_t points; + hb_vector_t end_points; + if (!glyf_accel.get_contour_points (glyph, points, end_points)) return false; + if (!apply_deltas_to_points (glyph, coords, coord_count, points.as_array (), end_points.as_array ())) return false; + + glyf::CompositeGlyphHeader::Iterator composite; + if (!glyf_accel.get_composite (glyph, &composite)) + { + /* simple glyph */ + for (unsigned int i = 0; i + glyf_acc_t::PHANTOM_COUNT < points.length; i++) + bounds.add (points[i]); + return true; + } + /* composite glyph */ + do + { + bounds_t comp_bounds; + if (!get_bounds_var (composite.current->glyphIndex, coords, coord_count, comp_bounds)) + return false; + + /* TODO: support component scale/transformation */ + bounds._union (comp_bounds); + } while (composite.move_to_next()); + return true; + } + + public: float get_advance_var (hb_codepoint_t glyph, const int *coords, unsigned int coord_count, bool vertical) const @@ -461,15 +574,48 @@ struct gvar if (coord_count != gvar_table->axisCount) return advance; hb_vector_t points; - points.resize (glyf::accelerator_t::PHANTOM_COUNT); + points.resize (glyf_acc_t::PHANTOM_COUNT); if (!get_var_metrics (glyph, coords, coord_count, points)) return advance; if (vertical) - return -(points[glyf::accelerator_t::PHANTOM_BOTTOM].y - points[glyf::accelerator_t::PHANTOM_TOP].y); // is this sign correct? + return -(points[glyf_acc_t::PHANTOM_BOTTOM].y - points[glyf_acc_t::PHANTOM_TOP].y); // is this sign correct? else - return points[glyf::accelerator_t::PHANTOM_RIGHT].x - points[glyf::accelerator_t::PHANTOM_LEFT].x; + return points[glyf_acc_t::PHANTOM_RIGHT].x - points[glyf_acc_t::PHANTOM_LEFT].x; + } + + bool get_extents (hb_font_t *font, hb_codepoint_t glyph, + hb_glyph_extents_t *extents) const + { + unsigned int coord_count; + const int *coords = hb_font_get_var_coords_normalized (font, &coord_count); + if (!coords || coord_count != gvar_table->axisCount) return false; /* fallback on glyf */ + + bounds_t bounds; + if (unlikely (!get_bounds_var (glyph, coords, coord_count, bounds))) return false; + + if (bounds.min.x >= bounds.max.x) + { + extents->width = 0; + extents->x_bearing = 0; + } + else + { + extents->x_bearing = (int32_t)floorf (bounds.min.x); + extents->width = (int32_t)ceilf (bounds.max.x) - extents->x_bearing; + } + if (bounds.min.y >= bounds.max.y) + { + extents->height = 0; + extents->y_bearing = 0; + } + else + { + extents->y_bearing = (int32_t)ceilf (bounds.max.y); + extents->height = (int32_t)floorf (bounds.min.y) - extents->y_bearing; + } + return true; } protected: @@ -590,6 +736,8 @@ struct gvar DEFINE_SIZE_MIN (20); }; +struct gvar_accelerator_t : gvar::accelerator_t {}; + } /* namespace OT */ #endif /* HB_OT_VAR_GVAR_TABLE_HH */