applied SVG patch from Magnus Lundin
[swftools.git] / lib / art / art_render.c
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 *
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
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
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
152 art_render_nop_done (ArtRenderCallback *self, ArtRender *render)
153 {
154 }
155
156 static void
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
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
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 *
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
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
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
620           for (j = 0; j < n_chan; j++)
621             {
622               art_u32 src, dst;
623               art_u32 tmp;
624
625               src = (bufptr[j] * src_mul + 0x8000) >> 16;
626               dst = (dstptr[j] * dst_mul + 0x8000) >> 16;
627               tmp = ((dst * (0x10000 - src_alpha) + 0x8000) >> 16) + src;
628               tmp -= tmp >> 16;
629               dstptr[j] = (tmp * dst_save_mul + 0x8000) >> 16;
630             }
631           if (alpha_type != ART_ALPHA_NONE)
632             dstptr[n_chan] = (dst_alpha * 0xff + 0x8000) >> 16;
633
634           bufptr += buf_pixstride;
635           dstptr += dst_pixstride;
636         }
637     }
638 }
639
640 const ArtRenderCallback art_render_composite_8_obj =
641 {
642   art_render_composite_8,
643   art_render_nop_done
644 };
645
646
647 /* Assumes:
648  * alpha_buf is NULL
649  * buf_alpha = ART_ALPHA_NONE  (source)
650  * alpha_type = ART_ALPHA_SEPARATE (dest)
651  * n_chan = 3;
652  */
653 static void
654 art_render_composite_8_opt1 (ArtRenderCallback *self, ArtRender *render,
655                              art_u8 *dest, int y)
656 {
657   ArtRenderMaskRun *run = render->run;
658   int n_run = render->n_run;
659   int x0 = render->x0;
660   int x;
661   int run_x0, run_x1;
662   art_u8 *image_buf = render->image_buf;
663   int i, j;
664   art_u32 tmp;
665   art_u32 run_alpha;
666   int image_ix;
667   art_u8 *bufptr;
668   art_u32 src_mul;
669   art_u8 *dstptr;
670   art_u32 dst_alpha;
671   art_u32 dst_mul, dst_save_mul;
672
673   image_ix = 0;
674   for (i = 0; i < n_run - 1; i++)
675     {
676       run_x0 = run[i].x;
677       run_x1 = run[i + 1].x;
678       tmp = run[i].alpha;
679       if (tmp < 0x10000)
680         continue;
681
682       run_alpha = (tmp + (tmp >> 8) + (tmp >> 16) - 0x8000) >> 8; /* range [0 .. 0x10000] */
683       bufptr = image_buf + (run_x0 - x0) * 3;
684       dstptr = dest + (run_x0 - x0) * 4;
685       if (run_alpha == 0x10000)
686         {
687           for (x = run_x0; x < run_x1; x++)
688             {
689               *dstptr++ = *bufptr++;
690               *dstptr++ = *bufptr++;
691               *dstptr++ = *bufptr++;
692               *dstptr++ = 0xff;
693             }
694         }
695       else
696         {
697           for (x = run_x0; x < run_x1; x++)
698             {
699               src_mul = run_alpha * 0x101;
700               
701               tmp = dstptr[3];
702               /* range 0..0xff */
703               dst_alpha = (tmp << 8) + tmp + (tmp >> 7);
704               dst_mul = dst_alpha;
705               /* dst_alpha is the alpha of the dest pixel,
706                  range 0..0x10000 */
707               
708               dst_mul *= 0x101;
709               
710               dst_alpha += ((((0x10000 - dst_alpha) * run_alpha) >> 8) + 0x80) >> 8;
711               if (dst_alpha == 0)
712                   dst_save_mul = 0xff;
713               else /* (dst_alpha != 0) */
714                   dst_save_mul = 0xff0000 / dst_alpha;
715               
716               for (j = 0; j < 3; j++)
717                 {
718                   art_u32 src, dst;
719                   art_u32 tmp;
720                   
721                   src = (bufptr[j] * src_mul + 0x8000) >> 16;
722                   dst = (dstptr[j] * dst_mul + 0x8000) >> 16;
723                   tmp = ((dst * (0x10000 - run_alpha) + 0x8000) >> 16) + src;
724                   tmp -= tmp >> 16;
725                   dstptr[j] = (tmp * dst_save_mul + 0x8000) >> 16;
726                 }
727               dstptr[3] = (dst_alpha * 0xff + 0x8000) >> 16;
728               
729               bufptr += 3;
730               dstptr += 4;
731             }
732         }
733     }
734 }
735
736
737 const ArtRenderCallback art_render_composite_8_opt1_obj =
738 {
739   art_render_composite_8_opt1,
740   art_render_nop_done
741 };
742
743 /* Assumes:
744  * alpha_buf is NULL
745  * buf_alpha = ART_ALPHA_PREMUL  (source)
746  * alpha_type = ART_ALPHA_SEPARATE (dest)
747  * n_chan = 3;
748  */
749 static void
750 art_render_composite_8_opt2 (ArtRenderCallback *self, ArtRender *render,
751                              art_u8 *dest, int y)
752 {
753   ArtRenderMaskRun *run = render->run;
754   int n_run = render->n_run;
755   int x0 = render->x0;
756   int x;
757   int run_x0, run_x1;
758   art_u8 *image_buf = render->image_buf;
759   int i, j;
760   art_u32 tmp;
761   art_u32 run_alpha;
762   int image_ix;
763   art_u8 *bufptr;
764   art_u32 src_alpha;
765   art_u32 src_mul;
766   art_u8 *dstptr;
767   art_u32 dst_alpha;
768   art_u32 dst_mul, dst_save_mul;
769
770   image_ix = 0;
771   for (i = 0; i < n_run - 1; i++)
772     {
773       run_x0 = run[i].x;
774       run_x1 = run[i + 1].x;
775       tmp = run[i].alpha;
776       if (tmp < 0x10000)
777         continue;
778
779       run_alpha = (tmp + (tmp >> 8) + (tmp >> 16) - 0x8000) >> 8; /* range [0 .. 0x10000] */
780       bufptr = image_buf + (run_x0 - x0) * 4;
781       dstptr = dest + (run_x0 - x0) * 4;
782       if (run_alpha == 0x10000)
783         {
784           for (x = run_x0; x < run_x1; x++)
785             {
786               src_alpha = (bufptr[3] << 8) + bufptr[3] + (bufptr[3] >> 7);
787               /* src_alpha is the (alpha of the source pixel),
788                  range 0..0x10000 */
789               
790               dst_alpha = (dstptr[3] << 8) + dstptr[3] + (dstptr[3] >> 7);
791               /* dst_alpha is the alpha of the dest pixel,
792                  range 0..0x10000 */
793               
794               dst_mul = dst_alpha*0x101;
795               
796               if (src_alpha >= 0x10000)
797                 dst_alpha = 0x10000;
798               else
799                 dst_alpha += ((((0x10000 - dst_alpha) * src_alpha) >> 8) + 0x80) >> 8;
800               
801               if (dst_alpha == 0)
802                   dst_save_mul = 0xff;
803               else /* dst_alpha != 0) */
804                   dst_save_mul = 0xff0000 / dst_alpha;
805               
806               for (j = 0; j < 3; j++)
807                 {
808                   art_u32 src, dst;
809                   art_u32 tmp;
810                   
811                   src = (bufptr[j] << 8) |  bufptr[j];
812                   dst = (dstptr[j] * dst_mul + 0x8000) >> 16;
813                   tmp = ((dst * (0x10000 - src_alpha) + 0x8000) >> 16) + src;
814                   tmp -= tmp >> 16;
815                   dstptr[j] = (tmp * dst_save_mul + 0x8000) >> 16;
816                 }
817               dstptr[3] = (dst_alpha * 0xff + 0x8000) >> 16;
818               
819               bufptr += 4;
820               dstptr += 4;
821             }
822         }
823       else
824         {
825           for (x = run_x0; x < run_x1; x++)
826             {
827               tmp = run_alpha * bufptr[3] + 0x80;
828               /* range 0x80 .. 0xff0080 */
829               src_alpha = (tmp + (tmp >> 8) + (tmp >> 16)) >> 8;
830               /* src_alpha is the (alpha of the source pixel * alpha),
831                  range 0..0x10000 */
832               
833               src_mul = run_alpha * 0x101;
834               
835               tmp = dstptr[3];
836               /* range 0..0xff */
837               dst_alpha = (tmp << 8) + tmp + (tmp >> 7);
838               dst_mul = dst_alpha;
839               /* dst_alpha is the alpha of the dest pixel,
840                  range 0..0x10000 */
841               
842               dst_mul *= 0x101;
843               
844               if (src_alpha >= 0x10000)
845                 dst_alpha = 0x10000;
846               else
847                 dst_alpha += ((((0x10000 - dst_alpha) * src_alpha) >> 8) + 0x80) >> 8;
848               
849               if (dst_alpha == 0)
850                 {
851                   dst_save_mul = 0xff;
852                 }
853               else /* dst_alpha != 0) */
854                 {
855                   dst_save_mul = 0xff0000 / dst_alpha;
856                 }
857               
858               for (j = 0; j < 3; j++)
859                 {
860                   art_u32 src, dst;
861                   art_u32 tmp;
862                   
863                   src = (bufptr[j] * src_mul + 0x8000) >> 16;
864                   dst = (dstptr[j] * dst_mul + 0x8000) >> 16;
865                   tmp = ((dst * (0x10000 - src_alpha) + 0x8000) >> 16) + src;
866                   tmp -= tmp >> 16;
867                   dstptr[j] = (tmp * dst_save_mul + 0x8000) >> 16;
868                 }
869               dstptr[3] = (dst_alpha * 0xff + 0x8000) >> 16;
870               
871               bufptr += 4;
872               dstptr += 4;
873             }
874         }
875     }
876 }
877
878 const ArtRenderCallback art_render_composite_8_opt2_obj =
879 {
880   art_render_composite_8_opt2,
881   art_render_nop_done
882 };
883
884
885 /* todo: inline */
886 static ArtRenderCallback *
887 art_render_choose_compositing_callback (ArtRender *render)
888 {
889   if (render->depth == 8 && render->buf_depth == 8)
890     {
891       if (render->n_chan == 3 &&
892           render->alpha_buf == NULL &&
893           render->alpha_type == ART_ALPHA_SEPARATE)
894         {
895           if (render->buf_alpha == ART_ALPHA_NONE)
896             return (ArtRenderCallback *)&art_render_composite_8_opt1_obj;
897           else if (render->buf_alpha == ART_ALPHA_PREMUL)
898             return (ArtRenderCallback *)&art_render_composite_8_opt2_obj;
899         }
900           
901       return (ArtRenderCallback *)&art_render_composite_8_obj;
902     }
903   return (ArtRenderCallback *)&art_render_composite_obj;
904 }
905
906 /**
907  * art_render_invoke_callbacks: Invoke the callbacks in the render object.
908  * @render: The render object.
909  * @y: The current Y coordinate value.
910  *
911  * Invokes the callbacks of the render object in the appropriate
912  * order.  Drivers should call this routine once per scanline.
913  *
914  * todo: should management of dest devolve to this routine? very
915  * plausibly yes.
916  **/
917 void
918 art_render_invoke_callbacks (ArtRender *render, art_u8 *dest, int y)
919 {
920   ArtRenderPriv *priv = (ArtRenderPriv *)render;
921   int i;
922
923   for (i = 0; i < priv->n_callbacks; i++)
924     {
925       ArtRenderCallback *callback;
926
927       callback = priv->callbacks[i];
928       callback->render (callback, render, dest, y);
929     }
930 }
931
932 /**
933  * art_render_invoke: Perform the requested rendering task.
934  * @render: The render object.
935  *
936  * Invokes the renderer and all sources associated with it, to perform
937  * the requested rendering task.
938  **/
939 void
940 art_render_invoke (ArtRender *render)
941 {
942   ArtRenderPriv *priv = (ArtRenderPriv *)render;
943   int width;
944   int best_driver, best_score;
945   int i;
946   int n_callbacks, n_callbacks_max;
947   ArtImageSource *image_source;
948   ArtImageSourceFlags image_flags;
949   int buf_depth;
950   ArtAlphaType buf_alpha;
951   art_boolean first = ART_TRUE;
952
953   if (render == NULL)
954     {
955       art_warn ("art_render_invoke: called with render == NULL\n");
956       return;
957     }
958   if (priv->image_source == NULL)
959     {
960       art_warn ("art_render_invoke: no image source given\n");
961       return;
962     }
963
964   width = render->x1 - render->x0;
965
966   render->run = art_new (ArtRenderMaskRun, width + 1);
967
968   /* Elect a mask source as driver. */
969   best_driver = -1;
970   best_score = 0;
971   for (i = 0; i < priv->n_mask_source; i++)
972     {
973       int score;
974       ArtMaskSource *mask_source;
975
976       mask_source = priv->mask_source[i];
977       score = mask_source->can_drive (mask_source, render);
978       if (score > best_score)
979         {
980           best_score = score;
981           best_driver = i;
982         }
983     }
984
985   /* Allocate alpha buffer if needed. */
986   if (priv->n_mask_source > 1 ||
987       (priv->n_mask_source == 1 && best_driver < 0))
988     {
989       render->alpha_buf = art_new (art_u8, (width * render->depth) >> 3);
990     }
991
992   /* Negotiate image rendering and compositing. */
993   image_source = priv->image_source;
994   image_source->negotiate (image_source, render, &image_flags, &buf_depth,
995                            &buf_alpha);
996
997   /* Build callback list. */
998   n_callbacks_max = priv->n_mask_source + 3;
999   priv->callbacks = art_new (ArtRenderCallback *, n_callbacks_max);
1000   n_callbacks = 0;
1001   for (i = 0; i < priv->n_mask_source; i++)
1002     if (i != best_driver)
1003       {
1004         ArtMaskSource *mask_source = priv->mask_source[i];
1005
1006         mask_source->prepare (mask_source, render, first);
1007         first = ART_FALSE;
1008         priv->callbacks[n_callbacks++] = &mask_source->super;
1009       }
1010
1011   if (render->clear && !(image_flags & ART_IMAGE_SOURCE_CAN_CLEAR))
1012     priv->callbacks[n_callbacks++] =
1013       art_render_choose_clear_callback (render);
1014
1015   priv->callbacks[n_callbacks++] = &image_source->super;
1016
1017   /* Allocate image buffer and add compositing callback if needed. */
1018   if (!(image_flags & ART_IMAGE_SOURCE_CAN_COMPOSITE))
1019     {
1020       int bytespp = ((render->n_chan + (buf_alpha != ART_ALPHA_NONE)) *
1021                      buf_depth) >> 3;
1022       render->buf_depth = buf_depth;
1023       render->buf_alpha = buf_alpha;
1024       render->image_buf = art_new (art_u8, width * bytespp);
1025       priv->callbacks[n_callbacks++] =
1026         art_render_choose_compositing_callback (render);
1027     }
1028
1029   priv->n_callbacks = n_callbacks;
1030
1031   if (render->need_span)
1032     render->span_x = art_new (int, width + 1);
1033
1034   /* Invoke the driver */
1035   if (best_driver >= 0)
1036     {
1037       ArtMaskSource *driver;
1038
1039       driver = priv->mask_source[best_driver];
1040       driver->invoke_driver (driver, render);
1041     }
1042   else
1043     {
1044       art_u8 *dest_ptr = render->pixels;
1045       int y;
1046
1047       /* Dummy driver */
1048       render->n_run = 2;
1049       render->run[0].x = render->x0;
1050       render->run[0].alpha = 0x8000 + 0xff * render->opacity;
1051       render->run[1].x = render->x1;
1052       render->run[1].alpha = 0x8000;
1053       if (render->need_span)
1054         {
1055           render->n_span = 2;
1056           render->span_x[0] = render->x0;
1057           render->span_x[1] = render->x1;
1058         }
1059       for (y = render->y0; y < render->y1; y++)
1060         {
1061           art_render_invoke_callbacks (render, dest_ptr, y);
1062           dest_ptr += render->rowstride;
1063         }
1064     }
1065
1066   if (priv->mask_source != NULL)
1067     art_free (priv->mask_source);
1068
1069   /* clean up callbacks */
1070   for (i = 0; i < priv->n_callbacks; i++)
1071     {
1072       ArtRenderCallback *callback;
1073
1074       callback = priv->callbacks[i];
1075       callback->done (callback, render);
1076     }
1077
1078   /* Tear down object */
1079   if (render->alpha_buf != NULL)
1080     art_free (render->alpha_buf);
1081   if (render->image_buf != NULL)
1082     art_free (render->image_buf);
1083   art_free (render->run);
1084   if (render->span_x != NULL)
1085     art_free (render->span_x);
1086   art_free (priv->callbacks);
1087   art_free (render);
1088 }
1089
1090 /**
1091  * art_render_mask_solid: Add a solid translucent mask.
1092  * @render: The render object.
1093  * @opacity: Opacity in [0..0x10000] form.
1094  *
1095  * Adds a translucent mask to the rendering object.
1096  **/
1097 void
1098 art_render_mask_solid (ArtRender *render, int opacity)
1099 {
1100   art_u32 old_opacity = render->opacity;
1101   art_u32 new_opacity_tmp;
1102
1103   if (opacity == 0x10000)
1104     /* avoid potential overflow */
1105     return;
1106   new_opacity_tmp = old_opacity * (art_u32)opacity + 0x8000;
1107   render->opacity = new_opacity_tmp >> 16;
1108 }
1109
1110 /**
1111  * art_render_add_mask_source: Add a mask source to the render object.
1112  * @render: Render object.
1113  * @mask_source: Mask source to add.
1114  *
1115  * This routine adds a mask source to the render object. In general,
1116  * client api's for adding mask sources should just take a render object,
1117  * then the mask source creation function should call this function.
1118  * Clients should never have to call this function directly, unless of
1119  * course they're creating custom mask sources.
1120  **/
1121 void
1122 art_render_add_mask_source (ArtRender *render, ArtMaskSource *mask_source)
1123 {
1124   ArtRenderPriv *priv = (ArtRenderPriv *)render;
1125   int n_mask_source = priv->n_mask_source++;
1126
1127   if (n_mask_source == 0)
1128     priv->mask_source = art_new (ArtMaskSource *, 1);
1129   /* This predicate is true iff n_mask_source is a power of two */
1130   else if (!(n_mask_source & (n_mask_source - 1)))
1131     priv->mask_source = art_renew (priv->mask_source, ArtMaskSource *,
1132                                    n_mask_source << 1);
1133
1134   priv->mask_source[n_mask_source] = mask_source;
1135 }
1136
1137 /**
1138  * art_render_add_image_source: Add a mask source to the render object.
1139  * @render: Render object.
1140  * @image_source: Image source to add.
1141  *
1142  * This routine adds an image source to the render object. In general,
1143  * client api's for adding image sources should just take a render
1144  * object, then the mask source creation function should call this
1145  * function.  Clients should never have to call this function
1146  * directly, unless of course they're creating custom image sources.
1147  **/
1148 void
1149 art_render_add_image_source (ArtRender *render, ArtImageSource *image_source)
1150 {
1151   ArtRenderPriv *priv = (ArtRenderPriv *)render;
1152
1153   if (priv->image_source != NULL)
1154     {
1155       art_warn ("art_render_add_image_source: image source already present.\n");
1156       return;
1157     }
1158   priv->image_source = image_source;
1159 }
1160
1161 /* Solid image source object and methods. Perhaps this should go into a
1162    separate file. */
1163
1164 typedef struct _ArtImageSourceSolid ArtImageSourceSolid;
1165
1166 struct _ArtImageSourceSolid {
1167   ArtImageSource super;
1168   ArtPixMaxDepth color[ART_MAX_CHAN];
1169   art_u32 *rgbtab;
1170   art_boolean init;
1171 };
1172
1173 static void
1174 art_render_image_solid_done (ArtRenderCallback *self, ArtRender *render)
1175 {
1176   ArtImageSourceSolid *z = (ArtImageSourceSolid *)self;
1177
1178   if (z->rgbtab != NULL)
1179     art_free (z->rgbtab);
1180   art_free (self);
1181 }
1182
1183 static void
1184 art_render_image_solid_rgb8_opaq_init (ArtImageSourceSolid *self, ArtRender *render)
1185 {
1186   ArtImageSourceSolid *z = (ArtImageSourceSolid *)self;
1187   ArtPixMaxDepth color_max;
1188   int r_fg, g_fg, b_fg;
1189   int r_bg, g_bg, b_bg;
1190   int r, g, b;
1191   int dr, dg, db;
1192   int i;
1193   int tmp;
1194   art_u32 *rgbtab;
1195
1196   rgbtab = art_new (art_u32, 256);
1197   z->rgbtab = rgbtab;
1198
1199   color_max = self->color[0];
1200   r_fg = ART_PIX_8_FROM_MAX (color_max);
1201   color_max = self->color[1];
1202   g_fg = ART_PIX_8_FROM_MAX (color_max);
1203   color_max = self->color[2];
1204   b_fg = ART_PIX_8_FROM_MAX (color_max);
1205
1206   color_max = render->clear_color[0];
1207   r_bg = ART_PIX_8_FROM_MAX (color_max);
1208   color_max = render->clear_color[1];
1209   g_bg = ART_PIX_8_FROM_MAX (color_max);
1210   color_max = render->clear_color[2];
1211   b_bg = ART_PIX_8_FROM_MAX (color_max);
1212
1213   r = (r_bg << 16) + 0x8000;
1214   g = (g_bg << 16) + 0x8000;
1215   b = (b_bg << 16) + 0x8000;
1216   tmp = ((r_fg - r_bg) << 16) + 0x80;
1217   dr = (tmp + (tmp >> 8)) >> 8;
1218   tmp = ((g_fg - g_bg) << 16) + 0x80;
1219   dg = (tmp + (tmp >> 8)) >> 8;
1220   tmp = ((b_fg - b_bg) << 16) + 0x80;
1221   db = (tmp + (tmp >> 8)) >> 8;
1222
1223   for (i = 0; i < 256; i++)
1224     {
1225       rgbtab[i] = (r & 0xff0000) | ((g & 0xff0000) >> 8) | (b >> 16);
1226       r += dr;
1227       g += dg;
1228       b += db;
1229     }
1230 }
1231
1232 static void
1233 art_render_image_solid_rgb8_opaq (ArtRenderCallback *self, ArtRender *render,
1234                                   art_u8 *dest, int y)
1235 {
1236   ArtImageSourceSolid *z = (ArtImageSourceSolid *)self;
1237   ArtRenderMaskRun *run = render->run;
1238   int n_run = render->n_run;
1239   art_u32 *rgbtab = z->rgbtab;
1240   art_u32 rgb;
1241   int x0 = render->x0;
1242   int x1 = render->x1;
1243   int run_x0, run_x1;
1244   int i;
1245   int ix;
1246
1247   if (n_run > 0)
1248     {
1249       run_x1 = run[0].x;
1250       if (run_x1 > x0)
1251         {
1252           rgb = rgbtab[0];
1253           art_rgb_fill_run (dest,
1254                             rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff,
1255                             run_x1 - x0);
1256         }
1257       for (i = 0; i < n_run - 1; i++)
1258         {
1259           run_x0 = run_x1;
1260           run_x1 = run[i + 1].x;
1261           rgb = rgbtab[(run[i].alpha >> 16) & 0xff];
1262           ix = (run_x0 - x0) * 3;
1263 #define OPTIMIZE_LEN_1
1264 #ifdef OPTIMIZE_LEN_1
1265           if (run_x1 - run_x0 == 1)
1266             {
1267               dest[ix] = rgb >> 16;
1268               dest[ix + 1] = (rgb >> 8) & 0xff;
1269               dest[ix + 2] = rgb & 0xff;
1270             }
1271           else
1272             {
1273               art_rgb_fill_run (dest + ix,
1274                                 rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff,
1275                                 run_x1 - run_x0);
1276             }
1277 #else
1278           art_rgb_fill_run (dest + ix,
1279                             rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff,
1280                             run_x1 - run_x0);
1281 #endif
1282         }
1283     }
1284   else
1285     {
1286       run_x1 = x0;
1287     }
1288   if (run_x1 < x1)
1289     {
1290       rgb = rgbtab[0];
1291       art_rgb_fill_run (dest + (run_x1 - x0) * 3,
1292                         rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff,
1293                         x1 - run_x1);
1294     }
1295 }
1296
1297 static void
1298 art_render_image_solid_rgb8 (ArtRenderCallback *self, ArtRender *render,
1299                              art_u8 *dest, int y)
1300 {
1301   ArtImageSourceSolid *z = (ArtImageSourceSolid *)self;
1302   int width = render->x1 - render->x0;
1303   art_u8 r, g, b;
1304   ArtPixMaxDepth color_max;
1305
1306   /* todo: replace this simple test with real sparseness */
1307   if (z->init)
1308     return;
1309   z->init = ART_TRUE;
1310
1311   color_max = z->color[0];
1312   r = ART_PIX_8_FROM_MAX (color_max);
1313   color_max = z->color[1];
1314   g = ART_PIX_8_FROM_MAX (color_max);
1315   color_max = z->color[2];
1316   b = ART_PIX_8_FROM_MAX (color_max);
1317
1318   art_rgb_fill_run (render->image_buf, r, g, b, width);
1319 }
1320
1321 static void
1322 art_render_image_solid_negotiate (ArtImageSource *self, ArtRender *render,
1323                                   ArtImageSourceFlags *p_flags,
1324                                   int *p_buf_depth, ArtAlphaType *p_alpha)
1325 {
1326   ArtImageSourceSolid *z = (ArtImageSourceSolid *)self;
1327   ArtImageSourceFlags flags = 0;
1328   static void (*render_cbk) (ArtRenderCallback *self, ArtRender *render,
1329                              art_u8 *dest, int y);
1330
1331   render_cbk = NULL;
1332
1333   if (render->depth == 8 && render->n_chan == 3 &&
1334       render->alpha_type == ART_ALPHA_NONE)
1335     {
1336       if (render->clear)
1337         {
1338           render_cbk = art_render_image_solid_rgb8_opaq;
1339           flags |= ART_IMAGE_SOURCE_CAN_CLEAR | ART_IMAGE_SOURCE_CAN_COMPOSITE;
1340           art_render_image_solid_rgb8_opaq_init (z, render);
1341         }
1342     }
1343   if (render_cbk == NULL)
1344     {
1345       if (render->depth == 8)
1346         {
1347           render_cbk = art_render_image_solid_rgb8;
1348           *p_buf_depth = 8;
1349           *p_alpha = ART_ALPHA_NONE; /* todo */
1350         }
1351     }
1352   /* todo: general case */
1353   self->super.render = render_cbk;
1354   *p_flags = flags;
1355 }
1356
1357 /**
1358  * art_render_image_solid: Add a solid color image source.
1359  * @render: The render object.
1360  * @color: Color.
1361  *
1362  * Adds an image source with the solid color given by @color. The
1363  * color need not be retained in memory after this call.
1364  **/
1365 void
1366 art_render_image_solid (ArtRender *render, ArtPixMaxDepth *color)
1367 {
1368   ArtImageSourceSolid *image_source;
1369   int i;
1370
1371   image_source = art_new (ArtImageSourceSolid, 1);
1372   image_source->super.super.render = NULL;
1373   image_source->super.super.done = art_render_image_solid_done;
1374   image_source->super.negotiate = art_render_image_solid_negotiate;
1375
1376   for (i = 0; i < render->n_chan; i++)
1377     image_source->color[i] = color[i];
1378
1379   image_source->rgbtab = NULL;
1380   image_source->init = ART_FALSE;
1381
1382   art_render_add_image_source (render, &image_source->super);
1383 }