diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-02-10 15:43:59 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-02-10 15:43:59 -0800 |
commit | c27f813900a3c114562efbb8df1065e94766fc48 (patch) | |
tree | d95919283707dcab61009e27007374a745c9541e /android/skin/composer.c | |
parent | 0852ad57fa372f9b2854e4df685eaba8d8ef6790 (diff) | |
download | external_qemu-c27f813900a3c114562efbb8df1065e94766fc48.zip external_qemu-c27f813900a3c114562efbb8df1065e94766fc48.tar.gz external_qemu-c27f813900a3c114562efbb8df1065e94766fc48.tar.bz2 |
auto import from //branches/cupcake/...@130745
Diffstat (limited to 'android/skin/composer.c')
-rw-r--r-- | android/skin/composer.c | 401 |
1 files changed, 401 insertions, 0 deletions
diff --git a/android/skin/composer.c b/android/skin/composer.c new file mode 100644 index 0000000..6076449 --- /dev/null +++ b/android/skin/composer.c @@ -0,0 +1,401 @@ +/* Copyright (C) 2007-2008 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ +#include "android/skin/composer.h" +#include <stddef.h> +#include "android/utils/system.h" + +/* forwards */ +static void skin_plate_get_region ( SkinPlate* p, SkinRegion *pregion ); +static void skin_plate_get_opaque_region( SkinPlate* p, SkinRegion *pregion ); + +/* recompute region if needed */ +static void +skin_plate_ensure_region( SkinPlate* p ) +{ + if (p->any.type == SKIN_PLATE_SURFACE || p->group.hasRegion) + return; + else { + int n, count = areflist_count( p->group.children ); + + skin_region_reset(p->any.region); + + for (n = 0; n < count; n++) { + SkinRegion r[1]; + SkinPlate* child = areflist_get( p->group.children, n ); + + skin_plate_get_region( child, r ); + skin_region_translate( r, child->any.pos.x, child->any.pos.y ); + skin_region_union( p->any.region, r ); + } + + p->group.hasRegion = 1; + } +} + +/* return region in 'region' */ +static void +skin_plate_get_region( SkinPlate* p, SkinRegion* region ) +{ + if ( p->any.type != SKIN_PLATE_SURFACE && !p->group.hasRegion ) { + skin_plate_ensure_region(p); + } + skin_region_init_copy( region, p->any.region ); +} + + +/* recompute opaque region is needed */ +static void +skin_plate_ensure_opaque_region( SkinPlate* p ) +{ + if (p->any.type != SKIN_PLATE_SURFACE && !p->group.hasOpaqueRegion) { + int n, count = areflist_count( p->group.children ); + + skin_region_reset(p->group.opaqueRegion); + + for (n = 0; n < count; n++) { + SkinRegion r[1]; + SkinPlate* child = areflist_get( p->group.children, n ); + + skin_plate_get_opaque_region(child, r); + skin_region_translate(r, child->any.pos.x, child->any.pos.y); + skin_region_union( p->group.opaqueRegion, r); + } + + p->group.hasOpaqueRegion = 1; + } +} + + +/* return opaque pixels region */ +static void +skin_plate_get_opaque_region( SkinPlate* p, SkinRegion *pregion ) +{ + if ( p->any.type == SKIN_PLATE_SURFACE ) { + if (p->any.isOpaque) + skin_region_init_copy(pregion, p->any.region); + else + skin_region_reset(pregion); + } else { + skin_plate_ensure_opaque_region(p); + skin_region_init_copy(pregion, p->group.opaqueRegion); + } +} + + +/* invalidate region in parent groups */ +static void +skin_plate_invalidate_parent( SkinPlate* p ) +{ + if (!p->any.isVisible) + return; + + while (p) { + if (p->any.type != SKIN_PLATE_SURFACE) { + p->group.hasRegion = 0; + p->group.hasOpaqueRegion = 0; + } + p = p->any.parent; + } +} + + +static void +skin_plate_invalidate_( SkinPlate* p, SkinRegion* r, SkinPlate* child ) +{ + if (p->any.type != SKIN_PLATE_SURFACE) { + int n = areflist_count( p->group.children ); + if (child != NULL) { + n = areflist_indexOf( p->group.children, child ); + } + while (n > 0) { + n -= 1; + child = areflist_get( p->group.children, n ); + skin_region_translate( r, child->any.pos.x, child->any.pos.y ); + skin_plate_invalidate_( p, r, NULL ); + skin_region_translate( r, -child->any.pos.x, -child->any.pos.y ); + if (skin_region_is_empty(r)) + return; + } + if (p->any.type != SKIN_PLATE_SPACE) { + SkinPlate* parent = p->any.parent; + skin_region_translate(r, parent->any.pos.x, parent->any.pos.y ); + skin_plate_invalidate_(parent, r, p); + } else { + /* send to viewports */ + int n, count = areflist_count( p->space.viewports ); + for (n = 0; n < count; n++) { + SkinViewport* v = areflist_get( p->space.viewports, n ); + skin_viewport_invalidate(v, r); + } + } + } +} + +static void +skin_plate_invalidate_region( SkinPlate* p ) +{ + SkinRegion r[1]; + + skin_plate_get_region( p, r ); + skin_plate_invalidate_(p->any.parent, r, p); + skin_region_reset(r); +} + +/* change visibility */ +void +skin_plate_set_visible( SkinPlate* p, int isVisible ) +{ + isVisible = !!isVisible; + if (isVisible == p->any.isVisible) + return; + + skin_plate_invalidate_parent(p); + skin_plate_invalidate_region(p); + p->any.isVisible = isVisible; +} + +void +skin_plate_set_opaque( SkinPlate* p, int isOpaque ) +{ + isOpaque = !!isOpaque; + if (isOpaque == p->any.isOpaque) + return; + + skin_plate_invalidate_parent(p); + skin_plate_invalidate_region(p); + p->any.isOpaque = isOpaque; +} + + + +extern SkinPlate* +skin_plate_surface( SkinPlate* parent, + SkinPos* pos, + SkinRegion* region, + void* surface, + SkinPlateDrawFunc draw, + SkinPlateDoneFunc done ) +{ + SkinPlate* p; + + ANEW0(p); + p->any.type = SKIN_PLATE_SURFACE; + p->any.parent = parent; + p->any.pos.x = pos->x; + p->any.pos.y = pos->y; + p->any.isVisible = 1; + p->any.isOpaque = 1; + + skin_region_init_copy( p->any.region, region ); + return p; +} + + +SkinPlate* +skin_plate_group( SkinPlate* parent, SkinPos* pos ) +{ + SkinRegion r[1]; + SkinPlate* p; + + skin_region_reset(r); + p = skin_plate_surface( parent, pos, r, NULL, NULL, NULL ); + p->any.type = SKIN_PLATE_GROUP; + p->group.hasOpaqueRegion = 0; + skin_region_init_empty( p->group.opaqueRegion ); + + areflist_init( p->group.children ); + return p; +} + + +SkinPlate* +skin_plate_space( void ) +{ + SkinPos pos; + SkinPlate* p; + + pos.x = pos.y = 0; + p = skin_plate_group( NULL, &pos ); + p->any.type = SKIN_PLATE_SPACE; + areflist_init( p->space.viewports ); + return p; +} + + +extern void +skin_plate_free( SkinPlate* p ) +{ + if (p->any.type >= SKIN_PLATE_SPACE) { + while ( areflist_count( p->space.viewports ) ) + skin_viewport_free( areflist_get( p->space.viewports, 0 ) ); + } + if (p->any.type >= SKIN_PLATE_GROUP) { + skin_region_reset( p->group.opaqueRegion ); + p->group.hasOpaqueRegion = 0; + p->group.hasRegion = 0; + + while ( areflist_count( p->group.children ) ) + skin_plate_free( areflist_get( p->group.children, 0 ) ); + } + if (p->any.type == SKIN_PLATE_SURFACE) { + if (p->surface.done) + p->surface.done( p->surface.user ); + } + + skin_region_reset( p->any.region ); + + if (p->any.parent) { + areflist_del( p->any.parent->group.children, p ); + } +} + +void +skin_plate_invalidate( SkinPlate* plate, SkinRegion* region ) +{ + SkinRegion r[1]; + skin_region_init_copy( r, region ); +} + + +/* we use two regions to manage the front-to-back composition here + * + * 'updated' initially contains the update region, in parent coordinates + * + * 'drawn' is initially empty, and will be filled with the region of translucent + * pixels that have been + * + * for a given surface plate, we translate the regions to plate coordinates, + * then we do an opaque blit of 'intersection(updated,region)', then removing it from 'updated' + * + * after that, we make a DSTOVER blit of 'intersection(drawn,region)' + * if the plate is not opaque, we add this intersection to 'drawn' + * + */ +static void +skin_plate_redraw( SkinPlate* plate, SkinRegion* updated, SkinRegion* drawn, SkinPos* apos, SkinViewport* viewport ) +{ + SkinPos pos = plate->any.pos; + + if (!plate->any.isVisible) + return; + + if (skin_region_is_empty(updated) && skin_region_is_empty(drawn)) + return; + + /* translate regions to plate coordinates */ + skin_region_translate( updated, pos.x, pos.y ); + skin_region_translate( drawn, pos.y, pos.y ); + apos->x += pos.x; + apos->y += pos.y; + + if (plate->any.type == SKIN_PLATE_SURFACE) { + SkinRegion r[1]; + + /* inter(updated,region) => opaque blit + remove 'region' from 'updated'*/ + skin_plate_get_region(plate, r); + skin_region_intersect(r, updated); + if (!skin_region_is_empty(r)) { + plate->surface.draw( plate->surface.user, r, apos, viewport, 1 ); + skin_region_substract(updated, r); + skin_region_reset(r); + } + + /* inter(drawn,region) => DSTOVER blit + if non-opaque add it to 'drawn' */ + skin_plate_get_region(plate, r); + skin_region_intersect(r, drawn); + if (!skin_region_is_empty(r)) { + plate->surface.draw( plate->surface.user, r, apos, viewport, 0); + if (!plate->any.isOpaque) + skin_region_union(drawn, r); + skin_region_reset(r); + } + + } else { + int n, count = areflist_count(plate->group.children); + for (n = 0; n < count; n++) { + SkinPos pos; + + pos.x = apos->x + plate->any.pos.x; + pos.y = apos->y + plate->any.pos.y; + + skin_plate_redraw( areflist_get(plate->group.children, n ), updated, drawn, &pos, viewport ); + if (skin_region_is_empty(updated) && skin_region_is_empty(drawn)) + break; + } + } + + /* convert back to parent coordinates */ + apos->x -= pos.x; + apos->y -= pos.y; + skin_region_translate( updated, -pos.x, -pos.y ); + skin_region_translate( drawn, -pos.x, -pos.y ); +} + + +extern SkinViewport* +skin_viewport( SkinPlate* space, SkinRect* rect, void* surface, int sx, int sy ) +{ + SkinViewport* v; + + ANEW0(v); + v->space = space; + v->rect = rect[0]; + v->spos.x = sx; + v->spos.y = sy; + v->surface = surface; + + skin_region_init_empty( v->update ); + return v; +} + +extern void +skin_viewport_free( SkinViewport* v ) +{ + SkinPlate* space = v->space; + if (space != NULL) { + areflist_del( space->space.viewports, v ); + v->space = NULL; + } + skin_region_reset( v->update ); + AFREE(v); +} + +extern void +skin_viewport_invalidate( SkinViewport* v, SkinRegion* region ) +{ + SkinRegion r[1]; + skin_region_init_copy(r,region); + skin_region_translate(r, -v->spos.x, -v->spos.y); + skin_region_intersect_rect(r,&v->rect); + skin_region_union( v->update, r ); + skin_region_reset(r); +} + +extern void +skin_viewport_redraw( SkinViewport* v ) +{ + if (v->space && !skin_region_is_empty(v->update)) { + SkinRegion update[1]; + SkinRegion drawn[1]; + SkinPos apos; + + skin_region_copy(update, v->update); + skin_region_reset(drawn); + skin_region_reset( v->update ); + + apos.x = apos.y = 0; + skin_plate_redraw( v->space, update, drawn, &apos, v ); + + skin_region_reset(update); + skin_region_reset(drawn); + } +} |