Partially fix #561: Hi-DPI-aware rendering of images.
authorZoltan Ivanfi <zivanfi@apache.org>
Thu, 28 Dec 2017 18:32:22 +0000 (19:32 +0100)
committerZoltan Ivanfi <zivanfi@apache.org>
Wed, 3 Jan 2018 10:06:47 +0000 (11:06 +0100)
Displayed images are no longer blurry on Hi-DPI displays, nor they have a grid
artifact any more.

Image overlays and thumbnails are not addresset yet and are still blurry.

src/renderer-tiles.c

index 9279270..efffba0 100644 (file)
@@ -147,6 +147,7 @@ struct _RendererTiles
        gint x_scroll;  /* allow local adjustment and mirroring */
        gint y_scroll;
 
+       gint hidpi_scale;
 };
 
 
@@ -499,6 +500,25 @@ static gint pixmap_calc_size(cairo_surface_t *surface)
        return PR_TILE_SIZE * PR_TILE_SIZE * 4 / 8;
 }
 
+static void rt_hidpi_aware_draw(
+       RendererTiles *rt,
+       cairo_t *cr,
+       GdkPixbuf *pixbuf,
+       double x,
+       double y)
+{
+#if GTK_CHECK_VERSION(3, 10, 0)
+       cairo_surface_t *surface;
+       surface = gdk_cairo_surface_create_from_pixbuf(pixbuf, rt->hidpi_scale, NULL);
+       cairo_set_source_surface(cr, surface, x, y);
+       cairo_fill(cr);
+       cairo_surface_destroy(surface);
+#else
+       gdk_cairo_set_source_pixbuf(cr, pixbuf, x, y);
+       cairo_fill(cr);
+#endif
+}
+
 static void rt_tile_prepare(RendererTiles *rt, ImageTile *it)
 {
        PixbufRenderer *pr = rt->pr;
@@ -511,7 +531,7 @@ static void rt_tile_prepare(RendererTiles *rt, ImageTile *it)
                                                            CAIRO_CONTENT_COLOR,
                                                            rt->tile_width, rt->tile_height);
 
-               size = pixmap_calc_size(surface);
+               size = pixmap_calc_size(surface) * rt->hidpi_scale * rt->hidpi_scale;
                rt_tile_free_space(rt, size, it);
 
                it->surface = surface;
@@ -523,9 +543,9 @@ static void rt_tile_prepare(RendererTiles *rt, ImageTile *it)
                {
                GdkPixbuf *pixbuf;
                guint size;
-               pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, rt->tile_width, rt->tile_height);
+               pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, rt->hidpi_scale * rt->tile_width, rt->hidpi_scale * rt->tile_height);
 
-               size = gdk_pixbuf_get_rowstride(pixbuf) * rt->tile_height;
+               size = gdk_pixbuf_get_rowstride(pixbuf) * rt->tile_height * rt->hidpi_scale;
                rt_tile_free_space(rt, size, it);
 
                it->pixbuf = pixbuf;
@@ -623,7 +643,7 @@ static void rt_overlay_draw(RendererTiles *rt, gint x, gint y, gint w, gint h,
                                cairo_fill_preserve(cr);
 
                                gdk_cairo_set_source_pixbuf(cr, od->pixbuf, px - rx, py - ry);
-                               cairo_fill (cr);
+                               cairo_fill(cr);
                                cairo_destroy (cr);
 
                                cr = gdk_cairo_create(od->window);
@@ -881,7 +901,7 @@ static void rt_hierarchy_changed_cb(GtkWidget *widget, GtkWidget *previous_tople
 
 static GdkPixbuf *rt_get_spare_tile(RendererTiles *rt)
 {
-       if (!rt->spare_tile) rt->spare_tile = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, rt->tile_width, rt->tile_height);
+       if (!rt->spare_tile) rt->spare_tile = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, rt->tile_width * rt->hidpi_scale, rt->tile_height * rt->hidpi_scale);
        return rt->spare_tile;
 }
 
