Code

fix by dvlierop2 for snapping bugs 1579556 and 1579587
[inkscape.git] / src / libnr / nr-compose-transform.cpp
1 #define __NR_COMPOSE_TRANSFORM_C__
3 /*
4  * Pixel buffer rendering library
5  *
6  * Authors:
7  *   Lauris Kaplinski <lauris@kaplinski.com>
8  *
9  * This code is in public domain
10  */
12 #ifdef HAVE_CONFIG_H
13 # include "config.h"
14 #endif
16 #include "nr-pixops.h"
17 #include "nr-matrix.h"
20 #ifdef WITH_MMX
21 #ifdef __cplusplus
22 extern "C" {
23 #endif /* __cplusplus */
24 /* fixme: */
25 int nr_have_mmx (void);
26 void nr_mmx_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_0 (unsigned char *px, int w, int h, int rs,
27                                                           const unsigned char *spx, int sw, int sh, int srs,
28                                                           const long *FFd2s, unsigned int alpha);
29 void nr_mmx_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_n (unsigned char *px, int w, int h, int rs,
30                                                           const unsigned char *spx, int sw, int sh, int srs,
31                                                           const long *FFd2s, const long *FF_S, unsigned int alpha, int dbits);
32 #define NR_PIXOPS_MMX (1 && nr_have_mmx ())
33 #ifdef __cplusplus
34 }
35 #endif //__cplusplus
36 #endif
38 /* fixme: Implement missing (Lauris) */
39 /* fixme: PREMUL colors before calculating average (Lauris) */
41 /* Fixed point precision */
42 #define FBITS 12
44 void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs,
45                                                const unsigned char *spx, int sw, int sh, int srs,
46                                                const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);
47 void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs,
48                                                const unsigned char *spx, int sw, int sh, int srs,
49                                                const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);
50 void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs,
51                                                const unsigned char *spx, int sw, int sh, int srs,
52                                                const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);
53 void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs,
54                                                const unsigned char *spx, int sw, int sh, int srs,
55                                                const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);
57 void
58 nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs,
59                                                const unsigned char *spx, int sw, int sh, int srs,
60                                                const NR::Matrix &d2s, unsigned int alpha, int xd, int yd)
61 {
62         int xsize, ysize, size, dbits;
63         long FFs_x_x, FFs_x_y, FFs_y_x, FFs_y_y, FFs__x, FFs__y;
64         long FFs_x_x_S, FFs_x_y_S, FFs_y_x_S, FFs_y_y_S;
65         /* Subpixel positions */
66         int FF_sx_S[256];
67         int FF_sy_S[256];
68         unsigned char *d0;
69         int FFsx0, FFsy0;
70         int x, y;
72         if (alpha == 0) return;
74         xsize = (1 << xd);
75         ysize = (1 << yd);
76         size = xsize * ysize;
77         dbits = xd + yd;
79         /* Set up fixed point matrix */
80         FFs_x_x = (long) (d2s[0] * (1 << FBITS) + 0.5);
81         FFs_x_y = (long) (d2s[1] * (1 << FBITS) + 0.5);
82         FFs_y_x = (long) (d2s[2] * (1 << FBITS) + 0.5);
83         FFs_y_y = (long) (d2s[3] * (1 << FBITS) + 0.5);
84         FFs__x = (long) (d2s[4] * (1 << FBITS) + 0.5);
85         FFs__y = (long) (d2s[5] * (1 << FBITS) + 0.5);
87         FFs_x_x_S = FFs_x_x >> xd;
88         FFs_x_y_S = FFs_x_y >> xd;
89         FFs_y_x_S = FFs_y_x >> yd;
90         FFs_y_y_S = FFs_y_y >> yd;
92         /* Set up subpixel matrix */
93         /* fixme: We can calculate that in floating point (Lauris) */
94         for (y = 0; y < ysize; y++) {
95                 for (x = 0; x < xsize; x++) {
96                         FF_sx_S[y * xsize + x] = FFs_x_x_S * x + FFs_y_x_S * y;
97                         FF_sy_S[y * xsize + x] = FFs_x_y_S * x + FFs_y_y_S * y;
98                 }
99         }
101         d0 = px;
102         FFsx0 = FFs__x;
103         FFsy0 = FFs__y;
105         for (y = 0; y < h; y++) {
106                 unsigned char *d;
107                 long FFsx, FFsy;
108                 d = d0;
109                 FFsx = FFsx0;
110                 FFsy = FFsy0;
111                 for (x = 0; x < w; x++) {
112                         unsigned int r, g, b, a;
113                         long sx, sy;
114                         int i;
115                         r = g = b = a = 0;
116                         for (i = 0; i < size; i++) {
117                                 sx = (FFsx + FF_sx_S[i]) >> FBITS;
118                                 if ((sx >= 0) && (sx < sw)) {
119                                         sy = (FFsy + FF_sy_S[i]) >> FBITS;
120                                         if ((sy >= 0) && (sy < sh)) {
121                                                 const unsigned char *s;
122                                                 unsigned int ca;
123                                                 s = spx + sy * srs + sx * 4;
124                                                 ca = NR_PREMUL_112 (s[3], alpha);
125                                                 r += NR_PREMUL_121 (s[0], ca);
126                                                 g += NR_PREMUL_121 (s[1], ca);
127                                                 b += NR_PREMUL_121 (s[2], ca);
128                                                 a += NR_NORMALIZE_21(ca);
129                                         }
130                                 }
131                         }
132                         a >>= dbits;
133                         if (a != 0) {
134                                 r = r >> dbits;
135                                 g = g >> dbits;
136                                 b = b >> dbits;
137                                 if (a == 255) {
138                                         /* Transparent BG, premul src */
139                                         d[0] = r;
140                                         d[1] = g;
141                                         d[2] = b;
142                                         d[3] = a;
143                                 } else {
144                                         unsigned int ca;
145                                         /* Full composition */
146                                         ca = NR_COMPOSEA_112(a, d[3]);
147                                         d[0] = NR_COMPOSENNN_111121 (r, a, d[0], d[3], ca);
148                                         d[1] = NR_COMPOSENNN_111121 (g, a, d[1], d[3], ca);
149                                         d[2] = NR_COMPOSENNN_111121 (b, a, d[2], d[3], ca);
150                                         d[3] = NR_NORMALIZE_21(ca);
151                                 }
152                         }
153                         /* Advance pointers */
154                         FFsx += FFs_x_x;
155                         FFsy += FFs_x_y;
156                         d += 4;
157                 }
158                 FFsx0 += FFs_y_x;
159                 FFsy0 += FFs_y_y;
160                 d0 += rs;
161         }
164 void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs,
165                                                     const unsigned char *spx, int sw, int sh, int srs,
166                                                     const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);
168 static void
169 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_0 (unsigned char *px, int w, int h, int rs,
170                                                  const unsigned char *spx, int sw, int sh, int srs,
171                                                  const long *FFd2s, unsigned int alpha)
173         unsigned char *d0;
174         int FFsx0, FFsy0;
175         int x, y;
177         d0 = px;
178         FFsx0 = FFd2s[4];
179         FFsy0 = FFd2s[5];
181         for (y = 0; y < h; y++) {
182                 unsigned char *d;
183                 long FFsx, FFsy;
184                 d = d0;
185                 FFsx = FFsx0;
186                 FFsy = FFsy0;
187                 for (x = 0; x < w; x++) {
188                         long sx, sy;
189                         sx = FFsx >> FBITS;
190                         if ((sx >= 0) && (sx < sw)) {
191                                 sy = FFsy >> FBITS;
192                                 if ((sy >= 0) && (sy < sh)) {
193                                         const unsigned char *s;
194                                         unsigned int a;
195                                         s = spx + sy * srs + sx * 4;
196                                         a = NR_PREMUL_112 (s[3], alpha);
197                                         if (a != 0) {
198                                                 if ((a == 255*255) || (d[3] == 0)) {
199                                                         /* Transparent BG, premul src */
200                                                         d[0] = NR_PREMUL_121 (s[0], a);
201                                                         d[1] = NR_PREMUL_121 (s[1], a);
202                                                         d[2] = NR_PREMUL_121 (s[2], a);
203                                                         d[3] = NR_NORMALIZE_21(a);
204                                                 } else {
205                                                         d[0] = NR_COMPOSENPP_1211 (s[0], a, d[0]);
206                                                         d[1] = NR_COMPOSENPP_1211 (s[1], a, d[1]);
207                                                         d[2] = NR_COMPOSENPP_1211 (s[2], a, d[2]);
208                                                         d[3] = NR_COMPOSEA_211(a, d[3]);
209                                                 }
210                                         }
211                                 }
212                         }
213                         /* Advance pointers */
214                         FFsx += FFd2s[0];
215                         FFsy += FFd2s[1];
216                         d += 4;
217                 }
218                 FFsx0 += FFd2s[2];
219                 FFsy0 += FFd2s[3];
220                 d0 += rs;
221         }
224 static void
225 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_n (unsigned char *px, int w, int h, int rs,
226                                                  const unsigned char *spx, int sw, int sh, int srs,
227                                                  const long *FFd2s, const long *FF_S, unsigned int alpha, int dbits)
229         int size;
230         unsigned char *d0;
231         int FFsx0, FFsy0;
232         int x, y;
234         size = (1 << dbits);
235     unsigned alpha_rounding_fix = size * 255;
236     unsigned rgb_rounding_fix = size * (255 * 256);
237     if (alpha > 127) ++alpha;
239         d0 = px;
240         FFsx0 = FFd2s[4];
241         FFsy0 = FFd2s[5];
243         for (y = 0; y < h; y++) {
244                 unsigned char *d;
245                 long FFsx, FFsy;
246                 d = d0;
247                 FFsx = FFsx0;
248                 FFsy = FFsy0;
249                 for (x = 0; x < w; x++) {
250                         unsigned int r, g, b, a;
251                         int i;
252                         r = g = b = a = 0;
253                         for (i = 0; i < size; i++) {
254                                 long sx, sy;
255                                 sx = (FFsx + FF_S[2 * i]) >> FBITS;
256                                 if ((sx >= 0) && (sx < sw)) {
257                                         sy = (FFsy + FF_S[2 * i + 1]) >> FBITS;
258                                         if ((sy >= 0) && (sy < sh)) {
259                                                 const unsigned char *s;
260                                                 unsigned int ca;
261                                                 s = spx + sy * srs + sx * 4;
262                                                 ca = NR_PREMUL_112(s[3], alpha);
263                                                 r += NR_PREMUL_123(s[0], ca);
264                                                 g += NR_PREMUL_123(s[1], ca);
265                                                 b += NR_PREMUL_123(s[2], ca);
266                                                 a += ca;
267                                         }
268                                 }
269                         }
270                         a = (a + alpha_rounding_fix) >> (8 + dbits);
271                         if (a != 0) {
272                                 r = (r + rgb_rounding_fix) >> (16 + dbits);
273                                 g = (g + rgb_rounding_fix) >> (16 + dbits);
274                                 b = (b + rgb_rounding_fix) >> (16 + dbits);
275                                 if ((a == 255) || (d[3] == 0)) {
276                                         /* Transparent BG, premul src */
277                                         d[0] = r;
278                                         d[1] = g;
279                                         d[2] = b;
280                                         d[3] = a;
281                                 } else {
282                                         d[0] = NR_COMPOSEPPP_1111 (r, a, d[0]);
283                                         d[1] = NR_COMPOSEPPP_1111 (g, a, d[1]);
284                                         d[2] = NR_COMPOSEPPP_1111 (b, a, d[2]);
285                                         d[3] = NR_COMPOSEA_111(a, d[3]);
286                                 }
287                         }
288                         /* Advance pointers */
289                         FFsx += FFd2s[0];
290                         FFsy += FFd2s[1];
291                         d += 4;
292                 }
293                 FFsx0 += FFd2s[2];
294                 FFsy0 += FFd2s[3];
295                 d0 += rs;
296         }
299 void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs,
300                                                     const unsigned char *spx, int sw, int sh, int srs,
301                                                     const NR::Matrix &d2s, unsigned int alpha, int xd, int yd)
303         int dbits;
304         long FFd2s[6];
305         int i;
307         if (alpha == 0) return;
309         dbits = xd + yd;
311         for (i = 0; i < 6; i++) {
312                 FFd2s[i] = (long) (d2s[i] * (1 << FBITS) + 0.5);
313         }
315         if (dbits == 0) {
316 #ifdef WITH_MMX
317                 if (NR_PIXOPS_MMX) {
318                         /* WARNING: MMX composer REQUIRES w > 0 and h > 0 */
319                         nr_mmx_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_0 (px, w, h, rs, spx, sw, sh, srs, FFd2s, alpha);
320                         return;
321                 }
322 #endif
323                 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_0 (px, w, h, rs, spx, sw, sh, srs, FFd2s, alpha);
324         } else {
325                 int xsize, ysize;
326                 long FFs_x_x_S, FFs_x_y_S, FFs_y_x_S, FFs_y_y_S;
327                 long FF_S[2 * 256];
328                 int x, y;
330                 xsize = (1 << xd);
331                 ysize = (1 << yd);
333                 FFs_x_x_S = FFd2s[0] >> xd;
334                 FFs_x_y_S = FFd2s[1] >> xd;
335                 FFs_y_x_S = FFd2s[2] >> yd;
336                 FFs_y_y_S = FFd2s[3] >> yd;
338                 /* Set up subpixel matrix */
339                 /* fixme: We can calculate that in floating point (Lauris) */
340                 for (y = 0; y < ysize; y++) {
341                         for (x = 0; x < xsize; x++) {
342                                 FF_S[2 * (y * xsize + x)] = FFs_x_x_S * x + FFs_y_x_S * y;
343                                 FF_S[2 * (y * xsize + x) + 1] = FFs_x_y_S * x + FFs_y_y_S * y;
344                         }
345                 }
347 #ifdef WITH_MMX
348                 if (NR_PIXOPS_MMX) {
349                         /* WARNING: MMX composer REQUIRES w > 0 and h > 0 */
350                         nr_mmx_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_n (px, w, h, rs, spx, sw, sh, srs, FFd2s, FF_S, alpha, dbits);
351                         return;
352                 }
353 #endif
354                 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_n (px, w, h, rs, spx, sw, sh, srs, FFd2s, FF_S, alpha, dbits);
355         }
358 void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs,
359                                                     const unsigned char *spx, int sw, int sh, int srs,
360                                                     const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);