From 9d028413f98d61937750f633703ad3de2eee1fad Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Mon, 11 Apr 2016 15:15:17 +0200 Subject: Fix feTile rendering bug with Krzysztof's help. Hackfest 2016. (bzr r14777) --- src/display/nr-filter-tile.cpp | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'src/display') diff --git a/src/display/nr-filter-tile.cpp b/src/display/nr-filter-tile.cpp index 913812828..7172f88ee 100644 --- a/src/display/nr-filter-tile.cpp +++ b/src/display/nr-filter-tile.cpp @@ -126,11 +126,8 @@ void FilterTile::render_cairo(FilterSlot &slot) void FilterTile::area_enlarge(Geom::IntRect &area, Geom::Affine const &trans) { - // We need to enlarge enough to get tile source... we don't the area of the source tile in this - // function so we guess. This is VERY inefficient. - Geom::Point enlarge(200, 200); - enlarge *= trans; - area.expandBy( enlarge[Geom::X] < 100 ? 100: enlarge[Geom::X] ); + // Set to infinite rectangle so we get tile source. It will be clipped later. + area = Geom::IntRect::infinite(); } double FilterTile::complexity(Geom::Affine const &) -- cgit v1.2.3 From a907096a990015010ec1171cd8997d33951f28a2 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Tue, 12 Apr 2016 11:35:15 +0100 Subject: Hackfest 2016: un-obfuscate the SPCanvas widget. (bzr r14790) --- src/display/sp-canvas.cpp | 898 ++++++++++++++++++---------------------------- src/display/sp-canvas.h | 183 ++++++---- 2 files changed, 472 insertions(+), 609 deletions(-) (limited to 'src/display') diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index 81ea7d142..df84e379c 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -173,159 +173,8 @@ bool is_descendant(SPCanvasItem const *item, SPCanvasItem const *parent); guint item_signals[ITEM_LAST_SIGNAL] = { 0 }; -struct PaintRectSetup; - } // namespace -class SPCanvasImpl -{ -public: - - /** - * Helper that emits an event for an item in the canvas, be it the current - * item, grabbed item, or focused item, as appropriate. - */ - static int emitEvent(SPCanvas *canvas, GdkEvent *event); - - /** - * Helper that re-picks the current item in the canvas, based on the event's - * coordinates and emits enter/leave events for items as appropriate. - */ - static int pickCurrentItem(SPCanvas *canvas, GdkEvent *event); - - /** - * The canvas widget's realize callback. - */ - static void realize(GtkWidget *widget); - - /** - * The canvas widget's unrealize callback. - */ - static void unrealize(GtkWidget *widget); - - /** - * The canvas widget's size request callback. - */ -#if GTK_CHECK_VERSION(3,0,0) - static void getPreferredWidth(GtkWidget *widget, gint *min_w, gint *nat_w); - static void getPreferredHeight(GtkWidget *widget, gint *min_h, gint *nat_h); -#else - static void sizeRequest(GtkWidget *widget, GtkRequisition *req); -#endif - - /** - * The canvas widget's size allocate callback. - */ - static void sizeAllocate(GtkWidget *widget, GtkAllocation *allocation); - - /** - * Button event handler for the canvas. - */ - static gint button(GtkWidget *widget, GdkEventButton *event); - - /** - * Scroll event handler for the canvas. - * - * @todo FIXME: generate motion events to re-select items. - */ - static gint handleScroll(GtkWidget *widget, GdkEventScroll *event); - - /** - * Motion event handler for the canvas. - */ - static gint handleMotion(GtkWidget *widget, GdkEventMotion *event); - - /** - * The canvas widget's expose callback. - * - * @todo FIXME: function allways retruns false. - */ -#if GTK_CHECK_VERSION(3,0,0) - static gboolean handleDraw(GtkWidget *widget, cairo_t *cr); -#else - static gboolean handleExpose(GtkWidget *widget, GdkEventExpose *event); -#endif - - /** - * The canvas widget's keypress callback. - */ - static gint handleKeyEvent(GtkWidget *widget, GdkEventKey *event); - - /** - * Crossing event handler for the canvas. - */ - static gint handleCrossing(GtkWidget *widget, GdkEventCrossing *event); - - /** - * Focus in handler for the canvas. - */ - static gint handleFocusIn(GtkWidget *widget, GdkEventFocus *event); - - /** - * Focus out handler for the canvas. - */ - static gint handleFocusOut(GtkWidget *widget, GdkEventFocus *event); - - /** - * Helper that allocates a new tile array for the canvas, copying overlapping tiles from the old array - */ - static void sp_canvas_resize_tiles(SPCanvas* canvas, int nl, int nt, int nr, int nb); - - /** - * Helper that queues a canvas rectangle for redraw - */ - static void sp_canvas_dirty_rect(SPCanvas* canvas, Geom::IntRect const &area); - - /** - * Helper that marks specific canvas rectangle as clean (val == 0) or dirty (otherwise) - */ - static void sp_canvas_mark_rect(SPCanvas* canvas, Geom::IntRect const &area, uint8_t val); - - /** - * Helper that invokes update, paint, and repick on canvas. - */ - static int do_update(SPCanvas *canvas); - - static void sp_canvas_paint_single_buffer(SPCanvas *canvas, Geom::IntRect const &paint_rect, Geom::IntRect const &canvas_rect, int sw); - - /** - * Paint the given rect, recursively subdividing the region until it is the size of a single - * buffer. - * - * @return true if the drawing completes - */ - static int sp_canvas_paint_rect_internal(PaintRectSetup const *setup, Geom::IntRect const &this_rect); - - /** - * Helper that draws a specific rectangular part of the canvas. - * - * @return true if the rectangle painting succeeds. - */ - static bool sp_canvas_paint_rect(SPCanvas *canvas, int xx0, int yy0, int xx1, int yy1); - - /** - * Helper that repaints the areas in the canvas that need it. - * - * @return true if all the dirty parts have been redrawn - */ - static int paint(SPCanvas *canvas); - - /** - * Idle handler for the canvas that deals with pending updates and redraws. - */ - static gint idle_handler(gpointer data); - - /** - * Convenience function to add an idle handler to a canvas. - */ - static void add_idle(SPCanvas *canvas); - - /** - * Update callback for canvas widget. - */ - static void requestCanvasUpdate(SPCanvas *canvas); -}; - G_DEFINE_TYPE(SPCanvasItem, sp_canvas_item, G_TYPE_INITIALLY_UNOWNED); static void @@ -456,18 +305,18 @@ void sp_canvas_item_dispose(GObject *object) } item->visible = FALSE; - if (item == item->canvas->current_item) { - item->canvas->current_item = NULL; - item->canvas->need_repick = TRUE; + if (item == item->canvas->_current_item) { + item->canvas->_current_item = NULL; + item->canvas->_need_repick = TRUE; } - if (item == item->canvas->new_current_item) { - item->canvas->new_current_item = NULL; - item->canvas->need_repick = TRUE; + if (item == item->canvas->_new_current_item) { + item->canvas->_new_current_item = NULL; + item->canvas->_need_repick = TRUE; } - if (item == item->canvas->grabbed_item) { - item->canvas->grabbed_item = NULL; + if (item == item->canvas->_grabbed_item) { + item->canvas->_grabbed_item = NULL; #if GTK_CHECK_VERSION(3,0,0) GdkDeviceManager *dm = gdk_display_get_device_manager(gdk_display_get_default()); @@ -478,8 +327,8 @@ void sp_canvas_item_dispose(GObject *object) #endif } - if (item == item->canvas->focused_item) { - item->canvas->focused_item = NULL; + if (item == item->canvas->_focused_item) { + item->canvas->_focused_item = NULL; } if (item->parent) { @@ -577,11 +426,11 @@ void sp_canvas_item_affine_absolute(SPCanvasItem *item, Geom::Affine const &affi if (item->parent != NULL) { sp_canvas_item_request_update (item->parent); } else { - SPCanvasImpl::requestCanvasUpdate(item->canvas); + item->canvas->requestUpdate(); } } - item->canvas->need_repick = TRUE; + item->canvas->_need_repick = TRUE; } /** @@ -614,7 +463,7 @@ void sp_canvas_item_raise(SPCanvasItem *item, int positions) parent->items.insert(l, item); redraw_if_visible (item); - item->canvas->need_repick = TRUE; + item->canvas->_need_repick = TRUE; } void sp_canvas_item_raise_to_top(SPCanvasItem *item) @@ -627,7 +476,7 @@ void sp_canvas_item_raise_to_top(SPCanvasItem *item) parent->items.remove(item); parent->items.push_back(item); redraw_if_visible (item); - item->canvas->need_repick = TRUE; + item->canvas->_need_repick = TRUE; } @@ -663,7 +512,7 @@ void sp_canvas_item_lower(SPCanvasItem *item, int positions) parent->items.insert(l, item); redraw_if_visible (item); - item->canvas->need_repick = TRUE; + item->canvas->_need_repick = TRUE; } void sp_canvas_item_lower_to_bottom(SPCanvasItem *item) @@ -676,7 +525,7 @@ void sp_canvas_item_lower_to_bottom(SPCanvasItem *item) parent->items.remove(item); parent->items.push_front(item); redraw_if_visible (item); - item->canvas->need_repick = TRUE; + item->canvas->_need_repick = TRUE; } bool sp_canvas_item_is_visible(SPCanvasItem *item) @@ -705,7 +554,7 @@ void sp_canvas_item_show(SPCanvasItem *item) if (x0 !=0 || x1 !=0 || y0 !=0 || y1 !=0) { item->canvas->requestRedraw((int)(item->x1), (int)(item->y1), (int)(item->x2 + 1), (int)(item->y2 + 1)); - item->canvas->need_repick = TRUE; + item->canvas->_need_repick = TRUE; } } @@ -730,7 +579,7 @@ void sp_canvas_item_hide(SPCanvasItem *item) if (x0 !=0 || x1 !=0 || y0 !=0 || y1 !=0) { item->canvas->requestRedraw((int)item->x1, (int)item->y1, (int)(item->x2 + 1), (int)(item->y2 + 1)); - item->canvas->need_repick = TRUE; + item->canvas->_need_repick = TRUE; } } @@ -745,7 +594,7 @@ int sp_canvas_item_grab(SPCanvasItem *item, guint event_mask, GdkCursor *cursor, g_return_val_if_fail (SP_IS_CANVAS_ITEM (item), -1); g_return_val_if_fail (gtk_widget_get_mapped (GTK_WIDGET (item->canvas)), -1); - if (item->canvas->grabbed_item) { + if (item->canvas->_grabbed_item) { return -1; } @@ -780,9 +629,9 @@ int sp_canvas_item_grab(SPCanvasItem *item, guint event_mask, GdkCursor *cursor, NULL, cursor, etime); #endif - item->canvas->grabbed_item = item; - item->canvas->grabbed_event_mask = event_mask; - item->canvas->current_item = item; // So that events go to the grabbed item + item->canvas->_grabbed_item = item; + item->canvas->_grabbed_event_mask = event_mask; + item->canvas->_current_item = item; // So that events go to the grabbed item return 0; } @@ -799,11 +648,11 @@ void sp_canvas_item_ungrab(SPCanvasItem *item, guint32 etime) g_return_if_fail (item != NULL); g_return_if_fail (SP_IS_CANVAS_ITEM (item)); - if (item->canvas->grabbed_item != item) { + if (item->canvas->_grabbed_item != item) { return; } - item->canvas->grabbed_item = NULL; + item->canvas->_grabbed_item = NULL; #if GTK_CHECK_VERSION(3,0,0) GdkDeviceManager *dm = gdk_display_get_device_manager(gdk_display_get_default()); @@ -865,7 +714,7 @@ void sp_canvas_item_request_update(SPCanvasItem *item) sp_canvas_item_request_update (item->parent); } else { // Have reached the top of the tree, make sure the update call gets scheduled. - SPCanvasImpl::requestCanvasUpdate(item->canvas); + item->canvas->requestUpdate(); } } @@ -955,10 +804,10 @@ double SPCanvasGroup::point(SPCanvasItem *item, Geom::Point p, SPCanvasItem **ac SPCanvasGroup const *group = SP_CANVAS_GROUP(item); double const x = p[Geom::X]; double const y = p[Geom::Y]; - int x1 = (int)(x - item->canvas->close_enough); - int y1 = (int)(y - item->canvas->close_enough); - int x2 = (int)(x + item->canvas->close_enough); - int y2 = (int)(y + item->canvas->close_enough); + int x1 = (int)(x - item->canvas->_close_enough); + int y1 = (int)(y - item->canvas->_close_enough); + int x2 = (int)(x + item->canvas->_close_enough); + int y2 = (int)(y + item->canvas->_close_enough); double best = 0.0; *actual_item = NULL; @@ -984,7 +833,7 @@ double SPCanvasGroup::point(SPCanvasItem *item, Geom::Point p, SPCanvasItem **ac // of the item to be focused, and have that one selected. Of course this will only work if the // centers are not coincident, but at least it's better than what we have now. // See the extensive comment in Inkscape::SelTrans::_updateHandles() - if (pickable && point_item && ((int) (dist + 0.5) <= item->canvas->close_enough)) { + if (pickable && point_item && ((int) (dist + 0.5) <= item->canvas->_close_enough)) { best = dist; *actual_item = point_item; } @@ -1049,135 +898,117 @@ void SPCanvasGroup::remove(SPCanvasItem *item) } -static void sp_canvas_dispose (GObject *object); -static void sp_canvas_shutdown_transients(SPCanvas *canvas); - G_DEFINE_TYPE(SPCanvas, sp_canvas, GTK_TYPE_WIDGET); -static void -sp_canvas_class_init(SPCanvasClass *klass) +void sp_canvas_class_init(SPCanvasClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS(klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); - object_class->dispose = sp_canvas_dispose; + object_class->dispose = SPCanvas::dispose; - widget_class->realize = SPCanvasImpl::realize; - widget_class->unrealize = SPCanvasImpl::unrealize; + widget_class->realize = SPCanvas::handle_realize; + widget_class->unrealize = SPCanvas::handle_unrealize; #if GTK_CHECK_VERSION(3,0,0) - widget_class->get_preferred_width = SPCanvasImpl::getPreferredWidth; - widget_class->get_preferred_height = SPCanvasImpl::getPreferredHeight; - widget_class->draw = SPCanvasImpl::handleDraw; + widget_class->get_preferred_width = SPCanvas::handle_get_preferred_width; + widget_class->get_preferred_height = SPCanvas::handle_get_preferred_height; + widget_class->draw = SPCanvas::handle_draw; #else - widget_class->size_request = SPCanvasImpl::sizeRequest; - widget_class->expose_event = SPCanvasImpl::handleExpose; + widget_class->size_request = SPCanvas::handle_size_request; + widget_class->expose_event = SPCanvas::handle_expose; #endif - widget_class->size_allocate = SPCanvasImpl::sizeAllocate; - widget_class->button_press_event = SPCanvasImpl::button; - widget_class->button_release_event = SPCanvasImpl::button; - widget_class->motion_notify_event = SPCanvasImpl::handleMotion; - widget_class->scroll_event = SPCanvasImpl::handleScroll; - widget_class->key_press_event = SPCanvasImpl::handleKeyEvent; - widget_class->key_release_event = SPCanvasImpl::handleKeyEvent; - widget_class->enter_notify_event = SPCanvasImpl::handleCrossing; - widget_class->leave_notify_event = SPCanvasImpl::handleCrossing; - widget_class->focus_in_event = SPCanvasImpl::handleFocusIn; - widget_class->focus_out_event = SPCanvasImpl::handleFocusOut; + widget_class->size_allocate = SPCanvas::handle_size_allocate; + widget_class->button_press_event = SPCanvas::handle_button; + widget_class->button_release_event = SPCanvas::handle_button; + widget_class->motion_notify_event = SPCanvas::handle_motion; + widget_class->scroll_event = SPCanvas::handle_scroll; + widget_class->key_press_event = SPCanvas::handle_key_event; + widget_class->key_release_event = SPCanvas::handle_key_event; + widget_class->enter_notify_event = SPCanvas::handle_crossing; + widget_class->leave_notify_event = SPCanvas::handle_crossing; + widget_class->focus_in_event = SPCanvas::handle_focus_in; + widget_class->focus_out_event = SPCanvas::handle_focus_out; } -static void -sp_canvas_init(SPCanvas *canvas) +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; - canvas->pick_event.crossing.x = 0; - canvas->pick_event.crossing.y = 0; + canvas->_pick_event.type = GDK_LEAVE_NOTIFY; + canvas->_pick_event.crossing.x = 0; + canvas->_pick_event.crossing.y = 0; // Create the root item as a special case - canvas->root = SP_CANVAS_ITEM(g_object_new(SP_TYPE_CANVAS_GROUP, NULL)); - canvas->root->canvas = canvas; + canvas->_root = SP_CANVAS_ITEM(g_object_new(SP_TYPE_CANVAS_GROUP, NULL)); + canvas->_root->canvas = canvas; - g_object_ref (canvas->root); - g_object_ref_sink (canvas->root); + g_object_ref (canvas->_root); + g_object_ref_sink (canvas->_root); - canvas->need_repick = TRUE; + canvas->_need_repick = TRUE; // See comment at in sp-canvas.h. - canvas->gen_all_enter_events = false; + canvas->_gen_all_enter_events = false; - canvas->drawing_disabled = false; + canvas->_drawing_disabled = false; - canvas->tiles=NULL; - canvas->tLeft=canvas->tTop=canvas->tRight=canvas->tBottom=0; - canvas->tileH=canvas->tileV=0; + 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; + canvas->_forced_redraw_count = 0; + canvas->_forced_redraw_limit = -1; #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - canvas->enable_cms_display_adj = false; - new (&canvas->cms_key) Glib::ustring(""); + canvas->_enable_cms_display_adj = false; + new (&canvas->_cms_key) Glib::ustring(""); #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - canvas->is_scrolling = false; + canvas->_is_scrolling = false; } -static void sp_canvas_remove_idle(SPCanvas *canvas) -{ - if (canvas->idle_id) { - g_source_remove (canvas->idle_id); - canvas->idle_id = 0; - } -} - -static void -sp_canvas_shutdown_transients(SPCanvas *canvas) +void SPCanvas::shutdownTransients() { // 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. // - if (canvas->need_redraw) { - canvas->need_redraw = FALSE; - } - if ( canvas->tiles ) g_free(canvas->tiles); - canvas->tiles=NULL; - canvas->tLeft=canvas->tTop=canvas->tRight=canvas->tBottom=0; - canvas->tileH=canvas->tileV=0; - - if (canvas->grabbed_item) { - canvas->grabbed_item = NULL; + _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; #if GTK_CHECK_VERSION(3,0,0) GdkDeviceManager *dm = gdk_display_get_device_manager(gdk_display_get_default()); GdkDevice *device = gdk_device_manager_get_client_pointer(dm); gdk_device_ungrab(device, GDK_CURRENT_TIME); #else - gdk_pointer_ungrab (GDK_CURRENT_TIME); + gdk_pointer_ungrab(GDK_CURRENT_TIME); #endif } - - sp_canvas_remove_idle(canvas); + removeIdle(); } -static void -sp_canvas_dispose(GObject *object) +void SPCanvas::dispose(GObject *object) { SPCanvas *canvas = SP_CANVAS(object); - if (canvas->root) { - g_object_unref (canvas->root); - canvas->root = NULL; + if (canvas->_root) { + g_object_unref (canvas->_root); + canvas->_root = NULL; } - sp_canvas_shutdown_transients(canvas); + canvas->shutdownTransients(); #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - canvas->cms_key.~ustring(); + canvas->_cms_key.~ustring(); #endif if (G_OBJECT_CLASS(sp_canvas_parent_class)->dispose) { (* G_OBJECT_CLASS(sp_canvas_parent_class)->dispose)(object); @@ -1203,7 +1034,7 @@ GtkWidget *SPCanvas::createAA() return GTK_WIDGET(canvas); } -void SPCanvasImpl::realize(GtkWidget *widget) +void SPCanvas::handle_realize(GtkWidget *widget) { GdkWindowAttr attributes; GtkAllocation allocation; @@ -1264,15 +1095,15 @@ void SPCanvasImpl::realize(GtkWidget *widget) gtk_widget_set_realized (widget, TRUE); } -void SPCanvasImpl::unrealize(GtkWidget *widget) +void SPCanvas::handle_unrealize(GtkWidget *widget) { SPCanvas *canvas = SP_CANVAS (widget); - canvas->current_item = NULL; - canvas->grabbed_item = NULL; - canvas->focused_item = NULL; + canvas->_current_item = NULL; + canvas->_grabbed_item = NULL; + canvas->_focused_item = NULL; - sp_canvas_shutdown_transients(canvas); + canvas->shutdownTransients(); if (GTK_WIDGET_CLASS(sp_canvas_parent_class)->unrealize) (* GTK_WIDGET_CLASS(sp_canvas_parent_class)->unrealize)(widget); @@ -1280,21 +1111,21 @@ void SPCanvasImpl::unrealize(GtkWidget *widget) #if GTK_CHECK_VERSION(3,0,0) -void SPCanvasImpl::getPreferredWidth(GtkWidget *widget, gint *minimum_width, gint *natural_width) +void SPCanvas::handle_get_preferred_width(GtkWidget *widget, gint *minimum_width, gint *natural_width) { static_cast(SP_CANVAS (widget)); *minimum_width = 256; *natural_width = 256; } -void SPCanvasImpl::getPreferredHeight(GtkWidget *widget, gint *minimum_height, gint *natural_height) +void SPCanvas::handle_get_preferred_height(GtkWidget *widget, gint *minimum_height, gint *natural_height) { static_cast(SP_CANVAS (widget)); *minimum_height = 256; *natural_height = 256; } #else -void SPCanvasImpl::sizeRequest(GtkWidget *widget, GtkRequisition *req) +void SPCanvas::handle_size_request(GtkWidget *widget, GtkRequisition *req) { static_cast(SP_CANVAS (widget)); @@ -1304,7 +1135,7 @@ void SPCanvasImpl::sizeRequest(GtkWidget *widget, GtkRequisition *req) #endif -void SPCanvasImpl::sizeAllocate(GtkWidget *widget, GtkAllocation *allocation) +void SPCanvas::handle_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { SPCanvas *canvas = SP_CANVAS (widget); GtkAllocation widg_allocation; @@ -1314,25 +1145,25 @@ void SPCanvasImpl::sizeAllocate(GtkWidget *widget, GtkAllocation *allocation) // 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, + Geom::IntRect new_area = Geom::IntRect::from_xywh(canvas->_x0, canvas->_y0, allocation->width, allocation->height); // Schedule redraw of new region - sp_canvas_resize_tiles(canvas,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); - + 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, + canvas->requestRedraw(canvas->_x0 + widg_allocation.width, 0, - canvas->x0 + allocation->width, - canvas->y0 + allocation->height); + 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); + canvas->_y0 + widg_allocation.height, + canvas->_x0 + allocation->width, + canvas->_y0 + allocation->height); } gtk_widget_set_allocation (widget, allocation); @@ -1344,11 +1175,11 @@ void SPCanvasImpl::sizeAllocate(GtkWidget *widget, GtkAllocation *allocation) } } -int SPCanvasImpl::emitEvent(SPCanvas *canvas, GdkEvent *event) +int SPCanvas::emitEvent(GdkEvent *event) { guint mask; - if (canvas->grabbed_item) { + if (_grabbed_item) { switch (event->type) { case GDK_ENTER_NOTIFY: mask = GDK_ENTER_NOTIFY_MASK; @@ -1384,7 +1215,7 @@ int SPCanvasImpl::emitEvent(SPCanvas *canvas, GdkEvent *event) break; } - if (!(mask & canvas->grabbed_event_mask)) return FALSE; + if (!(mask & _grabbed_event_mask)) return FALSE; } // Convert to world coordinates -- we have two cases because of different @@ -1395,25 +1226,25 @@ int SPCanvasImpl::emitEvent(SPCanvas *canvas, GdkEvent *event) switch (ev->type) { case GDK_ENTER_NOTIFY: case GDK_LEAVE_NOTIFY: - ev->crossing.x += canvas->x0; - ev->crossing.y += canvas->y0; + ev->crossing.x += _x0; + ev->crossing.y += _y0; break; case GDK_MOTION_NOTIFY: case GDK_BUTTON_PRESS: case GDK_2BUTTON_PRESS: case GDK_3BUTTON_PRESS: case GDK_BUTTON_RELEASE: - ev->motion.x += canvas->x0; - ev->motion.y += canvas->y0; + ev->motion.x += _x0; + ev->motion.y += _y0; break; default: break; } // Block Undo and Redo while we drag /anything/ if(event->type == GDK_BUTTON_PRESS && event->button.button == 1) - canvas->is_dragging = true; + _is_dragging = true; else if(event->type == GDK_BUTTON_RELEASE) - canvas->is_dragging = false; + _is_dragging = false; // Choose where we send the event @@ -1422,17 +1253,17 @@ int SPCanvasImpl::emitEvent(SPCanvas *canvas, GdkEvent *event) // Lauris applied to SP to get around the problem. // SPCanvasItem* item = NULL; - if (canvas->grabbed_item && !is_descendant (canvas->current_item, canvas->grabbed_item)) { - item = canvas->grabbed_item; + if (_grabbed_item && !is_descendant(_current_item, _grabbed_item)) { + item = _grabbed_item; } else { - item = canvas->current_item; + item = _current_item; } - if (canvas->focused_item && + if (_focused_item && ((event->type == GDK_KEY_PRESS) || (event->type == GDK_KEY_RELEASE) || (event->type == GDK_FOCUS_CHANGE))) { - item = canvas->focused_item; + item = _focused_item; } // The event is propagated up the hierarchy (for if someone connected to @@ -1454,24 +1285,24 @@ int SPCanvasImpl::emitEvent(SPCanvas *canvas, GdkEvent *event) return finished; } -int SPCanvasImpl::pickCurrentItem(SPCanvas *canvas, GdkEvent *event) +int SPCanvas::pickCurrentItem(GdkEvent *event) { int button_down = 0; - if (!canvas->root) // canvas may have already be destroyed by closing desktop during interrupted display! + if (!_root) // canvas may have already be destroyed by closing desktop during interrupted display! return FALSE; int retval = FALSE; - if (canvas->gen_all_enter_events == false) { + if (_gen_all_enter_events == false) { // If a button is down, we'll perform enter and leave events on the // current item, but not enter on any other item. This is more or // less like X pointer grabbing for canvas items. // - button_down = canvas->state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | + button_down = _state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK | GDK_BUTTON4_MASK | GDK_BUTTON5_MASK); - if (!button_down) canvas->left_grabbed_item = FALSE; + if (!button_down) _left_grabbed_item = FALSE; } // Save the event in the canvas. This is used to synthesize enter and @@ -1479,116 +1310,115 @@ int SPCanvasImpl::pickCurrentItem(SPCanvas *canvas, GdkEvent *event) // re-pick the current item if the current one gets deleted. Also, // synthesize an enter event. - if (event != &canvas->pick_event) { + if (event != &_pick_event) { if ((event->type == GDK_MOTION_NOTIFY) || (event->type == GDK_BUTTON_RELEASE)) { // these fields have the same offsets in both types of events - canvas->pick_event.crossing.type = GDK_ENTER_NOTIFY; - canvas->pick_event.crossing.window = event->motion.window; - canvas->pick_event.crossing.send_event = event->motion.send_event; - canvas->pick_event.crossing.subwindow = NULL; - canvas->pick_event.crossing.x = event->motion.x; - canvas->pick_event.crossing.y = event->motion.y; - canvas->pick_event.crossing.mode = GDK_CROSSING_NORMAL; - canvas->pick_event.crossing.detail = GDK_NOTIFY_NONLINEAR; - canvas->pick_event.crossing.focus = FALSE; - canvas->pick_event.crossing.state = event->motion.state; + _pick_event.crossing.type = GDK_ENTER_NOTIFY; + _pick_event.crossing.window = event->motion.window; + _pick_event.crossing.send_event = event->motion.send_event; + _pick_event.crossing.subwindow = NULL; + _pick_event.crossing.x = event->motion.x; + _pick_event.crossing.y = event->motion.y; + _pick_event.crossing.mode = GDK_CROSSING_NORMAL; + _pick_event.crossing.detail = GDK_NOTIFY_NONLINEAR; + _pick_event.crossing.focus = FALSE; + _pick_event.crossing.state = event->motion.state; // these fields don't have the same offsets in both types of events if (event->type == GDK_MOTION_NOTIFY) { - canvas->pick_event.crossing.x_root = event->motion.x_root; - canvas->pick_event.crossing.y_root = event->motion.y_root; + _pick_event.crossing.x_root = event->motion.x_root; + _pick_event.crossing.y_root = event->motion.y_root; } else { - canvas->pick_event.crossing.x_root = event->button.x_root; - canvas->pick_event.crossing.y_root = event->button.y_root; + _pick_event.crossing.x_root = event->button.x_root; + _pick_event.crossing.y_root = event->button.y_root; } } else { - canvas->pick_event = *event; + _pick_event = *event; } } // Don't do anything else if this is a recursive call - if (canvas->in_repick) { + if (_in_repick) { return retval; } // LeaveNotify means that there is no current item, so we don't look for one - if (canvas->pick_event.type != GDK_LEAVE_NOTIFY) { + if (_pick_event.type != GDK_LEAVE_NOTIFY) { // these fields don't have the same offsets in both types of events double x, y; - if (canvas->pick_event.type == GDK_ENTER_NOTIFY) { - x = canvas->pick_event.crossing.x; - y = canvas->pick_event.crossing.y; + if (_pick_event.type == GDK_ENTER_NOTIFY) { + x = _pick_event.crossing.x; + y = _pick_event.crossing.y; } else { - x = canvas->pick_event.motion.x; - y = canvas->pick_event.motion.y; + x = _pick_event.motion.x; + y = _pick_event.motion.y; } // world coords - x += canvas->x0; - y += canvas->y0; + x += _x0; + y += _y0; // find the closest item - if (canvas->root->visible) { - sp_canvas_item_invoke_point (canvas->root, Geom::Point(x, y), &canvas->new_current_item); + if (_root->visible) { + sp_canvas_item_invoke_point (_root, Geom::Point(x, y), &_new_current_item); } else { - canvas->new_current_item = NULL; + _new_current_item = NULL; } } else { - canvas->new_current_item = NULL; + _new_current_item = NULL; } - if ((canvas->new_current_item == canvas->current_item) && !canvas->left_grabbed_item) { + if ((_new_current_item == _current_item) && !_left_grabbed_item) { return retval; // current item did not change } // Synthesize events for old and new current items - if ((canvas->new_current_item != canvas->current_item) - && (canvas->current_item != NULL) - && !canvas->left_grabbed_item) { + if ((_new_current_item != _current_item) && + _current_item != NULL && !_left_grabbed_item) + { GdkEvent new_event; - new_event = canvas->pick_event; + new_event = _pick_event; new_event.type = GDK_LEAVE_NOTIFY; new_event.crossing.detail = GDK_NOTIFY_ANCESTOR; new_event.crossing.subwindow = NULL; - canvas->in_repick = TRUE; - retval = emitEvent(canvas, &new_event); - canvas->in_repick = FALSE; + _in_repick = TRUE; + retval = emitEvent(&new_event); + _in_repick = FALSE; } - if (canvas->gen_all_enter_events == false) { + if (_gen_all_enter_events == false) { // new_current_item may have been set to NULL during the call to // emitEvent() above - if ((canvas->new_current_item != canvas->current_item) && button_down) { - canvas->left_grabbed_item = TRUE; + if ((_new_current_item != _current_item) && button_down) { + _left_grabbed_item = TRUE; return retval; } } // Handle the rest of cases + _left_grabbed_item = FALSE; + _current_item = _new_current_item; - canvas->left_grabbed_item = FALSE; - canvas->current_item = canvas->new_current_item; - - if (canvas->current_item != NULL) { + if (_current_item != NULL) { GdkEvent new_event; - new_event = canvas->pick_event; + new_event = _pick_event; new_event.type = GDK_ENTER_NOTIFY; new_event.crossing.detail = GDK_NOTIFY_ANCESTOR; new_event.crossing.subwindow = NULL; - retval = emitEvent(canvas, &new_event); + retval = emitEvent(&new_event); } return retval; } -gint SPCanvasImpl::button(GtkWidget *widget, GdkEventButton *event) +gint SPCanvas::handle_button(GtkWidget *widget, GdkEventButton *event) { SPCanvas *canvas = SP_CANVAS (widget); @@ -1596,7 +1426,7 @@ gint SPCanvasImpl::button(GtkWidget *widget, GdkEventButton *event) // dispatch normally regardless of the event's window if an item // has a pointer grab in effect - if (!canvas->grabbed_item && + if (!canvas->_grabbed_item && event->window != getWindow(canvas)) return retval; @@ -1628,21 +1458,21 @@ gint SPCanvasImpl::button(GtkWidget *widget, GdkEventButton *event) // Pick the current item as if the button were not pressed, and // then process the event. // - canvas->state = event->state; - pickCurrentItem(canvas, reinterpret_cast(event)); - canvas->state ^= mask; - retval = emitEvent(canvas, (GdkEvent *) event); + canvas->_state = event->state; + canvas->pickCurrentItem(reinterpret_cast(event)); + canvas->_state ^= mask; + retval = canvas->emitEvent((GdkEvent *) event); break; case GDK_BUTTON_RELEASE: // Process the event as if the button were pressed, then repick // after the button has been released // - canvas->state = event->state; - retval = emitEvent(canvas, (GdkEvent *) event); + canvas->_state = event->state; + retval = canvas->emitEvent((GdkEvent *) event); event->state ^= mask; - canvas->state = event->state; - pickCurrentItem(canvas, reinterpret_cast(event)); + canvas->_state = event->state; + canvas->pickCurrentItem(reinterpret_cast(event)); event->state ^= mask; break; @@ -1654,9 +1484,9 @@ gint SPCanvasImpl::button(GtkWidget *widget, GdkEventButton *event) return retval; } -gint SPCanvasImpl::handleScroll(GtkWidget *widget, GdkEventScroll *event) +gint SPCanvas::handle_scroll(GtkWidget *widget, GdkEventScroll *event) { - return emitEvent(SP_CANVAS(widget), reinterpret_cast(event)); + return SP_CANVAS(widget)->emitEvent(reinterpret_cast(event)); } static inline void request_motions(GdkWindow *w, GdkEventMotion *event) { @@ -1670,7 +1500,7 @@ static inline void request_motions(GdkWindow *w, GdkEventMotion *event) { gdk_event_request_motions(event); } -int SPCanvasImpl::handleMotion(GtkWidget *widget, GdkEventMotion *event) +int SPCanvas::handle_motion(GtkWidget *widget, GdkEventMotion *event) { int status; SPCanvas *canvas = SP_CANVAS (widget); @@ -1681,12 +1511,12 @@ int SPCanvasImpl::handleMotion(GtkWidget *widget, GdkEventMotion *event) return FALSE; } - if (canvas->root == NULL) // canvas being deleted + if (canvas->_root == NULL) // canvas being deleted return FALSE; - canvas->state = event->state; - pickCurrentItem(canvas, reinterpret_cast(event)); - status = emitEvent(canvas, reinterpret_cast(event)); + canvas->_state = event->state; + canvas->pickCurrentItem(reinterpret_cast(event)); + status = canvas->emitEvent(reinterpret_cast(event)); if (event->is_hint) { request_motions(gtk_widget_get_window (widget), event); } @@ -1694,12 +1524,12 @@ int SPCanvasImpl::handleMotion(GtkWidget *widget, GdkEventMotion *event) return status; } -void SPCanvasImpl::sp_canvas_paint_single_buffer(SPCanvas *canvas, Geom::IntRect const &paint_rect, Geom::IntRect const &canvas_rect, int /*sw*/) +void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect const &canvas_rect, int /*sw*/) { - GtkWidget *widget = GTK_WIDGET (canvas); + GtkWidget *widget = GTK_WIDGET (this); // Mark the region clean - sp_canvas_mark_rect(canvas, paint_rect, 0); + markRect(paint_rect, 0); SPCanvasBuf buf; buf.buf = NULL; @@ -1709,16 +1539,6 @@ void SPCanvasImpl::sp_canvas_paint_single_buffer(SPCanvas *canvas, Geom::IntRect buf.is_empty = true; //buf.ct = gdk_cairo_create(widget->window); - /* - cairo_t *xctt = gdk_cairo_create(widget->window); - cairo_translate(xctt, paint_rect.left() - canvas->x0, paint_rect.top() - canvas->y0); - cairo_set_source_rgb(xctt, 1,0,0); - cairo_rectangle(xctt, 0, 0, paint_rect.width(), paint_rect.height()); - cairo_fill(xctt); - cairo_destroy(xctt); - // - */ - // 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); @@ -1749,20 +1569,20 @@ void SPCanvasImpl::sp_canvas_paint_single_buffer(SPCanvas *canvas, Geom::IntRect cairo_paint(buf.ct); cairo_set_operator(buf.ct, CAIRO_OPERATOR_OVER); - if (canvas->root->visible) { - SP_CANVAS_ITEM_GET_CLASS (canvas->root)->render (canvas->root, &buf); + if (_root->visible) { + SP_CANVAS_ITEM_GET_CLASS(_root)->render(_root, &buf); } // output to X cairo_destroy(buf.ct); #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - if (canvas->enable_cms_display_adj) { + if (_enable_cms_display_adj) { cmsHTRANSFORM transf = 0; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); bool fromDisplay = prefs->getBool( "/options/displayprofile/from_display"); if ( fromDisplay ) { - transf = Inkscape::CMSSystem::getDisplayPer( canvas->cms_key ); + transf = Inkscape::CMSSystem::getDisplayPer(_cms_key); } else { transf = Inkscape::CMSSystem::getDisplayTransform(); } @@ -1781,7 +1601,7 @@ void SPCanvasImpl::sp_canvas_paint_single_buffer(SPCanvas *canvas, Geom::IntRect #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) cairo_t *xct = gdk_cairo_create(gtk_widget_get_window (widget)); - cairo_translate(xct, paint_rect.left() - canvas->x0, paint_rect.top() - canvas->y0); + 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); @@ -1789,26 +1609,16 @@ void SPCanvasImpl::sp_canvas_paint_single_buffer(SPCanvas *canvas, Geom::IntRect cairo_paint(xct); cairo_destroy(xct); cairo_surface_destroy(imgs); - - //cairo_surface_t *cst = cairo_get_target(buf.ct); - //cairo_destroy (buf.ct); - //cairo_surface_finish (cst); - //cairo_surface_destroy (cst); } -namespace { - struct PaintRectSetup { - SPCanvas* canvas; Geom::IntRect big_rect; GTimeVal start_time; int max_pixels; Geom::Point mouse_loc; }; -}// namespace - -int SPCanvasImpl::sp_canvas_paint_rect_internal(PaintRectSetup const *setup, Geom::IntRect const &this_rect) +int SPCanvas::paintRectInternal(PaintRectSetup const *setup, Geom::IntRect const &this_rect) { GTimeVal now; g_get_current_time (&now); @@ -1831,11 +1641,11 @@ int SPCanvasImpl::sp_canvas_paint_rect_internal(PaintRectSetup const *setup, Geo // If this limit is set, and if we have aborted redraw more times than is allowed, // interrupting is blocked and we're forced to redraw full screen once // (after which we can again interrupt forced_redraw_limit times). - if (setup->canvas->forced_redraw_limit < 0 || - setup->canvas->forced_redraw_count < setup->canvas->forced_redraw_limit) { + if (_forced_redraw_limit < 0 || + _forced_redraw_count < _forced_redraw_limit) { - if (setup->canvas->forced_redraw_limit != -1) { - setup->canvas->forced_redraw_count++; + if (_forced_redraw_limit != -1) { + _forced_redraw_count++; } return false; @@ -1861,8 +1671,7 @@ int SPCanvasImpl::sp_canvas_paint_rect_internal(PaintRectSetup const *setup, Geo gdk_window_begin_paint_rect(window, &r); */ - sp_canvas_paint_single_buffer (setup->canvas, - this_rect, setup->big_rect, bw); + paintSingleBuffer(this_rect, setup->big_rect, bw); //gdk_window_end_paint(window); return 1; } @@ -1894,11 +1703,11 @@ The default for now is the strips mode. if (setup->mouse_loc[Geom::X] < mid) { // Always paint towards the mouse first - return sp_canvas_paint_rect_internal(setup, lo) - && sp_canvas_paint_rect_internal(setup, hi); + return paintRectInternal(setup, lo) + && paintRectInternal(setup, hi); } else { - return sp_canvas_paint_rect_internal(setup, hi) - && sp_canvas_paint_rect_internal(setup, lo); + return paintRectInternal(setup, hi) + && paintRectInternal(setup, lo); } } else { int mid = this_rect[Geom::Y].middle(); @@ -1910,24 +1719,24 @@ The default for now is the strips mode. if (setup->mouse_loc[Geom::Y] < mid) { // Always paint towards the mouse first - return sp_canvas_paint_rect_internal(setup, lo) - && sp_canvas_paint_rect_internal(setup, hi); + return paintRectInternal(setup, lo) + && paintRectInternal(setup, hi); } else { - return sp_canvas_paint_rect_internal(setup, hi) - && sp_canvas_paint_rect_internal(setup, lo); + return paintRectInternal(setup, hi) + && paintRectInternal(setup, lo); } } } -bool SPCanvasImpl::sp_canvas_paint_rect(SPCanvas *canvas, int xx0, int yy0, int xx1, int yy1) +bool SPCanvas::paintRect(int xx0, int yy0, int xx1, int yy1) { GtkAllocation allocation; - g_return_val_if_fail (!canvas->need_update, false); + g_return_val_if_fail (!_need_update, false); - gtk_widget_get_allocation (GTK_WIDGET (canvas), &allocation); + gtk_widget_get_allocation(GTK_WIDGET(this), &allocation); - Geom::IntRect canvas_rect = Geom::IntRect::from_xywh(canvas->x0, canvas->y0, + Geom::IntRect canvas_rect = Geom::IntRect::from_xywh(_x0, _y0, allocation.width, allocation.height); Geom::IntRect paint_rect(xx0, yy0, xx1, yy1); @@ -1937,8 +1746,6 @@ bool SPCanvasImpl::sp_canvas_paint_rect(SPCanvas *canvas, int xx0, int yy0, int paint_rect = *area; PaintRectSetup setup; - - setup.canvas = canvas; setup.big_rect = paint_rect; // Save the mouse location @@ -1948,16 +1755,16 @@ bool SPCanvasImpl::sp_canvas_paint_rect(SPCanvas *canvas, int xx0, int yy0, int GdkDeviceManager *dm = gdk_display_get_device_manager(gdk_display_get_default()); GdkDevice *device = gdk_device_manager_get_client_pointer(dm); - gdk_window_get_device_position(gtk_widget_get_window(GTK_WIDGET(canvas)), + gdk_window_get_device_position(gtk_widget_get_window(GTK_WIDGET(this)), device, &x, &y, NULL); #else - gdk_window_get_pointer (gtk_widget_get_window (GTK_WIDGET(canvas)), &x, &y, NULL); + gdk_window_get_pointer(gtk_widget_get_window(GTK_WIDGET(this)), &x, &y, NULL); #endif - setup.mouse_loc = sp_canvas_window_to_world (canvas, Geom::Point(x,y)); + setup.mouse_loc = sp_canvas_window_to_world(this, Geom::Point(x,y)); - if (canvas->rendermode != Inkscape::RENDERMODE_OUTLINE) { + if (_rendermode != Inkscape::RENDERMODE_OUTLINE) { // use 256K as a compromise to not slow down gradients // 256K is the cached buffer and we need 4 channels setup.max_pixels = 65536; // 256K/4 @@ -1971,41 +1778,41 @@ bool SPCanvasImpl::sp_canvas_paint_rect(SPCanvas *canvas, int xx0, int yy0, int g_get_current_time(&(setup.start_time)); // Go - return sp_canvas_paint_rect_internal(&setup, paint_rect); + return paintRectInternal(&setup, paint_rect); } void SPCanvas::forceFullRedrawAfterInterruptions(unsigned int count) { - forced_redraw_limit = count; - forced_redraw_count = 0; + _forced_redraw_limit = count; + _forced_redraw_count = 0; } void SPCanvas::endForcedFullRedraws() { - forced_redraw_limit = -1; + _forced_redraw_limit = -1; } #if GTK_CHECK_VERSION(3,0,0) -gboolean SPCanvasImpl::handleDraw(GtkWidget *widget, cairo_t *cr) { - SPCanvas *canvas = SP_CANVAS(widget); +gboolean SPCanvas::handle_draw(GtkWidget *widget, cairo_t *cr) { + SPCanvas *canvas = SP_CANVAS(widget); - cairo_rectangle_list_t *rects = cairo_copy_clip_rectangle_list(cr); + cairo_rectangle_list_t *rects = cairo_copy_clip_rectangle_list(cr); - for (int i = 0; i < rects->num_rectangles; i++) { - cairo_rectangle_t rectangle = rects->rectangles[i]; + for (int i = 0; i < rects->num_rectangles; i++) { + cairo_rectangle_t rectangle = rects->rectangles[i]; - Geom::IntRect r = Geom::IntRect::from_xywh(rectangle.x + canvas->x0, rectangle.y + canvas->y0, - rectangle.width, rectangle.height); + 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()); - } + canvas->requestRedraw(r.left(), r.top(), r.right(), r.bottom()); + } - cairo_rectangle_list_destroy(rects); + cairo_rectangle_list_destroy(rects); return FALSE; } #else -gboolean SPCanvasImpl::handleExpose(GtkWidget *widget, GdkEventExpose *event) +gboolean SPCanvas::handle_expose(GtkWidget *widget, GdkEventExpose *event) { SPCanvas *canvas = SP_CANVAS(widget); @@ -2024,7 +1831,7 @@ gboolean SPCanvasImpl::handleExpose(GtkWidget *widget, GdkEventExpose *event) for (int i = 0; i < n_rects; i++) { GdkRectangle rectangle = rects[i]; - Geom::IntRect r = Geom::IntRect::from_xywh(rectangle.x + canvas->x0, rectangle.y + canvas->y0, + 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()); @@ -2035,12 +1842,12 @@ gboolean SPCanvasImpl::handleExpose(GtkWidget *widget, GdkEventExpose *event) #endif -gint SPCanvasImpl::handleKeyEvent(GtkWidget *widget, GdkEventKey *event) +gint SPCanvas::handle_key_event(GtkWidget *widget, GdkEventKey *event) { - return emitEvent(SP_CANVAS(widget), reinterpret_cast(event)); + return SP_CANVAS(widget)->emitEvent(reinterpret_cast(event)); } -gint SPCanvasImpl::handleCrossing(GtkWidget *widget, GdkEventCrossing *event) +gint SPCanvas::handle_crossing(GtkWidget *widget, GdkEventCrossing *event) { SPCanvas *canvas = SP_CANVAS (widget); @@ -2048,57 +1855,56 @@ gint SPCanvasImpl::handleCrossing(GtkWidget *widget, GdkEventCrossing *event) return FALSE; } - canvas->state = event->state; - return pickCurrentItem(canvas, reinterpret_cast(event)); + canvas->_state = event->state; + return canvas->pickCurrentItem(reinterpret_cast(event)); } -gint SPCanvasImpl::handleFocusIn(GtkWidget *widget, GdkEventFocus *event) +gint SPCanvas::handle_focus_in(GtkWidget *widget, GdkEventFocus *event) { gtk_widget_grab_focus (widget); SPCanvas *canvas = SP_CANVAS (widget); - if (canvas->focused_item) { - return emitEvent(canvas, reinterpret_cast(event)); + if (canvas->_focused_item) { + return canvas->emitEvent(reinterpret_cast(event)); } else { return FALSE; } } -gint SPCanvasImpl::handleFocusOut(GtkWidget *widget, GdkEventFocus *event) +gint SPCanvas::handle_focus_out(GtkWidget *widget, GdkEventFocus *event) { SPCanvas *canvas = SP_CANVAS(widget); - if (canvas->focused_item) { - return emitEvent(canvas, reinterpret_cast(event)); + if (canvas->_focused_item) { + return canvas->emitEvent(reinterpret_cast(event)); } else { return FALSE; } } -int SPCanvasImpl::paint(SPCanvas *canvas) +int SPCanvas::paint() { - if (canvas->need_update) { - sp_canvas_item_invoke_update (canvas->root, Geom::identity(), 0); - canvas->need_update = FALSE; + if (_need_update) { + sp_canvas_item_invoke_update(_root, Geom::identity(), 0); + _need_update = FALSE; } - if (!canvas->need_redraw) { + if (!_need_redraw) { return TRUE; } Cairo::RefPtr to_paint = Cairo::Region::create(); - for (int j=canvas->tTop; jtBottom; j++) { - for (int i=canvas->tLeft; itRight; i++) { - int tile_index = (i - canvas->tLeft) + (j - canvas->tTop)*canvas->tileH; + for (int j = _tTop; j < _tBottom; ++j) { + for (int i = _tLeft; i < _tRight; ++i) { + int tile_index = (i - _tLeft) + (j - _tTop) * _tile_h; - if ( canvas->tiles[tile_index] ) { // if this tile is dirtied (nonzero) + 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); } - } } @@ -2111,77 +1917,80 @@ int SPCanvasImpl::paint(SPCanvas *canvas) int y0 = rect.y; int x1 = x0 + rect.width; int y1 = y0 + rect.height; - if (!sp_canvas_paint_rect(canvas, x0, y0, x1, y1)) { + if (!paintRect(x0, y0, x1, y1)) { // Aborted return FALSE; }; } } - canvas->need_redraw = FALSE; + _need_redraw = FALSE; // we've had a full unaborted redraw, reset the full redraw counter - if (canvas->forced_redraw_limit != -1) { - canvas->forced_redraw_count = 0; + if (_forced_redraw_limit != -1) { + _forced_redraw_count = 0; } return TRUE; } -int SPCanvasImpl::do_update(SPCanvas *canvas) +int SPCanvas::doUpdate() { - if (!canvas->root) { // canvas may have already be destroyed by closing desktop during interrupted display! + if (!_root) { // canvas may have already be destroyed by closing desktop during interrupted display! return TRUE; } - - if (canvas->drawing_disabled) { + if (_drawing_disabled) { return TRUE; } // Cause the update if necessary - if (canvas->need_update) { - sp_canvas_item_invoke_update(canvas->root, Geom::identity(), 0); - canvas->need_update = FALSE; + if (_need_update) { + sp_canvas_item_invoke_update(_root, Geom::identity(), 0); + _need_update = FALSE; } // Paint if able to - if (gtk_widget_is_drawable( GTK_WIDGET(canvas) )) { - return paint(canvas); + if (gtk_widget_is_drawable(GTK_WIDGET(this))) { + return paint(); } // Pick new current item - while (canvas->need_repick) { - canvas->need_repick = FALSE; - pickCurrentItem(canvas, &canvas->pick_event); + while (_need_repick) { + _need_repick = FALSE; + pickCurrentItem(&_pick_event); } return TRUE; } -gint SPCanvasImpl::idle_handler(gpointer data) +gint SPCanvas::idle_handler(gpointer data) { SPCanvas *canvas = SP_CANVAS (data); - - int const ret = do_update (canvas); - + int const ret = canvas->doUpdate(); if (ret) { // Reset idle id - canvas->idle_id = 0; + canvas->_idle_id = 0; } - return !ret; } -void SPCanvasImpl::add_idle(SPCanvas *canvas) +void SPCanvas::addIdle() +{ + if (_idle_id == 0) { + _idle_id = gdk_threads_add_idle_full(UPDATE_PRIORITY, idle_handler, this, NULL); + } +} +void SPCanvas::removeIdle() { - if (canvas->idle_id == 0) { - canvas->idle_id = gdk_threads_add_idle_full(UPDATE_PRIORITY, idle_handler, canvas, NULL); + if (_idle_id) { + g_source_remove(_idle_id); + _idle_id = 0; } } SPCanvasGroup *SPCanvas::getRoot() { - return SP_CANVAS_GROUP(root); + return SP_CANVAS_GROUP(_root); } void SPCanvas::scrollTo(double cx, double cy, unsigned int clear, bool is_scrolling) @@ -2190,28 +1999,28 @@ void SPCanvas::scrollTo(double cx, double cy, unsigned int clear, bool is_scroll int ix = (int) round(cx); // ix and iy are the new canvas coordinates (integer screen pixels) int iy = (int) round(cy); // cx might be negative, so (int)(cx + 0.5) will not do! - int dx = ix - x0; // dx and dy specify the displacement (scroll) of the - int dy = iy - y0; // canvas w.r.t its previous position + int dx = ix - _x0; // dx and dy specify the displacement (scroll) of the + int dy = iy - _y0; // canvas w.r.t its previous position Geom::IntRect old_area = getViewboxIntegers(); Geom::IntRect new_area = old_area + Geom::IntPoint(dx, dy); - dx0 = cx; // here the 'd' stands for double, not delta! - dy0 = cy; - x0 = ix; - y0 = iy; + _dx0 = cx; // here the 'd' stands for double, not delta! + _dy0 = cy; + _x0 = ix; + _y0 = iy; - gtk_widget_get_allocation(&widget, &allocation); + gtk_widget_get_allocation(&_widget, &allocation); - SPCanvasImpl::sp_canvas_resize_tiles(this, 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); + 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); } if (!clear) { // scrolling without zoom; redraw only the newly exposed areas if ((dx != 0) || (dy != 0)) { - this->is_scrolling = is_scrolling; + this->_is_scrolling = is_scrolling; if (gtk_widget_get_realized(GTK_WIDGET(this))) { gdk_window_scroll(getWindow(this), -dx, -dy); } @@ -2223,15 +2032,15 @@ void SPCanvas::scrollTo(double cx, double cy, unsigned int clear, bool is_scroll void SPCanvas::updateNow() { - if (need_update || need_redraw) { - SPCanvasImpl::do_update(this); + if (_need_update || _need_redraw) { + doUpdate(); } } -void SPCanvasImpl::requestCanvasUpdate(SPCanvas *canvas) +void SPCanvas::requestUpdate() { - canvas->need_update = TRUE; - add_idle(canvas); + _need_update = TRUE; + addIdle(); } void SPCanvas::requestRedraw(int x0, int y0, int x1, int y1) @@ -2248,13 +2057,13 @@ void SPCanvas::requestRedraw(int x0, int y0, int x1, int y1) Geom::IntRect bbox(x0, y0, x1, y1); gtk_widget_get_allocation(GTK_WIDGET(this), &allocation); - Geom::IntRect canvas_rect = Geom::IntRect::from_xywh(this->x0, this->y0, + Geom::IntRect canvas_rect = Geom::IntRect::from_xywh(this->_x0, this->_y0, allocation.width, allocation.height); Geom::OptIntRect clip = bbox & canvas_rect; if (clip) { - SPCanvasImpl::sp_canvas_dirty_rect(this, *clip); - SPCanvasImpl::add_idle(this); + dirtyRect(*clip); + addIdle(); } } @@ -2266,8 +2075,8 @@ void sp_canvas_window_to_world(SPCanvas const *canvas, double winx, double winy, g_return_if_fail (canvas != NULL); g_return_if_fail (SP_IS_CANVAS (canvas)); - if (worldx) *worldx = canvas->x0 + winx; - if (worldy) *worldy = canvas->y0 + winy; + if (worldx) *worldx = canvas->_x0 + winx; + if (worldy) *worldy = canvas->_y0 + winy; } /** @@ -2278,8 +2087,8 @@ void sp_canvas_world_to_window(SPCanvas const *canvas, double worldx, double wor g_return_if_fail (canvas != NULL); g_return_if_fail (SP_IS_CANVAS (canvas)); - if (winx) *winx = worldx - canvas->x0; - if (winy) *winy = worldy - canvas->y0; + if (winx) *winx = worldx - canvas->_x0; + if (winy) *winy = worldy - canvas->_y0; } /** @@ -2290,7 +2099,7 @@ Geom::Point sp_canvas_window_to_world(SPCanvas const *canvas, Geom::Point const g_assert (canvas != NULL); g_assert (SP_IS_CANVAS (canvas)); - return Geom::Point(canvas->x0 + win[0], canvas->y0 + win[1]); + return Geom::Point(canvas->_x0 + win[0], canvas->_y0 + win[1]); } /** @@ -2301,7 +2110,7 @@ Geom::Point sp_canvas_world_to_window(SPCanvas const *canvas, Geom::Point const g_assert (canvas != NULL); g_assert (SP_IS_CANVAS (canvas)); - return Geom::Point(world[0] - canvas->x0, world[1] - canvas->y0); + return Geom::Point(world[0] - canvas->_x0, world[1] - canvas->_y0); } /** @@ -2317,10 +2126,10 @@ bool sp_canvas_world_pt_inside_window(SPCanvas const *canvas, Geom::Point const GtkWidget *w = GTK_WIDGET(canvas); gtk_widget_get_allocation (w, &allocation); - return ( ( canvas->x0 <= world[Geom::X] ) && - ( canvas->y0 <= world[Geom::Y] ) && - ( world[Geom::X] < canvas->x0 + allocation.width ) && - ( world[Geom::Y] < canvas->y0 + allocation.height ) ); + return ( ( canvas->_x0 <= world[Geom::X] ) && + ( canvas->_y0 <= world[Geom::Y] ) && + ( world[Geom::X] < canvas->_x0 + allocation.width ) && + ( world[Geom::Y] < canvas->_y0 + allocation.height ) ); } /** @@ -2331,8 +2140,8 @@ Geom::Rect SPCanvas::getViewbox() const GtkAllocation allocation; gtk_widget_get_allocation (GTK_WIDGET (this), &allocation); - return Geom::Rect(Geom::Point(dx0, dy0), - Geom::Point(dx0 + allocation.width, dy0 + allocation.height)); + return Geom::Rect(Geom::Point(_dx0, _dy0), + Geom::Point(_dx0 + allocation.width, _dy0 + allocation.height)); } /** @@ -2344,8 +2153,8 @@ Geom::IntRect SPCanvas::getViewboxIntegers() const gtk_widget_get_allocation (GTK_WIDGET(this), &allocation); Geom::IntRect ret; - ret.setMin(Geom::IntPoint(x0, y0)); - ret.setMax(Geom::IntPoint(x0 + allocation.width, y0 + allocation.height)); + ret.setMin(Geom::IntPoint(_x0, _y0)); + ret.setMax(Geom::IntPoint(_x0 + allocation.width, _y0 + allocation.height)); return ret; } @@ -2359,63 +2168,62 @@ inline int sp_canvas_tile_ceil(int x) return ((x + (TILE_SIZE - 1)) & (~(TILE_SIZE - 1))) / TILE_SIZE; } -void SPCanvasImpl::sp_canvas_resize_tiles(SPCanvas* canvas, int nl, int nt, int nr, int nb) +void SPCanvas::resizeTiles(int nl, int nt, int nr, int nb) { if ( nl >= nr || nt >= nb ) { - if ( canvas->tiles ) g_free(canvas->tiles); - canvas->tLeft=canvas->tTop=canvas->tRight=canvas->tBottom=0; - canvas->tileH=canvas->tileV=0; - canvas->tiles=NULL; + 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 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= canvas->tLeft && i < canvas->tRight && j >= canvas->tTop && j < canvas->tBottom ) { - ntiles[ind]=canvas->tiles[(i-canvas->tLeft)+(j-canvas->tTop)*canvas->tileH]; // copy from the old tile + 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 + ntiles[ind] = 0; // newly exposed areas get 0 } } } - if ( canvas->tiles ) g_free(canvas->tiles); - canvas->tiles=ntiles; - canvas->tLeft=tl; - canvas->tTop=tt; - canvas->tRight=tr; - canvas->tBottom=tb; - canvas->tileH=nh; - canvas->tileV=nv; + if (_tiles) g_free(_tiles); + _tiles = ntiles; + _tLeft = tl; + _tTop = tt; + _tRight = tr; + _tBottom = tb; + _tile_h = nh; + _tile_h = nv; } -void SPCanvasImpl::sp_canvas_dirty_rect(SPCanvas* canvas, Geom::IntRect const &area) { - canvas->need_redraw = TRUE; - - sp_canvas_mark_rect(canvas, area, 1); +void SPCanvas::dirtyRect(Geom::IntRect const &area) { + _need_redraw = TRUE; + markRect(area, 1); } -void SPCanvasImpl::sp_canvas_mark_rect(SPCanvas* canvas, Geom::IntRect const &area, uint8_t val) +void SPCanvas::markRect(Geom::IntRect const &area, uint8_t val) { - 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 >= canvas->tRight || tr <= canvas->tLeft || tt >= canvas->tBottom || tb <= canvas->tTop ) return; - if ( tl < canvas->tLeft ) tl=canvas->tLeft; - if ( tr > canvas->tRight ) tr=canvas->tRight; - if ( tt < canvas->tTop ) tt=canvas->tTop; - if ( tb > canvas->tBottom ) tb=canvas->tBottom; + 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; itiles[(i-canvas->tLeft)+(j-canvas->tTop)*canvas->tileH] = val; + _tiles[(i - _tLeft) + (j - _tTop) * _tile_h] = val; } } } diff --git a/src/display/sp-canvas.h b/src/display/sp-canvas.h index 65b06ade8..1a13250b3 100644 --- a/src/display/sp-canvas.h +++ b/src/display/sp-canvas.h @@ -60,7 +60,7 @@ G_END_DECLS // SPCanvas ------------------------------------------------- -class SPCanvasImpl; +struct PaintRectSetup; GType sp_canvas_get_type() G_GNUC_CONST; @@ -68,123 +68,178 @@ GType sp_canvas_get_type() G_GNUC_CONST; * Port of GnomeCanvas for inkscape needs. */ struct SPCanvas { - friend class SPCanvasImpl; + /// Scrolls canvas to specific position (cx and cy are measured in screen pixels). + void scrollTo(double cx, double cy, unsigned int clear, bool is_scrolling = false); - /** - * Returns new canvas as widget. - */ - static GtkWidget *createAA(); + /// Synchronously updates the canvas if necessary. + void updateNow(); - /** - * Returns the root group of the specified canvas. - */ + /// Queues a redraw of rectangular canvas area. + void requestRedraw(int x1, int y1, int x2, int y2); + void requestUpdate(); + + void forceFullRedrawAfterInterruptions(unsigned int count); + void endForcedFullRedraws(); + + Geom::Rect getViewbox() const; + Geom::IntRect getViewboxIntegers() const; SPCanvasGroup *getRoot(); - /** - * Scrolls canvas to specific position (cx and cy are measured in screen pixels). - */ - void scrollTo(double cx, double cy, unsigned int clear, bool is_scrolling = false); + /// Returns new canvas as widget. + static GtkWidget *createAA(); +private: + /// Emits an event for an item in the canvas, be it the current + /// item, grabbed item, or focused item, as appropriate. + int emitEvent(GdkEvent *event); - /** - * Updates canvas if necessary. - */ - void updateNow(); + /// Re-picks the current item in the canvas, based on the event's + /// coordinates and emits enter/leave events for items as appropriate. + int pickCurrentItem(GdkEvent *event); + void shutdownTransients(); - /** - * Forces redraw of rectangular canvas area. - */ - void requestRedraw(int x1, int y1, int x2, int y2); + /// Allocates a new tile array for the canvas, copying overlapping tiles from the old array + void resizeTiles(int nl, int nt, int nr, int nb); + + /// Marks the specified area as dirty (requiring redraw) + void dirtyRect(Geom::IntRect const &area); + /// 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. + int doUpdate(); + + void paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect const &canvas_rect, int sw); /** - * Force a full redraw after a specified number of interrupted redraws. + * Paint the given rect, recursively subdividing the region until it is the size of a single + * buffer. + * + * @return true if the drawing completes */ - void forceFullRedrawAfterInterruptions(unsigned int count); + int paintRectInternal(PaintRectSetup const *setup, Geom::IntRect const &this_rect); + + /// Draws a specific rectangular part of the canvas. + /// @return true if the rectangle painting succeeds. + bool paintRect(int xx0, int yy0, int xx1, int yy1); + + /// Repaints the areas in the canvas that need it. + /// @return true if all the dirty parts have been redrawn + int paint(); + + /// Idle handler for the canvas that deals with pending updates and redraws. + static gint idle_handler(gpointer data); + + /// Convenience function to add an idle handler to a canvas. + void addIdle(); + void removeIdle(); + +public: + // GTK virtual functions. + static void dispose(GObject *object); + static void handle_realize(GtkWidget *widget); + static void handle_unrealize(GtkWidget *widget); +#if GTK_CHECK_VERSION(3,0,0) + static void handle_get_preferred_width(GtkWidget *widget, gint *min_w, gint *nat_w); + static void handle_get_preferred_height(GtkWidget *widget, gint *min_h, gint *nat_h); +#else + static void handle_size_request(GtkWidget *widget, GtkRequisition *req); +#endif + static void handle_size_allocate(GtkWidget *widget, GtkAllocation *allocation); + static gint handle_button(GtkWidget *widget, GdkEventButton *event); /** - * End forced full redraw requests. + * Scroll event handler for the canvas. + * + * @todo FIXME: generate motion events to re-select items. */ - void endForcedFullRedraws(); - + 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); +#else + static gboolean handle_expose(GtkWidget *widget, GdkEventExpose *event); +#endif + static gint handle_key_event(GtkWidget *widget, GdkEventKey *event); + static gint handle_crossing(GtkWidget *widget, GdkEventCrossing *event); + static gint handle_focus_in(GtkWidget *widget, GdkEventFocus *event); + static gint handle_focus_out(GtkWidget *widget, GdkEventFocus *event); +public: // Data members: ---------------------------------------------------------- + GtkWidget _widget; - GtkWidget widget; + guint _idle_id; - guint idle_id; + SPCanvasItem *_root; - SPCanvasItem *root; - - bool is_dragging; - double dx0; - double dy0; - int x0; - int y0; + bool _is_dragging; + double _dx0; + double _dy0; + int _x0; + int _y0; /* Area that needs redrawing, stored as a microtile array */ - int tLeft, tTop, tRight, tBottom; - int tileH, tileV; - uint8_t *tiles; + 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; + int _state; /** The item containing the mouse pointer, or NULL if none. */ - SPCanvasItem *current_item; + SPCanvasItem *_current_item; /** Item that is about to become current (used to track deletions and such). */ - SPCanvasItem *new_current_item; + SPCanvasItem *_new_current_item; /** Item that holds a pointer grab, or NULL if none. */ - SPCanvasItem *grabbed_item; + SPCanvasItem *_grabbed_item; /** Event mask specified when grabbing an item. */ - guint grabbed_event_mask; + guint _grabbed_event_mask; /** If non-NULL, the currently focused item. */ - SPCanvasItem *focused_item; + SPCanvasItem *_focused_item; /** Event on which selection of current item is based. */ - GdkEvent pick_event; + GdkEvent _pick_event; - int close_enough; + int _close_enough; - unsigned int need_update : 1; - unsigned int need_redraw : 1; - unsigned int need_repick : 1; + unsigned int _need_update : 1; + unsigned int _need_redraw : 1; + unsigned int _need_repick : 1; - int forced_redraw_count; - int forced_redraw_limit; + int _forced_redraw_count; + int _forced_redraw_limit; /** For use by internal pick_current_item() function. */ - unsigned int left_grabbed_item : 1; + unsigned int _left_grabbed_item : 1; /** For use by internal pick_current_item() function. */ - unsigned int in_repick : 1; + unsigned int _in_repick : 1; // In most tools Inkscape only generates enter and leave events // on the current item, but no other enter events if a mouse button - // is depressed -- see function pick_current_item(). Some tools + // is depressed -- see function pickCurrentItem(). Some tools // may wish the canvas to generate to all enter events, (e.g., the // connector tool). If so, they may temporarily set this flag to // 'true'. - bool gen_all_enter_events; + bool _gen_all_enter_events; /** For scripting, sometimes we want to delay drawing. */ - bool drawing_disabled; + bool _drawing_disabled; - int rendermode; - int colorrendermode; + int _rendermode; + int _colorrendermode; #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - bool enable_cms_display_adj; - Glib::ustring cms_key; + bool _enable_cms_display_adj; + Glib::ustring _cms_key; #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) - bool is_scrolling; - - Geom::Rect getViewbox() const; - Geom::IntRect getViewboxIntegers() const; + bool _is_scrolling; }; bool sp_canvas_world_pt_inside_window(SPCanvas const *canvas, Geom::Point const &world); -- cgit v1.2.3 From 490f3d7181baff4d215d0077be9e4939f9af5fde Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Tue, 12 Apr 2016 16:23:42 +0100 Subject: Hackfest 2016: Fix SPCanvas to comply with GTK3 rendering model. For now, causes redraw issues with SVG preview in the open dialog. (bzr r14795) --- src/display/sp-canvas.cpp | 279 ++++++++++++++++++++++------------------------ src/display/sp-canvas.h | 8 +- 2 files changed, 139 insertions(+), 148 deletions(-) (limited to 'src/display') diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index df84e379c..2dced2512 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -122,7 +122,7 @@ struct SPCanvasClass { namespace { -gint const UPDATE_PRIORITY = G_PRIORITY_HIGH_IDLE; +gint const UPDATE_PRIORITY = G_PRIORITY_DEFAULT_IDLE; GdkWindow *getWindow(SPCanvas *canvas) { @@ -956,9 +956,8 @@ static void sp_canvas_init(SPCanvas *canvas) canvas->_drawing_disabled = false; - canvas->_tiles=NULL; - canvas->_tLeft=canvas->_tTop=canvas->_tRight=canvas->_tBottom=0; - canvas->_tile_h=canvas->_tile_h=0; + canvas->_backing_store = NULL; + canvas->_dirty_region = cairo_region_create(); canvas->_forced_redraw_count = 0; canvas->_forced_redraw_limit = -1; @@ -967,8 +966,6 @@ 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() @@ -979,10 +976,6 @@ void SPCanvas::shutdownTransients() // 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; @@ -1005,6 +998,14 @@ 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->_dirty_region) { + cairo_region_destroy(canvas->_dirty_region); + canvas->_dirty_region = NULL; + } canvas->shutdownTransients(); #if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) @@ -1138,41 +1139,53 @@ void SPCanvas::handle_size_request(GtkWidget *widget, GtkRequisition *req) void SPCanvas::handle_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { SPCanvas *canvas = SP_CANVAS (widget); - GtkAllocation widg_allocation; + GtkAllocation old_allocation; - gtk_widget_get_allocation (widget, &widg_allocation); + gtk_widget_get_allocation(widget, &old_allocation); -// Geom::IntRect old_area = Geom::IntRect::from_xywh(canvas->x0, canvas->y0, -// widg_allocation.width, widg_allocation.height); +// 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 + 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_set_source_surface(cr, canvas->_backing_store, 0, 0); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_paint(cr); + cairo_destroy(cr); + cairo_surface_destroy(canvas->_backing_store); + } + canvas->_backing_store = new_backing_store; + + 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, + if (gtk_widget_get_realized (widget)) { + gdk_window_move_resize (gtk_widget_get_window (widget), + allocation->x, allocation->y, + allocation->width, allocation->height); + } + + if (allocation->width > old_allocation.width) { + canvas->requestRedraw(canvas->_x0 + old_allocation.width, + canvas->_y0, canvas->_x0 + allocation->width, canvas->_y0 + allocation->height); } - if (allocation->height > widg_allocation.height) { - canvas->requestRedraw(0, - canvas->_y0 + widg_allocation.height, + if (allocation->height > old_allocation.height) { + canvas->requestRedraw(canvas->_x0, + canvas->_y0 + old_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); - } } int SPCanvas::emitEvent(GdkEvent *event) @@ -1600,7 +1613,8 @@ 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 = 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); @@ -1609,6 +1623,12 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect cairo_paint(xct); cairo_destroy(xct); cairo_surface_destroy(imgs); + + cairo_rectangle_int_t crect = { paint_rect.left(), paint_rect.right(), paint_rect.width(), paint_rect.height() }; + cairo_region_subtract_rectangle(_dirty_region, &crect); + + gtk_widget_queue_draw_area(GTK_WIDGET(this), paint_rect.left() -_x0, paint_rect.top() - _y0, + paint_rect.width(), paint_rect.height()); } struct PaintRectSetup { @@ -1792,52 +1812,66 @@ 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); cairo_rectangle_list_t *rects = cairo_copy_clip_rectangle_list(cr); + cairo_region_t *draw_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(draw_region, &irect); + } + cairo_rectangle_list_destroy(rects); - 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_t *draw_dirty = cairo_region_copy(draw_region); + cairo_region_intersect(draw_dirty, canvas->_dirty_region); + cairo_region_subtract(draw_region, draw_dirty); + + // Draw the clean portion + if (!cairo_region_is_empty(draw_region)) { + cairo_region_translate(draw_region, -canvas->_x0, -canvas->_y0); + cairo_save(cr); + int n_rects = cairo_region_num_rectangles(draw_region); + for (int i = 0; i < n_rects; ++i) { + cairo_rectangle_int_t crect; + cairo_region_get_rectangle(draw_region, i, &crect); + cairo_rectangle(cr, crect.x, crect.y, crect.width, crect.height); + } + cairo_clip(cr); + cairo_set_source_surface(cr, canvas->_backing_store, 0, 0); + cairo_paint(cr); + cairo_restore(cr); } - cairo_rectangle_list_destroy(rects); + // Render the dirty portion in the background + int n_rects = cairo_region_num_rectangles(draw_dirty); + for (int i = 0; i < n_rects; ++i) { + cairo_rectangle_int_t crect; + cairo_region_get_rectangle(draw_dirty, i, &crect); + canvas->requestRedraw(crect.x, crect.y, crect.x + crect.width, crect.y + crect.height); + } + cairo_region_destroy(draw_region); + cairo_region_destroy(draw_dirty); - return FALSE; + return TRUE; } -#else +#if !GTK_CHECK_VERSION(3,0,0) gboolean SPCanvas::handle_expose(GtkWidget *widget, GdkEventExpose *event) { - SPCanvas *canvas = SP_CANVAS(widget); + cairo_t *cr = gdk_cairo_create(gtk_widget_get_window(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 FALSE; + return result; } #endif @@ -1889,39 +1923,18 @@ int SPCanvas::paint() sp_canvas_item_invoke_update(_root, Geom::identity(), 0); _need_update = FALSE; } - if (!_need_redraw) { return TRUE; } - Cairo::RefPtr 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; - }; - } + int n_rects = cairo_region_num_rectangles(_dirty_region); + for (int i = 0; i < n_rects; ++i) { + cairo_rectangle_int_t crect; + cairo_region_get_rectangle(_dirty_region, i, &crect); + if (!paintRect(crect.x, crect.y, crect.x + crect.width, crect.y + crect.height)) { + // Aborted + return FALSE; + }; } _need_redraw = FALSE; @@ -2012,21 +2025,46 @@ void SPCanvas::scrollTo(double cx, double cy, unsigned int clear, bool is_scroll gtk_widget_get_allocation(&_widget, &allocation); - resizeTiles(_x0, _y0, _x0 + allocation.width, _y0 + allocation.height); + 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_source_rgb(cr, 1, 1, 1); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_paint(cr); + cairo_set_source_surface(cr, _backing_store, -dx, -dy); + cairo_paint(cr); + cairo_destroy(cr); + cairo_surface_destroy(_backing_store); + _backing_store = new_backing_store; + + cairo_rectangle_int_t crect = { _x0, _y0, allocation.width, allocation.height }; + cairo_region_intersect_rectangle(_dirty_region, &crect); + if (SP_CANVAS_ITEM_GET_CLASS(_root)->viewbox_changed) { SP_CANVAS_ITEM_GET_CLASS(_root)->viewbox_changed(_root, new_area); } - if (!clear) { + if (clear) { + requestRedraw(_x0, _y0, allocation.width, allocation.height); + } else { // 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 + + if (dx > 0) { + requestRedraw(_x0 + allocation.width - dx, _y0, _x0 + allocation.width, _y0 + allocation.height); + } else if (dx < 0) { + requestRedraw(_x0, _y0, _x0 - dx, _y0 + allocation.height); + } + if (dy > 0) { + requestRedraw(_x0, _y0 + allocation.height - dy, _x0 + allocation.width, _y0 + allocation.height); + } else if (dy < 0) { + requestRedraw(_x0, _y0, _x0 + allocation.width, _y0 - dy); + } } } @@ -2168,42 +2206,6 @@ inline int sp_canvas_tile_ceil(int x) return ((x + (TILE_SIZE - 1)) & (~(TILE_SIZE - 1))) / TILE_SIZE; } -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::dirtyRect(Geom::IntRect const &area) { _need_redraw = TRUE; markRect(area, 1); @@ -2211,20 +2213,11 @@ void SPCanvas::dirtyRect(Geom::IntRect const &area) { void SPCanvas::markRect(Geom::IntRect const &area, uint8_t val) { - 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 Date: Tue, 12 Apr 2016 16:46:20 +0100 Subject: Update copyright notices on display/sp-canvas.(h|cpp) (bzr r14798) --- src/display/sp-canvas.cpp | 2 ++ src/display/sp-canvas.h | 2 ++ 2 files changed, 4 insertions(+) (limited to 'src/display') diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index 2dced2512..8222f83ba 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -8,9 +8,11 @@ * fred * bbyak * Jon A. Cruz + * Krzysztof Kosiński * * Copyright (C) 1998 The Free Software Foundation * Copyright (C) 2002-2006 authors + * Copyright (C) 2016 Google * * Released under GNU GPL, read the file 'COPYING' for more information */ diff --git a/src/display/sp-canvas.h b/src/display/sp-canvas.h index 1f357a351..b626beedb 100644 --- a/src/display/sp-canvas.h +++ b/src/display/sp-canvas.h @@ -11,9 +11,11 @@ * Raph Levien * Lauris Kaplinski * Jon A. Cruz + * Krzysztof Kosiński * * Copyright (C) 1998 The Free Software Foundation * Copyright (C) 2002 Lauris Kaplinski + * Copyright (C) 2016 Google * * Released under GNU GPL, read the file 'COPYING' for more information */ -- cgit v1.2.3 From b3f4e955d1e0e8695e81a8dd9bb0b70f1a6bf7f1 Mon Sep 17 00:00:00 2001 From: Alex Valavanis Date: Tue, 12 Apr 2016 17:00:58 +0100 Subject: sp-canvas: Disable deprecated double-buffering #Hackfest2016 (bzr r14799) --- src/display/sp-canvas.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'src/display') diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index 8222f83ba..598f45a7a 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -937,7 +937,6 @@ 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; @@ -1569,11 +1568,7 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect #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); + gtk_render_background(context, buf.ct, 0, 0, paint_rect.width(), paint_rect.height()); #else GtkStyle *style = gtk_widget_get_style (widget); gdk_cairo_set_source_color(buf.ct, &style->bg[GTK_STATE_NORMAL]); -- cgit v1.2.3 From a78262c248224a8e486985de4736b20d2e9e3ff2 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Wed, 13 Apr 2016 10:28:57 +0100 Subject: Simplify SPCanvas by tracking the clean region instead of the dirty region. #Hackfest2016 (bzr r14816) --- src/display/sp-canvas.cpp | 113 ++++++++++++++++------------------------------ src/display/sp-canvas.h | 5 +- 2 files changed, 42 insertions(+), 76 deletions(-) (limited to 'src/display') diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index 598f45a7a..644da8d5a 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -12,7 +12,7 @@ * * Copyright (C) 1998 The Free Software Foundation * Copyright (C) 2002-2006 authors - * Copyright (C) 2016 Google + * Copyright (C) 2016 Google Inc. * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -958,7 +958,7 @@ static void sp_canvas_init(SPCanvas *canvas) canvas->_drawing_disabled = false; canvas->_backing_store = NULL; - canvas->_dirty_region = cairo_region_create(); + canvas->_clean_region = cairo_region_create(); canvas->_forced_redraw_count = 0; canvas->_forced_redraw_limit = -1; @@ -971,12 +971,11 @@ static void sp_canvas_init(SPCanvas *canvas) void SPCanvas::shutdownTransients() { - // 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; + // Reset the clean region + if (_clean_region && !cairo_region_is_empty(_clean_region)) { + cairo_region_destroy(_clean_region); + _clean_region = cairo_region_create(); + } if (_grabbed_item) { _grabbed_item = NULL; @@ -1003,9 +1002,9 @@ void SPCanvas::dispose(GObject *object) cairo_surface_destroy(canvas->_backing_store); canvas->_backing_store = NULL; } - if (canvas->_dirty_region) { - cairo_region_destroy(canvas->_dirty_region); - canvas->_dirty_region = NULL; + if (canvas->_clean_region) { + cairo_region_destroy(canvas->_clean_region); + canvas->_clean_region = NULL; } canvas->shutdownTransients(); @@ -1150,7 +1149,7 @@ void SPCanvas::handle_size_allocate(GtkWidget *widget, GtkAllocation *allocation Geom::IntRect new_area = Geom::IntRect::from_xywh(canvas->_x0, canvas->_y0, allocation->width, allocation->height); - // resize backing store + // resize backing store; the clean region does not change cairo_surface_t *new_backing_store = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation->width, allocation->height); if (canvas->_backing_store) { @@ -1174,19 +1173,7 @@ void SPCanvas::handle_size_allocate(GtkWidget *widget, GtkAllocation *allocation allocation->x, allocation->y, allocation->width, allocation->height); } - - if (allocation->width > old_allocation.width) { - canvas->requestRedraw(canvas->_x0 + old_allocation.width, - canvas->_y0, - canvas->_x0 + allocation->width, - canvas->_y0 + allocation->height); - } - if (allocation->height > old_allocation.height) { - canvas->requestRedraw(canvas->_x0, - canvas->_y0 + old_allocation.height, - canvas->_x0 + allocation->width, - canvas->_y0 + allocation->height); - } + canvas->addIdle(); } int SPCanvas::emitEvent(GdkEvent *event) @@ -1622,7 +1609,7 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect cairo_surface_destroy(imgs); cairo_rectangle_int_t crect = { paint_rect.left(), paint_rect.right(), paint_rect.width(), paint_rect.height() }; - cairo_region_subtract_rectangle(_dirty_region, &crect); + cairo_region_union_rectangle(_clean_region, &crect); gtk_widget_queue_draw_area(GTK_WIDGET(this), paint_rect.left() -_x0, paint_rect.top() - _y0, paint_rect.width(), paint_rect.height()); @@ -1826,8 +1813,8 @@ gboolean SPCanvas::handle_draw(GtkWidget *widget, cairo_t *cr) { cairo_rectangle_list_destroy(rects); cairo_region_t *draw_dirty = cairo_region_copy(draw_region); - cairo_region_intersect(draw_dirty, canvas->_dirty_region); - cairo_region_subtract(draw_region, draw_dirty); + cairo_region_subtract(draw_dirty, canvas->_clean_region); + cairo_region_intersect(draw_region, canvas->_clean_region); // Draw the clean portion if (!cairo_region_is_empty(draw_region)) { @@ -1846,11 +1833,8 @@ gboolean SPCanvas::handle_draw(GtkWidget *widget, cairo_t *cr) { } // Render the dirty portion in the background - int n_rects = cairo_region_num_rectangles(draw_dirty); - for (int i = 0; i < n_rects; ++i) { - cairo_rectangle_int_t crect; - cairo_region_get_rectangle(draw_dirty, i, &crect); - canvas->requestRedraw(crect.x, crect.y, crect.x + crect.width, crect.y + crect.height); + if (!cairo_region_is_empty(draw_dirty)) { + canvas->addIdle(); } cairo_region_destroy(draw_region); cairo_region_destroy(draw_dirty); @@ -1920,22 +1904,23 @@ int SPCanvas::paint() sp_canvas_item_invoke_update(_root, Geom::identity(), 0); _need_update = FALSE; } - if (!_need_redraw) { - return TRUE; - } - int n_rects = cairo_region_num_rectangles(_dirty_region); + 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); + + 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(_dirty_region, i, &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; }; } - _need_redraw = FALSE; - // we've had a full unaborted redraw, reset the full redraw counter if (_forced_redraw_limit != -1) { _forced_redraw_count = 0; @@ -2035,39 +2020,32 @@ void SPCanvas::scrollTo(double cx, double cy, unsigned int clear, bool is_scroll cairo_surface_destroy(_backing_store); _backing_store = new_backing_store; - cairo_rectangle_int_t crect = { _x0, _y0, allocation.width, allocation.height }; - cairo_region_intersect_rectangle(_dirty_region, &crect); + if (clear) { + cairo_region_destroy(_clean_region); + _clean_region = cairo_region_create(); + } else { + cairo_rectangle_int_t crect = { _x0, _y0, allocation.width, allocation.height }; + cairo_region_intersect_rectangle(_clean_region, &crect); + } if (SP_CANVAS_ITEM_GET_CLASS(_root)->viewbox_changed) { SP_CANVAS_ITEM_GET_CLASS(_root)->viewbox_changed(_root, new_area); } - if (clear) { - requestRedraw(_x0, _y0, allocation.width, allocation.height); - } else { + if (!clear) { // scrolling without zoom; redraw only the newly exposed areas if ((dx != 0) || (dy != 0)) { if (gtk_widget_get_realized(GTK_WIDGET(this))) { gdk_window_scroll(getWindow(this), -dx, -dy); } } - - if (dx > 0) { - requestRedraw(_x0 + allocation.width - dx, _y0, _x0 + allocation.width, _y0 + allocation.height); - } else if (dx < 0) { - requestRedraw(_x0, _y0, _x0 - dx, _y0 + allocation.height); - } - if (dy > 0) { - requestRedraw(_x0, _y0 + allocation.height - dy, _x0 + allocation.width, _y0 + allocation.height); - } else if (dy < 0) { - requestRedraw(_x0, _y0, _x0 + allocation.width, _y0 - dy); - } } + addIdle(); } void SPCanvas::updateNow() { - if (_need_update || _need_redraw) { + if (_need_update) { doUpdate(); } } @@ -2080,26 +2058,16 @@ 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); - gtk_widget_get_allocation(GTK_WIDGET(this), &allocation); - - 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(); - } + dirtyRect(bbox); + addIdle(); } /** @@ -2204,7 +2172,6 @@ inline int sp_canvas_tile_ceil(int x) } void SPCanvas::dirtyRect(Geom::IntRect const &area) { - _need_redraw = TRUE; markRect(area, 1); } @@ -2212,9 +2179,9 @@ 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_union_rectangle(_dirty_region, &crect); + cairo_region_subtract_rectangle(_clean_region, &crect); } else { - cairo_region_subtract_rectangle(_dirty_region, &crect); + cairo_region_union_rectangle(_clean_region, &crect); } } diff --git a/src/display/sp-canvas.h b/src/display/sp-canvas.h index b626beedb..a1f8d0a1a 100644 --- a/src/display/sp-canvas.h +++ b/src/display/sp-canvas.h @@ -15,7 +15,7 @@ * * Copyright (C) 1998 The Free Software Foundation * Copyright (C) 2002 Lauris Kaplinski - * Copyright (C) 2016 Google + * Copyright (C) 2016 Google Inc. * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -182,7 +182,7 @@ public: /* Area that needs redrawing, stored as a microtile array */ cairo_surface_t *_backing_store; - cairo_region_t *_dirty_region; + cairo_region_t *_clean_region; /** Last known modifier state, for deferred repick when a button is down. */ int _state; @@ -208,7 +208,6 @@ public: int _close_enough; unsigned int _need_update : 1; - unsigned int _need_redraw : 1; unsigned int _need_repick : 1; int _forced_redraw_count; -- cgit v1.2.3 From d2a3bc0b327557fba34f09a110a0ac5b6d18f85e Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Wed, 13 Apr 2016 12:38:28 +0100 Subject: Move background drawing to SPCanvas to avoid temporarily drawing an incorrect background. #Hackfest2016 (bzr r14821) --- src/display/sp-canvas.cpp | 85 +++++++++++++++++++++++++++++++++++------------ src/display/sp-canvas.h | 18 +++++++--- 2 files changed, 76 insertions(+), 27 deletions(-) (limited to 'src/display') diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index 644da8d5a..6b7836d2e 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -27,6 +27,7 @@ #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" @@ -37,6 +38,7 @@ #include "display/cairo-utils.h" #include "debug/gdk-event-latency-tracker.h" #include "desktop.h" +#include "color.h" using Inkscape::Debug::GdkEventLatencyTracker; @@ -959,6 +961,8 @@ static void sp_canvas_init(SPCanvas *canvas) 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->_forced_redraw_count = 0; canvas->_forced_redraw_limit = -1; @@ -972,10 +976,7 @@ static void sp_canvas_init(SPCanvas *canvas) void SPCanvas::shutdownTransients() { // Reset the clean region - if (_clean_region && !cairo_region_is_empty(_clean_region)) { - cairo_region_destroy(_clean_region); - _clean_region = cairo_region_create(); - } + dirtyAll(); if (_grabbed_item) { _grabbed_item = NULL; @@ -1006,6 +1007,10 @@ void SPCanvas::dispose(GObject *object) 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) @@ -1529,9 +1534,6 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect { GtkWidget *widget = GTK_WIDGET (this); - // Mark the region clean - markRect(paint_rect, 0); - SPCanvasBuf buf; buf.buf = NULL; buf.buf_rowstride = 0; @@ -1543,7 +1545,6 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect // 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); @@ -1553,18 +1554,12 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect //cairo_stroke_preserve(buf.ct); //cairo_clip(buf.ct); -#if GTK_CHECK_VERSION(3,0,0) - GtkStyleContext *context = gtk_widget_get_style_context(widget); - gtk_render_background(context, buf.ct, 0, 0, paint_rect.width(), paint_rect.height()); -#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_set_operator(buf.ct, CAIRO_OPERATOR_OVER); + cairo_restore(buf.ct); if (_root->visible) { SP_CANVAS_ITEM_GET_CLASS(_root)->render(_root, &buf); @@ -1608,8 +1603,8 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect cairo_destroy(xct); cairo_surface_destroy(imgs); - cairo_rectangle_int_t crect = { paint_rect.left(), paint_rect.right(), paint_rect.width(), paint_rect.height() }; - cairo_region_union_rectangle(_clean_region, &crect); + // 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()); @@ -1816,6 +1811,16 @@ gboolean SPCanvas::handle_draw(GtkWidget *widget, cairo_t *cr) { cairo_region_subtract(draw_dirty, canvas->_clean_region); cairo_region_intersect(draw_region, canvas->_clean_region); + // Draw the background + cairo_save(cr); + cairo_translate(cr, -canvas->_x0, -canvas->_y0); + cairo_set_source(cr, canvas->_background); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_paint(cr); + cairo_restore(cr); + /*cairo_set_source(cr, canvas->_background); + cairo_paint(cr);*/ + // Draw the clean portion if (!cairo_region_is_empty(draw_region)) { cairo_region_translate(draw_region, -canvas->_x0, -canvas->_y0); @@ -2007,6 +2012,7 @@ void SPCanvas::scrollTo(double cx, double cy, unsigned int clear, bool is_scroll 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); @@ -2021,8 +2027,7 @@ void SPCanvas::scrollTo(double cx, double cy, unsigned int clear, bool is_scroll _backing_store = new_backing_store; if (clear) { - cairo_region_destroy(_clean_region); - _clean_region = cairo_region_create(); + dirtyAll(); } else { cairo_rectangle_int_t crect = { _x0, _y0, allocation.width, allocation.height }; cairo_region_intersect_rectangle(_clean_region, &crect); @@ -2070,6 +2075,35 @@ void SPCanvas::requestRedraw(int x0, int y0, int x1, int y1) 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(); +} + +void SPCanvas::setBackgroundCheckerboard() { + if (_background_is_checkerboard) return; + if (_background) { + cairo_pattern_destroy(_background); + } + _background = ink_cairo_pattern_create_checkerboard(); + _background_is_checkerboard = true; + dirtyAll(); + addIdle(); +} + /** * Sets world coordinates from win and canvas. */ @@ -2175,6 +2209,13 @@ void SPCanvas::dirtyRect(Geom::IntRect const &area) { markRect(area, 1); } +void SPCanvas::dirtyAll() { + if (_clean_region && !cairo_region_is_empty(_clean_region)) { + cairo_region_destroy(_clean_region); + _clean_region = cairo_region_create(); + } +} + void SPCanvas::markRect(Geom::IntRect const &area, uint8_t val) { cairo_rectangle_int_t crect = { area.left(), area.top(), area.width(), area.height() }; diff --git a/src/display/sp-canvas.h b/src/display/sp-canvas.h index a1f8d0a1a..171fdaf67 100644 --- a/src/display/sp-canvas.h +++ b/src/display/sp-canvas.h @@ -87,6 +87,9 @@ struct SPCanvas { Geom::IntRect getViewboxIntegers() const; SPCanvasGroup *getRoot(); + void setBackgroundColor(guint32 rgba); + void setBackgroundCheckerboard(); + /// Returns new canvas as widget. static GtkWidget *createAA(); @@ -105,7 +108,8 @@ private: /// Marks the specified area as dirty (requiring redraw) void dirtyRect(Geom::IntRect const &area); - /// Marks specific canvas rectangle as clean (val == 0) or dirty (otherwise) + /// Marks the whole widget for redraw + void dirtyAll(); void markRect(Geom::IntRect const &area, uint8_t val); /// Invokes update, paint, and repick on canvas. @@ -177,14 +181,18 @@ public: bool _is_dragging; double _dx0; double _dy0; - int _x0; - int _y0; + int _x0; ///< World coordinate of the leftmost pixels + int _y0; ///< World coordinate of the topmost pixels - /* Area that needs redrawing, stored as a microtile array */ + /// 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. */ + /// Last known modifier state, for deferred repick when a button is down. int _state; /** The item containing the mouse pointer, or NULL if none. */ -- cgit v1.2.3 From de93b23d78770247c0b69a0b11b6097396a09fb5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Wed, 13 Apr 2016 12:58:25 +0100 Subject: Fix redraw problems when shrinking and then enlarging the SPCanvas widget. #Hackfest2016 (bzr r14824) --- src/display/sp-canvas.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/display') diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index 6b7836d2e..a311de7f1 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -1154,7 +1154,7 @@ void SPCanvas::handle_size_allocate(GtkWidget *widget, GtkAllocation *allocation Geom::IntRect new_area = Geom::IntRect::from_xywh(canvas->_x0, canvas->_y0, allocation->width, allocation->height); - // resize backing store; the clean region does not change + // resize backing store cairo_surface_t *new_backing_store = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation->width, allocation->height); if (canvas->_backing_store) { @@ -1167,9 +1167,12 @@ void SPCanvas::handle_size_allocate(GtkWidget *widget, GtkAllocation *allocation } 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 if (SP_CANVAS_ITEM_GET_CLASS (canvas->_root)->viewbox_changed) SP_CANVAS_ITEM_GET_CLASS (canvas->_root)->viewbox_changed (canvas->_root, new_area); @@ -1178,6 +1181,7 @@ void SPCanvas::handle_size_allocate(GtkWidget *widget, GtkAllocation *allocation allocation->x, allocation->y, allocation->width, allocation->height); } + // Schedule redraw of any newly exposed regions canvas->addIdle(); } @@ -1818,8 +1822,6 @@ gboolean SPCanvas::handle_draw(GtkWidget *widget, cairo_t *cr) { cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); cairo_paint(cr); cairo_restore(cr); - /*cairo_set_source(cr, canvas->_background); - cairo_paint(cr);*/ // Draw the clean portion if (!cairo_region_is_empty(draw_region)) { -- cgit v1.2.3 From 9e005239a9a2c93f40b1ac0e1a8e711ec7a2234e Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Wed, 13 Apr 2016 14:56:01 +0100 Subject: Fix canvas flicker while dragging objects. #Hackfest2016 (bzr r14829) --- src/display/sp-canvas.cpp | 44 +++++++++++--------------------------------- 1 file changed, 11 insertions(+), 33 deletions(-) (limited to 'src/display') diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index a311de7f1..3a801826b 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -1798,8 +1798,14 @@ void SPCanvas::endForcedFullRedraws() 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 *draw_region = cairo_region_create(); + cairo_region_t *dirty_region = cairo_region_create(); for (int i = 0; i < rects->num_rectangles; i++) { cairo_rectangle_t rectangle = rects->rectangles[i]; @@ -1807,44 +1813,16 @@ gboolean SPCanvas::handle_draw(GtkWidget *widget, cairo_t *cr) { 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(draw_region, &irect); + cairo_region_union_rectangle(dirty_region, &irect); } cairo_rectangle_list_destroy(rects); - - cairo_region_t *draw_dirty = cairo_region_copy(draw_region); - cairo_region_subtract(draw_dirty, canvas->_clean_region); - cairo_region_intersect(draw_region, canvas->_clean_region); - - // Draw the background - cairo_save(cr); - cairo_translate(cr, -canvas->_x0, -canvas->_y0); - cairo_set_source(cr, canvas->_background); - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - cairo_paint(cr); - cairo_restore(cr); - - // Draw the clean portion - if (!cairo_region_is_empty(draw_region)) { - cairo_region_translate(draw_region, -canvas->_x0, -canvas->_y0); - cairo_save(cr); - int n_rects = cairo_region_num_rectangles(draw_region); - for (int i = 0; i < n_rects; ++i) { - cairo_rectangle_int_t crect; - cairo_region_get_rectangle(draw_region, i, &crect); - cairo_rectangle(cr, crect.x, crect.y, crect.width, crect.height); - } - cairo_clip(cr); - cairo_set_source_surface(cr, canvas->_backing_store, 0, 0); - cairo_paint(cr); - cairo_restore(cr); - } + cairo_region_subtract(dirty_region, canvas->_clean_region); // Render the dirty portion in the background - if (!cairo_region_is_empty(draw_dirty)) { + if (!cairo_region_is_empty(dirty_region)) { canvas->addIdle(); } - cairo_region_destroy(draw_region); - cairo_region_destroy(draw_dirty); + cairo_region_destroy(dirty_region); return TRUE; } -- cgit v1.2.3 From af72bed26b283d07ab91b147d5b8791edef64cc5 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Wed, 13 Apr 2016 15:19:07 +0100 Subject: Fix artifacts at the border when panning the canvas. #Hackfest2016 (bzr r14831) --- src/display/sp-canvas.cpp | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) (limited to 'src/display') diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index 3a801826b..36fea767e 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -1544,20 +1544,11 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect 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); - // 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); - cairo_save(buf.ct); cairo_translate(buf.ct, -paint_rect.left(), -paint_rect.top()); cairo_set_source(buf.ct, _background); @@ -1984,11 +1975,6 @@ 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); - - _dx0 = cx; // here the 'd' stands for double, not delta! - _dy0 = cy; - _x0 = ix; - _y0 = iy; gtk_widget_get_allocation(&_widget, &allocation); @@ -1997,15 +1983,26 @@ void SPCanvas::scrollTo(double cx, double cy, unsigned int clear, bool is_scroll 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_source_rgb(cr, 1, 1, 1); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + // Paint the background + cairo_translate(cr, -ix, -iy); + cairo_set_source(cr, _background); cairo_paint(cr); - cairo_set_source_surface(cr, _backing_store, -dx, -dy); + // 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 { -- cgit v1.2.3 From d18eee586af65f913c7f614c9c9548ebf2594f3e Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Wed, 13 Apr 2016 15:38:06 +0100 Subject: Hopefully fix "invalid state when picking" warnings. #Hackfest2016 (bzr r14832) --- src/display/canvas-arena.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src/display') diff --git a/src/display/canvas-arena.cpp b/src/display/canvas-arena.cpp index ec99eca9a..366b3c7d1 100644 --- a/src/display/canvas-arena.cpp +++ b/src/display/canvas-arena.cpp @@ -250,7 +250,8 @@ sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event) arena->c = Geom::Point(event->crossing.x, event->crossing.y); /* fixme: Not sure abut this, but seems the right thing (Lauris) */ - arena->drawing.update(Geom::IntRect::infinite(), arena->ctx, DrawingItem::STATE_PICK, 0); + arena->drawing.update(Geom::IntRect::infinite(), arena->ctx, + DrawingItem::STATE_PICK | DrawingItem::STATE_BBOX, 0); arena->active = arena->drawing.pick(arena->c, arena->drawing.delta, arena->sticky); ret = sp_canvas_arena_send_event (arena, event); } @@ -269,7 +270,8 @@ sp_canvas_arena_event (SPCanvasItem *item, GdkEvent *event) arena->c = Geom::Point(event->motion.x, event->motion.y); /* fixme: Not sure abut this, but seems the right thing (Lauris) */ - arena->drawing.update(Geom::IntRect::infinite(), arena->ctx, DrawingItem::STATE_PICK); + arena->drawing.update(Geom::IntRect::infinite(), arena->ctx, + DrawingItem::STATE_PICK | DrawingItem::STATE_BBOX); new_arena = arena->drawing.pick(arena->c, arena->drawing.delta, arena->sticky); if (new_arena != arena->active) { GdkEventCrossing ec; -- cgit v1.2.3 From b9212ef6bdf7172f053bb8821d6579c9ab5e14cb Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Wed, 13 Apr 2016 15:40:55 +0100 Subject: Remove unused variable in sp-canvas.cpp (bzr r14833) --- src/display/sp-canvas.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/display') diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index 36fea767e..decb14184 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -1536,8 +1536,6 @@ 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); - SPCanvasBuf buf; buf.buf = NULL; buf.buf_rowstride = 0; -- cgit v1.2.3 From f5a95a0c8e4080b59d43cdcdcc1ea6b717f3d3f3 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Wed, 13 Apr 2016 17:02:57 +0200 Subject: Remove no longer needed warning about feTile rendering. (bzr r14835) --- src/display/nr-filter-tile.cpp | 12 ------------ 1 file changed, 12 deletions(-) (limited to 'src/display') diff --git a/src/display/nr-filter-tile.cpp b/src/display/nr-filter-tile.cpp index 7172f88ee..c151c8537 100644 --- a/src/display/nr-filter-tile.cpp +++ b/src/display/nr-filter-tile.cpp @@ -32,18 +32,6 @@ FilterTile::~FilterTile() void FilterTile::render_cairo(FilterSlot &slot) { - // FIX ME! - static bool tile_warning = false; - if (!tile_warning) { - g_warning("Renderer for feTile has non-optimal implementation, expect slowness and bugs."); - tile_warning = true; - } - - // Fixing isn't so easy as the Inkscape renderer breaks the canvas into "rendering" tiles for - // faster rendering. (The "rendering" tiles are not the same as the tiles in this primitive.) - // Only if the the feTile tile source falls inside the current "rendering" tile will the tile - // image be available. - // This input source contains only the "rendering" tile. cairo_surface_t *in = slot.getcairo(_input); -- cgit v1.2.3 From 6572b29914475c769c035265b089e9668c47a974 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Thu, 14 Apr 2016 15:33:35 -0400 Subject: Change idle priority back to high (bzr r14848) --- src/display/sp-canvas.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/display') diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index decb14184..46be95518 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -126,7 +126,7 @@ struct SPCanvasClass { namespace { -gint const UPDATE_PRIORITY = G_PRIORITY_DEFAULT_IDLE; +gint const UPDATE_PRIORITY = G_PRIORITY_HIGH_IDLE; GdkWindow *getWindow(SPCanvas *canvas) { -- cgit v1.2.3 From 50a770bd6f47f27d8a45894e2ff19cf630b4c9f8 Mon Sep 17 00:00:00 2001 From: "Liam P. White" Date: Thu, 14 Apr 2016 20:35:13 -0400 Subject: Priority is so high it blocks blitting the canvas (bzr r14849) --- src/display/sp-canvas.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/display') diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index 46be95518..decb14184 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -126,7 +126,7 @@ struct SPCanvasClass { namespace { -gint const UPDATE_PRIORITY = G_PRIORITY_HIGH_IDLE; +gint const UPDATE_PRIORITY = G_PRIORITY_DEFAULT_IDLE; GdkWindow *getWindow(SPCanvas *canvas) { -- cgit v1.2.3 From d5d626483bf0568595b4c921b709850e64e6e759 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Fri, 22 Apr 2016 17:57:41 +0200 Subject: Correct enumeration names. (bzr r14862) --- src/display/drawing-image.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/display') diff --git a/src/display/drawing-image.cpp b/src/display/drawing-image.cpp index 2a943d16c..e23c89c59 100644 --- a/src/display/drawing-image.cpp +++ b/src/display/drawing-image.cpp @@ -118,14 +118,14 @@ unsigned DrawingImage::_renderItem(DrawingContext &dc, Geom::IntRect const &/*ar // http://www.w3.org/TR/css4-images/#the-image-rendering // style.h/style.cpp switch (_style->image_rendering.computed) { - case SP_CSS_COLOR_RENDERING_AUTO: + case SP_CSS_IMAGE_RENDERING_AUTO: // Do nothing break; - case SP_CSS_COLOR_RENDERING_OPTIMIZEQUALITY: + case SP_CSS_IMAGE_RENDERING_OPTIMIZEQUALITY: // In recent Cairo, BEST used Lanczos3, which is prohibitively slow dc.patternSetFilter( CAIRO_FILTER_GOOD ); break; - case SP_CSS_COLOR_RENDERING_OPTIMIZESPEED: + case SP_CSS_IMAGE_RENDERING_OPTIMIZESPEED: default: dc.patternSetFilter( CAIRO_FILTER_NEAREST ); break; -- cgit v1.2.3 From efb5cb4a7a22316994b7a89b51d3d0ca654dabd4 Mon Sep 17 00:00:00 2001 From: Krzysztof Kosi??ski Date: Sat, 7 May 2016 22:55:11 -0700 Subject: Clarify license. Most Inkscape source code does not specify GPL version, so it is essentially GPL v1+ under section 9. Authors of the few GPL v2 only files were contacted and all agreed to relicense under GPL v2 or later. We also have a few files copies from GIMP, which are GPL v3+, so the complete program is available under GPL v3 or later. (bzr r14873) --- src/display/sp-canvas.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src/display') diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index decb14184..7d76fa043 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -1159,8 +1159,11 @@ void SPCanvas::handle_size_allocate(GtkWidget *widget, GtkAllocation *allocation allocation->width, allocation->height); if (canvas->_backing_store) { cairo_t *cr = cairo_create(new_backing_store); - cairo_set_source_surface(cr, canvas->_backing_store, 0, 0); + 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); -- cgit v1.2.3