Home | History | Annotate | Download | only in svg
      1 /*
      2     Copyright (C) 2004, 2005, 2006, 2008 Nikolas Zimmermann <zimmermann (at) kde.org>
      3                   2004, 2005, 2006, 2007 Rob Buis <buis (at) kde.org>
      4 
      5     This library is free software; you can redistribute it and/or
      6     modify it under the terms of the GNU Library General Public
      7     License as published by the Free Software Foundation; either
      8     version 2 of the License, or (at your option) any later version.
      9 
     10     This library is distributed in the hope that it will be useful,
     11     but WITHOUT ANY WARRANTY; without even the implied warranty of
     12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13     Library General Public License for more details.
     14 
     15     You should have received a copy of the GNU Library General Public License
     16     along with this library; see the file COPYING.LIB.  If not, write to
     17     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     18     Boston, MA 02110-1301, USA.
     19 */
     20 
     21 #include "config.h"
     22 
     23 #if ENABLE(SVG)
     24 #include "SVGGradientElement.h"
     25 
     26 #include "CSSStyleSelector.h"
     27 #include "MappedAttribute.h"
     28 #include "RenderPath.h"
     29 #include "RenderSVGHiddenContainer.h"
     30 #include "SVGNames.h"
     31 #include "SVGPaintServerLinearGradient.h"
     32 #include "SVGPaintServerRadialGradient.h"
     33 #include "SVGStopElement.h"
     34 #include "SVGTransformList.h"
     35 #include "SVGTransformable.h"
     36 #include "SVGUnitTypes.h"
     37 
     38 namespace WebCore {
     39 
     40 SVGGradientElement::SVGGradientElement(const QualifiedName& tagName, Document* doc)
     41     : SVGStyledElement(tagName, doc)
     42     , SVGURIReference()
     43     , SVGExternalResourcesRequired()
     44     , m_gradientUnits(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
     45     , m_gradientTransform(SVGTransformList::create(SVGNames::gradientTransformAttr))
     46 {
     47 }
     48 
     49 SVGGradientElement::~SVGGradientElement()
     50 {
     51 }
     52 
     53 void SVGGradientElement::parseMappedAttribute(MappedAttribute* attr)
     54 {
     55     if (attr->name() == SVGNames::gradientUnitsAttr) {
     56         if (attr->value() == "userSpaceOnUse")
     57             setGradientUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE);
     58         else if (attr->value() == "objectBoundingBox")
     59             setGradientUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
     60     } else if (attr->name() == SVGNames::gradientTransformAttr) {
     61         SVGTransformList* gradientTransforms = gradientTransformBaseValue();
     62         if (!SVGTransformable::parseTransformAttribute(gradientTransforms, attr->value())) {
     63             ExceptionCode ec = 0;
     64             gradientTransforms->clear(ec);
     65         }
     66     } else if (attr->name() == SVGNames::spreadMethodAttr) {
     67         if (attr->value() == "reflect")
     68             setSpreadMethodBaseValue(SpreadMethodReflect);
     69         else if (attr->value() == "repeat")
     70             setSpreadMethodBaseValue(SpreadMethodRepeat);
     71         else if (attr->value() == "pad")
     72             setSpreadMethodBaseValue(SpreadMethodPad);
     73     } else {
     74         if (SVGURIReference::parseMappedAttribute(attr))
     75             return;
     76         if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
     77             return;
     78 
     79         SVGStyledElement::parseMappedAttribute(attr);
     80     }
     81 }
     82 
     83 void SVGGradientElement::svgAttributeChanged(const QualifiedName& attrName)
     84 {
     85     SVGStyledElement::svgAttributeChanged(attrName);
     86 
     87     if (!m_resource)
     88         return;
     89 
     90     if (attrName == SVGNames::gradientUnitsAttr ||
     91         attrName == SVGNames::gradientTransformAttr ||
     92         attrName == SVGNames::spreadMethodAttr ||
     93         SVGURIReference::isKnownAttribute(attrName) ||
     94         SVGExternalResourcesRequired::isKnownAttribute(attrName) ||
     95         SVGStyledElement::isKnownAttribute(attrName))
     96         m_resource->invalidate();
     97 }
     98 
     99 void SVGGradientElement::synchronizeProperty(const QualifiedName& attrName)
    100 {
    101     SVGStyledElement::synchronizeProperty(attrName);
    102 
    103     if (attrName == anyQName()) {
    104         synchronizeGradientUnits();
    105         synchronizeGradientTransform();
    106         synchronizeSpreadMethod();
    107         synchronizeExternalResourcesRequired();
    108         synchronizeHref();
    109         return;
    110     }
    111 
    112     if (attrName == SVGNames::gradientUnitsAttr)
    113         synchronizeGradientUnits();
    114     else if (attrName == SVGNames::gradientTransformAttr)
    115         synchronizeGradientTransform();
    116     else if (attrName == SVGNames::spreadMethodAttr)
    117         synchronizeSpreadMethod();
    118     else if (SVGExternalResourcesRequired::isKnownAttribute(attrName))
    119         synchronizeExternalResourcesRequired();
    120     else if (SVGURIReference::isKnownAttribute(attrName))
    121         synchronizeHref();
    122 }
    123 
    124 void SVGGradientElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
    125 {
    126     SVGStyledElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
    127 
    128     if (m_resource)
    129         m_resource->invalidate();
    130 }
    131 
    132 RenderObject* SVGGradientElement::createRenderer(RenderArena* arena, RenderStyle*)
    133 {
    134     return new (arena) RenderSVGHiddenContainer(this);
    135 }
    136 
    137 SVGResource* SVGGradientElement::canvasResource(const RenderObject*)
    138 {
    139     if (!m_resource) {
    140         if (gradientType() == LinearGradientPaintServer)
    141             m_resource = SVGPaintServerLinearGradient::create(this);
    142         else
    143             m_resource = SVGPaintServerRadialGradient::create(this);
    144     }
    145 
    146     return m_resource.get();
    147 }
    148 
    149 Vector<SVGGradientStop> SVGGradientElement::buildStops() const
    150 {
    151     Vector<SVGGradientStop> stops;
    152     RefPtr<RenderStyle> gradientStyle;
    153 
    154     for (Node* n = firstChild(); n; n = n->nextSibling()) {
    155         SVGElement* element = n->isSVGElement() ? static_cast<SVGElement*>(n) : 0;
    156 
    157         if (element && element->isGradientStop()) {
    158             SVGStopElement* stop = static_cast<SVGStopElement*>(element);
    159             float stopOffset = stop->offset();
    160 
    161             Color color;
    162             float opacity;
    163 
    164             if (stop->renderer()) {
    165                 RenderStyle* stopStyle = stop->renderer()->style();
    166                 color = stopStyle->svgStyle()->stopColor();
    167                 opacity = stopStyle->svgStyle()->stopOpacity();
    168             } else {
    169                 // If there is no renderer for this stop element, then a parent element
    170                 // set display="none" - ie. <g display="none"><linearGradient><stop>..
    171                 // Unfortunately we have to manually rebuild the stop style. See pservers-grad-19-b.svg
    172                 if (!gradientStyle)
    173                     gradientStyle = const_cast<SVGGradientElement*>(this)->styleForRenderer();
    174 
    175                 RefPtr<RenderStyle> stopStyle = stop->resolveStyle(gradientStyle.get());
    176 
    177                 color = stopStyle->svgStyle()->stopColor();
    178                 opacity = stopStyle->svgStyle()->stopOpacity();
    179             }
    180 
    181             stops.append(makeGradientStop(stopOffset, makeRGBA(color.red(), color.green(), color.blue(), int(opacity * 255.))));
    182         }
    183     }
    184 
    185     return stops;
    186 }
    187 
    188 }
    189 
    190 #endif // ENABLE(SVG)
    191