From b3714b1e85fd81d4f7db3c562483232fd6a89807 Mon Sep 17 00:00:00 2001 From: Harley Acheson Date: Sun, 25 Sep 2022 11:25:31 -0700 Subject: BLF: Refactor of blf_font_boundbox_foreach_glyph Refactor of `BLF_boundbox_foreach_glyph` and simplification of its usage by only passing translated glyph bounds to callbacks. See D15765 for more details. Differential Revision: https://developer.blender.org/D15765 Reviewed by Campbell Barton --- source/blender/blenfont/BLF_api.h | 27 +++-- source/blender/blenfont/intern/blf.c | 37 ++++--- source/blender/blenfont/intern/blf_font.c | 116 ++++++++++++++------- source/blender/blenfont/intern/blf_internal.h | 18 ++-- .../blender/editors/interface/interface_handlers.c | 38 +------ .../blender/editors/interface/interface_widgets.c | 59 +++-------- 6 files changed, 148 insertions(+), 147 deletions(-) diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h index af2e4fd1784..01b6d1d8942 100644 --- a/source/blender/blenfont/BLF_api.h +++ b/source/blender/blenfont/BLF_api.h @@ -118,10 +118,7 @@ int BLF_draw_mono(int fontid, const char *str, size_t str_len, int cwidth) ATTR_ typedef bool (*BLF_GlyphBoundsFn)(const char *str, size_t str_step_ofs, - const struct rcti *glyph_step_bounds, - int glyph_advance_x, - const struct rcti *glyph_bounds, - const int glyph_bearing[2], + const struct rcti *bounds, void *user_data); /** @@ -132,18 +129,28 @@ typedef bool (*BLF_GlyphBoundsFn)(const char *str, * * \note The font position, clipping, matrix and rotation are not applied. */ -void BLF_boundbox_foreach_glyph_ex(int fontid, - const char *str, - size_t str_len, - BLF_GlyphBoundsFn user_fn, - void *user_data, - struct ResultBLF *r_info) ATTR_NONNULL(2); void BLF_boundbox_foreach_glyph(int fontid, const char *str, size_t str_len, BLF_GlyphBoundsFn user_fn, void *user_data) ATTR_NONNULL(2); +/** + * Get the byte offset within a string, selected by mouse at a horizontal location. + */ +size_t BLF_str_offset_from_cursor_position(int fontid, + const char *str, + size_t str_len, + int location_x); + +/** + * Return bounds of the glyph rect at the string offset. + */ +bool BLF_str_offset_to_glyph_bounds(int fontid, + const char *str, + size_t str_offset, + struct rcti *glyph_bounds); + /** * Get the string byte offset that fits within a given width. */ diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index df8a9734c9a..57c1e280e8d 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -563,32 +563,45 @@ int BLF_draw_mono(int fontid, const char *str, const size_t str_len, int cwidth) return columns; } -void BLF_boundbox_foreach_glyph_ex(int fontid, - const char *str, - size_t str_len, - BLF_GlyphBoundsFn user_fn, - void *user_data, - struct ResultBLF *r_info) +void BLF_boundbox_foreach_glyph( + int fontid, const char *str, size_t str_len, BLF_GlyphBoundsFn user_fn, void *user_data) { FontBLF *font = blf_get(fontid); - BLF_RESULT_CHECK_INIT(r_info); - if (font) { if (font->flags & BLF_WORD_WRAP) { /* TODO: word-wrap support. */ BLI_assert(0); } else { - blf_font_boundbox_foreach_glyph(font, str, str_len, user_fn, user_data, r_info); + blf_font_boundbox_foreach_glyph(font, str, str_len, user_fn, user_data); } } } -void BLF_boundbox_foreach_glyph( - int fontid, const char *str, const size_t str_len, BLF_GlyphBoundsFn user_fn, void *user_data) +size_t BLF_str_offset_from_cursor_position(int fontid, + const char *str, + size_t str_len, + int location_x) { - BLF_boundbox_foreach_glyph_ex(fontid, str, str_len, user_fn, user_data, NULL); + FontBLF *font = blf_get(fontid); + if (font) { + return blf_str_offset_from_cursor_position(font, str, str_len, location_x); + } + return 0; +} + +bool BLF_str_offset_to_glyph_bounds(int fontid, + const char *str, + size_t str_offset, + rcti *glyph_bounds) +{ + FontBLF *font = blf_get(fontid); + if (font) { + blf_str_offset_to_glyph_bounds(font, str, str_offset, glyph_bounds); + return true; + } + return false; } size_t BLF_width_to_strlen( diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 9ea7e529df2..cbf656289b5 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -901,25 +901,23 @@ float blf_font_fixed_width(FontBLF *font) return width; } -static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font, - GlyphCacheBLF *gc, - const char *str, - const size_t str_len, - BLF_GlyphBoundsFn user_fn, - void *user_data, - struct ResultBLF *r_info, - ft_pix pen_y) +void blf_font_boundbox_foreach_glyph(FontBLF *font, + const char *str, + const size_t str_len, + BLF_GlyphBoundsFn user_fn, + void *user_data) { GlyphBLF *g, *g_prev = NULL; ft_pix pen_x = 0; size_t i = 0, i_curr; - rcti gbox_px; if (str_len == 0 || str[0] == 0) { /* early output. */ return; } + GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); + while ((i < str_len) && str[i]) { i_curr = i; g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i); @@ -928,44 +926,88 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font, continue; } pen_x += blf_kerning(font, g_prev, g); - const ft_pix pen_x_next = ft_pix_round_advance(pen_x, g->advance_x); - - gbox_px.xmin = ft_pix_to_int_floor(pen_x); - gbox_px.xmax = ft_pix_to_int_ceil(pen_x_next); - gbox_px.ymin = ft_pix_to_int_floor(pen_y); - gbox_px.ymax = gbox_px.ymin - g->dims[1]; - const int advance_x_px = gbox_px.xmax - gbox_px.xmin; - - pen_x = pen_x_next; - rcti box_px; - box_px.xmin = ft_pix_to_int_floor(g->box_xmin); - box_px.xmax = ft_pix_to_int_ceil(g->box_xmax); - box_px.ymin = ft_pix_to_int_floor(g->box_ymin); - box_px.ymax = ft_pix_to_int_ceil(g->box_ymax); + rcti bounds; + bounds.xmin = ft_pix_to_int_floor(pen_x) + ft_pix_to_int_floor(g->box_xmin); + bounds.xmax = ft_pix_to_int_floor(pen_x) + ft_pix_to_int_ceil(g->box_xmax); + bounds.ymin = ft_pix_to_int_floor(g->box_ymin); + bounds.ymax = ft_pix_to_int_ceil(g->box_ymax); - if (user_fn(str, i_curr, &gbox_px, advance_x_px, &box_px, g->pos, user_data) == false) { + if (user_fn(str, i_curr, &bounds, user_data) == false) { break; } - + pen_x = ft_pix_round_advance(pen_x, g->advance_x); g_prev = g; } - if (r_info) { - r_info->lines = 1; - r_info->width = ft_pix_to_int(pen_x); + blf_glyph_cache_release(font); +} + +typedef struct CursorPositionForeachGlyph_Data { + /** Horizontal position to test. */ + int location_x; + /** Write the character offset here. */ + size_t r_offset; +} CursorPositionForeachGlyph_Data; + +static bool blf_cursor_position_foreach_glyph(const char *UNUSED(str), + const size_t str_step_ofs, + const rcti *bounds, + void *user_data) +{ + CursorPositionForeachGlyph_Data *data = user_data; + if (data->location_x < (bounds->xmin + bounds->xmax) / 2) { + data->r_offset = str_step_ofs; + return false; } + return true; } -void blf_font_boundbox_foreach_glyph(FontBLF *font, - const char *str, - const size_t str_len, - BLF_GlyphBoundsFn user_fn, - void *user_data, - struct ResultBLF *r_info) + +size_t blf_str_offset_from_cursor_position(struct FontBLF *font, + const char *str, + size_t str_len, + int location_x) { - GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - blf_font_boundbox_foreach_glyph_ex(font, gc, str, str_len, user_fn, user_data, r_info, 0); - blf_glyph_cache_release(font); + CursorPositionForeachGlyph_Data data = { + .location_x = location_x, + .r_offset = (size_t)-1, + }; + blf_font_boundbox_foreach_glyph(font, str, str_len, blf_cursor_position_foreach_glyph, &data); + if (data.r_offset == (size_t)-1) { + data.r_offset = BLI_strnlen(str, str_len); + } + return data.r_offset; +} + +typedef struct StrOffsetToGlyphBounds_Data { + size_t str_offset; + rcti bounds; +} StrOffsetToGlyphBounds_Data; + +static bool blf_str_offset_foreach_glyph(const char *UNUSED(str), + const size_t str_step_ofs, + const rcti *bounds, + void *user_data) +{ + StrOffsetToGlyphBounds_Data *data = user_data; + if (data->str_offset == str_step_ofs) { + data->bounds = *bounds; + return false; + } + return true; +} + +void blf_str_offset_to_glyph_bounds(struct FontBLF *font, + const char *str, + size_t str_offset, + rcti *glyph_bounds) +{ + StrOffsetToGlyphBounds_Data data = { + .str_offset = str_offset, + .bounds = {0}, + }; + blf_font_boundbox_foreach_glyph(font, str, str_offset + 1, blf_str_offset_foreach_glyph, &data); + *glyph_bounds = data.bounds; } /** \} */ diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h index 28f433a3018..2f3f7b52233 100644 --- a/source/blender/blenfont/intern/blf_internal.h +++ b/source/blender/blenfont/intern/blf_internal.h @@ -141,13 +141,19 @@ void blf_font_boundbox_foreach_glyph(struct FontBLF *font, size_t str_len, bool (*user_fn)(const char *str, size_t str_step_ofs, - const struct rcti *glyph_step_bounds, - int glyph_advance_x, - const struct rcti *glyph_bounds, - const int glyph_bearing[2], + const struct rcti *bounds, void *user_data), - void *user_data, - struct ResultBLF *r_info); + void *user_data); + +size_t blf_str_offset_from_cursor_position(struct FontBLF *font, + const char *str, + size_t str_len, + int location_x); + +void blf_str_offset_to_glyph_bounds(struct FontBLF *font, + const char *str, + size_t str_offset, + struct rcti *glyph_bounds); void blf_font_free(struct FontBLF *font); diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index a6c700bdc2f..56b550995be 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -3017,23 +3017,6 @@ static bool ui_textedit_delete_selection(uiBut *but, uiHandleButtonData *data) return changed; } -static bool ui_textedit_set_cursor_pos_foreach_glyph(const char *UNUSED(str), - const size_t str_step_ofs, - const rcti *glyph_step_bounds, - const int UNUSED(glyph_advance_x), - const rcti *glyph_bounds, - const int UNUSED(glyph_bearing[2]), - void *user_data) -{ - int *cursor_data = user_data; - const int center = glyph_step_bounds->xmin + (BLI_rcti_size_x(glyph_bounds) / 2.0f); - if (cursor_data[0] < center) { - cursor_data[1] = str_step_ofs; - return false; - } - return true; -} - /** * \param x: Screen space cursor location - #wmEvent.x * @@ -3064,7 +3047,7 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con startx += UI_DPI_ICON_SIZE / aspect; } } - startx += (UI_TEXT_MARGIN_X * U.widget_unit) / aspect; + startx += (UI_TEXT_MARGIN_X * U.widget_unit - U.pixelsize) / aspect; /* mouse dragged outside the widget to the left */ if (x < startx) { @@ -3088,23 +3071,8 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con } /* mouse inside the widget, mouse coords mapped in widget space */ else { - str_last = &str[but->ofs]; - const int str_last_len = strlen(str_last); - const int x_pos = (int)(x - startx); - int glyph_data[2] = { - x_pos, /* horizontal position to test. */ - -1, /* Write the character offset here. */ - }; - BLF_boundbox_foreach_glyph(fstyle.uifont_id, - str + but->ofs, - INT_MAX, - ui_textedit_set_cursor_pos_foreach_glyph, - glyph_data); - /* If value untouched then we are to the right. */ - if (glyph_data[1] == -1) { - glyph_data[1] = str_last_len; - } - but->pos = glyph_data[1] + but->ofs; + but->pos = but->ofs + BLF_str_offset_from_cursor_position( + fstyle.uifont_id, str + but->ofs, INT_MAX, (int)(x - startx)); } ui_but_text_password_hide(password_str, but, true); diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 1b13632b131..6ba80e2e0d9 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1858,33 +1858,6 @@ static void widget_draw_text_ime_underline(const uiFontStyle *fstyle, } #endif /* WITH_INPUT_IME */ -struct UnderlineData { - size_t str_offset; /* The string offset of the underlined character. */ - int width_px; /* The underline width in pixels. */ - int r_offset_px[2]; /* Write the X,Y offset here. */ -}; - -static bool widget_draw_text_underline_calc_position(const char *UNUSED(str), - const size_t str_step_ofs, - const rcti *glyph_step_bounds, - const int UNUSED(glyph_advance_x), - const rcti *glyph_bounds, - const int UNUSED(glyph_bearing[2]), - void *user_data) -{ - struct UnderlineData *ul_data = user_data; - if (ul_data->str_offset == str_step_ofs) { - /* Full width of this glyph including both bearings. */ - const int width = glyph_bounds->xmin + BLI_rcti_size_x(glyph_bounds) + glyph_bounds->xmin; - ul_data->r_offset_px[0] = glyph_step_bounds->xmin + ((width - ul_data->width_px) / 2); - /* One line-width below the lower glyph bounds. */ - ul_data->r_offset_px[1] = glyph_bounds->ymin - U.pixelsize; - /* Early exit. */ - return false; - } - return true; -} - static void widget_draw_text(const uiFontStyle *fstyle, const uiWidgetColors *wcol, uiBut *but, @@ -2150,26 +2123,18 @@ static void widget_draw_text(const uiFontStyle *fstyle, } if (ul_index != -1) { - int ul_width = round_fl_to_int(BLF_width(fstyle->uifont_id, "_", 2)); - - struct UnderlineData ul_data = { - .str_offset = ul_index, - .width_px = ul_width, - }; - - BLF_boundbox_foreach_glyph(fstyle->uifont_id, - drawstr_ofs, - ul_index + 1, - widget_draw_text_underline_calc_position, - &ul_data); - - const int pos_x = rect->xmin + font_xofs + ul_data.r_offset_px[0]; - const int pos_y = rect->ymin + font_yofs + ul_data.r_offset_px[1]; - - /* Use text output because direct drawing doesn't always work. See T89246. */ - BLF_position(fstyle->uifont_id, pos_x, pos_y, 0.0f); - BLF_color4ubv(fstyle->uifont_id, wcol->text); - BLF_draw(fstyle->uifont_id, "_", 2); + rcti bounds; + if (BLF_str_offset_to_glyph_bounds(fstyle->uifont_id, drawstr_ofs, ul_index, &bounds) && + !BLI_rcti_is_empty(&bounds)) { + int ul_width = round_fl_to_int(BLF_width(fstyle->uifont_id, "_", 2)); + int pos_x = rect->xmin + font_xofs + bounds.xmin + + (bounds.xmax - bounds.xmin - ul_width) / 2; + int pos_y = rect->ymin + font_yofs + bounds.ymin - U.pixelsize; + /* Use text output because direct drawing doesn't always work. See T89246. */ + BLF_position(fstyle->uifont_id, (float)pos_x, pos_y, 0.0f); + BLF_color4ubv(fstyle->uifont_id, wcol->text); + BLF_draw(fstyle->uifont_id, "_", 2); + } } } } -- cgit v1.2.3