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); }