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

Port font to SDL3(_ttf) #3326

Merged
merged 1 commit into from
Feb 10, 2025
Merged
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
11 changes: 11 additions & 0 deletions .github/workflows/build-sdl3.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,17 @@ jobs:
cmake --build . --config Release --parallel
sudo cmake --install . --config Release

- name: Install SDL3_ttf
if: matrix.os != 'windows-latest'
run: |
git clone https://github.com/libsdl-org/SDL_ttf
cd SDL_ttf
mkdir build
cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build . --config Release --parallel
sudo cmake --install . --config Release

- name: Build with SDL3
run: python3 dev.py build --sdl3

Expand Down
16 changes: 16 additions & 0 deletions buildconfig/download_win_prebuilt.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,10 @@ def get_urls(x86=True, x64=True):
'2d18b9a4fc2ec0eee80de2a946b088d4e6efd0ee'
],
[
'https://github.com/libsdl-org/SDL_ttf/releases/download/preview-3.1.0/SDL3_ttf-devel-3.1.0-VC.zip',
'34bb4a03c6f0f6c9de3658bac98adc7029830578'
],
[
'https://github.com/libsdl-org/SDL_mixer/releases/download/release-2.8.0/SDL2_mixer-devel-2.8.0-VC.zip',
'a10411644e08cd94f29712f430c7b71c407ae76d',
],
Expand Down Expand Up @@ -251,6 +255,18 @@ def copy(src, dst):
'SDL2_ttf-2.24.0'
)
)
copy(
os.path.join(
temp_dir,
'SDL3_ttf-devel-3.1.0-VC/SDL3_ttf-3.1.0'
),
os.path.join(
move_to_dir,
prebuilt_dir,
'SDL3_ttf-3.1.0'
)
)

copy(
os.path.join(
temp_dir,
Expand Down
1 change: 0 additions & 1 deletion dev.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
SDL3_ARGS = [
"-Csetup-args=-Dsdl_api=3",
"-Csetup-args=-Dmixer=disabled",
"-Csetup-args=-Dfont=disabled",
]
COVERAGE_ARGS = ["-Csetup-args=-Dcoverage=true"]

Expand Down
2 changes: 1 addition & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ if plat == 'win' and host_machine.cpu_family().startswith('x86')
sdl_ver = (sdl_api == 3) ? '3.2.2' : '2.30.12'
sdl_image_ver = (sdl_api == 3) ? '3.1.1' : '2.8.4'
sdl_mixer_ver = '2.8.0'
sdl_ttf_ver = '2.24.0'
sdl_ttf_ver = (sdl_api == 3) ? '3.1.0' : '2.24.0'

dlls = []

Expand Down
135 changes: 119 additions & 16 deletions src_c/font.c
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,14 @@ static PyObject *
fontmodule_init(PyObject *self, PyObject *_null)
{
if (!font_initialized) {
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
if (!TTF_Init())
#else
if (TTF_Init())
#endif
{
return RAISE(pgExc_SDLError, SDL_GetError());

}
font_initialized = 1;
}
Py_RETURN_NONE;
Expand Down Expand Up @@ -169,7 +174,11 @@ font_get_height(PyObject *self, PyObject *_null)
}

TTF_Font *font = PyFont_AsFont(self);
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
return PyLong_FromLong(TTF_GetFontHeight(font));
#else
return PyLong_FromLong(TTF_FontHeight(font));
#endif
}

static PyObject *
Expand All @@ -180,7 +189,11 @@ font_get_descent(PyObject *self, PyObject *_null)
}

TTF_Font *font = PyFont_AsFont(self);
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
return PyLong_FromLong(TTF_GetFontDescent(font));
#else
return PyLong_FromLong(TTF_FontDescent(font));
#endif
}

static PyObject *
Expand All @@ -191,7 +204,11 @@ font_get_ascent(PyObject *self, PyObject *_null)
}

TTF_Font *font = PyFont_AsFont(self);
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
return PyLong_FromLong(TTF_GetFontAscent(font));
#else
return PyLong_FromLong(TTF_FontAscent(font));
#endif
}

static PyObject *
Expand All @@ -202,7 +219,11 @@ font_get_linesize(PyObject *self, PyObject *_null)
}

TTF_Font *font = PyFont_AsFont(self);
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
return PyLong_FromLong(TTF_GetFontLineSkip(font));
#else
return PyLong_FromLong(TTF_FontLineSkip(font));
#endif
}

static PyObject *
Expand Down Expand Up @@ -453,7 +474,10 @@ font_getter_align(PyObject *self, void *closure)
return RAISE_FONT_QUIT_ERROR();
}

