feTurbulence is not rendered correctly on Retina display
[WebKit-https.git] / Source / WebCore / platform / graphics / filters / FETurbulence.cpp
index 6019876..4d0ded4 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
  * Copyright (C) 2010 Renata Hodovan <reni@inf.u-szeged.hu>
  * Copyright (C) 2011 Gabor Loki <loki@webkit.org>
- * Copyright (C) 2017 Apple Inc.
+ * Copyright (C) 2017-2018 Apple Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
 #include "FETurbulence.h"
 
 #include "Filter.h"
-#include <wtf/text/TextStream.h>
-
-#include <runtime/Uint8ClampedArray.h>
+#include <JavaScriptCore/Uint8ClampedArray.h>
 #include <wtf/MathExtras.h>
 #include <wtf/ParallelJobs.h>
+#include <wtf/text/TextStream.h>
 
 namespace WebCore {
 
@@ -366,9 +365,12 @@ ColorComponents FETurbulence::calculateTurbulenceValueForPoint(const PaintingDat
     return toColorComponents(turbulenceFunctionResult);
 }
 
-void FETurbulence::fillRegion(Uint8ClampedArray* pixelArray, const PaintingData& paintingData, StitchData stitchData, int startY, int endY) const
+void FETurbulence::fillRegion(Uint8ClampedArray& pixelArray, const PaintingData& paintingData, StitchData stitchData, int startY, int endY) const
 {
+    ASSERT(endY > startY);
+
     IntRect filterRegion = absolutePaintRect();
+    filterRegion.scale(filter().filterScale());
     FloatPoint point(0, filterRegion.y() + startY);
     int indexOfPixelChannel = startY * (filterRegion.width() << 2);
     AffineTransform inverseTransfrom = filter().absoluteTransform().inverse().value_or(AffineTransform());
@@ -380,17 +382,15 @@ void FETurbulence::fillRegion(Uint8ClampedArray* pixelArray, const PaintingData&
             point.setX(point.x() + 1);
             FloatPoint localPoint = inverseTransfrom.mapPoint(point);
             ColorComponents values = calculateTurbulenceValueForPoint(paintingData, stitchData, localPoint);
-            pixelArray->set(indexOfPixelChannel++, values.components[0]);
-            pixelArray->set(indexOfPixelChannel++, values.components[1]);
-            pixelArray->set(indexOfPixelChannel++, values.components[2]);
-            pixelArray->set(indexOfPixelChannel++, values.components[3]);
+            pixelArray.setRange(values.components, 4, indexOfPixelChannel);
+            indexOfPixelChannel += 4;
         }
     }
 }
 
 void FETurbulence::fillRegionWorker(FillRegionParameters* parameters)
 {
-    parameters->filter->fillRegion(parameters->pixelArray, *parameters->paintingData, parameters->stitchData, parameters->startY, parameters->endY);
+    parameters->filter->fillRegion(*parameters->pixelArray, *parameters->paintingData, parameters->stitchData, parameters->startY, parameters->endY);
 }
 
 void FETurbulence::platformApplySoftware()
@@ -399,7 +399,10 @@ void FETurbulence::platformApplySoftware()
     if (!pixelArray)
         return;
 
-    if (absolutePaintRect().isEmpty()) {
+    IntSize resultSize(absolutePaintRect().size());
+    resultSize.scale(filter().filterScale());
+
+    if (resultSize.isEmpty()) {
         pixelArray->zeroFill();
         return;
     }
@@ -413,46 +416,48 @@ void FETurbulence::platformApplySoftware()
     PaintingData paintingData(m_seed, tileSize, baseFrequencyX, baseFrequencyY);
     initPaint(paintingData);
 
-    int optimalThreadNumber = (absolutePaintRect().width() * absolutePaintRect().height()) / s_minimalRectDimension;
+    auto area = resultSize.area();
+    if (area.hasOverflowed())
+        return;
+
+    int height = resultSize.height();
+
+    unsigned maxNumThreads = height / 8;
+    unsigned optimalThreadNumber = std::min<unsigned>(area.unsafeGet() / s_minimalRectDimension, maxNumThreads);
     if (optimalThreadNumber > 1) {
-        // Initialize parallel jobs
         WTF::ParallelJobs<FillRegionParameters> parallelJobs(&WebCore::FETurbulence::fillRegionWorker, optimalThreadNumber);
 
         // Fill the parameter array
-        int i = parallelJobs.numberOfJobs();
-        if (i > 1) {
-            // Split the job into "stepY"-sized jobs but there a few jobs that need to be slightly larger since
-            // stepY * jobs < total size. These extras are handled by the remainder "jobsWithExtra".
-            const int stepY = absolutePaintRect().height() / i;
-            const int jobsWithExtra = absolutePaintRect().height() % i;
-
-            int startY = 0;
-            for (; i > 0; --i) {
-                FillRegionParameters& params = parallelJobs.parameter(i - 1);
+        auto numJobs = parallelJobs.numberOfJobs();
+        if (numJobs > 1) {
+            // Split the job into "stepY"-sized jobs, distributing the extra rows into the first "jobsWithExtra" jobs.
+            unsigned stepY = height / numJobs;
+            unsigned jobsWithExtra = height % numJobs;
+            unsigned startY = 0;
+
+            for (unsigned i = 0; i < numJobs; ++i) {
+                FillRegionParameters& params = parallelJobs.parameter(i);
                 params.filter = this;
                 params.pixelArray = pixelArray;
                 params.paintingData = &paintingData;
                 params.stitchData = stitchData;
                 params.startY = startY;
-                startY += i < jobsWithExtra ? stepY + 1 : stepY;
-                params.endY = startY;
+
+                unsigned jobHeight = (i < jobsWithExtra) ? stepY + 1 : stepY;
+                params.endY = params.startY + jobHeight;
+                startY += jobHeight;
             }
 
-            // Execute parallel jobs
             parallelJobs.execute();
             return;
         }
     }
 
     // Fallback to single threaded mode if there is no room for a new thread or the paint area is too small.
-    fillRegion(pixelArray, paintingData, stitchData, 0, absolutePaintRect().height());
-}
-
-void FETurbulence::dump()
-{
+    fillRegion(*pixelArray, paintingData, stitchData, 0, height);
 }
 
-static TextStream& operator<<(TextStream& ts, const TurbulenceType& type)
+static TextStream& operator<<(TextStream& ts, TurbulenceType type)
 {
     switch (type) {
     case TurbulenceType::Unknown:
@@ -468,11 +473,10 @@ static TextStream& operator<<(TextStream& ts, const TurbulenceType& type)
     return ts;
 }
 
-TextStream& FETurbulence::externalRepresentation(TextStream& ts, int indent) const
+TextStream& FETurbulence::externalRepresentation(TextStream& ts, RepresentationType representation) const
 {
-    writeIndent(ts, indent);
-    ts << "[feTurbulence";
-    FilterEffect::externalRepresentation(ts);
+    ts << indent << "[feTurbulence";
+    FilterEffect::externalRepresentation(ts, representation);
     ts << " type=\"" << type() << "\" "
        << "baseFrequency=\"" << baseFrequencyX() << ", " << baseFrequencyY() << "\" "
        << "seed=\"" << seed() << "\" "