diff --git a/source/blender/blenfont/intern/blf.cc b/source/blender/blenfont/intern/blf.cc index 1f7059cfb62..252fe0efee2 100644 --- a/source/blender/blenfont/intern/blf.cc +++ b/source/blender/blenfont/intern/blf.cc @@ -101,7 +101,7 @@ void BLF_cache_clear() for (int i = 0; i < BLF_MAX_FONT; i++) { FontBLF *font = global_font[i]; if (font) { - blf_glyph_cache_clear(font); + font->cache->clear(); } } } diff --git a/source/blender/blenfont/intern/blf_font.cc b/source/blender/blenfont/intern/blf_font.cc index dcd8b550df2..72b0c255c32 100644 --- a/source/blender/blenfont/intern/blf_font.cc +++ b/source/blender/blenfont/intern/blf_font.cc @@ -420,7 +420,7 @@ BLI_INLINE GlyphBLF *blf_glyph_from_utf8_and_step(FontBLF *font, /* Invalid unicode sequences return the byte value, stepping forward one. * This allows `latin1` to display (which is sometimes used for file-paths). */ BLI_assert(charcode != BLI_UTF8_ERR); - GlyphBLF *g = blf_glyph_ensure(font, gc, charcode); + GlyphBLF *g = GlyphBLF::glyph_ensure(font, gc, charcode); if (g && pen_x && !(font->flags & BLF_MONOSPACED)) { *pen_x += blf_kerning(font, g_prev, g); @@ -433,7 +433,7 @@ BLI_INLINE GlyphBLF *blf_glyph_from_utf8_and_step(FontBLF *font, #endif #ifdef BLF_SUBPIXEL_AA - g = blf_glyph_ensure_subpixel(font, gc, g, *pen_x); + g = g->glyph_refine(font, gc, *pen_x); #endif } return g; @@ -469,7 +469,7 @@ static void blf_font_draw_ex(FontBLF *font, continue; } /* Do not return this loop if clipped, we want every character tested. */ - blf_glyph_draw(font, gc, g, ft_pix_to_int_floor(pen_x), ft_pix_to_int_floor(pen_y)); + g->draw(font, gc, ft_pix_to_int_floor(pen_x), ft_pix_to_int_floor(pen_y)); pen_x += g->advance_x; } @@ -482,9 +482,9 @@ static void blf_font_draw_ex(FontBLF *font, } void blf_font_draw(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info) { - GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); + GlyphCacheBLF *gc = font->cache->acquire(); blf_font_draw_ex(font, gc, str, str_len, r_info, 0); - blf_glyph_cache_release(font); + font->cache->release(); } int blf_font_draw_mono( @@ -497,7 +497,7 @@ int blf_font_draw_mono( size_t i = 0; - GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); + GlyphCacheBLF *gc = font->cache->acquire(); blf_batch_draw_begin(font); @@ -508,7 +508,7 @@ int blf_font_draw_mono( continue; } /* Do not return this loop if clipped, we want every character tested. */ - blf_glyph_draw(font, gc, g, ft_pix_to_int_floor(pen_x), ft_pix_to_int_floor(pen_y)); + g->draw(font, gc, ft_pix_to_int_floor(pen_x), ft_pix_to_int_floor(pen_y)); const int col = UNLIKELY(g->c == '\t') ? (tab_columns - (columns % tab_columns)) : BLI_wcwidth_safe(char32_t(g->c)); @@ -518,7 +518,7 @@ int blf_font_draw_mono( blf_batch_draw_end(); - blf_glyph_cache_release(font); + font->cache->release(); return columns; } @@ -674,9 +674,9 @@ static void blf_font_draw_buffer_ex(FontBLF *font, void blf_font_draw_buffer(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info) { - GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); + GlyphCacheBLF *gc = font->cache->acquire(); blf_font_draw_buffer_ex(font, gc, str, str_len, r_info, 0); - blf_glyph_cache_release(font); + font->cache->release(); } /** \} */ @@ -713,7 +713,7 @@ static bool blf_font_width_to_strlen_glyph_process(FontBLF *font, #endif #ifdef BLF_SUBPIXEL_AA - g = blf_glyph_ensure_subpixel(font, gc, g, *pen_x); + g = g->glyph_refine(font, gc, *pen_x); #endif } @@ -731,7 +731,7 @@ size_t blf_font_width_to_strlen( ft_pix width_new; size_t i, i_prev; - GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); + GlyphCacheBLF *gc = font->cache->acquire(); const int width_i = int(width); for (i_prev = i = 0, width_new = pen_x = 0, g_prev = nullptr; (i < str_len) && str[i]; @@ -747,7 +747,7 @@ size_t blf_font_width_to_strlen( *r_width = ft_pix_to_int(width_new); } - blf_glyph_cache_release(font); + font->cache->release(); return i_prev; } @@ -759,7 +759,7 @@ size_t blf_font_width_to_rstrlen( size_t i, i_prev, i_tmp; const char *s, *s_prev; - GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); + GlyphCacheBLF *gc = font->cache->acquire(); i = BLI_strnlen(str, str_len); s = BLI_str_find_prev_char_utf8(&str[i], str); @@ -790,7 +790,7 @@ size_t blf_font_width_to_rstrlen( *r_width = ft_pix_to_int(width_new); } - blf_glyph_cache_release(font); + font->cache->release(); return i; } @@ -867,9 +867,9 @@ static void blf_font_boundbox_ex(FontBLF *font, void blf_font_boundbox( FontBLF *font, const char *str, const size_t str_len, rcti *r_box, ResultBLF *r_info) { - GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); + GlyphCacheBLF *gc = font->cache->acquire(); blf_font_boundbox_ex(font, gc, str, str_len, r_box, r_info, 0); - blf_glyph_cache_release(font); + font->cache->release(); } void blf_font_width_and_height(FontBLF *font, @@ -945,9 +945,9 @@ float blf_font_height(FontBLF *font, const char *str, const size_t str_len, Resu float blf_font_fixed_width(FontBLF *font) { - GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); + GlyphCacheBLF *gc = font->cache->acquire(); float width = (gc) ? float(gc->fixed_width) : font->size / 2.0f; - blf_glyph_cache_release(font); + font->cache->release(); return width; } @@ -966,7 +966,7 @@ void blf_font_boundbox_foreach_glyph(FontBLF *font, ft_pix pen_x = 0; size_t i = 0; - GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); + GlyphCacheBLF *gc = font->cache->acquire(); while ((i < str_len) && str[i]) { const size_t i_curr = i; @@ -987,7 +987,7 @@ void blf_font_boundbox_foreach_glyph(FontBLF *font, pen_x += g->advance_x; } - blf_glyph_cache_release(font); + font->cache->release(); } struct CursorPositionForeachGlyph_Data { @@ -1104,7 +1104,7 @@ static void blf_font_wrap_apply(FontBLF *font, ft_pix line_height = blf_font_height_max_ft_pix(font); - GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); + GlyphCacheBLF *gc = font->cache->acquire(); struct WordWrapVars { ft_pix wrap_width; @@ -1183,7 +1183,7 @@ static void blf_font_wrap_apply(FontBLF *font, r_info->width = ft_pix_to_int(pen_x_next); } - blf_glyph_cache_release(font); + font->cache->release(); } /** Utility for #blf_font_draw__wrap. */ @@ -1376,7 +1376,6 @@ static void blf_font_fill(FontBLF *font) font->char_width = 1.0f; font->char_spacing = 0.0f; - BLI_listbase_clear(&font->cache); font->kerning_cache = nullptr; #if BLF_BLUR_ENABLE font->blur = 0; @@ -1738,6 +1737,8 @@ static FontBLF *blf_font_new_impl(const char *filepath, { FontBLF *font = (FontBLF *)MEM_callocN(sizeof(FontBLF), "blf_font_new"); + font->cache = new GlyphCacheListBLF(font); + font->mem_name = mem_name ? BLI_strdup(mem_name) : nullptr; font->filepath = filepath ? BLI_strdup(filepath) : nullptr; if (mem) { @@ -1756,8 +1757,6 @@ static FontBLF *blf_font_new_impl(const char *filepath, font->ft_lib = ft_library ? (FT_Library)ft_library : ft_lib; - BLI_mutex_init(&font->glyph_cache_mutex); - /* If we have static details about this font file, we don't have to load the Face yet. */ bool face_needed = true; @@ -1826,7 +1825,7 @@ void blf_font_attach_from_mem(FontBLF *font, const uchar *mem, const size_t mem_ void blf_font_free(FontBLF *font) { - blf_glyph_cache_clear(font); + delete font->cache; if (font->kerning_cache) { MEM_freeN(font->kerning_cache); @@ -1854,8 +1853,6 @@ void blf_font_free(FontBLF *font) MEM_freeN(font->mem_name); } - BLI_mutex_end(&font->glyph_cache_mutex); - MEM_freeN(font); } diff --git a/source/blender/blenfont/intern/blf_glyph.cc b/source/blender/blenfont/intern/blf_glyph.cc index 3fdb2d99db3..f17e92a1c2a 100644 --- a/source/blender/blenfont/intern/blf_glyph.cc +++ b/source/blender/blenfont/intern/blf_glyph.cc @@ -71,40 +71,115 @@ static float from_16dot16(FT_Fixed value) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Glyph Cache +/** \name Glyph Cache List * \{ */ -static GlyphCacheBLF *blf_glyph_cache_find(const FontBLF *font, const float size) +GlyphCacheListBLF::GlyphCacheListBLF(FontBLF *font) : list{}, font(font) { - GlyphCacheBLF *gc = (GlyphCacheBLF *)font->cache.first; - while (gc) { - if (gc->size == size && (gc->bold == ((font->flags & BLF_BOLD) != 0)) && - (gc->italic == ((font->flags & BLF_ITALIC) != 0)) && - (gc->char_weight == font->char_weight) && (gc->char_slant == font->char_slant) && - (gc->char_width == font->char_width) && (gc->char_spacing == font->char_spacing)) - { - return gc; + BLI_mutex_init(&glyph_cache_mutex); +}; + +GlyphCacheListBLF ::~GlyphCacheListBLF() +{ + clear(); + BLI_mutex_end(&glyph_cache_mutex); +}; + +GlyphCacheBLF *GlyphCacheListBLF::acquire() +{ + BLI_mutex_lock(&glyph_cache_mutex); + + GlyphCacheBLF *gc = nullptr; + + for (auto &entry : list) { + if (entry->matches(font)) { + gc = entry; + break; } - gc = gc->next; } - return nullptr; + + if (!gc) { + gc = new GlyphCacheBLF(); + gc->init(font); + list.push_back(gc); + } + + return gc; } -static GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font) +void GlyphCacheListBLF::release() { - GlyphCacheBLF *gc = (GlyphCacheBLF *)MEM_callocN(sizeof(GlyphCacheBLF), "blf_glyph_cache_new"); + BLI_mutex_unlock(&glyph_cache_mutex); +} - gc->next = nullptr; - gc->prev = nullptr; - gc->size = font->size; - gc->bold = ((font->flags & BLF_BOLD) != 0); - gc->italic = ((font->flags & BLF_ITALIC) != 0); - gc->char_weight = font->char_weight; - gc->char_slant = font->char_slant; - gc->char_width = font->char_width; - gc->char_spacing = font->char_spacing; +void GlyphCacheListBLF::clear() +{ + BLI_mutex_lock(&glyph_cache_mutex); + for (auto &entry : list) { + delete entry; + } + list.clear(); + BLI_mutex_unlock(&glyph_cache_mutex); +} - memset(gc->bucket, 0, sizeof(gc->bucket)); +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Glyph Cache Entry + * \{ */ + +GlyphCacheBLF::GlyphCacheBLF() + : next(nullptr), + prev(nullptr), + size(11.0f), + char_weight(400), + char_slant(0.0f), + char_width(1.0f), + char_spacing(1.0f), + bold(false), + italic(false), + bucket{nullptr, nullptr}, + fixed_width(6), + texture(nullptr), + bitmap_result(nullptr), + bitmap_len(0), + bitmap_len_landed(0), + bitmap_len_alloc(0) +{ +} + +GlyphCacheBLF::~GlyphCacheBLF() +{ + for (uint i = 0; i < ARRAY_SIZE(bucket); i++) { + while (GlyphBLF *g = static_cast(BLI_pophead(&bucket[i]))) { + delete g; + } + } + if (texture) { + GPU_texture_free(texture); + } + if (bitmap_result) { + MEM_freeN(bitmap_result); + } +} + +bool GlyphCacheBLF::matches(FontBLF *font) const +{ + return (size == font->size && (bold == ((font->flags & BLF_BOLD) != 0)) && + (italic == ((font->flags & BLF_ITALIC) != 0)) && (char_weight == font->char_weight) && + (char_slant == font->char_slant) && (char_width == font->char_width) && + (char_spacing == font->char_spacing)); +} + +void GlyphCacheBLF::init(FontBLF *font) +{ + size = font->size; + char_weight = font->char_weight; + char_slant = font->char_slant; + char_width = font->char_width; + char_spacing = font->char_spacing; + bold = (font->flags & BLF_BOLD) != 0; + italic = ((font->flags & BLF_ITALIC) != 0); blf_ensure_size(font); @@ -114,82 +189,63 @@ static GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font) FT_Fixed advance = 0; FT_Get_Advance(font->face, gindex, FT_LOAD_NO_HINTING, &advance); /* Use CSS 'ch unit' width, advance of zero character. */ - gc->fixed_width = int(advance >> 16); + fixed_width = int(advance >> 16); } else { /* Font does not have a face or does not contain "0" so use CSS fallback of 1/2 of em. */ - gc->fixed_width = int((font->ft_size->metrics.height / 2) >> 6); + fixed_width = int((font->ft_size->metrics.height / 2) >> 6); } - if (gc->fixed_width < 1) { - gc->fixed_width = 1; + if (fixed_width < 1) { + fixed_width = 1; } - - BLI_addhead(&font->cache, gc); - return gc; } -GlyphCacheBLF *blf_glyph_cache_acquire(FontBLF *font) +void GlyphCacheBLF::cache_glyph(GlyphBLF *glyph, uint charcode, uint8_t subpixel) { - BLI_mutex_lock(&font->glyph_cache_mutex); - - GlyphCacheBLF *gc = blf_glyph_cache_find(font, font->size); - - if (!gc) { - gc = blf_glyph_cache_new(font); - } - - return gc; + BLI_addhead(&(bucket[blf_hash(charcode << 6 | subpixel)]), glyph); } -void blf_glyph_cache_release(FontBLF *font) +GlyphBLF *GlyphCacheBLF::find_glyph(uint charcode, uint8_t subpixel) const { - BLI_mutex_unlock(&font->glyph_cache_mutex); + GlyphBLF *g = static_cast(bucket[blf_hash(charcode << 6 | subpixel)].first); + return GlyphBLF::cache_match(g, charcode, subpixel); } -static void blf_glyph_cache_free(GlyphCacheBLF *gc) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name GlyphBLF + * \{ */ + +GlyphBLF::GlyphBLF() + : next(nullptr), + prev(nullptr), + c(0), + idx(0), + box_xmin(0), + box_xmax(INT_MAX), + box_ymin(0), + box_ymax(INT_MAX), + advance_x(0), + subpixel(0), + lsb_delta(0), + rsb_delta(0), + offset(0), + bitmap(nullptr), + dims{0, 0}, + pitch(0), + depth(0), + render_mode(0), + pos{0, 0}, + glyph_cache(nullptr) { - for (uint i = 0; i < ARRAY_SIZE(gc->bucket); i++) { - while (GlyphBLF *g = static_cast(BLI_pophead(&gc->bucket[i]))) { - blf_glyph_free(g); - } - } - if (gc->texture) { - GPU_texture_free(gc->texture); - } - if (gc->bitmap_result) { - MEM_freeN(gc->bitmap_result); - } - MEM_freeN(gc); } -void blf_glyph_cache_clear(FontBLF *font) +GlyphBLF::~GlyphBLF() { - BLI_mutex_lock(&font->glyph_cache_mutex); - - while (GlyphCacheBLF *gc = static_cast(BLI_pophead(&font->cache))) { - blf_glyph_cache_free(gc); + if (bitmap) { + MEM_freeN(bitmap); } - - BLI_mutex_unlock(&font->glyph_cache_mutex); -} - -/** - * Try to find a glyph in cache. - * - * \return nullptr if not found. - */ -static GlyphBLF *blf_glyph_cache_find_glyph(const GlyphCacheBLF *gc, - uint charcode, - uint8_t subpixel) -{ - GlyphBLF *g = static_cast(gc->bucket[blf_hash(charcode << 6 | subpixel)].first); - while (g) { - if (g->c == charcode && g->subpixel == subpixel) { - return g; - } - g = g->next; - } - return nullptr; } #ifdef BLF_GAMMA_CORRECT_GLYPHS @@ -232,14 +288,11 @@ static uchar blf_glyph_gamma(uchar c) /** * 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, - uint8_t subpixel) +GlyphBLF *GlyphBLF::create( + FontBLF *font, FT_GlyphSlot glyph, uint charcode, FT_UInt glyph_index, uint8_t subpixel) { - GlyphBLF *g = (GlyphBLF *)MEM_callocN(sizeof(GlyphBLF), "blf_glyph_get"); + GlyphBLF *g = new GlyphBLF(); + g->c = charcode; g->idx = glyph_index; g->advance_x = (ft_pix)glyph->advance.x; @@ -291,7 +344,7 @@ static GlyphBLF *blf_glyph_cache_add_glyph(FontBLF *font, } const int buffer_size = g->dims[0] * g->dims[1] * g->depth; - g->bitmap = static_cast(MEM_mallocN(size_t(buffer_size), "glyph bitmap")); + g->bitmap = static_cast(MEM_mallocN(size_t(buffer_size), __func__)); if (ELEM(glyph->bitmap.pixel_mode, FT_PIXEL_MODE_GRAY, @@ -351,12 +404,20 @@ static GlyphBLF *blf_glyph_cache_add_glyph(FontBLF *font, memcpy(g->bitmap, glyph->bitmap.buffer, size_t(buffer_size)); } } - - BLI_addhead(&(gc->bucket[blf_hash(g->c << 6 | subpixel)]), g); - return g; } +GlyphBLF *GlyphBLF::cache_match(GlyphBLF *glyph, uint charcode, uint8_t subpixel) +{ + while (glyph) { + if (glyph->c == charcode && glyph->subpixel == subpixel) { + return glyph; + } + glyph = glyph->next; + } + return nullptr; +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -791,7 +852,7 @@ static FT_UInt blf_glyph_index_from_charcode(FontBLF **font, const uint charcode /** * 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, bool outline_only) +static FT_GlyphSlot blf_glyph_load(FontBLF *font, FT_UInt glyph_index, bool outline_only = false) { int load_flags; @@ -1202,7 +1263,7 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font, uint charcode, uint8_t subpixel, int fixed_width, - bool outline_only) + bool outline_only = false) { if (glyph_font != settings_font) { blf_font_size(glyph_font, settings_font->size); @@ -1231,7 +1292,7 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font, /* Font variations need to be set before glyph loading. Even if new value is zero. */ if (glyph_font->variations) { - FT_Fixed coords[BLF_VARIATIONS_MAX]; + FT_Fixed coords[BLF_VARIATIONS_MAX] = {0}; /* Load current design coordinates. */ FT_Get_Var_Design_Coordinates(glyph_font->face, BLF_VARIATIONS_MAX, &coords[0]); /* Update design coordinates with new values. */ @@ -1285,12 +1346,12 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font, return nullptr; } -static GlyphBLF *blf_glyph_ensure_ex(FontBLF *font, - GlyphCacheBLF *gc, - const uint charcode, - uint8_t subpixel) +GlyphBLF *GlyphBLF::glyph_ensure(FontBLF *font, + GlyphCacheBLF *gc, + const uint charcode, + uint8_t subpixel) { - GlyphBLF *g = blf_glyph_cache_find_glyph(gc, charcode, subpixel); + GlyphBLF *g = gc->find_glyph(charcode, subpixel); if (g) { return g; } @@ -1304,81 +1365,69 @@ static GlyphBLF *blf_glyph_ensure_ex(FontBLF *font, } FT_GlyphSlot glyph = blf_glyph_render( - font, font_with_glyph, glyph_index, charcode, subpixel, gc->fixed_width, false); + font, font_with_glyph, glyph_index, charcode, subpixel, gc->fixed_width); if (glyph) { /* Save this glyph in the initial font's cache. */ - g = blf_glyph_cache_add_glyph(font, gc, glyph, charcode, glyph_index, subpixel); + g = GlyphBLF::create(font, glyph, charcode, glyph_index, subpixel); + gc->cache_glyph(g, charcode, subpixel); } return g; } -GlyphBLF *blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, const uint charcode) -{ - return blf_glyph_ensure_ex(font, gc, charcode, 0); -} - #ifdef BLF_SUBPIXEL_AA -GlyphBLF *blf_glyph_ensure_subpixel(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, int32_t pen_x) +GlyphBLF *GlyphBLF::glyph_refine(FontBLF *font, GlyphCacheBLF *gc, int32_t pen_x) { if (!(font->flags & BLF_RENDER_SUBPIXELAA)) { /* Not if we are in mono mode (aliased) or the feature is turned off. */ - return g; + return this; } - if (font->size > 35.0f || g->dims[0] == 0 || g->advance_x < 0) { + if (font->size > 35.0f || dims[0] == 0 || advance_x < 0) { /* Single position for large sizes, spaces, and combining characters. */ - return g; + return this; } /* Four sub-pixel positions up to 16 point, 2 until 35 points. */ const uint8_t subpixel = uint8_t(pen_x & ((font->size > 16.0f) ? 32L : 48L)); - if (g->subpixel != subpixel) { - g = blf_glyph_ensure_ex(font, gc, g->c, subpixel); + if (subpixel != subpixel) { + return GlyphBLF::glyph_ensure(font, gc, c, subpixel); } - return g; + + return this; } #endif -void blf_glyph_free(GlyphBLF *g) -{ - if (g->bitmap) { - MEM_freeN(g->bitmap); - } - MEM_freeN(g); -} - /** \} */ /* -------------------------------------------------------------------- */ /** \name Glyph Bounds Calculation * \{ */ -static void blf_glyph_calc_rect(rcti *rect, GlyphBLF *g, const int x, const int y) +void GlyphBLF::calc_rect(rcti *rect, const int x, const int y) const { - rect->xmin = x + g->pos[0]; - rect->xmax = rect->xmin + g->dims[0]; - rect->ymin = y + g->pos[1]; - rect->ymax = rect->ymin - g->dims[1]; + rect->xmin = x + pos[0]; + rect->xmax = rect->xmin + dims[0]; + rect->ymin = y + pos[1]; + rect->ymax = rect->ymin - dims[1]; } -static void blf_glyph_calc_rect_test(rcti *rect, GlyphBLF *g, const int x, const int y) +void GlyphBLF::calc_rect_test(rcti *rect, const int x, const int y) { /* Intentionally check with `g->advance`, because this is the * width used by BLF_width. This allows that the text slightly * overlaps the clipping border to achieve better alignment. */ - rect->xmin = x + abs(g->pos[0]) + 1; - rect->xmax = x + std::min(ft_pix_to_int(g->advance_x), g->dims[0]); + rect->xmin = x + abs(pos[0]) + 1; + rect->xmax = x + std::min(ft_pix_to_int(advance_x), dims[0]); rect->ymin = y; - rect->ymax = rect->ymin - g->dims[1]; + rect->ymax = rect->ymin - dims[1]; } -static void blf_glyph_calc_rect_shadow( - rcti *rect, GlyphBLF *g, const int x, const int y, FontBLF *font) +void GlyphBLF::calc_rect_shadow(rcti *rect, const int x, const int y, FontBLF *font) const { - blf_glyph_calc_rect(rect, g, x + font->shadow_x, y + font->shadow_y); + calc_rect(rect, x + font->shadow_x, y + font->shadow_y); } /** \} */ @@ -1387,13 +1436,12 @@ static void blf_glyph_calc_rect_shadow( /** \name Glyph Drawing * \{ */ -static void blf_texture_draw(GlyphBLF *g, - const uchar color[4], - const int glyph_size[2], - const int x1, - const int y1, - const int x2, - const int y2) +void GlyphBLF::texture_draw(const uchar color[4], + const int glyph_size[2], + const int x1, + const int y1, + const int x2, + const int y2) const { /* Only one vertex per glyph, geometry shader expand it into a quad. */ /* TODO: Get rid of Geom Shader because it's not optimal AT ALL for the GPU. */ @@ -1404,9 +1452,9 @@ static void blf_texture_draw(GlyphBLF *g, float(y2 + g_batch.ofs[1])); copy_v4_v4_uchar(static_cast(GPU_vertbuf_raw_step(&g_batch.col_step)), color); copy_v2_v2_int(static_cast(GPU_vertbuf_raw_step(&g_batch.glyph_size_step)), glyph_size); - *((int *)GPU_vertbuf_raw_step(&g_batch.offset_step)) = g->offset; - *((int *)GPU_vertbuf_raw_step(&g_batch.glyph_comp_len_step)) = g->depth; - *((int *)GPU_vertbuf_raw_step(&g_batch.glyph_mode_step)) = g->render_mode; + *((int *)GPU_vertbuf_raw_step(&g_batch.offset_step)) = offset; + *((int *)GPU_vertbuf_raw_step(&g_batch.glyph_comp_len_step)) = depth; + *((int *)GPU_vertbuf_raw_step(&g_batch.glyph_mode_step)) = render_mode; g_batch.glyph_len++; /* Flush cache if it's full. */ @@ -1415,42 +1463,42 @@ static void blf_texture_draw(GlyphBLF *g, } } -static void blf_texture5_draw( - GlyphBLF *g, const uchar color_in[4], const int x1, const int y1, const int x2, const int y2) +void GlyphBLF::texture5_draw( + const uchar color_in[4], const int x1, const int y1, const int x2, const int y2) const { - int glyph_size_flag[2]; + int glyph_size_flag[2] = {0}; /* flag the x and y component signs for 5x5 blurring */ - glyph_size_flag[0] = -g->dims[0]; - glyph_size_flag[1] = -g->dims[1]; + glyph_size_flag[0] = -dims[0]; + glyph_size_flag[1] = -dims[1]; - blf_texture_draw(g, color_in, glyph_size_flag, x1, y1, x2, y2); + texture_draw(color_in, glyph_size_flag, x1, y1, x2, y2); } -static void blf_texture3_draw( - GlyphBLF *g, const uchar color_in[4], const int x1, const int y1, const int x2, const int y2) +void GlyphBLF::texture3_draw( + const uchar color_in[4], const int x1, const int y1, const int x2, const int y2) const { - int glyph_size_flag[2]; + int glyph_size_flag[2] = {0}; /* flag the x component sign for 3x3 blurring */ - glyph_size_flag[0] = -g->dims[0]; - glyph_size_flag[1] = g->dims[1]; + glyph_size_flag[0] = -dims[0]; + glyph_size_flag[1] = dims[1]; - blf_texture_draw(g, color_in, glyph_size_flag, x1, y1, x2, y2); + texture_draw(color_in, glyph_size_flag, x1, y1, x2, y2); } -void blf_glyph_draw(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, const int x, const int y) +void GlyphBLF::draw(FontBLF *font, GlyphCacheBLF *gc, const int x, const int y) { - if ((!g->dims[0]) || (!g->dims[1])) { + if ((!dims[0]) || (!dims[1])) { return; } - if (g->glyph_cache == nullptr) { + if (glyph_cache == nullptr) { if (font->tex_size_max == -1) { font->tex_size_max = GPU_max_texture_size(); } - g->offset = gc->bitmap_len; + offset = gc->bitmap_len; - int buff_size = g->dims[0] * g->dims[1] * g->depth; + int buff_size = dims[0] * dims[1] * depth; int bitmap_len = gc->bitmap_len + buff_size; if (bitmap_len > gc->bitmap_len_alloc) { @@ -1471,10 +1519,10 @@ void blf_glyph_draw(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, const int x, gc->bitmap_len_landed = 0; } - memcpy(&gc->bitmap_result[gc->bitmap_len], g->bitmap, size_t(buff_size)); + memcpy(&gc->bitmap_result[gc->bitmap_len], bitmap, size_t(buff_size)); gc->bitmap_len = bitmap_len; - g->glyph_cache = gc; + glyph_cache = gc; } if (font->flags & BLF_CLIPPING) { @@ -1490,57 +1538,52 @@ void blf_glyph_draw(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, const int x, } rcti rect_test; - blf_glyph_calc_rect_test(&rect_test, g, int(float(x) * xa), int(float(y) * ya)); + calc_rect_test(&rect_test, int(float(x) * xa), int(float(y) * ya)); BLI_rcti_translate(&rect_test, font->pos[0], font->pos[1]); if (!BLI_rcti_inside_rcti(&font->clip_rec, &rect_test)) { return; } } - if (g_batch.glyph_cache != g->glyph_cache) { + if (g_batch.glyph_cache != glyph_cache) { blf_batch_draw(); - g_batch.glyph_cache = g->glyph_cache; + g_batch.glyph_cache = glyph_cache; } if (font->flags & BLF_SHADOW) { rcti rect_ofs; - blf_glyph_calc_rect_shadow(&rect_ofs, g, x, y, font); + calc_rect_shadow(&rect_ofs, x, y, font); if (font->shadow == 0) { - blf_texture_draw(g, - font->shadow_color, - g->dims, - rect_ofs.xmin, - rect_ofs.ymin, - rect_ofs.xmax, - rect_ofs.ymax); + texture_draw( + font->shadow_color, dims, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax); } else if (font->shadow <= 4) { - blf_texture3_draw( - g, font->shadow_color, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax); + texture3_draw( + font->shadow_color, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax); } else { - blf_texture5_draw( - g, font->shadow_color, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax); + texture5_draw( + font->shadow_color, rect_ofs.xmin, rect_ofs.ymin, rect_ofs.xmax, rect_ofs.ymax); } } rcti rect; - blf_glyph_calc_rect(&rect, g, x, y); + calc_rect(&rect, x, y); #if BLF_BLUR_ENABLE switch (font->blur) { case 3: - blf_texture3_draw(g, font->color, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + texture3_draw(font->color, rect.xmin, rect.ymin, rect.xmax, rect.ymax); break; case 5: - blf_texture5_draw(g, font->color, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + texture5_draw(font->color, rect.xmin, rect.ymin, rect.xmax, rect.ymax); break; default: - blf_texture_draw(g, font->color, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + texture_draw(font->color, rect.xmin, rect.ymin, rect.xmax, rect.ymax); } #else - blf_texture_draw(g, font->color, g->dims, rect.xmin, rect.ymin, rect.xmax, rect.ymax); + texture_draw(font->color, dims, rect.xmin, rect.ymin, rect.xmax, rect.ymax); #endif } diff --git a/source/blender/blenfont/intern/blf_internal.hh b/source/blender/blenfont/intern/blf_internal.hh index 5c0bafa2d89..679ae7b0bb5 100644 --- a/source/blender/blenfont/intern/blf_internal.hh +++ b/source/blender/blenfont/intern/blf_internal.hh @@ -9,8 +9,8 @@ #pragma once struct FontBLF; -struct GlyphBLF; -struct GlyphCacheBLF; +class GlyphBLF; +class GlyphCacheBLF; struct ResultBLF; struct rcti; @@ -166,22 +166,6 @@ void blf_str_offset_to_glyph_bounds(struct FontBLF *font, void blf_font_free(struct FontBLF *font); -struct GlyphCacheBLF *blf_glyph_cache_acquire(struct FontBLF *font); -void blf_glyph_cache_release(struct FontBLF *font); -void blf_glyph_cache_clear(struct FontBLF *font); - -/** - * Create (or load from cache) a fully-rendered bitmap glyph. - */ -struct GlyphBLF *blf_glyph_ensure(struct FontBLF *font, struct GlyphCacheBLF *gc, uint charcode); - -#ifdef BLF_SUBPIXEL_AA -struct GlyphBLF *blf_glyph_ensure_subpixel(struct FontBLF *font, - struct GlyphCacheBLF *gc, - struct GlyphBLF *g, - int32_t pen_x); -#endif - /** * Convert a character's outlines into curves. */ @@ -190,10 +174,6 @@ float blf_character_to_curves(FontBLF *font, struct ListBase *nurbsbase, const float scale); -void blf_glyph_free(struct GlyphBLF *g); -void blf_glyph_draw( - struct FontBLF *font, struct GlyphCacheBLF *gc, struct GlyphBLF *g, int x, int y); - #ifdef WIN32 /* `blf_font_win32_compat.cc` */ diff --git a/source/blender/blenfont/intern/blf_internal_types.hh b/source/blender/blenfont/intern/blf_internal_types.hh index b92e951894d..e730997a0ff 100644 --- a/source/blender/blenfont/intern/blf_internal_types.hh +++ b/source/blender/blenfont/intern/blf_internal_types.hh @@ -8,6 +8,8 @@ #pragma once +#include + #include "GPU_texture.h" #include "GPU_vertex_buffer.h" @@ -93,7 +95,7 @@ typedef struct BatchBLF { /* Previous call `modelmatrix`. */ float mat[4][4]; bool enabled, active, simple_shader; - struct GlyphCacheBLF *glyph_cache; + GlyphCacheBLF *glyph_cache; } BatchBLF; extern BatchBLF g_batch; @@ -106,9 +108,31 @@ typedef struct KerningCacheBLF { int ascii_table[KERNING_CACHE_TABLE_SIZE][KERNING_CACHE_TABLE_SIZE]; } KerningCacheBLF; -typedef struct GlyphCacheBLF { - struct GlyphCacheBLF *next; - struct GlyphCacheBLF *prev; +class GlyphCacheListBLF { + private: + /** + * List of glyph caches (#GlyphCacheBLF) for this font for size, DPI, bold, italic. + * Use font->cache->acquire() and font->cache->release() to access cache! + */ + std::vector list; + + FontBLF *font; + + /** Mutex lock for glyph cache. */ + ThreadMutex glyph_cache_mutex; + + public: + GlyphCacheListBLF(FontBLF *font); + ~GlyphCacheListBLF(); + GlyphCacheBLF *acquire(); + void release(); + void clear(); +}; + +class GlyphCacheBLF { + private: + GlyphCacheBLF *next; + GlyphCacheBLF *prev; /** Font size. */ float size; @@ -121,12 +145,13 @@ typedef struct GlyphCacheBLF { bool bold; bool italic; - /** Column width when printing monospaced. */ - int fixed_width; - /** The glyphs. */ ListBase bucket[257]; + public: + /** Column width when printing monospaced. */ + int fixed_width; + /** Texture array, to draw the glyphs. */ GPUTexture *texture; char *bitmap_result; @@ -134,12 +159,21 @@ typedef struct GlyphCacheBLF { int bitmap_len_landed; int bitmap_len_alloc; -} GlyphCacheBLF; + GlyphCacheBLF(); + ~GlyphCacheBLF(); + bool matches(FontBLF *font) const; + void init(FontBLF *font); + void cache_glyph(GlyphBLF *glyph, uint charcode, uint8_t subpixel); + GlyphBLF *find_glyph(uint charcode, uint8_t subpixel) const; +}; -typedef struct GlyphBLF { - struct GlyphBLF *next; - struct GlyphBLF *prev; +class GlyphBLF { + private: + GlyphBLF *next; + GlyphBLF *prev; + GlyphCacheBLF *glyph_cache; + public: /** The character, as UTF-32. */ unsigned int c; @@ -183,8 +217,41 @@ typedef struct GlyphBLF { */ int pos[2]; - struct GlyphCacheBLF *glyph_cache; -} GlyphBLF; + void calc_rect(rcti *rect, const int x, const int y) const; + void calc_rect_test(rcti *rect, const int x, const int y); + void calc_rect_shadow(rcti *rect, const int x, const int y, FontBLF *font) const; + + void texture_draw(const uchar color[4], + const int glyph_size[2], + const int x1, + const int y1, + const int x2, + const int y2) const; + void texture5_draw( + const uchar color_in[4], const int x1, const int y1, const int x2, const int y2) const; + void texture3_draw( + const uchar color_in[4], const int x1, const int y1, const int x2, const int y2) const; + + static GlyphBLF *create( + FontBLF *font, FT_GlyphSlot glyph, uint charcode, FT_UInt glyph_index, uint8_t subpixel); + + public: + GlyphBLF(); + ~GlyphBLF(); + + static GlyphBLF *glyph_ensure(struct FontBLF *font, + GlyphCacheBLF *gc, + uint charcode, + uint8_t subpixel = 0); + +#ifdef BLF_SUBPIXEL_AA + GlyphBLF *glyph_refine(struct FontBLF *font, GlyphCacheBLF *gc, int32_t pen_x); +#endif + + void draw(FontBLF *font, GlyphCacheBLF *gc, const int x, const int y); + + static GlyphBLF *cache_match(GlyphBLF *glyph, uint charcode, uint8_t subpixel); +}; typedef struct FontBufInfoBLF { /** For draw to buffer, always set this to NULL after finish! */ @@ -355,9 +422,9 @@ typedef struct FontBLF { /** * List of glyph caches (#GlyphCacheBLF) for this font for size, DPI, bold, italic. - * Use blf_glyph_cache_acquire(font) and blf_glyph_cache_release(font) to access cache! + * Use GlyphCacheBLF::cache_acquire(font) and GlyphCacheBLF::cache_release(font) to access cache! */ - ListBase cache; + GlyphCacheListBLF *cache; /** Cache of unscaled kerning values. Will be NULL if font does not have kerning. */ KerningCacheBLF *kerning_cache; @@ -379,7 +446,4 @@ typedef struct FontBLF { /** Data for buffer usage (drawing into a texture buffer) */ FontBufInfoBLF buf_info; - - /** Mutex lock for glyph cache. */ - ThreadMutex glyph_cache_mutex; } FontBLF;