summaryrefslogtreecommitdiffstats
path: root/src/sp-pattern.cpp
diff options
context:
space:
mode:
authorAndrew Higginson <at.higginson@gmail.com>2011-12-27 21:04:47 +0000
committerAndrew <at.higginson@gmail.com>2011-12-27 21:04:47 +0000
commit80960b623a99aae1402ab651b2974ef544ed3b03 (patch)
treeba49d42c2789e9e11f805e2d5263e10f9fedeef8 /src/sp-pattern.cpp
parenttry to fix bug (diff)
parentGDL: Cherry-pick upstream patch 73852 (2011-03-23) - Add missing return value. (diff)
downloadinkscape-80960b623a99aae1402ab651b2974ef544ed3b03.tar.gz
inkscape-80960b623a99aae1402ab651b2974ef544ed3b03.zip
merged with trunk so I can build again...
(bzr r10092.1.36)
Diffstat (limited to 'src/sp-pattern.cpp')
-rw-r--r--src/sp-pattern.cpp574
1 files changed, 122 insertions, 452 deletions
diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp
index 9ea0ef891..03afc1bf3 100644
--- a/src/sp-pattern.cpp
+++ b/src/sp-pattern.cpp
@@ -18,16 +18,18 @@
#include <cstring>
#include <string>
-#include <libnr/nr-matrix-ops.h>
-#include "libnr/nr-matrix-fns.h"
#include <2geom/transforms.h>
#include "macros.h"
#include "svg/svg.h"
-#include "display/nr-arena.h"
-#include "display/nr-arena-group.h"
+#include "display/cairo-utils.h"
+#include "display/drawing-context.h"
+#include "display/drawing-surface.h"
+#include "display/drawing.h"
+#include "display/drawing-group.h"
#include "attributes.h"
#include "document-private.h"
#include "uri.h"
+#include "style.h"
#include "sp-pattern.h"
#include "xml/repr.h"
#include "display/grayscale.h"
@@ -39,44 +41,19 @@
* Pattern
*/
-class SPPatPainter;
-
-struct SPPatPainter {
- SPPainter painter;
- SPPattern *pat;
-
- Geom::Affine ps2px;
- Geom::Affine px2ps;
- Geom::Affine pcs2px;
-
- NRArena *arena;
- unsigned int dkey;
- NRArenaItem *root;
-
- bool use_cached_tile;
- Geom::Affine ca2pa;
- Geom::Affine pa2ca;
- NRRectL cached_bbox;
- NRPixBlock cached_tile;
-
- std::map<SPObject *, sigc::connection> *_release_connections;
-};
-
static void sp_pattern_class_init (SPPatternClass *klass);
static void sp_pattern_init (SPPattern *gr);
static void sp_pattern_build (SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
static void sp_pattern_release (SPObject *object);
static void sp_pattern_set (SPObject *object, unsigned int key, const gchar *value);
-static void sp_pattern_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref);
static void sp_pattern_update (SPObject *object, SPCtx *ctx, unsigned int flags);
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, Geom::Affine const &full_transform, Geom::Affine const &parent_transform, const NRRect *bbox);
-static void sp_pattern_painter_free (SPPaintServer *ps, SPPainter *painter);
+static cairo_pattern_t *sp_pattern_create_pattern(SPPaintServer *ps, cairo_t *ct, Geom::OptRect const &bbox, double opacity);
static SPPaintServerClass * pattern_parent_class;
@@ -116,14 +93,12 @@ sp_pattern_class_init (SPPatternClass *klass)
sp_object_class->build = sp_pattern_build;
sp_object_class->release = sp_pattern_release;
sp_object_class->set = sp_pattern_set;
- sp_object_class->child_added = sp_pattern_child_added;
sp_object_class->update = sp_pattern_update;
sp_object_class->modified = sp_pattern_modified;
// do we need _write? seems to work without it
- ps_class->painter_new = sp_pattern_painter_new;
- ps_class->painter_free = sp_pattern_painter_free;
+ ps_class->pattern_new = sp_pattern_create_pattern;
}
static void
@@ -138,7 +113,7 @@ sp_pattern_init (SPPattern *pat)
pat->patternContentUnits = SP_PATTERN_UNITS_USERSPACEONUSE;
pat->patternContentUnits_set = FALSE;
- pat->patternTransform = NR::identity();
+ pat->patternTransform = Geom::identity();
pat->patternTransform_set = FALSE;
pat->x.unset();
@@ -232,7 +207,7 @@ sp_pattern_set (SPObject *object, unsigned int key, const gchar *value)
pat->patternTransform = t;
pat->patternTransform_set = TRUE;
} else {
- pat->patternTransform = NR::identity();
+ pat->patternTransform = Geom::identity();
pat->patternTransform_set = FALSE;
}
object->requestModified(SP_OBJECT_MODIFIED_FLAG);
@@ -270,11 +245,8 @@ sp_pattern_set (SPObject *object, unsigned int key, const gchar *value)
height = g_ascii_strtod (eptr, &eptr);
while (*eptr && ((*eptr == ',') || (*eptr == ' '))) eptr++;
if ((width > 0) && (height > 0)) {
- pat->viewBox.x0 = x;
- pat->viewBox.y0 = y;
- pat->viewBox.x1 = x + width;
- pat->viewBox.y1 = y + height;
- pat->viewBox_set = TRUE;
+ pat->viewBox = Geom::Rect::from_xywh(x, y, width, height);
+ pat->viewBox_set = TRUE;
} else {
pat->viewBox_set = FALSE;
}
@@ -314,34 +286,6 @@ sp_pattern_set (SPObject *object, unsigned int key, const gchar *value)
}
}
-static void
-sp_pattern_child_added (SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
-{
- SPPattern *pat = SP_PATTERN (object);
-
- if (((SPObjectClass *) (pattern_parent_class))->child_added)
- (* ((SPObjectClass *) (pattern_parent_class))->child_added) (object, child, ref);
-
- SPObject *ochild = object->get_child_by_repr(child);
- if (SP_IS_ITEM (ochild)) {
-
- SPPaintServer *ps = SP_PAINT_SERVER (pat);
- unsigned position = SP_ITEM(ochild)->pos_in_parent();
-
- for (SPPainter *p = ps->painters; p != NULL; p = p->next) {
-
- SPPatPainter *pp = (SPPatPainter *) p;
- NRArenaItem *ai = SP_ITEM (ochild)->invoke_show (pp->arena, pp->dkey, SP_ITEM_REFERENCE_FLAGS);
-
- if (ai) {
- nr_arena_item_add_child (pp->root, ai, NULL);
- nr_arena_item_set_order (ai, position);
- nr_arena_item_unref (ai);
- }
- }
- }
-}
-
/* TODO: do we need a ::remove_child handler? */
/* fixme: We need ::order_changed handler too (Lauris) */
@@ -472,7 +416,7 @@ SPPattern *pattern_chain(SPPattern *pattern)
{
SPDocument *document = pattern->document;
Inkscape::XML::Document *xml_doc = document->getReprDoc();
- Inkscape::XML::Node *defsrepr = SP_DOCUMENT_DEFS(document)->getRepr();
+ Inkscape::XML::Node *defsrepr = document->getDefs()->getRepr();
Inkscape::XML::Node *repr = xml_doc->createElement("svg:pattern");
repr->setAttribute("inkscape:collect", "always");
@@ -525,7 +469,7 @@ sp_pattern_transform_multiply (SPPattern *pattern, Geom::Affine postmul, bool se
const gchar *pattern_tile(GSList *reprs, Geom::Rect bounds, SPDocument *document, Geom::Affine transform, Geom::Affine move)
{
Inkscape::XML::Document *xml_doc = document->getReprDoc();
- Inkscape::XML::Node *defsrepr = SP_DOCUMENT_DEFS(document)->getRepr();
+ Inkscape::XML::Node *defsrepr = document->getDefs()->getRepr();
Inkscape::XML::Node *repr = xml_doc->createElement("svg:pattern");
repr->setAttribute("patternUnits", "userSpaceOnUse");
@@ -634,13 +578,16 @@ gdouble pattern_height (SPPattern *pat)
return 0;
}
-NRRect *pattern_viewBox (SPPattern *pat)
+Geom::OptRect pattern_viewBox (SPPattern *pat)
{
- for (SPPattern *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) {
- if (pat_i->viewBox_set)
- return &(pat_i->viewBox);
- }
- return &(pat->viewBox);
+ Geom::OptRect viewbox;
+ for (SPPattern *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) {
+ if (pat_i->viewBox_set) {
+ viewbox = pat_i->viewBox;
+ break;
+ }
+ }
+ return viewbox;
}
bool pattern_hasItemChildren (SPPattern *pat)
@@ -654,401 +601,124 @@ bool pattern_hasItemChildren (SPPattern *pat)
return hasChildren;
}
-
-
-/* Painter */
-
-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)
+static cairo_pattern_t *
+sp_pattern_create_pattern(SPPaintServer *ps,
+ cairo_t *base_ct,
+ Geom::OptRect const &bbox,
+ double opacity)
{
- std::map<SPObject *, sigc::connection>::iterator iter = painter->_release_connections->find(obj);
- if (iter != painter->_release_connections->end()) {
- iter->second.disconnect();
- painter->_release_connections->erase(obj);
- }
+ SPPattern *pat = SP_PATTERN (ps);
+ Geom::Affine ps2user;
+ Geom::Affine vb2ps = Geom::identity();
+ bool needs_opacity = (1.0 - opacity) >= 1e-3;
+ bool visible = opacity >= 1e-3;
- SP_ITEM(obj)->invoke_hide(painter->dkey);
-}
+ if (!visible)
+ return NULL;
-/**
-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, Geom::Affine const &full_transform, Geom::Affine const &/*parent_transform*/, const NRRect *bbox)
-{
- SPPattern *pat = SP_PATTERN (ps);
- SPPatPainter *pp = g_new (SPPatPainter, 1);
-
- pp->painter.type = SP_PAINTER_IND;
- pp->painter.fill = sp_pat_fill;
-
- pp->pat = pat;
-
- if (pattern_patternUnits (pat) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) {
- /* BBox to user coordinate system */
- Geom::Affine bbox2user (bbox->x1 - bbox->x0, 0.0, 0.0, bbox->y1 - bbox->y0, bbox->x0, bbox->y0);
-
- // the final patternTransform, taking into account bbox
- Geom::Affine const ps2user(pattern_patternTransform(pat) * bbox2user);
+ /* Show items */
+ SPPattern *shown = NULL;
+ for (SPPattern *pat_i = pat; pat_i != NULL; pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) {
+ // find the first one with item children
+ if (pat_i && SP_IS_OBJECT (pat_i) && pattern_hasItemChildren(pat_i)) {
+ shown = pat_i;
+ break; // do not go further up the chain if children are found
+ }
+ }
- // see (*) comment below
- 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) */
-
- /* fixme: We may try to normalize here too, look at linearGradient (Lauris) */
-
- // (*) The spec says, "This additional transformation matrix [patternTransform] is
- // post-multiplied to (i.e., inserted to the right of) any previously defined
- // transformations, including the implicit transformation necessary to convert from
- // object bounding box units to user space." To me, this means that the order should be:
- // item_transform * patternTransform * parent_transform
- // However both Batik and Adobe plugin use:
- // patternTransform * item_transform * parent_transform
- // So here I comply with the majority opinion, but leave my interpretation commented out below.
- // (To get item_transform, I subtract parent from full.)
-
- //pp->ps2px = (full_transform / parent_transform) * pattern_patternTransform(pat) * parent_transform;
- pp->ps2px = pattern_patternTransform(pat) * full_transform;
- }
+ if (!shown) {
+ return cairo_pattern_create_rgba(0,0,0,0);
+ }
- pp->px2ps = pp->ps2px.inverse();
+ /* Create drawing for rendering */
+ Inkscape::Drawing drawing;
+ unsigned int dkey = SPItem::display_key_new (1);
+ Inkscape::DrawingGroup *root = new Inkscape::DrawingGroup(drawing);
+ drawing.setRoot(root);
+
+ for (SPObject *child = shown->firstChild(); child != NULL; child = child->getNext() ) {
+ if (SP_IS_ITEM (child)) {
+ // for each item in pattern, show it on our drawing, add to the group,
+ // and connect to the release signal in case the item gets deleted
+ Inkscape::DrawingItem *cai;
+ cai = SP_ITEM(child)->invoke_show (drawing, dkey, SP_ITEM_SHOW_DISPLAY);
+ root->appendChild(cai);
+ }
+ }
- if (pat->viewBox_set) {
- 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);
+ if (pat->viewBox_set) {
+ Geom::Rect vb = *pattern_viewBox(pat);
+ gdouble tmp_x = pattern_width (pat) / vb.width();
+ gdouble tmp_y = pattern_height (pat) / vb.height();
- // FIXME: preserveAspectRatio must be taken into account here too!
- Geom::Affine 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);
+ // FIXME: preserveAspectRatio must be taken into account here too!
+ vb2ps = Geom::Affine(tmp_x, 0.0, 0.0, tmp_y, pattern_x(pat) - vb.left() * tmp_x, pattern_y(pat) - vb.top() * tmp_y);
+ }
- Geom::Affine vb2us = vb2ps * pattern_patternTransform(pat);
+ ps2user = pattern_patternTransform(pat);
+ if (!pat->viewBox_set && pattern_patternContentUnits (pat) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) {
+ /* BBox to user coordinate system */
+ Geom::Affine bbox2user (bbox->width(), 0.0, 0.0, bbox->height(), bbox->left(), bbox->top());
+ ps2user *= bbox2user;
+ }
+ ps2user = Geom::Translate (pattern_x (pat), pattern_y (pat)) * ps2user;
- // see (*)
- pp->pcs2px = vb2us * full_transform;
- } else {
- /* No viewbox, have to parse units */
- if (pattern_patternContentUnits (pat) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) {
- /* BBox to user coordinate system */
- Geom::Affine bbox2user (bbox->x1 - bbox->x0, 0.0, 0.0, bbox->y1 - bbox->y0, bbox->x0, bbox->y0);
+ Geom::Rect pattern_tile = Geom::Rect::from_xywh(pattern_x(pat), pattern_y(pat),
+ pattern_width(pat), pattern_height(pat));
- Geom::Affine pcs2user = pattern_patternTransform(pat) * bbox2user;
+ if (pattern_patternUnits(pat) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) {
+ // interpret x, y, width, height in relation to bbox
+ Geom::Affine bbox2user(bbox->width(), 0.0, 0.0, bbox->height(), bbox->left(), bbox->top());
+ pattern_tile = pattern_tile * bbox2user;
+ }
- // see (*)
- pp->pcs2px = pcs2user * full_transform;
- } else {
- // see (*)
- //pcs2px = (full_transform / parent_transform) * pattern_patternTransform(pat) * parent_transform;
- pp->pcs2px = pattern_patternTransform(pat) * full_transform;
- }
+ cairo_matrix_t cm;
+ cairo_get_matrix(base_ct, &cm);
+ Geom::Affine full(cm.xx, cm.yx, cm.xy, cm.yy, 0, 0);
+
+ // oversample the pattern slightly
+ // TODO: find optimum value
+ // TODO: this is lame. instead of using descrim(), we should extract
+ // the scaling component from the complete matrix and use it
+ // to find the optimum tile size for rendering
+ Geom::Point c(pattern_tile.dimensions()*vb2ps.descrim()*ps2user.descrim()*full.descrim()*1.1);
+ c[Geom::X] = ceil(c[Geom::X]);
+ c[Geom::Y] = ceil(c[Geom::Y]);
+
+ Geom::IntRect one_tile = pattern_tile.roundOutwards();
+ Inkscape::DrawingSurface temp(pattern_tile, c.ceil());
+ Inkscape::DrawingContext ct(temp);
- pp->pcs2px = Geom::Translate (pattern_x (pat), pattern_y (pat)) * pp->pcs2px;
- }
+ // render pattern.
+ if (needs_opacity) {
+ ct.pushGroup(); // this group is for pattern + opacity
+ }
- /* Create arena */
- pp->arena = NRArena::create();
-
- pp->dkey = SPItem::display_key_new (1);
-
- /* Create group */
- pp->root = NRArenaGroup::create(pp->arena);
-
- /* Show items */
- pp->_release_connections = new std::map<SPObject *, sigc::connection>;
- 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 = pat_i->firstChild() ; child; child = child->getNext() ) {
- if (SP_IS_ITEM (child)) {
- // for each item in pattern,
- // show it on our arena,
- NRArenaItem *cai = SP_ITEM(child)->invoke_show(pp->arena, pp->dkey, SP_ITEM_REFERENCE_FLAGS);
- // add to the group,
- nr_arena_item_append_child (pp->root, 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
- }
+ // TODO: make sure there are no leaks.
+ Inkscape::UpdateContext ctx;
+ ctx.ctm = vb2ps;
+ drawing.update(Geom::IntRect::infinite(), ctx);
+ drawing.render(ct, one_tile);
+ for (SPObject *child = shown->firstChild() ; child != NULL; child = child->getNext() ) {
+ if (SP_IS_ITEM (child)) {
+ SP_ITEM(child)->invoke_hide(dkey);
}
+ }
- {
- NRRect one_tile,tr_tile;
- one_tile.x0=pattern_x(pp->pat);
- 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);
- // 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 ) {
- pp->use_cached_tile=false;//true;
- if ( tr_width > 1000 ) tr_width=1000;
- if ( tr_height > 1000 ) tr_height=1000;
- pp->cached_bbox.x0=0;
- pp->cached_bbox.y0=0;
- pp->cached_bbox.x1=tr_width;
- pp->cached_bbox.y1=tr_height;
-
- if (pp->use_cached_tile) {
- 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[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;
-// }
- }
-
- NRGC gc(NULL);
- if ( pp->use_cached_tile ) {
- gc.transform=pp->pa2ca;
- } else {
- gc.transform = pp->pcs2px;
- }
- 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 (NULL, pp->root, &pp->cached_bbox, &pp->cached_tile, 0);
- } else {
- // nothing to do now
- }
-
- return (SPPainter *) pp;
-}
-
+ if (needs_opacity) {
+ ct.popGroupToSource(); // pop raw pattern
+ ct.paint(opacity); // apply opacity
+ }
-static void
-sp_pattern_painter_free (SPPaintServer */*ps*/, SPPainter *painter)
-{
- SPPatPainter *pp = (SPPatPainter *) painter;
- // free our arena
- if (pp->arena) {
- ((NRObject *) pp->arena)->unreference();
- pp->arena = NULL;
- }
-
- // disconnect all connections
- std::map<SPObject *, sigc::connection>::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;
+ cairo_pattern_t *cp = cairo_pattern_create_for_surface(temp.raw());
- if ( pp->use_cached_tile ) nr_pixblock_release(&pp->cached_tile);
- g_free (pp);
-}
+ // Apply transformation to user space. Also compensate for oversampling.
+ ink_cairo_pattern_set_matrix(cp, ps2user.inverse() * temp.drawingTransform());
+ cairo_pattern_set_extend(cp, CAIRO_EXTEND_REPEAT);
-void
-get_cached_tile_pixel(SPPatPainter* pp,double x,double y,unsigned char &r,unsigned char &g,unsigned char &b,unsigned char &a)
-{
- int ca_h=(int)floor(x);
- int ca_v=(int)floor(y);
- int r_x=(int)floor(16*(x-floor(x)));
- int r_y=(int)floor(16*(y-floor(y)));
- unsigned int tl_m=(16-r_x)*(16-r_y);
- unsigned int bl_m=(16-r_x)*r_y;
- unsigned int tr_m=r_x*(16-r_y);
- unsigned int br_m=r_x*r_y;
- int cb_h=ca_h+1;
- int cb_v=ca_v+1;
- if ( cb_h >= pp->cached_bbox.x1 ) cb_h=0;
- if ( cb_v >= pp->cached_bbox.y1 ) cb_v=0;
-
- unsigned char* tlx=NR_PIXBLOCK_PX(&pp->cached_tile)+(ca_v*pp->cached_tile.rs)+4*ca_h;
- unsigned char* trx=NR_PIXBLOCK_PX(&pp->cached_tile)+(ca_v*pp->cached_tile.rs)+4*cb_h;
- unsigned char* blx=NR_PIXBLOCK_PX(&pp->cached_tile)+(cb_v*pp->cached_tile.rs)+4*ca_h;
- unsigned char* brx=NR_PIXBLOCK_PX(&pp->cached_tile)+(cb_v*pp->cached_tile.rs)+4*cb_h;
-
- unsigned int tl_c=tlx[0];
- unsigned int tr_c=trx[0];
- unsigned int bl_c=blx[0];
- unsigned int br_c=brx[0];
- unsigned int f_c=(tl_m*tl_c+tr_m*tr_c+bl_m*bl_c+br_m*br_c)>>8;
- r=f_c;
- tl_c=tlx[1];
- tr_c=trx[1];
- bl_c=blx[1];
- br_c=brx[1];
- f_c=(tl_m*tl_c+tr_m*tr_c+bl_m*bl_c+br_m*br_c)>>8;
- g=f_c;
- tl_c=tlx[2];
- tr_c=trx[2];
- bl_c=blx[2];
- br_c=brx[2];
- f_c=(tl_m*tl_c+tr_m*tr_c+bl_m*bl_c+br_m*br_c)>>8;
- b=f_c;
- tl_c=tlx[3];
- tr_c=trx[3];
- bl_c=blx[3];
- br_c=brx[3];
- f_c=(tl_m*tl_c+tr_m*tr_c+bl_m*bl_c+br_m*br_c)>>8;
- a=f_c;
+ return cp;
}
-static void
-sp_pat_fill (SPPainter *painter, NRPixBlock *pb)
-{
- SPPatPainter *pp;
- NRRect ba, psa;
- NRRectL area;
- double x, y;
-
- pp = (SPPatPainter *) painter;
-
- if (pattern_width (pp->pat) < NR_EPSILON) return;
- if (pattern_height (pp->pat) < NR_EPSILON) return;
-
- bool grayscale = Grayscale::activeDesktopIsGrayscale(); // TODO: find good way to access the current rendermode
-
- /* Find buffer area in gradient space */
- /* fixme: This is suboptimal (Lauris) */
-
- if ( !grayscale && pp->use_cached_tile ) {
- double pat_w=pattern_width (pp->pat);
- double pat_h=pattern_height (pp->pat);
- if ( pb->mode == NR_PIXBLOCK_MODE_R8G8B8A8N || pb->mode == NR_PIXBLOCK_MODE_R8G8B8A8P ) { // same thing because it's filling an empty pixblock
- unsigned char* lpx=NR_PIXBLOCK_PX(pb);
- double px_y=pb->area.y0;
- for (int j=pb->area.y0;j<pb->area.y1;j++) {
- unsigned char* cpx=lpx;
- double px_x = pb->area.x0;
-
- 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;i<pb->area.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[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;
- cpx[1]=n_g;
- cpx[2]=n_b;
- cpx[3]=n_a;
-
- px_x+=1.0;
- ps_x+=pp->px2ps[0];
- ps_y+=pp->px2ps[1];
- cpx+=4;
- }
- px_y+=1.0;
- lpx+=pb->rs;
- }
- } else if ( pb->mode == NR_PIXBLOCK_MODE_R8G8B8 ) {
- unsigned char* lpx=NR_PIXBLOCK_PX(pb);
- double px_y=pb->area.y0;
- for (int j=pb->area.y0;j<pb->area.y1;j++) {
- unsigned char* cpx=lpx;
- double px_x = pb->area.x0;
-
- 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;i<pb->area.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[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;
- cpx[1]=n_g;
- cpx[2]=n_b;
-
- px_x+=1.0;
- ps_x+=pp->px2ps[0];
- ps_y+=pp->px2ps[1];
- cpx+=4;
- }
- px_y+=1.0;
- lpx+=pb->rs;
- }
- }
- } else {
- ba.x0 = pb->area.x0;
- ba.y0 = pb->area.y0;
- ba.x1 = pb->area.x1;
- ba.y1 = pb->area.y1;
-
- // 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);
-
- Inkscape::ColorRenderMode saved_colormode = pp->root->arena->colorrendermode;
- if (grayscale) {
- pp->root->arena->colorrendermode = Inkscape::COLORRENDERMODE_GRAYSCALE;
- }
- nr_arena_item_invoke_render (NULL, pp->root, &area, &ppb, 0);
- pp->root->arena->colorrendermode = saved_colormode;
-
- nr_pixblock_release (&ppb);
- }
- }
- }
- }
-}
-
-
/*
Local Variables:
mode:c++
@@ -1058,4 +728,4 @@ sp_pat_fill (SPPainter *painter, NRPixBlock *pb)
fill-column:99
End:
*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :