~centralelyon2010/inkscape/imagelinks2

1 by mental
moving trunk for module inkscape
1
/*
2
 * Various utility methods for gradients
3
 *
4
 * Authors:
5
 *   Lauris Kaplinski <lauris@kaplinski.com>
6
 *   bulia byak
2276 by johanengelen
Sorry, forgot the copyright text.
7
 *   Johan Engelen <j.b.c.engelen@ewi.utwente.nl>
9012.1.141 by Jon A. Cruz
New tab in Fill&Stroke dialog for swatch fills.
8
 *   Jon A. Cruz <jon@joncruz.org>
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
9
 *   Abhishek Sharma
1 by mental
moving trunk for module inkscape
10
 *
9012.1.141 by Jon A. Cruz
New tab in Fill&Stroke dialog for swatch fills.
11
 * Copyright (C) 2010 Authors
2276 by johanengelen
Sorry, forgot the copyright text.
12
 * Copyright (C) 2007 Johan Engelen
1 by mental
moving trunk for module inkscape
13
 * Copyright (C) 2001-2005 authors
14
 * Copyright (C) 2001 Ximian, Inc.
15
 *
16
 * Released under GNU GPL, read the file 'COPYING' for more information
17
 */
18
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
19
#include <2geom/transforms.h>
20
#include <2geom/bezier-curve.h>
1 by mental
moving trunk for module inkscape
21
22
#include "style.h"
23
#include "document-private.h"
24
#include "desktop-style.h"
25
26
#include "sp-gradient-reference.h"
2228 by johanengelen
Upgraded gradient tool =)
27
#include "sp-gradient-vector.h"
1 by mental
moving trunk for module inkscape
28
#include "sp-linear-gradient.h"
29
#include "sp-radial-gradient.h"
30
#include "sp-stop.h"
31
#include "widgets/gradient-vector.h"
32
33
#include "sp-text.h"
34
#include "sp-tspan.h"
35
#include "xml/repr.h"
36
#include "svg/svg.h"
232 by pjrm
#include svg/svg-color.h instead of or as well as (as appropriate) svg/svg.h.
37
#include "svg/svg-color.h"
3841 by buliabyak
a few more utility methods
38
#include "svg/css-ostringstream.h"
6885 by Ted Gould
From trunk
39
#include "preferences.h"
1 by mental
moving trunk for module inkscape
40
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
41
#define noSP_GR_VERBOSE
1 by mental
moving trunk for module inkscape
42
43
// Terminology:
44
//
45
// "vector" is a gradient that has stops but not position coords. It can be referenced by one or
46
// more privates. Objects should not refer to it directly. It has no radial/linear distinction.
47
//
48
// "private" is a gradient that has no stops but has position coords (e.g. center, radius etc for a
49
// radial). It references a vector for the actual colors. Each private is only used by one
50
// object. It is either linear or radial.
51
52
static void sp_gradient_repr_set_link(Inkscape::XML::Node *repr, SPGradient *gr);
53
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
54
SPGradient *sp_gradient_ensure_vector_normalized(SPGradient *gr)
1 by mental
moving trunk for module inkscape
55
{
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
56
#ifdef SP_GR_VERBOSE
57
    g_message("sp_gradient_ensure_vector_normalized(%p)", gr);
58
#endif
1 by mental
moving trunk for module inkscape
59
    g_return_val_if_fail(gr != NULL, NULL);
60
    g_return_val_if_fail(SP_IS_GRADIENT(gr), NULL);
61
62
    /* If we are already normalized vector, just return */
63
    if (gr->state == SP_GRADIENT_STATE_VECTOR) return gr;
64
    /* Fail, if we have wrong state set */
65
    if (gr->state != SP_GRADIENT_STATE_UNKNOWN) {
9012.1.115 by Jon A. Cruz
Cleanup on id access.
66
        g_warning("file %s: line %d: Cannot normalize private gradient to vector (%s)", __FILE__, __LINE__, gr->getId());
1 by mental
moving trunk for module inkscape
67
        return NULL;
68
    }
69
70
    /* First make sure we have vector directly defined (i.e. gr has its own stops) */
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
71
    if ( !gr->hasStops() ) {
1 by mental
moving trunk for module inkscape
72
        /* We do not have stops ourselves, so flatten stops as well */
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
73
        gr->ensureVector();
1 by mental
moving trunk for module inkscape
74
        g_assert(gr->vector.built);
75
        // this adds stops from gr->vector as children to gr
76
        sp_gradient_repr_write_vector (gr);
77
    }
78
79
    /* If gr hrefs some other gradient, remove the href */
80
    if (gr->ref->getObject()) {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
81
        // We are hrefing someone, so require flattening
82
        gr->updateRepr(SP_OBJECT_WRITE_EXT | SP_OBJECT_WRITE_ALL);
83
        sp_gradient_repr_set_link(gr->getRepr(), NULL);
1 by mental
moving trunk for module inkscape
84
    }
85
86
    /* Everything is OK, set state flag */
87
    gr->state = SP_GRADIENT_STATE_VECTOR;
88
    return gr;
89
}
90
91
/**
92
 * Creates new private gradient for the given vector
93
 */
94
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
95
static SPGradient *sp_gradient_get_private_normalized(SPDocument *document, SPGradient *vector, SPGradientType type)
1 by mental
moving trunk for module inkscape
96
{
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
97
#ifdef SP_GR_VERBOSE
98
    g_message("sp_gradient_get_private_normalized(%p, %p, %d)", document, vector, type);
99
#endif
100
1 by mental
moving trunk for module inkscape
101
    g_return_val_if_fail(document != NULL, NULL);
102
    g_return_val_if_fail(vector != NULL, NULL);
103
    g_return_val_if_fail(SP_IS_GRADIENT(vector), NULL);
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
104
    g_return_val_if_fail(vector->hasStops(), NULL);
105
106
    SPDefs *defs = document->getDefs();
107
108
    Inkscape::XML::Document *xml_doc = document->getReprDoc();
1 by mental
moving trunk for module inkscape
109
    // create a new private gradient of the requested type
110
    Inkscape::XML::Node *repr;
111
    if (type == SP_GRADIENT_TYPE_LINEAR) {
2253 by mental
start switching sp_repr_new* over to XML::Document::create*, and rename create methods to match DOM
112
        repr = xml_doc->createElement("svg:linearGradient");
1 by mental
moving trunk for module inkscape
113
    } else {
2253 by mental
start switching sp_repr_new* over to XML::Document::create*, and rename create methods to match DOM
114
        repr = xml_doc->createElement("svg:radialGradient");
1 by mental
moving trunk for module inkscape
115
    }
116
117
    // privates are garbage-collectable
118
    repr->setAttribute("inkscape:collect", "always");
119
120
    // link to vector
121
    sp_gradient_repr_set_link(repr, vector);
122
123
    /* Append the new private gradient to defs */
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
124
    defs->getRepr()->appendChild(repr);
1 by mental
moving trunk for module inkscape
125
    Inkscape::GC::release(repr);
126
127
    // get corresponding object
128
    SPGradient *gr = (SPGradient *) document->getObjectByRepr(repr);
129
    g_assert(gr != NULL);
130
    g_assert(SP_IS_GRADIENT(gr));
131
132
    return gr;
133
}
134
135
/**
136
Count how many times gr is used by the styles of o and its descendants
137
*/
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
138
guint count_gradient_hrefs(SPObject *o, SPGradient *gr)
1 by mental
moving trunk for module inkscape
139
{
140
    if (!o)
141
        return 1;
142
143
    guint i = 0;
144
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
145
    SPStyle *style = o->style;
1 by mental
moving trunk for module inkscape
146
    if (style
3706 by joncruz
Purged fill type enum
147
        && style->fill.isPaintserver()
1 by mental
moving trunk for module inkscape
148
        && SP_IS_GRADIENT(SP_STYLE_FILL_SERVER(style))
149
        && SP_GRADIENT(SP_STYLE_FILL_SERVER(style)) == gr)
150
    {
151
        i ++;
152
    }
153
    if (style
3706 by joncruz
Purged fill type enum
154
        && style->stroke.isPaintserver()
1 by mental
moving trunk for module inkscape
155
        && SP_IS_GRADIENT(SP_STYLE_STROKE_SERVER(style))
156
        && SP_GRADIENT(SP_STYLE_STROKE_SERVER(style)) == gr)
157
    {
158
        i ++;
159
    }
160
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
161
    for ( SPObject *child = o->firstChild(); child; child = child->getNext() ) {
1 by mental
moving trunk for module inkscape
162
        i += count_gradient_hrefs(child, gr);
163
    }
164
165
    return i;
166
}
167
168
169
/**
170
 * If gr has other users, create a new private; also check if gr links to vector, relink if not
171
 */
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
172
SPGradient *sp_gradient_fork_private_if_necessary(SPGradient *gr, SPGradient *vector,
173
                                                  SPGradientType type, SPObject *o)
