2 Copyright (C) 2004, 2005, 2006, 2008 Nikolas Zimmermann <zimmermann@kde.org>
3 2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
4 2005 Alexander Kellett <lypanov@kde.org>
6 This file is part of the KDE project
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.
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.
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.
27 #include "SVGMaskElement.h"
29 #include "CSSStyleSelector.h"
30 #include "GraphicsContext.h"
31 #include "ImageBuffer.h"
32 #include "RenderSVGContainer.h"
33 #include "SVGLength.h"
35 #include "SVGRenderSupport.h"
36 #include "SVGUnitTypes.h"
38 #include <wtf/MathExtras.h>
39 #include <wtf/OwnPtr.h>
45 SVGMaskElement::SVGMaskElement(const QualifiedName
& tagName
, Document
* doc
)
46 : SVGStyledLocatableElement(tagName
, doc
)
50 , SVGExternalResourcesRequired()
51 , m_maskUnits(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
)
52 , m_maskContentUnits(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE
)
53 , m_x(this, LengthModeWidth
)
54 , m_y(this, LengthModeHeight
)
55 , m_width(this, LengthModeWidth
)
56 , m_height(this, LengthModeHeight
)
58 // Spec: If the attribute is not specified, the effect is as if a value of "-10%" were specified.
59 setXBaseValue(SVGLength(this, LengthModeWidth
, "-10%"));
60 setYBaseValue(SVGLength(this, LengthModeHeight
, "-10%"));
62 // Spec: If the attribute is not specified, the effect is as if a value of "120%" were specified.
63 setWidthBaseValue(SVGLength(this, LengthModeWidth
, "120%"));
64 setHeightBaseValue(SVGLength(this, LengthModeHeight
, "120%"));
67 SVGMaskElement::~SVGMaskElement()
71 ANIMATED_PROPERTY_DEFINITIONS(SVGMaskElement
, int, Enumeration
, enumeration
, MaskUnits
, maskUnits
, SVGNames::maskUnitsAttr
, m_maskUnits
)
72 ANIMATED_PROPERTY_DEFINITIONS(SVGMaskElement
, int, Enumeration
, enumeration
, MaskContentUnits
, maskContentUnits
, SVGNames::maskContentUnitsAttr
, m_maskContentUnits
)
73 ANIMATED_PROPERTY_DEFINITIONS(SVGMaskElement
, SVGLength
, Length
, length
, X
, x
, SVGNames::xAttr
, m_x
)
74 ANIMATED_PROPERTY_DEFINITIONS(SVGMaskElement
, SVGLength
, Length
, length
, Y
, y
, SVGNames::yAttr
, m_y
)
75 ANIMATED_PROPERTY_DEFINITIONS(SVGMaskElement
, SVGLength
, Length
, length
, Width
, width
, SVGNames::widthAttr
, m_width
)
76 ANIMATED_PROPERTY_DEFINITIONS(SVGMaskElement
, SVGLength
, Length
, length
, Height
, height
, SVGNames::heightAttr
, m_height
)
78 void SVGMaskElement::parseMappedAttribute(MappedAttribute
* attr
)
80 if (attr
->name() == SVGNames::maskUnitsAttr
) {
81 if (attr
->value() == "userSpaceOnUse")
82 setMaskUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE
);
83 else if (attr
->value() == "objectBoundingBox")
84 setMaskUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
);
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 } else if (attr
->name() == SVGNames::xAttr
)
91 setXBaseValue(SVGLength(this, LengthModeWidth
, attr
->value()));
92 else if (attr
->name() == SVGNames::yAttr
)
93 setYBaseValue(SVGLength(this, LengthModeHeight
, attr
->value()));
94 else if (attr
->name() == SVGNames::widthAttr
)
95 setWidthBaseValue(SVGLength(this, LengthModeWidth
, attr
->value()));
96 else if (attr
->name() == SVGNames::heightAttr
)
97 setHeightBaseValue(SVGLength(this, LengthModeHeight
, attr
->value()));
99 if (SVGURIReference::parseMappedAttribute(attr
))
101 if (SVGTests::parseMappedAttribute(attr
))
103 if (SVGLangSpace::parseMappedAttribute(attr
))
105 if (SVGExternalResourcesRequired::parseMappedAttribute(attr
))
107 SVGStyledElement::parseMappedAttribute(attr
);
111 void SVGMaskElement::svgAttributeChanged(const QualifiedName
& attrName
)
113 SVGStyledElement::svgAttributeChanged(attrName
);
118 if (attrName
== SVGNames::maskUnitsAttr
|| attrName
== SVGNames::maskContentUnitsAttr
||
119 attrName
== SVGNames::xAttr
|| attrName
== SVGNames::yAttr
||
120 attrName
== SVGNames::widthAttr
|| attrName
== SVGNames::heightAttr
||
121 SVGURIReference::isKnownAttribute(attrName
) ||
122 SVGTests::isKnownAttribute(attrName
) ||
123 SVGLangSpace::isKnownAttribute(attrName
) ||
124 SVGExternalResourcesRequired::isKnownAttribute(attrName
) ||
125 SVGStyledElement::isKnownAttribute(attrName
))
126 m_masker
->invalidate();
129 void SVGMaskElement::childrenChanged(bool changedByParser
, Node
* beforeChange
, Node
* afterChange
, int childCountDelta
)
131 SVGStyledElement::childrenChanged(changedByParser
, beforeChange
, afterChange
, childCountDelta
);
136 m_masker
->invalidate();
139 auto_ptr
<ImageBuffer
> SVGMaskElement::drawMaskerContent(const FloatRect
& targetRect
, FloatRect
& maskDestRect
) const
141 // Determine specified mask size
147 if (maskUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
) {
148 xValue
= x().valueAsPercentage() * targetRect
.width();
149 yValue
= y().valueAsPercentage() * targetRect
.height();
150 widthValue
= width().valueAsPercentage() * targetRect
.width();
151 heightValue
= height().valueAsPercentage() * targetRect
.height();
153 xValue
= x().value();
154 yValue
= y().value();
155 widthValue
= width().value();
156 heightValue
= height().value();
159 IntSize
imageSize(lroundf(widthValue
), lroundf(heightValue
));
160 clampImageBufferSizeToViewport(document()->renderer(), imageSize
);
162 if (imageSize
.width() < static_cast<int>(widthValue
))
163 widthValue
= imageSize
.width();
165 if (imageSize
.height() < static_cast<int>(heightValue
))
166 heightValue
= imageSize
.height();
168 auto_ptr
<ImageBuffer
> maskImage
= ImageBuffer::create(imageSize
, false);
169 if (!maskImage
.get())
172 maskDestRect
= FloatRect(xValue
, yValue
, widthValue
, heightValue
);
173 if (maskUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
)
174 maskDestRect
.move(targetRect
.x(), targetRect
.y());
176 GraphicsContext
* maskImageContext
= maskImage
->context();
177 ASSERT(maskImageContext
);
179 maskImageContext
->save();
180 maskImageContext
->translate(-xValue
, -yValue
);
182 if (maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
) {
183 maskImageContext
->save();
184 maskImageContext
->scale(FloatSize(targetRect
.width(), targetRect
.height()));
187 // Render subtree into ImageBuffer
188 for (Node
* n
= firstChild(); n
; n
= n
->nextSibling()) {
189 SVGElement
* elem
= 0;
190 if (n
->isSVGElement())
191 elem
= static_cast<SVGElement
*>(n
);
192 if (!elem
|| !elem
->isStyled())
195 SVGStyledElement
* e
= static_cast<SVGStyledElement
*>(elem
);
196 RenderObject
* item
= e
->renderer();
200 renderSubtreeToImage(maskImage
.get(), item
);
203 if (maskContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
)
204 maskImageContext
->restore();
206 maskImageContext
->restore();
210 RenderObject
* SVGMaskElement::createRenderer(RenderArena
* arena
, RenderStyle
*)
212 RenderSVGContainer
* maskContainer
= new (arena
) RenderSVGContainer(this);
213 maskContainer
->setDrawsContents(false);
214 return maskContainer
;
217 SVGResource
* SVGMaskElement::canvasResource()
220 m_masker
= SVGResourceMasker::create(this);
221 return m_masker
.get();
226 #endif // ENABLE(SVG)