Code

compile depending on WITH_LIBWPG
[inkscape.git] / src / sp-gradient.cpp
index d28f631ded7aab5513232452c8e0259811236d9a..a00924029c8970d5d427f380099ad4057d824ea7 100644 (file)
@@ -29,7 +29,7 @@
 #include <sigc++/functors/ptr_fun.h>
 #include <sigc++/adaptors/bind.h>
 
-#include "display/nr-gradient-gpl.h"
+#include "libnr/nr-gradient.h"
 #include "svg/svg.h"
 #include "svg/svg-color.h"
 #include "svg/css-ostringstream.h"
@@ -104,7 +104,7 @@ sp_stop_init(SPStop *stop)
 {
     stop->offset = 0.0;
     stop->currentColor = false;
-    sp_color_set_rgb_rgba32(&stop->specified_color, 0x000000ff);
+    stop->specified_color.set( 0x000000ff );
     stop->opacity = 1.0;
 }
 
@@ -148,7 +148,7 @@ sp_stop_set(SPObject *object, unsigned key, gchar const *value)
                     stop->currentColor = true;
                 } else {
                     guint32 const color = sp_svg_read_color(p, 0);
-                    sp_color_set_rgb_rgba32(&stop->specified_color, color);
+                    stop->specified_color.set( color );
                 }
             }
             {
@@ -167,7 +167,7 @@ sp_stop_set(SPObject *object, unsigned key, gchar const *value)
                 } else {
                     stop->currentColor = false;
                     guint32 const color = sp_svg_read_color(p, 0);
-                    sp_color_set_rgb_rgba32(&stop->specified_color, color);
+                    stop->specified_color.set( color );
                 }
             }
             object->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
@@ -204,9 +204,19 @@ sp_stop_write(SPObject *object, Inkscape::XML::Node *repr, guint flags)
     SPStop *stop = SP_STOP(object);
 
     if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
-        repr = sp_repr_new("svg:stop");
+        Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_OBJECT_DOCUMENT(object));
+        repr = xml_doc->createElement("svg:stop");
     }
 
+    guint32 specifiedcolor = stop->specified_color.toRGBA32( 255 );
+    gfloat opacity = stop->opacity;
+
+    if (((SPObjectClass *) stop_parent_class)->write)
+        (* ((SPObjectClass *) stop_parent_class)->write)(object, repr, flags);
+
+    // Since we do a hackish style setting here (because SPStyle does not support stop-color and
+    // stop-opacity), we must do it AFTER calling the parent write method; otherwise
+    // sp_object_write would clear our style= attribute (bug 1695287)
 
     Inkscape::CSSOStringStream os;
     os << "stop-color:";
@@ -214,10 +224,10 @@ sp_stop_write(SPObject *object, Inkscape::XML::Node *repr, guint flags)
         os << "currentColor";
     } else {
         gchar c[64];
-        sp_svg_write_color(c, 64, sp_color_get_rgba32_ualpha(&stop->specified_color, 255));
+        sp_svg_write_color(c, sizeof(c), specifiedcolor);
         os << c;
     }
-    os << ";stop-opacity:" << stop->opacity;
+    os << ";stop-opacity:" << opacity;
     repr->setAttribute("style", os.str().c_str());
     repr->setAttribute("stop-color", NULL);
     repr->setAttribute("stop-opacity", NULL);
@@ -225,9 +235,6 @@ sp_stop_write(SPObject *object, Inkscape::XML::Node *repr, guint flags)
     /* strictly speaking, offset an SVG <number> rather than a CSS one, but exponents make no sense
      * for offset proportions. */
 
-    if (((SPObjectClass *) stop_parent_class)->write)
-        (* ((SPObjectClass *) stop_parent_class)->write)(object, repr, flags);
-
     return repr;
 }
 
@@ -251,7 +258,7 @@ sp_stop_get_rgba32(SPStop const *const stop)
                              rgb0 | 0xff);
         return rgb0 | alpha;
     } else {
-        return sp_color_get_rgba32_falpha(&stop->specified_color, stop->opacity);
+        return stop->specified_color.toRGBA32( stop->opacity );
     }
 }
 
