hippo-canvas r7283 - in trunk: common/hippo linux/hippo



Author: otaylor
Date: Thu Jun 26 12:15:35 2008
New Revision: 7283
URL: http://svn.gnome.org/viewvc/hippo-canvas?rev=7283&view=rev

Log:
Optimize so that we don't repaint the entire box unnecessarily when:

 - We have a box with no borders/backgrounds or custom paint
 - It resizes but doesn't move

Only the children need to be repainted.


Modified:
   trunk/common/hippo/hippo-canvas-box.c
   trunk/common/hippo/hippo-canvas-item.c
   trunk/linux/hippo/hippo-canvas-helper.c
   trunk/linux/hippo/hippo-canvas-window.c

Modified: trunk/common/hippo/hippo-canvas-box.c
==============================================================================
--- trunk/common/hippo/hippo-canvas-box.c	(original)
+++ trunk/common/hippo/hippo-canvas-box.c	Thu Jun 26 12:15:35 2008
@@ -3179,25 +3179,28 @@
 {
     BoxChildPrivate *private = (BoxChildPrivate *)child;
     gboolean child_moved;
-    gboolean child_resized;
     int old_width, old_height;
 
     if (child->item == NULL)
         return;
 
     hippo_canvas_item_get_allocation(child->item, &old_width, &old_height);
-    
+
     child_moved = x != private->x || y != private->y;
-    child_resized = width != old_width || height != old_height;
-    
-    if ((child_moved || child_resized) && (old_width != 0 || old_height != 0))
+
+    /* We handle repainting when the child moves here, the child is however
+     * responsible for repainting itself on resize (this is to allow pure-containers
+     * that don't draw anything to avoid repainting children that stay fixed when
+     * the container resizes.
+     */
+    if (child_moved && (old_width != 0 || old_height != 0))
         hippo_canvas_item_emit_paint_needed(HIPPO_CANVAS_ITEM(private->box),
                                             private->x, private->y, old_width, old_height);
 
     private->x = x;
     private->y = y;
 
-    if ((child_moved || child_resized) && (width != 0 || height != 0))
+    if (child_moved && (width != 0 || height != 0))
         hippo_canvas_item_emit_paint_needed(HIPPO_CANVAS_ITEM(private->box),
                                             x, y, width, height);
 
@@ -3325,6 +3328,31 @@
 }
 
 static void
