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 2005 Alexander Kellett <lypanov@kde.org> 0005 0006 This file is part of the KDE project 0007 0008 This library is free software; you can redistribute it and/or 0009 modify it under the terms of the GNU Library General Public 0010 License as published by the Free Software Foundation; either 0011 version 2 of the License, or (at your option) any later version. 0012 0013 This library is distributed in the hope that it will be useful, 0014 but WITHOUT ANY WARRANTY; without even the implied warranty of 0015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0016 Library General Public License for more details. 0017 0018 You should have received a copy of the GNU Library General Public License 0019 along with this library; see the file COPYING.LIB. If not, write to 0020 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0021 Boston, MA 02110-1301, USA. 0022 */ 0023 0024 #if ENABLE(SVG) 0025 #include "SVGMaskElement.h" 0026 0027 #include "CSSStyleSelector.h" 0028 #include "GraphicsContext.h" 0029 #include "ImageBuffer.h" 0030 #include "RenderSVGContainer.h" 0031 #include "SVGLength.h" 0032 #include "SVGNames.h" 0033 #include "SVGRenderSupport.h" 0034 #include "SVGUnitTypes.h" 0035 #include <math.h> 0036 #include <wtf/MathExtras.h> 0037 #include <wtf/OwnPtr.h> 0038 0039 using namespace std; 0040 0041 namespace WebCore 0042 { 0043 0044 SVGMaskElement::SVGMaskElement(const QualifiedName &tagName, Document *doc) 0045 : SVGStyledLocatableElement(tagName, doc) 0046 , SVGURIReference() 0047 , SVGTests() 0048 , SVGLangSpace() 0049 , SVGExternalResourcesRequired() 0050 , m_maskUnits(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) 0051 , m_maskContentUnits(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE) 0052 , m_x(this, LengthModeWidth) 0053 , m_y(this, LengthModeHeight) 0054 , m_width(this, LengthModeWidth) 0055 , m_height(this, LengthModeHeight) 0056 { 0057 // Spec: If the attribute is not specified, the effect is as if a value of "-10%" were specified. 0058 setXBaseValue(SVGLength(this, LengthModeWidth, "-10%")); 0059 setYBaseValue(SVGLength(this, LengthModeHeight, "-10%")); 0060 0061 // Spec: If the attribute is not specified, the effect is as if a value of "120%" were specified. 0062 setWidthBaseValue(SVGLength(this, LengthModeWidth, "120%")); 0063 setHeightBaseValue(SVGLength(this, LengthModeHeight, "120%")); 0064 } 0065 0066 SVGMaskElement::~SVGMaskElement() 0067 { 0068 } 0069 0070 ANIMATED_PROPERTY_DEFINITIONS(SVGMaskElement, int, Enumeration, enumeration, MaskUnits, maskUnits, SVGNames::maskUnitsAttr, m_maskUnits) 0071 ANIMATED_PROPERTY_DEFINITIONS(SVGMaskElement, int, Enumeration, enumeration, MaskContentUnits, maskContentUnits, SVGNames::maskContentUnitsAttr, m_maskContentUnits) 0072 ANIMATED_PROPERTY_DEFINITIONS(SVGMaskElement, SVGLength, Length, length, X, x, SVGNames::xAttr, m_x) 0073 ANIMATED_PROPERTY_DEFINITIONS(SVGMaskElement, SVGLength, Length, length, Y, y, SVGNames::yAttr, m_y) 0074 ANIMATED_PROPERTY_DEFINITIONS(SVGMaskElement, SVGLength, Length, length, Width, width, SVGNames::widthAttr, m_width) 0075 ANIMATED_PROPERTY_DEFINITIONS(SVGMaskElement, SVGLength, Length, length, Height, height, SVGNames::heightAttr, m_height) 0076 0077 void SVGMaskElement::parseMappedAttribute(MappedAttribute *attr) 0078 { 0079 if (attr->name() == SVGNames::maskUnitsAttr) { 0080 if (attr->value() == "userSpaceOnUse") { 0081 setMaskUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE); 0082 } else if (attr->value() == "objectBoundingBox") { 0083 setMaskUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX); 0084 } 0085 } else if (attr->name() == SVGNames::maskContentUnitsAttr) { 0086 if (attr->value() == "userSpaceOnUse") { 0087 setMaskContentUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE); 0088 } else if (attr->value() == "objectBoundingBox") { 0089 setMaskContentUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX); 0090 } 0091 } else if (attr->name() == SVGNames::xAttr) { 0092 setXBaseValue(SVGLength(this, LengthModeWidth, attr->value())); 0093 } else if (attr->name() == SVGNames::yAttr) { 0094 setYBaseValue(SVGLength(this, LengthModeHeight, attr->value())); 0095 } else if (attr->name() == SVGNames::widthAttr) { 0096 setWidthBaseValue(SVGLength(this, LengthModeWidth, attr->value())); 0097 } else if (attr->name() == SVGNames::heightAttr) { 0098 setHeightBaseValue(SVGLength(this, LengthModeHeight, attr->value())); 0099 } else { 0100 if (SVGURIReference::parseMappedAttribute(attr)) { 0101 return; 0102 } 0103 if (SVGTests::parseMappedAttribute(attr)) { 0104 return; 0105 } 0106 if (SVGLangSpace::parseMappedAttribute(attr)) { 0107 return; 0108 } 0109 if (SVGExternalResourcesRequired::parseMappedAttribute(attr)) { 0110 return; 0111 } 0112 SVGStyledElement::parseMappedAttribute(attr); 0113 } 0114 } 0115 0116 void SVGMaskElement::svgAttributeChanged(const QualifiedName &attrName) 0117 { 0118 SVGStyledElement::svgAttributeChanged(attrName); 0119 0120 if (!m_masker) { 0121 return; 0122 } 0123 0124 if (attrName == SVGNames::maskUnitsAttr || attrName == SVGNames::maskContentUnitsAttr || 0125 attrName == SVGNames::xAttr || attrName == SVGNames::yAttr || 0126 attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr || 0127 SVGURIReference::isKnownAttribute(attrName) || 0128 SVGTests::isKnownAttribute(attrName) || 0129 SVGLangSpace::isKnownAttribute(attrName) || 0130 SVGExternalResourcesRequired::isKnownAttribute(attrName) || 0131 SVGStyledElement::isKnownAttribute(attrName)) { 0132 m_masker->invalidate(); 0133 } 0134 } 0135 0136 void SVGMaskElement::childrenChanged(bool changedByParser, Node *beforeChange, Node *afterChange, int childCountDelta) 0137 { 0138 SVGStyledElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); 0139 0140 if (!m_masker) { 0141 return; 0142 } 0143 0144 m_masker->invalidate(); 0145 } 0146 0147 unique_ptr<ImageBuffer> SVGMaskElement::drawMaskerContent(const FloatRect &targetRect, FloatRect &maskDestRect) const 0148 { 0149 // Determine specified mask size 0150 float xValue; 0151 float yValue; 0152 float widthValue; 0153 float heightValue; 0154 0155 if (maskUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { 0156 xValue = x().valueAsPercentage() * targetRect.width(); 0157 yValue = y().valueAsPercentage() * targetRect.height(); 0158 widthValue = width().valueAsPercentage() * targetRect.width(); 0159 heightValue = height().valueAsPercentage() * targetRect.height(); 0160 } else { 0161 xValue = x().value(); 0162 yValue = y().value(); 0163 widthValue = width().value(); 0164 heightValue = height().value(); 0165 } 0166 0167 IntSize imageSize(lroundf(widthValue), lroundf(heightValue)); 0168 clampImageBufferSizeToViewport(document()->renderer(), imageSize); 0169 0170 if (imageSize.width() < static_cast<int>(widthValue)) { 0171 widthValue = imageSize.width(); 0172 } 0173 0174 if (imageSize.height() < static_cast<int>(heightValue)) { 0175 heightValue = imageSize.height(); 0176 } 0177 0178 unique_ptr<ImageBuffer> maskImage = ImageBuffer::create(imageSize, false); 0179 if (!maskImage.get()) { 0180 return maskImage; 0181 } 0182 0183 maskDestRect = FloatRect(xValue, yValue, widthValue, heightValue); 0184 if (maskUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { 0185 maskDestRect.move(targetRect.x(), targetRect.y()); 0186 } 0187 0188 GraphicsContext *maskImageContext = maskImage->context(); 0189 ASSERT(maskImageContext); 0190 0191 maskImageContext->save(); 0192 maskImageContext->translate(-xValue, -yValue); 0193 0194 if (maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { 0195 maskImageContext->save(); 0196 maskImageContext->scale(FloatSize(targetRect.width(), targetRect.height())); 0197 } 0198 0199 // Render subtree into ImageBuffer 0200 for (Node *n = firstChild(); n; n = n->nextSibling()) { 0201 SVGElement *elem = 0; 0202 if (n->isSVGElement()) { 0203 elem = static_cast<SVGElement *>(n); 0204 } 0205 if (!elem || !elem->isStyled()) { 0206 continue; 0207 } 0208 0209 SVGStyledElement *e = static_cast<SVGStyledElement *>(elem); 0210 RenderObject *item = e->renderer(); 0211 if (!item) { 0212 continue; 0213 } 0214 0215 renderSubtreeToImage(maskImage.get(), item); 0216 } 0217 0218 if (maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { 0219 maskImageContext->restore(); 0220 } 0221 0222 maskImageContext->restore(); 0223 return maskImage; 0224 } 0225 0226 RenderObject *SVGMaskElement::createRenderer(RenderArena *arena, RenderStyle *) 0227 { 0228 RenderSVGContainer *maskContainer = new(arena) RenderSVGContainer(this); 0229 maskContainer->setDrawsContents(false); 0230 return maskContainer; 0231 } 0232 0233 SVGResource *SVGMaskElement::canvasResource() 0234 { 0235 if (!m_masker) { 0236 m_masker = SVGResourceMasker::create(this); 0237 } 0238 return m_masker.get(); 0239 } 0240 0241 } 0242 0243 #endif // ENABLE(SVG)