KHtml

SVGMaskElement.cpp
1 /*
2  Copyright (C) 2004, 2005, 2006, 2008 Nikolas Zimmermann <[email protected]>
3  2004, 2005, 2006, 2007 Rob Buis <[email protected]>
4  2005 Alexander Kellett <[email protected]>
5 
6  This file is part of the KDE project
7 
8  This library is free software; you can redistribute it and/or
9  modify it under the terms of the GNU Library General Public
10  License as published by the Free Software Foundation; either
11  version 2 of the License, or (at your option) any later version.
12 
13  This library is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  Library General Public License for more details.
17 
18  You should have received a copy of the GNU Library General Public License
19  along with this library; see the file COPYING.LIB. If not, write to
20  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  Boston, MA 02110-1301, USA.
22 */
23 
24 #if ENABLE(SVG)
25 #include "SVGMaskElement.h"
26 
27 #include "CSSStyleSelector.h"
28 #include "GraphicsContext.h"
29 #include "ImageBuffer.h"
30 #include "RenderSVGContainer.h"
31 #include "SVGLength.h"
32 #include "SVGNames.h"
33 #include "SVGRenderSupport.h"
34 #include "SVGUnitTypes.h"
35 #include <math.h>
36 #include <wtf/MathExtras.h>
37 #include <wtf/OwnPtr.h>
38 
39 using namespace std;
40 
41 namespace WebCore
42 {
43 
44 SVGMaskElement::SVGMaskElement(const QualifiedName &tagName, Document *doc)
45  : SVGStyledLocatableElement(tagName, doc)
46  , SVGURIReference()
47  , SVGTests()
48  , SVGLangSpace()
49  , SVGExternalResourcesRequired()
50  , m_maskUnits(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
51  , m_maskContentUnits(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE)
52  , m_x(this, LengthModeWidth)
53  , m_y(this, LengthModeHeight)
54  , m_width(this, LengthModeWidth)
55  , m_height(this, LengthModeHeight)
56 {
57  // Spec: If the attribute is not specified, the effect is as if a value of "-10%" were specified.
58  setXBaseValue(SVGLength(this, LengthModeWidth, "-10%"));
59  setYBaseValue(SVGLength(this, LengthModeHeight, "-10%"));
60 
61  // Spec: If the attribute is not specified, the effect is as if a value of "120%" were specified.
62  setWidthBaseValue(SVGLength(this, LengthModeWidth, "120%"));
63  setHeightBaseValue(SVGLength(this, LengthModeHeight, "120%"));
64 }
65 
66 SVGMaskElement::~SVGMaskElement()
67 {
68 }
69 
70 ANIMATED_PROPERTY_DEFINITIONS(SVGMaskElement, int, Enumeration, enumeration, MaskUnits, maskUnits, SVGNames::maskUnitsAttr, m_maskUnits)
71 ANIMATED_PROPERTY_DEFINITIONS(SVGMaskElement, int, Enumeration, enumeration, MaskContentUnits, maskContentUnits, SVGNames::maskContentUnitsAttr, m_maskContentUnits)
72 ANIMATED_PROPERTY_DEFINITIONS(SVGMaskElement, SVGLength, Length, length, X, x, SVGNames::xAttr, m_x)
73 ANIMATED_PROPERTY_DEFINITIONS(SVGMaskElement, SVGLength, Length, length, Y, y, SVGNames::yAttr, m_y)
74 ANIMATED_PROPERTY_DEFINITIONS(SVGMaskElement, SVGLength, Length, length, Width, width, SVGNames::widthAttr, m_width)
75 ANIMATED_PROPERTY_DEFINITIONS(SVGMaskElement, SVGLength, Length, length, Height, height, SVGNames::heightAttr, m_height)
76 
77 void SVGMaskElement::parseMappedAttribute(MappedAttribute *attr)
78 {
79  if (attr->name() == SVGNames::maskUnitsAttr) {
80  if (attr->value() == "userSpaceOnUse") {
81  setMaskUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE);
82  } else if (attr->value() == "objectBoundingBox") {
83  setMaskUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
84  }
85  } else if (attr->name() == SVGNames::maskContentUnitsAttr) {
86  if (attr->value() == "userSpaceOnUse") {
87  setMaskContentUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE);
88  } else if (attr->value() == "objectBoundingBox") {
89  setMaskContentUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
90  }
91  } else if (attr->name() == SVGNames::xAttr) {
92  setXBaseValue(SVGLength(this, LengthModeWidth, attr->value()));
93  } else if (attr->name() == SVGNames::yAttr) {
94  setYBaseValue(SVGLength(this, LengthModeHeight, attr->value()));
95  } else if (attr->name() == SVGNames::widthAttr) {
96  setWidthBaseValue(SVGLength(this, LengthModeWidth, attr->value()));
97  } else if (attr->name() == SVGNames::heightAttr) {
98  setHeightBaseValue(SVGLength(this, LengthModeHeight, attr->value()));
99  } else {
100  if (SVGURIReference::parseMappedAttribute(attr)) {
101  return;
102  }
103  if (SVGTests::parseMappedAttribute(attr)) {
104  return;
105  }
106  if (SVGLangSpace::parseMappedAttribute(attr)) {
107  return;
108  }
109  if (SVGExternalResourcesRequired::parseMappedAttribute(attr)) {
110  return;
111  }
112  SVGStyledElement::parseMappedAttribute(attr);
113  }
114 }
115 
116 void SVGMaskElement::svgAttributeChanged(const QualifiedName &attrName)
117 {
118  SVGStyledElement::svgAttributeChanged(attrName);
119 
120  if (!m_masker) {
121  return;
122  }
123 
124  if (attrName == SVGNames::maskUnitsAttr || attrName == SVGNames::maskContentUnitsAttr ||
125  attrName == SVGNames::xAttr || attrName == SVGNames::yAttr ||
126  attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr ||
127  SVGURIReference::isKnownAttribute(attrName) ||
128  SVGTests::isKnownAttribute(attrName) ||
129  SVGLangSpace::isKnownAttribute(attrName) ||
130  SVGExternalResourcesRequired::isKnownAttribute(attrName) ||
131  SVGStyledElement::isKnownAttribute(attrName)) {
132  m_masker->invalidate();
133  }
134 }
135 
136 void SVGMaskElement::childrenChanged(bool changedByParser, Node *beforeChange, Node *afterChange, int childCountDelta)
137 {
138  SVGStyledElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
139 
140  if (!m_masker) {
141  return;
142  }
143 
144  m_masker->invalidate();
145 }
146 
147 unique_ptr<ImageBuffer> SVGMaskElement::drawMaskerContent(const FloatRect &targetRect, FloatRect &maskDestRect) const
148 {
149  // Determine specified mask size
150  float xValue;
151  float yValue;
152  float widthValue;
153  float heightValue;
154 
155  if (maskUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
156  xValue = x().valueAsPercentage() * targetRect.width();
157  yValue = y().valueAsPercentage() * targetRect.height();
158  widthValue = width().valueAsPercentage() * targetRect.width();
159  heightValue = height().valueAsPercentage() * targetRect.height();
160  } else {
161  xValue = x().value();
162  yValue = y().value();
163  widthValue = width().value();
164  heightValue = height().value();
165  }
166 
167  IntSize imageSize(lroundf(widthValue), lroundf(heightValue));
168  clampImageBufferSizeToViewport(document()->renderer(), imageSize);
169 
170  if (imageSize.width() < static_cast<int>(widthValue)) {
171  widthValue = imageSize.width();
172  }
173 
174  if (imageSize.height() < static_cast<int>(heightValue)) {
175  heightValue = imageSize.height();
176  }
177 
178  unique_ptr<ImageBuffer> maskImage = ImageBuffer::create(imageSize, false);
179  if (!maskImage.get()) {
180  return maskImage;
181  }
182 
183  maskDestRect = FloatRect(xValue, yValue, widthValue, heightValue);
184  if (maskUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
185  maskDestRect.move(targetRect.x(), targetRect.y());
186  }
187 
188  GraphicsContext *maskImageContext = maskImage->context();
189  ASSERT(maskImageContext);
190 
191  maskImageContext->save();
192  maskImageContext->translate(-xValue, -yValue);
193 
194  if (maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
195  maskImageContext->save();
196  maskImageContext->scale(FloatSize(targetRect.width(), targetRect.height()));
197  }
198 
199  // Render subtree into ImageBuffer
200  for (Node *n = firstChild(); n; n = n->nextSibling()) {
201  SVGElement *elem = 0;
202  if (n->isSVGElement()) {
203  elem = static_cast<SVGElement *>(n);
204  }
205  if (!elem || !elem->isStyled()) {
206  continue;
207  }
208 
209  SVGStyledElement *e = static_cast<SVGStyledElement *>(elem);
210  RenderObject *item = e->renderer();
211  if (!item) {
212  continue;
213  }
214 
215  renderSubtreeToImage(maskImage.get(), item);
216  }
217 
218  if (maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
219  maskImageContext->restore();
220  }
221 
222  maskImageContext->restore();
223  return maskImage;
224 }
225 
226 RenderObject *SVGMaskElement::createRenderer(RenderArena *arena, RenderStyle *)
227 {
228  RenderSVGContainer *maskContainer = new(arena) RenderSVGContainer(this);
229  maskContainer->setDrawsContents(false);
230  return maskContainer;
231 }
232 
233 SVGResource *SVGMaskElement::canvasResource()
234 {
235  if (!m_masker) {
236  m_masker = SVGResourceMasker::create(this);
237  }
238  return m_masker.get();
239 }
240 
241 }
242 
243 #endif // ENABLE(SVG)
MESSAGECORE_EXPORT KMime::Content * firstChild(const KMime::Content *node)
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Oct 16 2021 22:48:02 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.