1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  *  art_rgba_svp.c: A slightly modified version of art_rgb_svp to render into rgba buffer
4  *
5  *  This program is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Library General Public License
7  *  as published by the Free Software Foundation; either version 2 of
8  *  the License, or (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU Library General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Library General Public
16  *  License along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  *
19  *  Authors:
20  *    Raph Levien <raph@acm.org>
21  *    Lauris Kaplinski <lauris@ariman.ee>
22  *
23  *  Copyright (C) 1998 Raph Levien
24  *
25  */
26 
27 #define SP_ART_RGBA_SVP_C
28 
29 /* Render a sorted vector path into an RGBA buffer. */
30 
31 #include <libart_lgpl/art_misc.h>
32 #include <libart_lgpl/art_svp.h>
33 #include <libart_lgpl/art_svp_render_aa.h>
34 #include <libart_lgpl/art_rgb.h>
35 
36 #include "art_rgba_svp.h"
37 #include "unused.h"
38 
39 static void art_rgba_fill_run (art_u8 * linebuf, art_u8 r, art_u8 g, art_u8 b, int n);
40 static void art_rgba_run_alpha (art_u8 * linebuf, art_u8 r, art_u8 g, art_u8 b, int alpha, int n);
41 
42 typedef struct _ArtRgbaSVPAlphaData ArtRgbaSVPAlphaData;
43 
44 struct _ArtRgbaSVPAlphaData {
45   int alphatab[256];
46   art_u8 r, g, b, alpha;
47   art_u8 *buf;
48   int rowstride;
49   int libart_x0, libart_x1;
50 };
51 
52 static void
art_rgba_svp_alpha_callback(void * callback_data,int UNUSED (y),int start,ArtSVPRenderAAStep * steps,int n_steps)53 art_rgba_svp_alpha_callback (void *callback_data, int UNUSED(y),
54 			    int start, ArtSVPRenderAAStep *steps, int n_steps)
55 {
56   ArtRgbaSVPAlphaData *data = callback_data;
57   art_u8 *linebuf;
58   int run_x0, run_x1;
59   art_u32 running_sum = start;
60   int libart_x0, libart_x1;
61   int k;
62   art_u8 r, g, b;
63   int *alphatab;
64   int alpha;
65 
66   linebuf = data->buf;
67   libart_x0 = data->libart_x0;
68   libart_x1 = data->libart_x1;
69 
70   r = data->r;
71   g = data->g;
72   b = data->b;
73   alphatab = data->alphatab;
74 
75   if (n_steps > 0)
76     {
77       run_x1 = steps[0].x;
78       if (run_x1 > libart_x0)
79 	{
80 	  alpha = (running_sum >> 16) & 0xff;
81 	  if (alpha)
82 	    art_rgba_run_alpha (linebuf,
83 			       r, g, b, alphatab[alpha],
84 			       run_x1 - libart_x0);
85 	}
86 
87       /* render the steps into tmpbuf */
88       for (k = 0; k < n_steps - 1; k++)
89 	{
90 	  running_sum += steps[k].delta;
91 	  run_x0 = run_x1;
92 	  run_x1 = steps[k + 1].x;
93 	  if (run_x1 > run_x0)
94 	    {
95 	      alpha = (running_sum >> 16) & 0xff;
96 	      if (alpha)
97 		art_rgba_run_alpha (linebuf + (run_x0 - libart_x0) * 4,
98 				   r, g, b, alphatab[alpha],
99 				   run_x1 - run_x0);
100 	    }
101 	}
102       running_sum += steps[k].delta;
103       if (libart_x1 > run_x1)
104 	{
105 	  alpha = (running_sum >> 16) & 0xff;
106 	  if (alpha)
107 	    art_rgba_run_alpha (linebuf + (run_x1 - libart_x0) * 4,
108 			       r, g, b, alphatab[alpha],
109 			       libart_x1 - run_x1);
110 	}
111     }
112   else
113     {
114       alpha = (running_sum >> 16) & 0xff;
115       if (alpha)
116 	art_rgba_run_alpha (linebuf,
117 			   r, g, b, alphatab[alpha],
118 			   libart_x1 - libart_x0);
119     }
120 
121   data->buf += data->rowstride;
122 }
123 
124 static void
art_rgba_svp_alpha_opaque_callback(void * callback_data,int UNUSED (y),int start,ArtSVPRenderAAStep * steps,int n_steps)125 art_rgba_svp_alpha_opaque_callback (void *callback_data, int UNUSED(y),
126 				   int start,
127 				   ArtSVPRenderAAStep *steps, int n_steps)
128 {
129   ArtRgbaSVPAlphaData *data = callback_data;
130   art_u8 *linebuf;
131   int run_x0, run_x1;
132   art_u32 running_sum = start;
133   int libart_x0, libart_x1;
134   int k;
135   art_u8 r, g, b;
136   int *alphatab;
137   int alpha;
138 
139   linebuf = data->buf;
140   libart_x0 = data->libart_x0;
141   libart_x1 = data->libart_x1;
142 
143   r = data->r;
144   g = data->g;
145   b = data->b;
146   alphatab = data->alphatab;
147 
148   if (n_steps > 0)
149     {
150       run_x1 = steps[0].x;
151       if (run_x1 > libart_x0)
152 	{
153 	  alpha = running_sum >> 16;
154 	  if (alpha)
155 	    {
156 	      if (alpha >= 255)
157 		art_rgba_fill_run (linebuf,
158 				  r, g, b,
159 				  run_x1 - libart_x0);
160 	      else
161 		art_rgba_run_alpha (linebuf,
162 				   r, g, b, alphatab[alpha],
163 				   run_x1 - libart_x0);
164 	    }
165 	}
166 
167       /* render the steps into tmpbuf */
168       for (k = 0; k < n_steps - 1; k++)
169 	{
170 	  running_sum += steps[k].delta;
171 	  run_x0 = run_x1;
172 	  run_x1 = steps[k + 1].x;
173 	  if (run_x1 > run_x0)
174 	    {
175 	      alpha = running_sum >> 16;
176 	      if (alpha)
177 		{
178 		  if (alpha >= 255)
179 		    art_rgba_fill_run (linebuf + (run_x0 - libart_x0) * 4,
180 				      r, g, b,
181 				      run_x1 - run_x0);
182 		  else
183 		    art_rgba_run_alpha (linebuf + (run_x0 - libart_x0) * 4,
184 				       r, g, b, alphatab[alpha],
185 				       run_x1 - run_x0);
186 		}
187 	    }
188 	}
189       running_sum += steps[k].delta;
190       if (libart_x1 > run_x1)
191 	{
192 	  alpha = running_sum >> 16;
193 	  if (alpha)
194 	    {
195 	      if (alpha >= 255)
196 		art_rgba_fill_run (linebuf + (run_x1 - libart_x0) * 4,
197 				  r, g, b,
198 				  libart_x1 - run_x1);
199 	      else
200 		art_rgba_run_alpha (linebuf + (run_x1 - libart_x0) * 4,
201 				   r, g, b, alphatab[alpha],
202 				   libart_x1 - run_x1);
203 	    }
204 	}
205     }
206   else
207     {
208       alpha = running_sum >> 16;
209       if (alpha)
210 	{
211 	  if (alpha >= 255)
212 	    art_rgba_fill_run (linebuf,
213 			      r, g, b,
214 			      libart_x1 - libart_x0);
215 	  else
216 	    art_rgba_run_alpha (linebuf,
217 			       r, g, b, alphatab[alpha],
218 			       libart_x1 - libart_x0);
219 	}
220     }
221 
222   data->buf += data->rowstride;
223 }
224 
225 /**
226  * gnome_print_art_rgba_svp_alpha: Alpha-composite sorted vector path over RGBA buffer.
227  * @svp: The source sorted vector path.
228  * @libart_x0: Left coordinate of destination rectangle.
229  * @libart_y0: Top coordinate of destination rectangle.
230  * @libart_x1: Right coordinate of destination rectangle.
231  * @libart_y1: Bottom coordinate of destination rectangle.
232  * @rgba: Color in 0xRRGGBBAA format.
233  * @buf: Destination RGB buffer.
234  * @rowstride: Rowstride of @buf buffer.
235  * @alphagamma: #ArtAlphaGamma for gamma-correcting the compositing.
236  *
237  * Renders the shape specified with @svp over the @buf RGB buffer.
238  * @libart_x1 - @x0 specifies the width, and @libart_y1 - @libart_y0 specifies the height,
239  * of the rectangle rendered. The new pixels are stored starting at
240  * the first byte of @buf. Thus, the @x0 and @libart_y0 parameters specify
241  * an offset within @svp, and may be tweaked as a way of doing
242  * integer-pixel translations without fiddling with @svp itself.
243  *
244  * The @rgba argument specifies the color for the rendering. Pixels of
245  * entirely 0 winding number are left untouched. Pixels of entirely
246  * 1 winding number have the color @rgba composited over them (ie,
247  * are replaced by the red, green, blue components of @rgba if the alpha
248  * component is 0xff). Pixels of intermediate coverage are interpolated
249  * according to the rule in @alphagamma, or default to linear if
250  * @alphagamma is NULL.
251  **/
252 void
gnome_print_art_rgba_svp_alpha(const ArtSVP * svp,int libart_x0,int libart_y0,int libart_x1,int libart_y1,art_u32 rgba,art_u8 * buf,int rowstride,ArtAlphaGamma UNUSED (* alphagamma))253 gnome_print_art_rgba_svp_alpha (const ArtSVP *svp,
254 				int libart_x0, int libart_y0, int libart_x1, int libart_y1,
255 				art_u32 rgba,
256 				art_u8 *buf, int rowstride,
257 				ArtAlphaGamma UNUSED(*alphagamma))
258 {
259   ArtRgbaSVPAlphaData data;
260   int r, g, b, alpha;
261   int i;
262   int a, da;
263 
264   r = rgba >> 24;
265   g = (rgba >> 16) & 0xff;
266   b = (rgba >> 8) & 0xff;
267   alpha = rgba & 0xff;
268 
269   data.r = r;
270   data.g = g;
271   data.b = b;
272   data.alpha = alpha;
273 
274   a = 0x8000;
275   da = (alpha * 66051 + 0x80) >> 8; /* 66051 equals 2 ^ 32 / (255 * 255) */
276 
277   for (i = 0; i < 256; i++)
278     {
279       data.alphatab[i] = a >> 16;
280       a += da;
281     }
282 
283   data.buf = buf;
284   data.rowstride = rowstride;
285   data.libart_x0 = libart_x0;
286   data.libart_x1 = libart_x1;
287   if (alpha == 255)
288     art_svp_render_aa (svp, libart_x0, libart_y0, libart_x1, libart_y1, art_rgba_svp_alpha_opaque_callback,
289 		       &data);
290   else
291     art_svp_render_aa (svp, libart_x0, libart_y0, libart_x1, libart_y1, art_rgba_svp_alpha_callback, &data);
292 }
293 
294 static void
art_rgba_fill_run(art_u8 * buf,art_u8 r,art_u8 g,art_u8 b,int n)295 art_rgba_fill_run (art_u8 * buf, art_u8 r, art_u8 g, art_u8 b, int n)
296 {
297 	int i;
298 
299 	for (i = 0; i < n; i++) {
300 		* buf++ = r;
301 		* buf++ = g;
302 		* buf++ = b;
303 		* buf++ = 255;
304 	}
305 }
306 
307 /* fixme: this */
308 
309 static void
art_rgba_run_alpha(art_u8 * buf,art_u8 r,art_u8 g,art_u8 b,int alpha,int n)310 art_rgba_run_alpha (art_u8 * buf, art_u8 r, art_u8 g, art_u8 b, int alpha, int n)
311 {
312 	int i;
313 	int br, bg, bb, ba;
314 	int cr, cg, cb;
315 
316 	for (i = 0; i < n; i++) {
317 		br = * (buf + 0);
318 		bg = * (buf + 1);
319 		bb = * (buf + 2);
320 		ba = * (buf + 3);
321 
322 		cr = (br * ba + 0x80) >> 8;
323 		cg = (bg * ba + 0x80) >> 8;
324 		cb = (bb * ba + 0x80) >> 8;
325 
326 		* buf++ = cr + (((r - cr) * alpha + 0x80) >> 8);
327 		* buf++ = cg + (((g - cg) * alpha + 0x80) >> 8);
328 		* buf++ = cb + (((b - cb) * alpha + 0x80) >> 8);
329 		* buf++ = ba + (((255 - ba) * alpha + 0x80) >> 8);
330 	}
331 }
332 
333 
334