Tue, 06 Jan 2015 21:39:09 +0100
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