Home | History | Annotate | Download | only in svg
      1 /*
      2  * Copyright (C) 2004, 2005, 2006, 2008 Nikolas Zimmermann <zimmermann (at) kde.org>
      3  * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis (at) kde.org>
      4  * Copyright (C) 2008 Eric Seidel <eric (at) webkit.org>
      5  * Copyright (C) 2008 Dirk Schulze <krit (at) webkit.org>
      6  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
      7  *
      8  * This library is free software; you can redistribute it and/or
      9  * modify it under the terms of the GNU Library General Public
     10  * License as published by the Free Software Foundation; either
     11  * version 2 of the License, or (at your option) any later version.
     12  *
     13  * This library is distributed in the hope that it will be useful,
     14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     16  * Library General Public License for more details.
     17  *
     18  * You should have received a copy of the GNU Library General Public License
     19  * along with this library; see the file COPYING.LIB.  If not, write to
     20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
     21  * Boston, MA 02110-1301, USA.
     22  */
     23 
     24 #include "config.h"
     25 
     26 #include "core/svg/SVGRadialGradientElement.h"
     27 
     28 #include "core/rendering/svg/RenderSVGResourceRadialGradient.h"
     29 #include "core/svg/RadialGradientAttributes.h"
     30 #include "core/svg/SVGElementInstance.h"
     31 #include "core/svg/SVGTransformList.h"
     32 
     33 namespace WebCore {
     34 
     35 // Animated property definitions
     36 DEFINE_ANIMATED_LENGTH(SVGRadialGradientElement, SVGNames::cxAttr, Cx, cx)
     37 DEFINE_ANIMATED_LENGTH(SVGRadialGradientElement, SVGNames::cyAttr, Cy, cy)
     38 DEFINE_ANIMATED_LENGTH(SVGRadialGradientElement, SVGNames::rAttr, R, r)
     39 DEFINE_ANIMATED_LENGTH(SVGRadialGradientElement, SVGNames::fxAttr, Fx, fx)
     40 DEFINE_ANIMATED_LENGTH(SVGRadialGradientElement, SVGNames::fyAttr, Fy, fy)
     41 DEFINE_ANIMATED_LENGTH(SVGRadialGradientElement, SVGNames::frAttr, Fr, fr)
     42 
     43 BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGRadialGradientElement)
     44     REGISTER_LOCAL_ANIMATED_PROPERTY(cx)
     45     REGISTER_LOCAL_ANIMATED_PROPERTY(cy)
     46     REGISTER_LOCAL_ANIMATED_PROPERTY(r)
     47     REGISTER_LOCAL_ANIMATED_PROPERTY(fx)
     48     REGISTER_LOCAL_ANIMATED_PROPERTY(fy)
     49     REGISTER_LOCAL_ANIMATED_PROPERTY(fr)
     50     REGISTER_PARENT_ANIMATED_PROPERTIES(SVGGradientElement)
     51 END_REGISTER_ANIMATED_PROPERTIES
     52 
     53 inline SVGRadialGradientElement::SVGRadialGradientElement(Document& document)
     54     : SVGGradientElement(SVGNames::radialGradientTag, document)
     55     , m_cx(LengthModeWidth, "50%")
     56     , m_cy(LengthModeHeight, "50%")
     57     , m_r(LengthModeOther, "50%")
     58     , m_fx(LengthModeWidth)
     59     , m_fy(LengthModeHeight)
     60     , m_fr(LengthModeOther, "0%")
     61 {
     62     // Spec: If the cx/cy/r/fr attribute is not specified, the effect is as if a value of "50%" were specified.
     63     ScriptWrappable::init(this);
     64     registerAnimatedPropertiesForSVGRadialGradientElement();
     65 }
     66 
     67 PassRefPtr<SVGRadialGradientElement> SVGRadialGradientElement::create(Document& document)
     68 {
     69     return adoptRef(new SVGRadialGradientElement(document));
     70 }
     71 
     72 bool SVGRadialGradientElement::isSupportedAttribute(const QualifiedName& attrName)
     73 {
     74     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
     75     if (supportedAttributes.isEmpty()) {
     76         supportedAttributes.add(SVGNames::cxAttr);
     77         supportedAttributes.add(SVGNames::cyAttr);
     78         supportedAttributes.add(SVGNames::fxAttr);
     79         supportedAttributes.add(SVGNames::fyAttr);
     80         supportedAttributes.add(SVGNames::rAttr);
     81         supportedAttributes.add(SVGNames::frAttr);
     82     }
     83     return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
     84 }
     85 
     86 void SVGRadialGradientElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
     87 {
     88     SVGParsingError parseError = NoError;
     89 
     90     if (!isSupportedAttribute(name))
     91         SVGGradientElement::parseAttribute(name, value);
     92     else if (name == SVGNames::cxAttr)
     93         setCxBaseValue(SVGLength::construct(LengthModeWidth, value, parseError));
     94     else if (name == SVGNames::cyAttr)
     95         setCyBaseValue(SVGLength::construct(LengthModeHeight, value, parseError));
     96     else if (name == SVGNames::rAttr)
     97         setRBaseValue(SVGLength::construct(LengthModeOther, value, parseError, ForbidNegativeLengths));
     98     else if (name == SVGNames::fxAttr)
     99         setFxBaseValue(SVGLength::construct(LengthModeWidth, value, parseError));
    100     else if (name == SVGNames::fyAttr)
    101         setFyBaseValue(SVGLength::construct(LengthModeHeight, value, parseError));
    102     else if (name == SVGNames::frAttr)
    103         setFrBaseValue(SVGLength::construct(LengthModeOther, value, parseError, ForbidNegativeLengths));
    104     else
    105         ASSERT_NOT_REACHED();
    106 
    107     reportAttributeParsingError(parseError, name, value);
    108 }
    109 
    110 void SVGRadialGradientElement::svgAttributeChanged(const QualifiedName& attrName)
    111 {
    112     if (!isSupportedAttribute(attrName)) {
    113         SVGGradientElement::svgAttributeChanged(attrName);
    114         return;
    115     }
    116 
    117     SVGElementInstance::InvalidationGuard invalidationGuard(this);
    118 
    119     updateRelativeLengthsInformation();
    120 
    121     RenderSVGResourceContainer* renderer = toRenderSVGResourceContainer(this->renderer());
    122     if (renderer)
    123         renderer->invalidateCacheAndMarkForLayout();
    124 }
    125 
    126 RenderObject* SVGRadialGradientElement::createRenderer(RenderStyle*)
    127 {
    128     return new RenderSVGResourceRadialGradient(this);
    129 }
    130 
    131 bool SVGRadialGradientElement::collectGradientAttributes(RadialGradientAttributes& attributes)
    132 {
    133     HashSet<SVGGradientElement*> processedGradients;
    134 
    135     bool isRadial = true;
    136     SVGGradientElement* current = this;
    137 
    138     while (current) {
    139         if (!current->renderer())
    140             return false;
    141 
    142         if (!attributes.hasSpreadMethod() && current->hasAttribute(SVGNames::spreadMethodAttr))
    143             attributes.setSpreadMethod(current->spreadMethodCurrentValue());
    144 
    145         if (!attributes.hasGradientUnits() && current->hasAttribute(SVGNames::gradientUnitsAttr))
    146             attributes.setGradientUnits(current->gradientUnitsCurrentValue());
    147 
    148         if (!attributes.hasGradientTransform() && current->hasAttribute(SVGNames::gradientTransformAttr)) {
    149             AffineTransform transform;
    150             current->gradientTransformCurrentValue().concatenate(transform);
    151             attributes.setGradientTransform(transform);
    152         }
    153 
    154         if (!attributes.hasStops()) {
    155             const Vector<Gradient::ColorStop>& stops(current->buildStops());
    156             if (!stops.isEmpty())
    157                 attributes.setStops(stops);
    158         }
    159 
    160         if (isRadial) {
    161             SVGRadialGradientElement* radial = toSVGRadialGradientElement(current);
    162 
    163             if (!attributes.hasCx() && current->hasAttribute(SVGNames::cxAttr))
    164                 attributes.setCx(radial->cxCurrentValue());
    165 
    166             if (!attributes.hasCy() && current->hasAttribute(SVGNames::cyAttr))
    167                 attributes.setCy(radial->cyCurrentValue());
    168 
    169             if (!attributes.hasR() && current->hasAttribute(SVGNames::rAttr))
    170                 attributes.setR(radial->rCurrentValue());
    171 
    172             if (!attributes.hasFx() && current->hasAttribute(SVGNames::fxAttr))
    173                 attributes.setFx(radial->fxCurrentValue());
    174 
    175             if (!attributes.hasFy() && current->hasAttribute(SVGNames::fyAttr))
    176                 attributes.setFy(radial->fyCurrentValue());
    177 
    178             if (!attributes.hasFr() && current->hasAttribute(SVGNames::frAttr))
    179                 attributes.setFr(radial->frCurrentValue());
    180         }
    181 
    182         processedGradients.add(current);
    183 
    184         // Respect xlink:href, take attributes from referenced element
    185         Node* refNode = SVGURIReference::targetElementFromIRIString(current->hrefCurrentValue(), document());
    186         if (refNode && (refNode->hasTagName(SVGNames::radialGradientTag) || refNode->hasTagName(SVGNames::linearGradientTag))) {
    187             current = toSVGGradientElement(refNode);
    188 
    189             // Cycle detection
    190             if (processedGradients.contains(current)) {
    191                 current = 0;
    192                 break;
    193             }
    194 
    195             isRadial = current->hasTagName(SVGNames::radialGradientTag);
    196         } else
    197             current = 0;
    198     }
    199 
    200     // Handle default values for fx/fy
    201     if (!attributes.hasFx())
    202         attributes.setFx(attributes.cx());
    203 
    204     if (!attributes.hasFy())
    205         attributes.setFy(attributes.cy());
    206     return true;
    207 }
    208 
    209 bool SVGRadialGradientElement::selfHasRelativeLengths() const
    210 {
    211     return cxCurrentValue().isRelative()
    212         || cyCurrentValue().isRelative()
    213         || rCurrentValue().isRelative()
    214         || fxCurrentValue().isRelative()
    215         || fyCurrentValue().isRelative()
    216         || frCurrentValue().isRelative();
    217 }
    218 
    219 }
    220