The BIG graph update
[rrdtool.git] / libraries / libart_lgpl-2.3.7 / 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 "art_misc.h"
24 #include "art_alphagamma.h"
25 #include "art_rgb.h"
26
27 #include "art_render.h"
28
29 typedef struct _ArtRenderPriv ArtRenderPriv;
30
31 struct _ArtRenderPriv {
32   ArtRender super;
33
34   ArtImageSource *image_source;
35
36   int n_mask_source;
37   ArtMaskSource **mask_source;
38
39   int n_callbacks;
40   ArtRenderCallback **callbacks;
41 };
42
43 ArtRender *
44 art_render_new (int x0, int y0, int x1, int y1,
45                 art_u8 *pixels, int rowstride,
46                 int n_chan, int depth, ArtAlphaType alpha_type,
47                 ArtAlphaGamma *alphagamma)
48 {
49   ArtRenderPriv *priv;
50   ArtRender *result;
51
52   priv = art_new (ArtRenderPriv, 1);
53   result = &priv->super;
54
55   if (n_chan > ART_MAX_CHAN)
56     {
57       art_warn ("art_render_new: n_chan = %d, exceeds %d max\n",
58                 n_chan, ART_MAX_CHAN);
59       return NULL;
60     }
61   if (depth > ART_MAX_DEPTH)
62     {
63       art_warn ("art_render_new: depth = %d, exceeds %d max\n",
64                 depth, ART_MAX_DEPTH);
65       return NULL;
66     }
67   if (x0 >= x1)
68     {
69       art_warn ("art_render_new: x0 >= x1 (x0 = %d, x1 = %d)\n", x0, x1);
70       return NULL;
71     }
72   result->x0 = x0;
73   result->y0 = y0;
74   result->x1 = x1;
75   result->y1 = y1;
76   result->pixels = pixels;
77   result->rowstride = rowstride;
78   result->n_chan = n_chan;
79   result->depth = depth;
80   result->alpha_type = alpha_type;
81
82   result->clear = ART_FALSE;
83   result->opacity = 0x10000;
84   result->compositing_mode = ART_COMPOSITE_NORMAL;
85   result->alphagamma = alphagamma;
86
87   result->alpha_buf = NULL;
88   result->image_buf = NULL;
89
90   result->run = NULL;
91   result->span_x = NULL;
92
93   result->need_span = ART_FALSE;
94
95   priv->image_source = NULL;
96
97   priv->n_mask_source = 0;
98   priv->mask_source = NULL;
99
100   return result;
101 }
102
103 /* todo on clear routines: I haven't really figured out what to do
104    with clearing the alpha channel. It _should_ be possible to clear
105    to an arbitrary RGBA color. */
106
107 /**
108  * art_render_clear: Set clear color.
109  * @clear_color: Color with which to clear dest.
110  *
111  * Sets clear color, equivalent to actually clearing the destination
112  * buffer before rendering. This is the most general form.
113  **/
114 void
115 art_render_clear (ArtRender *render, const ArtPixMaxDepth *clear_color)
116 {
117   int i;
118   int n_ch = render->n_chan + (render->alpha_type != ART_ALPHA_NONE);
119
120   render->clear = ART_TRUE;
121   for (i = 0; i < n_ch; i++)
122     render->clear_color[i] = clear_color[i];
123 }
124
125 /**
126  * art_render_clear_rgb: Set clear color, given in RGB format.
127  * @clear_rgb: Clear color, in 0xRRGGBB format.
128  *
129  * Sets clear color, equivalent to actually clearing the destination
130  * buffer before rendering.
131  **/
132 void
133 art_render_clear_rgb (ArtRender *render, art_u32 clear_rgb)
134 {
135   if (render->n_chan != 3)
136     art_warn ("art_render_clear_rgb: called on render with %d channels, only works with 3\n",
137               render->n_chan);
138   else
139     {
140       int r, g, b;
141
142       render->clear = ART_TRUE;
143       r = clear_rgb >> 16;
144       g = (clear_rgb >> 8) & 0xff;
145       b = clear_rgb & 0xff;
146       render->clear_color[0] = ART_PIX_MAX_FROM_8(r);
147       render->clear_color[1] = ART_PIX_MAX_FROM_8(g);
148       render->clear_color[2] = ART_PIX_MAX_FROM_8(b);
149     }
150 }
151
152 static void
153 art_render_nop_done (ArtRenderCallback *self, ArtRender *render)
154 {
155 }
156
157 static void
158 art_render_clear_render_rgb8 (ArtRenderCallback *self, ArtRender *render,
159                               art_u8 *dest, int y)
160 {
161   int width = render->x1 - render->x0;
162   art_u8 r, g, b;
163   ArtPixMaxDepth color_max;
164
165   color_max = render->clear_color[0];
166   r = ART_PIX_8_FROM_MAX (color_max);
167   color_max = render->clear_color[1];
168   g = ART_PIX_8_FROM_MAX (color_max);
169   color_max = render->clear_color[2];
170   b = ART_PIX_8_FROM_MAX (color_max);
171
172   art_rgb_fill_run (dest, r, g, b, width);
173 }
174
175 static void
176 art_render_clear_render_8 (ArtRenderCallback *self, ArtRender *render,
177                            art_u8 *dest, int y)
178 {
179   int width = render->x1 - render->x0;
180   int i, j;
181   int n_ch = render->n_chan + (render->alpha_type != ART_ALPHA_NONE);
182   int ix;
183   art_u8 color[ART_MAX_CHAN + 1];
184
185   for (j = 0; j < n_ch; j++)
186     {
187       ArtPixMaxDepth color_max = render->clear_color[j];
188       color[j] = ART_PIX_8_FROM_MAX (color_max);
189     }
190
191   ix = 0;
192   for (i = 0; i < width; i++)
193     for (j = 0; j < n_ch; j++)
194       dest[ix++] = color[j];
195 }
196
197 const ArtRenderCallback art_render_clear_rgb8_obj =
198 {
199   art_render_clear_render_rgb8,
200   art_render_nop_done
201 };
202
203 const ArtRenderCallback art_render_clear_8_obj =
204 {
205   art_render_clear_render_8,
206   art_render_nop_done
207 };
208
209 #if ART_MAX_DEPTH >= 16
210
211 static void
212 art_render_clear_render_16 (ArtRenderCallback *self, ArtRender *render,
213                             art_u8 *dest, int y)
214 {
215   int width = render->x1 - render->x0;
216   int i, j;
217   int n_ch = render->n_chan + (render->alpha_type != ART_ALPHA_NONE);
218   int ix;
219   art_u16 *dest_16 = (art_u16 *)dest;
220   art_u8 color[ART_MAX_CHAN + 1];
221
222   for (j = 0; j < n_ch; j++)
223     {
224       int color_16 = render->clear_color[j];
225       color[j] = color_16;
226     }
227
228   ix = 0;
229   for (i = 0; i < width; i++)
230     for (j = 0; j < n_ch; j++)
231       dest_16[ix++] = color[j];
232 }
233
234 const ArtRenderCallback art_render_clear_16_obj =
235 {
236   art_render_clear_render_16,
237   art_render_nop_done
238 };
239
240 #endif /* ART_MAX_DEPTH >= 16 */
241
242 /* todo: inline */
243 static ArtRenderCallback *
244 art_render_choose_clear_callback (ArtRender *render)
245 {
246   ArtRenderCallback *clear_callback;
247
248   if (render->depth == 8)
249     {
250       if (render->n_chan == 3 &&
251           render->alpha_type == ART_ALPHA_NONE)
252         clear_callback = (ArtRenderCallback *)&art_render_clear_rgb8_obj;
253       else
254         clear_callback = (ArtRenderCallback *)&art_render_clear_8_obj;
255     }
256 #if ART_MAX_DEPTH >= 16
257   else if (render->depth == 16)
258     clear_callback = (ArtRenderCallback *)&art_render_clear_16_obj;
259 #endif
260   else
261     {
262       art_die ("art_render_choose_clear_callback: inconsistent render->depth = %d\n",
263                render->depth);
264     }
265   return clear_callback;
266 }
267
268 #if 0
269 /* todo: get around to writing this */
270 static void
271 art_render_composite_render_noa_8_norm (ArtRenderCallback *self, ArtRender *render,
272                                         art_u8 *dest, int y)
273 {
274   int width = render->x1 - render->x0;
275
276 }
277 #endif
278
279 /* This is the most general form of the function. It is slow but
280    (hopefully) correct. Actually, I'm still worried about roundoff
281    errors in the premul case - it seems to me that an off-by-one could
282    lead to overflow. */
283 static void
284 art_render_composite (ArtRenderCallback *self, ArtRender *render,
285                                         art_u8 *dest, int y)
286 {
287   ArtRenderMaskRun *run = render->run;
288   art_u32 depth = render->depth;
289   int n_run = render->n_run;
290   int x0 = render->x0;
291   int x;
292   int run_x0, run_x1;
293   art_u8 *alpha_buf = render->alpha_buf;
294   art_u8 *image_buf = render->image_buf;
295   int i, j;
296   art_u32 tmp;
297   art_u32 run_alpha;
298   art_u32 alpha;
299   int image_ix;
300   art_u16 src[ART_MAX_CHAN + 1];
301   art_u16 dst[ART_MAX_CHAN + 1];
302   int n_chan = render->n_chan;
303   ArtAlphaType alpha_type = render->alpha_type;
304   int n_ch = n_chan + (alpha_type != ART_ALPHA_NONE);
305   int dst_pixstride = n_ch * (depth >> 3);
306   int buf_depth = render->buf_depth;
307   ArtAlphaType buf_alpha = render->buf_alpha;
308   int buf_n_ch = n_chan + (buf_alpha != ART_ALPHA_NONE);
309   int buf_pixstride = buf_n_ch * (buf_depth >> 3);
310   art_u8 *bufptr;
311   art_u32 src_alpha;
312   art_u32 src_mul;
313   art_u8 *dstptr;
314   art_u32 dst_alpha;
315   art_u32 dst_mul;
316
317   image_ix = 0;
318   for (i = 0; i < n_run - 1; i++)
319     {
320       run_x0 = run[i].x;
321       run_x1 = run[i + 1].x;
322       tmp = run[i].alpha;
323       if (tmp < 0x8100)
324         continue;
325
326       run_alpha = (tmp + (tmp >> 8) + (tmp >> 16) - 0x8000) >> 8; /* range [0 .. 0x10000] */
327       bufptr = image_buf + (run_x0 - x0) * buf_pixstride;
328       dstptr = dest + (run_x0 - x0) * dst_pixstride;
329       for (x = run_x0; x < run_x1; x++)
330         {
331           if (alpha_buf)
332             {
333               if (depth == 8)
334                 {
335                   tmp = run_alpha * alpha_buf[x - x0] + 0x80;
336                   /* range 0x80 .. 0xff0080 */
337                   alpha = (tmp + (tmp >> 8) + (tmp >> 16)) >> 8;
338                 }
339               else /* (depth == 16) */
340                 {
341                   tmp = ((art_u16 *)alpha_buf)[x - x0];
342                   tmp = (run_alpha * tmp + 0x8000) >> 8;
343                   /* range 0x80 .. 0xffff80 */
344                   alpha = (tmp + (tmp >> 16)) >> 8;
345                 }
346             }
347           else
348             alpha = run_alpha;
349           /* alpha is run_alpha * alpha_buf[x], range 0 .. 0x10000 */
350
351           /* convert (src pixel * alpha) to premul alpha form,
352              store in src as 0..0xffff range */
353           if (buf_alpha == ART_ALPHA_NONE)
354             {
355               src_alpha = alpha;
356               src_mul = src_alpha;
357             }
358           else
359             {
360               if (buf_depth == 8)
361                 {
362                   tmp = alpha * bufptr[n_chan] + 0x80;
363                   /* range 0x80 .. 0xff0080 */
364                   src_alpha = (tmp + (tmp >> 8) + (tmp >> 16)) >> 8;
365                 }
366               else /* (depth == 16) */
367                 {
368                   tmp = ((art_u16 *)bufptr)[n_chan];
369                   tmp = (alpha * tmp + 0x8000) >> 8;
370                   /* range 0x80 .. 0xffff80 */
371                   src_alpha = (tmp + (tmp >> 16)) >> 8;
372                 }
373               if (buf_alpha == ART_ALPHA_SEPARATE)
374                 src_mul = src_alpha;
375               else /* buf_alpha == (ART_ALPHA_PREMUL) */
376                 src_mul = alpha;
377             }
378           /* src_alpha is the (alpha of the source pixel * alpha),
379              range 0..0x10000 */
380
381           if (buf_depth == 8)
382             {
383               src_mul *= 0x101;
384               for (j = 0; j < n_chan; j++)
385                 src[j] = (bufptr[j] * src_mul + 0x8000) >> 16;
386             }
387           else if (buf_depth == 16)
388             {
389               for (j = 0; j < n_chan; j++)
390                 src[j] = (((art_u16 *)bufptr)[j] * src_mul + 0x8000) >> 16;
391             }
392           bufptr += buf_pixstride;
393
394           /* src[0..n_chan - 1] (range 0..0xffff) and src_alpha (range
395              0..0x10000) now contain the source pixel with
396              premultiplied alpha */
397
398           /* convert dst pixel to premul alpha form,
399              store in dst as 0..0xffff range */
400           if (alpha_type == ART_ALPHA_NONE)
401             {
402               dst_alpha = 0x10000;
403               dst_mul = dst_alpha;
404             }
405           else
406             {
407               if (depth == 8)
408                 {
409                   tmp = dstptr[n_chan];
410                   /* range 0..0xff */
411                   dst_alpha = (tmp << 8) + tmp + (tmp >> 7);
412                 }
413               else /* (depth == 16) */
414                 {
415                   tmp = ((art_u16 *)bufptr)[n_chan];
416                   dst_alpha = (tmp + (tmp >> 15));
417                 }
418               if (alpha_type == ART_ALPHA_SEPARATE)
419                 dst_mul = dst_alpha;
420               else /* (alpha_type == ART_ALPHA_PREMUL) */
421                 dst_mul = 0x10000;
422             }
423           /* dst_alpha is the alpha of the dest pixel,
424              range 0..0x10000 */
425
426           if (depth == 8)
427             {
428               dst_mul *= 0x101;
429               for (j = 0; j < n_chan; j++)
430                 dst[j] = (dstptr[j] * dst_mul + 0x8000) >> 16;
431             }
432           else if (buf_depth == 16)
433             {
434               for (j = 0; j < n_chan; j++)
435                 dst[j] = (((art_u16 *)dstptr)[j] * dst_mul + 0x8000) >> 16;
436             }
437
438           /* do the compositing, dst = (src over dst) */
439           for (j = 0; j < n_chan; j++)
440             {
441               art_u32 srcv, dstv;
442               art_u32 tmp;
443
444               srcv = src[j];
445               dstv = dst[j];
446               tmp = ((dstv * (0x10000 - src_alpha) + 0x8000) >> 16) + srcv;
447               tmp -= tmp >> 16;
448               dst[j] = tmp;
449             }
450
451           if (alpha_type == ART_ALPHA_NONE)
452             {
453               if (depth == 8)
454                 dst_mul = 0xff;
455               else /* (depth == 16) */
456                 dst_mul = 0xffff;
457             }
458           else
459             {
460               if (src_alpha >= 0x10000)
461                 dst_alpha = 0x10000;
462               else
463                 dst_alpha += ((((0x10000 - dst_alpha) * src_alpha) >> 8) + 0x80) >> 8;
464               if (alpha_type == ART_ALPHA_PREMUL || dst_alpha == 0)
465                 {
466                   if (depth == 8)
467                     dst_mul = 0xff;
468                   else /* (depth == 16) */
469                     dst_mul = 0xffff;
470                 }
471               else /* (ALPHA_TYPE == ART_ALPHA_SEPARATE && dst_alpha != 0) */
472                 {
473                   if (depth == 8)
474                     dst_mul = 0xff0000 / dst_alpha;
475                   else /* (depth == 16) */
476                     dst_mul = 0xffff0000 / dst_alpha;
477                 }
478             }
479           if (depth == 8)
480             {
481               for (j = 0; j < n_chan; j++)
482                 dstptr[j] = (dst[j] * dst_mul + 0x8000) >> 16;
483               if (alpha_type != ART_ALPHA_NONE)
484                 dstptr[n_chan] = (dst_alpha * 0xff + 0x8000) >> 16;
485             }
486           else if (depth == 16)
487             {
488               for (j = 0; j < n_chan; j++)
489                 ((art_u16 *)dstptr)[j] = (dst[j] * dst_mul + 0x8000) >> 16;
490               if (alpha_type != ART_ALPHA_NONE)
491                 dstptr[n_chan] = (dst_alpha * 0xffff + 0x8000) >> 16;
492             }
493           dstptr += dst_pixstride;
494         }
495     }
496 }
497
498 const ArtRenderCallback art_render_composite_obj =
499 {
500   art_render_composite,
501   art_render_nop_done
502 };
503
504 static void
505 art_render_composite_8 (ArtRenderCallback *self, ArtRender *render,
506                         art_u8 *dest, int y)
507 {
508   ArtRenderMaskRun *run = render->run;
509   int n_run = render->n_run;
510   int x0 = render->x0;
511   int x;
512   int run_x0, run_x1;
513   art_u8 *alpha_buf = render->alpha_buf;
514   art_u8 *image_buf = render->image_buf;
515   int i, j;
516   art_u32 tmp;
517   art_u32 run_alpha;
518   art_u32 alpha;
519   int image_ix;
520   int n_chan = render->n_chan;
521   ArtAlphaType alpha_type = render->alpha_type;
522   int n_ch = n_chan + (alpha_type != ART_ALPHA_NONE);
523   int dst_pixstride = n_ch;
524   ArtAlphaType buf_alpha = render->buf_alpha;
525   int buf_n_ch = n_chan + (buf_alpha != ART_ALPHA_NONE);
526   int buf_pixstride = buf_n_ch;
527   art_u8 *bufptr;
528   art_u32 src_alpha;
529   art_u32 src_mul;
530   art_u8 *dstptr;
531   art_u32 dst_alpha;
532   art_u32 dst_mul, dst_save_mul;
533
534   image_ix = 0;
535   for (i = 0; i < n_run - 1; i++)
536     {
537       run_x0 = run[i].x;
538       run_x1 = run[i + 1].x;
539       tmp = run[i].alpha;
540       if (tmp < 0x10000)
541         continue;
542
543       run_alpha = (tmp + (tmp >> 8) + (tmp >> 16) - 0x8000) >> 8; /* range [0 .. 0x10000] */
544       bufptr = image_buf + (run_x0 - x0) * buf_pixstride;
545       dstptr = dest + (run_x0 - x0) * dst_pixstride;
546       for (x = run_x0; x < run_x1; x++)
547         {
548           if (alpha_buf)
549             {
550               tmp = run_alpha * alpha_buf[x - x0] + 0x80;
551               /* range 0x80 .. 0xff0080 */
552               alpha = (tmp + (tmp >> 8) + (tmp >> 16)) >> 8;
553             }
554           else
555             alpha = run_alpha;
556           /* alpha is run_alpha * alpha_buf[x], range 0 .. 0x10000 */
557
558           /* convert (src pixel * alpha) to premul alpha form,
559              store in src as 0..0xffff range */
560           if (buf_alpha == ART_ALPHA_NONE)
561             {
562               src_alpha = alpha;
563               src_mul = src_alpha;
564             }
565           else
566             {
567               tmp = alpha * bufptr[n_chan] + 0x80;
568               /* range 0x80 .. 0xff0080 */
569               src_alpha = (tmp + (tmp >> 8) + (tmp >> 16)) >> 8;
570
571               if (buf_alpha == ART_ALPHA_SEPARATE)
572                 src_mul = src_alpha;
573               else /* buf_alpha == (ART_ALPHA_PREMUL) */
574                 src_mul = alpha;
575             }
576           /* src_alpha is the (alpha of the source pixel * alpha),
577              range 0..0x10000 */
578
579           src_mul *= 0x101;
580
581           if (alpha_type == ART_ALPHA_NONE)
582             {
583               dst_alpha = 0x10000;
584               dst_mul = dst_alpha;
585             }
586           else
587             {
588               tmp = dstptr[n_chan];
589               /* range 0..0xff */
590               dst_alpha = (tmp << 8) + tmp + (tmp >> 7);
591               if (alpha_type == ART_ALPHA_SEPARATE)
592                 dst_mul = dst_alpha;
593               else /* (alpha_type == ART_ALPHA_PREMUL) */
594                 dst_mul = 0x10000;
595             }
596           /* dst_alpha is the alpha of the dest pixel,
597              range 0..0x10000 */
598
599           dst_mul *= 0x101;
600
601           if (alpha_type == ART_ALPHA_NONE)
602             {
603               dst_save_mul = 0xff;
604             }
605           else
606             {
607               if (src_alpha >= 0x10000)
608                 dst_alpha = 0x10000;
609               else
610                 dst_alpha += ((((0x10000 - dst_alpha) * src_alpha) >> 8) + 0x80) >> 8;
611               if (alpha_type == ART_ALPHA_PREMUL || dst_alpha == 0)
612                 {
613                   dst_save_mul = 0xff;
614                 }
615               else /* (ALPHA_TYPE == ART_ALPHA_SEPARATE && dst_alpha != 0) */
616                 {
617                   dst_save_mul = 0xff0000 / dst_alpha;
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 /* todo: inline */
647 static ArtRenderCallback *
648 art_render_choose_compositing_callback (ArtRender *render)
649 {
650   if (render->depth == 8 && render->buf_depth == 8)
651     return (ArtRenderCallback *)&art_render_composite_8_obj;
652   return (ArtRenderCallback *)&art_render_composite_obj;
653 }
654
655 /**
656  * art_render_invoke_callbacks: Invoke the callbacks in the render object.
657  * @render: The render object.
658  * @y: The current Y coordinate value.
659  *
660  * Invokes the callbacks of the render object in the appropriate
661  * order.  Drivers should call this routine once per scanline.
662  *
663  * todo: should management of dest devolve to this routine? very
664  * plausibly yes.
665  **/
666 void
667 art_render_invoke_callbacks (ArtRender *render, art_u8 *dest, int y)
668 {
669   ArtRenderPriv *priv = (ArtRenderPriv *)render;
670   int i;
671
672   for (i = 0; i < priv->n_callbacks; i++)
673     {
674       ArtRenderCallback *callback;
675
676       callback = priv->callbacks[i];
677       callback->render (callback, render, dest, y);
678     }
679 }
680
681 /**
682  * art_render_invoke: Perform the requested rendering task.
683  * @render: The render object.
684  *
685  * Invokes the renderer and all sources associated with it, to perform
686  * the requested rendering task.
687  **/
688 void
689 art_render_invoke (ArtRender *render)
690 {
691   ArtRenderPriv *priv = (ArtRenderPriv *)render;
692   int width;
693   int best_driver, best_score;
694   int i;
695   int n_callbacks, n_callbacks_max;
696   ArtImageSource *image_source;
697   ArtImageSourceFlags image_flags;
698   int buf_depth;
699   ArtAlphaType buf_alpha;
700   art_boolean first = ART_TRUE;
701
702   if (render == NULL)
703     {
704       art_warn ("art_render_invoke: called with render == NULL\n");
705       return;
706     }
707   if (priv->image_source == NULL)
708     {
709       art_warn ("art_render_invoke: no image source given\n");
710       return;
711     }
712
713   width = render->x1 - render->x0;
714
715   render->run = art_new (ArtRenderMaskRun, width + 1);
716
717   /* Elect a mask source as driver. */
718   best_driver = -1;
719   best_score = 0;
720   for (i = 0; i < priv->n_mask_source; i++)
721     {
722       int score;
723       ArtMaskSource *mask_source;
724
725       mask_source = priv->mask_source[i];
726       score = mask_source->can_drive (mask_source, render);
727       if (score > best_score)
728         {
729           best_score = score;
730           best_driver = i;
731         }
732     }
733
734   /* Allocate alpha buffer if needed. */
735   if (priv->n_mask_source > 1 ||
736       (priv->n_mask_source == 1 && best_driver < 0))
737     {
738       render->alpha_buf = art_new (art_u8, (width * render->depth) >> 3);
739     }
740
741   /* Negotiate image rendering and compositing. */
742   image_source = priv->image_source;
743   image_source->negotiate (image_source, render, &image_flags, &buf_depth,
744                            &buf_alpha);
745
746   /* Build callback list. */
747   n_callbacks_max = priv->n_mask_source + 3;
748   priv->callbacks = art_new (ArtRenderCallback *, n_callbacks_max);
749   n_callbacks = 0;
750   for (i = 0; i < priv->n_mask_source; i++)
751     if (i != best_driver)
752       {
753         ArtMaskSource *mask_source = priv->mask_source[i];
754
755         mask_source->prepare (mask_source, render, first);
756         first = ART_FALSE;
757         priv->callbacks[n_callbacks++] = &mask_source->super;
758       }
759
760   if (render->clear && !(image_flags & ART_IMAGE_SOURCE_CAN_CLEAR))
761     priv->callbacks[n_callbacks++] =
762       art_render_choose_clear_callback (render);
763
764   priv->callbacks[n_callbacks++] = &image_source->super;
765
766   /* Allocate image buffer and add compositing callback if needed. */
767   if (!(image_flags & ART_IMAGE_SOURCE_CAN_COMPOSITE))
768     {
769       int bytespp = ((render->n_chan + (buf_alpha != ART_ALPHA_NONE)) *
770                      buf_depth) >> 3;
771       render->buf_depth = buf_depth;
772       render->buf_alpha = buf_alpha;
773       render->image_buf = art_new (art_u8, width * bytespp);
774       priv->callbacks[n_callbacks++] =
775         art_render_choose_compositing_callback (render);
776     }
777
778   priv->n_callbacks = n_callbacks;
779
780   if (render->need_span)
781     render->span_x = art_new (int, width + 1);
782
783   /* Invoke the driver */
784   if (best_driver >= 0)
785     {
786       ArtMaskSource *driver;
787
788       driver = priv->mask_source[best_driver];
789       driver->invoke_driver (driver, render);
790     }
791   else
792     {
793       art_u8 *dest_ptr = render->pixels;
794       int y;
795
796       /* Dummy driver */
797       render->n_run = 2;
798       render->run[0].x = render->x0;
799       render->run[0].alpha = 0x8000 + 0xff * render->opacity;
800       render->run[1].x = render->x1;
801       render->run[1].alpha = 0x8000;
802       if (render->need_span)
803         {
804           render->n_span = 2;
805           render->span_x[0] = render->x0;
806           render->span_x[1] = render->x1;
807         }
808       for (y = render->y0; y < render->y1; y++)
809         {
810           art_render_invoke_callbacks (render, dest_ptr, y);
811           dest_ptr += render->rowstride;
812         }
813     }
814
815   if (priv->mask_source != NULL)
816     art_free (priv->mask_source);
817
818   /* clean up callbacks */
819   for (i = 0; i < priv->n_callbacks; i++)
820     {
821       ArtRenderCallback *callback;
822
823       callback = priv->callbacks[i];
824       callback->done (callback, render);
825     }
826
827   /* Tear down object */
828   if (render->alpha_buf != NULL)
829     art_free (render->alpha_buf);
830   if (render->image_buf != NULL)
831     art_free (render->image_buf);
832   art_free (render->run);
833   if (render->span_x != NULL)
834     art_free (render->span_x);
835   art_free (priv->callbacks);
836   art_free (render);
837 }
838
839 /**
840  * art_render_mask_solid: Add a solid translucent mask.
841  * @render: The render object.
842  * @opacity: Opacity in [0..0x10000] form.
843  *
844  * Adds a translucent mask to the rendering object.
845  **/
846 void
847 art_render_mask_solid (ArtRender *render, int opacity)
848 {
849   art_u32 old_opacity = render->opacity;
850   art_u32 new_opacity_tmp;
851
852   if (opacity == 0x10000)
853     /* avoid potential overflow */
854     return;
855   new_opacity_tmp = old_opacity * (art_u32)opacity + 0x8000;
856   render->opacity = new_opacity_tmp >> 16;
857 }
858
859 /**
860  * art_render_add_mask_source: Add a mask source to the render object.
861  * @render: Render object.
862  * @mask_source: Mask source to add.
863  *
864  * This routine adds a mask source to the render object. In general,
865  * client api's for adding mask sources should just take a render object,
866  * then the mask source creation function should call this function.
867  * Clients should never have to call this function directly, unless of
868  * course they're creating custom mask sources.
869  **/
870 void
871 art_render_add_mask_source (ArtRender *render, ArtMaskSource *mask_source)
872 {
873   ArtRenderPriv *priv = (ArtRenderPriv *)render;
874   int n_mask_source = priv->n_mask_source++;
875
876   if (n_mask_source == 0)
877     priv->mask_source = art_new (ArtMaskSource *, 1);
878   /* This predicate is true iff n_mask_source is a power of two */
879   else if (!(n_mask_source & (n_mask_source - 1)))
880     priv->mask_source = art_renew (priv->mask_source, ArtMaskSource *,
881                                    n_mask_source << 1);
882
883   priv->mask_source[n_mask_source] = mask_source;
884 }
885
886 /**
887  * art_render_add_image_source: Add a mask source to the render object.
888  * @render: Render object.
889  * @image_source: Image source to add.
890  *
891  * This routine adds an image source to the render object. In general,
892  * client api's for adding image sources should just take a render
893  * object, then the mask source creation function should call this
894  * function.  Clients should never have to call this function
895  * directly, unless of course they're creating custom image sources.
896  **/
897 void
898 art_render_add_image_source (ArtRender *render, ArtImageSource *image_source)
899 {
900   ArtRenderPriv *priv = (ArtRenderPriv *)render;
901
902   if (priv->image_source != NULL)
903     {
904       art_warn ("art_render_add_image_source: image source already present.\n");
905       return;
906     }
907   priv->image_source = image_source;
908 }
909
910 /* Solid image source object and methods. Perhaps this should go into a
911    separate file. */
912
913 typedef struct _ArtImageSourceSolid ArtImageSourceSolid;
914
915 struct _ArtImageSourceSolid {
916   ArtImageSource super;
917   ArtPixMaxDepth color[ART_MAX_CHAN];
918   art_u32 *rgbtab;
919   art_boolean init;
920 };
921
922 static void
923 art_render_image_solid_done (ArtRenderCallback *self, ArtRender *render)
924 {
925   ArtImageSourceSolid *z = (ArtImageSourceSolid *)self;
926
927   if (z->rgbtab != NULL)
928     art_free (z->rgbtab);
929   art_free (self);
930 }
931
932 static void
933 art_render_image_solid_rgb8_opaq_init (ArtImageSourceSolid *self, ArtRender *render)
934 {
935   ArtImageSourceSolid *z = (ArtImageSourceSolid *)self;
936   ArtPixMaxDepth color_max;
937   int r_fg, g_fg, b_fg;
938   int r_bg, g_bg, b_bg;
939   int r, g, b;
940   int dr, dg, db;
941   int i;
942   int tmp;
943   art_u32 *rgbtab;
944
945   rgbtab = art_new (art_u32, 256);
946   z->rgbtab = rgbtab;
947
948   color_max = self->color[0];
949   r_fg = ART_PIX_8_FROM_MAX (color_max);
950   color_max = self->color[1];
951   g_fg = ART_PIX_8_FROM_MAX (color_max);
952   color_max = self->color[2];
953   b_fg = ART_PIX_8_FROM_MAX (color_max);
954
955   color_max = render->clear_color[0];
956   r_bg = ART_PIX_8_FROM_MAX (color_max);
957   color_max = render->clear_color[1];
958   g_bg = ART_PIX_8_FROM_MAX (color_max);
959   color_max = render->clear_color[2];
960   b_bg = ART_PIX_8_FROM_MAX (color_max);
961
962   r = (r_bg << 16) + 0x8000;
963   g = (g_bg << 16) + 0x8000;
964   b = (b_bg << 16) + 0x8000;
965   tmp = ((r_fg - r_bg) << 16) + 0x80;
966   dr = (tmp + (tmp >> 8)) >> 8;
967   tmp = ((g_fg - g_bg) << 16) + 0x80;
968   dg = (tmp + (tmp >> 8)) >> 8;
969   tmp = ((b_fg - b_bg) << 16) + 0x80;
970   db = (tmp + (tmp >> 8)) >> 8;
971
972   for (i = 0; i < 256; i++)
973     {
974       rgbtab[i] = (r & 0xff0000) | ((g & 0xff0000) >> 8) | (b >> 16);
975       r += dr;
976       g += dg;
977       b += db;
978     }
979 }
980
981 static void
982 art_render_image_solid_rgb8_opaq (ArtRenderCallback *self, ArtRender *render,
983                                   art_u8 *dest, int y)
984 {
985   ArtImageSourceSolid *z = (ArtImageSourceSolid *)self;
986   ArtRenderMaskRun *run = render->run;
987   int n_run = render->n_run;
988   art_u32 *rgbtab = z->rgbtab;
989   art_u32 rgb;
990   int x0 = render->x0;
991   int x1 = render->x1;
992   int run_x0, run_x1;
993   int i;
994   int ix;
995
996   if (n_run > 0)
997     {
998       run_x1 = run[0].x;
999       if (run_x1 > x0)
1000         {
1001           rgb = rgbtab[0];
1002           art_rgb_fill_run (dest,
1003                             rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff,
1004                             run_x1 - x0);
1005         }
1006       for (i = 0; i < n_run - 1; i++)
1007         {
1008           run_x0 = run_x1;
1009           run_x1 = run[i + 1].x;
1010           rgb = rgbtab[(run[i].alpha >> 16) & 0xff];
1011           ix = (run_x0 - x0) * 3;
1012 #define OPTIMIZE_LEN_1
1013 #ifdef OPTIMIZE_LEN_1
1014           if (run_x1 - run_x0 == 1)
1015             {
1016               dest[ix] = rgb >> 16;
1017               dest[ix + 1] = (rgb >> 8) & 0xff;
1018               dest[ix + 2] = rgb & 0xff;
1019             }
1020           else
1021             {
1022               art_rgb_fill_run (dest + ix,
1023                                 rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff,
1024                                 run_x1 - run_x0);
1025             }
1026 #else
1027           art_rgb_fill_run (dest + ix,
1028                             rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff,
1029                             run_x1 - run_x0);
1030 #endif
1031         }
1032     }
1033   else
1034     {
1035       run_x1 = x0;
1036     }
1037   if (run_x1 < x1)
1038     {
1039       rgb = rgbtab[0];
1040       art_rgb_fill_run (dest + (run_x1 - x0) * 3,
1041                         rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff,
1042                         x1 - run_x1);
1043     }
1044 }
1045
1046 static void
1047 art_render_image_solid_rgb8 (ArtRenderCallback *self, ArtRender *render,
1048                              art_u8 *dest, int y)
1049 {
1050   ArtImageSourceSolid *z = (ArtImageSourceSolid *)self;
1051   int width = render->x1 - render->x0;
1052   art_u8 r, g, b;
1053   ArtPixMaxDepth color_max;
1054
1055   /* todo: replace this simple test with real sparseness */
1056   if (z->init)
1057     return;
1058   z->init = ART_TRUE;
1059
1060   color_max = z->color[0];
1061   r = ART_PIX_8_FROM_MAX (color_max);
1062   color_max = z->color[1];
1063   g = ART_PIX_8_FROM_MAX (color_max);
1064   color_max = z->color[2];
1065   b = ART_PIX_8_FROM_MAX (color_max);
1066
1067   art_rgb_fill_run (render->image_buf, r, g, b, width);
1068 }
1069
1070 static void
1071 art_render_image_solid_negotiate (ArtImageSource *self, ArtRender *render,
1072                                   ArtImageSourceFlags *p_flags,
1073                                   int *p_buf_depth, ArtAlphaType *p_alpha)
1074 {
1075   ArtImageSourceSolid *z = (ArtImageSourceSolid *)self;
1076   ArtImageSourceFlags flags = 0;
1077   static void (*render_cbk) (ArtRenderCallback *self, ArtRender *render,
1078                              art_u8 *dest, int y);
1079
1080   render_cbk = NULL;
1081
1082   if (render->depth == 8 && render->n_chan == 3 &&
1083       render->alpha_type == ART_ALPHA_NONE)
1084     {
1085       if (render->clear)
1086         {
1087           render_cbk = art_render_image_solid_rgb8_opaq;
1088           flags |= ART_IMAGE_SOURCE_CAN_CLEAR | ART_IMAGE_SOURCE_CAN_COMPOSITE;
1089           art_render_image_solid_rgb8_opaq_init (z, render);
1090         }
1091     }
1092   if (render_cbk == NULL)
1093     {
1094       if (render->depth == 8)
1095         {
1096           render_cbk = art_render_image_solid_rgb8;
1097           *p_buf_depth = 8;
1098           *p_alpha = ART_ALPHA_NONE; /* todo */
1099         }
1100     }
1101   /* todo: general case */
1102   self->super.render = render_cbk;
1103   *p_flags = flags;
1104 }
1105
1106 /**
1107  * art_render_image_solid: Add a solid color image source.
1108  * @render: The render object.
1109  * @color: Color.
1110  *
1111  * Adds an image source with the solid color given by @color. The
1112  * color need not be retained in memory after this call.
1113  **/
1114 void
1115 art_render_image_solid (ArtRender *render, ArtPixMaxDepth *color)
1116 {
1117   ArtImageSourceSolid *image_source;
1118   int i;
1119
1120   image_source = art_new (ArtImageSourceSolid, 1);
1121   image_source->super.super.render = NULL;
1122   image_source->super.super.done = art_render_image_solid_done;
1123   image_source->super.negotiate = art_render_image_solid_negotiate;
1124
1125   for (i = 0; i < render->n_chan; i++)
1126     image_source->color[i] = color[i];
1127
1128   image_source->rgbtab = NULL;
1129   image_source->init = ART_FALSE;
1130
1131   art_render_add_image_source (render, &image_source->super);
1132 }