1/* 2 * Copyright (C) 2004, 2005, 2006, 2008 Nikolas Zimmermann <zimmermann@kde.org> 3 * Copyright (C) 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org> 4 * Copyright (C) Research In Motion Limited 2010. All rights reserved. 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Library General Public 8 * License as published by the Free Software Foundation; either 9 * version 2 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Library General Public License for more details. 15 * 16 * You should have received a copy of the GNU Library General Public License 17 * along with this library; see the file COPYING.LIB. If not, write to 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19 * Boston, MA 02110-1301, USA. 20 */ 21 22#include "config.h" 23#include "SVGGradientElement.h" 24 25#include "ElementIterator.h" 26#include "RenderSVGHiddenContainer.h" 27#include "RenderSVGPath.h" 28#include "RenderSVGResourceLinearGradient.h" 29#include "RenderSVGResourceRadialGradient.h" 30#include "SVGElementInstance.h" 31#include "SVGNames.h" 32#include "SVGStopElement.h" 33#include "SVGTransformList.h" 34#include "SVGTransformable.h" 35#include "StyleResolver.h" 36#include "XLinkNames.h" 37#include <wtf/NeverDestroyed.h> 38 39namespace WebCore { 40 41// Animated property definitions 42DEFINE_ANIMATED_ENUMERATION(SVGGradientElement, SVGNames::spreadMethodAttr, SpreadMethod, spreadMethod, SVGSpreadMethodType) 43DEFINE_ANIMATED_ENUMERATION(SVGGradientElement, SVGNames::gradientUnitsAttr, GradientUnits, gradientUnits, SVGUnitTypes::SVGUnitType) 44DEFINE_ANIMATED_TRANSFORM_LIST(SVGGradientElement, SVGNames::gradientTransformAttr, GradientTransform, gradientTransform) 45DEFINE_ANIMATED_STRING(SVGGradientElement, XLinkNames::hrefAttr, Href, href) 46DEFINE_ANIMATED_BOOLEAN(SVGGradientElement, SVGNames::externalResourcesRequiredAttr, ExternalResourcesRequired, externalResourcesRequired) 47 48BEGIN_REGISTER_ANIMATED_PROPERTIES(SVGGradientElement) 49 REGISTER_LOCAL_ANIMATED_PROPERTY(spreadMethod) 50 REGISTER_LOCAL_ANIMATED_PROPERTY(gradientUnits) 51 REGISTER_LOCAL_ANIMATED_PROPERTY(gradientTransform) 52 REGISTER_LOCAL_ANIMATED_PROPERTY(href) 53 REGISTER_LOCAL_ANIMATED_PROPERTY(externalResourcesRequired) 54 REGISTER_PARENT_ANIMATED_PROPERTIES(SVGElement) 55END_REGISTER_ANIMATED_PROPERTIES 56 57SVGGradientElement::SVGGradientElement(const QualifiedName& tagName, Document& document) 58 : SVGElement(tagName, document) 59 , m_spreadMethod(SVGSpreadMethodPad) 60 , m_gradientUnits(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) 61{ 62 registerAnimatedPropertiesForSVGGradientElement(); 63} 64 65bool SVGGradientElement::isSupportedAttribute(const QualifiedName& attrName) 66{ 67 static NeverDestroyed<HashSet<QualifiedName>> supportedAttributes; 68 if (supportedAttributes.get().isEmpty()) { 69 SVGURIReference::addSupportedAttributes(supportedAttributes); 70 SVGExternalResourcesRequired::addSupportedAttributes(supportedAttributes); 71 supportedAttributes.get().add(SVGNames::gradientUnitsAttr); 72 supportedAttributes.get().add(SVGNames::gradientTransformAttr); 73 supportedAttributes.get().add(SVGNames::spreadMethodAttr); 74 } 75 return supportedAttributes.get().contains<SVGAttributeHashTranslator>(attrName); 76} 77 78void SVGGradientElement::parseAttribute(const QualifiedName& name, const AtomicString& value) 79{ 80 if (!isSupportedAttribute(name)) { 81 SVGElement::parseAttribute(name, value); 82 return; 83 } 84 85 if (name == SVGNames::gradientUnitsAttr) { 86 SVGUnitTypes::SVGUnitType propertyValue = SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::fromString(value); 87 if (propertyValue > 0) 88 setGradientUnitsBaseValue(propertyValue); 89 return; 90 } 91 92 if (name == SVGNames::gradientTransformAttr) { 93 SVGTransformList newList; 94 newList.parse(value); 95 detachAnimatedGradientTransformListWrappers(newList.size()); 96 setGradientTransformBaseValue(newList); 97 return; 98 } 99 100 if (name == SVGNames::spreadMethodAttr) { 101 SVGSpreadMethodType propertyValue = SVGPropertyTraits<SVGSpreadMethodType>::fromString(value); 102 if (propertyValue > 0) 103 setSpreadMethodBaseValue(propertyValue); 104 return; 105 } 106 107 if (SVGURIReference::parseAttribute(name, value)) 108 return; 109 if (SVGExternalResourcesRequired::parseAttribute(name, value)) 110 return; 111 112 ASSERT_NOT_REACHED(); 113} 114 115void SVGGradientElement::svgAttributeChanged(const QualifiedName& attrName) 116{ 117 if (!isSupportedAttribute(attrName)) { 118 SVGElement::svgAttributeChanged(attrName); 119 return; 120 } 121 122 SVGElementInstance::InvalidationGuard invalidationGuard(this); 123 124 if (RenderObject* object = renderer()) 125 object->setNeedsLayout(); 126} 127 128void SVGGradientElement::childrenChanged(const ChildChange& change) 129{ 130 SVGElement::childrenChanged(change); 131 132 if (change.source == ChildChangeSourceParser) 133 return; 134 135 if (RenderObject* object = renderer()) 136 object->setNeedsLayout(); 137} 138 139Vector<Gradient::ColorStop> SVGGradientElement::buildStops() 140{ 141 Vector<Gradient::ColorStop> stops; 142 float previousOffset = 0.0f; 143 144 for (auto& stop : childrenOfType<SVGStopElement>(*this)) { 145 Color color = stop.stopColorIncludingOpacity(); 146 147 // Figure out right monotonic offset 148 float offset = stop.offset(); 149 offset = std::min(std::max(previousOffset, offset), 1.0f); 150 previousOffset = offset; 151 152 // Extract individual channel values 153 // FIXME: Why doesn't ColorStop take a Color and an offset?? 154 float r, g, b, a; 155 color.getRGBA(r, g, b, a); 156 157 stops.append(Gradient::ColorStop(offset, r, g, b, a)); 158 } 159 160 return stops; 161} 162 163bool isSVGGradientElement(const Node& node) 164{ 165 return node.hasTagName(SVGNames::radialGradientTag) || node.hasTagName(SVGNames::linearGradientTag); 166} 167 168} 169