summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKrzysztof Kosi??ski <tweenk.pl@gmail.com>2016-07-25 05:27:21 +0000
committerKrzysztof Kosiński <tweenk.pl@gmail.com>2016-07-25 05:27:21 +0000
commit40136abc93171fd163a78472cdeaf5d875acefda (patch)
tree4f702f4c4273c00019de30e9415e938b4e07cc11 /src
parentOrder some headers (diff)
downloadinkscape-40136abc93171fd163a78472cdeaf5d875acefda.tar.gz
inkscape-40136abc93171fd163a78472cdeaf5d875acefda.zip
Revert the canvas widget changes, which cause performance regressions
on GTK2 on some platforms. (bzr r15023.3.1)
Diffstat (limited to 'src')
-rw-r--r--src/desktop.cpp19
-rw-r--r--src/desktop.h1
-rw-r--r--src/display/sp-canvas.cpp376
-rw-r--r--src/display/sp-canvas.h33
4 files changed, 229 insertions, 200 deletions
diff --git a/src/desktop.cpp b/src/desktop.cpp
index d482d0d7f..331ab3351 100644
--- a/src/desktop.cpp
+++ b/src/desktop.cpp
@@ -111,6 +111,7 @@ SPDesktop::SPDesktop() :
sketch( NULL ),
controls( NULL ),
tempgroup ( NULL ),
+ table( NULL ),
page( NULL ),
page_border( NULL ),
current( NULL ),
@@ -210,7 +211,11 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas, Inkscape::UI::View::EditWid
g_signal_connect (G_OBJECT (main), "event", G_CALLBACK (sp_desktop_root_handler), this);
/* This is the background the page sits on. */
- canvas->setBackgroundColor(0xffffff00);
+ table = sp_canvas_item_new (main, SP_TYPE_CTRLRECT, NULL);
+ SP_CTRLRECT(table)->setRectangle(Geom::Rect(Geom::Point(-80000, -80000), Geom::Point(80000, 80000)));
+ SP_CTRLRECT(table)->setColor(0x00000000, true, 0x00000000);
+ SP_CTRLRECT(table)->setCheckerboard( false );
+ sp_canvas_item_move_to_z (table, 0);
page = sp_canvas_item_new (main, SP_TYPE_CTRLRECT, NULL);
((CtrlRect *) page)->setColor(0x00000000, FALSE, 0x00000000);
@@ -1728,11 +1733,17 @@ static void _namedview_modified (SPObject *obj, guint flags, SPDesktop *desktop)
SPNamedView *nv=SP_NAMEDVIEW(obj);
if (flags & SP_OBJECT_MODIFIED_FLAG) {
+
+ /* Set page background */
+ sp_canvas_item_show (desktop->table);
if (nv->pagecheckerboard) {
- desktop->canvas->setBackgroundCheckerboard();
+ ((CtrlRect *) desktop->table)->setCheckerboard( true );
+ ((CtrlRect *) desktop->table)->setColor(0x00000000, true, nv->pagecolor ); // | 0xff);
} else {
- desktop->canvas->setBackgroundColor(nv->pagecolor);
+ ((CtrlRect *) desktop->table)->setCheckerboard( false );
+ ((CtrlRect *) desktop->table)->setColor(0x00000000, true, nv->pagecolor | 0xff);
}
+ sp_canvas_item_move_to_z (desktop->table, 0);
/* Show/hide page border */
if (nv->showborder) {
@@ -1745,7 +1756,7 @@ static void _namedview_modified (SPObject *obj, guint flags, SPDesktop *desktop)
}
// place in the z-order stack
if (nv->borderlayer == SP_BORDER_LAYER_BOTTOM) {
- sp_canvas_item_move_to_z (desktop->page_border, 1);
+ sp_canvas_item_move_to_z (desktop->page_border, 2);
} else {
int order = sp_canvas_item_order (desktop->page_border);
int morder = sp_canvas_item_order (desktop->drawing);
diff --git a/src/desktop.h b/src/desktop.h
index 3652d4a97..f1444ba7b 100644
--- a/src/desktop.h
+++ b/src/desktop.h
@@ -174,6 +174,7 @@ public:
SPCanvasGroup *sketch;
SPCanvasGroup *controls;
SPCanvasGroup *tempgroup; ///< contains temporary canvas items
+ SPCanvasItem *table; ///< outside-of-page background
SPCanvasItem *page; ///< page background
SPCanvasItem *page_border; ///< page border
SPCSSAttr *current; ///< current style
diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp
index 7d76fa043..df84e379c 100644
--- a/src/display/sp-canvas.cpp
+++ b/src/display/sp-canvas.cpp
@@ -8,11 +8,9 @@
* fred
* bbyak
* Jon A. Cruz <jon@joncruz.org>
- * Krzysztof Kosiński <tweenk.pl@gmail.com>
*
* Copyright (C) 1998 The Free Software Foundation
* Copyright (C) 2002-2006 authors
- * Copyright (C) 2016 Google Inc.
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
@@ -27,7 +25,6 @@
#include "helper/sp-marshal.h"
#include <2geom/rect.h>
#include <2geom/affine.h>
-#include "display/cairo-utils.h"
#include "display/sp-canvas.h"
#include "display/sp-canvas-group.h"
#include "preferences.h"
@@ -38,7 +35,6 @@
#include "display/cairo-utils.h"
#include "debug/gdk-event-latency-tracker.h"
#include "desktop.h"
-#include "color.h"
using Inkscape::Debug::GdkEventLatencyTracker;
@@ -126,7 +122,7 @@ struct SPCanvasClass {
namespace {
-gint const UPDATE_PRIORITY = G_PRIORITY_DEFAULT_IDLE;
+gint const UPDATE_PRIORITY = G_PRIORITY_HIGH_IDLE;
GdkWindow *getWindow(SPCanvas *canvas)
{
@@ -939,6 +935,7 @@ void sp_canvas_class_init(SPCanvasClass *klass)
static void sp_canvas_init(SPCanvas *canvas)
{
gtk_widget_set_has_window (GTK_WIDGET (canvas), TRUE);
+ gtk_widget_set_double_buffered (GTK_WIDGET (canvas), FALSE);
gtk_widget_set_can_focus (GTK_WIDGET (canvas), TRUE);
canvas->_pick_event.type = GDK_LEAVE_NOTIFY;
@@ -959,10 +956,9 @@ static void sp_canvas_init(SPCanvas *canvas)
canvas->_drawing_disabled = false;
- canvas->_backing_store = NULL;
- canvas->_clean_region = cairo_region_create();
- canvas->_background = cairo_pattern_create_rgb(1, 1, 1);
- canvas->_background_is_checkerboard = false;
+ canvas->_tiles=NULL;
+ canvas->_tLeft=canvas->_tTop=canvas->_tRight=canvas->_tBottom=0;
+ canvas->_tile_h=canvas->_tile_h=0;
canvas->_forced_redraw_count = 0;
canvas->_forced_redraw_limit = -1;
@@ -971,12 +967,22 @@ static void sp_canvas_init(SPCanvas *canvas)
canvas->_enable_cms_display_adj = false;
new (&canvas->_cms_key) Glib::ustring("");
#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
+
+ canvas->_is_scrolling = false;
}
void SPCanvas::shutdownTransients()
{
- // Reset the clean region
- dirtyAll();
+ // We turn off the need_redraw flag, since if the canvas is mapped again
+ // it will request a redraw anyways. We do not turn off the need_update
+ // flag, though, because updates are not queued when the canvas remaps
+ // itself.
+ //
+ _need_redraw = FALSE;
+ if (_tiles) g_free(_tiles);
+ _tiles = NULL;
+ _tLeft = _tTop = _tRight = _tBottom = 0;
+ _tile_h = _tile_h = 0;
if (_grabbed_item) {
_grabbed_item = NULL;
@@ -999,18 +1005,6 @@ void SPCanvas::dispose(GObject *object)
g_object_unref (canvas->_root);
canvas->_root = NULL;
}
- if (canvas->_backing_store) {
- cairo_surface_destroy(canvas->_backing_store);
- canvas->_backing_store = NULL;
- }
- if (canvas->_clean_region) {
- cairo_region_destroy(canvas->_clean_region);
- canvas->_clean_region = NULL;
- }
- if (canvas->_background) {
- cairo_pattern_destroy(canvas->_background);
- canvas->_background = NULL;
- }
canvas->shutdownTransients();
#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
@@ -1144,48 +1138,41 @@ void SPCanvas::handle_size_request(GtkWidget *widget, GtkRequisition *req)
void SPCanvas::handle_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
{
SPCanvas *canvas = SP_CANVAS (widget);
- GtkAllocation old_allocation;
+ GtkAllocation widg_allocation;
- gtk_widget_get_allocation(widget, &old_allocation);
+ gtk_widget_get_allocation (widget, &widg_allocation);
-// Geom::IntRect old_area = Geom::IntRect::from_xywh(canvas->_x0, canvas->_y0,
-// old_allocation.width, old_allocation.height);
+// Geom::IntRect old_area = Geom::IntRect::from_xywh(canvas->x0, canvas->y0,
+// widg_allocation.width, widg_allocation.height);
Geom::IntRect new_area = Geom::IntRect::from_xywh(canvas->_x0, canvas->_y0,
allocation->width, allocation->height);
- // resize backing store
- cairo_surface_t *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);
- cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
- cairo_set_source(cr, canvas->_background);
- cairo_paint(cr);
- cairo_set_source_surface(cr, canvas->_backing_store, canvas->_x0, canvas->_y0);
- cairo_paint(cr);
- cairo_destroy(cr);
- cairo_surface_destroy(canvas->_backing_store);
- }
- canvas->_backing_store = new_backing_store;
-
- // Clip the clean region to the new allocation
- cairo_rectangle_int_t crect = { canvas->_x0, canvas->_y0, allocation->width, allocation->height };
- cairo_region_intersect_rectangle(canvas->_clean_region, &crect);
-
- gtk_widget_set_allocation (widget, allocation);
-
+ // Schedule redraw of new region
+ canvas->resizeTiles(canvas->_x0, canvas->_y0, canvas->_x0 + allocation->width, canvas->_y0 + allocation->height);
if (SP_CANVAS_ITEM_GET_CLASS (canvas->_root)->viewbox_changed)
SP_CANVAS_ITEM_GET_CLASS (canvas->_root)->viewbox_changed (canvas->_root, new_area);
+ if (allocation->width > widg_allocation.width) {
+ canvas->requestRedraw(canvas->_x0 + widg_allocation.width,
+ 0,
+ canvas->_x0 + allocation->width,
+ canvas->_y0 + allocation->height);
+ }
+ if (allocation->height > widg_allocation.height) {
+ canvas->requestRedraw(0,
+ canvas->_y0 + widg_allocation.height,
+ canvas->_x0 + allocation->width,
+ canvas->_y0 + allocation->height);
+ }
+
+ gtk_widget_set_allocation (widget, allocation);
+
if (gtk_widget_get_realized (widget)) {
gdk_window_move_resize (gtk_widget_get_window (widget),
allocation->x, allocation->y,
allocation->width, allocation->height);
}
- // Schedule redraw of any newly exposed regions
- canvas->addIdle();
}
int SPCanvas::emitEvent(GdkEvent *event)
@@ -1539,23 +1526,48 @@ int SPCanvas::handle_motion(GtkWidget *widget, GdkEventMotion *event)
void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect const &canvas_rect, int /*sw*/)
{
+ GtkWidget *widget = GTK_WIDGET (this);
+
+ // Mark the region clean
+ markRect(paint_rect, 0);
+
SPCanvasBuf buf;
buf.buf = NULL;
buf.buf_rowstride = 0;
buf.rect = paint_rect;
buf.visible_rect = canvas_rect;
buf.is_empty = true;
+ //buf.ct = gdk_cairo_create(widget->window);
// create temporary surface
cairo_surface_t *imgs = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, paint_rect.width(), paint_rect.height());
buf.ct = cairo_create(imgs);
+ //cairo_translate(buf.ct, -x0, -y0);
+
+ // fix coordinates, clip all drawing to the tile and clear the background
+ //cairo_translate(buf.ct, paint_rect.left() - canvas->x0, paint_rect.top() - canvas->y0);
+ //cairo_rectangle(buf.ct, 0, 0, paint_rect.width(), paint_rect.height());
+ //cairo_set_line_width(buf.ct, 3);
+ //cairo_set_source_rgba(buf.ct, 1.0, 0.0, 0.0, 0.1);
+ //cairo_stroke_preserve(buf.ct);
+ //cairo_clip(buf.ct);
+
+#if GTK_CHECK_VERSION(3,0,0)
+ GtkStyleContext *context = gtk_widget_get_style_context(widget);
+ GdkRGBA color;
+ gtk_style_context_get_background_color(context,
+ gtk_widget_get_state_flags(widget),
+ &color);
+ gdk_cairo_set_source_rgba(buf.ct, &color);
+#else
+ GtkStyle *style = gtk_widget_get_style (widget);
+ gdk_cairo_set_source_color(buf.ct, &style->bg[GTK_STATE_NORMAL]);
+#endif
- cairo_save(buf.ct);
- cairo_translate(buf.ct, -paint_rect.left(), -paint_rect.top());
- cairo_set_source(buf.ct, _background);
cairo_set_operator(buf.ct, CAIRO_OPERATOR_SOURCE);
+ //cairo_rectangle(buf.ct, 0, 0, paint_rect.width(), paint_rec.height());
cairo_paint(buf.ct);
- cairo_restore(buf.ct);
+ cairo_set_operator(buf.ct, CAIRO_OPERATOR_OVER);
if (_root->visible) {
SP_CANVAS_ITEM_GET_CLASS(_root)->render(_root, &buf);
@@ -1588,8 +1600,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_t *xct = gdk_cairo_create(gtk_widget_get_window (widget));
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);
@@ -1598,12 +1609,6 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect
cairo_paint(xct);
cairo_destroy(xct);
cairo_surface_destroy(imgs);
-
- // Mark the painted rectangle clean
- markRect(paint_rect, 0);
-
- gtk_widget_queue_draw_area(GTK_WIDGET(this), paint_rect.left() -_x0, paint_rect.top() - _y0,
- paint_rect.width(), paint_rect.height());
}
struct PaintRectSetup {
@@ -1787,49 +1792,52 @@ void SPCanvas::endForcedFullRedraws()
_forced_redraw_limit = -1;
}
+#if GTK_CHECK_VERSION(3,0,0)
gboolean SPCanvas::handle_draw(GtkWidget *widget, cairo_t *cr) {
SPCanvas *canvas = SP_CANVAS(widget);
- // 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.
- cairo_set_source_surface(cr, canvas->_backing_store, 0, 0);
- cairo_paint(cr);
-
cairo_rectangle_list_t *rects = cairo_copy_clip_rectangle_list(cr);
- cairo_region_t *dirty_region = cairo_region_create();
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);
- 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);
- }
- cairo_rectangle_list_destroy(rects);
- cairo_region_subtract(dirty_region, canvas->_clean_region);
- // Render the dirty portion in the background
- if (!cairo_region_is_empty(dirty_region)) {
- canvas->addIdle();
+ Geom::IntRect r = Geom::IntRect::from_xywh(rectangle.x + canvas->_x0, rectangle.y + canvas->_y0,
+ rectangle.width, rectangle.height);
+
+ canvas->requestRedraw(r.left(), r.top(), r.right(), r.bottom());
}
- cairo_region_destroy(dirty_region);
- return TRUE;
+ cairo_rectangle_list_destroy(rects);
+
+ return FALSE;
}
-#if !GTK_CHECK_VERSION(3,0,0)
+#else
gboolean SPCanvas::handle_expose(GtkWidget *widget, GdkEventExpose *event)
{
- cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(widget));
+ SPCanvas *canvas = SP_CANVAS(widget);
+
+ if (!gtk_widget_is_drawable (widget) ||
+ (event->window != getWindow(canvas))) {
+ return FALSE;
+ }
+
+ int n_rects = 0;
+ GdkRectangle *rects = NULL;
+ gdk_region_get_rectangles(event->region, &rects, &n_rects);
- gdk_cairo_region (cr, event->region);
- cairo_clip (cr);
- gboolean result = SPCanvas::handle_draw(widget, cr);
+ if(rects == NULL)
+ return FALSE;
+
+ for (int i = 0; i < n_rects; i++) {
+ GdkRectangle rectangle = rects[i];
- cairo_destroy (cr);
+ Geom::IntRect r = Geom::IntRect::from_xywh(rectangle.x + canvas->_x0, rectangle.y + canvas->_y0,
+ rectangle.width, rectangle.height);
+
+ canvas->requestRedraw(r.left(), r.top(), r.right(), r.bottom());
+ }
- return result;
+ return FALSE;
}
#endif
@@ -1882,22 +1890,42 @@ int SPCanvas::paint()
_need_update = FALSE;
}
- GtkAllocation allocation;
- gtk_widget_get_allocation(GTK_WIDGET(this), &allocation);
- cairo_rectangle_int_t crect = { _x0, _y0, allocation.width, allocation.height };
- cairo_region_t *to_draw = cairo_region_create_rectangle(&crect);
- cairo_region_subtract(to_draw, _clean_region);
+ if (!_need_redraw) {
+ return TRUE;
+ }
- int n_rects = cairo_region_num_rectangles(to_draw);
- for (int i = 0; i < n_rects; ++i) {
- cairo_rectangle_int_t crect;
- cairo_region_get_rectangle(to_draw, i, &crect);
- if (!paintRect(crect.x, crect.y, crect.x + crect.width, crect.y + crect.height)) {
- // Aborted
- return FALSE;
- };
+ Cairo::RefPtr<Cairo::Region> to_paint = Cairo::Region::create();
+
+ for (int j = _tTop; j < _tBottom; ++j) {
+ for (int i = _tLeft; i < _tRight; ++i) {
+ int tile_index = (i - _tLeft) + (j - _tTop) * _tile_h;
+
+ if (_tiles[tile_index]) { // if this tile is dirtied (nonzero)
+ Cairo::RectangleInt rect = {i*TILE_SIZE, j*TILE_SIZE,
+ TILE_SIZE, TILE_SIZE};
+ to_paint->do_union(rect);
+ }
+ }
+ }
+
+ int n_rect = to_paint->get_num_rectangles();
+
+ if (n_rect > 0) {
+ for (int i=0; i < n_rect; i++) {
+ Cairo::RectangleInt rect = to_paint->get_rectangle(i);
+ int x0 = rect.x;
+ int y0 = rect.y;
+ int x1 = x0 + rect.width;
+ int y1 = y0 + rect.height;
+ if (!paintRect(x0, y0, x1, y1)) {
+ // Aborted
+ return FALSE;
+ };
+ }
}
+ _need_redraw = FALSE;
+
// we've had a full unaborted redraw, reset the full redraw counter
if (_forced_redraw_limit != -1) {
_forced_redraw_count = 0;
@@ -1976,41 +2004,15 @@ void SPCanvas::scrollTo(double cx, double cy, unsigned int clear, bool is_scroll
Geom::IntRect old_area = getViewboxIntegers();
Geom::IntRect new_area = old_area + Geom::IntPoint(dx, dy);
-
- gtk_widget_get_allocation(&_widget, &allocation);
-
- // 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_t *cr = cairo_create(new_backing_store);
- cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
- // Paint the background
- cairo_translate(cr, -ix, -iy);
- cairo_set_source(cr, _background);
- cairo_paint(cr);
- // Copy the old backing store contents
- cairo_set_source_surface(cr, _backing_store, _x0, _y0);
- cairo_rectangle(cr, _x0, _y0, allocation.width, allocation.height);
- cairo_clip(cr);
- cairo_paint(cr);
- cairo_destroy(cr);
- cairo_surface_destroy(_backing_store);
- _backing_store = new_backing_store;
-
+
_dx0 = cx; // here the 'd' stands for double, not delta!
_dy0 = cy;
_x0 = ix;
_y0 = iy;
- // Adjust the clean region
- if (clear) {
- dirtyAll();
- } else {
- cairo_rectangle_int_t crect = { _x0, _y0, allocation.width, allocation.height };
- cairo_region_intersect_rectangle(_clean_region, &crect);
- }
+ gtk_widget_get_allocation(&_widget, &allocation);
+ resizeTiles(_x0, _y0, _x0 + allocation.width, _y0 + allocation.height);
if (SP_CANVAS_ITEM_GET_CLASS(_root)->viewbox_changed) {
SP_CANVAS_ITEM_GET_CLASS(_root)->viewbox_changed(_root, new_area);
}
@@ -2018,17 +2020,19 @@ void SPCanvas::scrollTo(double cx, double cy, unsigned int clear, bool is_scroll
if (!clear) {
// scrolling without zoom; redraw only the newly exposed areas
if ((dx != 0) || (dy != 0)) {
+ this->_is_scrolling = is_scrolling;
if (gtk_widget_get_realized(GTK_WIDGET(this))) {
gdk_window_scroll(getWindow(this), -dx, -dy);
}
}
+ } else {
+ // scrolling as part of zoom; do nothing here - the next do_update will perform full redraw
}
- addIdle();
}
void SPCanvas::updateNow()
{
- if (_need_update) {
+ if (_need_update || _need_redraw) {
doUpdate();
}
}
@@ -2041,45 +2045,26 @@ void SPCanvas::requestUpdate()
void SPCanvas::requestRedraw(int x0, int y0, int x1, int y1)
{
+ GtkAllocation allocation;
+
if (!gtk_widget_is_drawable( GTK_WIDGET(this) )) {
return;
}
- if (x0 >= x1 || y0 >= y1) {
+ if ((x0 >= x1) || (y0 >= y1)) {
return;
}
Geom::IntRect bbox(x0, y0, x1, y1);
- dirtyRect(bbox);
- addIdle();
-}
-
-void SPCanvas::setBackgroundColor(guint32 rgba) {
- double new_r = SP_RGBA32_R_F(rgba);
- double new_g = SP_RGBA32_G_F(rgba);
- double new_b = SP_RGBA32_B_F(rgba);
- if (!_background_is_checkerboard) {
- double old_r, old_g, old_b;
- cairo_pattern_get_rgba(_background, &old_r, &old_g, &old_b, NULL);
- if (new_r == old_r && new_g == old_g && new_b == old_b) return;
- }
- if (_background) {
- cairo_pattern_destroy(_background);
- }
- _background = cairo_pattern_create_rgb(new_r, new_g, new_b);
- _background_is_checkerboard = false;
- dirtyAll();
- addIdle();
-}
+ gtk_widget_get_allocation(GTK_WIDGET(this), &allocation);
-void SPCanvas::setBackgroundCheckerboard() {
- if (_background_is_checkerboard) return;
- if (_background) {
- cairo_pattern_destroy(_background);
+ Geom::IntRect canvas_rect = Geom::IntRect::from_xywh(this->_x0, this->_y0,
+ allocation.width, allocation.height);
+
+ Geom::OptIntRect clip = bbox & canvas_rect;
+ if (clip) {
+ dirtyRect(*clip);
+ addIdle();
}
- _background = ink_cairo_pattern_create_checkerboard();
- _background_is_checkerboard = true;
- dirtyAll();
- addIdle();
}
/**
@@ -2183,24 +2168,63 @@ inline int sp_canvas_tile_ceil(int x)
return ((x + (TILE_SIZE - 1)) & (~(TILE_SIZE - 1))) / TILE_SIZE;
}
-void SPCanvas::dirtyRect(Geom::IntRect const &area) {
- markRect(area, 1);
+void SPCanvas::resizeTiles(int nl, int nt, int nr, int nb)
+{
+ if ( nl >= nr || nt >= nb ) {
+ if (_tiles) g_free(_tiles);
+ _tLeft = _tTop = _tRight = _tBottom = 0;
+ _tile_h = _tile_h = 0;
+ _tiles = NULL;
+ return;
+ }
+ int tl = sp_canvas_tile_floor(nl);
+ int tt = sp_canvas_tile_floor(nt);
+ int tr = sp_canvas_tile_ceil(nr);
+ int tb = sp_canvas_tile_ceil(nb);
+
+ int nh = tr-tl, nv = tb-tt;
+ uint8_t *ntiles = (uint8_t*) g_malloc(nh * nv * sizeof(uint8_t));
+ for (int i = tl; i < tr; i++) {
+ for (int j = tt; j < tb; j++) {
+ int ind = (i-tl) + (j-tt)*nh;
+ if ( i >= _tLeft && i < _tRight && j >= _tTop && j < _tBottom ) {
+ ntiles[ind] = _tiles[(i - _tLeft) + (j - _tTop) * _tile_h]; // copy from the old tile
+ } else {
+ ntiles[ind] = 0; // newly exposed areas get 0
+ }
+ }
+ }
+ if (_tiles) g_free(_tiles);
+ _tiles = ntiles;
+ _tLeft = tl;
+ _tTop = tt;
+ _tRight = tr;
+ _tBottom = tb;
+ _tile_h = nh;
+ _tile_h = nv;
}
-void SPCanvas::dirtyAll() {
- if (_clean_region && !cairo_region_is_empty(_clean_region)) {
- cairo_region_destroy(_clean_region);
- _clean_region = cairo_region_create();
- }
+void SPCanvas::dirtyRect(Geom::IntRect const &area) {
+ _need_redraw = TRUE;
+ markRect(area, 1);
}
void SPCanvas::markRect(Geom::IntRect const &area, uint8_t val)
{
- cairo_rectangle_int_t crect = { area.left(), area.top(), area.width(), area.height() };
- if (val) {
- cairo_region_subtract_rectangle(_clean_region, &crect);
- } else {
- cairo_region_union_rectangle(_clean_region, &crect);
+ int tl = sp_canvas_tile_floor(area.left());
+ int tt = sp_canvas_tile_floor(area.top());
+ int tr = sp_canvas_tile_ceil(area.right());
+ int tb = sp_canvas_tile_ceil(area.bottom());
+ if ( tl >= _tRight || tr <= _tLeft || tt >= _tBottom || tb <= _tTop ) return;
+ if ( tl < _tLeft ) tl = _tLeft;
+ if ( tr > _tRight ) tr = _tRight;
+ if ( tt < _tTop ) tt = _tTop;
+ if ( tb > _tBottom ) tb = _tBottom;
+
+ for (int i=tl; i<tr; i++) {
+ for (int j=tt; j<tb; j++) {
+ _tiles[(i - _tLeft) + (j - _tTop) * _tile_h] = val;
+ }
}
}
diff --git a/src/display/sp-canvas.h b/src/display/sp-canvas.h
index 171fdaf67..1a13250b3 100644
--- a/src/display/sp-canvas.h
+++ b/src/display/sp-canvas.h
@@ -11,11 +11,9 @@
* Raph Levien <raph@gimp.org>
* Lauris Kaplinski <lauris@kaplinski.com>
* Jon A. Cruz <jon@joncruz.org>
- * Krzysztof Kosiński <tweenk.pl@gmail.com>
*
* Copyright (C) 1998 The Free Software Foundation
* Copyright (C) 2002 Lauris Kaplinski
- * Copyright (C) 2016 Google Inc.
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
@@ -87,9 +85,6 @@ struct SPCanvas {
Geom::IntRect getViewboxIntegers() const;
SPCanvasGroup *getRoot();
- void setBackgroundColor(guint32 rgba);
- void setBackgroundCheckerboard();
-
/// Returns new canvas as widget.
static GtkWidget *createAA();
@@ -108,8 +103,7 @@ private:
/// Marks the specified area as dirty (requiring redraw)
void dirtyRect(Geom::IntRect const &area);
- /// Marks the whole widget for redraw
- void dirtyAll();
+ /// Marks specific canvas rectangle as clean (val == 0) or dirty (otherwise)
void markRect(Geom::IntRect const &area, uint8_t val);
/// Invokes update, paint, and repick on canvas.
@@ -161,8 +155,9 @@ public:
*/
static gint handle_scroll(GtkWidget *widget, GdkEventScroll *event);
static gint handle_motion(GtkWidget *widget, GdkEventMotion *event);
+#if GTK_CHECK_VERSION(3,0,0)
static gboolean handle_draw(GtkWidget *widget, cairo_t *cr);
-#if !GTK_CHECK_VERSION(3,0,0)
+#else
static gboolean handle_expose(GtkWidget *widget, GdkEventExpose *event);
#endif
static gint handle_key_event(GtkWidget *widget, GdkEventKey *event);
@@ -181,18 +176,15 @@ public:
bool _is_dragging;
double _dx0;
double _dy0;
- int _x0; ///< World coordinate of the leftmost pixels
- int _y0; ///< World coordinate of the topmost pixels
-
- /// Image surface storing the contents of the widget
- cairo_surface_t *_backing_store;
- /// Area of the widget that has up-to-date content
- cairo_region_t *_clean_region;
- /// Widget background, defaults to white
- cairo_pattern_t *_background;
- bool _background_is_checkerboard;
-
- /// Last known modifier state, for deferred repick when a button is down.
+ int _x0;
+ int _y0;
+
+ /* Area that needs redrawing, stored as a microtile array */
+ int _tLeft, _tTop, _tRight, _tBottom;
+ int _tile_w, _tile_h;
+ uint8_t *_tiles;
+
+ /** Last known modifier state, for deferred repick when a button is down. */
int _state;
/** The item containing the mouse pointer, or NULL if none. */
@@ -216,6 +208,7 @@ public:
int _close_enough;
unsigned int _need_update : 1;
+ unsigned int _need_redraw : 1;
unsigned int _need_repick : 1;
int _forced_redraw_count;