#include "evas_engine_dfb.h"
#include <math.h>
#include <string.h>

Evas_Func           evas_engine_directfb_func = {
   evas_engine_directfb_info,
   evas_engine_directfb_info_free,
   evas_engine_directfb_setup,
   evas_engine_directfb_output_free,
   evas_engine_directfb_output_resize,
   evas_engine_directfb_output_tile_size_set,
   evas_engine_directfb_output_redraws_rect_add,
   evas_engine_directfb_output_redraws_rect_del,
   evas_engine_directfb_output_redraws_clear,
   evas_engine_directfb_output_redraws_next_update_get,
   evas_engine_directfb_output_redraws_next_update_push,
   evas_engine_directfb_output_flush,
   /* draw context virtual methods */
   evas_engine_directfb_context_new,
   evas_engine_directfb_context_free,
   evas_engine_directfb_context_clip_set,
   evas_engine_directfb_context_clip_clip,
   evas_engine_directfb_context_clip_unset,
   evas_engine_directfb_context_clip_get,
   evas_engine_directfb_context_color_set,
   evas_engine_directfb_context_color_get,
   evas_engine_directfb_context_multiplier_set,
   evas_engine_directfb_context_multiplier_unset,
   evas_engine_directfb_context_multiplier_get,
   evas_engine_directfb_context_cutout_add,
   evas_engine_directfb_context_cutout_clear,
   /* rectangle draw funcs */
   evas_engine_directfb_draw_rectangle,
   /* line draw funcs */
   evas_engine_directfb_line_draw,
   /* poly draw funcs */
   evas_engine_directfb_polygon_point_add,
   evas_engine_directfb_polygon_points_clear,
   evas_engine_directfb_polygon_draw,
   /* gardient draw funcs */
   evas_engine_directfb_gradient_color_add,
   evas_engine_directfb_gradient_colors_clear,
   evas_engine_directfb_gradient_draw,
   /* image draw funcs */
   evas_engine_directfb_image_load,
   evas_engine_directfb_image_new_from_data,
   evas_engine_directfb_image_new_from_copied_data,
   evas_engine_directfb_image_free,
   evas_engine_directfb_image_size_get,
   evas_engine_directfb_image_size_set,
   evas_engine_directfb_image_dirty_region,
   evas_engine_directfb_image_data_get,
   evas_engine_directfb_image_data_put,
   evas_engine_directfb_image_alpha_set,
   evas_engine_directfb_image_alpha_get,
   evas_engine_directfb_image_draw,
   evas_engine_directfb_image_comment_get,
   evas_engine_directfb_image_format_get,

   evas_engine_directfb_image_cache_flush,
   evas_engine_directfb_image_cache_set,
   evas_engine_directfb_image_cache_get,
   /* more to come */
   evas_engine_directfb_font_load,
   evas_engine_directfb_font_memory_load,
   evas_engine_directfb_font_free,
   evas_engine_directfb_font_ascent_get,
   evas_engine_directfb_font_descent_get,
   evas_engine_directfb_font_max_ascent_get,
   evas_engine_directfb_font_max_descent_get,
   evas_engine_directfb_font_string_size_get,
   evas_engine_directfb_font_inset_get,
   evas_engine_directfb_font_h_advance_get,
   evas_engine_directfb_font_v_advance_get,
   evas_engine_directfb_font_char_coords_get,
   evas_engine_directfb_font_char_at_coords_get,
   evas_engine_directfb_font_draw,
   /* font cache functions */
   evas_engine_directfb_font_cache_flush,
   evas_engine_directfb_font_cache_set,
   evas_engine_directfb_font_cache_get
};


   
void        *
evas_engine_directfb_info(Evas * e)
{
   Evas_Engine_Info_DirectFB *info;

   info = calloc(1, sizeof(Evas_Engine_Info_DirectFB));
   if (!info)
      return NULL;

   info->magic.magic = rand();

   return info;
   e = NULL;
}

void
evas_engine_directfb_info_free(Evas *e, void *info)
{
   Evas_Engine_Info_DirectFB *in;
   
   in = (Evas_Engine_Info_DirectFB *)info;
   free(in);
}

