diff options
Diffstat (limited to 'riscos/ufont.c')
-rw-r--r-- | riscos/ufont.c | 1273 |
1 files changed, 0 insertions, 1273 deletions
diff --git a/riscos/ufont.c b/riscos/ufont.c deleted file mode 100644 index 9cedcd79a..000000000 --- a/riscos/ufont.c +++ /dev/null @@ -1,1273 +0,0 @@ -/* ufont.c - * Licensed under the GNU General Public License, - * http://www.opensource.org/licenses/gpl-license - * Copyright 2000 James Bursa <bursa@users.sourceforge.net> - * Copyright 2004 John Tytgat <John.Tytgat@aaug.net> - */ - -/** \file - * UFont - Unicode wrapper for non-Unicode aware FontManager - * - * This code allows non-Unicode aware FontManager to be used for - * displaying Unicode encoded text lines. It needs the !UFont - * resource (accessed via UFont$Path). - */ - -#include <assert.h> -#include <limits.h> -#include <wchar.h> - -#include "oslib/osfile.h" - -#include "ufont.h" - -// #define DEBUG_UFONT -// #define DEBUG_ACTIVATE_SANITY_CHECK -// #define DEBUG_DUMP_INTERNALS - -#ifdef DEBUG_UFONT -# define dbg_fprintf fprintf -#else -# define dbg_fprintf (1)?0:fprintf -#endif -#ifdef DEBUG_ACTIVATE_SANITY_CHECK -# define do_sanity_check sanity_check -#else -# define do_sanity_check (1)?0:sanity_check -#endif -#define MALLOC_CHUNK 256 - -typedef struct usage_chain_s usage_chain_t; -typedef struct virtual_fh_s virtual_fh_t; -/* Virtual font handle : - */ -struct virtual_fh_s - { - const char *fontNameP; /* => malloc'ed block holding RISC OS font name */ - int xsize, ysize; /* font size */ - int xres, yres; /* requested or actual resolution */ - unsigned int usage; /* the higher, the more this font handle is used for setting its glyphs */ - unsigned int refCount; /* number of times this struct is refered from ufont_f element */ - usage_chain_t *usageP; /* Ptr to element usage chain; if non NULL, we have a RISC OS font handle allocated. When refCount is 0, this is not necessary NULL. */ - }; -#define kInitialFHArraySize 20 -static virtual_fh_t *oVirtualFHArrayP; -static size_t oCurVirtualFHArrayElems; -static size_t oMaxVirtualFHArrayElems; - -/* Usage chain (one element per open RISC OS font handle) : - */ -struct usage_chain_s - { - usage_chain_t *nextP; - usage_chain_t *prevP; - - size_t chainTimer; /* When equal to oChainTimer, you can not throw this element out the chain. */ - font_f ro_fhandle; /* RISC OS font handle (garanteed non zero) */ - virtual_fh_t *virFHP; - }; - -typedef struct ufont_map_s ufont_map_t; - -struct ufont_map_s - { - byte fontnr[65536]; /* Must be 1st (comes straight from 'Data' file). Each entry is an index in the virtual_font_index array. */ - byte character[65536]; /* Must be 2nd (comes straight from 'Data' file) */ - - const char *uFontNameP; /* => malloc'ed block holding UFont name */ - unsigned int refCount; - ufont_map_t *nextP; - }; -static const ufont_map_t *oMapCollectionP; - -struct ufont_font - { - ufont_map_t *mapP; - unsigned int virtual_handles_used; /* Number of filled virtual_font_index[] elements */ - size_t virtual_font_index[256]; /* Index in the oVirtualFHArrayP */ - }; - -/* Walking the chain starting with oUsageChain->nextP and continuing via - * ->nextP until reaching oUsageChain again, results in equal or - * decreasing ->virFHP->usage values. - * Also walking the chain starting with oUsageChain->prevP and continuing - * via ->prevP until reaching oUsageChain again, results in equal or - * increasing ->virFHP->usage values. - */ -static usage_chain_t oUsageChain; -static size_t oCurUsageChainElems; -/* Maximum number of RISC OS handles open by UFont : - */ -#define kMaxUsageChainElems 80 -static size_t oChainTimer; - -static os_error *create_map(const char *fontNameP, const ufont_map_t **mapPP); -static os_error *delete_map(ufont_map_t *mapP); -static int eat_utf8(wchar_t *pwc, const byte *s, int n); -static os_error *addref_virtual_fonthandle(const char *fontNameP, int xsize, int ysize, int xres, int yres, int *xresOutP, int *yresOutP, size_t *offsetP); -static os_error *deref_virtual_fonthandle(size_t offset); -static os_error *activate_virtual_fh(virtual_fh_t *virFHP); -static os_error *remove_usage_chain_elem(usage_chain_t *usageElemP); -static void repos_usage_chain_elem(usage_chain_t *usageElemP); -static const char *get_rofontname(font_f rofhandle); -#ifdef DEBUG_DUMP_INTERNALS -static void dump_internals(void); -#endif -static int sanity_check(const char *testMsgP); - -/* UFont error messages : - */ -static os_error error_badparams = { error_BAD_PARAMETERS, "Bad parameters" }; -static os_error error_exists = { error_FONT_NOT_FOUND, "UFont Fonts/Data file not found" }; -static os_error error_memory = { error_FONT_NO_ROOM, "Insufficient memory for font" }; -static os_error error_size = { error_FONT_BAD_FONT_FILE, "Wrong size of font file" }; -static os_error error_fnt_corrupt = { 1 /** \todo */, "UFont is corrupt" }; -static os_error error_toomany_handles = { 2 /** \todo */, "Too many UFont handles are needed to fulfill current request" }; -static os_error error_noufont = { 3 /** \todo */, "Unable to find UFont font" }; -static os_error error_badrohandle = { 4 /** \todo */, "Invalid internal RISC OS font handle" }; - -/* - * UFont_FindFont - * - * => as Font_FindFont, but - * font_name does not support '\' qualifiers - * - * <= as Font_FindFont, but - * handle is 32-bit - * Results from xres_out and yres_out are questionable because we - * delay-loading the real font data. - */ -os_error * -xufont_find_font(char const *fontNameP, - int xsize, - int ysize, - int xres, - int yres, - ufont_f *font, - int *xresOutP, - int *yresOutP) -{ - ufont_f fontP; - const char *old_font; - char *fonts_file; - char file_name[256]; // \todo: fixed size, i.e. not safe. - fileswitch_object_type objType; - int size; - os_error *errorP; - -if (font == NULL) - return &error_badparams; -/* Be sure never to return garbage as result. */ -*font = NULL; - -/* Allocate memory for UFont font set */ -if ((fontP = (ufont_f)calloc(1, sizeof(struct ufont_font))) == NULL) - return &error_memory; - -if ((errorP = create_map(fontNameP, &fontP->mapP)) != NULL) - { - (void)xufont_lose_font(fontP); - return errorP; - } -if (fontP->mapP == NULL) - { - (void)xufont_lose_font(fontP); - return &error_noufont; - } - -/* Find size of Fonts file : - */ -strcpy(file_name, fontNameP); -strcat(file_name, ".Fonts"); -if ((errorP = xosfile_read_stamped_path(file_name, "UFont:", &objType, NULL, NULL, &size, NULL, NULL)) != NULL) - { - (void)xufont_lose_font(fontP); - return errorP; - } -if (objType != fileswitch_IS_FILE) - { - (void)xufont_lose_font(fontP); - return &error_exists; - } - -if ((fonts_file = (char *)malloc(size)) == NULL) - { - (void)xufont_lose_font(fontP); - return &error_memory; - } - -/* Load Fonts : - */ -if ((errorP = xosfile_load_stamped_path(file_name, fonts_file, "UFont:", NULL, NULL, NULL, NULL, NULL)) != NULL) - { - (void)xufont_lose_font(fontP); - free((void *)fonts_file); - return errorP; - } - -/* Open all fonts listed in Fonts : - */ -for (old_font = fonts_file, fontP->virtual_handles_used = 0; - old_font - fonts_file < size; - old_font += strlen(old_font) + 1, ++fontP->virtual_handles_used) - { - /* UFont can maximum have 256 real RISC OS fonts : - */ - if (fontP->virtual_handles_used < 256) - { - dbg_fprintf(stderr, "%i %s: ", fontP->virtual_handles_used, old_font); - errorP = addref_virtual_fonthandle(old_font, xsize, ysize, xres, yres, xresOutP, yresOutP, &fontP->virtual_font_index[fontP->virtual_handles_used]); - } - else - errorP = &error_fnt_corrupt; - - if (errorP != NULL) - { - (void)xufont_lose_font(fontP); - free((void *)fonts_file); - return errorP; - } - - dbg_fprintf(stderr, "%i\n", fontP->virtual_font_index[fontP->virtual_handles_used]); - } - -/* free Fonts */ -free((void *)fonts_file); fonts_file = NULL; - -*font = fontP; -if (xresOutP != NULL) - *xresOutP = 96; -if (yresOutP != NULL) - *yresOutP = 96; -return NULL; -} - - -/* - * UFont_LoseFont - * - * => font handle as returned by UFont_FindFont - * Even if there was an error returned, we tried to delete as much - * as possible. The ufont_f is definately not reusable afterwards. - */ -os_error * -xufont_lose_font(ufont_f fontP) -{ - unsigned int index; - os_error *theErrorP; - -theErrorP = (fontP->mapP != NULL) ? delete_map(fontP->mapP) : NULL; - -/* Close all fonts used : - */ -for (index = 0; index < fontP->virtual_handles_used; ++index) - { - os_error *errorP; - dbg_fprintf(stderr, "About to deref virtual font handle %d\n", fontP->virtual_font_index[index]); - if ((errorP = deref_virtual_fonthandle(fontP->virtual_font_index[index])) != NULL) - theErrorP = errorP; - } - -/* Free ufont structure : - */ -free((void *)fontP); - -return theErrorP; -} - - -/* - * UFont_Paint - * - * => font handle as returned by UFont_FindFont - * string is Unicode UTF-8 encoded - * other parameters as Font_Paint - */ -os_error * -xufont_paint(ufont_f fontP, - unsigned char const *string, - font_string_flags flags, - int xpos, - int ypos, - font_paint_block const *block, - os_trfm const *trfm, - int length) -{ - char *result; - os_error *error; - - if ((flags & font_GIVEN_LENGTH) == 0) - length = INT_MAX; - - dbg_fprintf(stderr, "xufont_paint() : size %d, consider len %d\n", strlen(string), length); - if ((error = xufont_convert(fontP, string, length, &result, NULL)) != NULL) - return error; - if (result[0] == '\0') - return NULL; - - assert(result[0] == font_COMMAND_FONT); - error = xfont_paint(result[1], &result[2], - (flags & (~font_GIVEN_LENGTH)) | font_GIVEN_FONT, - xpos, ypos, block, trfm, 0); - return error; -} - - -/* - * UFont_ScanString - * - * => font handle as returned by UFont_FindFont - * string is Unicode UTF-8 encoded - * split length is index in string, not pointer - * other parameters as Font_ScanString - * - * <= as Font_ScanString - */ -os_error * -xufont_scan_string(ufont_f fontP, - unsigned char const *string, - font_string_flags flags, - int x, - int y, - font_scan_block const *block, - os_trfm const *trfm, - int length, - unsigned char const **split_point, - int *x_out, - int *y_out, - int *length_out) -{ - char *result; - char *split_point_i; - unsigned int *table; - os_error *error; - - if ((flags & font_GIVEN_LENGTH) == 0) - length = INT_MAX; - - dbg_fprintf(stderr, "xufont_scan_string() : size %d, consider len %d\n", strlen(string), length); - if ((error = xufont_convert(fontP, string, length, &result, &table)) != NULL) - return error; - if (result[0] == '\0') - { - if (split_point != NULL) - *split_point = string; - if (x_out != NULL) - *x_out = 0; - if (y_out != NULL) - *y_out = 0; - if (length_out != NULL) - *length_out = 0; - return NULL; - } - - assert(result[0] == font_COMMAND_FONT); - error = xfont_scan_string(result[1], &result[2], - (flags & (~font_GIVEN_LENGTH)) | font_GIVEN_FONT, - x, y, block, trfm, 0, - (split_point) ? &split_point_i : NULL, - x_out, y_out, length_out); - if (error != NULL) - return error; - - if (split_point != NULL) - { - dbg_fprintf(stderr, "RISC OS scan string split at offset %d (char %d)\n", split_point_i - result, *split_point_i); - *split_point = &string[table[split_point_i - result]]; - dbg_fprintf(stderr, "UTF-8 Split offset at %d (char %d)\n", *split_point - string, **split_point); - } - - return NULL; -} - - -/** - * Given a text line, return the number of bytes which can be set using - * one RISC OS font and the bounding box fitting that part of the text - * only. - * - * \param font a ufont font handle, as returned by xufont_find_font(). - * \param string string text. Does not have to be NUL terminated. - * \param flags FontManger flags to be used internally - * \param length length in bytes of the text to consider. - * \param width returned width of the text which can be set with one RISC OS font. If 0, then error happened or initial text length was 0. - * \param rofontname returned name of the RISC OS font which can be used to set the text. If NULL, then error happened or initial text length was 0. - * \param rotext returned string containing the characters in returned RISC OS font. Not necessary NUL terminated. free() after use. If NULL, then error happened or initial text length was 0. - * \param rolength length of return rotext string. If 0, then error happened or initial text length was 0. - * \param consumed number of bytes of the given text which can be set with one RISC OS font. If 0, then error happened or initial text length was 0. - */ -os_error *xufont_txtenum(ufont_f fontP, - unsigned char const *string, - font_string_flags flags, - size_t length, - int *widthP, - unsigned char const **rofontnameP, - unsigned char const **rotextP, - size_t *rolengthP, - size_t *consumedP) -{ - char *result, *end_result; - unsigned int *table; - os_error *errorP; - - int width; - const char *rofontname; - char *rotext; - size_t rolength; - - *rotextP = *rofontnameP = NULL; - *consumedP = *rolengthP = *widthP = 0; - - if ((flags & font_GIVEN_LENGTH) == 0) - length = INT_MAX; - - if (length == 0) - return NULL; - - if ((errorP = xufont_convert(fontP, string, length, &result, &table)) != NULL) - return errorP; - if (result[0] == '\0') - return NULL; - assert(result[0] == font_COMMAND_FONT); - - /* Find how many characters starting at <result + 2> onwards - are set using the RISC OS font with handle <result + 1> */ - for (end_result = result + 2; *end_result != '\0' && *end_result != font_COMMAND_FONT; ++end_result) - ; - - rolength = end_result - result - 2; - if ((errorP = xfont_scan_string(result[1], &result[2], - flags | font_GIVEN_LENGTH | font_GIVEN_FONT, - 0x7fffffff, 0x7fffffff, - NULL, NULL, - rolength, - NULL, - &width, NULL, - NULL)) != NULL) - return errorP; - if ((rofontname = get_rofontname(result[1])) == NULL) - return &error_badrohandle; - if ((rotext = malloc(rolength)) == NULL) - return &error_memory; - memcpy(rotext, result + 2, rolength); - - *widthP = width; - *rofontnameP = rofontname; - *rotextP = rotext; - *rolengthP = rolength; - *consumedP = table[end_result - result]; - - return NULL; -} - - -/* - * UFont_Convert - * - * => initial font - * UTF-8 string to convert to RISC OS font numbers and codes. - * max length to convert (characters) or NUL char terminated. - * - * <= string converted to Font_Paint format - * table of offsets in UTF-8 string - */ -os_error * -xufont_convert(ufont_f fontP, - unsigned char const *string, - size_t length, - char **presult, /* may not be NULL ! */ - size_t **ptable /* may be NULL */) -{ - static char *resultP; - static size_t *tableP; - static size_t currentSize; - - size_t max_length; - size_t string_index, new_string_index, result_index; - virtual_fh_t *curVirFH = NULL; - -assert(presult != NULL); - -do_sanity_check("xufont_convert() : begin"); - -/* Find upfront if we're NUL char terminated or length terminated. */ -for (max_length = 0; max_length < length && string[max_length] != '\0'; ++max_length) - /* no body */; - -/* Increase timer so we can enforce a set of usage elements to remain active. - */ -++oChainTimer; - -/* Ensure memory block. - */ -if (resultP == NULL) - { - if ((resultP = (char *)malloc(MALLOC_CHUNK)) == NULL) - return &error_memory; - currentSize = MALLOC_CHUNK; - } -if (tableP == NULL && (tableP = (size_t *)malloc(MALLOC_CHUNK * sizeof(size_t))) == NULL) - return &error_memory; - -dbg_fprintf(stderr, "xufont_convert() : "); -for (string_index = 0, result_index = 0; - string_index < max_length; - string_index = new_string_index) - { - wchar_t wchar; - int result = eat_utf8(&wchar, &string[string_index], max_length - string_index); - - if (result == 0) - { - /* Too few input bytes : abort conversion */ - fprintf(stderr, "eat_utf8() : too few input bytes\n"); - break; - } - else if (result < 0) - { - /* Corrupt UTF-8 stream : skip <-result> input characters. */ - fprintf(stderr, "eat_utf8() : error %d\n", result); -fprintf(stderr, "String <%.*s> error pos %d\n", length, string, string_index); - wchar = '?'; - new_string_index = string_index - result; - } - else - { - /* Normal case : one wchar_t produced, <result> bytes consumed. */ - if (wchar >= 0x10000) - wchar = '?'; - new_string_index = string_index + result; - } - - dbg_fprintf(stderr, "src offset 0x%x : 0x%x ", string_index, wchar); - - /* Reserve room for at least 32 more entries. - */ - if (result_index + 32 > currentSize) - { - if ((resultP = realloc(resultP, currentSize*2)) == NULL - || (tableP = realloc(tableP, currentSize*2 * sizeof(size_t))) == NULL) - return &error_memory; - - currentSize *= 2; - } - - { - const byte fontnr = fontP->mapP->fontnr[wchar]; - virtual_fh_t *virFHP; - usage_chain_t *usageP; - - assert(fontnr < fontP->virtual_handles_used); - virFHP = &oVirtualFHArrayP[fontP->virtual_font_index[fontnr]]; - - /* Check if current font is ok : - */ - if (virFHP != curVirFH) - { - os_error *errorP; - - curVirFH = virFHP; - - /* Make sure we have a RISC OS font handle associated : - */ - if ((errorP = activate_virtual_fh(virFHP)) != NULL) - return errorP; - usageP = virFHP->usageP; - assert(usageP != NULL); - assert(usageP->ro_fhandle != 0); - tableP[result_index] = tableP[result_index + 1] = string_index; - resultP[result_index++] = font_COMMAND_FONT; - resultP[result_index++] = usageP->ro_fhandle; - - dbg_fprintf(stderr, "{%i} ", resultP[result_index - 1]); - } - else - { - usageP = virFHP->usageP; - assert(usageP != NULL); - } - - ++virFHP->usage; - /* By increasing the usage counter, it might that the oUsageChain needs - * reordering. - */ - if (usageP != oUsageChain.nextP && virFHP->usage > usageP->prevP->virFHP->usage) - repos_usage_chain_elem(usageP); - - tableP[result_index] = string_index; - resultP[result_index++] = fontP->mapP->character[wchar]; - dbg_fprintf(stderr, "[0x%x] ", resultP[result_index - 1]); - } - } -resultP[result_index] = 0; -*presult = resultP; - -tableP[result_index] = string_index; -if (ptable != NULL) - *ptable = tableP; - -#ifdef DEBUG_UFONT -fprintf(stderr, "\nRISC OS font string result:\n"); - -for (result_index = 0; resultP[result_index] != 0; ++result_index) - fprintf(stderr, " Dst offset %d : 0x%x (src offset %d)\n", result_index, resultP[result_index], tableP[result_index]); -#endif - -do_sanity_check("xufont_convert() : end"); - -dbg_fprintf(stderr, "--- After convert()\n"); -//dump_internals(); - -return NULL; -} - - -/* Creates or reuses an existing ufont_map_t - */ -static os_error *create_map(const char *uFontNameP, const ufont_map_t **mapPP) -{ - ufont_map_t *curMapP; - size_t uFontNameLen = strlen(uFontNameP); - char *fileNameP; - os_error *errorP; - -/* Make sure we never return garbage results. - */ -*mapPP = NULL; - -if ((fileNameP = (char *)alloca(uFontNameLen + sizeof(".Data"))) == NULL) - return &error_memory; -memcpy(fileNameP, uFontNameP, uFontNameLen); -do { - fileswitch_object_type objType; - int size; - - memcpy(&fileNameP[uFontNameLen], ".Data", sizeof(".Data")); - if ((errorP = xosfile_read_stamped_path(fileNameP, "UFont:", &objType, NULL, NULL, &size, NULL, NULL)) != NULL) - return errorP; - - if (objType == fileswitch_NOT_FOUND) - { - /* Look for the Data file one directory level up. */ - while (uFontNameLen != 0 && fileNameP[--uFontNameLen] != '.') - /* no body */; - if (uFontNameLen == 0) - return &error_exists; - } - else if (objType == fileswitch_IS_FILE) - { - if (size != 2*65536) - return &error_size; - break; - } - else - return &error_exists; - } while (1); - -/* Try to reuse an existing map : - */ -for (curMapP = oMapCollectionP; curMapP != NULL; curMapP = curMapP->nextP) - { - size_t curUFontNameLen = strlen(curMapP->uFontNameP); - - if (uFontNameLen != curUFontNameLen) - continue; - - if (memcmp(fileNameP, curMapP->uFontNameP, curUFontNameLen) != 0) - break; - } -if (curMapP != NULL) - { - ++curMapP->refCount; - *mapPP = curMapP; - return NULL; - } - -/* We need to create & load new map into memory : - */ -if ((curMapP = (ufont_map_t *)malloc(sizeof(ufont_map_t))) == NULL) - return &error_memory; - -/* Load Data file : - */ -if ((errorP = xosfile_load_stamped_path(fileNameP, (byte *)&curMapP->fontnr[0], "UFont:", NULL, NULL, NULL, NULL, NULL)) != NULL) - { - free((void *)curMapP); - return errorP; - } -fileNameP[uFontNameLen] = '\0'; -if ((curMapP->uFontNameP = strdup(fileNameP)) == NULL) - { - free((void *)curMapP); - return &error_memory; - } -curMapP->refCount = 1; -curMapP->nextP = oMapCollectionP; -oMapCollectionP = curMapP; - -*mapPP = curMapP; -return NULL; -} - - -static os_error *delete_map(ufont_map_t *mapP) -{ -assert(mapP->refCount > 0); ---mapP->refCount; -/** \todo: we don't remove the map from the oMapCollection list. Should we ? - */ - -return NULL; -} - - -/** - * Convert next sequence of UTF-8 bytes into wchar_t - * - * \param pwc resulting wchar_t result. - * \param s ptr to UTF-8 encoded string - * \param n maximum of bytes which can be consumed via s - * \return - * x > 0: number of bytes consumed at s, valid wchar_t returned at pwc[0] - * x = 0: too few input bytes, pwc[0] is undefined - * x < 0: illegal UTF-8 stream, skip -x characters at s, pwc[0] is undefined - */ -static int eat_utf8(wchar_t *pwc, const byte *s, int n) -{ - byte c; - int i; - - if (n < 1) - return 0; /* not enough input bytes */ - else if ((c = s[0]) < 0x80) { - *pwc = c; - return 1; - } else if (c < 0xc2) - goto do_sync; - else if (c < 0xe0) { - if (n < 2) - return 0; /* not enough input bytes */ - if (!((s[1] ^ 0x80) < 0x40)) - goto do_sync; - *pwc = ((wchar_t) (c & 0x1f) << 6) | (wchar_t) (s[1] ^ 0x80); - return 2; - } else if (c < 0xf0) { - if (n < 3) - return 0; /* not enough input bytes */ - if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40 && (c >= 0xe1 || s[1] >= 0xa0))) - goto do_sync; - *pwc = ((wchar_t) (c & 0x0f) << 12) | ((wchar_t) (s[1] ^ 0x80) << 6) | (wchar_t) (s[2] ^ 0x80); - return 3; - } else if (c < 0xf8) { - if (n < 4) - return 0; /* not enough input bytes */ - if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40 && (s[3] ^ 0x80) < 0x40 && (c >= 0xf1 || s[1] >= 0x90))) - goto do_sync; - *pwc = ((wchar_t) (c & 0x07) << 18) | ((wchar_t) (s[1] ^ 0x80) << 12) | ((wchar_t) (s[2] ^ 0x80) << 6) | (wchar_t) (s[3] ^ 0x80); - return 4; - } else if (c < 0xfc) { - if (n < 5) - return 0; /* not enough input bytes */ - if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40 && (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40 && (c >= 0xf9 || s[1] >= 0x88))) - goto do_sync; - *pwc = ((wchar_t) (c & 0x03) << 24) | ((wchar_t) (s[1] ^ 0x80) << 18) | ((wchar_t) (s[2] ^ 0x80) << 12) | ((wchar_t) (s[3] ^ 0x80) << 6) | (wchar_t) (s[4] ^ 0x80); - return 5; - } else if (c < 0xfe) { - if (n < 6) - return 0; /* not enough input bytes */ - if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40 && (s[3] ^ 0x80) < 0x40 && (s[4] ^ 0x80) < 0x40 && (s[5] ^ 0x80) < 0x40 && (c >= 0xfd || s[1] >= 0x84))) - goto do_sync; - *pwc = ((wchar_t) (c & 0x01) << 30) | ((wchar_t) (s[1] ^ 0x80) << 24) | ((wchar_t) (s[2] ^ 0x80) << 18) | ((wchar_t) (s[3] ^ 0x80) << 12) | ((wchar_t) (s[4] ^ 0x80) << 6) | (wchar_t) (s[5] ^ 0x80); - return 6; - } - -do_sync: - /* The UTF-8 sequence at s is illegal, skipping from s onwards - * until first non top character is found or %11xxxxxx is found - * (both valid UTF-8 *starts* - not necessary valid sequences). - */ - for (i = 1; i < n && !((s[i] & 0x80) == 0x00 || (s[i] & 0xC0) == 0xC0); ++i) - /* no body */; - return -i; -} - - -/** - * Adds the RISC OS font <fontNameP> to the oVirtualFHArrayP list and - * returns the index in that array. - * oVirtualFHArrayP can be reallocated (and all virFHP ptrs in oUsageChain). - * Results in xresOutP and yresOutP are not always that meaningful because - * of the delayed-loading of the real RISC OS font data. - * xresOutP and/or yresOutP may be NULL. - */ -static os_error *addref_virtual_fonthandle(const char *fontNameP, int xsize, int ysize, int xres, int yres, int *xresOutP, int *yresOutP, size_t *offsetP) -{ - size_t curIndex; - virtual_fh_t *unusedSlotP; - - assert(offsetP != NULL); - - do_sanity_check("addref_virtual_fonthandle() : begin"); - - if (oVirtualFHArrayP == NULL) { - if ((oVirtualFHArrayP = (virtual_fh_t *)calloc(kInitialFHArraySize, sizeof(virtual_fh_t))) == NULL) - return &error_memory; - /* oCurVirtualFHArrayElems = 0; Isn't really necessary because of static */ - oMaxVirtualFHArrayElems = kInitialFHArraySize; - } - - /* Check for duplicate (and find first unused slot if any) : - */ - for (unusedSlotP = NULL, curIndex = 0; - curIndex < oCurVirtualFHArrayElems; - ++curIndex) { - virtual_fh_t *virFHP = &oVirtualFHArrayP[curIndex]; - - if (virFHP->fontNameP != NULL /* case strdup(fontNameP) failed */ - && stricmp(virFHP->fontNameP, fontNameP) == 0 - && virFHP->xsize == xsize && virFHP->ysize == ysize) { - if (xresOutP != NULL) - *xresOutP = virFHP->xres; - if (yresOutP != NULL) - *yresOutP = virFHP->yres; - ++virFHP->refCount; - *offsetP = curIndex; - do_sanity_check("addref_virtual_fonthandle() : case 1"); - return NULL; - } - - if (virFHP->refCount == 0 && unusedSlotP == NULL) - unusedSlotP = virFHP; - } - - /* Can we reuse a slot ? - * I.e. a virtual FH which refCount is zero. - */ - if (unusedSlotP != NULL) { - if (unusedSlotP->usageP != NULL) { - os_error *errorP; - - /* This slot is refered in the usage chain, we have to unlink it. - */ - if ((errorP = remove_usage_chain_elem(unusedSlotP->usageP)) != NULL) - return errorP; - } - - unusedSlotP->usage = 0; - if (unusedSlotP->fontNameP != NULL) - free((void *)unusedSlotP->fontNameP); - if ((unusedSlotP->fontNameP = strdup(fontNameP)) == NULL) - return &error_memory; - - unusedSlotP->xsize = xsize; - unusedSlotP->ysize = ysize; - unusedSlotP->xres = (xres > 1) ? xres : 96; - if (xresOutP != NULL) - *xresOutP = unusedSlotP->xres; - unusedSlotP->yres = (yres > 1) ? yres : 96; - if (yresOutP != NULL) - *yresOutP = unusedSlotP->yres; - unusedSlotP->refCount = 1; - *offsetP = unusedSlotP - oVirtualFHArrayP; - do_sanity_check("addref_virtual_fonthandle() : case 2"); - return NULL; - } - - /* Add new entry : - */ - if (oCurVirtualFHArrayElems == oMaxVirtualFHArrayElems) { - virtual_fh_t *newVirtualFHArrayP; - size_t extraOffset; - usage_chain_t *usageP; - - /* Don't use realloc() as when that fails, we don't even have the original - * memory block anymore. - */ - if ((newVirtualFHArrayP = (virtual_fh_t *)calloc(2*oMaxVirtualFHArrayElems, sizeof(virtual_fh_t))) == NULL) - return &error_memory; - memcpy(newVirtualFHArrayP, oVirtualFHArrayP, oMaxVirtualFHArrayElems * sizeof(virtual_fh_t)); - free((void *)oVirtualFHArrayP); - extraOffset = (const char *)newVirtualFHArrayP - (const char *)oVirtualFHArrayP; - oVirtualFHArrayP = newVirtualFHArrayP; - oMaxVirtualFHArrayElems *= 2; - - /* Update the virFHP pointers in the usage chain : - */ - if (oUsageChain.nextP != NULL) { - for (usageP = oUsageChain.nextP; usageP != &oUsageChain; usageP = usageP->nextP) - usageP->virFHP = (virtual_fh_t *)&((char *)usageP->virFHP)[extraOffset]; - } - } - - unusedSlotP = &oVirtualFHArrayP[oCurVirtualFHArrayElems]; - if ((unusedSlotP->fontNameP = (const char *)strdup(fontNameP)) == NULL) - return &error_memory; - unusedSlotP->xsize = xsize; - unusedSlotP->ysize = ysize; - unusedSlotP->xres = (xres > 1) ? xres : 96; - if (xresOutP != NULL) - *xresOutP = unusedSlotP->xres; - unusedSlotP->yres = (yres > 1) ? yres : 96; - if (yresOutP != NULL) - *yresOutP = unusedSlotP->yres; - unusedSlotP->refCount = 1; - *offsetP = oCurVirtualFHArrayElems++; - - do_sanity_check("addref_virtual_fonthandle() : case 3"); - return NULL; -} - - -/** - * Deref virtual_fh_t element in oVirtualFHArrayP array. - */ -static os_error *deref_virtual_fonthandle(size_t offset) -{ - assert(/* offset >= 0 && */ offset < oCurVirtualFHArrayElems); - assert(oVirtualFHArrayP[offset].refCount > 0); - - /* When the refCount reaches 0, it will be reused by preference when a - * new usageChain element is needed in addref_virtual_fonthandle(). - */ - --oVirtualFHArrayP[offset].refCount; - - do_sanity_check("deref_virtual_fonthandle()"); - return NULL; -} - - -/** - * Virtual font handle <virFHP> needs to have a RISC OS font handle - * associated via virFHP->usageP. For this we can throw out all other - * usage chain elements which have a chainTimer different from oChainTimer. - * However, we may not have more than kMaxUsageChainElems chain elements - * active. - * Afterwards: either an error, either virFHP->usageP points to an usage chain - * element in the oUsageChain linked list and that usage chain element has - * a valid RISC OS font handle associated. - */ -static os_error *activate_virtual_fh(virtual_fh_t *virFHP) -{ - usage_chain_t *usageP; - - dbg_fprintf(stderr, "+++ activate_virtual_fh(virFHP %p, usageP ? %p)\n", virFHP, virFHP->usageP); - do_sanity_check("activate_virtual_fh() : begin"); - - /* The easiest case : we already have a RISC OS font handle : - */ - if ((usageP = virFHP->usageP) != NULL) { - usageP->chainTimer = oChainTimer; - assert(usageP->ro_fhandle != 0); - assert(usageP->virFHP == virFHP); - do_sanity_check("activate_virtual_fh() : case 1"); - dbg_fprintf(stderr, "--- done, activate_virtual_fh(), case 1\n"); - return NULL; - } - - /* The second easiest case : we're still allowed to create an extra - * chain element : - */ - if (oCurUsageChainElems < kMaxUsageChainElems) { - os_error *errorP; - - if ((usageP = (usage_chain_t *)malloc(sizeof(usage_chain_t))) == NULL) - return &error_memory; - usageP->chainTimer = oChainTimer; - - if ((errorP = xfont_find_font(virFHP->fontNameP, - virFHP->xsize, virFHP->ysize, - virFHP->xres, virFHP->yres, - &usageP->ro_fhandle, - &virFHP->xres, &virFHP->yres)) != NULL) { - free((void *)usageP); - return errorP; - } - usageP->virFHP = virFHP; - virFHP->usageP = usageP; - ++oCurUsageChainElems; - - /* Make sure oUsageChain nextP and prevP point to at least something (is - * only executed once and should probably better be done in a global - * init routine). - */ - if (oUsageChain.nextP == NULL) - oUsageChain.nextP = oUsageChain.prevP = &oUsageChain; - } - else { - os_error *errorP; - - /* The more difficult one : we need to reuse a usage chain element. - * Take the last one because that is least used but skip the onces - * with chainTimer equal to the current oChainTimer because those - * RISC OS font handles are still used in the font string we're - * currently processing. - */ - for (usageP = oUsageChain.prevP; - usageP != &oUsageChain && usageP->chainTimer == oChainTimer; - usageP = usageP->prevP) - /* no body */; - if (usageP == &oUsageChain) { - /* Painful : all usage chain elements are in use and we already have the - * maximum of chain elements reached. - */ - return &error_toomany_handles; - } - - usageP->chainTimer = oChainTimer; - /* The virtual font handle currently in usageP->virFHP no longer has a real - * RISC OS font handle anymore. - */ - usageP->virFHP->usageP = NULL; - if ((errorP = xfont_lose_font(usageP->ro_fhandle)) != NULL) - return errorP; - if ((errorP = xfont_find_font(virFHP->fontNameP, - virFHP->xsize, virFHP->ysize, - virFHP->xres, virFHP->yres, - &usageP->ro_fhandle, - &virFHP->xres, &virFHP->yres)) != NULL) - return errorP; - usageP->virFHP = virFHP; - virFHP->usageP = usageP; - - /* Delink : - */ - usageP->prevP->nextP = usageP->nextP; - usageP->nextP->prevP = usageP->prevP; - } - - /* Link usageP in the oUsageChain based on its current virFHP->usage value : - */ - { - const unsigned int usage = virFHP->usage; - usage_chain_t *runUsageP; - - for (runUsageP = &oUsageChain; - runUsageP != oUsageChain.nextP && runUsageP->prevP->virFHP->usage <= usage; - runUsageP = runUsageP->prevP) - /* no body */; - - /* We have to link usageP between runUsageP and runUsageP->prevP - * because runUsageP->prevP has higher usage than the one we need to - * link in -or- we're at the end/start. - */ - usageP->nextP = runUsageP; - usageP->prevP = runUsageP->prevP; - runUsageP->prevP->nextP = usageP; - runUsageP->prevP = usageP; - } - do_sanity_check("activate_virtual_fh() : case 2"); - dbg_fprintf(stderr, "--- done, activate_virtual_fh(), case 2\n"); - - return NULL; -} - - -/** - * Remove the usage_chaint_t element from the usage chain - */ -static os_error *remove_usage_chain_elem(usage_chain_t *usageP) -{ - os_error *errorP; - - assert(usageP != NULL); - assert(oCurUsageChainElems > 0); - assert(usageP->ro_fhandle != 0); - assert(usageP->virFHP != NULL); - - if ((errorP = xfont_lose_font(usageP->ro_fhandle)) != NULL) - return errorP; - - usageP->virFHP->usageP = NULL; - - /* Delink it : - */ - usageP->prevP->nextP = usageP->nextP; - usageP->nextP->prevP = usageP->prevP; - - --oCurUsageChainElems; - free((void *)usageP); - - do_sanity_check("remove_usage_chain_elem() : end"); - return NULL; -} - - -/*** - * Should be called when the usage_chain_t element is no longer in the right - * place in the chain based on its virFHP->usage value. - * - * usageP is no longer in the right place in the chain because its - * ->virFHP->usage value increased. Reposition it towards prev - * direction. - */ -static void repos_usage_chain_elem(usage_chain_t *usageP) -{ - usage_chain_t *prev1P, *prev2P; - const unsigned int curUsage = usageP->virFHP->usage; - - dbg_fprintf(stderr, "+++ repos_usage_chain_elem(%p)\n", usageP); - - /* If this assert goes off, then it means that this routine shouldn't - * have been called. - */ - assert(curUsage > usageP->prevP->virFHP->usage); - - /* Delink : - */ - usageP->prevP->nextP = usageP->nextP; - usageP->nextP->prevP = usageP->prevP; - - /* Place usageElemP between prev1P and prev2P. - */ - for (prev1P = usageP->prevP, prev2P = prev1P->prevP; - prev2P != &oUsageChain && curUsage > prev2P->virFHP->usage; - prev1P = prev2P, prev2P = prev2P->prevP) { - dbg_fprintf(stderr, "> prev1P %p (%d), usageElemP %p (%d), prev2P %p (%d), dummy %p\n", prev1P, prev1P->virFHP->usage, usageP, usageP->virFHP->usage, prev2P, prev2P->virFHP->usage, &oUsageChain); - assert(prev1P->virFHP->usage <= prev2P->virFHP->usage); - } - - dbg_fprintf(stderr, "prev1P %p (%d), usageElemP %p (%d), prev2P %p (%d), dummy %p\n", prev1P, prev1P->virFHP->usage, usageP, usageP->virFHP->usage, prev2P, prev2P->virFHP->usage, &oUsageChain); - - /* Relink between prev1P and prev2P : - */ - prev1P->prevP = usageP; - usageP->prevP = prev2P; - prev2P->nextP = usageP; - usageP->nextP = prev1P; - - do_sanity_check("repos_usage_chain_elem() : end"); - dbg_fprintf(stderr, "--- done, repos_usage_chain_elem()\n"); -} - - -/** - * Retrieves the RISC OS font name of given RISC OS fonthandle. - * - * \param rofhandle RISC OS font handle - */ -static const char *get_rofontname(font_f rofhandle) -{ - usage_chain_t *usageP; - - if (oUsageChain.nextP == NULL) - return NULL; - - for (usageP = oUsageChain.nextP; usageP != &oUsageChain; usageP = usageP->nextP) - if (usageP->ro_fhandle == rofhandle) - return usageP->virFHP->fontNameP; - - return NULL; -} - - -#ifdef DEBUG_DUMP_INTERNALS -/** - * Prints to stderr the complete internal state of UFont. - */ -static void dump_internals(void) -{ - fprintf(stderr, "Dump UFont internals:\n - Virtual font handle array at %p (length %d, max length %d)\n - Usage chain elements %d\n - Chain timer is %d\n Dump usage chain (first dummy at %p):\n", oVirtualFHArrayP, oCurVirtualFHArrayElems, oMaxVirtualFHArrayElems, oCurUsageChainElems, oChainTimer, &oUsageChain); - if (oUsageChain.prevP == NULL || oUsageChain.nextP == NULL) { - fprintf(stderr, " Empty usage chain\n"); - if (oUsageChain.prevP != oUsageChain.nextP) - fprintf(stderr, " *** Corrupted empty usage chain: next %p, prev %p\n", oUsageChain.nextP, oUsageChain.prevP); - if (oCurUsageChainElems != 0) - fprintf(stderr, " *** Current usage chain length is wrong\n"); - } - else { - size_t usageCount; - const usage_chain_t *usageP; - - for (usageCount = 0, usageP = oUsageChain.nextP; usageP != &oUsageChain; ++usageCount, usageP = usageP->nextP) { - fprintf(stderr, " -%d- : cur %p, next %p, prev %p, timer %d, RISC OS font handle %d, virtual font %p (%d, %s), usage %d\n", usageCount, usageP, usageP->nextP, usageP->prevP, usageP->chainTimer, usageP->ro_fhandle, usageP->virFHP, usageP->virFHP - oVirtualFHArrayP, usageP->virFHP->fontNameP, usageP->virFHP->usage); - if (usageP->nextP->prevP != usageP) - fprintf(stderr, " *** Bad usageP->nextP->prevP != usageP\n"); - if (usageP->prevP->nextP != usageP) - fprintf(stderr, " *** Bad usageP->prevP->nextP != usageP\n"); - if (usageP->virFHP < oVirtualFHArrayP || usageP->virFHP >= &oVirtualFHArrayP[oCurVirtualFHArrayElems]) - fprintf(stderr, " *** Bad virtual font handle\n"); - } - if (usageCount != oCurUsageChainElems) - fprintf(stderr, " *** Current usage chain length is wrong\n"); - if (usageCount > kMaxUsageChainElems) - fprintf(stderr, " *** Current usage chain is too long\n"); - } - - if (oVirtualFHArrayP != NULL) { - size_t fhIndex; - - fprintf(stderr, " Dump virtual font handles:\n"); - for (fhIndex = 0; fhIndex < oCurVirtualFHArrayElems; ++fhIndex) { - const virtual_fh_t *virFHP = &oVirtualFHArrayP[fhIndex]; - - fprintf(stderr, " -%d (%p)- : <%s>, size %d,%d, res %d,%d, usage %d, ref count %d, usage chain ptr %p\n", fhIndex, virFHP, virFHP->fontNameP, virFHP->xsize, virFHP->ysize, virFHP->xres, virFHP->yres, virFHP->usage, virFHP->refCount, virFHP->usageP); - if (virFHP->usageP != NULL) { - const usage_chain_t *usageP; - - for (usageP = oUsageChain.nextP; - usageP != virFHP->usageP && usageP != &oUsageChain; - usageP = usageP->nextP) - /* no body */; - if (usageP != virFHP->usageP) - fprintf(stderr, " *** Usage chain ptr could not be found in usage chain\n"); - } - } - } -} -#endif - - -/** - * Does do a full sanity check of UFont internal datastructures. - * Will assert() when something odd if found. - */ -static int sanity_check(const char *testMsgP) -{ - dbg_fprintf(stderr, "Sanity check <%s>\n", testMsgP); - if (oUsageChain.prevP == NULL || oUsageChain.nextP == NULL) { - assert(oUsageChain.prevP == oUsageChain.nextP); - assert(oCurUsageChainElems == 0); - } - else { - size_t usageCount; - const usage_chain_t *usageP; - - /* We should see equal or decreasing usage values. - */ - for (usageCount = 0, usageP = oUsageChain.nextP; usageP != &oUsageChain; ++usageCount, usageP = usageP->nextP) { - assert(usageP->nextP->prevP == usageP); - assert(usageP->prevP->nextP == usageP); - assert(usageP->chainTimer <= oChainTimer); - assert(usageP->ro_fhandle != 0); - assert(oVirtualFHArrayP != NULL); - assert(usageP->virFHP >= oVirtualFHArrayP && usageP->virFHP < &oVirtualFHArrayP[oCurVirtualFHArrayElems]); - assert(usageP->virFHP->usageP == usageP); - assert(usageP == oUsageChain.prevP || usageP->virFHP->usage >= usageP->nextP->virFHP->usage); - } - assert(usageCount == oCurUsageChainElems); - assert(usageCount <= kMaxUsageChainElems); - } - - if (oVirtualFHArrayP != NULL) { - size_t fhIndex; - - for (fhIndex = 0; fhIndex < oCurVirtualFHArrayElems; ++fhIndex) { - const virtual_fh_t *virFHP = &oVirtualFHArrayP[fhIndex]; - - if (virFHP->usageP != NULL) { - const usage_chain_t *usageP; - - assert(virFHP->fontNameP != NULL); - assert(virFHP->xsize > 0 && virFHP->ysize > 0); - assert(virFHP->xres > 0 && virFHP->yres > 0); - for (usageP = oUsageChain.nextP; - usageP != virFHP->usageP && usageP != &oUsageChain; - usageP = usageP->nextP) - /* no body */; - assert(usageP == virFHP->usageP); - } - } - } - - return 0; -} |