1 by mental
moving trunk for module inkscape
174
{
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
175
#ifdef SP_GR_VERBOSE
176
    g_message("sp_gradient_fork_private_if_necessary(%p, %p, %d, %p)", gr, vector, type, o);
177
#endif
1 by mental
moving trunk for module inkscape
178
    g_return_val_if_fail(gr != NULL, NULL);
179
    g_return_val_if_fail(SP_IS_GRADIENT(gr), NULL);
180
181
    // Orphaned gradient, no vector with stops at the end of the line; this used to be an assert
182
    // but i think we should not abort on this - maybe just write a validity warning into some sort
183
    // of log
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
184
    if ( !vector || !vector->hasStops() ) {
1 by mental
moving trunk for module inkscape
185
        return (gr);
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
186
    }
1 by mental
moving trunk for module inkscape
187
188
    // user is the object that uses this gradient; normally it's item but for tspans, we
189
    // check its ancestor text so that tspans don't get different gradients from their
190
    // texts.
191
    SPObject *user = o;
192
    while (SP_IS_TSPAN(user)) {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
193
        user = user->parent;
1 by mental
moving trunk for module inkscape
194
    }
195
196
    // Check the number of uses of the gradient within this object;
197
    // if we are private and there are no other users,
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
198
    if (!vector->isSwatch() && (gr->hrefcount <= count_gradient_hrefs(user, gr))) {
1 by mental
moving trunk for module inkscape
199
        // check vector
200
        if ( gr != vector && gr->ref->getObject() != vector ) {
201
            /* our href is not the vector, and vector is different from gr; relink */
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
202
            sp_gradient_repr_set_link(gr->getRepr(), vector);
1 by mental
moving trunk for module inkscape
203
        }
204
        return gr;
205
    }
206
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
207
    SPDocument *doc = gr->document;
208
    SPObject *defs = doc->getDefs();
1 by mental
moving trunk for module inkscape
209
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
210
    if ((gr->hasStops()) ||
1 by mental
moving trunk for module inkscape
211
        (gr->state != SP_GRADIENT_STATE_UNKNOWN) ||
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
212
        (gr->parent != SP_OBJECT(defs)) ||
213
        (gr->hrefcount > 1)) {
1 by mental
moving trunk for module inkscape
214
        // we have to clone a fresh new private gradient for the given vector
215
216
        // create an empty one
217
        SPGradient *gr_new = sp_gradient_get_private_normalized(doc, vector, type);
218
219
        // copy all the attributes to it
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
220
        Inkscape::XML::Node *repr_new = gr_new->getRepr();
221
        Inkscape::XML::Node *repr = gr->getRepr();
1 by mental
moving trunk for module inkscape
222
        repr_new->setAttribute("gradientUnits", repr->attribute("gradientUnits"));
223
        repr_new->setAttribute("gradientTransform", repr->attribute("gradientTransform"));
224
        repr_new->setAttribute("spreadMethod", repr->attribute("spreadMethod"));
225
        if (SP_IS_RADIALGRADIENT(gr)) {
226
            repr_new->setAttribute("cx", repr->attribute("cx"));
227
            repr_new->setAttribute("cy", repr->attribute("cy"));
228
            repr_new->setAttribute("fx", repr->attribute("fx"));
229
            repr_new->setAttribute("fy", repr->attribute("fy"));
230
            repr_new->setAttribute("r", repr->attribute("r"));
231
        } else {
232
            repr_new->setAttribute("x1", repr->attribute("x1"));
233
            repr_new->setAttribute("y1", repr->attribute("y1"));
234
            repr_new->setAttribute("x2", repr->attribute("x2"));
235
            repr_new->setAttribute("y2", repr->attribute("y2"));
236
        }
237
238
        return gr_new;
239
    } else {
240
        return gr;
241
    }
242
}
243
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
244
SPGradient *sp_gradient_fork_vector_if_necessary(SPGradient *gr)
1 by mental
moving trunk for module inkscape
245
{
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
246
#ifdef SP_GR_VERBOSE
247
    g_message("sp_gradient_fork_vector_if_necessary(%p)", gr);
248
#endif
3886 by buliabyak
implement no-forking option
249
    // Some people actually prefer their gradient vectors to be shared...
6885 by Ted Gould
From trunk
250
    Inkscape::Preferences *prefs = Inkscape::Preferences::get();
251
    if (!prefs->getBool("/options/forkgradientvectors/value", true))
3886 by buliabyak
implement no-forking option
252
        return gr;
253
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
254
    if (gr->hrefcount > 1) {
255
        SPDocument *doc = gr->document;
256
        Inkscape::XML::Document *xml_doc = doc->getReprDoc();
1 by mental
moving trunk for module inkscape
257
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
258
        Inkscape::XML::Node *repr = gr->getRepr()->duplicate(xml_doc);
259
        doc->getDefs()->getRepr()->addChild(repr, NULL);
2723 by mental
plumb XML::Document parameter into duplication, courtesy of bryce
260
        SPGradient *gr_new = (SPGradient *) doc->getObjectByRepr(repr);
1 by mental
moving trunk for module inkscape
261
        gr_new = sp_gradient_ensure_vector_normalized (gr_new);
262
        Inkscape::GC::release(repr);
263
        return gr_new;
264
    }
265
    return gr;
266
}
267
268
/**
2758 by johanengelen
Gradient tool: fixed live updating of midstop dragging + [ 1667584 ] Crash when moving gradient nodes on group
269
 *  Obtain the vector from the gradient. A forked vector will be created and linked to this gradient if another gradient uses it.
270
 */
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
271
SPGradient *sp_gradient_get_forked_vector_if_necessary(SPGradient *gradient, bool force_vector)
2758 by johanengelen
Gradient tool: fixed live updating of midstop dragging + [ 1667584 ] Crash when moving gradient nodes on group
272
{
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
273
#ifdef SP_GR_VERBOSE
274
    g_message("sp_gradient_get_forked_vector_if_necessary(%p, %d)", gradient, force_vector);
275
#endif
9012.1.157 by Jon A. Cruz
Initial F&S dialog setting of swatch colors.
276
    SPGradient *vector = gradient->getVector(force_vector);
2758 by johanengelen
Gradient tool: fixed live updating of midstop dragging + [ 1667584 ] Crash when moving gradient nodes on group
277
    vector = sp_gradient_fork_vector_if_necessary (vector);
278
    if ( gradient != vector && gradient->ref->getObject() != vector ) {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
279
        sp_gradient_repr_set_link(gradient->getRepr(), vector);
2758 by johanengelen
Gradient tool: fixed live updating of midstop dragging + [ 1667584 ] Crash when moving gradient nodes on group
280
    }
281
    return vector;
282
}
283
284
285
/**
1 by mental
moving trunk for module inkscape
286
 * Convert an item's gradient to userspace _without_ preserving coords, setting them to defaults
149 by rwst
bulk trailing spaces removal. consistency through MD5 of binary
287
 * instead. No forking or reapplying is done because this is only called for newly created privates.
1 by mental
moving trunk for module inkscape
288
 * @return The new gradient.
289
 */
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
290
SPGradient *sp_gradient_reset_to_userspace(SPGradient *gr, SPItem *item)
1 by mental
moving trunk for module inkscape
291
{
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
292
#ifdef SP_GR_VERBOSE
293
    g_message("sp_gradient_reset_to_userspace(%p, %p)", gr, item);
294
#endif
295
    Inkscape::XML::Node *repr = gr->getRepr();
1 by mental
moving trunk for module inkscape
296
297
    // calculate the bbox of the item
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
298
    item->document->ensureUpToDate();
299
    Geom::OptRect bbox = item->visualBounds(); // we need "true" bbox without item_i2d_affine
2543 by mental
more NR::Maybe<NR::Rect> work
300
6891 by Ted Gould
Merge from fe-moved
301
    if (!bbox)
2953 by buliabyak
fix 1705412: handle gracefully assigning gradients to no-bbox items
302
        return gr;
303
6884 by Ted Gould
Merging from trunk
304
    Geom::Coord const width = bbox->dimensions()[Geom::X];
305
    Geom::Coord const height = bbox->dimensions()[Geom::Y];
2543 by mental
more NR::Maybe<NR::Rect> work
306
6884 by Ted Gould
Merging from trunk
307
    Geom::Point const center = bbox->midpoint();
1 by mental
moving trunk for module inkscape
308
309
    if (SP_IS_RADIALGRADIENT(gr)) {
6884 by Ted Gould
Merging from trunk
310
        sp_repr_set_svg_double(repr, "cx", center[Geom::X]);
311
        sp_repr_set_svg_double(repr, "cy", center[Geom::Y]);
312
        sp_repr_set_svg_double(repr, "fx", center[Geom::X]);
313
        sp_repr_set_svg_double(repr, "fy", center[Geom::Y]);
1 by mental
moving trunk for module inkscape
314
        sp_repr_set_svg_double(repr, "r", width/2);
315
316
        // we want it to be elliptic, not circular
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
317
        Geom::Affine squeeze = Geom::Translate (-center) *
6793 by johanengelen
convert almost all libnrtype to Geom::
318
            Geom::Scale(1, height/width) *
319
            Geom::Translate (center);
1 by mental
moving trunk for module inkscape
320
321
        gr->gradientTransform = squeeze;
322
        {
2543 by mental
more NR::Maybe<NR::Rect> work
323
            gchar *c=sp_svg_transform_write(gr->gradientTransform);
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
324
            gr->getRepr()->setAttribute("gradientTransform", c);
2543 by mental
more NR::Maybe<NR::Rect> work
325
            g_free(c);
1 by mental
moving trunk for module inkscape
326
        }
327
    } else {
6884 by Ted Gould
Merging from trunk
328
        sp_repr_set_svg_double(repr, "x1", (center - Geom::Point(width/2, 0))[Geom::X]);
329
        sp_repr_set_svg_double(repr, "y1", (center - Geom::Point(width/2, 0))[Geom::Y]);
330
        sp_repr_set_svg_double(repr, "x2", (center + Geom::Point(width/2, 0))[Geom::X]);
331
        sp_repr_set_svg_double(repr, "y2", (center + Geom::Point(width/2, 0))[Geom::Y]);
1 by mental
moving trunk for module inkscape
332
    }
333
334
    // set the gradientUnits
335
    repr->setAttribute("gradientUnits", "userSpaceOnUse");
336
337
    return gr;
338
}
339
340
/**
341
 * Convert an item's gradient to userspace if necessary, also fork it if necessary.
342
 * @return The new gradient.
343
 */
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
344
SPGradient *sp_gradient_convert_to_userspace(SPGradient *gr, SPItem *item, gchar const *property)
1 by mental
moving trunk for module inkscape
345
{
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
346
#ifdef SP_GR_VERBOSE
347
    g_message("sp_gradient_convert_to_userspace(%p, %p, \"%s\")", gr, item, property);
348
#endif
1 by mental
moving trunk for module inkscape
349
    g_return_val_if_fail(SP_IS_GRADIENT(gr), NULL);
350
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
351
    if ( gr && gr->isSolid() ) {
352
        return gr;
353
    }
354
1 by mental
moving trunk for module inkscape
355
    // First, fork it if it is shared
9012.1.157 by Jon A. Cruz
Initial F&S dialog setting of swatch colors.
356
    gr = sp_gradient_fork_private_if_necessary(gr, gr->getVector(),
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
357
                                               SP_IS_RADIALGRADIENT(gr) ? SP_GRADIENT_TYPE_RADIAL : SP_GRADIENT_TYPE_LINEAR, item);
358
359
    if (gr->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) {
360
361
        Inkscape::XML::Node *repr = gr->getRepr();
1 by mental
moving trunk for module inkscape
362
363
        // calculate the bbox of the item
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
364
        item->document->ensureUpToDate();
365
        Geom::Affine bbox2user;
366
        Geom::OptRect bbox = item->visualBounds(); // we need "true" bbox without item_i2d_affine
6891 by Ted Gould
Merge from fe-moved
367
        if ( bbox ) {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
368
            bbox2user = Geom::Affine(bbox->dimensions()[Geom::X], 0,
6884 by Ted Gould
Merging from trunk
369
                                   0, bbox->dimensions()[Geom::Y],
370
                                   bbox->min()[Geom::X], bbox->min()[Geom::Y]);
2543 by mental
more NR::Maybe<NR::Rect> work
371
        } else {
372
            // would be degenerate otherwise
6884 by Ted Gould
Merging from trunk
373
            bbox2user = Geom::identity();
2543 by mental
more NR::Maybe<NR::Rect> work
374
        }
1 by mental
moving trunk for module inkscape
375
376
        /* skew is the additional transform, defined by the proportions of the item, that we need
377
         * to apply to the gradient in order to work around this weird bit from SVG 1.1
378
         * (http://www.w3.org/TR/SVG11/pservers.html#LinearGradients):
379
         *
380
         *   When gradientUnits="objectBoundingBox" and gradientTransform is the identity
381
         *   matrix, the stripes of the linear gradient are perpendicular to the gradient
382
         *   vector in object bounding box space (i.e., the abstract coordinate system where
383
         *   (0,0) is at the top/left of the object bounding box and (1,1) is at the
384
         *   bottom/right of the object bounding box). When the object's bounding box is not
385
         *   square, the stripes that are conceptually perpendicular to the gradient vector
386
         *   within object bounding box space will render non-perpendicular relative to the
387
         *   gradient vector in user space due to application of the non-uniform scaling
388
         *   transformation from bounding box space to user space.
389
         */
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
390
        Geom::Affine skew = bbox2user;
6884 by Ted Gould
Merging from trunk
391
        double exp = skew.descrim();
1 by mental
moving trunk for module inkscape
392
        skew[0] /= exp;
393
        skew[1] /= exp;
394
        skew[2] /= exp;
395
        skew[3] /= exp;
396
        skew[4] = 0;
397
        skew[5] = 0;
398
399
        // apply skew to the gradient
400
        gr->gradientTransform = skew;
401
        {
2543 by mental
more NR::Maybe<NR::Rect> work
402
            gchar *c=sp_svg_transform_write(gr->gradientTransform);
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
403
            gr->getRepr()->setAttribute("gradientTransform", c);
2543 by mental
more NR::Maybe<NR::Rect> work
404
            g_free(c);
1 by mental
moving trunk for module inkscape
405
        }
406
407
        // Matrix to convert points to userspace coords; postmultiply by inverse of skew so
408
        // as to cancel it out when it's applied to the gradient during rendering
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
409
        Geom::Affine point_convert = bbox2user * skew.inverse();
1 by mental
moving trunk for module inkscape
410
411
        if (SP_IS_RADIALGRADIENT(gr)) {
412
            SPRadialGradient *rg = SP_RADIALGRADIENT(gr);
413
414
            // original points in the bbox coords
6884 by Ted Gould
Merging from trunk
415
            Geom::Point c_b = Geom::Point(rg->cx.computed, rg->cy.computed);
416
            Geom::Point f_b = Geom::Point(rg->fx.computed, rg->fy.computed);
1 by mental
moving trunk for module inkscape
417
            double r_b = rg->r.computed;
418
419
            // converted points in userspace coords
6884 by Ted Gould
Merging from trunk
420
            Geom::Point c_u = c_b * point_convert;
421
            Geom::Point f_u = f_b * point_convert;
422
            double r_u = r_b * point_convert.descrim();
1 by mental
moving trunk for module inkscape
423
6884 by Ted Gould
Merging from trunk
424
            sp_repr_set_svg_double(repr, "cx", c_u[Geom::X]);
425
            sp_repr_set_svg_double(repr, "cy", c_u[Geom::Y]);
426
            sp_repr_set_svg_double(repr, "fx", f_u[Geom::X]);
427
            sp_repr_set_svg_double(repr, "fy", f_u[Geom::Y]);
1 by mental
moving trunk for module inkscape
428
            sp_repr_set_svg_double(repr, "r", r_u);
429
430
        } else {
431
            SPLinearGradient *lg = SP_LINEARGRADIENT(gr);
432
6884 by Ted Gould
Merging from trunk
433
            Geom::Point p1_b = Geom::Point(lg->x1.computed, lg->y1.computed);
434
            Geom::Point p2_b = Geom::Point(lg->x2.computed, lg->y2.computed);
435
436
            Geom::Point p1_u = p1_b * point_convert;
437
            Geom::Point p2_u = p2_b * point_convert;
438
439
            sp_repr_set_svg_double(repr, "x1", p1_u[Geom::X]);
440
            sp_repr_set_svg_double(repr, "y1", p1_u[Geom::Y]);
441
            sp_repr_set_svg_double(repr, "x2", p2_u[Geom::X]);
442
            sp_repr_set_svg_double(repr, "y2", p2_u[Geom::Y]);
1 by mental
moving trunk for module inkscape
443
        }
444
445
        // set the gradientUnits
446
        repr->setAttribute("gradientUnits", "userSpaceOnUse");
447
    }
448
449
    // apply the gradient to the item (may be necessary if we forked it); not recursive
450
    // generally because grouped items will be taken care of later (we're being called
451
    // from sp_item_adjust_paint_recursive); however text and all its children should all
452
    // refer to one gradient, hence the recursive call for text (because we can't/don't
453
    // want to access tspans and set gradients on them separately)
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
454
    if (SP_IS_TEXT(item)) {
455
        sp_style_set_property_url(item, property, gr, true);
456
    } else {
457
        sp_style_set_property_url(item, property, gr, false);
458
    }
1 by mental
moving trunk for module inkscape
459
460
    return gr;
461
}
462
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
463
void sp_gradient_transform_multiply(SPGradient *gradient, Geom::Affine postmul, bool set)
1 by mental
moving trunk for module inkscape
464
{
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
465
#ifdef SP_GR_VERBOSE
466
    g_message("sp_gradient_transform_multiply(%p, , %d)", gradient, set);
467
#endif
1 by mental
moving trunk for module inkscape
468
    if (set) {
469
        gradient->gradientTransform = postmul;
470
    } else {
471
        gradient->gradientTransform *= postmul; // fixme: get gradient transform by climbing to hrefs?
472
    }
473
    gradient->gradientTransform_set = TRUE;
474
2543 by mental
more NR::Maybe<NR::Rect> work
475
    gchar *c=sp_svg_transform_write(gradient->gradientTransform);
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
476
    gradient->getRepr()->setAttribute("gradientTransform", c);
2543 by mental
more NR::Maybe<NR::Rect> work
477
    g_free(c);
1 by mental
moving trunk for module inkscape
478
}
479
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
480
SPGradient *sp_item_gradient(SPItem *item, bool fill_or_stroke)
1 by mental
moving trunk for module inkscape
481
{
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
482
    SPStyle *style = item->style;
483
    SPGradient *gradient = 0;
1 by mental
moving trunk for module inkscape
484
485
    if (fill_or_stroke) {
3706 by joncruz
Purged fill type enum
486
        if (style && (style->fill.isPaintserver())) {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
487
            SPPaintServer *server = item->style->getFillPaintServer();
488
            if ( SP_IS_GRADIENT(server) ) {
489
                gradient = SP_GRADIENT(server);
1 by mental
moving trunk for module inkscape
490
            }
491
        }
492
    } else {
3706 by joncruz
Purged fill type enum
493
        if (style && (style->stroke.isPaintserver())) {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
494
            SPPaintServer *server = item->style->getStrokePaintServer();
495
            if ( SP_IS_GRADIENT(server) ) {
496
                gradient = SP_GRADIENT(server);
1 by mental
moving trunk for module inkscape
497
            }
498
        }
499
    }
149 by rwst
bulk trailing spaces removal. consistency through MD5 of binary
500
1 by mental
moving trunk for module inkscape
501
   return gradient;
502
}
503
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
504
SPStop *sp_last_stop(SPGradient *gradient)
9012.1.151 by Jon A. Cruz
Cleanup of gradients and stops.
505
{
506
    for (SPStop *stop = gradient->getFirstStop(); stop != NULL; stop = stop->getNextStop()) {
507
        if (stop->getNextStop() == NULL)
3841 by buliabyak
a few more utility methods
508
            return stop;
509
    }
510
    return NULL;
9012.1.127 by Jon A. Cruz
Fixed const correctness for gradient stop count routines.
511
}
512
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
513
SPStop *sp_get_stop_i(SPGradient *gradient, guint stop_i)
9012.1.127 by Jon A. Cruz
Fixed const correctness for gradient stop count routines.
514
{
9012.1.141 by Jon A. Cruz
New tab in Fill&Stroke dialog for swatch fills.
515
    SPStop *stop = gradient->getFirstStop();
5191 by buliabyak
fix crash caused by a gradient without a zero-offset stop
516
9012.1.127 by Jon A. Cruz
Fixed const correctness for gradient stop count routines.
517
    // if this is valid but weird gradient without an offset-zero stop element,
5191 by buliabyak
fix crash caused by a gradient without a zero-offset stop
518
    // inkscape has created a handle for the start of gradient anyway,
519
    // so when it asks for stop N that corresponds to stop element N-1
520
    if (stop->offset != 0)
521
        stop_i --;
9012.1.127 by Jon A. Cruz
Fixed const correctness for gradient stop count routines.
522
9012.1.151 by Jon A. Cruz
Cleanup of gradients and stops.
523
    for (guint i = 0; i < stop_i; i++) {
524
        if (!stop) {
525
            return NULL;
526
        }
527
        stop = stop->getNextStop();
9012.1.127 by Jon A. Cruz
Fixed const correctness for gradient stop count routines.
528
    }
529
3841 by buliabyak
a few more utility methods
530
    return stop;
531
}
532
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
533
guint32 average_color(guint32 c1, guint32 c2, gdouble p)
3841 by buliabyak
a few more utility methods
534
{
9012.1.127 by Jon A. Cruz
Fixed const correctness for gradient stop count routines.
535
    guint32 r = (guint32) (SP_RGBA32_R_U (c1) * (1 - p) + SP_RGBA32_R_U (c2) * p);
536
    guint32 g = (guint32) (SP_RGBA32_G_U (c1) * (1 - p) + SP_RGBA32_G_U (c2) * p);
537
    guint32 b = (guint32) (SP_RGBA32_B_U (c1) * (1 - p) + SP_RGBA32_B_U (c2) * p);
538
    guint32 a = (guint32) (SP_RGBA32_A_U (c1) * (1 - p) + SP_RGBA32_A_U (c2) * p);
3841 by buliabyak
a few more utility methods
539
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
540
    return SP_RGBA32_U_COMPOSE(r, g, b, a);
3841 by buliabyak
a few more utility methods
541
}
542
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
543
SPStop *sp_vector_add_stop(SPGradient *vector, SPStop* prev_stop, SPStop* next_stop, gfloat offset)
3841 by buliabyak
a few more utility methods
544
{
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
545
#ifdef SP_GR_VERBOSE
546
    g_message("sp_vector_add_stop(%p, %p, %p, %f)", vector, prev_stop, next_stop, offset);
547
#endif
548
3841 by buliabyak
a few more utility methods
549
    Inkscape::XML::Node *new_stop_repr = NULL;
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
550
    new_stop_repr = prev_stop->getRepr()->duplicate(vector->getRepr()->document());
551
    vector->getRepr()->addChild(new_stop_repr, prev_stop->getRepr());
3841 by buliabyak
a few more utility methods
552
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
553
    SPStop *newstop = reinterpret_cast<SPStop *>(vector->document->getObjectByRepr(new_stop_repr));
3841 by buliabyak
a few more utility methods
554
    newstop->offset = offset;
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
555
    sp_repr_set_css_double( newstop->getRepr(), "offset", (double)offset);
3841 by buliabyak
a few more utility methods
556
    guint32 const c1 = sp_stop_get_rgba32(prev_stop);
557
    guint32 const c2 = sp_stop_get_rgba32(next_stop);
558
    guint32 cnew = average_color (c1, c2, (offset - prev_stop->offset) / (next_stop->offset - prev_stop->offset));
559
    Inkscape::CSSOStringStream os;
560
    gchar c[64];
561
    sp_svg_write_color (c, sizeof(c), cnew);
562
    gdouble opacity = (gdouble) SP_RGBA32_A_F (cnew);
563
    os << "stop-color:" << c << ";stop-opacity:" << opacity <<";";
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
564
    newstop->getRepr()->setAttribute("style", os.str().c_str());
3841 by buliabyak
a few more utility methods
565
    Inkscape::GC::release(new_stop_repr);
566
567
    return newstop;
568
}
1 by mental
moving trunk for module inkscape
569
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
570
void sp_item_gradient_edit_stop(SPItem *item, guint point_type, guint point_i, bool fill_or_stroke)
1 by mental
moving trunk for module inkscape
571
{
572
    SPGradient *gradient = sp_item_gradient (item, fill_or_stroke);
573
574
    if (!gradient || !SP_IS_GRADIENT(gradient))
575
        return;
576
9012.1.157 by Jon A. Cruz
Initial F&S dialog setting of swatch colors.
577
    SPGradient *vector = gradient->getVector();
2228 by johanengelen
Upgraded gradient tool =)
578
    switch (point_type) {
579
        case POINT_LG_BEGIN:
1 by mental
moving trunk for module inkscape
580
        case POINT_RG_CENTER:
581
        case POINT_RG_FOCUS:
582
        {
9012.1.141 by Jon A. Cruz
New tab in Fill&Stroke dialog for swatch fills.
583
            GtkWidget *dialog = sp_gradient_vector_editor_new (vector, vector->getFirstStop());
1 by mental
moving trunk for module inkscape
584
            gtk_widget_show (dialog);
585
        }
586
        break;
587
2228 by johanengelen
Upgraded gradient tool =)
588
        case POINT_LG_END:
