Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1844)

Unified Diff: Source/core/rendering/svg/RenderSVGResourceClipper.cpp

Issue 908243002: Move rendering/svg/RenderSVGResource* to layout/svg. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: Source/core/rendering/svg/RenderSVGResourceClipper.cpp
diff --git a/Source/core/rendering/svg/RenderSVGResourceClipper.cpp b/Source/core/rendering/svg/RenderSVGResourceClipper.cpp
deleted file mode 100644
index 049d674450be0a93612f37ec78c65bcbe511600b..0000000000000000000000000000000000000000
--- a/Source/core/rendering/svg/RenderSVGResourceClipper.cpp
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * Copyright (C) 2004, 2005, 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org>
- * Copyright (C) 2004, 2005, 2006, 2007, 2008 Rob Buis <buis@kde.org>
- * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved.
- * Copyright (C) 2011 Dirk Schulze <krit@webkit.org>
- *
- * 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 "core/rendering/svg/RenderSVGResourceClipper.h"
-
-#include "core/SVGNames.h"
-#include "core/dom/ElementTraversal.h"
-#include "core/layout/HitTestResult.h"
-#include "core/layout/PaintInfo.h"
-#include "core/layout/svg/SVGLayoutSupport.h"
-#include "core/layout/svg/SVGResources.h"
-#include "core/layout/svg/SVGResourcesCache.h"
-#include "core/svg/SVGUseElement.h"
-#include "platform/RuntimeEnabledFeatures.h"
-#include "platform/graphics/GraphicsContextStateSaver.h"
-#include "platform/graphics/paint/ClipPathDisplayItem.h"
-#include "platform/graphics/paint/DisplayItemList.h"
-#include "third_party/skia/include/core/SkPicture.h"
-#include "wtf/TemporaryChange.h"
-
-namespace blink {
-
-RenderSVGResourceClipper::RenderSVGResourceClipper(SVGClipPathElement* node)
- : RenderSVGResourceContainer(node)
- , m_inClipExpansion(false)
-{
-}
-
-RenderSVGResourceClipper::~RenderSVGResourceClipper()
-{
-}
-
-void RenderSVGResourceClipper::removeAllClientsFromCache(bool markForInvalidation)
-{
- m_clipContentPicture.clear();
- m_clipBoundaries = FloatRect();
- markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation);
-}
-
-void RenderSVGResourceClipper::removeClientFromCache(LayoutObject* client, bool markForInvalidation)
-{
- ASSERT(client);
- markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidation : ParentOnlyInvalidation);
-}
-
-bool RenderSVGResourceClipper::applyStatefulResource(LayoutObject* object, GraphicsContext*& context, ClipperState& clipperState)
-{
- ASSERT(object);
- ASSERT(context);
-
- clearInvalidationMask();
-
- return applyClippingToContext(object, object->objectBoundingBox(), object->paintInvalidationRectInLocalCoordinates(), context, clipperState);
-}
-
-bool RenderSVGResourceClipper::tryPathOnlyClipping(DisplayItemClient client, GraphicsContext* context,
- const AffineTransform& animatedLocalTransform, const FloatRect& objectBoundingBox) {
- // If the current clip-path gets clipped itself, we have to fallback to masking.
- if (!style()->svgStyle().clipperResource().isEmpty())
- return false;
- WindRule clipRule = RULE_NONZERO;
- Path clipPath = Path();
-
- for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement)) {
- LayoutObject* renderer = childElement->renderer();
- if (!renderer)
- continue;
- // Only shapes or paths are supported for direct clipping. We need to fallback to masking for texts.
- if (renderer->isSVGText())
- return false;
- if (!childElement->isSVGGraphicsElement())
- continue;
- SVGGraphicsElement* styled = toSVGGraphicsElement(childElement);
- const LayoutStyle* style = renderer->style();
- if (!style || style->display() == NONE || style->visibility() != VISIBLE)
- continue;
- const SVGLayoutStyle& svgStyle = style->svgStyle();
- // Current shape in clip-path gets clipped too. Fallback to masking.
- if (!svgStyle.clipperResource().isEmpty())
- return false;
-
- if (clipPath.isEmpty()) {
- // First clip shape.
- styled->toClipPath(clipPath);
- clipRule = svgStyle.clipRule();
- clipPath.setWindRule(clipRule);
- continue;
- }
-
- if (RuntimeEnabledFeatures::pathOpsSVGClippingEnabled()) {
- // Attempt to generate a combined clip path, fall back to masking if not possible.
- Path subPath;
- styled->toClipPath(subPath);
- subPath.setWindRule(svgStyle.clipRule());
- if (!clipPath.unionPath(subPath))
- return false;
- } else {
- return false;
- }
- }
- // Only one visible shape/path was found. Directly continue clipping and transform the content to userspace if necessary.
- if (clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
- AffineTransform transform;
- transform.translate(objectBoundingBox.x(), objectBoundingBox.y());
- transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
- clipPath.transform(transform);
- }
-
- // Transform path by animatedLocalTransform.
- clipPath.transform(animatedLocalTransform);
-
- // The SVG specification wants us to clip everything, if clip-path doesn't have a child.
- if (clipPath.isEmpty())
- clipPath.addRect(FloatRect());
-
- if (RuntimeEnabledFeatures::slimmingPaintEnabled()) {
- context->displayItemList()->add(BeginClipPathDisplayItem::create(client, clipPath, clipRule));
- } else {
- BeginClipPathDisplayItem clipPathDisplayItem(client, clipPath, clipRule);
- clipPathDisplayItem.replay(context);
- }
-
- return true;
-}
-
-bool RenderSVGResourceClipper::applyClippingToContext(LayoutObject* target, const FloatRect& targetBoundingBox,
- const FloatRect& paintInvalidationRect, GraphicsContext* context, ClipperState& clipperState)
-{
- ASSERT(target);
- ASSERT(context);
- ASSERT(clipperState == ClipperNotApplied);
- ASSERT_WITH_SECURITY_IMPLICATION(!needsLayout());
-
- if (paintInvalidationRect.isEmpty() || m_inClipExpansion)
- return false;
- TemporaryChange<bool> inClipExpansionChange(m_inClipExpansion, true);
-
- AffineTransform animatedLocalTransform = toSVGClipPathElement(element())->calculateAnimatedLocalTransform();
- // When drawing a clip for non-SVG elements, the CTM does not include the zoom factor.
- // In this case, we need to apply the zoom scale explicitly - but only for clips with
- // userSpaceOnUse units (the zoom is accounted for objectBoundingBox-resolved lengths).
- if (!target->isSVG() && clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_USERSPACEONUSE) {
- ASSERT(style());
- animatedLocalTransform.scale(style()->effectiveZoom());
- }
-
- // First, try to apply the clip as a clipPath.
- if (tryPathOnlyClipping(target->displayItemClient(), context, animatedLocalTransform, targetBoundingBox)) {
- clipperState = ClipperAppliedPath;
- return true;
- }
-
- // Fall back to masking.
- clipperState = ClipperAppliedMask;
-
- // Mask layer start
- context->beginTransparencyLayer(1, &paintInvalidationRect);
- {
- GraphicsContextStateSaver maskContentSaver(*context);
- context->concatCTM(animatedLocalTransform);
-
- // clipPath can also be clipped by another clipPath.
- SVGResources* resources = SVGResourcesCache::cachedResourcesForLayoutObject(this);
- RenderSVGResourceClipper* clipPathClipper = resources ? resources->clipper() : 0;
- ClipperState clipPathClipperState = ClipperNotApplied;
- if (clipPathClipper && !clipPathClipper->applyClippingToContext(this, targetBoundingBox, paintInvalidationRect, context, clipPathClipperState)) {
- // FIXME: Awkward state micro-management. Ideally, GraphicsContextStateSaver should
- // a) pop saveLayers also
- // b) pop multiple states if needed (similarly to SkCanvas::restoreToCount())
- // Then we should be able to replace this mess with a single, top-level GCSS.
- maskContentSaver.restore();
- context->endLayer();
- return false;
- }
-
- drawClipMaskContent(context, targetBoundingBox);
-
- if (clipPathClipper)
- clipPathClipper->postApplyStatefulResource(this, context, clipPathClipperState);
- }
-
- // Masked content layer start.
- context->beginLayer(1, SkXfermode::kSrcIn_Mode, &paintInvalidationRect);
-
- return true;
-}
-
-void RenderSVGResourceClipper::postApplyStatefulResource(LayoutObject* target, GraphicsContext*& context, ClipperState& clipperState)
-{
- switch (clipperState) {
- case ClipperAppliedPath:
- // Path-only clipping, no layers to restore but we need to emit an end to the clip path display item.
- {
- if (RuntimeEnabledFeatures::slimmingPaintEnabled()) {
- context->displayItemList()->add(EndClipPathDisplayItem::create(target->displayItemClient()));
- } else {
- EndClipPathDisplayItem endClipPathDisplayItem(target->displayItemClient());
- endClipPathDisplayItem.replay(context);
- }
- }
- break;
- case ClipperAppliedMask:
- // Transfer content layer -> mask layer (SrcIn)
- context->endLayer();
- // Transfer mask layer -> bg layer (SrcOver)
- context->endLayer();
- break;
- default:
- ASSERT_NOT_REACHED();
- }
-}
-
-void RenderSVGResourceClipper::drawClipMaskContent(GraphicsContext* context, const FloatRect& targetBoundingBox)
-{
- ASSERT(context);
-
- AffineTransform contentTransformation;
- if (clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
- contentTransformation.translate(targetBoundingBox.x(), targetBoundingBox.y());
- contentTransformation.scaleNonUniform(targetBoundingBox.width(), targetBoundingBox.height());
- context->concatCTM(contentTransformation);
- }
-
- if (!m_clipContentPicture) {
- SubtreeContentTransformScope contentTransformScope(contentTransformation);
- createPicture(context);
- }
-
- context->drawPicture(m_clipContentPicture.get());
-}
-
-void RenderSVGResourceClipper::createPicture(GraphicsContext* context)
-{
- ASSERT(context);
- ASSERT(frame());
-
- // Using strokeBoundingBox (instead of paintInvalidationRectInLocalCoordinates) to avoid the intersection
- // with local clips/mask, which may yield incorrect results when mixing objectBoundingBox and
- // userSpaceOnUse units (http://crbug.com/294900).
- FloatRect bounds = strokeBoundingBox();
- context->beginRecording(bounds);
-
- for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement)) {
- LayoutObject* renderer = childElement->renderer();
- if (!renderer)
- continue;
-
- const LayoutStyle* style = renderer->style();
- if (!style || style->display() == NONE || style->visibility() != VISIBLE)
- continue;
-
- WindRule newClipRule = style->svgStyle().clipRule();
- bool isUseElement = isSVGUseElement(*childElement);
- if (isUseElement) {
- SVGUseElement& useElement = toSVGUseElement(*childElement);
- renderer = useElement.rendererClipChild();
- if (!renderer)
- continue;
- if (!useElement.hasAttribute(SVGNames::clip_ruleAttr))
- newClipRule = renderer->style()->svgStyle().clipRule();
- }
-
- // Only shapes, paths and texts are allowed for clipping.
- if (!renderer->isSVGShape() && !renderer->isSVGText())
- continue;
-
- context->setFillRule(newClipRule);
-
- if (isUseElement)
- renderer = childElement->renderer();
-
- // Switch to a paint behavior where all children of this <clipPath> will be rendered using special constraints:
- // - fill-opacity/stroke-opacity/opacity set to 1
- // - masker/filter not applied when rendering the children
- // - fill is set to the initial fill paint server (solid, black)
- // - stroke is set to the initial stroke paint server (none)
- PaintInfo info(context, LayoutRect::infiniteIntRect(), PaintPhaseForeground, PaintBehaviorRenderingClipPathAsMask);
- renderer->paint(info, IntPoint());
- }
-
- m_clipContentPicture = context->endRecording();
-}
-
-void RenderSVGResourceClipper::calculateClipContentPaintInvalidationRect()
-{
- // This is a rough heuristic to appraise the clip size and doesn't consider clip on clip.
- for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement)) {
- LayoutObject* renderer = childElement->renderer();
- if (!renderer)
- continue;
- if (!renderer->isSVGShape() && !renderer->isSVGText() && !isSVGUseElement(*childElement))
- continue;
- const LayoutStyle* style = renderer->style();
- if (!style || style->display() == NONE || style->visibility() != VISIBLE)
- continue;
- m_clipBoundaries.unite(renderer->localToParentTransform().mapRect(renderer->paintInvalidationRectInLocalCoordinates()));
- }
- m_clipBoundaries = toSVGClipPathElement(element())->calculateAnimatedLocalTransform().mapRect(m_clipBoundaries);
-}
-
-bool RenderSVGResourceClipper::hitTestClipContent(const FloatRect& objectBoundingBox, const FloatPoint& nodeAtPoint)
-{
- FloatPoint point = nodeAtPoint;
- if (!SVGLayoutSupport::pointInClippingArea(this, point))
- return false;
-
- if (clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
- AffineTransform transform;
- transform.translate(objectBoundingBox.x(), objectBoundingBox.y());
- transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
- point = transform.inverse().mapPoint(point);
- }
-
- AffineTransform animatedLocalTransform = toSVGClipPathElement(element())->calculateAnimatedLocalTransform();
- if (!animatedLocalTransform.isInvertible())
- return false;
-
- point = animatedLocalTransform.inverse().mapPoint(point);
-
- for (SVGElement* childElement = Traversal<SVGElement>::firstChild(*element()); childElement; childElement = Traversal<SVGElement>::nextSibling(*childElement)) {
- LayoutObject* renderer = childElement->renderer();
- if (!renderer)
- continue;
- if (!renderer->isSVGShape() && !renderer->isSVGText() && !isSVGUseElement(*childElement))
- continue;
- IntPoint hitPoint;
- HitTestResult result(hitPoint);
- if (renderer->nodeAtFloatPoint(HitTestRequest(HitTestRequest::SVGClipContent), result, point, HitTestForeground))
- return true;
- }
-
- return false;
-}
-
-FloatRect RenderSVGResourceClipper::resourceBoundingBox(const LayoutObject* object)
-{
- // Resource was not layouted yet. Give back the boundingBox of the object.
- if (selfNeedsLayout())
- return object->objectBoundingBox();
-
- if (m_clipBoundaries.isEmpty())
- calculateClipContentPaintInvalidationRect();
-
- if (clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
- FloatRect objectBoundingBox = object->objectBoundingBox();
- AffineTransform transform;
- transform.translate(objectBoundingBox.x(), objectBoundingBox.y());
- transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
- return transform.mapRect(m_clipBoundaries);
- }
-
- return m_clipBoundaries;
-}
-
-}
« no previous file with comments | « Source/core/rendering/svg/RenderSVGResourceClipper.h ('k') | Source/core/rendering/svg/RenderSVGResourceContainer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698