~ubuntu-branches/ubuntu/maverick/webkit/maverick

« back to all changes in this revision

Viewing changes to WebCore/ksvg2/svg/SVGPatternElement.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Mike Hommey
  • Date: 2007-08-19 15:54:12 UTC
  • Revision ID: james.westby@ubuntu.com-20070819155412-uxxg1h9plpghmtbi
Tags: upstream-0~svn25144
ImportĀ upstreamĀ versionĀ 0~svn25144

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    Copyright (C) 2004, 2005, 2006 Nikolas Zimmermann <zimmermann@kde.org>
 
3
                  2004, 2005, 2006, 2007 Rob Buis <buis@kde.org>
 
4
 
 
5
    This file is part of the KDE project
 
6
 
 
7
    This library is free software; you can redistribute it and/or
 
8
    modify it under the terms of the GNU Library General Public
 
9
    License as published by the Free Software Foundation; either
 
10
    version 2 of the License, or (at your option) any later version.
 
11
 
 
12
    This library is distributed in the hope that it will be useful,
 
13
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
15
    Library General Public License for more details.
 
16
 
 
17
    You should have received a copy of the GNU Library General Public License
 
18
    along with this library; see the file COPYING.LIB.  If not, write to
 
19
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 
20
    Boston, MA 02111-1307, USA.
 
21
*/
 
22
 
 
23
#include "config.h"
 
24
 
 
25
#if ENABLE(SVG)
 
26
#include "SVGPatternElement.h"
 
27
 
 
28
#include "AffineTransform.h"
 
29
#include "Document.h"
 
30
#include "FloatConversion.h"
 
31
#include "GraphicsContext.h"
 
32
#include "ImageBuffer.h"
 
33
#include "PatternAttributes.h"
 
34
#include "RenderSVGContainer.h"
 
35
#include "SVGLength.h"
 
36
#include "SVGNames.h"
 
37
#include "SVGPaintServerPattern.h"
 
38
#include "SVGSVGElement.h"
 
39
#include "SVGTransformList.h"
 
40
#include "SVGTransformable.h"
 
41
#include "SVGUnitTypes.h"
 
42
 
 
43
#include <math.h>
 
44
#include <wtf/OwnPtr.h>
 
45
#include <wtf/MathExtras.h>
 
46
 
 
47
using namespace std;
 
