[glyf] Switch to ttf-parser's glyf to path algorithm

It consumes each point at a time and doesn't need to know contour size before hand
This commit is contained in:
Ebrahim Byagowi 2020-02-17 10:11:49 +03:30
parent 3c792c2aa5
commit 60f8f384f9
2 changed files with 254 additions and 206 deletions

View File

@ -1059,6 +1059,19 @@ struct glyf
user_data);
}
struct optional_point_t
{
optional_point_t () { is_null = true; }
optional_point_t (float x_, float y_) { x = x_; y = y_; is_null = false; }
bool is_null;
float x;
float y;
optional_point_t lerp (optional_point_t p, float t)
{ return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); }
};
bool
get_path (hb_font_t *font, hb_codepoint_t gid,
const hb_draw_funcs_t *funcs, void *user_data) const
@ -1075,69 +1088,115 @@ struct glyf
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)
/* based on https://github.com/RazrFalcon/ttf-parser/blob/master/src/glyf.rs#L292 which is base on font-rs */
unsigned point_index = 0;
while (point_index < points.length)
{
float prev_x = 0; float prev_y = 0;
unsigned contour_length = 0;
for (unsigned i = contour_start; i < points.length; ++i)
/* Skip empty contours */
if (points[point_index].is_end_point)
{
contour_length++;
if (points[i].is_end_point)
break;
}
/* Skip contours with less than 2 points */
if (contour_length < 2)
{
contour_start += contour_length;
++point_index;
continue;
}
contour_point_t *curr = &points[contour_start + contour_length - 1];
contour_point_t *next = &points[contour_start];
if (curr->flag & Glyph::FLAG_ON_CURVE)
optional_point_t first_oncurve = optional_point_t ();
optional_point_t first_offcurve = optional_point_t ();
optional_point_t last_offcurve = optional_point_t ();
float last_x = 0, last_y = 0;
do
{
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)
bool is_on_curve = points[point_index].flag & Glyph::FLAG_ON_CURVE;
optional_point_t p (points[point_index].x, points[point_index].y);
if (first_oncurve.is_null)
{
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);
if (is_on_curve)
{
first_oncurve = p;
last_x = p.x; last_y = p.y;
funcs->move_to (font->em_scalef_x (last_x), font->em_scalef_y (last_y),
user_data);
}
else
{
if (!first_offcurve.is_null)
{
optional_point_t mid = first_offcurve.lerp (p, .5f);
first_oncurve = mid;
last_offcurve = p;
last_x = mid.x; last_y = mid.y;
funcs->move_to (font->em_scalef_x (last_x), font->em_scalef_y (last_y),
user_data);
}
else
first_offcurve = p;
}
}
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 (prev_x), font->em_scalef_y (prev_y), user_data);
if (!last_offcurve.is_null)
{
if (is_on_curve)
{
quad_to (font, funcs, last_x, last_y, last_offcurve.x, last_offcurve.y, p.x, p.y, user_data);
last_x = p.x;
last_y = p.y;
last_offcurve = optional_point_t ();
}
else
{
optional_point_t mid = last_offcurve.lerp (p, .5f);
quad_to (font, funcs, last_x, last_y, last_offcurve.x, last_offcurve.y, mid.x, mid.y, user_data);
last_x = mid.x;
last_y = mid.y;
last_offcurve = p;
}
}
else
{
if (is_on_curve)
{
last_x = p.x;
last_y = p.y;
funcs->line_to (font->em_scalef_x (last_x), font->em_scalef_y (last_y),
user_data);
}
else
{
last_offcurve = p;
}
}
}
}
} while (!points[point_index++].is_end_point);
for (unsigned i = 0; i < contour_length; ++i)
while (true)
{
curr = next;
next = &points[contour_start + ((i + 1) % contour_length)];
if (curr->flag & Glyph::FLAG_ON_CURVE)
if (!first_offcurve.is_null && !last_offcurve.is_null)
{
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);
optional_point_t mid = last_offcurve.lerp (first_offcurve, .5f);
quad_to (font, funcs, last_x, last_y, last_offcurve.x, last_offcurve.y, mid.x, mid.y, user_data);
last_x = mid.x;
last_y = mid.y;
last_offcurve = optional_point_t ();
}
else
else if (!first_offcurve.is_null && last_offcurve.is_null)
{
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; }
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;
if (!first_oncurve.is_null)
quad_to (font, funcs, last_x, last_y, first_offcurve.x, first_offcurve.y, first_oncurve.x, first_oncurve.y, user_data);
break;
}
else if (first_offcurve.is_null && !last_offcurve.is_null)
{
if (!first_oncurve.is_null)
quad_to (font, funcs, last_x, last_y, last_offcurve.x, last_offcurve.y, first_oncurve.x, first_oncurve.y, user_data);
break;
}
else /* first_offcurve.is_null && last_offcurve.is_null */
{
if (!first_oncurve.is_null)
funcs->line_to (font->em_scalef_x (first_oncurve.x), font->em_scalef_y (first_oncurve.y),
user_data);
break;
}
}
contour_start += contour_length;
funcs->close_path (user_data);
}
return true;