1 by mental
moving trunk for module inkscape
589
        case POINT_RG_R1:
590
        case POINT_RG_R2:
591
        {
592
            GtkWidget *dialog = sp_gradient_vector_editor_new (vector, sp_last_stop (vector));
593
            gtk_widget_show (dialog);
594
        }
595
        break;
9012.1.127 by Jon A. Cruz
Fixed const correctness for gradient stop count routines.
596
2228 by johanengelen
Upgraded gradient tool =)
597
        case POINT_LG_MID:
598
        case POINT_RG_MID1:
599
        case POINT_RG_MID2:
600
        {
601
            GtkWidget *dialog = sp_gradient_vector_editor_new (vector, sp_get_stop_i (vector, point_i));
602
            gtk_widget_show (dialog);
603
        }
604
        break;
1 by mental
moving trunk for module inkscape
605
        default:
606
            break;
607
    }
608
}
609
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
610
guint32 sp_item_gradient_stop_query_style(SPItem *item, guint point_type, guint point_i, bool fill_or_stroke)
1 by mental
moving trunk for module inkscape
611
{
612
    SPGradient *gradient = sp_item_gradient (item, fill_or_stroke);
613
614
    if (!gradient || !SP_IS_GRADIENT(gradient))
615
        return 0;
616
9012.1.157 by Jon A. Cruz
Initial F&S dialog setting of swatch colors.
617
    SPGradient *vector = gradient->getVector();
1 by mental
moving trunk for module inkscape
618
619
    if (!vector) // orphan!
620
        return 0; // what else to do?
621
2228 by johanengelen
Upgraded gradient tool =)
622
    switch (point_type) {
623
        case POINT_LG_BEGIN:
1 by mental
moving trunk for module inkscape
624
        case POINT_RG_CENTER:
625
        case POINT_RG_FOCUS:
626
        {
9012.1.141 by Jon A. Cruz
New tab in Fill&Stroke dialog for swatch fills.
627
            SPStop *first = vector->getFirstStop();
1 by mental
moving trunk for module inkscape
628
            if (first) {
629
                return sp_stop_get_rgba32(first);
630
            }
631
        }
632
        break;
633
2228 by johanengelen
Upgraded gradient tool =)
634
        case POINT_LG_END:
