blob: 152858410e97860acffa6115768901f89202592e [file] [log] [blame]
/*____________________________________________________________________________
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;
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);
}
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)
{
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;
features[0].start = HB_FEATURE_GLOBAL_START;
features[0].end = HB_FEATURE_GLOBAL_END;
}
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);
return TestData(buffer, face, font, features, nbFeatures);
}
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)
{
TestData data = runTest(testName,
fontfileName,
in, nbIn,
select, nbSelect);
// verify
hb_glyph_info_t *actual = hb_buffer_get_glyph_infos(data.buffer, 0);
unsigned int nbActual = hb_buffer_get_length(data.buffer);
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, "#");
fprintf (tests_file, "../fonts/%s;--features=\"", fontfileName + 9);
for (unsigned int i = 0; i < data.num_features; i++)
{
if (i != 0) fprintf (tests_file, ",");
char buf[255];
hb_feature_to_string (&data.features[i], buf, sizeof (buf));
fprintf (tests_file, "%s", buf);
}
fprintf (tests_file, "\" --no-clusters --no-glyph-names --no-positions;");
for (unsigned int i = 0; i < nbIn; i++)
{
if (i != 0) fprintf (tests_file, ",");
fprintf (tests_file, "U+%04X", in[i]);
}
fprintf (tests_file, ";[");
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++) {
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)
{
TestData data = runTest(testName,
fontfileName,
in, nbIn,
select, nbSelect);
// verify
hb_glyph_info_t *actual = hb_buffer_get_glyph_infos(data.buffer, 0);
unsigned int nbActual = hb_buffer_get_length(data.buffer);
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, "#");
fprintf (tests_file, "../fonts/%s;--features=\"", fontfileName + 9);
for (unsigned int i = 0; i < data.num_features; i++)
{
if (i != 0) fprintf (tests_file, ",");
char buf[255];
hb_feature_to_string (&data.features[i], buf, sizeof (buf));
fprintf (tests_file, "%s", buf);
}
fprintf (tests_file, "\" --no-clusters --no-glyph-names --no-positions --font-funcs=ot;");
for (unsigned int i = 0; i < nbIn; i++)
{
if (i != 0) fprintf (tests_file, ",");
fprintf (tests_file, "U+%04X", in[i]);
}
fprintf (tests_file, ";[");
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++) {
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)
{
TestData data = runTest(testName,
fontfileName,
in, nbIn,
0, 0);
// verify
unsigned int nbActual;
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);
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;
if (hb_ot_layout_get_glyph_class (data.face, actualG[i]) != HB_OT_LAYOUT_GLYPH_CLASS_MARK)
curX -= 1500;
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, "#");
fprintf (tests_file, "../fonts/%s;--features=\"", fontfileName + 9);
for (unsigned int i = 0; i < data.num_features; i++)
{
if (i != 0) fprintf (tests_file, ",");
char buf[255];
hb_feature_to_string (&data.features[i], buf, sizeof (buf));
fprintf (tests_file, "%s", buf);
}
fprintf (tests_file, "\" --no-clusters --no-glyph-names --ned;");
for (unsigned int i = 0; i < nbIn; i++)
{
if (i != 0) fprintf (tests_file, ",");
fprintf (tests_file, "U+%04X", in[i]);
}
fprintf (tests_file, ";[");
int accumlatedAdvance = 0;
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]);
int expected_x = x[i] + accumlatedAdvance;
int expected_y = y[i];
if (expected_x || expected_y) fprintf (tests_file, "@%d,%d", expected_x, expected_y);
if (hb_ot_layout_get_glyph_class (data.face, actualG[i]) != HB_OT_LAYOUT_GLYPH_CLASS_MARK)
accumlatedAdvance += 1500;
}
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);
}