X11TK: Add Arabic/Hebrew/Farsi support by increasing font size slightly and using FriBidi. (#14134)

This commit is contained in:
eafton
2025-10-04 05:08:24 +03:00
committed by GitHub
parent 49d51a0d3c
commit c2429e85ec
9 changed files with 503 additions and 30 deletions

160
src/core/unix/SDL_fribidi.c Normal file
View File

@@ -0,0 +1,160 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#ifdef HAVE_FRIBIDI_H
#include "SDL_internal.h"
#include "SDL_fribidi.h"
#include <fribidi.h>
SDL_FriBidi *SDL_FriBidi_Create(void) {
SDL_FriBidi *fribidi;
fribidi = (SDL_FriBidi *)SDL_malloc(sizeof(SDL_FriBidi));
if (!fribidi) {
return NULL;
}
#ifdef SDL_FRIBIDI_DYNAMIC
#define SDL_FRIBIDI_LOAD_SYM(x, n, t) x = ((t)SDL_LoadFunction(fribidi->lib, n)); if (!x) { SDL_UnloadObject(fribidi->lib); SDL_free(fribidi); return NULL; }
fribidi->lib = SDL_LoadObject(SDL_FRIBIDI_DYNAMIC);
if (!fribidi->lib) {
SDL_free(fribidi);
return NULL;
}
SDL_FRIBIDI_LOAD_SYM(fribidi->unicode_to_charset, "fribidi_unicode_to_charset", SDL_FriBidiUnicodeToCharset);
SDL_FRIBIDI_LOAD_SYM(fribidi->charset_to_unicode, "fribidi_charset_to_unicode", SDL_FriBidiCharsetToUnicode);
SDL_FRIBIDI_LOAD_SYM(fribidi->get_bidi_types, "fribidi_get_bidi_types", SDL_FriBidiGetBidiTypes);
SDL_FRIBIDI_LOAD_SYM(fribidi->get_par_direction, "fribidi_get_par_direction", SDL_FriBidiGetParDirection);
SDL_FRIBIDI_LOAD_SYM(fribidi->get_par_embedding_levels, "fribidi_get_par_embedding_levels", SDL_FriBidiGetParEmbeddingLevels);
SDL_FRIBIDI_LOAD_SYM(fribidi->get_joining_types, "fribidi_get_joining_types", SDL_FriBidiGetJoiningTypes);
SDL_FRIBIDI_LOAD_SYM(fribidi->join_arabic, "fribidi_join_arabic", SDL_FriBidiJoinArabic);
SDL_FRIBIDI_LOAD_SYM(fribidi->shape, "fribidi_shape", SDL_FriBidiShape);
SDL_FRIBIDI_LOAD_SYM(fribidi->reorder_line, "fribidi_reorder_line", SDL_FriBidiReorderLine);
#else
fribidi->unicode_to_charset = fribidi_unicode_to_charset;
fribidi->charset_to_unicode = fribidi_charset_to_unicode;
fribidi->get_bidi_types = fribidi_get_bidi_types;
fribidi->get_par_direction = fribidi_get_par_direction;
fribidi->get_par_embedding_levels = fribidi_get_par_embedding_levels;
fribidi->get_joining_types = fribidi_get_joining_types;
fribidi->join_arabic = fribidi_join_arabic;
fribidi->shape = fribidi_shape;
fribidi->reorder_line = fribidi_reorder_line;
#endif
return fribidi;
}
char *SDL_FriBidi_Process(SDL_FriBidi *fribidi, char *utf8, ssize_t utf8_len, bool shaping, FriBidiParType *out_par_type) {
FriBidiCharType *types;
FriBidiLevel *levels;
FriBidiArabicProp *props;
FriBidiChar *str;
char *result;
FriBidiStrIndex len;
FriBidiLevel max_level;
FriBidiLevel start;
FriBidiLevel end;
FriBidiParType direction;
FriBidiParType str_direction;
unsigned int i;
unsigned int c;
if (!fribidi || !utf8) {
return NULL;
}
/* Convert to UTF32 */
if (utf8_len < 0) {
utf8_len = SDL_strlen(utf8);
}
str = SDL_calloc(SDL_utf8strnlen(utf8, utf8_len), sizeof(FriBidiChar));
len = fribidi->charset_to_unicode(FRIBIDI_CHAR_SET_UTF8, utf8, utf8_len, str);
/* Setup various BIDI structures */
direction = FRIBIDI_PAR_LTR;
types = NULL;
levels = NULL;
props = SDL_calloc(len + 1, sizeof(FriBidiArabicProp));
levels = SDL_calloc(len + 1, sizeof(FriBidiLevel));
types = SDL_calloc(len + 1, sizeof(FriBidiCharType));
/* Shape */
fribidi->get_bidi_types(str, len, types);
str_direction = fribidi->get_par_direction(types, len);
max_level = fribidi->get_par_embedding_levels(types, len, &direction, levels);
if (shaping) {
fribidi->get_joining_types(str, len, props);
fribidi->join_arabic(types, len, levels, props);
fribidi->shape(FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC, levels, len, props, str);
}
/* BIDI */
for (end = 0, start = 0; end < len; end++) {
if (str[end] == '\n' || str[end] == '\r' || str[end] == '\f' || str[end] == '\v' || end == len - 1) {
max_level = fribidi->reorder_line(FRIBIDI_FLAGS_DEFAULT | FRIBIDI_FLAGS_ARABIC, types, end - start + 1, start, direction, levels, str, NULL);
start = end + 1;
}
}
/* Silence warning */
(void)max_level;
/* Remove fillers */
for (i = 0, c = 0; i < len; i++) {
if (str[i] != FRIBIDI_CHAR_FILL) {
str[c++] = str[i];
}
}
len = c;
/* Convert back to UTF8 */
result = SDL_malloc(len * 4 + 1);
fribidi->unicode_to_charset(FRIBIDI_CHAR_SET_UTF8, str, len, result);
/* Cleanup */
SDL_free(levels);
SDL_free(props);
SDL_free(types);
/* Return */
if (out_par_type) {
*out_par_type = str_direction;
}
return result;
}
void SDL_FriBidi_Destroy(SDL_FriBidi *fribidi) {
if (!fribidi) {
return;
}
#ifdef SDL_FRIBIDI_DYNAMIC
SDL_UnloadObject(fribidi->lib);
#endif
SDL_free(fribidi);
}
#endif

View File

@@ -0,0 +1,58 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#ifdef HAVE_FRIBIDI_H
#include <fribidi.h>
#ifndef SDL_fribidi_h_
#define SDL_fribidi_h_
typedef FriBidiStrIndex (*SDL_FriBidiUnicodeToCharset)(FriBidiCharSet, const FriBidiChar *, FriBidiStrIndex, char *);
typedef FriBidiStrIndex (*SDL_FriBidiCharsetToUnicode)(FriBidiCharSet, const char *, FriBidiStrIndex, FriBidiChar *);
typedef void (*SDL_FriBidiGetBidiTypes)(const FriBidiChar *, const FriBidiStrIndex, FriBidiCharType *);
typedef FriBidiParType (*SDL_FriBidiGetParDirection)(const FriBidiCharType *, const FriBidiStrIndex);
typedef FriBidiLevel (*SDL_FriBidiGetParEmbeddingLevels)(const FriBidiCharType *, const FriBidiStrIndex, FriBidiParType *, FriBidiLevel *);
typedef void (*SDL_FriBidiGetJoiningTypes)(const FriBidiChar *, const FriBidiStrIndex, FriBidiJoiningType *);
typedef void (*SDL_FriBidiJoinArabic)(const FriBidiCharType *, const FriBidiStrIndex, const FriBidiLevel *, FriBidiArabicProp *);
typedef void (*SDL_FriBidiShape)(FriBidiFlags flags, const FriBidiLevel *, const FriBidiStrIndex, FriBidiArabicProp *, FriBidiChar *str);
typedef FriBidiLevel (*SDL_FriBidiReorderLine)(FriBidiFlags flags, const FriBidiCharType *, const FriBidiStrIndex, const FriBidiStrIndex, const FriBidiParType, FriBidiLevel *, FriBidiChar *, FriBidiStrIndex *);
typedef struct SDL_FriBidi {
SDL_SharedObject *lib;
SDL_FriBidiUnicodeToCharset unicode_to_charset;
SDL_FriBidiCharsetToUnicode charset_to_unicode;
SDL_FriBidiGetBidiTypes get_bidi_types;
SDL_FriBidiGetParDirection get_par_direction;
SDL_FriBidiGetParEmbeddingLevels get_par_embedding_levels;
SDL_FriBidiGetJoiningTypes get_joining_types;
SDL_FriBidiJoinArabic join_arabic;
SDL_FriBidiShape shape;
SDL_FriBidiReorderLine reorder_line;
} SDL_FriBidi;
extern SDL_FriBidi *SDL_FriBidi_Create(void);
extern char *SDL_FriBidi_Process(SDL_FriBidi *fribidi, char *utf8, ssize_t utf8_len, bool shaping, FriBidiParType *out_par_type);
extern void SDL_FriBidi_Destroy(SDL_FriBidi *fribidi);
#endif
#endif // SDL_fribidi_h_

View File

@@ -235,8 +235,10 @@ SDL_X11_SYM(int,Xutf8TextExtents,(XFontSet a, _Xconst char* b, int c, XRectangle
SDL_X11_SYM(char*,XSetLocaleModifiers,(const char *a))
SDL_X11_SYM(char*,Xutf8ResetIC,(XIC a))
SDL_X11_SYM(XFontSetExtents*,XExtentsOfFontSet,(XFontSet a))
SDL_X11_SYM(Bool,XContextDependentDrawing,(XFontSet a))
#endif
#ifndef NO_SHARED_MEMORY
SDL_X11_MODULE(SHM)
SDL_X11_SYM(Status,XShmAttach,(Display* a,XShmSegmentInfo* b))

View File

@@ -28,6 +28,9 @@
#ifdef SDL_USE_LIBDBUS
#include "../../core/linux/SDL_system_theme.h"
#endif
#ifdef HAVE_FRIBIDI_H
#include "../../core/unix/SDL_fribidi.h"
#endif
#include "SDL_x11dyn.h"
#include "SDL_x11toolkit.h"
#include "SDL_x11settings.h"
@@ -70,12 +73,16 @@ typedef struct SDL_ToolkitButtonControlX11
/* Data */
const SDL_MessageBoxButtonData *data;
/* Text */
SDL_Rect text_rect;
int text_a;
int text_d;
int str_sz;
#ifdef HAVE_FRIBIDI_H
char *text;
bool free_text;
#endif
/* Callback */
void *cb_data;
@@ -90,6 +97,12 @@ typedef struct SDL_ToolkitLabelControlX11
int *y;
size_t *szs;
size_t sz;
#ifdef HAVE_FRIBIDI_H
int *x;
int *w;
bool *free_lines;
FriBidiParType *par_types;
#endif
} SDL_ToolkitLabelControlX11;
typedef struct SDL_ToolkitMenuBarControlX11
@@ -109,7 +122,7 @@ typedef struct SDL_ToolkitMenuControlX11
/* Font for icon control */
static const char *g_IconFont = "-*-*-bold-r-normal-*-%d-*-*-*-*-*-iso8859-1[33 88 105]";
#define G_ICONFONT_SIZE 18
#define G_ICONFONT_SIZE 22
/* General UI font */
static const char g_ToolkitFontLatin1[] =
@@ -128,7 +141,7 @@ static const char *g_ToolkitFont[] = {
"-*-*-*-*-*--*-*-*-*-*-*-iso8859-1,*", // just give me anything latin1.
NULL
};
#define G_TOOLKITFONT_SIZE 120
#define G_TOOLKITFONT_SIZE 140
static const SDL_MessageBoxColor g_default_colors[SDL_MESSAGEBOX_COLOR_COUNT] = {
{ 191, 184, 191 }, // SDL_MESSAGEBOX_COLOR_BACKGROUND,
@@ -399,6 +412,10 @@ static void X11Toolkit_InitWindowFonts(SDL_ToolkitWindowX11 *window)
if (!window->font_set) {
goto load_font_traditional;
} else {
#ifdef HAVE_FRIBIDI_H
window->do_shaping = !X11_XContextDependentDrawing(window->font_set);
#endif
}
} else
#endif
@@ -549,27 +566,40 @@ static void X11Toolkit_GetTextWidthHeightForFont(XFontStruct *font, const char *
*ascent = text_structure.ascent;
}
static void X11Toolkit_GetTextWidthHeight(SDL_ToolkitWindowX11 *data, const char *str, int nbytes, int *pwidth, int *pheight, int *ascent, int *font_descent)
static void X11Toolkit_GetTextWidthHeight(SDL_ToolkitWindowX11 *data, const char *str, int nbytes, int *pwidth, int *pheight, int *ascent, int *descent, int *font_height)
{
#ifdef X_HAVE_UTF8_STRING
if (data->utf8) {
XRectangle overall_ink, overall_logical;
X11_Xutf8TextExtents(data->font_set, str, nbytes, &overall_ink, &overall_logical);
*pwidth = overall_logical.width;
*pheight = overall_logical.height;
*ascent = -overall_logical.y;
*font_descent = overall_logical.height - *ascent;
*descent = overall_logical.height - *ascent;
if (font_height) {
XFontSetExtents *extents;
extents = X11_XExtentsOfFontSet(data->font_set);
*font_height = extents->max_logical_extent.height;
}
} else
#endif
{
XCharStruct text_structure;
int font_direction, font_ascent;
int font_direction, font_ascent, font_descent;
X11_XTextExtents(data->font_struct, str, nbytes,
&font_direction, &font_ascent, font_descent,
&font_direction, &font_ascent, &font_descent,
&text_structure);
*pwidth = text_structure.width;
*pheight = text_structure.ascent + text_structure.descent;
*ascent = text_structure.ascent;
*descent = text_structure.descent;
if (font_height) {
*font_height = font_ascent + font_descent;
}
}
}
@@ -778,7 +808,10 @@ SDL_ToolkitWindowX11 *X11Toolkit_CreateWindowStruct(SDL_Window *parent, SDL_Tool
/* Menu windows */
window->popup_windows = NULL;
#ifdef HAVE_FRIBIDI_H
window->fribidi = SDL_FriBidi_Create();
#endif
return window;
}
@@ -1653,7 +1686,7 @@ static void X11Toolkit_CalculateButtonControl(SDL_ToolkitControlX11 *control) {
int text_d;
button_control = (SDL_ToolkitButtonControlX11 *)control;
X11Toolkit_GetTextWidthHeight(control->window, button_control->data->text, button_control->str_sz, &button_control->text_rect.w, &button_control->text_rect.h, &button_control->text_a, &text_d);
X11Toolkit_GetTextWidthHeight(control->window, button_control->data->text, button_control->str_sz, &button_control->text_rect.w, &button_control->text_rect.h, &button_control->text_a, &text_d, NULL);
if (control->do_size) {
control->rect.w = SDL_TOOLKIT_X11_ELEMENT_PADDING_3 * 2 * control->window->iscale + button_control->text_rect.w;
control->rect.h = SDL_TOOLKIT_X11_ELEMENT_PADDING_3 * 2 * control->window->iscale + button_control->text_rect.h;
@@ -1665,8 +1698,16 @@ static void X11Toolkit_CalculateButtonControl(SDL_ToolkitControlX11 *control) {
static void X11Toolkit_DrawButtonControl(SDL_ToolkitControlX11 *control) {
SDL_ToolkitButtonControlX11 *button_control;
char *text;
button_control = (SDL_ToolkitButtonControlX11 *)control;
#ifdef HAVE_FRIBIDI_H
text = button_control->text;
#else
text = (char *)button_control->data->text;
#endif
X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor[SDL_MESSAGEBOX_COLOR_TEXT].pixel);
/* Draw bevel */
if (control->state == SDL_TOOLKIT_CONTROL_STATE_X11_PRESSED || control->state == SDL_TOOLKIT_CONTROL_STATE_X11_PRESSED_HELD) {
@@ -1754,13 +1795,13 @@ static void X11Toolkit_DrawButtonControl(SDL_ToolkitControlX11 *control) {
X11_Xutf8DrawString(control->window->display, control->window->drawable, control->window->font_set, control->window->ctx,
control->rect.x + button_control->text_rect.x,
control->rect.y + button_control->text_rect.y,
button_control->data->text, button_control->str_sz);
text, button_control->str_sz);
} else
#endif
{
X11_XDrawString(control->window->display, control->window->drawable, control->window->ctx,
control->rect.x + button_control->text_rect.x, control->rect.y + button_control->text_rect.y,
button_control->data->text, button_control->str_sz);
text, button_control->str_sz);
}
}
@@ -1773,7 +1814,15 @@ static void X11Toolkit_OnButtonControlStateChange(SDL_ToolkitControlX11 *control
}
}
static void X11Toolkit_DestroyGenericControl(SDL_ToolkitControlX11 *control) {
static void X11Toolkit_DestroyButtonControl(SDL_ToolkitControlX11 *control) {
#ifdef HAVE_FRIBIDI_H
SDL_ToolkitButtonControlX11 *button_control;
button_control = (SDL_ToolkitButtonControlX11 *)control;
if (button_control->free_text) {
SDL_free(button_control->text);
}
#endif
SDL_free(control);
}
@@ -1793,7 +1842,7 @@ SDL_ToolkitControlX11 *X11Toolkit_CreateButtonControl(SDL_ToolkitWindowX11 *wind
base_control->func_calc_size = X11Toolkit_CalculateButtonControl;
base_control->func_draw = X11Toolkit_DrawButtonControl;
base_control->func_on_state_change = X11Toolkit_OnButtonControlStateChange;
base_control->func_free = X11Toolkit_DestroyGenericControl;
base_control->func_free = X11Toolkit_DestroyButtonControl;
base_control->func_on_scale_change = NULL;
base_control->state = SDL_TOOLKIT_CONTROL_STATE_X11_NORMAL;
base_control->selected = false;
@@ -1810,8 +1859,23 @@ SDL_ToolkitControlX11 *X11Toolkit_CreateButtonControl(SDL_ToolkitWindowX11 *wind
base_control->do_size = false;
control->data = data;
control->str_sz = SDL_strlen(control->data->text);
#ifdef HAVE_FRIBIDI_H
if (base_control->window->fribidi) {
control->text = SDL_FriBidi_Process(base_control->window->fribidi, (char *)control->data->text, control->str_sz, base_control->window->do_shaping, NULL);
if (control->text) {
control->free_text = true;
control->str_sz = SDL_strlen(control->text);
} else {
control->text = (char *)control->data->text;
control->free_text = false;
}
} else {
control->text = (char *)control->data->text;
control->free_text = false;
}
#endif
control->cb = NULL;
X11Toolkit_GetTextWidthHeight(base_control->window, control->data->text, control->str_sz, &control->text_rect.w, &control->text_rect.h, &control->text_a, &text_d);
X11Toolkit_GetTextWidthHeight(base_control->window, control->data->text, control->str_sz, &control->text_rect.w, &control->text_rect.h, &control->text_a, &text_d, NULL);
base_control->rect.w = SDL_TOOLKIT_X11_ELEMENT_PADDING_3 * 2 * window->iscale + control->text_rect.w;
base_control->rect.h = SDL_TOOLKIT_X11_ELEMENT_PADDING_3 * 2 * window->iscale + control->text_rect.h;
control->text_rect.x = control->text_rect.y = 0;
@@ -1923,6 +1987,10 @@ void X11Toolkit_DestroyWindow(SDL_ToolkitWindowX11 *data) {
}
#endif
#ifdef HAVE_FRIBIDI_H
SDL_FriBidi_Destroy(data->fribidi);
#endif
SDL_free(data);
}
@@ -1940,20 +2008,27 @@ static int X11Toolkit_CountLinesOfText(const char *text)
static void X11Toolkit_DrawLabelControl(SDL_ToolkitControlX11 *control) {
SDL_ToolkitLabelControlX11 *label_control;
int i;
int x;
label_control = (SDL_ToolkitLabelControlX11 *)control;
X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor[SDL_MESSAGEBOX_COLOR_TEXT].pixel);
for (i = 0; i < label_control->sz; i++) {
x = control->rect.x;
#ifdef HAVE_FRIBIDI_H
if (control->window->fribidi) {
x += label_control->x[i];
}
#endif
#ifdef X_HAVE_UTF8_STRING
if (control->window->utf8) {
X11_Xutf8DrawString(control->window->display, control->window->drawable, control->window->font_set, control->window->ctx,
control->rect.x, control->rect.y + label_control->y[i],
x, control->rect.y + label_control->y[i],
label_control->lines[i], label_control->szs[i]);
} else
#endif
{
X11_XDrawString(control->window->display, control->window->drawable, control->window->ctx,
control->rect.x, control->rect.y + label_control->y[i],
x, control->rect.y + label_control->y[i],
label_control->lines[i], label_control->szs[i]);
}
}
@@ -1963,6 +2038,21 @@ static void X11Toolkit_DestroyLabelControl(SDL_ToolkitControlX11 *control) {
SDL_ToolkitLabelControlX11 *label_control;
label_control = (SDL_ToolkitLabelControlX11 *)control;
#ifdef HAVE_FRIBIDI_H
if (control->window->fribidi) {
int i;
for (i = 0; i < label_control->sz; i++) {
if (label_control->free_lines[i]) {
SDL_free(label_control->lines[i]);
}
}
SDL_free(label_control->x);
SDL_free(label_control->free_lines);
SDL_free(label_control->w);
SDL_free(label_control->par_types);
}
#endif
SDL_free(label_control->lines);
SDL_free(label_control->szs);
SDL_free(label_control->y);
@@ -1971,20 +2061,26 @@ static void X11Toolkit_DestroyLabelControl(SDL_ToolkitControlX11 *control) {
static void X11Toolkit_CalculateLabelControl(SDL_ToolkitControlX11 *base_control) {
SDL_ToolkitLabelControlX11 *control;
int last_h;
int last_h;
int ascent;
int descent;
int font_h;
int w;
int h;
int i;
#ifdef HAVE_FRIBIDI_H
FriBidiParType first_ndn_dir;
int last_ndn;
#endif
last_h = 0;
control = (SDL_ToolkitLabelControlX11 *)base_control;
for (i = 0; i < control->sz; i++) {
X11Toolkit_GetTextWidthHeight(base_control->window, control->lines[i], control->szs[i], &w, &h, &ascent, &descent);
X11Toolkit_GetTextWidthHeight(base_control->window, control->lines[i], control->szs[i], &w, &h, &ascent, &descent, &font_h);
base_control->rect.w = SDL_max(base_control->rect.w, w);
if (i > 0) {
control->y[i] = ascent + descent + control->y[i-1];
control->y[i] = font_h + control->y[i-1];
} else {
control->y[i] = ascent;
}
@@ -1992,12 +2088,56 @@ static void X11Toolkit_CalculateLabelControl(SDL_ToolkitControlX11 *base_control
last_h = h;
}
base_control->rect.h = control->y[control->sz -1] + last_h;
#ifdef HAVE_FRIBIDI_H
if (base_control->window->fribidi) {
first_ndn_dir = FRIBIDI_PAR_LTR;
for (i = 0; i < control->sz; i++) {
if (control->par_types[i] != FRIBIDI_PAR_ON) {
first_ndn_dir = control->par_types[i];
}
}
last_ndn = -1;
for (i = 0; i < control->sz; i++) {
switch (control->par_types[i]) {
case FRIBIDI_PAR_LTR:
control->x[i] = 0;
last_ndn = i;
break;
case FRIBIDI_PAR_RTL:
control->x[i] = base_control->rect.w - control->w[i];
last_ndn = i;
break;
default:
if (last_ndn != -1) {
if (control->par_types[last_ndn] == FRIBIDI_PAR_RTL) {
control->x[i] = base_control->rect.w - control->w[i];
} else {
control->x[i] = 0;
}
} else {
if (first_ndn_dir == FRIBIDI_PAR_RTL) {
control->x[i] = base_control->rect.w - control->w[i];
} else {
control->x[i] = 0;
}
}
}
}
}
#endif
}
SDL_ToolkitControlX11 *X11Toolkit_CreateLabelControl(SDL_ToolkitWindowX11 *window, char *utf8) {
SDL_ToolkitLabelControlX11 *control;
SDL_ToolkitControlX11 *base_control;
int last_h;
#ifdef HAVE_FRIBIDI_H
FriBidiParType first_ndn_dir;
int last_ndn;
#endif
int font_h;
int last_h;
int ascent;
int descent;
int i;
@@ -2028,6 +2168,14 @@ SDL_ToolkitControlX11 *X11Toolkit_CreateLabelControl(SDL_ToolkitWindowX11 *windo
control->lines = (char **)SDL_malloc(sizeof(char *) * control->sz);
control->y = (int *)SDL_calloc(control->sz, sizeof(int));
control->szs = (size_t *)SDL_calloc(control->sz, sizeof(size_t));
#ifdef HAVE_FRIBIDI_H
if (base_control->window->fribidi) {
control->x = (int *)SDL_calloc(control->sz, sizeof(int));
control->free_lines = (bool *)SDL_calloc(control->sz, sizeof(bool));
control->par_types = (FriBidiParType *)SDL_calloc(control->sz, sizeof(FriBidiParType));
control->w = (int *)SDL_calloc(control->sz, sizeof(int));
}
#endif
last_h = 0;
for (i = 0; i < control->sz; i++) {
const char *lf = SDL_strchr(utf8, '\n');
@@ -2035,17 +2183,34 @@ SDL_ToolkitControlX11 *X11Toolkit_CreateLabelControl(SDL_ToolkitWindowX11 *windo
int w;
int h;
control->lines[i] = utf8;
X11Toolkit_GetTextWidthHeight(window, utf8, length, &w, &h, &ascent, &descent);
#ifdef HAVE_FRIBIDI_H
if (base_control->window->fribidi) {
control->lines[i] = SDL_FriBidi_Process(base_control->window->fribidi, utf8, length, base_control->window->do_shaping, &control->par_types[i]);
control->szs[i] = SDL_strlen(control->lines[i]);
control->free_lines[i] = true;
} else
#endif
{
control->lines[i] = utf8;
control->szs[i] = length;
#ifdef HAVE_FRIBIDI_H
control->free_lines[i] = false;
#endif
}
X11Toolkit_GetTextWidthHeight(window, control->lines[i], control->szs[i], &w, &h, &ascent, &descent, &font_h);
#ifdef HAVE_FRIBIDI_H
if (base_control->window->fribidi) {
control->w[i] = w;
}
#endif
base_control->rect.w = SDL_max(base_control->rect.w, w);
control->szs[i] = length;
if (lf && (lf > utf8) && (lf[-1] == '\r')) {
if (lf && (lf > control->lines[i]) && (lf[-1] == '\r')) {
control->szs[i]--;
}
if (i > 0) {
control->y[i] = ascent + descent + control->y[i-1];
control->y[i] = font_h + control->y[i-1];
} else {
control->y[i] = ascent;
}
@@ -2057,6 +2222,44 @@ SDL_ToolkitControlX11 *X11Toolkit_CreateLabelControl(SDL_ToolkitWindowX11 *windo
}
}
base_control->rect.h = control->y[control->sz -1] + last_h;
#ifdef HAVE_FRIBIDI_H
if (base_control->window->fribidi) {
first_ndn_dir = FRIBIDI_PAR_LTR;
for (i = 0; i < control->sz; i++) {
if (control->par_types[i] != FRIBIDI_PAR_ON) {
first_ndn_dir = control->par_types[i];
}
}
last_ndn = -1;
for (i = 0; i < control->sz; i++) {
switch (control->par_types[i]) {
case FRIBIDI_PAR_LTR:
control->x[i] = 0;
last_ndn = i;
break;
case FRIBIDI_PAR_RTL:
control->x[i] = base_control->rect.w - control->w[i];
last_ndn = i;
break;
default:
if (last_ndn != -1) {
if (control->par_types[last_ndn] == FRIBIDI_PAR_RTL) {
control->x[i] = base_control->rect.w - control->w[i];
} else {
control->x[i] = 0;
}
} else {
if (first_ndn_dir == FRIBIDI_PAR_RTL) {
control->x[i] = base_control->rect.w - control->w[i];
} else {
control->x[i] = 0;
}
}
}
}
}
#endif
X11Toolkit_AddControlToWindow(window, base_control);

View File

@@ -29,6 +29,9 @@
#include "SDL_x11settings.h"
#include "SDL_x11toolkit.h"
#include "xsettings-client.h"
#ifdef HAVE_FRIBIDI_H
#include "../../core/unix/SDL_fribidi.h"
#endif
#ifdef SDL_VIDEO_DRIVER_X11
@@ -95,7 +98,6 @@ typedef struct SDL_ToolkitWindowX11
Bool shm_pixmap;
#endif
bool utf8;
/* Atoms */
Atom wm_protocols;
Atom wm_delete_message;
@@ -155,6 +157,12 @@ typedef struct SDL_ToolkitWindowX11
bool draw;
bool close;
long event_mask;
#ifdef HAVE_FRIBIDI_H
/* BIDI engine */
SDL_FriBidi *fribidi;
bool do_shaping;
#endif
} SDL_ToolkitWindowX11;
typedef enum SDL_ToolkitControlStateX11