X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fsp-pattern.cpp;h=90af65b97cb8f3c072509d3268c272497a71d72d;hb=325ab30ef9de67f89aed7e743d02f09c3a501c42;hp=beea89b02ced8f5c62ace242fde0f9d03ef8ab5f;hpb=6b15695578f07a3f72c4c9475c1a261a3021472a;p=inkscape.git diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp index beea89b02..90af65b97 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -12,11 +12,15 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "config.h" +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include +#include #include #include "libnr/nr-matrix-fns.h" -#include +#include <2geom/transforms.h> #include "macros.h" #include "svg/svg.h" #include "display/nr-arena.h" @@ -27,6 +31,9 @@ #include "sp-pattern.h" #include "xml/repr.h" +#include +#include + /* * Pattern */ @@ -37,19 +44,21 @@ struct SPPatPainter { SPPainter painter; SPPattern *pat; - NRMatrix ps2px; - NRMatrix px2ps; - NRMatrix pcs2px; + Geom::Matrix ps2px; + Geom::Matrix px2ps; + Geom::Matrix pcs2px; NRArena *arena; unsigned int dkey; NRArenaItem *root; bool use_cached_tile; - NRMatrix ca2pa; - NRMatrix pa2ca; + Geom::Matrix ca2pa; + Geom::Matrix pa2ca; NRRectL cached_bbox; NRPixBlock cached_tile; + + std::map *_release_connections; }; static void sp_pattern_class_init (SPPatternClass *klass); @@ -65,7 +74,7 @@ static void sp_pattern_modified (SPObject *object, unsigned int flags); static void pattern_ref_changed(SPObject *old_ref, SPObject *ref, SPPattern *pat); static void pattern_ref_modified (SPObject *ref, guint flags, SPPattern *pattern); -static SPPainter *sp_pattern_painter_new (SPPaintServer *ps, NR::Matrix const &full_transform, NR::Matrix const &parent_transform, const NRRect *bbox); +static SPPainter *sp_pattern_painter_new (SPPaintServer *ps, Geom::Matrix const &full_transform, Geom::Matrix const &parent_transform, const NRRect *bbox); static void sp_pattern_painter_free (SPPaintServer *ps, SPPainter *painter); static SPPaintServerClass * pattern_parent_class; @@ -137,6 +146,8 @@ sp_pattern_init (SPPattern *pat) pat->height.unset(); pat->viewBox_set = FALSE; + + new (&pat->modified_connection) sigc::connection(); } static void @@ -172,13 +183,14 @@ sp_pattern_release (SPObject *object) } if (pat->ref) { - if (pat->ref->getObject()) - sp_signal_disconnect_by_data(pat->ref->getObject(), pat); + pat->modified_connection.disconnect(); pat->ref->detach(); delete pat->ref; pat->ref = NULL; } + pat->modified_connection.~connection(); + if (((SPObjectClass *) pattern_parent_class)->release) ((SPObjectClass *) pattern_parent_class)->release (object); } @@ -216,7 +228,7 @@ sp_pattern_set (SPObject *object, unsigned int key, const gchar *value) object->requestModified(SP_OBJECT_MODIFIED_FLAG); break; case SP_ATTR_PATTERNTRANSFORM: { - NR::Matrix t; + Geom::Matrix t; if (value && sp_svg_transform_read (value, &t)) { pat->patternTransform = t; pat->patternTransform_set = TRUE; @@ -332,7 +344,7 @@ sp_pattern_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape:: } /* TODO: do we need a ::remove_child handler? */ - + /* fixme: We need ::order_changed handler too (Lauris) */ GSList * @@ -403,10 +415,10 @@ static void pattern_ref_changed(SPObject *old_ref, SPObject *ref, SPPattern *pat) { if (old_ref) { - sp_signal_disconnect_by_data(old_ref, pat); + pat->modified_connection.disconnect(); } if (SP_IS_PATTERN (ref)) { - g_signal_connect(G_OBJECT (ref), "modified", G_CALLBACK (pattern_ref_modified), pat); + pat->modified_connection = ref->connectModified(sigc::bind<2>(sigc::ptr_fun(&pattern_ref_modified), pat)); } pattern_ref_modified (ref, 0, pat); @@ -416,7 +428,7 @@ pattern_ref_changed(SPObject *old_ref, SPObject *ref, SPPattern *pat) Gets called when the referenced is changed */ static void -pattern_ref_modified (SPObject *ref, guint flags, SPPattern *pattern) +pattern_ref_modified (SPObject */*ref*/, guint /*flags*/, SPPattern *pattern) { if (SP_IS_OBJECT (pattern)) SP_OBJECT (pattern)->requestModified(SP_OBJECT_MODIFIED_FLAG); @@ -432,9 +444,10 @@ SPPattern * pattern_chain (SPPattern *pattern) { SPDocument *document = SP_OBJECT_DOCUMENT (pattern); + Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document); Inkscape::XML::Node *defsrepr = SP_OBJECT_REPR (SP_DOCUMENT_DEFS (document)); - Inkscape::XML::Node *repr = sp_repr_new ("svg:pattern"); + Inkscape::XML::Node *repr = xml_doc->createElement("svg:pattern"); repr->setAttribute("inkscape:collect", "always"); gchar *parent_ref = g_strconcat ("#", SP_OBJECT_REPR(pattern)->attribute("id"), NULL); repr->setAttribute("xlink:href", parent_ref); @@ -458,12 +471,12 @@ sp_pattern_clone_if_necessary (SPItem *item, SPPattern *pattern, const gchar *pr SPCSSAttr *css = sp_repr_css_attr_new (); sp_repr_css_set_property (css, property, href); sp_repr_css_change_recursive (SP_OBJECT_REPR (item), css, "style"); - } + } return pattern; } void -sp_pattern_transform_multiply (SPPattern *pattern, NR::Matrix postmul, bool set) +sp_pattern_transform_multiply (SPPattern *pattern, Geom::Matrix postmul, bool set) { // this formula is for a different interpretation of pattern transforms as described in (*) in sp-pattern.cpp // for it to work, we also need sp_object_read_attr (SP_OBJECT (item), "transform"); @@ -477,31 +490,25 @@ sp_pattern_transform_multiply (SPPattern *pattern, NR::Matrix postmul, bool set) } pattern->patternTransform_set = TRUE; - gchar c[256]; - if (sp_svg_transform_write(c, 256, pattern->patternTransform)) { - SP_OBJECT_REPR(pattern)->setAttribute("patternTransform", c); - } else { - SP_OBJECT_REPR(pattern)->setAttribute("patternTransform", NULL); - } + gchar *c=sp_svg_transform_write(pattern->patternTransform); + SP_OBJECT_REPR(pattern)->setAttribute("patternTransform", c); + g_free(c); } const gchar * -pattern_tile (GSList *reprs, NR::Rect bounds, SPDocument *document, NR::Matrix transform, NR::Matrix move) +pattern_tile (GSList *reprs, Geom::Rect bounds, SPDocument *document, Geom::Matrix transform, Geom::Matrix move) { + Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document); Inkscape::XML::Node *defsrepr = SP_OBJECT_REPR (SP_DOCUMENT_DEFS (document)); - Inkscape::XML::Node *repr = sp_repr_new ("svg:pattern"); + Inkscape::XML::Node *repr = xml_doc->createElement("svg:pattern"); repr->setAttribute("patternUnits", "userSpaceOnUse"); - sp_repr_set_svg_double(repr, "width", bounds.extent(NR::X)); - sp_repr_set_svg_double(repr, "height", bounds.extent(NR::Y)); - - gchar t[256]; - if (sp_svg_transform_write(t, 256, transform)) { - repr->setAttribute("patternTransform", t); - } else { - repr->setAttribute("patternTransform", NULL); - } + sp_repr_set_svg_double(repr, "width", bounds.dimensions()[Geom::X]); + sp_repr_set_svg_double(repr, "height", bounds.dimensions()[Geom::Y]); + gchar *t=sp_svg_transform_write(transform); + repr->setAttribute("patternTransform", t); + g_free(t); defsrepr->appendChild(repr); const gchar *pat_id = repr->attribute("id"); @@ -511,12 +518,12 @@ pattern_tile (GSList *reprs, NR::Rect bounds, SPDocument *document, NR::Matrix t Inkscape::XML::Node *node = (Inkscape::XML::Node *)(i->data); SPItem *copy = SP_ITEM(pat_object->appendChildRepr(node)); - NR::Matrix dup_transform; - if (!sp_svg_transform_read (node->attribute("transform"), &dup_transform)) - dup_transform = NR::identity(); + Geom::Matrix dup_transform; + if (!sp_svg_transform_read (node->attribute("transform"), &dup_transform)) + dup_transform = Geom::identity(); dup_transform *= move; - sp_item_write_transform(copy, SP_OBJECT_REPR(copy), dup_transform); + sp_item_write_transform(copy, SP_OBJECT_REPR(copy), dup_transform, NULL, false); } Inkscape::GC::release(repr); @@ -524,7 +531,7 @@ pattern_tile (GSList *reprs, NR::Rect bounds, SPDocument *document, NR::Matrix t } SPPattern * -pattern_getroot (SPPattern *pat) +pattern_getroot (SPPattern *pat) { for (SPPattern *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { if (sp_object_first_child(SP_OBJECT(pat_i))) { // find the first one with children @@ -537,6 +544,7 @@ pattern_getroot (SPPattern *pat) // Access functions that look up fields up the chain of referenced patterns and return the first one which is set +// FIXME: all of them must use chase_hrefs the same as in SPGradient, to avoid lockup on circular refs guint pattern_patternUnits (SPPattern *pat) { @@ -556,7 +564,7 @@ guint pattern_patternContentUnits (SPPattern *pat) return pat->patternContentUnits; } -NR::Matrix const &pattern_patternTransform(SPPattern const *pat) +Geom::Matrix const &pattern_patternTransform(SPPattern const *pat) { for (SPPattern const *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { if (pat_i->patternTransform_set) @@ -626,12 +634,25 @@ bool pattern_hasItemChildren (SPPattern *pat) static void sp_pat_fill (SPPainter *painter, NRPixBlock *pb); +// item in this pattern is about to be deleted, hide it on our arena and disconnect +void +sp_pattern_painter_release (SPObject *obj, SPPatPainter *painter) +{ + std::map::iterator iter = painter->_release_connections->find(obj); + if (iter != painter->_release_connections->end()) { + iter->second.disconnect(); + painter->_release_connections->erase(obj); + } + + sp_item_invoke_hide(SP_ITEM(obj), painter->dkey); +} + /** Creates a painter (i.e. the thing that does actual filling at the given zoom). See (*) below for why the parent_transform may be necessary. */ static SPPainter * -sp_pattern_painter_new (SPPaintServer *ps, NR::Matrix const &full_transform, NR::Matrix const &parent_transform, const NRRect *bbox) +sp_pattern_painter_new (SPPaintServer *ps, Geom::Matrix const &full_transform, Geom::Matrix const &/*parent_transform*/, const NRRect *bbox) { SPPattern *pat = SP_PATTERN (ps); SPPatPainter *pp = g_new (SPPatPainter, 1); @@ -643,16 +664,13 @@ sp_pattern_painter_new (SPPaintServer *ps, NR::Matrix const &full_transform, NR: if (pattern_patternUnits (pat) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) { /* BBox to user coordinate system */ - NR::Matrix bbox2user (bbox->x1 - bbox->x0, 0.0, 0.0, bbox->y1 - bbox->y0, bbox->x0, bbox->y0); + Geom::Matrix bbox2user (bbox->x1 - bbox->x0, 0.0, 0.0, bbox->y1 - bbox->y0, bbox->x0, bbox->y0); // the final patternTransform, taking into account bbox - NR::Matrix const ps2user(pattern_patternTransform(pat) * bbox2user); + Geom::Matrix const ps2user(pattern_patternTransform(pat) * bbox2user); // see (*) comment below - NR::Matrix ps2px = ps2user * full_transform; - - ps2px.copyto (&pp->ps2px); - + pp->ps2px = ps2user * full_transform; } else { /* Problem: What to do, if we have mixed lengths and percentages? */ /* Currently we do ignore percentages at all, but that is not good (lauris) */ @@ -669,48 +687,40 @@ sp_pattern_painter_new (SPPaintServer *ps, NR::Matrix const &full_transform, NR: // So here I comply with the majority opinion, but leave my interpretation commented out below. // (To get item_transform, I subtract parent from full.) - //NR::Matrix ps2px = (full_transform / parent_transform) * pattern_patternTransform(pat) * parent_transform; - NR::Matrix ps2px = pattern_patternTransform(pat) * full_transform; - - ps2px.copyto (&pp->ps2px); + //pp->ps2px = (full_transform / parent_transform) * pattern_patternTransform(pat) * parent_transform; + pp->ps2px = pattern_patternTransform(pat) * full_transform; } - nr_matrix_invert (&pp->px2ps, &pp->ps2px); + pp->px2ps = pp->ps2px.inverse(); if (pat->viewBox_set) { - gdouble tmp_x = (pattern_viewBox(pat)->x1 - pattern_viewBox(pat)->x0) / pattern_width (pat); - gdouble tmp_y = (pattern_viewBox(pat)->y1 - pattern_viewBox(pat)->y0) / pattern_height (pat); + gdouble tmp_x = pattern_width (pat) / (pattern_viewBox(pat)->x1 - pattern_viewBox(pat)->x0); + gdouble tmp_y = pattern_height (pat) / (pattern_viewBox(pat)->y1 - pattern_viewBox(pat)->y0); // FIXME: preserveAspectRatio must be taken into account here too! - NR::Matrix vb2ps (tmp_x, 0.0, 0.0, tmp_y, pattern_x(pat) - pattern_viewBox(pat)->x0, pattern_y(pat) - pattern_viewBox(pat)->y0); + Geom::Matrix vb2ps (tmp_x, 0.0, 0.0, tmp_y, pattern_x(pat) - pattern_viewBox(pat)->x0 * tmp_x, pattern_y(pat) - pattern_viewBox(pat)->y0 * tmp_y); - NR::Matrix vb2us = vb2ps * pattern_patternTransform(pat); + Geom::Matrix vb2us = vb2ps * pattern_patternTransform(pat); // see (*) - NR::Matrix pcs2px = vb2us * full_transform; - - pcs2px.copyto (&pp->pcs2px); + pp->pcs2px = vb2us * full_transform; } else { - NR::Matrix pcs2px; - /* No viewbox, have to parse units */ if (pattern_patternContentUnits (pat) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) { /* BBox to user coordinate system */ - NR::Matrix bbox2user (bbox->x1 - bbox->x0, 0.0, 0.0, bbox->y1 - bbox->y0, bbox->x0, bbox->y0); + Geom::Matrix bbox2user (bbox->x1 - bbox->x0, 0.0, 0.0, bbox->y1 - bbox->y0, bbox->x0, bbox->y0); - NR::Matrix pcs2user = pattern_patternTransform(pat) * bbox2user; + Geom::Matrix pcs2user = pattern_patternTransform(pat) * bbox2user; // see (*) - pcs2px = pcs2user * full_transform; + pp->pcs2px = pcs2user * full_transform; } else { // see (*) //pcs2px = (full_transform / parent_transform) * pattern_patternTransform(pat) * parent_transform; - pcs2px = pattern_patternTransform(pat) * full_transform; + pp->pcs2px = pattern_patternTransform(pat) * full_transform; } - pcs2px = NR::translate (pattern_x (pat), pattern_y (pat)) * pcs2px; - - pcs2px.copyto (&pp->pcs2px); + pp->pcs2px = Geom::Translate (pattern_x (pat), pattern_y (pat)) * pp->pcs2px; } /* Create arena */ @@ -722,14 +732,19 @@ sp_pattern_painter_new (SPPaintServer *ps, NR::Matrix const &full_transform, NR: pp->root = NRArenaGroup::create(pp->arena); /* Show items */ + pp->_release_connections = new std::map; for (SPPattern *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { if (pat_i && SP_IS_OBJECT (pat_i) && pattern_hasItemChildren(pat_i)) { // find the first one with item children for (SPObject *child = sp_object_first_child(SP_OBJECT(pat_i)) ; child != NULL; child = SP_OBJECT_NEXT(child) ) { if (SP_IS_ITEM (child)) { + // for each item in pattern, NRArenaItem *cai; + // show it on our arena, cai = sp_item_invoke_show (SP_ITEM (child), pp->arena, pp->dkey, SP_ITEM_REFERENCE_FLAGS); + // add to the group, nr_arena_item_append_child (pp->root, cai); - nr_arena_item_unref (cai); + // and connect to the release signal in case the item gets deleted + pp->_release_connections->insert(std::make_pair(child, child->connectRelease(sigc::bind<1>(sigc::ptr_fun(&sp_pattern_painter_release), pp)))); } } break; // do not go further up the chain if children are found @@ -742,7 +757,9 @@ sp_pattern_painter_new (SPPaintServer *ps, NR::Matrix const &full_transform, NR: one_tile.y0=pattern_y(pp->pat); one_tile.x1=one_tile.x0+pattern_width (pp->pat); one_tile.y1=one_tile.y0+pattern_height (pp->pat); - nr_rect_d_matrix_transform (&tr_tile, &one_tile, &pp->ps2px); + // TODO: remove ps2px_nr after converting to 2geom + NR::Matrix ps2px_nr = from_2geom(pp->ps2px); + nr_rect_d_matrix_transform (&tr_tile, &one_tile, &ps2px_nr); int tr_width=(int)ceil(1.3*(tr_tile.x1-tr_tile.x0)); int tr_height=(int)ceil(1.3*(tr_tile.y1-tr_tile.y0)); // if ( tr_width < 10000 && tr_height < 10000 && tr_width*tr_height < 1000000 ) { @@ -758,18 +775,18 @@ sp_pattern_painter_new (SPPaintServer *ps, NR::Matrix const &full_transform, NR: nr_pixblock_setup (&pp->cached_tile,NR_PIXBLOCK_MODE_R8G8B8A8N, pp->cached_bbox.x0, pp->cached_bbox.y0, pp->cached_bbox.x1, pp->cached_bbox.y1,TRUE); } - pp->pa2ca.c[0]=((double)tr_width)/(one_tile.x1-one_tile.x0); - pp->pa2ca.c[1]=0; - pp->pa2ca.c[2]=0; - pp->pa2ca.c[3]=((double)tr_height)/(one_tile.y1-one_tile.y0); - pp->pa2ca.c[4]=-one_tile.x0*pp->pa2ca.c[0]; - pp->pa2ca.c[5]=-one_tile.y0*pp->pa2ca.c[1]; - pp->ca2pa.c[0]=(one_tile.x1-one_tile.x0)/((double)tr_width); - pp->ca2pa.c[1]=0; - pp->ca2pa.c[2]=0; - pp->ca2pa.c[3]=(one_tile.y1-one_tile.y0)/((double)tr_height); - pp->ca2pa.c[4]=one_tile.x0; - pp->ca2pa.c[5]=one_tile.y0; + pp->pa2ca[0]=((double)tr_width)/(one_tile.x1-one_tile.x0); + pp->pa2ca[1]=0; + pp->pa2ca[2]=0; + pp->pa2ca[3]=((double)tr_height)/(one_tile.y1-one_tile.y0); + pp->pa2ca[4]=-one_tile.x0*pp->pa2ca[0]; + pp->pa2ca[5]=-one_tile.y0*pp->pa2ca[1]; + pp->ca2pa[0]=(one_tile.x1-one_tile.x0)/((double)tr_width); + pp->ca2pa[1]=0; + pp->ca2pa[2]=0; + pp->ca2pa[3]=(one_tile.y1-one_tile.y0)/((double)tr_height); + pp->ca2pa[4]=one_tile.x0; + pp->ca2pa[5]=one_tile.y0; // } else { // pp->use_cached_tile=false; // } @@ -783,7 +800,7 @@ sp_pattern_painter_new (SPPaintServer *ps, NR::Matrix const &full_transform, NR: } nr_arena_item_invoke_update (pp->root, NULL, &gc, NR_ARENA_ITEM_STATE_ALL, NR_ARENA_ITEM_STATE_ALL); if ( pp->use_cached_tile ) { - nr_arena_item_invoke_render (pp->root, &pp->cached_bbox, &pp->cached_tile, 0); + nr_arena_item_invoke_render (NULL, pp->root, &pp->cached_bbox, &pp->cached_tile, 0); } else { // nothing to do now } @@ -791,22 +808,25 @@ sp_pattern_painter_new (SPPaintServer *ps, NR::Matrix const &full_transform, NR: return (SPPainter *) pp; } + static void -sp_pattern_painter_free (SPPaintServer *ps, SPPainter *painter) +sp_pattern_painter_free (SPPaintServer */*ps*/, SPPainter *painter) { SPPatPainter *pp = (SPPatPainter *) painter; - SPPattern *pat = pp->pat; + // free our arena + if (pp->arena) { + ((NRObject *) pp->arena)->unreference(); + pp->arena = NULL; + } - for (SPPattern *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) { - if (pat_i && SP_IS_OBJECT (pat_i) && pattern_hasItemChildren(pat_i)) { // find the first one with item children - for (SPObject *child = sp_object_first_child(SP_OBJECT(pat_i)) ; child != NULL; child = SP_OBJECT_NEXT(child) ) { - if (SP_IS_ITEM (child)) { - sp_item_invoke_hide (SP_ITEM (child), pp->dkey); - } - } - break; // do not go further up the chain if children are found - } + // disconnect all connections + std::map::iterator iter; + for (iter = pp->_release_connections->begin() ; iter!=pp->_release_connections->end() ; iter++) { + iter->second.disconnect(); } + pp->_release_connections->clear(); + delete pp->_release_connections; + if ( pp->use_cached_tile ) nr_pixblock_release(&pp->cached_tile); g_free (pp); } @@ -884,15 +904,15 @@ sp_pat_fill (SPPainter *painter, NRPixBlock *pb) unsigned char* cpx=lpx; double px_x = pb->area.x0; - double ps_x=pp->px2ps.c[0]*px_x+pp->px2ps.c[2]*px_y+pp->px2ps.c[4]; - double ps_y=pp->px2ps.c[1]*px_x+pp->px2ps.c[3]*px_y+pp->px2ps.c[5]; + double ps_x=pp->px2ps[0]*px_x+pp->px2ps[2]*px_y+pp->px2ps[4]; + double ps_y=pp->px2ps[1]*px_x+pp->px2ps[3]*px_y+pp->px2ps[5]; for (int i=pb->area.x0;iarea.x1;i++) { while ( ps_x > pat_w ) ps_x-=pat_w; while ( ps_x < 0 ) ps_x+=pat_w; while ( ps_y > pat_h ) ps_y-=pat_h; while ( ps_y < 0 ) ps_y+=pat_h; - double ca_x=pp->pa2ca.c[0]*ps_x+pp->pa2ca.c[2]*ps_y+pp->pa2ca.c[4]; - double ca_y=pp->pa2ca.c[1]*ps_x+pp->pa2ca.c[3]*ps_y+pp->pa2ca.c[5]; + double ca_x=pp->pa2ca[0]*ps_x+pp->pa2ca[2]*ps_y+pp->pa2ca[4]; + double ca_y=pp->pa2ca[1]*ps_x+pp->pa2ca[3]*ps_y+pp->pa2ca[5]; unsigned char n_a,n_r,n_g,n_b; get_cached_tile_pixel(pp,ca_x,ca_y,n_r,n_g,n_b,n_a); cpx[0]=n_r; @@ -901,8 +921,8 @@ sp_pat_fill (SPPainter *painter, NRPixBlock *pb) cpx[3]=n_a; px_x+=1.0; - ps_x+=pp->px2ps.c[0]; - ps_y+=pp->px2ps.c[1]; + ps_x+=pp->px2ps[0]; + ps_y+=pp->px2ps[1]; cpx+=4; } px_y+=1.0; @@ -915,15 +935,15 @@ sp_pat_fill (SPPainter *painter, NRPixBlock *pb) unsigned char* cpx=lpx; double px_x = pb->area.x0; - double ps_x=pp->px2ps.c[0]*px_x+pp->px2ps.c[2]*px_y+pp->px2ps.c[4]; - double ps_y=pp->px2ps.c[1]*px_x+pp->px2ps.c[3]*px_y+pp->px2ps.c[5]; + double ps_x=pp->px2ps[0]*px_x+pp->px2ps[2]*px_y+pp->px2ps[4]; + double ps_y=pp->px2ps[1]*px_x+pp->px2ps[3]*px_y+pp->px2ps[5]; for (int i=pb->area.x0;iarea.x1;i++) { while ( ps_x > pat_w ) ps_x-=pat_w; while ( ps_x < 0 ) ps_x+=pat_w; while ( ps_y > pat_h ) ps_y-=pat_h; while ( ps_y < 0 ) ps_y+=pat_h; - double ca_x=pp->pa2ca.c[0]*ps_x+pp->pa2ca.c[2]*ps_y+pp->pa2ca.c[4]; - double ca_y=pp->pa2ca.c[1]*ps_x+pp->pa2ca.c[3]*ps_y+pp->pa2ca.c[5]; + double ca_x=pp->pa2ca[0]*ps_x+pp->pa2ca[2]*ps_y+pp->pa2ca[4]; + double ca_y=pp->pa2ca[1]*ps_x+pp->pa2ca[3]*ps_y+pp->pa2ca[5]; unsigned char n_a,n_r,n_g,n_b; get_cached_tile_pixel(pp,ca_x,ca_y,n_r,n_g,n_b,n_a); cpx[0]=n_r; @@ -931,8 +951,8 @@ sp_pat_fill (SPPainter *painter, NRPixBlock *pb) cpx[2]=n_b; px_x+=1.0; - ps_x+=pp->px2ps.c[0]; - ps_y+=pp->px2ps.c[1]; + ps_x+=pp->px2ps[0]; + ps_y+=pp->px2ps[1]; cpx+=4; } px_y+=1.0; @@ -944,36 +964,54 @@ sp_pat_fill (SPPainter *painter, NRPixBlock *pb) ba.y0 = pb->area.y0; ba.x1 = pb->area.x1; ba.y1 = pb->area.y1; - nr_rect_d_matrix_transform (&psa, &ba, &pp->px2ps); - - psa.x0 = floor ((psa.x0 - pattern_x (pp->pat)) / pattern_width (pp->pat)) -1; - psa.y0 = floor ((psa.y0 - pattern_y (pp->pat)) / pattern_height (pp->pat)) -1; - psa.x1 = ceil ((psa.x1 - pattern_x (pp->pat)) / pattern_width (pp->pat)) +1; - psa.y1 = ceil ((psa.y1 - pattern_y (pp->pat)) / pattern_height (pp->pat)) +1; - for (y = psa.y0; y < psa.y1; y++) { - for (x = psa.x0; x < psa.x1; x++) { - NRPixBlock ppb; - double psx, psy; - - psx = x * pattern_width (pp->pat); - psy = y * pattern_height (pp->pat); - - area.x0 = (gint32)(pb->area.x0 - (pp->ps2px.c[0] * psx + pp->ps2px.c[2] * psy)); - area.y0 = (gint32)(pb->area.y0 - (pp->ps2px.c[1] * psx + pp->ps2px.c[3] * psy)); - area.x1 = area.x0 + pb->area.x1 - pb->area.x0; - area.y1 = area.y0 + pb->area.y1 - pb->area.y0; - - // We do not update here anymore - - // Set up buffer - // fixme: (Lauris) - nr_pixblock_setup_extern (&ppb, pb->mode, area.x0, area.y0, area.x1, area.y1, NR_PIXBLOCK_PX (pb), pb->rs, FALSE, FALSE); - - nr_arena_item_invoke_render (pp->root, &area, &ppb, 0); - - nr_pixblock_release (&ppb); - } - } + // Trying to solve this bug: https://bugs.launchpad.net/inkscape/+bug/167416 + // Bail out if the transformation matrix has extreme values. If we bail out + // however, then something (which was meaningless anyway) won't be rendered, + // which is better than getting stuck in a virtually infinite loop + if (fabs(pp->px2ps[0]) < 1e6 && + fabs(pp->px2ps[3]) < 1e6 && + fabs(pp->px2ps[4]) < 1e6 && + fabs(pp->px2ps[5]) < 1e6) + { + // TODO: remove px2ps_nr after converting to 2geom + NR::Matrix px2ps_nr = from_2geom(pp->px2ps); + nr_rect_d_matrix_transform (&psa, &ba, &px2ps_nr); + + psa.x0 = floor ((psa.x0 - pattern_x (pp->pat)) / pattern_width (pp->pat)) -1; + psa.y0 = floor ((psa.y0 - pattern_y (pp->pat)) / pattern_height (pp->pat)) -1; + psa.x1 = ceil ((psa.x1 - pattern_x (pp->pat)) / pattern_width (pp->pat)) +1; + psa.y1 = ceil ((psa.y1 - pattern_y (pp->pat)) / pattern_height (pp->pat)) +1; + + // If psa is too wide or tall, then something must be wrong! This is due to + // nr_rect_d_matrix_transform (&psa, &ba, &pp->px2ps) using a weird transformation matrix pp->px2ps. + g_assert(std::abs(psa.x1 - psa.x0) < 1e6); + g_assert(std::abs(psa.y1 - psa.y0) < 1e6); + + for (y = psa.y0; y < psa.y1; y++) { + for (x = psa.x0; x < psa.x1; x++) { + NRPixBlock ppb; + double psx, psy; + + psx = x * pattern_width (pp->pat); + psy = y * pattern_height (pp->pat); + + area.x0 = (gint32)(pb->area.x0 - (pp->ps2px[0] * psx + pp->ps2px[2] * psy)); + area.y0 = (gint32)(pb->area.y0 - (pp->ps2px[1] * psx + pp->ps2px[3] * psy)); + area.x1 = area.x0 + pb->area.x1 - pb->area.x0; + area.y1 = area.y0 + pb->area.y1 - pb->area.y0; + + // We do not update here anymore + + // Set up buffer + // fixme: (Lauris) + nr_pixblock_setup_extern (&ppb, pb->mode, area.x0, area.y0, area.x1, area.y1, NR_PIXBLOCK_PX (pb), pb->rs, FALSE, FALSE); + + nr_arena_item_invoke_render (NULL, pp->root, &area, &ppb, 0); + + nr_pixblock_release (&ppb); + } + } + } } }