From df64d50c8406298de0430c20c88d78199f3811cb Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Thu, 26 Sep 2024 18:33:00 -0700
Subject: [PATCH] Made SDL_Init(), SDL_Quit(), and TTF_OpenFont*() thread-safe.
Also documented the thread-safety of other API functions.
Fixes https://github.com/libsdl-org/SDL_ttf/issues/28
---
external/SDL | 2 +-
include/SDL3_ttf/SDL_ttf.h | 108 +++++++++++++++++++++++++-
src/SDL_ttf.c | 150 +++++++++++++++++++++++++++----------
3 files changed, 220 insertions(+), 40 deletions(-)
diff --git a/external/SDL b/external/SDL
index 53bf2baa..d8c76d2f 160000
--- a/external/SDL
+++ b/external/SDL
@@ -1 +1 @@
-Subproject commit 53bf2baac3ca32f49c62963a15e6140c696a33cf
+Subproject commit d8c76d2f348b1521e55ad73bb155470d63ee1b75
diff --git a/include/SDL3_ttf/SDL_ttf.h b/include/SDL3_ttf/SDL_ttf.h
index bba1cc09..c983240e 100644
--- a/include/SDL3_ttf/SDL_ttf.h
+++ b/include/SDL3_ttf/SDL_ttf.h
@@ -70,6 +70,8 @@ extern "C" {
*
* \returns SDL_ttf version.
*
+ * \threadsafety It is safe to call this function from any thread.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*/
extern SDL_DECLSPEC int SDLCALL TTF_Version(void);
@@ -83,6 +85,8 @@ extern SDL_DECLSPEC int SDLCALL TTF_Version(void);
* \param minor to be filled in with the minor version number. Can be NULL.
* \param patch to be filled in with the param version number. Can be NULL.
*
+ * \threadsafety It is safe to call this function from any thread.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_Init
@@ -98,6 +102,8 @@ extern SDL_DECLSPEC void SDLCALL TTF_GetFreeTypeVersion(int *major, int *minor,
* \param minor to be filled in with the minor version number. Can be NULL.
* \param patch to be filled in with the param version number. Can be NULL.
*
+ * \threadsafety It is safe to call this function from any thread.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*/
extern SDL_DECLSPEC void SDLCALL TTF_GetHarfBuzzVersion(int *major, int *minor, int *patch);
@@ -146,6 +152,8 @@ extern SDL_DECLSPEC bool SDLCALL TTF_Init(void);
* \returns a valid TTF_Font, or NULL on failure; call SDL_GetError() for more
* information.
*
+ * \threadsafety It is safe to call this function from any thread.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_CloseFont
@@ -171,6 +179,8 @@ extern SDL_DECLSPEC TTF_Font * SDLCALL TTF_OpenFont(const char *file, int ptsize
* \returns a valid TTF_Font, or NULL on failure; call SDL_GetError() for more
* information.
*
+ * \threadsafety It is safe to call this function from any thread.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_CloseFont
@@ -207,6 +217,8 @@ extern SDL_DECLSPEC TTF_Font * SDLCALL TTF_OpenFontIO(SDL_IOStream *src, bool cl
* \returns a valid TTF_Font, or NULL on failure; call SDL_GetError() for more
* information.
*
+ * \threadsafety It is safe to call this function from any thread.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_CloseFont
@@ -231,6 +243,8 @@ extern SDL_DECLSPEC TTF_Font * SDLCALL TTF_OpenFontWithProperties(SDL_Properties
* \returns true on success or false on failure; call SDL_GetError() for more
* information.
*
+ * \threadsafety This function should be called on the thread that created the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*/
extern SDL_DECLSPEC bool SDLCALL TTF_SetFontSize(TTF_Font *font, int ptsize);
@@ -247,6 +261,8 @@ extern SDL_DECLSPEC bool SDLCALL TTF_SetFontSize(TTF_Font *font, int ptsize);
* \returns true on success or false on failure; call SDL_GetError() for more
* information.
*
+ * \threadsafety This function should be called on the thread that created the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*/
extern SDL_DECLSPEC bool SDLCALL TTF_SetFontSizeDPI(TTF_Font *font, int ptsize, unsigned int hdpi, unsigned int vdpi);
@@ -274,6 +290,8 @@ extern SDL_DECLSPEC bool SDLCALL TTF_SetFontSizeDPI(TTF_Font *font, int ptsize,
* \param font the font to query.
* \returns the current font style, as a set of bit flags.
*
+ * \threadsafety It is safe to call this function from any thread.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_SetFontStyle
@@ -296,6 +314,8 @@ extern SDL_DECLSPEC int SDLCALL TTF_GetFontStyle(const TTF_Font *font);
* \param font the font to set a new style on.
* \param style the new style values to set, OR'd together.
*
+ * \threadsafety This function should be called on the thread that created the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_GetFontStyle
@@ -308,6 +328,8 @@ extern SDL_DECLSPEC void SDLCALL TTF_SetFontStyle(TTF_Font *font, int style);
* \param font the font to query.
* \returns the font's current outline value.
*
+ * \threadsafety It is safe to call this function from any thread.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_SetFontOutline
@@ -319,12 +341,16 @@ extern SDL_DECLSPEC int SDLCALL TTF_GetFontOutline(const TTF_Font *font);
*
* \param font the font to set a new outline on.
* \param outline positive outline value, 0 to default.
+ * \returns true on success or false on failure; call SDL_GetError() for more
+ * information.
+ *
+ * \threadsafety This function should be called on the thread that created the font.
*
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_GetFontOutline
*/
-extern SDL_DECLSPEC void SDLCALL TTF_SetFontOutline(TTF_Font *font, int outline);
+extern SDL_DECLSPEC bool SDLCALL TTF_SetFontOutline(TTF_Font *font, int outline);
/**
@@ -350,6 +376,8 @@ extern SDL_DECLSPEC void SDLCALL TTF_SetFontOutline(TTF_Font *font, int outline)
* \param font the font to query.
* \returns the font's current hinter value.
*
+ * \threadsafety It is safe to call this function from any thread.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_SetFontHinting
@@ -372,6 +400,8 @@ extern SDL_DECLSPEC int SDLCALL TTF_GetFontHinting(const TTF_Font *font);
* \param font the font to set a new hinter setting on.
* \param hinting the new hinter setting.
*
+ * \threadsafety This function should be called on the thread that created the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_GetFontHinting
@@ -397,6 +427,8 @@ extern SDL_DECLSPEC void SDLCALL TTF_SetFontHinting(TTF_Font *font, int hinting)
* \param font the font to query.
* \returns the font's current wrap alignment option.
*
+ * \threadsafety It is safe to call this function from any thread.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_SetFontWrappedAlign
@@ -415,6 +447,8 @@ extern SDL_DECLSPEC int SDLCALL TTF_GetFontWrappedAlign(const TTF_Font *font);
* \param font the font to set a new wrap alignment option on.
* \param align the new wrap alignment option.
*
+ * \threadsafety This function should be called on the thread that created the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_GetFontWrappedAlign
@@ -429,6 +463,8 @@ extern SDL_DECLSPEC void SDLCALL TTF_SetFontWrappedAlign(TTF_Font *font, int ali
* \param font the font to query.
* \returns the font's height.
*
+ * \threadsafety It is safe to call this function from any thread.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*/
extern SDL_DECLSPEC int SDLCALL TTF_FontHeight(const TTF_Font *font);
@@ -441,6 +477,8 @@ extern SDL_DECLSPEC int SDLCALL TTF_FontHeight(const TTF_Font *font);
* \param font the font to query.
* \returns the font's ascent.
*
+ * \threadsafety It is safe to call this function from any thread.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*/
extern SDL_DECLSPEC int SDLCALL TTF_FontAscent(const TTF_Font *font);
@@ -453,6 +491,8 @@ extern SDL_DECLSPEC int SDLCALL TTF_FontAscent(const TTF_Font *font);
* \param font the font to query.
* \returns the font's descent.
*
+ * \threadsafety It is safe to call this function from any thread.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*/
extern SDL_DECLSPEC int SDLCALL TTF_FontDescent(const TTF_Font *font);
@@ -463,6 +503,8 @@ extern SDL_DECLSPEC int SDLCALL TTF_FontDescent(const TTF_Font *font);
* \param font the font to query.
* \returns the font's recommended spacing.
*
+ * \threadsafety It is safe to call this function from any thread.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*/
extern SDL_DECLSPEC int SDLCALL TTF_FontLineSkip(const TTF_Font *font);
@@ -473,6 +515,8 @@ extern SDL_DECLSPEC int SDLCALL TTF_FontLineSkip(const TTF_Font *font);
* \param font the font to query.
* \returns true if kerning is enabled, false otherwise.
*
+ * \threadsafety It is safe to call this function from any thread.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*/
extern SDL_DECLSPEC bool SDLCALL TTF_GetFontKerning(const TTF_Font *font);
@@ -488,6 +532,8 @@ extern SDL_DECLSPEC bool SDLCALL TTF_GetFontKerning(const TTF_Font *font);
* \param font the font to set kerning on.
* \param enabled true to enable kerning, false to disable.
*
+ * \threadsafety This function should be called on the thread that created the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*/
extern SDL_DECLSPEC void SDLCALL TTF_SetFontKerning(TTF_Font *font, bool enabled);
@@ -498,6 +544,8 @@ extern SDL_DECLSPEC void SDLCALL TTF_SetFontKerning(TTF_Font *font, bool enabled
* \param font the font to query.
* \returns the number of FreeType font faces.
*
+ * \threadsafety It is safe to call this function from any thread.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*/
extern SDL_DECLSPEC long SDLCALL TTF_FontFaces(const TTF_Font *font);
@@ -514,6 +562,8 @@ extern SDL_DECLSPEC long SDLCALL TTF_FontFaces(const TTF_Font *font);
* \param font the font to query.
* \returns true if the font is fixed-width, false otherwise.
*
+ * \threadsafety It is safe to call this function from any thread.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*/
extern SDL_DECLSPEC bool SDLCALL TTF_FontFaceIsFixedWidth(const TTF_Font *font);
@@ -530,6 +580,8 @@ extern SDL_DECLSPEC bool SDLCALL TTF_FontFaceIsFixedWidth(const TTF_Font *font);
* \param font the font to query.
* \returns the font's family name.
*
+ * \threadsafety It is safe to call this function from any thread.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*/
extern SDL_DECLSPEC const char * SDLCALL TTF_FontFaceFamilyName(const TTF_Font *font);
@@ -546,6 +598,8 @@ extern SDL_DECLSPEC const char * SDLCALL TTF_FontFaceFamilyName(const TTF_Font *
* \param font the font to query.
* \returns the font's style name.
*
+ * \threadsafety It is safe to call this function from any thread.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*/
extern SDL_DECLSPEC const char * SDLCALL TTF_FontFaceStyleName(const TTF_Font *font);
@@ -557,6 +611,8 @@ extern SDL_DECLSPEC const char * SDLCALL TTF_FontFaceStyleName(const TTF_Font *f
* \param ch the character code to check.
* \returns true if font provides a glyph for this character, false if not.
*
+ * \threadsafety This function should be called on the thread that created the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*/
extern SDL_DECLSPEC bool SDLCALL TTF_GlyphIsProvided(TTF_Font *font, Uint32 ch);
@@ -585,6 +641,8 @@ extern SDL_DECLSPEC bool SDLCALL TTF_GlyphIsProvided(TTF_Font *font, Uint32 ch);
* \returns true on success or false on failure; call SDL_GetError() for more
* information.
*
+ * \threadsafety This function should be called on the thread that created the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*/
extern SDL_DECLSPEC bool SDLCALL TTF_GlyphMetrics(TTF_Font *font, Uint32 ch, int *minx, int *maxx, int *miny, int *maxy, int *advance);
@@ -606,6 +664,8 @@ extern SDL_DECLSPEC bool SDLCALL TTF_GlyphMetrics(TTF_Font *font, Uint32 ch, int
* \returns true on success or false on failure; call SDL_GetError() for more
* information.
*
+ * \threadsafety This function should be called on the thread that created the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*/
extern SDL_DECLSPEC bool SDLCALL TTF_SizeText(TTF_Font *font, const char *text, size_t length, int *w, int *h);
@@ -629,6 +689,8 @@ extern SDL_DECLSPEC bool SDLCALL TTF_SizeText(TTF_Font *font, const char *text,
* \returns true on success or false on failure; call SDL_GetError() for more
* information.
*
+ * \threadsafety This function should be called on the thread that created the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*/
extern SDL_DECLSPEC bool SDLCALL TTF_MeasureText(TTF_Font *font, const char *text, size_t length, int measure_width, int *extent, int *count);
@@ -657,6 +719,8 @@ extern SDL_DECLSPEC bool SDLCALL TTF_MeasureText(TTF_Font *font, const char *tex
* \param fg the foreground color for the text.
* \returns a new 8-bit, palettized surface, or NULL if there was an error.
*
+ * \threadsafety This function should be called on the thread that created the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_RenderText_Blended
@@ -691,6 +755,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Solid(TTF_Font *font, c
* newline characters.
* \returns a new 8-bit, palettized surface, or NULL if there was an error.
*
+ * \threadsafety This function should be called on the thread that created the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_RenderText_Blended_Wrapped
@@ -718,6 +784,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Solid_Wrapped(TTF_Font
* \param fg the foreground color for the text.
* \returns a new 8-bit, palettized surface, or NULL if there was an error.
*
+ * \threadsafety This function should be called on the thread that created the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_RenderGlyph_Blended
@@ -752,6 +820,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderGlyph_Solid(TTF_Font *font,
* \param bg the background color for the text.
* \returns a new 8-bit, palettized surface, or NULL if there was an error.
*
+ * \threadsafety This function should be called on the thread that created the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_RenderText_Blended
@@ -787,6 +857,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Shaded(TTF_Font *font,
* newline characters.
* \returns a new 8-bit, palettized surface, or NULL if there was an error.
*
+ * \threadsafety This function should be called on the thread that created the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_RenderText_Blended_Wrapped
@@ -816,6 +888,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Shaded_Wrapped(TTF_Font
* \param bg the background color for the text.
* \returns a new 8-bit, palettized surface, or NULL if there was an error.
*
+ * \threadsafety This function should be called on the thread that created the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_RenderGlyph_Blended
@@ -848,6 +922,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderGlyph_Shaded(TTF_Font *font,
* \param fg the foreground color for the text.
* \returns a new 32-bit, ARGB surface, or NULL if there was an error.
*
+ * \threadsafety This function should be called on the thread that created the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_RenderText_Blended_Wrapped
@@ -881,6 +957,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Blended(TTF_Font *font,
* newline characters.
* \returns a new 32-bit, ARGB surface, or NULL if there was an error.
*
+ * \threadsafety This function should be called on the thread that created the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_RenderText_Blended
@@ -908,6 +986,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Blended_Wrapped(TTF_Fon
* \param fg the foreground color for the text.
* \returns a new 32-bit, ARGB surface, or NULL if there was an error.
*
+ * \threadsafety This function should be called on the thread that created the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_RenderGlyph_LCD
@@ -941,6 +1021,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderGlyph_Blended(TTF_Font *font
* \param bg the background color for the text.
* \returns a new 32-bit, ARGB surface, or NULL if there was an error.
*
+ * \threadsafety This function should be called on the thread that created the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_RenderText_Blended
@@ -976,6 +1058,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_LCD(TTF_Font *font, con
* newline characters.
* \returns a new 32-bit, ARGB surface, or NULL if there was an error.
*
+ * \threadsafety This function should be called on the thread that created the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_RenderText_Blended_Wrapped
@@ -1004,6 +1088,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_LCD_Wrapped(TTF_Font *f
* \param bg the background color for the text.
* \returns a new 32-bit, ARGB surface, or NULL if there was an error.
*
+ * \threadsafety This function should be called on the thread that created the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_RenderGlyph_Blended
@@ -1027,6 +1113,8 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderGlyph_LCD(TTF_Font *font, Ui
*
* \param font the font to dispose of.
*
+ * \threadsafety This function should not be called while any other thread is using the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_OpenFont
@@ -1057,6 +1145,8 @@ extern SDL_DECLSPEC void SDLCALL TTF_CloseFont(TTF_Font *font);
* deal with it. A well-written program should call TTF_CloseFont() on any
* open fonts before calling this function!
*
+ * \threadsafety It is safe to call this function from any thread.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*/
extern SDL_DECLSPEC void SDLCALL TTF_Quit(void);
@@ -1076,6 +1166,8 @@ extern SDL_DECLSPEC void SDLCALL TTF_Quit(void);
* \returns the current number of initialization calls, that need to
* eventually be paired with this many calls to TTF_Quit().
*
+ * \threadsafety It is safe to call this function from any thread.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_Init
@@ -1091,6 +1183,8 @@ extern SDL_DECLSPEC int SDLCALL TTF_WasInit(void);
* \param ch the current character's code, 32 bits.
* \returns The kerning size between the two specified characters, in pixels, or -1 on failure; call SDL_GetError() for more information.
*
+ * \threadsafety This function should be called on the thread that created the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*/
extern SDL_DECLSPEC int TTF_GetFontKerningSizeGlyphs(TTF_Font *font, Uint32 previous_ch, Uint32 ch);
@@ -1108,6 +1202,8 @@ extern SDL_DECLSPEC int TTF_GetFontKerningSizeGlyphs(TTF_Font *font, Uint32 prev
* \returns true on success or false on failure; call SDL_GetError()
* for more information.
*
+ * \threadsafety This function should be called on the thread that created the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_GetFontSDF
@@ -1121,6 +1217,8 @@ extern SDL_DECLSPEC bool TTF_SetFontSDF(TTF_Font *font, bool enabled);
*
* \returns true if enabled, false otherwise.
*
+ * \threadsafety It is safe to call this function from any thread.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_SetFontSDF
@@ -1157,6 +1255,8 @@ typedef enum TTF_Direction
* \returns true on success or false on failure; call SDL_GetError() for more
* information.
*
+ * \threadsafety This function should be called on the thread that created the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*/
extern SDL_DECLSPEC bool SDLCALL TTF_SetFontDirection(TTF_Font *font, TTF_Direction direction);
@@ -1174,6 +1274,8 @@ extern SDL_DECLSPEC bool SDLCALL TTF_SetFontDirection(TTF_Font *font, TTF_Direct
* \returns true on success or false on failure; call SDL_GetError() for more
* information.
*
+ * \threadsafety This function should be called on the thread that created the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*/
extern SDL_DECLSPEC bool SDLCALL TTF_SetFontScriptName(TTF_Font *font, const char *script);
@@ -1188,6 +1290,8 @@ extern SDL_DECLSPEC bool SDLCALL TTF_SetFontScriptName(TTF_Font *font, const cha
* \returns true on success or false on failure; call SDL_GetError()
* for more information.
*
+ * \threadsafety This function should be called on the thread that created the font.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*/
extern SDL_DECLSPEC bool TTF_SetFontLanguage(TTF_Font *font, const char *language_bcp47);
@@ -1201,6 +1305,8 @@ extern SDL_DECLSPEC bool TTF_SetFontLanguage(TTF_Font *font, const char *languag
*
* \returns true if the font is scalable, false otherwise.
*
+ * \threadsafety It is safe to call this function from any thread.
+ *
* \since This function is available since SDL_ttf 3.0.0.
*
* \sa TTF_SetFontSDF
diff --git a/src/SDL_ttf.c b/src/SDL_ttf.c
index dda31b4e..5606dab7 100644
--- a/src/SDL_ttf.c
+++ b/src/SDL_ttf.c
@@ -232,6 +232,7 @@ struct TTF_Font {
/* The font style */
int style;
int outline_val;
+ FT_Stroker stroker;
/* Whether kerning is desired */
bool enable_kerning;
@@ -289,11 +290,17 @@ struct TTF_Font {
#define TTF_STYLE_NO_GLYPH_CHANGE (TTF_STYLE_UNDERLINE | TTF_STYLE_STRIKETHROUGH)
/* The FreeType font engine/library */
-static FT_Library library = NULL;
-static int TTF_initialized = 0;
+static struct
+{
+ SDL_InitState init;
+ SDL_AtomicInt refcount;
+ SDL_Mutex *lock;
+ FT_Library library;
+} TTF_state;
#define TTF_CHECK_INITIALIZED(errval) \
- if (!TTF_initialized) { \
+ if (SDL_ShouldInit(&TTF_state.init)) { \
+ SDL_SetInitialized(&TTF_state.init, false); \
SDL_SetError("Library not initialized"); \
return errval; \
}
@@ -1660,32 +1667,61 @@ bool TTF_Init(void)
SDL_Log("Sizeof TTF_Image: %d c_glyph: %d TTF_Font: %d", sizeof (TTF_Image), sizeof (c_glyph), sizeof (TTF_Font));
#endif
- if (!TTF_initialized) {
- FT_Error error = FT_Init_FreeType(&library);
- if (error) {
- result = TTF_SetFTError("Couldn't init FreeType engine", error);
- }
+ SDL_AtomicIncRef(&TTF_state.refcount);
+
+ if (!SDL_ShouldInit(&TTF_state.init)) {
+ return true;
}
+
+ FT_Error error = FT_Init_FreeType(&TTF_state.library);
+ if (error) {
+ TTF_SetFTError("Couldn't init FreeType engine", error);
+ result = false;
+ }
+
if (result) {
- ++TTF_initialized;
#if TTF_USE_SDF
-# if 0
+#if 0
/* Set various properties of the renderers. */
int spread = 4;
int overlaps = 0;
- FT_Property_Set( library, "bsdf", "spread", &spread);
- FT_Property_Set( library, "sdf", "spread", &spread);
- FT_Property_Set( library, "sdf", "overlaps", &overlaps);
-# endif
+ FT_Property_Set(TTF_state.library, "bsdf", "spread", &spread);
+ FT_Property_Set(TTF_state.library, "sdf", "spread", &spread);
+ FT_Property_Set(TTF_state.library, "sdf", "overlaps", &overlaps);
+#endif
#endif
+ TTF_state.lock = SDL_CreateMutex();
+ } else {
+ (void)SDL_AtomicDecRef(&TTF_state.refcount);
}
+ SDL_SetInitialized(&TTF_state.init, result);
+
return result;
}
-SDL_COMPILE_TIME_ASSERT(FT_Int, sizeof(int) == sizeof(FT_Int)); /* just in case. */
void TTF_GetFreeTypeVersion(int *major, int *minor, int *patch)
{
- FT_Library_Version(library, major, minor, patch);
+ FT_Int ft_major = 0;
+ FT_Int ft_minor = 0;
+ FT_Int ft_patch = 0;
+
+ if (SDL_ShouldInit(&TTF_state.init)) {
+ SDL_SetInitialized(&TTF_state.init, false);
+ } else {
+ SDL_LockMutex(TTF_state.lock);
+ FT_Library_Version(TTF_state.library, &ft_major, &ft_minor, &ft_patch);
+ SDL_UnlockMutex(TTF_state.lock);
+ }
+
+ if (major) {
+ *major = (int)ft_major;
+ }
+ if (minor) {
+ *minor = (int)ft_minor;
+ }
+ if (patch) {
+ *patch = (int)ft_patch;
+ }
}
void TTF_GetHarfBuzzVersion(int *major, int *minor, int *patch)
@@ -1719,7 +1755,7 @@ static unsigned long IOread(
src = (SDL_IOStream *)stream->descriptor.pointer;
SDL_SeekIO(src, offset, SDL_IO_SEEK_SET);
- return SDL_ReadIO(src, buffer, count);
+ return (unsigned long)SDL_ReadIO(src, buffer, count);
}
TTF_Font *TTF_OpenFontWithProperties(SDL_PropertiesID props)
@@ -1739,7 +1775,8 @@ TTF_Font *TTF_OpenFontWithProperties(SDL_PropertiesID props)
Sint64 position;
int i;
- if (!TTF_initialized) {
+ if (SDL_ShouldInit(&TTF_state.init)) {
+ SDL_SetInitialized(&TTF_state.init, false);
SDL_SetError("Library not initialized");
if (src && closeio) {
SDL_CloseIO(src);
@@ -1799,7 +1836,9 @@ TTF_Font *TTF_OpenFontWithProperties(SDL_PropertiesID props)
font->args.flags = FT_OPEN_STREAM;
font->args.stream = stream;
- error = FT_Open_Face(library, &font->args, index, &font->face);
+ SDL_LockMutex(TTF_state.lock);
+ error = FT_Open_Face(TTF_state.library, &font->args, index, &font->face);
+ SDL_UnlockMutex(TTF_state.lock);
if (error || font->face == NULL) {
TTF_SetFTError("Couldn't load font file", error);
TTF_CloseFont(font);
@@ -2203,8 +2242,8 @@ static FT_Error Load_Glyph(TTF_Font *font, c_glyph *cached, int want, int transl
}
/* Render as outline */
- if ((font->outline_val > 0 && slot->format == FT_GLYPH_FORMAT_OUTLINE)
- || slot->format == FT_GLYPH_FORMAT_BITMAP) {
+ if ((font->outline_val > 0 && slot->format == FT_GLYPH_FORMAT_OUTLINE) ||
+ slot->format == FT_GLYPH_FORMAT_BITMAP) {
FT_BitmapGlyph bitmap_glyph;
@@ -2214,14 +2253,7 @@ static FT_Error Load_Glyph(TTF_Font *font, c_glyph *cached, int want, int transl
}
if (font->outline_val > 0) {
- FT_Stroker stroker;
- error = FT_Stroker_New(library, &stroker);
- if (error) {
- goto ft_failure;
- }
- FT_Stroker_Set(stroker, font->outline_val * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
- FT_Glyph_Stroke(&glyph, stroker, 1 /* delete the original glyph */);
- FT_Stroker_Done(stroker);
+ FT_Glyph_Stroke(&glyph, font->stroker, 1 /* delete the original glyph */);
}
/* Render the glyph */
@@ -2714,6 +2746,9 @@ void TTF_CloseFont(TTF_Font *font)
if (font->face) {
FT_Done_Face(font->face);
}
+ if (font->stroker) {
+ FT_Stroker_Done(font->stroker);
+ }
if (font->args.stream) {
SDL_free(font->args.stream);
}
@@ -3668,13 +3703,38 @@ int TTF_GetFontStyle(const TTF_Font *font)
return style;
}
-void TTF_SetFontOutline(TTF_Font *font, int outline)
+bool TTF_SetFontOutline(TTF_Font *font, int outline)
{
- TTF_CHECK_FONT(font,);
+ TTF_CHECK_FONT(font, false);
+
+ outline = SDL_max(0, outline);
+
+ if (outline > 0) {
+ if (!font->stroker) {
+ FT_Error error;
+
+ SDL_LockMutex(TTF_state.lock);
+ error = FT_Stroker_New(TTF_state.library, &font->stroker);
+ SDL_UnlockMutex(TTF_state.lock);
+ if (error) {
+ return TTF_SetFTError("Couldn't create font stroker", error);
+ }
+ }
+
+ FT_Stroker_Set(font->stroker, outline * 64, FT_STROKER_LINECAP_ROUND, FT_STROKER_LINEJOIN_ROUND, 0);
+ } else {
+ if (font->stroker) {
+ FT_Stroker_Done(font->stroker);
+ font->stroker = NULL;
+ }
+ }
+
+ font->outline_val = outline;
- font->outline_val = SDL_max(0, outline);
TTF_initFontMetrics(font);
Flush_Cache(font);
+
+ return true;
}
int TTF_GetFontOutline(const TTF_Font *font)
@@ -3768,17 +3828,31 @@ int TTF_GetFontWrappedAlign(const TTF_Font *font)
void TTF_Quit(void)
{
- if (TTF_initialized) {
- if (--TTF_initialized == 0) {
- FT_Done_FreeType(library);
- library = NULL;
- }
+ if (!SDL_ShouldQuit(&TTF_state.init)) {
+ return;
+ }
+
+ if (!SDL_AtomicDecRef(&TTF_state.refcount)) {
+ SDL_SetInitialized(&TTF_state.init, true);
+ return;
+ }
+
+ if (TTF_state.library) {
+ FT_Done_FreeType(TTF_state.library);
+ TTF_state.library = NULL;
}
+
+ if (TTF_state.lock) {
+ SDL_DestroyMutex(TTF_state.lock);
+ TTF_state.lock = NULL;
+ }
+
+ SDL_SetInitialized(&TTF_state.init, false);
}
int TTF_WasInit(void)
{
- return TTF_initialized;
+ return SDL_GetAtomicInt(&TTF_state.refcount);
}
int TTF_GetFontKerningSizeGlyphs(TTF_Font *font, Uint32 previous_ch, Uint32 ch)