1 by mental
moving trunk for module inkscape
635
        case POINT_RG_R1:
636
        case POINT_RG_R2:
637
        {
638
            SPStop *last = sp_last_stop (vector);
639
            if (last) {
640
                return sp_stop_get_rgba32(last);
641
            }
642
        }
643
        break;
9012.1.127 by Jon A. Cruz
Fixed const correctness for gradient stop count routines.
644
2228 by johanengelen
Upgraded gradient tool =)
645
        case POINT_LG_MID:
646
        case POINT_RG_MID1:
647
        case POINT_RG_MID2:
648
        {
649
            SPStop *stopi = sp_get_stop_i (vector, point_i);
650
            if (stopi) {
651
                return sp_stop_get_rgba32(stopi);
652
            }
653
        }
654
        break;
655
1 by mental
moving trunk for module inkscape
656
        default:
657
            break;
658
    }
659
    return 0;
660
}
661
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
662
void sp_item_gradient_stop_set_style(SPItem *item, guint point_type, guint point_i, bool fill_or_stroke, SPCSSAttr *stop)
1 by mental
moving trunk for module inkscape
663
{
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
664
#ifdef SP_GR_VERBOSE
665
    g_message("sp_item_gradient_stop_set_style(%p, %d, %d, %d, %p)", item, point_type, point_i, fill_or_stroke, stop);
666
#endif
1 by mental
moving trunk for module inkscape
667
    SPGradient *gradient = sp_item_gradient (item, fill_or_stroke);
668
669
    if (!gradient || !SP_IS_GRADIENT(gradient))
670
        return;
671
9012.1.157 by Jon A. Cruz
Initial F&S dialog setting of swatch colors.
672
    SPGradient *vector = gradient->getVector();
1 by mental
moving trunk for module inkscape
673
674
    if (!vector) // orphan!
675
        return;
2320 by johanengelen
Fork gradientvector upon deletion of stops.
676
677
    vector = sp_gradient_fork_vector_if_necessary (vector);
1 by mental
moving trunk for module inkscape
678
    if ( gradient != vector && gradient->ref->getObject() != vector ) {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
679
        sp_gradient_repr_set_link(gradient->getRepr(), vector);
1 by mental
moving trunk for module inkscape
680
    }
681
2228 by johanengelen
Upgraded gradient tool =)
682
    switch (point_type) {
683
        case POINT_LG_BEGIN:
1 by mental
moving trunk for module inkscape
684
        case POINT_RG_CENTER:
685
        case POINT_RG_FOCUS:
686
        {
9012.1.141 by Jon A. Cruz
New tab in Fill&Stroke dialog for swatch fills.
687
            SPStop *first = vector->getFirstStop();
1 by mental
moving trunk for module inkscape
688
            if (first) {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
689
                sp_repr_css_change(first->getRepr(), stop, "style");
1 by mental
moving trunk for module inkscape
690
            }
691
        }
692
        break;
693
2228 by johanengelen
Upgraded gradient tool =)
694
        case POINT_LG_END:
