[Bf-blender-cvs] [ae43872ad57] master: BLF: sub-pixel positioning support

Campbell Barton noreply at git.blender.org
Wed Apr 13 03:59:42 CEST 2022


Commit: ae43872ad572eb3e6ad1ebfd02921fc2403059bc
Author: Campbell Barton
Date:   Tue Apr 5 20:10:55 2022 +1000
Branches: master
https://developer.blender.org/rBae43872ad572eb3e6ad1ebfd02921fc2403059bc

BLF: sub-pixel positioning support

Support sub-pixel kerning and hinting for future support for improved
character placement. No user visible changes have been made.

- Calculate sub-pixel offsets, using integer maths.
- Use convenience functions to perform the conversions and hide the
  underlying values.
- Use `ft_pix` type to distinguish values that use sub-pixel integer
  values from freetype and values rounded to pixels.

This was originally based on D12999 by @harley with the user visible
changes removed so they can be applied separately.

===================================================================

M	source/blender/blenfont/intern/blf_font.c
M	source/blender/blenfont/intern/blf_glyph.c
M	source/blender/blenfont/intern/blf_internal.h
M	source/blender/blenfont/intern/blf_internal_types.h

===================================================================

diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c
index 60ff5f6470f..e5d7cb05408 100644
--- a/source/blender/blenfont/intern/blf_font.c
+++ b/source/blender/blenfont/intern/blf_font.c
@@ -57,34 +57,26 @@ static SpinLock blf_glyph_cache_mutex;
 /* May be set to #UI_widgetbase_draw_cache_flush. */
 static void (*blf_draw_cache_flush)(void) = NULL;
 
+static ft_pix blf_font_height_max_ft_pix(struct FontBLF *font);
+static ft_pix blf_font_width_max_ft_pix(struct FontBLF *font);
+
 /* -------------------------------------------------------------------- */
 /** \name FreeType Utilities (Internal)
  * \{ */
 
-/**
- * Convert a FreeType 26.6 value representing an unscaled design size to pixels.
- * This is an exact copy of the scaling done inside FT_Get_Kerning when called
- * with #FT_KERNING_DEFAULT, including arbitrary resizing for small fonts.
- */
-static int blf_unscaled_F26Dot6_to_pixels(FontBLF *font, FT_Pos value)
+/* Convert a FreeType 26.6 value representing an unscaled design size to factional pixels. */
+static ft_pix blf_unscaled_F26Dot6_to_pixels(FontBLF *font, FT_Pos value)
 {
   /* Scale value by font size using integer-optimized multiplication. */
   FT_Long scaled = FT_MulFix(value, font->face->size->metrics.x_scale);
 
-  /* FreeType states that this '25' has been determined heuristically. */
+  /* Copied from FreeType's FT_Get_Kerning (with FT_KERNING_DEFAULT), scaling down */
+  /* kerning distances at small ppem values so that they don't become too big. */
   if (font->face->size->metrics.x_ppem < 25) {
     scaled = FT_MulDiv(scaled, font->face->size->metrics.x_ppem, 25);
   }
 
-  /* Copies of internal FreeType macros needed here. */
-#define FT_PIX_FLOOR(x) ((x) & ~63)
-#define FT_PIX_ROUND(x) FT_PIX_FLOOR((x) + 32)
-
-  /* Round to even 64ths, then divide by 64. */
-  return (int)FT_PIX_ROUND(scaled) >> 6;
-
-#undef FT_PIX_FLOOR
-#undef FT_PIX_ROUND
+  return (ft_pix)scaled;
 }
 
 /** \} */
@@ -293,36 +285,39 @@ BLI_INLINE GlyphBLF *blf_glyph_from_utf8_and_step(
   return blf_glyph_ensure(font, gc, charcode);
 }
 
-BLI_INLINE int blf_kerning(FontBLF *font, const GlyphBLF *g_prev, const GlyphBLF *g)
+BLI_INLINE ft_pix blf_kerning(FontBLF *font, const GlyphBLF *g_prev, const GlyphBLF *g)
 {
-  if (!FT_HAS_KERNING(font->face) || g_prev == NULL) {
-    return 0;
-  }
+  ft_pix adjustment = 0;
 
-  FT_Vector delta = {KERNING_ENTRY_UNSET};
+  /* Small adjust if there is hinting. */
+  adjustment += g->lsb_delta - ((g_prev) ? g_prev->rsb_delta : 0);
 
-  /* Get unscaled kerning value from our cache if ASCII. */
-  if ((g_prev->c < KERNING_CACHE_TABLE_SIZE) && (g->c < GLYPH_ASCII_TABLE_SIZE)) {
-    delta.x = font->kerning_cache->ascii_table[g->c][g_prev->c];
-  }
+  if (FT_HAS_KERNING(font->face) && g_prev) {
+    FT_Vector delta = {KERNING_ENTRY_UNSET};
 
-  /* If not ASCII or not found in cache, ask FreeType for kerning. */
-  if (UNLIKELY(delta.x == KERNING_ENTRY_UNSET)) {
-    /* Note that this function sets delta values to zero on any error. */
-    FT_Get_Kerning(font->face, g_prev->idx, g->idx, FT_KERNING_UNSCALED, &delta);
-  }
+    /* Get unscaled kerning value from our cache if ASCII. */
+    if ((g_prev->c < KERNING_CACHE_TABLE_SIZE) && (g->c < GLYPH_ASCII_TABLE_SIZE)) {
+      delta.x = font->kerning_cache->ascii_table[g->c][g_prev->c];
+    }
 
-  /* 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)) {
-    font->kerning_cache->ascii_table[g->c][g_prev->c] = (int)delta.x;
-  }
+    /* If not ASCII or not found in cache, ask FreeType for kerning. */
+    if (UNLIKELY(delta.x == KERNING_ENTRY_UNSET)) {
+      /* Note that this function sets delta values to zero on any error. */
+      FT_Get_Kerning(font->face, g_prev->idx, g->idx, FT_KERNING_UNSCALED, &delta);
+    }
+
+    /* 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)) {
+      font->kerning_cache->ascii_table[g->c][g_prev->c] = (int)delta.x;
+    }
 
-  if (delta.x != 0) {
-    /* Convert unscaled design units to pixels and move pen. */
-    return blf_unscaled_F26Dot6_to_pixels(font, delta.x);
+    if (delta.x != 0) {
+      /* Convert unscaled design units to pixels and move pen. */
+      adjustment += blf_unscaled_F26Dot6_to_pixels(font, delta.x);
+    }
   }
 
-  return 0;
+  return adjustment;
 }
 
 /** \} */
