From 25b596c820a1377cdf7fccbcfc1e0399705d5e5c Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Mon, 30 Sep 2024 09:39:23 -0700
Subject: [PATCH] Added TTF_GetTextProperties()
Also made the internal fields of TTF_Text private, and added a debug label instead of always copying the text used to create the TTF_Text.
---
include/SDL3_ttf/SDL_textengine.h | 8 +++++
include/SDL3_ttf/SDL_ttf.h | 22 +++++++++++--
src/SDL_renderer_textengine.c | 10 +++---
src/SDL_surface_textengine.c | 19 +++++------
src/SDL_ttf.c | 53 +++++++++++++++++++++----------
5 files changed, 78 insertions(+), 34 deletions(-)
diff --git a/include/SDL3_ttf/SDL_textengine.h b/include/SDL3_ttf/SDL_textengine.h
index b3e32ba4..59dbdee6 100644
--- a/include/SDL3_ttf/SDL_textengine.h
+++ b/include/SDL3_ttf/SDL_textengine.h
@@ -39,6 +39,14 @@ extern "C" {
/* Text created with the text engine */
typedef struct TTF_Text TTF_Text;
+/* Private data in TTF_Text, available to implementations */
+struct TTF_TextData
+{
+ TTF_TextEngine *engine; /**< The engine used to create this text, read-only. */
+ SDL_PropertiesID props; /**< Custom properties associated with this text, read-write. */
+ void *textrep; /**< The implementation-specific representation of this text */
+};
+
/**
* A font atlas draw command.
*
diff --git a/include/SDL3_ttf/SDL_ttf.h b/include/SDL3_ttf/SDL_ttf.h
index 25982f55..83779c81 100644
--- a/include/SDL3_ttf/SDL_ttf.h
+++ b/include/SDL3_ttf/SDL_ttf.h
@@ -1228,6 +1228,9 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL TTF_RenderGlyph_LCD(TTF_Font *font, Ui
*/
typedef struct TTF_TextEngine TTF_TextEngine;
+/* Internal data for TTF_Text */
+typedef struct TTF_TextData TTF_TextData;
+
/**
* Text created with TTF_CreateText()
*
@@ -1235,6 +1238,7 @@ typedef struct TTF_TextEngine TTF_TextEngine;
*
* \sa TTF_CreateText
* \sa TTF_CreateText_Wrapped
+ * \sa TTF_GetTextProperties
* \sa TTF_DestroyText
*/
typedef struct TTF_Text
@@ -1243,8 +1247,11 @@ typedef struct TTF_Text
int w; /**< The width of this text, in pixels, read-only. */
int h; /**< The height of this text, in pixels, read-only. */
SDL_FColor color; /**< The color of the text, read-write. You can change this anytime. */
- TTF_TextEngine *engine; /**< The engine used to create this text, read-only. */
- void *internal; /**< The internal representation of this text, read-only */
+
+ int refcount; /**< Application reference count, used when freeing surface */
+
+ TTF_TextData *internal; /**< Private */
+
} TTF_Text;
/**
@@ -1402,6 +1409,17 @@ extern SDL_DECLSPEC TTF_Text * SDLCALL TTF_CreateText(TTF_TextEngine *engine, TT
*/
extern SDL_DECLSPEC TTF_Text * SDLCALL TTF_CreateText_Wrapped(TTF_TextEngine *engine, TTF_Font *font, const char *text, size_t length, int wrapLength);
+/**
+ * Get the properties associated with a text object.
+ *
+ * \param text the TTF_Text to query.
+ * \returns a valid property ID on success or 0 on failure; call
+ * SDL_GetError() for more information.
+ *
+ * \since This function is available since SDL 3.0.0.
+ */
+extern SDL_DECLSPEC SDL_PropertiesID SDLCALL TTF_GetTextProperties(TTF_Text *text);
+
/**
* Destroy a text object created by a text engine.
*
diff --git a/src/SDL_renderer_textengine.c b/src/SDL_renderer_textengine.c
index 282949a8..4a74341b 100644
--- a/src/SDL_renderer_textengine.c
+++ b/src/SDL_renderer_textengine.c
@@ -262,13 +262,13 @@ static bool SDLCALL CreateText(void *userdata, TTF_Font *font, Uint32 font_gener
if (!data) {
return false;
}
- text->internal = data;
+ text->internal->textrep = data;
return true;
}
static void SDLCALL DestroyText(void *userdata, TTF_Text *text)
{
- TTF_RendererTextEngineTextData *data = (TTF_RendererTextEngineTextData *)text->internal;
+ TTF_RendererTextEngineTextData *data = (TTF_RendererTextEngineTextData *)text->internal->textrep;
(void)userdata;
DestroyTextData(data);
@@ -333,12 +333,12 @@ bool TTF_DrawRendererText(TTF_Text *text, float x, float y)
TTF_RendererTextEngineTextData *data;
SDL_Renderer *renderer;
- if (!text || !text->engine || text->engine->CreateText != CreateText) {
+ if (!text || !text->internal || text->internal->engine->CreateText != CreateText) {
return SDL_InvalidParamError("text");
}
- renderer = ((TTF_RendererTextEngineData *)text->engine->userdata)->renderer;
- data = (TTF_RendererTextEngineTextData *)text->internal;
+ renderer = ((TTF_RendererTextEngineData *)text->internal->engine->userdata)->renderer;
+ data = (TTF_RendererTextEngineTextData *)text->internal->textrep;
for (int i = 0; i < data->num_ops; ++i) {
const TTF_DrawOperation *op = &data->ops[i];
diff --git a/src/SDL_surface_textengine.c b/src/SDL_surface_textengine.c
index 06a290a4..0bc84342 100644
--- a/src/SDL_surface_textengine.c
+++ b/src/SDL_surface_textengine.c
@@ -251,13 +251,13 @@ static bool SDLCALL CreateText(void *userdata, TTF_Font *font, Uint32 font_gener
if (!data) {
return false;
}
- text->internal = data;
+ text->internal->textrep = data;
return true;
}
static void SDLCALL DestroyText(void *userdata, TTF_Text *text)
{
- TTF_SurfaceTextEngineTextData *data = (TTF_SurfaceTextEngineTextData *)text->internal;
+ TTF_SurfaceTextEngineTextData *data = (TTF_SurfaceTextEngineTextData *)text->internal->textrep;
(void)userdata;
DestroyTextData(data);
@@ -290,10 +290,8 @@ static void UpdateColor(TTF_SurfaceTextEngineTextData *data, const SDL_FColor *c
SDL_copyp(&data->fcolor, color);
}
-static void DrawFill(TTF_Text *text, const TTF_FillOperation *op, int x, int y, SDL_Surface *surface)
+static void DrawFill(TTF_SurfaceTextEngineTextData *data, const TTF_FillOperation *op, int x, int y, SDL_Surface *surface)
{
- TTF_SurfaceTextEngineTextData *data = (TTF_SurfaceTextEngineTextData *)text->internal;
-
Uint32 color = SDL_MapSurfaceRGBA(surface, data->color.r, data->color.g, data->color.b, data->color.a);
SDL_Rect dst;
@@ -303,9 +301,8 @@ static void DrawFill(TTF_Text *text, const TTF_FillOperation *op, int x, int y,
SDL_FillSurfaceRect(surface, &dst, color);
}
-static void DrawCopy(TTF_Text *text, const TTF_CopyOperation *op, int x, int y, SDL_Surface *surface)
+static void DrawCopy(TTF_SurfaceTextEngineTextData *data, const TTF_CopyOperation *op, int x, int y, SDL_Surface *surface)
{
- TTF_SurfaceTextEngineTextData *data = (TTF_SurfaceTextEngineTextData *)text->internal;
TTF_SurfaceTextEngineGlyphData *glyph = (TTF_SurfaceTextEngineGlyphData *)op->reserved;
if (data->color.r != glyph->color.r ||
@@ -328,14 +325,14 @@ bool TTF_DrawSurfaceText(TTF_Text *text, int x, int y, SDL_Surface *surface)
{
TTF_SurfaceTextEngineTextData *data;
- if (!text || !text->engine || text->engine->CreateText != CreateText) {
+ if (!text || !text->internal || text->internal->engine->CreateText != CreateText) {
return SDL_InvalidParamError("text");
}
if (!surface) {
return SDL_InvalidParamError("surface");
}
- data = (TTF_SurfaceTextEngineTextData *)text->internal;
+ data = (TTF_SurfaceTextEngineTextData *)text->internal->textrep;
if (text->color.r != data->fcolor.r ||
text->color.g != data->fcolor.g ||
@@ -348,10 +345,10 @@ bool TTF_DrawSurfaceText(TTF_Text *text, int x, int y, SDL_Surface *surface)
const TTF_DrawOperation *op = &data->ops[i];
switch (op->cmd) {
case TTF_DRAW_COMMAND_FILL:
- DrawFill(text, &op->fill, x, y, surface);
+ DrawFill(data, &op->fill, x, y, surface);
break;
case TTF_DRAW_COMMAND_COPY:
- DrawCopy(text, &op->copy, x, y, surface);
+ DrawCopy(data, &op->copy, x, y, surface);
break;
default:
break;
diff --git a/src/SDL_ttf.c b/src/SDL_ttf.c
index 4224992a..0cc00de6 100644
--- a/src/SDL_ttf.c
+++ b/src/SDL_ttf.c
@@ -3547,21 +3547,29 @@ SDL_Surface* TTF_RenderText_LCD_Wrapped(TTF_Font *font, const char *text, size_t
return TTF_Render_Wrapped_Internal(font, text, length, fg, bg, wrapLength, RENDER_LCD);
}
-static TTF_Text *CreateText(TTF_TextEngine *engine, const char *text, int width, int height)
+typedef struct TTF_InternalText
{
- TTF_Text *result = (TTF_Text *)SDL_calloc(1, sizeof(*result));
- if (!result) {
+ TTF_Text text;
+ TTF_TextData internal;
+} TTF_InternalText;
+
+static TTF_Text *CreateText(TTF_TextEngine *engine, int width, int height)
+{
+ TTF_InternalText *mem = (TTF_InternalText *)SDL_calloc(1, sizeof(*mem));
+ if (!mem) {
return NULL;
}
- result->w = width;
- result->h = height;
- result->color.r = 1.0f;
- result->color.g = 1.0f;
- result->color.b = 1.0f;
- result->color.a = 1.0f;
- result->engine = engine;
- return result;
+ TTF_Text *text = &mem->text;
+ text->internal = &mem->internal;
+ text->w = width;
+ text->h = height;
+ text->color.r = 1.0f;
+ text->color.g = 1.0f;
+ text->color.b = 1.0f;
+ text->color.a = 1.0f;
+ text->internal->engine = engine;
+ return text;
}
TTF_Text *TTF_CreateText(TTF_TextEngine *engine, TTF_Font *font, const char *text, size_t length)
@@ -3620,7 +3628,7 @@ TTF_Text *TTF_CreateText(TTF_TextEngine *engine, TTF_Font *font, const char *tex
Draw_Line_TextEngine(font, width, height, 0, ystart + font->strikethrough_top_row, width, font->line_thickness, ops, &num_ops);
}
- result = CreateText(engine, text, width, height);
+ result = CreateText(engine, width, height);
if (!result) {
goto failure;
}
@@ -3713,7 +3721,7 @@ TTF_Text *TTF_CreateText_Wrapped(TTF_TextEngine *engine, TTF_Font *font, const c
}
}
- result = CreateText(engine, text, width, height);
+ result = CreateText(engine, width, height);
if (!result) {
goto failure;
}
@@ -3733,14 +3741,27 @@ TTF_Text *TTF_CreateText_Wrapped(TTF_TextEngine *engine, TTF_Font *font, const c
return NULL;
}
+SDL_PropertiesID TTF_GetTextProperties(TTF_Text *text)
+{
+ TTF_CHECK_POINTER("text", text, 0);
+ TTF_CHECK_POINTER("text", text->internal, 0);
+
+ if (!text->internal->props) {
+ text->internal->props = SDL_CreateProperties();
+ }
+ return text->internal->props;
+}
+
void TTF_DestroyText(TTF_Text *text)
{
- if (!text || !text->engine) {
+ if (!text || !text->internal) {
return;
}
- text->engine->DestroyText(text->engine->userdata, text);
- text->engine = NULL;
+ TTF_TextEngine *engine = text->internal->engine;
+ engine->DestroyText(engine->userdata, text);
+ SDL_DestroyProperties(text->internal->props);
+ text->internal = NULL;
SDL_free(text->label);
SDL_free(text);
}