add support of anchor point & SCALED/UNSCALED_COMPONENT_OFFSET

some code cleanup
This commit is contained in:
Michiharu Ariza 2019-03-26 17:10:46 -07:00
parent 94ef1a703f
commit 49f9359632
4 changed files with 179 additions and 58 deletions

View File

@ -34,6 +34,8 @@
#include "hb-ot-var-gvar-table.hh"
#include "hb-subset-glyf.hh"
#include <float.h>
namespace OT {
@ -174,8 +176,50 @@ struct glyf
return size;
}
void transform_point (float &x, float &y) const
bool is_anchored () const { return (flags & ARGS_ARE_XY_VALUES) == 0; }
void get_anchor_points (unsigned int &point1, unsigned int &point2) const
{
const HBUINT8 *p = &StructAfter<const HBUINT8> (glyphIndex);
if (flags & ARG_1_AND_2_ARE_WORDS)
{
point1 = ((const HBUINT16 *)p)[0];
point2 = ((const HBUINT16 *)p)[1];
}
else
{
point1 = p[0];
point2 = p[1];
}
}
void transform_points (contour_point_vector_t &points) const
{
float matrix[4];
contour_point_t trans;
if (get_transformation (matrix, trans))
{
if (scaled_offsets ())
{
points.translate (trans);
points.transform (matrix);
}
else
{
points.transform (matrix);
points.translate (trans);
}
}
}
protected:
bool scaled_offsets () const
{ return (flags & (SCALED_COMPONENT_OFFSET|UNSCALED_COMPONENT_OFFSET)) == SCALED_COMPONENT_OFFSET; }
bool get_transformation (float (&matrix)[4], contour_point_t &trans) const
{
matrix[0] = matrix[3] = 1.f;
matrix[1] = matrix[2] = 0.f;
int tx, ty;
const HBINT8 *p = &StructAfter<const HBINT8> (glyphIndex);
if (flags & ARG_1_AND_2_ARE_WORDS)
@ -190,28 +234,33 @@ struct glyf
tx = *p++;
ty = *p++;
}
if (!(flags & ARGS_ARE_XY_VALUES)) tx = ty = 0; /* TODO: anchor point unsupported for now */
if (is_anchored ()) tx = ty = 0;
trans.init ((float)tx, (float)ty);
if (flags & WE_HAVE_A_SCALE)
{
float scale = ((const F2DOT14*)p)->to_float ();
x *= scale;
y *= scale;
matrix[0] = matrix[3] = ((const F2DOT14*)p)->to_float ();
return true;
}
else if (flags & WE_HAVE_AN_X_AND_Y_SCALE)
{
x *= ((const F2DOT14*)p)[0].to_float ();
y *= ((const F2DOT14*)p)[1].to_float ();
matrix[0] = ((const F2DOT14*)p)[0].to_float ();
matrix[3] = ((const F2DOT14*)p)[1].to_float ();
return true;
}
else if (flags & WE_HAVE_A_TWO_BY_TWO)
{
float x_ = x * ((const F2DOT14*)p)[0].to_float () + y * ((const F2DOT14*)p)[1].to_float ();
y = x * ((const F2DOT14*)p)[2].to_float () + y * ((const F2DOT14*)p)[3].to_float ();
x = x_;
matrix[0] = ((const F2DOT14*)p)[0].to_float ();
matrix[1] = ((const F2DOT14*)p)[1].to_float ();
matrix[2] = ((const F2DOT14*)p)[2].to_float ();
matrix[3] = ((const F2DOT14*)p)[3].to_float ();
return true;
}
if (tx | ty) { x += tx; y += ty; }
return tx || ty;
}
public:
struct Iterator
{
const char *glyph_start;
@ -362,7 +411,7 @@ struct glyf
template <typename T>
static bool read_points (const HBUINT8 *&p /* IN/OUT */,
hb_vector_t<contour_point_t> &points_ /* IN/OUT */,
contour_point_vector_t &points_ /* IN/OUT */,
const range_checker_t &checker)
{
T coord_setter;
@ -411,7 +460,7 @@ struct glyf
* 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 */,
contour_point_vector_t &points_ /* OUT */,
hb_vector_t<unsigned int> &end_points_ /* OUT */,
const bool phantom_only=false) const
{
@ -493,9 +542,9 @@ struct glyf
/* 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_array_t<contour_point_t> phantoms /* OUT */) const
contour_point_vector_t &phantoms /* OUT */) const
{
hb_vector_t<contour_point_t> points;
contour_point_vector_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);
@ -513,9 +562,9 @@ struct glyf
if (composite.current->flags & CompositeGlyphHeader::USE_MY_METRICS)
{
if (unlikely (!get_var_metrics (composite.current->glyphIndex, coords, coord_count,
phantoms.sub_array (0, 2)))) return false;
for (unsigned int j = 0; j < phantoms.length; j++)
composite.current->transform_point (phantoms[j].x, phantoms[j].y);
phantoms))) return false;
composite.current->transform_points (phantoms);
}
} while (composite.move_to_next());
return true;
@ -533,27 +582,20 @@ struct glyf
max.y = MAX (max.y, p.y);
}
void offset (const contour_point_t &p) { min.offset (p); max.offset (p); }
void merge (const contour_bounds_t &b)
{
if (empty ()) { *this = b; return; }
add (b.min);
add (b.max);
}
bool empty () const { return (min.x >= max.x) || (min.y >= max.y); }
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,
/* Note: Recursively calls itself.
* all_points does not include phantom points
*/
bool get_points_var (hb_codepoint_t glyph,
const int *coords, unsigned int coord_count,
contour_bounds_t &bounds) const
contour_point_vector_t &all_points /* OUT */) const
{
hb_vector_t<contour_point_t> points;
contour_point_vector_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);
@ -565,34 +607,50 @@ struct glyf
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? */
if (likely (points.length >= PHANTOM_COUNT))
all_points.extend (points.sub_array (0, points.length - PHANTOM_COUNT));
}
else
{
/* composite glyph */
do
{
contour_bounds_t comp_bounds;
if (unlikely (!get_bounds_var (composite.current->glyphIndex, coords, coord_count, comp_bounds))) return false;
contour_point_vector_t comp_points;
if (unlikely (!get_points_var (composite.current->glyphIndex, coords, coord_count,
comp_points))) return false;
/* Apply offset & scaling */
composite.current->transform_point (comp_bounds.min.x, comp_bounds.min.y);
composite.current->transform_point (comp_bounds.max.x, comp_bounds.max.y);
/* Apply component transformation & translation */
composite.current->transform_points (comp_points);
/* Apply offset adjustments from gvar */
comp_bounds.offset (points[comp_index]);
/* Apply translatation from gvar */
comp_points.translate (points[comp_index]);
if (composite.current->is_anchored ())
{
unsigned int p1, p2;
composite.current->get_anchor_points (p1, p2);
if (likely (p1 < all_points.length && p2 < comp_points.length))
{
contour_point_t delta;
delta.init (all_points[p1].x - comp_points[p2].x,
all_points[p1].y - comp_points[p2].y);
comp_points.translate (delta);
}
}
all_points.extend (comp_points.as_array ());
bounds.merge (comp_bounds);
comp_index++;
} 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;
/* Undocumented rasterizer behavior:
* Shift points horizontally by the updated left side bearing
*/
contour_point_t delta;
delta.init (points[points.length - PHANTOM_COUNT + PHANTOM_LEFT].x, 0.f);
if (delta.x != 0.f) all_points.translate (delta);
}
return true;
@ -602,8 +660,12 @@ struct glyf
const int *coords, unsigned int coord_count,
hb_glyph_extents_t *extents) const
{
contour_point_vector_t all_points;
if (unlikely (!get_points_var (glyph, coords, coord_count, all_points))) return false;
contour_bounds_t bounds;
if (unlikely (!get_bounds_var (glyph, coords, coord_count, bounds))) return false;
for (unsigned int i = 0; i < all_points.length; i++)
bounds.add (all_points[i]);
if (bounds.min.x >= bounds.max.x)
{
@ -793,11 +855,11 @@ struct glyf
bool vertical) const
{
bool success = false;
hb_vector_t<contour_point_t> phantoms;
contour_point_vector_t phantoms;
phantoms.resize (PHANTOM_COUNT);
if (likely (coord_count == gvar_accel.get_axis_count ()))
success = get_var_metrics (glyph, coords, coord_count, phantoms.as_array ());
success = get_var_metrics (glyph, coords, coord_count, phantoms);
if (unlikely (!success))
return vertical? vmtx_accel.get_advance (glyph): hmtx_accel.get_advance (glyph);
@ -810,7 +872,7 @@ struct glyf
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;
contour_point_vector_t phantoms;
phantoms.resize (PHANTOM_COUNT);
if (unlikely (!get_var_metrics (glyph, coords, coord_count, phantoms)))

View File

@ -31,8 +31,6 @@
#include "hb-ot-glyf-table.hh"
#include "hb-ot-var-fvar-table.hh"
#include <float.h>
/*
* gvar -- Glyph Variation Table
* https://docs.microsoft.com/en-us/typography/opentype/spec/gvar
@ -43,14 +41,42 @@ namespace OT {
struct contour_point_t
{
void init () { flag = 0; x = y = 0.0f; }
void init (float x_=0.f, float y_=0.f) { flag = 0; x = x_; y = y_; }
void offset (const contour_point_t &p) { x += p.x; y += p.y; }
void translate (const contour_point_t &p) { x += p.x; y += p.y; }
uint8_t flag;
float x, y;
};
struct contour_point_vector_t : hb_vector_t<contour_point_t>
{
void extend (const hb_array_t<contour_point_t> &a)
{
unsigned int old_len = length;
resize (old_len + a.length);
for (unsigned int i = 0; i < a.length; i++)
(*this)[old_len + i] = a[i];
}
void transform (const float (&matrix)[4])
{
for (unsigned int i = 0; i < length; i++)
{
contour_point_t &p = (*this)[i];
float x_ = p.x * matrix[0] + p.y * matrix[1];
p.y = p.x * matrix[2] + p.y * matrix[3];
p.x = x_;
}
}
void translate (const contour_point_t& delta)
{
for (unsigned int i = 0; i < length; i++)
(*this)[i].translate (delta);
}
};
struct range_checker_t
{
range_checker_t (const void *table_, unsigned int start_offset_, unsigned int end_offset_)
@ -564,7 +590,7 @@ struct gvar
&iterator))
return false;
hb_vector_t<contour_point_t> deltas; /* flag is used to indicate referenced point */
contour_point_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 ();
@ -605,7 +631,7 @@ struct gvar
} while (iterator.move_to_next ());
/* infer deltas for unreferenced points */
hb_vector_t<contour_point_t> orig_points;
contour_point_vector_t orig_points;
orig_points.resize (points.length);
for (unsigned int i = 0; i < orig_points.length; i++)
orig_points[i] = points[i];

Binary file not shown.

View File

@ -133,6 +133,38 @@ test_advance_tt_var_hvarvvar (void)
hb_font_destroy (font);
}
static void
test_advance_tt_var_anchor (void)
{
hb_face_t *face = hb_test_open_font_file ("fonts/SourceSansVariable-Roman.anchor.ttf");
g_assert (face);
hb_font_t *font = hb_font_create (face);
hb_face_destroy (face);
g_assert (font);
hb_ot_font_set_funcs (font);
hb_glyph_extents_t extents;
hb_bool_t result = hb_font_get_glyph_extents (font, 2, &extents);
g_assert (result);
g_assert_cmpint (extents.x_bearing, ==, 56);
g_assert_cmpint (extents.y_bearing, ==, 672);
g_assert_cmpint (extents.width, ==, 556);
g_assert_cmpint (extents.height, ==, -684);
float coords[1] = { 500.0f };
hb_font_set_var_coords_design (font, coords, 1);
result = hb_font_get_glyph_extents (font, 2, &extents);
g_assert (result);
g_assert_cmpint (extents.x_bearing, ==, 50);
g_assert_cmpint (extents.y_bearing, ==, 668);
g_assert_cmpint (extents.width, ==, 593);
g_assert_cmpint (extents.height, ==, -680);
hb_font_destroy (font);
}
int
main (int argc, char **argv)
{
@ -141,6 +173,7 @@ main (int argc, char **argv)
hb_test_add (test_extents_tt_var);
hb_test_add (test_advance_tt_var_nohvar);
hb_test_add (test_advance_tt_var_hvarvvar);
hb_test_add (test_advance_tt_var_anchor);
return hb_test_run ();
}