Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / rendering / svg / RenderSVGResourceGradient.cpp
index 5ad5d84..a16c909 100644 (file)
  */
 
 #include "config.h"
-
-#if ENABLE(SVG)
 #include "RenderSVGResourceGradient.h"
 
 #include "GradientAttributes.h"
 #include "GraphicsContext.h"
 #include "RenderSVGText.h"
-#include "SVGImageBufferTools.h"
-#include "SVGRenderSupport.h"
-#include <wtf/UnusedParam.h>
+#include "SVGRenderingContext.h"
 
 namespace WebCore {
 
-RenderSVGResourceGradient::RenderSVGResourceGradient(SVGGradientElement* node)
-    : RenderSVGResourceContainer(node)
+RenderSVGResourceGradient::RenderSVGResourceGradient(SVGGradientElement& node, Ref<RenderStyle>&& style)
+    : RenderSVGResourceContainer(node, WTFMove(style))
     , m_shouldCollectGradientAttributes(true)
-#if PLATFORM(CG)
+#if USE(CG)
     , m_savedContext(0)
 #endif
 {
 }
 
-RenderSVGResourceGradient::~RenderSVGResourceGradient()
-{
-    if (m_gradient.isEmpty())
-        return;
-
-    deleteAllValues(m_gradient);
-    m_gradient.clear();
-}
-
 void RenderSVGResourceGradient::removeAllClientsFromCache(bool markForInvalidation)
 {
-    if (!m_gradient.isEmpty()) {
-        deleteAllValues(m_gradient);
-        m_gradient.clear();
-    }
-
+    m_gradientMap.clear();
     m_shouldCollectGradientAttributes = true;
     markAllClientsForInvalidation(markForInvalidation ? RepaintInvalidation : ParentOnlyInvalidation);
 }
 
-void RenderSVGResourceGradient::removeClientFromCache(RenderObject* client, bool markForInvalidation)
+void RenderSVGResourceGradient::removeClientFromCache(RenderElement& client, bool markForInvalidation)
 {
-    ASSERT(client);
-
-    if (m_gradient.contains(client))
-        delete m_gradient.take(client);
-
+    m_gradientMap.remove(&client);
     markClientForInvalidation(client, markForInvalidation ? RepaintInvalidation : ParentOnlyInvalidation);
 }
 
-#if PLATFORM(CG)
-static inline bool createMaskAndSwapContextForTextGradient(GraphicsContext*& context,
-                                                           GraphicsContext*& savedContext,
-                                                           OwnPtr<ImageBuffer>& imageBuffer,
-                                                           RenderObject* object)
+#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;
-    SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(textRootBlock, absoluteTransform);
-
-    FloatRect absoluteTargetRect = absoluteTransform.mapRect(textRootBlock->repaintRectInLocalCoordinates());
-    FloatRect clampedAbsoluteTargetRect = SVGImageBufferTools::clampedAbsoluteTargetRectForRenderer(textRootBlock, absoluteTargetRect);
-    if (clampedAbsoluteTargetRect.isEmpty())
-        return false;
+    AffineTransform absoluteTransform = SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(*textRootBlock);
+    FloatRect repaintRect = textRootBlock->repaintRectInLocalCoordinates();
 
-    OwnPtr<ImageBuffer> maskImage;
-    if (!SVGImageBufferTools::createImageBuffer(absoluteTargetRect, clampedAbsoluteTargetRect, maskImage, ColorSpaceDeviceRGB))
+    auto maskImage = SVGRenderingContext::createImageBuffer(repaintRect, absoluteTransform, ColorSpaceSRGB, context->renderingMode());
+    if (!maskImage)
         return false;
 
-    GraphicsContext* maskImageContext = maskImage->context();
-    ASSERT(maskImageContext);
-
-    maskImageContext->translate(-clampedAbsoluteTargetRect.x(), -clampedAbsoluteTargetRect.y());
-    maskImageContext->concatCTM(absoluteTransform);
-
+    GraphicsContext& maskImageContext = maskImage->context();
     ASSERT(maskImage);
     savedContext = context;
-    context = maskImageContext;
-    imageBuffer = maskImage.release();
+    context = &maskImageContext;
+    imageBuffer = WTFMove(maskImage);
     return true;
 }
 
-static inline AffineTransform clipToTextMask(GraphicsContext* context,
-                                             OwnPtr<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);
 
-    targetRect = textRootBlock->repaintRectInLocalCoordinates();
-
-    AffineTransform absoluteTransform;
-    SVGImageBufferTools::calculateTransformationToOutermostSVGCoordinateSystem(textRootBlock, absoluteTransform);
+    AffineTransform absoluteTransform = SVGRenderingContext::calculateTransformationToOutermostCoordinateSystem(*textRootBlock);
 