@@ -336,10 +331,10 @@ static void blf_font_draw_ex(FontBLF *font,
                              const char *str,
                              const size_t str_len,
                              struct ResultBLF *r_info,
-                             int pen_y)
+                             ft_pix pen_y)
 {
   GlyphBLF *g, *g_prev = NULL;
-  int pen_x = 0;
+  ft_pix pen_x = 0;
   size_t i = 0;
 
   if (str_len == 0) {
@@ -358,9 +353,9 @@ static void blf_font_draw_ex(FontBLF *font,
     pen_x += blf_kerning(font, g_prev, g);
 
     /* do not return this loop if clipped, we want every character tested */
-    blf_glyph_draw(font, gc, g, (float)pen_x, (float)pen_y);
+    blf_glyph_draw(font, gc, g, ft_pix_to_int_floor(pen_x), ft_pix_to_int_floor(pen_y));
 
-    pen_x += g->advance_i;
+    pen_x = ft_pix_round_advance(pen_x, g->advance_x);
     g_prev = g;
   }
 
@@ -368,7 +363,7 @@ static void blf_font_draw_ex(FontBLF *font,
 
   if (r_info) {
     r_info->lines = 1;
-    r_info->width = pen_x;
+    r_info->width = ft_pix_to_int(pen_x);
   }
 }
 void blf_font_draw(FontBLF *font, const char *str, const size_t str_len, struct ResultBLF *r_info)
@@ -382,7 +377,9 @@ int blf_font_draw_mono(FontBLF *font, const char *str, const size_t str_len, int
 {
   GlyphBLF *g;
   int col, columns = 0;
-  int pen_x = 0, pen_y = 0;
+  ft_pix pen_x = 0, pen_y = 0;
+  ft_pix cwidth_fpx = ft_pix_from_int(cwidth);
+
   size_t i = 0;
 
   GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
@@ -396,7 +393,7 @@ int blf_font_draw_mono(FontBLF *font, const char *str, const size_t str_len, int
       continue;
     }
     /* do not return this loop if clipped, we want every character tested */
-    blf_glyph_draw(font, gc, g, (float)pen_x, (float)pen_y);
+    blf_glyph_draw(font, gc, g, ft_pix_to_int_floor(pen_x), ft_pix_to_int_floor(pen_y));
 
     col = BLI_wcwidth((char32_t)g->c);
     if (col < 0) {
@@ -404,7 +401,7 @@ int blf_font_draw_mono(FontBLF *font, const char *str, const size_t str_len, int
     }
 
     columns += col;
-    pen_x += cwidth * col;
+    pen_x += cwidth_fpx * col;
   }
 
   blf_batch_draw_end();
@@ -425,11 +422,11 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
                                     const char *str,
                                     const size_t str_len,
                                     struct ResultBLF *r_info,
-                                    int pen_y)
+                                    ft_pix pen_y)
 {
   GlyphBLF *g, *g_prev = NULL;
-  int pen_x = (int)font->pos[0];
-  int pen_y_basis = (int)font->pos[1] + pen_y;
+  ft_pix pen_x = ft_pix_from_float(font->pos[0]);
+  ft_pix pen_y_basis = ft_pix_from_float(font->pos[1]) + pen_y;
   size_t i = 0;
 
   /* buffer specific vars */
@@ -449,18 +446,18 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
     }
     pen_x += blf_kerning(font, g_prev, g);
 
-    chx = pen_x + ((int)g->pos[0]);
-    chy = pen_y_basis + g->dims[1];
+    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 + (g->dims[1] - g->pos[1]);
+      pen_y = pen_y_basis + ft_pix_from_int(g->dims[1] - g->pos[1]);
     }
     else {
-      pen_y = pen_y_basis - (g->dims[1] - g->pos[1]);
+      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] && (pen_y + g->dims[1]) >= 0 &&
-        pen_y < buf_info->dims[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];
@@ -469,17 +466,20 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
       if (width_clip + chx > buf_info->dims[0]) {
         width_clip -= chx + width_clip - buf_info->dims[0];
       }
-      if (height_clip + pen_y > buf_info->dims[1]) {
-        height_clip -= pen_y + height_clip - buf_info->dims[1];
+      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) ? -pen_y : pen_y;
-        height_clip += pen_y;
+        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++) {
@@ -488,7 +488,7 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
             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 + y) * (size_t)buf_info->dims[0])) *
+                                       ((size_t)(pen_y_px + y) * (size_t)buf_info->dims[0])) *
                                       (size_t)buf_info->ch);
               float *fbuf = buf_info->fbuf + buf_ofs;
 
@@ -519,7 +519,7 @@ static void blf_font_draw_buffer_ex(FontBLF *font,
             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 + y) * (size_t)buf_info->dims[0])) *
+                             

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list