@@ -271,8 +278,7 @@ sp_stop_get_color(SPStop const *const stop)
         if (str) {
             color = sp_svg_read_color(str, dfl);
         }
-        SPColor ret;
-        sp_color_set_rgb_rgba32(&ret, color);
+        SPColor ret( color );
         return ret;
     } else {
         return stop->specified_color;
@@ -304,6 +310,9 @@ static void sp_gradient_rebuild_vector(SPGradient *gr);
 
 static void gradient_ref_changed(SPObject *old_ref, SPObject *ref, SPGradient *gradient);
 
+SPGradientSpread sp_gradient_get_spread(SPGradient *gradient);
+SPGradientUnits sp_gradient_get_units(SPGradient *gradient);
+
 static SPPaintServerClass *gradient_parent_class;
 
 /**
@@ -529,6 +538,16 @@ gradient_ref_changed(SPObject *old_ref, SPObject *ref, SPGradient *gr)
     {
         gr->modified_connection = ref->connectModified(sigc::bind<2>(sigc::ptr_fun(&gradient_ref_modified), gr));
     }
+
+    // Per SVG, all unset attributes must be inherited from linked gradient.
+    // So, as we're now (re)linked, we assign linkee's values to this gradient if they are not yet set -
+    // but without setting the _set flags.
+    // FIXME: do the same for gradientTransform too
+    if (!gr->units_set)
+        gr->units = sp_gradient_get_units (gr);
+    if (!gr->spread_set)
+        gr->spread = sp_gradient_get_spread (gr);
+
     /// \todo Fixme: what should the flags (second) argument be? */
     gradient_ref_modified(ref, 0, gr);
 }
@@ -596,7 +615,7 @@ sp_gradient_modified(SPObject *object, guint flags)
     if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) {
         sp_gradient_ensure_colors(gr);
     }
-    
+
     if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
     flags &= SP_OBJECT_MODIFIED_CASCADE;
 
@@ -660,12 +679,9 @@ sp_gradient_write(SPObject *object, Inkscape::XML::Node *repr, guint flags)
     }
 
     if ((flags & SP_OBJECT_WRITE_ALL) || gr->gradientTransform_set) {
-        gchar c[256];
-        if (sp_svg_transform_write(c, 256, gr->gradientTransform)) {
-            repr->setAttribute("gradientTransform", c);
-        } else {
-            repr->setAttribute("gradientTransform", NULL);
-        }
+        gchar *c=sp_svg_transform_write(gr->gradientTransform);
+        repr->setAttribute("gradientTransform", c);
+        g_free(c);
     }
 
     if ((flags & SP_OBJECT_WRITE_ALL) || gr->spread_set) {
@@ -790,6 +806,15 @@ has_spread_set(SPGradient const *gr)
     return gr->spread_set;
 }
 
+/**
+ * True if gradient has units set.
+ */
+static bool
+has_units_set(SPGradient const *gr)
+{
+    return gr->units_set;
+}
+
 
 /**
  * Returns private vector of given gradient (the gradient at the end of the href chain which has
@@ -826,6 +851,23 @@ sp_gradient_get_spread(SPGradient *gradient)
              : SP_GRADIENT_SPREAD_PAD ); // pad is the default
 }
 
+/**
+ * Returns the effective units of given gradient (climbing up the refs chain if needed).
+ *
+ * \pre SP_IS_GRADIENT(gradient).
+ */
+SPGradientUnits
+sp_gradient_get_units(SPGradient *gradient)
+{
+    g_return_val_if_fail(SP_IS_GRADIENT(gradient), SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX);
+
+    SPGradient const *src = chase_hrefs(gradient, has_units_set);
+    return ( src
+             ? src->units
+             : SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX ); // bbox is the default
+}
+
+
 /**
  * Clears the gradient's svg:stop children from its repr.
  */
@@ -862,6 +904,7 @@ sp_gradient_repr_write_vector(SPGradient *gr)
     g_return_if_fail(gr != NULL);
     g_return_if_fail(SP_IS_GRADIENT(gr));
 