-    FloatRect absoluteTargetRect = absoluteTransform.mapRect(targetRect);
-    FloatRect clampedAbsoluteTargetRect = SVGImageBufferTools::clampedAbsoluteTargetRectForRenderer(textRootBlock, absoluteTargetRect);
+    targetRect = textRootBlock->repaintRectInLocalCoordinates();
 
-    SVGImageBufferTools::clipToImageBuffer(context, absoluteTransform, clampedAbsoluteTargetRect, imageBuffer);
+    SVGRenderingContext::clipToImageBuffer(context, absoluteTransform, targetRect, imageBuffer, false);
 
     AffineTransform matrix;
     if (boundingBoxMode) {
@@ -133,15 +90,13 @@ static inline AffineTransform clipToTextMask(GraphicsContext* context,
         matrix.translate(maskBoundingBox.x(), maskBoundingBox.y());
         matrix.scaleNonUniform(maskBoundingBox.width(), maskBoundingBox.height());
     }
-    matrix.multLeft(gradientTransform);
+    matrix *= gradientTransform;
     return matrix;
 }
 #endif
 
-bool RenderSVGResourceGradient::applyResource(RenderObject* object, RenderStyle* style, GraphicsContext*& context, unsigned short resourceMode)
+bool RenderSVGResourceGradient::applyResource(RenderElement& renderer, const RenderStyle& style, GraphicsContext*& context, unsigned short resourceMode)
 {
-    ASSERT(object);
-    ASSERT(style);
     ASSERT(context);
     ASSERT(resourceMode != ApplyToDefaultMode);
 
@@ -149,39 +104,37 @@ bool RenderSVGResourceGradient::applyResource(RenderObject* object, RenderStyle*
     // Otherwhise the call to collectGradientAttributes() in createTileImage(), may cause the SVG DOM property
     // synchronization to kick in, which causes removeAllClientsFromCache() to be called, which in turn deletes our
     // GradientData object! Leaving out the line below will cause svg/dynamic-updates/SVG*GradientElement-svgdom* to crash.
-    SVGGradientElement* gradientElement = static_cast<SVGGradientElement*>(node());
-    if (!gradientElement)
-        return false;
-
     if (m_shouldCollectGradientAttributes) {
-        gradientElement->updateAnimatedSVGAttribute(anyQName());
-        collectGradientAttributes(gradientElement);
+        gradientElement().synchronizeAnimatedSVGAttribute(anyQName());
+        if (!collectGradientAttributes())
+            return false;
+
         m_shouldCollectGradientAttributes = 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 = object->objectBoundingBox();
-    if (boundingBoxMode() && objectBoundingBox.isEmpty())
+    FloatRect objectBoundingBox = renderer.objectBoundingBox();
+    if (gradientUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX && objectBoundingBox.isEmpty())
         return false;
 
-    if (!m_gradient.contains(object))
-        m_gradient.set(object, new GradientData);
+    auto& gradientData = m_gradientMap.add(&renderer, nullptr).iterator->value;
+    if (!gradientData)
+        gradientData = std::make_unique<GradientData>();
 
-    GradientData* gradientData = m_gradient.get(object);
     bool isPaintingText = resourceMode & ApplyToTextMode;
 
     // Create gradient object
     if (!gradientData->gradient) {
-        buildGradient(gradientData, gradientElement);
+        buildGradient(gradientData.get());
 
         // CG platforms will handle the gradient space transform for text after applying the
         // resource, so don't apply it here. For non-CG platforms, we want the text bounding
         // box applied to the gradient space transform now, so the gradient shader can use it.
-#if PLATFORM(CG)
-        if (boundingBoxMode() && !objectBoundingBox.isEmpty() && !isPaintingText) {
+#if USE(CG)
+        if (gradientUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX && !objectBoundingBox.isEmpty() && !isPaintingText) {
 #else
-        if (boundingBoxMode() && !objectBoundingBox.isEmpty()) {
+        if (gradientUnits() == SVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX && !objectBoundingBox.isEmpty()) {
 #endif
             gradientData->userspaceTransform.translate(objectBoundingBox.x(), objectBoundingBox.y());
             gradientData->userspaceTransform.scaleNonUniform(objectBoundingBox.width(), objectBoundingBox.height());
@@ -190,7 +143,14 @@ bool RenderSVGResourceGradient::applyResource(RenderObject* object, RenderStyle*
         AffineTransform gradientTransform;
         calculateGradientTransform(gradientTransform);
 
-        gradientData->userspaceTransform.multLeft(gradientTransform);
+        gradientData->userspaceTransform *= gradientTransform;
+        if (isPaintingText) {
+            // 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))
+                gradientData->userspaceTransform *= additionalTextTransform;
+        }
         gradientData->gradient->setGradientSpaceTransform(gradientData->userspaceTransform);
     }
 
@@ -201,8 +161,8 @@ bool RenderSVGResourceGradient::applyResource(RenderObject* object, RenderStyle*
     context->save();
 
     if (isPaintingText) {
-#if PLATFORM(CG)
-        if (!createMaskAndSwapContextForTextGradient(context, m_savedContext, m_imageBuffer, object)) {
+#if USE(CG)
+        if (!createMaskAndSwapContextForTextGradient(context, m_savedContext, m_imageBuffer, &renderer)) {
             context->restore();
             return false;
         }
@@ -211,35 +171,33 @@ bool RenderSVGResourceGradient::applyResource(RenderObject* object, RenderStyle*
         context->setTextDrawingMode(resourceMode & ApplyToFillMode ? TextModeFill : TextModeStroke);
     }
 
-    const SVGRenderStyle* svgStyle = style->svgStyle();
-    ASSERT(svgStyle);
+    const SVGRenderStyle& svgStyle = style.svgStyle();
 
     if (resourceMode & ApplyToFillMode) {
-        context->setAlpha(svgStyle->fillOpacity());
-        context->setFillGradient(gradientData->gradient);
-        context->setFillRule(svgStyle->fillRule());
+        context->setAlpha(svgStyle.fillOpacity());
+        context->setFillGradient(*gradientData->gradient);
+        context->setFillRule(svgStyle.fillRule());
     } else if (resourceMode & ApplyToStrokeMode) {
-        if (svgStyle->vectorEffect() == VE_NON_SCALING_STROKE)
-            gradientData->gradient->setGradientSpaceTransform(transformOnNonScalingStroke(object, gradientData->userspaceTransform));
-        context->setAlpha(svgStyle->strokeOpacity());
-        context->setStrokeGradient(gradientData->gradient);
-        SVGRenderSupport::applyStrokeStyleToContext(context, style, object);
+        if (svgStyle.vectorEffect() == VE_NON_SCALING_STROKE)
+            gradientData->gradient->setGradientSpaceTransform(transformOnNonScalingStroke(&renderer, gradientData->userspaceTransform));
+        context->setAlpha(svgStyle.strokeOpacity());
+        context->setStrokeGradient(*gradientData->gradient);
+        SVGRenderSupport::applyStrokeStyleToContext(context, style, renderer);
     }
 
     return true;
 }
 
-void RenderSVGResourceGradient::postApplyResource(RenderObject* object, GraphicsContext*& context, unsigned short resourceMode, const Path* path)
+void RenderSVGResourceGradient::postApplyResource(RenderElement& renderer, GraphicsContext*& context, unsigned short resourceMode, const Path* path, const RenderSVGShape* shape)
 {
     ASSERT(context);
     ASSERT(resourceMode != ApplyToDefaultMode);
 
     if (resourceMode & ApplyToTextMode) {
-#if PLATFORM(CG)
+#if USE(CG)
         // CG requires special handling for gradient on text
-        if (m_savedContext && m_gradient.contains(object)) {
-            GradientData* gradientData = m_gradient.get(object);
-
+        GradientData* gradientData;
+        if (m_savedContext && (gradientData = m_gradientMap.get(&renderer))) {
             // Restore on-screen drawing context
             context = m_savedContext;
             m_savedContext = 0;
@@ -248,20 +206,28 @@ void RenderSVGResourceGradient::postApplyResource(RenderObject* object, Graphics
             calculateGradientTransform(gradientTransform);
 
             FloatRect targetRect;
-            gradientData->gradient->setGradientSpaceTransform(clipToTextMask(context, m_imageBuffer, targetRect, object, boundingBoxMode(), 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.clear();
+            m_imageBuffer.reset();
         }
 #else
-        UNUSED_PARAM(object);
+        UNUSED_PARAM(renderer);
 #endif
-    } else if (path) {
-        if (resourceMode & ApplyToFillMode)
-            context->fillPath(*path);
-        else if (resourceMode & ApplyToStrokeMode)
-            context->strokePath(*path);
+    } else {
+        if (resourceMode & ApplyToFillMode) {
+            if (path)
+                context->fillPath(*path);
+            else if (shape)
+                shape->fillShape(*context);
+        }
+        if (resourceMode & ApplyToStrokeMode) {
+            if (path)
+                context->strokePath(*path);
+            else if (shape)
+                shape->strokeShape(*context);
+        }
     }
 
     context->restore();
@@ -276,6 +242,20 @@ void RenderSVGResourceGradient::addStops(GradientData* gradientData, const Vecto
         gradientData->gradient->addColorStop(*it);
 }
 
+GradientSpreadMethod RenderSVGResourceGradient::platformSpreadMethodFromSVGType(SVGSpreadMethodType method) const
+{
+    switch (method) {
+    case SVGSpreadMethodUnknown:
+    case SVGSpreadMethodPad:
+        return SpreadMethodPad;
+    case SVGSpreadMethodReflect:
+        return SpreadMethodReflect;
+    case SVGSpreadMethodRepeat:
+        return SpreadMethodRepeat;
+    }
+
+    ASSERT_NOT_REACHED();
+    return SpreadMethodPad;
 }
 
-#endif
+}