1dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block/* 2dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * Copyright (C) 2004, 2005, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org> 365f03d4f644ce73618e5f4f50dd694b26f55ae12Ben Murdoch * Copyright (C) 2004, 2005, 2006, 2007, 2008 Rob Buis <buis@kde.org> 4dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. 5dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * 6dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * This library is free software; you can redistribute it and/or 7dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * modify it under the terms of the GNU Library General Public 8dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * License as published by the Free Software Foundation; either 9dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * version 2 of the License, or (at your option) any later version. 10dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * 11dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * This library is distributed in the hope that it will be useful, 12dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * but WITHOUT ANY WARRANTY; without even the implied warranty of 13dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * Library General Public License for more details. 15dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * 16dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * You should have received a copy of the GNU Library General Public License 17dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * along with this library; see the file COPYING.LIB. If not, write to 18dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 19dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block * Boston, MA 02110-1301, USA. 20dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block */ 21dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 22dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "config.h" 23db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block 246c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen#if ENABLE(SVG) 25dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "RenderSVGResourceClipper.h" 26dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 27dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "AffineTransform.h" 28dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "FloatRect.h" 29dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "GraphicsContext.h" 30545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch#include "HitTestRequest.h" 31545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch#include "HitTestResult.h" 32dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "ImageBuffer.h" 33dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "IntRect.h" 34dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "RenderObject.h" 35dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "RenderSVGResource.h" 36db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block#include "RenderStyle.h" 37dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "SVGClipPathElement.h" 38dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "SVGElement.h" 39e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block#include "SVGImageBufferTools.h" 40f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch#include "SVGNames.h" 41dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "SVGRenderSupport.h" 42db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block#include "SVGResources.h" 43dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "SVGStyledElement.h" 44dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "SVGStyledTransformableElement.h" 45dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "SVGUnitTypes.h" 46dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "SVGUseElement.h" 4721939df44de1705786c545cd1bf519d47250322dBen Murdoch#include <wtf/UnusedParam.h> 48dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 49dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blocknamespace WebCore { 50dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 51dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve BlockRenderSVGResourceType RenderSVGResourceClipper::s_resourceType = ClipperResourceType; 52dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 5321939df44de1705786c545cd1bf519d47250322dBen MurdochRenderSVGResourceClipper::RenderSVGResourceClipper(SVGClipPathElement* node) 5421939df44de1705786c545cd1bf519d47250322dBen Murdoch : RenderSVGResourceContainer(node) 55967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch , m_invalidationBlocked(false) 56dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{ 57dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block} 58dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 59dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve BlockRenderSVGResourceClipper::~RenderSVGResourceClipper() 60dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{ 61db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block if (m_clipper.isEmpty()) 62db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block return; 63db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block 64dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block deleteAllValues(m_clipper); 65dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block m_clipper.clear(); 66dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block} 67dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 68f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrickvoid RenderSVGResourceClipper::removeAllClientsFromCache(bool markForInvalidation) 69dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{ 70967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch if (m_invalidationBlocked) 71967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch return; 72967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch 736c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen m_clipBoundaries = FloatRect(); 74db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block if (!m_clipper.isEmpty()) { 75db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block deleteAllValues(m_clipper); 76db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block m_clipper.clear(); 77db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block } 78db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block 79f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation); 80dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block} 81dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 82f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrickvoid RenderSVGResourceClipper::removeClientFromCache(RenderObject* client, bool markForInvalidation) 83dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{ 84db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block ASSERT(client); 85967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch if (m_invalidationBlocked) 86967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch return; 87dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 88db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block if (m_clipper.contains(client)) 89db14019a23d96bc8a444b6576a5da8bd1cfbc8b0Steve Block delete m_clipper.take(client); 90dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 91f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidation : ParentOnlyInvalidation); 92dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block} 93dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 9421939df44de1705786c545cd1bf519d47250322dBen Murdochbool RenderSVGResourceClipper::applyResource(RenderObject* object, RenderStyle*, GraphicsContext*& context, unsigned short resourceMode) 95dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{ 9621939df44de1705786c545cd1bf519d47250322dBen Murdoch ASSERT(object); 9721939df44de1705786c545cd1bf519d47250322dBen Murdoch ASSERT(context); 9821939df44de1705786c545cd1bf519d47250322dBen Murdoch#ifndef NDEBUG 9921939df44de1705786c545cd1bf519d47250322dBen Murdoch ASSERT(resourceMode == ApplyToDefaultMode); 10021939df44de1705786c545cd1bf519d47250322dBen Murdoch#else 10121939df44de1705786c545cd1bf519d47250322dBen Murdoch UNUSED_PARAM(resourceMode); 10221939df44de1705786c545cd1bf519d47250322dBen Murdoch#endif 103967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch 104e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return applyClippingToContext(object, object->objectBoundingBox(), object->repaintRectInLocalCoordinates(), context); 105dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block} 106dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 107dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockbool RenderSVGResourceClipper::pathOnlyClipping(GraphicsContext* context, const FloatRect& objectBoundingBox) 108dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{ 109dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // If the current clip-path gets clipped itself, we have to fallback to masking. 110dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (!style()->svgStyle()->clipperResource().isEmpty()) 111dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return false; 112dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block WindRule clipRule = RULE_NONZERO; 113dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block Path clipPath = Path(); 114dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 115dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // If clip-path only contains one visible shape or path, we can use path-based clipping. Invisible 116dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // shapes don't affect the clipping and can be ignored. If clip-path contains more than one 117dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // visible shape, the additive clipping may not work, caused by the clipRule. EvenOdd 118dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // as well as NonZero can cause self-clipping of the elements. 119dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // See also http://www.w3.org/TR/SVG/painting.html#FillRuleProperty 120dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) { 121dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block RenderObject* renderer = childNode->renderer(); 122dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (!renderer) 123dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block continue; 124dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // Only shapes or paths are supported for direct clipping. We need to fallback to masking for texts. 125dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (renderer->isSVGText()) 126dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return false; 127dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyledTransformable()) 128dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block continue; 129dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block SVGStyledTransformableElement* styled = static_cast<SVGStyledTransformableElement*>(childNode); 130dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block RenderStyle* style = renderer->style(); 131dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (!style || style->display() == NONE || style->visibility() != VISIBLE) 132dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block continue; 133dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block const SVGRenderStyle* svgStyle = style->svgStyle(); 134dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // Current shape in clip-path gets clipped too. Fallback to masking. 135dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (!svgStyle->clipperResource().isEmpty()) 136dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return false; 137dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // Fallback to masking, if there is more than one clipping path. 138dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (clipPath.isEmpty()) { 139a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch styled->toClipPath(clipPath); 140dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block clipRule = svgStyle->clipRule(); 141dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } else 142dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return false; 143dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } 144dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // Only one visible shape/path was found. Directly continue clipping and transform the content to userspace if necessary. 145dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (static_cast<SVGClipPathElement*>(node())->clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { 146dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block AffineTransform transform; 147dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block transform.translate(objectBoundingBox.x(), objectBoundingBox.y()); 148dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); 149dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block clipPath.transform(transform); 150dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } 151dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // The SVG specification wants us to clip everything, if clip-path doesn't have a child. 152dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (clipPath.isEmpty()) 153dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block clipPath.addRect(FloatRect()); 154f05b935882198ccf7d81675736e3aeb089c5113aBen Murdoch context->clipPath(clipPath, clipRule); 155dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return true; 156dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block} 157dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 158dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockbool RenderSVGResourceClipper::applyClippingToContext(RenderObject* object, const FloatRect& objectBoundingBox, 159dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block const FloatRect& repaintRect, GraphicsContext* context) 160dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{ 161dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (!m_clipper.contains(object)) 162dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block m_clipper.set(object, new ClipperData); 163dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 164e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block bool shouldCreateClipData = false; 165dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block ClipperData* clipperData = m_clipper.get(object); 166dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (!clipperData->clipMaskImage) { 167dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (pathOnlyClipping(context, objectBoundingBox)) 168dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return true; 169e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block shouldCreateClipData = true; 170e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block } 171e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 172e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block AffineTransform absoluteTransform; 173e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(object, absoluteTransform); 174e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 175e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block FloatRect absoluteTargetRect = absoluteTransform.mapRect(repaintRect); 176e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block FloatRect clampedAbsoluteTargetRect = SVGImageBufferTools::clampedAbsoluteTargetRectForRenderer(object, absoluteTargetRect); 177e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 178e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block if (shouldCreateClipData && !clampedAbsoluteTargetRect.isEmpty()) { 179a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (!SVGImageBufferTools::createImageBuffer(absoluteTargetRect, clampedAbsoluteTargetRect, clipperData->clipMaskImage, ColorSpaceDeviceRGB)) 180e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return false; 181e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 182e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block GraphicsContext* maskContext = clipperData->clipMaskImage->context(); 183e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block ASSERT(maskContext); 184e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 185e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block // The save/restore pair is needed for clipToImageBuffer - it doesn't work without it on non-Cg platforms. 186e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block maskContext->save(); 187e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block maskContext->translate(-clampedAbsoluteTargetRect.x(), -clampedAbsoluteTargetRect.y()); 188e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block maskContext->concatCTM(absoluteTransform); 189e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 190e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block // clipPath can also be clipped by another clipPath. 191e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this)) { 192e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block if (RenderSVGResourceClipper* clipper = resources->clipper()) { 193e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block if (!clipper->applyClippingToContext(this, objectBoundingBox, repaintRect, maskContext)) { 194e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block maskContext->restore(); 195e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block return false; 196e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block } 197e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block } 198e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block } 199e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block 200e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block drawContentIntoMaskImage(clipperData, objectBoundingBox); 201e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block maskContext->restore(); 202dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } 203dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 204dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (!clipperData->clipMaskImage) 205dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return false; 206dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 207e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block SVGImageBufferTools::clipToImageBuffer(context, absoluteTransform, clampedAbsoluteTargetRect, clipperData->clipMaskImage); 208dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return true; 209dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block} 210dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 211e8b154fd68f9b33be40a3590e58347f353835f5cSteve Blockbool RenderSVGResourceClipper::drawContentIntoMaskImage(ClipperData* clipperData, const FloatRect& objectBoundingBox) 212dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{ 213e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block ASSERT(clipperData); 214e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block ASSERT(clipperData->clipMaskImage); 215dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 216dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block GraphicsContext* maskContext = clipperData->clipMaskImage->context(); 217dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block ASSERT(maskContext); 218dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 219e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block AffineTransform maskContentTransformation; 220dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block SVGClipPathElement* clipPath = static_cast<SVGClipPathElement*>(node()); 221dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (clipPath->clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { 222e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block maskContentTransformation.translate(objectBoundingBox.x(), objectBoundingBox.y()); 223e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block maskContentTransformation.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); 224e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block maskContext->concatCTM(maskContentTransformation); 225dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } 226dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 227dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // Draw all clipPath children into a global mask. 228dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) { 229dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block RenderObject* renderer = childNode->renderer(); 230dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyled() || !renderer) 231dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block continue; 232dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block RenderStyle* style = renderer->style(); 233dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (!style || style->display() == NONE || style->visibility() != VISIBLE) 234dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block continue; 235dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 236dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block WindRule newClipRule = style->svgStyle()->clipRule(); 237dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block bool isUseElement = renderer->isSVGShadowTreeRootContainer(); 238dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (isUseElement) { 239dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block SVGUseElement* useElement = static_cast<SVGUseElement*>(childNode); 240dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block renderer = useElement->rendererClipChild(); 241dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (!renderer) 242dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block continue; 243dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (!useElement->hasAttribute(SVGNames::clip_ruleAttr)) 244dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block newClipRule = renderer->style()->svgStyle()->clipRule(); 245dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } 246dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 247dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // Only shapes, paths and texts are allowed for clipping. 248a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (!renderer->isSVGPath() && !renderer->isSVGText()) 249dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block continue; 250dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 251dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // Save the old RenderStyle of the current object for restoring after drawing 252dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // it to the MaskImage. The new intermediate RenderStyle needs to inherit from 253dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // the old one. 254dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block RefPtr<RenderStyle> oldRenderStyle = renderer->style(); 255dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block RefPtr<RenderStyle> newRenderStyle = RenderStyle::clone(oldRenderStyle.get()); 256dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block SVGRenderStyle* svgStyle = newRenderStyle.get()->accessSVGStyle(); 25754cdeeebc7adcbcd900e8b6a141a8cae27d9a631Steve Block svgStyle->setFillPaint(SVGPaint::defaultFill()); 25854cdeeebc7adcbcd900e8b6a141a8cae27d9a631Steve Block svgStyle->setStrokePaint(SVGPaint::defaultStroke()); 259dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block svgStyle->setFillRule(newClipRule); 260dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block newRenderStyle.get()->setOpacity(1.0f); 261dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block svgStyle->setFillOpacity(1.0f); 262dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block svgStyle->setStrokeOpacity(1.0f); 263dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block svgStyle->setFilterResource(String()); 264dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block svgStyle->setMaskerResource(String()); 265967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch 266967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch // The setStyle() call results in a styleDidChange() call, which in turn invalidations the resources. 267967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch // As we're mutating the resource on purpose, block updates until we've resetted the style again. 268967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch m_invalidationBlocked = true; 269dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block renderer->setStyle(newRenderStyle.release()); 270dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 2716c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen // In the case of a <use> element, we obtained its renderere above, to retrieve its clipRule. 272e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block // We have to pass the <use> renderer itself to renderSubtreeToImageBuffer() to apply it's x/y/transform/etc. values when rendering. 2736c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen // So if isUseElement is true, refetch the childNode->renderer(), as renderer got overriden above. 274e8b154fd68f9b33be40a3590e58347f353835f5cSteve Block SVGImageBufferTools::renderSubtreeToImageBuffer(clipperData->clipMaskImage.get(), isUseElement ? childNode->renderer() : renderer, maskContentTransformation); 275dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 276dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block renderer->setStyle(oldRenderStyle.release()); 277967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch m_invalidationBlocked = false; 278dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } 279dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 280dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return true; 281dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block} 282dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 2836c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsenvoid RenderSVGResourceClipper::calculateClipContentRepaintRect() 284dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{ 285dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // This is a rough heuristic to appraise the clip size and doesn't consider clip on clip. 286dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) { 287dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block RenderObject* renderer = childNode->renderer(); 288dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyled() || !renderer) 289dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block continue; 290a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (!renderer->isSVGPath() && !renderer->isSVGText() && !renderer->isSVGShadowTreeRootContainer()) 291dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block continue; 2926c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen RenderStyle* style = renderer->style(); 2936c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen if (!style || style->display() == NONE || style->visibility() != VISIBLE) 2946c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen continue; 2956c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen m_clipBoundaries.unite(renderer->localToParentTransform().mapRect(renderer->repaintRectInLocalCoordinates())); 296dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } 2976c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen} 2986c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen 299545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdochbool RenderSVGResourceClipper::hitTestClipContent(const FloatRect& objectBoundingBox, const FloatPoint& nodeAtPoint) 3006c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen{ 301545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch FloatPoint point = nodeAtPoint; 302ca9cb53ed1119a3fd98fafa0972ffeb56dee1c24Steve Block if (!SVGRenderSupport::pointInClippingArea(this, point)) 303545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch return false; 304545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch 305545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch if (static_cast<SVGClipPathElement*>(node())->clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { 306545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch AffineTransform transform; 307545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch transform.translate(objectBoundingBox.x(), objectBoundingBox.y()); 308545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); 309545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch point = transform.inverse().mapPoint(point); 310545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch } 311545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch 312545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) { 313545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch RenderObject* renderer = childNode->renderer(); 314545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyled() || !renderer) 315545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch continue; 316a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch if (!renderer->isSVGPath() && !renderer->isSVGText() && !renderer->isSVGShadowTreeRootContainer()) 317545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch continue; 318545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch IntPoint hitPoint; 319545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch HitTestResult result(hitPoint); 320545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch if (renderer->nodeAtFloatPoint(HitTestRequest(HitTestRequest::SVGClipContent), result, point, HitTestForeground)) 321545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch return true; 322545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch } 323545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch 324545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch return false; 325545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch} 326545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch 327967717af5423377c967781471ee106e2bb4e11c8Ben MurdochFloatRect RenderSVGResourceClipper::resourceBoundingBox(RenderObject* object) 328967717af5423377c967781471ee106e2bb4e11c8Ben Murdoch{ 329545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch // Resource was not layouted yet. Give back the boundingBox of the object. 330545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch if (selfNeedsLayout()) 331545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch return object->objectBoundingBox(); 332545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch 3336c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen if (m_clipBoundaries.isEmpty()) 3346c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen calculateClipContentRepaintRect(); 335dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 336dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (static_cast<SVGClipPathElement*>(node())->clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) { 337545e470e52f0ac6a3a072bf559c796b42c6066b6Ben Murdoch FloatRect objectBoundingBox = object->objectBoundingBox(); 338dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block AffineTransform transform; 339dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block transform.translate(objectBoundingBox.x(), objectBoundingBox.y()); 340dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); 3416c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen return transform.mapRect(m_clipBoundaries); 342dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } 343dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 3446c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen return m_clipBoundaries; 345dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block} 346dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 347dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block} 3486c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen 3496c2af9490927c3c5959b5cb07461b646f8b32f6cKristian Monsen#endif // ENABLE(SVG) 350