123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946 |
- /* RetroArch - A frontend for libretro.
- * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
- * Copyright (C) 2011-2017 - Daniel De Matteis
- *
- * RetroArch is free software: you can redistribute it and/or modify it under the terms
- * 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.
- *
- * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- * PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with RetroArch.
- * If not, see <http://www.gnu.org/licenses/>.
- */
- #include <stdlib.h>
- #include <math.h>
- #ifdef HAVE_CONFIG_H
- #include "../config.h"
- #endif
- #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
- #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,
- #else
- &stb_unicode_font_renderer,
- #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;
- }
- }
- *drv = NULL;
- *handle = NULL;
- return 0;
- }
- 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:
- {
- void *data = gl1_raster_font.init(
- video_data, font_path, font_size, is_threaded);
- if (data)
- {
- *font_driver = &gl1_raster_font;
- *font_handle = data;
- return true;
- }
- }
- break;
- #endif
- #ifdef HAVE_OPENGL
- case FONT_DRIVER_RENDER_OPENGL_API:
- {
- void *data = gl2_raster_font.init(
- video_data, font_path, font_size, is_threaded);
- if (data)
- {
- *font_driver = &gl2_raster_font;
- *font_handle = data;
- return true;
- }
- }
- break;
- #endif
- #ifdef HAVE_OPENGL_CORE
- case FONT_DRIVER_RENDER_OPENGL_CORE_API:
- {
- void *data = gl3_raster_font.init(
- video_data, font_path, font_size, is_threaded);
- if (data)
- {
- *font_driver = &gl3_raster_font;
- *font_handle = data;
- return true;
- }
- }
- break;
- #endif
- #ifdef HAVE_VULKAN
- case FONT_DRIVER_RENDER_VULKAN_API:
- {
- void *data = vulkan_raster_font.init(video_data,
- font_path, font_size, is_threaded);
- if (data)
- {
- *font_driver = &vulkan_raster_font;
- *font_handle = data;
- return true;
- }
- }
- break;
- #endif
- #ifdef HAVE_METAL
- case FONT_DRIVER_RENDER_METAL_API:
- {
- void *data = metal_raster_font.init(video_data,
- font_path, font_size, is_threaded);
- if (data)
- {
- *font_driver = &metal_raster_font;
- *font_handle = data;
- return true;
- }
- }
- #endif
- #ifdef HAVE_D3D8
- case FONT_DRIVER_RENDER_D3D8_API:
- {
- 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)
- {
- *font_driver = d3d8_font_backends[i];
- *font_handle = data;
- return true;
- }
- }
- }
- break;
- #endif
- #ifdef HAVE_D3D9
- case FONT_DRIVER_RENDER_D3D9_API:
- {
- 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++)
- {
- void *data = d3d9_font_backends[i] ? d3d9_font_backends[i]->init(
- video_data, font_path, font_size, is_threaded) : NULL;
- if (data)
- {
- *font_driver = d3d9_font_backends[i];
- *font_handle = data;
- return true;
- }
- }
- }
- break;
- #endif
- #ifdef HAVE_D3D10
- case FONT_DRIVER_RENDER_D3D10_API:
- {
- void *data = d3d10_font.init(video_data,
- font_path, font_size, is_threaded);
- if (data)
- {
- *font_driver = &d3d10_font;
- *font_handle = data;
- return true;
- }
- }
- break;
- #endif
- #ifdef HAVE_D3D11
- case FONT_DRIVER_RENDER_D3D11_API:
- {
- void *data = d3d11_font.init(video_data,
- font_path, font_size, is_threaded);
- if (data)
- {
- *font_driver = &d3d11_font;
- *font_handle = data;
- return true;
- }
- }
- break;
- #endif
- #ifdef HAVE_D3D12
- case FONT_DRIVER_RENDER_D3D12_API:
- {
- void *data = d3d12_font.init(video_data,
- font_path, font_size, is_threaded);
- if (data)
- {
- *font_driver = &d3d12_font;
- *font_handle = data;
- return true;
- }
- }
- break;
- #endif
- #ifdef HAVE_VITA2D
- case FONT_DRIVER_RENDER_VITA2D:
- {
- void *data = vita2d_vita_font.init(
- video_data, font_path, font_size, is_threaded);
- if (data)
- {
- *font_driver = &vita2d_vita_font;
- *font_handle = data;
- return true;
- }
- }
- break;
- #endif
- #ifdef PS2
- case FONT_DRIVER_RENDER_PS2:
- {
- void *data = ps2_font.init(
- video_data, font_path, font_size,
- is_threaded);
- if (data)
- {
- *font_driver = &ps2_font;
- *font_handle = data;
- return true;
- }
- }
- break;
- #endif
- #ifdef _3DS
- case FONT_DRIVER_RENDER_CTR:
- {
- void *data = ctr_font.init(
- video_data, font_path, font_size,
- is_threaded);
- if (data)
- {
- *font_driver = &ctr_font;
- *font_handle = data;
- return true;
- }
- }
- break;
- #endif
- #ifdef WIIU
- case FONT_DRIVER_RENDER_WIIU:
- {
- void *data = wiiu_font.init(
- video_data, font_path, font_size, is_threaded);
- if (data)
- {
- *font_driver = &wiiu_font;
- *font_handle = data;
- return true;
- }
- }
- break;
- #endif
- #ifdef HAVE_CACA
- case FONT_DRIVER_RENDER_CACA:
- {
- void *data = caca_font.init(
- video_data, font_path, font_size,
- is_threaded);
- if (data)
- {
- *font_driver = &caca_font;
- *font_handle = data;
- return true;
- }
- }
- break;
- #endif
- #ifdef HAVE_SIXEL
- case FONT_DRIVER_RENDER_SIXEL:
- {
- void *data = sixel_font.init(
- video_data, font_path, font_size,
- is_threaded);
- if (data)
- {
- *font_driver = &sixel_font;
- *font_handle = data;
- return true;
- }
- }
- break;
- #endif
- #ifdef HAVE_LIBNX
- case FONT_DRIVER_RENDER_SWITCH:
- {
- void *data = switch_font.init(
- video_data, font_path, font_size,
- is_threaded);
- if (data)
- {
- *font_driver = &switch_font;
- *font_handle = data;
- return true;
- }
- }
- break;
- #endif
- #ifdef HAVE_GCM
- case FONT_DRIVER_RENDER_RSX:
- {
- void *data = rsx_font.init(
- video_data, font_path, font_size,
- is_threaded);
- if (data)
- {
- *font_driver = &rsx_font;
- *font_handle = data;
- return true;
- }
- }
- break;
- #endif
- #ifdef HAVE_GDI
- #if defined(_WIN32) && !defined(_XBOX) && !defined(__WINRT__)
- case FONT_DRIVER_RENDER_GDI:
- {
- void *data = gdi_font.init(
- video_data, font_path, font_size,
- is_threaded);
- if (data)
- {
- *font_driver = &gdi_font;
- *font_handle = data;
- return true;
- }
- }
- break;
- #endif
- #endif
- #ifdef DJGPP
- case FONT_DRIVER_RENDER_VGA:
- {
- void *data = vga_font.init(
- video_data, font_path, font_size,
- is_threaded);
- if (data)
- {
- *font_driver = &vga_font;
- *font_handle = data;
- return true;
- }
- }
- break;
- #endif
- case FONT_DRIVER_RENDER_DONT_CARE:
- /* TODO/FIXME - lookup graphics driver's 'API' */
- break;
- default:
- break;
- }
- return false;
- }
- #ifdef HAVE_LANGEXTRA
- /* ASCII: 0xxxxxxx (c & 0x80) == 0x00
- * 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)
- * Arabic:
- * 0600 - 06FF: 110110xx (c & 0xFC) == 0xD8 (2 bytes)
- */
- /* 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))
- /* 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)
- {
- /* 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 },
- { 0 }, { 0 }, { 0 }, { 0 }, /* 0x06B0 */
- { 0 }, { 0 }, { 0 }, { 0 },
- { 0 }, { 0 }, { 0 }, { 0 },
- { 0 }, { 0 }, { 0 }, { 0 },
- { 0 }, { 0 }, { 0 }, { 0 }, /* 0x06C0 */
- { 0 }, { 0 }, { 0 }, { 0 },
- { 0 }, { 0 }, { 0 }, { 0 },
- { 0xFBFC, 0xFBFD, 0xFBFE, 0xFBFF },
- { 0 }, { 0 }, { 0 },
- { 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;
- }
- if (prev_id == 0x44) /* Arabic Letter Lam */
- {
- unsigned char prev2_id = 0;
- const char* prev2 = prev - 2;
- if (prev2 >= start)
- prev2_id = (prev2[0] << 6) | (prev2[1] & 0x3F);
- /* 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;
- }
- }
- prev_connected = !!arabic_shape_map[prev_id][2];
- }
- 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];
- }
- /* clang-format on */
- static char* font_driver_reshape_msg(const char* msg, unsigned char *buffer, size_t buffer_size)
- {
- 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;
- while (*src || reverse)
- {
- if (reverse)
- {
- src--;
- while (src > (const unsigned char*)msg && IS_MBCONT(src))
- src--;
- if (src >= (const unsigned char*)msg && (IS_RTL(src) || IS_DIR_NEUTRAL(src) || is_misc_ws(src)))
- {
- if (IS_ARABIC(src))
- {
- unsigned replacement = font_get_arabic_replacement(
- (const char*)src, msg);
- if (replacement)
- {
- 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;
- }
- }
- *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))
- src++;
- }
- }
- else
- {
- if (IS_RTL(src))
- {
- reverse = true;
- while ( IS_MBCONT(src)
- || IS_RTL(src)
- || IS_DIR_NEUTRAL(src)
- || is_misc_ws(src))
- src++;
- }
- else
- *dst++ = *src++;
- }
- }
- *dst = '\0';
- return (char*)dst_buffer;
- }
- #endif
- void font_driver_render_msg(void *data, const char *msg,
- const struct font_params *params, void *font_data)
- {
- font_data_t *font = (font_data_t*)(font_data
- ? font_data : video_font_driver);
- if (msg && *msg && font && font->renderer && font->renderer->render_msg)
- {
- #ifdef HAVE_LANGEXTRA
- unsigned char tmp_buffer[64];
- char *new_msg = font_driver_reshape_msg(msg, tmp_buffer, sizeof(tmp_buffer));
- #else
- char *new_msg = (char*)msg;
- #endif
- font->renderer->render_msg(data,
- font->renderer_data, new_msg, params);
- #ifdef HAVE_LANGEXTRA
- if (new_msg != (char*)tmp_buffer)
- free(new_msg);
- #endif
- }
- }
- void font_driver_bind_block(void *font_data, void *block)
- {
- font_data_t *font = (font_data_t*)(font_data ? font_data : video_font_driver);
- if (font && font->renderer && font->renderer->bind_block)
- font->renderer->bind_block(font->renderer_data, block);
- }
- void font_driver_flush(unsigned width, unsigned height, void *font_data)
- {
- font_data_t *font = (font_data_t*)(font_data ? font_data : video_font_driver);
- if (font && font->renderer && font->renderer->flush)
- font->renderer->flush(width, height, font->renderer_data);
- }
- int font_driver_get_message_width(void *font_data,
- const char *msg, size_t len, float scale)
- {
- font_data_t *font = (font_data_t*)(font_data ? font_data : video_font_driver);
- if (len == 0 && msg)
- len = strlen(msg);
- if (font && font->renderer && font->renderer->get_message_width)
- return font->renderer->get_message_width(font->renderer_data, msg, len, scale);
- return -1;
- }
- int font_driver_get_line_height(font_data_t *font, float scale)
- {
- struct font_line_metrics *metrics = NULL;
- /* 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);
- /* 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, "a", 1, scale) / 0.6f);
- }
- int font_driver_get_line_ascender(font_data_t *font, float scale)
- {
- struct font_line_metrics *metrics = NULL;
- /* 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, "a", 1, scale) / 0.6f);
- }
- int font_driver_get_line_descender(font_data_t *font, float scale)
- {
- struct font_line_metrics *metrics = NULL;
- /* 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, "a", 1, scale) / 0.6f);
- }
- int font_driver_get_line_centre_offset(font_data_t *font, float scale)
- {
- struct font_line_metrics *metrics = NULL;
- /* 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, "a", 1, scale) / 0.6f) / 2.0f);
- }
- void font_driver_free(font_data_t *font)
- {
- if (font)
- {
- bool is_threaded = false;
- #ifdef HAVE_THREADS
- 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);
- font->renderer = NULL;
- font->renderer_data = NULL;
- 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;
- #ifdef HAVE_THREADS
- if ( threading_hint
- && is_threaded
- && !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
- #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;
- }
- }
- return NULL;
- }
- 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)
- {
- if (video_font_driver)
- font_driver_free(video_font_driver);
- video_font_driver = NULL;
- }
|