From aada7689cc025605ba4b49f6d6b0bb83c720493f Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Thu, 6 Feb 2025 11:02:32 -0800
Subject: [PATCH] Added TTF_StringToTag() and TTF_TagToString()
Also clarified that the script used in the API is an ISO 15924 script code.
Fixes https://github.com/libsdl-org/SDL_ttf/issues/505
---
include/SDL3_ttf/SDL_ttf.h | 53 +++++++++++++++++++++++++++++++++-----
src/SDL_ttf.c | 45 ++++++++++++++++++++++++++------
src/SDL_ttf.sym | 2 ++
3 files changed, 85 insertions(+), 15 deletions(-)
diff --git a/include/SDL3_ttf/SDL_ttf.h b/include/SDL3_ttf/SDL_ttf.h
index f39d0ab2..969cc1be 100644
--- a/include/SDL3_ttf/SDL_ttf.h
+++ b/include/SDL3_ttf/SDL_ttf.h
@@ -941,15 +941,44 @@ extern SDL_DECLSPEC bool SDLCALL TTF_SetFontDirection(TTF_Font *font, TTF_Direct
*/
extern SDL_DECLSPEC TTF_Direction SDLCALL TTF_GetFontDirection(TTF_Font *font);
+/**
+ * Convert from a 4 character string to a 32-bit tag.
+ *
+ * \param string the 4 character string to convert.
+ * \returns the 32-bit representation of the string.
+ *
+ * \threadsafety It is safe to call this function from any thread.
+ *
+ * \since This function is available since SDL_ttf 3.0.0.
+ *
+ * \sa TTF_TagToString
+ */
+extern SDL_DECLSPEC Uint32 SDLCALL TTF_StringToTag(const char *string);
+
+/**
+ * Convert from a 32-bit tag to a 4 character string.
+ *
+ * \param tag the 32-bit tag to convert.
+ * \param string a pointer filled in with the 4 character representation of the tag.
+ * \param size the size of the buffer pointed at by string, should be at least 4.
+ *
+ * \threadsafety It is safe to call this function from any thread.
+ *
+ * \since This function is available since SDL_ttf 3.0.0.
+ *
+ * \sa TTF_TagToString
+ */
+extern SDL_DECLSPEC void SDLCALL TTF_TagToString(Uint32 tag, char *string, size_t size);
+
/**
* Set the script to be used for text shaping by a font.
*
- * This returns false if SDL_ttf isn't build with HarfBuzz support.
+ * This returns false if SDL_ttf isn't built with HarfBuzz support.
*
* This updates any TTF_Text objects using this font.
*
* \param font the font to modify.
- * \param script a script tag in the format used by HarfBuzz.
+ * \param script an [ISO 15924 code](https://unicode.org/iso15924/iso15924-codes.html).
* \returns true on success or false on failure; call SDL_GetError() for more
* information.
*
@@ -957,6 +986,8 @@ extern SDL_DECLSPEC TTF_Direction SDLCALL TTF_GetFontDirection(TTF_Font *font);
* font.
*
* \since This function is available since SDL_ttf 3.0.0.
+ *
+ * \sa TTF_StringToTag
*/
extern SDL_DECLSPEC bool SDLCALL TTF_SetFontScript(TTF_Font *font, Uint32 script);
@@ -964,12 +995,14 @@ extern SDL_DECLSPEC bool SDLCALL TTF_SetFontScript(TTF_Font *font, Uint32 script
* Get the script used for text shaping a font.
*
* \param font the font to query.
- * \returns a script tag in the format used by HarfBuzz.
+ * \returns an [ISO 15924 code](https://unicode.org/iso15924/iso15924-codes.html) or 0 if a script hasn't been set.
*
* \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_TagToString
*/
extern SDL_DECLSPEC Uint32 SDLCALL TTF_GetFontScript(TTF_Font *font);
@@ -977,12 +1010,14 @@ extern SDL_DECLSPEC Uint32 SDLCALL TTF_GetFontScript(TTF_Font *font);
* Get the script used by a 32-bit codepoint.
*
* \param ch the character code to check.
- * \returns a script tag in the format used by HarfBuzz on success, or 0 on
+ * \returns an [ISO 15924 code](https://unicode.org/iso15924/iso15924-codes.html) on success, or 0 on
* failure; call SDL_GetError() for more information.
*
* \threadsafety This function is thread-safe.
*
* \since This function is available since SDL_ttf 3.0.0.
+ *
+ * \sa TTF_TagToString
*/
extern SDL_DECLSPEC Uint32 SDLCALL TTF_GetGlyphScript(Uint32 ch);
@@ -2110,10 +2145,10 @@ extern SDL_DECLSPEC TTF_Direction SDLCALL TTF_GetTextDirection(TTF_Text *text);
/**
* Set the script to be used for text shaping a text object.
*
- * This returns false if SDL_ttf isn't build with HarfBuzz support.
+ * This returns false if SDL_ttf isn't built with HarfBuzz support.
*
* \param text the text to modify.
- * \param script a script tag in the format used by HarfBuzz.
+ * \param script an [ISO 15924 code](https://unicode.org/iso15924/iso15924-codes.html).
* \returns true on success or false on failure; call SDL_GetError() for more
* information.
*
@@ -2121,6 +2156,8 @@ extern SDL_DECLSPEC TTF_Direction SDLCALL TTF_GetTextDirection(TTF_Text *text);
* text.
*
* \since This function is available since SDL_ttf 3.0.0.
+ *
+ * \sa TTF_StringToTag
*/
extern SDL_DECLSPEC bool SDLCALL TTF_SetTextScript(TTF_Text *text, Uint32 script);
@@ -2130,12 +2167,14 @@ extern SDL_DECLSPEC bool SDLCALL TTF_SetTextScript(TTF_Text *text, Uint32 script
* This defaults to the script of the font used by the text object.
*
* \param text the text to query.
- * \returns a script tag in the format used by HarfBuzz.
+ * \returns an [ISO 15924 code](https://unicode.org/iso15924/iso15924-codes.html) or 0 if a script hasn't been set on either the text object or the font.
*
* \threadsafety This function should be called on the thread that created the
* text.
*
* \since This function is available since SDL_ttf 3.0.0.
+ *
+ * \sa TTF_TagToString
*/
extern SDL_DECLSPEC Uint32 SDLCALL TTF_GetTextScript(TTF_Text *text);
diff --git a/src/SDL_ttf.c b/src/SDL_ttf.c
index eb3f6b97..ea9edfc1 100644
--- a/src/SDL_ttf.c
+++ b/src/SDL_ttf.c
@@ -346,7 +346,7 @@ struct TTF_Font {
hb_font_t *hb_font;
hb_language_t hb_language;
#endif
- Uint32 script;
+ Uint32 script; // ISO 15924 script tag
TTF_Direction direction;
bool render_sdf;
@@ -3352,7 +3352,7 @@ static bool CollectGlyphsFromFont(TTF_Font *font, const char *text, size_t lengt
// Set global configuration
hb_buffer_set_language(hb_buffer, font->hb_language);
hb_buffer_set_direction(hb_buffer, (hb_direction_t)direction);
- hb_buffer_set_script(hb_buffer, script);
+ hb_buffer_set_script(hb_buffer, hb_script_from_iso15924_tag(script));
// Layout the text
hb_buffer_add_utf8(hb_buffer, text, (int)length, 0, -1);
@@ -4369,7 +4369,7 @@ SDL_Surface* TTF_RenderText_LCD_Wrapped(TTF_Font *font, const char *text, size_t
struct TTF_TextLayout
{
TTF_Direction direction;
- Uint32 script;
+ Uint32 script; // ISO 15924 script tag
int font_height;
int wrap_length;
bool wrap_whitespace_visible;
@@ -4815,7 +4815,7 @@ Uint32 TTF_GetTextScript(TTF_Text *text)
{
TTF_CHECK_POINTER("text", text, 0);
- if (text->internal->layout->script != 0) {
+ if (text->internal->layout->script) {
return text->internal->layout->script;
}
return TTF_GetFontScript(text->internal->font);
@@ -6001,6 +6001,38 @@ TTF_Direction TTF_GetFontDirection(TTF_Font *font)
return font->direction;
}
+Uint32 TTF_StringToTag(const char *string)
+{
+ Uint8 bytes[4] = { 0, 0, 0, 0 };
+
+ if (string) {
+ for (size_t i = 0; i < 4 && string[i]; ++i) {
+ bytes[i] = (Uint8)string[i];
+ }
+ }
+
+ Uint32 tag = ((Uint32)bytes[0] << 24) |
+ ((Uint32)bytes[1] << 16) |
+ ((Uint32)bytes[2] << 8) |
+ ((Uint32)bytes[3] << 0);
+ return tag;
+}
+
+void TTF_TagToString(Uint32 tag, char *string, size_t size)
+{
+ if (!string || !size) {
+ return;
+ }
+
+ for (size_t i = 0; i < 4 && i < size; ++i) {
+ string[i] = (char)(Uint8)(tag >> 24);
+ tag <<= 8;
+ }
+ if (size > 4) {
+ string[4] = '\0';
+ }
+}
+
bool TTF_SetFontScript(TTF_Font *font, Uint32 script)
{
TTF_CHECK_FONT(font, false);
@@ -6045,10 +6077,7 @@ Uint32 TTF_GetGlyphScript(Uint32 ch)
hb_buffer_clear_contents(hb_buffer);
hb_buffer_set_content_type(hb_buffer, HB_BUFFER_CONTENT_TYPE_UNICODE);
- script = hb_unicode_script(hb_unicode_functions, ch);
- if (script == HB_SCRIPT_UNKNOWN) {
- script = 0;
- }
+ script = hb_script_to_iso15924_tag(hb_unicode_script(hb_unicode_functions, ch));
hb_buffer_destroy(hb_buffer);
#else
diff --git a/src/SDL_ttf.sym b/src/SDL_ttf.sym
index 0720cd19..51963f38 100644
--- a/src/SDL_ttf.sym
+++ b/src/SDL_ttf.sym
@@ -109,6 +109,8 @@ SDL3_ttf_0.0.0 {
TTF_SetTextString;
TTF_SetTextWrapWhitespaceVisible;
TTF_SetTextWrapWidth;
+ TTF_StringToTag;
+ TTF_TagToString;
TTF_TextWrapWhitespaceVisible;
TTF_UpdateText;
TTF_Version;