Chromium Code Reviews| 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..dd0bec997276da718cbe4501736622c091606c2a 100644 |
| --- a/Source/core/rendering/svg/RenderSVGResourceMasker.cpp |
| +++ b/Source/core/rendering/svg/RenderSVGResourceMasker.cpp |
| @@ -23,13 +23,18 @@ |
| #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/skia/SkiaUtils.h" |
| #include "core/platform/graphics/transforms/AffineTransform.h" |
| #include "core/rendering/svg/RenderSVGResource.h" |
| #include "core/rendering/svg/SVGRenderingContext.h" |
| #include "core/svg/SVGElement.h" |
| #include "core/svg/SVGMaskElement.h" |
| #include "core/svg/SVGUnitTypes.h" |
| +#include "third_party/skia/include/core/SkColorFilter.h" |
| +#include "third_party/skia/include/effects/SkLumaXfermode.h" |
| +#include "third_party/skia/include/effects/SkTableColorFilter.h" |
|
pdr.
2013/08/28 03:32:36
Including Skia and using SkRect types in rendering
Stephen White
2013/08/28 14:11:10
+1
f(malita)
2013/08/28 19:54:38
Skia types are already leaked into the world due t
|
| #include "wtf/UnusedParam.h" |
| #include "wtf/Vector.h" |
| @@ -45,111 +50,108 @@ 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); |
| + FloatRect repaintRect = object->repaintRectInLocalCoordinates(); |
| + if (repaintRect.isEmpty() || !node()->hasChildNodes()) |
| + return false; |
| - MaskerData* maskerData = m_masker.get(object); |
| + SkRect rect = WebCoreFloatRectToSKRect(repaintRect); |
| + const SVGRenderStyle* svgStyle = style()->svgStyle(); |
| + ASSERT(svgStyle); |
| + ColorSpace colorSpace = svgStyle->colorInterpolation() == CI_LINEARRGB |
| + ? ColorSpaceLinearRGB |
| + : ColorSpaceDeviceRGB; |
| + RefPtr<SkColorFilter> colorSpaceConverter = ImageBuffer::createColorSpaceFilter( |
| + ColorSpaceDeviceRGB, colorSpace); |
| + |
| + // Mask layer start. |
| + context->saveLayer(&rect, 0); |
| + |
| + if (colorSpaceConverter) { |
| + // TODO: investigate handling color space conversion via an inline paint color filter. |
| + // That would allow us to avoid this extra saveLayer, but requires the color filter |
| + // to be part of GraphicsContext's state (and be applied in setupPaintCommon()). |
| + SkPaint converterPaint; |
| + converterPaint.setColorFilter(colorSpaceConverter.get()); |
| + |
| + // Color converter layer start. |
| + context->saveLayer(&rect, &converterPaint); |
| + } |
| - AffineTransform absoluteTransform; |
| - SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(object, absoluteTransform); |
| + drawMaskContent(context, object->objectBoundingBox()); |
| - FloatRect repaintRect = object->repaintRectInLocalCoordinates(); |
| + if (colorSpaceConverter) |
| + context->restoreLayer(); |
| - 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(); |
| - } |
| - } |
| + // Use a transfer mode appropriate for mask-type. |
| + RefPtr<SkXfermode> xferMode = svgStyle->maskType() == MT_LUMINANCE |
| + ? adoptRef(SkLumaMaskXfermode::Create(SkXfermode::kSrcIn_Mode)) |
| + : adoptRef(SkXfermode::Create(SkXfermode::kSrcIn_Mode)); |
| + SkPaint contentPaint; |
| + contentPaint.setXfermode(xferMode.get()); |
| - if (!maskerData->maskImage) |
| - return false; |
| + // Content layer start. |
| + context->saveLayer(&rect, &contentPaint); |
| - 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*) |
| +{ |
| + ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode); |
| + |
| + // Transfer content layer -> mask layer (SrcIn) |
| + context->restoreLayer(); |
| + // Transfer mask layer -> bg layer (SrcOver) |
| + context->restoreLayer(); |
| +} |
| + |
| +void RenderSVGResourceMasker::drawMaskContent(GraphicsContext* context, const FloatRect& targetBoundingBox) |
| { |
| - GraphicsContext* maskImageContext = maskerData->maskImage->context(); |
| - ASSERT(maskImageContext); |
| + ASSERT(context); |
| - // Eventually adjust the mask image context according to the target objectBoundingBox. |
| + // 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); |
| + GraphicsContextStateSaver maskContentSaver(*context, false); |
| + if (toSVGMaskElement(node())->maskContentUnitsCurrentValue() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { |
| + maskContentSaver.save(); |
| + maskContentTransformation = makeMapBetweenRects(FloatRect(0, 0, 1, 1), targetBoundingBox); |
|
pdr.
2013/08/28 03:32:36
Ditto
f(malita)
2013/08/28 19:54:38
Done.
|
| + 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() |