Code

lay groundwork for non-filter view mode
[inkscape.git] / src / display / nr-arena-item.cpp
index 0657144eddbacdc17ceb4274e9d8c6d56c580eaa..195dba2f073c530a70c66f3220a291f48112ada1 100644 (file)
 #define noNR_ARENA_ITEM_VERBOSE
 #define noNR_ARENA_ITEM_DEBUG_CASCADE
 
+#include <cstring>
+#include <string>
 
 #include <libnr/nr-blit.h>
 #include <libnr/nr-pixops.h>
+#include <libnr/nr-matrix-ops.h>
+#include <libnr/nr-matrix-fns.h>
 #include "nr-arena.h"
 #include "nr-arena-item.h"
 #include "gc-core.h"
@@ -203,6 +207,7 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc,
                              unsigned int state, unsigned int reset)
 {
     NRGC childgc (gc);
+    bool filter = (item->arena->rendermode == Inkscape::RENDERMODE_NORMAL);
 
     nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID);
     nr_return_val_if_fail (NR_IS_ARENA_ITEM (item),
@@ -243,8 +248,7 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc,
     /* Set up local gc */
     childgc = *gc;
     if (item->transform) {
-        nr_matrix_multiply (&childgc.transform, item->transform,
-                            &childgc.transform);
+        childgc.transform = (*item->transform) * childgc.transform;
     }
     /* Remember the transformation matrix */
     item->ctm = childgc.transform;
@@ -256,13 +260,18 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc,
     if (item->state & NR_ARENA_ITEM_STATE_INVALID)
         return item->state;
     /* Enlarge the bounding box to contain filter effects */
-    if (item->filter) {
+    if (item->filter && filter) {
         item->filter->bbox_enlarge (item->bbox);
     }
+    // fixme: to fix the display glitches, in outline mode bbox must be a combination of 
+    // full item bbox and its clip and mask (after we have the API to get these)
 
     /* Clipping */
     if (item->clip) {
-        unsigned int newstate = nr_arena_item_invoke_update (item->clip, area, &childgc, state, reset);
+        // FIXME: since here we only need bbox, consider passing 
+        // ((state & !(NR_ARENA_ITEM_STATE_RENDER)) | NR_ARENA_ITEM_STATE_BBOX)
+        // instead of state, so it does not have to create rendering structures in nr_arena_shape_update
+        unsigned int newstate = nr_arena_item_invoke_update (item->clip, area, &childgc, state, reset); 
         if (newstate & NR_ARENA_ITEM_STATE_INVALID) {
             item->state |= NR_ARENA_ITEM_STATE_INVALID;
             return item->state;
@@ -289,10 +298,11 @@ nr_arena_item_invoke_update (NRArenaItem *item, NRRectL *area, NRGC *gc,
  */
 
 unsigned int
-nr_arena_item_invoke_render (NRArenaItem *item, NRRectL const *area,
+nr_arena_item_invoke_render (cairo_t *ct, NRArenaItem *item, NRRectL const *area,
                              NRPixBlock *pb, unsigned int flags)
 {
-   bool outline = (item->arena->rendermode == RENDERMODE_OUTLINE);
+   bool outline = (item->arena->rendermode == Inkscape::RENDERMODE_OUTLINE);
+    bool filter = (item->arena->rendermode == Inkscape::RENDERMODE_NORMAL);
 
     nr_return_val_if_fail (item != NULL, NR_ARENA_ITEM_STATE_INVALID);
     nr_return_val_if_fail (NR_IS_ARENA_ITEM (item),
@@ -313,11 +323,39 @@ nr_arena_item_invoke_render (NRArenaItem *item, NRRectL const *area,
     nr_rect_l_intersect (&carea, area, &item->bbox);
     if (nr_rect_l_test_empty (&carea))
         return item->state | NR_ARENA_ITEM_STATE_RENDER;
-    if (item->filter && !outline) {
-        nr_rect_l_enlarge (&carea, item->filter->get_enlarge (item->ctm));
+    if (item->filter && filter) {
+        item->filter->area_enlarge (carea, item->ctm);
         nr_rect_l_intersect (&carea, &carea, &item->bbox);
     }
 
+    if (outline) {
+    // No caching in outline mode for now; investigate if it really gives any advantage with cairo.
+    // Also no attempts to clip anything; just render everything: item, clip, mask   
+            // First, render the object itself 
+            unsigned int state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, &carea, pb, flags);
+            if (state & NR_ARENA_ITEM_STATE_INVALID) {
+                /* Clean up and return error */
+                item->state |= NR_ARENA_ITEM_STATE_INVALID;
+                return item->state;
+            }
+
+            // render clip and mask, if any
+            guint32 saved_rgba = item->arena->outlinecolor; // save current outline color
+            // render clippath as an object, using a different color
+            if (item->clip) {
+                item->arena->outlinecolor = prefs_get_int_attribute("options.wireframecolors", "clips", 0x00ff00ff); // green clips
+                NR_ARENA_ITEM_VIRTUAL (item->clip, render) (ct, item->clip, &carea, pb, flags);
+            } 
+            // render mask as an object, using a different color
+            if (item->mask) {
+                item->arena->outlinecolor = prefs_get_int_attribute("options.wireframecolors", "masks", 0x0000ffff); // blue masks
+                NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ct, item->mask, &carea, pb, flags);
+            }
+            item->arena->outlinecolor = saved_rgba; // restore outline color
+
+            return item->state | NR_ARENA_ITEM_STATE_RENDER;
+    }
+
     NRPixBlock cpb;
     if (item->px) {
         /* Has cache pixblock, render this and return */
@@ -359,12 +397,12 @@ nr_arena_item_invoke_render (NRArenaItem *item, NRRectL const *area,
         dpb = &cpb;
         // Set nocache flag for downstream rendering
         flags |= NR_ARENA_ITEM_RENDER_NO_CACHE;
-    } 
+    }
 
     /* Determine, whether we need temporary buffer */
     if (item->clip || item->mask
-        || ((item->opacity != 255) && !item->render_opacity && !outline)
-        || (item->filter && !outline) || item->background_new
+        || ((item->opacity != 255) && !item->render_opacity)
+        || (item->filter && filter) || item->background_new
         || (item->parent && item->parent->background_pb)) {
 
         /* Setup and render item buffer */
@@ -374,19 +412,24 @@ nr_arena_item_invoke_render (NRArenaItem *item, NRRectL const *area,
                                 TRUE);
 
         //  if memory allocation failed, abort render
-        if (ipb.data.px == NULL) {
+        if (ipb.size != NR_PIXBLOCK_SIZE_TINY && ipb.data.px == NULL) {
             nr_pixblock_release (&ipb);
             return (item->state);
         }
 
         /* If background access is used, save the pixblock address.
          * This address is set to NULL at the end of this block */
-        if (item->background_new
-            || (item->parent && item->parent->background_pb)) {
+        if (item->background_new ||
+            (item->parent && item->parent->background_pb)) {
             item->background_pb = &ipb;
         }
+
         ipb.visible_area = pb->visible_area;
-        unsigned int state = NR_ARENA_ITEM_VIRTUAL (item, render) (item, &carea, &ipb, flags);
+        if (item->filter && filter) {
+              item->filter->area_enlarge (ipb.visible_area, item->ctm);
+        }
+
+        unsigned int state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, &carea, &ipb, flags);
         if (state & NR_ARENA_ITEM_STATE_INVALID) {
             /* Clean up and return error */
             nr_pixblock_release (&ipb);
@@ -398,11 +441,11 @@ nr_arena_item_invoke_render (NRArenaItem *item, NRRectL const *area,
         ipb.empty = FALSE;
 
         /* Run filtering, if a filter is set for this object */
-        if (item->filter && !outline) {
+        if (item->filter && filter) {
             item->filter->render (item, &ipb);
         }
 
-        if ((item->clip || item->mask) && !outline) {
+        if (item->clip || item->mask) {
             /* Setup mask pixblock */
             NRPixBlock mpb;
             nr_pixblock_setup_fast (&mpb, NR_PIXBLOCK_MODE_A8, carea.x0,
@@ -436,7 +479,7 @@ nr_arena_item_invoke_render (NRArenaItem *item, NRRectL const *area,
                     if (tpb.data.px != NULL) { // if memory allocation was successful
 
                         tpb.visible_area = pb->visible_area;
-                        unsigned int state = NR_ARENA_ITEM_VIRTUAL (item->mask, render) (item->mask, &carea, &tpb, flags);
+                        unsigned int state = NR_ARENA_ITEM_VIRTUAL (item->mask, render) (ct, item->mask, &carea, &tpb, flags);
                         if (state & NR_ARENA_ITEM_STATE_INVALID) {
                             /* Clean up and return error */
                             nr_pixblock_release (&tpb);
@@ -489,7 +532,7 @@ nr_arena_item_invoke_render (NRArenaItem *item, NRRectL const *area,
                 }
                 /* Multiply with opacity if needed */
                 if ((item->opacity != 255) && !item->render_opacity
-                    && !outline) {
+                    ) {
                     int x, y;
                     unsigned int a;
                     a = item->opacity;
@@ -506,35 +549,6 @@ nr_arena_item_invoke_render (NRArenaItem *item, NRRectL const *area,
                 nr_blit_pixblock_pixblock_mask (dpb, &ipb, &mpb);
             }
             nr_pixblock_release (&mpb);
-            /* This pointer wouldn't be valid outside this block, so clear it */
-            item->background_pb = NULL;
-
-        } else if ((item->clip || item->mask) && outline) {
-            // Render clipped or masked object in outline mode:
-
-            // First, render the object itself 
-            unsigned int state = NR_ARENA_ITEM_VIRTUAL (item, render) (item, &carea, dpb, flags);
-            if (state & NR_ARENA_ITEM_STATE_INVALID) {
-                /* Clean up and return error */
-                if (dpb != pb)
-                    nr_pixblock_release (dpb);
-                item->state |= NR_ARENA_ITEM_STATE_INVALID;
-                return item->state;
-            }
-
-            guint32 saved_rgba = item->arena->outlinecolor; // save current outline color
-            // render clippath as an object, using a different color
-            if (item->clip) {
-                item->arena->outlinecolor = prefs_get_int_attribute("options.wireframecolors", "clips", 0x00ff00ff); // green clips
-                NR_ARENA_ITEM_VIRTUAL (item->clip, render) (item->clip, &carea, dpb, flags);
-            } 
-            // render mask as an object, using a different color
-            if (item->mask) {
-                item->arena->outlinecolor = prefs_get_int_attribute("options.wireframecolors", "masks", 0x0000ffff); // blue masks
-                NR_ARENA_ITEM_VIRTUAL (item->mask, render) (item->mask, &carea, dpb, flags);
-            }
-            item->arena->outlinecolor = saved_rgba; // restore outline color
-
         } else {
             if (item->render_opacity) { // opacity was already rendered in, just copy to dpb here
                 nr_blit_pixblock_pixblock(dpb, &ipb);
@@ -544,9 +558,11 @@ nr_arena_item_invoke_render (NRArenaItem *item, NRRectL const *area,
         }
         nr_pixblock_release (&ipb);
         dpb->empty = FALSE;
+        /* This pointer wouldn't be valid outside this block, so clear it */
+        item->background_pb = NULL;
     } else {
         /* Just render */
-        unsigned int state = NR_ARENA_ITEM_VIRTUAL (item, render) (item, &carea, dpb, flags);
+        unsigned int state = NR_ARENA_ITEM_VIRTUAL (item, render) (ct, item, &carea, dpb, flags);
         if (state & NR_ARENA_ITEM_STATE_INVALID) {
             /* Clean up and return error */
             if (dpb != pb)
@@ -697,12 +713,12 @@ nr_arena_item_append_child (NRArenaItem *parent, NRArenaItem *child)
 void
 nr_arena_item_set_transform (NRArenaItem *item, NR::Matrix const &transform)
 {
-    NRMatrix const t (transform);
+    NR::Matrix const t (transform);
     nr_arena_item_set_transform (item, &t);
 }
 
 void
-nr_arena_item_set_transform (NRArenaItem *item, NRMatrix const *transform)
+nr_arena_item_set_transform (NRArenaItem *item, NR::Matrix const *transform)
 {
     nr_return_if_fail (item != NULL);
     nr_return_if_fail (NR_IS_ARENA_ITEM (item));
@@ -710,17 +726,17 @@ nr_arena_item_set_transform (NRArenaItem *item, NRMatrix const *transform)
     if (!transform && !item->transform)
         return;
 
-    const NRMatrix *md = (item->transform) ? item->transform : &NR_MATRIX_IDENTITY;
-    const NRMatrix *ms = (transform) ? transform : &NR_MATRIX_IDENTITY;
+    const NR::Matrix *md = (item->transform) ? item->transform : &NR_MATRIX_IDENTITY;
+    const NR::Matrix *ms = (transform) ? transform : &NR_MATRIX_IDENTITY;
 
-    if (!NR_MATRIX_DF_TEST_CLOSE (md, ms, NR_EPSILON)) {
+    if (!NR::matrix_equalp(*md, *ms, NR_EPSILON)) {
         nr_arena_item_request_render (item);
-        if (!transform || nr_matrix_test_identity (transform, NR_EPSILON)) {
+        if (!transform || transform->test_identity()) {
             /* Set to identity affine */
             item->transform = NULL;
         } else {
             if (!item->transform)
-                item->transform = new (GC::ATOMIC) NRMatrix ();
+                item->transform = new (GC::ATOMIC) NR::Matrix ();
             *item->transform = *transform;
         }
         nr_arena_item_request_update (item, NR_ARENA_ITEM_STATE_ALL, TRUE);
@@ -819,6 +835,15 @@ nr_arena_item_set_order (NRArenaItem *item, int order)
     nr_arena_item_set_child_position (item->parent, item, ref);
 }
 
+void
+nr_arena_item_set_item_bbox (NRArenaItem *item, NR::Maybe<NR::Rect> &bbox)
+{
+    nr_return_if_fail(item != NULL);
+    nr_return_if_fail(NR_IS_ARENA_ITEM(item));
+
+    item->item_bbox = bbox;
+}
+
 /** Returns a background image for use with filter effects. */
 NRPixBlock *
 nr_arena_item_get_background (NRArenaItem const *item, int depth)
@@ -833,7 +858,7 @@ nr_arena_item_get_background (NRArenaItem const *item, int depth)
                                 item->background_pb->area.y0,
                                 item->background_pb->area.x1,
                                 item->background_pb->area.y1, true);
-        if (pb->data.px == NULL) // allocation failed
+        if (pb->size != NR_PIXBLOCK_SIZE_TINY && pb->data.px == NULL) // allocation failed
             return NULL;
     } else if (item->parent) {
         pb = nr_arena_item_get_background (item->parent, depth + 1);