FLTK logo

[master] c6659c9 - Fl_Cairo_Graphics_Driver: fix issues in string width computations when scaling applies.

FLTK matrix user chat room
(using Element browser app)   FLTK gitter user chat room   GitHub FLTK Project   FLTK News RSS Feed  
  FLTK Apps      FLTK Library      Forums      Links     Login 
 All Forums  |  Back to fltk.commit  ]
 
Previous Message ]Next Message ]

[master] c6659c9 - Fl_Cairo_Graphics_Driver: fix issues in string width computations when scaling applies. "ManoloFLTK" Jul 06, 2022  
 
commit c6659c9a29ae4299736a5e4de627cc8e105bd40b
Author:     ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>
AuthorDate: Wed Jul 6 10:05:00 2022 +0200
Commit:     ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com>
CommitDate: Wed Jul 6 10:05:00 2022 +0200

    Fl_Cairo_Graphics_Driver: fix issues in string width computations when scaling applies.
    
    The implemented approach is to create and use the pango_layout_ object only relatively
    to an unscaled cairo context. With this, the pixel width of a drawn string equals
    the sum of the widths of its characters.

 src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H   |  1 +
 src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx | 60 +++++++++++++++++---------
 2 files changed, 41 insertions(+), 20 deletions(-)

diff --git src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H
index dfe6753..255027e 100644
--- src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H
+++ src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H
@@ -45,6 +45,7 @@ private:
   cairo_t *pango_layout_cairo_;
   PangoLayout *pango_layout_;
   int linestyle_;
+  int width_unscaled_(unsigned int c);
 protected:
   cairo_t *cairo_;
 public:
diff --git src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx
index 89b2622..a8f5d90 100644
--- src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx
+++ src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx
@@ -939,12 +939,12 @@ void Fl_Cairo_Graphics_Driver::delete_bitmask(fl_uintptr_t bm) {
 
 int Fl_Cairo_Graphics_Driver::height() {
   if (!font_descriptor()) font(0, 12);
-  return ((Fl_Cairo_Font_Descriptor*)font_descriptor())->line_height;
+  return ceil(((Fl_Cairo_Font_Descriptor*)font_descriptor())->line_height /(PANGO_SCALE*scale()));
 }
 
 
 int Fl_Cairo_Graphics_Driver::descent() {
-  return font_descriptor()->descent;
+  return font_descriptor()->descent /(PANGO_SCALE*scale());
 }
 
 
@@ -1083,14 +1083,14 @@ Fl_Cairo_Font_Descriptor::Fl_Cairo_Font_Descriptor(const char* name, Fl_Fontsize
   static PangoLanguage *language = pango_language_get_default(); // 1.16
   PangoFontset *fontset = pango_font_map_load_fontset(def_font_map, pango_context, fontref, language);
   PangoFontMetrics *metrics = pango_fontset_get_metrics(fontset);
-  ascent = pango_font_metrics_get_ascent(metrics)/PANGO_SCALE;
-  descent = pango_font_metrics_get_descent(metrics)/PANGO_SCALE;
+  ascent = pango_font_metrics_get_ascent(metrics);
+  descent = pango_font_metrics_get_descent(metrics);
 #if PANGO_VERSION_CHECK(1,44,0)
-  line_height = ceil(pango_font_metrics_get_height(metrics)/double(PANGO_SCALE)); // 1.44
+  line_height = pango_font_metrics_get_height(metrics); // 1.44
 #else
-  line_height = int( (pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent(metrics)) * 1.025 / PANGO_SCALE + 0.5);
+  line_height = (pango_font_metrics_get_ascent(metrics) + pango_font_metrics_get_descent(metrics)) * 1.025 + 0.5;
 #endif
-  q_width = pango_font_metrics_get_approximate_char_width(metrics)/PANGO_SCALE;
+  q_width = 0; // useless;
   pango_font_metrics_unref(metrics);
   g_object_unref(fontset);
 //fprintf(stderr, "[%s](%d) ascent=%d descent=%d q_width=%d\n", name, size, ascent, descent, q_width);
@@ -1119,6 +1119,12 @@ static Fl_Font_Descriptor* find(Fl_Font fnum, Fl_Fontsize size) {
 }
 
 
+/* Implementation note :
+ * The pango_layout_ object is created relatively to the unscaled cairo context (scale() == 1).
+ * Therefore, the cairo context is unscaled before calling pango_cairo_create_layout(),
+ * pango_cairo_show_layout(), and pango_cairo_update_layout().
+ * This way, the pixel width of a drawn string equals the sum of the widths of its characters.
+ */
 void Fl_Cairo_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize s) {
   if (!font_descriptor()) fl_open_display();
   if (!pango_layout_) {
@@ -1128,13 +1134,19 @@ void Fl_Cairo_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize s) {
       cairo_ = cairo_create(surf);
       cairo_surface_destroy(surf);
     }
+    cairo_save(cairo_);
+    double f = scale(); cairo_scale(cairo_, 1/f, 1/f);
     pango_layout_ = pango_cairo_create_layout(cairo_); // 1.10
+    cairo_restore(cairo_);
     pango_layout_cairo_ = cairo_;
     if (needs_dummy) {
       dummy_cairo_ = cairo_;
     }
   } else if (pango_layout_cairo_ != cairo_) {
+    cairo_save(cairo_);
+    double f = scale(); cairo_scale(cairo_, 1/f, 1/f);
     pango_cairo_update_layout(cairo_, pango_layout_);
+    cairo_restore(cairo_);
     pango_layout_cairo_ = cairo_;
   }
   if (s == 0) return;
@@ -1144,7 +1156,7 @@ void Fl_Cairo_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize s) {
     return;
   }
   Fl_Graphics_Driver::font(fnum, s);
