GtkWidget's Pango matrix is incorrect on hidpi

Hi fellows.

There’s a bug in GTK3 bug tracker on GNOME’s gitlab.

https://gitlab.gnome.org/GNOME/gtk/issues/818

Essentially it’s about 1 px error mean when doing pango layouts under 2x desktop scaling. Which gives most of the text GTK draws look wanky.

I was hoping to dive in and try to do my best at fixing it but honestly had no idea where to start yet. I did some digging through codebase but to no luck yet.

  • Is it worth fixing? Would be great if someone gave me some suggestions then.
  • Shouldn’t the issue be remedied by coming subpixel font rendering support in cairo?
  • Or maybe my best bet is just to patiently wait for the advent of GTK4?

It would be great to get any feedback. Should I supply more details? Do I need to provide some steps to reproduce?

Hi! I don’t know if I can be of any help, but I will take a look at it tomorrow

1 Like

Hi! I was able to proceed further on this. You can take a look at this small C sample based only on pangocairo that exhibits the problem. This code shows what Gtk3 does internally. The integer scaling factor (gdk_scale) is set on the CairoSurface with cairo_surface_set_device_scale. The text scaling factor (gdk_dpi_scale) instead is set on the PangoCairoContext using pango_cairo_context_set_resolution. You can compile and run the following snippet and see the output.png file:

/* 
 * FILE:     test_pango.c
 * COMMENTS: compile with: gcc -o test_pango test_pango.c $(pkg-config --cflags --libs pangocairo)
 */

#include <pango/pangocairo.h>

const int gdk_scale = 5;
const double gdk_dpi_scale = 1.0 / 5.0;

void draw_text (cairo_t *cr) {
  PangoFontMap *font_map = pango_cairo_font_map_get_default ();
  PangoContext *pango_cairo_context = pango_font_map_create_context (font_map);

  pango_cairo_context_set_resolution (pango_cairo_context, 96.0 * gdk_dpi_scale);

  PangoLayout *pango_layout = pango_layout_new (pango_cairo_context);
  pango_layout_set_text (pango_layout, "Hello, world", -1);

  PangoFontDescription *pango_font = pango_font_description_from_string ("Segoe UI 9");
  pango_layout_set_font_description (pango_layout, pango_font);

  pango_cairo_show_layout (cr, pango_layout);

  pango_font_description_free (pango_font);
  g_object_unref (pango_layout);
  g_object_unref (pango_cairo_context);
}

void clear_to_white_background (cairo_t *cr) {
  cairo_rectangle (cr, 0, 0, 500, 100);
  cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
  cairo_fill (cr);
  cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
}

int main () {
  cairo_surface_t *surface;
  cairo_t         *cr;

  surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 500, 100);
  cr = cairo_create (surface);

  clear_to_white_background (cr);

  cairo_surface_set_device_scale (surface, gdk_scale, gdk_scale);
  draw_text (cr);
  cairo_surface_write_to_png (surface, "output.png");

  cairo_destroy (cr);
  cairo_surface_destroy (surface);
  return 0;
}

Using both cairo_surface_set_device_scale and pango_cairo_context_set_resolution causes a bad interaction. I don’t know if it is a sign of a problem in Pango or if we are instead ‘abusing’ the APIs (and asking for troubles) :slight_smile:

Wow, great insight, I’m sure that you’re onto something here!

Good question. Personally I’m inclined to think of it as a bug more than as an abuse, because there seem to be a loss of precision every time a cairo_surface_set_device_scale is used apparently, at least when dealing with pango. But in order to be sure to call it a bug I need some free time to look closely into gtk innards.