| Index: Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp
|
| ===================================================================
|
| --- Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp (revision 136569)
|
| +++ Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp (working copy)
|
| @@ -55,20 +55,15 @@
|
| 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,71 +73,81 @@
|
| m_shouldCollectPatternAttributes = false;
|
| }
|
|
|
| - // 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;
|
| + // If we couldn't determine the pattern content element root, stop here.
|
| + if (!m_attributes.patternContentElement())
|
| + return 0;
|
|
|
| - OwnPtr<PatternData>& patternData = m_patternMap.add(object, nullptr).iterator->value;
|
| - if (!patternData)
|
| - patternData = adoptPtr(new PatternData);
|
| + // 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;
|
|
|
| - if (!patternData->pattern) {
|
| - // If we couldn't determine the pattern content element root, stop here.
|
| - if (!m_attributes.patternContentElement())
|
| - return false;
|
| + AffineTransform absoluteTransformIgnoringRotation;
|
| + SVGRenderingContext::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransformIgnoringRotation);
|
|
|
| - // 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;
|
| + // Ignore 2D rotation, as it doesn't affect the size of the tile.
|
| + SVGRenderingContext::clear2DRotation(absoluteTransformIgnoringRotation);
|
| + FloatRect absoluteTileBoundaries = absoluteTransformIgnoringRotation.mapRect(tileBoundaries);
|
| + FloatRect clampedAbsoluteTileBoundaries;
|
|
|
| - AffineTransform absoluteTransformIgnoringRotation;
|
| - SVGRenderingContext::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransformIgnoringRotation);
|
| + // 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()));
|
|
|
| - // Ignore 2D rotation, as it doesn't affect the size of the tile.
|
| - SVGRenderingContext::clear2DRotation(absoluteTransformIgnoringRotation);
|
| - FloatRect absoluteTileBoundaries = absoluteTransformIgnoringRotation.mapRect(tileBoundaries);
|
| - FloatRect clampedAbsoluteTileBoundaries;
|
| + // Build tile image.
|
| + OwnPtr<ImageBuffer> tileImage = createTileImage(m_attributes, tileBoundaries, absoluteTileBoundaries, tileImageTransform, clampedAbsoluteTileBoundaries);
|
| + if (!tileImage)
|
| + return 0;
|
|
|
| - // 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()));
|
| + RefPtr<Image> copiedImage = tileImage->copyImage(CopyBackingStore);
|
| + if (!copiedImage)
|
| + return 0;
|
|
|
| - // Build tile image.
|
| - OwnPtr<ImageBuffer> tileImage = createTileImage(m_attributes, tileBoundaries, absoluteTileBoundaries, tileImageTransform, clampedAbsoluteTileBoundaries);
|
| - if (!tileImage)
|
| - return false;
|
| + // Build pattern.
|
| + OwnPtr<PatternData> patternData = adoptPtr(new PatternData);
|
| + patternData->pattern = Pattern::create(copiedImage, true, true);
|
|
|
| - RefPtr<Image> copiedImage = tileImage->copyImage(CopyBackingStore);
|
| - if (!copiedImage)
|
| - 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());
|
|
|
| - // Build pattern.
|
| - patternData->pattern = Pattern::create(copiedImage, true, true);
|
| - if (!patternData->pattern)
|
| - return false;
|
| + AffineTransform patternTransform = m_attributes.patternTransform();
|
| + if (!patternTransform.isIdentity())
|
| + patternData->transform = patternTransform * patternData->transform;
|
|
|
| - // 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());
|
| + // 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);
|
|
|
| - 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()).iterator->value.get();
|
| +}
|
|
|
| - // 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);
|
| - }
|
| +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;
|
| +
|
| + PatternData* patternData = buildPattern(object, resourceMode);
|
| + if (!patternData)
|
| + return false;
|
| +
|
| // Draw pattern
|
| context->save();
|
|
|
|
|