diff options
| author | Jabier Arraiza <jabier.arraiza@marker.es> | 2017-07-01 23:31:49 +0000 |
|---|---|---|
| committer | Jabier Arraiza <jabier.arraiza@marker.es> | 2017-07-01 23:31:49 +0000 |
| commit | 03bb87a0175289274132a0240628936fbccf6ca5 (patch) | |
| tree | 979519e873c0ceff7a6a8b0f53252a4a5ece1143 /src/display | |
| parent | Improving CR feedback. thanks! (diff) | |
| parent | When running without installing, extensions will spawn correct Inkscape (diff) | |
| download | inkscape-03bb87a0175289274132a0240628936fbccf6ca5.tar.gz inkscape-03bb87a0175289274132a0240628936fbccf6ca5.zip | |
Merge https://gitlab.com/inkscape/inkscape into selectable-knots
Diffstat (limited to 'src/display')
| -rw-r--r-- | src/display/sp-canvas.cpp | 84 | ||||
| -rw-r--r-- | src/display/sp-canvas.h | 4 |
2 files changed, 72 insertions, 16 deletions
diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index d04c81ecb..8857b8c68 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -966,6 +966,9 @@ static void sp_canvas_init(SPCanvas *canvas) canvas->_drawing_disabled = false; canvas->_backing_store = NULL; +#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0) + canvas->_surface_for_similar = NULL; +#endif canvas->_clean_region = cairo_region_create(); canvas->_background = cairo_pattern_create_rgb(1, 1, 1); canvas->_background_is_checkerboard = false; @@ -1003,6 +1006,12 @@ void SPCanvas::dispose(GObject *object) cairo_surface_destroy(canvas->_backing_store); canvas->_backing_store = NULL; } +#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0) + if (canvas->_surface_for_similar) { + cairo_surface_destroy(canvas->_surface_for_similar); + canvas->_surface_for_similar = NULL; + } +#endif if (canvas->_clean_region) { cairo_region_destroy(canvas->_clean_region); canvas->_clean_region = NULL; @@ -1125,8 +1134,14 @@ void SPCanvas::handle_size_allocate(GtkWidget *widget, GtkAllocation *allocation allocation->width, allocation->height); // resize backing store - cairo_surface_t *new_backing_store = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - allocation->width, allocation->height); + 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); +#endif + if (new_backing_store == NULL) + new_backing_store = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation->width, allocation->height); if (canvas->_backing_store) { cairo_t *cr = cairo_create(new_backing_store); cairo_translate(cr, -canvas->_x0, -canvas->_y0); @@ -1510,8 +1525,23 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect buf.canvas_rect = canvas_rect; buf.is_empty = true; - // create temporary surface - cairo_surface_t *imgs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, paint_rect.width(), paint_rect.height()); + // Make sure the following code does not go outside of _backing_store's data + assert(cairo_image_surface_get_format(_backing_store) == CAIRO_FORMAT_ARGB32); + assert(paint_rect.left() - _x0 >= 0); + assert(paint_rect.top() - _y0 >= 0); + assert(paint_rect.right() - _x0 <= cairo_image_surface_get_width(_backing_store)); + assert(paint_rect.bottom() - _y0 <= cairo_image_surface_get_height(_backing_store)); + + // Create a temporary surface that draws directly to _backing_store + cairo_surface_flush(_backing_store); + unsigned char *data = cairo_image_surface_get_data(_backing_store); + int stride = cairo_image_surface_get_stride(_backing_store); + // 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); buf.ct = cairo_create(imgs); cairo_save(buf.ct); @@ -1552,16 +1582,7 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect } #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - //cairo_t *xct = gdk_cairo_create(gtk_widget_get_window (widget)); - cairo_t *xct = cairo_create(_backing_store); - cairo_translate(xct, paint_rect.left() - _x0, paint_rect.top() - _y0); - cairo_rectangle(xct, 0, 0, paint_rect.width(), paint_rect.height()); - cairo_clip(xct); - cairo_set_source_surface(xct, imgs, 0, 0); - cairo_set_operator(xct, CAIRO_OPERATOR_SOURCE); - cairo_paint(xct); - cairo_destroy(xct); - cairo_surface_destroy(imgs); + cairo_surface_mark_dirty(_backing_store); // Mark the painted rectangle clean markRect(paint_rect, 0); @@ -1764,6 +1785,28 @@ void SPCanvas::endForcedFullRedraws() gboolean SPCanvas::handle_draw(GtkWidget *widget, cairo_t *cr) { SPCanvas *canvas = SP_CANVAS(widget); +#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0) + if (canvas->_surface_for_similar == NULL && canvas->_backing_store != NULL) { + canvas->_surface_for_similar = cairo_surface_create_similar( + cairo_get_target(cr), CAIRO_CONTENT_COLOR_ALPHA, 1, 1); + + // Reallocate backing store so that cairo can use shared memory + 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)); + + // Copy the old backing store contents + cairo_t *cr = cairo_create(new_backing_store); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_surface(cr, canvas->_backing_store, 0, 0); + cairo_paint(cr); + cairo_destroy(cr); + cairo_surface_destroy(canvas->_backing_store); + canvas->_backing_store = new_backing_store; + } +#endif + // Blit from the backing store, without regard for the clean region. // This is necessary because GTK clears the widget for us, which causes // severe flicker while drawing if we don't blit the old contents. @@ -1853,6 +1896,7 @@ int SPCanvas::paint() cairo_region_get_rectangle(to_draw, i, &crect); if (!paintRect(crect.x, crect.y, crect.x + crect.width, crect.y + crect.height)) { // Aborted + cairo_region_destroy(to_draw); return FALSE; }; } @@ -1862,6 +1906,8 @@ int SPCanvas::paint() _forced_redraw_count = 0; } + cairo_region_destroy(to_draw); + return TRUE; } @@ -1946,8 +1992,14 @@ void SPCanvas::scrollTo( Geom::Point const &c, unsigned int clear, bool is_scrol // adjust backing store contents assert(_backing_store); - cairo_surface_t *new_backing_store = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, - allocation.width, allocation.height); + 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); +#endif + if (new_backing_store == NULL) + new_backing_store = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation.width, allocation.height); cairo_t *cr = cairo_create(new_backing_store); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); // Paint the background diff --git a/src/display/sp-canvas.h b/src/display/sp-canvas.h index a2cbe0b27..92a50da11 100644 --- a/src/display/sp-canvas.h +++ b/src/display/sp-canvas.h @@ -179,6 +179,10 @@ public: /// Image surface storing the contents of the widget cairo_surface_t *_backing_store; +#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 12, 0) + /// This should be e.g. a cairo-xlib surface that is used to allocate _backing_store; might be NULL. + cairo_surface_t *_surface_for_similar; +#endif /// Area of the widget that has up-to-date content cairo_region_t *_clean_region; /// Widget background, defaults to white |
