2018-11-24 17:37:24 +01:00
|
|
|
/*____________________________________________________________________________
|
|
|
|
|
|
|
|
Copyright 2000-2016 Adobe Systems Incorporated. All Rights Reserved.
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use these files except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
____________________________________________________________________________*/
|
|
|
|
|
|
|
|
#include "stdlib.h"
|
|
|
|
#include "stdio.h"
|
|
|
|
#include "string.h"
|
|
|
|
#include "hb.h"
|
|
|
|
#include "hb-ot.h"
|
|
|
|
|
|
|
|
static const bool verbose = true;
|
|
|
|
|
2021-07-29 18:20:03 +02:00
|
|
|
struct TestData
|
|
|
|
{
|
|
|
|
TestData(hb_buffer_t *buffer_,
|
|
|
|
hb_face_t *face_,
|
|
|
|
hb_font_t *font_,
|
|
|
|
hb_feature_t *features_,
|
|
|
|
int num_features_)
|
|
|
|
: buffer(buffer_), face(face_), font(font_),
|
|
|
|
features(features_), num_features(num_features_)
|
|
|
|
{ }
|
|
|
|
~TestData()
|
|
|
|
{
|
|
|
|
free (features);
|
|
|
|
hb_face_destroy (face);
|
|
|
|
hb_font_destroy (font);
|
|
|
|
hb_buffer_destroy (buffer);
|
|
|
|
}
|
2018-11-24 17:37:24 +01:00
|
|
|
|
2021-07-29 18:20:03 +02:00
|
|
|
hb_buffer_t *buffer;
|
|
|
|
hb_face_t *face;
|
|
|
|
hb_font_t *font;
|
|
|
|
hb_feature_t *features;
|
|
|
|
int num_features;
|
|
|
|
};
|
|
|
|
|
|
|
|
TestData
|
|
|
|
runTest(const char *testName,
|
|
|
|
const char *fontfileName,
|
|
|
|
unsigned int *in, int nbIn,
|
|
|
|
unsigned int *select, int nbSelect)
|
2018-11-24 17:37:24 +01:00
|
|
|
{
|
|
|
|
FILE *f = fopen (fontfileName, "rb");
|
|
|
|
fseek(f, 0, SEEK_END);
|
|
|
|
long fontsize = ftell(f);
|
|
|
|
fseek(f, 0, SEEK_SET);
|
|
|
|
char *fontdata = (char *)malloc (fontsize);
|
|
|
|
fread(fontdata, fontsize, 1, f);
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
if (verbose) {
|
|
|
|
printf ("------------------------------- %s\n", testName);
|
|
|
|
}
|
|
|
|
|
|
|
|
// setup font
|
|
|
|
hb_blob_t *blob = hb_blob_create(fontdata, fontsize,
|
|
|
|
HB_MEMORY_MODE_WRITABLE,
|
|
|
|
0, 0);
|
|
|
|
hb_face_t *face = hb_face_create(blob, 0);
|
|
|
|
hb_font_t *font = hb_font_create(face);
|
|
|
|
unsigned int upem = hb_face_get_upem (face);
|
|
|
|
|
|
|
|
hb_font_set_scale(font, upem, upem);
|
|
|
|
hb_ot_font_set_funcs (font);
|
|
|
|
|
|
|
|
// setup buffer
|
|
|
|
hb_buffer_t *buffer = hb_buffer_create();
|
|
|
|
hb_buffer_set_direction(buffer, HB_DIRECTION_LTR);
|
|
|
|
hb_buffer_set_script(buffer, HB_SCRIPT_LATIN);
|
|
|
|
hb_buffer_set_language(buffer, hb_language_from_string("en", 2));
|
|
|
|
|
|
|
|
hb_buffer_add_utf32(buffer, in, nbIn, 0, nbIn);
|
|
|
|
|
|
|
|
// setup features
|
|
|
|
hb_feature_t *features;
|
|
|
|
int nbFeatures;
|
|
|
|
|
|
|
|
if (nbSelect == 0)
|
|
|
|
{
|
|
|
|
nbFeatures = 1;
|
|
|
|
|
|
|
|
features = (hb_feature_t *) malloc (sizeof (*features));
|
|
|
|
features[0].tag = HB_TAG('t', 'e', 's', 't');
|
|
|
|
features[0].value = 1;
|
2019-12-15 15:50:01 +01:00
|
|
|
features[0].start = HB_FEATURE_GLOBAL_START;
|
|
|
|
features[0].end = HB_FEATURE_GLOBAL_END;
|
2018-11-24 17:37:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
nbFeatures = 0;
|
|
|
|
|
|
|
|
features = (hb_feature_t *) malloc (sizeof (*features) * nbSelect);
|
|
|
|
for (int i = 0; i < nbSelect; i++) {
|
|
|
|
if (select[i] != -1) {
|
|
|
|
features[nbFeatures].tag = HB_TAG('t', 'e', 's', 't');
|
|
|
|
features[nbFeatures].value = select[i];
|
|
|
|
features[nbFeatures].start = i;
|
|
|
|
features[nbFeatures].end = i + 1;
|
|
|
|
nbFeatures++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// shape
|
|
|
|
hb_shape(font, buffer, features, nbFeatures);
|
|
|
|
|
|
|
|
hb_blob_destroy(blob);
|
|
|
|
|
2021-07-29 18:20:03 +02:00
|
|
|
return TestData(buffer, face, font, features, nbFeatures);
|
2018-11-24 17:37:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void printArray (const char* s, int *a, int n)
|
|
|
|
{
|
|
|
|
printf ("%s %d : ", s, n);
|
|
|
|
for (int i = 0; i < n; i++) {
|
|
|
|
printf (" %d", a[i]);
|
|
|
|
}
|
|
|
|
printf ("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void printUArray (const char* s, unsigned int *a, int n)
|
|
|
|
{
|
|
|
|
printArray (s, (int *) a, n);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool gsub_test(const char *testName,
|
|
|
|
const char *fontfileName,
|
|
|
|
int nbIn, unsigned int *in,
|
|
|
|
int nbSelect, unsigned int *select,
|
|
|
|
int nbExpected, unsigned int *expected)
|
|
|
|
{
|
2021-07-29 18:20:03 +02:00
|
|
|
TestData data = runTest(testName,
|
|
|
|
fontfileName,
|
|
|
|
in, nbIn,
|
|
|
|
select, nbSelect);
|
2018-11-24 17:37:24 +01:00
|
|
|
|
|
|
|
// verify
|
2021-07-29 18:20:03 +02:00
|
|
|
hb_glyph_info_t *actual = hb_buffer_get_glyph_infos(data.buffer, 0);
|
|
|
|
unsigned int nbActual = hb_buffer_get_length(data.buffer);
|
2018-11-24 17:37:24 +01:00
|
|
|
|
|
|
|
bool ok = true;
|
|
|
|
|
|
|
|
if (nbActual != nbExpected)
|
|
|
|
ok = false;
|
|
|
|
else {
|
|
|
|
for (int i = 0; i < nbActual; i++) {
|
|
|
|
if (actual[i].codepoint != expected [i]) {
|
|
|
|
ok = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char test_name[255];
|
|
|
|
sprintf (test_name, "../../tests/%.*s.tests", (int) (strrchr (testName, '_') - testName), testName);
|
|
|
|
FILE *tests_file = fopen (test_name, "a+");
|
2018-11-24 18:19:21 +01:00
|
|
|
if (!ok) fprintf (tests_file, "#");
|
2021-08-10 19:05:40 +02:00
|
|
|
fprintf (tests_file, "../fonts/%s;--features=\"", fontfileName + 9);
|
2021-07-29 18:20:03 +02:00
|
|
|
for (unsigned int i = 0; i < data.num_features; i++)
|
2018-11-24 17:37:24 +01:00
|
|
|
{
|
|
|
|
if (i != 0) fprintf (tests_file, ",");
|
|
|
|
char buf[255];
|
2021-07-29 18:20:03 +02:00
|
|
|
hb_feature_to_string (&data.features[i], buf, sizeof (buf));
|
2018-11-24 17:37:24 +01:00
|
|
|
fprintf (tests_file, "%s", buf);
|
|
|
|
}
|
2021-11-25 19:49:16 +01:00
|
|
|
fprintf (tests_file, "\" --single-par --no-clusters --no-glyph-names --no-positions;");
|
2018-11-24 17:37:24 +01:00
|
|
|
|
|
|
|
for (unsigned int i = 0; i < nbIn; i++)
|
|
|
|
{
|
|
|
|
if (i != 0) fprintf (tests_file, ",");
|
|
|
|
fprintf (tests_file, "U+%04X", in[i]);
|
|
|
|
}
|
|
|
|
|
2021-08-10 19:05:40 +02:00
|
|
|
fprintf (tests_file, ";[");
|
2018-11-24 17:37:24 +01:00
|
|
|
for (unsigned int i = 0; i < nbActual; i++)
|
|
|
|
{
|
|
|
|
if (i != 0) fprintf (tests_file, "|");
|
|
|
|
fprintf (tests_file, "%d", expected[i]);
|
|
|
|
}
|
|
|
|
fprintf (tests_file, "]");
|
|
|
|
|
|
|
|
fprintf (tests_file, "\n");
|
|
|
|
fclose (tests_file);
|
|
|
|
|
|
|
|
|
|
|
|
if (! ok) {
|
|
|
|
printf ("******* GSUB %s\n", testName);
|
|
|
|
|
|
|
|
printf ("expected %d:", nbExpected);
|
|
|
|
for (int i = 0; i < nbExpected; i++) {
|
2021-07-28 16:29:43 +02:00
|
|
|
printf (" %d", expected[i]); }
|
|
|
|
printf ("\n");
|
|
|
|
|
|
|
|
printf (" actual %d:", nbActual);
|
|
|
|
for (int i = 0; i < nbActual; i++) {
|
|
|
|
printf (" %d", actual[i].codepoint); }
|
|
|
|
printf ("\n");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cmap_test(const char *testName,
|
|
|
|
const char *fontfileName,
|
|
|
|
int nbIn, unsigned int *in,
|
|
|
|
int nbSelect, unsigned int *select,
|
|
|
|
int nbExpected, unsigned int *expected)
|
|
|
|
{
|
2021-07-29 18:20:03 +02:00
|
|
|
TestData data = runTest(testName,
|
|
|
|
fontfileName,
|
|
|
|
in, nbIn,
|
|
|
|
select, nbSelect);
|
2021-07-28 16:29:43 +02:00
|
|
|
|
|
|
|
// verify
|
2021-07-29 18:20:03 +02:00
|
|
|
hb_glyph_info_t *actual = hb_buffer_get_glyph_infos(data.buffer, 0);
|
|
|
|
unsigned int nbActual = hb_buffer_get_length(data.buffer);
|
2021-07-28 16:29:43 +02:00
|
|
|
|
|
|
|
bool ok = true;
|
|
|
|
|
|
|
|
if (nbActual != nbExpected)
|
|
|
|
ok = false;
|
|
|
|
else {
|
|
|
|
for (int i = 0; i < nbActual; i++) {
|
|
|
|
if (actual[i].codepoint != expected [i]) {
|
|
|
|
ok = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char test_name[255];
|
|
|
|
sprintf (test_name, "../../tests/%.*s.tests", (int) (strrchr (testName, '_') - testName), testName);
|
|
|
|
FILE *tests_file = fopen (test_name, "a+");
|
|
|
|
if (!ok) fprintf (tests_file, "#");
|
2021-08-10 19:05:40 +02:00
|
|
|
fprintf (tests_file, "../fonts/%s;--features=\"", fontfileName + 9);
|
2021-07-29 18:20:03 +02:00
|
|
|
for (unsigned int i = 0; i < data.num_features; i++)
|
2021-07-28 16:29:43 +02:00
|
|
|
{
|
|
|
|
if (i != 0) fprintf (tests_file, ",");
|
|
|
|
char buf[255];
|
2021-07-29 18:20:03 +02:00
|
|
|
hb_feature_to_string (&data.features[i], buf, sizeof (buf));
|
2021-07-28 16:29:43 +02:00
|
|
|
fprintf (tests_file, "%s", buf);
|
|
|
|
}
|
2022-01-19 22:13:50 +01:00
|
|
|
fprintf (tests_file, "\" --single-par --no-clusters --no-glyph-names --no-positions --font-funcs=ot;");
|
2021-07-28 16:29:43 +02:00
|
|
|
|
|
|
|
for (unsigned int i = 0; i < nbIn; i++)
|
|
|
|
{
|
|
|
|
if (i != 0) fprintf (tests_file, ",");
|
|
|
|
fprintf (tests_file, "U+%04X", in[i]);
|
|
|
|
}
|
|
|
|
|
2021-08-10 19:05:40 +02:00
|
|
|
fprintf (tests_file, ";[");
|
2021-07-28 16:29:43 +02:00
|
|
|
for (unsigned int i = 0; i < nbActual; i++)
|
|
|
|
{
|
|
|
|
if (i != 0) fprintf (tests_file, "|");
|
|
|
|
fprintf (tests_file, "%d", expected[i]);
|
|
|
|
}
|
|
|
|
fprintf (tests_file, "]");
|
|
|
|
|
|
|
|
fprintf (tests_file, "\n");
|
|
|
|
fclose (tests_file);
|
|
|
|
|
|
|
|
|
|
|
|
if (! ok) {
|
|
|
|
printf ("******* cmap %s\n", testName);
|
|
|
|
|
|
|
|
printf ("expected %d:", nbExpected);
|
|
|
|
for (int i = 0; i < nbExpected; i++) {
|
2018-11-24 17:37:24 +01:00
|
|
|
printf (" %d", expected[i]); }
|
|
|
|
printf ("\n");
|
|
|
|
|
|
|
|
printf (" actual %d:", nbActual);
|
|
|
|
for (int i = 0; i < nbActual; i++) {
|
|
|
|
printf (" %d", actual[i].codepoint); }
|
|
|
|
printf ("\n");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool gpos_test(const char *testName,
|
|
|
|
const char *fontfileName,
|
|
|
|
int nbIn,
|
|
|
|
unsigned int *in,
|
|
|
|
int nbOut,
|
|
|
|
unsigned int *out,
|
|
|
|
int *x,
|
|
|
|
int *y)
|
|
|
|
{
|
2021-07-29 18:20:03 +02:00
|
|
|
TestData data = runTest(testName,
|
|
|
|
fontfileName,
|
|
|
|
in, nbIn,
|
|
|
|
0, 0);
|
2018-11-24 17:37:24 +01:00
|
|
|
|
|
|
|
// verify
|
|
|
|
unsigned int nbActual;
|
2021-07-29 18:20:03 +02:00
|
|
|
hb_glyph_info_t *actual = hb_buffer_get_glyph_infos(data.buffer, &nbActual);
|
|
|
|
hb_glyph_position_t *pos = hb_buffer_get_glyph_positions (data.buffer, NULL);
|
2018-11-24 17:37:24 +01:00
|
|
|
|
|
|
|
unsigned int *actualG = (unsigned int *) malloc(sizeof(*actualG) * nbActual);
|
|
|
|
int *actualX = (int *) malloc(sizeof(*actualX) * nbActual);
|
|
|
|
int *actualY = (int *) malloc(sizeof(*actualY) * nbActual);
|
|
|
|
int curX = 0;
|
|
|
|
int curY = 0;
|
|
|
|
for (int i = 0; i < nbActual; i++) {
|
|
|
|
actualG[i] = actual[i].codepoint;
|
|
|
|
actualX[i] = curX + pos[i].x_offset;
|
|
|
|
actualY[i] = curY + pos[i].y_offset;
|
|
|
|
|
|
|
|
curX += pos[i].x_advance;
|
2021-07-29 18:20:03 +02:00
|
|
|
if (hb_ot_layout_get_glyph_class (data.face, actualG[i]) != HB_OT_LAYOUT_GLYPH_CLASS_MARK)
|
2021-07-29 18:03:00 +02:00
|
|
|
curX -= 1500;
|
2018-11-24 17:37:24 +01:00
|
|
|
curY += pos[i].y_advance;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool nbOk = true;
|
|
|
|
bool xOk = true;
|
|
|
|
bool yOk = true;
|
|
|
|
|
|
|
|
if (nbActual != nbOut)
|
|
|
|
nbOk = false;
|
|
|
|
else {
|
|
|
|
for (int i = 0; i < nbActual; i++) {
|
|
|
|
if (actualX[i] != x[i]) {
|
|
|
|
xOk = false;
|
|
|
|
}
|
|
|
|
if (actualY[i] != y[i]) {
|
|
|
|
yOk = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ok = (nbOk && xOk && yOk);
|
|
|
|
if (! ok) {
|
|
|
|
printf ("******* GPOS %s\n", testName);
|
|
|
|
|
|
|
|
if (! (nbOk && xOk)) {
|
|
|
|
printArray ("expectedX", x, nbOut);
|
|
|
|
printArray ("actualX ", actualX, nbActual);
|
|
|
|
|
|
|
|
printf ("xadv/pos:");
|
|
|
|
for (int i = 0; i < nbOut; i++) {
|
|
|
|
printf (" %d/%d", pos[i].x_advance, pos[i].x_offset);
|
|
|
|
}
|
|
|
|
printf ("\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! (nbOk && yOk)) {
|
|
|
|
printArray ("expectedY", y, nbOut);
|
|
|
|
printArray ("actualY ", actualY, nbActual);
|
|
|
|
|
|
|
|
printf ("yadv/pos:");
|
|
|
|
for (int i = 0; i < nbOut; i++) {
|
|
|
|
printf (" %d/%d", pos[i].y_advance, pos[i].y_offset);
|
|
|
|
}
|
|
|
|
printf ("\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
char test_name[255];
|
|
|
|
sprintf (test_name, "../../tests/%.*s.tests", (int) (strrchr (testName, '_') - testName), testName);
|
|
|
|
FILE *tests_file = fopen (test_name, "a+");
|
|
|
|
if (!ok) fprintf (tests_file, "#");
|
2021-08-10 19:05:40 +02:00
|
|
|
fprintf (tests_file, "../fonts/%s;--features=\"", fontfileName + 9);
|
2021-07-29 18:20:03 +02:00
|
|
|
for (unsigned int i = 0; i < data.num_features; i++)
|
2018-11-24 17:37:24 +01:00
|
|
|
{
|
|
|
|
if (i != 0) fprintf (tests_file, ",");
|
|
|
|
char buf[255];
|
2021-07-29 18:20:03 +02:00
|
|
|
hb_feature_to_string (&data.features[i], buf, sizeof (buf));
|
2018-11-24 17:37:24 +01:00
|
|
|
fprintf (tests_file, "%s", buf);
|
|
|
|
}
|
2022-01-19 22:13:50 +01:00
|
|
|
fprintf (tests_file, "\" --single-par --no-clusters --no-glyph-names --ned;");
|
2018-11-24 17:37:24 +01:00
|
|
|
|
|
|
|
for (unsigned int i = 0; i < nbIn; i++)
|
|
|
|
{
|
|
|
|
if (i != 0) fprintf (tests_file, ",");
|
|
|
|
fprintf (tests_file, "U+%04X", in[i]);
|
|
|
|
}
|
|
|
|
|
2021-08-10 19:05:40 +02:00
|
|
|
fprintf (tests_file, ";[");
|
2021-07-29 18:03:00 +02:00
|
|
|
int accumlatedAdvance = 0;
|
2018-11-24 17:37:24 +01:00
|
|
|
for (unsigned int i = 0; i < nbActual; i++)
|
|
|
|
{
|
|
|
|
if (i != 0) fprintf (tests_file, "|");
|
|
|
|
fprintf (tests_file, "%d", /*it should be "out[i]"*/ actualG[i]);
|
|
|
|
|
2021-07-29 18:03:00 +02:00
|
|
|
int expected_x = x[i] + accumlatedAdvance;
|
2018-11-24 17:37:24 +01:00
|
|
|
int expected_y = y[i];
|
|
|
|
if (expected_x || expected_y) fprintf (tests_file, "@%d,%d", expected_x, expected_y);
|
2021-07-29 18:20:03 +02:00
|
|
|
if (hb_ot_layout_get_glyph_class (data.face, actualG[i]) != HB_OT_LAYOUT_GLYPH_CLASS_MARK)
|
2021-07-29 18:03:00 +02:00
|
|
|
accumlatedAdvance += 1500;
|
2018-11-24 17:37:24 +01:00
|
|
|
}
|
|
|
|
fprintf (tests_file, "]");
|
|
|
|
|
|
|
|
fprintf (tests_file, "\n");
|
|
|
|
fclose (tests_file);
|
|
|
|
|
|
|
|
|
|
|
|
free(actualG);
|
|
|
|
free(actualX);
|
|
|
|
free(actualY);
|
|
|
|
|
|
|
|
return ok;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
|
|
|
int failures = 0;
|
|
|
|
int pass = 0;
|
|
|
|
|
|
|
|
#include "hb-aots-tester.h"
|
|
|
|
|
|
|
|
printf ("%d failures, %d pass\n", failures, pass);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|