void
evas_engine_directfb_setup(Evas * e, void *in)
{
   Evas_Engine_Info_DirectFB *info;
   IDirectFBImageProvider *provider;

   info = (Evas_Engine_Info_DirectFB *) in;
   /* if we arent set to directfb, why the hell do we get called?! */
   if (evas_output_method_get(e) != RENDER_METHOD_DIRECTFB)
      return;
   /* lets just set up */
   e->engine.data.output = evas_engine_directfb_output_setup(e->output.w,
							     e->output.h,
							     info->info.dfb,
							     info->info.surface,
							     info->info.flags);
   if (!e->engine.data.output)
      return;
   e->engine.func = &evas_engine_directfb_func;
   e->engine.data.context = e->engine.func->context_new(e->engine.data.output);
}

void        *
evas_engine_directfb_output_setup(int w, int h, IDirectFB * dfb,
				  IDirectFBSurface * surf,
				  DFBSurfaceDrawingFlags flags)
{
   Render_Engine      *re;
   IDirectFBSurface   *buf;
   DFBSurfaceDescription dsc;
   RGBA_Image *im;

   re = calloc(1, sizeof(Render_Engine));
   /* if we haven't initialized - init (automatic abort if already done) */
   evas_common_cpu_init();
   evas_common_blend_init();
   evas_common_image_init();
   evas_common_convert_init();
   evas_common_scale_init();
   evas_common_rectangle_init();
   evas_common_gradient_init();
   evas_common_polygon_init();
   evas_common_line_init();
   evas_common_font_init();
   evas_common_draw_init();
   evas_common_tilebuf_init();

   re->tb = evas_common_tilebuf_new(w, h);
   /* in preliminary tests 16x16 gave highest framerates */
   evas_common_tilebuf_set_tile_size(re->tb, 16, 16);
   re->dfb = dfb;
   re->surface = surf;

   memset(&dsc, 0, sizeof(DFBSurfaceDescription));
   dsc.flags = DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT;
   dsc.width = w;
   dsc.height = h;
   dsc.pixelformat = DSPF_ARGB;

   if (dfb->CreateSurface(dfb, &dsc, &buf) == DFB_OK)
      re->backbuf = buf;
   if (!buf)
     {
	printf("DFB engine: cannot create backbuf\n");
	exit(-1);
     }
   /* FIXME else exit with error. */

   re->backbuf->SetDrawingFlags(re->backbuf, flags);

   /* We create a "fake" RGBA_Image which points the to DFB surface. Each access 
    * to that surface is wrapped in Lock / Unlock calls whenever the data is
    * manipulated directly. */
   im = evas_common_image_new();
   if (!im) return;
   im->image = evas_common_image_surface_new();
   if (!im->image) 
   {
      evas_common_image_free(im);
      return;
   }
   im->image->w = w;
   im->image->h = h;
   im->image->data =(void*) re->backbuf;
   im->image->no_free = 1;
   re->rgba_image = im;

   return re;
}

void
evas_engine_directfb_output_free(void *data)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   evas_common_tilebuf_free(re->tb);
   if (re->rects)
      evas_common_tilebuf_free_render_rects(re->rects);
   re->backbuf->Release(re->backbuf);
   evas_common_image_free(re->rgba_image);
   free(re);

   evas_common_font_shutdown();
   evas_common_image_shutdown();
}

void
evas_engine_directfb_output_resize(void *data, int w, int h)
{
   Render_Engine      *re;
   IDirectFBSurface *new_surf;
   DFBSurfaceDescription dsc;

   re = (Render_Engine *) data;
   if (w == re->tb->outbuf_w && h == re->tb->outbuf_h) return;
   evas_common_tilebuf_free(re->tb);
   re->tb = evas_common_tilebuf_new(w, h);
   if (re->tb)
      evas_common_tilebuf_set_tile_size(re->tb, 16, 16);

   memset(&dsc, 0, sizeof(DFBSurfaceDescription));
   dsc.flags = DSDESC_WIDTH | DSDESC_HEIGHT | DSDESC_PIXELFORMAT;
   dsc.width = w;
   dsc.height = h;
   dsc.pixelformat = DSPF_ARGB;

   if (re->dfb->CreateSurface(re->dfb, &dsc, &new_surf) == DFB_OK)
   {
      new_surf->StretchBlit(new_surf, re->backbuf, NULL, NULL);
      re->backbuf->Release(re->backbuf);
      re->backbuf = new_surf;
      re->rgba_image->image->w = w;
      re->rgba_image->image->h = h;
      re->rgba_image->image->data = (void *)new_surf;
   }
}

 void
