From 731f43e0bc18f6edb68b20da18a593f80521c3ae Mon Sep 17 00:00:00 2001 From: Steven Wallace Date: Wed, 1 Oct 2025 17:39:00 -0500 Subject: [PATCH 01/14] Added outline property to pygame.font.Font --- buildconfig/stubs/pygame/font.pyi | 6 ++ docs/reST/ref/font.rst | 42 ++++++++++++++ src_c/doc/font_doc.h | 3 + src_c/font.c | 94 +++++++++++++++++++++++++++++++ test/font_test.py | 87 +++++++++++++++++++++++++++- 5 files changed, 231 insertions(+), 1 deletion(-) diff --git a/buildconfig/stubs/pygame/font.pyi b/buildconfig/stubs/pygame/font.pyi index df5a89bb55..cd096ad7df 100644 --- a/buildconfig/stubs/pygame/font.pyi +++ b/buildconfig/stubs/pygame/font.pyi @@ -57,6 +57,10 @@ class Font: def point_size(self) -> int: ... @point_size.setter def point_size(self, value: int) -> None: ... + @property + def outline(self) -> int: ... + @outline.setter + def outline(self, value: int) -> None: ... def __init__(self, filename: FileLike | None = None, size: int = 20) -> None: ... def render( self, @@ -85,6 +89,8 @@ class Font: def set_direction(self, direction: int) -> None: ... def get_point_size(self) -> int: ... def set_point_size(self, val: int, /) -> None: ... + def get_outline(self) -> int: ... + def set_outline(self, val: int, /) -> None: ... @deprecated("Use `Font` instead (FontType is an old alias)") class FontType(Font): ... diff --git a/docs/reST/ref/font.rst b/docs/reST/ref/font.rst index 8057bb46f2..b31eeede63 100644 --- a/docs/reST/ref/font.rst +++ b/docs/reST/ref/font.rst @@ -306,6 +306,22 @@ solves no longer exists, it will likely be removed in the future. .. ## Font.point_size ## + + .. attribute:: outline + + | :sl:`Gets or sets the font's outline value` + | :sg:`outline -> int` + + The outline value of the font. + + When set to 0, the font will be drawn normally. When positive, + the text will be drawn as a hollow outline. This can be drawn + underneath unoutlined text to create a text outline effect. + + .. versionadded:: 2.5.6 + + .. ## Font.outline ## + .. method:: render | :sl:`draw text on a new Surface` @@ -562,6 +578,32 @@ solves no longer exists, it will likely be removed in the future. .. ## Font.get_point_size ## + .. method:: set_outline + + | :sl:`set the outline value of the font` + | :sg:`set_outline(size, /) -> None` + + Sets the outline value of the font. + + .. note:: This is the same as the :attr:`outline` attribute. + + .. versionadded:: 2.5.6 + + .. ## Font.set_outline ## + + .. method:: get_outline + + | :sl:`get the outline value of the font` + | :sg:`get_outline() -> int` + + Returns the outline value of the font. + + .. note:: This is the same as the :attr:`outline` attribute. + + .. versionadded:: 2.5.6 + + .. ## Font.get_outline ## + .. method:: get_ascent | :sl:`get the ascent of the font` diff --git a/src_c/doc/font_doc.h b/src_c/doc/font_doc.h index 486e2d9088..6a8ffc1f16 100644 --- a/src_c/doc/font_doc.h +++ b/src_c/doc/font_doc.h @@ -17,6 +17,7 @@ #define DOC_FONT_FONT_STRIKETHROUGH "strikethrough -> bool\nGets or sets whether the font should be rendered with a strikethrough." #define DOC_FONT_FONT_ALIGN "align -> int\nSet how rendered text is aligned when given a wrap length." #define DOC_FONT_FONT_POINTSIZE "point_size -> int\nGets or sets the font's point size" +#define DOC_FONT_FONT_OUTLINE "outline -> int\nGets or sets the font's outline value" #define DOC_FONT_FONT_RENDER "render(text, antialias, color, bgcolor=None, wraplength=0) -> Surface\ndraw text on a new Surface" #define DOC_FONT_FONT_SIZE "size(text, /) -> (width, height)\ndetermine the amount of space needed to render text" #define DOC_FONT_FONT_SETUNDERLINE "set_underline(bool, /) -> None\ncontrol if text is rendered with an underline" @@ -33,6 +34,8 @@ #define DOC_FONT_FONT_GETHEIGHT "get_height() -> int\nget the height of the font" #define DOC_FONT_FONT_SETPOINTSIZE "set_point_size(size, /) -> None\nset the point size of the font" #define DOC_FONT_FONT_GETPOINTSIZE "get_point_size() -> int\nget the point size of the font" +#define DOC_FONT_FONT_SETOUTLINE "set_outline(outline, /) -> None\nset The outline value of the font" +#define DOC_FONT_FONT_GETOUTLINE "get_outline() -> int\nget the outline value of the font" #define DOC_FONT_FONT_GETASCENT "get_ascent() -> int\nget the ascent of the font" #define DOC_FONT_FONT_GETDESCENT "get_descent() -> int\nget the descent of the font" #define DOC_FONT_FONT_SETSCRIPT "set_script(str, /) -> None\nset the script code for text shaping" diff --git a/src_c/font.c b/src_c/font.c index 11b7b20530..1bc71c5bfc 100644 --- a/src_c/font.c +++ b/src_c/font.c @@ -901,6 +901,96 @@ font_set_ptsize(PyObject *self, PyObject *arg) #endif } +static PyObject * +font_getter_outline(PyObject *self, void *closure) +{ + if (!PgFont_GenerationCheck(self)) { + return RAISE_FONT_QUIT_ERROR(); + } + +#if SDL_TTF_VERSION_ATLEAST(2, 0, 12) + TTF_Font *font = PyFont_AsFont(self); + return PyLong_FromLong(TTF_GetFontOutline(font)); +#else + return RAISE(pgExc_SDLError, + "pygame.font not compiled with a new enough SDL_ttf version. " + "Needs SDL_ttf 2.0.12 or above."); +#endif +} + +static int +font_setter_outline(PyObject *self, PyObject *value, void *closure) +{ + if (!PgFont_GenerationCheck(self)) { + RAISE_FONT_QUIT_ERROR_RETURN(-1); + } +#if SDL_TTF_VERSION_ATLEAST(2, 0, 12) + TTF_Font *font = PyFont_AsFont(self); + + DEL_ATTR_NOT_SUPPORTED_CHECK("outline", value); + + if (!PyLong_Check(value)) { + PyErr_SetString(PyExc_TypeError, "outline must be an integer"); + return -1; + } + long val = PyLong_AsLong(value); + if (val == -1 && PyErr_Occurred()) { + return -1; + } + if (val < 0) { + PyErr_SetString(PyExc_ValueError, "outline must be >= 0"); + return -1; + } + TTF_SetFontOutline(font, (int)val); + return 0; +#else + RAISE(pgExc_SDLError, + "pygame.font not compiled with a new enough SDL_ttf version. Needs SDL_ttf 2.0.12 or above."); + return -1; +#endif +} + +static PyObject * +font_get_outline(PyObject *self, PyObject *_null) +{ + if (!PgFont_GenerationCheck(self)) { + return RAISE_FONT_QUIT_ERROR(); + } +#if SDL_TTF_VERSION_ATLEAST(2, 0, 12) + TTF_Font *font = PyFont_AsFont(self); + return PyLong_FromLong(TTF_GetFontOutline(font)); +#else + return RAISE(pgExc_SDLError, + "pygame.font not compiled with a new enough SDL_ttf version. " + "Needs SDL_ttf 2.0.12 or above."); +#endif +} + +static PyObject * +font_set_outline(PyObject *self, PyObject *arg) +{ + if (!PgFont_GenerationCheck(self)) { + return RAISE_FONT_QUIT_ERROR(); + } +#if SDL_TTF_VERSION_ATLEAST(2, 0, 12) + TTF_Font *font = PyFont_AsFont(self); + long val = PyLong_AsLong(arg); + if (val == -1 && PyErr_Occurred()) { + return NULL; + } + if (val < 0) { + return RAISE(PyExc_ValueError, "outline must be >= 0"); + } + TTF_SetFontOutline(font, (int)val); + Py_RETURN_NONE; +#else + return RAISE(pgExc_SDLError, + "pygame.font not compiled with a new enough SDL_ttf version. " + "Needs SDL_ttf 2.0.12 or above."); +#endif +} + + static PyObject * font_getter_name(PyObject *self, void *closure) { @@ -1168,6 +1258,8 @@ static PyGetSetDef font_getsets[] = { DOC_FONT_FONT_UNDERLINE, NULL}, {"strikethrough", (getter)font_getter_strikethrough, (setter)font_setter_strikethrough, DOC_FONT_FONT_STRIKETHROUGH, NULL}, + {"outline", (getter)font_getter_outline, (setter)font_setter_outline, + DOC_FONT_FONT_OUTLINE, NULL}, {"align", (getter)font_getter_align, (setter)font_setter_align, DOC_FONT_FONT_ALIGN, NULL}, {"point_size", (getter)font_getter_point_size, @@ -1192,6 +1284,8 @@ static PyMethodDef font_methods[] = { DOC_FONT_FONT_GETSTRIKETHROUGH}, {"set_strikethrough", font_set_strikethrough, METH_O, DOC_FONT_FONT_SETSTRIKETHROUGH}, + {"get_outline", font_get_outline, METH_NOARGS, DOC_FONT_FONT_GETOUTLINE}, + {"set_outline", font_set_outline, METH_O, DOC_FONT_FONT_SETOUTLINE}, {"get_point_size", font_get_ptsize, METH_NOARGS, DOC_FONT_FONT_GETPOINTSIZE}, {"set_point_size", font_set_ptsize, METH_O, DOC_FONT_FONT_SETPOINTSIZE}, diff --git a/test/font_test.py b/test/font_test.py index bdac5235c1..7cd9576b3d 100644 --- a/test/font_test.py +++ b/test/font_test.py @@ -688,6 +688,70 @@ def test_point_size_method(self): self.assertRaises(ValueError, f.set_point_size, -500) self.assertRaises(TypeError, f.set_point_size, "15") + def test_outline_property(self): + if pygame_font.__name__ == "pygame.ftfont": + return # not a pygame.ftfont feature + + pygame_font.init() + font_path = os.path.join( + os.path.split(pygame.__file__)[0], pygame_font.get_default_font() + ) + f = pygame_font.Font(pathlib.Path(font_path), 25) + + ttf_version = pygame_font.get_sdl_ttf_version() + if ttf_version < (2, 0, 12): + with self.assertRaises(pygame.error): + f.outline = 0 + with self.assertRaises(pygame.error): + _ = f.outline + return + + # Default outline should be an integer >= 0 (typically 0) + self.assertIsInstance(f.outline, int) + self.assertGreaterEqual(f.outline, 0) + + orig = f.outline + f.outline = orig + 1 + self.assertEqual(orig + 1, f.outline) + f.outline += 2 + self.assertEqual(orig + 3, f.outline) + f.outline -= 1 + self.assertEqual(orig + 2, f.outline) + + def test_neg(): + f.outline = -1 + + def test_incorrect_type(): + f.outline = "2" + + self.assertRaises(ValueError, test_neg) + self.assertRaises(TypeError, test_incorrect_type) + + def test_outline_method(self): + if pygame_font.__name__ == "pygame.ftfont": + return # not a pygame.ftfont feature + + pygame_font.init() + font_path = os.path.join( + os.path.split(pygame.__file__)[0], pygame_font.get_default_font() + ) + f = pygame_font.Font(pathlib.Path(font_path), 25) + + ttf_version = pygame_font.get_sdl_ttf_version() + if ttf_version < (2, 0, 12): + self.assertRaises(pygame.error, f.get_outline) + self.assertRaises(pygame.error, f.set_outline, 1) + return + + val0 = f.get_outline() + self.assertIsInstance(val0, int) + self.assertGreaterEqual(val0, 0) + + f.set_outline(5) + self.assertEqual(5, f.get_outline()) + self.assertRaises(ValueError, f.set_outline, -1) + self.assertRaises(TypeError, f.set_outline, "2") + def test_font_name(self): f = pygame_font.Font(None, 20) self.assertEqual(f.name, "FreeSans") @@ -936,6 +1000,14 @@ def test_font_method_should_raise_exception_after_quit(self): ] skip_methods = set() version = pygame.font.get_sdl_ttf_version() + + if version >= (2, 0, 12): + methods.append(("get_outline", ())) + methods.append(("set_outline", (2,))) + else: + skip_methods.add("get_outline") + skip_methods.add("set_outline") + if version >= (2, 0, 18): methods.append(("get_point_size", ())) methods.append(("set_point_size", (34,))) @@ -1035,6 +1107,11 @@ def test_font_property_should_raise_exception_after_quit(self): else: skip_properties.add("point_size") + if version >= (2, 0, 12): + properties.append(("outline", 1)) + else: + skip_properties.add("outline") + font = pygame_font.Font(None, 10) actual_names = [] @@ -1099,6 +1176,7 @@ def query( underline=False, strikethrough=False, antialiase=False, + outline=0 ): if self.aborted: return False @@ -1109,7 +1187,7 @@ def query( screen = self.screen screen.fill((255, 255, 255)) pygame.display.flip() - if not (bold or italic or underline or strikethrough or antialiase): + if not (bold or italic or underline or strikethrough or antialiase or outline): text = "normal" else: modes = [] @@ -1123,11 +1201,14 @@ def query( modes.append("strikethrough") if antialiase: modes.append("antialiased") + if outline: + modes.append("outlined") text = f"{'-'.join(modes)} (y/n):" f.set_bold(bold) f.set_italic(italic) f.set_underline(underline) f.set_strikethrough(strikethrough) + f.set_outline(outline) s = f.render(text, antialiase, (0, 0, 0)) screen.blit(s, (offset, y)) y += s.get_size()[1] + spacing @@ -1135,6 +1216,7 @@ def query( f.set_italic(False) f.set_underline(False) f.set_strikethrough(False) + f.set_outline(0) s = f.render("(some comparison text)", False, (0, 0, 0)) screen.blit(s, (offset, y)) pygame.display.flip() @@ -1176,6 +1258,9 @@ def test_italic_underline(self): def test_bold_strikethrough(self): self.assertTrue(self.query(bold=True, strikethrough=True)) + def test_outline(self): + self.assertTrue(self.query(outline=1)) + if __name__ == "__main__": unittest.main() From 9087d3ecf3465b8eeda1367ddd7b5f24383aa5f7 Mon Sep 17 00:00:00 2001 From: Steven Wallace Date: Wed, 1 Oct 2025 19:27:02 -0500 Subject: [PATCH 02/14] Updated font outline formatting. --- src_c/doc/font_doc.h | 2 +- src_c/font.c | 4 ++-- test/font_test.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src_c/doc/font_doc.h b/src_c/doc/font_doc.h index 6a8ffc1f16..0adb400947 100644 --- a/src_c/doc/font_doc.h +++ b/src_c/doc/font_doc.h @@ -34,7 +34,7 @@ #define DOC_FONT_FONT_GETHEIGHT "get_height() -> int\nget the height of the font" #define DOC_FONT_FONT_SETPOINTSIZE "set_point_size(size, /) -> None\nset the point size of the font" #define DOC_FONT_FONT_GETPOINTSIZE "get_point_size() -> int\nget the point size of the font" -#define DOC_FONT_FONT_SETOUTLINE "set_outline(outline, /) -> None\nset The outline value of the font" +#define DOC_FONT_FONT_SETOUTLINE "set_outline(size, /) -> None\nset the outline value of the font" #define DOC_FONT_FONT_GETOUTLINE "get_outline() -> int\nget the outline value of the font" #define DOC_FONT_FONT_GETASCENT "get_ascent() -> int\nget the ascent of the font" #define DOC_FONT_FONT_GETDESCENT "get_descent() -> int\nget the descent of the font" diff --git a/src_c/font.c b/src_c/font.c index 1bc71c5bfc..9bd997b2ed 100644 --- a/src_c/font.c +++ b/src_c/font.c @@ -945,7 +945,8 @@ font_setter_outline(PyObject *self, PyObject *value, void *closure) return 0; #else RAISE(pgExc_SDLError, - "pygame.font not compiled with a new enough SDL_ttf version. Needs SDL_ttf 2.0.12 or above."); + "pygame.font not compiled with a new enough SDL_ttf version. Needs " + "SDL_ttf 2.0.12 or above."); return -1; #endif } @@ -990,7 +991,6 @@ font_set_outline(PyObject *self, PyObject *arg) #endif } - static PyObject * font_getter_name(PyObject *self, void *closure) { diff --git a/test/font_test.py b/test/font_test.py index 7cd9576b3d..8498bffddb 100644 --- a/test/font_test.py +++ b/test/font_test.py @@ -1176,7 +1176,7 @@ def query( underline=False, strikethrough=False, antialiase=False, - outline=0 + outline=0, ): if self.aborted: return False From 1146a3a2b738d62c07aa057b14b7c44baa3c32ff Mon Sep 17 00:00:00 2001 From: Steven Wallace Date: Thu, 2 Oct 2025 08:49:37 -0500 Subject: [PATCH 03/14] Improved version checks when in font outline tests. --- test/font_test.py | 64 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 48 insertions(+), 16 deletions(-) diff --git a/test/font_test.py b/test/font_test.py index 8498bffddb..a4b6b7f904 100644 --- a/test/font_test.py +++ b/test/font_test.py @@ -688,6 +688,9 @@ def test_point_size_method(self): self.assertRaises(ValueError, f.set_point_size, -500) self.assertRaises(TypeError, f.set_point_size, "15") + @unittest.skipIf( + pygame.font.get_sdl_ttf_version() < (2, 0, 12), "outlines were added in SDL_TTF 2.0.12" + ) def test_outline_property(self): if pygame_font.__name__ == "pygame.ftfont": return # not a pygame.ftfont feature @@ -698,14 +701,6 @@ def test_outline_property(self): ) f = pygame_font.Font(pathlib.Path(font_path), 25) - ttf_version = pygame_font.get_sdl_ttf_version() - if ttf_version < (2, 0, 12): - with self.assertRaises(pygame.error): - f.outline = 0 - with self.assertRaises(pygame.error): - _ = f.outline - return - # Default outline should be an integer >= 0 (typically 0) self.assertIsInstance(f.outline, int) self.assertGreaterEqual(f.outline, 0) @@ -727,7 +722,10 @@ def test_incorrect_type(): self.assertRaises(ValueError, test_neg) self.assertRaises(TypeError, test_incorrect_type) - def test_outline_method(self): + @unittest.skipIf( + pygame.font.get_sdl_ttf_version() >= (2, 0, 12), "outlines were added in SDL_TTF 2.0.12" + ) + def test_outline_property_stub(self): if pygame_font.__name__ == "pygame.ftfont": return # not a pygame.ftfont feature @@ -737,11 +735,24 @@ def test_outline_method(self): ) f = pygame_font.Font(pathlib.Path(font_path), 25) - ttf_version = pygame_font.get_sdl_ttf_version() - if ttf_version < (2, 0, 12): - self.assertRaises(pygame.error, f.get_outline) - self.assertRaises(pygame.error, f.set_outline, 1) - return + with self.assertRaises(pygame.error): + f.outline = 0 + with self.assertRaises(pygame.error): + _ = f.outline + + + @unittest.skipIf( + pygame.font.get_sdl_ttf_version() < (2, 0, 12), "outlines were added in SDL_TTF 2.0.12" + ) + def test_outline_method(self): + if pygame_font.__name__ == "pygame.ftfont": + return # not a pygame.ftfont feature + + pygame_font.init() + font_path = os.path.join( + os.path.split(pygame.__file__)[0], pygame_font.get_default_font() + ) + f = pygame_font.Font(pathlib.Path(font_path), 25) val0 = f.get_outline() self.assertIsInstance(val0, int) @@ -752,6 +763,22 @@ def test_outline_method(self): self.assertRaises(ValueError, f.set_outline, -1) self.assertRaises(TypeError, f.set_outline, "2") + @unittest.skipIf( + pygame.font.get_sdl_ttf_version() >= (2, 0, 12), "outlines were added in SDL_TTF 2.0.12" + ) + def test_outline_method_stub(self): + if pygame_font.__name__ == "pygame.ftfont": + return # not a pygame.ftfont feature + + pygame_font.init() + font_path = os.path.join( + os.path.split(pygame.__file__)[0], pygame_font.get_default_font() + ) + f = pygame_font.Font(pathlib.Path(font_path), 25) + + self.assertRaises(pygame.error, f.get_outline) + self.assertRaises(pygame.error, f.set_outline, 1) + def test_font_name(self): f = pygame_font.Font(None, 20) self.assertEqual(f.name, "FreeSans") @@ -1208,7 +1235,8 @@ def query( f.set_italic(italic) f.set_underline(underline) f.set_strikethrough(strikethrough) - f.set_outline(outline) + if pygame.font.get_sdl_ttf_version() >= (2, 0, 12): + f.set_outline(outline) s = f.render(text, antialiase, (0, 0, 0)) screen.blit(s, (offset, y)) y += s.get_size()[1] + spacing @@ -1216,7 +1244,8 @@ def query( f.set_italic(False) f.set_underline(False) f.set_strikethrough(False) - f.set_outline(0) + if pygame.font.get_sdl_ttf_version() >= (2, 0, 12): + f.set_outline(0) s = f.render("(some comparison text)", False, (0, 0, 0)) screen.blit(s, (offset, y)) pygame.display.flip() @@ -1258,6 +1287,9 @@ def test_italic_underline(self): def test_bold_strikethrough(self): self.assertTrue(self.query(bold=True, strikethrough=True)) + @unittest.skipIf( + pygame.font.get_sdl_ttf_version() < (2, 0, 12), "outlines were added in SDL_TTF 2.0.12" + ) def test_outline(self): self.assertTrue(self.query(outline=1)) From dba644855b8db5acf3943176a046e87896bbdae3 Mon Sep 17 00:00:00 2001 From: Steven Wallace Date: Thu, 2 Oct 2025 08:50:01 -0500 Subject: [PATCH 04/14] Expanded font outline documentation to better explain effects of values. --- docs/reST/ref/font.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/reST/ref/font.rst b/docs/reST/ref/font.rst index b31eeede63..bbd7852055 100644 --- a/docs/reST/ref/font.rst +++ b/docs/reST/ref/font.rst @@ -316,7 +316,8 @@ solves no longer exists, it will likely be removed in the future. When set to 0, the font will be drawn normally. When positive, the text will be drawn as a hollow outline. This can be drawn - underneath unoutlined text to create a text outline effect. + underneath unoutlined text to create a text outline effect. Larger values + produce a thicker outline. Negative values are not valid. .. versionadded:: 2.5.6 From bb8323426504a0310f5a243bd4837befbbe28b66 Mon Sep 17 00:00:00 2001 From: Steven Wallace Date: Thu, 2 Oct 2025 09:05:13 -0500 Subject: [PATCH 05/14] Deduplicated font outline getter and setter logic. --- src_c/font.c | 35 +++++++---------------------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/src_c/font.c b/src_c/font.c index 9bd997b2ed..c04d2eb94a 100644 --- a/src_c/font.c +++ b/src_c/font.c @@ -954,41 +954,20 @@ font_setter_outline(PyObject *self, PyObject *value, void *closure) static PyObject * font_get_outline(PyObject *self, PyObject *_null) { - if (!PgFont_GenerationCheck(self)) { - return RAISE_FONT_QUIT_ERROR(); - } -#if SDL_TTF_VERSION_ATLEAST(2, 0, 12) - TTF_Font *font = PyFont_AsFont(self); - return PyLong_FromLong(TTF_GetFontOutline(font)); -#else - return RAISE(pgExc_SDLError, - "pygame.font not compiled with a new enough SDL_ttf version. " - "Needs SDL_ttf 2.0.12 or above."); -#endif + /* logic is identical to the getter, aside from the closure in the signature */ + return font_getter_outline(self, NULL); } static PyObject * font_set_outline(PyObject *self, PyObject *arg) { - if (!PgFont_GenerationCheck(self)) { - return RAISE_FONT_QUIT_ERROR(); - } -#if SDL_TTF_VERSION_ATLEAST(2, 0, 12) - TTF_Font *font = PyFont_AsFont(self); - long val = PyLong_AsLong(arg); - if (val == -1 && PyErr_Occurred()) { + /* logic is identical to the setter, but we need to massage the return type + from int to PyObject*) */ + if(font_setter_outline(self, arg, NULL) < 0) + { return NULL; } - if (val < 0) { - return RAISE(PyExc_ValueError, "outline must be >= 0"); - } - TTF_SetFontOutline(font, (int)val); - Py_RETURN_NONE; -#else - return RAISE(pgExc_SDLError, - "pygame.font not compiled with a new enough SDL_ttf version. " - "Needs SDL_ttf 2.0.12 or above."); -#endif + return Py_None; } static PyObject * From 7df8039caaf2295fb68260e4af0e9629e88d5a52 Mon Sep 17 00:00:00 2001 From: Steven Wallace Date: Thu, 2 Oct 2025 09:07:06 -0500 Subject: [PATCH 06/14] Font outline code formatting. --- src_c/font.c | 6 +++--- test/font_test.py | 16 ++++++++++------ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src_c/font.c b/src_c/font.c index c04d2eb94a..b22639e894 100644 --- a/src_c/font.c +++ b/src_c/font.c @@ -954,7 +954,8 @@ font_setter_outline(PyObject *self, PyObject *value, void *closure) static PyObject * font_get_outline(PyObject *self, PyObject *_null) { - /* logic is identical to the getter, aside from the closure in the signature */ + /* logic is identical to the getter, aside from the closure in the + * signature */ return font_getter_outline(self, NULL); } @@ -963,8 +964,7 @@ font_set_outline(PyObject *self, PyObject *arg) { /* logic is identical to the setter, but we need to massage the return type from int to PyObject*) */ - if(font_setter_outline(self, arg, NULL) < 0) - { + if (font_setter_outline(self, arg, NULL) < 0) { return NULL; } return Py_None; diff --git a/test/font_test.py b/test/font_test.py index a4b6b7f904..233a855a61 100644 --- a/test/font_test.py +++ b/test/font_test.py @@ -689,7 +689,8 @@ def test_point_size_method(self): self.assertRaises(TypeError, f.set_point_size, "15") @unittest.skipIf( - pygame.font.get_sdl_ttf_version() < (2, 0, 12), "outlines were added in SDL_TTF 2.0.12" + pygame.font.get_sdl_ttf_version() < (2, 0, 12), + "outlines were added in SDL_TTF 2.0.12", ) def test_outline_property(self): if pygame_font.__name__ == "pygame.ftfont": @@ -723,7 +724,8 @@ def test_incorrect_type(): self.assertRaises(TypeError, test_incorrect_type) @unittest.skipIf( - pygame.font.get_sdl_ttf_version() >= (2, 0, 12), "outlines were added in SDL_TTF 2.0.12" + pygame.font.get_sdl_ttf_version() >= (2, 0, 12), + "outlines were added in SDL_TTF 2.0.12", ) def test_outline_property_stub(self): if pygame_font.__name__ == "pygame.ftfont": @@ -740,9 +742,9 @@ def test_outline_property_stub(self): with self.assertRaises(pygame.error): _ = f.outline - @unittest.skipIf( - pygame.font.get_sdl_ttf_version() < (2, 0, 12), "outlines were added in SDL_TTF 2.0.12" + pygame.font.get_sdl_ttf_version() < (2, 0, 12), + "outlines were added in SDL_TTF 2.0.12", ) def test_outline_method(self): if pygame_font.__name__ == "pygame.ftfont": @@ -764,7 +766,8 @@ def test_outline_method(self): self.assertRaises(TypeError, f.set_outline, "2") @unittest.skipIf( - pygame.font.get_sdl_ttf_version() >= (2, 0, 12), "outlines were added in SDL_TTF 2.0.12" + pygame.font.get_sdl_ttf_version() >= (2, 0, 12), + "outlines were added in SDL_TTF 2.0.12", ) def test_outline_method_stub(self): if pygame_font.__name__ == "pygame.ftfont": @@ -1288,7 +1291,8 @@ def test_bold_strikethrough(self): self.assertTrue(self.query(bold=True, strikethrough=True)) @unittest.skipIf( - pygame.font.get_sdl_ttf_version() < (2, 0, 12), "outlines were added in SDL_TTF 2.0.12" + pygame.font.get_sdl_ttf_version() < (2, 0, 12), + "outlines were added in SDL_TTF 2.0.12", ) def test_outline(self): self.assertTrue(self.query(outline=1)) From 3b6077469261631fd5c540402d41853174b97c94 Mon Sep 17 00:00:00 2001 From: Steven Wallace Date: Thu, 2 Oct 2025 09:21:53 -0500 Subject: [PATCH 07/14] Changed return Py_None to Py_RETURN_NONE. --- src_c/font.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src_c/font.c b/src_c/font.c index b22639e894..b4694fabbc 100644 --- a/src_c/font.c +++ b/src_c/font.c @@ -967,7 +967,7 @@ font_set_outline(PyObject *self, PyObject *arg) if (font_setter_outline(self, arg, NULL) < 0) { return NULL; } - return Py_None; + Py_RETURN_NONE; } static PyObject * From 3ae7d367c6e4447cd7c808c1bdea6c13f5e6ecfe Mon Sep 17 00:00:00 2001 From: Steven Wallace Date: Thu, 2 Oct 2025 09:50:55 -0500 Subject: [PATCH 08/14] Changed use of RAISE to PyErr_SetString for consistency. --- src_c/font.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src_c/font.c b/src_c/font.c index b4694fabbc..9a2b7cc513 100644 --- a/src_c/font.c +++ b/src_c/font.c @@ -944,7 +944,7 @@ font_setter_outline(PyObject *self, PyObject *value, void *closure) TTF_SetFontOutline(font, (int)val); return 0; #else - RAISE(pgExc_SDLError, + PyErr_SetString(pgExc_SDLError, "pygame.font not compiled with a new enough SDL_ttf version. Needs " "SDL_ttf 2.0.12 or above."); return -1; From c73ae0292ea5532ee13c883c78839c29aaf9afe1 Mon Sep 17 00:00:00 2001 From: Steven Wallace Date: Thu, 2 Oct 2025 19:20:59 -0500 Subject: [PATCH 09/14] font.c formatting. --- src_c/font.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src_c/font.c b/src_c/font.c index 9a2b7cc513..629da2ceba 100644 --- a/src_c/font.c +++ b/src_c/font.c @@ -944,9 +944,10 @@ font_setter_outline(PyObject *self, PyObject *value, void *closure) TTF_SetFontOutline(font, (int)val); return 0; #else - PyErr_SetString(pgExc_SDLError, - "pygame.font not compiled with a new enough SDL_ttf version. Needs " - "SDL_ttf 2.0.12 or above."); + PyErr_SetString( + pgExc_SDLError, + "pygame.font not compiled with a new enough SDL_ttf version. Needs " + "SDL_ttf 2.0.12 or above."); return -1; #endif } From 16b597627eb16c072cb8569da36497602b59363a Mon Sep 17 00:00:00 2001 From: Steven Wallace Date: Sat, 4 Oct 2025 11:35:07 -0500 Subject: [PATCH 10/14] Removed Font outline getters/setters. Preferring properties for new values. --- buildconfig/stubs/pygame/font.pyi | 2 -- docs/reST/ref/font.rst | 26 ---------------- src_c/doc/font_doc.h | 2 -- src_c/font.c | 21 ------------- test/font_test.py | 50 ++----------------------------- 5 files changed, 2 insertions(+), 99 deletions(-) diff --git a/buildconfig/stubs/pygame/font.pyi b/buildconfig/stubs/pygame/font.pyi index cd096ad7df..77a68f095d 100644 --- a/buildconfig/stubs/pygame/font.pyi +++ b/buildconfig/stubs/pygame/font.pyi @@ -89,8 +89,6 @@ class Font: def set_direction(self, direction: int) -> None: ... def get_point_size(self) -> int: ... def set_point_size(self, val: int, /) -> None: ... - def get_outline(self) -> int: ... - def set_outline(self, val: int, /) -> None: ... @deprecated("Use `Font` instead (FontType is an old alias)") class FontType(Font): ... diff --git a/docs/reST/ref/font.rst b/docs/reST/ref/font.rst index bbd7852055..48caa589f7 100644 --- a/docs/reST/ref/font.rst +++ b/docs/reST/ref/font.rst @@ -579,32 +579,6 @@ solves no longer exists, it will likely be removed in the future. .. ## Font.get_point_size ## - .. method:: set_outline - - | :sl:`set the outline value of the font` - | :sg:`set_outline(size, /) -> None` - - Sets the outline value of the font. - - .. note:: This is the same as the :attr:`outline` attribute. - - .. versionadded:: 2.5.6 - - .. ## Font.set_outline ## - - .. method:: get_outline - - | :sl:`get the outline value of the font` - | :sg:`get_outline() -> int` - - Returns the outline value of the font. - - .. note:: This is the same as the :attr:`outline` attribute. - - .. versionadded:: 2.5.6 - - .. ## Font.get_outline ## - .. method:: get_ascent | :sl:`get the ascent of the font` diff --git a/src_c/doc/font_doc.h b/src_c/doc/font_doc.h index 0adb400947..97a87004fb 100644 --- a/src_c/doc/font_doc.h +++ b/src_c/doc/font_doc.h @@ -34,8 +34,6 @@ #define DOC_FONT_FONT_GETHEIGHT "get_height() -> int\nget the height of the font" #define DOC_FONT_FONT_SETPOINTSIZE "set_point_size(size, /) -> None\nset the point size of the font" #define DOC_FONT_FONT_GETPOINTSIZE "get_point_size() -> int\nget the point size of the font" -#define DOC_FONT_FONT_SETOUTLINE "set_outline(size, /) -> None\nset the outline value of the font" -#define DOC_FONT_FONT_GETOUTLINE "get_outline() -> int\nget the outline value of the font" #define DOC_FONT_FONT_GETASCENT "get_ascent() -> int\nget the ascent of the font" #define DOC_FONT_FONT_GETDESCENT "get_descent() -> int\nget the descent of the font" #define DOC_FONT_FONT_SETSCRIPT "set_script(str, /) -> None\nset the script code for text shaping" diff --git a/src_c/font.c b/src_c/font.c index 629da2ceba..83465bd07c 100644 --- a/src_c/font.c +++ b/src_c/font.c @@ -952,25 +952,6 @@ font_setter_outline(PyObject *self, PyObject *value, void *closure) #endif } -static PyObject * -font_get_outline(PyObject *self, PyObject *_null) -{ - /* logic is identical to the getter, aside from the closure in the - * signature */ - return font_getter_outline(self, NULL); -} - -static PyObject * -font_set_outline(PyObject *self, PyObject *arg) -{ - /* logic is identical to the setter, but we need to massage the return type - from int to PyObject*) */ - if (font_setter_outline(self, arg, NULL) < 0) { - return NULL; - } - Py_RETURN_NONE; -} - static PyObject * font_getter_name(PyObject *self, void *closure) { @@ -1264,8 +1245,6 @@ static PyMethodDef font_methods[] = { DOC_FONT_FONT_GETSTRIKETHROUGH}, {"set_strikethrough", font_set_strikethrough, METH_O, DOC_FONT_FONT_SETSTRIKETHROUGH}, - {"get_outline", font_get_outline, METH_NOARGS, DOC_FONT_FONT_GETOUTLINE}, - {"set_outline", font_set_outline, METH_O, DOC_FONT_FONT_SETOUTLINE}, {"get_point_size", font_get_ptsize, METH_NOARGS, DOC_FONT_FONT_GETPOINTSIZE}, {"set_point_size", font_set_ptsize, METH_O, DOC_FONT_FONT_SETPOINTSIZE}, diff --git a/test/font_test.py b/test/font_test.py index 233a855a61..cb21bac9d7 100644 --- a/test/font_test.py +++ b/test/font_test.py @@ -742,45 +742,6 @@ def test_outline_property_stub(self): with self.assertRaises(pygame.error): _ = f.outline - @unittest.skipIf( - pygame.font.get_sdl_ttf_version() < (2, 0, 12), - "outlines were added in SDL_TTF 2.0.12", - ) - def test_outline_method(self): - if pygame_font.__name__ == "pygame.ftfont": - return # not a pygame.ftfont feature - - pygame_font.init() - font_path = os.path.join( - os.path.split(pygame.__file__)[0], pygame_font.get_default_font() - ) - f = pygame_font.Font(pathlib.Path(font_path), 25) - - val0 = f.get_outline() - self.assertIsInstance(val0, int) - self.assertGreaterEqual(val0, 0) - - f.set_outline(5) - self.assertEqual(5, f.get_outline()) - self.assertRaises(ValueError, f.set_outline, -1) - self.assertRaises(TypeError, f.set_outline, "2") - - @unittest.skipIf( - pygame.font.get_sdl_ttf_version() >= (2, 0, 12), - "outlines were added in SDL_TTF 2.0.12", - ) - def test_outline_method_stub(self): - if pygame_font.__name__ == "pygame.ftfont": - return # not a pygame.ftfont feature - - pygame_font.init() - font_path = os.path.join( - os.path.split(pygame.__file__)[0], pygame_font.get_default_font() - ) - f = pygame_font.Font(pathlib.Path(font_path), 25) - - self.assertRaises(pygame.error, f.get_outline) - self.assertRaises(pygame.error, f.set_outline, 1) def test_font_name(self): f = pygame_font.Font(None, 20) @@ -1031,13 +992,6 @@ def test_font_method_should_raise_exception_after_quit(self): skip_methods = set() version = pygame.font.get_sdl_ttf_version() - if version >= (2, 0, 12): - methods.append(("get_outline", ())) - methods.append(("set_outline", (2,))) - else: - skip_methods.add("get_outline") - skip_methods.add("set_outline") - if version >= (2, 0, 18): methods.append(("get_point_size", ())) methods.append(("set_point_size", (34,))) @@ -1239,7 +1193,7 @@ def query( f.set_underline(underline) f.set_strikethrough(strikethrough) if pygame.font.get_sdl_ttf_version() >= (2, 0, 12): - f.set_outline(outline) + f.outline = outline s = f.render(text, antialiase, (0, 0, 0)) screen.blit(s, (offset, y)) y += s.get_size()[1] + spacing @@ -1248,7 +1202,7 @@ def query( f.set_underline(False) f.set_strikethrough(False) if pygame.font.get_sdl_ttf_version() >= (2, 0, 12): - f.set_outline(0) + f.outline = 0 s = f.render("(some comparison text)", False, (0, 0, 0)) screen.blit(s, (offset, y)) pygame.display.flip() From 8eac437a674292cc145309cedb217c59a2ce667a Mon Sep 17 00:00:00 2001 From: Steven Wallace Date: Sat, 4 Oct 2025 12:36:17 -0500 Subject: [PATCH 11/14] font test formatting fix. --- test/font_test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/font_test.py b/test/font_test.py index cb21bac9d7..0ef1e1afc5 100644 --- a/test/font_test.py +++ b/test/font_test.py @@ -742,7 +742,6 @@ def test_outline_property_stub(self): with self.assertRaises(pygame.error): _ = f.outline - def test_font_name(self): f = pygame_font.Font(None, 20) self.assertEqual(f.name, "FreeSans") From fc71ffaa38e0ec011557ad55faa979230e8e7650 Mon Sep 17 00:00:00 2001 From: Steven Wallace Date: Sun, 12 Oct 2025 09:00:10 -0500 Subject: [PATCH 12/14] Removed checks for SDL_TTF < 2.0.12 in outline code. We depend on SDL_TTF >= 2.0.15, so this is not needed. --- src_c/font.c | 26 ++++++++------------------ test/font_test.py | 39 +++------------------------------------ 2 files changed, 11 insertions(+), 54 deletions(-) diff --git a/src_c/font.c b/src_c/font.c index 83465bd07c..c28cb0d94a 100644 --- a/src_c/font.c +++ b/src_c/font.c @@ -908,14 +908,8 @@ font_getter_outline(PyObject *self, void *closure) return RAISE_FONT_QUIT_ERROR(); } -#if SDL_TTF_VERSION_ATLEAST(2, 0, 12) TTF_Font *font = PyFont_AsFont(self); return PyLong_FromLong(TTF_GetFontOutline(font)); -#else - return RAISE(pgExc_SDLError, - "pygame.font not compiled with a new enough SDL_ttf version. " - "Needs SDL_ttf 2.0.12 or above."); -#endif } static int @@ -924,15 +918,10 @@ font_setter_outline(PyObject *self, PyObject *value, void *closure) if (!PgFont_GenerationCheck(self)) { RAISE_FONT_QUIT_ERROR_RETURN(-1); } -#if SDL_TTF_VERSION_ATLEAST(2, 0, 12) TTF_Font *font = PyFont_AsFont(self); DEL_ATTR_NOT_SUPPORTED_CHECK("outline", value); - if (!PyLong_Check(value)) { - PyErr_SetString(PyExc_TypeError, "outline must be an integer"); - return -1; - } long val = PyLong_AsLong(value); if (val == -1 && PyErr_Occurred()) { return -1; @@ -941,15 +930,16 @@ font_setter_outline(PyObject *self, PyObject *value, void *closure) PyErr_SetString(PyExc_ValueError, "outline must be >= 0"); return -1; } - TTF_SetFontOutline(font, (int)val); - return 0; + +#if SDL_TTF_VERSION_ATLEAST(3, 0, 0) + if (!TTF_SetFontOutline(font, (int)val)) { + PyErr_SetString(pgExc_SDLError, SDL_GetError()); + return -1; + } #else - PyErr_SetString( - pgExc_SDLError, - "pygame.font not compiled with a new enough SDL_ttf version. Needs " - "SDL_ttf 2.0.12 or above."); - return -1; + TTF_SetFontOutline(font, (int)val); #endif + return 0; } static PyObject * diff --git a/test/font_test.py b/test/font_test.py index 0ef1e1afc5..152b7d45f9 100644 --- a/test/font_test.py +++ b/test/font_test.py @@ -688,10 +688,6 @@ def test_point_size_method(self): self.assertRaises(ValueError, f.set_point_size, -500) self.assertRaises(TypeError, f.set_point_size, "15") - @unittest.skipIf( - pygame.font.get_sdl_ttf_version() < (2, 0, 12), - "outlines were added in SDL_TTF 2.0.12", - ) def test_outline_property(self): if pygame_font.__name__ == "pygame.ftfont": return # not a pygame.ftfont feature @@ -723,25 +719,6 @@ def test_incorrect_type(): self.assertRaises(ValueError, test_neg) self.assertRaises(TypeError, test_incorrect_type) - @unittest.skipIf( - pygame.font.get_sdl_ttf_version() >= (2, 0, 12), - "outlines were added in SDL_TTF 2.0.12", - ) - def test_outline_property_stub(self): - if pygame_font.__name__ == "pygame.ftfont": - return # not a pygame.ftfont feature - - pygame_font.init() - font_path = os.path.join( - os.path.split(pygame.__file__)[0], pygame_font.get_default_font() - ) - f = pygame_font.Font(pathlib.Path(font_path), 25) - - with self.assertRaises(pygame.error): - f.outline = 0 - with self.assertRaises(pygame.error): - _ = f.outline - def test_font_name(self): f = pygame_font.Font(None, 20) self.assertEqual(f.name, "FreeSans") @@ -1078,6 +1055,7 @@ def test_font_property_should_raise_exception_after_quit(self): ("italic", True), ("underline", True), ("strikethrough", True), + ("outline", 1), ] skip_properties = set() version = pygame.font.get_sdl_ttf_version() @@ -1090,11 +1068,6 @@ def test_font_property_should_raise_exception_after_quit(self): else: skip_properties.add("point_size") - if version >= (2, 0, 12): - properties.append(("outline", 1)) - else: - skip_properties.add("outline") - font = pygame_font.Font(None, 10) actual_names = [] @@ -1191,8 +1164,7 @@ def query( f.set_italic(italic) f.set_underline(underline) f.set_strikethrough(strikethrough) - if pygame.font.get_sdl_ttf_version() >= (2, 0, 12): - f.outline = outline + f.outline = outline s = f.render(text, antialiase, (0, 0, 0)) screen.blit(s, (offset, y)) y += s.get_size()[1] + spacing @@ -1200,8 +1172,7 @@ def query( f.set_italic(False) f.set_underline(False) f.set_strikethrough(False) - if pygame.font.get_sdl_ttf_version() >= (2, 0, 12): - f.outline = 0 + f.outline = 0 s = f.render("(some comparison text)", False, (0, 0, 0)) screen.blit(s, (offset, y)) pygame.display.flip() @@ -1243,10 +1214,6 @@ def test_italic_underline(self): def test_bold_strikethrough(self): self.assertTrue(self.query(bold=True, strikethrough=True)) - @unittest.skipIf( - pygame.font.get_sdl_ttf_version() < (2, 0, 12), - "outlines were added in SDL_TTF 2.0.12", - ) def test_outline(self): self.assertTrue(self.query(outline=1)) From c6e377a6a5af6b5f291eb602ea5265ab65efad97 Mon Sep 17 00:00:00 2001 From: Steven Wallace Date: Sun, 12 Oct 2025 09:02:58 -0500 Subject: [PATCH 13/14] Improved font outline docs. Specify that the thickness is in pixels, and added example to render outlined text. --- docs/reST/ref/font.rst | 29 +++++++++++++++++++++++++---- src_c/doc/font_doc.h | 2 +- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/docs/reST/ref/font.rst b/docs/reST/ref/font.rst index 48caa589f7..7f830e73bd 100644 --- a/docs/reST/ref/font.rst +++ b/docs/reST/ref/font.rst @@ -309,15 +309,36 @@ solves no longer exists, it will likely be removed in the future. .. attribute:: outline - | :sl:`Gets or sets the font's outline value` + | :sl:`Gets or sets the font's outline thickness (pixels)` | :sg:`outline -> int` The outline value of the font. When set to 0, the font will be drawn normally. When positive, - the text will be drawn as a hollow outline. This can be drawn - underneath unoutlined text to create a text outline effect. Larger values - produce a thicker outline. Negative values are not valid. + the text will be drawn as a hollow outline. The outline grows in all + directions a number of pixels equal to the value set. Negative values + are not allowed. + + This can be drawn underneath unoutlined text to create a text outline + effect. For example: :: + + def render_outlined( + font: pygame.Font, + text: str, + text_color: pygame.typing.ColorLike, + outline_color: pygame.typing.ColorLike, + outline_width: int, + ) -> pygame.Surface: + old_outline = font.outline + if old_outline != 0: + font.outline = 0 + base_text_surf = font.render(text, True, text_color) + font.outline = outline_width + outlined_text_surf = font.render(text, True, outline_color) + + outlined_text_surf.blit(base_text_surf, (outline_width, outline_width)) + font.outline = old_outline + return outlined_text_surf .. versionadded:: 2.5.6 diff --git a/src_c/doc/font_doc.h b/src_c/doc/font_doc.h index 97a87004fb..b100ce3a65 100644 --- a/src_c/doc/font_doc.h +++ b/src_c/doc/font_doc.h @@ -17,7 +17,7 @@ #define DOC_FONT_FONT_STRIKETHROUGH "strikethrough -> bool\nGets or sets whether the font should be rendered with a strikethrough." #define DOC_FONT_FONT_ALIGN "align -> int\nSet how rendered text is aligned when given a wrap length." #define DOC_FONT_FONT_POINTSIZE "point_size -> int\nGets or sets the font's point size" -#define DOC_FONT_FONT_OUTLINE "outline -> int\nGets or sets the font's outline value" +#define DOC_FONT_FONT_OUTLINE "outline -> int\nGets or sets the font's outline thickness (pixels)" #define DOC_FONT_FONT_RENDER "render(text, antialias, color, bgcolor=None, wraplength=0) -> Surface\ndraw text on a new Surface" #define DOC_FONT_FONT_SIZE "size(text, /) -> (width, height)\ndetermine the amount of space needed to render text" #define DOC_FONT_FONT_SETUNDERLINE "set_underline(bool, /) -> None\ncontrol if text is rendered with an underline" From d098f2b0f7213085721cb64ac50af19499f118bf Mon Sep 17 00:00:00 2001 From: Steven Wallace Date: Sun, 2 Nov 2025 13:35:57 -0600 Subject: [PATCH 14/14] Updated version note for Font.outline to 2.5.7. 2.5.6 released while this was still in review. --- docs/reST/ref/font.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reST/ref/font.rst b/docs/reST/ref/font.rst index 7f830e73bd..ba3df6577a 100644 --- a/docs/reST/ref/font.rst +++ b/docs/reST/ref/font.rst @@ -340,7 +340,7 @@ solves no longer exists, it will likely be removed in the future. font.outline = old_outline return outlined_text_surf - .. versionadded:: 2.5.6 + .. versionadded:: 2.5.7 .. ## Font.outline ##