Code

Merge and cleanup of GSoC C++-ification project.
[inkscape.git] / src / gradient-chemistry.cpp
index 0d99e7fa6d4aee14c729e4edb36c73e87d5f68a1..fb5dab648249b11873d83796c86b256a48b483d4 100644 (file)
@@ -6,6 +6,7 @@
  *   bulia byak
  *   Johan Engelen <j.b.c.engelen@ewi.utwente.nl>
  *   Jon A. Cruz <jon@joncruz.org>
+ *   Abhishek Sharma
  *
  * Copyright (C) 2010 Authors
  * Copyright (C) 2007 Johan Engelen
@@ -40,6 +41,7 @@
 #include "svg/css-ostringstream.h"
 #include "preferences.h"
 
+#define noSP_GR_VERBOSE
 
 // Terminology:
 //
 
 static void sp_gradient_repr_set_link(Inkscape::XML::Node *repr, SPGradient *gr);
 
-SPGradient *
-sp_gradient_ensure_vector_normalized(SPGradient *gr)
+SPGradient *sp_gradient_ensure_vector_normalized(SPGradient *gr)
 {
+#ifdef SP_GR_VERBOSE
+    g_message("sp_gradient_ensure_vector_normalized(%p)", gr);
+#endif
     g_return_val_if_fail(gr != NULL, NULL);
     g_return_val_if_fail(SP_IS_GRADIENT(gr), NULL);
 
@@ -91,9 +95,12 @@ sp_gradient_ensure_vector_normalized(SPGradient *gr)
  * Creates new private gradient for the given vector
  */
 
-static SPGradient *
-sp_gradient_get_private_normalized(SPDocument *document, SPGradient *vector, SPGradientType type)
+static SPGradient *sp_gradient_get_private_normalized(SPDocument *document, SPGradient *vector, SPGradientType type)
 {
+#ifdef SP_GR_VERBOSE
+    g_message("sp_gradient_get_private_normalized(%p, %p, %d)", document, vector, 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);
@@ -101,7 +108,7 @@ sp_gradient_get_private_normalized(SPDocument *document, SPGradient *vector, SPG
 
     SPDefs *defs = (SPDefs *) SP_DOCUMENT_DEFS(document);
 
-    Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document);
+    Inkscape::XML::Document *xml_doc = document->getReprDoc();
     // create a new private gradient of the requested type
     Inkscape::XML::Node *repr;
     if (type == SP_GRADIENT_TYPE_LINEAR) {
@@ -131,8 +138,7 @@ sp_gradient_get_private_normalized(SPDocument *document, SPGradient *vector, SPG
 /**
 Count how many times gr is used by the styles of o and its descendants
 */
-guint
-count_gradient_hrefs(SPObject *o, SPGradient *gr)
+guint count_gradient_hrefs(SPObject *o, SPGradient *gr)
 {
     if (!o)
         return 1;
@@ -155,8 +161,7 @@ count_gradient_hrefs(SPObject *o, SPGradient *gr)
         i ++;
     }
 
-    for (SPObject *child = o->first_child();
-         child != NULL; child = SP_OBJECT_NEXT(child)) {
+    for ( SPObject *child = o->firstChild(); child; child = child->getNext() ) {
         i += count_gradient_hrefs(child, gr);
     }
 
@@ -167,10 +172,12 @@ 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
  */
-SPGradient *
-sp_gradient_fork_private_if_necessary(SPGradient *gr, SPGradient *vector,
-                                      SPGradientType type, SPObject *o)
+SPGradient *sp_gradient_fork_private_if_necessary(SPGradient *gr, SPGradient *vector,
+                                                  SPGradientType type, SPObject *o)
 {
+#ifdef SP_GR_VERBOSE
+    g_message("sp_gradient_fork_private_if_necessary(%p, %p, %d, %p)", gr, vector, type, o);
+#endif
     g_return_val_if_fail(gr != NULL, NULL);
     g_return_val_if_fail(SP_IS_GRADIENT(gr), NULL);
 
@@ -191,7 +198,7 @@ sp_gradient_fork_private_if_necessary(SPGradient *gr, SPGradient *vector,
 
     // Check the number of uses of the gradient within this object;
     // if we are private and there are no other users,
-    if (!vector->isSwatch() && (SP_OBJECT_HREFCOUNT(gr) <= count_gradient_hrefs(user, gr))) {
+    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 */
@@ -206,7 +213,7 @@ sp_gradient_fork_private_if_necessary(SPGradient *gr, SPGradient *vector,
     if ((gr->hasStops()) ||
         (gr->state != SP_GRADIENT_STATE_UNKNOWN) ||
         (SP_OBJECT_PARENT(gr) != SP_OBJECT(defs)) ||
-        (SP_OBJECT_HREFCOUNT(gr) > 1)) {
+        (gr->hrefcount > 1)) {
         // we have to clone a fresh new private gradient for the given vector
 
         // create an empty one
@@ -237,17 +244,19 @@ sp_gradient_fork_private_if_necessary(SPGradient *gr, SPGradient *vector,
     }
 }
 
-SPGradient *
-sp_gradient_fork_vector_if_necessary (SPGradient *gr)
+SPGradient *sp_gradient_fork_vector_if_necessary(SPGradient *gr)
 {
+#ifdef SP_GR_VERBOSE
+    g_message("sp_gradient_fork_vector_if_necessary(%p)", gr);
+#endif
     // Some people actually prefer their gradient vectors to be shared...
     Inkscape::Preferences *prefs = Inkscape::Preferences::get();
     if (!prefs->getBool("/options/forkgradientvectors/value", true))
         return gr;
 
-    if (SP_OBJECT_HREFCOUNT(gr) > 1) {
+    if (gr->hrefcount > 1) {
         SPDocument *doc = SP_OBJECT_DOCUMENT(gr);
-        Inkscape::XML::Document *xml_doc = sp_document_repr_doc(doc);
+        Inkscape::XML::Document *xml_doc = doc->getReprDoc();
 
         Inkscape::XML::Node *repr = SP_OBJECT_REPR (gr)->duplicate(xml_doc);
         SP_OBJECT_REPR (SP_DOCUMENT_DEFS (doc))->addChild(repr, NULL);
@@ -262,9 +271,11 @@ sp_gradient_fork_vector_if_necessary (SPGradient *gr)
 /**
  *  Obtain the vector from the gradient. A forked vector will be created and linked to this gradient if another gradient uses it.
  */
-SPGradient *
-sp_gradient_get_forked_vector_if_necessary(SPGradient *gradient, bool force_vector)
+SPGradient *sp_gradient_get_forked_vector_if_necessary(SPGradient *gradient, bool force_vector)
 {
+#ifdef SP_GR_VERBOSE
+    g_message("sp_gradient_get_forked_vector_if_necessary(%p, %d)", gradient, force_vector);
+#endif
     SPGradient *vector = gradient->getVector(force_vector);
     vector = sp_gradient_fork_vector_if_necessary (vector);
     if ( gradient != vector && gradient->ref->getObject() != vector ) {
@@ -279,13 +290,15 @@ sp_gradient_get_forked_vector_if_necessary(SPGradient *gradient, bool force_vect
  * instead. No forking or reapplying is done because this is only called for newly created privates.
  * @return The new gradient.
  */
-SPGradient *
-sp_gradient_reset_to_userspace (SPGradient *gr, SPItem *item)
+SPGradient *sp_gradient_reset_to_userspace(SPGradient *gr, SPItem *item)
 {
+#ifdef SP_GR_VERBOSE
+    g_message("sp_gradient_reset_to_userspace(%p, %p)", gr, item);
+#endif
     Inkscape::XML::Node *repr = SP_OBJECT_REPR(gr);
 
     // calculate the bbox of the item
-    SP_OBJECT_DOCUMENT(item)->ensure_up_to_date();
+    SP_OBJECT_DOCUMENT(item)->ensureUpToDate();
     Geom::OptRect bbox = item->getBounds(Geom::identity()); // we need "true" bbox without item_i2d_affine
 
     if (!bbox)
@@ -331,11 +344,17 @@ sp_gradient_reset_to_userspace (SPGradient *gr, SPItem *item)
  * Convert an item's gradient to userspace if necessary, also fork it if necessary.
  * @return The new gradient.
  */
-SPGradient *
-sp_gradient_convert_to_userspace(SPGradient *gr, SPItem *item, gchar const *property)
+SPGradient *sp_gradient_convert_to_userspace(SPGradient *gr, SPItem *item, gchar const *property)
 {
+#ifdef SP_GR_VERBOSE
+    g_message("sp_gradient_convert_to_userspace(%p, %p, \"%s\")", gr, item, property);
+#endif
     g_return_val_if_fail(SP_IS_GRADIENT(gr), NULL);
 
+    if ( gr && gr->isSolid() ) {
+        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, SP_OBJECT(item));
@@ -345,7 +364,7 @@ sp_gradient_convert_to_userspace(SPGradient *gr, SPItem *item, gchar const *prop
         Inkscape::XML::Node *repr = SP_OBJECT_REPR(gr);
 
         // calculate the bbox of the item
-        SP_OBJECT_DOCUMENT(item)->ensure_up_to_date();
+        SP_OBJECT_DOCUMENT(item)->ensureUpToDate();
         Geom::Matrix bbox2user;
         Geom::OptRect bbox = item->getBounds(Geom::identity()); // we need "true" bbox without item_i2d_affine
         if ( bbox ) {
@@ -443,9 +462,11 @@ sp_gradient_convert_to_userspace(SPGradient *gr, SPItem *item, gchar const *prop
     return gr;
 }
 
-void
-sp_gradient_transform_multiply(SPGradient *gradient, Geom::Matrix postmul, bool set)
+void sp_gradient_transform_multiply(SPGradient *gradient, Geom::Matrix postmul, bool set)
 {
+#ifdef SP_GR_VERBOSE
+    g_message("sp_gradient_transform_multiply(%p, , %d)", gradient, set);
+#endif
     if (set) {
         gradient->gradientTransform = postmul;
     } else {
@@ -458,24 +479,23 @@ sp_gradient_transform_multiply(SPGradient *gradient, Geom::Matrix postmul, bool
     g_free(c);
 }
 
-SPGradient *
-sp_item_gradient (SPItem *item, bool fill_or_stroke)
+SPGradient *sp_item_gradient(SPItem *item, bool fill_or_stroke)
 {
-    SPStyle *style = SP_OBJECT_STYLE (item);
-    SPGradient *gradient = NULL;
+    SPStyle *style = item->style;
+    SPGradient *gradient = 0;
 
     if (fill_or_stroke) {
         if (style && (style->fill.isPaintserver())) {
-            SPObject *server = SP_OBJECT_STYLE_FILL_SERVER(item);
-            if (SP_IS_GRADIENT (server)) {
-                gradient = SP_GRADIENT (server);
+            SPPaintServer *server = item->style->getFillPaintServer();
+            if ( SP_IS_GRADIENT(server) ) {
+                gradient = SP_GRADIENT(server);
             }
         }
     } else {
         if (style && (style->stroke.isPaintserver())) {
-            SPObject *server = SP_OBJECT_STYLE_STROKE_SERVER(item);
-            if (SP_IS_GRADIENT (server)) {
-                gradient = SP_GRADIENT (server);
+            SPPaintServer *server = item->style->getStrokePaintServer();
+            if ( SP_IS_GRADIENT(server) ) {
+                gradient = SP_GRADIENT(server);
             }
         }
     }
@@ -483,7 +503,7 @@ sp_item_gradient (SPItem *item, bool fill_or_stroke)
    return gradient;
 }
 
-SPStopsp_last_stop(SPGradient *gradient)
+SPStop *sp_last_stop(SPGradient *gradient)
 {
     for (SPStop *stop = gradient->getFirstStop(); stop != NULL; stop = stop->getNextStop()) {
         if (stop->getNextStop() == NULL)
@@ -492,8 +512,7 @@ SPStop* sp_last_stop(SPGradient *gradient)
     return NULL;
 }
 
-SPStop*
-sp_get_stop_i(SPGradient *gradient, guint stop_i)
+SPStop *sp_get_stop_i(SPGradient *gradient, guint stop_i)
 {
     SPStop *stop = gradient->getFirstStop();
 
@@ -513,20 +532,22 @@ sp_get_stop_i(SPGradient *gradient, guint stop_i)
     return stop;
 }
 
-guint32
-average_color (guint32 c1, guint32 c2, gdouble p)
+guint32 average_color(guint32 c1, guint32 c2, gdouble p)
 {
     guint32 r = (guint32) (SP_RGBA32_R_U (c1) * (1 - p) + SP_RGBA32_R_U (c2) * p);
     guint32 g = (guint32) (SP_RGBA32_G_U (c1) * (1 - p) + SP_RGBA32_G_U (c2) * p);
     guint32 b = (guint32) (SP_RGBA32_B_U (c1) * (1 - p) + SP_RGBA32_B_U (c2) * p);
     guint32 a = (guint32) (SP_RGBA32_A_U (c1) * (1 - p) + SP_RGBA32_A_U (c2) * p);
 
-    return SP_RGBA32_U_COMPOSE (r, g, b, a);
+    return SP_RGBA32_U_COMPOSE(r, g, b, a);
 }
 
-SPStop *
-sp_vector_add_stop (SPGradient *vector, SPStop* prev_stop, SPStop* next_stop, gfloat offset)
+SPStop *sp_vector_add_stop(SPGradient *vector, SPStop* prev_stop, SPStop* next_stop, gfloat offset)
 {
+#ifdef SP_GR_VERBOSE
+    g_message("sp_vector_add_stop(%p, %p, %p, %f)", vector, prev_stop, next_stop, offset);
+#endif
+
     Inkscape::XML::Node *new_stop_repr = NULL;
     new_stop_repr = SP_OBJECT_REPR(prev_stop)->duplicate(SP_OBJECT_REPR(vector)->document());
     SP_OBJECT_REPR(vector)->addChild(new_stop_repr, SP_OBJECT_REPR(prev_stop));
@@ -548,8 +569,7 @@ sp_vector_add_stop (SPGradient *vector, SPStop* prev_stop, SPStop* next_stop, gf
     return newstop;
 }
 
-void
-sp_item_gradient_edit_stop (SPItem *item, guint point_type, guint point_i, bool fill_or_stroke)
+void sp_item_gradient_edit_stop(SPItem *item, guint point_type, guint point_i, bool fill_or_stroke)
 {
     SPGradient *gradient = sp_item_gradient (item, fill_or_stroke);
 
@@ -589,8 +609,7 @@ sp_item_gradient_edit_stop (SPItem *item, guint point_type, guint point_i, bool
     }
 }
 
-guint32
-sp_item_gradient_stop_query_style (SPItem *item, guint point_type, guint point_i, bool fill_or_stroke)
+guint32 sp_item_gradient_stop_query_style(SPItem *item, guint point_type, guint point_i, bool fill_or_stroke)
 {
     SPGradient *gradient = sp_item_gradient (item, fill_or_stroke);
 
@@ -642,9 +661,11 @@ sp_item_gradient_stop_query_style (SPItem *item, guint point_type, guint point_i
     return 0;
 }
 
-void
-sp_item_gradient_stop_set_style (SPItem *item, guint point_type, guint point_i, bool fill_or_stroke, SPCSSAttr *stop)
+void sp_item_gradient_stop_set_style(SPItem *item, guint point_type, guint point_i, bool fill_or_stroke, SPCSSAttr *stop)
 {
+#ifdef SP_GR_VERBOSE
+    g_message("sp_item_gradient_stop_set_style(%p, %d, %d, %d, %p)", item, point_type, point_i, fill_or_stroke, stop);
+#endif
     SPGradient *gradient = sp_item_gradient (item, fill_or_stroke);
 
     if (!gradient || !SP_IS_GRADIENT(gradient))
@@ -699,9 +720,11 @@ sp_item_gradient_stop_set_style (SPItem *item, guint point_type, guint point_i,
     }
 }
 
-void
-sp_item_gradient_reverse_vector (SPItem *item, bool fill_or_stroke)
+void sp_item_gradient_reverse_vector(SPItem *item, bool fill_or_stroke)
 {
+#ifdef SP_GR_VERBOSE
+    g_message("sp_item_gradient_reverse_vector(%p, %d)", item, fill_or_stroke);
+#endif
     SPGradient *gradient = sp_item_gradient (item, fill_or_stroke);
     if (!gradient || !SP_IS_GRADIENT(gradient))
         return;
@@ -718,8 +741,7 @@ sp_item_gradient_reverse_vector (SPItem *item, bool fill_or_stroke)
     GSList *child_reprs = NULL;
     GSList *child_objects = NULL;
     std::vector<double> offsets;
-    for (SPObject *child = vector->first_child();
-         child != NULL; child = SP_OBJECT_NEXT(child)) {
+    for ( SPObject *child = vector->firstChild(); child; child = child->getNext()) {
         child_reprs = g_slist_prepend (child_reprs, SP_OBJECT_REPR(child));
         child_objects = g_slist_prepend (child_objects, child);
         offsets.push_back(sp_repr_get_double_attribute(SP_OBJECT_REPR(child), "offset", 0));
@@ -757,9 +779,11 @@ sp_item_gradient_reverse_vector (SPItem *item, bool fill_or_stroke)
 Set the position of point point_type of the gradient applied to item (either fill_or_stroke) to
 p_w (in desktop coordinates). Write_repr if you want the change to become permanent.
 */
-void
-sp_item_gradient_set_coords (SPItem *item, guint point_type, guint point_i, Geom::Point p_w, bool fill_or_stroke, bool write_repr, bool scale)
+void sp_item_gradient_set_coords(SPItem *item, guint point_type, guint point_i, Geom::Point p_w, bool fill_or_stroke, bool write_repr, bool scale)
 {
+#ifdef SP_GR_VERBOSE
+    g_message("sp_item_gradient_set_coords(%p, %d, %d, ...)", item, point_type, point_i );
+#endif
     SPGradient *gradient = sp_item_gradient (item, fill_or_stroke);
 
     if (!gradient || !SP_IS_GRADIENT(gradient))
@@ -954,8 +978,7 @@ sp_item_gradient_set_coords (SPItem *item, guint point_type, guint point_i, Geom
     }
 }
 
-SPGradient *
-sp_item_gradient_get_vector (SPItem *item, bool fill_or_stroke)
+SPGradient *sp_item_gradient_get_vector(SPItem *item, bool fill_or_stroke)
 {
     SPGradient *gradient = sp_item_gradient (item, fill_or_stroke);
 
@@ -965,8 +988,7 @@ sp_item_gradient_get_vector (SPItem *item, bool fill_or_stroke)
     return NULL;
 }
 
-SPGradientSpread
-sp_item_gradient_get_spread (SPItem *item, bool fill_or_stroke)
+SPGradientSpread sp_item_gradient_get_spread(SPItem *item, bool fill_or_stroke)
 {
     SPGradientSpread spread = SP_GRADIENT_SPREAD_PAD;
     SPGradient *gradient = sp_item_gradient (item, fill_or_stroke);
@@ -983,9 +1005,11 @@ Returns the position of point point_type of the gradient applied to item (either
 in desktop coordinates.
 */
 
-Geom::Point
-sp_item_gradient_get_coords (SPItem *item, guint point_type, guint point_i, bool fill_or_stroke)
+Geom::Point sp_item_gradient_get_coords(SPItem *item, guint point_type, guint point_i, bool fill_or_stroke)
 {
+#ifdef SP_GR_VERBOSE
+    g_message("sp_item_gradient_get_coords(%p, %d, %d, %d)", item, point_type, point_i, fill_or_stroke);
+#endif
     SPGradient *gradient = sp_item_gradient (item, fill_or_stroke);
 
     Geom::Point p (0, 0);
@@ -1040,7 +1064,7 @@ sp_item_gradient_get_coords (SPItem *item, guint point_type, guint point_i, bool
     }
 
     if (SP_GRADIENT(gradient)->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) {
-        SP_OBJECT_DOCUMENT(item)->ensure_up_to_date();
+        SP_OBJECT_DOCUMENT(item)->ensureUpToDate();
         Geom::OptRect bbox = item->getBounds(Geom::identity()); // we need "true" bbox without item_i2d_affine
         if (bbox) {
             p *= Geom::Matrix(bbox->dimensions()[Geom::X], 0,
@@ -1059,9 +1083,11 @@ sp_item_gradient_get_coords (SPItem *item, guint point_type, guint point_i, bool
  * gr has to be a normalized vector.
  */
 
-SPGradient *
-sp_item_set_gradient(SPItem *item, SPGradient *gr, SPGradientType type, bool is_fill)
+SPGradient *sp_item_set_gradient(SPItem *item, SPGradient *gr, SPGradientType type, bool is_fill)
 {
+#ifdef SP_GR_VERBOSE
+    g_message("sp_item_set_gradient(%p, %p, %d, %d)", item, gr, type, is_fill);
+#endif
     g_return_val_if_fail(item != NULL, NULL);
     g_return_val_if_fail(SP_IS_ITEM(item), NULL);
     g_return_val_if_fail(gr != NULL, NULL);
@@ -1083,11 +1109,11 @@ sp_item_set_gradient(SPItem *item, SPGradient *gr, SPGradientType type, bool is_
         /* Current fill style is the gradient of the required type */
         SPGradient *current = SP_GRADIENT(ps);
 
-        //g_message("hrefcount %d   count %d\n", SP_OBJECT_HREFCOUNT(current), count_gradient_hrefs(SP_OBJECT(item), current));
+        //g_message("hrefcount %d   count %d\n", current->hrefcount, count_gradient_hrefs(SP_OBJECT(item), current));
 
         if (!current->isSwatch()
-            && (SP_OBJECT_HREFCOUNT(current) == 1 ||
-            SP_OBJECT_HREFCOUNT(current) == count_gradient_hrefs(SP_OBJECT(item), current))) {
+            && (current->hrefcount == 1 ||
+            current->hrefcount == count_gradient_hrefs(SP_OBJECT(item), current))) {
 
             // current is private and it's either used once, or all its uses are by children of item;
             // so just change its href to vector
@@ -1130,6 +1156,9 @@ sp_item_set_gradient(SPItem *item, SPGradient *gr, SPGradientType type, bool is_
 
 static void sp_gradient_repr_set_link(Inkscape::XML::Node *repr, SPGradient *link)
 {
+#ifdef SP_GR_VERBOSE
+    g_message("sp_gradient_repr_set_link(%p, %p)", repr, link);
+#endif
     g_return_if_fail(repr != NULL);
     if (link) {
         g_return_if_fail(SP_IS_GRADIENT(link));
@@ -1144,59 +1173,54 @@ static void sp_gradient_repr_set_link(Inkscape::XML::Node *repr, SPGradient *lin
     }
 }
 
-/*
- * Get default normalized gradient vector of document, create if there is none
- */
 
-SPGradient *
-sp_document_default_gradient_vector(SPDocument *document, guint32 color)
+static void addStop( Inkscape::XML::Node *parent, Glib::ustring const &color, gint opacity, gchar const *offset )
 {
-    SPDefs *defs = (SPDefs *) SP_DOCUMENT_DEFS(document);
-    Inkscape::XML::Document *xml_doc = sp_document_repr_doc(document);
-
-    Inkscape::XML::Node *repr = xml_doc->createElement("svg:linearGradient");
-
-    repr->setAttribute("inkscape:collect", "always");
-    // set here, but removed when it's edited in the gradient editor
-    // to further reduce clutter, we could
-    // (1) here, search gradients by color and return what is found without duplication
-    // (2) in fill & stroke, show only one copy of each gradient in list
-
-    Inkscape::XML::Node *stop = xml_doc->createElement("svg:stop");
-
-    gchar b[64];
-    sp_svg_write_color(b, sizeof(b), color);
-
+#ifdef SP_GR_VERBOSE
+    g_message("addStop(%p, %s, %d, %s)", parent, color.c_str(), opacity, offset);
+#endif
+    Inkscape::XML::Node *stop = parent->document()->createElement("svg:stop");
     {
-        gchar *t = g_strdup_printf("stop-color:%s;stop-opacity:1;", b);
-        stop->setAttribute("style", t);
-        g_free(t);
+        gchar *tmp = g_strdup_printf( "stop-color:%s;stop-opacity:%d;", color.c_str(), opacity );
+        stop->setAttribute( "style", tmp );
+        g_free(tmp);
     }
 
-    stop->setAttribute("offset", "0");
+    stop->setAttribute( "offset", offset );
 
-    repr->appendChild(stop);
+    parent->appendChild(stop);
     Inkscape::GC::release(stop);
+}
 
-    stop = xml_doc->createElement("svg:stop");
+/*
+ * Get default normalized gradient vector of document, create if there is none
+ */
+SPGradient *sp_document_default_gradient_vector( SPDocument *document, SPColor const &color, bool singleStop )
+{
+    SPDefs *defs = static_cast<SPDefs *>(SP_DOCUMENT_DEFS(document));
+    Inkscape::XML::Document *xml_doc = document->rdoc;
 
-    {
-        gchar *t = g_strdup_printf("stop-color:%s;stop-opacity:0;", b);
-        stop->setAttribute("style", t);
-        g_free(t);
-    }
+    Inkscape::XML::Node *repr = xml_doc->createElement("svg:linearGradient");
 
-    stop->setAttribute("offset", "1");
+    if ( !singleStop ) {
+        repr->setAttribute("inkscape:collect", "always");
+        // set here, but removed when it's edited in the gradient editor
+        // to further reduce clutter, we could
+        // (1) here, search gradients by color and return what is found without duplication
+        // (2) in fill & stroke, show only one copy of each gradient in list
+    }
 
-    repr->appendChild(stop);
-    Inkscape::GC::release(stop);
+    Glib::ustring colorStr = color.toString();
+    addStop( repr, colorStr, 1, "0" );
+    if ( !singleStop ) {
+        addStop( repr, colorStr, 0, "1" );
+    }
 
     SP_OBJECT_REPR(defs)->addChild(repr, NULL);
     Inkscape::GC::release(repr);
 
     /* fixme: This does not look like nice */
-    SPGradient *gr;
-    gr = (SPGradient *) document->getObjectByRepr(repr);
+    SPGradient *gr = static_cast<SPGradient *>(document->getObjectByRepr(repr));
     g_assert(gr != NULL);
     g_assert(SP_IS_GRADIENT(gr));
     /* fixme: Maybe add extra sanity check here */
@@ -1209,13 +1233,12 @@ sp_document_default_gradient_vector(SPDocument *document, guint32 color)
 Return the preferred vector for \a o, made from (in order of preference) its current vector,
 current fill or stroke color, or from desktop style if \a o is NULL or doesn't have style.
 */
-SPGradient *
-sp_gradient_vector_for_object(SPDocument *const doc, SPDesktop *const desktop,
-                              SPObject *const o, bool const is_fill)
+SPGradient *sp_gradient_vector_for_object( SPDocument *const doc, SPDesktop *const desktop,
+                                           SPObject *const o, bool const is_fill, bool singleStop )
 {
-    guint32 rgba = 0;
+    SPColor color;
     if (o == NULL || SP_OBJECT_STYLE(o) == NULL) {
-        rgba = sp_desktop_get_color(desktop, is_fill);
+        color = sp_desktop_get_color(desktop, is_fill);
     } else {
         // take the color of the object
         SPStyle const &style = *SP_OBJECT_STYLE(o);
@@ -1223,21 +1246,21 @@ sp_gradient_vector_for_object(SPDocument *const doc, SPDesktop *const desktop,
                                   ? style.fill
                                   : style.stroke );
         if (paint.isPaintserver()) {
-            SPObject *server = is_fill? SP_OBJECT_STYLE_FILL_SERVER(o) : SP_OBJECT_STYLE_STROKE_SERVER(o);
-            if (SP_IS_GRADIENT (server)) {
+            SPObject *server = is_fill? o->style->getFillPaintServer() : o->style->getStrokePaintServer();
+            if ( SP_IS_GRADIENT(server) ) {
                 return SP_GRADIENT(server)->getVector(true);
             } else {
-                rgba = sp_desktop_get_color(desktop, is_fill);
+                color = sp_desktop_get_color(desktop, is_fill);
             }
         } else if (paint.isColor()) {
-            rgba = paint.value.color.toRGBA32( 0xff );
+            color = paint.value.color;
         } else {
             // if o doesn't use flat color, then take current color of the desktop.
-            rgba = sp_desktop_get_color(desktop, is_fill);
+            color = sp_desktop_get_color(desktop, is_fill);
         }
     }
 
-    return sp_document_default_gradient_vector(doc, rgba);
+    return sp_document_default_gradient_vector( doc, color, singleStop );
 }
 
 
@@ -1250,4 +1273,4 @@ sp_gradient_vector_for_object(SPDocument *const doc, SPDesktop *const desktop,
   fill-column:99
   End:
 */
-// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :