mathematical 1.4.2 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (149) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +11 -21
  3. data/ext/mathematical/extconf.rb +21 -12
  4. data/ext/mathematical/lasem/Makefile +10 -10
  5. data/ext/mathematical/lasem/docs/Makefile +9 -9
  6. data/ext/mathematical/lasem/docs/reference/Makefile +9 -9
  7. data/ext/mathematical/lasem/docs/reference/lasem/Makefile +15 -9
  8. data/ext/mathematical/lasem/docs/reference/lasem/lasem-decl-list.txt +245 -0
  9. data/ext/mathematical/lasem/docs/reference/lasem/lasem-decl.txt +856 -0
  10. data/ext/mathematical/lasem/docs/reference/lasem/lasem-overrides.txt +0 -0
  11. data/ext/mathematical/lasem/itex2mml/Makefile +9 -9
  12. data/ext/mathematical/lasem/src/Makefile +34 -13
  13. data/ext/mathematical/lasem/src/lasemrender.c +13 -7
  14. data/ext/mathematical/lasem/src/lsmdomenumtypes.c +99 -0
  15. data/ext/mathematical/lasem/src/lsmdomenumtypes.h +26 -0
  16. data/ext/mathematical/lasem/src/lsmmathmlenums.c +24 -0
  17. data/ext/mathematical/lasem/src/lsmmathmlenums.h +12 -1
  18. data/ext/mathematical/lasem/src/lsmmathmlenumtypes.c +793 -0
  19. data/ext/mathematical/lasem/src/lsmmathmlenumtypes.h +96 -0
  20. data/ext/mathematical/lasem/src/lsmmathmlspaceelement.c +14 -0
  21. data/ext/mathematical/lasem/src/lsmmathmlspaceelement.h +1 -1
  22. data/ext/mathematical/lasem/src/lsmmathmltraits.c +24 -0
  23. data/ext/mathematical/lasem/src/lsmmathmltraits.h +1 -0
  24. data/ext/mathematical/lasem/src/lsmsvgattributes.h +50 -0
  25. data/ext/mathematical/lasem/src/lsmsvgdocument.c +18 -0
  26. data/ext/mathematical/lasem/src/lsmsvgenums.c +130 -0
  27. data/ext/mathematical/lasem/src/lsmsvgenums.h +59 -0
  28. data/ext/mathematical/lasem/src/lsmsvgenumtypes.c +1254 -0
  29. data/ext/mathematical/lasem/src/lsmsvgenumtypes.h +129 -0
  30. data/ext/mathematical/lasem/src/lsmsvgfiltercolormatrix.c +115 -0
  31. data/ext/mathematical/lasem/src/lsmsvgfiltercolormatrix.h +58 -0
  32. data/ext/mathematical/lasem/src/lsmsvgfilterconvolvematrix.c +206 -0
  33. data/ext/mathematical/lasem/src/lsmsvgfilterconvolvematrix.h +64 -0
  34. data/ext/mathematical/lasem/src/lsmsvgfilterdisplacementmap.c +124 -0
  35. data/ext/mathematical/lasem/src/lsmsvgfilterdisplacementmap.h +60 -0
  36. data/ext/mathematical/lasem/src/lsmsvgfilterimage.c +167 -0
  37. data/ext/mathematical/lasem/src/lsmsvgfilterimage.h +61 -0
  38. data/ext/mathematical/lasem/src/lsmsvgfiltermorphology.c +116 -0
  39. data/ext/mathematical/lasem/src/lsmsvgfiltermorphology.h +58 -0
  40. data/ext/mathematical/lasem/src/lsmsvgfilterspecularlighting.c +9 -2
  41. data/ext/mathematical/lasem/src/lsmsvgfiltersurface.c +1169 -87
  42. data/ext/mathematical/lasem/src/lsmsvgfiltersurface.h +28 -2
  43. data/ext/mathematical/lasem/src/lsmsvgfilterturbulence.c +142 -0
  44. data/ext/mathematical/lasem/src/lsmsvgfilterturbulence.h +61 -0
  45. data/ext/mathematical/lasem/src/lsmsvgtraits.c +249 -0
  46. data/ext/mathematical/lasem/src/lsmsvgtraits.h +18 -0
  47. data/ext/mathematical/lasem/src/lsmsvgtypes.h +6 -0
  48. data/ext/mathematical/lasem/src/lsmsvgview.c +267 -66
  49. data/ext/mathematical/lasem/src/lsmsvgview.h +23 -0
  50. data/ext/mathematical/lasem/src/lsmtraits.c +53 -1
  51. data/ext/mathematical/lasem/src/lsmtraits.h +2 -0
  52. data/ext/mathematical/lasem/tests/Makefile +26 -15
  53. data/ext/mathematical/lasem/tests/filter.c +152 -0
  54. data/ext/mathematical/lasem/tests/lsmtest.c +34 -30
  55. data/ext/mathematical/lasem/tests/suite.c +5 -2
  56. data/ext/mathematical/lib/libmtex2MML.a +0 -0
  57. data/ext/mathematical/mtex2MML/build/CMakeCache.txt +425 -0
  58. data/ext/mathematical/mtex2MML/build/CMakeFiles/2.8.10.1/CMakeCCompiler.cmake +55 -0
  59. data/ext/mathematical/mtex2MML/build/CMakeFiles/2.8.10.1/CMakeCXXCompiler.cmake +56 -0
  60. data/ext/mathematical/mtex2MML/build/CMakeFiles/2.8.10.1/CMakeSystem.cmake +15 -0
  61. data/ext/mathematical/mtex2MML/build/CMakeFiles/2.8.10.1/CompilerIdC/CMakeCCompilerId.c +393 -0
  62. data/ext/mathematical/mtex2MML/build/CMakeFiles/CMakeDirectoryInformation.cmake +16 -0
  63. data/ext/mathematical/mtex2MML/build/CMakeFiles/CMakeRuleHashes.txt +34 -0
  64. data/ext/mathematical/mtex2MML/build/CMakeFiles/Continuous.dir/DependInfo.cmake +27 -0
  65. data/ext/mathematical/mtex2MML/build/CMakeFiles/Continuous.dir/cmake_clean.cmake +8 -0
  66. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousBuild.dir/DependInfo.cmake +27 -0
  67. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousBuild.dir/cmake_clean.cmake +8 -0
  68. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousConfigure.dir/DependInfo.cmake +27 -0
  69. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousConfigure.dir/cmake_clean.cmake +8 -0
  70. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousCoverage.dir/DependInfo.cmake +27 -0
  71. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousCoverage.dir/cmake_clean.cmake +8 -0
  72. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousMemCheck.dir/DependInfo.cmake +27 -0
  73. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousMemCheck.dir/cmake_clean.cmake +8 -0
  74. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousStart.dir/DependInfo.cmake +27 -0
  75. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousStart.dir/cmake_clean.cmake +8 -0
  76. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousSubmit.dir/DependInfo.cmake +27 -0
  77. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousSubmit.dir/cmake_clean.cmake +8 -0
  78. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousTest.dir/DependInfo.cmake +27 -0
  79. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousTest.dir/cmake_clean.cmake +8 -0
  80. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousUpdate.dir/DependInfo.cmake +27 -0
  81. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousUpdate.dir/cmake_clean.cmake +8 -0
  82. data/ext/mathematical/mtex2MML/build/CMakeFiles/Experimental.dir/DependInfo.cmake +27 -0
  83. data/ext/mathematical/mtex2MML/build/CMakeFiles/Experimental.dir/cmake_clean.cmake +8 -0
  84. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalBuild.dir/DependInfo.cmake +27 -0
  85. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalBuild.dir/cmake_clean.cmake +8 -0
  86. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalConfigure.dir/DependInfo.cmake +27 -0
  87. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalConfigure.dir/cmake_clean.cmake +8 -0
  88. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalCoverage.dir/DependInfo.cmake +27 -0
  89. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalCoverage.dir/cmake_clean.cmake +8 -0
  90. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalMemCheck.dir/DependInfo.cmake +27 -0
  91. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalMemCheck.dir/cmake_clean.cmake +8 -0
  92. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalStart.dir/DependInfo.cmake +27 -0
  93. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalStart.dir/cmake_clean.cmake +8 -0
  94. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalSubmit.dir/DependInfo.cmake +27 -0
  95. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalSubmit.dir/cmake_clean.cmake +8 -0
  96. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalTest.dir/DependInfo.cmake +27 -0
  97. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalTest.dir/cmake_clean.cmake +8 -0
  98. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalUpdate.dir/DependInfo.cmake +27 -0
  99. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalUpdate.dir/cmake_clean.cmake +8 -0
  100. data/ext/mathematical/mtex2MML/build/CMakeFiles/Makefile.cmake +95 -0
  101. data/ext/mathematical/mtex2MML/build/CMakeFiles/Nightly.dir/DependInfo.cmake +27 -0
  102. data/ext/mathematical/mtex2MML/build/CMakeFiles/Nightly.dir/cmake_clean.cmake +8 -0
  103. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyBuild.dir/DependInfo.cmake +27 -0
  104. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyBuild.dir/cmake_clean.cmake +8 -0
  105. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyConfigure.dir/DependInfo.cmake +27 -0
  106. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyConfigure.dir/cmake_clean.cmake +8 -0
  107. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyCoverage.dir/DependInfo.cmake +27 -0
  108. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyCoverage.dir/cmake_clean.cmake +8 -0
  109. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyMemCheck.dir/DependInfo.cmake +27 -0
  110. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyMemCheck.dir/cmake_clean.cmake +8 -0
  111. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyMemoryCheck.dir/DependInfo.cmake +27 -0
  112. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyMemoryCheck.dir/cmake_clean.cmake +8 -0
  113. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyStart.dir/DependInfo.cmake +27 -0
  114. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyStart.dir/cmake_clean.cmake +8 -0
  115. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlySubmit.dir/DependInfo.cmake +27 -0
  116. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlySubmit.dir/cmake_clean.cmake +8 -0
  117. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyTest.dir/DependInfo.cmake +27 -0
  118. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyTest.dir/cmake_clean.cmake +8 -0
  119. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyUpdate.dir/DependInfo.cmake +27 -0
  120. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyUpdate.dir/cmake_clean.cmake +8 -0
  121. data/ext/mathematical/mtex2MML/build/CMakeFiles/TargetDirectories.txt +34 -0
  122. data/ext/mathematical/mtex2MML/build/CMakeFiles/format.dir/DependInfo.cmake +27 -0
  123. data/ext/mathematical/mtex2MML/build/CMakeFiles/format.dir/cmake_clean.cmake +8 -0
  124. data/ext/mathematical/mtex2MML/build/CMakeFiles/libmtex2MML.dir/DependInfo.cmake +44 -0
  125. data/ext/mathematical/mtex2MML/build/CMakeFiles/libmtex2MML.dir/cmake_clean.cmake +19 -0
  126. data/ext/mathematical/mtex2MML/build/CMakeFiles/libmtex2MML.dir/link.txt +1 -0
  127. data/ext/mathematical/mtex2MML/build/CMakeFiles/libmtex2MML_static.dir/DependInfo.cmake +43 -0
  128. data/ext/mathematical/mtex2MML/build/CMakeFiles/libmtex2MML_static.dir/cmake_clean.cmake +18 -0
  129. data/ext/mathematical/mtex2MML/build/CMakeFiles/libmtex2MML_static.dir/cmake_clean_target.cmake +3 -0
  130. data/ext/mathematical/mtex2MML/build/CMakeFiles/libmtex2MML_static.dir/link.txt +2 -0
  131. data/ext/mathematical/mtex2MML/build/CMakeFiles/memcheck.dir/DependInfo.cmake +27 -0
  132. data/ext/mathematical/mtex2MML/build/CMakeFiles/memcheck.dir/cmake_clean.cmake +8 -0
  133. data/ext/mathematical/mtex2MML/build/CMakeFiles/mtex2MML.dir/DependInfo.cmake +44 -0
  134. data/ext/mathematical/mtex2MML/build/CMakeFiles/mtex2MML.dir/cmake_clean.cmake +19 -0
  135. data/ext/mathematical/mtex2MML/build/CMakeFiles/mtex2MML.dir/link.txt +1 -0
  136. data/ext/mathematical/mtex2MML/build/CMakeFiles/mtex2MML_clar.dir/DependInfo.cmake +59 -0
  137. data/ext/mathematical/mtex2MML/build/CMakeFiles/mtex2MML_clar.dir/cmake_clean.cmake +35 -0
  138. data/ext/mathematical/mtex2MML/build/CMakeFiles/mtex2MML_clar.dir/link.txt +1 -0
  139. data/ext/mathematical/mtex2MML/build/CTestTestfile.cmake +7 -0
  140. data/ext/mathematical/mtex2MML/build/Makefile +1332 -0
  141. data/ext/mathematical/mtex2MML/build/cmake_install.cmake +43 -0
  142. data/ext/mathematical/mtex2MML/build/lexer.c +8877 -0
  143. data/ext/mathematical/mtex2MML/build/libmtex2MML.a +0 -0
  144. data/ext/mathematical/mtex2MML/build/mtex2mml_export.h +35 -0
  145. data/ext/mathematical/mtex2MML/build/parser.c +10202 -0
  146. data/ext/mathematical/mtex2MML/build/parser.h +619 -0
  147. data/ext/mathematical/mtex2MML/src/mtex2MML.h +1 -1
  148. data/lib/mathematical/version.rb +1 -1
  149. metadata +115 -2
