add support of anchor point & SCALED/UNSCALED_COMPONENT_OFFSET
some code cleanup
This commit is contained in:
parent
94ef1a703f
commit
49f9359632
|
@ -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)))
|
||||
|
|
|
@ -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.
|
@ -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 ();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue