1 /*
2  * art_render_mask.c: Alpha mask source for modular rendering.
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  * Authors: Raph Levien <raph@acm.org>
23  */
24 
25 #include "config.h"
26 #include "art_render_mask.h"
27 
28 #include <string.h>
29 
30 
31 typedef struct _ArtMaskSourceMask ArtMaskSourceMask;
32 
33 struct _ArtMaskSourceMask {
34   ArtMaskSource super;
35   ArtRender *render;
36   art_boolean first;
37   int x0;
38   int y0;
39   int x1;
40   int y1;
41   const art_u8 *mask_buf;
42   int rowstride;
43 };
44 
45 static void
art_render_mask_done(ArtRenderCallback * self,ArtRender * render)46 art_render_mask_done (ArtRenderCallback *self, ArtRender *render)
47 {
48   art_free (self);
49 }
50 
51 static int
art_render_mask_can_drive(ArtMaskSource * self,ArtRender * render)52 art_render_mask_can_drive (ArtMaskSource *self, ArtRender *render)
53 {
54   return 0;
55 }
56 
57 static void
art_render_mask_render(ArtRenderCallback * self,ArtRender * render,art_u8 * dest,int y)58 art_render_mask_render (ArtRenderCallback *self, ArtRender *render,
59 			art_u8 *dest, int y)
60 {
61   ArtMaskSourceMask *z = (ArtMaskSourceMask *)self;
62   int x0 = render->x0, x1 = render->x1;
63   int z_x0 = z->x0, z_x1 = z->x1;
64   int width = x1 - x0;
65   int z_width = z_x1 - z_x0;
66   art_u8 *alpha_buf = render->alpha_buf;
67 
68   if (y < z->y0 || y >= z->y1 || z_width <= 0)
69     memset (alpha_buf, 0, width);
70   else
71     {
72       const art_u8 *src_line = z->mask_buf + (y - z->y0) * z->rowstride;
73       art_u8 *dst_line = alpha_buf + z_x0 - x0;
74 
75       if (z_x0 > x0)
76 	memset (alpha_buf, 0, z_x0 - x0);
77 
78       if (z->first)
79 	memcpy (dst_line, src_line, z_width);
80       else
81 	{
82 	  int x;
83 
84 	  for (x = 0; x < z_width; x++)
85 	    {
86 	      int v;
87 	      v = src_line[x];
88 	      if (v)
89 		{
90 		  v = v * dst_line[x] + 0x80;
91 		  v = (v + (v >> 8)) >> 8;
92 		  dst_line[x] = v;
93 		}
94 	      else
95 		{
96 		  dst_line[x] = 0;
97 		}
98 	    }
99 	}
100 
101       if (z_x1 < x1)
102 	memset (alpha_buf + z_x1 - x0, 0, x1 - z_x1);
103     }
104 }
105 
106 static void
art_render_mask_prepare(ArtMaskSource * self,ArtRender * render,art_boolean first)107 art_render_mask_prepare (ArtMaskSource *self, ArtRender *render,
108 			 art_boolean first)
109 {
110   ArtMaskSourceMask *z = (ArtMaskSourceMask *)self;
111   self->super.render = art_render_mask_render;
112   z->first = first;
113 }
114 
115 /**
116  * art_render_mask: Use an alpha buffer as a render mask source.
117  * @render: Render object.
118  * @x0: Left coordinate of mask rect.
119  * @y0: Top coordinate of mask rect.
120  * @x1: Right coordinate of mask rect.
121  * @y1: Bottom coordinate of mask rect.
122  * @mask_buf: Buffer containing 8bpp alpha mask data.
123  * @rowstride: Rowstride of @mask_buf.
124  *
125  * Adds @mask_buf to the render object as a mask. Note: @mask_buf must
126  * remain allocated until art_render_invoke() is called on @render.
127  **/
128 void
art_render_mask(ArtRender * render,int x0,int y0,int x1,int y1,const art_u8 * mask_buf,int rowstride)129 art_render_mask (ArtRender *render,
130 		 int x0, int y0, int x1, int y1,
131 		 const art_u8 *mask_buf, int rowstride)
132 {
133   ArtMaskSourceMask *mask_source;
134 
135   if (x0 < render->x0)
136     {
137       mask_buf += render->x0 - x0;
138       x0 = render->x0;
139     }
140   if (x1 > render->x1)
141     x1 = render->x1;
142 
143   if (y0 < render->y0)
144     {
145       mask_buf += (render->y0 - y0) * rowstride;
146       y0 = render->y0;
147     }
148   if (y1 > render->y1)
149     y1 = render->y1;
150 
151   mask_source = art_new (ArtMaskSourceMask, 1);
152 
153   mask_source->super.super.render = NULL;
154   mask_source->super.super.done = art_render_mask_done;
155   mask_source->super.can_drive = art_render_mask_can_drive;
156   mask_source->super.invoke_driver = NULL;
157   mask_source->super.prepare = art_render_mask_prepare;
158   mask_source->render = render;
159   mask_source->x0 = x0;
160   mask_source->y0 = y0;
161   mask_source->x1 = x1;
162   mask_source->y1 = y1;
163   mask_source->mask_buf = mask_buf;
164   mask_source->rowstride = rowstride;
165 
166   art_render_add_mask_source (render, &mask_source->super);
167 
168 }
169