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)