#if SDL_TTF_VERSION_ATLEAST(2, 20, 0)
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
TTF_Font *font = PyFont_AsFont(self);
return PyLong_FromLong(TTF_GetFontWrapAlignment(font));
#elif SDL_TTF_VERSION_ATLEAST(2, 20, 0)
TTF_Font *font = PyFont_AsFont(self);
return PyLong_FromLong(TTF_GetFontWrappedAlign(font));
#else
Expand Down Expand Up @@ -492,7 +516,11 @@ font_setter_align(PyObject *self, PyObject *value, void *closure)
return -1;
}

#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
TTF_SetFontWrapAlignment(font, val);
#else
TTF_SetFontWrappedAlign(font, val);
#endif
return 0;
#else
PyErr_SetString(pgExc_SDLError,
Expand Down Expand Up @@ -611,28 +639,41 @@ font_render(PyObject *self, PyObject *args, PyObject *kwds)
length string */

if (strlen(astring) == 0) { /* special 0 string case */
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
int height = TTF_GetFontHeight(font);
#else
int height = TTF_FontHeight(font);
#endif
surf = PG_CreateSurface(0, height, SDL_PIXELFORMAT_XRGB8888);
}
else { /* normal case */
if (antialias && bg_rgba_obj == Py_None) {
#if SDL_TTF_VERSION_ATLEAST(2, 0, 18)
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
surf = TTF_RenderText_Blended_Wrapped(font, astring, 0, foreg,
wraplength);
#elif SDL_TTF_VERSION_ATLEAST(2, 0, 18)
surf = TTF_RenderUTF8_Blended_Wrapped(font, astring, foreg,
wraplength);
#else
surf = TTF_RenderUTF8_Blended(font, astring, foreg);
#endif
}
else if (antialias) {
#if SDL_TTF_VERSION_ATLEAST(2, 0, 18)
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
surf = TTF_RenderText_Shaded_Wrapped(font, astring, 0, foreg,
backg, wraplength);
#elif SDL_TTF_VERSION_ATLEAST(2, 0, 18)
surf = TTF_RenderUTF8_Shaded_Wrapped(font, astring, foreg, backg,
wraplength);
#else
surf = TTF_RenderUTF8_Shaded(font, astring, foreg, backg);
#endif
}
else {
#if SDL_TTF_VERSION_ATLEAST(2, 0, 18)
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
surf = TTF_RenderText_Solid_Wrapped(font, astring, 0, foreg,
wraplength);
#elif SDL_TTF_VERSION_ATLEAST(2, 0, 18)
surf =
TTF_RenderUTF8_Solid_Wrapped(font, astring, foreg, wraplength);
#else
Expand All @@ -642,9 +683,16 @@ font_render(PyObject *self, PyObject *args, PyObject *kwds)
resolve to Render_Solid, that needs to be explicitly handled. */
if (surf != NULL && bg_rgba_obj != Py_None) {
SDL_SetColorKey(surf, 0, 0);
surf->format->palette->colors[0].r = backg.r;
surf->format->palette->colors[0].g = backg.g;
surf->format->palette->colors[0].b = backg.b;
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
SDL_Palette *palette = SDL_GetSurfacePalette(surf);
#else
SDL_Palette *palette = surf->format->palette;
#endif
if (palette) {
palette->colors[0].r = backg.r;
palette->colors[0].g = backg.g;
palette->colors[0].b = backg.b;
}
}
}
}
Expand Down Expand Up @@ -683,15 +731,24 @@ font_size(PyObject *self, PyObject *text)
return NULL;
}
string = PyBytes_AS_STRING(bytes);
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
ecode = TTF_GetStringSize(font, string, 0, &w, &h) ? 0 : -1;
#else
ecode = TTF_SizeUTF8(font, string, &w, &h);
#endif
Py_DECREF(bytes);
if (ecode) {
return RAISE(pgExc_SDLError, TTF_GetError());
}
}
else if (PyBytes_Check(text)) {
string = PyBytes_AS_STRING(text);
if (TTF_SizeText(font, string, &w, &h)) {
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
if (!TTF_GetStringSize(font, string, 0, &w, &h))
#else
if (TTF_SizeText(font, string, &w, &h))
#endif
{
return RAISE(pgExc_SDLError, TTF_GetError());
}
}
Expand Down Expand Up @@ -737,7 +794,13 @@ font_setter_point_size(PyFontObject *self, PyObject *value, void *closure)
return -1;
}

if (TTF_SetFontSize(font, val) == -1) {
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
/* TODO: can consider supporting float in python API */
if (!TTF_SetFontSize(font, (float)val))
#else
if (TTF_SetFontSize(font, val) == -1)
#endif
{
PyErr_SetString(pgExc_SDLError, SDL_GetError());
return -1;
}
Expand Down Expand Up @@ -786,7 +849,13 @@ font_set_ptsize(PyObject *self, PyObject *arg)
"point_size cannot be equal to, or less than 0");
}

