Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenfont/intern')
-rw-r--r--source/blender/blenfont/intern/blf.c77
-rw-r--r--source/blender/blenfont/intern/blf_default.c10
-rw-r--r--source/blender/blenfont/intern/blf_dir.c2
-rw-r--r--source/blender/blenfont/intern/blf_font.c389
-rw-r--r--source/blender/blenfont/intern/blf_font_default.c2
-rw-r--r--source/blender/blenfont/intern/blf_font_win32_compat.c5
-rw-r--r--source/blender/blenfont/intern/blf_glyph.c11
-rw-r--r--source/blender/blenfont/intern/blf_internal.h30
-rw-r--r--source/blender/blenfont/intern/blf_internal_types.h6
-rw-r--r--source/blender/blenfont/intern/blf_thumbs.c423
-rw-r--r--source/blender/blenfont/intern/blf_util.c6
11 files changed, 646 insertions, 315 deletions
diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c
index 9d9cc51ebcc..d4f5be617fd 100644
--- a/source/blender/blenfont/intern/blf.c
+++ b/source/blender/blenfont/intern/blf.c
@@ -63,8 +63,6 @@ int BLF_init(void)
global_font[i] = NULL;
}
- BLF_default_dpi(72);
-
return blf_font_init();
}
@@ -100,7 +98,7 @@ static int blf_search(const char *name)
{
for (int i = 0; i < BLF_MAX_FONT; i++) {
const FontBLF *font = global_font[i];
- if (font && (STREQ(font->name, name))) {
+ if (font && STREQ(font->name, name)) {
return i;
}
}
@@ -119,7 +117,7 @@ static int blf_search_available(void)
return -1;
}
-bool BLF_has_glyph(int fontid, unsigned int unicode)
+bool BLF_has_glyph(int fontid, uint unicode)
{
FontBLF *font = blf_get(fontid);
if (font) {
@@ -164,6 +162,14 @@ int BLF_load_unique(const char *name)
}
FontBLF *font = blf_font_new(name, filepath);
+
+ /* XXX: Temporarily disable kerning in our main font. Kerning had been accidentally removed from
+ * our font in 3.1. In 3.4 we disable kerning here in the new version to keep spacing the same
+ * (T101506). Enable again later with change of font, placement, or rendering - Harley. */
+ if (font && BLI_str_endswith(filepath, BLF_DEFAULT_PROPORTIONAL_FONT)) {
+ font->face_flags &= ~FT_FACE_FLAG_KERNING;
+ }
+
MEM_freeN(filepath);
if (!font) {
@@ -176,7 +182,7 @@ int BLF_load_unique(const char *name)
return i;
}
-void BLF_metrics_attach(int fontid, unsigned char *mem, int mem_size)
+void BLF_metrics_attach(int fontid, uchar *mem, int mem_size)
{
FontBLF *font = blf_get(fontid);
@@ -185,7 +191,7 @@ void BLF_metrics_attach(int fontid, unsigned char *mem, int mem_size)
}
}
-int BLF_load_mem(const char *name, const unsigned char *mem, int mem_size)
+int BLF_load_mem(const char *name, const uchar *mem, int mem_size)
{
int i = blf_search(name);
if (i >= 0) {
@@ -195,7 +201,7 @@ int BLF_load_mem(const char *name, const unsigned char *mem, int mem_size)
return BLF_load_mem_unique(name, mem, mem_size);
}
-int BLF_load_mem_unique(const char *name, const unsigned char *mem, int mem_size)
+int BLF_load_mem_unique(const char *name, const uchar *mem, int mem_size)
{
/*
* Don't search in the cache, make a new object font!
@@ -228,7 +234,7 @@ void BLF_unload(const char *name)
for (int i = 0; i < BLF_MAX_FONT; i++) {
FontBLF *font = global_font[i];
- if (font && (STREQ(font->name, name))) {
+ if (font && STREQ(font->name, name)) {
BLI_assert(font->reference_count > 0);
font->reference_count--;
@@ -361,12 +367,12 @@ void BLF_position(int fontid, float x, float y, float z)
}
}
-void BLF_size(int fontid, float size, int dpi)
+void BLF_size(int fontid, float size)
{
FontBLF *font = blf_get(fontid);
if (font) {
- blf_font_size(font, size, dpi);
+ blf_font_size(font, size);
}
}
@@ -381,7 +387,7 @@ void BLF_blur(int fontid, int size)
}
#endif
-void BLF_color4ubv(int fontid, const unsigned char rgba[4])
+void BLF_color4ubv(int fontid, const uchar rgba[4])
{
FontBLF *font = blf_get(fontid);
@@ -393,7 +399,7 @@ void BLF_color4ubv(int fontid, const unsigned char rgba[4])
}
}
-void BLF_color3ubv_alpha(int fontid, const unsigned char rgb[3], unsigned char alpha)
+void BLF_color3ubv_alpha(int fontid, const uchar rgb[3], uchar alpha)
{
FontBLF *font = blf_get(fontid);
@@ -405,13 +411,12 @@ void BLF_color3ubv_alpha(int fontid, const unsigned char rgb[3], unsigned char a
}
}
-void BLF_color3ubv(int fontid, const unsigned char rgb[3])
+void BLF_color3ubv(int fontid, const uchar rgb[3])
{
BLF_color3ubv_alpha(fontid, rgb, 255);
}
-void BLF_color4ub(
- int fontid, unsigned char r, unsigned char g, unsigned char b, unsigned char alpha)
+void BLF_color4ub(int fontid, uchar r, uchar g, uchar b, uchar alpha)
{
FontBLF *font = blf_get(fontid);
@@ -423,7 +428,7 @@ void BLF_color4ub(
}
}
-void BLF_color3ub(int fontid, unsigned char r, unsigned char g, unsigned char b)
+void BLF_color3ub(int fontid, uchar r, uchar g, uchar b)
{
FontBLF *font = blf_get(fontid);
@@ -566,32 +571,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(
@@ -816,7 +834,7 @@ void BLF_shadow_offset(int fontid, int x, int y)
void BLF_buffer(int fontid,
float *fbuf,
- unsigned char *cbuf,
+ uchar *cbuf,
int w,
int h,
int nch,
@@ -912,7 +930,6 @@ void BLF_state_print(int fontid)
printf("fontid %d %p\n", fontid, (void *)font);
printf(" name: '%s'\n", font->name);
printf(" size: %f\n", font->size);
- printf(" dpi: %u\n", font->dpi);
printf(" pos: %d %d %d\n", UNPACK3(font->pos));
printf(" aspect: (%d) %.6f %.6f %.6f\n",
(font->flags & BLF_ROTATION) != 0,
diff --git a/source/blender/blenfont/intern/blf_default.c b/source/blender/blenfont/intern/blf_default.c
index a1f1b84636f..738683284e3 100644
--- a/source/blender/blenfont/intern/blf_default.c
+++ b/source/blender/blenfont/intern/blf_default.c
@@ -20,15 +20,9 @@
/* Default size and dpi, for BLF_draw_default. */
static int global_font_default = -1;
-static int global_font_dpi = 72;
/* Keep in sync with `UI_DEFAULT_TEXT_POINTS` */
static float global_font_size = 11.0f;
-void BLF_default_dpi(int dpi)
-{
- global_font_dpi = dpi;
-}
-
void BLF_default_size(float size)
{
global_font_size = size;
@@ -51,7 +45,7 @@ int BLF_set_default(void)
{
ASSERT_DEFAULT_SET;
- BLF_size(global_font_default, global_font_size, global_font_dpi);
+ BLF_size(global_font_default, global_font_size * U.dpi_fac);
return global_font_default;
}
@@ -59,7 +53,7 @@ int BLF_set_default(void)
void BLF_draw_default(float x, float y, float z, const char *str, const size_t str_len)
{
ASSERT_DEFAULT_SET;
- BLF_size(global_font_default, global_font_size, global_font_dpi);
+ BLF_size(global_font_default, global_font_size * U.dpi_fac);
BLF_position(global_font_default, x, y, z);
BLF_draw(global_font_default, str, str_len);
}
diff --git a/source/blender/blenfont/intern/blf_dir.c b/source/blender/blenfont/intern/blf_dir.c
index 8534a8c583f..395d981cb0b 100644
--- a/source/blender/blenfont/intern/blf_dir.c
+++ b/source/blender/blenfont/intern/blf_dir.c
@@ -115,7 +115,7 @@ char *blf_dir_search(const char *file)
char *s = NULL;
for (dir = global_font_dir.first; dir; dir = dir->next) {
- BLI_join_dirfile(full_path, sizeof(full_path), dir->path, file);
+ BLI_path_join(full_path, sizeof(full_path), dir->path, file);
if (BLI_exists(full_path)) {
s = BLI_strdup(full_path);
break;
diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index b96c01e704d..2c877ecb41d 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -33,6 +33,7 @@
#include "BLI_path_util.h"
#include "BLI_rect.h"
#include "BLI_string.h"
+#include "BLI_string_cursor_utf8.h"
#include "BLI_string_utf8.h"
#include "BLI_threads.h"
@@ -377,7 +378,7 @@ BLI_INLINE ft_pix blf_kerning(FontBLF *font, const GlyphBLF *g_prev, const Glyph
FT_Vector delta = {KERNING_ENTRY_UNSET};
/* Get unscaled kerning value from our cache if ASCII. */
- if ((g_prev->c < KERNING_CACHE_TABLE_SIZE) && (g->c < GLYPH_ASCII_TABLE_SIZE)) {
+ if ((g_prev->c < KERNING_CACHE_TABLE_SIZE) && (g->c < KERNING_CACHE_TABLE_SIZE)) {
delta.x = font->kerning_cache->ascii_table[g->c][g_prev->c];
}
@@ -388,7 +389,7 @@ BLI_INLINE ft_pix blf_kerning(FontBLF *font, const GlyphBLF *g_prev, const Glyph
}
/* If ASCII we save this value to our cache for quicker access next time. */
- if ((g_prev->c < KERNING_CACHE_TABLE_SIZE) && (g->c < GLYPH_ASCII_TABLE_SIZE)) {
+ if ((g_prev->c < KERNING_CACHE_TABLE_SIZE) && (g->c < KERNING_CACHE_TABLE_SIZE)) {
font->kerning_cache->ascii_table[g->c][g_prev->c] = (int)delta.x;
}
@@ -497,6 +498,115 @@ int blf_font_draw_mono(FontBLF *font, const char *str, const size_t str_len, int
/** \name Text Drawing: Buffer
* \{ */
+/**
+ * Draw glyph `g` into `buf_info` pixels.
+ */
+static void blf_glyph_draw_buffer(FontBufInfoBLF *buf_info,
+ GlyphBLF *g,
+ const ft_pix pen_x,
+ const ft_pix pen_y_basis)
+{
+ const int chx = ft_pix_to_int(pen_x + ft_pix_from_int(g->pos[0]));
+ const int chy = ft_pix_to_int(pen_y_basis + ft_pix_from_int(g->dims[1]));
+
+ ft_pix pen_y = (g->pitch < 0) ? (pen_y_basis + ft_pix_from_int(g->dims[1] - g->pos[1])) :
+ (pen_y_basis - ft_pix_from_int(g->dims[1] - g->pos[1]));
+
+ if ((chx + g->dims[0]) < 0 || /* Out of bounds: left. */
+ chx >= buf_info->dims[0] || /* Out of bounds: right. */
+ (ft_pix_to_int(pen_y) + g->dims[1]) < 0 || /* Out of bounds: bottom. */
+ ft_pix_to_int(pen_y) >= buf_info->dims[1] /* Out of bounds: top. */
+ ) {
+ return;
+ }
+
+ /* Don't draw beyond the buffer bounds. */
+ int width_clip = g->dims[0];
+ int height_clip = g->dims[1];
+ int yb_start = g->pitch < 0 ? 0 : g->dims[1] - 1;
+
+ if (width_clip + chx > buf_info->dims[0]) {
+ width_clip -= chx + width_clip - buf_info->dims[0];
+ }
+ if (height_clip + ft_pix_to_int(pen_y) > buf_info->dims[1]) {
+ height_clip -= ft_pix_to_int(pen_y) + height_clip - buf_info->dims[1];
+ }
+
+ /* Clip drawing below the image. */
+ if (pen_y < 0) {
+ yb_start += (g->pitch < 0) ? -ft_pix_to_int(pen_y) : ft_pix_to_int(pen_y);
+ height_clip += ft_pix_to_int(pen_y);
+ pen_y = 0;
+ }
+
+ /* Avoid conversions in the pixel writing loop. */
+ const int pen_y_px = ft_pix_to_int(pen_y);
+
+ const float *b_col_float = buf_info->col_float;
+ const uchar *b_col_char = buf_info->col_char;
+
+ if (buf_info->fbuf) {
+ int yb = yb_start;
+ for (int y = ((chy >= 0) ? 0 : -chy); y < height_clip; y++) {
+ for (int x = ((chx >= 0) ? 0 : -chx); x < width_clip; x++) {
+ const char a_byte = *(g->bitmap + x + (yb * g->pitch));
+ if (a_byte) {
+ const float a = (a_byte / 255.0f) * b_col_float[3];
+ const size_t buf_ofs = (((size_t)(chx + x) +
+ ((size_t)(pen_y_px + y) * (size_t)buf_info->dims[0])) *
+ (size_t)buf_info->ch);
+ float *fbuf = buf_info->fbuf + buf_ofs;
+
+ float font_pixel[4];
+ font_pixel[0] = b_col_float[0] * a;
+ font_pixel[1] = b_col_float[1] * a;
+ font_pixel[2] = b_col_float[2] * a;
+ font_pixel[3] = a;
+ blend_color_mix_float(fbuf, fbuf, font_pixel);
+ }
+ }
+
+ if (g->pitch < 0) {
+ yb++;
+ }
+ else {
+ yb--;
+ }
+ }
+ }
+
+ if (buf_info->cbuf) {
+ int yb = yb_start;
+ for (int y = ((chy >= 0) ? 0 : -chy); y < height_clip; y++) {
+ for (int x = ((chx >= 0) ? 0 : -chx); x < width_clip; x++) {
+ const char a_byte = *(g->bitmap + x + (yb * g->pitch));
+
+ if (a_byte) {
+ const float a = (a_byte / 255.0f) * b_col_float[3];
+ const size_t buf_ofs = (((size_t)(chx + x) +
+ ((size_t)(pen_y_px + y) * (size_t)buf_info->dims[0])) *
+ (size_t)buf_info->ch);
+ uchar *cbuf = buf_info->cbuf + buf_ofs;
+
+ uchar font_pixel[4];
+ font_pixel[0] = b_col_char[0];
+ font_pixel[1] = b_col_char[1];
+ font_pixel[2] = b_col_char[2];
+ font_pixel[3] = unit_float_to_uchar_clamp(a);
+ blend_color_mix_byte(cbuf, cbuf, font_pixel);
+ }
+ }
+
+ if (g->pitch < 0) {
+ yb++;
+ }
+ else {
+ yb--;
+ }
+ }
+ }
+}
+
/* Sanity checks are done by BLF_draw_buffer() */
static void blf_font_draw_buffer_ex(FontBLF *font,
GlyphCacheBLF *gc,
@@ -512,10 +622,6 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
/* buffer specific vars */
FontBufInfoBLF *buf_info = &font->buf_info;
- const float *b_col_float = buf_info->col_float;
- const uchar *b_col_char = buf_info->col_char;
- int chx, chy;
- int y, x;
/* another buffer specific call for color conversion */
@@ -527,101 +633,7 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
}
pen_x += blf_kerning(font, g_prev, g);
- chx = ft_pix_to_int(pen_x + ft_pix_from_int(g->pos[0]));
- chy = ft_pix_to_int(pen_y_basis + ft_pix_from_int(g->dims[1]));
-
- if (g->pitch < 0) {
- pen_y = pen_y_basis + ft_pix_from_int(g->dims[1] - g->pos[1]);
- }
- else {
- pen_y = pen_y_basis - ft_pix_from_int(g->dims[1] - g->pos[1]);
- }
-
- if ((chx + g->dims[0]) >= 0 && chx < buf_info->dims[0] &&
- (ft_pix_to_int(pen_y) + g->dims[1]) >= 0 && ft_pix_to_int(pen_y) < buf_info->dims[1]) {
- /* don't draw beyond the buffer bounds */
- int width_clip = g->dims[0];
- int height_clip = g->dims[1];
- int yb_start = g->pitch < 0 ? 0 : g->dims[1] - 1;
-
- if (width_clip + chx > buf_info->dims[0]) {
- width_clip -= chx + width_clip - buf_info->dims[0];
- }
- if (height_clip + ft_pix_to_int(pen_y) > buf_info->dims[1]) {
- height_clip -= ft_pix_to_int(pen_y) + height_clip - buf_info->dims[1];
- }
-
- /* drawing below the image? */
- if (pen_y < 0) {
- yb_start += (g->pitch < 0) ? -ft_pix_to_int(pen_y) : ft_pix_to_int(pen_y);
- height_clip += ft_pix_to_int(pen_y);
- pen_y = 0;
- }
-
- /* Avoid conversions in the pixel writing loop. */
- const int pen_y_px = ft_pix_to_int(pen_y);
-
- if (buf_info->fbuf) {
- int yb = yb_start;
- for (y = ((chy >= 0) ? 0 : -chy); y < height_clip; y++) {
- for (x = ((chx >= 0) ? 0 : -chx); x < width_clip; x++) {
- const char a_byte = *(g->bitmap + x + (yb * g->pitch));
- if (a_byte) {
- const float a = (a_byte / 255.0f) * b_col_float[3];
- const size_t buf_ofs = (((size_t)(chx + x) +
- ((size_t)(pen_y_px + y) * (size_t)buf_info->dims[0])) *
- (size_t)buf_info->ch);
- float *fbuf = buf_info->fbuf + buf_ofs;
-
- float font_pixel[4];
- font_pixel[0] = b_col_float[0] * a;
- font_pixel[1] = b_col_float[1] * a;
- font_pixel[2] = b_col_float[2] * a;
- font_pixel[3] = a;
- blend_color_mix_float(fbuf, fbuf, font_pixel);
- }
- }
-
- if (g->pitch < 0) {
- yb++;
- }
- else {
- yb--;
- }
- }
- }
-
- if (buf_info->cbuf) {
- int yb = yb_start;
- for (y = ((chy >= 0) ? 0 : -chy); y < height_clip; y++) {
- for (x = ((chx >= 0) ? 0 : -chx); x < width_clip; x++) {
- const char a_byte = *(g->bitmap + x + (yb * g->pitch));
-
- if (a_byte) {
- const float a = (a_byte / 255.0f) * b_col_float[3];
- const size_t buf_ofs = (((size_t)(chx + x) +
- ((size_t)(pen_y_px + y) * (size_t)buf_info->dims[0])) *
- (size_t)buf_info->ch);
- uchar *cbuf = buf_info->cbuf + buf_ofs;
-
- uchar font_pixel[4];
- font_pixel[0] = b_col_char[0];
- font_pixel[1] = b_col_char[1];
- font_pixel[2] = b_col_char[2];
- font_pixel[3] = unit_float_to_uchar_clamp(a);
- blend_color_mix_byte(cbuf, cbuf, font_pixel);
- }
- }
-
- if (g->pitch < 0) {
- yb++;
- }
- else {
- yb--;
- }
- }
- }
- }
+ blf_glyph_draw_buffer(buf_info, g, pen_x, pen_y_basis);
pen_x = ft_pix_round_advance(pen_x, g->advance_x);
g_prev = g;
@@ -901,25 +913,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 +938,95 @@ 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) {
+ /* We are to the right of the string, so return position of null terminator. */
+ data.r_offset = BLI_strnlen(str, str_len);
+ }
+ else if (BLI_str_utf8_char_width(&str[data.r_offset]) < 1) {
+ /* This is a combining character (or invalid), so move to previous visible valid char. */
+ BLI_str_cursor_step_prev_utf8(str, str_len, (int *)&data.r_offset);
+ }
+
+ 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;
}
/** \} */
@@ -1146,38 +1207,6 @@ void blf_font_draw_buffer__wrap(FontBLF *font,
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Text Evaluation: Count Missing Characters
- * \{ */
-
-int blf_font_count_missing_chars(FontBLF *font,
- const char *str,
- const size_t str_len,
- int *r_tot_chars)
-{
- int missing = 0;
- size_t i = 0;
-
- *r_tot_chars = 0;
- while (i < str_len) {
- uint c;
-
- if ((c = str[i]) < GLYPH_ASCII_TABLE_SIZE) {
- i++;
- }
- else {
- c = BLI_str_utf8_as_unicode_step(str, str_len, &i);
- if (blf_get_char_index(font, c) == 0) {
- missing++;
- }
- }
- (*r_tot_chars)++;
- }
- return missing;
-}
-
-/** \} */
-
-/* -------------------------------------------------------------------- */
/** \name Font Query: Attributes
* \{ */
@@ -1300,7 +1329,6 @@ static void blf_font_fill(FontBLF *font)
font->clip_rec.ymin = 0;
font->clip_rec.ymax = 0;
font->flags = 0;
- font->dpi = 0;
font->size = 0;
BLI_listbase_clear(&font->cache);
font->kerning_cache = NULL;
@@ -1346,7 +1374,9 @@ bool blf_ensure_face(FontBLF *font)
if (font->mem) {
err = FT_New_Memory_Face(font->ft_lib, font->mem, (FT_Long)font->mem_size, 0, &font->face);
}
- font->face->generic.data = font;
+ if (!err) {
+ font->face->generic.data = font;
+ }
BLI_mutex_unlock(&ft_lib_mutex);
}
@@ -1611,8 +1641,8 @@ void blf_ensure_size(FontBLF *font)
scaler.width = 0;
scaler.height = round_fl_to_uint(font->size * 64.0f);
scaler.pixel = 0;
- scaler.x_res = font->dpi;
- scaler.y_res = font->dpi;
+ scaler.x_res = BLF_DPI;
+ scaler.y_res = BLF_DPI;
if (FTC_Manager_LookupSize(ftc_manager, &scaler, &font->ft_size) == FT_Err_Ok) {
font->ft_size->generic.data = (void *)font;
font->ft_size->generic.finalizer = blf_size_finalizer;
@@ -1622,7 +1652,7 @@ void blf_ensure_size(FontBLF *font)
BLI_assert_unreachable();
}
-bool blf_font_size(FontBLF *font, float size, uint dpi)
+bool blf_font_size(FontBLF *font, float size)
{
if (!blf_ensure_face(font)) {
return false;
@@ -1633,15 +1663,15 @@ bool blf_font_size(FontBLF *font, float size, uint dpi)
/* Adjust our new size to be on even 64ths. */
size = (float)ft_size / 64.0f;
- if (font->size != size || font->dpi != dpi) {
+ if (font->size != size) {
if (font->flags & BLF_CACHED) {
FTC_ScalerRec scaler = {0};
scaler.face_id = font;
scaler.width = 0;
scaler.height = ft_size;
scaler.pixel = 0;
- scaler.x_res = dpi;
- scaler.y_res = dpi;
+ scaler.x_res = BLF_DPI;
+ scaler.y_res = BLF_DPI;
if (FTC_Manager_LookupSize(ftc_manager, &scaler, &font->ft_size) != FT_Err_Ok) {
return false;
}
@@ -1649,7 +1679,7 @@ bool blf_font_size(FontBLF *font, float size, uint dpi)
font->ft_size->generic.finalizer = blf_size_finalizer;
}
else {
- if (FT_Set_Char_Size(font->face, 0, ft_size, dpi, dpi) != FT_Err_Ok) {
+ if (FT_Set_Char_Size(font->face, 0, ft_size, BLF_DPI, BLF_DPI) != FT_Err_Ok) {
return false;
}
font->ft_size = font->face->size;
@@ -1657,7 +1687,6 @@ bool blf_font_size(FontBLF *font, float size, uint dpi)
}
font->size = size;
- font->dpi = dpi;
return true;
}
diff --git a/source/blender/blenfont/intern/blf_font_default.c b/source/blender/blenfont/intern/blf_font_default.c
index d35692f6eae..63b1cf34db5 100644
--- a/source/blender/blenfont/intern/blf_font_default.c
+++ b/source/blender/blenfont/intern/blf_font_default.c
@@ -32,7 +32,7 @@ static int blf_load_font_default(const char *filename, const bool unique)
}
char filepath[FILE_MAX];
- BLI_join_dirfile(filepath, sizeof(filepath), dir, filename);
+ BLI_path_join(filepath, sizeof(filepath), dir, filename);
return (unique) ? BLF_load_unique(filepath) : BLF_load(filepath);
}
diff --git a/source/blender/blenfont/intern/blf_font_win32_compat.c b/source/blender/blenfont/intern/blf_font_win32_compat.c
index 17213275c74..4bb2a010dd9 100644
--- a/source/blender/blenfont/intern/blf_font_win32_compat.c
+++ b/source/blender/blenfont/intern/blf_font_win32_compat.c
@@ -39,10 +39,7 @@ static void ft_ansi_stream_close(FT_Stream stream)
MEM_freeN(stream);
}
-static unsigned long ft_ansi_stream_io(FT_Stream stream,
- unsigned long offset,
- unsigned char *buffer,
- unsigned long count)
+static ulong ft_ansi_stream_io(FT_Stream stream, ulong offset, uchar *buffer, ulong count)
{
FILE *file;
if (!count && offset > stream->size) {
diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c
index c08d52307b7..b60ca3da1ea 100644
--- a/source/blender/blenfont/intern/blf_glyph.c
+++ b/source/blender/blenfont/intern/blf_glyph.c
@@ -54,7 +54,7 @@
*/
static FT_Fixed to_16dot16(double val)
{
- return (FT_Fixed)(lround(val * 65536.0));
+ return (FT_Fixed)lround(val * 65536.0);
}
/** \} */
@@ -63,11 +63,11 @@ static FT_Fixed to_16dot16(double val)
/** \name Glyph Cache
* \{ */
-static GlyphCacheBLF *blf_glyph_cache_find(const FontBLF *font, const float size, uint dpi)
+static GlyphCacheBLF *blf_glyph_cache_find(const FontBLF *font, const float size)
{
GlyphCacheBLF *gc = (GlyphCacheBLF *)font->cache.first;
while (gc) {
- if (gc->size == size && gc->dpi == dpi && (gc->bold == ((font->flags & BLF_BOLD) != 0)) &&
+ 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)) {
@@ -85,7 +85,6 @@ static GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font)
gc->next = NULL;
gc->prev = NULL;
gc->size = font->size;
- gc->dpi = font->dpi;
gc->bold = ((font->flags & BLF_BOLD) != 0);
gc->italic = ((font->flags & BLF_ITALIC) != 0);
gc->char_weight = font->char_weight;
@@ -122,7 +121,7 @@ GlyphCacheBLF *blf_glyph_cache_acquire(FontBLF *font)
{
BLI_mutex_lock(&font->glyph_cache_mutex);
- GlyphCacheBLF *gc = blf_glyph_cache_find(font, font->size, font->dpi);
+ GlyphCacheBLF *gc = blf_glyph_cache_find(font, font->size);
if (!gc) {
gc = blf_glyph_cache_new(font);
@@ -967,7 +966,7 @@ static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
int fixed_width)
{
if (glyph_font != settings_font) {
- blf_font_size(glyph_font, settings_font->size, settings_font->dpi);
+ blf_font_size(glyph_font, settings_font->size);
}
blf_ensure_size(glyph_font);
diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h
index 39d3af22562..2f3f7b52233 100644
--- a/source/blender/blenfont/intern/blf_internal.h
+++ b/source/blender/blenfont/intern/blf_internal.h
@@ -25,6 +25,13 @@ struct rcti;
/* Maximum number of bytes to use for cached data nodes. 0 is default of 200,000. */
#define BLF_CACHE_BYTES 400000
+/* We assume square pixels at a fixed DPI of 72, scaling only the size. Therefore
+ * font size = points = pixels, i.e. a size of 20 will result in a 20-pixel EM square.
+ * Although we could use the actual monitor DPI instead, we would then have to scale
+ * the size to cancel that out. Other libraries like Skia use this same fixed value.
+ */
+#define BLF_DPI 72
+
extern struct FontBLF *global_font[BLF_MAX_FONT];
void blf_batch_draw_begin(struct FontBLF *font);
@@ -70,7 +77,7 @@ void blf_font_attach_from_mem(struct FontBLF *font, const unsigned char *mem, si
/**
* Change font's output size. Returns true if successful in changing the size.
*/
-bool blf_font_size(struct FontBLF *font, float size, unsigned int dpi);
+bool blf_font_size(struct FontBLF *font, float size);
void blf_font_draw(struct FontBLF *font,
const char *str,
@@ -134,18 +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);
-int blf_font_count_missing_chars(struct FontBLF *font,
- const char *str,
- size_t str_len,
- int *r_tot_chars);
+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/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h
index d64bd9c5452..cc4be9f7f0e 100644
--- a/source/blender/blenfont/intern/blf_internal_types.h
+++ b/source/blender/blenfont/intern/blf_internal_types.h
@@ -142,9 +142,6 @@ typedef struct GlyphCacheBLF {
/** Font size. */
float size;
- /** DPI. */
- unsigned int dpi;
-
float char_weight;
float char_slant;
float char_width;
@@ -300,9 +297,6 @@ typedef struct FontBLF {
/** The width to wrap the text, see #BLF_WORD_WRAP. */
int wrap_width;
- /** Font DPI (default 72). */
- unsigned int dpi;
-
/** Font size. */
float size;
diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c
index bafa927a440..8a640ac86a7 100644
--- a/source/blender/blenfont/intern/blf_thumbs.c
+++ b/source/blender/blenfont/intern/blf_thumbs.c
@@ -8,16 +8,20 @@
* Isolate since this needs to be called by #ImBuf code (bad level call).
*/
-#include <stdio.h>
#include <stdlib.h>
-#include <string.h>
#include <ft2build.h>
#include FT_FREETYPE_H
+#include FT_ADVANCES_H /* For FT_Get_Advance */
+#include FT_TRUETYPE_IDS_H /* Code-point coverage constants. */
+#include FT_TRUETYPE_TABLES_H /* For TT_OS2 */
#include "BLI_listbase.h"
+#include "BLI_math_bits.h"
#include "BLI_rect.h"
+#include "BLI_string.h"
+#include "BLI_string_utf8.h"
#include "BLI_threads.h"
#include "BLI_utildefines.h"
@@ -25,90 +29,379 @@
#include "blf_internal_types.h"
#include "BLF_api.h"
-#include "BLT_translation.h"
#include "BLI_strict_flags.h"
-void BLF_thumb_preview(const char *filepath,
- const char **draw_str,
- const char **i18n_draw_str,
- const uchar draw_str_lines,
- const float font_color[4],
- const int font_size,
- uchar *buf,
- const int w,
- const int h,
- const int channels)
+/* Maximum length of text sample in char32_t, including NULL terminator. */
+#define BLF_SAMPLE_LEN 5
+
+typedef struct UnicodeSample {
+ char32_t sample[BLF_SAMPLE_LEN];
+ int field; /* ‘OS/2’ table ulUnicodeRangeX field (1-4). */
+ FT_ULong mask; /* ‘OS/2’ table ulUnicodeRangeX bit mask. */
+} UnicodeSample;
+
+/* The seemingly arbitrary order that follows is to help quickly find the most-likely designed
+ * intent of the font. Many feature-specific fonts contain Latin, Greek, & Coptic characters so
+ * those need to be checked last. */
+static const UnicodeSample unicode_samples[] = {
+ /* Chinese, Japanese, Korean, ordered specific to general. */
+ {U"\ud55c\uad6d\uc5b4", 2, TT_UCR_HANGUL}, /* 한국어 */
+ {U"\u3042\u30a2\u4e9c", 2, TT_UCR_HIRAGANA}, /* あア亜 */
+ {U"\u30a2\u30a4\u4e9c", 2, TT_UCR_KATAKANA}, /* アイ亜 */
+ {U"\u1956\u195b\u1966", 3, TT_UCR_TAI_LE}, /* ᥖᥛᥦ */
+ {U"\u3105\u3106\u3107", 2, TT_UCR_BOPOMOFO}, /* ㄅㄆㄇ */
+ {U"\ua840\ua841\ua85d", 2, TT_UCR_PHAGSPA}, /* ꡀꡁꡝ */
+ {U"\u5e03\u4e01\u4f53", 2, TT_UCR_CJK_UNIFIED_IDEOGRAPHS}, /* 布丁体 */
+ /* Languages in the BMP with a coverage bit. */
+ {U"\u05d0\u05da\u05e4", 1, TT_UCR_HEBREW},
+ {U"\ua500\ua502\ua549", 1, TT_UCR_VAI},
+ {U"\ufee6\ufef4\ufeb3", 1, TT_UCR_ARABIC},
+ {U"\u07C1\u07C2\u07C3", 1, TT_UCR_NKO},
+ {U"\u0905\u093f\u092a", 1, TT_UCR_DEVANAGARI},
+ {U"\u0986\u0987\u098c", 1, TT_UCR_BENGALI},
+ {U"\u0a05\u0a16\u0a30", 1, TT_UCR_GURMUKHI},
+ {U"\u0aaa\u0aaf\u0ab8", 1, TT_UCR_GUJARATI},
+ {U"\u0b2a\u0b30\u0b37", 1, TT_UCR_ORIYA},
+ {U"\u0b85\u0b88\u0b8f", 1, TT_UCR_TAMIL},
+ {U"\u0c05\u0c0c\u0c36", 1, TT_UCR_TELUGU},
+ {U"\u0c85\u0c87\u0c8e", 1, TT_UCR_KANNADA},
+ {U"\u0d05\u0d09\u0d3d", 1, TT_UCR_MALAYALAM},
+ {U"\u0e05\u0e06\u0e07", 1, TT_UCR_THAI},
+ {U"\u0e81\u0e82\u0e84", 1, TT_UCR_LAO},
+ {U"\u10a0\u10a1\u10a2", 1, TT_UCR_GEORGIAN},
+ {U"\u1B05\u1B07\u1B09", 1, TT_UCR_BALINESE},
+ {U"\u0f00\u0f04\u0f08", 3, TT_UCR_TIBETAN},
+ {U"\u0710\u0717\u071c", 3, TT_UCR_SYRIAC},
+ {U"\u0784\u0783\u0798", 3, TT_UCR_THAANA},
+ {U"\u0d85\u0d89\u0daf", 3, TT_UCR_SINHALA},
+ {U"\u1000\u1001\u1014", 3, TT_UCR_MYANMAR},
+ {U"\u1202\u1207\u1250", 3, TT_UCR_ETHIOPIC},
+ {U"\u13a3\u13a4\u13a8", 3, TT_UCR_CHEROKEE},
+ {U"\u1401\u144d\u156e", 3, TT_UCR_CANADIAN_ABORIGINAL_SYLLABICS},
+ {U"\u1681\u1687\u168b", 3, TT_UCR_OGHAM},
+ {U"\u16A0\u16A4\u16AA", 3, TT_UCR_RUNIC},
+ {U"\u1780\u1781\u1783", 3, TT_UCR_KHMER},
+ {U"\u1820\u1826\u1845", 3, TT_UCR_MONGOLIAN},
+ {U"\ua188\ua320\ua4bf", 3, TT_UCR_YI},
+ {U"\u1900\u1901\u1902", 3, TT_UCR_LIMBU},
+ {U"\u1950\u1951\u1952", 3, TT_UCR_TAI_LE},
+ {U"\u1980\u1982\u1986", 3, (FT_ULong)TT_UCR_NEW_TAI_LUE},
+ {U"\u1A00\u1A01\u1A02", 4, TT_UCR_BUGINESE},
+ {U"\u2c01\u2c05\u2c0c", 4, TT_UCR_GLAGOLITIC},
+ {U"\u2d31\u2d33\u2d37", 4, TT_UCR_TIFINAGH},
+ {U"\u2d31\u2d33\u2d37", 4, TT_UCR_YIJING},
+ {U"\u1B83\u1B84\u1B88", 4, TT_UCR_SUNDANESE},
+ {U"\u1C00\u1C01\u1C02", 4, TT_UCR_LEPCHA},
+ {U"\u1C50\u1C51\u1C52", 4, TT_UCR_OL_CHIKI},
+ {U"\uA800\uA801\uA805", 4, TT_UCR_SYLOTI_NAGRI},
+ {U"\uA882\uA88a\uA892", 4, TT_UCR_SAURASHTRA},
+ {U"\uA901\uA902\uA904", 4, TT_UCR_KAYAH_LI},
+ {U"\uA930\uA932\uA943", 4, TT_UCR_REJANG},
+ {U"\uaa00\uaa02\uaa05", 4, TT_UCR_CHAM},
+ /* Indexed languages in the Supplementary Multilingual Plane. */
+ {U"\U00010000\U00010001\U00010002", 4, TT_UCR_LINEAR_B},
+ {U"\U00010300\U00010301\U00010302", 3, TT_UCR_OLD_ITALIC},
+ {U"\U00010330\U00010331\U00010332", 3, TT_UCR_GOTHIC},
+ {U"\U00010380\U00010381\U00010382", 4, TT_UCR_UGARITIC},
+ {U"\U000103A0\U000103A1\U000103A2", 4, TT_UCR_OLD_PERSIAN},
+ {U"\U00010400\U00010401\U00010402", 3, TT_UCR_DESERET},
+ {U"\U00010450\U00010451\U00010452", 4, TT_UCR_SHAVIAN},
+ {U"\U00010480\U00010481\U00010482", 4, TT_UCR_OSMANYA},
+ {U"\U00010800\U00010803\U00010805", 4, TT_UCR_CYPRIOT_SYLLABARY},
+ {U"\U00010900\U00010901\U00010902", 2, TT_UCR_PHOENICIAN},
+ {U"\U00010A10\U00010A11\U00010A12", 4, TT_UCR_KHAROSHTHI},
+ {U"\U00012000\U00012001\U00012002", 4, TT_UCR_CUNEIFORM},
+ /* Philippine languages use a single OS2 coverage bit. */
+ {U"\u1700\u1701\u1702", 3, TT_UCR_PHILIPPINE}, /* Tagalog */
+ {U"\u1720\u1721\u1722", 3, TT_UCR_PHILIPPINE}, /* Hanunoo */
+ {U"\u1740\u1741\u1742", 3, TT_UCR_PHILIPPINE}, /* Buhid */
+ {U"\u1760\u1761\u1762", 3, TT_UCR_PHILIPPINE}, /* Tagbanwa */
+ /* Anatolian languages use a single OS2 coverage bit. */
+ {U"\U000102A3\U000102A8\U000102CB", 4, TT_UCR_OLD_ANATOLIAN}, /* Carian */
+ {U"\U00010280\U00010281\U00010282", 4, TT_UCR_OLD_ANATOLIAN}, /* Lycian */
+ {U"\U00010920\U00010921\U00010922", 4, TT_UCR_OLD_ANATOLIAN}, /* Lydian */
+ /* Symbol blocks. */
+ {U"\U0001f600\U0001f638", 0, 0}, /* Emoticons 😀😸 */
+ {U"\uf021\uf022\uf023", 0, 0}, /* MS Symbols */
+ {U"\u280f\u2815\u283f", 3, TT_UCR_BRAILLE},
+ {U"\U0001D11e\U0001D161\U0001D130", 3, TT_UCR_MUSICAL_SYMBOLS},
+ {U"\u2700\u2708\u2709", 2, TT_UCR_DINGBATS},
+ {U"\u2600\u2601\u2602", 2, TT_UCR_MISCELLANEOUS_SYMBOLS},
+ {U"\ue000\ue001\ue002", 2, TT_UCR_PRIVATE_USE},
+ {U"\ue702\ue703\ue704", 2, TT_UCR_PRIVATE_USE},
+ {U"\U000F0001\U000F0002\U000F0003", 2, TT_UCR_PRIVATE_USE_SUPPLEMENTARY},
+ /* Languages in the Supplementary Multilingual Plane. */
+ {U"\U00010350\U00010352\U00010353", 2, TT_UCR_NON_PLANE_0}, /* Old Permic */
+ {U"\U000104B0\U000104B6\U000104B8", 2, TT_UCR_NON_PLANE_0}, /* Osage */
+ {U"\U00010500\U00010501\U00010502", 2, TT_UCR_NON_PLANE_0}, /* Elbasan */
+ {U"\U00010530\U00010531\U00010532", 2, TT_UCR_NON_PLANE_0}, /* Caucasian Albanian */
+ {U"\U00010600\U00010601\U00010602", 2, TT_UCR_NON_PLANE_0}, /* Linear A */
+ {U"\U00010840\U00010841\U00010842", 2, TT_UCR_NON_PLANE_0}, /* Imperial Aramaic */
+ {U"\U00010860\U00010861\U00010862", 2, TT_UCR_NON_PLANE_0}, /* Palmyrene */
+ {U"\U00010880\U00010881\U00010882", 2, TT_UCR_NON_PLANE_0}, /* Nabataean */
+ {U"\U000108E0\U000108E3\U000108E4", 2, TT_UCR_NON_PLANE_0}, /* Hatran */
+ {U"\U00010980\U00010983\U00010989", 2, TT_UCR_NON_PLANE_0}, /* Meroitic Hieroglyphs */
+ {U"\U000109A0\U000109A1\U000109A2", 2, TT_UCR_NON_PLANE_0}, /* Meroitic Cursive */
+ {U"\U00010A60\U00010A61\U00010A62", 2, TT_UCR_NON_PLANE_0}, /* Old South Arabian */
+ {U"\U00010A80\U00010A81\U00010A82", 2, TT_UCR_NON_PLANE_0}, /* Old North Arabian */
+ {U"\U00010ac0\U00010ac3\U00010ac6", 2, TT_UCR_NON_PLANE_0}, /* Manichaean */
+ {U"\U00010B00\U00010B04\U00010B08", 2, TT_UCR_NON_PLANE_0}, /* Avestan */
+ {U"\U00010B40\U00010B41\U00010B42", 2, TT_UCR_NON_PLANE_0}, /* Inscriptional Parthian */
+ {U"\U00010B60\U00010B61\U00010B62", 2, TT_UCR_NON_PLANE_0}, /* Inscriptional Pahlavi */
+ {U"\U00010B80\U00010B84\U00010B87", 2, TT_UCR_NON_PLANE_0}, /* Psalter Pahlavi */
+ {U"\U00010C00\U00010C01\U00010C02", 2, TT_UCR_NON_PLANE_0}, /* Old Turkic */
+ {U"\U00010C80\U00010C81\U00010C82", 2, TT_UCR_NON_PLANE_0}, /* Old Hungarian */
+ {U"\U00010D00\U00010D07\U00010D0D", 2, TT_UCR_NON_PLANE_0}, /* Hanifi Rohingya */
+ {U"\U00010E80\U00010E81\U00010E82", 2, TT_UCR_NON_PLANE_0}, /* Yezidi */
+ {U"\U00010F00\U00010F01\U00010F02", 2, TT_UCR_NON_PLANE_0}, /* Old Sogdian */
+ {U"\U00010F30\U00010F32\U00010F34", 2, TT_UCR_NON_PLANE_0}, /* Sogdian */
+ {U"\U00010F70\U00010F71\U00010F72", 2, TT_UCR_NON_PLANE_0}, /* Old Uyghur */
+ {U"\U00010FB0\U00010FB1\U00010FB2", 2, TT_UCR_NON_PLANE_0}, /* Chorasmian */
+ {U"\U00010FE0\U00010FE1\U00010FE2", 2, TT_UCR_NON_PLANE_0}, /* Elymaic */
+ {U"\U00011003\U00011004\U00011005", 2, TT_UCR_NON_PLANE_0}, /* Brahmi */
+ {U"\U00011083\U00011085\U00011087", 2, TT_UCR_NON_PLANE_0}, /* Kaithi */
+ {U"\U000110D0\U000110D1\U000110D2", 2, TT_UCR_NON_PLANE_0}, /* Sora Sompeng */
+ {U"\U00011103\U00011104\U00011105", 2, TT_UCR_NON_PLANE_0}, /* Chakma */
+ {U"\U00011150\U00011151\U00011152", 2, TT_UCR_NON_PLANE_0}, /* Mahajani */
+ {U"\U00011183\U00011185\U0001118b", 2, TT_UCR_NON_PLANE_0}, /* Sharada */
+ {U"\U00011200\U00011201\U00011202", 2, TT_UCR_NON_PLANE_0}, /* Khojki */
+ {U"\U00011280\U00011281\U00011282", 2, TT_UCR_NON_PLANE_0}, /* Multani */
+ {U"\U000112B0\U000112B2\U000112B4", 2, TT_UCR_NON_PLANE_0}, /* Khudawadi */
+ {U"\U00011305\U00011309\U0001130b", 2, TT_UCR_NON_PLANE_0}, /* Grantha */
+ {U"\U00011400\U00011404\U00011409", 2, TT_UCR_NON_PLANE_0}, /* Newa */
+ {U"\U00011480\U00011481\U00011482", 2, TT_UCR_NON_PLANE_0}, /* Tirhuta */
+ {U"\U00011580\U00011582\U00011589", 2, TT_UCR_NON_PLANE_0}, /* Siddham */
+ {U"\U00011600\U00011604\U00011609", 2, TT_UCR_NON_PLANE_0}, /* Modi */
+ {U"\U00011680\U00011682\U0001168A", 2, TT_UCR_NON_PLANE_0}, /* Takri */
+ {U"\U00011700\U00011701\U00011702", 2, TT_UCR_NON_PLANE_0}, /* Ahom */
+ {U"\U00011800\U00011801\U00011802", 2, TT_UCR_NON_PLANE_0}, /* Dogri */
+ {U"\U000118A0\U000118A1\U000118AA", 2, TT_UCR_NON_PLANE_0}, /* Warang Citi */
+ {U"\U00011900\U00011901\U00011902", 2, TT_UCR_NON_PLANE_0}, /* Dives Akuru */
+ {U"\U00011A00\U00011A10\U00011A15", 2, TT_UCR_NON_PLANE_0}, /* Zanabazar Square */
+ {U"\U00011A50\U00011A5C\U00011A6B", 2, TT_UCR_NON_PLANE_0}, /* Soyombo */
+ {U"\U00011AC0\U00011AC1\U00011AC2", 2, TT_UCR_NON_PLANE_0}, /* Pau Cin Hau */
+ {U"\U00011C00\U00011C01\U00011C02", 2, TT_UCR_NON_PLANE_0}, /* Bhaiksuki */
+ {U"\U00011C70\U00011C71\U00011C72", 2, TT_UCR_NON_PLANE_0}, /* Marchen */
+ {U"\U00011D00\U00011D02\U00011D08", 2, TT_UCR_NON_PLANE_0}, /* Masaram Gondi */
+ {U"\U00011D60\U00011D62\U00011D6c", 2, TT_UCR_NON_PLANE_0}, /* Gunjala Gondi */
+ {U"\U00011FC1\U00011FC2\U00011FC8", 2, TT_UCR_NON_PLANE_0}, /* Tamil Supplement */
+ {U"\U00012F90\U00012F91\U00012F92", 2, TT_UCR_NON_PLANE_0}, /* Cypro-Minoan */
+ {U"\U00013000\U00013076\U0001307f", 2, TT_UCR_NON_PLANE_0}, /* Egyptian Hieroglyphs */
+ {U"\U00014400\U00014409\U00014447", 2, TT_UCR_NON_PLANE_0}, /* Anatolian Hieroglyphs */
+ {U"\U00016A40\U00016A41\U00016A42", 2, TT_UCR_NON_PLANE_0}, /* Mro */
+ {U"\U00016A70\U00016A71\U00016A72", 2, TT_UCR_NON_PLANE_0}, /* Tangsa */
+ {U"\U00016AD0\U00016AD2\U00016ADA", 2, TT_UCR_NON_PLANE_0}, /* Bassa Vah */
+ {U"\U00016B00\U00016B01\U00016B02", 2, TT_UCR_NON_PLANE_0}, /* Pahawh Hmong */
+ {U"\U00016F01\U00016F05\U00016F09", 2, TT_UCR_NON_PLANE_0}, /* Miao */
+ {U"\U0001BC19\U0001BC1f\U0001BC0e", 2, TT_UCR_NON_PLANE_0}, /* Duployan */
+ {U"\U0001D2E0\U0001D2E6\U0001D2f3", 2, TT_UCR_NON_PLANE_0}, /* Mayan Numerals */
+ {U"\U0001E800\U0001E80A\U0001E80F", 2, TT_UCR_NON_PLANE_0}, /* Mende Kikakui */
+ {U"\U0001E900\U0001E902\U0001E907", 2, TT_UCR_NON_PLANE_0}, /* Adlam */
+ {U"\U0001E2C0\U0001E2C2\U0001E2C7", 2, TT_UCR_NON_PLANE_0}, /* Wancho */
+ {U"\U0001EC71\U0001EC72\U0001EC73", 2, TT_UCR_NON_PLANE_0}, /* Indic Siyaq Numbers */
+ /* Basic Multilingual Plane but are not indexed with an OS2 coverage bit. */
+ {U"\u0638\u0630\u0633", 0, 0}, /* Urdu */
+ {U"\u0800\u0801\u0802", 0, 0}, /* Samaritan */
+ {U"\u0841\u0842\u084c", 0, 0}, /* Mandaic */
+ {U"\u1A20\u1A21\u1A22", 0, 0}, /* Tai Tham */
+ {U"\u1BC0\u1BC1\u1BC2", 0, 0}, /* Batak */
+ {U"\uA4EF\uA4E8\uA4ED", 0, 0}, /* Lisu */
+ {U"\uA6A0\uA6A1\uA6A2", 0, 0}, /* Bamum */
+ {U"\ua983\ua984\ua98d", 0, 0}, /* Javanese */
+ {U"\uaa80\uaa81\uaa82", 0, 0}, /* Tai Viet */
+ {U"\uABC0\uABC1\uABC2", 0, 0}, /* Meetei Mayek */
+ /* Near the end since many fonts contain these. */
+ {U"\u03e2\u03e4\u03e8", 1, TT_UCR_COPTIC},
+ {U"\u1f08\u03a6\u03a8", 1, TT_UCR_GREEK},
+ {U"\u0518\u0409\u040f", 1, TT_UCR_CYRILLIC},
+ {U"\u0533\u0537\u0539", 1, TT_UCR_ARMENIAN},
+};
+
+static const char32_t *blf_get_sample_text(FT_Face face)
{
- const uint dpi = 72;
- const int font_size_min = 6;
- int font_size_curr;
- /* shrink 1/th each line */
- int font_shrink = 4;
+ /* First check for fonts with MS Symbol character map. */
+ if (face->charmap->encoding == FT_ENCODING_MS_SYMBOL) {
+ /* Many of these have characters starting from F020. */
+ if (FT_Get_Char_Index(face, U'\uf041') != 0) {
+ return U"\uf041\uf044\uf048";
+ }
+ if (FT_Get_Char_Index(face, U'\uf030') != 0) {
+ return U"\uf030\uf031\uf032";
+ }
+ return U"ADH";
+ }
- /* While viewing thumbnails in font directories this function can be called simultaneously from a
- * greater number of threads than we want the FreeType cache to keep open at a time. Therefore
- * pass own FT_Library to font creation so that it is not managed by the FreeType cache system.
- */
+ const char32_t *def = U"Aabg";
+ const char32_t *sample = def;
- FT_Library ft_library = NULL;
- if (FT_Init_FreeType(&ft_library) != FT_Err_Ok) {
- return;
+ /* Fonts too old to have a Unicode character map. */
+ if (face->charmap->encoding != FT_ENCODING_UNICODE) {
+ return def;
}
- FontBLF *font = blf_font_new_ex("thumb_font", filepath, NULL, 0, ft_library);
- if (!font) {
- printf("Info: Can't load font '%s', no preview possible\n", filepath);
- FT_Done_FreeType(ft_library);
- return;
+ /* TrueType table with bits to quickly test most Unicode block coverage. */
+ TT_OS2 *os2_table = (TT_OS2 *)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
+ if (!os2_table) {
+ return def;
+ }
+
+ /* Detect "Last resort" fonts. They have everything, except the last 5 bits. */
+ if (os2_table->ulUnicodeRange1 == 0xffffffffU && os2_table->ulUnicodeRange2 == 0xffffffffU &&
+ os2_table->ulUnicodeRange3 == 0xffffffffU && os2_table->ulUnicodeRange4 >= 0x7FFFFFFU) {
+ return U"\xE000\xFFFF";
+ }
+
+ int language_count = count_bits_i((uint)os2_table->ulUnicodeRange1) +
+ count_bits_i((uint)os2_table->ulUnicodeRange2) +
+ count_bits_i((uint)os2_table->ulUnicodeRange3) +
+ count_bits_i((uint)os2_table->ulUnicodeRange4);
+
+ for (uint i = 0; i < ARRAY_SIZE(unicode_samples); ++i) {
+ const UnicodeSample *s = &unicode_samples[i];
+ if (os2_table && s->field && s->mask) {
+ /* OS/2 Table contains 4 contiguous integers of script coverage bit flags. */
+ const FT_ULong *unicode_range = &os2_table->ulUnicodeRange1;
+ const int index = (s->field - 1);
+ BLI_assert(index < 4);
+ if (!(unicode_range[index] & s->mask)) {
+ continue;
+ }
+ }
+ if (FT_Get_Char_Index(face, s->sample[0]) != 0) {
+ sample = s->sample;
+ break;
+ }
}
- /* Would be done via the BLF API, but we're not using a fontid here */
- font->buf_info.cbuf = buf;
- font->buf_info.ch = channels;
- font->buf_info.dims[0] = w;
- font->buf_info.dims[1] = h;
+ bool has_latin = (os2_table && (os2_table->ulUnicodeRange1 & TT_UCR_BASIC_LATIN) &&
+ (FT_Get_Char_Index(face, U'A') != 0));
+ bool has_cjk = (os2_table && (os2_table->ulUnicodeRange2 & TT_UCR_CJK_UNIFIED_IDEOGRAPHS));
- /* Always create the image with a white font,
- * the caller can theme how it likes */
- memcpy(font->buf_info.col_init, font_color, sizeof(font->buf_info.col_init));
- font->pos[1] = h;
+ if (has_latin && ((has_cjk && language_count > 40) || (!has_cjk && language_count > 5))) {
+ return def;
+ }
- font_size_curr = font_size;
+ return sample;
+}
- blf_draw_buffer__start(font);
+bool BLF_thumb_preview(const char *filename, uchar *buf, int w, int h, int UNUSED(channels))
+{
+ /* Use own FT_Library and direct FreeType calls as this is called from multiple threads. */
+ FT_Library ft_lib = NULL;
+ if (FT_Init_FreeType(&ft_lib) != FT_Err_Ok) {
+ return false;
+ }
- for (int i = 0; i < draw_str_lines; i++) {
- const char *draw_str_i18n = i18n_draw_str[i] != NULL ? i18n_draw_str[i] : draw_str[i];
- const size_t draw_str_i18n_len = strlen(draw_str_i18n);
- int draw_str_i18_count = 0;
+ FT_Face face;
+ if (FT_New_Face(ft_lib, filename, 0, &face) != FT_Err_Ok) {
+ FT_Done_FreeType(ft_lib);
+ return false;
+ }
- CLAMP_MIN(font_size_curr, font_size_min);
- if (!blf_font_size(font, (float)font_size_curr, dpi)) {
- break;
+ if (!(face->face_flags & FT_FACE_FLAG_SCALABLE)) {
+ return false;
+ }
+
+ FT_Error err = FT_Select_Charmap(face, FT_ENCODING_UNICODE);
+ if (err) {
+ err = FT_Select_Charmap(face, FT_ENCODING_MS_SYMBOL);
+ }
+ if (err) {
+ err = FT_Select_Charmap(face, FT_ENCODING_APPLE_ROMAN);
+ }
+ if (err && face->num_charmaps > 0) {
+ err = FT_Select_Charmap(face, face->charmaps[0]->encoding);
+ }
+ if (err != FT_Err_Ok) {
+ FT_Done_Face(face);
+ FT_Done_FreeType(ft_lib);
+ return false;
+ }
+
+ const char32_t *codepoints = blf_get_sample_text(face);
+ uint glyph_ids[BLF_SAMPLE_LEN] = {0};
+
+ /* A large initial font size for measuring. Nothing will be rendered this size. */
+ if (FT_Set_Char_Size(face, w * 64, 0, 72, 72) != FT_Err_Ok) {
+ FT_Done_Face(face);
+ FT_Done_FreeType(ft_lib);
+ return false;
+ }
+
+ /* Approximate length of the sample. Uses only advances, ignores bearings. */
+ int width = 0;
+ for (uint i = 0; i < BLF_SAMPLE_LEN && codepoints[i]; i++) {
+ glyph_ids[i] = FT_Get_Char_Index(face, codepoints[i]);
+ /* If sample glyph is not found, use another. */
+ if (!glyph_ids[i]) {
+ glyph_ids[i] = (uint)(face->num_glyphs / (BLF_SAMPLE_LEN + 1)) * (i + 1);
}
+ /* Get advance without loading the glyph. */
+ FT_Fixed advance;
+ FT_Get_Advance(face, glyph_ids[i], FT_LOAD_NO_HINTING, &advance);
+ /* Advance is returned in 16.16 format, so divide by 65536 for pixels. */
+ width += (int)(advance >> 16);
+ }
+
+ int height = ft_pix_to_int((ft_pix)face->size->metrics.ascender -
+ (ft_pix)face->size->metrics.descender);
+ width = MAX2(width, height);
+
+ /* Fill up to 96% horizontally or vertically. */
+ float font_size = MIN3((float)w,
+ ((float)w * 0.96f / (float)width * (float)w),
+ (float)h * 0.96f / (float)height * (float)h);
- /* decrease font size each time */
- font_size_curr -= (font_size_curr / font_shrink);
- font_shrink += 1;
+ if (font_size < 1 || FT_Set_Char_Size(face, (int)(font_size * 64.0f), 0, 72, 72) != FT_Err_Ok) {
+ /* Sizing can fail, but very rarely. */
+ FT_Done_Face(face);
+ FT_Done_FreeType(ft_lib);
+ return false;
+ }
+
+ /* Horizontally center, line up baselines vertically. */
+ int left = (int)(((float)w - ((float)width * (font_size / (float)w))) / 2.0f);
+ int top = (int)((float)h * 0.7f);
+
+ /* Print out to buffer. */
- font->pos[1] -= (int)((float)blf_font_ascender(font) * 1.1f);
+ FT_Pos advance_x = 0;
+ int glyph_count = 0; /* How many are successfully loaded and rendered. */
- /* We fallback to default english strings in case not enough chars are available in current
- * font for given translated string (useful in non-Latin i18n context, like Chinese,
- * since many fonts will then show nothing but ugly 'missing char' in their preview).
- * Does not handle all cases, but much better than nothing.
- */
- if (blf_font_count_missing_chars(font, draw_str_i18n, draw_str_i18n_len, &draw_str_i18_count) >
- (draw_str_i18_count / 2)) {
- blf_font_draw_buffer(font, draw_str[i], strlen(draw_str[i]), NULL);
+ for (int i = 0; i < BLF_SAMPLE_LEN && glyph_ids[i]; i++) {
+ if (FT_Load_Glyph(face, glyph_ids[i], FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING) !=
+ FT_Err_Ok) {
+ break;
}
- else {
- blf_font_draw_buffer(font, draw_str_i18n, draw_str_i18n_len, NULL);
+
+ if (FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL) != FT_Err_Ok ||
+ face->glyph->format != FT_GLYPH_FORMAT_BITMAP) {
+ break;
}
+
+ glyph_count++;
+
+ for (int y = 0; y < (int)face->glyph->bitmap.rows; y++) {
+ int dest_row = (h - y - 1 + (int)face->glyph->bitmap_top - top);
+ if (dest_row >= 0 && dest_row < h) {
+ for (int x = 0; x < (int)face->glyph->bitmap.width; x++) {
+ int dest_col = (x + ft_pix_to_int((ft_pix)advance_x) + face->glyph->bitmap_left + left);
+ if (dest_col >= 0 && dest_col < w) {
+ uchar *source = &face->glyph->bitmap.buffer[y * (int)face->glyph->bitmap.width + x];
+ uchar *dest = &buf[dest_row * w * 4 + (dest_col * 4 + 3)];
+ *dest = (uchar)MIN2(((uint)*dest + (uint)*source), 255u);
+ }
+ }
+ }
+ }
+
+ advance_x += face->glyph->advance.x;
}
- blf_draw_buffer__end();
- blf_font_free(font);
- FT_Done_FreeType(ft_library);
+ FT_Done_Face(face);
+ FT_Done_FreeType(ft_lib);
+
+ /* Return success if we printed at least one glyph. */
+ return glyph_count > 0;
}
diff --git a/source/blender/blenfont/intern/blf_util.c b/source/blender/blenfont/intern/blf_util.c
index 09ddb56e53b..2243da4df18 100644
--- a/source/blender/blenfont/intern/blf_util.c
+++ b/source/blender/blenfont/intern/blf_util.c
@@ -15,7 +15,7 @@
#include "blf_internal.h"
-unsigned int blf_next_p2(unsigned int x)
+uint blf_next_p2(uint x)
{
x -= 1;
x |= (x >> 16);
@@ -27,9 +27,9 @@ unsigned int blf_next_p2(unsigned int x)
return x;
}
-unsigned int blf_hash(unsigned int val)
+uint blf_hash(uint val)
{
- unsigned int key;
+ uint key;
key = val;
key += ~(key << 16);