diff --git a/internal/c/libqb.cpp b/internal/c/libqb.cpp index 61fe3bd26..b7ab82703 100644 --- a/internal/c/libqb.cpp +++ b/internal/c/libqb.cpp @@ -3563,7 +3563,7 @@ void convert_text_to_utf16(int32 fonthandle, void *buf, int32 size) { unicode16_buf = (uint16 *)malloc(unicode16_buf_size); } // convert text - if ((fontflags[fonthandle] & 32) && (fonthandle != NULL)) { // unicode font + if ((fontflags[fonthandle] & FONT_LOAD_UNICODE) && (fonthandle != NULL)) { // unicode font if (size == 1) size = 4; convert_unicode(32, buf, size, 16, unicode16_buf); @@ -11202,7 +11202,7 @@ void printchr(int32 character) { x = im->cursor_x - 1; y = (im->cursor_y - 1) * fontheight[f]; h = fontheight[f]; - if ((fontflags[f] & 32) == 0) + if ((fontflags[f] & FONT_LOAD_UNICODE) == 0) character &= 255; // unicodefontsupport // if (mode==1) img[i].print_mode=3;//fill @@ -11212,7 +11212,7 @@ void printchr(int32 character) { if (f >= 32) { // custom font // 8-bit / alpha-disabled 32-bit / dont-blend(alpha may still be applied) - if ((im->bytes_per_pixel == 1) || ((im->bytes_per_pixel == 4) && (im->alpha_disabled)) || (fontflags[f] & 8)) { + if ((im->bytes_per_pixel == 1) || ((im->bytes_per_pixel == 4) && (im->alpha_disabled)) || (fontflags[f] & FONT_LOAD_DONTBLEND)) { // render character static int32 ok; @@ -11408,7 +11408,7 @@ int32_t chrwidth(uint32_t character) { // Custom font // a740g: No need to render just to find the pixel length - if ((fontflags[f] & 32)) { // UNICODE character + if ((fontflags[f] & FONT_LOAD_UNICODE)) { // UNICODE character w = FontPrintWidthUTF32(font[f], (uint32_t *)&character, 1); } else { // ASCII character character &= 255; @@ -11684,7 +11684,7 @@ void qbs_print(qbs *str, int32 finish_on_new_line) { character = str->chr[i]; - if (fontflags[write_page->font] & 32) { // unicode font + if (fontflags[write_page->font] & FONT_LOAD_UNICODE) { // unicode font if (i > (str->len - 4)) break; // not enough data for a utf32 encoding character = *((int32 *)(&str->chr[i])); @@ -20141,7 +20141,7 @@ void sub__printstring(float x, float y, qbs *text, int32 i, int32 passed) { if (f >= 32) { // custom font // 8-bit / alpha-disabled 32-bit / dont-blend(alpha may still be applied) - if ((im->bytes_per_pixel == 1) || ((im->bytes_per_pixel == 4) && (im->alpha_disabled)) || (fontflags[f] & 8)) { + if ((im->bytes_per_pixel == 1) || ((im->bytes_per_pixel == 4) && (im->alpha_disabled)) || (fontflags[f] & FONT_LOAD_DONTBLEND)) { // render character static int32 ok; @@ -20376,18 +20376,14 @@ int32 func__printwidth(qbs *text, int32 screenhandle, int32 passed) { } /// @brief f = _LOADFONT(ttf_filename$, height[, "monospace,dontblend,unicode,memory"][, index]) -/// @param f The font file path name or a font memory buffer when loading from memory +/// @param qbsFileName The font file path name or a font memory buffer when loading from memory /// @param size The font height in pixels -/// @param requirements This can be monospace, dontblend, unicode, memory +/// @param qbsRequirements This can be monospace, dontblend, unicode, memory /// @param font_index The index of the font to load from a font collection /// @param passed Which optional arguments were passed /// @return Returns a valid handle on success or zero on failure -int32_t func__loadfont(qbs *file_name, int32_t size, qbs *requirements, int32_t font_index, int32_t passed) { - // Some QB strings that we'll need - static qbs *fileNameZ = nullptr; - static qbs *reqs = nullptr; - - if (is_error_pending() || !file_name->len) +int32_t func__loadfont(const qbs *qbsFileName, int32_t size, const qbs *qbsRequirements, int32_t font_index, int32_t passed) { + if (is_error_pending() || !qbsFileName->len) return INVALID_FONT_HANDLE; // return invalid handle for any garbage input // validate size @@ -20396,12 +20392,6 @@ int32_t func__loadfont(qbs *file_name, int32_t size, qbs *requirements, int32_t return INVALID_FONT_HANDLE; } - if (!fileNameZ) - fileNameZ = qbs_new(0, 0); - - if (!reqs) - reqs = qbs_new(0, 0); - auto isLoadFromMemory = false; // should the font be loaded from memory? int32_t options = 0; // font flags that we'll prepare and save to fontflags[] @@ -20411,29 +20401,35 @@ int32_t func__loadfont(qbs *file_name, int32_t size, qbs *requirements, int32_t // 8 dontblend (blending is the default in 32-bit alpha-enabled modes) // 16 monospace // 32 unicode - if ((passed & 1) && requirements->len) { - FONT_DEBUG_PRINT("Parsing requirements"); + if ((passed & 1) && qbsRequirements->len) { + std::string requirements(reinterpret_cast(qbsRequirements->chr), qbsRequirements->len); + std::transform(requirements.begin(), requirements.end(), requirements.begin(), [](unsigned char c) { return std::toupper(c); }); - qbs_set(reqs, qbs_ucase(requirements)); // Convert tmp str to perm str + FONT_DEBUG_PRINT("Parsing requirements string: %s", requirements.c_str()); - if (func_instr(1, reqs, qbs_new_txt("DONTBLEND"), 1)) { + if (requirements.find("DONTBLEND") != std::string::npos) { options |= FONT_LOAD_DONTBLEND; - FONT_DEBUG_PRINT("DONTBLEND requested"); + FONT_DEBUG_PRINT("No alpha blending requested"); } - if (func_instr(1, reqs, qbs_new_txt("MONOSPACE"), 1)) { + if (requirements.find("MONOSPACE") != std::string::npos) { options |= FONT_LOAD_MONOSPACE; - FONT_DEBUG_PRINT("MONOSPACE requested"); + FONT_DEBUG_PRINT("Monospaced font requested"); } - if (func_instr(1, reqs, qbs_new_txt("UNICODE"), 1)) { + if (requirements.find("UNICODE") != std::string::npos) { options |= FONT_LOAD_UNICODE; - FONT_DEBUG_PRINT("UNICODE requested"); + FONT_DEBUG_PRINT("Unicode requested"); } - if (func_instr(1, reqs, qbs_new_txt("MEMORY"), 1)) { + if (requirements.find("MEMORY") != std::string::npos) { isLoadFromMemory = true; - FONT_DEBUG_PRINT("MEMORY requested"); + FONT_DEBUG_PRINT("Loading from memory requested"); + } + + if (requirements.find("AUTOMONO") != std::string::npos) { + options |= FONT_LOAD_AUTOMONO; + FONT_DEBUG_PRINT("Automatic monospacing requested"); } } @@ -20449,13 +20445,13 @@ int32_t func__loadfont(qbs *file_name, int32_t size, qbs *requirements, int32_t int32_t bytes; if (isLoadFromMemory) { - content = file_name->chr; // we should not free this!!! - bytes = file_name->len; + content = qbsFileName->chr; // we should not free this!!! + bytes = qbsFileName->len; FONT_DEBUG_PRINT("Loading font from memory. Size = %i", bytes); } else { - qbs_set(fileNameZ, qbs_add(file_name, qbs_new_txt_len("\0", 1))); // s1 = filename + CHR$(0) - content = FontLoadFileToMemory(filepath_fix_directory(fileNameZ), &bytes); // this we must free!!! - FONT_DEBUG_PRINT("Loading font from file %s", fileNameZ->chr); + std::string fileName(reinterpret_cast(qbsFileName->chr), qbsFileName->len); + content = FontLoadFileToMemory(filepath_fix_directory(fileName), &bytes); // this we must free!!! + FONT_DEBUG_PRINT("Loading font from file %s", fileName.c_str()); } if (!content) @@ -20489,9 +20485,9 @@ got_font_index: return INVALID_FONT_HANDLE; font[i] = h; + fontflags[i] = options; fontheight[i] = size; fontwidth[i] = FontWidth(h); - fontflags[i] = options; return i; } @@ -20537,8 +20533,8 @@ void sub__font(int32 f, int32 i, int32 passed) { return; } - if (im->text && ((fontflags[f] & 16) == 0)) { // fontflags[f] & 16 is the bit which we set for MONOSPACE fonts. If it's a SCREEN 0 screen, and the font - error(5);// isn't monospaced, toss and error and return. + if (im->text && ((fontflags[f] & FONT_LOAD_MONOSPACE) == 0)) { // fontflags[f] & 16 is the bit which we set for MONOSPACE fonts. If it's a SCREEN 0 screen, and the font + error(5); // isn't monospaced, toss an error and return. return; } // note: font changes to text screen mode images requires: @@ -29585,18 +29581,18 @@ int main(int argc, char *argv[]) { fontheight[8] = 8; fontheight[14] = 14; fontheight[16] = 16; - fontflags[8] = 16; - fontflags[14] = 16; - fontflags[16] = 16; // monospace flag + fontflags[8] = FONT_LOAD_MONOSPACE; + fontflags[14] = FONT_LOAD_MONOSPACE; + fontflags[16] = FONT_LOAD_MONOSPACE; // monospace flag fontwidth[8 + 1] = 8 * 2; fontwidth[14 + 1] = 8 * 2; fontwidth[16 + 1] = 8 * 2; fontheight[8 + 1] = 8; fontheight[14 + 1] = 14; fontheight[16 + 1] = 16; - fontflags[8 + 1] = 16; - fontflags[14 + 1] = 16; - fontflags[16 + 1] = 16; // monospace flag + fontflags[8 + 1] = FONT_LOAD_MONOSPACE; + fontflags[14 + 1] = FONT_LOAD_MONOSPACE; + fontflags[16 + 1] = FONT_LOAD_MONOSPACE; // monospace flag memset(img, 0, IMG_BUFFERSIZE * sizeof(img_struct)); x = newimg(); // reserve index 0 diff --git a/internal/c/libqb/include/font.h b/internal/c/libqb/include/font.h index f96c343f7..cb6a8fb39 100644 --- a/internal/c/libqb/include/font.h +++ b/internal/c/libqb/include/font.h @@ -19,11 +19,11 @@ FONT_DEBUG_PRINT("Condition (%s) failed", #_exp_) #else # ifdef _MSC_VER -# define FONT_DEBUG_PRINT(_fmt_, ...) // Don't do anything in release builds +# define FONT_DEBUG_PRINT(_fmt_, ...) // Don't do anything in release builds # else # define FONT_DEBUG_PRINT(_fmt_, _args_...) // Don't do anything in release builds # endif -# define FONT_DEBUG_CHECK(_exp_) // Don't do anything in release builds +# define FONT_DEBUG_CHECK(_exp_) // Don't do anything in release builds #endif #define INVALID_FONT_HANDLE 0 @@ -32,6 +32,7 @@ #define FONT_LOAD_DONTBLEND 8 #define FONT_LOAD_MONOSPACE 16 #define FONT_LOAD_UNICODE 32 +#define FONT_LOAD_AUTOMONO 64 // Font render options #define FONT_RENDER_MONOCHROME 1 @@ -41,7 +42,7 @@ struct qbs; extern uint16_t codepage437_to_unicode16[]; uint8_t *FontLoadFileToMemory(const char *file_path_name, int32_t *out_bytes); -int32_t FontLoad(const uint8_t *content_original, int32_t content_bytes, int32_t default_pixel_height, int32_t which_font, int32_t options); +int32_t FontLoad(const uint8_t *content_original, int32_t content_bytes, int32_t default_pixel_height, int32_t which_font, int32_t &options); void FontFree(int32_t fh); int32_t FontWidth(int32_t fh); bool FontRenderTextUTF32(int32_t fh, const uint32_t *codepoint, int32_t codepoints, int32_t options, uint8_t **out_data, int32_t *out_x, int32_t *out_y); diff --git a/internal/c/parts/video/font/font.cpp b/internal/c/parts/video/font/font.cpp index 1671590be..80f01a873 100644 --- a/internal/c/parts/video/font/font.cpp +++ b/internal/c/parts/video/font/font.cpp @@ -775,9 +775,9 @@ uint8_t *FontLoadFileToMemory(const char *file_path_name, int32_t *out_bytes) { /// @param content_bytes The length of the data in bytes /// @param default_pixel_height The maximum rendering height of the font /// @param which_font The font index in a font collection (< 0 means default) -/// @param options 16=monospace (all old flags are ignored like it always was since forever) +/// @param options [IN/OUT] 16=monospace (all old flags are ignored like it always was since forever) /// @return A valid font handle (> 0) or 0 on failure -int32_t FontLoad(const uint8_t *content_original, int32_t content_bytes, int32_t default_pixel_height, int32_t which_font, int32_t options) { +int32_t FontLoad(const uint8_t *content_original, int32_t content_bytes, int32_t default_pixel_height, int32_t which_font, int32_t &options) { libqb_mutex_guard lock(fontManager.m); // Allocate a font handle @@ -816,12 +816,23 @@ int32_t FontLoad(const uint8_t *content_original, int32_t content_bytes, int32_t } fontManager.fonts[h]->defaultHeight = default_pixel_height; // save default pixel height - fontManager.fonts[h]->baseline = - (FT_Pos)qbr((((double)fontManager.fonts[h]->face->size->metrics.ascender / 64.0) / ((double)fontManager.fonts[h]->face->size->metrics.height / 64.0)) * - (double)default_pixel_height); - fontManager.fonts[h]->options = options; // save the options for use later - if ((options & FONT_LOAD_MONOSPACE) || FT_IS_FIXED_WIDTH(fontManager.fonts[h]->face)) { + // Calculate the baseline using font metrics only if it is scalable + if (FT_IS_SCALABLE(fontManager.fonts[h]->face)) { + if (FT_IS_FIXED_WIDTH(fontManager.fonts[h]->face)) { + fontManager.fonts[h]->baseline = + (FT_Pos)qbr((double)fontManager.fonts[h]->face->ascender / (double)fontManager.fonts[h]->face->units_per_EM * (double)default_pixel_height); + } else { + fontManager.fonts[h]->baseline = (FT_Pos)qbr(((double)fontManager.fonts[h]->face->size->metrics.ascender / 64.0) / + ((double)fontManager.fonts[h]->face->size->metrics.height / 64.0) * (double)default_pixel_height); + } + } + + // Check if automatic fixed width font detection was requested + if ((options & FONT_LOAD_AUTOMONO) && FT_IS_FIXED_WIDTH(fontManager.fonts[h]->face)) + options |= FONT_LOAD_MONOSPACE; // force set monospace flag and pass it upstream if the font is fixed width + + if (options & FONT_LOAD_MONOSPACE) { const FT_ULong testCP = 'W'; // since W is usually the widest // Load using monochrome rendering @@ -839,8 +850,18 @@ int32_t FontLoad(const uint8_t *content_original, int32_t content_bytes, int32_t FONT_DEBUG_PRINT("Monospace font (width = %li) requested", fontManager.fonts[h]->monospaceWidth); } + + // Set the baseline to bitmap_top if the font is not scalable + if (!FT_IS_SCALABLE(fontManager.fonts[h]->face)) + fontManager.fonts[h]->baseline = fontManager.fonts[h]->face->glyph->bitmap_top; // for bitmap fonts bitmap_top is the same for all glyph bitmaps + + // Clear the monospace flag is we failed to get the monospace width + if (!fontManager.fonts[h]->monospaceWidth) + options &= ~FONT_LOAD_MONOSPACE; } + fontManager.fonts[h]->options = options; // save the options for use later + FONT_DEBUG_PRINT("Font (height = %i, index = %i) successfully initialized", default_pixel_height, which_font); return h; } @@ -1323,10 +1344,7 @@ void sub__UPrintString(int32_t start_x, int32_t start_y, const qbs *text, int32_ FONT_DEBUG_PRINT("Rendering using TrueType font"); // Render using custom font - if (FT_IS_SCALABLE(face)) - pen.y = (float)face->ascender / (float)face->units_per_EM * (float)fnt->defaultHeight; - else - pen.y = face->glyph->bitmap_top; // for bitmap fonts bitmap_top is the same for all glyph bitmaps + pen.y = fnt->baseline; FONT_DEBUG_PRINT("pen.y = %i", pen.y); diff --git a/internal/c/parts/video/font/stub_font.cpp b/internal/c/parts/video/font/stub_font.cpp index 31f739fda..3ad891d02 100644 --- a/internal/c/parts/video/font/stub_font.cpp +++ b/internal/c/parts/video/font/stub_font.cpp @@ -8,7 +8,7 @@ uint8_t *FontLoadFileToMemory(const char *file_path_name, int32_t *out_bytes) { return nullptr; } -int32_t FontLoad(const uint8_t *content_original, int32_t content_bytes, int32_t default_pixel_height, int32_t which_font, int32_t options) { +int32_t FontLoad(const uint8_t *content_original, int32_t content_bytes, int32_t default_pixel_height, int32_t which_font, int32_t &options) { (void)content_original; (void)content_bytes; (void)default_pixel_height; diff --git a/internal/c/qbx.cpp b/internal/c/qbx.cpp index ca9de8d6e..1d40e301a 100755 --- a/internal/c/qbx.cpp +++ b/internal/c/qbx.cpp @@ -410,7 +410,7 @@ extern void sub__copypalette(int32 i, int32 i2, int32 passed); extern void sub__printstring(float x, float y, qbs *text, int32 i, int32 passed); extern int32 func__printwidth(qbs *text, int32 i, int32 passed); -extern int32_t func__loadfont(qbs *file_name, int32_t size, qbs *requirements, int32_t font_index, int32_t passed); +extern int32_t func__loadfont(const qbs *qbsFileName, int32_t size, const qbs *qbsRequirements, int32_t font_index, int32_t passed); extern void sub__font(int32 f, int32 i, int32 passed); extern int32 func__fontwidth(int32 f, int32 passed); extern int32 func__fontheight(int32 f, int32 passed);