X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fdisplay%2Fnr-arena-shape.cpp;h=6a252e5f57c085e544a883e0a5cfff9ebf1e6893;hb=90a3966dd44e306d23febc15ebd65cde07d7a4dd;hp=146d1a5ca87f3072959234c75f78f7e69fc56123;hpb=b5918eee4f0043a8fa03d11e3cfe62eb107feabf;p=inkscape.git diff --git a/src/display/nr-arena-shape.cpp b/src/display/nr-arena-shape.cpp index 146d1a5ca..6a252e5f5 100644 --- a/src/display/nr-arena-shape.cpp +++ b/src/display/nr-arena-shape.cpp @@ -12,20 +12,19 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ - - +#include <2geom/svg-path.h> +#include <2geom/svg-path-parser.h> #include #include #include #include "display/curve.h" -#include -#include #include #include #include #include #include #include <2geom/pathvector.h> +#include <2geom/curves.h> #include #include #include @@ -33,12 +32,17 @@ #include "prefs-utils.h" #include "inkscape-cairo.h" #include "helper/geom.h" +#include "helper/geom-curves.h" #include "sp-filter.h" #include "sp-filter-reference.h" #include "display/nr-filter.h" - +#include #include +#include +#include "svg/svg.h" +#include + //int showRuns=0; void nr_pixblock_render_shape_mask_or(NRPixBlock &m,Shape* theS); @@ -54,7 +58,7 @@ static void nr_arena_shape_set_child_position(NRArenaItem *item, NRArenaItem *ch static guint nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, guint reset); static unsigned int nr_arena_shape_render(cairo_t *ct, NRArenaItem *item, NRRectL *area, NRPixBlock *pb, unsigned int flags); static guint nr_arena_shape_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb); -static NRArenaItem *nr_arena_shape_pick(NRArenaItem *item, NR::Point p, double delta, unsigned int sticky); +static NRArenaItem *nr_arena_shape_pick(NRArenaItem *item, Geom::Point p, double delta, unsigned int sticky); static NRArenaItemClass *shape_parent_class; @@ -109,7 +113,7 @@ nr_arena_shape_init(NRArenaShape *shape) shape->paintbox.x0 = shape->paintbox.y0 = 0.0F; shape->paintbox.x1 = shape->paintbox.y1 = 256.0F; - shape->ctm.set_identity(); + shape->ctm.setIdentity(); shape->fill_painter = NULL; shape->stroke_painter = NULL; shape->cached_fill = NULL; @@ -123,8 +127,8 @@ nr_arena_shape_init(NRArenaShape *shape) shape->approx_bbox.x0 = shape->approx_bbox.y0 = 0; shape->approx_bbox.x1 = shape->approx_bbox.y1 = 0; - shape->cached_fctm.set_identity(); - shape->cached_sctm.set_identity(); + shape->cached_fctm.setIdentity(); + shape->cached_sctm.setIdentity(); shape->markers = NULL; @@ -251,7 +255,7 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g shape->ctm = gc->transform; if (state & NR_ARENA_ITEM_STATE_BBOX) { if (shape->curve) { - boundingbox = bounds_fast_transformed(shape->curve->get_pathvector(), to_2geom(gc->transform)); + boundingbox = bounds_exact_transformed(shape->curve->get_pathvector(), gc->transform); item->bbox.x0 = (gint32)(boundingbox[0][0] - 1.0F); item->bbox.y0 = (gint32)(boundingbox[1][0] - 1.0F); item->bbox.x1 = (gint32)(boundingbox[0][1] + 1.9999F); @@ -274,11 +278,11 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g bool outline = (NR_ARENA_ITEM(shape)->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); if (shape->curve) { - boundingbox = bounds_fast_transformed(shape->curve->get_pathvector(), to_2geom(gc->transform)); + boundingbox = bounds_exact_transformed(shape->curve->get_pathvector(), gc->transform); if (shape->_stroke.paint.type() != NRArenaShape::Paint::NONE || outline) { float width, scale; - scale = NR::expansion(gc->transform); + scale = gc->transform.descrim(); width = MAX(0.125, shape->_stroke.width * scale); if ( fabs(shape->_stroke.width * scale) > 0.01 ) { // sinon c'est 0=oon veut pas de bord boundingbox.expandBy(width); @@ -296,10 +300,10 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g shape->approx_bbox.y0 = (gint32)(boundingbox[1][0] - 1.0F); shape->approx_bbox.x1 = (gint32)(boundingbox[0][1] + 1.9999F); shape->approx_bbox.y1 = (gint32)(boundingbox[1][1] + 1.9999F); - if ( area && nr_rect_l_test_intersect(area, &shape->approx_bbox) ) shape->delayed_shp=false; + if ( area && nr_rect_l_test_intersect_ptr(area, &shape->approx_bbox) ) shape->delayed_shp=false; /* Release state data */ - if (TRUE || !NR::transform_equalp(gc->transform, shape->ctm, NR_EPSILON)) { + if (TRUE || !Geom::transform_equalp(gc->transform, shape->ctm, NR_EPSILON)) { /* Concept test */ if (shape->fill_shp) { delete shape->fill_shp; @@ -389,8 +393,8 @@ nr_arena_shape_update(NRArenaItem *item, NRRectL *area, NRGC *gc, guint state, g return NR_ARENA_ITEM_STATE_ALL; } -int matrix_is_isometry(NR::Matrix p) { - NR::Matrix tp; +int matrix_is_isometry(Geom::Matrix p) { + Geom::Matrix tp; // transposition tp[0]=p[0]; tp[1]=p[2]; @@ -398,9 +402,9 @@ int matrix_is_isometry(NR::Matrix p) { tp[3]=p[3]; for (int i = 4; i < 6; i++) // shut valgrind up :) tp[i] = p[i] = 0; - NR::Matrix isom = tp*p; // A^T * A = adjunct? + Geom::Matrix isom = tp*p; // A^T * A = adjunct? // Is the adjunct nearly an identity function? - if (isom.is_translation(0.01)) { + if (isom.isTranslation(0.01)) { // the transformation is an isometry -> no need to recompute // the uncrossed polygon if ( p.det() < 0 ) @@ -415,14 +419,34 @@ static bool is_inner_area(NRRectL const &outer, NRRectL const &inner) { return (outer.x0 <= inner.x0 && outer.y0 <= inner.y0 && outer.x1 >= inner.x1 && outer.y1 >= inner.y1); } +/* returns true if the pathvector has a region that needs fill. + * is for optimizing purposes, so should be fast and can falsely return true. + * CANNOT falsely return false. */ +static bool has_inner_area(Geom::PathVector const & pv) { + // return false for the cases where there is surely no region to be filled + if (pv.empty()) + return false; + + if ( (pv.size() == 1) && (pv.front().size() <= 1) ) { + // vector has only one path with only one segment, see if that's a non-curve segment: that would mean no internal region + if ( is_straight_curve(pv.front().front()) ) + { + return false; + } + } + + return true; //too costly to see if it has region to be filled, so return true. +} + /** force_shape is used for clipping paths, when we need the shape for clipping even if it's not filled */ void nr_arena_shape_update_fill(NRArenaShape *shape, NRGC *gc, NRRectL *area, bool force_shape) { if ((shape->_fill.paint.type() != NRArenaShape::Paint::NONE || force_shape) && - ((shape->curve->get_length() > 2) || (SP_CURVE_BPATH(shape->curve)[1].code == NR_CURVETO)) ) { +// ((shape->curve->get_length() > 2) || (SP_CURVE_BPATH(shape->curve)[1].code == NR_CURVETO)) ) { // <-- this used to be the old code, i think it has to determine that the path has a sort of 'internal region' where fill would occur + has_inner_area(shape->curve->get_pathvector()) ) { if (TRUE || !shape->fill_shp) { - NR::Matrix cached_to_new = NR::identity(); + Geom::Matrix cached_to_new = Geom::identity(); int isometry = 0; if ( shape->cached_fill ) { if (shape->cached_fctm == gc->transform) { @@ -441,8 +465,8 @@ nr_arena_shape_update_fill(NRArenaShape *shape, NRGC *gc, NRRectL *area, bool fo Path* thePath=new Path; Shape* theShape=new Shape; { - NR::Matrix tempMat(gc->transform); - thePath->LoadArtBPath(SP_CURVE_BPATH(shape->curve),tempMat,true); + Geom::Matrix tempMat(gc->transform); + thePath->LoadPathVector(shape->curve->get_pathvector(), tempMat, true); } if (is_inner_area(*area, NR_ARENA_ITEM(shape)->bbox)) { @@ -484,7 +508,7 @@ nr_arena_shape_update_fill(NRArenaShape *shape, NRGC *gc, NRRectL *area, bool fo shape->fill_shp->Reset(shape->cached_fill->numberOfPoints(), shape->cached_fill->numberOfEdges()); for (int i = 0; i < shape->cached_fill->numberOfPoints(); i++) - shape->fill_shp->AddPoint(shape->cached_fill->getPoint(i).x * cached_to_new); + shape->fill_shp->AddPoint(to_2geom(shape->cached_fill->getPoint(i).x) * cached_to_new); if ( isometry == 1 ) { for (int i = 0; i < shape->cached_fill->numberOfEdges(); i++) shape->fill_shp->AddEdge(shape->cached_fill->getEdge(i).st, @@ -508,7 +532,7 @@ nr_arena_shape_update_stroke(NRArenaShape *shape,NRGC* gc, NRRectL *area) { SPStyle* style = shape->style; - float const scale = NR::expansion(gc->transform); + float const scale = gc->transform.descrim(); bool outline = (NR_ARENA_ITEM(shape)->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); @@ -532,7 +556,7 @@ nr_arena_shape_update_stroke(NRArenaShape *shape,NRGC* gc, NRRectL *area) width = style_width; } - NR::Matrix cached_to_new = NR::identity(); + Geom::Matrix cached_to_new = Geom::identity(); int isometry = 0; if ( shape->cached_stroke ) { @@ -556,8 +580,8 @@ nr_arena_shape_update_stroke(NRArenaShape *shape,NRGC* gc, NRRectL *area) Path* thePath = new Path; Shape* theShape = new Shape; { - NR::Matrix tempMat(gc->transform); - thePath->LoadArtBPath(SP_CURVE_BPATH(shape->curve), tempMat, true); + Geom::Matrix tempMat( gc->transform ); + thePath->LoadPathVector(shape->curve->get_pathvector(), tempMat, true); } // add some padding to the rendering area, so clipped path does not go into a render area @@ -640,7 +664,7 @@ nr_arena_shape_update_stroke(NRArenaShape *shape,NRGC* gc, NRRectL *area) shape->stroke_shp=new Shape; shape->stroke_shp->Reset(shape->cached_stroke->numberOfPoints(), shape->cached_stroke->numberOfEdges()); for (int i = 0; i < shape->cached_stroke->numberOfPoints(); i++) - shape->stroke_shp->AddPoint(shape->cached_stroke->getPoint(i).x * cached_to_new); + shape->stroke_shp->AddPoint(to_2geom(shape->cached_stroke->getPoint(i).x) * cached_to_new); if ( isometry == 1 ) { for (int i = 0; i < shape->cached_stroke->numberOfEdges(); i++) shape->stroke_shp->AddEdge(shape->cached_stroke->getEdge(i).st, @@ -692,7 +716,7 @@ nr_arena_shape_add_bboxes(NRArenaShape* shape, Geom::Rect &bbox) // cairo outline rendering: static unsigned int -cairo_arena_shape_render_outline(cairo_t *ct, NRArenaItem *item, NR::Maybe area) +cairo_arena_shape_render_outline(cairo_t *ct, NRArenaItem *item, boost::optional area) { NRArenaShape *shape = NR_ARENA_SHAPE(item); @@ -708,7 +732,7 @@ cairo_arena_shape_render_outline(cairo_t *ct, NRArenaItem *item, NR::Maybecurve->get_pathvector(), to_2geom(shape->ctm), area, true, 0); + feed_pathvector_to_cairo (ct, shape->curve->get_pathvector(), shape->ctm, area, true, 0); cairo_stroke(ct); @@ -724,7 +748,7 @@ cairo_arena_shape_render_stroke(NRArenaItem *item, NRRectL *area, NRPixBlock *pb NRArenaShape *shape = NR_ARENA_SHAPE(item); SPStyle const *style = shape->style; - float const scale = NR::expansion(shape->ctm); + float const scale = shape->ctm.descrim(); if (fabs(shape->_stroke.width * scale) < 0.01) return; @@ -789,7 +813,7 @@ cairo_arena_shape_render_stroke(NRArenaItem *item, NRRectL *area, NRPixBlock *pb cairo_set_tolerance(ct, 0.1); cairo_new_path(ct); - feed_pathvector_to_cairo (ct, shape->curve->get_pathvector(), to_2geom(shape->ctm), area->upgrade(), true, style_width); + feed_pathvector_to_cairo (ct, shape->curve->get_pathvector(), shape->ctm, to_2geom(area->upgrade()), true, style_width); cairo_stroke(ct); @@ -818,13 +842,13 @@ 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, (&pb->area)->upgrade()); + unsigned int ret = cairo_arena_shape_render_outline (ct, item, to_2geom((&pb->area)->upgrade())); if (ret & NR_ARENA_ITEM_STATE_INVALID) return ret; } else { if ( shape->delayed_shp ) { - if ( nr_rect_l_test_intersect(area, &item->bbox) ) { + if ( nr_rect_l_test_intersect_ptr(area, &item->bbox) ) { NRGC tempGC(NULL); tempGC.transform=shape->ctm; shape->delayed_shp = false; @@ -964,7 +988,7 @@ cairo_arena_shape_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb) cairo_new_path(ct); - feed_pathvector_to_cairo (ct, shape->curve->get_pathvector(), to_2geom(shape->ctm), (area)->upgrade(), false, 0); + feed_pathvector_to_cairo (ct, shape->curve->get_pathvector(), shape->ctm, (area)->upgrade(), false, 0); cairo_fill(ct); @@ -989,7 +1013,7 @@ nr_arena_shape_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb) if (!shape->curve) return item->state; if ( shape->delayed_shp || shape->fill_shp == NULL) { // we need a fill shape no matter what - if ( nr_rect_l_test_intersect(area, &item->bbox) ) { + if ( nr_rect_l_test_intersect_ptr(area, &item->bbox) ) { NRGC tempGC(NULL); tempGC.transform=shape->ctm; shape->delayed_shp = false; @@ -1032,7 +1056,7 @@ nr_arena_shape_clip(NRArenaItem *item, NRRectL *area, NRPixBlock *pb) } static NRArenaItem * -nr_arena_shape_pick(NRArenaItem *item, NR::Point p, double delta, unsigned int /*sticky*/) +nr_arena_shape_pick(NRArenaItem *item, Geom::Point p, double delta, unsigned int /*sticky*/) { NRArenaShape *shape = NR_ARENA_SHAPE(item); @@ -1044,37 +1068,37 @@ nr_arena_shape_pick(NRArenaItem *item, NR::Point p, double delta, unsigned int / if (!shape->curve) return NULL; if (!shape->style) return NULL; - if (SP_SCALE24_TO_FLOAT(shape->style->opacity.value) == 0) // fully transparent, no pick + + bool outline = (NR_ARENA_ITEM(shape)->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); + + if (SP_SCALE24_TO_FLOAT(shape->style->opacity.value) == 0 && !outline) + // fully transparent, no pick unless outline mode return NULL; GTimeVal tstart, tfinish; g_get_current_time (&tstart); - bool outline = (NR_ARENA_ITEM(shape)->arena->rendermode == Inkscape::RENDERMODE_OUTLINE); - double width; if (outline) { width = 0.5; } else if (shape->_stroke.paint.type() != NRArenaShape::Paint::NONE && shape->_stroke.opacity > 1e-3) { - float const scale = NR::expansion(shape->ctm); + float const scale = shape->ctm.descrim(); width = MAX(0.125, shape->_stroke.width * scale) / 2; } else { width = 0; } - const_NRBPath bp; - bp.path = SP_CURVE_BPATH(shape->curve); double dist = NR_HUGE; int wind = 0; bool needfill = (shape->_fill.paint.type() != NRArenaShape::Paint::NONE && shape->_fill.opacity > 1e-3 && !outline); if (item->arena->canvasarena) { - NR::Rect viewbox = item->arena->canvasarena->item.canvas->getViewbox(); - viewbox.growBy (width); - nr_path_matrix_point_bbox_wind_distance(&bp, shape->ctm, p, NULL, needfill? &wind : NULL, &dist, 0.5, &viewbox); + Geom::Rect viewbox = item->arena->canvasarena->item.canvas->getViewbox(); + viewbox.expandBy (width); + pathv_matrix_point_bbox_wind_distance(shape->curve->get_pathvector(), shape->ctm, p, NULL, needfill? &wind : NULL, &dist, 0.5, &viewbox); } else { - nr_path_matrix_point_bbox_wind_distance(&bp, shape->ctm, p, NULL, needfill? &wind : NULL, &dist, 0.5, NULL); + pathv_matrix_point_bbox_wind_distance(shape->curve->get_pathvector(), shape->ctm, p, NULL, needfill? &wind : NULL, &dist, 0.5, NULL); } g_get_current_time (&tfinish); @@ -1335,12 +1359,12 @@ nr_arena_shape_set_paintbox(NRArenaShape *shape, NRRect const *pbox) nr_arena_item_request_update(shape, NR_ARENA_ITEM_STATE_ALL, FALSE); } -void NRArenaShape::setPaintBox(NR::Rect const &pbox) +void NRArenaShape::setPaintBox(Geom::Rect const &pbox) { - paintbox.x0 = pbox.min()[NR::X]; - paintbox.y0 = pbox.min()[NR::Y]; - paintbox.x1 = pbox.max()[NR::X]; - paintbox.y1 = pbox.max()[NR::Y]; + paintbox.x0 = pbox.min()[Geom::X]; + paintbox.y0 = pbox.min()[Geom::Y]; + paintbox.x1 = pbox.max()[Geom::X]; + paintbox.y1 = pbox.max()[Geom::Y]; nr_arena_item_request_update(this, NR_ARENA_ITEM_STATE_ALL, FALSE); }