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 #if ENABLE(SVG)
     27 #include "SVGLinearGradientElement.h"
     28 
     29 #include "Attribute.h"
     30 #include "Document.h"
     31 #include "FloatPoint.h"
     32 #include "LinearGradientAttributes.h"
     33 #include "RenderSVGResourceLinearGradient.h"
     34 #include "SVGLength.h"
     35 #include "SVGNames.h"
     36 #include "SVGTransform.h"
     37 #include "SVGTransformList.h"
     38 #include "SVGUnitTypes.h"
     39 
     40 namespace WebCore {
     41 
     42 // Animated property definitions
     43 DEFINE_ANIMATED_LENGTH(SVGLinearGradientElement, SVGNames::x1Attr, X1, x1)
     44 DEFINE_ANIMATED_LENGTH(SVGLinearGradientElement, SVGNames::y1Attr, Y1, y1)
     45 DEFINE_ANIMATED_LENGTH(SVGLinearGradientElement, SVGNames::x2Attr, X2, x2)
     46 DEFINE_ANIMATED_LENGTH(SVGLinearGradientElement, SVGNames::y2Attr, Y2, y2)
     47 
     48 inline SVGLinearGradientElement::SVGLinearGradientElement(const QualifiedName& tagName, Document* document)
     49     : SVGGradientElement(tagName, document)
     50     , m_x1(LengthModeWidth)
     51     , m_y1(LengthModeHeight)
     52     , m_x2(LengthModeWidth, "100%")
     53     , m_y2(LengthModeHeight)
     54 {
     55     // Spec: If the x2 attribute is not specified, the effect is as if a value of "100%" were specified.
     56 }
     57 
     58 PassRefPtr<SVGLinearGradientElement> SVGLinearGradientElement::create(const QualifiedName& tagName, Document* document)
     59 {
     60     return adoptRef(new SVGLinearGradientElement(tagName, document));
     61 }
     62 
     63 void SVGLinearGradientElement::parseMappedAttribute(Attribute* attr)
     64 {
     65     if (attr->name() == SVGNames::x1Attr)
     66         setX1BaseValue(SVGLength(LengthModeWidth, attr->value()));
     67     else if (attr->name() == SVGNames::y1Attr)
     68         setY1BaseValue(SVGLength(LengthModeHeight, attr->value()));
     69     else if (attr->name() == SVGNames::x2Attr)
     70         setX2BaseValue(SVGLength(LengthModeWidth, attr->value()));
     71     else if (attr->name() == SVGNames::y2Attr)
     72         setY2BaseValue(SVGLength(LengthModeHeight, attr->value()));
     73     else
     74         SVGGradientElement::parseMappedAttribute(attr);
     75 }
     76 
     77 void SVGLinearGradientElement::svgAttributeChanged(const QualifiedName& attrName)
     78 {
     79     SVGGradientElement::svgAttributeChanged(attrName);
     80 
     81     if (attrName == SVGNames::x1Attr
     82         || attrName == SVGNames::y1Attr
     83         || attrName == SVGNames::x2Attr
     84         || attrName == SVGNames::y2Attr) {
     85         updateRelativeLengthsInformation();
     86 
     87         RenderObject* object = renderer();
     88         if (!object)
     89             return;
     90 
     91         object->setNeedsLayout(true);
     92     }
     93 }
     94 
     95 void SVGLinearGradientElement::synchronizeProperty(const QualifiedName& attrName)
     96 {
     97     SVGGradientElement::synchronizeProperty(attrName);
     98 
     99     if (attrName == anyQName()) {
    100         synchronizeX1();
    101         synchronizeY1();
    102         synchronizeX2();
    103         synchronizeY2();
    104         return;
    105     }
    106 
    107     if (attrName == SVGNames::x1Attr)
    108         synchronizeX1();
    109     else if (attrName == SVGNames::y1Attr)
    110         synchronizeY1();
    111     else if (attrName == SVGNames::x2Attr)
    112         synchronizeX2();
    113     else if (attrName == SVGNames::y2Attr)
    114         synchronizeY2();
    115 }
    116 
    117 AttributeToPropertyTypeMap& SVGLinearGradientElement::attributeToPropertyTypeMap()
    118 {
    119     DEFINE_STATIC_LOCAL(AttributeToPropertyTypeMap, s_attributeToPropertyTypeMap, ());
    120     return s_attributeToPropertyTypeMap;
    121 }
    122 
    123 void SVGLinearGradientElement::fillAttributeToPropertyTypeMap()
    124 {
    125     AttributeToPropertyTypeMap& attributeToPropertyTypeMap = this->attributeToPropertyTypeMap();
    126 
    127     SVGGradientElement::fillPassedAttributeToPropertyTypeMap(attributeToPropertyTypeMap);
    128     attributeToPropertyTypeMap.set(SVGNames::x1Attr, AnimatedLength);
    129     attributeToPropertyTypeMap.set(SVGNames::y1Attr, AnimatedLength);
    130     attributeToPropertyTypeMap.set(SVGNames::x2Attr, AnimatedLength);
    131     attributeToPropertyTypeMap.set(SVGNames::y2Attr, AnimatedLength);
    132 }
    133 
    134 RenderObject* SVGLinearGradientElement::createRenderer(RenderArena* arena, RenderStyle*)
    135 {
    136     return new (arena) RenderSVGResourceLinearGradient(this);
    137 }
    138 
    139 void SVGLinearGradientElement::collectGradientAttributes(LinearGradientAttributes& attributes)
    140 {
    141     HashSet<SVGGradientElement*> processedGradients;
    142 
    143     bool isLinear = true;
    144     SVGGradientElement* current = this;
    145 
    146     while (current) {
    147         if (!attributes.hasSpreadMethod() && current->hasAttribute(SVGNames::spreadMethodAttr))
    148             attributes.setSpreadMethod((GradientSpreadMethod) current->spreadMethod());
    149 
    150         if (!attributes.hasBoundingBoxMode() && current->hasAttribute(SVGNames::gradientUnitsAttr))
    151             attributes.setBoundingBoxMode(current->gradientUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
    152 
    153         if (!attributes.hasGradientTransform() && current->hasAttribute(SVGNames::gradientTransformAttr)) {
    154             AffineTransform transform;
    155             current->gradientTransform().concatenate(transform);
    156             attributes.setGradientTransform(transform);
    157         }
    158 
    159         if (!attributes.hasStops()) {
    160             const Vector<Gradient::ColorStop>& stops(current->buildStops());
    161             if (!stops.isEmpty())
    162                 attributes.setStops(stops);
    163         }
    164 
    165         if (isLinear) {
    166             SVGLinearGradientElement* linear = static_cast<SVGLinearGradientElement*>(current);
    167 
    168             if (!attributes.hasX1() && current->hasAttribute(SVGNames::x1Attr))
    169                 attributes.setX1(linear->x1());
    170 
    171             if (!attributes.hasY1() && current->hasAttribute(SVGNames::y1Attr))
    172                 attributes.setY1(linear->y1());
    173 
    174             if (!attributes.hasX2() && current->hasAttribute(SVGNames::x2Attr))
    175                 attributes.setX2(linear->x2());
    176 
    177             if (!attributes.hasY2() && current->hasAttribute(SVGNames::y2Attr))
    178                 attributes.setY2(linear->y2());
    179         }
    180 
    181         processedGradients.add(current);
    182 
    183         // Respect xlink:href, take attributes from referenced element
    184         Node* refNode = ownerDocument()->getElementById(SVGURIReference::getTarget(current->href()));
    185         if (refNode && (refNode->hasTagName(SVGNames::linearGradientTag) || refNode->hasTagName(SVGNames::radialGradientTag))) {
    186             current = static_cast<SVGGradientElement*>(refNode);
    187 
    188             // Cycle detection
    189             if (processedGradients.contains(current)) {
    190                 current = 0;
    191                 break;
    192             }
    193 
    194             isLinear = current->hasTagName(SVGNames::linearGradientTag);
    195         } else
    196             current = 0;
    197     }
    198 }
    199 
    200 void SVGLinearGradientElement::calculateStartEndPoints(const LinearGradientAttributes& attributes, FloatPoint& startPoint, FloatPoint& endPoint)
    201 {
    202     // Determine gradient start/end points
    203     if (attributes.boundingBoxMode()) {
    204         startPoint = FloatPoint(attributes.x1().valueAsPercentage(), attributes.y1().valueAsPercentage());
    205         endPoint = FloatPoint(attributes.x2().valueAsPercentage(), attributes.y2().valueAsPercentage());
    206     } else {
    207         startPoint = FloatPoint(attributes.x1().value(this), attributes.y1().value(this));
    208         endPoint = FloatPoint(attributes.x2().value(this), attributes.y2().value(this));
    209     }
    210 }
    211 
    212 bool SVGLinearGradientElement::selfHasRelativeLengths() const
    213 {
    214     return x1().isRelative()
    215         || y1().isRelative()
    216         || x2().isRelative()
    217         || y2().isRelative();
    218 }
    219 
    220 }
    221 
    222 #endif // ENABLE(SVG)
    223