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
This commit is contained in:
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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,46 +926,90 @@ 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;
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
size_t blf_str_offset_from_cursor_position(struct FontBLF *font,
|
||||
const char *str,
|
||||
size_t str_len,
|
||||
int location_x)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user