diff options
author | Florin Malita <fmalita@chromium.org> | 2013-02-06 17:58:42 +0100 |
---|---|---|
committer | The Qt Project <gerrit-noreply@qt-project.org> | 2013-02-07 19:21:20 +0100 |
commit | f47c0b0c6d7a96558273254f014d7515c04b42fb (patch) | |
tree | f8557ec77399ac031033c832ad4cd947b1a544b6 /Source/WebCore/rendering | |
parent | 659c84da41ad75ebd446ec6549f66e60263e1430 (diff) | |
download | qtwebkit-f47c0b0c6d7a96558273254f014d7515c04b42fb.tar.gz |
SVG pattern data deleted while in use
https://bugs.webkit.org/show_bug.cgi?id=103415
Reviewed by Dirk Schulze.
Various calls in RenderSVGResourcePattern::applyResource() can trigger invalidations,
which may end up deleting our current pattern data (via removeAllClientsFromCache).
To avoid this, we should add the pattern data to the cache only after it is fully built.
For clarity, the patch also refactors the pattern setup code into a separate method.
Test: svg/custom/large-image-pattern-crash.html
* rendering/svg/RenderSVGResourcePattern.cpp:
(WebCore::RenderSVGResourcePattern::buildPattern):
(WebCore::RenderSVGResourcePattern::applyResource):
* rendering/svg/RenderSVGResourcePattern.h:
(RenderSVGResourcePattern):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@136250 268f45cc-cd09-0410-ab3c-d52691b4dbfc
Change-Id: I1ad128e056f7825727e2d1a9f365dd5f1aa2e4fa
Reviewed-by: Jocelyn Turcotte <jocelyn.turcotte@digia.com>
Diffstat (limited to 'Source/WebCore/rendering')
-rw-r--r-- | Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp | 139 | ||||
-rw-r--r-- | Source/WebCore/rendering/svg/RenderSVGResourcePattern.h | 2 |
2 files changed, 74 insertions, 67 deletions
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp b/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp index b3c0b0bd1..55dbb8319 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp @@ -55,20 +55,15 @@ void RenderSVGResourcePattern::removeClientFromCache(RenderObject* client, bool markClientForInvalidation(client, markForInvalidation ? RepaintInvalidation : ParentOnlyInvalidation); } -bool RenderSVGResourcePattern::applyResource(RenderObject* object, RenderStyle* style, GraphicsContext*& context, unsigned short resourceMode) +PatternData* RenderSVGResourcePattern::buildPattern(RenderObject* object, unsigned short resourceMode) { - ASSERT(object); - ASSERT(style); - ASSERT(context); - ASSERT(resourceMode != ApplyToDefaultMode); + PatternData* currentData = m_patternMap.get(object); + if (currentData && currentData->pattern) + return currentData; - // Be sure to synchronize all SVG properties on the patternElement _before_ processing any further. - // Otherwhise the call to collectPatternAttributes() below, may cause the SVG DOM property - // synchronization to kick in, which causes removeAllClientsFromCache() to be called, which in turn deletes our - // PatternData object! Leaving out the line below will cause svg/dynamic-updates/SVGPatternElement-svgdom* to crash. SVGPatternElement* patternElement = static_cast<SVGPatternElement*>(node()); if (!patternElement) - return false; + return 0; if (m_shouldCollectPatternAttributes) { patternElement->updateAnimatedSVGAttribute(anyQName()); @@ -78,70 +73,80 @@ bool RenderSVGResourcePattern::applyResource(RenderObject* object, RenderStyle* m_shouldCollectPatternAttributes = false; } + // If we couldn't determine the pattern content element root, stop here. + if (!m_attributes.patternContentElement()) + 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::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransformIgnoringRotation); + + // Ignore 2D rotation, as it doesn't affect the size of the tile. + SVGRenderingContext::clear2DRotation(absoluteTransformIgnoringRotation); + FloatRect absoluteTileBoundaries = absoluteTransformIgnoringRotation.mapRect(tileBoundaries); + FloatRect clampedAbsoluteTileBoundaries; + + // 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())); + + // Build tile image. + OwnPtr<ImageBuffer> tileImage = createTileImage(m_attributes, tileBoundaries, absoluteTileBoundaries, tileImageTransform, clampedAbsoluteTileBoundaries); + if (!tileImage) + return 0; + + RefPtr<Image> copiedImage = tileImage->copyImage(CopyBackingStore); + if (!copiedImage) + return 0; + + // Build pattern. + OwnPtr<PatternData> patternData = adoptPtr(new PatternData); + patternData->pattern = Pattern::create(copiedImage, true, true); + + // Compute pattern space transformation. + const IntSize tileImageSize = tileImage->logicalSize(); + patternData->transform.translate(tileBoundaries.x(), tileBoundaries.y()); + patternData->transform.scale(tileBoundaries.width() / tileImageSize.width(), tileBoundaries.height() / tileImageSize.height()); + + AffineTransform patternTransform = m_attributes.patternTransform(); + if (!patternTransform.isIdentity()) + patternData->transform = patternTransform * patternData->transform; + + // Account for text drawing resetting the context to non-scaled, see SVGInlineTextBox::paintTextWithShadows. + if (resourceMode & ApplyToTextMode) { + AffineTransform additionalTextTransformation; + if (shouldTransformOnTextPainting(object, additionalTextTransformation)) + patternData->transform *= additionalTextTransformation; + } + patternData->pattern->setPatternSpaceTransform(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()).iterator->value.get(); +} + +bool RenderSVGResourcePattern::applyResource(RenderObject* object, RenderStyle* style, GraphicsContext*& context, unsigned short resourceMode) +{ + ASSERT(object); + ASSERT(style); + ASSERT(context); + ASSERT(resourceMode != ApplyToDefaultMode); + // Spec: When the geometry of the applicable element has no width or height and objectBoundingBox is specified, // then the given effect (e.g. a gradient or a filter) will be ignored. FloatRect objectBoundingBox = object->objectBoundingBox(); if (m_attributes.patternUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX && objectBoundingBox.isEmpty()) return false; - OwnPtr<PatternData>& patternData = m_patternMap.add(object, nullptr).iterator->value; + PatternData* patternData = buildPattern(object, resourceMode); if (!patternData) - patternData = adoptPtr(new PatternData); - - if (!patternData->pattern) { - // If we couldn't determine the pattern content element root, stop here. - if (!m_attributes.patternContentElement()) - return false; - - // Compute all necessary transformations to build the tile image & the pattern. - FloatRect tileBoundaries; - AffineTransform tileImageTransform; - if (!buildTileImageTransform(object, m_attributes, patternElement, tileBoundaries, tileImageTransform)) - return false; - - AffineTransform absoluteTransformIgnoringRotation; - SVGRenderingContext::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransformIgnoringRotation); - - // Ignore 2D rotation, as it doesn't affect the size of the tile. - SVGRenderingContext::clear2DRotation(absoluteTransformIgnoringRotation); - FloatRect absoluteTileBoundaries = absoluteTransformIgnoringRotation.mapRect(tileBoundaries); - FloatRect clampedAbsoluteTileBoundaries; - - // 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())); - - // Build tile image. - OwnPtr<ImageBuffer> tileImage = createTileImage(m_attributes, tileBoundaries, absoluteTileBoundaries, tileImageTransform, clampedAbsoluteTileBoundaries); - if (!tileImage) - return false; - - RefPtr<Image> copiedImage = tileImage->copyImage(CopyBackingStore); - if (!copiedImage) - return false; - - // Build pattern. - patternData->pattern = Pattern::create(copiedImage, true, true); - if (!patternData->pattern) - return false; - - // Compute pattern space transformation. - const IntSize tileImageSize = tileImage->logicalSize(); - patternData->transform.translate(tileBoundaries.x(), tileBoundaries.y()); - patternData->transform.scale(tileBoundaries.width() / tileImageSize.width(), tileBoundaries.height() / tileImageSize.height()); - - AffineTransform patternTransform = m_attributes.patternTransform(); - if (!patternTransform.isIdentity()) - patternData->transform = patternTransform * patternData->transform; - - // Account for text drawing resetting the context to non-scaled, see SVGInlineTextBox::paintTextWithShadows. - if (resourceMode & ApplyToTextMode) { - AffineTransform additionalTextTransformation; - if (shouldTransformOnTextPainting(object, additionalTextTransformation)) - patternData->transform *= additionalTextTransformation; - } - patternData->pattern->setPatternSpaceTransform(patternData->transform); - } + return false; // Draw pattern context->save(); diff --git a/Source/WebCore/rendering/svg/RenderSVGResourcePattern.h b/Source/WebCore/rendering/svg/RenderSVGResourcePattern.h index 9e39383bd..d4da53567 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourcePattern.h +++ b/Source/WebCore/rendering/svg/RenderSVGResourcePattern.h @@ -66,6 +66,8 @@ private: const FloatRect& absoluteTileBoundaries, const AffineTransform& tileImageTransform, FloatRect& clampedAbsoluteTileBoundaries) const; + PatternData* buildPattern(RenderObject*, unsigned short resourceMode); + bool m_shouldCollectPatternAttributes : 1; PatternAttributes m_attributes; HashMap<RenderObject*, OwnPtr<PatternData> > m_patternMap; |