1 by mental
moving trunk for module inkscape
695
        case POINT_RG_R1:
696
        case POINT_RG_R2:
697
        {
698
            SPStop *last = sp_last_stop (vector);
699
            if (last) {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
700
                sp_repr_css_change(last->getRepr(), stop, "style");
1 by mental
moving trunk for module inkscape
701
            }
702
        }
703
        break;
9012.1.127 by Jon A. Cruz
Fixed const correctness for gradient stop count routines.
704
2228 by johanengelen
Upgraded gradient tool =)
705
        case POINT_LG_MID:
706
        case POINT_RG_MID1:
707
        case POINT_RG_MID2:
708
        {
709
            SPStop *stopi = sp_get_stop_i (vector, point_i);
710
            if (stopi) {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
711
                sp_repr_css_change(stopi->getRepr(), stop, "style");
2228 by johanengelen
Upgraded gradient tool =)
712
            }
713
        }
714
        break;
9012.1.127 by Jon A. Cruz
Fixed const correctness for gradient stop count routines.
715
1 by mental
moving trunk for module inkscape
716
        default:
717
            break;
718
    }
719
}
720
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
721
void sp_item_gradient_reverse_vector(SPItem *item, bool fill_or_stroke)
1 by mental
moving trunk for module inkscape
722
{
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
723
#ifdef SP_GR_VERBOSE
724
    g_message("sp_item_gradient_reverse_vector(%p, %d)", item, fill_or_stroke);
725
#endif
1 by mental
moving trunk for module inkscape
726
    SPGradient *gradient = sp_item_gradient (item, fill_or_stroke);
727
    if (!gradient || !SP_IS_GRADIENT(gradient))
728
        return;
729
9012.1.157 by Jon A. Cruz
Initial F&S dialog setting of swatch colors.
730
    SPGradient *vector = gradient->getVector();
1 by mental
moving trunk for module inkscape
731
    if (!vector) // orphan!
732
        return;
733
734
    vector = sp_gradient_fork_vector_if_necessary (vector);
735
    if ( gradient != vector && gradient->ref->getObject() != vector ) {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
736
        sp_gradient_repr_set_link(gradient->getRepr(), vector);
1 by mental
moving trunk for module inkscape
737
    }
738
739
    GSList *child_reprs = NULL;
740
    GSList *child_objects = NULL;
741
    std::vector<double> offsets;
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
742
    for ( SPObject *child = vector->firstChild(); child; child = child->getNext()) {
743
        child_reprs = g_slist_prepend (child_reprs, child->getRepr());
1 by mental
moving trunk for module inkscape
744
        child_objects = g_slist_prepend (child_objects, child);
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
745
        offsets.push_back(sp_repr_get_double_attribute(child->getRepr(), "offset", 0));
1 by mental
moving trunk for module inkscape
746
    }
747
748
    GSList *child_copies = NULL;
749
    for (GSList *i = child_reprs; i != NULL; i = i->next) {
750
        Inkscape::XML::Node *repr = (Inkscape::XML::Node *) i->data;
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
751
        Inkscape::XML::Document *xml_doc = vector->getRepr()->document();
2723 by mental
plumb XML::Document parameter into duplication, courtesy of bryce
752
        child_copies = g_slist_append (child_copies, repr->duplicate(xml_doc));
1 by mental
moving trunk for module inkscape
753
    }
754
755
756
    for (GSList *i = child_objects; i != NULL; i = i->next) {
757
        SPObject *child = SP_OBJECT (i->data);
758
        child->deleteObject();
759
    }
760
761
    std::vector<double>::iterator iter = offsets.end() - 1;
762
    for (GSList *i = child_copies; i != NULL; i = i->next) {
763
        Inkscape::XML::Node *copy = (Inkscape::XML::Node *) i->data;
764
        vector->appendChildRepr(copy);
765
        sp_repr_set_svg_double (copy, "offset", 1 - *iter);
766
        iter --;
767
        Inkscape::GC::release(copy);
768
    }
769
770
    g_slist_free (child_reprs);
771
    g_slist_free (child_copies);
772
    g_slist_free (child_objects);
773
}
774
775
776
/**
2228 by johanengelen
Upgraded gradient tool =)
777
Set the position of point point_type of the gradient applied to item (either fill_or_stroke) to
1 by mental
moving trunk for module inkscape
778
p_w (in desktop coordinates). Write_repr if you want the change to become permanent.
779
*/
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
780
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)
1 by mental
moving trunk for module inkscape
781
{
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
782
#ifdef SP_GR_VERBOSE
783
    g_message("sp_item_gradient_set_coords(%p, %d, %d, ...)", item, point_type, point_i );
784
#endif
1 by mental
moving trunk for module inkscape
785
    SPGradient *gradient = sp_item_gradient (item, fill_or_stroke);
786
787
    if (!gradient || !SP_IS_GRADIENT(gradient))
788
        return;
789
790
    gradient = sp_gradient_convert_to_userspace (gradient, item, fill_or_stroke? "fill" : "stroke");
791
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
792
    Geom::Affine i2d (item->i2dt_affine ());
6887 by Ted Gould
Merge from trunk
793
    Geom::Point p = p_w * i2d.inverse();
1 by mental
moving trunk for module inkscape
794
    p *= (gradient->gradientTransform).inverse();
795
    // now p is in gradient's original coordinates
796
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
797
    Inkscape::XML::Node *repr = gradient->getRepr();
1 by mental
moving trunk for module inkscape
798
799
    if (SP_IS_LINEARGRADIENT(gradient)) {
800
        SPLinearGradient *lg = SP_LINEARGRADIENT(gradient);
2228 by johanengelen
Upgraded gradient tool =)
801
        switch (point_type) {
802
            case POINT_LG_BEGIN:
1 by mental
moving trunk for module inkscape
803
                if (scale) {
6887 by Ted Gould
Merge from trunk
804
                    lg->x2.computed += (lg->x1.computed - p[Geom::X]);
805
                    lg->y2.computed += (lg->y1.computed - p[Geom::Y]);
149 by rwst
bulk trailing spaces removal. consistency through MD5 of binary
806
                }
6887 by Ted Gould
Merge from trunk
807
                lg->x1.computed = p[Geom::X];
808
                lg->y1.computed = p[Geom::Y];
1 by mental
moving trunk for module inkscape
809
                if (write_repr) {
810
                    if (scale) {
811
                        sp_repr_set_svg_double(repr, "x2", lg->x2.computed);
812
                        sp_repr_set_svg_double(repr, "y2", lg->y2.computed);
813
                    }
814
                    sp_repr_set_svg_double(repr, "x1", lg->x1.computed);
815
                    sp_repr_set_svg_double(repr, "y1", lg->y1.computed);
816
                } else {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
817
                    gradient->requestModified(SP_OBJECT_MODIFIED_FLAG);
1 by mental
moving trunk for module inkscape
818
                }
819
                break;
2228 by johanengelen
Upgraded gradient tool =)
820
            case POINT_LG_END:
1 by mental
moving trunk for module inkscape
821
                if (scale) {
6887 by Ted Gould
Merge from trunk
822
                    lg->x1.computed += (lg->x2.computed - p[Geom::X]);
823
                    lg->y1.computed += (lg->y2.computed - p[Geom::Y]);
149 by rwst
bulk trailing spaces removal. consistency through MD5 of binary
824
                }
6887 by Ted Gould
Merge from trunk
825
                lg->x2.computed = p[Geom::X];
826
                lg->y2.computed = p[Geom::Y];
1 by mental
moving trunk for module inkscape
827
                if (write_repr) {
828
                    if (scale) {
829
                        sp_repr_set_svg_double(repr, "x1", lg->x1.computed);
830
                        sp_repr_set_svg_double(repr, "y1", lg->y1.computed);
831
                    }
832
                    sp_repr_set_svg_double(repr, "x2", lg->x2.computed);
833
                    sp_repr_set_svg_double(repr, "y2", lg->y2.computed);
834
                } else {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
835
                    gradient->requestModified(SP_OBJECT_MODIFIED_FLAG);
1 by mental
moving trunk for module inkscape
836
                }
9012.1.127 by Jon A. Cruz
Fixed const correctness for gradient stop count routines.
837
                break;
2228 by johanengelen
Upgraded gradient tool =)
838
            case POINT_LG_MID:
