[draw][glyf] Implement quadratic to cubic call translation
This commit is contained in:
parent
74fdcdcac8
commit
d106900bfd
@ -123,11 +123,6 @@ _move_to_nil (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *
|
||||
static void
|
||||
_line_to_nil (hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED, void *user_data HB_UNUSED) {}
|
||||
|
||||
static void
|
||||
_quadratic_to_nil (hb_position_t control_x HB_UNUSED, hb_position_t control_y HB_UNUSED,
|
||||
hb_position_t to_x HB_UNUSED, hb_position_t to_y HB_UNUSED,
|
||||
void *user_data HB_UNUSED) {}
|
||||
|
||||
static void
|
||||
_cubic_to_nil (hb_position_t control1_x HB_UNUSED, hb_position_t control1_y HB_UNUSED,
|
||||
hb_position_t control2_x HB_UNUSED, hb_position_t control2_y HB_UNUSED,
|
||||
@ -153,7 +148,7 @@ hb_draw_funcs_create ()
|
||||
|
||||
funcs->move_to = (hb_draw_move_to_func_t) _move_to_nil;
|
||||
funcs->line_to = (hb_draw_line_to_func_t) _line_to_nil;
|
||||
funcs->quadratic_to = (hb_draw_quadratic_to_func_t) _quadratic_to_nil;
|
||||
funcs->quadratic_to = nullptr;
|
||||
funcs->cubic_to = (hb_draw_cubic_to_func_t) _cubic_to_nil;
|
||||
funcs->close_path = (hb_draw_close_path_func_t) _close_path_nil;
|
||||
return funcs;
|
||||
|
@ -49,6 +49,9 @@ typedef void (*hb_draw_close_path_func_t) (void *user_data);
|
||||
*
|
||||
* Glyph decompose callbacks.
|
||||
*
|
||||
* _move_to, _line_to and _cubic_to are nessecary to be defined but we
|
||||
* can translate _quadratic_to calls to _cubic_to in case isn't defined.
|
||||
*
|
||||
* Since: REPLACEME
|
||||
**/
|
||||
typedef struct hb_draw_funcs_t hb_draw_funcs_t;
|
||||
|
@ -1043,6 +1043,36 @@ struct glyf
|
||||
add_gid_and_children (item.glyphIndex, gids_to_retain, depth);
|
||||
}
|
||||
|
||||
static void
|
||||
_normal_quadratic_to_call (hb_font_t *font, const hb_draw_funcs_t *funcs,
|
||||
float from_x HB_UNUSED, float from_y HB_UNUSED,
|
||||
float control_x, float control_y,
|
||||
float to_x, float to_y,
|
||||
void *user_data)
|
||||
{
|
||||
funcs->quadratic_to (font->em_scalef_x (control_x), font->em_scalef_y (control_y),
|
||||
font->em_scalef_x (to_x), font->em_scalef_y (to_y),
|
||||
user_data);
|
||||
}
|
||||
|
||||
static void
|
||||
_translate_quadratic_to_cubic (hb_font_t *font, const hb_draw_funcs_t *funcs,
|
||||
float from_x, float from_y,
|
||||
float control_x, float control_y,
|
||||
float to_x, float to_y,
|
||||
void *user_data)
|
||||
{
|
||||
/* based on https://github.com/fonttools/fonttools/blob/a37dab3/Lib/fontTools/pens/basePen.py#L218 */
|
||||
float mid1_x = from_x + 0.6666666667f * (control_x - from_x);
|
||||
float mid1_y = from_y + 0.6666666667f * (control_y - from_y);
|
||||
float mid2_x = to_x + 0.6666666667f * (control_x - to_x);
|
||||
float mid2_y = to_y + 0.6666666667f * (control_y - to_y);
|
||||
funcs->cubic_to (font->em_scalef_x (mid1_x), font->em_scalef_y (mid1_y),
|
||||
font->em_scalef_x (mid2_x), font->em_scalef_y (mid2_y),
|
||||
font->em_scalef_x (to_x), font->em_scalef_y (to_y),
|
||||
user_data);
|
||||
}
|
||||
|
||||
bool
|
||||
get_path (hb_font_t *font, hb_codepoint_t gid,
|
||||
const hb_draw_funcs_t *funcs, void *user_data) const
|
||||
@ -1055,10 +1085,15 @@ struct glyf
|
||||
if (unlikely (!get_points (font, gid, all_points))) return false;
|
||||
hb_array_t<contour_point_t> points = all_points.sub_array (0, all_points.length - 4);
|
||||
|
||||
void (*quad_to) (hb_font_t *, const hb_draw_funcs_t *,
|
||||
float, float, float, float, float, float,
|
||||
void *) = funcs->quadratic_to ? _normal_quadratic_to_call : _translate_quadratic_to_cubic;
|
||||
|
||||
unsigned contour_start = 0;
|
||||
/* Learnt from https://github.com/opentypejs/opentype.js/blob/4e0bb99/src/tables/glyf.js#L222 */
|
||||
while (contour_start < points.length)
|
||||
{
|
||||
float prev_x = 0; float prev_y = 0;
|
||||
unsigned contour_length = 0;
|
||||
for (unsigned i = contour_start; i < points.length; ++i)
|
||||
{
|
||||
@ -1070,15 +1105,23 @@ struct glyf
|
||||
contour_point_t *next = &points[contour_start];
|
||||
|
||||
if (curr->flag & Glyph::FLAG_ON_CURVE)
|
||||
funcs->move_to (font->em_scalef_x (curr->x), font->em_scalef_y (curr->y), user_data);
|
||||
{
|
||||
prev_x = curr->x; prev_y = curr->y;
|
||||
funcs->move_to (font->em_scalef_x (prev_x), font->em_scalef_y (prev_y), user_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (next->flag & Glyph::FLAG_ON_CURVE)
|
||||
funcs->move_to (font->em_scalef_x (next->x), font->em_scalef_y (next->y), user_data);
|
||||
{
|
||||
prev_x = next->x; prev_y = next->y;
|
||||
funcs->move_to (font->em_scalef_x (prev_x), font->em_scalef_y (prev_y), user_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
prev_x = (curr->x + next->x) / 2.f; prev_y = (curr->y + next->y) / 2.f;
|
||||
/* If both first and last points are off-curve, start at their middle. */
|
||||
funcs->move_to (font->em_scalef_x ((curr->x + next->x) / 2.f),
|
||||
font->em_scalef_y ((curr->y + next->y) / 2.f), user_data);
|
||||
funcs->move_to (font->em_scalef_x (prev_x), font->em_scalef_y (prev_y), user_data);
|
||||
}
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < contour_length; ++i)
|
||||
@ -1087,14 +1130,17 @@ struct glyf
|
||||
next = &points[contour_start + ((i + 1) % contour_length)];
|
||||
|
||||
if (curr->flag & Glyph::FLAG_ON_CURVE)
|
||||
{
|
||||
prev_x = curr->x; prev_y = curr->y;
|
||||
funcs->line_to (font->em_scalef_x (curr->x), font->em_scalef_y (curr->y), user_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
float to_x, to_y;
|
||||
if (next->flag & Glyph::FLAG_ON_CURVE) { to_x = next->x; to_y = next->y; }
|
||||
else { to_x = (curr->x + next->x) / 2.f; to_y = (curr->y + next->y) / 2.f; }
|
||||
funcs->quadratic_to (font->em_scalef_x (curr->x), font->em_scalef_y (curr->y),
|
||||
font->em_scalef_x (to_x), font->em_scalef_y (to_y), user_data);
|
||||
quad_to (font, funcs, prev_x, prev_y, curr->x, curr->y, to_x, to_y, user_data);
|
||||
prev_x = to_x; prev_y = to_y;
|
||||
}
|
||||
}
|
||||
contour_start += contour_length;
|
||||
|
@ -160,6 +160,7 @@ close_path (user_data_t *user_data)
|
||||
}
|
||||
|
||||
static hb_draw_funcs_t *funcs;
|
||||
static hb_draw_funcs_t *funcs2; /* this one translates quadratic calls to cubic ones */
|
||||
|
||||
static void
|
||||
test_hb_glyph_empty (void)
|
||||
@ -183,6 +184,7 @@ test_hb_glyph_glyf (void)
|
||||
|
||||
user_data.consumed = 0;
|
||||
g_assert (!hb_font_draw_glyph (font, 4, funcs, &user_data));
|
||||
|
||||
user_data.consumed = 0;
|
||||
g_assert (hb_font_draw_glyph (font, 3, funcs, &user_data));
|
||||
char expected[] = "M275,442L275,442Q232,442 198,420Q164,397 145,353Q126,309 126,245L126,245"
|
||||
@ -193,6 +195,20 @@ test_hb_glyph_glyf (void)
|
||||
"Q378,321 367,334Q355,347 350,366L350,366L325,454L371,417Q346,430 321,436Q296,442 275,442Z";
|
||||
g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
|
||||
|
||||
/* Test translating quadratic calls to cubic by a _draw_funcs_t that doesn't set the callback */
|
||||
user_data.consumed = 0;
|
||||
g_assert (hb_font_draw_glyph (font, 3, funcs2, &user_data));
|
||||
char expected2[] = "M275,442L275,442C246,442 221,435 198,420C175,405 158,382 145,353C132,324 126,288 126,245"
|
||||
"L126,245C126,203 133,168 147,139C160,110 179,88 204,73C228,58 256,50 287,50L287,50"
|
||||
"C316,50 342,57 367,70C392,83 412,103 427,128L427,128L451,116C438,75 415,43 384,21"
|
||||
"C352,-2 313,-13 266,-13L266,-13C221,-13 181,-3 148,18C114,38 88,67 70,104"
|
||||
"C52,141 43,185 43,236L43,236C43,288 54,333 76,371C97,408 125,437 160,457"
|
||||
"C195,477 232,487 272,487L272,487C301,487 329,481 354,470C379,459 400,443 417,424"
|
||||
"C434,405 444,383 448,358L448,358C443,333 428,321 403,321L403,321"
|
||||
"C386,321 374,325 367,334C359,343 353,353 350,366L350,366L325,454"
|
||||
"L371,417C354,426 338,432 321,436C304,440 289,442 275,442Z";
|
||||
g_assert_cmpmem (str, user_data.consumed, expected2, sizeof (expected2) - 1);
|
||||
|
||||
hb_variation_t var;
|
||||
var.tag = HB_TAG ('w','g','h','t');
|
||||
var.value = 800;
|
||||
@ -200,13 +216,13 @@ test_hb_glyph_glyf (void)
|
||||
|
||||
user_data.consumed = 0;
|
||||
g_assert (hb_font_draw_glyph (font, 3, funcs, &user_data));
|
||||
char expected2[] = "M323,448L323,448Q297,448 271,430Q244,412 227,371"
|
||||
char expected3[] = "M323,448L323,448Q297,448 271,430Q244,412 227,371"
|
||||
"Q209,330 209,261L209,261Q209,204 226,166Q242,127 273,107Q303,86 344,86L344,86Q378,86 404,101"
|
||||
"Q430,115 451,137L451,137L488,103Q458,42 404,13Q350,-16 279,-16L279,-16Q211,-16 153,13Q95,41 60,99"
|
||||
"Q25,156 25,241L25,241Q25,323 62,382Q99,440 163,471Q226,501 303,501L303,501Q357,501 399,481"
|
||||
"Q440,460 464,426Q488,392 492,352L492,352Q475,297 420,297L420,297Q390,297 366,320"
|
||||
"Q342,342 339,401L339,401L333,469L411,427Q387,438 368,443Q348,448 323,448Z";
|
||||
g_assert_cmpmem (str, user_data.consumed, expected2, sizeof (expected2) - 1);
|
||||
g_assert_cmpmem (str, user_data.consumed, expected3, sizeof (expected3) - 1);
|
||||
|
||||
hb_font_destroy (font);
|
||||
}
|
||||
@ -754,6 +770,12 @@ main (int argc, char **argv)
|
||||
hb_draw_funcs_set_cubic_to_func (funcs, (hb_draw_cubic_to_func_t) cubic_to);
|
||||
hb_draw_funcs_set_close_path_func (funcs, (hb_draw_close_path_func_t) close_path);
|
||||
|
||||
funcs2 = hb_draw_funcs_create ();
|
||||
hb_draw_funcs_set_move_to_func (funcs2, (hb_draw_move_to_func_t) move_to);
|
||||
hb_draw_funcs_set_line_to_func (funcs2, (hb_draw_line_to_func_t) line_to);
|
||||
hb_draw_funcs_set_cubic_to_func (funcs2, (hb_draw_cubic_to_func_t) cubic_to);
|
||||
hb_draw_funcs_set_close_path_func (funcs2, (hb_draw_close_path_func_t) close_path);
|
||||
|
||||
hb_test_init (&argc, &argv);
|
||||
hb_test_add (test_itoa);
|
||||
hb_test_add (test_hb_glyph_empty);
|
||||
@ -767,5 +789,6 @@ main (int argc, char **argv)
|
||||
unsigned result = hb_test_run ();
|
||||
|
||||
hb_draw_funcs_destroy (funcs);
|
||||
hb_draw_funcs_destroy (funcs2);
|
||||
return result;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user