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/drawing-item.cpp | 25 +++++- src/display/drawing-surface.cpp | 49 +++++++++--- src/display/drawing-surface.h | 8 +- src/display/sp-canvas.cpp | 169 ++++++++++++++++++++++++++++++++++++---- 4 files changed, 218 insertions(+), 33 deletions(-) (limited to 'src') 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::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') 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/drawing-item.cpp | 16 +---- src/display/drawing-surface.cpp | 11 +--- src/display/sp-canvas.cpp | 126 +++++++--------------------------------- 3 files changed, 25 insertions(+), 128 deletions(-) (limited to 'src') diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp index a9408e4b0..cc4673bc8 100644 --- a/src/display/drawing-item.cpp +++ b/src/display/drawing-item.cpp @@ -678,15 +678,6 @@ 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(); @@ -707,11 +698,9 @@ 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) + // Device scale for HiDPI screens (typically 1 or 2) int device_scale = dc.surface()->device_scale(); - std::cout << "DrawingItem::render: device_scale: " << device_scale << std::endl; switch(_antialias){ case 0: @@ -784,7 +773,6 @@ 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); } @@ -800,7 +788,6 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag iarea.intersectWith(_drawbox); } - std::cout << " intermediate area required! Device scale: " << device_scale << std::endl; DrawingSurface intermediate(*iarea, device_scale); DrawingContext ict(intermediate); unsigned render_result = RENDER_OK; @@ -870,7 +857,6 @@ 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 fe7a1bf74..2752789e2 100644 --- a/src/display/drawing-surface.cpp +++ b/src/display/drawing-surface.cpp @@ -48,7 +48,7 @@ DrawingSurface::DrawingSurface(Geom::IntRect const &area, int device_scale) , _pixels(area.dimensions()) , _device_scale(device_scale) { - std::cout << "DrawingSurface::DrawingSurface() 1" << std::endl; + assert(_device_scale > 0); } /** @@ -66,7 +66,7 @@ DrawingSurface::DrawingSurface(Geom::Rect const &logbox, Geom::IntPoint const &p , _pixels(pixdims) , _device_scale(device_scale) { - std::cout << "DrawingSurface::DrawingSurface() 2" << std::endl; + assert(_device_scale > 0); } /** @@ -79,7 +79,6 @@ 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); double x_scale = 0; @@ -89,10 +88,7 @@ DrawingSurface::DrawingSurface(cairo_surface_t *surface, Geom::Point const &orig 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; - } + assert(_device_scale > 0); _pixels[X] = cairo_image_surface_get_width(surface)/_device_scale; _pixels[Y] = cairo_image_surface_get_height(surface)/_device_scale; @@ -183,7 +179,6 @@ DrawingSurface::createRawContext() _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); 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 041a02d51fa93277cb9794730d554447efcf3418 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Sun, 26 Nov 2017 18:05:42 +0100 Subject: Simple scaling of controls for high DPI screens (nodes, arrows, etc.). --- src/display/sodipodi-ctrl.cpp | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/display/sodipodi-ctrl.cpp b/src/display/sodipodi-ctrl.cpp index 27b6988c5..80020c0bd 100644 --- a/src/display/sodipodi-ctrl.cpp +++ b/src/display/sodipodi-ctrl.cpp @@ -574,8 +574,18 @@ sp_ctrl_render (SPCanvasItem *item, SPCanvasBuf *buf) // The code below works even when the target is not an image surface if (ctrl->mode == SP_CTRL_MODE_XOR) { + // 1. Copy the affected part of output to a temporary surface - cairo_surface_t *work = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h); + + // Find device scale of source surface + double x_scale = 0; + double y_scale = 0; + cairo_surface_get_device_scale(cairo_get_target(buf->ct), &x_scale, &y_scale); + + // Size in device pixels. Does not set device scale. + cairo_surface_t *work = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * x_scale, h * y_scale); + cairo_surface_set_device_scale(work, x_scale, y_scale); + cairo_t *cr = cairo_create(work); cairo_translate(cr, -ctrl->box.left(), -ctrl->box.top()); cairo_set_source_surface(cr, cairo_get_target(buf->ct), buf->rect.left(), buf->rect.top()); @@ -586,22 +596,31 @@ sp_ctrl_render (SPCanvasItem *item, SPCanvasBuf *buf) cairo_surface_flush(work); int strideb = cairo_image_surface_get_stride(work); unsigned char *pxb = cairo_image_surface_get_data(work); + + int device_scale = x_scale; guint32 *p = ctrl->cache; for (int i=0; i(pxb + i*strideb); + guint32 *pb = reinterpret_cast(pxb + i*strideb*device_scale); for (int j=0; j> 24, ac); guint32 go = compose_xor(gb, (cc & 0x00ff0000) >> 16, ac); guint32 bo = compose_xor(bb, (cc & 0x0000ff00) >> 8, ac); ASSEMBLE_ARGB32(px, ab,ro,go,bo) - *pb++ = px; + *pb = px; + } + if (device_scale == 2) { + *(pb+1) = *pb; + *(pb+strideb/4) = *pb; + *(pb+strideb/4+1) = *pb; + pb++; } + pb++; } } cairo_surface_mark_dirty(work); -- cgit v1.2.3 From 54340f1958acd5a3fb1f0c3db480a96e42156866 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Mon, 27 Nov 2017 15:09:09 +0100 Subject: Adapt control shapes for hi DPI displays. Rework how shapes are generated to simplify code. --- src/display/sodipodi-ctrl.cpp | 349 ++++++++++++++++++++++-------------------- 1 file changed, 182 insertions(+), 167 deletions(-) (limited to 'src') diff --git a/src/display/sodipodi-ctrl.cpp b/src/display/sodipodi-ctrl.cpp index 80020c0bd..fdb079446 100644 --- a/src/display/sodipodi-ctrl.cpp +++ b/src/display/sodipodi-ctrl.cpp @@ -7,6 +7,7 @@ */ #include <2geom/transforms.h> +#include <2geom/line.h> #include "sp-canvas-util.h" #include "sodipodi-ctrl.h" #include "display/cairo-utils.h" @@ -303,9 +304,9 @@ sp_ctrl_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item) } bool -sp_point_inside_line(Geom::Point a, Geom::Point b, Geom::Point c, double tolerance = 0.1){ - //http://stackoverflow.com/questions/328107/how-can-you-determine-a-point-is-between-two-other-points-on-a-line-segment - return Geom::are_near(Geom::distance(a,c) + Geom::distance(c,b) , Geom::distance(a,b), tolerance); +sp_point_inside_line(Geom::Point a, Geom::Point b, Geom::Point c, double tolerance = 0.1) { + Geom::LineSegment segment(a, b); + return Geom::are_near(c, segment, tolerance); } bool @@ -320,12 +321,9 @@ sp_point_inside_triangle(Geom::Point p1,Geom::Point p2,Geom::Point p3, Geom::Poi } static void -sp_ctrl_build_cache (SPCtrl *ctrl) +sp_ctrl_build_cache (SPCtrl *ctrl, int device_scale) { - guint32 *p, *q; - gint size, x, y, z, s, a, width, height, c; guint32 stroke_color, fill_color; - if (ctrl->filled) { if (ctrl->mode == SP_CTRL_MODE_XOR) { fill_color = ctrl->fill_color; @@ -335,6 +333,7 @@ sp_ctrl_build_cache (SPCtrl *ctrl) } else { fill_color = 0; } + if (ctrl->stroked) { if (ctrl->mode == SP_CTRL_MODE_XOR) { stroke_color = ctrl->stroke_color; @@ -344,203 +343,226 @@ sp_ctrl_build_cache (SPCtrl *ctrl) } else { stroke_color = fill_color; } - gint32 stroke_color_smooth = SP_RGBA32_F_COMPOSE(SP_RGBA32_R_F(stroke_color), SP_RGBA32_G_F(stroke_color), SP_RGBA32_B_F(stroke_color), 0.15); - width = (ctrl->width * 2 +1); - height = (ctrl->height * 2 +1); - c = ctrl->width; // Only used for pre-set square drawing - size = width * height; + + gint width = (ctrl->width * 2 + 1) * device_scale; + gint height = (ctrl->height * 2 + 1) * device_scale; if (width < 2) return; + gint size = width * height; if (ctrl->cache) delete[] ctrl->cache; ctrl->cache = new guint32[size]; - Geom::Point point; - Geom::Point p1; - Geom::Point p2; - Geom::Point p3; - if(ctrl->shape == SP_CTRL_SHAPE_TRIANGLE){ - Geom::Affine m = Geom::Translate(Geom::Point(-width/2.0,-height/2.0)); - m *= Geom::Rotate(-ctrl->angle); - m *= Geom::Translate(Geom::Point(width/2.0, height/2.0)); - p1 = Geom::Point(0,height/2); - p2 = Geom::Point(width - (width/M_PI), height/M_PI); - p3 = Geom::Point(width - (width/M_PI), height-(height/M_PI)); - p1 *= m; - p2 *= m; - p3 *= m; - p1 = p1.floor(); - p2 = p2.floor(); - p3 = p3.floor(); - } + switch (ctrl->shape) { case SP_CTRL_SHAPE_SQUARE: - p = ctrl->cache; - // top edge - for (x=0; x < width; x++) { - *p++ = stroke_color; - } - // middle - for (y = 2; y < height; y++) { - *p++ = stroke_color; // stroke at first and last pixel - for (x=2; x < width; x++) { - *p++ = fill_color; // fill in the middle + { + guint32* p = ctrl->cache; + + for (int i = 0; i < width; ++i) { + for (int j = 0; j < height; ++j) { + if ( i > device_scale - 1 && + j > device_scale - 1 && + width - i > device_scale && + height -j > device_scale) { + *p++ = fill_color; + } else { + *p++ = stroke_color; + } } - *p++ = stroke_color; - } - // bottom edge - for (x=0; x < width; x++) { - *p++ = stroke_color; } + ctrl->build = TRUE; break; + } case SP_CTRL_SHAPE_DIAMOND: - p = ctrl->cache; - for (y = 0; y < height; y++) { - z = abs (c - y); - for (x = 0; x < z; x++) { - *p++ = 0; - } - *p++ = stroke_color; x++; - for (; x < width - z -1; x++) { - *p++ = fill_color; - } - if (z != c) { - *p++ = stroke_color; x++; - } - for (; x < width; x++) { - *p++ = 0; + { + // width == height + guint32* p = ctrl->cache; + int m = (width+1)/2; + + for (int i = 0; i < width; ++i) { + for (int j = 0; j < height; ++j) { + if ( i + j > m-1+device_scale && + (width-1-i) + j > m-1+device_scale && + (width-1-i) + (height-1-j) > m-1+device_scale && + i + (height-1-j) > m-1+device_scale ) { + *p++ = fill_color; + } else + if ( i + j > m-2 && + (width-1-i) + j > m-2 && + (width-1-i) + (height-1-j) > m-2 && + i + (height-1-j) > m-2 ) { + *p++ = stroke_color; + } else { + *p++ = 0; + } } } + ctrl->build = TRUE; break; + } case SP_CTRL_SHAPE_CIRCLE: - p = ctrl->cache; - q = p + size -1; - s = -1; - for (y = 0; y <= c ; y++) { - a = abs (c - y); - z = (gint)(0.0 + sqrt ((c+.4)*(c+.4) - a*a)); - x = 0; - while (x < c-z) { - *p++ = 0; - *q-- = 0; - x++; - } - do { - *p++ = stroke_color; - *q-- = stroke_color; - x++; - } while (x < c-s); - while (x < MIN(c+s+1, c+z)) { - *p++ = fill_color; - *q-- = fill_color; - x++; - } - do { - *p++ = stroke_color; - *q-- = stroke_color; - x++; - } while (x <= c+z); - while (x < width) { - *p++ = 0; - *q-- = 0; - x++; + { + guint32* p = ctrl->cache; + + double rs = width/2.0; + double rs2 = rs*rs; + double rf = rs-device_scale; + double rf2 = rf*rf; + + for (int i = 0; i < width; ++i) { + for (int j = 0; j < height; ++j) { + + double rx = i - (width /2.0) + 0.5; + double ry = j - (height/2.0) + 0.5; + double r2 = rx*rx + ry*ry; + + if (r2 < rf2) { + *p++ = fill_color; + } else if (r2 < rs2) { + *p++ = stroke_color; + } else { + *p++ = 0; + } } - s = z; } + ctrl->build = TRUE; break; + } case SP_CTRL_SHAPE_TRIANGLE: - p = ctrl->cache; - for(y = 0; y < height; y++) { - for(x = 0; x < width; x++) { - point = Geom::Point(x,y); - if (sp_point_inside_triangle(p1, p2, p3, point)) { + { + guint* p = ctrl->cache; + + Geom::Affine m = Geom::Translate(Geom::Point(-width/2.0,-height/2.0)); + m *= Geom::Rotate(-ctrl->angle); + m *= Geom::Translate(Geom::Point(width/2.0, height/2.0)); + + // Construct an arrowhead (triangle) of maximum size that won't leak out of rectangle + // defined by width and height, assuming width == height. + double w2 = width/2.0; + double h2 = height/2.0; + double w2cos = w2 * cos( M_PI/6 ); + double h2sin = h2 * sin( M_PI/6 ); + Geom::Point p1s(0, h2); + Geom::Point p2s(w2 + w2cos, h2 + h2sin); + Geom::Point p3s(w2 + w2cos, h2 - h2sin); + // Needed for constructing smaller arrowhead below. + double theta = atan2( Geom::Point( p2s - p1s ) ); + p1s *= m; + p2s *= m; + p3s *= m; + + // Construct a smaller arrow head for fill. + Geom::Point p1f(device_scale/sin(theta), h2); + Geom::Point p2f(w2 + w2cos, h2 - h2sin + device_scale/cos(theta)); + Geom::Point p3f(w2 + w2cos, h2 + h2sin - device_scale/cos(theta)); + p1f *= m; + p2f *= m; + p3f *= m; + + for(int y = 0; y < height; y++) { + for(int x = 0; x < width; x++) { + Geom::Point point = Geom::Point(x+0.5,y+0.5); + if (sp_point_inside_triangle(p1f, p2f, p3f, point)) { p[(y*width)+x] = fill_color; - } else if (point == p1 || point == p2 || point == p3 || sp_point_inside_line(p1, p2, point, 0.2) || - sp_point_inside_line(p3, p1, point, 0.2)) - { + } else + if (sp_point_inside_triangle(p1s, p2s, p3s, point)) { p[(y*width)+x] = stroke_color; - } else if (sp_point_inside_line(p1, p2, point, 0.5) || - sp_point_inside_line(p3, p1, point, 0.5)) - { - p[(y*width)+x] = stroke_color_smooth; } else { p[(y*width)+x] = 0; } } } + ctrl->build = TRUE; break; + } case SP_CTRL_SHAPE_CROSS: - p = ctrl->cache; - for (y = 0; y < height; y++) { - z = abs (c - y); - for (x = 0; x < c-z; x++) { - *p++ = 0; - } - *p++ = stroke_color; x++; - for (; x < c + z; x++) { - *p++ = 0; - } - if (z != 0) { - *p++ = stroke_color; x++; - } - for (; x < width; x++) { - *p++ = 0; + { + guint* p = ctrl->cache; + for(int y = 0; y < height; y++) { + for(int x = 0; x < width; x++) { + if ( abs(x - y) < device_scale || + abs(width - 1 - x - y) < device_scale ) { + *p++ = stroke_color; + } else { + *p++ = 0; + } } } + ctrl->build = TRUE; break; + } case SP_CTRL_SHAPE_BITMAP: + { if (ctrl->pixbuf) { - unsigned char *px; - unsigned int rs; - px = gdk_pixbuf_get_pixels (ctrl->pixbuf); - rs = gdk_pixbuf_get_rowstride (ctrl->pixbuf); - for (y = 0; y < height; y++){ - guint32 *d; - unsigned char *s; - s = px + y * rs; - d = ctrl->cache + height * y; - for (x = 0; x < width; x++) { + unsigned char* px = gdk_pixbuf_get_pixels (ctrl->pixbuf); + unsigned int rs = gdk_pixbuf_get_rowstride (ctrl->pixbuf); + for (int y = 0; y < height/device_scale; y++){ + for (int x = 0; x < width/device_scale; x++) { + unsigned char *s = px + rs*y + 4*x; + guint32 color; if (s[3] < 0x80) { - *d++ = 0; + color = 0; } else if (s[0] < 0x80) { - *d++ = stroke_color; + color = stroke_color; } else { - *d++ = fill_color; + color = fill_color; + } + + // Fill in device_scale x device_scale block + for (int i = 0; i < device_scale; ++i) { + for (int j = 0; j < device_scale; ++j) { + guint* p = ctrl->cache + + (x * device_scale + i) + // Column + (y * device_scale + j) * width; // Row + *p = color; + } } - s += 4; } } } else { - g_print ("control has no pixmap\n"); + g_print ("control has no pixbuf\n"); } + ctrl->build = TRUE; break; + } case SP_CTRL_SHAPE_IMAGE: + { if (ctrl->pixbuf) { - guint r = gdk_pixbuf_get_rowstride (ctrl->pixbuf); - guint32 *px; + guint rs = gdk_pixbuf_get_rowstride (ctrl->pixbuf); guchar *data = gdk_pixbuf_get_pixels (ctrl->pixbuf); - p = ctrl->cache; - for (y = 0; y < height; y++){ - px = reinterpret_cast(data + y * r); - for (x = 0; x < width; x++) { - *p++ = *px++; + + for (int y = 0; y < height/device_scale; y++){ + for (int x = 0; x < width/device_scale; x++) { + guint32 *px = reinterpret_cast(data + rs*y + 4*x); + + // Fill in device_scale x device_scale block + for (int i = 0; i < device_scale; ++i) { + for (int j = 0; j < device_scale; ++j) { + guint* p = ctrl->cache + + (x * device_scale + i) + // Column + (y * device_scale + j) * width; // Row + *p = *px; + } + } } } } else { - g_print ("control has no pixmap\n"); + g_print ("control has no pixbuf\n"); } ctrl->build = TRUE; break; + } default: break; @@ -556,80 +578,73 @@ static inline guint32 compose_xor(guint32 bg, guint32 fg, guint32 a) static void sp_ctrl_render (SPCanvasItem *item, SPCanvasBuf *buf) { - //gint y0, y1, y, x0,x1,x; - //guchar *p, *q, a; - SPCtrl *ctrl = SP_CTRL (item); if (!ctrl->defined) return; if ((!ctrl->filled) && (!ctrl->stroked)) return; + // Find device scale of source surface. + double x_scale = 0; + double y_scale = 0; + cairo_surface_get_device_scale(cairo_get_target(buf->ct), &x_scale, &y_scale); + int device_scale = x_scale; + // the control-image is rendered into ctrl->cache if (!ctrl->build) { - sp_ctrl_build_cache (ctrl); + sp_ctrl_build_cache (ctrl, device_scale); } - int w = (ctrl->width * 2 + 1); - int h = (ctrl->height * 2 + 1); + // Must match width/height sp_ctrl_build_cache. + int w = (ctrl->width * 2 + 1) * device_scale; + int h = (ctrl->height * 2 + 1) * device_scale; // The code below works even when the target is not an image surface if (ctrl->mode == SP_CTRL_MODE_XOR) { // 1. Copy the affected part of output to a temporary surface - // Find device scale of source surface - double x_scale = 0; - double y_scale = 0; - cairo_surface_get_device_scale(cairo_get_target(buf->ct), &x_scale, &y_scale); - // Size in device pixels. Does not set device scale. - cairo_surface_t *work = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w * x_scale, h * y_scale); - cairo_surface_set_device_scale(work, x_scale, y_scale); + cairo_surface_t *work = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h); + cairo_surface_set_device_scale(work, device_scale, device_scale); cairo_t *cr = cairo_create(work); cairo_translate(cr, -ctrl->box.left(), -ctrl->box.top()); cairo_set_source_surface(cr, cairo_get_target(buf->ct), buf->rect.left(), buf->rect.top()); cairo_paint(cr); cairo_destroy(cr); + cairo_surface_write_to_png( work, "ctrl0.png" ); // 2. Composite the control on a temporary surface cairo_surface_flush(work); int strideb = cairo_image_surface_get_stride(work); unsigned char *pxb = cairo_image_surface_get_data(work); - int device_scale = x_scale; guint32 *p = ctrl->cache; for (int i=0; i(pxb + i*strideb*device_scale); + guint32 *pb = reinterpret_cast(pxb + i*strideb); for (int j=0; j> 24, ac); guint32 go = compose_xor(gb, (cc & 0x00ff0000) >> 16, ac); guint32 bo = compose_xor(bb, (cc & 0x0000ff00) >> 8, ac); ASSEMBLE_ARGB32(px, ab,ro,go,bo) - *pb = px; - } - if (device_scale == 2) { - *(pb+1) = *pb; - *(pb+strideb/4) = *pb; - *(pb+strideb/4+1) = *pb; - pb++; + *pb++ = px; } - pb++; } } cairo_surface_mark_dirty(work); + cairo_surface_write_to_png( work, "ctrl1.png" ); // 3. Replace the affected part of output with contents of temporary surface cairo_save(buf->ct); cairo_set_source_surface(buf->ct, work, ctrl->box.left() - buf->rect.left(), ctrl->box.top() - buf->rect.top()); - cairo_rectangle(buf->ct, ctrl->box.left() - buf->rect.left(), ctrl->box.top() - buf->rect.top(), w, h); + cairo_rectangle(buf->ct, ctrl->box.left() - buf->rect.left(), ctrl->box.top() - buf->rect.top(), w/device_scale, h/device_scale); cairo_clip(buf->ct); cairo_set_operator(buf->ct, CAIRO_OPERATOR_SOURCE); cairo_paint(buf->ct); -- 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/cairo-utils.cpp | 22 ++++++++++++++++++-- src/display/sodipodi-ctrl.cpp | 16 +++++---------- src/display/sp-canvas.cpp | 47 ++++++++++++++++++++++++------------------- src/display/sp-canvas.h | 3 +++ 4 files changed, 54 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp index 8045007e7..aeda3f379 100644 --- a/src/display/cairo-utils.cpp +++ b/src/display/cairo-utils.cpp @@ -842,8 +842,19 @@ ink_cairo_surface_create_identical(cairo_surface_t *s) cairo_surface_t * ink_cairo_surface_create_same_size(cairo_surface_t *s, cairo_content_t c) { - cairo_surface_t *ns = cairo_surface_create_similar(s, c, - ink_cairo_surface_get_width(s), ink_cairo_surface_get_height(s)); + // ink_cairo_surface_get_width()/height() returns value in pixels + // cairo_surface_create_similar() uses device units + double x_scale = 0; + double y_scale = 0; + cairo_surface_get_device_scale( s, &x_scale, &y_scale ); + + assert (x_scale > 0); + assert (y_scale > 0); + + cairo_surface_t *ns = + cairo_surface_create_similar(s, c, + ink_cairo_surface_get_width(s)/x_scale, + ink_cairo_surface_get_height(s)/y_scale); return ns; } @@ -908,6 +919,9 @@ ink_cairo_surface_blit(cairo_surface_t *src, cairo_surface_t *dest) } } +/** + * Return width in pixels. + */ int ink_cairo_surface_get_width(cairo_surface_t *surface) { @@ -916,6 +930,10 @@ ink_cairo_surface_get_width(cairo_surface_t *surface) assert(cairo_surface_get_type(surface) == CAIRO_SURFACE_TYPE_IMAGE); return cairo_image_surface_get_width(surface); } + +/** + * Return height in pixels. + */ int ink_cairo_surface_get_height(cairo_surface_t *surface) { diff --git a/src/display/sodipodi-ctrl.cpp b/src/display/sodipodi-ctrl.cpp index fdb079446..0c346eccf 100644 --- a/src/display/sodipodi-ctrl.cpp +++ b/src/display/sodipodi-ctrl.cpp @@ -583,20 +583,14 @@ sp_ctrl_render (SPCanvasItem *item, SPCanvasBuf *buf) if (!ctrl->defined) return; if ((!ctrl->filled) && (!ctrl->stroked)) return; - // Find device scale of source surface. - double x_scale = 0; - double y_scale = 0; - cairo_surface_get_device_scale(cairo_get_target(buf->ct), &x_scale, &y_scale); - int device_scale = x_scale; - // the control-image is rendered into ctrl->cache if (!ctrl->build) { - sp_ctrl_build_cache (ctrl, device_scale); + sp_ctrl_build_cache (ctrl, buf->device_scale); } // Must match width/height sp_ctrl_build_cache. - int w = (ctrl->width * 2 + 1) * device_scale; - int h = (ctrl->height * 2 + 1) * device_scale; + int w = (ctrl->width * 2 + 1) * buf->device_scale; + int h = (ctrl->height * 2 + 1) * buf->device_scale; // The code below works even when the target is not an image surface if (ctrl->mode == SP_CTRL_MODE_XOR) { @@ -605,7 +599,7 @@ sp_ctrl_render (SPCanvasItem *item, SPCanvasBuf *buf) // Size in device pixels. Does not set device scale. cairo_surface_t *work = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h); - cairo_surface_set_device_scale(work, device_scale, device_scale); + cairo_surface_set_device_scale(work, buf->device_scale, buf->device_scale); cairo_t *cr = cairo_create(work); cairo_translate(cr, -ctrl->box.left(), -ctrl->box.top()); @@ -644,7 +638,7 @@ sp_ctrl_render (SPCanvasItem *item, SPCanvasBuf *buf) cairo_save(buf->ct); cairo_set_source_surface(buf->ct, work, ctrl->box.left() - buf->rect.left(), ctrl->box.top() - buf->rect.top()); - cairo_rectangle(buf->ct, ctrl->box.left() - buf->rect.left(), ctrl->box.top() - buf->rect.top(), w/device_scale, h/device_scale); + cairo_rectangle(buf->ct, ctrl->box.left() - buf->rect.left(), ctrl->box.top() - buf->rect.top(), w/buf->device_scale, h/buf->device_scale); cairo_clip(buf->ct); cairo_set_operator(buf->ct, CAIRO_OPERATOR_SOURCE); cairo_paint(buf->ct); 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); diff --git a/src/display/sp-canvas.h b/src/display/sp-canvas.h index 92a50da11..d30e0a485 100644 --- a/src/display/sp-canvas.h +++ b/src/display/sp-canvas.h @@ -55,6 +55,7 @@ struct SPCanvasBuf { unsigned char *buf; int buf_rowstride; + int device_scale; // For high DPI monitors. bool is_empty; }; @@ -177,6 +178,8 @@ public: int _x0; ///< World coordinate of the leftmost pixels of window int _y0; ///< World coordinate of the topmost pixels of window + int _device_scale; ///< Scale for high DPI montiors + /// Image surface storing the contents of the widget cairo_surface_t *_backing_store; #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0) -- cgit v1.2.3 From 542441374b6d6129b69470da18e5230dd421bc21 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Thu, 30 Nov 2017 11:35:36 +0100 Subject: Support device scale in filters. --- src/display/nr-filter-diffuselighting.cpp | 23 ++++++++++++++++------- src/display/nr-filter-displacement-map.cpp | 11 +++++++++-- src/display/nr-filter-gaussian.cpp | 14 +++++++++++--- src/display/nr-filter-image.cpp | 23 ++++++++++++++++++----- src/display/nr-filter-morphology.cpp | 5 +++-- src/display/nr-filter-slot.cpp | 8 ++++++++ src/display/nr-filter-slot.h | 7 +++++++ src/display/nr-filter-specularlighting.cpp | 20 +++++++++++++------- src/display/nr-filter-turbulence.cpp | 23 ++++++++++++++++++++++- src/display/nr-filter.cpp | 5 +++++ src/display/nr-light.cpp | 22 +++++++++++----------- src/display/nr-light.h | 6 ++++-- 12 files changed, 127 insertions(+), 40 deletions(-) (limited to 'src') diff --git a/src/display/nr-filter-diffuselighting.cpp b/src/display/nr-filter-diffuselighting.cpp index c6724e3ba..ed5afa82a 100644 --- a/src/display/nr-filter-diffuselighting.cpp +++ b/src/display/nr-filter-diffuselighting.cpp @@ -83,9 +83,10 @@ private: struct DiffusePointLight : public DiffuseLight { DiffusePointLight(cairo_surface_t *bumpmap, SPFePointLight *light, guint32 color, - Geom::Affine const &trans, double scale, double diffuse_constant, double x0, double y0) + Geom::Affine const &trans, double scale, double diffuse_constant, + double x0, double y0, int device_scale) : DiffuseLight(bumpmap, scale, diffuse_constant) - , _light(light, color, trans) + , _light(light, color, trans, device_scale) , _x0(x0) , _y0(y0) { @@ -105,9 +106,10 @@ private: struct DiffuseSpotLight : public DiffuseLight { DiffuseSpotLight(cairo_surface_t *bumpmap, SPFeSpotLight *light, guint32 color, - Geom::Affine const &trans, double scale, double diffuse_constant, double x0, double y0) + Geom::Affine const &trans, double scale, double diffuse_constant, + double x0, double y0, int device_scale) : DiffuseLight(bumpmap, scale, diffuse_constant) - , _light(light, color, trans) + , _light(light, color, trans, device_scale) , _x0(x0) , _y0(y0) {} @@ -160,11 +162,18 @@ void FilterDiffuseLighting::render_cairo(FilterSlot &slot) set_cairo_surface_ci(out, ci_fp ); guint32 color = SP_RGBA32_F_COMPOSE( r, g, b, 1.0 ); + int device_scale = slot.get_device_scale(); + Geom::Rect slot_area = slot.get_slot_area(); Geom::Point p = slot_area.min(); + + // trans has inverse y... so we can't just scale by device_scale! We must instead explicitly + // scale the point and spot light coordinates (as well as "scale"). + Geom::Affine trans = slot.get_units().get_matrix_primitiveunits2pb(); + double x0 = p[Geom::X], y0 = p[Geom::Y]; - double scale = surfaceScale * trans.descrim(); + double scale = surfaceScale * trans.descrim() * device_scale; switch (light_type) { case DISTANT_LIGHT: @@ -173,11 +182,11 @@ void FilterDiffuseLighting::render_cairo(FilterSlot &slot) break; case POINT_LIGHT: ink_cairo_surface_synthesize(out, - DiffusePointLight(input, light.point, color, trans, scale, diffuseConstant, x0, y0)); + DiffusePointLight(input, light.point, color, trans, scale, diffuseConstant, x0, y0, device_scale)); break; case SPOT_LIGHT: ink_cairo_surface_synthesize(out, - DiffuseSpotLight(input, light.spot, color, trans, scale, diffuseConstant, x0, y0)); + DiffuseSpotLight(input, light.spot, color, trans, scale, diffuseConstant, x0, y0, device_scale)); break; default: { cairo_t *ct = cairo_create(out); diff --git a/src/display/nr-filter-displacement-map.cpp b/src/display/nr-filter-displacement-map.cpp index c0d1ae411..fb2f3a0f0 100644 --- a/src/display/nr-filter-displacement-map.cpp +++ b/src/display/nr-filter-displacement-map.cpp @@ -71,12 +71,17 @@ private: void FilterDisplacementMap::render_cairo(FilterSlot &slot) { + std::cout << "FilterDisplacementMap:" << std::endl; cairo_surface_t *texture = slot.getcairo(_input); cairo_surface_t *map = slot.getcairo(_input2); cairo_surface_t *out = ink_cairo_surface_create_identical(texture); // color_interpolation_filters for out same as texture. See spec. copy_cairo_surface_ci( texture, out ); + std::cout << " texture: " << cairo_image_surface_get_width(texture) << std::endl; + std::cout << " map: " << cairo_image_surface_get_width(map) << std::endl; + std::cout << " out: " << cairo_image_surface_get_width(out) << std::endl; + // We may need to transform map surface to correct color interpolation space. The map surface // might be used as input to another primitive but it is likely that all the primitives in a given // filter use the same color interpolation space so we don't copy the map before converting. @@ -87,8 +92,10 @@ void FilterDisplacementMap::render_cairo(FilterSlot &slot) set_cairo_surface_ci( map, ci_fp ); Geom::Affine trans = slot.get_units().get_matrix_primitiveunits2pb(); - double scalex = scale * trans.expansionX(); - double scaley = scale * trans.expansionY(); + + int device_scale = slot.get_device_scale(); + double scalex = scale * trans.expansionX() * device_scale; + double scaley = scale * trans.expansionY() * device_scale; ink_cairo_surface_synthesize(out, Displace(texture, map, Xchannel, Ychannel, scalex, scaley)); diff --git a/src/display/nr-filter-gaussian.cpp b/src/display/nr-filter-gaussian.cpp index cdd01e75e..2227edfef 100644 --- a/src/display/nr-filter-gaussian.cpp +++ b/src/display/nr-filter-gaussian.cpp @@ -583,6 +583,12 @@ void FilterGaussian::render_cairo(FilterSlot &slot) double deviation_x_orig = dx * trans.expansionX(); double deviation_y_orig = dy * trans.expansionY(); + + int device_scale = slot.get_device_scale(); + + deviation_x_orig *= device_scale; + deviation_y_orig *= device_scale; + cairo_format_t fmt = cairo_image_surface_get_format(in); int bytes_per_pixel = 0; switch (fmt) { @@ -604,7 +610,7 @@ void FilterGaussian::render_cairo(FilterSlot &slot) int x_step = 1 << _effect_subsample_step_log2(deviation_x_orig, quality); int y_step = 1 << _effect_subsample_step_log2(deviation_y_orig, quality); bool resampling = x_step > 1 || y_step > 1; - int w_orig = ink_cairo_surface_get_width(in); + int w_orig = ink_cairo_surface_get_width(in); // Pixels int h_orig = ink_cairo_surface_get_height(in); int w_downsampled = resampling ? static_cast(ceil(static_cast(w_orig)/x_step))+1 : w_orig; int h_downsampled = resampling ? static_cast(ceil(static_cast(h_orig)/y_step))+1 : h_orig; @@ -633,8 +639,10 @@ void FilterGaussian::render_cairo(FilterSlot &slot) cairo_surface_t *downsampled = NULL; if (resampling) { + // Divide by device scale as w_downsampled is in pixels while + // cairo_surface_create_similar() uses device units. downsampled = cairo_surface_create_similar(in, cairo_surface_get_content(in), - w_downsampled, h_downsampled); + w_downsampled/device_scale, h_downsampled/device_scale); cairo_t *ct = cairo_create(downsampled); cairo_scale(ct, static_cast(w_downsampled)/w_orig, static_cast(h_downsampled)/h_orig); cairo_set_source_surface(ct, in, 0, 0); @@ -671,7 +679,7 @@ void FilterGaussian::render_cairo(FilterSlot &slot) cairo_surface_mark_dirty(downsampled); if (resampling) { cairo_surface_t *upsampled = cairo_surface_create_similar(downsampled, cairo_surface_get_content(downsampled), - w_orig, h_orig); + w_orig/device_scale, h_orig/device_scale); cairo_t *ct = cairo_create(upsampled); cairo_scale(ct, static_cast(w_orig)/w_downsampled, static_cast(h_orig)/h_downsampled); cairo_set_source_surface(ct, downsampled, 0, 0); diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp index 7e859314a..86ebb49cb 100644 --- a/src/display/nr-filter-image.cpp +++ b/src/display/nr-filter-image.cpp @@ -47,6 +47,7 @@ FilterImage::~FilterImage() void FilterImage::render_cairo(FilterSlot &slot) { + std::cout << "FilterImage::render_cairo: Entrance" << std::endl; if (!feImageHref) return; @@ -78,8 +79,11 @@ void FilterImage::render_cairo(FilterSlot &slot) if( feImageWidth == 0 ) feImageWidth = bbox_width; if( feImageHeight == 0 ) feImageHeight = bbox_height; + int device_scale = slot.get_device_scale(); + // Internal image, like if (from_element) { + std::cout << " Internal image" << std::endl; if (!SVGElem) return; // TODO: do not recreate the rendering tree every time @@ -108,8 +112,12 @@ void FilterImage::render_cairo(FilterSlot &slot) */ Geom::Rect sa = slot.get_slot_area(); - cairo_surface_t *out = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - sa.width(), sa.height()); + cairo_surface_t *out = + cairo_image_surface_create(CAIRO_FORMAT_ARGB32, + sa.width() * device_scale, + sa.height() * device_scale); + cairo_surface_set_device_scale(out, device_scale, device_scale); + Inkscape::DrawingContext dc(out, sa.min()); dc.transform(user2pb); // we are now in primitive units dc.translate(feImageX, feImageY); @@ -128,11 +136,14 @@ void FilterImage::render_cairo(FilterSlot &slot) slot.set(_output, out); cairo_surface_destroy(out); + std::cout << " feImage: out: " << cairo_image_surface_get_width( out) << std::endl; + std::cout << "FilterImage::render_cairo: Exit 2" << std::endl; return; } // External image, like if (!image && !broken_ref) { + std::cout << " External image" << std::endl; broken_ref = true; /* TODO: If feImageHref is absolute, then use that (preferably handling the @@ -170,10 +181,12 @@ void FilterImage::render_cairo(FilterSlot &slot) } cairo_surface_t *image_surface = image->getSurfaceRaw(); - + std::cout << " image: " << cairo_image_surface_get_width(image_surface) << std::endl; Geom::Rect sa = slot.get_slot_area(); cairo_surface_t *out = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - sa.width(), sa.height()); + sa.width() * device_scale, sa.height() * device_scale); + cairo_surface_set_device_scale( out, device_scale, device_scale ); + std::cout << " out: " << cairo_image_surface_get_width(out) << std::endl; // For the moment, we'll assume that any image is in sRGB color space // set_cairo_surface_ci(out, SP_CSS_COLOR_INTERPOLATION_SRGB); @@ -278,8 +291,8 @@ void FilterImage::render_cairo(FilterSlot &slot) cairo_set_source_surface(ct, image_surface, 0, 0); cairo_paint(ct); cairo_destroy(ct); - slot.set(_output, out); + std::cout << "FilterImage::render_cairo: Exit 2" << std::endl; } bool FilterImage::can_handle_affine(Geom::Affine const &) diff --git a/src/display/nr-filter-morphology.cpp b/src/display/nr-filter-morphology.cpp index b6e5052e1..a06033e80 100644 --- a/src/display/nr-filter-morphology.cpp +++ b/src/display/nr-filter-morphology.cpp @@ -171,9 +171,10 @@ void FilterMorphology::render_cairo(FilterSlot &slot) return; } + int device_scale = slot.get_device_scale(); Geom::Affine p2pb = slot.get_units().get_matrix_primitiveunits2pb(); - double xr = fabs(xradius * p2pb.expansionX()); - double yr = fabs(yradius * p2pb.expansionY()); + double xr = fabs(xradius * p2pb.expansionX()) * device_scale; + double yr = fabs(yradius * p2pb.expansionY()) * device_scale; int bpp = cairo_image_surface_get_format(input) == CAIRO_FORMAT_A8 ? 1 : 4; cairo_surface_t *interm = ink_cairo_surface_create_identical(input); diff --git a/src/display/nr-filter-slot.cpp b/src/display/nr-filter-slot.cpp index a6e0c5c4e..9d76462c0 100644 --- a/src/display/nr-filter-slot.cpp +++ b/src/display/nr-filter-slot.cpp @@ -270,6 +270,14 @@ int FilterSlot::get_blurquality(void) { return blurquality; } +void FilterSlot::set_device_scale(int const s) { + device_scale = s; +} + +int FilterSlot::get_device_scale() { + return device_scale; +} + Geom::Rect FilterSlot::get_slot_area() const { Geom::Point p(_slot_x, _slot_y); Geom::Point dim(_slot_w, _slot_h); diff --git a/src/display/nr-filter-slot.h b/src/display/nr-filter-slot.h index 166b2e718..d73e9d91c 100644 --- a/src/display/nr-filter-slot.h +++ b/src/display/nr-filter-slot.h @@ -72,6 +72,12 @@ public: /** Gets the gaussian filtering quality. Affects used interpolation methods */ int get_blurquality(void); + /** Sets the device scale; for high DPI monitors. */ + void set_device_scale(int const s); + + /** Gets the device scale; for high DPI monitors. */ + int get_device_scale(); + FilterUnits const &get_units() const { return _units; } Geom::Rect get_slot_area() const; @@ -98,6 +104,7 @@ private: int _last_out; FilterQuality filterquality; int blurquality; + int device_scale; cairo_surface_t *_get_transformed_source_graphic(); cairo_surface_t *_get_transformed_background(); diff --git a/src/display/nr-filter-specularlighting.cpp b/src/display/nr-filter-specularlighting.cpp index 2ce02adee..e8d03d42e 100644 --- a/src/display/nr-filter-specularlighting.cpp +++ b/src/display/nr-filter-specularlighting.cpp @@ -93,9 +93,9 @@ private: struct SpecularPointLight : public SpecularLight { SpecularPointLight(cairo_surface_t *bumpmap, SPFePointLight *light, guint32 color, Geom::Affine const &trans, double scale, double specular_constant, - double specular_exponent, double x0, double y0) + double specular_exponent, double x0, double y0, int device_scale) : SpecularLight(bumpmap, scale, specular_constant, specular_exponent) - , _light(light, color, trans) + , _light(light, color, trans, device_scale) , _x0(x0) , _y0(y0) { @@ -117,9 +117,9 @@ private: struct SpecularSpotLight : public SpecularLight { SpecularSpotLight(cairo_surface_t *bumpmap, SPFeSpotLight *light, guint32 color, Geom::Affine const &trans, double scale, double specular_constant, - double specular_exponent, double x0, double y0) + double specular_exponent, double x0, double y0, int device_scale) : SpecularLight(bumpmap, scale, specular_constant, specular_exponent) - , _light(light, color, trans) + , _light(light, color, trans, device_scale) , _x0(x0) , _y0(y0) {} @@ -173,11 +173,17 @@ void FilterSpecularLighting::render_cairo(FilterSlot &slot) set_cairo_surface_ci(out, ci_fp ); guint32 color = SP_RGBA32_F_COMPOSE( r, g, b, 1.0 ); + int device_scale = slot.get_device_scale(); + + // trans has inverse y... so we can't just scale by device_scale! We must instead explicitly + // scale the point and spot light coordinates (as well as "scale"). + Geom::Affine trans = slot.get_units().get_matrix_primitiveunits2pb(); + Geom::Point p = slot.get_slot_area().min(); double x0 = p[Geom::X]; double y0 = p[Geom::Y]; - double scale = surfaceScale * trans.descrim(); + double scale = surfaceScale * trans.descrim() * device_scale; double ks = specularConstant; double se = specularExponent; @@ -188,11 +194,11 @@ void FilterSpecularLighting::render_cairo(FilterSlot &slot) break; case POINT_LIGHT: ink_cairo_surface_synthesize(out, - SpecularPointLight(input, light.point, color, trans, scale, ks, se, x0, y0)); + SpecularPointLight(input, light.point, color, trans, scale, ks, se, x0, y0, device_scale)); break; case SPOT_LIGHT: ink_cairo_surface_synthesize(out, - SpecularSpotLight(input, light.spot, color, trans, scale, ks, se, x0, y0)); + SpecularSpotLight(input, light.spot, color, trans, scale, ks, se, x0, y0, device_scale)); break; default: { cairo_t *ct = cairo_create(out); diff --git a/src/display/nr-filter-turbulence.cpp b/src/display/nr-filter-turbulence.cpp index 1397c0f34..349bcc242 100644 --- a/src/display/nr-filter-turbulence.cpp +++ b/src/display/nr-filter-turbulence.cpp @@ -378,6 +378,19 @@ void FilterTurbulence::render_cairo(FilterSlot &slot) cairo_surface_t *input = slot.getcairo(_input); cairo_surface_t *out = ink_cairo_surface_create_same_size(input, CAIRO_CONTENT_COLOR_ALPHA); + // It is probably possible to render at a device scale greater than one + // but for the moment rendering at a device scale of one is the easiest. + // cairo_image_surface_get_width() returns width in pixels but + // cairo_surface_create_similar() requires width in device units so divide by device scale. + // We are rendering at a device scale of 1... so divide by device scale again! + double x_scale = 0; + double y_scale = 0; + cairo_surface_get_device_scale(input, &x_scale, &y_scale); + int width = ceil(cairo_image_surface_get_width( input)/x_scale/x_scale); + int height = ceil(cairo_image_surface_get_height(input)/y_scale/y_scale); + cairo_surface_t *temp = cairo_surface_create_similar (input, CAIRO_CONTENT_COLOR_ALPHA, width, height); + cairo_surface_set_device_scale( temp, 1, 1 ); + // color_interpolation_filter is determined by CSS value (see spec. Turbulence). if( _style ) { set_cairo_surface_ci(out, (SPColorInterpolation)_style->color_interpolation_filters.computed ); @@ -395,8 +408,16 @@ void FilterTurbulence::render_cairo(FilterSlot &slot) Geom::Rect slot_area = slot.get_slot_area(); double x0 = slot_area.min()[Geom::X]; double y0 = slot_area.min()[Geom::Y]; + ink_cairo_surface_synthesize(temp, Turbulence(*gen, unit_trans, x0, y0)); + + // cairo_surface_write_to_png( temp, "turbulence0.png" ); + + cairo_t *ct = cairo_create(out); + cairo_set_source_surface(ct, temp, 0, 0); + cairo_paint(ct); + cairo_destroy(ct); - ink_cairo_surface_synthesize(out, Turbulence(*gen, unit_trans, x0, y0)); + cairo_surface_destroy(temp); cairo_surface_mark_dirty(out); diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp index d430553d4..a1bea4fce 100644 --- a/src/display/nr-filter.cpp +++ b/src/display/nr-filter.cpp @@ -42,6 +42,7 @@ #include "display/drawing.h" #include "display/drawing-item.h" #include "display/drawing-context.h" +#include "display/drawing-surface.h" #include <2geom/affine.h> #include <2geom/rect.h> #include "svg/svg-length.h" @@ -95,6 +96,9 @@ Filter::~Filter() int Filter::render(Inkscape::DrawingItem const *item, DrawingContext &graphic, DrawingContext *bgdc) { + // std::cout << "Filter::render() for: " << const_cast(item)->name() << std::endl; + // std::cout << " graphic drawing_scale: " << graphic.surface()->device_scale() << std::endl; + if (_primitive.empty()) { // when no primitives are defined, clear source graphic graphic.setSource(0,0,0,0); @@ -150,6 +154,7 @@ int Filter::render(Inkscape::DrawingItem const *item, DrawingContext &graphic, D FilterSlot slot(const_cast(item), bgdc, graphic, units); slot.set_quality(filterquality); slot.set_blurquality(blurquality); + slot.set_device_scale(graphic.surface()->device_scale()); for (unsigned i = 0 ; i < _primitive.size() ; i++) { _primitive[i]->render_cairo(slot); diff --git a/src/display/nr-light.cpp b/src/display/nr-light.cpp index 0e9a55a9f..791ae53da 100644 --- a/src/display/nr-light.cpp +++ b/src/display/nr-light.cpp @@ -41,11 +41,11 @@ void DistantLight::light_components(NR::Fvector &lc) { lc[LIGHT_BLUE] = SP_RGBA32_B_U(color); } -PointLight::PointLight(SPFePointLight *light, guint32 lighting_color, const Geom::Affine &trans) { +PointLight::PointLight(SPFePointLight *light, guint32 lighting_color, const Geom::Affine &trans, int device_scale) { color = lighting_color; - l_x = light->x; - l_y = light->y; - l_z = light->z; + l_x = light->x * device_scale; + l_y = light->y * device_scale; + l_z = light->z * device_scale; NR::convert_coord(l_x, l_y, l_z, trans); } @@ -64,15 +64,15 @@ void PointLight::light_components(NR::Fvector &lc) { lc[LIGHT_BLUE] = SP_RGBA32_B_U(color); } -SpotLight::SpotLight(SPFeSpotLight *light, guint32 lighting_color, const Geom::Affine &trans) { +SpotLight::SpotLight(SPFeSpotLight *light, guint32 lighting_color, const Geom::Affine &trans, int device_scale) { double p_x, p_y, p_z; color = lighting_color; - l_x = light->x; - l_y = light->y; - l_z = light->z; - p_x = light->pointsAtX; - p_y = light->pointsAtY; - p_z = light->pointsAtZ; + l_x = light->x * device_scale; + l_y = light->y * device_scale; + l_z = light->z * device_scale; + p_x = light->pointsAtX * device_scale; + p_y = light->pointsAtY * device_scale; + p_z = light->pointsAtZ * device_scale; cos_lca = std::cos(M_PI / 180 * light->limitingConeAngle); speExp = light->specularExponent; NR::convert_coord(l_x, l_y, l_z, trans); diff --git a/src/display/nr-light.h b/src/display/nr-light.h index 57c421f4a..2eacdc92b 100644 --- a/src/display/nr-light.h +++ b/src/display/nr-light.h @@ -69,8 +69,9 @@ class PointLight { * \param trans the transformation between absolute coordinate (those * employed in the sp light object) and current coordinate (those * employed in the rendering) + * \param device_scale for high DPI monitors. */ - PointLight(SPFePointLight *light, guint32 lighting_color, const Geom::Affine &trans); + PointLight(SPFePointLight *light, guint32 lighting_color, const Geom::Affine &trans, int device_scale = 1); virtual ~PointLight(); /** * Computes the light vector of the distant light at point (x,y,z). @@ -109,8 +110,9 @@ class SpotLight { * \param trans the transformation between absolute coordinate (those * employed in the sp light object) and current coordinate (those * employed in the rendering) + * \param device_scale for high DPI monitors. */ - SpotLight(SPFeSpotLight *light, guint32 lighting_color, const Geom::Affine &trans); + SpotLight(SPFeSpotLight *light, guint32 lighting_color, const Geom::Affine &trans, int device_scale = 1); virtual ~SpotLight(); /** -- cgit v1.2.3 From 177a8e85bba1eccc79f5025208b141436ab94fed Mon Sep 17 00:00:00 2001 From: Duncan Date: Fri, 8 Dec 2017 17:15:48 +1300 Subject: Prevent snapping while space-panning --- src/ui/tools/tool-base.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/ui/tools/tool-base.cpp b/src/ui/tools/tool-base.cpp index 7b4f67da9..79e1cbc10 100644 --- a/src/ui/tools/tool-base.cpp +++ b/src/ui/tools/tool-base.cpp @@ -1289,8 +1289,9 @@ void sp_event_context_snap_delay_handler(ToolBase *ec, // The snap delay will repeat the last motion event, which will lead to // erroneous points in the calligraphy context. And because we don't snap // in this context, we might just as well disable the snap delay all together + bool const c4 = ec->space_panning; // Don't snap while panning with the spacebar - if (c1 || c2 || c3) { + if (c1 || c2 || c3 || c4) { // Make sure that we don't send any pending snap events to a context if we know in advance // that we're not going to snap any way (e.g. while scrolling with middle mouse button) // Any motion event might affect the state of the context, leading to unexpected behavior -- cgit v1.2.3 From 578da50c794702991970f287699914596b5358ef Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Mon, 11 Dec 2017 15:41:46 +0100 Subject: Fix rendering of controls that don't invert color. --- src/display/sodipodi-ctrl.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/display/sodipodi-ctrl.cpp b/src/display/sodipodi-ctrl.cpp index 0c346eccf..04ec947f6 100644 --- a/src/display/sodipodi-ctrl.cpp +++ b/src/display/sodipodi-ctrl.cpp @@ -606,7 +606,7 @@ sp_ctrl_render (SPCanvasItem *item, SPCanvasBuf *buf) cairo_set_source_surface(cr, cairo_get_target(buf->ct), buf->rect.left(), buf->rect.top()); cairo_paint(cr); cairo_destroy(cr); - cairo_surface_write_to_png( work, "ctrl0.png" ); + // cairo_surface_write_to_png( work, "ctrl0.png" ); // 2. Composite the control on a temporary surface cairo_surface_flush(work); @@ -632,7 +632,7 @@ sp_ctrl_render (SPCanvasItem *item, SPCanvasBuf *buf) } } cairo_surface_mark_dirty(work); - cairo_surface_write_to_png( work, "ctrl1.png" ); + // cairo_surface_write_to_png( work, "ctrl1.png" ); // 3. Replace the affected part of output with contents of temporary surface cairo_save(buf->ct); @@ -647,6 +647,7 @@ sp_ctrl_render (SPCanvasItem *item, SPCanvasBuf *buf) } else { cairo_surface_t *cache = cairo_image_surface_create_for_data( reinterpret_cast(ctrl->cache), CAIRO_FORMAT_ARGB32, w, h, w*4); + cairo_surface_set_device_scale(cache, buf->device_scale, buf->device_scale); cairo_set_source_surface(buf->ct, cache, ctrl->box.left() - buf->rect.left(), ctrl->box.top() - buf->rect.top()); cairo_paint(buf->ct); -- cgit v1.2.3 From b9c6b5a23405e974a711b115347d68956d01f367 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Mon, 11 Dec 2017 21:49:55 +0100 Subject: Name a few more widgets. --- src/ui/widget/notebook-page.cpp | 1 + src/ui/widget/object-composite-settings.cpp | 1 + src/ui/widget/spin-scale.cpp | 2 ++ src/widgets/paint-selector.cpp | 1 + 4 files changed, 5 insertions(+) (limited to 'src') diff --git a/src/ui/widget/notebook-page.cpp b/src/ui/widget/notebook-page.cpp index 6d8ff1d75..6bb84014c 100644 --- a/src/ui/widget/notebook-page.cpp +++ b/src/ui/widget/notebook-page.cpp @@ -20,6 +20,7 @@ namespace Widget { NotebookPage::NotebookPage(int n_rows, int n_columns, bool expand, bool fill, guint padding) :_table(Gtk::manage(new Gtk::Grid())) { + set_name("NotebookPage"); set_border_width(2); _table->set_row_spacing(2); diff --git a/src/ui/widget/object-composite-settings.cpp b/src/ui/widget/object-composite-settings.cpp index 5f5b801d1..fa3f6e905 100644 --- a/src/ui/widget/object-composite-settings.cpp +++ b/src/ui/widget/object-composite-settings.cpp @@ -41,6 +41,7 @@ ObjectCompositeSettings::ObjectCompositeSettings(unsigned int verb_code, char co _fe_vbox(false, 0), _blocked(false) { + set_name( "CompositeSettings"); // Filter Effects pack_start(_fe_vbox, false, false, 2); diff --git a/src/ui/widget/spin-scale.cpp b/src/ui/widget/spin-scale.cpp index f74626d9b..c658b4756 100644 --- a/src/ui/widget/spin-scale.cpp +++ b/src/ui/widget/spin-scale.cpp @@ -21,6 +21,7 @@ SpinScale::SpinScale(const char* label, double value, double lower, double upper double /*climb_rate*/, int digits, const SPAttributeEnum a, const char* tip_text) : AttrWidget(a, value) { + set_name("SpinScale"); _adjustment = Gtk::Adjustment::create(value, lower, upper, step_inc); _spinscale = gimp_spin_scale_new (_adjustment->gobj(), label, digits); @@ -122,6 +123,7 @@ DualSpinScale::DualSpinScale(const char* label1, const char* label2, double valu //TRANSLATORS: "Link" means to _link_ two sliders together _link(C_("Sliders", "Link")) { + set_name("DualSpinScale"); signal_value_changed().connect(signal_attr_changed().make_slot()); _s1.get_adjustment()->signal_value_changed().connect(_signal_value_changed.make_slot()); diff --git a/src/widgets/paint-selector.cpp b/src/widgets/paint-selector.cpp index 840a64f95..557dc8da2 100644 --- a/src/widgets/paint-selector.cpp +++ b/src/widgets/paint-selector.cpp @@ -199,6 +199,7 @@ sp_paint_selector_init(SPPaintSelector *psel) /* Paint style button box */ psel->style = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); gtk_box_set_homogeneous(GTK_BOX(psel->style), FALSE); + gtk_widget_set_name(psel->style,"PaintSelector"); gtk_widget_show(psel->style); gtk_container_set_border_width(GTK_CONTAINER(psel->style), 4); gtk_box_pack_start(GTK_BOX(psel), psel->style, FALSE, FALSE, 0); -- cgit v1.2.3