9012.1.127 by Jon A. Cruz
Fixed const correctness for gradient stop count routines.
839
            {
2228 by johanengelen
Upgraded gradient tool =)
840
                // using X-coordinates only to determine the offset, assuming p has been snapped to the vector from begin to end.
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
841
                Geom::Point begin(lg->x1.computed, lg->y1.computed);
842
                Geom::Point end(lg->x2.computed, lg->y2.computed);
843
                double offset = Geom::LineSegment(begin, end).nearestPoint(p);
2758 by johanengelen
Gradient tool: fixed live updating of midstop dragging + [ 1667584 ] Crash when moving gradient nodes on group
844
                SPGradient *vector = sp_gradient_get_forked_vector_if_necessary (lg, false);
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
845
                lg->ensureVector();
2573 by johanengelen
Fixed interactive updating.
846
                lg->vector.stops.at(point_i).offset = offset;
2228 by johanengelen
Upgraded gradient tool =)
847
                SPStop* stopi = sp_get_stop_i(vector, point_i);
848
                stopi->offset = offset;
849
                if (write_repr) {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
850
                    sp_repr_set_css_double(stopi->getRepr(), "offset", stopi->offset);
2228 by johanengelen
Upgraded gradient tool =)
851
                } else {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
852
                    stopi->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
2228 by johanengelen
Upgraded gradient tool =)
853
                }
854
            }
855
            break;
9012.1.127 by Jon A. Cruz
Fixed const correctness for gradient stop count routines.
856
            default:
857
                break;
858
        }
859
    } else if (SP_IS_RADIALGRADIENT(gradient)) {
2758 by johanengelen
Gradient tool: fixed live updating of midstop dragging + [ 1667584 ] Crash when moving gradient nodes on group
860
        SPRadialGradient *rg = SP_RADIALGRADIENT(gradient);
6887 by Ted Gould
Merge from trunk
861
        Geom::Point c (rg->cx.computed, rg->cy.computed);
862
        Geom::Point c_w = c * gradient->gradientTransform * i2d; // now in desktop coords
863
        if ((point_type == POINT_RG_R1 || point_type == POINT_RG_R2) && Geom::L2 (p_w - c_w) < 1e-3) {
2758 by johanengelen
Gradient tool: fixed live updating of midstop dragging + [ 1667584 ] Crash when moving gradient nodes on group
864
            // prevent setting a radius too close to the center
865
            return;
866
        }
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
867
        Geom::Affine new_transform;
2758 by johanengelen
Gradient tool: fixed live updating of midstop dragging + [ 1667584 ] Crash when moving gradient nodes on group
868
        bool transform_set = false;
1 by mental
moving trunk for module inkscape
869
9012.1.127 by Jon A. Cruz
Fixed const correctness for gradient stop count routines.
870
        switch (point_type) {
871
            case POINT_RG_CENTER:
872
                rg->fx.computed = p[Geom::X] + (rg->fx.computed - rg->cx.computed);
873
                rg->fy.computed = p[Geom::Y] + (rg->fy.computed - rg->cy.computed);
874
                rg->cx.computed = p[Geom::X];
875
                rg->cy.computed = p[Geom::Y];
876
                if (write_repr) {
877
                    sp_repr_set_svg_double(repr, "fx", rg->fx.computed);
878
                    sp_repr_set_svg_double(repr, "fy", rg->fy.computed);
879
                    sp_repr_set_svg_double(repr, "cx", rg->cx.computed);
880
                    sp_repr_set_svg_double(repr, "cy", rg->cy.computed);
881
                } else {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
882
                    gradient->requestModified(SP_OBJECT_MODIFIED_FLAG);
9012.1.127 by Jon A. Cruz
Fixed const correctness for gradient stop count routines.
883
                }
884
                break;
885
            case POINT_RG_FOCUS:
886
                rg->fx.computed = p[Geom::X];
887
                rg->fy.computed = p[Geom::Y];
888
                if (write_repr) {
889
                    sp_repr_set_svg_double(repr, "fx", rg->fx.computed);
890
                    sp_repr_set_svg_double(repr, "fy", rg->fy.computed);
891
                } else {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
892
                    gradient->requestModified(SP_OBJECT_MODIFIED_FLAG);
9012.1.127 by Jon A. Cruz
Fixed const correctness for gradient stop count routines.
893
                }
894
                break;
895
            case POINT_RG_R1:
896
            {
6887 by Ted Gould
Merge from trunk
897
                Geom::Point r1_w = (c + Geom::Point(rg->r.computed, 0)) * gradient->gradientTransform * i2d;
9012.1.127 by Jon A. Cruz
Fixed const correctness for gradient stop count routines.
898
                double r1_angle = Geom::atan2(r1_w - c_w);
899
                double move_angle = Geom::atan2(p_w - c_w) - r1_angle;
900
                double move_stretch = Geom::L2(p_w - c_w) / Geom::L2(r1_w - c_w);
901
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
902
                Geom::Affine move = Geom::Affine (Geom::Translate (-c_w)) *
903
                    Geom::Affine (Geom::Rotate(-r1_angle)) *
904
                    Geom::Affine (Geom::Scale(move_stretch, scale? move_stretch : 1)) *
905
                    Geom::Affine (Geom::Rotate(r1_angle)) *
906
                    Geom::Affine (Geom::Rotate(move_angle)) *
907
                    Geom::Affine (Geom::Translate (c_w));
9012.1.127 by Jon A. Cruz
Fixed const correctness for gradient stop count routines.
908
909
                new_transform = gradient->gradientTransform * i2d * move * i2d.inverse();
910
                transform_set = true;
911
912
                break;
913
            }
914
            case POINT_RG_R2:
915
            {
916
                Geom::Point r2_w = (c + Geom::Point(0, -rg->r.computed)) * gradient->gradientTransform * i2d;
917
                double r2_angle = Geom::atan2(r2_w - c_w);
918
                double move_angle = Geom::atan2(p_w - c_w) - r2_angle;
919
                double move_stretch = Geom::L2(p_w - c_w) / Geom::L2(r2_w - c_w);
920
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
921
                Geom::Affine move = Geom::Affine (Geom::Translate (-c_w)) *
922
                    Geom::Affine (Geom::Rotate(-r2_angle)) *
923
                    Geom::Affine (Geom::Scale(move_stretch, scale? move_stretch : 1)) *
924
                    Geom::Affine (Geom::Rotate(r2_angle)) *
925
                    Geom::Affine (Geom::Rotate(move_angle)) *
926
                    Geom::Affine (Geom::Translate (c_w));
9012.1.127 by Jon A. Cruz
Fixed const correctness for gradient stop count routines.
927
928
                new_transform = gradient->gradientTransform * i2d * move * i2d.inverse();
929
                transform_set = true;
1 by mental
moving trunk for module inkscape
930
2573 by johanengelen
Fixed interactive updating.
931
                break;
932
            }
2228 by johanengelen
Upgraded gradient tool =)
933
        case POINT_RG_MID1:
2573 by johanengelen
Fixed interactive updating.
934
            {
6887 by Ted Gould
Merge from trunk
935
                Geom::Point start = Geom::Point (rg->cx.computed, rg->cy.computed);
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
936
                Geom::Point end   = Geom::Point (rg->cx.computed + rg->r.computed, rg->cy.computed);
937
                double offset = Geom::LineSegment(start, end).nearestPoint(p);
2758 by johanengelen
Gradient tool: fixed live updating of midstop dragging + [ 1667584 ] Crash when moving gradient nodes on group
938
                SPGradient *vector = sp_gradient_get_forked_vector_if_necessary (rg, false);
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
939
                rg->ensureVector();
9012.1.127 by Jon A. Cruz
Fixed const correctness for gradient stop count routines.
940
                rg->vector.stops.at(point_i).offset = offset;
2228 by johanengelen
Upgraded gradient tool =)
941
                SPStop* stopi = sp_get_stop_i(vector, point_i);
942
                stopi->offset = offset;
943
                if (write_repr) {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
944
                    sp_repr_set_css_double(stopi->getRepr(), "offset", stopi->offset);
2228 by johanengelen
Upgraded gradient tool =)
945
                } else {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
946
                    stopi->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
2228 by johanengelen
Upgraded gradient tool =)
947
                }
2573 by johanengelen
Fixed interactive updating.
948
                break;
949
            }
2228 by johanengelen
Upgraded gradient tool =)
950
        case POINT_RG_MID2:
6887 by Ted Gould
Merge from trunk
951
                Geom::Point start = Geom::Point (rg->cx.computed, rg->cy.computed);
952
                Geom::Point end   = Geom::Point (rg->cx.computed, rg->cy.computed - rg->r.computed);
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
953
                double offset = Geom::LineSegment(start, end).nearestPoint(p);
2758 by johanengelen
Gradient tool: fixed live updating of midstop dragging + [ 1667584 ] Crash when moving gradient nodes on group
954
                SPGradient *vector = sp_gradient_get_forked_vector_if_necessary(rg, false);
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
955
                rg->ensureVector();
2573 by johanengelen
Fixed interactive updating.
956
                rg->vector.stops.at(point_i).offset = offset;
2228 by johanengelen
Upgraded gradient tool =)
957
                SPStop* stopi = sp_get_stop_i(vector, point_i);
958
                stopi->offset = offset;
