summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTomasz Boczkowski <penginsbacon@gmail.com>2014-10-14 11:30:31 +0000
committerTomasz Boczkowski <penginsbacon@gmail.com>2014-10-14 11:30:31 +0000
commitbf11ecdfe29082801833fa565f0a1710f6fcd281 (patch)
tree6030ebac0996bd586d648567544e9f9198a3b654 /src
parentMerged hatch rendering code (diff)
downloadinkscape-bf11ecdfe29082801833fa565f0a1710f6fcd281.tar.gz
inkscape-bf11ecdfe29082801833fa565f0a1710f6fcd281.zip
Merged hatch pdf and png export code
(bzr r13611.1.9)
Diffstat (limited to 'src')
-rw-r--r--src/display/drawing-pattern.cpp1
-rw-r--r--src/display/drawing-pattern.h1
-rw-r--r--src/extension/internal/cairo-render-context.cpp116
-rw-r--r--src/extension/internal/cairo-render-context.h1
-rw-r--r--src/extension/internal/cairo-renderer.cpp16
-rw-r--r--src/extension/internal/cairo-renderer.h2
-rw-r--r--src/sp-hatch-path.cpp61
-rw-r--r--src/sp-hatch-path.h7
-rw-r--r--src/sp-hatch.cpp124
-rw-r--r--src/sp-hatch.h26
-rw-r--r--src/sp-item.cpp32
-rw-r--r--src/sp-paint-server.h2
12 files changed, 315 insertions, 74 deletions
diff --git a/src/display/drawing-pattern.cpp b/src/display/drawing-pattern.cpp
index 77752bce3..cf6358278 100644
--- a/src/display/drawing-pattern.cpp
+++ b/src/display/drawing-pattern.cpp
@@ -159,7 +159,6 @@ DrawingPattern::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx,
}
Geom::Rect pattern_tile = *_tile_rect;
-
Geom::Coord det_ctm = ctx.ctm.descrim();
Geom::Coord det_ps2user = _pattern_to_user ? _pattern_to_user->descrim() : 1.0;
Geom::Coord det_child_transform = _child_transform ? _child_transform->descrim() : 1.0;
diff --git a/src/display/drawing-pattern.h b/src/display/drawing-pattern.h
index b614785dc..7483ba067 100644
--- a/src/display/drawing-pattern.h
+++ b/src/display/drawing-pattern.h
@@ -59,7 +59,6 @@ public:
protected:
virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx,
unsigned flags, unsigned reset);
- Geom::IntPoint _patternDimentions();
Geom::Affine *_pattern_to_user;
Geom::Affine _overflow_initial_transform;
diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp
index c09b8e9c8..7e61cdbbb 100644
--- a/src/extension/internal/cairo-render-context.cpp
+++ b/src/extension/internal/cairo-render-context.cpp
@@ -39,6 +39,7 @@
#include "sp-item.h"
#include "sp-item-group.h"
#include "style.h"
+#include "sp-hatch.h"
#include "sp-linear-gradient.h"
#include "sp-radial-gradient.h"
#include "sp-pattern.h"
@@ -1130,6 +1131,82 @@ CairoRenderContext::_createPatternPainter(SPPaintServer const *const paintserver
}
cairo_pattern_t*
+CairoRenderContext::_createHatchPainter(SPPaintServer const *const paintserver, Geom::OptRect const &pbox) {
+ g_assert( SP_IS_HATCH(paintserver) );
+ SPHatch *hatch = SP_HATCH(paintserver);
+
+ g_assert(hatch->pitch() > 0);
+
+ // create drawing and group
+ Inkscape::Drawing drawing;
+ unsigned dkey = SPItem::display_key_new(1);
+
+ hatch->show(drawing, dkey, pbox);
+
+ SPHatch::RenderInfo render_info = hatch->calculateRenderInfo(dkey);
+ Geom::Rect tile_rect = render_info.tile_rect;
+
+ // Cairo requires an integer pattern surface width/height.
+ // Subtract 0.5 to prevent small rounding errors from increasing pattern size by one pixel.
+ // Multiply by SUBPIX_SCALE to allow for less than a pixel precision
+ const int subpix_scale = 10;
+ double surface_width = MAX(ceil(subpix_scale * tile_rect.width() - 0.5), 1);
+ double surface_height = MAX(ceil(subpix_scale * tile_rect.height() - 0.5), 1);
+ Geom::Affine drawing_scale = Geom::Scale(surface_width / tile_rect.width(), surface_height / tile_rect.height());
+ Geom::Affine drawing_transform = Geom::Translate(-tile_rect.min()) * drawing_scale;
+
+ Geom::Affine child_transform = render_info.child_transform;
+ child_transform *= drawing_transform;
+
+ //The rendering of hatch overflow is implemented by repeated drawing
+ //of hatch paths over one strip. Within each iteration paths are moved by pitch value.
+ //The movement progresses from right to left. This gives the same result
+ //as drawing whole strips in left-to-right order.
+ gdouble overflow_right_strip = 0.0;
+ int overflow_steps = 1;
+ Geom::Affine overflow_transform;
+ if (hatch->style->overflow.computed == SP_CSS_OVERFLOW_VISIBLE) {
+ Geom::Interval bounds = hatch->bounds();
+ overflow_right_strip = floor(bounds.max() / hatch->pitch()) * hatch->pitch();
+ overflow_steps = ceil((overflow_right_strip - bounds.min()) / hatch->pitch()) + 1;
+ overflow_transform = Geom::Translate(hatch->pitch(), 0.0);
+ }
+
+ CairoRenderContext *pattern_ctx = cloneMe(surface_width, surface_height);
+ pattern_ctx->setTransform(child_transform);
+ pattern_ctx->transform(Geom::Translate(-overflow_right_strip, 0.0));
+ pattern_ctx->pushState();
+
+ std::vector<SPHatchPath *> children;
+ hatch->hatchPaths(children);
+
+ for (int i = 0; i < overflow_steps; i++) {
+ for (std::vector<SPHatchPath *>::iterator iter = children.begin(); iter != children.end(); iter++) {
+ SPHatchPath *path = *iter;
+ _renderer->renderHatchPath(pattern_ctx, *path, dkey);
+ }
+ pattern_ctx->transform(overflow_transform);
+ }
+
+ pattern_ctx->popState();
+
+ // setup a cairo_pattern_t
+ cairo_surface_t *pattern_surface = pattern_ctx->getSurface();
+ TEST(pattern_ctx->saveAsPng("hatch.png"));
+ cairo_pattern_t *result = cairo_pattern_create_for_surface(pattern_surface);
+ cairo_pattern_set_extend(result, CAIRO_EXTEND_REPEAT);
+
+ Geom::Affine pattern_transform;
+ pattern_transform = render_info.pattern_to_user_transform.inverse() * drawing_transform;
+ ink_cairo_pattern_set_matrix(result, pattern_transform);
+
+ hatch->hide(dkey);
+
+ delete pattern_ctx;
+ return result;
+}
+
+cairo_pattern_t*
CairoRenderContext::_createPatternForPaintServer(SPPaintServer const *const paintserver,
Geom::OptRect const &pbox, float alpha)
{
@@ -1182,8 +1259,9 @@ CairoRenderContext::_createPatternForPaintServer(SPPaintServer const *const pain
cairo_pattern_add_color_stop_rgba(pattern, rg->vector.stops[i].offset, rgb[0], rgb[1], rgb[2], rg->vector.stops[i].opacity * alpha);
}
} else if (SP_IS_PATTERN (paintserver)) {
-
pattern = _createPatternPainter(paintserver, pbox);
+ } else if (SP_IS_HATCH (paintserver)) {
+ pattern = _createHatchPainter(paintserver, pbox);
} else {
return NULL;
}
@@ -1249,26 +1327,29 @@ CairoRenderContext::_setFillStyle(SPStyle const *const style, Geom::OptRect cons
TRACE(("merged op=%f\n", alpha));
}
- if (style->fill.isColor()) {
- float rgb[3];
- sp_color_get_rgb_floatv(&style->fill.value.color, rgb);
+ SPPaintServer const *paint_server = style->getFillPaintServer();
+ if (paint_server && paint_server->isValid()) {
- cairo_set_source_rgba(_cr, rgb[0], rgb[1], rgb[2], alpha);
-
- } else if (!style->fill.set) { // unset fill is black
- cairo_set_source_rgba(_cr, 0, 0, 0, alpha);
-
- } else {
- g_assert( style->fill.isPaintserver()
- || SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style))
- || SP_IS_PATTERN(SP_STYLE_FILL_SERVER(style)) );
-
- cairo_pattern_t *pattern = _createPatternForPaintServer(SP_STYLE_FILL_SERVER(style), pbox, alpha);
+ g_assert(SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style))
+ || SP_IS_PATTERN(SP_STYLE_FILL_SERVER(style))
+ || SP_IS_HATCH(SP_STYLE_FILL_SERVER(style)));
+ cairo_pattern_t *pattern = _createPatternForPaintServer(paint_server, pbox, alpha);
if (pattern) {
cairo_set_source(_cr, pattern);
cairo_pattern_destroy(pattern);
}
+ } else if (style->fill.colorSet) {
+ float rgb[3];
+ sp_color_get_rgb_floatv(&style->fill.value.color, rgb);
+
+ cairo_set_source_rgba(_cr, rgb[0], rgb[1], rgb[2], alpha);
+
+ } else { // unset fill is black
+ g_assert(!style->fill.set
+ || (paint_server && !paint_server->isValid()));
+
+ cairo_set_source_rgba(_cr, 0, 0, 0, alpha);
}
}
@@ -1279,7 +1360,7 @@ CairoRenderContext::_setStrokeStyle(SPStyle const *style, Geom::OptRect const &p
if (_state->merge_opacity)
alpha *= _state->opacity;
- if (style->stroke.isColor()) {
+ if (style->stroke.isColor() || (style->stroke.isPaintserver() && !style->getStrokePaintServer()->isValid())) {
float rgb[3];
sp_color_get_rgb_floatv(&style->stroke.value.color, rgb);
@@ -1287,7 +1368,8 @@ CairoRenderContext::_setStrokeStyle(SPStyle const *style, Geom::OptRect const &p
} else {
g_assert( style->stroke.isPaintserver()
|| SP_IS_GRADIENT(SP_STYLE_STROKE_SERVER(style))
- || SP_IS_PATTERN(SP_STYLE_STROKE_SERVER(style)) );
+ || SP_IS_PATTERN(SP_STYLE_STROKE_SERVER(style))
+ || SP_IS_HATCH(SP_STYLE_STROKE_SERVER(style)));
cairo_pattern_t *pattern = _createPatternForPaintServer(SP_STYLE_STROKE_SERVER(style), pbox, alpha);
diff --git a/src/extension/internal/cairo-render-context.h b/src/extension/internal/cairo-render-context.h
index 8d3e63775..59781a49c 100644
--- a/src/extension/internal/cairo-render-context.h
+++ b/src/extension/internal/cairo-render-context.h
@@ -201,6 +201,7 @@ protected:
cairo_pattern_t *_createPatternForPaintServer(SPPaintServer const *const paintserver,
Geom::OptRect const &pbox, float alpha);
cairo_pattern_t *_createPatternPainter(SPPaintServer const *const paintserver, Geom::OptRect const &pbox);
+ cairo_pattern_t *_createHatchPainter(SPPaintServer const *const paintserver, Geom::OptRect const &pbox);
unsigned int _showGlyphs(cairo_t *cr, PangoFont *font, std::vector<CairoGlyphInfo> const &glyphtext, bool is_stroke);
diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp
index 6fbc85c05..ec302bbfc 100644
--- a/src/extension/internal/cairo-renderer.cpp
+++ b/src/extension/internal/cairo-renderer.cpp
@@ -50,6 +50,7 @@
#include "sp-use.h"
#include "sp-text.h"
#include "sp-flowtext.h"
+#include "sp-hatch-path.h"
#include "sp-image.h"
#include "sp-symbol.h"
#include "sp-pattern.h"
@@ -596,6 +597,21 @@ void CairoRenderer::renderItem(CairoRenderContext *ctx, SPItem *item)
ctx->popState();
}
+void CairoRenderer::renderHatchPath(CairoRenderContext *ctx, SPHatchPath const &hatchPath, unsigned key) {
+ ctx->pushState();
+ ctx->setStateForStyle(hatchPath.style);
+ ctx->transform(Geom::Translate(hatchPath.offset.computed, 0));
+
+ SPCurve *curve = hatchPath.calculateRenderCurve(key);
+ Geom::PathVector const & pathv =curve->get_pathvector();
+ if (!pathv.empty()) {
+ ctx->renderPathVector(pathv, hatchPath.style, Geom::OptRect());
+ }
+
+ curve->unref();
+ ctx->popState();
+}
+
bool
CairoRenderer::setupDocument(CairoRenderContext *ctx, SPDocument *doc, bool pageBoundingBox, float bleedmargin_px, SPItem *base)
{
diff --git a/src/extension/internal/cairo-renderer.h b/src/extension/internal/cairo-renderer.h
index cfef6bdea..abc0447d8 100644
--- a/src/extension/internal/cairo-renderer.h
+++ b/src/extension/internal/cairo-renderer.h
@@ -29,6 +29,7 @@
class SPClipPath;
class SPMask;
+class SPHatchPath;
namespace Inkscape {
namespace Extension {
@@ -57,6 +58,7 @@ public:
/** Traverses the object tree and invokes the render methods. */
void renderItem(CairoRenderContext *ctx, SPItem *item);
+ void renderHatchPath(CairoRenderContext *ctx, SPHatchPath const &hatchPath, unsigned key);
};
// FIXME: this should be a static method of CairoRenderer
diff --git a/src/sp-hatch-path.cpp b/src/sp-hatch-path.cpp
index bdefd32d8..f7138fac2 100644
--- a/src/sp-hatch-path.cpp
+++ b/src/sp-hatch-path.cpp
@@ -25,6 +25,7 @@
#include "display/drawing-surface.h"
#include "display/drawing.h"
#include "display/drawing-shape.h"
+#include "helper/geom.h"
#include "attributes.h"
#include "document-private.h"
#include "uri.h"
@@ -45,6 +46,7 @@ bool hatchRegistered = SPFactory::instance().registerObject("svg:hatchPath", cre
SPHatchPath::SPHatchPath()
: _curve(NULL)
+ , _continuous(false)
{
offset.unset();
}
@@ -131,6 +133,8 @@ void SPHatchPath::update(SPCtx* ctx, unsigned int flags) {
if (flags & (SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
if (this->style->stroke_width.unit == SP_CSS_UNIT_PERCENT) {
+ //TODO: Check specification
+
SPItemCtx *ictx = (SPItemCtx *) ctx;
double const aw = 1.0 / ictx->i2vp.descrim();
this->style->stroke_width.computed = this->style->stroke_width.value * aw;
@@ -155,9 +159,10 @@ bool SPHatchPath::isValid() const {
return true;
}
-Inkscape::DrawingItem *SPHatchPath::show(Inkscape::Drawing &drawing, unsigned int key) {
+Inkscape::DrawingItem *SPHatchPath::show(Inkscape::Drawing &drawing, unsigned int key, Geom::OptInterval extents) {
Inkscape::DrawingShape *s = new Inkscape::DrawingShape(drawing);
_display.push_front(View(s, key));
+ _display.front().extents = extents;
_updateView(_display.front());
@@ -185,6 +190,36 @@ void SPHatchPath::setStripExtents(unsigned int key, Geom::OptInterval const &ext
}
}
+Geom::Interval SPHatchPath::bounds() const {
+ Geom::OptRect bbox;
+ Geom::Interval result;
+
+ Geom::Affine transform = Geom::Translate(offset.computed, 0);
+ if (!this->_curve) {
+ SPCurve test_curve;
+ test_curve.moveto(Geom::Point(0, 0));
+ test_curve.moveto(Geom::Point(0, 1));
+ bbox = bounds_exact_transformed(test_curve.get_pathvector(), transform);
+ } else {
+ bbox = bounds_exact_transformed(this->_curve->get_pathvector(), transform);
+ }
+
+ gdouble stroke_width = style->stroke_width.computed;
+ result.setMin(bbox->left() - stroke_width / 2);
+ result.setMax(bbox->right() + stroke_width / 2);
+ return result;
+}
+
+SPCurve *SPHatchPath::calculateRenderCurve(unsigned key) const {
+ for (ConstViewIterator iter = _display.begin(); iter != _display.end(); iter++) {
+ if (iter->key == key) {
+ return _calculateRenderCurve(*iter);
+ }
+ }
+ g_assert_not_reached();
+ return NULL;
+}
+
gdouble SPHatchPath::_repeatLength() const {
if (!_curve) {
return 0;
@@ -198,10 +233,22 @@ gdouble SPHatchPath::_repeatLength() const {
}
void SPHatchPath::_updateView(View &view) {
+ SPCurve *calculated_curve = _calculateRenderCurve(view);
+
+ Geom::Affine offset_transform = Geom::Translate(offset.computed, 0);
+ view.arenaitem->setTransform(offset_transform);
+ style->fill.setNone();
+ view.arenaitem->setStyle(this->style);
+ view.arenaitem->setPath(calculated_curve);
+
+ calculated_curve->unref();
+}
+
+SPCurve *SPHatchPath::_calculateRenderCurve(View const &view) const {
SPCurve *calculated_curve = new SPCurve;
if (!view.extents) {
- return;
+ return calculated_curve;
}
if (!_curve) {
@@ -230,16 +277,10 @@ void SPHatchPath::_updateView(View &view) {
segment->unref();
}
}
-
- Geom::Affine offset_transform = Geom::Translate(offset.computed, 0);
- view.arenaitem->setTransform(offset_transform);
- style->fill.setNone();
- view.arenaitem->setStyle(this->style);
- view.arenaitem->setPath(calculated_curve);
-
- calculated_curve->unref();
+ return calculated_curve;
}
+
void SPHatchPath::_readHatchPathVector(char const *str, Geom::PathVector &pathv, bool &continous_join) {
if (!str) {
return;
diff --git a/src/sp-hatch-path.h b/src/sp-hatch-path.h
index ff091c6f9..57b3a8237 100644
--- a/src/sp-hatch-path.h
+++ b/src/sp-hatch-path.h
@@ -40,10 +40,13 @@ public:
bool isValid() const;
- Inkscape::DrawingItem *show(Inkscape::Drawing &drawing, unsigned int key);
+ Inkscape::DrawingItem *show(Inkscape::Drawing &drawing, unsigned int key, Geom::OptInterval extents);
void hide(unsigned int key);
void setStripExtents(unsigned int key, Geom::OptInterval const &extents);
+ Geom::Interval bounds() const;
+
+ SPCurve *calculateRenderCurve(unsigned key) const;
protected:
virtual void build(SPDocument* doc, Inkscape::XML::Node* repr);
@@ -61,10 +64,12 @@ private:
unsigned int key;
};
typedef std::list<SPHatchPath::View>::iterator ViewIterator;
+ typedef std::list<SPHatchPath::View>::const_iterator ConstViewIterator;
std::list<View> _display;
gdouble _repeatLength() const;
void _updateView(View &view);
+ SPCurve *_calculateRenderCurve(View const &view) const;
void _readHatchPathVector(char const *str, Geom::PathVector &pathv, bool &continous_join);
diff --git a/src/sp-hatch.cpp b/src/sp-hatch.cpp
index cde6c86cb..98cc596d7 100644
--- a/src/sp-hatch.cpp
+++ b/src/sp-hatch.cpp
@@ -77,6 +77,7 @@ void SPHatch::build(SPDocument* doc, Inkscape::XML::Node* repr) {
this->readAttr("pitch");
this->readAttr("rotate");
this->readAttr("xlink:href");
+ this->readAttr( "style" );
/* Register ourselves */
doc->addResource("hatch", this);
@@ -89,7 +90,7 @@ void SPHatch::release() {
}
std::vector<SPHatchPath *> children;
- _children(children);
+ hatchPaths(children);
for (ViewIterator view_iter = _display.begin(); view_iter != _display.end(); view_iter++) {
for (ChildIterator child_iter = children.begin(); child_iter != children.end();
child_iter++) {
@@ -117,10 +118,9 @@ void SPHatch::child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref)
if (path_child) {
for (ViewIterator iter = _display.begin(); iter != _display.end(); iter++) {
- Inkscape::DrawingItem *ac = path_child->show(iter->arenaitem->drawing(), iter->key);
+ Geom::OptInterval extents = _calculateStripExtents(iter->bbox);
+ Inkscape::DrawingItem *ac = path_child->show(iter->arenaitem->drawing(), iter->key, extents);
- Geom::OptInterval strip_extents = _calculateStripExtents(iter->bbox);
- path_child->setStripExtents(iter->key, strip_extents);
path_child->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
if (ac) {
iter->arenaitem->prependChild(ac);
@@ -224,7 +224,12 @@ void SPHatch::set(unsigned int key, const gchar* value) {
break;
default:
- SPPaintServer::set(key, value);
+ if (SP_ATTRIBUTE_IS_CSS(key)) {
+ sp_style_read_from_object(this->style, this);
+ requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
+ } else {
+ SPPaintServer::set(key, value);
+ }
break;
}
}
@@ -238,7 +243,7 @@ bool SPHatch::_hasHatchPatchChildren(SPHatch const *hatch) {
return false;
}
-void SPHatch::_children(std::vector<SPHatchPath*>& l) {
+void SPHatch::hatchPaths(std::vector<SPHatchPath*>& l) {
SPHatch *src = chase_hrefs<SPHatch>(this, sigc::ptr_fun(&_hasHatchPatchChildren));
if (src) {
@@ -250,7 +255,7 @@ void SPHatch::_children(std::vector<SPHatchPath*>& l) {
}
}
-void SPHatch::_children(std::vector<SPHatchPath const*>& l) const {
+void SPHatch::hatchPaths(std::vector<SPHatchPath const*>& l) const {
SPHatch const *src = chase_hrefs<SPHatch const>(this, sigc::ptr_fun(&_hasHatchPatchChildren));
if (src) {
@@ -275,7 +280,7 @@ void SPHatch::update(SPCtx* ctx, unsigned int flags) {
flags &= SP_OBJECT_MODIFIED_CASCADE;
std::vector<SPHatchPath *> children;
- _children(children);
+ hatchPaths(children);
for (ChildIterator iter = children.begin(); iter != children.end(); iter++) {
SPHatchPath* child = *iter;
@@ -308,7 +313,7 @@ void SPHatch::modified(unsigned int flags) {
flags &= SP_OBJECT_MODIFIED_CASCADE;
std::vector<SPHatchPath *> children;
- _children(children);
+ hatchPaths(children);
for (ChildIterator iter = children.begin(); iter != children.end(); iter++) {
SPObject *child = *iter;
@@ -337,29 +342,28 @@ void SPHatch::_onRefChanged(SPObject *old_ref, SPObject *ref) {
if (!_hasHatchPatchChildren(this)) {
SPHatch *old_shown = NULL;
SPHatch *new_shown = NULL;
- std::vector<SPHatchPath *> old_children;
- std::vector<SPHatchPath *> new_children;
+ std::vector<SPHatchPath *> oldhatchPaths;
+ std::vector<SPHatchPath *> newhatchPaths;
if (SP_IS_HATCH(old_ref)) {
old_shown = SP_HATCH(old_ref)->rootHatch();
- old_shown->_children(old_children);
+ old_shown->hatchPaths(oldhatchPaths);
}
if (SP_IS_HATCH(ref)) {
new_shown = SP_HATCH(ref)->rootHatch();
- new_shown->_children(new_children);
+ new_shown->hatchPaths(newhatchPaths);
}
if (old_shown != new_shown) {
for (ViewIterator iter = _display.begin(); iter != _display.end(); iter++) {
Geom::OptInterval extents = _calculateStripExtents(iter->bbox);
- for (ChildIterator child_iter = old_children.begin(); child_iter != old_children.end(); child_iter++) {
+ for (ChildIterator child_iter = oldhatchPaths.begin(); child_iter != oldhatchPaths.end(); child_iter++) {
SPHatchPath *child = *child_iter;
child->hide(iter->key);
}
- for (ChildIterator child_iter = new_children.begin(); child_iter != new_children.end(); child_iter++) {
+ for (ChildIterator child_iter = newhatchPaths.begin(); child_iter != newhatchPaths.end(); child_iter++) {
SPHatchPath *child = *child_iter;
- Inkscape::DrawingItem *cai = child->show(iter->arenaitem->drawing(), iter->key);
- child->setStripExtents(iter->key, extents);
+ Inkscape::DrawingItem *cai = child->show(iter->arenaitem->drawing(), iter->key, extents);
child->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
if (cai) {
iter->arenaitem->appendChild(cai);
@@ -457,7 +461,7 @@ bool SPHatch::isValid() const {
}
std::vector<SPHatchPath const *> children;
- _children(children);
+ hatchPaths(children);
if (children.empty()) {
return false;
}
@@ -471,17 +475,19 @@ bool SPHatch::isValid() const {
return true;
}
-Inkscape::DrawingPattern *SPHatch::show(Inkscape::Drawing &drawing, unsigned int key) {
+Inkscape::DrawingPattern *SPHatch::show(Inkscape::Drawing &drawing, unsigned int key, Geom::OptRect bbox) {
Inkscape::DrawingPattern *ai = new Inkscape::DrawingPattern(drawing);
//TODO: set some debug flag to see DrawingPattern
_display.push_front(View(ai, key));
+ _display.front().bbox = bbox;
std::vector<SPHatchPath *> children;
- _children(children);
+ hatchPaths(children);
+ Geom::OptInterval extents = _calculateStripExtents(bbox);
for (ChildIterator iter = children.begin(); iter != children.end(); iter++) {
SPHatchPath *child = *iter;
- Inkscape::DrawingItem *cai = child->show(drawing, key);
+ Inkscape::DrawingItem *cai = child->show(drawing, key, extents);
if (cai) {
ai->appendChild(cai);
}
@@ -495,7 +501,7 @@ Inkscape::DrawingPattern *SPHatch::show(Inkscape::Drawing &drawing, unsigned int
void SPHatch::hide(unsigned int key) {
std::vector<SPHatchPath *> children;
- _children(children);
+ hatchPaths(children);
for (ChildIterator iter = children.begin(); iter != children.end(); iter++) {
SPHatchPath *child = *iter;
@@ -513,10 +519,56 @@ void SPHatch::hide(unsigned int key) {
g_assert_not_reached();
}
+
+Geom::Interval SPHatch::bounds() const {
+ Geom::Interval result;
+ std::vector<SPHatchPath const *> children;
+ hatchPaths(children);
+
+ for (ConstChildIterator iter = children.begin(); iter != children.end(); iter++) {
+ SPHatchPath const *child = *iter;
+ if (result.extent() == 0) {
+ result = child->bounds();
+ } else {
+ result |= child->bounds();
+ }
+ }
+ return result;
+}
+
+SPHatch::RenderInfo SPHatch::calculateRenderInfo(unsigned key) const {
+ RenderInfo info;
+ for (ConstViewIterator iter = _display.begin(); iter != _display.end(); iter++) {
+ if (iter->key == key) {
+ return _calculateRenderInfo(*iter);
+ }
+ }
+ g_assert_not_reached();
+ return info;
+}
+
void SPHatch::_updateView(View &view) {
+ RenderInfo info = _calculateRenderInfo(view);
+ //The rendering of hatch overflow is implemented by repeated drawing
+ //of hatch paths over one strip. Within each iteration paths are moved by pitch value.
+ //The movement progresses from right to left. This gives the same result
+ //as drawing whole strips in left-to-right order.
+
+
+ view.arenaitem->setChildTransform(info.child_transform);
+ view.arenaitem->setPatternToUserTransform(info.pattern_to_user_transform);
+ view.arenaitem->setTileRect(info.tile_rect);
+ view.arenaitem->setStyle(this->style);
+ view.arenaitem->setOverflow(info.overflow_initial_transform, info.overflow_steps,
+ info.overflow_step_transform);
+}
+
+SPHatch::RenderInfo SPHatch::_calculateRenderInfo(View const &view) const {
+ RenderInfo info;
+
Geom::OptInterval extents = _calculateStripExtents(view.bbox);
if (!extents) {
- return;
+ return info;
}
double tile_x = x();
@@ -545,14 +597,26 @@ void SPHatch::_updateView(View &view) {
// Tile (hatch space) to user.
Geom::Affine ps2user = Geom::Translate(tile_x, tile_y) * Geom::Rotate::from_degrees(tile_rotate) * hatchTransform();
- view.arenaitem->setChildTransform(content2ps);
- view.arenaitem->setPatternToUserTransform(ps2user);
- view.arenaitem->setTileRect(hatch_tile);
- view.arenaitem->setStyle(this->style);
+ info.child_transform = content2ps;
+ info.pattern_to_user_transform = ps2user;
+ info.tile_rect = hatch_tile;
+
+ if (style->overflow.computed == SP_CSS_OVERFLOW_VISIBLE) {
+ Geom::Interval bounds = this->bounds();
+ gdouble pitch = this->pitch();
+ gdouble overflow_right_strip = floor(bounds.max() / pitch) * pitch;
+ info.overflow_steps = ceil((overflow_right_strip - bounds.min()) / pitch) + 1;
+ info.overflow_step_transform = Geom::Translate(pitch, 0.0);
+ info.overflow_initial_transform = Geom::Translate(-overflow_right_strip, 0.0);
+ } else {
+ info.overflow_steps = 1;
+ }
+
+ return info;
}
//calculates strip extents in content space
-Geom::OptInterval SPHatch::_calculateStripExtents(Geom::OptRect bbox) {
+Geom::OptInterval SPHatch::_calculateStripExtents(Geom::OptRect bbox) const {
if (!bbox || (bbox->area() == 0)) {
return Geom::OptInterval();
}
@@ -590,9 +654,7 @@ cairo_pattern_t* SPHatch::pattern_new(cairo_t *base_ct, Geom::OptRect const &bbo
}
void SPHatch::setBBox(unsigned int key, Geom::OptRect const &bbox) {
- typedef std::list<View>::iterator ViewIter;
-
- for (ViewIter iter = _display.begin(); iter != _display.end(); iter++) {
+ for (ViewIterator iter = _display.begin(); iter != _display.end(); iter++) {
if (iter->key == key) {
iter->bbox = bbox;
break;
diff --git a/src/sp-hatch.h b/src/sp-hatch.h
index 170f68a7a..dc6ee0add 100644
--- a/src/sp-hatch.h
+++ b/src/sp-hatch.h
@@ -48,6 +48,16 @@ public:
UNITS_OBJECTBOUNDINGBOX
};
+ struct RenderInfo {
+ Geom::Affine child_transform;
+ Geom::Affine pattern_to_user_transform;
+ Geom::Rect tile_rect;
+
+ int overflow_steps;
+ Geom::Affine overflow_step_transform;
+ Geom::Affine overflow_initial_transform;
+ };
+
SPHatch();
virtual ~SPHatch();
@@ -64,12 +74,17 @@ public:
Geom::Affine const &hatchTransform() const;
SPHatch *rootHatch(); //TODO: const
+ void hatchPaths(std::vector<SPHatchPath*>& l);
+ void hatchPaths(std::vector<SPHatchPath const *>& l) const;
+
bool isValid() const;
- Inkscape::DrawingPattern *show(Inkscape::Drawing &drawing, unsigned int key);
+ Inkscape::DrawingPattern *show(Inkscape::Drawing &drawing, unsigned int key, Geom::OptRect bbox);
void hide(unsigned int key);
virtual cairo_pattern_t* pattern_new(cairo_t *ct, Geom::OptRect const &bbox, double opacity);
+ RenderInfo calculateRenderInfo(unsigned key) const;
+ Geom::Interval bounds() const;
void setBBox(unsigned int key, Geom::OptRect const &bbox);
protected:
@@ -89,17 +104,18 @@ private:
Geom::OptRect bbox;
unsigned int key;
};
+
typedef std::vector<SPHatchPath *>::iterator ChildIterator;
typedef std::vector<SPHatchPath const *>::const_iterator ConstChildIterator;
typedef std::list<View>::iterator ViewIterator;
- void _updateView(View &view);
+ typedef std::list<View>::const_iterator ConstViewIterator;
static bool _hasHatchPatchChildren(SPHatch const* hatch);
- void _children(std::vector<SPHatchPath*>& l);
- void _children(std::vector<SPHatchPath const *>& l) const;
+ void _updateView(View &view);
+ RenderInfo _calculateRenderInfo(View const &view) const;
+ Geom::OptInterval _calculateStripExtents(Geom::OptRect bbox) const;
- Geom::OptInterval _calculateStripExtents(Geom::OptRect bbox);
/**
Gets called when the hatch is reattached to another <hatch>
diff --git a/src/sp-item.cpp b/src/sp-item.cpp
index da6e6ea58..f6de165a6 100644
--- a/src/sp-item.cpp
+++ b/src/sp-item.cpp
@@ -615,9 +615,8 @@ void SPItem::fill_ps_ref_changed(SPObject *old_ps, SPObject *ps, SPItem *item) {
v->arenaitem->setKey(SPItem::display_key_new(3));
}
Inkscape::DrawingPattern *pi = new_fill_ps->show(
- v->arenaitem->drawing(), v->arenaitem->key());
+ v->arenaitem->drawing(), v->arenaitem->key(), bbox);
v->arenaitem->setFillPattern(pi);
- new_fill_ps->setBBox(v->arenaitem->key(), bbox);
if (pi) {
new_fill_ps->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
}
@@ -625,8 +624,29 @@ void SPItem::fill_ps_ref_changed(SPObject *old_ps, SPObject *ps, SPItem *item) {
}
}
-void SPItem::stroke_ps_ref_changed(SPObject *old_clip, SPObject *clip, SPItem *item) {
+void SPItem::stroke_ps_ref_changed(SPObject *old_ps, SPObject *ps, SPItem *item) {
+ SPPaintServer *old_stroke_ps = SP_PAINT_SERVER(old_ps);
+ if (old_stroke_ps) {
+ for (SPItemView *v =item->display; v != NULL; v = v->next) {
+ old_stroke_ps->hide(v->arenaitem->key());
+ }
+ }
+ SPPaintServer *new_stroke_ps = SP_PAINT_SERVER(ps);
+ if (new_stroke_ps) {
+ Geom::OptRect bbox = item->geometricBounds();
+ for (SPItemView *v = item->display; v != NULL; v = v->next) {
+ if (!v->arenaitem->key()) {
+ v->arenaitem->setKey(SPItem::display_key_new(3));
+ }
+ Inkscape::DrawingPattern *pi = new_stroke_ps->show(
+ v->arenaitem->drawing(), v->arenaitem->key(), bbox);
+ v->arenaitem->setStrokePattern(pi);
+ if (pi) {
+ new_stroke_ps->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ }
+ }
+ }
}
void SPItem::update(SPCtx* /*ctx*/, guint flags) {
@@ -1142,9 +1162,8 @@ Inkscape::DrawingItem *SPItem::invoke_show(Inkscape::Drawing &drawing, unsigned
}
int fill_key = display->arenaitem->key();
- Inkscape::DrawingPattern *ap = fill_ps->show(drawing, fill_key);
+ Inkscape::DrawingPattern *ap = fill_ps->show(drawing, fill_key, item_bbox);
ai->setFillPattern(ap);
- fill_ps->setBBox(fill_key, item_bbox);
if (ap) {
fill_ps->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
}
@@ -1156,9 +1175,8 @@ Inkscape::DrawingItem *SPItem::invoke_show(Inkscape::Drawing &drawing, unsigned
}
int stroke_key = display->arenaitem->key();
- Inkscape::DrawingPattern *ap = stroke_ps->show(drawing, stroke_key);
+ Inkscape::DrawingPattern *ap = stroke_ps->show(drawing, stroke_key, item_bbox);
ai->setStrokePattern(ap);
- stroke_ps->setBBox(stroke_key, item_bbox);
if (ap) {
stroke_ps->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
}
diff --git a/src/sp-paint-server.h b/src/sp-paint-server.h
index 91d292424..6c88199b9 100644
--- a/src/sp-paint-server.h
+++ b/src/sp-paint-server.h
@@ -43,7 +43,7 @@ public:
//on demand by pattern_new method. It is used for gradients. The other one is to add elements
//representing PaintServer in NR tree. It is used by hatches and patterns.
//Either pattern new or all three methods show, hide, setBBox need to be implemented
- virtual Inkscape::DrawingPattern *show(Inkscape::Drawing &drawing, unsigned int key) {return NULL;}
+ virtual Inkscape::DrawingPattern *show(Inkscape::Drawing &drawing, unsigned int key, Geom::OptRect bbox) {return NULL;}
virtual void hide(unsigned int key) {};
virtual void setBBox(unsigned int key, Geom::OptRect const &bbox) {};