Code

Fix for bug #455302 and bug #165529, also partially fixes bounding box of various...
[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"
19 /*#ifdef WITH_MMX
20 #ifdef __cplusplus
21 extern "C" {
22 #endif // __cplusplus
23 / * fixme: * /
24 / *int nr_have_mmx (void);
25 #define NR_PIXOPS_MMX (1 && nr_have_mmx ())
26 #ifdef __cplusplus
27 }
28 #endif //__cplusplus
29 #endif
30 */
32 /* fixme: Implement missing (Lauris) */
33 /* fixme: PREMUL colors before calculating average (Lauris) */
35 /* Fixed point precision */
36 #define FBITS 12
37 #define FBITS_HP 18 // In some places we need a higher precision
39 void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs,
40                                                const unsigned char *spx, int sw, int sh, int srs,
41                                                const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);
42 void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs,
43                                                const unsigned char *spx, int sw, int sh, int srs,
44                                                const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);
45 void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs,
46                                                const unsigned char *spx, int sw, int sh, int srs,
47                                                const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);
48 void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs,
49                                                const unsigned char *spx, int sw, int sh, int srs,
50                                                const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);
52 void
53 nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_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)
56 {
57         int xsize, ysize, size, dbits;
58         long FFs_x_x, FFs_x_y, FFs_y_x, FFs_y_y, FFs__x, FFs__y;
59         long FFs_x_x_S, FFs_x_y_S, FFs_y_x_S, FFs_y_y_S;
60         /* Subpixel positions */
61         int FF_sx_S[256];
62         int FF_sy_S[256];
63         unsigned char *d0;
64         int FFsx0, FFsy0;
65         int x, y;
67         if (alpha == 0) return;
69     // Both alpha and color components are stored temporarily with a range of [0,255^2], so more supersampling and we get an overflow
70     if (xd+yd>16) {
71         xd = 8;
72         yd = 8;
73     }
75         xsize = (1 << xd);
76         ysize = (1 << yd);
77         size = xsize * ysize;
78         dbits = xd + yd;
79     unsigned int rounding_fix = size/2;
81         /* Set up fixed point matrix */
82         FFs_x_x = (long) floor(d2s[0] * (1 << FBITS) + 0.5);
83         FFs_x_y = (long) floor(d2s[1] * (1 << FBITS) + 0.5);
84         FFs_y_x = (long) floor(d2s[2] * (1 << FBITS) + 0.5);
85         FFs_y_y = (long) floor(d2s[3] * (1 << FBITS) + 0.5);
86         FFs__x = (long) floor(d2s[4] * (1 << FBITS) + 0.5);
87         FFs__y = (long) floor(d2s[5] * (1 << FBITS) + 0.5);
89         FFs_x_x_S = FFs_x_x >> xd;
90         FFs_x_y_S = FFs_x_y >> xd;
91         FFs_y_x_S = FFs_y_x >> yd;
92         FFs_y_y_S = FFs_y_y >> yd;
94         /* Set up subpixel matrix */
95         /* fixme: We can calculate that in floating point (Lauris) */
96         for (y = 0; y < ysize; y++) {
97                 for (x = 0; x < xsize; x++) {
98                         FF_sx_S[y * xsize + x] = FFs_x_x_S * x + FFs_y_x_S * y;
99                         FF_sy_S[y * xsize + x] = FFs_x_y_S * x + FFs_y_y_S * y;
100                 }
101         }
103         d0 = px;
104         FFsx0 = FFs__x;
105         FFsy0 = FFs__y;
107         for (y = 0; y < h; y++) {
108                 unsigned char *d;
109                 long FFsx, FFsy;
110                 d = d0;
111                 FFsx = FFsx0;
112                 FFsy = FFsy0;
113                 for (x = 0; x < w; x++) {
114                         unsigned int r, g, b, a;
115                         long sx, sy;
116                         int i;
117                         r = g = b = a = 0;
118                         for (i = 0; i < size; i++) {
119                                 sx = (FFsx + FF_sx_S[i]) >> FBITS;
120                                 if ((sx >= 0) && (sx < sw)) {
121                                         sy = (FFsy + FF_sy_S[i]) >> FBITS;
122                                         if ((sy >= 0) && (sy < sh)) {
123                                                 const unsigned char *s;
124                                                 s = spx + sy * srs + sx * 4;
125                                                 r += NR_PREMUL_112 (s[0], s[3]);
126                                                 g += NR_PREMUL_112 (s[1], s[3]);
127                                                 b += NR_PREMUL_112 (s[2], s[3]);
128                                                 a += s[3];
129                                         }
130                                 }
131                         }
132                         a = (a*alpha + rounding_fix) >> dbits;
133             // Compare to nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P
134                         if (a != 0) {
135                                 r = (r + rounding_fix) >> dbits;
136                                 g = (g + rounding_fix) >> dbits;
137                                 b = (b + rounding_fix) >> dbits;
138                 if (a == 255) {
139                                         /* Full coverage, demul src */
140                                         d[0] = NR_NORMALIZE_21(r);
141                                         d[1] = NR_NORMALIZE_21(g);
142                                         d[2] = NR_NORMALIZE_21(b);
143                                         d[3] = NR_NORMALIZE_21(a);
144                 } else if (d[3] == 0) {
145                     /* Only foreground, demul src */
146                     d[0] = NR_DEMUL_221(r,a);
147                     d[1] = NR_DEMUL_221(g,a);
148                     d[2] = NR_DEMUL_221(b,a);
149                     d[3] = NR_NORMALIZE_21(a);
150                                 } else {
151                                         unsigned int ca;
152                                         /* Full composition */
153                                         ca = NR_COMPOSEA_213(a, d[3]);
154                                         d[0] = NR_COMPOSEPNN_221131 (r, a, d[0], d[3], ca);
155                                         d[1] = NR_COMPOSEPNN_221131 (g, a, d[1], d[3], ca);
156                                         d[2] = NR_COMPOSEPNN_221131 (b, a, d[2], d[3], ca);
157                                         d[3] = NR_NORMALIZE_31(ca);
158                                 }
159                         }
160                         /* Advance pointers */
161                         FFsx += FFs_x_x;
162                         FFsy += FFs_x_y;
163                         d += 4;
164                 }
165                 FFsx0 += FFs_y_x;
166                 FFsy0 += FFs_y_y;
167                 d0 += rs;
168         }
171 void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs,
172                                                     const unsigned char *spx, int sw, int sh, int srs,
173                                                     const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);
175 static void
176 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_0 (unsigned char *px, int w, int h, int rs,
177                                                  const unsigned char *spx, int sw, int sh, int srs,
178                                                  const long long *FFd2s, unsigned int alpha)
180     unsigned char *d0;
181         long long FFsx0, FFsy0;
182         int x, y;
184         d0 = px;
185         FFsx0 = FFd2s[4];
186         FFsy0 = FFd2s[5];
188         for (y = 0; y < h; y++) {
189                 unsigned char *d;
190                 long long FFsx, FFsy;
191                 d = d0;
192                 FFsx = FFsx0;
193                 FFsy = FFsy0;
194                 for (x = 0; x < w; x++) {
195                         long sx, sy;
196                         sx = long(FFsx >> FBITS_HP);
197                         if ((sx >= 0) && (sx < sw)) {
198                                 sy = long(FFsy >> FBITS_HP);
199                                 if ((sy >= 0) && (sy < sh)) {
200                                         const unsigned char *s;
201                                         unsigned int a;
202                                         s = spx + sy * srs + sx * 4;
203                                         a = NR_PREMUL_112 (s[3], alpha);
204                                         if (a != 0) {
205                                                 if ((a == 255*255) || (d[3] == 0)) {
206                                                         /* Transparent BG, premul src */
207                                                         d[0] = NR_PREMUL_121 (s[0], a);
208                                                         d[1] = NR_PREMUL_121 (s[1], a);
209                                                         d[2] = NR_PREMUL_121 (s[2], a);
210                                                         d[3] = NR_NORMALIZE_21(a);
211                                                 } else {
212                                                         d[0] = NR_COMPOSENPP_1211 (s[0], a, d[0]);
213                                                         d[1] = NR_COMPOSENPP_1211 (s[1], a, d[1]);
214                                                         d[2] = NR_COMPOSENPP_1211 (s[2], a, d[2]);
215                                                         d[3] = NR_COMPOSEA_211(a, d[3]);
216                                                 }
217                                         }
218                                 }
219                         }
220                         /* Advance pointers */
221                         FFsx += FFd2s[0];
222                         FFsy += FFd2s[1];
223                         d += 4;
224                 }
225                 FFsx0 += FFd2s[2];
226                 FFsy0 += FFd2s[3];
227                 d0 += rs;
228         }
231 static void
232 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_n (unsigned char *px, int w, int h, int rs,
233                                                  const unsigned char *spx, int sw, int sh, int srs,
234                                                  const long long *FFd2s, const long *FF_S, unsigned int alpha, int dbits)
236         int size;
237         unsigned char *d0;
238         long long FFsx0, FFsy0;
239         int x, y;
241         size = (1 << dbits);
242     unsigned int rounding_fix = size/2;
244         d0 = px;
245         FFsx0 = FFd2s[4];
246         FFsy0 = FFd2s[5];
248         for (y = 0; y < h; y++) {
249                 unsigned char *d;
250                 long long FFsx, FFsy;
251                 d = d0;
252                 FFsx = FFsx0;
253                 FFsy = FFsy0;
254                 for (x = 0; x < w; x++) {
255                         unsigned int r, g, b, a;
256                         int i;
257                         r = g = b = a = 0;
258                         for (i = 0; i < size; i++) {
259                                 long sx, sy;
260                                 sx = (long (FFsx >> (FBITS_HP - FBITS)) + FF_S[2 * i]) >> FBITS;
261                                 if ((sx >= 0) && (sx < sw)) {
262                                         sy = (long (FFsy >> (FBITS_HP - FBITS)) + FF_S[2 * i + 1]) >> FBITS;
263                                         if ((sy >= 0) && (sy < sh)) {
264                                                 const unsigned char *s;
265                                                 s = spx + sy * srs + sx * 4;
266                                                 r += NR_PREMUL_112(s[0], s[3]);
267                                                 g += NR_PREMUL_112(s[1], s[3]);
268                                                 b += NR_PREMUL_112(s[2], s[3]);
269                                                 a += s[3];
270                                         }
271                                 }
272                         }
273                         a = (a*alpha + rounding_fix) >> dbits;
274                         if (a != 0) {
275                                 r = (r + rounding_fix) >> dbits;
276                                 g = (g + rounding_fix) >> dbits;
277                                 b = (b + rounding_fix) >> dbits;
278                                 if ((a == 255) || (d[3] == 0)) {
279                                         /* Transparent BG, premul src */
280                                         d[0] = NR_NORMALIZE_21(r);
281                                         d[1] = NR_NORMALIZE_21(g);
282                                         d[2] = NR_NORMALIZE_21(b);
283                                         d[3] = NR_NORMALIZE_21(a);
284                                 } else {
285                                         d[0] = NR_COMPOSEPPP_2211 (r, a, d[0]);
286                                         d[1] = NR_COMPOSEPPP_2211 (g, a, d[1]);
287                                         d[2] = NR_COMPOSEPPP_2211 (b, a, d[2]);
288                                         d[3] = NR_COMPOSEA_211(a, d[3]);
289                                 }
290                         }
291                         /* Advance pointers */
292                         FFsx += FFd2s[0];
293                         FFsy += FFd2s[1];
294                         d += 4;
295                 }
296                 FFsx0 += FFd2s[2];
297                 FFsy0 += FFd2s[3];
298                 d0 += rs;
299         }
302 void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs,
303                                                     const unsigned char *spx, int sw, int sh, int srs,
304                                                     const NR::Matrix &d2s, unsigned int alpha, int xd, int yd)
306         int dbits;
307         long FFd2s[6];
308         long long FFd2s_HP[6]; // with higher precision
309         int i;
311         if (alpha == 0) return;
313     // Both alpha and color components are stored temporarily with a range of [0,255^2], so more supersampling and we get an overflow
314     if (xd+yd>16) {
315         xd = 8;
316         yd = 8;
317     }
319     dbits = xd + yd;
321         for (i = 0; i < 6; i++) {
322                 FFd2s[i] = (long) floor(d2s[i] * (1 << FBITS) + 0.5);
323                 FFd2s_HP[i] = (long long) floor(d2s[i] * (1 << FBITS_HP) + 0.5);;
324         }
326         if (dbits == 0) {
327                 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_0 (px, w, h, rs, spx, sw, sh, srs, FFd2s_HP, alpha);
328         } else {
329                 int xsize, ysize;
330                 long FFs_x_x_S, FFs_x_y_S, FFs_y_x_S, FFs_y_y_S;
331                 long FF_S[2 * 256];
332                 int x, y;
334                 xsize = (1 << xd);
335                 ysize = (1 << yd);
337                 FFs_x_x_S = FFd2s[0] >> xd;
338                 FFs_x_y_S = FFd2s[1] >> xd;
339                 FFs_y_x_S = FFd2s[2] >> yd;
340                 FFs_y_y_S = FFd2s[3] >> yd;
342                 /* Set up subpixel matrix */
343                 /* fixme: We can calculate that in floating point (Lauris) */
344                 for (y = 0; y < ysize; y++) {
345                         for (x = 0; x < xsize; x++) {
346                                 FF_S[2 * (y * xsize + x)] = FFs_x_x_S * x + FFs_y_x_S * y;
347                                 FF_S[2 * (y * xsize + x) + 1] = FFs_x_y_S * x + FFs_y_y_S * y;
348                         }
349                 }
351                 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_n (px, w, h, rs, spx, sw, sh, srs, FFd2s_HP, FF_S, alpha, dbits);
352         }
355 void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs,
356                                                     const unsigned char *spx, int sw, int sh, int srs,
357                                                     const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);