959
                if (write_repr) {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
960
                    sp_repr_set_css_double(stopi->getRepr(), "offset", stopi->offset);
2228 by johanengelen
Upgraded gradient tool =)
961
                } else {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
962
                    stopi->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
2228 by johanengelen
Upgraded gradient tool =)
963
                }
2573 by johanengelen
Fixed interactive updating.
964
                break;
9012.1.127 by Jon A. Cruz
Fixed const correctness for gradient stop count routines.
965
        }
966
967
        if (transform_set) {
968
            gradient->gradientTransform = new_transform;
969
            gradient->gradientTransform_set = TRUE;
970
            if (write_repr) {
971
                gchar *s=sp_svg_transform_write(gradient->gradientTransform);
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
972
                gradient->getRepr()->setAttribute("gradientTransform", s);
9012.1.127 by Jon A. Cruz
Fixed const correctness for gradient stop count routines.
973
                g_free(s);
974
            } else {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
975
                gradient->requestModified(SP_OBJECT_MODIFIED_FLAG);
2228 by johanengelen
Upgraded gradient tool =)
976
            }
9012.1.127 by Jon A. Cruz
Fixed const correctness for gradient stop count routines.
977
        }
978
    }
1 by mental
moving trunk for module inkscape
979
}
980
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
981
SPGradient *sp_item_gradient_get_vector(SPItem *item, bool fill_or_stroke)
1 by mental
moving trunk for module inkscape
982
{
983
    SPGradient *gradient = sp_item_gradient (item, fill_or_stroke);
984
9012.1.157 by Jon A. Cruz
Initial F&S dialog setting of swatch colors.
985
    if (gradient) {
986
        return gradient->getVector();
987
    }
1 by mental
moving trunk for module inkscape
988
    return NULL;
989
}
990
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
991
SPGradientSpread sp_item_gradient_get_spread(SPItem *item, bool fill_or_stroke)
1 by mental
moving trunk for module inkscape
992
{
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
993
    SPGradientSpread spread = SP_GRADIENT_SPREAD_PAD;
1 by mental
moving trunk for module inkscape
994
    SPGradient *gradient = sp_item_gradient (item, fill_or_stroke);
995
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
996
    if (gradient) {
997
        spread = gradient->fetchSpread();
998
    }
999
    return spread;
1 by mental
moving trunk for module inkscape
1000
}
1001
1002
1003
/**
2228 by johanengelen
Upgraded gradient tool =)
1004
Returns the position of point point_type of the gradient applied to item (either fill_or_stroke),
1 by mental
moving trunk for module inkscape
1005
in desktop coordinates.
1006
*/
1007
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1008
Geom::Point sp_item_gradient_get_coords(SPItem *item, guint point_type, guint point_i, bool fill_or_stroke)
1 by mental
moving trunk for module inkscape
1009
{
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1010
#ifdef SP_GR_VERBOSE
1011
    g_message("sp_item_gradient_get_coords(%p, %d, %d, %d)", item, point_type, point_i, fill_or_stroke);
1012
#endif
1 by mental
moving trunk for module inkscape
1013
    SPGradient *gradient = sp_item_gradient (item, fill_or_stroke);
1014
6884 by Ted Gould
Merging from trunk
1015
    Geom::Point p (0, 0);
1 by mental
moving trunk for module inkscape
1016
1017
    if (!gradient)
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1018
        return p;
1 by mental
moving trunk for module inkscape
1019
1020
    if (SP_IS_LINEARGRADIENT(gradient)) {
1021
        SPLinearGradient *lg = SP_LINEARGRADIENT(gradient);
2228 by johanengelen
Upgraded gradient tool =)
1022
        switch (point_type) {
1023
            case POINT_LG_BEGIN:
6887 by Ted Gould
Merge from trunk
1024
                p = Geom::Point (lg->x1.computed, lg->y1.computed);
1 by mental
moving trunk for module inkscape
1025
                break;
2228 by johanengelen
Upgraded gradient tool =)
1026
            case POINT_LG_END:
6887 by Ted Gould
Merge from trunk
1027
                p = Geom::Point (lg->x2.computed, lg->y2.computed);
1 by mental
moving trunk for module inkscape
1028
                break;
2228 by johanengelen
Upgraded gradient tool =)
1029
            case POINT_LG_MID:
9012.1.127 by Jon A. Cruz
Fixed const correctness for gradient stop count routines.
1030
                {
2228 by johanengelen
Upgraded gradient tool =)
1031
                    gdouble offset = lg->vector.stops.at(point_i).offset;
6884 by Ted Gould
Merging from trunk
1032
                    p = (1-offset) * Geom::Point(lg->x1.computed, lg->y1.computed) + offset * Geom::Point(lg->x2.computed, lg->y2.computed);
2228 by johanengelen
Upgraded gradient tool =)
1033
                }
1034
                break;
1 by mental
moving trunk for module inkscape
1035
        }
1036
    } else     if (SP_IS_RADIALGRADIENT(gradient)) {
1037
        SPRadialGradient *rg = SP_RADIALGRADIENT(gradient);
2228 by johanengelen
Upgraded gradient tool =)
1038
        switch (point_type) {
1 by mental
moving trunk for module inkscape
1039
            case POINT_RG_CENTER:
6884 by Ted Gould
Merging from trunk
1040
                p = Geom::Point (rg->cx.computed, rg->cy.computed);
1 by mental
moving trunk for module inkscape
1041
                break;
1042
            case POINT_RG_FOCUS:
6884 by Ted Gould
Merging from trunk
1043
                p = Geom::Point (rg->fx.computed, rg->fy.computed);
1 by mental
moving trunk for module inkscape
1044
                break;
1045
            case POINT_RG_R1:
6884 by Ted Gould
Merging from trunk
1046
                p = Geom::Point (rg->cx.computed + rg->r.computed, rg->cy.computed);
1 by mental
moving trunk for module inkscape
1047
                break;
1048
            case POINT_RG_R2:
6884 by Ted Gould
Merging from trunk
1049
                p = Geom::Point (rg->cx.computed, rg->cy.computed - rg->r.computed);
1 by mental
moving trunk for module inkscape
1050
                break;
2228 by johanengelen
Upgraded gradient tool =)
1051
            case POINT_RG_MID1:
1052
                {
1053
                    gdouble offset = rg->vector.stops.at(point_i).offset;
6884 by Ted Gould
Merging from trunk
1054
                    p = (1-offset) * Geom::Point (rg->cx.computed, rg->cy.computed) + offset * Geom::Point(rg->cx.computed + rg->r.computed, rg->cy.computed);
9012.1.127 by Jon A. Cruz
Fixed const correctness for gradient stop count routines.
1055
                }
2228 by johanengelen
Upgraded gradient tool =)
1056
                break;
1057
            case POINT_RG_MID2:
1058
                {
1059
                    gdouble offset = rg->vector.stops.at(point_i).offset;
6884 by Ted Gould
Merging from trunk
1060
                    p = (1-offset) * Geom::Point (rg->cx.computed, rg->cy.computed) + offset * Geom::Point(rg->cx.computed, rg->cy.computed - rg->r.computed);
9012.1.127 by Jon A. Cruz
Fixed const correctness for gradient stop count routines.
1061
                }
2228 by johanengelen
Upgraded gradient tool =)
1062
                break;
1 by mental
moving trunk for module inkscape
1063
        }
1064
    }
1065
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1066
    if (SP_GRADIENT(gradient)->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) {
1067
        item->document->ensureUpToDate();
1068
        Geom::OptRect bbox = item->visualBounds(); // we need "true" bbox without item_i2d_affine
2543 by mental
more NR::Maybe<NR::Rect> work
1069
        if (bbox) {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1070
            p *= Geom::Affine(bbox->dimensions()[Geom::X], 0,
6884 by Ted Gould
Merging from trunk
1071
                            0, bbox->dimensions()[Geom::Y],
1072
                            bbox->min()[Geom::X], bbox->min()[Geom::Y]);
2543 by mental
more NR::Maybe<NR::Rect> work
1073
        }
1 by mental
moving trunk for module inkscape
1074
    }
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1075
    p *= Geom::Affine(gradient->gradientTransform) * (Geom::Affine)item->i2dt_affine();
1076
    return p;
1 by mental
moving trunk for module inkscape
1077
}
1078
1079
1080
/**
1081
 * Sets item fill or stroke to the gradient of the specified type with given vector, creating
1082
 * new private gradient, if needed.
1083
 * gr has to be a normalized vector.
1084
 */
