1 /*
2 * art_render.c: Modular rendering architecture.
3 *
4 * Libart_LGPL - library of basic graphic primitives
5 * Copyright (C) 2000 Raph Levien
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
21 */
22
23 #include "config.h"
24 #include "art_render.h"
25
26 #include "art_rgb.h"
27
28 typedef struct _ArtRenderPriv ArtRenderPriv;
29
30 struct _ArtRenderPriv {
31 ArtRender super;
32
33 ArtImageSource *image_source;
34
35 int n_mask_source;
36 ArtMaskSource **mask_source;
37
38 int n_callbacks;
39 ArtRenderCallback **callbacks;
40 };
41
42 ArtRender *
art_render_new(int x0,int y0,int x1,int y1,art_u8 * pixels,int rowstride,int n_chan,int depth,ArtAlphaType alpha_type,ArtAlphaGamma * alphagamma)43 art_render_new (int x0, int y0, int x1, int y1,
44 art_u8 *pixels, int rowstride,
45 int n_chan, int depth, ArtAlphaType alpha_type,
46 ArtAlphaGamma *alphagamma)
47 {
48 ArtRenderPriv *priv;
49 ArtRender *result;
50
51 priv = art_new (ArtRenderPriv, 1);
52 result = &priv->super;
53
54 if (n_chan > ART_MAX_CHAN)
55 {
56 art_warn ("art_render_new: n_chan = %d, exceeds %d max\n",
57 n_chan, ART_MAX_CHAN);
58 return NULL;
59 }
60 if (depth > ART_MAX_DEPTH)
61 {
62 art_warn ("art_render_new: depth = %d, exceeds %d max\n",
63 depth, ART_MAX_DEPTH);
64 return NULL;
65 }
66 if (x0 >= x1)
67 {
68 art_warn ("art_render_new: x0 >= x1 (x0 = %d, x1 = %d)\n", x0, x1);
69 return NULL;
70 }
71 result->x0 = x0;
72 result->y0 = y0;
73 result->x1 = x1;
74 result->y1 = y1;
75 result->pixels = pixels;
76 result->rowstride = rowstride;
77 result->n_chan = n_chan;
78 result->depth = depth;
79 result->alpha_type = alpha_type;
80
81 result->clear = ART_FALSE;
82 result->opacity = 0x10000;
83 result->compositing_mode = ART_COMPOSITE_NORMAL;
84 result->alphagamma = alphagamma;
85
86 result->alpha_buf = NULL;
87 result->image_buf = NULL;
88
89 result->run = NULL;
90 result->span_x = NULL;
91
92 result->need_span = ART_FALSE;
93
94 priv->image_source = NULL;
95
96 priv->n_mask_source = 0;
97 priv->mask_source = NULL;
98
99 return result;
100 }
101
102 /* todo on clear routines: I haven't really figured out what to do
103 with clearing the alpha channel. It _should_ be possible to clear
104 to an arbitrary RGBA color. */
105
106 /**
107 * art_render_clear: Set clear color.
108 * @clear_color: Color with which to clear dest.
109 *
110 * Sets clear color, equivalent to actually clearing the destination
111 * buffer before rendering. This is the most general form.
112 **/
113 void
art_render_clear(ArtRender * render,const ArtPixMaxDepth * clear_color)114 art_render_clear (ArtRender *render, const ArtPixMaxDepth *clear_color)
115 {
116 int i;
117 int n_ch = render->n_chan + (render->alpha_type != ART_ALPHA_NONE);
118
119 render->clear = ART_TRUE;
120 for (i = 0; i < n_ch; i++)
121 render->clear_color[i] = clear_color[i];
122 }
123
124 /**
125 * art_render_clear_rgb: Set clear color, given in RGB format.
126 * @clear_rgb: Clear color, in 0xRRGGBB format.
127 *
128 * Sets clear color, equivalent to actually clearing the destination
129 * buffer before rendering.
130 **/
131 void
art_render_clear_rgb(ArtRender * render,art_u32 clear_rgb)132 art_render_clear_rgb (ArtRender *render, art_u32 clear_rgb)
133 {
134 if (render->n_chan != 3)
135 art_warn ("art_render_clear_rgb: called on render with %d channels, only works with 3\n",
136 render->n_chan);
137 else
138 {
139 int r, g, b;
140
141 render->clear = ART_TRUE;
142 r = clear_rgb >> 16;
143 g = (clear_rgb >> 8) & 0xff;
144 b = clear_rgb & 0xff;
145 render->clear_color[0] = ART_PIX_MAX_FROM_8(r);
146 render->clear_color[1] = ART_PIX_MAX_FROM_8(g);
147 render->clear_color[2] = ART_PIX_MAX_FROM_8(b);
148 }
149 }
150
151 static void
art_render_nop_done(ArtRenderCallback * self,ArtRender * render)152 art_render_nop_done (ArtRenderCallback *self, ArtRender *render)
153 {
154 }
155
156 static void
art_render_clear_render_rgb8(ArtRenderCallback * self,ArtRender * render,art_u8 * dest,int y)157 art_render_clear_render_rgb8 (ArtRenderCallback *self, ArtRender *render,
158 art_u8 *dest, int y)
159 {
160 int width = render->x1 - render->x0;
161 art_u8 r, g, b;
162 ArtPixMaxDepth color_max;
163
164 color_max = render->clear_color[0];
165 r = ART_PIX_8_FROM_MAX (color_max);
166 color_max = render->clear_color[1];
167 g = ART_PIX_8_FROM_MAX (color_max);
168 color_max = render->clear_color[2];
169 b = ART_PIX_8_FROM_MAX (color_max);
170
171 art_rgb_fill_run (dest, r, g, b, width);
172 }
173
174 static void
art_render_clear_render_8(ArtRenderCallback * self,ArtRender * render,art_u8 * dest,int y)175 art_render_clear_render_8 (ArtRenderCallback *self, ArtRender *render,
176 art_u8 *dest, int y)
177 {
178 int width = render->x1 - render->x0;
179 int i, j;
180 int n_ch = render->n_chan + (render->alpha_type != ART_ALPHA_NONE);
181 int ix;
182 art_u8 color[ART_MAX_CHAN + 1];
183
184 for (j = 0; j < n_ch; j++)
185 {
186 ArtPixMaxDepth color_max = render->clear_color[j];
187 color[j] = ART_PIX_8_FROM_MAX (color_max);
188 }
189
190 ix = 0;
191 for (i = 0; i < width; i++)
192 for (j = 0; j < n_ch; j++)
193 dest[ix++] = color[j];
194 }
195
196 const ArtRenderCallback art_render_clear_rgb8_obj =
197 {
198 art_render_clear_render_rgb8,
199 art_render_nop_done
200 };
201
202 const ArtRenderCallback art_render_clear_8_obj =
203 {
204 art_render_clear_render_8,
205 art_render_nop_done
206 };
207
208 #if ART_MAX_DEPTH >= 16
209
210 static void
art_render_clear_render_16(ArtRenderCallback * self,ArtRender * render,art_u8 * dest,int y)211 art_render_clear_render_16 (ArtRenderCallback *self, ArtRender *render,
212 art_u8 *dest, int y)
213 {
214 int width = render->x1 - render->x0;
215 int i, j;
216 int n_ch = render->n_chan + (render->alpha_type != ART_ALPHA_NONE);
217 int ix;
218 art_u16 *dest_16 = (art_u16 *)dest;
219 art_u8 color[ART_MAX_CHAN + 1];
220
221 for (j = 0; j < n_ch; j++)
222 {
223 int color_16 = render->clear_color[j];
224 color[j] = color_16;
225 }
226
227 ix = 0;
228 for (i = 0; i < width; i++)
229 for (j = 0; j < n_ch; j++)
230 dest_16[ix++] = color[j];
231 }
232
233 const ArtRenderCallback art_render_clear_16_obj =
234 {
235 art_render_clear_render_16,
236 art_render_nop_done
237 };
238
239 #endif /* ART_MAX_DEPTH >= 16 */
240
241 /* todo: inline */
242 static ArtRenderCallback *
art_render_choose_clear_callback(ArtRender * render)243 art_render_choose_clear_callback (ArtRender *render)
244 {
245 ArtRenderCallback *clear_callback;
246
247 if (render->depth == 8)
248 {
249 if (render->n_chan == 3 &&
250 render->alpha_type == ART_ALPHA_NONE)
251 clear_callback = (ArtRenderCallback *)&art_render_clear_rgb8_obj;
252 else
253 clear_callback = (ArtRenderCallback *)&art_render_clear_8_obj;
254 }
255 #if ART_MAX_DEPTH >= 16
256 else if (render->depth == 16)
257 clear_callback = (ArtRenderCallback *)&art_render_clear_16_obj;
258 #endif
259 else
260 {
261 art_die ("art_render_choose_clear_callback: inconsistent render->depth = %d\n",
262 render->depth);
263 }
264 return clear_callback;
265 }
266
267 #if 0
268 /* todo: get around to writing this */
269 static void
270 art_render_composite_render_noa_8_norm (ArtRenderCallback *self, ArtRender *render,
271 art_u8 *dest, int y)
272 {
273 int width = render->x1 - render->x0;
274
275 }
276 #endif
277
278 /* This is the most general form of the function. It is slow but
279 (hopefully) correct. Actually, I'm still worried about roundoff
280 errors in the premul case - it seems to me that an off-by-one could
281 lead to overflow. */
282 static void
art_render_composite(ArtRenderCallback * self,ArtRender * render,art_u8 * dest,int y)283 art_render_composite (ArtRenderCallback *self, ArtRender *render,
284 art_u8 *dest, int y)
285 {
286 ArtRenderMaskRun *run = render->run;
287 art_u32 depth = render->depth;
288 int n_run = render->n_run;
289 int x0 = render->x0;
290 int x;
291 int run_x0, run_x1;
292 art_u8 *alpha_buf = render->alpha_buf;
293 art_u8 *image_buf = render->image_buf;
294 int i, j;
295 art_u32 tmp;
296 art_u32 run_alpha;
297 art_u32 alpha;
298 int image_ix;
299 art_u16 src[ART_MAX_CHAN + 1];
300 art_u16 dst[ART_MAX_CHAN + 1];
301 int n_chan = render->n_chan;
302 ArtAlphaType alpha_type = render->alpha_type;
303 int n_ch = n_chan + (alpha_type != ART_ALPHA_NONE);
304 int dst_pixstride = n_ch * (depth >> 3);
305 int buf_depth = render->buf_depth;
306 ArtAlphaType buf_alpha = render->buf_alpha;
307 int buf_n_ch = n_chan + (buf_alpha != ART_ALPHA_NONE);
308 int buf_pixstride = buf_n_ch * (buf_depth >> 3);
309 art_u8 *bufptr;
310 art_u32 src_alpha;
311 art_u32 src_mul;
312 art_u8 *dstptr;
313 art_u32 dst_alpha;
314 art_u32 dst_mul;
315
316 image_ix = 0;
317 for (i = 0; i < n_run - 1; i++)
318 {
319 run_x0 = run[i].x;
320 run_x1 = run[i + 1].x;
321 tmp = run[i].alpha;
322 if (tmp < 0x8100)
323 continue;
324
325 run_alpha = (tmp + (tmp >> 8) + (tmp >> 16) - 0x8000) >> 8; /* range [0 .. 0x10000] */
326 bufptr = image_buf + (run_x0 - x0) * buf_pixstride;
327 dstptr = dest + (run_x0 - x0) * dst_pixstride;
328 for (x = run_x0; x < run_x1; x++)
329 {
330 if (alpha_buf)
331 {
332 if (depth == 8)
333 {
334 tmp = run_alpha * alpha_buf[x - x0] + 0x80;
335 /* range 0x80 .. 0xff0080 */
336 alpha = (tmp + (tmp >> 8) + (tmp >> 16)) >> 8;
337 }
338 else /* (depth == 16) */
339 {
340 tmp = ((art_u16 *)alpha_buf)[x - x0];
341 tmp = (run_alpha * tmp + 0x8000) >> 8;
342 /* range 0x80 .. 0xffff80 */
343 alpha = (tmp + (tmp >> 16)) >> 8;
344 }
345 }
346 else
347 alpha = run_alpha;
348 /* alpha is run_alpha * alpha_buf[x], range 0 .. 0x10000 */
349
350 /* convert (src pixel * alpha) to premul alpha form,
351 store in src as 0..0xffff range */
352 if (buf_alpha == ART_ALPHA_NONE)
353 {
354 src_alpha = alpha;
355 src_mul = src_alpha;
356 }
357 else
358 {
359 if (buf_depth == 8)
360 {
361 tmp = alpha * bufptr[n_chan] + 0x80;
362 /* range 0x80 .. 0xff0080 */
363 src_alpha = (tmp + (tmp >> 8) + (tmp >> 16)) >> 8;
364 }
365 else /* (depth == 16) */
366 {
367 tmp = ((art_u16 *)bufptr)[n_chan];
368 tmp = (alpha * tmp + 0x8000) >> 8;
369 /* range 0x80 .. 0xffff80 */
370 src_alpha = (tmp + (tmp >> 16)) >> 8;
371 }
372 if (buf_alpha == ART_ALPHA_SEPARATE)
373 src_mul = src_alpha;
374 else /* buf_alpha == (ART_ALPHA_PREMUL) */
375 src_mul = alpha;
376 }
377 /* src_alpha is the (alpha of the source pixel * alpha),
378 range 0..0x10000 */
379
380 if (buf_depth == 8)
381 {
382 src_mul *= 0x101;
383 for (j = 0; j < n_chan; j++)
384 src[j] = (bufptr[j] * src_mul + 0x8000) >> 16;
385 }
386 else if (buf_depth == 16)
387 {
388 for (j = 0; j < n_chan; j++)
389 src[j] = (((art_u16 *)bufptr)[j] * src_mul + 0x8000) >> 16;
390 }
391 bufptr += buf_pixstride;
392
393 /* src[0..n_chan - 1] (range 0..0xffff) and src_alpha (range
394 0..0x10000) now contain the source pixel with
395 premultiplied alpha */
396
397 /* convert dst pixel to premul alpha form,
398 store in dst as 0..0xffff range */
399 if (alpha_type == ART_ALPHA_NONE)
400 {
401 dst_alpha = 0x10000;
402 dst_mul = dst_alpha;
403 }
404 else
405 {
406 if (depth == 8)
407 {
408 tmp = dstptr[n_chan];
409 /* range 0..0xff */
410 dst_alpha = (tmp << 8) + tmp + (tmp >> 7);
411 }
412 else /* (depth == 16) */
413 {
414 tmp = ((art_u16 *)dstptr)[n_chan];
415 dst_alpha = (tmp + (tmp >> 15));
416 }
417 if (alpha_type == ART_ALPHA_SEPARATE)
418 dst_mul = dst_alpha;
419 else /* (alpha_type == ART_ALPHA_PREMUL) */
420 dst_mul = 0x10000;
421 }
422 /* dst_alpha is the alpha of the dest pixel,
423 range 0..0x10000 */
424
425 if (depth == 8)
426 {
427 dst_mul *= 0x101;
428 for (j = 0; j < n_chan; j++)
429 dst[j] = (dstptr[j] * dst_mul + 0x8000) >> 16;
430 }
431 else if (buf_depth == 16)
432 {
433 for (j = 0; j < n_chan; j++)
434 dst[j] = (((art_u16 *)dstptr)[j] * dst_mul + 0x8000) >> 16;
435 }
436
437 /* do the compositing, dst = (src over dst) */
438 for (j = 0; j < n_chan; j++)
439 {
440 art_u32 srcv, dstv;
441 art_u32 tmp;
442
443 srcv = src[j];
444 dstv = dst[j];
445 tmp = ((dstv * (0x10000 - src_alpha) + 0x8000) >> 16) + srcv;
446 tmp -= tmp >> 16;
447 dst[j] = tmp;
448 }
449
450 if (alpha_type == ART_ALPHA_NONE)
451 {
452 if (depth == 8)
453 dst_mul = 0xff;
454 else /* (depth == 16) */
455 dst_mul = 0xffff;
456 }
457 else
458 {
459 if (src_alpha >= 0x10000)
460 dst_alpha = 0x10000;
461 else
462 dst_alpha += ((((0x10000 - dst_alpha) * src_alpha) >> 8) + 0x80) >> 8;
463 if (alpha_type == ART_ALPHA_PREMUL || dst_alpha == 0)
464 {
465 if (depth == 8)
466 dst_mul = 0xff;
467 else /* (depth == 16) */
468 dst_mul = 0xffff;
469 }
470 else /* (ALPHA_TYPE == ART_ALPHA_SEPARATE && dst_alpha != 0) */
471 {
472 if (depth == 8)
473 dst_mul = 0xff0000 / dst_alpha;
474 else /* (depth == 16) */
475 dst_mul = 0xffff0000 / dst_alpha;
476 }
477 }
478 if (depth == 8)
479 {
480 for (j = 0; j < n_chan; j++)
481 dstptr[j] = (dst[j] * dst_mul + 0x8000) >> 16;
482 if (alpha_type != ART_ALPHA_NONE)
483 dstptr[n_chan] = (dst_alpha * 0xff + 0x8000) >> 16;
484 }
485 else if (depth == 16)
486 {
487 for (j = 0; j < n_chan; j++)
488 ((art_u16 *)dstptr)[j] = (dst[j] * dst_mul + 0x8000) >> 16;
489 if (alpha_type != ART_ALPHA_NONE)
490 ((art_u16 *)dstptr)[n_chan] = (dst_alpha * 0xffff + 0x8000) >> 16;
491 }
492 dstptr += dst_pixstride;
493 }
494 }
495 }
496
497 const ArtRenderCallback art_render_composite_obj =
498 {
499 art_render_composite,
500 art_render_nop_done
501 };
502
503 static void
art_render_composite_8(ArtRenderCallback * self,ArtRender * render,art_u8 * dest,int y)504 art_render_composite_8 (ArtRenderCallback *self, ArtRender *render,
505 art_u8 *dest, int y)
506 {
507 ArtRenderMaskRun *run = render->run;
508 int n_run = render->n_run;
509 int x0 = render->x0;
510 int x;
511 int run_x0, run_x1;
512 art_u8 *alpha_buf = render->alpha_buf;
513 art_u8 *image_buf = render->image_buf;
514 int i, j;
515 art_u32 tmp;
516 art_u32 run_alpha;
517 art_u32 alpha;
518 int image_ix;
519 int n_chan = render->n_chan;
520 ArtAlphaType alpha_type = render->alpha_type;
521 int n_ch = n_chan + (alpha_type != ART_ALPHA_NONE);
522 int dst_pixstride = n_ch;
523 ArtAlphaType buf_alpha = render->buf_alpha;
524 int buf_n_ch = n_chan + (buf_alpha != ART_ALPHA_NONE);
525 int buf_pixstride = buf_n_ch;
526 art_u8 *bufptr;
527 art_u32 src_alpha;
528 art_u32 src_mul;
529 art_u8 *dstptr;
530 art_u32 dst_alpha;
531 art_u32 dst_mul, dst_save_mul;
532
533 image_ix = 0;
534 for (i = 0; i < n_run - 1; i++)
535 {
536 run_x0 = run[i].x;
537 run_x1 = run[i + 1].x;
538 tmp = run[i].alpha;
539 if (tmp < 0x10000)
540 continue;
541
542 run_alpha = (tmp + (tmp >> 8) + (tmp >> 16) - 0x8000) >> 8; /* range [0 .. 0x10000] */
543 bufptr = image_buf + (run_x0 - x0) * buf_pixstride;
544 dstptr = dest + (run_x0 - x0) * dst_pixstride;
545 for (x = run_x0; x < run_x1; x++)
546 {
547 if (alpha_buf)
548 {
549 tmp = run_alpha * alpha_buf[x - x0] + 0x80;
550 /* range 0x80 .. 0xff0080 */
551 alpha = (tmp + (tmp >> 8) + (tmp >> 16)) >> 8;
552 }
553 else
554 alpha = run_alpha;
555 /* alpha is run_alpha * alpha_buf[x], range 0 .. 0x10000 */
556
557 /* convert (src pixel * alpha) to premul alpha form,
558 store in src as 0..0xffff range */
559 if (buf_alpha == ART_ALPHA_NONE)
560 {
561 src_alpha = alpha;
562 src_mul = src_alpha;
563 }
564 else
565 {
566 tmp = alpha * bufptr[n_chan] + 0x80;
567 /* range 0x80 .. 0xff0080 */
568 src_alpha = (tmp + (tmp >> 8) + (tmp >> 16)) >> 8;
569
570 if (buf_alpha == ART_ALPHA_SEPARATE)
571 src_mul = src_alpha;
572 else /* buf_alpha == (ART_ALPHA_PREMUL) */
573 src_mul = alpha;
574 }
575 /* src_alpha is the (alpha of the source pixel * alpha),
576 range 0..0x10000 */
577
578 src_mul *= 0x101;
579
580 if (alpha_type == ART_ALPHA_NONE)
581 {
582 dst_alpha = 0x10000;
583 dst_mul = dst_alpha;
584 }
585 else
586 {
587 tmp = dstptr[n_chan];
588 /* range 0..0xff */
589 dst_alpha = (tmp << 8) + tmp + (tmp >> 7);
590 if (alpha_type == ART_ALPHA_SEPARATE)
591 dst_mul = dst_alpha;
592 else /* (alpha_type == ART_ALPHA_PREMUL) */
593 dst_mul = 0x10000;
594 }
595 /* dst_alpha is the alpha of the dest pixel,
596 range 0..0x10000 */
597
598 dst_mul *= 0x101;
599
600 if (alpha_type == ART_ALPHA_NONE)
601 {
602 dst_save_mul = 0xff;
603 }
604 else
605 {
606 if (src_alpha >= 0x10000)
607 dst_alpha = 0x10000;
608 else
609 dst_alpha += ((((0x10000 - dst_alpha) * src_alpha) >> 8) + 0x80) >> 8;
610 if (alpha_type == ART_ALPHA_PREMUL || dst_alpha == 0)
611 {
612 dst_save_mul = 0xff;
613 }
614 else /* (ALPHA_TYPE == ART_ALPHA_SEPARATE && dst_alpha != 0) */
615 {
616 dst_save_mul = 0xff0000 / dst_alpha;
617 }
618 }
619 for (j = 0; j < n_chan; j++)
620 {
621 art_u32 src, dst;
622 art_u32 tmp;
623
624 src = (bufptr[j] * src_mul + 0x8000) >> 16;
625 dst = (dstptr[j] * dst_mul + 0x8000) >> 16;
626 tmp = ((dst * (0x10000 - src_alpha) + 0x8000) >> 16) + src;
627 tmp -= tmp >> 16;
628 dstptr[j] = (tmp * dst_save_mul + 0x8000) >> 16;
629 }
630 if (alpha_type != ART_ALPHA_NONE)
631 dstptr[n_chan] = (dst_alpha * 0xff + 0x8000) >> 16;
632
633 bufptr += buf_pixstride;
634 dstptr += dst_pixstride;
635 }
636 }
637 }
638
639 const ArtRenderCallback art_render_composite_8_obj =
640 {
641 art_render_composite_8,
642 art_render_nop_done
643 };
644
645
646 /* Assumes:
647 * alpha_buf is NULL
648 * buf_alpha = ART_ALPHA_NONE (source)
649 * alpha_type = ART_ALPHA_SEPARATE (dest)
650 * n_chan = 3;
651 */
652 static void
art_render_composite_8_opt1(ArtRenderCallback * self,ArtRender * render,art_u8 * dest,int y)653 art_render_composite_8_opt1 (ArtRenderCallback *self, ArtRender *render,
654 art_u8 *dest, int y)
655 {
656 ArtRenderMaskRun *run = render->run;
657 int n_run = render->n_run;
658 int x0 = render->x0;
659 int x;
660 int run_x0, run_x1;
661 art_u8 *image_buf = render->image_buf;
662 int i, j;
663 art_u32 tmp;
664 art_u32 run_alpha;
665 int image_ix;
666 art_u8 *bufptr;
667 art_u32 src_mul;
668 art_u8 *dstptr;
669 art_u32 dst_alpha;
670 art_u32 dst_mul, dst_save_mul;
671
672 image_ix = 0;
673 for (i = 0; i < n_run - 1; i++)
674 {
675 run_x0 = run[i].x;
676 run_x1 = run[i + 1].x;
677 tmp = run[i].alpha;
678 if (tmp < 0x10000)
679 continue;
680
681 run_alpha = (tmp + (tmp >> 8) + (tmp >> 16) - 0x8000) >> 8; /* range [0 .. 0x10000] */
682 bufptr = image_buf + (run_x0 - x0) * 3;
683 dstptr = dest + (run_x0 - x0) * 4;
684 if (run_alpha == 0x10000)
685 {
686 for (x = run_x0; x < run_x1; x++)
687 {
688 *dstptr++ = *bufptr++;
689 *dstptr++ = *bufptr++;
690 *dstptr++ = *bufptr++;
691 *dstptr++ = 0xff;
692 }
693 }
694 else
695 {
696 for (x = run_x0; x < run_x1; x++)
697 {
698 src_mul = run_alpha * 0x101;
699
700 tmp = dstptr[3];
701 /* range 0..0xff */
702 dst_alpha = (tmp << 8) + tmp + (tmp >> 7);
703 dst_mul = dst_alpha;
704 /* dst_alpha is the alpha of the dest pixel,
705 range 0..0x10000 */
706
707 dst_mul *= 0x101;
708
709 dst_alpha += ((((0x10000 - dst_alpha) * run_alpha) >> 8) + 0x80) >> 8;
710 if (dst_alpha == 0)
711 dst_save_mul = 0xff;
712 else /* (dst_alpha != 0) */
713 dst_save_mul = 0xff0000 / dst_alpha;
714
715 for (j = 0; j < 3; j++)
716 {
717 art_u32 src, dst;
718 art_u32 tmp;
719
720 src = (bufptr[j] * src_mul + 0x8000) >> 16;
721 dst = (dstptr[j] * dst_mul + 0x8000) >> 16;
722 tmp = ((dst * (0x10000 - run_alpha) + 0x8000) >> 16) + src;
723 tmp -= tmp >> 16;
724 dstptr[j] = (tmp * dst_save_mul + 0x8000) >> 16;
725 }
726 dstptr[3] = (dst_alpha * 0xff + 0x8000) >> 16;
727
728 bufptr += 3;
729 dstptr += 4;
730 }
731 }
732 }
733 }
734
735
736 const ArtRenderCallback art_render_composite_8_opt1_obj =
737 {
738 art_render_composite_8_opt1,
739 art_render_nop_done
740 };
741
742 /* Assumes:
743 * alpha_buf is NULL
744 * buf_alpha = ART_ALPHA_PREMUL (source)
745 * alpha_type = ART_ALPHA_SEPARATE (dest)
746 * n_chan = 3;
747 */
748 static void
art_render_composite_8_opt2(ArtRenderCallback * self,ArtRender * render,art_u8 * dest,int y)749 art_render_composite_8_opt2 (ArtRenderCallback *self, ArtRender *render,
750 art_u8 *dest, int y)
751 {
752 ArtRenderMaskRun *run = render->run;
753 int n_run = render->n_run;
754 int x0 = render->x0;
755 int x;
756 int run_x0, run_x1;
757 art_u8 *image_buf = render->image_buf;
758 int i, j;
759 art_u32 tmp;
760 art_u32 run_alpha;
761 int image_ix;
762 art_u8 *bufptr;
763 art_u32 src_alpha;
764 art_u32 src_mul;
765 art_u8 *dstptr;
766 art_u32 dst_alpha;
767 art_u32 dst_mul, dst_save_mul;
768
769 image_ix = 0;
770 for (i = 0; i < n_run - 1; i++)
771 {
772 run_x0 = run[i].x;
773 run_x1 = run[i + 1].x;
774 tmp = run[i].alpha;
775 if (tmp < 0x10000)
776 continue;
777
778 run_alpha = (tmp + (tmp >> 8) + (tmp >> 16) - 0x8000) >> 8; /* range [0 .. 0x10000] */
779 bufptr = image_buf + (run_x0 - x0) * 4;
780 dstptr = dest + (run_x0 - x0) * 4;
781 if (run_alpha == 0x10000)
782 {
783 for (x = run_x0; x < run_x1; x++)
784 {
785 src_alpha = (bufptr[3] << 8) + bufptr[3] + (bufptr[3] >> 7);
786 /* src_alpha is the (alpha of the source pixel),
787 range 0..0x10000 */
788
789 dst_alpha = (dstptr[3] << 8) + dstptr[3] + (dstptr[3] >> 7);
790 /* dst_alpha is the alpha of the dest pixel,
791 range 0..0x10000 */
792
793 dst_mul = dst_alpha*0x101;
794
795 if (src_alpha >= 0x10000)
796 dst_alpha = 0x10000;
797 else
798 dst_alpha += ((((0x10000 - dst_alpha) * src_alpha) >> 8) + 0x80) >> 8;
799
800 if (dst_alpha == 0)
801 dst_save_mul = 0xff;
802 else /* dst_alpha != 0) */
803 dst_save_mul = 0xff0000 / dst_alpha;
804
805 for (j = 0; j < 3; j++)
806 {
807 art_u32 src, dst;
808 art_u32 tmp;
809
810 src = (bufptr[j] << 8) | bufptr[j];
811 dst = (dstptr[j] * dst_mul + 0x8000) >> 16;
812 tmp = ((dst * (0x10000 - src_alpha) + 0x8000) >> 16) + src;
813 tmp -= tmp >> 16;
814 dstptr[j] = (tmp * dst_save_mul + 0x8000) >> 16;
815 }
816 dstptr[3] = (dst_alpha * 0xff + 0x8000) >> 16;
817
818 bufptr += 4;
819 dstptr += 4;
820 }
821 }
822 else
823 {
824 for (x = run_x0; x < run_x1; x++)
825 {
826 tmp = run_alpha * bufptr[3] + 0x80;
827 /* range 0x80 .. 0xff0080 */
828 src_alpha = (tmp + (tmp >> 8) + (tmp >> 16)) >> 8;
829 /* src_alpha is the (alpha of the source pixel * alpha),
830 range 0..0x10000 */
831
832 src_mul = run_alpha * 0x101;
833
834 tmp = dstptr[3];
835 /* range 0..0xff */
836 dst_alpha = (tmp << 8) + tmp + (tmp >> 7);
837 dst_mul = dst_alpha;
838 /* dst_alpha is the alpha of the dest pixel,
839 range 0..0x10000 */
840
841 dst_mul *= 0x101;
842
843 if (src_alpha >= 0x10000)
844 dst_alpha = 0x10000;
845 else
846 dst_alpha += ((((0x10000 - dst_alpha) * src_alpha) >> 8) + 0x80) >> 8;
847
848 if (dst_alpha == 0)
849 {
850 dst_save_mul = 0xff;
851 }
852 else /* dst_alpha != 0) */
853 {
854 dst_save_mul = 0xff0000 / dst_alpha;
855 }
856
857 for (j = 0; j < 3; j++)
858 {
859 art_u32 src, dst;
860 art_u32 tmp;
861
862 src = (bufptr[j] * src_mul + 0x8000) >> 16;
863 dst = (dstptr[j] * dst_mul + 0x8000) >> 16;
864 tmp = ((dst * (0x10000 - src_alpha) + 0x8000) >> 16) + src;
865 tmp -= tmp >> 16;
866 dstptr[j] = (tmp * dst_save_mul + 0x8000) >> 16;
867 }
868 dstptr[3] = (dst_alpha * 0xff + 0x8000) >> 16;
869
870 bufptr += 4;
871 dstptr += 4;
872 }
873 }
874 }
875 }
876
877 const ArtRenderCallback art_render_composite_8_opt2_obj =
878 {
879 art_render_composite_8_opt2,
880 art_render_nop_done
881 };
882
883
884 /* todo: inline */
885 static ArtRenderCallback *
art_render_choose_compositing_callback(ArtRender * render)886 art_render_choose_compositing_callback (ArtRender *render)
887 {
888 if (render->depth == 8 && render->buf_depth == 8)
889 {
890 if (render->n_chan == 3 &&
891 render->alpha_buf == NULL &&
892 render->alpha_type == ART_ALPHA_SEPARATE)
893 {
894 if (render->buf_alpha == ART_ALPHA_NONE)
895 return (ArtRenderCallback *)&art_render_composite_8_opt1_obj;
896 else if (render->buf_alpha == ART_ALPHA_PREMUL)
897 return (ArtRenderCallback *)&art_render_composite_8_opt2_obj;
898 }
899
900 return (ArtRenderCallback *)&art_render_composite_8_obj;
901 }
902 return (ArtRenderCallback *)&art_render_composite_obj;
903 }
904
905 /**
906 * art_render_invoke_callbacks: Invoke the callbacks in the render object.
907 * @render: The render object.
908 * @y: The current Y coordinate value.
909 *
910 * Invokes the callbacks of the render object in the appropriate
911 * order. Drivers should call this routine once per scanline.
912 *
913 * todo: should management of dest devolve to this routine? very
914 * plausibly yes.
915 **/
916 void
art_render_invoke_callbacks(ArtRender * render,art_u8 * dest,int y)917 art_render_invoke_callbacks (ArtRender *render, art_u8 *dest, int y)
918 {
919 ArtRenderPriv *priv = (ArtRenderPriv *)render;
920 int i;
921
922 for (i = 0; i < priv->n_callbacks; i++)
923 {
924 ArtRenderCallback *callback;
925
926 callback = priv->callbacks[i];
927 callback->render (callback, render, dest, y);
928 }
929 }
930
931 /**
932 * art_render_invoke: Perform the requested rendering task.
933 * @render: The render object.
934 *
935 * Invokes the renderer and all sources associated with it, to perform
936 * the requested rendering task.
937 **/
938 void
art_render_invoke(ArtRender * render)939 art_render_invoke (ArtRender *render)
940 {
941 ArtRenderPriv *priv = (ArtRenderPriv *)render;
942 int width;
943 int best_driver, best_score;
944 int i;
945 int n_callbacks, n_callbacks_max;
946 ArtImageSource *image_source;
947 ArtImageSourceFlags image_flags;
948 int buf_depth;
949 ArtAlphaType buf_alpha;
950 art_boolean first = ART_TRUE;
951
952 if (render == NULL)
953 {
954 art_warn ("art_render_invoke: called with render == NULL\n");
955 return;
956 }
957 if (priv->image_source == NULL)
958 {
959 art_warn ("art_render_invoke: no image source given\n");
960 return;
961 }
962
963 width = render->x1 - render->x0;
964
965 render->run = art_new (ArtRenderMaskRun, width + 1);
966
967 /* Elect a mask source as driver. */
968 best_driver = -1;
969 best_score = 0;
970 for (i = 0; i < priv->n_mask_source; i++)
971 {
972 int score;
973 ArtMaskSource *mask_source;
974
975 mask_source = priv->mask_source[i];
976 score = mask_source->can_drive (mask_source, render);
977 if (score > best_score)
978 {
979 best_score = score;
980 best_driver = i;
981 }
982 }
983
984 /* Allocate alpha buffer if needed. */
985 if (priv->n_mask_source > 1 ||
986 (priv->n_mask_source == 1 && best_driver < 0))
987 {
988 render->alpha_buf = art_new (art_u8, (width * render->depth) >> 3);
989 }
990
991 /* Negotiate image rendering and compositing. */
992 image_source = priv->image_source;
993 image_source->negotiate (image_source, render, &image_flags, &buf_depth,
994 &buf_alpha);
995
996 /* Build callback list. */
997 n_callbacks_max = priv->n_mask_source + 3;
998 priv->callbacks = art_new (ArtRenderCallback *, n_callbacks_max);
999 n_callbacks = 0;
1000 for (i = 0; i < priv->n_mask_source; i++)
1001 if (i != best_driver)
1002 {
1003 ArtMaskSource *mask_source = priv->mask_source[i];
1004
1005 mask_source->prepare (mask_source, render, first);
1006 first = ART_FALSE;
1007 priv->callbacks[n_callbacks++] = &mask_source->super;
1008 }
1009
1010 if (render->clear && !(image_flags & ART_IMAGE_SOURCE_CAN_CLEAR))
1011 priv->callbacks[n_callbacks++] =
1012 art_render_choose_clear_callback (render);
1013
1014 priv->callbacks[n_callbacks++] = &image_source->super;
1015
1016 /* Allocate image buffer and add compositing callback if needed. */
1017 if (!(image_flags & ART_IMAGE_SOURCE_CAN_COMPOSITE))
1018 {
1019 int bytespp = ((render->n_chan + (buf_alpha != ART_ALPHA_NONE)) *
1020 buf_depth) >> 3;
1021 render->buf_depth = buf_depth;
1022 render->buf_alpha = buf_alpha;
1023 render->image_buf = art_new (art_u8, width * bytespp);
1024 priv->callbacks[n_callbacks++] =
1025 art_render_choose_compositing_callback (render);
1026 }
1027
1028 priv->n_callbacks = n_callbacks;
1029
1030 if (render->need_span)
1031 render->span_x = art_new (int, width + 1);
1032
1033 /* Invoke the driver */
1034 if (best_driver >= 0)
1035 {
1036 ArtMaskSource *driver;
1037
1038 driver = priv->mask_source[best_driver];
1039 driver->invoke_driver (driver, render);
1040 }
1041 else
1042 {
1043 art_u8 *dest_ptr = render->pixels;
1044 int y;
1045
1046 /* Dummy driver */
1047 render->n_run = 2;
1048 render->run[0].x = render->x0;
1049 render->run[0].alpha = 0x8000 + 0xff * render->opacity;
1050 render->run[1].x = render->x1;
1051 render->run[1].alpha = 0x8000;
1052 if (render->need_span)
1053 {
1054 render->n_span = 2;
1055 render->span_x[0] = render->x0;
1056 render->span_x[1] = render->x1;
1057 }
1058 for (y = render->y0; y < render->y1; y++)
1059 {
1060 art_render_invoke_callbacks (render, dest_ptr, y);
1061 dest_ptr += render->rowstride;
1062 }
1063 }
1064
1065 if (priv->mask_source != NULL)
1066 art_free (priv->mask_source);
1067
1068 /* clean up callbacks */
1069 for (i = 0; i < priv->n_callbacks; i++)
1070 {
1071 ArtRenderCallback *callback;
1072
1073 callback = priv->callbacks[i];
1074 callback->done (callback, render);
1075 }
1076
1077 /* Tear down object */
1078 if (render->alpha_buf != NULL)
1079 art_free (render->alpha_buf);
1080 if (render->image_buf != NULL)
1081 art_free (render->image_buf);
1082 art_free (render->run);
1083 if (render->span_x != NULL)
1084 art_free (render->span_x);
1085 art_free (priv->callbacks);
1086 art_free (render);
1087 }
1088
1089 /**
1090 * art_render_mask_solid: Add a solid translucent mask.
1091 * @render: The render object.
1092 * @opacity: Opacity in [0..0x10000] form.
1093 *
1094 * Adds a translucent mask to the rendering object.
1095 **/
1096 void
art_render_mask_solid(ArtRender * render,int opacity)1097 art_render_mask_solid (ArtRender *render, int opacity)
1098 {
1099 art_u32 old_opacity = render->opacity;
1100 art_u32 new_opacity_tmp;
1101
1102 if (opacity == 0x10000)
1103 /* avoid potential overflow */
1104 return;
1105 new_opacity_tmp = old_opacity * (art_u32)opacity + 0x8000;
1106 render->opacity = new_opacity_tmp >> 16;
1107 }
1108
1109 /**
1110 * art_render_add_mask_source: Add a mask source to the render object.
1111 * @render: Render object.
1112 * @mask_source: Mask source to add.
1113 *
1114 * This routine adds a mask source to the render object. In general,
1115 * client api's for adding mask sources should just take a render object,
1116 * then the mask source creation function should call this function.
1117 * Clients should never have to call this function directly, unless of
1118 * course they're creating custom mask sources.
1119 **/
1120 void
art_render_add_mask_source(ArtRender * render,ArtMaskSource * mask_source)1121 art_render_add_mask_source (ArtRender *render, ArtMaskSource *mask_source)
1122 {
1123 ArtRenderPriv *priv = (ArtRenderPriv *)render;
1124 int n_mask_source = priv->n_mask_source++;
1125
1126 if (n_mask_source == 0)
1127 priv->mask_source = art_new (ArtMaskSource *, 1);
1128 /* This predicate is true iff n_mask_source is a power of two */
1129 else if (!(n_mask_source & (n_mask_source - 1)))
1130 priv->mask_source = art_renew (priv->mask_source, ArtMaskSource *,
1131 n_mask_source << 1);
1132
1133 priv->mask_source[n_mask_source] = mask_source;
1134 }
1135
1136 /**
1137 * art_render_add_image_source: Add a mask source to the render object.
1138 * @render: Render object.
1139 * @image_source: Image source to add.
1140 *
1141 * This routine adds an image source to the render object. In general,
1142 * client api's for adding image sources should just take a render
1143 * object, then the mask source creation function should call this
1144 * function. Clients should never have to call this function
1145 * directly, unless of course they're creating custom image sources.
1146 **/
1147 void
art_render_add_image_source(ArtRender * render,ArtImageSource * image_source)1148 art_render_add_image_source (ArtRender *render, ArtImageSource *image_source)
1149 {
1150 ArtRenderPriv *priv = (ArtRenderPriv *)render;
1151
1152 if (priv->image_source != NULL)
1153 {
1154 art_warn ("art_render_add_image_source: image source already present.\n");
1155 return;
1156 }
1157 priv->image_source = image_source;
1158 }
1159
1160 /* Solid image source object and methods. Perhaps this should go into a
1161 separate file. */
1162
1163 typedef struct _ArtImageSourceSolid ArtImageSourceSolid;
1164
1165 struct _ArtImageSourceSolid {
1166 ArtImageSource super;
1167 ArtPixMaxDepth color[ART_MAX_CHAN];
1168 art_u32 *rgbtab;
1169 art_boolean init;
1170 };
1171
1172 static void
art_render_image_solid_done(ArtRenderCallback * self,ArtRender * render)1173 art_render_image_solid_done (ArtRenderCallback *self, ArtRender *render)
1174 {
1175 ArtImageSourceSolid *z = (ArtImageSourceSolid *)self;
1176
1177 if (z->rgbtab != NULL)
1178 art_free (z->rgbtab);
1179 art_free (self);
1180 }
1181
1182 static void
art_render_image_solid_rgb8_opaq_init(ArtImageSourceSolid * self,ArtRender * render)1183 art_render_image_solid_rgb8_opaq_init (ArtImageSourceSolid *self, ArtRender *render)
1184 {
1185 ArtImageSourceSolid *z = (ArtImageSourceSolid *)self;
1186 ArtPixMaxDepth color_max;
1187 int r_fg, g_fg, b_fg;
1188 int r_bg, g_bg, b_bg;
1189 int r, g, b;
1190 int dr, dg, db;
1191 int i;
1192 int tmp;
1193 art_u32 *rgbtab;
1194
1195 rgbtab = art_new (art_u32, 256);
1196 z->rgbtab = rgbtab;
1197
1198 color_max = self->color[0];
1199 r_fg = ART_PIX_8_FROM_MAX (color_max);
1200 color_max = self->color[1];
1201 g_fg = ART_PIX_8_FROM_MAX (color_max);
1202 color_max = self->color[2];
1203 b_fg = ART_PIX_8_FROM_MAX (color_max);
1204
1205 color_max = render->clear_color[0];
1206 r_bg = ART_PIX_8_FROM_MAX (color_max);
1207 color_max = render->clear_color[1];
1208 g_bg = ART_PIX_8_FROM_MAX (color_max);
1209 color_max = render->clear_color[2];
1210 b_bg = ART_PIX_8_FROM_MAX (color_max);
1211
1212 r = (r_bg << 16) + 0x8000;
1213 g = (g_bg << 16) + 0x8000;
1214 b = (b_bg << 16) + 0x8000;
1215 tmp = ((r_fg - r_bg) << 16) + 0x80;
1216 dr = (tmp + (tmp >> 8)) >> 8;
1217 tmp = ((g_fg - g_bg) << 16) + 0x80;
1218 dg = (tmp + (tmp >> 8)) >> 8;
1219 tmp = ((b_fg - b_bg) << 16) + 0x80;
1220 db = (tmp + (tmp >> 8)) >> 8;
1221
1222 for (i = 0; i < 256; i++)
1223 {
1224 rgbtab[i] = (r & 0xff0000) | ((g & 0xff0000) >> 8) | (b >> 16);
1225 r += dr;
1226 g += dg;
1227 b += db;
1228 }
1229 }
1230
1231 static void
art_render_image_solid_rgb8_opaq(ArtRenderCallback * self,ArtRender * render,art_u8 * dest,int y)1232 art_render_image_solid_rgb8_opaq (ArtRenderCallback *self, ArtRender *render,
1233 art_u8 *dest, int y)
1234 {
1235 ArtImageSourceSolid *z = (ArtImageSourceSolid *)self;
1236 ArtRenderMaskRun *run = render->run;
1237 int n_run = render->n_run;
1238 art_u32 *rgbtab = z->rgbtab;
1239 art_u32 rgb;
1240 int x0 = render->x0;
1241 int x1 = render->x1;
1242 int run_x0, run_x1;
1243 int i;
1244 int ix;
1245
1246 if (n_run > 0)
1247 {
1248 run_x1 = run[0].x;
1249 if (run_x1 > x0)
1250 {
1251 rgb = rgbtab[0];
1252 art_rgb_fill_run (dest,
1253 (art_u8)(rgb >> 16), (art_u8)((rgb >> 8) & 0xff), (art_u8)(rgb & 0xff),
1254 run_x1 - x0);
1255 }
1256 for (i = 0; i < n_run - 1; i++)
1257 {
1258 run_x0 = run_x1;
1259 run_x1 = run[i + 1].x;
1260 rgb = rgbtab[(run[i].alpha >> 16) & 0xff];
1261 ix = (run_x0 - x0) * 3;
1262 #define OPTIMIZE_LEN_1
1263 #ifdef OPTIMIZE_LEN_1
1264 if (run_x1 - run_x0 == 1)
1265 {
1266 dest[ix] = rgb >> 16;
1267 dest[ix + 1] = (rgb >> 8) & 0xff;
1268 dest[ix + 2] = rgb & 0xff;
1269 }
1270 else
1271 {
1272 art_rgb_fill_run (dest + ix,
1273 (art_u8)(rgb >> 16), (art_u8)((rgb >> 8) & 0xff), (art_u8)(rgb & 0xff),
1274 run_x1 - run_x0);
1275 }
1276 #else
1277 art_rgb_fill_run (dest + ix,
1278 (art_u8)(rgb >> 16), (art_u8)((rgb >> 8) & 0xff), (art_u8)(rgb & 0xff),
1279 run_x1 - run_x0);
1280 #endif
1281 }
1282 }
1283 else
1284 {
1285 run_x1 = x0;
1286 }
1287 if (run_x1 < x1)
1288 {
1289 rgb = rgbtab[0];
1290 art_rgb_fill_run (dest + (run_x1 - x0) * 3,
1291 (art_u8)(rgb >> 16), (art_u8)((rgb >> 8) & 0xff), (art_u8)(rgb & 0xff),
1292 x1 - run_x1);
1293 }
1294 }
1295
1296 static void
art_render_image_solid_rgb8(ArtRenderCallback * self,ArtRender * render,art_u8 * dest,int y)1297 art_render_image_solid_rgb8 (ArtRenderCallback *self, ArtRender *render,
1298 art_u8 *dest, int y)
1299 {
1300 ArtImageSourceSolid *z = (ArtImageSourceSolid *)self;
1301 int width = render->x1 - render->x0;
1302 art_u8 r, g, b;
1303 ArtPixMaxDepth color_max;
1304
1305 /* todo: replace this simple test with real sparseness */
1306 if (z->init)
1307 return;
1308 z->init = ART_TRUE;
1309
1310 color_max = z->color[0];
1311 r = ART_PIX_8_FROM_MAX (color_max);
1312 color_max = z->color[1];
1313 g = ART_PIX_8_FROM_MAX (color_max);
1314 color_max = z->color[2];
1315 b = ART_PIX_8_FROM_MAX (color_max);
1316
1317 art_rgb_fill_run (render->image_buf, r, g, b, width);
1318 }
1319
1320 static void
art_render_image_solid_negotiate(ArtImageSource * self,ArtRender * render,ArtImageSourceFlags * p_flags,int * p_buf_depth,ArtAlphaType * p_alpha)1321 art_render_image_solid_negotiate (ArtImageSource *self, ArtRender *render,
1322 ArtImageSourceFlags *p_flags,
1323 int *p_buf_depth, ArtAlphaType *p_alpha)
1324 {
1325 ArtImageSourceSolid *z = (ArtImageSourceSolid *)self;
1326 ArtImageSourceFlags flags = 0;
1327 static void (*render_cbk) (ArtRenderCallback *self, ArtRender *render,
1328 art_u8 *dest, int y);
1329
1330 render_cbk = NULL;
1331
1332 if (render->depth == 8 && render->n_chan == 3 &&
1333 render->alpha_type == ART_ALPHA_NONE)
1334 {
1335 if (render->clear)
1336 {
1337 render_cbk = art_render_image_solid_rgb8_opaq;
1338 flags |= ART_IMAGE_SOURCE_CAN_CLEAR | ART_IMAGE_SOURCE_CAN_COMPOSITE;
1339 art_render_image_solid_rgb8_opaq_init (z, render);
1340 }
1341 }
1342 if (render_cbk == NULL)
1343 {
1344 if (render->depth == 8)
1345 {
1346 render_cbk = art_render_image_solid_rgb8;
1347 *p_buf_depth = 8;
1348 *p_alpha = ART_ALPHA_NONE; /* todo */
1349 }
1350 }
1351 /* todo: general case */
1352 self->super.render = render_cbk;
1353 *p_flags = flags;
1354 }
1355
1356 /**
1357 * art_render_image_solid: Add a solid color image source.
1358 * @render: The render object.
1359 * @color: Color.
1360 *
1361 * Adds an image source with the solid color given by @color. The
1362 * color need not be retained in memory after this call.
1363 **/
1364 void
art_render_image_solid(ArtRender * render,ArtPixMaxDepth * color)1365 art_render_image_solid (ArtRender *render, ArtPixMaxDepth *color)
1366 {
1367 ArtImageSourceSolid *image_source;
1368 int i;
1369
1370 image_source = art_new (ArtImageSourceSolid, 1);
1371 image_source->super.super.render = NULL;
1372 image_source->super.super.done = art_render_image_solid_done;
1373 image_source->super.negotiate = art_render_image_solid_negotiate;
1374
1375 for (i = 0; i < render->n_chan; i++)
1376 image_source->color[i] = color[i];
1377
1378 image_source->rgbtab = NULL;
1379 image_source->init = ART_FALSE;
1380
1381 art_render_add_image_source (render, &image_source->super);
1382 }
1383