View File

@ -187,26 +187,27 @@ test_hb_draw_glyf (void)
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"
"Q126,182 147,139Q167,95 204,73Q240,50 287,50L287,50Q330,50 367,70"
"Q404,90 427,128L427,128L451,116Q431,54 384,21Q336,-13 266,-13L266,-13Q198,-13 148,18"
"Q97,48 70,104Q43,160 43,236L43,236Q43,314 76,371Q108,427 160,457Q212,487 272,487L272,487"
"Q316,487 354,470Q392,453 417,424Q442,395 448,358L448,358Q441,321 403,321L403,321"
"Q378,321 367,334Q355,347 350,366L350,366L325,454L371,417Q346,430 321,436Q296,442 275,442Z";
char expected[] = "M275,442Q232,442 198,420Q164,397 145,353Q126,309 126,245"
"Q126,182 147,139Q167,95 204,73Q240,50 287,50Q330,50 367,70"
"Q404,90 427,128L451,116Q431,54 384,21Q336,-13 266,-13"
"Q198,-13 148,18Q97,48 70,104Q43,160 43,236Q43,314 76,371"
"Q108,427 160,457Q212,487 272,487Q316,487 354,470Q392,453 417,424"
"Q442,395 448,358Q441,321 403,321Q378,321 367,334"
"Q355,347 350,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";
char expected2[] = "M275,442C246,442 221,435 198,420C175,405 158,382 145,353"
"C132,324 126,288 126,245C126,203 133,168 147,139C160,110 179,88 204,73"
"C228,58 256,50 287,50C316,50 342,57 367,70C392,83 412,103 427,128"
"L451,116C438,75 415,43 384,21C352,-2 313,-13 266,-13C221,-13 181,-3 148,18"
"C114,38 88,67 70,104C52,141 43,185 43,236C43,288 54,333 76,371"
"C97,408 125,437 160,457C195,477 232,487 272,487C301,487 329,481 354,470"
"C379,459 400,443 417,424C434,405 444,383 448,358C443,333 428,321 403,321"
"C386,321 374,325 367,334C359,343 353,353 350,366L325,454L371,417"
"C354,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;
@ -216,12 +217,13 @@ test_hb_draw_glyf (void)
user_data.consumed = 0;
g_assert (hb_font_draw_glyph (font, 3, funcs, &user_data));
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";
char expected3[] = "M323,448Q297,448 271,430Q244,412 227,371Q209,330 209,261"
"Q209,204 226,166Q242,127 273,107Q303,86 344,86Q378,86 404,101"
"Q430,115 451,137L488,103Q458,42 404,13Q350,-16 279,-16"
"Q211,-16 153,13Q95,41 60,99Q25,156 25,241Q25,323 62,382"
"Q99,440 163,471Q226,501 303,501Q357,501 399,481Q440,460 464,426"
"Q488,392 492,352Q475,297 420,297Q390,297 366,320Q342,342 339,401"
"L333,469L411,427Q387,438 368,443Q348,448 323,448Z";
g_assert_cmpmem (str, user_data.consumed, expected3, sizeof (expected3) - 1);
hb_font_destroy (font);
@ -317,7 +319,7 @@ static void
test_hb_draw_ttf_parser_tests (void)
{
/* https://github.com/RazrFalcon/ttf-parser/blob/337e7d1c/tests/tests.rs#L50-L133 */
char str[1024] = {0};
char str[1024];
user_data_t user_data = {
.str = str,
.size = sizeof (str)
@ -327,28 +329,27 @@ test_hb_draw_ttf_parser_tests (void)
hb_font_t *font = hb_font_create (face);
hb_face_destroy (face);
{
/* We aren't identical on paths points for glyf with ttf-parser but visually, investigate */
user_data.consumed = 0;
g_assert (hb_font_draw_glyph (font, 0, funcs, &user_data));
char expected[] = "M450,0L50,0L50,750L450,750L450,0Z";
char expected[] = "M50,0L50,750L450,750L450,0L50,0Z";
g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
}
{
user_data.consumed = 0;
g_assert (hb_font_draw_glyph (font, 1, funcs, &user_data));
char expected[] = "M514,416L56,416L56,487L514,487L514,416ZM514,217L56,217L56,288L514,288L514,217Z";
char expected[] = "M56,416L56,487L514,487L514,416L56,416ZM56,217L56,288L514,288L514,217L56,217Z";
g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
}
{
user_data.consumed = 0;
g_assert (hb_font_draw_glyph (font, 4, funcs, &user_data));
char expected[] = "M332,536L332,468L197,468L197,0L109,0L109,468L15,468L15,509L109,539L109,570"
"Q109,674 155,720Q201,765 283,765L283,765Q315,765 342,760Q368,754 387,747"
"L387,747L364,678Q348,683 327,688Q306,693 284,693L284,693Q240,693 219,664"
"Q197,634 197,571L197,571L197,536L332,536ZM474,737L474,737Q494,737 510,724"
"Q525,710 525,681L525,681Q525,653 510,639Q494,625 474,625L474,625"
"Q452,625 437,639Q422,653 422,681L422,681Q422,710 437,724Q452,737 474,737Z"
"M429,536L517,536L517,0L429,0L429,536Z";
char expected[] = "M332,468L197,468L197,0L109,0L109,468L15,468L15,509L109,539"
"L109,570Q109,674 155,720Q201,765 283,765Q315,765 342,760"
"Q368,754 387,747L364,678Q348,683 327,688Q306,693 284,693"
"Q240,693 219,664Q197,634 197,571L197,536L332,536L332,468Z"
"M474,737Q494,737 510,724Q525,710 525,681Q525,653 510,639"
"Q494,625 474,625Q452,625 437,639Q422,653 422,681"
"Q422,710 437,724Q452,737 474,737ZM517,536L517,0L429,0L429,536L517,536Z";
g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
}
{
@ -360,11 +361,10 @@ test_hb_draw_ttf_parser_tests (void)
{
user_data.consumed = 0;
g_assert (hb_font_draw_glyph (font, 6, funcs, &user_data));
char expected[] = "M346,536L346,468L211,468L211,0L123,0L123,468L29,468"
"L29,509L123,539L123,570Q123,674 169,720Q215,765 297,765"
"L297,765Q329,765 356,760Q382,754 401,747L401,747L378,678"
"Q362,683 341,688Q320,693 298,693L298,693Q254,693 233,664"
"Q211,634 211,571L211,571L211,536L346,536Z";
char expected[] = "M346,468L211,468L211,0L123,0L123,468L29,468L29,509L123,539"
"L123,570Q123,674 169,720Q215,765 297,765Q329,765 356,760"
"Q382,754 401,747L378,678Q362,683 341,688Q320,693 298,693"
"Q254,693 233,664Q211,634 211,571L211,536L346,536L346,468Z";
g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
}
@ -420,27 +420,25 @@ test_hb_draw_font_kit_glyphs_tests (void)
/* should get a path for the glyph */
user_data.consumed = 0;
g_assert (hb_font_draw_glyph (font, 37, funcs, &user_data));
char expected[] = "M201,0L201,1462L614,1462Q905,1462 1035,1375Q1165,1288 1165,1100"
"L1165,1100Q1165,970 1093,886Q1020,801 881,776L881,776L881,766"
"Q1214,709 1214,416L1214,416Q1214,220 1082,110Q949,0 711,0L711,0L201,0Z"
"M371,1315L371,836L651,836Q831,836 910,893Q989,949 989,1083L989,1083"
"Q989,1206 901,1261Q813,1315 621,1315L621,1315L371,1315ZM662,692L371,692"
"L371,145L676,145Q853,145 943,214Q1032,282 1032,428L1032,428"
"Q1032,564 941,628Q849,692 662,692L662,692Z";
char expected[] = "M201,1462L614,1462Q905,1462 1035,1375Q1165,1288 1165,1100"
"Q1165,970 1093,886Q1020,801 881,776L881,766Q1214,709 1214,416"
"Q1214,220 1082,110Q949,0 711,0L201,0L201,1462ZM371,836L651,836"
"Q831,836 910,893Q989,949 989,1083Q989,1206 901,1261"
"Q813,1315 621,1315L371,1315L371,836ZM371,692L371,145L676,145"
"Q853,145 943,214Q1032,282 1032,428Q1032,564 941,628Q849,692 662,692L371,692Z";
g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
/* should get a path for the glyph */
user_data.consumed = 0;
g_assert (hb_font_draw_glyph (font, 171, funcs, &user_data));
char expected2[] = "M639,-20L639,-20Q396,-20 256,128Q115,276 115,539L115,539"
"Q115,804 246,960Q376,1116 596,1116L596,1116Q802,1116 922,981"
"Q1042,845 1042,623L1042,623L1042,518L287,518Q292,325 385,225"
"Q477,125 645,125L645,125Q822,125 995,199L995,199L995,51"
"Q907,13 829,-4Q750,-20 639,-20ZM594,977L594,977"
"Q462,977 384,891Q305,805 291,653L291,653L864,653"
"Q864,810 794,894Q724,977 594,977ZM471,1241L471,1266"
"Q519,1328 575,1416Q630,1504 662,1569L662,1569L864,1569"
"L864,1548Q820,1483 733,1388Q646,1293 582,1241L582,1241L471,1241Z";
char expected2[] = "M639,-20Q396,-20 256,128Q115,276 115,539Q115,804 246,960"
"Q376,1116 596,1116Q802,1116 922,981Q1042,845 1042,623"
"L1042,518L287,518Q292,325 385,225Q477,125 645,125"
"Q822,125 995,199L995,51Q907,13 829,-4Q750,-20 639,-20Z"
"M594,977Q462,977 384,891Q305,805 291,653L864,653"
"Q864,810 794,894Q724,977 594,977ZM471,1266Q519,1328 575,1416"
"Q630,1504 662,1569L864,1569L864,1548Q820,1483 733,1388"
"Q646,1293 582,1241L471,1241L471,1266Z";
g_assert_cmpmem (str, user_data.consumed, expected2, sizeof (expected2) - 1);
hb_font_destroy (font);
@ -461,27 +459,27 @@ test_hb_draw_font_kit_glyphs_tests (void)
/* should resolve composite glyphs recursively */
user_data.consumed = 0;
g_assert (hb_font_draw_glyph (font, codepoint, funcs, &user_data));
char expected[] = "M581,170L581,274L443,274Q409,274 384,259Q359,243 348,219"
"Q336,194 340,166Q343,138 365,111L365,111L468,-13Q470,-10 473,-7"
"Q475,-3 477,0L477,0L253,0Q225,0 203,8Q180,15 168,32Q155,48 155,73"
"L155,73L155,269L50,269L50,73Q50,24 69,-10Q88,-44 118,-65"
"Q147,-85 181,-95Q214,-104 243,-104L243,-104L473,-104"
"Q501,-104 525,-91Q549,-78 564,-56Q578,-34 578,-8Q578,18 557,43"
"L557,43L442,182Q439,179 437,176Q435,173 432,170L432,170L581,170Z"
"M184,-194L184,-194Q184,-216 199,-231Q214,-246 236,-246L236,-246"
"Q258,-246 273,-231Q288,-216 288,-194L288,-194Q288,-172 273,-157"
"Q258,-142 236,-142L236,-142Q214,-142 199,-157Q184,-172 184,-194Z"
"M360,-194L360,-194Q360,-216 375,-231Q390,-246 412,-246L412,-246"
"Q434,-246 449,-231Q464,-216 464,-194L464,-194Q464,-172 449,-157"
"Q434,-142 412,-142L412,-142Q390,-142 375,-157Q360,-172 360,-194Z";
char expected[] = "M581,274L443,274Q409,274 384,259Q359,243 348,219Q336,194 340,166"
"Q343,138 365,111L468,-13Q470,-10 473,-7Q475,-3 477,0L253,0"
"Q225,0 203,8Q180,15 168,32Q155,48 155,73L155,269L50,269L50,73"
"Q50,24 69,-10Q88,-44 118,-65Q147,-85 181,-95Q214,-104 243,-104"
"L473,-104Q501,-104 525,-91Q549,-78 564,-56Q578,-34 578,-8"
"Q578,18 557,43L442,182Q439,179 437,176Q435,173 432,170"
"L581,170L581,274ZM184,-194Q184,-216 199,-231Q214,-246 236,-246"
"Q258,-246 273,-231Q288,-216 288,-194Q288,-172 273,-157"
"Q258,-142 236,-142Q214,-142 199,-157Q184,-172 184,-194Z"
"M360,-194Q360,-216 375,-231Q390,-246 412,-246"
"Q434,-246 449,-231Q464,-216 464,-194Q464,-172 449,-157"
"Q434,-142 412,-142Q390,-142 375,-157Q360,-172 360,-194Z";
g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
/* should transform points of a composite glyph */
user_data.consumed = 0;
g_assert (hb_font_draw_glyph (font, 2, funcs, &user_data)); /* 2 == arAlef.fina */
char expected2[] = "M50,624L155,624L155,84Q150,90 146,95Q141,99 136,105L136,105"
"L292,105L292,0L156,0Q128,0 104,14Q79,27 65,51Q50,74 50,104"
"L50,104L50,624ZM282,0L282,105L312,105L312,0L282,0Z";
char expected2[] = "M155,624L155,84Q150,90 146,95Q141,99 136,105"
"L292,105L292,0L156,0Q128,0 104,14Q79,27 65,51"
"Q50,74 50,104L50,624L155,624ZM282,105L312,105"
"L312,0L282,0L282,105Z";
g_assert_cmpmem (str, user_data.consumed, expected2, sizeof (expected2) - 1);
hb_font_destroy (font);
@ -554,27 +552,25 @@ test_hb_draw_font_kit_variations_tests (void)
user_data.consumed = 0;
g_assert (hb_font_draw_glyph (font, codepoint, funcs, &user_data));
char expected[] = "M414,-102L371,-102L371,539L914,539L914,-27Q914,-102 840,-102L840,-102Q796,-102 755,-98"
"L755,-98L742,-59Q790,-66 836,-66L836,-66Q871,-66 871,-31L871,-31L871,504L414,504L414,-102Z"
"M203,-94L203,-94Q138,-94 86,-90L86,-90L74,-52Q137,-59 188,-59L188,-59Q211,-59 222,-47"
"Q233,-34 236,12Q238,58 240,135Q242,211 242,262L242,262L74,262L94,527L242,527L242,719"
"L63,719L63,754L285,754L285,492L133,492L117,297L285,297Q285,241 284,185L284,185"
"Q284,104 281,46L281,46Q278,-20 269,-49Q260,-78 242,-86Q223,-94 203,-94ZM461,12L461,12"
"L434,43Q473,73 503,115L503,115Q478,150 441,188L441,188L469,211Q501,179 525,147"
"L525,147Q538,172 559,230L559,230L594,211Q571,152 551,117L551,117Q577,84 602,43L602,43"
"L566,20Q544,64 528,86L528,86Q500,44 461,12ZM465,258L465,258L438,285Q474,316 501,351L501,351"
"Q474,388 445,418L445,418L473,441Q500,414 523,381L523,381Q546,413 563,453L563,453"
"L598,434Q571,382 549,352L549,352Q576,320 598,285L598,285L563,262Q546,294 525,322"
"L525,322Q491,280 465,258ZM707,12L707,12L680,43Q717,68 753,115L753,115Q731,147 691,188"
"L691,188L719,211Q739,190 754,172Q769,154 774,147L774,147Q793,185 809,230L809,230"
"L844,211Q822,155 801,117L801,117Q828,82 852,43L852,43L820,20Q798,58 778,87"
"L778,87Q747,43 707,12ZM664,-94L621,-94L621,730L664,730L664,-94ZM348,570L348,570"
"L324,605Q425,629 527,688L527,688L555,656Q491,621 439,601Q386,581 348,570ZM715,258"
"L715,258L688,285Q727,318 753,351L753,351Q733,378 695,418L695,418L723,441Q754,410 775,381"
"L775,381Q794,407 813,453L813,453L848,434Q826,387 801,352L801,352Q823,321 848,281"
"L848,281L813,262Q791,301 775,323L775,323Q749,288 715,258ZM941,719L348,719L348,754"
"L941,754L941,719ZM957,605L936,570Q870,602 817,622Q764,641 727,652L727,652L749,688"
"Q852,655 957,605L957,605Z";
char expected[] = "M371,-102L371,539L914,539L914,-27Q914,-102 840,-102Q796,-102 755,-98"
"L742,-59Q790,-66 836,-66Q871,-66 871,-31L871,504L414,504L414,-102"
"L371,-102ZM203,-94Q138,-94 86,-90L74,-52Q137,-59 188,-59Q211,-59 222,-47"
"Q233,-34 236,12Q238,58 240,135Q242,211 242,262L74,262L94,527L242,527"
"L242,719L63,719L63,754L285,754L285,492L133,492L117,297L285,297"
"Q285,241 284,185Q284,104 281,46Q278,-20 269,-49Q260,-78 242,-86"
"Q223,-94 203,-94ZM461,12L434,43Q473,73 503,115Q478,150 441,188L469,211"
"Q501,179 525,147Q538,172 559,230L594,211Q571,152 551,117Q577,84 602,43"
"L566,20Q544,64 528,86Q500,44 461,12ZM465,258L438,285Q474,316 501,351"
"Q474,388 445,418L473,441Q500,414 523,381Q546,413 563,453L598,434"
"Q571,382 549,352Q576,320 598,285L563,262Q546,294 525,322Q491,280 465,258Z"
"M707,12L680,43Q717,68 753,115Q731,147 691,188L719,211Q739,190 754,172"
"Q769,154 774,147Q793,185 809,230L844,211Q822,155 801,117Q828,82 852,43"
"L820,20Q798,58 778,87Q747,43 707,12ZM621,-94L621,730L664,730L664,-94"
"L621,-94ZM348,570L324,605Q425,629 527,688L555,656Q491,621 439,601"
"Q386,581 348,570ZM715,258L688,285Q727,318 753,351Q733,378 695,418L723,441"
"Q754,410 775,381Q794,407 813,453L848,434Q826,387 801,352Q823,321 848,281"
"L813,262Q791,301 775,323Q749,288 715,258ZM348,719L348,754L941,754L941,719"
"L348,719ZM936,570Q870,602 817,622Q764,641 727,652L749,688Q852,655 957,605L936,570Z";
g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
hb_font_destroy (font);
@ -600,27 +596,25 @@ test_hb_draw_font_kit_variations_tests (void)
user_data.consumed = 0;
g_assert (hb_font_draw_glyph (font, codepoint, funcs, &user_data));
char expected[] = "M414,-102L371,-102L371,539L914,539L914,-27Q914,-102 840,-102L840,-102Q796,-102 755,-98"
"L755,-98L742,-59Q790,-66 836,-66L836,-66Q871,-66 871,-31L871,-31L871,504L414,504"
"L414,-102ZM203,-94L203,-94Q138,-94 86,-90L86,-90L74,-52Q137,-59 188,-59L188,-59"
"Q211,-59 222,-47Q233,-34 236,12Q238,58 240,135Q242,211 242,262L242,262L74,262"
"L94,527L242,527L242,719L63,719L63,754L285,754L285,492L133,492L117,297"
"L285,297Q285,241 284,185L284,185Q284,104 281,46L281,46Q278,-20 269,-49Q260,-78 242,-86"
"Q223,-94 203,-94ZM461,12L461,12L434,43Q473,73 503,115L503,115Q478,150 441,188L441,188"
"L469,211Q501,179 525,147L525,147Q538,172 559,230L559,230L594,211Q571,152 551,117"
"L551,117Q577,84 602,43L602,43L566,20Q544,64 528,86L528,86Q500,44 461,12ZM465,258"
"L465,258L438,285Q474,316 501,351L501,351Q474,388 445,418L445,418L473,441"
"Q500,414 523,381L523,381Q546,413 563,453L563,453L598,434Q571,382 549,352L549,352"
"Q576,320 598,285L598,285L563,262Q546,294 525,322L525,322Q491,280 465,258ZM707,12"
"L707,12L680,43Q717,68 753,115L753,115Q731,147 691,188L691,188L719,211Q739,190 754,172"
"Q769,154 774,147L774,147Q793,185 809,230L809,230L844,211Q822,155 801,117L801,117"
"Q828,82 852,43L852,43L820,20Q798,58 778,87L778,87Q747,43 707,12ZM664,-94L621,-94L621,730"
"L664,730L664,-94ZM348,570L348,570L324,605Q425,629 527,688L527,688L555,656Q491,621 439,601"
"Q386,581 348,570ZM715,258L715,258L688,285Q727,318 753,351L753,351Q733,378 695,418"
"L695,418L723,441Q754,410 775,381L775,381Q794,407 813,453L813,453L848,434Q826,387 801,352"
"L801,352Q823,321 848,281L848,281L813,262Q791,301 775,323L775,323Q749,288 715,258ZM941,719"
"L348,719L348,754L941,754L941,719ZM957,605L936,570Q870,602 817,622Q764,641 727,652L727,652"
"L749,688Q852,655 957,605L957,605Z";
char expected[] = "M371,-102L371,539L914,539L914,-27Q914,-102 840,-102Q796,-102 755,-98"
"L742,-59Q790,-66 836,-66Q871,-66 871,-31L871,504L414,504L414,-102"
"L371,-102ZM203,-94Q138,-94 86,-90L74,-52Q137,-59 188,-59Q211,-59 222,-47"
"Q233,-34 236,12Q238,58 240,135Q242,211 242,262L74,262L94,527L242,527"
"L242,719L63,719L63,754L285,754L285,492L133,492L117,297L285,297"
"Q285,241 284,185Q284,104 281,46Q278,-20 269,-49Q260,-78 242,-86"
"Q223,-94 203,-94ZM461,12L434,43Q473,73 503,115Q478,150 441,188"
"L469,211Q501,179 525,147Q538,172 559,230L594,211Q571,152 551,117"
"Q577,84 602,43L566,20Q544,64 528,86Q500,44 461,12ZM465,258L438,285"
"Q474,316 501,351Q474,388 445,418L473,441Q500,414 523,381Q546,413 563,453"
"L598,434Q571,382 549,352Q576,320 598,285L563,262Q546,294 525,322"
"Q491,280 465,258ZM707,12L680,43Q717,68 753,115Q731,147 691,188L719,211"
"Q739,190 754,172Q769,154 774,147Q793,185 809,230L844,211Q822,155 801,117"
"Q828,82 852,43L820,20Q798,58 778,87Q747,43 707,12ZM621,-94L621,730L664,730"
"L664,-94L621,-94ZM348,570L324,605Q425,629 527,688L555,656Q491,621 439,601"
"Q386,581 348,570ZM715,258L688,285Q727,318 753,351Q733,378 695,418L723,441"
"Q754,410 775,381Q794,407 813,453L848,434Q826,387 801,352Q823,321 848,281"
"L813,262Q791,301 775,323Q749,288 715,258ZM348,719L348,754L941,754L941,719"
"L348,719ZM936,570Q870,602 817,622Q764,641 727,652L749,688Q852,655 957,605L936,570Z";
g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
hb_font_destroy (font);
@ -646,28 +640,25 @@ test_hb_draw_font_kit_variations_tests (void)
user_data.consumed = 0;
g_assert (hb_font_draw_glyph (font, codepoint, funcs, &user_data));
char expected[] = "M414,-102L371,-102L371,539L914,539L914,-27Q914,-102 840,-102L840,-102"
"Q796,-102 755,-98L755,-98L742,-59Q790,-66 836,-66L836,-66Q871,-66 871,-31"
"L871,-31L871,504L414,504L414,-102ZM203,-94L203,-94Q138,-94 86,-90"
"L86,-90L74,-52Q137,-59 188,-59L188,-59Q211,-59 222,-47Q233,-34 236,12"
"Q238,58 240,135Q242,211 242,262L242,262L74,262L94,527L242,527L242,719"
"L63,719L63,754L285,754L285,492L133,492L117,297L285,297Q285,241 284,185"
"L284,185Q284,104 281,46L281,46Q278,-20 269,-49Q260,-78 242,-86Q223,-94 203,-94Z"
"M461,12L461,12L434,43Q473,73 503,115L503,115Q478,150 441,188L441,188L469,211"
"Q501,179 525,147L525,147Q538,172 559,230L559,230L594,211Q571,152 551,117L551,117"
"Q577,84 602,43L602,43L566,20Q544,64 528,86L528,86Q500,44 461,12ZM465,258L465,258L438,285"
"Q474,316 501,351L501,351Q474,388 445,418L445,418L473,441Q500,414 523,381L523,381"
"Q546,413 563,453L563,453L598,434Q571,382 549,352L549,352Q576,320 598,285L598,285"
"L563,262Q546,294 525,322L525,322Q491,280 465,258ZM707,12L707,12L680,43Q717,68 753,115"
"L753,115Q731,147 691,188L691,188L719,211Q739,190 754,172Q769,154 774,147L774,147"
"Q793,185 809,230L809,230L844,211Q822,155 801,117L801,117Q828,82 852,43L852,43L820,20"
"Q798,58 778,87L778,87Q747,43 707,12ZM664,-94L621,-94L621,730L664,730L664,-94Z"
"M348,570L348,570L324,605Q425,629 527,688L527,688L555,656Q491,621 439,601"
"Q386,581 348,570ZM715,258L715,258L688,285Q727,318 753,351L753,351Q733,378 695,418"
"L695,418L723,441Q754,410 775,381L775,381Q794,407 813,453L813,453L848,434"
"Q826,387 801,352L801,352Q823,321 848,281L848,281L813,262Q791,301 775,323L775,323"
"Q749,288 715,258ZM941,719L348,719L348,754L941,754L941,719ZM957,605L936,570"
"Q870,602 817,622Q764,641 727,652L727,652L749,688Q852,655 957,605L957,605Z";
char expected[] = "M371,-102L371,539L914,539L914,-27Q914,-102 840,-102Q796,-102 755,-98"
"L742,-59Q790,-66 836,-66Q871,-66 871,-31L871,504L414,504L414,-102"
"L371,-102ZM203,-94Q138,-94 86,-90L74,-52Q137,-59 188,-59Q211,-59 222,-47"
"Q233,-34 236,12Q238,58 240,135Q242,211 242,262L74,262L94,527L242,527"
"L242,719L63,719L63,754L285,754L285,492L133,492L117,297L285,297"
"Q285,241 284,185Q284,104 281,46Q278,-20 269,-49Q260,-78 242,-86"
"Q223,-94 203,-94ZM461,12L434,43Q473,73 503,115Q478,150 441,188"
"L469,211Q501,179 525,147Q538,172 559,230L594,211Q571,152 551,117"
"Q577,84 602,43L566,20Q544,64 528,86Q500,44 461,12ZM465,258L438,285"
"Q474,316 501,351Q474,388 445,418L473,441Q500,414 523,381Q546,413 563,453"
"L598,434Q571,382 549,352Q576,320 598,285L563,262Q546,294 525,322"
"Q491,280 465,258ZM707,12L680,43Q717,68 753,115Q731,147 691,188L719,211"
"Q739,190 754,172Q769,154 774,147Q793,185 809,230L844,211Q822,155 801,117"
"Q828,82 852,43L820,20Q798,58 778,87Q747,43 707,12ZM621,-94L621,730L664,730"
"L664,-94L621,-94ZM348,570L324,605Q425,629 527,688L555,656Q491,621 439,601"
"Q386,581 348,570ZM715,258L688,285Q727,318 753,351Q733,378 695,418L723,441"
"Q754,410 775,381Q794,407 813,453L848,434Q826,387 801,352Q823,321 848,281"
"L813,262Q791,301 775,323Q749,288 715,258ZM348,719L348,754L941,754L941,719"
"L348,719ZM936,570Q870,602 817,622Q764,641 727,652L749,688Q852,655 957,605L936,570Z";
g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
hb_font_destroy (font);
@ -776,37 +767,35 @@ test_hb_draw_stroking (void)
user_data.consumed = 0;
g_assert (hb_font_draw_glyph (font, 6, funcs, &user_data));
char expected[] = "M1626,1522Q1626,1522 1626,1522Q1626,1522 1626,1522ZM531,1985"
"Q436,1764 436,1522Q436,1280 531,1060Q625,839 784,680Q943,521 1164,427"
"Q1384,332 1626,332Q1868,332 2089,427Q2309,521 2468,680Q2627,839 2722,1060"
"Q2816,1280 2816,1522Q2816,1764 2722,1985Q2627,2205 2468,2364"
"Q2309,2523 2089,2618Q1868,2712 1626,2712Q1384,2712 1164,2618"
"Q943,2523 784,2364Q625,2205 531,1985ZM306,1165Q256,1342 256,1528"
"Q256,1714 306,1892Q355,2069 443,2220Q531,2370 658,2497"
"Q784,2623 935,2711Q1085,2799 1263,2849Q1440,2898 1626,2898"
"Q1812,2898 1990,2849Q2167,2799 2318,2711Q2468,2623 2595,2497"
"Q2721,2370 2809,2220Q2897,2069 2947,1892Q2996,1714 2996,1528"
"Q2996,1342 2947,1165Q2897,987 2809,837Q2721,686 2595,560"
"Q2468,433 2318,345Q2167,257 1990,208Q1812,158 1626,158"
"Q1440,158 1263,208Q1085,257 935,345Q784,433 658,560"
"Q531,686 443,837Q355,987 306,1165Z";
char expected[] = "M1626,1522Q1626,1522 1626,1522Q1626,1522 1626,1522ZM436,1522"
"Q436,1280 531,1060Q625,839 784,680Q943,521 1164,427Q1384,332 1626,332"
"Q1868,332 2089,427Q2309,521 2468,680Q2627,839 2722,1060Q2816,1280 2816,1522"
"Q2816,1764 2722,1985Q2627,2205 2468,2364Q2309,2523 2089,2618Q1868,2712 1626,2712"
"Q1384,2712 1164,2618Q943,2523 784,2364Q625,2205 531,1985Q436,1764 436,1522ZM256,1528"
"Q256,1714 306,1892Q355,2069 443,2220Q531,2370 658,2497Q784,2623 935,2711"
"Q1085,2799 1263,2849Q1440,2898 1626,2898Q1812,2898 1990,2849Q2167,2799 2318,2711"
"Q2468,2623 2595,2497Q2721,2370 2809,2220Q2897,2069 2947,1892Q2996,1714 2996,1528"
"Q2996,1342 2947,1165Q2897,987 2809,837Q2721,686 2595,560Q2468,433 2318,345"
"Q2167,257 1990,208Q1812,158 1626,158Q1440,158 1263,208Q1085,257 935,345"
"Q784,433 658,560Q531,686 443,837Q355,987 306,1165Q256,1342 256,1528Z";
g_assert_cmpmem (str, user_data.consumed, expected, sizeof (expected) - 1);
user_data.consumed = 0;
g_assert (hb_font_draw_glyph (font, 7, funcs, &user_data));
char expected2[] = "M531,1985Q436,1764 436,1522Q436,1280 531,1060Q625,839 784,680"
"Q943,521 1164,427Q1384,332 1626,332Q1868,332 2089,427"
"Q2309,521 2468,680Q2627,839 2722,1060Q2816,1280 2816,1522"
"Q2816,1764 2722,1985Q2627,2205 2468,2364Q2309,2523 2089,2618"
"Q1868,2712 1626,2712Q1384,2712 1164,2618Q943,2523 784,2364"
"Q625,2205 531,1985ZM306,1165Q256,1342 256,1528Q256,1714 306,1892"
"Q355,2069 443,2220Q531,2370 658,2497Q784,2623 935,2711"
"Q1085,2799 1263,2849Q1440,2898 1626,2898Q1812,2898 1990,2849"
"Q2167,2799 2318,2711Q2468,2623 2595,2497Q2721,2370 2809,2220"
"Q2897,2069 2947,1892Q2996,1714 2996,1528Q2996,1342 2947,1165"
"Q2897,987 2809,837Q2721,686 2595,560Q2468,433 2318,345"
"Q2167,257 1990,208Q1812,158 1626,158Q1440,158 1263,208"
"Q1085,257 935,345Q784,433 658,560Q531,686 443,837Q355,987 306,1165Z";
char expected2[] = "M436,1522Q436,1280 531,1060Q625,839 784,680Q943,521 1164,427"
"Q1384,332 1626,332Q1868,332 2089,427Q2309,521 2468,680"
"Q2627,839 2722,1060Q2816,1280 2816,1522Q2816,1764 2722,1985"
"Q2627,2205 2468,2364Q2309,2523 2089,2618Q1868,2712 1626,2712"
"Q1384,2712 1164,2618Q943,2523 784,2364Q625,2205 531,1985"
"Q436,1764 436,1522ZM256,1528Q256,1714 306,1892Q355,2069 443,2220"
"Q531,2370 658,2497Q784,2623 935,2711Q1085,2799 1263,2849"
"Q1440,2898 1626,2898Q1812,2898 1990,2849Q2167,2799 2318,2711"
"Q2468,2623 2595,2497Q2721,2370 2809,2220Q2897,2069 2947,1892"
"Q2996,1714 2996,1528Q2996,1342 2947,1165Q2897,987 2809,837"
"Q2721,686 2595,560Q2468,433 2318,345Q2167,257 1990,208"
"Q1812,158 1626,158Q1440,158 1263,208Q1085,257 935,345"
"Q784,433 658,560Q531,686 443,837Q355,987 306,1165"
"Q256,1342 256,1528Z";
g_assert_cmpmem (str, user_data.consumed, expected2, sizeof (expected2) - 1);
hb_font_destroy (font);