From c6659c9a29ae4299736a5e4de627cc8e105bd40b Mon Sep 17 00:00:00 2001 From: ManoloFLTK <41016272+ManoloFLTK@users.noreply.github.com> Date: Wed, 6 Jul 2022 10:05:00 +0200 Subject: 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(-) (limited to 'src') diff --git a/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H b/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H index dfe67535e..255027e59 100644 --- a/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H +++ b/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 a/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx b/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx index 89b2622df..a8f5d90a2 100644 --- a/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx +++ b/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; } // -- cgit v1.2.3