summaryrefslogtreecommitdiffstats
path: root/src/display/sp-canvas.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/display/sp-canvas.cpp')
-rw-r--r--src/display/sp-canvas.cpp120
1 files changed, 97 insertions, 23 deletions
diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp
index 7acd645c8..20ad27bf5 100644
--- a/src/display/sp-canvas.cpp
+++ b/src/display/sp-canvas.cpp
@@ -1123,25 +1123,42 @@ void SPCanvas::handle_get_preferred_height(GtkWidget *widget, gint *minimum_heig
void SPCanvas::handle_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
{
SPCanvas *canvas = SP_CANVAS (widget);
- GtkAllocation old_allocation;
+ // Allocation does not depend on device scale.
+ GtkAllocation old_allocation;
gtk_widget_get_allocation(widget, &old_allocation);
-// Geom::IntRect old_area = Geom::IntRect::from_xywh(canvas->_x0, canvas->_y0,
-// old_allocation.width, old_allocation.height);
+ // For HiDPI monitors.
+ canvas->_device_scale = gtk_widget_get_scale_factor( widget );
Geom::IntRect new_area = Geom::IntRect::from_xywh(canvas->_x0, canvas->_y0,
allocation->width, allocation->height);
- // resize backing store
+ // Resize backing store.
cairo_surface_t *new_backing_store = NULL;
#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0)
- if (canvas->_surface_for_similar != NULL)
- new_backing_store = cairo_surface_create_similar_image(canvas->_surface_for_similar,
- CAIRO_FORMAT_ARGB32, allocation->width, allocation->height);
+ if (canvas->_surface_for_similar != NULL) {
+
+ // Size in device pixels. Does not set device scale.
+ new_backing_store =
+ cairo_surface_create_similar_image(canvas->_surface_for_similar,
+ CAIRO_FORMAT_ARGB32,
+ allocation->width * canvas->_device_scale,
+ allocation->height * canvas->_device_scale);
+ }
#endif
- if (new_backing_store == NULL)
- new_backing_store = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation->width, allocation->height);
+ if (new_backing_store == NULL) {
+
+ // Size in device pixels. Does not set device scale.
+ new_backing_store =
+ cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+ allocation->width * canvas->_device_scale,
+ allocation->height * canvas->_device_scale);
+ }
+
+ // Set device scale
+ cairo_surface_set_device_scale(new_backing_store, canvas->_device_scale, canvas->_device_scale);
+
if (canvas->_backing_store) {
cairo_t *cr = cairo_create(new_backing_store);
cairo_translate(cr, -canvas->_x0, -canvas->_y0);
@@ -1521,7 +1538,6 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect
// Prevent crash if paintSingleBuffer is called before _backing_store is
// initialized.
-
if (_backing_store == NULL)
return;
@@ -1530,9 +1546,11 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect
buf.buf_rowstride = 0;
buf.rect = paint_rect;
buf.canvas_rect = canvas_rect;
+ buf.device_scale = _device_scale;
buf.is_empty = true;
// Make sure the following code does not go outside of _backing_store's data
+ // FIXME for device_scale.
assert(cairo_image_surface_get_format(_backing_store) == CAIRO_FORMAT_ARGB32);
assert(paint_rect.left() - _x0 >= 0);
assert(paint_rect.top() - _y0 >= 0);
@@ -1541,14 +1559,28 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect
// Create a temporary surface that draws directly to _backing_store
cairo_surface_flush(_backing_store);
+ // cairo_surface_write_to_png( _backing_store, "debug0.png" );
unsigned char *data = cairo_image_surface_get_data(_backing_store);
int stride = cairo_image_surface_get_stride(_backing_store);
+
+ // Check we are using correct device scale
+ double x_scale = 0;
+ double y_scale = 0;
+ cairo_surface_get_device_scale(_backing_store, &x_scale, &y_scale);
+ assert (_device_scale == (int)x_scale);
+ assert (_device_scale == (int)y_scale);
+
// Move to the right row
- data += stride * (paint_rect.top() - _y0);
+ data += stride * (paint_rect.top() - _y0) * (int)y_scale;
// Move to the right pixel inside of that row
- data += 4 * (paint_rect.left() - _x0);
- cairo_surface_t *imgs = cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32,
- paint_rect.width(), paint_rect.height(), stride);
+ data += 4 * (paint_rect.left() - _x0) * (int)x_scale;
+ cairo_surface_t *imgs =
+ cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32,
+ paint_rect.width() * _device_scale,
+ paint_rect.height() * _device_scale,
+ stride);
+ cairo_surface_set_device_scale(imgs, _device_scale, _device_scale);
+
buf.ct = cairo_create(imgs);
cairo_save(buf.ct);
@@ -1557,10 +1589,12 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect
cairo_set_operator(buf.ct, CAIRO_OPERATOR_SOURCE);
cairo_paint(buf.ct);
cairo_restore(buf.ct);
+ // cairo_surface_write_to_png( imgs, "debug1.png" );
if (_root->visible) {
SP_CANVAS_ITEM_GET_CLASS(_root)->render(_root, &buf);
}
+ // cairo_surface_write_to_png( imgs, "debug2.png" );
// output to X
cairo_destroy(buf.ct);
@@ -1590,6 +1624,7 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect
#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
cairo_surface_mark_dirty(_backing_store);
+ // cairo_surface_write_to_png( _backing_store, "debug3.png" );
// Mark the painted rectangle clean
markRect(paint_rect, 0);
@@ -1730,7 +1765,6 @@ bool SPCanvas::paintRect(int xx0, int yy0, int xx1, int yy1)
Geom::OptIntRect area = paint_rect & canvas_rect;
if (!area || area->hasZeroArea()) return 0;
-
paint_rect = *area;
PaintRectSetup setup;
@@ -1787,19 +1821,34 @@ void SPCanvas::endForcedFullRedraws()
}
gboolean SPCanvas::handle_draw(GtkWidget *widget, cairo_t *cr) {
+
SPCanvas *canvas = SP_CANVAS(widget);
#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0)
if (canvas->_surface_for_similar == NULL && canvas->_backing_store != NULL) {
- canvas->_surface_for_similar = cairo_surface_create_similar(
- cairo_get_target(cr), CAIRO_CONTENT_COLOR_ALPHA, 1, 1);
+
+ // Device scale is copied but since this is only created one time, we'll
+ // need to check/set device scale anytime it is used in case window moved
+ // to monitor with different scale.
+ canvas->_surface_for_similar =
+ cairo_surface_create_similar(cairo_get_target(cr), CAIRO_CONTENT_COLOR_ALPHA, 1, 1);
+
+ // Check we are using correct device scale
+ double x_scale = 0;
+ double y_scale = 0;
+ cairo_surface_get_device_scale(canvas->_backing_store, &x_scale, &y_scale);
+ assert (canvas->_device_scale == (int)x_scale);
+ assert (canvas->_device_scale == (int)y_scale);
// Reallocate backing store so that cairo can use shared memory
+ // Function does NOT copy device scale! Width and height are in device pixels.
cairo_surface_t *new_backing_store = cairo_surface_create_similar_image(
canvas->_surface_for_similar, CAIRO_FORMAT_ARGB32,
cairo_image_surface_get_width(canvas->_backing_store),
cairo_image_surface_get_height(canvas->_backing_store));
+ cairo_surface_set_device_scale(new_backing_store, canvas->_device_scale, canvas->_device_scale);
+
// Copy the old backing store contents
cairo_t *cr = cairo_create(new_backing_store);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
@@ -1824,6 +1873,7 @@ gboolean SPCanvas::handle_draw(GtkWidget *widget, cairo_t *cr) {
cairo_rectangle_t rectangle = rects->rectangles[i];
Geom::Rect dr = Geom::Rect::from_xywh(rectangle.x + canvas->_x0, rectangle.y + canvas->_y0,
rectangle.width, rectangle.height);
+
Geom::IntRect ir = dr.roundOutwards();
cairo_rectangle_int_t irect = { ir.left(), ir.top(), ir.width(), ir.height() };
cairo_region_union_rectangle(dirty_region, &irect);
@@ -1837,7 +1887,7 @@ gboolean SPCanvas::handle_draw(GtkWidget *widget, cairo_t *cr) {
}
cairo_region_destroy(dirty_region);
- return TRUE;
+ return TRUE;
}
gint SPCanvas::handle_key_event(GtkWidget *widget, GdkEventKey *event)
@@ -1979,7 +2029,11 @@ SPCanvasGroup *SPCanvas::getRoot()
*/
void SPCanvas::scrollTo( Geom::Point const &c, unsigned int clear, bool is_scrolling)
{
- GtkAllocation allocation;
+ // To do: extract out common code with SPCanvas::handle_size_allocate()
+
+ // For HiDPI monitors
+ int device_scale = gtk_widget_get_scale_factor(GTK_WIDGET(this));
+ assert( device_scale == _device_scale);
double cx = c[Geom::X];
double cy = c[Geom::Y];
@@ -1992,18 +2046,34 @@ void SPCanvas::scrollTo( Geom::Point const &c, unsigned int clear, bool is_scrol
Geom::IntRect old_area = getViewboxIntegers();
Geom::IntRect new_area = old_area + Geom::IntPoint(dx, dy);
+ GtkAllocation allocation;
gtk_widget_get_allocation(&_widget, &allocation);
- // adjust backing store contents
+ // Adjust backing store contents
assert(_backing_store);
+
cairo_surface_t *new_backing_store = NULL;
#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0)
if (_surface_for_similar != NULL)
- new_backing_store = cairo_surface_create_similar_image(
- _surface_for_similar, CAIRO_FORMAT_ARGB32, allocation.width, allocation.height);
+
+ // Size in device pixels. Does not set device scale.
+ new_backing_store =
+ cairo_surface_create_similar_image(_surface_for_similar,
+ CAIRO_FORMAT_ARGB32,
+ allocation.width * _device_scale,
+ allocation.height * _device_scale);
#endif
if (new_backing_store == NULL)
- new_backing_store = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation.width, allocation.height);
+
+ // Size in device pixels. Does not set device scale.
+ new_backing_store =
+ cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+ allocation.width * _device_scale,
+ allocation.height * _device_scale);
+
+ // Set device scale
+ cairo_surface_set_device_scale(new_backing_store, _device_scale, _device_scale);
+
cairo_t *cr = cairo_create(new_backing_store);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
// Paint the background
@@ -2011,6 +2081,8 @@ void SPCanvas::scrollTo( Geom::Point const &c, unsigned int clear, bool is_scrol
cairo_set_source(cr, _background);
cairo_paint(cr);
+ // cairo_surface_write_to_png( _backing_store, "scroll0.png" );
+
// Copy the old backing store contents
cairo_set_source_surface(cr, _backing_store, _x0, _y0);
cairo_rectangle(cr, _x0, _y0, allocation.width, allocation.height);
@@ -2020,6 +2092,8 @@ void SPCanvas::scrollTo( Geom::Point const &c, unsigned int clear, bool is_scrol
cairo_surface_destroy(_backing_store);
_backing_store = new_backing_store;
+ // cairo_surface_write_to_png( _backing_store, "scroll1.png" );
+
_dx0 = cx; // here the 'd' stands for double, not delta!
_dy0 = cy;
_x0 = ix;