• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (C) 2007-2008 The Android Open Source Project
2 **
3 ** This software is licensed under the terms of the GNU General Public
4 ** License version 2, as published by the Free Software Foundation, and
5 ** may be copied, distributed, and modified under those terms.
6 **
7 ** This program is distributed in the hope that it will be useful,
8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 ** GNU General Public License for more details.
11 */
12 #include "android/skin/composer.h"
13 #include <stddef.h>
14 #include "android/utils/system.h"
15 
16 /* forwards */
17 static void  skin_plate_get_region       ( SkinPlate*  p, SkinRegion  *pregion );
18 static void  skin_plate_get_opaque_region( SkinPlate*  p, SkinRegion  *pregion );
19 
20 /* recompute region if needed */
21 static void
skin_plate_ensure_region(SkinPlate * p)22 skin_plate_ensure_region( SkinPlate*  p )
23 {
24     if (p->any.type == SKIN_PLATE_SURFACE || p->group.hasRegion)
25         return;
26     else {
27         int  n, count = areflist_count( p->group.children );
28 
29         skin_region_reset(p->any.region);
30 
31         for (n = 0; n < count; n++) {
32             SkinRegion  r[1];
33             SkinPlate*  child = areflist_get( p->group.children, n );
34 
35             skin_plate_get_region( child, r );
36             skin_region_translate( r, child->any.pos.x, child->any.pos.y );
37             skin_region_union( p->any.region, r );
38         }
39 
40         p->group.hasRegion = 1;
41     }
42 }
43 
44 /* return region in 'region' */
45 static void
skin_plate_get_region(SkinPlate * p,SkinRegion * region)46 skin_plate_get_region( SkinPlate*  p, SkinRegion*  region )
47 {
48     if ( p->any.type != SKIN_PLATE_SURFACE && !p->group.hasRegion ) {
49         skin_plate_ensure_region(p);
50     }
51     skin_region_init_copy( region, p->any.region );
52 }
53 
54 
55 /* recompute opaque region is needed */
56 static void
skin_plate_ensure_opaque_region(SkinPlate * p)57 skin_plate_ensure_opaque_region( SkinPlate*  p )
58 {
59     if (p->any.type != SKIN_PLATE_SURFACE && !p->group.hasOpaqueRegion) {
60         int  n, count = areflist_count( p->group.children );
61 
62         skin_region_reset(p->group.opaqueRegion);
63 
64         for (n = 0; n < count; n++) {
65             SkinRegion  r[1];
66             SkinPlate*  child = areflist_get( p->group.children, n );
67 
68             skin_plate_get_opaque_region(child, r);
69             skin_region_translate(r, child->any.pos.x, child->any.pos.y);
70             skin_region_union( p->group.opaqueRegion, r);
71         }
72 
73         p->group.hasOpaqueRegion = 1;
74     }
75 }
76 
77 
78 /* return opaque pixels region */
79 static void
skin_plate_get_opaque_region(SkinPlate * p,SkinRegion * pregion)80 skin_plate_get_opaque_region( SkinPlate*  p, SkinRegion  *pregion )
81 {
82     if ( p->any.type == SKIN_PLATE_SURFACE ) {
83         if (p->any.isOpaque)
84             skin_region_init_copy(pregion, p->any.region);
85         else
86             skin_region_reset(pregion);
87     } else {
88         skin_plate_ensure_opaque_region(p);
89         skin_region_init_copy(pregion, p->group.opaqueRegion);
90     }
91 }
92 
93 
94 /* invalidate region in parent groups */
95 static void
skin_plate_invalidate_parent(SkinPlate * p)96 skin_plate_invalidate_parent( SkinPlate*  p )
97 {
98     if (!p->any.isVisible)
99         return;
100 
101     while (p) {
102         if (p->any.type != SKIN_PLATE_SURFACE) {
103             p->group.hasRegion       = 0;
104             p->group.hasOpaqueRegion = 0;
105         }
106         p = p->any.parent;
107     }
108 }
109 
110 
111 static void
skin_plate_invalidate_(SkinPlate * p,SkinRegion * r,SkinPlate * child)112 skin_plate_invalidate_( SkinPlate*  p, SkinRegion*  r, SkinPlate*  child )
113 {
114     if (p->any.type != SKIN_PLATE_SURFACE) {
115         int  n = areflist_count( p->group.children );
116         if (child != NULL) {
117             n = areflist_indexOf( p->group.children, child );
118         }
119         while (n > 0) {
120             n -= 1;
121             child = areflist_get( p->group.children, n );
122             skin_region_translate( r, child->any.pos.x, child->any.pos.y );
123             skin_plate_invalidate_( p, r, NULL );
124             skin_region_translate( r, -child->any.pos.x, -child->any.pos.y );
125             if (skin_region_is_empty(r))
126                 return;
127         }
128         if (p->any.type != SKIN_PLATE_SPACE) {
129             SkinPlate*  parent = p->any.parent;
130             skin_region_translate(r, parent->any.pos.x, parent->any.pos.y );
131             skin_plate_invalidate_(parent, r, p);
132         } else {
133             /* send to viewports */
134             int  n, count = areflist_count( p->space.viewports );
135             for (n = 0; n < count; n++) {
136                 SkinViewport*  v = areflist_get( p->space.viewports, n );
137                 skin_viewport_invalidate(v, r);
138             }
139         }
140     }
141 }
142 
143 static void
skin_plate_invalidate_region(SkinPlate * p)144 skin_plate_invalidate_region( SkinPlate*  p )
145 {
146     SkinRegion  r[1];
147 
148     skin_plate_get_region( p, r );
149     skin_plate_invalidate_(p->any.parent, r, p);
150     skin_region_reset(r);
151 }
152 
153 /* change visibility */
154 void
skin_plate_set_visible(SkinPlate * p,int isVisible)155 skin_plate_set_visible( SkinPlate*  p, int  isVisible )
156 {
157     isVisible = !!isVisible;
158     if (isVisible == p->any.isVisible)
159         return;
160 
161     skin_plate_invalidate_parent(p);
162     skin_plate_invalidate_region(p);
163     p->any.isVisible = isVisible;
164 }
165 
166 void
skin_plate_set_opaque(SkinPlate * p,int isOpaque)167 skin_plate_set_opaque( SkinPlate*  p, int  isOpaque )
168 {
169     isOpaque = !!isOpaque;
170     if (isOpaque == p->any.isOpaque)
171         return;
172 
173     skin_plate_invalidate_parent(p);
174     skin_plate_invalidate_region(p);
175     p->any.isOpaque = isOpaque;
176 }
177 
178 
179 
180 extern SkinPlate*
skin_plate_surface(SkinPlate * parent,SkinPos * pos,SkinRegion * region,void * surface,SkinPlateDrawFunc draw,SkinPlateDoneFunc done)181 skin_plate_surface( SkinPlate*         parent,
182                     SkinPos*           pos,
183                     SkinRegion*        region,
184                     void*              surface,
185                     SkinPlateDrawFunc  draw,
186                     SkinPlateDoneFunc  done )
187 {
188     SkinPlate*  p;
189 
190     ANEW0(p);
191     p->any.type      = SKIN_PLATE_SURFACE;
192     p->any.parent    = parent;
193     p->any.pos.x     = pos->x;
194     p->any.pos.y     = pos->y;
195     p->any.isVisible = 1;
196     p->any.isOpaque  = 1;
197 
198     skin_region_init_copy( p->any.region, region );
199     return p;
200 }
201 
202 
203 SkinPlate*
skin_plate_group(SkinPlate * parent,SkinPos * pos)204 skin_plate_group( SkinPlate*  parent, SkinPos*  pos )
205 {
206     SkinRegion  r[1];
207     SkinPlate*  p;
208 
209     skin_region_reset(r);
210     p = skin_plate_surface( parent, pos, r, NULL, NULL, NULL );
211     p->any.type              = SKIN_PLATE_GROUP;
212     p->group.hasOpaqueRegion = 0;
213     skin_region_init_empty( p->group.opaqueRegion );
214 
215     areflist_init( p->group.children );
216     return p;
217 }
218 
219 
220 SkinPlate*
skin_plate_space(void)221 skin_plate_space( void )
222 {
223     SkinPos     pos;
224     SkinPlate*  p;
225 
226     pos.x       = pos.y = 0;
227     p           = skin_plate_group( NULL, &pos );
228     p->any.type = SKIN_PLATE_SPACE;
229     areflist_init( p->space.viewports );
230     return p;
231 }
232 
233 
234 extern void
skin_plate_free(SkinPlate * p)235 skin_plate_free( SkinPlate*  p )
236 {
237     if (p->any.type >= SKIN_PLATE_SPACE) {
238         while ( areflist_count( p->space.viewports ) )
239             skin_viewport_free( areflist_get( p->space.viewports, 0 ) );
240     }
241     if (p->any.type >= SKIN_PLATE_GROUP) {
242         skin_region_reset( p->group.opaqueRegion );
243         p->group.hasOpaqueRegion = 0;
244         p->group.hasRegion       = 0;
245 
246         while ( areflist_count( p->group.children ) )
247             skin_plate_free( areflist_get( p->group.children, 0 ) );
248     }
249     if (p->any.type == SKIN_PLATE_SURFACE) {
250         if (p->surface.done)
251             p->surface.done( p->surface.user );
252     }
253 
254     skin_region_reset( p->any.region );
255 
256     if (p->any.parent) {
257         areflist_delFirst( p->any.parent->group.children, p );
258     }
259 }
260 
261 void
skin_plate_invalidate(SkinPlate * plate,SkinRegion * region)262 skin_plate_invalidate( SkinPlate*  plate, SkinRegion*  region )
263 {
264     SkinRegion  r[1];
265     skin_region_init_copy( r, region );
266 }
267 
268 
269 /* we use two regions to manage the front-to-back composition here
270  *
271  *  'updated' initially contains the update region, in parent coordinates
272  *
273  *  'drawn'   is initially empty, and will be filled with the region of translucent
274  *            pixels that have been
275  *
276  *  for a given surface plate, we translate the regions to plate coordinates,
277  *  then we do an opaque blit of 'intersection(updated,region)', then removing it from 'updated'
278  *
279  *  after that, we make a DSTOVER blit of 'intersection(drawn,region)'
280  *  if the plate is not opaque, we add this intersection to 'drawn'
281  *
282  */
283 static void
skin_plate_redraw(SkinPlate * plate,SkinRegion * updated,SkinRegion * drawn,SkinPos * apos,SkinViewport * viewport)284 skin_plate_redraw( SkinPlate*  plate, SkinRegion*  updated, SkinRegion*  drawn, SkinPos*  apos, SkinViewport*  viewport )
285 {
286     SkinPos  pos = plate->any.pos;
287 
288     if (!plate->any.isVisible)
289         return;
290 
291     if (skin_region_is_empty(updated) && skin_region_is_empty(drawn))
292         return;
293 
294     /* translate regions to plate coordinates */
295     skin_region_translate( updated, pos.x, pos.y );
296     skin_region_translate( drawn,   pos.y, pos.y );
297     apos->x += pos.x;
298     apos->y += pos.y;
299 
300     if (plate->any.type == SKIN_PLATE_SURFACE) {
301         SkinRegion  r[1];
302 
303         /* inter(updated,region) => opaque blit + remove 'region' from 'updated'*/
304         skin_plate_get_region(plate, r);
305         skin_region_intersect(r, updated);
306         if (!skin_region_is_empty(r)) {
307             plate->surface.draw( plate->surface.user, r, apos, viewport, 1 );
308             skin_region_substract(updated, r);
309             skin_region_reset(r);
310         }
311 
312         /* inter(drawn,region) => DSTOVER blit + if non-opaque add it to 'drawn' */
313         skin_plate_get_region(plate, r);
314         skin_region_intersect(r, drawn);
315         if (!skin_region_is_empty(r)) {
316             plate->surface.draw( plate->surface.user, r, apos, viewport, 0);
317             if (!plate->any.isOpaque)
318                 skin_region_union(drawn, r);
319             skin_region_reset(r);
320         }
321 
322     } else {
323         int  n, count = areflist_count(plate->group.children);
324         for (n = 0; n < count; n++) {
325             SkinPos  pos;
326 
327             pos.x = apos->x + plate->any.pos.x;
328             pos.y = apos->y + plate->any.pos.y;
329 
330             skin_plate_redraw( areflist_get(plate->group.children, n ), updated, drawn, &pos, viewport );
331             if (skin_region_is_empty(updated) && skin_region_is_empty(drawn))
332                 break;
333         }
334     }
335 
336     /* convert back to parent coordinates */
337     apos->x -= pos.x;
338     apos->y -= pos.y;
339     skin_region_translate( updated, -pos.x, -pos.y );
340     skin_region_translate( drawn,   -pos.x, -pos.y );
341 }
342 
343 
344 extern SkinViewport*
skin_viewport(SkinPlate * space,SkinRect * rect,void * surface,int sx,int sy)345 skin_viewport( SkinPlate*  space, SkinRect*  rect, void*  surface, int  sx, int  sy )
346 {
347     SkinViewport*  v;
348 
349     ANEW0(v);
350     v->space   = space;
351     v->rect    = rect[0];
352     v->spos.x  = sx;
353     v->spos.y  = sy;
354     v->surface = surface;
355 
356     skin_region_init_empty( v->update );
357     return v;
358 }
359 
360 extern void
skin_viewport_free(SkinViewport * v)361 skin_viewport_free( SkinViewport*  v )
362 {
363     SkinPlate*  space = v->space;
364     if (space != NULL) {
365         areflist_delFirst( space->space.viewports, v );
366         v->space = NULL;
367     }
368     skin_region_reset( v->update );
369     AFREE(v);
370 }
371 
372 extern void
skin_viewport_invalidate(SkinViewport * v,SkinRegion * region)373 skin_viewport_invalidate( SkinViewport*  v, SkinRegion*  region )
374 {
375     SkinRegion  r[1];
376     skin_region_init_copy(r,region);
377     skin_region_translate(r, -v->spos.x, -v->spos.y);
378     skin_region_intersect_rect(r,&v->rect);
379     skin_region_union( v->update, r );
380     skin_region_reset(r);
381 }
382 
383 extern void
skin_viewport_redraw(SkinViewport * v)384 skin_viewport_redraw( SkinViewport*  v )
385 {
386     if (v->space && !skin_region_is_empty(v->update)) {
387         SkinRegion  update[1];
388         SkinRegion  drawn[1];
389         SkinPos     apos;
390 
391         skin_region_copy(update, v->update);
392         skin_region_reset(drawn);
393         skin_region_reset( v->update );
394 
395         apos.x = apos.y = 0;
396         skin_plate_redraw( v->space, update, drawn, &apos, v );
397 
398         skin_region_reset(update);
399         skin_region_reset(drawn);
400     }
401 }
402