X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fsp-pattern.cpp;h=f89562d256bb9187529acab04512a3c89f4df43e;hb=9e973c4fb2183b877bb600a7e9c75e93b3e7d6d1;hp=8de8ac77b1a3e1a3beffbe7af6b0d3d8c76f6dcc;hpb=3caca4f8381f7ae35678d16074c2414c02a0c0ff;p=inkscape.git diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp index 8de8ac77b..f89562d25 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -12,8 +12,12 @@ * 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 @@ -40,17 +44,17 @@ struct SPPatPainter { SPPainter painter; SPPattern *pat; - NRMatrix ps2px; - NRMatrix px2ps; - NRMatrix pcs2px; + NR::Matrix ps2px; + NR::Matrix px2ps; + NR::Matrix pcs2px; NRArena *arena; unsigned int dkey; NRArenaItem *root; bool use_cached_tile; - NRMatrix ca2pa; - NRMatrix pa2ca; + NR::Matrix ca2pa; + NR::Matrix pa2ca; NRRectL cached_bbox; NRPixBlock cached_tile; }; @@ -422,7 +426,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); @@ -484,12 +488,9 @@ 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 * @@ -503,13 +504,9 @@ pattern_tile (GSList *reprs, NR::Rect bounds, SPDocument *document, NR::Matrix t 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); - } - + gchar *t=sp_svg_transform_write(transform); + repr->setAttribute("patternTransform", t); + g_free(t); defsrepr->appendChild(repr); const gchar *pat_id = repr->attribute("id"); @@ -545,6 +542,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) { @@ -639,7 +637,7 @@ 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, NR::Matrix const &full_transform, NR::Matrix const &/*parent_transform*/, const NRRect *bbox) { SPPattern *pat = SP_PATTERN (ps); SPPatPainter *pp = g_new (SPPatPainter, 1); @@ -657,10 +655,7 @@ sp_pattern_painter_new (SPPaintServer *ps, NR::Matrix const &full_transform, NR: NR::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) */ @@ -677,30 +672,24 @@ 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); + NR::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); // 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 */ @@ -709,16 +698,14 @@ sp_pattern_painter_new (SPPaintServer *ps, NR::Matrix const &full_transform, NR: NR::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 = NR::translate (pattern_x (pat), pattern_y (pat)) * pp->pcs2px; } /* Create arena */ @@ -766,18 +753,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; // } @@ -791,7 +778,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 } @@ -800,7 +787,7 @@ sp_pattern_painter_new (SPPaintServer *ps, NR::Matrix const &full_transform, NR: } 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; @@ -892,15 +879,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; @@ -909,8 +896,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; @@ -923,15 +910,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; @@ -939,8 +926,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; @@ -952,36 +939,52 @@ 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) + { + 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; + + // 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); + } + } + } } }