@@ -21,6 +21,10 @@
21
21
  * Authors:
22
22
  * Caleb Moore <c.moore@student.unsw.edu.au>
23
23
  * Emmanuel Pacaud <emmanuel@gnome.org>
24
+ * Mario Klingemann <mario@quasimondo.com>
25
+ *
26
+ * Image manipulation routines in this file are an adaptation of the code
27
+ * of librsvg: https://git.gnome.org/browse/librsvg
24
28
  */
25
29
 
26
30
  #include <lsmsvgfiltersurface.h>
@@ -29,6 +33,8 @@
29
33
  #include <math.h>
30
34
  #include <string.h>
31
35
 
36
+ static const int channelmap[4] = {2, 1, 0, 3};
37
+
32
38
  struct _LsmSvgFilterSurface {
33
39
  char *name;
34
40
  cairo_surface_t *surface;
@@ -141,93 +147,270 @@ lsm_svg_filter_surface_unref (LsmSvgFilterSurface *filter_surface)
141
147
 
142
148
  G_DEFINE_BOXED_TYPE (LsmSvgFilterSurface, lsm_svg_filter_surface, lsm_svg_filter_surface_ref, lsm_svg_filter_surface_unref)
143
149
 
150
+ /*
151
+ * The stack blur algorithm was invented by Mario Klingemann <mario@quasimondo.com>
152
+ * http://incubator.quasimondo.com/processing/fast_blur_deluxe.php
153
+ *
154
+ * Compared to Mario's original source code, the lookup table is removed as the benefit
155
+ * doesn't worth the memory usage in case of large radiuses. Also, the following code adds
156
+ * alpha channel support and different radius for vertical and horizontal directions.
157
+ */
158
+
144
159
  static void
145
- box_blur (cairo_surface_t *in,
146
- cairo_surface_t *output,
147
- int kw,
148
- int kh,
149
- int shiftx,
150
- int shifty,
151
- int x0,
152
- int y0,
153
- int x1,
154
- int y1)
160
+ stack_blur (cairo_surface_t *input, cairo_surface_t *output, int rx, int ry)
155
161
  {
156
- gint ch;
157
- gint x, y;
158
- gint offset;
159
- gint rowstride;
160
- guchar *intermediate;
161
- guchar *in_pixels;
162
- guchar *output_pixels;
163
- gint sum;
164
-
165
- in_pixels = cairo_image_surface_get_data (in);
166
- output_pixels = cairo_image_surface_get_data (output);
167
-
168
- rowstride = cairo_image_surface_get_stride (in);
169
-
170
- intermediate = g_new (guchar, MAX (kw, kh));
171
-
172
- if (kw > 1) {
173
- offset = shiftx - kw / 2;
174
- for (ch = 0; ch < 4; ch++) {
175
- for (y = y0; y < y1; y++) {
176
- sum = 0;
177
- for (x = x0; x < x0 + kw; x++) {
178
- sum += (intermediate[x % kw] = in_pixels[4 * x + y * rowstride + ch]);
179
- if (x + offset >= 0 && x + offset < x1)
180
- output_pixels[4 * (x + offset) + y * rowstride + ch] = sum / kw;
181
- }
182
- for (x = x0 + kw; x < x1; x++) {
183
- sum -= intermediate[x % kw];
184
- sum += (intermediate[x % kw] = in_pixels[4 * x + y * rowstride + ch]);
185
- if (x + offset >= 0 && x + offset < x1)
186
- output_pixels[4 * (x + offset) + y * rowstride + ch] = sum / kw;
187
- }
188
- for (x = x1; x < x1 + kw; x++) {
189
- sum -= intermediate[x % kw];
190
- if (x + offset >= 0 && x + offset < x1)
191
- output_pixels[4 * (x + offset) + y * rowstride + ch] = sum / kw;
192
- }
193
- }
194
- }
195
- in_pixels = output_pixels;
196
- }
197
-
198
- if (kh > 1) {
199
- offset = shifty - kh / 2;
200
- for (ch = 0; ch < 4; ch++) {
201
- for (x = x0; x < x1; x++) {
202
- sum = 0;
203
-
204
- for (y = y0; y < y0 + kh; y++) {
205
- sum += (intermediate[y % kh] = in_pixels[4 * x + y * rowstride + ch]);
206
- if (y + offset >= 0 && y + offset < y1)
207
- output_pixels[4 * x + (y + offset) * rowstride + ch] = sum / kh;
208
- }
209
- for (y = y0 + kh; y < y1; y++) {
210
- sum -= intermediate[y % kh];
211
- sum += (intermediate[y % kh] = in_pixels[4 * x + y * rowstride + ch]);
212
- if (y + offset >= 0 && y + offset < y1)
213
- output_pixels[4 * x + (y + offset) * rowstride + ch] = sum / kh;
214
- }
215
- for (y = y1; y < y1 + kh; y++) {
216
- sum -= intermediate[y % kh];
217
- if (y + offset >= 0 && y + offset < y1)
218
- output_pixels[4 * x + (y + offset) * rowstride + ch] = sum / kh;
219
- }
220
- }
221
- }
222
- }
223
-
224
- g_free (intermediate);
162
+ guint32 *input_pixels;
163
+ guint32 *output_pixels;
164
+ int w, h, wm, hm, wh, div;
165
+ int *r, *g, *b, *a;
166
+
167
+ int rsum,gsum,bsum,asum,x,y,i,p,yp,yi,yw;
168
+ int *vmin;
169
+ int divsum;
170
+
171
+ yw=yi=0;
172
+
173
+ int *stack;
174
+ int stackpointer;
175
+ int stackstart;
176
+ int *sir;
177
+ int rbs;
178
+ int r1;
179
+ int routsum,goutsum,boutsum, aoutsum;
180
+ int rinsum,ginsum,binsum, ainsum;
181
+ int rowstride;
182
+
183
+ g_return_if_fail (rx > 0 || ry > 0);
184
+
185
+ input_pixels = (guint32 *) cairo_image_surface_get_data (input);
186
+ output_pixels = (guint32 *) cairo_image_surface_get_data (output);
187
+ rowstride = cairo_image_surface_get_stride (input);
188
+ w = cairo_image_surface_get_width (input);
189
+ h = cairo_image_surface_get_height (input);
190
+
191
+ g_return_if_fail (cairo_image_surface_get_width (output) == w);
192
+ g_return_if_fail (cairo_image_surface_get_height (output) == h);
193
+ g_return_if_fail (cairo_image_surface_get_stride (output) == rowstride);
194
+
195
+ wm = w - 1;
196
+ hm = h - 1;
197
+ wh = w * h;
198
+
199
+ r = g_new (int, wh);
200
+ g = g_new (int, wh);
201
+ b = g_new (int, wh);
202
+ a = g_new (int, wh);
203
+
204
+ div = 2 * rx + 1;
205
+ divsum = (div + 1) >> 1;
206
+ divsum *= divsum;
207
+ stack = g_new (int, div * 4);
208
+ r1 = rx + 1;
209
+
210
+ vmin = g_new (int, w);
211
+ for (y =0; y < h; y++) {
212
+ rinsum=ginsum=binsum=ainsum=routsum=goutsum=boutsum=aoutsum=rsum=gsum=bsum=asum=0;
213
+ yi = y * rowstride / 4;
214
+
215
+ for (i = -rx; i <= rx; i++) {
216
+ p = input_pixels [yi + MIN (wm, MAX (i, 0))];
217
+ sir = &stack [4 * (i + rx)];
218
+ sir[0]=(p & 0x00ff0000)>>16;
219
+ sir[1]=(p & 0x0000ff00)>>8;
220
+ sir[2]=(p & 0x000000ff);
221
+ sir[3]=(p & 0xff0000ff)>>24;
222
+ rbs= r1 - ABS (i);
223
+ rsum+=sir[0]*rbs;
224
+ gsum+=sir[1]*rbs;
225
+ bsum+=sir[2]*rbs;
226
+ asum+=sir[3]*rbs;
227
+ if (i>0){
228
+ rinsum+=sir[0];
229
+ ginsum+=sir[1];
230
+ binsum+=sir[2];
231
+ ainsum+=sir[3];
232
+ } else {
233
+ routsum+=sir[0];
234
+ goutsum+=sir[1];
235
+ boutsum+=sir[2];
236
+ aoutsum+=sir[3];
237
+ }
238
+ }
239
+ stackpointer=rx;
240
+
241
+ for (x=0;x<w;x++){
242
+
243
+ r[yi] = rsum / divsum;
244
+ g[yi] = gsum / divsum;
245
+ b[yi] = bsum / divsum;
246
+ a[yi] = asum / divsum;
247
+ rsum-=routsum;
248
+ gsum-=goutsum;
249
+ bsum-=boutsum;
250
+ asum-=aoutsum;
251
+
252
+ stackstart=stackpointer-rx+div;
253
+ sir = &stack [4 * (stackstart % div)];
254
+
255
+ routsum-=sir[0];
256
+ goutsum-=sir[1];
257
+ boutsum-=sir[2];
258
+ aoutsum-=sir[3];
259
+
260
+ if(y==0){
261
+ vmin[x]=MIN (x + rx + 1, wm);
262
+ }
263
+ p = input_pixels [yw + vmin[x]];
264
+
265
+ sir[0]=(p & 0x00ff0000)>>16;
266
+ sir[1]=(p & 0x0000ff00)>>8;
267
+ sir[2]=(p & 0x000000ff);
268
+ sir[3]=(p & 0xff000000)>>24;
269
+
270
+ rinsum+=sir[0];
271
+ ginsum+=sir[1];
272
+ binsum+=sir[2];
273
+ ainsum+=sir[3];
274
+
275
+ rsum+=rinsum;
276
+ gsum+=ginsum;
277
+ bsum+=binsum;
278
+ asum+=ainsum;
279
+
280
+ stackpointer = (stackpointer + 1) % div;
281
+ sir = &stack [4 * ((stackpointer) % div)];
282
+
283
+ routsum+=sir[0];
284
+ goutsum+=sir[1];
285
+ boutsum+=sir[2];
286
+ aoutsum+=sir[3];
287
+
288
+ rinsum-=sir[0];
289
+ ginsum-=sir[1];
290
+ binsum-=sir[2];
291
+ ainsum-=sir[3];
292
+
293
+ yi++;
294
+ }
295
+ yw+=w;
296
+ }
297
+ g_free (vmin);
298
+ g_free (stack);
299
+
300
+ div = 2 * ry + 1;
301
+ divsum = (div + 1) >> 1;
302
+ divsum *= divsum;
303
+
304
+ stack = g_new0 (int, div * 4);
305
+ r1 = ry + 1;
306
+
307
+ vmin = g_new0 (int, h);
308
+ for (x=0;x<w;x++){
309
+ rinsum=ginsum=binsum=ainsum=routsum=goutsum=boutsum=aoutsum=rsum=gsum=bsum=asum=0;
310
+ yp=-ry*w;
311
+ for(i=-ry;i<=ry;i++){
312
+ yi= MAX(0,yp)+x;
313
+
314
+ sir = &stack [4 * (i + ry)];
315
+
316
+ sir[0]=r[yi];
317
+ sir[1]=g[yi];
318
+ sir[2]=b[yi];
319
+ sir[3]=a[yi];
320
+
321
+ rbs=r1 - ABS(i);
322
+
323
+ rsum+=r[yi]*rbs;
324
+ gsum+=g[yi]*rbs;
325
+ bsum+=b[yi]*rbs;
326
+ asum+=a[yi]*rbs;
327
+
328
+ if (i>0){
329
+ rinsum+=sir[0];
330
+ ginsum+=sir[1];
331
+ binsum+=sir[2];
332
+ ainsum+=sir[3];
333
+ } else {
334
+ routsum+=sir[0];
335
+ goutsum+=sir[1];
336
+ boutsum+=sir[2];
337
+ aoutsum+=sir[3];
338
+ }
339
+
340
+ if(i<hm){
341
+ yp+=w;
342
+ }
343
+ }
344
+ yi=x;
345
+ stackpointer=ry;
346
+ for (y=0;y<h;y++){
347
+ output_pixels [yi] =
348
+ ((asum / divsum) << 24) |
349
+ ((rsum / divsum) << 16) |
350
+ ((gsum / divsum) << 8) |
351
+ (bsum / divsum);
352
+ rsum-=routsum;
353
+ gsum-=goutsum;
354
+ bsum-=boutsum;
355
+ asum-=aoutsum;
356
+
357
+ stackstart=stackpointer-ry+div;
358
+ sir = &stack [4 * (stackstart % div)];
359
+
360
+ routsum-=sir[0];
361
+ goutsum-=sir[1];
362
+ boutsum-=sir[2];
363
+ aoutsum-=sir[3];
364
+
365
+ if(x==0) {
366
+ vmin[y] = MIN(y+r1,hm)*w;
367
+ }
368
+ p=x+vmin[y];
369
+
370
+ sir[0]=r[p];
371
+ sir[1]=g[p];
372
+ sir[2]=b[p];
373
+ sir[3]=a[p];
374
+
375
+ rinsum+=sir[0];
376
+ ginsum+=sir[1];
377
+ binsum+=sir[2];
378
+ ainsum+=sir[3];
379
+
380
+ rsum+=rinsum;
381
+ gsum+=ginsum;
382
+ bsum+=binsum;
383
+ asum+=ainsum;
384
+
385
+ stackpointer=(stackpointer+1)%div;
386
+ sir = &stack[4 * stackpointer];
387
+
388
+ routsum+=sir[0];
389
+ goutsum+=sir[1];
390
+ boutsum+=sir[2];
391
+ aoutsum+=sir[3];
392
+
393
+ rinsum-=sir[0];
394
+ ginsum-=sir[1];
395
+ binsum-=sir[2];
396
+ ainsum-=sir[3];
397
+
398
+ yi+= rowstride / 4;
399
+ }
400
+ }
401
+ g_free (vmin);
402
+ g_free (stack);
403
+
404
+ g_free (r);
405
+ g_free (g);
406
+ g_free (b);
407
+ g_free (a);
225
408
  }
226
409
 
227
410
  void
228
- lsm_svg_filter_surface_fast_blur (LsmSvgFilterSurface *input,
229
- LsmSvgFilterSurface *output,
230
- double sx, double sy)
411
+ lsm_svg_filter_surface_blur (LsmSvgFilterSurface *input,
412
+ LsmSvgFilterSurface *output,
413
+ double sx, double sy)
231
414
  {
232
415
  int kx, ky;
233
416
  int width, height;
@@ -247,6 +430,9 @@ lsm_svg_filter_surface_fast_blur (LsmSvgFilterSurface *input,
247
430
  height != cairo_image_surface_get_height (output->surface))
248
431
  return;
249
432
 
433
+ if (width < 1 || height < 1)
434
+ return;
435
+
250
436
  if (kx > 1 || ky > 1) {
251
437
  int x1, y1, x2, y2;
252
438
  cairo_surface_t *blur_surface;
@@ -271,9 +457,7 @@ lsm_svg_filter_surface_fast_blur (LsmSvgFilterSurface *input,
271
457
  } else
272
458
  blur_surface = output->surface;
273
459
 
274
- box_blur (input->surface, blur_surface, kx, ky, 0, 0, x1, y1, x2, y2);
275
- box_blur (blur_surface, blur_surface, kx, ky, (kx + 1) % 2, (ky + 1) % 2, x1, y1, x2, y2);
276
- box_blur (blur_surface, blur_surface, kx + (kx + 1) % 2, ky + (ky + 1) % 2, 0, 0, x1, y1, x2, y2);
460
+ stack_blur (input->surface, blur_surface, kx, ky);
277
461
 
278
462
  cairo_surface_mark_dirty (blur_surface);
279
463
 
@@ -424,14 +608,14 @@ lsm_svg_filter_surface_tile (LsmSvgFilterSurface *input, LsmSvgFilterSurface *ou
424
608
 
425
609
  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, input->subregion.width, input->subregion.height);
426
610
  cairo = cairo_create (surface);
427
- cairo_set_source_surface (cairo, input->surface, input->subregion.x, input->subregion.y);
611
+ cairo_set_source_surface (cairo, input->surface, -input->subregion.x, -input->subregion.y);
428
612
  cairo_paint (cairo);
429
613
  cairo_destroy (cairo);
430
614
 
431
615
  cairo = cairo_create (output->surface);
432
616
  cairo_rectangle (cairo, output->subregion.x, output->subregion.y, output->subregion.width, output->subregion.height);
433
617
  cairo_clip (cairo);
434
- cairo_set_source_surface (cairo, surface, 0, 0);
618
+ cairo_set_source_surface (cairo, surface, input->subregion.x, input->subregion.y);
435
619
  pattern = cairo_get_source (cairo);
436
620
  cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
437
621
  cairo_paint (cairo);
@@ -453,3 +637,901 @@ lsm_svg_filter_surface_alpha (LsmSvgFilterSurface *input, LsmSvgFilterSurface *o
453
637
 
454
638
  cairo_destroy (cairo);
455
639
  }
640
+
641
+ void
642
+ lsm_svg_filter_surface_color_matrix (LsmSvgFilterSurface *input, LsmSvgFilterSurface *output,
643
+ LsmSvgColorFilterType type, unsigned n_values, const double *values)
644
+ {
645
+ cairo_t *cairo;
646
+ unsigned i;
647
+ int matrix[20];
648
+ double cosval;
649
+ double sinval;
650
+ int ch;
651
+ gint x, y, x1, x2, y1, y2;
652
+ gint width, height;
653
+ gint rowstride;
654
+ gint sum;
655
+ guchar *in_pixels;
656
+ guchar *output_pixels;
657
+ double setting;
658
+
659
+ g_return_if_fail (input != NULL);
660
+ g_return_if_fail (output != NULL);
661
+ g_return_if_fail (values != NULL || n_values < 1);
662
+
663
+ width = cairo_image_surface_get_width (input->surface);
664
+ height = cairo_image_surface_get_height (input->surface);
665
+
666
+ if (width != cairo_image_surface_get_width (output->surface) ||
667
+ height != cairo_image_surface_get_height (output->surface))
668
+ return;
669
+
670
+ if (height < 1 || width < 1)
671
+ return;
672
+
673
+ memset (matrix, 0, sizeof (*matrix) * G_N_ELEMENTS (matrix));
674
+
675
+ switch (type) {
676
+ case LSM_SVG_COLOR_FILTER_TYPE_MATRIX:
677
+ for (i = 0; i < G_N_ELEMENTS (matrix) && i < n_values; i++)
678
+ matrix[i] = values[i] * 255.0;
679
+ break;
680
+ case LSM_SVG_COLOR_FILTER_TYPE_SATURATE:
681
+ if (n_values > 0)
682
+ setting = values[0];
683
+ else
684
+ setting = 1.0;
685
+
686
+ matrix[0] = 255.0 * (0.213 + 0.787 * setting);
687
+ matrix[1] = 255.0 * (0.715 - 0.715 * setting);
688
+ matrix[2] = 255.0 * (0.072 - 0.072 * setting);
689
+ matrix[5] = 255.0 * (0.213 - 0.213 * setting);
690
+ matrix[6] = 255.0 * (0.715 + 0.285 * setting);
691
+ matrix[7] = 255.0 * (0.072 - 0.072 * setting);
692
+ matrix[10] = 255.0 * (0.213 - 0.213 * setting);
693
+ matrix[11] = 255.0 * (0.715 - 0.715 * setting);
694
+ matrix[12] = 255.0 * (0.072 + 0.928 * setting);
695
+ matrix[18] = 255;
696
+ break;
697
+ case LSM_SVG_COLOR_FILTER_TYPE_HUE_ROTATE:
698
+ if (n_values > 0)
699
+ setting = values[0];
700
+ else
701
+ setting = 0.0;
702
+
703
+ cosval = cos (setting);
704
+ sinval = sin (setting);
705
+
706
+ matrix[0] = (0.213 + cosval * 0.787 + sinval * -0.213) * 255.;
707
+ matrix[1] = (0.715 + cosval * -0.715 + sinval * -0.715) * 255.;
708
+ matrix[2] = (0.072 + cosval * -0.072 + sinval * 0.928) * 255.;
709
+ matrix[5] = (0.213 + cosval * -0.213 + sinval * 0.143) * 255.;
710
+ matrix[6] = (0.715 + cosval * 0.285 + sinval * 0.140) * 255.;
711
+ matrix[7] = (0.072 + cosval * -0.072 + sinval * -0.283) * 255.;
712
+ matrix[10] = (0.213 + cosval * -0.213 + sinval * -0.787) * 255.;
713
+ matrix[11] = (0.715 + cosval * -0.715 + sinval * 0.715) * 255.;
714
+ matrix[12] = (0.072 + cosval * 0.928 + sinval * 0.072) * 255.;
715
+ matrix[18] = 255;
716
+ break;
717
+ case LSM_SVG_COLOR_FILTER_TYPE_LUMINANCE_TO_ALPHA:
718
+ matrix[15] = 0.2125 * 255.;
719
+ matrix[16] = 0.7154 * 255.;
720
+ matrix[17] = 0.0721 * 255.;
721
+ break;
722
+ default:
723
+ return;
724
+ }
725
+
726
+ cairo_surface_flush (input->surface);
727
+ cairo = cairo_create (output->surface);
728
+
729
+ in_pixels = cairo_image_surface_get_data (input->surface);
730
+ output_pixels = cairo_image_surface_get_data (output->surface);
731
+ rowstride = cairo_image_surface_get_stride (input->surface);
732
+
733
+ x1 = CLAMP (input->subregion.x, 0, width);
734
+ x2 = CLAMP (input->subregion.x + input->subregion.width, 0, width);
735
+ y1 = CLAMP (input->subregion.y, 0, height);
736
+ y2 = CLAMP (input->subregion.y + input->subregion.height, 0, height);
737
+
738
+ for (y = y1; y < y2; y++)
739
+ for (x = x1; x < x2; x++) {
740
+ int umch;
741
+ int alpha = in_pixels[4 * x + y * rowstride + channelmap[3]];
742
+ if (!alpha)
743
+ for (umch = 0; umch < 4; umch++) {
744
+ sum = matrix[umch * 5 + 4];
745
+ if (sum > 255)
746
+ sum = 255;
747
+ if (sum < 0)
748
+ sum = 0;
749
+ output_pixels[4 * x + y * rowstride + channelmap[umch]] = sum;
750
+ } else
751
+ for (umch = 0; umch < 4; umch++) {
752
+ int umi;
753
+ ch = channelmap[umch];
754
+ sum = 0;
755
+ for (umi = 0; umi < 4; umi++) {
756
+ i = channelmap[umi];
757
+ if (umi != 3)
758
+ sum += matrix[umch * 5 + umi] *
759
+ in_pixels[4 * x + y * rowstride + i] / alpha;
760
+ else
761
+ sum += matrix[umch * 5 + umi] *
762
+ in_pixels[4 * x + y * rowstride + i] / 255;
763
+ }
764
+ sum += matrix[umch * 5 + 4];
765
+
766
+
767
+
768
+ if (sum > 255)
769
+ sum = 255;
770
+ if (sum < 0)
771
+ sum = 0;
772
+
773
+ output_pixels[4 * x + y * rowstride + ch] = sum;
774
+ }
775
+ for (umch = 0; umch < 3; umch++) {
776
+ ch = channelmap[umch];
777
+ output_pixels[4 * x + y * rowstride + ch] =
778
+ output_pixels[4 * x + y * rowstride + ch] *
779
+ output_pixels[4 * x + y * rowstride + channelmap[3]] / 255;
780
+ }
781
+ }
782
+
783
+ cairo_surface_mark_dirty (output->surface);
784
+
785
+ cairo_destroy (cairo);
786
+ }
787
+
788
+ void
789
+ lsm_svg_filter_surface_convolve_matrix (LsmSvgFilterSurface *input, LsmSvgFilterSurface *output,
790
+ unsigned order_x, unsigned order_y, unsigned n_values, const double *values,
791
+ double divisor, double bias, unsigned target_x, unsigned target_y,
792
+ LsmSvgEdgeMode edge_mode, gboolean preserve_alpha)
793
+ {
794
+ cairo_t *cairo;
795
+ int ch;
796
+ gint x, y, x1, x2, y1, y2;
797
+ gint width, height;
798
+ gint rowstride;
799
+ guchar *in_pixels;
800
+ guchar *output_pixels;
801
+ double kval, sum;
802
+ guchar sval;
803
+ int sx, sy, kx, ky;
804
+ double dx = 1.0, dy = 1.0;
805
+ int umch, i, j;
806
+ gint tempresult;
807
+
808
+ g_return_if_fail (input != NULL);
809
+ g_return_if_fail (output != NULL);
810
+ g_return_if_fail (values != NULL || n_values < 1);
811
+
812
+ if (divisor <= 0.0)
813
+ return;
814
+
815
+ width = cairo_image_surface_get_width (input->surface);
816
+ height = cairo_image_surface_get_height (input->surface);
817
+
818
+ if (width != cairo_image_surface_get_width (output->surface) ||
819
+ height != cairo_image_surface_get_height (output->surface))
820
+ return;
821
+
822
+ if (height < 1 || width < 1)
823
+ return;
824
+
825
+ if (order_y * order_x != n_values)
826
+ return;
827
+
828
+ if (target_x > order_x || target_y > order_y)
829
+ return;
830
+
831
+ x1 = CLAMP (input->subregion.x, 0, width);
832
+ x2 = CLAMP (input->subregion.x + input->subregion.width, 0, width);
833
+ y1 = CLAMP (input->subregion.y, 0, height);
834
+ y2 = CLAMP (input->subregion.y + input->subregion.height, 0, height);
835
+
836
+ cairo_surface_flush (input->surface);
837
+ cairo = cairo_create (output->surface);
838
+
839
+ in_pixels = cairo_image_surface_get_data (input->surface);
840
+ output_pixels = cairo_image_surface_get_data (output->surface);
841
+ rowstride = cairo_image_surface_get_stride (input->surface);
842
+
843
+ for (y = y1; y < y2; y++)
844
+ for (x = x1; x < x2; x++) {
845
+ for (umch = 0; umch < 3 + !preserve_alpha; umch++) {
846
+ ch = channelmap[umch];
847
+ sum = 0;
848
+ for (i = 0; i < order_y; i++)
849
+ for (j = 0; j < order_x; j++) {
850
+ int alpha;
851
+ sx = x - target_x + j * dx;
852
+ sy = y - target_y + i * dy;
853
+ if (edge_mode == LSM_SVG_EDGE_MODE_DUPLICATE) {
854
+ if (sx < x1)
855
+ sx = x1;
856
+ if (sx >= x2)
857
+ sx = x2 - 1;
858
+ if (sy < y1)
859
+ sy = y1;
860
+ if (sy >= y2)
861
+ sy = y2 - 1;
862
+ } else if (edge_mode == LSM_SVG_EDGE_MODE_WRAP) {
863
+ if (sx < x1 || (sx >= x2))
864
+ sx = x1 + (sx - x1) % (x2 - x1);
865
+ if (sy < y1 || (sy >= y2))
866
+ sy = y1 + (sy - y1) % (y2 - y1);
867
+ } else if (edge_mode == LSM_SVG_EDGE_MODE_NONE)
868
+ if (sx < x1 || (sx >= x2) ||
869
+ sy < y1 || (sy >= y2))
870
+ continue;
871
+
872
+ kx = order_x - j - 1;
873
+ ky = order_y - i - 1;
874
+ alpha = in_pixels[4 * sx + sy * rowstride + 3];
875
+ if (ch == 3)
876
+ sval = alpha;
877
+ else if (alpha)
878
+ sval = in_pixels[4 * sx + sy * rowstride + ch] * 255 / alpha;
879
+ else
880
+ sval = 0;
881
+ kval = values[kx + ky * order_x];
882
+ sum += (double) sval *kval;
883
+ }
884
+ tempresult = sum / divisor + bias;
885
+
886
+ if (tempresult > 255)
887
+ tempresult = 255;
888
+ if (tempresult < 0)
889
+ tempresult = 0;
890
+
891
+ output_pixels[4 * x + y * rowstride + ch] = tempresult;
892
+ }
893
+ if (preserve_alpha)
894
+ output_pixels[4 * x + y * rowstride + channelmap[3]] =
895
+ in_pixels[4 * x + y * rowstride + channelmap[3]];
896
+ for (umch = 0; umch < 3; umch++) {
897
+ ch = channelmap[umch];
898
+ output_pixels[4 * x + y * rowstride + ch] =
899
+ output_pixels[4 * x + y * rowstride + ch] *
900
+ output_pixels[4 * x + y * rowstride + channelmap[3]] / 255;
901
+ }
902
+ }
903
+
904
+ cairo_surface_mark_dirty (output->surface);
905
+
906
+ cairo_destroy (cairo);
907
+ }
908
+
909
+ static guchar
910
+ _get_interp_pixel (guchar * src, gdouble ox, gdouble oy, guchar ch,
911
+ gint x1, gint x2, gint y1, gint y2,
912
+ guint rowstride)
913
+ {
914
+ double xmod, ymod;
915
+ double dist1, dist2, dist3, dist4;
916
+ double c, c1, c2, c3, c4;
917
+ double fox, foy, cox, coy;
918
+
919
+ xmod = fmod (ox, 1.0);
920
+ ymod = fmod (oy, 1.0);
921
+
922
+ dist1 = (1 - xmod) * (1 - ymod);
923
+ dist2 = (xmod) * (1 - ymod);
924
+ dist3 = (xmod) * (ymod);
925
+ dist4 = (1 - xmod) * (ymod);
926
+
927
+ fox = floor (ox);
928
+ foy = floor (oy);
929
+ cox = ceil (ox);
930
+ coy = ceil (oy);
931
+
932
+ if (fox <= x1 || fox >= x2 ||
933
+ foy <= y1 || foy >= y2)
934
+ c1 = 0;
935
+ else
936
+ c1 = src[(guint) foy * rowstride + (guint) fox * 4 + ch];
937
+
938
+ if (cox <= x1 || cox >= x2 ||
939
+ foy <= y1 || foy >= y2)
940
+ c2 = 0;
941
+ else
942
+ c2 = src[(guint) foy * rowstride + (guint) cox * 4 + ch];
943
+
944
+ if (cox <= x1 || cox >= x2 ||
945
+ coy <= y1 || coy >= y2)
946
+ c3 = 0;
947
+ else
948
+ c3 = src[(guint) coy * rowstride + (guint) cox * 4 + ch];
949
+
950
+ if (fox <= x1 || fox >= x2 ||
951
+ coy <= y1 || coy >= y2)
952
+ c4 = 0;
953
+ else
954
+ c4 = src[(guint) coy * rowstride + (guint) fox * 4 + ch];
955
+
956
+ c = (c1 * dist1 + c2 * dist2 + c3 * dist3 + c4 * dist4) / (dist1 + dist2 + dist3 + dist4);
957
+
958
+ return (guchar) c;
959
+ }
960
+
961
+ void
962
+ lsm_svg_filter_surface_displacement_map (LsmSvgFilterSurface *input_1,
963
+ LsmSvgFilterSurface *input_2,
964
+ LsmSvgFilterSurface *output,
965
+ double x_scale,
966
+ double y_scale,
967
+ LsmSvgChannelSelector x_channel_selector,
968
+ LsmSvgChannelSelector y_channel_selector)
969
+ {
970
+ guchar ch, xch, ych;
971
+ gint x, y, x1, x2, y1, y2;
972
+ double ox, oy;
973
+ gint rowstride, height, width;
974
+ guchar *in_pixels;
975
+ guchar *in2_pixels;
976
+ guchar *output_pixels;
977
+ cairo_t *cairo;
978
+
979
+ g_return_if_fail (input_1 != NULL);
980
+ g_return_if_fail (input_2 != NULL);
981
+ g_return_if_fail (output != NULL);
982
+
983
+ height = cairo_image_surface_get_height (input_1->surface);
984
+ width = cairo_image_surface_get_width (input_1->surface);
985
+
986
+ if (width != cairo_image_surface_get_width (input_2->surface) ||
987
+ height != cairo_image_surface_get_height (input_2->surface))
988
+ return;
989
+
990
+ if (width != cairo_image_surface_get_width (output->surface) ||
991
+ height != cairo_image_surface_get_height (output->surface))
992
+ return;
993
+
994
+ cairo_surface_flush (input_1->surface);
995
+ cairo_surface_flush (input_2->surface);
996
+
997
+ cairo = cairo_create (output->surface);
998
+
999
+ in_pixels = cairo_image_surface_get_data (input_1->surface);
1000
+ in2_pixels = cairo_image_surface_get_data (input_2->surface);
1001
+
1002
+ rowstride = cairo_image_surface_get_stride (input_1->surface);
1003
+
1004
+ output_pixels = cairo_image_surface_get_data (output->surface);
1005
+
1006
+ switch (x_channel_selector) {
1007
+ case LSM_SVG_CHANNEL_SELECTOR_RED:
1008
+ xch = 0;
1009
+ break;
1010
+ case LSM_SVG_CHANNEL_SELECTOR_GREEN:
1011
+ xch = 1;
1012
+ break;
1013
+ case LSM_SVG_CHANNEL_SELECTOR_BLUE:
1014
+ xch = 2;
1015
+ break;
1016
+ case LSM_SVG_CHANNEL_SELECTOR_ALPHA:
1017
+ xch = 3;
1018
+ break;
1019
+ default:
1020
+ xch = 4;
1021
+ };
1022
+
1023
+ switch (y_channel_selector) {
1024
+ case LSM_SVG_CHANNEL_SELECTOR_RED:
1025
+ ych = 0;
1026
+ break;
1027
+ case LSM_SVG_CHANNEL_SELECTOR_GREEN:
1028
+ ych = 1;
1029
+ break;
1030
+ case LSM_SVG_CHANNEL_SELECTOR_BLUE:
1031
+ ych = 2;
1032
+ break;
1033
+ case LSM_SVG_CHANNEL_SELECTOR_ALPHA:
1034
+ ych = 3;
1035
+ break;
1036
+ default:
1037
+ ych = 4;
1038
+ };
1039
+
1040
+ x1 = CLAMP (input_1->subregion.x, 0, width);
1041
+ x2 = CLAMP (input_1->subregion.x + input_1->subregion.width, 0, width);
1042
+ y1 = CLAMP (input_1->subregion.y, 0, height);
1043
+ y2 = CLAMP (input_1->subregion.y + input_1->subregion.height, 0, height);
1044
+
1045
+ xch = channelmap[xch];
1046
+ ych = channelmap[ych];
1047
+ for (y = y1; y < y2; y++)
1048
+ for (x = x1; x < x2; x++) {
1049
+ if (xch != 4)
1050
+ ox = x + x_scale *
1051
+ ((double) in2_pixels[y * rowstride + x * 4 + xch] / 255.0 - 0.5);
1052
+ else
1053
+ ox = x;
1054
+
1055
+ if (ych != 4)
1056
+ oy = y + y_scale *
1057
+ ((double) in2_pixels[y * rowstride + x * 4 + ych] / 255.0 - 0.5);
1058
+ else
1059
+ oy = y;
1060
+
1061
+ for (ch = 0; ch < 4; ch++) {
1062
+ output_pixels[y * rowstride + x * 4 + ch] =
1063
+ _get_interp_pixel (in_pixels, ox, oy, ch, x1, x2, y1, y2, rowstride);
1064
+ }
1065
+ }
1066
+
1067
+ cairo_surface_mark_dirty (output->surface);
1068
+
1069
+ cairo_destroy (cairo);
1070
+ }
1071
+
1072
+ void
1073
+ lsm_svg_filter_surface_specular_lighting (LsmSvgFilterSurface *output,
1074
+ double surface_scale, double specular_constant, double specular_exponent,
1075
+ double dx, double dy)
1076
+ {
1077
+ cairo_t *cairo;
1078
+ int width, height;
1079
+ #if 0
1080
+ guchar *output_pixels;
1081
+ gint rowstride;
1082
+ gint x1, x2, y1, y2;
1083
+ #endif
1084
+
1085
+ g_return_if_fail (output != NULL);
1086
+
1087
+ width = cairo_image_surface_get_width (output->surface);
1088
+ height = cairo_image_surface_get_height (output->surface);
1089
+
1090
+ if (height < 1 || width < 1)
1091
+ return;
1092
+
1093
+ cairo = cairo_create (output->surface);
1094
+
1095
+ #if 0
1096
+ output_pixels = cairo_image_surface_get_data (output->surface);
1097
+ rowstride = cairo_image_surface_get_stride (output->surface);
1098
+
1099
+ x1 = CLAMP (output->subregion.x, 0, width);
1100
+ x2 = CLAMP (output->subregion.x + output->subregion.width, 0, width);
1101
+ y1 = CLAMP (output->subregion.y, 0, height);
1102
+ y2 = CLAMP (output->subregion.y + output->subregion.height, 0, height);
1103
+ #endif
1104
+
1105
+ cairo_surface_mark_dirty (output->surface);
1106
+
1107
+ cairo_destroy (cairo);
1108
+ }
1109
+
1110
+ void
1111
+ lsm_svg_filter_surface_image (LsmSvgFilterSurface *output, GdkPixbuf *pixbuf,
1112
+ LsmSvgPreserveAspectRatio preserve_aspect_ratio)
1113
+ {
1114
+ cairo_t *cairo;
1115
+ int width, height;
1116
+ double zoom_x, zoom_y;
1117
+
1118
+ g_return_if_fail (output != NULL);
1119
+ g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
1120
+
1121
+ if (output->subregion.width < 1 ||
1122
+ output->subregion.height < 1)
1123
+ return;
1124
+
1125
+ /* TODO Implement preserve_aspect_ratio support */
1126
+
1127
+ width = gdk_pixbuf_get_height (pixbuf);
1128
+ height = gdk_pixbuf_get_width (pixbuf);
1129
+
1130
+ if (height < 1 || width < 1)
1131
+ return;
1132
+
1133
+ zoom_x = (double) output->subregion.width / (double) width;
1134
+ zoom_y = (double) output->subregion.height / (double) height;
1135
+
1136
+ cairo = cairo_create (output->surface);
1137
+
1138
+ cairo_translate (cairo, output->subregion.x, output->subregion.y);
1139
+ cairo_scale (cairo, zoom_x, zoom_y);
1140
+ lsm_cairo_set_source_pixbuf (cairo, pixbuf, 0, 0);
1141
+ cairo_paint (cairo);
1142
+
1143
+ cairo_destroy (cairo);
1144
+ }
1145
+
1146
+ void
1147
+ lsm_svg_filter_surface_morphology (LsmSvgFilterSurface *input, LsmSvgFilterSurface *output,
1148
+ LsmSvgMorphologyOperator op, double rx, double ry)
1149
+ {
1150
+ cairo_t *cairo;
1151
+ int i, j;
1152
+ int ch, extreme;
1153
+ gint x, y, x1, x2, y1, y2;
1154
+ gint width, height;
1155
+ gint rowstride;
1156
+ guchar *in_pixels;
1157
+ guchar *output_pixels;
1158
+ gint kx, ky;
1159
+ guchar val;
1160
+
1161
+ g_return_if_fail (input != NULL);
1162
+ g_return_if_fail (output != NULL);
1163
+
1164
+ width = cairo_image_surface_get_width (input->surface);
1165
+ height = cairo_image_surface_get_height (input->surface);
1166
+
1167
+ if (width != cairo_image_surface_get_width (output->surface) ||
1168
+ height != cairo_image_surface_get_height (output->surface))
1169
+ return;
1170
+
1171
+ if (height < 1 || width < 1)
1172
+ return;
1173
+
1174
+ kx = rx;
1175
+ ky = ry;
1176
+
1177
+ if (kx < 1 && ky < 1)
1178
+ return;
1179
+
1180
+ cairo_surface_flush (input->surface);
1181
+ cairo = cairo_create (output->surface);
1182
+
1183
+ in_pixels = cairo_image_surface_get_data (input->surface);
1184
+ output_pixels = cairo_image_surface_get_data (output->surface);
1185
+ rowstride = cairo_image_surface_get_stride (input->surface);
1186
+
1187
+ x1 = CLAMP (input->subregion.x, 0, width);
1188
+ x2 = CLAMP (input->subregion.x + input->subregion.width, 0, width);
1189
+ y1 = CLAMP (input->subregion.y, 0, height);
1190
+ y2 = CLAMP (input->subregion.y + input->subregion.height, 0, height);
1191
+
1192
+ for (y = y1; y < y2; y++)
1193
+ for (x = x1; x < x2; x++)
1194
+ for (ch = 0; ch < 4; ch++) {
1195
+ if (op == LSM_SVG_MORPHOLOGY_OPERATOR_ERODE)
1196
+ extreme = 255;
1197
+ else
1198
+ extreme = 0;
1199
+ for (i = -ky; i < ky + 1; i++)
1200
+ for (j = -kx; j < kx + 1; j++) {
1201
+ if (y + i >= height || y + i < 0 || x + j >= width || x + j < 0)
1202
+ continue;
1203
+
1204
+ val = in_pixels[(y + i) * rowstride + (x + j) * 4 + ch];
1205
+
1206
+
1207
+ if (op == LSM_SVG_MORPHOLOGY_OPERATOR_ERODE) {
1208
+ if (extreme > val)
1209
+ extreme = val;
1210
+ } else {
1211
+ if (extreme < val)
1212
+ extreme = val;
1213
+ }
1214
+
1215
+ }
1216
+ output_pixels[y * rowstride + x * 4 + ch] = extreme;
1217
+ }
1218
+
1219
+ cairo_surface_mark_dirty (output->surface);
1220
+
1221
+ cairo_destroy (cairo);
1222
+ }
1223
+
1224
+ /* Produces results in the range [1, 2**31 - 2].
1225
+ Algorithm is: r = (a * r) mod m
1226
+ where a = 16807 and m = 2**31 - 1 = 2147483647
1227
+ See [Park & Miller], CACM vol. 31 no. 10 p. 1195, Oct. 1988
1228
+ To test: the algorithm should produce the result 1043618065
1229
+ as the 10,000th generated number if the original seed is 1.
1230
+ */
1231
+
1232
+ #define LSM_SVG_TURBULENCE_RAND_m 2147483647 /* 2**31 - 1 */
1233
+ #define LSM_SVG_TURBULENCE_RAND_a 16807 /* 7**5; primitive root of m */
1234
+ #define LSM_SVG_TURBULENCE_RAND_q 127773 /* m / a */
1235
+ #define LSM_SVG_TURBULENCE_RAND_r 2836 /* m % a */
1236
+ #define LSM_SVG_TURBULENCE_BSize 0x100
1237
+ #define LSM_SVG_TURBULENCE_BM 0xff
1238
+ #define LSM_SVG_TURBULENCE_PerlinN 0x1000
1239
+ #define LSM_SVG_TURBULENCE_NP 12 /* 2^PerlinN */
1240
+ #define LSM_SVG_TURBULENCE_NM 0xfff
1241
+
1242
+ typedef struct {
1243
+ double base_frequency_x;
1244
+ double base_frequency_y;
1245
+ int n_octaves;
1246
+ double seed;
1247
+ LsmSvgStitchTiles stitch_tiles;
1248
+ LsmSvgTurbulenceType type;
1249
+
1250
+ int uLatticeSelector[LSM_SVG_TURBULENCE_BSize + LSM_SVG_TURBULENCE_BSize + 2];
1251
+ double fGradient[4][LSM_SVG_TURBULENCE_BSize + LSM_SVG_TURBULENCE_BSize + 2][2];
1252
+ } LsmSvgTurbulence;
1253
+
1254
+ typedef struct {
1255
+ int nWidth; /* How much to subtract to wrap for stitching. */
1256
+ int nHeight;
1257
+ int nWrapX; /* Minimum value to wrap. */
1258
+ int nWrapY;
1259
+ } LsmSvgTurbulenceStitchInfo;
1260
+
1261
+ static long
1262
+ _turbulence_setup_seed (int lSeed)
1263
+ {
1264
+ if (lSeed <= 0)
1265
+ lSeed = -(lSeed % (LSM_SVG_TURBULENCE_RAND_m - 1)) + 1;
1266
+ if (lSeed > LSM_SVG_TURBULENCE_RAND_m - 1)
1267
+ lSeed = LSM_SVG_TURBULENCE_RAND_m - 1;
1268
+ return lSeed;
1269
+ }
1270
+
1271
+ static long
1272
+ _turbulence_random (int lSeed)
1273
+ {
1274
+ long result;
1275
+
1276
+ result =
1277
+ LSM_SVG_TURBULENCE_RAND_a * (lSeed % LSM_SVG_TURBULENCE_RAND_q) -
1278
+ LSM_SVG_TURBULENCE_RAND_r * (lSeed / LSM_SVG_TURBULENCE_RAND_q);
1279
+ if (result <= 0)
1280
+ result += LSM_SVG_TURBULENCE_RAND_m;
1281
+ return result;
1282
+ }
1283
+
1284
+ static void
1285
+ _turbulence_init (LsmSvgTurbulence *turbulence)
1286
+ {
1287
+ double s;
1288
+ int i, j, k, lSeed;
1289
+
1290
+ lSeed = _turbulence_setup_seed (turbulence->seed);
1291
+ for (k = 0; k < 4; k++) {
1292
+ for (i = 0; i < LSM_SVG_TURBULENCE_BSize; i++) {
1293
+ turbulence->uLatticeSelector[i] = i;
1294
+ for (j = 0; j < 2; j++)
1295
+ turbulence->fGradient[k][i][j] =
1296
+ (double) (((lSeed =
1297
+ _turbulence_random (lSeed)) % (LSM_SVG_TURBULENCE_BSize +
1298
+ LSM_SVG_TURBULENCE_BSize)) -
1299
+ LSM_SVG_TURBULENCE_BSize) / LSM_SVG_TURBULENCE_BSize;
1300
+ s = (double) (sqrt (turbulence->fGradient[k][i][0] * turbulence->fGradient[k][i][0] +
1301
+ turbulence->fGradient[k][i][1] * turbulence->fGradient[k][i][1]));
1302
+ turbulence->fGradient[k][i][0] /= s;
1303
+ turbulence->fGradient[k][i][1] /= s;
1304
+ }
1305
+ }
1306
+
1307
+ while (--i) {
1308
+ k = turbulence->uLatticeSelector[i];
1309
+ turbulence->uLatticeSelector[i] = turbulence->uLatticeSelector[j =
1310
+ (lSeed = _turbulence_random (lSeed)) % LSM_SVG_TURBULENCE_BSize];
1311
+ turbulence->uLatticeSelector[j] = k;
1312
+ }
1313
+
1314
+ for (i = 0; i < LSM_SVG_TURBULENCE_BSize + 2; i++) {
1315
+ turbulence->uLatticeSelector[LSM_SVG_TURBULENCE_BSize + i] = turbulence->uLatticeSelector[i];
1316
+ for (k = 0; k < 4; k++)
1317
+ for (j = 0; j < 2; j++)
1318
+ turbulence->fGradient[k][LSM_SVG_TURBULENCE_BSize + i][j] = turbulence->fGradient[k][i][j];
1319
+ }
1320
+ }
1321
+
1322
+ #define _turbulence_s_curve(t) ( t * t * (3. - 2. * t) )
1323
+ #define _turbulence_lerp(t, a, b) ( a + t * (b - a) )
1324
+
1325
+ static double
1326
+ _turbulence_noise2 (LsmSvgTurbulence * turbulence,
1327
+ int nColorChannel, double vec[2], LsmSvgTurbulenceStitchInfo *pStitchInfo)
1328
+ {
1329
+ int bx0, bx1, by0, by1, b00, b10, b01, b11;
1330
+ double rx0, rx1, ry0, ry1, *q, sx, sy, a, b, t, u, v;
1331
+ register int i, j;
1332
+
1333
+ t = vec[0] + LSM_SVG_TURBULENCE_PerlinN;
1334
+ bx0 = (int) t;
1335
+ bx1 = bx0 + 1;
1336
+ rx0 = t - (int) t;
1337
+ rx1 = rx0 - 1.0f;
1338
+ t = vec[1] + LSM_SVG_TURBULENCE_PerlinN;
1339
+ by0 = (int) t;
1340
+ by1 = by0 + 1;
1341
+ ry0 = t - (int) t;
1342
+ ry1 = ry0 - 1.0f;
1343
+
1344
+ /* If stitching, adjust lattice points accordingly. */
1345
+ if (pStitchInfo != NULL) {
1346
+ if (bx0 >= pStitchInfo->nWrapX)
1347
+ bx0 -= pStitchInfo->nWidth;
1348
+ if (bx1 >= pStitchInfo->nWrapX)
1349
+ bx1 -= pStitchInfo->nWidth;
1350
+ if (by0 >= pStitchInfo->nWrapY)
1351
+ by0 -= pStitchInfo->nHeight;
1352
+ if (by1 >= pStitchInfo->nWrapY)
1353
+ by1 -= pStitchInfo->nHeight;
1354
+ }
1355
+
1356
+ bx0 &= LSM_SVG_TURBULENCE_BM;
1357
+ bx1 &= LSM_SVG_TURBULENCE_BM;
1358
+ by0 &= LSM_SVG_TURBULENCE_BM;
1359
+ by1 &= LSM_SVG_TURBULENCE_BM;
1360
+ i = turbulence->uLatticeSelector[bx0];
1361
+ j = turbulence->uLatticeSelector[bx1];
1362
+ b00 = turbulence->uLatticeSelector[i + by0];
1363
+ b10 = turbulence->uLatticeSelector[j + by0];
1364
+ b01 = turbulence->uLatticeSelector[i + by1];
1365
+ b11 = turbulence->uLatticeSelector[j + by1];
1366
+ sx = (double) (_turbulence_s_curve (rx0));
1367
+ sy = (double) (_turbulence_s_curve (ry0));
1368
+ q = turbulence->fGradient[nColorChannel][b00];
1369
+ u = rx0 * q[0] + ry0 * q[1];
1370
+ q = turbulence->fGradient[nColorChannel][b10];
1371
+ v = rx1 * q[0] + ry0 * q[1];
1372
+ a = _turbulence_lerp (sx, u, v);
1373
+ q = turbulence->fGradient[nColorChannel][b01];
1374
+ u = rx0 * q[0] + ry1 * q[1];
1375
+ q = turbulence->fGradient[nColorChannel][b11];
1376
+ v = rx1 * q[0] + ry1 * q[1];
1377
+ b = _turbulence_lerp (sx, u, v);
1378
+
1379
+ return _turbulence_lerp (sy, a, b);
1380
+ }
1381
+
1382
+ static double
1383
+ _turbulence (LsmSvgTurbulence * turbulence,
1384
+ int nColorChannel, double *point,
1385
+ double fTileX, double fTileY, double fTileWidth, double fTileHeight)
1386
+ {
1387
+ LsmSvgTurbulenceStitchInfo stitch;
1388
+ LsmSvgTurbulenceStitchInfo *pStitchInfo = NULL; /* Not stitching when NULL. */
1389
+
1390
+ double fSum = 0.0f, vec[2], ratio = 1.;
1391
+ int nOctave;
1392
+
1393
+ /* Adjust the base frequencies if necessary for stitching. */
1394
+ if (turbulence->stitch_tiles == LSM_SVG_STITCH_TILES_STITCH) {
1395
+ /* When stitching tiled turbulence, the frequencies must be adjusted
1396
+ so that the tile borders will be continuous. */
1397
+ if (turbulence->base_frequency_x != 0.0) {
1398
+ double fLoFreq = (double) (floor (fTileWidth * turbulence->base_frequency_x)) / fTileWidth;
1399
+ double fHiFreq = (double) (ceil (fTileWidth * turbulence->base_frequency_x)) / fTileWidth;
1400
+ if (turbulence->base_frequency_x / fLoFreq < fHiFreq / turbulence->base_frequency_x)
1401
+ turbulence->base_frequency_x = fLoFreq;
1402
+ else
1403
+ turbulence->base_frequency_x = fHiFreq;
1404
+ }
1405
+
1406
+ if (turbulence->base_frequency_y != 0.0) {
1407
+ double fLoFreq = (double) (floor (fTileHeight * turbulence->base_frequency_y)) / fTileHeight;
1408
+ double fHiFreq = (double) (ceil (fTileHeight * turbulence->base_frequency_y)) / fTileHeight;
1409
+ if (turbulence->base_frequency_y / fLoFreq < fHiFreq / turbulence->base_frequency_y)
1410
+ turbulence->base_frequency_y = fLoFreq;
1411
+ else
1412
+ turbulence->base_frequency_y = fHiFreq;
1413
+ }
1414
+
1415
+ /* Set up initial stitch values. */
1416
+ pStitchInfo = &stitch;
1417
+ stitch.nWidth = (int) (fTileWidth * turbulence->base_frequency_x + 0.5f);
1418
+ stitch.nWrapX = fTileX * turbulence->base_frequency_x + LSM_SVG_TURBULENCE_PerlinN + stitch.nWidth;
1419
+ stitch.nHeight = (int) (fTileHeight * turbulence->base_frequency_y + 0.5f);
1420
+ stitch.nWrapY = fTileY * turbulence->base_frequency_y + LSM_SVG_TURBULENCE_PerlinN + stitch.nHeight;
1421
+ }
1422
+
1423
+ vec[0] = point[0] * turbulence->base_frequency_x;
1424
+ vec[1] = point[1] * turbulence->base_frequency_y;
1425
+
1426
+ for (nOctave = 0; nOctave < turbulence->n_octaves; nOctave++) {
1427
+ if (turbulence->type == LSM_SVG_TURBULENCE_TYPE_FRACTAL_NOISE)
1428
+ fSum +=
1429
+ (double) (_turbulence_noise2 (turbulence, nColorChannel, vec, pStitchInfo) / ratio);
1430
+ else
1431
+ fSum +=
1432
+ (double) (fabs (_turbulence_noise2 (turbulence, nColorChannel, vec, pStitchInfo)) /
1433
+ ratio);
1434
+
1435
+ vec[0] *= 2;
1436
+ vec[1] *= 2;
1437
+ ratio *= 2;
1438
+
1439
+ if (pStitchInfo != NULL) {
1440
+ /* Update stitch values. Subtracting PerlinN before the multiplication and
1441
+ adding it afterward simplifies to subtracting it once. */
1442
+ stitch.nWidth *= 2;
1443
+ stitch.nWrapX = 2 * stitch.nWrapX - LSM_SVG_TURBULENCE_PerlinN;
1444
+ stitch.nHeight *= 2;
1445
+ stitch.nWrapY = 2 * stitch.nWrapY - LSM_SVG_TURBULENCE_PerlinN;
1446
+ }
1447
+ }
1448
+
1449
+ return fSum;
1450
+ }
1451
+
1452
+ void
1453
+ lsm_svg_filter_surface_turbulence (LsmSvgFilterSurface *output,
1454
+ double base_frequency_x, double base_frequency_y,
1455
+ int n_octaves, double seed,
1456
+ LsmSvgStitchTiles stitch_tiles, LsmSvgTurbulenceType type,
1457
+ const cairo_matrix_t *transform)
1458
+ {
1459
+ LsmSvgTurbulence turbulence;
1460
+ cairo_t *cairo;
1461
+ gint x, y, x1, x2, y1, y2;
1462
+ gint width, height, tileWidth, tileHeight;
1463
+ gint rowstride;
1464
+ guchar *output_pixels;
1465
+ cairo_matrix_t affine;
1466
+
1467
+ g_return_if_fail (output != NULL);
1468
+ g_return_if_fail (transform != NULL);
1469
+
1470
+ affine = *transform;
1471
+ if (cairo_matrix_invert (&affine) != CAIRO_STATUS_SUCCESS)
1472
+ return;
1473
+
1474
+ width = cairo_image_surface_get_width (output->surface);
1475
+ height = cairo_image_surface_get_height (output->surface);
1476
+
1477
+ if (height < 1 || width < 1)
1478
+ return;
1479
+
1480
+ cairo = cairo_create (output->surface);
1481
+
1482
+ output_pixels = cairo_image_surface_get_data (output->surface);
1483
+ rowstride = cairo_image_surface_get_stride (output->surface);
1484
+
1485
+ x1 = CLAMP (output->subregion.x, 0, width);
1486
+ x2 = CLAMP (output->subregion.x + output->subregion.width, 0, width);
1487
+ y1 = CLAMP (output->subregion.y, 0, height);
1488
+ y2 = CLAMP (output->subregion.y + output->subregion.height, 0, height);
1489
+
1490
+ turbulence.base_frequency_x = base_frequency_x;
1491
+ turbulence.base_frequency_y = base_frequency_y;
1492
+ turbulence.n_octaves = n_octaves;
1493
+ turbulence.seed = seed;
1494
+ turbulence.stitch_tiles = stitch_tiles;
1495
+ turbulence.type = type;
1496
+
1497
+ _turbulence_init (&turbulence);
1498
+
1499
+ tileWidth = x2 - x1;
1500
+ tileHeight = y2 - y1;
1501
+
1502
+ for (y = 0; y < tileHeight; y++) {
1503
+ for (x = 0; x < tileWidth; x++) {
1504
+ gint i;
1505
+ double point[2];
1506
+ guchar *pixel;
1507
+ point[0] = affine.xx * (x + x1) + affine.xy * (y + y1) + affine.x0;
1508
+ point[1] = affine.yx * (x + x1) + affine.yy * (y + y1) + affine.y0;
1509
+
1510
+ pixel = output_pixels + 4 * (x + x1) + (y + y1) * rowstride;
1511
+
1512
+ for (i = 0; i < 4; i++) {
1513
+ double cr;
1514
+
1515
+ cr = _turbulence (&turbulence, i, point, (double) x, (double) y,
1516
+ (double) tileWidth, (double) tileHeight);
1517
+
1518
+ if (type == LSM_SVG_TURBULENCE_TYPE_FRACTAL_NOISE)
1519
+ cr = ((cr * 255.) + 255.) / 2.;
1520
+ else
1521
+ cr = (cr * 255.);
1522
+
1523
+ cr = CLAMP (cr, 0., 255.);
1524
+
1525
+ pixel[channelmap[i]] = (guchar) cr;
1526
+ }
1527
+ for (i = 0; i < 3; i++)
1528
+ pixel[channelmap[i]] =
1529
+ pixel[channelmap[i]] * pixel[channelmap[3]] / 255;
1530
+
1531
+ }
1532
+ }
1533
+
1534
+ cairo_surface_mark_dirty (output->surface);
1535
+
1536
+ cairo_destroy (cairo);
1537
+ }