~centralelyon2010/inkscape/imagelinks2

« back to all changes in this revision

Viewing changes to src/sp-gradient.cpp

  • Committer: JazzyNico
  • Date: 2011-08-29 20:25:30 UTC
  • Revision ID: nicoduf@yahoo.fr-20110829202530-6deuoz11q90usldv
Code refactoring and merging with trunk (revision 10599).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#define __SP_GRADIENT_C__
2
 
 
3
1
/** \file
4
2
 * SPGradient, SPStop, SPLinearGradient, SPRadialGradient.
5
3
 */
8
6
 *   Lauris Kaplinski <lauris@kaplinski.com>
9
7
 *   bulia byak <buliabyak@users.sf.net>
10
8
 *   Jasper van de Gronde <th.v.d.gronde@hccnet.nl>
 
9
 *   Jon A. Cruz <jon@joncruz.org>
 
10
 *   Abhishek Sharma
11
11
 *
12
12
 * Copyright (C) 1999-2002 Lauris Kaplinski
13
13
 * Copyright (C) 2000-2001 Ximian, Inc.
23
23
#include <cstring>
24
24
#include <string>
25
25
 
26
 
#include <libnr/nr-matrix-fns.h>
27
 
#include <libnr/nr-matrix-ops.h>
28
 
#include <libnr/nr-matrix-scale-ops.h>
29
26
#include <2geom/transforms.h>
30
27
 
31
28
#include <sigc++/functors/ptr_fun.h>
32
29
#include <sigc++/adaptors/bind.h>
33
30
 
34
 
#include "libnr/nr-gradient.h"
35
 
#include "libnr/nr-pixops.h"
 
31
#include "display/cairo-utils.h"
36
32
#include "svg/svg.h"
37
33
#include "svg/svg-color.h"
38
34
#include "svg/css-ostringstream.h"
39
35
#include "attributes.h"
40
36
#include "document-private.h"
 
37
#include "sp-gradient.h"
41
38
#include "gradient-chemistry.h"
42
39
#include "sp-gradient-reference.h"
43
40
#include "sp-linear-gradient.h"
46
43
#include "streq.h"
47
44
#include "uri.h"
48
45
#include "xml/repr.h"
 
46
#include "style.h"
 
47
#include "display/grayscale.h"
49
48
 
50
49
#define SP_MACROS_SILENT
51
50
#include "macros.h"
62
61
 
63
62
static SPObjectClass *stop_parent_class;
64
63
 
 
64
class SPGradientImpl
 
65
{
 
66
    friend class SPGradient;
 
67
 
 
68
    static void classInit(SPGradientClass *klass);
 
69
 
 
70
    static void init(SPGradient *gr);
 
71
    static void build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
 
72
    static void release(SPObject *object);
 
73
    static void modified(SPObject *object, guint flags);
 
74
    static Inkscape::XML::Node *write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags);
 
75
 
 
76
    static void gradientRefModified(SPObject *href, guint flags, SPGradient *gradient);
 
77
    static void gradientRefChanged(SPObject *old_ref, SPObject *ref, SPGradient *gr);
 
78
 
 
79
    static void childAdded(SPObject *object,
 
80
                           Inkscape::XML::Node *child,
 
81
                           Inkscape::XML::Node *ref);
 
82
    static void removeChild(SPObject *object, Inkscape::XML::Node *child);
 
83
 
 
84
    static void setGradientAttr(SPObject *object, unsigned key, gchar const *value);
 
85
};
 
86
 
65
87
/**
66
88
 * Registers SPStop class and returns its type.
67
89
 */
119
141
    if (((SPObjectClass *) stop_parent_class)->build)
120
142
        (* ((SPObjectClass *) stop_parent_class)->build)(object, document, repr);
121
143
 
122
 
    sp_object_read_attr(object, "offset");
123
 
    sp_object_read_attr(object, "stop-color");
124
 
    sp_object_read_attr(object, "stop-opacity");
125
 
    sp_object_read_attr(object, "style");
 
144
    object->readAttr( "offset" );
 
145
    object->readAttr( "stop-color" );
 
146
    object->readAttr( "stop-opacity" );
 
147
    object->readAttr( "style" );
126
148
}
127
149
 
128
150
/**
146
168
         * stop-color and stop-opacity properties.
147
169
         */
148
170
            {
149
 
                gchar const *p = sp_object_get_style_property(object, "stop-color", "black");
 
171
                gchar const *p = object->getStyleProperty( "stop-color", "black");
150
172
                if (streq(p, "currentColor")) {
151
173
                    stop->currentColor = true;
152
174
                } else {
153
 
                    guint32 const color = sp_svg_read_color(p, 0);
154
 
                    stop->specified_color.set( color );
 
175
                    stop->specified_color = SPStop::readStopColor( p );
155
176
                }
156
177
            }
157
178
            {
158
 
                gchar const *p = sp_object_get_style_property(object, "stop-opacity", "1");
 
179
                gchar const *p = object->getStyleProperty( "stop-opacity", "1");
159
180
                gdouble opacity = sp_svg_read_percentage(p, stop->opacity);
160
181
                stop->opacity = opacity;
161
182
            }
164
185
        }
165
186
        case SP_PROP_STOP_COLOR: {
166
187
            {
167
 
                gchar const *p = sp_object_get_style_property(object, "stop-color", "black");
 
188
                gchar const *p = object->getStyleProperty( "stop-color", "black");
168
189
                if (streq(p, "currentColor")) {
169
190
                    stop->currentColor = true;
170
191
                } else {
171
192
                    stop->currentColor = false;
172
 
                    guint32 const color = sp_svg_read_color(p, 0);
173
 
                    stop->specified_color.set( color );
 
193
                    stop->specified_color = SPStop::readStopColor( p );
174
194
                }
175
195
            }
176
196
            object->requestModified(SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG);
178
198
        }
179
199
        case SP_PROP_STOP_OPACITY: {
180
200
            {
181
 
                gchar const *p = sp_object_get_style_property(object, "stop-opacity", "1");
 
201
                gchar const *p = object->getStyleProperty( "stop-opacity", "1");
182
202
                gdouble opacity = sp_svg_read_percentage(p, stop->opacity);
183
203
                stop->opacity = opacity;
184
204
            }
210
230
        repr = xml_doc->createElement("svg:stop");
211
231
    }
212
232
 
213
 
    guint32 specifiedcolor = stop->specified_color.toRGBA32( 255 );
 
233
    Glib::ustring colorStr = stop->specified_color.toString();
214
234
    gfloat opacity = stop->opacity;
215
235
 
216
 
    if (((SPObjectClass *) stop_parent_class)->write)
 
236
    if (((SPObjectClass *) stop_parent_class)->write) {
217
237
        (* ((SPObjectClass *) stop_parent_class)->write)(object, xml_doc, repr, flags);
 
238
    }
218
239
 
219
240
    // Since we do a hackish style setting here (because SPStyle does not support stop-color and
220
241
    // stop-opacity), we must do it AFTER calling the parent write method; otherwise
225
246
    if (stop->currentColor) {
226
247
        os << "currentColor";
227
248
    } else {
228
 
        gchar c[64];
229
 
        sp_svg_write_color(c, sizeof(c), specifiedcolor);
230
 
        os << c;
 
249
        os << colorStr;
231
250
    }
232
251
    os << ";stop-opacity:" << opacity;
233
252
    repr->setAttribute("style", os.str().c_str());
240
259
    return repr;
241
260
}
242
261
 
 
262
 
 
263
bool SPGradient::hasStops() const
 
264
{
 
265
    return has_stops;
 
266
}
 
267
 
 
268
bool SPGradient::isUnitsSet() const
 
269
{
 
270
    return units_set;
 
271
}
 
272
 
 
273
SPGradientUnits SPGradient::getUnits() const
 
274
{
 
275
    return units;
 
276
}
 
277
 
 
278
bool SPGradient::isSpreadSet() const
 
279
{
 
280
    return spread_set;
 
281
}
 
282
 
 
283
SPGradientSpread SPGradient::getSpread() const
 
284
{
 
285
    return spread;
 
286
}
 
287
 
 
288
void SPGradient::setSwatch( bool swatch )
 
289
{
 
290
    if ( swatch != isSwatch() ) {
 
291
        this->swatch = swatch; // to make isSolid() work, this happens first
 
292
        gchar const* paintVal = swatch ? (isSolid() ? "solid" : "gradient") : 0;
 
293
        setAttribute( "osb:paint", paintVal, 0 );
 
294
 
 
295
        requestModified( SP_OBJECT_MODIFIED_FLAG );
 
296
    }
 
297
}
 
298
 
243
299
/**
244
300
 * Return stop's color as 32bit value.
245
301
 */
251
307
     * value depends on user agent, and don't give any further restrictions that I can
252
308
     * see.) */
253
309
    if (stop->currentColor) {
254
 
        char const *str = sp_object_get_style_property(stop, "color", NULL);
 
310
        char const *str = stop->getStyleProperty( "color", NULL);
255
311
        if (str) {
256
312
            rgb0 = sp_svg_read_color(str, rgb0);
257
313
        }
264
320
    }
265
321
}
266
322
 
267
 
/**
268
 
 * Return stop's color as SPColor.
269
 
 */
270
 
static SPColor
271
 
sp_stop_get_color(SPStop const *const stop)
272
 
{
273
 
    if (stop->currentColor) {
274
 
        char const *str = sp_object_get_style_property(stop, "color", NULL);
275
 
        guint32 const dfl = 0;
276
 
        /* Default value: arbitrarily black.  (SVG1.1 and CSS2 both say that the initial
277
 
         * value depends on user agent, and don't give any further restrictions that I can
278
 
         * see.) */
279
 
        guint32 color = dfl;
280
 
        if (str) {
281
 
            color = sp_svg_read_color(str, dfl);
282
 
        }
283
 
        SPColor ret( color );
284
 
        return ret;
285
 
    } else {
286
 
        return stop->specified_color;
287
 
    }
288
 
}
289
 
 
290
323
/*
291
324
 * Gradient
292
325
 */
293
326
 
294
 
static void sp_gradient_class_init(SPGradientClass *klass);
295
 
static void sp_gradient_init(SPGradient *gr);
296
 
 
297
 
static void sp_gradient_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
298
 
static void sp_gradient_release(SPObject *object);
299
 
static void sp_gradient_set(SPObject *object, unsigned key, gchar const *value);
300
 
static void sp_gradient_child_added(SPObject *object,
301
 
                                    Inkscape::XML::Node *child,
302
 
                                    Inkscape::XML::Node *ref);
303
 
static void sp_gradient_remove_child(SPObject *object, Inkscape::XML::Node *child);
304
 