@@ -896,7 +916,7 @@ static void rt_tile_rotate_90_clockwise(RendererTiles *rt, GdkPixbuf **tile, gin
        guchar *sp, *dp;
        guchar *ip, *spi, *dpi;
        gint i, j;
-       gint tw = rt->tile_width;
+       gint tw = rt->tile_width * rt->hidpi_scale;
 
        srs = gdk_pixbuf_get_rowstride(src);
        s_pix = gdk_pixbuf_get_pixels(src);
@@ -932,7 +952,7 @@ static void rt_tile_rotate_90_counter_clockwise(RendererTiles *rt, GdkPixbuf **t
        guchar *sp, *dp;
        guchar *ip, *spi, *dpi;
        gint i, j;
-       gint th = rt->tile_height;
+       gint th = rt->tile_height * rt->hidpi_scale;
 
        srs = gdk_pixbuf_get_rowstride(src);
        s_pix = gdk_pixbuf_get_pixels(src);
@@ -969,7 +989,7 @@ static void rt_tile_mirror_only(RendererTiles *rt, GdkPixbuf **tile, gint x, gin
        guchar *spi, *dpi;
        gint i, j;
 
-       gint tw = rt->tile_width;
+       gint tw = rt->tile_width * rt->hidpi_scale;
 
        srs = gdk_pixbuf_get_rowstride(src);
        s_pix = gdk_pixbuf_get_pixels(src);
@@ -1005,8 +1025,8 @@ static void rt_tile_mirror_and_flip(RendererTiles *rt, GdkPixbuf **tile, gint x,
        guchar *sp, *dp;
        guchar *dpi;
        gint i, j;
-       gint tw = rt->tile_width;
-       gint th = rt->tile_height;
+       gint tw = rt->tile_width * rt->hidpi_scale;
+       gint th = rt->tile_height * rt->hidpi_scale;
 
        srs = gdk_pixbuf_get_rowstride(src);
        s_pix = gdk_pixbuf_get_pixels(src);
@@ -1041,7 +1061,7 @@ static void rt_tile_flip_only(RendererTiles *rt, GdkPixbuf **tile, gint x, gint
        guchar *sp, *dp;
        guchar *spi, *dpi;
        gint i;
-       gint th = rt->tile_height;
+       gint th = rt->tile_height * rt->hidpi_scale;
 
        srs = gdk_pixbuf_get_rowstride(src);
        s_pix = gdk_pixbuf_get_pixels(src);
@@ -1150,12 +1170,12 @@ static gboolean rt_source_tile_render(RendererTiles *rt, ImageTile *it,
                                if (st->blank)
                                        {
                                        cairo_set_source_rgb(cr, 0, 0, 0);
+                                       cairo_fill (cr);
                                        }
                                else /* (pr->zoom == 1.0 || pr->scale == 1.0) */
                                        {
-                                       gdk_cairo_set_source_pixbuf(cr, st->pixbuf, -it->x + st->x, -it->y + st->y);
+                                       rt_hidpi_aware_draw(rt, cr, st->pixbuf, -it->x + st->x, -it->y + st->y);
                                        }
-                               cairo_fill (cr);
                                cairo_destroy (cr);
                                }
                        }
@@ -1356,8 +1376,8 @@ static void rt_tile_render(RendererTiles *rt, ImageTile *it,
 
                if (pr->image_width == 0 || pr->image_height == 0) return;
 
-               scale_x = (gdouble)pr->width / pr->image_width;
-               scale_y = (gdouble)pr->height / pr->image_height;
+               scale_x = rt->hidpi_scale * (gdouble)pr->width / pr->image_width;
+               scale_y = rt->hidpi_scale * (gdouble)pr->height / pr->image_height;
 
                pr_tile_coords_map_orientation(orientation, it->x, it->y,
                                            pr->width, pr->height,
@@ -1369,6 +1389,13 @@ static void rt_tile_render(RendererTiles *rt, ImageTile *it,
                                            &pb_x, &pb_y,
                                            &pb_w, &pb_h);
 
+               src_x *= rt->hidpi_scale;
+               src_y *= rt->hidpi_scale;
+               pb_x *= rt->hidpi_scale;
+               pb_y *= rt->hidpi_scale;
+               pb_w *= rt->hidpi_scale;
+               pb_h *= rt->hidpi_scale;
+
                switch (orientation)
                        {
                        gdouble tmp;
@@ -1424,8 +1451,7 @@ static void rt_tile_render(RendererTiles *rt, ImageTile *it,
 
                cr = cairo_create(it->surface);
                cairo_rectangle (cr, x, y, w, h);
-               gdk_cairo_set_source_pixbuf(cr, it->pixbuf, 0, 0);
-               cairo_fill (cr);
+               rt_hidpi_aware_draw(rt, cr, it->pixbuf, 0, 0);
                cairo_destroy (cr);
                }
 }
@@ -2164,6 +2190,12 @@ RendererFuncs *renderer_tiles_new(PixbufRenderer *pr)
        rt->stereo_off_x = 0;
        rt->stereo_off_y = 0;
 
+#if GTK_CHECK_VERSION(3, 10, 0)
+       rt->hidpi_scale = gtk_widget_get_scale_factor(GTK_WIDGET(rt->pr));
+#else
+       rt->hidpi_scale = 1;
+#endif
+
        g_signal_connect(G_OBJECT(pr), "hierarchy-changed",
                         G_CALLBACK(rt_hierarchy_changed_cb), rt);
 
@@ -2174,6 +2206,7 @@ RendererFuncs *renderer_tiles_new(PixbufRenderer *pr)
        g_signal_connect(G_OBJECT(pr), "expose_event",
                         G_CALLBACK(rt_expose_cb), rt);
 #endif
+
        return (RendererFuncs *) rt;
 }