summaryrefslogtreecommitdiff
path: root/Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp')
-rw-r--r--Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp104
1 files changed, 48 insertions, 56 deletions
diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp
index 5a6af206d..5d835fe17 100644
--- a/Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp
+++ b/Source/WebCore/rendering/svg/RenderSVGResourceClipper.cpp
@@ -21,8 +21,6 @@
*/
#include "config.h"
-
-#if ENABLE(SVG)
#include "RenderSVGResourceClipper.h"
#include "ElementIterator.h"
@@ -42,10 +40,8 @@
namespace WebCore {
-RenderSVGResourceType RenderSVGResourceClipper::s_resourceType = ClipperResourceType;
-
-RenderSVGResourceClipper::RenderSVGResourceClipper(SVGClipPathElement& element, PassRef<RenderStyle> style)
- : RenderSVGResourceContainer(element, std::move(style))
+RenderSVGResourceClipper::RenderSVGResourceClipper(SVGClipPathElement& element, RenderStyle&& style)
+ : RenderSVGResourceContainer(element, WTFMove(style))
{
}
@@ -61,7 +57,7 @@ void RenderSVGResourceClipper::removeAllClientsFromCache(bool markForInvalidatio
markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation);
}
-void RenderSVGResourceClipper::removeClientFromCache(RenderObject& client, bool markForInvalidation)
+void RenderSVGResourceClipper::removeClientFromCache(RenderElement& client, bool markForInvalidation)
{
m_clipper.remove(&client);
@@ -73,10 +69,10 @@ bool RenderSVGResourceClipper::applyResource(RenderElement& renderer, const Rend
ASSERT(context);
ASSERT_UNUSED(resourceMode, resourceMode == ApplyToDefaultMode);
- return applyClippingToContext(renderer, renderer.objectBoundingBox(), renderer.repaintRectInLocalCoordinates(), context);
+ return applyClippingToContext(renderer, renderer.objectBoundingBox(), renderer.repaintRectInLocalCoordinates(), *context);
}
-bool RenderSVGResourceClipper::pathOnlyClipping(GraphicsContext* context, const AffineTransform& animatedLocalTransform, const FloatRect& objectBoundingBox)
+bool RenderSVGResourceClipper::pathOnlyClipping(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())
@@ -96,9 +92,9 @@ bool RenderSVGResourceClipper::pathOnlyClipping(GraphicsContext* context, const
// Only shapes or paths are supported for direct clipping. We need to fallback to masking for texts.
if (renderer->isSVGText())
return false;
- if (!childNode->isSVGElement() || !toSVGElement(childNode)->isSVGGraphicsElement())
+ if (!childNode->isSVGElement() || !downcast<SVGElement>(*childNode).isSVGGraphicsElement())
continue;
- SVGGraphicsElement* styled = toSVGGraphicsElement(childNode);
+ SVGGraphicsElement& styled = downcast<SVGGraphicsElement>(*childNode);
const RenderStyle& style = renderer->style();
if (style.display() == NONE || style.visibility() != VISIBLE)
continue;
@@ -108,7 +104,7 @@ bool RenderSVGResourceClipper::pathOnlyClipping(GraphicsContext* context, const
return false;
// Fallback to masking, if there is more than one clipping path.
if (clipPath.isEmpty()) {
- styled->toClipPath(clipPath);
+ styled.toClipPath(clipPath);
clipRule = svgStyle.clipRule();
} else
return false;
@@ -127,77 +123,68 @@ bool RenderSVGResourceClipper::pathOnlyClipping(GraphicsContext* context, const
// The SVG specification wants us to clip everything, if clip-path doesn't have a child.
if (clipPath.isEmpty())
clipPath.addRect(FloatRect());
- context->clipPath(clipPath, clipRule);
+ context.clipPath(clipPath, clipRule);
return true;
}
-bool RenderSVGResourceClipper::applyClippingToContext(RenderElement& renderer, const FloatRect& objectBoundingBox,
- const FloatRect& repaintRect, GraphicsContext* context)
+bool RenderSVGResourceClipper::applyClippingToContext(RenderElement& renderer, const FloatRect& objectBoundingBox, const FloatRect& repaintRect, GraphicsContext& context)
{
- bool missingClipperData = !m_clipper.contains(&renderer);
- if (missingClipperData)
- m_clipper.set(&renderer, std::make_unique<ClipperData>());
+ ClipperMaskImage& clipperMaskImage = addRendererToClipper(renderer);
+ bool shouldCreateClipperMaskImage = !clipperMaskImage;
- bool shouldCreateClipData = false;
AffineTransform animatedLocalTransform = clipPathElement().animatedLocalTransform();
- ClipperData* clipperData = m_clipper.get(&renderer);
- if (!clipperData->clipMaskImage) {
- if (pathOnlyClipping(context, animatedLocalTransform, objectBoundingBox))
- return true;
- shouldCreateClipData = true;
- }
- AffineTransform absoluteTransform;
- SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(&renderer, absoluteTransform);
+ if (shouldCreateClipperMaskImage && pathOnlyClipping(context, animatedLocalTransform, objectBoundingBox))
+ return true;
- if (shouldCreateClipData && !repaintRect.isEmpty()) {
- if (!SVGRenderingContext::createImageBuffer(repaintRect, absoluteTransform, clipperData->clipMaskImage, ColorSpaceDeviceRGB, Unaccelerated))
- return false;
+ AffineTransform absoluteTransform = SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(renderer);
- GraphicsContext* maskContext = clipperData->clipMaskImage->context();
- ASSERT(maskContext);
+ if (shouldCreateClipperMaskImage && !repaintRect.isEmpty()) {
+ // FIXME (149469): This image buffer should not be unconditionally unaccelerated. Making it match the context breaks nested clipping, though.
+ clipperMaskImage = SVGRenderingContext::createImageBuffer(repaintRect, absoluteTransform, ColorSpaceSRGB, Unaccelerated);
+ if (!clipperMaskImage)
+ return false;
- maskContext->concatCTM(animatedLocalTransform);
+ GraphicsContext& maskContext = clipperMaskImage->context();
+ maskContext.concatCTM(animatedLocalTransform);
// clipPath can also be clipped by another clipPath.
- SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(*this);
+ auto* resources = SVGResourcesCache::cachedResourcesForRenderer(*this);
RenderSVGResourceClipper* clipper;
bool succeeded;
if (resources && (clipper = resources->clipper())) {
- GraphicsContextStateSaver stateSaver(*maskContext);
+ GraphicsContextStateSaver stateSaver(maskContext);
if (!clipper->applyClippingToContext(*this, objectBoundingBox, repaintRect, maskContext))
return false;
- succeeded = drawContentIntoMaskImage(clipperData, objectBoundingBox);
+ succeeded = drawContentIntoMaskImage(clipperMaskImage, objectBoundingBox);
// The context restore applies the clipping on non-CG platforms.
} else
- succeeded = drawContentIntoMaskImage(clipperData, objectBoundingBox);
+ succeeded = drawContentIntoMaskImage(clipperMaskImage, objectBoundingBox);
if (!succeeded)
- clipperData->clipMaskImage.reset();
+ clipperMaskImage.reset();
}
- if (!clipperData->clipMaskImage)
+ if (!clipperMaskImage)
return false;
- SVGRenderingContext::clipToImageBuffer(context, absoluteTransform, repaintRect, clipperData->clipMaskImage, missingClipperData);
+ SVGRenderingContext::clipToImageBuffer(context, absoluteTransform, repaintRect, clipperMaskImage, shouldCreateClipperMaskImage);
return true;
}
-bool RenderSVGResourceClipper::drawContentIntoMaskImage(ClipperData* clipperData, const FloatRect& objectBoundingBox)
+bool RenderSVGResourceClipper::drawContentIntoMaskImage(const ClipperMaskImage& clipperMaskImage, const FloatRect& objectBoundingBox)
{
- ASSERT(clipperData);
- ASSERT(clipperData->clipMaskImage);
+ ASSERT(clipperMaskImage);
- GraphicsContext* maskContext = clipperData->clipMaskImage->context();
- ASSERT(maskContext);
+ GraphicsContext& maskContext = clipperMaskImage->context();
AffineTransform maskContentTransformation;
if (clipPathElement().clipPathUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
maskContentTransformation.translate(objectBoundingBox.x(), objectBoundingBox.y());
maskContentTransformation.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
- maskContext->concatCTM(maskContentTransformation);
+ maskContext.concatCTM(maskContentTransformation);
}
// Switch to a paint behavior where all children of this <clipPath> will be rendered using special constraints:
@@ -224,11 +211,11 @@ bool RenderSVGResourceClipper::drawContentIntoMaskImage(ClipperData* clipperData
WindRule newClipRule = style.svgStyle().clipRule();
bool isUseElement = child.hasTagName(SVGNames::useTag);
if (isUseElement) {
- SVGUseElement& useElement = toSVGUseElement(child);
+ SVGUseElement& useElement = downcast<SVGUseElement>(child);
renderer = useElement.rendererClipChild();
if (!renderer)
continue;
- if (!useElement.hasAttribute(SVGNames::clip_ruleAttr))
+ if (!useElement.hasAttributeWithoutSynchronization(SVGNames::clip_ruleAttr))
newClipRule = renderer->style().svgStyle().clipRule();
}
@@ -236,12 +223,12 @@ bool RenderSVGResourceClipper::drawContentIntoMaskImage(ClipperData* clipperData
if (!renderer->isSVGShape() && !renderer->isSVGText())
continue;
- maskContext->setFillRule(newClipRule);
+ maskContext.setFillRule(newClipRule);
// In the case of a <use> element, we obtained its renderere above, to retrieve its clipRule.
// We have to pass the <use> renderer itself to renderSubtreeToImageBuffer() to apply it's x/y/transform/etc. values when rendering.
// So if isUseElement is true, refetch the childNode->renderer(), as renderer got overriden above.
- SVGRenderingContext::renderSubtreeToImageBuffer(clipperData->clipMaskImage.get(), isUseElement ? *child.renderer() : *renderer, maskContentTransformation);
+ SVGRenderingContext::renderSubtreeToImageBuffer(clipperMaskImage.get(), isUseElement ? *child.renderer() : *renderer, maskContentTransformation);
}
view().frameView().setPaintBehavior(oldBehavior);
@@ -265,6 +252,11 @@ void RenderSVGResourceClipper::calculateClipContentRepaintRect()
m_clipBoundaries = clipPathElement().animatedLocalTransform().mapRect(m_clipBoundaries);
}
+ClipperMaskImage& RenderSVGResourceClipper::addRendererToClipper(const RenderObject& object)
+{
+ return m_clipper.add(&object, ClipperMaskImage()).iterator->value;
+}
+
bool RenderSVGResourceClipper::hitTestClipContent(const FloatRect& objectBoundingBox, const FloatPoint& nodeAtPoint)
{
FloatPoint point = nodeAtPoint;
@@ -275,10 +267,10 @@ bool RenderSVGResourceClipper::hitTestClipContent(const FloatRect& objectBoundin
AffineTransform transform;
transform.translate(objectBoundingBox.x(), objectBoundingBox.y());
transform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
- point = transform.inverse().mapPoint(point);
+ point = transform.inverse().value_or(AffineTransform()).mapPoint(point);
}
- point = clipPathElement().animatedLocalTransform().inverse().mapPoint(point);
+ point = clipPathElement().animatedLocalTransform().inverse().value_or(AffineTransform()).mapPoint(point);
for (Node* childNode = clipPathElement().firstChild(); childNode; childNode = childNode->nextSibling()) {
RenderObject* renderer = childNode->renderer();
@@ -288,7 +280,7 @@ bool RenderSVGResourceClipper::hitTestClipContent(const FloatRect& objectBoundin
continue;
IntPoint hitPoint;
HitTestResult result(hitPoint);
- if (renderer->nodeAtFloatPoint(HitTestRequest(HitTestRequest::SVGClipContent | HitTestRequest::DisallowShadowContent), result, point, HitTestForeground))
+ if (renderer->nodeAtFloatPoint(HitTestRequest(HitTestRequest::SVGClipContent | HitTestRequest::DisallowUserAgentShadowContent), result, point, HitTestForeground))
return true;
}
@@ -298,8 +290,10 @@ bool RenderSVGResourceClipper::hitTestClipContent(const FloatRect& objectBoundin
FloatRect RenderSVGResourceClipper::resourceBoundingBox(const RenderObject& object)
{
// Resource was not layouted yet. Give back the boundingBox of the object.
- if (selfNeedsLayout())
+ if (selfNeedsLayout()) {
+ addRendererToClipper(object);
return object.objectBoundingBox();
+ }
if (m_clipBoundaries.isEmpty())
calculateClipContentRepaintRect();
@@ -316,5 +310,3 @@ FloatRect RenderSVGResourceClipper::resourceBoundingBox(const RenderObject& obje
}
}
-
-#endif // ENABLE(SVG)