Commit: eddf5ad5819fb48b2d8ebccc30a869f86718b565 Author: Harley Acheson Date: Sat Nov 6 11:28:28 2021 -0700 Branches: master https://developer.blender.org/rBeddf5ad5819fb48b2d8ebccc30a869f86718b565
BLF: Refactor blf_glyph.c Cleanup and Simplification of blf_glyph.c See D13095 for details. Differential Revision: https://developer.blender.org/D13095 Reviewed by Campbell Barton =================================================================== M source/blender/blenfont/intern/blf_glyph.c =================================================================== diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index c4ffb3f87f1..716670ac9c4 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -55,27 +55,25 @@ #include "BLI_math_vector.h" #include "BLI_strict_flags.h" +/* Find a glyph cache that matches a size, dpi, styles. */ GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, unsigned int size, unsigned int dpi) { - GlyphCacheBLF *p; - - p = (GlyphCacheBLF *)font->cache.first; - while (p) { - if (p->size == size && p->dpi == dpi && (p->bold == ((font->flags & BLF_BOLD) != 0)) && - (p->italic == ((font->flags & BLF_ITALIC) != 0))) { - return p; + GlyphCacheBLF *gc = (GlyphCacheBLF *)font->cache.first; + while (gc) { + if (gc->size == size && gc->dpi == dpi && (gc->bold == ((font->flags & BLF_BOLD) != 0)) && + (gc->italic == ((font->flags & BLF_ITALIC) != 0))) { + return gc; } - p = p->next; + gc = gc->next; } return NULL; } -/* Create a new glyph cache for the current size, dpi, bold, italic. */ +/* Create a new glyph cache for the current size, dpi, styles. */ GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font) { - GlyphCacheBLF *gc; + GlyphCacheBLF *gc = (GlyphCacheBLF *)MEM_callocN(sizeof(GlyphCacheBLF), "blf_glyph_cache_new"); - gc = (GlyphCacheBLF *)MEM_callocN(sizeof(GlyphCacheBLF), "blf_glyph_cache_new"); gc->next = NULL; gc->prev = NULL; gc->size = font->size; @@ -138,34 +136,85 @@ void blf_glyph_cache_free(GlyphCacheBLF *gc) MEM_freeN(gc); } -static GlyphBLF *blf_glyph_search(GlyphCacheBLF *gc, unsigned int c) +/* Try to find a glyph in cache, return NULL if not found. */ +static GlyphBLF *blf_glyph_cache_find_glyph(GlyphCacheBLF *gc, uint charcode) { - GlyphBLF *p; - unsigned int key; - - key = blf_hash(c); - p = gc->bucket[key].first; - while (p) { - if (p->c == c) { - return p; + if (charcode < GLYPH_ASCII_TABLE_SIZE) { + return gc->glyph_ascii_table[charcode]; + } + + GlyphBLF *g = gc->bucket[blf_hash(charcode)].first; + while (g) { + if (g->c == charcode) { + return g; } - p = p->next; + g = g->next; } return NULL; } -static bool blf_glyph_render(FontBLF *font, FT_UInt glyph_index) +/* Add a rendered glyph to a cache. */ +static GlyphBLF *blf_glyph_cache_add_glyph( + FontBLF *font, GlyphCacheBLF *gc, FT_GlyphSlot glyph, uint charcode, FT_UInt glyph_index) +{ + GlyphBLF *g = (GlyphBLF *)MEM_callocN(sizeof(GlyphBLF), "blf_glyph_get"); + g->c = charcode; + g->idx = glyph_index; + g->advance = ((float)glyph->advance.x) / 64.0f; + g->advance_i = (int)g->advance; + g->pos[0] = glyph->bitmap_left; + g->pos[1] = glyph->bitmap_top; + g->dims[0] = (int)glyph->bitmap.width; + g->dims[1] = (int)glyph->bitmap.rows; + g->pitch = glyph->bitmap.pitch; + + FT_BBox bbox; + FT_Outline_Get_CBox(&(glyph->outline), &bbox); + g->box.xmin = ((float)bbox.xMin) / 64.0f; + g->box.xmax = ((float)bbox.xMax) / 64.0f; + g->box.ymin = ((float)bbox.yMin) / 64.0f; + g->box.ymax = ((float)bbox.yMax) / 64.0f; + + const int buffer_size = (int)(glyph->bitmap.width * glyph->bitmap.rows); + if (buffer_size != 0) { + if (font->flags & BLF_MONOCHROME) { + /* Font buffer uses only 0 or 1 values, Blender expects full 0..255 range. */ + for (int i = 0; i < buffer_size; i++) { + glyph->bitmap.buffer[i] = glyph->bitmap.buffer[i] ? 255 : 0; + } + } + g->bitmap = MEM_mallocN((size_t)buffer_size, "glyph bitmap"); + memcpy(g->bitmap, glyph->bitmap.buffer, (size_t)buffer_size); + } + + unsigned int key = blf_hash(g->c); + BLI_addhead(&(gc->bucket[key]), g); + if (charcode < GLYPH_ASCII_TABLE_SIZE) { + gc->glyph_ascii_table[charcode] = g; + } + + return g; +} + +/* Return a glyph index from a charcode. Not found returns zero, which is a valid + * printable character (.notdef or "tofu"). Font is allowed to change here. */ +static FT_UInt blf_glyph_index_from_charcode(FontBLF **font, const uint charcode) +{ + FT_UInt glyph_index = FT_Get_Char_Index((*font)->face, charcode); + /* TODO: If not found in this font, check others, update font pointer. */ + return glyph_index; +} + +/* Load a glyph into the glyph slot of a font's face object. */ +static FT_GlyphSlot blf_glyph_load(FontBLF *font, FT_UInt glyph_index) { int load_flags; - int render_mode; if (font->flags & BLF_MONOCHROME) { load_flags = FT_LOAD_TARGET_MONO; - render_mode = FT_RENDER_MODE_MONO; } else { load_flags = FT_LOAD_NO_BITMAP; - render_mode = FT_RENDER_MODE_NORMAL; if (font->flags & BLF_HINTING_NONE) { load_flags |= FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING; } @@ -182,46 +231,29 @@ static bool blf_glyph_render(FontBLF *font, FT_UInt glyph_index) } } - FT_Error err = FT_Load_Glyph(font->face, glyph_index, load_flags); - if (err != 0) { - return false; + if (FT_Load_Glyph(font->face, glyph_index, load_flags) == 0) { + return font->face->glyph; } + return NULL; +} - /* Do not oblique a font that is designed to be italic! */ - if (((font->flags & BLF_ITALIC) != 0) && !(font->face->style_flags & FT_STYLE_FLAG_ITALIC) && - (font->face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)) { - /* For (fake) italic: a shear transform with a 6 degree angle. */ - FT_Matrix transform; - transform.xx = 0x10000L; - transform.yx = 0x00000L; - transform.xy = 0x03000L; - transform.yy = 0x10000L; - FT_Outline_Transform(&font->face->glyph->outline, &transform); - } - - /* Do not embolden an already bold font! */ - if (((font->flags & BLF_BOLD) != 0) && !(font->face->style_flags & FT_STYLE_FLAG_BOLD) && - (font->face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)) { - /* Strengthen the width more than the height. */ - const FT_Pos extra_x = FT_MulFix(font->face->units_per_EM, font->face->size->metrics.x_scale) / - 14; - const FT_Pos extra_y = FT_MulFix(font->face->units_per_EM, font->face->size->metrics.y_scale) / - 28; - FT_Outline_EmboldenXY(&font->face->glyph->outline, extra_x, extra_y); - if ((font->face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) == 0) { - /* Need to increase advance, but not for fixed-width fonts. */ - font->face->glyph->advance.x += (FT_Pos)(((float)extra_x) * 1.05f); - font->face->glyph->advance.y += extra_y; - } - else { - /* Widened fixed-pitch font gets a nudge left. */ - FT_Outline_Translate(&font->face->glyph->outline, (extra_x / -2), 0); - } +/* Convert a glyph from outlines to a bitmap that we can display. */ +static bool blf_glyph_render_bitmap(FontBLF *font, FT_GlyphSlot glyph) +{ + int render_mode; + + if (font->flags & BLF_MONOCHROME) { + render_mode = FT_RENDER_MODE_MONO; + } + else { + render_mode = FT_RENDER_MODE_NORMAL; } - /* get the glyph. */ - FT_GlyphSlot slot = font->face->glyph; - err = FT_Render_Glyph(slot, render_mode); + /* Render the glyph curves to a bitmap. */ + FT_Error err = FT_Render_Glyph(glyph, render_mode); + if (err != 0) { + return false; + } FT_Bitmap tempbitmap; @@ -231,78 +263,163 @@ static bool blf_glyph_render(FontBLF *font, FT_UInt glyph_index) FT_Bitmap_New(&tempbitmap); /* Does Blender use Pitch 1 always? It works so far */ - err += FT_Bitmap_Convert(font->ft_lib, &slot->bitmap, &tempbitmap, 1); - err += FT_Bitmap_Copy(font->ft_lib, &tempbitmap, &slot->bitmap); + err += FT_Bitmap_Convert(font->ft_lib, &glyph->bitmap, &tempbitmap, 1); + err += FT_Bitmap_Copy(font->ft_lib, &tempbitmap, &glyph->bitmap); err += FT_Bitmap_Done(font->ft_lib, &tempbitmap); } - if (err || slot->format != FT_GLYPH_FORMAT_BITMAP) { + if (err || glyph->format != FT_GLYPH_FORMAT_BITMAP) { return false; } return true; } -GlyphBLF *blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, uint charcode) +/* Convert a floating point value to a FreeType 16.16 fixed point value. */ +static FT_Fixed to_16dot16(double val) { - GlyphBLF *g = (charcode < GLYPH_ASCII_TABLE_SIZE) ? (gc->glyph_ascii_table)[charcode] : - blf_glyph_search(gc, charcode); - if (g) { - return g; + return (FT_Fixed)(lround(val * 65536.0)); +} + +/* Glyph weight by factor. -1 (min stroke width) <= 0 (normal) => 1 (max boldness). */ +static bool blf_glyph_transform_weight(FT_GlyphSlot glyph, float factor, bool monospaced) +{ + if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) { + /* Fake bold if the font does not have this variable axis. */ + const FT_Pos average_width = FT_MulFix(glyph->face->units_per_EM, + glyph->face->size->metrics.x_scale); + FT_Pos change = (FT_Pos)((float)average_width * factor * 0.1f); + FT_Outline_EmboldenXY(&glyph->outline, change, change / 2); + if (monospaced) { + /* Widened fixed-pitch font needs a nudge left. */ + FT_Outline_Translate(&glyph->outline, change / -2, 0); + } + else { + /* Need to increase advance. */ + glyph->advance.x += change; + glyph->advance.y += change / 2; + } + return true; } + return false; +} - FT_UInt glyph_index = FT_Get_Char_Index(font->face, charcode); +/* Glyph oblique by factor. -1 (max negative) <= 0 (no slant) => 1 (max positive). + * Note that left-leaning italics are possibile in some RTL writing systems. */ +static bool blf_glyph_transform_slant(FT_GlyphSlot glyph, float factor) +{ + if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) { + FT_Matrix transform = {to_16dot16(1), to_16dot16(factor / 2.0f), 0, to_16dot16(1)}; + FT_Outline_Transform(&glyph->outline, &transform); + return true; + } + return false; +} - if (!blf_glyph_render(font, glyph_index)) { - return NULL; +/* Glyph width by factor. -1 (min width) <= 0 (normal) => 1 (max width). */ +static bool UNUSED_FUNCTION(blf_glyph_transform_width)(FT_GlyphSlot glyph, float factor) +{ + if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) { + float scale = (factor * 0.4f) + 1.0f; /* 0.6f - 1.4f */ + FT_Matrix matrix = {to_16dot16(scale), 0, 0, to_16d @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list [email protected] List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs
