SDL_ttf: Added TTF_GetGlyphScript()

From 6e4a9777f8f5b61668446924cc51bcfb1412fd1f Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Thu, 26 Sep 2024 20:04:28 -0700
Subject: [PATCH] Added TTF_GetGlyphScript()

Fixes https://github.com/libsdl-org/SDL_ttf/issues/351
Closes https://github.com/libsdl-org/SDL_ttf/pull/312
---
 build-scripts/SDL_migration.cocci |  5 ++++
 docs/README-migration.md          |  1 +
 include/SDL3_ttf/SDL_ttf.h        | 28 ++++++++++++++++++---
 src/SDL_ttf.c                     | 42 ++++++++++++++++++++++++++++++-
 src/SDL_ttf.sym                   |  3 ++-
 5 files changed, 73 insertions(+), 6 deletions(-)

diff --git a/build-scripts/SDL_migration.cocci b/build-scripts/SDL_migration.cocci
index 81b3788f..9a7c931d 100644
--- a/build-scripts/SDL_migration.cocci
+++ b/build-scripts/SDL_migration.cocci
@@ -155,3 +155,8 @@
 - TTF_IsFontScalable
 + TTF_FontIsScalable
   (...)
+@@
+@@
+- TTF_SetFontScriptName
++ TTF_SetFontScript
+  (...)
diff --git a/docs/README-migration.md b/docs/README-migration.md
index 422011fc..bebaa9b7 100644
--- a/docs/README-migration.md
+++ b/docs/README-migration.md
@@ -63,6 +63,7 @@ The following functions have been renamed:
 * TTF_RenderUTF8_Shaded_Wrapped() => TTF_RenderText_Shaded_Wrapped()
 * TTF_RenderUTF8_Solid() => SDL_RenderText_Solid()
 * TTF_RenderUTF8_Solid_Wrapped() => TTF_RenderText_Solid_Wrapped()
+* TTF_SetFontScriptName() => TTF_SetFontScript()
 * TTF_SetFontWrappedAlign() => TTF_SetFontWrapAlignment()
 * TTF_SizeUTF8() => TTF_SizeText()
 
diff --git a/include/SDL3_ttf/SDL_ttf.h b/include/SDL3_ttf/SDL_ttf.h
index 31b376c6..cebe9e1c 100644
--- a/include/SDL3_ttf/SDL_ttf.h
+++ b/include/SDL3_ttf/SDL_ttf.h
@@ -1280,7 +1280,7 @@ typedef enum TTF_Direction
  * - `TTF_DIRECTION_TTB` (Top to Bottom)
  * - `TTF_DIRECTION_BTT` (Bottom to Top)
  *
- * If SDL_ttf was not built with HarfBuzz support, this function returns -1.
+ * If SDL_ttf was not built with HarfBuzz support, this function returns false.
  *
  * \param font the font to specify a direction for.
  * \param direction the new direction for text to flow.
