gfx/2d/SVGTurbulenceRenderer-inl.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include "2D.h"
     7 #include "Filters.h"
     8 #include "SIMD.h"
    10 namespace mozilla {
    11 namespace gfx {
    13 template<TurbulenceType Type, bool Stitch, typename f32x4_t, typename i32x4_t, typename u8x16_t>
    14 class SVGTurbulenceRenderer
    15 {
    16 public:
    17   SVGTurbulenceRenderer(const Size &aBaseFrequency, int32_t aSeed,
    18                         int aNumOctaves, const Rect &aTileRect);
    20   TemporaryRef<DataSourceSurface> Render(const IntSize &aSize, const Point &aOffset) const;
    22 private:
    23   /* The turbulence calculation code is an adapted version of what
    24      appears in the SVG 1.1 specification:
    25          http://www.w3.org/TR/SVG11/filters.html#feTurbulence
    26   */
    28   struct StitchInfo {
    29     int32_t width;     // How much to subtract to wrap for stitching.
    30     int32_t height;
    31     int32_t wrapX;     // Minimum value to wrap.
    32     int32_t wrapY;
    33   };
    35   const static int sBSize = 0x100;
    36   const static int sBM = 0xff;
    37   void InitFromSeed(int32_t aSeed);
    38   void AdjustBaseFrequencyForStitch(const Rect &aTileRect);
    39   IntPoint AdjustForStitch(IntPoint aLatticePoint, const StitchInfo& aStitchInfo) const;
    40   StitchInfo CreateStitchInfo(const Rect &aTileRect) const;
    41   f32x4_t Noise2(Point aVec, const StitchInfo& aStitchInfo) const;
    42   i32x4_t Turbulence(const Point &aPoint) const;
    43   Point EquivalentNonNegativeOffset(const Point &aOffset) const;
    45   Size mBaseFrequency;
    46   int32_t mNumOctaves;
    47   StitchInfo mStitchInfo;
    48   bool mStitchable;
    49   TurbulenceType mType;
    50   uint8_t mLatticeSelector[sBSize];
    51   f32x4_t mGradient[sBSize][2];
    52 };
    54 namespace {
    56 struct RandomNumberSource
    57 {
    58   RandomNumberSource(int32_t aSeed) : mLast(SetupSeed(aSeed)) {}
    59   int32_t Next() { mLast = Random(mLast); return mLast; }
    61 private:
    62   static const int32_t RAND_M = 2147483647; /* 2**31 - 1 */
    63   static const int32_t RAND_A = 16807;      /* 7**5; primitive root of m */
    64   static const int32_t RAND_Q = 127773;     /* m / a */
    65   static const int32_t RAND_R = 2836;       /* m % a */
    67   /* Produces results in the range [1, 2**31 - 2].
    68      Algorithm is: r = (a * r) mod m
    69      where a = 16807 and m = 2**31 - 1 = 2147483647
    70      See [Park & Miller], CACM vol. 31 no. 10 p. 1195, Oct. 1988
    71      To test: the algorithm should produce the result 1043618065
    72      as the 10,000th generated number if the original seed is 1.
    73   */
    75   static int32_t
    76   SetupSeed(int32_t aSeed) {
    77     if (aSeed <= 0)
    78       aSeed = -(aSeed % (RAND_M - 1)) + 1;
    79     if (aSeed > RAND_M - 1)
    80       aSeed = RAND_M - 1;
    81     return aSeed;
    82   }
    84   static int32_t
    85   Random(int32_t aSeed)
    86   {
    87     int32_t result = RAND_A * (aSeed % RAND_Q) - RAND_R * (aSeed / RAND_Q);
    88     if (result <= 0)
    89       result += RAND_M;
    90     return result;
    91   }
    93   int32_t mLast;
    94 };
    96 } // unnamed namespace
    98 template<TurbulenceType Type, bool Stitch, typename f32x4_t, typename i32x4_t, typename u8x16_t>
    99 SVGTurbulenceRenderer<Type,Stitch,f32x4_t,i32x4_t,u8x16_t>::SVGTurbulenceRenderer(const Size &aBaseFrequency, int32_t aSeed,
   100                                                             int aNumOctaves, const Rect &aTileRect)
   101  : mBaseFrequency(aBaseFrequency)
   102  , mNumOctaves(aNumOctaves)
   103 {
   104   InitFromSeed(aSeed);
   105   if (Stitch) {
   106     AdjustBaseFrequencyForStitch(aTileRect);
   107     mStitchInfo = CreateStitchInfo(aTileRect);
   108   }
   109 }
   111 template<typename T>
   112 static void
   113 Swap(T& a, T& b) {
   114   T c = a;
   115   a = b;
   116   b = c;
   117 }
   119 template<TurbulenceType Type, bool Stitch, typename f32x4_t, typename i32x4_t, typename u8x16_t>
   120 void
   121 SVGTurbulenceRenderer<Type,Stitch,f32x4_t,i32x4_t,u8x16_t>::InitFromSeed(int32_t aSeed)
   122 {
   123   RandomNumberSource rand(aSeed);
   125   float gradient[4][sBSize][2];
   126   for (int32_t k = 0; k < 4; k++) {
   127     for (int32_t i = 0; i < sBSize; i++) {
   128       float a = float((rand.Next() % (sBSize + sBSize)) - sBSize) / sBSize;
   129       float b = float((rand.Next() % (sBSize + sBSize)) - sBSize) / sBSize;
   130       float s = sqrt(a * a + b * b);
   131       gradient[k][i][0] = a / s;
   132       gradient[k][i][1] = b / s;
   133     }
   134   }
   136   for (int32_t i = 0; i < sBSize; i++) {
   137     mLatticeSelector[i] = i;
   138   }
   139   for (int32_t i1 = sBSize - 1; i1 > 0; i1--) {
   140     int32_t i2 = rand.Next() % sBSize;
   141     Swap(mLatticeSelector[i1], mLatticeSelector[i2]);
   142   }
   144   for (int32_t i = 0; i < sBSize; i++) {
   145     // Contrary to the code in the spec, we build the first lattice selector
   146     // lookup into mGradient so that we don't need to do it again for every
   147     // pixel.
   148     // We also change the order of the gradient indexing so that we can process
   149     // all four color channels at the same time.
   150     uint8_t j = mLatticeSelector[i];
   151     mGradient[i][0] = simd::FromF32<f32x4_t>(gradient[2][j][0], gradient[1][j][0],
   152                                              gradient[0][j][0], gradient[3][j][0]);
   153     mGradient[i][1] = simd::FromF32<f32x4_t>(gradient[2][j][1], gradient[1][j][1],
   154                                              gradient[0][j][1], gradient[3][j][1]);
   155   }
   156 }
   158 // Adjust aFreq such that aLength * AdjustForLength(aFreq, aLength) is integer
   159 // and as close to aLength * aFreq as possible.
   160 static inline float
   161 AdjustForLength(float aFreq, float aLength)
   162 {
   163   float lowFreq = floor(aLength * aFreq) / aLength;
   164   float hiFreq = ceil(aLength * aFreq) / aLength;
   165   if (aFreq / lowFreq < hiFreq / aFreq) {
   166     return lowFreq;
   167   }
   168   return hiFreq;
   169 }
   171 template<TurbulenceType Type, bool Stitch, typename f32x4_t, typename i32x4_t, typename u8x16_t>
   172 void
   173 SVGTurbulenceRenderer<Type,Stitch,f32x4_t,i32x4_t,u8x16_t>::AdjustBaseFrequencyForStitch(const Rect &aTileRect)
   174 {
   175   mBaseFrequency = Size(AdjustForLength(mBaseFrequency.width, aTileRect.width),
   176                         AdjustForLength(mBaseFrequency.height, aTileRect.height));
   177 }
   179 template<TurbulenceType Type, bool Stitch, typename f32x4_t, typename i32x4_t, typename u8x16_t>
   180 typename SVGTurbulenceRenderer<Type,Stitch,f32x4_t,i32x4_t,u8x16_t>::StitchInfo
   181 SVGTurbulenceRenderer<Type,Stitch,f32x4_t,i32x4_t,u8x16_t>::CreateStitchInfo(const Rect &aTileRect) const
   182 {
   183   StitchInfo stitch;
   184   stitch.width = int32_t(floorf(aTileRect.width * mBaseFrequency.width + 0.5f));
   185   stitch.height = int32_t(floorf(aTileRect.height * mBaseFrequency.height + 0.5f));
   186   stitch.wrapX = int32_t(aTileRect.x * mBaseFrequency.width) + stitch.width;
   187   stitch.wrapY = int32_t(aTileRect.y * mBaseFrequency.height) + stitch.height;
   188   return stitch;
   189 }
   191 static MOZ_ALWAYS_INLINE Float
   192 SCurve(Float t)
   193 {
   194   return t * t * (3 - 2 * t);
   195 }
   197 static MOZ_ALWAYS_INLINE Point
   198 SCurve(Point t)
   199 {
   200   return Point(SCurve(t.x), SCurve(t.y));
   201 }
   203 template<typename f32x4_t>
   204 static MOZ_ALWAYS_INLINE f32x4_t
   205 BiMix(const f32x4_t& aa, const f32x4_t& ab,
   206       const f32x4_t& ba, const f32x4_t& bb, Point s)
   207 {
   208   return simd::MixF32(simd::MixF32(aa, ab, s.x),
   209                       simd::MixF32(ba, bb, s.x), s.y);
   210 }
   212 template<TurbulenceType Type, bool Stitch, typename f32x4_t, typename i32x4_t, typename u8x16_t>
   213 IntPoint
   214 SVGTurbulenceRenderer<Type,Stitch,f32x4_t,i32x4_t,u8x16_t>::AdjustForStitch(IntPoint aLatticePoint,
   215                                                       const StitchInfo& aStitchInfo) const
   216 {
   217   if (Stitch) {
   218     if (aLatticePoint.x >= aStitchInfo.wrapX) {
   219       aLatticePoint.x -= aStitchInfo.width;
   220     }
   221     if (aLatticePoint.y >= aStitchInfo.wrapY) {
   222       aLatticePoint.y -= aStitchInfo.height;
   223     }
   224   }
   225   return aLatticePoint;
   226 }
   228 template<TurbulenceType Type, bool Stitch, typename f32x4_t, typename i32x4_t, typename u8x16_t>
   229 f32x4_t
   230 SVGTurbulenceRenderer<Type,Stitch,f32x4_t,i32x4_t,u8x16_t>::Noise2(Point aVec, const StitchInfo& aStitchInfo) const
   231 {
   232   // aVec is guaranteed to be non-negative, so casting to int32_t always
   233   // rounds towards negative infinity.
   234   IntPoint topLeftLatticePoint(int32_t(aVec.x), int32_t(aVec.y));
   235   Point r = aVec - topLeftLatticePoint; // fractional offset
   237   IntPoint b0 = AdjustForStitch(topLeftLatticePoint, aStitchInfo);
   238   IntPoint b1 = AdjustForStitch(b0 + IntPoint(1, 1), aStitchInfo);
   240   uint8_t i = mLatticeSelector[b0.x & sBM];
   241   uint8_t j = mLatticeSelector[b1.x & sBM];
   243   const f32x4_t* qua = mGradient[(i + b0.y) & sBM];
   244   const f32x4_t* qub = mGradient[(i + b1.y) & sBM];
   245   const f32x4_t* qva = mGradient[(j + b0.y) & sBM];
   246   const f32x4_t* qvb = mGradient[(j + b1.y) & sBM];
   248   return BiMix(simd::WSumF32(qua[0], qua[1], r.x, r.y),
   249                simd::WSumF32(qva[0], qva[1], r.x - 1, r.y),
   250                simd::WSumF32(qub[0], qub[1], r.x, r.y - 1),
   251                simd::WSumF32(qvb[0], qvb[1], r.x - 1, r.y - 1),
   252                SCurve(r));
   253 }
   255 template<typename f32x4_t, typename i32x4_t, typename u8x16_t>
   256 static inline i32x4_t
   257 ColorToBGRA(f32x4_t aUnscaledUnpreFloat)
   258 {
   259   // Color is an unpremultiplied float vector where 1.0f means white. We will
   260   // convert it into an integer vector where 255 means white.
   261   f32x4_t alpha = simd::SplatF32<3>(aUnscaledUnpreFloat);
   262   f32x4_t scaledUnpreFloat = simd::MulF32(aUnscaledUnpreFloat, simd::FromF32<f32x4_t>(255));
   263   i32x4_t scaledUnpreInt = simd::F32ToI32(scaledUnpreFloat);
   265   // Multiply all channels with alpha.
   266   i32x4_t scaledPreInt = simd::F32ToI32(simd::MulF32(scaledUnpreFloat, alpha));
   268   // Use the premultiplied color channels and the unpremultiplied alpha channel.
   269   i32x4_t alphaMask = simd::From32<i32x4_t>(0, 0, 0, -1);
   270   return simd::Pick(alphaMask, scaledPreInt, scaledUnpreInt);
   271 }
   273 template<TurbulenceType Type, bool Stitch, typename f32x4_t, typename i32x4_t, typename u8x16_t>
   274 i32x4_t
   275 SVGTurbulenceRenderer<Type,Stitch,f32x4_t,i32x4_t,u8x16_t>::Turbulence(const Point &aPoint) const
   276 {
   277   StitchInfo stitchInfo = mStitchInfo;
   278   f32x4_t sum = simd::FromF32<f32x4_t>(0);
   279   Point vec(aPoint.x * mBaseFrequency.width, aPoint.y * mBaseFrequency.height);
   280   f32x4_t ratio = simd::FromF32<f32x4_t>(1);
   282   for (int octave = 0; octave < mNumOctaves; octave++) {
   283     f32x4_t thisOctave = Noise2(vec, stitchInfo);
   284     if (Type == TURBULENCE_TYPE_TURBULENCE) {
   285       thisOctave = simd::AbsF32(thisOctave);
   286     }
   287     sum = simd::AddF32(sum, simd::DivF32(thisOctave, ratio));
   288     vec = vec * 2;
   289     ratio = simd::MulF32(ratio, simd::FromF32<f32x4_t>(2));
   291     if (Stitch) {
   292       stitchInfo.width *= 2;
   293       stitchInfo.wrapX *= 2;
   294       stitchInfo.height *= 2;
   295       stitchInfo.wrapY *= 2;
   296     }
   297   }
   299   if (Type == TURBULENCE_TYPE_FRACTAL_NOISE) {
   300     sum = simd::DivF32(simd::AddF32(sum, simd::FromF32<f32x4_t>(1)), simd::FromF32<f32x4_t>(2));
   301   }
   302   return ColorToBGRA<f32x4_t,i32x4_t,u8x16_t>(sum);
   303 }
   305 static inline Float
   306 MakeNonNegative(Float aValue, Float aIncrementSize)
   307 {
   308   if (aValue >= 0) {
   309     return aValue;
   310   }
   311   return aValue + ceilf(-aValue / aIncrementSize) * aIncrementSize;
   312 }
   314 template<TurbulenceType Type, bool Stitch, typename f32x4_t, typename i32x4_t, typename u8x16_t>
   315 Point
   316 SVGTurbulenceRenderer<Type,Stitch,f32x4_t,i32x4_t,u8x16_t>::EquivalentNonNegativeOffset(const Point &aOffset) const
   317 {
   318   Size basePeriod = Stitch ? Size(mStitchInfo.width, mStitchInfo.height) :
   319                              Size(sBSize, sBSize);
   320   Size repeatingSize(basePeriod.width / mBaseFrequency.width,
   321                      basePeriod.height / mBaseFrequency.height);
   322   return Point(MakeNonNegative(aOffset.x, repeatingSize.width),
   323                MakeNonNegative(aOffset.y, repeatingSize.height));
   324 }
   326 template<TurbulenceType Type, bool Stitch, typename f32x4_t, typename i32x4_t, typename u8x16_t>
   327 TemporaryRef<DataSourceSurface>
   328 SVGTurbulenceRenderer<Type,Stitch,f32x4_t,i32x4_t,u8x16_t>::Render(const IntSize &aSize, const Point &aOffset) const
   329 {
   330   RefPtr<DataSourceSurface> target =
   331     Factory::CreateDataSourceSurface(aSize, SurfaceFormat::B8G8R8A8);
   332   if (!target) {
   333     return nullptr;
   334   }
   336   uint8_t* targetData = target->GetData();
   337   uint32_t stride = target->Stride();
   339   Point startOffset = EquivalentNonNegativeOffset(aOffset);
   341   for (int32_t y = 0; y < aSize.height; y++) {
   342     for (int32_t x = 0; x < aSize.width; x += 4) {
   343       int32_t targIndex = y * stride + x * 4;
   344       i32x4_t a = Turbulence(startOffset + Point(x, y));
   345       i32x4_t b = Turbulence(startOffset + Point(x + 1, y));
   346       i32x4_t c = Turbulence(startOffset + Point(x + 2, y));
   347       i32x4_t d = Turbulence(startOffset + Point(x + 3, y));
   348       u8x16_t result1234 = simd::PackAndSaturate32To8(a, b, c, d);
   349       simd::Store8(&targetData[targIndex], result1234);
   350     }
   351   }
   353   return target;
   354 }
   356 } // namespace gfx
   357 } // namespace mozilla

mercurial