From 43665505e7f75cbacb303e542771507b58f1a12e Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Thu, 23 Nov 2017 16:07:25 +0100 Subject: First attempt at supporting HiDPI on canvas. Rendering seems to work but has not been fully tested. Editting does not work. --- src/display/sp-canvas.cpp | 169 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 152 insertions(+), 17 deletions(-) (limited to 'src/display/sp-canvas.cpp') 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::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 -- cgit v1.2.3 From 9df83d13058c4d831b4b64e54b247849bcbc17f4 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Fri, 24 Nov 2017 10:46:32 +0100 Subject: Fix repainting. --- src/display/sp-canvas.cpp | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) (limited to 'src/display/sp-canvas.cpp') diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index 845ee8e78..177f9f279 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -1606,9 +1606,9 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect } // 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); + 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()*x_scale, paint_rect.height()*y_scale, stride); @@ -1655,11 +1655,12 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect } cairo_surface_mark_dirty(imgs); } + cairo_surface_write_to_png( imgs, "hmm3.png" ); } #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) cairo_surface_mark_dirty(_backing_store); - cairo_surface_write_to_png( _backing_store, "hmm3.png" ); + cairo_surface_write_to_png( _backing_store, "hmm4.png" ); // Mark the painted rectangle clean markRect(paint_rect, 0); @@ -1838,6 +1839,8 @@ bool SPCanvas::paintRect(int xx0, int yy0, int xx1, int yy1) setup.mouse_loc = sp_canvas_window_to_world(this, Geom::Point(x,y)); + std::cout << " : " << setup.mouse_loc << std::endl; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); unsigned tile_multiplier = prefs->getIntLimited("/options/rendering/tile-multiplier", 16, 1, 512); @@ -1932,11 +1935,14 @@ gboolean SPCanvas::handle_draw(GtkWidget *widget, cairo_t *cr) { cairo_rectangle_list_t *rects = cairo_copy_clip_rectangle_list(cr); cairo_region_t *dirty_region = cairo_region_create(); + std::cout << " number of rectangles: " << rects->num_rectangles << std::endl; for (int i = 0; i < rects->num_rectangles; i++) { 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); + std::cout << " " << i << ": " << dr << std::endl; + 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); @@ -2123,6 +2129,13 @@ void SPCanvas::scrollTo( Geom::Point const &c, unsigned int clear, bool is_scrol std::cerr << "SPCanvas::scrollTo(): non-uniform device scale!" << std::endl; } + std::cout << " ix: " << ix << " iy: " << iy << " dx: " << dx << " dy: " << dy << std::endl; + std::cout << " old_area: " << old_area << std::endl; + std::cout << " new_area: " << new_area << std::endl; + std::cout << " allocation: " << allocation.width << "x" << allocation.height << std::endl; + std::cout << " device_scale: " << device_scale << std::endl; + std::cout << " x_scale: " << x_scale << std::endl; + cairo_surface_t *new_backing_store = NULL; #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0) if (_surface_for_similar != NULL) @@ -2139,6 +2152,7 @@ void SPCanvas::scrollTo( Geom::Point const &c, unsigned int clear, bool is_scrol 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 @@ -2146,6 +2160,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); @@ -2155,6 +2171,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; -- cgit v1.2.3 From 2a6647cad9a24ed63e53a2d1ca12edaae5449b8a Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Fri, 24 Nov 2017 13:23:54 +0100 Subject: Remove debugging code and other cleanup. --- src/display/sp-canvas.cpp | 126 ++++++++-------------------------------------- 1 file changed, 21 insertions(+), 105 deletions(-) (limited to 'src/display/sp-canvas.cpp') diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index 177f9f279..9fdc61a5e 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -862,10 +862,6 @@ 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::const_iterator it = group->items.begin(); it != group->items.end(); ++it) { @@ -881,7 +877,6 @@ void SPCanvasGroup::render(SPCanvasItem *item, SPCanvasBuf *buf) } } } - std::cout << "SPCanvasGroup::render: Exit" << std::endl; } void SPCanvasGroup::viewboxChanged(SPCanvasItem *item, Geom::IntRect const &new_area) @@ -1127,8 +1122,6 @@ 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); // Allocation does not depend on device scale. @@ -1137,40 +1130,24 @@ void SPCanvas::handle_size_allocate(GtkWidget *widget, GtkAllocation *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. - 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) { - // 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) { - std::cout << " _surface_for_similar == NULL && new_backing_store == NULL" << std::endl; // Size in device pixels. Does not set device scale. new_backing_store = @@ -1179,14 +1156,8 @@ void SPCanvas::handle_size_allocate(GtkWidget *widget, GtkAllocation *allocation 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; - + // Set device scale 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); @@ -1564,15 +1535,9 @@ 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. - if (_backing_store == NULL) return; @@ -1593,10 +1558,9 @@ 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" ); + // 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); - std::cout << " stride: " << stride << std::endl; double x_scale = 0; double y_scale = 0; @@ -1606,14 +1570,11 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect } // Move to the right row - data += stride * (paint_rect.top() - _y0)*(int)y_scale; + data += stride * (paint_rect.top() - _y0) * (int)y_scale; // Move to the right pixel inside of that row - data += 4 * (paint_rect.left() - _x0)*(int)x_scale; + 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()*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; + paint_rect.width() * x_scale, paint_rect.height() * y_scale, stride); cairo_surface_set_device_scale(imgs, x_scale, y_scale); buf.ct = cairo_create(imgs); @@ -1624,12 +1585,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" ); + // 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, "hmm2.png" ); + // cairo_surface_write_to_png( imgs, "debug2.png" ); // output to X cairo_destroy(buf.ct); @@ -1655,12 +1616,11 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect } cairo_surface_mark_dirty(imgs); } - cairo_surface_write_to_png( imgs, "hmm3.png" ); } #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) cairo_surface_mark_dirty(_backing_store); - cairo_surface_write_to_png( _backing_store, "hmm4.png" ); + // cairo_surface_write_to_png( _backing_store, "debug3.png" ); // Mark the painted rectangle clean markRect(paint_rect, 0); @@ -1789,31 +1749,18 @@ 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; @@ -1835,12 +1782,9 @@ 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)); - std::cout << " : " << setup.mouse_loc << std::endl; - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); unsigned tile_multiplier = prefs->getIntLimited("/options/rendering/tile-multiplier", 16, 1, 512); @@ -1874,36 +1818,23 @@ 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) { - 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. + // 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); 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. @@ -1922,8 +1853,6 @@ 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 @@ -1935,13 +1864,11 @@ gboolean SPCanvas::handle_draw(GtkWidget *widget, cairo_t *cr) { cairo_rectangle_list_t *rects = cairo_copy_clip_rectangle_list(cr); cairo_region_t *dirty_region = cairo_region_create(); - std::cout << " number of rectangles: " << rects->num_rectangles << std::endl; for (int i = 0; i < rects->num_rectangles; i++) { 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); - std::cout << " " << i << ": " << dr << std::endl; Geom::IntRect ir = dr.roundOutwards(); cairo_rectangle_int_t irect = { ir.left(), ir.top(), ir.width(), ir.height() }; @@ -1956,8 +1883,6 @@ gboolean SPCanvas::handle_draw(GtkWidget *widget, cairo_t *cr) { } cairo_region_destroy(dirty_region); - std::cout << "SPCanvas::handle_draw(): Exit" << std::endl; - return TRUE; } @@ -2100,11 +2025,10 @@ SPCanvasGroup *SPCanvas::getRoot() */ void SPCanvas::scrollTo( Geom::Point const &c, unsigned int clear, bool is_scrolling) { - std::cout << "\nSPCanvas::scrollTo" << std::endl; + // 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)); - std::cout << " Gtk::device_scale: " << device_scale << std::endl; double cx = c[Geom::X]; double cy = c[Geom::Y]; @@ -2120,25 +2044,14 @@ void SPCanvas::scrollTo( Geom::Point const &c, unsigned int clear, bool is_scrol GtkAllocation allocation; gtk_widget_get_allocation(&_widget, &allocation); - // adjust backing store contents + // 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; - } - - std::cout << " ix: " << ix << " iy: " << iy << " dx: " << dx << " dy: " << dy << std::endl; - std::cout << " old_area: " << old_area << std::endl; - std::cout << " new_area: " << new_area << std::endl; - std::cout << " allocation: " << allocation.width << "x" << allocation.height << std::endl; - std::cout << " device_scale: " << device_scale << std::endl; - std::cout << " x_scale: " << x_scale << std::endl; cairo_surface_t *new_backing_store = NULL; #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0) if (_surface_for_similar != NULL) + + // Size in device pixels. Does not set device scale. new_backing_store = cairo_surface_create_similar_image(_surface_for_similar, CAIRO_FORMAT_ARGB32, @@ -2146,12 +2059,15 @@ void SPCanvas::scrollTo( Geom::Point const &c, unsigned int clear, bool is_scrol allocation.height * device_scale); #endif 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 * device_scale, allocation.height * device_scale); - cairo_surface_set_device_scale(new_backing_store, x_scale, y_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); @@ -2160,7 +2076,7 @@ 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" ); + // cairo_surface_write_to_png( _backing_store, "scroll0.png" ); // Copy the old backing store contents cairo_set_source_surface(cr, _backing_store, _x0, _y0); @@ -2171,7 +2087,7 @@ 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" ); + // cairo_surface_write_to_png( _backing_store, "scroll1.png" ); _dx0 = cx; // here the 'd' stands for double, not delta! _dy0 = cy; -- cgit v1.2.3 From 21530cc5cfd6af290cc70be53dedad8c26d71ab9 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Thu, 30 Nov 2017 11:33:32 +0100 Subject: Store device-scale and propogate value where necessary. Avoids reliance on cairo_surface_get_device_scale. Also necessary for filters. --- src/display/sp-canvas.cpp | 47 ++++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 21 deletions(-) (limited to 'src/display/sp-canvas.cpp') diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index 9fdc61a5e..20ad27bf5 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -1129,7 +1129,7 @@ void SPCanvas::handle_size_allocate(GtkWidget *widget, GtkAllocation *allocation gtk_widget_get_allocation(widget, &old_allocation); // For HiDPI monitors. - int device_scale = gtk_widget_get_scale_factor( widget ); + 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); @@ -1143,8 +1143,8 @@ void SPCanvas::handle_size_allocate(GtkWidget *widget, GtkAllocation *allocation new_backing_store = cairo_surface_create_similar_image(canvas->_surface_for_similar, CAIRO_FORMAT_ARGB32, - allocation->width * device_scale, - allocation->height * device_scale); + allocation->width * canvas->_device_scale, + allocation->height * canvas->_device_scale); } #endif if (new_backing_store == NULL) { @@ -1152,12 +1152,12 @@ void SPCanvas::handle_size_allocate(GtkWidget *widget, GtkAllocation *allocation // 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); + allocation->width * canvas->_device_scale, + allocation->height * canvas->_device_scale); } // Set device scale - cairo_surface_set_device_scale(new_backing_store, device_scale, 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); @@ -1546,6 +1546,7 @@ 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 @@ -1562,21 +1563,24 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect 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); - if (x_scale != y_scale) { - std::cerr << "SPCanvas::paintSingleBuffer(): non-uniform device scale!" << std::endl; - } + assert (_device_scale == (int)x_scale); + assert (_device_scale == (int)y_scale); // Move to the right row data += stride * (paint_rect.top() - _y0) * (int)y_scale; // Move to the right pixel inside of that row 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() * x_scale, paint_rect.height() * y_scale, stride); + 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); - cairo_surface_set_device_scale(imgs, x_scale, y_scale); buf.ct = cairo_create(imgs); cairo_save(buf.ct); @@ -1829,12 +1833,12 @@ gboolean SPCanvas::handle_draw(GtkWidget *widget, cairo_t *cr) { 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); - if (x_scale != y_scale) { - std::cerr << "SPCanvas::handle_draw(): non-uniform device scale!" << std::endl; - } + 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. @@ -1843,7 +1847,7 @@ gboolean SPCanvas::handle_draw(GtkWidget *widget, cairo_t *cr) { 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); + 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); @@ -2029,6 +2033,7 @@ void SPCanvas::scrollTo( Geom::Point const &c, unsigned int clear, bool is_scrol // 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]; @@ -2055,19 +2060,19 @@ void SPCanvas::scrollTo( Geom::Point const &c, unsigned int clear, bool is_scrol new_backing_store = cairo_surface_create_similar_image(_surface_for_similar, CAIRO_FORMAT_ARGB32, - allocation.width * device_scale, - allocation.height * device_scale); + allocation.width * _device_scale, + allocation.height * _device_scale); #endif 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 * device_scale, - allocation.height * device_scale); + allocation.width * _device_scale, + allocation.height * _device_scale); // Set device scale - cairo_surface_set_device_scale(new_backing_store, device_scale, 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); -- cgit v1.2.3