@@ -1299,23 +1299,43 @@ extern SDL_DECLSPEC bool SDLCALL TTF_SetFontDirection(TTF_Font *font, TTF_Direct
  * The supplied script value must be a null-terminated string of exactly four
  * characters.
  *
- * If SDL_ttf was not built with HarfBuzz support, this function returns -1.
+ * If SDL_ttf was not built with HarfBuzz support, this function returns false.
  *
  * \param font the font to specify a script name for.
  * \param script null-terminated string of exactly 4 characters.
  * \returns true on success or false on failure; call SDL_GetError() for more
  *          information.
  *
+ * \threadsafety This function is not thread-safe.
+ *
+ * \since This function is available since SDL_ttf 3.0.0.
+ */
+extern SDL_DECLSPEC bool SDLCALL TTF_SetFontScript(TTF_Font *font, const char *script);
+
+/**
+ * Get the script used by a 32-bit codepoint.
+ *
+ * The supplied script value will be a null-terminated string of exactly four
+ * characters.
+ *
+ * If SDL_ttf was not built with HarfBuzz support, this function returns false.
+ *
+ * \param ch the character code to check.
+ * \param script a pointer filled in with the script used by `ch`.
+ * \param script_size the size of the script buffer, which must be at least 5 characters.
+ * \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);
+extern SDL_DECLSPEC bool SDLCALL TTF_GetGlyphScript(Uint32 ch, char *script, size_t script_size);
 
 /**
  * Set language to be used for text shaping by a font.
  *
- * If SDL_ttf was not built with HarfBuzz support, this function returns -1.
+ * If SDL_ttf was not built with HarfBuzz support, this function returns false.
  *
  * \param font the font to specify a language for.
  * \param language_bcp47 a null-terminated string containing the desired language's BCP47 code. Or null to reset the value.
diff --git a/src/SDL_ttf.c b/src/SDL_ttf.c
index 384286ce..1e9e9152 100644
--- a/src/SDL_ttf.c
+++ b/src/SDL_ttf.c
@@ -2903,7 +2903,7 @@ bool TTF_SetFontDirection(TTF_Font *font, TTF_Direction direction)
 #endif
 }
 
-bool TTF_SetFontScriptName(TTF_Font *font, const char *script)
+bool TTF_SetFontScript(TTF_Font *font, const char *script)
 {
     TTF_CHECK_FONT(font, false);
 
@@ -2928,6 +2928,46 @@ bool TTF_SetFontScriptName(TTF_Font *font, const char *script)
 #endif
 }
 
+bool TTF_GetGlyphScript(Uint32 ch, char *script, size_t script_size)
+{
+#if TTF_USE_HARFBUZZ
+    TTF_CHECK_POINTER("script", script, false);
+
+    if (script_size < 5) {
+        return SDL_SetError("Insufficient script buffer size");
+    }
+
+    hb_buffer_t *hb_buffer = hb_buffer_create();
+
+    if (hb_buffer == NULL) {
+        return SDL_SetError("Cannot create harfbuzz buffer");
+    }
+
+    hb_unicode_funcs_t* hb_unicode_functions = hb_buffer_get_unicode_funcs(hb_buffer);
+
+    if (hb_unicode_functions == NULL) {
+        hb_buffer_destroy(hb_buffer);
+        return SDL_SetError("Cannot get harfbuzz unicode functions");
+    }
+
+    hb_buffer_clear_contents(hb_buffer);
+    hb_buffer_set_content_type(hb_buffer, HB_BUFFER_CONTENT_TYPE_UNICODE);
+
+    uint8_t untagged_script[4] = { HB_UNTAG(hb_unicode_script(hb_unicode_functions, ch)) };
+    script[0] = (char)untagged_script[0];
+    script[1] = (char)untagged_script[1];
+    script[2] = (char)untagged_script[2];
+    script[3] = (char)untagged_script[3];
+    script[4] = '\0';
+
+    hb_buffer_destroy(hb_buffer);
+    return true;
+
+#else
+    return SDL_SetError("Unsupported");
+#endif
+}
+
 bool TTF_SetFontLanguage(TTF_Font *font, const char *language_bcp47)
 {
     TTF_CHECK_FONT(font, false);
diff --git a/src/SDL_ttf.sym b/src/SDL_ttf.sym
index c6891704..b8bfb910 100644
--- a/src/SDL_ttf.sym
+++ b/src/SDL_ttf.sym
@@ -20,6 +20,7 @@ SDL3_ttf_0.0.0 {
     TTF_GetFreeTypeVersion;
     TTF_GetGlyphKerning;
     TTF_GetGlyphMetrics;
+    TTF_GetGlyphScript;
     TTF_GetHarfBuzzVersion;
     TTF_Init;
     TTF_MeasureText;
@@ -46,7 +47,7 @@ SDL3_ttf_0.0.0 {
     TTF_SetFontLineSkip;
     TTF_SetFontOutline;
     TTF_SetFontSDF;
-    TTF_SetFontScriptName;
+    TTF_SetFontScript;
     TTF_SetFontSize;
     TTF_SetFontSizeDPI;
     TTF_SetFontStyle;