File indexing completed on 2024-04-28 15:24:35
0001 /* 0002 Copyright (C) 2004, 2005, 2006, 2008 Nikolas Zimmermann <zimmermann@kde.org> 0003 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org> 0004 0005 This file is part of the KDE project 0006 0007 This library is free software; you can redistribute it and/or 0008 modify it under the terms of the GNU Library General Public 0009 License as published by the Free Software Foundation; either 0010 version 2 of the License, or (at your option) any later version. 0011 0012 This library is distributed in the hope that it will be useful, 0013 but WITHOUT ANY WARRANTY; without even the implied warranty of 0014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0015 Library General Public License for more details. 0016 0017 You should have received a copy of the GNU Library General Public License 0018 along with this library; see the file COPYING.LIB. If not, write to 0019 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0020 Boston, MA 02110-1301, USA. 0021 */ 0022 0023 #include "wtf/Platform.h" 0024 0025 #if ENABLE(SVG) 0026 #include "SVGLinearGradientElement.h" 0027 0028 #include "FloatPoint.h" 0029 #include "LinearGradientAttributes.h" 0030 #include "SVGLength.h" 0031 #include "SVGNames.h" 0032 #include "SVGPaintServerLinearGradient.h" 0033 #include "SVGTransform.h" 0034 #include "SVGTransformList.h" 0035 #include "SVGUnitTypes.h" 0036 0037 namespace WebCore 0038 { 0039 0040 SVGLinearGradientElement::SVGLinearGradientElement(const QualifiedName &tagName, Document *doc) 0041 : SVGGradientElement(tagName, doc) 0042 , m_x1(this, LengthModeWidth) 0043 , m_y1(this, LengthModeHeight) 0044 , m_x2(this, LengthModeWidth) 0045 , m_y2(this, LengthModeHeight) 0046 { 0047 // Spec: If the attribute is not specified, the effect is as if a value of "100%" were specified. 0048 setX2BaseValue(SVGLength(this, LengthModeWidth, "100%")); 0049 } 0050 0051 SVGLinearGradientElement::~SVGLinearGradientElement() 0052 { 0053 } 0054 0055 ANIMATED_PROPERTY_DEFINITIONS(SVGLinearGradientElement, SVGLength, Length, length, X1, x1, SVGNames::x1Attr, m_x1) 0056 ANIMATED_PROPERTY_DEFINITIONS(SVGLinearGradientElement, SVGLength, Length, length, Y1, y1, SVGNames::y1Attr, m_y1) 0057 ANIMATED_PROPERTY_DEFINITIONS(SVGLinearGradientElement, SVGLength, Length, length, X2, x2, SVGNames::x2Attr, m_x2) 0058 ANIMATED_PROPERTY_DEFINITIONS(SVGLinearGradientElement, SVGLength, Length, length, Y2, y2, SVGNames::y2Attr, m_y2) 0059 0060 void SVGLinearGradientElement::parseMappedAttribute(MappedAttribute *attr) 0061 { 0062 if (attr->name() == SVGNames::x1Attr) { 0063 setX1BaseValue(SVGLength(this, LengthModeWidth, attr->value())); 0064 } else if (attr->name() == SVGNames::y1Attr) { 0065 setY1BaseValue(SVGLength(this, LengthModeHeight, attr->value())); 0066 } else if (attr->name() == SVGNames::x2Attr) { 0067 setX2BaseValue(SVGLength(this, LengthModeWidth, attr->value())); 0068 } else if (attr->name() == SVGNames::y2Attr) { 0069 setY2BaseValue(SVGLength(this, LengthModeHeight, attr->value())); 0070 } else { 0071 SVGGradientElement::parseMappedAttribute(attr); 0072 } 0073 } 0074 0075 void SVGLinearGradientElement::svgAttributeChanged(const QualifiedName &attrName) 0076 { 0077 SVGGradientElement::svgAttributeChanged(attrName); 0078 0079 if (!m_resource) { 0080 return; 0081 } 0082 0083 if (attrName == SVGNames::x1Attr || attrName == SVGNames::y1Attr || 0084 attrName == SVGNames::x2Attr || attrName == SVGNames::y2Attr) { 0085 m_resource->invalidate(); 0086 } 0087 } 0088 0089 void SVGLinearGradientElement::buildGradient() const 0090 { 0091 LinearGradientAttributes attributes = collectGradientProperties(); 0092 0093 // If we didn't find any gradient containing stop elements, ignore the request. 0094 if (attributes.stops().isEmpty()) { 0095 return; 0096 } 0097 0098 RefPtr<SVGPaintServerLinearGradient> linearGradient = WTF::static_pointer_cast<SVGPaintServerLinearGradient>(m_resource); 0099 0100 linearGradient->setGradientStops(attributes.stops()); 0101 linearGradient->setBoundingBoxMode(attributes.boundingBoxMode()); 0102 linearGradient->setGradientSpreadMethod(attributes.spreadMethod()); 0103 linearGradient->setGradientTransform(attributes.gradientTransform()); 0104 linearGradient->setGradientStart(FloatPoint::narrowPrecision(attributes.x1(), attributes.y1())); 0105 linearGradient->setGradientEnd(FloatPoint::narrowPrecision(attributes.x2(), attributes.y2())); 0106 } 0107 0108 LinearGradientAttributes SVGLinearGradientElement::collectGradientProperties() const 0109 { 0110 LinearGradientAttributes attributes; 0111 HashSet<const SVGGradientElement *> processedGradients; 0112 0113 bool isLinear = true; 0114 const SVGGradientElement *current = this; 0115 0116 while (current) { 0117 if (!attributes.hasSpreadMethod() && current->hasAttribute(SVGNames::spreadMethodAttr)) { 0118 attributes.setSpreadMethod((SVGGradientSpreadMethod) current->spreadMethod()); 0119 } 0120 0121 if (!attributes.hasBoundingBoxMode() && current->hasAttribute(SVGNames::gradientUnitsAttr)) { 0122 attributes.setBoundingBoxMode(current->getAttribute(SVGNames::gradientUnitsAttr) == "objectBoundingBox"); 0123 } 0124 0125 if (!attributes.hasGradientTransform() && current->hasAttribute(SVGNames::gradientTransformAttr)) { 0126 attributes.setGradientTransform(current->gradientTransform()->consolidate().matrix()); 0127 } 0128 0129 if (!attributes.hasStops()) { 0130 const Vector<SVGGradientStop> &stops(current->buildStops()); 0131 // qCDebug(KHTML_LOG) << "stops.isEmpty()" << stops.isEmpty(); 0132 if (!stops.isEmpty()) { 0133 attributes.setStops(stops); 0134 } 0135 } 0136 0137 if (isLinear) { 0138 const SVGLinearGradientElement *linear = static_cast<const SVGLinearGradientElement *>(current); 0139 0140 if (!attributes.hasX1() && current->hasAttribute(SVGNames::x1Attr)) { 0141 attributes.setX1(linear->x1().valueAsPercentage()); 0142 } 0143 0144 if (!attributes.hasY1() && current->hasAttribute(SVGNames::y1Attr)) { 0145 attributes.setY1(linear->y1().valueAsPercentage()); 0146 } 0147 0148 if (!attributes.hasX2() && current->hasAttribute(SVGNames::x2Attr)) { 0149 attributes.setX2(linear->x2().valueAsPercentage()); 0150 } 0151 0152 if (!attributes.hasY2() && current->hasAttribute(SVGNames::y2Attr)) { 0153 attributes.setY2(linear->y2().valueAsPercentage()); 0154 } 0155 } 0156 0157 processedGradients.add(current); 0158 0159 // Respect xlink:href, take attributes from referenced element 0160 Node *refNode = ownerDocument()->getElementById(SVGURIReference::getTarget(current->href())); 0161 if (refNode && (refNode->hasTagName(SVGNames::linearGradientTag) || refNode->hasTagName(SVGNames::radialGradientTag))) { 0162 current = static_cast<const SVGGradientElement *>(const_cast<const Node *>(refNode)); 0163 // int ec; 0164 // qCDebug(KHTML_LOG) << "take attributes from" << current->getAttributeNS("", "id", ec); 0165 0166 // Cycle detection 0167 if (processedGradients.contains(current)) { 0168 return LinearGradientAttributes(); 0169 } 0170 0171 isLinear = current->gradientType() == LinearGradientPaintServer; 0172 } else { 0173 current = nullptr; 0174 } 0175 } 0176 0177 return attributes; 0178 } 0179 0180 // KHTML ElementImpl pure virtual method 0181 quint32 SVGLinearGradientElement::id() const 0182 { 0183 return SVGNames::linearGradientTag.id(); 0184 } 0185 0186 } 0187 0188 #endif // ENABLE(SVG)