Code

optimize cairo paths by not drawing segments that are outside of view (for stroke...
authorbuliabyak <buliabyak@users.sourceforge.net>
Sun, 18 Mar 2007 21:07:21 +0000 (21:07 +0000)
committerbuliabyak <buliabyak@users.sourceforge.net>
Sun, 18 Mar 2007 21:07:21 +0000 (21:07 +0000)
src/display/inkscape-cairo.cpp
src/display/inkscape-cairo.h
src/display/nr-arena-glyphs.cpp
src/display/nr-arena-shape.cpp

index 39cd90ed61d7ccce2e25b9ad7e0f9ce22c25de5e..9a85008851029d18e77fe673223be6c535857a91 100644 (file)
@@ -46,9 +46,13 @@ nr_create_cairo_context (NRRectL *area, NRPixBlock *pb)
 
 /** Feeds path-creating calls to the cairo context translating them from the SPCurve, with the given transform and shift */
 void
-feed_curve_to_cairo (cairo_t *ct, NArtBpath *bpath, NR::Matrix trans, NR::Point shift)
+feed_curve_to_cairo (cairo_t *ct, NArtBpath *bpath, NR::Matrix trans, NR::Rect area, bool optimize_stroke, double stroke_width)
 {
-    NR::Point lastX(0,0);
+    NR::Point next(0,0), last(0,0);
+    NR::Point shift = area.min();
+    NR::Rect view = area;
+    view.growBy (stroke_width);
+    NR::Rect swept;
     bool  closed = false;
     for (int i = 0; bpath[i].code != NR_END; i++) {
         switch (bpath[i].code) {
@@ -56,19 +60,30 @@ feed_curve_to_cairo (cairo_t *ct, NArtBpath *bpath, NR::Matrix trans, NR::Point
             case NR_MOVETO:
                 if (closed) cairo_close_path(ct);
                 closed = (bpath[i].code == NR_MOVETO);
-                lastX[NR::X] = bpath[i].x3;
-                lastX[NR::Y] = bpath[i].y3;
-                lastX *= trans;
-                lastX -= shift;
-                cairo_move_to(ct, lastX[NR::X], lastX[NR::Y]);
+                next[NR::X] = bpath[i].x3;
+                next[NR::Y] = bpath[i].y3;
+                next *= trans;
+                last = next;
+                next -= shift;
+                cairo_move_to(ct, next[NR::X], next[NR::Y]);
                 break;
 
             case NR_LINETO:
-                lastX[NR::X] = bpath[i].x3;
-                lastX[NR::Y] = bpath[i].y3;
-                lastX *= trans;
-                lastX -= shift;
-                cairo_line_to(ct, lastX[NR::X], lastX[NR::Y]);
+                next[NR::X] = bpath[i].x3;
+                next[NR::Y] = bpath[i].y3;
+                next *= trans;
+                if (optimize_stroke) {
+                    swept = NR::Rect(last, next);
+                    //std::cout << "swept: " << swept;
+                    //std::cout << "view: " << view;
+                    //std::cout << "intersects? " << (swept.intersects(view)? "YES" : "NO") << "\n";
+                }
+                last = next;
+                next -= shift;
+                if (!optimize_stroke || swept.intersects(view)) 
+                    cairo_line_to(ct, next[NR::X], next[NR::Y]);
+                else 
+                    cairo_move_to(ct, next[NR::X], next[NR::Y]);
                 break;
 
             case NR_CURVETO: {
@@ -82,10 +97,20 @@ feed_curve_to_cairo (cairo_t *ct, NArtBpath *bpath, NR::Matrix trans, NR::Point
                 tm1 *= trans;
                 tm2 *= trans;
                 tm3 *= trans;
+                if (optimize_stroke) {
+                    swept = NR::Rect(last, last);
+                    swept.expandTo(tm1);
+                    swept.expandTo(tm2);
+                    swept.expandTo(tm3);
+                }
+                last = tm3;
                 tm1 -= shift;
                 tm2 -= shift;
                 tm3 -= shift;
-                cairo_curve_to (ct, tm1[NR::X], tm1[NR::Y], tm2[NR::X], tm2[NR::Y], tm3[NR::X], tm3[NR::Y]);
+                if (!optimize_stroke || swept.intersects(view)) 
+                    cairo_curve_to (ct, tm1[NR::X], tm1[NR::Y], tm2[NR::X], tm2[NR::Y], tm3[NR::X], tm3[NR::Y]);
+                else
+                    cairo_move_to(ct, tm3[NR::X], tm3[NR::Y]);
                 break;
             }
 
index 0692a0d06bc69fae4831c783f6dc505bb2100176..4b9f50e76ebd753c36c9926afaedddeafa3dfc74 100644 (file)
@@ -11,7 +11,7 @@
  */
 
 cairo_t *nr_create_cairo_context (NRRectL *area, NRPixBlock *pb);
-void feed_curve_to_cairo (cairo_t *ct, NArtBpath *bpath, NR::Matrix trans, NR::Point shift);
+void feed_curve_to_cairo (cairo_t *ct, NArtBpath *bpath, NR::Matrix trans, NR::Rect area, bool optimize_stroke, double stroke_width);
 
 #endif
 /*
index c8e51a19c49d27ca4f63e939c63afdded18c82a4..b6f0e5d601fdbf9f9395aab4053c57b2c617d8b8 100644 (file)
@@ -458,7 +458,7 @@ nr_arena_glyphs_group_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPi
 
             cairo_new_path(ct);
             NR::Matrix g_t(g->g_transform);
-            feed_curve_to_cairo (ct, bpath, g_t * group->ctm, NR::Point(pb->area.x0, pb->area.y0));
+            feed_curve_to_cairo (ct, bpath, g_t * group->ctm, NR::Rect(&pb->area), false, 0);
             cairo_fill(ct);
             pb->empty = FALSE;
         }
index 6aa259ba64d2fd718731e7923ac8c2ff6f6e65d4..259c6fb4528d1b48820238567971c81401362d1f 100644 (file)
@@ -728,7 +728,7 @@ nr_arena_shape_add_bboxes(NRArenaShape* shape, NRRect &bbox)
 
 // cairo outline rendering:
 static unsigned int
-cairo_arena_shape_render_outline(cairo_t *ct, NRArenaItem *item, NR::Point shift)
+cairo_arena_shape_render_outline(cairo_t *ct, NRArenaItem *item, NR::Rect area)
 {
     NRArenaShape *shape = NR_ARENA_SHAPE(item);
 
@@ -744,7 +744,7 @@ cairo_arena_shape_render_outline(cairo_t *ct, NRArenaItem *item, NR::Point shift
     cairo_set_tolerance(ct, 1.25); // low quality, but good enough for outline mode
     cairo_new_path(ct);
 
-    feed_curve_to_cairo (ct, SP_CURVE_BPATH(shape->curve), NR::Matrix(shape->ctm), shift);
+    feed_curve_to_cairo (ct, SP_CURVE_BPATH(shape->curve), NR::Matrix(shape->ctm), area, true, 0);
 
     cairo_stroke(ct);
 
@@ -827,7 +827,7 @@ cairo_arena_shape_render_stroke(NRArenaItem *item, NRRectL *area, NRPixBlock *pb
     cairo_set_tolerance(ct, 0.1);
     cairo_new_path(ct);
 
-    feed_curve_to_cairo (ct, SP_CURVE_BPATH(shape->curve), NR::Matrix(shape->ctm), NR::Point(area->x0, area->y0));
+    feed_curve_to_cairo (ct, SP_CURVE_BPATH(shape->curve), NR::Matrix(shape->ctm), NR::Rect(area), true, style_width);
 
     cairo_stroke(ct);
 
@@ -856,7 +856,7 @@ nr_arena_shape_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock
     if (outline) { // cairo outline rendering
 
         pb->empty = FALSE;
-        unsigned int ret = cairo_arena_shape_render_outline (ct, item, NR::Point(pb->area.x0, pb->area.y0));
+        unsigned int ret = cairo_arena_shape_render_outline (ct, item, NR::Rect(&pb->area));
         if (ret & NR_ARENA_ITEM_STATE_INVALID) return ret;
 
     } else {
@@ -1004,7 +1004,7 @@ cairo_arena_shape_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb)
 
         cairo_new_path(ct);
 
-        feed_curve_to_cairo (ct, SP_CURVE_BPATH(shape->curve), NR::Matrix(shape->ctm), NR::Point(area->x0, area->y0));
+        feed_curve_to_cairo (ct, SP_CURVE_BPATH(shape->curve), NR::Matrix(shape->ctm), NR::Rect(area), false, 0);
 
         cairo_fill(ct);
 
@@ -1091,10 +1091,11 @@ nr_arena_shape_pick(NRArenaItem *item, NR::Point p, double delta, unsigned int /
     bp.path = SP_CURVE_BPATH(shape->curve);
     double dist = NR_HUGE;
     int wind = 0;
-    nr_path_matrix_point_bbox_wind_distance(&bp, shape->ctm, p, NULL, &wind, &dist, NR_EPSILON);
+    bool needfill = (shape->_fill.paint.type() != NRArenaShape::Paint::NONE && !outline);
+    nr_path_matrix_point_bbox_wind_distance(&bp, shape->ctm, p, NULL, needfill? &wind : NULL, &dist, 0.5);
 
     // pick fill
-    if (shape->_fill.paint.type() != NRArenaShape::Paint::NONE && !outline) {
+    if (needfill) {
         if (!shape->style->fill_rule.computed) {
             if (wind != 0) return item;
         } else {