diff options
| author | Tavmjong Bah <tavmjong@free.fr> | 2016-10-14 20:01:57 +0000 |
|---|---|---|
| committer | tavmjong-free <tavmjong@free.fr> | 2016-10-14 20:01:57 +0000 |
| commit | 32442aec84cc13f0a22fa1f07f3de701c6938e5d (patch) | |
| tree | edbe1df058728d31fddd7a8ece45d3f5ae254b61 /src | |
| parent | Fix bug:1633521 on powerstroke (diff) | |
| download | inkscape-32442aec84cc13f0a22fa1f07f3de701c6938e5d.tar.gz inkscape-32442aec84cc13f0a22fa1f07f3de701c6938e5d.zip | |
Implement copying of objects with mesh gradients.
(bzr r15171)
Diffstat (limited to 'src')
| -rw-r--r-- | src/gradient-chemistry.cpp | 140 | ||||
| -rw-r--r-- | src/sp-mesh-array.cpp | 2 | ||||
| -rw-r--r-- | src/ui/tools/mesh-tool.cpp | 41 |
3 files changed, 105 insertions, 78 deletions
diff --git a/src/gradient-chemistry.cpp b/src/gradient-chemistry.cpp index cf5cda180..c133bfa7c 100644 --- a/src/gradient-chemistry.cpp +++ b/src/gradient-chemistry.cpp @@ -76,9 +76,14 @@ std::vector<PaintTarget> const &allPaintTargets() // "vector" is a gradient that has stops but not position coords. It can be referenced by one or // more privates. Objects should not refer to it directly. It has no radial/linear distinction. // -// "private" is a gradient that has no stops but has position coords (e.g. center, radius etc for a -// radial). It references a vector for the actual colors. Each private is only used by one -// object. It is either linear or radial. +// "array" is a gradient that has mesh rows and patches. It may or may not have "x" and "y" attributes. +// An array does have spacial information so it cannot be normalized like a "vector". +// +// "shared" is either a "vector" or "array" that is shared between multiple objects. +// +// "private" is a gradient that is not shared. A private linear or radial gradient has no stops but +// has position coords (e.g. center, radius etc for a radial); it references a "vector" for the +// actual colors. A mesh may or may not reference an array. Each private is only used by one object. static void sp_gradient_repr_set_link(Inkscape::XML::Node *repr, SPGradient *gr); @@ -89,6 +94,7 @@ SPGradient *sp_gradient_ensure_vector_normalized(SPGradient *gr) #endif g_return_val_if_fail(gr != NULL, NULL); g_return_val_if_fail(SP_IS_GRADIENT(gr), NULL); + g_return_val_if_fail(!SP_IS_MESHGRADIENT(gr), NULL); /* If we are already normalized vector, just return */ if (gr->state == SP_GRADIENT_STATE_VECTOR) return gr; @@ -122,19 +128,19 @@ SPGradient *sp_gradient_ensure_vector_normalized(SPGradient *gr) } /** - * Creates new private gradient for the given vector + * Creates new private gradient for the given shared gradient. */ -static SPGradient *sp_gradient_get_private_normalized(SPDocument *document, SPGradient *vector, SPGradientType type) +static SPGradient *sp_gradient_get_private_normalized(SPDocument *document, SPGradient *shared, SPGradientType type) { #ifdef SP_GR_VERBOSE - g_message("sp_gradient_get_private_normalized(%p, %p, %d)", document, vector, type); + g_message("sp_gradient_get_private_normalized(%p, %p, %d)", document, shared, type); #endif g_return_val_if_fail(document != NULL, NULL); - g_return_val_if_fail(vector != NULL, NULL); - g_return_val_if_fail(SP_IS_GRADIENT(vector), NULL); - g_return_val_if_fail(vector->hasStops(), NULL); + g_return_val_if_fail(shared != NULL, NULL); + g_return_val_if_fail(SP_IS_GRADIENT(shared), NULL); + g_return_val_if_fail(shared->hasStops() || shared->hasPatches(), NULL); SPDefs *defs = document->getDefs(); @@ -146,16 +152,14 @@ static SPGradient *sp_gradient_get_private_normalized(SPDocument *document, SPGr } else if(type == SP_GRADIENT_TYPE_RADIAL) { repr = xml_doc->createElement("svg:radialGradient"); } else { - // Rows/patches added in sp_gradient_reset_to_userspace for new meshes. repr = xml_doc->createElement("svg:meshgradient"); } // privates are garbage-collectable repr->setAttribute("inkscape:collect", "always"); - // link to vector - // MESH FIXME: Meshes don't used vector... but meshes simulating gradient across/along path might. - sp_gradient_repr_set_link(repr, vector); + // link to shared + sp_gradient_repr_set_link(repr, shared); /* Append the new private gradient to defs */ defs->getRepr()->appendChild(repr); @@ -204,21 +208,21 @@ static guint count_gradient_hrefs(SPObject *o, SPGradient *gr) /** - * If gr has other users, create a new private; also check if gr links to vector, relink if not + * If gr has other users, create a new shared; also check if gr links to shared, relink if not */ -static SPGradient *sp_gradient_fork_private_if_necessary(SPGradient *gr, SPGradient *vector, +static SPGradient *sp_gradient_fork_private_if_necessary(SPGradient *gr, SPGradient *shared, SPGradientType type, SPObject *o) { #ifdef SP_GR_VERBOSE - g_message("sp_gradient_fork_private_if_necessary(%p, %p, %d, %p)", gr, vector, type, o); + g_message("sp_gradient_fork_private_if_necessary(%p, %p, %d, %p)", gr, shared, type, o); #endif g_return_val_if_fail(gr != NULL, NULL); g_return_val_if_fail(SP_IS_GRADIENT(gr), NULL); - // Orphaned gradient, no vector with stops at the end of the line; this used to be an assert - // but i think we should not abort on this - maybe just write a validity warning into some sort - // of log - if ( !vector || !vector->hasStops() ) { + // Orphaned gradient, no shared with stops or patches at the end of the line; this used to be + // an assert + if ( !shared || !(shared->hasStops() || shared->hasPatches()) ) { + std::cerr << "sp_gradient_fork_private_if_necessary: Orphaned gradient" << std::endl; return (gr); } @@ -232,11 +236,11 @@ static SPGradient *sp_gradient_fork_private_if_necessary(SPGradient *gr, SPGradi // Check the number of uses of the gradient within this object; // if we are private and there are no other users, - if (!vector->isSwatch() && (gr->hrefcount <= count_gradient_hrefs(user, gr))) { - // check vector - if ( gr != vector && gr->ref->getObject() != vector ) { - /* our href is not the vector, and vector is different from gr; relink */ - sp_gradient_repr_set_link(gr->getRepr(), vector); + if (!shared->isSwatch() && (gr->hrefcount <= count_gradient_hrefs(user, gr))) { + // check shared + if ( gr != shared && gr->ref->getObject() != shared ) { + /* our href is not the shared, and shared is different from gr; relink */ + sp_gradient_repr_set_link(gr->getRepr(), shared); } return gr; } @@ -245,35 +249,49 @@ static SPGradient *sp_gradient_fork_private_if_necessary(SPGradient *gr, SPGradi SPObject *defs = doc->getDefs(); if ((gr->hasStops()) || + (gr->hasPatches()) || (gr->state != SP_GRADIENT_STATE_UNKNOWN) || (gr->parent != SP_OBJECT(defs)) || (gr->hrefcount > 1)) { - // we have to clone a fresh new private gradient for the given vector + + // we have to clone a fresh new private gradient for the given shared // create an empty one - SPGradient *gr_new = sp_gradient_get_private_normalized(doc, vector, type); + SPGradient *gr_new = sp_gradient_get_private_normalized(doc, shared, type); // copy all the attributes to it Inkscape::XML::Node *repr_new = gr_new->getRepr(); Inkscape::XML::Node *repr = gr->getRepr(); repr_new->setAttribute("gradientUnits", repr->attribute("gradientUnits")); repr_new->setAttribute("gradientTransform", repr->attribute("gradientTransform")); - repr_new->setAttribute("spreadMethod", repr->attribute("spreadMethod")); if (SP_IS_RADIALGRADIENT(gr)) { repr_new->setAttribute("cx", repr->attribute("cx")); repr_new->setAttribute("cy", repr->attribute("cy")); repr_new->setAttribute("fx", repr->attribute("fx")); repr_new->setAttribute("fy", repr->attribute("fy")); - repr_new->setAttribute("r", repr->attribute("r")); + repr_new->setAttribute("r", repr->attribute("r" )); + repr_new->setAttribute("fr", repr->attribute("fr")); + repr_new->setAttribute("spreadMethod", repr->attribute("spreadMethod")); } else if (SP_IS_LINEARGRADIENT(gr)) { repr_new->setAttribute("x1", repr->attribute("x1")); repr_new->setAttribute("y1", repr->attribute("y1")); repr_new->setAttribute("x2", repr->attribute("x2")); repr_new->setAttribute("y2", repr->attribute("y2")); - } else { - std::cerr << "sp_gradient_fork_private_if_necessary: mesh not implemented" << std::endl; + repr_new->setAttribute("spreadMethod", repr->attribute("spreadMethod")); + } else { // Mesh + repr_new->setAttribute("x", repr->attribute("x")); + repr_new->setAttribute("y", repr->attribute("y")); + repr_new->setAttribute("type", repr->attribute("type")); + + // We probably want a completely separate mesh gradient so + // copy the children and unset the link to the shared. + for ( Inkscape::XML::Node *child = repr->firstChild() ; child ; child = child->next() ) { + Inkscape::XML::Node *copy = child->duplicate(doc->getReprDoc()); + repr_new->appendChild( copy ); + Inkscape::GC::release( copy ); + } + sp_gradient_repr_set_link(repr_new, NULL); } - return gr_new; } else { return gr; @@ -409,6 +427,8 @@ SPGradient *sp_gradient_reset_to_userspace(SPGradient *gr, SPItem *item) // IN SPMeshNodeArray::create() //sp_repr_set_svg_double(repr, "x", bbox->min()[Geom::X]); //sp_repr_set_svg_double(repr, "y", bbox->min()[Geom::Y]); + + // We don't create a shared array gradient. SPMeshGradient* mg = SP_MESHGRADIENT( gr ); mg->array.create( mg, item, bbox ); } @@ -434,14 +454,14 @@ SPGradient *sp_gradient_convert_to_userspace(SPGradient *gr, SPItem *item, gchar return gr; } - // FIXME Transforming a mesh gradient is more complicated... probably need to add function to SPMeshArray.wq - if ( gr && SP_IS_MESHGRADIENT( gr ) ) { - return gr; - } - // First, fork it if it is shared - gr = sp_gradient_fork_private_if_necessary(gr, gr->getVector(), - SP_IS_RADIALGRADIENT(gr) ? SP_GRADIENT_TYPE_RADIAL : SP_GRADIENT_TYPE_LINEAR, item); + if (SP_IS_LINEARGRADIENT(gr)) { + gr = sp_gradient_fork_private_if_necessary(gr, gr->getVector(), SP_GRADIENT_TYPE_LINEAR, item); + } else if (SP_IS_RADIALGRADIENT(gr)) { + gr = sp_gradient_fork_private_if_necessary(gr, gr->getVector(), SP_GRADIENT_TYPE_RADIAL, item); + } else { + gr = sp_gradient_fork_private_if_necessary(gr, gr->getArray(), SP_GRADIENT_TYPE_MESH, item); + } if (gr->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) { @@ -495,7 +515,24 @@ SPGradient *sp_gradient_convert_to_userspace(SPGradient *gr, SPItem *item, gchar // as to cancel it out when it's applied to the gradient during rendering Geom::Affine point_convert = bbox2user * skew.inverse(); - if (SP_IS_RADIALGRADIENT(gr)) { + if (SP_IS_LINEARGRADIENT(gr)) { + SPLinearGradient *lg = SP_LINEARGRADIENT(gr); + + Geom::Point p1_b = Geom::Point(lg->x1.computed, lg->y1.computed); + Geom::Point p2_b = Geom::Point(lg->x2.computed, lg->y2.computed); + + Geom::Point p1_u = p1_b * point_convert; + Geom::Point p2_u = p2_b * point_convert; + + sp_repr_set_svg_double(repr, "x1", p1_u[Geom::X]); + sp_repr_set_svg_double(repr, "y1", p1_u[Geom::Y]); + sp_repr_set_svg_double(repr, "x2", p2_u[Geom::X]); + sp_repr_set_svg_double(repr, "y2", p2_u[Geom::Y]); + + // set the gradientUnits + repr->setAttribute("gradientUnits", "userSpaceOnUse"); + + } else if (SP_IS_RADIALGRADIENT(gr)) { SPRadialGradient *rg = SP_RADIALGRADIENT(gr); // original points in the bbox coords @@ -514,23 +551,12 @@ SPGradient *sp_gradient_convert_to_userspace(SPGradient *gr, SPItem *item, gchar sp_repr_set_svg_double(repr, "fy", f_u[Geom::Y]); sp_repr_set_svg_double(repr, "r", r_u); - } else { - SPLinearGradient *lg = SP_LINEARGRADIENT(gr); + // set the gradientUnits + repr->setAttribute("gradientUnits", "userSpaceOnUse"); - Geom::Point p1_b = Geom::Point(lg->x1.computed, lg->y1.computed); - Geom::Point p2_b = Geom::Point(lg->x2.computed, lg->y2.computed); - - Geom::Point p1_u = p1_b * point_convert; - Geom::Point p2_u = p2_b * point_convert; - - sp_repr_set_svg_double(repr, "x1", p1_u[Geom::X]); - sp_repr_set_svg_double(repr, "y1", p1_u[Geom::Y]); - sp_repr_set_svg_double(repr, "x2", p2_u[Geom::X]); - sp_repr_set_svg_double(repr, "y2", p2_u[Geom::Y]); + } else { + std::cerr << "sp_gradient_convert_to_userspace: Conversion of mesh to userspace not implemented" << std::endl; } - - // set the gradientUnits - repr->setAttribute("gradientUnits", "userSpaceOnUse"); } // apply the gradient to the item (may be necessary if we forked it); not recursive @@ -1281,10 +1307,10 @@ in desktop coordinates. */ Geom::Point getGradientCoords(SPItem *item, GrPointType point_type, guint point_i, Inkscape::PaintTarget fill_or_stroke) { + SPGradient *gradient = getGradient(item, fill_or_stroke); #ifdef SP_GR_VERBOSE - g_message("getGradientCoords(%p, %d, %d, %d)", item, point_type, point_i, fill_or_stroke); + g_message("getGradientCoords(%p, %d, %d, %d, %p)", item, point_type, point_i, fill_or_stroke, gradient); #endif - SPGradient *gradient = getGradient(item, fill_or_stroke); Geom::Point p (0, 0); diff --git a/src/sp-mesh-array.cpp b/src/sp-mesh-array.cpp index 87329b3f2..042800fbf 100644 --- a/src/sp-mesh-array.cpp +++ b/src/sp-mesh-array.cpp @@ -1096,7 +1096,7 @@ static SPColor default_color( SPItem *item ) { color = paint.value.color; } else if ( paint.isPaintserver() ) { SPObject const *server = item->style->getFillPaintServer(); - if ( SP_IS_GRADIENT(server) ) { + if ( SP_IS_GRADIENT(server) && SP_GRADIENT(server)->getVector() ) { SPStop *firstStop = SP_GRADIENT(server)->getVector()->getFirstStop(); if ( firstStop ) { color = firstStop->getEffectiveColor(); diff --git a/src/ui/tools/mesh-tool.cpp b/src/ui/tools/mesh-tool.cpp index 5e88e26b3..33cdc3bda 100644 --- a/src/ui/tools/mesh-tool.cpp +++ b/src/ui/tools/mesh-tool.cpp @@ -59,7 +59,7 @@ namespace Inkscape { namespace UI { namespace Tools { -static void sp_mesh_end_drag(MeshTool &rc); +static void sp_mesh_new_default(MeshTool &rc); const std::string& MeshTool::getPrefsPath() { return MeshTool::prefsPath; @@ -474,24 +474,25 @@ bool MeshTool::root_handler(GdkEvent* event) { // always resets selection to the single object under cursor sp_mesh_context_split_near_point(this, selection->items().front(), this->mousepoint_doc, event->button.time); } else { + sp_mesh_new_default(*this); // Create a new gradient with default coordinates. - auto items= selection->items(); - for(auto i=items.begin();i!=items.end();++i){ - SPItem *item = *i; - SPGradientType new_type = SP_GRADIENT_TYPE_MESH; - Inkscape::PaintTarget fsmode = (prefs->getInt("/tools/gradient/newfillorstroke", 1) != 0) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE; - -#ifdef DEBUG_MESH - std::cout << "sp_mesh_context_root_handler: creating new mesh on: " << (fsmode == Inkscape::FOR_FILL ? "Fill" : "Stroke") << std::endl; -#endif - SPGradient *vector = sp_gradient_vector_for_object(desktop->getDocument(), desktop, item, fsmode); - - SPGradient *priv = sp_item_set_gradient(item, vector, new_type, fsmode); - sp_gradient_reset_to_userspace(priv, item); - } - - DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_MESH, - _("Create default mesh")); +// auto items= selection->items(); +// for(auto i=items.begin();i!=items.end();++i){ +// SPItem *item = *i; +// SPGradientType new_type = SP_GRADIENT_TYPE_MESH; +// Inkscape::PaintTarget fsmode = (prefs->getInt("/tools/gradient/newfillorstroke", 1) != 0) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE; + +// #ifdef DEBUG_MESH +// std::cout << "sp_mesh_context_root_handler: creating new mesh on: " << (fsmode == Inkscape::FOR_FILL ? "Fill" : "Stroke") << std::endl; +// #endif +// SPGradient *vector = sp_gradient_vector_for_object(desktop->getDocument(), desktop, item, fsmode); + +// SPGradient *priv = sp_item_set_gradient(item, vector, new_type, fsmode); +// sp_gradient_reset_to_userspace(priv, item); +// } + +// DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_MESH, +// _("Create default mesh")); } ret = TRUE; @@ -666,7 +667,7 @@ bool MeshTool::root_handler(GdkEvent* event) { } } else { // Create a new mesh gradient - sp_mesh_end_drag(*this); + sp_mesh_new_default(*this); } } else if (this->item_to_select) { if (over_line && line) { @@ -931,7 +932,7 @@ bool MeshTool::root_handler(GdkEvent* event) { } // Creates a new mesh gradient. -static void sp_mesh_end_drag(MeshTool &rc) { +static void sp_mesh_new_default(MeshTool &rc) { SPDesktop *desktop = SP_EVENT_CONTEXT(&rc)->desktop; Inkscape::Selection *selection = desktop->getSelection(); SPDocument *document = desktop->getDocument(); |
