From f2341f829654c4dc97fcf9fd1f74a6526c4f50ff Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 18 Sep 2015 20:10:26 +1000 Subject: BLF: initial word-wrap support - Adds support for word wrapping to Blender's BLF font library. - Splits lines when width limit is reached or on explicit \n newlines. Details: - Word wrapping is used when `BLF_WORD_WRAP` flag is enabled. - There is a single loop to handle line wrapping, this runs callback, passing in a substring, this way we can avoid code-duplication for all word-wrapped versions of functions... OR... avoid having to add support for word-wrapping directly into each function. - The `ResultBLF` struct was added to be able to get the number of wrapped lines, when calling otherwise unrelated functions such as `BLF_draw/BLF_width/BLF_boundbox`, which can be passed as the last argument to `BLF_*_ex()` functions. - The `ResultBLF` struct is used to store the result of drawing (currently only the number of lines wrapped, and the width). --- source/blender/blenfont/BLF_api.h | 33 ++- source/blender/blenfont/intern/blf.c | 157 ++++++++++-- source/blender/blenfont/intern/blf_font.c | 277 ++++++++++++++++++--- source/blender/blenfont/intern/blf_internal.h | 18 +- .../blender/blenfont/intern/blf_internal_types.h | 9 +- source/blender/blenfont/intern/blf_thumbs.c | 6 +- source/blender/blenkernel/intern/image.c | 22 +- source/blender/blenkernel/intern/image_gen.c | 18 +- source/blender/blenkernel/intern/seqeffects.c | 4 +- source/blender/python/generic/blf_py_api.c | 25 ++ 10 files changed, 464 insertions(+), 105 deletions(-) (limited to 'source') diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h index d8dee7110a5..9527c4edcf0 100644 --- a/source/blender/blenfont/BLF_api.h +++ b/source/blender/blenfont/BLF_api.h @@ -36,6 +36,7 @@ struct rctf; struct ColorManagedDisplay; +struct ResultBLF; int BLF_init(int points, int dpi); void BLF_exit(void); @@ -79,9 +80,11 @@ void BLF_draw_default(float x, float y, float z, const char *str, size_t len) AT void BLF_draw_default_ascii(float x, float y, float z, const char *str, size_t len) ATTR_NONNULL(); /* Draw the string using the current font. */ -void BLF_draw(int fontid, const char *str, size_t len); -void BLF_draw_ascii(int fontid, const char *str, size_t len); -int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth); +void BLF_draw_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_info) ATTR_NONNULL(2); +void BLF_draw(int fontid, const char *str, size_t len) ATTR_NONNULL(2); +void BLF_draw_ascii_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_info) ATTR_NONNULL(2); +void BLF_draw_ascii(int fontid, const char *str, size_t len) ATTR_NONNULL(2); +int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth) ATTR_NONNULL(2); /* Get the string byte offset that fits within a given width */ size_t BLF_width_to_strlen(int fontid, const char *str, size_t len, float width, float *r_width) ATTR_NONNULL(2); @@ -91,17 +94,20 @@ size_t BLF_width_to_rstrlen(int fontid, const char *str, size_t len, float width /* This function return the bounding box of the string * and are not multiplied by the aspect. */ +void BLF_boundbox_ex(int fontid, const char *str, size_t len, struct rctf *box, struct ResultBLF *r_info) ATTR_NONNULL(2); void BLF_boundbox(int fontid, const char *str, size_t len, struct rctf *box) ATTR_NONNULL(); /* The next both function return the width and height * of the string, using the current font and both value * are multiplied by the aspect of the font. */ +float BLF_width_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_info) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2); float BLF_width(int fontid, const char *str, size_t len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +float BLF_height_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_info) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2); float BLF_height(int fontid, const char *str, size_t len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); /* Return dimensions of the font without any sample text. */ -float BLF_height_max(int fontid) ATTR_WARN_UNUSED_RESULT; +int BLF_height_max(int fontid) ATTR_WARN_UNUSED_RESULT; float BLF_width_max(int fontid) ATTR_WARN_UNUSED_RESULT; float BLF_descender(int fontid) ATTR_WARN_UNUSED_RESULT; float BLF_ascender(int fontid) ATTR_WARN_UNUSED_RESULT; @@ -137,6 +143,7 @@ void BLF_disable_default(int option); void BLF_rotation(int fontid, float angle); void BLF_clipping(int fontid, float xmin, float ymin, float xmax, float ymax); void BLF_clipping_default(float xmin, float ymin, float xmax, float ymax); +void BLF_wordwrap(int fontid, int wrap_width); void BLF_blur(int fontid, int size); void BLF_enable(int fontid, int option); @@ -172,7 +179,8 @@ void BLF_buffer_col(int fontid, float r, float g, float b, float a); /* Draw the string into the buffer, this function draw in both buffer, float and unsigned char _BUT_ * it's not necessary set both buffer, NULL is valid here. */ -void BLF_draw_buffer(int fontid, const char *str) ATTR_NONNULL(); +void BLF_draw_buffer_ex(int fontid, const char *str, size_t len, struct ResultBLF *r_info) ATTR_NONNULL(2); +void BLF_draw_buffer(int fontid, const char *str, size_t len) ATTR_NONNULL(2); /* Add a path to the font dir paths. */ void BLF_dir_add(const char *path) ATTR_NONNULL(); @@ -210,6 +218,7 @@ void BLF_state_print(int fontid); #define BLF_MATRIX (1 << 4) #define BLF_ASPECT (1 << 5) #define BLF_HINTING (1 << 6) +#define BLF_WORD_WRAP (1 << 7) #define BLF_DRAW_STR_DUMMY_MAX 1024 @@ -217,4 +226,18 @@ void BLF_state_print(int fontid); extern int blf_mono_font; extern int blf_mono_font_render; /* don't mess drawing with render threads. */ +/** + * Result of drawing/evaluating the string + */ +struct ResultBLF { + /** + * Number of lines drawn when #BLF_WORD_WRAP is enabled (both wrapped and `\n` newline). + */ + int lines; + /** + * The 'cursor' position on completion (ignoring character boundbox). + */ + int width; +}; + #endif /* __BLF_API_H__ */ diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index 127826f98c8..8a48384f06f 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -53,6 +53,8 @@ #include "BIF_gl.h" #include "BLF_api.h" +#include "IMB_colormanagement.h" + #include "blf_internal_types.h" #include "blf_internal.h" @@ -66,6 +68,11 @@ /* call BLF_default_set first! */ #define ASSERT_DEFAULT_SET BLI_assert(global_font_default != -1) +#define BLF_RESULT_CHECK_INIT(r_info) \ +if (r_info) { \ + memset(r_info, 0, sizeof(*(r_info))); \ +} ((void)0) + /* Font array. */ static FontBLF *global_font[BLF_MAX_FONT] = {NULL}; @@ -491,7 +498,7 @@ void BLF_rotation_default(float angle) } } -static void blf_draw__start(FontBLF *font, GLint *mode, GLint *param) +static void blf_draw_gl__start(FontBLF *font, GLint *mode, GLint *param) { /* * The pixmap alignment hack is handle @@ -535,7 +542,7 @@ static void blf_draw__start(FontBLF *font, GLint *mode, GLint *param) glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } -static void blf_draw__end(GLint mode, GLint param) +static void blf_draw_gl__end(GLint mode, GLint param) { /* and restore the original value. */ if (param != GL_MODULATE) @@ -554,29 +561,56 @@ static void blf_draw__end(GLint mode, GLint param) glDisable(GL_TEXTURE_2D); } -void BLF_draw(int fontid, const char *str, size_t len) +void BLF_draw_ex( + int fontid, const char *str, size_t len, + struct ResultBLF *r_info) { FontBLF *font = blf_get(fontid); GLint mode, param; + BLF_RESULT_CHECK_INIT(r_info); + if (font && font->glyph_cache) { - blf_draw__start(font, &mode, ¶m); - blf_font_draw(font, str, len); - blf_draw__end(mode, param); + blf_draw_gl__start(font, &mode, ¶m); + if (font->flags & BLF_WORD_WRAP) { + blf_font_draw__wrap(font, str, len, r_info); + } + else { + blf_font_draw(font, str, len, r_info); + } + blf_draw_gl__end(mode, param); } } +void BLF_draw(int fontid, const char *str, size_t len) +{ + BLF_draw_ex(fontid, str, len, NULL); +} -void BLF_draw_ascii(int fontid, const char *str, size_t len) +void BLF_draw_ascii_ex( + int fontid, const char *str, size_t len, + struct ResultBLF *r_info) { FontBLF *font = blf_get(fontid); GLint mode, param; + BLF_RESULT_CHECK_INIT(r_info); + if (font && font->glyph_cache) { - blf_draw__start(font, &mode, ¶m); - blf_font_draw_ascii(font, str, len); - blf_draw__end(mode, param); + blf_draw_gl__start(font, &mode, ¶m); + if (font->flags & BLF_WORD_WRAP) { + /* use non-ascii draw function for word-wrap */ + blf_font_draw__wrap(font, str, len, r_info); + } + else { + blf_font_draw_ascii(font, str, len, r_info); + } + blf_draw_gl__end(mode, param); } } +void BLF_draw_ascii(int fontid, const char *str, size_t len) +{ + BLF_draw_ascii_ex(fontid, str, len, NULL); +} int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth) { @@ -585,9 +619,9 @@ int BLF_draw_mono(int fontid, const char *str, size_t len, int cwidth) int columns = 0; if (font && font->glyph_cache) { - blf_draw__start(font, &mode, ¶m); + blf_draw_gl__start(font, &mode, ¶m); columns = blf_font_draw_mono(font, str, len, cwidth); - blf_draw__end(mode, param); + blf_draw_gl__end(mode, param); } return columns; @@ -633,21 +667,34 @@ size_t BLF_width_to_rstrlen(int fontid, const char *str, size_t len, float width return 0; } -void BLF_boundbox(int fontid, const char *str, size_t len, rctf *box) +void BLF_boundbox_ex( + int fontid, const char *str, size_t len, rctf *r_box, + struct ResultBLF *r_info) { FontBLF *font = blf_get(fontid); + BLF_RESULT_CHECK_INIT(r_info); + if (font) { - blf_font_boundbox(font, str, len, box); + if (font->flags & BLF_WORD_WRAP) { + blf_font_boundbox__wrap(font, str, len, r_box, r_info); + } + else { + blf_font_boundbox(font, str, len, r_box, r_info); + } } } +void BLF_boundbox(int fontid, const char *str, size_t len, rctf *r_box) +{ + BLF_boundbox_ex(fontid, str, len, r_box, NULL); +} void BLF_width_and_height(int fontid, const char *str, size_t len, float *r_width, float *r_height) { FontBLF *font = blf_get(fontid); if (font && font->glyph_cache) { - blf_font_width_and_height(font, str, len, r_width, r_height); + blf_font_width_and_height(font, str, len, r_width, r_height, NULL); } else { *r_width = *r_height = 0.0f; @@ -662,16 +709,24 @@ void BLF_width_and_height_default(const char *str, size_t len, float *r_width, f BLF_width_and_height(global_font_default, str, len, r_width, r_height); } -float BLF_width(int fontid, const char *str, size_t len) +float BLF_width_ex( + int fontid, const char *str, size_t len, + struct ResultBLF *r_info) { FontBLF *font = blf_get(fontid); + BLF_RESULT_CHECK_INIT(r_info); + if (font && font->glyph_cache) { - return blf_font_width(font, str, len); + return blf_font_width(font, str, len, r_info); } return 0.0f; } +float BLF_width(int fontid, const char *str, size_t len) +{ + return BLF_width_ex(fontid, str, len, NULL); +} float BLF_fixed_width(int fontid) { @@ -692,18 +747,26 @@ float BLF_width_default(const char *str, size_t len) return BLF_width(global_font_default, str, len); } -float BLF_height(int fontid, const char *str, size_t len) +float BLF_height_ex( + int fontid, const char *str, size_t len, + struct ResultBLF *r_info) { FontBLF *font = blf_get(fontid); + BLF_RESULT_CHECK_INIT(r_info); + if (font && font->glyph_cache) { - return blf_font_height(font, str, len); + return blf_font_height(font, str, len, r_info); } return 0.0f; } +float BLF_height(int fontid, const char *str, size_t len) +{ + return BLF_height_ex(fontid, str, len, NULL); +} -float BLF_height_max(int fontid) +int BLF_height_max(int fontid) { FontBLF *font = blf_get(fontid); @@ -711,7 +774,7 @@ float BLF_height_max(int fontid) return font->glyph_cache->max_glyph_height; } - return 0.0f; + return 0; } float BLF_width_max(int fontid) @@ -789,6 +852,15 @@ void BLF_clipping_default(float xmin, float ymin, float xmax, float ymax) } } +void BLF_wordwrap(int fontid, int wrap_width) +{ + FontBLF *font = blf_get(fontid); + + if (font) { + font->wrap_width = wrap_width; + } +} + void BLF_shadow(int fontid, int level, float r, float g, float b, float a) { FontBLF *font = blf_get(fontid); @@ -831,21 +903,52 @@ void BLF_buffer_col(int fontid, float r, float g, float b, float a) FontBLF *font = blf_get(fontid); if (font) { - font->buf_info.col[0] = r; - font->buf_info.col[1] = g; - font->buf_info.col[2] = b; - font->buf_info.col[3] = a; + ARRAY_SET_ITEMS(font->buf_info.col_init, r, g, b, a); } } -void BLF_draw_buffer(int fontid, const char *str) + +static void blf_draw_buffer__start(FontBLF *font) +{ + FontBufInfoBLF *buf_info = &font->buf_info; + + buf_info->col_char[0] = buf_info->col_init[0] * 255; + buf_info->col_char[1] = buf_info->col_init[1] * 255; + buf_info->col_char[2] = buf_info->col_init[2] * 255; + buf_info->col_char[3] = buf_info->col_init[3] * 255; + + if (buf_info->display) { + copy_v4_v4(buf_info->col_float, buf_info->col_init); + IMB_colormanagement_display_to_scene_linear_v3(buf_info->col_float, buf_info->display); + } + else { + srgb_to_linearrgb_v4(buf_info->col_float, buf_info->col_init); + } +} +static void blf_draw_buffer__end(void) {} + +void BLF_draw_buffer_ex( + int fontid, const char *str, size_t len, + struct ResultBLF *r_info) { FontBLF *font = blf_get(fontid); if (font && font->glyph_cache && (font->buf_info.fbuf || font->buf_info.cbuf)) { - blf_font_buffer(font, str); + blf_draw_buffer__start(font); + if (font->flags & BLF_WORD_WRAP) { + blf_font_draw_buffer__wrap(font, str, len, r_info); + } + else { + blf_font_draw_buffer(font, str, len, r_info); + } + blf_draw_buffer__end(); } } +void BLF_draw_buffer( + int fontid, const char *str, size_t len) +{ + BLF_draw_buffer_ex(fontid, str, len, NULL); +} #ifdef DEBUG void BLF_state_print(int fontid) diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 46e0e0e5359..edb982538ff 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -58,8 +58,6 @@ #include "BIF_gl.h" #include "BLF_api.h" -#include "IMB_colormanagement.h" - #include "blf_internal_types.h" #include "blf_internal.h" @@ -174,12 +172,14 @@ static void blf_font_ensure_ascii_table(FontBLF *font) } \ } (void)0 -void blf_font_draw(FontBLF *font, const char *str, size_t len) +static void blf_font_draw_ex( + FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info, + int pen_y) { unsigned int c; GlyphBLF *g, *g_prev = NULL; FT_Vector delta; - int pen_x = 0, pen_y = 0; + int pen_x = 0; size_t i = 0; GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table; @@ -203,15 +203,26 @@ void blf_font_draw(FontBLF *font, const char *str, size_t len) pen_x += g->advance_i; g_prev = g; } + + if (r_info) { + r_info->lines = 1; + r_info->width = pen_x; + } +} +void blf_font_draw(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info) +{ + blf_font_draw_ex(font, str, len, r_info, 0); } /* faster version of blf_font_draw, ascii only for view dimensions */ -void blf_font_draw_ascii(FontBLF *font, const char *str, size_t len) +static void blf_font_draw_ascii_ex( + FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info, + int pen_y) { unsigned char c; GlyphBLF *g, *g_prev = NULL; FT_Vector delta; - int pen_x = 0, pen_y = 0; + int pen_x = 0; GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table; BLF_KERNING_VARS(font, has_kerning, kern_mode); @@ -231,6 +242,15 @@ void blf_font_draw_ascii(FontBLF *font, const char *str, size_t len) pen_x += g->advance_i; g_prev = g; } + + if (r_info) { + r_info->lines = 1; + r_info->width = pen_x; + } +} +void blf_font_draw_ascii(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info) +{ + blf_font_draw_ascii_ex(font, str, len, r_info, 0); } /* use fixed column width, but an utf8 character may occupy multiple columns */ @@ -268,24 +288,22 @@ int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth) } /* Sanity checks are done by BLF_draw_buffer() */ -void blf_font_buffer(FontBLF *font, const char *str) +static void blf_font_draw_buffer_ex( + FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info, + int pen_y) { unsigned int c; GlyphBLF *g, *g_prev = NULL; FT_Vector delta; - int pen_x = (int)font->pos[0], pen_y = 0; + int pen_x = (int)font->pos[0]; + int pen_y_basis = (int)font->pos[1] + pen_y; size_t i = 0; GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table; /* buffer specific vars */ FontBufInfoBLF *buf_info = &font->buf_info; - float b_col_float[4]; - const unsigned char b_col_char[4] = { - (unsigned char)(buf_info->col[0] * 255), - (unsigned char)(buf_info->col[1] * 255), - (unsigned char)(buf_info->col[2] * 255), - (unsigned char)(buf_info->col[3] * 255)}; - + const float *b_col_float = buf_info->col_float; + const unsigned char *b_col_char = buf_info->col_char; int chx, chy; int y, x; float a; @@ -295,15 +313,8 @@ void blf_font_buffer(FontBLF *font, const char *str) blf_font_ensure_ascii_table(font); /* another buffer specific call for color conversion */ - if (buf_info->display) { - copy_v4_v4(b_col_float, buf_info->col); - IMB_colormanagement_display_to_scene_linear_v3(b_col_float, buf_info->display); - } - else { - srgb_to_linearrgb_v4(b_col_float, buf_info->col); - } - while (str[i]) { + while ((i < len) && str[i]) { BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table); if (UNLIKELY(c == BLI_UTF8_ERR)) @@ -314,13 +325,13 @@ void blf_font_buffer(FontBLF *font, const char *str) BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x); chx = pen_x + ((int)g->pos_x); - chy = (int)font->pos[1] + g->height; + chy = pen_y_basis + g->height; if (g->pitch < 0) { - pen_y = (int)font->pos[1] + (g->height - (int)g->pos_y); + pen_y = pen_y_basis + (g->height - (int)g->pos_y); } else { - pen_y = (int)font->pos[1] - (g->height - (int)g->pos_y); + pen_y = pen_y_basis - (g->height - (int)g->pos_y); } if ((chx + g->width) >= 0 && chx < buf_info->w && (pen_y + g->height) >= 0 && pen_y < buf_info->h) { @@ -429,6 +440,16 @@ void blf_font_buffer(FontBLF *font, const char *str) pen_x += g->advance_i; g_prev = g; } + + if (r_info) { + r_info->lines = 1; + r_info->width = pen_x; + } +} +void blf_font_draw_buffer( + FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info) +{ + blf_font_draw_buffer_ex(font, str, len, r_info, 0); } size_t blf_font_width_to_strlen(FontBLF *font, const char *str, size_t len, float width, float *r_width) @@ -558,12 +579,14 @@ size_t blf_font_width_to_rstrlen(FontBLF *font, const char *str, size_t len, flo return i_prev; } -void blf_font_boundbox(FontBLF *font, const char *str, size_t len, rctf *box) +static void blf_font_boundbox_ex( + FontBLF *font, const char *str, size_t len, rctf *box, struct ResultBLF *r_info, + int pen_y) { unsigned int c; GlyphBLF *g, *g_prev = NULL; FT_Vector delta; - int pen_x = 0, pen_y = 0; + int pen_x = 0; size_t i = 0; GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table; @@ -609,9 +632,168 @@ void blf_font_boundbox(FontBLF *font, const char *str, size_t len, rctf *box) box->xmax = 0.0f; box->ymax = 0.0f; } + + if (r_info) { + r_info->lines = 1; + r_info->width = pen_x; + } } +void blf_font_boundbox(FontBLF *font, const char *str, size_t len, rctf *r_box, struct ResultBLF *r_info) +{ + blf_font_boundbox_ex(font, str, len, r_box, r_info, 0); +} + + +/* -------------------------------------------------------------------- */ +/** \name Word-Wrap Support + * \{ */ + -void blf_font_width_and_height(FontBLF *font, const char *str, size_t len, float *width, float *height) +/** + * Generic function to add word-wrap support for other existing functions. + * + * Wraps on spaces and respects newlines. + * Intentionally ignores non-unix newlines, tabs and more advanced text formatting. + * + * \note If we want rich text - we better have a higher level API to handle that + * (color, bold, switching fonts... etc). + */ +static void blf_font_wrap_apply( + FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info, + void (*callback)(FontBLF *font, const char *str, size_t len, int pen_y, void *userdata), + void *userdata) +{ + unsigned int c; + GlyphBLF *g, *g_prev = NULL; + FT_Vector delta; + int pen_x = 0, pen_y = 0; + size_t i = 0; + GlyphBLF **glyph_ascii_table = font->glyph_cache->glyph_ascii_table; + int lines = 0; + + BLF_KERNING_VARS(font, has_kerning, kern_mode); + + struct WordWrapVars { + int wrap_width; + size_t start, last[2]; + } wrap = {font->wrap_width != -1 ? font->wrap_width : INT_MAX, 0, {0, 0}}; + + blf_font_ensure_ascii_table(font); + // printf("%s wrapping (%d, %d) `%s`:\n", __func__, len, strlen(str), str); + while ((i < len) && str[i]) { + + /* wrap vars */ + size_t i_curr = i; + int pen_x_next; + bool do_draw = false; + + BLF_UTF8_NEXT_FAST(font, g, str, i, c, glyph_ascii_table); + + if (UNLIKELY(c == BLI_UTF8_ERR)) + break; + if (UNLIKELY(g == NULL)) + continue; + if (has_kerning) + BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x); + + /** + * Implementation Detail (utf8). + * + * Take care with single byte offsets here, + * since this is utf8 we can't be sure a single byte is a single character. + * + * This is _only_ done when we know for sure the character is ascii (newline or a space). + */ + pen_x_next = pen_x + g->advance_i; + if (UNLIKELY((pen_x_next >= wrap.wrap_width) && (wrap.start != wrap.last[0]))) { + do_draw = true; + } + else if (UNLIKELY(((i < len) && str[i]) == 0)) { + /* need check here for trailing newline, else we draw it */ + wrap.last[0] = i + ((g->c != '\n') ? 1 : 0); + wrap.last[1] = i; + do_draw = true; + } + else if (UNLIKELY(g->c == '\n')) { + wrap.last[0] = i_curr + 1; + wrap.last[1] = i; + do_draw = true; + } + else if (UNLIKELY(g->c != ' ' && (g_prev ? g_prev->c == ' ' : false))) { + wrap.last[0] = i_curr; + wrap.last[1] = i; + } + + if (UNLIKELY(do_draw)) { + // printf("(%d..%d) `%.*s`\n", wrap.start, wrap.last[0], (wrap.last[0] - wrap.start) - 1, &str[wrap.start]); + callback(font, &str[wrap.start], (wrap.last[0] - wrap.start) - 1, pen_y, userdata); + wrap.start = wrap.last[0]; + i = wrap.last[1]; + pen_x = 0; + pen_y -= font->glyph_cache->max_glyph_height; + g_prev = NULL; + lines += 1; + continue; + } + + pen_x = pen_x_next; + g_prev = g; + } + + // printf("done! %d lines\n", lines); + + if (r_info) { + r_info->lines = lines; + /* width of last line only (with wrapped lines) */ + r_info->width = pen_x; + } +} + +/* blf_font_draw__wrap */ +static void blf_font_draw__wrap_cb(FontBLF *font, const char *str, size_t len, int pen_y, void *UNUSED(userdata)) +{ + blf_font_draw_ex(font, str, len, NULL, pen_y); +} +void blf_font_draw__wrap(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info) +{ + blf_font_wrap_apply(font, str, len, r_info, blf_font_draw__wrap_cb, NULL); +} + +/* blf_font_boundbox__wrap */ +static void blf_font_boundbox_wrap_cb(FontBLF *font, const char *str, size_t len, int pen_y, void *userdata) +{ + rctf *box = userdata; + rctf box_single; + + blf_font_boundbox_ex(font, str, len, &box_single, NULL, pen_y); + BLI_rctf_union(box, &box_single); +} +void blf_font_boundbox__wrap(FontBLF *font, const char *str, size_t len, rctf *box, struct ResultBLF *r_info) +{ + box->xmin = 32000.0f; + box->xmax = -32000.0f; + box->ymin = 32000.0f; + box->ymax = -32000.0f; + + blf_font_wrap_apply(font, str, len, r_info, blf_font_boundbox_wrap_cb, box); +} + +/* blf_font_draw_buffer__wrap */ +static void blf_font_draw_buffer__wrap_cb(FontBLF *font, const char *str, size_t len, int pen_y, void *UNUSED(userdata)) +{ + blf_font_draw_buffer_ex(font, str, len, NULL, pen_y); +} +void blf_font_draw_buffer__wrap(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info) +{ + blf_font_wrap_apply(font, str, len, r_info, blf_font_draw_buffer__wrap_cb, NULL); +} + +/** \} */ + + +void blf_font_width_and_height( + FontBLF *font, const char *str, size_t len, + float *r_width, float *r_height, struct ResultBLF *r_info) { float xa, ya; rctf box; @@ -625,12 +807,17 @@ void blf_font_width_and_height(FontBLF *font, const char *str, size_t len, float ya = 1.0f; } - blf_font_boundbox(font, str, len, &box); - *width = (BLI_rctf_size_x(&box) * xa); - *height = (BLI_rctf_size_y(&box) * ya); + if (font->flags & BLF_WORD_WRAP) { + blf_font_boundbox__wrap(font, str, len, &box, r_info); + } + else { + blf_font_boundbox(font, str, len, &box, r_info); + } + *r_width = (BLI_rctf_size_x(&box) * xa); + *r_height = (BLI_rctf_size_y(&box) * ya); } -float blf_font_width(FontBLF *font, const char *str, size_t len) +float blf_font_width(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info) { float xa; rctf box; @@ -640,11 +827,16 @@ float blf_font_width(FontBLF *font, const char *str, size_t len) else xa = 1.0f; - blf_font_boundbox(font, str, len, &box); + if (font->flags & BLF_WORD_WRAP) { + blf_font_boundbox__wrap(font, str, len, &box, r_info); + } + else { + blf_font_boundbox(font, str, len, &box, r_info); + } return BLI_rctf_size_x(&box) * xa; } -float blf_font_height(FontBLF *font, const char *str, size_t len) +float blf_font_height(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info) { float ya; rctf box; @@ -654,7 +846,12 @@ float blf_font_height(FontBLF *font, const char *str, size_t len) else ya = 1.0f; - blf_font_boundbox(font, str, len, &box); + if (font->flags & BLF_WORD_WRAP) { + blf_font_boundbox__wrap(font, str, len, &box, r_info); + } + else { + blf_font_boundbox(font, str, len, &box, r_info); + } return BLI_rctf_size_y(&box) * ya; } @@ -744,10 +941,10 @@ static void blf_font_fill(FontBLF *font) font->buf_info.w = 0; font->buf_info.h = 0; font->buf_info.ch = 0; - font->buf_info.col[0] = 0; - font->buf_info.col[1] = 0; - font->buf_info.col[2] = 0; - font->buf_info.col[3] = 0; + font->buf_info.col_init[0] = 0; + font->buf_info.col_init[1] = 0; + font->buf_info.col_init[2] = 0; + font->buf_info.col_init[3] = 0; font->ft_lib = ft_lib; font->ft_lib_mutex = &ft_lib_mutex; diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h index 85410a4d856..55bc61e0e43 100644 --- a/source/blender/blenfont/intern/blf_internal.h +++ b/source/blender/blenfont/intern/blf_internal.h @@ -31,6 +31,7 @@ #ifndef __BLF_INTERNAL_H__ #define __BLF_INTERNAL_H__ +struct ResultBLF; struct FontBLF; struct GlyphBLF; struct GlyphCacheBLF; @@ -51,16 +52,19 @@ struct FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem void blf_font_attach_from_mem(struct FontBLF *font, const unsigned char *mem, int mem_size); void blf_font_size(struct FontBLF *font, unsigned int size, unsigned int dpi); -void blf_font_draw(struct FontBLF *font, const char *str, size_t len); -void blf_font_draw_ascii(struct FontBLF *font, const char *str, size_t len); +void blf_font_draw(struct FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info); +void blf_font_draw__wrap(struct FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info); +void blf_font_draw_ascii(struct FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info); int blf_font_draw_mono(struct FontBLF *font, const char *str, size_t len, int cwidth); -void blf_font_buffer(struct FontBLF *font, const char *str); +void blf_font_draw_buffer(struct FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info); +void blf_font_draw_buffer__wrap(struct FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info); size_t blf_font_width_to_strlen(struct FontBLF *font, const char *str, size_t len, float width, float *r_width); size_t blf_font_width_to_rstrlen(struct FontBLF *font, const char *str, size_t len, float width, float *r_width); -void blf_font_boundbox(struct FontBLF *font, const char *str, size_t len, struct rctf *box); -void blf_font_width_and_height(struct FontBLF *font, const char *str, size_t len, float *width, float *height); -float blf_font_width(struct FontBLF *font, const char *str, size_t len); -float blf_font_height(struct FontBLF *font, const char *str, size_t len); +void blf_font_boundbox(struct FontBLF *font, const char *str, size_t len, struct rctf *r_box, struct ResultBLF *r_info); +void blf_font_boundbox__wrap(struct FontBLF *font, const char *str, size_t len, struct rctf *r_box, struct ResultBLF *r_info); +void blf_font_width_and_height(struct FontBLF *font, const char *str, size_t len, float *r_width, float *r_height, struct ResultBLF *r_info); +float blf_font_width(struct FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info); +float blf_font_height(struct FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info); float blf_font_fixed_width(struct FontBLF *font); int blf_font_count_missing_chars(struct FontBLF *font, const char *str, const size_t len, int *r_tot_chars); diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index 1404b9de250..f17401a9991 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -152,7 +152,11 @@ typedef struct FontBufInfoBLF { /* and the color, the alphas is get from the glyph! * color is srgb space */ - float col[4]; + float col_init[4]; + /* cached conversion from 'col_init' */ + unsigned char col_char[4]; + float col_float[4]; + } FontBufInfoBLF; typedef struct FontBLF { @@ -195,6 +199,9 @@ typedef struct FontBLF { /* clipping rectangle. */ rctf clip_rec; + /* the width to wrap the text, see BLF_WORD_WRAP */ + int wrap_width; + /* font dpi (default 72). */ unsigned int dpi; diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c index 4eea5d581d0..76479593b54 100644 --- a/source/blender/blenfont/intern/blf_thumbs.c +++ b/source/blender/blenfont/intern/blf_thumbs.c @@ -84,7 +84,7 @@ void BLF_thumb_preview( /* Always create the image with a white font, * the caller can theme how it likes */ - memcpy(font->buf_info.col, font_color, sizeof(font->buf_info.col)); + memcpy(font->buf_info.col_init, font_color, sizeof(font->buf_info.col_init)); font->pos[1] = (float)h; font_size_curr = font_size; @@ -110,10 +110,10 @@ void BLF_thumb_preview( if (blf_font_count_missing_chars( font, draw_str_i18n, draw_str_i18n_len, &draw_str_i18n_nbr) > (draw_str_i18n_nbr / 2)) { - blf_font_buffer(font, draw_str[i]); + blf_font_draw_buffer(font, draw_str[i], (size_t)draw_str_i18n_nbr, NULL); } else { - blf_font_buffer(font, draw_str_i18n); + blf_font_draw_buffer(font, draw_str_i18n, draw_str_i18n_len, NULL); } } diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 36aeb97c3f0..b6645a35b60 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -1917,7 +1917,7 @@ void BKE_image_stamp_buf( /* and draw the text. */ BLF_position(mono, x, y + y_ofs, 0.0); - BLF_draw_buffer(mono, stamp_data.file); + BLF_draw_buffer(mono, stamp_data.file, BLF_DRAW_STR_DUMMY_MAX); /* the extra pixel for background. */ y -= BUFF_MARGIN_Y * 2; @@ -1932,7 +1932,7 @@ void BKE_image_stamp_buf( 0, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); BLF_position(mono, x, y + y_ofs, 0.0); - BLF_draw_buffer(mono, stamp_data.note); + BLF_draw_buffer(mono, stamp_data.note, BLF_DRAW_STR_DUMMY_MAX); /* the extra pixel for background. */ y -= BUFF_MARGIN_Y * 2; @@ -1947,7 +1947,7 @@ void BKE_image_stamp_buf( 0, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); BLF_position(mono, x, y + y_ofs, 0.0); - BLF_draw_buffer(mono, stamp_data.date); + BLF_draw_buffer(mono, stamp_data.date, BLF_DRAW_STR_DUMMY_MAX); /* the extra pixel for background. */ y -= BUFF_MARGIN_Y * 2; @@ -1962,7 +1962,7 @@ void BKE_image_stamp_buf( 0, y - BUFF_MARGIN_Y, w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); BLF_position(mono, x, y + y_ofs, 0.0); - BLF_draw_buffer(mono, stamp_data.rendertime); + BLF_draw_buffer(mono, stamp_data.rendertime, BLF_DRAW_STR_DUMMY_MAX); } x = 0; @@ -1977,7 +1977,7 @@ void BKE_image_stamp_buf( /* and pad the text. */ BLF_position(mono, x, y + y_ofs, 0.0); - BLF_draw_buffer(mono, stamp_data.marker); + BLF_draw_buffer(mono, stamp_data.marker, BLF_DRAW_STR_DUMMY_MAX); /* space width. */ x += w + pad; @@ -1992,7 +1992,7 @@ void BKE_image_stamp_buf( /* and pad the text. */ BLF_position(mono, x, y + y_ofs, 0.0); - BLF_draw_buffer(mono, stamp_data.time); + BLF_draw_buffer(mono, stamp_data.time, BLF_DRAW_STR_DUMMY_MAX); /* space width. */ x += w + pad; @@ -2006,7 +2006,7 @@ void BKE_image_stamp_buf( /* and pad the text. */ BLF_position(mono, x, y + y_ofs, 0.0); - BLF_draw_buffer(mono, stamp_data.frame); + BLF_draw_buffer(mono, stamp_data.frame, BLF_DRAW_STR_DUMMY_MAX); /* space width. */ x += w + pad; @@ -2018,7 +2018,7 @@ void BKE_image_stamp_buf( buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display, x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, x + w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); BLF_position(mono, x, y + y_ofs, 0.0); - BLF_draw_buffer(mono, stamp_data.camera); + BLF_draw_buffer(mono, stamp_data.camera, BLF_DRAW_STR_DUMMY_MAX); /* space width. */ x += w + pad; @@ -2030,7 +2030,7 @@ void BKE_image_stamp_buf( buf_rectfill_area(rect, rectf, width, height, scene->r.bg_stamp, display, x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, x + w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); BLF_position(mono, x, y + y_ofs, 0.0); - BLF_draw_buffer(mono, stamp_data.cameralens); + BLF_draw_buffer(mono, stamp_data.cameralens, BLF_DRAW_STR_DUMMY_MAX); } if (TEXT_SIZE_CHECK(stamp_data.scene, w, h)) { @@ -2044,7 +2044,7 @@ void BKE_image_stamp_buf( /* and pad the text. */ BLF_position(mono, x, y + y_ofs, 0.0); - BLF_draw_buffer(mono, stamp_data.scene); + BLF_draw_buffer(mono, stamp_data.scene, BLF_DRAW_STR_DUMMY_MAX); } if (TEXT_SIZE_CHECK(stamp_data.strip, w, h)) { @@ -2058,7 +2058,7 @@ void BKE_image_stamp_buf( x - BUFF_MARGIN_X, y - BUFF_MARGIN_Y, x + w + BUFF_MARGIN_X, y + h + BUFF_MARGIN_Y); BLF_position(mono, x, y + y_ofs, 0.0); - BLF_draw_buffer(mono, stamp_data.strip); + BLF_draw_buffer(mono, stamp_data.strip, BLF_DRAW_STR_DUMMY_MAX); } /* cleanup the buffer. */ diff --git a/source/blender/blenkernel/intern/image_gen.c b/source/blender/blenkernel/intern/image_gen.c index 4f9ed5f258d..303d0c6adfc 100644 --- a/source/blender/blenkernel/intern/image_gen.c +++ b/source/blender/blenkernel/intern/image_gen.c @@ -309,26 +309,26 @@ static void checker_board_text(unsigned char *rect, float *rect_float, int width BLF_buffer_col(mono, 1.0, 1.0, 1.0, 1.0); BLF_position(mono, pen_x - outline, pen_y, 0.0); - BLF_draw_buffer(mono, text); + BLF_draw_buffer(mono, text, 2); BLF_position(mono, pen_x + outline, pen_y, 0.0); - BLF_draw_buffer(mono, text); + BLF_draw_buffer(mono, text, 2); BLF_position(mono, pen_x, pen_y - outline, 0.0); - BLF_draw_buffer(mono, text); + BLF_draw_buffer(mono, text, 2); BLF_position(mono, pen_x, pen_y + outline, 0.0); - BLF_draw_buffer(mono, text); + BLF_draw_buffer(mono, text, 2); BLF_position(mono, pen_x - outline, pen_y - outline, 0.0); - BLF_draw_buffer(mono, text); + BLF_draw_buffer(mono, text, 2); BLF_position(mono, pen_x + outline, pen_y + outline, 0.0); - BLF_draw_buffer(mono, text); + BLF_draw_buffer(mono, text, 2); BLF_position(mono, pen_x - outline, pen_y + outline, 0.0); - BLF_draw_buffer(mono, text); + BLF_draw_buffer(mono, text, 2); BLF_position(mono, pen_x + outline, pen_y - outline, 0.0); - BLF_draw_buffer(mono, text); + BLF_draw_buffer(mono, text, 2); BLF_buffer_col(mono, 0.0, 0.0, 0.0, 1.0); BLF_position(mono, pen_x, pen_y, 0.0); - BLF_draw_buffer(mono, text); + BLF_draw_buffer(mono, text, 2); text[1]++; } diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index c65ed527568..3e93fb53bfc 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -2968,11 +2968,11 @@ static ImBuf *do_text_effect(const SeqRenderData *context, Sequence *seq, float fonty = BLF_height_max(mono); BLF_position(mono, x + max_ii(fontx / 25, 1), y + max_ii(fonty / 25, 1), 0.0f); BLF_buffer_col(mono, 0.0f, 0.0f, 0.0f, 1.0f); - BLF_draw_buffer(mono, data->text); + BLF_draw_buffer(mono, data->text, BLF_DRAW_STR_DUMMY_MAX); } BLF_position(mono, x, y, 0.0f); BLF_buffer_col(mono, 1.0f, 1.0f, 1.0f, 1.0f); - BLF_draw_buffer(mono, data->text); + BLF_draw_buffer(mono, data->text, BLF_DRAW_STR_DUMMY_MAX); BLF_buffer(mono, NULL, NULL, 0, 0, 0, NULL); diff --git a/source/blender/python/generic/blf_py_api.c b/source/blender/python/generic/blf_py_api.c index 5364c3bbb9e..0dfff9b4a7b 100644 --- a/source/blender/python/generic/blf_py_api.c +++ b/source/blender/python/generic/blf_py_api.c @@ -221,6 +221,29 @@ static PyObject *py_blf_clipping(PyObject *UNUSED(self), PyObject *args) Py_RETURN_NONE; } +PyDoc_STRVAR(py_blf_word_wrap_doc, +".. function:: word_wrap(fontid, wrap_width)\n" +"\n" +" Set the wrap width, enable/disable using WORD_WRAP.\n" +"\n" +" :arg fontid: The id of the typeface as returned by :func:`blf.load`, for default font use 0.\n" +" :type fontid: int\n" +" :arg wrap_width: The width (in pixels) to wrap words at.\n" +" :type wrap_width: int\n" +); +static PyObject *py_blf_word_wrap(PyObject *UNUSED(self), PyObject *args) +{ + int wrap_width; + int fontid; + + if (!PyArg_ParseTuple(args, "ii:blf.word_wrap", &fontid, &wrap_width)) + return NULL; + + BLF_wordwrap(fontid, wrap_width); + + Py_RETURN_NONE; +} + PyDoc_STRVAR(py_blf_disable_doc, ".. function:: disable(fontid, option)\n" "\n" @@ -393,6 +416,7 @@ static PyMethodDef BLF_methods[] = { {"aspect", (PyCFunction) py_blf_aspect, METH_VARARGS, py_blf_aspect_doc}, {"blur", (PyCFunction) py_blf_blur, METH_VARARGS, py_blf_blur_doc}, {"clipping", (PyCFunction) py_blf_clipping, METH_VARARGS, py_blf_clipping_doc}, + {"word_wrap", (PyCFunction) py_blf_word_wrap, METH_VARARGS, py_blf_word_wrap_doc}, {"disable", (PyCFunction) py_blf_disable, METH_VARARGS, py_blf_disable_doc}, {"dimensions", (PyCFunction) py_blf_dimensions, METH_VARARGS, py_blf_dimensions_doc}, {"draw", (PyCFunction) py_blf_draw, METH_VARARGS, py_blf_draw_doc}, @@ -432,6 +456,7 @@ PyObject *BPyInit_blf(void) PyModule_AddIntConstant(submodule, "CLIPPING", BLF_CLIPPING); PyModule_AddIntConstant(submodule, "SHADOW", BLF_SHADOW); PyModule_AddIntConstant(submodule, "KERNING_DEFAULT", BLF_KERNING_DEFAULT); + PyModule_AddIntConstant(submodule, "WORD_WRAP", BLF_WORD_WRAP); return submodule; } -- cgit v1.2.3