/**
 * @file  BCGraphicsDeviceDirectFB.cpp
 *
 * AstroNav TQTVD Implementation of BCGraphicsDeviceDirectFB class.
 *
 */

#include "BCGraphicsDeviceDirectFB.h"
#include "BCNativeImageDirectFB.h"
#include "BIWindow.h"
#include <graphics/IntPoint.h>
#include <graphics/IntRect.h>
#include <graphics/IntSize.h>
#include "BTWidget.h"
#include "BTScrollView.h"
#include "BIMath.h"	/* M_PI */
#include <graphics/Color.h>


IMPLEMENT_GET_DELETE(BIGraphicsDevice, BCGraphicsDeviceDirectFB);


#define GET_NATIVE(image) ((static_cast<const BCNativeImage*>(image))->getNativeDirectFB())


namespace BAL {

BCGraphicsDeviceDirectFB::BCGraphicsDeviceDirectFB() 
{
	m_directfb = NULL;
	m_screen = NULL;
	m_ownDfb = m_ownScreen = m_screenLessMode = false;
	m_width = 0;
	m_height = 0;
	m_depth = 0;
	m_listeners = 0;
	m_backgroundColor = WebCore::Color::transparent;

	pthread_mutex_init(&m_listenersMutex, NULL);

}

BCGraphicsDeviceDirectFB::~BCGraphicsDeviceDirectFB()
{
	finalize();
}

void BCGraphicsDeviceDirectFB::initialize(uint16_t width, uint16_t height, uint8_t depth)
{
    // setSuperInterface() will create directFB if necessary  (this allows previous setting)
    if (!m_directfb)
		setSuperInterface ( m_directfb );

    if (m_directfb)
    {	
        // restricao INTEL: 32 nao da erro mas fica tela preta, 
        // menor que 32 da erro mas passa.
        // restricao ST: também passou a dar erro neste SetVideoMode

        DFBResult err = m_directfb->SetVideoMode( m_directfb, width, height, depth );
        if ( err != DFB_OK)
        {
            DirectFBError( "Failed switching the current video mode.", err );
        }

		m_width = width;
		m_height = height;
		m_depth = depth;
    }

	// setPrimarySurface() will create screen if necessary   (this allows previous setting)
	if (!m_screenLessMode && !m_screen)
		setPrimarySurface ( m_screen );


}

void BCGraphicsDeviceDirectFB::finalize()
{
	if ((NULL != m_directfb))
	{
	     if ( m_ownDfb )
	     {
	   	     m_directfb->Release(m_directfb);
			 m_ownDfb = false;
	     }
		 m_directfb = NULL;

		 if (!m_screenLessMode && m_ownScreen)
		 {
			m_screen->Release(m_screen);
			m_ownScreen = false;
		 }
		 m_screen = NULL;
	}
}

void BCGraphicsDeviceDirectFB::setScreenLessMode(bool mode)
{
	m_screenLessMode = mode;
}


void *BCGraphicsDeviceDirectFB::setSuperInterface (void* dfb)
{
   if (NULL != dfb)
   {
      m_directfb = (IDirectFB *) dfb;
	  m_ownDfb = false;
   }
   else
   {
        DFBCooperativeLevel level = DFSCL_FULLSCREEN;
        DFBResult err;

        err = DirectFBInit( NULL, NULL );
        if (err != DFB_OK)
        {
           DirectFBError( "Failed initializing DirectFB.", err );
           m_directfb = NULL;
        }
        else
        {
           err = DirectFBCreate( &m_directfb );
           if (err != DFB_OK)
           {
               DirectFBError( "Failed creating *super* interface IDirectFB.", err );
               m_directfb = NULL;
           }
           else
           {
               err = m_directfb->SetCooperativeLevel( m_directfb, level );
               if (err != DFB_OK)
               {
                   DirectFBError( "Failed requesting cooperative access.", err );
                   m_directfb = NULL;
               }
           }
        }

        m_ownDfb = true;

   }

   return m_directfb;

}


void *BCGraphicsDeviceDirectFB::setPrimarySurface (void* ps)
{
    if (!m_screenLessMode)
    {
	    if (NULL != ps)
	    {
			m_screen = (IDirectFBSurface *) ps;
			m_ownScreen = false;
	    }
		else
		{
		    if (m_directfb)
		    {
				DFBResult err = DFB_OK;
				IDirectFBSurface* surface = NULL;
				DFBSurfaceDescription dsc;

// DSDESC_WIDTH | DSDESC_HEIGHT : nao da erro mas fica tela preta
// DSCAPS_FLIPPING : primary.c:primaryFlipRegion:1845: gdl_flip() returned GDL_ERR_SURFACE, surface id:2
// DSCAPS_PREMULTIPLIED :  (#) DirectFBError [Failed creating primary surface]: Not supported!

//				dsc.flags  = (DFBSurfaceDescriptionFlags) ( DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_CAPS | DSDESC_PIXELFORMAT );
				dsc.flags  = (DFBSurfaceDescriptionFlags) ( DSDESC_CAPS );
				dsc.width  = m_width;
				dsc.height = m_height;
//                dsc.caps   = (DFBSurfaceCapabilities)( DSCAPS_PRIMARY | DSCAPS_FLIPPING | DSCAPS_PREMULTIPLIED );
                dsc.caps   = (DFBSurfaceCapabilities)( DSCAPS_PRIMARY );
				dsc.pixelformat = DSPF_ARGB;

				err = m_directfb->CreateSurface( m_directfb, &dsc, &surface );
				if (err != DFB_OK)
				{
					DirectFBError( "Failed creating primary surface", err );
					return NULL;
				}

				surface->Clear( surface, 0x00, 0x00, 0x00, 0x00 ); /* (transparente) 0 < alphaChannel < 255 (sólido) */

				surface->SetDrawingFlags( surface, DSDRAW_BLEND );
				surface->SetBlittingFlags( surface, DSBLIT_BLEND_ALPHACHANNEL);

				m_screen = surface;

				m_ownScreen = true;

		    }

		}
    }

    return m_screen;
}



BINativeImage* BCGraphicsDeviceDirectFB::createNativeImage(const WebCore::IntSize size)
{
	DFBResult err = DFB_OK;
	IDirectFBSurface* surface = NULL;
	DFBSurfaceDescription dsc;


	if (m_directfb && size.width() && size.height())
	{
		dsc.flags = (DFBSurfaceDescriptionFlags) ( DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_CAPS | DSDESC_PIXELFORMAT );
		dsc.caps =	(DFBSurfaceCapabilities) (  DSCAPS_PREMULTIPLIED );

		dsc.width = size.width();
		dsc.height = size.height();
		dsc.pixelformat = DSPF_ARGB;

		err = m_directfb->CreateSurface( m_directfb, &dsc, &surface );
		if (err != DFB_OK)
		{
			DirectFBError( "Failed creating native image surface", err );
		}
		else if (surface)
		{
			surface->Clear( surface, 0xFF, 0xFF, 0xFF, 0 ); /* (transparente) 0 < alphaChannel < 255 (sólido) */
//			surface->SetDrawingFlags( surface, (DFBSurfaceDrawingFlags)( DSDRAW_SRC_PREMULTIPLY | DSDRAW_BLEND ) );
			surface->SetDrawingFlags( surface, DSDRAW_BLEND );
			surface->SetBlittingFlags( surface, DSBLIT_BLEND_ALPHACHANNEL);


			//printf("createNativeImage (%d, %d)\n",size.width() , size.height());

			return new BCNativeImage(surface);
		}

	}
	return NULL;




}

BINativeImage* BCGraphicsDeviceDirectFB::createNativeImage(RGBA32Array& array, const WebCore::IntSize size)
{
	DFBResult err;
	DFBSurfaceDescription dsc;
	DFBGraphicsDeviceDescription gdesc;
	IDirectFBSurface* surface = NULL;

	m_directfb->GetDeviceDescription( m_directfb, &gdesc );

	dsc.flags = (DFBSurfaceDescriptionFlags) ( DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_CAPS | DSDESC_PIXELFORMAT );
	dsc.width = size.width();
	dsc.height = size.height();
	dsc.caps = (DFBSurfaceCapabilities) ( (gdesc.drawing_flags & DSDRAW_BLEND) ?
		0 | DSCAPS_PREMULTIPLIED :
		0 | DSCAPS_PREMULTIPLIED | DSCAPS_SYSTEMONLY);
	dsc.pixelformat= DSPF_ARGB;

	err = m_directfb->CreateSurface( m_directfb, &dsc, &surface );
	if (err != DFB_OK)
	{
		DirectFBError( "Failed creating secondary surface", err );
	}

	// FIXME should redraw with background color
	// i.e. transparent for transparent pages
	surface->Clear( surface, 0xFF, 0xFF, 0xFF, 0 ); /* (transparente) 0 < alpha < 255 (sólido) */
	// blend
	surface->SetDrawingFlags( surface, DSDRAW_BLEND );
	// alpha
	surface->SetBlittingFlags( surface, DSBLIT_BLEND_ALPHACHANNEL);

	int x=0, y=0 ;
	for (unsigned pix=0; pix<array.size(); pix++)
	{
		int alpha = ( array[pix] & 0xff000000 ) >> 24;
		int red   = ( array[pix] & 0x00ff0000 ) >> 16;
		int green = ( array[pix] & 0x0000ff00 ) >> 8;
		int blue  = ( array[pix] & 0x000000ff ) ;

// printf("pixel %03d is %08x, cor (%03d,%03d,%03d,%03d), pos(%03d,%03d)\n", pix, array[pix], red, green, blue, alpha, x, y);

		if (alpha !=  0)
		{
			surface->SetColor (surface, red, green, blue, alpha);
			surface->FillRectangle (surface, x, y, 1, 1);
		}
		if (++x == size.width())
		{
			y++;
			x =0;
		}
	}

	return new BCNativeImage(surface, &array);

}

void BCGraphicsDeviceDirectFB::copy(const BTWidget& widget, const BINativeImage& image, WebCore::IntRect zone, WebCore::IntPoint point, const uint8_t alphaChannel)
{
	if (!widget.backingStore())
		return;

	DFBResult err;
	DFBRectangle source_rect = { zone.x(), zone.y(), zone.width(), zone.height() };
	IDirectFBSurface* surface = GET_NATIVE(widget.backingStore());

	if (alphaChannel != 255)
	{
		IDirectFBSurface *surfaceWithAlpha = applyTransparency(image, alphaChannel);

		err = surface->Blit( surface, surfaceWithAlpha, &source_rect, point.x(),  point.y() );
		if (err != DFB_OK)
		{
			 DirectFBError( "Failed copying surface with alpha.", err );
		}
		surfaceWithAlpha->Release( surfaceWithAlpha );
	}
	else
	{
		err = surface->Blit( surface, GET_NATIVE(&image), &source_rect, point.x(),  point.y() );
		if (err != DFB_OK)
		{
			 DirectFBError( "Failed copying surface without alpha.", err );
		}
	}


}


void BCGraphicsDeviceDirectFB::drawArc(const BTWidget& widget, const WebCore::IntRect rect, uint16_t startAngle, uint16_t angleSpan, const WebCore::Color color)
{
	if (color.alpha() == 0 || !widget.backingStore() || rect.isEmpty())
		return;

	//
	//		  |y		  (This diagram is supposed to be a circle).
	//		  |
	//		 ...
	// z=1 .  |  . z=0		We know that there are 360 degrees in a circle. First we
	//	 .	  |    .		see that a circle is symetrical about the x axis, so
	//	.	  | 	.		only the first 180 degrees need to be calculated. Next
	//--.-----+-----.-- 	we see that it's also symetrical about the y axis, so now
	//	.	  | 	. x 	we only need to calculate the first 90 degrees.
	//	 .	  |    .		Each 90Â° region is associated to a zone (z value). Zone where
	// z=2 .  |  . z=3		we will draw is defined from startAngle and angleSpan.
	//		 ...			Thus after coord computation, we draw in the zone(s).
	//		  | 			Note: 0 <= alpha0, alpha1 <= 90
	//		  |

	int r = (rect.width() - 1) / 2;
	int xc = rect.x() + r;
	int yc = rect.y() + (rect.height() - 1)/ 2;
	int z0 = startAngle / 90;
	int z1 = (startAngle + angleSpan) / 90;
	int alpha0 = startAngle % 90;
	float xalpha0 = r * cosf((alpha0 * M_PI / 180));
	int alpha1 = (startAngle + angleSpan) % 90;
	float xalpha1 = r * cosf((alpha1 * M_PI / 180));

	float x0, y0, x1, y1;

	if (z0 == z1) {
		// Draw in the same zone from angle = z0 * 90 + alpha0 to angle = z0 * 90 + alpha1
		x0 = xalpha0;
		y0 = sqrt(pow(r, 2) - pow(x0, 2));
		for (x1 = xalpha0; x1 >= xalpha1; x1--) {
			y1 = sqrt(pow(r, 2) - pow(x1, 2));
			drawArc(widget, color, z0, xc, yc, x0, y0, x1, y1);
		}
	} else if ((z1 - z0) == 1) {
		// Begin to draw in zone Z and end in zone Z + 1
		if (alpha1 < alpha0) {
			// Draw from angle = z1 * 90 to angle = z1 * 90 + alpha1
			// Then from angle = z0 * 90 + alpha0 to angle = z1 * 90
			x0 = r;
			y0 = 0;
			for (x1 = r; x1 >= xalpha1; x1--) {
				y1 = sqrt(pow(r, 2) - pow(x1, 2));
				drawArc(widget, color, z1, xc, yc, x0, y0, x1, y1);
			}
			x0 = xalpha0;
			y0 = sqrt(pow(r, 2) - pow(x0, 2));
			for (x1 = xalpha0; x1 >= 0; x1--) {
				y1 = sqrt(pow(r, 2) - pow(x1, 2));
				drawArc(widget, color, z0, xc, yc, x0, y0, x1, y1);
			}
		} else {
			// Compute a complete quarter of circle.
			// Draw in zone1 from 0 to alpha0
			// Draw in zone0 and zone1 from alpha0 to alpha1
			// Draw in zone0 from alpha1 to 90
			x0 = r;
			y0 = 0;
			for (x1 = r; x1 >= 0; x1--) {
				y1 = sqrt(pow(r, 2) - pow(x1, 2));
				if (x1 < xalpha1)
					drawArc(widget, color, z0, xc, yc, x0, y0, x1, y1);
				else if (x1 > xalpha0)
					drawArc(widget, color, z1, xc, yc, x0, y0, x1, y1);
				else {
					drawArc(widget, color, z0, xc, yc, x0, y0, x1, y1, false);
					drawArc(widget, color, z1, xc, yc, x0, y0, x1, y1);
				}
			}
		}
	} else {
		// Draw at least a complete quarter of circle and probably many more
		x0 = r;
		y0 = 0;
		for (x1 = r; x1 >= 0; x1--) {
			y1 = sqrt(pow(r, 2) - pow(x1, 2));
			if ((z1 - z0) >= 3)
				drawArc(widget, color, z1 - 2, xc, yc, x0, y0, x1, y1, false);
			if (x1 < xalpha1)
				drawArc(widget, color, z1 % 3, xc, yc, x0, y0, x1, y1, false);
			if (x1 < xalpha0)
				drawArc(widget, color, z0, xc, yc, x0, y0, x1, y1, false);
			drawArc(widget, color, z1 - 1, xc, yc, x0, y0, x1, y1);
		}
	}
}



void BCGraphicsDeviceDirectFB::drawEllipse(const BTWidget& widget, WebCore::IntRect rect, const WebCore::Color color)
{
	if (color.alpha() == 0 || !widget.backingStore() || rect.isEmpty())
		return;

	// Dado um retângulo, desenhar a elipse que circunscreve este retângulo.
}


void BCGraphicsDeviceDirectFB::drawLine(const BTWidget& widget, WebCore::IntPoint p1, WebCore::IntPoint p2, const WebCore::Color color)
{
	if (color.alpha() == 0 || !widget.backingStore())
		return;

	IDirectFBSurface * surface = GET_NATIVE(widget.backingStore());

	surface->SetColor ( surface, color.red(), color.green(), color.blue(), color.alpha());
	surface->DrawLine( surface, p1.x(), p1.y(),  p2.x(), p2.y() );
}

void BCGraphicsDeviceDirectFB::drawRect(const BTWidget& widget, WebCore::IntRect rect, const WebCore::Color color)
{
	if (color.alpha() == 0 || !widget.backingStore() || rect.isEmpty())
		return;

	IDirectFBSurface * surface = GET_NATIVE(widget.backingStore());

	surface->SetColor( surface, color.red(), color.green(), color.blue(), color.alpha());
	surface->DrawRectangle( surface, rect.x(), rect.y(),  rect.width(),  rect.height() );
}

void BCGraphicsDeviceDirectFB::fillConvexPolygon(const BTWidget& widget, size_t npoints, const WebCore::IntPoint* points, const WebCore::Color color)
{
	if (color.alpha() == 0 || !widget.backingStore() ||(npoints <= 1))
		return;

	IDirectFBSurface * surface = GET_NATIVE(widget.backingStore());
	DFBRegion * lines = new DFBRegion[npoints];
		lines[0].x1 = static_cast<int>(points[npoints-1].x());
		lines[0].y1 = static_cast<int>(points[npoints-1].y());
		lines[0].x2 = static_cast<int>(points[0].x());
		lines[0].y2 = static_cast<int>(points[0].y());

	for(unsigned int i=1; i<npoints; i++) {
		lines[i].x1 = static_cast<int>(points[i-1].x());
		lines[i].y1 = static_cast<int>(points[i-1].y());
		lines[i].x2 = static_cast<int>(points[i].x());
		lines[i].y2 = static_cast<int>(points[i].y());

	}

	surface->SetColor( surface, color.red(), color.green(), color.blue(), color.alpha());
	surface->DrawLines( surface, lines, npoints );
	delete[] lines;
}

void BCGraphicsDeviceDirectFB::fillRect(const BTWidget& widget, WebCore::IntRect rect, const WebCore::Color color)
{
	if (color.alpha() == 0 || !widget.backingStore() || rect.isEmpty())
		return;

	IDirectFBSurface* surface = GET_NATIVE(widget.backingStore());

	surface->SetColor( surface, color.red(), color.green(), color.blue(), color.alpha());
	surface->FillRectangle( surface, rect.x(), rect.y(),  rect.width(),  rect.height() );

}

void BCGraphicsDeviceDirectFB::setClip(const BTWidget& widget, WebCore::IntRect rect)
{
	if (!widget.backingStore())
		return;

	IDirectFBSurface * surface = GET_NATIVE(widget.backingStore());

	if (rect.isEmpty())
	{
		surface->SetClip( surface, NULL);
	}
	else
	{
		const DFBRegion region = { rect.x(), rect.y(), rect.x()+rect.width(), rect.y()+rect.height() };

		surface->SetClip( surface, &region );
	}
}

WebCore::IntRect BCGraphicsDeviceDirectFB::clip(const BTWidget& widget)
{
	if (!widget.backingStore())
		return WebCore::IntRect(0,0,0,0);

	DFBRegion ret_clip;
	IDirectFBSurface * surface = GET_NATIVE(widget.backingStore());

	surface->GetClip( surface, &ret_clip );
	WebCore::IntRect rect(ret_clip.x1, ret_clip.y1, ret_clip.x2-ret_clip.x1, ret_clip.y2-ret_clip.y1);

	return rect;
}

void BCGraphicsDeviceDirectFB::stretchBlit(const BTWidget& widget, const BINativeImage& nativeImage, WebCore::IntRect src, WebCore::IntRect dst, const uint8_t alphaChannel)
{
	DFBRectangle _src = { src.x(), src.y(), src.width(), src.height() };
	DFBRectangle _dst = { dst.x(), dst.y(), dst.width(), dst.height() };

	IDirectFBSurface* surface = GET_NATIVE(widget.backingStore());
	surface->StretchBlit( surface, GET_NATIVE(&nativeImage), &_src, &_dst);
}

WebCore::IntSize BCGraphicsDeviceDirectFB::size() const
{
#ifndef NDEBUG
	if (m_layoutTests)
		return WebCore::IntSize(800, 600); // fixed for layout tests
#endif
	int ret_width, ret_height;

	if(m_screenLessMode)
	{
		ret_width = m_width;
		ret_height = m_height;
	}
	else
	{
		m_screen->GetSize( m_screen, &ret_width, &ret_height );
	}

	return IntSize(ret_width, ret_height);
}


void BCGraphicsDeviceDirectFB::update(const BTWidget& widget, const WebCore::IntRect rect)
{
	DFBResult err;

#ifndef NDEBUG
	if (m_layoutTests)
		return;
#endif

	if (!widget.backingStore() || rect.isEmpty())
		return;

	int updateX = widget.x() + rect.x();
	int updateY = widget.y() + rect.y();
	int updateWLimit = updateX + rect.width();
	int updateHLimit = updateY + rect.height();

	if ((updateX > m_width) || (updateY > m_height))
	{
		//printf("BCGraphicsDeviceDirectFB::update Discarding update outside screen\n");
		return;
	}

	if (updateWLimit > m_width)
	{
	   updateWLimit = m_width;
	}

    if (updateHLimit > m_height)
    {
	    updateHLimit = m_height;
    }


#if 0
	printf("\n=========\n");
	printf("BCGraphicsDeviceDirectFB::update widget is x,y,w,h is (%d,%d,%d,%d)\n", widget.x(), widget.y(), widget.width(), widget.height());
	printf("BCGraphicsDeviceDirectFB::update widget srcRect is (%d,%d,%d,%d)\n", updateX, updateY, updateWLimit - updateX, updateHLimit - updateY);
	printf("BCGraphicsDeviceDirectFB::update screen w,h is (%d,%d)\n", m_width, m_height);
	printf("=========\n\n");
#endif


    if (!m_screenLessMode)
    {
		DFBRectangle dfbSrcRect = { rect.x(), rect.y(), rect.width(), rect.height() };
		DFBRegion dfbRegion =  { updateX,  updateY, updateWLimit, updateHLimit };

		err = m_screen->Blit( m_screen, 
			                  ((BCNativeImage *)(widget.backingStore()))->getNativeDirectFB(),
			                  &dfbSrcRect, updateX, updateY );
		if (err != DFB_OK)
		{
			 DirectFBError( "Failed blitting to the the primary surface", err );
		}

	    if (m_ownScreen)
	    {
			err = m_screen->Flip( m_screen, &dfbRegion,
				                 (DFBSurfaceFlipFlags) (DSFLIP_BLIT | DSFLIP_WAITFORSYNC) );
			if (err != DFB_OK)
			{
				 DirectFBError( "Failed flipping the primary surface", err );
			}
		}
	}


	pthread_mutex_lock(&m_listenersMutex);

    for (int l = 0; l < m_listeners; ++l)
    {
        BIListener *listener = m_listenerMap[l];
        BIWindow* window = (BIWindow*)listener->getWindow();

		if (window->widget() == &widget)
		{
 	     	listener->update(((BCNativeImage *)(widget.backingStore()))->getNativeDirectFB(),
 	   	                   WebCore::IntRect( rect.x(),  rect.y(), rect.width(), rect.height()),			   	
 	   	                   WebCore::IntRect( updateX,  updateY, updateWLimit - updateX, updateHLimit - updateY));
		    break;
		}	
    }

	pthread_mutex_unlock(&m_listenersMutex);


}


void BCGraphicsDeviceDirectFB::clear(const BTWidget& widget, const WebCore::IntRect rect)
{
	if (!widget.backingStore() || rect.isEmpty())
		return;

	Color bgcolor(m_backgroundColor);
	fillRect( widget, rect, bgcolor );
}

inline void BCGraphicsDeviceDirectFB::drawArc(const BTWidget& widget, const WebCore::Color color, int zone, int xc, int yc, float& x0, float& y0, float x1, float y1, bool doSwap)
{
}

IDirectFBSurface* BCGraphicsDeviceDirectFB::applyTransparency(const BINativeImage& image, const uint8_t alphaChannel)
{

	DFBResult err;
	DFBSurfaceDescription dsc;
	DFBGraphicsDeviceDescription gdesc;
	IDirectFBSurface* surface = NULL;
	int width=0, height=0;

	m_directfb->GetDeviceDescription( m_directfb, &gdesc );
	GET_NATIVE(&image)->GetSize(  GET_NATIVE(&image), &width, &height );

	dsc.flags = (DFBSurfaceDescriptionFlags) ( DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_CAPS | DSDESC_PIXELFORMAT );
	dsc.width = width;
	dsc.height = height;
	dsc.caps = (DFBSurfaceCapabilities) ( (gdesc.drawing_flags & DSDRAW_BLEND) ?
		0 | DSCAPS_PREMULTIPLIED :
		0 | DSCAPS_PREMULTIPLIED | DSCAPS_SYSTEMONLY );
	dsc.pixelformat= DSPF_ARGB;

	err = m_directfb->CreateSurface( m_directfb, &dsc, &surface );
	if (err != DFB_OK)
	{
		DirectFBError( "Failed creating another surface to apply transparency", err );
	}

	// FIXME should redraw with background color
	// i.e. transparent for transparent pages
	surface->Clear( surface, 0xFF, 0xFF, 0xFF, alphaChannel ); /* (transparente) 0 < alphaChannel < 255 (sólido) */
	// blend
//	surface->SetDrawingFlags (surface, (DFBSurfaceDrawingFlags)(DSDRAW_SRC_PREMULTIPLY | DSDRAW_BLEND));
	surface->SetDrawingFlags (surface, DSDRAW_BLEND );
	// alpha
	surface->SetBlittingFlags( surface, DSBLIT_BLEND_ALPHACHANNEL);
	err = surface->Blit( surface, GET_NATIVE(&image), NULL, 0, 0 );
	if (err != DFB_OK)
	{
		DirectFBError( "Failed blitting the secondary surface", err );
	}

	return surface;
}

void BCGraphicsDeviceDirectFB::setBackgroundColor(WebCore::RGBA32 color)
{
    m_backgroundColor = color;
}

WebCore::RGBA32 BCGraphicsDeviceDirectFB::getBackgroundColor(void)
{
    return m_backgroundColor;
}

void BCGraphicsDeviceDirectFB::addUpdateListener(BIListener* listener)
{

	pthread_mutex_lock(&m_listenersMutex);
	m_listenerMap[m_listeners++] = listener;
	pthread_mutex_unlock(&m_listenersMutex);
}

void BCGraphicsDeviceDirectFB::removeUpdateListener(BIListener* listener)
{


   pthread_mutex_lock(&m_listenersMutex);

   for(int l = 0; l < m_listeners; ++l)
   {
	   	if (m_listenerMap[l] == listener)
	   	{
	   	    m_listenerMap[l] = m_listenerMap[--m_listeners];
			break;
	   	}
   }

   pthread_mutex_unlock(&m_listenersMutex);

}


} // namespace BAL
