Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a semi-automatic test for #221 #224

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,11 @@ EXTRA_DIST = CHANGES.txt COPYING.txt README.txt \
SDL2_ttfConfig.cmake.in \
autogen.sh gcc-fat.sh

noinst_PROGRAMS = showfont glfont
noinst_PROGRAMS = showfont glfont testfont

testfont_CPPFLAGS = $(TTF_CFLAGS) $(LOCAL_HB_FLAGS)
testfont_SOURCES = test/main.c
testfont_LDADD = libSDL2_ttf.la -lSDL2_test

showfont_LDADD = libSDL2_ttf.la
glfont_LDADD = libSDL2_ttf.la @GL_LIBS@ @MATHLIB@
Expand Down
35 changes: 28 additions & 7 deletions SDL_ttf.c
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,9 @@ struct _TTF_Font {
int render_subpixel;
#if TTF_USE_HARFBUZZ
hb_font_t *hb_font;
/* If HB_SCRIPT_INVALID, use global default script */
hb_script_t hb_script;
/* If HB_DIRECTION_INVALID, use global default direction */
hb_direction_t hb_direction;
#endif
int render_sdf;
Expand Down Expand Up @@ -1002,10 +1004,15 @@ static void Draw_Line(TTF_Font *font, const SDL_Surface *textbuf, int column, in
int tmp = row + line_thickness - textbuf->h;
int x_offset = column * textbuf->format->BytesPerPixel;
Uint8 *dst = (Uint8 *)textbuf->pixels + row * textbuf->pitch + x_offset;

#if TTF_USE_HARFBUZZ
hb_direction_t hb_direction = font->hb_direction;

if (hb_direction == HB_DIRECTION_INVALID) {
hb_direction = g_hb_direction;
}

/* No Underline/Strikethrough style if direction is vertical */
if (font->hb_direction == HB_DIRECTION_TTB || font->hb_direction == HB_DIRECTION_BTT) {
if (hb_direction == HB_DIRECTION_TTB || hb_direction == HB_DIRECTION_BTT) {
return;
}
#endif
Expand Down Expand Up @@ -1873,9 +1880,9 @@ TTF_Font* TTF_OpenFontIndexDPIRW(SDL_RWops *src, int freesrc, int ptsize, long i
* you will get mismatching advances and raster. */
hb_ft_font_set_load_flags(font->hb_font, FT_LOAD_DEFAULT | font->ft_load_target);

/* Default value script / direction */
font->hb_script = g_hb_script;
font->hb_direction = g_hb_direction;
/* By default the script / direction are inherited from global variables */
font->hb_script = HB_SCRIPT_INVALID;
font->hb_direction = HB_DIRECTION_INVALID;
#endif

if (TTF_SetFontSizeDPI(font, ptsize, hdpi, vdpi) < 0) {
Expand Down Expand Up @@ -3116,6 +3123,8 @@ static int TTF_Size_Internal(TTF_Font *font,
Uint8 *utf8_alloc = NULL;
c_glyph *glyph;
#if TTF_USE_HARFBUZZ
hb_direction_t hb_direction;
hb_script_t hb_script;
hb_buffer_t *hb_buffer = NULL;
unsigned int g;
unsigned int glyph_count;
Expand Down Expand Up @@ -3171,9 +3180,21 @@ static int TTF_Size_Internal(TTF_Font *font,
goto failure;
}


hb_direction = font->hb_direction;
hb_script = font->hb_script;

if (hb_script == HB_SCRIPT_INVALID) {
hb_script = g_hb_script;
}

if (hb_direction == HB_DIRECTION_INVALID) {
hb_direction = g_hb_direction;
}

/* Set global configuration */
hb_buffer_set_direction(hb_buffer, font->hb_direction);
hb_buffer_set_script(hb_buffer, font->hb_script);
hb_buffer_set_direction(hb_buffer, hb_direction);
hb_buffer_set_script(hb_buffer, hb_script);

/* Layout the text */
hb_buffer_add_utf8(hb_buffer, text, -1, 0, -1);
Expand Down
5 changes: 4 additions & 1 deletion SDL_ttf.h
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,10 @@ typedef enum
extern DECLSPEC int SDLCALL TTF_SetDirection(int direction); /* hb_direction_t */
extern DECLSPEC int SDLCALL TTF_SetScript(int script); /* hb_script_t */

/* Set direction and script per font.
/* Set direction and script per font, overriding the global direction
and script set with the deprecated TTF_SetDirection() and
TTF_SetScript().

'script' is null terminated string of exactly 4 characters.
These functions return 0, or -1 if SDL_ttf is not compiled with HarfBuzz or invalid parameter
*/
Expand Down
236 changes: 236 additions & 0 deletions test/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
/*
Copyright 1997-2022 Sam Lantinga
Copyright 2022 Collabora Ltd.

This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.

Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely.
*/

#include "SDL_ttf.h"
#include "SDL_test.h"

#if TTF_USE_HARFBUZZ
#include <hb.h>
#endif

static SDLTest_CommonState *state;
static const char *fontPath = NULL;

static int
TestDirection(void *arg)
{
static const char hello[] = "Hello, world!";
TTF_Font *font = NULL;
const char *error;
int ltr_w, ltr_h;
#if TTF_USE_HARFBUZZ
TTF_Font *font2 = NULL;
int ttb_w, ttb_h;
int w, h;
#endif

error = (TTF_Init() == 0) ? NULL : TTF_GetError();
if (!SDLTest_AssertCheck(error == NULL,
"Init: %s", error ? error : "successful")) {
goto out;
}

font = TTF_OpenFont(fontPath, 12);
error = (font != NULL) ? "successful" : TTF_GetError();
if (!SDLTest_AssertCheck(font != NULL,
"Load font %s: %s", fontPath, error)) {
goto out;
}

TTF_SizeUTF8(font, hello, &ltr_w, &ltr_h);
SDLTest_AssertCheck(ltr_w > ltr_h,
"Default text direction is horizontal: %d > %d",
ltr_w, ltr_h);

#if TTF_USE_HARFBUZZ
SDLTest_AssertCheck(TTF_SetDirection(HB_DIRECTION_TTB) == 0,
"Set global direction");
TTF_SizeUTF8(font, hello, &ttb_w, &ttb_h);
SDLTest_AssertCheck(ttb_w < ttb_h,
"Changing global direction works: %d < %d",
ttb_w, ttb_h);
SDLTest_AssertCheck(TTF_SetDirection(HB_DIRECTION_LTR) == 0,
"Set global direction");
TTF_SizeUTF8(font, hello, &w, &h);
SDLTest_AssertCheck(w == ltr_w && h == ltr_h,
"Changing global direction back works: %dx%d",
w, h);

SDLTest_AssertCheck(TTF_SetFontDirection(font, TTF_DIRECTION_TTB) == 0,
"Set font direction");
TTF_SizeUTF8(font, hello, &w, &h);
SDLTest_AssertCheck(w == ttb_w && h == ttb_h,
"Can change per-font direction: %dx%d", w, h);

SDLTest_AssertCheck(TTF_SetFontDirection(font, TTF_DIRECTION_LTR) == 0,
"Set font direction");
SDLTest_AssertCheck(TTF_SetDirection(HB_DIRECTION_TTB) == 0,
"Set global direction");
TTF_SizeUTF8(font, hello, &w, &h);
SDLTest_AssertCheck(w == ltr_w && h == ltr_h,
"Changing font direction works: %dx%d", w, h);

font2 = TTF_OpenFont(fontPath, 12);
error = (font2 != NULL) ? "successful" : TTF_GetError();
if (!SDLTest_AssertCheck(font2 != NULL,
"Load font %s: %s", fontPath, error)) {
goto out;
}

TTF_SizeUTF8(font2, hello, &w, &h);
SDLTest_AssertCheck(w == ttb_w && h == ttb_h,
"Global direction is used for new font: %dx%d",
w, h);
#endif

out:
if (font != NULL) {
TTF_CloseFont(font);
}
if (TTF_WasInit()) {
TTF_Quit();
}
return TEST_COMPLETED;
}

static const SDLTest_TestCaseReference directionTestCase = {
TestDirection, "Direction", "Render text directionally", TEST_ENABLED
};

static const SDLTest_TestCaseReference *testCases[] = {
&directionTestCase,
NULL
};
static SDLTest_TestSuiteReference testSuite = {
"ttf",
NULL,
testCases,
NULL
};
static SDLTest_TestSuiteReference *testSuites[] = {
&testSuite,
NULL
};

/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
static void
quit(int rc)
{
SDLTest_CommonQuit(state);
exit(rc);
}

int
main(int argc, char *argv[])
{
int result;
int testIterations = 1;
Uint64 userExecKey = 0;
char *userRunSeed = NULL;
char *filter = NULL;
int i, done;
SDL_Event event;

/* Initialize test framework */
state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO);
if (!state) {
return 1;
}

/* Parse commandline */
for (i = 1; i < argc;) {
int consumed;

consumed = SDLTest_CommonArg(state, i);
if (consumed == 0) {
consumed = -1;
if (SDL_strcasecmp(argv[i], "--iterations") == 0) {
if (argv[i + 1]) {
testIterations = SDL_atoi(argv[i + 1]);
if (testIterations < 1) testIterations = 1;
consumed = 2;
}
}
else if (SDL_strcasecmp(argv[i], "--execKey") == 0) {
if (argv[i + 1]) {
SDL_sscanf(argv[i + 1], "%"SDL_PRIu64, &userExecKey);
consumed = 2;
}
}
else if (SDL_strcasecmp(argv[i], "--seed") == 0) {
if (argv[i + 1]) {
userRunSeed = SDL_strdup(argv[i + 1]);
consumed = 2;
}
}
else if (SDL_strcasecmp(argv[i], "--filter") == 0) {
if (argv[i + 1]) {
filter = SDL_strdup(argv[i + 1]);
consumed = 2;
}
}
else if (argv[i][0] != '-') {
if (fontPath == NULL) {
fontPath = argv[i];
consumed = 1;
}
}
}
if (consumed < 0) {
static const char *options[] = { "[--iterations #]", "[--execKey #]", "[--seed string]", "[--filter suite_name|test_name] font_path", NULL };
SDLTest_CommonLogUsage(state, argv[0], options);
quit(1);
}

i += consumed;
}

if (fontPath == NULL) {
SDLTest_LogError("A font is required");
quit(1);
}

/* Initialize common state */
if (!SDLTest_CommonInit(state)) {
quit(2);
}

/* Create the windows, initialize the renderers */
for (i = 0; i < state->num_windows; ++i) {
SDL_Renderer *renderer = state->renderers[i];
SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF);
SDL_RenderClear(renderer);
}

/* Call Harness */
result = SDLTest_RunSuites(testSuites, (const char *)userRunSeed, userExecKey, (const char *)filter, testIterations);

/* Empty event queue */
done = 0;
for (i=0; i<100; i++) {
while (SDL_PollEvent(&event)) {
SDLTest_CommonEvent(state, &event, &done);
}
SDL_Delay(10);
}

/* Clean up */
SDL_free(userRunSeed);
SDL_free(filter);

/* Shutdown everything */
quit(result);
return(result);
}

/* vi: set ts=4 sw=4 expandtab: */