#include "core/rendering/svg/RenderSVGResourcePattern.h"
+#include "core/dom/ElementTraversal.h"
#include "core/rendering/svg/SVGRenderSupport.h"
#include "core/rendering/svg/SVGRenderingContext.h"
#include "core/svg/SVGFitToViewBox.h"
#include "platform/graphics/GraphicsContext.h"
-namespace WebCore {
+namespace blink {
const RenderSVGResourceType RenderSVGResourcePattern::s_resourceType = PatternResourceType;
{
m_patternMap.clear();
m_shouldCollectPatternAttributes = true;
- markAllClientsForInvalidation(markForInvalidation ? RepaintInvalidation : ParentOnlyInvalidation);
+ markAllClientsForInvalidation(markForInvalidation ? PaintInvalidation : ParentOnlyInvalidation);
}
void RenderSVGResourcePattern::removeClientFromCache(RenderObject* client, bool markForInvalidation)
{
ASSERT(client);
m_patternMap.remove(client);
- markClientForInvalidation(client, markForInvalidation ? RepaintInvalidation : ParentOnlyInvalidation);
+ markClientForInvalidation(client, markForInvalidation ? PaintInvalidation : ParentOnlyInvalidation);
}
-PatternData* RenderSVGResourcePattern::buildPattern(RenderObject* object, unsigned short resourceMode)
+PatternData* RenderSVGResourcePattern::buildPattern(RenderObject* object, const SVGPatternElement* patternElement)
{
ASSERT(object);
PatternData* currentData = m_patternMap.get(object);
if (currentData && currentData->pattern)
return currentData;
- SVGPatternElement* patternElement = toSVGPatternElement(element());
- if (!patternElement)
- return 0;
-
- if (m_shouldCollectPatternAttributes) {
- patternElement->synchronizeAnimatedSVGAttribute(anyQName());
-
- m_attributes = PatternAttributes();
- patternElement->collectPatternAttributes(m_attributes);
- m_shouldCollectPatternAttributes = false;
- }
-
// If we couldn't determine the pattern content element root, stop here.
if (!m_attributes.patternContentElement())
return 0;
// 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);
+ OwnPtr<ImageBuffer> tileImage = createTileImage(m_attributes, tileBoundaries, absoluteTileBoundaries, tileImageTransform);
if (!tileImage)
return 0;
// Build pattern.
OwnPtr<PatternData> patternData = adoptPtr(new PatternData);
- patternData->pattern = Pattern::create(copiedImage, true, true);
+ patternData->pattern = Pattern::createBitmapPattern(copiedImage);
// Compute pattern space transformation.
const IntSize tileImageSize = tileImage->size();
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.
clearInvalidationMask();
+ SVGPatternElement* patternElement = toSVGPatternElement(element());
+ if (!patternElement)
+ return false;
+
+ if (m_shouldCollectPatternAttributes) {
+ patternElement->synchronizeAnimatedSVGAttribute(anyQName());
+
+ m_attributes = PatternAttributes();
+ patternElement->collectPatternAttributes(m_attributes);
+ 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;
- PatternData* patternData = buildPattern(object, resourceMode);
+ PatternData* patternData = buildPattern(object, patternElement);
if (!patternData)
return false;
+ const SVGRenderStyle& svgStyle = style->svgStyle();
+
+ AffineTransform computedPatternSpaceTransform = computeResourceSpaceTransform(object, patternData->transform, svgStyle, resourceMode);
+ patternData->pattern->setPatternSpaceTransform(computedPatternSpaceTransform);
+
// Draw pattern
context->save();
- const SVGRenderStyle* svgStyle = style->svgStyle();
- ASSERT(svgStyle);
-
if (resourceMode & ApplyToFillMode) {
- context->setAlphaAsFloat(svgStyle->fillOpacity());
+ context->setAlphaAsFloat(svgStyle.fillOpacity());
context->setFillPattern(patternData->pattern);
- context->setFillRule(svgStyle->fillRule());
+ context->setFillRule(svgStyle.fillRule());
} else if (resourceMode & ApplyToStrokeMode) {
- if (svgStyle->vectorEffect() == VE_NON_SCALING_STROKE)
- patternData->pattern->setPatternSpaceTransform(transformOnNonScalingStroke(object, patternData->transform));
- context->setAlphaAsFloat(svgStyle->strokeOpacity());
+ context->setAlphaAsFloat(svgStyle.strokeOpacity());
context->setStrokePattern(patternData->pattern);
SVGRenderSupport::applyStrokeStyleToContext(context, style, object);
}
return true;
}
-void RenderSVGResourcePattern::postApplyResource(RenderObject*, GraphicsContext*& context, unsigned short resourceMode, const Path* path, const RenderSVGShape* shape)
+void RenderSVGResourcePattern::postApplyResource(RenderObject*, GraphicsContext*& context)
{
ASSERT(context);
- ASSERT(resourceMode != ApplyToDefaultMode);
-
- if (resourceMode & ApplyToFillMode) {
- if (path)
- context->fillPath(*path);
- else if (shape)
- shape->fillShape(context);
- }
- if (resourceMode & ApplyToStrokeMode) {
- if (path)
- context->strokePath(*path);
- else if (shape)
- shape->strokeShape(context);
- }
-
context->restore();
}
PassOwnPtr<ImageBuffer> RenderSVGResourcePattern::createTileImage(const PatternAttributes& attributes,
const FloatRect& tileBoundaries,
const FloatRect& absoluteTileBoundaries,
- const AffineTransform& tileImageTransform,
- FloatRect& clampedAbsoluteTileBoundaries) const
+ const AffineTransform& tileImageTransform) const
{
- clampedAbsoluteTileBoundaries = SVGRenderingContext::clampedAbsoluteTargetRect(absoluteTileBoundaries);
+ FloatRect clampedAbsoluteTileBoundaries = SVGRenderingContext::clampedAbsoluteTargetRect(absoluteTileBoundaries);
IntSize imageSize(roundedIntSize(clampedAbsoluteTileBoundaries.size()));
if (imageSize.isEmpty())
GraphicsContext* tileImageContext = tileImage->context();
ASSERT(tileImageContext);
IntSize unclampedImageSize(roundedIntSize(absoluteTileBoundaries.size()));
- tileImageContext->scale(FloatSize(unclampedImageSize.width() / absoluteTileBoundaries.width(), unclampedImageSize.height() / absoluteTileBoundaries.height()));
+ 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(FloatSize(clampedAbsoluteTileBoundaries.width() / tileBoundaries.width(),
- clampedAbsoluteTileBoundaries.height() / tileBoundaries.height()));
+ tileImageContext->scale(
+ clampedAbsoluteTileBoundaries.width() / tileBoundaries.width(),
+ clampedAbsoluteTileBoundaries.height() / tileBoundaries.height());
// Apply tile image transformations.
if (!tileImageTransform.isIdentity())
contentTransformation = tileImageTransform;
// Draw the content into the ImageBuffer.
- for (Element* element = ElementTraversal::firstWithin(*attributes.patternContentElement()); element; element = ElementTraversal::nextSibling(*element)) {
- if (!element->isSVGElement() || !element->renderer())
+ for (SVGElement* element = Traversal<SVGElement>::firstChild(*attributes.patternContentElement()); element; element = Traversal<SVGElement>::nextSibling(*element)) {
+ if (!element->renderer())
continue;
if (element->renderer()->needsLayout())
return nullptr;