-  font_descriptor( find(fnum, s) );
+  font_descriptor( find(fnum, int(s * scale() + 0.5)) );
   pango_layout_set_font_description(pango_layout_, ((Fl_Cairo_Font_Descriptor*)font_descriptor())->fontref);
 }
 
@@ -1154,6 +1166,7 @@ void Fl_Cairo_Graphics_Driver::draw(const char* str, int n, float x, float y) {
   cairo_save(cairo_);
   // The -0.5 below makes underscores visible in Fl_Text_Display at scale = 1
   cairo_translate(cairo_, x, y - height() + descent() -0.5);
+  float s = scale(); cairo_scale(cairo_, 1/s, 1/s);
   pango_layout_set_text(pango_layout_, str, n);
   pango_cairo_show_layout(cairo_, pango_layout_);
   cairo_restore(cairo_);
@@ -1185,13 +1198,18 @@ double Fl_Cairo_Graphics_Driver::width(const char* c, int n) {
   while (i < n) {
     ucs = fl_utf8decode(c + i, end, &l);
     i += l;
-    w += width(ucs);
+    w += width_unscaled_(ucs);
   }
-  return (double)w;
+  return w/(PANGO_SCALE*scale());
 }
 
 
 double Fl_Cairo_Graphics_Driver::width(unsigned int c) {
+  return width_unscaled_(c)/(PANGO_SCALE*scale());
+}
+
+
+int Fl_Cairo_Graphics_Driver::width_unscaled_(unsigned int c) {
   unsigned int r = 0;
   Fl_Cairo_Font_Descriptor *desc = NULL;
   if (c <= 0xFFFF) { // when inside basic multilingual plane
@@ -1206,28 +1224,30 @@ double Fl_Cairo_Graphics_Driver::width(unsigned int c) {
       for (int i = 0; i < 0x0400; i++) desc->width[r][i] = -1;
     } else {
       if ( desc->width[r][c & 0x03FF] >= 0 ) { // already cached
-        return (double) desc->width[r][c & 0x03FF];
+        return desc->width[r][c & 0x03FF];
       }
     }
   }
   char buf[4];
   int n = fl_utf8encode(c, buf);
   pango_layout_set_text(pango_layout_, buf, n);
-  int  W = 0, H;
-  pango_layout_get_pixel_size(pango_layout_, &W, &H);
-  if (c <= 0xFFFF) desc->width[r][c & 0x03FF] = W;
-  return (double)W;
+  PangoRectangle p_rect;
+  pango_layout_get_extents(pango_layout_, NULL, &p_rect);
+  if (c <= 0xFFFF) desc->width[r][c & 0x03FF] = p_rect.width;
+  return p_rect.width;
 }
 
 
 void Fl_Cairo_Graphics_Driver::text_extents(const char* txt, int n, int& dx, int& dy, int& w, int& h) {
   pango_layout_set_text(pango_layout_, txt, n);
   PangoRectangle ink_rect;
-  pango_layout_get_pixel_extents(pango_layout_, &ink_rect, NULL);
-  dx = ink_rect.x;
-  dy = ink_rect.y - height() + descent();
-  w = ink_rect.width;
-  h = ink_rect.height;
+  pango_layout_get_extents(pango_layout_, &ink_rect, NULL);
+  float f = PANGO_SCALE * scale();
+  Fl_Cairo_Font_Descriptor *fd = (Fl_Cairo_Font_Descriptor*)font_descriptor();
+  dx = ink_rect.x / f;
+  dy = (ink_rect.y - fd->line_height + fd->descent) / f;
+  w = ink_rect.width / f;
+  h = ink_rect.height / f;
 }
 
 //
Direct Link to Message ]
 
     
Previous Message ]Next Message ]
 
 

Comments are owned by the poster. All other content is copyright 1998-2024 by Bill Spitzak and others. This project is hosted by The FLTK Team. Please report site problems to 'erco@seriss.com'.