blob: a15442fe324ba9fa3a37e2090d536f2b4198aae0 [file] [log] [blame]
/*
* Copyright (C) 2004, 2005, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
* 2004, 2005, 2006, 2007, 2008 Rob Buis <buis@kde.org>
* Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#include "config.h"
#include "RenderSVGResourceClipper.h"
#include "AffineTransform.h"
#include "FloatRect.h"
#include "GraphicsContext.h"
#include "RenderSVGResource.h"
#include "SVGClipPathElement.h"
#include "SVGElement.h"
#include "SVGRenderSupport.h"
#include "SVGStyledElement.h"
#include "SVGStyledTransformableElement.h"
#include "SVGUnitTypes.h"
namespace WebCore {
RenderSVGResourceType RenderSVGResourceClipper::s_resourceType = ClipperResourceType;
RenderSVGResourceClipper::RenderSVGResourceClipper(SVGStyledElement* node)
: RenderSVGResource(node)
{
}
RenderSVGResourceClipper::~RenderSVGResourceClipper()
{
m_clipper.clear();
}
void RenderSVGResourceClipper::invalidateClients()
{
HashSet<RenderObject*>::const_iterator end = m_clipper.end();
for (HashSet<RenderObject*>::const_iterator it = m_clipper.begin(); it != end; ++it)
(*it)->setNeedsLayout(true);
m_clipper.clear();
}
void RenderSVGResourceClipper::invalidateClient(RenderObject* object)
{
ASSERT(object);
// FIXME: The HashSet should always contain the object on calling invalidateClient. A race condition
// during the parsing can causes a call of invalidateClient right before the call of applyResource.
// We return earlier for the moment. This bug should be fixed in:
// https://bugs.webkit.org/show_bug.cgi?id=35181
if (!m_clipper.contains(object))
return;
m_clipper.remove(object);
}
bool RenderSVGResourceClipper::applyResource(RenderObject* object, GraphicsContext* context)
{
ASSERT(object);
ASSERT(context);
m_clipper.add(object);
context->beginPath();
AffineTransform obbTransform;
FloatRect objectBoundingBox = object->objectBoundingBox();
bool bbox = static_cast<SVGClipPathElement*>(node())->clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX;
if (bbox) {
obbTransform.translate(objectBoundingBox.x(), objectBoundingBox.y());
obbTransform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
}
bool hasClipPath = false;
WindRule clipRule = RULE_EVENODD;
for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) {
if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyledTransformable())
continue;
SVGStyledTransformableElement* styled = static_cast<SVGStyledTransformableElement*>(childNode);
RenderStyle* style = styled->renderer() ? styled->renderer()->style() : 0;
if (!style || style->display() == NONE)
continue;
Path pathData = styled->toClipPath();
if (pathData.isEmpty())
continue;
if (bbox)
pathData.transform(obbTransform);
hasClipPath = true;
context->addPath(pathData);
clipRule = style->svgStyle()->clipRule();
}
if (!hasClipPath) {
Path clipPath;
clipPath.addRect(FloatRect());
context->addPath(clipPath);
}
// FIXME!
// We don't currently allow for heterogenous clip rules.
// we would have to detect such, draw to a mask, and then clip
// to that mask
context->clipPath(clipRule);
return true;
}
FloatRect RenderSVGResourceClipper::resourceBoundingBox(const FloatRect& objectBoundingBox) const
{
FloatRect clipRect;
for (Node* childNode = node()->firstChild(); childNode; childNode = childNode->nextSibling()) {
if (!childNode->isSVGElement() || !static_cast<SVGElement*>(childNode)->isStyledTransformable())
continue;
SVGStyledTransformableElement* styled = static_cast<SVGStyledTransformableElement*>(childNode);
RenderStyle* style = styled->renderer() ? styled->renderer()->style() : 0;
if (!style || style->display() == NONE)
continue;
clipRect.unite(styled->renderer()->objectBoundingBox());
}
if (clipRect.isEmpty())
return FloatRect();
if (static_cast<SVGClipPathElement*>(node())->clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
AffineTransform obbTransform;
obbTransform.translate(objectBoundingBox.x(), objectBoundingBox.y());
obbTransform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
return obbTransform.mapRect(clipRect);
}
return clipRect;
}
}