evas_engine_directfb_output_tile_size_set(void *data, int w, int h)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   evas_common_tilebuf_set_tile_size(re->tb, w, h);
}

void
evas_engine_directfb_output_redraws_rect_add(void *data, int x, int y, int w,
					     int h)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   evas_common_tilebuf_add_redraw(re->tb, x, y, w, h);
}

void
evas_engine_directfb_output_redraws_rect_del(void *data, int x, int y, int w,
					     int h)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   evas_common_tilebuf_del_redraw(re->tb, x, y, w, h);
}

void
evas_engine_directfb_output_redraws_clear(void *data)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   evas_common_tilebuf_clear(re->tb);
}

void        *
evas_engine_directfb_output_redraws_next_update_get(void *data, int *x, int *y,
						    int *w, int *h, int *cx,
						    int *cy, int *cw, int *ch)
{
   Render_Engine      *re;
   RGBA_Image         *surface;
   Tilebuf_Rect       *rect;
   Evas_Object_List   *l;
   int                 ux, uy, uw, uh;
   static             first = 1;
   DFBRegion          region;

   re = (Render_Engine *) data;
   if (re->end)
     {
	re->end = 0;
	return NULL;
     }
   if (!re->rects)
     {
	re->rects = evas_common_tilebuf_get_render_rects(re->tb);
	re->cur_rect = (Evas_Object_List *) re->rects;
     }
   if (!re->cur_rect)
      return NULL;
   rect = (Tilebuf_Rect *) re->cur_rect;
   ux = rect->x;
   uy = rect->y;
   uw = rect->w;
   uh = rect->h;
   re->cur_rect = re->cur_rect->next;
   if (!re->cur_rect)
     {
	evas_common_tilebuf_free_render_rects(re->rects);
	re->rects = NULL;
	re->end = 1;
     }
   *cx = *x = ux;
   *cy = *y = uy;
   *cw = *w = uw;
   *ch = *h = uh;
   region.x1 = ux;
   region.y1 = uy;
   region.x2 = ux + uw - 1;
   region.y2 = uy + uh - 1;
   re->backbuf->SetClip(re->backbuf, &region);
   re->backbuf->Clear(re->backbuf, 0, 0, 0, 0);
   re->backbuf->SetClip(re->backbuf, NULL);
   

   /* Return the "fake" surface so it is passed to the drawing routines. */
   return re->rgba_image;
}

void
evas_engine_directfb_output_redraws_next_update_push(void *data, void *surface,
						     int x, int y, int w, int h)
{
   Render_Engine      *re;
   DFBRectangle        rect;

   rect.x = x;
   rect.y = y;
   rect.w = w;
   rect.h = h;
   re = (Render_Engine *) data;
   re->surface->Blit(re->surface, re->backbuf, &rect, x, y);
   evas_common_cpu_end_opt();
}

void
evas_engine_directfb_output_flush(void *data)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
}

void        *
evas_engine_directfb_context_new(void *data)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   return evas_common_draw_context_new();
}

void
evas_engine_directfb_context_free(void *data, void *context)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   evas_common_draw_context_free(context);
}

void
evas_engine_directfb_context_clip_set(void *data, void *context, int x, int y,
				      int w, int h)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   evas_common_draw_context_set_clip(context, x, y, w, h);
}

void
evas_engine_directfb_context_clip_clip(void *data, void *context, int x, int y,
				       int w, int h)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   evas_common_draw_context_clip_clip(context, x, y, w, h);
}

void
evas_engine_directfb_context_clip_unset(void *data, void *context)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   evas_common_draw_context_unset_clip(context);
}

int
evas_engine_directfb_context_clip_get(void *data, void *context, int *x, int *y,
				      int *w, int *h)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   *x = ((RGBA_Draw_Context *) data)->clip.x;
   *y = ((RGBA_Draw_Context *) data)->clip.y;
   *w = ((RGBA_Draw_Context *) data)->clip.w;
   *h = ((RGBA_Draw_Context *) data)->clip.h;
   return ((RGBA_Draw_Context *) data)->clip.use;
}

void
evas_engine_directfb_context_color_set(void *data, void *context, int r, int g,
				       int b, int a)
{
   Render_Engine      *re;
   RGBA_Draw_Context  *dc = (RGBA_Draw_Context *) context;

   re = (Render_Engine *) data;
   evas_common_draw_context_set_color(dc, r, g, b, a);
}

