SDL_ttf: Add TTF_SetFontLanguage to set language BCP47 code, (see #308)

From c4daf98feca9e94d56dffaa2f21f5c24d0f261e5 Mon Sep 17 00:00:00 2001
From: Sylvain <[EMAIL REDACTED]>
Date: Mon, 9 Oct 2023 10:51:23 +0200
Subject: [PATCH] Add TTF_SetFontLanguage to set language BCP47 code, (see
 #308)

---
 include/SDL3_ttf/SDL_ttf.h | 13 +++++++++++++
 src/SDL_ttf.c              | 21 +++++++++++++++++++++
 src/SDL_ttf.sym            |  1 +
 3 files changed, 35 insertions(+)

diff --git a/include/SDL3_ttf/SDL_ttf.h b/include/SDL3_ttf/SDL_ttf.h
index caf87b3f..2fb72230 100644
--- a/include/SDL3_ttf/SDL_ttf.h
+++ b/include/SDL3_ttf/SDL_ttf.h
@@ -2218,6 +2218,19 @@ extern DECLSPEC int SDLCALL TTF_SetFontDirection(TTF_Font *font, TTF_Direction d
  */
 extern DECLSPEC int SDLCALL TTF_SetFontScriptName(TTF_Font *font, const char *script);
 
+/**
+ * Set language to be used for text shaping by a font.
+ *
+ * If SDL_ttf was not built with HarfBuzz support, this function returns -1.
+ *
+ * \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.
+ * \returns 0 on success, or -1 on error.
+ *
+ * \since This function is available since SDL_ttf 3.0.0.
+ */
+extern DECLSPEC int TTF_SetFontLanguage(TTF_Font *font, const char *language_bcp47);
+
 /**
  * Query whether a font is scalable or not.
  *
diff --git a/src/SDL_ttf.c b/src/SDL_ttf.c
index d81fd0ad..e75a3178 100644
--- a/src/SDL_ttf.c
+++ b/src/SDL_ttf.c
@@ -269,6 +269,7 @@ struct _TTF_Font {
     hb_script_t hb_script;
     /* If HB_DIRECTION_INVALID, use global default direction */
     hb_direction_t hb_direction;
+    hb_language_t hb_language;
 #endif
     int render_sdf;
 
@@ -1867,6 +1868,7 @@ TTF_Font* TTF_OpenFontIndexDPIRW(SDL_RWops *src, SDL_bool freesrc, int ptsize, l
     /* By default the script / direction are inherited from global variables */
     font->hb_script = HB_SCRIPT_INVALID;
     font->hb_direction = HB_DIRECTION_INVALID;
+    font->hb_language = hb_language_from_string("", -1);
 #endif
 
     if (TTF_SetFontSizeDPI(font, ptsize, hdpi, vdpi) < 0) {
@@ -3111,6 +3113,24 @@ int TTF_SetFontScriptName(TTF_Font *font, const char *script)
 #endif
 }
 
+int TTF_SetFontLanguage(TTF_Font *font, const char *language_bcp47)
+{
+#if TTF_USE_HARFBUZZ
+    TTF_CHECK_POINTER(font, -1);
+
+    if (language_bcp47 == NULL) {
+        font->hb_language = hb_language_from_string("", -1);
+    } else {
+        font->hb_language = hb_language_from_string(language_bcp47, -1);
+    }
+    return 0;
+#else
+    (void) font;
+    (void) language_bcp47;
+    return TTF_SetError("Unsupported");
+#endif
+}
+
 static int TTF_Size_Internal(TTF_Font *font,
         const char *text, const str_type_t str_type,
         int *w, int *h, int *xstart, int *ystart,
@@ -3200,6 +3220,7 @@ static int TTF_Size_Internal(TTF_Font *font,
     }
 
     /* Set global configuration */
+    hb_buffer_set_language(hb_buffer, font->hb_language);
     hb_buffer_set_direction(hb_buffer, hb_direction);
     hb_buffer_set_script(hb_buffer, hb_script);
 
diff --git a/src/SDL_ttf.sym b/src/SDL_ttf.sym
index 51e97344..f278e89e 100644
--- a/src/SDL_ttf.sym
+++ b/src/SDL_ttf.sym
@@ -74,6 +74,7 @@ SDL3_ttf_0.0.0 {
     TTF_SetFontDirection;
     TTF_SetFontHinting;
     TTF_SetFontKerning;
+    TTF_SetFontLanguage;
     TTF_SetFontOutline;
     TTF_SetFontSDF;
     TTF_SetFontScriptName;