48
 
 
49
namespace WebCore {
 
50
 
 
51
SVGPatternElement::SVGPatternElement(const QualifiedName& tagName, Document* doc)
 
52
    : SVGStyledElement(tagName, doc)
 
53
    , SVGURIReference()
 
54
    , SVGTests()
 
55
    , SVGLangSpace()
 
56
    , SVGExternalResourcesRequired()
 
57
    , SVGFitToViewBox()
 
58
    , m_x(this, LengthModeWidth)
 
59
    , m_y(this, LengthModeHeight)
 
60
    , m_width(this, LengthModeWidth)
 
61
    , m_height(this, LengthModeHeight)
 
62
    , m_patternUnits(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
 
63
    , m_patternContentUnits(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE)
 
64
    , m_patternTransform(new SVGTransformList)
 
65
{
 
66
}
 
67
 
 
68
SVGPatternElement::~SVGPatternElement()
 
69
{
 
70
}
 
71
 
 
72
ANIMATED_PROPERTY_DEFINITIONS(SVGPatternElement, int, Enumeration, enumeration, PatternUnits, patternUnits, SVGNames::patternUnitsAttr.localName(), m_patternUnits)
 
73
ANIMATED_PROPERTY_DEFINITIONS(SVGPatternElement, int, Enumeration, enumeration, PatternContentUnits, patternContentUnits, SVGNames::patternContentUnitsAttr.localName(), m_patternContentUnits)
 
74
ANIMATED_PROPERTY_DEFINITIONS(SVGPatternElement, SVGLength, Length, length, X, x, SVGNames::xAttr.localName(), m_x)
 
75
ANIMATED_PROPERTY_DEFINITIONS(SVGPatternElement, SVGLength, Length, length, Y, y, SVGNames::yAttr.localName(), m_y)
 
76
ANIMATED_PROPERTY_DEFINITIONS(SVGPatternElement, SVGLength, Length, length, Width, width, SVGNames::widthAttr.localName(), m_width)
 
77
ANIMATED_PROPERTY_DEFINITIONS(SVGPatternElement, SVGLength, Length, length, Height, height, SVGNames::heightAttr.localName(), m_height)
 
78
ANIMATED_PROPERTY_DEFINITIONS(SVGPatternElement, SVGTransformList*, TransformList, transformList, PatternTransform, patternTransform, SVGNames::patternTransformAttr.localName(), m_patternTransform.get())
 
79
 
 
80
void SVGPatternElement::parseMappedAttribute(MappedAttribute* attr)
 
81
{
 
82
    if (attr->name() == SVGNames::patternUnitsAttr) {
 
83
        if (attr->value() == "userSpaceOnUse")
 
84
            setPatternUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE);
 
85
        else if (attr->value() == "objectBoundingBox")
 
86
            setPatternUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
 
87
    } else if (attr->name() == SVGNames::patternContentUnitsAttr) {
 
88
        if (attr->value() == "userSpaceOnUse")
 
89
            setPatternContentUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE);
 
90
        else if (attr->value() == "objectBoundingBox")
 
91
            setPatternContentUnitsBaseValue(SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
 
92
    } else if (attr->name() == SVGNames::patternTransformAttr) {
 
93
        SVGTransformList* patternTransforms = patternTransformBaseValue();
 
94
        if (!SVGTransformable::parseTransformAttribute(patternTransforms, attr->value())) {
 
95
            ExceptionCode ec = 0;
 
96
            patternTransforms->clear(ec);
 
97
        }
 
98
    } else if (attr->name() == SVGNames::xAttr)
 
99
        setXBaseValue(SVGLength(this, LengthModeWidth, attr->value()));
 
100
    else if (attr->name() == SVGNames::yAttr)
 
101
        setYBaseValue(SVGLength(this, LengthModeHeight, attr->value()));
 
102
    else if (attr->name() == SVGNames::widthAttr) {
 
103
        setWidthBaseValue(SVGLength(this, LengthModeWidth, attr->value()));
 
104
        if (width().value() < 0.0)
 
105
            document()->accessSVGExtensions()->reportError("A negative value for pattern attribute <width> is not allowed");
 
106
    } else if (attr->name() == SVGNames::heightAttr) {
 
107
        setHeightBaseValue(SVGLength(this, LengthModeHeight, attr->value()));
 
108
        if (width().value() < 0.0)
 
109
            document()->accessSVGExtensions()->reportError("A negative value for pattern attribute <height> is not allowed");
 
110
    } else {
 
111
        if (SVGURIReference::parseMappedAttribute(attr))
 
112
            return;
 
113
        if (SVGTests::parseMappedAttribute(attr))
 
114
            return;
 
115
        if (SVGLangSpace::parseMappedAttribute(attr))
 
116
            return;
 
117
        if (SVGExternalResourcesRequired::parseMappedAttribute(attr))
 
118
            return;
 
119
        if (SVGFitToViewBox::parseMappedAttribute(attr))
 
120
            return;
 
121
 
 
122
        SVGStyledElement::parseMappedAttribute(attr);
 
123
    }
 
124
}
 
125
 
 
126
void SVGPatternElement::buildPattern(const FloatRect& targetRect) const
 
127
{
 
128
    PatternAttributes attributes = collectPatternProperties();
 
129
 
 
130
    // If we didn't find any pattern content, ignore the request.
 
131
    if (!attributes.patternContentElement())
 
132
        return;
 
133
 
 
134
    // Determine specified pattern size
 
135
    float xValue = narrowPrecisionToFloat(attributes.x());
 
136
    float yValue = narrowPrecisionToFloat(attributes.y());
 
137
    float widthValue = narrowPrecisionToFloat(attributes.width());
 
138
    float heightValue = narrowPrecisionToFloat(attributes.height());
 
139
 
 
140
    if (attributes.boundingBoxMode()) {
 
141
        xValue *= targetRect.width();
 
142
        yValue *= targetRect.height();
 
143
        widthValue *= targetRect.width();
 
144
        heightValue *= targetRect.height();
 
145
    }
 
146
 
 
147
    // As we're allocating buffers here, clip the buffer size to the target object size as upper boundary
 
148
    if (widthValue > targetRect.width())
 
149
        widthValue = targetRect.width();
 
150
 
 
151
    if (heightValue > targetRect.height())
 
152
        heightValue = targetRect.height();
 
153
 
 
154
    auto_ptr<ImageBuffer> patternImage = ImageBuffer::create(IntSize(lroundf(widthValue), lroundf(heightValue)), false);
 
155
    if (!patternImage.get())
 
156
        return;
 
157
 
 
158
    GraphicsContext* context = patternImage->context();
 
159
    ASSERT(context);
 
160
 
 
161
    if (attributes.boundingBoxModeContent()) {
 
162
        context->save();
 
163
        context->scale(FloatSize(targetRect.width(), targetRect.height()));
 
164
    }
 
165
 
 
166
    // Render subtree into ImageBuffer
 
167
    for (Node* n = attributes.patternContentElement()->firstChild(); n; n = n->nextSibling()) {
 
168
        SVGElement* elem = svg_dynamic_cast(n);
 
169
        if (!elem || !elem->isStyled())
 
170
            continue;
 
171
 
 
172
        SVGStyledElement* e = static_cast<SVGStyledElement*>(elem);
 
173
        RenderObject* item = e->renderer();
 
174
        if (!item)
 
175
            continue;
 
176
 
 
177
        ImageBuffer::renderSubtreeToImage(patternImage.get(), item);
 
178
    }
 
179
 
 
180
    if (attributes.boundingBoxModeContent())
 
181
        context->restore();
 
182
 
 
183
    m_resource->setPatternTransform(attributes.patternTransform());
 
184
    m_resource->setPatternBoundaries(FloatRect(xValue, yValue, widthValue, heightValue));
 
185
    m_resource->setTile(patternImage);
 
186
}
 
187
 
 
188
void SVGPatternElement::notifyAttributeChange() const
 
189
{
 
190
    if (!m_resource || !attached() || ownerDocument()->parsing())
 
191
        return;
 
192
 
 
193
    m_resource->invalidate();
 
194
    m_resource->repaintClients();
 
195
}
 
196
 
 
197
RenderObject* SVGPatternElement::createRenderer(RenderArena* arena, RenderStyle*)
 
198
{
 
199
    RenderSVGContainer* patternContainer = new (arena) RenderSVGContainer(this);
 
200
    patternContainer->setDrawsContents(false);
 
201
    return patternContainer;
 
202
}
 
203
 
 
204
SVGResource* SVGPatternElement::canvasResource()
 
205
{
 
206
    if (!m_resource)
 
207
        m_resource = new SVGPaintServerPattern(this);
 
208
 
 
209
    return m_resource.get();
 
210
}
 
211
 
 
212
PatternAttributes SVGPatternElement::collectPatternProperties() const
 
213
{
 
214
    PatternAttributes attributes;
 
215
    HashSet<const SVGPatternElement*> processedPatterns;
 
216
 
 
217
    const SVGPatternElement* current = this;
 
218
    while (current) {
 
219
        if (!attributes.hasX() && current->hasAttribute(SVGNames::xAttr))
 
220
            attributes.setX(current->x().valueAsPercentage());
 
221
 
 
222
        if (!attributes.hasY() && current->hasAttribute(SVGNames::yAttr))
 
223
            attributes.setY(current->y().valueAsPercentage());
 
224
 
 
225
        if (!attributes.hasWidth() && current->hasAttribute(SVGNames::widthAttr))
 
226
            attributes.setWidth(current->width().valueAsPercentage());
 
227
 
 
228
        if (!attributes.hasHeight() && current->hasAttribute(SVGNames::heightAttr))
 
229
            attributes.setHeight(current->height().valueAsPercentage());
 
230
 
 
231
        if (!attributes.hasBoundingBoxMode() && current->hasAttribute(SVGNames::patternUnitsAttr))
 
232
            attributes.setBoundingBoxMode(current->getAttribute(SVGNames::patternUnitsAttr) == "objectBoundingBox");
 
233
 
 
234
        if (!attributes.hasBoundingBoxModeContent() && current->hasAttribute(SVGNames::patternContentUnitsAttr))
 
235
            attributes.setBoundingBoxModeContent(current->getAttribute(SVGNames::patternContentUnitsAttr) == "objectBoundingBox");
 
236
 
 
237
        if (!attributes.hasPatternTransform() && current->hasAttribute(SVGNames::patternTransformAttr))
 
238
            attributes.setPatternTransform(current->patternTransform()->consolidate().matrix());
 
239
 
 
240
        if (!attributes.hasPatternContentElement() && current->hasChildNodes())
 
241
            attributes.setPatternContentElement(current);
 
242
 
 
243
        processedPatterns.add(current);
 
244
 
 
245
        // Respect xlink:href, take attributes from referenced element
 
246
        Node* refNode = ownerDocument()->getElementById(SVGURIReference::getTarget(current->href()));
 
247
        if (refNode && refNode->hasTagName(SVGNames::patternTag)) {
 
248
            current = static_cast<const SVGPatternElement*>(const_cast<const Node*>(refNode));
 
249
 
 
250
            // Cycle detection
 
251
            if (processedPatterns.contains(current))
 
252
                return PatternAttributes();
 
253
        } else
 
254
            current = 0;
 
255
    }
 
256
 
 
257
    return attributes;
 
258
}
 
259
 
 
260
}
 
261
 
 
262
#endif // ENABLE(SVG)
 
263
 
 
264
// vim:ts=4:noet