1085
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1086
SPGradient *sp_item_set_gradient(SPItem *item, SPGradient *gr, SPGradientType type, bool is_fill)
1 by mental
moving trunk for module inkscape
1087
{
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1088
#ifdef SP_GR_VERBOSE
1089
    g_message("sp_item_set_gradient(%p, %p, %d, %d)", item, gr, type, is_fill);
1090
#endif
1 by mental
moving trunk for module inkscape
1091
    g_return_val_if_fail(item != NULL, NULL);
1092
    g_return_val_if_fail(SP_IS_ITEM(item), NULL);
1093
    g_return_val_if_fail(gr != NULL, NULL);
1094
    g_return_val_if_fail(SP_IS_GRADIENT(gr), NULL);
1095
    g_return_val_if_fail(gr->state == SP_GRADIENT_STATE_VECTOR, NULL);
1096
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1097
    SPStyle *style = item->style;
1 by mental
moving trunk for module inkscape
1098
    g_assert(style != NULL);
1099
1100
    SPPaintServer *ps = NULL;
3706 by joncruz
Purged fill type enum
1101
    if (is_fill? style->fill.isPaintserver() : style->stroke.isPaintserver())
1 by mental
moving trunk for module inkscape
1102
        ps = is_fill? SP_STYLE_FILL_SERVER(style) : SP_STYLE_STROKE_SERVER(style);
1103
1104
    if (ps
1105
        && ( (type == SP_GRADIENT_TYPE_LINEAR && SP_IS_LINEARGRADIENT(ps)) ||
1106
             (type == SP_GRADIENT_TYPE_RADIAL && SP_IS_RADIALGRADIENT(ps))   ) )
1107
    {
1108
1109
        /* Current fill style is the gradient of the required type */
1110
        SPGradient *current = SP_GRADIENT(ps);
1111
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1112
        //g_message("hrefcount %d   count %d\n", current->hrefcount, count_gradient_hrefs(item, current));
1 by mental
moving trunk for module inkscape
1113
9012.1.212 by Jon A. Cruz
Update to reflect "swatch" gradients as being assumed to be shared.
1114
        if (!current->isSwatch()
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1115
            && (current->hrefcount == 1 ||
1116
            current->hrefcount == count_gradient_hrefs(item, current))) {
1 by mental
moving trunk for module inkscape
1117
1118
            // current is private and it's either used once, or all its uses are by children of item;
1119
            // so just change its href to vector
1120
9012.1.157 by Jon A. Cruz
Initial F&S dialog setting of swatch colors.
1121
            if ( current != gr && current->getVector() != gr ) {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1122
                // href is not the vector
1123
                sp_gradient_repr_set_link(current->getRepr(), gr);
1 by mental
moving trunk for module inkscape
1124
            }
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1125
            item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
1 by mental
moving trunk for module inkscape
1126
            return current;
1127
1128
        } else {
1129
1130
            // the gradient is not private, or it is shared with someone else;
1131
            // normalize it (this includes creating new private if necessary)
1132
            SPGradient *normalized = sp_gradient_fork_private_if_necessary(current, gr, type, item);
1133
1134
            g_return_val_if_fail(normalized != NULL, NULL);
1135
1136
            if (normalized != current) {
1137
1138
                /* We have to change object style here; recursive because this is used from
1139
                 * fill&stroke and must work for groups etc. */
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1140
                sp_style_set_property_url(item, is_fill? "fill" : "stroke", normalized, true);
1 by mental
moving trunk for module inkscape
1141
            }
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1142
            item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
1 by mental
moving trunk for module inkscape
1143
            return normalized;
1144
        }
1145
1146
    } else {
1147
        /* Current fill style is not a gradient or wrong type, so construct everything */
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1148
        SPGradient *constructed = sp_gradient_get_private_normalized(item->document, gr, type);
1 by mental
moving trunk for module inkscape
1149
        constructed = sp_gradient_reset_to_userspace(constructed, item);
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1150
        sp_style_set_property_url(item, ( is_fill ? "fill" : "stroke" ), constructed, true);
1151
        item->requestDisplayUpdate(( SP_OBJECT_MODIFIED_FLAG |
1152
                                     SP_OBJECT_STYLE_MODIFIED_FLAG ));
1 by mental
moving trunk for module inkscape
1153
        return constructed;
1154
    }
1155
}
1156
9012.1.157 by Jon A. Cruz
Initial F&S dialog setting of swatch colors.
1157
static void sp_gradient_repr_set_link(Inkscape::XML::Node *repr, SPGradient *link)
1 by mental
moving trunk for module inkscape
1158
{
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1159
#ifdef SP_GR_VERBOSE
1160
    g_message("sp_gradient_repr_set_link(%p, %p)", repr, link);
1161
#endif
1 by mental
moving trunk for module inkscape
1162
    g_return_if_fail(repr != NULL);
9012.1.157 by Jon A. Cruz
Initial F&S dialog setting of swatch colors.
1163
    if (link) {
1164
        g_return_if_fail(SP_IS_GRADIENT(link));
1165
    }
1 by mental
moving trunk for module inkscape
1166
1167
    if (link) {
9012.1.157 by Jon A. Cruz
Initial F&S dialog setting of swatch colors.
1168
        Glib::ustring ref("#");
1169
        ref += link->getId();
1170
        repr->setAttribute("xlink:href", ref.c_str());
1 by mental
moving trunk for module inkscape
1171
    } else {
9012.1.157 by Jon A. Cruz
Initial F&S dialog setting of swatch colors.
1172
        repr->setAttribute("xlink:href", 0);
1 by mental
moving trunk for module inkscape
1173
    }
1174
}
1175
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1176
1177
static void addStop( Inkscape::XML::Node *parent, Glib::ustring const &color, gint opacity, gchar const *offset )
1178
{
1179
#ifdef SP_GR_VERBOSE
1180
    g_message("addStop(%p, %s, %d, %s)", parent, color.c_str(), opacity, offset);
1181
#endif
1182
    Inkscape::XML::Node *stop = parent->document()->createElement("svg:stop");
1183
    {
1184
        gchar *tmp = g_strdup_printf( "stop-color:%s;stop-opacity:%d;", color.c_str(), opacity );
1185
        stop->setAttribute( "style", tmp );
1186
        g_free(tmp);
1187
    }
1188
1189
    stop->setAttribute( "offset", offset );
1190
1191
    parent->appendChild(stop);
1192
    Inkscape::GC::release(stop);
1193
}
1194
1 by mental
moving trunk for module inkscape
1195
/*
1196
 * Get default normalized gradient vector of document, create if there is none
1197
 */
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1198
SPGradient *sp_document_default_gradient_vector( SPDocument *document, SPColor const &color, bool singleStop )
1 by mental
moving trunk for module inkscape
1199
{
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1200
    SPDefs *defs = document->getDefs();
1201
    Inkscape::XML::Document *xml_doc = document->rdoc;
1 by mental
moving trunk for module inkscape
1202
2253 by mental
start switching sp_repr_new* over to XML::Document::create*, and rename create methods to match DOM
1203
    Inkscape::XML::Node *repr = xml_doc->createElement("svg:linearGradient");
1 by mental
moving trunk for module inkscape
1204
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1205
    if ( !singleStop ) {
1206
        repr->setAttribute("inkscape:collect", "always");
1207
        // set here, but removed when it's edited in the gradient editor
1208
        // to further reduce clutter, we could
1209
        // (1) here, search gradients by color and return what is found without duplication
1210
        // (2) in fill & stroke, show only one copy of each gradient in list
1211
    }
1212
1213
    Glib::ustring colorStr = color.toString();
1214
    addStop( repr, colorStr, 1, "0" );
1215
    if ( !singleStop ) {
1216
        addStop( repr, colorStr, 0, "1" );
1217
    }
1218
1219
    defs->getRepr()->addChild(repr, NULL);
1 by mental
moving trunk for module inkscape
1220
    Inkscape::GC::release(repr);
1221
1222
    /* fixme: This does not look like nice */
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1223
    SPGradient *gr = static_cast<SPGradient *>(document->getObjectByRepr(repr));
1 by mental
moving trunk for module inkscape
1224
    g_assert(gr != NULL);
1225
    g_assert(SP_IS_GRADIENT(gr));
1226
    /* fixme: Maybe add extra sanity check here */
1227
    gr->state = SP_GRADIENT_STATE_VECTOR;
1228
1229
    return gr;
1230
}
1231
1232
/**
1233
Return the preferred vector for \a o, made from (in order of preference) its current vector,
1234
current fill or stroke color, or from desktop style if \a o is NULL or doesn't have style.
1235
*/
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1236
SPGradient *sp_gradient_vector_for_object( SPDocument *const doc, SPDesktop *const desktop,
1237
                                           SPObject *const o, bool const is_fill, bool singleStop )
1 by mental
moving trunk for module inkscape
1238
{
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1239
    SPColor color;
1240
    if ( (o == NULL) || (o->style == NULL) ) {
1241
        color = sp_desktop_get_color(desktop, is_fill);
1 by mental
moving trunk for module inkscape
1242
    } else {
1243
        // take the color of the object
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1244
        SPStyle const &style = *(o->style);
1 by mental
moving trunk for module inkscape
1245
        SPIPaint const &paint = ( is_fill
1246
                                  ? style.fill
1247
                                  : style.stroke );
3706 by joncruz
Purged fill type enum
1248
        if (paint.isPaintserver()) {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1249
            SPObject *server = is_fill? o->style->getFillPaintServer() : o->style->getStrokePaintServer();
1250
            if ( SP_IS_GRADIENT(server) ) {
9012.1.157 by Jon A. Cruz
Initial F&S dialog setting of swatch colors.
1251
                return SP_GRADIENT(server)->getVector(true);
1 by mental
moving trunk for module inkscape
1252
            } else {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1253
                color = sp_desktop_get_color(desktop, is_fill);
1 by mental
moving trunk for module inkscape
1254
            }
3706 by joncruz
Purged fill type enum
1255
        } else if (paint.isColor()) {
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1256
            color = paint.value.color;
1 by mental
moving trunk for module inkscape
1257
        } else {
1258
            // if o doesn't use flat color, then take current color of the desktop.
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1259
            color = sp_desktop_get_color(desktop, is_fill);
1 by mental
moving trunk for module inkscape
1260
        }
1261
    }
1262
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1263
    return sp_document_default_gradient_vector( doc, color, singleStop );
1 by mental
moving trunk for module inkscape
1264
}
1265
2320 by johanengelen
Fork gradientvector upon deletion of stops.
1266
1 by mental
moving trunk for module inkscape
1267
/*
1268
  Local Variables:
1269
  mode:c++
1270
  c-file-style:"stroustrup"
1271
  c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1272
  indent-tabs-mode:nil
1273
  fill-column:99
1274
  End:
1275
*/
9020 by JazzyNico
Code refactoring and merging with trunk (revision 10599).
1276
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :