2 * art_render.c: Modular rendering architecture.
4 * Libart_LGPL - library of basic graphic primitives
5 * Copyright (C) 2000 Raph Levien
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.
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.
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.
24 #include "art_render.h"
28 typedef struct _ArtRenderPriv ArtRenderPriv;
30 struct _ArtRenderPriv {
33 ArtImageSource *image_source;
36 ArtMaskSource **mask_source;
39 ArtRenderCallback **callbacks;
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)
51 priv = art_new (ArtRenderPriv, 1);
52 result = &priv->super;
54 if (n_chan > ART_MAX_CHAN)
56 art_warn ("art_render_new: n_chan = %d, exceeds %d max\n",
57 n_chan, ART_MAX_CHAN);
60 if (depth > ART_MAX_DEPTH)
62 art_warn ("art_render_new: depth = %d, exceeds %d max\n",
63 depth, ART_MAX_DEPTH);
68 art_warn ("art_render_new: x0 >= x1 (x0 = %d, x1 = %d)\n", x0, x1);
75 result->pixels = pixels;
76 result->rowstride = rowstride;
77 result->n_chan = n_chan;
78 result->depth = depth;
79 result->alpha_type = alpha_type;
81 result->clear = ART_FALSE;
82 result->opacity = 0x10000;
83 result->compositing_mode = ART_COMPOSITE_NORMAL;
84 result->alphagamma = alphagamma;
86 result->alpha_buf = NULL;
87 result->image_buf = NULL;
90 result->span_x = NULL;
92 result->need_span = ART_FALSE;
94 priv->image_source = NULL;
96 priv->n_mask_source = 0;
97 priv->mask_source = NULL;
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. */
107 * art_render_clear: Set clear color.
108 * @clear_color: Color with which to clear dest.
110 * Sets clear color, equivalent to actually clearing the destination
111 * buffer before rendering. This is the most general form.
114 art_render_clear (ArtRender *render, const ArtPixMaxDepth *clear_color)
117 int n_ch = render->n_chan + (render->alpha_type != ART_ALPHA_NONE);
119 render->clear = ART_TRUE;
120 for (i = 0; i < n_ch; i++)
121 render->clear_color[i] = clear_color[i];
125 * art_render_clear_rgb: Set clear color, given in RGB format.
126 * @clear_rgb: Clear color, in 0xRRGGBB format.
128 * Sets clear color, equivalent to actually clearing the destination
129 * buffer before rendering.
132 art_render_clear_rgb (ArtRender *render, art_u32 clear_rgb)
134 if (render->n_chan != 3)
135 art_warn ("art_render_clear_rgb: called on render with %d channels, only works with 3\n",
141 render->clear = ART_TRUE;
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);
152 art_render_nop_done (ArtRenderCallback *self, ArtRender *render)
157 art_render_clear_render_rgb8 (ArtRenderCallback *self, ArtRender *render,
160 int width = render->x1 - render->x0;
162 ArtPixMaxDepth color_max;
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);
171 art_rgb_fill_run (dest, r, g, b, width);
175 art_render_clear_render_8 (ArtRenderCallback *self, ArtRender *render,
178 int width = render->x1 - render->x0;
180 int n_ch = render->n_chan + (render->alpha_type != ART_ALPHA_NONE);
182 art_u8 color[ART_MAX_CHAN + 1];
184 for (j = 0; j < n_ch; j++)
186 ArtPixMaxDepth color_max = render->clear_color[j];
187 color[j] = ART_PIX_8_FROM_MAX (color_max);
191 for (i = 0; i < width; i++)
192 for (j = 0; j < n_ch; j++)
193 dest[ix++] = color[j];
196 const ArtRenderCallback art_render_clear_rgb8_obj =
198 art_render_clear_render_rgb8,
202 const ArtRenderCallback art_render_clear_8_obj =
204 art_render_clear_render_8,
208 #if ART_MAX_DEPTH >= 16
211 art_render_clear_render_16 (ArtRenderCallback *self, ArtRender *render,
214 int width = render->x1 - render->x0;
216 int n_ch = render->n_chan + (render->alpha_type != ART_ALPHA_NONE);
218 art_u16 *dest_16 = (art_u16 *)dest;
219 art_u8 color[ART_MAX_CHAN + 1];
221 for (j = 0; j < n_ch; j++)
223 int color_16 = render->clear_color[j];
228 for (i = 0; i < width; i++)
229 for (j = 0; j < n_ch; j++)
230 dest_16[ix++] = color[j];
233 const ArtRenderCallback art_render_clear_16_obj =
235 art_render_clear_render_16,
239 #endif /* ART_MAX_DEPTH >= 16 */
242 static ArtRenderCallback *
243 art_render_choose_clear_callback (ArtRender *render)
245 ArtRenderCallback *clear_callback;
247 if (render->depth == 8)
249 if (render->n_chan == 3 &&
250 render->alpha_type == ART_ALPHA_NONE)
251 clear_callback = (ArtRenderCallback *)&art_render_clear_rgb8_obj;
253 clear_callback = (ArtRenderCallback *)&art_render_clear_8_obj;
255 #if ART_MAX_DEPTH >= 16
256 else if (render->depth == 16)
257 clear_callback = (ArtRenderCallback *)&art_render_clear_16_obj;
261 art_die ("art_render_choose_clear_callback: inconsistent render->depth = %d\n",
264 return clear_callback;
268 /* todo: get around to writing this */
270 art_render_composite_render_noa_8_norm (ArtRenderCallback *self, ArtRender *render,
273 int width = render->x1 - render->x0;
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
283 art_render_composite (ArtRenderCallback *self, ArtRender *render,
286 ArtRenderMaskRun *run = render->run;
287 art_u32 depth = render->depth;
288 int n_run = render->n_run;
292 art_u8 *alpha_buf = render->alpha_buf;
293 art_u8 *image_buf = render->image_buf;
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);
317 for (i = 0; i < n_run - 1; i++)
320 run_x1 = run[i + 1].x;
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++)
334 tmp = run_alpha * alpha_buf[x - x0] + 0x80;
335 /* range 0x80 .. 0xff0080 */
336 alpha = (tmp + (tmp >> 8) + (tmp >> 16)) >> 8;
338 else /* (depth == 16) */
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;
348 /* alpha is run_alpha * alpha_buf[x], range 0 .. 0x10000 */
350 /* convert (src pixel * alpha) to premul alpha form,
351 store in src as 0..0xffff range */
352 if (buf_alpha == ART_ALPHA_NONE)
361 tmp = alpha * bufptr[n_chan] + 0x80;
362 /* range 0x80 .. 0xff0080 */
363 src_alpha = (tmp + (tmp >> 8) + (tmp >> 16)) >> 8;
365 else /* (depth == 16) */
367 tmp = ((art_u16 *)bufptr)[n_chan];
368 tmp = (alpha * tmp + 0x8000) >> 8;
369 /* range 0x80 .. 0xffff80 */
370 src_alpha = (tmp + (tmp >> 16)) >> 8;
372 if (buf_alpha == ART_ALPHA_SEPARATE)
374 else /* buf_alpha == (ART_ALPHA_PREMUL) */
377 /* src_alpha is the (alpha of the source pixel * alpha),
383 for (j = 0; j < n_chan; j++)
384 src[j] = (bufptr[j] * src_mul + 0x8000) >> 16;
386 else if (buf_depth == 16)
388 for (j = 0; j < n_chan; j++)
389 src[j] = (((art_u16 *)bufptr)[j] * src_mul + 0x8000) >> 16;
391 bufptr += buf_pixstride;
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 */
397 /* convert dst pixel to premul alpha form,
398 store in dst as 0..0xffff range */
399 if (alpha_type == ART_ALPHA_NONE)
408 tmp = dstptr[n_chan];
410 dst_alpha = (tmp << 8) + tmp + (tmp >> 7);
412 else /* (depth == 16) */
414 tmp = ((art_u16 *)dstptr)[n_chan];
415 dst_alpha = (tmp + (tmp >> 15));
417 if (alpha_type == ART_ALPHA_SEPARATE)
419 else /* (alpha_type == ART_ALPHA_PREMUL) */
422 /* dst_alpha is the alpha of the dest pixel,
428 for (j = 0; j < n_chan; j++)
429 dst[j] = (dstptr[j] * dst_mul + 0x8000) >> 16;
431 else if (buf_depth == 16)
433 for (j = 0; j < n_chan; j++)
434 dst[j] = (((art_u16 *)dstptr)[j] * dst_mul + 0x8000) >> 16;
437 /* do the compositing, dst = (src over dst) */
438 for (j = 0; j < n_chan; j++)
445 tmp = ((dstv * (0x10000 - src_alpha) + 0x8000) >> 16) + srcv;
450 if (alpha_type == ART_ALPHA_NONE)
454 else /* (depth == 16) */
459 if (src_alpha >= 0x10000)
462 dst_alpha += ((((0x10000 - dst_alpha) * src_alpha) >> 8) + 0x80) >> 8;
463 if (alpha_type == ART_ALPHA_PREMUL || dst_alpha == 0)
467 else /* (depth == 16) */
470 else /* (ALPHA_TYPE == ART_ALPHA_SEPARATE && dst_alpha != 0) */
473 dst_mul = 0xff0000 / dst_alpha;
474 else /* (depth == 16) */
475 dst_mul = 0xffff0000 / dst_alpha;
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;
485 else if (depth == 16)
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;
492 dstptr += dst_pixstride;
497 const ArtRenderCallback art_render_composite_obj =
499 art_render_composite,
504 art_render_composite_8 (ArtRenderCallback *self, ArtRender *render,
507 ArtRenderMaskRun *run = render->run;
508 int n_run = render->n_run;
512 art_u8 *alpha_buf = render->alpha_buf;
513 art_u8 *image_buf = render->image_buf;
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;
531 art_u32 dst_mul, dst_save_mul;
534 for (i = 0; i < n_run - 1; i++)
537 run_x1 = run[i + 1].x;
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++)
549 tmp = run_alpha * alpha_buf[x - x0] + 0x80;
550 /* range 0x80 .. 0xff0080 */
551 alpha = (tmp + (tmp >> 8) + (tmp >> 16)) >> 8;
555 /* alpha is run_alpha * alpha_buf[x], range 0 .. 0x10000 */
557 /* convert (src pixel * alpha) to premul alpha form,
558 store in src as 0..0xffff range */
559 if (buf_alpha == ART_ALPHA_NONE)
566 tmp = alpha * bufptr[n_chan] + 0x80;
567 /* range 0x80 .. 0xff0080 */
568 src_alpha = (tmp + (tmp >> 8) + (tmp >> 16)) >> 8;
570 if (buf_alpha == ART_ALPHA_SEPARATE)
572 else /* buf_alpha == (ART_ALPHA_PREMUL) */
575 /* src_alpha is the (alpha of the source pixel * alpha),
580 if (alpha_type == ART_ALPHA_NONE)
587 tmp = dstptr[n_chan];
589 dst_alpha = (tmp << 8) + tmp + (tmp >> 7);
590 if (alpha_type == ART_ALPHA_SEPARATE)
592 else /* (alpha_type == ART_ALPHA_PREMUL) */
595 /* dst_alpha is the alpha of the dest pixel,
600 if (alpha_type == ART_ALPHA_NONE)
606 if (src_alpha >= 0x10000)
609 dst_alpha += ((((0x10000 - dst_alpha) * src_alpha) >> 8) + 0x80) >> 8;
610 if (alpha_type == ART_ALPHA_PREMUL || dst_alpha == 0)
614 else /* (ALPHA_TYPE == ART_ALPHA_SEPARATE && dst_alpha != 0) */
616 dst_save_mul = 0xff0000 / dst_alpha;
620 for (j = 0; j < n_chan; j++)
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;
629 dstptr[j] = (tmp * dst_save_mul + 0x8000) >> 16;
631 if (alpha_type != ART_ALPHA_NONE)
632 dstptr[n_chan] = (dst_alpha * 0xff + 0x8000) >> 16;
634 bufptr += buf_pixstride;
635 dstptr += dst_pixstride;
640 const ArtRenderCallback art_render_composite_8_obj =
642 art_render_composite_8,
649 * buf_alpha = ART_ALPHA_NONE (source)
650 * alpha_type = ART_ALPHA_SEPARATE (dest)
654 art_render_composite_8_opt1 (ArtRenderCallback *self, ArtRender *render,
657 ArtRenderMaskRun *run = render->run;
658 int n_run = render->n_run;
662 art_u8 *image_buf = render->image_buf;
671 art_u32 dst_mul, dst_save_mul;
674 for (i = 0; i < n_run - 1; i++)
677 run_x1 = run[i + 1].x;
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)
687 for (x = run_x0; x < run_x1; x++)
689 *dstptr++ = *bufptr++;
690 *dstptr++ = *bufptr++;
691 *dstptr++ = *bufptr++;
697 for (x = run_x0; x < run_x1; x++)
699 src_mul = run_alpha * 0x101;
703 dst_alpha = (tmp << 8) + tmp + (tmp >> 7);
705 /* dst_alpha is the alpha of the dest pixel,
710 dst_alpha += ((((0x10000 - dst_alpha) * run_alpha) >> 8) + 0x80) >> 8;
713 else /* (dst_alpha != 0) */
714 dst_save_mul = 0xff0000 / dst_alpha;
716 for (j = 0; j < 3; j++)
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;
725 dstptr[j] = (tmp * dst_save_mul + 0x8000) >> 16;
727 dstptr[3] = (dst_alpha * 0xff + 0x8000) >> 16;
737 const ArtRenderCallback art_render_composite_8_opt1_obj =
739 art_render_composite_8_opt1,
745 * buf_alpha = ART_ALPHA_PREMUL (source)
746 * alpha_type = ART_ALPHA_SEPARATE (dest)
750 art_render_composite_8_opt2 (ArtRenderCallback *self, ArtRender *render,
753 ArtRenderMaskRun *run = render->run;
754 int n_run = render->n_run;
758 art_u8 *image_buf = render->image_buf;
768 art_u32 dst_mul, dst_save_mul;
771 for (i = 0; i < n_run - 1; i++)
774 run_x1 = run[i + 1].x;
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)
784 for (x = run_x0; x < run_x1; x++)
786 src_alpha = (bufptr[3] << 8) + bufptr[3] + (bufptr[3] >> 7);
787 /* src_alpha is the (alpha of the source pixel),
790 dst_alpha = (dstptr[3] << 8) + dstptr[3] + (dstptr[3] >> 7);
791 /* dst_alpha is the alpha of the dest pixel,
794 dst_mul = dst_alpha*0x101;
796 if (src_alpha >= 0x10000)
799 dst_alpha += ((((0x10000 - dst_alpha) * src_alpha) >> 8) + 0x80) >> 8;
803 else /* dst_alpha != 0) */
804 dst_save_mul = 0xff0000 / dst_alpha;
806 for (j = 0; j < 3; j++)
811 src = (bufptr[j] << 8) | bufptr[j];
812 dst = (dstptr[j] * dst_mul + 0x8000) >> 16;
813 tmp = ((dst * (0x10000 - src_alpha) + 0x8000) >> 16) + src;
815 dstptr[j] = (tmp * dst_save_mul + 0x8000) >> 16;
817 dstptr[3] = (dst_alpha * 0xff + 0x8000) >> 16;
825 for (x = run_x0; x < run_x1; x++)
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),
833 src_mul = run_alpha * 0x101;
837 dst_alpha = (tmp << 8) + tmp + (tmp >> 7);
839 /* dst_alpha is the alpha of the dest pixel,
844 if (src_alpha >= 0x10000)
847 dst_alpha += ((((0x10000 - dst_alpha) * src_alpha) >> 8) + 0x80) >> 8;
853 else /* dst_alpha != 0) */
855 dst_save_mul = 0xff0000 / dst_alpha;
858 for (j = 0; j < 3; j++)
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;
867 dstptr[j] = (tmp * dst_save_mul + 0x8000) >> 16;
869 dstptr[3] = (dst_alpha * 0xff + 0x8000) >> 16;
878 const ArtRenderCallback art_render_composite_8_opt2_obj =
880 art_render_composite_8_opt2,
886 static ArtRenderCallback *
887 art_render_choose_compositing_callback (ArtRender *render)
889 if (render->depth == 8 && render->buf_depth == 8)
891 if (render->n_chan == 3 &&
892 render->alpha_buf == NULL &&
893 render->alpha_type == ART_ALPHA_SEPARATE)
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;
901 return (ArtRenderCallback *)&art_render_composite_8_obj;
903 return (ArtRenderCallback *)&art_render_composite_obj;
907 * art_render_invoke_callbacks: Invoke the callbacks in the render object.
908 * @render: The render object.
909 * @y: The current Y coordinate value.
911 * Invokes the callbacks of the render object in the appropriate
912 * order. Drivers should call this routine once per scanline.
914 * todo: should management of dest devolve to this routine? very
918 art_render_invoke_callbacks (ArtRender *render, art_u8 *dest, int y)
920 ArtRenderPriv *priv = (ArtRenderPriv *)render;
923 for (i = 0; i < priv->n_callbacks; i++)
925 ArtRenderCallback *callback;
927 callback = priv->callbacks[i];
928 callback->render (callback, render, dest, y);
933 * art_render_invoke: Perform the requested rendering task.
934 * @render: The render object.
936 * Invokes the renderer and all sources associated with it, to perform
937 * the requested rendering task.
940 art_render_invoke (ArtRender *render)
942 ArtRenderPriv *priv = (ArtRenderPriv *)render;
944 int best_driver, best_score;
946 int n_callbacks, n_callbacks_max;
947 ArtImageSource *image_source;
950 ArtAlphaType buf_alpha;
951 art_boolean first = ART_TRUE;
955 art_warn ("art_render_invoke: called with render == NULL\n");
958 if (priv->image_source == NULL)
960 art_warn ("art_render_invoke: no image source given\n");
964 width = render->x1 - render->x0;
966 render->run = art_new (ArtRenderMaskRun, width + 1);
968 /* Elect a mask source as driver. */
971 for (i = 0; i < priv->n_mask_source; i++)
974 ArtMaskSource *mask_source;
976 mask_source = priv->mask_source[i];
977 score = mask_source->can_drive (mask_source, render);
978 if (score > best_score)
985 /* Allocate alpha buffer if needed. */
986 if (priv->n_mask_source > 1 ||
987 (priv->n_mask_source == 1 && best_driver < 0))
989 render->alpha_buf = art_new (art_u8, (width * render->depth) >> 3);
992 /* Negotiate image rendering and compositing. */
993 image_source = priv->image_source;
994 image_source->negotiate (image_source, render, &image_flags, &buf_depth,
997 /* Build callback list. */
998 n_callbacks_max = priv->n_mask_source + 3;
999 priv->callbacks = art_new (ArtRenderCallback *, n_callbacks_max);
1001 for (i = 0; i < priv->n_mask_source; i++)
1002 if (i != best_driver)
1004 ArtMaskSource *mask_source = priv->mask_source[i];
1006 mask_source->prepare (mask_source, render, first);
1008 priv->callbacks[n_callbacks++] = &mask_source->super;
1011 if (render->clear && !(image_flags & ART_IMAGE_SOURCE_CAN_CLEAR))
1012 priv->callbacks[n_callbacks++] =
1013 art_render_choose_clear_callback (render);
1015 priv->callbacks[n_callbacks++] = &image_source->super;
1017 /* Allocate image buffer and add compositing callback if needed. */
1018 if (!(image_flags & ART_IMAGE_SOURCE_CAN_COMPOSITE))
1020 int bytespp = ((render->n_chan + (buf_alpha != ART_ALPHA_NONE)) *
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);
1029 priv->n_callbacks = n_callbacks;
1031 if (render->need_span)
1032 render->span_x = art_new (int, width + 1);
1034 /* Invoke the driver */
1035 if (best_driver >= 0)
1037 ArtMaskSource *driver;
1039 driver = priv->mask_source[best_driver];
1040 driver->invoke_driver (driver, render);
1044 art_u8 *dest_ptr = render->pixels;
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)
1056 render->span_x[0] = render->x0;
1057 render->span_x[1] = render->x1;
1059 for (y = render->y0; y < render->y1; y++)
1061 art_render_invoke_callbacks (render, dest_ptr, y);
1062 dest_ptr += render->rowstride;
1066 if (priv->mask_source != NULL)
1067 art_free (priv->mask_source);
1069 /* clean up callbacks */
1070 for (i = 0; i < priv->n_callbacks; i++)
1072 ArtRenderCallback *callback;
1074 callback = priv->callbacks[i];
1075 callback->done (callback, render);
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);
1091 * art_render_mask_solid: Add a solid translucent mask.
1092 * @render: The render object.
1093 * @opacity: Opacity in [0..0x10000] form.
1095 * Adds a translucent mask to the rendering object.
1098 art_render_mask_solid (ArtRender *render, int opacity)
1100 art_u32 old_opacity = render->opacity;
1101 art_u32 new_opacity_tmp;
1103 if (opacity == 0x10000)
1104 /* avoid potential overflow */
1106 new_opacity_tmp = old_opacity * (art_u32)opacity + 0x8000;
1107 render->opacity = new_opacity_tmp >> 16;
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.
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.
1122 art_render_add_mask_source (ArtRender *render, ArtMaskSource *mask_source)
1124 ArtRenderPriv *priv = (ArtRenderPriv *)render;
1125 int n_mask_source = priv->n_mask_source++;
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);
1134 priv->mask_source[n_mask_source] = mask_source;
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.
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.
1149 art_render_add_image_source (ArtRender *render, ArtImageSource *image_source)
1151 ArtRenderPriv *priv = (ArtRenderPriv *)render;
1153 if (priv->image_source != NULL)
1155 art_warn ("art_render_add_image_source: image source already present.\n");
1158 priv->image_source = image_source;
1161 /* Solid image source object and methods. Perhaps this should go into a
1164 typedef struct _ArtImageSourceSolid ArtImageSourceSolid;
1166 struct _ArtImageSourceSolid {
1167 ArtImageSource super;
1168 ArtPixMaxDepth color[ART_MAX_CHAN];
1174 art_render_image_solid_done (ArtRenderCallback *self, ArtRender *render)
1176 ArtImageSourceSolid *z = (ArtImageSourceSolid *)self;
1178 if (z->rgbtab != NULL)
1179 art_free (z->rgbtab);
1184 art_render_image_solid_rgb8_opaq_init (ArtImageSourceSolid *self, ArtRender *render)
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;
1196 rgbtab = art_new (art_u32, 256);
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);
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);
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;
1223 for (i = 0; i < 256; i++)
1225 rgbtab[i] = (r & 0xff0000) | ((g & 0xff0000) >> 8) | (b >> 16);
1233 art_render_image_solid_rgb8_opaq (ArtRenderCallback *self, ArtRender *render,
1234 art_u8 *dest, int y)
1236 ArtImageSourceSolid *z = (ArtImageSourceSolid *)self;
1237 ArtRenderMaskRun *run = render->run;
1238 int n_run = render->n_run;
1239 art_u32 *rgbtab = z->rgbtab;
1241 int x0 = render->x0;
1242 int x1 = render->x1;
1253 art_rgb_fill_run (dest,
1254 rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff,
1257 for (i = 0; i < n_run - 1; i++)
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)
1267 dest[ix] = rgb >> 16;
1268 dest[ix + 1] = (rgb >> 8) & 0xff;
1269 dest[ix + 2] = rgb & 0xff;
1273 art_rgb_fill_run (dest + ix,
1274 rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff,
1278 art_rgb_fill_run (dest + ix,
1279 rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff,
1291 art_rgb_fill_run (dest + (run_x1 - x0) * 3,
1292 rgb >> 16, (rgb >> 8) & 0xff, rgb & 0xff,
1298 art_render_image_solid_rgb8 (ArtRenderCallback *self, ArtRender *render,
1299 art_u8 *dest, int y)
1301 ArtImageSourceSolid *z = (ArtImageSourceSolid *)self;
1302 int width = render->x1 - render->x0;
1304 ArtPixMaxDepth color_max;
1306 /* todo: replace this simple test with real sparseness */
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);
1318 art_rgb_fill_run (render->image_buf, r, g, b, width);
1322 art_render_image_solid_negotiate (ArtImageSource *self, ArtRender *render,
1324 int *p_buf_depth, ArtAlphaType *p_alpha)
1326 ArtImageSourceSolid *z = (ArtImageSourceSolid *)self;
1328 static void (*render_cbk) (ArtRenderCallback *self, ArtRender *render,
1329 art_u8 *dest, int y);
1333 if (render->depth == 8 && render->n_chan == 3 &&
1334 render->alpha_type == ART_ALPHA_NONE)
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);
1343 if (render_cbk == NULL)
1345 if (render->depth == 8)
1347 render_cbk = art_render_image_solid_rgb8;
1349 *p_alpha = ART_ALPHA_NONE; /* todo */
1352 /* todo: general case */
1353 self->super.render = render_cbk;
1358 * art_render_image_solid: Add a solid color image source.
1359 * @render: The render object.
1362 * Adds an image source with the solid color given by @color. The
1363 * color need not be retained in memory after this call.
1366 art_render_image_solid (ArtRender *render, ArtPixMaxDepth *color)
1368 ArtImageSourceSolid *image_source;
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;
1376 for (i = 0; i < render->n_chan; i++)
1377 image_source->color[i] = color[i];
1379 image_source->rgbtab = NULL;
1380 image_source->init = ART_FALSE;
1382 art_render_add_image_source (render, &image_source->super);