121939df44de1705786c545cd1bf519d47250322dBen Murdoch/*
221939df44de1705786c545cd1bf519d47250322dBen Murdoch * Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
321939df44de1705786c545cd1bf519d47250322dBen Murdoch * Copyright (C) Research In Motion Limited 2010. All rights reserved.
421939df44de1705786c545cd1bf519d47250322dBen Murdoch *
521939df44de1705786c545cd1bf519d47250322dBen Murdoch * This library is free software; you can redistribute it and/or
621939df44de1705786c545cd1bf519d47250322dBen Murdoch * modify it under the terms of the GNU Library General Public
721939df44de1705786c545cd1bf519d47250322dBen Murdoch * License as published by the Free Software Foundation; either
821939df44de1705786c545cd1bf519d47250322dBen Murdoch * version 2 of the License, or (at your option) any later version.
921939df44de1705786c545cd1bf519d47250322dBen Murdoch *
1021939df44de1705786c545cd1bf519d47250322dBen Murdoch * This library is distributed in the hope that it will be useful,
1121939df44de1705786c545cd1bf519d47250322dBen Murdoch * but WITHOUT ANY WARRANTY; without even the implied warranty of
1221939df44de1705786c545cd1bf519d47250322dBen Murdoch * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1321939df44de1705786c545cd1bf519d47250322dBen Murdoch * Library General Public License for more details.
1421939df44de1705786c545cd1bf519d47250322dBen Murdoch *
1521939df44de1705786c545cd1bf519d47250322dBen Murdoch * You should have received a copy of the GNU Library General Public License
1621939df44de1705786c545cd1bf519d47250322dBen Murdoch * along with this library; see the file COPYING.LIB.  If not, write to
1721939df44de1705786c545cd1bf519d47250322dBen Murdoch * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
1821939df44de1705786c545cd1bf519d47250322dBen Murdoch * Boston, MA 02110-1301, USA.
1921939df44de1705786c545cd1bf519d47250322dBen Murdoch */
2021939df44de1705786c545cd1bf519d47250322dBen Murdoch
2121939df44de1705786c545cd1bf519d47250322dBen Murdoch#include "config.h"
2221939df44de1705786c545cd1bf519d47250322dBen Murdoch
2321939df44de1705786c545cd1bf519d47250322dBen Murdoch#if ENABLE(SVG)
2421939df44de1705786c545cd1bf519d47250322dBen Murdoch#include "RenderSVGResourcePattern.h"
2521939df44de1705786c545cd1bf519d47250322dBen Murdoch
26ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block#include "FrameView.h"
2721939df44de1705786c545cd1bf519d47250322dBen Murdoch#include "GraphicsContext.h"
2821939df44de1705786c545cd1bf519d47250322dBen Murdoch#include "PatternAttributes.h"
29e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block#include "RenderSVGRoot.h"
30e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block#include "SVGImageBufferTools.h"
3121939df44de1705786c545cd1bf519d47250322dBen Murdoch#include "SVGRenderSupport.h"
3221939df44de1705786c545cd1bf519d47250322dBen Murdoch
3321939df44de1705786c545cd1bf519d47250322dBen Murdochnamespace WebCore {
3421939df44de1705786c545cd1bf519d47250322dBen Murdoch
3521939df44de1705786c545cd1bf519d47250322dBen MurdochRenderSVGResourceType RenderSVGResourcePattern::s_resourceType = PatternResourceType;
3621939df44de1705786c545cd1bf519d47250322dBen Murdoch
3721939df44de1705786c545cd1bf519d47250322dBen MurdochRenderSVGResourcePattern::RenderSVGResourcePattern(SVGPatternElement* node)
3821939df44de1705786c545cd1bf519d47250322dBen Murdoch    : RenderSVGResourceContainer(node)
39a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    , m_shouldCollectPatternAttributes(true)
4021939df44de1705786c545cd1bf519d47250322dBen Murdoch{
4121939df44de1705786c545cd1bf519d47250322dBen Murdoch}
4221939df44de1705786c545cd1bf519d47250322dBen Murdoch
4321939df44de1705786c545cd1bf519d47250322dBen MurdochRenderSVGResourcePattern::~RenderSVGResourcePattern()
4421939df44de1705786c545cd1bf519d47250322dBen Murdoch{
45db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block    if (m_pattern.isEmpty())
46db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block        return;
4721939df44de1705786c545cd1bf519d47250322dBen Murdoch
4821939df44de1705786c545cd1bf519d47250322dBen Murdoch    deleteAllValues(m_pattern);
4921939df44de1705786c545cd1bf519d47250322dBen Murdoch    m_pattern.clear();
5021939df44de1705786c545cd1bf519d47250322dBen Murdoch}
5121939df44de1705786c545cd1bf519d47250322dBen Murdoch
52f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrickvoid RenderSVGResourcePattern::removeAllClientsFromCache(bool markForInvalidation)
5321939df44de1705786c545cd1bf519d47250322dBen Murdoch{
54db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block    if (!m_pattern.isEmpty()) {
55db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block        deleteAllValues(m_pattern);
56db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block        m_pattern.clear();
57db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block    }
5821939df44de1705786c545cd1bf519d47250322dBen Murdoch
59a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    m_shouldCollectPatternAttributes = true;
60f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    markAllClientsForInvalidation(markForInvalidation ? RepaintInvalidation : ParentOnlyInvalidation);
61967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch}
62967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
63f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrickvoid RenderSVGResourcePattern::removeClientFromCache(RenderObject* client, bool markForInvalidation)
64967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch{
65db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block    ASSERT(client);
66967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
67db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block    if (m_pattern.contains(client))
68db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block        delete m_pattern.take(client);
69967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch
70f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    markClientForInvalidation(client, markForInvalidation ? RepaintInvalidation : ParentOnlyInvalidation);
7121939df44de1705786c545cd1bf519d47250322dBen Murdoch}
7221939df44de1705786c545cd1bf519d47250322dBen Murdoch
7321939df44de1705786c545cd1bf519d47250322dBen Murdochbool RenderSVGResourcePattern::applyResource(RenderObject* object, RenderStyle* style, GraphicsContext*& context, unsigned short resourceMode)
7421939df44de1705786c545cd1bf519d47250322dBen Murdoch{
7521939df44de1705786c545cd1bf519d47250322dBen Murdoch    ASSERT(object);
7621939df44de1705786c545cd1bf519d47250322dBen Murdoch    ASSERT(style);
7721939df44de1705786c545cd1bf519d47250322dBen Murdoch    ASSERT(context);
7821939df44de1705786c545cd1bf519d47250322dBen Murdoch    ASSERT(resourceMode != ApplyToDefaultMode);
7921939df44de1705786c545cd1bf519d47250322dBen Murdoch
8021939df44de1705786c545cd1bf519d47250322dBen Murdoch    // Be sure to synchronize all SVG properties on the patternElement _before_ processing any further.
81e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    // Otherwhise the call to collectPatternAttributes() below, may cause the SVG DOM property
82f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    // synchronization to kick in, which causes removeAllClientsFromCache() to be called, which in turn deletes our
8321939df44de1705786c545cd1bf519d47250322dBen Murdoch    // PatternData object! Leaving out the line below will cause svg/dynamic-updates/SVGPatternElement-svgdom* to crash.
8421939df44de1705786c545cd1bf519d47250322dBen Murdoch    SVGPatternElement* patternElement = static_cast<SVGPatternElement*>(node());
8521939df44de1705786c545cd1bf519d47250322dBen Murdoch    if (!patternElement)
8621939df44de1705786c545cd1bf519d47250322dBen Murdoch        return false;
8721939df44de1705786c545cd1bf519d47250322dBen Murdoch
88a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (m_shouldCollectPatternAttributes) {
89a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        patternElement->updateAnimatedSVGAttribute(anyQName());
90a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
91a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        m_attributes = PatternAttributes();
92a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        patternElement->collectPatternAttributes(m_attributes);
93a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        m_shouldCollectPatternAttributes = false;
94a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
95a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
96a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // Spec: When the geometry of the applicable element has no width or height and objectBoundingBox is specified,
97a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // then the given effect (e.g. a gradient or a filter) will be ignored.
98a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    FloatRect objectBoundingBox = object->objectBoundingBox();
99a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (m_attributes.boundingBoxMode() && objectBoundingBox.isEmpty())
100a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        return false;
10121939df44de1705786c545cd1bf519d47250322dBen Murdoch
10221939df44de1705786c545cd1bf519d47250322dBen Murdoch    if (!m_pattern.contains(object))
10321939df44de1705786c545cd1bf519d47250322dBen Murdoch        m_pattern.set(object, new PatternData);
10421939df44de1705786c545cd1bf519d47250322dBen Murdoch
10521939df44de1705786c545cd1bf519d47250322dBen Murdoch    PatternData* patternData = m_pattern.get(object);
10621939df44de1705786c545cd1bf519d47250322dBen Murdoch    if (!patternData->pattern) {
107e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        // If we couldn't determine the pattern content element root, stop here.
108a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (!m_attributes.patternContentElement())
109e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block            return false;
110e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
111e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        // Compute all necessary transformations to build the tile image & the pattern.
112e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        FloatRect tileBoundaries;
113a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        AffineTransform tileImageTransform;
114a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (!buildTileImageTransform(object, m_attributes, patternElement, tileBoundaries, tileImageTransform))
115a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            return false;
116e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
117e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        AffineTransform absoluteTransform;
118e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform);
119e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
120e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        FloatRect absoluteTileBoundaries = absoluteTransform.mapRect(tileBoundaries);
121e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
122e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        // Build tile image.
123a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        OwnPtr<ImageBuffer> tileImage = createTileImage(object, m_attributes, tileBoundaries, absoluteTileBoundaries, tileImageTransform);
12421939df44de1705786c545cd1bf519d47250322dBen Murdoch        if (!tileImage)
12521939df44de1705786c545cd1bf519d47250322dBen Murdoch            return false;
12621939df44de1705786c545cd1bf519d47250322dBen Murdoch
127e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        RefPtr<Image> copiedImage = tileImage->copyImage();
128e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        if (!copiedImage)
129e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block            return false;
13021939df44de1705786c545cd1bf519d47250322dBen Murdoch
131e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        // Build pattern.
132e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        patternData->pattern = Pattern::create(copiedImage, true, true);
13321939df44de1705786c545cd1bf519d47250322dBen Murdoch        if (!patternData->pattern)
13421939df44de1705786c545cd1bf519d47250322dBen Murdoch            return false;
13521939df44de1705786c545cd1bf519d47250322dBen Murdoch
136e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        // Compute pattern space transformation.
137e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        patternData->transform.translate(tileBoundaries.x(), tileBoundaries.y());
138e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        patternData->transform.scale(tileBoundaries.width() / absoluteTileBoundaries.width(), tileBoundaries.height() / absoluteTileBoundaries.height());
139e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
140a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        AffineTransform patternTransform = m_attributes.patternTransform();
141e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        if (!patternTransform.isIdentity())
142ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch            patternData->transform = patternTransform * patternData->transform;
143e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
144545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        patternData->pattern->setPatternSpaceTransform(patternData->transform);
14521939df44de1705786c545cd1bf519d47250322dBen Murdoch    }
14621939df44de1705786c545cd1bf519d47250322dBen Murdoch
14721939df44de1705786c545cd1bf519d47250322dBen Murdoch    // Draw pattern
14821939df44de1705786c545cd1bf519d47250322dBen Murdoch    context->save();
14921939df44de1705786c545cd1bf519d47250322dBen Murdoch
15021939df44de1705786c545cd1bf519d47250322dBen Murdoch    const SVGRenderStyle* svgStyle = style->svgStyle();
15121939df44de1705786c545cd1bf519d47250322dBen Murdoch    ASSERT(svgStyle);
15221939df44de1705786c545cd1bf519d47250322dBen Murdoch
15321939df44de1705786c545cd1bf519d47250322dBen Murdoch    if (resourceMode & ApplyToFillMode) {
15421939df44de1705786c545cd1bf519d47250322dBen Murdoch        context->setAlpha(svgStyle->fillOpacity());
15521939df44de1705786c545cd1bf519d47250322dBen Murdoch        context->setFillPattern(patternData->pattern);
15621939df44de1705786c545cd1bf519d47250322dBen Murdoch        context->setFillRule(svgStyle->fillRule());
15721939df44de1705786c545cd1bf519d47250322dBen Murdoch    } else if (resourceMode & ApplyToStrokeMode) {
158545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch        if (svgStyle->vectorEffect() == VE_NON_SCALING_STROKE)
159545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch            patternData->pattern->setPatternSpaceTransform(transformOnNonScalingStroke(object, patternData->transform));
16021939df44de1705786c545cd1bf519d47250322dBen Murdoch        context->setAlpha(svgStyle->strokeOpacity());
16121939df44de1705786c545cd1bf519d47250322dBen Murdoch        context->setStrokePattern(patternData->pattern);
162ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block        SVGRenderSupport::applyStrokeStyleToContext(context, style, object);
16321939df44de1705786c545cd1bf519d47250322dBen Murdoch    }
16421939df44de1705786c545cd1bf519d47250322dBen Murdoch
16521939df44de1705786c545cd1bf519d47250322dBen Murdoch    if (resourceMode & ApplyToTextMode) {
16621939df44de1705786c545cd1bf519d47250322dBen Murdoch        if (resourceMode & ApplyToFillMode) {
167f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            context->setTextDrawingMode(TextModeFill);
16821939df44de1705786c545cd1bf519d47250322dBen Murdoch
1692daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#if USE(CG)
17021939df44de1705786c545cd1bf519d47250322dBen Murdoch            context->applyFillPattern();
17121939df44de1705786c545cd1bf519d47250322dBen Murdoch#endif
17221939df44de1705786c545cd1bf519d47250322dBen Murdoch        } else if (resourceMode & ApplyToStrokeMode) {
173f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            context->setTextDrawingMode(TextModeStroke);
17421939df44de1705786c545cd1bf519d47250322dBen Murdoch
1752daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#if USE(CG)
17621939df44de1705786c545cd1bf519d47250322dBen Murdoch            context->applyStrokePattern();
17721939df44de1705786c545cd1bf519d47250322dBen Murdoch#endif
17821939df44de1705786c545cd1bf519d47250322dBen Murdoch        }
17921939df44de1705786c545cd1bf519d47250322dBen Murdoch    }
18021939df44de1705786c545cd1bf519d47250322dBen Murdoch
18121939df44de1705786c545cd1bf519d47250322dBen Murdoch    return true;
18221939df44de1705786c545cd1bf519d47250322dBen Murdoch}
18321939df44de1705786c545cd1bf519d47250322dBen Murdoch
184f05b935882198ccf7d81675736e3aeb089c5113aBen Murdochvoid RenderSVGResourcePattern::postApplyResource(RenderObject*, GraphicsContext*& context, unsigned short resourceMode, const Path* path)
18521939df44de1705786c545cd1bf519d47250322dBen Murdoch{
18621939df44de1705786c545cd1bf519d47250322dBen Murdoch    ASSERT(context);
18721939df44de1705786c545cd1bf519d47250322dBen Murdoch    ASSERT(resourceMode != ApplyToDefaultMode);
18821939df44de1705786c545cd1bf519d47250322dBen Murdoch
189f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch    if (path && !(resourceMode & ApplyToTextMode)) {
19021939df44de1705786c545cd1bf519d47250322dBen Murdoch        if (resourceMode & ApplyToFillMode)
191f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            context->fillPath(*path);
19221939df44de1705786c545cd1bf519d47250322dBen Murdoch        else if (resourceMode & ApplyToStrokeMode)
193f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch            context->strokePath(*path);
19421939df44de1705786c545cd1bf519d47250322dBen Murdoch    }
19521939df44de1705786c545cd1bf519d47250322dBen Murdoch
19621939df44de1705786c545cd1bf519d47250322dBen Murdoch    context->restore();
19721939df44de1705786c545cd1bf519d47250322dBen Murdoch}
19821939df44de1705786c545cd1bf519d47250322dBen Murdoch
199e8b154fd68f9b33be40a3590e58347f353835f5cSteve Blockstatic inline FloatRect calculatePatternBoundaries(const PatternAttributes& attributes,
20021939df44de1705786c545cd1bf519d47250322dBen Murdoch                                                   const FloatRect& objectBoundingBox,
20121939df44de1705786c545cd1bf519d47250322dBen Murdoch                                                   const SVGPatternElement* patternElement)
20221939df44de1705786c545cd1bf519d47250322dBen Murdoch{
203e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    ASSERT(patternElement);
204e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block
20521939df44de1705786c545cd1bf519d47250322dBen Murdoch    if (attributes.boundingBoxMode())
206e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        return FloatRect(attributes.x().valueAsPercentage() * objectBoundingBox.width() + objectBoundingBox.x(),
207e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block                         attributes.y().valueAsPercentage() * objectBoundingBox.height() + objectBoundingBox.y(),
20821939df44de1705786c545cd1bf519d47250322dBen Murdoch                         attributes.width().valueAsPercentage() * objectBoundingBox.width(),
20921939df44de1705786c545cd1bf519d47250322dBen Murdoch                         attributes.height().valueAsPercentage() * objectBoundingBox.height());
21021939df44de1705786c545cd1bf519d47250322dBen Murdoch
21121939df44de1705786c545cd1bf519d47250322dBen Murdoch    return FloatRect(attributes.x().value(patternElement),
21221939df44de1705786c545cd1bf519d47250322dBen Murdoch                     attributes.y().value(patternElement),
21321939df44de1705786c545cd1bf519d47250322dBen Murdoch                     attributes.width().value(patternElement),
21421939df44de1705786c545cd1bf519d47250322dBen Murdoch                     attributes.height().value(patternElement));
21521939df44de1705786c545cd1bf519d47250322dBen Murdoch}
21621939df44de1705786c545cd1bf519d47250322dBen Murdoch
217a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochbool RenderSVGResourcePattern::buildTileImageTransform(RenderObject* renderer,
218a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                                                       const PatternAttributes& attributes,
219a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                                                       const SVGPatternElement* patternElement,
220a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                                                       FloatRect& patternBoundaries,
221a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                                                       AffineTransform& tileImageTransform) const
22221939df44de1705786c545cd1bf519d47250322dBen Murdoch{
223e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    ASSERT(renderer);
224e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    ASSERT(patternElement);
22521939df44de1705786c545cd1bf519d47250322dBen Murdoch
226a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    FloatRect objectBoundingBox = renderer->objectBoundingBox();
227e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    patternBoundaries = calculatePatternBoundaries(attributes, objectBoundingBox, patternElement);
228a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (patternBoundaries.width() <= 0 || patternBoundaries.height() <= 0)
229a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        return false;
23021939df44de1705786c545cd1bf519d47250322dBen Murdoch
231ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch    AffineTransform viewBoxCTM = patternElement->viewBoxToViewTransform(attributes.viewBox(), attributes.preserveAspectRatio(), patternBoundaries.width(), patternBoundaries.height());
23221939df44de1705786c545cd1bf519d47250322dBen Murdoch
233e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    // Apply viewBox/objectBoundingBox transformations.
23421939df44de1705786c545cd1bf519d47250322dBen Murdoch    if (!viewBoxCTM.isIdentity())
235e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        tileImageTransform = viewBoxCTM;
23681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    else if (attributes.boundingBoxModeContent())
237e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        tileImageTransform.scale(objectBoundingBox.width(), objectBoundingBox.height());
238ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block
239a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    return true;
240ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block}
241ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block
242e8b154fd68f9b33be40a3590e58347f353835f5cSteve BlockPassOwnPtr<ImageBuffer> RenderSVGResourcePattern::createTileImage(RenderObject* object,
243e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block                                                                  const PatternAttributes& attributes,
244e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block                                                                  const FloatRect& tileBoundaries,
245e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block                                                                  const FloatRect& absoluteTileBoundaries,
246e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block                                                                  const AffineTransform& tileImageTransform) const
24721939df44de1705786c545cd1bf519d47250322dBen Murdoch{
248e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    ASSERT(object);
24921939df44de1705786c545cd1bf519d47250322dBen Murdoch
250e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    // Clamp tile image size against SVG viewport size, as last resort, to avoid allocating huge image buffers.
251e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    FloatRect contentBoxRect = SVGRenderSupport::findTreeRootObject(object)->contentBoxRect();
25221939df44de1705786c545cd1bf519d47250322dBen Murdoch
253e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    FloatRect clampedAbsoluteTileBoundaries = absoluteTileBoundaries;
254e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    if (clampedAbsoluteTileBoundaries.width() > contentBoxRect.width())
255e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        clampedAbsoluteTileBoundaries.setWidth(contentBoxRect.width());
25621939df44de1705786c545cd1bf519d47250322dBen Murdoch
257e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    if (clampedAbsoluteTileBoundaries.height() > contentBoxRect.height())
258e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        clampedAbsoluteTileBoundaries.setHeight(contentBoxRect.height());
25921939df44de1705786c545cd1bf519d47250322dBen Murdoch
260e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    OwnPtr<ImageBuffer> tileImage;
26121939df44de1705786c545cd1bf519d47250322dBen Murdoch
262a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (!SVGImageBufferTools::createImageBuffer(absoluteTileBoundaries, clampedAbsoluteTileBoundaries, tileImage, ColorSpaceDeviceRGB))
263e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        return PassOwnPtr<ImageBuffer>();
26421939df44de1705786c545cd1bf519d47250322dBen Murdoch
265e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    GraphicsContext* tileImageContext = tileImage->context();
266e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    ASSERT(tileImageContext);
26721939df44de1705786c545cd1bf519d47250322dBen Murdoch
268e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    // The image buffer represents the final rendered size, so the content has to be scaled (to avoid pixelation).
269e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    tileImageContext->scale(FloatSize(absoluteTileBoundaries.width() / tileBoundaries.width(),
270e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block                                      absoluteTileBoundaries.height() / tileBoundaries.height()));
27121939df44de1705786c545cd1bf519d47250322dBen Murdoch
272e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    // Apply tile image transformations.
273e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    if (!tileImageTransform.isIdentity())
274e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        tileImageContext->concatCTM(tileImageTransform);
27521939df44de1705786c545cd1bf519d47250322dBen Murdoch
276e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    AffineTransform contentTransformation;
27781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    if (attributes.boundingBoxModeContent())
27881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch        contentTransformation = tileImageTransform;
27921939df44de1705786c545cd1bf519d47250322dBen Murdoch
280e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block    // Draw the content into the ImageBuffer.
28121939df44de1705786c545cd1bf519d47250322dBen Murdoch    for (Node* node = attributes.patternContentElement()->firstChild(); node; node = node->nextSibling()) {
28221939df44de1705786c545cd1bf519d47250322dBen Murdoch        if (!node->isSVGElement() || !static_cast<SVGElement*>(node)->isStyled() || !node->renderer())
28321939df44de1705786c545cd1bf519d47250322dBen Murdoch            continue;
284e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block        SVGImageBufferTools::renderSubtreeToImageBuffer(tileImage.get(), node->renderer(), contentTransformation);
28521939df44de1705786c545cd1bf519d47250322dBen Murdoch    }
28621939df44de1705786c545cd1bf519d47250322dBen Murdoch
28721939df44de1705786c545cd1bf519d47250322dBen Murdoch    return tileImage.release();
28821939df44de1705786c545cd1bf519d47250322dBen Murdoch}
28921939df44de1705786c545cd1bf519d47250322dBen Murdoch
29021939df44de1705786c545cd1bf519d47250322dBen Murdoch}
29121939df44de1705786c545cd1bf519d47250322dBen Murdoch
29221939df44de1705786c545cd1bf519d47250322dBen Murdoch#endif
293