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:
parent
00b2653ac3
commit
8a7998fd6c
|
@ -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 \
|
||||
|
|
|
@ -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. */ \
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue