Changeset 64340 in webkit


Ignore:
Timestamp:
Jul 30, 2010 12:49:14 AM (14 years ago)
Author:
commit-queue@webkit.org
Message:

2010-07-30 Renata Hodovan <reni@inf.u-szeged.hu>

Reviewed by Nikolas Zimmermann.

Update expectation for turbulence filter:
svg/W3C-SVG-1.1/filters-turb-01-f.svg

  • platform/mac/svg/W3C-SVG-1.1/filters-turb-01-f-expected.checksum:
  • platform/mac/svg/W3C-SVG-1.1/filters-turb-01-f-expected.png:

2010-07-30 Renata Hodovan <reni@inf.u-szeged.hu>

Reviewed by Nikolas Zimmermann.

feTurbulence is not implemented.
https://bugs.webkit.org/show_bug.cgi?id=5864

This code is based on the previous implementation of
Dirk Schulze, extended with some modification and optimization.

LayoutTests: Updating expected values for turbulence filter.
svg/W3C-SVG-1.1/filters-turb-01-f.svg

  • svg/SVGFETurbulenceElement.cpp: (WebCore::SVGFETurbulenceElement::build):
  • svg/graphics/filters/SVGFETurbulence.cpp: (WebCore::FETurbulence::FETurbulence): (WebCore::FETurbulence::create): (WebCore::FETurbulence::PaintingData::PaintingData): (WebCore::FETurbulence::PaintingData::random): (WebCore::smoothCurve): (WebCore::linearInterpolation): (WebCore::FETurbulence::initPaint): (WebCore::checkNoise): (WebCore::FETurbulence::noise2D): (WebCore::Noise::if): (WebCore::FETurbulence::calculateTurbulenceValueForPoint): (WebCore::FETurbulence::apply):
  • svg/graphics/filters/SVGFETurbulence.h: (WebCore::):
Location:
trunk
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r64338 r64340  
     12010-07-30  Renata Hodovan  <reni@inf.u-szeged.hu>
     2
     3        Reviewed by Nikolas Zimmermann.
     4
     5        Update expectation for turbulence filter:
     6        svg/W3C-SVG-1.1/filters-turb-01-f.svg
     7
     8        * platform/mac/svg/W3C-SVG-1.1/filters-turb-01-f-expected.checksum:
     9        * platform/mac/svg/W3C-SVG-1.1/filters-turb-01-f-expected.png:
     10
    1112010-07-29  Martin Robinson  <mrobinson@igalia.com>
    212
  • trunk/LayoutTests/platform/mac/svg/W3C-SVG-1.1/filters-turb-01-f-expected.checksum

    r51800 r64340  
    1 df22aa4b3c9bb8a8cf3116b93706e9dd
     1197d4313f7f222ab4981ad65104effaf
  • trunk/WebCore/ChangeLog

    r64339 r64340  
     12010-07-30  Renata Hodovan  <reni@inf.u-szeged.hu>
     2
     3        Reviewed by Nikolas Zimmermann.
     4
     5        feTurbulence is not implemented.
     6        https://bugs.webkit.org/show_bug.cgi?id=5864
     7
     8        This code is based on the previous implementation of
     9        Dirk Schulze, extended with some modification and optimization.
     10
     11        LayoutTests: Updating expected values for turbulence filter.
     12        svg/W3C-SVG-1.1/filters-turb-01-f.svg
     13
     14        * svg/SVGFETurbulenceElement.cpp:
     15        (WebCore::SVGFETurbulenceElement::build):
     16        * svg/graphics/filters/SVGFETurbulence.cpp:
     17        (WebCore::FETurbulence::FETurbulence):
     18        (WebCore::FETurbulence::create):
     19        (WebCore::FETurbulence::PaintingData::PaintingData):
     20        (WebCore::FETurbulence::PaintingData::random):
     21        (WebCore::smoothCurve):
     22        (WebCore::linearInterpolation):
     23        (WebCore::FETurbulence::initPaint):
     24        (WebCore::checkNoise):
     25        (WebCore::FETurbulence::noise2D):
     26        (WebCore::Noise::if):
     27        (WebCore::FETurbulence::calculateTurbulenceValueForPoint):
     28        (WebCore::FETurbulence::apply):
     29        * svg/graphics/filters/SVGFETurbulence.h:
     30        (WebCore::):
     31
    1322010-07-29  Martin Robinson  <mrobinson@igalia.com>
    233
  • trunk/WebCore/svg/SVGFETurbulenceElement.cpp

    r59773 r64340  
    100100PassRefPtr<FilterEffect> SVGFETurbulenceElement::build(SVGFilterBuilder*)
    101101{
     102    if (baseFrequencyX() < 0 || baseFrequencyY() < 0)
     103        return 0;
     104
    102105    return FETurbulence::create(static_cast<TurbulanceType>(type()), baseFrequencyX(),
    103106                baseFrequencyY(), numOctaves(), seed(), stitchTiles() == SVG_STITCHTYPE_STITCH);
  • trunk/WebCore/svg/graphics/filters/SVGFETurbulence.cpp

    r59069 r64340  
    33                  2004, 2005 Rob Buis <buis@kde.org>
    44                  2005 Eric Seidel <eric@webkit.org>
     5                  2009 Dirk Schulze <krit@webkit.org>
     6                  2010 Renata Hodovan <reni@inf.u-szeged.hu>
    57
    68    This library is free software; you can redistribute it and/or
     
    2426#if ENABLE(SVG) && ENABLE(FILTERS)
    2527#include "SVGFETurbulence.h"
     28
     29#include "CanvasPixelArray.h"
     30#include "Filter.h"
     31#include "ImageData.h"
    2632#include "SVGRenderTreeAsText.h"
    27 #include "Filter.h"
     33
     34#include <wtf/MathExtras.h>
    2835
    2936namespace WebCore {
    3037
    31 FETurbulence::FETurbulence(TurbulanceType type, const float& baseFrequencyX, const float& baseFrequencyY,
    32     const int& numOctaves, const float& seed, bool stitchTiles)
     38/*
     39    Produces results in the range [1, 2**31 - 2]. Algorithm is:
     40    r = (a * r) mod m where a = randAmplitude = 16807 and
     41    m = randMaximum = 2**31 - 1 = 2147483647, r = seed.
     42    See [Park & Miller], CACM vol. 31 no. 10 p. 1195, Oct. 1988
     43    To test: the algorithm should produce the result 1043618065
     44    as the 10,000th generated number if the original seed is 1.
     45*/
     46static const int s_perlinNoise = 4096;
     47static const long s_randMaximum = 2147483647; // 2**31 - 1
     48static const int s_randAmplitude = 16807; // 7**5; primitive root of m
     49static const int s_randQ = 127773; // m / a
     50static const int s_randR = 2836; // m % a
     51
     52FETurbulence::FETurbulence(TurbulanceType type, float baseFrequencyX, float baseFrequencyY, int numOctaves, float seed, bool stitchTiles)
    3353    : FilterEffect()
    3454    , m_type(type)
     
    4161}
    4262
    43 PassRefPtr<FETurbulence> FETurbulence::create(TurbulanceType type, const float& baseFrequencyX, const float& baseFrequencyY,
    44     const int& numOctaves, const float& seed, bool stitchTiles)
     63PassRefPtr<FETurbulence> FETurbulence::create(TurbulanceType type, float baseFrequencyX, float baseFrequencyY, int numOctaves, float seed, bool stitchTiles)
    4564{
    4665    return adoptRef(new FETurbulence(type, baseFrequencyX, baseFrequencyY, numOctaves, seed, stitchTiles));
     
    107126}
    108127
    109 void FETurbulence::apply(Filter*)
    110 {
     128// The turbulence calculation code is an adapted version of what appears in the SVG 1.1 specification:
     129// http://www.w3.org/TR/SVG11/filters.html#feTurbulence
     130
     131FETurbulence::PaintingData::PaintingData(long paintingSeed, const IntSize& paintingSize)
     132    : seed(paintingSeed)
     133    , width(0)
     134    , height(0)
     135    , wrapX(0)
     136    , wrapY(0)
     137    , channel(0)
     138    , filterSize(paintingSize)
     139{
     140}
     141
     142// Compute pseudo random number.
     143inline long FETurbulence::PaintingData::random()
     144{
     145    long result = s_randAmplitude * (seed % s_randQ) - s_randR * (seed / s_randQ);
     146    if (result <= 0)
     147        result += s_randMaximum;
     148    seed = result;
     149    return result;
     150}
     151
     152inline float smoothCurve(float t)
     153{
     154    return t * t * (3 - 2 * t);
     155}
     156
     157inline float linearInterpolation(float t, float a, float b)
     158{
     159    return a + t * (b - a);
     160}
     161
     162inline void FETurbulence::initPaint(PaintingData& paintingData)
     163{
     164    float normalizationFactor;
     165
     166    // The seed value clamp to the range [1, s_randMaximum - 1].
     167    if (paintingData.seed <= 0)
     168        paintingData.seed = -(paintingData.seed % (s_randMaximum - 1)) + 1;
     169    if (paintingData.seed > s_randMaximum - 1)
     170        paintingData.seed = s_randMaximum - 1;
     171
     172    float* gradient;
     173    for (int channel = 0; channel < 4; ++channel) {
     174        for (int i = 0; i < s_blockSize; ++i) {
     175            paintingData.latticeSelector[i] = i;
     176            gradient = paintingData.gradient[channel][i];
     177            gradient[0] = static_cast<float>((paintingData.random() % (2 * s_blockSize)) - s_blockSize) / s_blockSize;
     178            gradient[1] = static_cast<float>((paintingData.random() % (2 * s_blockSize)) - s_blockSize) / s_blockSize;
     179            normalizationFactor = sqrtf(gradient[0] * gradient[0] + gradient[1] * gradient[1]);
     180            gradient[0] /= normalizationFactor;
     181            gradient[1] /= normalizationFactor;
     182        }
     183    }
     184    for (int i = s_blockSize - 1; i >= 0; --i) {
     185        int k = paintingData.latticeSelector[i];
     186        int j = paintingData.random() % s_blockSize;
     187        ASSERT(j >= 0);
     188        ASSERT(j < 2 * s_blockSize + 2);
     189        paintingData.latticeSelector[i] = paintingData.latticeSelector[j];
     190        paintingData.latticeSelector[j] = k;
     191    }
     192    for (int i = 0; i < s_blockSize + 2; ++i) {
     193        paintingData.latticeSelector[s_blockSize + i] = paintingData.latticeSelector[i];
     194        for (int channel = 0; channel < 4; ++channel) {
     195            paintingData.gradient[channel][s_blockSize + i][0] = paintingData.gradient[channel][i][0];
     196            paintingData.gradient[channel][s_blockSize + i][1] = paintingData.gradient[channel][i][1];
     197        }
     198    }
     199}
     200
     201inline void checkNoise(int& noiseValue, int limitValue, int newValue)
     202{
     203    if (noiseValue >= limitValue)
     204        noiseValue -= newValue;
     205    if (noiseValue >= limitValue - 1)
     206        noiseValue -= newValue - 1;
     207}
     208
     209float FETurbulence::noise2D(PaintingData& paintingData, const FloatPoint& noiseVector)
     210{
     211    struct Noise {
     212        int noisePositionIntegerValue;
     213        float noisePositionFractionValue;
     214
     215        Noise(float component)
     216        {
     217            float position = component + s_perlinNoise;
     218            noisePositionIntegerValue = static_cast<int>(position);
     219            noisePositionFractionValue = position - noisePositionIntegerValue;
     220        }
     221    };
     222
     223    Noise noiseX(noiseVector.x());
     224    Noise noiseY(noiseVector.y());
     225    float* q;
     226    float sx, sy, a, b, u, v;
     227
     228    // If stitching, adjust lattice points accordingly.
     229    if (m_stitchTiles) {
     230        checkNoise(noiseX.noisePositionIntegerValue, paintingData.wrapX, paintingData.width);
     231        checkNoise(noiseY.noisePositionIntegerValue, paintingData.wrapY, paintingData.height);
     232    }
     233
     234    noiseX.noisePositionIntegerValue &= s_blockMask;
     235    noiseY.noisePositionIntegerValue &= s_blockMask;
     236    int latticeIndex = paintingData.latticeSelector[noiseX.noisePositionIntegerValue];
     237    int nextLatticeIndex = paintingData.latticeSelector[(noiseX.noisePositionIntegerValue + 1) & s_blockMask];
     238
     239    sx = smoothCurve(noiseX.noisePositionFractionValue);
     240    sy = smoothCurve(noiseY.noisePositionFractionValue);
     241
     242    // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement.
     243    int temp = paintingData.latticeSelector[latticeIndex + noiseY.noisePositionIntegerValue];
     244    q = paintingData.gradient[paintingData.channel][temp];
     245    u = noiseX.noisePositionFractionValue * q[0] + noiseY.noisePositionFractionValue * q[1];
     246    temp = paintingData.latticeSelector[nextLatticeIndex + noiseY.noisePositionIntegerValue];
     247    q = paintingData.gradient[paintingData.channel][temp];
     248    v = (noiseX.noisePositionFractionValue - 1) * q[0] + noiseY.noisePositionFractionValue * q[1];
     249    a = linearInterpolation(sx, u, v);
     250    temp = paintingData.latticeSelector[latticeIndex + noiseY.noisePositionIntegerValue + 1];
     251    q = paintingData.gradient[paintingData.channel][temp];
     252    u = noiseX.noisePositionFractionValue * q[0] + (noiseY.noisePositionFractionValue - 1) * q[1];
     253    temp = paintingData.latticeSelector[nextLatticeIndex + noiseY.noisePositionIntegerValue + 1];
     254    q = paintingData.gradient[paintingData.channel][temp];
     255    v = (noiseX.noisePositionFractionValue - 1) * q[0] + (noiseY.noisePositionFractionValue - 1) * q[1];
     256    b = linearInterpolation(sx, u, v);
     257    return linearInterpolation(sy, a, b);
     258}
     259
     260unsigned char FETurbulence::calculateTurbulenceValueForPoint(PaintingData& paintingData, const FloatPoint& point)
     261{
     262    float tileWidth = paintingData.filterSize.width();
     263    ASSERT(tileWidth > 0);
     264    float tileHeight = paintingData.filterSize.height();
     265    ASSERT(tileHeight > 0);
     266    // Adjust the base frequencies if necessary for stitching.
     267    if (m_stitchTiles) {
     268        // When stitching tiled turbulence, the frequencies must be adjusted
     269        // so that the tile borders will be continuous.
     270        if (m_baseFrequencyX) {
     271            float lowFrequency = floorf(tileWidth * m_baseFrequencyX) / tileWidth;
     272            float highFrequency = ceilf(tileWidth * m_baseFrequencyX) / tileWidth;
     273            // BaseFrequency should be non-negative according to the standard.
     274            if (m_baseFrequencyX / lowFrequency < highFrequency / m_baseFrequencyX)
     275                m_baseFrequencyX = lowFrequency;
     276            else
     277                m_baseFrequencyX = highFrequency;
     278        }
     279        if (m_baseFrequencyY) {
     280            float lowFrequency = floorf(tileHeight * m_baseFrequencyY) / tileHeight;
     281            float highFrequency = ceilf(tileHeight * m_baseFrequencyY) / tileHeight;
     282            if (m_baseFrequencyY / lowFrequency < highFrequency / m_baseFrequencyY)
     283                m_baseFrequencyY = lowFrequency;
     284            else
     285                m_baseFrequencyY = highFrequency;
     286        }
     287        // Set up TurbulenceInitial stitch values.
     288        paintingData.width = roundf(tileWidth * m_baseFrequencyX);
     289        paintingData.wrapX = s_perlinNoise + paintingData.width;
     290        paintingData.height = roundf(tileHeight * m_baseFrequencyY);
     291        paintingData.wrapY = s_perlinNoise + paintingData.height;
     292    }
     293    float turbulenceFunctionResult = 0;
     294    FloatPoint noiseVector(point.x() * m_baseFrequencyX, point.y() * m_baseFrequencyY);
     295    float ratio = 1;
     296    for (int octave = 0; octave < m_numOctaves; ++octave) {
     297        if (m_type == FETURBULENCE_TYPE_FRACTALNOISE)
     298            turbulenceFunctionResult += noise2D(paintingData, noiseVector) / ratio;
     299        else
     300            turbulenceFunctionResult += fabsf(noise2D(paintingData, noiseVector)) / ratio;
     301        noiseVector.setX(noiseVector.x() * 2);
     302        noiseVector.setY(noiseVector.y() * 2);
     303        ratio *= 2;
     304        if (m_stitchTiles) {
     305            // Update stitch values. Subtracting s_perlinNoiseoise before the multiplication and
     306            // adding it afterward simplifies to subtracting it once.
     307            paintingData.width *= 2;
     308            paintingData.wrapX = 2 * paintingData.wrapX - s_perlinNoise;
     309            paintingData.height *= 2;
     310            paintingData.wrapY = 2 * paintingData.wrapY - s_perlinNoise;
     311        }
     312    }
     313
     314    // Clamp result
     315    turbulenceFunctionResult = std::max(std::min(turbulenceFunctionResult, 255.f), 0.f);
     316    if (m_type == FETURBULENCE_TYPE_FRACTALNOISE)
     317        return static_cast<unsigned char>(turbulenceFunctionResult * 127.5f + 127.5f); // It comes form (turbulenceFunctionResult * 255 + 255) / 2
     318    return static_cast<unsigned char>(turbulenceFunctionResult * 255);
     319}
     320
     321void FETurbulence::apply(Filter* filter)
     322{
     323    if (!getEffectContext())
     324        return;
     325
     326    IntRect imageRect(IntPoint(), resultImage()->size());
     327    if (!imageRect.size().width() || !imageRect.size().height())
     328        return;
     329
     330    RefPtr<ImageData> imageData = ImageData::create(imageRect.width(), imageRect.height());
     331    PaintingData paintingData(floorf(fabsf(m_seed)), imageRect.size());
     332    initPaint(paintingData);
     333
     334    FloatRect filterRegion = filter->filterRegion();
     335    FloatPoint point;
     336    point.setY(filterRegion.y());
     337    int indexOfPixelChannel = 0;
     338    for (int y = 0; y < imageRect.height(); ++y) {
     339        point.setY(point.y() + 1);
     340        point.setX(filterRegion.x());
     341        for (int x = 0; x < imageRect.width(); ++x) {
     342            point.setX(point.x() + 1);
     343            for (paintingData.channel = 0; paintingData.channel < 4; ++paintingData.channel, ++indexOfPixelChannel)
     344                imageData->data()->set(indexOfPixelChannel, calculateTurbulenceValueForPoint(paintingData, point));
     345        }
     346    }
     347    resultImage()->putUnmultipliedImageData(imageData.get(), imageRect, IntPoint());
    111348}
    112349
  • trunk/WebCore/svg/graphics/filters/SVGFETurbulence.h

    r59069 r64340  
    33                  2004, 2005 Rob Buis <buis@kde.org>
    44                  2005 Eric Seidel <eric@webkit.org>
     5                  2009 Dirk Schulze <krit@webkit.org>
     6                  2010 Renata Hodovan <reni@inf.u-szeged.hu>
    57
    68    This library is free software; you can redistribute it and/or
     
    2931namespace WebCore {
    3032
    31     enum TurbulanceType {
    32         FETURBULENCE_TYPE_UNKNOWN      = 0,
    33         FETURBULENCE_TYPE_FRACTALNOISE = 1,
    34         FETURBULENCE_TYPE_TURBULENCE   = 2
     33enum TurbulanceType {
     34    FETURBULENCE_TYPE_UNKNOWN = 0,
     35    FETURBULENCE_TYPE_FRACTALNOISE = 1,
     36    FETURBULENCE_TYPE_TURBULENCE = 2
     37};
     38
     39class FETurbulence : public FilterEffect {
     40public:
     41    static PassRefPtr<FETurbulence> create(TurbulanceType, float, float, int, float, bool);
     42
     43    TurbulanceType type() const;
     44    void setType(TurbulanceType);
     45
     46    float baseFrequencyY() const;
     47    void setBaseFrequencyY(float);
     48
     49    float baseFrequencyX() const;
     50    void setBaseFrequencyX(float);
     51
     52    float seed() const;
     53    void setSeed(float);
     54
     55    int numOctaves() const;
     56    void setNumOctaves(bool);
     57
     58    bool stitchTiles() const;
     59    void setStitchTiles(bool);
     60
     61    void apply(Filter*);
     62    void dump();
     63    TextStream& externalRepresentation(TextStream&, int indent) const;
     64
     65private:
     66    static const int s_blockSize = 256;
     67    static const int s_blockMask = s_blockSize - 1;
     68
     69    struct PaintingData {
     70        long seed;
     71        int latticeSelector[2 * s_blockSize + 2];
     72        float gradient[4][2 * s_blockSize + 2][2];
     73        int width; // How much to subtract to wrap for stitching.
     74        int height;
     75        int wrapX; // Minimum value to wrap.
     76        int wrapY;
     77        int channel;
     78        IntSize filterSize;
     79
     80        PaintingData(long paintingSeed, const IntSize& paintingSize);
     81        inline long random();
    3582    };
    3683
    37     class FETurbulence : public FilterEffect {
    38     public:
    39         static PassRefPtr<FETurbulence> create(TurbulanceType, const float&, const float&, const int&, const float&,
    40                 bool);
     84    FETurbulence(TurbulanceType, float, float, int, float, bool);
    4185
    42         TurbulanceType type() const;
    43         void setType(TurbulanceType);
     86    inline void initPaint(PaintingData&);
     87    float noise2D(PaintingData&, const FloatPoint&);
     88    unsigned char calculateTurbulenceValueForPoint(PaintingData&, const FloatPoint&);
    4489
    45         float baseFrequencyY() const;
    46         void setBaseFrequencyY(float);
    47 
    48         float baseFrequencyX() const;
    49         void setBaseFrequencyX(float);
    50 
    51         float seed() const;
    52         void setSeed(float);
    53 
    54         int numOctaves() const;
    55         void setNumOctaves(bool);
    56 
    57         bool stitchTiles() const;
    58         void setStitchTiles(bool);
    59 
    60         void apply(Filter*);
    61         void dump();
    62         TextStream& externalRepresentation(TextStream&, int indent) const;
    63 
    64     private:
    65         FETurbulence(TurbulanceType, const float&, const float&, const int&, const float&,
    66                 bool);
    67 
    68         TurbulanceType m_type;
    69         float m_baseFrequencyX;
    70         float m_baseFrequencyY;
    71         int m_numOctaves;
    72         float m_seed;
    73         bool m_stitchTiles;
    74     };
     90    TurbulanceType m_type;
     91    float m_baseFrequencyX;
     92    float m_baseFrequencyY;
     93    int m_numOctaves;
     94    float m_seed;
     95    bool m_stitchTiles;
     96};
    7597
    7698} // namespace WebCore
Note: See TracChangeset for help on using the changeset viewer.