KHTML
SVGMaskElement.cpp
Go to the documentation of this file.
00001 /* 00002 Copyright (C) 2004, 2005, 2006, 2008 Nikolas Zimmermann <zimmermann@kde.org> 00003 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org> 00004 2005 Alexander Kellett <lypanov@kde.org> 00005 00006 This file is part of the KDE project 00007 00008 This library is free software; you can redistribute it and/or 00009 modify it under the terms of the GNU Library General Public 00010 License as published by the Free Software Foundation; either 00011 version 2 of the License, or (at your option) any later version. 00012 00013 This library is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00016 Library General Public License for more details. 00017 00018 You should have received a copy of the GNU Library General Public License 00019 along with this library; see the file COPYING.LIB. If not, write to 00020 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00021 Boston, MA 02110-1301, USA. 00022 */ 00023 00024 #include "config.h" 00025 00026 #if ENABLE(SVG) 00027 #include "SVGMaskElement.h" 00028 00029 #include "CSSStyleSelector.h" 00030 #include "GraphicsContext.h" 00031 #include "ImageBuffer.h" 00032 #include "RenderSVGContainer.h" 00033 #include "SVGLength.h" 00034 #include "SVGNames.h" 00035 #include "SVGRenderSupport.h" 00036 #include "SVGUnitTypes.h" 00037 #include <math.h> 00038 #include <wtf/MathExtras.h> 00039 #include <wtf/OwnPtr.h> 00040 00041 using namespace std; 00042 00043 namespace WebCore { 00044 00045 SVGMaskElement::SVGMaskElement(const QualifiedName& tagName, Document* doc) 00046 : SVGStyledLocatableElement(tagName, doc) 00047 , SVGURIReference() 00048 , SVGTests() 00049 , SVGLangSpace() 00050 , SVGExternalResourcesRequired() 00051 , m_maskUnits(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) 00052 , m_maskContentUnits(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE) 00053 , m_x(this, LengthModeWidth) 00054 , m_y(this, LengthModeHeight) 00055 , m_width(this, LengthModeWidth) 00056 , m_height(this, LengthModeHeight) 00057 { 00058 // Spec: If the attribute is not specified, the effect is as if a value of "-10%" were specified. 00059 setXBaseValue(SVGLength(this, LengthModeWidth, "-10%")); 00060 setYBaseValue(SVGLength(this, LengthModeHeight, "-10%")); 00061 00062 // Spec: If the attribute is not specified, the effect is as if a value of "120%" were specified. 00063 setWidthBaseValue(SVGLength(this, LengthModeWidth, "120%")); 00064 setHeightBaseValue(SVGLength(this, LengthModeHeight, "120%")); 00065 } 00066 00067 SVGMaskElement::~SVGMaskElement() 00068 { 00069 } 00070 00071 ANIMATED_PROPERTY_DEFINITIONS(SVGMaskElement, int, Enumeration, enumeration, MaskUnits, maskUnits, SVGNames::maskUnitsAttr, m_maskUnits) 00072 ANIMATED_PROPERTY_DEFINITIONS(SVGMaskElement, int, Enumeration, enumeration, MaskContentUnits, maskContentUnits, SVGNames::maskContentUnitsAttr, m_maskContentUnits) 00073 ANIMATED_PROPERTY_DEFINITIONS(SVGMaskElement, SVGLength, Length, length, X, x, SVGNames::xAttr, m_x) 00074 ANIMATED_PROPERTY_DEFINITIONS(SVGMaskElement, SVGLength, Length, length, Y, y, SVGNames::yAttr, m_y) 00075 ANIMATED_PROPERTY_DEFINITIONS(SVGMaskElement, SVGLength, Length, length, Width, width, SVGNames::widthAttr, m_width) 00076 ANIMATED_PROPERTY_DEFINITIONS(SVGMaskElement, SVGLength, Length, length, Height, height, SVGNames::heightAttr, m_height) 00077 00078 void SVGMaskElement::parseMappedAttribute(MappedAttribute* attr) 00079 { 00080 if (attr->name() == SVGNames::maskUnitsAttr) { 00081 if (attr->value() == "userSpaceOnUse") 00082 setMaskUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE); 00083 else if (attr->value() == "objectBoundingBox") 00084 setMaskUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX); 00085 } else if (attr->name() == SVGNames::maskContentUnitsAttr) { 00086 if (attr->value() == "userSpaceOnUse") 00087 setMaskContentUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE); 00088 else if (attr->value() == "objectBoundingBox") 00089 setMaskContentUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX); 00090 } else if (attr->name() == SVGNames::xAttr) 00091 setXBaseValue(SVGLength(this, LengthModeWidth, attr->value())); 00092 else if (attr->name() == SVGNames::yAttr) 00093 setYBaseValue(SVGLength(this, LengthModeHeight, attr->value())); 00094 else if (attr->name() == SVGNames::widthAttr) 00095 setWidthBaseValue(SVGLength(this, LengthModeWidth, attr->value())); 00096 else if (attr->name() == SVGNames::heightAttr) 00097 setHeightBaseValue(SVGLength(this, LengthModeHeight, attr->value())); 00098 else { 00099 if (SVGURIReference::parseMappedAttribute(attr)) 00100 return; 00101 if (SVGTests::parseMappedAttribute(attr)) 00102 return; 00103 if (SVGLangSpace::parseMappedAttribute(attr)) 00104 return; 00105 if (SVGExternalResourcesRequired::parseMappedAttribute(attr)) 00106 return; 00107 SVGStyledElement::parseMappedAttribute(attr); 00108 } 00109 } 00110 00111 void SVGMaskElement::svgAttributeChanged(const QualifiedName& attrName) 00112 { 00113 SVGStyledElement::svgAttributeChanged(attrName); 00114 00115 if (!m_masker) 00116 return; 00117 00118 if (attrName == SVGNames::maskUnitsAttr || attrName == SVGNames::maskContentUnitsAttr || 00119 attrName == SVGNames::xAttr || attrName == SVGNames::yAttr || 00120 attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr || 00121 SVGURIReference::isKnownAttribute(attrName) || 00122 SVGTests::isKnownAttribute(attrName) || 00123 SVGLangSpace::isKnownAttribute(attrName) || 00124 SVGExternalResourcesRequired::isKnownAttribute(attrName) || 00125 SVGStyledElement::isKnownAttribute(attrName)) 00126 m_masker->invalidate(); 00127 } 00128 00129 void SVGMaskElement::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) 00130 { 00131 SVGStyledElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); 00132 00133 if (!m_masker) 00134 return; 00135 00136 m_masker->invalidate(); 00137 } 00138 00139 auto_ptr<ImageBuffer> SVGMaskElement::drawMaskerContent(const FloatRect& targetRect, FloatRect& maskDestRect) const 00140 { 00141 // Determine specified mask size 00142 float xValue; 00143 float yValue; 00144 float widthValue; 00145 float heightValue; 00146 00147 if (maskUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { 00148 xValue = x().valueAsPercentage() * targetRect.width(); 00149 yValue = y().valueAsPercentage() * targetRect.height(); 00150 widthValue = width().valueAsPercentage() * targetRect.width(); 00151 heightValue = height().valueAsPercentage() * targetRect.height(); 00152 } else { 00153 xValue = x().value(); 00154 yValue = y().value(); 00155 widthValue = width().value(); 00156 heightValue = height().value(); 00157 } 00158 00159 IntSize imageSize(lroundf(widthValue), lroundf(heightValue)); 00160 clampImageBufferSizeToViewport(document()->renderer(), imageSize); 00161 00162 if (imageSize.width() < static_cast<int>(widthValue)) 00163 widthValue = imageSize.width(); 00164 00165 if (imageSize.height() < static_cast<int>(heightValue)) 00166 heightValue = imageSize.height(); 00167 00168 auto_ptr<ImageBuffer> maskImage = ImageBuffer::create(imageSize, false); 00169 if (!maskImage.get()) 00170 return maskImage; 00171 00172 maskDestRect = FloatRect(xValue, yValue, widthValue, heightValue); 00173 if (maskUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) 00174 maskDestRect.move(targetRect.x(), targetRect.y()); 00175 00176 GraphicsContext* maskImageContext = maskImage->context(); 00177 ASSERT(maskImageContext); 00178 00179 maskImageContext->save(); 00180 maskImageContext->translate(-xValue, -yValue); 00181 00182 if (maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { 00183 maskImageContext->save(); 00184 maskImageContext->scale(FloatSize(targetRect.width(), targetRect.height())); 00185 } 00186 00187 // Render subtree into ImageBuffer 00188 for (Node* n = firstChild(); n; n = n->nextSibling()) { 00189 SVGElement* elem = 0; 00190 if (n->isSVGElement()) 00191 elem = static_cast<SVGElement*>(n); 00192 if (!elem || !elem->isStyled()) 00193 continue; 00194 00195 SVGStyledElement* e = static_cast<SVGStyledElement*>(elem); 00196 RenderObject* item = e->renderer(); 00197 if (!item) 00198 continue; 00199 00200 renderSubtreeToImage(maskImage.get(), item); 00201 } 00202 00203 if (maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) 00204 maskImageContext->restore(); 00205 00206 maskImageContext->restore(); 00207 return maskImage; 00208 } 00209 00210 RenderObject* SVGMaskElement::createRenderer(RenderArena* arena, RenderStyle*) 00211 { 00212 RenderSVGContainer* maskContainer = new (arena) RenderSVGContainer(this); 00213 maskContainer->setDrawsContents(false); 00214 return maskContainer; 00215 } 00216 00217 SVGResource* SVGMaskElement::canvasResource() 00218 { 00219 if (!m_masker) 00220 m_masker = SVGResourceMasker::create(this); 00221 return m_masker.get(); 00222 } 00223 00224 } 00225 00226 #endif // ENABLE(SVG)
KDE 4.6 API Reference