From 7fe60435bce6595a9c58a9bfd8244d74b5320e96 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Tue, 15 Jan 2013 08:46:13 +0100 Subject: Import DirectFB141_2k11R3_beta5 --- Source/DirectFB/src/display/idirectfbsurface.c | 2841 ++++++++++++++++++++++++ 1 file changed, 2841 insertions(+) create mode 100755 Source/DirectFB/src/display/idirectfbsurface.c (limited to 'Source/DirectFB/src/display/idirectfbsurface.c') diff --git a/Source/DirectFB/src/display/idirectfbsurface.c b/Source/DirectFB/src/display/idirectfbsurface.c new file mode 100755 index 0000000..bd23975 --- /dev/null +++ b/Source/DirectFB/src/display/idirectfbsurface.c @@ -0,0 +1,2841 @@ +/* + (c) Copyright 2001-2009 The world wide DirectFB Open Source Community (directfb.org) + (c) Copyright 2000-2004 Convergence (integrated media) GmbH + + All rights reserved. + + Written by Denis Oliver Kropp , + Andreas Hundt , + Sven Neumann , + Ville Syrjälä and + Claudio Ciccani . + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include + +#include +#include +#include +#include +#include + +#include + + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + + +D_DEBUG_DOMAIN( Surface, "IDirectFBSurface", "IDirectFBSurface Interface" ); + +/**********************************************************************************************************************/ + +static ReactionResult IDirectFBSurface_listener( const void *msg_data, void *ctx ); + +/**********************************************************************************************************************/ + +void +IDirectFBSurface_Destruct( IDirectFBSurface *thiz ) +{ + IDirectFBSurface_data *data; + IDirectFBSurface *parent; + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + D_ASSERT( thiz != NULL ); + + data = thiz->priv; + + D_ASSERT( data != NULL ); + D_ASSERT( data->children_data == NULL ); + + parent = data->parent; + if (parent) { + IDirectFBSurface_data *parent_data; + + D_MAGIC_ASSERT( (IAny*) parent, DirectInterface ); + + parent_data = parent->priv; + D_ASSERT( parent_data != NULL ); + + pthread_mutex_lock( &parent_data->children_lock ); + + direct_list_remove( &parent_data->children_data, &data->link ); + + pthread_mutex_unlock( &parent_data->children_lock ); + } + + if (data->surface) + dfb_surface_detach( data->surface, &data->reaction ); + + dfb_state_stop_drawing( &data->state ); + + dfb_state_set_destination( &data->state, NULL ); + dfb_state_set_source( &data->state, NULL ); + dfb_state_set_source_mask( &data->state, NULL ); + + dfb_state_destroy( &data->state ); + + if (data->font) + data->font->Release( data->font ); + + if (data->surface) { + if (data->locked) + dfb_surface_unlock_buffer( data->surface, &data->lock ); + + dfb_surface_unref( data->surface ); + } + + pthread_mutex_destroy( &data->children_lock ); + + DIRECT_DEALLOCATE_INTERFACE( thiz ); + + if (parent) + parent->Release( parent ); +} + +static DirectResult +IDirectFBSurface_AddRef( IDirectFBSurface *thiz ) +{ + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + data->ref++; + + return DFB_OK; +} + +static DirectResult +IDirectFBSurface_Release( IDirectFBSurface *thiz ) +{ + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + if (--data->ref == 0) + IDirectFBSurface_Destruct( thiz ); + + return DFB_OK; +} + + +static DFBResult +IDirectFBSurface_GetPixelFormat( IDirectFBSurface *thiz, + DFBSurfacePixelFormat *format ) +{ + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + if (!data->surface) + return DFB_DESTROYED; + + if (!format) + return DFB_INVARG; + + *format = data->surface->config.format; + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_GetAccelerationMask( IDirectFBSurface *thiz, + IDirectFBSurface *source, + DFBAccelerationMask *ret_mask ) +{ + DFBAccelerationMask mask = DFXL_NONE; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + if (!data->surface) + return DFB_DESTROYED; + + if (!ret_mask) + return DFB_INVARG; + + dfb_state_lock( &data->state ); + + /* Check drawing functions */ + if (dfb_gfxcard_state_check( &data->state, DFXL_FILLRECTANGLE )) + mask |= DFXL_FILLRECTANGLE; + + if (dfb_gfxcard_state_check( &data->state, DFXL_DRAWRECTANGLE )) + mask |= DFXL_DRAWRECTANGLE; + + if (dfb_gfxcard_state_check( &data->state, DFXL_DRAWLINE )) + mask |= DFXL_DRAWLINE; + + if (dfb_gfxcard_state_check( &data->state, DFXL_FILLTRIANGLE )) + mask |= DFXL_FILLTRIANGLE; + + dfb_state_unlock( &data->state ); + + /* Check blitting functions */ + if (source) { + IDirectFBSurface_data *src_data = source->priv; + + dfb_state_set_source( &data->state, src_data->surface ); + + dfb_state_lock( &data->state ); + + if (dfb_gfxcard_state_check( &data->state, DFXL_BLIT )) + mask |= DFXL_BLIT; + + if (dfb_gfxcard_state_check( &data->state, DFXL_STRETCHBLIT )) + mask |= DFXL_STRETCHBLIT; + + if (dfb_gfxcard_state_check( &data->state, DFXL_TEXTRIANGLES )) + mask |= DFXL_TEXTRIANGLES; + + dfb_state_unlock( &data->state ); + } + + /* Check text rendering function */ + if (data->font) { + IDirectFBFont_data *font_data = data->font->priv; + + if (dfb_gfxcard_drawstring_check_state( font_data->font, &data->state )) + mask |= DFXL_DRAWSTRING; + } + + *ret_mask = mask; + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_GetPosition( IDirectFBSurface *thiz, + int *x, + int *y ) +{ + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + if (!x && !y) + return DFB_INVARG; + + if (x) + *x = data->area.wanted.x; + + if (y) + *y = data->area.wanted.y; + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_GetSize( IDirectFBSurface *thiz, + int *width, + int *height ) +{ + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + if (!width && !height) + return DFB_INVARG; + + if (width) + *width = data->area.wanted.w; + + if (height) + *height = data->area.wanted.h; + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_GetVisibleRectangle( IDirectFBSurface *thiz, + DFBRectangle *rect ) +{ + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + if (!rect) + return DFB_INVARG; + + rect->x = data->area.current.x - data->area.wanted.x; + rect->y = data->area.current.y - data->area.wanted.y; + rect->w = data->area.current.w; + rect->h = data->area.current.h; + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_GetCapabilities( IDirectFBSurface *thiz, + DFBSurfaceCapabilities *caps ) +{ + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + if (!caps) + return DFB_INVARG; + + *caps = data->caps; + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_GetPalette( IDirectFBSurface *thiz, + IDirectFBPalette **interface ) +{ + DFBResult ret; + CoreSurface *surface; + IDirectFBPalette *palette; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + surface = data->surface; + if (!surface) + return DFB_DESTROYED; + + if (!surface->palette) + return DFB_UNSUPPORTED; + + if (!interface) + return DFB_INVARG; + + DIRECT_ALLOCATE_INTERFACE( palette, IDirectFBPalette ); + + ret = IDirectFBPalette_Construct( palette, surface->palette ); + if (ret) + return ret; + + *interface = palette; + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_SetPalette( IDirectFBSurface *thiz, + IDirectFBPalette *palette ) +{ + CoreSurface *surface; + IDirectFBPalette_data *palette_data; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + surface = data->surface; + if (!surface) + return DFB_DESTROYED; + + if (!palette) + return DFB_INVARG; + + if (! DFB_PIXELFORMAT_IS_INDEXED( surface->config.format )) + return DFB_UNSUPPORTED; + + palette_data = (IDirectFBPalette_data*) palette->priv; + if (!palette_data) + return DFB_DEAD; + + if (!palette_data->palette) + return DFB_DESTROYED; + + dfb_surface_set_palette( surface, palette_data->palette ); + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_SetAlphaRamp( IDirectFBSurface *thiz, + u8 a0, + u8 a1, + u8 a2, + u8 a3 ) +{ + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + if (!data->surface) + return DFB_DESTROYED; + + dfb_surface_set_alpha_ramp( data->surface, a0, a1, a2, a3 ); + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_Lock( IDirectFBSurface *thiz, + DFBSurfaceLockFlags flags, + void **ret_ptr, int *ret_pitch ) +{ + DFBResult ret; + CoreSurfaceBufferRole role = CSBR_FRONT; + CoreSurfaceAccessFlags access = CSAF_NONE; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + if (!data->surface) + return DFB_DESTROYED; + + if (data->locked) + return DFB_LOCKED; + + if (!flags || !ret_ptr || !ret_pitch) + return DFB_INVARG; + + if (!data->area.current.w || !data->area.current.h) + return DFB_INVAREA; + + if (flags & DSLF_READ) + access |= CSAF_READ; + + if (flags & DSLF_WRITE) { + access |= CSAF_WRITE; + role = CSBR_BACK; + } + + ret = dfb_surface_lock_buffer( data->surface, role, CSAID_CPU, access, &data->lock ); + if (ret) + return ret; + + data->locked = true; + + *ret_ptr = data->lock.addr + data->lock.pitch * data->area.current.y + + DFB_BYTES_PER_LINE( data->surface->config.format, data->area.current.x ); + *ret_pitch = data->lock.pitch; + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_GetFramebufferOffset( IDirectFBSurface *thiz, + int *offset ) +{ + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + if (!data->surface) + return DFB_DESTROYED; + + if (!offset) + return DFB_INVARG; + + if (!data->locked) + return DFB_ACCESSDENIED; + + if (!data->lock.phys) { + /* The surface is probably in a system buffer if there's no physical address. */ + return DFB_UNSUPPORTED; + } + + *offset = data->lock.offset; + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_Unlock( IDirectFBSurface *thiz ) +{ + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + if (!data->surface) + return DFB_DESTROYED; + + if (data->locked) { + dfb_surface_unlock_buffer( data->surface, &data->lock ); + + data->locked = false; + } + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_Write( IDirectFBSurface *thiz, + const DFBRectangle *rect, + const void *ptr, + int pitch ) +{ + CoreSurface *surface; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p, %p, %p [%d] )\n", __FUNCTION__, thiz, rect, ptr, pitch ); + + surface = data->surface; + if (!surface) + return DFB_DESTROYED; + + if (!rect || !ptr || pitch < DFB_BYTES_PER_LINE(surface->config.format,rect->w ) ) + return DFB_INVARG; + + if (data->locked) + return DFB_LOCKED; + + if (!data->area.current.w || !data->area.current.h) + return DFB_INVAREA; + + D_DEBUG_AT( Surface, " -> %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS( rect ) ); + + //FIXME: check rectangle + + return dfb_surface_write_buffer( data->surface, CSBR_BACK, ptr, pitch, rect ); +} + +static DFBResult +IDirectFBSurface_Read( IDirectFBSurface *thiz, + const DFBRectangle *rect, + void *ptr, + int pitch ) +{ + CoreSurface *surface; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p, %p, %p [%d] )\n", __FUNCTION__, thiz, rect, ptr, pitch ); + + surface = data->surface; + if (!surface) + return DFB_DESTROYED; + + if (!rect || !ptr || pitch < DFB_BYTES_PER_LINE(surface->config.format,rect->w ) ) + return DFB_INVARG; + + if (data->locked) + return DFB_LOCKED; + + if (!data->area.current.w || !data->area.current.h) + return DFB_INVAREA; + + D_DEBUG_AT( Surface, " -> %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS( rect ) ); + + //FIXME: check rectangle + + return dfb_surface_read_buffer( data->surface, CSBR_FRONT, ptr, pitch, rect ); +} + +static DFBResult +IDirectFBSurface_Flip( IDirectFBSurface *thiz, + const DFBRegion *region, + DFBSurfaceFlipFlags flags ) +{ + DFBResult ret; + DFBRegion reg; + CoreSurface *surface; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p, %p, 0x%08x )\n", __FUNCTION__, thiz, region, flags ); + + surface = data->surface; + if (!surface) + return DFB_DESTROYED; + + if (data->locked) + return DFB_LOCKED; + + if (!(surface->config.caps & DSCAPS_FLIPPING)) + return DFB_UNSUPPORTED; + + if (!data->area.current.w || !data->area.current.h || + (region && (region->x1 > region->x2 || region->y1 > region->y2))) + return DFB_INVAREA; + + IDirectFBSurface_StopAll( data ); + + /* FIXME: This is a temporary workaround for LiTE. */ + if (data->parent) { + IDirectFBSurface_data *parent_data; + + DIRECT_INTERFACE_GET_DATA_FROM( data->parent, parent_data, IDirectFBSurface ); + + /* Signal end of sequence of operations. */ + dfb_state_lock( &parent_data->state ); + dfb_state_stop_drawing( &parent_data->state ); + dfb_state_unlock( &parent_data->state ); + } + + dfb_region_from_rectangle( ®, &data->area.current ); + + if (region) { + DFBRegion clip = DFB_REGION_INIT_TRANSLATED( region, + data->area.wanted.x, + data->area.wanted.y ); + + if (!dfb_region_region_intersect( ®, &clip )) + return DFB_INVAREA; + } + + D_DEBUG_AT( Surface, " -> %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS_FROM_REGION( ® ) ); + + if (!(flags & DSFLIP_BLIT) && reg.x1 == 0 && reg.y1 == 0 && + reg.x2 == surface->config.size.w - 1 && reg.y2 == surface->config.size.h - 1) + { + ret = dfb_surface_lock( data->surface ); + if (ret) + return ret; + + dfb_surface_flip( data->surface, false ); + + dfb_surface_unlock( data->surface ); + } + else + dfb_back_to_front_copy( data->surface, ® ); + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_SetField( IDirectFBSurface *thiz, + int field ) +{ + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + if (!data->surface) + return DFB_DESTROYED; + + if (!(data->surface->config.caps & DSCAPS_INTERLACED)) + return DFB_UNSUPPORTED; + + if (field < 0 || field > 1) + return DFB_INVARG; + + dfb_surface_set_field( data->surface, field ); + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_Clear( IDirectFBSurface *thiz, + u8 r, u8 g, u8 b, u8 a ) +{ + DFBColor old_color; + unsigned int old_index; + DFBSurfaceDrawingFlags old_flags; + DFBSurfaceRenderOptions old_options; + CoreSurface *surface; + DFBColor color = { a, r, g, b }; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p, 0x%08x )\n", __FUNCTION__, thiz, PIXEL_ARGB(a,r,g,b) ); + + surface = data->surface; + if (!surface) + return DFB_DESTROYED; + + if (!data->area.current.w || !data->area.current.h) + return DFB_INVAREA; + + if (data->locked) + return DFB_LOCKED; + + /* save current color and drawing flags */ + old_color = data->state.color; + old_index = data->state.color_index; + old_flags = data->state.drawingflags; + old_options = data->state.render_options; + + /* set drawing flags */ + dfb_state_set_drawing_flags( &data->state, DSDRAW_NOFX ); + + /* set render options */ + dfb_state_set_render_options( &data->state, DSRO_NONE ); + + /* set color */ + if (DFB_PIXELFORMAT_IS_INDEXED( surface->config.format )) + dfb_state_set_color_index( &data->state, + dfb_palette_search( surface->palette, r, g, b, a ) ); + + dfb_state_set_color( &data->state, &color ); + + /* fill the visible rectangle */ + dfb_gfxcard_fillrectangles( &data->area.current, 1, &data->state ); + + /* clear the depth buffer */ + if (data->caps & DSCAPS_DEPTH) + dfb_clear_depth( data->surface, &data->state.clip ); + + /* restore drawing flags */ + dfb_state_set_drawing_flags( &data->state, old_flags ); + + /* restore render options */ + dfb_state_set_render_options( &data->state, old_options ); + + /* restore color */ + if (DFB_PIXELFORMAT_IS_INDEXED( surface->config.format )) + dfb_state_set_color_index( &data->state, old_index ); + + dfb_state_set_color( &data->state, &old_color ); + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_SetClip( IDirectFBSurface *thiz, const DFBRegion *clip ) +{ + DFBRegion newclip; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p, %p )\n", __FUNCTION__, thiz, clip ); + + + if (!data->area.current.w || !data->area.current.h) + return DFB_INVAREA; + + if (clip) { + newclip = DFB_REGION_INIT_TRANSLATED( clip, data->area.wanted.x, data->area.wanted.y ); + + D_DEBUG_AT( Surface, " <- %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS_FROM_REGION(&newclip) ); + + if (!dfb_unsafe_region_rectangle_intersect( &newclip, + &data->area.wanted )) + return DFB_INVARG; + + D_DEBUG_AT( Surface, " -> %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS_FROM_REGION(&newclip) ); + + data->clip_set = true; + data->clip_wanted = newclip; + + if (!dfb_region_rectangle_intersect( &newclip, &data->area.current )) + return DFB_INVAREA; + } + else { + dfb_region_from_rectangle( &newclip, &data->area.current ); + data->clip_set = false; + } + + D_DEBUG_AT( Surface, " => CLIP %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS_FROM_REGION(&newclip) ); + + dfb_state_set_clip( &data->state, &newclip ); + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_GetClip( IDirectFBSurface *thiz, DFBRegion *ret_clip ) +{ + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + if (!ret_clip) + return DFB_INVARG; + + if (!data->area.current.w || !data->area.current.h) + return DFB_INVAREA; + + *ret_clip = DFB_REGION_INIT_TRANSLATED( &data->state.clip, -data->area.wanted.x, -data->area.wanted.y ); + + D_DEBUG_AT( Surface, " -> %4d,%4d-%4dx%4d\n", DFB_RECTANGLE_VALS_FROM_REGION(ret_clip) ); + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_SetColor( IDirectFBSurface *thiz, + u8 r, u8 g, u8 b, u8 a ) +{ + CoreSurface *surface; + DFBColor color = { a, r, g, b }; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p, COLOR 0x%08x )\n", __FUNCTION__, thiz, PIXEL_ARGB(a, r, g, b) ); + + surface = data->surface; + if (!surface) + return DFB_DESTROYED; + + dfb_state_set_color( &data->state, &color ); + + if (DFB_PIXELFORMAT_IS_INDEXED( surface->config.format )) + dfb_state_set_color_index( &data->state, + dfb_palette_search( surface->palette, r, g, b, a ) ); + + data->state.colors[0] = data->state.color; + data->state.color_indices[0] = data->state.color_index; + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_SetColors( IDirectFBSurface *thiz, + const DFBColorID *ids, + const DFBColor *colors, + unsigned int num ) +{ + unsigned int i; + CoreSurface *surface; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p, %p, %p, %u )\n", __FUNCTION__, thiz, ids, colors, num ); + + surface = data->surface; + if (!surface) + return DFB_DESTROYED; + + for (i=0; i [%d] id %d = %02x %02x %02x %02x\n", + i, ids[i], colors[i].a, colors[i].r, colors[i].g, colors[i].b ); + + if (ids[i] >= DFB_COLOR_IDS_MAX) + return DFB_INVARG; + + data->state.colors[ids[i]] = colors[i]; + + if (DFB_PIXELFORMAT_IS_INDEXED( surface->config.format )) + data->state.color_indices[ids[i]] = dfb_palette_search( surface->palette, + colors[i].r, colors[i].g, colors[i].b, colors[i].a ); + } + + dfb_state_set_color( &data->state, &data->state.colors[0] ); + dfb_state_set_color_index( &data->state, data->state.color_indices[0] ); + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_SetColorIndex( IDirectFBSurface *thiz, + unsigned int index ) +{ + CoreSurface *surface; + CorePalette *palette; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p, COLOR INDEX %3u )\n", __FUNCTION__, thiz, index ); + + surface = data->surface; + if (!surface) + return DFB_DESTROYED; + + if (! DFB_PIXELFORMAT_IS_INDEXED( surface->config.format )) + return DFB_UNSUPPORTED; + + palette = surface->palette; + if (!palette) + return DFB_UNSUPPORTED; + + if (index > palette->num_entries) + return DFB_INVARG; + + dfb_state_set_color( &data->state, &palette->entries[index] ); + + dfb_state_set_color_index( &data->state, index ); + + data->state.colors[0] = data->state.color; + data->state.color_indices[0] = data->state.color_index; + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_SetSrcBlendFunction( IDirectFBSurface *thiz, + DFBSurfaceBlendFunction src ) +{ + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p, %d )\n", __FUNCTION__, thiz, src ); + + switch (src) { + case DSBF_ZERO: + case DSBF_ONE: + case DSBF_SRCCOLOR: + case DSBF_INVSRCCOLOR: + case DSBF_SRCALPHA: + case DSBF_INVSRCALPHA: + case DSBF_DESTALPHA: + case DSBF_INVDESTALPHA: + case DSBF_DESTCOLOR: + case DSBF_INVDESTCOLOR: + case DSBF_SRCALPHASAT: + dfb_state_set_src_blend( &data->state, src ); + return DFB_OK; + + default: + break; + } + + return DFB_INVARG; +} + +static DFBResult +IDirectFBSurface_SetDstBlendFunction( IDirectFBSurface *thiz, + DFBSurfaceBlendFunction dst ) +{ + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p, %d )\n", __FUNCTION__, thiz, dst ); + + switch (dst) { + case DSBF_ZERO: + case DSBF_ONE: + case DSBF_SRCCOLOR: + case DSBF_INVSRCCOLOR: + case DSBF_SRCALPHA: + case DSBF_INVSRCALPHA: + case DSBF_DESTALPHA: + case DSBF_INVDESTALPHA: + case DSBF_DESTCOLOR: + case DSBF_INVDESTCOLOR: + case DSBF_SRCALPHASAT: + dfb_state_set_dst_blend( &data->state, dst ); + return DFB_OK; + + default: + break; + } + + return DFB_INVARG; +} + +static DFBResult +IDirectFBSurface_SetPorterDuff( IDirectFBSurface *thiz, + DFBSurfacePorterDuffRule rule ) +{ + DFBSurfaceBlendFunction src; + DFBSurfaceBlendFunction dst; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p, %d )\n", __FUNCTION__, thiz, rule ); + + + switch (rule) { + case DSPD_NONE: + src = DSBF_SRCALPHA; + dst = DSBF_INVSRCALPHA; + break; + case DSPD_CLEAR: + src = DSBF_ZERO; + dst = DSBF_ZERO; + break; + case DSPD_SRC: + src = DSBF_ONE; + dst = DSBF_ZERO; + break; + case DSPD_SRC_OVER: + src = DSBF_ONE; + dst = DSBF_INVSRCALPHA; + break; + case DSPD_DST_OVER: + src = DSBF_INVDESTALPHA; + dst = DSBF_ONE; + break; + case DSPD_SRC_IN: + src = DSBF_DESTALPHA; + dst = DSBF_ZERO; + break; + case DSPD_DST_IN: + src = DSBF_ZERO; + dst = DSBF_SRCALPHA; + break; + case DSPD_SRC_OUT: + src = DSBF_INVDESTALPHA; + dst = DSBF_ZERO; + break; + case DSPD_DST_OUT: + src = DSBF_ZERO; + dst = DSBF_INVSRCALPHA; + break; + case DSPD_SRC_ATOP: + src = DSBF_DESTALPHA; + dst = DSBF_INVSRCALPHA; + break; + case DSPD_DST_ATOP: + src = DSBF_INVDESTALPHA; + dst = DSBF_SRCALPHA; + break; + case DSPD_ADD: + src = DSBF_ONE; + dst = DSBF_ONE; + break; + case DSPD_XOR: + src = DSBF_INVDESTALPHA; + dst = DSBF_INVSRCALPHA; + break; + default: + return DFB_INVARG; + } + + dfb_state_set_src_blend( &data->state, src ); + dfb_state_set_dst_blend( &data->state, dst ); + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_SetSrcColorKey( IDirectFBSurface *thiz, + u8 r, + u8 g, + u8 b ) +{ + CoreSurface *surface; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + surface = data->surface; + if (!surface) + return DFB_DESTROYED; + + data->src_key.r = r; + data->src_key.g = g; + data->src_key.b = b; + + if (DFB_PIXELFORMAT_IS_INDEXED( surface->config.format )) + data->src_key.value = dfb_palette_search( surface->palette, + r, g, b, 0x80 ); + else + data->src_key.value = dfb_color_to_pixel( surface->config.format, r, g, b ); + + /* The new key won't be applied to this surface's state. + The key will be taken by the destination surface to apply it + to its state when source color keying is used. */ + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_SetSrcColorKeyIndex( IDirectFBSurface *thiz, + unsigned int index ) +{ + CoreSurface *surface; + CorePalette *palette; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + surface = data->surface; + if (!surface) + return DFB_DESTROYED; + + if (! DFB_PIXELFORMAT_IS_INDEXED( surface->config.format )) + return DFB_UNSUPPORTED; + + palette = surface->palette; + if (!palette) + return DFB_UNSUPPORTED; + + if (index > palette->num_entries) + return DFB_INVARG; + + data->src_key.r = palette->entries[index].r; + data->src_key.g = palette->entries[index].g; + data->src_key.b = palette->entries[index].b; + + data->src_key.value = index; + + /* The new key won't be applied to this surface's state. + The key will be taken by the destination surface to apply it + to its state when source color keying is used. */ + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_SetDstColorKey( IDirectFBSurface *thiz, + u8 r, + u8 g, + u8 b ) +{ + CoreSurface *surface; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + surface = data->surface; + if (!surface) + return DFB_DESTROYED; + + data->dst_key.r = r; + data->dst_key.g = g; + data->dst_key.b = b; + + if (DFB_PIXELFORMAT_IS_INDEXED( surface->config.format )) + data->dst_key.value = dfb_palette_search( surface->palette, + r, g, b, 0x80 ); + else + data->dst_key.value = dfb_color_to_pixel( surface->config.format, r, g, b ); + + dfb_state_set_dst_colorkey( &data->state, data->dst_key.value ); + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_SetDstColorKeyIndex( IDirectFBSurface *thiz, + unsigned int index ) +{ + CoreSurface *surface; + CorePalette *palette; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + surface = data->surface; + if (!surface) + return DFB_DESTROYED; + + if (! DFB_PIXELFORMAT_IS_INDEXED( surface->config.format )) + return DFB_UNSUPPORTED; + + palette = surface->palette; + if (!palette) + return DFB_UNSUPPORTED; + + if (index > palette->num_entries) + return DFB_INVARG; + + data->dst_key.r = palette->entries[index].r; + data->dst_key.g = palette->entries[index].g; + data->dst_key.b = palette->entries[index].b; + + data->dst_key.value = index; + + dfb_state_set_dst_colorkey( &data->state, data->dst_key.value ); + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_SetIndexTranslation( IDirectFBSurface *thiz, + const int *indices, + int num_indices ) +{ + CoreSurface *surface; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + surface = data->surface; + if (!surface) + return DFB_DESTROYED; + + if (! DFB_PIXELFORMAT_IS_INDEXED( surface->config.format )) + return DFB_UNSUPPORTED; + + if (!indices && num_indices > 0) + return DFB_INVAREA; + + if (num_indices < 0 || num_indices > 256) + return DFB_INVARG; + + return dfb_state_set_index_translation( &data->state, indices, num_indices ); +} + +static DFBResult +IDirectFBSurface_SetFont( IDirectFBSurface *thiz, + IDirectFBFont *font ) +{ + DFBResult ret; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p, %p )\n", __FUNCTION__, thiz, font ); + + if (data->font != font) { + if (font) { + IDirectFBFont_data *font_data; + + ret = font->AddRef( font ); + if (ret) + return ret; + + DIRECT_INTERFACE_GET_DATA_FROM( font, font_data, IDirectFBFont ); + + data->encoding = font_data->encoding; + } + + if (data->font) + data->font->Release( data->font ); + + data->font = font; + } + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_GetFont( IDirectFBSurface *thiz, + IDirectFBFont **ret_font ) +{ + DFBResult ret; + IDirectFBFont *font; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + if (!ret_font) + return DFB_INVARG; + + font = data->font; + if (!font) { + *ret_font = NULL; + return DFB_MISSINGFONT; + } + + ret = font->AddRef( font ); + if (ret) + return ret; + + *ret_font = font; + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_SetDrawingFlags( IDirectFBSurface *thiz, + DFBSurfaceDrawingFlags flags ) +{ + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p, 0x%08x )\n", __FUNCTION__, thiz, flags ); + + dfb_state_set_drawing_flags( &data->state, flags ); + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_FillRectangle( IDirectFBSurface *thiz, + int x, int y, int w, int h ) +{ + DFBRectangle rect = { x, y, w, h }; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + D_DEBUG_AT( Surface, " -> [%2d] %4d,%4d-%4dx%4d\n", 0, x, y, w, h ); + + if (!data->surface) + return DFB_DESTROYED; + + + if (!data->area.current.w || !data->area.current.h) + return DFB_INVAREA; + + if (data->locked) + return DFB_LOCKED; + + if (w<=0 || h<=0) + return DFB_INVARG; + + rect.x += data->area.wanted.x; + rect.y += data->area.wanted.y; + + dfb_gfxcard_fillrectangles( &rect, 1, &data->state ); + + return DFB_OK; +} + + +static DFBResult +IDirectFBSurface_DrawLine( IDirectFBSurface *thiz, + int x1, int y1, int x2, int y2 ) +{ + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + D_DEBUG_AT( Surface, " -> [%2d] %4d,%4d-%4d,%4d\n", 0, x1, y1, x2, y2 ); + + if (!data->surface) + return DFB_DESTROYED; + + + if (!data->area.current.w || !data->area.current.h) + return DFB_INVAREA; + + if (data->locked) + return DFB_LOCKED; + + if ((x1 == x2 || y1 == y2) && !(data->state.render_options & DSRO_MATRIX)) { + DFBRectangle rect; + + if (x1 <= x2) { + rect.x = x1; + rect.w = x2 - x1 + 1; + } + else { + rect.x = x2; + rect.w = x1 - x2 + 1; + } + + if (y1 <= y2) { + rect.y = y1; + rect.h = y2 - y1 + 1; + } + else { + rect.y = y2; + rect.h = y1 - y2 + 1; + } + + rect.x += data->area.wanted.x; + rect.y += data->area.wanted.y; + + dfb_gfxcard_fillrectangles( &rect, 1, &data->state ); + } + else { + DFBRegion line = { x1, y1, x2, y2 }; + + line.x1 += data->area.wanted.x; + line.x2 += data->area.wanted.x; + line.y1 += data->area.wanted.y; + line.y2 += data->area.wanted.y; + + dfb_gfxcard_drawlines( &line, 1, &data->state ); + } + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_DrawLines( IDirectFBSurface *thiz, + const DFBRegion *lines, + unsigned int num_lines ) +{ + unsigned int i; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p, %p [%d] )\n", __FUNCTION__, thiz, lines, num_lines ); + + if (!data->surface) + return DFB_DESTROYED; + + + if (!data->area.current.w || !data->area.current.h) + return DFB_INVAREA; + + if (data->locked) + return DFB_LOCKED; + + if (!lines || !num_lines) + return DFB_INVARG; + + /* Check if all lines are either horizontal or vertical */ + for (i=0; iarea.wanted.x || data->area.wanted.y) { + for (i=0; iarea.wanted.x; + local_lines[i].x2 = lines[i].x2 + data->area.wanted.x; + local_lines[i].y1 = lines[i].y1 + data->area.wanted.y; + local_lines[i].y2 = lines[i].y2 + data->area.wanted.y; + } + } + else + /* clipping may modify lines, so we copy them */ + direct_memcpy( local_lines, lines, sizeof(DFBRegion) * num_lines ); + + dfb_gfxcard_drawlines( local_lines, num_lines, &data->state ); + } + /* Optimized rectangle drawing */ + else { + DFBRectangle *local_rects = alloca(sizeof(DFBRectangle) * num_lines); + + for (i=0; iarea.wanted.x + lines[i].x1; + local_rects[i].y = data->area.wanted.y + MIN( lines[i].y1, lines[i].y2 ); + local_rects[i].w = 1; + local_rects[i].h = ABS( lines[i].y2 - lines[i].y1 ) + 1; + } + /* Horizontal line */ + else { + local_rects[i].x = data->area.wanted.x + MIN( lines[i].x1, lines[i].x2 ); + local_rects[i].y = data->area.wanted.y + lines[i].y1; + local_rects[i].w = ABS( lines[i].x2 - lines[i].x1 ) + 1; + local_rects[i].h = 1; + } + } + + dfb_gfxcard_fillrectangles( local_rects, num_lines, &data->state ); + } + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_DrawRectangle( IDirectFBSurface *thiz, + int x, int y, int w, int h ) +{ + DFBRectangle rect = { x, y, w, h }; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + D_DEBUG_AT( Surface, " -> [%2d] %4d,%4d-%4dx%4d\n", 0, x, y, w, h ); + + if (!data->surface) + return DFB_DESTROYED; + + + if (!data->area.current.w || !data->area.current.h) + return DFB_INVAREA; + + if (data->locked) + return DFB_LOCKED; + + if (w<=0 || h<=0) + return DFB_INVARG; + + rect.x += data->area.wanted.x; + rect.y += data->area.wanted.y; + + dfb_gfxcard_drawrectangle( &rect, &data->state ); + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_FillTriangle( IDirectFBSurface *thiz, + int x1, int y1, + int x2, int y2, + int x3, int y3 ) +{ + DFBTriangle tri = { x1, y1, x2, y2, x3, y3 }; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + D_DEBUG_AT( Surface, " -> [%2d] %4d,%4d-%4d,%4d-%4d,%4d\n", 0, x1, y1, x2, y2, x3, y3 ); + + if (!data->surface) + return DFB_DESTROYED; + + + if (!data->area.current.w || !data->area.current.h) + return DFB_INVAREA; + + if (data->locked) + return DFB_LOCKED; + + tri.x1 += data->area.wanted.x; + tri.y1 += data->area.wanted.y; + tri.x2 += data->area.wanted.x; + tri.y2 += data->area.wanted.y; + tri.x3 += data->area.wanted.x; + tri.y3 += data->area.wanted.y; + + dfb_gfxcard_filltriangles( &tri, 1, &data->state ); + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_FillRectangles( IDirectFBSurface *thiz, + const DFBRectangle *rects, + unsigned int num_rects ) +{ + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p, %p [%d] )\n", __FUNCTION__, thiz, rects, num_rects ); + + DFB_RECTANGLES_DEBUG_AT( Surface, rects, num_rects ); + + + if (!data->surface) + return DFB_DESTROYED; + + + if (!data->area.current.w || !data->area.current.h) + return DFB_INVAREA; + + if (data->locked) + return DFB_LOCKED; + + if (!rects || !num_rects) + return DFB_INVARG; + + if (data->area.wanted.x || data->area.wanted.y) { + unsigned int i; + DFBRectangle *local_rects; + bool malloced = (num_rects > 256); + + if (malloced) + local_rects = D_MALLOC( sizeof(DFBRectangle) * num_rects ); + else + local_rects = alloca( sizeof(DFBRectangle) * num_rects ); + + for (i=0; iarea.wanted.x; + local_rects[i].y = rects[i].y + data->area.wanted.y; + local_rects[i].w = rects[i].w; + local_rects[i].h = rects[i].h; + } + + dfb_gfxcard_fillrectangles( local_rects, num_rects, &data->state ); + + if (malloced) + D_FREE( local_rects ); + } + else + dfb_gfxcard_fillrectangles( rects, num_rects, &data->state ); + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_FillSpans( IDirectFBSurface *thiz, + int y, + const DFBSpan *spans, + unsigned int num_spans ) +{ + DFBSpan *local_spans = alloca(sizeof(DFBSpan) * num_spans); + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + if (!data->surface) + return DFB_DESTROYED; + + + if (!data->area.current.w || !data->area.current.h) + return DFB_INVAREA; + + if (data->locked) + return DFB_LOCKED; + + if (!spans || !num_spans) + return DFB_INVARG; + + if (data->area.wanted.x || data->area.wanted.y) { + unsigned int i; + + for (i=0; iarea.wanted.x; + local_spans[i].w = spans[i].w; + } + } + else + /* clipping may modify spans, so we copy them */ + direct_memcpy( local_spans, spans, sizeof(DFBSpan) * num_spans ); + + dfb_gfxcard_fillspans( y + data->area.wanted.y, local_spans, num_spans, &data->state ); + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_FillTriangles( IDirectFBSurface *thiz, + const DFBTriangle *tris, + unsigned int num_tris ) +{ + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + if (!data->surface) + return DFB_DESTROYED; + + + if (!data->area.current.w || !data->area.current.h) + return DFB_INVAREA; + + if (data->locked) + return DFB_LOCKED; + + if (!tris || !num_tris) + return DFB_INVARG; + + if (data->area.wanted.x || data->area.wanted.y) { + unsigned int i; + DFBTriangle *local_tris; + bool malloced = (num_tris > 170); + + if (malloced) + local_tris = D_MALLOC( sizeof(DFBTriangle) * num_tris ); + else + local_tris = alloca( sizeof(DFBTriangle) * num_tris ); + + for (i=0; iarea.wanted.x; + local_tris[i].y1 = tris[i].y1 + data->area.wanted.y; + local_tris[i].x2 = tris[i].x2 + data->area.wanted.x; + local_tris[i].y2 = tris[i].y2 + data->area.wanted.y; + local_tris[i].x3 = tris[i].x3 + data->area.wanted.x; + local_tris[i].y3 = tris[i].y3 + data->area.wanted.y; + } + + dfb_gfxcard_filltriangles( local_tris, num_tris, &data->state ); + + if (malloced) + D_FREE( local_tris ); + } + else + dfb_gfxcard_filltriangles( tris, num_tris, &data->state ); + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_SetBlittingFlags( IDirectFBSurface *thiz, + DFBSurfaceBlittingFlags flags ) +{ + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + dfb_state_set_blitting_flags( &data->state, flags ); + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_Blit( IDirectFBSurface *thiz, + IDirectFBSurface *source, + const DFBRectangle *sr, + int dx, int dy ) +{ + DFBRectangle srect; + IDirectFBSurface_data *src_data; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + if (sr) + D_DEBUG_AT( Surface, " -> [%2d] %4d,%4d-%4dx%4d <- %4d,%4d\n", 0, dx, dy, sr->w, sr->h, sr->x, sr->y ); + + if (!data->surface) + return DFB_DESTROYED; + + if (!source) + return DFB_INVARG; + + if (!data->area.current.w || !data->area.current.h) + return DFB_INVAREA; + + if (data->locked) + return DFB_LOCKED; + + + src_data = (IDirectFBSurface_data*)source->priv; + + if (!src_data->area.current.w || !src_data->area.current.h) + return DFB_INVAREA; + + if (sr) { + if (sr->w < 1 || sr->h < 1) + return DFB_OK; + + srect = *sr; + + srect.x += src_data->area.wanted.x; + srect.y += src_data->area.wanted.y; + + if (!dfb_rectangle_intersect( &srect, &src_data->area.current )) + return DFB_INVAREA; + + dx += srect.x - (sr->x + src_data->area.wanted.x); + dy += srect.y - (sr->y + src_data->area.wanted.y); + } + else { + srect = src_data->area.current; + + dx += srect.x - src_data->area.wanted.x; + dy += srect.y - src_data->area.wanted.y; + } + + dfb_state_set_source( &data->state, src_data->surface ); + + /* fetch the source color key from the source if necessary */ + if (data->state.blittingflags & DSBLIT_SRC_COLORKEY) + dfb_state_set_src_colorkey( &data->state, src_data->src_key.value ); + + dfb_gfxcard_blit( &srect, + data->area.wanted.x + dx, + data->area.wanted.y + dy, &data->state ); + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_TileBlit( IDirectFBSurface *thiz, + IDirectFBSurface *source, + const DFBRectangle *sr, + int dx, int dy ) +{ + DFBRectangle srect; + IDirectFBSurface_data *src_data; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + if (sr) + D_DEBUG_AT( Surface, " -> [%2d] %4d,%4d-%4dx%4d <- %4d,%4d\n", 0, dx, dy, sr->w, sr->h, sr->x, sr->y ); + + if (!data->surface) + return DFB_DESTROYED; + + + if (!data->area.current.w || !data->area.current.h) + return DFB_INVAREA; + + if (data->locked) + return DFB_LOCKED; + + if (!source) + return DFB_INVARG; + + + src_data = (IDirectFBSurface_data*)source->priv; + + if (!src_data->area.current.w || !src_data->area.current.h) + return DFB_INVAREA; + + + if (sr) { + if (sr->w < 1 || sr->h < 1) + return DFB_OK; + + srect = *sr; + + srect.x += src_data->area.wanted.x; + srect.y += src_data->area.wanted.y; + + if (!dfb_rectangle_intersect( &srect, &src_data->area.current )) + return DFB_INVAREA; + + dx += srect.x - (sr->x + src_data->area.wanted.x); + dy += srect.y - (sr->y + src_data->area.wanted.y); + } + else { + srect = src_data->area.current; + + dx += srect.x - src_data->area.wanted.x; + dy += srect.y - src_data->area.wanted.y; + } + + dfb_state_set_source( &data->state, src_data->surface ); + + /* fetch the source color key from the source if necessary */ + if (data->state.blittingflags & DSBLIT_SRC_COLORKEY) + dfb_state_set_src_colorkey( &data->state, src_data->src_key.value ); + + dx %= srect.w; + if (dx > 0) + dx -= srect.w; + + dy %= srect.h; + if (dy > 0) + dy -= srect.h; + + dx += data->area.wanted.x; + dy += data->area.wanted.y; + + dfb_gfxcard_tileblit( &srect, dx, dy, + dx + data->area.wanted.w + srect.w - 1, + dy + data->area.wanted.h + srect.h - 1, &data->state ); + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_BatchBlit( IDirectFBSurface *thiz, + IDirectFBSurface *source, + const DFBRectangle *source_rects, + const DFBPoint *dest_points, + int num ) +{ + int i, dx, dy, sx, sy; + DFBRectangle *rects; + DFBPoint *points; + IDirectFBSurface_data *src_data; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + if (!data->surface) + return DFB_DESTROYED; + + if (!source || !source_rects || !dest_points || num < 1) + return DFB_INVARG; + + if (!data->area.current.w || !data->area.current.h) + return DFB_INVAREA; + + if (data->locked) + return DFB_LOCKED; + + + src_data = (IDirectFBSurface_data*)source->priv; + + if (!src_data->area.current.w || !src_data->area.current.h) + return DFB_INVAREA; + + dx = data->area.wanted.x; + dy = data->area.wanted.y; + + sx = src_data->area.wanted.x; + sy = src_data->area.wanted.y; + + rects = alloca( sizeof(DFBRectangle) * num ); + points = alloca( sizeof(DFBPoint) * num ); + + direct_memcpy( rects, source_rects, sizeof(DFBRectangle) * num ); + direct_memcpy( points, dest_points, sizeof(DFBPoint) * num ); + + for (i=0; iarea.current )) + rects[i].w = rects[i].h = 0; + + points[i].x += rects[i].x - (source_rects[i].x + sx); + points[i].y += rects[i].y - (source_rects[i].y + sy); + } + + dfb_state_set_source( &data->state, src_data->surface ); + + /* fetch the source color key from the source if necessary */ + if (data->state.blittingflags & DSBLIT_SRC_COLORKEY) + dfb_state_set_src_colorkey( &data->state, src_data->src_key.value ); + + dfb_gfxcard_batchblit( rects, points, num, &data->state ); + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_StretchBlit( IDirectFBSurface *thiz, + IDirectFBSurface *source, + const DFBRectangle *source_rect, + const DFBRectangle *destination_rect ) +{ + DFBRectangle srect, drect; + IDirectFBSurface_data *src_data; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + if (!data->surface) + return DFB_DESTROYED; + + + if (!data->area.current.w || !data->area.current.h) + return DFB_INVAREA; + + if (data->locked) + return DFB_LOCKED; + + if (!source) + return DFB_INVARG; + + + src_data = (IDirectFBSurface_data*)source->priv; + + if (!src_data->area.current.w || !src_data->area.current.h) + return DFB_INVAREA; + + + /* do destination rectangle */ + if (destination_rect) { + if (destination_rect->w < 1 || destination_rect->h < 1) + return DFB_INVARG; + + drect = *destination_rect; + + drect.x += data->area.wanted.x; + drect.y += data->area.wanted.y; + } + else + drect = data->area.wanted; + + /* do source rectangle */ + if (source_rect) { + if (source_rect->w < 1 || source_rect->h < 1) + return DFB_INVARG; + + srect = *source_rect; + + srect.x += src_data->area.wanted.x; + srect.y += src_data->area.wanted.y; + } + else + srect = src_data->area.wanted; + + + /* clipping of the source rectangle must be applied to the destination */ + { + DFBRectangle orig_src = srect; + + if (!dfb_rectangle_intersect( &srect, &src_data->area.current )) + return DFB_INVAREA; + + if (srect.x != orig_src.x) + drect.x += (int)( (srect.x - orig_src.x) * + (drect.w / (float)orig_src.w) + 0.5f); + + if (srect.y != orig_src.y) + drect.y += (int)( (srect.y - orig_src.y) * + (drect.h / (float)orig_src.h) + 0.5f); + + if (srect.w != orig_src.w) + drect.w = D_ICEIL(drect.w * (srect.w / (float)orig_src.w)); + if (srect.h != orig_src.h) + drect.h = D_ICEIL(drect.h * (srect.h / (float)orig_src.h)); + } + + dfb_state_set_source( &data->state, src_data->surface ); + + /* fetch the source color key from the source if necessary */ + if (data->state.blittingflags & DSBLIT_SRC_COLORKEY) + dfb_state_set_src_colorkey( &data->state, src_data->src_key.value ); + + dfb_gfxcard_stretchblit( &srect, &drect, &data->state ); + + return DFB_OK; +} + +#define SET_VERTEX(v,X,Y,Z,W,S,T) \ + do { \ + (v)->x = X; \ + (v)->y = Y; \ + (v)->z = Z; \ + (v)->w = W; \ + (v)->s = S; \ + (v)->t = T; \ + } while (0) + +static DFBResult +IDirectFBSurface_TextureTriangles( IDirectFBSurface *thiz, + IDirectFBSurface *source, + const DFBVertex *vertices, + const int *indices, + int num, + DFBTriangleFormation formation ) +{ + int i; + DFBVertex *translated; + IDirectFBSurface_data *src_data; + bool src_sub; + float x0 = 0; + float y0 = 0; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + if (!data->surface) + return DFB_DESTROYED; + + + if (!data->area.current.w || !data->area.current.h) + return DFB_INVAREA; + + if (data->locked) + return DFB_LOCKED; + + if (!source || !vertices || num < 3) + return DFB_INVARG; + + src_data = (IDirectFBSurface_data*)source->priv; + + if ((src_sub = (src_data->caps & DSCAPS_SUBSURFACE))) { + D_ONCE( "sub surface texture not fully working with 'repeated' mapping" ); + + x0 = data->area.wanted.x; + y0 = data->area.wanted.y; + } + + switch (formation) { + case DTTF_LIST: + if (num % 3) + return DFB_INVARG; + break; + + case DTTF_STRIP: + case DTTF_FAN: + break; + + default: + return DFB_INVARG; + } + + translated = alloca( num * sizeof(DFBVertex) ); + if (!translated) + return DFB_NOSYSTEMMEMORY; + + /* TODO: pass indices through to driver */ + if (src_sub) { + float oowidth = 1.0f / src_data->surface->config.size.w; + float ooheight = 1.0f / src_data->surface->config.size.h; + + float s0 = src_data->area.wanted.x * oowidth; + float t0 = src_data->area.wanted.y * ooheight; + + float fs = src_data->area.wanted.w * oowidth; + float ft = src_data->area.wanted.h * ooheight; + + for (i=0; ix, y0 + in->y, in->z, in->w, + s0 + fs * in->s, t0 + ft * in->t ); + } + } + else { + if (indices) { + for (i=0; ix, y0 + in->y, in->z, in->w, in->s, in->t ); + } + } + else { + direct_memcpy( translated, vertices, num * sizeof(DFBVertex) ); + + for (i=0; istate, src_data->surface ); + + /* fetch the source color key from the source if necessary */ + if (data->state.blittingflags & DSBLIT_SRC_COLORKEY) + dfb_state_set_src_colorkey( &data->state, src_data->src_key.value ); + + dfb_gfxcard_texture_triangles( translated, num, formation, &data->state ); + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_DrawString( IDirectFBSurface *thiz, + const char *text, int bytes, + int x, int y, + DFBSurfaceTextFlags flags ) +{ + DFBResult ret; + IDirectFBFont *font; + IDirectFBFont_data *font_data; + CoreFont *core_font; + unsigned int layers = 1; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + if (!data->surface) + return DFB_DESTROYED; + + if (!text) + return DFB_INVARG; + + if (!data->area.current.w || !data->area.current.h) + return DFB_INVAREA; + + if (data->locked) + return DFB_LOCKED; + + if (!data->font) + return DFB_MISSINGFONT; + + if (bytes < 0) + bytes = strlen (text); + + if (bytes == 0) + return DFB_OK; + + font = data->font; + + DIRECT_INTERFACE_GET_DATA_FROM( font, font_data, IDirectFBFont ); + + core_font = font_data->font; + + if (flags & DSTF_OUTLINE) { + if (!(core_font->attributes & DFFA_OUTLINED)) + return DFB_UNSUPPORTED; + + layers = 2; + } + + if (!(flags & DSTF_TOP)) { + x += core_font->ascender * core_font->up_unit_x; + y += core_font->ascender * core_font->up_unit_y; + + if (flags & DSTF_BOTTOM) { + x -= core_font->descender * core_font->up_unit_x; + y -= core_font->descender * core_font->up_unit_y; + } + } + + if (flags & (DSTF_RIGHT | DSTF_CENTER)) { + int i, num, kx, ky; + int xsize = 0; + int ysize = 0; + unsigned int prev = 0; + unsigned int indices[bytes]; + + /* FIXME: Avoid double locking and decoding. */ + dfb_font_lock( core_font ); + + /* Decode string to character indices. */ + ret = dfb_font_decode_text( core_font, data->encoding, text, bytes, indices, &num ); + if (ret) { + dfb_font_unlock( core_font ); + return ret; + } + + /* Calculate string width. */ + for (i=0; ixadvance; + ysize += glyph->yadvance; + + if (prev && core_font->GetKerning && + core_font->GetKerning( core_font, prev, current, &kx, &ky ) == DFB_OK) { + xsize += kx; + ysize += ky; + } + } + + prev = current; + } + + dfb_font_unlock( core_font ); + + /* Justify. */ + if (flags & DSTF_RIGHT) { + x -= xsize; + y -= ysize; + } + else if (flags & DSTF_CENTER) { + x -= xsize >> 1; + y -= ysize >> 1; + } + } + + dfb_gfxcard_drawstring( (const unsigned char*) text, bytes, data->encoding, + data->area.wanted.x + x, data->area.wanted.y + y, + core_font, layers, &data->state ); + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_DrawGlyph( IDirectFBSurface *thiz, + unsigned int character, int x, int y, + DFBSurfaceTextFlags flags ) +{ + DFBResult ret; + int l; + IDirectFBFont *font; + IDirectFBFont_data *font_data; + CoreFont *core_font; + CoreGlyphData *glyph[DFB_FONT_MAX_LAYERS]; + unsigned int index; + unsigned int layers = 1; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p, 0x%x, %d,%d, 0x%x )\n", + __FUNCTION__, thiz, character, x, y, flags ); + + if (!data->surface) + return DFB_DESTROYED; + + if (!character) + return DFB_INVARG; + + if (!data->area.current.w || !data->area.current.h) + return DFB_INVAREA; + + if (data->locked) + return DFB_LOCKED; + + if (!data->font) + return DFB_MISSINGFONT; + + font = data->font; + + DIRECT_INTERFACE_GET_DATA_FROM( font, font_data, IDirectFBFont ); + + core_font = font_data->font; + + if (flags & DSTF_OUTLINE) { + if (!(core_font->attributes & DFFA_OUTLINED)) + return DFB_UNSUPPORTED; + + layers = 2; + } + + dfb_font_lock( core_font ); + + ret = dfb_font_decode_character( core_font, data->encoding, character, &index ); + if (ret) { + dfb_font_unlock( core_font ); + return ret; + } + + for (l=0; lascender * core_font->up_unit_x; + y += core_font->ascender * core_font->up_unit_y; + + if (flags & DSTF_BOTTOM) { + x -= core_font->descender * core_font->up_unit_x; + y -= core_font->descender * core_font->up_unit_y; + } + } + + if (flags & (DSTF_RIGHT | DSTF_CENTER)) { + if (flags & DSTF_RIGHT) { + x -= glyph[0]->xadvance; + y -= glyph[0]->yadvance; + } + else if (flags & DSTF_CENTER) { + x -= glyph[0]->xadvance >> 1; + y -= glyph[0]->yadvance >> 1; + } + } + + dfb_gfxcard_drawglyph( glyph, + data->area.wanted.x + x, data->area.wanted.y + y, + core_font, layers, &data->state ); + + dfb_font_unlock( core_font ); + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_SetEncoding( IDirectFBSurface *thiz, + DFBTextEncodingID encoding ) +{ + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p, %d )\n", __FUNCTION__, thiz, encoding ); + + /* TODO: check for support or fail later? */ + data->encoding = encoding; + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_GetSubSurface( IDirectFBSurface *thiz, + const DFBRectangle *rect, + IDirectFBSurface **surface ) +{ + DFBResult ret; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + /* Check arguments */ + if (!data->surface) + return DFB_DESTROYED; + + if (!surface) + return DFB_INVARG; + + /* Allocate interface */ + DIRECT_ALLOCATE_INTERFACE( *surface, IDirectFBSurface ); + + if (rect || data->limit_set) { + DFBRectangle wanted, granted; + + /* Compute wanted rectangle */ + if (rect) { + wanted = *rect; + + wanted.x += data->area.wanted.x; + wanted.y += data->area.wanted.y; + + if (wanted.w <= 0 || wanted.h <= 0) { + wanted.w = 0; + wanted.h = 0; + } + } + else { + wanted = data->area.wanted; + } + + /* Compute granted rectangle */ + granted = wanted; + + dfb_rectangle_intersect( &granted, &data->area.granted ); + + /* Construct */ + ret = IDirectFBSurface_Construct( *surface, thiz, + &wanted, &granted, &data->area.insets, + data->surface, + data->caps | DSCAPS_SUBSURFACE, data->core ); + } + else { + /* Construct */ + ret = IDirectFBSurface_Construct( *surface, thiz, + NULL, NULL, &data->area.insets, + data->surface, + data->caps | DSCAPS_SUBSURFACE, data->core ); + } + + return ret; +} + +static DFBResult +IDirectFBSurface_MakeSubSurface( IDirectFBSurface *thiz, + IDirectFBSurface *from, + const DFBRectangle *rect ) +{ + CoreSurface *surface; + DFBRectangle wanted, granted; + DFBRectangle full_rect; + IDirectFBSurface_data *from_data; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + /* Check arguments */ + if (!from) + return DFB_INVARG; + + surface = data->surface; + if (!surface) + return DFB_DESTROYED; + + DIRECT_INTERFACE_GET_DATA_FROM(from, from_data, IDirectFBSurface); + + /* Check if CoreSurface is the same */ + if (from_data->surface != surface) + return DFB_UNSUPPORTED; + + + full_rect.x = 0; + full_rect.y = 0; + full_rect.w = surface->config.size.w; + full_rect.h = surface->config.size.h; + + if (rect || from_data->limit_set) { + /* Compute wanted rectangle */ + if (rect) { + wanted = *rect; + + wanted.x += from_data->area.wanted.x; + wanted.y += from_data->area.wanted.y; + + if (wanted.w <= 0 || wanted.h <= 0) { + wanted.w = 0; + wanted.h = 0; + } + } + else { + wanted = from_data->area.wanted; + } + + /* Compute granted rectangle */ + granted = wanted; + + dfb_rectangle_intersect( &granted, &from_data->area.granted ); + } + else { + wanted = full_rect; + granted = full_rect; + } + + + data->caps |= DSCAPS_SUBSURFACE; + + + data->area.wanted = wanted; + data->area.granted = granted; + + data->area.current = data->area.granted; + dfb_rectangle_intersect( &data->area.current, &full_rect ); + + + data->state.clip.x1 = data->area.current.x; + data->state.clip.y1 = data->area.current.y; + data->state.clip.x2 = data->area.current.x + (data->area.current.w ? : 1) - 1; + data->state.clip.y2 = data->area.current.y + (data->area.current.h ? : 1) - 1; + + data->state.modified |= SMF_CLIP; + + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_GetGL( IDirectFBSurface *thiz, + IDirectFBGL **interface ) +{ + DFBResult ret; + DirectInterfaceFuncs *funcs = NULL; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + if (!data->surface) + return DFB_DESTROYED; + + if (!interface) + return DFB_INVARG; + + if (!data->area.current.w || !data->area.current.h) + return DFB_INVAREA; + + + ret = DirectGetInterface( &funcs, "IDirectFBGL", NULL, DirectProbeInterface, thiz ); + if (ret) + return ret; + + ret = funcs->Allocate( (void**)interface ); + if (ret) + return ret; + + ret = funcs->Construct( *interface, thiz ); + if (ret) + *interface = NULL; + + return ret; +} + +static DFBResult +IDirectFBSurface_Dump( IDirectFBSurface *thiz, + const char *directory, + const char *prefix ) +{ + CoreSurface *surface; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + if (!directory) + return DFB_INVARG; + + if (!data->area.current.w || !data->area.current.h) + return DFB_INVAREA; + + if (data->caps & DSCAPS_SUBSURFACE) { + D_ONCE( "sub surface dumping not supported yet" ); + return DFB_UNSUPPORTED; + } + + surface = data->surface; + if (!surface) + return DFB_DESTROYED; + + return dfb_surface_dump_buffer( surface, CSBR_FRONT, directory, prefix ); +} + +static DFBResult +IDirectFBSurface_DisableAcceleration( IDirectFBSurface *thiz, + DFBAccelerationMask mask ) +{ + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + if (D_FLAGS_INVALID( mask, DFXL_ALL )) + return DFB_INVARG; + + data->state.disabled = mask; + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_ReleaseSource( IDirectFBSurface *thiz ) +{ + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + dfb_state_set_source( &data->state, NULL ); + dfb_state_set_source_mask( &data->state, NULL ); + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_SetRenderOptions( IDirectFBSurface *thiz, + DFBSurfaceRenderOptions options ) +{ + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + dfb_state_set_render_options( &data->state, options ); + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_SetMatrix( IDirectFBSurface *thiz, + const s32 *matrix ) +{ + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p, %p )\n", __FUNCTION__, thiz, matrix ); + + if (!matrix) + return DFB_INVARG; + + dfb_state_set_matrix( &data->state, matrix ); + + return DFB_OK; +} + +static DFBResult +IDirectFBSurface_SetSourceMask( IDirectFBSurface *thiz, + IDirectFBSurface *mask, + int x, + int y, + DFBSurfaceMaskFlags flags ) +{ + DFBResult ret; + DFBPoint offset = { x, y }; + IDirectFBSurface_data *mask_data; + + DIRECT_INTERFACE_GET_DATA(IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p, %p, %d,%d, 0x%04x )\n", __FUNCTION__, thiz, mask, x, y, flags ); + + if (!mask || flags & ~DSMF_ALL) + return DFB_INVARG; + + DIRECT_INTERFACE_GET_DATA_FROM(mask, mask_data, IDirectFBSurface); + + if (!mask_data->surface) + return DFB_DESTROYED; + + ret = dfb_state_set_source_mask( &data->state, mask_data->surface ); + if (ret) + return ret; + + dfb_state_set_source_mask_vals( &data->state, &offset, flags ); + + return DFB_OK; +} + +/******/ + +DFBResult IDirectFBSurface_Construct( IDirectFBSurface *thiz, + IDirectFBSurface *parent, + DFBRectangle *wanted, + DFBRectangle *granted, + DFBInsets *insets, + CoreSurface *surface, + DFBSurfaceCapabilities caps, + CoreDFB *core ) +{ + DFBRectangle rect = { 0, 0, surface->config.size.w, surface->config.size.h }; + + DIRECT_ALLOCATE_INTERFACE_DATA(thiz, IDirectFBSurface) + + D_DEBUG_AT( Surface, "%s( %p )\n", __FUNCTION__, thiz ); + + data->ref = 1; + data->caps = caps | surface->config.caps; + data->core = core; + + if (dfb_surface_ref( surface )) { + DIRECT_DEALLOCATE_INTERFACE(thiz); + return DFB_FAILURE; + } + + if (parent && dfb_config->startstop) { + IDirectFBSurface_data *parent_data; + + if (parent->AddRef( parent )) { + dfb_surface_unref( surface ); + DIRECT_DEALLOCATE_INTERFACE(thiz); + return DFB_FAILURE; + } + + DIRECT_INTERFACE_GET_DATA_FROM( parent, parent_data, IDirectFBSurface ); + + pthread_mutex_lock( &parent_data->children_lock ); + + direct_list_append( &parent_data->children_data, &data->link ); + + pthread_mutex_unlock( &parent_data->children_lock ); + + data->parent = parent; + } + + pthread_mutex_init( &data->children_lock, NULL ); + + /* The area insets */ + if (insets) { + data->area.insets = *insets; + dfb_rectangle_subtract( &rect, insets ); + } + + /* The area that was requested */ + if (wanted) + data->area.wanted = *wanted; + else + data->area.wanted = rect; + + /* The area that will never be exceeded */ + if (granted) + data->area.granted = *granted; + else + data->area.granted = data->area.wanted; + + /* The currently accessible rectangle */ + data->area.current = data->area.granted; + dfb_rectangle_intersect( &data->area.current, &rect ); + + /* Whether granted rectangle is meaningful */ + data->limit_set = (granted != NULL); + + data->surface = surface; + + dfb_state_init( &data->state, NULL ); + dfb_state_set_destination( &data->state, surface ); + + data->state.clip.x1 = data->area.current.x; + data->state.clip.y1 = data->area.current.y; + data->state.clip.x2 = data->area.current.x + (data->area.current.w ? : 1) - 1; + data->state.clip.y2 = data->area.current.y + (data->area.current.h ? : 1) - 1; + + data->state.modified = SMF_ALL; + + thiz->AddRef = IDirectFBSurface_AddRef; + thiz->Release = IDirectFBSurface_Release; + + thiz->GetCapabilities = IDirectFBSurface_GetCapabilities; + thiz->GetPosition = IDirectFBSurface_GetPosition; + thiz->GetSize = IDirectFBSurface_GetSize; + thiz->GetVisibleRectangle = IDirectFBSurface_GetVisibleRectangle; + thiz->GetPixelFormat = IDirectFBSurface_GetPixelFormat; + thiz->GetAccelerationMask = IDirectFBSurface_GetAccelerationMask; + + thiz->GetPalette = IDirectFBSurface_GetPalette; + thiz->SetPalette = IDirectFBSurface_SetPalette; + thiz->SetAlphaRamp = IDirectFBSurface_SetAlphaRamp; + + thiz->Lock = IDirectFBSurface_Lock; + thiz->GetFramebufferOffset = IDirectFBSurface_GetFramebufferOffset; + thiz->Unlock = IDirectFBSurface_Unlock; + thiz->Flip = IDirectFBSurface_Flip; + thiz->SetField = IDirectFBSurface_SetField; + thiz->Clear = IDirectFBSurface_Clear; + + thiz->SetClip = IDirectFBSurface_SetClip; + thiz->GetClip = IDirectFBSurface_GetClip; + thiz->SetColor = IDirectFBSurface_SetColor; + thiz->SetColorIndex = IDirectFBSurface_SetColorIndex; + thiz->SetSrcBlendFunction = IDirectFBSurface_SetSrcBlendFunction; + thiz->SetDstBlendFunction = IDirectFBSurface_SetDstBlendFunction; + thiz->SetPorterDuff = IDirectFBSurface_SetPorterDuff; + thiz->SetSrcColorKey = IDirectFBSurface_SetSrcColorKey; + thiz->SetSrcColorKeyIndex = IDirectFBSurface_SetSrcColorKeyIndex; + thiz->SetDstColorKey = IDirectFBSurface_SetDstColorKey; + thiz->SetDstColorKeyIndex = IDirectFBSurface_SetDstColorKeyIndex; + thiz->SetIndexTranslation = IDirectFBSurface_SetIndexTranslation; + + thiz->SetBlittingFlags = IDirectFBSurface_SetBlittingFlags; + thiz->Blit = IDirectFBSurface_Blit; + thiz->TileBlit = IDirectFBSurface_TileBlit; + thiz->BatchBlit = IDirectFBSurface_BatchBlit; + thiz->StretchBlit = IDirectFBSurface_StretchBlit; + thiz->TextureTriangles = IDirectFBSurface_TextureTriangles; + + thiz->SetDrawingFlags = IDirectFBSurface_SetDrawingFlags; + thiz->FillRectangle = IDirectFBSurface_FillRectangle; + thiz->DrawLine = IDirectFBSurface_DrawLine; + thiz->DrawLines = IDirectFBSurface_DrawLines; + thiz->DrawRectangle = IDirectFBSurface_DrawRectangle; + thiz->FillTriangle = IDirectFBSurface_FillTriangle; + thiz->FillRectangles = IDirectFBSurface_FillRectangles; + thiz->FillSpans = IDirectFBSurface_FillSpans; + thiz->FillTriangles = IDirectFBSurface_FillTriangles; + + thiz->SetFont = IDirectFBSurface_SetFont; + thiz->GetFont = IDirectFBSurface_GetFont; + thiz->DrawString = IDirectFBSurface_DrawString; + thiz->DrawGlyph = IDirectFBSurface_DrawGlyph; + thiz->SetEncoding = IDirectFBSurface_SetEncoding; + + thiz->GetSubSurface = IDirectFBSurface_GetSubSurface; + + thiz->GetGL = IDirectFBSurface_GetGL; + + thiz->Dump = IDirectFBSurface_Dump; + thiz->DisableAcceleration = IDirectFBSurface_DisableAcceleration; + thiz->ReleaseSource = IDirectFBSurface_ReleaseSource; + + thiz->SetRenderOptions = IDirectFBSurface_SetRenderOptions; + thiz->SetMatrix = IDirectFBSurface_SetMatrix; + thiz->SetSourceMask = IDirectFBSurface_SetSourceMask; + + thiz->MakeSubSurface = IDirectFBSurface_MakeSubSurface; + + thiz->Write = IDirectFBSurface_Write; + thiz->Read = IDirectFBSurface_Read; + + thiz->SetColors = IDirectFBSurface_SetColors; + + dfb_surface_attach( surface, + IDirectFBSurface_listener, thiz, &data->reaction ); + + return DFB_OK; +} + + +/* internal */ + +static ReactionResult +IDirectFBSurface_listener( const void *msg_data, void *ctx ) +{ + const CoreSurfaceNotification *notification = msg_data; + IDirectFBSurface *thiz = ctx; + IDirectFBSurface_data *data = thiz->priv; + CoreSurface *surface = data->surface; + + D_DEBUG_AT( Surface, "%s( %p, %p )\n", __FUNCTION__, msg_data, ctx ); + + if (notification->flags & CSNF_DESTROY) { + if (data->surface) { + data->surface = NULL; + dfb_surface_unref( surface ); + } + return RS_REMOVE; + } + + if (notification->flags & CSNF_SIZEFORMAT) { + DFBRectangle rect = { 0, 0, surface->config.size.w, surface->config.size.h }; + + dfb_rectangle_subtract( &rect, &data->area.insets ); + + if (data->limit_set) { + data->area.current = data->area.granted; + + dfb_rectangle_intersect( &data->area.current, &rect ); + } + else + data->area.wanted = data->area.granted = data->area.current = rect; + + /* Reset clip to avoid crashes caused by drawing out of bounds. */ + if (data->clip_set) + thiz->SetClip( thiz, &data->clip_wanted ); + else + thiz->SetClip( thiz, NULL ); + } + + return RS_OK; +} + +void +IDirectFBSurface_StopAll( IDirectFBSurface_data *data ) +{ + if (!dfb_config->startstop) + return; + + if (data->children_data) { + IDirectFBSurface_data *child; + + pthread_mutex_lock( &data->children_lock ); + + direct_list_foreach (child, data->children_data) + IDirectFBSurface_StopAll( child ); + + pthread_mutex_unlock( &data->children_lock ); + } + + /* Signal end of sequence of operations. */ + dfb_state_lock( &data->state ); + dfb_state_stop_drawing( &data->state ); + dfb_state_unlock( &data->state ); +} + -- cgit