| Index: Source/core/rendering/svg/RenderSVGResourceMasker.cpp
|
| diff --git a/Source/core/rendering/svg/RenderSVGResourceMasker.cpp b/Source/core/rendering/svg/RenderSVGResourceMasker.cpp
|
| index ad9631da31e3ee2e9c899cba97f49a89e000e223..6a599a83aeb24a4e6f97d77caf06cdc4a08e9905 100644
|
| --- a/Source/core/rendering/svg/RenderSVGResourceMasker.cpp
|
| +++ b/Source/core/rendering/svg/RenderSVGResourceMasker.cpp
|
| @@ -23,6 +23,7 @@
|
|
|
| #include "core/platform/graphics/FloatRect.h"
|
| #include "core/platform/graphics/GraphicsContext.h"
|
| +#include "core/platform/graphics/GraphicsContextStateSaver.h"
|
| #include "core/platform/graphics/ImageBuffer.h"
|
| #include "core/platform/graphics/transforms/AffineTransform.h"
|
| #include "core/rendering/svg/RenderSVGResource.h"
|
| @@ -45,111 +46,89 @@ RenderSVGResourceMasker::RenderSVGResourceMasker(SVGMaskElement* node)
|
|
|
| RenderSVGResourceMasker::~RenderSVGResourceMasker()
|
| {
|
| - if (m_masker.isEmpty())
|
| - return;
|
| -
|
| - deleteAllValues(m_masker);
|
| - m_masker.clear();
|
| }
|
|
|
| void RenderSVGResourceMasker::removeAllClientsFromCache(bool markForInvalidation)
|
| {
|
| m_maskContentBoundaries = FloatRect();
|
| - if (!m_masker.isEmpty()) {
|
| - deleteAllValues(m_masker);
|
| - m_masker.clear();
|
| - }
|
| -
|
| markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation);
|
| }
|
|
|
| void RenderSVGResourceMasker::removeClientFromCache(RenderObject* client, bool markForInvalidation)
|
| {
|
| ASSERT(client);
|
| -
|
| - if (m_masker.contains(client))
|
| - delete m_masker.take(client);
|
| -
|
| markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidation : ParentOnlyInvalidation);
|
| }
|
|
|
| -bool RenderSVGResourceMasker::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode)
|
| +bool RenderSVGResourceMasker::applyResource(RenderObject* object, RenderStyle*,
|
| + GraphicsContext*& context, unsigned short resourceMode)
|
| {
|
| ASSERT(object);
|
| ASSERT(context);
|
| + ASSERT(style());
|
| ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode);
|
| + ASSERT_WITH_SECURITY_IMPLICATION(!needsLayout());
|
|
|
| - bool missingMaskerData = !m_masker.contains(object);
|
| - if (missingMaskerData)
|
| - m_masker.set(object, new MaskerData);
|
| -
|
| - MaskerData* maskerData = m_masker.get(object);
|
| + FloatRect repaintRect = object->repaintRectInLocalCoordinates();
|
| + if (repaintRect.isEmpty() || !node()->hasChildNodes())
|
| + return false;
|
|
|
| - AffineTransform absoluteTransform;
|
| - SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(object, absoluteTransform);
|
| + const SVGRenderStyle* svgStyle = style()->svgStyle();
|
| + ASSERT(svgStyle);
|
| + ColorSpace colorSpace = svgStyle->colorInterpolation() == CI_LINEARRGB
|
| + ? ColorSpaceLinearRGB
|
| + : ColorSpaceDeviceRGB;
|
|
|
| - FloatRect repaintRect = object->repaintRectInLocalCoordinates();
|
| + // Mask layer start.
|
| + context->beginTransparencyLayer(1, &repaintRect);
|
| + {
|
| + // Draw the mask with color conversion (when needed).
|
| + GraphicsContextStateSaver maskContentSaver(*context);
|
| + context->setColorSpaceConversion(ColorSpaceDeviceRGB, colorSpace);
|
|
|
| - if (!maskerData->maskImage && !repaintRect.isEmpty()) {
|
| - SVGMaskElement* maskElement = toSVGMaskElement(node());
|
| - if (!maskElement)
|
| - return false;
|
| -
|
| - ASSERT(style());
|
| - const SVGRenderStyle* svgStyle = style()->svgStyle();
|
| - ASSERT(svgStyle);
|
| - ColorSpace colorSpace = svgStyle->colorInterpolation() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceDeviceRGB;
|
| - if (!SVGRenderingContext::createImageBuffer(repaintRect, absoluteTransform, maskerData->maskImage, Unaccelerated))
|
| - return false;
|
| -
|
| - if (!drawContentIntoMaskImage(maskerData, colorSpace, maskElement, object)) {
|
| - maskerData->maskImage.clear();
|
| - }
|
| + drawMaskContent(context, object->objectBoundingBox());
|
| }
|
|
|
| - if (!maskerData->maskImage)
|
| - return false;
|
| + // Content layer start.
|
| + MaskType maskType = svgStyle->maskType() == MT_LUMINANCE ? LuminanceMaskType : AlphaMaskType;
|
| + context->beginMaskedLayer(repaintRect, maskType);
|
|
|
| - SVGRenderingContext::clipToImageBuffer(context, absoluteTransform, repaintRect, maskerData->maskImage, missingMaskerData);
|
| return true;
|
| }
|
|
|
| -bool RenderSVGResourceMasker::drawContentIntoMaskImage(MaskerData* maskerData, ColorSpace colorSpace, const SVGMaskElement* maskElement, RenderObject* object)
|
| +void RenderSVGResourceMasker::postApplyResource(RenderObject*, GraphicsContext*& context,
|
| + unsigned short resourceMode, const Path*, const RenderSVGShape*)
|
| {
|
| - GraphicsContext* maskImageContext = maskerData->maskImage->context();
|
| - ASSERT(maskImageContext);
|
| + ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode);
|
| +
|
| + // Transfer content layer -> mask layer (SrcIn)
|
| + context->endLayer();
|
| + // Transfer mask layer -> bg layer (SrcOver)
|
| + context->endLayer();
|
| +}
|
|
|
| - // Eventually adjust the mask image context according to the target objectBoundingBox.
|
| +void RenderSVGResourceMasker::drawMaskContent(GraphicsContext* context, const FloatRect& targetBoundingBox)
|
| +{
|
| + ASSERT(context);
|
| +
|
| + // Adjust the mask image context according to the target objectBoundingBox.
|
| AffineTransform maskContentTransformation;
|
| - if (maskElement->maskContentUnitsCurrentValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
|
| - FloatRect objectBoundingBox = object->objectBoundingBox();
|
| - maskContentTransformation.translate(objectBoundingBox.x(), objectBoundingBox.y());
|
| - maskContentTransformation.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
|
| - maskImageContext->concatCTM(maskContentTransformation);
|
| + if (toSVGMaskElement(node())->maskContentUnitsCurrentValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
|
| + maskContentTransformation.translate(targetBoundingBox.x(), targetBoundingBox.y());
|
| + maskContentTransformation.scaleNonUniform(targetBoundingBox.width(), targetBoundingBox.height());
|
| + context->concatCTM(maskContentTransformation);
|
| }
|
|
|
| - // Draw the content into the ImageBuffer.
|
| - for (Node* node = maskElement->firstChild(); node; node = node->nextSibling()) {
|
| - RenderObject* renderer = node->renderer();
|
| - if (!node->isSVGElement() || !renderer)
|
| + for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) {
|
| + RenderObject* renderer = childNode->renderer();
|
| + if (!childNode->isSVGElement() || !renderer)
|
| continue;
|
| - if (renderer->needsLayout())
|
| - return false;
|
| RenderStyle* style = renderer->style();
|
| if (!style || style->display() == NONE || style->visibility() != VISIBLE)
|
| continue;
|
| - SVGRenderingContext::renderSubtreeToImageBuffer(maskerData->maskImage.get(), renderer, maskContentTransformation);
|
| - }
|
| -
|
| - maskerData->maskImage->transformColorSpace(ColorSpaceDeviceRGB, colorSpace);
|
| -
|
| - ASSERT(style());
|
| - ASSERT(style()->svgStyle());
|
| - // Create the luminance mask.
|
| - if (style()->svgStyle()->maskType() == MT_LUMINANCE)
|
| - maskerData->maskImage->convertToLuminanceMask();
|
|
|
| - return true;
|
| + SVGRenderingContext::renderSubtree(context, renderer, maskContentTransformation);
|
| + }
|
| }
|
|
|
| void RenderSVGResourceMasker::calculateMaskContentRepaintRect()
|
|
|