summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLiam P. White <inkscapebrony@gmail.com>2014-10-18 21:44:39 +0000
committerLiam P. White <inkscapebrony@gmail.com>2014-10-18 21:44:39 +0000
commit68136c8b24a6995976db963a790207858e9baba5 (patch)
tree550e81af7c8d626ec80a2be5efec66dd10d84bc4 /src
parentUpdate to experimental r13598 (diff)
parentUpdate to trunk r13621 (diff)
downloadinkscape-68136c8b24a6995976db963a790207858e9baba5.tar.gz
inkscape-68136c8b24a6995976db963a790207858e9baba5.zip
Update to experimental r13619
(bzr r13341.5.18)
Diffstat (limited to 'src')
-rw-r--r--src/2geom/math-utils.h4
-rw-r--r--src/2geom/numeric/symmetric-matrix-fs-operation.h2
-rw-r--r--src/2geom/numeric/symmetric-matrix-fs-trace.h2
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/Makefile_insert2
-rw-r--r--src/attributes.cpp5
-rw-r--r--src/attributes.h5
-rw-r--r--src/box3d-side.h4
-rw-r--r--src/box3d.cpp23
-rw-r--r--src/desktop-style.cpp6
-rw-r--r--src/display/CMakeLists.txt2
-rw-r--r--src/display/Makefile_insert2
-rw-r--r--src/display/drawing-item.cpp47
-rw-r--r--src/display/drawing-item.h9
-rw-r--r--src/display/drawing-pattern.cpp194
-rw-r--r--src/display/drawing-pattern.h87
-rw-r--r--src/display/drawing-shape.cpp8
-rw-r--r--src/display/drawing-text.cpp8
-rw-r--r--src/display/nr-style.cpp60
-rw-r--r--src/display/nr-style.h9
-rw-r--r--src/document.cpp33
-rw-r--r--src/extension/implementation/script.cpp100
-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/extension/internal/cdr-input.cpp36
-rw-r--r--src/extension/internal/pdfinput/pdf-input.cpp24
-rw-r--r--src/extension/internal/pdfinput/pdf-parser.cpp182
-rw-r--r--src/extension/internal/pdfinput/pdf-parser.h30
-rw-r--r--src/extension/internal/vsd-input.cpp37
-rw-r--r--src/extension/internal/wpg-input.cpp57
-rw-r--r--src/extension/param/color.cpp12
-rw-r--r--src/extension/param/enum.cpp55
-rw-r--r--src/filters/blend.cpp26
-rw-r--r--src/filters/composite.cpp26
-rw-r--r--src/filters/displacementmap.cpp25
-rw-r--r--src/libnrtype/FontFactory.h2
-rw-r--r--src/live_effects/CMakeLists.txt5
-rw-r--r--src/live_effects/Makefile_insert6
-rw-r--r--src/live_effects/effect-enum.h2
-rw-r--r--src/live_effects/effect.cpp8
-rw-r--r--src/live_effects/lpe-bspline.cpp126
-rw-r--r--src/live_effects/lpe-bspline.h18
-rw-r--r--src/live_effects/lpe-perspective-envelope.cpp (renamed from src/live_effects/lpe-envelope-perspective.cpp)132
-rw-r--r--src/live_effects/lpe-perspective-envelope.h (renamed from src/live_effects/lpe-envelope-perspective.h)26
-rw-r--r--src/live_effects/lpe-vonkoch.cpp6
-rw-r--r--src/object-snapper.cpp5
-rw-r--r--src/path-chemistry.cpp1
-rw-r--r--src/path-prefix.h34
-rw-r--r--src/sp-hatch-path.cpp331
-rw-r--r--src/sp-hatch-path.h91
-rw-r--r--src/sp-hatch.cpp679
-rw-r--r--src/sp-hatch.h174
-rw-r--r--src/sp-item.cpp100
-rw-r--r--src/sp-item.h4
-rw-r--r--src/sp-lpe-item.cpp3
-rw-r--r--src/sp-paint-server.cpp20
-rw-r--r--src/sp-paint-server.h59
-rw-r--r--src/style-internal.cpp32
-rw-r--r--src/style-internal.h653
-rw-r--r--src/style.cpp14
-rw-r--r--src/style.h16
-rw-r--r--src/svg/CMakeLists.txt2
-rw-r--r--src/svg/Makefile_insert2
-rw-r--r--src/svg/svg-angle.cpp136
-rw-r--r--src/svg/svg-angle.h69
-rw-r--r--src/svg/svg-color.cpp4
-rw-r--r--src/ui/dialog/clonetiler.cpp7
-rw-r--r--src/ui/dialog/symbols.cpp26
-rw-r--r--src/ui/dialog/template-widget.cpp6
-rw-r--r--src/ui/widget/highlight-picker.cpp9
-rw-r--r--src/ui/widget/insertordericon.cpp8
-rw-r--r--src/ui/widget/insertordericon.h4
-rw-r--r--src/ui/widget/selected-style.cpp4
-rw-r--r--src/viewbox.cpp21
-rw-r--r--src/widgets/ink-comboboxentry-action.cpp2
-rw-r--r--src/widgets/stroke-style.cpp6
-rw-r--r--src/xml/node-event-vector.h6
-rw-r--r--src/xml/repr-io.cpp1
80 files changed, 3384 insertions, 737 deletions
diff --git a/src/2geom/math-utils.h b/src/2geom/math-utils.h
index 83c7b4f5e..0d5d3667b 100644
--- a/src/2geom/math-utils.h
+++ b/src/2geom/math-utils.h
@@ -111,7 +111,7 @@ inline void sincos(double angle, double &sin_, double &cos_) {
# define IS_NAN(_a) (_isnan(_a)) /* Win32 definition */
#elif defined(isnan) || defined(__FreeBSD__) || defined(__osf__)
# define IS_NAN(_a) (isnan(_a)) /* GNU definition */
-#elif defined (SOLARIS_2_8) && __GNUC__ == 3 && __GNUC_MINOR__ == 2
+#elif defined (SOLARIS)
# define IS_NAN(_a) (isnan(_a)) /* GNU definition */
#else
# define IS_NAN(_a) (boost::math::isnan(_a))
@@ -129,7 +129,7 @@ inline void sincos(double angle, double &sin_, double &cos_) {
# define IS_FINITE(_a) (isfinite(_a))
#elif defined(__osf__)
# define IS_FINITE(_a) (finite(_a) && !IS_NAN(_a))
-#elif defined (SOLARIS_2_8) && __GNUC__ == 3 && __GNUC_MINOR__ == 2
+#elif defined (SOLARIS)
#include <ieeefp.h>
#define IS_FINITE(_a) (finite(_a) && !IS_NAN(_a))
#else
diff --git a/src/2geom/numeric/symmetric-matrix-fs-operation.h b/src/2geom/numeric/symmetric-matrix-fs-operation.h
index 5222d2734..37ece56ae 100644
--- a/src/2geom/numeric/symmetric-matrix-fs-operation.h
+++ b/src/2geom/numeric/symmetric-matrix-fs-operation.h
@@ -44,7 +44,7 @@ namespace Geom { namespace NL {
template <size_t N>
inline
-SymmetricMatrix<N> adj(const ConstBaseSymmetricMatrix<N> & S)
+SymmetricMatrix<N> adj(const ConstBaseSymmetricMatrix<N> & /*S*/)
{
THROW_NOTIMPLEMENTED();
return SymmetricMatrix<N>();
diff --git a/src/2geom/numeric/symmetric-matrix-fs-trace.h b/src/2geom/numeric/symmetric-matrix-fs-trace.h
index 099c834a8..dbabecf6e 100644
--- a/src/2geom/numeric/symmetric-matrix-fs-trace.h
+++ b/src/2geom/numeric/symmetric-matrix-fs-trace.h
@@ -74,7 +74,7 @@ template <size_t K, size_t N>
struct trace
{
static
- double evaluate (const ConstBaseSymmetricMatrix<N> & S)
+ double evaluate (const ConstBaseSymmetricMatrix<N> & /*S*/)
{
THROW_NOTIMPLEMENTED();
return K;
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 008a888e0..f0bacff16 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -32,6 +32,8 @@ set(sp_SRC
sp-gradient-reference.cpp
sp-gradient.cpp
sp-guide.cpp
+ sp-hatch.cpp
+ sp-hatch-path.cpp
sp-image.cpp
sp-item-group.cpp
sp-item-notify-moveto.cpp
@@ -116,6 +118,8 @@ set(sp_SRC
sp-guide-attachment.h
sp-guide-constraint.h
sp-guide.h
+ sp-hatch.h
+ sp-hatch-path.h
sp-image.h
sp-item-group.h
sp-item-notify-moveto.h
diff --git a/src/Makefile_insert b/src/Makefile_insert
index 541bd20ca..acf317c47 100644
--- a/src/Makefile_insert
+++ b/src/Makefile_insert
@@ -145,6 +145,8 @@ ink_common_sources += \
sp-guide-attachment.h \
sp-guide-constraint.h \
sp-guide.cpp sp-guide.h \
+ sp-hatch.cpp sp-hatch.h \
+ sp-hatch-path.cpp sp-hatch-path.h \
sp-image.cpp sp-image.h \
sp-item.cpp sp-item.h \
sp-item-group.cpp sp-item-group.h \
diff --git a/src/attributes.cpp b/src/attributes.cpp
index 87bfdbe88..d142d1a06 100644
--- a/src/attributes.cpp
+++ b/src/attributes.cpp
@@ -293,6 +293,11 @@ static SPStyleProp const props[] = {
{SP_ATTR_PATTERNUNITS, "patternUnits"},
{SP_ATTR_PATTERNCONTENTUNITS, "patternContentUnits"},
{SP_ATTR_PATTERNTRANSFORM, "patternTransform"},
+ /* SPHatch */
+ {SP_ATTR_HATCHUNITS, "hatchUnits"},
+ {SP_ATTR_HATCHCONTENTUNITS, "hatchContentUnits"},
+ {SP_ATTR_HATCHTRANSFORM, "hatchTransform"},
+ {SP_ATTR_PITCH, "pitch"},
/* SPClipPath */
{SP_ATTR_CLIPPATHUNITS, "clipPathUnits"},
/* SPMask */
diff --git a/src/attributes.h b/src/attributes.h
index 598d68fa3..8e091df71 100644
--- a/src/attributes.h
+++ b/src/attributes.h
@@ -295,6 +295,11 @@ enum SPAttributeEnum {
SP_ATTR_PATTERNUNITS,
SP_ATTR_PATTERNCONTENTUNITS,
SP_ATTR_PATTERNTRANSFORM,
+ /* SPHatch */
+ SP_ATTR_HATCHUNITS,
+ SP_ATTR_HATCHCONTENTUNITS,
+ SP_ATTR_HATCHTRANSFORM,
+ SP_ATTR_PITCH,
/* SPClipPath */
SP_ATTR_CLIPPATHUNITS,
/* SPMask */
diff --git a/src/box3d-side.h b/src/box3d-side.h
index 89b3b0399..4783a5f24 100644
--- a/src/box3d-side.h
+++ b/src/box3d-side.h
@@ -7,6 +7,7 @@
* Authors:
* Maximilian Albert <Anhalter42@gmx.de>
* Abhishek Sharma
+ * Jon A. Cruz <jon@joncruz.org>
*
* Copyright (C) 2007 Authors
*
@@ -17,9 +18,6 @@
#include "axis-manip.h"
-#define SP_BOX3D_SIDE(obj) (dynamic_cast<Box3DSide*>((SPObject*)obj))
-#define SP_IS_BOX3D_SIDE(obj) (dynamic_cast<const Box3DSide*>((SPObject*)obj) != NULL)
-
class SPBox3D;
class Persp3D;
diff --git a/src/box3d.cpp b/src/box3d.cpp
index 5598bc83d..f872081b8 100644
--- a/src/box3d.cpp
+++ b/src/box3d.cpp
@@ -6,6 +6,7 @@
* Lauris Kaplinski <lauris@kaplinski.com>
* bulia byak <buliabyak@users.sf.net>
* Abhishek Sharma
+ * Jon A. Cruz <jon@joncruz.org>
*
* Copyright (C) 2007 Authors
* Copyright (C) 1999-2002 Lauris Kaplinski
@@ -263,9 +264,10 @@ void box3d_position_set(SPBox3D *box)
{
/* This draws the curve and calls requestDisplayUpdate() for each side (the latter is done in
box3d_side_position_set() to avoid update conflicts with the parent box) */
- for ( SPObject *child = box->firstChild(); child; child = child->getNext() ) {
- if (SP_IS_BOX3D_SIDE(child)) {
- box3d_side_position_set(SP_BOX3D_SIDE(child));
+ for ( SPObject *obj = box->firstChild(); obj; obj = obj->getNext() ) {
+ Box3DSide *side = dynamic_cast<Box3DSide *>(obj);
+ if (side) {
+ box3d_side_position_set(side);
}
}
}
@@ -1079,10 +1081,10 @@ box3d_recompute_z_orders (SPBox3D *box) {
static std::map<int, Box3DSide *> box3d_get_sides(SPBox3D *box)
{
std::map<int, Box3DSide *> sides;
- for ( SPObject *side = box->firstChild(); side; side = side->getNext() ) {
- if (SP_IS_BOX3D_SIDE(side)){
- Box3DSide *bside = SP_BOX3D_SIDE(side);
- sides[Box3D::face_to_int(bside->getFaceId())] = bside;
+ for ( SPObject *obj = box->firstChild(); obj; obj = obj->getNext() ) {
+ Box3DSide *side = dynamic_cast<Box3DSide *>(obj);
+ if (side) {
+ sides[Box3D::face_to_int(side->getFaceId())] = side;
}
}
sides.erase(-1);
@@ -1280,9 +1282,10 @@ SPGroup *box3d_convert_to_group(SPBox3D *box)
// create a new group and add the sides (converted to ordinary paths) as its children
Inkscape::XML::Node *grepr = xml_doc->createElement("svg:g");
- for ( SPObject *child = box->firstChild(); child; child = child->getNext() ) {
- if (SP_IS_BOX3D_SIDE(child)) {
- Inkscape::XML::Node *repr = box3d_side_convert_to_path(SP_BOX3D_SIDE(child));
+ for ( SPObject *obj = box->firstChild(); obj; obj = obj->getNext() ) {
+ Box3DSide *side = dynamic_cast<Box3DSide *>(obj);
+ if (side) {
+ Inkscape::XML::Node *repr = box3d_side_convert_to_path(side);
grepr->appendChild(repr);
} else {
g_warning("Non-side item encountered as child of a 3D box.");
diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp
index ce8a06f29..15dc339cf 100644
--- a/src/desktop-style.cpp
+++ b/src/desktop-style.cpp
@@ -174,8 +174,10 @@ sp_desktop_set_style(SPDesktop *desktop, SPCSSAttr *css, bool change, bool write
for (const GSList *i = desktop->selection->itemList(); i != NULL; i = i->next) {
/* last used styles for 3D box faces are stored separately */
- if (SP_IS_BOX3D_SIDE (i->data)) {
- const char * descr = box3d_side_axes_string(SP_BOX3D_SIDE(i->data));
+ SPObject *obj = reinterpret_cast<SPObject *>(i->data); // TODO unsafe until Selection is refactored.
+ Box3DSide *side = dynamic_cast<Box3DSide *>(obj);
+ if (side) {
+ const char * descr = box3d_side_axes_string(side);
if (descr != NULL) {
prefs->mergeStyle(Glib::ustring("/desktop/") + descr + "/style", css_write);
}
diff --git a/src/display/CMakeLists.txt b/src/display/CMakeLists.txt
index 20424c845..800c4d0d4 100644
--- a/src/display/CMakeLists.txt
+++ b/src/display/CMakeLists.txt
@@ -13,6 +13,7 @@ set(display_SRC
drawing-group.cpp
drawing-image.cpp
drawing-item.cpp
+ drawing-pattern.cpp
drawing-shape.cpp
drawing-surface.cpp
drawing-text.cpp
@@ -75,6 +76,7 @@ set(display_SRC
drawing-group.h
drawing-image.h
drawing-item.h
+ drawing-pattern.h
drawing-shape.h
drawing-surface.h
drawing-text.h
diff --git a/src/display/Makefile_insert b/src/display/Makefile_insert
index abbd89a68..2355c3653 100644
--- a/src/display/Makefile_insert
+++ b/src/display/Makefile_insert
@@ -33,6 +33,8 @@ ink_common_sources += \
display/drawing-image.h \
display/drawing-item.cpp \
display/drawing-item.h \
+ display/drawing-pattern.cpp \
+ display/drawing-pattern.h \
display/drawing-shape.cpp \
display/drawing-shape.h \
display/drawing-surface.cpp \
diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp
index 56507bacb..9bb81cea5 100644
--- a/src/display/drawing-item.cpp
+++ b/src/display/drawing-item.cpp
@@ -15,6 +15,7 @@
#include "display/drawing-context.h"
#include "display/drawing-item.h"
#include "display/drawing-group.h"
+#include "display/drawing-pattern.h"
#include "display/drawing-surface.h"
#include "nr-filter.h"
#include "preferences.h"
@@ -112,6 +113,8 @@ DrawingItem::DrawingItem(Drawing &drawing)
, _transform(NULL)
, _clip(NULL)
, _mask(NULL)
+ , _fill_pattern(NULL)
+ , _stroke_pattern(NULL)
, _filter(NULL)
, _user_data(NULL)
, _cache(NULL)
@@ -166,6 +169,12 @@ DrawingItem::~DrawingItem()
case CHILD_ROOT:
_drawing._root = NULL;
break;
+ case CHILD_FILL_PATTERN:
+ _parent->_fill_pattern = NULL;
+ break;
+ case CHILD_STROKE_PATTERN:
+ _parent->_stroke_pattern = NULL;
+ break;
default: ;
}
@@ -174,6 +183,8 @@ DrawingItem::~DrawingItem()
}
clearChildren();
delete _transform;
+ delete _stroke_pattern;
+ delete _fill_pattern;
delete _clip;
delete _mask;
delete _filter;
@@ -368,6 +379,34 @@ DrawingItem::setMask(DrawingItem *item)
_markForUpdate(STATE_ALL, true);
}
+void
+DrawingItem::setFillPattern(DrawingPattern *pattern)
+{
+ _markForRendering();
+ delete _fill_pattern;
+ _fill_pattern = pattern;
+ if (pattern) {
+ pattern->_parent = this;
+ assert(pattern->_child_type == CHILD_ORPHAN);
+ pattern->_child_type = CHILD_FILL_PATTERN;
+ }
+ _markForUpdate(STATE_ALL, true);
+}
+
+void
+DrawingItem::setStrokePattern(DrawingPattern *pattern)
+{
+ _markForRendering();
+ delete _stroke_pattern;
+ _stroke_pattern = pattern;
+ if (pattern) {
+ pattern->_parent = this;
+ assert(pattern->_child_type == CHILD_ORPHAN);
+ pattern->_child_type = CHILD_STROKE_PATTERN;
+ }
+ _markForUpdate(STATE_ALL, true);
+}
+
/// Move this item to the given place in the Z order of siblings.
/// Does nothing if the item has no parent.
void
@@ -532,6 +571,12 @@ DrawingItem::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigne
if (to_update & STATE_RENDER) {
// now that we know drawbox, dirty the corresponding rect on canvas
// unless filtered, groups do not need to render by themselves, only their members
+ if (_fill_pattern) {
+ _fill_pattern->update(area, child_ctx, flags, reset);
+ }
+ if (_stroke_pattern) {
+ _stroke_pattern->update(area, child_ctx, flags, reset);
+ }
if (!is_drawing_group(this) || (_filter && render_filters)) {
_markForRendering();
}
@@ -970,7 +1015,7 @@ DrawingItem::_setStyleCommon(SPStyle *&_style, SPStyle *style)
if (_style) sp_style_unref(_style);
_style = style;
- if (style->filter.set && style->getFilter()) {
+ if (style && style->filter.set && style->getFilter()) {
if (!_filter) {
int primitives = sp_filter_primitive_count(SP_FILTER(style->getFilter()));
_filter = new Inkscape::Filters::Filter(primitives);
diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h
index dda5cd6ac..9b399e6e3 100644
--- a/src/display/drawing-item.h
+++ b/src/display/drawing-item.h
@@ -28,6 +28,7 @@ class Drawing;
class DrawingCache;
class DrawingContext;
class DrawingItem;
+class DrawingPattern;
namespace Filters {
@@ -114,6 +115,8 @@ public:
void setTransform(Geom::Affine const &trans);
void setClip(DrawingItem *item);
void setMask(DrawingItem *item);
+ void setFillPattern(DrawingPattern *pattern);
+ void setStrokePattern(DrawingPattern *pattern);
void setZOrder(unsigned z);
void setItemBounds(Geom::OptRect const &bounds);
void setFilterBounds(Geom::OptRect const &bounds);
@@ -135,8 +138,8 @@ protected:
CHILD_CLIP = 2, // referenced by _clip member of parent
CHILD_MASK = 3, // referenced by _mask member of parent
CHILD_ROOT = 4, // root item of _drawing
- CHILD_FILL_PATTERN = 5, // not yet implemented: referenced by fill pattern of parent
- CHILD_STROKE_PATTERN = 6 // not yet implemented: referenced by stroke pattern of parent
+ CHILD_FILL_PATTERN = 5, // referenced by fill pattern of parent
+ CHILD_STROKE_PATTERN = 6 // referenced by stroke pattern of parent
};
enum RenderResult {
RENDER_OK = 0,
@@ -185,6 +188,8 @@ protected:
DrawingItem *_clip;
DrawingItem *_mask;
+ DrawingPattern *_fill_pattern;
+ DrawingPattern *_stroke_pattern;
Inkscape::Filters::Filter *_filter;
void *_user_data; ///< Used to associate DrawingItems with SPItems that created them
DrawingCache *_cache;
diff --git a/src/display/drawing-pattern.cpp b/src/display/drawing-pattern.cpp
new file mode 100644
index 000000000..cf6358278
--- /dev/null
+++ b/src/display/drawing-pattern.cpp
@@ -0,0 +1,194 @@
+/**
+ * @file
+ * Canvas belonging to SVG pattern.
+ *//*
+ * Authors:
+ * Tomasz Boczkowski <penginsbacon@gmail.com>
+ *
+ * Copyright (C) 2014 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "display/cairo-utils.h"
+#include "display/drawing-context.h"
+#include "display/drawing-pattern.h"
+#include "display/drawing-surface.h"
+
+namespace Inkscape {
+
+DrawingPattern::DrawingPattern(Drawing &drawing, bool debug)
+ : DrawingGroup(drawing)
+ , _pattern_to_user(NULL)
+ , _overflow_steps(1)
+ , _debug(debug)
+{
+}
+
+DrawingPattern::~DrawingPattern()
+{
+ delete _pattern_to_user; // delete NULL; is safe
+}
+
+void
+DrawingPattern::setPatternToUserTransform(Geom::Affine const &new_trans) {
+ Geom::Affine current;
+ if (_pattern_to_user) {
+ current = *_pattern_to_user;
+ }
+
+ if (!Geom::are_near(current, new_trans, 1e-18)) {
+ // mark the area where the object was for redraw.
+ _markForRendering();
+ if (new_trans.isIdentity()) {
+ delete _pattern_to_user; // delete NULL; is safe
+ _pattern_to_user = NULL;
+ } else {
+ _pattern_to_user = new Geom::Affine(new_trans);
+ }
+ _markForUpdate(STATE_ALL, true);
+ }
+}
+
+void
+DrawingPattern::setTileRect(Geom::Rect const &tile_rect) {
+ _tile_rect = tile_rect;
+}
+
+void
+DrawingPattern::setOverflow(Geom::Affine initial_transform, int steps, Geom::Affine step_transform) {
+ _overflow_initial_transform = initial_transform;
+ _overflow_steps = steps;
+ _overflow_step_transform = step_transform;
+}
+
+cairo_pattern_t *
+DrawingPattern::renderPattern(float opacity) {
+ bool needs_opacity = (1.0 - opacity) >= 1e-3;
+ bool visible = opacity >= 1e-3;
+
+ if (!visible) {
+ return NULL;
+ }
+
+ if (!_tile_rect || (_tile_rect->area() == 0)) {
+ return NULL;
+ }
+ Geom::Rect pattern_tile = *_tile_rect;
+
+ //TODO: If pattern_to_user set it to identity transform
+
+ // The DrawingSurface class handles the mapping from "logical space"
+ // (coordinates in the rendering) to "physical space" (surface pixels).
+ // An oversampling is done as the pattern may not pixel align with the final surface.
+ // The cairo surface is created when the DrawingContext is declared.
+ // Create drawing surface with size of pattern tile (in pattern space) but with number of pixels
+ // based on required resolution (c).
+ Inkscape::DrawingSurface pattern_surface(pattern_tile, _pattern_resolution);
+ Inkscape::DrawingContext dc(pattern_surface);
+ dc.transform( pattern_surface.drawingTransform().inverse() );
+
+ pattern_tile *= pattern_surface.drawingTransform();
+ Geom::IntRect one_tile = pattern_tile.roundOutwards();
+
+ // Render pattern.
+ if (needs_opacity) {
+ dc.pushGroup(); // this group is for pattern + opacity
+ }
+
+ if (_debug) {
+ dc.setSource(0.8, 0.0, 0.8);
+ dc.paint();
+ }
+
+ //FIXME: What flags to choose?
+ if (_overflow_steps == 1) {
+ render(dc, one_tile, RENDER_DEFAULT);
+ } else {
+ //Overflow transforms need to be transformed to the new coordinate system
+ //introduced by dc.transform( pattern_surface.drawingTransform().inverse() );
+ Geom::Affine dt = pattern_surface.drawingTransform();
+ Geom::Affine idt = pattern_surface.drawingTransform().inverse();
+ Geom::Affine initial_transform = idt * _overflow_initial_transform * dt;
+ Geom::Affine step_transform = idt * _overflow_step_transform * dt;
+
+ dc.transform(initial_transform);
+ for (int i = 0; i < _overflow_steps; i++) {
+ render(dc, one_tile, RENDER_DEFAULT);
+ dc.transform(step_transform);
+ }
+ }
+
+ //Uncomment to debug
+ // cairo_surface_t* raw = pattern_surface.raw();
+ // std::cout << " cairo_surface (sp-pattern): "
+ // << " width: " << cairo_image_surface_get_width( raw )
+ // << " height: " << cairo_image_surface_get_height( raw )
+ // << std::endl;
+ // std::string filename = "drawing-pattern.png";
+ // cairo_surface_write_to_png( pattern_surface.raw(), filename.c_str() );
+
+ if (needs_opacity) {
+ dc.popGroupToSource(); // pop raw pattern
+ dc.paint(opacity); // apply opacity
+ }
+
+ cairo_pattern_t *cp = cairo_pattern_create_for_surface(pattern_surface.raw());
+ // Apply transformation to user space. Also compensate for oversampling.
+ if (_pattern_to_user) {
+ ink_cairo_pattern_set_matrix(cp, _pattern_to_user->inverse() * pattern_surface.drawingTransform());
+ } else {
+ ink_cairo_pattern_set_matrix(cp, pattern_surface.drawingTransform());
+ }
+
+ if (_debug) {
+ cairo_pattern_set_extend(cp, CAIRO_EXTEND_NONE);
+ } else {
+ cairo_pattern_set_extend(cp, CAIRO_EXTEND_REPEAT);
+ }
+
+ return cp;
+}
+
+unsigned
+DrawingPattern::_updateItem(Geom::IntRect const &area, UpdateContext const &ctx, unsigned flags, unsigned reset)
+{
+ UpdateContext pattern_ctx;
+
+ if (!_tile_rect || (_tile_rect->area() == 0)) {
+ return STATE_NONE;
+ }
+
+ 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;
+ const double oversampling = 2.0;
+ double scale = det_ctm*det_ps2user*det_child_transform * oversampling;
+ //FIXME: When scale is too big (zooming in a hatch), cairo doesn't render the pattern
+ //More precisely it fails when seting pattern matrix in DrawingPattern::renderPattern
+ //Fully correct solution should make use of visible area bbox and change hach tile rect
+ //accordingly
+ if (scale > 25) {
+ scale = 25;
+ }
+ Geom::Point c(pattern_tile.dimensions()*scale*oversampling);
+ _pattern_resolution = c.ceil();
+
+ Inkscape::DrawingSurface pattern_surface(pattern_tile, _pattern_resolution);
+
+ pattern_ctx.ctm = pattern_surface.drawingTransform();
+ return DrawingGroup::_updateItem(Geom::IntRect::infinite(), pattern_ctx, flags, reset);
+}
+
+} // end namespace Inkscape
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/drawing-pattern.h b/src/display/drawing-pattern.h
new file mode 100644
index 000000000..7483ba067
--- /dev/null
+++ b/src/display/drawing-pattern.h
@@ -0,0 +1,87 @@
+/**
+ * @file
+ * Canvas belonging to SVG pattern.
+ *//*
+ * Authors:
+ * Tomasz Boczkowski <penginsbacon@gmail.com>
+ *
+ * Copyright (C) 2014 Authors
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_INKSCAPE_DISPLAY_DRAWING_PATTERN_H
+#define SEEN_INKSCAPE_DISPLAY_DRAWING_PATTERN_H
+
+#include "display/drawing-group.h"
+
+typedef struct _cairo_pattern cairo_pattern_t;
+class SPStyle;
+
+namespace Inkscape {
+
+/**
+ * @brief Drawing tree node used for rendering paints.
+ *
+ * DrawingPattern is used for rendering patterns and hatches.
+ *
+ * It renders it's children to a cairo_pattern_t structure that can be
+ * applied as source for fill or stroke operations.
+ */
+class DrawingPattern
+ : public DrawingGroup
+{
+public:
+ DrawingPattern(Drawing &drawing, bool debug = false);
+ ~DrawingPattern();
+
+ /**
+ * Set the transformation from pattern to user coordinate systems.
+ * @see SPPattern description for explanation of coordinate systems.
+ */
+ void setPatternToUserTransform(Geom::Affine const &new_trans);
+ /**
+ * Set the tile rect position and dimentions in content coordinate system
+ */
+ void setTileRect(Geom::Rect const &tile_rect);
+ /**
+ * Turn on overflow rendering.
+ *
+ * Overflow is implemented as repeated rendering of pattern contents. In every step
+ * a translation transform is applied.
+ */
+ void setOverflow(Geom::Affine initial_transform, int steps, Geom::Affine step_transform);
+ /**
+ * Render the pattern.
+ *
+ * Returns caito_pattern_t structure that can be set as source surface.
+ */
+ cairo_pattern_t *renderPattern(float opacity);
+protected:
+ virtual unsigned _updateItem(Geom::IntRect const &area, UpdateContext const &ctx,
+ unsigned flags, unsigned reset);
+
+ Geom::Affine *_pattern_to_user;
+ Geom::Affine _overflow_initial_transform;
+ Geom::Affine _overflow_step_transform;
+ int _overflow_steps;
+ Geom::OptRect _tile_rect;
+ bool _debug;
+ Geom::IntPoint _pattern_resolution;
+};
+
+bool is_drawing_group(DrawingItem *item);
+
+} // end namespace Inkscape
+
+#endif // !SEEN_INKSCAPE_DISPLAY_DRAWING_PATTERN_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/display/drawing-shape.cpp b/src/display/drawing-shape.cpp
index 88506f2b9..66160638f 100644
--- a/src/display/drawing-shape.cpp
+++ b/src/display/drawing-shape.cpp
@@ -155,7 +155,7 @@ DrawingShape::_renderFill(DrawingContext &dc)
Inkscape::DrawingContext::Save save(dc);
dc.transform(_ctm);
- bool has_fill = _nrstyle.prepareFill(dc, _item_bbox);
+ bool has_fill = _nrstyle.prepareFill(dc, _item_bbox, _fill_pattern);
if( has_fill ) {
dc.path(_curve->get_pathvector());
@@ -171,7 +171,7 @@ DrawingShape::_renderStroke(DrawingContext &dc)
Inkscape::DrawingContext::Save save(dc);
dc.transform(_ctm);
- bool has_stroke = _nrstyle.prepareStroke(dc, _item_bbox);
+ bool has_stroke = _nrstyle.prepareStroke(dc, _item_bbox, _stroke_pattern);
has_stroke &= (_nrstyle.stroke_width != 0);
if( has_stroke ) {
@@ -231,8 +231,8 @@ DrawingShape::_renderItem(DrawingContext &dc, Geom::IntRect const &area, unsigne
// update fill and stroke paints.
// this cannot be done during nr_arena_shape_update, because we need a Cairo context
// to render svg:pattern
- bool has_fill = _nrstyle.prepareFill(dc, _item_bbox);
- bool has_stroke = _nrstyle.prepareStroke(dc, _item_bbox);
+ bool has_fill = _nrstyle.prepareFill(dc, _item_bbox, _fill_pattern);
+ bool has_stroke = _nrstyle.prepareStroke(dc, _item_bbox, _stroke_pattern);
has_stroke &= (_nrstyle.stroke_width != 0);
if (has_fill || has_stroke) {
diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp
index 97a8c23d3..afe661b2e 100644
--- a/src/display/drawing-text.cpp
+++ b/src/display/drawing-text.cpp
@@ -448,13 +448,13 @@ unsigned DrawingText::_renderItem(DrawingContext &dc, Geom::IntRect const &/*are
Inkscape::DrawingContext::Save save(dc);
dc.transform(_ctm);
- has_fill = _nrstyle.prepareFill( dc, _item_bbox);
- has_stroke = _nrstyle.prepareStroke( dc, _item_bbox);
+ has_fill = _nrstyle.prepareFill( dc, _item_bbox, _fill_pattern);
+ has_stroke = _nrstyle.prepareStroke( dc, _item_bbox, _stroke_pattern);
// Avoid creating patterns if not needed
if( decorate ) {
- has_td_fill = _nrstyle.prepareTextDecorationFill( dc, _item_bbox);
- has_td_stroke = _nrstyle.prepareTextDecorationStroke(dc, _item_bbox);
+ has_td_fill = _nrstyle.prepareTextDecorationFill( dc, _item_bbox, _fill_pattern);
+ has_td_stroke = _nrstyle.prepareTextDecorationStroke(dc, _item_bbox, _stroke_pattern);
}
}
diff --git a/src/display/nr-style.cpp b/src/display/nr-style.cpp
index a9f101f69..96d16bf06 100644
--- a/src/display/nr-style.cpp
+++ b/src/display/nr-style.cpp
@@ -14,6 +14,7 @@
#include "sp-paint-server.h"
#include "display/canvas-bpath.h" // contains SPStrokeJoinType, SPStrokeCapType etc. (WTF!)
#include "display/drawing-context.h"
+#include "display/drawing-pattern.h"
void NRStyle::Paint::clear()
{
@@ -299,13 +300,16 @@ void NRStyle::set(SPStyle *style)
update();
}
-bool NRStyle::prepareFill(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox)
+bool NRStyle::prepareFill(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox, Inkscape::DrawingPattern *pattern)
{
// update fill pattern
if (!fill_pattern) {
switch (fill.type) {
- case PAINT_SERVER: {
- fill_pattern = fill.server->pattern_new(dc.raw(), paintbox, fill.opacity);
+ case PAINT_SERVER:
+ if (pattern) {
+ fill_pattern = pattern->renderPattern(fill.opacity);
+ } else {
+ fill_pattern = fill.server->pattern_new(dc.raw(), paintbox, fill.opacity);
} break;
case PAINT_COLOR: {
SPColor const &c = fill.color;
@@ -325,14 +329,20 @@ void NRStyle::applyFill(Inkscape::DrawingContext &dc)
dc.setFillRule(fill_rule);
}
-bool NRStyle::prepareTextDecorationFill(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox)
+bool NRStyle::prepareTextDecorationFill(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox, Inkscape::DrawingPattern *pattern)
{
// update text decoration pattern
if (!text_decoration_fill_pattern) {
switch (text_decoration_fill.type) {
- case PAINT_SERVER: {
- text_decoration_fill_pattern = text_decoration_fill.server->pattern_new(dc.raw(), paintbox, text_decoration_fill.opacity);
- } break;
+ case PAINT_SERVER:
+ if (pattern) {
+ text_decoration_fill_pattern = pattern->renderPattern(
+ text_decoration_fill.opacity);
+ } else {
+ text_decoration_fill_pattern = text_decoration_fill.server->pattern_new(dc.raw(),
+ paintbox, text_decoration_fill.opacity);
+ }
+ break;
case PAINT_COLOR: {
SPColor const &c = text_decoration_fill.color;
text_decoration_fill_pattern = cairo_pattern_create_rgba(
@@ -351,19 +361,25 @@ void NRStyle::applyTextDecorationFill(Inkscape::DrawingContext &dc)
// Fill rule does not matter, no intersections.
}
-bool NRStyle::prepareStroke(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox)
+bool NRStyle::prepareStroke(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox, Inkscape::DrawingPattern *pattern)
{
if (!stroke_pattern) {
switch (stroke.type) {
- case PAINT_SERVER: {
- stroke_pattern = stroke.server->pattern_new(dc.raw(), paintbox, stroke.opacity);
- } break;
+ case PAINT_SERVER:
+ if (pattern) {
+ stroke_pattern = pattern->renderPattern(stroke.opacity);
+ } else {
+ stroke_pattern = stroke.server->pattern_new(dc.raw(), paintbox, stroke.opacity);
+ }
+ break;
case PAINT_COLOR: {
SPColor const &c = stroke.color;
- stroke_pattern = cairo_pattern_create_rgba(
- c.v.c[0], c.v.c[1], c.v.c[2], stroke.opacity);
- } break;
- default: break;
+ stroke_pattern = cairo_pattern_create_rgba(c.v.c[0], c.v.c[1], c.v.c[2],
+ stroke.opacity);
+ }
+ break;
+ default:
+ break;
}
}
if (!stroke_pattern) return false;
@@ -380,13 +396,19 @@ void NRStyle::applyStroke(Inkscape::DrawingContext &dc)
cairo_set_dash(dc.raw(), dash, n_dash, dash_offset); // fixme
}
-bool NRStyle::prepareTextDecorationStroke(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox)
+bool NRStyle::prepareTextDecorationStroke(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox, Inkscape::DrawingPattern *pattern)
{
if (!text_decoration_stroke_pattern) {
switch (text_decoration_stroke.type) {
- case PAINT_SERVER: {
- text_decoration_stroke_pattern = text_decoration_stroke.server->pattern_new(dc.raw(), paintbox, text_decoration_stroke.opacity);
- } break;
+ case PAINT_SERVER:
+ if (pattern) {
+ text_decoration_stroke_pattern = pattern->renderPattern(
+ text_decoration_stroke.opacity);
+ } else {
+ text_decoration_stroke_pattern = text_decoration_stroke.server->pattern_new(
+ dc.raw(), paintbox, text_decoration_stroke.opacity);
+ }
+ break;
case PAINT_COLOR: {
SPColor const &c = text_decoration_stroke.color;
text_decoration_stroke_pattern = cairo_pattern_create_rgba(
diff --git a/src/display/nr-style.h b/src/display/nr-style.h
index 83bcb1ab7..f324fdb56 100644
--- a/src/display/nr-style.h
+++ b/src/display/nr-style.h
@@ -21,6 +21,7 @@ class SPStyle;
namespace Inkscape {
class DrawingContext;
+class DrawingPattern;
}
struct NRStyle {
@@ -28,10 +29,10 @@ struct NRStyle {
~NRStyle();
void set(SPStyle *);
- bool prepareFill(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox);
- bool prepareStroke(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox);
- bool prepareTextDecorationFill(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox);
- bool prepareTextDecorationStroke(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox);
+ bool prepareFill(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox, Inkscape::DrawingPattern *pattern);
+ bool prepareStroke(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox, Inkscape::DrawingPattern *pattern);
+ bool prepareTextDecorationFill(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox, Inkscape::DrawingPattern *pattern);
+ bool prepareTextDecorationStroke(Inkscape::DrawingContext &dc, Geom::OptRect const &paintbox, Inkscape::DrawingPattern *pattern);
void applyFill(Inkscape::DrawingContext &dc);
void applyStroke(Inkscape::DrawingContext &dc);
void applyTextDecorationFill(Inkscape::DrawingContext &dc);
diff --git a/src/document.cpp b/src/document.cpp
index 5aad4ca5e..70fec83d7 100644
--- a/src/document.cpp
+++ b/src/document.cpp
@@ -709,7 +709,12 @@ void SPDocument::fitToRect(Geom::Rect const &rect, bool with_margins)
double const h = rect.height();
double const old_height = getHeight().value("px");
- Inkscape::Util::Unit const *px = unit_table.getUnit("px");
+ Inkscape::Util::Unit const *nv_units = unit_table.getUnit("px");
+ SPNamedView *nv = sp_document_namedview(this, NULL);
+ if (nv != NULL) {
+ if (nv->getAttribute("units"))
+ nv_units = unit_table.getUnit(nv->getAttribute("units"));
+ }
/* in px */
double margin_top = 0.0;
@@ -717,22 +722,16 @@ void SPDocument::fitToRect(Geom::Rect const &rect, bool with_margins)
double margin_right = 0.0;
double margin_bottom = 0.0;
- SPNamedView *nv = sp_document_namedview(this, NULL);
-
if (with_margins && nv) {
if (nv != NULL) {
- gchar const * const units_abbr = nv->getAttribute("units");
- Inkscape::Util::Unit const *margin_units = NULL;
- if (units_abbr) {
- margin_units = unit_table.getUnit(units_abbr);
- }
- if (!margin_units) {
- margin_units = px;
- }
- margin_top = nv->getMarginLength("fit-margin-top",margin_units, px, w, h, false);
- margin_left = nv->getMarginLength("fit-margin-left",margin_units, px, w, h, true);
- margin_right = nv->getMarginLength("fit-margin-right",margin_units, px, w, h, true);
- margin_bottom = nv->getMarginLength("fit-margin-bottom",margin_units, px, w, h, false);
+ margin_top = nv->getMarginLength("fit-margin-top", nv_units, unit_table.getUnit("px"), w, h, false);
+ margin_left = nv->getMarginLength("fit-margin-left", nv_units, unit_table.getUnit("px"), w, h, true);
+ margin_right = nv->getMarginLength("fit-margin-right", nv_units, unit_table.getUnit("px"), w, h, true);
+ margin_bottom = nv->getMarginLength("fit-margin-bottom", nv_units, unit_table.getUnit("px"), w, h, false);
+ margin_top = Inkscape::Util::Quantity::convert(margin_top, nv_units, "px");
+ margin_left = Inkscape::Util::Quantity::convert(margin_left, nv_units, "px");
+ margin_right = Inkscape::Util::Quantity::convert(margin_right, nv_units, "px");
+ margin_bottom = Inkscape::Util::Quantity::convert(margin_bottom, nv_units, "px");
}
}
@@ -741,8 +740,8 @@ void SPDocument::fitToRect(Geom::Rect const &rect, bool with_margins)
rect.max() + Geom::Point(margin_right, margin_top));
- setWidth(Inkscape::Util::Quantity(rect_with_margins.width(), px));
- setHeight(Inkscape::Util::Quantity(rect_with_margins.height(), px));
+ setWidth(Inkscape::Util::Quantity(Inkscape::Util::Quantity::convert(rect_with_margins.width(), "px", nv_units), nv_units));
+ setHeight(Inkscape::Util::Quantity(Inkscape::Util::Quantity::convert(rect_with_margins.height(), "px", nv_units), nv_units));
Geom::Translate const tr(
Geom::Point(0, old_height - rect_with_margins.height())
diff --git a/src/extension/implementation/script.cpp b/src/extension/implementation/script.cpp
index 5ee226ccf..e6ac13cdc 100644
--- a/src/extension/implementation/script.cpp
+++ b/src/extension/implementation/script.cpp
@@ -726,12 +726,12 @@ void Script::effect(Inkscape::Extension::Effect *module,
vd->emitReconstructionStart();
copy_doc(vd->rroot, mydoc->rroot);
vd->emitReconstructionFinish();
- SPObject *layer = NULL;
-
+
// Getting the named view from the document generated by the extension
SPNamedView *nv = sp_document_namedview(mydoc, NULL);
//Check if it has a default layer set up
+ SPObject *layer = NULL;
if ( nv != NULL)
{
if( nv->default_layer_id != 0 ) {
@@ -760,19 +760,21 @@ void Script::effect(Inkscape::Extension::Effect *module,
/**
- \brief A function to take all the svg elements from one document
- and put them in another.
- \param oldroot The root node of the document to be replaced
- \param newroot The root node of the document to replace it with
-
- This function first deletes all of the data in the old document. It
- does this by creating a list of what needs to be deleted, and then
- goes through the list. This two pass approach removes issues with
- the list being change while parsing through it. Lots of nasty bugs.
-
- Then, it goes through the new document, duplicating all of the
- elements and putting them into the old document. The copy
- is then complete.
+ \brief A function to replace all the elements in an old document
+ by those from a new document.
+ document and repinserts them into an emptied old document.
+ \param oldroot The root node of the old (destination) document.
+ \param newroot The root node of the new (source) document.
+
+ This function first deletes all the elements in the old document by
+ making two pass, the first to create a list of the old elements and
+ the second to actually delete them. This two pass approach removes issues
+ with the list being change while parsing through it... lots of nasty bugs.
+
+ Then, it copies all the element in the new document into the old document.
+
+ Finally, it replaces the attributes in the root element of the old document
+ by the attributes in root of the new document.
*/
void Script::copy_doc (Inkscape::XML::Node * oldroot, Inkscape::XML::Node * newroot)
{
@@ -781,9 +783,21 @@ void Script::copy_doc (Inkscape::XML::Node * oldroot, Inkscape::XML::Node * newr
g_warning("Error on copy_doc: NULL pointer input.");
return;
}
+
+ // For copying attributes in root and in namedview
+ using Inkscape::Util::List;
+ using Inkscape::XML::AttributeRecord;
+
+ // Question: Why is the "sodipodi:namedview" special? Treating it as a normal
+ // elmement results in crashes.
+ // Seems to be a bug:
+ // http://inkscape.13.x6.nabble.com/Effect-that-modifies-the-document-properties-tt2822126.html
+
std::vector<Inkscape::XML::Node *> delete_list;
Inkscape::XML::Node * oldroot_namedview = NULL;
+ Inkscape::XML::Node * newroot_namedview = NULL;
+ // Make list
for (Inkscape::XML::Node * child = oldroot->firstChild();
child != NULL;
child = child->next()) {
@@ -798,14 +812,18 @@ void Script::copy_doc (Inkscape::XML::Node * oldroot, Inkscape::XML::Node * newr
delete_list.push_back(child);
}
}
+
+ // Unparent (delete)
for (unsigned int i = 0; i < delete_list.size(); i++) {
sp_repr_unparent(delete_list[i]);
}
+ // Copy
for (Inkscape::XML::Node * child = newroot->firstChild();
child != NULL;
child = child->next()) {
if (!strcmp("sodipodi:namedview", child->name())) {
+ newroot_namedview = child;
if (oldroot_namedview != NULL) {
for (Inkscape::XML::Node * newroot_namedview_child = child->firstChild();
newroot_namedview_child != NULL;
@@ -818,26 +836,44 @@ void Script::copy_doc (Inkscape::XML::Node * oldroot, Inkscape::XML::Node * newr
}
}
- {
- using Inkscape::Util::List;
- using Inkscape::XML::AttributeRecord;
- std::vector<gchar const *> attribs;
+ std::vector<gchar const *> attribs;
- // Make a list of all attributes of the old root node.
- for (List<AttributeRecord const> iter = oldroot->attributeList(); iter; ++iter) {
- attribs.push_back(g_quark_to_string(iter->key));
- }
+ // Must explicitly copy root attributes.
- // Delete the attributes of the old root nodes.
- for (std::vector<gchar const *>::const_iterator it = attribs.begin(); it != attribs.end(); ++it) {
- oldroot->setAttribute(*it, NULL);
- }
+ // Make a list of all attributes of the old root node.
+ for (List<AttributeRecord const> iter = oldroot->attributeList(); iter; ++iter) {
+ attribs.push_back(g_quark_to_string(iter->key));
+ }
- // Set the new attributes.
- for (List<AttributeRecord const> iter = newroot->attributeList(); iter; ++iter) {
- gchar const *name = g_quark_to_string(iter->key);
- oldroot->setAttribute(name, newroot->attribute(name));
- }
+ // Delete the attributes of the old root node.
+ for (std::vector<gchar const *>::const_iterator it = attribs.begin(); it != attribs.end(); ++it) {
+ oldroot->setAttribute(*it, NULL);
+ }
+
+ // Set the new attributes.
+ for (List<AttributeRecord const> iter = newroot->attributeList(); iter; ++iter) {
+ gchar const *name = g_quark_to_string(iter->key);
+ oldroot->setAttribute(name, newroot->attribute(name));
+ }
+
+ attribs.clear();
+
+ // Must explicitly copy namedview attributes.
+
+ // Make a list of all attributes of the old namedview node.
+ for (List<AttributeRecord const> iter = oldroot_namedview->attributeList(); iter; ++iter) {
+ attribs.push_back(g_quark_to_string(iter->key));
+ }
+
+ // Delete the attributes of the old namedview node.
+ for (std::vector<gchar const *>::const_iterator it = attribs.begin(); it != attribs.end(); ++it) {
+ oldroot_namedview->setAttribute(*it, NULL);
+ }
+
+ // Set the new attributes.
+ for (List<AttributeRecord const> iter = newroot_namedview->attributeList(); iter; ++iter) {
+ gchar const *name = g_quark_to_string(iter->key);
+ oldroot_namedview->setAttribute(name, newroot_namedview->attribute(name));
}
/** \todo Restore correct layer */
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 8071cae36..57d155b60 100644
--- a/src/extension/internal/cairo-render-context.h
+++ b/src/extension/internal/cairo-render-context.h
@@ -204,6 +204,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 8196e34fb..a725685d4 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"
@@ -598,6 +599,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/extension/internal/cdr-input.cpp b/src/extension/internal/cdr-input.cpp
index 1de3f304b..fb58887c9 100644
--- a/src/extension/internal/cdr-input.cpp
+++ b/src/extension/internal/cdr-input.cpp
@@ -24,7 +24,21 @@
#include <cstring>
#include <libcdr/libcdr.h>
-#include <libwpd-stream/libwpd-stream.h>
+
+// TODO: Drop this check when librevenge is widespread.
+#if WITH_LIBCDR01
+ #include <librevenge-stream/librevenge-stream.h>
+
+ using librevenge::RVNGString;
+ using librevenge::RVNGFileStream;
+ using librevenge::RVNGStringVector;
+#else
+ #include <libwpd-stream/libwpd-stream.h>
+
+ typedef WPXString RVNGString;
+ typedef WPXFileStream RVNGFileStream;
+ typedef libcdr::CDRStringVector RVNGStringVector;
+#endif
#include <gtkmm/alignment.h>
#include <gtkmm/comboboxtext.h>
@@ -60,7 +74,7 @@ namespace Internal {
class CdrImportDialog : public Gtk::Dialog {
public:
- CdrImportDialog(const std::vector<WPXString> &vec);
+ CdrImportDialog(const std::vector<RVNGString> &vec);
virtual ~CdrImportDialog();
bool showDialog();
@@ -86,12 +100,12 @@ private:
class Gtk::VBox * vbox2;
class Gtk::Widget * _previewArea;
- const std::vector<WPXString> &_vec; // Document to be imported
+ const std::vector<RVNGString> &_vec; // Document to be imported
unsigned _current_page; // Current selected page
int _preview_width, _preview_height; // Size of the preview area
};
-CdrImportDialog::CdrImportDialog(const std::vector<WPXString> &vec)
+CdrImportDialog::CdrImportDialog(const std::vector<RVNGString> &vec)
: _vec(vec), _current_page(1)
{
int num_pages = _vec.size();
@@ -216,14 +230,20 @@ void CdrImportDialog::_setPreviewPage(unsigned page)
SPDocument *CdrInput::open(Inkscape::Extension::Input * /*mod*/, const gchar * uri)
{
- WPXFileStream input(uri);
+ RVNGFileStream input(uri);
if (!libcdr::CDRDocument::isSupported(&input)) {
return NULL;
}
- libcdr::CDRStringVector output;
+ RVNGStringVector output;
+#if WITH_LIBCDR01
+ librevenge::RVNGSVGDrawingGenerator generator(output, "svg");
+
+ if (!libcdr::CDRDocument::parse(&input, &generator)) {
+#else
if (!libcdr::CDRDocument::generateSVG(&input, output)) {
+#endif
return NULL;
}
@@ -231,9 +251,9 @@ SPDocument *CdrInput::open(Inkscape::Extension::Input * /*mod*/, const gchar * u
return NULL;
}
- std::vector<WPXString> tmpSVGOutput;
+ std::vector<RVNGString> tmpSVGOutput;
for (unsigned i=0; i<output.size(); ++i) {
- WPXString tmpString("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
+ RVNGString tmpString("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
tmpString.append(output[i]);
tmpSVGOutput.push_back(tmpString);
}
diff --git a/src/extension/internal/pdfinput/pdf-input.cpp b/src/extension/internal/pdfinput/pdf-input.cpp
index e18d898f5..defb15754 100644
--- a/src/extension/internal/pdfinput/pdf-input.cpp
+++ b/src/extension/internal/pdfinput/pdf-input.cpp
@@ -647,7 +647,31 @@ PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) {
// Initialize the globalParams variable for poppler
if (!globalParams) {
+#ifdef ENABLE_OSX_APP_LOCATIONS
+ //
+ // data files for poppler are not relocatable (loaded from
+ // path defined at build time). This fails to work with relocatable
+ // application bundles for OS X.
+ //
+ // Workaround:
+ // 1. define $POPPLER_DATADIR env variable in app launcher script
+ // 2. pass custom $POPPLER_DATADIR via poppler's GlobalParams()
+ //
+ // relevant poppler commit:
+ // <http://cgit.freedesktop.org/poppler/poppler/commit/?id=869584a84eed507775ff1c3183fe484c14b6f77b>
+ //
+ // FIXES: Inkscape bug #956282, #1264793
+ // TODO: report RFE upstream (full relocation support for OS X packaging)
+ //
+ gchar const *poppler_datadir = g_getenv("POPPLER_DATADIR");
+ if (poppler_datadir != NULL) {
+ globalParams = new GlobalParams(poppler_datadir);
+ } else {
+ globalParams = new GlobalParams();
+ }
+#else
globalParams = new GlobalParams();
+#endif // ENABLE_OSX_APP_LOCATIONS
}
// poppler does not use glib g_open. So on win32 we must use unicode call. code was copied from glib gstdio.c
#ifndef WIN32
diff --git a/src/extension/internal/pdfinput/pdf-parser.cpp b/src/extension/internal/pdfinput/pdf-parser.cpp
index c5f03e5aa..0b7dc7905 100644
--- a/src/extension/internal/pdfinput/pdf-parser.cpp
+++ b/src/extension/internal/pdfinput/pdf-parser.cpp
@@ -247,30 +247,74 @@ PdfOperator PdfParser::opTab[] = {
#define numOps (sizeof(opTab) / sizeof(PdfOperator))
+namespace {
+
+GfxPatch blankPatch()
+{
+ GfxPatch patch;
+ memset(&patch, 0, sizeof(patch)); // quick-n-dirty
+ return patch;
+}
+
+} // namespace
+
//------------------------------------------------------------------------
-// PdfParser
+// ClipHistoryEntry
//------------------------------------------------------------------------
-PdfParser::PdfParser(XRef *xrefA, Inkscape::Extension::Internal::SvgBuilder *builderA,
- int /*pageNum*/, int rotate, Dict *resDict,
- PDFRectangle *box, PDFRectangle *cropBox)
-{
- xref = xrefA;
- subPage = gFalse;
- printCommands = false;
+class ClipHistoryEntry {
+public:
+
+ ClipHistoryEntry(GfxPath *clipPath = NULL, GfxClipType clipType = clipNormal);
+ virtual ~ClipHistoryEntry();
+
+ // Manipulate clip path stack
+ ClipHistoryEntry *save();
+ ClipHistoryEntry *restore();
+ GBool hasSaves() { return saved != NULL; }
+ void setClip(GfxPath *newClipPath, GfxClipType newClipType = clipNormal);
+ GfxPath *getClipPath() { return clipPath; }
+ GfxClipType getClipType() { return clipType; }
- // start the resource stack
- res = new GfxResources(xref, resDict, NULL);
+private:
- // initialize
- state = new GfxState(72.0, 72.0, box, rotate, gTrue);
- clipHistory = new ClipHistoryEntry();
+ ClipHistoryEntry *saved; // next clip path on stack
+
+ GfxPath *clipPath; // used as the path to be filled for an 'sh' operator
+ GfxClipType clipType;
+
+ ClipHistoryEntry(ClipHistoryEntry *other);
+};
+
+//------------------------------------------------------------------------
+// PdfParser
+//------------------------------------------------------------------------
+
+PdfParser::PdfParser(XRef *xrefA,
+ Inkscape::Extension::Internal::SvgBuilder *builderA,
+ int /*pageNum*/,
+ int rotate,
+ Dict *resDict,
+ PDFRectangle *box,
+ PDFRectangle *cropBox) :
+ xref(xrefA),
+ builder(builderA),
+ subPage(gFalse),
+ printCommands(false),
+ res(new GfxResources(xref, resDict, NULL)), // start the resource stack
+ state(new GfxState(72.0, 72.0, box, rotate, gTrue)),
+ fontChanged(gFalse),
+ clip(clipNone),
+ ignoreUndef(0),
+ baseMatrix(),
+ formDepth(0),
+ parser(NULL),
+ colorDeltas(),
+ maxDepths(),
+ clipHistory(new ClipHistoryEntry()),
+ operatorHistory(NULL)
+{
setDefaultApproximationPrecision();
- fontChanged = gFalse;
- clip = clipNone;
- ignoreUndef = 0;
- operatorHistory = NULL;
- builder = builderA;
builder->setDocumentSize(Inkscape::Util::Quantity::convert(state->getPageWidth(), "pt", "px"),
Inkscape::Util::Quantity::convert(state->getPageHeight(), "pt", "px"));
@@ -306,50 +350,62 @@ PdfParser::PdfParser(XRef *xrefA, Inkscape::Extension::Internal::SvgBuilder *bui
pushOperator("startPage");
}
-PdfParser::PdfParser(XRef *xrefA, Inkscape::Extension::Internal::SvgBuilder *builderA,
- Dict *resDict, PDFRectangle *box) {
-
- int i;
- parser = NULL;
-
- xref = xrefA;
- subPage = gTrue;
- printCommands = false;
-
- // start the resource stack
- res = new GfxResources(xref, resDict, NULL);
-
- // initialize
- operatorHistory = NULL;
- builder = builderA;
- state = new GfxState(72, 72, box, 0, gFalse);
- clipHistory = new ClipHistoryEntry();
+PdfParser::PdfParser(XRef *xrefA,
+ Inkscape::Extension::Internal::SvgBuilder *builderA,
+ Dict *resDict,
+ PDFRectangle *box) :
+ xref(xrefA),
+ builder(builderA),
+ subPage(gTrue),
+ printCommands(false),
+ res(new GfxResources(xref, resDict, NULL)), // start the resource stack
+ state(new GfxState(72, 72, box, 0, gFalse)),
+ fontChanged(gFalse),
+ clip(clipNone),
+ ignoreUndef(0),
+ baseMatrix(),
+ formDepth(0),
+ parser(NULL),
+ colorDeltas(),
+ maxDepths(),
+ clipHistory(new ClipHistoryEntry()),
+ operatorHistory(NULL)
+{
setDefaultApproximationPrecision();
- fontChanged = gFalse;
- clip = clipNone;
- ignoreUndef = 0;
- for (i = 0; i < 6; ++i) {
+ for (int i = 0; i < 6; ++i) {
baseMatrix[i] = state->getCTM()[i];
}
formDepth = 0;
}
PdfParser::~PdfParser() {
- while (state->hasSaves()) {
+ while(operatorHistory) {
+ OpHistoryEntry *tmp = operatorHistory->next;
+ delete operatorHistory;
+ operatorHistory = tmp;
+ }
+
+ while (state && state->hasSaves()) {
restoreState();
}
+
if (!subPage) {
//out->endPage();
}
+
while (res) {
popResources();
}
+
if (state) {
delete state;
+ state = NULL;
}
+
if (clipHistory) {
delete clipHistory;
+ clipHistory = NULL;
}
}
@@ -460,7 +516,8 @@ void PdfParser::go(GBool /*topLevel*/)
}
}
-void PdfParser::pushOperator(const char *name) {
+void PdfParser::pushOperator(const char *name)
+{
OpHistoryEntry *newEntry = new OpHistoryEntry;
newEntry->name = name;
newEntry->state = NULL;
@@ -2086,13 +2143,19 @@ void PdfParser::doPatchMeshShFill(GfxPatchMeshShading *shading) {
}
void PdfParser::fillPatch(GfxPatch *patch, int nComps, int depth) {
- GfxPatch patch00, patch01, patch10, patch11;
+ GfxPatch patch00 = blankPatch();
+ GfxPatch patch01 = blankPatch();
+ GfxPatch patch10 = blankPatch();
+ GfxPatch patch11 = blankPatch();
#ifdef POPPLER_NEW_GFXPATCH
- GfxColor color;
+ GfxColor color = {{0}};
#endif
- double xx[4][8], yy[4][8];
- double xxm, yym;
- double patchColorDelta = colorDeltas[pdfPatchMeshShading-1];
+ double xx[4][8];
+ double yy[4][8];
+ double xxm;
+ double yym;
+ double patchColorDelta = colorDeltas[pdfPatchMeshShading - 1];
+
int i;
for (i = 0; i < nComps; ++i) {
@@ -3463,9 +3526,7 @@ void PdfParser::popResources() {
}
void PdfParser::setDefaultApproximationPrecision() {
- int i;
-
- for (i = 1; i <= pdfNumShadingTypes; ++i) {
+ for (int i = 1; i <= pdfNumShadingTypes; ++i) {
setApproximationPrecision(i, defaultShadingColorDelta, defaultShadingMaxDepth);
}
}
@@ -3484,19 +3545,18 @@ void PdfParser::setApproximationPrecision(int shadingType, double colorDelta,
// ClipHistoryEntry
//------------------------------------------------------------------------
-ClipHistoryEntry::ClipHistoryEntry(GfxPath *clipPathA, GfxClipType clipTypeA) {
- if (clipPathA) {
- clipPath = clipPathA->copy();
- } else {
- clipPath = NULL;
- }
- clipType = clipTypeA;
- saved = NULL;
+ClipHistoryEntry::ClipHistoryEntry(GfxPath *clipPathA, GfxClipType clipTypeA) :
+ saved(NULL),
+ clipPath((clipPathA) ? clipPathA->copy() : NULL),
+ clipType(clipTypeA)
+{
}
-ClipHistoryEntry::~ClipHistoryEntry() {
+ClipHistoryEntry::~ClipHistoryEntry()
+{
if (clipPath) {
delete clipPath;
+ clipPath = NULL;
}
}
@@ -3510,6 +3570,7 @@ void ClipHistoryEntry::setClip(GfxPath *clipPathA, GfxClipType clipTypeA) {
clipType = clipTypeA;
} else {
clipPath = NULL;
+ clipType = clipNormal;
}
}
@@ -3526,7 +3587,7 @@ ClipHistoryEntry *ClipHistoryEntry::restore() {
if (saved) {
oldEntry = saved;
saved = NULL;
- delete this;
+ delete this; // TODO really should avoid deleting from inside.
} else {
oldEntry = this;
}
@@ -3540,6 +3601,7 @@ ClipHistoryEntry::ClipHistoryEntry(ClipHistoryEntry *other) {
this->clipType = other->clipType;
} else {
this->clipPath = NULL;
+ this->clipType = clipNormal;
}
saved = NULL;
}
diff --git a/src/extension/internal/pdfinput/pdf-parser.h b/src/extension/internal/pdfinput/pdf-parser.h
index a63d669c7..e28fecc2e 100644
--- a/src/extension/internal/pdfinput/pdf-parser.h
+++ b/src/extension/internal/pdfinput/pdf-parser.h
@@ -58,6 +58,8 @@ class AnnotBorderStyle;
class PdfParser;
+class ClipHistoryEntry;
+
//------------------------------------------------------------------------
#ifndef GFX_H
@@ -101,34 +103,6 @@ struct OpHistoryEntry {
};
//------------------------------------------------------------------------
-// ClipHistoryEntry
-//------------------------------------------------------------------------
-
-class ClipHistoryEntry {
-public:
-
- ClipHistoryEntry(GfxPath *clipPath=NULL, GfxClipType clipType=clipNormal);
- virtual ~ClipHistoryEntry();
-
- // Manipulate clip path stack
- ClipHistoryEntry *save();
- ClipHistoryEntry *restore();
- GBool hasSaves() { return saved != NULL; }
- void setClip(GfxPath *newClipPath, GfxClipType newClipType=clipNormal);
- GfxPath *getClipPath() { return clipPath; }
- GfxClipType getClipType() { return clipType; }
-
-private:
-
- ClipHistoryEntry *saved; // next clip path on stack
-
- GfxPath *clipPath; // used as the path to be filled for an 'sh' operator
- GfxClipType clipType;
-
- ClipHistoryEntry(ClipHistoryEntry *other);
-};
-
-//------------------------------------------------------------------------
// PdfParser
//------------------------------------------------------------------------
diff --git a/src/extension/internal/vsd-input.cpp b/src/extension/internal/vsd-input.cpp
index 2623d1ca7..25815e64f 100644
--- a/src/extension/internal/vsd-input.cpp
+++ b/src/extension/internal/vsd-input.cpp
@@ -24,7 +24,22 @@
#include <cstring>
#include <libvisio/libvisio.h>
-#include <libwpd-stream/libwpd-stream.h>
+
+// TODO: Drop this check when librevenge is widespread.
+#if WITH_LIBVISIO01
+ #include <librevenge-stream/librevenge-stream.h>
+
+ using librevenge::RVNGString;
+ using librevenge::RVNGFileStream;
+ using librevenge::RVNGStringVector;
+#else
+ #include <libwpd-stream/libwpd-stream.h>
+
+ typedef WPXString RVNGString;
+ typedef WPXFileStream RVNGFileStream;
+ typedef libvisio::VSDStringVector RVNGStringVector;
+#endif
+
#include <gtkmm/alignment.h>
#include <gtkmm/comboboxtext.h>
@@ -59,7 +74,7 @@ namespace Internal {
class VsdImportDialog : public Gtk::Dialog {
public:
- VsdImportDialog(const std::vector<WPXString> &vec);
+ VsdImportDialog(const std::vector<RVNGString> &vec);
virtual ~VsdImportDialog();
bool showDialog();
@@ -85,12 +100,12 @@ private:
class Gtk::VBox * vbox2;
class Gtk::Widget * _previewArea;
- const std::vector<WPXString> &_vec; // Document to be imported
+ const std::vector<RVNGString> &_vec; // Document to be imported
unsigned _current_page; // Current selected page
int _preview_width, _preview_height; // Size of the preview area
};
-VsdImportDialog::VsdImportDialog(const std::vector<WPXString> &vec)
+VsdImportDialog::VsdImportDialog(const std::vector<RVNGString> &vec)
: _vec(vec), _current_page(1)
{
int num_pages = _vec.size();
@@ -215,14 +230,20 @@ void VsdImportDialog::_setPreviewPage(unsigned page)
SPDocument *VsdInput::open(Inkscape::Extension::Input * /*mod*/, const gchar * uri)
{
- WPXFileStream input(uri);
+ RVNGFileStream input(uri);
if (!libvisio::VisioDocument::isSupported(&input)) {
return NULL;
}
- libvisio::VSDStringVector output;
+ RVNGStringVector output;
+#if WITH_LIBVISIO01
+ librevenge::RVNGSVGDrawingGenerator generator(output, "svg");
+
+ if (!libvisio::VisioDocument::parse(&input, &generator)) {
+#else
if (!libvisio::VisioDocument::generateSVG(&input, output)) {
+#endif
return NULL;
}
@@ -230,9 +251,9 @@ SPDocument *VsdInput::open(Inkscape::Extension::Input * /*mod*/, const gchar * u
return NULL;
}
- std::vector<WPXString> tmpSVGOutput;
+ std::vector<RVNGString> tmpSVGOutput;
for (unsigned i=0; i<output.size(); ++i) {
- WPXString tmpString("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
+ RVNGString tmpString("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
tmpString.append(output[i]);
tmpSVGOutput.push_back(tmpString);
}
diff --git a/src/extension/internal/wpg-input.cpp b/src/extension/internal/wpg-input.cpp
index 14ff3ec77..12d86a99a 100644
--- a/src/extension/internal/wpg-input.cpp
+++ b/src/extension/internal/wpg-input.cpp
@@ -52,16 +52,24 @@
#include "util/units.h"
#include <cstring>
-// Take a guess and fallback to 0.1.x if no configure has run
-#if !defined(WITH_LIBWPG01) && !defined(WITH_LIBWPG02)
-#define WITH_LIBWPG01 1
+// Take a guess and fallback to 0.2.x if no configure has run
+#if !defined(WITH_LIBWPG03) && !defined(WITH_LIBWPG02)
+#define WITH_LIBWPG02 1
#endif
#include "libwpg/libwpg.h"
-#if WITH_LIBWPG01
-#include "libwpg/WPGStreamImplementation.h"
-#elif WITH_LIBWPG02
-#include "libwpd-stream/libwpd-stream.h"
+#if WITH_LIBWPG03
+ #include <librevenge-stream/librevenge-stream.h>
+
+ using librevenge::RVNGString;
+ using librevenge::RVNGFileStream;
+ using librevenge::RVNGInputStream;
+#else
+ #include "libwpd-stream/libwpd-stream.h"
+
+ typedef WPXString RVNGString;
+ typedef WPXFileStream RVNGFileStream;
+ typedef WPXInputStream RVNGInputStream;
#endif
using namespace libwpg;
@@ -73,17 +81,15 @@ namespace Internal {
SPDocument *WpgInput::open(Inkscape::Extension::Input * /*mod*/, const gchar * uri)
{
-#if WITH_LIBWPG01
- WPXInputStream* input = new libwpg::WPGFileStream(uri);
-#elif WITH_LIBWPG02
- WPXInputStream* input = new WPXFileStream(uri);
-#endif
+ RVNGInputStream* input = new RVNGFileStream(uri);
+#if WITH_LIBWPG03
+ if (input->isStructured()) {
+ RVNGInputStream* olestream = input->getSubStreamByName("PerfectOffice_MAIN");
+#else
if (input->isOLEStream()) {
-#if WITH_LIBWPG01
- WPXInputStream* olestream = input->getDocumentOLEStream();
-#elif WITH_LIBWPG02
- WPXInputStream* olestream = input->getDocumentOLEStream("PerfectOffice_MAIN");
+ RVNGInputStream* olestream = input->getDocumentOLEStream("PerfectOffice_MAIN");
#endif
+
if (olestream) {
delete input;
input = olestream;
@@ -98,15 +104,24 @@ SPDocument *WpgInput::open(Inkscape::Extension::Input * /*mod*/, const gchar * u
return NULL;
}
-#if WITH_LIBWPG01
- libwpg::WPGString output;
-#elif WITH_LIBWPG02
- WPXString output;
-#endif
+#if WITH_LIBWPG03
+ librevenge::RVNGStringVector vec;
+ librevenge::RVNGSVGDrawingGenerator generator(vec, "");
+
+ if (!libwpg::WPGraphics::parse(input, &generator) || vec.empty() || vec[0].empty()) {
+ delete input;
+ return NULL;
+ }
+
+ RVNGString output("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n");
+ output.append(vec[0]);
+#else
+ RVNGString output;
if (!libwpg::WPGraphics::generateSVG(input, output)) {
delete input;
return NULL;
}
+#endif
//printf("I've got a doc: \n%s", painter.document.c_str());
diff --git a/src/extension/param/color.cpp b/src/extension/param/color.cpp
index 0a2598c56..5bd70359f 100644
--- a/src/extension/param/color.cpp
+++ b/src/extension/param/color.cpp
@@ -59,9 +59,10 @@ guint32 ParamColor::set( guint32 in, SPDocument * /*doc*/, Inkscape::XML::Node *
return _value;
}
-ParamColor::ParamColor (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, bool gui_hidden, const gchar * gui_tip, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) :
- Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, ext),
- _changeSignal(0)
+ParamColor::ParamColor(const gchar *name, const gchar *guitext, const gchar *desc, const Parameter::_scope_t scope,
+ bool gui_hidden, const gchar *gui_tip, Inkscape::Extension::Extension *ext,
+ Inkscape::XML::Node *xml)
+ : Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, ext), _value(0), _changeSignal(0)
{
const char * defaulthex = NULL;
if (xml->firstChild() != NULL)
@@ -75,7 +76,8 @@ ParamColor::ParamColor (const gchar * name, const gchar * guitext, const gchar *
if (!paramval.empty())
defaulthex = paramval.data();
- _value = atoi(defaulthex);
+ if (defaulthex)
+ _value = atoi(defaulthex);
}
void ParamColor::string(std::string &string) const
@@ -87,7 +89,7 @@ void ParamColor::string(std::string &string) const
Gtk::Widget *ParamColor::get_widget( SPDocument * /*doc*/, Inkscape::XML::Node * /*node*/, sigc::signal<void> * changeSignal )
{
- if (_gui_hidden) return NULL;
+ if (_gui_hidden) return NULL;
_changeSignal = new sigc::signal<void>(*changeSignal);
Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4));
diff --git a/src/extension/param/enum.cpp b/src/extension/param/enum.cpp
index bb50c06e1..74b2a75ad 100644
--- a/src/extension/param/enum.cpp
+++ b/src/extension/param/enum.cpp
@@ -41,8 +41,8 @@ namespace Extension {
class enumentry {
public:
enumentry (Glib::ustring &val, Glib::ustring &text) :
- value(val),
- guitext(text)
+ value(val),
+ guitext(text)
{}
Glib::ustring value;
@@ -50,16 +50,19 @@ public:
};
-ParamComboBox::ParamComboBox (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, bool gui_hidden, const gchar * gui_tip, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) :
- Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, ext), _indent(0)
+ParamComboBox::ParamComboBox(const gchar *name, const gchar *guitext, const gchar *desc,
+ const Parameter::_scope_t scope, bool gui_hidden, const gchar *gui_tip,
+ Inkscape::Extension::Extension *ext, Inkscape::XML::Node *xml)
+ : Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, ext)
+ , _value(NULL)
+ , _indent(0)
+ , choices(NULL)
{
- choices = NULL;
- _value = NULL;
+ const char *xmlval = NULL; // the value stored in XML
- // Read XML tree to add enumeration items:
- // printf("Extension Constructor: ");
if (xml != NULL) {
- for (Inkscape::XML::Node *node = xml->firstChild(); node; node = node->next()) {
+ // Read XML tree to add enumeration items:
+ for (Inkscape::XML::Node *node = xml->firstChild(); node; node = node->next()) {
char const * chname = node->name();
if (!strcmp(chname, INKSCAPE_EXTENSION_NS "item") || !strcmp(chname, INKSCAPE_EXTENSION_NS "_item")) {
Glib::ustring newguitext, newvalue;
@@ -69,8 +72,8 @@ ParamComboBox::ParamComboBox (const gchar * name, const gchar * guitext, const g
}
if (contents != NULL) {
// don't translate when 'item' but do translate when '_item'
- // NOTE: internal extensions use build_from_mem and don't need _item but
- // still need to include if are to be localized
+ // NOTE: internal extensions use build_from_mem and don't need _item but
+ // still need to include if are to be localized
if (!strcmp(chname, INKSCAPE_EXTENSION_NS "_item")) {
if (node->attribute("msgctxt") != NULL) {
newguitext = g_dpgettext2(NULL, node->attribute("msgctxt"), contents);
@@ -95,30 +98,28 @@ ParamComboBox::ParamComboBox (const gchar * name, const gchar * guitext, const g
}
}
}
- }
-
- // Initialize _value with the default value from xml
- // for simplicity : default to the contents of the first xml-child
- const char * defaultval = NULL;
- if (xml->firstChild() && xml->firstChild()->firstChild()) {
- defaultval = xml->firstChild()->attribute("value");
- }
+
+ // Initialize _value with the default value from xml
+ // for simplicity : default to the contents of the first xml-child
+ if (xml->firstChild() && xml->firstChild()->firstChild()) {
+ xmlval = xml->firstChild()->attribute("value");
+ }
- const char * indent = xml->attribute("indent");
- if (indent != NULL) {
- _indent = atoi(indent) * 12;
+ const char *indent = xml->attribute("indent");
+ if (indent != NULL) {
+ _indent = atoi(indent) * 12;
+ }
}
gchar * pref_name = this->pref_name();
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- Glib::ustring paramval = prefs->getString(extension_pref_root + pref_name);
+ Glib::ustring paramval = prefs ? prefs->getString(extension_pref_root + pref_name) : "";
g_free(pref_name);
if (!paramval.empty()) {
- defaultval = paramval.data();
- }
- if (defaultval != NULL) {
- _value = g_strdup(defaultval);
+ _value = g_strdup(paramval.data());
+ } else if (xmlval) {
+ _value = g_strdup(xmlval);
}
}
diff --git a/src/filters/blend.cpp b/src/filters/blend.cpp
index fd5a9871e..ca1d5bf96 100644
--- a/src/filters/blend.cpp
+++ b/src/filters/blend.cpp
@@ -183,6 +183,8 @@ void SPFeBlend::update(SPCtx *ctx, guint flags) {
/* Unlike normal in, in2 is required attribute. Make sure, we can call
* it by some name. */
+ /* This may not be true.... see issue at
+ * http://www.w3.org/TR/filter-effects/#feBlendElement (but it doesn't hurt). */
if (this->in2 == Inkscape::Filters::NR_FILTER_SLOT_NOT_SET ||
this->in2 == Inkscape::Filters::NR_FILTER_UNNAMED_SLOT)
{
@@ -206,26 +208,30 @@ Inkscape::XML::Node* SPFeBlend::write(Inkscape::XML::Document *doc, Inkscape::XM
repr = doc->createElement("svg:feBlend");
}
- gchar const *out_name = sp_filter_name_for_image(parent, this->in2);
+ gchar const *in2_name = sp_filter_name_for_image(parent, this->in2);
- if (out_name) {
- repr->setAttribute("in2", out_name);
- } else {
+ if( !in2_name ) {
+
+ // This code is very similar to sp_filter_primtive_name_previous_out()
SPObject *i = parent->children;
+ // Find previous filter primitive
while (i && i->next != this) {
i = i->next;
}
- SPFilterPrimitive *i_prim = SP_FILTER_PRIMITIVE(i);
- out_name = sp_filter_name_for_image(parent, i_prim->image_out);
- repr->setAttribute("in2", out_name);
-
- if (!out_name) {
- g_warning("Unable to set in2 for feBlend");
+ if( i ) {
+ SPFilterPrimitive *i_prim = SP_FILTER_PRIMITIVE(i);
+ in2_name = sp_filter_name_for_image(parent, i_prim->image_out);
}
}
+ if (in2_name) {
+ repr->setAttribute("in2", in2_name);
+ } else {
+ g_warning("Unable to set in2 for feBlend");
+ }
+
char const *mode;
switch(this->blend_mode) {
case Inkscape::Filters::BLEND_NORMAL:
diff --git a/src/filters/composite.cpp b/src/filters/composite.cpp
index 257292f12..e600b6d20 100644
--- a/src/filters/composite.cpp
+++ b/src/filters/composite.cpp
@@ -205,6 +205,8 @@ void SPFeComposite::update(SPCtx *ctx, guint flags) {
/* Unlike normal in, in2 is required attribute. Make sure, we can call
* it by some name. */
+ /* This may not be true.... see issue at
+ * http://www.w3.org/TR/filter-effects/#feBlendElement (but it doesn't hurt). */
if (this->in2 == Inkscape::Filters::NR_FILTER_SLOT_NOT_SET ||
this->in2 == Inkscape::Filters::NR_FILTER_UNNAMED_SLOT)
{
@@ -228,26 +230,30 @@ Inkscape::XML::Node* SPFeComposite::write(Inkscape::XML::Document *doc, Inkscape
repr = doc->createElement("svg:feComposite");
}
- gchar const *out_name = sp_filter_name_for_image(parent, this->in2);
+ gchar const *in2_name = sp_filter_name_for_image(parent, this->in2);
- if (out_name) {
- repr->setAttribute("in2", out_name);
- } else {
+ if( !in2_name ) {
+
+ // This code is very similar to sp_filter_primitive_name_previous_out()
SPObject *i = parent->children;
+ // Find previous filter primitive
while (i && i->next != this) {
i = i->next;
}
- SPFilterPrimitive *i_prim = SP_FILTER_PRIMITIVE(i);
- out_name = sp_filter_name_for_image(parent, i_prim->image_out);
- repr->setAttribute("in2", out_name);
-
- if (!out_name) {
- g_warning("Unable to set in2 for feComposite");
+ if( i ) {
+ SPFilterPrimitive *i_prim = SP_FILTER_PRIMITIVE(i);
+ in2_name = sp_filter_name_for_image(parent, i_prim->image_out);
}
}
+ if (in2_name) {
+ repr->setAttribute("in2", in2_name);
+ } else {
+ g_warning("Unable to set in2 for feComposite");
+ }
+
char const *comp_op;
switch (this->composite_operator) {
diff --git a/src/filters/displacementmap.cpp b/src/filters/displacementmap.cpp
index 473e4913f..7dedfc031 100644
--- a/src/filters/displacementmap.cpp
+++ b/src/filters/displacementmap.cpp
@@ -202,25 +202,30 @@ Inkscape::XML::Node* SPFeDisplacementMap::write(Inkscape::XML::Document *doc, In
repr = doc->createElement("svg:feDisplacementMap");
}
- gchar const *out_name = sp_filter_name_for_image(parent, this->in2);
- if (out_name) {
- repr->setAttribute("in2", out_name);
- } else {
+ gchar const *in2_name = sp_filter_name_for_image(parent, this->in2);
+
+ if( !in2_name ) {
+
+ // This code is very similar to sp_filter_primtive_name_previous_out()
SPObject *i = parent->children;
+ // Find previous filter primitive
while (i && i->next != this) {
i = i->next;
}
- SPFilterPrimitive *i_prim = SP_FILTER_PRIMITIVE(i);
- out_name = sp_filter_name_for_image(parent, i_prim->image_out);
- repr->setAttribute("in2", out_name);
-
- if (!out_name) {
- g_warning("Unable to set in2 for feDisplacementMap");
+ if( i ) {
+ SPFilterPrimitive *i_prim = SP_FILTER_PRIMITIVE(i);
+ in2_name = sp_filter_name_for_image(parent, i_prim->image_out);
}
}
+ if (in2_name) {
+ repr->setAttribute("in2", in2_name);
+ } else {
+ g_warning("Unable to set in2 for feDisplacementMap");
+ }
+
sp_repr_set_svg_double(repr, "scale", this->scale);
repr->setAttribute("xChannelSelector",
get_channelselector_name(this->xChannelSelector));
diff --git a/src/libnrtype/FontFactory.h b/src/libnrtype/FontFactory.h
index 46df0181a..bd5a4460c 100644
--- a/src/libnrtype/FontFactory.h
+++ b/src/libnrtype/FontFactory.h
@@ -21,7 +21,7 @@
#include <pango/pango.h>
#include "nr-type-primitives.h"
-#include "../style.h"
+#include "style.h"
/* Freetype */
#ifdef USE_PANGO_WIN32
diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt
index 30c2b2f41..c8a02c810 100644
--- a/src/live_effects/CMakeLists.txt
+++ b/src/live_effects/CMakeLists.txt
@@ -15,7 +15,6 @@ set(live_effects_SRC
lpe-dynastroke.cpp
lpe-ellipse-5pts.cpp
lpe-envelope.cpp
- lpe-envelope-perspective.cpp
lpe-extrude.cpp
lpe-fill-between-many.cpp
lpe-fill-between-strokes.cpp
@@ -32,6 +31,7 @@ set(live_effects_SRC
lpe-patternalongpath.cpp
lpe-perp_bisector.cpp
lpe-perspective_path.cpp
+ lpe-perspective-envelope.cpp
lpe-powerstroke.cpp
lpe-recursiveskeleton.cpp
lpe-rough-hatches.cpp
@@ -47,7 +47,6 @@ set(live_effects_SRC
lpe-bspline.cpp
lpe-text_label.cpp
lpe-vonkoch.cpp
- lpe-envelope-perspective.cpp
lpegroupbbox.cpp
lpeobject-reference.cpp
lpeobject.cpp
@@ -106,6 +105,7 @@ set(live_effects_SRC
lpe-patternalongpath.h
lpe-perp_bisector.h
lpe-perspective_path.h
+ lpe-perspective-envelope.h
lpe-powerstroke.h
lpe-powerstroke-interpolators.h
lpe-recursiveskeleton.h
@@ -122,7 +122,6 @@ set(live_effects_SRC
lpe-bspline.h
lpe-text_label.h
lpe-vonkoch.h
- lpe-envelope-perspective.h
lpegroupbbox.h
lpeobject-reference.h
lpeobject.h
diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert
index f18dcdef0..8f0a3ac57 100644
--- a/src/live_effects/Makefile_insert
+++ b/src/live_effects/Makefile_insert
@@ -70,6 +70,8 @@ ink_common_sources += \
live_effects/lpe-circle_with_radius.h \
live_effects/lpe-perspective_path.cpp \
live_effects/lpe-perspective_path.h \
+ live_effects/lpe-perspective-envelope.cpp \
+ live_effects/lpe-perspective-envelope.h \
live_effects/lpe-mirror_symmetry.cpp \
live_effects/lpe-mirror_symmetry.h \
live_effects/lpe-circle_3pts.cpp \
@@ -112,6 +114,4 @@ ink_common_sources += \
live_effects/lpe-jointype.cpp \
live_effects/lpe-jointype.h \
live_effects/lpe-taperstroke.cpp \
- live_effects/lpe-taperstroke.h \
- live_effects/lpe-envelope-perspective.cpp \
- live_effects/lpe-envelope-perspective.h
+ live_effects/lpe-taperstroke.h
diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h
index c53f1a5b9..383eec19e 100644
--- a/src/live_effects/effect-enum.h
+++ b/src/live_effects/effect-enum.h
@@ -63,7 +63,7 @@ enum EffectType {
BOUNDING_BOX,
JOIN_TYPE,
TAPER_STROKE,
- ENVELOPE_PERSPECTIVE,
+ PERSPECTIVE_ENVELOPE,
FILLET_CHAMFER,
INVALID_LPE // This must be last (I made it such that it is not needed anymore I think..., Don't trust on it being last. - johan)
};
diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp
index 22f688873..b002eaf7f 100644
--- a/src/live_effects/effect.cpp
+++ b/src/live_effects/effect.cpp
@@ -25,6 +25,7 @@
#include "live_effects/lpe-curvestitch.h"
#include "live_effects/lpe-circle_with_radius.h"
#include "live_effects/lpe-perspective_path.h"
+#include "live_effects/lpe-perspective-envelope.h"
#include "live_effects/lpe-spiro.h"
#include "live_effects/lpe-lattice.h"
#include "live_effects/lpe-lattice2.h"
@@ -60,7 +61,6 @@
#include "live_effects/lpe-bounding-box.h"
#include "live_effects/lpe-jointype.h"
#include "live_effects/lpe-taperstroke.h"
-#include "live_effects/lpe-envelope-perspective.h"
#include "live_effects/lpe-fillet-chamfer.h"
#include "xml/node-event-vector.h"
@@ -152,7 +152,7 @@ const Util::EnumData<EffectType> LPETypeData[] = {
/* 0.91 */
{SIMPLIFY, N_("Simplify"), "simplify"},
{LATTICE2, N_("Lattice Deformation 2"), "lattice2"},
- {ENVELOPE_PERSPECTIVE, N_("Envelope-Perspective"), "envelope-perspective"},
+ {PERSPECTIVE_ENVELOPE, N_("Perspective/Envelope"), "perspective-envelope"},
{FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet-chamfer"},
{INTERPOLATE_POINTS, N_("Interpolate points"), "interpolate_points"},
};
@@ -311,8 +311,8 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj)
case LATTICE2:
neweffect = static_cast<Effect*> ( new LPELattice2(lpeobj) );
break;
- case ENVELOPE_PERSPECTIVE:
- neweffect = static_cast<Effect*> ( new LPEEnvelopePerspective(lpeobj) );
+ case PERSPECTIVE_ENVELOPE:
+ neweffect = static_cast<Effect*> ( new LPEPerspectiveEnvelope(lpeobj) );
break;
case FILLET_CHAMFER:
neweffect = static_cast<Effect*> ( new LPEFilletChamfer(lpeobj) );
diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp
index 5ba0d697b..7703b8221 100644
--- a/src/live_effects/lpe-bspline.cpp
+++ b/src/live_effects/lpe-bspline.cpp
@@ -59,17 +59,22 @@ const double noPower = 0.0;
const double defaultStartPower = 0.3334;
const double defaultEndPower = 0.6667;
-LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject) :
- Effect(lpeobject),
- steps(_("Steps whith CTRL:"), _("Change number of steps whith CTRL pressed"), "steps", &wr, this, 2),
- ignoreCusp(_("Ignore cusp nodes"), _("Change ignoring cusp nodes"), "ignoreCusp", &wr, this, true),
- onlySelected(_("Change only selected nodes"), _("Change only selected nodes"), "onlySelected", &wr, this, false),
- weight(_("Change weight:"), _("Change weight of the effect"), "weight", &wr, this, defaultStartPower)
+LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject)
+ : Effect(lpeobject),
+ // initialise your parameters here:
+ //testpointA(_("Test Point A"), _("Test A"), "ptA", &wr, this,
+ //Geom::Point(100,100)),
+ steps(_("Steps whith CTRL:"), _("Change number of steps whith CTRL pressed"), "steps", &wr, this, 2),
+ ignoreCusp(_("Ignore cusp nodes"), _("Change ignoring cusp nodes"), "ignoreCusp", &wr, this, true),
+ onlySelected(_("Change only selected nodes"), _("Change only selected nodes"), "onlySelected", &wr, this, false),
+ showHelper(_("Show helper paths"), _("Show helper paths"), "showHelper", &wr, this, false),
+ weight(_("Change weight:"), _("Change weight of the effect"), "weight", &wr, this, defaultStartPower)
{
- registerParameter(&weight);
- registerParameter(&steps);
- registerParameter(&ignoreCusp);
- registerParameter(&onlySelected);
+ registerParameter(dynamic_cast<Parameter *>(&weight));
+ registerParameter(dynamic_cast<Parameter *>(&steps));
+ registerParameter(dynamic_cast<Parameter *>(&ignoreCusp));
+ registerParameter(dynamic_cast<Parameter *>(&onlySelected));
+ registerParameter(dynamic_cast<Parameter *>(&showHelper));
weight.param_set_range(noPower, 1);
weight.param_set_increments(0.1, 0.1);
@@ -89,7 +94,9 @@ void LPEBSpline::doBeforeEffect (SPLPEItem const* lpeitem)
}
}
-void LPEBSpline::createAndApply(const char *name, SPDocument *doc, SPItem *item)
+
+void LPEBSpline::createAndApply(const char *name, SPDocument *doc,
+ SPItem *item)
{
if (!SP_IS_SHAPE(item)) {
g_warning("LPE BSpline can only be applied to shapes (not groups).");
@@ -99,7 +106,8 @@ void LPEBSpline::createAndApply(const char *name, SPDocument *doc, SPItem *item)
Inkscape::XML::Node *repr = xml_doc->createElement("inkscape:path-effect");
repr->setAttribute("effect", name);
- doc->getDefs()->getRepr()->addChild(repr, NULL); // adds to <defs> and assigns the 'id' attribute
+ doc->getDefs()->getRepr()
+ ->addChild(repr, NULL); // adds to <defs> and assigns the 'id' attribute
const gchar *repr_id = repr->attribute("id");
Inkscape::GC::release(repr);
@@ -111,13 +119,13 @@ void LPEBSpline::createAndApply(const char *name, SPDocument *doc, SPItem *item)
void LPEBSpline::doEffect(SPCurve *curve)
{
+
if (curve->get_segment_count() < 1){
return;
}
-
+ // Make copy of old path as it is changed during processing
Geom::PathVector const original_pathv = curve->get_pathvector();
curve->reset();
-
double radiusHelperNodes = 6.0;
SPDesktop *desktop = SP_ACTIVE_DESKTOP;
if (desktop){
@@ -125,7 +133,6 @@ void LPEBSpline::doEffect(SPCurve *curve)
SPNamedView *nv = sp_desktop_namedview(desktop);
radiusHelperNodes = Inkscape::Util::Quantity::convert(radiusHelperNodes, "px", nv->doc_units->abbr);
}
-
for (Geom::PathVector::const_iterator path_it = original_pathv.begin();
path_it != original_pathv.end(); ++path_it) {
if (path_it->empty())
@@ -133,7 +140,7 @@ void LPEBSpline::doEffect(SPCurve *curve)
Geom::Path::const_iterator curve_it1 = path_it->begin();
Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
- Geom::Path::const_iterator curve_endit = path_it->end_default();
+ Geom::Path::const_iterator curve_endit = path_it->end_default();
SPCurve *nCurve = new SPCurve();
Geom::Point previousNode(0, 0);
Geom::Point node(0, 0);
@@ -145,13 +152,29 @@ void LPEBSpline::doEffect(SPCurve *curve)
Geom::D2<Geom::SBasis> SBasisHelper;
Geom::CubicBezier const *cubic = NULL;
if (path_it->closed()) {
- const Geom::Curve &closingline = path_it->back_closed();
+ // if the path is closed, maybe we have to stop a bit earlier because the
+ // closing line segment has zerolength.
+ const Geom::Curve &closingline =
+ path_it->back_closed(); // the closing line segment is always of type
+ // Geom::LineSegment.
if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
+ // closingline.isDegenerate() did not work, because it only checks for
+ // *exact* zero length, which goes wrong for relative coordinates and
+ // rounding errors...
+ // the closing line segment has zero-length. So stop before that one!
curve_endit = path_it->end_open();
}
}
+ //Si la curva está cerrada calculamos el punto donde
+ //deveria estar el nodo BSpline de cierre/inicio de la curva
+ //en posible caso de que se cierre con una linea recta creando un nodo
+ //BSPline
nCurve->moveto(curve_it1->initialPoint());
+ //Recorremos todos los segmentos menos el último
while (curve_it1 != curve_endit) {
+ //previousPointAt3 = pointAt3;
+ //Calculamos los puntos que dividirían en tres segmentos iguales el path
+ //recto de entrada y de salida
SPCurve *in = new SPCurve();
in->moveto(curve_it1->initialPoint());
in->lineto(curve_it1->finalPoint());
@@ -192,7 +215,6 @@ void LPEBSpline::doEffect(SPCurve *curve)
out->reset();
delete out;
}
- Geom::Point startNode = path_it->begin()->initialPoint();
if (path_it->closed() && curve_it2 == curve_endit) {
SPCurve *start = new SPCurve();
start->moveto(path_it->begin()->initialPoint());
@@ -225,9 +247,9 @@ void LPEBSpline::doEffect(SPCurve *curve)
SBasisHelper = lineHelper->first_segment()->toSBasis();
lineHelper->reset();
delete lineHelper;
- startNode = SBasisHelper.valueAt(0.5);
- nCurve->curveto(pointAt1, pointAt2, startNode);
- nCurve->move_endpoints(startNode, startNode);
+ node = SBasisHelper.valueAt(0.5);
+ nCurve->curveto(pointAt1, pointAt2, node);
+ nCurve->move_endpoints(node, node);
} else if ( curve_it2 == curve_endit) {
nCurve->curveto(pointAt1, pointAt2, curve_it1->finalPoint());
nCurve->move_endpoints(path_it->begin()->initialPoint(), curve_it1->finalPoint());
@@ -238,17 +260,26 @@ void LPEBSpline::doEffect(SPCurve *curve)
SBasisHelper = lineHelper->first_segment()->toSBasis();
lineHelper->reset();
delete lineHelper;
+ //almacenamos el punto del anterior bucle -o el de cierre- que nos hara de
+ //principio de curva
previousNode = node;
+ //Y este hará de final de curva
node = SBasisHelper.valueAt(0.5);
Geom::CubicBezier const *cubic2 = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1);
if((cubic && are_near((*cubic)[0],(*cubic)[1])) || (cubic2 && are_near((*cubic2)[2],(*cubic2)[3]))) {
node = curve_it1->finalPoint();
}
nCurve->curveto(pointAt1, pointAt2, node);
- if(!are_near(node,curve_it1->finalPoint())){
- drawHandle(node, radiusHelperNodes);
- }
}
+ if(!are_near(node,curve_it1->finalPoint()) && showHelper){
+ drawHandle(node, radiusHelperNodes);
+ }
+ //La curva BSpline se forma calculando el centro del segmanto de unión
+ //de el punto situado en las 2/3 partes de el segmento de entrada
+ //con el punto situado en la posición 1/3 del segmento de salida
+ //Estos dos puntos ademas estan posicionados en el lugas correspondiente
+ //de los manejadores de la curva
+ //aumentamos los valores para el siguiente paso en el bucle
++curve_it1;
++curve_it2;
}
@@ -259,6 +290,8 @@ void LPEBSpline::doEffect(SPCurve *curve)
curve->append(nCurve, false);
nCurve->reset();
delete nCurve;
+ }
+ if(showHelper){
Geom::PathVector const pathv = curve->get_pathvector();
hp.push_back(pathv[0]);
}
@@ -293,32 +326,44 @@ Gtk::Widget *LPEBSpline::newWidget()
while (it != param_vector.end()) {
if ((*it)->widget_is_visible) {
Parameter *param = *it;
- Gtk::Widget *widg = Gtk::manage(param->param_newWidget());
+ Gtk::Widget *widg = dynamic_cast<Gtk::Widget *>(param->param_newWidget());
if (param->param_key == "weight") {
- Gtk::HBox * buttons = Gtk::manage(new Gtk::HBox(true, 0));
-
- Gtk::Button *defaultWeight = Gtk::manage(new Gtk::Button(Glib::ustring(_("Default weight"))));
- defaultWeight->signal_clicked().connect(sigc::bind<Gtk::Widget *>(sigc::mem_fun(*this, &LPEBSpline::toDefaultWeight), widg));
+ Gtk::HBox * buttons = Gtk::manage(new Gtk::HBox(true,0));
+ Gtk::Button *defaultWeight =
+ Gtk::manage(new Gtk::Button(Glib::ustring(_("Default weight"))));
+ defaultWeight->signal_clicked()
+ .connect(sigc::bind<Gtk::Widget *>(sigc::mem_fun(*this, &LPEBSpline::toDefaultWeight), widg));
buttons->pack_start(*defaultWeight, true, true, 2);
-
- Gtk::Button *makeCusp = Gtk::manage(new Gtk::Button(Glib::ustring(_("Make cusp"))));
- makeCusp->signal_clicked().connect(sigc::bind<Gtk::Widget *>(sigc::mem_fun(*this, &LPEBSpline::toMakeCusp), widg));
+ Gtk::Button *makeCusp =
+ Gtk::manage(new Gtk::Button(Glib::ustring(_("Make cusp"))));
+ makeCusp->signal_clicked()
+ .connect(sigc::bind<Gtk::Widget *>(sigc::mem_fun(*this, &LPEBSpline::toMakeCusp), widg));
buttons->pack_start(*makeCusp, true, true, 2);
-
vbox->pack_start(*buttons, true, true, 2);
}
if (param->param_key == "weight" || param->param_key == "steps") {
- Inkscape::UI::Widget::Scalar *widgRegistered = Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg));
- widgRegistered->signal_value_changed().connect(sigc::mem_fun(*this, &LPEBSpline::toWeight));
-
+ Inkscape::UI::Widget::Scalar *widgRegistered =
+ Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg));
+ widgRegistered->signal_value_changed()
+ .connect(sigc::mem_fun(*this, &LPEBSpline::toWeight));
+ widg = dynamic_cast<Gtk::Widget *>(widgRegistered);
if (widg) {
Gtk::HBox * scalarParameter = dynamic_cast<Gtk::HBox *>(widg);
- std::vector<Gtk::Widget *> childList = scalarParameter->get_children();
+ std::vector< Gtk::Widget* > childList = scalarParameter->get_children();
Gtk::Entry* entryWidg = dynamic_cast<Gtk::Entry *>(childList[1]);
entryWidg->set_width_chars(6);
}
}
-
+ if (param->param_key == "onlySelected") {
+ Gtk::CheckButton *widgRegistered =
+ Gtk::manage(dynamic_cast<Gtk::CheckButton *>(widg));
+ widg = dynamic_cast<Gtk::Widget *>(widgRegistered);
+ }
+ if (param->param_key == "ignoreCusp") {
+ Gtk::CheckButton *widgRegistered =
+ Gtk::manage(dynamic_cast<Gtk::CheckButton *>(widg));
+ widg = dynamic_cast<Gtk::Widget *>(widgRegistered);
+ }
Glib::ustring *tip = param->param_getTooltip();
if (widg) {
vbox->pack_start(*widg, true, true, 2);
@@ -333,7 +378,7 @@ Gtk::Widget *LPEBSpline::newWidget()
++it;
}
- return vbox;
+ return dynamic_cast<Gtk::Widget *>(vbox);
}
void LPEBSpline::toDefaultWeight(Gtk::Widget *widgWeight)
@@ -379,7 +424,8 @@ void LPEBSpline::changeWeight(double weightValue)
g_free(str);
curve->unref();
desktop->clearWaitingCursor();
- DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_LPE, _("Modified the weight of a BSpline"));
+ DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_LPE,
+ _("Modified the weight of the BSpline"));
}
bool LPEBSpline::nodeIsSelected(Geom::Point nodePoint)
diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h
index e066015ad..169658b94 100644
--- a/src/live_effects/lpe-bspline.h
+++ b/src/live_effects/lpe-bspline.h
@@ -24,19 +24,16 @@ public:
return SUPPRESS_FLASH;
}
virtual void doEffect(SPCurve *curve);
- virtual void doBeforeEffect(SPLPEItem const* lpeitem);
+ virtual void doBeforeEffect (SPLPEItem const* lpeitem);
void drawHandle(Geom::Point p, double radiusHelperNodes);
void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec);
-
- void doBSplineFromWidget(SPCurve *curve, double value);
- bool nodeIsSelected(Geom::Point nodePoint);
-
+ virtual void doBSplineFromWidget(SPCurve *curve, double value);
+ virtual bool nodeIsSelected(Geom::Point nodePoint);
virtual Gtk::Widget *newWidget();
-
- void changeWeight(double weightValue);
- void toDefaultWeight(Gtk::Widget *widgWeight);
- void toMakeCusp(Gtk::Widget *widgWeight);
- void toWeight();
+ virtual void changeWeight(double weightValue);
+ virtual void toDefaultWeight(Gtk::Widget *widgWeight);
+ virtual void toMakeCusp(Gtk::Widget *widgWeight);
+ virtual void toWeight();
// TODO make this private
ScalarParam steps;
@@ -45,6 +42,7 @@ private:
std::vector<Geom::Point> points;
BoolParam ignoreCusp;
BoolParam onlySelected;
+ BoolParam showHelper;
ScalarParam weight;
Geom::PathVector hp;
diff --git a/src/live_effects/lpe-envelope-perspective.cpp b/src/live_effects/lpe-perspective-envelope.cpp
index 378ef5a92..6f6838c81 100644
--- a/src/live_effects/lpe-envelope-perspective.cpp
+++ b/src/live_effects/lpe-perspective-envelope.cpp
@@ -1,5 +1,5 @@
/** \file
- * LPE <envelope-perspective> implementation
+ * LPE <perspective-envelope> implementation
*/
/*
@@ -15,7 +15,7 @@
*/
#include <gtkmm.h>
-#include "live_effects/lpe-envelope-perspective.h"
+#include "live_effects/lpe-perspective-envelope.h"
#include "helper/geom.h"
#include "display/curve.h"
#include "svg/svg.h"
@@ -29,21 +29,21 @@ namespace Inkscape {
namespace LivePathEffect {
enum DeformationType {
- DEFORMATION_ENVELOPE,
- DEFORMATION_PERSPECTIVE
+ DEFORMATION_PERSPECTIVE,
+ DEFORMATION_ENVELOPE
};
static const Util::EnumData<unsigned> DeformationTypeData[] = {
- {DEFORMATION_ENVELOPE , N_("Envelope deformation"), "Envelope deformation"},
- {DEFORMATION_PERSPECTIVE , N_("Perspective"), "Perspective"}
+ {DEFORMATION_PERSPECTIVE , N_("Perspective"), "Perspective"},
+ {DEFORMATION_ENVELOPE , N_("Envelope deformation"), "Envelope deformation"}
};
static const Util::EnumDataConverter<unsigned> DeformationTypeConverter(DeformationTypeData, sizeof(DeformationTypeData)/sizeof(*DeformationTypeData));
-LPEEnvelopePerspective::LPEEnvelopePerspective(LivePathEffectObject *lpeobject) :
+LPEPerspectiveEnvelope::LPEPerspectiveEnvelope(LivePathEffectObject *lpeobject) :
Effect(lpeobject),
// initialise your parameters here:
- deform_type(_("Type"), _("Select the type of deformation"), "deform_type", DeformationTypeConverter, &wr, this, DEFORMATION_ENVELOPE),
+ deform_type(_("Type"), _("Select the type of deformation"), "deform_type", DeformationTypeConverter, &wr, this, DEFORMATION_PERSPECTIVE),
Up_Left_Point(_("Top Left"), _("Top Left - Ctrl+Alt+Click to reset"), "Up_Left_Point", &wr, this),
Up_Right_Point(_("Top Right"), _("Top Right - Ctrl+Alt+Click to reset"), "Up_Right_Point", &wr, this),
Down_Left_Point(_("Down Left"), _("Down Left - Ctrl+Alt+Click to reset"), "Down_Left_Point", &wr, this),
@@ -57,11 +57,11 @@ LPEEnvelopePerspective::LPEEnvelopePerspective(LivePathEffectObject *lpeobject)
registerParameter( dynamic_cast<Parameter *>(&Down_Right_Point) );
}
-LPEEnvelopePerspective::~LPEEnvelopePerspective()
+LPEPerspectiveEnvelope::~LPEPerspectiveEnvelope()
{
}
-void LPEEnvelopePerspective::doEffect(SPCurve *curve) {
+void LPEPerspectiveEnvelope::doEffect(SPCurve *curve) {
using Geom::X;
using Geom::Y;
double projmatrix[3][3];
@@ -135,32 +135,23 @@ void LPEEnvelopePerspective::doEffect(SPCurve *curve) {
continue;
//Itreadores
SPCurve *nCurve = new SPCurve();
- Geom::Path::const_iterator curve_it1 = path_it->begin(); // incoming curve
- Geom::Path::const_iterator curve_it2 =
- ++(path_it->begin()); // outgoing curve
- Geom::Path::const_iterator curve_endit =
- path_it->end_default(); // this determines when the loop has to stop
+ Geom::Path::const_iterator curve_it1 = path_it->begin();
+ Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
+ Geom::Path::const_iterator curve_endit = path_it->end_default();
if (path_it->closed()) {
- // if the path is closed, maybe we have to stop a bit earlier because the
- // closing line segment has zerolength.
- const Geom::Curve &closingline =
- path_it->back_closed(); // the closing line segment is always of type
- // Geom::LineSegment.
- if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
- // closingline.isDegenerate() did not work, because it only checks for
- // *exact* zero length, which goes wrong for relative coordinates and
- // rounding errors...
- // the closing line segment has zero-length. So stop before that one!
- curve_endit = path_it->end_open();
- }
+ const Geom::Curve &closingline =
+ path_it->back_closed();
+ if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
+ curve_endit = path_it->end_open();
+ }
}
if(deform_type == DEFORMATION_PERSPECTIVE){
nCurve->moveto(project_point(curve_it1->initialPoint(),projmatrix));
}else{
nCurve->moveto(project_point(curve_it1->initialPoint()));
}
- while (curve_it2 != curve_endit) {
+ while (curve_it1 != curve_endit) {
cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1);
if (cubic) {
pointAt1 = (*cubic)[1];
@@ -181,34 +172,13 @@ void LPEEnvelopePerspective::doEffect(SPCurve *curve) {
}
nCurve->curveto(pointAt1, pointAt2, pointAt3);
++curve_it1;
- ++curve_it2;
- }
- cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1);
- if (cubic) {
- pointAt1 = (*cubic)[1];
- pointAt2 = (*cubic)[2];
- } else {
- pointAt1 = curve_it1->initialPoint();
- pointAt2 = curve_it1->finalPoint();
- }
- pointAt3 = curve_it1->finalPoint();
- if(deform_type == DEFORMATION_PERSPECTIVE){
- pointAt1 = project_point(pointAt1,projmatrix);
- pointAt2 = project_point(pointAt2,projmatrix);
- pointAt3 = project_point(pointAt3,projmatrix);
- }else{
- pointAt1 = project_point(pointAt1);
- pointAt2 = project_point(pointAt2);
- pointAt3 = project_point(pointAt3);
- }
- nCurve->curveto(pointAt1, pointAt2, pointAt3);
- if(deform_type == DEFORMATION_PERSPECTIVE){
- nCurve->move_endpoints(project_point(path_it->begin()->initialPoint(),projmatrix), pointAt3);
- }else{
- nCurve->move_endpoints(project_point(path_it->begin()->initialPoint()), pointAt3);
+ if(curve_it2 != curve_endit) {
+ ++curve_it2;
+ }
}
//y cerramos la curva
if (path_it->closed()) {
+ nCurve->move_endpoints(pointAt3, pointAt3);
nCurve->closepath_current();
}
curve->append(nCurve, false);
@@ -218,11 +188,13 @@ void LPEEnvelopePerspective::doEffect(SPCurve *curve) {
}
Geom::Point
-LPEEnvelopePerspective::project_point(Geom::Point p){
+LPEPerspectiveEnvelope::project_point(Geom::Point p){
double width = boundingbox_X.extent();
double height = boundingbox_Y.extent();
- Geom::Coord xratio = abs(Geom::Point(boundingbox_X.min(), boundingbox_Y.max())[X]-p[X])/width;
- Geom::Coord yratio = abs(Geom::Point(boundingbox_X.min(), boundingbox_Y.max())[Y]-p[Y])/height;
+ double delta_x = boundingbox_X.min() - p[X];
+ double delta_y = boundingbox_Y.max() - p[Y];
+ Geom::Coord xratio = (delta_x * sgn(delta_x)) / width;
+ Geom::Coord yratio = (delta_y * sgn(delta_y)) / height;
Geom::Line* horiz = new Geom::Line();
Geom::Line* vert = new Geom::Line();
vert->setPoints (pointAtRatio(yratio,Down_Left_Point,Up_Left_Point),pointAtRatio(yratio,Down_Right_Point,Up_Right_Point));
@@ -237,7 +209,7 @@ LPEEnvelopePerspective::project_point(Geom::Point p){
}
Geom::Point
-LPEEnvelopePerspective::project_point(Geom::Point p, double m[][3]){
+LPEPerspectiveEnvelope::project_point(Geom::Point p, double m[][3]){
Geom::Coord x = p[0];
Geom::Coord y = p[1];
return Geom::Point(
@@ -246,7 +218,7 @@ LPEEnvelopePerspective::project_point(Geom::Point p, double m[][3]){
}
Geom::Point
-LPEEnvelopePerspective::pointAtRatio(Geom::Coord ratio,Geom::Point A, Geom::Point B){
+LPEPerspectiveEnvelope::pointAtRatio(Geom::Coord ratio,Geom::Point A, Geom::Point B){
Geom::Coord x = A[X] + (ratio * (B[X]-A[X]));
Geom::Coord y = A[Y]+ (ratio * (B[Y]-A[Y]));
return Point(x, y);
@@ -254,7 +226,7 @@ LPEEnvelopePerspective::pointAtRatio(Geom::Coord ratio,Geom::Point A, Geom::Poin
Gtk::Widget *
-LPEEnvelopePerspective::newWidget()
+LPEPerspectiveEnvelope::newWidget()
{
// use manage here, because after deletion of Effect object, others might still be pointing to this widget.
Gtk::VBox * vbox = Gtk::manage( new Gtk::VBox(Effect::newWidget()) );
@@ -285,20 +257,12 @@ LPEEnvelopePerspective::newWidget()
Gtk::Label* handles = Gtk::manage(new Gtk::Label(Glib::ustring(_("Handles:")),Gtk::ALIGN_START));
vbox->pack_start(*handles, false, false, 2);
hboxUpHandles->pack_start(*widg, true, true, 2);
-#if WITH_GTKMM_3_0
- hboxUpHandles->pack_start(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_VERTICAL)), Gtk::PACK_EXPAND_WIDGET);
-#else
hboxUpHandles->pack_start(*Gtk::manage(new Gtk::VSeparator()), Gtk::PACK_EXPAND_WIDGET);
-#endif
}else if(param->param_key == "Up_Right_Point"){
hboxUpHandles->pack_start(*widg, true, true, 2);
}else if(param->param_key == "Down_Left_Point"){
hboxDownHandles->pack_start(*widg, true, true, 2);
-#if WITH_GTKMM_3_0
- hboxDownHandles->pack_start(*Gtk::manage(new Gtk::Separator(Gtk::ORIENTATION_VERTICAL)), Gtk::PACK_EXPAND_WIDGET);
-#else
hboxDownHandles->pack_start(*Gtk::manage(new Gtk::VSeparator()), Gtk::PACK_EXPAND_WIDGET);
-#endif
}else{
hboxDownHandles->pack_start(*widg, true, true, 2);
}
@@ -327,18 +291,13 @@ LPEEnvelopePerspective::newWidget()
}
vbox->pack_start(*hboxUpHandles,true, true, 2);
Gtk::HBox * hboxMiddle = Gtk::manage(new Gtk::HBox(true,2));
-#if WITH_GTKMM_3_0
- hboxMiddle->pack_start(*Gtk::manage(new Gtk::Separator()), Gtk::PACK_EXPAND_WIDGET);
- hboxMiddle->pack_start(*Gtk::manage(new Gtk::Separator()), Gtk::PACK_EXPAND_WIDGET);
-#else
hboxMiddle->pack_start(*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_EXPAND_WIDGET);
hboxMiddle->pack_start(*Gtk::manage(new Gtk::HSeparator()), Gtk::PACK_EXPAND_WIDGET);
-#endif
vbox->pack_start(*hboxMiddle, false, true, 2);
vbox->pack_start(*hboxDownHandles, true, true, 2);
Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false,0));
Gtk::Button* resetButton = Gtk::manage(new Gtk::Button(Gtk::Stock::CLEAR));
- resetButton->signal_clicked().connect(sigc::mem_fun (*this,&LPEEnvelopePerspective::resetGrid));
+ resetButton->signal_clicked().connect(sigc::mem_fun (*this,&LPEPerspectiveEnvelope::resetGrid));
resetButton->set_size_request(140,45);
vbox->pack_start(*hbox, true,true,2);
hbox->pack_start(*resetButton, false, false,2);
@@ -346,17 +305,14 @@ LPEEnvelopePerspective::newWidget()
}
void
-LPEEnvelopePerspective::doBeforeEffect (SPLPEItem const* lpeitem)
+LPEPerspectiveEnvelope::doBeforeEffect (SPLPEItem const* lpeitem)
{
original_bbox(lpeitem);
setDefaults();
- SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem);
- item->apply_to_clippath(item);
- item->apply_to_mask(item);
}
void
-LPEEnvelopePerspective::setDefaults()
+LPEPerspectiveEnvelope::setDefaults()
{
Geom::Point Up_Left(boundingbox_X.min(), boundingbox_Y.min());
Geom::Point Up_Right(boundingbox_X.max(), boundingbox_Y.min());
@@ -370,7 +326,7 @@ LPEEnvelopePerspective::setDefaults()
}
void
-LPEEnvelopePerspective::resetGrid()
+LPEPerspectiveEnvelope::resetGrid()
{
Up_Left_Point.param_set_and_write_default();
Up_Right_Point.param_set_and_write_default();
@@ -384,7 +340,7 @@ LPEEnvelopePerspective::resetGrid()
}
void
-LPEEnvelopePerspective::resetDefaults(SPItem const* item)
+LPEPerspectiveEnvelope::resetDefaults(SPItem const* item)
{
Effect::resetDefaults(item);
original_bbox(SP_LPE_ITEM(item));
@@ -393,19 +349,7 @@ LPEEnvelopePerspective::resetDefaults(SPItem const* item)
}
void
-LPEEnvelopePerspective::calculateCurve(Geom::Point a,Geom::Point b, SPCurve* c, bool horizontal, bool move)
-{
- using Geom::X;
- using Geom::Y;
- if(move) c->moveto(a);
- Geom::Point cubic1 = a + (1./3)* (b - a);
- Geom::Point cubic2 = b + (1./3)* (a - b);
- if(horizontal) c->curveto(Geom::Point(cubic1[X],a[Y]),Geom::Point(cubic2[X],b[Y]),b);
- else c->curveto(Geom::Point(a[X],cubic1[Y]),Geom::Point(b[X],cubic2[Y]),b);
-}
-
-void
-LPEEnvelopePerspective::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
+LPEPerspectiveEnvelope::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
{
hp_vec.clear();
@@ -437,4 +381,4 @@ LPEEnvelopePerspective::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::v
fill-column:99
End:
*/
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: file_type=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/live_effects/lpe-envelope-perspective.h b/src/live_effects/lpe-perspective-envelope.h
index 0de9a0e35..2f253882e 100644
--- a/src/live_effects/lpe-envelope-perspective.h
+++ b/src/live_effects/lpe-perspective-envelope.h
@@ -1,8 +1,8 @@
-#ifndef INKSCAPE_LPE_ENVELOPE_PERSPECTIVE_H
-#define INKSCAPE_LPE_ENVELOPE_PERSPECTIVE_H
+#ifndef INKSCAPE_LPE_PERSPECTIVE_ENVELOPE_H
+#define INKSCAPE_LPE_PERSPECTIVE_ENVELOPE_H
/** \file
- * LPE <envelope-perspective> implementation , see lpe-envelope-perspective.cpp.
+ * LPE <perspective-envelope> implementation , see lpe-perspective-envelope.cpp.
*/
/*
@@ -25,11 +25,12 @@
namespace Inkscape {
namespace LivePathEffect {
-class LPEEnvelopePerspective : public Effect, GroupBBoxEffect {
+class LPEPerspectiveEnvelope : public Effect, GroupBBoxEffect {
public:
- LPEEnvelopePerspective(LivePathEffectObject *lpeobject);
- virtual ~LPEEnvelopePerspective();
+ LPEPerspectiveEnvelope(LivePathEffectObject *lpeobject);
+
+ virtual ~LPEPerspectiveEnvelope();
virtual void doEffect(SPCurve *curve);
@@ -37,7 +38,7 @@ public:
virtual Geom::Point project_point(Geom::Point p, double m[][3]);
- Geom::Point pointAtRatio(Geom::Coord ratio,Geom::Point A, Geom::Point B);
+ virtual Geom::Point pointAtRatio(Geom::Coord ratio,Geom::Point A, Geom::Point B);
virtual void resetDefaults(SPItem const* item);
@@ -45,17 +46,10 @@ public:
virtual Gtk::Widget * newWidget();
- virtual void calculateCurve(Geom::Point a,Geom::Point b, SPCurve *c, bool horizontal, bool move);
-
virtual void setDefaults();
virtual void resetGrid();
- //virtual void original_bbox(SPLPEItem const* lpeitem, bool absolute = false);
-
- //virtual void addCanvasIndicators(SPLPEItem const*/*lpeitem*/, std::vector<Geom::PathVector> &/*hp_vec*/);
-
- //virtual std::vector<Geom::PathVector> getHelperPaths(SPLPEItem const* lpeitem);
protected:
void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec);
private:
@@ -66,8 +60,8 @@ private:
PointReseteableParam Down_Left_Point;
PointReseteableParam Down_Right_Point;
- LPEEnvelopePerspective(const LPEEnvelopePerspective&);
- LPEEnvelopePerspective& operator=(const LPEEnvelopePerspective&);
+ LPEPerspectiveEnvelope(const LPEPerspectiveEnvelope&);
+ LPEPerspectiveEnvelope& operator=(const LPEPerspectiveEnvelope&);
};
} //namespace LivePathEffect
diff --git a/src/live_effects/lpe-vonkoch.cpp b/src/live_effects/lpe-vonkoch.cpp
index 7c1913076..b52816c87 100644
--- a/src/live_effects/lpe-vonkoch.cpp
+++ b/src/live_effects/lpe-vonkoch.cpp
@@ -132,8 +132,8 @@ LPEVonKoch::doEffect_path (std::vector<Geom::Path> const & path_in)
int path_in_complexity = 0;
for (unsigned k = 0; k < path_in.size(); k++){
path_in_complexity+=path_in[k].size();
- }
- double complexity = std::pow(transforms.size(),nbgenerations)*path_in_complexity;
+ }
+ double complexity = std::pow(transforms.size(), nbgenerations) * path_in_complexity;
if (drawall.get_value()){
int k = transforms.size();
if(k>1){
@@ -141,8 +141,6 @@ LPEVonKoch::doEffect_path (std::vector<Geom::Path> const & path_in)
}else{
complexity = nbgenerations*k*path_in_complexity;
}
- }else{
- complexity = std::pow(transforms.size(),nbgenerations)*path_in_complexity;
}
if (complexity > double(maxComplexity)){
g_warning("VonKoch lpe's output too complex. Effect bypassed.");
diff --git a/src/object-snapper.cpp b/src/object-snapper.cpp
index 9ff6df3bf..2b29814b0 100644
--- a/src/object-snapper.cpp
+++ b/src/object-snapper.cpp
@@ -289,7 +289,7 @@ void Inkscape::ObjectSnapper::_snapNodes(IntermSnapResults &isr,
for (std::vector<SnapCandidatePoint>::const_iterator k = _points_to_snap_to->begin(); k != _points_to_snap_to->end(); ++k) {
if (_allowSourceToSnapToTarget(p.getSourceType(), (*k).getTargetType(), strict_snapping)) {
Geom::Point target_pt = (*k).getPoint();
- Geom::Coord dist = Geom::infinity();
+ Geom::Coord dist = Geom::L2(target_pt - p.getPoint()); // Default: free (unconstrained) snapping
if (!c.isUndefined()) {
// We're snapping to nodes along a constraint only, so find out if this node
// is at the constraint, while allowing for a small margin
@@ -299,9 +299,6 @@ void Inkscape::ObjectSnapper::_snapNodes(IntermSnapResults &isr,
continue;
}
dist = Geom::L2(target_pt - p_proj_on_constraint);
- } else {
- // Free (unconstrained) snapping
- dist = Geom::L2(target_pt - p.getPoint());
}
if (dist < getSnapperTolerance() && dist < s.getSnapDistance()) {
diff --git a/src/path-chemistry.cpp b/src/path-chemistry.cpp
index a72601276..fe241381f 100644
--- a/src/path-chemistry.cpp
+++ b/src/path-chemistry.cpp
@@ -79,6 +79,7 @@ sp_selected_path_combine(SPDesktop *desktop)
items = g_slist_sort(items, (GCompareFunc) sp_item_repr_compare_position);
items = g_slist_reverse(items);
+ assert(items); // cannot be NULL because of list length check at top of function
// remember the position, id, transform and style of the topmost path, they will be assigned to the combined one
gint position = 0;
diff --git a/src/path-prefix.h b/src/path-prefix.h
index 6ef0ccbe9..7042d5124 100644
--- a/src/path-prefix.h
+++ b/src/path-prefix.h
@@ -66,23 +66,23 @@
# define CREATE_PALETTESDIR WIN32_DATADIR("create\\swatches")
# define CREATE_PATTERNSDIR WIN32_DATADIR("create\\patterns\\vector")
# elif defined ENABLE_OSX_APP_LOCATIONS
-# define INKSCAPE_APPICONDIR "Contents/Resources/pixmaps"
-# define INKSCAPE_ATTRRELDIR "Contents/Resources/attributes"
-# define INKSCAPE_BINDDIR "Contents/Resources/bind"
-# define INKSCAPE_EXAMPLESDIR "Contents/Resources/examples"
-# define INKSCAPE_EXTENSIONDIR "Contents/Resources/extensions"
-# define INKSCAPE_FILTERDIR "Contents/Resources/filters"
-# define INKSCAPE_GRADIENTSDIR "Contents/Resources/gradients"
-# define INKSCAPE_KEYSDIR "Contents/Resources/keys"
-# define INKSCAPE_PIXMAPDIR "Contents/Resources/icons"
-# define INKSCAPE_MARKERSDIR "Contents/Resources/markers"
-# define INKSCAPE_PALETTESDIR "Contents/Resources/palettes"
-# define INKSCAPE_PATTERNSDIR "Contents/Resources/patterns"
-# define INKSCAPE_SCREENSDIR "Contents/Resources/screens"
-# define INKSCAPE_SYMBOLSDIR "Contents/Resources/symbols"
-# define INKSCAPE_TUTORIALSDIR "Contents/Resources/tutorials"
-# define INKSCAPE_TEMPLATESDIR "Contents/Resources/templates"
-# define INKSCAPE_UIDIR "Contents/Resources/ui"
+# define INKSCAPE_APPICONDIR "Contents/Resources/share/pixmaps"
+# define INKSCAPE_ATTRRELDIR "Contents/Resources/share/inkscape/attributes"
+# define INKSCAPE_BINDDIR "Contents/Resources/share/inkscape/bind"
+# define INKSCAPE_EXAMPLESDIR "Contents/Resources/share/inkscape/examples"
+# define INKSCAPE_EXTENSIONDIR "Contents/Resources/share/inkscape/extensions"
+# define INKSCAPE_FILTERDIR "Contents/Resources/share/inkscape/filters"
+# define INKSCAPE_GRADIENTSDIR "Contents/Resources/share/inkscape/gradients"
+# define INKSCAPE_KEYSDIR "Contents/Resources/share/inkscape/keys"
+# define INKSCAPE_PIXMAPDIR "Contents/Resources/share/inkscape/icons"
+# define INKSCAPE_MARKERSDIR "Contents/Resources/share/inkscape/markers"
+# define INKSCAPE_PALETTESDIR "Contents/Resources/share/inkscape/palettes"
+# define INKSCAPE_PATTERNSDIR "Contents/Resources/share/inkscape/patterns"
+# define INKSCAPE_SCREENSDIR "Contents/Resources/share/inkscape/screens"
+# define INKSCAPE_SYMBOLSDIR "Contents/Resources/share/inkscape/symbols"
+# define INKSCAPE_TUTORIALSDIR "Contents/Resources/share/inkscape/tutorials"
+# define INKSCAPE_TEMPLATESDIR "Contents/Resources/share/inkscape/templates"
+# define INKSCAPE_UIDIR "Contents/Resources/share/inkscape/ui"
//CREATE V0.1 support
# define CREATE_GRADIENTSDIR "/Library/Application Support/create/gradients/gimp"
# define CREATE_PALETTESDIR "/Library/Application Support/create/swatches"
diff --git a/src/sp-hatch-path.cpp b/src/sp-hatch-path.cpp
new file mode 100644
index 000000000..f7138fac2
--- /dev/null
+++ b/src/sp-hatch-path.cpp
@@ -0,0 +1,331 @@
+/** @file
+ * SVG <hatchPath> implementation
+ *//*
+ * Author:
+ * Tomasz Boczkowski <penginsbacon@gmail.com>
+ *
+ * Copyright (C) 2014 Tomasz Boczkowski
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <cstring>
+#include <string>
+#include <2geom/path.h>
+#include <2geom/transforms.h>
+
+#include "svg/svg.h"
+#include "display/cairo-utils.h"
+#include "display/curve.h"
+#include "display/drawing-context.h"
+#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"
+#include "style.h"
+#include "sp-hatch-path.h"
+#include "svg/css-ostringstream.h"
+#include "xml/repr.h"
+
+#include "sp-factory.h"
+
+namespace {
+SPObject* createHatchPath() {
+ return new SPHatchPath();
+}
+
+bool hatchRegistered = SPFactory::instance().registerObject("svg:hatchPath", createHatchPath);
+}
+
+SPHatchPath::SPHatchPath()
+ : _curve(NULL)
+ , _continuous(false)
+{
+ offset.unset();
+}
+
+SPHatchPath::~SPHatchPath() {
+}
+
+void SPHatchPath::setCurve(SPCurve *new_curve, bool owner) {
+ if (_curve) {
+ _curve = _curve->unref();
+ }
+
+ if (new_curve) {
+ if (owner) {
+ _curve = new_curve->ref();
+ } else {
+ _curve = new_curve->copy();
+ }
+ }
+
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+}
+
+void SPHatchPath::build(SPDocument* doc, Inkscape::XML::Node* repr) {
+ SPObject::build(doc, repr);
+
+ this->readAttr("d");
+ this->readAttr("offset");
+ this->readAttr( "style" );
+
+ style->fill.setNone();
+}
+
+void SPHatchPath::release() {
+ for (ViewIterator iter = _display.begin(); iter != _display.end(); iter++) {
+ delete iter->arenaitem;
+ iter->arenaitem = NULL;
+ }
+
+ SPObject::release();
+}
+
+void SPHatchPath::set(unsigned int key, const gchar* value) {
+ switch (key) {
+ case SP_ATTR_D:
+ if (value) {
+ Geom::PathVector pv;
+ _readHatchPathVector(value, pv, _continuous);
+ SPCurve *curve = new SPCurve(pv);
+
+ if (curve) {
+ this->setCurve(curve, true);
+ curve->unref();
+ }
+ } else {
+ this->setCurve(NULL, true);
+ }
+
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ break;
+
+ case SP_ATTR_OFFSET:
+ offset.readOrUnset(value);
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ break;
+
+ default:
+ 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 {
+ SPObject::set(key, value);
+ }
+ break;
+ }
+}
+
+
+void SPHatchPath::update(SPCtx* ctx, unsigned int flags) {
+
+ if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
+ flags &= ~SP_OBJECT_USER_MODIFIED_FLAG_B;
+ }
+
+ 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;
+
+ for (ViewIterator iter = _display.begin(); iter != _display.end(); iter++) {
+ iter->arenaitem->setStyle(this->style);
+ }
+ }
+ }
+
+ if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_PARENT_MODIFIED_FLAG)) {
+ for (ViewIterator iter = _display.begin(); iter != _display.end(); iter++) {
+ _updateView(*iter);
+ }
+ }
+}
+
+bool SPHatchPath::isValid() const {
+ if (_curve && (_repeatLength() <= 0)) {
+ return false;
+ }
+ return true;
+}
+
+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());
+
+ return s;
+}
+
+void SPHatchPath::hide(unsigned int key) {
+ for (ViewIterator iter = _display.begin(); iter != _display.end(); iter++) {
+ if (iter->key == key) {
+ delete iter->arenaitem;
+ _display.erase(iter);
+ return;
+ }
+ }
+
+ g_assert_not_reached();
+}
+
+void SPHatchPath::setStripExtents(unsigned int key, Geom::OptInterval const &extents) {
+ for (ViewIterator iter = _display.begin(); iter != _display.end(); iter++) {
+ if (iter->key == key) {
+ iter->extents = extents;
+ break;
+ }
+ }
+}
+
+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;
+ }
+
+ if (!_curve->last_point()) {
+ return 0;
+ }
+
+ return _curve->last_point()->y();
+}
+
+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 calculated_curve;
+ }
+
+ if (!_curve) {
+ calculated_curve->moveto(0, view.extents->min());
+ calculated_curve->lineto(0, view.extents->max());
+ //TODO: if hatch has a dasharray defined, adjust line ends
+ } else {
+ gdouble repeatLength = _repeatLength();
+ if (repeatLength > 0) {
+ gdouble initial_y = floor(view.extents->min() / repeatLength) * repeatLength;
+ int segment_cnt = ceil((view.extents->extent()) / repeatLength) + 1;
+
+ SPCurve *segment =_curve->copy();
+ segment->transform(Geom::Translate(0, initial_y));
+
+ Geom::Affine step_transform = Geom::Translate(0, repeatLength);
+ for (int i = 0; i < segment_cnt; i++) {
+ if (_continuous) {
+ calculated_curve->append_continuous(segment, 0.0625);
+ } else {
+ calculated_curve->append(segment, false);
+ }
+ segment->transform(step_transform);
+ }
+
+ segment->unref();
+ }
+ }
+ return calculated_curve;
+}
+
+
+void SPHatchPath::_readHatchPathVector(char const *str, Geom::PathVector &pathv, bool &continous_join) {
+ if (!str) {
+ return;
+ }
+
+ pathv = sp_svg_read_pathv(str);
+
+ if (!pathv.empty()) {
+ continous_join = false;
+ } else {
+ Glib::ustring str2 = Glib::ustring::compose("M0,0 %1", str);
+ pathv = sp_svg_read_pathv(str2.c_str());
+ if (pathv.empty()) {
+ return;
+ }
+
+ gdouble last_point_x = pathv.back().finalPoint().x();
+ Inkscape::CSSOStringStream stream;
+ stream << last_point_x;
+ Glib::ustring str3 = Glib::ustring::compose("M%1,0 %2", stream.str(), str);
+ Geom::PathVector pathv3 = sp_svg_read_pathv(str3.c_str());
+
+ //Path can be composed of relative commands only. In this case final point
+ //coordinates would depend on first point position. If this happens, fall
+ //back to using 0,0 as first path point
+ if (pathv3.back().finalPoint().y() == pathv.back().finalPoint().y()) {
+ pathv = pathv3;
+ }
+ continous_join = true;
+ }
+}
+
+SPHatchPath::View::View(Inkscape::DrawingShape *arenaitem, int key)
+ : arenaitem(arenaitem), key(key)
+{
+}
+
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+ */
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/sp-hatch-path.h b/src/sp-hatch-path.h
new file mode 100644
index 000000000..57b3a8237
--- /dev/null
+++ b/src/sp-hatch-path.h
@@ -0,0 +1,91 @@
+/** @file
+ * SVG <hatchPath> implementation
+ *//*
+ * Author:
+ * Tomasz Boczkowski <penginsbacon@gmail.com>
+ *
+ * Copyright (C) 2014 Tomasz Boczkowski
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_SP_HATCH_PATH_H
+#define SEEN_SP_HATCH_PATH_H
+
+#include <list>
+#include <stddef.h>
+#include <glibmm/ustring.h>
+#include <sigc++/connection.h>
+
+#include "svg/svg-length.h"
+
+namespace Inkscape {
+
+class Drawing;
+class DrawingShape;
+
+}
+
+#define SP_HATCH_PATH(obj) (dynamic_cast<SPHatchPath*>((SPObject*)obj))
+#define SP_IS_HATCH_PATH(obj) (dynamic_cast<const SPHatchPath*>((SPObject*)obj) != NULL)
+
+class SPHatchPath : public SPObject {
+public:
+ SPHatchPath();
+ virtual ~SPHatchPath();
+
+ SVGLength offset;
+
+ void setCurve(SPCurve *curve, bool owner);
+
+ bool isValid() const;
+
+ 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);
+ virtual void release();
+ virtual void set(unsigned int key, const gchar* value);
+ virtual void update(SPCtx* ctx, unsigned int flags);
+
+private:
+ struct View {
+ View(Inkscape::DrawingShape *arenaitem, int key);
+ //Do not delete arenaitem in destructor.
+
+ Inkscape::DrawingShape *arenaitem;
+ Geom::OptInterval extents;
+ 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);
+
+ SPCurve *_curve;
+ bool _continuous;
+};
+
+#endif // SEEN_SP_HATCH_PATH_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/sp-hatch.cpp b/src/sp-hatch.cpp
new file mode 100644
index 000000000..b007fc846
--- /dev/null
+++ b/src/sp-hatch.cpp
@@ -0,0 +1,679 @@
+/** @file
+ * SVG <hatch> implementation
+ *//*
+ * Author:
+ * Tomasz Boczkowski <penginsbacon@gmail.com>
+ *
+ * Copyright (C) 2014 Tomasz Boczkowski
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <cstring>
+#include <string>
+#include <2geom/transforms.h>
+#include <sigc++/functors/mem_fun.h>
+
+#include "svg/svg.h"
+#include "display/cairo-utils.h"
+#include "display/drawing-context.h"
+#include "display/drawing-surface.h"
+#include "display/drawing.h"
+#include "display/drawing-pattern.h"
+#include "attributes.h"
+#include "document-private.h"
+#include "uri.h"
+#include "style.h"
+#include "sp-hatch.h"
+#include "sp-hatch-path.h"
+#include "xml/repr.h"
+
+#include "sp-factory.h"
+
+namespace {
+SPObject* createHatch() {
+ return new SPHatch();
+}
+
+bool hatchRegistered = SPFactory::instance().registerObject("svg:hatch", createHatch);
+}
+
+SPHatch::SPHatch()
+ : SPPaintServer()
+{
+ this->ref = new SPHatchReference(this);
+ this->ref->changedSignal().connect(sigc::mem_fun(this, &SPHatch::_onRefChanged));
+
+ this->_hatchUnits = UNITS_OBJECTBOUNDINGBOX;
+ this->_hatchUnits_set = false;
+
+ this->_hatchContentUnits = UNITS_USERSPACEONUSE;
+ this->_hatchContentUnits_set = false;
+
+ this->_hatchTransform = Geom::identity();
+ this->_hatchTransform_set = false;
+
+ this->_x.unset();
+ this->_y.unset();
+ this->_pitch.unset();
+ this->_rotate.unset();
+}
+
+SPHatch::~SPHatch() {
+}
+
+void SPHatch::build(SPDocument* doc, Inkscape::XML::Node* repr) {
+ SPPaintServer::build(doc, repr);
+
+ this->readAttr("hatchUnits");
+ this->readAttr("hatchContentUnits");
+ this->readAttr("hatchTransform");
+ this->readAttr("x");
+ this->readAttr("y");
+ this->readAttr("pitch");
+ this->readAttr("rotate");
+ this->readAttr("xlink:href");
+ this->readAttr( "style" );
+
+ /* Register ourselves */
+ doc->addResource("hatch", this);
+}
+
+void SPHatch::release() {
+ if (this->document) {
+ // Unregister ourselves
+ this->document->removeResource("hatch", this);
+ }
+
+ std::vector<SPHatchPath *> 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++) {
+ SPHatchPath *child = *child_iter;
+ child->hide(view_iter->key);
+ }
+ delete view_iter->arenaitem;
+ view_iter->arenaitem = NULL;
+ }
+
+ if (this->ref) {
+ this->_modified_connection.disconnect();
+ this->ref->detach();
+ delete this->ref;
+ this->ref = NULL;
+ }
+
+ SPPaintServer::release();
+}
+
+void SPHatch::child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref) {
+ SPObject::child_added(child, ref);
+
+ SPHatchPath *path_child = SP_HATCH_PATH(this->document->getObjectByRepr(child));
+
+ if (path_child) {
+ for (ViewIterator iter = _display.begin(); iter != _display.end(); iter++) {
+ Geom::OptInterval extents = _calculateStripExtents(iter->bbox);
+ Inkscape::DrawingItem *ac = path_child->show(iter->arenaitem->drawing(), iter->key, extents);
+
+ path_child->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ if (ac) {
+ iter->arenaitem->prependChild(ac);
+ }
+ }
+ }
+ //FIXME: notify all hatches that refer to this child set
+}
+
+void SPHatch::set(unsigned int key, const gchar* value) {
+ switch (key) {
+ case SP_ATTR_HATCHUNITS:
+ if (value) {
+ if (!strcmp(value, "userSpaceOnUse")) {
+ this->_hatchUnits = UNITS_USERSPACEONUSE;
+ } else {
+ this->_hatchUnits = UNITS_OBJECTBOUNDINGBOX;
+ }
+
+ this->_hatchUnits_set = true;
+ } else {
+ this->_hatchUnits_set = false;
+ }
+
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ break;
+
+ case SP_ATTR_HATCHCONTENTUNITS:
+ if (value) {
+ if (!strcmp(value, "userSpaceOnUse")) {
+ this->_hatchContentUnits = UNITS_USERSPACEONUSE;
+ } else {
+ this->_hatchContentUnits = UNITS_OBJECTBOUNDINGBOX;
+ }
+
+ this->_hatchContentUnits_set = true;
+ } else {
+ this->_hatchContentUnits_set = false;
+ }
+
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ break;
+
+ case SP_ATTR_HATCHTRANSFORM: {
+ Geom::Affine t;
+
+ if (value && sp_svg_transform_read(value, &t)) {
+ this->_hatchTransform = t;
+ this->_hatchTransform_set = true;
+ } else {
+ this->_hatchTransform = Geom::identity();
+ this->_hatchTransform_set = false;
+ }
+
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ }
+ case SP_ATTR_X:
+ this->_x.readOrUnset(value);
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ break;
+
+ case SP_ATTR_Y:
+ this->_y.readOrUnset(value);
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ break;
+
+ case SP_ATTR_PITCH:
+ this->_pitch.readOrUnset(value);
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ break;
+
+ case SP_ATTR_ROTATE:
+ this->_rotate.readOrUnset(value);
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ break;
+
+ case SP_ATTR_XLINK_HREF:
+ if (value && this->href == value) {
+ /* Href unchanged, do nothing. */
+ } else {
+ this->href.clear();
+
+ if (value) {
+ // First, set the href field; it's only used in the "unchanged" check above.
+ this->href = value;
+ // Now do the attaching, which emits the changed signal.
+ if (value) {
+ try {
+ this->ref->attach(Inkscape::URI(value));
+ } catch (Inkscape::BadURIException &e) {
+ g_warning("%s", e.what());
+ this->ref->detach();
+ }
+ } else {
+ this->ref->detach();
+ }
+ }
+ }
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ break;
+
+ default:
+ 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;
+ }
+}
+
+bool SPHatch::_hasHatchPatchChildren(SPHatch const *hatch) {
+ for (SPObject const *child = hatch->firstChild(); child; child = child->getNext() ) {
+ if (SP_IS_HATCH_PATH(child)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void SPHatch::hatchPaths(std::vector<SPHatchPath*>& l) {
+ SPHatch *src = chase_hrefs<SPHatch>(this, sigc::ptr_fun(&_hasHatchPatchChildren));
+
+ if (src) {
+ for (SPObject *child = src->firstChild(); child; child = child->getNext()) {
+ if (SP_IS_HATCH_PATH(child)) {
+ l.push_back(SP_HATCH_PATH(child));
+ }
+ }
+ }
+}
+
+void SPHatch::hatchPaths(std::vector<SPHatchPath const*>& l) const {
+ SPHatch const *src = chase_hrefs<SPHatch const>(this, sigc::ptr_fun(&_hasHatchPatchChildren));
+
+ if (src) {
+ for (SPObject const *child = src->firstChild(); child; child = child->getNext()) {
+ if (SP_IS_HATCH_PATH(child)) {
+ l.push_back(SP_HATCH_PATH(child));
+ }
+ }
+ }
+}
+
+/* TODO: ::remove_child and ::order_changed handles - see SPPattern */
+
+
+void SPHatch::update(SPCtx* ctx, unsigned int flags) {
+ typedef std::list<SPHatch::View>::iterator ViewIterator;
+
+ if (flags & SP_OBJECT_MODIFIED_FLAG) {
+ flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
+ }
+
+ flags &= SP_OBJECT_MODIFIED_CASCADE;
+
+ std::vector<SPHatchPath *> children;
+ hatchPaths(children);
+
+ for (ChildIterator iter = children.begin(); iter != children.end(); iter++) {
+ SPHatchPath* child = *iter;
+
+ sp_object_ref(child, NULL);
+
+ for (ViewIterator view_iter = _display.begin(); view_iter != _display.end(); view_iter++) {
+ Geom::OptInterval strip_extents = _calculateStripExtents(view_iter->bbox);
+ child->setStripExtents(view_iter->key, strip_extents);
+ }
+
+ if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
+
+ child->updateDisplay(ctx, flags);
+ }
+
+ sp_object_unref(child, NULL);
+ }
+
+ for (ViewIterator iter = _display.begin(); iter != _display.end(); iter++) {
+ _updateView(*iter);
+ }
+}
+
+void SPHatch::modified(unsigned int flags) {
+ if (flags & SP_OBJECT_MODIFIED_FLAG) {
+ flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
+ }
+
+ flags &= SP_OBJECT_MODIFIED_CASCADE;
+
+ std::vector<SPHatchPath *> children;
+ hatchPaths(children);
+
+ for (ChildIterator iter = children.begin(); iter != children.end(); iter++) {
+ SPObject *child = *iter;
+
+ sp_object_ref(child, NULL);
+
+ if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
+ child->emitModified(flags);
+ }
+
+ sp_object_unref(child, NULL);
+ }
+}
+
+void SPHatch::_onRefChanged(SPObject *old_ref, SPObject *ref) {
+ typedef std::list<SPHatch::View>::iterator ViewIterator;
+
+ if (old_ref) {
+ _modified_connection.disconnect();
+ }
+
+ if (SP_IS_HATCH(ref)) {
+ _modified_connection = ref->connectModified(sigc::mem_fun(this, &SPHatch::_onRefModified));
+ }
+
+ if (!_hasHatchPatchChildren(this)) {
+ SPHatch *old_shown = NULL;
+ SPHatch *new_shown = NULL;
+ std::vector<SPHatchPath *> oldhatchPaths;
+ std::vector<SPHatchPath *> newhatchPaths;
+ if (SP_IS_HATCH(old_ref)) {
+ old_shown = SP_HATCH(old_ref)->rootHatch();
+ old_shown->hatchPaths(oldhatchPaths);
+ }
+ if (SP_IS_HATCH(ref)) {
+ new_shown = SP_HATCH(ref)->rootHatch();
+ 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 = oldhatchPaths.begin(); child_iter != oldhatchPaths.end(); child_iter++) {
+ SPHatchPath *child = *child_iter;
+ child->hide(iter->key);
+ }
+ 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, extents);
+ child->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ if (cai) {
+ iter->arenaitem->appendChild(cai);
+ }
+
+ }
+ }
+ }
+ }
+
+ _onRefModified(ref, 0);
+}
+
+void SPHatch::_onRefModified(SPObject */*ref*/, guint /*flags*/) {
+ requestModified(SP_OBJECT_MODIFIED_FLAG);
+ // Conditional to avoid causing infinite loop if there's a cycle in the href chain.
+}
+
+
+SPHatch *SPHatch::rootHatch() {
+ SPHatch *src = chase_hrefs<SPHatch>(this, sigc::ptr_fun(&_hasHatchPatchChildren));
+ return src ? src : this; // document is broken, we can't get to root; but at least we can return pat which is supposedly a valid hatch
+}
+
+// Access functions that look up fields up the chain of referenced hatchs and return the first one which is set
+// FIXME: all of them must use chase_hrefs as children() and rootHatch()
+
+SPHatch::HatchUnits SPHatch::hatchUnits() const {
+ for (SPHatch const *pat_i = this; pat_i != NULL;
+ pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) {
+ if (pat_i->_hatchUnits_set)
+ return pat_i->_hatchUnits;
+ }
+ return _hatchUnits;
+}
+
+SPHatch::HatchUnits SPHatch::hatchContentUnits() const {
+ for (SPHatch const *pat_i = this; pat_i != NULL;
+ pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) {
+ if (pat_i->_hatchContentUnits_set)
+ return pat_i->_hatchContentUnits;
+ }
+ return _hatchContentUnits;
+}
+
+Geom::Affine const &SPHatch::hatchTransform() const {
+ for (SPHatch const *pat_i = this; pat_i != NULL;
+ pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) {
+ if (pat_i->_hatchTransform_set)
+ return pat_i->_hatchTransform;
+ }
+ return _hatchTransform;
+}
+
+gdouble SPHatch::x() const {
+ for (SPHatch const *pat_i = this; pat_i != NULL;
+ pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) {
+ if (pat_i->_x._set)
+ return pat_i->_x.computed;
+ }
+ return 0;
+}
+
+gdouble SPHatch::y() const {
+ for (SPHatch const *pat_i = this; pat_i != NULL;
+ pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) {
+ if (pat_i->_y._set)
+ return pat_i->_y.computed;
+ }
+ return 0;
+}
+
+gdouble SPHatch::pitch() const {
+ for (SPHatch const *pat_i = this; pat_i != NULL;
+ pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) {
+ if (pat_i->_pitch._set)
+ return pat_i->_pitch.computed;
+ }
+ return 0;
+}
+
+gdouble SPHatch::rotate() const {
+ for (SPHatch const *pat_i = this; pat_i != NULL;
+ pat_i = pat_i->ref ? pat_i->ref->getObject() : NULL) {
+ if (pat_i->_rotate._set)
+ return pat_i->_rotate.computed;
+ }
+ return 0;
+}
+
+bool SPHatch::isValid() const {
+ double strip_pitch = pitch();
+ if (strip_pitch <= 0) {
+ return false;
+ }
+
+ std::vector<SPHatchPath const *> children;
+ hatchPaths(children);
+ if (children.empty()) {
+ return false;
+ }
+ for (ConstChildIterator iter = children.begin(); iter != children.end(); iter++) {
+ SPHatchPath const *child = *iter;
+ if (!child->isValid()) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+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;
+ 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, extents);
+ if (cai) {
+ ai->appendChild(cai);
+ }
+ }
+
+ View& view = _display.front();
+ _updateView(view);
+
+ return ai;
+}
+
+void SPHatch::hide(unsigned int key) {
+ std::vector<SPHatchPath *> children;
+ hatchPaths(children);
+
+ for (ChildIterator iter = children.begin(); iter != children.end(); iter++) {
+ SPHatchPath *child = *iter;
+ child->hide(key);
+ }
+
+ for (ViewIterator iter = _display.begin(); iter != _display.end(); iter++) {
+ if (iter->key == key) {
+ delete iter->arenaitem;
+ _display.erase(iter);
+ return;
+ }
+ }
+
+ 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 info;
+ }
+
+ double tile_x = x();
+ double tile_y = y();
+ double tile_width = pitch();
+ double tile_height = extents->max() - extents->min();
+ double tile_rotate = rotate();
+ double tile_render_y = extents->min();
+
+ if (view.bbox && (hatchUnits() == UNITS_OBJECTBOUNDINGBOX)) {
+ tile_x *= view.bbox->width();
+ tile_y *= view.bbox->height();
+ tile_width *= view.bbox->width();
+ tile_height *= view.bbox->height();
+ tile_render_y *= view.bbox->height();
+ }
+
+ // Pattern size in hatch space
+ Geom::Rect hatch_tile = Geom::Rect::from_xywh(0, tile_render_y, tile_width, tile_height);
+ // Content to bbox
+ Geom::Affine content2ps;
+ if (view.bbox && (hatchContentUnits() == UNITS_OBJECTBOUNDINGBOX)) {
+ content2ps = Geom::Affine(view.bbox->width(), 0.0, 0.0, view.bbox->height(), 0, 0);
+ }
+
+ // Tile (hatch space) to user.
+ Geom::Affine ps2user = Geom::Translate(tile_x, tile_y) * Geom::Rotate::from_degrees(tile_rotate) * hatchTransform();
+
+ 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) const {
+ if (!bbox || (bbox->area() == 0)) {
+ return Geom::OptInterval();
+ }
+
+ double tile_x = x();
+ double tile_y = y();
+ double tile_rotate = rotate();
+
+ Geom::Affine ps2user = Geom::Translate(tile_x, tile_y) * Geom::Rotate::from_degrees(tile_rotate) * hatchTransform();
+ Geom::Affine user2ps = ps2user.inverse();
+
+ Geom::Interval extents;
+ for (int i = 0; i < 4; i++) {
+ Geom::Point corner = bbox->corner(i);
+ Geom::Point corner_ps = corner * user2ps;
+ if (i == 0 || corner_ps.y() < extents.min()) {
+ extents.setMin(corner_ps.y());
+ }
+ if (i == 0 || corner_ps.y() > extents.max()) {
+ extents.setMax(corner_ps.y());
+ }
+ }
+
+ if (hatchUnits() == UNITS_OBJECTBOUNDINGBOX) {
+ extents /= bbox->height();
+ }
+
+ return extents;
+}
+
+cairo_pattern_t* SPHatch::pattern_new(cairo_t * /*base_ct*/, Geom::OptRect const &/*bbox*/, double /*opacity*/)
+{
+ //this code should not be used
+ //it is however required by the fact that SPPaintServer::hatch_new is pure virtual
+ return cairo_pattern_create_rgb(0.5, 0.5, 1.0);
+}
+
+void SPHatch::setBBox(unsigned int key, Geom::OptRect const &bbox) {
+ for (ViewIterator iter = _display.begin(); iter != _display.end(); iter++) {
+ if (iter->key == key) {
+ iter->bbox = bbox;
+ break;
+ }
+ }
+}
+
+SPHatch::View::View(Inkscape::DrawingPattern *arenaitem, int key)
+ : arenaitem(arenaitem), key(key)
+{
+}
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+ */
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/sp-hatch.h b/src/sp-hatch.h
new file mode 100644
index 000000000..dc6ee0add
--- /dev/null
+++ b/src/sp-hatch.h
@@ -0,0 +1,174 @@
+/** @file
+ * SVG <hatch> implementation
+ *//*
+ * Author:
+ * Tomasz Boczkowski <penginsbacon@gmail.com>
+ *
+ * Copyright (C) 2014 Tomasz Boczkowski
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_SP_HATCH_H
+#define SEEN_SP_HATCH_H
+
+#include <list>
+#include <stddef.h>
+#include <glibmm/ustring.h>
+#include <sigc++/connection.h>
+
+#include "svg/svg-length.h"
+#include "svg/svg-angle.h"
+#include "sp-paint-server.h"
+#include "uri-references.h"
+
+class SPHatchReference;
+class SPHatchPath;
+class SPItem;
+
+namespace Inkscape {
+
+class Drawing;
+class DrawingPattern;
+
+namespace XML {
+
+class Node;
+
+}
+}
+
+#define SP_HATCH(obj) (dynamic_cast<SPHatch*>((SPObject*)obj))
+#define SP_IS_HATCH(obj) (dynamic_cast<const SPHatch*>((SPObject*)obj) != NULL)
+
+class SPHatch : public SPPaintServer {
+public:
+ enum HatchUnits {
+ UNITS_USERSPACEONUSE,
+ 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();
+
+ /* Reference (href) */
+ Glib::ustring href;
+ SPHatchReference *ref;
+
+ gdouble x() const;
+ gdouble y() const;
+ gdouble pitch() const;
+ gdouble rotate() const;
+ HatchUnits hatchUnits() const;
+ HatchUnits hatchContentUnits() const;
+ 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, 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:
+ virtual void build(SPDocument* doc, Inkscape::XML::Node* repr);
+ virtual void release();
+ virtual void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref);
+ virtual void set(unsigned int key, const gchar* value);
+ virtual void update(SPCtx* ctx, unsigned int flags);
+ virtual void modified(unsigned int flags);
+
+private:
+ struct View {
+ View(Inkscape::DrawingPattern *arenaitem, int key);
+ //Do not delete arenaitem in destructor.
+
+ Inkscape::DrawingPattern *arenaitem;
+ 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;
+ typedef std::list<View>::const_iterator ConstViewIterator;
+
+ static bool _hasHatchPatchChildren(SPHatch const* hatch);
+
+ void _updateView(View &view);
+ RenderInfo _calculateRenderInfo(View const &view) const;
+ Geom::OptInterval _calculateStripExtents(Geom::OptRect bbox) const;
+
+
+ /**
+ Gets called when the hatch is reattached to another <hatch>
+ */
+ void _onRefChanged(SPObject *old_ref, SPObject *ref);
+
+ /**
+ Gets called when the referenced <hatch> is changed
+ */
+ void _onRefModified(SPObject *ref, guint flags);
+
+ /* patternUnits and patternContentUnits attribute */
+ HatchUnits _hatchUnits : 1;
+ bool _hatchUnits_set : 1;
+ HatchUnits _hatchContentUnits : 1;
+ bool _hatchContentUnits_set : 1;
+ /* hatchTransform attribute */
+ Geom::Affine _hatchTransform;
+ bool _hatchTransform_set : 1;
+ /* Strip */
+ SVGLength _x;
+ SVGLength _y;
+ SVGLength _pitch;
+ SVGAngle _rotate;
+
+ sigc::connection _modified_connection;
+
+ std::list<View> _display;
+};
+
+
+class SPHatchReference : public Inkscape::URIReference {
+public:
+ SPHatchReference (SPObject *obj) : URIReference(obj) {}
+ SPHatch *getObject() const {
+ return reinterpret_cast<SPHatch *>(URIReference::getObject());
+ }
+
+protected:
+ virtual bool _acceptObject(SPObject *obj) const {
+ return SP_IS_HATCH (obj);
+ }
+};
+
+#endif // SEEN_SP_HATCH_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/sp-item.cpp b/src/sp-item.cpp
index b1a22fd8c..94ab1b181 100644
--- a/src/sp-item.cpp
+++ b/src/sp-item.cpp
@@ -120,6 +120,9 @@ SPItem::SPItem() : SPObject() {
mask_ref = new SPMaskReference(this);
mask_ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(mask_ref_changed), this));
+ style->signal_fill_ps_changed.connect(sigc::bind(sigc::ptr_fun(fill_ps_ref_changed), this));
+ style->signal_stroke_ps_changed.connect(sigc::bind(sigc::ptr_fun(stroke_ps_ref_changed), this));
+
avoidRef = new SPAvoidRef(this);
}
@@ -465,7 +468,15 @@ void SPItem::release() {
SPObject::release();
+ SPPaintServer *fill_ps = style->getFillPaintServer();
+ SPPaintServer *stroke_ps = style->getStrokePaintServer();
while (item->display) {
+ if (fill_ps) {
+ fill_ps->hide(item->display->arenaitem->key());
+ }
+ if (stroke_ps) {
+ stroke_ps->hide(item->display->arenaitem->key());
+ }
item->display = sp_item_view_list_remove(item->display, item->display);
}
@@ -623,6 +634,56 @@ void SPItem::mask_ref_changed(SPObject *old_mask, SPObject *mask, SPItem *item)
}
}
+void SPItem::fill_ps_ref_changed(SPObject *old_ps, SPObject *ps, SPItem *item) {
+ SPPaintServer *old_fill_ps = SP_PAINT_SERVER(old_ps);
+ if (old_fill_ps) {
+ for (SPItemView *v =item->display; v != NULL; v = v->next) {
+ old_fill_ps->hide(v->arenaitem->key());
+ }
+ }
+
+ SPPaintServer *new_fill_ps = SP_PAINT_SERVER(ps);
+ if (new_fill_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_fill_ps->show(
+ v->arenaitem->drawing(), v->arenaitem->key(), bbox);
+ v->arenaitem->setFillPattern(pi);
+ if (pi) {
+ new_fill_ps->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ }
+ }
+ }
+}
+
+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) {
SPItem *item = this;
SPItem* object = item;
@@ -682,6 +743,10 @@ void SPItem::update(SPCtx* /*ctx*/, guint flags) {
item->avoidRef->handleSettingChange();
}
+void SPItem::modified(unsigned int /*flags*/)
+{
+}
+
Inkscape::XML::Node* SPItem::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) {
SPItem *item = this;
SPItem* object = item;
@@ -1130,6 +1195,33 @@ Inkscape::DrawingItem *SPItem::invoke_show(Inkscape::Drawing &drawing, unsigned
SP_MASK(mask)->sp_mask_set_bbox(mask_key, item_bbox);
mask->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
}
+
+ SPPaintServer *fill_ps = style->getFillPaintServer();
+ if (fill_ps) {
+ if (!display->arenaitem->key()) {
+ display->arenaitem->setKey(display_key_new(3));
+ }
+ int fill_key = display->arenaitem->key();
+
+ Inkscape::DrawingPattern *ap = fill_ps->show(drawing, fill_key, item_bbox);
+ ai->setFillPattern(ap);
+ if (ap) {
+ fill_ps->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ }
+ }
+ SPPaintServer *stroke_ps = style->getStrokePaintServer();
+ if (stroke_ps) {
+ if (!display->arenaitem->key()) {
+ display->arenaitem->setKey(display_key_new(3));
+ }
+ int stroke_key = display->arenaitem->key();
+
+ Inkscape::DrawingPattern *ap = stroke_ps->show(drawing, stroke_key, item_bbox);
+ ai->setStrokePattern(ap);
+ if (ap) {
+ stroke_ps->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ }
+ }
ai->setData(this);
ai->setItemBounds(geometricBounds());
}
@@ -1159,6 +1251,14 @@ void SPItem::invoke_hide(unsigned key)
mask_ref->getObject()->sp_mask_hide(v->arenaitem->key());
v->arenaitem->setMask(NULL);
}
+ SPPaintServer *fill_ps = style->getFillPaintServer();
+ if (fill_ps) {
+ fill_ps->hide(v->arenaitem->key());
+ }
+ SPPaintServer *stroke_ps = style->getStrokePaintServer();
+ if (stroke_ps) {
+ stroke_ps->hide(v->arenaitem->key());
+ }
if (!ref) {
display = v->next;
} else {
diff --git a/src/sp-item.h b/src/sp-item.h
index 1e4f5f4c6..1656a0c2b 100644
--- a/src/sp-item.h
+++ b/src/sp-item.h
@@ -34,6 +34,7 @@
class SPClipPathReference;
class SPMaskReference;
class SPAvoidRef;
+class SPPattern;
struct SPPrintContext;
typedef unsigned int guint32;
@@ -252,12 +253,15 @@ private:
static SPItemView *sp_item_view_new_prepend(SPItemView *list, SPItem *item, unsigned flags, unsigned key, Inkscape::DrawingItem *arenaitem);
static void clip_ref_changed(SPObject *old_clip, SPObject *clip, SPItem *item);
static void mask_ref_changed(SPObject *old_clip, SPObject *clip, SPItem *item);
+ static void fill_ps_ref_changed(SPObject *old_clip, SPObject *clip, SPItem *item);
+ static void stroke_ps_ref_changed(SPObject *old_clip, SPObject *clip, SPItem *item);
public:
virtual void build(SPDocument *document, Inkscape::XML::Node *repr);
virtual void release();
virtual void set(unsigned int key, char const* value);
virtual void update(SPCtx *ctx, unsigned int flags);
+ virtual void modified(unsigned int flags);
virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, unsigned int flags);
virtual Geom::OptRect bbox(Geom::Affine const &transform, SPItem::BBoxType type) const;
diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp
index a2a935951..019d15162 100644
--- a/src/sp-lpe-item.cpp
+++ b/src/sp-lpe-item.cpp
@@ -702,9 +702,8 @@ SPLPEItem::apply_to_mask(SPItem *item)
{
SPMask *mask = item->mask_ref->getObject();
if(mask) {
- SPObject * mask_data = mask->firstChild();
+ SPObject *mask_data = mask->firstChild();
SPCurve * mask_curve = NULL;
- mask_data = mask->firstChild();
if (SP_IS_PATH(mask_data)) {
mask_curve = SP_PATH(mask_data)->get_original_curve();
} else if(SP_IS_SHAPE(mask_data)) {
diff --git a/src/sp-paint-server.cpp b/src/sp-paint-server.cpp
index 77ad7a35f..ae40ad1aa 100644
--- a/src/sp-paint-server.cpp
+++ b/src/sp-paint-server.cpp
@@ -60,7 +60,25 @@ bool SPPaintServer::isSolid() const
bool SPPaintServer::isValid() const
{
- return true;
+ return true;
+}
+
+Inkscape::DrawingPattern *SPPaintServer::show(Inkscape::Drawing &/*drawing*/, unsigned int /*key*/, Geom::OptRect /*bbox*/)
+{
+ return NULL;
+}
+
+void SPPaintServer::hide(unsigned int /*key*/)
+{
+}
+
+void SPPaintServer::setBBox(unsigned int /*key*/, Geom::OptRect const &/*bbox*/)
+{
+}
+
+cairo_pattern_t* SPPaintServer::pattern_new(cairo_t * /*ct*/, Geom::OptRect const &/*bbox*/, double /*opacity*/)
+{
+ return NULL;
}
/*
diff --git a/src/sp-paint-server.h b/src/sp-paint-server.h
index beac72af5..7f3bfcba0 100644
--- a/src/sp-paint-server.h
+++ b/src/sp-paint-server.h
@@ -15,11 +15,17 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+#include <cairo.h>
#include <2geom/rect.h>
+#include <sigc++/slot.h>
#include "sp-object.h"
-typedef struct _cairo cairo_t;
-typedef struct _cairo_pattern cairo_pattern_t;
+namespace Inkscape {
+
+class Drawing;
+class DrawingPattern;
+
+}
#define SP_PAINT_SERVER(obj) (dynamic_cast<SPPaintServer*>((SPObject*)obj))
#define SP_IS_PAINT_SERVER(obj) (dynamic_cast<const SPPaintServer*>((SPObject*)obj) != NULL)
@@ -33,12 +39,59 @@ public:
bool isSolid() const;
virtual bool isValid() const;
- virtual cairo_pattern_t* pattern_new(cairo_t *ct, Geom::OptRect const &bbox, double opacity) = 0;
+ //There are two ways to render a paint. The simple one is to create cairo_pattern_t structure
+ //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, Geom::OptRect bbox); // TODO check passing bbox by value. Looks suspicious.
+ virtual void hide(unsigned int key);
+ virtual void setBBox(unsigned int key, Geom::OptRect const &bbox);
+
+ virtual cairo_pattern_t* pattern_new(cairo_t *ct, Geom::OptRect const &bbox, double opacity);
protected:
bool swatch;
};
+/**
+ * Returns the first of {src, src-\>ref-\>getObject(),
+ * src-\>ref-\>getObject()-\>ref-\>getObject(),...}
+ * for which \a match is true, or NULL if none found.
+ *
+ * The raison d'être of this routine is that it correctly handles cycles in the href chain (e.g., if
+ * a gradient gives itself as its href, or if each of two gradients gives the other as its href).
+ *
+ * \pre SP_IS_GRADIENT(src).
+ */
+template <class PaintServer>
+PaintServer *chase_hrefs(PaintServer *src, sigc::slot<bool, PaintServer const *> match) {
+ /* Use a pair of pointers for detecting loops: p1 advances half as fast as p2. If there is a
+ loop, then once p1 has entered the loop, we'll detect it the next time the distance between
+ p1 and p2 is a multiple of the loop size. */
+ PaintServer *p1 = src, *p2 = src;
+ bool do1 = false;
+ for (;;) {
+ if (match(p2)) {
+ return p2;
+ }
+
+ p2 = p2->ref->getObject();
+ if (!p2) {
+ return p2;
+ }
+ if (do1) {
+ p1 = p1->ref->getObject();
+ }
+ do1 = !do1;
+
+ if ( p2 == p1 ) {
+ /* We've been here before, so return NULL to indicate that no matching gradient found
+ * in the chain. */
+ return NULL;
+ }
+ }
+}
+
#endif // SEEN_SP_PAINT_SERVER_H
/*
Local Variables:
diff --git a/src/style-internal.cpp b/src/style-internal.cpp
index a55a11403..b858e5cb6 100644
--- a/src/style-internal.cpp
+++ b/src/style-internal.cpp
@@ -964,7 +964,11 @@ SPIPaint::read( gchar const *str ) {
if (!value.href && document) {
// std::cout << " Creating value.href" << std::endl;
value.href = new SPPaintServerReference(document);
- value.href->changedSignal().connect(sigc::bind(sigc::ptr_fun((this == &style->fill)? sp_style_fill_paint_server_ref_changed : sp_style_stroke_paint_server_ref_changed), style));
+ if (this == &style->fill) {
+ style->fill_ps_changed_connection = value.href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_fill_paint_server_ref_changed), style));
+ } else {
+ style->stroke_ps_changed_connection = value.href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_stroke_paint_server_ref_changed), style));
+ }
}
// std::cout << "uri: " << (uri?uri:"null") << std::endl;
@@ -981,7 +985,16 @@ SPIPaint::read( gchar const *str ) {
if (streq(str, "currentColor")) {
set = true;
currentcolor = true;
- setColor( style->color.value.color );
+ if (style) {
+ setColor( style->color.value.color );
+ } else {
+ // Normally an SPIPaint is part of an SPStyle and the value of 'color' is
+ // available. SPIPaint can be used 'stand-alone' (e.g. to parse color values) in
+ // which case a value of 'currentColor' is meaningless, thus we shouldn't reach
+ // here.
+ std::cerr << "SPIPaint::read(): value is 'currentColor' but 'color' not available." << std::endl;
+ setColor( 0 );
+ }
} else if (streq(str, "none")) {
set = true;
noneSet = true;
@@ -1396,11 +1409,20 @@ SPIFilter::read( gchar const *str ) {
set = true;
// Create href if not already done.
- if (!href && style->object) {
- href = new SPFilterReference(style->object);
- href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_filter_ref_changed), style));
+ if (!href) {
+ if (style->object) {
+ href = new SPFilterReference(style->object);
+ }
+ // Do we have href now?
+ if ( href ) {
+ href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_filter_ref_changed), style));
+ } else {
+ std::cerr << "SPIFilter::read(): Could not allocate 'href'" << std::endl;
+ return;
+ }
}
+ // We have href
try {
href->attach(Inkscape::URI(uri));
} catch (Inkscape::BadURIException &e) {
diff --git a/src/style-internal.h b/src/style-internal.h
index 9158ed60e..32792827a 100644
--- a/src/style-internal.h
+++ b/src/style-internal.h
@@ -104,22 +104,45 @@ static const unsigned SP_STYLE_FLAG_IFDIFF (1 << 1);
*/
/// Virtual base class for all SPStyle interal classes
-class SPIBase {
+class SPIBase
+{
- public:
+public:
SPIBase( Glib::ustring const &name, bool inherits = true )
- : name(name), inherits(inherits), set(false), inherit(false), style_att(false), style(NULL) {};
- virtual ~SPIBase() {};
+ : name(name),
+ inherits(inherits),
+ set(false),
+ inherit(false),
+ style_att(false),
+ style(NULL)
+ {}
+
+ virtual ~SPIBase()
+ {}
+
virtual void read( gchar const *str ) = 0;
- virtual void readIfUnset( gchar const *str ) { if( !set ) read( str ); }
- virtual void readAttribute( Inkscape::XML::Node *repr ) { readIfUnset( repr->attribute( name.c_str() ) ); }
+ virtual void readIfUnset( gchar const *str ) {
+ if ( !set ) {
+ read( str );
+ }
+ }
+
+ virtual void readAttribute( Inkscape::XML::Node *repr ) {
+ readIfUnset( repr->attribute( name.c_str() ) );
+ }
+
virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
SPIBase const *const base = NULL ) const = 0;
- virtual void clear() { set = false, inherit = false; };
+ virtual void clear() {
+ set = false, inherit = false;
+ }
+
virtual void cascade( const SPIBase* const parent ) = 0;
virtual void merge( const SPIBase* const parent ) = 0;
- virtual void setStylePointer( SPStyle *style_in ) { style = style_in; };
+ virtual void setStylePointer( SPStyle *style_in ) {
+ style = style_in;
+ }
// Explicit assignment operator required due to templates.
SPIBase& operator=(const SPIBase& rhs) {
@@ -133,11 +156,16 @@ class SPIBase {
}
// Check apples being compared to apples
- virtual bool operator==(const SPIBase& rhs) { return (name == rhs.name); };
- virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+ virtual bool operator==(const SPIBase& rhs) {
+ return (name == rhs.name);
+ }
+
+ virtual bool operator!=(const SPIBase& rhs) {
+ return !(*this == rhs);
+ }
// To do: make private
- public:
+public:
Glib::ustring name; // Make const
unsigned inherits : 1; // Property inherits by default from parent.
unsigned set : 1; // Property has been explicitly set (vs. inherited).
@@ -145,22 +173,35 @@ class SPIBase {
unsigned style_att : 2; // Source (attribute, style attribute, style-sheet). NOT USED YET FIX ME
// To do: make private after g_asserts removed
- public:
+public:
SPStyle* style; // Used by SPIPaint, SPIFilter... to find values of other properties
};
/// Float type internal to SPStyle. (Only 'stroke-miterlimit')
-class SPIFloat : public SPIBase {
-
- public:
- SPIFloat() : SPIBase( "anonymous_float" ), value(0.0) {};
- SPIFloat( Glib::ustring name, float value_default = 0.0 )
- : SPIBase( name ), value(value_default), value_default(value_default) {};
- virtual ~SPIFloat() {};
+class SPIFloat : public SPIBase
+{
+
+public:
+ SPIFloat()
+ : SPIBase( "anonymous_float" ),
+ value(0.0)
+ {}
+
+ SPIFloat( Glib::ustring const &name, float value_default = 0.0 )
+ : SPIBase( name ),
+ value(value_default),
+ value_default(value_default)
+ {}
+
+ virtual ~SPIFloat() {}
virtual void read( gchar const *str );
virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
SPIBase const *const base = NULL ) const;
- virtual void clear() { SPIBase::clear(); value = value_default; };
+ virtual void clear() {
+ SPIBase::clear();
+ value = value_default;
+ }
+
virtual void cascade( const SPIBase* const parent );
virtual void merge( const SPIBase* const parent );
@@ -172,13 +213,15 @@ class SPIFloat : public SPIBase {
}
virtual bool operator==(const SPIBase& rhs);
- virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+ virtual bool operator!=(const SPIBase& rhs) {
+ return !(*this == rhs);
+ }
// To do: make private
- public:
+public:
float value;
- private:
+private:
float value_default;
};
@@ -214,17 +257,32 @@ static const unsigned SP_SCALE24_MAX = 0xff0000;
/// 24 bit data type internal to SPStyle.
// Used only for opacity, fill-opacity, stroke-opacity.
// Opacity does not inherit but stroke-opacity and fill-opacity do.
-class SPIScale24 : public SPIBase {
+class SPIScale24 : public SPIBase
+{
+
+public:
+ SPIScale24()
+ : SPIBase( "anonymous_scale24" ),
+ value(0)
+ {}
+
+ SPIScale24( Glib::ustring const &name, unsigned value = 0, bool inherits = true )
+ : SPIBase( name, inherits ),
+ value(value),
+ value_default(value)
+ {}
+
+ virtual ~SPIScale24()
+ {}
- public:
- SPIScale24() : SPIBase( "anonymous_scale24" ), value(0) {};
- SPIScale24( Glib::ustring name, unsigned value = 0, bool inherits = true )
- : SPIBase( name, inherits ), value(value), value_default(value) {};
- virtual ~SPIScale24() {};
virtual void read( gchar const *str );
virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
SPIBase const *const base = NULL ) const;
- virtual void clear() { SPIBase::clear(); value = value_default; };
+ virtual void clear() {
+ SPIBase::clear();
+ value = value_default;
+ }
+
virtual void cascade( const SPIBase* const parent );
virtual void merge( const SPIBase* const parent );
@@ -236,14 +294,16 @@ class SPIScale24 : public SPIBase {
}
virtual bool operator==(const SPIBase& rhs);
- virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+ virtual bool operator!=(const SPIBase& rhs) {
+ return !(*this == rhs);
+ }
// To do: make private
- public:
+public:
unsigned value : 24;
- private:
+private:
unsigned value_default : 24;
};
@@ -265,17 +325,37 @@ enum SPCSSUnit {
/// Length type internal to SPStyle.
// Needs access to 'font-size' and 'font-family' for computed values.
// Used for 'stroke-width' 'stroke-dash-offset' ('none' not handled), text-indent
-class SPILength : public SPIBase {
+class SPILength : public SPIBase
+{
+
+public:
+ SPILength()
+ : SPIBase( "anonymous_length" ),
+ unit(SP_CSS_UNIT_NONE),
+ value(0),
+ computed(0)
+ {}
+
+ SPILength( Glib::ustring const &name, unsigned value = 0 )
+ : SPIBase( name ),
+ unit(SP_CSS_UNIT_NONE),
+ value(value),
+ computed(value),
+ value_default(value)
+ {}
+
+ virtual ~SPILength()
+ {}
- public:
- SPILength() : SPIBase( "anonymous_length" ), unit(SP_CSS_UNIT_NONE), value(0), computed(0) {};
- SPILength( Glib::ustring name, unsigned value = 0 )
- : SPIBase( name ), unit(SP_CSS_UNIT_NONE), value(value), computed(value), value_default(value) {};
- virtual ~SPILength() {};
virtual void read( gchar const *str );
virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
SPIBase const *const base = NULL ) const;
- virtual void clear() { SPIBase::clear(); unit = SP_CSS_UNIT_NONE, value = value_default; computed = value_default; };
+ virtual void clear() {
+ SPIBase::clear();
+ unit = SP_CSS_UNIT_NONE, value = value_default;
+ computed = value_default;
+ }
+
virtual void cascade( const SPIBase* const parent );
virtual void merge( const SPIBase* const parent );
@@ -286,35 +366,51 @@ class SPILength : public SPIBase {
computed = rhs.computed;
value_default = rhs.value_default;
return *this;
- };
+ }
virtual bool operator==(const SPIBase& rhs);
- virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+ virtual bool operator!=(const SPIBase& rhs) {
+ return !(*this == rhs);
+ }
// To do: make private
- public:
+public:
unsigned unit : 4;
float value;
float computed;
- private:
+private:
float value_default;
};
/// Extended length type internal to SPStyle.
// Used for: line-height, letter-spacing, word-spacing
-class SPILengthOrNormal : public SPILength {
+class SPILengthOrNormal : public SPILength
+{
+
+public:
+ SPILengthOrNormal()
+ : SPILength( "anonymous_length" ),
+ normal(true)
+ {}
+
+ SPILengthOrNormal( Glib::ustring const &name, unsigned value = 0 )
+ : SPILength( name, value ),
+ normal(true)
+ {}
+
+ virtual ~SPILengthOrNormal()
+ {}
- public:
- SPILengthOrNormal() : SPILength( "anonymous_length" ), normal(true) {};
- SPILengthOrNormal( Glib::ustring name, unsigned value = 0 )
- : SPILength( name, value ), normal(true) {};
- virtual ~SPILengthOrNormal() {};
virtual void read( gchar const *str );
virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
SPIBase const *const base = NULL ) const;
- virtual void clear() { SPILength::clear(); normal = true; };
+ virtual void clear() {
+ SPILength::clear();
+ normal = true;
+ }
+
virtual void cascade( const SPIBase* const parent );
virtual void merge( const SPIBase* const parent );
@@ -325,33 +421,59 @@ class SPILengthOrNormal : public SPILength {
}
virtual bool operator==(const SPIBase& rhs);
- virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+ virtual bool operator!=(const SPIBase& rhs) {
+ return !(*this == rhs);
+ }
// To do: make private
- public:
+public:
bool normal : 1;
};
/// Enum type internal to SPStyle.
// Used for many properties. 'font-stretch' and 'font-weight' must be special cased.
-class SPIEnum : public SPIBase {
+class SPIEnum : public SPIBase
+{
- public:
+public:
SPIEnum() :
- SPIBase( "anonymous_enum" ), enums( NULL ), value(0), computed(0) {};
- SPIEnum( Glib::ustring const name, SPStyleEnum const *enums, unsigned value = 0, bool inherits = true ) :
- SPIBase( name, inherits ), enums( enums ), value(value), computed(value),
- value_default(value), computed_default(value) {};
+ SPIBase( "anonymous_enum" ),
+ enums( NULL ),
+ value(0),
+ computed(0)
+ {}
+
+ SPIEnum( Glib::ustring const &name, SPStyleEnum const *enums, unsigned value = 0, bool inherits = true ) :
+ SPIBase( name, inherits ),
+ enums( enums ),
+ value(value),
+ computed(value),
+ value_default(value),
+ computed_default(value)
+ {}
+
// Following is needed for font-weight
- SPIEnum( Glib::ustring name, SPStyleEnum const *enums, SPCSSFontWeight value, SPCSSFontWeight computed ) :
- SPIBase( name ), enums( enums ), value(value), computed(computed),
- value_default(value), computed_default(computed) {};
- virtual ~SPIEnum() {};
+ SPIEnum( Glib::ustring const &name, SPStyleEnum const *enums, SPCSSFontWeight value, SPCSSFontWeight computed ) :
+ SPIBase( name ),
+ enums( enums ),
+ value(value),
+ computed(computed),
+ value_default(value),
+ computed_default(computed)
+ {}
+
+ virtual ~SPIEnum()
+ {}
+
virtual void read( gchar const *str );
virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
SPIBase const *const base = NULL ) const;
- virtual void clear() { SPIBase::clear(); value = value_default, computed = computed_default; };
+ virtual void clear() {
+ SPIBase::clear();
+ value = value_default, computed = computed_default;
+ }
+
virtual void cascade( const SPIBase* const parent );
virtual void merge( const SPIBase* const parent );
@@ -365,16 +487,18 @@ class SPIEnum : public SPIBase {
}
virtual bool operator==(const SPIBase& rhs);
- virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+ virtual bool operator!=(const SPIBase& rhs) {
+ return !(*this == rhs);
+ }
// To do: make private
- public:
+public:
SPStyleEnum const *enums;
unsigned value : 8;
unsigned computed: 8;
- private:
+private:
unsigned value_default : 8;
unsigned computed_default: 8; // for font-weight
};
@@ -382,20 +506,31 @@ class SPIEnum : public SPIBase {
/// String type internal to SPStyle.
// Used for 'marker', ..., 'font', 'font-family', 'inkscape-font-specification'
-class SPIString : public SPIBase {
-
- public:
- SPIString() :
- SPIBase( "anonymous_string" ), value(NULL) {};
- SPIString( Glib::ustring name, gchar* value_default_in = NULL ) :
- SPIBase( name ) , value(NULL) , value_default(NULL) {
- value_default = value_default_in?g_strdup(value_default_in):NULL;
- };
- virtual ~SPIString() { g_free(value); g_free(value_default); };
+class SPIString : public SPIBase
+{
+
+public:
+ SPIString()
+ : SPIBase( "anonymous_string" ),
+ value(NULL)
+ {}
+
+ // TODO probably want to avoid gchar* and c-style strings.
+ SPIString( Glib::ustring const &name, gchar const* value_default_in = NULL )
+ : SPIBase( name ),
+ value(NULL),
+ value_default(value_default_in ? g_strdup(value_default_in) : NULL)
+ {}
+
+ virtual ~SPIString() {
+ g_free(value);
+ g_free(value_default);
+ }
+
virtual void read( gchar const *str );
virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
SPIBase const *const base = NULL ) const;
- virtual void clear();
+ virtual void clear(); // TODO check about value and value_default
virtual void cascade( const SPIBase* const parent );
virtual void merge( const SPIBase* const parent );
@@ -403,31 +538,50 @@ class SPIString : public SPIBase {
SPIBase::operator=(rhs);
g_free(value);
g_free(value_default);
- value = rhs.value?g_strdup(rhs.value):NULL;
- value_default = rhs.value_default?g_strdup(rhs.value_default):NULL;
+ value = rhs.value ? g_strdup(rhs.value) : NULL;
+ value_default = rhs.value_default ? g_strdup(rhs.value_default) : NULL;
return *this;
}
virtual bool operator==(const SPIBase& rhs);
- virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+ virtual bool operator!=(const SPIBase& rhs) {
+ return !(*this == rhs);
+ }
// To do: make private, convert value to Glib::ustring
- public:
+public:
gchar *value;
gchar *value_default;
};
/// Color type interal to SPStyle, FIXME Add string value to store SVG named color.
-class SPIColor : public SPIBase {
+class SPIColor : public SPIBase
+{
+
+public:
+ SPIColor()
+ : SPIBase( "anonymous_color" ),
+ currentcolor(false) {
+ value.color.set(0);
+ }
+
+ SPIColor( Glib::ustring const &name )
+ : SPIBase( name ),
+ currentcolor(false) {
+ value.color.set(0);
+ }
+
+ virtual ~SPIColor()
+ {}
- public:
- SPIColor() : SPIBase( "anonymous_color" ), currentcolor(false) { value.color.set(0); }
- SPIColor( Glib::ustring name ) : SPIBase( name ), currentcolor(false) { value.color.set(0); }
- virtual ~SPIColor() {}
virtual void read( gchar const *str );
virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
SPIBase const *const base = NULL ) const;
- virtual void clear() { SPIBase::clear(); value.color.set(0); }
+ virtual void clear() {
+ SPIBase::clear();
+ value.color.set(0);
+ }
+
virtual void cascade( const SPIBase* const parent );
virtual void merge( const SPIBase* const parent );
@@ -439,13 +593,23 @@ class SPIColor : public SPIBase {
}
virtual bool operator==(const SPIBase& rhs);
- virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); }
+ virtual bool operator!=(const SPIBase& rhs) {
+ return !(*this == rhs);
+ }
- void setColor( float r, float g, float b ) { value.color.set( r, g, b ); }
- void setColor( guint32 val ) { value.color.set( val ); }
- void setColor( SPColor const& color ) { value.color = color; }
+ void setColor( float r, float g, float b ) {
+ value.color.set( r, g, b );
+ }
+
+ void setColor( guint32 val ) {
+ value.color.set( val );
+ }
+
+ void setColor( SPColor const& color ) {
+ value.color = color;
+ }
- public:
+public:
bool currentcolor : 1;
// FIXME: remove structure and derive SPIPaint from this class.
struct {
@@ -459,18 +623,28 @@ class SPIColor : public SPIBase {
#define SP_STYLE_STROKE_SERVER(s) ((const_cast<SPStyle *> (s))->getStrokePaintServer())
/// Paint type internal to SPStyle.
-class SPIPaint : public SPIBase {
-
- public:
- SPIPaint() : SPIBase( "anonymous_paint" ), currentcolor(false), colorSet(false), noneSet(false) {
+class SPIPaint : public SPIBase
+{
+
+public:
+ SPIPaint()
+ : SPIBase( "anonymous_paint" ),
+ currentcolor(false),
+ colorSet(false),
+ noneSet(false) {
value.href = NULL;
clear();
- };
- SPIPaint( Glib::ustring name )
- : SPIBase( name ), currentcolor(false), colorSet(false), noneSet(false) {
+ }
+
+ SPIPaint( Glib::ustring const &name )
+ : SPIBase( name ),
+ currentcolor(false),
+ colorSet(false),
+ noneSet(false) {
value.href = NULL;
clear(); // Sets defaults
- };
+ }
+
virtual ~SPIPaint(); // Clear and delete href.
virtual void read( gchar const *str );
virtual void read( gchar const *str, SPStyle &style, SPDocument *document = 0);
@@ -492,24 +666,46 @@ class SPIPaint : public SPIBase {
}
virtual bool operator==(const SPIBase& rhs);
- virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+ virtual bool operator!=(const SPIBase& rhs) {
+ return !(*this == rhs);
+ }
+
+ bool isSameType( SPIPaint const & other ) const {
+ return (isPaintserver() == other.isPaintserver()) && (colorSet == other.colorSet) && (currentcolor == other.currentcolor);
+ }
- bool isSameType( SPIPaint const & other ) const {return (isPaintserver() == other.isPaintserver()) && (colorSet == other.colorSet) && (currentcolor == other.currentcolor);}
+ bool isNoneSet() const {
+ return noneSet;
+ }
+
+ bool isNone() const {
+ return !currentcolor && !colorSet && !isPaintserver();
+ } // TODO refine
+
+ bool isColor() const {
+ return colorSet && !isPaintserver();
+ }
- bool isNoneSet() const {return noneSet;}
+ bool isPaintserver() const {
+ return (value.href) ? value.href->getObject() : 0;
+ }
- bool isNone() const {return !currentcolor && !colorSet && !isPaintserver();} // TODO refine
- bool isColor() const {return colorSet && !isPaintserver();}
- bool isPaintserver() const {return (value.href) ? value.href->getObject():0;}
+ void setColor( float r, float g, float b ) {
+ value.color.set( r, g, b ); colorSet = true;
+ }
- void setColor( float r, float g, float b ) {value.color.set( r, g, b ); colorSet = true;}
- void setColor( guint32 val ) {value.color.set( val ); colorSet = true;}
- void setColor( SPColor const& color ) {value.color = color; colorSet = true;}
+ void setColor( guint32 val ) {
+ value.color.set( val ); colorSet = true;
+ }
+ void setColor( SPColor const& color ) {
+ value.color = color; colorSet = true;
+ }
+ void setNone() {noneSet = true; colorSet=false;}
// To do: make private
- public:
+public:
bool currentcolor : 1;
bool colorSet : 1;
bool noneSet : 1;
@@ -536,11 +732,20 @@ enum SPPaintOrderLayer {
const size_t PAINT_ORDER_LAYERS = 3;
/// Paint order type internal to SPStyle
-class SPIPaintOrder : public SPIBase {
+class SPIPaintOrder : public SPIBase
+{
+
+public:
+ SPIPaintOrder()
+ : SPIBase( "paint-order" ),
+ value(NULL) {
+ this->clear();
+ }
+
+ virtual ~SPIPaintOrder() {
+ g_free( value );
+ }
- public:
- SPIPaintOrder() : SPIBase( "paint-order" ), value(NULL) { this->clear(); };
- virtual ~SPIPaintOrder() { g_free( value ); };
virtual void read( gchar const *str );
virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
SPIBase const *const base = NULL ) const;
@@ -568,11 +773,13 @@ class SPIPaintOrder : public SPIBase {
}
virtual bool operator==(const SPIBase& rhs);
- virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+ virtual bool operator!=(const SPIBase& rhs) {
+ return !(*this == rhs);
+ }
// To do: make private
- public:
+public:
SPPaintOrderLayer layer[PAINT_ORDER_LAYERS];
bool layer_set[PAINT_ORDER_LAYERS];
gchar *value; // Raw string
@@ -580,15 +787,25 @@ class SPIPaintOrder : public SPIBase {
/// Filter type internal to SPStyle
-class SPIDashArray : public SPIBase {
+class SPIDashArray : public SPIBase
+{
+
+public:
+ SPIDashArray()
+ : SPIBase( "stroke-dasharray" )
+ {} // Only one instance of SPIDashArray
+
+ virtual ~SPIDashArray()
+ {}
- public:
- SPIDashArray() : SPIBase( "stroke-dasharray" ) {}; // Only one instance of SPIDashArray
- virtual ~SPIDashArray() {};
virtual void read( gchar const *str );
virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
SPIBase const *const base = NULL ) const;
- virtual void clear() { SPIBase::clear(); values.clear(); };
+ virtual void clear() {
+ SPIBase::clear();
+ values.clear();
+ }
+
virtual void cascade( const SPIBase* const parent );
virtual void merge( const SPIBase* const parent );
@@ -599,19 +816,26 @@ class SPIDashArray : public SPIBase {
}
virtual bool operator==(const SPIBase& rhs);
- virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+ virtual bool operator!=(const SPIBase& rhs) {
+ return !(*this == rhs);
+ }
// To do: make private, change double to SVGLength
- public:
+public:
std::vector<double> values;
};
/// Filter type internal to SPStyle
-class SPIFilter : public SPIBase {
+class SPIFilter : public SPIBase
+{
+
+public:
+ SPIFilter()
+ : SPIBase( "filter", false ),
+ href(NULL)
+ {}
- public:
- SPIFilter() : SPIBase( "filter", false ), href(NULL) {};
virtual ~SPIFilter();
virtual void read( gchar const *str );
virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
@@ -627,10 +851,12 @@ class SPIFilter : public SPIBase {
}
virtual bool operator==(const SPIBase& rhs);
- virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+ virtual bool operator!=(const SPIBase& rhs) {
+ return !(*this == rhs);
+ }
// To do: make private
- public:
+public:
SPFilterReference *href;
};
@@ -643,16 +869,27 @@ enum {
};
/// Fontsize type internal to SPStyle (also used by libnrtype/Layout-TNG-Input.cpp).
-class SPIFontSize : public SPIBase {
+class SPIFontSize : public SPIBase
+{
+
+public:
+ SPIFontSize()
+ : SPIBase( "font-size" ) {
+ this->clear();
+ }
+
+ virtual ~SPIFontSize()
+ {}
- public:
- SPIFontSize() : SPIBase( "font-size" ) { this->clear(); };
- virtual ~SPIFontSize() {};
virtual void read( gchar const *str );
virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
SPIBase const *const base = NULL ) const;
- virtual void clear() { SPIBase::clear(); type = SP_FONT_SIZE_LITERAL, unit = SP_CSS_UNIT_NONE,
- literal = SP_CSS_FONT_SIZE_MEDIUM, value = 12.0, computed = 12.0; }
+ virtual void clear() {
+ SPIBase::clear();
+ type = SP_FONT_SIZE_LITERAL, unit = SP_CSS_UNIT_NONE,
+ literal = SP_CSS_FONT_SIZE_MEDIUM, value = 12.0, computed = 12.0;
+ }
+
virtual void cascade( const SPIBase* const parent );
virtual void merge( const SPIBase* const parent );
@@ -667,39 +904,51 @@ class SPIFontSize : public SPIBase {
}
virtual bool operator==(const SPIBase& rhs);
- virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+ virtual bool operator!=(const SPIBase& rhs) {
+ return !(*this == rhs);
+ }
- public:
+public:
static float const font_size_default;
// To do: make private
- public:
+public:
unsigned type : 2;
unsigned unit : 4;
unsigned literal : 4;
float value;
float computed;
- private:
+private:
double relative_fraction() const;
static float const font_size_table[];
};
/// Font type internal to SPStyle ('font' shorthand)
-class SPIFont : public SPIBase {
+class SPIFont : public SPIBase
+{
+
+public:
+ SPIFont()
+ : SPIBase( "font" )
+ {}
+
+ virtual ~SPIFont()
+ {}
- public:
- SPIFont() : SPIBase( "font" ) {};
- virtual ~SPIFont() {};
virtual void read( gchar const *str );
virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
SPIBase const *const base = NULL ) const;
virtual void clear() {
SPIBase::clear();
- };
- virtual void cascade( const SPIBase* const parent ) { (void)parent; }; // Done in dependent properties
- virtual void merge( const SPIBase* const parent ) { (void)parent; };
+ }
+
+ virtual void cascade( const SPIBase* const /*parent*/ )
+ {} // Done in dependent properties
+
+ virtual void merge( const SPIBase* const /*parent*/ )
+ {}
SPIFont& operator=(const SPIFont& rhs) {
SPIBase::operator=(rhs);
@@ -707,7 +956,9 @@ class SPIFont : public SPIBase {
}
virtual bool operator==(const SPIBase& rhs);
- virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+ virtual bool operator!=(const SPIBase& rhs) {
+ return !(*this == rhs);
+ }
};
@@ -718,16 +969,27 @@ enum {
};
/// Baseline shift type internal to SPStyle. (This is actually just like SPIFontSize)
-class SPIBaselineShift : public SPIBase {
+class SPIBaselineShift : public SPIBase
+{
+
+public:
+ SPIBaselineShift()
+ : SPIBase( "baseline-shift", false ) {
+ this->clear();
+ }
+
+ virtual ~SPIBaselineShift()
+ {}
- public:
- SPIBaselineShift() : SPIBase( "baseline-shift", false ) { this->clear(); };
- virtual ~SPIBaselineShift() {};
virtual void read( gchar const *str );
virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
SPIBase const *const base = NULL ) const;
- virtual void clear() { SPIBase::clear(); type=SP_BASELINE_SHIFT_LITERAL, unit=SP_CSS_UNIT_NONE,
- literal = SP_CSS_BASELINE_SHIFT_BASELINE, value = 0.0, computed = 0.0; }
+ virtual void clear() {
+ SPIBase::clear();
+ type=SP_BASELINE_SHIFT_LITERAL, unit=SP_CSS_UNIT_NONE,
+ literal = SP_CSS_BASELINE_SHIFT_BASELINE, value = 0.0, computed = 0.0;
+ }
+
virtual void cascade( const SPIBase* const parent );
virtual void merge( const SPIBase* const parent );
@@ -743,11 +1005,14 @@ class SPIBaselineShift : public SPIBase {
// This is not used but we have it for completeness, it has not been tested.
virtual bool operator==(const SPIBase& rhs);
- virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+ virtual bool operator!=(const SPIBase& rhs) {
+ return !(*this == rhs);
+ }
+
bool isZero() const;
// To do: make private
- public:
+public:
unsigned type : 2;
unsigned unit : 4;
unsigned literal: 2;
@@ -760,15 +1025,26 @@ class SPIBaselineShift : public SPIBase {
// CSS3 2.2
/// Text decoration line type internal to SPStyle. THIS SHOULD BE A GENERIC CLASS
-class SPITextDecorationLine : public SPIBase {
+class SPITextDecorationLine : public SPIBase
+{
+
+public:
+ SPITextDecorationLine()
+ : SPIBase( "text-decoration-line" ) {
+ this->clear();
+ }
+
+ virtual ~SPITextDecorationLine()
+ {}
- public:
- SPITextDecorationLine() : SPIBase( "text-decoration-line" ) { this->clear(); };
- virtual ~SPITextDecorationLine() {};
virtual void read( gchar const *str );
virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
SPIBase const *const base = NULL ) const;
- virtual void clear() { SPIBase::clear(); underline = false, overline = false, line_through = false, blink = false; }
+ virtual void clear() {
+ SPIBase::clear();
+ underline = false, overline = false, line_through = false, blink = false;
+ }
+
virtual void cascade( const SPIBase* const parent );
virtual void merge( const SPIBase* const parent );
@@ -782,10 +1058,12 @@ class SPITextDecorationLine : public SPIBase {
}
virtual bool operator==(const SPIBase& rhs);
- virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+ virtual bool operator!=(const SPIBase& rhs) {
+ return !(*this == rhs);
+ }
// To do: make private
- public:
+public:
bool underline : 1;
bool overline : 1;
bool line_through : 1;
@@ -794,15 +1072,26 @@ class SPITextDecorationLine : public SPIBase {
// CSS3 2.2
/// Text decoration style type internal to SPStyle. THIS SHOULD JUST BE SPIEnum!
-class SPITextDecorationStyle : public SPIBase {
+class SPITextDecorationStyle : public SPIBase
+{
+
+public:
+ SPITextDecorationStyle()
+ : SPIBase( "text-decoration-style" ) {
+ this->clear();
+ }
+
+ virtual ~SPITextDecorationStyle()
+ {}
- public:
- SPITextDecorationStyle() : SPIBase( "text-decoration-style" ) { this->clear(); };
- virtual ~SPITextDecorationStyle() {};
virtual void read( gchar const *str );
virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
SPIBase const *const base = NULL ) const;
- virtual void clear() { SPIBase::clear(); solid = true, isdouble = false, dotted = false, dashed = false, wavy = false; }
+ virtual void clear() {
+ SPIBase::clear();
+ solid = true, isdouble = false, dotted = false, dashed = false, wavy = false;
+ }
+
virtual void cascade( const SPIBase* const parent );
virtual void merge( const SPIBase* const parent );
@@ -817,10 +1106,12 @@ class SPITextDecorationStyle : public SPIBase {
}
virtual bool operator==(const SPIBase& rhs);
- virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+ virtual bool operator!=(const SPIBase& rhs) {
+ return !(*this == rhs);
+ }
// To do: make private
- public:
+public:
bool solid : 1;
bool isdouble : 1; // cannot use "double" as it is a reserved keyword
bool dotted : 1;
@@ -837,18 +1128,26 @@ class SPITextDecorationStyle : public SPIBase {
// the right style. (See http://www.w3.org/TR/css-text-decor-3/#text-decoration-property )
/// Text decoration type internal to SPStyle.
-class SPITextDecoration : public SPIBase {
+class SPITextDecoration : public SPIBase
+{
+
+public:
+ SPITextDecoration()
+ : SPIBase( "text-decoration" ),
+ style_td( NULL )
+ {}
+
+ virtual ~SPITextDecoration()
+ {}
- public:
- SPITextDecoration() : SPIBase( "text-decoration" ), style_td( NULL ) {};
- virtual ~SPITextDecoration() {};
virtual void read( gchar const *str );
virtual const Glib::ustring write( guint const flags = SP_STYLE_FLAG_IFSET,
SPIBase const *const base = NULL ) const;
virtual void clear() {
SPIBase::clear();
style_td = NULL;
- };
+ }
+
virtual void cascade( const SPIBase* const parent );
virtual void merge( const SPIBase* const parent );
@@ -859,9 +1158,11 @@ class SPITextDecoration : public SPIBase {
// Use CSS2 value
virtual bool operator==(const SPIBase& rhs);
- virtual bool operator!=(const SPIBase& rhs) { return !(*this == rhs); };
+ virtual bool operator!=(const SPIBase& rhs) {
+ return !(*this == rhs);
+ }
- public:
+public:
SPStyle* style_td; // Style to be used for drawing CSS2 text decorations
};
diff --git a/src/style.cpp b/src/style.cpp
index 66672e949..e0c8536fc 100644
--- a/src/style.cpp
+++ b/src/style.cpp
@@ -440,6 +440,8 @@ SPStyle::~SPStyle() {
// Remove connections
release_connection.disconnect();
+ fill_ps_changed_connection.disconnect();
+ stroke_ps_changed_connection.disconnect();
// The following shoud be moved into SPIPaint and SPIFilter
if (fill.value.href) {
@@ -499,10 +501,10 @@ SPStyle::clear() {
filter.href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_filter_ref_changed), this));
fill.value.href = new SPPaintServerReference(document);
- fill.value.href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_fill_paint_server_ref_changed), this));
+ fill_ps_changed_connection = fill.value.href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_fill_paint_server_ref_changed), this));
stroke.value.href = new SPPaintServerReference(document);
- stroke.value.href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_stroke_paint_server_ref_changed), this));
+ stroke_ps_changed_connection = stroke.value.href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_stroke_paint_server_ref_changed), this));
}
cloned = false;
@@ -1118,6 +1120,7 @@ sp_style_fill_paint_server_ref_changed(SPObject *old_ref, SPObject *ref, SPStyle
ref->connectModified(sigc::bind(sigc::ptr_fun(&sp_style_paint_server_ref_modified), style));
}
+ style->signal_fill_ps_changed.emit(old_ref, ref);
sp_style_paint_server_ref_modified(ref, 0, style);
}
@@ -1135,6 +1138,7 @@ sp_style_stroke_paint_server_ref_changed(SPObject *old_ref, SPObject *ref, SPSty
ref->connectModified(sigc::bind(sigc::ptr_fun(&sp_style_paint_server_ref_modified), style));
}
+ style->signal_stroke_ps_changed.emit(old_ref, ref);
sp_style_paint_server_ref_modified(ref, 0, style);
}
@@ -1363,7 +1367,11 @@ sp_style_set_ipaint_to_uri(SPStyle *style, SPIPaint *paint, const Inkscape::URI
// now that we have a document, we can create it here
if (!paint->value.href && document) {
paint->value.href = new SPPaintServerReference(document);
- paint->value.href->changedSignal().connect(sigc::bind(sigc::ptr_fun((paint == &style->fill)? sp_style_fill_paint_server_ref_changed : sp_style_stroke_paint_server_ref_changed), style));
+ if (paint == &style->fill) {
+ style->fill_ps_changed_connection = paint->value.href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_fill_paint_server_ref_changed), style));
+ } else {
+ style->stroke_ps_changed_connection = paint->value.href->changedSignal().connect(sigc::bind(sigc::ptr_fun(sp_style_stroke_paint_server_ref_changed), style));
+ }
}
if (paint->value.href){
diff --git a/src/style.h b/src/style.h
index 48eb55430..a4c2b3043 100644
--- a/src/style.h
+++ b/src/style.h
@@ -252,6 +252,22 @@ public:
sigc::connection filter_modified_connection;
sigc::connection fill_ps_modified_connection;
sigc::connection stroke_ps_modified_connection;
+ sigc::connection fill_ps_changed_connection;
+ sigc::connection stroke_ps_changed_connection;
+
+ /**
+ * Emitted when paint server object, fill paint refers to, is changed. That is
+ * when the reference starts pointing to a different address in memory.
+ *
+ * NB It is different from fill_ps_modified signal. When paint server is modified
+ * it means some of it's attributes or chilren change.
+ */
+ sigc::signal<void, SPObject *, SPObject *> signal_fill_ps_changed;
+ /**
+ * Emitted when paint server object, fill paint refers to, is changed. That is
+ * when the reference starts pointing to a different address in memory.
+ */
+ sigc::signal<void, SPObject *, SPObject *> signal_stroke_ps_changed;
SPObject *getFilter() { return (filter.href) ? filter.href->getObject() : NULL; }
SPObject const *getFilter() const { return (filter.href) ? filter.href->getObject() : NULL; }
diff --git a/src/svg/CMakeLists.txt b/src/svg/CMakeLists.txt
index 968287895..f9d0bc52d 100644
--- a/src/svg/CMakeLists.txt
+++ b/src/svg/CMakeLists.txt
@@ -7,6 +7,7 @@ set(svg_SRC
strip-trailing-zeros.cpp
svg-affine.cpp
svg-color.cpp
+ svg-angle.cpp
svg-length.cpp
svg-path.cpp
# test-stubs.cpp
@@ -24,6 +25,7 @@ set(svg_SRC
svg-color-test.h
svg-color.h
svg-icc-color.h
+ svg-angle.h
svg-length-test.h
svg-length.h
svg-path-geom-test.h
diff --git a/src/svg/Makefile_insert b/src/svg/Makefile_insert
index cf9bf3fbb..4f82bdd76 100644
--- a/src/svg/Makefile_insert
+++ b/src/svg/Makefile_insert
@@ -13,6 +13,8 @@ ink_common_sources += \
svg/svg-color.cpp \
svg/svg-color.h \
svg/svg-icc-color.h \
+ svg/svg-angle.cpp \
+ svg/svg-angle.h \
svg/svg-length.cpp \
svg/svg-length.h \
svg/svg-path.cpp \
diff --git a/src/svg/svg-angle.cpp b/src/svg/svg-angle.cpp
new file mode 100644
index 000000000..63152368e
--- /dev/null
+++ b/src/svg/svg-angle.cpp
@@ -0,0 +1,136 @@
+/**
+ * \file src/svg/svg-angle.cpp
+ * \brief SVG angle type
+ */
+/*
+ * Authors:
+ * Tomasz Boczkowski <penginsbacon@gmail.com>
+ *
+ * Copyright (C) 1999-2002 Lauris Kaplinski
+ * Copyright (C) 2000-2001 Ximian, Inc.
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <cstring>
+#include <string>
+#include <math.h>
+#include <glib.h>
+
+#include "svg.h"
+#include "stringstream.h"
+#include "svg/svg-angle.h"
+#include "util/units.h"
+
+
+static bool sp_svg_angle_read_lff(gchar const *str, SVGAngle::Unit &unit, float &val, float &computed);
+
+SVGAngle::SVGAngle()
+ : _set(false)
+ , unit(NONE)
+ , value(0)
+ , computed(0)
+{
+}
+
+/* Angle */
+
+bool SVGAngle::read(gchar const *str)
+{
+ if (!str) {
+ return false;
+ }
+
+ SVGAngle::Unit u;
+ float v;
+ float c;
+ if (!sp_svg_angle_read_lff(str, u, v, c)) {
+ return false;
+ }
+
+ _set = true;
+ unit = u;
+ value = v;
+ computed = c;
+
+ return true;
+}
+
+void SVGAngle::unset(SVGAngle::Unit u, float v, float c) {
+ _set = false;
+ unit = u;
+ value = v;
+ computed = c;
+}
+
+void SVGAngle::readOrUnset(gchar const *str, Unit u, float v, float c) {
+ if (!read(str)) {
+ unset(u, v, c);
+ }
+}
+
+static bool sp_svg_angle_read_lff(gchar const *str, SVGAngle::Unit &unit, float &val, float &computed)
+{
+ if (!str) {
+ return false;
+ }
+
+ gchar const *e;
+ float const v = g_ascii_strtod(str, (char **) &e);
+ if (e == str) {
+ return false;
+ }
+
+ if (!e[0]) {
+ /* Unitless (defaults to degrees)*/
+ unit = SVGAngle::NONE;
+ val = v;
+ computed = v;
+ return true;
+ } else if (!g_ascii_isalnum(e[0])) {
+ if (g_ascii_isspace(e[0]) && e[1] && g_ascii_isalpha(e[1])) {
+ return false; // spaces between value and unit are not allowed
+ } else {
+ /* Unitless (defaults to degrees)*/
+ unit = SVGAngle::NONE;
+ val = v;
+ computed = v;
+ return true;
+ }
+ } else {
+ if (strncmp(e, "deg", 3) == 0) {
+ unit = SVGAngle::DEG;
+ computed = v;
+ } else if (strncmp(e, "grad", 4) == 0) {
+ unit = SVGAngle::GRAD;
+ computed = Inkscape::Util::Quantity::convert(v, "grad", "°");
+ } else if (strncmp(e, "rad", 3) == 0) {
+ unit = SVGAngle::RAD;
+ computed = Inkscape::Util::Quantity::convert(v, "rad", "°");
+ } else if (strncmp(e, "turn", 4) == 0) {
+ unit = SVGAngle::TURN;
+ computed = Inkscape::Util::Quantity::convert(v, "turn", "°");
+ } else {
+ return false;
+ }
+ return true;
+ }
+
+ /* Invalid */
+ return false;
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/svg/svg-angle.h b/src/svg/svg-angle.h
new file mode 100644
index 000000000..966491174
--- /dev/null
+++ b/src/svg/svg-angle.h
@@ -0,0 +1,69 @@
+#ifndef SEEN_SP_SVG_ANGLE_H
+#define SEEN_SP_SVG_ANGLE_H
+
+/**
+ * \file src/svg/svg-angle.h
+ * \brief SVG angle type
+ */
+/*
+ * Authors:
+ * Tomasz Boczkowski <penginsbacon@gmail.com>
+ *
+ * Copyright (C) 1999-2002 Lauris Kaplinski
+ * Copyright (C) 2000-2001 Ximian, Inc.
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <glib.h>
+
+class SVGAngle
+{
+public:
+ SVGAngle();
+
+ enum Unit {
+ NONE,
+ DEG,
+ GRAD,
+ RAD,
+ TURN,
+ LAST_UNIT = TURN
+ };
+
+ // The object's value is valid / exists in SVG.
+ bool _set;
+
+ // The unit of value.
+ Unit unit;
+
+ // The value of this SVGAngle as found in the SVG.
+ float value;
+
+ // The value in degrees.
+ float computed;
+
+ float operator=(float v) {
+ _set = true;
+ unit = NONE;
+ value = computed = v;
+ return v;
+ }
+
+ bool read(gchar const *str);
+ void unset(Unit u = NONE, float v = 0, float c = 0);
+ void readOrUnset(gchar const *str, Unit u = NONE, float v = 0, float c = 0);
+};
+
+#endif // SEEN_SP_SVG_ANGLE_H
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
diff --git a/src/svg/svg-color.cpp b/src/svg/svg-color.cpp
index 5108b7702..c9f22f8a4 100644
--- a/src/svg/svg-color.cpp
+++ b/src/svg/svg-color.cpp
@@ -511,18 +511,18 @@ sp_svg_create_color_hash()
void icc_color_to_sRGB(SVGICCColor* icc, guchar* r, guchar* g, guchar* b)
{
- guchar color_out[4];
- guchar color_in[4];
if (icc) {
g_message("profile name: %s", icc->colorProfile.c_str());
Inkscape::ColorProfile* prof = SP_ACTIVE_DOCUMENT->profileManager->find(icc->colorProfile.c_str());
if ( prof ) {
+ guchar color_out[4] = {0,0,0,0};
cmsHTRANSFORM trans = prof->getTransfToSRGB8();
if ( trans ) {
std::vector<colorspace::Component> comps = colorspace::getColorSpaceInfo( prof );
size_t count = CMSSystem::getChannelCount( prof );
size_t cap = std::min(count, comps.size());
+ guchar color_in[4];
for (size_t i = 0; i < cap; i++) {
color_in[i] = static_cast<guchar>((((gdouble)icc->colors[i]) * 256.0) * (gdouble)comps[i].scale);
g_message("input[%d]: %d", (int)i, (int)color_in[i]);
diff --git a/src/ui/dialog/clonetiler.cpp b/src/ui/dialog/clonetiler.cpp
index 8d3d2b57c..5ac2ef29d 100644
--- a/src/ui/dialog/clonetiler.cpp
+++ b/src/ui/dialog/clonetiler.cpp
@@ -2235,7 +2235,11 @@ void CloneTiler::clonetiler_apply(GtkWidget */*widget*/, GtkWidget *dlg)
gdk_window_process_all_updates();
SPObject *obj = selection->singleItem();
- SPItem *item = SP_IS_ITEM(obj) ? SP_ITEM(obj) : 0;
+ if (!obj) {
+ // Should never happen (empty selection checked above).
+ std::cerr << "CloneTiler::clonetile_apply(): No object in single item selection!!!" << std::endl;
+ return;
+ }
Inkscape::XML::Node *obj_repr = obj->getRepr();
const char *id_href = g_strdup_printf("#%s", obj_repr->attribute("id"));
SPObject *parent = obj->parent;
@@ -2326,6 +2330,7 @@ void CloneTiler::clonetiler_apply(GtkWidget */*widget*/, GtkWidget *dlg)
bool invert_picked = prefs->getBool(prefs_path + "invert_picked");
double gamma_picked = prefs->getDoubleLimited(prefs_path + "gamma_picked", 0, -10, 10);
+ SPItem *item = SP_IS_ITEM(obj) ? SP_ITEM(obj) : 0;
if (dotrace) {
clonetiler_trace_setup (sp_desktop_document(desktop), 1.0, item);
}
diff --git a/src/ui/dialog/symbols.cpp b/src/ui/dialog/symbols.cpp
index 76532eb7e..647753c4f 100644
--- a/src/ui/dialog/symbols.cpp
+++ b/src/ui/dialog/symbols.cpp
@@ -62,8 +62,20 @@
#include "widgets/icon.h"
#ifdef WITH_LIBVISIO
-#include <libvisio/libvisio.h>
-#include <libwpd-stream/libwpd-stream.h>
+ #include <libvisio/libvisio.h>
+
+ // TODO: Drop this check when librevenge is widespread.
+ #if WITH_LIBVISIO01
+ #include <librevenge-stream/librevenge-stream.h>
+
+ using librevenge::RVNGFileStream;
+ using librevenge::RVNGStringVector;
+ #else
+ #include <libwpd-stream/libwpd-stream.h>
+
+ typedef WPXFileStream RVNGFileStream;
+ typedef libvisio::VSDStringVector RVNGStringVector;
+ #endif
#endif
#include "verbs.h"
@@ -495,14 +507,20 @@ void SymbolsDialog::iconChanged() {
// Read Visio stencil files
SPDocument* read_vss( gchar* fullname, gchar* filename ) {
- WPXFileStream input(fullname);
+ RVNGFileStream input(fullname);
if (!libvisio::VisioDocument::isSupported(&input)) {
return NULL;
}
- libvisio::VSDStringVector output;
+ RVNGStringVector output;
+#if WITH_LIBVISIO01
+ librevenge::RVNGSVGDrawingGenerator generator(output, "svg");
+
+ if (!libvisio::VisioDocument::parseStencils(&input, &generator)) {
+#else
if (!libvisio::VisioDocument::generateSVGStencils(&input, output)) {
+#endif
return NULL;
}
diff --git a/src/ui/dialog/template-widget.cpp b/src/ui/dialog/template-widget.cpp
index 9758b35ac..f79d166f2 100644
--- a/src/ui/dialog/template-widget.cpp
+++ b/src/ui/dialog/template-widget.cpp
@@ -24,6 +24,7 @@
#include "document.h"
#include "document-undo.h"
#include "file.h"
+#include "sp-namedview.h"
#include "extension/implementation/implementation.h"
#include "inkscape.h"
@@ -69,7 +70,10 @@ void TemplateWidget::create()
_current_template.tpl_effect->effect(desc);
DocumentUndo::clearUndo(sp_desktop_document(desc));
sp_desktop_document(desc)->setModifiedSinceSave(false);
-
+
+ // Apply cx,cy etc. from document
+ sp_namedview_window_from_document( desc );
+
if (desktop)
desktop->clearWaitingCursor();
}
diff --git a/src/ui/widget/highlight-picker.cpp b/src/ui/widget/highlight-picker.cpp
index bc6bdcf22..8593f0bdf 100644
--- a/src/ui/widget/highlight-picker.cpp
+++ b/src/ui/widget/highlight-picker.cpp
@@ -7,15 +7,8 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
+#include <glibmm.h>
#include <gtkmm/icontheme.h>
-
-#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
-#include <glibmm/threads.h>
-#endif
#include "display/cairo-utils.h"
diff --git a/src/ui/widget/insertordericon.cpp b/src/ui/widget/insertordericon.cpp
index 97aa30aa6..a28b0f834 100644
--- a/src/ui/widget/insertordericon.cpp
+++ b/src/ui/widget/insertordericon.cpp
@@ -9,14 +9,6 @@
#include "ui/widget/insertordericon.h"
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
-#include <glibmm/threads.h>
-#endif
-
#include <gtkmm/icontheme.h>
#include "widgets/icon.h"
diff --git a/src/ui/widget/insertordericon.h b/src/ui/widget/insertordericon.h
index e6c2e1c5b..fb3412d3f 100644
--- a/src/ui/widget/insertordericon.h
+++ b/src/ui/widget/insertordericon.h
@@ -10,12 +10,12 @@
*/
#if HAVE_CONFIG_H
-#include "config.h"
+# include "config.h"
#endif
+#include <glibmm.h>
#include <gtkmm/cellrendererpixbuf.h>
#include <gtkmm/widget.h>
-#include <glibmm/property.h>
namespace Inkscape {
namespace UI {
diff --git a/src/ui/widget/selected-style.cpp b/src/ui/widget/selected-style.cpp
index d3adb6307..d22c59aa4 100644
--- a/src/ui/widget/selected-style.cpp
+++ b/src/ui/widget/selected-style.cpp
@@ -1220,7 +1220,9 @@ void SelectedStyle::on_opacity_menu (Gtk::Menu *menu) {
menu->show_all();
}
-void SelectedStyle::on_opacity_changed () {
+void SelectedStyle::on_opacity_changed ()
+{
+ g_return_if_fail(_desktop); // TODO this shouldn't happen!
if (_opacity_blocked)
return;
_opacity_blocked = true;
diff --git a/src/viewbox.cpp b/src/viewbox.cpp
index f59909abc..662b05686 100644
--- a/src/viewbox.cpp
+++ b/src/viewbox.cpp
@@ -164,16 +164,17 @@ void SPViewBox::set_preserveAspectRatio(const gchar* value) {
void SPViewBox::apply_viewbox(const Geom::Rect& in) {
/* Determine actual viewbox in viewport coordinates */
- double x = 0.0;
- double y = 0.0;
- double width = in.width();
- double height = in.height();
+ /* These are floats since SVGLength is a float: See bug 1374614 */
+ float x = 0.0;
+ float y = 0.0;
+ float width = in.width();
+ float height = in.height();
// std::cout << " width: " << width << " height: " << height << std::endl;
if (this->aspect_align != SP_ASPECT_NONE) {
/* Things are getting interesting */
- double scalex = in.width() / this->viewBox.width();
- double scaley = in.height() / this->viewBox.height();
+ double scalex = in.width() / ((float) this->viewBox.width());
+ double scaley = in.height() / ((float) this->viewBox.height());
double scale = (this->aspect_clip == SP_ASPECT_MEET) ? MIN (scalex, scaley) : MAX (scalex, scaley);
width = this->viewBox.width() * scale;
height = this->viewBox.height() * scale;
@@ -217,12 +218,12 @@ void SPViewBox::apply_viewbox(const Geom::Rect& in) {
/* Viewbox transform from scale and position */
Geom::Affine q;
- q[0] = width / this->viewBox.width();
+ q[0] = width / ((float) this->viewBox.width());
q[1] = 0.0;
q[2] = 0.0;
- q[3] = height / this->viewBox.height();
- q[4] = x - q[0] * this->viewBox.left();
- q[5] = y - q[3] * this->viewBox.top();
+ q[3] = height / ((float) this->viewBox.height());
+ q[4] = x - q[0] * ((float) this->viewBox.left());
+ q[5] = y - q[3] * ((float) this->viewBox.top());
// std::cout << " q\n" << q << std::endl;
diff --git a/src/widgets/ink-comboboxentry-action.cpp b/src/widgets/ink-comboboxentry-action.cpp
index 5c59f6961..1114d2cdb 100644
--- a/src/widgets/ink-comboboxentry-action.cpp
+++ b/src/widgets/ink-comboboxentry-action.cpp
@@ -389,7 +389,7 @@ GtkWidget* create_tool_item( GtkAction* action )
GtkTreeViewRowSeparatorFunc (ink_comboboxentry_action->separator_func),
NULL, NULL );
}
-
+
// FIXME: once gtk3 migration is done this can be removed
// https://bugzilla.gnome.org/show_bug.cgi?id=734915
gtk_widget_show_all (comboBoxEntry);
diff --git a/src/widgets/stroke-style.cpp b/src/widgets/stroke-style.cpp
index 3fa39da6f..cb18207f4 100644
--- a/src/widgets/stroke-style.cpp
+++ b/src/widgets/stroke-style.cpp
@@ -763,6 +763,9 @@ StrokeStyle::setJoinType (unsigned const jointype)
tb = joinBevel;
break;
default:
+ // Should not happen
+ std::cerr << "StrokeStyle::setJoinType(): Invalid value" << std::endl;
+ tb = joinMiter;
break;
}
setJoinButtons(tb);
@@ -786,6 +789,9 @@ StrokeStyle::setCapType (unsigned const captype)
tb = capSquare;
break;
default:
+ // Should not happen
+ std::cerr << "StrokeStyle::setCapType(): Invalid value" << std::endl;
+ tb = capButt;
break;
}
setCapButtons(tb);
diff --git a/src/xml/node-event-vector.h b/src/xml/node-event-vector.h
index 416640b86..16add2960 100644
--- a/src/xml/node-event-vector.h
+++ b/src/xml/node-event-vector.h
@@ -58,11 +58,7 @@ struct NodeEventVector {
void (* attr_changed) (Node *repr, char const *key, char const *oldval, char const *newval, bool is_interactive, void* data);
void (* content_changed) (Node *repr, char const *oldcontent, char const *newcontent, void * data);
void (* order_changed) (Node *repr, Node *child, Node *oldref, Node *newref, void* data);
-}
-#ifdef __GNUC__
-__attribute__((deprecated))
-#endif
-;
+};
}
}
diff --git a/src/xml/repr-io.cpp b/src/xml/repr-io.cpp
index 0319bb5e3..a4146f215 100644
--- a/src/xml/repr-io.cpp
+++ b/src/xml/repr-io.cpp
@@ -623,7 +623,6 @@ static Node *sp_repr_svg_read_node (Document *xml_doc, xmlNodePtr node, const gc
repr->setContent(reinterpret_cast<gchar*>(node->content));
}
- child = node->xmlChildrenNode;
for (child = node->xmlChildrenNode; child != NULL; child = child->next) {
Node *crepr = sp_repr_svg_read_node (xml_doc, child, default_ns, prefix_map);
if (crepr) {