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/SVGLinearGradientElement.h"
     27 
     28 #include "core/rendering/svg/RenderSVGResourceLinearGradient.h"
     29 #include "core/svg/LinearGradientAttributes.h"
     30 #include "core/svg/SVGLength.h"
     31 #include "core/svg/SVGTransformList.h"
     32 
     33 namespace blink {
     34 
     35 inline SVGLinearGradientElement::SVGLinearGradientElement(Document& document)
     36     : SVGGradientElement(SVGNames::linearGradientTag, document)
     37     , m_x1(SVGAnimatedLength::create(this, SVGNames::x1Attr, SVGLength::create(LengthModeWidth), AllowNegativeLengths))
     38     , m_y1(SVGAnimatedLength::create(this, SVGNames::y1Attr, SVGLength::create(LengthModeHeight), AllowNegativeLengths))
     39     , m_x2(SVGAnimatedLength::create(this, SVGNames::x2Attr, SVGLength::create(LengthModeWidth), AllowNegativeLengths))
     40     , m_y2(SVGAnimatedLength::create(this, SVGNames::y2Attr, SVGLength::create(LengthModeHeight), AllowNegativeLengths))
     41 {
     42     // Spec: If the x2 attribute is not specified, the effect is as if a value of "100%" were specified.
     43     m_x2->setDefaultValueAsString("100%");
     44 
     45     addToPropertyMap(m_x1);
     46     addToPropertyMap(m_y1);
     47     addToPropertyMap(m_x2);
     48     addToPropertyMap(m_y2);
     49 }
     50 
     51 DEFINE_NODE_FACTORY(SVGLinearGradientElement)
     52 
     53 bool SVGLinearGradientElement::isSupportedAttribute(const QualifiedName& attrName)
     54 {
     55     DEFINE_STATIC_LOCAL(HashSet<QualifiedName>, supportedAttributes, ());
     56     if (supportedAttributes.isEmpty()) {
     57         supportedAttributes.add(SVGNames::x1Attr);
     58         supportedAttributes.add(SVGNames::x2Attr);
     59         supportedAttributes.add(SVGNames::y1Attr);
     60         supportedAttributes.add(SVGNames::y2Attr);
     61     }
     62     return supportedAttributes.contains<SVGAttributeHashTranslator>(attrName);
     63 }
     64 
     65 void SVGLinearGradientElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
     66 {
     67     SVGParsingError parseError = NoError;
     68 
     69     if (!isSupportedAttribute(name))
     70         SVGGradientElement::parseAttribute(name, value);
     71     else if (name == SVGNames::x1Attr)
     72         m_x1->setBaseValueAsString(value, parseError);
     73     else if (name == SVGNames::y1Attr)
     74         m_y1->setBaseValueAsString(value, parseError);
     75     else if (name == SVGNames::x2Attr)
     76         m_x2->setBaseValueAsString(value, parseError);
     77     else if (name == SVGNames::y2Attr)
     78         m_y2->setBaseValueAsString(value, parseError);
     79     else
     80         ASSERT_NOT_REACHED();
     81 
     82     reportAttributeParsingError(parseError, name, value);
     83 }
     84 
     85 void SVGLinearGradientElement::svgAttributeChanged(const QualifiedName& attrName)
     86 {
     87     if (!isSupportedAttribute(attrName)) {
     88         SVGGradientElement::svgAttributeChanged(attrName);
     89         return;
     90     }
     91 
     92     SVGElement::InvalidationGuard invalidationGuard(this);
     93 
     94     updateRelativeLengthsInformation();
     95 
     96     RenderSVGResourceContainer* renderer = toRenderSVGResourceContainer(this->renderer());
     97     if (renderer)
     98         renderer->invalidateCacheAndMarkForLayout();
     99 }
    100 
    101 RenderObject* SVGLinearGradientElement::createRenderer(RenderStyle*)
    102 {
    103     return new RenderSVGResourceLinearGradient(this);
    104 }
    105 
    106 static void setGradientAttributes(SVGGradientElement* element, LinearGradientAttributes& attributes, bool isLinear = true)
    107 {
    108     if (!attributes.hasSpreadMethod() && element->spreadMethod()->isSpecified())
    109         attributes.setSpreadMethod(element->spreadMethod()->currentValue()->enumValue());
    110 
    111     if (!attributes.hasGradientUnits() && element->gradientUnits()->isSpecified())
    112         attributes.setGradientUnits(element->gradientUnits()->currentValue()->enumValue());
    113 
    114     if (!attributes.hasGradientTransform() && element->gradientTransform()->isSpecified()) {
    115         AffineTransform transform;
    116         element->gradientTransform()->currentValue()->concatenate(transform);
    117         attributes.setGradientTransform(transform);
    118     }
    119 
    120     if (!attributes.hasStops()) {
    121         const Vector<Gradient::ColorStop>& stops(element->buildStops());
    122         if (!stops.isEmpty())
    123             attributes.setStops(stops);
    124     }
    125 
    126     if (isLinear) {
    127         SVGLinearGradientElement* linear = toSVGLinearGradientElement(element);
    128 
    129         if (!attributes.hasX1() && linear->x1()->isSpecified())
    130             attributes.setX1(linear->x1()->currentValue());
    131 
    132         if (!attributes.hasY1() && linear->y1()->isSpecified())
    133             attributes.setY1(linear->y1()->currentValue());
    134 
    135         if (!attributes.hasX2() && linear->x2()->isSpecified())
    136             attributes.setX2(linear->x2()->currentValue());
    137 
    138         if (!attributes.hasY2() && linear->y2()->isSpecified())
    139             attributes.setY2(linear->y2()->currentValue());
    140     }
    141 }
    142 
    143 bool SVGLinearGradientElement::collectGradientAttributes(LinearGradientAttributes& attributes)
    144 {
    145     if (!renderer())
    146         return false;
    147 
    148     WillBeHeapHashSet<RawPtrWillBeMember<SVGGradientElement> > processedGradients;
    149     SVGGradientElement* current = this;
    150 
    151     setGradientAttributes(current, attributes);
    152     processedGradients.add(current);
    153 
    154     while (true) {
    155         // Respect xlink:href, take attributes from referenced element
    156         Node* refNode = SVGURIReference::targetElementFromIRIString(current->href()->currentValue()->value(), treeScope());
    157         if (refNode && isSVGGradientElement(*refNode)) {
    158             current = toSVGGradientElement(refNode);
    159 
    160             // Cycle detection
    161             if (processedGradients.contains(current))
    162                 return true;
    163 
    164             if (!current->renderer())
    165                 return false;
    166 
    167             setGradientAttributes(current, attributes, isSVGLinearGradientElement(*current));
    168             processedGradients.add(current);
    169         } else {
    170             return true;
    171         }
    172     }
    173 
    174     ASSERT_NOT_REACHED();
    175     return false;
    176 }
    177 
    178 bool SVGLinearGradientElement::selfHasRelativeLengths() const
    179 {
    180     return m_x1->currentValue()->isRelative()
    181         || m_y1->currentValue()->isRelative()
    182         || m_x2->currentValue()->isRelative()
    183         || m_y2->currentValue()->isRelative();
    184 }
    185 
    186 } // namespace blink
    187