15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2010 Renata Hodovan <reni@inf.u-szeged.hu>
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2011 Gabor Loki <loki@webkit.org>
853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) * Copyright (C) 2013 Google Inc. All rights reserved.
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * This library is free software; you can redistribute it and/or
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modify it under the terms of the GNU Library General Public
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * License as published by the Free Software Foundation; either
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * version 2 of the License, or (at your option) any later version.
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * This library is distributed in the hope that it will be useful,
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * but WITHOUT ANY WARRANTY; without even the implied warranty of
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Library General Public License for more details.
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * You should have received a copy of the GNU Library General Public License
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * along with this library; see the file COPYING.LIB.  If not, write to
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Boston, MA 02110-1301, USA.
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h"
27a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)#include "platform/graphics/filters/FETurbulence.h"
285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
29521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)#include "SkPerlinNoiseShader.h"
30521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)#include "SkRectShaderImageFilter.h"
31a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)#include "platform/graphics/filters/ParallelJobs.h"
32a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles)#include "platform/graphics/filters/SkiaImageFilterBuilder.h"
331e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "platform/text/TextStream.h"
347757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#include "wtf/MathExtras.h"
357757ec2eadfa2dd8ac2aeed0a4399e9b07ec38cbBen Murdoch#include "wtf/Uint8ClampedArray.h"
365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
37c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)namespace blink {
385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Produces results in the range [1, 2**31 - 2]. Algorithm is:
415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    r = (a * r) mod m where a = randAmplitude = 16807 and
425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m = randMaximum = 2**31 - 1 = 2147483647, r = seed.
435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    See [Park & Miller], CACM vol. 31 no. 10 p. 1195, Oct. 1988
445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    To test: the algorithm should produce the result 1043618065
455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    as the 10,000th generated number if the original seed is 1.
465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)*/
475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static const int s_perlinNoise = 4096;
485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static const long s_randMaximum = 2147483647; // 2**31 - 1
495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static const int s_randAmplitude = 16807; // 7**5; primitive root of m
505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static const int s_randQ = 127773; // m / a
515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static const int s_randR = 2836; // m % a
525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)FETurbulence::FETurbulence(Filter* filter, TurbulenceType type, float baseFrequencyX, float baseFrequencyY, int numOctaves, float seed, bool stitchTiles)
545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    : FilterEffect(filter)
555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_type(type)
565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_baseFrequencyX(baseFrequencyX)
575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_baseFrequencyY(baseFrequencyY)
585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_numOctaves(numOctaves)
595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_seed(seed)
605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_stitchTiles(stitchTiles)
615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)PassRefPtr<FETurbulence> FETurbulence::create(Filter* filter, TurbulenceType type, float baseFrequencyX, float baseFrequencyY, int numOctaves, float seed, bool stitchTiles)
655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return adoptRef(new FETurbulence(filter, type, baseFrequencyX, baseFrequencyY, numOctaves, seed, stitchTiles));
675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)TurbulenceType FETurbulence::type() const
705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return m_type;
725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool FETurbulence::setType(TurbulenceType type)
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_type == type)
775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_type = type;
795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)float FETurbulence::baseFrequencyY() const
835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return m_baseFrequencyY;
855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool FETurbulence::setBaseFrequencyY(float baseFrequencyY)
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_baseFrequencyY == baseFrequencyY)
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_baseFrequencyY = baseFrequencyY;
925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)float FETurbulence::baseFrequencyX() const
965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return m_baseFrequencyX;
985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool FETurbulence::setBaseFrequencyX(float baseFrequencyX)
1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_baseFrequencyX == baseFrequencyX)
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
1045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_baseFrequencyX = baseFrequencyX;
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)float FETurbulence::seed() const
1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
11002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch    return m_seed;
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool FETurbulence::setSeed(float seed)
1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_seed == seed)
1165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_seed = seed;
1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)int FETurbulence::numOctaves() const
1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return m_numOctaves;
1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool FETurbulence::setNumOctaves(int numOctaves)
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_numOctaves == numOctaves)
1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_numOctaves = numOctaves;
1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool FETurbulence::stitchTiles() const
1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return m_stitchTiles;
1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool FETurbulence::setStitchTiles(bool stitch)
1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_stitchTiles == stitch)
1425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_stitchTiles = stitch;
1445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
1455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// The turbulence calculation code is an adapted version of what appears in the SVG 1.1 specification:
1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// http://www.w3.org/TR/SVG11/filters.html#feTurbulence
1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Compute pseudo random number.
1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)inline long FETurbulence::PaintingData::random()
1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    long result = s_randAmplitude * (seed % s_randQ) - s_randR * (seed / s_randQ);
1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (result <= 0)
1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result += s_randMaximum;
1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    seed = result;
1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return result;
1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)inline float smoothCurve(float t)
1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return t * t * (3 - 2 * t);
1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)inline float linearInterpolation(float t, float a, float b)
1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return a + t * (b - a);
1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)inline void FETurbulence::initPaint(PaintingData& paintingData)
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float normalizationFactor;
1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // The seed value clamp to the range [1, s_randMaximum - 1].
1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (paintingData.seed <= 0)
1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        paintingData.seed = -(paintingData.seed % (s_randMaximum - 1)) + 1;
1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (paintingData.seed > s_randMaximum - 1)
1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        paintingData.seed = s_randMaximum - 1;
1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float* gradient;
1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (int channel = 0; channel < 4; ++channel) {
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (int i = 0; i < s_blockSize; ++i) {
1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            paintingData.latticeSelector[i] = i;
1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            gradient = paintingData.gradient[channel][i];
1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            gradient[0] = static_cast<float>((paintingData.random() % (2 * s_blockSize)) - s_blockSize) / s_blockSize;
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            gradient[1] = static_cast<float>((paintingData.random() % (2 * s_blockSize)) - s_blockSize) / s_blockSize;
1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            normalizationFactor = sqrtf(gradient[0] * gradient[0] + gradient[1] * gradient[1]);
1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            gradient[0] /= normalizationFactor;
1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            gradient[1] /= normalizationFactor;
1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (int i = s_blockSize - 1; i > 0; --i) {
1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        int k = paintingData.latticeSelector[i];
1945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        int j = paintingData.random() % s_blockSize;
1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ASSERT(j >= 0);
1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ASSERT(j < 2 * s_blockSize + 2);
1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        paintingData.latticeSelector[i] = paintingData.latticeSelector[j];
1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        paintingData.latticeSelector[j] = k;
1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (int i = 0; i < s_blockSize + 2; ++i) {
2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        paintingData.latticeSelector[s_blockSize + i] = paintingData.latticeSelector[i];
2025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (int channel = 0; channel < 4; ++channel) {
2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            paintingData.gradient[channel][s_blockSize + i][0] = paintingData.gradient[channel][i][0];
2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            paintingData.gradient[channel][s_blockSize + i][1] = paintingData.gradient[channel][i][1];
2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)inline void checkNoise(int& noiseValue, int limitValue, int newValue)
2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (noiseValue >= limitValue)
2125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        noiseValue -= newValue;
2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (noiseValue >= limitValue - 1)
2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        noiseValue -= newValue - 1;
2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)float FETurbulence::noise2D(int channel, PaintingData& paintingData, StitchData& stitchData, const FloatPoint& noiseVector)
2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    struct Noise {
2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        int noisePositionIntegerValue;
2215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        float noisePositionFractionValue;
2225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        Noise(float component)
2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        {
2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            float position = component + s_perlinNoise;
2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            noisePositionIntegerValue = static_cast<int>(position);
2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            noisePositionFractionValue = position - noisePositionIntegerValue;
2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    };
2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Noise noiseX(noiseVector.x());
2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Noise noiseY(noiseVector.y());
2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float* q;
2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float sx, sy, a, b, u, v;
2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // If stitching, adjust lattice points accordingly.
2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_stitchTiles) {
2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        checkNoise(noiseX.noisePositionIntegerValue, stitchData.wrapX, stitchData.width);
2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        checkNoise(noiseY.noisePositionIntegerValue, stitchData.wrapY, stitchData.height);
2405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    noiseX.noisePositionIntegerValue &= s_blockMask;
2435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    noiseY.noisePositionIntegerValue &= s_blockMask;
2445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int latticeIndex = paintingData.latticeSelector[noiseX.noisePositionIntegerValue];
2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int nextLatticeIndex = paintingData.latticeSelector[(noiseX.noisePositionIntegerValue + 1) & s_blockMask];
2465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    sx = smoothCurve(noiseX.noisePositionFractionValue);
2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    sy = smoothCurve(noiseY.noisePositionFractionValue);
2495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement.
2515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int temp = paintingData.latticeSelector[latticeIndex + noiseY.noisePositionIntegerValue];
2525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    q = paintingData.gradient[channel][temp];
2535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    u = noiseX.noisePositionFractionValue * q[0] + noiseY.noisePositionFractionValue * q[1];
2545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    temp = paintingData.latticeSelector[nextLatticeIndex + noiseY.noisePositionIntegerValue];
2555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    q = paintingData.gradient[channel][temp];
2565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    v = (noiseX.noisePositionFractionValue - 1) * q[0] + noiseY.noisePositionFractionValue * q[1];
2575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    a = linearInterpolation(sx, u, v);
2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    temp = paintingData.latticeSelector[latticeIndex + noiseY.noisePositionIntegerValue + 1];
2595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    q = paintingData.gradient[channel][temp];
2605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    u = noiseX.noisePositionFractionValue * q[0] + (noiseY.noisePositionFractionValue - 1) * q[1];
2615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    temp = paintingData.latticeSelector[nextLatticeIndex + noiseY.noisePositionIntegerValue + 1];
2625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    q = paintingData.gradient[channel][temp];
2635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    v = (noiseX.noisePositionFractionValue - 1) * q[0] + (noiseY.noisePositionFractionValue - 1) * q[1];
2645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    b = linearInterpolation(sx, u, v);
2655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return linearInterpolation(sy, a, b);
2665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
268591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdochunsigned char FETurbulence::calculateTurbulenceValueForPoint(int channel, PaintingData& paintingData, StitchData& stitchData, const FloatPoint& point, float baseFrequencyX, float baseFrequencyY)
2695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float tileWidth = paintingData.filterSize.width();
2715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float tileHeight = paintingData.filterSize.height();
2725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(tileWidth > 0 && tileHeight > 0);
2735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Adjust the base frequencies if necessary for stitching.
2745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_stitchTiles) {
2755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // When stitching tiled turbulence, the frequencies must be adjusted
2765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // so that the tile borders will be continuous.
2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (baseFrequencyX) {
2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            float lowFrequency = floorf(tileWidth * baseFrequencyX) / tileWidth;
2795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            float highFrequency = ceilf(tileWidth * baseFrequencyX) / tileWidth;
2805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // BaseFrequency should be non-negative according to the standard.
2815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (baseFrequencyX / lowFrequency < highFrequency / baseFrequencyX)
2825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                baseFrequencyX = lowFrequency;
2835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            else
2845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                baseFrequencyX = highFrequency;
2855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
2865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (baseFrequencyY) {
2875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            float lowFrequency = floorf(tileHeight * baseFrequencyY) / tileHeight;
2885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            float highFrequency = ceilf(tileHeight * baseFrequencyY) / tileHeight;
2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (baseFrequencyY / lowFrequency < highFrequency / baseFrequencyY)
2905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                baseFrequencyY = lowFrequency;
2915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            else
2925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                baseFrequencyY = highFrequency;
2935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
2945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Set up TurbulenceInitial stitch values.
2955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        stitchData.width = roundf(tileWidth * baseFrequencyX);
2965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        stitchData.wrapX = s_perlinNoise + stitchData.width;
2975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        stitchData.height = roundf(tileHeight * baseFrequencyY);
2985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        stitchData.wrapY = s_perlinNoise + stitchData.height;
2995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float turbulenceFunctionResult = 0;
3015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    FloatPoint noiseVector(point.x() * baseFrequencyX, point.y() * baseFrequencyY);
3025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    float ratio = 1;
3035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (int octave = 0; octave < m_numOctaves; ++octave) {
3045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (m_type == FETURBULENCE_TYPE_FRACTALNOISE)
3055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            turbulenceFunctionResult += noise2D(channel, paintingData, stitchData, noiseVector) / ratio;
3065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else
3075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            turbulenceFunctionResult += fabsf(noise2D(channel, paintingData, stitchData, noiseVector)) / ratio;
3085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        noiseVector.setX(noiseVector.x() * 2);
3095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        noiseVector.setY(noiseVector.y() * 2);
3105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ratio *= 2;
3115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (m_stitchTiles) {
3125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // Update stitch values. Subtracting s_perlinNoiseoise before the multiplication and
3135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // adding it afterward simplifies to subtracting it once.
3145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            stitchData.width *= 2;
3155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            stitchData.wrapX = 2 * stitchData.wrapX - s_perlinNoise;
3165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            stitchData.height *= 2;
3175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            stitchData.wrapY = 2 * stitchData.wrapY - s_perlinNoise;
3185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
3195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult * 255) + 255) / 2 by fractalNoise
3225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // and (turbulenceFunctionResult * 255) by turbulence.
3235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_type == FETURBULENCE_TYPE_FRACTALNOISE)
3245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        turbulenceFunctionResult = turbulenceFunctionResult * 0.5f + 0.5f;
3255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Clamp result
3265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    turbulenceFunctionResult = std::max(std::min(turbulenceFunctionResult, 1.f), 0.f);
3275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return static_cast<unsigned char>(turbulenceFunctionResult * 255);
3285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
330591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdochinline void FETurbulence::fillRegion(Uint8ClampedArray* pixelArray, PaintingData& paintingData, int startY, int endY, float baseFrequencyX, float baseFrequencyY)
3315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
3325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    IntRect filterRegion = absolutePaintRect();
3335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    IntPoint point(0, filterRegion.y() + startY);
3345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int indexOfPixelChannel = startY * (filterRegion.width() << 2);
3355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int channel;
3365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    StitchData stitchData;
3375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (int y = startY; y < endY; ++y) {
3395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        point.setY(point.y() + 1);
3405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        point.setX(filterRegion.x());
3415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (int x = 0; x < filterRegion.width(); ++x) {
3425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            point.setX(point.x() + 1);
3435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            for (channel = 0; channel < 4; ++channel, ++indexOfPixelChannel)
344591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch                pixelArray->set(indexOfPixelChannel, calculateTurbulenceValueForPoint(channel, paintingData, stitchData, filter()->mapAbsolutePointToLocalPoint(point), baseFrequencyX, baseFrequencyY));
3455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
3465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void FETurbulence::fillRegionWorker(FillRegionParameters* parameters)
3505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
351591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch    parameters->filter->fillRegion(parameters->pixelArray, *parameters->paintingData, parameters->startY, parameters->endY, parameters->baseFrequencyX, parameters->baseFrequencyY);
3525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
35453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)void FETurbulence::applySoftware()
3555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
3565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Uint8ClampedArray* pixelArray = createUnmultipliedImageResult();
3575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!pixelArray)
3585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
3595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (absolutePaintRect().isEmpty()) {
3615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        pixelArray->zeroFill();
3625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
3635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    PaintingData paintingData(m_seed, roundedIntSize(filterPrimitiveSubregion().size()));
3665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    initPaint(paintingData);
3675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    int optimalThreadNumber = (absolutePaintRect().width() * absolutePaintRect().height()) / s_minimalRectDimension;
3695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (optimalThreadNumber > 1) {
3705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Initialize parallel jobs
371e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)        ParallelJobs<FillRegionParameters> parallelJobs(&FETurbulence::fillRegionWorker, optimalThreadNumber);
3725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // Fill the parameter array
3745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        int i = parallelJobs.numberOfJobs();
3755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (i > 1) {
3765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // Split the job into "stepY"-sized jobs but there a few jobs that need to be slightly larger since
3775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // stepY * jobs < total size. These extras are handled by the remainder "jobsWithExtra".
3785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            const int stepY = absolutePaintRect().height() / i;
3795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            const int jobsWithExtra = absolutePaintRect().height() % i;
3805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            int startY = 0;
3825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            for (; i > 0; --i) {
3835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                FillRegionParameters& params = parallelJobs.parameter(i-1);
3845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                params.filter = this;
3855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                params.pixelArray = pixelArray;
3865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                params.paintingData = &paintingData;
3875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                params.startY = startY;
3885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                startY += i < jobsWithExtra ? stepY + 1 : stepY;
3895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                params.endY = startY;
39009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)                params.baseFrequencyX = m_baseFrequencyX;
39109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)                params.baseFrequencyY = m_baseFrequencyY;
3925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            }
3935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            // Execute parallel jobs
3955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            parallelJobs.execute();
3965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            return;
3975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
3985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Fallback to single threaded mode if there is no room for a new thread or the paint area is too small.
40109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    fillRegion(pixelArray, paintingData, 0, absolutePaintRect().height(), m_baseFrequencyX, m_baseFrequencyY);
4025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4045d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)SkShader* FETurbulence::createShader()
405521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles){
4065d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)    const SkISize size = SkISize::Make(effectBoundaries().width(), effectBoundaries().height());
407a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    // Frequency should be scaled by page zoom, but not by primitiveUnits.
408a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    // So we apply only the transform scale (as Filter::apply*Scale() do)
409a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    // and not the target bounding box scale (as SVGFilter::apply*Scale()
410a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    // would do). Note also that we divide by the scale since this is
411a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    // a frequency, not a period.
412a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    const AffineTransform& absoluteTransform = filter()->absoluteTransform();
413a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    float baseFrequencyX = m_baseFrequencyX / absoluteTransform.a();
414a9984bf9ddc3cf73fdae3f29134a2bab379e7029Ben Murdoch    float baseFrequencyY = m_baseFrequencyY / absoluteTransform.d();
415521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)    return (type() == FETURBULENCE_TYPE_FRACTALNOISE) ?
416591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch        SkPerlinNoiseShader::CreateFractalNoise(SkFloatToScalar(baseFrequencyX),
417591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch            SkFloatToScalar(baseFrequencyY), numOctaves(), SkFloatToScalar(seed()),
418521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)            stitchTiles() ? &size : 0) :
4196f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch        SkPerlinNoiseShader::CreateTurbulence(SkFloatToScalar(baseFrequencyX),
420591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch            SkFloatToScalar(baseFrequencyY), numOctaves(), SkFloatToScalar(seed()),
421521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)            stitchTiles() ? &size : 0);
422521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)}
423521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
4243c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben MurdochPassRefPtr<SkImageFilter> FETurbulence::createImageFilter(SkiaImageFilterBuilder* builder)
425521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles){
4265d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)    SkAutoTUnref<SkShader> shader(createShader());
427bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    SkImageFilter::CropRect rect = getCropRect(builder->cropOffset());
428bfe3590b1806e3ff18f46ee3af5d4b83078f305aTorne (Richard Coles)    return adoptRef(SkRectShaderImageFilter::Create(shader, &rect));
429521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)}
430521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)
4315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static TextStream& operator<<(TextStream& ts, const TurbulenceType& type)
4325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    switch (type) {
4345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case FETURBULENCE_TYPE_UNKNOWN:
4355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ts << "UNKNOWN";
4365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
4375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case FETURBULENCE_TYPE_TURBULENCE:
438521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)        ts << "TURBULENCE";
4395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
4405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case FETURBULENCE_TYPE_FRACTALNOISE:
4415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ts << "NOISE";
4425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
4435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
4445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return ts;
4455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)TextStream& FETurbulence::externalRepresentation(TextStream& ts, int indent) const
4485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    writeIndent(ts, indent);
4505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ts << "[feTurbulence";
4515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    FilterEffect::externalRepresentation(ts);
4525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ts << " type=\"" << type() << "\" "
4535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)       << "baseFrequency=\"" << baseFrequencyX() << ", " << baseFrequencyY() << "\" "
4545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)       << "seed=\"" << seed() << "\" "
4555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)       << "numOctaves=\"" << numOctaves() << "\" "
4565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)       << "stitchTiles=\"" << stitchTiles() << "\"]\n";
4575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return ts;
4585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
460c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)} // namespace blink
461