diff --git a/src/Makefile.sources b/src/Makefile.sources index a8f609de4..6dc7427f6 100644 --- a/src/Makefile.sources +++ b/src/Makefile.sources @@ -68,6 +68,7 @@ HB_BASE_sources = \ hb-ot-head-table.hh \ hb-ot-hhea-table.hh \ hb-ot-hmtx-table.hh \ + hb-ot-hmtx-table.cc \ hb-ot-kern-table.hh \ hb-ot-layout-base-table.hh \ hb-ot-layout-common.hh \ diff --git a/src/hb-ot-face.hh b/src/hb-ot-face.hh index 9deb37798..7f47ba6cb 100644 --- a/src/hb-ot-face.hh +++ b/src/hb-ot-face.hh @@ -72,7 +72,6 @@ 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 742059ee7..d03371cc3 100644 --- a/src/hb-ot-font.cc +++ b/src/hb-ot-font.cc @@ -158,10 +158,10 @@ hb_ot_get_glyph_v_origin (hb_font_t *font, } hb_glyph_extents_t extents = {0}; - if (ot_face->glyf->get_extents (glyph, &extents)) + if (ot_face->glyf->get_extents (font, glyph, &extents)) { const OT::vmtx_accelerator_t &vmtx = *ot_face->vmtx; - hb_position_t tsb = vmtx.get_side_bearing (glyph); + hb_position_t tsb = vmtx.get_side_bearing (font, glyph); *y = font->em_scale_y (extents.y_bearing + tsb); return true; } @@ -183,9 +183,7 @@ 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); + ret = ot_face->glyf->get_extents (font, glyph, extents); if (!ret) ret = ot_face->cff1->get_extents (glyph, extents); if (!ret) diff --git a/src/hb-ot-glyf-table.hh b/src/hb-ot-glyf-table.hh index 2793fbaa3..a07a15630 100644 --- a/src/hb-ot-glyf-table.hh +++ b/src/hb-ot-glyf-table.hh @@ -30,6 +30,8 @@ #include "hb-open-type.hh" #include "hb-ot-head-table.hh" +#include "hb-ot-hmtx-table.hh" +#include "hb-ot-var-gvar-table.hh" #include "hb-subset-glyf.hh" namespace OT { @@ -222,8 +224,7 @@ struct glyf { const CompositeGlyphHeader *possible = &StructAfter (*current); - if (!in_range (possible)) - return false; + if (unlikely (!in_range (possible))) return false; current = possible; return true; } @@ -281,12 +282,19 @@ struct glyf glyf_table = hb_sanitize_context_t ().reference_table (face); num_glyphs = MAX (1u, loca_table.get_length () / (short_offset ? 2 : 4)) - 1; + + gvar_accel.init (face); + hmtx_accel.init (face); + vmtx_accel.init (face); } void fini () { loca_table.destroy (); glyf_table.destroy (); + gvar_accel.fini (); + hmtx_accel.fini (); + vmtx_accel.fini (); } /* @@ -328,30 +336,15 @@ struct glyf PHANTOM_COUNT = 4 }; - struct contour_point_t + protected: + const GlyphHeader &get_header (hb_codepoint_t glyph) const { - void init () { flag = 0; x = y = 0.0f; } - uint8_t flag; - float x, y; - }; + unsigned int start_offset, end_offset; + if (!get_offsets (glyph, &start_offset, &end_offset) || end_offset - start_offset < GlyphHeader::static_size) + return Null(GlyphHeader); - struct range_checker_t - { - range_checker_t (const void *table_, unsigned int start_offset_, unsigned int end_offset_) - : table ((const char*)table_), start_offset (start_offset_), end_offset (end_offset_) {} - - template - bool in_range (const T *p) const - { - return ((const char *) p) >= table + start_offset - && ((const char *) p + T::static_size) <= table + end_offset; - } - - protected: - const char *table; - const unsigned int start_offset; - const unsigned int end_offset; - }; + return StructAtOffset (glyf_table, start_offset); + } struct x_setter_t { @@ -379,8 +372,7 @@ struct glyf uint8_t flag = points_[i].flag; if (coord_setter.is_short (flag)) { - if (unlikely (!checker.in_range (p))) - return false; + if (unlikely (!checker.in_range (p))) return false; if (coord_setter.is_same (flag)) v += *p++; else @@ -390,8 +382,7 @@ struct glyf { if (!coord_setter.is_same (flag)) { - if (unlikely (!checker.in_range ((const HBUINT16 *)p))) - return false; + if (unlikely (!checker.in_range ((const HBUINT16 *)p))) return false; v += *(const HBINT16 *)p; p += HBINT16::static_size; } @@ -401,23 +392,35 @@ struct glyf return true; } + void init_phantom_points (hb_codepoint_t glyph, hb_array_t &phantoms /* IN/OUT */) const + { + const GlyphHeader &header = get_header (glyph); + int h_delta = (int)header.xMin - hmtx_accel.get_side_bearing (glyph); + int v_delta = (int)header.yMax - vmtx_accel.get_side_bearing (glyph); + unsigned int h_adv = hmtx_accel.get_advance (glyph); + unsigned int v_adv = vmtx_accel.get_advance (glyph); + + phantoms[PHANTOM_LEFT].x = h_delta; + phantoms[PHANTOM_RIGHT].x = h_adv + h_delta; + phantoms[PHANTOM_TOP].y = v_delta; + phantoms[PHANTOM_BOTTOM].y = -v_adv + v_delta; + } + /* 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 (hb_codepoint_t glyph, hb_vector_t &points_ /* OUT */, - hb_vector_t &_end_points /* OUT */, + hb_vector_t &end_points_ /* OUT */, const bool phantom_only=false) const { unsigned int num_points = 0; unsigned int start_offset, end_offset; - if (unlikely (!get_offsets (glyph, &start_offset, &end_offset))) - return false; - if (end_offset - start_offset < GlyphHeader::static_size) - return false; + if (unlikely (!get_offsets (glyph, &start_offset, &end_offset))) return false; + if (unlikely (end_offset - start_offset < GlyphHeader::static_size)) return false; - glyf::CompositeGlyphHeader::Iterator composite; + CompositeGlyphHeader::Iterator composite; if (get_composite (glyph, &composite)) { /* For a composite glyph, add one pseudo point for each component */ @@ -441,7 +444,7 @@ struct glyf else if (num_contours < 0) { CompositeGlyphHeader::Iterator composite; - if (!get_composite (glyph, &composite)) return false; + if (unlikely (!get_composite (glyph, &composite))) return false; do { num_points++; @@ -453,10 +456,10 @@ struct glyf if ((num_contours <= 0) || phantom_only) return true; /* Read simple glyph points if !phantom_only */ - _end_points.resize (num_contours); + end_points_.resize (num_contours); for (int16_t i = 0; i < num_contours; i++) - _end_points[i] = end_pts[i]; + end_points_[i] = end_pts[i]; /* Skip instructions */ const HBUINT8 *p = &StructAtOffset (&end_pts[num_contours+1], end_pts[num_contours]); @@ -481,6 +484,126 @@ struct glyf read_points (p, points_, checker)); } + /* Note: Recursively calls itself. Who's checking recursively nested composite glyph BTW? */ + bool get_var_metrics (hb_codepoint_t glyph, + const int *coords, unsigned int coord_count, + hb_vector_t &phantoms /* OUT */) const + { + hb_vector_t points; + hb_vector_t end_points; + if (unlikely (!get_contour_points (glyph, points, end_points, true/*phantom_only*/))) return false; + hb_array_t phantoms_array = points.sub_array (points.length-PHANTOM_COUNT, PHANTOM_COUNT); + init_phantom_points (glyph, phantoms_array); + if (unlikely (!gvar_accel.apply_deltas_to_points (glyph, coords, coord_count, points.as_array (), end_points.as_array ()))) return false; + + for (unsigned int i = 0; i < PHANTOM_COUNT; i++) + phantoms[i] = points[points.length - PHANTOM_COUNT + i]; + + CompositeGlyphHeader::Iterator composite; + if (!get_composite (glyph, &composite)) return true; /* simple glyph */ + do + { + if (composite.current->flags & CompositeGlyphHeader::USE_MY_METRICS) + { + if (unlikely (!get_var_metrics (composite.current->glyphIndex, coords, coord_count, phantoms))) return false; + for (unsigned int j = 0; j < phantoms.length; j++) + composite.current->transform_point (phantoms[j].x, phantoms[j].y); + } + } while (composite.move_to_next()); + 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 (unlikely (!get_contour_points (glyph, points, end_points))) return false; + hb_array_t phantoms_array = points.sub_array (points.length-PHANTOM_COUNT, PHANTOM_COUNT); + init_phantom_points (glyph, phantoms_array); + if (unlikely (!gvar_accel.apply_deltas_to_points (glyph, coords, coord_count, points.as_array (), end_points.as_array ()))) return false; + + CompositeGlyphHeader::Iterator composite; + if (!get_composite (glyph, &composite)) + { + /* simple glyph */ + for (unsigned int i = 0; i + PHANTOM_COUNT < points.length; i++) + bounds.add (points[i]); /* TODO: need to check ON_CURVE or flatten? */ + return true; + } + /* composite glyph */ + do + { + bounds_t comp_bounds; + if (unlikely (!get_bounds_var (composite.current->glyphIndex, coords, coord_count, comp_bounds))) return false; + + composite.current->transform_point (comp_bounds.min.x, comp_bounds.min.y); + composite.current->transform_point (comp_bounds.max.x, comp_bounds.max.y); + bounds._union (comp_bounds); + } while (composite.move_to_next()); + + /* Shift bounds by the updated left side bearing (vertically too?) */ + { + float x_delta = points[points.length - PHANTOM_COUNT + PHANTOM_LEFT].x; + bounds.min.x -= x_delta; + bounds.max.x -= x_delta; + } + + return true; + } + + bool get_extents_var (hb_codepoint_t glyph, + const int *coords, unsigned int coord_count, + hb_glyph_extents_t *extents) const + { + 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; + } + + public: /* based on FontTools _g_l_y_f.py::trim */ bool remove_padding (unsigned int start_offset, unsigned int *end_offset) const @@ -640,8 +763,40 @@ struct glyf return true; } - bool get_extents (hb_codepoint_t glyph, hb_glyph_extents_t *extents) const + float get_advance_var (hb_codepoint_t glyph, + const int *coords, unsigned int coord_count, + bool vertical) const { + float advance = 0.f; + if (coord_count != gvar_accel.get_axis_count ()) return advance; + + hb_vector_t phantoms; + phantoms.resize (PHANTOM_COUNT); + + if (unlikely (!get_var_metrics (glyph, coords, coord_count, phantoms))) return advance; + + if (vertical) + return -(phantoms[PHANTOM_BOTTOM].y - phantoms[PHANTOM_TOP].y); // is this sign correct? + else + return phantoms[PHANTOM_RIGHT].x - phantoms[PHANTOM_LEFT].x; + } + + int get_side_bearing_var (hb_codepoint_t glyph, const int *coords, unsigned int coord_count, bool vertical) const + { + hb_vector_t phantoms; + phantoms.resize (PHANTOM_COUNT); + + if (unlikely (!get_var_metrics (glyph, coords, coord_count, phantoms))) return 0; + return (int)(vertical? -ceilf (phantoms[PHANTOM_TOP].y): floorf (phantoms[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 > 0 && coord_count == gvar_accel.get_axis_count ()) + return get_extents_var (glyph, coords, coord_count, extents); + unsigned int start_offset, end_offset; if (!get_offsets (glyph, &start_offset, &end_offset)) return false; @@ -664,6 +819,11 @@ struct glyf unsigned int num_glyphs; hb_blob_ptr_t loca_table; hb_blob_ptr_t glyf_table; + + /* variable font support */ + gvar::accelerator_t gvar_accel; + hmtx::accelerator_t hmtx_accel; + vmtx::accelerator_t vmtx_accel; }; protected: diff --git a/src/hb-ot-hmtx-table.cc b/src/hb-ot-hmtx-table.cc new file mode 100644 index 000000000..9a58c1a51 --- /dev/null +++ b/src/hb-ot-hmtx-table.cc @@ -0,0 +1,61 @@ +/* + * Copyright © 2019 Adobe Inc. + * + * 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. + * + * Adobe Author(s): Michiharu Ariza + */ + +#include "hb-ot-hmtx-table.hh" +#include "hb-ot-glyf-table.hh" + +namespace OT { + +template +int hmtxvmtx::accelerator_t::get_side_bearing_var_tt (hb_font_t *font, hb_codepoint_t glyph) const +{ + glyf::accelerator_t glyf_accel; + glyf_accel.init (font->face); + + int side_bearing = glyf_accel.get_side_bearing_var (glyph, font->coords, font->num_coords, T::tableTag==HB_OT_TAG_vmtx); + glyf_accel.fini (); + + return side_bearing; +} + +template +unsigned int hmtxvmtx::accelerator_t::get_advance_var_tt (hb_font_t *font, hb_codepoint_t glyph) const +{ + glyf::accelerator_t glyf_accel; + glyf_accel.init (font->face); + + unsigned int advance = glyf_accel.get_advance_var (glyph, font->coords, font->num_coords, T::tableTag==HB_OT_TAG_vmtx); + glyf_accel.fini (); + + return advance; +} + +template int hmtxvmtx::accelerator_t::get_side_bearing_var_tt (hb_font_t *font, hb_codepoint_t glyph) const; +template int hmtxvmtx::accelerator_t::get_side_bearing_var_tt (hb_font_t *font, hb_codepoint_t glyph) const; +template unsigned int hmtxvmtx::accelerator_t::get_advance_var_tt (hb_font_t *font, hb_codepoint_t glyph) const; +template unsigned int hmtxvmtx::accelerator_t::get_advance_var_tt (hb_font_t *font, hb_codepoint_t glyph) const; + +} diff --git a/src/hb-ot-hmtx-table.hh b/src/hb-ot-hmtx-table.hh index 4c1693f48..ff79199b0 100644 --- a/src/hb-ot-hmtx-table.hh +++ b/src/hb-ot-hmtx-table.hh @@ -31,7 +31,6 @@ #include "hb-ot-hhea-table.hh" #include "hb-ot-os2-table.hh" #include "hb-ot-var-hvar-table.hh" -#include "hb-ot-var-gvar-table.hh" /* * hmtx -- Horizontal Metrics @@ -115,7 +114,7 @@ struct hmtxvmtx bool failed = false; for (unsigned int i = 0; i < num_output_glyphs; i++) { - unsigned int side_bearing = 0; + int side_bearing = 0; unsigned int advance = 0; hb_codepoint_t old_gid; if (plan->old_gid_for_new_gid (i, &old_gid)) @@ -208,28 +207,16 @@ struct hmtxvmtx } var_table = hb_sanitize_context_t().reference_table (face, T::variationsTag); - - /* If a TrueType variable font has no HVAR/VVAR table, gvar & glyf table is required for metrics calculation */ - if (var_table.get_blob () == hb_blob_get_empty ()) - { - hb_blob_ptr_t fvar_table = hb_sanitize_context_t().reference_table (face, HB_OT_TAG_fvar); - if (fvar_table.get_blob () != hb_blob_get_empty ()) - { - gvar_accel.init (face); - } - fvar_table.destroy (); - } } void fini () { table.destroy (); var_table.destroy (); - gvar_accel.fini (); } /* TODO Add variations version. */ - unsigned int get_side_bearing (hb_codepoint_t glyph) const + int get_side_bearing (hb_codepoint_t glyph) const { if (glyph < num_advances) return table->longMetricZ[glyph].sb; @@ -241,6 +228,22 @@ struct hmtxvmtx return bearings[glyph - num_advances]; } + int get_side_bearing (hb_font_t *font, hb_codepoint_t glyph) const + { + int side_bearing = get_side_bearing (glyph); + if (likely (glyph < num_metrics)) + { + if (font->num_coords) + { + if (var_table.get_blob () != hb_blob_get_empty ()) + side_bearing += var_table->get_side_bearing_var (glyph, font->coords, font->num_coords); // TODO Optimize?! + else + side_bearing = get_side_bearing_var_tt (font, glyph); + } + } + return side_bearing; + } + unsigned int get_advance (hb_codepoint_t glyph) const { if (unlikely (glyph >= num_metrics)) @@ -268,7 +271,7 @@ struct hmtxvmtx if (var_table.get_blob () != hb_blob_get_empty ()) advance += var_table->get_advance_var (glyph, font->coords, font->num_coords); // TODO Optimize?! else - advance += gvar_accel.get_advance_var (glyph, font->coords, font->num_coords, T::tableTag==HB_OT_TAG_vmtx); + advance = get_advance_var_tt (font, glyph); } } return advance; @@ -290,6 +293,9 @@ struct hmtxvmtx } private: + int get_side_bearing_var_tt (hb_font_t *font, hb_codepoint_t glyph) const; + unsigned int get_advance_var_tt (hb_font_t *font, hb_codepoint_t glyph) const; + unsigned int _advance_for_new_gid (const hb_subset_plan_t *plan, hb_codepoint_t new_gid) const { @@ -314,7 +320,6 @@ struct hmtxvmtx private: hb_blob_ptr_t table; hb_blob_ptr_t var_table; - gvar::accelerator_t gvar_accel; }; protected: diff --git a/src/hb-ot-var-gvar-table.hh b/src/hb-ot-var-gvar-table.hh index 43841274d..0a8a4909a 100644 --- a/src/hb-ot-var-gvar-table.hh +++ b/src/hb-ot-var-gvar-table.hh @@ -41,6 +41,31 @@ namespace OT { +struct contour_point_t +{ + void init () { flag = 0; x = y = 0.0f; } + uint8_t flag; + float x, y; +}; + +struct range_checker_t +{ + range_checker_t (const void *table_, unsigned int start_offset_, unsigned int end_offset_) + : table ((const char*)table_), start_offset (start_offset_), end_offset (end_offset_) {} + + template + bool in_range (const T *p) const + { + return ((const char *) p) >= table + start_offset + && ((const char *) p + T::static_size) <= table + end_offset; + } + + protected: + const char *table; + const unsigned int start_offset; + const unsigned int end_offset; +}; + struct Tuple : UnsizedArrayOf {}; struct TuppleIndex : HBUINT16 @@ -159,8 +184,6 @@ struct TupleVarCount : HBUINT16 struct GlyphVarData { - typedef glyf::accelerator_t::range_checker_t range_checker_t; - const TupleVarHeader &get_tuple_var_header (void) const { return StructAfter(data); } @@ -461,8 +484,6 @@ struct gvar const HBUINT32 *get_long_offset_array () const { return (const HBUINT32 *)&offsetZ; } const HBUINT16 *get_short_offset_array () const { return (const HBUINT16 *)&offsetZ; } - typedef glyf::accelerator_t::contour_point_t contour_point_t; - public: struct accelerator_t { @@ -471,7 +492,6 @@ struct gvar memset (this, 0, sizeof (accelerator_t)); gvar_table = hb_sanitize_context_t ().reference_table (face); - glyf_accel.init (face); hb_blob_ptr_t fvar_table = hb_sanitize_context_t ().reference_table (face); unsigned int axis_count = fvar_table->get_axis_count (); fvar_table.destroy (); @@ -489,27 +509,8 @@ struct gvar void fini () { gvar_table.destroy (); - 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, @@ -541,7 +542,7 @@ struct gvar if (unlikely (!iterator.in_range (p, length))) return false; - GlyphVarData::range_checker_t checker (p, 0, length); + range_checker_t checker (p, 0, length); hb_vector_t private_indices; if (iterator.current_tuple->has_private_points () && !GlyphVarData::unpack_points (p, private_indices, checker)) @@ -607,148 +608,30 @@ struct gvar return true; } - /* Note: Recursively calls itself. Who's checking recursively nested composite glyph BTW? */ - bool get_var_metrics (hb_codepoint_t glyph, - const int *coords, unsigned int coord_count, - hb_vector_t &phantoms) const - { - hb_vector_t points; - hb_vector_t end_points; - 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_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 */ - do - { - if (composite.current->flags & glyf::CompositeGlyphHeader::USE_MY_METRICS) - { - if (!get_var_metrics (composite.current->glyphIndex, coords, coord_count, phantoms)) - return false; - for (unsigned int j = 0; j < phantoms.length; j++) - composite.current->transform_point (phantoms[j].x, phantoms[j].y); - } - } while (composite.move_to_next()); - 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]); /* TODO: need to check ON_CURVE or flatten? */ - return true; - } - /* composite glyph */ - do - { - bounds_t comp_bounds; - if (!get_bounds_var (composite.current->glyphIndex, coords, coord_count, comp_bounds)) - return false; - - composite.current->transform_point (comp_bounds.min.x, comp_bounds.min.y); - composite.current->transform_point (comp_bounds.max.x, comp_bounds.max.y); - 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 - { - float advance = 0.f; - if (coord_count != gvar_table->axisCount) return advance; - - hb_vector_t points; - points.resize (glyf_acc_t::PHANTOM_COUNT); - - if (!get_var_metrics (glyph, coords, coord_count, points)) - return advance; - - if (vertical) - return -(points[glyf_acc_t::PHANTOM_BOTTOM].y - points[glyf_acc_t::PHANTOM_TOP].y); // is this sign correct? - else - 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; - } + unsigned int get_axis_count () const { return gvar_table->axisCount; } protected: + static float infer_delta (float target_val, float prev_val, float next_val, + float prev_delta, float next_delta) + { + if (prev_val == next_val) + return (prev_delta == next_delta)? prev_delta: 0.f; + else if (target_val <= MIN (prev_val, next_val)) + return (prev_val < next_val) ? prev_delta: next_delta; + else if (target_val >= MAX (prev_val, next_val)) + return (prev_val > next_val)? prev_delta: next_delta; + + /* linear interpolation */ + float r = (target_val - prev_val) / (next_val - prev_val); + return (1.f - r) * prev_delta + r * next_delta; + } + const GlyphVarData *get_glyph_var_data (hb_codepoint_t glyph) const { return gvar_table->get_glyph_var_data (glyph); } private: hb_blob_ptr_t gvar_table; hb_vector_t shared_tuples; - glyf::accelerator_t glyf_accel; }; protected: diff --git a/src/hb-ot-var-hvar-table.hh b/src/hb-ot-var-hvar-table.hh index 97e70605c..21d6b765b 100644 --- a/src/hb-ot-var-hvar-table.hh +++ b/src/hb-ot-var-hvar-table.hh @@ -359,7 +359,15 @@ struct HVARVVAR return (this+varStore).get_delta (varidx, coords, coord_count); } - bool has_sidebearing_deltas () const { return lsbMap && rsbMap; } + float get_side_bearing_var (hb_codepoint_t glyph, + const int *coords, unsigned int coord_count) const + { + if (!has_side_bearing_deltas ()) return 0.f; + unsigned int varidx = (this+lsbMap).map (glyph); + return (this+varStore).get_delta (varidx, coords, coord_count); + } + + bool has_side_bearing_deltas () const { return lsbMap && rsbMap; } protected: FixedVersion<>version; /* Version of the metrics variation table