moved most of var code from gvar to glyf

initialize phantom points from metrics from htmx/vmtx & glyf bbox before execution
added source file hb-ot-hmtx-table.cc to call glyf from hmtx/vmtx indirectly & temporarily, workaround a cyclic reference between the two
This commit is contained in:
Michiharu Ariza 2019-03-17 15:36:26 -07:00
parent 00b2653ac3
commit 8a7998fd6c
8 changed files with 336 additions and 221 deletions

View File

@ -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 \

View File

@ -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. */ \

View File

@ -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)

View File

@ -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<CompositeGlyphHeader, CompositeGlyphHeader> (*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<glyf> (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 <typename T>
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<GlyphHeader> (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<contour_point_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<contour_point_t> &points_ /* OUT */,
hb_vector_t<unsigned int> &_end_points /* OUT */,
hb_vector_t<unsigned int> &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<HBUINT8> (&end_pts[num_contours+1], end_pts[num_contours]);
@ -481,6 +484,126 @@ struct glyf
read_points<y_setter_t> (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<contour_point_t> &phantoms /* OUT */) const
{
hb_vector_t<contour_point_t> points;
hb_vector_t<unsigned int> end_points;
if (unlikely (!get_contour_points (glyph, points, end_points, true/*phantom_only*/))) return false;
hb_array_t<contour_point_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<contour_point_t> points;
hb_vector_t<unsigned int> end_points;
if (unlikely (!get_contour_points (glyph, points, end_points))) return false;
hb_array_t<contour_point_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<contour_point_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<contour_point_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> loca_table;
hb_blob_ptr_t<glyf> glyf_table;
/* variable font support */
gvar::accelerator_t gvar_accel;
hmtx::accelerator_t hmtx_accel;
vmtx::accelerator_t vmtx_accel;
};
protected:

61
src/hb-ot-hmtx-table.cc Normal file
View File

@ -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 <typename T, typename H>
int hmtxvmtx<T, H>::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 <typename T, typename H>
unsigned int hmtxvmtx<T, H>::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<hmtx, hhea>::accelerator_t::get_side_bearing_var_tt (hb_font_t *font, hb_codepoint_t glyph) const;
template int hmtxvmtx<vmtx, vhea>::accelerator_t::get_side_bearing_var_tt (hb_font_t *font, hb_codepoint_t glyph) const;
template unsigned int hmtxvmtx<hmtx, hhea>::accelerator_t::get_advance_var_tt (hb_font_t *font, hb_codepoint_t glyph) const;
template unsigned int hmtxvmtx<vmtx, vhea>::accelerator_t::get_advance_var_tt (hb_font_t *font, hb_codepoint_t glyph) const;
}

View File

@ -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<HVARVVAR> (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> fvar_table = hb_sanitize_context_t().reference_table<fvar> (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<hmtxvmtx> table;
hb_blob_ptr_t<HVARVVAR> var_table;
gvar::accelerator_t gvar_accel;
};
protected:

View File

@ -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 <typename T>
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<F2DOT14> {};
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<TupleVarHeader>(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<gvar> (face);
glyf_accel.init (face);
hb_blob_ptr_t<fvar> fvar_table = hb_sanitize_context_t ().reference_table<fvar> (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<contour_point_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 <unsigned int> 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<contour_point_t> &phantoms) const
{
hb_vector_t<contour_point_t> points;
hb_vector_t<unsigned int> 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<contour_point_t> points;
hb_vector_t<unsigned int> 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<contour_point_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> gvar_table;
hb_vector_t<F2DOT14> shared_tuples;
glyf::accelerator_t glyf_accel;
};
protected:

View File

@ -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