int
evas_engine_directfb_context_color_get(void *data, void *context, int *r,
				       int *g, int *b, int *a)
{

   DATA32              p;
   DATA8              *pp;
   RGBA_Draw_Context  *dc = (RGBA_Draw_Context *) context;

   p = dc->col.col;
   pp = (DATA8 *) & p;
   *r = R_VAL(pp);
   *g = G_VAL(pp);
   *b = B_VAL(pp);
   *a = A_VAL(pp);
}

void
evas_engine_directfb_context_multiplier_set(void *data, void *context, int r,
					    int g, int b, int a)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   evas_common_draw_context_set_multiplier(context, r, g, b, a);
}

void
evas_engine_directfb_context_multiplier_unset(void *data, void *context)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   evas_common_draw_context_unset_multiplier(context);
}

int
evas_engine_directfb_context_multiplier_get(void *data, void *context, int *r,
					    int *g, int *b, int *a)
{
   DATA32              p;
   DATA8              *pp;
   RGBA_Draw_Context  *dc = (RGBA_Draw_Context *) context;

   p = dc->mul.col;
   pp = (DATA8 *) & p;
   *r = R_VAL(pp);
   *g = G_VAL(pp);
   *b = B_VAL(pp);
   *a = A_VAL(pp);

   return dc->mul.use;
}

void
evas_engine_directfb_context_cutout_add(void *data, void *context, int x, int y,
					int w, int h)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   evas_common_draw_context_add_cutout(context, x, y, w, h);
}

void
evas_engine_directfb_context_cutout_clear(void *data, void *context)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   evas_common_draw_context_clear_cutouts(context);
}

/* 
 * Rectangles
 *
 *
 *
 * */

void
evas_engine_directfb_draw_rectangle(void *data, void *context, void *surface,
				    int x, int y, int w, int h)
{
   int                 c, cx, cy, cw, ch;
   Cutout_Rect        *rects, *r;
   RGBA_Draw_Context  *dc = (RGBA_Draw_Context *) context;
   Evas_Object_List   *l;
   Render_Engine      *re = (Render_Engine *) data;

   /* handle cutouts here! */

   /* no cutouts - cut right to the chase */
   if (!dc->cutout.rects)
     {
	rectangle_draw_internal(data, dc, x, y, w, h);
	return;
     }
   /* save out clip info */
   c = dc->clip.use;
   cx = dc->clip.x;
   cy = dc->clip.y;
   cw = dc->clip.w;
   ch = dc->clip.h;
   evas_common_draw_context_clip_clip(dc, 0, 0, re->tb->outbuf_w, re->tb->outbuf_h);
   evas_common_draw_context_clip_clip(dc, x, y, w, h);
   /* our clip is 0 size.. abort */
   if ((dc->clip.w <= 0) || (dc->clip.h <= 0))
     {
	dc->clip.use = c;
	dc->clip.x = cx;
	dc->clip.y = cy;
	dc->clip.w = cw;
	dc->clip.h = ch;
	return;
     }
   rects = evas_common_draw_context_apply_cutouts(dc);
   for (l = (Evas_Object_List *) rects; l; l = l->next)
     {
	r = (Cutout_Rect *) l;
	evas_common_draw_context_set_clip(dc, r->x, r->y, r->w, r->h);
	rectangle_draw_internal(data, dc, x, y, w, h);
     }
   evas_common_draw_context_apply_free_cutouts(rects);
   /* restore clip info */
   dc->clip.use = c;
   dc->clip.x = cx;
   dc->clip.y = cy;
   dc->clip.w = cw;
   dc->clip.h = ch;

}

