25#define noSP_GRADIENT_VERBOSE
37#include <sigc++/functors/ptr_fun.h>
38#include <sigc++/adaptors/bind.h>
93 gchar
const* paintVal =
swatch ? (
isSolid() ?
"solid" :
"gradient") :
nullptr;
103 setAttribute(
"inkscape:pinned", pinned ?
"true" :
"false");
129 (is<SPLinearGradient>(
this) && is<SPLinearGradient>(that)) ||
130 (is<SPRadialGradient>(
this) && is<SPRadialGradient>(that)) ||
131 (is<SPMeshGradient>(
this) && is<SPMeshGradient>(that))) {
139 bool effective =
true;
140 while (effective && (as &&
bs)) {
150 if (!effective)
break;
183 if (is<SPLinearGradient>(
this) && is<SPLinearGradient>(that)) {
184 auto sg = cast<SPLinearGradient>(
this);
185 auto tg = cast<SPLinearGradient>(that);
187 if( sg->x1._set != tg->x1._set) {
break; }
188 if( sg->y1._set != tg->y1._set) {
break; }
189 if( sg->x2._set != tg->x2._set) {
break; }
190 if( sg->y2._set != tg->y2._set) {
break; }
191 if( sg->x1._set && sg->y1._set && sg->x2._set && sg->y2._set) {
192 if( (sg->x1.computed != tg->x1.computed) ||
193 (sg->y1.computed != tg->y1.computed) ||
194 (sg->x2.computed != tg->x2.computed) ||
195 (sg->y2.computed != tg->y2.computed) ) {
break; }
196 }
else if( sg->x1._set || sg->y1._set || sg->x2._set || sg->y2._set) {
break; }
198 }
else if (is<SPRadialGradient>(
this) && is<SPLinearGradient>(that)) {
199 auto sg = cast<SPRadialGradient>(
this);
200 auto tg = cast<SPRadialGradient>(that);
202 if( sg->cx._set != tg->cx._set) {
break; }
203 if( sg->cy._set != tg->cy._set) {
break; }
204 if( sg->r._set != tg->r._set) {
break; }
205 if( sg->fx._set != tg->fx._set) {
break; }
206 if( sg->fy._set != tg->fy._set) {
break; }
207 if( sg->cx._set && sg->cy._set && sg->fx._set && sg->fy._set && sg->r._set) {
208 if( (sg->cx.computed != tg->cx.computed) ||
209 (sg->cy.computed != tg->cy.computed) ||
210 (sg->r.computed != tg->r.computed ) ||
211 (sg->fx.computed != tg->fx.computed) ||
212 (sg->fy.computed != tg->fy.computed) ) {
break; }
213 }
else if( sg->cx._set || sg->cy._set || sg->fx._set || sg->fy._set || sg->r._set ) {
break; }
215 }
else if (is<SPMeshGradient>(
this) && is<SPMeshGradient>(that)) {
216 auto sg = cast<SPMeshGradient>(
this);
217 auto tg = cast<SPMeshGradient>(that);
219 if( sg->x._set != !tg->x._set) {
break; }
220 if( sg->y._set != !tg->y._set) {
break; }
221 if( sg->x._set && sg->y._set) {
222 if( (sg->x.computed != tg->x.computed) ||
223 (sg->y.computed != tg->y.computed) ) {
break; }
224 }
else if( sg->x._set || sg->y._set) {
break; }
286 if (is<SPStop>(&ochild)) {
290 if (is<SPMeshrow>(&ochild)) {
291 for (
auto& ochild2: ochild.children) {
292 if (is<SPMeshpatch>(&ochild2)) {
320#ifdef SP_GRADIENT_VERBOSE
321 g_print(
"Releasing this %s\n", this->
getId());
345 std::stringstream temp;
353 if (!strcmp(value,
"userSpaceOnUse")) {
383 if (!strcmp(value,
"reflect")) {
385 }
else if (!strcmp(value,
"repeat")) {
404 g_warning(
"%s", e.what());
415 this->
_pinned = !strcmp(value,
"true");
421 bool newVal = (value !=
nullptr);
424 if (newVal != this->
swatch) {
431 Glib::ustring paintVal = ( this->
hasStops() && (this->
getStopCount() <= 1) ) ?
"solid" :
"gradient";
433 if ( paintVal != value ) {
462 if ( is<SPGradient>(
ref)
493 if ( ochild && is<SPStop>(ochild) ) {
496 gchar
const * attr = this->
getAttribute(
"inkscape:swatch");
497 if ( attr && strcmp(attr,
"gradient") ) {
502 if ( ochild && is<SPMeshrow>(ochild) ) {
522 if (is<SPStop>(&ochild)) {
526 if (is<SPMeshrow>(&ochild)) {
527 for (
auto& ochild2: ochild.children) {
528 if (is<SPMeshpatch>(&ochild2)) {
540 gchar
const * attr = this->
getAttribute(
"inkscape:swatch");
542 if ( attr && strcmp(attr,
"solid") ) {
559 if (flags & SP_OBJECT_CHILD_MODIFIED_FLAG) {
560 if (is<SPMeshGradient>(
this)) {
567 if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) {
568 if (is<SPMeshGradient>(
this)) {
575 if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
576 flags &= SP_OBJECT_MODIFIED_CASCADE;
579 std::vector<SPObject *> l;
586 if (flags || (
child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
587 child->emitModified(flags);
601 if (is<SPStop>(&ochild)) {
602 first = cast<SPStop>(&ochild);
633 if (flags & SP_OBJECT_WRITE_BUILD) {
634 std::vector<Inkscape::XML::Node *> l;
644 for (
auto i=l.rbegin();i!=l.rend();++i) {
656 if ((flags & SP_OBJECT_WRITE_ALL) || this->
units_set) {
657 switch (this->
units) {
672 if ((flags & SP_OBJECT_WRITE_ALL) || this->
spread_set) {
689 if ( (flags & SP_OBJECT_WRITE_EXT) && this->
isSwatch() ) {
743 if (
units != this->units) {
755 if (
spread != this->spread) {
775 g_return_val_if_fail(src, NULL);
841 if (src ==
nullptr) {
854 if (src ==
nullptr) {
897 std::vector<Inkscape::XML::Node *> l;
899 if (!strcmp(
child->name(),
"svg:stop")) {
904 for (
auto i=l.rbegin();i!=l.rend();++i) {
924 std::vector<Inkscape::XML::Node *> l;
933 if (
auto color = stop.color)
934 obj->setColor(*color);
942 for (
auto i=l.rbegin();i!=l.rend();++i) {
991 if (is<SPStop>(&
child)) {
1011 if (is<SPStop>(&
child)) {
1012 auto stop = cast<SPStop>(&
child);
1023 gstop.
offset = stop->offset;
1030 gstop.
color = stop->getColor();
1078 if( !is<SPMeshGradient>(
this) ) {
1079 g_warning(
"SPGradient::rebuildArray() called for non-mesh gradient" );
1083 array.
read( cast<SPMeshGradient>(
this ) );
1133 std::vector<SPObject *> links;
1137 for (
auto obj : links) {
1138 if (
auto item = cast<SPItem>(obj)) {
1156 cairo_pattern_set_extend(cp, CAIRO_EXTEND_REFLECT);
1159 cairo_pattern_set_extend(cp, CAIRO_EXTEND_REPEAT);
1163 cairo_pattern_set_extend(cp, CAIRO_EXTEND_PAD);
1168 if (!is<SPMeshGradient>(gr)) {
1178 Geom::Affine bbox2user(bbox->width(), 0, 0, bbox->height(), bbox->left(), bbox->top());
1179 gs2user *= bbox2user;
1189 if (!is<SPMeshGradient>(
this)) {
1192 pat = cairo_pattern_create_linear(0, 0,
width, 0);
1195 if (stop.color.has_value()) {
1201 double offset = 1.0/double(num_columns);
1203 pat = cairo_pattern_create_linear(0, 0,
width, 0);
1205 for (
unsigned i = 0; i < num_columns + 1; ++i) {
1207 if (
node->color.has_value()) {
gchar const * sp_attribute_name(SPAttr id)
Get attribute name by id.
Lookup dictionary for attributes/properties.
TODO: insert short description here.
void ink_cairo_pattern_add_color_stop(cairo_pattern_t *ptn, double offset, Inkscape::Colors::Color const &color, double opacity)
void ink_cairo_pattern_set_matrix(cairo_pattern_t *cp, Geom::Affine const &m)
Cairo integration helpers.
3x3 matrix representing an affine transformation.
Affine inverse() const
Compute the inverse matrix.
void unionWith(CRect const &b)
Enlarge the rectangle to contain the argument.
CPoint min() const
Get the corner of the rectangle with smallest coordinate values.
CPoint dimensions() const
Get rectangle's width and height as a point.
Axis-aligned rectangle that can be empty.
Axis aligned, non-empty rectangle.
A thin wrapper around std::ostringstream, but writing floating point numbers in the format required b...
bool isClose(Color const &other, double epsilon=EPSILON) const
Find out if a color is a close match to another color of the same type.
URI const * getURI() const
Returns a pointer to a URI containing the currently attached URI, or NULL if no URI is currently atta...
void detach()
Detaches from the currently attached URI target, if any; the current referrent is signaled as NULL.
sigc::signal< void(SPObject *, SPObject *)> changedSignal()
Accessor for the referrent change notification signal; this signal is emitted whenever the URIReferen...
void attach(URI const &uri)
Attaches to a URI, relative to the specified document.
Represents an URI as per RFC 2396.
std::string str(char const *baseuri=nullptr) const
Return the string representation of this URI.
Interface for refcounted XML nodes.
virtual void addChild(Node *child, Node *after)=0
Insert another node as a child of this node.
void setAttributeOrRemoveIfEmpty(Inkscape::Util::const_char_ptr key, Inkscape::Util::const_char_ptr value)
Change an attribute of this node.
void setAttribute(Util::const_char_ptr key, Util::const_char_ptr value)
Change an attribute of this node.
virtual Node * firstChild()=0
Get the first child of this node.
bool setAttributeCssDouble(Util::const_char_ptr key, double val)
Set a property attribute to val [slightly rounded], in the format required for CSS properties: in par...
virtual char const * attribute(char const *key) const =0
Get the string representation of a node's attribute.
void removeAttribute(Inkscape::Util::const_char_ptr key)
Remove an attribute of this node.
Typed SVG document implementation.
bool removeResource(char const *key, SPObject *object)
bool addResource(char const *key, SPObject *object)
Inkscape::XML::Document * getReprDoc()
Our Inkscape::XML::Document.
SPObject * getObjectByRepr(Inkscape::XML::Node *repr) const
SPGradient * getObject() const
SPGradient * getArray(bool force_private=false)
Returns private mesh of given gradient (the gradient at the end of the href chain which has patches),...
void setPinned(bool pinned=true)
unsigned int state
State in Inkscape gradient system.
void ensureArray()
Forces array (mesh) to be built, if not present (i.e.
void build(SPDocument *document, Inkscape::XML::Node *repr) override
Virtual build: set gradient attributes from its associated repr.
void set_gs2d_matrix(Geom::Affine const &ctm, Geom::Rect const &bbox, Geom::Affine const &gs2d)
SPGradientVector vector
Linear and Radial Gradients.
Inkscape::XML::Node * write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, unsigned int flags) override
Write gradient attributes to repr.
void remove_child(Inkscape::XML::Node *child) override
Callback for remove_child event.
Geom::Affine gradientTransform
gradientTransform attribute
SPGradientUnits fetchUnits()
Returns the effective units of given gradient (climbing up the refs chain if needed).
sigc::connection modified_connection
SPGradientSpread getSpread() const
bool invalidateVector()
Return true if change made.
unsigned int has_stops
Gradient stops.
void release() override
Virtual release of SPGradient members before destruction.
void child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref) override
Callback for child_added event.
static void gradientRefChanged(SPObject *old_ref, SPObject *ref, SPGradient *gr)
Gets called when the gradient is (re)attached to another gradient.
SPGradientSpread fetchSpread() const
Returns the effective spread of given gradient (climbing up the refs chain if needed).
void modified(unsigned int flags) override
Callback for modified event.
SPGradientReference * ref
Reference (href)
unsigned int gradientTransform_set
SPGradient * getVector(bool force_private=false)
Returns private vector of given gradient (the gradient at the end of the href chain which has stops),...
bool invalidateArray()
Return true if change made.
void rebuildVector() const
Creates normalized color vector.
void setSpread(SPGradientSpread spread)
Set spread property of gradient and emit modified.
cairo_pattern_t * create_preview_pattern(double width)
SPGradientUnits getUnits() const
SPGradientUnits units
gradientUnits attribute
void repr_clear_vector()
Clears the gradient's svg:stop children from its repr.
unsigned int has_patches
Gradient patches.
bool isEquivalent(SPGradient *b)
return true if this gradient is "equivalent" to that gradient.
void rebuildArray()
Creates normalized color mesh patch array.
SPMeshNodeArray array
Mesh Gradients.
bool _pinned
Pinned in swatches dialog.
Geom::OptRect getAllItemsBox() const
Return a visual bounding box that covers every item this gradient would paint added together.
bool isUnitsSet() const
All Gradients.
bool isAligned(SPGradient *b)
return true if this gradient is "aligned" to that gradient.
void setUnits(SPGradientUnits units)
Set units property of gradient and emit modified.
Geom::Affine get_g2d_matrix(Geom::Affine const &ctm, Geom::Rect const &bbox) const
Transforms to/from gradient position space in given environment.
SPGradientSpread spread
spreadMethod attribute
void set(SPAttr key, char const *value) override
Set gradient attribute to value.
static void gradientRefModified(SPObject *href, unsigned int flags, SPGradient *gradient)
SPGradientVector const & getGradientVector() const
void repr_write_vector()
Writes the gradient's internal vector (whether from its own stops, or inherited from refs) into the g...
Geom::Affine get_gs2d_matrix(Geom::Affine const &ctm, Geom::Rect const &bbox) const
void ensureVector()
Forces vector to be built, if not present (i.e.
void setSwatch(bool swatch=true)
Geom::OptRect visualBounds(Geom::Affine const &transform=Geom::identity(), bool wfilter=true, bool wclip=true, bool wmask=true) const
Get item's visual bounding box in this item's coordinate system.
unsigned patch_columns()
Number of patch columns.
bool read(SPMeshGradient *mg)
SPMeshNode * node(unsigned i, unsigned j)
SPObject is an abstract base class of all of the document nodes at the SVG document level.
Inkscape::XML::Node * repr
void setAttribute(Inkscape::Util::const_char_ptr key, Inkscape::Util::const_char_ptr value)
void requestModified(unsigned int flags)
Requests that a modification notification signal be emitted later (e.g.
SPObject * get_child_by_repr(Inkscape::XML::Node *repr)
Return object's child whose node pointer equals repr.
virtual void set(SPAttr key, const char *value)
virtual void remove_child(Inkscape::XML::Node *child)
void getLinkedRecursive(std::vector< SPObject * > &objects, LinkedObjectNature direction=LinkedObjectNature::ANY) const
Grows the input list with all linked items recursively in both child nodes and links of links.
char const * getId() const
Returns the objects current ID string.
virtual Inkscape::XML::Node * write(Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, unsigned int flags)
void readAttr(char const *key)
Read value of key attribute from XML node into object.
Inkscape::XML::Node * getRepr()
Returns the XML representation of tree.
virtual void child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
char const * getAttribute(char const *name) const
void objectTrace(std::string const &, bool in=true, unsigned flags=0)
virtual void build(SPDocument *doc, Inkscape::XML::Node *repr)
SPStop * getNextStop()
Virtual write: write object attributes to repr.
Inkscape::Colors::Color getColor() const
TODO: insert short description here.
_cairo_pattern cairo_pattern_t
SPGradient * sp_gradient_ensure_vector_normalized(SPGradient *gr)
Either normalizes given gradient to vector, or returns fresh normalized vector - in latter case,...
Inkscape::XML::Node * node
Affine identity()
Create an identity matrix.
static R & release(R &r)
Decrements the reference count of a anchored object.
std::pair< char const *, char const * > getHrefAttribute(XML::Node const &node)
Get the 'href' or 'xlink:href' (fallback) attribute from an XML node.
static cairo_user_data_key_t key
void sp_repr_unparent(Inkscape::XML::Node *repr)
Remove repr from children of its parent node.
TODO: insert short description here.
@ SP_GRADIENT_SPREAD_REPEAT
@ SP_GRADIENT_SPREAD_REFLECT
@ SP_GRADIENT_UNITS_USERSPACEONUSE
@ SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX
static bool has_patchesFN(SPGradient const *gr)
True if gradient has patches (i.e.
void sp_gradient_pattern_common_setup(cairo_pattern_t *cp, SPGradient *gr, Geom::OptRect const &bbox, double opacity)
static SPGradient * chase_hrefs(SPGradient *const src, bool(*match)(SPGradient const *))
Returns the first of {src, src->ref->getObject(), src->ref->getObject()->ref->getObject(),...
static bool has_stopsFN(SPGradient const *gr)
True if gradient has stops.
static bool has_spread_set(SPGradient const *gr)
True if gradient has spread set.
static bool has_units_set(SPGradient const *gr)
True if gradient has units set.
@ SP_GRADIENT_STATE_UNKNOWN
TODO: insert short description here.
TODO: insert short description here.
SPMeshpatch: SVG <meshpatch> implementation.
SPMeshrow: SVG <meshrow> implementation.
SPObject * sp_object_unref(SPObject *object, SPObject *owner)
Decrease reference count of object, with possible debugging and finalization.
SPObject * sp_object_ref(SPObject *object, SPObject *owner)
Increase reference count of object, with possible debugging.
TODO: insert short description here.
TODO: insert short description here.
Interface for XML documents.
virtual Node * createElement(char const *name)=0
Differs from SPStop in that SPStop mirrors the <stop> element in the document, whereas SPGradientStop...
std::optional< Inkscape::Colors::Color > color
The effective gradient vector, after copying stops from the referenced gradient if necessary.
std::vector< SPGradientStop > stops
bool sp_svg_transform_read(gchar const *str, Geom::Affine *transform)
std::string sp_svg_transform_write(Geom::Affine const &transform)