summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTavmjong Bah <tavmjong@free.fr>2017-11-23 15:07:25 +0000
committerTavmjong Bah <tavmjong@free.fr>2017-11-23 15:07:25 +0000
commit43665505e7f75cbacb303e542771507b58f1a12e (patch)
tree88c09db558dfa9fa1455348ff31eab5bdd5e0d4c /src
parenttypo (diff)
downloadinkscape-43665505e7f75cbacb303e542771507b58f1a12e.tar.gz
inkscape-43665505e7f75cbacb303e542771507b58f1a12e.zip
First attempt at supporting HiDPI on canvas.
Rendering seems to work but has not been fully tested. Editting does not work.
Diffstat (limited to 'src')
-rw-r--r--src/display/drawing-item.cpp25
-rw-r--r--src/display/drawing-surface.cpp49
-rw-r--r--src/display/drawing-surface.h8
-rw-r--r--src/display/sp-canvas.cpp169
4 files changed, 218 insertions, 33 deletions
diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp
index 43db4f259..a9408e4b0 100644
--- a/src/display/drawing-item.cpp
+++ b/src/display/drawing-item.cpp
@@ -667,7 +667,7 @@ struct MaskLuminanceToAlpha {
/**
* Rasterize items.
- * This method submits the drawing opeartions required to draw this item
+ * This method submits the drawing operations required to draw this item
* to the supplied DrawingContext, restricting drawing the specified area.
*
* This method does some common tasks and calls the item-specific rendering
@@ -678,6 +678,15 @@ struct MaskLuminanceToAlpha {
unsigned
DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flags, DrawingItem *stop_at)
{
+ std::cout << "\nDrawingItem::render:" << std::endl;
+ std::cout << " area: " << area << std::endl;
+ if (_drawbox)
+ std::cout << " _drawbox: " << *_drawbox << std::endl;
+ else
+ std::cout << " No _drawbox" << std::endl;
+ std::cout << " Surface: width: " << cairo_image_surface_get_width(dc.rawTarget())
+ << " height: " << cairo_image_surface_get_height(dc.rawTarget()) << std::endl;
+
bool outline = _drawing.outline();
bool render_filters = _drawing.renderFilters();
@@ -698,6 +707,11 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag
// carea is the area to paint
Geom::OptIntRect carea = Geom::intersect(area, _drawbox);
if (!carea) return RENDER_OK;
+ std::cout << " carea: " << *carea << std::endl;
+
+ // Device scale for HiDPI screens (either 1 or 2)
+ int device_scale = dc.surface()->device_scale();
+ std::cout << "DrawingItem::render: device_scale: " << device_scale << std::endl;
switch(_antialias){
case 0:
@@ -731,7 +745,7 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag
Geom::OptIntRect cl = _drawing.cacheLimit();
cl.intersectWith(_drawbox);
if (cl) {
- _cache = new DrawingCache(*cl);
+ _cache = new DrawingCache(*cl, device_scale);
}
}
} else {
@@ -770,6 +784,7 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag
// filters and opacity do not apply when rendering the ancestors of the filtered
// element
if ((flags & RENDER_FILTER_BACKGROUND) || !needs_intermediate_rendering) {
+ std::cout << " short-circuit!" << std::endl;
return _renderItem(dc, *carea, flags & ~RENDER_FILTER_BACKGROUND, stop_at);
}
@@ -785,7 +800,8 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag
iarea.intersectWith(_drawbox);
}
- DrawingSurface intermediate(*iarea);
+ std::cout << " intermediate area required! Device scale: " << device_scale << std::endl;
+ DrawingSurface intermediate(*iarea, device_scale);
DrawingContext ict(intermediate);
unsigned render_result = RENDER_OK;
@@ -832,7 +848,7 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag
if (bg_root->_background_new) break;
}
if (bg_root) {
- DrawingSurface bg(*iarea);
+ DrawingSurface bg(*iarea, device_scale);
DrawingContext bgdc(bg);
bg_root->render(bgdc, *iarea, flags | RENDER_FILTER_BACKGROUND, this);
_filter->render(this, ict, &bgdc);
@@ -854,6 +870,7 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag
// 6. Paint the completed rendering onto the base context (or into cache)
if (_cached && _cache) {
+ std::cout << " cache!!!!!!!!!!!!!!" << std::endl;
DrawingContext cachect(*_cache);
cachect.rectangle(*carea);
cachect.setOperator(CAIRO_OPERATOR_SOURCE);
diff --git a/src/display/drawing-surface.cpp b/src/display/drawing-surface.cpp
index d2540de66..fe7a1bf74 100644
--- a/src/display/drawing-surface.cpp
+++ b/src/display/drawing-surface.cpp
@@ -41,12 +41,15 @@ using Geom::Y;
* When a drawing context is created for this surface, its pixels
* will cover the area under the given rectangle.
*/
-DrawingSurface::DrawingSurface(Geom::IntRect const &area)
+DrawingSurface::DrawingSurface(Geom::IntRect const &area, int device_scale)
: _surface(NULL)
, _origin(area.min())
, _scale(1, 1)
, _pixels(area.dimensions())
-{}
+ , _device_scale(device_scale)
+{
+ std::cout << "DrawingSurface::DrawingSurface() 1" << std::endl;
+}
/**
* Creates a surface with the given logical and physical extents.
@@ -56,12 +59,15 @@ DrawingSurface::DrawingSurface(Geom::IntRect const &area)
* @param logbox Logical extents of the surface
* @param pixdims Pixel dimensions of the surface.
*/
-DrawingSurface::DrawingSurface(Geom::Rect const &logbox, Geom::IntPoint const &pixdims)
+DrawingSurface::DrawingSurface(Geom::Rect const &logbox, Geom::IntPoint const &pixdims, int device_scale)
: _surface(NULL)
, _origin(logbox.min())
, _scale(pixdims[X] / logbox.width(), pixdims[Y] / logbox.height())
, _pixels(pixdims)
-{}
+ , _device_scale(device_scale)
+{
+ std::cout << "DrawingSurface::DrawingSurface() 2" << std::endl;
+}
/**
* Wrap a cairo_surface_t.
@@ -73,9 +79,23 @@ DrawingSurface::DrawingSurface(cairo_surface_t *surface, Geom::Point const &orig
, _origin(origin)
, _scale(1, 1)
{
+ std::cout << "DrawingSurface::DrawingSurface() 3" << std::endl;
cairo_surface_reference(surface);
- _pixels[X] = cairo_image_surface_get_width(surface);
- _pixels[Y] = cairo_image_surface_get_height(surface);
+
+ double x_scale = 0;
+ double y_scale = 0;
+ cairo_surface_get_device_scale( surface, &x_scale, &y_scale);
+ if (x_scale != y_scale) {
+ std::cerr << "DrawingSurface::DrawingSurface: non-uniform device scale!" << std::endl;
+ }
+ _device_scale = x_scale;
+ if (_device_scale != 1 && _device_scale != 2) {
+ std::cerr << "DrawingSurface::DrawingSurface: device scale not 1 or 2! ("
+ << _device_scale << ")" << std::endl;
+ }
+
+ _pixels[X] = cairo_image_surface_get_width(surface)/_device_scale;
+ _pixels[Y] = cairo_image_surface_get_height(surface)/_device_scale;
}
DrawingSurface::~DrawingSurface()
@@ -119,6 +139,13 @@ DrawingSurface::scale() const
return _scale;
}
+/// Device scale for HiDPI screens
+int
+DrawingSurface::device_scale() const
+{
+ return _device_scale;
+}
+
/// Get the transformation applied to the drawing context on construction.
Geom::Affine
DrawingSurface::drawingTransform() const
@@ -153,7 +180,11 @@ DrawingSurface::createRawContext()
{
// deferred allocation
if (!_surface) {
- _surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, _pixels[X], _pixels[Y]);
+ _surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+ _pixels[X] * _device_scale,
+ _pixels[Y] * _device_scale);
+ std::cout << "DrawingSurface::createRawContext() Entrance" << std::endl;
+ cairo_surface_set_device_scale(_surface, _device_scale, _device_scale);
}
cairo_t *ct = cairo_create(_surface);
if (_scale != Geom::Scale::identity()) {
@@ -172,8 +203,8 @@ DrawingSurface::pixelArea() const
//////////////////////////////////////////////////////////////////////////////
-DrawingCache::DrawingCache(Geom::IntRect const &area)
- : DrawingSurface(area)
+DrawingCache::DrawingCache(Geom::IntRect const &area, int device_scale)
+ : DrawingSurface(area, device_scale)
, _clean_region(cairo_region_create())
, _pending_area(area)
{}
diff --git a/src/display/drawing-surface.h b/src/display/drawing-surface.h
index 78471649a..569964721 100644
--- a/src/display/drawing-surface.h
+++ b/src/display/drawing-surface.h
@@ -29,8 +29,8 @@ class DrawingContext;
class DrawingSurface
{
public:
- explicit DrawingSurface(Geom::IntRect const &area);
- DrawingSurface(Geom::Rect const &logbox, Geom::IntPoint const &pixdims);
+ explicit DrawingSurface(Geom::IntRect const &area, int device_scale = 1);
+ DrawingSurface(Geom::Rect const &logbox, Geom::IntPoint const &pixdims, int device_scale = 1);
DrawingSurface(cairo_surface_t *surface, Geom::Point const &origin);
virtual ~DrawingSurface();
@@ -39,6 +39,7 @@ public:
Geom::Point dimensions() const;
Geom::Point origin() const;
Geom::Scale scale() const;
+ int device_scale() const;
Geom::Affine drawingTransform() const;
cairo_surface_type_t type() const;
void dropContents();
@@ -53,6 +54,7 @@ protected:
Geom::Point _origin;
Geom::Scale _scale;
Geom::IntPoint _pixels;
+ int _device_scale; // To support HiDPI screens
bool _has_context;
friend class DrawingContext;
@@ -62,7 +64,7 @@ class DrawingCache
: public DrawingSurface
{
public:
- explicit DrawingCache(Geom::IntRect const &area);
+ explicit DrawingCache(Geom::IntRect const &area, int device_scale = 1);
~DrawingCache();
void markDirty(Geom::IntRect const &area = Geom::IntRect::infinite());
diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp
index 7acd645c8..845ee8e78 100644
--- a/src/display/sp-canvas.cpp
+++ b/src/display/sp-canvas.cpp
@@ -862,6 +862,10 @@ double SPCanvasGroup::point(SPCanvasItem *item, Geom::Point p, SPCanvasItem **ac
void SPCanvasGroup::render(SPCanvasItem *item, SPCanvasBuf *buf)
{
+ std::cout << "SPCanvasGroup::render: " << buf->rect << std::endl;
+ std::cout << " width: " << cairo_image_surface_get_width( cairo_get_target(buf->ct) )
+ << " height: " << cairo_image_surface_get_height( cairo_get_target(buf->ct) ) << std::endl;
+
SPCanvasGroup const *group = SP_CANVAS_GROUP(item);
for (std::list<SPCanvasItem *>::const_iterator it = group->items.begin(); it != group->items.end(); ++it) {
@@ -877,6 +881,7 @@ void SPCanvasGroup::render(SPCanvasItem *item, SPCanvasBuf *buf)
}
}
}
+ std::cout << "SPCanvasGroup::render: Exit" << std::endl;
}
void SPCanvasGroup::viewboxChanged(SPCanvasItem *item, Geom::IntRect const &new_area)
@@ -1122,26 +1127,67 @@ void SPCanvas::handle_get_preferred_height(GtkWidget *widget, gint *minimum_heig
void SPCanvas::handle_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
{
+ std::cout << "\nSPCanvas::handle_size_allocate()" << std::endl;
+
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);
+ // For HiDPI monitors.
+ int device_scale = gtk_widget_get_scale_factor( widget );
+ std::cout << " Gtk::device_scale: " << device_scale << std::endl;
+
// Geom::IntRect old_area = Geom::IntRect::from_xywh(canvas->_x0, canvas->_y0,
// old_allocation.width, old_allocation.height);
Geom::IntRect new_area = Geom::IntRect::from_xywh(canvas->_x0, canvas->_y0,
allocation->width, allocation->height);
- // resize backing store
+ // Resize backing store.
+ double scale_x = 0;
+ double scale_y = 0;
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) {
+
+ // Debug
+ cairo_surface_get_device_scale(canvas->_surface_for_similar, &scale_x, &scale_y);
+ std::cout << " _surface_for_similar != NULL: scale: x: " << scale_x << ", y: " << scale_y
+ << std::endl;
+
+ // 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 * device_scale,
+ allocation->height * device_scale);
+ cairo_surface_get_device_scale(new_backing_store, &scale_x, &scale_y);
+ std::cout << " new_backing_store: A scale: x: " << scale_x << ", y: " << scale_y
+ << std::endl;
+ }
#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) {
+ std::cout << " _surface_for_similar == NULL && new_backing_store == NULL" << std::endl;
+
+ // 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);
+ }
+
+ cairo_surface_get_device_scale(new_backing_store, &scale_x, &scale_y);
+ std::cout << " new_backing_store: B scale: x: " << scale_x << ", y: " << scale_y
+ << std::endl;
+
+ cairo_surface_set_device_scale(new_backing_store, device_scale, device_scale);
+ cairo_surface_get_device_scale(new_backing_store, &scale_x, &scale_y);
+ std::cout << " new_backing_store: C scale: x: " << scale_x << ", y: " << scale_y
+ << std::endl;
+
if (canvas->_backing_store) {
cairo_t *cr = cairo_create(new_backing_store);
cairo_translate(cr, -canvas->_x0, -canvas->_y0);
@@ -1518,7 +1564,12 @@ int SPCanvas::handle_motion(GtkWidget *widget, GdkEventMotion *event)
void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect const &canvas_rect, int /*sw*/)
{
-
+ std::cout << "\nSPCanvas::paintSingleBuffer:"
+ << "\n paint_rect: " << paint_rect
+ << "\n canvas_rect: " << canvas_rect
+ << std::endl;
+ std::cout << " _backing_store: width: " << cairo_image_surface_get_width(_backing_store)
+ << " height: " << cairo_image_surface_get_height(_backing_store) << std::endl;
// Prevent crash if paintSingleBuffer is called before _backing_store is
// initialized.
@@ -1533,6 +1584,7 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect
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 +1593,29 @@ 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, "hmm0.png" );
unsigned char *data = cairo_image_surface_get_data(_backing_store);
int stride = cairo_image_surface_get_stride(_backing_store);
+ std::cout << " stride: " << stride << std::endl;
+
+ double x_scale = 0;
+ double y_scale = 0;
+ cairo_surface_get_device_scale(_backing_store, &x_scale, &y_scale);
+ if (x_scale != y_scale) {
+ std::cerr << "SPCanvas::paintSingleBuffer(): non-uniform device scale!" << std::endl;
+ }
+
// Move to the right row
data += stride * (paint_rect.top() - _y0);
// 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);
+ paint_rect.width()*x_scale, paint_rect.height()*y_scale, stride);
+
+ std::cout << " imgs: width: " << cairo_image_surface_get_width(imgs)
+ << " height: " << cairo_image_surface_get_height(imgs) << std::endl;
+
+ cairo_surface_set_device_scale(imgs, x_scale, y_scale);
buf.ct = cairo_create(imgs);
cairo_save(buf.ct);
@@ -1557,10 +1624,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, "hmm1.png" );
if (_root->visible) {
SP_CANVAS_ITEM_GET_CLASS(_root)->render(_root, &buf);
}
+ cairo_surface_write_to_png( imgs, "hmm2.png" );
// output to X
cairo_destroy(buf.ct);
@@ -1590,6 +1659,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, "hmm3.png" );
// Mark the painted rectangle clean
markRect(paint_rect, 0);
@@ -1718,19 +1788,31 @@ The default for now is the strips mode.
bool SPCanvas::paintRect(int xx0, int yy0, int xx1, int yy1)
{
+ std::cout << "\nSPCanvas::paintRect: "
+ << xx0 << ".." << xx1 << ", "
+ << yy0 << ".." << yy1
+ << std::endl;
GtkAllocation allocation;
g_return_val_if_fail (!_need_update, false);
gtk_widget_get_allocation(GTK_WIDGET(this), &allocation);
+ std::cout << " allocation: width: " << allocation.width
+ << " height: " << allocation.height << std::endl;
+
+ // For HiDPI monitors
+ int device_scale = gtk_widget_get_scale_factor(GTK_WIDGET(this));
+ std::cout << " Gtk::device_scale: " << device_scale << std::endl;
+
// Find window rectangle in 'world coordinates'.
Geom::IntRect canvas_rect = Geom::IntRect::from_xywh(_x0, _y0,
allocation.width, allocation.height);
+ // Geom::IntRect paint_rect(xx0, yy0, xx0+(xx1-xx0)*2, yy0+(yy1-yy0)*2);
Geom::IntRect paint_rect(xx0, yy0, xx1, yy1);
Geom::OptIntRect area = paint_rect & canvas_rect;
if (!area || area->hasZeroArea()) return 0;
-
+ std::cout << " area: " << *area << std::endl;
paint_rect = *area;
PaintRectSetup setup;
@@ -1752,6 +1834,7 @@ bool SPCanvas::paintRect(int xx0, int yy0, int xx1, int yy1)
gdk_window_get_device_position(gtk_widget_get_window(GTK_WIDGET(this)),
device->gobj(),
&x, &y, NULL);
+ std::cout << " mouse: " << x << "x" << y << std::endl;
setup.mouse_loc = sp_canvas_window_to_world(this, Geom::Point(x,y));
@@ -1787,19 +1870,47 @@ void SPCanvas::endForcedFullRedraws()
}
gboolean SPCanvas::handle_draw(GtkWidget *widget, cairo_t *cr) {
+
+ std::cout << "\nSPCanvas::handle_draw():" << std::endl;
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);
+
+ std::cout << " CREATING _surface_for_similar" << std::endl;
+ // Create a dummy surface to store something or other.
+ // Device scale is copied but since this is only created one time, we'll
+ // need to check/set device scale anytime it is used.
+ canvas->_surface_for_similar =
+ cairo_surface_create_similar(cairo_get_target(cr), CAIRO_CONTENT_COLOR_ALPHA, 1, 1);
+
+ double x_scale = 0;
+ double y_scale = 0;
+ cairo_surface_get_device_scale(canvas->_surface_for_similar, &x_scale, &y_scale);
+ std::cout << " _surface_for... x_scale: " << x_scale << " y_scale: " << y_scale << std::endl;
+
+ cairo_surface_get_device_scale(cairo_get_target(cr), &x_scale, &y_scale);
+ std::cout << " cr: x_scale: " << x_scale << " y_scale: " << y_scale << std::endl;
+
+ cairo_surface_get_device_scale(canvas->_backing_store, &x_scale, &y_scale);
+ if (x_scale != y_scale) {
+ std::cerr << "SPCanvas::handle_draw(): non-uniform device scale!" << std::endl;
+ }
+ std::cout << " _backing_store: x_scale: " << x_scale << " y_scale: " << y_scale << std::endl;
+ std::cout << " _backing_store: width: "
+ << cairo_image_surface_get_width(canvas->_backing_store)
+ << " height: "
+ << cairo_image_surface_get_height(canvas->_backing_store) << std::endl;
// 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, x_scale, y_scale);
+
// Copy the old backing store contents
cairo_t *cr = cairo_create(new_backing_store);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
@@ -1808,6 +1919,8 @@ gboolean SPCanvas::handle_draw(GtkWidget *widget, cairo_t *cr) {
cairo_destroy(cr);
cairo_surface_destroy(canvas->_backing_store);
canvas->_backing_store = new_backing_store;
+ } else {
+ std::cout << " Not creating _surface_for_similar" << std::endl;
}
#endif
@@ -1837,7 +1950,9 @@ gboolean SPCanvas::handle_draw(GtkWidget *widget, cairo_t *cr) {
}
cairo_region_destroy(dirty_region);
- return TRUE;
+ std::cout << "SPCanvas::handle_draw(): Exit" << std::endl;
+
+ return TRUE;
}
gint SPCanvas::handle_key_event(GtkWidget *widget, GdkEventKey *event)
@@ -1979,7 +2094,11 @@ SPCanvasGroup *SPCanvas::getRoot()
*/
void SPCanvas::scrollTo( Geom::Point const &c, unsigned int clear, bool is_scrolling)
{
- GtkAllocation allocation;
+ std::cout << "\nSPCanvas::scrollTo" << std::endl;
+
+ // For HiDPI monitors
+ int device_scale = gtk_widget_get_scale_factor(GTK_WIDGET(this));
+ std::cout << " Gtk::device_scale: " << device_scale << std::endl;
double cx = c[Geom::X];
double cy = c[Geom::Y];
@@ -1992,18 +2111,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
assert(_backing_store);
+ double x_scale = 0;
+ double y_scale = 0;
+ cairo_surface_get_device_scale(_backing_store, &x_scale, &y_scale);
+ if (x_scale != y_scale) {
+ std::cerr << "SPCanvas::scrollTo(): non-uniform device scale!" << std::endl;
+ }
+
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);
+ 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);
+ new_backing_store =
+ cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+ allocation.width * device_scale,
+ allocation.height * device_scale);
+
+ cairo_surface_set_device_scale(new_backing_store, x_scale, y_scale);
cairo_t *cr = cairo_create(new_backing_store);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
// Paint the background