sp-gradient.cpp revision d616708f7747571c94108bb2e61a70d2da3768bd
#define __SP_GRADIENT_C__
/** \file
* SPGradient, SPStop, SPLinearGradient, SPRadialGradient.
*/
/*
* Authors:
* Lauris Kaplinski <lauris@kaplinski.com>
* bulia byak <buliabyak@users.sf.net>
* Jasper van de Gronde <th.v.d.gronde@hccnet.nl>
*
* Copyright (C) 1999-2002 Lauris Kaplinski
* Copyright (C) 2000-2001 Ximian, Inc.
* Copyright (C) 2004 David Turner
* Copyright (C) 2009 Jasper van de Gronde
*
* Released under GNU GPL, read the file 'COPYING' for more information
*
*/
#define noSP_GRADIENT_VERBOSE
#include <cstring>
#include <string>
#include "display/cairo-utils.h"
#include "svg/svg-color.h"
#include "svg/css-ostringstream.h"
#include "attributes.h"
#include "document-private.h"
#include "gradient-chemistry.h"
#include "sp-gradient-reference.h"
#include "sp-linear-gradient.h"
#include "sp-radial-gradient.h"
#include "sp-stop.h"
#include "streq.h"
#include "uri.h"
#define SP_MACROS_SILENT
#include "macros.h"
/// Has to be power of 2
#define NCOLORS NR_GRADIENT_VECTOR_LENGTH
static Inkscape::XML::Node *sp_stop_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr, guint flags);
static SPObjectClass *stop_parent_class;
/**
* Registers SPStop class and returns its type.
*/
{
if (!type) {
sizeof(SPStopClass),
sizeof(SPStop),
16,
NULL, /* value_table */
};
}
return type;
}
/**
* Callback to initialize SPStop vtable.
*/
{
}
/**
* Callback to initialize SPStop object.
*/
static void
{
stop->currentColor = false;
}
/**
* Virtual build: set stop attributes from its associated XML node.
*/
{
}
/**
* Virtual set: set attribute to value.
*/
static void
{
switch (key) {
case SP_ATTR_STYLE: {
/** \todo
* fixme: We are reading simple values 3 times during build (Lauris).
* \par
* We need presentation attributes etc.
* \par
* remove the hackish "style reading" from here: see comments in
* sp_object_get_style_property about the bugs in our current
* approach. However, note that SPStyle doesn't currently have
* stop-color and stop-opacity properties.
*/
{
if (streq(p, "currentColor")) {
stop->currentColor = true;
} else {
}
}
{
}
break;
}
case SP_PROP_STOP_COLOR: {
{
if (streq(p, "currentColor")) {
stop->currentColor = true;
} else {
stop->currentColor = false;
}
}
break;
}
case SP_PROP_STOP_OPACITY: {
{
}
break;
}
case SP_ATTR_OFFSET: {
break;
}
default: {
break;
}
}
}
/**
* Virtual write: write object attributes to repr.
*/
sp_stop_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
{
}
// Since we do a hackish style setting here (because SPStyle does not support stop-color and
// stop-opacity), we must do it AFTER calling the parent write method; otherwise
// sp_object_write would clear our style= attribute (bug 1695287)
os << "stop-color:";
if (stop->currentColor) {
os << "currentColor";
} else {
gchar c[64];
sp_svg_write_color(c, sizeof(c), specifiedcolor);
os << c;
}
/* strictly speaking, offset an SVG <number> rather than a CSS one, but exponents make no sense
* for offset proportions. */
return repr;
}
/**
* Return stop's color as 32bit value.
*/
{
/* Default value: arbitrarily black. (SVG1.1 and CSS2 both say that the initial
* value depends on user agent, and don't give any further restrictions that I can
* see.) */
if (stop->currentColor) {
if (str) {
}
rgb0 | 0xff);
} else {
}
}
/**
* Return stop's color as SPColor.
*/
static SPColor
{
if (stop->currentColor) {
/* Default value: arbitrarily black. (SVG1.1 and CSS2 both say that the initial
* value depends on user agent, and don't give any further restrictions that I can
* see.) */
if (str) {
}
return ret;
} else {
return stop->specified_color;
}
}
/*
* Gradient
*/
static Inkscape::XML::Node *sp_gradient_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr,
static SPPaintServerClass *gradient_parent_class;
/**
* Registers SPGradient class and returns its type.
*/
{
static GType gradient_type = 0;
if (!gradient_type) {
sizeof(SPGradientClass),
sizeof(SPGradient),
16,
NULL, /* value_table */
};
&gradient_info, (GTypeFlags)0);
}
return gradient_type;
}
/**
* SPGradient vtable initialization.
*/
static void
{
}
/**
* Callback for SPGradient object initialization.
*/
static void
{
/** \todo
* Fixme: reprs being rearranged (e.g. via the XML editor)
* may require us to clear the state.
*/
}
/**
* Virtual build: set gradient attributes from its associated repr.
*/
static void
{
if (SP_IS_STOP(ochild)) {
break;
}
}
/* Register ourselves */
}
/**
* Virtual release of SPGradient members before destruction.
*/
static void
{
#ifdef SP_GRADIENT_VERBOSE
#endif
if (SP_OBJECT_DOCUMENT(object)) {
/* Unregister ourselves */
}
}
}
/**
* Set gradient attribute to value.
*/
static void
{
switch (key) {
case SP_ATTR_GRADIENTUNITS:
if (value) {
} else {
}
} else {
}
break;
case SP_ATTR_GRADIENTTRANSFORM: {
gr->gradientTransform = t;
} else {
}
break;
}
case SP_ATTR_SPREADMETHOD:
if (value) {
} else {
}
} else {
}
break;
case SP_ATTR_XLINK_HREF:
if (value) {
try {
} catch (Inkscape::BadURIException &e) {
}
} else {
}
break;
default:
break;
}
}
/**
* Gets called when the gradient is (re)attached to another gradient.
*/
static void
{
if (old_ref) {
}
if ( SP_IS_GRADIENT(ref)
{
gr->modified_connection = ref->connectModified(sigc::bind<2>(sigc::ptr_fun(&gradient_ref_modified), gr));
}
// Per SVG, all unset attributes must be inherited from linked gradient.
// So, as we're now (re)linked, we assign linkee's values to this gradient if they are not yet set -
// but without setting the _set flags.
// FIXME: do the same for gradientTransform too
if (!gr->spread_set)
/// \todo Fixme: what should the flags (second) argument be? */
}
/**
* Callback for child_added event.
*/
static void
{
}
/// \todo Fixme: should we schedule "modified" here?
}
/**
* Callback for remove_child event.
*/
static void
{
if (SP_IS_STOP(ochild)) {
break;
}
}
/* Fixme: should we schedule "modified" here? */
}
/**
* Callback for modified event.
*/
static void
{
if (flags & SP_OBJECT_CHILD_MODIFIED_FLAG) {
}
if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) {
}
// FIXME: climb up the ladder of hrefs
for (SPObject *child = sp_object_first_child(object) ; child != NULL; child = SP_OBJECT_NEXT(child) ) {
l = g_slist_prepend(l, child);
}
l = g_slist_reverse(l);
while (l) {
l = g_slist_remove(l, child);
}
}
}
{
for (SPObject *ochild = sp_object_first_child(this); ochild && !first; ochild = SP_OBJECT_NEXT(ochild)) {
if (SP_IS_STOP(ochild)) {
}
}
return first;
}
int SPGradient::getStopCount() const
{
int count = 0;
for (SPStop *stop = const_cast<SPGradient*>(this)->getFirstStop(); stop && stop->getNextStop(); stop = stop->getNextStop()) {
count++;
}
return count;
}
/**
* Write gradient attributes to repr.
*/
sp_gradient_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
{
if (flags & SP_OBJECT_WRITE_BUILD) {
}
while (l) {
l = g_slist_remove(l, l->data);
}
}
}
break;
default:
break;
}
}
g_free(c);
}
/* FIXME: Ensure that gr->spread is the inherited value
* if !gr->spread_set. Not currently happening: see sp_gradient_modified.
*/
break;
break;
default:
break;
}
}
return repr;
}
/**
* Forces the vector to be built, if not present (i.e., changed).
*
* \pre SP_IS_GRADIENT(gradient).
*/
void
{
}
}
/**
* Set units property of gradient and emit modified.
*/
void
{
}
}
/**
* Set spread property of gradient and emit modified.
*/
void
{
}
}
/**
* Returns the first of {src, src-\>ref-\>getObject(),
* src-\>ref-\>getObject()-\>ref-\>getObject(),...}
* for which \a match is true, or NULL if none found.
*
* The raison d'être of this routine is that it correctly handles cycles in the href chain (e.g., if
* a gradient gives itself as its href, or if each of two gradients gives the other as its href).
*
* \pre SP_IS_GRADIENT(src).
*/
static SPGradient *
{
/* Use a pair of pointers for detecting loops: p1 advances half as fast as p2. If there is a
loop, then once p1 has entered the loop, we'll detect it the next time the distance between
p1 and p2 is a multiple of the loop size. */
bool do1 = false;
for (;;) {
return p2;
}
if (!p2) {
return p2;
}
if (do1) {
}
/* We've been here before, so return NULL to indicate that no matching gradient found
* in the chain. */
return NULL;
}
}
}
/**
* True if gradient has stops.
*/
{
return SP_GRADIENT_HAS_STOPS(gr);
}
/**
* True if gradient has spread set.
*/
static bool
{
return gr->spread_set;
}
/**
* True if gradient has units set.
*/
static bool
{
}
{
if (force_vector) {
}
return src;
}
/**
* Returns the effective spread of given gradient (climbing up the refs chain if needed).
*
* \pre SP_IS_GRADIENT(gradient).
*/
{
return ( src
: SP_GRADIENT_SPREAD_PAD ); // pad is the default
}
/**
* Returns the effective units of given gradient (climbing up the refs chain if needed).
*
* \pre SP_IS_GRADIENT(gradient).
*/
{
return ( src
: SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX ); // bbox is the default
}
/**
* Clears the gradient's svg:stop children from its repr.
*/
void
{
/* Collect stops from original repr */
}
}
/* Remove all stops */
while (sl) {
/** \todo
* fixme: This should work, unless we make gradient
* into generic group.
*/
}
}
/**
* Writes the gradient's internal vector (whether from its own stops, or
* inherited from refs) into the gradient repr as svg:stop elements.
*/
void
{
/* We have to be careful, as vector may be our own, so construct repr list at first */
/* strictly speaking, offset an SVG <number> rather than a CSS one, but exponents make no
* sense for offset proportions. */
gchar c[64];
/* Order will be reversed here */
}
/* And insert new children from list */
while (cl) {
}
}
static void
{
/* Conditional to avoid causing infinite loop if there's a cycle in the href chain. */
}
}
/** Return true iff change made. */
static bool
{
bool ret = false;
ret = true;
}
return ret;
}
/** Creates normalized color vector */
static void
{
if (SP_IS_STOP(child)) {
len ++;
}
}
/* Copy vector from referenced gradient */
return;
}
}
if (SP_IS_STOP(child)) {
// "Each gradient offset value is required to be equal to or greater than the
// previous gradient stop's offset value. If a given gradient stop's offset
// value is not equal to or greater than all previous offset values, then the
// offset value is adjusted to be equal to the largest of all previous offset
// values."
} else {
}
// "Gradient offset values less than 0 (or less than 0%) are rounded up to
// 0%. Gradient offset values greater than 1 (or greater than 100%) are rounded
// down to 100%."
}
}
// Normalize per section 13.2.4 of SVG 1.1.
/* "If no stops are defined, then painting shall occur as if 'none' were specified as the
* paint style."
*/
{
}
{
}
} else {
/* "If one stop is defined, then paint with the solid color fill using the color defined
* for that gradient stop."
*/
// If the first one is not at 0, then insert a copy of the first at 0.
}
// If the last one is not at 1, then insert a copy of the last at 1.
}
}
}
{
} else {
return ctm;
}
}
{
return ( gr->gradientTransform
} else {
}
}
void
{
}
}
/*
* Linear Gradient
*/
static Inkscape::XML::Node *sp_lineargradient_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr,
static cairo_pattern_t *sp_lineargradient_create_pattern(SPPaintServer *ps, cairo_t *ct, NRRect const *bbox, double opacity);
static SPGradientClass *lg_parent_class;
/**
* Register SPLinearGradient class and return its type.
*/
{
if (!type) {
sizeof(SPLinearGradientClass),
sizeof(SPLinearGradient),
16,
NULL, /* value_table */
};
}
return type;
}
/**
* SPLinearGradient vtable initialization.
*/
{
}
/**
* Callback for SPLinearGradient object initialization.
*/
{
}
/**
* Callback: set attributes from associated repr.
*/
{
}
/**
* Callback: set attribute.
*/
static void
{
switch (key) {
case SP_ATTR_X1:
break;
case SP_ATTR_Y1:
break;
case SP_ATTR_X2:
break;
case SP_ATTR_Y2:
break;
default:
break;
}
}
/**
* Callback: write attributes to associated repr.
*/
sp_lineargradient_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
{
}
return repr;
}
/**
* Directly set properties of linear gradient and request modified.
*/
void
{
/* fixme: units? (Lauris) */
}
/*
* Radial Gradient
*/
static Inkscape::XML::Node *sp_radialgradient_write(SPObject *object, Inkscape::XML::Document *doc, Inkscape::XML::Node *repr,
static cairo_pattern_t *sp_radialgradient_create_pattern(SPPaintServer *ps, cairo_t *ct, NRRect const *bbox, double opacity);
static SPGradientClass *rg_parent_class;
/**
* Register SPRadialGradient class and return its type.
*/
{
if (!type) {
sizeof(SPRadialGradientClass),
sizeof(SPRadialGradient),
16,
NULL, /* value_table */
};
}
return type;
}
/**
* SPRadialGradient vtable initialization.
*/
{
}
/**
* Callback for SPRadialGradient object initialization.
*/
static void
{
}
/**
* Set radial gradient attributes from associated repr.
*/
static void
{
}
/**
* Set radial gradient attribute.
*/
static void
{
switch (key) {
case SP_ATTR_CX:
}
}
break;
case SP_ATTR_CY:
}
}
break;
case SP_ATTR_R:
}
break;
case SP_ATTR_FX:
}
break;
case SP_ATTR_FY:
}
break;
default:
break;
}
}
/**
* Write radial gradient attributes to associated repr.
*/
sp_radialgradient_write(SPObject *object, Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags)
{
}
if ((flags & SP_OBJECT_WRITE_ALL) || rg->cx._set) sp_repr_set_svg_double(repr, "cx", rg->cx.computed);
if ((flags & SP_OBJECT_WRITE_ALL) || rg->cy._set) sp_repr_set_svg_double(repr, "cy", rg->cy.computed);
if ((flags & SP_OBJECT_WRITE_ALL) || rg->fx._set) sp_repr_set_svg_double(repr, "fx", rg->fx.computed);
if ((flags & SP_OBJECT_WRITE_ALL) || rg->fy._set) sp_repr_set_svg_double(repr, "fy", rg->fy.computed);
return repr;
}
/**
* Directly set properties of radial gradient and request modified.
*/
void
{
/* fixme: units? (Lauris) */
}
/* CAIRO RENDERING STUFF */
static void
SPGradient *gr,
double opacity)
{
// set spread type
switch (sp_gradient_get_spread(gr)) {
break;
break;
case SP_GRADIENT_SPREAD_PAD:
default:
break;
}
// add stops
{
// multiply stop opacity by paint opacity
}
// set pattern matrix
}
}
static cairo_pattern_t *
cairo_t */* ct */,
double opacity)
{
return cp;
}
static cairo_pattern_t *
cairo_t */* ct */,
double opacity)
{
return cp;
}
{
{
}
return pat;
}
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :