Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1553)

Unified Diff: Source/core/rendering/svg/RenderSVGResourcePattern.cpp

Issue 453653003: [SVG] DisplayList-based patterns. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: review comments Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: Source/core/rendering/svg/RenderSVGResourcePattern.cpp
diff --git a/Source/core/rendering/svg/RenderSVGResourcePattern.cpp b/Source/core/rendering/svg/RenderSVGResourcePattern.cpp
index a15d4f3813c225a06ade3659b7b2e4fbc96cb201..71d08069dc058d8505b0809293e356a20d0b53e2 100644
--- a/Source/core/rendering/svg/RenderSVGResourcePattern.cpp
+++ b/Source/core/rendering/svg/RenderSVGResourcePattern.cpp
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2006 Nikolas Zimmermann <zimmermann@kde.org>
* Copyright (C) Research In Motion Limited 2010. All rights reserved.
+ * Copyright 2014 The Chromium Authors. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -24,10 +25,19 @@
#include "core/dom/ElementTraversal.h"
#include "core/rendering/svg/SVGRenderingContext.h"
#include "core/svg/SVGFitToViewBox.h"
+#include "core/svg/SVGPatternElement.h"
+#include "platform/graphics/DisplayList.h"
#include "platform/graphics/GraphicsContext.h"
namespace blink {
+struct PatternData {
+ WTF_MAKE_FAST_ALLOCATED;
+public:
+ RefPtr<Pattern> pattern;
+ AffineTransform transform;
+};
+
const RenderSVGResourceType RenderSVGResourcePattern::s_resourceType = PatternResourceType;
RenderSVGResourcePattern::RenderSVGResourcePattern(SVGPatternElement* node)
@@ -50,63 +60,57 @@ void RenderSVGResourcePattern::removeClientFromCache(RenderObject* client, bool
markClientForInvalidation(client, markForInvalidation ? PaintInvalidation : ParentOnlyInvalidation);
}
-PatternData* RenderSVGResourcePattern::buildPattern(const RenderObject& object, const SVGPatternElement* patternElement)
+PatternData* RenderSVGResourcePattern::patternForRenderer(const RenderObject& object)
{
- PatternData* currentData = m_patternMap.get(&object);
- if (currentData && currentData->pattern)
- return currentData;
+ OwnPtr<PatternData>& patternData = m_patternMap.add(&object, nullptr).storedValue->value;
Stephen White 2014/10/22 15:11:26 Nit: This seems a bit of a convoluted way to use a
f(malita) 2014/10/22 16:23:47 I agree it's convoluted, but it avoids a double ha
Stephen White 2014/10/22 17:50:48 Acknowledged.
+ if (!patternData)
+ patternData = buildPatternData(object);
+
+ ASSERT(!m_shouldCollectPatternAttributes);
+ return patternData.get();
+}
+PassOwnPtr<PatternData> RenderSVGResourcePattern::buildPatternData(const RenderObject& object)
+{
// If we couldn't determine the pattern content element root, stop here.
if (!m_attributes.patternContentElement())
- return 0;
+ return nullptr;
// An empty viewBox disables rendering.
if (m_attributes.hasViewBox() && m_attributes.viewBox().isEmpty())
- return 0;
-
- // Compute all necessary transformations to build the tile image & the pattern.
- FloatRect tileBoundaries;
- AffineTransform tileImageTransform;
- if (!buildTileImageTransform(object, m_attributes, patternElement, tileBoundaries, tileImageTransform))
- return 0;
-
- AffineTransform absoluteTransformIgnoringRotation;
- SVGRenderingContext::calculateDeviceSpaceTransformation(&object, absoluteTransformIgnoringRotation);
-
- // Ignore 2D rotation, as it doesn't affect the size of the tile.
- SVGRenderingContext::clear2DRotation(absoluteTransformIgnoringRotation);
- FloatRect absoluteTileBoundaries = absoluteTransformIgnoringRotation.mapRect(tileBoundaries);
-
- // Scale the tile size to match the scale level of the patternTransform.
- absoluteTileBoundaries.scale(static_cast<float>(m_attributes.patternTransform().xScale()),
- static_cast<float>(m_attributes.patternTransform().yScale()));
+ return nullptr;
- // Build tile image.
- OwnPtr<ImageBuffer> tileImage = createTileImage(m_attributes, tileBoundaries, absoluteTileBoundaries, tileImageTransform);
- if (!tileImage)
- return 0;
+ ASSERT(element());
+ // Compute tile metrics.
+ FloatRect clientBoundingBox = object.objectBoundingBox();
+ FloatRect tileBounds = SVGLengthContext::resolveRectangle(element(),
+ m_attributes.patternUnits(), clientBoundingBox,
+ m_attributes.x(), m_attributes.y(), m_attributes.width(), m_attributes.height());
+ if (tileBounds.isEmpty())
+ return nullptr;
- RefPtr<Image> copiedImage = tileImage->copyImage(CopyBackingStore);
- if (!copiedImage)
- return 0;
+ AffineTransform tileTransform;
+ if (m_attributes.hasViewBox()) {
+ if (m_attributes.viewBox().isEmpty())
+ return nullptr;
+ tileTransform = SVGFitToViewBox::viewBoxToViewTransform(m_attributes.viewBox(),
+ m_attributes.preserveAspectRatio(), tileBounds.width(), tileBounds.height());
+ } else {
+ // A viewbox overrides patternContentUnits, per spec.
+ if (m_attributes.patternContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
+ tileTransform.scale(clientBoundingBox.width(), clientBoundingBox.height());
+ }
- // Build pattern.
OwnPtr<PatternData> patternData = adoptPtr(new PatternData);
- patternData->pattern = Pattern::createBitmapPattern(copiedImage);
+ patternData->pattern = Pattern::createDisplayListPattern(asDisplayList(tileBounds, tileTransform));
// Compute pattern space transformation.
- const IntSize tileImageSize = tileImage->size();
- patternData->transform.translate(tileBoundaries.x(), tileBoundaries.y());
- patternData->transform.scale(tileBoundaries.width() / tileImageSize.width(), tileBoundaries.height() / tileImageSize.height());
-
+ patternData->transform.translate(tileBounds.x(), tileBounds.y());
AffineTransform patternTransform = m_attributes.patternTransform();
if (!patternTransform.isIdentity())
patternData->transform = patternTransform * patternData->transform;
- // Various calls above may trigger invalidations in some fringe cases (ImageBuffer allocation
- // failures in the SVG image cache for example). To avoid having our PatternData deleted by
- // removeAllClientsFromCache(), we only make it visible in the cache at the very end.
- return m_patternMap.set(&object, patternData.release()).storedValue->value.get();
+ return patternData.release();
}
SVGPaintServer RenderSVGResourcePattern::preparePaintServer(const RenderObject& object)
@@ -131,7 +135,7 @@ SVGPaintServer RenderSVGResourcePattern::preparePaintServer(const RenderObject&
if (m_attributes.patternUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX && objectBoundingBox.isEmpty())
return SVGPaintServer::invalid();
- PatternData* patternData = buildPattern(object, patternElement);
+ PatternData* patternData = patternForRenderer(object);
if (!patternData)
return SVGPaintServer::invalid();
@@ -140,80 +144,30 @@ SVGPaintServer RenderSVGResourcePattern::preparePaintServer(const RenderObject&
return SVGPaintServer(patternData->pattern);
}
-static inline FloatRect calculatePatternBoundaries(const PatternAttributes& attributes,
- const FloatRect& objectBoundingBox,
- const SVGPatternElement* patternElement)
-{
- ASSERT(patternElement);
- return SVGLengthContext::resolveRectangle(patternElement, attributes.patternUnits(), objectBoundingBox, attributes.x(), attributes.y(), attributes.width(), attributes.height());
-}
-
-bool RenderSVGResourcePattern::buildTileImageTransform(const RenderObject& renderer,
- const PatternAttributes& attributes,
- const SVGPatternElement* patternElement,
- FloatRect& patternBoundaries,
- AffineTransform& tileImageTransform) const
+PassRefPtr<DisplayList> RenderSVGResourcePattern::asDisplayList(const FloatRect& tileBounds,
+ const AffineTransform& tileTransform) const
{
- ASSERT(patternElement);
+ ASSERT(!m_shouldCollectPatternAttributes);
- FloatRect objectBoundingBox = renderer.objectBoundingBox();
- patternBoundaries = calculatePatternBoundaries(attributes, objectBoundingBox, patternElement);
- if (patternBoundaries.width() <= 0 || patternBoundaries.height() <= 0)
- return false;
+ AffineTransform contentTransform;
+ if (m_attributes.patternContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
+ contentTransform = tileTransform;
- AffineTransform viewBoxCTM = SVGFitToViewBox::viewBoxToViewTransform(attributes.viewBox(), attributes.preserveAspectRatio(), patternBoundaries.width(), patternBoundaries.height());
+ // Draw the content into a DisplayList.
+ GraphicsContext recordingContext(nullptr);
+ recordingContext.beginRecording(FloatRect(FloatPoint(), tileBounds.size()));
+ recordingContext.concatCTM(tileTransform);
- // Apply viewBox/objectBoundingBox transformations.
- if (!viewBoxCTM.isIdentity())
- tileImageTransform = viewBoxCTM;
- else if (attributes.patternContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
- tileImageTransform.scale(objectBoundingBox.width(), objectBoundingBox.height());
+ ASSERT(m_attributes.patternContentElement());
+ RenderSVGResourceContainer* patternRenderer =
+ toRenderSVGResourceContainer(m_attributes.patternContentElement()->renderer());
+ ASSERT(patternRenderer);
+ ASSERT(!patternRenderer->needsLayout());
- return true;
-}
-
-PassOwnPtr<ImageBuffer> RenderSVGResourcePattern::createTileImage(const PatternAttributes& attributes,
- const FloatRect& tileBoundaries,
- const FloatRect& absoluteTileBoundaries,
- const AffineTransform& tileImageTransform) const
-{
- FloatRect clampedAbsoluteTileBoundaries = SVGRenderingContext::clampedAbsoluteTargetRect(absoluteTileBoundaries);
-
- IntSize imageSize(roundedIntSize(clampedAbsoluteTileBoundaries.size()));
- if (imageSize.isEmpty())
- return nullptr;
- OwnPtr<ImageBuffer> tileImage = ImageBuffer::create(imageSize);
- if (!tileImage)
- return nullptr;
-
- GraphicsContext* tileImageContext = tileImage->context();
- ASSERT(tileImageContext);
- IntSize unclampedImageSize(roundedIntSize(absoluteTileBoundaries.size()));
- tileImageContext->scale(unclampedImageSize.width() / absoluteTileBoundaries.width(), unclampedImageSize.height() / absoluteTileBoundaries.height());
-
- // The image buffer represents the final rendered size, so the content has to be scaled (to avoid pixelation).
- tileImageContext->scale(
- clampedAbsoluteTileBoundaries.width() / tileBoundaries.width(),
- clampedAbsoluteTileBoundaries.height() / tileBoundaries.height());
-
- // Apply tile image transformations.
- if (!tileImageTransform.isIdentity())
- tileImageContext->concatCTM(tileImageTransform);
-
- AffineTransform contentTransformation;
- if (attributes.patternContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX)
- contentTransformation = tileImageTransform;
-
- // Draw the content into the ImageBuffer.
- for (SVGElement* element = Traversal<SVGElement>::firstChild(*attributes.patternContentElement()); element; element = Traversal<SVGElement>::nextSibling(*element)) {
- if (!element->renderer())
- continue;
- if (element->renderer()->needsLayout())
- return nullptr;
- SVGRenderingContext::renderSubtree(tileImage->context(), element->renderer(), contentTransformation);
- }
+ for (RenderObject* child = patternRenderer->firstChild(); child; child = child->nextSibling())
+ SVGRenderingContext::renderSubtree(&recordingContext, child, contentTransform);
- return tileImage.release();
+ return recordingContext.endRecording();
}
}

Powered by Google App Engine
This is Rietveld 408576698