+layout_all_children_hidden(HippoCanvasBox *box)
+{
+    GSList *link;
+    
+    /* If we are !visible (0 allocation) then allocate all our
+     * children to 0.  This should happen in the layout algorithms
+     * below, but they are all lame about dealing with too-small
+     * allocations, so they don't "just work" for this.
+     */
+    
+    for (link = box->children; link != NULL; link = link->next) {
+        HippoCanvasBoxChild *child = link->data;
+        hippo_canvas_box_child_allocate(child, 0, 0, 0, 0, FALSE);
+    }
+}
+
+static gboolean
+has_paint_signal_handlers(HippoCanvasItem *item)
+{
+    guint paint_id = g_signal_lookup("paint", HIPPO_TYPE_CANVAS_ITEM);
+    
+    return g_signal_has_handler_pending(item, paint_id, 0, TRUE);
+}
+
+static void
 hippo_canvas_box_allocate(HippoCanvasItem *item,
                           int              allocated_box_width,
                           int              allocated_box_height,
@@ -3340,23 +3368,94 @@
     GSList *link;
     int content_x, content_y;
     gboolean has_floats;
+    gboolean size_changed;
 
     box = HIPPO_CANVAS_BOX(item);
 
+    size_changed = (box->allocated_width != allocated_box_width ||
+                    box->allocated_height != allocated_box_height);
+
     /* If we haven't emitted request-changed then we are allowed to short-circuit 
      * an unchanged allocation
      */
-    if (!origin_changed && !box->needs_allocate &&
-        (box->allocated_width == allocated_box_width && 
-         box->allocated_height == allocated_box_height))
+    if (!origin_changed && !size_changed && !box->needs_allocate)
         return;
 
+    /* Figure out whether we need to queue a repaint */
+    if (size_changed && !origin_changed) {
+        HippoCanvasBoxClass *klass = HIPPO_CANVAS_BOX_GET_CLASS(box);
+        gboolean need_repaint = TRUE;
+
+        /* Detecting if we need to repaint the box on resize is hard; it's possible
+         * that we should just make it a property; the problem with making it a
+         * property is that we want to avoid such repaints of HippoCanvasBox,
+         * as a pure container, so we'd have to make it default off. And so then
+         * you'd have to set it before connecting to ::paint or overriding
+         * paint_below_children.
+         *
+         * The exact rule we follow here is somewhat non-scientific:
+         *
+         *  - We draw borders, or background => need resize
+         *  - Subclass overrides paint_below_children or paint_above_children => need resize
+         *  - User connects to ::paint => resize needed
+         *    (Consider this a way of customizing existing painting)
+         *  - Subclass overrides paint => NO resize needed
+         *    (Subclass is really doing it's own thing ... skipping borders and backgrounds.
+         *     we dont' want to break this optimization for such classes)
+         */
+        if (klass->paint_below_children == NULL &&
+            klass->paint_above_children == NULL &&
+            klass->paint_background == hippo_canvas_box_paint_background &&
+            !has_paint_signal_handlers(item))
+        {
+            HippoCanvasStyle *style = hippo_canvas_context_get_style(HIPPO_CANVAS_CONTEXT(box));
+            guint32 background_color_rgba;
+            guint32 border_color_rgba;            
+            
+            if (box->background_color_set)
+                background_color_rgba = box->background_color_rgba;
+            else
+                background_color_rgba = hippo_canvas_style_get_background_color(style);
+
+            if (box->border_color_set)
+                border_color_rgba = box->border_color_rgba;
+            else
+                /* We just care if any have non-zero in the bottom bits, so | together */
+                border_color_rgba =
+                    (hippo_canvas_style_get_border_color(style, HIPPO_CANVAS_SIDE_LEFT) |
+                     hippo_canvas_style_get_border_color(style, HIPPO_CANVAS_SIDE_RIGHT) |
+                     hippo_canvas_style_get_border_color(style, HIPPO_CANVAS_SIDE_TOP) |
+                     hippo_canvas_style_get_border_color(style, HIPPO_CANVAS_SIDE_BOTTOM));
+
+            if (hippo_canvas_style_get_background_theme_image(style) == NULL &&
+                (background_color_rgba & 0xff) == 0 &&
+                (border_color_rgba & 0xff) == 0)
+                need_repaint = FALSE;
+        }
+
+        /* Our repaint area would be a little more accurate if we invalidated the old and new
+         * sizes separately, instead of combining them into a single box, but it's not
+         * going to be common to resize by large amounts in both directions at once.
+         */
+        if (need_repaint)
+            hippo_canvas_item_emit_paint_needed(HIPPO_CANVAS_ITEM(box), 0, 0,
+                                                MAX(box->allocated_width, allocated_box_width),
+                                                MAX(box->allocated_height, allocated_box_height));
+    }
+
     box->allocated_width = allocated_box_width;
     box->allocated_height = allocated_box_height;
     box->needs_allocate = FALSE;
 
+    if (allocated_box_width <= 0 || allocated_box_height <= 0) {
+        /* Skip computation of content area in this common case (item hidden) */
+        
+        layout_all_children_hidden(box);
+        return;
+    }
+    
     get_content_width_request(box, &requested_content_width, &natural_content_width);  
-
+    
     get_content_area_horizontal(box, requested_content_width, natural_content_width,
                                 allocated_box_width,
                                 &content_x, &allocated_content_width);
@@ -3364,12 +3463,11 @@
     get_content_height_request(box,
                                allocated_content_width,
                                &requested_content_height, &natural_content_height);
-
+    
     get_content_area_vertical(box, requested_content_height, natural_content_height,
                               allocated_box_height,
                               &content_y, &allocated_content_height);
     
-
     if (box->debug_name != NULL) {
         g_debug("box %s allocated %dx%d  requested %dx%d lay out into %d,%d %dx%d",
                 box->debug_name, box->allocated_width, box->allocated_height,
@@ -3377,18 +3475,8 @@
                 content_x, content_y, allocated_content_width, allocated_content_height);
     }
 
-    if (allocated_content_width == 0 || allocated_content_height == 0) {
-
-        /* If we are !visible (0 allocation) then allocate all our
-         * children to 0.  This should happen in the layout algorithms
-         * below, but they are all lame about dealing with too-small
-         * allocations, so they don't "just work" for this.
-         */
-        
-        for (link = box->children; link != NULL; link = link->next) {
-            HippoCanvasBoxChild *child = link->data;
-            hippo_canvas_box_child_allocate(child, 0, 0, 0, 0, origin_changed);
-        }
+    if (allocated_content_width <= 0 || allocated_content_height <= 0) {
+        layout_all_children_hidden(box);
     } else {
         /* Allocate fixed children their natural size and invisible
          * children 0x0

Modified: trunk/common/hippo/hippo-canvas-item.c
==============================================================================
--- trunk/common/hippo/hippo-canvas-item.c	(original)
+++ trunk/common/hippo/hippo-canvas-item.c	Thu Jun 26 12:15:35 2008
@@ -593,6 +593,10 @@
             damage_box.height = h;
     }
 
+    /* Skip chaining signal emission up the tree if nothing to invalidate */
+    if (damage_box.width <= 0 || damage_box.height <= 0)
+        return;
+    
     g_signal_emit(canvas_item, signals[PAINT_NEEDED], 0,
                   &damage_box);
 }

Modified: trunk/linux/hippo/hippo-canvas-helper.c
==============================================================================
--- trunk/linux/hippo/hippo-canvas-helper.c	(original)
+++ trunk/linux/hippo/hippo-canvas-helper.c	Thu Jun 26 12:15:35 2008
@@ -538,15 +538,12 @@
         int border_width = GTK_CONTAINER(helper->widget)->border_width;
         int child_width = allocation->width - border_width * 2;
         int child_height = allocation->height - border_width * 2;
-        int old_width, old_height;
         gboolean border_changed;
         
-        hippo_canvas_item_get_allocation(helper->root, &old_width, &old_height);
-
         border_changed = border_width = helper->last_allocated_border;
         helper->last_allocated_border = border_width;
 
-        if (child_width != old_width || child_height != old_height || border_changed)
+        if (border_changed)
             gtk_widget_queue_draw(helper->widget);
         
         hippo_canvas_item_allocate(helper->root,
@@ -1281,7 +1278,7 @@
     int window_x, window_y;
     
     get_root_item_window_coords(helper, &window_x, &window_y);
-    
+
     gtk_widget_queue_draw_area(widget,
                                damage_box->x + window_x,
                                damage_box->y + window_y,

Modified: trunk/linux/hippo/hippo-canvas-window.c
==============================================================================
--- trunk/linux/hippo/hippo-canvas-window.c	(original)
+++ trunk/linux/hippo/hippo-canvas-window.c	Thu Jun 26 12:15:35 2008
@@ -92,6 +92,7 @@
     GtkWidget *window_child;
 
     gtk_widget_set_app_paintable(widget, TRUE);
+    gtk_widget_set_redraw_on_allocate(widget, FALSE);
 
     gtk_widget_add_events(widget, HIPPO_CANVAS_EVENT_MASK);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]