void
rectangle_draw_internal(void *data, void *context, int x, int y, int w, int h)
{
   int                 yy;
   DATA32             *ptr;
   RGBA_Draw_Context  *dc = (RGBA_Draw_Context *) context;
   Render_Engine      *re = (Render_Engine *) data;
   int                 r, g, b, a;

   if ((w <= 0) || (h <= 0))
      return;

   if (!(RECTS_INTERSECT(x, y, w, h, 0, 0, re->tb->outbuf_w, re->tb->outbuf_h)))
      return;

   if (x < 0)
     {
	w += x;
	x = 0;
     }
   if ((x + w) > re->tb->outbuf_w)
      w = re->tb->outbuf_w - x;
   if (y < 0)
     {
	h += y;
	y = 0;
     }
   if ((w <= 0) || (h <= 0))
      return;

   if (dc->clip.use)
     {
	if (dc->clip.x > x)
	  {
	     w += x - dc->clip.x;
	     x = dc->clip.x;
	  }
	if ((dc->clip.x + dc->clip.w) < (x + w))
	   w = dc->clip.x + dc->clip.w - x;
	if (dc->clip.y > y)
	  {
	     h += y - dc->clip.y;
	     y = dc->clip.y;
	  }
	if ((dc->clip.y + dc->clip.h) < (y + h))
	   h = dc->clip.y + dc->clip.h - y;
     }
   if ((w <= 0) || (h <= 0))
      return;

   evas_engine_directfb_context_color_get(data, context, &r, &g, &b, &a);
   re->backbuf->SetColor(re->backbuf, r, g, b, a);
   re->backbuf->FillRectangle(re->backbuf, x, y, w, h);
   evas_common_cpu_end_opt();
}

/* 
 * Lines
 *
 *
 *
 * */

void
evas_engine_directfb_line_draw(void *data, void *context, void *surface, int x1,
			       int y1, int x2, int y2)
{
   int r, g, b, a;
   Render_Engine      *re = (Render_Engine *) data;

   evas_engine_directfb_context_color_get(data, context, &r, &g, &b, &a);

   re->backbuf->SetColor(re->backbuf, r, g, b, a);
   re->backbuf->DrawLine(re->backbuf, x1, y1, x2, y2);
}

/* 
 * Polygons
 *
 *
 *
 * */

void *
evas_engine_directfb_polygon_point_add(void *data, void *context, void *polygon, int x, int y)
{
   Render_Engine *re;
   
   re = (Render_Engine *)data;
   return evas_common_polygon_point_add(polygon, x, y);
   context = NULL;
}

void *
evas_engine_directfb_polygon_points_clear(void *data, void *context, void *polygon)
{
   Render_Engine *re;
   
   re = (Render_Engine *)data;
   return evas_common_polygon_points_clear(polygon);
   context = NULL;
}

void
evas_engine_directfb_polygon_draw(void *data, void *context, void *surface, void *polygon)
{

   Render_Engine *re;
   IDirectFBSurface *surf;
   RGBA_Image  *im;
   void *p;
   int pitch;
   
   re = (Render_Engine *)data;
   im = surface;
   surf = (IDirectFBSurface *)im->image->data;
   surf->Lock(surf, DSLF_WRITE, &p, & pitch);
   im->image->data = p;
   evas_common_polygon_draw(im, context, polygon);
   surf->Unlock(surf);
   im->image->data = (void *)surf;
   evas_common_cpu_end_opt();
}


/* 
 * Gradients
 *
 *
 *
 * */
void *
evas_engine_directfb_gradient_color_add(void *data, void *context, void *gradient, int r, int g, int b, int a, int distance)
{
   Render_Engine *re;
   
   re = (Render_Engine *)data;
   if (!gradient)
     gradient = evas_common_gradient_new();
   evas_common_gradient_color_add(gradient, r, g, b, a, distance);
   return gradient;
   context = NULL;
}

void *
evas_engine_directfb_gradient_colors_clear(void *data, void *context, void *gradient)
{
   Render_Engine *re;
   
   re = (Render_Engine *)data;
   if (gradient) evas_common_gradient_free(gradient);
   return NULL;
   context = NULL;
}

void
evas_engine_directfb_gradient_draw(void *data, void *context, void *surface, void *gradient, int x, int y, int w, int h, double angle)
{
   Render_Engine *re;
   IDirectFBSurface *surf;
   RGBA_Image  *im;
   void *p;
   int pitch;
   
   re = (Render_Engine *)data;
   im = surface;
   surf = (IDirectFBSurface *)im->image->data;
   surf->Lock(surf, DSLF_WRITE, &p, & pitch);
   im->image->data = p;
   evas_common_gradient_draw(im, context, x, y, w, h, gradient, angle);
   surf->Unlock(surf);
   im->image->data = (void *)surf;
   evas_common_cpu_end_opt();
}



/* 
 * Font objects
 *
 *
 *
 * */

void        *
evas_engine_directfb_font_load(void *data, char *name, int size)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   return evas_common_font_load(name, size);
}

void        *
evas_engine_directfb_font_memory_load(void *data, char *name, int size, const void *fdata, int fdata_size)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   return evas_common_font_memory_load(name, size, fdata, fdata_size);
}