static void sp_gradient_modified(SPObject *object, guint flags);
305
 
static Inkscape::XML::Node *sp_gradient_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr,
306
 
                                              guint flags);
307
 
 
308
 
static void gradient_ref_modified(SPObject *href, guint flags, SPGradient *gradient);
309
 
 
310
 
static bool sp_gradient_invalidate_vector(SPGradient *gr);
311
 
static void sp_gradient_rebuild_vector(SPGradient *gr);
312
 
 
313
 
static void gradient_ref_changed(SPObject *old_ref, SPObject *ref, SPGradient *gradient);
314
 
 
315
 
SPGradientSpread sp_gradient_get_spread(SPGradient *gradient);
316
 
SPGradientUnits sp_gradient_get_units(SPGradient *gradient);
317
 
 
318
327
static SPPaintServerClass *gradient_parent_class;
319
328
 
320
329
/**
321
330
 * Registers SPGradient class and returns its type.
322
331
 */
323
 
GType
324
 
sp_gradient_get_type()
 
332
GType SPGradient::getType()
325
333
{
326
334
    static GType gradient_type = 0;
327
335
    if (!gradient_type) {
328
336
        GTypeInfo gradient_info = {
329
337
            sizeof(SPGradientClass),
330
338
            NULL, NULL,
331
 
            (GClassInitFunc) sp_gradient_class_init,
 
339
            (GClassInitFunc) SPGradientImpl::classInit,
332
340
            NULL, NULL,
333
341
            sizeof(SPGradient),
334
342
            16,
335
 
            (GInstanceInitFunc) sp_gradient_init,
 
343
            (GInstanceInitFunc) SPGradientImpl::init,
336
344
            NULL,   /* value_table */
337
345
        };
338
346
        gradient_type = g_type_register_static(SP_TYPE_PAINT_SERVER, "SPGradient",
344
352
/**
345
353
 * SPGradient vtable initialization.
346
354
 */
347
 
static void
348
 
sp_gradient_class_init(SPGradientClass *klass)
 
355
void SPGradientImpl::classInit(SPGradientClass *klass)
349
356
{
350
357
    SPObjectClass *sp_object_class = (SPObjectClass *) klass;
351
358
 
352
359
    gradient_parent_class = (SPPaintServerClass *)g_type_class_ref(SP_TYPE_PAINT_SERVER);
353
360
 
354
 
    sp_object_class->build = sp_gradient_build;
355
 
    sp_object_class->release = sp_gradient_release;
356
 
    sp_object_class->set = sp_gradient_set;
357
 
    sp_object_class->child_added = sp_gradient_child_added;
358
 
    sp_object_class->remove_child = sp_gradient_remove_child;
359
 
    sp_object_class->modified = sp_gradient_modified;
360
 
    sp_object_class->write = sp_gradient_write;
 
361
    sp_object_class->build = SPGradientImpl::build;
 
362
    sp_object_class->release = SPGradientImpl::release;
 
363
    sp_object_class->set = SPGradientImpl::setGradientAttr;
 
364
    sp_object_class->child_added = SPGradientImpl::childAdded;
 
365
    sp_object_class->remove_child = SPGradientImpl::removeChild;
 
366
    sp_object_class->modified = SPGradientImpl::modified;
 
367
    sp_object_class->write = SPGradientImpl::write;
361
368
}
362
369
 
363
370
/**
364
371
 * Callback for SPGradient object initialization.
365
372
 */
366
 
static void
367
 
sp_gradient_init(SPGradient *gr)
 
373
void SPGradientImpl::init(SPGradient *gr)
368
374
{
369
 
    gr->ref = new SPGradientReference(SP_OBJECT(gr));
370
 
    gr->ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(gradient_ref_changed), gr));
 
375
    gr->ref = new SPGradientReference(gr);
 
376
    gr->ref->changedSignal().connect(sigc::bind(sigc::ptr_fun(SPGradientImpl::gradientRefChanged), gr));
371
377
 
372
378
    /** \todo
373
379
     * Fixme: reprs being rearranged (e.g. via the XML editor)
389
395
    gr->vector.built = false;
390
396
    gr->vector.stops.clear();
391
397
 
392
 
    gr->color = NULL;
393
 
 
394
398
    new (&gr->modified_connection) sigc::connection();
395
399
}
396
400
 
397
401
/**
398
402
 * Virtual build: set gradient attributes from its associated repr.
399
403
 */
400
 
static void
401
 
sp_gradient_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
 
404
void SPGradientImpl::build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
402
405
{
403
406
    SPGradient *gradient = SP_GRADIENT(object);
404
407
 
405
 
    if (((SPObjectClass *) gradient_parent_class)->build)
 
408
    // Work-around in case a swatch had been marked for immediate collection:
 
409
    if ( repr->attribute("osb:paint") && repr->attribute("inkscape:collect") ) {
 
410
        repr->setAttribute("inkscape:collect", 0);
 
411
    }
 
412
 
 
413
    if (((SPObjectClass *) gradient_parent_class)->build) {
406
414
        (* ((SPObjectClass *) gradient_parent_class)->build)(object, document, repr);
 
415
    }
407
416
 
408
 
    SPObject *ochild;
409
 
    for ( ochild = sp_object_first_child(object) ; ochild ; ochild = SP_OBJECT_NEXT(ochild) ) {
 
417
    for ( SPObject *ochild = object->firstChild() ; ochild ; ochild = ochild->getNext() ) {
410
418
        if (SP_IS_STOP(ochild)) {
411
419
            gradient->has_stops = TRUE;
412
420
            break;
413
421
        }
414
422
    }
415
423
 
416
 
    sp_object_read_attr(object, "gradientUnits");
417
 
    sp_object_read_attr(object, "gradientTransform");
418
 
    sp_object_read_attr(object, "spreadMethod");
419
 
    sp_object_read_attr(object, "xlink:href");
 
424
    object->readAttr( "gradientUnits" );
 
425
    object->readAttr( "gradientTransform" );
 
426
    object->readAttr( "spreadMethod" );
 
427
    object->readAttr( "xlink:href" );
 
428
    object->readAttr( "osb:paint" );
420
429
 
421
 
    /* Register ourselves */
422
 
    sp_document_add_resource(document, "gradient", object);
 
430
    // Register ourselves
 
431
    document->addResource("gradient", object);
423
432
}
424
433
 
425
434
/**
426
435
 * Virtual release of SPGradient members before destruction.
427
436
 */
428
 
static void
429
 
sp_gradient_release(SPObject *object)
 
437
void SPGradientImpl::release(SPObject *object)
430
438
{
431
439
    SPGradient *gradient = (SPGradient *) object;
432
440
 
433
441
#ifdef SP_GRADIENT_VERBOSE
434
 
    g_print("Releasing gradient %s\n", SP_OBJECT_ID(object));
 
442
    g_print("Releasing gradient %s\n", object->getId());
435
443
#endif
436
444
 
437
 
    if (SP_OBJECT_DOCUMENT(object)) {
438
 
        /* Unregister ourselves */
439
 
        sp_document_remove_resource(SP_OBJECT_DOCUMENT(object), "gradient", SP_OBJECT(object));
 
445
    if (object->document) {
 
446
        // Unregister ourselves
 
447
        object->document->removeResource("gradient", object);
440
448
    }
441
449
 
442
450
    if (gradient->ref) {
446
454
        gradient->ref = NULL;
447
455
    }
448
456
 
449
 
    if (gradient->color) {
450
 
        g_free(gradient->color);
451
 
        gradient->color = NULL;
452
 
    }
453
 
 
454
457
    gradient->modified_connection.~connection();
455
458
 
456
459
    if (((SPObjectClass *) gradient_parent_class)->release)
460
463
/**
461
464
 * Set gradient attribute to value.
462
465
 */
463
 
static void
464
 
sp_gradient_set(SPObject *object, unsigned key, gchar const *value)
 
466
void SPGradientImpl::setGradientAttr(SPObject *object, unsigned key, gchar const *value)
465
467
{
466
468
    SPGradient *gr = SP_GRADIENT(object);
467
469
 
481
483
            object->requestModified(SP_OBJECT_MODIFIED_FLAG);
482
484
            break;
483
485
        case SP_ATTR_GRADIENTTRANSFORM: {
484
 
            Geom::Matrix t;
 
486
            Geom::Affine t;
485
487
            if (value && sp_svg_transform_read(value, &t)) {
486
488
                gr->gradientTransform = t;
487
489
                gr->gradientTransform_set = TRUE;
519
521
                gr->ref->detach();
520
522
            }
521
523
            break;
 
524
        case SP_ATTR_OSB_SWATCH:
 
525
        {
 
526
            bool newVal = (value != 0);
 
527
            bool modified = false;
 
528
            if (newVal != gr->swatch) {
 
529
                gr->swatch = newVal;
 
530
                modified = true;
 
531
            }
 
532
            if (newVal) {
 
533
                // Might need to flip solid/gradient
 
534
                Glib::ustring paintVal = ( gr->hasStops() && (gr->getStopCount() == 0) ) ? "solid" : "gradient";
 
535
                if ( paintVal != value ) {
 
536
                    gr->setAttribute( "osb:paint", paintVal.c_str(), 0 );
 
537
                    modified = true;
 
538
                }
 
539
            }
 
540
            if (modified) {
 
541
                object->requestModified(SP_OBJECT_MODIFIED_FLAG);
 
542
            }
 
543
        }
 
544
            break;
522
545
        default:
523
 
            if (((SPObjectClass *) gradient_parent_class)->set)
 
546
            if (((SPObjectClass *) gradient_parent_class)->set) {
524
547
                ((SPObjectClass *) gradient_parent_class)->set(object, key, value);
 
548
            }
525
549
            break;
526
550
    }
527
551
}
529
553
/**
530
554
 * Gets called when the gradient is (re)attached to another gradient.
531
555
 */
532
 
static void
533
 
gradient_ref_changed(SPObject *old_ref, SPObject *ref, SPGradient *gr)
 
556
void SPGradientImpl::gradientRefChanged(SPObject *old_ref, SPObject *ref, SPGradient *gr)
534
557
{
535
558
    if (old_ref) {
536
559
        gr->modified_connection.disconnect();
538
561
    if ( SP_IS_GRADIENT(ref)
539
562
         && ref != gr )
540
563
    {
541
 
        gr->modified_connection = ref->connectModified(sigc::bind<2>(sigc::ptr_fun(&gradient_ref_modified), gr));
 
564
        gr->modified_connection = ref->connectModified(sigc::bind<2>(sigc::ptr_fun(&SPGradientImpl::gradientRefModified), gr));
542
565
    }
543
566
 
544
567
    // Per SVG, all unset attributes must be inherited from linked gradient.
545
568
    // So, as we're now (re)linked, we assign linkee's values to this gradient if they are not yet set -
546
569
    // but without setting the _set flags.
547
570
    // FIXME: do the same for gradientTransform too
548
 
    if (!gr->units_set)
549
 
        gr->units = sp_gradient_get_units (gr);
550
 
    if (!gr->spread_set)
551
 
        gr->spread = sp_gradient_get_spread (gr);
 
571
    if (!gr->units_set) {
 
572
        gr->units = gr->fetchUnits();
 
573
    }
 
574
    if (!gr->spread_set) {
 
575
        gr->spread = gr->fetchSpread();
 
576
    }
552
577
 
553
578
    /// \todo Fixme: what should the flags (second) argument be? */
554
 
    gradient_ref_modified(ref, 0, gr);
 
579
    gradientRefModified(ref, 0, gr);
555
580
}
556
581
 
557
582
/**
558
583
 * Callback for child_added event.
559
584
 */
560
 
static void
561
 
sp_gradient_child_added(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
 
585
void SPGradientImpl::childAdded(SPObject *object, Inkscape::XML::Node *child, Inkscape::XML::Node *ref)
562
586
{
563
587
    SPGradient *gr = SP_GRADIENT(object);
564
588
 
565
 
    sp_gradient_invalidate_vector(gr);
 
589
    gr->invalidateVector();
566
590
 
567
 
    if (((SPObjectClass *) gradient_parent_class)->child_added)
 
591
    if (((SPObjectClass *) gradient_parent_class)->child_added) {
568
592
        (* ((SPObjectClass *) gradient_parent_class)->child_added)(object, child, ref);
 
593
    }
569
594
 
570
 
    SPObject *ochild = sp_object_get_child_by_repr(object, child);
 
595
    SPObject *ochild = object->get_child_by_repr(child);
571
596
    if ( ochild && SP_IS_STOP(ochild) ) {
572
597
        gr->has_stops = TRUE;
 
598
        if ( gr->getStopCount() > 0 ) {
 
599
            gchar const * attr = gr->getAttribute("osb:paint");
 
600
            if ( attr && strcmp(attr, "gradient") ) {
 
601
                gr->setAttribute( "osb:paint", "gradient", 0 );
 
602
            }
 
603
        }
573
604
    }
574
605
 
575
606
    /// \todo Fixme: should we schedule "modified" here?
579
610
/**
580
611
 * Callback for remove_child event.
581
612
 */
582
 
static void
583
 
sp_gradient_remove_child(SPObject *object, Inkscape::XML::Node *child)
 
613
void SPGradientImpl::removeChild(SPObject *object, Inkscape::XML::Node *child)
584
614
{
585
615
    SPGradient *gr = SP_GRADIENT(object);
586
616
 
587
 
    sp_gradient_invalidate_vector(gr);
 
617
    gr->invalidateVector();
588
618
 
589
 
    if (((SPObjectClass *) gradient_parent_class)->remove_child)
 
619
    if (((SPObjectClass *) gradient_parent_class)->remove_child) {
590
620
        (* ((SPObjectClass *) gradient_parent_class)->remove_child)(object, child);
 
621
    }
591
622
 
592
623
    gr->has_stops = FALSE;
593
 
    SPObject *ochild;
594
 
    for ( ochild = sp_object_first_child(object) ; ochild ; ochild = SP_OBJECT_NEXT(ochild) ) {
 
624
    for ( SPObject *ochild = object->firstChild() ; ochild ; ochild = ochild->getNext() ) {
595
625
        if (SP_IS_STOP(ochild)) {
596
626
            gr->has_stops = TRUE;
597
627
            break;
598
628
        }
599
629
    }
600
630
 
 
631
    if ( gr->getStopCount() == 0 ) {
 
632
        gchar const * attr = gr->getAttribute("osb:paint");
 
633
        if ( attr && strcmp(attr, "solid") ) {
 
634
            gr->setAttribute( "osb:paint", "solid", 0 );
 
635
        }
 
636
    }
 
637
 
601
638
    /* Fixme: should we schedule "modified" here? */
602
639
    object->requestModified(SP_OBJECT_MODIFIED_FLAG);
603
640
}
605
642
/**
606
643
 * Callback for modified event.
607
644
 */
608
 
static void
609
 
sp_gradient_modified(SPObject *object, guint flags)
 
645
void SPGradientImpl::modified(SPObject *object, guint flags)
610
646
{
611
647
    SPGradient *gr = SP_GRADIENT(object);
612
648
 
613
649
    if (flags & SP_OBJECT_CHILD_MODIFIED_FLAG) {
614
 
        sp_gradient_invalidate_vector(gr);
 
650
        gr->invalidateVector();
615
651
    }
616
652
 
617
653
    if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) {
618
 
        sp_gradient_ensure_colors(gr);
 
654
        gr->ensureVector();
619
655
    }
620
656
 
621
657
    if (flags & SP_OBJECT_MODIFIED_FLAG) flags |= SP_OBJECT_PARENT_MODIFIED_FLAG;
623
659
 
624
660
    // FIXME: climb up the ladder of hrefs
625
661
    GSList *l = NULL;
626
 
    for (SPObject *child = sp_object_first_child(object) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
 
662
    for (SPObject *child = object->firstChild() ; child; child = child->getNext() ) {
627
663
        g_object_ref(G_OBJECT(child));
628
664
        l = g_slist_prepend(l, child);
629
665
    }
641
677
SPStop* SPGradient::getFirstStop()
642
678
{
643
679
    SPStop* first = 0;
644
 
    for (SPObject *ochild = sp_object_first_child(this); ochild && !first; ochild = SP_OBJECT_NEXT(ochild)) {
 
680
    for (SPObject *ochild = firstChild(); ochild && !first; ochild = ochild->getNext()) {
645
681
        if (SP_IS_STOP(ochild)) {
646
682
            first = SP_STOP(ochild);
647
683
        }
663
699
/**
664
700
 * Write gradient attributes to repr.
665
701
 */
666
 
static Inkscape::XML::Node *
667
 
sp_gradient_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
 
702
Inkscape::XML::Node *SPGradientImpl::write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
668
703
{
669
704
    SPGradient *gr = SP_GRADIENT(object);
670
705
 
671
 
    if (((SPObjectClass *) gradient_parent_class)->write)
 
706
    if (((SPObjectClass *) gradient_parent_class)->write) {
672
707
        (* ((SPObjectClass *) gradient_parent_class)->write)(object, xml_doc, repr, flags);
 
708
    }
673
709
 
674
710
    if (flags & SP_OBJECT_WRITE_BUILD) {
675
711
        GSList *l = NULL;
676
 
        for (SPObject *child = sp_object_first_child(object); child; child = SP_OBJECT_NEXT(child)) {
677
 
            Inkscape::XML::Node *crepr;
678
 
            crepr = child->updateRepr(xml_doc, NULL, flags);
679
 
            if (crepr) l = g_slist_prepend(l, crepr);
 
712
        for (SPObject *child = object->firstChild(); child; child = child->getNext()) {
 
713
            Inkscape::XML::Node *crepr = child->updateRepr(xml_doc, NULL, flags);
 
714
            if (crepr) {
 
715
                l = g_slist_prepend(l, crepr);
 
716
            }
680
717
        }
681
718
        while (l) {
682
719
            repr->addChild((Inkscape::XML::Node *) l->data, NULL);
710
747
 
711
748
    if ((flags & SP_OBJECT_WRITE_ALL) || gr->spread_set) {
712
749
        /* FIXME: Ensure that gr->spread is the inherited value
713
 
         * if !gr->spread_set.  Not currently happening: see sp_gradient_modified.
 
750
         * if !gr->spread_set.  Not currently happening: see SPGradient::modified.
714
751
         */
715
752
        switch (gr->spread) {
716
753
            case SP_GRADIENT_SPREAD_REFLECT:
725
762
        }
726
763
    }
727
764
 
 
765
    if ( (flags & SP_OBJECT_WRITE_EXT) && gr->isSwatch() ) {
 
766
        if ( gr->isSolid() ) {
 
767
            repr->setAttribute( "osb:paint", "solid" );
 
768
        } else {
 
769
            repr->setAttribute( "osb:paint", "gradient" );
 
770
        }
 
771
    } else {
 
772
        repr->setAttribute( "osb:paint", 0 );
 
773
    }
 
774
 
728
775
    return repr;
729
776
}
730
777
 
733
780
 *
734
781
 * \pre SP_IS_GRADIENT(gradient).
735
782
 */
736
 
void
737
 
sp_gradient_ensure_vector(SPGradient *gradient)
 
783
void SPGradient::ensureVector()
738
784
{
739
 
    g_return_if_fail(gradient != NULL);
740
 
    g_return_if_fail(SP_IS_GRADIENT(gradient));
741
 
 
742
 
    if (!gradient->vector.built) {
743
 
        sp_gradient_rebuild_vector(gradient);
 
785
    if ( !vector.built ) {
 
786
        rebuildVector();
744
787
    }
745
788
}
746
789
 
747
790
/**
748
791
 * Set units property of gradient and emit modified.
749
792
 */
750
 
void
751
 
sp_gradient_set_units(SPGradient *gr, SPGradientUnits units)
 
793
void SPGradient::setUnits(SPGradientUnits units)
752
794
{
753
 
    if (units != gr->units) {
754
 
        gr->units = units;
755
 
        gr->units_set = TRUE;
756
 
        SP_OBJECT(gr)->requestModified(SP_OBJECT_MODIFIED_FLAG);
 
795
    if (units != this->units) {
 
796
        this->units = units;
 
797
        units_set = TRUE;
 
798
        requestModified(SP_OBJECT_MODIFIED_FLAG);
757
799
    }
758
800
}
759
801
 
760
802
/**
761
803
 * Set spread property of gradient and emit modified.
762
804
 */
763
 
void
764
 
sp_gradient_set_spread(SPGradient *gr, SPGradientSpread spread)
 
805
void SPGradient::setSpread(SPGradientSpread spread)
765
806
{
766
 
    if (spread != gr->spread) {
767
 
        gr->spread = spread;
768
 
        gr->spread_set = TRUE;
769
 
        SP_OBJECT(gr)->requestModified(SP_OBJECT_MODIFIED_FLAG);
 
807
    if (spread != this->spread) {
 
808
        this->spread = spread;
 
809
        spread_set = TRUE;
 
810
        requestModified(SP_OBJECT_MODIFIED_FLAG);
770
811
    }
771
812
}
772
813
 
817
858
 */
818
859
static bool has_stopsFN(SPGradient const *gr)
819
860
{
820
 
    return SP_GRADIENT_HAS_STOPS(gr);
 
861
    return gr->hasStops();
821
862
}
822
863
 
823
864
/**
824
865
 * True if gradient has spread set.
825
866
 */
826
 
static bool
827
 
has_spread_set(SPGradient const *gr)
 
867
static bool has_spread_set(SPGradient const *gr)
828
868
{
829
 
    return gr->spread_set;
 
869
    return gr->isSpreadSet();
830
870
}
831
871
 
832
872
/**
835
875
static bool
836
876
has_units_set(SPGradient const *gr)
837
877
{
838
 
    return gr->units_set;
 
878
    return gr->isUnitsSet();
839
879
}
840
880
 
841
881
 
854
894
 *
855
895
 * \pre SP_IS_GRADIENT(gradient).
856
896
 */
857
 
SPGradientSpread
858
 
sp_gradient_get_spread(SPGradient *gradient)
 
897
SPGradientSpread SPGradient::fetchSpread()
859
898
{
860
 
    g_return_val_if_fail(SP_IS_GRADIENT(gradient), SP_GRADIENT_SPREAD_PAD);
861
 
 
862
 
    SPGradient const *src = chase_hrefs(gradient, has_spread_set);
 
899
    SPGradient const *src = chase_hrefs(this, has_spread_set);
863
900
    return ( src
864
901
             ? src->spread
865
902
             : SP_GRADIENT_SPREAD_PAD ); // pad is the default
870
907
 *
871
908
 * \pre SP_IS_GRADIENT(gradient).
872
909
 */
873
 
SPGradientUnits
874
 
sp_gradient_get_units(SPGradient *gradient)
 
910
SPGradientUnits SPGradient::fetchUnits()
875
911
{
876
 
    g_return_val_if_fail(SP_IS_GRADIENT(gradient), SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX);
877
 
 
878
 
    SPGradient const *src = chase_hrefs(gradient, has_units_set);
 
912
    SPGradient const *src = chase_hrefs(this, has_units_set);
879
913
    return ( src
880
914
             ? src->units
881
915
             : SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX ); // bbox is the default
888
922
void
889
923
sp_gradient_repr_clear_vector(SPGradient *gr)
890
924
{
891
 
    Inkscape::XML::Node *repr = SP_OBJECT_REPR(gr);
 
925
    Inkscape::XML::Node *repr = gr->getRepr();
892
926
 
893
927
    /* Collect stops from original repr */
894
928
    GSList *sl = NULL;
918
952
    g_return_if_fail(gr != NULL);
919
953
    g_return_if_fail(SP_IS_GRADIENT(gr));
920
954
 
921
 
    Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_OBJECT_DOCUMENT(gr));
922
 
    Inkscape::XML::Node *repr = SP_OBJECT_REPR(gr);
 
955
    Inkscape::XML::Document *xml_doc = gr->document->getReprDoc();
 
956
    Inkscape::XML::Node *repr = gr->getRepr();
923
957
 
924
958
    /* We have to be careful, as vector may be our own, so construct repr list at first */
925
959
    GSList *cl = NULL;
930
964
        sp_repr_set_css_double(child, "offset", gr->vector.stops[i].offset);
931
965
        /* strictly speaking, offset an SVG <number> rather than a CSS one, but exponents make no
932
966
         * sense for offset proportions. */
933
 
        gchar c[64];
934
 
        sp_svg_write_color(c, sizeof(c), gr->vector.stops[i].color.toRGBA32( 0x00 ));
935
 
        os << "stop-color:" << c << ";stop-opacity:" << gr->vector.stops[i].opacity;
 
967
        os << "stop-color:" << gr->vector.stops[i].color.toString() << ";stop-opacity:" << gr->vector.stops[i].opacity;
936
968
        child->setAttribute("style", os.str().c_str());
937
969
        /* Order will be reversed here */
938
970
        cl = g_slist_prepend(cl, child);
950
982
}
951
983
 
952
984
 
953
 
static void
954
 
gradient_ref_modified(SPObject */*href*/, guint /*flags*/, SPGradient *gradient)
 
985
void SPGradientImpl::gradientRefModified(SPObject */*href*/, guint /*flags*/, SPGradient *gradient)
955
986
{
956
 
    if (sp_gradient_invalidate_vector(gradient)) {
957
 
        SP_OBJECT(gradient)->requestModified(SP_OBJECT_MODIFIED_FLAG);
958
 
        /* Conditional to avoid causing infinite loop if there's a cycle in the href chain. */
 
987
    if ( gradient->invalidateVector() ) {
 
988
        gradient->requestModified(SP_OBJECT_MODIFIED_FLAG);
 
989
        // Conditional to avoid causing infinite loop if there's a cycle in the href chain.
959
990
    }
960
991
}
961
992
 
962
 
/** Return true iff change made. */
963
 
static bool
964
 
sp_gradient_invalidate_vector(SPGradient *gr)
 
993
/** Return true if change made. */
 
994
bool SPGradient::invalidateVector()
965
995
{
966
996
    bool ret = false;
967
997
 
968
 
    if (gr->color != NULL) {
969
 
        g_free(gr->color);
970
 
        gr->color = NULL;
971
 
        ret = true;
972
 
    }
973
 
 
974
 
    if (gr->vector.built) {
975
 
        gr->vector.built = false;
976
 
        gr->vector.stops.clear();
 
998
    if (vector.built) {
 
999
        vector.built = false;
 
1000
        vector.stops.clear();
977
1001
        ret = true;
978
1002
    }
979
1003
 
981
1005
}
982
1006
 
983
1007
/** Creates normalized color vector */
984
 
static void
985
 
sp_gradient_rebuild_vector(SPGradient *gr)
 
1008
void SPGradient::rebuildVector()
986
1009
{
987
1010
    gint len = 0;
988
 
    for ( SPObject *child = sp_object_first_child(SP_OBJECT(gr)) ;
989
 
          child != NULL ;
990
 
          child = SP_OBJECT_NEXT(child) ) {
 
1011
    for ( SPObject *child = firstChild() ; child ; child = child->getNext() ) {
991
1012
        if (SP_IS_STOP(child)) {
992
1013
            len ++;
993
1014
        }
994
1015
    }
995
1016
 
996
 
    gr->has_stops = (len != 0);
997
 
 
998
 
    gr->vector.stops.clear();
999
 
 
1000
 
    SPGradient *ref = gr->ref->getObject();
1001
 
    if ( !gr->has_stops && ref ) {
 
1017
    has_stops = (len != 0);
 
1018
 
 
1019
    vector.stops.clear();
 
1020
 
 
1021
    SPGradient *reffed = ref->getObject();
 
1022
    if ( !hasStops() && reffed ) {
1002
1023
        /* Copy vector from referenced gradient */
1003
 
        gr->vector.built = true;   // Prevent infinite recursion.
1004
 
        sp_gradient_ensure_vector(ref);
1005
 
        if (!ref->vector.stops.empty()) {
1006
 
            gr->vector.built = ref->vector.built;
1007
 
            gr->vector.stops.assign(ref->vector.stops.begin(), ref->vector.stops.end());
 
1024
        vector.built = true;   // Prevent infinite recursion.
 
1025
        reffed->ensureVector();
 
1026
        if (!reffed->vector.stops.empty()) {
 
1027
            vector.built = reffed->vector.built;
 
1028
            vector.stops.assign(reffed->vector.stops.begin(), reffed->vector.stops.end());
1008
1029
            return;
1009
1030
        }
1010
1031
    }
1011
1032
 
1012
 
    for (SPObject *child = sp_object_first_child(SP_OBJECT(gr)) ;
1013
 
         child != NULL;
1014
 
         child = SP_OBJECT_NEXT(child) ) {
 
1033
    for ( SPObject *child = firstChild(); child; child = child->getNext() ) {
1015
1034
        if (SP_IS_STOP(child)) {
1016
1035
            SPStop *stop = SP_STOP(child);
1017
1036
 
1018
1037
            SPGradientStop gstop;
1019
 
            if (gr->vector.stops.size() > 0) {
 
1038
            if (vector.stops.size() > 0) {
1020
1039
                // "Each gradient offset value is required to be equal to or greater than the
1021
1040
                // previous gradient stop's offset value. If a given gradient stop's offset
1022
1041
                // value is not equal to or greater than all previous offset values, then the
1023
1042
                // offset value is adjusted to be equal to the largest of all previous offset
1024
1043
                // values."
1025
 
                gstop.offset = MAX(stop->offset, gr->vector.stops.back().offset);
 
1044
                gstop.offset = MAX(stop->offset, vector.stops.back().offset);
1026
1045
            } else {
1027
1046
                gstop.offset = stop->offset;
1028
1047
            }
1032
1051
            // down to 100%."
1033
1052
            gstop.offset = CLAMP(gstop.offset, 0, 1);
1034
1053
 
1035
 
            gstop.color = sp_stop_get_color(stop);
 
1054
            gstop.color = stop->getEffectiveColor();
1036
1055
            gstop.opacity = stop->opacity;
1037
1056
 
1038
 
            gr->vector.stops.push_back(gstop);
 
1057
            vector.stops.push_back(gstop);
1039
1058
        }
1040
1059
    }
1041
1060
 
1042
1061
    // Normalize per section 13.2.4 of SVG 1.1.
1043
 
    if (gr->vector.stops.size() == 0) {
 
1062
    if (vector.stops.size() == 0) {
1044
1063
        /* "If no stops are defined, then painting shall occur as if 'none' were specified as the
1045
1064
         * paint style."
1046
1065
         */
1049
1068
            gstop.offset = 0.0;
1050
1069
            gstop.color.set( 0x00000000 );
1051
1070
            gstop.opacity = 0.0;
1052
 
            gr->vector.stops.push_back(gstop);
 
1071
            vector.stops.push_back(gstop);
1053
1072
        }
1054
1073
        {
1055
1074
            SPGradientStop gstop;
1056
1075
            gstop.offset = 1.0;
1057
1076
            gstop.color.set( 0x00000000 );
1058
1077
            gstop.opacity = 0.0;
1059
 
            gr->vector.stops.push_back(gstop);
 
1078
            vector.stops.push_back(gstop);
1060
1079
        }
1061
1080
    } else {
1062
1081
        /* "If one stop is defined, then paint with the solid color fill using the color defined
1063
1082
         * for that gradient stop."
1064
1083
         */
1065
 
        if (gr->vector.stops.front().offset > 0.0) {
 
1084
        if (vector.stops.front().offset > 0.0) {
1066
1085
            // If the first one is not at 0, then insert a copy of the first at 0.
1067
1086
            SPGradientStop gstop;
1068
1087
            gstop.offset = 0.0;
1069
 
            gstop.color = gr->vector.stops.front().color;
1070
 
            gstop.opacity = gr->vector.stops.front().opacity;
1071
 
            gr->vector.stops.insert(gr->vector.stops.begin(), gstop);
 
1088
            gstop.color = vector.stops.front().color;
 
1089
            gstop.opacity = vector.stops.front().opacity;
 
1090
            vector.stops.insert(vector.stops.begin(), gstop);
1072
1091
        }
1073
 
        if (gr->vector.stops.back().offset < 1.0) {
 
1092
        if (vector.stops.back().offset < 1.0) {
1074
1093
            // If the last one is not at 1, then insert a copy of the last at 1.
1075
1094
            SPGradientStop gstop;
1076
1095
            gstop.offset = 1.0;
1077
 
            gstop.color = gr->vector.stops.back().color;
1078
 
            gstop.opacity = gr->vector.stops.back().opacity;
1079
 
            gr->vector.stops.push_back(gstop);
1080
 
        }
1081
 
    }
1082
 
 
1083
 
    gr->vector.built = true;
1084
 
}
1085
 
 
1086
 
/**
1087
 
 * The gradient's color array is newly created and set up from vector.
1088
 
 */
1089
 
void
1090
 
sp_gradient_ensure_colors(SPGradient *gr)
1091
 
{
1092
 
    if (!gr->vector.built) {
1093
 
        sp_gradient_rebuild_vector(gr);
1094
 
    }
1095
 
    g_return_if_fail(!gr->vector.stops.empty());
1096
 
 
1097
 
    /// \todo Where is the memory freed?
1098
 
    if (!gr->color) {
1099
 
        gr->color = g_new(guchar, 4 * NCOLORS);
1100
 
    }
1101
 
 
1102
 
    // This assumes that gr->vector is a zero-order B-spline (box function) approximation of the "true" gradient.
1103
 
    // This means that the "true" gradient must be prefiltered using a zero order B-spline and then sampled.
1104
 
    // Furthermore, the first element corresponds to offset="0" and the last element to offset="1".
1105
 
 
1106
 
    double remainder[4] = {0,0,0,0};
1107
 
    double remainder_for_end[4] = {0,0,0,0}; // Used at the end
1108
 
    switch(gr->spread) {
1109
 
    case SP_GRADIENT_SPREAD_PAD:
1110
 
        remainder[0] = 0.5*gr->vector.stops[0].color.v.c[0]; // Half of the first cell uses the color of the first stop
1111
 
        remainder[1] = 0.5*gr->vector.stops[0].color.v.c[1];
1112
 
        remainder[2] = 0.5*gr->vector.stops[0].color.v.c[2];
1113
 
        remainder[3] = 0.5*gr->vector.stops[0].opacity;
1114
 
        remainder_for_end[0] = 0.5*gr->vector.stops[gr->vector.stops.size() - 1].color.v.c[0]; // Half of the first cell uses the color of the last stop
1115
 
        remainder_for_end[1] = 0.5*gr->vector.stops[gr->vector.stops.size() - 1].color.v.c[1];
1116
 
        remainder_for_end[2] = 0.5*gr->vector.stops[gr->vector.stops.size() - 1].color.v.c[2];
1117
 
        remainder_for_end[3] = 0.5*gr->vector.stops[gr->vector.stops.size() - 1].opacity;
1118
 
        break;
1119
 
    case SP_GRADIENT_SPREAD_REFLECT:
1120
 
    case SP_GRADIENT_SPREAD_REPEAT:
1121
 
        // These two are handled differently, see below.
1122
 
        break;
1123
 
    default:
1124
 
        g_error("Spread type not supported!");
1125
 
    };
1126
 
    for (unsigned int i = 0; i < gr->vector.stops.size() - 1; i++) {
1127
 
        double r0 = gr->vector.stops[i].color.v.c[0];
1128
 
        double g0 = gr->vector.stops[i].color.v.c[1];
1129
 
        double b0 = gr->vector.stops[i].color.v.c[2];
1130
 
        double a0 = gr->vector.stops[i].opacity;
1131
 
        double r1 = gr->vector.stops[i+1].color.v.c[0];
1132
 
        double g1 = gr->vector.stops[i+1].color.v.c[1];
1133
 
        double b1 = gr->vector.stops[i+1].color.v.c[2];
1134
 
        double a1 = gr->vector.stops[i+1].opacity;
1135
 
        double o0 = gr->vector.stops[i].offset * (NCOLORS-1);
1136
 
        double o1 = gr->vector.stops[i + 1].offset * (NCOLORS-1);
1137
 
        unsigned int ob = (unsigned int) floor(o0+.5); // These are the first and last element that might be affected by this interval.
1138
 
        unsigned int oe = (unsigned int) floor(o1+.5); // These need to be computed the same to ensure that ob will be covered by the next interval if oe==ob
1139
 
 
1140
 
        if (oe == ob) {
1141
 
            // Simple case, this interval starts and stops within one cell
1142
 
            // The contribution of this interval is:
1143
 
            //    (o1-o0)*(c(o0)+c(o1))/2
1144
 
            //  = (o1-o0)*(c0+c1)/2
1145
 
            double dt = 0.5*(o1-o0);
1146
 
            remainder[0] += dt*(r0 + r1);
1147
 
            remainder[1] += dt*(g0 + g1);
1148
 
            remainder[2] += dt*(b0 + b1);
1149
 
            remainder[3] += dt*(a0 + a1);
1150
 
        } else {
1151
 
            // First compute colors for the cells which are fully covered by the current interval.
1152
 
            // The prefiltered values are equal to the midpoint of each cell here.
1153
 
            //  f = (j-o0)/(o1-o0)
1154
 
            //    = j*(1/(o1-o0)) - o0/(o1-o0)
1155
 
            double f = (ob-o0) / (o1-o0);
1156
 
            double df = 1. / (o1-o0);
1157
 
            for (unsigned int j = ob+1; j < oe; j++) {
1158
 
                f += df;
1159
 
                gr->color[4 * j + 0] = (unsigned char) floor(255*(r0 + f*(r1-r0)) + .5);
1160
 
                gr->color[4 * j + 1] = (unsigned char) floor(255*(g0 + f*(g1-g0)) + .5);
1161
 
                gr->color[4 * j + 2] = (unsigned char) floor(255*(b0 + f*(b1-b0)) + .5);
1162
 
                gr->color[4 * j + 3] = (unsigned char) floor(255*(a0 + f*(a1-a0)) + .5);
1163
 
            }
1164
 
 
1165
 
            // Now handle the beginning
1166
 
            // The contribution of the last point is already in remainder.
1167
 
            // The contribution of this point is:
1168
 
            //    (ob+.5-o0)*(c(o0)+c(ob+.5))/2
1169
 
            //  = (ob+.5-o0)*c((o0+ob+.5)/2)
1170
 
            //  = (ob+.5-o0)*(c0+((o0+ob+.5)/2-o0)*df*(c1-c0))
1171
 
            //  = (ob+.5-o0)*(c0+(ob+.5-o0)*df*(c1-c0)/2)
1172
 
            double dt = ob+.5-o0;
1173
 
            f = 0.5*dt*df;
1174
 
            if (ob==0 && gr->spread==SP_GRADIENT_SPREAD_REFLECT) {
1175
 
                // The first half of the first cell is just a mirror image of the second half, so simply multiply it by 2.
1176
 
                gr->color[4 * ob + 0] = (unsigned char) floor(2*255*(remainder[0] + dt*(r0 + f*(r1-r0))) + .5);
1177
 
                gr->color[4 * ob + 1] = (unsigned char) floor(2*255*(remainder[1] + dt*(g0 + f*(g1-g0))) + .5);
1178
 
                gr->color[4 * ob + 2] = (unsigned char) floor(2*255*(remainder[2] + dt*(b0 + f*(b1-b0))) + .5);
1179
 
                gr->color[4 * ob + 3] = (unsigned char) floor(2*255*(remainder[3] + dt*(a0 + f*(a1-a0))) + .5);
1180
 
            } else if (ob==0 && gr->spread==SP_GRADIENT_SPREAD_REPEAT) {
1181
 
                // The first cell is the same as the last cell, so save whatever is in the second half here and deal with the rest later.
1182
 
                remainder_for_end[0] = remainder[0] + dt*(r0 + f*(r1-r0));
1183
 
                remainder_for_end[1] = remainder[1] + dt*(g0 + f*(g1-g0));
1184
 
                remainder_for_end[2] = remainder[2] + dt*(b0 + f*(b1-b0));
1185
 
                remainder_for_end[3] = remainder[3] + dt*(a0 + f*(a1-a0));
1186
 
            } else {
1187
 
                // The first half of the cell was already in remainder.
1188
 
                gr->color[4 * ob + 0] = (unsigned char) floor(255*(remainder[0] + dt*(r0 + f*(r1-r0))) + .5);
1189
 
                gr->color[4 * ob + 1] = (unsigned char) floor(255*(remainder[1] + dt*(g0 + f*(g1-g0))) + .5);
1190
 
                gr->color[4 * ob + 2] = (unsigned char) floor(255*(remainder[2] + dt*(b0 + f*(b1-b0))) + .5);
1191
 
                gr->color[4 * ob + 3] = (unsigned char) floor(255*(remainder[3] + dt*(a0 + f*(a1-a0))) + .5);
1192
 
            }
1193
 
 
1194
 
            // Now handle the end, which should end up in remainder
1195
 
            // The contribution of this point is:
1196
 
            //    (o1-oe+.5)*(c(o1)+c(oe-.5))/2
1197
 
            //  = (o1-oe+.5)*c((o1+oe-.5)/2)
1198
 
            //  = (o1-oe+.5)*(c0+((o1+oe-.5)/2-o0)*df*(c1-c0))
1199
 
            dt = o1-oe+.5;
1200
 
            f = (0.5*(o1+oe-.5)-o0)*df;
1201
 
            remainder[0] = dt*(r0 + f*(r1-r0));
1202
 
            remainder[1] = dt*(g0 + f*(g1-g0));
1203
 
            remainder[2] = dt*(b0 + f*(b1-b0));
1204
 
            remainder[3] = dt*(a0 + f*(a1-a0));
1205
 
        }
1206
 
    }
1207
 
    switch(gr->spread) {
1208
 
    case SP_GRADIENT_SPREAD_PAD:
1209
 
        gr->color[4 * (NCOLORS-1) + 0] = (unsigned char) floor(255*(remainder[0]+remainder_for_end[0]) + .5);
1210
 
        gr->color[4 * (NCOLORS-1) + 1] = (unsigned char) floor(255*(remainder[1]+remainder_for_end[1]) + .5);
1211
 
        gr->color[4 * (NCOLORS-1) + 2] = (unsigned char) floor(255*(remainder[2]+remainder_for_end[2]) + .5);
1212
 
        gr->color[4 * (NCOLORS-1) + 3] = (unsigned char) floor(255*(remainder[3]+remainder_for_end[3]) + .5);
1213
 
        break;
1214
 
    case SP_GRADIENT_SPREAD_REFLECT:
1215
 
        // The second half is the same as the first half, so multiply by 2.
1216
 
        gr->color[4 * (NCOLORS-1) + 0] = (unsigned char) floor(2*255*remainder[0] + .5);
1217
 
        gr->color[4 * (NCOLORS-1) + 1] = (unsigned char) floor(2*255*remainder[1] + .5);
1218
 
        gr->color[4 * (NCOLORS-1) + 2] = (unsigned char) floor(2*255*remainder[2] + .5);
1219
 
        gr->color[4 * (NCOLORS-1) + 3] = (unsigned char) floor(2*255*remainder[3] + .5);
1220
 
        break;
1221
 
    case SP_GRADIENT_SPREAD_REPEAT:
1222
 
        // The second half is the same as the second half of the first cell (which was saved in remainder_for_end).
1223
 
        gr->color[0] = gr->color[4 * (NCOLORS-1) + 0] = (unsigned char) floor(255*(remainder[0]+remainder_for_end[0]) + .5);
1224
 
        gr->color[1] = gr->color[4 * (NCOLORS-1) + 1] = (unsigned char) floor(255*(remainder[1]+remainder_for_end[1]) + .5);
1225
 
        gr->color[2] = gr->color[4 * (NCOLORS-1) + 2] = (unsigned char) floor(255*(remainder[2]+remainder_for_end[2]) + .5);
1226
 
        gr->color[3] = gr->color[4 * (NCOLORS-1) + 3] = (unsigned char) floor(255*(remainder[3]+remainder_for_end[3]) + .5);
1227
 
        break;
1228
 
    }
1229
 
}
1230
 
 
1231
 
/**
1232
 
 * Renders gradient vector to buffer as line.
1233
 
 *
1234
 
 * RGB buffer background should be set up beforehand.
1235
 
 *
1236
 
 * @param len,width,height,rowstride Buffer parameters (1 or 2 dimensional).
1237
 
 * @param span Full integer width of requested gradient.
1238
 
 * @param pos Buffer starting position in span.
1239
 
 */
1240
 
static void
1241
 
sp_gradient_render_vector_line_rgba(SPGradient *const gradient, guchar *buf,
1242
 
                                    gint const len, gint const pos, gint const span)
1243
 
{
1244
 
    g_return_if_fail(gradient != NULL);
1245
 
    g_return_if_fail(SP_IS_GRADIENT(gradient));
1246
 
    g_return_if_fail(buf != NULL);
1247
 
    g_return_if_fail(len > 0);
1248
 
    g_return_if_fail(pos >= 0);
1249
 
    g_return_if_fail(pos + len <= span);
1250
 
    g_return_if_fail(span > 0);
1251
 
 
1252
 
    if (!gradient->color) {
1253
 
        sp_gradient_ensure_colors(gradient);
1254
 
    }
1255
 
 
1256
 
    gint idx = (pos * 1024 << 8) / span;
1257
 
    gint didx = (1024 << 8) / span;
1258
 
 
1259
 
    for (gint x = 0; x < len; x++) {
1260
 
        /// \todo Can this be done with 4 byte copies?
1261
 
        *buf++ = gradient->color[4 * (idx >> 8)];
1262
 
        *buf++ = gradient->color[4 * (idx >> 8) + 1];
1263
 
        *buf++ = gradient->color[4 * (idx >> 8) + 2];
1264
 
        *buf++ = gradient->color[4 * (idx >> 8) + 3];
1265
 
        idx += didx;
1266
 
    }
1267
 
}
1268
 
 
1269
 
/**
1270
 
 * Render rectangular RGBA area from gradient vector.
1271
 
 */
1272
 
void
1273
 
sp_gradient_render_vector_block_rgba(SPGradient *const gradient, guchar *buf,
1274
 
                                     gint const width, gint const height, gint const rowstride,
1275
 
                                     gint const pos, gint const span, bool const horizontal)
1276
 
{
1277
 
    g_return_if_fail(gradient != NULL);
1278
 
    g_return_if_fail(SP_IS_GRADIENT(gradient));
1279
 
    g_return_if_fail(buf != NULL);
1280
 
    g_return_if_fail(width > 0);
1281
 
    g_return_if_fail(height > 0);
1282
 
    g_return_if_fail(pos >= 0);
1283
 
    g_return_if_fail((horizontal && (pos + width <= span)) || (!horizontal && (pos + height <= span)));
1284
 
    g_return_if_fail(span > 0);
1285
 
 
1286
 
    if (horizontal) {
1287
 
        sp_gradient_render_vector_line_rgba(gradient, buf, width, pos, span);
1288
 
        for (gint y = 1; y < height; y++) {
1289
 
            memcpy(buf + y * rowstride, buf, 4 * width);
1290
 
        }
1291
 
    } else {
1292
 
        guchar *tmp = (guchar *)alloca(4 * height);
1293
 
        sp_gradient_render_vector_line_rgba(gradient, tmp, height, pos, span);
1294
 
        for (gint y = 0; y < height; y++) {
1295
 
            guchar *b = buf + y * rowstride;
1296
 
            for (gint x = 0; x < width; x++) {
1297
 
                *b++ = tmp[0];
1298
 
                *b++ = tmp[1];
1299
 
                *b++ = tmp[2];
1300
 
                *b++ = tmp[3];
1301
 
            }
1302
 
            tmp += 4;
1303
 
        }
1304
 
    }
1305
 
}
1306
 
 
1307
 
/**
1308
 
 * Render rectangular RGB area from gradient vector.
1309
 
 */
1310
 
void
1311
 
sp_gradient_render_vector_block_rgb(SPGradient *gradient, guchar *buf,
1312
 
                                    gint const width, gint const height, gint const /*rowstride*/,
1313
 
                                    gint const pos, gint const span, bool const horizontal)
1314
 
{
1315
 
    g_return_if_fail(gradient != NULL);
1316
 
    g_return_if_fail(SP_IS_GRADIENT(gradient));
1317
 
    g_return_if_fail(buf != NULL);
1318
 
    g_return_if_fail(width > 0);
1319
 
    g_return_if_fail(height > 0);
1320
 
    g_return_if_fail(pos >= 0);
1321
 
    g_return_if_fail((horizontal && (pos + width <= span)) || (!horizontal && (pos + height <= span)));
1322
 
    g_return_if_fail(span > 0);
1323
 
 
1324
 
    if (horizontal) {
1325
 
        guchar *tmp = (guchar*)alloca(4 * width);
1326
 
        sp_gradient_render_vector_line_rgba(gradient, tmp, width, pos, span);
1327
 
        for (gint y = 0; y < height; y++) {
1328
 
            guchar *t = tmp;
1329
 
            for (gint x = 0; x < width; x++) {
1330
 
                gint a = t[3];
1331
 
                gint fc = (t[0] - buf[0]) * a;
1332
 
                buf[0] = buf[0] + ((fc + (fc >> 8) + 0x80) >> 8);
1333
 
                fc = (t[1] - buf[1]) * a;
1334
 
                buf[1] = buf[1] + ((fc + (fc >> 8) + 0x80) >> 8);
1335
 
                fc = (t[2] - buf[2]) * a;
1336
 
                buf[2] = buf[2] + ((fc + (fc >> 8) + 0x80) >> 8);
1337
 
                buf += 3;
1338
 
                t += 4;
1339
 
            }
1340
 
        }
1341
 
    } else {
1342
 
        guchar *tmp = (guchar*)alloca(4 * height);
1343
 
        sp_gradient_render_vector_line_rgba(gradient, tmp, height, pos, span);
1344
 
        for (gint y = 0; y < height; y++) {
1345
 
            guchar *t = tmp + 4 * y;
1346
 
            for (gint x = 0; x < width; x++) {
1347
 
                gint a = t[3];
1348
 
                gint fc = (t[0] - buf[0]) * a;
1349
 
                buf[0] = buf[0] + ((fc + (fc >> 8) + 0x80) >> 8);
1350
 
                fc = (t[1] - buf[1]) * a;
1351
 
                buf[1] = buf[1] + ((fc + (fc >> 8) + 0x80) >> 8);
1352
 
                fc = (t[2] - buf[2]) * a;
1353
 
                buf[2] = buf[2] + ((fc + (fc >> 8) + 0x80) >> 8);
1354
 
            }
1355
 
        }
1356
 
    }
1357
 
}
1358
 
 
1359
 
Geom::Matrix
1360
 
sp_gradient_get_g2d_matrix(SPGradient const *gr, Geom::Matrix const &ctm, Geom::Rect const &bbox)
1361
 
{
1362
 
    if (gr->units == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) {
 
1096
            gstop.color = vector.stops.back().color;
 
1097
            gstop.opacity = vector.stops.back().opacity;
 
1098
            vector.stops.push_back(gstop);
 
1099
        }
 
1100
    }
 
1101
 
 
1102
    vector.built = true;
 
1103
}
 
1104
 
 
1105
Geom::Affine
 
1106
sp_gradient_get_g2d_matrix(SPGradient const *gr, Geom::Affine const &ctm, Geom::Rect const &bbox)
 
1107
{
 
1108
    if (gr->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) {
1363
1109
        return ( Geom::Scale(bbox.dimensions())
1364
1110
                 * Geom::Translate(bbox.min())
1365
 
                 * Geom::Matrix(ctm) );
 
1111
                 * Geom::Affine(ctm) );
1366
1112
    } else {
1367
1113
        return ctm;
1368
1114
    }
1369
1115
}
1370
1116
 
1371
 
Geom::Matrix
1372
 
sp_gradient_get_gs2d_matrix(SPGradient const *gr, Geom::Matrix const &ctm, Geom::Rect const &bbox)
 
1117
Geom::Affine
 
1118
sp_gradient_get_gs2d_matrix(SPGradient const *gr, Geom::Affine const &ctm, Geom::Rect const &bbox)
1373
1119
{
1374
 
    if (gr->units == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) {
 
1120
    if (gr->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) {
1375
1121
        return ( gr->gradientTransform
1376
1122
                 * Geom::Scale(bbox.dimensions())
1377
1123
                 * Geom::Translate(bbox.min())
1378
 
                 * Geom::Matrix(ctm) );
 
1124
                 * Geom::Affine(ctm) );
1379
1125
    } else {
1380
1126
        return gr->gradientTransform * ctm;
1381
1127
    }
1382
1128
}
1383
1129
 
1384
1130
void
1385
 
sp_gradient_set_gs2d_matrix(SPGradient *gr, Geom::Matrix const &ctm,
1386
 
                            Geom::Rect const &bbox, Geom::Matrix const &gs2d)
 
1131
sp_gradient_set_gs2d_matrix(SPGradient *gr, Geom::Affine const &ctm,
 
1132
                            Geom::Rect const &bbox, Geom::Affine const &gs2d)
1387
1133
{
1388
1134
    gr->gradientTransform = gs2d * ctm.inverse();
1389
 
    if (gr->units == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX ) {
 
1135
    if (gr->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX ) {
1390
1136
        gr->gradientTransform = ( gr->gradientTransform
1391
1137
                                  * Geom::Translate(-bbox.min())
1392
1138
                                  * Geom::Scale(bbox.dimensions()).inverse() );
1393
1139
    }
1394
1140
    gr->gradientTransform_set = TRUE;
1395
1141
 
1396
 
    SP_OBJECT(gr)->requestModified(SP_OBJECT_MODIFIED_FLAG);
 
1142
    gr->requestModified(SP_OBJECT_MODIFIED_FLAG);
1397
1143
}
1398
1144
 
1399
1145
/*
1400
1146
 * Linear Gradient
1401
1147
 */
1402
1148
 
1403
 
class SPLGPainter;
1404
 
 
1405
 
/// A context with linear gradient, painter, and gradient renderer.
1406
 
struct SPLGPainter {
1407
 
    SPPainter painter;
1408
 
    SPLinearGradient *lg;
1409
 
 
1410
 
    NRLGradientRenderer lgr;
1411
 
};
1412
 
 
1413
1149
static void sp_lineargradient_class_init(SPLinearGradientClass *klass);
1414
1150
static void sp_lineargradient_init(SPLinearGradient *lg);
1415
1151
 
1419
1155
static void sp_lineargradient_set(SPObject *object, unsigned key, gchar const *value);
1420
1156
static Inkscape::XML::Node *sp_lineargradient_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr,
1421
1157
                                                    guint flags);
1422
 
 
1423
 
static SPPainter *sp_lineargradient_painter_new(SPPaintServer *ps,
1424
 
                                                Geom::Matrix const &full_transform,
1425
 
                                                Geom::Matrix const &parent_transform,
1426
 
                                                NRRect const *bbox);
1427
 
static void sp_lineargradient_painter_free(SPPaintServer *ps, SPPainter *painter);
1428
 
 
1429
 
static void sp_lg_fill(SPPainter *painter, NRPixBlock *pb);
 
1158
static cairo_pattern_t *sp_lineargradient_create_pattern(SPPaintServer *ps, cairo_t *ct, Geom::OptRect const &bbox, double opacity);
1430
1159
 
1431
1160
static SPGradientClass *lg_parent_class;
1432
1161
 
1467
1196
    sp_object_class->set = sp_lineargradient_set;
1468
1197
    sp_object_class->write = sp_lineargradient_write;
1469
1198
 
1470
 
    ps_class->painter_new = sp_lineargradient_painter_new;
1471
 
    ps_class->painter_free = sp_lineargradient_painter_free;
 
1199
    ps_class->pattern_new = sp_lineargradient_create_pattern;
1472
1200
}
1473
1201
 
1474
1202
/**
1492
1220
    if (((SPObjectClass *) lg_parent_class)->build)
1493
1221
        (* ((SPObjectClass *) lg_parent_class)->build)(object, document, repr);
1494
1222
 
1495
 
    sp_object_read_attr(object, "x1");
1496
 
    sp_object_read_attr(object, "y1");
1497
 
    sp_object_read_attr(object, "x2");
1498
 
    sp_object_read_attr(object, "y2");
 
1223
    object->readAttr( "x1" );
 
1224
    object->readAttr( "y1" );
 
1225
    object->readAttr( "x2" );
 
1226
    object->readAttr( "y2" );
1499
1227
}
1500
1228
 
1501
1229
/**
1558
1286
}
1559
1287
 
1560
1288
/**
1561
 
 * Create linear gradient context.
1562
 
 *
1563
 
 * Basically we have to deal with transformations
1564
 
 *
1565
 
 * 1) color2norm - maps point in (0,NCOLORS) vector to (0,1) vector
1566
 
 * 2) norm2pos - maps (0,1) vector to x1,y1 - x2,y2
1567
 
 * 2) gradientTransform
1568
 
 * 3) bbox2user
1569
 
 * 4) ctm == userspace to pixel grid
1570
 
 *
1571
 
 * See also (*) in sp-pattern about why we may need parent_transform.
1572
 
 *
1573
 
 * \todo (point 1 above) fixme: I do not know how to deal with start > 0
1574
 
 * and end < 1.
1575
 
 */
1576
 
static SPPainter *
1577
 
sp_lineargradient_painter_new(SPPaintServer *ps,
1578
 
                              Geom::Matrix const &full_transform,
1579
 
                              Geom::Matrix const &/*parent_transform*/,
1580
 
                              NRRect const *bbox)
1581
 
{
1582
 
    SPLinearGradient *lg = SP_LINEARGRADIENT(ps);
1583
 
    SPGradient *gr = SP_GRADIENT(ps);
1584
 
 
1585
 
    if (!gr->color) sp_gradient_ensure_colors(gr);
1586
 
 
1587
 
    SPLGPainter *lgp = g_new(SPLGPainter, 1);
1588
 
 
1589
 
    lgp->painter.type = SP_PAINTER_IND;
1590
 
    lgp->painter.fill = sp_lg_fill;
1591
 
 
1592
 
    lgp->lg = lg;
1593
 
 
1594
 
    /** \todo
1595
 
     * Technically speaking, we map NCOLORS on line [start,end] onto line
1596
 
     * [0,1].  I almost think we should fill color array start and end in
1597
 
     * that case. The alternative would be to leave these just empty garbage
1598
 
     * or something similar. Originally I had 1023.9999 here - not sure
1599
 
     * whether we have really to cut out ceil int (Lauris).
1600
 
     */
1601
 
    Geom::Matrix color2norm(Geom::identity());
1602
 
    Geom::Matrix color2px;
1603
 
    if (gr->units == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) {
1604
 
        Geom::Matrix norm2pos(Geom::identity());
1605
 
 
1606
 
        /* BBox to user coordinate system */
1607
 
        Geom::Matrix bbox2user(bbox->x1 - bbox->x0, 0, 0, bbox->y1 - bbox->y0, bbox->x0, bbox->y0);
1608
 
 
1609
 
        Geom::Matrix color2pos = color2norm * norm2pos;
1610
 
        Geom::Matrix color2tpos = color2pos * gr->gradientTransform;
1611
 
        Geom::Matrix color2user = color2tpos * bbox2user;
1612
 
        color2px = color2user * full_transform;
1613
 
 
1614
 
    } else {
1615
 
        /* Problem: What to do, if we have mixed lengths and percentages? */
1616
 
        /* Currently we do ignore percentages at all, but that is not good (lauris) */
1617
 
 
1618
 
        Geom::Matrix norm2pos(Geom::identity());
1619
 
        Geom::Matrix color2pos = color2norm * norm2pos;
1620
 
        Geom::Matrix color2tpos = color2pos * gr->gradientTransform;
1621
 
        color2px = color2tpos * full_transform;
1622
 
 
1623
 
    }
1624
 
    // TODO: remove color2px_nr after converting to 2geom
1625
 
    NR::Matrix color2px_nr = from_2geom(color2px);
1626
 
    nr_lgradient_renderer_setup(&lgp->lgr, gr->color, sp_gradient_get_spread(gr), &color2px_nr,
1627
 
                                lg->x1.computed, lg->y1.computed,
1628
 
                                lg->x2.computed, lg->y2.computed);
1629
 
 
1630
 
    return (SPPainter *) lgp;
1631
 
}
1632
 
 
1633
 
static void
1634
 
sp_lineargradient_painter_free(SPPaintServer */*ps*/, SPPainter *painter)
1635
 
{
1636
 
    g_free(painter);
1637
 
}
1638
 
 
1639
 
/**
1640
1289
 * Directly set properties of linear gradient and request modified.
1641
1290
 */
1642
1291
void
1653
1302
    lg->x2.set(SVGLength::NONE, x2, x2);
1654
1303
    lg->y2.set(SVGLength::NONE, y2, y2);
1655
1304
 
1656
 
    SP_OBJECT(lg)->requestModified(SP_OBJECT_MODIFIED_FLAG);
1657
 
}
1658
 
 
1659
 
/**
1660
 
 * Callback when linear gradient object is rendered.
1661
 
 */
1662
 
static void
1663
 
sp_lg_fill(SPPainter *painter, NRPixBlock *pb)
1664
 
{
1665
 
    SPLGPainter *lgp = (SPLGPainter *) painter;
1666
 
 
1667
 
    if (lgp->lg->color == NULL) {
1668
 
        sp_gradient_ensure_colors (lgp->lg);
1669
 
        lgp->lgr.vector = lgp->lg->color;
1670
 
    }
1671
 
 
1672
 
    nr_render((NRRenderer *) &lgp->lgr, pb, NULL);
 
1305
    lg->requestModified(SP_OBJECT_MODIFIED_FLAG);
1673
1306
}
1674
1307
 
1675
1308
/*
1676
1309
 * Radial Gradient
1677
1310
 */
1678
1311
 
1679
 
class SPRGPainter;
1680
 
 
1681
 
/// A context with radial gradient, painter, and gradient renderer.
1682
 
struct SPRGPainter {
1683
 
    SPPainter painter;
1684
 
    SPRadialGradient *rg;
1685
 
    NRRGradientRenderer rgr;
1686
 
};
1687
 
 
1688
1312
static void sp_radialgradient_class_init(SPRadialGradientClass *klass);
1689
1313
static void sp_radialgradient_init(SPRadialGradient *rg);
1690
1314
 
1694
1318
static void sp_radialgradient_set(SPObject *object, unsigned key, gchar const *value);
1695
1319
static Inkscape::XML::Node *sp_radialgradient_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr,
1696
1320
                                                    guint flags);
1697
 
 
1698
 
static SPPainter *sp_radialgradient_painter_new(SPPaintServer *ps,
1699
 
                                                Geom::Matrix const &full_transform,
1700
 
                                                Geom::Matrix const &parent_transform,
1701
 
                                                NRRect const *bbox);
1702
 
static void sp_radialgradient_painter_free(SPPaintServer *ps, SPPainter *painter);
1703
 
 
1704
 
static void sp_rg_fill(SPPainter *painter, NRPixBlock *pb);
 
1321
static cairo_pattern_t *sp_radialgradient_create_pattern(SPPaintServer *ps, cairo_t *ct, Geom::OptRect const &bbox, double opacity);
1705
1322
 
1706
1323
static SPGradientClass *rg_parent_class;
1707
1324
 
1742
1359
    sp_object_class->set = sp_radialgradient_set;
1743
1360
    sp_object_class->write = sp_radialgradient_write;
1744
1361
 
1745
 
    ps_class->painter_new = sp_radialgradient_painter_new;
1746
 
    ps_class->painter_free = sp_radialgradient_painter_free;
 
1362
    ps_class->pattern_new = sp_radialgradient_create_pattern;
1747
1363
}
1748
1364
 
1749
1365
/**
1768
1384
    if (((SPObjectClass *) rg_parent_class)->build)
1769
1385
        (* ((SPObjectClass *) rg_parent_class)->build)(object, document, repr);
1770
1386
 
1771
 
    sp_object_read_attr(object, "cx");
1772
 
    sp_object_read_attr(object, "cy");
1773
 
    sp_object_read_attr(object, "r");
1774
 
    sp_object_read_attr(object, "fx");
1775
 
    sp_object_read_attr(object, "fy");
 
1387
    object->readAttr( "cx" );
 
1388
    object->readAttr( "cy" );
 
1389
    object->readAttr( "r" );
 
1390
    object->readAttr( "fx" );
 
1391
    object->readAttr( "fy" );
1776
1392
}
1777
1393
 
1778
1394
/**
1854
1470
}
1855
1471
 
1856
1472
/**
1857
 
 * Create radial gradient context.
1858
 
 */
1859
 
static SPPainter *
1860
 
sp_radialgradient_painter_new(SPPaintServer *ps,
1861
 
                              Geom::Matrix const &full_transform,
1862
 
                              Geom::Matrix const &/*parent_transform*/,
1863
 
                              NRRect const *bbox)
1864
 
{
1865
 
    SPRadialGradient *rg = SP_RADIALGRADIENT(ps);
1866
 
    SPGradient *gr = SP_GRADIENT(ps);
1867
 
 
1868
 
    if (!gr->color) sp_gradient_ensure_colors(gr);
1869
 
 
1870
 
    SPRGPainter *rgp = g_new(SPRGPainter, 1);
1871
 
 
1872
 
    rgp->painter.type = SP_PAINTER_IND;
1873
 
    rgp->painter.fill = sp_rg_fill;
1874
 
 
1875
 
    rgp->rg = rg;
1876
 
 
1877
 
    Geom::Matrix gs2px;
1878
 
 
1879
 
    if (gr->units == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) {
1880
 
        /** \todo
1881
 
         * fixme: We may try to normalize here too, look at
1882
 
         * linearGradient (Lauris)
1883
 
         */
1884
 
 
1885
 
        /* BBox to user coordinate system */
1886
 
        Geom::Matrix bbox2user(bbox->x1 - bbox->x0, 0, 0, bbox->y1 - bbox->y0, bbox->x0, bbox->y0);
1887
 
 
1888
 
        Geom::Matrix gs2user = gr->gradientTransform * bbox2user;
1889
 
 
1890
 
        gs2px = gs2user * full_transform;
1891
 
    } else {
1892
 
        /** \todo
1893
 
         * Problem: What to do, if we have mixed lengths and percentages?
1894
 
         * Currently we do ignore percentages at all, but that is not
1895
 
         * good (lauris)
1896
 
         */
1897
 
 
1898
 
        gs2px = gr->gradientTransform * full_transform;
1899
 
    }
1900
 
    // TODO: remove gs2px_nr after converting to 2geom
1901
 
    NR::Matrix gs2px_nr = from_2geom(gs2px);
1902
 
    nr_rgradient_renderer_setup(&rgp->rgr, gr->color, sp_gradient_get_spread(gr),
1903
 
                                &gs2px_nr,
1904
 
                                rg->cx.computed, rg->cy.computed,
1905
 
                                rg->fx.computed, rg->fy.computed,
1906
 
                                rg->r.computed);
1907
 
 
1908
 
    return (SPPainter *) rgp;
1909
 
}
1910
 
 
1911
 
static void
1912
 
sp_radialgradient_painter_free(SPPaintServer */*ps*/, SPPainter *painter)
1913
 
{
1914
 
    g_free(painter);
1915
 
}
1916
 
 
1917
 
/**
1918
1473
 * Directly set properties of radial gradient and request modified.
1919
1474
 */
1920
1475
void
1931
1486
    rg->fy.set(SVGLength::NONE, fy, fy);
1932
1487
    rg->r.set(SVGLength::NONE, r, r);
1933
1488
 
1934
 
    SP_OBJECT(rg)->requestModified(SP_OBJECT_MODIFIED_FLAG);
 
1489
    rg->requestModified(SP_OBJECT_MODIFIED_FLAG);
1935
1490
}
1936
1491
 
1937
 
/**
1938
 
 * Callback when radial gradient object is rendered.
1939
 
 */
 
1492
/* CAIRO RENDERING STUFF */
 
1493
 
1940
1494
static void
1941
 
sp_rg_fill(SPPainter *painter, NRPixBlock *pb)
1942
 
{
1943
 
    SPRGPainter *rgp = (SPRGPainter *) painter;
1944
 
 
1945
 
    if (rgp->rg->color == NULL) {
1946
 
        sp_gradient_ensure_colors (rgp->rg);
1947
 
        rgp->rgr.vector = rgp->rg->color;
1948
 
    }
1949
 
 
1950
 
    nr_render((NRRenderer *) &rgp->rgr, pb, NULL);
 
1495
sp_gradient_pattern_common_setup(cairo_pattern_t *cp,
 
1496
                                 SPGradient *gr,
 
1497
                                 Geom::OptRect const &bbox,
 
1498
                                 double opacity)
 
1499
{
 
1500
    // set spread type
 
1501
    switch (gr->getSpread()) {
 
1502
    case SP_GRADIENT_SPREAD_REFLECT:
 
1503
        cairo_pattern_set_extend(cp, CAIRO_EXTEND_REFLECT);
 
1504
        break;
 
1505
    case SP_GRADIENT_SPREAD_REPEAT:
 
1506
        cairo_pattern_set_extend(cp, CAIRO_EXTEND_REPEAT);
 
1507
        break;
 
1508
    case SP_GRADIENT_SPREAD_PAD:
 
1509
    default:
 
1510
        cairo_pattern_set_extend(cp, CAIRO_EXTEND_PAD);
 
1511
        break;
 
1512
    }
 
1513
 
 
1514
    // add stops
 
1515
    for (std::vector<SPGradientStop>::iterator i = gr->vector.stops.begin();
 
1516
         i != gr->vector.stops.end(); ++i)
 
1517
    {
 
1518
        // multiply stop opacity by paint opacity
 
1519
        cairo_pattern_add_color_stop_rgba(cp, i->offset,
 
1520
            i->color.v.c[0], i->color.v.c[1], i->color.v.c[2], i->opacity * opacity);
 
1521
    }
 
1522
 
 
1523
    // set pattern matrix
 
1524
    Geom::Affine gs2user = gr->gradientTransform;
 
1525
    if (gr->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) {
 
1526
        Geom::Affine bbox2user(bbox->width(), 0, 0, bbox->height(), bbox->left(), bbox->top());
 
1527
        gs2user *= bbox2user;
 
1528
    }
 
1529
    ink_cairo_pattern_set_matrix(cp, gs2user.inverse());
 
1530
}
 
1531
 
 
1532
static cairo_pattern_t *
 
1533
sp_radialgradient_create_pattern(SPPaintServer *ps,
 
1534
                                 cairo_t */* ct */,
 
1535
                                 Geom::OptRect const &bbox,
 
1536
                                 double opacity)
 
1537
{
 
1538
    SPRadialGradient *rg = SP_RADIALGRADIENT(ps);
 
1539
    SPGradient *gr = SP_GRADIENT(ps);
 
1540
 
 
1541
    gr->ensureVector();
 
1542
 
 
1543
    cairo_pattern_t *cp = cairo_pattern_create_radial(
 
1544
        rg->fx.computed, rg->fy.computed, 0,
 
1545
        rg->cx.computed, rg->cy.computed, rg->r.computed);
 
1546
 
 
1547
    sp_gradient_pattern_common_setup(cp, gr, bbox, opacity);
 
1548
 
 
1549
    return cp;
 
1550
}
 
1551
 
 
1552
static cairo_pattern_t *
 
1553
sp_lineargradient_create_pattern(SPPaintServer *ps,
 
1554
                                 cairo_t */* ct */,
 
1555
                                 Geom::OptRect const &bbox,
 
1556
                                 double opacity)
 
1557
{
 
1558
    SPLinearGradient *lg = SP_LINEARGRADIENT(ps);
 
1559
    SPGradient *gr = SP_GRADIENT(ps);
 
1560
 
 
1561
    gr->ensureVector();
 
1562
 
 
1563
    cairo_pattern_t *cp = cairo_pattern_create_linear(
 
1564
        lg->x1.computed, lg->y1.computed,
 
1565
        lg->x2.computed, lg->y2.computed);
 
1566
 
 
1567
    sp_gradient_pattern_common_setup(cp, gr, bbox, opacity);
 
1568
 
 
1569
    return cp;
 
1570
}
 
1571
 
 
1572
cairo_pattern_t *
 
1573
sp_gradient_create_preview_pattern(SPGradient *gr, double width)
 
1574
{
 
1575
    gr->ensureVector();
 
1576
 
 
1577
    cairo_pattern_t *pat = cairo_pattern_create_linear(0, 0, width, 0);
 
1578
 
 
1579
    for (std::vector<SPGradientStop>::iterator i = gr->vector.stops.begin();
 
1580
         i != gr->vector.stops.end(); ++i)
 
1581
    {
 
1582
        cairo_pattern_add_color_stop_rgba(pat, i->offset,
 
1583
            i->color.v.c[0], i->color.v.c[1], i->color.v.c[2], i->opacity);
 
1584
    }
 
1585
 
 
1586
    return pat;
1951
1587
}
1952
1588
 
1953
1589
/*
1959
1595
  fill-column:99
1960
1596
  End:
1961
1597
*/
1962
 
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :
 
1598
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :