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.

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

mercurial