diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/rendering/svg | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/rendering/svg')
107 files changed, 3055 insertions, 3922 deletions
diff --git a/Source/WebCore/rendering/svg/RenderSVGAllInOne.cpp b/Source/WebCore/rendering/svg/RenderSVGAllInOne.cpp new file mode 100644 index 000000000..3cd5c4a3d --- /dev/null +++ b/Source/WebCore/rendering/svg/RenderSVGAllInOne.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2009, 2010 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +// This all-in-one cpp file cuts down on template bloat to allow us to build our Windows release build. + +#include "RenderSVGBlock.cpp" +#include "RenderSVGContainer.cpp" +#include "RenderSVGEllipse.cpp" +#include "RenderSVGForeignObject.cpp" +#include "RenderSVGGradientStop.cpp" +#include "RenderSVGHiddenContainer.cpp" +#include "RenderSVGImage.cpp" +#include "RenderSVGInline.cpp" +#include "RenderSVGInlineText.cpp" +#include "RenderSVGModelObject.cpp" +#include "RenderSVGPath.cpp" +#include "RenderSVGRect.cpp" +#include "RenderSVGResource.cpp" +#include "RenderSVGResourceClipper.cpp" +#include "RenderSVGResourceContainer.cpp" +#include "RenderSVGResourceFilter.cpp" +#include "RenderSVGResourceFilterPrimitive.cpp" +#include "RenderSVGResourceGradient.cpp" +#include "RenderSVGResourceLinearGradient.cpp" +#include "RenderSVGResourceMarker.cpp" +#include "RenderSVGResourceMasker.cpp" +#include "RenderSVGResourcePattern.cpp" +#include "RenderSVGResourceRadialGradient.cpp" +#include "RenderSVGResourceSolidColor.cpp" +#include "RenderSVGRoot.cpp" +#include "RenderSVGShape.cpp" +#include "RenderSVGText.cpp" +#include "RenderSVGTextPath.cpp" +#include "RenderSVGTransformableContainer.cpp" +#include "RenderSVGViewportContainer.cpp" +#include "SVGInlineFlowBox.cpp" +#include "SVGInlineTextBox.cpp" +#include "SVGPathData.cpp" +#include "SVGRenderSupport.cpp" +#include "SVGRenderTreeAsText.cpp" +#include "SVGRenderingContext.cpp" +#include "SVGResources.cpp" +#include "SVGResourcesCache.cpp" +#include "SVGResourcesCycleSolver.cpp" +#include "SVGRootInlineBox.cpp" +#include "SVGTextChunk.cpp" +#include "SVGTextChunkBuilder.cpp" +#include "SVGTextLayoutAttributes.cpp" +#include "SVGTextLayoutAttributesBuilder.cpp" +#include "SVGTextLayoutEngine.cpp" +#include "SVGTextLayoutEngineBaseline.cpp" +#include "SVGTextLayoutEngineSpacing.cpp" +#include "SVGTextMetrics.cpp" +#include "SVGTextMetricsBuilder.cpp" +#include "SVGTextQuery.cpp" + diff --git a/Source/WebCore/rendering/svg/RenderSVGBlock.cpp b/Source/WebCore/rendering/svg/RenderSVGBlock.cpp index 953728b01..ab63ecf97 100644 --- a/Source/WebCore/rendering/svg/RenderSVGBlock.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGBlock.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006 Apple Inc. * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> * Copyright (C) Research In Motion Limited 2010. All rights reserved. * @@ -20,8 +20,6 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGBlock.h" #include "RenderSVGResource.h" @@ -30,8 +28,8 @@ namespace WebCore { -RenderSVGBlock::RenderSVGBlock(SVGGraphicsElement& element, PassRef<RenderStyle> style) - : RenderBlockFlow(element, std::move(style)) +RenderSVGBlock::RenderSVGBlock(SVGGraphicsElement& element, RenderStyle&& style) + : RenderBlockFlow(element, WTFMove(style)) { } @@ -85,5 +83,3 @@ void RenderSVGBlock::styleDidChange(StyleDifference diff, const RenderStyle* old } } - -#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGBlock.h b/Source/WebCore/rendering/svg/RenderSVGBlock.h index 23efff55d..c231156ed 100644 --- a/Source/WebCore/rendering/svg/RenderSVGBlock.h +++ b/Source/WebCore/rendering/svg/RenderSVGBlock.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006 Apple Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -17,10 +17,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef RenderSVGBlock_h -#define RenderSVGBlock_h +#pragma once -#if ENABLE(SVG) #include "RenderBlockFlow.h" #include "SVGGraphicsElement.h" #include "SVGRenderSupport.h" @@ -31,26 +29,26 @@ class SVGElement; class RenderSVGBlock : public RenderBlockFlow { public: - virtual LayoutRect visualOverflowRect() const override final; + LayoutRect visualOverflowRect() const final; - SVGGraphicsElement& graphicsElement() const { return toSVGGraphicsElement(nodeForNonAnonymous()); } + SVGGraphicsElement& graphicsElement() const { return downcast<SVGGraphicsElement>(nodeForNonAnonymous()); } protected: - RenderSVGBlock(SVGGraphicsElement&, PassRef<RenderStyle>); - virtual void willBeDestroyed() override; + RenderSVGBlock(SVGGraphicsElement&, RenderStyle&&); + void willBeDestroyed() override; private: void element() const = delete; - virtual void updateFromStyle() override final; + void updateFromStyle() final; - virtual bool isRenderSVGBlock() const override final { return true; }; + bool isRenderSVGBlock() const final { return true; } - virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const; + void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const override; - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) override final; + void styleDidChange(StyleDifference, const RenderStyle* oldStyle) final; }; -} -#endif -#endif +} // namespace WebCore + +SPECIALIZE_TYPE_TRAITS_RENDER_OBJECT(RenderSVGBlock, isRenderSVGBlock()) diff --git a/Source/WebCore/rendering/svg/RenderSVGContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGContainer.cpp index 71c7bcc00..ccdf24f9c 100644 --- a/Source/WebCore/rendering/svg/RenderSVGContainer.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGContainer.cpp @@ -22,11 +22,10 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGContainer.h" #include "GraphicsContext.h" +#include "HitTestRequest.h" #include "LayoutRepainter.h" #include "RenderIterator.h" #include "RenderSVGResourceFilter.h" @@ -38,8 +37,8 @@ namespace WebCore { -RenderSVGContainer::RenderSVGContainer(SVGElement& element, PassRef<RenderStyle> style) - : RenderSVGModelObject(element, std::move(style)) +RenderSVGContainer::RenderSVGContainer(SVGElement& element, RenderStyle&& style) + : RenderSVGModelObject(element, WTFMove(style)) , m_objectBoundingBoxValid(false) , m_needsBoundariesUpdate(true) { @@ -103,13 +102,13 @@ void RenderSVGContainer::removeChild(RenderObject& child) bool RenderSVGContainer::selfWillPaint() { - SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(*this); + auto* resources = SVGResourcesCache::cachedResourcesForRenderer(*this); return resources && resources->filter(); } void RenderSVGContainer::paint(PaintInfo& paintInfo, const LayoutPoint&) { - if (paintInfo.context->paintingDisabled()) + if (paintInfo.context().paintingDisabled()) return; // Spec: groups w/o children still may render filter content. @@ -122,7 +121,7 @@ void RenderSVGContainer::paint(PaintInfo& paintInfo, const LayoutPoint&) PaintInfo childPaintInfo(paintInfo); { - GraphicsContextStateSaver stateSaver(*childPaintInfo.context); + GraphicsContextStateSaver stateSaver(childPaintInfo.context()); // Let the RenderSVGViewportContainer subclass clip if necessary applyViewportClip(childPaintInfo); @@ -144,20 +143,20 @@ void RenderSVGContainer::paint(PaintInfo& paintInfo, const LayoutPoint&) } // FIXME: This really should be drawn from local coordinates, but currently we hack it - // to avoid our clip killing our outline rect. Thus we translate our + // to avoid our clip killing our outline rect. Thus we translate our // outline rect into parent coords before drawing. // FIXME: This means our focus ring won't share our rotation like it should. // We should instead disable our clip during PaintPhaseOutline - if ((paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) && style().outlineWidth() && style().visibility() == VISIBLE) { + if (paintInfo.phase == PaintPhaseSelfOutline && style().outlineWidth() && style().visibility() == VISIBLE) { IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRect)); paintOutline(paintInfo, paintRectInParent); } } // addFocusRingRects is called from paintOutline and needs to be in the same coordinates as the paintOuline call -void RenderSVGContainer::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint&, const RenderLayerModelObject*) +void RenderSVGContainer::addFocusRingRects(Vector<LayoutRect>& rects, const LayoutPoint&, const RenderLayerModelObject*) { - IntRect paintRectInParent = enclosingIntRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates())); + LayoutRect paintRectInParent = LayoutRect(localToParentTransform().mapRect(repaintRectInLocalCoordinates())); if (!paintRectInParent.isEmpty()) rects.append(paintRectInParent); } @@ -174,21 +173,21 @@ bool RenderSVGContainer::nodeAtFloatPoint(const HitTestRequest& request, HitTest if (!pointIsInsideViewportClip(pointInParent)) return false; - FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent); + FloatPoint localPoint = localToParentTransform().inverse().value_or(AffineTransform()).mapPoint(pointInParent); if (!SVGRenderSupport::pointInClippingArea(*this, localPoint)) return false; for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { if (child->nodeAtFloatPoint(request, result, localPoint, hitTestAction)) { - updateHitTestResult(result, roundedLayoutPoint(localPoint)); + updateHitTestResult(result, LayoutPoint(localPoint)); return true; } } // Accessibility wants to return SVG containers, if appropriate. if (request.type() & HitTestRequest::AccessibilityHitTest && m_objectBoundingBox.contains(localPoint)) { - updateHitTestResult(result, roundedLayoutPoint(localPoint)); + updateHitTestResult(result, LayoutPoint(localPoint)); return true; } @@ -198,5 +197,3 @@ bool RenderSVGContainer::nodeAtFloatPoint(const HitTestRequest& request, HitTest } } - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGContainer.h b/Source/WebCore/rendering/svg/RenderSVGContainer.h index 78d318e99..bffbfefc5 100644 --- a/Source/WebCore/rendering/svg/RenderSVGContainer.h +++ b/Source/WebCore/rendering/svg/RenderSVGContainer.h @@ -20,10 +20,7 @@ * Boston, MA 02110-1301, USA. */ -#ifndef RenderSVGContainer_h -#define RenderSVGContainer_h - -#if ENABLE(SVG) +#pragma once #include "RenderSVGModelObject.h" @@ -35,31 +32,30 @@ class RenderSVGContainer : public RenderSVGModelObject { public: virtual ~RenderSVGContainer(); - virtual void paint(PaintInfo&, const LayoutPoint&) override; - virtual void setNeedsBoundariesUpdate() override final { m_needsBoundariesUpdate = true; } - virtual bool needsBoundariesUpdate() override final { return m_needsBoundariesUpdate; } + void paint(PaintInfo&, const LayoutPoint&) override; + void setNeedsBoundariesUpdate() final { m_needsBoundariesUpdate = true; } + bool needsBoundariesUpdate() final { return m_needsBoundariesUpdate; } virtual bool didTransformToRootUpdate() { return false; } bool isObjectBoundingBoxValid() const { return m_objectBoundingBoxValid; } protected: - RenderSVGContainer(SVGElement&, PassRef<RenderStyle>); + RenderSVGContainer(SVGElement&, RenderStyle&&); - virtual bool isSVGContainer() const override final { return true; } - virtual const char* renderName() const override { return "RenderSVGContainer"; } + const char* renderName() const override { return "RenderSVGContainer"; } - virtual bool canHaveChildren() const override final { return true; } + bool canHaveChildren() const final { return true; } - virtual void layout() override; + void layout() override; - virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0) override final; - virtual void removeChild(RenderObject&) override final; - virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer = 0) override final; + void addChild(RenderObject* child, RenderObject* beforeChild = 0) final; + void removeChild(RenderObject&) final; + void addFocusRingRects(Vector<LayoutRect>&, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer = 0) final; - virtual FloatRect objectBoundingBox() const override final { return m_objectBoundingBox; } - virtual FloatRect strokeBoundingBox() const override final { return m_strokeBoundingBox; } - virtual FloatRect repaintRectInLocalCoordinates() const override final { return m_repaintBoundingBox; } + FloatRect objectBoundingBox() const final { return m_objectBoundingBox; } + FloatRect strokeBoundingBox() const final { return m_strokeBoundingBox; } + FloatRect repaintRectInLocalCoordinates() const final { return m_repaintBoundingBox; } - virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction) override; + bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction) override; // Allow RenderSVGTransformableContainer to hook in at the right time in layout() virtual bool calculateLocalTransform() { return false; } @@ -75,6 +71,8 @@ protected: void updateCachedBoundaries(); private: + bool isSVGContainer() const final { return true; } + FloatRect m_objectBoundingBox; bool m_objectBoundingBoxValid; FloatRect m_strokeBoundingBox; @@ -82,9 +80,6 @@ private: bool m_needsBoundariesUpdate : 1; }; -RENDER_OBJECT_TYPE_CASTS(RenderSVGContainer, isSVGContainer()) - } // namespace WebCore -#endif // ENABLE(SVG) -#endif // RenderSVGContainer_h +SPECIALIZE_TYPE_TRAITS_RENDER_OBJECT(RenderSVGContainer, isSVGContainer()) diff --git a/Source/WebCore/rendering/svg/RenderSVGEllipse.cpp b/Source/WebCore/rendering/svg/RenderSVGEllipse.cpp index dac2e84ff..4b6dd4585 100644 --- a/Source/WebCore/rendering/svg/RenderSVGEllipse.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGEllipse.cpp @@ -25,18 +25,15 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGEllipse.h" #include "SVGCircleElement.h" #include "SVGEllipseElement.h" -#include "SVGNames.h" namespace WebCore { -RenderSVGEllipse::RenderSVGEllipse(SVGGraphicsElement& element, PassRef<RenderStyle> style) - : RenderSVGShape(element, std::move(style)) +RenderSVGEllipse::RenderSVGEllipse(SVGGraphicsElement& element, RenderStyle&& style) + : RenderSVGShape(element, WTFMove(style)) , m_usePathFallback(false) { } @@ -54,20 +51,23 @@ void RenderSVGEllipse::updateShapeFromElement() m_center = FloatPoint(); m_radii = FloatSize(); - // Fallback to RenderSVGShape if shape has a non-scaling stroke. - if (hasNonScalingStroke()) { - RenderSVGShape::updateShapeFromElement(); - m_usePathFallback = true; - return; - } else - m_usePathFallback = false; - calculateRadiiAndCenter(); - // Spec: "A value of zero disables rendering of the element." - if (m_radii.width() <= 0 || m_radii.height() <= 0) + // Element is invalid if either dimension is negative. + if (m_radii.width() < 0 || m_radii.height() < 0) return; + // Spec: "A value of zero disables rendering of the element." + if (!m_radii.isEmpty()) { + if (hasNonScalingStroke()) { + // Fallback to RenderSVGShape if shape has a non-scaling stroke. + RenderSVGShape::updateShapeFromElement(); + m_usePathFallback = true; + return; + } + m_usePathFallback = false; + } + m_fillBoundingBox = FloatRect(m_center.x() - m_radii.width(), m_center.y() - m_radii.height(), 2 * m_radii.width(), 2 * m_radii.height()); m_strokeBoundingBox = m_fillBoundingBox; if (style().svgStyle().hasStroke()) @@ -76,41 +76,40 @@ void RenderSVGEllipse::updateShapeFromElement() void RenderSVGEllipse::calculateRadiiAndCenter() { - if (isSVGCircleElement(graphicsElement())) { - SVGCircleElement& circle = toSVGCircleElement(graphicsElement()); - SVGLengthContext lengthContext(&circle); - float radius = circle.r().value(lengthContext); + SVGLengthContext lengthContext(&graphicsElement()); + m_center = FloatPoint( + lengthContext.valueForLength(style().svgStyle().cx(), LengthModeWidth), + lengthContext.valueForLength(style().svgStyle().cy(), LengthModeHeight)); + if (is<SVGCircleElement>(graphicsElement())) { + float radius = lengthContext.valueForLength(style().svgStyle().r()); m_radii = FloatSize(radius, radius); - m_center = FloatPoint(circle.cx().value(lengthContext), circle.cy().value(lengthContext)); return; } - ASSERT(isSVGEllipseElement(graphicsElement())); - SVGEllipseElement& ellipse = toSVGEllipseElement(graphicsElement()); - - SVGLengthContext lengthContext(&ellipse); - m_radii = FloatSize(ellipse.rx().value(lengthContext), ellipse.ry().value(lengthContext)); - m_center = FloatPoint(ellipse.cx().value(lengthContext), ellipse.cy().value(lengthContext)); + ASSERT(is<SVGEllipseElement>(graphicsElement())); + m_radii = FloatSize( + lengthContext.valueForLength(style().svgStyle().rx(), LengthModeWidth), + lengthContext.valueForLength(style().svgStyle().ry(), LengthModeHeight)); } -void RenderSVGEllipse::fillShape(GraphicsContext* context) const +void RenderSVGEllipse::fillShape(GraphicsContext& context) const { if (m_usePathFallback) { RenderSVGShape::fillShape(context); return; } - context->fillEllipse(m_fillBoundingBox); + context.fillEllipse(m_fillBoundingBox); } -void RenderSVGEllipse::strokeShape(GraphicsContext* context) const +void RenderSVGEllipse::strokeShape(GraphicsContext& context) const { - if (!style().svgStyle().hasVisibleStroke()) + if (!style().hasVisibleStroke()) return; if (m_usePathFallback) { RenderSVGShape::strokeShape(context); return; } - context->strokeEllipse(m_fillBoundingBox); + context.strokeEllipse(m_fillBoundingBox); } bool RenderSVGEllipse::shapeDependentStrokeContains(const FloatPoint& point) @@ -152,6 +151,10 @@ bool RenderSVGEllipse::shapeDependentFillContains(const FloatPoint& point, const return xrX * xrX + yrY * yrY <= 1.0; } +bool RenderSVGEllipse::isRenderingDisabled() const +{ + // A radius of zero disables rendering of the element, and results in an empty bounding box. + return m_fillBoundingBox.isEmpty(); } -#endif // ENABLE(SVG) +} diff --git a/Source/WebCore/rendering/svg/RenderSVGEllipse.h b/Source/WebCore/rendering/svg/RenderSVGEllipse.h index 4331c1841..a4deb99d8 100644 --- a/Source/WebCore/rendering/svg/RenderSVGEllipse.h +++ b/Source/WebCore/rendering/svg/RenderSVGEllipse.h @@ -24,28 +24,27 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef RenderSVGEllipse_h -#define RenderSVGEllipse_h +#pragma once -#if ENABLE(SVG) #include "RenderSVGShape.h" namespace WebCore { class RenderSVGEllipse final : public RenderSVGShape { public: - RenderSVGEllipse(SVGGraphicsElement&, PassRef<RenderStyle>); + RenderSVGEllipse(SVGGraphicsElement&, RenderStyle&&); virtual ~RenderSVGEllipse(); private: - virtual const char* renderName() const { return "RenderSVGEllipse"; } - - virtual void updateShapeFromElement(); - virtual bool isEmpty() const { return m_usePathFallback ? RenderSVGShape::isEmpty() : m_fillBoundingBox.isEmpty(); }; - virtual void fillShape(GraphicsContext*) const; - virtual void strokeShape(GraphicsContext*) const; - virtual bool shapeDependentStrokeContains(const FloatPoint&); - virtual bool shapeDependentFillContains(const FloatPoint&, const WindRule) const; + const char* renderName() const override { return "RenderSVGEllipse"; } + + void updateShapeFromElement() override; + bool isEmpty() const override { return m_usePathFallback ? RenderSVGShape::isEmpty() : m_fillBoundingBox.isEmpty(); } + bool isRenderingDisabled() const override; + void fillShape(GraphicsContext&) const override; + void strokeShape(GraphicsContext&) const override; + bool shapeDependentStrokeContains(const FloatPoint&) override; + bool shapeDependentFillContains(const FloatPoint&, const WindRule) const override; void calculateRadiiAndCenter(); private: @@ -54,7 +53,4 @@ private: bool m_usePathFallback; }; -} - -#endif // ENABLE(SVG) -#endif +} // namespace WebCore diff --git a/Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp b/Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp index 4ab82952b..b31f0211c 100644 --- a/Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGForeignObject.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006 Apple Inc. * Copyright (C) 2009 Google, Inc. * Copyright (C) Research In Motion Limited 2010. All rights reserved. * @@ -20,8 +20,6 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGForeignObject.h" #include "GraphicsContext.h" @@ -33,14 +31,13 @@ #include "SVGForeignObjectElement.h" #include "SVGRenderingContext.h" #include "SVGResourcesCache.h" -#include "SVGSVGElement.h" #include "TransformState.h" #include <wtf/StackStats.h> namespace WebCore { -RenderSVGForeignObject::RenderSVGForeignObject(SVGForeignObjectElement& element, PassRef<RenderStyle> style) - : RenderSVGBlock(element, std::move(style)) +RenderSVGForeignObject::RenderSVGForeignObject(SVGForeignObjectElement& element, RenderStyle&& style) + : RenderSVGBlock(element, WTFMove(style)) , m_needsTransformUpdate(true) { } @@ -51,47 +48,49 @@ RenderSVGForeignObject::~RenderSVGForeignObject() SVGForeignObjectElement& RenderSVGForeignObject::foreignObjectElement() const { - return toSVGForeignObjectElement(RenderSVGBlock::graphicsElement()); + return downcast<SVGForeignObjectElement>(RenderSVGBlock::graphicsElement()); } void RenderSVGForeignObject::paint(PaintInfo& paintInfo, const LayoutPoint&) { - if (paintInfo.context->paintingDisabled() - || (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection)) + if (paintInfo.context().paintingDisabled()) + return; + + if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection) return; PaintInfo childPaintInfo(paintInfo); - GraphicsContextStateSaver stateSaver(*childPaintInfo.context); + GraphicsContextStateSaver stateSaver(childPaintInfo.context()); childPaintInfo.applyTransform(localTransform()); if (SVGRenderSupport::isOverflowHidden(*this)) - childPaintInfo.context->clip(m_viewport); + childPaintInfo.context().clip(m_viewport); SVGRenderingContext renderingContext; - bool continueRendering = true; if (paintInfo.phase == PaintPhaseForeground) { renderingContext.prepareToRenderSVGContent(*this, childPaintInfo); - continueRendering = renderingContext.isRenderingPrepared(); + if (!renderingContext.isRenderingPrepared()) + return; } - if (continueRendering) { - // Paint all phases of FO elements atomically, as though the FO element established its - // own stacking context. - bool preservePhase = paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip; - LayoutPoint childPoint = IntPoint(); - childPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground; - RenderBlock::paint(childPaintInfo, IntPoint()); - if (!preservePhase) { - childPaintInfo.phase = PaintPhaseChildBlockBackgrounds; - RenderBlock::paint(childPaintInfo, childPoint); - childPaintInfo.phase = PaintPhaseFloat; - RenderBlock::paint(childPaintInfo, childPoint); - childPaintInfo.phase = PaintPhaseForeground; - RenderBlock::paint(childPaintInfo, childPoint); - childPaintInfo.phase = PaintPhaseOutline; - RenderBlock::paint(childPaintInfo, childPoint); - } + LayoutPoint childPoint = IntPoint(); + if (paintInfo.phase == PaintPhaseSelection) { + RenderBlock::paint(childPaintInfo, childPoint); + return; } + + // Paint all phases of FO elements atomically, as though the FO element established its + // own stacking context. + childPaintInfo.phase = PaintPhaseBlockBackground; + RenderBlock::paint(childPaintInfo, childPoint); + childPaintInfo.phase = PaintPhaseChildBlockBackgrounds; + RenderBlock::paint(childPaintInfo, childPoint); + childPaintInfo.phase = PaintPhaseFloat; + RenderBlock::paint(childPaintInfo, childPoint); + childPaintInfo.phase = PaintPhaseForeground; + RenderBlock::paint(childPaintInfo, childPoint); + childPaintInfo.phase = PaintPhaseOutline; + RenderBlock::paint(childPaintInfo, childPoint); } LayoutRect RenderSVGForeignObject::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const @@ -99,9 +98,14 @@ LayoutRect RenderSVGForeignObject::clippedOverflowRectForRepaint(const RenderLay return SVGRenderSupport::clippedOverflowRectForRepaint(*this, repaintContainer); } -void RenderSVGForeignObject::computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) const +FloatRect RenderSVGForeignObject::computeFloatRectForRepaint(const FloatRect& repaintRect, const RenderLayerModelObject* repaintContainer, bool fixed) const { - SVGRenderSupport::computeFloatRectForRepaint(*this, repaintContainer, repaintRect, fixed); + return SVGRenderSupport::computeFloatRectForRepaint(*this, repaintRect, repaintContainer, fixed); +} + +LayoutRect RenderSVGForeignObject::computeRectForRepaint(const LayoutRect& repaintRect, const RenderLayerModelObject* repaintContainer, RepaintContext context) const +{ + return enclosingLayoutRect(computeFloatRectForRepaint(repaintRect, repaintContainer, context.m_hasPositionFixedDescendant)); } const AffineTransform& RenderSVGForeignObject::localToParentTransform() const @@ -118,13 +122,12 @@ void RenderSVGForeignObject::updateLogicalWidth() setWidth(static_cast<int>(roundf(m_viewport.width()))); } -void RenderSVGForeignObject::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTop, LogicalExtentComputedValues& computedValues) const +RenderBox::LogicalExtentComputedValues RenderSVGForeignObject::computeLogicalHeight(LayoutUnit, LayoutUnit logicalTop) const { // FIXME: Investigate in size rounding issues // FIXME: Remove unnecessary rounding when layout is off ints: webkit.org/b/63656 // FIXME: Is this correct for vertical writing mode? - computedValues.m_extent = static_cast<int>(roundf(m_viewport.height())); - computedValues.m_position = logicalTop; + return { static_cast<int>(roundf(m_viewport.height())), logicalTop, ComputedMarginValues() }; } void RenderSVGForeignObject::layout() @@ -179,14 +182,14 @@ bool RenderSVGForeignObject::nodeAtFloatPoint(const HitTestRequest& request, Hit if (hitTestAction != HitTestForeground) return false; - FloatPoint localPoint = localTransform().inverse().mapPoint(pointInParent); + FloatPoint localPoint = localTransform().inverse().value_or(AffineTransform()).mapPoint(pointInParent); // Early exit if local point is not contained in clipped viewport area if (SVGRenderSupport::isOverflowHidden(*this) && !m_viewport.contains(localPoint)) return false; // FOs establish a stacking context, so we need to hit-test all layers. - HitTestLocation hitTestLocation(roundedLayoutPoint(localPoint)); + HitTestLocation hitTestLocation(localPoint); return RenderBlock::nodeAtPoint(request, result, hitTestLocation, LayoutPoint(), HitTestForeground) || RenderBlock::nodeAtPoint(request, result, hitTestLocation, LayoutPoint(), HitTestFloat) || RenderBlock::nodeAtPoint(request, result, hitTestLocation, LayoutPoint(), HitTestChildBlockBackgrounds); @@ -209,5 +212,3 @@ const RenderObject* RenderSVGForeignObject::pushMappingToContainer(const RenderL } } - -#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGForeignObject.h b/Source/WebCore/rendering/svg/RenderSVGForeignObject.h index b75c373f9..1011353a5 100644 --- a/Source/WebCore/rendering/svg/RenderSVGForeignObject.h +++ b/Source/WebCore/rendering/svg/RenderSVGForeignObject.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006 Apple Inc. * Copyright (C) 2009 Google, Inc. * * This library is free software; you can redistribute it and/or @@ -18,10 +18,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef RenderSVGForeignObject_h -#define RenderSVGForeignObject_h +#pragma once -#if ENABLE(SVG) #include "AffineTransform.h" #include "FloatPoint.h" #include "FloatRect.h" @@ -33,40 +31,41 @@ class SVGForeignObjectElement; class RenderSVGForeignObject final : public RenderSVGBlock { public: - RenderSVGForeignObject(SVGForeignObjectElement&, PassRef<RenderStyle>); + RenderSVGForeignObject(SVGForeignObjectElement&, RenderStyle&&); virtual ~RenderSVGForeignObject(); SVGForeignObjectElement& foreignObjectElement() const; - virtual void paint(PaintInfo&, const LayoutPoint&); + void paint(PaintInfo&, const LayoutPoint&) override; - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const override; - virtual void computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect&, bool fixed = false) const override; + LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const override; + FloatRect computeFloatRectForRepaint(const FloatRect&, const RenderLayerModelObject* repaintContainer, bool fixed = false) const override; + LayoutRect computeRectForRepaint(const LayoutRect&, const RenderLayerModelObject* repaintContainer, RepaintContext = { }) const override; - virtual bool requiresLayer() const { return false; } - virtual void layout(); + bool requiresLayer() const override { return false; } + void layout() override; - virtual FloatRect objectBoundingBox() const { return FloatRect(FloatPoint(), m_viewport.size()); } - virtual FloatRect strokeBoundingBox() const { return FloatRect(FloatPoint(), m_viewport.size()); } - virtual FloatRect repaintRectInLocalCoordinates() const { return FloatRect(FloatPoint(), m_viewport.size()); } + FloatRect objectBoundingBox() const override { return FloatRect(FloatPoint(), m_viewport.size()); } + FloatRect strokeBoundingBox() const override { return FloatRect(FloatPoint(), m_viewport.size()); } + FloatRect repaintRectInLocalCoordinates() const override { return FloatRect(FloatPoint(), m_viewport.size()); } - virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) override; - virtual bool isSVGForeignObject() const { return true; } + bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction) override; + bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) override; - virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const override; - virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const override; - virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; } + void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags, bool* wasFixed) const override; + const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const override; + void setNeedsTransformUpdate() override { m_needsTransformUpdate = true; } private: + bool isSVGForeignObject() const override { return true; } void graphicsElement() const = delete; - virtual const char* renderName() const override { return "RenderSVGForeignObject"; } + const char* renderName() const override { return "RenderSVGForeignObject"; } - virtual void updateLogicalWidth() override; - virtual void computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop, LogicalExtentComputedValues&) const override; + void updateLogicalWidth() override; + LogicalExtentComputedValues computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop) const override; - virtual const AffineTransform& localToParentTransform() const; - virtual AffineTransform localTransform() const { return m_localTransform; } + const AffineTransform& localToParentTransform() const override; + AffineTransform localTransform() const override { return m_localTransform; } bool m_needsTransformUpdate : 1; FloatRect m_viewport; @@ -74,7 +73,4 @@ private: mutable AffineTransform m_localToParentTransform; }; -} - -#endif -#endif +} // namespace WebCore diff --git a/Source/WebCore/rendering/svg/RenderSVGGradientStop.cpp b/Source/WebCore/rendering/svg/RenderSVGGradientStop.cpp index 6e90d6e01..41a159258 100644 --- a/Source/WebCore/rendering/svg/RenderSVGGradientStop.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGGradientStop.cpp @@ -18,8 +18,6 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGGradientStop.h" #include "RenderSVGResourceContainer.h" @@ -33,8 +31,8 @@ namespace WebCore { using namespace SVGNames; -RenderSVGGradientStop::RenderSVGGradientStop(SVGStopElement& element, PassRef<RenderStyle> style) - : RenderElement(element, std::move(style), 0) +RenderSVGGradientStop::RenderSVGGradientStop(SVGStopElement& element, RenderStyle&& style) + : RenderElement(element, WTFMove(style), 0) { } @@ -50,17 +48,15 @@ void RenderSVGGradientStop::styleDidChange(StyleDifference diff, const RenderSty // <stop> elements should only be allowed to make renderers under gradient elements // but I can imagine a few cases we might not be catching, so let's not crash if our parent isn't a gradient. - SVGGradientElement* gradient = gradientElement(); + const auto* gradient = gradientElement(); if (!gradient) return; - RenderObject* renderer = gradient->renderer(); + RenderElement* renderer = gradient->renderer(); if (!renderer) return; - ASSERT(renderer->isSVGResourceContainer()); - RenderSVGResourceContainer* container = renderer->toRenderSVGResourceContainer(); - container->removeAllClientsFromCache(); + downcast<RenderSVGResourceContainer>(*renderer).removeAllClientsFromCache(); } void RenderSVGGradientStop::layout() @@ -69,14 +65,11 @@ void RenderSVGGradientStop::layout() clearNeedsLayout(); } -SVGGradientElement* RenderSVGGradientStop::gradientElement() const +SVGGradientElement* RenderSVGGradientStop::gradientElement() { - ContainerNode* parentNode = element()->parentNode(); - if (parentNode->hasTagName(linearGradientTag) || parentNode->hasTagName(radialGradientTag)) - return toSVGGradientElement(parentNode); - return 0; + if (is<SVGGradientElement>(element().parentElement())) + return downcast<SVGGradientElement>(element().parentElement()); + return nullptr; } } - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGGradientStop.h b/Source/WebCore/rendering/svg/RenderSVGGradientStop.h index 9428bb85a..46ba3d33d 100644 --- a/Source/WebCore/rendering/svg/RenderSVGGradientStop.h +++ b/Source/WebCore/rendering/svg/RenderSVGGradientStop.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2007 Eric Seidel <eric@webkit.org> * Copyright (C) 2009 Google, Inc. + * Copyright (C) 2014 Apple Inc. 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 @@ -18,50 +19,46 @@ * Boston, MA 02110-1301, USA. */ -#ifndef RenderSVGGradientStop_h -#define RenderSVGGradientStop_h +#pragma once -#if ENABLE(SVG) #include "RenderElement.h" +#include "SVGStopElement.h" namespace WebCore { class SVGGradientElement; -class SVGStopElement; // This class exists mostly so we can hear about gradient stop style changes class RenderSVGGradientStop final : public RenderElement { public: - RenderSVGGradientStop(SVGStopElement&, PassRef<RenderStyle>); + RenderSVGGradientStop(SVGStopElement&, RenderStyle&&); virtual ~RenderSVGGradientStop(); - virtual bool isSVGGradientStop() const { return true; } - virtual const char* renderName() const { return "RenderSVGGradientStop"; } + SVGStopElement& element() const { return downcast<SVGStopElement>(RenderObject::nodeForNonAnonymous()); } - virtual void layout(); +private: + void styleDidChange(StyleDifference, const RenderStyle* oldStyle) override; + + void layout() override; - // This overrides are needed to prevent ASSERTs on <svg><stop /></svg> + // These overrides are needed to prevent ASSERTs on <svg><stop /></svg> // RenderObject's default implementations ASSERT_NOT_REACHED() // https://bugs.webkit.org/show_bug.cgi?id=20400 - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject*) const override { return LayoutRect(); } - virtual FloatRect objectBoundingBox() const { return FloatRect(); } - virtual FloatRect strokeBoundingBox() const { return FloatRect(); } - virtual FloatRect repaintRectInLocalCoordinates() const { return FloatRect(); } - virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint&, HitTestAction) override { return false; } + LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject*) const override { return LayoutRect(); } + FloatRect objectBoundingBox() const override { return FloatRect(); } + FloatRect strokeBoundingBox() const override { return FloatRect(); } + FloatRect repaintRectInLocalCoordinates() const override { return FloatRect(); } + bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint&, HitTestAction) override { return false; } -protected: - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle); + bool isSVGGradientStop() const override { return true; } + const char* renderName() const override { return "RenderSVGGradientStop"; } -private: - virtual bool canHaveChildren() const override { return false; } - virtual void paint(PaintInfo&, const LayoutPoint&) override final { } + bool canHaveChildren() const override { return false; } + void paint(PaintInfo&, const LayoutPoint&) override { } - SVGGradientElement* gradientElement() const; + SVGGradientElement* gradientElement(); }; -RENDER_OBJECT_TYPE_CASTS(RenderSVGGradientStop, isSVGGradientStop()) - -} +} // namespace WebCore -#endif // ENABLE(SVG) -#endif // RenderSVGGradientStop_h +SPECIALIZE_TYPE_TRAITS_RENDER_OBJECT(RenderSVGGradientStop, isSVGGradientStop()) diff --git a/Source/WebCore/rendering/svg/RenderSVGHiddenContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGHiddenContainer.cpp index e874860ca..39487aad8 100644 --- a/Source/WebCore/rendering/svg/RenderSVGHiddenContainer.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGHiddenContainer.cpp @@ -18,8 +18,6 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGHiddenContainer.h" #include "RenderSVGPath.h" @@ -27,8 +25,8 @@ namespace WebCore { -RenderSVGHiddenContainer::RenderSVGHiddenContainer(SVGElement& element, PassRef<RenderStyle> style) - : RenderSVGContainer(element, std::move(style)) +RenderSVGHiddenContainer::RenderSVGHiddenContainer(SVGElement& element, RenderStyle&& style) + : RenderSVGContainer(element, WTFMove(style)) { } @@ -56,5 +54,3 @@ bool RenderSVGHiddenContainer::nodeAtFloatPoint(const HitTestRequest&, HitTestRe } } - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGHiddenContainer.h b/Source/WebCore/rendering/svg/RenderSVGHiddenContainer.h index 44abca36d..236438d5c 100644 --- a/Source/WebCore/rendering/svg/RenderSVGHiddenContainer.h +++ b/Source/WebCore/rendering/svg/RenderSVGHiddenContainer.h @@ -17,10 +17,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef RenderSVGHiddenContainer_h -#define RenderSVGHiddenContainer_h +#pragma once -#if ENABLE(SVG) #include "RenderSVGContainer.h" namespace WebCore { @@ -31,23 +29,21 @@ class SVGElement; // <defs>, <linearGradient>, <radialGradient> are all good examples class RenderSVGHiddenContainer : public RenderSVGContainer { public: - RenderSVGHiddenContainer(SVGElement&, PassRef<RenderStyle>); + RenderSVGHiddenContainer(SVGElement&, RenderStyle&&); protected: - virtual void layout() override; + void layout() override; private: - virtual bool isSVGHiddenContainer() const override final { return true; } - virtual const char* renderName() const override { return "RenderSVGHiddenContainer"; } + bool isSVGHiddenContainer() const final { return true; } + const char* renderName() const override { return "RenderSVGHiddenContainer"; } - virtual void paint(PaintInfo&, const LayoutPoint&) override final; + void paint(PaintInfo&, const LayoutPoint&) final; - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject*) const override final { return LayoutRect(); } - virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const override final; + LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject*) const final { return LayoutRect(); } + void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const final; - virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction) override final; + bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction) final; }; -} -#endif // ENABLE(SVG) -#endif // RenderSVGHiddenContainer_h +} // namespace WebCore diff --git a/Source/WebCore/rendering/svg/RenderSVGImage.cpp b/Source/WebCore/rendering/svg/RenderSVGImage.cpp index 58dc14597..cd2386d7a 100644 --- a/Source/WebCore/rendering/svg/RenderSVGImage.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGImage.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2006 Alexander Kellett <lypanov@kde.org> - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006 Apple Inc. * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> * Copyright (C) 2007, 2008, 2009 Rob Buis <buis@kde.org> * Copyright (C) 2009 Google, Inc. @@ -24,20 +24,17 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGImage.h" -#include "Attr.h" #include "FloatQuad.h" #include "GraphicsContext.h" #include "LayoutRepainter.h" #include "PointerEventsHitRules.h" #include "RenderImageResource.h" #include "RenderLayer.h" +#include "RenderSVGResource.h" #include "RenderSVGResourceFilter.h" #include "SVGImageElement.h" -#include "SVGLength.h" #include "SVGRenderingContext.h" #include "SVGResources.h" #include "SVGResourcesCache.h" @@ -45,8 +42,8 @@ namespace WebCore { -RenderSVGImage::RenderSVGImage(SVGImageElement& element, PassRef<RenderStyle> style) - : RenderSVGModelObject(element, std::move(style)) +RenderSVGImage::RenderSVGImage(SVGImageElement& element, RenderStyle&& style) + : RenderSVGModelObject(element, WTFMove(style)) , m_needsBoundariesUpdate(true) , m_needsTransformUpdate(true) , m_imageResource(std::make_unique<RenderImageResource>()) @@ -56,27 +53,48 @@ RenderSVGImage::RenderSVGImage(SVGImageElement& element, PassRef<RenderStyle> st RenderSVGImage::~RenderSVGImage() { +} + +void RenderSVGImage::willBeDestroyed() +{ imageResource().shutdown(); + RenderSVGModelObject::willBeDestroyed(); } SVGImageElement& RenderSVGImage::imageElement() const { - return toSVGImageElement(RenderSVGModelObject::element()); + return downcast<SVGImageElement>(RenderSVGModelObject::element()); } bool RenderSVGImage::updateImageViewport() { FloatRect oldBoundaries = m_objectBoundingBox; + bool updatedViewport = false; SVGLengthContext lengthContext(&imageElement()); m_objectBoundingBox = FloatRect(imageElement().x().value(lengthContext), imageElement().y().value(lengthContext), imageElement().width().value(lengthContext), imageElement().height().value(lengthContext)); - if (oldBoundaries == m_objectBoundingBox) - return false; + // Images with preserveAspectRatio=none should force non-uniform scaling. This can be achieved + // by setting the image's container size to its intrinsic size. + // See: http://www.w3.org/TR/SVG/single-page.html, 7.8 The ‘preserveAspectRatio’ attribute. + if (imageElement().preserveAspectRatio().align() == SVGPreserveAspectRatioValue::SVG_PRESERVEASPECTRATIO_NONE) { + if (CachedImage* cachedImage = imageResource().cachedImage()) { + LayoutSize intrinsicSize = cachedImage->imageSizeForRenderer(0, style().effectiveZoom()); + if (intrinsicSize != imageResource().imageSize(style().effectiveZoom())) { + imageResource().setContainerSizeForRenderer(roundedIntSize(intrinsicSize)); + updatedViewport = true; + } + } + } - imageResource().setContainerSizeForRenderer(enclosingIntRect(m_objectBoundingBox).size()); - m_needsBoundariesUpdate = true; - return true; + if (oldBoundaries != m_objectBoundingBox) { + if (!updatedViewport) + imageResource().setContainerSizeForRenderer(enclosingIntRect(m_objectBoundingBox).size()); + updatedViewport = true; + m_needsBoundariesUpdate = true; + } + + return updatedViewport; } void RenderSVGImage::layout() @@ -117,7 +135,8 @@ void RenderSVGImage::layout() void RenderSVGImage::paint(PaintInfo& paintInfo, const LayoutPoint&) { - if (paintInfo.context->paintingDisabled() || style().visibility() == HIDDEN || !imageResource().hasImage()) + if (paintInfo.context().paintingDisabled() || paintInfo.phase != PaintPhaseForeground + || style().visibility() == HIDDEN || !imageResource().hasImage()) return; FloatRect boundingBox = repaintRectInLocalCoordinates(); @@ -125,36 +144,36 @@ void RenderSVGImage::paint(PaintInfo& paintInfo, const LayoutPoint&) return; PaintInfo childPaintInfo(paintInfo); - bool drawsOutline = style().outlineWidth() && (childPaintInfo.phase == PaintPhaseOutline || childPaintInfo.phase == PaintPhaseSelfOutline); - if (drawsOutline || childPaintInfo.phase == PaintPhaseForeground) { - GraphicsContextStateSaver stateSaver(*childPaintInfo.context); - childPaintInfo.applyTransform(m_localTransform); + GraphicsContextStateSaver stateSaver(childPaintInfo.context()); + childPaintInfo.applyTransform(m_localTransform); - if (childPaintInfo.phase == PaintPhaseForeground) { - SVGRenderingContext renderingContext(*this, childPaintInfo); + if (childPaintInfo.phase == PaintPhaseForeground) { + SVGRenderingContext renderingContext(*this, childPaintInfo); - if (renderingContext.isRenderingPrepared()) { - if (style().svgStyle().bufferedRendering() == BR_STATIC && renderingContext.bufferForeground(m_bufferedForeground)) - return; + if (renderingContext.isRenderingPrepared()) { + if (style().svgStyle().bufferedRendering() == BR_STATIC && renderingContext.bufferForeground(m_bufferedForeground)) + return; - paintForeground(childPaintInfo); - } + paintForeground(childPaintInfo); } - - if (drawsOutline) - paintOutline(childPaintInfo, IntRect(boundingBox)); } + + if (style().outlineWidth()) + paintOutline(childPaintInfo, IntRect(boundingBox)); } void RenderSVGImage::paintForeground(PaintInfo& paintInfo) { RefPtr<Image> image = imageResource().image(); + if (!image) + return; + FloatRect destRect = m_objectBoundingBox; FloatRect srcRect(0, 0, image->width(), image->height()); imageElement().preserveAspectRatio().transformRect(destRect, srcRect); - paintInfo.context->drawImage(image.get(), ColorSpaceDeviceRGB, destRect, srcRect); + paintInfo.context().drawImage(*image, destRect, srcRect); } void RenderSVGImage::invalidateBufferedForeground() @@ -171,14 +190,14 @@ bool RenderSVGImage::nodeAtFloatPoint(const HitTestRequest& request, HitTestResu PointerEventsHitRules hitRules(PointerEventsHitRules::SVG_IMAGE_HITTESTING, request, style().pointerEvents()); bool isVisible = (style().visibility() == VISIBLE); if (isVisible || !hitRules.requireVisible) { - FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent); + FloatPoint localPoint = localToParentTransform().inverse().value_or(AffineTransform()).mapPoint(pointInParent); if (!SVGRenderSupport::pointInClippingArea(*this, localPoint)) return false; if (hitRules.canHitFill) { if (m_objectBoundingBox.contains(localPoint)) { - updateHitTestResult(result, roundedLayoutPoint(localPoint)); + updateHitTestResult(result, LayoutPoint(localPoint)); return true; } } @@ -191,7 +210,7 @@ void RenderSVGImage::imageChanged(WrappedImagePtr, const IntRect*) { // The image resource defaults to nullImage until the resource arrives. // This empty image may be cached by SVG resources which must be invalidated. - if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(*this)) + if (auto* resources = SVGResourcesCache::cachedResourcesForRenderer(*this)) resources->removeClientFromCache(*this); // Eventually notify parent resources, that we've changed. @@ -207,14 +226,12 @@ void RenderSVGImage::imageChanged(WrappedImagePtr, const IntRect*) repaint(); } -void RenderSVGImage::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint&, const RenderLayerModelObject*) +void RenderSVGImage::addFocusRingRects(Vector<LayoutRect>& rects, const LayoutPoint&, const RenderLayerModelObject*) { // this is called from paint() after the localTransform has already been applied - IntRect contentRect = enclosingIntRect(repaintRectInLocalCoordinates()); + LayoutRect contentRect = LayoutRect(repaintRectInLocalCoordinates()); if (!contentRect.isEmpty()) rects.append(contentRect); } } // namespace WebCore - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGImage.h b/Source/WebCore/rendering/svg/RenderSVGImage.h index bb101cdaa..0b688f379 100644 --- a/Source/WebCore/rendering/svg/RenderSVGImage.h +++ b/Source/WebCore/rendering/svg/RenderSVGImage.h @@ -21,14 +21,11 @@ * Boston, MA 02110-1301, USA. */ -#ifndef RenderSVGImage_h -#define RenderSVGImage_h +#pragma once -#if ENABLE(SVG) #include "AffineTransform.h" #include "FloatRect.h" #include "RenderSVGModelObject.h" -#include "SVGPreserveAspectRatio.h" namespace WebCore { @@ -37,15 +34,15 @@ class SVGImageElement; class RenderSVGImage final : public RenderSVGModelObject { public: - RenderSVGImage(SVGImageElement&, PassRef<RenderStyle>); + RenderSVGImage(SVGImageElement&, RenderStyle&&); virtual ~RenderSVGImage(); SVGImageElement& imageElement() const; bool updateImageViewport(); - virtual void setNeedsBoundariesUpdate() { m_needsBoundariesUpdate = true; } - virtual bool needsBoundariesUpdate() override { return m_needsBoundariesUpdate; } - virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; } + void setNeedsBoundariesUpdate() override { m_needsBoundariesUpdate = true; } + bool needsBoundariesUpdate() override { return m_needsBoundariesUpdate; } + void setNeedsTransformUpdate() override { m_needsTransformUpdate = true; } RenderImageResource& imageResource() { return *m_imageResource; } const RenderImageResource& imageResource() const { return *m_imageResource; } @@ -54,31 +51,33 @@ public: void paintForeground(PaintInfo&); private: + void willBeDestroyed() override; + void element() const = delete; - virtual const char* renderName() const { return "RenderSVGImage"; } - virtual bool isSVGImage() const override { return true; } - virtual bool canHaveChildren() const override { return false; } + const char* renderName() const override { return "RenderSVGImage"; } + bool isSVGImage() const override { return true; } + bool canHaveChildren() const override { return false; } - virtual const AffineTransform& localToParentTransform() const { return m_localTransform; } + const AffineTransform& localToParentTransform() const override { return m_localTransform; } - virtual FloatRect objectBoundingBox() const { return m_objectBoundingBox; } - virtual FloatRect strokeBoundingBox() const { return m_objectBoundingBox; } - virtual FloatRect repaintRectInLocalCoordinates() const { return m_repaintBoundingBox; } - virtual FloatRect repaintRectInLocalCoordinatesExcludingSVGShadow() const override { return m_repaintBoundingBoxExcludingShadow; } + FloatRect objectBoundingBox() const override { return m_objectBoundingBox; } + FloatRect strokeBoundingBox() const override { return m_objectBoundingBox; } + FloatRect repaintRectInLocalCoordinates() const override { return m_repaintBoundingBox; } + FloatRect repaintRectInLocalCoordinatesExcludingSVGShadow() const override { return m_repaintBoundingBoxExcludingShadow; } - virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer = 0) override; + void addFocusRingRects(Vector<LayoutRect>&, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer = 0) override; - virtual void imageChanged(WrappedImagePtr, const IntRect* = 0); + void imageChanged(WrappedImagePtr, const IntRect* = nullptr) override; - virtual void layout(); - virtual void paint(PaintInfo&, const LayoutPoint&); + void layout() override; + void paint(PaintInfo&, const LayoutPoint&) override; void invalidateBufferedForeground(); - virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); + bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction) override; - virtual AffineTransform localTransform() const { return m_localTransform; } + AffineTransform localTransform() const override { return m_localTransform; } void calculateImageViewport(); bool m_needsBoundariesUpdate : 1; @@ -91,9 +90,6 @@ private: std::unique_ptr<ImageBuffer> m_bufferedForeground; }; -RENDER_OBJECT_TYPE_CASTS(RenderSVGImage, isSVGImage()) - } // namespace WebCore -#endif // ENABLE(SVG) -#endif // RenderSVGImage_h +SPECIALIZE_TYPE_TRAITS_RENDER_OBJECT(RenderSVGImage, isSVGImage()) diff --git a/Source/WebCore/rendering/svg/RenderSVGInline.cpp b/Source/WebCore/rendering/svg/RenderSVGInline.cpp index f1f384e93..71489ad76 100644 --- a/Source/WebCore/rendering/svg/RenderSVGInline.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGInline.cpp @@ -20,8 +20,6 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGInline.h" #include "RenderSVGInlineText.h" @@ -32,8 +30,8 @@ namespace WebCore { -RenderSVGInline::RenderSVGInline(SVGGraphicsElement& element, PassRef<RenderStyle> style) - : RenderInline(element, std::move(style)) +RenderSVGInline::RenderSVGInline(SVGGraphicsElement& element, RenderStyle&& style) + : RenderInline(element, WTFMove(style)) { setAlwaysCreateLineBoxes(); } @@ -42,29 +40,29 @@ std::unique_ptr<InlineFlowBox> RenderSVGInline::createInlineFlowBox() { auto box = std::make_unique<SVGInlineFlowBox>(*this); box->setHasVirtualLogicalHeight(); - return std::move(box); + return WTFMove(box); } FloatRect RenderSVGInline::objectBoundingBox() const { - if (const RenderObject* object = RenderSVGText::locateRenderSVGTextAncestor(this)) - return object->objectBoundingBox(); + if (auto* textAncestor = RenderSVGText::locateRenderSVGTextAncestor(*this)) + return textAncestor->objectBoundingBox(); return FloatRect(); } FloatRect RenderSVGInline::strokeBoundingBox() const { - if (const RenderObject* object = RenderSVGText::locateRenderSVGTextAncestor(this)) - return object->strokeBoundingBox(); + if (auto* textAncestor = RenderSVGText::locateRenderSVGTextAncestor(*this)) + return textAncestor->strokeBoundingBox(); return FloatRect(); } FloatRect RenderSVGInline::repaintRectInLocalCoordinates() const { - if (const RenderObject* object = RenderSVGText::locateRenderSVGTextAncestor(this)) - return object->repaintRectInLocalCoordinates(); + if (auto* textAncestor = RenderSVGText::locateRenderSVGTextAncestor(*this)) + return textAncestor->repaintRectInLocalCoordinates(); return FloatRect(); } @@ -74,9 +72,9 @@ LayoutRect RenderSVGInline::clippedOverflowRectForRepaint(const RenderLayerModel return SVGRenderSupport::clippedOverflowRectForRepaint(*this, repaintContainer); } -void RenderSVGInline::computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) const +FloatRect RenderSVGInline::computeFloatRectForRepaint(const FloatRect& repaintRect, const RenderLayerModelObject* repaintContainer, bool fixed) const { - SVGRenderSupport::computeFloatRectForRepaint(*this, repaintContainer, repaintRect, fixed); + return SVGRenderSupport::computeFloatRectForRepaint(*this, repaintRect, repaintContainer, fixed); } void RenderSVGInline::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags, bool* wasFixed) const @@ -91,13 +89,13 @@ const RenderObject* RenderSVGInline::pushMappingToContainer(const RenderLayerMod void RenderSVGInline::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const { - const RenderObject* object = RenderSVGText::locateRenderSVGTextAncestor(this); - if (!object) + auto* textAncestor = RenderSVGText::locateRenderSVGTextAncestor(*this); + if (!textAncestor) return; - FloatRect textBoundingBox = object->strokeBoundingBox(); + FloatRect textBoundingBox = textAncestor->strokeBoundingBox(); for (InlineFlowBox* box = firstLineBox(); box; box = box->nextLineBox()) - quads.append(localToAbsoluteQuad(FloatRect(textBoundingBox.x() + box->x(), textBoundingBox.y() + box->y(), box->logicalWidth(), box->logicalHeight()), false, wasFixed)); + quads.append(localToAbsoluteQuad(FloatRect(textBoundingBox.x() + box->x(), textBoundingBox.y() + box->y(), box->logicalWidth(), box->logicalHeight()), UseTransforms, wasFixed)); } void RenderSVGInline::willBeDestroyed() @@ -114,30 +112,37 @@ void RenderSVGInline::styleDidChange(StyleDifference diff, const RenderStyle* ol SVGResourcesCache::clientStyleChanged(*this, diff, style()); } +void RenderSVGInline::updateFromStyle() +{ + RenderInline::updateFromStyle(); + + // SVG text layout code expects us to be an inline-level element. + setInline(true); +} + void RenderSVGInline::addChild(RenderObject* child, RenderObject* beforeChild) { RenderInline::addChild(child, beforeChild); SVGResourcesCache::clientWasAddedToTree(*child); - if (RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(this)) - textRenderer->subtreeChildWasAdded(child); + if (auto* textAncestor = RenderSVGText::locateRenderSVGTextAncestor(*this)) + textAncestor->subtreeChildWasAdded(child); } void RenderSVGInline::removeChild(RenderObject& child) { SVGResourcesCache::clientWillBeRemovedFromTree(child); - RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(this); - if (!textRenderer) { + auto* textAncestor = RenderSVGText::locateRenderSVGTextAncestor(*this); + if (!textAncestor) { RenderInline::removeChild(child); return; } + Vector<SVGTextLayoutAttributes*, 2> affectedAttributes; - textRenderer->subtreeChildWillBeRemoved(&child, affectedAttributes); + textAncestor->subtreeChildWillBeRemoved(&child, affectedAttributes); RenderInline::removeChild(child); - textRenderer->subtreeChildWasRemoved(affectedAttributes); + textAncestor->subtreeChildWasRemoved(affectedAttributes); } } - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGInline.h b/Source/WebCore/rendering/svg/RenderSVGInline.h index f6dee80e9..07dd95043 100644 --- a/Source/WebCore/rendering/svg/RenderSVGInline.h +++ b/Source/WebCore/rendering/svg/RenderSVGInline.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz> - * Copyright (C) 2006 Apple Computer Inc. + * Copyright (C) 2006 Apple Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -18,10 +18,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef RenderSVGInline_h -#define RenderSVGInline_h +#pragma once -#if ENABLE(SVG) #include "RenderInline.h" #include "SVGGraphicsElement.h" @@ -29,42 +27,43 @@ namespace WebCore { class RenderSVGInline : public RenderInline { public: - RenderSVGInline(SVGGraphicsElement&, PassRef<RenderStyle>); + RenderSVGInline(SVGGraphicsElement&, RenderStyle&&); - SVGGraphicsElement& graphicsElement() const { return toSVGGraphicsElement(nodeForNonAnonymous()); } + SVGGraphicsElement& graphicsElement() const { return downcast<SVGGraphicsElement>(nodeForNonAnonymous()); } private: void element() const = delete; - virtual const char* renderName() const override { return "RenderSVGInline"; } - virtual bool requiresLayer() const override final { return false; } - virtual bool isSVGInline() const override final { return true; } + const char* renderName() const override { return "RenderSVGInline"; } + bool requiresLayer() const final { return false; } + bool isSVGInline() const final { return true; } + + void updateFromStyle() final; // Chapter 10.4 of the SVG Specification say that we should use the // object bounding box of the parent text element. // We search for the root text element and take its bounding box. // It is also necessary to take the stroke and repaint rect of // this element, since we need it for filters. - virtual FloatRect objectBoundingBox() const override final; - virtual FloatRect strokeBoundingBox() const override final; - virtual FloatRect repaintRectInLocalCoordinates() const override final; + FloatRect objectBoundingBox() const final; + FloatRect strokeBoundingBox() const final; + FloatRect repaintRectInLocalCoordinates() const final; - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const override final; - virtual void computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect&, bool fixed = false) const override final; - virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const override final; - virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const override final; - virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const override final; + LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const final; + FloatRect computeFloatRectForRepaint(const FloatRect&, const RenderLayerModelObject* repaintContainer, bool fixed = false) const final; + void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags, bool* wasFixed) const final; + const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const final; + void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const final; - virtual std::unique_ptr<InlineFlowBox> createInlineFlowBox() override final; + std::unique_ptr<InlineFlowBox> createInlineFlowBox() final; - virtual void willBeDestroyed() override final; - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) override final; + void willBeDestroyed() final; + void styleDidChange(StyleDifference, const RenderStyle* oldStyle) final; - virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0) override final; - virtual void removeChild(RenderObject&) override final; + void addChild(RenderObject* child, RenderObject* beforeChild = nullptr) final; + void removeChild(RenderObject&) final; }; -} +} // namespace WebCore -#endif // ENABLE(SVG) -#endif // !RenderSVGTSpan_H +SPECIALIZE_TYPE_TRAITS_RENDER_OBJECT(RenderSVGInline, isSVGInline()) diff --git a/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp b/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp index 0667e8479..5aebea8ab 100644 --- a/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGInlineText.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz> - * Copyright (C) 2006 Apple Computer Inc. + * Copyright (C) 2006 Apple Inc. * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> * Copyright (C) 2008 Rob Buis <buis@kde.org> * Copyright (C) Research In Motion Limited 2010. All rights reserved. @@ -22,8 +22,6 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGInlineText.h" #include "CSSFontSelector.h" @@ -32,7 +30,6 @@ #include "RenderBlock.h" #include "RenderSVGRoot.h" #include "RenderSVGText.h" -#include "Settings.h" #include "SVGInlineTextBox.h" #include "SVGRenderingContext.h" #include "SVGRootInlineBox.h" @@ -79,11 +76,11 @@ String RenderSVGInlineText::originalText() const return textNode().data(); } -void RenderSVGInlineText::setTextInternal(const String& text) +void RenderSVGInlineText::setRenderedText(const String& text) { - RenderText::setTextInternal(text); - if (RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(this)) - textRenderer->subtreeTextDidChange(this); + RenderText::setRenderedText(text); + if (auto* textAncestor = RenderSVGText::locateRenderSVGTextAncestor(*this)) + textAncestor->subtreeTextDidChange(this); } void RenderSVGInlineText::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) @@ -107,35 +104,35 @@ void RenderSVGInlineText::styleDidChange(StyleDifference diff, const RenderStyle return; // The text metrics may be influenced by style changes. - if (RenderSVGText* textRenderer = RenderSVGText::locateRenderSVGTextAncestor(this)) - textRenderer->subtreeStyleDidChange(this); + if (auto* textAncestor = RenderSVGText::locateRenderSVGTextAncestor(*this)) + textAncestor->subtreeStyleDidChange(this); } std::unique_ptr<InlineTextBox> RenderSVGInlineText::createTextBox() { auto box = std::make_unique<SVGInlineTextBox>(*this); box->setHasVirtualLogicalHeight(); - return std::move(box); + return WTFMove(box); } -LayoutRect RenderSVGInlineText::localCaretRect(InlineBox* box, int caretOffset, LayoutUnit*) +LayoutRect RenderSVGInlineText::localCaretRect(InlineBox* box, unsigned caretOffset, LayoutUnit*) { - if (!box || !box->isInlineTextBox()) + if (!is<InlineTextBox>(box)) return LayoutRect(); - InlineTextBox* textBox = toInlineTextBox(box); - if (static_cast<unsigned>(caretOffset) < textBox->start() || static_cast<unsigned>(caretOffset) > textBox->start() + textBox->len()) + auto& textBox = downcast<InlineTextBox>(*box); + if (caretOffset < textBox.start() || caretOffset > textBox.start() + textBox.len()) return LayoutRect(); // Use the edge of the selection rect to determine the caret rect. - if (static_cast<unsigned>(caretOffset) < textBox->start() + textBox->len()) { - LayoutRect rect = textBox->localSelectionRect(caretOffset, caretOffset + 1); - LayoutUnit x = box->isLeftToRightDirection() ? rect.x() : rect.maxX(); + if (caretOffset < textBox.start() + textBox.len()) { + LayoutRect rect = textBox.localSelectionRect(caretOffset, caretOffset + 1); + LayoutUnit x = textBox.isLeftToRightDirection() ? rect.x() : rect.maxX(); return LayoutRect(x, rect.y(), caretWidth, rect.height()); } - LayoutRect rect = textBox->localSelectionRect(caretOffset - 1, caretOffset); - LayoutUnit x = box->isLeftToRightDirection() ? rect.maxX() : rect.x(); + LayoutRect rect = textBox.localSelectionRect(caretOffset - 1, caretOffset); + LayoutUnit x = textBox.isLeftToRightDirection() ? rect.maxX() : rect.x(); return LayoutRect(x, rect.y(), caretWidth, rect.height()); } @@ -168,7 +165,7 @@ bool RenderSVGInlineText::characterStartsNewTextChunk(int position) const return it->value.x != SVGTextLayoutAttributes::emptyValue() || it->value.y != SVGTextLayoutAttributes::emptyValue(); } -VisiblePosition RenderSVGInlineText::positionForPoint(const LayoutPoint& point) +VisiblePosition RenderSVGInlineText::positionForPoint(const LayoutPoint& point, const RenderRegion*) { if (!firstTextBox() || !textLength()) return createVisiblePosition(0, DOWNSTREAM); @@ -184,16 +181,16 @@ VisiblePosition RenderSVGInlineText::positionForPoint(const LayoutPoint& point) float closestDistance = std::numeric_limits<float>::max(); float closestDistancePosition = 0; - const SVGTextFragment* closestDistanceFragment = 0; - SVGInlineTextBox* closestDistanceBox = 0; + const SVGTextFragment* closestDistanceFragment = nullptr; + SVGInlineTextBox* closestDistanceBox = nullptr; AffineTransform fragmentTransform; for (InlineTextBox* box = firstTextBox(); box; box = box->nextTextBox()) { - if (!box->isSVGInlineTextBox()) + if (!is<SVGInlineTextBox>(*box)) continue; - SVGInlineTextBox* textBox = toSVGInlineTextBox(box); - Vector<SVGTextFragment>& fragments = textBox->textFragments(); + auto& textBox = downcast<SVGInlineTextBox>(*box); + Vector<SVGTextFragment>& fragments = textBox.textFragments(); unsigned textFragmentsSize = fragments.size(); for (unsigned i = 0; i < textFragmentsSize; ++i) { @@ -208,7 +205,7 @@ VisiblePosition RenderSVGInlineText::positionForPoint(const LayoutPoint& point) if (distance < closestDistance) { closestDistance = distance; - closestDistanceBox = textBox; + closestDistanceBox = &textBox; closestDistanceFragment = &fragment; closestDistancePosition = fragmentRect.x(); } @@ -224,31 +221,31 @@ VisiblePosition RenderSVGInlineText::positionForPoint(const LayoutPoint& point) void RenderSVGInlineText::updateScaledFont() { - computeNewScaledFontForStyle(this, &style(), m_scalingFactor, m_scaledFont); + computeNewScaledFontForStyle(*this, style(), m_scalingFactor, m_scaledFont); } -void RenderSVGInlineText::computeNewScaledFontForStyle(RenderObject* renderer, const RenderStyle* style, float& scalingFactor, Font& scaledFont) +void RenderSVGInlineText::computeNewScaledFontForStyle(const RenderObject& renderer, const RenderStyle& style, float& scalingFactor, FontCascade& scaledFont) { - ASSERT(style); - ASSERT(renderer); - // Alter font-size to the right on-screen value to avoid scaling the glyphs themselves, except when GeometricPrecision is specified scalingFactor = SVGRenderingContext::calculateScreenFontSizeScalingFactor(renderer); - if (scalingFactor == 1 || !scalingFactor || style->fontDescription().textRenderingMode() == GeometricPrecision) { + if (!scalingFactor || style.fontDescription().textRenderingMode() == GeometricPrecision) { scalingFactor = 1; - scaledFont = style->font(); + scaledFont = style.fontCascade(); return; } - FontDescription fontDescription(style->fontDescription()); + auto fontDescription = style.fontDescription(); // FIXME: We need to better handle the case when we compute very small fonts below (below 1pt). - fontDescription.setComputedSize(Style::computedFontSizeFromSpecifiedSizeForSVGInlineText(fontDescription.computedSize(), fontDescription.isAbsoluteSize(), scalingFactor, renderer->document())); + fontDescription.setComputedSize(Style::computedFontSizeFromSpecifiedSizeForSVGInlineText(fontDescription.computedSize(), fontDescription.isAbsoluteSize(), scalingFactor, renderer.document())); - scaledFont = Font(fontDescription, 0, 0); - scaledFont.update(renderer->document().ensureStyleResolver().fontSelector()); -} + // SVG controls its own glyph orientation, so don't allow writing-mode + // to affect it. + if (fontDescription.orientation() != FontOrientation::Horizontal) + fontDescription.setOrientation(FontOrientation::Horizontal); + scaledFont = FontCascade(fontDescription, 0, 0); + scaledFont.update(&renderer.document().fontSelector()); } -#endif // ENABLE(SVG) +} diff --git a/Source/WebCore/rendering/svg/RenderSVGInlineText.h b/Source/WebCore/rendering/svg/RenderSVGInlineText.h index c07228e21..1973d589e 100644 --- a/Source/WebCore/rendering/svg/RenderSVGInlineText.h +++ b/Source/WebCore/rendering/svg/RenderSVGInlineText.h @@ -19,11 +19,9 @@ * Boston, MA 02110-1301, USA. */ -#ifndef RenderSVGInlineText_h -#define RenderSVGInlineText_h +#pragma once -#if ENABLE(SVG) -#include "Font.h" +#include "FontCascade.h" #include "RenderText.h" #include "SVGTextLayoutAttributes.h" #include "Text.h" @@ -36,43 +34,40 @@ class RenderSVGInlineText final : public RenderText { public: RenderSVGInlineText(Text&, const String&); - Text& textNode() const { return toText(nodeForNonAnonymous()); } + Text& textNode() const { return downcast<Text>(nodeForNonAnonymous()); } bool characterStartsNewTextChunk(int position) const; SVGTextLayoutAttributes* layoutAttributes() { return &m_layoutAttributes; } float scalingFactor() const { return m_scalingFactor; } - const Font& scaledFont() const { return m_scaledFont; } + const FontCascade& scaledFont() const { return m_scaledFont; } void updateScaledFont(); - static void computeNewScaledFontForStyle(RenderObject*, const RenderStyle*, float& scalingFactor, Font& scaledFont); + static void computeNewScaledFontForStyle(const RenderObject&, const RenderStyle&, float& scalingFactor, FontCascade& scaledFont); // Preserves floating point precision for the use in DRT. It knows how to round and does a better job than enclosingIntRect. FloatRect floatLinesBoundingBox() const; private: - virtual const char* renderName() const override { return "RenderSVGInlineText"; } + const char* renderName() const override { return "RenderSVGInlineText"; } - virtual String originalText() const override; - virtual void setTextInternal(const String&) override; - virtual void styleDidChange(StyleDifference, const RenderStyle*) override; + String originalText() const override; + void setRenderedText(const String&) override; + void styleDidChange(StyleDifference, const RenderStyle*) override; - virtual FloatRect objectBoundingBox() const override { return floatLinesBoundingBox(); } + FloatRect objectBoundingBox() const override { return floatLinesBoundingBox(); } - virtual bool isSVGInlineText() const override { return true; } + bool isSVGInlineText() const override { return true; } - virtual VisiblePosition positionForPoint(const LayoutPoint&) override; - virtual LayoutRect localCaretRect(InlineBox*, int caretOffset, LayoutUnit* extraWidthToEndOfLine = 0) override; - virtual IntRect linesBoundingBox() const override; - virtual std::unique_ptr<InlineTextBox> createTextBox() override; + VisiblePosition positionForPoint(const LayoutPoint&, const RenderRegion*) override; + LayoutRect localCaretRect(InlineBox*, unsigned caretOffset, LayoutUnit* extraWidthToEndOfLine = 0) override; + IntRect linesBoundingBox() const override; + std::unique_ptr<InlineTextBox> createTextBox() override; float m_scalingFactor; - Font m_scaledFont; + FontCascade m_scaledFont; SVGTextLayoutAttributes m_layoutAttributes; }; -RENDER_OBJECT_TYPE_CASTS(RenderSVGInlineText, isSVGInlineText()) +} // namespace WebCore -} - -#endif // ENABLE(SVG) -#endif // RenderSVGInlineText_h +SPECIALIZE_TYPE_TRAITS_RENDER_OBJECT(RenderSVGInlineText, isSVGInlineText()) diff --git a/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp b/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp index 78768eafe..e64cafa4d 100644 --- a/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGModelObject.cpp @@ -29,8 +29,6 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGModelObject.h" #include "RenderLayerModelObject.h" @@ -41,8 +39,8 @@ namespace WebCore { -RenderSVGModelObject::RenderSVGModelObject(SVGElement& element, PassRef<RenderStyle> style) - : RenderElement(element, std::move(style), 0) +RenderSVGModelObject::RenderSVGModelObject(SVGElement& element, RenderStyle&& style) + : RenderElement(element, WTFMove(style), 0) , m_hasSVGShadow(false) { } @@ -52,9 +50,9 @@ LayoutRect RenderSVGModelObject::clippedOverflowRectForRepaint(const RenderLayer return SVGRenderSupport::clippedOverflowRectForRepaint(*this, repaintContainer); } -void RenderSVGModelObject::computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) const +FloatRect RenderSVGModelObject::computeFloatRectForRepaint(const FloatRect& repaintRect, const RenderLayerModelObject* repaintContainer, bool fixed) const { - SVGRenderSupport::computeFloatRectForRepaint(*this, repaintContainer, repaintRect, fixed); + return SVGRenderSupport::computeFloatRectForRepaint(*this, repaintRect, repaintContainer, fixed); } void RenderSVGModelObject::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags, bool* wasFixed) const @@ -76,7 +74,7 @@ LayoutRect RenderSVGModelObject::outlineBoundsForRepaint(const RenderLayerModelO adjustRectForOutlineAndShadow(box); FloatQuad containerRelativeQuad = localToContainerQuad(FloatRect(box), repaintContainer); - return containerRelativeQuad.enclosingBoundingBox(); + return LayoutRect(snapRectToDevicePixels(LayoutRect(containerRelativeQuad.boundingBox()), document().deviceScaleFactor())); } void RenderSVGModelObject::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const @@ -88,7 +86,7 @@ void RenderSVGModelObject::absoluteRects(Vector<IntRect>& rects, const LayoutPoi void RenderSVGModelObject::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const { - quads.append(localToAbsoluteQuad(strokeBoundingBox(), 0 /* mode */, wasFixed)); + quads.append(localToAbsoluteQuad(strokeBoundingBox(), UseTransforms, wasFixed)); } void RenderSVGModelObject::willBeDestroyed() @@ -126,11 +124,11 @@ static void getElementCTM(SVGElement* element, AffineTransform& transform) Node* current = element; while (current && current->isSVGElement()) { - SVGElement* currentElement = toSVGElement(current); - localTransform = currentElement->renderer()->localToParentTransform(); + SVGElement& currentElement = downcast<SVGElement>(*current); + localTransform = currentElement.renderer()->localToParentTransform(); transform = localTransform.multiply(transform); // For getCTM() computation, stop at the nearest viewport element - if (currentElement == stopAtElement) + if (¤tElement == stopAtElement) break; current = current->parentOrShadowHostNode(); @@ -173,7 +171,7 @@ bool RenderSVGModelObject::checkIntersection(RenderElement* renderer, const Floa if (!isGraphicsElement(*renderer)) return false; AffineTransform ctm; - SVGElement* svgElement = toSVGElement(renderer->element()); + SVGElement* svgElement = downcast<SVGElement>(renderer->element()); getElementCTM(svgElement, ctm); ASSERT(svgElement->renderer()); return intersectsAllowingEmpty(rect, ctm.mapRect(svgElement->renderer()->repaintRectInLocalCoordinates())); @@ -186,12 +184,10 @@ bool RenderSVGModelObject::checkEnclosure(RenderElement* renderer, const FloatRe if (!isGraphicsElement(*renderer)) return false; AffineTransform ctm; - SVGElement* svgElement = toSVGElement(renderer->element()); + SVGElement* svgElement = downcast<SVGElement>(renderer->element()); getElementCTM(svgElement, ctm); ASSERT(svgElement->renderer()); return rect.contains(ctm.mapRect(svgElement->renderer()->repaintRectInLocalCoordinates())); } } // namespace WebCore - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGModelObject.h b/Source/WebCore/rendering/svg/RenderSVGModelObject.h index a7cd417aa..d396becff 100644 --- a/Source/WebCore/rendering/svg/RenderSVGModelObject.h +++ b/Source/WebCore/rendering/svg/RenderSVGModelObject.h @@ -28,10 +28,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef RenderSVGModelObject_h -#define RenderSVGModelObject_h - -#if ENABLE(SVG) +#pragma once #include "RenderElement.h" #include "SVGElement.h" @@ -48,16 +45,16 @@ class SVGElement; class RenderSVGModelObject : public RenderElement { public: - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const override; - virtual void computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect&, bool fixed = false) const override final; - virtual LayoutRect outlineBoundsForRepaint(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap*) const override final; + LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const override; + FloatRect computeFloatRectForRepaint(const FloatRect&, const RenderLayerModelObject* repaintContainer, bool fixed = false) const final; + LayoutRect outlineBoundsForRepaint(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap*) const final; - virtual void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const override final; - virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const override; + void absoluteRects(Vector<IntRect>&, const LayoutPoint& accumulatedOffset) const final; + void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const override; - virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const override final; - virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const override final; - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) override; + void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags, bool* wasFixed) const final; + const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const final; + void styleDidChange(StyleDifference, const RenderStyle* oldStyle) override; static bool checkIntersection(RenderElement*, const FloatRect&); static bool checkEnclosure(RenderElement*, const FloatRect&); @@ -66,25 +63,22 @@ public: bool hasSVGShadow() const { return m_hasSVGShadow; } void setHasSVGShadow(bool hasShadow) { m_hasSVGShadow = hasShadow; } - SVGElement& element() const { return toSVGElement(nodeForNonAnonymous()); } + SVGElement& element() const { return downcast<SVGElement>(nodeForNonAnonymous()); } protected: - RenderSVGModelObject(SVGElement&, PassRef<RenderStyle>); + RenderSVGModelObject(SVGElement&, RenderStyle&&); - virtual void willBeDestroyed() override; + void willBeDestroyed() override; private: - virtual bool isRenderSVGModelObject() const override final { return true; } + bool isRenderSVGModelObject() const final { return true; } // This method should never be called, SVG uses a different nodeAtPoint method - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) override; - virtual void absoluteFocusRingQuads(Vector<FloatQuad>&) override final; + bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) override; + void absoluteFocusRingQuads(Vector<FloatQuad>&) final; bool m_hasSVGShadow; }; -RENDER_OBJECT_TYPE_CASTS(RenderSVGModelObject, isRenderSVGModelObject()); - -} +} // namespace WebCore -#endif // ENABLE(SVG) -#endif +SPECIALIZE_TYPE_TRAITS_RENDER_OBJECT(RenderSVGModelObject, isRenderSVGModelObject()) diff --git a/Source/WebCore/rendering/svg/RenderSVGPath.cpp b/Source/WebCore/rendering/svg/RenderSVGPath.cpp index 353dd238c..208f11f8c 100644 --- a/Source/WebCore/rendering/svg/RenderSVGPath.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGPath.cpp @@ -26,8 +26,6 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGPath.h" #include "SVGPathElement.h" @@ -35,8 +33,8 @@ namespace WebCore { -RenderSVGPath::RenderSVGPath(SVGGraphicsElement& element, PassRef<RenderStyle> style) - : RenderSVGShape(element, std::move(style)) +RenderSVGPath::RenderSVGPath(SVGGraphicsElement& element, RenderStyle&& style) + : RenderSVGShape(element, WTFMove(style)) { } @@ -66,19 +64,19 @@ FloatRect RenderSVGPath::calculateUpdatedStrokeBoundingBox() const return strokeBoundingBox; } -static void useStrokeStyleToFill(GraphicsContext* context) +static void useStrokeStyleToFill(GraphicsContext& context) { - if (Gradient* gradient = context->strokeGradient()) - context->setFillGradient(gradient); - else if (Pattern* pattern = context->strokePattern()) - context->setFillPattern(pattern); + if (Gradient* gradient = context.strokeGradient()) + context.setFillGradient(*gradient); + else if (Pattern* pattern = context.strokePattern()) + context.setFillPattern(*pattern); else - context->setFillColor(context->strokeColor(), context->strokeColorSpace()); + context.setFillColor(context.strokeColor()); } -void RenderSVGPath::strokeShape(GraphicsContext* context) const +void RenderSVGPath::strokeShape(GraphicsContext& context) const { - if (!style().svgStyle().hasVisibleStroke()) + if (!style().hasVisibleStroke()) return; RenderSVGShape::strokeShape(context); @@ -92,13 +90,13 @@ void RenderSVGPath::strokeShape(GraphicsContext* context) const if (hasNonScalingStroke()) nonScalingTransform = nonScalingStrokeTransform(); - GraphicsContextStateSaver stateSaver(*context, true); + GraphicsContextStateSaver stateSaver(context, true); useStrokeStyleToFill(context); for (size_t i = 0; i < m_zeroLengthLinecapLocations.size(); ++i) { usePath = zeroLengthLinecapPath(m_zeroLengthLinecapLocations[i]); if (hasNonScalingStroke()) usePath = nonScalingStrokePath(usePath, nonScalingTransform); - context->fillPath(*usePath); + context.fillPath(*usePath); } } @@ -107,15 +105,14 @@ bool RenderSVGPath::shapeDependentStrokeContains(const FloatPoint& point) if (RenderSVGShape::shapeDependentStrokeContains(point)) return true; - const SVGRenderStyle& svgStyle = style().svgStyle(); for (size_t i = 0; i < m_zeroLengthLinecapLocations.size(); ++i) { - ASSERT(svgStyle.hasStroke()); + ASSERT(style().svgStyle().hasStroke()); float strokeWidth = this->strokeWidth(); - if (svgStyle.capStyle() == SquareCap) { + if (style().capStyle() == SquareCap) { if (zeroLengthSubpathRect(m_zeroLengthLinecapLocations[i], strokeWidth).contains(point)) return true; } else { - ASSERT(svgStyle.capStyle() == RoundCap); + ASSERT(style().capStyle() == RoundCap); FloatPoint radiusVector(point.x() - m_zeroLengthLinecapLocations[i].x(), point.y() - m_zeroLengthLinecapLocations[i].y()); if (radiusVector.lengthSquared() < strokeWidth * strokeWidth * .25f) return true; @@ -128,20 +125,20 @@ bool RenderSVGPath::shouldStrokeZeroLengthSubpath() const { // Spec(11.4): Any zero length subpath shall not be stroked if the "stroke-linecap" property has a value of butt // but shall be stroked if the "stroke-linecap" property has a value of round or square - return style().svgStyle().hasStroke() && style().svgStyle().capStyle() != ButtCap; + return style().svgStyle().hasStroke() && style().capStyle() != ButtCap; } Path* RenderSVGPath::zeroLengthLinecapPath(const FloatPoint& linecapPosition) const { - DEFINE_STATIC_LOCAL(Path, tempPath, ()); + static NeverDestroyed<Path> tempPath; - tempPath.clear(); - if (style().svgStyle().capStyle() == SquareCap) - tempPath.addRect(zeroLengthSubpathRect(linecapPosition, this->strokeWidth())); + tempPath.get().clear(); + if (style().capStyle() == SquareCap) + tempPath.get().addRect(zeroLengthSubpathRect(linecapPosition, this->strokeWidth())); else - tempPath.addEllipse(zeroLengthSubpathRect(linecapPosition, this->strokeWidth())); + tempPath.get().addEllipse(zeroLengthSubpathRect(linecapPosition, this->strokeWidth())); - return &tempPath; + return &tempPath.get(); } FloatRect RenderSVGPath::zeroLengthSubpathRect(const FloatPoint& linecapPosition, float strokeWidth) const @@ -157,10 +154,17 @@ void RenderSVGPath::updateZeroLengthSubpaths() return; SVGSubpathData subpathData(m_zeroLengthLinecapLocations); - path().apply(&subpathData, SVGSubpathData::updateFromPathElement); + path().apply([&subpathData](const PathElement& pathElement) { + SVGSubpathData::updateFromPathElement(subpathData, pathElement); + }); subpathData.pathIsDone(); } +bool RenderSVGPath::isRenderingDisabled() const +{ + // For a polygon, polyline or path, rendering is disabled if there is no path data. + // No path data is possible in the case of a missing or empty 'd' or 'points' attribute. + return path().isEmpty(); } -#endif // ENABLE(SVG) +} diff --git a/Source/WebCore/rendering/svg/RenderSVGPath.h b/Source/WebCore/rendering/svg/RenderSVGPath.h index 5ffd494f4..6b69e23f9 100644 --- a/Source/WebCore/rendering/svg/RenderSVGPath.h +++ b/Source/WebCore/rendering/svg/RenderSVGPath.h @@ -2,7 +2,7 @@ * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> * Copyright (C) 2005 Eric Seidel <eric@webkit.org> - * Copyright (C) 2006 Apple Computer, Inc + * Copyright (C) 2006 Apple Inc. * Copyright (C) 2009 Google, Inc. * Copyright (C) 2011 Renata Hodovan <reni@webkit.org> * Copyright (C) 2011 University of Szeged @@ -23,40 +23,37 @@ * Boston, MA 02110-1301, USA. */ -#ifndef RenderSVGPath_h -#define RenderSVGPath_h +#pragma once -#if ENABLE(SVG) #include "RenderSVGShape.h" namespace WebCore { class RenderSVGPath final : public RenderSVGShape { public: - RenderSVGPath(SVGGraphicsElement&, PassRef<RenderStyle>); + RenderSVGPath(SVGGraphicsElement&, RenderStyle&&); virtual ~RenderSVGPath(); private: - virtual bool isSVGPath() const override { return true; } - virtual const char* renderName() const { return "RenderSVGPath"; } + bool isSVGPath() const override { return true; } + const char* renderName() const override { return "RenderSVGPath"; } - virtual void updateShapeFromElement() override; + void updateShapeFromElement() override; FloatRect calculateUpdatedStrokeBoundingBox() const; - virtual void strokeShape(GraphicsContext*) const override; - virtual bool shapeDependentStrokeContains(const FloatPoint&) override; + void strokeShape(GraphicsContext&) const override; + bool shapeDependentStrokeContains(const FloatPoint&) override; bool shouldStrokeZeroLengthSubpath() const; Path* zeroLengthLinecapPath(const FloatPoint&) const; FloatRect zeroLengthSubpathRect(const FloatPoint&, float) const; void updateZeroLengthSubpaths(); + bool isRenderingDisabled() const override; + Vector<FloatPoint> m_zeroLengthLinecapLocations; }; -RENDER_OBJECT_TYPE_CASTS(RenderSVGPath, isSVGPath()) - -} +} // namespace WebCore -#endif // ENABLE(SVG) -#endif +SPECIALIZE_TYPE_TRAITS_RENDER_OBJECT(RenderSVGPath, isSVGPath()) diff --git a/Source/WebCore/rendering/svg/RenderSVGRect.cpp b/Source/WebCore/rendering/svg/RenderSVGRect.cpp index bfda62f5f..2ceba5d91 100644 --- a/Source/WebCore/rendering/svg/RenderSVGRect.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGRect.cpp @@ -26,16 +26,12 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGRect.h" -#include "SVGNames.h" - namespace WebCore { -RenderSVGRect::RenderSVGRect(SVGRectElement& element, PassRef<RenderStyle> style) - : RenderSVGShape(element, std::move(style)) +RenderSVGRect::RenderSVGRect(SVGRectElement& element, RenderStyle&& style) + : RenderSVGShape(element, WTFMove(style)) , m_usePathFallback(false) { } @@ -46,7 +42,7 @@ RenderSVGRect::~RenderSVGRect() SVGRectElement& RenderSVGRect::rectElement() const { - return toSVGRectElement(RenderSVGShape::graphicsElement()); + return downcast<SVGRectElement>(RenderSVGShape::graphicsElement()); } void RenderSVGRect::updateShapeFromElement() @@ -58,19 +54,26 @@ void RenderSVGRect::updateShapeFromElement() m_outerStrokeRect = FloatRect(); SVGLengthContext lengthContext(&rectElement()); - // Fallback to RenderSVGShape if rect has rounded corners or a non-scaling stroke. - if (rectElement().rx().value(lengthContext) > 0 || rectElement().ry().value(lengthContext) > 0 || hasNonScalingStroke()) { - RenderSVGShape::updateShapeFromElement(); - m_usePathFallback = true; - return; - } + FloatSize boundingBoxSize(lengthContext.valueForLength(style().width(), LengthModeWidth), lengthContext.valueForLength(style().height(), LengthModeHeight)); - m_usePathFallback = false; - FloatSize boundingBoxSize(rectElement().width().value(lengthContext), rectElement().height().value(lengthContext)); - if (boundingBoxSize.isEmpty()) + // Element is invalid if either dimension is negative. + if (boundingBoxSize.width() < 0 || boundingBoxSize.height() < 0) return; - m_fillBoundingBox = FloatRect(FloatPoint(rectElement().x().value(lengthContext), rectElement().y().value(lengthContext)), boundingBoxSize); + // Rendering enabled? Spec: "A value of zero disables rendering of the element." + if (!boundingBoxSize.isEmpty()) { + if (rectElement().rx().value(lengthContext) > 0 || rectElement().ry().value(lengthContext) > 0 || hasNonScalingStroke()) { + // Fall back to RenderSVGShape + RenderSVGShape::updateShapeFromElement(); + m_usePathFallback = true; + return; + } + m_usePathFallback = false; + } + + m_fillBoundingBox = FloatRect(FloatPoint(lengthContext.valueForLength(style().svgStyle().x(), LengthModeWidth), + lengthContext.valueForLength(style().svgStyle().y(), LengthModeHeight)), + boundingBoxSize); // To decide if the stroke contains a point we create two rects which represent the inner and // the outer stroke borders. A stroke contains the point, if the point is between them. @@ -92,7 +95,7 @@ void RenderSVGRect::updateShapeFromElement() #endif } -void RenderSVGRect::fillShape(GraphicsContext* context) const +void RenderSVGRect::fillShape(GraphicsContext& context) const { if (m_usePathFallback) { RenderSVGShape::fillShape(context); @@ -104,20 +107,20 @@ void RenderSVGRect::fillShape(GraphicsContext* context) const // shadow drawing method, which draws an extra shadow. // This is a workaround for switching off the extra shadow. // https://bugs.webkit.org/show_bug.cgi?id=68899 - if (context->hasShadow()) { - GraphicsContextStateSaver stateSaver(*context); - context->clearShadow(); - context->fillRect(m_fillBoundingBox); + if (context.hasShadow()) { + GraphicsContextStateSaver stateSaver(context); + context.clearShadow(); + context.fillRect(m_fillBoundingBox); return; } #endif - context->fillRect(m_fillBoundingBox); + context.fillRect(m_fillBoundingBox); } -void RenderSVGRect::strokeShape(GraphicsContext* context) const +void RenderSVGRect::strokeShape(GraphicsContext& context) const { - if (!style().svgStyle().hasVisibleStroke()) + if (!style().hasVisibleStroke()) return; if (m_usePathFallback) { @@ -125,7 +128,7 @@ void RenderSVGRect::strokeShape(GraphicsContext* context) const return; } - context->strokeRect(m_fillBoundingBox, strokeWidth()); + context.strokeRect(m_fillBoundingBox, strokeWidth()); } bool RenderSVGRect::shapeDependentStrokeContains(const FloatPoint& point) @@ -148,6 +151,10 @@ bool RenderSVGRect::shapeDependentFillContains(const FloatPoint& point, const Wi return m_fillBoundingBox.contains(point.x(), point.y()); } +bool RenderSVGRect::isRenderingDisabled() const +{ + // A width or height of zero disables rendering for the element, and results in an empty bounding box. + return m_fillBoundingBox.isEmpty(); } -#endif // ENABLE(SVG) +} diff --git a/Source/WebCore/rendering/svg/RenderSVGRect.h b/Source/WebCore/rendering/svg/RenderSVGRect.h index c305726b8..98f7c5c91 100644 --- a/Source/WebCore/rendering/svg/RenderSVGRect.h +++ b/Source/WebCore/rendering/svg/RenderSVGRect.h @@ -25,10 +25,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef RenderSVGRect_h -#define RenderSVGRect_h +#pragma once -#if ENABLE(SVG) #include "RenderSVGPath.h" #include "SVGRectElement.h" @@ -36,7 +34,7 @@ namespace WebCore { class RenderSVGRect final : public RenderSVGShape { public: - RenderSVGRect(SVGRectElement&, PassRef<RenderStyle>); + RenderSVGRect(SVGRectElement&, RenderStyle&&); virtual ~RenderSVGRect(); SVGRectElement& rectElement() const; @@ -44,14 +42,15 @@ public: private: void graphicsElement() const = delete; - virtual const char* renderName() const { return "RenderSVGRect"; } + const char* renderName() const override { return "RenderSVGRect"; } - virtual void updateShapeFromElement(); - virtual bool isEmpty() const { return m_usePathFallback ? RenderSVGShape::isEmpty() : m_fillBoundingBox.isEmpty(); }; - virtual void fillShape(GraphicsContext*) const; - virtual void strokeShape(GraphicsContext*) const; - virtual bool shapeDependentStrokeContains(const FloatPoint&); - virtual bool shapeDependentFillContains(const FloatPoint&, const WindRule) const; + void updateShapeFromElement() override; + bool isEmpty() const override { return m_usePathFallback ? RenderSVGShape::isEmpty() : m_fillBoundingBox.isEmpty(); } + bool isRenderingDisabled() const override; + void fillShape(GraphicsContext&) const override; + void strokeShape(GraphicsContext&) const override; + bool shapeDependentStrokeContains(const FloatPoint&) override; + bool shapeDependentFillContains(const FloatPoint&, const WindRule) const override; private: FloatRect m_innerStrokeRect; @@ -59,7 +58,4 @@ private: bool m_usePathFallback; }; -} - -#endif // ENABLE(SVG) -#endif +} // namespace WebCore diff --git a/Source/WebCore/rendering/svg/RenderSVGResource.cpp b/Source/WebCore/rendering/svg/RenderSVGResource.cpp index d9e1d835e..e6c5c2401 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResource.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResource.cpp @@ -21,8 +21,6 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGResource.h" #include "Frame.h" @@ -72,18 +70,16 @@ static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode m } bool applyToFill = mode == ApplyToFillMode; - SVGPaint::SVGPaintType paintType = applyToFill ? svgStyle.fillPaintType() : svgStyle.strokePaintType(); - if (paintType == SVGPaint::SVG_PAINTTYPE_NONE) + SVGPaintType paintType = applyToFill ? svgStyle.fillPaintType() : svgStyle.strokePaintType(); + if (paintType == SVG_PAINTTYPE_NONE) return nullptr; Color color; switch (paintType) { - case SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR: - case SVGPaint::SVG_PAINTTYPE_RGBCOLOR: - case SVGPaint::SVG_PAINTTYPE_RGBCOLOR_ICCCOLOR: - case SVGPaint::SVG_PAINTTYPE_URI_CURRENTCOLOR: - case SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR: - case SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR_ICCCOLOR: + case SVG_PAINTTYPE_CURRENTCOLOR: + case SVG_PAINTTYPE_RGBCOLOR: + case SVG_PAINTTYPE_URI_CURRENTCOLOR: + case SVG_PAINTTYPE_URI_RGBCOLOR: color = applyToFill ? svgStyle.fillPaintColor() : svgStyle.strokePaintColor(); break; default: @@ -92,19 +88,19 @@ static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode m if (style.insideLink() == InsideVisitedLink) { // FIXME: This code doesn't support the uri component of the visited link paint, https://bugs.webkit.org/show_bug.cgi?id=70006 - SVGPaint::SVGPaintType visitedPaintType = applyToFill ? svgStyle.visitedLinkFillPaintType() : svgStyle.visitedLinkStrokePaintType(); + SVGPaintType visitedPaintType = applyToFill ? svgStyle.visitedLinkFillPaintType() : svgStyle.visitedLinkStrokePaintType(); // For SVG_PAINTTYPE_CURRENTCOLOR, 'color' already contains the 'visitedColor'. - if (visitedPaintType < SVGPaint::SVG_PAINTTYPE_URI_NONE && visitedPaintType != SVGPaint::SVG_PAINTTYPE_CURRENTCOLOR) { + if (visitedPaintType < SVG_PAINTTYPE_URI_NONE && visitedPaintType != SVG_PAINTTYPE_CURRENTCOLOR) { const Color& visitedColor = applyToFill ? svgStyle.visitedLinkFillPaintColor() : svgStyle.visitedLinkStrokePaintColor(); if (visitedColor.isValid()) - color = Color(visitedColor.red(), visitedColor.green(), visitedColor.blue(), color.alpha()); + color = visitedColor.colorWithAlpha(color.alphaAsFloat()); } } // If the primary resource is just a color, return immediately. RenderSVGResourceSolidColor* colorResource = RenderSVGResource::sharedSolidPaintingResource(); - if (paintType < SVGPaint::SVG_PAINTTYPE_URI_NONE) { + if (paintType < SVG_PAINTTYPE_URI_NONE) { if (!inheritColorFromParentStyleIfNeeded(renderer, applyToFill, color)) return nullptr; @@ -113,9 +109,9 @@ static inline RenderSVGResource* requestPaintingResource(RenderSVGResourceMode m } // If no resources are associated with the given renderer, return the color resource. - SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(renderer); + auto* resources = SVGResourcesCache::cachedResourcesForRenderer(renderer); if (!resources) { - if (paintType == SVGPaint::SVG_PAINTTYPE_URI_NONE || !inheritColorFromParentStyleIfNeeded(renderer, applyToFill, color)) + if (paintType == SVG_PAINTTYPE_URI_NONE || !inheritColorFromParentStyleIfNeeded(renderer, applyToFill, color)) return nullptr; colorResource->setColor(color); @@ -156,28 +152,38 @@ RenderSVGResourceSolidColor* RenderSVGResource::sharedSolidPaintingResource() return s_sharedSolidPaintingResource; } -static inline void removeFromCacheAndInvalidateDependencies(RenderObject& object, bool needsLayout) +static inline void removeFromCacheAndInvalidateDependencies(RenderElement& renderer, bool needsLayout) { - if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(object)) { -#if ENABLE(FILTERS) + if (auto* resources = SVGResourcesCache::cachedResourcesForRenderer(renderer)) { if (RenderSVGResourceFilter* filter = resources->filter()) - filter->removeClientFromCache(object); -#endif + filter->removeClientFromCache(renderer); + if (RenderSVGResourceMasker* masker = resources->masker()) - masker->removeClientFromCache(object); + masker->removeClientFromCache(renderer); if (RenderSVGResourceClipper* clipper = resources->clipper()) - clipper->removeClientFromCache(object); + clipper->removeClientFromCache(renderer); } - if (!object.node() || !object.node()->isSVGElement()) + if (!renderer.element() || !renderer.element()->isSVGElement()) return; - HashSet<SVGElement*>* dependencies = object.document().accessSVGExtensions()->setOfElementsReferencingTarget(toSVGElement(object.node())); + HashSet<SVGElement*>* dependencies = renderer.document().accessSVGExtensions().setOfElementsReferencingTarget(downcast<SVGElement>(renderer.element())); if (!dependencies) return; - for (auto element : *dependencies) { - if (auto renderer = element->renderer()) + + // We allow cycles in SVGDocumentExtensions reference sets in order to avoid expensive + // reference graph adjustments on changes, so we need to break possible cycles here. + static NeverDestroyed<HashSet<SVGElement*>> invalidatingDependencies; + + for (auto* element : *dependencies) { + if (auto* renderer = element->renderer()) { + if (UNLIKELY(!invalidatingDependencies.get().add(element).isNewEntry)) { + // Reference cycle: we are in process of invalidating this dependant. + continue; + } RenderSVGResource::markForLayoutAndParentResourceInvalidation(*renderer, needsLayout); + invalidatingDependencies.get().remove(element); + } } } @@ -185,19 +191,20 @@ void RenderSVGResource::markForLayoutAndParentResourceInvalidation(RenderObject& { ASSERT(object.node()); - if (needsLayout && !object.documentBeingDestroyed()) + if (needsLayout && !object.renderTreeBeingDestroyed()) object.setNeedsLayout(); - removeFromCacheAndInvalidateDependencies(object, needsLayout); + if (is<RenderElement>(object)) + removeFromCacheAndInvalidateDependencies(downcast<RenderElement>(object), needsLayout); // Invalidate resources in ancestor chain, if needed. - RenderObject* current = object.parent(); + auto current = object.parent(); while (current) { removeFromCacheAndInvalidateDependencies(*current, needsLayout); - if (current->isSVGResourceContainer()) { + if (is<RenderSVGResourceContainer>(*current)) { // This will process the rest of the ancestors. - current->toRenderSVGResourceContainer()->removeAllClientsFromCache(); + downcast<RenderSVGResourceContainer>(*current).removeAllClientsFromCache(); break; } @@ -206,6 +213,3 @@ void RenderSVGResource::markForLayoutAndParentResourceInvalidation(RenderObject& } } - -#endif - diff --git a/Source/WebCore/rendering/svg/RenderSVGResource.h b/Source/WebCore/rendering/svg/RenderSVGResource.h index 2c66ffade..c06a30766 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResource.h +++ b/Source/WebCore/rendering/svg/RenderSVGResource.h @@ -17,13 +17,12 @@ * Boston, MA 02110-1301, USA. */ -#ifndef RenderSVGResource_h -#define RenderSVGResource_h +#pragma once -#if ENABLE(SVG) #include "RenderSVGShape.h" #include "RenderStyleConstants.h" #include "SVGDocumentExtensions.h" +#include <wtf/TypeCasts.h> namespace WebCore { @@ -60,7 +59,7 @@ public: virtual ~RenderSVGResource() { } virtual void removeAllClientsFromCache(bool markForInvalidation = true) = 0; - virtual void removeClientFromCache(RenderObject&, bool markForInvalidation = true) = 0; + virtual void removeClientFromCache(RenderElement&, bool markForInvalidation = true) = 0; virtual bool applyResource(RenderElement&, const RenderStyle&, GraphicsContext*&, unsigned short resourceMode) = 0; virtual void postApplyResource(RenderElement&, GraphicsContext*&, unsigned short, const Path*, const RenderSVGShape*) { } @@ -68,15 +67,6 @@ public: virtual RenderSVGResourceType resourceType() const = 0; - template<class Renderer> - Renderer* cast() - { - if (Renderer::s_resourceType == resourceType()) - return static_cast<Renderer*>(this); - - return 0; - } - // Helper utilities used in the render tree to access resources used for painting shapes/text (gradients & patterns & solid colors only) static RenderSVGResource* fillPaintingResource(RenderElement&, const RenderStyle&, Color& fallbackColor); static RenderSVGResource* strokePaintingResource(RenderElement&, const RenderStyle&, Color& fallbackColor); @@ -85,7 +75,9 @@ public: static void markForLayoutAndParentResourceInvalidation(RenderObject&, bool needsLayout = true); }; -} +} // namespace WebCore -#endif -#endif +#define SPECIALIZE_TYPE_TRAITS_RENDER_SVG_RESOURCE(ToValueTypeName, ResourceType) \ +SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::ToValueTypeName) \ + static bool isType(const WebCore::RenderSVGResource& resource) { return resource.resourceType() == WebCore::ResourceType; } \ +SPECIALIZE_TYPE_TRAITS_END() 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) diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceClipper.h b/Source/WebCore/rendering/svg/RenderSVGResourceClipper.h index 31c64b8b7..943e10312 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceClipper.h +++ b/Source/WebCore/rendering/svg/RenderSVGResourceClipper.h @@ -17,13 +17,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef RenderSVGResourceClipper_h -#define RenderSVGResourceClipper_h +#pragma once -#if ENABLE(SVG) -#include "GraphicsContext.h" -#include "ImageBuffer.h" -#include "IntSize.h" #include "RenderSVGResourceContainer.h" #include "SVGClipPathElement.h" #include "SVGUnitTypes.h" @@ -32,50 +27,55 @@ namespace WebCore { -struct ClipperData { - WTF_MAKE_FAST_ALLOCATED; -public: - std::unique_ptr<ImageBuffer> clipMaskImage; -}; +class GraphicsContext; +class ImageBuffer; + +typedef std::unique_ptr<ImageBuffer> ClipperMaskImage; class RenderSVGResourceClipper final : public RenderSVGResourceContainer { public: - RenderSVGResourceClipper(SVGClipPathElement&, PassRef<RenderStyle>); + RenderSVGResourceClipper(SVGClipPathElement&, RenderStyle&&); virtual ~RenderSVGResourceClipper(); - SVGClipPathElement& clipPathElement() const { return toSVGClipPathElement(nodeForNonAnonymous()); } + SVGClipPathElement& clipPathElement() const { return downcast<SVGClipPathElement>(nodeForNonAnonymous()); } - virtual void removeAllClientsFromCache(bool markForInvalidation = true); - virtual void removeClientFromCache(RenderObject&, bool markForInvalidation = true); + void removeAllClientsFromCache(bool markForInvalidation = true) override; + void removeClientFromCache(RenderElement&, bool markForInvalidation = true) override; - virtual bool applyResource(RenderElement&, const RenderStyle&, GraphicsContext*&, unsigned short resourceMode) override; + bool applyResource(RenderElement&, const RenderStyle&, GraphicsContext*&, unsigned short resourceMode) override; // clipPath can be clipped too, but don't have a boundingBox or repaintRect. So we can't call // applyResource directly and use the rects from the object, since they are empty for RenderSVGResources // FIXME: We made applyClippingToContext public because we cannot call applyResource on HTML elements (it asserts on RenderObject::objectBoundingBox) - bool applyClippingToContext(RenderElement&, const FloatRect&, const FloatRect&, GraphicsContext*); - virtual FloatRect resourceBoundingBox(const RenderObject&) override; + bool applyClippingToContext(RenderElement&, const FloatRect&, const FloatRect&, GraphicsContext&); + FloatRect resourceBoundingBox(const RenderObject&) override; - virtual RenderSVGResourceType resourceType() const { return ClipperResourceType; } + RenderSVGResourceType resourceType() const override { return ClipperResourceType; } bool hitTestClipContent(const FloatRect&, const FloatPoint&); SVGUnitTypes::SVGUnitType clipPathUnits() const { return clipPathElement().clipPathUnits(); } - static RenderSVGResourceType s_resourceType; +protected: + bool selfNeedsClientInvalidation() const override { return (everHadLayout() || m_clipper.size()) && selfNeedsLayout(); } + private: void element() const = delete; - virtual const char* renderName() const override { return "RenderSVGResourceClipper"; } + const char* renderName() const override { return "RenderSVGResourceClipper"; } + bool isSVGResourceClipper() const override { return true; } - bool pathOnlyClipping(GraphicsContext*, const AffineTransform&, const FloatRect&); - bool drawContentIntoMaskImage(ClipperData*, const FloatRect& objectBoundingBox); + bool pathOnlyClipping(GraphicsContext&, const AffineTransform&, const FloatRect&); + bool drawContentIntoMaskImage(const ClipperMaskImage&, const FloatRect& objectBoundingBox); void calculateClipContentRepaintRect(); + ClipperMaskImage& addRendererToClipper(const RenderObject&); FloatRect m_clipBoundaries; - HashMap<RenderObject*, std::unique_ptr<ClipperData>> m_clipper; + HashMap<const RenderObject*, ClipperMaskImage> m_clipper; }; } -#endif -#endif +SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::RenderSVGResourceClipper) +static bool isType(const WebCore::RenderObject& renderer) { return renderer.isSVGResourceClipper(); } +static bool isType(const WebCore::RenderSVGResource& resource) { return resource.resourceType() == WebCore::ClipperResourceType; } +SPECIALIZE_TYPE_TRAITS_END() diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp index 2d8a73138..3d44c6aaa 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceContainer.cpp @@ -18,8 +18,6 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGResourceContainer.h" #include "RenderLayer.h" @@ -33,12 +31,11 @@ namespace WebCore { static inline SVGDocumentExtensions& svgExtensionsFromElement(SVGElement& element) { - // FIXME: accessSVGExtensions() should return a reference. - return *element.document().accessSVGExtensions(); + return element.document().accessSVGExtensions(); } -RenderSVGResourceContainer::RenderSVGResourceContainer(SVGElement& element, PassRef<RenderStyle> style) - : RenderSVGHiddenContainer(element, std::move(style)) +RenderSVGResourceContainer::RenderSVGResourceContainer(SVGElement& element, RenderStyle&& style) + : RenderSVGHiddenContainer(element, WTFMove(style)) , m_id(element.getIdAttribute()) , m_registered(false) , m_isInvalidating(false) @@ -47,15 +44,13 @@ RenderSVGResourceContainer::RenderSVGResourceContainer(SVGElement& element, Pass RenderSVGResourceContainer::~RenderSVGResourceContainer() { - if (m_registered) - svgExtensionsFromElement(element()).removeResource(m_id); } void RenderSVGResourceContainer::layout() { StackStats::LayoutCheckPoint layoutCheckPoint; // Invalidate all resources if our layout changed. - if (everHadLayout() && selfNeedsLayout()) + if (selfNeedsClientInvalidation()) RenderSVGRoot::addResourceForClientInvalidation(this); RenderSVGHiddenContainer::layout(); @@ -64,6 +59,12 @@ void RenderSVGResourceContainer::layout() void RenderSVGResourceContainer::willBeDestroyed() { SVGResourcesCache::resourceDestroyed(*this); + + if (m_registered) { + svgExtensionsFromElement(element()).removeResource(m_id); + m_registered = false; + } + RenderSVGHiddenContainer::willBeDestroyed(); } @@ -97,10 +98,15 @@ void RenderSVGResourceContainer::markAllClientsForInvalidation(InvalidationMode m_isInvalidating = true; bool needsLayout = mode == LayoutAndBoundariesInvalidation; bool markForInvalidation = mode != ParentOnlyInvalidation; + auto* root = SVGRenderSupport::findTreeRootObject(*this); - for (auto client : m_clients) { - if (client->isSVGResourceContainer()) { - client->toRenderSVGResourceContainer()->removeAllClientsFromCache(markForInvalidation); + for (auto* client : m_clients) { + // We should not mark any client outside the current root for invalidation + if (root != SVGRenderSupport::findTreeRootObject(*client)) + continue; + + if (is<RenderSVGResourceContainer>(*client)) { + downcast<RenderSVGResourceContainer>(*client).removeAllClientsFromCache(markForInvalidation); continue; } @@ -117,10 +123,8 @@ void RenderSVGResourceContainer::markAllClientsForInvalidation(InvalidationMode void RenderSVGResourceContainer::markAllClientLayersForInvalidation() { -#if ENABLE(CSS_FILTERS) - for (auto clientLayer : m_clientLayers) + for (auto* clientLayer : m_clientLayers) clientLayer->filterNeedsRepaint(); -#endif } void RenderSVGResourceContainer::markClientForInvalidation(RenderObject& client, InvalidationMode mode) @@ -133,7 +137,7 @@ void RenderSVGResourceContainer::markClientForInvalidation(RenderObject& client, client.setNeedsBoundariesUpdate(); break; case RepaintInvalidation: - if (!client.documentBeingDestroyed()) + if (!client.renderTreeBeingDestroyed()) client.repaint(); break; case ParentOnlyInvalidation: @@ -141,17 +145,15 @@ void RenderSVGResourceContainer::markClientForInvalidation(RenderObject& client, } } -void RenderSVGResourceContainer::addClient(RenderObject* client) +void RenderSVGResourceContainer::addClient(RenderElement& client) { - ASSERT(client); - m_clients.add(client); + m_clients.add(&client); } -void RenderSVGResourceContainer::removeClient(RenderObject* client) +void RenderSVGResourceContainer::removeClient(RenderElement& client) { - ASSERT(client); - removeClientFromCache(*client, false); - m_clients.remove(client); + removeClientFromCache(client, false); + m_clients.remove(&client); } void RenderSVGResourceContainer::addClientRenderLayer(RenderLayer* client) @@ -180,11 +182,10 @@ void RenderSVGResourceContainer::registerResource() extensions.addResource(m_id, this); // Update cached resources of pending clients. - auto end = clients->end(); - for (auto it = clients->begin(); it != end; ++it) { - ASSERT((*it)->hasPendingResources()); - extensions.clearHasPendingResourcesIfPossible(*it); - auto renderer = (*it)->renderer(); + for (auto* client : *clients) { + ASSERT(client->hasPendingResources()); + extensions.clearHasPendingResourcesIfPossible(client); + auto* renderer = client->renderer(); if (!renderer) continue; SVGResourcesCache::clientStyleChanged(*renderer, StyleDifferenceLayout, renderer->style()); @@ -192,20 +193,20 @@ void RenderSVGResourceContainer::registerResource() } } -bool RenderSVGResourceContainer::shouldTransformOnTextPainting(RenderObject* object, AffineTransform& resourceTransform) +bool RenderSVGResourceContainer::shouldTransformOnTextPainting(const RenderElement& renderer, AffineTransform& resourceTransform) { - ASSERT_UNUSED(object, object); #if USE(CG) + UNUSED_PARAM(renderer); UNUSED_PARAM(resourceTransform); return false; #else // This method should only be called for RenderObjects that deal with text rendering. Cmp. RenderObject.h's is*() methods. - ASSERT(object->isSVGText() || object->isSVGTextPath() || object->isSVGInline()); + ASSERT(renderer.isSVGText() || renderer.isSVGTextPath() || renderer.isSVGInline()); // In text drawing, the scaling part of the graphics context CTM is removed, compare SVGInlineTextBox::paintTextWithShadows. // So, we use that scaling factor here, too, and then push it down to pattern or gradient space // in order to keep the pattern or gradient correctly scaled. - float scalingFactor = SVGRenderingContext::calculateScreenFontSizeScalingFactor(object); + float scalingFactor = SVGRenderingContext::calculateScreenFontSizeScalingFactor(renderer); if (scalingFactor == 1) return false; resourceTransform.scale(scalingFactor); @@ -219,12 +220,10 @@ AffineTransform RenderSVGResourceContainer::transformOnNonScalingStroke(RenderOb if (!object->isSVGShape()) return resourceTransform; - SVGGraphicsElement* element = toSVGGraphicsElement(object->node()); + SVGGraphicsElement* element = downcast<SVGGraphicsElement>(object->node()); AffineTransform transform = element->getScreenCTM(SVGLocatable::DisallowStyleUpdate); transform *= resourceTransform; return transform; } } - -#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceContainer.h b/Source/WebCore/rendering/svg/RenderSVGResourceContainer.h index b4045cabe..0cd7f1655 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceContainer.h +++ b/Source/WebCore/rendering/svg/RenderSVGResourceContainer.h @@ -17,10 +17,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef RenderSVGResourceContainer_h -#define RenderSVGResourceContainer_h +#pragma once -#if ENABLE(SVG) #include "RenderSVGHiddenContainer.h" #include "RenderSVGResource.h" @@ -33,13 +31,12 @@ class RenderSVGResourceContainer : public RenderSVGHiddenContainer, public: virtual ~RenderSVGResourceContainer(); - virtual void layout() override; - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) override final; + void layout() override; + void styleDidChange(StyleDifference, const RenderStyle* oldStyle) final; - virtual bool isSVGResourceContainer() const override final { return true; } - virtual RenderSVGResourceContainer* toRenderSVGResourceContainer() override final { return this; } + bool isSVGResourceContainer() const final { return true; } - static bool shouldTransformOnTextPainting(RenderObject*, AffineTransform&); + static bool shouldTransformOnTextPainting(const RenderElement&, AffineTransform&); static AffineTransform transformOnNonScalingStroke(RenderObject*, const AffineTransform& resourceTransform); void idChanged(); @@ -47,7 +44,7 @@ public: void removeClientRenderLayer(RenderLayer*); protected: - RenderSVGResourceContainer(SVGElement&, PassRef<RenderStyle>); + RenderSVGResourceContainer(SVGElement&, RenderStyle&&); enum InvalidationMode { LayoutAndBoundariesInvalidation, @@ -57,47 +54,50 @@ protected: }; // Used from the invalidateClient/invalidateClients methods from classes, inheriting from us. + virtual bool selfNeedsClientInvalidation() const { return everHadLayout() && selfNeedsLayout(); } + void markAllClientsForInvalidation(InvalidationMode); void markAllClientLayersForInvalidation(); void markClientForInvalidation(RenderObject&, InvalidationMode); private: friend class SVGResourcesCache; - void addClient(RenderObject*); - void removeClient(RenderObject*); + void addClient(RenderElement&); + void removeClient(RenderElement&); -private: - virtual void willBeDestroyed() override final; + void willBeDestroyed() final; void registerResource(); AtomicString m_id; bool m_registered : 1; bool m_isInvalidating : 1; - HashSet<RenderObject*> m_clients; + HashSet<RenderElement*> m_clients; HashSet<RenderLayer*> m_clientLayers; }; inline RenderSVGResourceContainer* getRenderSVGResourceContainerById(Document& document, const AtomicString& id) { if (id.isEmpty()) - return 0; + return nullptr; - if (RenderSVGResourceContainer* renderResource = document.accessSVGExtensions()->resourceById(id)) + if (RenderSVGResourceContainer* renderResource = document.accessSVGExtensions().resourceById(id)) return renderResource; - return 0; + return nullptr; } template<typename Renderer> Renderer* getRenderSVGResourceById(Document& document, const AtomicString& id) { - if (RenderSVGResourceContainer* container = getRenderSVGResourceContainerById(document, id)) - return container->cast<Renderer>(); + // Using the RenderSVGResource type here avoids ambiguous casts for types that + // descend from both RenderObject and RenderSVGResourceContainer. + RenderSVGResource* container = getRenderSVGResourceContainerById(document, id); + if (is<Renderer>(container)) + return downcast<Renderer>(container); - return 0; + return nullptr; } -} +} // namespace WebCore -#endif -#endif +SPECIALIZE_TYPE_TRAITS_RENDER_OBJECT(RenderSVGResourceContainer, isSVGResourceContainer()) diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp index 9dd85d6d8..2394db6aa 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.cpp @@ -22,8 +22,6 @@ */ #include "config.h" - -#if ENABLE(SVG) && ENABLE(FILTERS) #include "RenderSVGResourceFilter.h" #include "ElementChildIterator.h" @@ -34,22 +32,18 @@ #include "Image.h" #include "ImageData.h" #include "IntRect.h" -#include "Page.h" #include "RenderSVGResourceFilterPrimitive.h" #include "RenderView.h" #include "SVGFilterPrimitiveStandardAttributes.h" #include "SVGNames.h" #include "SVGRenderingContext.h" #include "Settings.h" -#include "SourceAlpha.h" #include "SourceGraphic.h" namespace WebCore { -RenderSVGResourceType RenderSVGResourceFilter::s_resourceType = FilterResourceType; - -RenderSVGResourceFilter::RenderSVGResourceFilter(SVGFilterElement& element, PassRef<RenderStyle> style) - : RenderSVGResourceContainer(element, std::move(style)) +RenderSVGResourceFilter::RenderSVGResourceFilter(SVGFilterElement& element, RenderStyle&& style) + : RenderSVGResourceContainer(element, WTFMove(style)) { } @@ -64,7 +58,7 @@ void RenderSVGResourceFilter::removeAllClientsFromCache(bool markForInvalidation markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation); } -void RenderSVGResourceFilter::removeClientFromCache(RenderObject& client, bool markForInvalidation) +void RenderSVGResourceFilter::removeClientFromCache(RenderElement& client, bool markForInvalidation) { if (FilterData* filterData = m_filter.get(&client)) { if (filterData->savedContext) @@ -76,46 +70,32 @@ void RenderSVGResourceFilter::removeClientFromCache(RenderObject& client, bool m markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidation : ParentOnlyInvalidation); } -std::unique_ptr<SVGFilterBuilder> RenderSVGResourceFilter::buildPrimitives(SVGFilter* filter) +std::unique_ptr<SVGFilterBuilder> RenderSVGResourceFilter::buildPrimitives(SVGFilter& filter) const { static const unsigned maxCountChildNodes = 200; - if (filterElement().childNodeCount() > maxCountChildNodes) + if (filterElement().countChildNodes() > maxCountChildNodes) return nullptr; - FloatRect targetBoundingBox = filter->targetBoundingBox(); + FloatRect targetBoundingBox = filter.targetBoundingBox(); // Add effects to the builder - auto builder = std::make_unique<SVGFilterBuilder>(SourceGraphic::create(filter), SourceAlpha::create(filter)); + auto builder = std::make_unique<SVGFilterBuilder>(SourceGraphic::create(filter)); for (auto& element : childrenOfType<SVGFilterPrimitiveStandardAttributes>(filterElement())) { RefPtr<FilterEffect> effect = element.build(builder.get(), filter); if (!effect) { builder->clearEffects(); return nullptr; } - builder->appendEffectToEffectReferences(effect, element.renderer()); + builder->appendEffectToEffectReferences(effect.copyRef(), element.renderer()); element.setStandardAttributes(effect.get()); effect->setEffectBoundaries(SVGLengthContext::resolveRectangle<SVGFilterPrimitiveStandardAttributes>(&element, filterElement().primitiveUnits(), targetBoundingBox)); - effect->setOperatingColorSpace(element.renderer()->style().svgStyle().colorInterpolationFilters() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceDeviceRGB); - builder->add(element.result(), effect.release()); + if (element.renderer()) + effect->setOperatingColorSpace(element.renderer()->style().svgStyle().colorInterpolationFilters() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceSRGB); + builder->add(element.result(), WTFMove(effect)); } return builder; } -bool RenderSVGResourceFilter::fitsInMaximumImageSize(const FloatSize& size, FloatSize& scale) -{ - bool matchesFilterSize = true; - if (size.width() > kMaxFilterSize) { - scale.setWidth(scale.width() * kMaxFilterSize / size.width()); - matchesFilterSize = false; - } - if (size.height() > kMaxFilterSize) { - scale.setHeight(scale.height() * kMaxFilterSize / size.height()); - matchesFilterSize = false; - } - - return matchesFilterSize; -} - bool RenderSVGResourceFilter::applyResource(RenderElement& renderer, const RenderStyle&, GraphicsContext*& context, unsigned short resourceMode) { ASSERT(context); @@ -136,8 +116,7 @@ bool RenderSVGResourceFilter::applyResource(RenderElement& renderer, const Rende return false; // Determine absolute transformation matrix for filter. - AffineTransform absoluteTransform; - SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(&renderer, absoluteTransform); + AffineTransform absoluteTransform = SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(renderer); if (!absoluteTransform.isInvertible()) return false; @@ -155,7 +134,7 @@ bool RenderSVGResourceFilter::applyResource(RenderElement& renderer, const Rende filterData->filter = SVGFilter::create(filterData->shearFreeAbsoluteTransform, absoluteDrawingRegion, targetBoundingBox, filterData->boundaries, primitiveBoundingBoxMode); // Create all relevant filter primitives. - filterData->builder = buildPrimitives(filterData->filter.get()); + filterData->builder = buildPrimitives(*filterData->filter); if (!filterData->builder) return false; @@ -172,8 +151,8 @@ bool RenderSVGResourceFilter::applyResource(RenderElement& renderer, const Rende // Determine scale factor for filter. The size of intermediate ImageBuffers shouldn't be bigger than kMaxFilterSize. FloatRect tempSourceRect = absoluteDrawingRegion; + ImageBuffer::sizeNeedsClamping(tempSourceRect.size(), scale); tempSourceRect.scale(scale.width(), scale.height()); - fitsInMaximumImageSize(tempSourceRect.size(), scale); // Set the scale level in SVGFilter. filterData->filter->setFilterResolution(scale); @@ -183,13 +162,13 @@ bool RenderSVGResourceFilter::applyResource(RenderElement& renderer, const Rende if (!lastEffect || lastEffect->totalNumberOfEffectInputs() > maxTotalOfEffectInputs) return false; - RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(lastEffect); + RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(*lastEffect); FloatRect subRegion = lastEffect->maxEffectRect(); // At least one FilterEffect has a too big image size, // recalculate the effect sizes with new scale factors. - if (!fitsInMaximumImageSize(subRegion.size(), scale)) { + if (ImageBuffer::sizeNeedsClamping(subRegion.size(), scale)) { filterData->filter->setFilterResolution(scale); - RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(lastEffect); + RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(*lastEffect); } // If the drawingRegion is empty, we have something like <g filter=".."/>. @@ -197,7 +176,7 @@ bool RenderSVGResourceFilter::applyResource(RenderElement& renderer, const Rende if (filterData->drawingRegion.isEmpty()) { ASSERT(!m_filter.contains(&renderer)); filterData->savedContext = context; - m_filter.set(&renderer, std::move(filterData)); + m_filter.set(&renderer, WTFMove(filterData)); return false; } @@ -206,28 +185,27 @@ bool RenderSVGResourceFilter::applyResource(RenderElement& renderer, const Rende effectiveTransform.scale(scale.width(), scale.height()); effectiveTransform.multiply(filterData->shearFreeAbsoluteTransform); - std::unique_ptr<ImageBuffer> sourceGraphic; - RenderingMode renderingMode = renderer.frame().settings().acceleratedFiltersEnabled() ? Accelerated : Unaccelerated; - if (!SVGRenderingContext::createImageBuffer(filterData->drawingRegion, effectiveTransform, sourceGraphic, ColorSpaceLinearRGB, renderingMode)) { + RenderingMode renderingMode = renderer.settings().acceleratedFiltersEnabled() ? Accelerated : Unaccelerated; + auto sourceGraphic = SVGRenderingContext::createImageBuffer(filterData->drawingRegion, effectiveTransform, ColorSpaceLinearRGB, renderingMode); + if (!sourceGraphic) { ASSERT(!m_filter.contains(&renderer)); filterData->savedContext = context; - m_filter.set(&renderer, std::move(filterData)); + m_filter.set(&renderer, WTFMove(filterData)); return false; } // Set the rendering mode from the page's settings. filterData->filter->setRenderingMode(renderingMode); - GraphicsContext* sourceGraphicContext = sourceGraphic->context(); - ASSERT(sourceGraphicContext); + GraphicsContext& sourceGraphicContext = sourceGraphic->context(); - filterData->sourceGraphicBuffer = std::move(sourceGraphic); + filterData->sourceGraphicBuffer = WTFMove(sourceGraphic); filterData->savedContext = context; - context = sourceGraphicContext; + context = &sourceGraphicContext; ASSERT(!m_filter.contains(&renderer)); - m_filter.set(&renderer, std::move(filterData)); + m_filter.set(&renderer, WTFMove(filterData)); return true; } @@ -275,7 +253,7 @@ void RenderSVGResourceFilter::postApplyResource(RenderElement& renderer, Graphic // initial filtering process. We just take the stored filter result on a // second drawing. if (filterData->state != FilterData::Built) - filterData->filter->setSourceImage(std::move(filterData->sourceGraphicBuffer)); + filterData->filter->setSourceImage(WTFMove(filterData->sourceGraphicBuffer)); // Always true if filterData is just built (filterData->state == FilterData::Built). if (!lastEffect->hasResult()) { @@ -288,10 +266,10 @@ void RenderSVGResourceFilter::postApplyResource(RenderElement& renderer, Graphic ImageBuffer* resultImage = lastEffect->asImageBuffer(); if (resultImage) { - context->concatCTM(filterData->shearFreeAbsoluteTransform.inverse()); + context->concatCTM(filterData->shearFreeAbsoluteTransform.inverse().value_or(AffineTransform())); context->scale(FloatSize(1 / filterData->filter->filterResolution().width(), 1 / filterData->filter->filterResolution().height())); - context->drawImageBuffer(resultImage, renderer.style().colorSpace(), lastEffect->absolutePaintRect()); + context->drawImageBuffer(*resultImage, lastEffect->absolutePaintRect()); context->scale(filterData->filter->filterResolution()); context->concatCTM(filterData->shearFreeAbsoluteTransform); @@ -337,4 +315,3 @@ FloatRect RenderSVGResourceFilter::drawingRegion(RenderObject* object) const } } -#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilter.h b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.h index 97e6fdbf9..2e7bbbee1 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceFilter.h +++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilter.h @@ -21,17 +21,14 @@ * Boston, MA 02110-1301, USA. */ -#ifndef RenderSVGResourceFilter_h -#define RenderSVGResourceFilter_h +#pragma once -#if ENABLE(SVG) && ENABLE(FILTERS) #include "ImageBuffer.h" #include "RenderSVGResourceContainer.h" #include "SVGFilter.h" #include "SVGFilterBuilder.h" #include "SVGFilterElement.h" #include "SVGUnitTypes.h" - #include <wtf/RefPtr.h> namespace WebCore { @@ -63,44 +60,41 @@ class GraphicsContext; class RenderSVGResourceFilter final : public RenderSVGResourceContainer { public: - RenderSVGResourceFilter(SVGFilterElement&, PassRef<RenderStyle>); + RenderSVGResourceFilter(SVGFilterElement&, RenderStyle&&); virtual ~RenderSVGResourceFilter(); - SVGFilterElement& filterElement() const { return toSVGFilterElement(RenderSVGResourceContainer::element()); } + SVGFilterElement& filterElement() const { return downcast<SVGFilterElement>(RenderSVGResourceContainer::element()); } - virtual void removeAllClientsFromCache(bool markForInvalidation = true); - virtual void removeClientFromCache(RenderObject&, bool markForInvalidation = true); + void removeAllClientsFromCache(bool markForInvalidation = true) override; + void removeClientFromCache(RenderElement&, bool markForInvalidation = true) override; - virtual bool applyResource(RenderElement&, const RenderStyle&, GraphicsContext*&, unsigned short resourceMode) override; - virtual void postApplyResource(RenderElement&, GraphicsContext*&, unsigned short resourceMode, const Path*, const RenderSVGShape*) override; + bool applyResource(RenderElement&, const RenderStyle&, GraphicsContext*&, unsigned short resourceMode) override; + void postApplyResource(RenderElement&, GraphicsContext*&, unsigned short resourceMode, const Path*, const RenderSVGShape*) override; - virtual FloatRect resourceBoundingBox(const RenderObject&) override; + FloatRect resourceBoundingBox(const RenderObject&) override; - std::unique_ptr<SVGFilterBuilder> buildPrimitives(SVGFilter*); + std::unique_ptr<SVGFilterBuilder> buildPrimitives(SVGFilter&) const; SVGUnitTypes::SVGUnitType filterUnits() const { return filterElement().filterUnits(); } SVGUnitTypes::SVGUnitType primitiveUnits() const { return filterElement().primitiveUnits(); } void primitiveAttributeChanged(RenderObject*, const QualifiedName&); - virtual RenderSVGResourceType resourceType() const { return s_resourceType; } - static RenderSVGResourceType s_resourceType; + RenderSVGResourceType resourceType() const override { return FilterResourceType; } FloatRect drawingRegion(RenderObject*) const; private: void element() const = delete; - virtual const char* renderName() const override { return "RenderSVGResourceFilter"; } - virtual bool isSVGResourceFilter() const override { return true; } - - bool fitsInMaximumImageSize(const FloatSize&, FloatSize&); + const char* renderName() const override { return "RenderSVGResourceFilter"; } + bool isSVGResourceFilter() const override { return true; } HashMap<RenderObject*, std::unique_ptr<FilterData>> m_filter; }; -RENDER_OBJECT_TYPE_CASTS(RenderSVGResourceFilter, isSVGResourceFilter()) - -} +} // namespace WebCore -#endif -#endif +SPECIALIZE_TYPE_TRAITS_BEGIN(WebCore::RenderSVGResourceFilter) + static bool isType(const WebCore::RenderObject& renderer) { return renderer.isSVGResourceFilter(); } + static bool isType(const WebCore::RenderSVGResource& resource) { return resource.resourceType() == WebCore::FilterResourceType; } +SPECIALIZE_TYPE_TRAITS_END() diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp index 24887b702..323643bf8 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.cpp @@ -26,18 +26,19 @@ */ #include "config.h" - -#if ENABLE(SVG) && ENABLE(FILTERS) #include "RenderSVGResourceFilterPrimitive.h" +#include "SVGFEDiffuseLightingElement.h" +#include "SVGFEFloodElement.h" #include "SVGFEImage.h" +#include "SVGFESpecularLightingElement.h" #include "SVGFilterPrimitiveStandardAttributes.h" #include "SVGNames.h" namespace WebCore { -RenderSVGResourceFilterPrimitive::RenderSVGResourceFilterPrimitive(SVGFilterPrimitiveStandardAttributes& filterPrimitiveElement, PassRef<RenderStyle> style) - : RenderSVGHiddenContainer(filterPrimitiveElement, std::move(style)) +RenderSVGResourceFilterPrimitive::RenderSVGResourceFilterPrimitive(SVGFilterPrimitiveStandardAttributes& filterPrimitiveElement, RenderStyle&& style) + : RenderSVGHiddenContainer(filterPrimitiveElement, WTFMove(style)) { } @@ -50,69 +51,65 @@ void RenderSVGResourceFilterPrimitive::styleDidChange(StyleDifference diff, cons { RenderSVGHiddenContainer::styleDidChange(diff, oldStyle); - RenderObject* filter = parent(); + auto* filter = parent(); if (!filter) return; - ASSERT(filter->isSVGResourceFilter()); if (diff == StyleDifferenceEqual || !oldStyle) return; const SVGRenderStyle& newStyle = style().svgStyle(); - if (filterPrimitiveElement().hasTagName(SVGNames::feFloodTag)) { + if (is<SVGFEFloodElement>(filterPrimitiveElement())) { if (newStyle.floodColor() != oldStyle->svgStyle().floodColor()) - toRenderSVGResourceFilter(filter)->primitiveAttributeChanged(this, SVGNames::flood_colorAttr); + downcast<RenderSVGResourceFilter>(*filter).primitiveAttributeChanged(this, SVGNames::flood_colorAttr); if (newStyle.floodOpacity() != oldStyle->svgStyle().floodOpacity()) - toRenderSVGResourceFilter(filter)->primitiveAttributeChanged(this, SVGNames::flood_opacityAttr); - } else if (filterPrimitiveElement().hasTagName(SVGNames::feDiffuseLightingTag) || filterPrimitiveElement().hasTagName(SVGNames::feSpecularLightingTag)) { + downcast<RenderSVGResourceFilter>(*filter).primitiveAttributeChanged(this, SVGNames::flood_opacityAttr); + } else if (is<SVGFEDiffuseLightingElement>(filterPrimitiveElement()) || is<SVGFESpecularLightingElement>(filterPrimitiveElement())) { if (newStyle.lightingColor() != oldStyle->svgStyle().lightingColor()) - toRenderSVGResourceFilter(filter)->primitiveAttributeChanged(this, SVGNames::lighting_colorAttr); + downcast<RenderSVGResourceFilter>(*filter).primitiveAttributeChanged(this, SVGNames::lighting_colorAttr); } } -FloatRect RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(FilterEffect* effect) +FloatRect RenderSVGResourceFilterPrimitive::determineFilterPrimitiveSubregion(FilterEffect& effect) { - SVGFilter* filter = toSVGFilter(effect->filter()); - ASSERT(filter); + auto& filter = downcast<SVGFilter>(effect.filter()); // FETile, FETurbulence, FEFlood don't have input effects, take the filter region as unite rect. FloatRect subregion; - if (unsigned numberOfInputEffects = effect->inputEffects().size()) { - subregion = determineFilterPrimitiveSubregion(effect->inputEffect(0)); + if (unsigned numberOfInputEffects = effect.inputEffects().size()) { + subregion = determineFilterPrimitiveSubregion(*effect.inputEffect(0)); for (unsigned i = 1; i < numberOfInputEffects; ++i) - subregion.unite(determineFilterPrimitiveSubregion(effect->inputEffect(i))); + subregion.unite(determineFilterPrimitiveSubregion(*effect.inputEffect(i))); } else - subregion = filter->filterRegionInUserSpace(); + subregion = filter.filterRegionInUserSpace(); // After calling determineFilterPrimitiveSubregion on the target effect, reset the subregion again for <feTile>. - if (effect->filterEffectType() == FilterEffectTypeTile) - subregion = filter->filterRegionInUserSpace(); + if (effect.filterEffectType() == FilterEffectTypeTile) + subregion = filter.filterRegionInUserSpace(); - FloatRect effectBoundaries = effect->effectBoundaries(); - if (effect->hasX()) + FloatRect effectBoundaries = effect.effectBoundaries(); + if (effect.hasX()) subregion.setX(effectBoundaries.x()); - if (effect->hasY()) + if (effect.hasY()) subregion.setY(effectBoundaries.y()); - if (effect->hasWidth()) + if (effect.hasWidth()) subregion.setWidth(effectBoundaries.width()); - if (effect->hasHeight()) + if (effect.hasHeight()) subregion.setHeight(effectBoundaries.height()); - effect->setFilterPrimitiveSubregion(subregion); + effect.setFilterPrimitiveSubregion(subregion); - FloatRect absoluteSubregion = filter->absoluteTransform().mapRect(subregion); - FloatSize filterResolution = filter->filterResolution(); + FloatRect absoluteSubregion = filter.absoluteTransform().mapRect(subregion); + FloatSize filterResolution = filter.filterResolution(); absoluteSubregion.scale(filterResolution.width(), filterResolution.height()); // Clip every filter effect to the filter region. - FloatRect absoluteScaledFilterRegion = filter->filterRegion(); + FloatRect absoluteScaledFilterRegion = filter.filterRegion(); absoluteScaledFilterRegion.scale(filterResolution.width(), filterResolution.height()); absoluteSubregion.intersect(absoluteScaledFilterRegion); - effect->setMaxEffectRect(absoluteSubregion); + effect.setMaxEffectRect(absoluteSubregion); return subregion; } } // namespace WebCore - -#endif // ENABLE(SVG) && ENABLE(FILTERS) diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h index f67d61a0f..7b546bf65 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h +++ b/Source/WebCore/rendering/svg/RenderSVGResourceFilterPrimitive.h @@ -24,10 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef RenderSVGResourceFilterPrimitive_h -#define RenderSVGResourceFilterPrimitive_h - -#if ENABLE(SVG) && ENABLE(FILTERS) +#pragma once #include "RenderSVGResourceFilter.h" @@ -38,16 +35,15 @@ class SVGFilterPrimitiveStandardAttributes; class RenderSVGResourceFilterPrimitive final : public RenderSVGHiddenContainer { public: - RenderSVGResourceFilterPrimitive(SVGFilterPrimitiveStandardAttributes&, PassRef<RenderStyle>); + RenderSVGResourceFilterPrimitive(SVGFilterPrimitiveStandardAttributes&, RenderStyle&&); SVGFilterPrimitiveStandardAttributes& filterPrimitiveElement() const; - virtual void styleDidChange(StyleDifference, const RenderStyle*); + void styleDidChange(StyleDifference, const RenderStyle*) override; - virtual const char* renderName() const { return "RenderSVGResourceFilterPrimitive"; } - virtual bool isSVGResourceFilterPrimitive() const { return true; } + const char* renderName() const override { return "RenderSVGResourceFilterPrimitive"; } // They depend on the RenderObject argument of RenderSVGResourceFilter::applyResource. - static FloatRect determineFilterPrimitiveSubregion(FilterEffect*); + static FloatRect determineFilterPrimitiveSubregion(FilterEffect&); inline void primitiveAttributeChanged(const QualifiedName& attribute) { @@ -57,11 +53,8 @@ public: static_cast<RenderSVGResourceFilter*>(filter)->primitiveAttributeChanged(this, attribute); } private: + bool isSVGResourceFilterPrimitive() const override { return true; } void element() const = delete; }; } // namespace WebCore - -#endif // ENABLE(SVG) && ENABLE(FILTERS) - -#endif // RenderSVGResourceFilterPrimitive_h diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp index 496a7be59..bc9d02a27 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.cpp @@ -21,8 +21,6 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGResourceGradient.h" #include "GradientAttributes.h" @@ -32,8 +30,8 @@ namespace WebCore { -RenderSVGResourceGradient::RenderSVGResourceGradient(SVGGradientElement& node, PassRef<RenderStyle> style) - : RenderSVGResourceContainer(node, std::move(style)) +RenderSVGResourceGradient::RenderSVGResourceGradient(SVGGradientElement& node, RenderStyle&& style) + : RenderSVGResourceContainer(node, WTFMove(style)) , m_shouldCollectGradientAttributes(true) #if USE(CG) , m_savedContext(0) @@ -48,7 +46,7 @@ void RenderSVGResourceGradient::removeAllClientsFromCache(bool markForInvalidati markAllClientsForInvalidation(markForInvalidation ? RepaintInvalidation : ParentOnlyInvalidation); } -void RenderSVGResourceGradient::removeClientFromCache(RenderObject& client, bool markForInvalidation) +void RenderSVGResourceGradient::removeClientFromCache(RenderElement& client, bool markForInvalidation) { m_gradientMap.remove(&client); markClientForInvalidation(client, markForInvalidation ? RepaintInvalidation : ParentOnlyInvalidation); @@ -57,35 +55,33 @@ void RenderSVGResourceGradient::removeClientFromCache(RenderObject& client, bool #if USE(CG) static inline bool createMaskAndSwapContextForTextGradient(GraphicsContext*& context, GraphicsContext*& savedContext, std::unique_ptr<ImageBuffer>& imageBuffer, RenderObject* object) { - RenderObject* textRootBlock = RenderSVGText::locateRenderSVGTextAncestor(object); + auto* textRootBlock = RenderSVGText::locateRenderSVGTextAncestor(*object); ASSERT(textRootBlock); - AffineTransform absoluteTransform; - SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(textRootBlock, absoluteTransform); - + AffineTransform absoluteTransform = SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(*textRootBlock); FloatRect repaintRect = textRootBlock->repaintRectInLocalCoordinates(); - std::unique_ptr<ImageBuffer> maskImage; - if (!SVGRenderingContext::createImageBuffer(repaintRect, absoluteTransform, maskImage, ColorSpaceDeviceRGB, Unaccelerated)) + + auto maskImage = SVGRenderingContext::createImageBuffer(repaintRect, absoluteTransform, ColorSpaceSRGB, context->renderingMode()); + if (!maskImage) return false; - GraphicsContext* maskImageContext = maskImage->context(); - ASSERT(maskImageContext); + GraphicsContext& maskImageContext = maskImage->context(); ASSERT(maskImage); savedContext = context; - context = maskImageContext; - imageBuffer = std::move(maskImage); + context = &maskImageContext; + imageBuffer = WTFMove(maskImage); return true; } -static inline AffineTransform clipToTextMask(GraphicsContext* context, std::unique_ptr<ImageBuffer>& imageBuffer, FloatRect& targetRect, RenderObject* object, bool boundingBoxMode, const AffineTransform& gradientTransform) +static inline AffineTransform clipToTextMask(GraphicsContext& context, std::unique_ptr<ImageBuffer>& imageBuffer, FloatRect& targetRect, RenderObject* object, bool boundingBoxMode, const AffineTransform& gradientTransform) { - RenderObject* textRootBlock = RenderSVGText::locateRenderSVGTextAncestor(object); + auto* textRootBlock = RenderSVGText::locateRenderSVGTextAncestor(*object); ASSERT(textRootBlock); - AffineTransform absoluteTransform; - SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(textRootBlock, absoluteTransform); + AffineTransform absoluteTransform = SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(*textRootBlock); targetRect = textRootBlock->repaintRectInLocalCoordinates(); + SVGRenderingContext::clipToImageBuffer(context, absoluteTransform, targetRect, imageBuffer, false); AffineTransform matrix; @@ -122,9 +118,9 @@ bool RenderSVGResourceGradient::applyResource(RenderElement& renderer, const Ren if (gradientUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX && objectBoundingBox.isEmpty()) return false; - OwnPtr<GradientData>& gradientData = m_gradientMap.add(&renderer, nullptr).iterator->value; + auto& gradientData = m_gradientMap.add(&renderer, nullptr).iterator->value; if (!gradientData) - gradientData = adoptPtr(new GradientData); + gradientData = std::make_unique<GradientData>(); bool isPaintingText = resourceMode & ApplyToTextMode; @@ -152,7 +148,7 @@ bool RenderSVGResourceGradient::applyResource(RenderElement& renderer, const Ren // Depending on font scaling factor, we may need to rescale the gradient here since // text painting removes the scale factor from the context. AffineTransform additionalTextTransform; - if (shouldTransformOnTextPainting(&renderer, additionalTextTransform)) + if (shouldTransformOnTextPainting(renderer, additionalTextTransform)) gradientData->userspaceTransform *= additionalTextTransform; } gradientData->gradient->setGradientSpaceTransform(gradientData->userspaceTransform); @@ -179,13 +175,13 @@ bool RenderSVGResourceGradient::applyResource(RenderElement& renderer, const Ren if (resourceMode & ApplyToFillMode) { context->setAlpha(svgStyle.fillOpacity()); - context->setFillGradient(gradientData->gradient); + context->setFillGradient(*gradientData->gradient); context->setFillRule(svgStyle.fillRule()); } else if (resourceMode & ApplyToStrokeMode) { if (svgStyle.vectorEffect() == VE_NON_SCALING_STROKE) gradientData->gradient->setGradientSpaceTransform(transformOnNonScalingStroke(&renderer, gradientData->userspaceTransform)); context->setAlpha(svgStyle.strokeOpacity()); - context->setStrokeGradient(gradientData->gradient); + context->setStrokeGradient(*gradientData->gradient); SVGRenderSupport::applyStrokeStyleToContext(context, style, renderer); } @@ -210,8 +206,8 @@ void RenderSVGResourceGradient::postApplyResource(RenderElement& renderer, Graph calculateGradientTransform(gradientTransform); FloatRect targetRect; - gradientData->gradient->setGradientSpaceTransform(clipToTextMask(context, m_imageBuffer, targetRect, &renderer, gradientUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX, gradientTransform)); - context->setFillGradient(gradientData->gradient); + gradientData->gradient->setGradientSpaceTransform(clipToTextMask(*context, m_imageBuffer, targetRect, &renderer, gradientUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX, gradientTransform)); + context->setFillGradient(*gradientData->gradient); context->fillRect(targetRect); m_imageBuffer.reset(); @@ -224,13 +220,13 @@ void RenderSVGResourceGradient::postApplyResource(RenderElement& renderer, Graph if (path) context->fillPath(*path); else if (shape) - shape->fillShape(context); + shape->fillShape(*context); } if (resourceMode & ApplyToStrokeMode) { if (path) context->strokePath(*path); else if (shape) - shape->strokeShape(context); + shape->strokeShape(*context); } } @@ -263,5 +259,3 @@ GradientSpreadMethod RenderSVGResourceGradient::platformSpreadMethodFromSVGType( } } - -#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceGradient.h b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.h index c37fc7a5c..e7918f594 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceGradient.h +++ b/Source/WebCore/rendering/svg/RenderSVGResourceGradient.h @@ -19,15 +19,13 @@ * Boston, MA 02110-1301, USA. */ -#ifndef RenderSVGResourceGradient_h -#define RenderSVGResourceGradient_h +#pragma once -#if ENABLE(SVG) #include "Gradient.h" #include "ImageBuffer.h" #include "RenderSVGResourceContainer.h" #include "SVGGradientElement.h" - +#include <memory> #include <wtf/HashMap.h> namespace WebCore { @@ -45,15 +43,15 @@ class RenderSVGResourceGradient : public RenderSVGResourceContainer { public: SVGGradientElement& gradientElement() const { return static_cast<SVGGradientElement&>(RenderSVGResourceContainer::element()); } - virtual void removeAllClientsFromCache(bool markForInvalidation = true) override final; - virtual void removeClientFromCache(RenderObject&, bool markForInvalidation = true) override final; + void removeAllClientsFromCache(bool markForInvalidation = true) final; + void removeClientFromCache(RenderElement&, bool markForInvalidation = true) final; - virtual bool applyResource(RenderElement&, const RenderStyle&, GraphicsContext*&, unsigned short resourceMode) override final; - virtual void postApplyResource(RenderElement&, GraphicsContext*&, unsigned short resourceMode, const Path*, const RenderSVGShape*) override final; - virtual FloatRect resourceBoundingBox(const RenderObject&) override final { return FloatRect(); } + bool applyResource(RenderElement&, const RenderStyle&, GraphicsContext*&, unsigned short resourceMode) final; + void postApplyResource(RenderElement&, GraphicsContext*&, unsigned short resourceMode, const Path*, const RenderSVGShape*) final; + FloatRect resourceBoundingBox(const RenderObject&) final { return FloatRect(); } protected: - RenderSVGResourceGradient(SVGGradientElement&, PassRef<RenderStyle>); + RenderSVGResourceGradient(SVGGradientElement&, RenderStyle&&); void element() const = delete; @@ -68,7 +66,7 @@ protected: private: bool m_shouldCollectGradientAttributes : 1; - HashMap<RenderObject*, OwnPtr<GradientData>> m_gradientMap; + HashMap<RenderObject*, std::unique_ptr<GradientData>> m_gradientMap; #if USE(CG) GraphicsContext* m_savedContext; @@ -76,7 +74,4 @@ private: #endif }; -} - -#endif -#endif +} // namespace WebCore diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.cpp index c928e5b86..e51ff5fb3 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.cpp @@ -19,17 +19,13 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGResourceLinearGradient.h" namespace WebCore { -RenderSVGResourceType RenderSVGResourceLinearGradient::s_resourceType = LinearGradientResourceType; - -RenderSVGResourceLinearGradient::RenderSVGResourceLinearGradient(SVGLinearGradientElement& element, PassRef<RenderStyle> style) - : RenderSVGResourceGradient(element, std::move(style)) +RenderSVGResourceLinearGradient::RenderSVGResourceLinearGradient(SVGLinearGradientElement& element, RenderStyle&& style) + : RenderSVGResourceGradient(element, WTFMove(style)) { } @@ -61,5 +57,3 @@ void RenderSVGResourceLinearGradient::buildGradient(GradientData* gradientData) } } - -#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.h b/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.h index eaec65974..8a28d7557 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.h +++ b/Source/WebCore/rendering/svg/RenderSVGResourceLinearGradient.h @@ -18,10 +18,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef RenderSVGResourceLinearGradient_h -#define RenderSVGResourceLinearGradient_h +#pragma once -#if ENABLE(SVG) #include "LinearGradientAttributes.h" #include "RenderSVGResourceGradient.h" #include "SVGLinearGradientElement.h" @@ -30,18 +28,17 @@ namespace WebCore { class RenderSVGResourceLinearGradient final : public RenderSVGResourceGradient { public: - RenderSVGResourceLinearGradient(SVGLinearGradientElement&, PassRef<RenderStyle>); + RenderSVGResourceLinearGradient(SVGLinearGradientElement&, RenderStyle&&); virtual ~RenderSVGResourceLinearGradient(); - SVGLinearGradientElement& linearGradientElement() const { return toSVGLinearGradientElement(RenderSVGResourceGradient::gradientElement()); } + SVGLinearGradientElement& linearGradientElement() const { return downcast<SVGLinearGradientElement>(RenderSVGResourceGradient::gradientElement()); } - virtual RenderSVGResourceType resourceType() const { return s_resourceType; } - static RenderSVGResourceType s_resourceType; + RenderSVGResourceType resourceType() const override { return LinearGradientResourceType; } - virtual SVGUnitTypes::SVGUnitType gradientUnits() const { return m_attributes.gradientUnits(); } - virtual void calculateGradientTransform(AffineTransform& transform) { transform = m_attributes.gradientTransform(); } - virtual bool collectGradientAttributes() override; - virtual void buildGradient(GradientData*) const; + SVGUnitTypes::SVGUnitType gradientUnits() const override { return m_attributes.gradientUnits(); } + void calculateGradientTransform(AffineTransform& transform) override { transform = m_attributes.gradientTransform(); } + bool collectGradientAttributes() override; + void buildGradient(GradientData*) const override; FloatPoint startPoint(const LinearGradientAttributes&) const; FloatPoint endPoint(const LinearGradientAttributes&) const; @@ -49,12 +46,11 @@ public: private: void gradientElement() const = delete; - virtual const char* renderName() const override { return "RenderSVGResourceLinearGradient"; } + const char* renderName() const override { return "RenderSVGResourceLinearGradient"; } LinearGradientAttributes m_attributes; }; -} +} // namespace WebCore -#endif -#endif +SPECIALIZE_TYPE_TRAITS_RENDER_SVG_RESOURCE(RenderSVGResourceLinearGradient, LinearGradientResourceType) diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp index 3ea195056..75360ae6a 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceMarker.cpp @@ -20,8 +20,6 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGResourceMarker.h" #include "GraphicsContext.h" @@ -30,10 +28,8 @@ namespace WebCore { -RenderSVGResourceType RenderSVGResourceMarker::s_resourceType = MarkerResourceType; - -RenderSVGResourceMarker::RenderSVGResourceMarker(SVGMarkerElement& element, PassRef<RenderStyle> style) - : RenderSVGResourceContainer(element, std::move(style)) +RenderSVGResourceMarker::RenderSVGResourceMarker(SVGMarkerElement& element, RenderStyle&& style) + : RenderSVGResourceContainer(element, WTFMove(style)) { } @@ -59,7 +55,7 @@ void RenderSVGResourceMarker::removeAllClientsFromCache(bool markForInvalidation markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation); } -void RenderSVGResourceMarker::removeClientFromCache(RenderObject& client, bool markForInvalidation) +void RenderSVGResourceMarker::removeClientFromCache(RenderElement& client, bool markForInvalidation) { markClientForInvalidation(client, markForInvalidation ? BoundariesInvalidation : ParentOnlyInvalidation); } @@ -67,7 +63,7 @@ void RenderSVGResourceMarker::removeClientFromCache(RenderObject& client, bool m void RenderSVGResourceMarker::applyViewportClip(PaintInfo& paintInfo) { if (SVGRenderSupport::isOverflowHidden(*this)) - paintInfo.context->clip(m_viewport); + paintInfo.context().clip(m_viewport); } FloatRect RenderSVGResourceMarker::markerBoundaries(const AffineTransform& markerTransformation) const @@ -122,7 +118,7 @@ void RenderSVGResourceMarker::draw(PaintInfo& paintInfo, const AffineTransform& return; PaintInfo info(paintInfo); - GraphicsContextStateSaver stateSaver(*info.context); + GraphicsContextStateSaver stateSaver(info.context()); info.applyTransform(transform); RenderSVGContainer::paint(info, IntPoint()); } @@ -157,5 +153,3 @@ void RenderSVGResourceMarker::calcViewport() } } - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceMarker.h b/Source/WebCore/rendering/svg/RenderSVGResourceMarker.h index 442cc60d7..63c8bf785 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceMarker.h +++ b/Source/WebCore/rendering/svg/RenderSVGResourceMarker.h @@ -17,13 +17,10 @@ * Boston, MA 02110-1301, USA. */ -#ifndef RenderSVGResourceMarker_h -#define RenderSVGResourceMarker_h +#pragma once -#if ENABLE(SVG) #include "RenderSVGResourceContainer.h" #include "SVGMarkerElement.h" - #include <wtf/HashSet.h> namespace WebCore { @@ -33,40 +30,39 @@ class RenderObject; class RenderSVGResourceMarker final : public RenderSVGResourceContainer { public: - RenderSVGResourceMarker(SVGMarkerElement&, PassRef<RenderStyle>); + RenderSVGResourceMarker(SVGMarkerElement&, RenderStyle&&); virtual ~RenderSVGResourceMarker(); - SVGMarkerElement& markerElement() const { return toSVGMarkerElement(RenderSVGResourceContainer::element()); } + SVGMarkerElement& markerElement() const { return downcast<SVGMarkerElement>(RenderSVGResourceContainer::element()); } - virtual void removeAllClientsFromCache(bool markForInvalidation = true); - virtual void removeClientFromCache(RenderObject&, bool markForInvalidation = true); + void removeAllClientsFromCache(bool markForInvalidation = true) override; + void removeClientFromCache(RenderElement&, bool markForInvalidation = true) override; void draw(PaintInfo&, const AffineTransform&); // Calculates marker boundaries, mapped to the target element's coordinate space FloatRect markerBoundaries(const AffineTransform& markerTransformation) const; - virtual void applyViewportClip(PaintInfo&); - virtual void layout(); - virtual void calcViewport(); + void applyViewportClip(PaintInfo&) override; + void layout() override; + void calcViewport() override; - virtual const AffineTransform& localToParentTransform() const; + const AffineTransform& localToParentTransform() const override; AffineTransform markerTransformation(const FloatPoint& origin, float angle, float strokeWidth) const; - virtual bool applyResource(RenderElement&, const RenderStyle&, GraphicsContext*&, unsigned short) override { return false; } - virtual FloatRect resourceBoundingBox(const RenderObject&) override { return FloatRect(); } + bool applyResource(RenderElement&, const RenderStyle&, GraphicsContext*&, unsigned short) override { return false; } + FloatRect resourceBoundingBox(const RenderObject&) override { return FloatRect(); } FloatPoint referencePoint() const; float angle() const; SVGMarkerUnitsType markerUnits() const { return markerElement().markerUnits(); } - virtual RenderSVGResourceType resourceType() const { return s_resourceType; } - static RenderSVGResourceType s_resourceType; + RenderSVGResourceType resourceType() const override { return MarkerResourceType; } private: void element() const = delete; - virtual const char* renderName() const override { return "RenderSVGResourceMarker"; } + const char* renderName() const override { return "RenderSVGResourceMarker"; } // Generates a transformation matrix usable to render marker content. Handles scaling the marker content // acording to SVGs markerUnits="strokeWidth" concept, when a strokeWidth value != -1 is passed in. @@ -78,7 +74,6 @@ private: FloatRect m_viewport; }; -} -#endif +} // namespace WebCore -#endif +SPECIALIZE_TYPE_TRAITS_RENDER_SVG_RESOURCE(RenderSVGResourceMarker, MarkerResourceType) diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp index e02fab47b..f0d6744c0 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceMasker.cpp @@ -18,8 +18,6 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGResourceMasker.h" #include "Element.h" @@ -31,10 +29,8 @@ namespace WebCore { -RenderSVGResourceType RenderSVGResourceMasker::s_resourceType = MaskerResourceType; - -RenderSVGResourceMasker::RenderSVGResourceMasker(SVGMaskElement& element, PassRef<RenderStyle> style) - : RenderSVGResourceContainer(element, std::move(style)) +RenderSVGResourceMasker::RenderSVGResourceMasker(SVGMaskElement& element, RenderStyle&& style) + : RenderSVGResourceContainer(element, WTFMove(style)) { } @@ -50,7 +46,7 @@ void RenderSVGResourceMasker::removeAllClientsFromCache(bool markForInvalidation markAllClientsForInvalidation(markForInvalidation ? LayoutAndBoundariesInvalidation : ParentOnlyInvalidation); } -void RenderSVGResourceMasker::removeClientFromCache(RenderObject& client, bool markForInvalidation) +void RenderSVGResourceMasker::removeClientFromCache(RenderElement& client, bool markForInvalidation) { m_masker.remove(&client); @@ -67,34 +63,31 @@ bool RenderSVGResourceMasker::applyResource(RenderElement& renderer, const Rende m_masker.set(&renderer, std::make_unique<MaskerData>()); MaskerData* maskerData = m_masker.get(&renderer); - - AffineTransform absoluteTransform; - SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(&renderer, absoluteTransform); - + AffineTransform absoluteTransform = SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(renderer); FloatRect repaintRect = renderer.repaintRectInLocalCoordinates(); if (!maskerData->maskImage && !repaintRect.isEmpty()) { const SVGRenderStyle& svgStyle = style().svgStyle(); - ColorSpace colorSpace = svgStyle.colorInterpolation() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceDeviceRGB; - if (!SVGRenderingContext::createImageBuffer(repaintRect, absoluteTransform, maskerData->maskImage, colorSpace, Unaccelerated)) + ColorSpace colorSpace = svgStyle.colorInterpolation() == CI_LINEARRGB ? ColorSpaceLinearRGB : ColorSpaceSRGB; + // FIXME (149470): This image buffer should not be unconditionally unaccelerated. Making it match the context breaks alpha masking, though. + maskerData->maskImage = SVGRenderingContext::createImageBuffer(repaintRect, absoluteTransform, colorSpace, Unaccelerated); + if (!maskerData->maskImage) return false; - if (!drawContentIntoMaskImage(maskerData, colorSpace, &renderer)) { + if (!drawContentIntoMaskImage(maskerData, colorSpace, &renderer)) maskerData->maskImage.reset(); - } } if (!maskerData->maskImage) return false; - SVGRenderingContext::clipToImageBuffer(context, absoluteTransform, repaintRect, maskerData->maskImage, missingMaskerData); + SVGRenderingContext::clipToImageBuffer(*context, absoluteTransform, repaintRect, maskerData->maskImage, missingMaskerData); return true; } bool RenderSVGResourceMasker::drawContentIntoMaskImage(MaskerData* maskerData, ColorSpace colorSpace, RenderObject* object) { - GraphicsContext* maskImageContext = maskerData->maskImage->context(); - ASSERT(maskImageContext); + GraphicsContext& maskImageContext = maskerData->maskImage->context(); // Eventually adjust the mask image context according to the target objectBoundingBox. AffineTransform maskContentTransformation; @@ -102,7 +95,7 @@ bool RenderSVGResourceMasker::drawContentIntoMaskImage(MaskerData* maskerData, C FloatRect objectBoundingBox = object->objectBoundingBox(); maskContentTransformation.translate(objectBoundingBox.x(), objectBoundingBox.y()); maskContentTransformation.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height()); - maskImageContext->concatCTM(maskContentTransformation); + maskImageContext.concatCTM(maskContentTransformation); } // Draw the content into the ImageBuffer. @@ -169,5 +162,3 @@ FloatRect RenderSVGResourceMasker::resourceBoundingBox(const RenderObject& objec } } - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceMasker.h b/Source/WebCore/rendering/svg/RenderSVGResourceMasker.h index ecae4332e..5b93ac9e6 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceMasker.h +++ b/Source/WebCore/rendering/svg/RenderSVGResourceMasker.h @@ -17,11 +17,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef RenderSVGResourceMasker_h -#define RenderSVGResourceMasker_h +#pragma once -#if ENABLE(SVG) -#include "GraphicsContext.h" #include "ImageBuffer.h" #include "IntSize.h" #include "RenderSVGResourceContainer.h" @@ -32,32 +29,33 @@ namespace WebCore { +class GraphicsContext; + struct MaskerData { std::unique_ptr<ImageBuffer> maskImage; }; class RenderSVGResourceMasker final : public RenderSVGResourceContainer { public: - RenderSVGResourceMasker(SVGMaskElement&, PassRef<RenderStyle>); + RenderSVGResourceMasker(SVGMaskElement&, RenderStyle&&); virtual ~RenderSVGResourceMasker(); - SVGMaskElement& maskElement() const { return toSVGMaskElement(RenderSVGResourceContainer::element()); } + SVGMaskElement& maskElement() const { return downcast<SVGMaskElement>(RenderSVGResourceContainer::element()); } - virtual void removeAllClientsFromCache(bool markForInvalidation = true); - virtual void removeClientFromCache(RenderObject&, bool markForInvalidation = true); - virtual bool applyResource(RenderElement&, const RenderStyle&, GraphicsContext*&, unsigned short resourceMode) override; - virtual FloatRect resourceBoundingBox(const RenderObject&) override; + void removeAllClientsFromCache(bool markForInvalidation = true) override; + void removeClientFromCache(RenderElement&, bool markForInvalidation = true) override; + bool applyResource(RenderElement&, const RenderStyle&, GraphicsContext*&, unsigned short resourceMode) override; + FloatRect resourceBoundingBox(const RenderObject&) override; SVGUnitTypes::SVGUnitType maskUnits() const { return maskElement().maskUnits(); } SVGUnitTypes::SVGUnitType maskContentUnits() const { return maskElement().maskContentUnits(); } - virtual RenderSVGResourceType resourceType() const { return s_resourceType; } - static RenderSVGResourceType s_resourceType; + RenderSVGResourceType resourceType() const override { return MaskerResourceType; } private: void element() const = delete; - virtual const char* renderName() const override { return "RenderSVGResourceMasker"; } + const char* renderName() const override { return "RenderSVGResourceMasker"; } bool drawContentIntoMaskImage(MaskerData*, ColorSpace, RenderObject*); void calculateMaskContentRepaintRect(); @@ -68,5 +66,4 @@ private: } -#endif -#endif +SPECIALIZE_TYPE_TRAITS_RENDER_SVG_RESOURCE(RenderSVGResourceMasker, MaskerResourceType) diff --git a/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp b/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp index 4ed8e6a98..ea936a4dc 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourcePattern.cpp @@ -19,8 +19,6 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGResourcePattern.h" #include "ElementIterator.h" @@ -29,20 +27,20 @@ #include "RenderSVGRoot.h" #include "SVGFitToViewBox.h" #include "SVGRenderingContext.h" +#include "SVGResources.h" +#include "SVGResourcesCache.h" namespace WebCore { -RenderSVGResourceType RenderSVGResourcePattern::s_resourceType = PatternResourceType; - -RenderSVGResourcePattern::RenderSVGResourcePattern(SVGPatternElement& element, PassRef<RenderStyle> style) - : RenderSVGResourceContainer(element, std::move(style)) +RenderSVGResourcePattern::RenderSVGResourcePattern(SVGPatternElement& element, RenderStyle&& style) + : RenderSVGResourceContainer(element, WTFMove(style)) , m_shouldCollectPatternAttributes(true) { } SVGPatternElement& RenderSVGResourcePattern::patternElement() const { - return toSVGPatternElement(RenderSVGResourceContainer::element()); + return downcast<SVGPatternElement>(RenderSVGResourceContainer::element()); } void RenderSVGResourcePattern::removeAllClientsFromCache(bool markForInvalidation) @@ -52,42 +50,48 @@ void RenderSVGResourcePattern::removeAllClientsFromCache(bool markForInvalidatio markAllClientsForInvalidation(markForInvalidation ? RepaintInvalidation : ParentOnlyInvalidation); } -void RenderSVGResourcePattern::removeClientFromCache(RenderObject& client, bool markForInvalidation) +void RenderSVGResourcePattern::removeClientFromCache(RenderElement& client, bool markForInvalidation) { m_patternMap.remove(&client); markClientForInvalidation(client, markForInvalidation ? RepaintInvalidation : ParentOnlyInvalidation); } -PatternData* RenderSVGResourcePattern::buildPattern(RenderObject* object, unsigned short resourceMode) +void RenderSVGResourcePattern::collectPatternAttributes(PatternAttributes& attributes) const { - PatternData* currentData = m_patternMap.get(object); - if (currentData && currentData->pattern) - return currentData; + const RenderSVGResourcePattern* current = this; - if (m_shouldCollectPatternAttributes) { - patternElement().synchronizeAnimatedSVGAttribute(anyQName()); + while (current) { + const SVGPatternElement& pattern = current->patternElement(); + pattern.collectPatternAttributes(attributes); - m_attributes = PatternAttributes(); - patternElement().collectPatternAttributes(m_attributes); - m_shouldCollectPatternAttributes = false; + auto* resources = SVGResourcesCache::cachedResourcesForRenderer(*current); + current = resources ? downcast<RenderSVGResourcePattern>(resources->linkedResource()) : nullptr; } +} + +PatternData* RenderSVGResourcePattern::buildPattern(RenderElement& renderer, unsigned short resourceMode, GraphicsContext& context) +{ + ASSERT(!m_shouldCollectPatternAttributes); + + PatternData* currentData = m_patternMap.get(&renderer); + if (currentData && currentData->pattern) + return currentData; // If we couldn't determine the pattern content element root, stop here. if (!m_attributes.patternContentElement()) - return 0; + return nullptr; // An empty viewBox disables rendering. if (m_attributes.hasViewBox() && m_attributes.viewBox().isEmpty()) - return 0; + return nullptr; // Compute all necessary transformations to build the tile image & the pattern. FloatRect tileBoundaries; AffineTransform tileImageTransform; - if (!buildTileImageTransform(object, m_attributes, patternElement(), tileBoundaries, tileImageTransform)) - return 0; + if (!buildTileImageTransform(renderer, m_attributes, patternElement(), tileBoundaries, tileImageTransform)) + return nullptr; - AffineTransform absoluteTransformIgnoringRotation; - SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(object, absoluteTransformIgnoringRotation); + AffineTransform absoluteTransformIgnoringRotation = SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(renderer); // Ignore 2D rotation, as it doesn't affect the size of the tile. SVGRenderingContext::clear2DRotation(absoluteTransformIgnoringRotation); @@ -99,20 +103,22 @@ PatternData* RenderSVGResourcePattern::buildPattern(RenderObject* object, unsign static_cast<float>(m_attributes.patternTransform().yScale())); // Build tile image. - std::unique_ptr<ImageBuffer> tileImage = createTileImage(m_attributes, tileBoundaries, absoluteTileBoundaries, tileImageTransform, clampedAbsoluteTileBoundaries); + auto tileImage = createTileImage(m_attributes, tileBoundaries, absoluteTileBoundaries, tileImageTransform, clampedAbsoluteTileBoundaries, context.renderingMode()); if (!tileImage) - return 0; + return nullptr; - RefPtr<Image> copiedImage = tileImage->copyImage(CopyBackingStore); + const IntSize tileImageSize = tileImage->logicalSize(); + + RefPtr<Image> copiedImage = ImageBuffer::sinkIntoImage(WTFMove(tileImage)); if (!copiedImage) - return 0; + return nullptr; // Build pattern. - OwnPtr<PatternData> patternData = adoptPtr(new PatternData); + auto patternData = std::make_unique<PatternData>(); patternData->pattern = Pattern::create(copiedImage, true, true); // Compute pattern space transformation. - const IntSize tileImageSize = tileImage->logicalSize(); + patternData->transform.translate(tileBoundaries.x(), tileBoundaries.y()); patternData->transform.scale(tileBoundaries.width() / tileImageSize.width(), tileBoundaries.height() / tileImageSize.height()); @@ -123,7 +129,7 @@ PatternData* RenderSVGResourcePattern::buildPattern(RenderObject* object, unsign // Account for text drawing resetting the context to non-scaled, see SVGInlineTextBox::paintTextWithShadows. if (resourceMode & ApplyToTextMode) { AffineTransform additionalTextTransformation; - if (shouldTransformOnTextPainting(object, additionalTextTransformation)) + if (shouldTransformOnTextPainting(renderer, additionalTextTransformation)) patternData->transform *= additionalTextTransformation; } patternData->pattern->setPatternSpaceTransform(patternData->transform); @@ -131,7 +137,7 @@ PatternData* RenderSVGResourcePattern::buildPattern(RenderObject* object, unsign // Various calls above may trigger invalidations in some fringe cases (ImageBuffer allocation // failures in the SVG image cache for example). To avoid having our PatternData deleted by // removeAllClientsFromCache(), we only make it visible in the cache at the very end. - return m_patternMap.set(object, patternData.release()).iterator->value.get(); + return m_patternMap.set(&renderer, WTFMove(patternData)).iterator->value.get(); } bool RenderSVGResourcePattern::applyResource(RenderElement& renderer, const RenderStyle& style, GraphicsContext*& context, unsigned short resourceMode) @@ -139,13 +145,21 @@ bool RenderSVGResourcePattern::applyResource(RenderElement& renderer, const Rend ASSERT(context); ASSERT(resourceMode != ApplyToDefaultMode); + if (m_shouldCollectPatternAttributes) { + patternElement().synchronizeAnimatedSVGAttribute(anyQName()); + + m_attributes = PatternAttributes(); + collectPatternAttributes(m_attributes); + m_shouldCollectPatternAttributes = false; + } + // Spec: When the geometry of the applicable element has no width or height and objectBoundingBox is specified, // then the given effect (e.g. a gradient or a filter) will be ignored. FloatRect objectBoundingBox = renderer.objectBoundingBox(); if (m_attributes.patternUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX && objectBoundingBox.isEmpty()) return false; - PatternData* patternData = buildPattern(&renderer, resourceMode); + PatternData* patternData = buildPattern(renderer, resourceMode, *context); if (!patternData) return false; @@ -156,13 +170,13 @@ bool RenderSVGResourcePattern::applyResource(RenderElement& renderer, const Rend if (resourceMode & ApplyToFillMode) { context->setAlpha(svgStyle.fillOpacity()); - context->setFillPattern(patternData->pattern); + context->setFillPattern(*patternData->pattern); context->setFillRule(svgStyle.fillRule()); } else if (resourceMode & ApplyToStrokeMode) { if (svgStyle.vectorEffect() == VE_NON_SCALING_STROKE) patternData->pattern->setPatternSpaceTransform(transformOnNonScalingStroke(&renderer, patternData->transform)); context->setAlpha(svgStyle.strokeOpacity()); - context->setStrokePattern(patternData->pattern); + context->setStrokePattern(*patternData->pattern); SVGRenderSupport::applyStrokeStyleToContext(context, style, renderer); } @@ -194,13 +208,13 @@ void RenderSVGResourcePattern::postApplyResource(RenderElement&, GraphicsContext if (path) context->fillPath(*path); else if (shape) - shape->fillShape(context); + shape->fillShape(*context); } if (resourceMode & ApplyToStrokeMode) { if (path) context->strokePath(*path); else if (shape) - shape->strokeShape(context); + shape->strokeShape(*context); } context->restore(); @@ -213,15 +227,13 @@ static inline FloatRect calculatePatternBoundaries(const PatternAttributes& attr return SVGLengthContext::resolveRectangle(&patternElement, attributes.patternUnits(), objectBoundingBox, attributes.x(), attributes.y(), attributes.width(), attributes.height()); } -bool RenderSVGResourcePattern::buildTileImageTransform(RenderObject* renderer, +bool RenderSVGResourcePattern::buildTileImageTransform(RenderElement& renderer, const PatternAttributes& attributes, const SVGPatternElement& patternElement, FloatRect& patternBoundaries, AffineTransform& tileImageTransform) const { - ASSERT(renderer); - - FloatRect objectBoundingBox = renderer->objectBoundingBox(); + FloatRect objectBoundingBox = renderer.objectBoundingBox(); patternBoundaries = calculatePatternBoundaries(attributes, objectBoundingBox, patternElement); if (patternBoundaries.width() <= 0 || patternBoundaries.height() <= 0) return false; @@ -237,25 +249,22 @@ bool RenderSVGResourcePattern::buildTileImageTransform(RenderObject* renderer, return true; } -std::unique_ptr<ImageBuffer> RenderSVGResourcePattern::createTileImage(const PatternAttributes& attributes, const FloatRect& tileBoundaries, const FloatRect& absoluteTileBoundaries, const AffineTransform& tileImageTransform, FloatRect& clampedAbsoluteTileBoundaries) const +std::unique_ptr<ImageBuffer> RenderSVGResourcePattern::createTileImage(const PatternAttributes& attributes, const FloatRect& tileBoundaries, const FloatRect& absoluteTileBoundaries, const AffineTransform& tileImageTransform, FloatRect& clampedAbsoluteTileBoundaries, RenderingMode renderingMode) const { - clampedAbsoluteTileBoundaries = SVGRenderingContext::clampedAbsoluteTargetRect(absoluteTileBoundaries); - - std::unique_ptr<ImageBuffer> tileImage; - - if (!SVGRenderingContext::createImageBufferForPattern(absoluteTileBoundaries, clampedAbsoluteTileBoundaries, tileImage, ColorSpaceDeviceRGB, Unaccelerated)) + clampedAbsoluteTileBoundaries = ImageBuffer::clampedRect(absoluteTileBoundaries); + auto tileImage = SVGRenderingContext::createImageBuffer(absoluteTileBoundaries, clampedAbsoluteTileBoundaries, ColorSpaceSRGB, renderingMode); + if (!tileImage) return nullptr; - GraphicsContext* tileImageContext = tileImage->context(); - ASSERT(tileImageContext); + GraphicsContext& tileImageContext = tileImage->context(); // The image buffer represents the final rendered size, so the content has to be scaled (to avoid pixelation). - tileImageContext->scale(FloatSize(clampedAbsoluteTileBoundaries.width() / tileBoundaries.width(), + tileImageContext.scale(FloatSize(clampedAbsoluteTileBoundaries.width() / tileBoundaries.width(), clampedAbsoluteTileBoundaries.height() / tileBoundaries.height())); // Apply tile image transformations. if (!tileImageTransform.isIdentity()) - tileImageContext->concatCTM(tileImageTransform); + tileImageContext.concatCTM(tileImageTransform); AffineTransform contentTransformation; if (attributes.patternContentUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) @@ -274,5 +283,3 @@ std::unique_ptr<ImageBuffer> RenderSVGResourcePattern::createTileImage(const Pat } } - -#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourcePattern.h b/Source/WebCore/rendering/svg/RenderSVGResourcePattern.h index 9eebeefa4..5f5b560df 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourcePattern.h +++ b/Source/WebCore/rendering/svg/RenderSVGResourcePattern.h @@ -18,17 +18,15 @@ * Boston, MA 02110-1301, USA. */ -#ifndef RenderSVGResourcePattern_h -#define RenderSVGResourcePattern_h +#pragma once -#if ENABLE(SVG) #include "ImageBuffer.h" #include "Pattern.h" #include "PatternAttributes.h" #include "RenderSVGResourceContainer.h" #include "SVGPatternElement.h" #include "SVGUnitTypes.h" - +#include <memory> #include <wtf/HashMap.h> namespace WebCore { @@ -42,35 +40,35 @@ public: class RenderSVGResourcePattern final : public RenderSVGResourceContainer { public: - RenderSVGResourcePattern(SVGPatternElement&, PassRef<RenderStyle>); + RenderSVGResourcePattern(SVGPatternElement&, RenderStyle&&); SVGPatternElement& patternElement() const; - virtual void removeAllClientsFromCache(bool markForInvalidation = true); - virtual void removeClientFromCache(RenderObject&, bool markForInvalidation = true); + void removeAllClientsFromCache(bool markForInvalidation = true) override; + void removeClientFromCache(RenderElement&, bool markForInvalidation = true) override; + + bool applyResource(RenderElement&, const RenderStyle&, GraphicsContext*&, unsigned short resourceMode) override; + void postApplyResource(RenderElement&, GraphicsContext*&, unsigned short resourceMode, const Path*, const RenderSVGShape*) override; + FloatRect resourceBoundingBox(const RenderObject&) override { return FloatRect(); } - virtual bool applyResource(RenderElement&, const RenderStyle&, GraphicsContext*&, unsigned short resourceMode) override; - virtual void postApplyResource(RenderElement&, GraphicsContext*&, unsigned short resourceMode, const Path*, const RenderSVGShape*) override; - virtual FloatRect resourceBoundingBox(const RenderObject&) override { return FloatRect(); } + RenderSVGResourceType resourceType() const override { return PatternResourceType; } - virtual RenderSVGResourceType resourceType() const { return s_resourceType; } - static RenderSVGResourceType s_resourceType; + void collectPatternAttributes(PatternAttributes&) const; private: void element() const = delete; - virtual const char* renderName() const override { return "RenderSVGResourcePattern"; } + const char* renderName() const override { return "RenderSVGResourcePattern"; } - bool buildTileImageTransform(RenderObject*, const PatternAttributes&, const SVGPatternElement&, FloatRect& patternBoundaries, AffineTransform& tileImageTransform) const; + bool buildTileImageTransform(RenderElement&, const PatternAttributes&, const SVGPatternElement&, FloatRect& patternBoundaries, AffineTransform& tileImageTransform) const; - std::unique_ptr<ImageBuffer> createTileImage(const PatternAttributes&, const FloatRect& tileBoundaries, const FloatRect& absoluteTileBoundaries, const AffineTransform& tileImageTransform, FloatRect& clampedAbsoluteTileBoundaries) const; + std::unique_ptr<ImageBuffer> createTileImage(const PatternAttributes&, const FloatRect& tileBoundaries, const FloatRect& absoluteTileBoundaries, const AffineTransform& tileImageTransform, FloatRect& clampedAbsoluteTileBoundaries, RenderingMode) const; - PatternData* buildPattern(RenderObject*, unsigned short resourceMode); + PatternData* buildPattern(RenderElement&, unsigned short resourceMode, GraphicsContext&); bool m_shouldCollectPatternAttributes : 1; PatternAttributes m_attributes; - HashMap<RenderObject*, OwnPtr<PatternData>> m_patternMap; + HashMap<RenderElement*, std::unique_ptr<PatternData>> m_patternMap; }; -} +} // namespace WebCore -#endif -#endif +SPECIALIZE_TYPE_TRAITS_RENDER_SVG_RESOURCE(RenderSVGResourcePattern, PatternResourceType) diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.cpp index 1f5b8d163..ecbc39b89 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.cpp @@ -20,17 +20,12 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGResourceRadialGradient.h" - namespace WebCore { -RenderSVGResourceType RenderSVGResourceRadialGradient::s_resourceType = RadialGradientResourceType; - -RenderSVGResourceRadialGradient::RenderSVGResourceRadialGradient(SVGRadialGradientElement& element, PassRef<RenderStyle> style) - : RenderSVGResourceGradient(element, std::move(style)) +RenderSVGResourceRadialGradient::RenderSVGResourceRadialGradient(SVGRadialGradientElement& element, RenderStyle&& style) + : RenderSVGResourceGradient(element, WTFMove(style)) { } @@ -77,5 +72,3 @@ void RenderSVGResourceRadialGradient::buildGradient(GradientData* gradientData) } } - -#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.h b/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.h index f1e61a4ee..0b8ae3efd 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.h +++ b/Source/WebCore/rendering/svg/RenderSVGResourceRadialGradient.h @@ -18,10 +18,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef RenderSVGResourceRadialGradient_h -#define RenderSVGResourceRadialGradient_h +#pragma once -#if ENABLE(SVG) #include "RadialGradientAttributes.h" #include "RenderSVGResourceGradient.h" #include "SVGRadialGradientElement.h" @@ -32,17 +30,16 @@ class SVGRadialGradientElement; class RenderSVGResourceRadialGradient final : public RenderSVGResourceGradient { public: - RenderSVGResourceRadialGradient(SVGRadialGradientElement&, PassRef<RenderStyle>); + RenderSVGResourceRadialGradient(SVGRadialGradientElement&, RenderStyle&&); virtual ~RenderSVGResourceRadialGradient(); - SVGRadialGradientElement& radialGradientElement() const { return toSVGRadialGradientElement(RenderSVGResourceGradient::gradientElement()); } + SVGRadialGradientElement& radialGradientElement() const { return downcast<SVGRadialGradientElement>(RenderSVGResourceGradient::gradientElement()); } - virtual RenderSVGResourceType resourceType() const { return s_resourceType; } - static RenderSVGResourceType s_resourceType; + RenderSVGResourceType resourceType() const override { return RadialGradientResourceType; } - virtual SVGUnitTypes::SVGUnitType gradientUnits() const { return m_attributes.gradientUnits(); } - virtual void calculateGradientTransform(AffineTransform& transform) { transform = m_attributes.gradientTransform(); } - virtual void buildGradient(GradientData*) const; + SVGUnitTypes::SVGUnitType gradientUnits() const override { return m_attributes.gradientUnits(); } + void calculateGradientTransform(AffineTransform& transform) override { transform = m_attributes.gradientTransform(); } + void buildGradient(GradientData*) const override; FloatPoint centerPoint(const RadialGradientAttributes&) const; FloatPoint focalPoint(const RadialGradientAttributes&) const; @@ -52,13 +49,12 @@ public: private: void gradientElement() const = delete; - virtual const char* renderName() const override { return "RenderSVGResourceRadialGradient"; } - virtual bool collectGradientAttributes() override; + const char* renderName() const override { return "RenderSVGResourceRadialGradient"; } + bool collectGradientAttributes() override; RadialGradientAttributes m_attributes; }; -} +} // namespace WebCore -#endif -#endif +SPECIALIZE_TYPE_TRAITS_RENDER_SVG_RESOURCE(RenderSVGResourceRadialGradient, RadialGradientResourceType) diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.cpp b/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.cpp index 1d9ada519..4b20da58f 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.cpp @@ -18,8 +18,6 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGResourceSolidColor.h" #include "Frame.h" @@ -30,8 +28,6 @@ namespace WebCore { -RenderSVGResourceType RenderSVGResourceSolidColor::s_resourceType = SolidColorResourceType; - RenderSVGResourceSolidColor::RenderSVGResourceSolidColor() { } @@ -46,7 +42,6 @@ bool RenderSVGResourceSolidColor::applyResource(RenderElement& renderer, const R ASSERT(resourceMode != ApplyToDefaultMode); const SVGRenderStyle& svgStyle = style.svgStyle(); - ColorSpace colorSpace = style.colorSpace(); bool isRenderingMask = renderer.view().frameView().paintBehavior() & PaintBehaviorRenderingSVGMask; @@ -55,7 +50,7 @@ bool RenderSVGResourceSolidColor::applyResource(RenderElement& renderer, const R context->setAlpha(svgStyle.fillOpacity()); else context->setAlpha(1); - context->setFillColor(m_color, colorSpace); + context->setFillColor(m_color); if (!isRenderingMask) context->setFillRule(svgStyle.fillRule()); @@ -65,7 +60,7 @@ bool RenderSVGResourceSolidColor::applyResource(RenderElement& renderer, const R // When rendering the mask for a RenderSVGResourceClipper, the stroke code path is never hit. ASSERT(!isRenderingMask); context->setAlpha(svgStyle.strokeOpacity()); - context->setStrokeColor(m_color, colorSpace); + context->setStrokeColor(m_color); SVGRenderSupport::applyStrokeStyleToContext(context, style, renderer); @@ -85,16 +80,14 @@ void RenderSVGResourceSolidColor::postApplyResource(RenderElement&, GraphicsCont if (path) context->fillPath(*path); else if (shape) - shape->fillShape(context); + shape->fillShape(*context); } if (resourceMode & ApplyToStrokeMode) { if (path) context->strokePath(*path); else if (shape) - shape->strokeShape(context); + shape->strokeShape(*context); } } } - -#endif diff --git a/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.h b/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.h index 80eb45df6..79301bcab 100644 --- a/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.h +++ b/Source/WebCore/rendering/svg/RenderSVGResourceSolidColor.h @@ -17,29 +17,27 @@ * Boston, MA 02110-1301, USA. */ -#ifndef RenderSVGResourceSolidColor_h -#define RenderSVGResourceSolidColor_h +#pragma once -#if ENABLE(SVG) #include "Color.h" #include "RenderSVGResource.h" namespace WebCore { -class RenderSVGResourceSolidColor : public RenderSVGResource { +class RenderSVGResourceSolidColor final : public RenderSVGResource { + WTF_MAKE_FAST_ALLOCATED; public: RenderSVGResourceSolidColor(); virtual ~RenderSVGResourceSolidColor(); - virtual void removeAllClientsFromCache(bool = true) { } - virtual void removeClientFromCache(RenderObject&, bool = true) { } + void removeAllClientsFromCache(bool = true) override { } + void removeClientFromCache(RenderElement&, bool = true) override { } - virtual bool applyResource(RenderElement&, const RenderStyle&, GraphicsContext*&, unsigned short resourceMode) override; - virtual void postApplyResource(RenderElement&, GraphicsContext*&, unsigned short resourceMode, const Path*, const RenderSVGShape*) override; - virtual FloatRect resourceBoundingBox(const RenderObject&) override { return FloatRect(); } + bool applyResource(RenderElement&, const RenderStyle&, GraphicsContext*&, unsigned short resourceMode) override; + void postApplyResource(RenderElement&, GraphicsContext*&, unsigned short resourceMode, const Path*, const RenderSVGShape*) override; + FloatRect resourceBoundingBox(const RenderObject&) override { return FloatRect(); } - virtual RenderSVGResourceType resourceType() const { return s_resourceType; } - static RenderSVGResourceType s_resourceType; + RenderSVGResourceType resourceType() const override { return SolidColorResourceType; } const Color& color() const { return m_color; } void setColor(const Color& color) { m_color = color; } @@ -48,7 +46,6 @@ private: Color m_color; }; -} +} // namespace WebCore -#endif -#endif +SPECIALIZE_TYPE_TRAITS_RENDER_SVG_RESOURCE(RenderSVGResourceSolidColor, SolidColorResourceType) diff --git a/Source/WebCore/rendering/svg/RenderSVGRoot.cpp b/Source/WebCore/rendering/svg/RenderSVGRoot.cpp index 6de3aa3c6..0ddbbbcac 100644 --- a/Source/WebCore/rendering/svg/RenderSVGRoot.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGRoot.cpp @@ -22,21 +22,21 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGRoot.h" -#include "Chrome.h" -#include "ChromeClient.h" #include "Frame.h" #include "GraphicsContext.h" #include "HitTestResult.h" #include "LayoutRepainter.h" #include "Page.h" #include "RenderIterator.h" +#include "RenderLayer.h" +#include "RenderNamedFlowFragment.h" +#include "RenderSVGResource.h" +#include "RenderSVGResourceContainer.h" +#include "RenderSVGResourceFilter.h" #include "RenderView.h" #include "SVGImage.h" -#include "SVGLength.h" #include "SVGRenderingContext.h" #include "SVGResources.h" #include "SVGResourcesCache.h" @@ -45,18 +45,15 @@ #include "TransformState.h" #include <wtf/StackStats.h> -#if ENABLE(FILTERS) -#include "RenderSVGResourceFilter.h" -#endif - namespace WebCore { -RenderSVGRoot::RenderSVGRoot(SVGSVGElement& element, PassRef<RenderStyle> style) - : RenderReplaced(element, std::move(style)) +RenderSVGRoot::RenderSVGRoot(SVGSVGElement& element, RenderStyle&& style) + : RenderReplaced(element, WTFMove(style)) , m_objectBoundingBoxValid(false) , m_isLayoutSizeChanged(false) , m_needsBoundariesOrTransformUpdate(true) , m_hasSVGShadow(false) + , m_hasBoxDecorations(false) { } @@ -66,20 +63,13 @@ RenderSVGRoot::~RenderSVGRoot() SVGSVGElement& RenderSVGRoot::svgSVGElement() const { - return toSVGSVGElement(nodeForNonAnonymous()); + return downcast<SVGSVGElement>(nodeForNonAnonymous()); } -void RenderSVGRoot::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const +void RenderSVGRoot::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio) const { // Spec: http://www.w3.org/TR/SVG/coords.html#IntrinsicSizing // SVG needs to specify how to calculate some intrinsic sizing properties to enable inclusion within other languages. - // The intrinsic width and height of the viewport of SVG content must be determined from the ‘width’ and ‘height’ attributes. - // If either of these are not specified, a value of '100%' must be assumed. Note: the ‘width’ and ‘height’ attributes are not - // the same as the CSS width and height properties. Specifically, percentage values do not provide an intrinsic width or height, - // and do not indicate a percentage of the containing block. Rather, once the viewport is established, they indicate the portion - // of the viewport that is actually covered by image data. - Length intrinsicWidthAttribute = svgSVGElement().intrinsicWidth(SVGSVGElement::IgnoreCSSProperties); - Length intrinsicHeightAttribute = svgSVGElement().intrinsicHeight(SVGSVGElement::IgnoreCSSProperties); // The intrinsic aspect ratio of the viewport of SVG content is necessary for example, when including SVG from an ‘object’ // element in HTML styled with CSS. It is possible (indeed, common) for an SVG graphic to have an intrinsic aspect ratio but @@ -88,33 +78,22 @@ void RenderSVGRoot::computeIntrinsicRatioInformation(FloatSize& intrinsicSize, d // - If the ‘width’ and ‘height’ of the rootmost ‘svg’ element are both specified with unit identifiers (in, mm, cm, pt, pc, // px, em, ex) or in user units, then the aspect ratio is calculated from the ‘width’ and ‘height’ attributes after // resolving both values to user units. - if (intrinsicWidthAttribute.isFixed() || intrinsicHeightAttribute.isFixed()) { - if (intrinsicWidthAttribute.isFixed()) - intrinsicSize.setWidth(floatValueForLength(intrinsicWidthAttribute, 0)); - if (intrinsicHeightAttribute.isFixed()) - intrinsicSize.setHeight(floatValueForLength(intrinsicHeightAttribute, 0)); - if (!intrinsicSize.isEmpty()) - intrinsicRatio = intrinsicSize.width() / static_cast<double>(intrinsicSize.height()); - return; - } + intrinsicSize.setWidth(floatValueForLength(svgSVGElement().intrinsicWidth(), 0)); + intrinsicSize.setHeight(floatValueForLength(svgSVGElement().intrinsicHeight(), 0)); - // - If either/both of the ‘width’ and ‘height’ of the rootmost ‘svg’ element are in percentage units (or omitted), the - // aspect ratio is calculated from the width and height values of the ‘viewBox’ specified for the current SVG document - // fragment. If the ‘viewBox’ is not correctly specified, or set to 'none', the intrinsic aspect ratio cannot be - // calculated and is considered unspecified. - intrinsicSize = svgSVGElement().viewBox().size(); - if (!intrinsicSize.isEmpty()) { - // The viewBox can only yield an intrinsic ratio, not an intrinsic size. - intrinsicRatio = intrinsicSize.width() / static_cast<double>(intrinsicSize.height()); - intrinsicSize = FloatSize(); - return; - } - // If our intrinsic size is in percentage units, return those to the caller through the intrinsicSize. Notify the caller - // about the special situation, by setting isPercentageIntrinsicSize=true, so it knows how to interpret the return values. - if (intrinsicWidthAttribute.isPercent() && intrinsicHeightAttribute.isPercent()) { - isPercentageIntrinsicSize = true; - intrinsicSize = FloatSize(intrinsicWidthAttribute.percent(), intrinsicHeightAttribute.percent()); + if (!intrinsicSize.isEmpty()) + intrinsicRatio = intrinsicSize.width() / static_cast<double>(intrinsicSize.height()); + else { + // - If either/both of the ‘width’ and ‘height’ of the rootmost ‘svg’ element are in percentage units (or omitted), the + // aspect ratio is calculated from the width and height values of the ‘viewBox’ specified for the current SVG document + // fragment. If the ‘viewBox’ is not correctly specified, or set to 'none', the intrinsic aspect ratio cannot be + // calculated and is considered unspecified. + FloatSize viewBoxSize = svgSVGElement().viewBox().size(); + if (!viewBoxSize.isEmpty()) { + // The viewBox can only yield an intrinsic ratio, not an intrinsic size. + intrinsicRatio = viewBoxSize.width() / static_cast<double>(viewBoxSize.height()); + } } } @@ -132,9 +111,9 @@ bool RenderSVGRoot::isEmbeddedThroughFrameContainingSVGDocument() const return frame().document()->isSVGDocument(); } -static inline LayoutUnit resolveLengthAttributeForSVG(const Length& length, float scale, float maxSize, RenderView* renderView) +static inline LayoutUnit resolveLengthAttributeForSVG(const Length& length, float scale, float maxSize) { - return static_cast<LayoutUnit>(valueForLength(length, maxSize, renderView) * (length.isFixed() ? scale : 1)); + return valueForLength(length, maxSize) * (length.isFixed() ? scale : 1); } LayoutUnit RenderSVGRoot::computeReplacedLogicalWidth(ShouldComputePreferred shouldComputePreferred) const @@ -143,50 +122,24 @@ LayoutUnit RenderSVGRoot::computeReplacedLogicalWidth(ShouldComputePreferred sho if (!m_containerSize.isEmpty()) return m_containerSize.width(); - if (style().logicalWidth().isSpecified() || style().logicalMaxWidth().isSpecified()) - return RenderReplaced::computeReplacedLogicalWidth(shouldComputePreferred); - - if (svgSVGElement().widthAttributeEstablishesViewport()) - return resolveLengthAttributeForSVG(svgSVGElement().intrinsicWidth(SVGSVGElement::IgnoreCSSProperties), style().effectiveZoom(), containingBlock()->availableLogicalWidth(), &view()); - - // SVG embedded through object/embed/iframe. if (isEmbeddedThroughFrameContainingSVGDocument()) - return frame().ownerRenderer()->availableLogicalWidth(); + return containingBlock()->availableLogicalWidth(); // SVG embedded via SVGImage (background-image/border-image/etc) / Inline SVG. return RenderReplaced::computeReplacedLogicalWidth(shouldComputePreferred); } -LayoutUnit RenderSVGRoot::computeReplacedLogicalHeight() const +LayoutUnit RenderSVGRoot::computeReplacedLogicalHeight(std::optional<LayoutUnit> estimatedUsedWidth) const { // When we're embedded through SVGImage (border-image/background-image/<html:img>/...) we're forced to resize to a specific size. if (!m_containerSize.isEmpty()) return m_containerSize.height(); - if (style().logicalHeight().isSpecified() || style().logicalMaxHeight().isSpecified()) - return RenderReplaced::computeReplacedLogicalHeight(); - - if (svgSVGElement().heightAttributeEstablishesViewport()) { - Length height = svgSVGElement().intrinsicHeight(SVGSVGElement::IgnoreCSSProperties); - if (height.isPercent()) { - RenderBlock* cb = containingBlock(); - ASSERT(cb); - while (cb->isAnonymous() && !cb->isRenderView()) { - cb = cb->containingBlock(); - cb->addPercentHeightDescendant(const_cast<RenderSVGRoot&>(*this)); - } - } else - RenderBlock::removePercentHeightDescendant(const_cast<RenderSVGRoot&>(*this)); - - return resolveLengthAttributeForSVG(height, style().effectiveZoom(), containingBlock()->availableLogicalHeight(IncludeMarginBorderPadding), &view()); - } - - // SVG embedded through object/embed/iframe. if (isEmbeddedThroughFrameContainingSVGDocument()) - return frame().ownerRenderer()->availableLogicalHeight(IncludeMarginBorderPadding); + return containingBlock()->availableLogicalHeight(IncludeMarginBorderPadding); // SVG embedded via SVGImage (background-image/border-image/etc) / Inline SVG. - return RenderReplaced::computeReplacedLogicalHeight(); + return RenderReplaced::computeReplacedLogicalHeight(estimatedUsedWidth); } void RenderSVGRoot::layout() @@ -197,7 +150,7 @@ void RenderSVGRoot::layout() m_resourcesNeedingToInvalidateClients.clear(); // Arbitrary affine transforms are incompatible with LayoutState. - LayoutStateDisabler layoutStateDisabler(&view()); + LayoutStateDisabler layoutStateDisabler(view()); bool needsLayout = selfNeedsLayout(); LayoutRepainter repainter(*this, checkForRepaintDuringLayout() && needsLayout); @@ -212,9 +165,10 @@ void RenderSVGRoot::layout() if (!m_resourcesNeedingToInvalidateClients.isEmpty()) { // Invalidate resource clients, which may mark some nodes for layout. - HashSet<RenderSVGResourceContainer*>::iterator end = m_resourcesNeedingToInvalidateClients.end(); - for (HashSet<RenderSVGResourceContainer*>::iterator it = m_resourcesNeedingToInvalidateClients.begin(); it != end; ++it) - (*it)->removeAllClientsFromCache(); + for (auto& resource : m_resourcesNeedingToInvalidateClients) { + resource->removeAllClientsFromCache(); + SVGResourcesCache::clientStyleChanged(*resource, StyleDifferenceLayout, resource->style()); + } m_isLayoutSizeChanged = false; SVGRenderSupport::layoutChildren(*this, false); @@ -227,21 +181,45 @@ void RenderSVGRoot::layout() m_needsBoundariesOrTransformUpdate = false; } + clearOverflow(); + if (!shouldApplyViewportClip()) { + FloatRect contentRepaintRect = repaintRectInLocalCoordinates(); + contentRepaintRect = m_localToBorderBoxTransform.mapRect(contentRepaintRect); + addVisualOverflow(enclosingLayoutRect(contentRepaintRect)); + } + updateLayerTransform(); + m_hasBoxDecorations = isDocumentElementRenderer() ? hasVisibleBoxDecorationStyle() : hasVisibleBoxDecorations(); + invalidateBackgroundObscurationStatus(); repainter.repaintAfterLayout(); clearNeedsLayout(); } +bool RenderSVGRoot::shouldApplyViewportClip() const +{ + // the outermost svg is clipped if auto, and svg document roots are always clipped + // When the svg is stand-alone (isDocumentElement() == true) the viewport clipping should always + // be applied, noting that the window scrollbars should be hidden if overflow=hidden. + return style().overflowX() == OHIDDEN + || style().overflowX() == OAUTO + || style().overflowX() == OSCROLL + || this->isDocumentElementRenderer(); +} + void RenderSVGRoot::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paintOffset) { // An empty viewport disables rendering. - if (pixelSnappedBorderBoxRect().isEmpty()) + if (borderBoxRect().isEmpty()) return; // Don't paint, if the context explicitly disabled it. - if (paintInfo.context->paintingDisabled()) + if (paintInfo.context().paintingDisabled()) + return; + + // SVG outlines are painted during PaintPhaseForeground. + if (paintInfo.phase == PaintPhaseOutline || paintInfo.phase == PaintPhaseSelfOutline) return; // An empty viewBox also disables rendering. @@ -249,34 +227,33 @@ void RenderSVGRoot::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paint if (svgSVGElement().hasEmptyViewBox()) return; - Page* page = frame().page(); - // Don't paint if we don't have kids, except if we have filters we should paint those. if (!firstChild()) { - SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(*this); + auto* resources = SVGResourcesCache::cachedResourcesForRenderer(*this); if (!resources || !resources->filter()) { - if (page && paintInfo.phase == PaintPhaseForeground) - page->addRelevantUnpaintedObject(this, visualOverflowRect()); + if (paintInfo.phase == PaintPhaseForeground) + page().addRelevantUnpaintedObject(this, visualOverflowRect()); return; } } - if (page && paintInfo.phase == PaintPhaseForeground) - page->addRelevantRepaintedObject(this, visualOverflowRect()); + if (paintInfo.phase == PaintPhaseForeground) + page().addRelevantRepaintedObject(this, visualOverflowRect()); // Make a copy of the PaintInfo because applyTransform will modify the damage rect. PaintInfo childPaintInfo(paintInfo); - childPaintInfo.context->save(); + childPaintInfo.context().save(); - // Apply initial viewport clip - not affected by overflow handling - childPaintInfo.context->clip(pixelSnappedIntRect(overflowClipRect(paintOffset, paintInfo.renderRegion))); + // Apply initial viewport clip + if (shouldApplyViewportClip()) + childPaintInfo.context().clip(snappedIntRect(overflowClipRect(paintOffset, currentRenderNamedFlowFragment()))); // Convert from container offsets (html renderers) to a relative transform (svg renderers). // Transform from our paint container's coordinate system to our local coords. IntPoint adjustedPaintOffset = roundedIntPoint(paintOffset); childPaintInfo.applyTransform(AffineTransform::translation(adjustedPaintOffset.x(), adjustedPaintOffset.y()) * localToBorderBoxTransform()); - // SVGRenderingContext must be destroyed before we restore the childPaintInfo.context, because a filter may have + // SVGRenderingContext must be destroyed before we restore the childPaintInfo.context(), because a filter may have // changed the context and it is only reverted when the SVGRenderingContext destructor finishes applying the filter. { SVGRenderingContext renderingContext; @@ -293,7 +270,7 @@ void RenderSVGRoot::paintReplaced(PaintInfo& paintInfo, const LayoutPoint& paint } } - childPaintInfo.context->restore(); + childPaintInfo.context().restore(); } void RenderSVGRoot::willBeDestroyed() @@ -304,10 +281,27 @@ void RenderSVGRoot::willBeDestroyed() RenderReplaced::willBeDestroyed(); } +void RenderSVGRoot::insertedIntoTree() +{ + RenderReplaced::insertedIntoTree(); + SVGResourcesCache::clientWasAddedToTree(*this); +} + +void RenderSVGRoot::willBeRemovedFromTree() +{ + SVGResourcesCache::clientWillBeRemovedFromTree(*this); + RenderReplaced::willBeRemovedFromTree(); +} + void RenderSVGRoot::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) { if (diff == StyleDifferenceLayout) setNeedsBoundariesUpdate(); + + // Box decorations may have appeared/disappeared - recompute status. + if (diff == StyleDifferenceRepaint) + m_hasBoxDecorations = hasVisibleBoxDecorationStyle(); + RenderReplaced::styleDidChange(diff, oldStyle); SVGResourcesCache::clientStyleChanged(*this, diff, style()); } @@ -329,10 +323,10 @@ void RenderSVGRoot::removeChild(RenderObject& child) void RenderSVGRoot::buildLocalToBorderBoxTransform() { float scale = style().effectiveZoom(); - SVGPoint translate = svgSVGElement().currentTranslate(); + FloatPoint translate = svgSVGElement().currentTranslateValue(); LayoutSize borderAndPadding(borderLeft() + paddingLeft(), borderTop() + paddingTop()); m_localToBorderBoxTransform = svgSVGElement().viewBoxToViewTransform(contentWidth() / scale, contentHeight() / scale); - if (borderAndPadding.isEmpty() && scale == 1 && translate == SVGPoint::zero()) + if (borderAndPadding.isZero() && scale == 1 && translate == FloatPoint::zero()) return; m_localToBorderBoxTransform = AffineTransform(scale, 0, 0, scale, borderAndPadding.width() + translate.x(), borderAndPadding.height() + translate.y()) * m_localToBorderBoxTransform; } @@ -350,25 +344,40 @@ const AffineTransform& RenderSVGRoot::localToParentTransform() const LayoutRect RenderSVGRoot::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const { - return SVGRenderSupport::clippedOverflowRectForRepaint(*this, repaintContainer); + if (style().visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent()) + return LayoutRect(); + + FloatRect contentRepaintRect = m_localToBorderBoxTransform.mapRect(repaintRectInLocalCoordinates()); + contentRepaintRect.intersect(snappedIntRect(borderBoxRect())); + + LayoutRect repaintRect = enclosingLayoutRect(contentRepaintRect); + if (m_hasBoxDecorations || hasRenderOverflow()) + repaintRect.unite(unionRect(localSelectionRect(false), visualOverflowRect())); + + return RenderReplaced::computeRectForRepaint(enclosingIntRect(repaintRect), repaintContainer); } -void RenderSVGRoot::computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) const +FloatRect RenderSVGRoot::computeFloatRectForRepaint(const FloatRect& repaintRect, const RenderLayerModelObject* repaintContainer, bool fixed) const { // Apply our local transforms (except for x/y translation), then our shadow, // and then call RenderBox's method to handle all the normal CSS Box model bits - repaintRect = m_localToBorderBoxTransform.mapRect(repaintRect); + FloatRect adjustedRect = m_localToBorderBoxTransform.mapRect(repaintRect); const SVGRenderStyle& svgStyle = style().svgStyle(); if (const ShadowData* shadow = svgStyle.shadow()) - shadow->adjustRectForShadow(repaintRect); + shadow->adjustRectForShadow(adjustedRect); - // Apply initial viewport clip - not affected by overflow settings - repaintRect.intersect(pixelSnappedBorderBoxRect()); + // Apply initial viewport clip + if (shouldApplyViewportClip()) + adjustedRect.intersect(snappedIntRect(borderBoxRect())); - LayoutRect rect = enclosingIntRect(repaintRect); - RenderReplaced::computeRectForRepaint(repaintContainer, rect, fixed); - repaintRect = rect; + if (m_hasBoxDecorations || hasRenderOverflow()) { + // The selectionRect can project outside of the overflowRect, so take their union + // for repainting to avoid selection painting glitches. + LayoutRect decoratedRepaintRect = unionRect(localSelectionRect(false), visualOverflowRect()); + adjustedRect.unite(decoratedRepaintRect); + } + return RenderReplaced::computeRectForRepaint(enclosingIntRect(adjustedRect), repaintContainer, {fixed, false}); } // This method expects local CSS box coordinates. @@ -391,7 +400,7 @@ void RenderSVGRoot::updateCachedBoundaries() { SVGRenderSupport::computeContainerBoundingBoxes(*this, m_objectBoundingBox, m_objectBoundingBoxValid, m_strokeBoundingBox, m_repaintBoundingBoxExcludingShadow); SVGRenderSupport::intersectRepaintRectWithResources(*this, m_repaintBoundingBoxExcludingShadow); - m_repaintBoundingBoxExcludingShadow.inflate(borderAndPaddingWidth()); + m_repaintBoundingBoxExcludingShadow.inflate(horizontalBorderAndPaddingExtent()); m_repaintBoundingBox = m_repaintBoundingBoxExcludingShadow; SVGRenderSupport::intersectRepaintRectWithShadows(*this, m_repaintBoundingBox); @@ -405,7 +414,7 @@ bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& re // Only test SVG content if the point is in our content box. // FIXME: This should be an intersection when rect-based hit tests are supported by nodeAtFloatPoint. if (contentBoxRect().contains(pointInBorderBox)) { - FloatPoint localPoint = localToParentTransform().inverse().mapPoint(FloatPoint(pointInParent)); + FloatPoint localPoint = localToParentTransform().inverse().value_or(AffineTransform()).mapPoint(FloatPoint(pointInParent)); for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { // FIXME: nodeAtFloatPoint() doesn't handle rect-based hit tests yet. @@ -418,7 +427,7 @@ bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& re } // If we didn't early exit above, we've just hit the container <svg> element. Unlike SVG 1.1, 2nd Edition allows container elements to be hit. - if (hitTestAction == HitTestBlockBackground && visibleToHitTesting()) { + if ((hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) && visibleToHitTesting()) { // Only return true here, if the last hit testing phase 'BlockBackground' is executed. If we'd return true in the 'Foreground' phase, // hit testing would stop immediately. For SVG only trees this doesn't matter. Though when we have a <foreignObject> subtree we need // to be able to detect hits on the background of a <div> element. If we'd return true here in the 'Foreground' phase, we are not able @@ -436,29 +445,15 @@ bool RenderSVGRoot::nodeAtPoint(const HitTestRequest& request, HitTestResult& re bool RenderSVGRoot::hasRelativeDimensions() const { - return svgSVGElement().intrinsicHeight(SVGSVGElement::IgnoreCSSProperties).isPercent() || svgSVGElement().intrinsicWidth(SVGSVGElement::IgnoreCSSProperties).isPercent(); -} - -bool RenderSVGRoot::hasRelativeIntrinsicLogicalWidth() const -{ - return svgSVGElement().intrinsicWidth(SVGSVGElement::IgnoreCSSProperties).isPercent(); -} - -bool RenderSVGRoot::hasRelativeLogicalHeight() const -{ - return svgSVGElement().intrinsicHeight(SVGSVGElement::IgnoreCSSProperties).isPercent(); + return svgSVGElement().intrinsicHeight().isPercentOrCalculated() || svgSVGElement().intrinsicWidth().isPercentOrCalculated(); } void RenderSVGRoot::addResourceForClientInvalidation(RenderSVGResourceContainer* resource) { - RenderObject* svgRoot = resource->parent(); - while (svgRoot && !svgRoot->isSVGRoot()) - svgRoot = svgRoot->parent(); + RenderSVGRoot* svgRoot = SVGRenderSupport::findTreeRootObject(*resource); if (!svgRoot) return; - toRenderSVGRoot(svgRoot)->m_resourcesNeedingToInvalidateClients.add(resource); + svgRoot->m_resourcesNeedingToInvalidateClients.add(resource); } } - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGRoot.h b/Source/WebCore/rendering/svg/RenderSVGRoot.h index edebf1cf8..ecff184fa 100644 --- a/Source/WebCore/rendering/svg/RenderSVGRoot.h +++ b/Source/WebCore/rendering/svg/RenderSVGRoot.h @@ -20,23 +20,21 @@ * Boston, MA 02110-1301, USA. */ -#ifndef RenderSVGRoot_h -#define RenderSVGRoot_h +#pragma once -#if ENABLE(SVG) #include "FloatRect.h" #include "RenderReplaced.h" - #include "SVGRenderSupport.h" namespace WebCore { class AffineTransform; +class RenderSVGResourceContainer; class SVGSVGElement; class RenderSVGRoot final : public RenderReplaced { public: - RenderSVGRoot(SVGSVGElement&, PassRef<RenderStyle>); + RenderSVGRoot(SVGSVGElement&, RenderStyle&&); virtual ~RenderSVGRoot(); SVGSVGElement& svgSVGElement() const; @@ -44,19 +42,17 @@ public: bool isEmbeddedThroughSVGImage() const; bool isEmbeddedThroughFrameContainingSVGDocument() const; - virtual void computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio, bool& isPercentageIntrinsicSize) const override; + void computeIntrinsicRatioInformation(FloatSize& intrinsicSize, double& intrinsicRatio) const override; bool isLayoutSizeChanged() const { return m_isLayoutSizeChanged; } - virtual void setNeedsBoundariesUpdate() override { m_needsBoundariesOrTransformUpdate = true; } - virtual bool needsBoundariesUpdate() override { return m_needsBoundariesOrTransformUpdate; } - virtual void setNeedsTransformUpdate() override { m_needsBoundariesOrTransformUpdate = true; } + void setNeedsBoundariesUpdate() override { m_needsBoundariesOrTransformUpdate = true; } + bool needsBoundariesUpdate() override { return m_needsBoundariesOrTransformUpdate; } + void setNeedsTransformUpdate() override { m_needsBoundariesOrTransformUpdate = true; } IntSize containerSize() const { return m_containerSize; } void setContainerSize(const IntSize& containerSize) { m_containerSize = containerSize; } - virtual bool hasRelativeDimensions() const override; - virtual bool hasRelativeIntrinsicLogicalWidth() const override; - virtual bool hasRelativeLogicalHeight() const override; + bool hasRelativeDimensions() const override; // localToBorderBoxTransform maps local SVG viewport coordinates to local CSS box coordinates. const AffineTransform& localToBorderBoxTransform() const { return m_localToBorderBoxTransform; } @@ -71,40 +67,45 @@ public: private: void element() const = delete; - virtual bool isSVGRoot() const override { return true; } - virtual const char* renderName() const override { return "RenderSVGRoot"; } + bool isSVGRoot() const override { return true; } + const char* renderName() const override { return "RenderSVGRoot"; } + + LayoutUnit computeReplacedLogicalWidth(ShouldComputePreferred = ComputeActual) const override; + LayoutUnit computeReplacedLogicalHeight(std::optional<LayoutUnit> estimatedUsedWidth = std::nullopt) const override; + void layout() override; + void paintReplaced(PaintInfo&, const LayoutPoint&) override; - virtual LayoutUnit computeReplacedLogicalWidth(ShouldComputePreferred = ComputeActual) const override; - virtual LayoutUnit computeReplacedLogicalHeight() const override; - virtual void layout() override; - virtual void paintReplaced(PaintInfo&, const LayoutPoint&) override; + void willBeDestroyed() override; - virtual void willBeDestroyed() override; - virtual void styleDidChange(StyleDifference, const RenderStyle* oldStyle) override; - virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0) override; - virtual void removeChild(RenderObject&) override; + void insertedIntoTree() override; + void willBeRemovedFromTree() override; - virtual const AffineTransform& localToParentTransform() const override; + void styleDidChange(StyleDifference, const RenderStyle* oldStyle) override; + void addChild(RenderObject* child, RenderObject* beforeChild = 0) override; + void removeChild(RenderObject&) override; + + const AffineTransform& localToParentTransform() const override; bool fillContains(const FloatPoint&) const; bool strokeContains(const FloatPoint&) const; - virtual FloatRect objectBoundingBox() const override { return m_objectBoundingBox; } - virtual FloatRect strokeBoundingBox() const override { return m_strokeBoundingBox; } - virtual FloatRect repaintRectInLocalCoordinates() const override { return m_repaintBoundingBox; } - virtual FloatRect repaintRectInLocalCoordinatesExcludingSVGShadow() const { return m_repaintBoundingBoxExcludingShadow; } + FloatRect objectBoundingBox() const override { return m_objectBoundingBox; } + FloatRect strokeBoundingBox() const override { return m_strokeBoundingBox; } + FloatRect repaintRectInLocalCoordinates() const override { return m_repaintBoundingBox; } + FloatRect repaintRectInLocalCoordinatesExcludingSVGShadow() const { return m_repaintBoundingBoxExcludingShadow; } - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) override; + bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) override; - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const override; - virtual void computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) const override; + LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const override; + FloatRect computeFloatRectForRepaint(const FloatRect&, const RenderLayerModelObject* repaintContainer, bool fixed) const override; - virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const override; - virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const override; + void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags, bool* wasFixed) const override; + const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const override; - virtual bool canBeSelectionLeaf() const override { return false; } - virtual bool canHaveChildren() const override { return true; } + bool canBeSelectionLeaf() const override { return false; } + bool canHaveChildren() const override { return true; } + bool shouldApplyViewportClip() const; void updateCachedBoundaries(); void buildLocalToBorderBoxTransform(); @@ -120,12 +121,9 @@ private: bool m_isLayoutSizeChanged : 1; bool m_needsBoundariesOrTransformUpdate : 1; bool m_hasSVGShadow : 1; + bool m_hasBoxDecorations : 1; }; -template<> inline bool isRendererOfType<const RenderSVGRoot>(const RenderObject& renderer) { return renderer.isSVGRoot(); } -RENDER_OBJECT_TYPE_CASTS(RenderSVGRoot, isSVGRoot()) - } // namespace WebCore -#endif // ENABLE(SVG) -#endif // RenderSVGRoot_h +SPECIALIZE_TYPE_TRAITS_RENDER_OBJECT(RenderSVGRoot, isSVGRoot()) diff --git a/Source/WebCore/rendering/svg/RenderSVGShape.cpp b/Source/WebCore/rendering/svg/RenderSVGShape.cpp index b93a028b5..d46734084 100644 --- a/Source/WebCore/rendering/svg/RenderSVGShape.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGShape.cpp @@ -26,8 +26,6 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGShape.h" #include "FloatPoint.h" @@ -42,7 +40,6 @@ #include "SVGRenderingContext.h" #include "SVGResources.h" #include "SVGResourcesCache.h" -#include "SVGTransformList.h" #include "SVGURIReference.h" #include "StrokeStyleApplier.h" #include <wtf/StackStats.h> @@ -56,7 +53,7 @@ public: { } - virtual void strokeStyle(GraphicsContext* context) override + void strokeStyle(GraphicsContext* context) override { SVGRenderSupport::applyStrokeStyleToContext(context, m_renderer.style(), m_renderer); } @@ -65,8 +62,8 @@ private: const RenderSVGShape& m_renderer; }; -RenderSVGShape::RenderSVGShape(SVGGraphicsElement& element, PassRef<RenderStyle> style) - : RenderSVGModelObject(element, std::move(style)) +RenderSVGShape::RenderSVGShape(SVGGraphicsElement& element, RenderStyle&& style) + : RenderSVGModelObject(element, WTFMove(style)) , m_needsBoundariesUpdate(false) // Default is false, the cached rects are empty from the beginning. , m_needsShapeUpdate(true) // Default is true, so we grab a Path object once from SVGGraphicsElement. , m_needsTransformUpdate(true) // Default is true, so we grab a AffineTransform object once from SVGGraphicsElement. @@ -79,8 +76,7 @@ RenderSVGShape::~RenderSVGShape() void RenderSVGShape::updateShapeFromElement() { - m_path.clear(); - m_path = adoptPtr(new Path); + m_path = std::make_unique<Path>(); ASSERT(RenderSVGShape::isEmpty()); updatePathFromGraphicsElement(&graphicsElement(), path()); @@ -92,15 +88,19 @@ void RenderSVGShape::updateShapeFromElement() bool RenderSVGShape::isEmpty() const { - return path().isEmpty(); + // This function should never be called before assigning a new Path to m_path. + // But this bug can happen if this renderer was created and its layout was not + // done before painting. Assert this did not happen but do not crash. + ASSERT(hasPath()); + return !hasPath() || path().isEmpty(); } -void RenderSVGShape::fillShape(GraphicsContext* context) const +void RenderSVGShape::fillShape(GraphicsContext& context) const { - context->fillPath(path()); + context.fillPath(path()); } -void RenderSVGShape::strokeShape(GraphicsContext* context) const +void RenderSVGShape::strokeShape(GraphicsContext& context) const { ASSERT(m_path); Path* usePath = m_path.get(); @@ -108,7 +108,7 @@ void RenderSVGShape::strokeShape(GraphicsContext* context) const if (hasNonScalingStroke()) usePath = nonScalingStrokePath(usePath, nonScalingStrokeTransform()); - context->strokePath(*usePath); + context.strokePath(*usePath); } bool RenderSVGShape::shapeDependentStrokeContains(const FloatPoint& point) @@ -190,21 +190,22 @@ void RenderSVGShape::layout() Path* RenderSVGShape::nonScalingStrokePath(const Path* path, const AffineTransform& strokeTransform) const { - DEFINE_STATIC_LOCAL(Path, tempPath, ()); + static NeverDestroyed<Path> tempPath; - tempPath = *path; - tempPath.transform(strokeTransform); + tempPath.get() = *path; + tempPath.get().transform(strokeTransform); - return &tempPath; + return &tempPath.get(); } bool RenderSVGShape::setupNonScalingStrokeContext(AffineTransform& strokeTransform, GraphicsContextStateSaver& stateSaver) { - if (!strokeTransform.isInvertible()) + std::optional<AffineTransform> inverse = strokeTransform.inverse(); + if (!inverse) return false; stateSaver.save(); - stateSaver.context()->concatCTM(strokeTransform.inverse()); + stateSaver.context()->concatCTM(inverse.value()); return true; } @@ -221,15 +222,16 @@ bool RenderSVGShape::shouldGenerateMarkerPositions() const if (!graphicsElement().supportsMarkers()) return false; - SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(*this); + auto* resources = SVGResourcesCache::cachedResourcesForRenderer(*this); if (!resources) return false; return resources->markerStart() || resources->markerMid() || resources->markerEnd(); } -void RenderSVGShape::fillShape(const RenderStyle& style, GraphicsContext* context) +void RenderSVGShape::fillShape(const RenderStyle& style, GraphicsContext& originalContext) { + GraphicsContext* context = &originalContext; Color fallbackColor; if (RenderSVGResource* fillPaintingResource = RenderSVGResource::fillPaintingResource(*this, style, fallbackColor)) { if (fillPaintingResource->applyResource(*this, style, context, ApplyToFillMode)) @@ -243,8 +245,9 @@ void RenderSVGShape::fillShape(const RenderStyle& style, GraphicsContext* contex } } -void RenderSVGShape::strokeShape(const RenderStyle& style, GraphicsContext* context) +void RenderSVGShape::strokeShape(const RenderStyle& style, GraphicsContext& originalContext) { + GraphicsContext* context = &originalContext; Color fallbackColor; if (RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintingResource(*this, style, fallbackColor)) { if (strokePaintingResource->applyResource(*this, style, context, ApplyToStrokeMode)) @@ -258,62 +261,73 @@ void RenderSVGShape::strokeShape(const RenderStyle& style, GraphicsContext* cont } } -void RenderSVGShape::fillAndStrokeShape(GraphicsContext* context) +void RenderSVGShape::strokeShape(GraphicsContext& context) { - fillShape(style(), context); - - if (!style().svgStyle().hasVisibleStroke()) + if (!style().hasVisibleStroke()) return; - GraphicsContextStateSaver stateSaver(*context, false); - + GraphicsContextStateSaver stateSaver(context, false); if (hasNonScalingStroke()) { AffineTransform nonScalingTransform = nonScalingStrokeTransform(); if (!setupNonScalingStrokeContext(nonScalingTransform, stateSaver)) return; } - strokeShape(style(), context); } +void RenderSVGShape::fillStrokeMarkers(PaintInfo& childPaintInfo) +{ + auto paintOrder = style().paintTypesForPaintOrder(); + for (unsigned i = 0; i < paintOrder.size(); ++i) { + switch (paintOrder.at(i)) { + case PaintTypeFill: + fillShape(style(), childPaintInfo.context()); + break; + case PaintTypeStroke: + strokeShape(childPaintInfo.context()); + break; + case PaintTypeMarkers: + if (!m_markerPositions.isEmpty()) + drawMarkers(childPaintInfo); + break; + } + } +} + void RenderSVGShape::paint(PaintInfo& paintInfo, const LayoutPoint&) { - if (paintInfo.context->paintingDisabled() || style().visibility() == HIDDEN || isEmpty()) + if (paintInfo.context().paintingDisabled() || paintInfo.phase != PaintPhaseForeground + || style().visibility() == HIDDEN || isEmpty()) return; FloatRect boundingBox = repaintRectInLocalCoordinates(); if (!SVGRenderSupport::paintInfoIntersectsRepaintRect(boundingBox, m_localTransform, paintInfo)) return; PaintInfo childPaintInfo(paintInfo); - bool drawsOutline = style().outlineWidth() && (childPaintInfo.phase == PaintPhaseOutline || childPaintInfo.phase == PaintPhaseSelfOutline); - if (drawsOutline || childPaintInfo.phase == PaintPhaseForeground) { - GraphicsContextStateSaver stateSaver(*childPaintInfo.context); - childPaintInfo.applyTransform(m_localTransform); - - if (childPaintInfo.phase == PaintPhaseForeground) { - SVGRenderingContext renderingContext(*this, childPaintInfo); - - if (renderingContext.isRenderingPrepared()) { - const SVGRenderStyle& svgStyle = style().svgStyle(); - if (svgStyle.shapeRendering() == SR_CRISPEDGES) - childPaintInfo.context->setShouldAntialias(false); - - fillAndStrokeShape(childPaintInfo.context); - if (!m_markerPositions.isEmpty()) - drawMarkers(childPaintInfo); - } - } + GraphicsContextStateSaver stateSaver(childPaintInfo.context()); + childPaintInfo.applyTransform(m_localTransform); + + if (childPaintInfo.phase == PaintPhaseForeground) { + SVGRenderingContext renderingContext(*this, childPaintInfo); - if (drawsOutline) - paintOutline(childPaintInfo, IntRect(boundingBox)); + if (renderingContext.isRenderingPrepared()) { + const SVGRenderStyle& svgStyle = style().svgStyle(); + if (svgStyle.shapeRendering() == SR_CRISPEDGES) + childPaintInfo.context().setShouldAntialias(false); + + fillStrokeMarkers(childPaintInfo); + } } + + if (style().outlineWidth()) + paintOutline(childPaintInfo, IntRect(boundingBox)); } // This method is called from inside paintOutline() since we call paintOutline() // while transformed to our coord system, return local coords -void RenderSVGShape::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint&, const RenderLayerModelObject*) +void RenderSVGShape::addFocusRingRects(Vector<LayoutRect>& rects, const LayoutPoint&, const RenderLayerModelObject*) { - IntRect rect = enclosingIntRect(repaintRectInLocalCoordinates()); + LayoutRect rect = LayoutRect(repaintRectInLocalCoordinates()); if (!rect.isEmpty()) rects.append(rect); } @@ -324,7 +338,7 @@ bool RenderSVGShape::nodeAtFloatPoint(const HitTestRequest& request, HitTestResu if (hitTestAction != HitTestForeground) return false; - FloatPoint localPoint = m_localTransform.inverse().mapPoint(pointInParent); + FloatPoint localPoint = m_localTransform.inverse().value_or(AffineTransform()).mapPoint(pointInParent); if (!SVGRenderSupport::pointInClippingArea(*this, localPoint)) return false; @@ -338,7 +352,7 @@ bool RenderSVGShape::nodeAtFloatPoint(const HitTestRequest& request, HitTestResu fillRule = svgStyle.clipRule(); if ((hitRules.canHitStroke && (svgStyle.hasStroke() || !hitRules.requireStroke) && strokeContains(localPoint, hitRules.requireStroke)) || (hitRules.canHitFill && (svgStyle.hasFill() || !hitRules.requireFill) && fillContains(localPoint, hitRules.requireFill, fillRule))) { - updateHitTestResult(result, roundedLayoutPoint(localPoint)); + updateHitTestResult(result, LayoutPoint(localPoint)); return true; } } @@ -364,7 +378,7 @@ FloatRect RenderSVGShape::markerRect(float strokeWidth) const { ASSERT(!m_markerPositions.isEmpty()); - SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(*this); + auto* resources = SVGResourcesCache::cachedResourcesForRenderer(*this); ASSERT(resources); RenderSVGResourceMarker* markerStart = resources->markerStart(); @@ -396,10 +410,10 @@ FloatRect RenderSVGShape::calculateStrokeBoundingBox() const BoundingRectStrokeStyleApplier strokeStyle(*this); if (hasNonScalingStroke()) { AffineTransform nonScalingTransform = nonScalingStrokeTransform(); - if (nonScalingTransform.isInvertible()) { + if (std::optional<AffineTransform> inverse = nonScalingTransform.inverse()) { Path* usePath = nonScalingStrokePath(m_path.get(), nonScalingTransform); FloatRect strokeBoundingRect = usePath->strokeBoundingRect(&strokeStyle); - strokeBoundingRect = nonScalingTransform.inverse().mapRect(strokeBoundingRect); + strokeBoundingRect = inverse.value().mapRect(strokeBoundingRect); strokeBoundingBox.unite(strokeBoundingRect); } } else @@ -424,7 +438,7 @@ void RenderSVGShape::updateRepaintBoundingBox() float RenderSVGShape::strokeWidth() const { SVGLengthContext lengthContext(&graphicsElement()); - return style().svgStyle().strokeWidth().value(lengthContext); + return lengthContext.valueForLength(style().strokeWidth()); } bool RenderSVGShape::hasSmoothStroke() const @@ -432,15 +446,15 @@ bool RenderSVGShape::hasSmoothStroke() const const SVGRenderStyle& svgStyle = style().svgStyle(); return svgStyle.strokeDashArray().isEmpty() && svgStyle.strokeMiterLimit() == svgStyle.initialStrokeMiterLimit() - && svgStyle.joinStyle() == svgStyle.initialJoinStyle() - && svgStyle.capStyle() == svgStyle.initialCapStyle(); + && style().joinStyle() == style().initialJoinStyle() + && style().capStyle() == style().initialCapStyle(); } void RenderSVGShape::drawMarkers(PaintInfo& paintInfo) { ASSERT(!m_markerPositions.isEmpty()); - SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(*this); + auto* resources = SVGResourcesCache::cachedResourcesForRenderer(*this); if (!resources) return; @@ -467,11 +481,11 @@ void RenderSVGShape::processMarkerPositions() ASSERT(m_path); - SVGMarkerData markerData(m_markerPositions); - m_path->apply(&markerData, SVGMarkerData::updateFromPathElement); + SVGMarkerData markerData(m_markerPositions, SVGResourcesCache::cachedResourcesForRenderer(*this)->markerReverseStart()); + m_path->apply([&markerData](const PathElement& pathElement) { + SVGMarkerData::updateFromPathElement(markerData, pathElement); + }); markerData.pathIsDone(); } } - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGShape.h b/Source/WebCore/rendering/svg/RenderSVGShape.h index e27b4b42f..f1db416e4 100644 --- a/Source/WebCore/rendering/svg/RenderSVGShape.h +++ b/Source/WebCore/rendering/svg/RenderSVGShape.h @@ -2,7 +2,7 @@ * Copyright (C) 2004, 2005, 2007 Nikolas Zimmermann <zimmermann@kde.org> * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org> * Copyright (C) 2005 Eric Seidel <eric@webkit.org> - * Copyright (C) 2006 Apple Computer, Inc + * Copyright (C) 2006 Apple Inc. * Copyright (C) 2009 Google, Inc. * Copyright (C) 2011 Renata Hodovan <reni@webkit.org> * Copyright (C) 2011 University of Szeged @@ -23,16 +23,14 @@ * Boston, MA 02110-1301, USA. */ -#ifndef RenderSVGShape_h -#define RenderSVGShape_h +#pragma once -#if ENABLE(SVG) #include "AffineTransform.h" #include "FloatRect.h" #include "RenderSVGModelObject.h" #include "SVGGraphicsElement.h" #include "SVGMarkerData.h" -#include <wtf/OwnPtr.h> +#include <memory> #include <wtf/Vector.h> namespace WebCore { @@ -46,18 +44,18 @@ class SVGGraphicsElement; class RenderSVGShape : public RenderSVGModelObject { public: - RenderSVGShape(SVGGraphicsElement&, PassRef<RenderStyle>); - RenderSVGShape(SVGGraphicsElement&, PassRef<RenderStyle>, Path*, bool); + RenderSVGShape(SVGGraphicsElement&, RenderStyle&&); virtual ~RenderSVGShape(); - SVGGraphicsElement& graphicsElement() const { return toSVGGraphicsElement(RenderSVGModelObject::element()); } + SVGGraphicsElement& graphicsElement() const { return downcast<SVGGraphicsElement>(RenderSVGModelObject::element()); } void setNeedsShapeUpdate() { m_needsShapeUpdate = true; } - virtual void setNeedsBoundariesUpdate() override final { m_needsBoundariesUpdate = true; } - virtual bool needsBoundariesUpdate() override final { return m_needsBoundariesUpdate; } - virtual void setNeedsTransformUpdate() override final { m_needsTransformUpdate = true; } - virtual void fillShape(GraphicsContext*) const; - virtual void strokeShape(GraphicsContext*) const; + void setNeedsBoundariesUpdate() final { m_needsBoundariesUpdate = true; } + bool needsBoundariesUpdate() final { return m_needsBoundariesUpdate; } + void setNeedsTransformUpdate() final { m_needsTransformUpdate = true; } + virtual void fillShape(GraphicsContext&) const; + virtual void strokeShape(GraphicsContext&) const; + virtual bool isRenderingDisabled() const = 0; bool hasPath() const { return m_path.get(); } Path& path() const @@ -70,7 +68,7 @@ protected: void element() const = delete; virtual void updateShapeFromElement(); - virtual bool isEmpty() const override; + virtual bool isEmpty() const; virtual bool shapeDependentStrokeContains(const FloatPoint&); virtual bool shapeDependentFillContains(const FloatPoint&, const WindRule) const; float strokeWidth() const; @@ -88,23 +86,23 @@ private: bool fillContains(const FloatPoint&, bool requiresFill = true, const WindRule fillRule = RULE_NONZERO); bool strokeContains(const FloatPoint&, bool requiresStroke = true); - virtual FloatRect repaintRectInLocalCoordinates() const override final { return m_repaintBoundingBox; } - virtual FloatRect repaintRectInLocalCoordinatesExcludingSVGShadow() const override final { return m_repaintBoundingBoxExcludingShadow; } - virtual const AffineTransform& localToParentTransform() const override final { return m_localTransform; } - virtual AffineTransform localTransform() const override final { return m_localTransform; } + FloatRect repaintRectInLocalCoordinates() const final { return m_repaintBoundingBox; } + FloatRect repaintRectInLocalCoordinatesExcludingSVGShadow() const final { return m_repaintBoundingBoxExcludingShadow; } + const AffineTransform& localToParentTransform() const final { return m_localTransform; } + AffineTransform localTransform() const final { return m_localTransform; } - virtual bool isSVGShape() const override final { return true; } - virtual bool canHaveChildren() const override final { return false; } - virtual const char* renderName() const override { return "RenderSVGShape"; } + bool isSVGShape() const final { return true; } + bool canHaveChildren() const final { return false; } + const char* renderName() const override { return "RenderSVGShape"; } - virtual void layout() override final; - virtual void paint(PaintInfo&, const LayoutPoint&) override final; - virtual void addFocusRingRects(Vector<IntRect>&, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer = 0) override final; + void layout() final; + void paint(PaintInfo&, const LayoutPoint&) final; + void addFocusRingRects(Vector<LayoutRect>&, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer = 0) final; - virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction) override final; + bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction) final; - virtual FloatRect objectBoundingBox() const override final { return m_fillBoundingBox; } - virtual FloatRect strokeBoundingBox() const override final { return m_strokeBoundingBox; } + FloatRect objectBoundingBox() const final { return m_fillBoundingBox; } + FloatRect strokeBoundingBox() const final { return m_strokeBoundingBox; } FloatRect calculateObjectBoundingBox() const; FloatRect calculateStrokeBoundingBox() const; void updateRepaintBoundingBox(); @@ -115,16 +113,17 @@ private: FloatRect markerRect(float strokeWidth) const; void processMarkerPositions(); - void fillShape(const RenderStyle&, GraphicsContext*); - void strokeShape(const RenderStyle&, GraphicsContext*); - void fillAndStrokeShape(GraphicsContext*); + void fillShape(const RenderStyle&, GraphicsContext&); + void strokeShape(const RenderStyle&, GraphicsContext&); + void strokeShape(GraphicsContext&); + void fillStrokeMarkers(PaintInfo&); void drawMarkers(PaintInfo&); private: FloatRect m_repaintBoundingBox; FloatRect m_repaintBoundingBoxExcludingShadow; AffineTransform m_localTransform; - OwnPtr<Path> m_path; + std::unique_ptr<Path> m_path; Vector<MarkerPosition> m_markerPositions; bool m_needsBoundariesUpdate : 1; @@ -132,9 +131,6 @@ private: bool m_needsTransformUpdate : 1; }; -RENDER_OBJECT_TYPE_CASTS(RenderSVGShape, isSVGShape()) +} // namespace WebCore -} - -#endif // ENABLE(SVG) -#endif +SPECIALIZE_TYPE_TRAITS_RENDER_OBJECT(RenderSVGShape, isSVGShape()) diff --git a/Source/WebCore/rendering/svg/RenderSVGTSpan.h b/Source/WebCore/rendering/svg/RenderSVGTSpan.h index bdd33bbb0..fd75d1525 100644 --- a/Source/WebCore/rendering/svg/RenderSVGTSpan.h +++ b/Source/WebCore/rendering/svg/RenderSVGTSpan.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz> - * Copyright (C) 2006 Apple Computer Inc. + * Copyright (C) 2006 Apple Inc. * Copyright (C) 2009 Google Inc. * * This library is free software; you can redistribute it and/or @@ -19,18 +19,17 @@ * Boston, MA 02110-1301, USA. */ -#ifndef RenderSVGTSpan_h -#define RenderSVGTSpan_h +#pragma once -#if ENABLE(SVG) #include "RenderSVGInline.h" #include "SVGTextPositioningElement.h" namespace WebCore { + class RenderSVGTSpan final : public RenderSVGInline { public: - explicit RenderSVGTSpan(SVGTextPositioningElement& element, PassRef<RenderStyle> style) - : RenderSVGInline(element, std::move(style)) + explicit RenderSVGTSpan(SVGTextPositioningElement& element, RenderStyle&& style) + : RenderSVGInline(element, WTFMove(style)) { } @@ -38,9 +37,10 @@ public: private: void graphicsElement() const = delete; - virtual const char* renderName() const { return "RenderSVGTSpan"; } + const char* renderName() const override { return "RenderSVGTSpan"; } + bool isSVGTSpan() const override { return true; } }; -} -#endif // ENABLE(SVG) -#endif // !RenderSVGTSpan_h +} // namespace WebCore + +SPECIALIZE_TYPE_TRAITS_RENDER_OBJECT(RenderSVGTSpan, isSVGTSpan()) diff --git a/Source/WebCore/rendering/svg/RenderSVGText.cpp b/Source/WebCore/rendering/svg/RenderSVGText.cpp index 22c1cdaab..8f3b60f0d 100644 --- a/Source/WebCore/rendering/svg/RenderSVGText.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGText.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006 Apple Inc. * Copyright (C) 2006 Alexander Kellett <lypanov@kde.org> * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz> * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> @@ -25,17 +25,17 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGText.h" #include "FloatQuad.h" -#include "FontCache.h" +#include "Font.h" #include "GraphicsContext.h" #include "HitTestRequest.h" #include "HitTestResult.h" #include "LayoutRepainter.h" #include "PointerEventsHitRules.h" +#include "RenderIterator.h" +#include "RenderSVGInline.h" #include "RenderSVGInlineText.h" #include "RenderSVGResource.h" #include "RenderSVGRoot.h" @@ -43,18 +43,15 @@ #include "SVGResourcesCache.h" #include "SVGRootInlineBox.h" #include "SVGTextElement.h" -#include "SVGTextRunRenderingContext.h" -#include "SVGTransformList.h" #include "SVGURIReference.h" -#include "SimpleFontData.h" #include "TransformState.h" #include "VisiblePosition.h" #include <wtf/StackStats.h> namespace WebCore { -RenderSVGText::RenderSVGText(SVGTextElement& element, PassRef<RenderStyle> style) - : RenderSVGBlock(element, std::move(style)) +RenderSVGText::RenderSVGText(SVGTextElement& element, RenderStyle&& style) + : RenderSVGBlock(element, WTFMove(style)) , m_needsReordering(false) , m_needsPositioningValuesUpdate(false) , m_needsTransformUpdate(true) @@ -69,7 +66,7 @@ RenderSVGText::~RenderSVGText() SVGTextElement& RenderSVGText::textElement() const { - return toSVGTextElement(RenderSVGBlock::graphicsElement()); + return downcast<SVGTextElement>(RenderSVGBlock::graphicsElement()); } bool RenderSVGText::isChildAllowed(const RenderObject& child, const RenderStyle&) const @@ -77,24 +74,14 @@ bool RenderSVGText::isChildAllowed(const RenderObject& child, const RenderStyle& return child.isInline(); } -RenderSVGText* RenderSVGText::locateRenderSVGTextAncestor(RenderObject* start) +RenderSVGText* RenderSVGText::locateRenderSVGTextAncestor(RenderObject& start) { - ASSERT(start); - while (start && !start->isSVGText()) - start = start->parent(); - if (!start || !start->isSVGText()) - return 0; - return toRenderSVGText(start); + return lineageOfType<RenderSVGText>(start).first(); } -const RenderSVGText* RenderSVGText::locateRenderSVGTextAncestor(const RenderObject* start) +const RenderSVGText* RenderSVGText::locateRenderSVGTextAncestor(const RenderObject& start) { - ASSERT(start); - while (start && !start->isSVGText()) - start = start->parent(); - if (!start || !start->isSVGText()) - return 0; - return toRenderSVGText(start); + return lineageOfType<RenderSVGText>(start).first(); } LayoutRect RenderSVGText::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const @@ -102,16 +89,14 @@ LayoutRect RenderSVGText::clippedOverflowRectForRepaint(const RenderLayerModelOb return SVGRenderSupport::clippedOverflowRectForRepaint(*this, repaintContainer); } -void RenderSVGText::computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect& rect, bool fixed) const +LayoutRect RenderSVGText::computeRectForRepaint(const LayoutRect& rect, const RenderLayerModelObject* repaintContainer, RepaintContext context) const { - FloatRect repaintRect = rect; - computeFloatRectForRepaint(repaintContainer, repaintRect, fixed); - rect = enclosingLayoutRect(repaintRect); + return enclosingLayoutRect(computeFloatRectForRepaint(rect, repaintContainer, context.m_hasPositionFixedDescendant)); } -void RenderSVGText::computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) const +FloatRect RenderSVGText::computeFloatRectForRepaint(const FloatRect& repaintRect, const RenderLayerModelObject* repaintContainer, bool fixed) const { - SVGRenderSupport::computeFloatRectForRepaint(*this, repaintContainer, repaintRect, fixed); + return SVGRenderSupport::computeFloatRectForRepaint(*this, repaintRect, repaintContainer, fixed); } void RenderSVGText::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags, bool* wasFixed) const @@ -127,26 +112,25 @@ const RenderObject* RenderSVGText::pushMappingToContainer(const RenderLayerModel static inline void collectLayoutAttributes(RenderObject* text, Vector<SVGTextLayoutAttributes*>& attributes) { for (RenderObject* descendant = text; descendant; descendant = descendant->nextInPreOrder(text)) { - if (descendant->isSVGInlineText()) - attributes.append(toRenderSVGInlineText(descendant)->layoutAttributes()); + if (is<RenderSVGInlineText>(*descendant)) + attributes.append(downcast<RenderSVGInlineText>(*descendant).layoutAttributes()); } } -static inline bool findPreviousAndNextAttributes(RenderElement* start, RenderSVGInlineText* locateElement, bool& stopAfterNext, SVGTextLayoutAttributes*& previous, SVGTextLayoutAttributes*& next) +static inline bool findPreviousAndNextAttributes(RenderElement& start, RenderSVGInlineText* locateElement, bool& stopAfterNext, SVGTextLayoutAttributes*& previous, SVGTextLayoutAttributes*& next) { - ASSERT(start); ASSERT(locateElement); // FIXME: Make this iterative. - for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) { - if (child->isSVGInlineText()) { - RenderSVGInlineText* text = toRenderSVGInlineText(child); - if (locateElement != text) { + for (auto& child : childrenOfType<RenderObject>(start)) { + if (is<RenderSVGInlineText>(child)) { + auto& text = downcast<RenderSVGInlineText>(child); + if (locateElement != &text) { if (stopAfterNext) { - next = text->layoutAttributes(); + next = text.layoutAttributes(); return true; } - previous = text->layoutAttributes(); + previous = text.layoutAttributes(); continue; } @@ -154,10 +138,10 @@ static inline bool findPreviousAndNextAttributes(RenderElement* start, RenderSVG continue; } - if (!child->isSVGInline()) + if (!is<RenderSVGInline>(child)) continue; - if (findPreviousAndNextAttributes(toRenderElement(child), locateElement, stopAfterNext, previous, next)) + if (findPreviousAndNextAttributes(downcast<RenderElement>(child), locateElement, stopAfterNext, previous, next)) return true; } @@ -177,12 +161,9 @@ inline bool RenderSVGText::shouldHandleSubtreeMutations() const void RenderSVGText::subtreeChildWasAdded(RenderObject* child) { ASSERT(child); - if (!shouldHandleSubtreeMutations() || documentBeingDestroyed()) + if (!shouldHandleSubtreeMutations() || renderTreeBeingDestroyed()) return; - // Always protect the cache before clearing text positioning elements when the cache will subsequently be rebuilt. - FontCachePurgePreventer fontCachePurgePreventer; - // The positioning elements cache doesn't include the new 'child' yet. Clear the // cache, as the next buildLayoutAttributesForTextRenderer() call rebuilds it. m_layoutAttributesBuilder.clearTextPositioningElements(); @@ -209,7 +190,7 @@ void RenderSVGText::subtreeChildWasAdded(RenderObject* child) SVGTextLayoutAttributes* previous = 0; SVGTextLayoutAttributes* next = 0; ASSERT_UNUSED(child, &attributes->context() == child); - findPreviousAndNextAttributes(this, &attributes->context(), stopAfterNext, previous, next); + findPreviousAndNextAttributes(*this, &attributes->context(), stopAfterNext, previous, next); if (previous) m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(previous->context()); @@ -264,26 +245,25 @@ void RenderSVGText::subtreeChildWillBeRemoved(RenderObject* child, Vector<SVGTex return; // This logic requires that the 'text' child is still inserted in the tree. - RenderSVGInlineText* text = toRenderSVGInlineText(child); + auto& text = downcast<RenderSVGInlineText>(*child); bool stopAfterNext = false; - SVGTextLayoutAttributes* previous = 0; - SVGTextLayoutAttributes* next = 0; - if (!documentBeingDestroyed()) - findPreviousAndNextAttributes(this, text, stopAfterNext, previous, next); + SVGTextLayoutAttributes* previous = nullptr; + SVGTextLayoutAttributes* next = nullptr; + if (!renderTreeBeingDestroyed()) + findPreviousAndNextAttributes(*this, &text, stopAfterNext, previous, next); if (previous) affectedAttributes.append(previous); if (next) affectedAttributes.append(next); - size_t position = m_layoutAttributes.find(text->layoutAttributes()); - ASSERT(position != notFound); - m_layoutAttributes.remove(position); + bool removed = m_layoutAttributes.removeFirst(text.layoutAttributes()); + ASSERT_UNUSED(removed, removed); } void RenderSVGText::subtreeChildWasRemoved(const Vector<SVGTextLayoutAttributes*, 2>& affectedAttributes) { - if (!shouldHandleSubtreeMutations() || documentBeingDestroyed()) { + if (!shouldHandleSubtreeMutations() || renderTreeBeingDestroyed()) { ASSERT(affectedAttributes.isEmpty()); return; } @@ -298,17 +278,16 @@ void RenderSVGText::subtreeChildWasRemoved(const Vector<SVGTextLayoutAttributes* void RenderSVGText::subtreeStyleDidChange(RenderSVGInlineText* text) { ASSERT(text); - if (!shouldHandleSubtreeMutations() || documentBeingDestroyed()) + if (!shouldHandleSubtreeMutations() || renderTreeBeingDestroyed()) return; checkLayoutAttributesConsistency(this, m_layoutAttributes); // Only update the metrics cache, but not the text positioning element cache // nor the layout attributes cached in the leaf #text renderers. - FontCachePurgePreventer fontCachePurgePreventer; for (RenderObject* descendant = text; descendant; descendant = descendant->nextInPreOrder(text)) { - if (descendant->isSVGInlineText()) - m_layoutAttributesBuilder.rebuildMetricsForTextRenderer(toRenderSVGInlineText(descendant)); + if (is<RenderSVGInlineText>(*descendant)) + m_layoutAttributesBuilder.rebuildMetricsForTextRenderer(downcast<RenderSVGInlineText>(*descendant)); } } @@ -327,29 +306,26 @@ void RenderSVGText::subtreeTextDidChange(RenderSVGInlineText* text) return; } - // Always protect the cache before clearing text positioning elements when the cache will subsequently be rebuilt. - FontCachePurgePreventer fontCachePurgePreventer; - // The positioning elements cache depends on the size of each text renderer in the // subtree. If this changes, clear the cache. It's going to be rebuilt below. m_layoutAttributesBuilder.clearTextPositioningElements(); checkLayoutAttributesConsistency(this, m_layoutAttributes); for (RenderObject* descendant = text; descendant; descendant = descendant->nextInPreOrder(text)) { - if (descendant->isSVGInlineText()) - m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(toRenderSVGInlineText(*descendant)); + if (is<RenderSVGInlineText>(*descendant)) + m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(downcast<RenderSVGInlineText>(*descendant)); } } -static inline void updateFontInAllDescendants(RenderObject* start, SVGTextLayoutAttributesBuilder* builder = 0) +static inline void updateFontInAllDescendants(RenderObject* start, SVGTextLayoutAttributesBuilder* builder = nullptr) { for (RenderObject* descendant = start; descendant; descendant = descendant->nextInPreOrder(start)) { - if (!descendant->isSVGInlineText()) + if (!is<RenderSVGInlineText>(*descendant)) continue; - RenderSVGInlineText& text = toRenderSVGInlineText(*descendant); + auto& text = downcast<RenderSVGInlineText>(*descendant); text.updateScaledFont(); if (builder) - builder->rebuildMetricsForTextRenderer(&text); + builder->rebuildMetricsForTextRenderer(text); } } @@ -372,7 +348,7 @@ void RenderSVGText::layout() ASSERT(m_layoutAttributes.isEmpty()); collectLayoutAttributes(this, m_layoutAttributes); updateFontInAllDescendants(this); - m_layoutAttributesBuilder.buildLayoutAttributesForForSubtree(this); + m_layoutAttributesBuilder.buildLayoutAttributesForForSubtree(*this); m_needsReordering = true; m_needsTextMetricsUpdate = false; @@ -386,11 +362,11 @@ void RenderSVGText::layout() m_needsTextMetricsUpdate = false; } - m_layoutAttributesBuilder.buildLayoutAttributesForForSubtree(this); + m_layoutAttributesBuilder.buildLayoutAttributesForForSubtree(*this); m_needsReordering = true; m_needsPositioningValuesUpdate = false; updateCachedBoundariesInParents = true; - } else if (m_needsTextMetricsUpdate || SVGRenderSupport::findTreeRootObject(*this).isLayoutSizeChanged()) { + } else if (m_needsTextMetricsUpdate || SVGRenderSupport::findTreeRootObject(*this)->isLayoutSizeChanged()) { // If the root layout size changed (eg. window size changes) or the transform to the root // context has changed then recompute the on-screen font size. updateFontInAllDescendants(this, &m_layoutAttributesBuilder); @@ -409,7 +385,7 @@ void RenderSVGText::layout() ASSERT(!simplifiedLayout()); ASSERT(!scrollsOverflow()); ASSERT(!hasControlClip()); - ASSERT(!hasColumns()); + ASSERT(!multiColumnFlowThread()); ASSERT(!positionedObjects()); ASSERT(!m_overflow); ASSERT(!isAnonymousBlock()); @@ -422,7 +398,7 @@ void RenderSVGText::layout() ASSERT(childrenInline()); LayoutUnit repaintLogicalTop = 0; LayoutUnit repaintLogicalBottom = 0; - clearFloats(); + rebuildFloatingObjectSetFromIntrudingFloats(); layoutInlineChildren(true, repaintLogicalTop, repaintLogicalBottom); if (m_needsReordering) @@ -447,7 +423,7 @@ std::unique_ptr<RootInlineBox> RenderSVGText::createRootInlineBox() { auto box = std::make_unique<SVGRootInlineBox>(*this); box->setHasVirtualLogicalHeight(); - return std::move(box); + return WTFMove(box); } bool RenderSVGText::nodeAtFloatPoint(const HitTestRequest& request, HitTestResult& result, const FloatPoint& pointInParent, HitTestAction hitTestAction) @@ -457,7 +433,7 @@ bool RenderSVGText::nodeAtFloatPoint(const HitTestRequest& request, HitTestResul if (isVisible || !hitRules.requireVisible) { if ((hitRules.canHitStroke && (style().svgStyle().hasStroke() || !hitRules.requireStroke)) || (hitRules.canHitFill && (style().svgStyle().hasFill() || !hitRules.requireFill))) { - FloatPoint localPoint = localToParentTransform().inverse().mapPoint(pointInParent); + FloatPoint localPoint = localToParentTransform().inverse().value_or(AffineTransform()).mapPoint(pointInParent); if (!SVGRenderSupport::pointInClippingArea(*this, localPoint)) return false; @@ -476,42 +452,46 @@ bool RenderSVGText::nodeAtPoint(const HitTestRequest&, HitTestResult&, const Hit return false; } -VisiblePosition RenderSVGText::positionForPoint(const LayoutPoint& pointInContents) +VisiblePosition RenderSVGText::positionForPoint(const LayoutPoint& pointInContents, const RenderRegion* region) { RootInlineBox* rootBox = firstRootBox(); if (!rootBox) return createVisiblePosition(0, DOWNSTREAM); - ASSERT_WITH_SECURITY_IMPLICATION(rootBox->isSVGRootInlineBox()); ASSERT(!rootBox->nextRootBox()); ASSERT(childrenInline()); - InlineBox* closestBox = toSVGRootInlineBox(rootBox)->closestLeafChildForPosition(pointInContents); + InlineBox* closestBox = downcast<SVGRootInlineBox>(*rootBox).closestLeafChildForPosition(pointInContents); if (!closestBox) return createVisiblePosition(0, DOWNSTREAM); - return closestBox->renderer().positionForPoint(LayoutPoint(pointInContents.x(), closestBox->y())); + return closestBox->renderer().positionForPoint(LayoutPoint(pointInContents.x(), closestBox->y()), region); } void RenderSVGText::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const { - quads.append(localToAbsoluteQuad(strokeBoundingBox(), 0 /* mode */, wasFixed)); + quads.append(localToAbsoluteQuad(strokeBoundingBox(), UseTransforms, wasFixed)); } void RenderSVGText::paint(PaintInfo& paintInfo, const LayoutPoint&) { - if (paintInfo.context->paintingDisabled()) + if (paintInfo.context().paintingDisabled()) return; if (paintInfo.phase != PaintPhaseForeground - && paintInfo.phase != PaintPhaseSelfOutline && paintInfo.phase != PaintPhaseSelection) return; PaintInfo blockInfo(paintInfo); - GraphicsContextStateSaver stateSaver(*blockInfo.context); + GraphicsContextStateSaver stateSaver(blockInfo.context()); blockInfo.applyTransform(localToParentTransform()); RenderBlock::paint(blockInfo, LayoutPoint()); + + // Paint the outlines, if any + if (paintInfo.phase == PaintPhaseForeground) { + blockInfo.phase = PaintPhaseSelfOutline; + RenderBlock::paint(blockInfo, LayoutPoint()); + } } FloatRect RenderSVGText::strokeBoundingBox() const @@ -522,7 +502,7 @@ FloatRect RenderSVGText::strokeBoundingBox() const return strokeBoundaries; SVGLengthContext lengthContext(&textElement()); - strokeBoundaries.inflate(svgStyle.strokeWidth().value(lengthContext)); + strokeBoundaries.inflate(lengthContext.valueForLength(style().strokeWidth())); return strokeBoundaries; } @@ -550,7 +530,6 @@ void RenderSVGText::removeChild(RenderObject& child) SVGResourcesCache::clientWillBeRemovedFromTree(child); Vector<SVGTextLayoutAttributes*, 2> affectedAttributes; - FontCachePurgePreventer fontCachePurgePreventer; subtreeChildWillBeRemoved(&child, affectedAttributes); RenderSVGBlock::removeChild(child); subtreeChildWasRemoved(affectedAttributes); @@ -565,10 +544,8 @@ RenderBlock* RenderSVGText::firstLineBlock() const // Fix for <rdar://problem/8048875>. We should not render :first-letter CSS Style // in a SVG text element context. -void RenderSVGText::updateFirstLetter() +void RenderSVGText::updateFirstLetter(RenderTreeMutationIsAllowed) { } } - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGText.h b/Source/WebCore/rendering/svg/RenderSVGText.h index 93ac44246..6ef1bd3a9 100644 --- a/Source/WebCore/rendering/svg/RenderSVGText.h +++ b/Source/WebCore/rendering/svg/RenderSVGText.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006 Apple Inc. * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> * Copyright (C) Research In Motion Limited 2010-2012. All rights reserved. * @@ -19,10 +19,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef RenderSVGText_h -#define RenderSVGText_h +#pragma once -#if ENABLE(SVG) #include "AffineTransform.h" #include "RenderSVGBlock.h" #include "SVGTextLayoutAttributesBuilder.h" @@ -35,20 +33,20 @@ class RenderSVGInlineText; class RenderSVGText final : public RenderSVGBlock { public: - RenderSVGText(SVGTextElement&, PassRef<RenderStyle>); + RenderSVGText(SVGTextElement&, RenderStyle&&); virtual ~RenderSVGText(); SVGTextElement& textElement() const; - virtual bool isChildAllowed(const RenderObject&, const RenderStyle&) const; + bool isChildAllowed(const RenderObject&, const RenderStyle&) const override; void setNeedsPositioningValuesUpdate() { m_needsPositioningValuesUpdate = true; } - virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; } + void setNeedsTransformUpdate() override { m_needsTransformUpdate = true; } void setNeedsTextMetricsUpdate() { m_needsTextMetricsUpdate = true; } - virtual FloatRect repaintRectInLocalCoordinates() const; + FloatRect repaintRectInLocalCoordinates() const override; - static RenderSVGText* locateRenderSVGTextAncestor(RenderObject*); - static const RenderSVGText* locateRenderSVGTextAncestor(const RenderObject*); + static RenderSVGText* locateRenderSVGTextAncestor(RenderObject&); + static const RenderSVGText* locateRenderSVGTextAncestor(const RenderObject&); bool needsReordering() const { return m_needsReordering; } Vector<SVGTextLayoutAttributes*>& layoutAttributes() { return m_layoutAttributes; } @@ -59,41 +57,41 @@ public: void subtreeStyleDidChange(RenderSVGInlineText*); void subtreeTextDidChange(RenderSVGInlineText*); + FloatRect objectBoundingBox() const override { return frameRect(); } + FloatRect strokeBoundingBox() const override; + private: void graphicsElement() const = delete; - virtual const char* renderName() const { return "RenderSVGText"; } - virtual bool isSVGText() const { return true; } - - virtual void paint(PaintInfo&, const LayoutPoint&); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) override; - virtual bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction); - virtual VisiblePosition positionForPoint(const LayoutPoint&); + const char* renderName() const override { return "RenderSVGText"; } + bool isSVGText() const override { return true; } - virtual bool requiresLayer() const { return false; } - virtual void layout(); + void paint(PaintInfo&, const LayoutPoint&) override; + bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction) override; + bool nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint& pointInParent, HitTestAction) override; + VisiblePosition positionForPoint(const LayoutPoint&, const RenderRegion*) override; - virtual void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const; + bool requiresLayer() const override { return false; } + void layout() override; - virtual LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const override; - virtual void computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect&, bool fixed = false) const override; - virtual void computeFloatRectForRepaint(const RenderLayerModelObject* repaintContainer, FloatRect&, bool fixed = false) const override; + void absoluteQuads(Vector<FloatQuad>&, bool* wasFixed) const override; - virtual void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags = ApplyContainerFlip, bool* wasFixed = 0) const override; - virtual const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const override; - virtual void addChild(RenderObject* child, RenderObject* beforeChild = 0); - virtual void removeChild(RenderObject&) override; - virtual void willBeDestroyed() override; + LayoutRect clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const override; + LayoutRect computeRectForRepaint(const LayoutRect&, const RenderLayerModelObject* repaintContainer, RepaintContext = { }) const override; + FloatRect computeFloatRectForRepaint(const FloatRect&, const RenderLayerModelObject* repaintContainer, bool fixed = false) const override; - virtual FloatRect objectBoundingBox() const { return frameRect(); } - virtual FloatRect strokeBoundingBox() const; + void mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState&, MapCoordinatesFlags, bool* wasFixed) const override; + const RenderObject* pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&) const override; + void addChild(RenderObject* child, RenderObject* beforeChild = nullptr) override; + void removeChild(RenderObject&) override; + void willBeDestroyed() override; - virtual const AffineTransform& localToParentTransform() const { return m_localTransform; } - virtual AffineTransform localTransform() const { return m_localTransform; } - virtual std::unique_ptr<RootInlineBox> createRootInlineBox() override; + const AffineTransform& localToParentTransform() const override { return m_localTransform; } + AffineTransform localTransform() const override { return m_localTransform; } + std::unique_ptr<RootInlineBox> createRootInlineBox() override; - virtual RenderBlock* firstLineBlock() const; - virtual void updateFirstLetter(); + RenderBlock* firstLineBlock() const override; + void updateFirstLetter(RenderTreeMutationIsAllowed = RenderTreeMutationIsAllowed::Yes) override; bool shouldHandleSubtreeMutations() const; @@ -106,9 +104,6 @@ private: Vector<SVGTextLayoutAttributes*> m_layoutAttributes; }; -RENDER_OBJECT_TYPE_CASTS(RenderSVGText, isSVGText()) - -} +} // namespace WebCore -#endif // ENABLE(SVG) -#endif +SPECIALIZE_TYPE_TRAITS_RENDER_OBJECT(RenderSVGText, isSVGText()) diff --git a/Source/WebCore/rendering/svg/RenderSVGTextPath.cpp b/Source/WebCore/rendering/svg/RenderSVGTextPath.cpp index 12cb6d361..3d5f36528 100644 --- a/Source/WebCore/rendering/svg/RenderSVGTextPath.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGTextPath.cpp @@ -18,8 +18,6 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGTextPath.h" #include "FloatQuad.h" @@ -30,18 +28,17 @@ #include "SVGPathElement.h" #include "SVGRootInlineBox.h" #include "SVGTextPathElement.h" -#include "SVGTransformList.h" namespace WebCore { -RenderSVGTextPath::RenderSVGTextPath(SVGTextPathElement& element, PassRef<RenderStyle> style) - : RenderSVGInline(element, std::move(style)) +RenderSVGTextPath::RenderSVGTextPath(SVGTextPathElement& element, RenderStyle&& style) + : RenderSVGInline(element, WTFMove(style)) { } SVGTextPathElement& RenderSVGTextPath::textPathElement() const { - return toSVGTextPathElement(RenderSVGInline::graphicsElement()); + return downcast<SVGTextPathElement>(RenderSVGInline::graphicsElement()); } Path RenderSVGTextPath::layoutPath() const @@ -50,17 +47,17 @@ Path RenderSVGTextPath::layoutPath() const if (!targetElement || !targetElement->hasTagName(SVGNames::pathTag)) return Path(); - SVGPathElement* pathElement = toSVGPathElement(targetElement); + SVGPathElement& pathElement = downcast<SVGPathElement>(*targetElement); Path pathData; - updatePathFromGraphicsElement(pathElement, pathData); + updatePathFromGraphicsElement(&pathElement, pathData); // Spec: The transform attribute on the referenced 'path' element represents a // supplemental transformation relative to the current user coordinate system for // the current 'text' element, including any adjustments to the current user coordinate // system due to a possible transform attribute on the current 'text' element. // http://www.w3.org/TR/SVG/text.html#TextPathElement - pathData.transform(pathElement->animatedLocalTransform()); + pathData.transform(pathElement.animatedLocalTransform()); return pathData; } @@ -80,5 +77,3 @@ bool RenderSVGTextPath::stretchMethod() const } } - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGTextPath.h b/Source/WebCore/rendering/svg/RenderSVGTextPath.h index e7e11ad98..95a379274 100644 --- a/Source/WebCore/rendering/svg/RenderSVGTextPath.h +++ b/Source/WebCore/rendering/svg/RenderSVGTextPath.h @@ -18,17 +18,15 @@ * Boston, MA 02110-1301, USA. */ -#ifndef RenderSVGTextPath_h -#define RenderSVGTextPath_h +#pragma once -#if ENABLE(SVG) #include "RenderSVGInline.h" namespace WebCore { class RenderSVGTextPath final : public RenderSVGInline { public: - RenderSVGTextPath(SVGTextPathElement&, PassRef<RenderStyle>); + RenderSVGTextPath(SVGTextPathElement&, RenderStyle&&); SVGTextPathElement& textPathElement() const; @@ -40,15 +38,12 @@ public: private: void graphicsElement() const = delete; - virtual bool isSVGTextPath() const override { return true; } - virtual const char* renderName() const override { return "RenderSVGTextPath"; } + bool isSVGTextPath() const override { return true; } + const char* renderName() const override { return "RenderSVGTextPath"; } Path m_layoutPath; }; -RENDER_OBJECT_TYPE_CASTS(RenderSVGTextPath, isSVGTextPath()) +} // namespace WebCore -} - -#endif // ENABLE(SVG) -#endif // RenderSVGTextPath_h +SPECIALIZE_TYPE_TRAITS_RENDER_OBJECT(RenderSVGTextPath, isSVGTextPath()) diff --git a/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.cpp index 3268b676a..0b08a17b8 100644 --- a/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.cpp @@ -20,17 +20,15 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGTransformableContainer.h" -#include "SVGNames.h" +#include "SVGGElement.h" #include "SVGUseElement.h" namespace WebCore { -RenderSVGTransformableContainer::RenderSVGTransformableContainer(SVGGraphicsElement& element, PassRef<RenderStyle> style) - : RenderSVGContainer(element, std::move(style)) +RenderSVGTransformableContainer::RenderSVGTransformableContainer(SVGGraphicsElement& element, RenderStyle&& style) + : RenderSVGContainer(element, WTFMove(style)) , m_needsTransformUpdate(true) , m_didTransformToRootUpdate(false) { @@ -43,13 +41,13 @@ bool RenderSVGTransformableContainer::calculateLocalTransform() // If we're either the renderer for a <use> element, or for any <g> element inside the shadow // tree, that was created during the use/symbol/svg expansion in SVGUseElement. These containers // need to respect the translations induced by their corresponding use elements x/y attributes. - SVGUseElement* useElement = 0; - if (isSVGUseElement(element)) - useElement = &toSVGUseElement(element); - else if (element.isInShadowTree() && isSVGGElement(element)) { + SVGUseElement* useElement = nullptr; + if (is<SVGUseElement>(element)) + useElement = &downcast<SVGUseElement>(element); + else if (element.isInShadowTree() && is<SVGGElement>(element)) { SVGElement* correspondingElement = element.correspondingElement(); - if (correspondingElement && isSVGUseElement(correspondingElement)) - useElement = toSVGUseElement(correspondingElement); + if (is<SVGUseElement>(correspondingElement)) + useElement = downcast<SVGUseElement>(correspondingElement); } if (useElement) { @@ -71,5 +69,3 @@ bool RenderSVGTransformableContainer::calculateLocalTransform() } } - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.h b/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.h index d97eafda0..f21199004 100644 --- a/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.h +++ b/Source/WebCore/rendering/svg/RenderSVGTransformableContainer.h @@ -18,10 +18,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef RenderSVGTransformableContainer_h -#define RenderSVGTransformableContainer_h +#pragma once -#if ENABLE(SVG) #include "RenderSVGContainer.h" #include "SVGGraphicsElement.h" @@ -30,18 +28,18 @@ namespace WebCore { class SVGGraphicsElement; class RenderSVGTransformableContainer final : public RenderSVGContainer { public: - RenderSVGTransformableContainer(SVGGraphicsElement&, PassRef<RenderStyle>); - SVGGraphicsElement& graphicsElement() { return toSVGGraphicsElement(RenderSVGContainer::element()); } + RenderSVGTransformableContainer(SVGGraphicsElement&, RenderStyle&&); + SVGGraphicsElement& graphicsElement() { return downcast<SVGGraphicsElement>(RenderSVGContainer::element()); } - virtual bool isSVGTransformableContainer() const { return true; } - virtual const AffineTransform& localToParentTransform() const { return m_localTransform; } - virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; } - virtual bool didTransformToRootUpdate() { return m_didTransformToRootUpdate; } + bool isSVGTransformableContainer() const override { return true; } + const AffineTransform& localToParentTransform() const override { return m_localTransform; } + void setNeedsTransformUpdate() override { m_needsTransformUpdate = true; } + bool didTransformToRootUpdate() override { return m_didTransformToRootUpdate; } private: void element() const = delete; - virtual bool calculateLocalTransform(); - virtual AffineTransform localTransform() const { return m_localTransform; } + bool calculateLocalTransform() override; + AffineTransform localTransform() const override { return m_localTransform; } bool m_needsTransformUpdate : 1; bool m_didTransformToRootUpdate : 1; @@ -49,7 +47,6 @@ private: FloatSize m_lastTranslation; }; -} +} // namespace WebCore -#endif // ENABLE(SVG) -#endif // RenderSVGTransformableContainer_h +SPECIALIZE_TYPE_TRAITS_RENDER_OBJECT(RenderSVGTransformableContainer, isSVGTransformableContainer()) diff --git a/Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp b/Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp index f03467c62..932fb8517 100644 --- a/Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp +++ b/Source/WebCore/rendering/svg/RenderSVGViewportContainer.cpp @@ -21,21 +21,16 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "RenderSVGViewportContainer.h" #include "GraphicsContext.h" #include "RenderView.h" -#include "SVGElementInstance.h" -#include "SVGNames.h" #include "SVGSVGElement.h" -#include "SVGUseElement.h" namespace WebCore { -RenderSVGViewportContainer::RenderSVGViewportContainer(SVGSVGElement& element, PassRef<RenderStyle> style) - : RenderSVGContainer(element, std::move(style)) +RenderSVGViewportContainer::RenderSVGViewportContainer(SVGSVGElement& element, RenderStyle&& style) + : RenderSVGContainer(element, WTFMove(style)) , m_didTransformToRootUpdate(false) , m_isLayoutSizeChanged(false) , m_needsTransformUpdate(true) @@ -44,7 +39,7 @@ RenderSVGViewportContainer::RenderSVGViewportContainer(SVGSVGElement& element, P SVGSVGElement& RenderSVGViewportContainer::svgSVGElement() const { - return toSVGSVGElement(RenderSVGContainer::element()); + return downcast<SVGSVGElement>(RenderSVGContainer::element()); } void RenderSVGViewportContainer::determineIfLayoutSizeChanged() @@ -55,67 +50,22 @@ void RenderSVGViewportContainer::determineIfLayoutSizeChanged() void RenderSVGViewportContainer::applyViewportClip(PaintInfo& paintInfo) { if (SVGRenderSupport::isOverflowHidden(*this)) - paintInfo.context->clip(m_viewport); + paintInfo.context().clip(m_viewport); } void RenderSVGViewportContainer::calcViewport() { - SVGSVGElement& svg = svgSVGElement(); - FloatRect oldViewport = m_viewport; - - SVGLengthContext lengthContext(&svg); - m_viewport = FloatRect(svg.x().value(lengthContext), svg.y().value(lengthContext), svg.width().value(lengthContext), svg.height().value(lengthContext)); - - SVGElement* correspondingElement = svg.correspondingElement(); - if (correspondingElement && svg.isInShadowTree()) { - const HashSet<SVGElementInstance*>& instances = correspondingElement->instancesForElement(); - ASSERT(!instances.isEmpty()); - - SVGUseElement* useElement = 0; - const HashSet<SVGElementInstance*>::const_iterator end = instances.end(); - for (HashSet<SVGElementInstance*>::const_iterator it = instances.begin(); it != end; ++it) { - const SVGElementInstance* instance = (*it); - ASSERT(instance->correspondingElement()->hasTagName(SVGNames::svgTag) || instance->correspondingElement()->hasTagName(SVGNames::symbolTag)); - if (instance->shadowTreeElement() == &svg) { - ASSERT(correspondingElement == instance->correspondingElement()); - useElement = instance->directUseElement(); - if (!useElement) - useElement = instance->correspondingUseElement(); - break; - } - } - - ASSERT(useElement); - bool isSymbolElement = correspondingElement->hasTagName(SVGNames::symbolTag); - - // Spec (<use> on <symbol>): This generated 'svg' will always have explicit values for attributes width and height. - // If attributes width and/or height are provided on the 'use' element, then these attributes - // will be transferred to the generated 'svg'. If attributes width and/or height are not specified, - // the generated 'svg' element will use values of 100% for these attributes. - - // Spec (<use> on <svg>): If attributes width and/or height are provided on the 'use' element, then these - // values will override the corresponding attributes on the 'svg' in the generated tree. - - SVGLengthContext lengthContext(&svg); - if (useElement->hasAttribute(SVGNames::widthAttr)) - m_viewport.setWidth(useElement->width().value(lengthContext)); - else if (isSymbolElement && svg.hasAttribute(SVGNames::widthAttr)) { - SVGLength containerWidth(LengthModeWidth, "100%"); - m_viewport.setWidth(containerWidth.value(lengthContext)); - } - - if (useElement->hasAttribute(SVGNames::heightAttr)) - m_viewport.setHeight(useElement->height().value(lengthContext)); - else if (isSymbolElement && svg.hasAttribute(SVGNames::heightAttr)) { - SVGLength containerHeight(LengthModeHeight, "100%"); - m_viewport.setHeight(containerHeight.value(lengthContext)); - } - } - - if (oldViewport != m_viewport) { - setNeedsBoundariesUpdate(); - setNeedsTransformUpdate(); - } + SVGSVGElement& element = svgSVGElement(); + SVGLengthContext lengthContext(&element); + FloatRect newViewport(element.x().value(lengthContext), element.y().value(lengthContext), element.width().value(lengthContext), element.height().value(lengthContext)); + + if (m_viewport == newViewport) + return; + + m_viewport = newViewport; + + setNeedsBoundariesUpdate(); + setNeedsTransformUpdate(); } bool RenderSVGViewportContainer::calculateLocalTransform() @@ -153,5 +103,3 @@ void RenderSVGViewportContainer::paint(PaintInfo& paintInfo, const LayoutPoint& } } - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/RenderSVGViewportContainer.h b/Source/WebCore/rendering/svg/RenderSVGViewportContainer.h index 182431eb5..56ac6fc1b 100644 --- a/Source/WebCore/rendering/svg/RenderSVGViewportContainer.h +++ b/Source/WebCore/rendering/svg/RenderSVGViewportContainer.h @@ -20,10 +20,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef RenderSVGViewportContainer_h -#define RenderSVGViewportContainer_h +#pragma once -#if ENABLE(SVG) #include "RenderSVGContainer.h" namespace WebCore { @@ -32,34 +30,34 @@ namespace WebCore { // thus we inherit from RenderSVGContainer instead of RenderSVGTransformableContainer class RenderSVGViewportContainer final : public RenderSVGContainer { public: - RenderSVGViewportContainer(SVGSVGElement&, PassRef<RenderStyle>); + RenderSVGViewportContainer(SVGSVGElement&, RenderStyle&&); SVGSVGElement& svgSVGElement() const; FloatRect viewport() const { return m_viewport; } bool isLayoutSizeChanged() const { return m_isLayoutSizeChanged; } - virtual bool didTransformToRootUpdate() { return m_didTransformToRootUpdate; } + bool didTransformToRootUpdate() override { return m_didTransformToRootUpdate; } - virtual void determineIfLayoutSizeChanged(); - virtual void setNeedsTransformUpdate() { m_needsTransformUpdate = true; } + void determineIfLayoutSizeChanged() override; + void setNeedsTransformUpdate() override { m_needsTransformUpdate = true; } - virtual void paint(PaintInfo&, const LayoutPoint&) override; + void paint(PaintInfo&, const LayoutPoint&) override; private: void element() const = delete; - virtual bool isSVGViewportContainer() const { return true; } - virtual const char* renderName() const { return "RenderSVGViewportContainer"; } + bool isSVGViewportContainer() const override { return true; } + const char* renderName() const override { return "RenderSVGViewportContainer"; } AffineTransform viewportTransform() const; - virtual const AffineTransform& localToParentTransform() const { return m_localToParentTransform; } + const AffineTransform& localToParentTransform() const override { return m_localToParentTransform; } - virtual void calcViewport(); - virtual bool calculateLocalTransform(); + void calcViewport() override; + bool calculateLocalTransform() override; - virtual void applyViewportClip(PaintInfo&); - virtual bool pointIsInsideViewportClip(const FloatPoint& pointInParent); + void applyViewportClip(PaintInfo&) override; + bool pointIsInsideViewportClip(const FloatPoint& pointInParent) override; FloatRect m_viewport; mutable AffineTransform m_localToParentTransform; @@ -68,9 +66,6 @@ private: bool m_needsTransformUpdate : 1; }; -RENDER_OBJECT_TYPE_CASTS(RenderSVGViewportContainer, isSVGViewportContainer()) - } // namespace WebCore -#endif // ENABLE(SVG) -#endif // RenderSVGViewportContainer_h +SPECIALIZE_TYPE_TRAITS_RENDER_OBJECT(RenderSVGViewportContainer, isSVGViewportContainer()) diff --git a/Source/WebCore/rendering/svg/SVGInlineFlowBox.cpp b/Source/WebCore/rendering/svg/SVGInlineFlowBox.cpp index db017adba..2d5079e32 100644 --- a/Source/WebCore/rendering/svg/SVGInlineFlowBox.cpp +++ b/Source/WebCore/rendering/svg/SVGInlineFlowBox.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz> - * Copyright (C) 2006 Apple Computer Inc. + * Copyright (C) 2006 Apple Inc. * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> * Copyright (C) Research In Motion Limited 2010. All rights reserved. * @@ -23,10 +23,7 @@ #include "config.h" #include "SVGInlineFlowBox.h" -#if ENABLE(SVG) -#include "DocumentMarkerController.h" #include "GraphicsContext.h" -#include "RenderedDocumentMarker.h" #include "SVGInlineTextBox.h" #include "SVGRenderingContext.h" @@ -35,30 +32,26 @@ namespace WebCore { void SVGInlineFlowBox::paintSelectionBackground(PaintInfo& paintInfo) { ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection); - ASSERT(!paintInfo.context->paintingDisabled()); + ASSERT(!paintInfo.context().paintingDisabled()); PaintInfo childPaintInfo(paintInfo); for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { - if (child->isSVGInlineTextBox()) - toSVGInlineTextBox(child)->paintSelectionBackground(childPaintInfo); - else if (child->isSVGInlineFlowBox()) - toSVGInlineFlowBox(child)->paintSelectionBackground(childPaintInfo); + if (is<SVGInlineTextBox>(*child)) + downcast<SVGInlineTextBox>(*child).paintSelectionBackground(childPaintInfo); + else if (is<SVGInlineFlowBox>(*child)) + downcast<SVGInlineFlowBox>(*child).paintSelectionBackground(childPaintInfo); } } -void SVGInlineFlowBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUnit, LayoutUnit) +void SVGInlineFlowBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit, LayoutUnit) { ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection); - ASSERT(!paintInfo.context->paintingDisabled()); + ASSERT(!paintInfo.context().paintingDisabled()); SVGRenderingContext renderingContext(renderer(), paintInfo, SVGRenderingContext::SaveGraphicsContext); if (renderingContext.isRenderingPrepared()) { - for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { - if (child->isSVGInlineTextBox()) - computeTextMatchMarkerRectForRenderer(&(toSVGInlineTextBox(child)->renderer())); - - child->paint(paintInfo, LayoutPoint(), 0, 0); - } + for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) + child->paint(paintInfo, paintOffset, 0, 0); } } @@ -73,66 +66,4 @@ FloatRect SVGInlineFlowBox::calculateBoundaries() const return childRect; } -void SVGInlineFlowBox::computeTextMatchMarkerRectForRenderer(RenderSVGInlineText* textRenderer) -{ - ASSERT(textRenderer); - - Text& textNode = textRenderer->textNode(); - if (!textNode.inDocument()) - return; - - RenderStyle& style = textRenderer->style(); - - AffineTransform fragmentTransform; - Vector<DocumentMarker*> markers = textRenderer->document().markers().markersFor(&textNode); - - Vector<DocumentMarker*>::iterator markerEnd = markers.end(); - for (Vector<DocumentMarker*>::iterator markerIt = markers.begin(); markerIt != markerEnd; ++markerIt) { - DocumentMarker* marker = *markerIt; - - // SVG is only interessted in the TextMatch marker, for now. - if (marker->type() != DocumentMarker::TextMatch) - continue; - - FloatRect markerRect; - for (InlineTextBox* box = textRenderer->firstTextBox(); box; box = box->nextTextBox()) { - if (!box->isSVGInlineTextBox()) - continue; - - SVGInlineTextBox* textBox = toSVGInlineTextBox(box); - - int markerStartPosition = std::max<int>(marker->startOffset() - textBox->start(), 0); - int markerEndPosition = std::min<int>(marker->endOffset() - textBox->start(), textBox->len()); - - if (markerStartPosition >= markerEndPosition) - continue; - - int fragmentStartPosition = 0; - int fragmentEndPosition = 0; - - const Vector<SVGTextFragment>& fragments = textBox->textFragments(); - unsigned textFragmentsSize = fragments.size(); - for (unsigned i = 0; i < textFragmentsSize; ++i) { - const SVGTextFragment& fragment = fragments.at(i); - - fragmentStartPosition = markerStartPosition; - fragmentEndPosition = markerEndPosition; - if (!textBox->mapStartEndPositionsIntoFragmentCoordinates(fragment, fragmentStartPosition, fragmentEndPosition)) - continue; - - FloatRect fragmentRect = textBox->selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, &style); - fragment.buildFragmentTransform(fragmentTransform); - if (!fragmentTransform.isIdentity()) - fragmentRect = fragmentTransform.mapRect(fragmentRect); - - markerRect.unite(fragmentRect); - } - } - - toRenderedDocumentMarker(marker)->setRenderedRect(textRenderer->localToAbsoluteQuad(markerRect).enclosingBoundingBox()); - } -} - } // namespace WebCore - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/SVGInlineFlowBox.h b/Source/WebCore/rendering/svg/SVGInlineFlowBox.h index 88165dfda..58cc1fcaa 100644 --- a/Source/WebCore/rendering/svg/SVGInlineFlowBox.h +++ b/Source/WebCore/rendering/svg/SVGInlineFlowBox.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz> - * Copyright (C) 2006 Apple Computer Inc. + * Copyright (C) 2006 Apple Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -18,10 +18,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef SVGInlineFlowBox_h -#define SVGInlineFlowBox_h +#pragma once -#if ENABLE(SVG) #include "InlineFlowBox.h" #include "RenderSVGInline.h" @@ -39,24 +37,19 @@ public: RenderSVGInline& renderer() { return static_cast<RenderSVGInline&>(InlineFlowBox::renderer()); } - virtual FloatRect calculateBoundaries() const override; + FloatRect calculateBoundaries() const override; void setLogicalHeight(float h) { m_logicalHeight = h; } void paintSelectionBackground(PaintInfo&); - static void computeTextMatchMarkerRectForRenderer(RenderSVGInlineText*); private: - virtual bool isSVGInlineFlowBox() const override { return true; } - virtual float virtualLogicalHeight() const override { return m_logicalHeight; } - virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) override; + bool isSVGInlineFlowBox() const override { return true; } + float virtualLogicalHeight() const override { return m_logicalHeight; } + void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) override; float m_logicalHeight; }; -INLINE_BOX_OBJECT_TYPE_CASTS(SVGInlineFlowBox, isSVGInlineFlowBox()) - } // namespace WebCore -#endif // ENABLE(SVG) - -#endif // SVGInlineFlowBox_h +SPECIALIZE_TYPE_TRAITS_INLINE_BOX(SVGInlineFlowBox, isSVGInlineFlowBox()) diff --git a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp index f55976e95..e70f0903a 100644 --- a/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp +++ b/Source/WebCore/rendering/svg/SVGInlineTextBox.cpp @@ -22,8 +22,6 @@ #include "config.h" #include "SVGInlineTextBox.h" -#if ENABLE(SVG) -#include "FontCache.h" #include "Frame.h" #include "FrameView.h" #include "GraphicsContext.h" @@ -31,12 +29,13 @@ #include "InlineFlowBox.h" #include "PointerEventsHitRules.h" #include "RenderBlock.h" +#include "RenderInline.h" #include "RenderSVGResourceSolidColor.h" #include "RenderView.h" #include "SVGRenderingContext.h" #include "SVGResourcesCache.h" #include "SVGRootInlineBox.h" -#include "SVGTextRunRenderingContext.h" +#include "TextPainter.h" namespace WebCore { @@ -54,7 +53,7 @@ SVGInlineTextBox::SVGInlineTextBox(RenderSVGInlineText& renderer) , m_logicalHeight(0) , m_paintingResourceMode(ApplyToDefaultMode) , m_startsNewTextChunk(false) - , m_paintingResource(0) + , m_paintingResource(nullptr) { } @@ -89,7 +88,7 @@ int SVGInlineTextBox::offsetForPositionInFragment(const SVGTextFragment& fragmen float scalingFactor = renderer().scalingFactor(); ASSERT(scalingFactor); - TextRun textRun = constructTextRun(&renderer().style(), fragment); + TextRun textRun = constructTextRun(renderer().style(), fragment); // Eventually handle lengthAdjust="spacingAndGlyphs". // FIXME: Handle vertical text. @@ -101,53 +100,52 @@ int SVGInlineTextBox::offsetForPositionInFragment(const SVGTextFragment& fragmen return fragment.characterOffset - start() + renderer().scaledFont().offsetForPosition(textRun, position * scalingFactor, includePartialGlyphs); } -float SVGInlineTextBox::positionForOffset(int) const +float SVGInlineTextBox::positionForOffset(unsigned) const { // SVG doesn't use the offset <-> position selection system. ASSERT_NOT_REACHED(); return 0; } -FloatRect SVGInlineTextBox::selectionRectForTextFragment(const SVGTextFragment& fragment, int startPosition, int endPosition, RenderStyle* style) const +FloatRect SVGInlineTextBox::selectionRectForTextFragment(const SVGTextFragment& fragment, unsigned startPosition, unsigned endPosition, const RenderStyle& style) const { ASSERT_WITH_SECURITY_IMPLICATION(startPosition < endPosition); - ASSERT(style); - - FontCachePurgePreventer fontCachePurgePreventer; float scalingFactor = renderer().scalingFactor(); ASSERT(scalingFactor); - const Font& scaledFont = renderer().scaledFont(); + const FontCascade& scaledFont = renderer().scaledFont(); const FontMetrics& scaledFontMetrics = scaledFont.fontMetrics(); FloatPoint textOrigin(fragment.x, fragment.y); if (scalingFactor != 1) - textOrigin.scale(scalingFactor, scalingFactor); + textOrigin.scale(scalingFactor); textOrigin.move(0, -scaledFontMetrics.floatAscent()); - FloatRect selectionRect = scaledFont.selectionRectForText(constructTextRun(style, fragment), textOrigin, fragment.height * scalingFactor, startPosition, endPosition); + LayoutRect selectionRect = LayoutRect(textOrigin, LayoutSize(0, fragment.height * scalingFactor)); + TextRun run = constructTextRun(style, fragment); + scaledFont.adjustSelectionRectForText(run, selectionRect, startPosition, endPosition); + FloatRect snappedSelectionRect = snapRectToDevicePixelsWithWritingDirection(selectionRect, renderer().document().deviceScaleFactor(), run.ltr()); if (scalingFactor == 1) - return selectionRect; + return snappedSelectionRect; - selectionRect.scale(1 / scalingFactor); - return selectionRect; + snappedSelectionRect.scale(1 / scalingFactor); + return snappedSelectionRect; } -LayoutRect SVGInlineTextBox::localSelectionRect(int startPosition, int endPosition) const +LayoutRect SVGInlineTextBox::localSelectionRect(unsigned startPosition, unsigned endPosition) const { - int boxStart = start(); - startPosition = std::max(startPosition - boxStart, 0); - endPosition = std::min(endPosition - boxStart, static_cast<int>(len())); + startPosition = clampedOffset(startPosition); + endPosition = clampedOffset(endPosition); if (startPosition >= endPosition) return LayoutRect(); - RenderStyle& style = renderer().style(); + auto& style = renderer().style(); AffineTransform fragmentTransform; FloatRect selectionRect; - int fragmentStartPosition = 0; - int fragmentEndPosition = 0; + unsigned fragmentStartPosition = 0; + unsigned fragmentEndPosition = 0; unsigned textFragmentsSize = m_textFragments.size(); for (unsigned i = 0; i < textFragmentsSize; ++i) { @@ -158,7 +156,7 @@ LayoutRect SVGInlineTextBox::localSelectionRect(int startPosition, int endPositi if (!mapStartEndPositionsIntoFragmentCoordinates(fragment, fragmentStartPosition, fragmentEndPosition)) continue; - FloatRect fragmentRect = selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, &style); + FloatRect fragmentRect = selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, style); fragment.buildFragmentTransform(fragmentTransform); if (!fragmentTransform.isIdentity()) fragmentRect = fragmentTransform.mapRect(fragmentRect); @@ -171,7 +169,7 @@ LayoutRect SVGInlineTextBox::localSelectionRect(int startPosition, int endPositi static inline bool textShouldBePainted(const RenderSVGInlineText& textRenderer) { - // Font::pixelSize(), returns FontDescription::computedPixelSize(), which returns "int(x + 0.5)". + // FontCascade::pixelSize(), returns FontDescription::computedPixelSize(), which returns "int(x + 0.5)". // If the absolute font size on screen is below x=0.5, don't render anything. return textRenderer.scaledFont().pixelSize(); } @@ -185,7 +183,7 @@ void SVGInlineTextBox::paintSelectionBackground(PaintInfo& paintInfo) if (renderer().style().visibility() != VISIBLE) return; - RenderObject& parentRenderer = parent()->renderer(); + auto& parentRenderer = parent()->renderer(); ASSERT(!parentRenderer.document().printing()); // Determine whether or not we're selected. @@ -195,26 +193,20 @@ void SVGInlineTextBox::paintSelectionBackground(PaintInfo& paintInfo) return; Color backgroundColor = renderer().selectionBackgroundColor(); - if (!backgroundColor.isValid() || !backgroundColor.alpha()) + if (!backgroundColor.isVisible()) return; if (!textShouldBePainted(renderer())) return; - RenderStyle& style = parentRenderer.style(); + auto& style = parentRenderer.style(); - RenderStyle* selectionStyle = &style; - if (hasSelection) { - selectionStyle = parentRenderer.getCachedPseudoStyle(SELECTION); - if (!selectionStyle) - selectionStyle = &style; - } - - int startPosition, endPosition; - selectionStartEnd(startPosition, endPosition); + unsigned startPosition; + unsigned endPosition; + std::tie(startPosition, endPosition) = selectionStartEnd(); - int fragmentStartPosition = 0; - int fragmentEndPosition = 0; + unsigned fragmentStartPosition = 0; + unsigned fragmentEndPosition = 0; AffineTransform fragmentTransform; unsigned textFragmentsSize = m_textFragments.size(); for (unsigned i = 0; i < textFragmentsSize; ++i) { @@ -226,13 +218,13 @@ void SVGInlineTextBox::paintSelectionBackground(PaintInfo& paintInfo) if (!mapStartEndPositionsIntoFragmentCoordinates(fragment, fragmentStartPosition, fragmentEndPosition)) continue; - GraphicsContextStateSaver stateSaver(*paintInfo.context); + GraphicsContextStateSaver stateSaver(paintInfo.context()); fragment.buildFragmentTransform(fragmentTransform); if (!fragmentTransform.isIdentity()) - paintInfo.context->concatCTM(fragmentTransform); + paintInfo.context().concatCTM(fragmentTransform); - paintInfo.context->setFillColor(backgroundColor, style.colorSpace()); - paintInfo.context->fillRect(selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, &style), backgroundColor, style.colorSpace()); + paintInfo.context().setFillColor(backgroundColor); + paintInfo.context().fillRect(selectionRectForTextFragment(fragment, fragmentStartPosition, fragmentEndPosition, style), backgroundColor); m_paintingResourceMode = ApplyToDefaultMode; } @@ -240,7 +232,7 @@ void SVGInlineTextBox::paintSelectionBackground(PaintInfo& paintInfo) ASSERT(!m_paintingResource); } -void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUnit, LayoutUnit) +void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit, LayoutUnit) { ASSERT(paintInfo.shouldPaintWithinRoot(renderer())); ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection); @@ -252,9 +244,10 @@ void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUni // Note: We're explicitely not supporting composition & custom underlines and custom highlighters - unlike InlineTextBox. // If we ever need that for SVG, it's very easy to refactor and reuse the code. - RenderObject& parentRenderer = parent()->renderer(); + auto& parentRenderer = parent()->renderer(); bool paintSelectedTextOnly = paintInfo.phase == PaintPhaseSelection; + bool shouldPaintSelectionHighlight = !(paintInfo.paintBehavior & PaintBehaviorSkipSelectionHighlight); bool hasSelection = !parentRenderer.document().printing() && selectionState() != RenderObject::SelectionNone; if (!hasSelection && paintSelectedTextOnly) return; @@ -262,15 +255,15 @@ void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUni if (!textShouldBePainted(renderer())) return; - RenderStyle& style = parentRenderer.style(); + auto& style = parentRenderer.style(); const SVGRenderStyle& svgStyle = style.svgStyle(); bool hasFill = svgStyle.hasFill(); - bool hasVisibleStroke = svgStyle.hasVisibleStroke(); + bool hasVisibleStroke = style.hasVisibleStroke(); - RenderStyle* selectionStyle = &style; - if (hasSelection) { + const RenderStyle* selectionStyle = &style; + if (hasSelection && shouldPaintSelectionHighlight) { selectionStyle = parentRenderer.getCachedPseudoStyle(SELECTION); if (selectionStyle) { const SVGRenderStyle& svgSelectionStyle = selectionStyle->svgStyle(); @@ -278,7 +271,7 @@ void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUni if (!hasFill) hasFill = svgSelectionStyle.hasFill(); if (!hasVisibleStroke) - hasVisibleStroke = svgSelectionStyle.hasVisibleStroke(); + hasVisibleStroke = selectionStyle->hasVisibleStroke(); } else selectionStyle = &style; } @@ -294,51 +287,64 @@ void SVGInlineTextBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUni SVGTextFragment& fragment = m_textFragments.at(i); ASSERT(!m_paintingResource); - GraphicsContextStateSaver stateSaver(*paintInfo.context); + GraphicsContextStateSaver stateSaver(paintInfo.context()); fragment.buildFragmentTransform(fragmentTransform); if (!fragmentTransform.isIdentity()) - paintInfo.context->concatCTM(fragmentTransform); + paintInfo.context().concatCTM(fragmentTransform); // Spec: All text decorations except line-through should be drawn before the text is filled and stroked; thus, the text is rendered on top of these decorations. int decorations = style.textDecorationsInEffect(); if (decorations & TextDecorationUnderline) - paintDecoration(paintInfo.context, TextDecorationUnderline, fragment); + paintDecoration(paintInfo.context(), TextDecorationUnderline, fragment); if (decorations & TextDecorationOverline) - paintDecoration(paintInfo.context, TextDecorationOverline, fragment); - - // Fill text - if (hasFill) { - m_paintingResourceMode = ApplyToFillMode | ApplyToTextMode; - paintText(paintInfo.context, &style, selectionStyle, fragment, hasSelection, paintSelectedTextOnly); - } - - // Stroke text - if (hasVisibleStroke) { - m_paintingResourceMode = ApplyToStrokeMode | ApplyToTextMode; - paintText(paintInfo.context, &style, selectionStyle, fragment, hasSelection, paintSelectedTextOnly); + paintDecoration(paintInfo.context(), TextDecorationOverline, fragment); + + auto paintOrder = style.paintTypesForPaintOrder(); + for (unsigned i = 0; i < paintOrder.size(); ++i) { + switch (paintOrder.at(i)) { + case PaintTypeFill: + if (!hasFill) + continue; + m_paintingResourceMode = ApplyToFillMode | ApplyToTextMode; + ASSERT(selectionStyle); + paintText(paintInfo.context(), style, *selectionStyle, fragment, hasSelection, paintSelectedTextOnly); + break; + case PaintTypeStroke: + if (!hasVisibleStroke) + continue; + m_paintingResourceMode = ApplyToStrokeMode | ApplyToTextMode; + ASSERT(selectionStyle); + paintText(paintInfo.context(), style, *selectionStyle, fragment, hasSelection, paintSelectedTextOnly); + break; + case PaintTypeMarkers: + continue; + } } // Spec: Line-through should be drawn after the text is filled and stroked; thus, the line-through is rendered on top of the text. if (decorations & TextDecorationLineThrough) - paintDecoration(paintInfo.context, TextDecorationLineThrough, fragment); + paintDecoration(paintInfo.context(), TextDecorationLineThrough, fragment); m_paintingResourceMode = ApplyToDefaultMode; } + // Finally, paint the outline if any. + if (renderer().style().hasOutline() && is<RenderInline>(parentRenderer)) + downcast<RenderInline>(parentRenderer).paintOutline(paintInfo, paintOffset); + ASSERT(!m_paintingResource); } -bool SVGInlineTextBox::acquirePaintingResource(GraphicsContext*& context, float scalingFactor, RenderBoxModelObject& renderer, RenderStyle* style) +bool SVGInlineTextBox::acquirePaintingResource(GraphicsContext*& context, float scalingFactor, RenderBoxModelObject& renderer, const RenderStyle& style) { ASSERT(scalingFactor); - ASSERT(style); ASSERT(m_paintingResourceMode != ApplyToDefaultMode); Color fallbackColor; if (m_paintingResourceMode & ApplyToFillMode) - m_paintingResource = RenderSVGResource::fillPaintingResource(renderer, *style, fallbackColor); + m_paintingResource = RenderSVGResource::fillPaintingResource(renderer, style, fallbackColor); else if (m_paintingResourceMode & ApplyToStrokeMode) - m_paintingResource = RenderSVGResource::strokePaintingResource(renderer, *style, fallbackColor); + m_paintingResource = RenderSVGResource::strokePaintingResource(renderer, style, fallbackColor); else { // We're either called for stroking or filling. ASSERT_NOT_REACHED(); @@ -347,13 +353,13 @@ bool SVGInlineTextBox::acquirePaintingResource(GraphicsContext*& context, float if (!m_paintingResource) return false; - if (!m_paintingResource->applyResource(renderer, *style, context, m_paintingResourceMode)) { + if (!m_paintingResource->applyResource(renderer, style, context, m_paintingResourceMode)) { if (fallbackColor.isValid()) { RenderSVGResourceSolidColor* fallbackResource = RenderSVGResource::sharedSolidPaintingResource(); fallbackResource->setColor(fallbackColor); m_paintingResource = fallbackResource; - m_paintingResource->applyResource(renderer, *style, context, m_paintingResourceMode); + m_paintingResource->applyResource(renderer, style, context, m_paintingResourceMode); } } @@ -367,55 +373,28 @@ void SVGInlineTextBox::releasePaintingResource(GraphicsContext*& context, const { ASSERT(m_paintingResource); - m_paintingResource->postApplyResource(parent()->renderer(), context, m_paintingResourceMode, path, /*RenderSVGShape*/ 0); + m_paintingResource->postApplyResource(parent()->renderer(), context, m_paintingResourceMode, path, /*RenderSVGShape*/ nullptr); m_paintingResource = nullptr; } -bool SVGInlineTextBox::prepareGraphicsContextForTextPainting(GraphicsContext*& context, float scalingFactor, TextRun& textRun, RenderStyle* style) +bool SVGInlineTextBox::prepareGraphicsContextForTextPainting(GraphicsContext*& context, float scalingFactor, const RenderStyle& style) { - bool acquiredResource = acquirePaintingResource(context, scalingFactor, parent()->renderer(), style); - if (!acquiredResource) - return false; - -#if ENABLE(SVG_FONTS) - // SVG Fonts need access to the painting resource used to draw the current text chunk. - TextRun::RenderingContext* renderingContext = textRun.renderingContext(); - if (renderingContext) - static_cast<SVGTextRunRenderingContext*>(renderingContext)->setActivePaintingResource(m_paintingResource); -#endif - - return true; + return acquirePaintingResource(context, scalingFactor, parent()->renderer(), style); } -void SVGInlineTextBox::restoreGraphicsContextAfterTextPainting(GraphicsContext*& context, TextRun& textRun) +void SVGInlineTextBox::restoreGraphicsContextAfterTextPainting(GraphicsContext*& context) { - releasePaintingResource(context, /* path */0); - -#if ENABLE(SVG_FONTS) - TextRun::RenderingContext* renderingContext = textRun.renderingContext(); - if (renderingContext) - static_cast<SVGTextRunRenderingContext*>(renderingContext)->setActivePaintingResource(0); -#else - UNUSED_PARAM(textRun); -#endif + releasePaintingResource(context, /* path */nullptr); } -TextRun SVGInlineTextBox::constructTextRun(RenderStyle* style, const SVGTextFragment& fragment) const +TextRun SVGInlineTextBox::constructTextRun(const RenderStyle& style, const SVGTextFragment& fragment) const { - ASSERT(style); - - TextRun run(renderer().deprecatedCharacters() + fragment.characterOffset - , fragment.length + TextRun run(StringView(renderer().text()).substring(fragment.characterOffset, fragment.length) , 0 /* xPos, only relevant with allowTabs=true */ , 0 /* padding, only relevant for justified text, not relevant for SVG */ - , TextRun::AllowTrailingExpansion + , AllowTrailingExpansion , direction() - , dirOverride() || style->rtlOrdering() == VisualOrder /* directionalOverride */); - - if (style->font().isSVGFont()) - run.setRenderingContext(SVGTextRunRenderingContext::create(renderer())); - - run.disableRoundingHacks(); + , dirOverride() || style.rtlOrdering() == VisualOrder /* directionalOverride */); // We handle letter & word spacing ourselves. run.disableSpacing(); @@ -426,21 +405,24 @@ TextRun SVGInlineTextBox::constructTextRun(RenderStyle* style, const SVGTextFrag return run; } -bool SVGInlineTextBox::mapStartEndPositionsIntoFragmentCoordinates(const SVGTextFragment& fragment, int& startPosition, int& endPosition) const +bool SVGInlineTextBox::mapStartEndPositionsIntoFragmentCoordinates(const SVGTextFragment& fragment, unsigned& startPosition, unsigned& endPosition) const { if (startPosition >= endPosition) return false; - int offset = static_cast<int>(fragment.characterOffset) - start(); - int length = static_cast<int>(fragment.length); + ASSERT(fragment.characterOffset >= start()); + unsigned offset = fragment.characterOffset - start(); + unsigned length = fragment.length; if (startPosition >= offset + length || endPosition <= offset) return false; if (startPosition < offset) startPosition = 0; - else + else { + ASSERT(startPosition >= offset); startPosition -= offset; + } if (endPosition > offset + length) endPosition = length; @@ -468,7 +450,7 @@ static inline float positionOffsetForDecoration(TextDecoration decoration, const return 0.0f; } -static inline float thicknessForDecoration(TextDecoration, const Font& font) +static inline float thicknessForDecoration(TextDecoration, const FontCascade& font) { // FIXME: For SVG Fonts we need to use the attributes defined in the <font-face> if specified. // Compatible with Batik/Opera @@ -492,7 +474,7 @@ static inline RenderBoxModelObject& findRendererDefininingTextDecoration(InlineF return *renderer; } -void SVGInlineTextBox::paintDecoration(GraphicsContext* context, TextDecoration decoration, const SVGTextFragment& fragment) +void SVGInlineTextBox::paintDecoration(GraphicsContext& context, TextDecoration decoration, const SVGTextFragment& fragment) { if (renderer().style().textDecorationsInEffect() == TextDecorationNone) return; @@ -507,7 +489,7 @@ void SVGInlineTextBox::paintDecoration(GraphicsContext* context, TextDecoration const SVGRenderStyle& svgDecorationStyle = decorationStyle.svgStyle(); bool hasDecorationFill = svgDecorationStyle.hasFill(); - bool hasVisibleDecorationStroke = svgDecorationStyle.hasVisibleStroke(); + bool hasVisibleDecorationStroke = decorationStyle.hasVisibleStroke(); if (hasDecorationFill) { m_paintingResourceMode = ApplyToFillMode; @@ -520,16 +502,16 @@ void SVGInlineTextBox::paintDecoration(GraphicsContext* context, TextDecoration } } -void SVGInlineTextBox::paintDecorationWithStyle(GraphicsContext* context, TextDecoration decoration, const SVGTextFragment& fragment, RenderBoxModelObject& decorationRenderer) +void SVGInlineTextBox::paintDecorationWithStyle(GraphicsContext& context, TextDecoration decoration, const SVGTextFragment& fragment, RenderBoxModelObject& decorationRenderer) { ASSERT(!m_paintingResource); ASSERT(m_paintingResourceMode != ApplyToDefaultMode); - RenderStyle& decorationStyle = decorationRenderer.style(); + auto& decorationStyle = decorationRenderer.style(); float scalingFactor = 1; - Font scaledFont; - RenderSVGInlineText::computeNewScaledFontForStyle(&decorationRenderer, &decorationStyle, scalingFactor, scaledFont); + FontCascade scaledFont; + RenderSVGInlineText::computeNewScaledFontForStyle(decorationRenderer, decorationStyle, scalingFactor, scaledFont); ASSERT(scalingFactor); // The initial y value refers to overline position. @@ -542,11 +524,11 @@ void SVGInlineTextBox::paintDecorationWithStyle(GraphicsContext* context, TextDe float width = fragment.width; const FontMetrics& scaledFontMetrics = scaledFont.fontMetrics(); - GraphicsContextStateSaver stateSaver(*context); + GraphicsContextStateSaver stateSaver(context); if (scalingFactor != 1) { width *= scalingFactor; - decorationOrigin.scale(scalingFactor, scalingFactor); - context->scale(FloatSize(1 / scalingFactor, 1 / scalingFactor)); + decorationOrigin.scale(scalingFactor); + context.scale(1 / scalingFactor); } decorationOrigin.move(0, -scaledFontMetrics.floatAscent() + positionOffsetForDecoration(decoration, scaledFontMetrics, thickness)); @@ -554,66 +536,62 @@ void SVGInlineTextBox::paintDecorationWithStyle(GraphicsContext* context, TextDe Path path; path.addRect(FloatRect(decorationOrigin, FloatSize(width, thickness))); - if (acquirePaintingResource(context, scalingFactor, decorationRenderer, &decorationStyle)) - releasePaintingResource(context, &path); + GraphicsContext* contextPtr = &context; + if (acquirePaintingResource(contextPtr, scalingFactor, decorationRenderer, decorationStyle)) + releasePaintingResource(contextPtr, &path); } -void SVGInlineTextBox::paintTextWithShadows(GraphicsContext* context, RenderStyle* style, TextRun& textRun, const SVGTextFragment& fragment, int startPosition, int endPosition) +void SVGInlineTextBox::paintTextWithShadows(GraphicsContext& context, const RenderStyle& style, TextRun& textRun, const SVGTextFragment& fragment, unsigned startPosition, unsigned endPosition) { float scalingFactor = renderer().scalingFactor(); ASSERT(scalingFactor); - const Font& scaledFont = renderer().scaledFont(); - const ShadowData* shadow = style->textShadow(); + const FontCascade& scaledFont = renderer().scaledFont(); + const ShadowData* shadow = style.textShadow(); FloatPoint textOrigin(fragment.x, fragment.y); FloatSize textSize(fragment.width, fragment.height); if (scalingFactor != 1) { - textOrigin.scale(scalingFactor, scalingFactor); + textOrigin.scale(scalingFactor); textSize.scale(scalingFactor); } FloatRect shadowRect(FloatPoint(textOrigin.x(), textOrigin.y() - scaledFont.fontMetrics().floatAscent()), textSize); + GraphicsContext* usedContext = &context; do { - if (!prepareGraphicsContextForTextPainting(context, scalingFactor, textRun, style)) + if (!prepareGraphicsContextForTextPainting(usedContext, scalingFactor, style)) break; - FloatSize extraOffset; - if (shadow) - extraOffset = applyShadowToGraphicsContext(context, shadow, shadowRect, false /* stroked */, true /* opaque */, true /* horizontal */); + { + ShadowApplier shadowApplier(*usedContext, shadow, shadowRect); - context->save(); - context->scale(FloatSize(1 / scalingFactor, 1 / scalingFactor)); + if (!shadowApplier.didSaveContext()) + usedContext->save(); + usedContext->scale(1 / scalingFactor); - scaledFont.drawText(context, textRun, textOrigin + extraOffset, startPosition, endPosition); + scaledFont.drawText(*usedContext, textRun, textOrigin + shadowApplier.extraOffset(), startPosition, endPosition); - context->restore(); + if (!shadowApplier.didSaveContext()) + usedContext->restore(); + } - restoreGraphicsContextAfterTextPainting(context, textRun); + restoreGraphicsContextAfterTextPainting(usedContext); if (!shadow) break; - if (shadow->next()) - context->restore(); - else - context->clearShadow(); - shadow = shadow->next(); } while (shadow); } -void SVGInlineTextBox::paintText(GraphicsContext* context, RenderStyle* style, RenderStyle* selectionStyle, const SVGTextFragment& fragment, bool hasSelection, bool paintSelectedTextOnly) +void SVGInlineTextBox::paintText(GraphicsContext& context, const RenderStyle& style, const RenderStyle& selectionStyle, const SVGTextFragment& fragment, bool hasSelection, bool paintSelectedTextOnly) { - ASSERT(style); - ASSERT(selectionStyle); - - int startPosition = 0; - int endPosition = 0; + unsigned startPosition = 0; + unsigned endPosition = 0; if (hasSelection) { - selectionStartEnd(startPosition, endPosition); + std::tie(startPosition, endPosition) = selectionStartEnd(); hasSelection = mapStartEndPositionsIntoFragmentCoordinates(fragment, startPosition, endPosition); } @@ -630,16 +608,15 @@ void SVGInlineTextBox::paintText(GraphicsContext* context, RenderStyle* style, R // Draw text using selection style from the start to the end position of the selection if (style != selectionStyle) - SVGResourcesCache::clientStyleChanged(parent()->renderer(), StyleDifferenceRepaint, *selectionStyle); + SVGResourcesCache::clientStyleChanged(parent()->renderer(), StyleDifferenceRepaint, selectionStyle); - TextRun selectionTextRun = constructTextRun(selectionStyle, fragment); paintTextWithShadows(context, selectionStyle, textRun, fragment, startPosition, endPosition); if (style != selectionStyle) - SVGResourcesCache::clientStyleChanged(parent()->renderer(), StyleDifferenceRepaint, *style); + SVGResourcesCache::clientStyleChanged(parent()->renderer(), StyleDifferenceRepaint, style); // Eventually draw text using regular style from the end position of the selection to the end of the current chunk part - if (endPosition < static_cast<int>(fragment.length) && !paintSelectedTextOnly) + if (endPosition < fragment.length && !paintSelectedTextOnly) paintTextWithShadows(context, style, textRun, fragment, endPosition, fragment.length); } @@ -667,7 +644,7 @@ FloatRect SVGInlineTextBox::calculateBoundaries() const return textRect; } -bool SVGInlineTextBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit, LayoutUnit) +bool SVGInlineTextBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit, LayoutUnit, HitTestAction) { // FIXME: integrate with InlineTextBox::nodeAtPoint better. ASSERT(!isLineBreak()); @@ -681,9 +658,25 @@ bool SVGInlineTextBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& boxOrigin.moveBy(accumulatedOffset); FloatRect rect(boxOrigin, size()); if (locationInContainer.intersects(rect)) { - renderer().updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); - if (!result.addNodeToRectBasedTestResult(&renderer().textNode(), request, locationInContainer, rect)) - return true; + + float scalingFactor = renderer().scalingFactor(); + ASSERT(scalingFactor); + + float baseline = renderer().scaledFont().fontMetrics().floatAscent() / scalingFactor; + + AffineTransform fragmentTransform; + for (auto& fragment : m_textFragments) { + FloatQuad fragmentQuad(FloatRect(fragment.x, fragment.y - baseline, fragment.width, fragment.height)); + fragment.buildFragmentTransform(fragmentTransform); + if (!fragmentTransform.isIdentity()) + fragmentQuad = fragmentTransform.mapQuad(fragmentQuad); + + if (fragmentQuad.containsPoint(locationInContainer.point())) { + renderer().updateHitTestResult(result, locationInContainer.point() - toLayoutSize(accumulatedOffset)); + if (!result.addNodeToRectBasedTestResult(&renderer().textNode(), request, locationInContainer, rect)) + return true; + } + } } } } @@ -691,5 +684,3 @@ bool SVGInlineTextBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& } } // namespace WebCore - -#endif diff --git a/Source/WebCore/rendering/svg/SVGInlineTextBox.h b/Source/WebCore/rendering/svg/SVGInlineTextBox.h index 97df4d698..217bac12e 100644 --- a/Source/WebCore/rendering/svg/SVGInlineTextBox.h +++ b/Source/WebCore/rendering/svg/SVGInlineTextBox.h @@ -19,10 +19,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef SVGInlineTextBox_h -#define SVGInlineTextBox_h +#pragma once -#if ENABLE(SVG) #include "InlineTextBox.h" #include "SVGTextLayoutEngine.h" #include "RenderSVGInlineText.h" @@ -36,54 +34,54 @@ class SVGInlineTextBox final : public InlineTextBox { public: explicit SVGInlineTextBox(RenderSVGInlineText&); - RenderSVGInlineText& renderer() const { return toRenderSVGInlineText(InlineTextBox::renderer()); } + RenderSVGInlineText& renderer() const { return downcast<RenderSVGInlineText>(InlineTextBox::renderer()); } - virtual float virtualLogicalHeight() const { return m_logicalHeight; } + float virtualLogicalHeight() const override { return m_logicalHeight; } void setLogicalHeight(float height) { m_logicalHeight = height; } - virtual int selectionTop() { return top(); } - virtual int selectionHeight() { return static_cast<int>(ceilf(m_logicalHeight)); } - virtual int offsetForPosition(float x, bool includePartialGlyphs = true) const; - virtual float positionForOffset(int offset) const; + int selectionTop() { return top(); } + int selectionHeight() { return static_cast<int>(ceilf(m_logicalHeight)); } + int offsetForPosition(float x, bool includePartialGlyphs = true) const override; + float positionForOffset(unsigned offset) const override; void paintSelectionBackground(PaintInfo&); - virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom); - virtual LayoutRect localSelectionRect(int startPosition, int endPosition) const override; + void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) override; + LayoutRect localSelectionRect(unsigned startPosition, unsigned endPosition) const override; - bool mapStartEndPositionsIntoFragmentCoordinates(const SVGTextFragment&, int& startPosition, int& endPosition) const; + bool mapStartEndPositionsIntoFragmentCoordinates(const SVGTextFragment&, unsigned& startPosition, unsigned& endPosition) const; - virtual FloatRect calculateBoundaries() const; + FloatRect calculateBoundaries() const override; void clearTextFragments() { m_textFragments.clear(); } Vector<SVGTextFragment>& textFragments() { return m_textFragments; } const Vector<SVGTextFragment>& textFragments() const { return m_textFragments; } - virtual void dirtyOwnLineBoxes() override final; - virtual void dirtyLineBoxes() override final; + void dirtyOwnLineBoxes() override; + void dirtyLineBoxes() override; bool startsNewTextChunk() const { return m_startsNewTextChunk; } void setStartsNewTextChunk(bool newTextChunk) { m_startsNewTextChunk = newTextChunk; } int offsetForPositionInFragment(const SVGTextFragment&, float position, bool includePartialGlyphs) const; - FloatRect selectionRectForTextFragment(const SVGTextFragment&, int fragmentStartPosition, int fragmentEndPosition, RenderStyle*) const; + FloatRect selectionRectForTextFragment(const SVGTextFragment&, unsigned fragmentStartPosition, unsigned fragmentEndPosition, const RenderStyle&) const; private: - virtual bool isSVGInlineTextBox() const override { return true; } + bool isSVGInlineTextBox() const override { return true; } - TextRun constructTextRun(RenderStyle*, const SVGTextFragment&) const; + TextRun constructTextRun(const RenderStyle&, const SVGTextFragment&) const; - bool acquirePaintingResource(GraphicsContext*&, float scalingFactor, RenderBoxModelObject&, RenderStyle*); + bool acquirePaintingResource(GraphicsContext*&, float scalingFactor, RenderBoxModelObject&, const RenderStyle&); void releasePaintingResource(GraphicsContext*&, const Path*); - bool prepareGraphicsContextForTextPainting(GraphicsContext*&, float scalingFactor, TextRun&, RenderStyle*); - void restoreGraphicsContextAfterTextPainting(GraphicsContext*&, TextRun&); + bool prepareGraphicsContextForTextPainting(GraphicsContext*&, float scalingFactor, const RenderStyle&); + void restoreGraphicsContextAfterTextPainting(GraphicsContext*&); - void paintDecoration(GraphicsContext*, TextDecoration, const SVGTextFragment&); - void paintDecorationWithStyle(GraphicsContext*, TextDecoration, const SVGTextFragment&, RenderBoxModelObject& decorationRenderer); - void paintTextWithShadows(GraphicsContext*, RenderStyle*, TextRun&, const SVGTextFragment&, int startPosition, int endPosition); - void paintText(GraphicsContext*, RenderStyle*, RenderStyle* selectionStyle, const SVGTextFragment&, bool hasSelection, bool paintSelectedTextOnly); + void paintDecoration(GraphicsContext&, TextDecoration, const SVGTextFragment&); + void paintDecorationWithStyle(GraphicsContext&, TextDecoration, const SVGTextFragment&, RenderBoxModelObject& decorationRenderer); + void paintTextWithShadows(GraphicsContext&, const RenderStyle&, TextRun&, const SVGTextFragment&, unsigned startPosition, unsigned endPosition); + void paintText(GraphicsContext&, const RenderStyle&, const RenderStyle& selectionStyle, const SVGTextFragment&, bool hasSelection, bool paintSelectedTextOnly); - virtual bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom) override; + bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom, HitTestAction) override; private: float m_logicalHeight; @@ -93,9 +91,6 @@ private: Vector<SVGTextFragment> m_textFragments; }; -INLINE_BOX_OBJECT_TYPE_CASTS(SVGInlineTextBox, isSVGInlineTextBox()) - } // namespace WebCore -#endif -#endif // SVGInlineTextBox_h +SPECIALIZE_TYPE_TRAITS_INLINE_BOX(SVGInlineTextBox, isSVGInlineTextBox()) diff --git a/Source/WebCore/rendering/svg/SVGMarkerData.h b/Source/WebCore/rendering/svg/SVGMarkerData.h index 5d5a86d98..53da371f7 100644 --- a/Source/WebCore/rendering/svg/SVGMarkerData.h +++ b/Source/WebCore/rendering/svg/SVGMarkerData.h @@ -17,13 +17,10 @@ * Boston, MA 02110-1301, USA. */ -#ifndef SVGMarkerData_h -#define SVGMarkerData_h +#pragma once -#if ENABLE(SVG) #include "FloatConversion.h" #include "Path.h" -#include <wtf/MathExtras.h> namespace WebCore { @@ -50,28 +47,27 @@ struct MarkerPosition { class SVGMarkerData { public: - SVGMarkerData(Vector<MarkerPosition>& positions) + SVGMarkerData(Vector<MarkerPosition>& positions, bool reverseStart) : m_positions(positions) , m_elementIndex(0) + , m_reverseStart(reverseStart) { } - static void updateFromPathElement(void* info, const PathElement* element) + static void updateFromPathElement(SVGMarkerData& markerData, const PathElement& element) { - SVGMarkerData* markerData = static_cast<SVGMarkerData*>(info); - // First update the outslope for the previous element. - markerData->updateOutslope(element->points[0]); + markerData.updateOutslope(element.points[0]); // Record the marker for the previous element. - if (markerData->m_elementIndex > 0) { - SVGMarkerType markerType = markerData->m_elementIndex == 1 ? StartMarker : MidMarker; - markerData->m_positions.append(MarkerPosition(markerType, markerData->m_origin, markerData->currentAngle(markerType))); + if (markerData.m_elementIndex > 0) { + SVGMarkerType markerType = markerData.m_elementIndex == 1 ? StartMarker : MidMarker; + markerData.m_positions.append(MarkerPosition(markerType, markerData.m_origin, markerData.currentAngle(markerType))); } // Update our marker data for this element. - markerData->updateMarkerDataForPathElement(element); - ++markerData->m_elementIndex; + markerData.updateMarkerDataForPathElement(element); + ++markerData.m_elementIndex; } void pathIsDone() @@ -91,6 +87,8 @@ private: switch (type) { case StartMarker: + if (m_reverseStart) + return narrowPrecisionToFloat(outAngle - 180); return narrowPrecisionToFloat(outAngle); case MidMarker: // WK193015: Prevent bugs due to angles being non-continuous. @@ -111,11 +109,11 @@ private: m_outslopePoints[1] = point; } - void updateMarkerDataForPathElement(const PathElement* element) + void updateMarkerDataForPathElement(const PathElement& element) { - FloatPoint* points = element->points; + FloatPoint* points = element.points; - switch (element->type) { + switch (element.type) { case PathElementAddQuadCurveToPoint: // FIXME: https://bugs.webkit.org/show_bug.cgi?id=33115 (PathElementAddQuadCurveToPoint not handled for <marker>) m_origin = points[1]; @@ -151,9 +149,7 @@ private: FloatPoint m_subpathStart; FloatPoint m_inslopePoints[2]; FloatPoint m_outslopePoints[2]; + bool m_reverseStart; }; -} - -#endif // ENABLE(SVG) -#endif // SVGMarkerData_h +} // namespace WebCore diff --git a/Source/WebCore/rendering/svg/SVGPathData.cpp b/Source/WebCore/rendering/svg/SVGPathData.cpp index 01ef871f7..6eeb5476c 100644 --- a/Source/WebCore/rendering/svg/SVGPathData.cpp +++ b/Source/WebCore/rendering/svg/SVGPathData.cpp @@ -20,14 +20,18 @@ #include "config.h" #include "SVGPathData.h" -#if ENABLE(SVG) #include "Path.h" +#include "RenderElement.h" +#include "RenderStyle.h" #include "SVGCircleElement.h" #include "SVGEllipseElement.h" +#include "SVGLengthContext.h" #include "SVGLineElement.h" #include "SVGNames.h" #include "SVGPathElement.h" #include "SVGPathUtilities.h" +#include "SVGPoint.h" +#include "SVGPointList.h" #include "SVGPolygonElement.h" #include "SVGPolylineElement.h" #include "SVGRectElement.h" @@ -37,32 +41,42 @@ namespace WebCore { static void updatePathFromCircleElement(SVGElement* element, Path& path) { - ASSERT(isSVGCircleElement(element)); - SVGCircleElement* circle = toSVGCircleElement(element); + ASSERT(is<SVGCircleElement>(element)); SVGLengthContext lengthContext(element); - float r = circle->r().value(lengthContext); - if (r > 0) - path.addEllipse(FloatRect(circle->cx().value(lengthContext) - r, circle->cy().value(lengthContext) - r, r * 2, r * 2)); + RenderElement* renderer = element->renderer(); + if (!renderer) + return; + auto& style = renderer->style(); + float r = lengthContext.valueForLength(style.svgStyle().r()); + if (r > 0) { + float cx = lengthContext.valueForLength(style.svgStyle().cx(), LengthModeWidth); + float cy = lengthContext.valueForLength(style.svgStyle().cy(), LengthModeHeight); + path.addEllipse(FloatRect(cx - r, cy - r, r * 2, r * 2)); + } } static void updatePathFromEllipseElement(SVGElement* element, Path& path) { - SVGEllipseElement* ellipse = toSVGEllipseElement(element); - + RenderElement* renderer = element->renderer(); + if (!renderer) + return; + auto& style = renderer->style(); SVGLengthContext lengthContext(element); - float rx = ellipse->rx().value(lengthContext); + float rx = lengthContext.valueForLength(style.svgStyle().rx(), LengthModeWidth); if (rx <= 0) return; - float ry = ellipse->ry().value(lengthContext); + float ry = lengthContext.valueForLength(style.svgStyle().ry(), LengthModeHeight); if (ry <= 0) return; - path.addEllipse(FloatRect(ellipse->cx().value(lengthContext) - rx, ellipse->cy().value(lengthContext) - ry, rx * 2, ry * 2)); + float cx = lengthContext.valueForLength(style.svgStyle().cx(), LengthModeWidth); + float cy = lengthContext.valueForLength(style.svgStyle().cy(), LengthModeHeight); + path.addEllipse(FloatRect(cx - rx, cy - ry, rx * 2, ry * 2)); } static void updatePathFromLineElement(SVGElement* element, Path& path) { - SVGLineElement* line = toSVGLineElement(element); + SVGLineElement* line = downcast<SVGLineElement>(element); SVGLengthContext lengthContext(element); path.moveTo(FloatPoint(line->x1().value(lengthContext), line->y1().value(lengthContext))); @@ -71,12 +85,12 @@ static void updatePathFromLineElement(SVGElement* element, Path& path) static void updatePathFromPathElement(SVGElement* element, Path& path) { - buildPathFromByteStream(toSVGPathElement(element)->pathByteStream(), path); + buildPathFromByteStream(downcast<SVGPathElement>(element)->pathByteStream(), path); } static void updatePathFromPolygonElement(SVGElement* element, Path& path) { - SVGPointList& points = toSVGPolygonElement(element)->animatedPoints()->values(); + auto& points = downcast<SVGPolygonElement>(element)->animatedPoints()->values(); if (points.isEmpty()) return; @@ -91,7 +105,7 @@ static void updatePathFromPolygonElement(SVGElement* element, Path& path) static void updatePathFromPolylineElement(SVGElement* element, Path& path) { - SVGPointList& points = toSVGPolylineElement(element)->animatedPoints()->values(); + auto& points = downcast<SVGPolylineElement>(element)->animatedPoints()->values(); if (points.isEmpty()) return; @@ -104,19 +118,22 @@ static void updatePathFromPolylineElement(SVGElement* element, Path& path) static void updatePathFromRectElement(SVGElement* element, Path& path) { - SVGRectElement* rect = toSVGRectElement(element); + RenderElement* renderer = element->renderer(); + if (!renderer) + return; + auto& style = renderer->style(); SVGLengthContext lengthContext(element); - float width = rect->width().value(lengthContext); + float width = lengthContext.valueForLength(style.width(), LengthModeWidth); if (width <= 0) return; - float height = rect->height().value(lengthContext); + float height = lengthContext.valueForLength(style.height(), LengthModeHeight); if (height <= 0) return; - float x = rect->x().value(lengthContext); - float y = rect->y().value(lengthContext); - float rx = rect->rx().value(lengthContext); - float ry = rect->ry().value(lengthContext); + float x = lengthContext.valueForLength(style.svgStyle().x(), LengthModeWidth); + float y = lengthContext.valueForLength(style.svgStyle().y(), LengthModeHeight); + float rx = lengthContext.valueForLength(style.svgStyle().rx(), LengthModeWidth); + float ry = lengthContext.valueForLength(style.svgStyle().ry(), LengthModeHeight); bool hasRx = rx > 0; bool hasRy = ry > 0; if (hasRx || hasRy) { @@ -143,13 +160,13 @@ void updatePathFromGraphicsElement(SVGElement* element, Path& path) static HashMap<AtomicStringImpl*, PathUpdateFunction>* map = 0; if (!map) { map = new HashMap<AtomicStringImpl*, PathUpdateFunction>; - map->set(SVGNames::circleTag.localName().impl(), &updatePathFromCircleElement); - map->set(SVGNames::ellipseTag.localName().impl(), &updatePathFromEllipseElement); - map->set(SVGNames::lineTag.localName().impl(), &updatePathFromLineElement); - map->set(SVGNames::pathTag.localName().impl(), &updatePathFromPathElement); - map->set(SVGNames::polygonTag.localName().impl(), &updatePathFromPolygonElement); - map->set(SVGNames::polylineTag.localName().impl(), &updatePathFromPolylineElement); - map->set(SVGNames::rectTag.localName().impl(), &updatePathFromRectElement); + map->set(SVGNames::circleTag.localName().impl(), updatePathFromCircleElement); + map->set(SVGNames::ellipseTag.localName().impl(), updatePathFromEllipseElement); + map->set(SVGNames::lineTag.localName().impl(), updatePathFromLineElement); + map->set(SVGNames::pathTag.localName().impl(), updatePathFromPathElement); + map->set(SVGNames::polygonTag.localName().impl(), updatePathFromPolygonElement); + map->set(SVGNames::polylineTag.localName().impl(), updatePathFromPolylineElement); + map->set(SVGNames::rectTag.localName().impl(), updatePathFromRectElement); } if (PathUpdateFunction pathUpdateFunction = map->get(element->localName().impl())) @@ -157,5 +174,3 @@ void updatePathFromGraphicsElement(SVGElement* element, Path& path) } } // namespace WebCore - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/SVGPathData.h b/Source/WebCore/rendering/svg/SVGPathData.h index 1a4b7ba89..9da6bad30 100644 --- a/Source/WebCore/rendering/svg/SVGPathData.h +++ b/Source/WebCore/rendering/svg/SVGPathData.h @@ -17,10 +17,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef SVGPathData_h -#define SVGPathData_h +#pragma once -#if ENABLE(SVG) namespace WebCore { class SVGElement; @@ -28,7 +26,4 @@ class Path; void updatePathFromGraphicsElement(SVGElement*, Path&); -}; - -#endif // ENABLE(SVG) -#endif // SVGPathData_h +} // namespace WebCore diff --git a/Source/WebCore/rendering/svg/SVGRenderSupport.cpp b/Source/WebCore/rendering/svg/SVGRenderSupport.cpp index 9602927f2..0113c7015 100644 --- a/Source/WebCore/rendering/svg/SVGRenderSupport.cpp +++ b/Source/WebCore/rendering/svg/SVGRenderSupport.cpp @@ -23,21 +23,22 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "SVGRenderSupport.h" #include "NodeRenderStyle.h" +#include "RenderChildIterator.h" #include "RenderElement.h" #include "RenderGeometryMap.h" #include "RenderIterator.h" #include "RenderLayer.h" +#include "RenderSVGImage.h" #include "RenderSVGResourceClipper.h" #include "RenderSVGResourceFilter.h" #include "RenderSVGResourceMarker.h" #include "RenderSVGResourceMasker.h" #include "RenderSVGRoot.h" #include "RenderSVGText.h" +#include "RenderSVGTransformableContainer.h" #include "RenderSVGViewportContainer.h" #include "SVGResources.h" #include "SVGResourcesCache.h" @@ -49,8 +50,8 @@ FloatRect SVGRenderSupport::repaintRectForRendererInLocalCoordinatesExcludingSVG { // FIXME: Add support for RenderSVGBlock. - if (renderer.isSVGShape() || renderer.isSVGImage() || renderer.isSVGContainer()) - return toRenderSVGModelObject(renderer).repaintRectInLocalCoordinatesExcludingSVGShadow(); + if (is<RenderSVGModelObject>(renderer)) + return downcast<RenderSVGModelObject>(renderer).repaintRectInLocalCoordinatesExcludingSVGShadow(); return renderer.repaintRectInLocalCoordinates(); } @@ -67,34 +68,43 @@ LayoutRect SVGRenderSupport::clippedOverflowRectForRepaint(const RenderElement& const SVGRenderStyle& svgStyle = renderer.style().svgStyle(); if (const ShadowData* shadow = svgStyle.shadow()) shadow->adjustRectForShadow(repaintRect); - renderer.computeFloatRectForRepaint(repaintContainer, repaintRect); - return enclosingLayoutRect(repaintRect); + return enclosingLayoutRect(renderer.computeFloatRectForRepaint(repaintRect, repaintContainer)); } -void SVGRenderSupport::computeFloatRectForRepaint(const RenderElement& renderer, const RenderLayerModelObject* repaintContainer, FloatRect& repaintRect, bool fixed) +FloatRect SVGRenderSupport::computeFloatRectForRepaint(const RenderElement& renderer, const FloatRect& repaintRect, const RenderLayerModelObject* repaintContainer, bool fixed) { + FloatRect adjustedRect = repaintRect; const SVGRenderStyle& svgStyle = renderer.style().svgStyle(); if (const ShadowData* shadow = svgStyle.shadow()) - shadow->adjustRectForShadow(repaintRect); - repaintRect.inflate(renderer.style().outlineWidth()); + shadow->adjustRectForShadow(adjustedRect); + adjustedRect.inflate(renderer.style().outlineWidth()); // Translate to coords in our parent renderer, and then call computeFloatRectForRepaint() on our parent. - repaintRect = renderer.localToParentTransform().mapRect(repaintRect); - renderer.parent()->computeFloatRectForRepaint(repaintContainer, repaintRect, fixed); + adjustedRect = renderer.localToParentTransform().mapRect(adjustedRect); + return renderer.parent()->computeFloatRectForRepaint(adjustedRect, repaintContainer, fixed); } -void SVGRenderSupport::mapLocalToContainer(const RenderElement& renderer, const RenderLayerModelObject* repaintContainer, TransformState& transformState, bool* wasFixed) +const RenderElement& SVGRenderSupport::localToParentTransform(const RenderElement& renderer, AffineTransform &transform) { - transformState.applyTransform(renderer.localToParentTransform()); - ASSERT(renderer.parent()); auto& parent = *renderer.parent(); - - // At the SVG/HTML boundary (aka RenderSVGRoot), we apply the localToBorderBoxTransform + + // At the SVG/HTML boundary (aka RenderSVGRoot), we apply the localToBorderBoxTransform // to map an element from SVG viewport coordinates to CSS box coordinates. - // RenderSVGRoot's mapLocalToContainer method expects CSS box coordinates. - if (parent.isSVGRoot()) - transformState.applyTransform(toRenderSVGRoot(parent).localToBorderBoxTransform()); + if (is<RenderSVGRoot>(parent)) + transform = downcast<RenderSVGRoot>(parent).localToBorderBoxTransform() * renderer.localToParentTransform(); + else + transform = renderer.localToParentTransform(); + + return parent; +} + +void SVGRenderSupport::mapLocalToContainer(const RenderElement& renderer, const RenderLayerModelObject* repaintContainer, TransformState& transformState, bool* wasFixed) +{ + AffineTransform transform; + auto& parent = localToParentTransform(renderer, transform); + + transformState.applyTransform(transform); MapCoordinatesFlags mode = UseTransforms; parent.mapLocalToContainer(repaintContainer, transformState, mode, wasFixed); @@ -104,19 +114,10 @@ const RenderElement* SVGRenderSupport::pushMappingToContainer(const RenderElemen { ASSERT_UNUSED(ancestorToStopAt, ancestorToStopAt != &renderer); - ASSERT(renderer.parent()); - auto& parent = *renderer.parent(); - - // At the SVG/HTML boundary (aka RenderSVGRoot), we apply the localToBorderBoxTransform - // to map an element from SVG viewport coordinates to CSS box coordinates. - // RenderSVGRoot's mapLocalToContainer method expects CSS box coordinates. - if (parent.isSVGRoot()) { - TransformationMatrix matrix(renderer.localToParentTransform()); - matrix.multiply(toRenderSVGRoot(parent).localToBorderBoxTransform()); - geometryMap.push(&renderer, matrix); - } else - geometryMap.push(&renderer, renderer.localToParentTransform()); + AffineTransform transform; + auto& parent = localToParentTransform(renderer, transform); + geometryMap.push(&renderer, transform); return &parent; } @@ -127,13 +128,13 @@ bool SVGRenderSupport::checkForSVGRepaintDuringLayout(const RenderElement& rende // When a parent container is transformed in SVG, all children will be painted automatically // so we are able to skip redundant repaint checks. auto parent = renderer.parent(); - return !(parent && parent->isSVGContainer() && toRenderSVGContainer(parent)->didTransformToRootUpdate()); + return !(is<RenderSVGContainer>(parent) && downcast<RenderSVGContainer>(*parent).didTransformToRootUpdate()); } // Update a bounding box taking into account the validity of the other bounding box. -static inline void updateObjectBoundingBox(FloatRect& objectBoundingBox, bool& objectBoundingBoxValid, RenderObject* other, FloatRect otherBoundingBox) +static inline void updateObjectBoundingBox(FloatRect& objectBoundingBox, bool& objectBoundingBoxValid, const RenderObject* other, FloatRect otherBoundingBox) { - bool otherValid = other->isSVGContainer() ? toRenderSVGContainer(other)->isObjectBoundingBoxValid() : true; + bool otherValid = is<RenderSVGContainer>(*other) ? downcast<RenderSVGContainer>(*other).isObjectBoundingBoxValid() : true; if (!otherValid) return; @@ -155,17 +156,21 @@ void SVGRenderSupport::computeContainerBoundingBoxes(const RenderElement& contai // When computing the strokeBoundingBox, we use the repaintRects of the container's children so that the container's stroke includes // the resources applied to the children (such as clips and filters). This allows filters applied to containers to correctly bound // the children, and also improves inlining of SVG content, as the stroke bound is used in that situation also. - for (RenderObject* current = container.firstChild(); current; current = current->nextSibling()) { - if (current->isSVGHiddenContainer()) + for (auto& current : childrenOfType<RenderObject>(container)) { + if (current.isSVGHiddenContainer()) + continue; + + // Don't include elements in the union that do not render. + if (is<RenderSVGShape>(current) && downcast<RenderSVGShape>(current).isRenderingDisabled()) continue; - const AffineTransform& transform = current->localToParentTransform(); + const AffineTransform& transform = current.localToParentTransform(); if (transform.isIdentity()) { - updateObjectBoundingBox(objectBoundingBox, objectBoundingBoxValid, current, current->objectBoundingBox()); - strokeBoundingBox.unite(current->repaintRectInLocalCoordinates()); + updateObjectBoundingBox(objectBoundingBox, objectBoundingBoxValid, ¤t, current.objectBoundingBox()); + strokeBoundingBox.unite(current.repaintRectInLocalCoordinates()); } else { - updateObjectBoundingBox(objectBoundingBox, objectBoundingBoxValid, current, transform.mapRect(current->objectBoundingBox())); - strokeBoundingBox.unite(transform.mapRect(current->repaintRectInLocalCoordinates())); + updateObjectBoundingBox(objectBoundingBox, objectBoundingBoxValid, ¤t, transform.mapRect(current.objectBoundingBox())); + strokeBoundingBox.unite(transform.mapRect(current.repaintRectInLocalCoordinates())); } } @@ -180,141 +185,149 @@ bool SVGRenderSupport::paintInfoIntersectsRepaintRect(const FloatRect& localRepa return localTransform.mapRect(localRepaintRect).intersects(paintInfo.rect); } -const RenderSVGRoot& SVGRenderSupport::findTreeRootObject(const RenderElement& start) +RenderSVGRoot* SVGRenderSupport::findTreeRootObject(RenderElement& start) { - return *lineageOfType<RenderSVGRoot>(start).first(); + return lineageOfType<RenderSVGRoot>(start).first(); } -static inline void invalidateResourcesOfChildren(RenderObject& start) +const RenderSVGRoot* SVGRenderSupport::findTreeRootObject(const RenderElement& start) { - ASSERT(!start.needsLayout()); - if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(start)) - resources->removeClientFromCache(start, false); + return lineageOfType<RenderSVGRoot>(start).first(); +} + +static inline void invalidateResourcesOfChildren(RenderElement& renderer) +{ + ASSERT(!renderer.needsLayout()); + if (auto* resources = SVGResourcesCache::cachedResourcesForRenderer(renderer)) + resources->removeClientFromCache(renderer, false); - for (RenderObject* child = start.firstChildSlow(); child; child = child->nextSibling()) - invalidateResourcesOfChildren(*child); + for (auto& child : childrenOfType<RenderElement>(renderer)) + invalidateResourcesOfChildren(child); } static inline bool layoutSizeOfNearestViewportChanged(const RenderElement& renderer) { const RenderElement* start = &renderer; - while (start && !start->isSVGRoot() && !start->isSVGViewportContainer()) + while (start && !is<RenderSVGRoot>(*start) && !is<RenderSVGViewportContainer>(*start)) start = start->parent(); ASSERT(start); - ASSERT(start->isSVGRoot() || start->isSVGViewportContainer()); - if (start->isSVGViewportContainer()) - return toRenderSVGViewportContainer(start)->isLayoutSizeChanged(); + if (is<RenderSVGViewportContainer>(*start)) + return downcast<RenderSVGViewportContainer>(*start).isLayoutSizeChanged(); - return toRenderSVGRoot(start)->isLayoutSizeChanged(); + return downcast<RenderSVGRoot>(*start).isLayoutSizeChanged(); } bool SVGRenderSupport::transformToRootChanged(RenderElement* ancestor) { - while (ancestor && !ancestor->isSVGRoot()) { - if (ancestor->isSVGTransformableContainer()) - return toRenderSVGContainer(ancestor)->didTransformToRootUpdate(); - if (ancestor->isSVGViewportContainer()) - return toRenderSVGViewportContainer(ancestor)->didTransformToRootUpdate(); + while (ancestor && !is<RenderSVGRoot>(*ancestor)) { + if (is<RenderSVGTransformableContainer>(*ancestor)) + return downcast<RenderSVGTransformableContainer>(*ancestor).didTransformToRootUpdate(); + if (is<RenderSVGViewportContainer>(*ancestor)) + return downcast<RenderSVGViewportContainer>(*ancestor).didTransformToRootUpdate(); ancestor = ancestor->parent(); } return false; } +void SVGRenderSupport::layoutDifferentRootIfNeeded(const RenderElement& renderer) +{ + if (auto* resources = SVGResourcesCache::cachedResourcesForRenderer(renderer)) { + auto* svgRoot = SVGRenderSupport::findTreeRootObject(renderer); + ASSERT(svgRoot); + resources->layoutDifferentRootIfNeeded(svgRoot); + } +} + void SVGRenderSupport::layoutChildren(RenderElement& start, bool selfNeedsLayout) { bool layoutSizeChanged = layoutSizeOfNearestViewportChanged(start); bool transformChanged = transformToRootChanged(&start); bool hasSVGShadow = rendererHasSVGShadow(start); bool needsBoundariesUpdate = start.needsBoundariesUpdate(); - HashSet<RenderObject*> notlayoutedObjects; + HashSet<RenderElement*> elementsThatDidNotReceiveLayout; - for (RenderObject* child = start.firstChild(); child; child = child->nextSibling()) { + for (auto& child : childrenOfType<RenderObject>(start)) { bool needsLayout = selfNeedsLayout; - bool childEverHadLayout = child->everHadLayout(); + bool childEverHadLayout = child.everHadLayout(); if (needsBoundariesUpdate && hasSVGShadow) { // If we have a shadow, our shadow is baked into our children's cached boundaries, // so they need to update. - child->setNeedsBoundariesUpdate(); + child.setNeedsBoundariesUpdate(); needsLayout = true; } if (transformChanged) { // If the transform changed we need to update the text metrics (note: this also happens for layoutSizeChanged=true). - if (child->isSVGText()) - toRenderSVGText(child)->setNeedsTextMetricsUpdate(); + if (is<RenderSVGText>(child)) + downcast<RenderSVGText>(child).setNeedsTextMetricsUpdate(); needsLayout = true; } - if (layoutSizeChanged) { + if (layoutSizeChanged && is<SVGElement>(*child.node())) { // When selfNeedsLayout is false and the layout size changed, we have to check whether this child uses relative lengths - if (SVGElement* element = child->node()->isSVGElement() ? toSVGElement(child->node()) : 0) { - if (element->hasRelativeLengths()) { - // When the layout size changed and when using relative values tell the RenderSVGShape to update its shape object - if (child->isSVGShape()) - toRenderSVGShape(child)->setNeedsShapeUpdate(); - else if (child->isSVGText()) { - toRenderSVGText(child)->setNeedsTextMetricsUpdate(); - toRenderSVGText(child)->setNeedsPositioningValuesUpdate(); - } - - needsLayout = true; + auto& element = downcast<SVGElement>(*child.node()); + if (element.hasRelativeLengths()) { + // When the layout size changed and when using relative values tell the RenderSVGShape to update its shape object + if (is<RenderSVGShape>(child)) + downcast<RenderSVGShape>(child).setNeedsShapeUpdate(); + else if (is<RenderSVGText>(child)) { + auto& svgText = downcast<RenderSVGText>(child); + svgText.setNeedsTextMetricsUpdate(); + svgText.setNeedsPositioningValuesUpdate(); } + + needsLayout = true; } } if (needsLayout) - child->setNeedsLayout(MarkOnlyThis); + child.setNeedsLayout(MarkOnlyThis); - if (child->needsLayout()) { - toRenderElement(child)->layout(); + if (child.needsLayout()) { + layoutDifferentRootIfNeeded(downcast<RenderElement>(child)); + downcast<RenderElement>(child).layout(); // Renderers are responsible for repainting themselves when changing, except // for the initial paint to avoid potential double-painting caused by non-sensical "old" bounds. // We could handle this in the individual objects, but for now it's easier to have // parent containers call repaint(). (RenderBlock::layout* has similar logic.) if (!childEverHadLayout) - child->repaint(); - } else if (layoutSizeChanged) - notlayoutedObjects.add(child); + child.repaint(); + } else if (layoutSizeChanged && is<RenderElement>(child)) + elementsThatDidNotReceiveLayout.add(&downcast<RenderElement>(child)); - ASSERT(!child->needsLayout()); + ASSERT(!child.needsLayout()); } if (!layoutSizeChanged) { - ASSERT(notlayoutedObjects.isEmpty()); + ASSERT(elementsThatDidNotReceiveLayout.isEmpty()); return; } // If the layout size changed, invalidate all resources of all children that didn't go through the layout() code path. - for (auto child : notlayoutedObjects) - invalidateResourcesOfChildren(*child); + for (auto* element : elementsThatDidNotReceiveLayout) + invalidateResourcesOfChildren(*element); } bool SVGRenderSupport::isOverflowHidden(const RenderElement& renderer) { - // SVG doesn't support independent x/y overflow - ASSERT(renderer.style().overflowX() == renderer.style().overflowY()); - - // OSCROLL is never set for SVG - see StyleResolver::adjustRenderStyle - ASSERT(renderer.style().overflowX() != OSCROLL); - // RenderSVGRoot should never query for overflow state - it should always clip itself to the initial viewport size. - ASSERT(!renderer.isRoot()); + ASSERT(!renderer.isDocumentElementRenderer()); - return renderer.style().overflowX() == OHIDDEN; + return renderer.style().overflowX() == OHIDDEN || renderer.style().overflowX() == OSCROLL; } bool SVGRenderSupport::rendererHasSVGShadow(const RenderObject& renderer) { // FIXME: Add support for RenderSVGBlock. - if (renderer.isSVGShape() || renderer.isSVGImage() || renderer.isSVGContainer()) - return toRenderSVGModelObject(renderer).hasSVGShadow(); + if (is<RenderSVGModelObject>(renderer)) + return downcast<RenderSVGModelObject>(renderer).hasSVGShadow(); - if (renderer.isSVGRoot()) - return toRenderSVGRoot(renderer).hasSVGShadow(); + if (is<RenderSVGRoot>(renderer)) + return downcast<RenderSVGRoot>(renderer).hasSVGShadow(); return false; } @@ -323,13 +336,13 @@ void SVGRenderSupport::setRendererHasSVGShadow(RenderObject& renderer, bool hasS { // FIXME: Add support for RenderSVGBlock. - if (renderer.isSVGShape() || renderer.isSVGImage() || renderer.isSVGContainer()) { - toRenderSVGModelObject(renderer).setHasSVGShadow(hasShadow); + if (is<RenderSVGModelObject>(renderer)) { + downcast<RenderSVGModelObject>(renderer).setHasSVGShadow(hasShadow); return; } - if (renderer.isSVGRoot()) - toRenderSVGRoot(renderer).setHasSVGShadow(hasShadow); + if (is<RenderSVGRoot>(renderer)) + downcast<RenderSVGRoot>(renderer).setHasSVGShadow(hasShadow); } void SVGRenderSupport::intersectRepaintRectWithShadows(const RenderElement& renderer, FloatRect& repaintRect) @@ -357,20 +370,18 @@ void SVGRenderSupport::intersectRepaintRectWithShadows(const RenderElement& rend if (localToRootTransform.isIdentity()) return; - AffineTransform rootToLocalTransform = localToRootTransform.inverse(); + AffineTransform rootToLocalTransform = localToRootTransform.inverse().value_or(AffineTransform()); repaintRect = rootToLocalTransform.mapRect(repaintRect); } void SVGRenderSupport::intersectRepaintRectWithResources(const RenderElement& renderer, FloatRect& repaintRect) { - SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(renderer); + auto* resources = SVGResourcesCache::cachedResourcesForRenderer(renderer); if (!resources) return; -#if ENABLE(FILTERS) if (RenderSVGResourceFilter* filter = resources->filter()) repaintRect = filter->resourceBoundingBox(renderer); -#endif if (RenderSVGResourceClipper* clipper = resources->clipper()) repaintRect.intersect(clipper->resourceBoundingBox(renderer)); @@ -386,7 +397,7 @@ bool SVGRenderSupport::filtersForceContainerLayout(const RenderElement& renderer if (!renderer.normalChildNeedsLayout()) return false; - SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(renderer); + auto* resources = SVGResourcesCache::cachedResourcesForRenderer(renderer); if (!resources || !resources->filter()) return false; @@ -397,7 +408,7 @@ bool SVGRenderSupport::pointInClippingArea(const RenderElement& renderer, const { // We just take clippers into account to determine if a point is on the node. The Specification may // change later and we also need to check maskers. - SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(renderer); + auto* resources = SVGResourcesCache::cachedResourcesForRenderer(renderer); if (!resources) return true; @@ -415,23 +426,31 @@ void SVGRenderSupport::applyStrokeStyleToContext(GraphicsContext* context, const const SVGRenderStyle& svgStyle = style.svgStyle(); - SVGLengthContext lengthContext(toSVGElement(renderer.element())); - context->setStrokeThickness(svgStyle.strokeWidth().value(lengthContext)); - context->setLineCap(svgStyle.capStyle()); - context->setLineJoin(svgStyle.joinStyle()); - if (svgStyle.joinStyle() == MiterJoin) + SVGLengthContext lengthContext(downcast<SVGElement>(renderer.element())); + context->setStrokeThickness(lengthContext.valueForLength(style.strokeWidth())); + context->setLineCap(style.capStyle()); + context->setLineJoin(style.joinStyle()); + if (style.joinStyle() == MiterJoin) context->setMiterLimit(svgStyle.strokeMiterLimit()); - const Vector<SVGLength>& dashes = svgStyle.strokeDashArray(); + const Vector<SVGLengthValue>& dashes = svgStyle.strokeDashArray(); if (dashes.isEmpty()) context->setStrokeStyle(SolidStroke); else { DashArray dashArray; dashArray.reserveInitialCapacity(dashes.size()); - for (unsigned i = 0, size = dashes.size(); i < size; ++i) - dashArray.uncheckedAppend(dashes[i].value(lengthContext)); + bool canSetLineDash = false; - context->setLineDash(dashArray, svgStyle.strokeDashOffset().value(lengthContext)); + for (auto& dash : dashes) { + dashArray.uncheckedAppend(dash.value(lengthContext)); + if (dashArray.last() > 0) + canSetLineDash = true; + } + + if (canSetLineDash) + context->setLineDash(dashArray, lengthContext.valueForLength(svgStyle.strokeDashOffset())); + else + context->setStrokeStyle(SolidStroke); } } @@ -440,12 +459,40 @@ void SVGRenderSupport::childAdded(RenderElement& parent, RenderObject& child) SVGRenderSupport::setRendererHasSVGShadow(child, SVGRenderSupport::rendererHasSVGShadow(parent) || SVGRenderSupport::rendererHasSVGShadow(child)); } -void SVGRenderSupport::styleChanged(RenderElement& renderer) +void SVGRenderSupport::styleChanged(RenderElement& renderer, const RenderStyle* oldStyle) { auto parent = renderer.parent(); SVGRenderSupport::setRendererHasSVGShadow(renderer, (parent && SVGRenderSupport::rendererHasSVGShadow(*parent)) || renderer.style().svgStyle().shadow()); + +#if ENABLE(CSS_COMPOSITING) + if (renderer.element() && renderer.element()->isSVGElement() && (!oldStyle || renderer.style().hasBlendMode() != oldStyle->hasBlendMode())) + SVGRenderSupport::updateMaskedAncestorShouldIsolateBlending(renderer); +#else + UNUSED_PARAM(oldStyle); +#endif } +#if ENABLE(CSS_COMPOSITING) +bool SVGRenderSupport::isolatesBlending(const RenderStyle& style) +{ + return style.svgStyle().isolatesBlending() || style.hasFilter() || style.hasBlendMode() || style.opacity() < 1.0f; } +void SVGRenderSupport::updateMaskedAncestorShouldIsolateBlending(const RenderElement& renderer) +{ + ASSERT(renderer.element()); + ASSERT(renderer.element()->isSVGElement()); + + bool maskedAncestorShouldIsolateBlending = renderer.style().hasBlendMode(); + for (auto* ancestor = renderer.element()->parentElement(); ancestor && ancestor->isSVGElement(); ancestor = ancestor->parentElement()) { + if (!downcast<SVGElement>(*ancestor).isSVGGraphicsElement() || !isolatesBlending(*ancestor->computedStyle())) + continue; + + if (ancestor->computedStyle()->svgStyle().hasMasker()) + downcast<SVGGraphicsElement>(*ancestor).setShouldIsolateBlending(maskedAncestorShouldIsolateBlending); + + return; + } +} #endif +} diff --git a/Source/WebCore/rendering/svg/SVGRenderSupport.h b/Source/WebCore/rendering/svg/SVGRenderSupport.h index 026c14e7a..d6ff72d7c 100644 --- a/Source/WebCore/rendering/svg/SVGRenderSupport.h +++ b/Source/WebCore/rendering/svg/SVGRenderSupport.h @@ -21,10 +21,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef SVGRenderSupport_h -#define SVGRenderSupport_h +#pragma once -#if ENABLE(SVG) #include "PaintInfo.h" namespace WebCore { @@ -45,6 +43,8 @@ class TransformState; // SVGRendererSupport is a helper class sharing code between all SVG renderers. class SVGRenderSupport { public: + static void layoutDifferentRootIfNeeded(const RenderElement&); + // Shares child layouting code between RenderSVGRoot/RenderSVG(Hidden)Container static void layoutChildren(RenderElement&, bool selfNeedsLayout); @@ -68,8 +68,9 @@ public: // Important functions used by nearly all SVG renderers centralizing coordinate transformations / repaint rect calculations static FloatRect repaintRectForRendererInLocalCoordinatesExcludingSVGShadow(const RenderElement&); static LayoutRect clippedOverflowRectForRepaint(const RenderElement&, const RenderLayerModelObject* repaintContainer); - static void computeFloatRectForRepaint(const RenderElement&, const RenderLayerModelObject* repaintContainer, FloatRect&, bool fixed); - static void mapLocalToContainer(const RenderElement&, const RenderLayerModelObject* repaintContainer, TransformState&, bool* wasFixed = 0); + static FloatRect computeFloatRectForRepaint(const RenderElement&, const FloatRect&, const RenderLayerModelObject* repaintContainer, bool fixed); + static const RenderElement& localToParentTransform(const RenderElement&, AffineTransform &); + static void mapLocalToContainer(const RenderElement&, const RenderLayerModelObject* repaintContainer, TransformState&, bool* wasFixed); static const RenderElement* pushMappingToContainer(const RenderElement&, const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap&); static bool checkForSVGRepaintDuringLayout(const RenderElement&); @@ -84,10 +85,15 @@ public: static void setRendererHasSVGShadow(RenderObject&, bool hasShadow); static void childAdded(RenderElement& parent, RenderObject& child); - static void styleChanged(RenderElement&); + static void styleChanged(RenderElement&, const RenderStyle*); + +#if ENABLE(CSS_COMPOSITING) + static bool isolatesBlending(const RenderStyle&); + static void updateMaskedAncestorShouldIsolateBlending(const RenderElement&); +#endif - // FIXME: These methods do not belong here. - static const RenderSVGRoot& findTreeRootObject(const RenderElement&); + static RenderSVGRoot* findTreeRootObject(RenderElement&); + static const RenderSVGRoot* findTreeRootObject(const RenderElement&); private: // This class is not constructable. @@ -96,6 +102,3 @@ private: }; } // namespace WebCore - -#endif // ENABLE(SVG) -#endif // SVGRenderSupport_h diff --git a/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp b/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp index aa6040968..8823bc668 100644 --- a/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp +++ b/Source/WebCore/rendering/svg/SVGRenderTreeAsText.cpp @@ -13,10 +13,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -27,14 +27,12 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "SVGRenderTreeAsText.h" #include "GraphicsTypes.h" -#include "HTMLNames.h" #include "NodeRenderStyle.h" #include "RenderImage.h" +#include "RenderIterator.h" #include "RenderSVGGradientStop.h" #include "RenderSVGImage.h" #include "RenderSVGPath.h" @@ -48,15 +46,12 @@ #include "RenderSVGResourceSolidColor.h" #include "RenderSVGRoot.h" #include "RenderSVGText.h" -#include "RenderTreeAsText.h" #include "SVGCircleElement.h" #include "SVGEllipseElement.h" #include "SVGInlineTextBox.h" #include "SVGLineElement.h" -#include "SVGNames.h" #include "SVGPathElement.h" #include "SVGPathUtilities.h" -#include "SVGPointList.h" #include "SVGPolyElement.h" #include "SVGRectElement.h" #include "SVGRootInlineBox.h" @@ -119,45 +114,6 @@ static void writeIfNotDefault(TextStream& ts, const char* name, ValueType value, writeNameValuePair(ts, name, value); } -TextStream& operator<<(TextStream& ts, const FloatRect& r) -{ - ts << "at (" << TextStream::FormatNumberRespectingIntegers(r.x()); - ts << "," << TextStream::FormatNumberRespectingIntegers(r.y()); - ts << ") size " << TextStream::FormatNumberRespectingIntegers(r.width()); - ts << "x" << TextStream::FormatNumberRespectingIntegers(r.height()); - return ts; -} - -TextStream& operator<<(TextStream& ts, const AffineTransform& transform) -{ - if (transform.isIdentity()) - ts << "identity"; - else - ts << "{m=((" - << transform.a() << "," << transform.b() - << ")(" - << transform.c() << "," << transform.d() - << ")) t=(" - << transform.e() << "," << transform.f() - << ")}"; - - return ts; -} - -static TextStream& operator<<(TextStream& ts, const WindRule rule) -{ - switch (rule) { - case RULE_NONZERO: - ts << "NON-ZERO"; - break; - case RULE_EVENODD: - ts << "EVEN-ODD"; - break; - } - - return ts; -} - static TextStream& operator<<(TextStream& ts, const SVGUnitTypes::SVGUnitType& unitType) { ts << SVGPropertyTraits<SVGUnitTypes::SVGUnitType>::toString(unitType); @@ -170,11 +126,6 @@ static TextStream& operator<<(TextStream& ts, const SVGMarkerUnitsType& markerUn return ts; } -TextStream& operator<<(TextStream& ts, const Color& c) -{ - return ts << c.nameForRenderTreeAsText(); -} - // FIXME: Maybe this should be in KCanvasRenderingStyle.cpp static TextStream& operator<<(TextStream& ts, const DashArray& a) { @@ -189,43 +140,9 @@ static TextStream& operator<<(TextStream& ts, const DashArray& a) return ts; } -// FIXME: Maybe this should be in GraphicsTypes.cpp -static TextStream& operator<<(TextStream& ts, LineCap style) -{ - switch (style) { - case ButtCap: - ts << "BUTT"; - break; - case RoundCap: - ts << "ROUND"; - break; - case SquareCap: - ts << "SQUARE"; - break; - } - return ts; -} - -// FIXME: Maybe this should be in GraphicsTypes.cpp -static TextStream& operator<<(TextStream& ts, LineJoin style) -{ - switch (style) { - case MiterJoin: - ts << "MITER"; - break; - case RoundJoin: - ts << "ROUND"; - break; - case BevelJoin: - ts << "BEVEL"; - break; - } - return ts; -} - static TextStream& operator<<(TextStream& ts, const SVGSpreadMethodType& type) { - ts << SVGPropertyTraits<SVGSpreadMethodType>::toString(type).upper(); + ts << SVGPropertyTraits<SVGSpreadMethodType>::toString(type).convertToASCIIUppercase(); return ts; } @@ -250,17 +167,17 @@ static void writeSVGPaintingResource(TextStream& ts, RenderSVGResource* resource ts << " [id=\"" << element.getIdAttribute() << "\"]"; } -static void writeStyle(TextStream& ts, const RenderObject& object) +static void writeStyle(TextStream& ts, const RenderElement& renderer) { - const RenderStyle& style = object.style(); + const RenderStyle& style = renderer.style(); const SVGRenderStyle& svgStyle = style.svgStyle(); - if (!object.localTransform().isIdentity()) - writeNameValuePair(ts, "transform", object.localTransform()); + if (!renderer.localTransform().isIdentity()) + writeNameValuePair(ts, "transform", renderer.localTransform()); writeIfNotDefault(ts, "image rendering", style.imageRendering(), RenderStyle::initialImageRendering()); writeIfNotDefault(ts, "opacity", style.opacity(), RenderStyle::initialOpacity()); - if (object.isSVGShape()) { - const RenderSVGShape& shape = static_cast<const RenderSVGShape&>(object); + if (is<RenderSVGShape>(renderer)) { + const auto& shape = downcast<RenderSVGShape>(renderer); Color fallbackColor; if (RenderSVGResource* strokePaintingResource = RenderSVGResource::strokePaintingResource(const_cast<RenderSVGShape&>(shape), shape.style(), fallbackColor)) { @@ -269,20 +186,19 @@ static void writeStyle(TextStream& ts, const RenderObject& object) writeSVGPaintingResource(ts, strokePaintingResource); SVGLengthContext lengthContext(&shape.graphicsElement()); - double dashOffset = svgStyle.strokeDashOffset().value(lengthContext); - double strokeWidth = svgStyle.strokeWidth().value(lengthContext); - const Vector<SVGLength>& dashes = svgStyle.strokeDashArray(); + double dashOffset = lengthContext.valueForLength(svgStyle.strokeDashOffset()); + double strokeWidth = lengthContext.valueForLength(style.strokeWidth()); + const auto& dashes = svgStyle.strokeDashArray(); DashArray dashArray; - const Vector<SVGLength>::const_iterator end = dashes.end(); - for (Vector<SVGLength>::const_iterator it = dashes.begin(); it != end; ++it) - dashArray.append((*it).value(lengthContext)); + for (auto& length : dashes) + dashArray.append(length.value(lengthContext)); writeIfNotDefault(ts, "opacity", svgStyle.strokeOpacity(), 1.0f); writeIfNotDefault(ts, "stroke width", strokeWidth, 1.0); writeIfNotDefault(ts, "miter limit", svgStyle.strokeMiterLimit(), 4.0f); - writeIfNotDefault(ts, "line cap", svgStyle.capStyle(), ButtCap); - writeIfNotDefault(ts, "line join", svgStyle.joinStyle(), MiterJoin); + writeIfNotDefault(ts, "line cap", style.capStyle(), ButtCap); + writeIfNotDefault(ts, "line join", style.joinStyle(), MiterJoin); writeIfNotDefault(ts, "dash offset", dashOffset, 0.0); if (!dashArray.isEmpty()) writeNameValuePair(ts, "dash array", dashArray); @@ -307,10 +223,20 @@ static void writeStyle(TextStream& ts, const RenderObject& object) writeIfNotEmpty(ts, "end marker", svgStyle.markerEndResource()); } -static TextStream& writePositionAndStyle(TextStream& ts, const RenderObject& object) +static TextStream& writePositionAndStyle(TextStream& ts, const RenderElement& renderer, RenderAsTextBehavior behavior = RenderAsTextBehaviorNormal) { - ts << " " << enclosingIntRect(const_cast<RenderObject&>(object).absoluteClippedOverflowRect()); - writeStyle(ts, object); + if (behavior & RenderAsTextShowSVGGeometry) { + if (is<RenderBox>(renderer)) { + LayoutRect r = downcast<RenderBox>(renderer).frameRect(); + ts << " " << enclosingIntRect(r); + } + + ts << " clipped"; + } + + ts << " " << enclosingIntRect(renderer.absoluteClippedOverflowRect()); + + writeStyle(ts, renderer); return ts; } @@ -321,34 +247,34 @@ static TextStream& operator<<(TextStream& ts, const RenderSVGShape& shape) SVGGraphicsElement& svgElement = shape.graphicsElement(); SVGLengthContext lengthContext(&svgElement); - if (isSVGRectElement(svgElement)) { - const SVGRectElement& element = toSVGRectElement(svgElement); + if (is<SVGRectElement>(svgElement)) { + const SVGRectElement& element = downcast<SVGRectElement>(svgElement); writeNameValuePair(ts, "x", element.x().value(lengthContext)); writeNameValuePair(ts, "y", element.y().value(lengthContext)); writeNameValuePair(ts, "width", element.width().value(lengthContext)); writeNameValuePair(ts, "height", element.height().value(lengthContext)); - } else if (isSVGLineElement(svgElement)) { - const SVGLineElement& element = toSVGLineElement(svgElement); + } else if (is<SVGLineElement>(svgElement)) { + const SVGLineElement& element = downcast<SVGLineElement>(svgElement); writeNameValuePair(ts, "x1", element.x1().value(lengthContext)); writeNameValuePair(ts, "y1", element.y1().value(lengthContext)); writeNameValuePair(ts, "x2", element.x2().value(lengthContext)); writeNameValuePair(ts, "y2", element.y2().value(lengthContext)); - } else if (isSVGEllipseElement(svgElement)) { - const SVGEllipseElement& element = toSVGEllipseElement(svgElement); + } else if (is<SVGEllipseElement>(svgElement)) { + const SVGEllipseElement& element = downcast<SVGEllipseElement>(svgElement); writeNameValuePair(ts, "cx", element.cx().value(lengthContext)); writeNameValuePair(ts, "cy", element.cy().value(lengthContext)); writeNameValuePair(ts, "rx", element.rx().value(lengthContext)); writeNameValuePair(ts, "ry", element.ry().value(lengthContext)); - } else if (isSVGCircleElement(svgElement)) { - const SVGCircleElement& element = toSVGCircleElement(svgElement); + } else if (is<SVGCircleElement>(svgElement)) { + const SVGCircleElement& element = downcast<SVGCircleElement>(svgElement); writeNameValuePair(ts, "cx", element.cx().value(lengthContext)); writeNameValuePair(ts, "cy", element.cy().value(lengthContext)); writeNameValuePair(ts, "r", element.r().value(lengthContext)); - } else if (svgElement.hasTagName(SVGNames::polygonTag) || svgElement.hasTagName(SVGNames::polylineTag)) { - const SVGPolyElement& element = toSVGPolyElement(svgElement); + } else if (is<SVGPolyElement>(svgElement)) { + const SVGPolyElement& element = downcast<SVGPolyElement>(svgElement); writeNameAndQuotedValue(ts, "points", element.pointList().valueAsString()); - } else if (isSVGPathElement(svgElement)) { - const SVGPathElement& element = toSVGPathElement(svgElement); + } else if (is<SVGPathElement>(svgElement)) { + const SVGPathElement& element = downcast<SVGPathElement>(svgElement); String pathString; // FIXME: We should switch to UnalteredParsing here - this will affect the path dumping output of dozens of tests. buildStringFromByteStream(element.pathByteStream(), pathString, NormalizedParsing); @@ -358,14 +284,9 @@ static TextStream& operator<<(TextStream& ts, const RenderSVGShape& shape) return ts; } -static TextStream& operator<<(TextStream& ts, const RenderSVGRoot& root) -{ - return writePositionAndStyle(ts, root); -} - static void writeRenderSVGTextBox(TextStream& ts, const RenderSVGText& text) { - SVGRootInlineBox* box = toSVGRootInlineBox(text.firstRootBox()); + auto* box = downcast<SVGRootInlineBox>(text.firstRootBox()); if (!box) return; @@ -398,7 +319,7 @@ static inline void writeSVGInlineTextBox(TextStream& ts, SVGInlineTextBox* textB // FIXME: Remove this hack, once the new text layout engine is completly landed. We want to preserve the old layout test results for now. ts << "chunk 1 "; ETextAnchor anchor = svgStyle.textAnchor(); - bool isVerticalText = svgStyle.isVerticalWritingMode(); + bool isVerticalText = textBox->renderer().style().isVerticalWritingMode(); if (anchor == TA_MIDDLE) { ts << "(middle anchor"; if (isVerticalText) @@ -435,26 +356,31 @@ static inline void writeSVGInlineTextBox(TextStream& ts, SVGInlineTextBox* textB static inline void writeSVGInlineTextBoxes(TextStream& ts, const RenderText& text, int indent) { for (InlineTextBox* box = text.firstTextBox(); box; box = box->nextTextBox()) { - if (!box->isSVGInlineTextBox()) + if (!is<SVGInlineTextBox>(*box)) continue; - writeSVGInlineTextBox(ts, toSVGInlineTextBox(box), indent); + writeSVGInlineTextBox(ts, downcast<SVGInlineTextBox>(box), indent); } } -static void writeStandardPrefix(TextStream& ts, const RenderObject& object, int indent) +static void writeStandardPrefix(TextStream& ts, const RenderObject& object, int indent, RenderAsTextBehavior behavior) { writeIndent(ts, indent); ts << object.renderName(); + if (behavior & RenderAsTextShowAddresses) + ts << " " << static_cast<const void*>(&object); + if (object.node()) ts << " {" << object.node()->nodeName() << "}"; + + writeDebugInfo(ts, object, behavior); } -static void writeChildren(TextStream& ts, const RenderObject& object, int indent) +static void writeChildren(TextStream& ts, const RenderElement& parent, int indent, RenderAsTextBehavior behavior) { - for (RenderObject* child = object.firstChildSlow(); child; child = child->nextSibling()) - write(ts, *child, indent + 1); + for (const auto& child : childrenOfType<RenderObject>(parent)) + write(ts, child, indent + 1, behavior); } static inline void writeCommonGradientProperties(TextStream& ts, SVGSpreadMethodType spreadMethod, const AffineTransform& gradientTransform, SVGUnitTypes::SVGUnitType gradientUnits) @@ -468,56 +394,50 @@ static inline void writeCommonGradientProperties(TextStream& ts, SVGSpreadMethod ts << " [gradientTransform=" << gradientTransform << "]"; } -void writeSVGResourceContainer(TextStream& ts, const RenderObject& object, int indent) +void writeSVGResourceContainer(TextStream& ts, const RenderSVGResourceContainer& resource, int indent, RenderAsTextBehavior behavior) { - writeStandardPrefix(ts, object, indent); + writeStandardPrefix(ts, resource, indent, behavior); - Element* element = toElement(object.node()); - const AtomicString& id = element->getIdAttribute(); + const AtomicString& id = resource.element().getIdAttribute(); writeNameAndQuotedValue(ts, "id", id); - RenderSVGResourceContainer* resource = const_cast<RenderObject&>(object).toRenderSVGResourceContainer(); - ASSERT(resource); - - if (resource->resourceType() == MaskerResourceType) { - RenderSVGResourceMasker* masker = static_cast<RenderSVGResourceMasker*>(resource); - writeNameValuePair(ts, "maskUnits", masker->maskUnits()); - writeNameValuePair(ts, "maskContentUnits", masker->maskContentUnits()); + if (resource.resourceType() == MaskerResourceType) { + const auto& masker = static_cast<const RenderSVGResourceMasker&>(resource); + writeNameValuePair(ts, "maskUnits", masker.maskUnits()); + writeNameValuePair(ts, "maskContentUnits", masker.maskContentUnits()); ts << "\n"; -#if ENABLE(FILTERS) - } else if (resource->resourceType() == FilterResourceType) { - RenderSVGResourceFilter* filter = static_cast<RenderSVGResourceFilter*>(resource); - writeNameValuePair(ts, "filterUnits", filter->filterUnits()); - writeNameValuePair(ts, "primitiveUnits", filter->primitiveUnits()); + } else if (resource.resourceType() == FilterResourceType) { + const auto& filter = static_cast<const RenderSVGResourceFilter&>(resource); + writeNameValuePair(ts, "filterUnits", filter.filterUnits()); + writeNameValuePair(ts, "primitiveUnits", filter.primitiveUnits()); ts << "\n"; // Creating a placeholder filter which is passed to the builder. FloatRect dummyRect; RefPtr<SVGFilter> dummyFilter = SVGFilter::create(AffineTransform(), dummyRect, dummyRect, dummyRect, true); - if (auto builder = filter->buildPrimitives(dummyFilter.get())) { + if (auto builder = filter.buildPrimitives(*dummyFilter)) { if (FilterEffect* lastEffect = builder->lastEffect()) lastEffect->externalRepresentation(ts, indent + 1); } -#endif - } else if (resource->resourceType() == ClipperResourceType) { - RenderSVGResourceClipper* clipper = static_cast<RenderSVGResourceClipper*>(resource); - writeNameValuePair(ts, "clipPathUnits", clipper->clipPathUnits()); + } else if (resource.resourceType() == ClipperResourceType) { + const auto& clipper = static_cast<const RenderSVGResourceClipper&>(resource); + writeNameValuePair(ts, "clipPathUnits", clipper.clipPathUnits()); ts << "\n"; - } else if (resource->resourceType() == MarkerResourceType) { - RenderSVGResourceMarker* marker = static_cast<RenderSVGResourceMarker*>(resource); - writeNameValuePair(ts, "markerUnits", marker->markerUnits()); - ts << " [ref at " << marker->referencePoint() << "]"; + } else if (resource.resourceType() == MarkerResourceType) { + const auto& marker = static_cast<const RenderSVGResourceMarker&>(resource); + writeNameValuePair(ts, "markerUnits", marker.markerUnits()); + ts << " [ref at " << marker.referencePoint() << "]"; ts << " [angle="; - if (marker->angle() == -1) + if (marker.angle() == -1) ts << "auto" << "]\n"; else - ts << marker->angle() << "]\n"; - } else if (resource->resourceType() == PatternResourceType) { - RenderSVGResourcePattern* pattern = static_cast<RenderSVGResourcePattern*>(resource); + ts << marker.angle() << "]\n"; + } else if (resource.resourceType() == PatternResourceType) { + const auto& pattern = static_cast<const RenderSVGResourcePattern&>(resource); // Dump final results that are used for rendering. No use in asking SVGPatternElement for its patternUnits(), as it may // link to other patterns using xlink:href, we need to build the full inheritance chain, aka. collectPatternProperties() PatternAttributes attributes; - pattern->patternElement().collectPatternAttributes(attributes); + pattern.collectPatternAttributes(attributes); writeNameValuePair(ts, "patternUnits", attributes.patternUnits()); writeNameValuePair(ts, "patternContentUnits", attributes.patternContentUnits()); @@ -526,139 +446,140 @@ void writeSVGResourceContainer(TextStream& ts, const RenderObject& object, int i if (!transform.isIdentity()) ts << " [patternTransform=" << transform << "]"; ts << "\n"; - } else if (resource->resourceType() == LinearGradientResourceType) { - RenderSVGResourceLinearGradient* gradient = static_cast<RenderSVGResourceLinearGradient*>(resource); + } else if (resource.resourceType() == LinearGradientResourceType) { + const auto& gradient = static_cast<const RenderSVGResourceLinearGradient&>(resource); // Dump final results that are used for rendering. No use in asking SVGGradientElement for its gradientUnits(), as it may // link to other gradients using xlink:href, we need to build the full inheritance chain, aka. collectGradientProperties() LinearGradientAttributes attributes; - gradient->linearGradientElement().collectGradientAttributes(attributes); + gradient.linearGradientElement().collectGradientAttributes(attributes); writeCommonGradientProperties(ts, attributes.spreadMethod(), attributes.gradientTransform(), attributes.gradientUnits()); - ts << " [start=" << gradient->startPoint(attributes) << "] [end=" << gradient->endPoint(attributes) << "]\n"; - } else if (resource->resourceType() == RadialGradientResourceType) { - RenderSVGResourceRadialGradient* gradient = static_cast<RenderSVGResourceRadialGradient*>(resource); + ts << " [start=" << gradient.startPoint(attributes) << "] [end=" << gradient.endPoint(attributes) << "]\n"; + } else if (resource.resourceType() == RadialGradientResourceType) { + const auto& gradient = static_cast<const RenderSVGResourceRadialGradient&>(resource); // Dump final results that are used for rendering. No use in asking SVGGradientElement for its gradientUnits(), as it may // link to other gradients using xlink:href, we need to build the full inheritance chain, aka. collectGradientProperties() RadialGradientAttributes attributes; - gradient->radialGradientElement().collectGradientAttributes(attributes); + gradient.radialGradientElement().collectGradientAttributes(attributes); writeCommonGradientProperties(ts, attributes.spreadMethod(), attributes.gradientTransform(), attributes.gradientUnits()); - FloatPoint focalPoint = gradient->focalPoint(attributes); - FloatPoint centerPoint = gradient->centerPoint(attributes); - float radius = gradient->radius(attributes); - float focalRadius = gradient->focalRadius(attributes); + FloatPoint focalPoint = gradient.focalPoint(attributes); + FloatPoint centerPoint = gradient.centerPoint(attributes); + float radius = gradient.radius(attributes); + float focalRadius = gradient.focalRadius(attributes); ts << " [center=" << centerPoint << "] [focal=" << focalPoint << "] [radius=" << radius << "] [focalRadius=" << focalRadius << "]\n"; } else ts << "\n"; - writeChildren(ts, object, indent); + writeChildren(ts, resource, indent, behavior); } -void writeSVGContainer(TextStream& ts, const RenderObject& container, int indent) +void writeSVGContainer(TextStream& ts, const RenderSVGContainer& container, int indent, RenderAsTextBehavior behavior) { // Currently RenderSVGResourceFilterPrimitive has no meaningful output. if (container.isSVGResourceFilterPrimitive()) return; - writeStandardPrefix(ts, container, indent); - writePositionAndStyle(ts, container); + writeStandardPrefix(ts, container, indent, behavior); + writePositionAndStyle(ts, container, behavior); ts << "\n"; - writeResources(ts, container, indent); - writeChildren(ts, container, indent); + writeResources(ts, container, indent, behavior); + writeChildren(ts, container, indent, behavior); } -void write(TextStream& ts, const RenderSVGRoot& root, int indent) +void write(TextStream& ts, const RenderSVGRoot& root, int indent, RenderAsTextBehavior behavior) { - writeStandardPrefix(ts, root, indent); - ts << root << "\n"; - writeChildren(ts, root, indent); + writeStandardPrefix(ts, root, indent, behavior); + writePositionAndStyle(ts, root, behavior); + ts << "\n"; + writeChildren(ts, root, indent, behavior); } -void writeSVGText(TextStream& ts, const RenderSVGText& text, int indent) +void writeSVGText(TextStream& ts, const RenderSVGText& text, int indent, RenderAsTextBehavior behavior) { - writeStandardPrefix(ts, text, indent); + writeStandardPrefix(ts, text, indent, behavior); writeRenderSVGTextBox(ts, text); ts << "\n"; - writeResources(ts, text, indent); - writeChildren(ts, text, indent); + writeResources(ts, text, indent, behavior); + writeChildren(ts, text, indent, behavior); } -void writeSVGInlineText(TextStream& ts, const RenderSVGInlineText& text, int indent) +void writeSVGInlineText(TextStream& ts, const RenderSVGInlineText& text, int indent, RenderAsTextBehavior behavior) { - writeStandardPrefix(ts, text, indent); - ts << " " << enclosingIntRect(FloatRect(text.firstRunOrigin(), text.floatLinesBoundingBox().size())) << "\n"; - writeResources(ts, text, indent); + writeStandardPrefix(ts, text, indent, behavior); + ts << " " << enclosingIntRect(FloatRect(text.firstRunLocation(), text.floatLinesBoundingBox().size())) << "\n"; + writeResources(ts, text, indent, behavior); writeSVGInlineTextBoxes(ts, text, indent); } -void writeSVGImage(TextStream& ts, const RenderSVGImage& image, int indent) +void writeSVGImage(TextStream& ts, const RenderSVGImage& image, int indent, RenderAsTextBehavior behavior) { - writeStandardPrefix(ts, image, indent); - writePositionAndStyle(ts, image); + writeStandardPrefix(ts, image, indent, behavior); + writePositionAndStyle(ts, image, behavior); ts << "\n"; - writeResources(ts, image, indent); + writeResources(ts, image, indent, behavior); } -void write(TextStream& ts, const RenderSVGShape& shape, int indent) +void write(TextStream& ts, const RenderSVGShape& shape, int indent, RenderAsTextBehavior behavior) { - writeStandardPrefix(ts, shape, indent); + writeStandardPrefix(ts, shape, indent, behavior); ts << shape << "\n"; - writeResources(ts, shape, indent); + writeResources(ts, shape, indent, behavior); } -void writeSVGGradientStop(TextStream& ts, const RenderSVGGradientStop& stop, int indent) +void writeSVGGradientStop(TextStream& ts, const RenderSVGGradientStop& stop, int indent, RenderAsTextBehavior behavior) { - writeStandardPrefix(ts, stop, indent); + writeStandardPrefix(ts, stop, indent, behavior); - SVGStopElement* stopElement = toSVGStopElement(toSVGElement(stop.element())); - ASSERT(stopElement); - - ts << " [offset=" << stopElement->offset() << "] [color=" << stopElement->stopColorIncludingOpacity() << "]\n"; + ts << " [offset=" << stop.element().offset() << "] [color=" << stop.element().stopColorIncludingOpacity() << "]\n"; } -void writeResources(TextStream& ts, const RenderObject& object, int indent) +void writeResources(TextStream& ts, const RenderObject& renderer, int indent, RenderAsTextBehavior behavior) { - const RenderStyle& style = object.style(); + const RenderStyle& style = renderer.style(); const SVGRenderStyle& svgStyle = style.svgStyle(); // FIXME: We want to use SVGResourcesCache to determine which resources are present, instead of quering the resource <-> id cache. // For now leave the DRT output as is, but later on we should change this so cycles are properly ignored in the DRT output. - RenderObject& renderer = const_cast<RenderObject&>(object); if (!svgStyle.maskerResource().isEmpty()) { - if (RenderSVGResourceMasker* masker = getRenderSVGResourceById<RenderSVGResourceMasker>(object.document(), svgStyle.maskerResource())) { + if (RenderSVGResourceMasker* masker = getRenderSVGResourceById<RenderSVGResourceMasker>(renderer.document(), svgStyle.maskerResource())) { writeIndent(ts, indent); ts << " "; writeNameAndQuotedValue(ts, "masker", svgStyle.maskerResource()); ts << " "; - writeStandardPrefix(ts, *masker, 0); + writeStandardPrefix(ts, *masker, 0, behavior); ts << " " << masker->resourceBoundingBox(renderer) << "\n"; } } if (!svgStyle.clipperResource().isEmpty()) { - if (RenderSVGResourceClipper* clipper = getRenderSVGResourceById<RenderSVGResourceClipper>(object.document(), svgStyle.clipperResource())) { + if (RenderSVGResourceClipper* clipper = getRenderSVGResourceById<RenderSVGResourceClipper>(renderer.document(), svgStyle.clipperResource())) { writeIndent(ts, indent); ts << " "; writeNameAndQuotedValue(ts, "clipPath", svgStyle.clipperResource()); ts << " "; - writeStandardPrefix(ts, *clipper, 0); + writeStandardPrefix(ts, *clipper, 0, behavior); ts << " " << clipper->resourceBoundingBox(renderer) << "\n"; } } -#if ENABLE(FILTERS) - if (!svgStyle.filterResource().isEmpty()) { - if (RenderSVGResourceFilter* filter = getRenderSVGResourceById<RenderSVGResourceFilter>(object.document(), svgStyle.filterResource())) { - writeIndent(ts, indent); - ts << " "; - writeNameAndQuotedValue(ts, "filter", svgStyle.filterResource()); - ts << " "; - writeStandardPrefix(ts, *filter, 0); - ts << " " << filter->resourceBoundingBox(renderer) << "\n"; + if (style.hasFilter()) { + const FilterOperations& filterOperations = style.filter(); + if (filterOperations.size() == 1) { + const FilterOperation& filterOperation = *filterOperations.at(0); + if (filterOperation.type() == FilterOperation::REFERENCE) { + const auto& referenceFilterOperation = downcast<ReferenceFilterOperation>(filterOperation); + AtomicString id = SVGURIReference::fragmentIdentifierFromIRIString(referenceFilterOperation.url(), renderer.document()); + if (RenderSVGResourceFilter* filter = getRenderSVGResourceById<RenderSVGResourceFilter>(renderer.document(), id)) { + writeIndent(ts, indent); + ts << " "; + writeNameAndQuotedValue(ts, "filter", id); + ts << " "; + writeStandardPrefix(ts, *filter, 0, behavior); + ts << " " << filter->resourceBoundingBox(renderer) << "\n"; + } + } } } -#endif } } // namespace WebCore - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/SVGRenderTreeAsText.h b/Source/WebCore/rendering/svg/SVGRenderTreeAsText.h index 5458c0dd2..7cce1c6a9 100644 --- a/Source/WebCore/rendering/svg/SVGRenderTreeAsText.h +++ b/Source/WebCore/rendering/svg/SVGRenderTreeAsText.h @@ -10,10 +10,10 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -23,11 +23,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef SVGRenderTreeAsText_h -#define SVGRenderTreeAsText_h - -#if ENABLE(SVG) +#pragma once +#include "RenderTreeAsText.h" #include "TextStream.h" namespace WebCore { @@ -38,9 +36,11 @@ class FloatSize; class Node; class RenderImage; class RenderObject; +class RenderSVGContainer; class RenderSVGGradientStop; class RenderSVGImage; class RenderSVGInlineText; +class RenderSVGResourceContainer; class RenderSVGShape; class RenderSVGRoot; class RenderSVGText; @@ -48,20 +48,15 @@ class AffineTransform; class SVGUnitTypes; // functions used by the main RenderTreeAsText code -void write(TextStream&, const RenderSVGShape&, int indent); -void write(TextStream&, const RenderSVGRoot&, int indent); -void writeSVGGradientStop(TextStream&, const RenderSVGGradientStop&, int indent); -void writeSVGResourceContainer(TextStream&, const RenderObject&, int indent); -void writeSVGContainer(TextStream&, const RenderObject&, int indent); -void writeSVGImage(TextStream&, const RenderSVGImage&, int indent); -void writeSVGInlineText(TextStream&, const RenderSVGInlineText&, int indent); -void writeSVGText(TextStream&, const RenderSVGText&, int indent); -void writeResources(TextStream&, const RenderObject&, int indent); - -// helper operators defined used in various classes to dump the render tree. -TextStream& operator<<(TextStream&, const AffineTransform&); -TextStream& operator<<(TextStream&, const Color&); -TextStream& operator<<(TextStream&, const FloatRect&); +void write(TextStream&, const RenderSVGShape&, int indent, RenderAsTextBehavior); +void write(TextStream&, const RenderSVGRoot&, int indent, RenderAsTextBehavior); +void writeSVGGradientStop(TextStream&, const RenderSVGGradientStop&, int indent, RenderAsTextBehavior); +void writeSVGResourceContainer(TextStream&, const RenderSVGResourceContainer&, int indent, RenderAsTextBehavior); +void writeSVGContainer(TextStream&, const RenderSVGContainer&, int indent, RenderAsTextBehavior); +void writeSVGImage(TextStream&, const RenderSVGImage&, int indent, RenderAsTextBehavior); +void writeSVGInlineText(TextStream&, const RenderSVGInlineText&, int indent, RenderAsTextBehavior); +void writeSVGText(TextStream&, const RenderSVGText&, int indent, RenderAsTextBehavior); +void writeResources(TextStream&, const RenderObject&, int indent, RenderAsTextBehavior); // helper operators specific to dumping the render tree. these are used in various classes to dump the render tree // these could be defined in separate namespace to avoid matching these generic signatures unintentionally. @@ -89,7 +84,3 @@ TextStream& operator<<(TextStream& ts, Pointer* t) } } // namespace WebCore - -#endif // ENABLE(SVG) - -#endif // SVGRenderTreeAsText_h diff --git a/Source/WebCore/rendering/svg/SVGRenderingContext.cpp b/Source/WebCore/rendering/svg/SVGRenderingContext.cpp index a0ad33016..67c55967b 100644 --- a/Source/WebCore/rendering/svg/SVGRenderingContext.cpp +++ b/Source/WebCore/rendering/svg/SVGRenderingContext.cpp @@ -23,25 +23,21 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "SVGRenderingContext.h" #include "BasicShapes.h" #include "Frame.h" #include "FrameView.h" -#include "Page.h" #include "RenderLayer.h" #include "RenderSVGImage.h" #include "RenderSVGResourceClipper.h" #include "RenderSVGResourceFilter.h" #include "RenderSVGResourceMasker.h" #include "RenderView.h" +#include "SVGLengthContext.h" #include "SVGResources.h" #include "SVGResourcesCache.h" -static int kMaxImageBufferSize = 4096; - namespace WebCore { static inline bool isRenderingMaskImage(const RenderObject& object) @@ -57,23 +53,22 @@ SVGRenderingContext::~SVGRenderingContext() ASSERT(m_renderer && m_paintInfo); -#if ENABLE(FILTERS) if (m_renderingFlags & EndFilterLayer) { ASSERT(m_filter); - m_filter->postApplyResource(*m_renderer, m_paintInfo->context, ApplyToDefaultMode, 0, 0); - m_paintInfo->context = m_savedContext; + GraphicsContext* contextPtr = &m_paintInfo->context(); + m_filter->postApplyResource(*m_renderer, contextPtr, ApplyToDefaultMode, 0, 0); + m_paintInfo->setContext(*m_savedContext); m_paintInfo->rect = m_savedPaintRect; } -#endif if (m_renderingFlags & EndOpacityLayer) - m_paintInfo->context->endTransparencyLayer(); + m_paintInfo->context().endTransparencyLayer(); if (m_renderingFlags & EndShadowLayer) - m_paintInfo->context->endTransparencyLayer(); + m_paintInfo->context().endTransparencyLayer(); if (m_renderingFlags & RestoreGraphicsContext) - m_paintInfo->context->restore(); + m_paintInfo->context().restore(); } void SVGRenderingContext::prepareToRenderSVGContent(RenderElement& renderer, PaintInfo& paintInfo, NeedsGraphicsContextSave needsGraphicsContextSave) @@ -86,80 +81,115 @@ void SVGRenderingContext::prepareToRenderSVGContent(RenderElement& renderer, Pai m_renderer = &renderer; m_paintInfo = &paintInfo; -#if ENABLE(FILTERS) m_filter = 0; -#endif // We need to save / restore the context even if the initialization failed. if (needsGraphicsContextSave == SaveGraphicsContext) { - m_paintInfo->context->save(); + m_paintInfo->context().save(); m_renderingFlags |= RestoreGraphicsContext; } - RenderStyle& style = m_renderer->style(); + auto& style = m_renderer->style(); const SVGRenderStyle& svgStyle = style.svgStyle(); // Setup transparency layers before setting up SVG resources! bool isRenderingMask = isRenderingMaskImage(*m_renderer); - float opacity = isRenderingMask ? 1 : style.opacity(); + // RenderLayer takes care of root opacity. + float opacity = (renderer.isSVGRoot() || isRenderingMask) ? 1 : style.opacity(); const ShadowData* shadow = svgStyle.shadow(); - if (opacity < 1 || shadow) { + bool hasBlendMode = style.hasBlendMode(); + bool hasIsolation = style.hasIsolation(); + bool isolateMaskForBlending = false; + +#if ENABLE(CSS_COMPOSITING) + if (svgStyle.hasMasker() && is<SVGGraphicsElement>(downcast<SVGElement>(*renderer.element()))) { + SVGGraphicsElement& graphicsElement = downcast<SVGGraphicsElement>(*renderer.element()); + isolateMaskForBlending = graphicsElement.shouldIsolateBlending(); + } +#endif + + if (opacity < 1 || shadow || hasBlendMode || isolateMaskForBlending || hasIsolation) { FloatRect repaintRect = m_renderer->repaintRectInLocalCoordinates(); + m_paintInfo->context().clip(repaintRect); + + if (opacity < 1 || hasBlendMode || isolateMaskForBlending || hasIsolation) { + + if (hasBlendMode) + m_paintInfo->context().setCompositeOperation(m_paintInfo->context().compositeOperation(), style.blendMode()); + + m_paintInfo->context().beginTransparencyLayer(opacity); + + if (hasBlendMode) + m_paintInfo->context().setCompositeOperation(m_paintInfo->context().compositeOperation(), BlendModeNormal); - if (opacity < 1) { - m_paintInfo->context->clip(repaintRect); - m_paintInfo->context->beginTransparencyLayer(opacity); m_renderingFlags |= EndOpacityLayer; } if (shadow) { - m_paintInfo->context->clip(repaintRect); - m_paintInfo->context->setShadow(IntSize(roundToInt(shadow->x()), roundToInt(shadow->y())), shadow->radius(), shadow->color(), style.colorSpace()); - m_paintInfo->context->beginTransparencyLayer(1); + m_paintInfo->context().setShadow(IntSize(roundToInt(shadow->x()), roundToInt(shadow->y())), shadow->radius(), shadow->color()); + m_paintInfo->context().beginTransparencyLayer(1); m_renderingFlags |= EndShadowLayer; } } ClipPathOperation* clipPathOperation = style.clipPath(); - if (clipPathOperation && clipPathOperation->type() == ClipPathOperation::Shape) { - ShapeClipPathOperation* clipPath = static_cast<ShapeClipPathOperation*>(clipPathOperation); - m_paintInfo->context->clipPath(clipPath->pathForReferenceRect(renderer.objectBoundingBox()), clipPath->windRule()); + if (is<ShapeClipPathOperation>(clipPathOperation)) { + auto& clipPath = downcast<ShapeClipPathOperation>(*clipPathOperation); + FloatRect referenceBox; + if (clipPath.referenceBox() == Stroke) + // FIXME: strokeBoundingBox() takes dasharray into account but shouldn't. + referenceBox = renderer.strokeBoundingBox(); + else if (clipPath.referenceBox() == ViewBox && renderer.element()) { + FloatSize viewportSize; + SVGLengthContext(downcast<SVGElement>(renderer.element())).determineViewport(viewportSize); + referenceBox.setWidth(viewportSize.width()); + referenceBox.setHeight(viewportSize.height()); + } else + referenceBox = renderer.objectBoundingBox(); + m_paintInfo->context().clipPath(clipPath.pathForReferenceRect(referenceBox), clipPath.windRule()); } - SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(*m_renderer); + auto* resources = SVGResourcesCache::cachedResourcesForRenderer(*m_renderer); if (!resources) { -#if ENABLE(FILTERS) - if (svgStyle.hasFilter()) + if (style.hasReferenceFilterOnly()) return; -#endif + m_renderingFlags |= RenderingPrepared; return; } if (!isRenderingMask) { if (RenderSVGResourceMasker* masker = resources->masker()) { - if (!masker->applyResource(*m_renderer, style, m_paintInfo->context, ApplyToDefaultMode)) + GraphicsContext* contextPtr = &m_paintInfo->context(); + bool result = masker->applyResource(*m_renderer, style, contextPtr, ApplyToDefaultMode); + m_paintInfo->setContext(*contextPtr); + if (!result) return; } } RenderSVGResourceClipper* clipper = resources->clipper(); if (!clipPathOperation && clipper) { - if (!clipper->applyResource(*m_renderer, style, m_paintInfo->context, ApplyToDefaultMode)) + GraphicsContext* contextPtr = &m_paintInfo->context(); + bool result = clipper->applyResource(*m_renderer, style, contextPtr, ApplyToDefaultMode); + m_paintInfo->setContext(*contextPtr); + if (!result) return; } -#if ENABLE(FILTERS) if (!isRenderingMask) { m_filter = resources->filter(); if (m_filter) { - m_savedContext = m_paintInfo->context; + m_savedContext = &m_paintInfo->context(); m_savedPaintRect = m_paintInfo->rect; // Return with false here may mean that we don't need to draw the content // (because it was either drawn before or empty) but we still need to apply the filter. m_renderingFlags |= EndFilterLayer; - if (!m_filter->applyResource(*m_renderer, style, m_paintInfo->context, ApplyToDefaultMode)) + GraphicsContext* contextPtr = &m_paintInfo->context(); + bool result = m_filter->applyResource(*m_renderer, style, contextPtr, ApplyToDefaultMode); + m_paintInfo->setContext(*contextPtr); + if (!result) return; // Since we're caching the resulting bitmap and do not invalidate it on repaint rect @@ -169,45 +199,38 @@ void SVGRenderingContext::prepareToRenderSVGContent(RenderElement& renderer, Pai m_paintInfo->rect = IntRect(m_filter->drawingRegion(m_renderer)); } } -#endif m_renderingFlags |= RenderingPrepared; } static AffineTransform& currentContentTransformation() { - DEFINE_STATIC_LOCAL(AffineTransform, s_currentContentTransformation, ()); + static NeverDestroyed<AffineTransform> s_currentContentTransformation; return s_currentContentTransformation; } -float SVGRenderingContext::calculateScreenFontSizeScalingFactor(const RenderObject* renderer) +float SVGRenderingContext::calculateScreenFontSizeScalingFactor(const RenderObject& renderer) { - ASSERT(renderer); - - AffineTransform ctm; - calculateTransformationToOutermostCoordinateSystem(renderer, ctm); + AffineTransform ctm = calculateTransformationToOutermostCoordinateSystem(renderer); return narrowPrecisionToFloat(sqrt((pow(ctm.xScale(), 2) + pow(ctm.yScale(), 2)) / 2)); } -void SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(const RenderObject* renderer, AffineTransform& absoluteTransform) +AffineTransform SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(const RenderObject& renderer) { - ASSERT(renderer); - absoluteTransform = currentContentTransformation(); - - float deviceScaleFactor = 1; - if (Page* page = renderer->document().page()) - deviceScaleFactor = page->deviceScaleFactor(); + AffineTransform absoluteTransform = currentContentTransformation(); + float deviceScaleFactor = renderer.document().deviceScaleFactor(); // Walk up the render tree, accumulating SVG transforms. - while (renderer) { - absoluteTransform = renderer->localToParentTransform() * absoluteTransform; - if (renderer->isSVGRoot()) + const RenderObject* ancestor = &renderer; + while (ancestor) { + absoluteTransform = ancestor->localToParentTransform() * absoluteTransform; + if (ancestor->isSVGRoot()) break; - renderer = renderer->parent(); + ancestor = ancestor->parent(); } // Continue walking up the layer tree, accumulating CSS transforms. - RenderLayer* layer = renderer ? renderer->enclosingLayer() : 0; + RenderLayer* layer = ancestor ? ancestor->enclosingLayer() : nullptr; while (layer) { if (TransformationMatrix* layerTransform = layer->transform()) absoluteTransform = layerTransform->toAffineTransform() * absoluteTransform; @@ -220,61 +243,60 @@ void SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(con } absoluteTransform.scale(deviceScaleFactor); + return absoluteTransform; } -bool SVGRenderingContext::createImageBuffer(const FloatRect& targetRect, const AffineTransform& absoluteTransform, std::unique_ptr<ImageBuffer>& imageBuffer, ColorSpace colorSpace, RenderingMode renderingMode) +std::unique_ptr<ImageBuffer> SVGRenderingContext::createImageBuffer(const FloatRect& targetRect, const AffineTransform& absoluteTransform, ColorSpace colorSpace, RenderingMode renderingMode) { IntRect paintRect = calculateImageBufferRect(targetRect, absoluteTransform); // Don't create empty ImageBuffers. if (paintRect.isEmpty()) - return false; + return nullptr; - IntSize clampedSize = clampedAbsoluteSize(paintRect.size()); - std::unique_ptr<ImageBuffer> image = ImageBuffer::create(clampedSize, 1, colorSpace, renderingMode); - if (!image) - return false; + FloatSize scale; + FloatSize clampedSize = ImageBuffer::clampedSize(paintRect.size(), scale); - GraphicsContext* imageContext = image->context(); - ASSERT(imageContext); + auto imageBuffer = ImageBuffer::create(clampedSize, renderingMode, 1, colorSpace); + if (!imageBuffer) + return nullptr; - imageContext->scale(FloatSize(static_cast<float>(clampedSize.width()) / paintRect.width(), - static_cast<float>(clampedSize.height()) / paintRect.height())); - imageContext->translate(-paintRect.x(), -paintRect.y()); - imageContext->concatCTM(absoluteTransform); + AffineTransform transform; + transform.scale(scale).translate(-paintRect.location()).multiply(absoluteTransform); - imageBuffer = std::move(image); - return true; + GraphicsContext& imageContext = imageBuffer->context(); + imageContext.concatCTM(transform); + + return imageBuffer; } -bool SVGRenderingContext::createImageBufferForPattern(const FloatRect& absoluteTargetRect, const FloatRect& clampedAbsoluteTargetRect, std::unique_ptr<ImageBuffer>& imageBuffer, ColorSpace colorSpace, RenderingMode renderingMode) +std::unique_ptr<ImageBuffer> SVGRenderingContext::createImageBuffer(const FloatRect& targetRect, const FloatRect& clampedRect, ColorSpace colorSpace, RenderingMode renderingMode) { - IntSize imageSize(roundedIntSize(clampedAbsoluteTargetRect.size())); - IntSize unclampedImageSize(roundedIntSize(absoluteTargetRect.size())); + IntSize clampedSize = roundedIntSize(clampedRect.size()); + IntSize unclampedSize = roundedIntSize(targetRect.size()); // Don't create empty ImageBuffers. - if (imageSize.isEmpty()) - return false; + if (clampedSize.isEmpty()) + return nullptr; - std::unique_ptr<ImageBuffer> image = ImageBuffer::create(imageSize, 1, colorSpace, renderingMode); - if (!image) - return false; + auto imageBuffer = ImageBuffer::create(clampedSize, renderingMode, 1, colorSpace); + if (!imageBuffer) + return nullptr; - GraphicsContext* imageContext = image->context(); - ASSERT(imageContext); + GraphicsContext& imageContext = imageBuffer->context(); // Compensate rounding effects, as the absolute target rect is using floating-point numbers and the image buffer size is integer. - imageContext->scale(FloatSize(unclampedImageSize.width() / absoluteTargetRect.width(), unclampedImageSize.height() / absoluteTargetRect.height())); + imageContext.scale(FloatSize(unclampedSize.width() / targetRect.width(), unclampedSize.height() / targetRect.height())); - imageBuffer = std::move(image); - return true; + return imageBuffer; } void SVGRenderingContext::renderSubtreeToImageBuffer(ImageBuffer* image, RenderElement& item, const AffineTransform& subtreeContentTransformation) { ASSERT(image); - ASSERT(image->context()); - PaintInfo info(image->context(), IntRect::infiniteRect(), PaintPhaseForeground, PaintBehaviorNormal); + // Rendering into a buffer implies we're being used for masking, clipping, patterns or filters. In each of these + // cases we don't want to paint the selection. + PaintInfo info(image->context(), LayoutRect::infiniteRect(), PaintPhaseForeground, PaintBehaviorSkipSelectionHighlight); AffineTransform& contentTransformation = currentContentTransformation(); AffineTransform savedContentTransformation = contentTransformation; @@ -286,18 +308,18 @@ void SVGRenderingContext::renderSubtreeToImageBuffer(ImageBuffer* image, RenderE contentTransformation = savedContentTransformation; } -void SVGRenderingContext::clipToImageBuffer(GraphicsContext* context, const AffineTransform& absoluteTransform, const FloatRect& targetRect, std::unique_ptr<ImageBuffer>& imageBuffer, bool safeToClear) +void SVGRenderingContext::clipToImageBuffer(GraphicsContext& context, const AffineTransform& absoluteTransform, const FloatRect& targetRect, std::unique_ptr<ImageBuffer>& imageBuffer, bool safeToClear) { - ASSERT(context); - ASSERT(imageBuffer); + if (!imageBuffer) + return; FloatRect absoluteTargetRect = calculateImageBufferRect(targetRect, absoluteTransform); // The mask image has been created in the absolute coordinate space, as the image should not be scaled. // So the actual masking process has to be done in the absolute coordinate space as well. - context->concatCTM(absoluteTransform.inverse()); - context->clipToImageBuffer(imageBuffer.get(), absoluteTargetRect); - context->concatCTM(absoluteTransform); + context.concatCTM(absoluteTransform.inverse().value_or(AffineTransform())); + context.clipToImageBuffer(*imageBuffer, absoluteTargetRect); + context.concatCTM(absoluteTransform); // When nesting resources, with objectBoundingBox as content unit types, there's no use in caching the // resulting image buffer as the parent resource already caches the result. @@ -305,18 +327,6 @@ void SVGRenderingContext::clipToImageBuffer(GraphicsContext* context, const Affi imageBuffer.reset(); } -FloatRect SVGRenderingContext::clampedAbsoluteTargetRect(const FloatRect& absoluteTargetRect) -{ - const FloatSize maxImageBufferSize(kMaxImageBufferSize, kMaxImageBufferSize); - return FloatRect(absoluteTargetRect.location(), absoluteTargetRect.size().shrunkTo(maxImageBufferSize)); -} - -IntSize SVGRenderingContext::clampedAbsoluteSize(const IntSize& absoluteSize) -{ - const IntSize maxImageBufferSize(kMaxImageBufferSize, kMaxImageBufferSize); - return absoluteSize.shrunkTo(maxImageBufferSize); -} - void SVGRenderingContext::clear2DRotation(AffineTransform& transform) { AffineTransform::DecomposedType decomposition; @@ -328,12 +338,12 @@ void SVGRenderingContext::clear2DRotation(AffineTransform& transform) bool SVGRenderingContext::bufferForeground(std::unique_ptr<ImageBuffer>& imageBuffer) { ASSERT(m_paintInfo); - ASSERT(m_renderer->isSVGImage()); + ASSERT(is<RenderSVGImage>(*m_renderer)); FloatRect boundingBox = m_renderer->objectBoundingBox(); // Invalidate an existing buffer if the scale is not correct. if (imageBuffer) { - AffineTransform transform = m_paintInfo->context->getCTM(GraphicsContext::DefinitelyIncludeDeviceScale); + AffineTransform transform = m_paintInfo->context().getCTM(GraphicsContext::DefinitelyIncludeDeviceScale); IntSize expandedBoundingBox = expandedIntSize(boundingBox.size()); IntSize bufferSize(static_cast<int>(ceil(expandedBoundingBox.width() * transform.xScale())), static_cast<int>(ceil(expandedBoundingBox.height() * transform.yScale()))); if (bufferSize != imageBuffer->internalSize()) @@ -342,20 +352,18 @@ bool SVGRenderingContext::bufferForeground(std::unique_ptr<ImageBuffer>& imageBu // Create a new buffer and paint the foreground into it. if (!imageBuffer) { - if ((imageBuffer = m_paintInfo->context->createCompatibleBuffer(expandedIntSize(boundingBox.size()), true))) { - GraphicsContext* bufferedRenderingContext = imageBuffer->context(); - bufferedRenderingContext->translate(-boundingBox.x(), -boundingBox.y()); + if ((imageBuffer = ImageBuffer::createCompatibleBuffer(expandedIntSize(boundingBox.size()), ColorSpaceSRGB, m_paintInfo->context()))) { + GraphicsContext& bufferedRenderingContext = imageBuffer->context(); + bufferedRenderingContext.translate(-boundingBox.x(), -boundingBox.y()); PaintInfo bufferedInfo(*m_paintInfo); - bufferedInfo.context = bufferedRenderingContext; - toRenderSVGImage(m_renderer)->paintForeground(bufferedInfo); + bufferedInfo.setContext(bufferedRenderingContext); + downcast<RenderSVGImage>(*m_renderer).paintForeground(bufferedInfo); } else return false; } - m_paintInfo->context->drawImageBuffer(imageBuffer.get(), ColorSpaceDeviceRGB, boundingBox); + m_paintInfo->context().drawImageBuffer(*imageBuffer, boundingBox); return true; } } - -#endif diff --git a/Source/WebCore/rendering/svg/SVGRenderingContext.h b/Source/WebCore/rendering/svg/SVGRenderingContext.h index 3bf604cc2..fb6c29c97 100644 --- a/Source/WebCore/rendering/svg/SVGRenderingContext.h +++ b/Source/WebCore/rendering/svg/SVGRenderingContext.h @@ -22,19 +22,17 @@ * Boston, MA 02110-1301, USA. */ -#ifndef SVGRenderingContext_h -#define SVGRenderingContext_h +#pragma once -#if ENABLE(SVG) #include "ImageBuffer.h" #include "PaintInfo.h" namespace WebCore { class AffineTransform; +class FloatRect; class RenderElement; class RenderObject; -class FloatRect; class RenderSVGResourceFilter; // SVGRenderingContext @@ -51,9 +49,7 @@ public: , m_renderer(nullptr) , m_paintInfo(nullptr) , m_savedContext(nullptr) -#if ENABLE(FILTERS) , m_filter(nullptr) -#endif { } @@ -62,9 +58,7 @@ public: , m_renderer(nullptr) , m_paintInfo(nullptr) , m_savedContext(nullptr) -#if ENABLE(FILTERS) , m_filter(nullptr) -#endif { prepareToRenderSVGContent(object, paintinfo, needsGraphicsContextSave); } @@ -76,17 +70,14 @@ public: void prepareToRenderSVGContent(RenderElement&, PaintInfo&, NeedsGraphicsContextSave = DontSaveGraphicsContext); bool isRenderingPrepared() const { return m_renderingFlags & RenderingPrepared; } - static bool createImageBuffer(const FloatRect& paintRect, const AffineTransform& absoluteTransform, std::unique_ptr<ImageBuffer>&, ColorSpace, RenderingMode); - // Patterns need a different float-to-integer coordinate mapping. - static bool createImageBufferForPattern(const FloatRect& absoluteTargetRect, const FloatRect& clampedAbsoluteTargetRect, std::unique_ptr<ImageBuffer>&, ColorSpace, RenderingMode); + static std::unique_ptr<ImageBuffer> createImageBuffer(const FloatRect& targetRect, const AffineTransform& absoluteTransform, ColorSpace, RenderingMode); + static std::unique_ptr<ImageBuffer> createImageBuffer(const FloatRect& targetRect, const FloatRect& clampedRect, ColorSpace, RenderingMode); static void renderSubtreeToImageBuffer(ImageBuffer*, RenderElement&, const AffineTransform&); - static void clipToImageBuffer(GraphicsContext*, const AffineTransform& absoluteTransform, const FloatRect& targetRect, std::unique_ptr<ImageBuffer>&, bool safeToClear); + static void clipToImageBuffer(GraphicsContext&, const AffineTransform& absoluteTransform, const FloatRect& targetRect, std::unique_ptr<ImageBuffer>&, bool safeToClear); - static float calculateScreenFontSizeScalingFactor(const RenderObject*); - static void calculateTransformationToOutermostCoordinateSystem(const RenderObject*, AffineTransform& absoluteTransform); - static IntSize clampedAbsoluteSize(const IntSize&); - static FloatRect clampedAbsoluteTargetRect(const FloatRect& absoluteTargetRect); + static float calculateScreenFontSizeScalingFactor(const RenderObject&); + static AffineTransform calculateTransformationToOutermostCoordinateSystem(const RenderObject&); static void clear2DRotation(AffineTransform&); static IntRect calculateImageBufferRect(const FloatRect& targetRect, const AffineTransform& absoluteTransform) @@ -116,12 +107,7 @@ private: PaintInfo* m_paintInfo; GraphicsContext* m_savedContext; LayoutRect m_savedPaintRect; -#if ENABLE(FILTERS) RenderSVGResourceFilter* m_filter; -#endif }; } // namespace WebCore - -#endif // ENABLE(SVG) -#endif // SVGRenderingContext_h diff --git a/Source/WebCore/rendering/svg/SVGResources.cpp b/Source/WebCore/rendering/svg/SVGResources.cpp index bdb586b89..ea9b45211 100644 --- a/Source/WebCore/rendering/svg/SVGResources.cpp +++ b/Source/WebCore/rendering/svg/SVGResources.cpp @@ -20,19 +20,19 @@ #include "config.h" #include "SVGResources.h" -#if ENABLE(SVG) +#include "FilterOperation.h" #include "RenderSVGResourceClipper.h" #include "RenderSVGResourceFilter.h" #include "RenderSVGResourceMarker.h" #include "RenderSVGResourceMasker.h" +#include "RenderSVGRoot.h" #include "SVGGradientElement.h" #include "SVGNames.h" -#include "SVGPaint.h" #include "SVGPatternElement.h" #include "SVGRenderStyle.h" #include "SVGURIReference.h" -#ifndef NDEBUG +#if ENABLE(TREE_DEBUGGING) #include <stdio.h> #endif @@ -45,44 +45,44 @@ SVGResources::SVGResources() static HashSet<AtomicString>& clipperFilterMaskerTags() { - DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ()); - if (s_tagList.isEmpty()) { + static NeverDestroyed<HashSet<AtomicString>> s_tagList; + if (s_tagList.get().isEmpty()) { // "container elements": http://www.w3.org/TR/SVG11/intro.html#TermContainerElement // "graphics elements" : http://www.w3.org/TR/SVG11/intro.html#TermGraphicsElement - s_tagList.add(SVGNames::aTag.localName()); - s_tagList.add(SVGNames::circleTag.localName()); - s_tagList.add(SVGNames::ellipseTag.localName()); - s_tagList.add(SVGNames::glyphTag.localName()); - s_tagList.add(SVGNames::gTag.localName()); - s_tagList.add(SVGNames::imageTag.localName()); - s_tagList.add(SVGNames::lineTag.localName()); - s_tagList.add(SVGNames::markerTag.localName()); - s_tagList.add(SVGNames::maskTag.localName()); - s_tagList.add(SVGNames::missing_glyphTag.localName()); - s_tagList.add(SVGNames::pathTag.localName()); - s_tagList.add(SVGNames::polygonTag.localName()); - s_tagList.add(SVGNames::polylineTag.localName()); - s_tagList.add(SVGNames::rectTag.localName()); - s_tagList.add(SVGNames::svgTag.localName()); - s_tagList.add(SVGNames::textTag.localName()); - s_tagList.add(SVGNames::useTag.localName()); + s_tagList.get().add(SVGNames::aTag.localName()); + s_tagList.get().add(SVGNames::circleTag.localName()); + s_tagList.get().add(SVGNames::ellipseTag.localName()); + s_tagList.get().add(SVGNames::glyphTag.localName()); + s_tagList.get().add(SVGNames::gTag.localName()); + s_tagList.get().add(SVGNames::imageTag.localName()); + s_tagList.get().add(SVGNames::lineTag.localName()); + s_tagList.get().add(SVGNames::markerTag.localName()); + s_tagList.get().add(SVGNames::maskTag.localName()); + s_tagList.get().add(SVGNames::missing_glyphTag.localName()); + s_tagList.get().add(SVGNames::pathTag.localName()); + s_tagList.get().add(SVGNames::polygonTag.localName()); + s_tagList.get().add(SVGNames::polylineTag.localName()); + s_tagList.get().add(SVGNames::rectTag.localName()); + s_tagList.get().add(SVGNames::svgTag.localName()); + s_tagList.get().add(SVGNames::textTag.localName()); + s_tagList.get().add(SVGNames::useTag.localName()); // Not listed in the definitions is the clipPath element, the SVG spec says though: // The "clipPath" element or any of its children can specify property "clip-path". // So we have to add clipPathTag here, otherwhise clip-path on clipPath will fail. // (Already mailed SVG WG, waiting for a solution) - s_tagList.add(SVGNames::clipPathTag.localName()); + s_tagList.get().add(SVGNames::clipPathTag.localName()); // Not listed in the definitions are the text content elements, though filter/clipper/masker on tspan/text/.. is allowed. // (Already mailed SVG WG, waiting for a solution) - s_tagList.add(SVGNames::altGlyphTag.localName()); - s_tagList.add(SVGNames::textPathTag.localName()); - s_tagList.add(SVGNames::trefTag.localName()); - s_tagList.add(SVGNames::tspanTag.localName()); + s_tagList.get().add(SVGNames::altGlyphTag.localName()); + s_tagList.get().add(SVGNames::textPathTag.localName()); + s_tagList.get().add(SVGNames::trefTag.localName()); + s_tagList.get().add(SVGNames::tspanTag.localName()); // Not listed in the definitions is the foreignObject element, but clip-path // is a supported attribute. - s_tagList.add(SVGNames::foreignObjectTag.localName()); + s_tagList.get().add(SVGNames::foreignObjectTag.localName()); // Elements that we ignore, as it doesn't make any sense. // defs, pattern, switch (FIXME: Mail SVG WG about these) @@ -94,12 +94,12 @@ static HashSet<AtomicString>& clipperFilterMaskerTags() static HashSet<AtomicString>& markerTags() { - DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ()); - if (s_tagList.isEmpty()) { - s_tagList.add(SVGNames::lineTag.localName()); - s_tagList.add(SVGNames::pathTag.localName()); - s_tagList.add(SVGNames::polygonTag.localName()); - s_tagList.add(SVGNames::polylineTag.localName()); + static NeverDestroyed<HashSet<AtomicString>> s_tagList; + if (s_tagList.get().isEmpty()) { + s_tagList.get().add(SVGNames::lineTag.localName()); + s_tagList.get().add(SVGNames::pathTag.localName()); + s_tagList.get().add(SVGNames::polygonTag.localName()); + s_tagList.get().add(SVGNames::polylineTag.localName()); } return s_tagList; @@ -107,20 +107,20 @@ static HashSet<AtomicString>& markerTags() static HashSet<AtomicString>& fillAndStrokeTags() { - DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ()); - if (s_tagList.isEmpty()) { - s_tagList.add(SVGNames::altGlyphTag.localName()); - s_tagList.add(SVGNames::circleTag.localName()); - s_tagList.add(SVGNames::ellipseTag.localName()); - s_tagList.add(SVGNames::lineTag.localName()); - s_tagList.add(SVGNames::pathTag.localName()); - s_tagList.add(SVGNames::polygonTag.localName()); - s_tagList.add(SVGNames::polylineTag.localName()); - s_tagList.add(SVGNames::rectTag.localName()); - s_tagList.add(SVGNames::textTag.localName()); - s_tagList.add(SVGNames::textPathTag.localName()); - s_tagList.add(SVGNames::trefTag.localName()); - s_tagList.add(SVGNames::tspanTag.localName()); + static NeverDestroyed<HashSet<AtomicString>> s_tagList; + if (s_tagList.get().isEmpty()) { + s_tagList.get().add(SVGNames::altGlyphTag.localName()); + s_tagList.get().add(SVGNames::circleTag.localName()); + s_tagList.get().add(SVGNames::ellipseTag.localName()); + s_tagList.get().add(SVGNames::lineTag.localName()); + s_tagList.get().add(SVGNames::pathTag.localName()); + s_tagList.get().add(SVGNames::polygonTag.localName()); + s_tagList.get().add(SVGNames::polylineTag.localName()); + s_tagList.get().add(SVGNames::rectTag.localName()); + s_tagList.get().add(SVGNames::textTag.localName()); + s_tagList.get().add(SVGNames::textPathTag.localName()); + s_tagList.get().add(SVGNames::trefTag.localName()); + s_tagList.get().add(SVGNames::tspanTag.localName()); } return s_tagList; @@ -128,12 +128,12 @@ static HashSet<AtomicString>& fillAndStrokeTags() static HashSet<AtomicString>& chainableResourceTags() { - DEFINE_STATIC_LOCAL(HashSet<AtomicString>, s_tagList, ()); - if (s_tagList.isEmpty()) { - s_tagList.add(SVGNames::linearGradientTag.localName()); - s_tagList.add(SVGNames::filterTag.localName()); - s_tagList.add(SVGNames::patternTag.localName()); - s_tagList.add(SVGNames::radialGradientTag.localName()); + static NeverDestroyed<HashSet<AtomicString>> s_tagList; + if (s_tagList.get().isEmpty()) { + s_tagList.get().add(SVGNames::linearGradientTag.localName()); + s_tagList.get().add(SVGNames::filterTag.localName()); + s_tagList.get().add(SVGNames::patternTag.localName()); + s_tagList.get().add(SVGNames::radialGradientTag.localName()); } return s_tagList; @@ -142,23 +142,21 @@ static HashSet<AtomicString>& chainableResourceTags() static inline String targetReferenceFromResource(SVGElement& element) { String target; - if (isSVGPatternElement(element)) - target = toSVGPatternElement(element).href(); - else if (isSVGGradientElement(element)) - target = toSVGGradientElement(element).href(); -#if ENABLE(FILTERS) - else if (isSVGFilterElement(element)) - target = toSVGFilterElement(element).href(); -#endif + if (is<SVGPatternElement>(element)) + target = downcast<SVGPatternElement>(element).href(); + else if (is<SVGGradientElement>(element)) + target = downcast<SVGGradientElement>(element).href(); + else if (is<SVGFilterElement>(element)) + target = downcast<SVGFilterElement>(element).href(); else ASSERT_NOT_REACHED(); return SVGURIReference::fragmentIdentifierFromIRIString(target, element.document()); } -static inline RenderSVGResourceContainer* paintingResourceFromSVGPaint(Document& document, const SVGPaint::SVGPaintType& paintType, const String& paintUri, AtomicString& id, bool& hasPendingResource) +static inline RenderSVGResourceContainer* paintingResourceFromSVGPaint(Document& document, const SVGPaintType& paintType, const String& paintUri, AtomicString& id, bool& hasPendingResource) { - if (paintType != SVGPaint::SVG_PAINTTYPE_URI && paintType != SVGPaint::SVG_PAINTTYPE_URI_RGBCOLOR) + if (paintType != SVG_PAINTTYPE_URI && paintType != SVG_PAINTTYPE_URI_RGBCOLOR && paintType != SVG_PAINTTYPE_URI_CURRENTCOLOR) return 0; id = SVGURIReference::fragmentIdentifierFromIRIString(paintUri, document); @@ -175,12 +173,12 @@ static inline RenderSVGResourceContainer* paintingResourceFromSVGPaint(Document& return container; } -static inline void registerPendingResource(SVGDocumentExtensions* extensions, const AtomicString& id, SVGElement& element) +static inline void registerPendingResource(SVGDocumentExtensions& extensions, const AtomicString& id, SVGElement& element) { - extensions->addPendingResource(id, &element); + extensions.addPendingResource(id, &element); } -bool SVGResources::buildCachedResources(const RenderElement& renderer, const SVGRenderStyle& svgStyle) +bool SVGResources::buildCachedResources(const RenderElement& renderer, const RenderStyle& style) { ASSERT(renderer.element()); ASSERT_WITH_SECURITY_IMPLICATION(renderer.element()->isSVGElement()); @@ -188,17 +186,18 @@ bool SVGResources::buildCachedResources(const RenderElement& renderer, const SVG if (!renderer.element()) return false; - auto& element = toSVGElement(*renderer.element()); + auto& element = downcast<SVGElement>(*renderer.element()); Document& document = element.document(); - SVGDocumentExtensions* extensions = document.accessSVGExtensions(); - ASSERT(extensions); + SVGDocumentExtensions& extensions = document.accessSVGExtensions(); const AtomicString& tagName = element.localName(); if (tagName.isNull()) return false; + const SVGRenderStyle& svgStyle = style.svgStyle(); + bool foundResources = false; if (clipperFilterMaskerTags().contains(tagName)) { if (svgStyle.hasClipper()) { @@ -209,15 +208,20 @@ bool SVGResources::buildCachedResources(const RenderElement& renderer, const SVG registerPendingResource(extensions, id, element); } -#if ENABLE(FILTERS) - if (svgStyle.hasFilter()) { - AtomicString id(svgStyle.filterResource()); - if (setFilter(getRenderSVGResourceById<RenderSVGResourceFilter>(document, id))) - foundResources = true; - else - registerPendingResource(extensions, id, element); + if (style.hasFilter()) { + const FilterOperations& filterOperations = style.filter(); + if (filterOperations.size() == 1) { + const FilterOperation& filterOperation = *filterOperations.at(0); + if (filterOperation.type() == FilterOperation::REFERENCE) { + const auto& referenceFilterOperation = downcast<ReferenceFilterOperation>(filterOperation); + AtomicString id = SVGURIReference::fragmentIdentifierFromIRIString(referenceFilterOperation.url(), element.document()); + if (setFilter(getRenderSVGResourceById<RenderSVGResourceFilter>(document, id))) + foundResources = true; + else + registerPendingResource(extensions, id, element); + } + } } -#endif if (svgStyle.hasMasker()) { AtomicString id(svgStyle.maskerResource()); @@ -279,7 +283,35 @@ bool SVGResources::buildCachedResources(const RenderElement& renderer, const SVG return foundResources; } -void SVGResources::removeClientFromCache(RenderObject& object, bool markForInvalidation) const +void SVGResources::layoutDifferentRootIfNeeded(const RenderSVGRoot* svgRoot) +{ + if (clipper() && svgRoot != SVGRenderSupport::findTreeRootObject(*clipper())) + clipper()->layoutIfNeeded(); + + if (masker() && svgRoot != SVGRenderSupport::findTreeRootObject(*masker())) + masker()->layoutIfNeeded(); + + if (filter() && svgRoot != SVGRenderSupport::findTreeRootObject(*filter())) + filter()->layoutIfNeeded(); + + if (markerStart() && svgRoot != SVGRenderSupport::findTreeRootObject(*markerStart())) + markerStart()->layoutIfNeeded(); + + if (markerMid() && svgRoot != SVGRenderSupport::findTreeRootObject(*markerMid())) + markerMid()->layoutIfNeeded(); + + if (markerEnd() && svgRoot != SVGRenderSupport::findTreeRootObject(*markerEnd())) + markerEnd()->layoutIfNeeded(); +} + +bool SVGResources::markerReverseStart() const +{ + return m_markerData + && m_markerData->markerStart + && m_markerData->markerStart->markerElement().orientType() == SVGMarkerOrientAutoStartReverse; +} + +void SVGResources::removeClientFromCache(RenderElement& renderer, bool markForInvalidation) const { if (!m_clipperFilterMaskerData && !m_markerData && !m_fillStrokeData && !m_linkedResource) return; @@ -288,35 +320,33 @@ void SVGResources::removeClientFromCache(RenderObject& object, bool markForInval ASSERT(!m_clipperFilterMaskerData); ASSERT(!m_markerData); ASSERT(!m_fillStrokeData); - m_linkedResource->removeClientFromCache(object, markForInvalidation); + m_linkedResource->removeClientFromCache(renderer, markForInvalidation); return; } if (m_clipperFilterMaskerData) { if (m_clipperFilterMaskerData->clipper) - m_clipperFilterMaskerData->clipper->removeClientFromCache(object, markForInvalidation); -#if ENABLE(FILTERS) + m_clipperFilterMaskerData->clipper->removeClientFromCache(renderer, markForInvalidation); if (m_clipperFilterMaskerData->filter) - m_clipperFilterMaskerData->filter->removeClientFromCache(object, markForInvalidation); -#endif + m_clipperFilterMaskerData->filter->removeClientFromCache(renderer, markForInvalidation); if (m_clipperFilterMaskerData->masker) - m_clipperFilterMaskerData->masker->removeClientFromCache(object, markForInvalidation); + m_clipperFilterMaskerData->masker->removeClientFromCache(renderer, markForInvalidation); } if (m_markerData) { if (m_markerData->markerStart) - m_markerData->markerStart->removeClientFromCache(object, markForInvalidation); + m_markerData->markerStart->removeClientFromCache(renderer, markForInvalidation); if (m_markerData->markerMid) - m_markerData->markerMid->removeClientFromCache(object, markForInvalidation); + m_markerData->markerMid->removeClientFromCache(renderer, markForInvalidation); if (m_markerData->markerEnd) - m_markerData->markerEnd->removeClientFromCache(object, markForInvalidation); + m_markerData->markerEnd->removeClientFromCache(renderer, markForInvalidation); } if (m_fillStrokeData) { if (m_fillStrokeData->fill) - m_fillStrokeData->fill->removeClientFromCache(object, markForInvalidation); + m_fillStrokeData->fill->removeClientFromCache(renderer, markForInvalidation); if (m_fillStrokeData->stroke) - m_fillStrokeData->stroke->removeClientFromCache(object, markForInvalidation); + m_fillStrokeData->stroke->removeClientFromCache(renderer, markForInvalidation); } } @@ -374,16 +404,12 @@ void SVGResources::resourceDestroyed(RenderSVGResourceContainer& resource) } break; case FilterResourceType: -#if ENABLE(FILTERS) if (!m_clipperFilterMaskerData) break; if (m_clipperFilterMaskerData->filter == &resource) { m_clipperFilterMaskerData->filter->removeAllClientsFromCache(); m_clipperFilterMaskerData->filter = 0; } -#else - ASSERT_NOT_REACHED(); -#endif break; case ClipperResourceType: if (!m_clipperFilterMaskerData) @@ -414,10 +440,8 @@ void SVGResources::buildSetOfResources(HashSet<RenderSVGResourceContainer*>& set if (m_clipperFilterMaskerData) { if (m_clipperFilterMaskerData->clipper) set.add(m_clipperFilterMaskerData->clipper); -#if ENABLE(FILTERS) if (m_clipperFilterMaskerData->filter) set.add(m_clipperFilterMaskerData->filter); -#endif if (m_clipperFilterMaskerData->masker) set.add(m_clipperFilterMaskerData->masker); } @@ -447,7 +471,7 @@ bool SVGResources::setClipper(RenderSVGResourceClipper* clipper) ASSERT(clipper->resourceType() == ClipperResourceType); if (!m_clipperFilterMaskerData) - m_clipperFilterMaskerData = ClipperFilterMaskerData::create(); + m_clipperFilterMaskerData = std::make_unique<ClipperFilterMaskerData>(); m_clipperFilterMaskerData->clipper = clipper; return true; @@ -460,7 +484,6 @@ void SVGResources::resetClipper() m_clipperFilterMaskerData->clipper = 0; } -#if ENABLE(FILTERS) bool SVGResources::setFilter(RenderSVGResourceFilter* filter) { if (!filter) @@ -469,7 +492,7 @@ bool SVGResources::setFilter(RenderSVGResourceFilter* filter) ASSERT(filter->resourceType() == FilterResourceType); if (!m_clipperFilterMaskerData) - m_clipperFilterMaskerData = ClipperFilterMaskerData::create(); + m_clipperFilterMaskerData = std::make_unique<ClipperFilterMaskerData>(); m_clipperFilterMaskerData->filter = filter; return true; @@ -481,7 +504,6 @@ void SVGResources::resetFilter() ASSERT(m_clipperFilterMaskerData->filter); m_clipperFilterMaskerData->filter = 0; } -#endif bool SVGResources::setMarkerStart(RenderSVGResourceMarker* markerStart) { @@ -491,7 +513,7 @@ bool SVGResources::setMarkerStart(RenderSVGResourceMarker* markerStart) ASSERT(markerStart->resourceType() == MarkerResourceType); if (!m_markerData) - m_markerData = MarkerData::create(); + m_markerData = std::make_unique<MarkerData>(); m_markerData->markerStart = markerStart; return true; @@ -512,7 +534,7 @@ bool SVGResources::setMarkerMid(RenderSVGResourceMarker* markerMid) ASSERT(markerMid->resourceType() == MarkerResourceType); if (!m_markerData) - m_markerData = MarkerData::create(); + m_markerData = std::make_unique<MarkerData>(); m_markerData->markerMid = markerMid; return true; @@ -533,7 +555,7 @@ bool SVGResources::setMarkerEnd(RenderSVGResourceMarker* markerEnd) ASSERT(markerEnd->resourceType() == MarkerResourceType); if (!m_markerData) - m_markerData = MarkerData::create(); + m_markerData = std::make_unique<MarkerData>(); m_markerData->markerEnd = markerEnd; return true; @@ -554,7 +576,7 @@ bool SVGResources::setMasker(RenderSVGResourceMasker* masker) ASSERT(masker->resourceType() == MaskerResourceType); if (!m_clipperFilterMaskerData) - m_clipperFilterMaskerData = ClipperFilterMaskerData::create(); + m_clipperFilterMaskerData = std::make_unique<ClipperFilterMaskerData>(); m_clipperFilterMaskerData->masker = masker; return true; @@ -577,7 +599,7 @@ bool SVGResources::setFill(RenderSVGResourceContainer* fill) || fill->resourceType() == RadialGradientResourceType); if (!m_fillStrokeData) - m_fillStrokeData = FillStrokeData::create(); + m_fillStrokeData = std::make_unique<FillStrokeData>(); m_fillStrokeData->fill = fill; return true; @@ -600,7 +622,7 @@ bool SVGResources::setStroke(RenderSVGResourceContainer* stroke) || stroke->resourceType() == RadialGradientResourceType); if (!m_fillStrokeData) - m_fillStrokeData = FillStrokeData::create(); + m_fillStrokeData = std::make_unique<FillStrokeData>(); m_fillStrokeData->stroke = stroke; return true; @@ -628,7 +650,7 @@ void SVGResources::resetLinkedResource() m_linkedResource = 0; } -#ifndef NDEBUG +#if ENABLE(TREE_DEBUGGING) void SVGResources::dump(const RenderObject* object) { ASSERT(object); @@ -642,10 +664,8 @@ void SVGResources::dump(const RenderObject* object) if (m_clipperFilterMaskerData) { if (RenderSVGResourceClipper* clipper = m_clipperFilterMaskerData->clipper) fprintf(stderr, " |-> Clipper : %p (node=%p)\n", clipper, &clipper->clipPathElement()); -#if ENABLE(FILTERS) if (RenderSVGResourceFilter* filter = m_clipperFilterMaskerData->filter) fprintf(stderr, " |-> Filter : %p (node=%p)\n", filter, &filter->filterElement()); -#endif if (RenderSVGResourceMasker* masker = m_clipperFilterMaskerData->masker) fprintf(stderr, " |-> Masker : %p (node=%p)\n", masker, &masker->maskElement()); } @@ -672,5 +692,3 @@ void SVGResources::dump(const RenderObject* object) #endif } - -#endif diff --git a/Source/WebCore/rendering/svg/SVGResources.h b/Source/WebCore/rendering/svg/SVGResources.h index 240276a1d..e92b76199 100644 --- a/Source/WebCore/rendering/svg/SVGResources.h +++ b/Source/WebCore/rendering/svg/SVGResources.h @@ -17,25 +17,25 @@ * Boston, MA 02110-1301, USA. */ -#ifndef SVGResources_h -#define SVGResources_h +#pragma once -#if ENABLE(SVG) +#include "RenderSVGResourceMarker.h" +#include <memory> #include <wtf/HashSet.h> #include <wtf/Noncopyable.h> -#include <wtf/OwnPtr.h> -#include <wtf/PassOwnPtr.h> namespace WebCore { class Document; class RenderElement; class RenderObject; +class RenderStyle; class RenderSVGResourceClipper; class RenderSVGResourceContainer; class RenderSVGResourceFilter; class RenderSVGResourceMarker; class RenderSVGResourceMasker; +class RenderSVGRoot; class SVGRenderStyle; // Holds a set of resources associated with a RenderObject @@ -44,27 +44,21 @@ class SVGResources { public: SVGResources(); - bool buildCachedResources(const RenderElement&, const SVGRenderStyle&); + bool buildCachedResources(const RenderElement&, const RenderStyle&); + void layoutDifferentRootIfNeeded(const RenderSVGRoot*); // Ordinary resources - RenderSVGResourceClipper* clipper() const { return m_clipperFilterMaskerData ? m_clipperFilterMaskerData->clipper : 0; } - RenderSVGResourceMarker* markerStart() const { return m_markerData ? m_markerData->markerStart : 0; } - RenderSVGResourceMarker* markerMid() const { return m_markerData ? m_markerData->markerMid : 0; } - RenderSVGResourceMarker* markerEnd() const { return m_markerData ? m_markerData->markerEnd : 0; } - RenderSVGResourceMasker* masker() const { return m_clipperFilterMaskerData ? m_clipperFilterMaskerData->masker : 0; } - - RenderSVGResourceFilter* filter() const - { -#if ENABLE(FILTERS) - if (m_clipperFilterMaskerData) - return m_clipperFilterMaskerData->filter; -#endif - return 0; - } + RenderSVGResourceClipper* clipper() const { return m_clipperFilterMaskerData ? m_clipperFilterMaskerData->clipper : nullptr; } + RenderSVGResourceMarker* markerStart() const { return m_markerData ? m_markerData->markerStart : nullptr; } + RenderSVGResourceMarker* markerMid() const { return m_markerData ? m_markerData->markerMid : nullptr; } + RenderSVGResourceMarker* markerEnd() const { return m_markerData ? m_markerData->markerEnd : nullptr; } + bool markerReverseStart() const; + RenderSVGResourceMasker* masker() const { return m_clipperFilterMaskerData ? m_clipperFilterMaskerData->masker : nullptr; } + RenderSVGResourceFilter* filter() const { return m_clipperFilterMaskerData ? m_clipperFilterMaskerData->filter : nullptr; } // Paint servers - RenderSVGResourceContainer* fill() const { return m_fillStrokeData ? m_fillStrokeData->fill : 0; } - RenderSVGResourceContainer* stroke() const { return m_fillStrokeData ? m_fillStrokeData->stroke : 0; } + RenderSVGResourceContainer* fill() const { return m_fillStrokeData ? m_fillStrokeData->fill : nullptr; } + RenderSVGResourceContainer* stroke() const { return m_fillStrokeData ? m_fillStrokeData->stroke : nullptr; } // Chainable resources - linked through xlink:href RenderSVGResourceContainer* linkedResource() const { return m_linkedResource; } @@ -72,10 +66,10 @@ public: void buildSetOfResources(HashSet<RenderSVGResourceContainer*>&); // Methods operating on all cached resources - void removeClientFromCache(RenderObject&, bool markForInvalidation = true) const; + void removeClientFromCache(RenderElement&, bool markForInvalidation = true) const; void resourceDestroyed(RenderSVGResourceContainer&); -#ifndef NDEBUG +#if ENABLE(TREE_DEBUGGING) void dump(const RenderObject*); #endif @@ -84,9 +78,7 @@ private: // Only used by SVGResourcesCache cycle detection logic void resetClipper(); -#if ENABLE(FILTERS) void resetFilter(); -#endif void resetMarkerStart(); void resetMarkerMid(); void resetMarkerEnd(); @@ -97,9 +89,7 @@ private: private: bool setClipper(RenderSVGResourceClipper*); -#if ENABLE(FILTERS) bool setFilter(RenderSVGResourceFilter*); -#endif bool setMarkerStart(RenderSVGResourceMarker*); bool setMarkerMid(RenderSVGResourceMarker*); bool setMarkerEnd(RenderSVGResourceMarker*); @@ -118,22 +108,13 @@ private: public: ClipperFilterMaskerData() : clipper(0) -#if ENABLE(FILTERS) , filter(0) -#endif , masker(0) { } - static PassOwnPtr<ClipperFilterMaskerData> create() - { - return adoptPtr(new ClipperFilterMaskerData); - } - RenderSVGResourceClipper* clipper; -#if ENABLE(FILTERS) RenderSVGResourceFilter* filter; -#endif RenderSVGResourceMasker* masker; }; @@ -149,11 +130,6 @@ private: { } - static PassOwnPtr<MarkerData> create() - { - return adoptPtr(new MarkerData); - } - RenderSVGResourceMarker* markerStart; RenderSVGResourceMarker* markerMid; RenderSVGResourceMarker* markerEnd; @@ -172,22 +148,14 @@ private: { } - static PassOwnPtr<FillStrokeData> create() - { - return adoptPtr(new FillStrokeData); - } - RenderSVGResourceContainer* fill; RenderSVGResourceContainer* stroke; }; - OwnPtr<ClipperFilterMaskerData> m_clipperFilterMaskerData; - OwnPtr<MarkerData> m_markerData; - OwnPtr<FillStrokeData> m_fillStrokeData; + std::unique_ptr<ClipperFilterMaskerData> m_clipperFilterMaskerData; + std::unique_ptr<MarkerData> m_markerData; + std::unique_ptr<FillStrokeData> m_fillStrokeData; RenderSVGResourceContainer* m_linkedResource; }; -} - -#endif -#endif +} // namespace WebCore diff --git a/Source/WebCore/rendering/svg/SVGResourcesCache.cpp b/Source/WebCore/rendering/svg/SVGResourcesCache.cpp index fad518a32..83d912eeb 100644 --- a/Source/WebCore/rendering/svg/SVGResourcesCache.cpp +++ b/Source/WebCore/rendering/svg/SVGResourcesCache.cpp @@ -20,8 +20,6 @@ #include "config.h" #include "SVGResourcesCache.h" -#if ENABLE(SVG) -#include "HTMLNames.h" #include "RenderSVGResourceContainer.h" #include "SVGResources.h" #include "SVGResourcesCycleSolver.h" @@ -40,15 +38,13 @@ void SVGResourcesCache::addResourcesFromRenderer(RenderElement& renderer, const { ASSERT(!m_cache.contains(&renderer)); - const SVGRenderStyle& svgStyle = style.svgStyle(); - // Build a list of all resources associated with the passed RenderObject - OwnPtr<SVGResources> newResources = adoptPtr(new SVGResources); - if (!newResources->buildCachedResources(renderer, svgStyle)) + auto newResources = std::make_unique<SVGResources>(); + if (!newResources->buildCachedResources(renderer, style)) return; // Put object in cache. - SVGResources& resources = *m_cache.add(&renderer, newResources.release()).iterator->value; + SVGResources& resources = *m_cache.add(&renderer, WTFMove(newResources)).iterator->value; // Run cycle-detection _afterwards_, so self-references can be caught as well. SVGResourcesCycleSolver solver(renderer, resources); @@ -58,13 +54,13 @@ void SVGResourcesCache::addResourcesFromRenderer(RenderElement& renderer, const HashSet<RenderSVGResourceContainer*> resourceSet; resources.buildSetOfResources(resourceSet); - for (auto it = resourceSet.begin(), end = resourceSet.end(); it != end; ++it) - (*it)->addClient(&renderer); + for (auto* resourceContainer : resourceSet) + resourceContainer->addClient(renderer); } void SVGResourcesCache::removeResourcesFromRenderer(RenderElement& renderer) { - OwnPtr<SVGResources> resources = m_cache.take(&renderer); + std::unique_ptr<SVGResources> resources = m_cache.take(&renderer); if (!resources) return; @@ -72,29 +68,23 @@ void SVGResourcesCache::removeResourcesFromRenderer(RenderElement& renderer) HashSet<RenderSVGResourceContainer*> resourceSet; resources->buildSetOfResources(resourceSet); - for (auto it = resourceSet.begin(), end = resourceSet.end(); it != end; ++it) - (*it)->removeClient(&renderer); + for (auto* resourceContainer : resourceSet) + resourceContainer->removeClient(renderer); } -static inline SVGResourcesCache* resourcesCacheFromRenderObject(const RenderObject& renderer) +static inline SVGResourcesCache& resourcesCacheFromRenderer(const RenderElement& renderer) { - SVGDocumentExtensions* extensions = renderer.document().accessSVGExtensions(); - ASSERT(extensions); - - SVGResourcesCache* cache = extensions->resourcesCache(); - ASSERT(cache); - - return cache; + return renderer.document().accessSVGExtensions().resourcesCache(); } -SVGResources* SVGResourcesCache::cachedResourcesForRenderObject(const RenderObject& renderer) +SVGResources* SVGResourcesCache::cachedResourcesForRenderer(const RenderElement& renderer) { - return resourcesCacheFromRenderObject(renderer)->m_cache.get(&renderer); + return resourcesCacheFromRenderer(renderer).m_cache.get(&renderer); } void SVGResourcesCache::clientLayoutChanged(RenderElement& renderer) { - SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(renderer); + auto* resources = SVGResourcesCache::cachedResourcesForRenderer(renderer); if (!resources) return; @@ -122,15 +112,15 @@ void SVGResourcesCache::clientStyleChanged(RenderElement& renderer, StyleDiffere // FIXME: Avoid passing in a useless StyleDifference, but instead compare oldStyle/newStyle to see which resources changed // to be able to selectively rebuild individual resources, instead of all of them. if (rendererCanHaveResources(renderer)) { - SVGResourcesCache* cache = resourcesCacheFromRenderObject(renderer); - cache->removeResourcesFromRenderer(renderer); - cache->addResourcesFromRenderer(renderer, newStyle); + auto& cache = resourcesCacheFromRenderer(renderer); + cache.removeResourcesFromRenderer(renderer); + cache.addResourcesFromRenderer(renderer, newStyle); } RenderSVGResource::markForLayoutAndParentResourceInvalidation(renderer, false); if (renderer.element() && !renderer.element()->isSVGElement()) - renderer.element()->setNeedsStyleRecalc(SyntheticStyleChange); + renderer.element()->invalidateStyleAndLayerComposition(); } void SVGResourcesCache::clientWasAddedToTree(RenderObject& renderer) @@ -142,9 +132,8 @@ void SVGResourcesCache::clientWasAddedToTree(RenderObject& renderer) if (!rendererCanHaveResources(renderer)) return; - RenderElement& elementRenderer = toRenderElement(renderer); - SVGResourcesCache* cache = resourcesCacheFromRenderObject(elementRenderer); - cache->addResourcesFromRenderer(elementRenderer, elementRenderer.style()); + RenderElement& elementRenderer = downcast<RenderElement>(renderer); + resourcesCacheFromRenderer(elementRenderer).addResourcesFromRenderer(elementRenderer, elementRenderer.style()); } void SVGResourcesCache::clientWillBeRemovedFromTree(RenderObject& renderer) @@ -156,40 +145,33 @@ void SVGResourcesCache::clientWillBeRemovedFromTree(RenderObject& renderer) if (!rendererCanHaveResources(renderer)) return; - RenderElement& elementRenderer = toRenderElement(renderer); - SVGResourcesCache* cache = resourcesCacheFromRenderObject(elementRenderer); - cache->removeResourcesFromRenderer(elementRenderer); + RenderElement& elementRenderer = downcast<RenderElement>(renderer); + resourcesCacheFromRenderer(elementRenderer).removeResourcesFromRenderer(elementRenderer); } void SVGResourcesCache::clientDestroyed(RenderElement& renderer) { - SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(renderer); - if (resources) + if (auto* resources = SVGResourcesCache::cachedResourcesForRenderer(renderer)) resources->removeClientFromCache(renderer); - SVGResourcesCache* cache = resourcesCacheFromRenderObject(renderer); - cache->removeResourcesFromRenderer(renderer); + resourcesCacheFromRenderer(renderer).removeResourcesFromRenderer(renderer); } void SVGResourcesCache::resourceDestroyed(RenderSVGResourceContainer& resource) { - SVGResourcesCache* cache = resourcesCacheFromRenderObject(resource); + auto& cache = resourcesCacheFromRenderer(resource); // The resource itself may have clients, that need to be notified. - cache->removeResourcesFromRenderer(resource); + cache.removeResourcesFromRenderer(resource); - for (auto it = cache->m_cache.begin(), end = cache->m_cache.end(); it != end; ++it) { - it->value->resourceDestroyed(resource); + for (auto& it : cache.m_cache) { + it.value->resourceDestroyed(resource); // Mark users of destroyed resources as pending resolution based on the id of the old resource. Element& resourceElement = resource.element(); - Element* clientElement = toElement(it->key->node()); - SVGDocumentExtensions* extensions = clientElement->document().accessSVGExtensions(); - - extensions->addPendingResource(resourceElement.getIdAttribute(), clientElement); + Element* clientElement = it.key->element(); + clientElement->document().accessSVGExtensions().addPendingResource(resourceElement.getIdAttribute(), clientElement); } } } - -#endif diff --git a/Source/WebCore/rendering/svg/SVGResourcesCache.h b/Source/WebCore/rendering/svg/SVGResourcesCache.h index fe6d5e6ed..6983a7f3c 100644 --- a/Source/WebCore/rendering/svg/SVGResourcesCache.h +++ b/Source/WebCore/rendering/svg/SVGResourcesCache.h @@ -17,13 +17,12 @@ * Boston, MA 02110-1301, USA. */ -#ifndef SVGResourcesCache_h -#define SVGResourcesCache_h +#pragma once -#if ENABLE(SVG) #include "RenderStyleConstants.h" +#include <memory> #include <wtf/HashMap.h> -#include <wtf/OwnPtr.h> +#include <wtf/Noncopyable.h> namespace WebCore { @@ -39,7 +38,7 @@ public: SVGResourcesCache(); ~SVGResourcesCache(); - static SVGResources* cachedResourcesForRenderObject(const RenderObject&); + static SVGResources* cachedResourcesForRenderer(const RenderElement&); // Called from all SVG renderers addChild() methods. static void clientWasAddedToTree(RenderObject&); @@ -63,11 +62,8 @@ private: void addResourcesFromRenderer(RenderElement&, const RenderStyle&); void removeResourcesFromRenderer(RenderElement&); - typedef HashMap<const RenderObject*, OwnPtr<SVGResources>> CacheMap; + typedef HashMap<const RenderElement*, std::unique_ptr<SVGResources>> CacheMap; CacheMap m_cache; }; -} - -#endif -#endif +} // namespace WebCore diff --git a/Source/WebCore/rendering/svg/SVGResourcesCycleSolver.cpp b/Source/WebCore/rendering/svg/SVGResourcesCycleSolver.cpp index c6776f667..be76c1f9d 100644 --- a/Source/WebCore/rendering/svg/SVGResourcesCycleSolver.cpp +++ b/Source/WebCore/rendering/svg/SVGResourcesCycleSolver.cpp @@ -20,12 +20,8 @@ #include "config.h" #include "SVGResourcesCycleSolver.h" -// Set to a value > 0, to debug the resource cache. -#define DEBUG_CYCLE_DETECTION 0 - -#if ENABLE(SVG) -#include "RenderElement.h" -#include "RenderIterator.h" +#include "Logging.h" +#include "RenderAncestorIterator.h" #include "RenderSVGResourceClipper.h" #include "RenderSVGResourceFilter.h" #include "RenderSVGResourceMarker.h" @@ -35,6 +31,15 @@ #include "SVGResources.h" #include "SVGResourcesCache.h" +// Set to truthy value to debug the resource cache. +#define DEBUG_CYCLE_DETECTION 0 + +#if DEBUG_CYCLE_DETECTION +#define LOG_DEBUG_CYCLE(...) LOG(SVG, __VA_ARGS__) +#else +#define LOG_DEBUG_CYCLE(...) ((void)0) +#endif + namespace WebCore { SVGResourcesCycleSolver::SVGResourcesCycleSolver(RenderElement& renderer, SVGResources& resources) @@ -49,43 +54,65 @@ SVGResourcesCycleSolver::~SVGResourcesCycleSolver() bool SVGResourcesCycleSolver::resourceContainsCycles(RenderElement& renderer) const { + LOG_DEBUG_CYCLE("\n(%p) Check for cycles\n", &renderer); + // First operate on the resources of the given renderer. // <marker id="a"> <path marker-start="url(#b)"/> ... // <marker id="b" marker-start="url(#a)"/> - if (SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(renderer)) { + if (auto* resources = SVGResourcesCache::cachedResourcesForRenderer(renderer)) { HashSet<RenderSVGResourceContainer*> resourceSet; resources->buildSetOfResources(resourceSet); - // Walk all resources and check wheter they reference any resource contained in the resources set. - for (auto resource : resourceSet) { + LOG_DEBUG_CYCLE("(%p) Examine our cached resources\n", &renderer); + + // Walk all resources and check whether they reference any resource contained in the resources set. + for (auto* resource : resourceSet) { + LOG_DEBUG_CYCLE("(%p) Check %p\n", &renderer, resource); if (m_allResources.contains(resource)) return true; + + // Now check if the resources themselves contain cycles. + if (resourceContainsCycles(*resource)) + return true; } } + LOG_DEBUG_CYCLE("(%p) Now the children renderers\n", &renderer); + // Then operate on the child resources of the given renderer. // <marker id="a"> <path marker-start="url(#b)"/> ... // <marker id="b"> <path marker-start="url(#a)"/> ... for (auto& child : childrenOfType<RenderElement>(renderer)) { - SVGResources* childResources = SVGResourcesCache::cachedResourcesForRenderObject(child); - if (!childResources) - continue; - - // A child of the given 'resource' contains resources. - HashSet<RenderSVGResourceContainer*> childResourceSet; - childResources->buildSetOfResources(childResourceSet); - - // Walk all child resources and check wheter they reference any resource contained in the resources set. - for (auto& resource : childResourceSet) { - if (m_allResources.contains(resource)) - return true; + + LOG_DEBUG_CYCLE("(%p) Checking child %p\n", &renderer, &child); + + if (auto* childResources = SVGResourcesCache::cachedResourcesForRenderer(child)) { + + LOG_DEBUG_CYCLE("(%p) Child %p had cached resources. Check them.\n", &renderer, &child); + + // A child of the given 'resource' contains resources. + HashSet<RenderSVGResourceContainer*> childResourceSet; + childResources->buildSetOfResources(childResourceSet); + + // Walk all child resources and check whether they reference any resource contained in the resources set. + for (auto* resource : childResourceSet) { + LOG_DEBUG_CYCLE("(%p) Child %p had resource %p\n", &renderer, &child, resource); + if (m_allResources.contains(resource)) + return true; + } } + LOG_DEBUG_CYCLE("(%p) Recurse into child %p\n", &renderer, &child); + // Walk children recursively, stop immediately if we found a cycle if (resourceContainsCycles(child)) return true; + + LOG_DEBUG_CYCLE("\n(%p) Child %p was ok\n", &renderer, &child); } + LOG_DEBUG_CYCLE("\n(%p) No cycles found\n", &renderer); + return false; } @@ -93,8 +120,8 @@ void SVGResourcesCycleSolver::resolveCycles() { ASSERT(m_allResources.isEmpty()); -#if DEBUG_CYCLE_DETECTION > 0 - fprintf(stderr, "\nBefore cycle detection:\n"); +#if DEBUG_CYCLE_DETECTION + LOG_DEBUG_CYCLE("\nBefore cycle detection:\n"); m_resources.dump(&m_renderer); #endif @@ -104,49 +131,52 @@ void SVGResourcesCycleSolver::resolveCycles() ASSERT(!localResources.isEmpty()); // Add all parent resource containers to the HashSet. - HashSet<RenderSVGResourceContainer*> parentResources; - auto parent = m_renderer.parent(); - while (parent) { - if (parent->isSVGResourceContainer()) - parentResources.add(parent->toRenderSVGResourceContainer()); - parent = parent->parent(); - } + HashSet<RenderSVGResourceContainer*> ancestorResources; + for (auto& resource : ancestorsOfType<RenderSVGResourceContainer>(m_renderer)) + ancestorResources.add(&resource); -#if DEBUG_CYCLE_DETECTION > 0 - fprintf(stderr, "\nDetecting wheter any resources references any of following objects:\n"); +#if DEBUG_CYCLE_DETECTION + LOG_DEBUG_CYCLE("\nDetecting whether any resources references any of following objects:\n"); { - fprintf(stderr, "Local resources:\n"); - for (auto it = localResources.begin(), end = localResources.end(); it != end; ++it) - fprintf(stderr, "|> %s: object=%p (node=%p)\n", (*it)->renderName(), *it, (*it)->node()); + LOG_DEBUG_CYCLE("Local resources:\n"); + for (RenderObject* resource : localResources) + LOG_DEBUG_CYCLE("|> %s : %p (node %p)\n", resource->renderName(), resource, resource->node()); fprintf(stderr, "Parent resources:\n"); - for (auto it = parentResources.begin(), end = parentResources.end(); it != end; ++it) - fprintf(stderr, "|> %s: object=%p (node=%p)\n", (*it)->renderName(), *it, (*it)->node()); + for (RenderObject* resource : ancestorResources) + LOG_DEBUG_CYCLE("|> %s : %p (node %p)\n", resource->renderName(), resource, resource->node()); } #endif // Build combined set of local and parent resources. m_allResources = localResources; - for (auto it = parentResources.begin(), end = parentResources.end(); it != end; ++it) - m_allResources.add(*it); + for (auto* resource : ancestorResources) + m_allResources.add(resource); // If we're a resource, add ourselves to the HashSet. - if (m_renderer.isSVGResourceContainer()) - m_allResources.add(m_renderer.toRenderSVGResourceContainer()); + if (is<RenderSVGResourceContainer>(m_renderer)) + m_allResources.add(&downcast<RenderSVGResourceContainer>(m_renderer)); ASSERT(!m_allResources.isEmpty()); +#if DEBUG_CYCLE_DETECTION + LOG_DEBUG_CYCLE("\nAll resources:\n"); + for (auto* resource : m_allResources) + LOG_DEBUG_CYCLE("- %p\n", resource); +#endif + // The job of this function is to determine wheter any of the 'resources' associated with the given 'renderer' - // references us (or wheter any of its kids references us) -> that's a cycle, we need to find and break it. - for (auto it = localResources.begin(), end = localResources.end(); it != end; ++it) { - RenderSVGResourceContainer& resource = **it; - if (parentResources.contains(&resource) || resourceContainsCycles(resource)) - breakCycle(resource); + // references us (or whether any of its kids references us) -> that's a cycle, we need to find and break it. + for (auto* resource : localResources) { + if (ancestorResources.contains(resource) || resourceContainsCycles(*resource)) { + LOG_DEBUG_CYCLE("\n**** Detected a cycle (see the last test in the output above) ****\n"); + breakCycle(*resource); + } } -#if DEBUG_CYCLE_DETECTION > 0 - fprintf(stderr, "\nAfter cycle detection:\n"); - m_resources.dump(m_renderer); +#if DEBUG_CYCLE_DETECTION + LOG_DEBUG_CYCLE("\nAfter cycle detection:\n"); + m_resources.dump(&m_renderer); #endif m_allResources.clear(); @@ -183,10 +213,8 @@ void SVGResourcesCycleSolver::breakCycle(RenderSVGResourceContainer& resourceLea m_resources.resetStroke(); break; case FilterResourceType: -#if ENABLE(FILTERS) ASSERT(&resourceLeadingToCycle == m_resources.filter()); m_resources.resetFilter(); -#endif break; case ClipperResourceType: ASSERT(&resourceLeadingToCycle == m_resources.clipper()); @@ -199,5 +227,3 @@ void SVGResourcesCycleSolver::breakCycle(RenderSVGResourceContainer& resourceLea } } - -#endif diff --git a/Source/WebCore/rendering/svg/SVGResourcesCycleSolver.h b/Source/WebCore/rendering/svg/SVGResourcesCycleSolver.h index fd95a7428..2e666a7ee 100644 --- a/Source/WebCore/rendering/svg/SVGResourcesCycleSolver.h +++ b/Source/WebCore/rendering/svg/SVGResourcesCycleSolver.h @@ -17,10 +17,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef SVGResourcesCycleSolver_h -#define SVGResourcesCycleSolver_h +#pragma once -#if ENABLE(SVG) #include <wtf/HashSet.h> #include <wtf/Noncopyable.h> @@ -47,7 +45,4 @@ private: HashSet<RenderSVGResourceContainer*> m_allResources; }; -} - -#endif -#endif +} // namespace WebCore diff --git a/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp b/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp index ec628b168..c6d23f57c 100644 --- a/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp +++ b/Source/WebCore/rendering/svg/SVGRootInlineBox.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz> - * Copyright (C) 2006 Apple Computer Inc. + * Copyright (C) 2006 Apple Inc. * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> * Copyright (C) Research In Motion Limited 2010. All rights reserved. * Copyright (C) 2011 Torch Mobile (Beijing) CO. Ltd. All rights reserved. @@ -24,9 +24,9 @@ #include "config.h" #include "SVGRootInlineBox.h" -#if ENABLE(SVG) #include "GraphicsContext.h" #include "RenderSVGText.h" +#include "RenderSVGTextPath.h" #include "SVGInlineFlowBox.h" #include "SVGInlineTextBox.h" #include "SVGNames.h" @@ -43,48 +43,44 @@ SVGRootInlineBox::SVGRootInlineBox(RenderSVGText& renderSVGText) RenderSVGText& SVGRootInlineBox::renderSVGText() { - return toRenderSVGText(blockFlow()); + return downcast<RenderSVGText>(blockFlow()); } -void SVGRootInlineBox::paint(PaintInfo& paintInfo, const LayoutPoint&, LayoutUnit, LayoutUnit) +void SVGRootInlineBox::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset, LayoutUnit, LayoutUnit) { ASSERT(paintInfo.phase == PaintPhaseForeground || paintInfo.phase == PaintPhaseSelection); - ASSERT(!paintInfo.context->paintingDisabled()); + ASSERT(!paintInfo.context().paintingDisabled()); bool isPrinting = renderSVGText().document().printing(); bool hasSelection = !isPrinting && selectionState() != RenderObject::SelectionNone; + bool shouldPaintSelectionHighlight = !(paintInfo.paintBehavior & PaintBehaviorSkipSelectionHighlight); PaintInfo childPaintInfo(paintInfo); - if (hasSelection) { + if (hasSelection && shouldPaintSelectionHighlight) { for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { - if (child->isSVGInlineTextBox()) - toSVGInlineTextBox(child)->paintSelectionBackground(childPaintInfo); - else if (child->isSVGInlineFlowBox()) - toSVGInlineFlowBox(child)->paintSelectionBackground(childPaintInfo); + if (is<SVGInlineTextBox>(*child)) + downcast<SVGInlineTextBox>(*child).paintSelectionBackground(childPaintInfo); + else if (is<SVGInlineFlowBox>(*child)) + downcast<SVGInlineFlowBox>(*child).paintSelectionBackground(childPaintInfo); } } SVGRenderingContext renderingContext(renderSVGText(), paintInfo, SVGRenderingContext::SaveGraphicsContext); if (renderingContext.isRenderingPrepared()) { - for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) { - if (child->isSVGInlineTextBox()) - SVGInlineFlowBox::computeTextMatchMarkerRectForRenderer(&toSVGInlineTextBox(child)->renderer()); - - child->paint(paintInfo, LayoutPoint(), 0, 0); - } + for (InlineBox* child = firstChild(); child; child = child->nextOnLine()) + child->paint(paintInfo, paintOffset, 0, 0); } } void SVGRootInlineBox::computePerCharacterLayoutInformation() { - RenderSVGText* textRoot = toRenderSVGText(&blockFlow()); - ASSERT(textRoot); + auto& textRoot = downcast<RenderSVGText>(blockFlow()); - Vector<SVGTextLayoutAttributes*>& layoutAttributes = textRoot->layoutAttributes(); + Vector<SVGTextLayoutAttributes*>& layoutAttributes = textRoot.layoutAttributes(); if (layoutAttributes.isEmpty()) return; - if (textRoot->needsReordering()) + if (textRoot.needsReordering()) reorderValueLists(layoutAttributes); // Perform SVG text layout phase two (see SVGTextLayoutEngine for details). @@ -104,31 +100,27 @@ void SVGRootInlineBox::computePerCharacterLayoutInformation() void SVGRootInlineBox::layoutCharactersInTextBoxes(InlineFlowBox* start, SVGTextLayoutEngine& characterLayout) { for (InlineBox* child = start->firstChild(); child; child = child->nextOnLine()) { - if (child->isSVGInlineTextBox()) { - ASSERT(child->renderer().isSVGInlineText()); - - SVGInlineTextBox* textBox = toSVGInlineTextBox(child); - characterLayout.layoutInlineTextBox(textBox); + if (is<SVGInlineTextBox>(*child)) { + ASSERT(is<RenderSVGInlineText>(child->renderer())); + characterLayout.layoutInlineTextBox(downcast<SVGInlineTextBox>(*child)); } else { // Skip generated content. Node* node = child->renderer().node(); if (!node) continue; - ASSERT_WITH_SECURITY_IMPLICATION(child->isInlineFlowBox()); - - SVGInlineFlowBox* flowBox = toSVGInlineFlowBox(child); + auto& flowBox = downcast<SVGInlineFlowBox>(*child); bool isTextPath = node->hasTagName(SVGNames::textPathTag); if (isTextPath) { // Build text chunks for all <textPath> children, using the line layout algorithm. // This is needeed as text-anchor is just an additional startOffset for text paths. SVGTextLayoutEngine lineLayout(characterLayout.layoutAttributes()); - layoutCharactersInTextBoxes(flowBox, lineLayout); + layoutCharactersInTextBoxes(&flowBox, lineLayout); - characterLayout.beginTextPathLayout(&child->renderer(), lineLayout); + characterLayout.beginTextPathLayout(downcast<RenderSVGTextPath>(child->renderer()), lineLayout); } - layoutCharactersInTextBoxes(flowBox, characterLayout); + layoutCharactersInTextBoxes(&flowBox, characterLayout); if (isTextPath) characterLayout.endTextPathLayout(); @@ -140,30 +132,28 @@ void SVGRootInlineBox::layoutChildBoxes(InlineFlowBox* start, FloatRect* childRe { for (InlineBox* child = start->firstChild(); child; child = child->nextOnLine()) { FloatRect boxRect; - if (child->isSVGInlineTextBox()) { - ASSERT(child->renderer().isSVGInlineText()); - - SVGInlineTextBox* textBox = toSVGInlineTextBox(child); - boxRect = textBox->calculateBoundaries(); - textBox->setX(boxRect.x()); - textBox->setY(boxRect.y()); - textBox->setLogicalWidth(boxRect.width()); - textBox->setLogicalHeight(boxRect.height()); + if (is<SVGInlineTextBox>(*child)) { + ASSERT(is<RenderSVGInlineText>(child->renderer())); + + auto& textBox = downcast<SVGInlineTextBox>(*child); + boxRect = textBox.calculateBoundaries(); + textBox.setX(boxRect.x()); + textBox.setY(boxRect.y()); + textBox.setLogicalWidth(boxRect.width()); + textBox.setLogicalHeight(boxRect.height()); } else { // Skip generated content. if (!child->renderer().node()) continue; - ASSERT_WITH_SECURITY_IMPLICATION(child->isInlineFlowBox()); - - SVGInlineFlowBox* flowBox = toSVGInlineFlowBox(child); - layoutChildBoxes(flowBox); + auto& flowBox = downcast<SVGInlineFlowBox>(*child); + layoutChildBoxes(&flowBox); - boxRect = flowBox->calculateBoundaries(); - flowBox->setX(boxRect.x()); - flowBox->setY(boxRect.y()); - flowBox->setLogicalWidth(boxRect.width()); - flowBox->setLogicalHeight(boxRect.height()); + boxRect = flowBox.calculateBoundaries(); + flowBox.setX(boxRect.x()); + flowBox.setY(boxRect.y()); + flowBox.setLogicalWidth(boxRect.width()); + flowBox.setLogicalHeight(boxRect.height()); } if (childRect) childRect->unite(boxRect); @@ -203,7 +193,7 @@ InlineBox* SVGRootInlineBox::closestLeafChildForPosition(const LayoutPoint& poin return firstLeaf; // FIXME: Check for vertical text! - InlineBox* closestLeaf = 0; + InlineBox* closestLeaf = nullptr; for (InlineBox* leaf = firstLeaf; leaf; leaf = leaf->nextLeafChild()) { if (!leaf->isSVGInlineTextBox()) continue; @@ -220,6 +210,18 @@ InlineBox* SVGRootInlineBox::closestLeafChildForPosition(const LayoutPoint& poin return closestLeaf ? closestLeaf : lastLeaf; } +bool SVGRootInlineBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom, HitTestAction hitTestAction) +{ + for (InlineBox* leaf = firstLeafChild(); leaf; leaf = leaf->nextLeafChild()) { + if (!leaf->isSVGInlineTextBox()) + continue; + if (leaf->nodeAtPoint(request, result, locationInContainer, accumulatedOffset, lineTop, lineBottom, hitTestAction)) + return true; + } + + return false; +} + static inline void swapItemsInLayoutAttributes(SVGTextLayoutAttributes* firstAttributes, SVGTextLayoutAttributes* lastAttributes, unsigned firstPosition, unsigned lastPosition) { SVGCharacterDataMap::iterator itFirst = firstAttributes->characterDataMap().find(firstPosition + 1); @@ -246,8 +248,8 @@ static inline void swapItemsInLayoutAttributes(SVGTextLayoutAttributes* firstAtt static inline void findFirstAndLastAttributesInVector(Vector<SVGTextLayoutAttributes*>& attributes, RenderSVGInlineText* firstContext, RenderSVGInlineText* lastContext, SVGTextLayoutAttributes*& first, SVGTextLayoutAttributes*& last) { - first = 0; - last = 0; + first = nullptr; + last = nullptr; unsigned attributesSize = attributes.size(); for (unsigned i = 0; i < attributesSize; ++i) { @@ -274,7 +276,7 @@ static inline void reverseInlineBoxRangeAndValueListsIfNeeded(void* userData, Ve if (first == last || first == --last) return; - if (!(*last)->isSVGInlineTextBox() || !(*first)->isSVGInlineTextBox()) { + if (!is<SVGInlineTextBox>(**last) || !is<SVGInlineTextBox>(**first)) { InlineBox* temp = *first; *first = *last; *last = temp; @@ -282,18 +284,18 @@ static inline void reverseInlineBoxRangeAndValueListsIfNeeded(void* userData, Ve continue; } - SVGInlineTextBox* firstTextBox = toSVGInlineTextBox(*first); - SVGInlineTextBox* lastTextBox = toSVGInlineTextBox(*last); + auto& firstTextBox = downcast<SVGInlineTextBox>(**first); + auto& lastTextBox = downcast<SVGInlineTextBox>(**last); // Reordering is only necessary for BiDi text that is _absolutely_ positioned. - if (firstTextBox->len() == 1 && firstTextBox->len() == lastTextBox->len()) { - RenderSVGInlineText& firstContext = firstTextBox->renderer(); - RenderSVGInlineText& lastContext = lastTextBox->renderer(); + if (firstTextBox.len() == 1 && firstTextBox.len() == lastTextBox.len()) { + RenderSVGInlineText& firstContext = firstTextBox.renderer(); + RenderSVGInlineText& lastContext = lastTextBox.renderer(); - SVGTextLayoutAttributes* firstAttributes = 0; - SVGTextLayoutAttributes* lastAttributes = 0; + SVGTextLayoutAttributes* firstAttributes = nullptr; + SVGTextLayoutAttributes* lastAttributes = nullptr; findFirstAndLastAttributesInVector(attributes, &firstContext, &lastContext, firstAttributes, lastAttributes); - swapItemsInLayoutAttributes(firstAttributes, lastAttributes, firstTextBox->start(), lastTextBox->start()); + swapItemsInLayoutAttributes(firstAttributes, lastAttributes, firstTextBox.start(), lastTextBox.start()); } InlineBox* temp = *first; @@ -311,5 +313,3 @@ void SVGRootInlineBox::reorderValueLists(Vector<SVGTextLayoutAttributes*>& attri } } // namespace WebCore - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/SVGRootInlineBox.h b/Source/WebCore/rendering/svg/SVGRootInlineBox.h index 643af3108..bd4455203 100644 --- a/Source/WebCore/rendering/svg/SVGRootInlineBox.h +++ b/Source/WebCore/rendering/svg/SVGRootInlineBox.h @@ -1,6 +1,6 @@ /* * Copyright (C) 2006 Oliver Hunt <ojh16@student.canterbury.ac.nz> - * Copyright (C) 2006 Apple Computer Inc. + * Copyright (C) 2006 Apple Inc. * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> * Copyright (C) Research In Motion Limited 2010. All rights reserved. * @@ -20,10 +20,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef SVGRootInlineBox_h -#define SVGRootInlineBox_h +#pragma once -#if ENABLE(SVG) #include "RootInlineBox.h" #include "SVGRenderSupport.h" #include "SVGTextLayoutEngine.h" @@ -39,29 +37,27 @@ public: RenderSVGText& renderSVGText(); - virtual float virtualLogicalHeight() const override final { return m_logicalHeight; } + float virtualLogicalHeight() const override { return m_logicalHeight; } void setLogicalHeight(float height) { m_logicalHeight = height; } - virtual void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) override final; + void paint(PaintInfo&, const LayoutPoint&, LayoutUnit lineTop, LayoutUnit lineBottom) override; void computePerCharacterLayoutInformation(); InlineBox* closestLeafChildForPosition(const LayoutPoint&); + bool nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, LayoutUnit lineTop, LayoutUnit lineBottom, HitTestAction) final; + private: - virtual bool isSVGRootInlineBox() const override final { return true; } + bool isSVGRootInlineBox() const override { return true; } void reorderValueLists(Vector<SVGTextLayoutAttributes*>&); void layoutCharactersInTextBoxes(InlineFlowBox*, SVGTextLayoutEngine&); - void layoutChildBoxes(InlineFlowBox*, FloatRect* = 0); + void layoutChildBoxes(InlineFlowBox*, FloatRect* = nullptr); void layoutRootBox(const FloatRect&); float m_logicalHeight; }; -INLINE_BOX_OBJECT_TYPE_CASTS(SVGRootInlineBox, isSVGRootInlineBox()) - } // namespace WebCore -#endif // ENABLE(SVG) - -#endif // SVGRootInlineBox_h +SPECIALIZE_TYPE_TRAITS_INLINE_BOX(SVGRootInlineBox, isSVGRootInlineBox()) diff --git a/Source/WebCore/rendering/svg/SVGSubpathData.h b/Source/WebCore/rendering/svg/SVGSubpathData.h index cf7901d8d..073afd4ce 100644 --- a/Source/WebCore/rendering/svg/SVGSubpathData.h +++ b/Source/WebCore/rendering/svg/SVGSubpathData.h @@ -17,10 +17,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef SVGSubpathData_h -#define SVGSubpathData_h +#pragma once -#if ENABLE(SVG) #include "Path.h" #include <wtf/Vector.h> @@ -30,51 +28,46 @@ class SVGSubpathData { public: SVGSubpathData(Vector<FloatPoint>& zeroLengthSubpathLocations) : m_zeroLengthSubpathLocations(zeroLengthSubpathLocations) - , m_haveSeenMoveOnly(true) - , m_pathIsZeroLength(true) { - m_lastPoint.set(0, 0); - m_movePoint.set(0, 0); } - static void updateFromPathElement(void* info, const PathElement* element) + static void updateFromPathElement(SVGSubpathData& subpathFinder, const PathElement& element) { - SVGSubpathData* subpathFinder = static_cast<SVGSubpathData*>(info); - switch (element->type) { + switch (element.type) { case PathElementMoveToPoint: - if (subpathFinder->m_pathIsZeroLength && !subpathFinder->m_haveSeenMoveOnly) - subpathFinder->m_zeroLengthSubpathLocations.append(subpathFinder->m_lastPoint); - subpathFinder->m_lastPoint = subpathFinder->m_movePoint = element->points[0]; - subpathFinder->m_haveSeenMoveOnly = true; - subpathFinder->m_pathIsZeroLength = true; + if (subpathFinder.m_pathIsZeroLength && !subpathFinder.m_haveSeenMoveOnly) + subpathFinder.m_zeroLengthSubpathLocations.append(subpathFinder.m_lastPoint); + subpathFinder.m_lastPoint = subpathFinder.m_movePoint = element.points[0]; + subpathFinder.m_haveSeenMoveOnly = true; + subpathFinder.m_pathIsZeroLength = true; break; case PathElementAddLineToPoint: - if (subpathFinder->m_lastPoint != element->points[0]) { - subpathFinder->m_pathIsZeroLength = false; - subpathFinder->m_lastPoint = element->points[0]; + if (subpathFinder.m_lastPoint != element.points[0]) { + subpathFinder.m_pathIsZeroLength = false; + subpathFinder.m_lastPoint = element.points[0]; } - subpathFinder->m_haveSeenMoveOnly = false; + subpathFinder.m_haveSeenMoveOnly = false; break; case PathElementAddQuadCurveToPoint: - if (subpathFinder->m_lastPoint != element->points[0] || element->points[0] != element->points[1]) { - subpathFinder->m_pathIsZeroLength = false; - subpathFinder->m_lastPoint = element->points[1]; + if (subpathFinder.m_lastPoint != element.points[0] || element.points[0] != element.points[1]) { + subpathFinder.m_pathIsZeroLength = false; + subpathFinder.m_lastPoint = element.points[1]; } - subpathFinder->m_haveSeenMoveOnly = false; + subpathFinder.m_haveSeenMoveOnly = false; break; case PathElementAddCurveToPoint: - if (subpathFinder->m_lastPoint != element->points[0] || element->points[0] != element->points[1] || element->points[1] != element->points[2]) { - subpathFinder->m_pathIsZeroLength = false; - subpathFinder->m_lastPoint = element->points[2]; + if (subpathFinder.m_lastPoint != element.points[0] || element.points[0] != element.points[1] || element.points[1] != element.points[2]) { + subpathFinder.m_pathIsZeroLength = false; + subpathFinder.m_lastPoint = element.points[2]; } - subpathFinder->m_haveSeenMoveOnly = false; + subpathFinder.m_haveSeenMoveOnly = false; break; case PathElementCloseSubpath: - if (subpathFinder->m_pathIsZeroLength) - subpathFinder->m_zeroLengthSubpathLocations.append(subpathFinder->m_lastPoint); - subpathFinder->m_haveSeenMoveOnly = true; // This is an implicit move for the next element - subpathFinder->m_pathIsZeroLength = true; // A new sub-path also starts here - subpathFinder->m_lastPoint = subpathFinder->m_movePoint; + if (subpathFinder.m_pathIsZeroLength) + subpathFinder.m_zeroLengthSubpathLocations.append(subpathFinder.m_lastPoint); + subpathFinder.m_haveSeenMoveOnly = true; // This is an implicit move for the next element + subpathFinder.m_pathIsZeroLength = true; // A new sub-path also starts here + subpathFinder.m_lastPoint = subpathFinder.m_movePoint; break; } } @@ -89,12 +82,8 @@ private: Vector<FloatPoint>& m_zeroLengthSubpathLocations; FloatPoint m_lastPoint; FloatPoint m_movePoint; - bool m_haveSeenMoveOnly; - bool m_pathIsZeroLength; + bool m_haveSeenMoveOnly { false }; + bool m_pathIsZeroLength { false }; }; -} - -#endif // ENABLE(SVG) -#endif // SVGSubpathData_h - +} // namespace WebCore diff --git a/Source/WebCore/rendering/svg/SVGTextChunk.cpp b/Source/WebCore/rendering/svg/SVGTextChunk.cpp index b7072753b..17811864e 100644 --- a/Source/WebCore/rendering/svg/SVGTextChunk.cpp +++ b/Source/WebCore/rendering/svg/SVGTextChunk.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * Copyright (C) 2015 Apple Inc. 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 @@ -18,60 +19,102 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "SVGTextChunk.h" #include "SVGInlineTextBox.h" namespace WebCore { -SVGTextChunk::SVGTextChunk(unsigned chunkStyle, float desiredTextLength) - : m_chunkStyle(chunkStyle) - , m_desiredTextLength(desiredTextLength) -{ -} - -void SVGTextChunk::calculateLength(float& length, unsigned& characters) const +SVGTextChunk::SVGTextChunk(const Vector<SVGInlineTextBox*>& lineLayoutBoxes, unsigned first, unsigned limit) { - SVGTextFragment* lastFragment = 0; + ASSERT(first < limit); + ASSERT(limit <= lineLayoutBoxes.size()); + + const SVGInlineTextBox* box = lineLayoutBoxes[first]; + const RenderStyle& style = box->renderer().style(); + const SVGRenderStyle& svgStyle = style.svgStyle(); + + if (!style.isLeftToRightDirection()) + m_chunkStyle |= SVGTextChunk::RightToLeftText; + + if (style.isVerticalWritingMode()) + m_chunkStyle |= SVGTextChunk::VerticalText; + + switch (svgStyle.textAnchor()) { + case TA_START: + break; + case TA_MIDDLE: + m_chunkStyle |= MiddleAnchor; + break; + case TA_END: + m_chunkStyle |= EndAnchor; + break; + } - unsigned boxCount = m_boxes.size(); - for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition) { - SVGInlineTextBox* textBox = m_boxes.at(boxPosition); - Vector<SVGTextFragment>& fragments = textBox->textFragments(); + if (auto* textContentElement = SVGTextContentElement::elementFromRenderer(box->renderer().parent())) { + SVGLengthContext lengthContext(textContentElement); + m_desiredTextLength = textContentElement->specifiedTextLength().value(lengthContext); + + switch (textContentElement->lengthAdjust()) { + case SVGLengthAdjustUnknown: + break; + case SVGLengthAdjustSpacing: + m_chunkStyle |= LengthAdjustSpacing; + break; + case SVGLengthAdjustSpacingAndGlyphs: + m_chunkStyle |= LengthAdjustSpacingAndGlyphs; + break; + } + } - unsigned size = fragments.size(); - if (!size) - continue; + for (unsigned i = first; i < limit; ++i) + m_boxes.append(lineLayoutBoxes[i]); +} - for (unsigned i = 0; i < size; ++i) { - SVGTextFragment& fragment = fragments.at(i); +unsigned SVGTextChunk::totalCharacters() const +{ + unsigned characters = 0; + for (auto* box : m_boxes) { + for (auto& fragment : box->textFragments()) characters += fragment.length; + } + return characters; +} - if (m_chunkStyle & VerticalText) - length += fragment.height; - else - length += fragment.width; - - if (!lastFragment) { - lastFragment = &fragment; - continue; - } - - // Resepect gap between chunks. - if (m_chunkStyle & VerticalText) - length += fragment.y - (lastFragment->y + lastFragment->height); - else - length += fragment.x - (lastFragment->x + lastFragment->width); +float SVGTextChunk::totalLength() const +{ + const SVGTextFragment* firstFragment = nullptr; + const SVGTextFragment* lastFragment = nullptr; + + for (auto* box : m_boxes) { + auto& fragments = box->textFragments(); + if (fragments.size()) { + firstFragment = &(*fragments.begin()); + break; + } + } - lastFragment = &fragment; + for (auto it = m_boxes.rbegin(), end = m_boxes.rend(); it != end; ++it) { + auto& fragments = (*it)->textFragments(); + if (fragments.size()) { + lastFragment = &(*fragments.rbegin()); + break; } } + + ASSERT(!firstFragment == !lastFragment); + if (!firstFragment) + return 0; + + if (m_chunkStyle & VerticalText) + return (lastFragment->y + lastFragment->height) - firstFragment->y; + + return (lastFragment->x + lastFragment->width) - firstFragment->x; } -float SVGTextChunk::calculateTextAnchorShift(float length) const +float SVGTextChunk::totalAnchorShift() const { + float length = totalLength(); if (m_chunkStyle & MiddleAnchor) return -length / 2; if (m_chunkStyle & EndAnchor) @@ -79,6 +122,88 @@ float SVGTextChunk::calculateTextAnchorShift(float length) const return m_chunkStyle & RightToLeftText ? -length : 0; } -} // namespace WebCore +void SVGTextChunk::layout(HashMap<SVGInlineTextBox*, AffineTransform>& textBoxTransformations) const +{ + if (hasDesiredTextLength()) { + if (hasLengthAdjustSpacing()) + processTextLengthSpacingCorrection(); + else { + ASSERT(hasLengthAdjustSpacingAndGlyphs()); + buildBoxTransformations(textBoxTransformations); + } + } -#endif // ENABLE(SVG) + if (hasTextAnchor()) + processTextAnchorCorrection(); +} + +void SVGTextChunk::processTextLengthSpacingCorrection() const +{ + float textLengthShift = (desiredTextLength() - totalLength()) / totalCharacters(); + bool isVerticalText = m_chunkStyle & VerticalText; + unsigned atCharacter = 0; + + for (auto* box : m_boxes) { + for (auto& fragment : box->textFragments()) { + if (isVerticalText) + fragment.y += textLengthShift * atCharacter; + else + fragment.x += textLengthShift * atCharacter; + + atCharacter += fragment.length; + } + } +} + +void SVGTextChunk::buildBoxTransformations(HashMap<SVGInlineTextBox*, AffineTransform>& textBoxTransformations) const +{ + AffineTransform spacingAndGlyphsTransform; + bool foundFirstFragment = false; + + for (auto* box : m_boxes) { + if (!foundFirstFragment) { + if (!boxSpacingAndGlyphsTransform(box, spacingAndGlyphsTransform)) + continue; + foundFirstFragment = true; + } + + textBoxTransformations.set(box, spacingAndGlyphsTransform); + } +} + +bool SVGTextChunk::boxSpacingAndGlyphsTransform(const SVGInlineTextBox* box, AffineTransform& spacingAndGlyphsTransform) const +{ + auto& fragments = box->textFragments(); + if (fragments.isEmpty()) + return false; + + const SVGTextFragment& fragment = fragments.first(); + float scale = desiredTextLength() / totalLength(); + + spacingAndGlyphsTransform.translate(fragment.x, fragment.y); + + if (m_chunkStyle & VerticalText) + spacingAndGlyphsTransform.scaleNonUniform(1, scale); + else + spacingAndGlyphsTransform.scaleNonUniform(scale, 1); + + spacingAndGlyphsTransform.translate(-fragment.x, -fragment.y); + return true; +} + +void SVGTextChunk::processTextAnchorCorrection() const +{ + float textAnchorShift = totalAnchorShift(); + bool isVerticalText = m_chunkStyle & VerticalText; + + for (auto* box : m_boxes) { + for (auto& fragment : box->textFragments()) { + if (isVerticalText) + fragment.y += textAnchorShift; + else + fragment.x += textAnchorShift; + } + } +} + +} // namespace WebCore diff --git a/Source/WebCore/rendering/svg/SVGTextChunk.h b/Source/WebCore/rendering/svg/SVGTextChunk.h index 9618d9fb6..f000f26da 100644 --- a/Source/WebCore/rendering/svg/SVGTextChunk.h +++ b/Source/WebCore/rendering/svg/SVGTextChunk.h @@ -1,5 +1,6 @@ /* * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * Copyright (C) 2015 Apple Inc. 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 @@ -17,10 +18,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef SVGTextChunk_h -#define SVGTextChunk_h +#pragma once -#if ENABLE(SVG) #include "SVGRenderStyleDefs.h" #include "SVGTextContentElement.h" @@ -41,31 +40,34 @@ public: LengthAdjustSpacingAndGlyphs = 1 << 6 }; - SVGTextChunk(unsigned chunkStyle, float desiredTextLength); + SVGTextChunk(const Vector<SVGInlineTextBox*>&, unsigned first, unsigned limit); - void calculateLength(float& length, unsigned& characters) const; - float calculateTextAnchorShift(float length) const; + unsigned totalCharacters() const; + float totalLength() const; + float totalAnchorShift() const; + void layout(HashMap<SVGInlineTextBox*, AffineTransform>&) const; + +private: + void processTextAnchorCorrection() const; + void buildBoxTransformations(HashMap<SVGInlineTextBox*, AffineTransform>&) const; + void processTextLengthSpacingCorrection() const; bool isVerticalText() const { return m_chunkStyle & VerticalText; } float desiredTextLength() const { return m_desiredTextLength; } - Vector<SVGInlineTextBox*>& boxes() { return m_boxes; } - const Vector<SVGInlineTextBox*>& boxes() const { return m_boxes; } - bool hasDesiredTextLength() const { return m_desiredTextLength > 0 && ((m_chunkStyle & LengthAdjustSpacing) || (m_chunkStyle & LengthAdjustSpacingAndGlyphs)); } - bool hasTextAnchor() const { return m_chunkStyle & RightToLeftText ? !(m_chunkStyle & EndAnchor) : (m_chunkStyle & MiddleAnchor) || (m_chunkStyle & EndAnchor); } + bool hasTextAnchor() const { return m_chunkStyle & RightToLeftText ? !(m_chunkStyle & EndAnchor) : (m_chunkStyle & (MiddleAnchor | EndAnchor)); } bool hasLengthAdjustSpacing() const { return m_chunkStyle & LengthAdjustSpacing; } bool hasLengthAdjustSpacingAndGlyphs() const { return m_chunkStyle & LengthAdjustSpacingAndGlyphs; } + bool boxSpacingAndGlyphsTransform(const SVGInlineTextBox*, AffineTransform&) const; + private: // Contains all SVGInlineTextBoxes this chunk spans. Vector<SVGInlineTextBox*> m_boxes; - unsigned m_chunkStyle; - float m_desiredTextLength; + unsigned m_chunkStyle { DefaultStyle }; + float m_desiredTextLength { 0 }; }; } // namespace WebCore - -#endif // ENABLE(SVG) -#endif diff --git a/Source/WebCore/rendering/svg/SVGTextChunkBuilder.cpp b/Source/WebCore/rendering/svg/SVGTextChunkBuilder.cpp index 26ab67e25..68b2d4875 100644 --- a/Source/WebCore/rendering/svg/SVGTextChunkBuilder.cpp +++ b/Source/WebCore/rendering/svg/SVGTextChunkBuilder.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * Copyright (C) 2015 Apple Inc. 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 @@ -18,8 +19,6 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "SVGTextChunkBuilder.h" #include "SVGElement.h" @@ -32,229 +31,71 @@ SVGTextChunkBuilder::SVGTextChunkBuilder() { } -void SVGTextChunkBuilder::transformationForTextBox(SVGInlineTextBox* textBox, AffineTransform& transform) const +unsigned SVGTextChunkBuilder::totalCharacters() const { - DEFINE_STATIC_LOCAL(const AffineTransform, s_identityTransform, ()); - if (!m_textBoxTransformations.contains(textBox)) { - transform = s_identityTransform; - return; - } - - transform = m_textBoxTransformations.get(textBox); + unsigned characters = 0; + for (const auto& chunk : m_textChunks) + characters += chunk.totalCharacters(); + return characters; } -void SVGTextChunkBuilder::buildTextChunks(Vector<SVGInlineTextBox*>& lineLayoutBoxes) +float SVGTextChunkBuilder::totalLength() const { - if (lineLayoutBoxes.isEmpty()) - return; - - bool foundStart = false; - unsigned lastChunkStartPosition = 0; - unsigned boxPosition = 0; - unsigned boxCount = lineLayoutBoxes.size(); - for (; boxPosition < boxCount; ++boxPosition) { - SVGInlineTextBox* textBox = lineLayoutBoxes[boxPosition]; - if (!textBox->startsNewTextChunk()) - continue; - - if (!foundStart) { - lastChunkStartPosition = boxPosition; - foundStart = true; - } else { - ASSERT_WITH_SECURITY_IMPLICATION(boxPosition > lastChunkStartPosition); - addTextChunk(lineLayoutBoxes, lastChunkStartPosition, boxPosition - lastChunkStartPosition); - lastChunkStartPosition = boxPosition; - } - } - - if (!foundStart) - return; - - if (boxPosition - lastChunkStartPosition > 0) - addTextChunk(lineLayoutBoxes, lastChunkStartPosition, boxPosition - lastChunkStartPosition); + float length = 0; + for (const auto& chunk : m_textChunks) + length += chunk.totalLength(); + return length; } -void SVGTextChunkBuilder::layoutTextChunks(Vector<SVGInlineTextBox*>& lineLayoutBoxes) +float SVGTextChunkBuilder::totalAnchorShift() const { - buildTextChunks(lineLayoutBoxes); - if (m_textChunks.isEmpty()) - return; - - unsigned chunkCount = m_textChunks.size(); - for (unsigned i = 0; i < chunkCount; ++i) - processTextChunk(m_textChunks[i]); - - m_textChunks.clear(); + float anchorShift = 0; + for (const auto& chunk : m_textChunks) + anchorShift += chunk.totalAnchorShift(); + return anchorShift; } -void SVGTextChunkBuilder::addTextChunk(Vector<SVGInlineTextBox*>& lineLayoutBoxes, unsigned boxStart, unsigned boxCount) +AffineTransform SVGTextChunkBuilder::transformationForTextBox(SVGInlineTextBox* textBox) const { - SVGInlineTextBox* textBox = lineLayoutBoxes[boxStart]; - ASSERT(textBox); - - const RenderStyle& style = textBox->renderer().style(); - - const SVGRenderStyle& svgStyle = style.svgStyle(); - - // Build chunk style flags. - unsigned chunkStyle = SVGTextChunk::DefaultStyle; - - // Handle 'direction' property. - if (!style.isLeftToRightDirection()) - chunkStyle |= SVGTextChunk::RightToLeftText; - - // Handle 'writing-mode' property. - if (svgStyle.isVerticalWritingMode()) - chunkStyle |= SVGTextChunk::VerticalText; - - // Handle 'text-anchor' property. - switch (svgStyle.textAnchor()) { - case TA_START: - break; - case TA_MIDDLE: - chunkStyle |= SVGTextChunk::MiddleAnchor; - break; - case TA_END: - chunkStyle |= SVGTextChunk::EndAnchor; - break; - }; - - // Handle 'lengthAdjust' property. - float desiredTextLength = 0; - if (SVGTextContentElement* textContentElement = SVGTextContentElement::elementFromRenderer(textBox->renderer().parent())) { - SVGLengthContext lengthContext(textContentElement); - desiredTextLength = textContentElement->specifiedTextLength().value(lengthContext); - - switch (textContentElement->lengthAdjust()) { - case SVGLengthAdjustUnknown: - break; - case SVGLengthAdjustSpacing: - chunkStyle |= SVGTextChunk::LengthAdjustSpacing; - break; - case SVGLengthAdjustSpacingAndGlyphs: - chunkStyle |= SVGTextChunk::LengthAdjustSpacingAndGlyphs; - break; - }; - } - - SVGTextChunk chunk(chunkStyle, desiredTextLength); - - Vector<SVGInlineTextBox*>& boxes = chunk.boxes(); - for (unsigned i = boxStart; i < boxStart + boxCount; ++i) - boxes.append(lineLayoutBoxes[i]); - - m_textChunks.append(chunk); + auto it = m_textBoxTransformations.find(textBox); + return it == m_textBoxTransformations.end() ? AffineTransform() : it->value; } -void SVGTextChunkBuilder::processTextChunk(const SVGTextChunk& chunk) +void SVGTextChunkBuilder::buildTextChunks(const Vector<SVGInlineTextBox*>& lineLayoutBoxes) { - bool processTextLength = chunk.hasDesiredTextLength(); - bool processTextAnchor = chunk.hasTextAnchor(); - if (!processTextAnchor && !processTextLength) - return; - - const Vector<SVGInlineTextBox*>& boxes = chunk.boxes(); - unsigned boxCount = boxes.size(); - if (!boxCount) - return; - - // Calculate absolute length of whole text chunk (starting from text box 'start', spanning 'length' text boxes). - float chunkLength = 0; - unsigned chunkCharacters = 0; - chunk.calculateLength(chunkLength, chunkCharacters); - - bool isVerticalText = chunk.isVerticalText(); - if (processTextLength) { - if (chunk.hasLengthAdjustSpacing()) { - float textLengthShift = (chunk.desiredTextLength() - chunkLength) / chunkCharacters; - unsigned atCharacter = 0; - for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition) { - Vector<SVGTextFragment>& fragments = boxes[boxPosition]->textFragments(); - if (fragments.isEmpty()) - continue; - processTextLengthSpacingCorrection(isVerticalText, textLengthShift, fragments, atCharacter); - } - } else { - ASSERT(chunk.hasLengthAdjustSpacingAndGlyphs()); - float textLengthScale = chunk.desiredTextLength() / chunkLength; - AffineTransform spacingAndGlyphsTransform; - - bool foundFirstFragment = false; - for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition) { - SVGInlineTextBox* textBox = boxes[boxPosition]; - Vector<SVGTextFragment>& fragments = textBox->textFragments(); - if (fragments.isEmpty()) - continue; - - if (!foundFirstFragment) { - foundFirstFragment = true; - buildSpacingAndGlyphsTransform(isVerticalText, textLengthScale, fragments.first(), spacingAndGlyphsTransform); - } - - m_textBoxTransformations.set(textBox, spacingAndGlyphsTransform); - } - } - } - - if (!processTextAnchor) + if (lineLayoutBoxes.isEmpty()) return; - // If we previously applied a lengthAdjust="spacing" correction, we have to recalculate the chunk length, to be able to apply the text-anchor shift. - if (processTextLength && chunk.hasLengthAdjustSpacing()) { - chunkLength = 0; - chunkCharacters = 0; - chunk.calculateLength(chunkLength, chunkCharacters); - } + unsigned limit = lineLayoutBoxes.size(); + unsigned first = limit; - float textAnchorShift = chunk.calculateTextAnchorShift(chunkLength); - for (unsigned boxPosition = 0; boxPosition < boxCount; ++boxPosition) { - Vector<SVGTextFragment>& fragments = boxes[boxPosition]->textFragments(); - if (fragments.isEmpty()) + for (unsigned i = 0; i < limit; ++i) { + if (!lineLayoutBoxes[i]->startsNewTextChunk()) continue; - processTextAnchorCorrection(isVerticalText, textAnchorShift, fragments); - } -} - -void SVGTextChunkBuilder::processTextLengthSpacingCorrection(bool isVerticalText, float textLengthShift, Vector<SVGTextFragment>& fragments, unsigned& atCharacter) -{ - unsigned fragmentCount = fragments.size(); - for (unsigned i = 0; i < fragmentCount; ++i) { - SVGTextFragment& fragment = fragments[i]; - if (isVerticalText) - fragment.y += textLengthShift * atCharacter; - else - fragment.x += textLengthShift * atCharacter; - - atCharacter += fragment.length; + if (first == limit) + first = i; + else { + ASSERT_WITH_SECURITY_IMPLICATION(first != i); + m_textChunks.append(SVGTextChunk(lineLayoutBoxes, first, i)); + first = i; + } } -} -void SVGTextChunkBuilder::processTextAnchorCorrection(bool isVerticalText, float textAnchorShift, Vector<SVGTextFragment>& fragments) -{ - unsigned fragmentCount = fragments.size(); - for (unsigned i = 0; i < fragmentCount; ++i) { - SVGTextFragment& fragment = fragments[i]; - - if (isVerticalText) - fragment.y += textAnchorShift; - else - fragment.x += textAnchorShift; - } + if (first != limit) + m_textChunks.append(SVGTextChunk(lineLayoutBoxes, first, limit)); } -void SVGTextChunkBuilder::buildSpacingAndGlyphsTransform(bool isVerticalText, float scale, const SVGTextFragment& fragment, AffineTransform& spacingAndGlyphsTransform) +void SVGTextChunkBuilder::layoutTextChunks(const Vector<SVGInlineTextBox*>& lineLayoutBoxes) { - spacingAndGlyphsTransform.translate(fragment.x, fragment.y); + buildTextChunks(lineLayoutBoxes); + if (m_textChunks.isEmpty()) + return; - if (isVerticalText) - spacingAndGlyphsTransform.scaleNonUniform(1, scale); - else - spacingAndGlyphsTransform.scaleNonUniform(scale, 1); + for (const auto& chunk : m_textChunks) + chunk.layout(m_textBoxTransformations); - spacingAndGlyphsTransform.translate(-fragment.x, -fragment.y); + m_textChunks.clear(); } } - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/SVGTextChunkBuilder.h b/Source/WebCore/rendering/svg/SVGTextChunkBuilder.h index 321f3915f..7a7880a87 100644 --- a/Source/WebCore/rendering/svg/SVGTextChunkBuilder.h +++ b/Source/WebCore/rendering/svg/SVGTextChunkBuilder.h @@ -1,5 +1,6 @@ /* * Copyright (C) Research In Motion Limited 2010. All rights reserved. + * Copyright (C) 2015 Apple Inc. 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 @@ -17,10 +18,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef SVGTextChunkBuilder_h -#define SVGTextChunkBuilder_h +#pragma once -#if ENABLE(SVG) #include "SVGTextChunk.h" #include <wtf/Vector.h> @@ -41,18 +40,13 @@ public: SVGTextChunkBuilder(); const Vector<SVGTextChunk>& textChunks() const { return m_textChunks; } - void transformationForTextBox(SVGInlineTextBox*, AffineTransform&) const; + unsigned totalCharacters() const; + float totalLength() const; + float totalAnchorShift() const; + AffineTransform transformationForTextBox(SVGInlineTextBox*) const; - void buildTextChunks(Vector<SVGInlineTextBox*>& lineLayoutBoxes); - void layoutTextChunks(Vector<SVGInlineTextBox*>& lineLayoutBoxes); - -private: - void addTextChunk(Vector<SVGInlineTextBox*>& lineLayoutBoxes, unsigned boxPosition, unsigned boxCount); - void processTextChunk(const SVGTextChunk&); - - void processTextLengthSpacingCorrection(bool isVerticalText, float textLengthShift, Vector<SVGTextFragment>&, unsigned& atCharacter); - void processTextAnchorCorrection(bool isVerticalText, float textAnchorShift, Vector<SVGTextFragment>&); - void buildSpacingAndGlyphsTransform(bool isVerticalText, float scale, const SVGTextFragment&, AffineTransform&); + void buildTextChunks(const Vector<SVGInlineTextBox*>& lineLayoutBoxes); + void layoutTextChunks(const Vector<SVGInlineTextBox*>& lineLayoutBoxes); private: Vector<SVGTextChunk> m_textChunks; @@ -60,6 +54,3 @@ private: }; } // namespace WebCore - -#endif // ENABLE(SVG) -#endif diff --git a/Source/WebCore/rendering/svg/SVGTextFragment.h b/Source/WebCore/rendering/svg/SVGTextFragment.h index a44d0fabc..ad3e9b4c4 100644 --- a/Source/WebCore/rendering/svg/SVGTextFragment.h +++ b/Source/WebCore/rendering/svg/SVGTextFragment.h @@ -17,10 +17,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef SVGTextFragment_h -#define SVGTextFragment_h +#pragma once -#if ENABLE(SVG) #include "AffineTransform.h" namespace WebCore { @@ -110,6 +108,3 @@ private: }; } // namespace WebCore - -#endif // ENABLE(SVG) -#endif diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.cpp b/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.cpp index 05d6cc332..6441272a4 100644 --- a/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.cpp +++ b/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.cpp @@ -18,8 +18,6 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "SVGTextLayoutAttributes.h" #include <stdio.h> @@ -74,5 +72,3 @@ void SVGTextLayoutAttributes::dump() const } } - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.h b/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.h index 00d138e53..f72075ea6 100644 --- a/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.h +++ b/Source/WebCore/rendering/svg/SVGTextLayoutAttributes.h @@ -17,10 +17,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef SVGTextLayoutAttributes_h -#define SVGTextLayoutAttributes_h +#pragma once -#if ENABLE(SVG) #include "SVGTextMetrics.h" #include <wtf/HashMap.h> #include <wtf/Noncopyable.h> @@ -75,6 +73,3 @@ inline SVGCharacterData::SVGCharacterData() } } // namespace WebCore - -#endif // ENABLE(SVG) -#endif diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp b/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp index 1dbb01fd9..2c068b9c3 100644 --- a/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp +++ b/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.cpp @@ -18,10 +18,10 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "SVGTextLayoutAttributesBuilder.h" +#include "RenderChildIterator.h" +#include "RenderSVGInline.h" #include "RenderSVGInlineText.h" #include "RenderSVGText.h" #include "SVGTextPositioningElement.h" @@ -35,7 +35,7 @@ SVGTextLayoutAttributesBuilder::SVGTextLayoutAttributesBuilder() void SVGTextLayoutAttributesBuilder::buildLayoutAttributesForTextRenderer(RenderSVGInlineText& text) { - RenderSVGText* textRoot = RenderSVGText::locateRenderSVGTextAncestor(&text); + auto* textRoot = RenderSVGText::locateRenderSVGTextAncestor(text); if (!textRoot) return; @@ -43,82 +43,79 @@ void SVGTextLayoutAttributesBuilder::buildLayoutAttributesForTextRenderer(Render m_characterDataMap.clear(); m_textLength = 0; - const UChar* lastCharacter = 0; - collectTextPositioningElements(textRoot, lastCharacter); + bool lastCharacterWasSpace = true; + collectTextPositioningElements(*textRoot, lastCharacterWasSpace); if (!m_textLength) return; - buildCharacterDataMap(textRoot); + buildCharacterDataMap(*textRoot); } - m_metricsBuilder.buildMetricsAndLayoutAttributes(textRoot, &text, m_characterDataMap); + m_metricsBuilder.buildMetricsAndLayoutAttributes(*textRoot, &text, m_characterDataMap); } -bool SVGTextLayoutAttributesBuilder::buildLayoutAttributesForForSubtree(RenderSVGText* textRoot) +bool SVGTextLayoutAttributesBuilder::buildLayoutAttributesForForSubtree(RenderSVGText& textRoot) { - ASSERT(textRoot); - m_characterDataMap.clear(); if (m_textPositions.isEmpty()) { m_textLength = 0; - const UChar* lastCharacter = 0; - collectTextPositioningElements(textRoot, lastCharacter); + bool lastCharacterWasSpace = true; + collectTextPositioningElements(textRoot, lastCharacterWasSpace); } if (!m_textLength) return false; buildCharacterDataMap(textRoot); - m_metricsBuilder.buildMetricsAndLayoutAttributes(textRoot, 0, m_characterDataMap); + m_metricsBuilder.buildMetricsAndLayoutAttributes(textRoot, nullptr, m_characterDataMap); return true; } -void SVGTextLayoutAttributesBuilder::rebuildMetricsForTextRenderer(RenderSVGInlineText* text) +void SVGTextLayoutAttributesBuilder::rebuildMetricsForTextRenderer(RenderSVGInlineText& text) { - ASSERT(text); m_metricsBuilder.measureTextRenderer(text); } -static inline void processRenderSVGInlineText(RenderSVGInlineText* text, unsigned& atCharacter, const UChar*& lastCharacter) +static inline void processRenderSVGInlineText(const RenderSVGInlineText& text, unsigned& atCharacter, bool& lastCharacterWasSpace) { - if (text->style().whiteSpace() == PRE) { - atCharacter += text->textLength(); + if (text.style().whiteSpace() == PRE) { + atCharacter += text.textLength(); return; } - const UChar* characters = text->deprecatedCharacters(); - unsigned textLength = text->textLength(); - for (unsigned textPosition = 0; textPosition < textLength; ++textPosition) { - const UChar* currentCharacter = characters + textPosition; - if (*currentCharacter == ' ' && (!lastCharacter || *lastCharacter == ' ')) + for (unsigned textPosition = 0, textLength = text.textLength(); textPosition < textLength; ++textPosition) { + const UChar currentCharacter = text[textPosition]; + if (currentCharacter == ' ' && lastCharacterWasSpace) continue; - lastCharacter = currentCharacter; + lastCharacterWasSpace = currentCharacter == ' '; ++atCharacter; } } -void SVGTextLayoutAttributesBuilder::collectTextPositioningElements(RenderObject* start, const UChar*& lastCharacter) +void SVGTextLayoutAttributesBuilder::collectTextPositioningElements(RenderBoxModelObject& start, bool& lastCharacterWasSpace) { - ASSERT(!start->isSVGText() || m_textPositions.isEmpty()); + ASSERT(!is<RenderSVGText>(start) || m_textPositions.isEmpty()); - for (RenderObject* child = start->firstChildSlow(); child; child = child->nextSibling()) { - if (child->isSVGInlineText()) { - processRenderSVGInlineText(toRenderSVGInlineText(child), m_textLength, lastCharacter); + for (auto& child : childrenOfType<RenderObject>(start)) { + if (is<RenderSVGInlineText>(child)) { + processRenderSVGInlineText(downcast<RenderSVGInlineText>(child), m_textLength, lastCharacterWasSpace); continue; } - if (!child->isSVGInline()) + if (!is<RenderSVGInline>(child)) continue; - SVGTextPositioningElement* element = SVGTextPositioningElement::elementFromRenderer(child); + auto& inlineChild = downcast<RenderSVGInline>(child); + SVGTextPositioningElement* element = SVGTextPositioningElement::elementFromRenderer(inlineChild); + unsigned atPosition = m_textPositions.size(); if (element) m_textPositions.append(TextPosition(element, m_textLength)); - collectTextPositioningElements(child, lastCharacter); + collectTextPositioningElements(inlineChild, lastCharacterWasSpace); if (!element) continue; @@ -130,7 +127,7 @@ void SVGTextLayoutAttributesBuilder::collectTextPositioningElements(RenderObject } } -void SVGTextLayoutAttributesBuilder::buildCharacterDataMap(RenderSVGText* textRoot) +void SVGTextLayoutAttributesBuilder::buildCharacterDataMap(RenderSVGText& textRoot) { SVGTextPositioningElement* outermostTextElement = SVGTextPositioningElement::elementFromRenderer(textRoot); ASSERT(outermostTextElement); @@ -160,7 +157,7 @@ void SVGTextLayoutAttributesBuilder::buildCharacterDataMap(RenderSVGText* textRo fillCharacterDataMap(m_textPositions[i]); } -static inline void updateCharacterData(unsigned i, float& lastRotation, SVGCharacterData& data, const SVGLengthContext& lengthContext, const SVGLengthList* xList, const SVGLengthList* yList, const SVGLengthList* dxList, const SVGLengthList* dyList, const SVGNumberList* rotateList) +static inline void updateCharacterData(unsigned i, float& lastRotation, SVGCharacterData& data, const SVGLengthContext& lengthContext, const SVGLengthListValues* xList, const SVGLengthListValues* yList, const SVGLengthListValues* dxList, const SVGLengthListValues* dyList, const SVGNumberListValues* rotateList) { if (xList) data.x = xList->at(i).value(lengthContext); @@ -178,11 +175,11 @@ static inline void updateCharacterData(unsigned i, float& lastRotation, SVGChara void SVGTextLayoutAttributesBuilder::fillCharacterDataMap(const TextPosition& position) { - const SVGLengthList& xList = position.element->x(); - const SVGLengthList& yList = position.element->y(); - const SVGLengthList& dxList = position.element->dx(); - const SVGLengthList& dyList = position.element->dy(); - const SVGNumberList& rotateList = position.element->rotate(); + const auto& xList = position.element->x(); + const auto& yList = position.element->y(); + const auto& dxList = position.element->dx(); + const auto& dyList = position.element->dy(); + const auto& rotateList = position.element->rotate(); unsigned xListSize = xList.size(); unsigned yListSize = yList.size(); @@ -195,11 +192,11 @@ void SVGTextLayoutAttributesBuilder::fillCharacterDataMap(const TextPosition& po float lastRotation = SVGTextLayoutAttributes::emptyValue(); SVGLengthContext lengthContext(position.element); for (unsigned i = 0; i < position.length; ++i) { - const SVGLengthList* xListPtr = i < xListSize ? &xList : 0; - const SVGLengthList* yListPtr = i < yListSize ? &yList : 0; - const SVGLengthList* dxListPtr = i < dxListSize ? &dxList : 0; - const SVGLengthList* dyListPtr = i < dyListSize ? &dyList : 0; - const SVGNumberList* rotateListPtr = i < rotateListSize ? &rotateList : 0; + const SVGLengthListValues* xListPtr = i < xListSize ? &xList : 0; + const SVGLengthListValues* yListPtr = i < yListSize ? &yList : 0; + const SVGLengthListValues* dxListPtr = i < dxListSize ? &dxList : 0; + const SVGLengthListValues* dyListPtr = i < dyListSize ? &dyList : 0; + const SVGNumberListValues* rotateListPtr = i < rotateListSize ? &rotateList : 0; if (!xListPtr && !yListPtr && !dxListPtr && !dyListPtr && !rotateListPtr) break; @@ -232,5 +229,3 @@ void SVGTextLayoutAttributesBuilder::fillCharacterDataMap(const TextPosition& po } } - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h b/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h index 5aa60e923..99c5f422d 100644 --- a/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h +++ b/Source/WebCore/rendering/svg/SVGTextLayoutAttributesBuilder.h @@ -17,14 +17,13 @@ * Boston, MA 02110-1301, USA. */ -#ifndef SVGTextLayoutAttributesBuilder_h -#define SVGTextLayoutAttributesBuilder_h +#pragma once -#if ENABLE(SVG) #include "SVGTextMetricsBuilder.h" namespace WebCore { +class RenderBoxModelObject; class RenderObject; class RenderSVGInlineText; class RenderSVGText; @@ -42,10 +41,10 @@ class SVGTextLayoutAttributesBuilder { WTF_MAKE_NONCOPYABLE(SVGTextLayoutAttributesBuilder); public: SVGTextLayoutAttributesBuilder(); - bool buildLayoutAttributesForForSubtree(RenderSVGText*); + bool buildLayoutAttributesForForSubtree(RenderSVGText&); void buildLayoutAttributesForTextRenderer(RenderSVGInlineText&); - void rebuildMetricsForTextRenderer(RenderSVGInlineText*); + void rebuildMetricsForTextRenderer(RenderSVGInlineText&); // Invoked whenever the underlying DOM tree changes, so that m_textPositions is rebuild. void clearTextPositioningElements() { m_textPositions.clear(); } @@ -65,8 +64,8 @@ private: unsigned length; }; - void buildCharacterDataMap(RenderSVGText*); - void collectTextPositioningElements(RenderObject*, const UChar*& lastCharacter); + void buildCharacterDataMap(RenderSVGText&); + void collectTextPositioningElements(RenderBoxModelObject&, bool& lastCharacterWasSpace); void fillCharacterDataMap(const TextPosition&); private: @@ -77,6 +76,3 @@ private: }; } // namespace WebCore - -#endif // ENABLE(SVG) -#endif diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp b/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp index aec25e146..0a0c3cd0b 100644 --- a/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp +++ b/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp @@ -18,10 +18,9 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "SVGTextLayoutEngine.h" +#include "PathTraversalState.h" #include "RenderSVGTextPath.h" #include "SVGElement.h" #include "SVGInlineTextBox.h" @@ -111,7 +110,7 @@ void SVGTextLayoutEngine::updateRelativePositionAdjustmentsIfNeeded(float dx, fl m_dy = dy; } -void SVGTextLayoutEngine::recordTextFragment(SVGInlineTextBox* textBox, Vector<SVGTextMetrics>& textMetricsValues) +void SVGTextLayoutEngine::recordTextFragment(SVGInlineTextBox& textBox, Vector<SVGTextMetrics>& textMetricsValues) { ASSERT(!m_currentTextFragment.length); ASSERT(m_visualMetricsListOffset > 0); @@ -138,7 +137,7 @@ void SVGTextLayoutEngine::recordTextFragment(SVGInlineTextBox* textBox, Vector<S } } - textBox->textFragments().append(m_currentTextFragment); + textBox.textFragments().append(m_currentTextFragment); m_currentTextFragment = SVGTextFragment(); } @@ -162,58 +161,39 @@ bool SVGTextLayoutEngine::parentDefinesTextLength(RenderObject* parent) const return false; } -void SVGTextLayoutEngine::beginTextPathLayout(RenderObject* object, SVGTextLayoutEngine& lineLayout) +void SVGTextLayoutEngine::beginTextPathLayout(RenderSVGTextPath& textPath, SVGTextLayoutEngine& lineLayout) { - ASSERT(object); - m_inPathLayout = true; - RenderSVGTextPath* textPath = toRenderSVGTextPath(object); - m_textPath = textPath->layoutPath(); + m_textPath = textPath.layoutPath(); if (m_textPath.isEmpty()) return; - m_textPathStartOffset = textPath->startOffset(); + + m_textPathStartOffset = textPath.startOffset(); m_textPathLength = m_textPath.length(); if (m_textPathStartOffset > 0 && m_textPathStartOffset <= 1) m_textPathStartOffset *= m_textPathLength; - float totalLength = 0; - unsigned totalCharacters = 0; - lineLayout.m_chunkLayoutBuilder.buildTextChunks(lineLayout.m_lineLayoutBoxes); - const Vector<SVGTextChunk>& textChunks = lineLayout.m_chunkLayoutBuilder.textChunks(); - - unsigned size = textChunks.size(); - for (unsigned i = 0; i < size; ++i) { - const SVGTextChunk& chunk = textChunks.at(i); - - float length = 0; - unsigned characters = 0; - chunk.calculateLength(length, characters); - - // Handle text-anchor as additional start offset for text paths. - m_textPathStartOffset += chunk.calculateTextAnchorShift(length); - - totalLength += length; - totalCharacters += characters; - } + // Handle text-anchor as additional start offset for text paths. + m_textPathStartOffset += lineLayout.m_chunkLayoutBuilder.totalAnchorShift(); m_textPathCurrentOffset = m_textPathStartOffset; // Eventually handle textLength adjustments. - SVGLengthAdjustType lengthAdjust = SVGLengthAdjustUnknown; - float desiredTextLength = 0; - - if (SVGTextContentElement* textContentElement = SVGTextContentElement::elementFromRenderer(textPath)) { - SVGLengthContext lengthContext(textContentElement); - lengthAdjust = textContentElement->lengthAdjust(); - desiredTextLength = textContentElement->specifiedTextLength().value(lengthContext); - } + auto* textContentElement = SVGTextContentElement::elementFromRenderer(&textPath); + if (!textContentElement) + return; + SVGLengthContext lengthContext(textContentElement); + float desiredTextLength = textContentElement->specifiedTextLength().value(lengthContext); if (!desiredTextLength) return; - if (lengthAdjust == SVGLengthAdjustSpacing) + float totalLength = lineLayout.m_chunkLayoutBuilder.totalLength(); + unsigned totalCharacters = lineLayout.m_chunkLayoutBuilder.totalCharacters(); + + if (textContentElement->lengthAdjust() == SVGLengthAdjustSpacing) m_textPathSpacing = (desiredTextLength - totalLength) / totalCharacters; else m_textPathScaling = desiredTextLength / totalLength; @@ -230,27 +210,25 @@ void SVGTextLayoutEngine::endTextPathLayout() m_textPathScaling = 1; } -void SVGTextLayoutEngine::layoutInlineTextBox(SVGInlineTextBox* textBox) +void SVGTextLayoutEngine::layoutInlineTextBox(SVGInlineTextBox& textBox) { - ASSERT(textBox); - - RenderSVGInlineText& text = textBox->renderer(); + RenderSVGInlineText& text = textBox.renderer(); ASSERT(text.parent()); ASSERT(text.parent()->element()); ASSERT(text.parent()->element()->isSVGElement()); const RenderStyle& style = text.style(); - textBox->clearTextFragments(); - m_isVerticalText = style.svgStyle().isVerticalWritingMode(); - layoutTextOnLineOrPath(textBox, &text, &style); + textBox.clearTextFragments(); + m_isVerticalText = style.isVerticalWritingMode(); + layoutTextOnLineOrPath(textBox, text, style); if (m_inPathLayout) { - m_pathLayoutBoxes.append(textBox); + m_pathLayoutBoxes.append(&textBox); return; } - m_lineLayoutBoxes.append(textBox); + m_lineLayoutBoxes.append(&textBox); } #if DUMP_TEXT_FRAGMENTS > 0 @@ -292,7 +270,7 @@ void SVGTextLayoutEngine::finalizeTransformMatrices(Vector<SVGInlineTextBox*>& b unsigned fragmentCount = fragments.size(); for (unsigned i = 0; i < fragmentCount; ++i) { - m_chunkLayoutBuilder.transformationForTextBox(textBox, textBoxTransformation); + textBoxTransformation = m_chunkLayoutBuilder.transformationForTextBox(textBox); if (textBoxTransformation.isIdentity()) continue; ASSERT(fragments[i].lengthAdjustTransform.isIdentity()); @@ -380,12 +358,12 @@ bool SVGTextLayoutEngine::currentLogicalCharacterMetrics(SVGTextLayoutAttributes return true; } -bool SVGTextLayoutEngine::currentVisualCharacterMetrics(SVGInlineTextBox* textBox, Vector<SVGTextMetrics>& visualMetricsValues, SVGTextMetrics& visualMetrics) +bool SVGTextLayoutEngine::currentVisualCharacterMetrics(const SVGInlineTextBox& textBox, Vector<SVGTextMetrics>& visualMetricsValues, SVGTextMetrics& visualMetrics) { ASSERT(!visualMetricsValues.isEmpty()); unsigned textMetricsSize = visualMetricsValues.size(); - unsigned boxStart = textBox->start(); - unsigned boxLength = textBox->len(); + unsigned boxStart = textBox.start(); + unsigned boxLength = textBox.len(); if (m_visualMetricsListOffset == textMetricsSize) return false; @@ -420,26 +398,28 @@ void SVGTextLayoutEngine::advanceToNextVisualCharacter(const SVGTextMetrics& vis m_visualCharacterOffset += visualMetrics.length(); } -void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, RenderSVGInlineText* text, const RenderStyle* style) +void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox& textBox, RenderSVGInlineText& text, const RenderStyle& style) { if (m_inPathLayout && m_textPath.isEmpty()) return; - SVGElement* lengthContext = toSVGElement(text->parent()->element()); + RenderElement* textParent = text.parent(); + ASSERT(textParent); + SVGElement* lengthContext = downcast<SVGElement>(textParent->element()); - RenderObject* textParent = text->parent(); - bool definesTextLength = textParent ? parentDefinesTextLength(textParent) : false; + bool definesTextLength = parentDefinesTextLength(textParent); - const SVGRenderStyle& svgStyle = style->svgStyle(); + const SVGRenderStyle& svgStyle = style.svgStyle(); m_visualMetricsListOffset = 0; m_visualCharacterOffset = 0; - Vector<SVGTextMetrics>& visualMetricsValues = text->layoutAttributes()->textMetricsValues(); + Vector<SVGTextMetrics>& visualMetricsValues = text.layoutAttributes()->textMetricsValues(); ASSERT(!visualMetricsValues.isEmpty()); - const UChar* characters = text->deprecatedCharacters(); - const Font& font = style->font(); + auto upconvertedCharacters = StringView(text.text()).upconvertedCharacters(); + const UChar* characters = upconvertedCharacters; + const FontCascade& font = style.fontCascade(); SVGTextLayoutEngineSpacing spacingLayout(font); SVGTextLayoutEngineBaseline baselineLayout(font); @@ -448,7 +428,7 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend bool applySpacingToNextCharacter = false; float lastAngle = 0; - float baselineShift = baselineLayout.calculateBaselineShift(&svgStyle, lengthContext); + float baselineShift = baselineLayout.calculateBaselineShift(svgStyle, lengthContext); baselineShift -= baselineLayout.calculateAlignmentBaselineShift(m_isVerticalText, text); // Main layout algorithm. @@ -481,16 +461,16 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend float x = data.x; float y = data.y; - // When we've advanced to the box start offset, determine using the original x/y values, - // whether this character starts a new text chunk, before doing any further processing. - if (m_visualCharacterOffset == textBox->start()) - textBox->setStartsNewTextChunk(logicalAttributes->context().characterStartsNewTextChunk(m_logicalCharacterOffset)); + // When we've advanced to the box start offset, determine using the original x/y values + // whether this character starts a new text chunk before doing any further processing. + if (m_visualCharacterOffset == textBox.start()) + textBox.setStartsNewTextChunk(logicalAttributes->context().characterStartsNewTextChunk(m_logicalCharacterOffset)); float angle = data.rotate == SVGTextLayoutAttributes::emptyValue() ? 0 : data.rotate; // Calculate glyph orientation angle. const UChar* currentCharacter = characters + m_visualCharacterOffset; - float orientationAngle = baselineLayout.calculateGlyphOrientationAngle(m_isVerticalText, &svgStyle, *currentCharacter); + float orientationAngle = baselineLayout.calculateGlyphOrientationAngle(m_isVerticalText, svgStyle, *currentCharacter); // Calculate glyph advance & x/y orientation shifts. float xOrientationShift = 0; @@ -503,9 +483,6 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend // Apply dx/dy value adjustments to current text position, if needed. updateRelativePositionAdjustmentsIfNeeded(data.dx, data.dy); - // Calculate SVG Fonts kerning, if needed. - float kerning = spacingLayout.calculateSVGKerning(m_isVerticalText, visualMetrics.glyph()); - // Calculate CSS 'kerning', 'letter-spacing' and 'word-spacing' for next character, if needed. float spacing = spacingLayout.calculateCSSKerningAndSpacing(&svgStyle, lengthContext, currentCharacter); @@ -517,7 +494,7 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend if (y != SVGTextLayoutAttributes::emptyValue()) m_textPathCurrentOffset = y + m_textPathStartOffset; - m_textPathCurrentOffset += m_dy - kerning; + m_textPathCurrentOffset += m_dy; m_dy = 0; // Apply dx/dy correction and setup translations that move to the glyph midpoint. @@ -528,7 +505,7 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend if (x != SVGTextLayoutAttributes::emptyValue()) m_textPathCurrentOffset = x + m_textPathStartOffset; - m_textPathCurrentOffset += m_dx - kerning; + m_textPathCurrentOffset += m_dx; m_dx = 0; // Apply dx/dy correction and setup translations that move to the glyph midpoint. @@ -553,27 +530,25 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend if (textPathOffset > m_textPathLength) break; - bool ok = false; - FloatPoint point = m_textPath.pointAtLength(textPathOffset, ok); - ASSERT(ok); + bool success = false; + auto traversalState(m_textPath.traversalStateAtLength(textPathOffset, success)); + ASSERT(success); + FloatPoint point = traversalState.current(); x = point.x(); y = point.y(); - angle = m_textPath.normalAngleAtLength(textPathOffset, ok); - ASSERT(ok); + + angle = traversalState.normalAngle(); // For vertical text on path, the actual angle has to be rotated 90 degrees anti-clockwise, not the orientation angle! if (m_isVerticalText) angle -= 90; } else { // Apply all previously calculated shift values. - if (m_isVerticalText) { + if (m_isVerticalText) x += baselineShift; - y -= kerning; - } else { - x -= kerning; + else y -= baselineShift; - } x += m_dx; y += m_dy; @@ -581,7 +556,7 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend // Determine whether we have to start a new fragment. bool shouldStartNewFragment = m_dx || m_dy || m_isVerticalText || m_inPathLayout || angle || angle != lastAngle - || orientationAngle || kerning || applySpacingToNextCharacter || definesTextLength; + || orientationAngle || applySpacingToNextCharacter || definesTextLength; // If we already started a fragment, close it now. if (didStartTextFragment && shouldStartNewFragment) { @@ -651,5 +626,3 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend } } - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutEngine.h b/Source/WebCore/rendering/svg/SVGTextLayoutEngine.h index c4a926400..3fcfdb4f0 100644 --- a/Source/WebCore/rendering/svg/SVGTextLayoutEngine.h +++ b/Source/WebCore/rendering/svg/SVGTextLayoutEngine.h @@ -17,10 +17,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef SVGTextLayoutEngine_h -#define SVGTextLayoutEngine_h +#pragma once -#if ENABLE(SVG) #include "Path.h" #include "SVGTextChunkBuilder.h" #include "SVGTextFragment.h" @@ -31,6 +29,7 @@ namespace WebCore { class RenderObject; class RenderStyle; class RenderSVGInlineText; +class RenderSVGTextPath; class SVGElement; class SVGInlineTextBox; class SVGRenderStyle; @@ -51,10 +50,10 @@ public: Vector<SVGTextLayoutAttributes*>& layoutAttributes() { return m_layoutAttributes; } SVGTextChunkBuilder& chunkLayoutBuilder() { return m_chunkLayoutBuilder; } - void beginTextPathLayout(RenderObject*, SVGTextLayoutEngine& lineLayout); + void beginTextPathLayout(RenderSVGTextPath&, SVGTextLayoutEngine& lineLayout); void endTextPathLayout(); - void layoutInlineTextBox(SVGInlineTextBox*); + void layoutInlineTextBox(SVGInlineTextBox&); void finishLayout(); private: @@ -62,15 +61,15 @@ private: void updateCurrentTextPosition(float x, float y, float glyphAdvance); void updateRelativePositionAdjustmentsIfNeeded(float dx, float dy); - void recordTextFragment(SVGInlineTextBox*, Vector<SVGTextMetrics>&); + void recordTextFragment(SVGInlineTextBox&, Vector<SVGTextMetrics>&); bool parentDefinesTextLength(RenderObject*) const; - void layoutTextOnLineOrPath(SVGInlineTextBox*, RenderSVGInlineText*, const RenderStyle*); + void layoutTextOnLineOrPath(SVGInlineTextBox&, RenderSVGInlineText&, const RenderStyle&); void finalizeTransformMatrices(Vector<SVGInlineTextBox*>&); bool currentLogicalCharacterAttributes(SVGTextLayoutAttributes*&); bool currentLogicalCharacterMetrics(SVGTextLayoutAttributes*&, SVGTextMetrics&); - bool currentVisualCharacterMetrics(SVGInlineTextBox*, Vector<SVGTextMetrics>&, SVGTextMetrics&); + bool currentVisualCharacterMetrics(const SVGInlineTextBox&, Vector<SVGTextMetrics>&, SVGTextMetrics&); void advanceToNextLogicalCharacter(const SVGTextMetrics&); void advanceToNextVisualCharacter(const SVGTextMetrics&); @@ -105,6 +104,3 @@ private: }; } // namespace WebCore - -#endif // ENABLE(SVG) -#endif diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.cpp b/Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.cpp index 0497a3456..e0377167f 100644 --- a/Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.cpp +++ b/Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.cpp @@ -18,11 +18,9 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "SVGTextLayoutEngineBaseline.h" -#include "Font.h" +#include "FontCascade.h" #include "RenderElement.h" #include "SVGLengthContext.h" #include "SVGRenderStyle.h" @@ -30,33 +28,34 @@ namespace WebCore { -SVGTextLayoutEngineBaseline::SVGTextLayoutEngineBaseline(const Font& font) +SVGTextLayoutEngineBaseline::SVGTextLayoutEngineBaseline(const FontCascade& font) : m_font(font) { } -float SVGTextLayoutEngineBaseline::calculateBaselineShift(const SVGRenderStyle* style, SVGElement* contextElement) const +float SVGTextLayoutEngineBaseline::calculateBaselineShift(const SVGRenderStyle& style, SVGElement* context) const { - if (style->baselineShift() == BS_LENGTH) { - SVGLength baselineShiftValueLength = style->baselineShiftValue(); + if (style.baselineShift() == BS_LENGTH) { + auto baselineShiftValueLength = style.baselineShiftValue(); if (baselineShiftValueLength.unitType() == LengthTypePercentage) return baselineShiftValueLength.valueAsPercentage() * m_font.pixelSize(); - SVGLengthContext lengthContext(contextElement); + SVGLengthContext lengthContext(context); return baselineShiftValueLength.value(lengthContext); } - switch (style->baselineShift()) { + switch (style.baselineShift()) { case BS_BASELINE: return 0; case BS_SUB: return -m_font.fontMetrics().floatHeight() / 2; case BS_SUPER: return m_font.fontMetrics().floatHeight() / 2; - default: - ASSERT_NOT_REACHED(); - return 0; + case BS_LENGTH: + break; } + ASSERT_NOT_REACHED(); + return 0; } EAlignmentBaseline SVGTextLayoutEngineBaseline::dominantBaselineToAlignmentBaseline(bool isVerticalText, const RenderObject* textRenderer) const @@ -104,15 +103,12 @@ EAlignmentBaseline SVGTextLayoutEngineBaseline::dominantBaselineToAlignmentBasel } } -float SVGTextLayoutEngineBaseline::calculateAlignmentBaselineShift(bool isVerticalText, const RenderObject* textRenderer) const +float SVGTextLayoutEngineBaseline::calculateAlignmentBaselineShift(bool isVerticalText, const RenderObject& textRenderer) const { - ASSERT(textRenderer); - ASSERT(textRenderer->parent()); - - const RenderObject* textRendererParent = textRenderer->parent(); + const RenderObject* textRendererParent = textRenderer.parent(); ASSERT(textRendererParent); - EAlignmentBaseline baseline = textRenderer->style().svgStyle().alignmentBaseline(); + EAlignmentBaseline baseline = textRenderer.style().svgStyle().alignmentBaseline(); if (baseline == AB_AUTO) { baseline = dominantBaselineToAlignmentBaseline(isVerticalText, textRendererParent); ASSERT(baseline != AB_AUTO); @@ -147,11 +143,9 @@ float SVGTextLayoutEngineBaseline::calculateAlignmentBaselineShift(bool isVertic } } -float SVGTextLayoutEngineBaseline::calculateGlyphOrientationAngle(bool isVerticalText, const SVGRenderStyle* style, const UChar& character) const +float SVGTextLayoutEngineBaseline::calculateGlyphOrientationAngle(bool isVerticalText, const SVGRenderStyle& style, const UChar& character) const { - ASSERT(style); - - switch (isVerticalText ? style->glyphOrientationVertical() : style->glyphOrientationHorizontal()) { + switch (isVerticalText ? style.glyphOrientationVertical() : style.glyphOrientationHorizontal()) { case GO_AUTO: // Spec: Fullwidth ideographic and fullwidth Latin text will be set with a glyph-orientation of 0-degrees. // Text which is not fullwidth will be set with a glyph-orientation of 90-degrees. @@ -240,5 +234,3 @@ float SVGTextLayoutEngineBaseline::calculateGlyphAdvanceAndOrientation(bool isVe } } - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.h b/Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.h index 6794bf3f8..44d7f73d2 100644 --- a/Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.h +++ b/Source/WebCore/rendering/svg/SVGTextLayoutEngineBaseline.h @@ -17,16 +17,14 @@ * Boston, MA 02110-1301, USA. */ -#ifndef SVGTextLayoutEngineBaseline_h -#define SVGTextLayoutEngineBaseline_h +#pragma once -#if ENABLE(SVG) #include "SVGRenderStyleDefs.h" #include <wtf/Noncopyable.h> namespace WebCore { -class Font; +class FontCascade; class RenderObject; class SVGElement; class SVGRenderStyle; @@ -36,20 +34,17 @@ class SVGTextMetrics; class SVGTextLayoutEngineBaseline { WTF_MAKE_NONCOPYABLE(SVGTextLayoutEngineBaseline); public: - SVGTextLayoutEngineBaseline(const Font&); + SVGTextLayoutEngineBaseline(const FontCascade&); - float calculateBaselineShift(const SVGRenderStyle*, SVGElement* lengthContext) const; - float calculateAlignmentBaselineShift(bool isVerticalText, const RenderObject* textRenderer) const; - float calculateGlyphOrientationAngle(bool isVerticalText, const SVGRenderStyle*, const UChar& character) const; + float calculateBaselineShift(const SVGRenderStyle&, SVGElement* context) const; + float calculateAlignmentBaselineShift(bool isVerticalText, const RenderObject& textRenderer) const; + float calculateGlyphOrientationAngle(bool isVerticalText, const SVGRenderStyle&, const UChar& character) const; float calculateGlyphAdvanceAndOrientation(bool isVerticalText, SVGTextMetrics&, float angle, float& xOrientationShift, float& yOrientationShift) const; private: EAlignmentBaseline dominantBaselineToAlignmentBaseline(bool isVerticalText, const RenderObject* textRenderer) const; - const Font& m_font; + const FontCascade& m_font; }; } // namespace WebCore - -#endif // ENABLE(SVG) -#endif diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutEngineSpacing.cpp b/Source/WebCore/rendering/svg/SVGTextLayoutEngineSpacing.cpp index f0107c4ab..48d80ae99 100644 --- a/Source/WebCore/rendering/svg/SVGTextLayoutEngineSpacing.cpp +++ b/Source/WebCore/rendering/svg/SVGTextLayoutEngineSpacing.cpp @@ -18,73 +18,29 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "SVGTextLayoutEngineSpacing.h" -#include "Font.h" +#include "FontCascade.h" #include "SVGLengthContext.h" #include "SVGRenderStyle.h" #if ENABLE(SVG_FONTS) -#include "SVGFontData.h" #include "SVGFontElement.h" #include "SVGFontFaceElement.h" #endif namespace WebCore { -SVGTextLayoutEngineSpacing::SVGTextLayoutEngineSpacing(const Font& font) +SVGTextLayoutEngineSpacing::SVGTextLayoutEngineSpacing(const FontCascade& font) : m_font(font) , m_lastCharacter(0) { } -float SVGTextLayoutEngineSpacing::calculateSVGKerning(bool isVerticalText, const SVGTextMetrics::Glyph& currentGlyph) -{ -#if ENABLE(SVG_FONTS) - const SimpleFontData* fontData = m_font.primaryFont(); - if (!fontData->isSVGFont()) { - m_lastGlyph.isValid = false; - return 0; - } - - ASSERT(fontData->isCustomFont()); - ASSERT(fontData->isSVGFont()); - - const SVGFontData* svgFontData = static_cast<const SVGFontData*>(fontData->fontData()); - SVGFontFaceElement* svgFontFace = svgFontData->svgFontFaceElement(); - ASSERT(svgFontFace); - - SVGFontElement* svgFont = svgFontFace->associatedFontElement(); - if (!svgFont) { - m_lastGlyph.isValid = false; - return 0; - } - - float kerning = 0; - if (m_lastGlyph.isValid) { - if (isVerticalText) - kerning = svgFont->verticalKerningForPairOfStringsAndGlyphs(m_lastGlyph.unicodeString, m_lastGlyph.name, currentGlyph.unicodeString, currentGlyph.name); - else - kerning = svgFont->horizontalKerningForPairOfStringsAndGlyphs(m_lastGlyph.unicodeString, m_lastGlyph.name, currentGlyph.unicodeString, currentGlyph.name); - } - - m_lastGlyph = currentGlyph; - m_lastGlyph.isValid = true; - kerning *= m_font.size() / m_font.fontMetrics().unitsPerEm(); - return kerning; -#else - UNUSED_PARAM(isVerticalText); - UNUSED_PARAM(currentGlyph); - return false; -#endif -} - float SVGTextLayoutEngineSpacing::calculateCSSKerningAndSpacing(const SVGRenderStyle* style, SVGElement* contextElement, const UChar* currentCharacter) { float kerning = 0; - SVGLength kerningLength = style->kerning(); + auto kerningLength = style->kerning(); if (kerningLength.unitType() == LengthTypePercentage) kerning = kerningLength.valueAsPercentage() * m_font.pixelSize(); else { @@ -100,7 +56,7 @@ float SVGTextLayoutEngineSpacing::calculateCSSKerningAndSpacing(const SVGRenderS float spacing = m_font.letterSpacing() + kerning; if (currentCharacter && lastCharacter && m_font.wordSpacing()) { - if (Font::treatAsSpace(*currentCharacter) && !Font::treatAsSpace(*lastCharacter)) + if (FontCascade::treatAsSpace(*currentCharacter) && !FontCascade::treatAsSpace(*lastCharacter)) spacing += m_font.wordSpacing(); } @@ -108,5 +64,3 @@ float SVGTextLayoutEngineSpacing::calculateCSSKerningAndSpacing(const SVGRenderS } } - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutEngineSpacing.h b/Source/WebCore/rendering/svg/SVGTextLayoutEngineSpacing.h index 71d470737..8e98f2c87 100644 --- a/Source/WebCore/rendering/svg/SVGTextLayoutEngineSpacing.h +++ b/Source/WebCore/rendering/svg/SVGTextLayoutEngineSpacing.h @@ -17,15 +17,13 @@ * Boston, MA 02110-1301, USA. */ -#ifndef SVGTextLayoutEngineSpacing_h -#define SVGTextLayoutEngineSpacing_h +#pragma once -#if ENABLE(SVG) #include "SVGTextMetrics.h" namespace WebCore { -class Font; +class FontCascade; class SVGRenderStyle; class SVGElement; @@ -33,21 +31,13 @@ class SVGElement; class SVGTextLayoutEngineSpacing { WTF_MAKE_NONCOPYABLE(SVGTextLayoutEngineSpacing); public: - SVGTextLayoutEngineSpacing(const Font&); + SVGTextLayoutEngineSpacing(const FontCascade&); - float calculateSVGKerning(bool isVerticalText, const SVGTextMetrics::Glyph& currentGlyph); float calculateCSSKerningAndSpacing(const SVGRenderStyle*, SVGElement* lengthContext, const UChar* currentCharacter); private: - const Font& m_font; + const FontCascade& m_font; const UChar* m_lastCharacter; - -#if ENABLE(SVG_FONTS) - SVGTextMetrics::Glyph m_lastGlyph; -#endif }; } // namespace WebCore - -#endif // ENABLE(SVG) -#endif diff --git a/Source/WebCore/rendering/svg/SVGTextMetrics.cpp b/Source/WebCore/rendering/svg/SVGTextMetrics.cpp index 0e6446e31..7627fe553 100644 --- a/Source/WebCore/rendering/svg/SVGTextMetrics.cpp +++ b/Source/WebCore/rendering/svg/SVGTextMetrics.cpp @@ -18,12 +18,9 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "SVGTextMetrics.h" #include "RenderSVGInlineText.h" -#include "SVGTextRunRenderingContext.h" #include "WidthIterator.h" namespace WebCore { @@ -42,18 +39,18 @@ SVGTextMetrics::SVGTextMetrics(SVGTextMetrics::MetricsType) { } -SVGTextMetrics::SVGTextMetrics(RenderSVGInlineText* textRenderer, const TextRun& run) +SVGTextMetrics::SVGTextMetrics(RenderSVGInlineText& textRenderer, const TextRun& run) { - ASSERT(textRenderer); - - float scalingFactor = textRenderer->scalingFactor(); + float scalingFactor = textRenderer.scalingFactor(); ASSERT(scalingFactor); - const Font& scaledFont = textRenderer->scaledFont(); + const FontCascade& scaledFont = textRenderer.scaledFont(); int length = 0; // Calculate width/height using the scaled font, divide this result by the scalingFactor afterwards. - m_width = scaledFont.width(run, length, m_glyph.name) / scalingFactor; + m_width = scaledFont.width(run) / scalingFactor; + length = run.length(); + m_glyph.name = emptyString(); m_height = scaledFont.fontMetrics().floatHeight() / scalingFactor; m_glyph.unicodeString = run.is8Bit() ? String(run.characters8(), length) : String(run.characters16(), length); @@ -63,57 +60,40 @@ SVGTextMetrics::SVGTextMetrics(RenderSVGInlineText* textRenderer, const TextRun& m_length = static_cast<unsigned>(length); } -TextRun SVGTextMetrics::constructTextRun(RenderSVGInlineText* text, const UChar* characters, unsigned position, unsigned length) +TextRun SVGTextMetrics::constructTextRun(RenderSVGInlineText& text, unsigned position, unsigned length) { - const RenderStyle& style = text->style(); + const RenderStyle& style = text.style(); - TextRun run(characters + position - , length + TextRun run(StringView(text.text()).substring(position, length) , 0 /* xPos, only relevant with allowTabs=true */ , 0 /* padding, only relevant for justified text, not relevant for SVG */ - , TextRun::AllowTrailingExpansion + , AllowTrailingExpansion , style.direction() , isOverride(style.unicodeBidi()) /* directionalOverride */); - if (style.font().isSVGFont()) - run.setRenderingContext(SVGTextRunRenderingContext::create(*text)); - - run.disableRoundingHacks(); - // We handle letter & word spacing ourselves. run.disableSpacing(); // Propagate the maximum length of the characters buffer to the TextRun, even when we're only processing a substring. - run.setCharactersLength(text->textLength() - position); + run.setCharactersLength(text.textLength() - position); ASSERT(run.charactersLength() >= run.length()); return run; } -SVGTextMetrics SVGTextMetrics::measureCharacterRange(RenderSVGInlineText* text, unsigned position, unsigned length) +SVGTextMetrics SVGTextMetrics::measureCharacterRange(RenderSVGInlineText& text, unsigned position, unsigned length) { - ASSERT(text); - return SVGTextMetrics(text, constructTextRun(text, text->deprecatedCharacters(), position, length)); + return SVGTextMetrics(text, constructTextRun(text, position, length)); } -SVGTextMetrics::SVGTextMetrics(RenderSVGInlineText* text, unsigned position, unsigned length, float width, const String& glyphName) +SVGTextMetrics::SVGTextMetrics(RenderSVGInlineText& text, unsigned length, float width) { - ASSERT(text); - - bool needsContext = text->style().font().isSVGFont(); - float scalingFactor = text->scalingFactor(); + float scalingFactor = text.scalingFactor(); ASSERT(scalingFactor); m_width = width / scalingFactor; - m_height = text->scaledFont().fontMetrics().floatHeight() / scalingFactor; - if (needsContext) { - m_glyph.isValid = true; - m_glyph.unicodeString = String(text->deprecatedCharacters() + position, length); - m_glyph.name = glyphName; - } + m_height = text.scaledFont().fontMetrics().floatHeight() / scalingFactor; m_length = length; } } - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/SVGTextMetrics.h b/Source/WebCore/rendering/svg/SVGTextMetrics.h index ba008c0ef..809629d0f 100644 --- a/Source/WebCore/rendering/svg/SVGTextMetrics.h +++ b/Source/WebCore/rendering/svg/SVGTextMetrics.h @@ -17,10 +17,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef SVGTextMetrics_h -#define SVGTextMetrics_h +#pragma once -#if ENABLE(SVG) #include <wtf/text/WTFString.h> namespace WebCore { @@ -31,16 +29,14 @@ class TextRun; class SVGTextMetrics { public: - enum MetricsType { - SkippedSpaceMetrics - }; + enum MetricsType { SkippedSpaceMetrics }; SVGTextMetrics(); - SVGTextMetrics(MetricsType); - SVGTextMetrics(RenderSVGInlineText*, unsigned position, unsigned length, float width, const String& glyphName); + explicit SVGTextMetrics(MetricsType); + SVGTextMetrics(RenderSVGInlineText&, unsigned length, float width); - static SVGTextMetrics measureCharacterRange(RenderSVGInlineText*, unsigned position, unsigned length); - static TextRun constructTextRun(RenderSVGInlineText*, const UChar* characters, unsigned position, unsigned length); + static SVGTextMetrics measureCharacterRange(RenderSVGInlineText&, unsigned position, unsigned length); + static TextRun constructTextRun(RenderSVGInlineText&, unsigned position = 0, unsigned length = std::numeric_limits<unsigned>::max()); bool isEmpty() const { return !m_width && !m_height && !m_glyph.isValid && m_length == 1; } @@ -72,7 +68,7 @@ public: const Glyph& glyph() const { return m_glyph; } private: - SVGTextMetrics(RenderSVGInlineText*, const TextRun&); + SVGTextMetrics(RenderSVGInlineText&, const TextRun&); float m_width; float m_height; @@ -81,6 +77,3 @@ private: }; } // namespace WebCore - -#endif // ENABLE(SVG) -#endif diff --git a/Source/WebCore/rendering/svg/SVGTextMetricsBuilder.cpp b/Source/WebCore/rendering/svg/SVGTextMetricsBuilder.cpp index 86009e6e9..bb2593d38 100644 --- a/Source/WebCore/rendering/svg/SVGTextMetricsBuilder.cpp +++ b/Source/WebCore/rendering/svg/SVGTextMetricsBuilder.cpp @@ -18,19 +18,18 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "SVGTextMetricsBuilder.h" +#include "RenderChildIterator.h" +#include "RenderSVGInline.h" #include "RenderSVGInlineText.h" #include "RenderSVGText.h" -#include "SVGTextRunRenderingContext.h" namespace WebCore { SVGTextMetricsBuilder::SVGTextMetricsBuilder() : m_text(0) - , m_run(static_cast<const UChar*>(0), 0) + , m_run(StringView()) , m_textPosition(0) , m_isComplexText(false) , m_totalWidth(0) @@ -39,13 +38,13 @@ SVGTextMetricsBuilder::SVGTextMetricsBuilder() inline bool SVGTextMetricsBuilder::currentCharacterStartsSurrogatePair() const { - return U16_IS_LEAD(m_run[m_textPosition]) && int(m_textPosition + 1) < m_run.charactersLength() && U16_IS_TRAIL(m_run[m_textPosition + 1]); + return U16_IS_LEAD(m_run[m_textPosition]) && (m_textPosition + 1) < m_run.charactersLength() && U16_IS_TRAIL(m_run[m_textPosition + 1]); } bool SVGTextMetricsBuilder::advance() { m_textPosition += m_currentMetrics.length(); - if (int(m_textPosition) >= m_run.charactersLength()) + if (m_textPosition >= m_run.charactersLength()) return false; if (m_isComplexText) @@ -68,18 +67,14 @@ void SVGTextMetricsBuilder::advanceSimpleText() float currentWidth = m_simpleWidthIterator->runWidthSoFar() - m_totalWidth; m_totalWidth = m_simpleWidthIterator->runWidthSoFar(); -#if ENABLE(SVG_FONTS) - m_currentMetrics = SVGTextMetrics(m_text, m_textPosition, metricsLength, currentWidth, m_simpleWidthIterator->lastGlyphName()); -#else - m_currentMetrics = SVGTextMetrics(m_text, m_textPosition, metricsLength, currentWidth, emptyString()); -#endif + m_currentMetrics = SVGTextMetrics(*m_text, metricsLength, currentWidth); } void SVGTextMetricsBuilder::advanceComplexText() { unsigned metricsLength = currentCharacterStartsSurrogatePair() ? 2 : 1; - m_currentMetrics = SVGTextMetrics::measureCharacterRange(m_text, m_textPosition, metricsLength); - m_complexStartToCurrentMetrics = SVGTextMetrics::measureCharacterRange(m_text, 0, m_textPosition + metricsLength); + m_currentMetrics = SVGTextMetrics::measureCharacterRange(*m_text, m_textPosition, metricsLength); + m_complexStartToCurrentMetrics = SVGTextMetrics::measureCharacterRange(*m_text, 0, m_textPosition + metricsLength); ASSERT(m_currentMetrics.length() == metricsLength); // Frequent case for Arabic text: when measuring a single character the arabic isolated form is taken @@ -93,22 +88,22 @@ void SVGTextMetricsBuilder::advanceComplexText() m_totalWidth = m_complexStartToCurrentMetrics.width(); } -void SVGTextMetricsBuilder::initializeMeasurementWithTextRenderer(RenderSVGInlineText* text) +void SVGTextMetricsBuilder::initializeMeasurementWithTextRenderer(RenderSVGInlineText& text) { - m_text = text; + m_text = &text; m_textPosition = 0; m_currentMetrics = SVGTextMetrics(); m_complexStartToCurrentMetrics = SVGTextMetrics(); m_totalWidth = 0; - const Font& scaledFont = text->scaledFont(); - m_run = SVGTextMetrics::constructTextRun(text, text->deprecatedCharacters(), 0, text->textLength()); - m_isComplexText = scaledFont.codePath(m_run) == Font::Complex; + const FontCascade& scaledFont = text.scaledFont(); + m_run = SVGTextMetrics::constructTextRun(text); + m_isComplexText = scaledFont.codePath(m_run) == FontCascade::Complex; if (m_isComplexText) - m_simpleWidthIterator.clear(); + m_simpleWidthIterator = nullptr; else - m_simpleWidthIterator = adoptPtr(new WidthIterator(&scaledFont, m_run)); + m_simpleWidthIterator = std::make_unique<WidthIterator>(&scaledFont, m_run); } struct MeasureTextData { @@ -122,17 +117,15 @@ struct MeasureTextData { } SVGCharacterDataMap* allCharactersMap; - const UChar* lastCharacter; + UChar lastCharacter; bool processRenderer; unsigned valueListPosition; unsigned skippedCharacters; }; -void SVGTextMetricsBuilder::measureTextRenderer(RenderSVGInlineText* text, MeasureTextData* data) +void SVGTextMetricsBuilder::measureTextRenderer(RenderSVGInlineText& text, MeasureTextData* data) { - ASSERT(text); - - SVGTextLayoutAttributes* attributes = text->layoutAttributes(); + SVGTextLayoutAttributes* attributes = text.layoutAttributes(); Vector<SVGTextMetrics>* textMetricsValues = &attributes->textMetricsValues(); if (data->processRenderer) { if (data->allCharactersMap) @@ -142,12 +135,12 @@ void SVGTextMetricsBuilder::measureTextRenderer(RenderSVGInlineText* text, Measu } initializeMeasurementWithTextRenderer(text); - bool preserveWhiteSpace = text->style().whiteSpace() == PRE; + bool preserveWhiteSpace = text.style().whiteSpace() == PRE; int surrogatePairCharacters = 0; while (advance()) { - const UChar* currentCharacter = m_run.data16(m_textPosition); - if (*currentCharacter == ' ' && !preserveWhiteSpace && (!data->lastCharacter || *data->lastCharacter == ' ')) { + UChar currentCharacter = m_run[m_textPosition]; + if (currentCharacter == ' ' && !preserveWhiteSpace && (!data->lastCharacter || data->lastCharacter == ' ')) { if (data->processRenderer) textMetricsValues->append(SVGTextMetrics(SVGTextMetrics::SkippedSpaceMetrics)); if (data->allCharactersMap) @@ -179,10 +172,10 @@ void SVGTextMetricsBuilder::measureTextRenderer(RenderSVGInlineText* text, Measu void SVGTextMetricsBuilder::walkTree(RenderElement& start, RenderSVGInlineText* stopAtLeaf, MeasureTextData* data) { - for (auto child = start.firstChild(); child; child = child->nextSibling()) { - if (child->isSVGInlineText()) { - RenderSVGInlineText* text = toRenderSVGInlineText(child); - if (stopAtLeaf && stopAtLeaf != text) { + for (auto& child : childrenOfType<RenderObject>(start)) { + if (is<RenderSVGInlineText>(child)) { + auto& text = downcast<RenderSVGInlineText>(child); + if (stopAtLeaf && stopAtLeaf != &text) { data->processRenderer = false; measureTextRenderer(text, data); continue; @@ -196,32 +189,27 @@ void SVGTextMetricsBuilder::walkTree(RenderElement& start, RenderSVGInlineText* continue; } - if (!child->isSVGInline()) + if (!is<RenderSVGInline>(child)) continue; - walkTree(toRenderElement(*child), stopAtLeaf, data); + walkTree(downcast<RenderSVGInline>(child), stopAtLeaf, data); } } -void SVGTextMetricsBuilder::measureTextRenderer(RenderSVGInlineText* text) +void SVGTextMetricsBuilder::measureTextRenderer(RenderSVGInlineText& text) { - ASSERT(text); - - RenderSVGText* textRoot = RenderSVGText::locateRenderSVGTextAncestor(text); + auto* textRoot = RenderSVGText::locateRenderSVGTextAncestor(text); if (!textRoot) return; - MeasureTextData data(0); - walkTree(*textRoot, text, &data); + MeasureTextData data(nullptr); + walkTree(*textRoot, &text, &data); } -void SVGTextMetricsBuilder::buildMetricsAndLayoutAttributes(RenderSVGText* textRoot, RenderSVGInlineText* stopAtLeaf, SVGCharacterDataMap& allCharactersMap) +void SVGTextMetricsBuilder::buildMetricsAndLayoutAttributes(RenderSVGText& textRoot, RenderSVGInlineText* stopAtLeaf, SVGCharacterDataMap& allCharactersMap) { - ASSERT(textRoot); MeasureTextData data(&allCharactersMap); - walkTree(*textRoot, stopAtLeaf, &data); + walkTree(textRoot, stopAtLeaf, &data); } } - -#endif // ENABLE(SVG) diff --git a/Source/WebCore/rendering/svg/SVGTextMetricsBuilder.h b/Source/WebCore/rendering/svg/SVGTextMetricsBuilder.h index 5e0d12951..4f7402523 100644 --- a/Source/WebCore/rendering/svg/SVGTextMetricsBuilder.h +++ b/Source/WebCore/rendering/svg/SVGTextMetricsBuilder.h @@ -17,10 +17,8 @@ * Boston, MA 02110-1301, USA. */ -#ifndef SVGTextMetricsBuilder_h -#define SVGTextMetricsBuilder_h +#pragma once -#if ENABLE(SVG) #include "SVGTextLayoutAttributes.h" #include "TextRun.h" #include "WidthIterator.h" @@ -36,8 +34,8 @@ class SVGTextMetricsBuilder { WTF_MAKE_NONCOPYABLE(SVGTextMetricsBuilder); public: SVGTextMetricsBuilder(); - void measureTextRenderer(RenderSVGInlineText*); - void buildMetricsAndLayoutAttributes(RenderSVGText*, RenderSVGInlineText* stopAtLeaf, SVGCharacterDataMap& allCharactersMap); + void measureTextRenderer(RenderSVGInlineText&); + void buildMetricsAndLayoutAttributes(RenderSVGText&, RenderSVGInlineText* stopAtLeaf, SVGCharacterDataMap& allCharactersMap); private: bool advance(); @@ -45,9 +43,9 @@ private: void advanceComplexText(); bool currentCharacterStartsSurrogatePair() const; - void initializeMeasurementWithTextRenderer(RenderSVGInlineText*); + void initializeMeasurementWithTextRenderer(RenderSVGInlineText&); void walkTree(RenderElement&, RenderSVGInlineText* stopAtLeaf, MeasureTextData*); - void measureTextRenderer(RenderSVGInlineText*, MeasureTextData*); + void measureTextRenderer(RenderSVGInlineText&, MeasureTextData*); RenderSVGInlineText* m_text; TextRun m_run; @@ -57,13 +55,10 @@ private: float m_totalWidth; // Simple text only. - OwnPtr<WidthIterator> m_simpleWidthIterator; + std::unique_ptr<WidthIterator> m_simpleWidthIterator; // Complex text only. SVGTextMetrics m_complexStartToCurrentMetrics; }; } // namespace WebCore - -#endif // ENABLE(SVG) -#endif diff --git a/Source/WebCore/rendering/svg/SVGTextQuery.cpp b/Source/WebCore/rendering/svg/SVGTextQuery.cpp index f25dedcad..86e4bf2f3 100644 --- a/Source/WebCore/rendering/svg/SVGTextQuery.cpp +++ b/Source/WebCore/rendering/svg/SVGTextQuery.cpp @@ -20,11 +20,11 @@ #include "config.h" #include "SVGTextQuery.h" -#if ENABLE(SVG) #include "FloatConversion.h" #include "InlineFlowBox.h" #include "RenderBlockFlow.h" #include "RenderInline.h" +#include "RenderSVGText.h" #include "SVGInlineTextBox.h" #include "VisiblePosition.h" @@ -51,12 +51,12 @@ struct SVGTextQuery::Data { static inline InlineFlowBox* flowBoxForRenderer(RenderObject* renderer) { if (!renderer) - return 0; + return nullptr; - if (renderer->isRenderBlockFlow()) { + if (is<RenderBlockFlow>(*renderer)) { // If we're given a block element, it has to be a RenderSVGText. - ASSERT(renderer->isSVGText()); - RenderBlockFlow& renderBlock = toRenderBlockFlow(*renderer); + ASSERT(is<RenderSVGText>(*renderer)); + RenderBlockFlow& renderBlock = downcast<RenderBlockFlow>(*renderer); // RenderSVGText only ever contains a single line box. auto flowBox = renderBlock.firstRootBox(); @@ -64,9 +64,9 @@ static inline InlineFlowBox* flowBoxForRenderer(RenderObject* renderer) return flowBox; } - if (renderer->isRenderInline()) { + if (is<RenderInline>(*renderer)) { // We're given a RenderSVGInline or objects that derive from it (RenderSVGTSpan / RenderSVGTextPath) - RenderInline& renderInline = toRenderInline(*renderer); + RenderInline& renderInline = downcast<RenderInline>(*renderer); // RenderSVGInline only ever contains a single line box. InlineFlowBox* flowBox = renderInline.firstLineBox(); @@ -75,7 +75,7 @@ static inline InlineFlowBox* flowBoxForRenderer(RenderObject* renderer) } ASSERT_NOT_REACHED(); - return 0; + return nullptr; } SVGTextQuery::SVGTextQuery(RenderObject* renderer) @@ -89,17 +89,17 @@ void SVGTextQuery::collectTextBoxesInFlowBox(InlineFlowBox* flowBox) return; for (InlineBox* child = flowBox->firstChild(); child; child = child->nextOnLine()) { - if (child->isInlineFlowBox()) { + if (is<InlineFlowBox>(*child)) { // Skip generated content. if (!child->renderer().node()) continue; - collectTextBoxesInFlowBox(toInlineFlowBox(child)); + collectTextBoxesInFlowBox(downcast<InlineFlowBox>(child)); continue; } - if (child->isSVGInlineTextBox()) - m_textBoxes.append(toSVGInlineTextBox(child)); + if (is<SVGInlineTextBox>(*child)) + m_textBoxes.append(downcast<SVGInlineTextBox>(child)); } } @@ -115,7 +115,7 @@ bool SVGTextQuery::executeQuery(Data* queryData, ProcessTextFragmentCallback fra queryData->textBox = m_textBoxes.at(textBoxPosition); queryData->textRenderer = &queryData->textBox->renderer(); - queryData->isVerticalText = queryData->textRenderer->style().svgStyle().isVerticalWritingMode(); + queryData->isVerticalText = queryData->textRenderer->style().isVerticalWritingMode(); const Vector<SVGTextFragment>& fragments = queryData->textBox->textFragments(); // Loop over all text fragments in this text box, firing a callback for each. @@ -134,13 +134,15 @@ bool SVGTextQuery::executeQuery(Data* queryData, ProcessTextFragmentCallback fra return false; } -bool SVGTextQuery::mapStartEndPositionsIntoFragmentCoordinates(Data* queryData, const SVGTextFragment& fragment, int& startPosition, int& endPosition) const +bool SVGTextQuery::mapStartEndPositionsIntoFragmentCoordinates(Data* queryData, const SVGTextFragment& fragment, unsigned& startPosition, unsigned& endPosition) const { // Reuse the same logic used for text selection & painting, to map our query start/length into start/endPositions of the current text fragment. + ASSERT(startPosition >= queryData->processedCharacters); + ASSERT(endPosition >= queryData->processedCharacters); startPosition -= queryData->processedCharacters; endPosition -= queryData->processedCharacters; - if (startPosition >= endPosition || startPosition < 0 || endPosition < 0) + if (startPosition >= endPosition) return false; modifyStartEndPositionsRespectingLigatures(queryData, startPosition, endPosition); @@ -151,7 +153,7 @@ bool SVGTextQuery::mapStartEndPositionsIntoFragmentCoordinates(Data* queryData, return true; } -void SVGTextQuery::modifyStartEndPositionsRespectingLigatures(Data* queryData, int& startPosition, int& endPosition) const +void SVGTextQuery::modifyStartEndPositionsRespectingLigatures(Data* queryData, unsigned& startPosition, unsigned& endPosition) const { SVGTextLayoutAttributes* layoutAttributes = queryData->textRenderer->layoutAttributes(); Vector<SVGTextMetrics>& textMetricsValues = layoutAttributes->textMetricsValues(); @@ -167,7 +169,7 @@ void SVGTextQuery::modifyStartEndPositionsRespectingLigatures(Data* queryData, i bool alterStartPosition = true; bool alterEndPosition = true; - int lastPositionOffset = -1; + std::optional<unsigned> lastPositionOffset; for (; textMetricsOffset < textMetricsSize && positionOffset < positionSize; ++textMetricsOffset) { SVGTextMetrics& metrics = textMetricsValues[textMetricsOffset]; @@ -182,21 +184,21 @@ void SVGTextQuery::modifyStartEndPositionsRespectingLigatures(Data* queryData, i break; // If the start position maps to a character in the metrics list, we don't need to modify it. - if (startPosition == static_cast<int>(positionOffset)) + if (startPosition == positionOffset) alterStartPosition = false; // If the start position maps to a character in the metrics list, we don't need to modify it. - if (endPosition == static_cast<int>(positionOffset)) + if (endPosition == positionOffset) alterEndPosition = false; // Detect ligatures. - if (lastPositionOffset != -1 && lastPositionOffset - positionOffset > 1) { - if (alterStartPosition && startPosition > lastPositionOffset && startPosition < static_cast<int>(positionOffset)) { - startPosition = lastPositionOffset; + if (lastPositionOffset && lastPositionOffset.value() - positionOffset > 1) { + if (alterStartPosition && startPosition > lastPositionOffset.value() && startPosition < positionOffset) { + startPosition = lastPositionOffset.value(); alterStartPosition = false; } - if (alterEndPosition && endPosition > lastPositionOffset && endPosition < static_cast<int>(positionOffset)) { + if (alterEndPosition && endPosition > lastPositionOffset.value() && endPosition < positionOffset) { endPosition = positionOffset; alterEndPosition = false; } @@ -212,16 +214,12 @@ void SVGTextQuery::modifyStartEndPositionsRespectingLigatures(Data* queryData, i if (!alterStartPosition && !alterEndPosition) return; - if (lastPositionOffset != -1 && lastPositionOffset - positionOffset > 1) { - if (alterStartPosition && startPosition > lastPositionOffset && startPosition < static_cast<int>(positionOffset)) { - startPosition = lastPositionOffset; - alterStartPosition = false; - } + if (lastPositionOffset && lastPositionOffset.value() - positionOffset > 1) { + if (alterStartPosition && startPosition > lastPositionOffset.value() && startPosition < positionOffset) + startPosition = lastPositionOffset.value(); - if (alterEndPosition && endPosition > lastPositionOffset && endPosition < static_cast<int>(positionOffset)) { + if (alterEndPosition && endPosition > lastPositionOffset.value() && endPosition < positionOffset) endPosition = positionOffset; - alterEndPosition = false; - } } } @@ -288,12 +286,12 @@ bool SVGTextQuery::subStringLengthCallback(Data* queryData, const SVGTextFragmen { SubStringLengthData* data = static_cast<SubStringLengthData*>(queryData); - int startPosition = data->startPosition; - int endPosition = startPosition + data->length; + unsigned startPosition = data->startPosition; + unsigned endPosition = startPosition + data->length; if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition)) return false; - SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset + startPosition, endPosition - startPosition); + SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(*queryData->textRenderer, fragment.characterOffset + startPosition, endPosition - startPosition); data->subStringLength += queryData->isVerticalText ? metrics.height() : metrics.width(); return false; } @@ -323,15 +321,15 @@ bool SVGTextQuery::startPositionOfCharacterCallback(Data* queryData, const SVGTe { StartPositionOfCharacterData* data = static_cast<StartPositionOfCharacterData*>(queryData); - int startPosition = data->position; - int endPosition = startPosition + 1; + unsigned startPosition = data->position; + unsigned endPosition = startPosition + 1; if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition)) return false; data->startPosition = FloatPoint(fragment.x, fragment.y); if (startPosition) { - SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset, startPosition); + SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(*queryData->textRenderer, fragment.characterOffset, startPosition); if (queryData->isVerticalText) data->startPosition.move(0, metrics.height()); else @@ -347,10 +345,10 @@ bool SVGTextQuery::startPositionOfCharacterCallback(Data* queryData, const SVGTe return true; } -SVGPoint SVGTextQuery::startPositionOfCharacter(unsigned position) const +FloatPoint SVGTextQuery::startPositionOfCharacter(unsigned position) const { if (m_textBoxes.isEmpty()) - return SVGPoint(); + return { }; StartPositionOfCharacterData data(position); executeQuery(&data, &SVGTextQuery::startPositionOfCharacterCallback); @@ -372,14 +370,14 @@ bool SVGTextQuery::endPositionOfCharacterCallback(Data* queryData, const SVGText { EndPositionOfCharacterData* data = static_cast<EndPositionOfCharacterData*>(queryData); - int startPosition = data->position; - int endPosition = startPosition + 1; + unsigned startPosition = data->position; + unsigned endPosition = startPosition + 1; if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition)) return false; data->endPosition = FloatPoint(fragment.x, fragment.y); - SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset, startPosition + 1); + SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(*queryData->textRenderer, fragment.characterOffset, startPosition + 1); if (queryData->isVerticalText) data->endPosition.move(0, metrics.height()); else @@ -394,10 +392,10 @@ bool SVGTextQuery::endPositionOfCharacterCallback(Data* queryData, const SVGText return true; } -SVGPoint SVGTextQuery::endPositionOfCharacter(unsigned position) const +FloatPoint SVGTextQuery::endPositionOfCharacter(unsigned position) const { if (m_textBoxes.isEmpty()) - return SVGPoint(); + return { }; EndPositionOfCharacterData data(position); executeQuery(&data, &SVGTextQuery::endPositionOfCharacterCallback); @@ -420,8 +418,8 @@ bool SVGTextQuery::rotationOfCharacterCallback(Data* queryData, const SVGTextFra { RotationOfCharacterData* data = static_cast<RotationOfCharacterData*>(queryData); - int startPosition = data->position; - int endPosition = startPosition + 1; + unsigned startPosition = data->position; + unsigned endPosition = startPosition + 1; if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition)) return false; @@ -458,7 +456,7 @@ struct ExtentOfCharacterData : SVGTextQuery::Data { FloatRect extent; }; -static inline void calculateGlyphBoundaries(SVGTextQuery::Data* queryData, const SVGTextFragment& fragment, int startPosition, FloatRect& extent) +static inline void calculateGlyphBoundaries(SVGTextQuery::Data* queryData, const SVGTextFragment& fragment, unsigned startPosition, FloatRect& extent) { float scalingFactor = queryData->textRenderer->scalingFactor(); ASSERT(scalingFactor); @@ -466,14 +464,14 @@ static inline void calculateGlyphBoundaries(SVGTextQuery::Data* queryData, const extent.setLocation(FloatPoint(fragment.x, fragment.y - queryData->textRenderer->scaledFont().fontMetrics().floatAscent() / scalingFactor)); if (startPosition) { - SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset, startPosition); + SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(*queryData->textRenderer, fragment.characterOffset, startPosition); if (queryData->isVerticalText) extent.move(0, metrics.height()); else extent.move(metrics.width(), 0); } - SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(queryData->textRenderer, fragment.characterOffset + startPosition, 1); + SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(*queryData->textRenderer, fragment.characterOffset + startPosition, 1); extent.setSize(FloatSize(metrics.width(), metrics.height())); AffineTransform fragmentTransform; @@ -488,8 +486,8 @@ bool SVGTextQuery::extentOfCharacterCallback(Data* queryData, const SVGTextFragm { ExtentOfCharacterData* data = static_cast<ExtentOfCharacterData*>(queryData); - int startPosition = data->position; - int endPosition = startPosition + 1; + unsigned startPosition = data->position; + unsigned endPosition = startPosition + 1; if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition)) return false; @@ -523,8 +521,8 @@ bool SVGTextQuery::characterNumberAtPositionCallback(Data* queryData, const SVGT FloatRect extent; for (unsigned i = 0; i < fragment.length; ++i) { - int startPosition = data->processedCharacters + i; - int endPosition = startPosition + 1; + unsigned startPosition = data->processedCharacters + i; + unsigned endPosition = startPosition + 1; if (!mapStartEndPositionsIntoFragmentCoordinates(queryData, fragment, startPosition, endPosition)) continue; @@ -538,7 +536,7 @@ bool SVGTextQuery::characterNumberAtPositionCallback(Data* queryData, const SVGT return false; } -int SVGTextQuery::characterNumberAtPosition(const SVGPoint& position) const +int SVGTextQuery::characterNumberAtPosition(const FloatPoint& position) const { if (m_textBoxes.isEmpty()) return -1; @@ -551,5 +549,3 @@ int SVGTextQuery::characterNumberAtPosition(const SVGPoint& position) const } } - -#endif diff --git a/Source/WebCore/rendering/svg/SVGTextQuery.h b/Source/WebCore/rendering/svg/SVGTextQuery.h index bf60a6da6..3f09a76c9 100644 --- a/Source/WebCore/rendering/svg/SVGTextQuery.h +++ b/Source/WebCore/rendering/svg/SVGTextQuery.h @@ -17,12 +17,9 @@ * Boston, MA 02110-1301, USA. */ -#ifndef SVGTextQuery_h -#define SVGTextQuery_h +#pragma once -#if ENABLE(SVG) #include "FloatRect.h" -#include "SVGPoint.h" #include "SVGTextFragment.h" #include <wtf/Vector.h> @@ -39,11 +36,11 @@ public: unsigned numberOfCharacters() const; float textLength() const; float subStringLength(unsigned startPosition, unsigned length) const; - SVGPoint startPositionOfCharacter(unsigned position) const; - SVGPoint endPositionOfCharacter(unsigned position) const; + FloatPoint startPositionOfCharacter(unsigned position) const; + FloatPoint endPositionOfCharacter(unsigned position) const; float rotationOfCharacter(unsigned position) const; FloatRect extentOfCharacter(unsigned position) const; - int characterNumberAtPosition(const SVGPoint&) const; + int characterNumberAtPosition(const FloatPoint&) const; // Public helper struct. Private classes in SVGTextQuery inherit from it. struct Data; @@ -53,8 +50,8 @@ private: bool executeQuery(Data*, ProcessTextFragmentCallback) const; void collectTextBoxesInFlowBox(InlineFlowBox*); - bool mapStartEndPositionsIntoFragmentCoordinates(Data*, const SVGTextFragment&, int& startPosition, int& endPosition) const; - void modifyStartEndPositionsRespectingLigatures(Data*, int& startPosition, int& endPosition) const; + bool mapStartEndPositionsIntoFragmentCoordinates(Data*, const SVGTextFragment&, unsigned& startPosition, unsigned& endPosition) const; + void modifyStartEndPositionsRespectingLigatures(Data*, unsigned& startPosition, unsigned& endPosition) const; private: bool numberOfCharactersCallback(Data*, const SVGTextFragment&) const; @@ -70,7 +67,4 @@ private: Vector<SVGInlineTextBox*> m_textBoxes; }; -} - -#endif -#endif +} // namespace WebCore diff --git a/Source/WebCore/rendering/svg/SVGTextRunRenderingContext.cpp b/Source/WebCore/rendering/svg/SVGTextRunRenderingContext.cpp deleted file mode 100644 index 3b2561af8..000000000 --- a/Source/WebCore/rendering/svg/SVGTextRunRenderingContext.cpp +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org> - * Copyright (C) Research In Motion Limited 2010-2011. 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" - -#if ENABLE(SVG_FONTS) -#include "SVGTextRunRenderingContext.h" - -#include "GlyphBuffer.h" -#include "GraphicsContext.h" -#include "RenderObject.h" -#include "RenderSVGInlineText.h" -#include "RenderSVGResourceSolidColor.h" -#include "SVGFontData.h" -#include "SVGFontElement.h" -#include "SVGFontFaceElement.h" -#include "SVGGlyphElement.h" -#include "SVGNames.h" -#include "WidthIterator.h" - -namespace WebCore { - -static inline const SVGFontData* svgFontAndFontFaceElementForFontData(const SimpleFontData* fontData, SVGFontFaceElement*& fontFace, SVGFontElement*& font) -{ - ASSERT(fontData); - ASSERT(fontData->isCustomFont()); - ASSERT(fontData->isSVGFont()); - - const SVGFontData* svgFontData = static_cast<const SVGFontData*>(fontData->fontData()); - - fontFace = svgFontData->svgFontFaceElement(); - ASSERT(fontFace); - - font = fontFace->associatedFontElement(); - return svgFontData; -} - -float SVGTextRunRenderingContext::floatWidthUsingSVGFont(const Font& font, const TextRun& run, int& charsConsumed, String& glyphName) const -{ - WidthIterator it(&font, run); - GlyphBuffer glyphBuffer; - charsConsumed += it.advance(run.length(), &glyphBuffer); - glyphName = it.lastGlyphName(); - return it.runWidthSoFar(); -} - -bool SVGTextRunRenderingContext::applySVGKerning(const SimpleFontData* fontData, WidthIterator& iterator, GlyphBuffer* glyphBuffer, int from) const -{ - ASSERT(glyphBuffer); - ASSERT(glyphBuffer->size() > 1); - SVGFontElement* fontElement = 0; - SVGFontFaceElement* fontFaceElement = 0; - - svgFontAndFontFaceElementForFontData(fontData, fontFaceElement, fontElement); - if (!fontElement || !fontFaceElement) - return false; - - float scale = scaleEmToUnits(fontData->platformData().size(), fontFaceElement->unitsPerEm()); - - String lastGlyphName; - String lastUnicodeString; - int characterOffset = iterator.m_currentCharacter; - String text = iterator.run().string(); - const int glyphCount = glyphBuffer->size() - from; - GlyphBufferAdvance* advances = glyphBuffer->advances(from); - - for (int i = 0; i < glyphCount; ++i) { - Glyph glyph = glyphBuffer->glyphAt(from + i); - if (!glyph) - continue; - float kerning = 0; - SVGGlyph svgGlyph = fontElement->svgGlyphForGlyph(glyph); - String unicodeString = text.substring(characterOffset, svgGlyph.unicodeStringLength); - if (i >= 1) { - // FIXME: Support vertical text. - kerning = fontElement->horizontalKerningForPairOfStringsAndGlyphs(lastUnicodeString, lastGlyphName, unicodeString, svgGlyph.glyphName); - advances[i - 1].setWidth(advances[i - 1].width() - kerning * scale); - } - lastGlyphName = svgGlyph.glyphName; - lastUnicodeString = unicodeString; - characterOffset += svgGlyph.unicodeStringLength; - } - - return true; -} - -void SVGTextRunRenderingContext::drawSVGGlyphs(GraphicsContext* context, const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer, int from, int numGlyphs, const FloatPoint& point) const -{ - SVGFontElement* fontElement = 0; - SVGFontFaceElement* fontFaceElement = 0; - - const SVGFontData* svgFontData = svgFontAndFontFaceElementForFontData(fontData, fontFaceElement, fontElement); - if (!fontElement || !fontFaceElement) - return; - - auto activePaintingResource = this->activePaintingResource(); - if (!activePaintingResource) { - // TODO: We're only supporting simple filled HTML text so far. - RenderSVGResourceSolidColor* solidPaintingResource = RenderSVGResource::sharedSolidPaintingResource(); - solidPaintingResource->setColor(context->fillColor()); - activePaintingResource = solidPaintingResource; - } - - auto& elementRenderer = renderer().isRenderElement() ? toRenderElement(renderer()) : *renderer().parent(); - RenderStyle& style = elementRenderer.style(); - bool isVerticalText = style.svgStyle().isVerticalWritingMode(); - - float scale = scaleEmToUnits(fontData->platformData().size(), fontFaceElement->unitsPerEm()); - ASSERT(activePaintingResource); - - FloatPoint glyphOrigin; - glyphOrigin.setX(svgFontData->horizontalOriginX() * scale); - glyphOrigin.setY(svgFontData->horizontalOriginY() * scale); - - FloatPoint currentPoint = point; - RenderSVGResourceMode resourceMode = context->textDrawingMode() == TextModeStroke ? ApplyToStrokeMode : ApplyToFillMode; - for (int i = 0; i < numGlyphs; ++i) { - Glyph glyph = glyphBuffer.glyphAt(from + i); - if (!glyph) - continue; - - float advance = glyphBuffer.advanceAt(from + i).width(); - SVGGlyph svgGlyph = fontElement->svgGlyphForGlyph(glyph); - ASSERT(!svgGlyph.isPartOfLigature); - ASSERT(svgGlyph.tableEntry == glyph); - - SVGGlyphElement::inheritUnspecifiedAttributes(svgGlyph, svgFontData); - - // FIXME: Support arbitary SVG content as glyph (currently limited to <glyph d="..."> situations). - if (svgGlyph.pathData.isEmpty()) { - if (isVerticalText) - currentPoint.move(0, advance); - else - currentPoint.move(advance, 0); - continue; - } - - if (isVerticalText) { - glyphOrigin.setX(svgGlyph.verticalOriginX * scale); - glyphOrigin.setY(svgGlyph.verticalOriginY * scale); - } - - AffineTransform glyphPathTransform; - glyphPathTransform.translate(currentPoint.x() + glyphOrigin.x(), currentPoint.y() + glyphOrigin.y()); - glyphPathTransform.scale(scale, -scale); - - Path glyphPath = svgGlyph.pathData; - glyphPath.transform(glyphPathTransform); - - if (activePaintingResource->applyResource(elementRenderer, style, context, resourceMode)) { - float strokeThickness = context->strokeThickness(); - if (renderer().isSVGInlineText()) - context->setStrokeThickness(strokeThickness * toRenderSVGInlineText(renderer()).scalingFactor()); - activePaintingResource->postApplyResource(elementRenderer, context, resourceMode, &glyphPath, 0); - context->setStrokeThickness(strokeThickness); - } - - if (isVerticalText) - currentPoint.move(0, advance); - else - currentPoint.move(advance, 0); - } -} - -GlyphData SVGTextRunRenderingContext::glyphDataForCharacter(const Font& font, WidthIterator& iterator, UChar32 character, bool mirror, int currentCharacter, unsigned& advanceLength) -{ - const SimpleFontData* primaryFont = font.primaryFont(); - ASSERT(primaryFont); - - std::pair<GlyphData, GlyphPage*> pair = font.glyphDataAndPageForCharacter(character, mirror, AutoVariant); - GlyphData glyphData = pair.first; - - // Check if we have the missing glyph data, in which case we can just return. - GlyphData missingGlyphData = primaryFont->missingGlyphData(); - if (glyphData.glyph == missingGlyphData.glyph && glyphData.fontData == missingGlyphData.fontData) { - ASSERT(glyphData.fontData); - return glyphData; - } - - // Save data fromt he font fallback list because we may modify it later. Do this before the - // potential change to glyphData.fontData below. - FontGlyphs* glyph = font.glyphs(); - ASSERT(glyph); - FontGlyphs::GlyphPagesStateSaver glyphPagesSaver(*glyph); - - // Characters enclosed by an <altGlyph> element, may not be registered in the GlyphPage. - const SimpleFontData* originalFontData = glyphData.fontData; - if (glyphData.fontData && !glyphData.fontData->isSVGFont()) { - auto& elementRenderer = renderer().isRenderElement() ? toRenderElement(renderer()) : *renderer().parent(); - if (Element* parentRendererElement = elementRenderer.element()) { - if (parentRendererElement->hasTagName(SVGNames::altGlyphTag)) - glyphData.fontData = primaryFont; - } - } - - const SimpleFontData* fontData = glyphData.fontData; - if (fontData) { - if (!fontData->isSVGFont()) - return glyphData; - - SVGFontElement* fontElement = 0; - SVGFontFaceElement* fontFaceElement = 0; - - const SVGFontData* svgFontData = svgFontAndFontFaceElementForFontData(fontData, fontFaceElement, fontElement); - if (!fontElement || !fontFaceElement) - return glyphData; - - // If we got here, we're dealing with a glyph defined in a SVG Font. - // The returned glyph by glyphDataAndPageForCharacter() is a glyph stored in the SVG Font glyph table. - // This doesn't necessarily mean the glyph is suitable for rendering/measuring in this context, its - // arabic-form/orientation/... may not match, we have to apply SVG Glyph selection to discover that. - if (svgFontData->applySVGGlyphSelection(iterator, glyphData, mirror, currentCharacter, advanceLength)) - return glyphData; - } - - GlyphPage* page = pair.second; - ASSERT(page); - - // No suitable glyph found that is compatible with the requirments (same language, arabic-form, orientation etc.) - // Even though our GlyphPage contains an entry for eg. glyph "a", it's not compatible. So we have to temporarily - // remove the glyph data information from the GlyphPage, and retry the lookup, which handles font fallbacks correctly. - page->setGlyphDataForCharacter(character, 0, 0); - - // Assure that the font fallback glyph selection worked, aka. the fallbackGlyphData font data is not the same as before. - GlyphData fallbackGlyphData = font.glyphDataForCharacter(character, mirror); - ASSERT(fallbackGlyphData.fontData != fontData); - - // Restore original state of the SVG Font glyph table and the current font fallback list, - // to assure the next lookup of the same glyph won't immediately return the fallback glyph. - page->setGlyphDataForCharacter(character, glyphData.glyph, originalFontData); - ASSERT(fallbackGlyphData.fontData); - return fallbackGlyphData; -} - -} - -#endif diff --git a/Source/WebCore/rendering/svg/SVGTextRunRenderingContext.h b/Source/WebCore/rendering/svg/SVGTextRunRenderingContext.h deleted file mode 100644 index e1270c19e..000000000 --- a/Source/WebCore/rendering/svg/SVGTextRunRenderingContext.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) Research In Motion Limited 2011. 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. - * - */ - -#ifndef SVGTextRunRenderingContext_h -#define SVGTextRunRenderingContext_h - -#include "Font.h" -#include "TextRun.h" - -namespace WebCore { - -class RenderObject; -class RenderSVGResource; - -class SVGTextRunRenderingContext final : public TextRun::RenderingContext { -public: - static PassRef<SVGTextRunRenderingContext> create(RenderObject& renderer) - { - return adoptRef(*new SVGTextRunRenderingContext(renderer)); - } - - RenderObject& renderer() const { return m_renderer; } - -#if ENABLE(SVG_FONTS) - RenderSVGResource* activePaintingResource() const { return m_activePaintingResource; } - void setActivePaintingResource(RenderSVGResource* object) { m_activePaintingResource = object; } - - virtual GlyphData glyphDataForCharacter(const Font&, WidthIterator&, UChar32 character, bool mirror, int currentCharacter, unsigned& advanceLength) override; - virtual void drawSVGGlyphs(GraphicsContext*, const SimpleFontData*, const GlyphBuffer&, int from, int to, const FloatPoint&) const override; - virtual float floatWidthUsingSVGFont(const Font&, const TextRun&, int& charsConsumed, String& glyphName) const override; - virtual bool applySVGKerning(const SimpleFontData*, WidthIterator&, GlyphBuffer*, int from) const override; -#endif - -private: - SVGTextRunRenderingContext(RenderObject& renderer) - : m_renderer(renderer) -#if ENABLE(SVG_FONTS) - , m_activePaintingResource(0) -#endif - { - } - - virtual ~SVGTextRunRenderingContext() { } - - RenderObject& m_renderer; - -#if ENABLE(SVG_FONTS) - RenderSVGResource* m_activePaintingResource; -#endif -}; - -} // namespace WebCore - -#endif // SVGTextRunRenderingContext_h |