+    Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_OBJECT_DOCUMENT(gr));
     Inkscape::XML::Node *repr = SP_OBJECT_REPR(gr);
 
     /* We have to be careful, as vector may be our own, so construct repr list at first */
@@ -869,12 +912,12 @@ sp_gradient_repr_write_vector(SPGradient *gr)
 
     for (guint i = 0; i < gr->vector.stops.size(); i++) {
         Inkscape::CSSOStringStream os;
-        Inkscape::XML::Node *child = sp_repr_new("svg:stop");
+        Inkscape::XML::Node *child = xml_doc->createElement("svg:stop");
         sp_repr_set_css_double(child, "offset", gr->vector.stops[i].offset);
         /* strictly speaking, offset an SVG <number> rather than a CSS one, but exponents make no
          * sense for offset proportions. */
         gchar c[64];
-        sp_svg_write_color(c, 64, sp_color_get_rgba32_ualpha(&gr->vector.stops[i].color, 0x00));
+        sp_svg_write_color(c, sizeof(c), gr->vector.stops[i].color.toRGBA32( 0x00 ));
         os << "stop-color:" << c << ";stop-opacity:" << gr->vector.stops[i].opacity;
         child->setAttribute("style", os.str().c_str());
         /* Order will be reversed here */
@@ -894,7 +937,7 @@ sp_gradient_repr_write_vector(SPGradient *gr)
 
 
 static void
-gradient_ref_modified(SPObject *href, guint flags, SPGradient *gradient)
+gradient_ref_modified(SPObject */*href*/, guint /*flags*/, SPGradient *gradient)
 {
     if (sp_gradient_invalidate_vector(gradient)) {
         SP_OBJECT(gradient)->requestModified(SP_OBJECT_MODIFIED_FLAG);
@@ -990,14 +1033,14 @@ sp_gradient_rebuild_vector(SPGradient *gr)
         {
             SPGradientStop gstop;
             gstop.offset = 0.0;
-            sp_color_set_rgb_rgba32(&gstop.color, 0x00000000);
+            gstop.color.set( 0x00000000 );
             gstop.opacity = 0.0;
             gr->vector.stops.push_back(gstop);
         }
         {
             SPGradientStop gstop;
             gstop.offset = 1.0;
-            sp_color_set_rgb_rgba32(&gstop.color, 0x00000000);
+            gstop.color.set( 0x00000000 );
             gstop.opacity = 0.0;
             gr->vector.stops.push_back(gstop);
         }
@@ -1009,7 +1052,7 @@ sp_gradient_rebuild_vector(SPGradient *gr)
             // If the first one is not at 0, then insert a copy of the first at 0.
             SPGradientStop gstop;
             gstop.offset = 0.0;
-            sp_color_copy(&gstop.color, &gr->vector.stops.front().color);
+            gstop.color = gr->vector.stops.front().color;
             gstop.opacity = gr->vector.stops.front().opacity;
             gr->vector.stops.insert(gr->vector.stops.begin(), gstop);
         }
@@ -1017,7 +1060,7 @@ sp_gradient_rebuild_vector(SPGradient *gr)
             // If the last one is not at 1, then insert a copy of the last at 1.
             SPGradientStop gstop;
             gstop.offset = 1.0;
-            sp_color_copy(&gstop.color, &gr->vector.stops.back().color);
+            gstop.color = gr->vector.stops.back().color;
             gstop.opacity = gr->vector.stops.back().opacity;
             gr->vector.stops.push_back(gstop);
         }
@@ -1043,14 +1086,12 @@ sp_gradient_ensure_colors(SPGradient *gr)
     }
 
     for (guint i = 0; i < gr->vector.stops.size() - 1; i++) {
-        guint32 color = sp_color_get_rgba32_falpha(&gr->vector.stops[i].color,
-                                                   gr->vector.stops[i].opacity);
+        guint32 color = gr->vector.stops[i].color.toRGBA32( gr->vector.stops[i].opacity );
         gint r0 = (color >> 24) & 0xff;
         gint g0 = (color >> 16) & 0xff;
         gint b0 = (color >> 8) & 0xff;
         gint a0 = color & 0xff;
-        color = sp_color_get_rgba32_falpha(&gr->vector.stops[i + 1].color,
-                                           gr->vector.stops[i + 1].opacity);
+        color = gr->vector.stops[i + 1].color.toRGBA32( gr->vector.stops[i + 1].opacity );
         gint r1 = (color >> 24) & 0xff;
         gint g1 = (color >> 16) & 0xff;
         gint b1 = (color >> 8) & 0xff;
@@ -1161,7 +1202,7 @@ sp_gradient_render_vector_block_rgba(SPGradient *const gradient, guchar *buf,
  */
 void
 sp_gradient_render_vector_block_rgb(SPGradient *gradient, guchar *buf,
-                                    gint const width, gint const height, gint const rowstride,
+                                    gint const width, gint const height, gint const /*rowstride*/,
                                     gint const pos, gint const span, bool const horizontal)
 {
     g_return_if_fail(gradient != NULL);
@@ -1238,7 +1279,7 @@ sp_gradient_set_gs2d_matrix(SPGradient *gr, NR::Matrix const &ctm,
                             NR::Rect const &bbox, NR::Matrix const &gs2d)
 {
     gr->gradientTransform = gs2d / ctm;
-    if ( gr->units == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX ) {
+    if (gr->units == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX ) {
         gr->gradientTransform = ( gr->gradientTransform
                                   / NR::translate(bbox.min())
                                   / NR::scale(bbox.dimensions()) );
@@ -1391,7 +1432,8 @@ sp_lineargradient_write(SPObject *object, Inkscape::XML::Node *repr, guint flags
     SPLinearGradient *lg = SP_LINEARGRADIENT(object);
 
     if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
-        repr = sp_repr_new("svg:linearGradient");
+        Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_OBJECT_DOCUMENT(object));
+        repr = xml_doc->createElement("svg:linearGradient");
     }
 
     if ((flags & SP_OBJECT_WRITE_ALL) || lg->x1._set)
@@ -1428,7 +1470,7 @@ sp_lineargradient_write(SPObject *object, Inkscape::XML::Node *repr, guint flags
 static SPPainter *
 sp_lineargradient_painter_new(SPPaintServer *ps,
                               NR::Matrix const &full_transform,
-                              NR::Matrix const &parent_transform,
+                              NR::Matrix const &/*parent_transform*/,
                               NRRect const *bbox)
 {
     SPLinearGradient *lg = SP_LINEARGRADIENT(ps);
@@ -1485,7 +1527,7 @@ sp_lineargradient_painter_new(SPPaintServer *ps,
 }
 
 static void
-sp_lineargradient_painter_free(SPPaintServer *ps, SPPainter *painter)
+sp_lineargradient_painter_free(SPPaintServer */*ps*/, SPPainter *painter)
 {
     g_free(painter);
 }
@@ -1692,7 +1734,8 @@ sp_radialgradient_write(SPObject *object, Inkscape::XML::Node *repr, guint flags
     SPRadialGradient *rg = SP_RADIALGRADIENT(object);
 
     if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
-        repr = sp_repr_new("svg:radialGradient");
+        Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_OBJECT_DOCUMENT(object));
+        repr = xml_doc->createElement("svg:radialGradient");
     }
 
     if ((flags & SP_OBJECT_WRITE_ALL) || rg->cx._set) sp_repr_set_svg_double(repr, "cx", rg->cx.computed);
@@ -1713,7 +1756,7 @@ sp_radialgradient_write(SPObject *object, Inkscape::XML::Node *repr, guint flags
 static SPPainter *
 sp_radialgradient_painter_new(SPPaintServer *ps,
                               NR::Matrix const &full_transform,
-                              NR::Matrix const &parent_transform,
+                              NR::Matrix const &/*parent_transform*/,
                               NRRect const *bbox)
 {
     SPRadialGradient *rg = SP_RADIALGRADIENT(ps);
@@ -1765,7 +1808,7 @@ sp_radialgradient_painter_new(SPPaintServer *ps,
 }
 
 static void
-sp_radialgradient_painter_free(SPPaintServer *ps, SPPainter *painter)
+sp_radialgradient_painter_free(SPPaintServer */*ps*/, SPPainter *painter)
 {
     g_free(painter);
 }