RetroArch/gfx/font_driver.c

1166 lines
32 KiB
C
Raw Normal View History

2012-04-21 21:13:50 +00:00
/* RetroArch - A frontend for libretro.
2014-01-01 00:50:59 +00:00
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
2017-01-22 12:40:32 +00:00
* Copyright (C) 2011-2017 - Daniel De Matteis
*
2012-04-21 21:13:50 +00:00
* RetroArch is free software: you can redistribute it and/or modify it under the terms
2012-02-12 14:23:35 +00:00
* of the GNU General Public License as published by the Free Software Found-
* ation, either version 3 of the License, or (at your option) any later version.
*
2012-04-21 21:13:50 +00:00
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
2012-02-12 14:23:35 +00:00
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
2012-04-21 21:31:57 +00:00
* You should have received a copy of the GNU General Public License along with RetroArch.
2012-02-12 14:23:35 +00:00
* If not, see <http://www.gnu.org/licenses/>.
*/
2018-01-04 13:42:13 +00:00
#include <stdlib.h>
#include <math.h>
2016-09-06 21:47:05 +00:00
#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif
2018-01-04 13:42:13 +00:00
#include "font_driver.h"
#include "video_thread_wrapper.h"
/* TODO/FIXME - global */
static void *video_font_driver = NULL;
int font_renderer_create_default(
const font_renderer_driver_t **drv,
void **handle,
const char *font_path, unsigned font_size)
{
static const font_renderer_driver_t *font_backends[] = {
#ifdef HAVE_FREETYPE
&freetype_font_renderer,
#endif
#if defined(__APPLE__) && defined(HAVE_CORETEXT)
&coretext_font_renderer,
#endif
#ifdef HAVE_STB_FONT
2020-06-20 21:05:20 +00:00
#if defined(VITA) || defined(ORBIS) || defined(WIIU) || defined(ANDROID) || (defined(_WIN32) && !defined(_XBOX) && !defined(_MSC_VER) && _MSC_VER >= 1400) || (defined(_WIN32) && !defined(_XBOX) && defined(_MSC_VER)) || defined(HAVE_LIBNX) || defined(__linux__) || defined (HAVE_EMSCRIPTEN) || defined(__APPLE__) || defined(HAVE_ODROIDGO2) || defined(__PS3__)
&stb_unicode_font_renderer,
2016-11-05 15:20:18 +00:00
#else
&stb_unicode_font_renderer,
2016-11-05 15:20:18 +00:00
#endif
#endif
&bitmap_font_renderer,
NULL
};
unsigned i;
for (i = 0; font_backends[i]; i++)
{
const char *path = font_path;
if (!path)
path = font_backends[i]->get_default_font();
if (!path)
continue;
*handle = font_backends[i]->init(path, font_size);
if (*handle)
{
*drv = font_backends[i];
return 1;
}
}
2018-07-13 22:54:14 +00:00
*drv = NULL;
*handle = NULL;
return 0;
}
2012-02-12 14:23:35 +00:00
#ifdef HAVE_D3D8
static bool d3d8_font_init_first(
const void **font_driver, void **font_handle,
void *video_data, const char *font_path,
float font_size, bool is_threaded)
{
static const font_renderer_t *d3d8_font_backends[] = {
#if defined(_XBOX1)
&d3d_xdk1_font,
#endif
NULL
};
unsigned i;
for (i = 0; i < ARRAY_SIZE(d3d8_font_backends); i++)
{
void *data = d3d8_font_backends[i] ? d3d8_font_backends[i]->init(
video_data, font_path, font_size,
is_threaded) : NULL;
if (!data)
continue;
*font_driver = d3d8_font_backends[i];
*font_handle = data;
return true;
}
return false;
}
#endif
#ifdef HAVE_D3D9
static bool d3d9_font_init_first(
const void **font_driver, void **font_handle,
void *video_data, const char *font_path,
float font_size, bool is_threaded)
2012-12-15 02:35:04 +00:00
{
static const font_renderer_t *d3d9_font_backends[] = {
#if defined(_WIN32) && defined(HAVE_D3DX)
&d3d_win32_font,
#endif
NULL
};
unsigned i;
for (i = 0; i < ARRAY_SIZE(d3d9_font_backends); i++)
2012-12-15 02:35:04 +00:00
{
void *data = d3d9_font_backends[i] ? d3d9_font_backends[i]->init(
video_data, font_path, font_size,
2018-01-04 13:42:13 +00:00
is_threaded) : NULL;
if (!data)
continue;
*font_driver = d3d9_font_backends[i];
*font_handle = data;
return true;
2012-12-15 02:35:04 +00:00
}
return false;
2012-12-15 02:35:04 +00:00
}
#endif
2019-04-22 21:30:24 +00:00
#ifdef HAVE_OPENGL1
static bool gl1_font_init_first(
const void **font_driver, void **font_handle,
void *video_data, const char *font_path,
float font_size, bool is_threaded)
{
void *data = gl1_raster_font.init(
video_data, font_path, font_size,
is_threaded);
if (!data)
return false;
*font_driver = &gl1_raster_font;
*font_handle = data;
return true;
}
2019-04-22 21:30:24 +00:00
#endif
2019-04-22 21:30:24 +00:00
#if defined(HAVE_OPENGL)
static bool gl_font_init_first(
const void **font_driver, void **font_handle,
void *video_data, const char *font_path,
float font_size, bool is_threaded)
{
void *data = gl2_raster_font.init(
video_data, font_path, font_size,
is_threaded);
if (!data)
return false;
*font_driver = &gl2_raster_font;
*font_handle = data;
return true;
}
#endif
#ifdef HAVE_OPENGL_CORE
static bool gl3_font_init_first(
const void **font_driver, void **font_handle,
void *video_data, const char *font_path,
float font_size, bool is_threaded)
{
void *data = gl3_raster_font.init(
video_data, font_path, font_size,
is_threaded);
if (!data)
return false;
*font_driver = &gl3_raster_font;
*font_handle = data;
return true;
}
#endif
2016-12-01 17:13:36 +00:00
#ifdef HAVE_CACA
static bool caca_font_init_first(
const void **font_driver, void **font_handle,
void *video_data, const char *font_path,
float font_size, bool is_threaded)
2016-12-01 17:13:36 +00:00
{
void *data = caca_font.init(
video_data, font_path, font_size,
is_threaded);
2016-12-01 17:13:36 +00:00
if (!data)
return false;
2016-12-01 17:13:36 +00:00
*font_driver = &caca_font;
*font_handle = data;
return true;
2016-12-01 17:13:36 +00:00
}
#endif
2018-07-12 20:55:08 +00:00
#ifdef HAVE_SIXEL
static bool sixel_font_init_first(
const void **font_driver, void **font_handle,
void *video_data, const char *font_path,
float font_size, bool is_threaded)
{
void *data = sixel_font.init(
video_data, font_path, font_size,
is_threaded);
2018-07-12 20:55:08 +00:00
if (!data)
return false;
2018-07-12 20:55:08 +00:00
*font_driver = &sixel_font;
*font_handle = data;
return true;
2018-07-12 20:55:08 +00:00
}
#endif
2017-01-21 22:41:20 +00:00
#ifdef DJGPP
static bool vga_font_init_first(
const void **font_driver, void **font_handle,
void *video_data, const char *font_path,
float font_size, bool is_threaded)
2017-01-21 22:41:20 +00:00
{
void *data = vga_font.init(
video_data, font_path, font_size,
is_threaded);
2017-01-21 22:41:20 +00:00
if (!data)
return false;
2017-01-21 22:41:20 +00:00
*font_driver = &vga_font;
*font_handle = data;
return true;
2017-01-21 22:41:20 +00:00
}
#endif
2019-07-11 11:18:38 +00:00
#ifdef HAVE_GDI
#if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__)
2017-01-04 07:07:19 +00:00
static bool gdi_font_init_first(
const void **font_driver, void **font_handle,
void *video_data, const char *font_path,
float font_size, bool is_threaded)
2017-01-04 07:07:19 +00:00
{
void *data = gdi_font.init(
video_data, font_path, font_size,
is_threaded);
2017-01-04 07:07:19 +00:00
if (!data)
return false;
2017-01-04 07:07:19 +00:00
*font_driver = &gdi_font;
*font_handle = data;
return true;
2017-01-04 07:07:19 +00:00
}
#endif
2019-07-11 11:18:38 +00:00
#endif
2017-01-04 07:07:19 +00:00
2016-02-16 19:24:00 +00:00
#ifdef HAVE_VULKAN
static bool vulkan_font_init_first(
const void **font_driver, void **font_handle,
void *video_data, const char *font_path,
float font_size, bool is_threaded)
2016-02-16 19:24:00 +00:00
{
void *data = vulkan_raster_font.init(video_data,
font_path, font_size,
is_threaded);
2016-02-16 19:24:00 +00:00
if (!data)
return false;
2016-02-16 19:24:00 +00:00
*font_driver = &vulkan_raster_font;
*font_handle = data;
return true;
2016-02-16 19:24:00 +00:00
}
#endif
#ifdef HAVE_METAL
static bool metal_font_init_first(
const void **font_driver, void **font_handle,
void *video_data, const char *font_path,
float font_size, bool is_threaded)
{
void *data = metal_raster_font.init(video_data,
font_path, font_size,
is_threaded);
if (!data)
return false;
*font_driver = &metal_raster_font;
*font_handle = data;
return true;
}
#endif
2018-04-21 01:27:41 +00:00
#ifdef HAVE_D3D10
static bool d3d10_font_init_first(
const void **font_driver, void **font_handle,
void *video_data, const char *font_path,
float font_size, bool is_threaded)
{
void *data = d3d10_font.init(video_data,
font_path, font_size,
is_threaded);
2018-04-21 01:27:41 +00:00
if (!data)
return false;
2018-04-21 01:27:41 +00:00
*font_driver = &d3d10_font;
*font_handle = data;
return true;
2018-04-21 01:27:41 +00:00
}
#endif
2018-01-24 19:51:19 +00:00
#ifdef HAVE_D3D11
static bool d3d11_font_init_first(
const void **font_driver, void **font_handle,
void *video_data, const char *font_path,
float font_size, bool is_threaded)
{
void *data = d3d11_font.init(video_data,
font_path, font_size,
is_threaded);
2018-01-24 19:51:19 +00:00
if (!data)
return false;
2018-01-24 19:51:19 +00:00
*font_driver = &d3d11_font;
*font_handle = data;
return true;
2018-01-24 19:51:19 +00:00
}
#endif
2018-02-07 20:59:18 +00:00
#ifdef HAVE_D3D12
static bool d3d12_font_init_first(
const void **font_driver, void **font_handle,
void *video_data, const char *font_path,
float font_size, bool is_threaded)
{
void *data = d3d12_font.init(video_data,
font_path, font_size,
is_threaded);
2018-02-07 20:59:18 +00:00
if (!data)
return false;
2018-02-07 20:59:18 +00:00
*font_driver = &d3d12_font;
*font_handle = data;
return true;
2018-02-07 20:59:18 +00:00
}
#endif
2019-01-07 20:49:55 +00:00
#ifdef PS2
static bool ps2_font_init_first(
const void **font_driver, void **font_handle,
void *video_data, const char *font_path,
float font_size, bool is_threaded)
{
void *data = ps2_font.init(
video_data, font_path, font_size,
is_threaded);
2019-01-07 20:49:55 +00:00
if (!data)
return false;
2019-01-07 20:49:55 +00:00
*font_driver = &ps2_font;
*font_handle = data;
return true;
2019-01-07 20:49:55 +00:00
}
#endif
2015-10-01 22:11:54 +00:00
#ifdef HAVE_VITA2D
static bool vita2d_font_init_first(
const void **font_driver, void **font_handle,
void *video_data, const char *font_path,
float font_size, bool is_threaded)
2015-10-01 22:11:54 +00:00
{
void *data = vita2d_vita_font.init(
video_data, font_path, font_size,
is_threaded);
2015-10-01 22:11:54 +00:00
if (!data)
return false;
2015-10-01 22:11:54 +00:00
*font_driver = &vita2d_vita_font;
*font_handle = data;
return true;
2015-10-01 22:11:54 +00:00
}
#endif
#ifdef _3DS
static bool ctr_font_init_first(
const void **font_driver, void **font_handle,
void *video_data, const char *font_path,
float font_size, bool is_threaded)
{
void *data = ctr_font.init(
video_data, font_path, font_size,
is_threaded);
if (!data)
return false;
*font_driver = &ctr_font;
*font_handle = data;
return true;
}
#endif
2019-02-03 23:49:35 +00:00
#ifdef HAVE_LIBNX
2018-09-26 23:18:07 +00:00
static bool switch_font_init_first(
const void **font_driver, void **font_handle,
void *video_data, const char *font_path,
float font_size, bool is_threaded)
{
void *data = switch_font.init(
video_data, font_path, font_size,
is_threaded);
2018-09-26 23:18:07 +00:00
if (!data)
return false;
2018-09-26 23:18:07 +00:00
*font_driver = &switch_font;
*font_handle = data;
return true;
2018-09-26 23:18:07 +00:00
}
#endif
2017-05-21 02:05:41 +00:00
#ifdef WIIU
static bool wiiu_font_init_first(
const void **font_driver, void **font_handle,
void *video_data, const char *font_path,
float font_size, bool is_threaded)
{
void *data = wiiu_font.init(
video_data, font_path, font_size,
is_threaded);
2017-05-21 02:05:41 +00:00
if (!data)
return false;
2017-05-21 02:05:41 +00:00
*font_driver = &wiiu_font;
*font_handle = data;
return true;
2017-05-21 02:05:41 +00:00
}
#endif
#ifdef __PSL1GHT__
static bool rsx_font_init_first(
const void **font_driver, void **font_handle,
void *video_data, const char *font_path,
float font_size, bool is_threaded)
{
void *data = rsx_font.init(
video_data, font_path, font_size,
is_threaded);
if (!data)
return false;
*font_driver = &rsx_font;
*font_handle = data;
return true;
}
#endif
2016-02-06 20:51:37 +00:00
static bool font_init_first(
const void **font_driver, void **font_handle,
void *video_data, const char *font_path, float font_size,
enum font_driver_render_api api, bool is_threaded)
{
if (font_path && !font_path[0])
font_path = NULL;
switch (api)
{
#ifdef HAVE_OPENGL1
case FONT_DRIVER_RENDER_OPENGL1_API:
return gl1_font_init_first(font_driver, font_handle,
video_data, font_path, font_size, is_threaded);
2015-10-01 22:11:54 +00:00
#endif
2019-04-22 21:30:24 +00:00
#ifdef HAVE_OPENGL
case FONT_DRIVER_RENDER_OPENGL_API:
return gl_font_init_first(font_driver, font_handle,
video_data, font_path, font_size, is_threaded);
#endif
#ifdef HAVE_OPENGL_CORE
case FONT_DRIVER_RENDER_OPENGL_CORE_API:
return gl3_font_init_first(font_driver, font_handle,
video_data, font_path, font_size, is_threaded);
#endif
2016-02-16 19:24:00 +00:00
#ifdef HAVE_VULKAN
case FONT_DRIVER_RENDER_VULKAN_API:
return vulkan_font_init_first(font_driver, font_handle,
video_data, font_path, font_size, is_threaded);
2016-02-16 19:24:00 +00:00
#endif
#ifdef HAVE_METAL
case FONT_DRIVER_RENDER_METAL_API:
return metal_font_init_first(font_driver, font_handle,
video_data, font_path, font_size, is_threaded);
#endif
#ifdef HAVE_D3D8
case FONT_DRIVER_RENDER_D3D8_API:
return d3d8_font_init_first(font_driver, font_handle,
video_data, font_path, font_size, is_threaded);
#endif
#ifdef HAVE_D3D9
case FONT_DRIVER_RENDER_D3D9_API:
return d3d9_font_init_first(font_driver, font_handle,
video_data, font_path, font_size, is_threaded);
#endif
2018-04-21 01:27:41 +00:00
#ifdef HAVE_D3D10
case FONT_DRIVER_RENDER_D3D10_API:
return d3d10_font_init_first(font_driver, font_handle,
video_data, font_path, font_size, is_threaded);
#endif
2018-01-24 19:51:19 +00:00
#ifdef HAVE_D3D11
case FONT_DRIVER_RENDER_D3D11_API:
return d3d11_font_init_first(font_driver, font_handle,
video_data, font_path, font_size, is_threaded);
#endif
2018-02-07 20:59:18 +00:00
#ifdef HAVE_D3D12
case FONT_DRIVER_RENDER_D3D12_API:
return d3d12_font_init_first(font_driver, font_handle,
video_data, font_path, font_size, is_threaded);
#endif
2015-10-01 22:11:54 +00:00
#ifdef HAVE_VITA2D
case FONT_DRIVER_RENDER_VITA2D:
return vita2d_font_init_first(font_driver, font_handle,
video_data, font_path, font_size, is_threaded);
#endif
2019-01-07 20:49:55 +00:00
#ifdef PS2
case FONT_DRIVER_RENDER_PS2:
return ps2_font_init_first(font_driver, font_handle,
video_data, font_path, font_size, is_threaded);
#endif
#ifdef _3DS
case FONT_DRIVER_RENDER_CTR:
return ctr_font_init_first(font_driver, font_handle,
video_data, font_path, font_size, is_threaded);
2016-12-01 17:13:36 +00:00
#endif
2017-05-21 02:05:41 +00:00
#ifdef WIIU
case FONT_DRIVER_RENDER_WIIU:
return wiiu_font_init_first(font_driver, font_handle,
video_data, font_path, font_size, is_threaded);
#endif
2016-12-01 17:13:36 +00:00
#ifdef HAVE_CACA
case FONT_DRIVER_RENDER_CACA:
return caca_font_init_first(font_driver, font_handle,
video_data, font_path, font_size, is_threaded);
2017-01-04 07:07:19 +00:00
#endif
2018-07-12 20:55:08 +00:00
#ifdef HAVE_SIXEL
case FONT_DRIVER_RENDER_SIXEL:
return sixel_font_init_first(font_driver, font_handle,
video_data, font_path, font_size, is_threaded);
#endif
2018-09-26 23:18:07 +00:00
#ifdef HAVE_LIBNX
case FONT_DRIVER_RENDER_SWITCH:
return switch_font_init_first(font_driver, font_handle,
video_data, font_path, font_size, is_threaded);
#endif
#ifdef __PSL1GHT__
case FONT_DRIVER_RENDER_RSX:
return rsx_font_init_first(font_driver, font_handle,
video_data, font_path, font_size, is_threaded);
#endif
2019-07-11 11:18:38 +00:00
#ifdef HAVE_GDI
#if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__)
2017-01-04 07:07:19 +00:00
case FONT_DRIVER_RENDER_GDI:
return gdi_font_init_first(font_driver, font_handle,
video_data, font_path, font_size, is_threaded);
2017-01-21 22:41:20 +00:00
#endif
2019-07-11 11:18:38 +00:00
#endif
2017-01-21 22:41:20 +00:00
#ifdef DJGPP
case FONT_DRIVER_RENDER_VGA:
return vga_font_init_first(font_driver, font_handle,
video_data, font_path, font_size, is_threaded);
#endif
case FONT_DRIVER_RENDER_DONT_CARE:
/* TODO/FIXME - lookup graphics driver's 'API' */
break;
default:
break;
}
return false;
}
2018-02-05 19:54:55 +00:00
#ifdef HAVE_LANGEXTRA
/* ASCII: 0xxxxxxx (c & 0x80) == 0x00
2018-02-05 19:54:55 +00:00
* other start: 11xxxxxx (c & 0xC0) == 0xC0
* other cont: 10xxxxxx (c & 0xC0) == 0x80
* Neutral:
* 0020 - 002F: 001xxxxx (c & 0xE0) == 0x20
* misc. white space:
* 2000 - 200D: 11100010 10000000 1000xxxx (c[2] < 0x8E) (3 bytes)
* Hebrew:
* 0591 - 05F4: 1101011x (c & 0xFE) == 0xD6 (2 bytes)
2018-02-05 19:54:55 +00:00
* Arabic:
* 0600 - 06FF: 110110xx (c & 0xFC) == 0xD8 (2 bytes)
*/
2018-02-05 19:54:55 +00:00
/* clang-format off */
#define IS_ASCII(p) ((*(p)&0x80) == 0x00)
#define IS_MBSTART(p) ((*(p)&0xC0) == 0xC0)
#define IS_MBCONT(p) ((*(p)&0xC0) == 0x80)
#define IS_DIR_NEUTRAL(p) ((*(p)&0xE0) == 0x20)
#define IS_HEBREW(p) ((*(p)&0xFE) == 0xD6)
#define IS_ARABIC(p) ((*(p)&0xFC) == 0xD8)
#define IS_RTL(p) (IS_HEBREW(p) || IS_ARABIC(p))
#define GET_ID_ARABIC(p) (((unsigned char)(p)[0] << 6) | ((unsigned char)(p)[1] & 0x3F))
2018-02-05 19:54:55 +00:00
/* Checks for miscellaneous whitespace characters in the range U+2000 to U+200D */
static INLINE unsigned is_misc_ws(const unsigned char* src)
{
unsigned res = 0;
if (*(src) == 0xE2) /* first byte */
{
src++;
if (*(src) == 0x80) /* second byte */
{
src++;
res = (*(src) < 0x8E); /* third byte */
}
}
return res;
}
static INLINE unsigned font_get_arabic_replacement(
const char* src, const char* start)
2018-02-05 19:54:55 +00:00
{
/* 0x0620 to 0x064F */
static const unsigned arabic_shape_map[0x100][0x4] = {
{ 0 }, { 0 }, { 0 }, { 0 }, /* 0x0600 */
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 }, /* 0x0610 */
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, /* 0x0620 */
{ 0xFE80 },
{ 0xFE81, 0xFE82 },
{ 0xFE83, 0xFE84 },
{ 0xFE85, 0xFE86 },
{ 0xFE87, 0xFE88 },
{ 0xFE89, 0xFE8A, 0xFE8B, 0xFE8C },
{ 0xFE8D, 0xFE8E },
{ 0xFE8F, 0xFE90, 0xFE91, 0xFE92 },
{ 0xFE93, 0xFE94 },
{ 0xFE95, 0xFE96, 0xFE97, 0xFE98 },
{ 0xFE99, 0xFE9A, 0xFE9B, 0xFE9C },
{ 0xFE9D, 0xFE9E, 0xFE9F, 0xFEA0 },
{ 0xFEA1, 0xFEA2, 0xFEA3, 0xFEA4 },
{ 0xFEA5, 0xFEA6, 0xFEA7, 0xFEA8 },
{ 0xFEA9, 0xFEAA },
{ 0xFEAB, 0xFEAC }, /* 0x0630 */
{ 0xFEAD, 0xFEAE },
{ 0xFEAF, 0xFEB0 },
{ 0xFEB1, 0xFEB2, 0xFEB3, 0xFEB4 },
{ 0xFEB5, 0xFEB6, 0xFEB7, 0xFEB8 },
{ 0xFEB9, 0xFEBA, 0xFEBB, 0xFEBC },
{ 0xFEBD, 0xFEBE, 0xFEBF, 0xFEC0 },
{ 0xFEC1, 0xFEC2, 0xFEC3, 0xFEC4 },
{ 0xFEC5, 0xFEC6, 0xFEC7, 0xFEC8 },
{ 0xFEC9, 0xFECA, 0xFECB, 0xFECC },
{ 0xFECD, 0xFECE, 0xFECF, 0xFED0 },
{ 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, /* 0x0640 */
{ 0xFED1, 0xFED2, 0xFED3, 0xFED4 },
{ 0xFED5, 0xFED6, 0xFED7, 0xFED8 },
{ 0xFED9, 0xFEDA, 0xFEDB, 0xFEDC },
{ 0xFEDD, 0xFEDE, 0xFEDF, 0xFEE0 },
{ 0xFEE1, 0xFEE2, 0xFEE3, 0xFEE4 },
{ 0xFEE5, 0xFEE6, 0xFEE7, 0xFEE8 },
{ 0xFEE9, 0xFEEA, 0xFEEB, 0xFEEC },
{ 0xFEED, 0xFEEE },
{ 0xFEEF, 0xFEF0, 0xFBE8, 0xFBE9 },
{ 0xFEF1, 0xFEF2, 0xFEF3, 0xFEF4 },
{ 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 }, /* 0x0650 */
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 }, /* 0x0660 */
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 }, /* 0x0670 */
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 },
{ 0xFB56, 0xFB57, 0xFB58, 0xFB59 },
{ 0 },
{ 0 }, { 0 }, { 0 }, { 0 }, /* 0x0680 */
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 }, /* 0x0690 */
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 }, /* 0x06A0 */
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 },
{ 0xFB8E, 0xFB8F, 0xFB90, 0xFB91 },
{ 0 }, { 0 },
{ 0 }, { 0 }, { 0 },
{ 0xFB92, 0xFB93, 0xFB94, 0xFB95 },
2018-02-05 19:54:55 +00:00
{ 0 }, { 0 }, { 0 }, { 0 }, /* 0x06B0 */
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
2018-02-05 19:54:55 +00:00
{ 0 }, { 0 }, { 0 }, { 0 }, /* 0x06C0 */
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
2018-02-05 19:54:55 +00:00
{ 0xFBFC, 0xFBFD, 0xFBFE, 0xFBFF },
{ 0 }, { 0 }, { 0 },
2018-02-05 19:54:55 +00:00
{ 0 }, { 0 }, { 0 }, { 0 }, /* 0x06D0 */
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 }, /* 0x06E0 */
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 }, /* 0x06F0 */
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
{ 0 }, { 0 }, { 0 }, { 0 },
};
unsigned result = 0;
bool prev_connected = false;
bool next_connected = false;
unsigned char id = GET_ID_ARABIC(src);
const char* prev = src - 2;
const char* next = src + 2;
if (IS_ARABIC(prev) && (prev >= start))
{
unsigned char prev_id = GET_ID_ARABIC(prev);
/* nonspacing diacritics 0x4b -- 0x5f */
while (prev_id > 0x4A && prev_id < 0x60)
{
prev -= 2;
if ((prev >= start) && IS_ARABIC(prev))
prev_id = GET_ID_ARABIC(prev);
else
break;
2018-02-05 19:54:55 +00:00
}
if (prev_id == 0x44) /* Arabic Letter Lam */
2018-02-05 19:54:55 +00:00
{
unsigned char prev2_id = 0;
const char* prev2 = prev - 2;
if (prev2 >= start)
prev2_id = (prev2[0] << 6) | (prev2[1] & 0x3F);
2018-02-05 19:54:55 +00:00
/* nonspacing diacritics 0x4b -- 0x5f */
while (prev2_id > 0x4A && prev2_id < 0x60)
{
prev2 -= 2;
if ((prev2 >= start) && IS_ARABIC(prev2))
prev2_id = GET_ID_ARABIC(prev2);
else
break;
}
prev_connected = !!arabic_shape_map[prev2_id][2];
switch (id)
{
case 0x22: /* Arabic Letter Alef with Madda Above */
return 0xFEF5 + prev_connected;
case 0x23: /* Arabic Letter Alef with Hamza Above */
return 0xFEF7 + prev_connected;
case 0x25: /* Arabic Letter Alef with Hamza Below */
return 0xFEF9 + prev_connected;
case 0x27: /* Arabic Letter Alef */
return 0xFEFB + prev_connected;
}
2018-02-05 19:54:55 +00:00
}
prev_connected = !!arabic_shape_map[prev_id][2];
2018-02-05 19:54:55 +00:00
}
if (IS_ARABIC(next))
{
unsigned char next_id = GET_ID_ARABIC(next);
/* nonspacing diacritics 0x4b -- 0x5f */
while (next_id > 0x4A && next_id < 0x60)
{
next += 2;
if (!IS_ARABIC(next))
break;
next_id = GET_ID_ARABIC(next);
}
next_connected = !!arabic_shape_map[next_id][1];
}
if ((result =
arabic_shape_map[id][prev_connected | (next_connected <<
1)]))
return result;
return arabic_shape_map[id][prev_connected];
2018-02-05 19:54:55 +00:00
}
/* clang-format on */
2018-02-05 19:54:55 +00:00
Implements small buffer optimization in font_driver_reshape_msg() Use a stack-allocated 64 bytes long buffer to avoid so many temp heap allocations when the menu is up. This size is more than enough store 75% of the return values from msg_hash_to_str and 50% of the returned values from msg_hash_get_help of any currently supported language (includes fallback to English). String size per type: count mean std ... 50% 75% max type ... msg_hash_get_help 83885.0 95.295476 106.331779 ... 54.0 103.0 842.0 msg_hash_to_str 83903.0 27.737959 33.389184 ... 19.0 31.0 440.0 string size per type and language: count mean std ... 50% 75% max type language ... msg_hash_get_help 0 4415.0 89.922310 96.873902 ... 55.0 101.0 590.0 1 4415.0 97.555606 118.031412 ... 55.0 101.0 842.0 2 4415.0 118.459570 127.811760 ... 75.0 131.0 774.0 3 4415.0 111.978256 112.702991 ... 68.0 125.0 651.0 4 4415.0 106.040544 111.360658 ... 62.0 124.0 776.0 5 4415.0 100.129105 114.437432 ... 62.0 103.0 688.0 6 4415.0 32.987769 31.047851 ... 28.0 28.0 595.0 7 4415.0 109.366025 124.717259 ... 71.0 121.0 720.0 8 4415.0 98.023783 105.149942 ... 62.0 105.0 610.0 9 4415.0 93.834428 104.433820 ... 55.0 101.0 637.0 10 4415.0 93.657984 96.884429 ... 55.0 101.0 594.0 11 4415.0 93.452775 104.040553 ... 48.0 100.0 583.0 12 4415.0 89.729558 104.062959 ... 50.0 100.0 550.0 13 4415.0 91.462514 95.968107 ... 55.0 101.0 590.0 14 4415.0 92.062741 97.959207 ... 55.0 101.0 611.0 15 4415.0 92.597055 97.190835 ... 56.0 101.0 600.0 16 4415.0 92.088109 98.110738 ... 55.0 101.0 608.0 17 4415.0 102.483126 106.379639 ... 65.0 110.0 652.0 18 4415.0 104.782786 114.025678 ... 65.0 112.0 646.0 msg_hash_to_str 0 4415.0 24.591619 29.148312 ... 18.0 28.0 346.0 1 4416.0 31.247736 36.302532 ... 21.0 36.0 352.0 2 4416.0 31.853714 39.332395 ... 21.0 36.0 418.0 3 4416.0 28.270833 33.300996 ... 21.0 32.0 429.0 4 4416.0 27.139040 31.905206 ... 19.0 31.0 346.0 5 4416.0 27.380435 32.314188 ... 19.0 31.0 346.0 6 4416.0 25.028080 29.188490 ... 19.0 28.0 346.0 7 4416.0 29.660553 35.283592 ... 21.0 33.0 393.0 8 4416.0 27.685915 32.707466 ... 20.0 31.0 346.0 9 4416.0 34.786685 43.587766 ... 21.0 39.0 414.0 10 4416.0 28.769928 34.428596 ... 20.0 32.0 440.0 11 4416.0 24.407609 28.690934 ... 18.0 27.0 346.0 12 4416.0 23.970788 27.075638 ... 18.0 28.0 346.0 13 4416.0 24.587636 29.146213 ... 18.0 28.0 346.0 14 4416.0 27.642889 33.300451 ... 20.0 31.0 346.0 15 4416.0 25.036005 29.159115 ... 18.0 28.0 346.0 16 4416.0 24.732111 29.134002 ... 18.0 28.0 346.0 17 4416.0 32.068161 38.807095 ... 21.0 36.0 407.0 18 4416.0 28.160779 34.013300 ... 20.0 31.0 432.0
2020-05-23 22:15:32 +00:00
static char* font_driver_reshape_msg(const char* msg, unsigned char *buffer, size_t buffer_size)
2018-02-05 19:54:55 +00:00
{
const unsigned char *src = (const unsigned char*)msg;
bool reverse = false;
size_t msg_size = (strlen(msg) * 2) + 1;
/* Fallback to heap allocated buffer if the buffer is too small */
/* worst case transformations are 2 bytes to 4 bytes -- aliaspider */
unsigned char* dst_buffer = (buffer_size < msg_size)
? (unsigned char*)malloc(msg_size)
: buffer;
unsigned char *dst = (unsigned char*)dst_buffer;
Implements small buffer optimization in font_driver_reshape_msg() Use a stack-allocated 64 bytes long buffer to avoid so many temp heap allocations when the menu is up. This size is more than enough store 75% of the return values from msg_hash_to_str and 50% of the returned values from msg_hash_get_help of any currently supported language (includes fallback to English). String size per type: count mean std ... 50% 75% max type ... msg_hash_get_help 83885.0 95.295476 106.331779 ... 54.0 103.0 842.0 msg_hash_to_str 83903.0 27.737959 33.389184 ... 19.0 31.0 440.0 string size per type and language: count mean std ... 50% 75% max type language ... msg_hash_get_help 0 4415.0 89.922310 96.873902 ... 55.0 101.0 590.0 1 4415.0 97.555606 118.031412 ... 55.0 101.0 842.0 2 4415.0 118.459570 127.811760 ... 75.0 131.0 774.0 3 4415.0 111.978256 112.702991 ... 68.0 125.0 651.0 4 4415.0 106.040544 111.360658 ... 62.0 124.0 776.0 5 4415.0 100.129105 114.437432 ... 62.0 103.0 688.0 6 4415.0 32.987769 31.047851 ... 28.0 28.0 595.0 7 4415.0 109.366025 124.717259 ... 71.0 121.0 720.0 8 4415.0 98.023783 105.149942 ... 62.0 105.0 610.0 9 4415.0 93.834428 104.433820 ... 55.0 101.0 637.0 10 4415.0 93.657984 96.884429 ... 55.0 101.0 594.0 11 4415.0 93.452775 104.040553 ... 48.0 100.0 583.0 12 4415.0 89.729558 104.062959 ... 50.0 100.0 550.0 13 4415.0 91.462514 95.968107 ... 55.0 101.0 590.0 14 4415.0 92.062741 97.959207 ... 55.0 101.0 611.0 15 4415.0 92.597055 97.190835 ... 56.0 101.0 600.0 16 4415.0 92.088109 98.110738 ... 55.0 101.0 608.0 17 4415.0 102.483126 106.379639 ... 65.0 110.0 652.0 18 4415.0 104.782786 114.025678 ... 65.0 112.0 646.0 msg_hash_to_str 0 4415.0 24.591619 29.148312 ... 18.0 28.0 346.0 1 4416.0 31.247736 36.302532 ... 21.0 36.0 352.0 2 4416.0 31.853714 39.332395 ... 21.0 36.0 418.0 3 4416.0 28.270833 33.300996 ... 21.0 32.0 429.0 4 4416.0 27.139040 31.905206 ... 19.0 31.0 346.0 5 4416.0 27.380435 32.314188 ... 19.0 31.0 346.0 6 4416.0 25.028080 29.188490 ... 19.0 28.0 346.0 7 4416.0 29.660553 35.283592 ... 21.0 33.0 393.0 8 4416.0 27.685915 32.707466 ... 20.0 31.0 346.0 9 4416.0 34.786685 43.587766 ... 21.0 39.0 414.0 10 4416.0 28.769928 34.428596 ... 20.0 32.0 440.0 11 4416.0 24.407609 28.690934 ... 18.0 27.0 346.0 12 4416.0 23.970788 27.075638 ... 18.0 28.0 346.0 13 4416.0 24.587636 29.146213 ... 18.0 28.0 346.0 14 4416.0 27.642889 33.300451 ... 20.0 31.0 346.0 15 4416.0 25.036005 29.159115 ... 18.0 28.0 346.0 16 4416.0 24.732111 29.134002 ... 18.0 28.0 346.0 17 4416.0 32.068161 38.807095 ... 21.0 36.0 407.0 18 4416.0 28.160779 34.013300 ... 20.0 31.0 432.0
2020-05-23 22:15:32 +00:00
2018-02-05 19:54:55 +00:00
while (*src || reverse)
{
if (reverse)
{
src--;
while (src > (const unsigned char*)msg && IS_MBCONT(src))
2018-02-05 19:54:55 +00:00
src--;
if (src >= (const unsigned char*)msg && (IS_RTL(src) || IS_DIR_NEUTRAL(src) || is_misc_ws(src)))
2018-02-05 19:54:55 +00:00
{
if (IS_ARABIC(src))
2018-02-05 19:54:55 +00:00
{
unsigned replacement = font_get_arabic_replacement(
(const char*)src, msg);
2018-02-05 19:54:55 +00:00
if (replacement)
2018-02-05 19:54:55 +00:00
{
if (replacement < 0x80)
*dst++ = replacement;
else if (replacement < 0x800)
{
*dst++ = 0xC0 | (replacement >> 6);
*dst++ = 0x80 | (replacement & 0x3F);
}
else if (replacement < 0x10000)
{
/* merged glyphs */
if ((replacement >= 0xFEF5) && (replacement <= 0xFEFC))
src -= 2;
*dst++ = 0xE0 | ( replacement >> 12);
*dst++ = 0x80 | ((replacement >> 6) & 0x3F);
*dst++ = 0x80 | ( replacement & 0x3F);
}
else
{
*dst++ = 0xF0 | (replacement >> 18);
*dst++ = 0x80 | ((replacement >> 12) & 0x3F);
*dst++ = 0x80 | ((replacement >> 6) & 0x3F);
*dst++ = 0x80 | ( replacement & 0x3F);
}
continue;
2018-02-05 19:54:55 +00:00
}
}
*dst++ = *src++;
while (IS_MBCONT(src))
*dst++ = *src++;
src--;
while (IS_MBCONT(src))
src--;
}
else
{
reverse = false;
src++;
while ( IS_MBCONT(src)
|| IS_RTL(src)
|| IS_DIR_NEUTRAL(src)
|| is_misc_ws(src))
2018-02-05 19:54:55 +00:00
src++;
}
}
else
{
if (IS_RTL(src))
{
reverse = true;
while ( IS_MBCONT(src)
|| IS_RTL(src)
|| IS_DIR_NEUTRAL(src)
|| is_misc_ws(src))
2018-02-05 19:54:55 +00:00
src++;
}
else
*dst++ = *src++;
}
}
2018-02-05 19:54:55 +00:00
*dst = '\0';
Implements small buffer optimization in font_driver_reshape_msg() Use a stack-allocated 64 bytes long buffer to avoid so many temp heap allocations when the menu is up. This size is more than enough store 75% of the return values from msg_hash_to_str and 50% of the returned values from msg_hash_get_help of any currently supported language (includes fallback to English). String size per type: count mean std ... 50% 75% max type ... msg_hash_get_help 83885.0 95.295476 106.331779 ... 54.0 103.0 842.0 msg_hash_to_str 83903.0 27.737959 33.389184 ... 19.0 31.0 440.0 string size per type and language: count mean std ... 50% 75% max type language ... msg_hash_get_help 0 4415.0 89.922310 96.873902 ... 55.0 101.0 590.0 1 4415.0 97.555606 118.031412 ... 55.0 101.0 842.0 2 4415.0 118.459570 127.811760 ... 75.0 131.0 774.0 3 4415.0 111.978256 112.702991 ... 68.0 125.0 651.0 4 4415.0 106.040544 111.360658 ... 62.0 124.0 776.0 5 4415.0 100.129105 114.437432 ... 62.0 103.0 688.0 6 4415.0 32.987769 31.047851 ... 28.0 28.0 595.0 7 4415.0 109.366025 124.717259 ... 71.0 121.0 720.0 8 4415.0 98.023783 105.149942 ... 62.0 105.0 610.0 9 4415.0 93.834428 104.433820 ... 55.0 101.0 637.0 10 4415.0 93.657984 96.884429 ... 55.0 101.0 594.0 11 4415.0 93.452775 104.040553 ... 48.0 100.0 583.0 12 4415.0 89.729558 104.062959 ... 50.0 100.0 550.0 13 4415.0 91.462514 95.968107 ... 55.0 101.0 590.0 14 4415.0 92.062741 97.959207 ... 55.0 101.0 611.0 15 4415.0 92.597055 97.190835 ... 56.0 101.0 600.0 16 4415.0 92.088109 98.110738 ... 55.0 101.0 608.0 17 4415.0 102.483126 106.379639 ... 65.0 110.0 652.0 18 4415.0 104.782786 114.025678 ... 65.0 112.0 646.0 msg_hash_to_str 0 4415.0 24.591619 29.148312 ... 18.0 28.0 346.0 1 4416.0 31.247736 36.302532 ... 21.0 36.0 352.0 2 4416.0 31.853714 39.332395 ... 21.0 36.0 418.0 3 4416.0 28.270833 33.300996 ... 21.0 32.0 429.0 4 4416.0 27.139040 31.905206 ... 19.0 31.0 346.0 5 4416.0 27.380435 32.314188 ... 19.0 31.0 346.0 6 4416.0 25.028080 29.188490 ... 19.0 28.0 346.0 7 4416.0 29.660553 35.283592 ... 21.0 33.0 393.0 8 4416.0 27.685915 32.707466 ... 20.0 31.0 346.0 9 4416.0 34.786685 43.587766 ... 21.0 39.0 414.0 10 4416.0 28.769928 34.428596 ... 20.0 32.0 440.0 11 4416.0 24.407609 28.690934 ... 18.0 27.0 346.0 12 4416.0 23.970788 27.075638 ... 18.0 28.0 346.0 13 4416.0 24.587636 29.146213 ... 18.0 28.0 346.0 14 4416.0 27.642889 33.300451 ... 20.0 31.0 346.0 15 4416.0 25.036005 29.159115 ... 18.0 28.0 346.0 16 4416.0 24.732111 29.134002 ... 18.0 28.0 346.0 17 4416.0 32.068161 38.807095 ... 21.0 36.0 407.0 18 4416.0 28.160779 34.013300 ... 20.0 31.0 432.0
2020-05-23 22:15:32 +00:00
return (char*)dst_buffer;
2018-02-05 19:54:55 +00:00
}
#endif
void font_driver_render_msg(
void *data,
const char *msg,
const void *_params,
void *font_data)
{
const struct font_params *params = (const struct font_params*)_params;
font_data_t *font = (font_data_t*)(font_data
? font_data : video_font_driver);
2018-02-05 19:54:55 +00:00
if (msg && *msg && font && font->renderer && font->renderer->render_msg)
2018-02-05 19:54:55 +00:00
{
#ifdef HAVE_LANGEXTRA
Implements small buffer optimization in font_driver_reshape_msg() Use a stack-allocated 64 bytes long buffer to avoid so many temp heap allocations when the menu is up. This size is more than enough store 75% of the return values from msg_hash_to_str and 50% of the returned values from msg_hash_get_help of any currently supported language (includes fallback to English). String size per type: count mean std ... 50% 75% max type ... msg_hash_get_help 83885.0 95.295476 106.331779 ... 54.0 103.0 842.0 msg_hash_to_str 83903.0 27.737959 33.389184 ... 19.0 31.0 440.0 string size per type and language: count mean std ... 50% 75% max type language ... msg_hash_get_help 0 4415.0 89.922310 96.873902 ... 55.0 101.0 590.0 1 4415.0 97.555606 118.031412 ... 55.0 101.0 842.0 2 4415.0 118.459570 127.811760 ... 75.0 131.0 774.0 3 4415.0 111.978256 112.702991 ... 68.0 125.0 651.0 4 4415.0 106.040544 111.360658 ... 62.0 124.0 776.0 5 4415.0 100.129105 114.437432 ... 62.0 103.0 688.0 6 4415.0 32.987769 31.047851 ... 28.0 28.0 595.0 7 4415.0 109.366025 124.717259 ... 71.0 121.0 720.0 8 4415.0 98.023783 105.149942 ... 62.0 105.0 610.0 9 4415.0 93.834428 104.433820 ... 55.0 101.0 637.0 10 4415.0 93.657984 96.884429 ... 55.0 101.0 594.0 11 4415.0 93.452775 104.040553 ... 48.0 100.0 583.0 12 4415.0 89.729558 104.062959 ... 50.0 100.0 550.0 13 4415.0 91.462514 95.968107 ... 55.0 101.0 590.0 14 4415.0 92.062741 97.959207 ... 55.0 101.0 611.0 15 4415.0 92.597055 97.190835 ... 56.0 101.0 600.0 16 4415.0 92.088109 98.110738 ... 55.0 101.0 608.0 17 4415.0 102.483126 106.379639 ... 65.0 110.0 652.0 18 4415.0 104.782786 114.025678 ... 65.0 112.0 646.0 msg_hash_to_str 0 4415.0 24.591619 29.148312 ... 18.0 28.0 346.0 1 4416.0 31.247736 36.302532 ... 21.0 36.0 352.0 2 4416.0 31.853714 39.332395 ... 21.0 36.0 418.0 3 4416.0 28.270833 33.300996 ... 21.0 32.0 429.0 4 4416.0 27.139040 31.905206 ... 19.0 31.0 346.0 5 4416.0 27.380435 32.314188 ... 19.0 31.0 346.0 6 4416.0 25.028080 29.188490 ... 19.0 28.0 346.0 7 4416.0 29.660553 35.283592 ... 21.0 33.0 393.0 8 4416.0 27.685915 32.707466 ... 20.0 31.0 346.0 9 4416.0 34.786685 43.587766 ... 21.0 39.0 414.0 10 4416.0 28.769928 34.428596 ... 20.0 32.0 440.0 11 4416.0 24.407609 28.690934 ... 18.0 27.0 346.0 12 4416.0 23.970788 27.075638 ... 18.0 28.0 346.0 13 4416.0 24.587636 29.146213 ... 18.0 28.0 346.0 14 4416.0 27.642889 33.300451 ... 20.0 31.0 346.0 15 4416.0 25.036005 29.159115 ... 18.0 28.0 346.0 16 4416.0 24.732111 29.134002 ... 18.0 28.0 346.0 17 4416.0 32.068161 38.807095 ... 21.0 36.0 407.0 18 4416.0 28.160779 34.013300 ... 20.0 31.0 432.0
2020-05-23 22:15:32 +00:00
unsigned char tmp_buffer[64];
char *new_msg = font_driver_reshape_msg(msg, tmp_buffer, sizeof(tmp_buffer));
2020-03-09 20:34:14 +00:00
font->renderer->render_msg(data,
font->renderer_data, new_msg, params);
Implements small buffer optimization in font_driver_reshape_msg() Use a stack-allocated 64 bytes long buffer to avoid so many temp heap allocations when the menu is up. This size is more than enough store 75% of the return values from msg_hash_to_str and 50% of the returned values from msg_hash_get_help of any currently supported language (includes fallback to English). String size per type: count mean std ... 50% 75% max type ... msg_hash_get_help 83885.0 95.295476 106.331779 ... 54.0 103.0 842.0 msg_hash_to_str 83903.0 27.737959 33.389184 ... 19.0 31.0 440.0 string size per type and language: count mean std ... 50% 75% max type language ... msg_hash_get_help 0 4415.0 89.922310 96.873902 ... 55.0 101.0 590.0 1 4415.0 97.555606 118.031412 ... 55.0 101.0 842.0 2 4415.0 118.459570 127.811760 ... 75.0 131.0 774.0 3 4415.0 111.978256 112.702991 ... 68.0 125.0 651.0 4 4415.0 106.040544 111.360658 ... 62.0 124.0 776.0 5 4415.0 100.129105 114.437432 ... 62.0 103.0 688.0 6 4415.0 32.987769 31.047851 ... 28.0 28.0 595.0 7 4415.0 109.366025 124.717259 ... 71.0 121.0 720.0 8 4415.0 98.023783 105.149942 ... 62.0 105.0 610.0 9 4415.0 93.834428 104.433820 ... 55.0 101.0 637.0 10 4415.0 93.657984 96.884429 ... 55.0 101.0 594.0 11 4415.0 93.452775 104.040553 ... 48.0 100.0 583.0 12 4415.0 89.729558 104.062959 ... 50.0 100.0 550.0 13 4415.0 91.462514 95.968107 ... 55.0 101.0 590.0 14 4415.0 92.062741 97.959207 ... 55.0 101.0 611.0 15 4415.0 92.597055 97.190835 ... 56.0 101.0 600.0 16 4415.0 92.088109 98.110738 ... 55.0 101.0 608.0 17 4415.0 102.483126 106.379639 ... 65.0 110.0 652.0 18 4415.0 104.782786 114.025678 ... 65.0 112.0 646.0 msg_hash_to_str 0 4415.0 24.591619 29.148312 ... 18.0 28.0 346.0 1 4416.0 31.247736 36.302532 ... 21.0 36.0 352.0 2 4416.0 31.853714 39.332395 ... 21.0 36.0 418.0 3 4416.0 28.270833 33.300996 ... 21.0 32.0 429.0 4 4416.0 27.139040 31.905206 ... 19.0 31.0 346.0 5 4416.0 27.380435 32.314188 ... 19.0 31.0 346.0 6 4416.0 25.028080 29.188490 ... 19.0 28.0 346.0 7 4416.0 29.660553 35.283592 ... 21.0 33.0 393.0 8 4416.0 27.685915 32.707466 ... 20.0 31.0 346.0 9 4416.0 34.786685 43.587766 ... 21.0 39.0 414.0 10 4416.0 28.769928 34.428596 ... 20.0 32.0 440.0 11 4416.0 24.407609 28.690934 ... 18.0 27.0 346.0 12 4416.0 23.970788 27.075638 ... 18.0 28.0 346.0 13 4416.0 24.587636 29.146213 ... 18.0 28.0 346.0 14 4416.0 27.642889 33.300451 ... 20.0 31.0 346.0 15 4416.0 25.036005 29.159115 ... 18.0 28.0 346.0 16 4416.0 24.732111 29.134002 ... 18.0 28.0 346.0 17 4416.0 32.068161 38.807095 ... 21.0 36.0 407.0 18 4416.0 28.160779 34.013300 ... 20.0 31.0 432.0
2020-05-23 22:15:32 +00:00
if (new_msg != (char*)tmp_buffer)
free(new_msg);
#else
char *new_msg = (char*)msg;
font->renderer->render_msg(data,
font->renderer_data, new_msg, params);
2018-02-05 19:54:55 +00:00
#endif
}
}
2015-12-05 10:34:56 +00:00
void font_driver_bind_block(void *font_data, void *block)
2015-12-05 09:59:03 +00:00
{
2017-01-10 20:26:48 +00:00
font_data_t *font = (font_data_t*)(font_data ? font_data : video_font_driver);
2015-12-05 09:59:03 +00:00
2016-10-19 22:30:34 +00:00
if (font && font->renderer && font->renderer->bind_block)
font->renderer->bind_block(font->renderer_data, block);
2015-12-05 09:59:03 +00:00
}
void font_driver_flush(unsigned width, unsigned height, void *font_data)
2015-12-05 11:10:12 +00:00
{
2017-01-10 20:26:48 +00:00
font_data_t *font = (font_data_t*)(font_data ? font_data : video_font_driver);
2016-10-19 22:30:34 +00:00
if (font && font->renderer && font->renderer->flush)
font->renderer->flush(width, height, font->renderer_data);
2015-12-05 11:10:12 +00:00
}
int font_driver_get_message_width(void *font_data,
const char *msg, size_t len, float scale)
2015-12-05 11:17:58 +00:00
{
2017-01-10 20:26:48 +00:00
font_data_t *font = (font_data_t*)(font_data ? font_data : video_font_driver);
if (len == 0 && msg)
len = strlen(msg);
2016-10-19 22:30:34 +00:00
if (font && font->renderer && font->renderer->get_message_width)
return font->renderer->get_message_width(font->renderer_data, msg, len, scale);
2016-10-19 22:30:34 +00:00
return -1;
2015-12-05 11:17:58 +00:00
}
2019-02-17 15:54:24 +00:00
int font_driver_get_line_height(void *font_data, float scale)
{
struct font_line_metrics *metrics = NULL;
2019-02-21 20:34:22 +00:00
font_data_t *font = (font_data_t*)(font_data ? font_data : video_font_driver);
2019-02-17 15:54:24 +00:00
/* First try the line metrics implementation */
if (font && font->renderer && font->renderer->get_line_metrics)
if ((font->renderer->get_line_metrics(
font->renderer_data, &metrics)))
return (int)roundf(metrics->height * scale);
2019-02-17 15:54:24 +00:00
/* Else return an approximation
* (uses a fudge of standard font metrics - mostly garbage...)
* > font_size = (width of 'a') / 0.6
* > line_height = font_size * 1.7f */
return (int)roundf(1.7f * (float)font_driver_get_message_width(font_data, "a", 1, scale) / 0.6f);
}
int font_driver_get_line_ascender(void *font_data, float scale)
{
struct font_line_metrics *metrics = NULL;
font_data_t *font = (font_data_t*)(font_data ? font_data : video_font_driver);
/* First try the line metrics implementation */
if (font && font->renderer && font->renderer->get_line_metrics)
if ((font->renderer->get_line_metrics(font->renderer_data, &metrics)))
return (int)roundf(metrics->ascender * scale);
/* Else return an approximation
* (uses a fudge of standard font metrics - mostly garbage...)
* > font_size = (width of 'a') / 0.6
* > ascender = 1.58 * font_size * 0.75 */
return (int)roundf(1.58f * 0.75f * (float)font_driver_get_message_width(font_data, "a", 1, scale) / 0.6f);
}
int font_driver_get_line_descender(void *font_data, float scale)
{
struct font_line_metrics *metrics = NULL;
font_data_t *font = (font_data_t*)(font_data ? font_data : video_font_driver);
/* First try the line metrics implementation */
if (font && font->renderer && font->renderer->get_line_metrics)
if ((font->renderer->get_line_metrics(font->renderer_data, &metrics)))
return (int)roundf(metrics->descender * scale);
/* Else return an approximation
* (uses a fudge of standard font metrics - mostly garbage...)
* > font_size = (width of 'a') / 0.6
* > descender = 1.58 * font_size * 0.25 */
return (int)roundf(1.58f * 0.25f * (float)font_driver_get_message_width(font_data, "a", 1, scale) / 0.6f);
}
int font_driver_get_line_centre_offset(void *font_data, float scale)
{
struct font_line_metrics *metrics = NULL;
font_data_t *font = (font_data_t*)(font_data ? font_data : video_font_driver);
/* First try the line metrics implementation */
if (font && font->renderer && font->renderer->get_line_metrics)
if ((font->renderer->get_line_metrics(font->renderer_data, &metrics)))
return (int)roundf((metrics->ascender - metrics->descender) * 0.5f * scale);
/* Else return an approximation... */
return (int)roundf((1.58f * 0.5f * (float)font_driver_get_message_width(font_data, "a", 1, scale) / 0.6f) / 2.0f);
2019-02-17 15:54:24 +00:00
}
void font_driver_free(void *font_data)
{
font_data_t *font = (font_data_t*)font_data;
if (font)
{
bool is_threaded = false;
#ifdef HAVE_THREADS
2017-04-29 15:02:35 +00:00
bool *is_threaded_tmp = video_driver_get_threaded();
is_threaded = *is_threaded_tmp;
#endif
if (font->renderer && font->renderer->free)
font->renderer->free(font->renderer_data, is_threaded);
2015-12-05 09:54:53 +00:00
font->renderer = NULL;
font->renderer_data = NULL;
2015-12-05 09:54:53 +00:00
free(font);
}
}
font_data_t *font_driver_init_first(
void *video_data, const char *font_path, float font_size,
bool threading_hint, bool is_threaded,
enum font_driver_render_api api)
{
const void *font_driver = NULL;
void *font_handle = NULL;
bool ok = false;
2015-12-06 21:42:22 +00:00
#ifdef HAVE_THREADS
if ( threading_hint
&& is_threaded
2016-05-08 12:00:51 +00:00
&& !video_driver_is_hw_context())
ok = video_thread_font_init(&font_driver, &font_handle,
video_data, font_path, font_size, api, font_init_first,
is_threaded);
else
2015-12-06 21:42:22 +00:00
#endif
ok = font_init_first(&font_driver, &font_handle,
video_data, font_path, font_size, api, is_threaded);
if (ok)
{
font_data_t *font = (font_data_t*)malloc(sizeof(*font));
if (font)
{
font->renderer = (const font_renderer_t*)font_driver;
font->renderer_data = font_handle;
font->size = font_size;
return font;
}
}
2015-12-05 10:29:06 +00:00
return NULL;
}
2015-12-05 11:10:12 +00:00
void font_driver_init_osd(
void *video_data,
const void *video_info_data,
bool threading_hint,
bool is_threaded,
enum font_driver_render_api api)
{
const video_info_t *video_info = (const video_info_t*)video_info_data;
if (!video_font_driver && video_info)
video_font_driver = font_driver_init_first(video_data,
*video_info->path_font ? video_info->path_font : NULL,
video_info->font_size, threading_hint, is_threaded, api);
}
void font_driver_free_osd(void)
{
2017-01-10 20:26:48 +00:00
if (video_font_driver)
font_driver_free(video_font_driver);
2017-01-10 20:26:48 +00:00
video_font_driver = NULL;
}