if (TTF_SetFontSize(font, val) == -1) {
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
/* TODO: can consider supporting float in python API */
if (!TTF_SetFontSize(font, (float)val))
#else
if (TTF_SetFontSize(font, val) == -1)
#endif
{
return RAISE(pgExc_SDLError, SDL_GetError());
}
((PyFontObject *)self)->ptsize = val;
Expand All @@ -806,7 +875,11 @@ font_getter_name(PyObject *self, void *closure)
}

TTF_Font *font = PyFont_AsFont(self);
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
const char *font_name = TTF_GetFontFamilyName(font);
#else
const char *font_name = TTF_FontFaceFamilyName(font);
#endif

return PyUnicode_FromString(font_name ? font_name : "");
}
Expand All @@ -819,7 +892,11 @@ font_getter_style_name(PyObject *self, void *closure)
}

TTF_Font *font = PyFont_AsFont(self);
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
const char *font_style_name = TTF_GetFontStyleName(font);
#else
const char *font_style_name = TTF_FontFaceStyleName(font);
#endif
return PyUnicode_FromString(font_style_name ? font_style_name : "");
}

Expand Down Expand Up @@ -882,9 +959,16 @@ font_metrics(PyObject *self, PyObject *textobj)
* TTF_GlyphMetrics() seems to return a value for any character,
* using the default invalid character, if the char is not found.
*/
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
if (!surrogate && /* conditional and */
TTF_GetGlyphMetrics(font, (Uint16)ch, &minx, &maxx, &miny, &maxy,
&advance))
#else
if (!surrogate && /* conditional and */
!TTF_GlyphMetrics(font, (Uint16)ch, &minx, &maxx, &miny, &maxy,
&advance)) {
&advance))
#endif
{
listitem =
Py_BuildValue("(iiiii)", minx, maxx, miny, maxy, advance);
if (!listitem) {
Expand Down Expand Up @@ -912,6 +996,14 @@ font_metrics(PyObject *self, PyObject *textobj)
return list;
}

/* This is taken from the harfbuzz header file. It converts script name in the
* format expected by sdl2 (a 4 char string) to the format expected by sdl3
* (a single uint32 tag) */
#define HB_TAG(c1, c2, c3, c4) \
((Uint32)((((uint32_t)(c1) & 0xFF) << 24) | \
(((uint32_t)(c2) & 0xFF) << 16) | \
(((uint32_t)(c3) & 0xFF) << 8) | ((uint32_t)(c4) & 0xFF)))

static PyObject *
font_set_script(PyObject *self, PyObject *arg)
{
Expand All @@ -935,7 +1027,13 @@ font_set_script(PyObject *self, PyObject *arg)
"script code must be exactly 4 characters");
}

if (TTF_SetFontScriptName(font, script_code) < 0) {
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
if (!TTF_SetFontScript(font, HB_TAG(script_code[0], script_code[1],
script_code[2], script_code[3])))
#else
if (TTF_SetFontScriptName(font, script_code) < 0)
Starbuck5 marked this conversation as resolved.
Show resolved Hide resolved
#endif
{
return RAISE(pgExc_SDLError, SDL_GetError());
}
#else
Expand Down Expand Up @@ -1013,8 +1111,12 @@ font_set_direction(PyObject *self, PyObject *arg, PyObject *kwarg)
" to https://github.com/pygame-community/pygame-ce");
}
}

if (TTF_SetFontDirection(font, dir)) {
#if SDL_TTF_VERSION_ATLEAST(3, 0, 0)
if (!TTF_SetFontDirection(font, dir))
#else
if (TTF_SetFontDirection(font, dir))
#endif
{
return RAISE(pgExc_SDLError, SDL_GetError());
}

Expand Down Expand Up @@ -1183,7 +1285,8 @@ font_init(PyFontObject *self, PyObject *args, PyObject *kwds)

Py_BEGIN_ALLOW_THREADS;
#if SDL_VERSION_ATLEAST(3, 0, 0)
font = TTF_OpenFontIO(rw, 1, fontsize);
/* TODO: can consider supporting float in python API */
font = TTF_OpenFontIO(rw, 1, (float)fontsize);
#else
font = TTF_OpenFontRW(rw, 1, fontsize);
#endif
Expand Down
9 changes: 8 additions & 1 deletion src_c/font.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
#ifndef PGFONT_INTERNAL_H
#define PGFONT_INTERNAL_H

#include <SDL_ttf.h>
#ifdef PG_SDL3
#include <SDL3_ttf/SDL_ttf.h>

// SDL3_ttf uses SDL3 error reporting API
#define TTF_GetError SDL_GetError

#else
#include <SDL_ttf.h>
#endif
/* test font initialization */
#define FONT_INIT_CHECK() \
if (!(*(int *)PyFONT_C_API[2])) \
Expand Down
Loading
Loading