/src/3rdparty/webkit/Source/WebCore/platform/graphics/filters/FETurbulence.cpp

https://bitbucket.org/ultra_iter/qt-vtl · C++ · 454 lines · 347 code · 56 blank · 51 comment · 46 complexity · e6c2f1191c02bd86eb41b6cafaf3b1bf MD5 · raw file

  1. /*
  2. * Copyright (C) 2004, 2005, 2006, 2007 Nikolas Zimmermann <zimmermann@kde.org>
  3. * Copyright (C) 2004, 2005 Rob Buis <buis@kde.org>
  4. * Copyright (C) 2005 Eric Seidel <eric@webkit.org>
  5. * Copyright (C) 2009 Dirk Schulze <krit@webkit.org>
  6. * Copyright (C) 2010 Renata Hodovan <reni@inf.u-szeged.hu>
  7. * Copyright (C) 2011 Gabor Loki <loki@webkit.org>
  8. *
  9. * This library is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU Library General Public
  11. * License as published by the Free Software Foundation; either
  12. * version 2 of the License, or (at your option) any later version.
  13. *
  14. * This library is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  17. * Library General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU Library General Public License
  20. * along with this library; see the file COPYING.LIB. If not, write to
  21. * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  22. * Boston, MA 02110-1301, USA.
  23. */
  24. #include "config.h"
  25. #if ENABLE(FILTERS)
  26. #include "FETurbulence.h"
  27. #include "Filter.h"
  28. #include "RenderTreeAsText.h"
  29. #include "TextStream.h"
  30. #include <wtf/ByteArray.h>
  31. #include <wtf/MathExtras.h>
  32. #include <wtf/ParallelJobs.h>
  33. namespace WebCore {
  34. /*
  35. Produces results in the range [1, 2**31 - 2]. Algorithm is:
  36. r = (a * r) mod m where a = randAmplitude = 16807 and
  37. m = randMaximum = 2**31 - 1 = 2147483647, r = seed.
  38. See [Park & Miller], CACM vol. 31 no. 10 p. 1195, Oct. 1988
  39. To test: the algorithm should produce the result 1043618065
  40. as the 10,000th generated number if the original seed is 1.
  41. */
  42. static const int s_perlinNoise = 4096;
  43. static const long s_randMaximum = 2147483647; // 2**31 - 1
  44. static const int s_randAmplitude = 16807; // 7**5; primitive root of m
  45. static const int s_randQ = 127773; // m / a
  46. static const int s_randR = 2836; // m % a
  47. FETurbulence::FETurbulence(Filter* filter, TurbulenceType type, float baseFrequencyX, float baseFrequencyY, int numOctaves, float seed, bool stitchTiles)
  48. : FilterEffect(filter)
  49. , m_type(type)
  50. , m_baseFrequencyX(baseFrequencyX)
  51. , m_baseFrequencyY(baseFrequencyY)
  52. , m_numOctaves(numOctaves)
  53. , m_seed(seed)
  54. , m_stitchTiles(stitchTiles)
  55. {
  56. }
  57. PassRefPtr<FETurbulence> FETurbulence::create(Filter* filter, TurbulenceType type, float baseFrequencyX, float baseFrequencyY, int numOctaves, float seed, bool stitchTiles)
  58. {
  59. return adoptRef(new FETurbulence(filter, type, baseFrequencyX, baseFrequencyY, numOctaves, seed, stitchTiles));
  60. }
  61. TurbulenceType FETurbulence::type() const
  62. {
  63. return m_type;
  64. }
  65. bool FETurbulence::setType(TurbulenceType type)
  66. {
  67. if (m_type == type)
  68. return false;
  69. m_type = type;
  70. return true;
  71. }
  72. float FETurbulence::baseFrequencyY() const
  73. {
  74. return m_baseFrequencyY;
  75. }
  76. bool FETurbulence::setBaseFrequencyY(float baseFrequencyY)
  77. {
  78. if (m_baseFrequencyY == baseFrequencyY)
  79. return false;
  80. m_baseFrequencyY = baseFrequencyY;
  81. return true;
  82. }
  83. float FETurbulence::baseFrequencyX() const
  84. {
  85. return m_baseFrequencyX;
  86. }
  87. bool FETurbulence::setBaseFrequencyX(float baseFrequencyX)
  88. {
  89. if (m_baseFrequencyX == baseFrequencyX)
  90. return false;
  91. m_baseFrequencyX = baseFrequencyX;
  92. return true;
  93. }
  94. float FETurbulence::seed() const
  95. {
  96. return m_seed;
  97. }
  98. bool FETurbulence::setSeed(float seed)
  99. {
  100. if (m_seed == seed)
  101. return false;
  102. m_seed = seed;
  103. return true;
  104. }
  105. int FETurbulence::numOctaves() const
  106. {
  107. return m_numOctaves;
  108. }
  109. bool FETurbulence::setNumOctaves(int numOctaves)
  110. {
  111. if (m_numOctaves == numOctaves)
  112. return false;
  113. m_numOctaves = numOctaves;
  114. return true;
  115. }
  116. bool FETurbulence::stitchTiles() const
  117. {
  118. return m_stitchTiles;
  119. }
  120. bool FETurbulence::setStitchTiles(bool stitch)
  121. {
  122. if (m_stitchTiles == stitch)
  123. return false;
  124. m_stitchTiles = stitch;
  125. return true;
  126. }
  127. // The turbulence calculation code is an adapted version of what appears in the SVG 1.1 specification:
  128. // http://www.w3.org/TR/SVG11/filters.html#feTurbulence
  129. FETurbulence::PaintingData::PaintingData(long paintingSeed, const IntSize& paintingSize)
  130. : seed(paintingSeed)
  131. , width(0)
  132. , height(0)
  133. , wrapX(0)
  134. , wrapY(0)
  135. , filterSize(paintingSize)
  136. {
  137. }
  138. // Compute pseudo random number.
  139. inline long FETurbulence::PaintingData::random()
  140. {
  141. long result = s_randAmplitude * (seed % s_randQ) - s_randR * (seed / s_randQ);
  142. if (result <= 0)
  143. result += s_randMaximum;
  144. seed = result;
  145. return result;
  146. }
  147. inline float smoothCurve(float t)
  148. {
  149. return t * t * (3 - 2 * t);
  150. }
  151. inline float linearInterpolation(float t, float a, float b)
  152. {
  153. return a + t * (b - a);
  154. }
  155. inline void FETurbulence::initPaint(PaintingData& paintingData)
  156. {
  157. float normalizationFactor;
  158. // The seed value clamp to the range [1, s_randMaximum - 1].
  159. if (paintingData.seed <= 0)
  160. paintingData.seed = -(paintingData.seed % (s_randMaximum - 1)) + 1;
  161. if (paintingData.seed > s_randMaximum - 1)
  162. paintingData.seed = s_randMaximum - 1;
  163. float* gradient;
  164. for (int channel = 0; channel < 4; ++channel) {
  165. for (int i = 0; i < s_blockSize; ++i) {
  166. paintingData.latticeSelector[i] = i;
  167. gradient = paintingData.gradient[channel][i];
  168. gradient[0] = static_cast<float>((paintingData.random() % (2 * s_blockSize)) - s_blockSize) / s_blockSize;
  169. gradient[1] = static_cast<float>((paintingData.random() % (2 * s_blockSize)) - s_blockSize) / s_blockSize;
  170. normalizationFactor = sqrtf(gradient[0] * gradient[0] + gradient[1] * gradient[1]);
  171. gradient[0] /= normalizationFactor;
  172. gradient[1] /= normalizationFactor;
  173. }
  174. }
  175. for (int i = s_blockSize - 1; i > 0; --i) {
  176. int k = paintingData.latticeSelector[i];
  177. int j = paintingData.random() % s_blockSize;
  178. ASSERT(j >= 0);
  179. ASSERT(j < 2 * s_blockSize + 2);
  180. paintingData.latticeSelector[i] = paintingData.latticeSelector[j];
  181. paintingData.latticeSelector[j] = k;
  182. }
  183. for (int i = 0; i < s_blockSize + 2; ++i) {
  184. paintingData.latticeSelector[s_blockSize + i] = paintingData.latticeSelector[i];
  185. for (int channel = 0; channel < 4; ++channel) {
  186. paintingData.gradient[channel][s_blockSize + i][0] = paintingData.gradient[channel][i][0];
  187. paintingData.gradient[channel][s_blockSize + i][1] = paintingData.gradient[channel][i][1];
  188. }
  189. }
  190. }
  191. inline void checkNoise(int& noiseValue, int limitValue, int newValue)
  192. {
  193. if (noiseValue >= limitValue)
  194. noiseValue -= newValue;
  195. if (noiseValue >= limitValue - 1)
  196. noiseValue -= newValue - 1;
  197. }
  198. float FETurbulence::noise2D(int channel, PaintingData& paintingData, const FloatPoint& noiseVector)
  199. {
  200. struct Noise {
  201. int noisePositionIntegerValue;
  202. float noisePositionFractionValue;
  203. Noise(float component)
  204. {
  205. float position = component + s_perlinNoise;
  206. noisePositionIntegerValue = static_cast<int>(position);
  207. noisePositionFractionValue = position - noisePositionIntegerValue;
  208. }
  209. };
  210. Noise noiseX(noiseVector.x());
  211. Noise noiseY(noiseVector.y());
  212. float* q;
  213. float sx, sy, a, b, u, v;
  214. // If stitching, adjust lattice points accordingly.
  215. if (m_stitchTiles) {
  216. checkNoise(noiseX.noisePositionIntegerValue, paintingData.wrapX, paintingData.width);
  217. checkNoise(noiseY.noisePositionIntegerValue, paintingData.wrapY, paintingData.height);
  218. }
  219. noiseX.noisePositionIntegerValue &= s_blockMask;
  220. noiseY.noisePositionIntegerValue &= s_blockMask;
  221. int latticeIndex = paintingData.latticeSelector[noiseX.noisePositionIntegerValue];
  222. int nextLatticeIndex = paintingData.latticeSelector[(noiseX.noisePositionIntegerValue + 1) & s_blockMask];
  223. sx = smoothCurve(noiseX.noisePositionFractionValue);
  224. sy = smoothCurve(noiseY.noisePositionFractionValue);
  225. // This is taken 1:1 from SVG spec: http://www.w3.org/TR/SVG11/filters.html#feTurbulenceElement.
  226. int temp = paintingData.latticeSelector[latticeIndex + noiseY.noisePositionIntegerValue];
  227. q = paintingData.gradient[channel][temp];
  228. u = noiseX.noisePositionFractionValue * q[0] + noiseY.noisePositionFractionValue * q[1];
  229. temp = paintingData.latticeSelector[nextLatticeIndex + noiseY.noisePositionIntegerValue];
  230. q = paintingData.gradient[channel][temp];
  231. v = (noiseX.noisePositionFractionValue - 1) * q[0] + noiseY.noisePositionFractionValue * q[1];
  232. a = linearInterpolation(sx, u, v);
  233. temp = paintingData.latticeSelector[latticeIndex + noiseY.noisePositionIntegerValue + 1];
  234. q = paintingData.gradient[channel][temp];
  235. u = noiseX.noisePositionFractionValue * q[0] + (noiseY.noisePositionFractionValue - 1) * q[1];
  236. temp = paintingData.latticeSelector[nextLatticeIndex + noiseY.noisePositionIntegerValue + 1];
  237. q = paintingData.gradient[channel][temp];
  238. v = (noiseX.noisePositionFractionValue - 1) * q[0] + (noiseY.noisePositionFractionValue - 1) * q[1];
  239. b = linearInterpolation(sx, u, v);
  240. return linearInterpolation(sy, a, b);
  241. }
  242. unsigned char FETurbulence::calculateTurbulenceValueForPoint(int channel, PaintingData& paintingData, const FloatPoint& point)
  243. {
  244. float tileWidth = paintingData.filterSize.width();
  245. ASSERT(tileWidth > 0);
  246. float tileHeight = paintingData.filterSize.height();
  247. ASSERT(tileHeight > 0);
  248. // Adjust the base frequencies if necessary for stitching.
  249. if (m_stitchTiles) {
  250. // When stitching tiled turbulence, the frequencies must be adjusted
  251. // so that the tile borders will be continuous.
  252. if (m_baseFrequencyX) {
  253. float lowFrequency = floorf(tileWidth * m_baseFrequencyX) / tileWidth;
  254. float highFrequency = ceilf(tileWidth * m_baseFrequencyX) / tileWidth;
  255. // BaseFrequency should be non-negative according to the standard.
  256. if (m_baseFrequencyX / lowFrequency < highFrequency / m_baseFrequencyX)
  257. m_baseFrequencyX = lowFrequency;
  258. else
  259. m_baseFrequencyX = highFrequency;
  260. }
  261. if (m_baseFrequencyY) {
  262. float lowFrequency = floorf(tileHeight * m_baseFrequencyY) / tileHeight;
  263. float highFrequency = ceilf(tileHeight * m_baseFrequencyY) / tileHeight;
  264. if (m_baseFrequencyY / lowFrequency < highFrequency / m_baseFrequencyY)
  265. m_baseFrequencyY = lowFrequency;
  266. else
  267. m_baseFrequencyY = highFrequency;
  268. }
  269. // Set up TurbulenceInitial stitch values.
  270. paintingData.width = roundf(tileWidth * m_baseFrequencyX);
  271. paintingData.wrapX = s_perlinNoise + paintingData.width;
  272. paintingData.height = roundf(tileHeight * m_baseFrequencyY);
  273. paintingData.wrapY = s_perlinNoise + paintingData.height;
  274. }
  275. float turbulenceFunctionResult = 0;
  276. FloatPoint noiseVector(point.x() * m_baseFrequencyX, point.y() * m_baseFrequencyY);
  277. float ratio = 1;
  278. for (int octave = 0; octave < m_numOctaves; ++octave) {
  279. if (m_type == FETURBULENCE_TYPE_FRACTALNOISE)
  280. turbulenceFunctionResult += noise2D(channel, paintingData, noiseVector) / ratio;
  281. else
  282. turbulenceFunctionResult += fabsf(noise2D(channel, paintingData, noiseVector)) / ratio;
  283. noiseVector.setX(noiseVector.x() * 2);
  284. noiseVector.setY(noiseVector.y() * 2);
  285. ratio *= 2;
  286. if (m_stitchTiles) {
  287. // Update stitch values. Subtracting s_perlinNoiseoise before the multiplication and
  288. // adding it afterward simplifies to subtracting it once.
  289. paintingData.width *= 2;
  290. paintingData.wrapX = 2 * paintingData.wrapX - s_perlinNoise;
  291. paintingData.height *= 2;
  292. paintingData.wrapY = 2 * paintingData.wrapY - s_perlinNoise;
  293. }
  294. }
  295. // The value of turbulenceFunctionResult comes from ((turbulenceFunctionResult * 255) + 255) / 2 by fractalNoise
  296. // and (turbulenceFunctionResult * 255) by turbulence.
  297. if (m_type == FETURBULENCE_TYPE_FRACTALNOISE)
  298. turbulenceFunctionResult = turbulenceFunctionResult * 0.5f + 0.5f;
  299. // Clamp result
  300. turbulenceFunctionResult = std::max(std::min(turbulenceFunctionResult, 1.f), 0.f);
  301. return static_cast<unsigned char>(turbulenceFunctionResult * 255);
  302. }
  303. inline void FETurbulence::fillRegion(ByteArray* pixelArray, PaintingData& paintingData, int startY, int endY)
  304. {
  305. IntRect filterRegion = absolutePaintRect();
  306. IntPoint point(0, filterRegion.y() + startY);
  307. int indexOfPixelChannel = startY * (filterRegion.width() << 2);
  308. int channel;
  309. for (int y = startY; y < endY; ++y) {
  310. point.setY(point.y() + 1);
  311. point.setX(filterRegion.x());
  312. for (int x = 0; x < filterRegion.width(); ++x) {
  313. point.setX(point.x() + 1);
  314. for (channel = 0; channel < 4; ++channel, ++indexOfPixelChannel)
  315. pixelArray->set(indexOfPixelChannel, calculateTurbulenceValueForPoint(channel, paintingData, filter()->mapAbsolutePointToLocalPoint(point)));
  316. }
  317. }
  318. }
  319. #if ENABLE(PARALLEL_JOBS)
  320. void FETurbulence::fillRegionWorker(FillRegionParameters* parameters)
  321. {
  322. parameters->filter->fillRegion(parameters->pixelArray, *parameters->paintingData, parameters->startY, parameters->endY);
  323. }
  324. #endif // ENABLE(PARALLEL_JOBS)
  325. void FETurbulence::apply()
  326. {
  327. if (hasResult())
  328. return;
  329. ByteArray* pixelArray = createUnmultipliedImageResult();
  330. if (!pixelArray)
  331. return;
  332. if (absolutePaintRect().isEmpty())
  333. return;
  334. PaintingData paintingData(m_seed, roundedIntSize(filterPrimitiveSubregion().size()));
  335. initPaint(paintingData);
  336. #if ENABLE(PARALLEL_JOBS)
  337. int optimalThreadNumber = (absolutePaintRect().width() * absolutePaintRect().height()) / s_minimalRectDimension;
  338. if (optimalThreadNumber > 1) {
  339. // Initialize parallel jobs
  340. ParallelJobs<FillRegionParameters> parallelJobs(&WebCore::FETurbulence::fillRegionWorker, optimalThreadNumber);
  341. // Fill the parameter array
  342. int i = parallelJobs.numberOfJobs();
  343. if (i > 1) {
  344. int startY = 0;
  345. int stepY = absolutePaintRect().height() / i;
  346. for (; i > 0; --i) {
  347. FillRegionParameters& params = parallelJobs.parameter(i-1);
  348. params.filter = this;
  349. params.pixelArray = pixelArray;
  350. params.paintingData = &paintingData;
  351. params.startY = startY;
  352. if (i != 1) {
  353. params.endY = startY + stepY;
  354. startY = startY + stepY;
  355. } else
  356. params.endY = absolutePaintRect().height();
  357. }
  358. // Execute parallel jobs
  359. parallelJobs.execute();
  360. return;
  361. }
  362. }
  363. // Fallback to sequential mode if there is no room for a new thread or the paint area is too small
  364. #endif // ENABLE(PARALLEL_JOBS)
  365. fillRegion(pixelArray, paintingData, 0, absolutePaintRect().height());
  366. }
  367. void FETurbulence::dump()
  368. {
  369. }
  370. static TextStream& operator<<(TextStream& ts, const TurbulenceType& type)
  371. {
  372. switch (type) {
  373. case FETURBULENCE_TYPE_UNKNOWN:
  374. ts << "UNKNOWN";
  375. break;
  376. case FETURBULENCE_TYPE_TURBULENCE:
  377. ts << "TURBULANCE";
  378. break;
  379. case FETURBULENCE_TYPE_FRACTALNOISE:
  380. ts << "NOISE";
  381. break;
  382. }
  383. return ts;
  384. }
  385. TextStream& FETurbulence::externalRepresentation(TextStream& ts, int indent) const
  386. {
  387. writeIndent(ts, indent);
  388. ts << "[feTurbulence";
  389. FilterEffect::externalRepresentation(ts);
  390. ts << " type=\"" << type() << "\" "
  391. << "baseFrequency=\"" << baseFrequencyX() << ", " << baseFrequencyY() << "\" "
  392. << "seed=\"" << seed() << "\" "
  393. << "numOctaves=\"" << numOctaves() << "\" "
  394. << "stitchTiles=\"" << stitchTiles() << "\"]\n";
  395. return ts;
  396. }
  397. } // namespace WebCore
  398. #endif // ENABLE(FILTERS)