31#include "GraphicsContext.h"
32#include "ImageBuffer.h"
34#include "RenderSVGContainer.h"
38#include "SVGRenderSupport.h"
46#include <wtf/OwnPtr.h>
47#include <wtf/MathExtras.h>
53SVGPatternElement::SVGPatternElement(
const QualifiedName& tagName, Document* doc)
54 : SVGStyledElement(tagName, doc)
58 , SVGExternalResourcesRequired()
60 , m_x(this, LengthModeWidth)
61 , m_y(this, LengthModeHeight)
62 , m_width(this, LengthModeWidth)
63 , m_height(this, LengthModeHeight)
64 , m_patternUnits(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
65 , m_patternContentUnits(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE)
70SVGPatternElement::~SVGPatternElement()
74ANIMATED_PROPERTY_DEFINITIONS(SVGPatternElement,
int, Enumeration, enumeration, PatternUnits, patternUnits, SVGNames::patternUnitsAttr, m_patternUnits)
75ANIMATED_PROPERTY_DEFINITIONS(SVGPatternElement,
int, Enumeration, enumeration, PatternContentUnits, patternContentUnits, SVGNames::patternContentUnitsAttr, m_patternContentUnits)
76ANIMATED_PROPERTY_DEFINITIONS(SVGPatternElement, SVGLength, Length, length,
X, x, SVGNames::xAttr, m_x)
77ANIMATED_PROPERTY_DEFINITIONS(SVGPatternElement, SVGLength, Length, length, Y, y, SVGNames::yAttr, m_y)
78ANIMATED_PROPERTY_DEFINITIONS(SVGPatternElement, SVGLength, Length, length, Width, width, SVGNames::widthAttr, m_width)
79ANIMATED_PROPERTY_DEFINITIONS(SVGPatternElement, SVGLength, Length, length, Height, height, SVGNames::heightAttr, m_height)
80ANIMATED_PROPERTY_DEFINITIONS(SVGPatternElement, SVGTransformList*, TransformList, transformList, PatternTransform, patternTransform, SVGNames::patternTransformAttr, m_patternTransform.get())
82void SVGPatternElement::parseMappedAttribute(MappedAttribute* attr)
84 if (attr->name() == SVGNames::patternUnitsAttr) {
85 if (attr->value() ==
"userSpaceOnUse")
86 setPatternUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE);
87 else if (attr->value() ==
"objectBoundingBox")
88 setPatternUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
89 }
else if (attr->name() == SVGNames::patternContentUnitsAttr) {
90 if (attr->value() ==
"userSpaceOnUse")
91 setPatternContentUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE);
92 else if (attr->value() ==
"objectBoundingBox")
93 setPatternContentUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
94 }
else if (attr->name() == SVGNames::patternTransformAttr) {
95 SVGTransformList* patternTransforms = patternTransformBaseValue();
96 if (!SVGTransformable::parseTransformAttribute(patternTransforms, attr->value())) {
98 patternTransforms->clear(ec);
100 }
else if (attr->name() == SVGNames::xAttr)
101 setXBaseValue(SVGLength(
this, LengthModeWidth, attr->value()));
102 else if (attr->name() == SVGNames::yAttr)
103 setYBaseValue(SVGLength(
this, LengthModeHeight, attr->value()));
104 else if (attr->name() == SVGNames::widthAttr) {
105 setWidthBaseValue(SVGLength(this, LengthModeWidth, attr->value()));
106 if (width().value() < 0.0)
107 document()->accessSVGExtensions()->reportError(
"A negative value for pattern attribute <width> is not allowed");
108 }
else if (attr->name() == SVGNames::heightAttr) {
109 setHeightBaseValue(SVGLength(this, LengthModeHeight, attr->value()));
110 if (width().value() < 0.0)
111 document()->accessSVGExtensions()->reportError(
"A negative value for pattern attribute <height> is not allowed");
113 if (SVGURIReference::parseMappedAttribute(attr))
115 if (SVGTests::parseMappedAttribute(attr))
117 if (SVGLangSpace::parseMappedAttribute(attr))
119 if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
121 if (SVGFitToViewBox::parseMappedAttribute(attr))
124 SVGStyledElement::parseMappedAttribute(attr);
128void SVGPatternElement::svgAttributeChanged(
const QualifiedName& attrName)
130 SVGStyledElement::svgAttributeChanged(attrName);
135 if (attrName == SVGNames::patternUnitsAttr || attrName == SVGNames::patternContentUnitsAttr ||
136 attrName == SVGNames::patternTransformAttr || attrName == SVGNames::xAttr || attrName == SVGNames::yAttr ||
137 attrName == SVGNames::widthAttr || attrName == SVGNames::heightAttr ||
138 SVGURIReference::isKnownAttribute(attrName) ||
139 SVGTests::isKnownAttribute(attrName) ||
140 SVGLangSpace::isKnownAttribute(attrName) ||
141 SVGExternalResourcesRequired::isKnownAttribute(attrName) ||
142 SVGFitToViewBox::isKnownAttribute(attrName) ||
143 SVGStyledElement::isKnownAttribute(attrName))
144 m_resource->invalidate();
147void SVGPatternElement::childrenChanged(
bool changedByParser,
Node* beforeChange,
Node* afterChange,
int childCountDelta)
149 SVGStyledElement::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
154 m_resource->invalidate();
157void SVGPatternElement::buildPattern(
const FloatRect& targetRect)
const
159 PatternAttributes attributes = collectPatternProperties();
162 if (!attributes.patternContentElement() || !renderer() || !renderer()->style())
165 FloatRect patternBoundaries;
166 FloatRect patternContentBoundaries;
169 if (attributes.boundingBoxMode())
170 patternBoundaries = FloatRect(attributes.x().valueAsPercentage() * targetRect.width(),
171 attributes.y().valueAsPercentage() * targetRect.height(),
172 attributes.width().valueAsPercentage() * targetRect.width(),
173 attributes.height().valueAsPercentage() * targetRect.height());
175 patternBoundaries = FloatRect(attributes.x().value(),
176 attributes.y().value(),
177 attributes.width().value(),
178 attributes.height().value());
181 if (patternBoundaries.width() > targetRect.width())
182 patternBoundaries.setWidth(targetRect.width());
184 if (patternBoundaries.height() > targetRect.height())
185 patternBoundaries.setHeight(targetRect.height());
187 IntSize patternSize(patternBoundaries.width(), patternBoundaries.height());
188 clampImageBufferSizeToViewport(document()->renderer(), patternSize);
190 if (patternSize.width() <
static_cast<int>(patternBoundaries.width()))
191 patternBoundaries.setWidth(patternSize.width());
193 if (patternSize.height() <
static_cast<int>(patternBoundaries.height()))
194 patternBoundaries.setHeight(patternSize.height());
197 RenderStyle* style = renderer()->style();
198 if (style->overflowX() == OVISIBLE && style->overflowY() == OVISIBLE) {
200 if (!n->isSVGElement() || !
static_cast<SVGElement*
>(n)->isStyledTransformable() || !n->renderer())
202 patternContentBoundaries.unite(n->renderer()->relativeBBox(
true));
206 AffineTransform viewBoxCTM = viewBoxToViewTransform(patternBoundaries.width(), patternBoundaries.height());
207 FloatRect patternBoundariesIncludingOverflow = patternBoundaries;
210 if (!patternContentBoundaries.isEmpty()) {
211 if (!viewBoxCTM.isIdentity())
212 patternContentBoundaries = viewBoxCTM.mapRect(patternContentBoundaries);
213 else if (attributes.boundingBoxModeContent())
214 patternContentBoundaries = FloatRect(patternContentBoundaries.x() * targetRect.width(),
215 patternContentBoundaries.y() * targetRect.height(),
216 patternContentBoundaries.width() * targetRect.width(),
217 patternContentBoundaries.height() * targetRect.height());
219 patternBoundariesIncludingOverflow.unite(patternContentBoundaries);
222 IntSize imageSize(lroundf(patternBoundariesIncludingOverflow.width()), lroundf(patternBoundariesIncludingOverflow.height()));
223 clampImageBufferSizeToViewport(document()->renderer(), imageSize);
225 auto_ptr<ImageBuffer> patternImage = ImageBuffer::create(imageSize,
false);
227 if (!patternImage.get())
230 GraphicsContext* context = patternImage->context();
236 if (patternBoundariesIncludingOverflow.location() != patternBoundaries.location()) {
237 context->translate(patternBoundaries.x() - patternBoundariesIncludingOverflow.x(),
238 patternBoundaries.y() - patternBoundariesIncludingOverflow.y());
240 patternBoundaries.setLocation(patternBoundariesIncludingOverflow.location());
244 if (!viewBoxCTM.isIdentity())
245 context->concatCTM(viewBoxCTM);
246 else if (attributes.boundingBoxModeContent()) {
247 context->translate(targetRect.x(), targetRect.y());
248 context->scale(FloatSize(targetRect.width(), targetRect.height()));
253 if (!n->isSVGElement() || !
static_cast<SVGElement*
>(n)->isStyled() || !n->renderer())
255 renderSubtreeToImage(patternImage.get(), n->renderer());
260 m_resource->setPatternTransform(attributes.patternTransform());
261 m_resource->setPatternBoundaries(patternBoundaries);
262 m_resource->setTile(patternImage);
265RenderObject* SVGPatternElement::createRenderer(RenderArena* arena, RenderStyle*)
267 RenderSVGContainer* patternContainer =
new (arena) RenderSVGContainer(
this);
268 patternContainer->setDrawsContents(
false);
269 return patternContainer;
272SVGResource* SVGPatternElement::canvasResource()
275 m_resource = SVGPaintServerPattern::create(
this);
277 return m_resource.get();
280PatternAttributes SVGPatternElement::collectPatternProperties()
const
282 PatternAttributes attributes;
283 HashSet<const SVGPatternElement*> processedPatterns;
285 const SVGPatternElement* current =
this;
287 if (!attributes.hasX() && current->hasAttribute(SVGNames::xAttr))
288 attributes.setX(current->x());
290 if (!attributes.hasY() && current->hasAttribute(SVGNames::yAttr))
291 attributes.setY(current->y());
293 if (!attributes.hasWidth() && current->hasAttribute(SVGNames::widthAttr))
294 attributes.setWidth(current->width());
296 if (!attributes.hasHeight() && current->hasAttribute(SVGNames::heightAttr))
297 attributes.setHeight(current->height());
299 if (!attributes.hasBoundingBoxMode() && current->hasAttribute(SVGNames::patternUnitsAttr))
300 attributes.setBoundingBoxMode(current->getAttribute(SVGNames::patternUnitsAttr) ==
"objectBoundingBox");
302 if (!attributes.hasBoundingBoxModeContent() && current->hasAttribute(SVGNames::patternContentUnitsAttr))
303 attributes.setBoundingBoxModeContent(current->getAttribute(SVGNames::patternContentUnitsAttr) ==
"objectBoundingBox");
305 if (!attributes.hasPatternTransform() && current->hasAttribute(SVGNames::patternTransformAttr))
306 attributes.setPatternTransform(current->patternTransform()->consolidate().matrix());
308 if (!attributes.hasPatternContentElement() && current->hasChildNodes())
309 attributes.setPatternContentElement(current);
311 processedPatterns.add(current);
314 Node* refNode = ownerDocument()->getElementById(SVGURIReference::getTarget(current->href()));
315 if (refNode && refNode->hasTagName(SVGNames::patternTag)) {
316 current =
static_cast<const SVGPatternElement*
>(
const_cast<const Node*
>(refNode));
319 if (processedPatterns.contains(current))
320 return PatternAttributes();
Node nextSibling() const
The node immediately following this node.
The Node interface is the primary datatype for the entire Document Object Model.
Node firstChild() const
The first child of this node.
KAction * create(StandardAction id, const QObject *recvr, const char *slot, QObject *parent)
DOM::QualifiedName patternTransformAttr