void
evas_engine_directfb_font_free(void *data, void *font)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   evas_common_font_free(font);
}

int
evas_engine_directfb_font_ascent_get(void *data, void *font)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   return evas_common_font_ascent_get(font);
}

int
evas_engine_directfb_font_descent_get(void *data, void *font)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   return evas_common_font_descent_get(font);
}

int
evas_engine_directfb_font_max_ascent_get(void *data, void *font)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   return evas_common_font_max_ascent_get(font);
}

int
evas_engine_directfb_font_max_descent_get(void *data, void *font)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   return evas_common_font_max_descent_get(font);
}

void
evas_engine_directfb_font_string_size_get(void *data, void *font, char *text,
					  int *w, int *h)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   evas_common_font_query_size(font, text, w, h);
}

int
evas_engine_directfb_font_inset_get(void *data, void *font, char *text)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   return evas_common_font_query_inset(font, text);
}

int
evas_engine_directfb_font_h_advance_get(void *data, void *font, char *text)
{
   Render_Engine      *re;
   int                 h, v;

   re = (Render_Engine *) data;
   evas_common_font_query_advance(font, text, &h, &v);
   return h;
}

int
evas_engine_directfb_font_v_advance_get(void *data, void *font, char *text)
{
   Render_Engine      *re;
   int                 h, v;

   re = (Render_Engine *) data;
   evas_common_font_query_advance(font, text, &h, &v);
   return v;
}

int
evas_engine_directfb_font_char_coords_get(void *data, void *font, char *text,
					  int pos, int *cx, int *cy, int *cw,
					  int *ch)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   return evas_common_font_query_char_coords(font, text, pos, cx, cy, cw, ch);
}

int
evas_engine_directfb_font_char_at_coords_get(void *data, void *font, char *text,
					     int x, int y, int *cx, int *cy,
					     int *cw, int *ch)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   return evas_common_font_query_text_at_pos(font, text, x, y, cx, cy, cw, ch);
}

void
evas_engine_directfb_font_draw(void *data, void *context, void *surface,
			       void *font, int x, int y, int w, int h, int ow,
			       int oh, char *text)
{
   Render_Engine *re;
   void *p;
   RGBA_Image *im;
   IDirectFBSurface * surf;
   int pitch;

   im = surface;
   re = (Render_Engine *)data;
   surf = (IDirectFBSurface *)im->image->data; 
   surf->Lock(surf, DSLF_WRITE, &p, &pitch);
   im->image->data = p;
   im->flags |= RGBA_IMAGE_HAS_ALPHA;
   if ((w == ow) && (h == oh))
      evas_common_font_draw(im, context, font, x, y, text);
   else
     {
	/* create output surface size ow x oh and scale to w x h */
	RGBA_Draw_Context *dc, *dc_in;

	dc_in = context;
	dc = evas_common_draw_context_new();
	if (dc)
	  {
	     RGBA_Image *im;
	     
	     dc->col.col = dc_in->col.col;
	     im = evas_common_image_create(ow, oh);
	     if (im)
	       {
		  int max_ascent;
		  int i, j;
		  
		  im->flags |= RGBA_IMAGE_HAS_ALPHA;
		  j = ow * oh;
		  memset(im->image->data, 0, j * sizeof(DATA32));
		  
		  max_ascent = evas_common_font_max_ascent_get(font);
		  
		  evas_common_font_draw(im, dc, font, 0, max_ascent, text);
		  evas_common_cpu_end_opt();
		  evas_common_scale_rgba_in_to_out_clip_smooth(im, surface, context, 
						   0, 0, ow, oh, 
						   x, y - ((max_ascent * h) / oh), 
						   w, h);
		  evas_common_image_free(im);
	       }
	     evas_common_draw_context_free(dc);
	  }
     }
      
   surf->Unlock(surf);
   im->image->data = (void *)surf;
   evas_common_cpu_end_opt();
}

void
evas_engine_directfb_font_cache_flush(void *data)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   evas_common_font_flush();
}

void
evas_engine_directfb_font_cache_set(void *data, int bytes)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   evas_common_font_cache_set(bytes);
}

int
evas_engine_directfb_font_cache_get(void *data)
{
   Render_Engine      *re;

   re = (Render_Engine *) data;
   return evas_common_font_cache_get();
}

