view src/cs/drivers/drv_app/r2d/r2d.c @ 258:13bcc2ed7e44

configure.sh & targets/*.conf: emit FLASH_BASE_ADDR & FLASH_SECTOR_SIZE into the generated Makefile
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 04 Aug 2017 07:14:16 +0000
parents 945cf7f506b2
children
line wrap: on
line source

/**
                                                                          
  @file       r2d.c   
  
  @author     Christophe Favergeon

  @version    0.5
                                                                          
  Function    Riviera 2D system implementation
              (higher software layer)                       
     
*/

/*
  Date        Modification                                                 
  ------------------------                                                 
  06/12/2001    Create    
  10/18/2001    Version 0.5 for first integration with Riviera database
 **************************************************************************
  History       
                                                                          
  Apr-06-2005 MMI-SPR-29655 - xreddymn
  Added function r2d_flush_region to allow flushing of portions 
  of framebuffer to the display

*/

 
#include "rv/general.h"
#include "rvf/rvf_api.h"
#include "r2d/r2d_config.h"
#include "r2d/r2d.h"
#include "r2d/r2d_i.h"
#include "r2d/r2d_independance_layer.h"
#include "r2d/r2d_convertion_table.h"
#include "r2d/r2d_env.h"
#include "rvm/rvm_use_id_list.h"
#include <string.h>

#include "r2d_cos.c"


#ifdef _WINDOWS
  #pragma warning(disable:4761) // integral size mismatch in argument; conversion supplied
#endif


/***************************************

     IMPORTANT INFORMATION

***************************************/

/*

Clipping is done on original coordinates.
Then those coordinates are modified to take into account a possible
mirror symetry of the LCD. 
Then the scanning algorithm is applied on those transformed and clipped
coordinates. It assumes a vertical scanning (column per column).
If it is not the case. The high level coordinates (x,y) are swapped
after clipping and mirroring. The scanning is done on the swapped coordinates
so that coulmns are mapped to lines.

Subroutine's comment use following rule:
H -> High level user coordinates
L -> LCD coordinates (mirroring or not and local_to_global applied)
S -> Scanning coordinates (vertical or horizontal)
*/

/***************************************

     CONSTANTS

***************************************/

// Used for char drawing algorithm with unicode
typedef enum K_R2D_CHAR_DRAWING_MODE
{
R2D_COMBINING_CHAR=1
} T_R2D_CHAR_DRAWING_MODE;

// Used for internal drawing function
typedef enum K_R2D_TEXT_DRAWING_SETTINGS
{
  R2D_TEXT_DRAW=1
} T_R2D_TEXT_DRAWING_SETTINGS;





/***************************************

     REFRESH TASK RELATED GLOBALS

***************************************/

extern INT16 r2d_update_ul_x,r2d_update_ul_y,r2d_update_br_x,r2d_update_br_y;

/***************************************

     STATIC INTERNAL FUNCTIONS
	 AND GLOBALS

***************************************/


#define IND_r2d_write_lcd_line r2d_write_lcd_line
#define IND_r2d_write_lcd_pixel r2d_write_lcd_pixel
#define IND_r2d_blit_lcd_to_lcd r2d_blit_lcd_to_lcd
#define IND_r2d_blit_lcd_to_color r2d_blit_lcd_to_color
#define IND_r2d_blit_color_to_lcd r2d_blit_color_to_lcd
#define IND_r2d_blit_color_to_color r2d_blit_color_to_color
#define IND_r2d_get_color_pixel_value r2d_get_color_pixel_value

static T_R2D_GC_PTR r2d_new_font_buffer_context(T_RVF_MB_ID bank,
												T_R2D_FRAMEBUFFER_KIND kind,
												UINT16 max_width,
												UINT16 ascent);
static T_R2D_FONT_CACHE_FRAMEBUFFER* r2d_new_font_framebuffer(T_RVF_MB_ID bank,
															  T_R2D_FRAMEBUFFER_KIND the_kind,UINT16 width, UINT16 height);
static T_R2D_SHAPE_PTR r2d_s_level(T_R2D_GC_PTR gc,T_R2D_SHAPE_PTR self);
static void r2d_mirror_rectangle(T_R2D_GC_PTR gc,T_R2D_SHAPE_PTR rectangle);
static void r2d_mirror_clip_rectangle(T_R2D_GC_PTR gc,T_R2D_SHAPE_PTR rectangle);
static void r2d_diagonal_mirror(T_R2D_SHAPE_PTR rectangle);

static void r2d_update_region(T_R2D_GC *gc,INT16 ul_x,INT16 ul_y,INT16 br_x,INT16 br_y);

void r2d_translate_shape(T_R2D_SHAPE_PTR self,INT16 dx,INT16 dy);

// Used for pen_size != 1. It computes the bounding rect and calls
// fillrectangle
static void r2d_s_fill_point(T_R2D_GC_PTR gc,INT16 x,INT16 y,INT16 pen_size);

static void           r2d_df_rectangle(T_R2D_GC_PTR gc,
                  INT16 ul_x,INT16 ul_y,INT16 br_x, INT16 br_y,BOOLEAN background);
static void           r2d_s_fill_rectangle(T_R2D_GC_PTR gc,
                  INT16 ul_x,INT16 ul_y,INT16 br_x, INT16 br_y,BOOLEAN background);



#define R2D_SQUARE_P(x) (x*x)
#define R2D_SWAP(x,y) tmp=x; x=y; y=tmp
#define SQRT2 0x16A09
#define PI 0x3243F

////////////////////////////////////////
//
// Utility functions
//

// L COORDINATES
void r2d_update_region(T_R2D_GC* gc,INT16 ul_x,INT16 ul_y,INT16 br_x,INT16 br_y)
{

	INT16 tmp;

	rvf_lock_mutex(r2d_g_global_mutex);

	if (ul_x>br_x)
	{
		tmp=ul_x;
		ul_x=br_x;
		br_x=tmp;
	}

	if (ul_y>br_y)
	{
		tmp=ul_y;
		ul_y=br_y;
		br_y=tmp;
	}

	if (gc)
	{
	  if (ul_x<((T_R2D_RECT*)(gc->p_clipping_shape))->ul_x-gc->org_x)
         ul_x=((T_R2D_RECT*)(gc->p_clipping_shape))->ul_x-gc->org_x;
      if (ul_y<((T_R2D_RECT*)(gc->p_clipping_shape))->ul_y-gc->org_y)
         ul_y=((T_R2D_RECT*)(gc->p_clipping_shape))->ul_y-gc->org_y;
      if (br_x>=((T_R2D_RECT*)(gc->p_clipping_shape))->br_x-1-gc->org_x)
         br_x=((T_R2D_RECT*)(gc->p_clipping_shape))->br_x-1-gc->org_x;
      if (br_y>=((T_R2D_RECT*)(gc->p_clipping_shape))->br_y-1-gc->org_y)
         br_y=((T_R2D_RECT*)(gc->p_clipping_shape))->br_y-1-gc->org_y;
    }

	if (ul_x < r2d_update_ul_x)
		r2d_update_ul_x=ul_x;
    if (ul_y < r2d_update_ul_y)
		r2d_update_ul_y=ul_y;
	if (br_x > r2d_update_br_x)
		r2d_update_br_x=br_x;
	if (br_y > r2d_update_br_y)
		r2d_update_br_y=br_y;

	
	  if (r2d_update_ul_x<0)
         r2d_update_ul_x=0;
      if (r2d_update_ul_y<0)
         r2d_update_ul_y=0;
      if (r2d_update_br_x>=R2D_WIDTH)
         r2d_update_br_x=R2D_WIDTH-1;
      if (r2d_update_br_y>=R2D_HEIGHT)
         r2d_update_br_y=R2D_HEIGHT-1;
	
	
	rvf_unlock_mutex(r2d_g_global_mutex);
}


void r2d_check_and_send_event(T_R2D_GC_PTR gc)
{
	  // If routine has drawn into the LCD framebuffer
	  // then refresh may be required
	  // If LCD framebuffer ONLY
	  if (((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)gc)->p_frame_buffer))->kind==0)
	  {
	  if ((r2d_g_event_was_sent==FALSE) && (r2d_g_refresh_disabled==0))
      {
		  //rvf_send_trace("R2D SEND EVENT",strlen("R2D SEND EVENT"), NULL_PARAM, 
			   //RV_TRACE_LEVEL_DEBUG_HIGH, TRACE_XXX );
		     r2d_g_event_was_sent=TRUE;
			 rvf_send_event( (UINT8)(r2d_addr_id & 0xFF), EVENT_MASK(RVF_APPL_EVT_0) );
	  }
	  }
}

// WILL HAVE TO BE IMPROVED

INT32 r2d_fixed_division(INT32 a,INT32 b)
{
    INT16 k;
    UINT32 q,nb;
    INT16 right_shift=0;
    INT16 sign=0;

	// Convert to positive values
    if ((b<0) && (a<0))
	{
		b=-b;
		a=-a;
	}
	if ((b<0) && (a>=0))
	{
		b=-b;
		sign=1;
	}
	if ((a<0) && (b>=0))
	{
		a=-a;
		sign=1;
	}


    // Normalize b between in [0.5,1[
    

    nb=b;

    if (nb>=0x10000)
    {
      //printf("%08X/%08X\n",a,nb);
      while(((nb>>16)&0x0FFFF)!=0)
      {
         nb>>=1;
         right_shift++;
         //printf("%08X\n",nb);
      }
    } else if (nb<0x8000)
    {
      while((nb&0x8000)==0)
      {
         nb<<=1;
         right_shift--;
         //printf("%08X\n",nb);
      }
    }
    //printf("right_shift=%d\n",right_shift);
    if (nb==0x8000)
    {
      //printf("nb=0x8000, return %08X\n",((a>>right_shift)<<1));
      if (sign)
        return (-((a>>right_shift)<<1));
      else
        return (((a>>right_shift)<<1));
    }


    

    // Newton method used to compute 1/nb with
    // q=q(2-nb * q)

    // Which first choice for q and which accuracies for intermediate
    // computations ?

    
    // nb being in ]0.5,1[ one must has q in ]0.5, 3[
    // And one must check that the function is contracting
    // Derivative is nul for q*nb = 1. Below, sign of
    // derivatuve (relatively to q) is positive if a<1 and
    // the derivative is between 2 and 0
    // <1 is got for q>1/(2 nb) and q must be < 1/nb
    // One can take q=1 as starting value. It solves
    // for the bounds except for nb=1 or nb=0.5

    // if q in ]1/2nb, 1/nb[ one can check that qnew
    // will at most reach 3/2nb at next iteration and then will
    // fall back into the intervall
    // So, one needs to represents values up to 3 for q
    // and 2 bits are required for integer part
    
    // So, q is 2.16, nb is 0.16
    // q*nb is 2.32 which cannot be represented and one needs
    // to shift value by 1 bit
    // nb will be 0.15 and q 2.15 sor nb*q is 2.30
    // It must be multiplied by a format 2.16
    // so both intermediate result must be shifted to
    // 2.15 (1 for q and 15 for np*q)
    
    

    q=(1<<16);
    //printf("-- q=%08X\n",q);

    
    for(k=0;k<5;k++)
    {
       q=((q>>1) * ((2 << 15) - (((nb>>1) * (q>>1))  >> 15))) >> 14;
       //printf("-- q=%08X\n",q);
    }
    
    // a is known to be an integer and q is know to be less than 1
    // so a 64 bits product is not required

    //printf("a=%08X, q=%08X\n",a,q);

    q>>=right_shift;

    q=((a>>16)*q) ;


    //printf("right_shift=%d, q=%08X\n",right_shift,q);

    if (sign)
     return(-((INT32)q));
    else
     return(q);

    
}

////////////////////////////////////////
//
// Texture
//

T_R2D_FREE_TEXTURE_PTR r2d_new_free_texture(T_RVF_MB_ID bank,INT16 size,T_R2D_ARGB_COLOR *pattern)
{
   T_R2D_FREE_TEXTURE *t;

   R2D_MALLOC(bank,T_R2D_FREE_TEXTURE,sizeof(T_R2D_FREE_TEXTURE),t);

   if (t)
   {
	   t->refcount=1;
	   t->size=size;
	   t->pattern=pattern;
   }

   return(t);
}

T_R2D_FREE_TEXTURE_PTR r2d_new_const_free_texture(T_RVF_MB_ID bank,INT16 size,T_R2D_ARGB_COLOR *pattern)
{
   T_R2D_FREE_TEXTURE *t;

   R2D_MALLOC(bank,T_R2D_FREE_TEXTURE,sizeof(T_R2D_FREE_TEXTURE),t);

   if (t)
   {
	   t->refcount=-1;
	   t->size=size;
	   t->pattern=pattern;
   }

   return(t);
}

void              r2d_release_free_texture(T_R2D_FREE_TEXTURE_PTR texture)
{
	if (texture)
    {
      // Remove the array of words if needed
      // (refcount must be 1 else the array should not be deleted)
      if (R2D_REFCOUNT(texture)==1) 
	  {
		if (((T_R2D_FREE_TEXTURE*)texture)->pattern)
          R2D_FREE(((T_R2D_FREE_TEXTURE*)texture)->pattern);
	  }
    }
    // Autorelease
    r2d_release(texture);
}

T_R2D_ANCHORED_TEXTURE_PTR r2d_new_anchored_texture(T_RVF_MB_ID bank,T_R2D_GC_PTR gc,T_R2D_FREE_TEXTURE_PTR texture)
{

  INT16 length;
  T_R2D_FREE_TEXTURE *ft;
  T_R2D_ANCHORED_TEXTURE *at;
  INT16 i,j,x,y,ni,nj,pos;
  UINT32 *p;

		 T_R2D_ARGB_COLOR b;

   // If a new texture is installed,
   // one must recompute p_background
   if (texture==NULL)
	  goto erroranchored;

   
     
   ft=(T_R2D_FREE_TEXTURE *)texture;

   length=1<<(ft->size);

   R2D_MALLOC(bank,T_R2D_ANCHORED_TEXTURE,sizeof(T_R2D_ANCHORED_TEXTURE),at);

   if (at==NULL)
	   goto erroranchored;

   at->refcount=1;

   at->size=ft->size;

   R2D_MALLOC(bank,UINT32,sizeof(UINT32)*length*length,at->pattern);

   if (at->pattern==NULL)
   {
	   R2D_FREE(at);
	   goto erroranchored;
   }
     
	 
   p=at->pattern;
   b=r2d_get_background_color(gc);

   if (((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)gc)->p_frame_buffer))->kind==R2D_FULL_KIND)
   {
			 x=0;
			 y=0;
			 for(i=0;i<length;i++) // Horizontal
				 for(j=0;j<length;j++) // Vertical
			 {
			   r2d_convert_background_color_color(gc,ft->pattern[i*length+j]);

               #if (R2D_REFRESH == R2D_VERTICAL)
                 #ifdef R2D_MIRRORED_X
			       ni=(length-1)-i;
                 #else
				   ni=i;
                 #endif

				 #ifdef R2D_MIRRORED_Y
			       nj=(length-1)-j;
                 #else
				   nj=j;
                 #endif
                 p[ni*length+nj]=((T_R2D_GC*)gc)->background_pixel_value;
               #else
				 #ifdef R2D_MIRRORED_X
			       nj=(length-1)-j;
                 #else
				   nj=j;
                 #endif

				 #ifdef R2D_MIRRORED_Y
			       ni=(length-1)-i;
                 #else
				   ni=i;
                 #endif

				 p[nj*length+ni]=((T_R2D_GC*)gc)->background_pixel_value;
               #endif
               
			 }
	}
	else
	{
			 for(i=0;i<length;i++)
				 for(j=0;j<length;j++)
			 {
			  r2d_convert_background_color(gc,ft->pattern[i*length+j]);
			  #if (R2D_REFRESH == R2D_VERTICAL)
                 #ifdef R2D_MIRRORED_X
			       ni=(length-1)-i;
                 #else
				   ni=i;
                 #endif

				 #ifdef R2D_MIRRORED_Y
			       nj=(length-1)-j;
                 #else
				   nj=j;
                 #endif
                 pos=ni*length+nj;
               #else
				 #ifdef R2D_MIRRORED_X
			       nj=(length-1)-j;
                 #else
				   nj=j;
                 #endif

				 #ifdef R2D_MIRRORED_Y
			       ni=(length-1)-i;
                 #else
				   ni=i;
                 #endif

				 pos=nj*length+ni;
               #endif
			  #if (R2D_DITHERING == R2D_OFF)
                  p[pos]=((T_R2D_GC*)gc)->background_pixel_value;
              #else
				  p[pos]=r2d_get_dithering_matrix_entry(((T_R2D_GC*)gc)->p_background_dithered_cache,x,y);      
              #endif

              #if (R2D_REFRESH == R2D_VERTICAL)
			    y++;
			    if (y==length)
				{
				  y=0;
				  x++;
				}
              #else
				x++;
			    if (x==length)
				{
				  x=0;
				  y++;
				}
              #endif
			 }
	}
		 // Force change
	r2d_set_background_color(gc,b^1);
    r2d_set_background_color(gc,b);
		 
   return((T_R2D_ANCHORED_TEXTURE_PTR)at);
erroranchored: return(NULL);
}

void              r2d_release_anchored_texture(T_R2D_ANCHORED_TEXTURE_PTR texture)
{
	if (texture)
    {
      // Remove the array of words if needed
      // (refcount must be 1 else the array should not be deleted)
      if (R2D_REFCOUNT(texture)==1) 
	  {
		if (((T_R2D_ANCHORED_TEXTURE*)texture)->pattern)
          R2D_FREE(((T_R2D_ANCHORED_TEXTURE*)texture)->pattern);
	  }
    }
    // Autorelease
    r2d_release(texture);
}


////////////////////////////////////////
//
// Framebuffer
//

UINT32 r2d_get_framebuffer_size(T_R2D_FRAMEBUFFER_KIND the_kind,UINT16 width, UINT16 height)
{
	UINT32 t;
	UINT32 length;

	t=0;

	
			

	t+=sizeof(T_R2D_FRAMEBUFFER);
		
	switch(the_kind) 
	{
       case R2D_LCD_KIND:
		    #if (R2D_REFRESH==R2D_VERTICAL)
              // Column is contiguous in memory
              length=width*R2D_ALIGNED_MWLENGTH(height);
              t+=((length+1)<<R2D_LONGSIZE_FACTOR);
            #else
			  length=height*R2D_ALIGNED_MWLENGTH(width);
              t+=((length+1)<<R2D_LONGSIZE_FACTOR);
            #endif
	   break;
	   default:
			  length=width*height;
              t+=((length+1)<<R2D_LONGSIZE_FACTOR);
	   break;
	}

	t+=sizeof(T_RVF_MUTEX);
	

	return(t);
}

UINT32 r2d_get_gc_size(void)
{
	UINT32 t;

	t=0;

	
	t+=sizeof(T_R2D_GC);
	t+=sizeof(T_R2D_RECT); // clipping
	t+=sizeof(T_R2D_RECT); // s_clipping
	t+=sizeof(UINT32)*4; // foreground dithering cache
	t+=sizeof(UINT32)*4; // backround dithering cache
	

	return(t);
}


T_R2D_FRAMEBUFFER_PTR r2d_new_framebuffer(T_RVF_MB_ID bank,T_R2D_FRAMEBUFFER_KIND the_kind,UINT16 width, UINT16 height)
{
   UINT32 length;
   T_R2D_FRAMEBUFFER *p;
//   UINT32 *elem;
   T_RVF_RET err;

   R2D_MALLOC(bank,T_R2D_FRAMEBUFFER,sizeof(T_R2D_FRAMEBUFFER),p);

   if (p)
   {
     switch(the_kind) 
     {
        case R2D_LCD_KIND:
          #if (R2D_REFRESH==R2D_VERTICAL)
            // Column is contiguous in memory
            length=width*R2D_ALIGNED_MWLENGTH(height);
            R2D_MALLOC(bank,UINT32,((length+1)<<R2D_LONGSIZE_FACTOR),p->p_memory_words);
			if (!(p->p_memory_words))
			{
		        R2D_FREE(p);
		        p=NULL;
				return(p);
			}
			p->refcount=1;
            p->kind=R2D_LCD_KIND;
            p->p_frame_buffer_end=p->p_memory_words+length;
            p->width=width;
            p->height=height;
			R2D_MALLOC(bank,T_RVF_MUTEX,sizeof(T_RVF_MUTEX),p->mutex);
		    if (p->mutex!=NULL)
			{
			  err=rvf_initialize_mutex(p->mutex);
			  if (err!=RVF_OK)
			  {
				 R2D_FREE(p->mutex);
				 R2D_FREE(p->p_memory_words);
				 R2D_FREE(p);
				 p=NULL;
				 return(p);
			  }
			}
			else
			{
				R2D_FREE(p->p_memory_words);
				R2D_FREE(p);
				p=NULL;
				return(p);
			}
			
         #else
             // Line is contiguous in memory
             length=height*R2D_ALIGNED_MWLENGTH(width);
             R2D_MALLOC(bank,UINT32,((length+1)<<R2D_LONGSIZE_FACTOR),p->p_memory_words);
             if (!(p->p_memory_words))
			{
		        R2D_FREE(p);
		        p=NULL;
				return(p);
			}
			 p->refcount=1;
             p->kind=R2D_LCD_KIND;
             p->p_frame_buffer_end=p->p_memory_words+length;
             p->width=width;
             p->height=height;
			 R2D_MALLOC(bank,T_RVF_MUTEX,sizeof(T_RVF_MUTEX),p->mutex);
		    if (p->mutex!=NULL)
			{
			  err=rvf_initialize_mutex(p->mutex);
			  if (err!=RVF_OK)
			  {
				 R2D_FREE(p->mutex);
				 R2D_FREE(p->p_memory_words);
				 R2D_FREE(p);
				 p=NULL;
				 return(p);
			  }
			}
			else
			{
				R2D_FREE(p->p_memory_words);
				R2D_FREE(p);
				p=NULL;
				return(p);
			}
         #endif
        break;
        default:
            length=width*height;
            R2D_MALLOC(bank,UINT32,((length+1)<<R2D_LONGSIZE_FACTOR),p->p_memory_words);
            if (!(p->p_memory_words))
			{
		        R2D_FREE(p);
		        p=NULL;
				return(p);
			}
			p->refcount=1;
            p->kind=R2D_FULL_KIND;
            p->p_frame_buffer_end=p->p_memory_words+length;
            p->width=width;
            p->height=height;
			R2D_MALLOC(bank,T_RVF_MUTEX,sizeof(T_RVF_MUTEX),p->mutex);
		    if (p->mutex!=NULL)
			{
			  err=rvf_initialize_mutex(p->mutex);
			  if (err!=RVF_OK)
			  {
				 R2D_FREE(p->mutex);
				 R2D_FREE(p->p_memory_words);
				 R2D_FREE(p);
				 p=NULL;
				 return(p);
			  }
			}
			else
			{
				R2D_FREE(p->p_memory_words);
				R2D_FREE(p);
				p=NULL;
				return(p);
			}
        break;
     }
   } else p=NULL;

   return(p);
}

static T_R2D_FONT_CACHE_FRAMEBUFFER* r2d_new_font_framebuffer(T_RVF_MB_ID bank,T_R2D_FRAMEBUFFER_KIND the_kind,UINT16 width, UINT16 height)
{
   UINT32 length;
   T_R2D_FONT_CACHE_FRAMEBUFFER *p;
//   UINT32 *elem;
   T_RVF_RET err;

   R2D_MALLOC(bank,T_R2D_FONT_CACHE_FRAMEBUFFER,sizeof(T_R2D_FONT_CACHE_FRAMEBUFFER),p);

   if (p)
   {
     switch(the_kind) 
     {
        case R2D_LCD_KIND:
          #if (R2D_REFRESH==R2D_VERTICAL)
            // Column is contiguous in memory
            length=width*R2D_ALIGNED_MWLENGTH(height);
            R2D_MALLOC(bank,UINT32,((length+1)<<R2D_LONGSIZE_FACTOR),p->p_memory_words);
			if (!(p->p_memory_words))
			{
		        R2D_FREE(p);
		        p=NULL;
				return(p);
			}
            p->refcount=1;
            p->kind=R2D_LCD_KIND;
            p->p_frame_buffer_end=p->p_memory_words+length;
            p->width=width;
            p->height=height;
			R2D_MALLOC(bank,T_RVF_MUTEX,sizeof(T_RVF_MUTEX),p->mutex);
		    if (p->mutex!=NULL)
			{
			  err=rvf_initialize_mutex(p->mutex);
			  if (err!=RVF_OK)
			  {
				 R2D_FREE(p->mutex);
				 R2D_FREE(p->p_memory_words);
				 R2D_FREE(p);
				 p=NULL;
				 return(p);
			  }
			}
			else
			{
				R2D_FREE(p->p_memory_words);
				R2D_FREE(p);
				p=NULL;
				return(p);
			}
         #else
             // Line is contiguous in memory
             length=height*R2D_ALIGNED_MWLENGTH(width);
             R2D_MALLOC(bank,UINT32,((length+1)<<R2D_LONGSIZE_FACTOR),p->p_memory_words);
             if (!(p->p_memory_words))
			{
		        R2D_FREE(p);
		        p=NULL;
				return(p);
			}
			 p->refcount=1;
             p->kind=R2D_LCD_KIND;
             p->p_frame_buffer_end=p->p_memory_words+length;
             p->width=width;
             p->height=height;
			 R2D_MALLOC(bank,T_RVF_MUTEX,sizeof(T_RVF_MUTEX),p->mutex);
		    if (p->mutex!=NULL)
			{
			  err=rvf_initialize_mutex(p->mutex);
			  if (err!=RVF_OK)
			  {
				 R2D_FREE(p->mutex);
				 R2D_FREE(p->p_memory_words);
				 R2D_FREE(p);
				 p=NULL;
				 return(p);
			  }
			}
			else
			{
				R2D_FREE(p->p_memory_words);
				R2D_FREE(p);
				p=NULL;
				return(p);
			}
         #endif
        break;
        default:
            length=width*height;
            R2D_MALLOC(bank,UINT32,((length+1)<<R2D_LONGSIZE_FACTOR),p->p_memory_words);
            if (!(p->p_memory_words))
			{
		        R2D_FREE(p);
		        p=NULL;
				return(p);
			}
			p->refcount=1;
            p->kind=R2D_FULL_KIND;
            p->p_frame_buffer_end=p->p_memory_words+length;
            p->width=width;
            p->height=height;
			R2D_MALLOC(bank,T_RVF_MUTEX,sizeof(T_RVF_MUTEX),p->mutex);
		    if (p->mutex!=NULL)
			{
			  err=rvf_initialize_mutex(p->mutex);
			  if (err!=RVF_OK)
			  {
				 R2D_FREE(p->mutex);
				 R2D_FREE(p->p_memory_words);
				 R2D_FREE(p);
				 p=NULL;
				 return(p);
			  }
			}
			else
			{
				R2D_FREE(p->p_memory_words);
				R2D_FREE(p);
				p=NULL;
				return(p);
			}
        break;
     }
     
   } else p=NULL;

   return(p);
}


// Release a framebuffer
void r2d_release_framebuffer(T_R2D_FRAMEBUFFER_PTR p)
{
    if (p)
    {
      // Remove the array of words if needed
      // (refcount must be 1 else the array should not be deleted)
      if (R2D_REFCOUNT(p)==1) 
	  {
        R2D_FREE(((T_R2D_FRAMEBUFFER*)p)->p_memory_words);
		rvf_delete_mutex(((T_R2D_FRAMEBUFFER*)p)->mutex);
		R2D_FREE(((T_R2D_FRAMEBUFFER*)p)->mutex);
	  }
    }
    // Autorelease
    r2d_release(p);
}


////////////////////////////////////////
//
// Graphic context
//


static T_R2D_GC_PTR r2d_new_font_buffer_context(T_RVF_MB_ID bank,
												T_R2D_FRAMEBUFFER_KIND kind,
												UINT16 max_width,
												UINT16 ascent)
{
   T_R2D_FRAMEBUFFER_PTR cache_buffer;
   T_R2D_GC_PTR result;

   //printf("width=%d,height=%d\n",the_width,((T_R2D_FRAMEBUFFER*)font_frame_buffer)->height);

   cache_buffer=r2d_new_font_framebuffer(bank,kind,
   max_width,ascent);

   

   if (cache_buffer!=NULL)
   {
     result=r2d_new_context(bank,cache_buffer);
     r2d_release_framebuffer(cache_buffer);
     
     return(result);
   } else return(NULL);
}


T_R2D_GC_PTR   r2d_new_context(T_RVF_MB_ID bank,T_R2D_FRAMEBUFFER_PTR the_frame_buffer)
{
   T_R2D_GC *gc;

   // Allocate a new gc structure
   R2D_MALLOC(bank,T_R2D_GC,sizeof(T_R2D_GC),gc);
   if (gc)
   {
      // gc is pointing to the LCD framebuffer
      gc->p_frame_buffer=(T_R2D_FRAMEBUFFER*)the_frame_buffer;
      r2d_retain(the_frame_buffer);

      // Default initialization for a gc
	  gc->background_texture=NULL;
      gc->foreground_color=r2d_get_standard_argb_color(R2D_BLACK);
      gc->background_color=r2d_get_standard_argb_color(R2D_WHITE);
      

	  #if (R2D_REFRESH == R2D_VERTICAL)
		gc->p_s_clipping_shape=r2d_new_rectangle(bank,0,0,((T_R2D_FRAMEBUFFER*)the_frame_buffer)->width,
        ((T_R2D_FRAMEBUFFER*)the_frame_buffer)->height);

      #else
		 gc->p_s_clipping_shape=r2d_new_rectangle(bank,0,0,((T_R2D_FRAMEBUFFER*)the_frame_buffer)->height,((T_R2D_FRAMEBUFFER*)the_frame_buffer)->width);

      #endif

	  if (gc->p_s_clipping_shape==NULL)
	  {
		  r2d_release_framebuffer(the_frame_buffer);
          R2D_FREE(gc);
          gc=NULL;
		  return(NULL);
	  }

	  gc->p_clipping_shape=r2d_new_rectangle(bank,0,0,((T_R2D_FRAMEBUFFER*)the_frame_buffer)->width,
      ((T_R2D_FRAMEBUFFER*)the_frame_buffer)->height);

      
      gc->drawing_mode=R2D_COPY_MODE;
	  
	  gc->drawing_op=r2d_get_drawing_op(gc,R2D_COPY_MODE);

      gc->org_x=gc->org_y=0;
	  gc->s_org_x=gc->s_org_y=0;

      gc->pen_size=1;
      gc->dash=0;
      gc->text_face=R2D_SYSTEM;
      gc->text_style=R2D_PLAIN;
      gc->internal_text_style=R2D_PLAIN;
      gc->text_size=R2D_SMALL;
	  gc->script_mode=R2D_LEFT_TO_RIGHT;
      gc->font_frame_buffer=r2d_g_default_font_framebuffer;
      gc->font_metrics=r2d_g_default_font_metrics;
	  gc->font_table=r2d_g_default_font_table;
	  if (gc->p_clipping_shape)
	  {
        r2d_retain(r2d_g_default_font_framebuffer);
      
        // refcount set to 1 for creation
        gc->refcount=1;
        R2D_MALLOC(bank,UINT32,sizeof(UINT32)*4,gc->p_foreground_dithered_cache);
        if (gc->p_foreground_dithered_cache)
		{
            R2D_MALLOC(bank,UINT32,sizeof(UINT32)*4,gc->p_background_dithered_cache);
              if (gc->p_background_dithered_cache)
			  {
				if (((T_R2D_FRAMEBUFFER*)the_frame_buffer)->kind==R2D_FULL_KIND)
				{
				  r2d_convert_foreground_color_color(gc,gc->foreground_color);
                  r2d_convert_background_color_color(gc,gc->background_color);
				}
				else
				{
                  r2d_convert_foreground_color(gc,gc->foreground_color);
                  r2d_convert_background_color(gc,gc->background_color);
				}
			  } else // cannot create backround dithered matrix
			  {
                r2d_release_shape(gc->p_clipping_shape);
				r2d_release_shape(gc->p_s_clipping_shape);
                r2d_release_framebuffer(gc->p_frame_buffer);
			    r2d_release_framebuffer(r2d_g_default_font_framebuffer);
                R2D_FREE(((T_R2D_GC *)gc)->p_foreground_dithered_cache);
				R2D_FREE(gc);
                gc=NULL;
			  }
		} else // Cannot create foreground dithered matrix
		{
          r2d_release_shape(gc->p_clipping_shape);
		  r2d_release_shape(gc->p_s_clipping_shape);
          r2d_release_framebuffer(gc->p_frame_buffer);
		  r2d_release_framebuffer(r2d_g_default_font_framebuffer);
		  R2D_FREE(gc);
          gc=NULL;
		}
	  } else // Cannot create clipping shape
	  {
		  R2D_FREE(gc);
		  gc=NULL;
	  }
   }
   else 
   gc=NULL;
   return(gc);
}

T_R2D_GC_PTR r2d_new_lcd_context(T_RVF_MB_ID bank)
{
//   T_R2D_GC *gc;
   T_R2D_GC_PTR result;

   result=r2d_new_context(bank,r2d_g_framebuffer);
   r2d_release_framebuffer(r2d_g_framebuffer);
   return (result);
}

void r2d_release_context(T_R2D_GC_PTR gc)
{
    if (gc)
    {
      if (R2D_REFCOUNT(gc)==1) 
      {
		  // framebuffer release since it is no more used
        r2d_release_framebuffer(((T_R2D_GC *)gc)->font_frame_buffer);
        r2d_release_shape(((T_R2D_GC *)gc)->p_clipping_shape);
	    r2d_release_shape(((T_R2D_GC *)gc)->p_s_clipping_shape);
        r2d_release_framebuffer(((T_R2D_GC *)gc)->p_frame_buffer);
        R2D_FREE((((T_R2D_GC *)gc)->p_foreground_dithered_cache));
        R2D_FREE((((T_R2D_GC *)gc)->p_background_dithered_cache));
      }
    }

    // Autodelete of the gc if required
    r2d_release(gc);
}

T_R2D_GC_PTR r2d_new_picture_context(T_RVF_MB_ID bank,const UINT32 *the_picture,T_R2D_FRAMEBUFFER_KIND kind)
{
   UINT32 h,v,length;
   UINT32 *p;
   T_R2D_FRAMEBUFFER *buf;
   T_R2D_GC_PTR result;
   T_RVF_RET err;

   p=((UINT32*)the_picture)+3;

   h=the_picture[0];
   v=the_picture[1];
   length=the_picture[2];

   rvf_get_buf(bank, sizeof(T_R2D_FRAMEBUFFER), 
   (T_RVF_BUFFER**)&buf);

   if (buf != NULL)
   {

	   
			
           
			
			
   buf->p_memory_words=p; 
   buf->refcount=-1; // Emulate infinite refcount
   buf->kind=kind; 
   buf->p_frame_buffer_end=p+length;
   buf->width=h; 
   buf->height=v; 

   R2D_MALLOC(bank,T_RVF_MUTEX,sizeof(T_RVF_MUTEX),buf->mutex);
   if (buf->mutex!=NULL)
   {
		err=rvf_initialize_mutex(buf->mutex);
		if (err!=RVF_OK)
		{
				 R2D_FREE(buf->mutex);
				 R2D_FREE(buf);
				 buf=NULL;
				 return(buf);
		}
	}
	else
	{
		R2D_FREE(buf);
		buf=NULL;
		return(buf);
	}

   result=r2d_new_context(bank,(T_R2D_FRAMEBUFFER_PTR)buf);
   r2d_release_framebuffer(buf);

   return(result);
   } else return(NULL);
}

void r2d_release_picture_context(T_R2D_GC_PTR gc)
{
    T_R2D_FRAMEBUFFER *fb_p;

    if (gc)
    {
        if (R2D_REFCOUNT(gc) == 1)
        {
            r2d_release_context(gc);
            fb_p = (T_R2D_FRAMEBUFFER *) ((T_R2D_GC *) gc)->p_frame_buffer;
            rvf_delete_mutex(fb_p->mutex);
            R2D_FREE(fb_p->mutex);
            R2D_FREE(fb_p);
        }

        r2d_release(gc);
    }
}

UINT16          r2d_get_width(T_R2D_GC_PTR gc)
{
  return(((T_R2D_FRAMEBUFFER*)((T_R2D_GC *)gc)->p_frame_buffer)->width);
}

UINT16          r2d_get_height(T_R2D_GC_PTR gc)
{
  return(((T_R2D_FRAMEBUFFER*)((T_R2D_GC *)gc)->p_frame_buffer)->height);
}

void           r2d_erase(T_R2D_GC_PTR gc)
{
//   UINT32 *p;
   INT16 x,y;
   T_R2D_ARGB_COLOR col;

   r2d_get_context_origin(gc,&x,&y);

   col=r2d_get_background_color(gc);
   r2d_set_background_color(gc,r2d_get_standard_argb_color(R2D_WHITE));

   
   r2d_fill_rectangle(gc,x-1,y-1,x+r2d_get_width(gc),y+r2d_get_height(gc));
   r2d_set_background_color(gc,col);

   if (((T_R2D_FRAMEBUFFER*)((T_R2D_GC*)gc)->p_frame_buffer)->kind==0)
      r2d_update_region((T_R2D_GC*)gc,x,y,x+r2d_get_width(gc)-1,y+r2d_get_height(gc)-1);
   r2d_check_and_send_event(gc);
}

void           r2d_erase_with_background(T_R2D_GC_PTR gc,
										 INT16 a,INT16 b,
										 INT16 c,INT16 d)
{
   
   r2d_fill_rectangle(gc,a-1,b-1,c+1,d+1);
}

T_R2D_DRAWING_MODE          r2d_get_drawing_mode(T_R2D_GC_PTR gc)
{
   return(((T_R2D_GC *)gc)->drawing_mode);
}

T_R2D_ERROR           r2d_set_drawing_mode(T_R2D_GC_PTR gc,T_R2D_DRAWING_MODE the_mode)
{
  if (the_mode!=((T_R2D_GC *)gc)->drawing_mode)
  {
	  // All modes must be supported in ASM mode

	  if (r2d_get_drawing_op(gc,the_mode)!=NULL)

	  {
	      ((T_R2D_GC *)gc)->drawing_mode=the_mode;
          ((T_R2D_GC *)gc)->drawing_op=r2d_get_drawing_op(gc,the_mode);

		  return(R2D_OK);
	  }

	  else
	   return(R2D_UNKNOWN_OP);

  }
  else
	  return(R2D_OK);
  
  
}

UINT16          r2d_get_pen_size(T_R2D_GC_PTR gc)
{
   return(((T_R2D_GC *)gc)->pen_size);
}

void           r2d_set_pen_size(T_R2D_GC_PTR gc,UINT16 the_size)
{
   ((T_R2D_GC *)gc)->pen_size=the_size;
}

// H COORDINATES
void           r2d_set_context_origin(T_R2D_GC_PTR gc,INT16 x,INT16 y)
{
  INT16 dx,dy;
  T_R2D_RECTANGLE *ra,*rb;

  dx=x-((T_R2D_GC *)gc)->org_x;
  dy=y-((T_R2D_GC *)gc)->org_y;

  ((T_R2D_GC *)gc)->org_x=x;
  ((T_R2D_GC *)gc)->org_y=y;

  r2d_translate_shape(((T_R2D_GC *)gc)->p_clipping_shape,dx,dy);


  ra=r2d_new_rectangle(r2d_mb_id,0,0,0,0);
  rb=r2d_s_level(gc,ra);

  if (rb)
  {
    ((T_R2D_GC *)gc)->s_org_x=rb->ul_x;
    ((T_R2D_GC *)gc)->s_org_y=rb->ul_y;
  }

  r2d_release_shape(ra);
  r2d_release_shape(rb);
  

 // No translation of p_s_clipping_shape which is in S coordinates.
  // Only H coordinates are impacted by the context origin
}

// H COORDINATES
void           r2d_get_context_origin(T_R2D_GC_PTR gc,INT16 *x,INT16 *y)
{
  *x=((T_R2D_GC *)gc)->org_x;
  *y=((T_R2D_GC *)gc)->org_y;
}

// H COORDINATES
void           r2d_local_to_global(T_R2D_GC_PTR gc,INT16 *x,INT16 *y)
{
  *x-=((T_R2D_GC *)gc)->org_x;
  *y-=((T_R2D_GC *)gc)->org_y;
}

// H coordinates
void           r2d_get_pen_pos(T_R2D_GC_PTR gc,INT16 *x,INT16 *y)
{
  *x=((T_R2D_GC *)gc)->pen_x;
  *y=((T_R2D_GC *)gc)->pen_y;
}

BOOLEAN        r2d_dash_enabled(T_R2D_GC_PTR gc)
{
   return(((T_R2D_GC *)gc)->dash);
}

void           r2d_set_dash_state(T_R2D_GC_PTR gc,BOOLEAN enabled)
{
   ((T_R2D_GC *)gc)->dash=enabled;
}

static void r2d_change_font(T_R2D_GC_PTR gc,T_R2D_FONT_DESCRIPTION *desc)
{
   r2d_retain(desc->framebuffer);
   r2d_release_framebuffer(((T_R2D_GC *)gc)->font_frame_buffer);
   ((T_R2D_GC *)gc)->font_frame_buffer=desc->framebuffer;

   ((T_R2D_GC *)gc)->font_metrics=desc->metrics;
   ((T_R2D_GC *)gc)->font_table=desc->table;
}

static T_R2D_FONT_DESCRIPTION *r2d_get_desc(T_R2D_GC_PTR gc)
{
    INT16 f;
	INT16 s;
	INT16 t;
	T_R2D_FONT_DESCRIPTION *p;
	INT16 temp;

	p=r2d_g_font_configuration;

	f=r2d_get_text_face(gc)-1;
    s=r2d_get_text_size(gc)-1;
    t=r2d_get_text_style(gc) & (R2D_BOLD | R2D_ITALIC);

	t=t-(t>>1);

	temp=(f<<2) + (f<<3) + (s<<2) + t;
	p=r2d_g_font_configuration+(temp);

	return(p);
}

void           r2d_set_text_face(T_R2D_GC_PTR gc,T_R2D_TEXT_FACE the_face)
{
  ((T_R2D_GC *)gc)->text_face=the_face;

  r2d_change_font(gc,r2d_get_desc(gc));

}

T_R2D_TEXT_FACE r2d_get_text_face(T_R2D_GC_PTR gc)
{
  return(((T_R2D_GC *)gc)->text_face);
}


void           r2d_set_text_style(T_R2D_GC_PTR gc,T_R2D_TEXT_STYLE the_style)
{
  T_R2D_FONT_DESCRIPTION *desc;

  ((T_R2D_GC *)gc)->text_style=the_style;

  // Clear italic bit;
  the_style=the_style & (~R2D_ITALIC);
  
  // Clear bold bit if desc for Bold is not NULL
  desc=r2d_get_desc(gc);
  if (!desc->compute_bold)
     the_style=the_style & (~R2D_BOLD);
  
  
  ((T_R2D_GC *)gc)->internal_text_style=the_style;

  r2d_change_font(gc,r2d_get_desc(gc));
  
}

T_R2D_TEXT_STYLE r2d_get_text_style(T_R2D_GC_PTR gc)
{
 return(((T_R2D_GC *)gc)->text_style);
}


void           r2d_set_text_size(T_R2D_GC_PTR gc,T_R2D_TEXT_SIZE the_size)
{
  ((T_R2D_GC *)gc)->text_size=the_size;
  r2d_change_font(gc,r2d_get_desc(gc));
}

T_R2D_TEXT_SIZE r2d_get_text_size(T_R2D_GC_PTR gc)
{
  return(((T_R2D_GC *)gc)->text_size);
}

T_R2D_ERROR r2d_context_lock(T_R2D_GC_PTR gc)
{
	T_RVF_RET err;
	err=RVF_OK;
	err=rvf_lock_mutex(((T_R2D_FRAMEBUFFER*)((T_R2D_GC*)gc)->p_frame_buffer)->mutex);
	if (err!=RVF_OK)
		return(R2D_LOCK_ERROR);
	else
	    return(R2D_OK);
}

T_R2D_ERROR r2d_context_unlock(T_R2D_GC_PTR gc)
{
	T_RVF_RET err;
	err=RVF_OK;
	err=rvf_unlock_mutex(((T_R2D_FRAMEBUFFER*)((T_R2D_GC*)gc)->p_frame_buffer)->mutex);
	if (err!=RVF_OK)
		return(R2D_UNLOCK_ERROR);
	else
	    return(R2D_OK);
}

// Return the a pointer to the memory area containing
// pixels for the graphic context gc
//
UINT32*        r2d_get_pixmap(T_R2D_GC_PTR gc)
{
	T_R2D_GC *src;
	T_R2D_FRAMEBUFFER *src_f;
	UINT32 *ps;

    src=(T_R2D_GC*)gc;
	src_f=(T_R2D_FRAMEBUFFER*)(src->p_frame_buffer);
    ps=src_f->p_memory_words;

	return(ps);
}

// Force the flushing of LCD framebuffer to display its
// content 
void r2d_flush(void)
{
	r2d_update_region(NULL,0,
		  0,
		  R2D_WIDTH-1,
		  R2D_HEIGHT-1);
    r2d_check_and_send_event(r2d_g_lcd_gc);
}

// xreddymn Apr-06-2005 MMI-SPR-29655
// Force the flushing of a portion of LCD framebuffer to display its
// content 
void r2d_flush_region(INT16 ul_x,INT16 ul_y,INT16 br_x,INT16 br_y)
{
	r2d_update_region(NULL, ul_x,
		  ul_y,
		  br_x,
		  br_y);
    r2d_check_and_send_event(r2d_g_lcd_gc);
}

void    r2d_disable_refresh(void) 
{
	rvf_lock_mutex(r2d_g_global_mutex);
	r2d_g_refresh_disabled++;
	//rvf_send_trace("R2D : disable refresh\n",sizeof("R2D : disable refresh\n"), NULL_PARAM, 
	//			   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );
	rvf_unlock_mutex(r2d_g_global_mutex);
}

void r2d_enable_refresh(void) 
{
	//rvf_send_trace("R2D : enable refresh\n",sizeof("R2D : enable refresh\n"), NULL_PARAM, 
	//			   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );
	rvf_lock_mutex(r2d_g_global_mutex);
	r2d_g_refresh_disabled--;
    if (r2d_g_refresh_disabled==0)
	{
		//rvf_send_trace("R2D : flush\n",sizeof("R2D : flush\n"), NULL_PARAM, 
				   //RV_TRACE_LEVEL_ERROR, R2D_USE_ID );
	  //rvf_send_trace("Enable refresh and flush",sizeof("Enable refresh and flush")-1, NULL_PARAM, 
	  //		   RV_TRACE_LEVEL_DEBUG_HIGH, R2D_USE_ID );
		// The flush will not raise a context commutation to R2D since R2D may
		// be sleeping waiting for the current refresh perio.
		// So, the event will not be processed at once. While R2D is sleeping,
		// another task may call r2d_disable_refresh and thus
		// when R2D is awaken, it will not process the event which is waiting.
		// So, finally, the display will not be refreshed.
		// To avoid this problem which occurs for a quick succession of
		// r2d_disable_refresh
		// r2d_enable_refresh
		// one should try to call them with a rate which is lower than the refresh rate
        rvf_unlock_mutex(r2d_g_global_mutex);
		//r2d_flush();
		
        r2d_check_and_send_event(r2d_g_lcd_gc);
	}
	else
	rvf_unlock_mutex(r2d_g_global_mutex);
}

////////////////////////////////////////
//
// Colors
//


// Return ARGB foreground color for the gc
T_R2D_ARGB_COLOR r2d_get_foreground_color(T_R2D_GC_PTR gc)
{
  return (((T_R2D_GC*)gc)->foreground_color);
}

// Set ARGB foreground color for the gc
// (Alpha channel not yet supported)
void r2d_set_foreground_color_with_argb(T_R2D_GC_PTR gc,UINT16 alpha,UINT16 red,UINT16 green,UINT16 blue)
{
 UINT32 color;
 color=r2d_new_argb_color(alpha,red,green,blue);
 if (color !=((T_R2D_GC*)gc)->foreground_color)
 {
   ((T_R2D_GC*)gc)->foreground_color=color;

   if (((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)gc)->p_frame_buffer))->kind==R2D_FULL_KIND)
r2d_convert_foreground_color_color(gc,color);
   else
   r2d_convert_foreground_color(gc,color);
 }
}

// Set ARGB foreground color for the gc
// (Alpha channel not yet supported)
void r2d_set_foreground_color(T_R2D_GC_PTR gc,T_R2D_ARGB_COLOR color)
{
 if (color !=((T_R2D_GC*)gc)->foreground_color)
 {
   ((T_R2D_GC*)gc)->foreground_color=color;
   if (((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)gc)->p_frame_buffer))->kind==R2D_FULL_KIND)
  r2d_convert_foreground_color_color(gc,color);
	   else
   r2d_convert_foreground_color(gc,color);
 }
}

// Return ARGB foreground color for the gc
T_R2D_ARGB_COLOR r2d_get_background_color(T_R2D_GC_PTR gc)
{
  return (((T_R2D_GC*)gc)->background_color);
}

// Set ARGB foreground color for the gc
// (Alpha channel not yet supported)
void r2d_set_background_color_with_argb(T_R2D_GC_PTR gc,UINT16 alpha,UINT16 red,UINT16 green,UINT16 blue)
{
 UINT32 color;
 color=r2d_new_argb_color(alpha,red,green,blue);
 if (color !=((T_R2D_GC*)gc)->background_color)
 {
   ((T_R2D_GC*)gc)->background_color=color;
   if (((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)gc)->p_frame_buffer))->kind==R2D_FULL_KIND)
  r2d_convert_background_color_color(gc,color);
	   else
   r2d_convert_background_color(gc,color);
 }
}

// Set ARGB foreground color for the gc
// (Alpha channel not yet supported)
void r2d_set_background_color(T_R2D_GC_PTR gc,T_R2D_ARGB_COLOR color)
{
 if (color !=((T_R2D_GC*)gc)->background_color)
 {
   ((T_R2D_GC*)gc)->background_color=color;
   if (((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)gc)->p_frame_buffer))->kind==R2D_FULL_KIND)
	   r2d_convert_background_color_color(gc,color);
  else
   r2d_convert_background_color(gc,color);
 }
}

void   r2d_set_background_texture(T_R2D_GC_PTR gc,T_R2D_ANCHORED_TEXTURE_PTR texture)
{
	
//    INT16 length;
//	T_R2D_ANCHORED_TEXTURE *t;

	// If a texture is already in place try to release it
	if (((T_R2D_GC*)gc)->background_texture!=NULL)
	{
		r2d_release_anchored_texture(((T_R2D_GC*)gc)->background_texture);
		((T_R2D_GC*)gc)->background_texture=NULL;
	}
	

	((T_R2D_GC*)gc)->background_texture=texture;
     

   if (texture!=NULL)
   {
     r2d_retain(texture);
   }

  

	
}

T_R2D_ANCHORED_TEXTURE_PTR r2d_get_background_texture(T_R2D_GC_PTR gc)
{
	return ((T_R2D_GC*)gc)->background_texture;
}

T_R2D_ARGB_COLOR         r2d_new_argb_color(UINT16 alpha,UINT16 red,UINT16 green,UINT16 blue)
{
   T_R2D_ARGB_COLOR col;
   col=0;

   col=col|(alpha&0xFF);
   col=col<<8;
   col=col|(red&0xFF);
   col=col<<8;
   col=col|(green&0xFF);
   col=col<<8;
   col=col|(blue&0xFF);
  
   return(col);
}

T_R2D_ARGB_COLOR         r2d_get_argb_color_at_point(T_R2D_GC_PTR gc,INT16 x,INT16 y)
{
  UINT32 result;
  if (r2d_point_in_shape(((T_R2D_GC*)gc)->p_clipping_shape,x,y))
  {
	r2d_local_to_global(gc,&x,&y);
	#ifdef R2D_MIRRORED_X
	
	  x=r2d_get_width(gc)-1-x;
    #endif

    #ifdef R2D_MIRRORED_Y
	  y=r2d_get_height(gc)-1-y;
    #endif
	
#if (R2D_REFRESH == R2D_VERTICAL)
	result=IND_r2d_get_color_pixel_value(gc,x,y);
#else
	result=IND_r2d_get_color_pixel_value(gc,y,x);
#endif
    return(result);
  } 
  else
  return(0);
}

T_R2D_ARGB_COLOR         r2d_get_standard_argb_color(T_R2D_COLOR_REF ref)
{
  switch(ref)
  {
     case R2D_RED: return(r2d_new_argb_color(0,255,0,0)); break;
     case R2D_BLUE:return(r2d_new_argb_color(0,0,0,255)); break;
     case R2D_GREEN:return(r2d_new_argb_color(0,0,255,0)); break;
     case R2D_WHITE:return(r2d_new_argb_color(0,255,255,255)); break;
     case R2D_BLACK:return(r2d_new_argb_color(0,0,0,0)); break;
     case R2D_GRAY50:return(r2d_new_argb_color(0,127,127,12)); break;
     default:return(r2d_new_argb_color(0,0,0,0)); break;
  }
}

// h from 0 to 360 : 
// s from 0 to 1 : 1 is 0x800000
// v from 0 to 1
// r,g,b from 0 to 1
// Value in Q8
void r2d_hsv_to_rgb( INT16 *r, INT16 *g, INT16 *b, INT32 h, INT32 s, INT32 v )
{
        int i;
        INT32 f, p, q, t;

		//s and v in Q8. So 255 is FF is 1
		
        if( s == 0 ) {
                // achromatic (grey)
                *r = *g = *b = (v>>13);
                return;
        }
        h = h * (0x3000000 >> 8) ; // 360/256 / 60 ;Q23 ; sector 0 to 5
        i = h & 0xFF800000;
        f = h - i;                      // factorial part of h
		i=i>>15;
        f = f >> 15; // Q16
        p = (v * ( 0x100 - s )) >> 8;
        q = (v * ( 0x100 - ((s * f) >> 8) )) >> 8;
        t = (v * ( 0x100 - ((s * ( 0x100 - f )) >> 8) )) >> 8;
        switch( i>>8 ) {
                case 0:
                        *r = v;
                        *g = t;
                        *b = p;
                        break;
                case 1:
                        *r = q;
                        *g = v;
                        *b = p;
                        break;
                case 2:
                        *r = p;  
                        *g = v;
                        *b = t;
                        break;
                case 3:
                        *r = p;
                        *g = q;
                        *b = v;
                        break;
                case 4:
                        *r = t;
                        *g = p;
                        *b = v;
                        break; 
                default:                // case 5:
                        *r = v;
                        *g = p;
                        *b = q;
                        break; 
        }
}

////////////////////////////////////////
//
// Shapes
//

// H COORDINATES ...
void r2d_draw_shape(T_R2D_SHAPE_PTR self,T_R2D_GC_PTR gc)
{
	
    if (self)
	{
		((T_R2D_SHAPE*)self)->p_r2d_class->draw(self,gc);
	  
	}
}

void r2d_fill_shape(T_R2D_SHAPE_PTR self,T_R2D_GC_PTR gc)
{
    if (self)
	{
      ((T_R2D_SHAPE*)self)->p_r2d_class->fill(self,gc);
	  
	}
}

void r2d_release_shape(T_R2D_SHAPE_PTR self)
{


   if (self)
     ((T_R2D_SHAPE*)self)->p_r2d_class->release(self);
}

T_R2D_SHAPE_PTR r2d_clone_shape(T_RVF_MB_ID bank,T_R2D_SHAPE_PTR self)
{
   if (self)
     return (((T_R2D_SHAPE*)self)->p_r2d_class->clone(bank,self));
   else
     return(NULL);
}

void r2d_translate_shape(T_R2D_SHAPE_PTR self,INT16 dx,INT16 dy)
{
   if (self)
     ((T_R2D_SHAPE*)self)->p_r2d_class->translate(self,dx,dy);
     
} 

BOOLEAN r2d_point_in_shape(T_R2D_SHAPE_PTR self,INT16 x,INT16 y)
{

  if (self)
     return(((T_R2D_SHAPE*)self)->p_r2d_class->point_in_shape(self,x,y));
  else
      return(FALSE);

}


BOOLEAN r2d_point_in_rectangle_shape(T_R2D_SHAPE* self,INT16 x,INT16 y)
{
	T_R2D_RECTANGLE *r;

	r=(T_R2D_RECTANGLE*)self;

    return (((x>=r2d_get_xmin(self))
    && (x<r2d_get_xmax(self))
    && (y>=r2d_get_ymin(self))
    && (y<r2d_get_ymax(self))));
}

BOOLEAN r2d_point_in_circle_shape(T_R2D_SHAPE* self,INT16 x,INT16 y)
{
	T_R2D_CIRCLE *c;
	c=(T_R2D_CIRCLE*)self;

	return((x-c->x)*(x-c->x)+(y-c->y)*(y-c->y)-c->r*c->r<0);
}

BOOLEAN r2d_point_in_ellipse_shape(T_R2D_SHAPE* self,INT16 x,INT16 y)
{
	T_R2D_ELLIPSE *c;
	INT32 a,b,cx,cy,nx,ny;

	c=(T_R2D_ELLIPSE*)self;
	// Work on Q1
	
	// a is half width so no <<1 is used here
	a=(c->br_x-c->ul_x);
	b=(c->br_y-c->ul_y);

	nx=x<<1;
	ny=y<<1;

	cx=((c->ul_x)<<1)+a;
    cy=((c->ul_y)<<1)+b;

    //b^2*x^2+a^2y^2-a^2b^2=0

	return((b*b*(nx-cx)*(nx-cx)+a*a*(ny-cy)*(ny-cy)-a*a*b*b)<0);

}

BOOLEAN r2d_point_in_round_rectangle_shape(T_R2D_SHAPE* self,INT16 x,INT16 y)
{
  T_R2D_ROUND_RECTANGLE *r;
  BOOLEAN result;

  result=FALSE;
  r=(T_R2D_ROUND_RECTANGLE *)self;

  if ((x>=r->ul_x+r->h+1) && (x<r->br_x-r->h) && (y>=r->ul_y) && (y<r->br_y))
	  result=TRUE;
  else if ((x>=r->ul_x) && (x<r->br_x) && (y>=r->ul_y+r->v+1) && (y<r->br_y-r->v))
	  result=TRUE;
  else
  {
	  INT32 a,b,cx,cy,nx,ny;

      if (x>=r->br_x-r->h)
		  x=x-(r->br_x-r->ul_x)+((r->h)<<1);

      if (y>=r->br_y-r->v)
	      y=y-(r->br_y-r->ul_y)+((r->v)<<1);

	  
	  a=(r->h<<1);
	  b=(r->v<<1);

	  nx=x<<1;
	  ny=y<<1;

	  cx=((r->ul_x)<<1)+a;
      cy=((r->ul_y)<<1)+b;

    //b^2*x^2+a^2y^2-a^2b^2=0

	 result=(b*b*(nx-cx)*(nx-cx)+a*a*(ny-cy)*(ny-cy)-a*a*b*b)<0;

   
  }
  
  return(result);
  
}

BOOLEAN r2d_point_in_not_supported_shape(T_R2D_SHAPE* self,INT16 x,INT16 y)
{
    return FALSE;
}

void r2d_translate_rectangle_shape(T_R2D_SHAPE* self,INT16 dx,INT16 dy)
{
   T_R2D_RECTANGLE *r;
   r=(T_R2D_RECTANGLE *)self;
   r->ul_x+=dx;
   r->ul_y+=dy;
   r->br_x+=dx;
   r->br_y+=dy;
} 

void r2d_translate_point_shape(T_R2D_SHAPE* self,INT16 dx,INT16 dy)
{
   T_R2D_CIRCLE *r;
   r=(T_R2D_CIRCLE *)self;
   r->x+=dx;
   r->y+=dy;
} 


T_R2D_SHAPE_PTR r2d_new_rectangle(T_RVF_MB_ID bank,INT16 ul_x,INT16 ul_y,INT16 br_x,INT16 br_y)
{
  T_R2D_RECTANGLE *r;
  T_R2D_ERROR err;
  err=R2D_MALLOC(bank,T_R2D_RECTANGLE,sizeof(T_R2D_RECTANGLE),r);
  if (r)
  {
  r->refcount=1;
  r->ul_x=ul_x;
  r->ul_y=ul_y;
  r->br_x=br_x;
  r->br_y=br_y;
  r->p_r2d_class=&r2d_class_rectangle;
  } else r=NULL;
  return(r);
}

void r2d_release_rectangle(T_R2D_SHAPE* self)
{
   T_R2D_RECTANGLE *r;
   r=(T_R2D_RECTANGLE *)self;

   r2d_release(r);
}

T_R2D_SHAPE_PTR r2d_clone_rectangle_shape(T_RVF_MB_ID bank,T_R2D_SHAPE* self)
{
   T_R2D_RECTANGLE *r;
   r=(T_R2D_RECTANGLE *)self;

   return(r2d_new_rectangle(bank,r->ul_x,r->ul_y,r->br_x,r->br_y));
}

void r2d_draw_rectangle_shape(T_R2D_SHAPE* self,T_R2D_GC_PTR gc)
{
   T_R2D_RECTANGLE *r;
   r=(T_R2D_RECTANGLE *)self;
   r2d_draw_rectangle(gc,r->ul_x,r->ul_y,r->br_x,r->br_y);
}

void r2d_fill_rectangle_shape(T_R2D_SHAPE* self,T_R2D_GC_PTR gc)
{
   T_R2D_RECTANGLE *r;
   r=(T_R2D_RECTANGLE *)self;
   r2d_fill_rectangle(gc,r->ul_x,r->ul_y,r->br_x,r->br_y);
}


void r2d_release_circle(T_R2D_SHAPE* self)
{
   T_R2D_CIRCLE *r;
   r=(T_R2D_CIRCLE *)self;

   r2d_release(r);

   #if (R2D_DEBUG == R2D_ON)
   r=NULL;
   #endif
}

T_R2D_SHAPE_PTR r2d_clone_circle_shape(T_RVF_MB_ID bank,T_R2D_SHAPE* self)
{
   T_R2D_CIRCLE *r;
   r=(T_R2D_CIRCLE *)self;

   return(r2d_new_circle(bank,r->x,r->y,r->r));
}

void r2d_draw_circle_shape(T_R2D_SHAPE* self,T_R2D_GC_PTR gc)
{
   T_R2D_CIRCLE *r;
   r=(T_R2D_CIRCLE *)self;
   r2d_draw_circle(gc,r->x,r->y,r->r);
}

void r2d_fill_circle_shape(T_R2D_SHAPE* self,T_R2D_GC_PTR gc)
{
   T_R2D_CIRCLE *r;
   r=(T_R2D_CIRCLE *)self;
   r2d_fill_circle(gc,r->x,r->y,r->r);
}

T_R2D_SHAPE_PTR r2d_new_circle(T_RVF_MB_ID bank,INT16 x,INT16 y,INT16 r)
{
  T_R2D_CIRCLE *c;
  R2D_MALLOC(bank,T_R2D_CIRCLE,sizeof(T_R2D_CIRCLE),c);
  if (c)
  {
  c->refcount=1;
  c->x=x;
  c->y=y;
  c->r=r;
  c->p_r2d_class=&r2d_class_circle;
  } else c=NULL;
  return(c);
}

void r2d_release_ellipse(T_R2D_SHAPE* self)
{
   T_R2D_ELLIPSE *r;
   r=(T_R2D_ELLIPSE *)self;

   r2d_release(r);
#if (R2D_DEBUG == R2D_ON)
   r=NULL;
#endif
}

void r2d_draw_ellipse_shape(T_R2D_SHAPE* self,T_R2D_GC_PTR gc)
{
   T_R2D_ELLIPSE *r;
   r=(T_R2D_ELLIPSE *)self;
   r2d_draw_ellipse(gc,r->ul_x,r->ul_y,r->br_x,r->br_y);
}

void r2d_fill_ellipse_shape(T_R2D_SHAPE* self,T_R2D_GC_PTR gc)
{
   T_R2D_ELLIPSE *r;
   r=(T_R2D_ELLIPSE *)self;
   r2d_fill_ellipse(gc,r->ul_x,r->ul_y,r->br_x,r->br_y);
}

T_R2D_SHAPE_PTR r2d_new_ellipse(T_RVF_MB_ID bank,INT16 ul_x,INT16 ul_y,INT16 br_x,INT16 br_y)
{
  T_R2D_ELLIPSE *r;
  R2D_MALLOC(bank,T_R2D_ELLIPSE,sizeof(T_R2D_ELLIPSE),r);
  if (r)
  {
  r->refcount=1;
  r->ul_x=ul_x;
  r->ul_y=ul_y;
  r->br_x=br_x;
  r->br_y=br_y;
  r->p_r2d_class=&r2d_class_ellipse;
  } else r=NULL;
  return(r);
}

void r2d_release_round_rectangle(T_R2D_SHAPE* self)
{
   T_R2D_ROUND_RECTANGLE *r;
   r=(T_R2D_ROUND_RECTANGLE *)self;

   r2d_release(r);
   #if (R2D_DEBUG == R2D_ON)
   r=NULL;
#endif
}

void r2d_draw_round_rectangle_shape(T_R2D_SHAPE* self,T_R2D_GC_PTR gc)
{
   T_R2D_ROUND_RECTANGLE *r;
   r=(T_R2D_ROUND_RECTANGLE *)self;
   r2d_draw_round_rectangle(gc,r->ul_x,r->ul_y,r->br_x,r->br_y,r->h,r->v);
}

void r2d_fill_round_rectangle_shape(T_R2D_SHAPE* self,T_R2D_GC_PTR gc)
{
   T_R2D_ROUND_RECTANGLE *r;
   r=(T_R2D_ROUND_RECTANGLE *)self;
   r2d_fill_round_rectangle(gc,r->ul_x,r->ul_y,r->br_x,r->br_y,r->h,r->v);
}

T_R2D_SHAPE_PTR r2d_clone_round_rectangle_shape(T_RVF_MB_ID bank,T_R2D_SHAPE* self)
{
   T_R2D_ROUND_RECTANGLE *r;
   r=(T_R2D_ROUND_RECTANGLE *)self;

   return(r2d_new_round_rectangle(bank,r->ul_x,r->ul_y,r->br_x,r->br_y,r->h,r->v));
}

T_R2D_SHAPE_PTR r2d_new_round_rectangle(T_RVF_MB_ID bank,INT16 ul_x,INT16 ul_y,INT16 br_x,INT16 br_y,INT16 h,INT16 v)
{
  T_R2D_ROUND_RECTANGLE *r;
  R2D_MALLOC(bank,T_R2D_ROUND_RECTANGLE,sizeof(T_R2D_ROUND_RECTANGLE),r);
  if (r)
  {
  r->refcount=1;
  r->ul_x=ul_x;
  r->ul_y=ul_y;
  r->br_x=br_x;
  r->br_y=br_y;
  r->h=h;
  r->v=v;
  r->p_r2d_class=&r2d_class_round_rectangle;
  } else r=NULL;
  return(r);
}

T_R2D_SHAPE_PTR r2d_clone_arc_shape(T_RVF_MB_ID bank,T_R2D_SHAPE* self)
{
   T_R2D_ARC *r;
   r=(T_R2D_ARC *)self;

   return(r2d_new_arc(bank,r->start_angle,r->stop_angle,r->ul_x,r->ul_y,r->br_x,r->br_y));
}

T_R2D_SHAPE_PTR r2d_new_arc(T_RVF_MB_ID bank,INT16 start_angle, INT16 stop_angle,INT16 ul_x,INT16 ul_y,
                                         INT16 br_x,INT16 br_y)
{
  T_R2D_ARC *r;
  R2D_MALLOC(bank,T_R2D_ARC,sizeof(T_R2D_ARC),r);
  if (r)
  {
  r->refcount=1;
  r->ul_x=ul_x;
  r->ul_y=ul_y;
  r->br_x=br_x;
  r->br_y=br_y;
  r->start_angle=start_angle;
  r->stop_angle=stop_angle;
  r->p_r2d_class=&r2d_class_arc;
  } else r=NULL;
  return(r);
}

void r2d_release_arc(T_R2D_SHAPE *self)
{
  T_R2D_ARC *r;
  r=(T_R2D_ARC *)self;

  r2d_release(r);
}

void r2d_draw_arc_shape(T_R2D_SHAPE *self,T_R2D_GC_PTR gc)
{
  T_R2D_ARC *r;
  r=(T_R2D_ARC *)self;

	r2d_draw_arc(gc,r->start_angle,r->stop_angle,
                  r->ul_x,r->ul_y,r->br_x,r->br_y);
}

void r2d_fill_arc_shape(T_R2D_SHAPE *self,T_R2D_GC_PTR gc)
{
 T_R2D_ARC *r;
  r=(T_R2D_ARC *)self;

	r2d_fill_arc(gc,r->start_angle,r->stop_angle,
                  r->ul_x,r->ul_y,r->br_x,r->br_y);
}

T_R2D_SHAPE_PTR r2d_new_rectangle_intersection(T_RVF_MB_ID bank,T_R2D_SHAPE_PTR a,T_R2D_SHAPE_PTR b)
{
if ( a && b && (((T_R2D_SHAPE*)a)->p_r2d_class==&r2d_class_rectangle)
&& (((T_R2D_SHAPE*)b)->p_r2d_class==&r2d_class_rectangle))
{
	T_R2D_RECT *ra;
	T_R2D_RECT *rb;
	INT16 xa,ya,xb,yb;

	ra=(T_R2D_RECT *)a;
	rb=(T_R2D_RECT *)b;

    if (ra->ul_x>rb->ul_x)
		xa=ra->ul_x;
	else
		xa=rb->ul_x;

    if (ra->ul_y>rb->ul_y)
		ya=ra->ul_y;
	else
		ya=rb->ul_y;

	if (ra->br_x<rb->br_x)
		xb=ra->br_x;
	else
		xb=rb->br_x;

    if (ra->br_y<rb->br_y)
		yb=ra->br_y;
	else
		yb=rb->br_y;

	if ((xa<=xb) && (ya<=yb))
		return(r2d_new_rectangle(bank,xa,ya,xb,yb));
	else
		return(R2D_EMPTY_RECT);

}
else return(NULL);
}

T_R2D_SHAPE_PTR r2d_new_rectangle_union(T_RVF_MB_ID bank,T_R2D_SHAPE_PTR a,T_R2D_SHAPE_PTR b)
{
	if ( a && b && (((T_R2D_SHAPE*)a)->p_r2d_class==&r2d_class_rectangle)
&& (((T_R2D_SHAPE*)b)->p_r2d_class==&r2d_class_rectangle))
{
	T_R2D_RECTANGLE *ra;
	T_R2D_RECTANGLE *rb;
	INT16 xa,ya,xb,yb;

	ra=(T_R2D_RECTANGLE *)a;
	rb=(T_R2D_RECTANGLE *)b;

    if (ra->ul_x<rb->ul_x)
		xa=ra->ul_x;
	else
		xa=rb->ul_x;

    if (ra->ul_y<rb->ul_y)
		ya=ra->ul_y;
	else
		ya=rb->ul_y;

	if (ra->br_x>rb->br_x)
		xb=ra->br_x;
	else
		xb=rb->br_x;

    if (ra->br_y>rb->br_y)
		yb=ra->br_y;
	else
		yb=rb->br_y;

	if ((xa<=xb) && (ya<=yb))
		return(r2d_new_rectangle(bank,xa,ya,xb,yb));
	else
		return(R2D_EMPTY_RECT);

}
else if (a) 
return(r2d_clone_shape(bank,a));
else if (b)
return(r2d_clone_shape(bank,b));
else
return(NULL);
}

T_R2D_SHAPE_PTR r2d_new_text(T_RVF_MB_ID bank,INT16 x, INT16 y,T_R2D_UTF16 *the_text)
{
  T_R2D_TEXT *r;
  R2D_MALLOC(bank,T_R2D_TEXT,sizeof(T_R2D_TEXT),r);
  if (r)
  {
  r->refcount=1;
  r->x=x;
  r->y=y;
  r->p_text=the_text;
  r->p_r2d_class=&r2d_class_text;
  } else r=NULL;
  return(r);
}

T_R2D_SHAPE_PTR r2d_clone_text_shape(T_RVF_MB_ID bank,T_R2D_SHAPE* self)
{
   T_R2D_TEXT *r;
   r=(T_R2D_TEXT *)self;

   return(r2d_new_text(bank,r->x,r->y,NULL));
}


void r2d_release_text(T_R2D_SHAPE *self)
{
  T_R2D_TEXT *r;
  r=(T_R2D_TEXT *)self;

  r2d_release(r);
}

void r2d_draw_text_shape(T_R2D_SHAPE *self,T_R2D_GC_PTR gc)
{
	T_R2D_TEXT *r;
	r=(T_R2D_TEXT *)self;
	r2d_draw_text(gc,r->x,r->y,r->p_text);
}

void r2d_fill_text_shape(T_R2D_SHAPE *self,T_R2D_GC_PTR gc)
{
    // A text has no interior and thus cannot be filled.
}




////////////////////////////////////////
//
// Clipping functions
//

// Conversion is done such that line y = ymax and x=xmax MUST NOT
// be drawn. So, they do not belong to the cliiping region
// So, behavior of s_clipping_shape is using drawing convention
// and not the clipping convention
static T_R2D_SHAPE_PTR r2d_s_level(T_R2D_GC_PTR gc,T_R2D_SHAPE_PTR self)
{
	T_R2D_SHAPE_PTR result;
	T_R2D_RECTANGLE *r;

	
	r=(T_R2D_RECTANGLE*)self;

	if ((r) && (gc))
	{

	result=r2d_clone_shape(r2d_mb_id,self);
	r=(T_R2D_RECTANGLE*)result;

	r2d_local_to_global(gc,&(r->ul_x),&(r->ul_y));
	r2d_local_to_global(gc,&(r->br_x),&(r->br_y));

	//r2d_mirror_clip_rectangle(gc,result);
	r2d_mirror_rectangle(gc,result);
	r=(T_R2D_RECTANGLE*)result;

#if (R2D_REFRESH != R2D_VERTICAL)
	r2d_diagonal_mirror(result);
	r=(T_R2D_RECTANGLE*)result;
#endif
	
	return(result);
	}
	else
		return(NULL);
}

void r2d_set_clipping_shape(T_R2D_SHAPE_PTR self,T_R2D_GC_PTR gc)
{

   if ((self) && (((T_R2D_SHAPE*)self)->p_r2d_class==&r2d_class_rectangle))
   {
       T_R2D_RECT *r;
	   INT16 orgx,orgy;

       r=(T_R2D_RECT *)self;

	   r2d_get_context_origin(gc,&orgx,&orgy);

	   if (r->ul_x-orgx<0)
		   r->ul_x=orgx;

	   if (r->ul_y-orgy<0)
		   r->ul_y=orgy;

	   if (r->br_x-orgx>=r2d_get_width(gc))
		   r->br_x=orgx+r2d_get_width(gc);

	   if (r->br_y-orgy>=r2d_get_height(gc))
		  r->br_y=orgy+r2d_get_height(gc);

		  
       {
       r2d_release_shape(((T_R2D_GC *)gc)->p_clipping_shape);
       ((T_R2D_GC *)gc)->p_clipping_shape=self;
       r2d_retain(self);

	   r2d_release_shape(((T_R2D_GC *)gc)->p_s_clipping_shape);
       ((T_R2D_GC *)gc)->p_s_clipping_shape=r2d_s_level(gc,self);
	   }
   }
}

T_R2D_SHAPE_PTR r2d_get_clipping_shape(T_R2D_GC_PTR gc)
{
   return(((T_R2D_GC *)gc)->p_clipping_shape);
}

T_R2D_ERROR r2d_restore_standard_clipping_shape(T_R2D_GC_PTR gc)
{
    INT16 x,y;
	T_R2D_SHAPE_PTR s,sb;
    r2d_get_context_origin(gc,&x,&y);
	s=((T_R2D_GC *)gc)->p_clipping_shape;
	sb=((T_R2D_GC *)gc)->p_s_clipping_shape;
    
    ((T_R2D_GC *)gc)->p_clipping_shape=r2d_new_rectangle(r2d_mb_id,x,y,x+r2d_get_width(gc),y+r2d_get_height(gc));
    
// No mirroring when shape is the whole LCD
// Force use of global coordinates for s_ frame
#if (R2D_REFRESH == R2D_VERTICAL)
	((T_R2D_GC *)gc)->p_s_clipping_shape=
		r2d_new_rectangle(r2d_mb_id,0,0,r2d_get_width(gc),r2d_get_height(gc));
#else
	((T_R2D_GC *)gc)->p_s_clipping_shape=
		r2d_new_rectangle(r2d_mb_id,0,0,r2d_get_height(gc),r2d_get_width(gc));
#endif

	 
	if ((((T_R2D_GC *)gc)->p_clipping_shape==NULL) 
		|| (((T_R2D_GC *)gc)->p_s_clipping_shape==NULL))
	{
		if (((T_R2D_GC *)gc)->p_clipping_shape!=NULL)
          r2d_release_shape(((T_R2D_GC *)gc)->p_clipping_shape);
		if (((T_R2D_GC *)gc)->p_s_clipping_shape!=NULL)
          r2d_release_shape(((T_R2D_GC *)gc)->p_s_clipping_shape);
        ((T_R2D_GC *)gc)->p_clipping_shape=s;
		((T_R2D_GC *)gc)->p_s_clipping_shape=sb;
		return(R2D_MEMORY_ERR);
	}
	else
	{
	    r2d_release_shape(s);
		r2d_release_shape(sb);
		return(R2D_OK);
	}
}


////////////////////////////////////////
//
// Graphical primitives
//

// S COORDINATES
static void r2d_s_fill_point(T_R2D_GC_PTR gc,INT16 x,INT16 y,INT16 pen_size)
{
    INT16 ul_x,ul_y,br_x,br_y,bs,as;
//    UINT32 f,b;

    bs=(pen_size>>1);
    as=(pen_size>>1) + (pen_size&1);

	// Squares are not symetrically placed
	// since pen_size is not always odd
    // Mirroring must take it into account so that the
	// asymetry is also mirrored
#ifdef R2D_MIRRORED_X
    ul_x=x-bs;
	br_x=x+as-1;
#else
	ul_x=x-bs+1;
	br_x=x+as;
    
#endif

#ifdef R2D_MIRRORED_Y
    ul_y=y-bs;
    br_y=y+as-1;
#else
    ul_y=y-bs+1;
    br_y=y+as;
#endif

    //printf("%d %d %d %d\n",ul_x,ul_y,br_x,br_y);

	
    r2d_s_fill_rectangle(gc,ul_x-1,ul_y-1,br_x+1,br_y+1,FALSE);

}

// Draw point in gc at position (x,y)
// S COORDINATES
static void r2d_s_draw_point(T_R2D_GC_PTR gc,INT16 x,INT16 y,INT32 l)
{
  UINT32 pixel_value;
  INT16 pen_size;
  BOOLEAN isLCD_format,can_draw;
  T_R2D_GC* pgc;

  can_draw=FALSE;

  if (r2d_dash_enabled(gc))
  {
	  // Q16, 0x0008000 is 8 pixels
	  if (!(l&0x00080000))
		  can_draw=TRUE;
  }
  else
	  can_draw=TRUE;
  
  if (can_draw==TRUE)
  {
  pgc=(T_R2D_GC*)gc;

  isLCD_format=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)gc)->p_frame_buffer))->kind!=R2D_FULL_KIND;


  pen_size=r2d_get_pen_size(gc);

  
  if (r2d_point_in_shape(((T_R2D_GC*)gc)->p_s_clipping_shape,x,y))
  {

	 
    if (pen_size>1)
	   r2d_s_fill_point(gc,x,y,pen_size);
     
       
    else
    {
       // Dithering is relative to global coordinate system
      

   // Color is recomputed only when dithering is on
   #if (R2D_DITHERING == R2D_ON)
       if (isLCD_format)
           pixel_value=r2d_get_dithering_matrix_entry(((T_R2D_GC*)gc)->p_foreground_dithered_cache,x,y);
       else
           pixel_value=((T_R2D_GC*)gc)->foreground_pixel_value;
   #else
       pixel_value=((T_R2D_GC*)gc)->foreground_pixel_value;
   #endif

       // Low level pixel drawing routine with CONVERTED color value
	   
       IND_r2d_write_lcd_pixel(gc,x,y,pixel_value);

    }
  }
  
  r2d_check_and_send_event(gc);
  }
}

// Draw point in gc at position (x,y)
// H COORDINATES
void r2d_draw_point(T_R2D_GC_PTR gc,INT16 x,INT16 y)
{
	if (r2d_point_in_shape(((T_R2D_GC*)gc)->p_clipping_shape,x,y))
	{
		r2d_local_to_global(gc,&x,&y);
	
#ifdef R2D_MIRRORED_X
	  x=r2d_get_width(gc)-1-x;
#endif

#ifdef R2D_MIRRORED_Y
	  y=r2d_get_height(gc)-1-y;
#endif

   
	
	
	if (((T_R2D_FRAMEBUFFER*)((T_R2D_GC*)gc)->p_frame_buffer)->kind==0)
      r2d_update_region((T_R2D_GC*)gc,x,y,x,y);
#if (R2D_REFRESH == R2D_VERTICAL)
	r2d_s_draw_point(gc,x,y,0);
#else
	r2d_s_draw_point(gc,y,x,0);
#endif

	}
}

void           r2d_erase_point(T_R2D_GC_PTR gc,INT16 x,INT16 y)
{

   T_R2D_ARGB_COLOR col;

   
if (r2d_point_in_shape(((T_R2D_GC*)gc)->p_clipping_shape,x,y))
{
	r2d_local_to_global(gc,&x,&y);
	col=r2d_get_foreground_color(gc);
   r2d_set_foreground_color(gc,r2d_get_background_color(gc));
	
#ifdef R2D_MIRRORED_X
	  x=r2d_get_width(gc)-1-x;
#endif

#ifdef R2D_MIRRORED_Y
	  y=r2d_get_height(gc)-1-y;

#endif

   
   if (((T_R2D_FRAMEBUFFER*)((T_R2D_GC*)gc)->p_frame_buffer)->kind==0)
      r2d_update_region((T_R2D_GC*)gc,x,y,x,y);
   
	#if (R2D_REFRESH == R2D_VERTICAL)
	r2d_s_draw_point(gc,x,y,0);
#else
	r2d_s_draw_point(gc,y,x,0);
#endif

   r2d_set_foreground_color(gc,col);
}
   

}

// Move pen to point (x,y)
// H_COORDINATES
void           r2d_moveto(T_R2D_GC_PTR gc,INT16 x,INT16 y)
{
   ((T_R2D_GC*)gc)->pen_x=x;
   ((T_R2D_GC*)gc)->pen_y=y;
}


static BOOLEAN r2d_clipt(INT32 denom,INT32 num,INT32 *tE,INT32 *tL)
{
    INT32 t;
    
    //printf("clipt %08X %08X\n",denom,num);
    if (denom<0)
    {
       t=r2d_fixed_division(num,denom);
       //printf("denom<0 ; t=%08X\n",t);
       if (t>*tL)
         return FALSE;
       else if (t > *tE)
         *tE=t;
    }
    else if (denom>0)
    {
       t=r2d_fixed_division(num,denom);
       //printf("denom>0 ; t=%08X\n",t);
       if (t<*tE)
         return FALSE;
       else if (t < *tL)
          *tL=t;
    } else if (num<0)
      return FALSE;

     //printf("t=%08X tE=%08X tL=%08X\n",t,*tE,*tL);
     return TRUE;
}

static BOOLEAN r2d_clip_line(T_R2D_SHAPE *self,INT32 *x0,INT32 *y0,INT32 *x1, INT32 *y1)
{
	T_R2D_RECTANGLE *r;
    BOOLEAN visible=FALSE;
    INT32 dx=*x1-*x0;
    INT32 dy=*y1-*y0;

	r=(T_R2D_RECTANGLE*)self;
  
    // Can only clip against reactangular shapes
    if (self->p_r2d_class==&r2d_class_rectangle)
    {
      
      if ((dx==0) && (dy==0) && r2d_point_in_shape(self,(*x0>>16) & 0x0FFFF,(*y0>>16) & 0x0FFFF))
        visible=TRUE;
      else
      {
         INT32 tE=0;
         INT32 tL=(1<<16);


         if (r2d_clipt(dx,((r2d_get_xmax(self)-1)<<16)-*x0,&tE,&tL)==TRUE)
           if (r2d_clipt(-dx,*x0-(r2d_get_xmin(self)<<16),&tE,&tL)==TRUE)
             if (r2d_clipt(-dy,*y0-(r2d_get_ymin(self)<<16),&tE,&tL)==TRUE)
               if (r2d_clipt(dy,((r2d_get_ymax(self)-1)<<16) -*y0,&tE,&tL)==TRUE)
               {
                   visible=TRUE;

                   //printf("tE=%08X tL=%08X\n",tE,tL);
                   // 1 with fixed point representation
                   if (tL < (1<<16))
                   {
                       // dx and dy are integer
                       // tL and tE should be lower than 1
                       // So intermediate values are shifted so that
                       // the product can be done on 32 bits instead of 64 bits
                       *x1=*x0 + (tL*(dx>>16)) ;
                       *y1=*y0 + (tL*(dy>>16)) ;
                       //printf("x1=%08X y1=%08X\n",*x1,*y1);
                   }
                   if (tE > 0)
                   {
                       *x0 += (tE*(dx>>16)) ;
                       *y0 += (tE*(dy>>16)) ;
                       //printf("x0=%08X y0=%08X\n",*x0,*y0);

                   }
               }
      }
    }
    return(visible);
}

// 0.5 is rounded down because in line drawing the bottom
// point is chosen when the line is passing through the middle
// point
#define R2D_Q16INT_VALUE(x) ((x+(0x7FFF)) & 0xFFFF0000)

#define R2D_FLOOR_VALUE(x) (x & 0xFFFF0000)

// Positive times signed value
#define R2D_MULT_PN(x,y) ((((x >> 16) & 0x0FFFF)*y) + (((x & 0x0FFFF) * y) >> 16))

// draw line from pen position to point (x,y)
void           r2d_lineto(T_R2D_GC_PTR gc,INT16 x,INT16 y)
{
    // Clipping
    // Now drawing with low level function

    UINT32 pixel_value;
    INT32 P0X,P0Y,P1X,P1Y,c,cy,cx;
    INT32 current_x,current_y,tmp,tmpx,tmpy;
    INT32 dx,dy,dn,dnp,dnn;
    INT16 xincrement,yincrement,reverse;
    INT32 nx,ny;
    INT16 pen_size;
	INT32 l;
    BOOLEAN isLCD_format;
	l=0;

	

    isLCD_format=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)gc)->p_frame_buffer))->kind!=R2D_FULL_KIND;

    pixel_value=((T_R2D_GC*)gc)->foreground_pixel_value;
    pen_size=r2d_get_pen_size(gc);

    P0X=((T_R2D_GC*)gc)->pen_x << 16;
    P0Y=((T_R2D_GC*)gc)->pen_y << 16;
    P1X=x << 16;
    P1Y=y << 16;
    //printf("\n\n(%d,%d) ; (%d,%d)\n",P0X>>16,P0Y>>16,P1X>>16,P1Y>>16);
    
// As far as possible, most datas are computed before clipping to get same accuracy
// Update pen position
    ((T_R2D_GC*)gc)->pen_x=x;
    ((T_R2D_GC*)gc)->pen_y=y;

if (r2d_clip_line((((T_R2D_GC*)gc)->p_clipping_shape),&P0X,&P0Y,&P1X,&P1Y))
{

// Local to global

	P0X-=((T_R2D_GC*)gc)->org_x << 16;
    P0Y-=((T_R2D_GC*)gc)->org_y << 16;
    P1X-=((T_R2D_GC*)gc)->org_x << 16;
    P1Y-=((T_R2D_GC*)gc)->org_y << 16;

	 
#ifdef R2D_MIRRORED_X
  P0X=((r2d_get_width(gc)-1)<<16)-P0X;
  P1X=((r2d_get_width(gc)-1)<<16)-P1X;
#endif

#ifdef R2D_MIRRORED_Y
  P0Y=((r2d_get_height(gc)-1)<<16)-P0Y;
  P1Y=((r2d_get_height(gc)-1)<<16)-P1Y;
#endif

    
    /*printf("%d %d %d %d\n",r2d_get_xmin(((T_R2D_GC*)gc)->p_clipping_shape),
    r2d_get_xmax(((T_R2D_GC*)gc)->p_clipping_shape),
    r2d_get_ymin(((T_R2D_GC*)gc)->p_clipping_shape),
    r2d_get_ymax(((T_R2D_GC*)gc)->p_clipping_shape)
   );*/

    //r2d_clip_line(&(((T_R2D_GC*)gc)->clipping_rectangle),&P0X,&P0Y,&P1X,&P1Y);
    
        //printf("(%d,%d) ; (%d,%d)\n",P0X>>16,P0Y>>16,P1X>>16,P1Y>>16);
        //printf("(%08X,%08X) ; (%08X,%08X)\n------------------\n",P0X,P0Y,P1X,P1Y);
      
      //printf("(%d,%d) ; (%d,%d)\n",P0X>>16,P0Y>>16,P1X>>16,P1Y>>16);

if (((T_R2D_FRAMEBUFFER*)((T_R2D_GC*)gc)->p_frame_buffer)->kind==0)
      r2d_update_region((T_R2D_GC*)gc,P0X>>16,P0Y>>16,P1X>>16,P1Y>>16);


#if (R2D_REFRESH==R2D_VERTICAL)
    current_x=P0Y;
    current_y=P0X;
    nx=P1Y; ny=P1X;

    
#else
    current_x=P0X;
    current_y=P0Y;
    nx=P1X; ny=P1Y;
#endif

    dx=nx-current_x;
    dy=ny-current_y;
    
    yincrement=1;

    if (dx>=0)
    {
       xincrement=1;
    }
    else
    {
       xincrement=-1;
       dx=-dx;
    }

    if (dy>=0)
    {
       yincrement=1;
    }
    else
    {
       yincrement=-1;
       dy=-dy;
    }

    if (dy<=dx)
      reverse=0;
    else
    {
      reverse=1;
      tmp=dy;
      dy=dx;
      dx=tmp;
      tmp=current_y;
      current_y=current_x;
      current_x=tmp;
      tmp=ny;
      ny=nx;
      nx=tmp;
      tmp=yincrement;
      yincrement=xincrement;
      xincrement=tmp;
    }

    reverse=1-reverse;


    //printf("dx,dy,current_x,current_y,nx,ny\n%08X %08X %08X %08X %08X %08X\n",dx,dy,current_x,current_y,nx,ny);


    // Remember that when one is speaking about a move of 1 horizontally
    // one is talking about internal coordinates used by the algorithm
    // In the window it may be vertical or horizontal depending on the
    // refresh mode and on the line slope (<1 or >1)


    dn=dy - (dx >> 1)  ; // d0 = a-b/2 
    dnp=dy-dx ;
    dnn=dy;
    
    // We draw the point which is the closest to the line so we use INT
    // instead of FLOOR or CEIL
    // But, then, the drawing algorithm assumes that the first drawn point is
    // the lowest one

    // If F(P) = 0 is a parametric description of the line
    // The, when one is moving from the point of the line on the frontier
    // of the clipping rectangle to the closest
    // point with x,y integer coordinate then one needs to compute dx*cy and dy*cx
    // since it is the variation of F along that path
    tmpx=(INT32)R2D_Q16INT_VALUE(current_x);
    tmpy=(INT32)R2D_Q16INT_VALUE(current_y);
    cx = current_x - tmpx;
    cy = current_y - tmpy;


    c= -R2D_MULT_PN(dx,cy) + R2D_MULT_PN(dy,cx);
    

    //printf("cx=%08X, cy=%08X, c=%08X, dx=%08X, dy=%08X \n",cx,cy,c,dx,dy);

    // Then, one can add c to the variation due to a move of 1 horizontally
    // an a move of 1/2 vertically.
    // One finally get the value of the decision variable at the midpoint
    dn+=c;

    //printf("%08X %08X %08X %08X %08X\n",current_x,current_y,nx,ny);
    current_x=((INT32)R2D_Q16INT_VALUE(current_x)) >> 16;
    current_y=((INT32)R2D_Q16INT_VALUE(current_y)) >> 16;
    nx=((INT32)R2D_Q16INT_VALUE(nx)) >> 16;
    ny=((INT32)R2D_Q16INT_VALUE(ny)) >> 16;

    
    //printf("dx=%08X dy=%08X dn=%08X dnp=%08X dnn=%08X\n",dx,dy,dn,dnp,dnn);
    
    if (reverse)
    {
        r2d_s_draw_point(gc,current_y,current_x,l);
        
    }
    else
    {
        r2d_s_draw_point(gc,current_x,current_y,l);
    }
    
    

    while(current_x != nx)
    {

      if (dn>0)
      {
        dn += dnp; 
        current_y+=yincrement;
		l=l+SQRT2;
      }
      else if (dn<0)
      {
        dn += dnn;
		l=l+0x10000;
      } 
      else
      {
          if (xincrement<0)
          {
             dn += dnp; 
             current_y+=yincrement;
			 l=l+SQRT2;
          }
          else
          {
             dn += dnn;
			 l=l+0x10000;
          }
      }

      current_x+=xincrement;
      //printf("    -->%08X %d %d\n",dn,current_x,current_y);
      // Color is recomputed only when dithering is on


      if (reverse)
      {

          r2d_s_draw_point(gc,current_y,current_x,l);
      }
      else
      {
          r2d_s_draw_point(gc,current_x,current_y,l);
      }
   }
   } // END CLIPPING

   //printf("END LINE\n");
   
  
   r2d_check_and_send_event(gc);
}

// Used for filling
// Do clipping and coordinate transforms then call
// low levl line filling algorithm
// No mirroring check since it is a low level routine
// S COORDINATES
static void r2d_s_fill_line(T_R2D_GC_PTR gc,INT16 x,INT16 y,INT16 nb,BOOLEAN background)
{
   T_R2D_SHAPE_PTR clip;
   T_R2D_RECTANGLE *r;
//   INT16 tmp;

   clip=((T_R2D_GC*)gc)->p_s_clipping_shape;
   r=(T_R2D_RECTANGLE*)clip;


   if ((x>=r2d_get_xmin(clip)) && ( x<r2d_get_xmax(clip)))
   {
      if (y<r2d_get_ymin(clip))
      {
       nb-=r2d_get_ymin(clip)-y;
       y=r2d_get_ymin(clip);
      }

      if (y+nb-1>=r2d_get_ymax(clip))
        nb=r2d_get_ymax(clip)-y;

      if (nb>0)

        IND_r2d_write_lcd_line(gc,x,y,nb,background); 
   }


}

// Used for filling
// Do clipping and coordinate transforms then call
// low levl line filling algorithm
// No mirroring check since it is a low level routine
// S COORDINATES
static void r2d_s_arc_fill_line(T_R2D_GC_PTR gc,INT16 x,INT16 y,
								INT16 org_x,INT16 org_y,INT16 nb,T_R2D_ARC_REGION *rgn,BOOLEAN background)
{
   T_R2D_SHAPE_PTR clip;
   T_R2D_RECTANGLE *r;
//   INT16 tmp;

   clip=((T_R2D_GC*)gc)->p_s_clipping_shape;
   r=(T_R2D_RECTANGLE*)clip;


   if ((x>=r2d_get_xmin(clip)) && ( x<r2d_get_xmax(clip)))
   {
      if (y<r2d_get_ymin(clip))
      {
       nb-=r2d_get_ymin(clip)-y;
       y=r2d_get_ymin(clip);
      }

      if (y+nb-1>=r2d_get_ymax(clip))
        nb=r2d_get_ymax(clip)-y;

      if (nb>0)

        r2d_arc_write_lcd_line(gc,x,y,org_x,org_y,nb,rgn,background); 
   }


}

// S coordinates
static void           r2d_s_fill_rectangle(T_R2D_GC_PTR gc,
                  INT16 ul_x,INT16 ul_y,INT16 br_x, INT16 br_y,BOOLEAN background)
{

    INT16 i;
	// The ifdef is not passing the coordinates to S frame.
	// It just changing the way the square is scanned
	// to improve behavior relatively to the scanning mode.
       for(i=ul_x+1;i<=br_x-1;i++)
       {
           r2d_s_fill_line(gc,i,ul_y+1,(br_y-ul_y)+1-2,background);
       }
     
}

// Background allows to chose the color for filling
// If TRUE, background color is used
// (required for pen_size different from 1)
// L coordinates
static void           r2d_df_rectangle(T_R2D_GC_PTR gc,
                  INT16 ul_x,INT16 ul_y,INT16 br_x, INT16 br_y,BOOLEAN background)
{

    INT16 i;
	// The ifdef is not passing the coordinates to S frame.
	// It just changing the way the square is scanned
	// to improve behavior relatively to the scanning mode.
     #if (R2D_REFRESH==R2D_VERTICAL)
       for(i=ul_x+1;i<=br_x-1;i++)
       {
           r2d_s_fill_line(gc,i,ul_y+1,(br_y-ul_y)+1-2,background);
       }
     #else
       for(i=ul_y+1;i<=br_y-1;i++)
       {
           r2d_s_fill_line(gc,i,ul_x+1,(br_x-ul_x)+1-2,background);
       }
     #endif
}

void           r2d_draw_rectangle(T_R2D_GC_PTR gc,
                  INT16 ul_x,INT16 ul_y,INT16 br_x, INT16 br_y)
{

	 
     r2d_moveto(gc,ul_x,ul_y);
     r2d_lineto(gc,br_x,ul_y);

	 
     r2d_moveto(gc,br_x,ul_y+1);
     r2d_lineto(gc,br_x,br_y);

	 
     r2d_moveto(gc,br_x-1,br_y);
     r2d_lineto(gc,ul_x,br_y);

	 
	 r2d_moveto(gc,ul_x,ul_y+1);
     r2d_lineto(gc,ul_x,br_y-1);
	 
}

void           r2d_fill_rectangle(T_R2D_GC_PTR gc,
                  INT16 ul_x,INT16 ul_y,INT16 br_x, INT16 br_y)
{
#ifdef R2D_MIRRORED_X
	INT16 tmp;
#endif
	r2d_local_to_global(gc,&ul_x,&ul_y);
	r2d_local_to_global(gc,&br_x,&br_y);

	
#ifdef R2D_MIRRORED_X
	   ul_x = r2d_get_width(gc)-1-ul_x;
	   br_x = r2d_get_width(gc)-1-br_x;
       R2D_SWAP(ul_x,br_x);
#endif

#ifdef R2D_MIRRORED_Y
	   ul_y = r2d_get_height(gc)-1-ul_y;
	   br_y = r2d_get_height(gc)-1-br_y;	   
	   R2D_SWAP(ul_y,br_y);
#endif
       r2d_df_rectangle(gc,ul_x,ul_y,br_x,br_y,TRUE);
	   if (((T_R2D_FRAMEBUFFER*)((T_R2D_GC*)gc)->p_frame_buffer)->kind==0)
          r2d_update_region((T_R2D_GC*)gc,ul_x,ul_y,br_x,br_y);

   r2d_check_and_send_event(gc);
}



void           r2d_df_circle(T_R2D_GC_PTR gc,
                 INT16 x,INT16 y,INT16 r,BOOLEAN filling)
{
  INT32 current_x,current_y,my,mx;
  INT32 dn,dnp,dnn,org_x,org_y,limit,rs,tmp,D_yx;
  INT32 l;
  INT32 p; // perimeter divided by 4

  l=0;

  p=(PI*r)>>1;
  

  #if (R2D_REFRESH==R2D_VERTICAL)
    current_x=y;
    current_y=x+r;
    org_x=y; 
    org_y=x;
	
  #else
    current_x=x;
    current_y=y+r;
    org_x=x;
    org_y=y;
  #endif

  D_yx=org_y-org_x;

  dnp=((-r) << 1) + 5;
  dnn=3;
  dn=-r;
  rs=r*r;
  limit=-r;

 



  tmp=1;
  while(limit<=0)
  {

     // Some points are their own image with symetries
     // and yet they must not be drawn twice for drawing
     // modes other than copy hence the tests

     my=(org_y << 1) - current_y;
     mx=(org_x << 1) - current_x;

     // PY or PX is reflection relatively to horizontal line or vertical line
     // PY = vertical mirroring where bottom becomes top

     // D = diagonal mirroring

     // AB means apply transform A then B

     // I is identity

     // Everything is done relatively to what is displayed on the LCD
     // so my may be PX according to the refresh mode


     if (!filling)
     {
        if (mx != current_x)
        {
          r2d_s_draw_point(gc,current_y,current_x,l); // I : 3
          r2d_s_draw_point(gc,mx+D_yx,current_y-D_yx,l); // D PX : 5
          r2d_s_draw_point(gc,my,mx,l); // PX.PY : 7
          r2d_s_draw_point(gc,current_x+D_yx,my-D_yx,l); // D PY : 1
        }

        if (current_x != current_y)
        {
          r2d_s_draw_point(gc,current_x+D_yx,current_y-D_yx,l+p); // D : 4
          r2d_s_draw_point(gc,current_y,mx,l+p); // PY : 2
        }

        if ((mx != my) || (current_x != current_y))
          r2d_s_draw_point(gc,my,current_x,l+p); // PX : 6


        if (mx != my)
          r2d_s_draw_point(gc,mx+D_yx,my-D_yx,l+p); // D PX PY : 8

     }
     else
     {
         //printf("%d\n",current_x);
         if (tmp)
         {
           if (current_x-mx!=0)
           {
             r2d_s_fill_line(gc,my,mx+1,(current_x-mx)+1-2,TRUE);
             r2d_s_fill_line(gc,current_y,mx+1,(current_x-mx)+1-2,TRUE);
           }
         }
         if (mx != my) 
         {
           r2d_s_fill_line(gc,mx+D_yx,my+1-D_yx,(current_y-my)+1-2,TRUE);
           if (current_x != mx);
            r2d_s_fill_line(gc,current_x+D_yx,my+1-D_yx,(current_y-my)+1-2,TRUE);
         }
     }


     if (dn>0) // M outside circle, point below must be drawn
     {
        dn+=dnp;
        dnp+=4;
        
        current_y--;
		l+=SQRT2;
        limit+=2;
        tmp=1;
     }
     else
     {
        dn+=dnn;
        dnp+=2;
        limit+=1;
        tmp=0;
		l+=0x10000;
     }
     
     current_x++;
     dnn+=2;

     
     
     
  }
  //printf("%08X\n",limit);
}

void           r2d_draw_circle(T_R2D_GC_PTR gc,
                 INT16 x,INT16 y,INT16 r)
{

	r2d_local_to_global(gc,&x,&y);
  

#ifdef R2D_MIRRORED_X
	   x = r2d_get_width(gc)-1-x;
#endif

#ifdef R2D_MIRRORED_Y
	   y = r2d_get_height(gc)-1-y;
#endif


   r2d_df_circle(gc,x,y,r,FALSE);
   if (((T_R2D_FRAMEBUFFER*)((T_R2D_GC*)gc)->p_frame_buffer)->kind==0)
          r2d_update_region((T_R2D_GC*)gc,x-r,y-r,x+r,y+r);
   r2d_check_and_send_event(gc);
}

void           r2d_fill_circle(T_R2D_GC_PTR gc,
                 INT16 x,INT16 y,INT16 r)
{
	r2d_local_to_global(gc,&x,&y);

#ifdef R2D_MIRRORED_X
	    x = r2d_get_width(gc)-1-x;
#endif

#ifdef R2D_MIRRORED_Y
	   y = r2d_get_height(gc)-1-y;
#endif

   r2d_df_circle(gc,x,y,r,TRUE);
   if (((T_R2D_FRAMEBUFFER*)((T_R2D_GC*)gc)->p_frame_buffer)->kind==0)
          r2d_update_region((T_R2D_GC*)gc,x-r,y-r,x+r,y+r);
   r2d_check_and_send_event(gc);
}



// h and v are used to draw roundrectangle (each piece of the ellipse must be
// separated from other parts)
void           r2d_df_ellipse(T_R2D_GC_PTR gc,
                  INT16 ul_x,INT16 ul_y,INT16 br_x, INT16 br_y, INT16 h,INT16 v,BOOLEAN filling)
{
  INT32 current_x,current_y,limit,newx,newy,org_x,org_y;
  INT32 dn,dnp,dnn,as,bs,tmp,a,b,mx,my,lastx,lasty,round;
  INT32 l;
  l=0;

  if ((h!=0) || (v!=0))
   round=1;
  else
   round=0;


  // Width of rectangle is assumed to be even
  // and it is forced to even dimension


  #if (R2D_REFRESH==R2D_VERTICAL)
    org_x=(ul_y + br_y)>>1;
    org_y=(br_x + ul_x)>>1; 
    a=(br_y-ul_y)>>1;
    as=R2D_SQUARE_P(a);
    b=(br_x-ul_x)>>1;
    bs=R2D_SQUARE_P(b);

    current_x=org_x ;
    current_y=org_y+b; 
    newx=org_y;
    newy=org_x+a;
    
  #else
    org_x=(ul_x + br_x)>>1; 
    org_y=(br_y + ul_y)>>1;

    b=(br_y-ul_y)>>1;
    bs=R2D_SQUARE_P(b);
    a=(br_x-ul_x)>>1;
    as=R2D_SQUARE_P(a);

    current_x=org_x;
    current_y=org_y+b; 
    newx=org_y;
    newy=org_x+a;
	R2D_SWAP(h,v);
    
  #endif

  // Now, shift by 2 to have the accuracy required by division by four


  //printf("current_x=%d, current_y=%d,as=%08X bs=%08X\n",current_x,current_y,as,bs);


  // New shift by 2 because one needs to compute quarter of values
  bs<<=2; as <<=2;b<<=2;a<<=2;

  limit = - ((as * b) >> 2); // -a^2 * b in Q2

  tmp=-((as * b) >> 2);
  dnp=(bs << 1) + bs + (tmp<<1) + (as << 1);
  dnn=(bs << 1) + bs;
  dn=bs + tmp + (as >>2);
  
  
  
  //printf("dn=%f dnp=%f dnn=%f\n",dn / 8.0,dnp / 8.0,dnn / 8.0);

/*#if (R2D_REFRESH==R2D_VERTICAL)
  r2d_draw_point(gc,current_y,current_x);
#else
  r2d_draw_point(gc,current_x,current_y);
#endif*/
  
  //printf("as=%08X bs=%08X\n",as,bs);

  tmp=1;
  while(limit<=0)
  {
     my=(org_y << 1) - current_y;
     mx=(org_x << 1) - current_x;

     lastx=current_y;
     lasty=current_x;

     if (!filling)
     {
       r2d_s_draw_point(gc,(current_y)+h,(current_x)+v,l); // I : 1
       r2d_s_draw_point(gc,my,mx,l); // PX PY : 2

       if ((mx != current_x) || (round))
       {
          r2d_s_draw_point(gc,(current_y)+h,mx,l); // PY : 3
          r2d_s_draw_point(gc,my,current_x+v,l); // PX : 4
       }
     }
     else
     {
         if (tmp)
         {

           // Used to remove point on horizontal extremity
           if (current_x+v-mx !=0)
           {
             r2d_s_fill_line(gc,my,mx+1,(current_x+v-mx)+1-2,TRUE);
             r2d_s_fill_line(gc,current_y+h,mx+1,(current_x+v-mx)+1-2,TRUE);
           }
         }  
     }

     if (dn>=0) // M outside circle, point below must be drawn
     {
        dn+=dnp;
        dnp+=((bs + as) << 1);
        current_y--; 
        limit+=(as + bs);
        tmp=1;
		l+=SQRT2;
     }
     else

     {
        dn+=dnn;
        dnp+=(bs << 1);
        limit+=bs;
        tmp=0;
		l+=0x10000;
        
     }
     current_x++; 
     dnn+=(bs << 1);

     
     //printf("limit=%f, dn=%f,dnn=%f,dnp=%f, pos= %d %d\n",limit / 4.0,dn / 4.0,dnn / 4.0,dnp /
//4.0,current_y,current_x);
     
     
  }
  
  current_x=newx;
  current_y=newy;
  R2D_SWAP(as,bs);
  R2D_SWAP(a,b);
  
  limit = - ((as * b) >> 2);

  tmp=-((as * b) >> 2);
  dnp=(bs << 1) + bs + (tmp<<1) + (as << 1);
  dnn=(bs << 1) + bs;
  dn=bs + tmp + (as >>2);

  //printf("newx=%d, newy=%d,a=%d,b=%d\n",newx,newy,a,b);
  //printf("dn=%f dnp=%f dnn=%f\n",dn / 4.0,dnp / 4.0,dnn / 4.0);

  tmp=1;

 /* #if (R2D_REFRESH==R2D_VERTICAL)
    r2d_draw_point(gc,current_x,current_y);
  #else
    r2d_draw_point(gc,current_y,current_x);
  #endif*/

  while(limit<0)
  {
     
     my=(org_x << 1) - current_y;
     mx=(org_y << 1) - current_x;

     if (!filling)
     {
        if ((lastx!=current_x) || (lasty!=current_y))
        {

          r2d_s_draw_point(gc,(current_x)+h,(current_y)+v,l); // D : 5


          r2d_s_draw_point(gc,mx,my,l); // D PX PY : 6

          if ((mx != (current_x+h)) || (round))
          {
            r2d_s_draw_point(gc,(current_x)+h,my,l); // D PY : 7
            r2d_s_draw_point(gc,mx,(current_y)+v,l); // D PX : 8
          }

        }
     }
     else
     {
        if (current_x != lastx)
        {
           r2d_s_fill_line(gc,mx,my+1,(current_y+v-my)+1-2,TRUE);
           if ((current_x+h) !=mx)
             r2d_s_fill_line(gc,current_x+h,my+1,(current_y+v-my)+1-2,TRUE);
        }
     }

     if (dn>0) // M outside circle, point below must be drawn
     {
        dn+=dnp;
        dnp+=((bs + as) << 1);
        current_y--; // Q1
        limit+=(as + bs);
        tmp=1;
		l+=SQRT2;
     }
     else
     {
        dn+=dnn;
        dnp+=(bs << 1);
        limit+=bs;
        tmp=0;
		l+=0x10000;
        
     }
     current_x++; // Q1
     dnn+=(bs << 1);

     
     
     
     //printf("limit=%f, dn=%f,dnn=%f,dnp=%f, pos= %d %d\n",limit / 4.0,dn / 4.0,dnn / 4.0,dnp / 4.0,current_y,current_x);
     
     
  }
}

void           r2d_draw_ellipse(T_R2D_GC_PTR gc,
                  INT16 ul_x,INT16 ul_y,INT16 br_x, INT16 br_y)
{
#ifdef R2D_MIRRORED_X
	INT16 tmp;
#endif
	r2d_local_to_global(gc,&ul_x,&ul_y);
	r2d_local_to_global(gc,&br_x,&br_y);
	

#ifdef R2D_MIRRORED_X
	   ul_x = r2d_get_width(gc)-1-ul_x;
	   br_x = r2d_get_width(gc)-1-br_x;
	   R2D_SWAP(ul_x,br_x);
#endif

#ifdef R2D_MIRRORED_Y
	   ul_y = r2d_get_height(gc)-1-ul_y;
	   br_y = r2d_get_height(gc)-1-br_y;
	   R2D_SWAP(ul_y,br_y);
#endif

   r2d_df_ellipse(gc,ul_x,ul_y,br_x,br_y,0,0,FALSE);
   if (((T_R2D_FRAMEBUFFER*)((T_R2D_GC*)gc)->p_frame_buffer)->kind==0)
          r2d_update_region((T_R2D_GC*)gc,ul_x,ul_y,br_x,br_y);

   r2d_check_and_send_event(gc);
}

void           r2d_fill_ellipse(T_R2D_GC_PTR gc,
                  INT16 ul_x,INT16 ul_y,INT16 br_x, INT16 br_y)
{
#ifdef R2D_MIRRORED_X
	INT16 tmp;
#endif
	r2d_local_to_global(gc,&ul_x,&ul_y);
	r2d_local_to_global(gc,&br_x,&br_y);

	
#ifdef R2D_MIRRORED_X
	   ul_x = r2d_get_width(gc)-1-ul_x;
	   br_x = r2d_get_width(gc)-1-br_x;
       R2D_SWAP(ul_x,br_x);
#endif

#ifdef R2D_MIRRORED_Y
	   ul_y = r2d_get_height(gc)-1-ul_y;
	   br_y = r2d_get_height(gc)-1-br_y;
	   R2D_SWAP(ul_y,br_y);
#endif

   r2d_df_ellipse(gc,ul_x,ul_y,br_x,br_y,0,0,TRUE);
   if (((T_R2D_FRAMEBUFFER*)((T_R2D_GC*)gc)->p_frame_buffer)->kind==0)
          r2d_update_region((T_R2D_GC*)gc,ul_x,ul_y,br_x,br_y);

   r2d_check_and_send_event(gc);
}

void           r2d_draw_round_rectangle(T_R2D_GC_PTR gc,
                  INT16 ul_x,INT16 ul_y,INT16 br_x, INT16 br_y,INT16 h,INT16 v)
{
#ifdef R2D_MIRRORED_X
	INT16 tmp;
#endif
	r2d_moveto(gc,ul_x+h+1,ul_y);
  r2d_lineto(gc,br_x-h-1,ul_y);

  r2d_moveto(gc,ul_x+h+1,br_y);
  r2d_lineto(gc,br_x-h-1,br_y);

  r2d_moveto(gc,ul_x,ul_y+v+1);
  r2d_lineto(gc,ul_x,br_y-v-1);

  r2d_moveto(gc,br_x,ul_y+v+1);
  r2d_lineto(gc,br_x,br_y-v-1);

   r2d_local_to_global(gc,&ul_x,&ul_y);
   r2d_local_to_global(gc,&br_x,&br_y);

	
#ifdef R2D_MIRRORED_X
	   ul_x = r2d_get_width(gc)-1-ul_x;
	   br_x = r2d_get_width(gc)-1-br_x;
       R2D_SWAP(ul_x,br_x);
#endif

#ifdef R2D_MIRRORED_Y
	   ul_y = r2d_get_height(gc)-1-ul_y;
	   br_y = r2d_get_height(gc)-1-br_y;
	   R2D_SWAP(ul_y,br_y);  
#endif
  r2d_df_ellipse(gc,ul_x,ul_y,ul_x+(h<<1),ul_y+(v<<1),(br_x - ul_x) - (h<<1),(br_y - ul_y) - (v<<1),FALSE);
if (((T_R2D_FRAMEBUFFER*)((T_R2D_GC*)gc)->p_frame_buffer)->kind==0)
          r2d_update_region((T_R2D_GC*)gc,ul_x,ul_y,br_x,br_y);

  //printf("%d %d\n",ul_x+h+1,br_x-h-1);
  
  
  r2d_check_and_send_event(gc);
}

void           r2d_fill_round_rectangle(T_R2D_GC_PTR gc,
                  INT16 ul_x,INT16 ul_y,INT16 br_x, INT16 br_y,INT16 h,INT16 v)
{
#ifdef R2D_MIRRORED_X
	INT16 tmp;
#endif
	r2d_local_to_global(gc,&ul_x,&ul_y);
   r2d_local_to_global(gc,&br_x,&br_y);

#ifdef R2D_MIRRORED_X
	   ul_x = r2d_get_width(gc)-1-ul_x;
	   br_x = r2d_get_width(gc)-1-br_x;
       R2D_SWAP(ul_x,br_x);
#endif


#ifdef R2D_MIRRORED_Y
	   ul_y = r2d_get_height(gc)-1-ul_y;
	   br_y = r2d_get_height(gc)-1-br_y;
	   R2D_SWAP(ul_y,br_y);
#endif

  r2d_df_ellipse(gc,ul_x,ul_y,ul_x+(h<<1),ul_y+(v<<1),(br_x - ul_x) - (h<<1),(br_y - ul_y) - (v<<1),TRUE);
#if (R2D_REFRESH == R2D_VERTICAL)
  r2d_df_rectangle(gc,ul_x+h,ul_y,br_x-h+1,br_y,TRUE);

#else
  
  r2d_df_rectangle(gc,ul_x,ul_y+v,br_x,br_y-v+1,TRUE);
#endif
  if (((T_R2D_FRAMEBUFFER*)((T_R2D_GC*)gc)->p_frame_buffer)->kind==0)
          r2d_update_region((T_R2D_GC*)gc,ul_x,ul_y,br_x,br_y);
  //printf("%d %d\n",ul_x+h+1,br_x-h-1);
  /*r2d_moveto(gc,ul_x+h+1,ul_y);
  r2d_lineto(gc,br_x-h-1,ul_y);

  r2d_moveto(gc,ul_x+h+1,br_y);
  r2d_lineto(gc,br_x-h-1,br_y);

  r2d_moveto(gc,ul_x,ul_y+v+1);
  r2d_lineto(gc,ul_x,br_y-v-1);

  r2d_moveto(gc,br_x,ul_y+v+1);
  r2d_lineto(gc,br_x,br_y-v-1);*/
  r2d_check_and_send_event(gc);
}

// angle must be between 0 and 359
static INT32 r2d_cos(INT16 angle)
{
	

	if (angle<=90)
		return(r2d_cos_table[angle]);
	else if (angle<=180)
		return(-r2d_cos_table[180-angle]);
	else if (angle<=270)
         return(-r2d_cos_table[angle-180]);
	else
         return(r2d_cos_table[360-angle]);
}

// angle must be between 0 and 359
static INT32 r2d_sin(INT16 angle)
{
	angle=angle+90;
	if (angle>=360)
		angle=angle-360;

	return(-r2d_cos(angle));
}

static void r2d_check_angles(INT16 *start,INT16 *stop)
{
//   INT16 tmp;
   

   while(*start<0)
	   *start+=360;
   while(*start>=360)
	   *start-=360;

   while(*stop<0)
	   *stop+=360;
   while(*stop>=360)
	   *stop-=360;

   //if (*start>*stop)
   //{
//	   R2D_SWAP((*start),(*stop));
	  
   //}

}



void           r2d_df_arc(T_R2D_GC_PTR gc,
                  INT16 ul_x,INT16 ul_y,INT16 br_x, INT16 br_y,T_R2D_ARC_REGION *rgn ,BOOLEAN filling)
{
  INT32 current_x,current_y,limit,newx,newy,org_x,org_y;
  INT32 dn,dnp,dnn,as,bs,tmp,a,b,mx,my,lastx,lasty;
  INT32 l;

  l=0;

  // Width of rectangle is assumed to be even
  // and it is forced to even dimension

  if (rgn->is_null)
	  goto end_arc;

  #if (R2D_REFRESH==R2D_VERTICAL)
    org_x=(ul_y + br_y)>>1;
    org_y=(br_x + ul_x)>>1; 
    a=(br_y-ul_y)>>1;
    as=R2D_SQUARE_P(a);
    b=(br_x-ul_x)>>1;
    bs=R2D_SQUARE_P(b);

    current_x=org_x ;
    current_y=org_y+b; 
    newx=org_y;
    newy=org_x+a;

    
    
  #else
    org_x=(ul_x + br_x)>>1; 
    org_y=(br_y + ul_y)>>1;

    b=(br_y-ul_y)>>1;
    bs=R2D_SQUARE_P(b);
    a=(br_x-ul_x)>>1;
    as=R2D_SQUARE_P(a);

    current_x=org_x;
    current_y=org_y+b; 
    newx=org_y;
    newy=org_x+a;
	
    r2d_arc_region_diagonal_reflect(rgn);
	r2d_arc_region_x_reflect(rgn);
	r2d_arc_region_y_reflect(rgn);
  #endif

	
	
	// Orthogonal is (eb,-ea)

	//r2d_s_draw_point(gc,org_y,org_x);
	//r2d_s_draw_point(gc,((rgn->sa)>>16)+org_y,((rgn->sb)>>16)+org_x);
	//r2d_s_draw_point(gc,((rgn->sb)>>16)+org_y,((-rgn->sa)>>16)+org_x);

	//r2d_s_draw_point(gc,((rgn->ea)>>16)+org_y,((rgn->eb)>>16)+org_x);
	
	//goto end_arc;

  // Now, shift by 2 to have the accuracy required by division by four


  //printf("current_x=%d, current_y=%d,as=%08X bs=%08X\n",current_x,current_y,as,bs);


  // New shift by 2 because one needs to compute quarter of values
  bs<<=2; as <<=2;b<<=2;a<<=2;

  limit = - ((as * b) >> 2); // -a^2 * b in Q2

  tmp=-((as * b) >> 2);
  dnp=(bs << 1) + bs + (tmp<<1) + (as << 1);
  dnn=(bs << 1) + bs;
  dn=bs + tmp + (as >>2);
  
  
  
  //printf("dn=%f dnp=%f dnn=%f\n",dn / 8.0,dnp / 8.0,dnn / 8.0);

/*#if (R2D_REFRESH==R2D_VERTICAL)
  r2d_draw_point(gc,current_y,current_x);
#else
  r2d_draw_point(gc,current_x,current_y);
#endif*/
  
  //printf("as=%08X bs=%08X\n",as,bs);

  tmp=1;
  while(limit<=0)
  {
     my=(org_y << 1) - current_y;
     mx=(org_x << 1) - current_x;

     lastx=current_y;
     lasty=current_x;

     if (!filling)
     {
	   if (r2d_check_is_in_arc_region(current_y-org_y,current_x-org_x,rgn))
         r2d_s_draw_point(gc,(current_y),(current_x),l); // I : 1

	   if (r2d_check_is_in_arc_region(my-org_y,mx-org_x,rgn))
          r2d_s_draw_point(gc,my,mx,l); // PX PY : 2

       if ((mx != current_x) )
       {
		  if (r2d_check_is_in_arc_region(current_y-org_y,mx-org_x,rgn))
             r2d_s_draw_point(gc,current_y,mx,l); // PY : 3

		  if (r2d_check_is_in_arc_region(my-org_y,current_x-org_x,rgn))
             r2d_s_draw_point(gc,my,current_x,l); // PX : 4
       }
     }
     else
     {
         if (tmp)
         {

           // Used to remove point on horizontal extremity
           if (current_x-mx !=0)
           {
			 r2d_s_arc_fill_line(gc,my,mx+1,org_y,org_x,(current_x-mx)+1-2
				 ,rgn,TRUE);

             r2d_s_arc_fill_line(gc,current_y,mx+1,org_y,org_x,(current_x-mx)+1-2
				 ,rgn,TRUE);
           }
         }  
     }

     if (dn>=0) // M outside circle, point below must be drawn
     {
        dn+=dnp;
        dnp+=((bs + as) << 1);
        current_y--; 
        limit+=(as + bs);
        tmp=1;
		l+=SQRT2;
     }
     else

     {
        dn+=dnn;
        dnp+=(bs << 1);
        limit+=bs;
        tmp=0;
        l+=0x10000;
     }
     current_x++; 
     dnn+=(bs << 1);

     
     //printf("limit=%f, dn=%f,dnn=%f,dnp=%f, pos= %d %d\n",limit / 4.0,dn / 4.0,dnn / 4.0,dnp /
//4.0,current_y,current_x);
     
     
  }
  
  current_x=newx;
  current_y=newy;
  R2D_SWAP(as,bs);
  R2D_SWAP(a,b);
  
  limit = - ((as * b) >> 2);

  tmp=-((as * b) >> 2);
  dnp=(bs << 1) + bs + (tmp<<1) + (as << 1);
  dnn=(bs << 1) + bs;
  dn=bs + tmp + (as >>2);

  //printf("newx=%d, newy=%d,a=%d,b=%d\n",newx,newy,a,b);
  //printf("dn=%f dnp=%f dnn=%f\n",dn / 4.0,dnp / 4.0,dnn / 4.0);

  tmp=1;

 /* #if (R2D_REFRESH==R2D_VERTICAL)
    r2d_draw_point(gc,current_x,current_y);
  #else
    r2d_draw_point(gc,current_y,current_x);
  #endif*/

  while(limit<0)
  {
     
     my=(org_x << 1) - current_y;
     mx=(org_y << 1) - current_x;

     if (!filling)
     {
        if ((lastx!=current_x) || (lasty!=current_y))
        {

		  if (r2d_check_is_in_arc_region(current_x-org_y,current_y-org_x,rgn))
             r2d_s_draw_point(gc,(current_x),(current_y),l); // D : 5


		  if (r2d_check_is_in_arc_region(mx-org_y,my-org_x,rgn))
            r2d_s_draw_point(gc,mx,my,l); // D PX PY : 6

          if ((mx != current_x) )
          {
			if (r2d_check_is_in_arc_region(current_x-org_y,my-org_x,rgn))
              r2d_s_draw_point(gc,(current_x),my,l); // D PY : 7

			if (r2d_check_is_in_arc_region(mx-org_y,current_y-org_x,rgn))
              r2d_s_draw_point(gc,mx,(current_y),l); // D PX : 8
          }

        }
     }
     else
     {
        if (current_x != lastx)
        {
		   r2d_s_arc_fill_line(gc,mx,my+1,org_y,org_x,(current_y-my)+1-2
			   ,rgn,TRUE);
           
		   if (current_x !=mx)
             r2d_s_arc_fill_line(gc,current_x,my+1,org_y,org_x,(current_y-my)+1-2
			 ,rgn,TRUE);
        }
     }

     if (dn>0) // M outside circle, point below must be drawn
     {
        dn+=dnp;
        dnp+=((bs + as) << 1);
        current_y--; // Q1
        limit+=(as + bs);
        tmp=1;
		l+=SQRT2;
     }
     else
     {
        dn+=dnn;
        dnp+=(bs << 1);
        limit+=bs;
        tmp=0;
		l+=0x10000;
        
     }
     current_x++; // Q1
     dnn+=(bs << 1);

     
     
     
     //printf("limit=%f, dn=%f,dnn=%f,dnp=%f, pos= %d %d\n",limit / 4.0,dn / 4.0,dnn / 4.0,dnp / 4.0,current_y,current_x);
     
     
  }

  end_arc:  current_x=0;
}

void           r2d_draw_arc(T_R2D_GC_PTR gc,INT16 start_angle,INT16 stop_angle,
                  INT16 ul_x,INT16 ul_y,INT16 br_x, INT16 br_y)
{
#ifdef R2D_MIRRORED_X
	INT16 tmp;
#endif
	BOOLEAN large=FALSE;
	T_R2D_ARC_REGION rgn;
	INT32 sa,sb,ea,eb;
	INT32 a,b;

	a=(br_x-ul_x)>>1;
	b=(br_y-ul_y)>>1;

	r2d_local_to_global(gc,&ul_x,&ul_y);
	r2d_local_to_global(gc,&br_x,&br_y);

    rgn.one_sector=0;
	if (stop_angle-start_angle>180)
		rgn.one_sector=1;

	if (stop_angle-start_angle==360)
         rgn.one_sector=2;

	if (start_angle==stop_angle)
		rgn.is_null=TRUE;
	else
		rgn.is_null=FALSE;
	r2d_check_angles(&start_angle,&stop_angle);
	

	sa=a * r2d_cos(start_angle); // Q16
	sb=  -b* r2d_sin(start_angle); // Q16
	// Orthogonal is (sb,-sa)

	ea= a * r2d_cos(stop_angle); // Q16
	eb= -b* r2d_sin(stop_angle); // Q16
	// Orthogonal is (-sb,sa)

	//r2d_moveto(gc,ul_x+a,ul_y+b);
	//r2d_lineto(gc,ul_x+a+(sa>>16),ul_y+b+(sb>>16));

	// Orthogonal
	//r2d_moveto(gc,ul_x+a,ul_y+b);
	//r2d_lineto(gc,ul_x+a+(sb>>16),ul_y+b+((-sa)>>16));

	//r2d_moveto(gc,ul_x+a,ul_y+b);
	//r2d_lineto(gc,ul_x+a+(ea>>16),ul_y+b+(eb>>16));

	rgn.sa=sa;
	rgn.sb=sb;


	rgn.ea=-ea;
	rgn.eb=-eb;

	
	

	

#ifdef R2D_MIRRORED_X
	   ul_x = r2d_get_width(gc)-1-ul_x;
	   br_x = r2d_get_width(gc)-1-br_x;
	   R2D_SWAP(ul_x,br_x);

	   r2d_arc_region_x_reflect(&rgn);
	   
#endif

#ifdef R2D_MIRRORED_Y
	   ul_y = r2d_get_height(gc)-1-ul_y;
	   br_y = r2d_get_height(gc)-1-br_y;
	   R2D_SWAP(ul_y,br_y);

	   r2d_arc_region_y_reflect(&rgn);
#endif

   

   r2d_df_arc(gc,ul_x,ul_y,br_x,br_y,&rgn,FALSE);
   if (((T_R2D_FRAMEBUFFER*)((T_R2D_GC*)gc)->p_frame_buffer)->kind==0)
          r2d_update_region((T_R2D_GC*)gc,ul_x,ul_y,br_x,br_y);

   r2d_check_and_send_event(gc);
}

void           r2d_fill_arc(T_R2D_GC_PTR gc, INT16 start_angle,INT16 stop_angle,
                  INT16 ul_x,INT16 ul_y,INT16 br_x, INT16 br_y)
{
#ifdef R2D_MIRRORED_X
	INT16 tmp;
#endif
	BOOLEAN large=FALSE;
	T_R2D_ARC_REGION rgn;
	INT32 sa,sb,ea,eb;
	INT32 a,b;

	a=(br_x-ul_x)>>1;
	b=(br_y-ul_y)>>1;

	r2d_local_to_global(gc,&ul_x,&ul_y);
	r2d_local_to_global(gc,&br_x,&br_y);


	rgn.one_sector=0;
	if (stop_angle-start_angle>180)
		rgn.one_sector=1;

	if (stop_angle-start_angle==360)
         rgn.one_sector=2;

	if (start_angle==stop_angle)
		rgn.is_null=TRUE;
	else
		rgn.is_null=FALSE;
	r2d_check_angles(&start_angle,&stop_angle);
	

	sa=a * r2d_cos(start_angle); // Q16
	sb=  -b* r2d_sin(start_angle); // Q16
	// Orthogonal is (sb,-sa)

	ea= a * r2d_cos(stop_angle); // Q16
	eb= -b* r2d_sin(stop_angle); // Q16
	// Orthogonal is (-sb,sa)

	//r2d_moveto(gc,ul_x+a,ul_y+b);
	//r2d_lineto(gc,ul_x+a+(sa>>16),ul_y+b+(sb>>16));

	// Orthogonal
	//r2d_moveto(gc,ul_x+a,ul_y+b);
	//r2d_lineto(gc,ul_x+a+(sb>>16),ul_y+b+((-sa)>>16));

	//r2d_moveto(gc,ul_x+a,ul_y+b);
	//r2d_lineto(gc,ul_x+a+(ea>>16),ul_y+b+(eb>>16));

	rgn.sa=sa;
	rgn.sb=sb;


	rgn.ea=-ea;
	rgn.eb=-eb;

	

#ifdef R2D_MIRRORED_X
	   ul_x = r2d_get_width(gc)-1-ul_x;
	   br_x = r2d_get_width(gc)-1-br_x;
       R2D_SWAP(ul_x,br_x);

	   r2d_arc_region_x_reflect(&rgn);
#endif

#ifdef R2D_MIRRORED_Y
	   ul_y = r2d_get_height(gc)-1-ul_y;
	   br_y = r2d_get_height(gc)-1-br_y;
	   R2D_SWAP(ul_y,br_y);

	   r2d_arc_region_y_reflect(&rgn);
#endif

   



   r2d_df_arc(gc,ul_x,ul_y,br_x,br_y,&rgn,TRUE);
   if (((T_R2D_FRAMEBUFFER*)((T_R2D_GC*)gc)->p_frame_buffer)->kind==0)
          r2d_update_region((T_R2D_GC*)gc,ul_x,ul_y,br_x,br_y);

   r2d_check_and_send_event(gc);
}

///////////////////////////////////////
//
// Copy function
//

static void r2d_diagonal_mirror(T_R2D_SHAPE_PTR rectangle)
{
   T_R2D_RECTANGLE *r;
   INT16 tmp;
   r=(T_R2D_RECTANGLE *)rectangle;

   tmp=r->ul_x;
   r->ul_x=r->ul_y;
   r->ul_y=tmp;

   tmp=r->br_x;
   r->br_x=r->br_y;
   r->br_y=tmp;
}

// Global coordinates
static void r2d_mirror_rectangle(T_R2D_GC_PTR gc,T_R2D_SHAPE_PTR rectangle)
{
   T_R2D_RECTANGLE *r;
   //INT16 org_x,org_y;
#ifdef R2D_MIRRORED_X
   INT16 tmp;
#endif
   r=(T_R2D_RECTANGLE *)rectangle;

   
#ifdef R2D_MIRRORED_X
   r->ul_x = r2d_get_width(gc)-r->ul_x;
   r->br_x = r2d_get_width(gc)-r->br_x;
   tmp=r->ul_x;
	r->ul_x=r->br_x;
	r->br_x=tmp;
#endif

#ifdef R2D_MIRRORED_Y
	r->ul_y = r2d_get_height(gc)-r->ul_y;
	r->br_y = r2d_get_height(gc)-r->br_y;

    tmp=r->ul_y;
	r->ul_y=r->br_y;
	r->br_y=tmp;
#endif

	   
}

// Global coordinates
// Here a rectangle with clipping convention is mirrored
// The resulting rectangle (s_clipping) is used with drawing
// convention. So, the boundary must be updated
static void r2d_mirror_clip_rectangle(T_R2D_GC_PTR gc,T_R2D_SHAPE_PTR rectangle)
{
   T_R2D_RECTANGLE *r;
//   INT16 org_x,org_y;
#ifdef R2D_MIRRORED_X
   INT16 tmp;
#endif
   r=(T_R2D_RECTANGLE *)rectangle;

   
   //Be careful br_x is NOT a line wich must be drawn
#ifdef R2D_MIRRORED_X
   r->ul_x = r2d_get_width(gc)-r->ul_x+1;
   r->br_x = r2d_get_width(gc)-(r->br_x-1);
   tmp=r->ul_x;
	r->ul_x=r->br_x;
	r->br_x=tmp;
#endif

#ifdef R2D_MIRRORED_Y
	r->ul_y = r2d_get_height(gc)-r->ul_y+1;
	r->br_y = r2d_get_height(gc)-(r->br_y-1);

    tmp=r->ul_y;
	r->ul_y=r->br_y;
	r->br_y=tmp;
#endif

	   
}

// Compute the intersection of the clipping shape of srcGc with
// the srcRectangle. Report he size reduction onto dstRectangle.
// Compute the intersection between dstRectangle and the clipping rectangle
// of dstGc and report the size reduction to srcRectangle.
// At the end, one get two rectangles of same size.
// The first one is contained in the clipping shape of srcGc
// and the second one in the clipping shape of dstGc.
// If the result is null, false is returned and no  copy is done
// The rectangles are modified.
static BOOLEAN r2d_clipped_is_not_null(T_R2D_GC* src_gc,T_R2D_GC *dst_gc,
                                       T_R2D_RECTANGLE* src_rectangle,T_R2D_RECTANGLE* dst_rectangle)
{
  BOOLEAN result=TRUE;
  //CC : clipping coordinate , RC : rectangle coordinate
  INT16 delta,CC,RC;

#if (R2D_DEBUG == R2D_ON)
#if (R2D_DEBUG_WARNING == R2D_DEBUG_HIGH)
	if (src_gc->p_clipping_shape==NULL)
	  rvf_send_trace("R2D : clipping shape error",26, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, r2d_use_id );
	if (dst_gc->p_clipping_shape==NULL)
	  rvf_send_trace("R2D : clipping shape error",26, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, r2d_use_id );
#endif
#endif

  //T_R2D_RECTANGLE *debug;

  //debug=(T_R2D_RECTANGLE*)src_gc->p_clipping_shape;


  // Intersections in src context
  CC=r2d_get_xmin(src_gc->p_clipping_shape);
  RC=r2d_get_xmin(src_rectangle);
  if ( CC > RC)
  {
     delta=CC-RC;
     src_rectangle->ul_x=CC;
     dst_rectangle->ul_x+=delta;
  }

  CC=r2d_get_xmax(src_gc->p_clipping_shape);
  RC=r2d_get_xmax(src_rectangle);
  if ( RC > CC)
  {
     delta=RC-CC;
     src_rectangle->br_x=CC;
     dst_rectangle->br_x-=delta;
  }

  CC=r2d_get_ymin(src_gc->p_clipping_shape);
  RC=r2d_get_ymin(src_rectangle);
  if ( CC > RC)
  {
     delta=CC-RC;
     src_rectangle->ul_y=CC;
     dst_rectangle->ul_y+=delta;
  }

  CC=r2d_get_ymax(src_gc->p_clipping_shape);
  RC=r2d_get_ymax(src_rectangle);
  if ( RC > CC)
  {
     delta=RC-CC;
     src_rectangle->br_y=CC;
     dst_rectangle->br_y-=delta;
  }

  // Intersection in dst context
  CC=r2d_get_xmin(dst_gc->p_clipping_shape);
  RC=r2d_get_xmin(dst_rectangle);
  if ( CC > RC)
  {
     delta=CC-RC;
     dst_rectangle->ul_x=CC;
     src_rectangle->ul_x+=delta;
  }

  CC=r2d_get_xmax(dst_gc->p_clipping_shape);
  RC=r2d_get_xmax(dst_rectangle);
  if ( RC > CC)
  {
     delta=RC-CC;
     dst_rectangle->br_x=CC;
     src_rectangle->br_x-=delta;
  }

  CC=r2d_get_ymin(dst_gc->p_clipping_shape);
  RC=r2d_get_ymin(dst_rectangle);
  if ( CC > RC)
  {
     delta=CC-RC;
     dst_rectangle->ul_y=CC;
     src_rectangle->ul_y+=delta;
  }

  CC=r2d_get_ymax(dst_gc->p_clipping_shape);
  RC=r2d_get_ymax(dst_rectangle);
  if ( RC > CC)
  {
     delta=RC-CC;
     dst_rectangle->br_y=CC;
     src_rectangle->br_y-=delta;
  }

  if (src_rectangle->ul_x>=src_rectangle->br_x)
   result=FALSE;


  if (src_rectangle->ul_y>=src_rectangle->br_y)
   result=FALSE;

  if (result)
  {
    /*printf("src: (%d,%d) -- (%d,%d)\n",src_rectangle->ul_x,src_rectangle->ul_y
    ,src_rectangle->br_x,src_rectangle->br_y);
    printf("dst: (%d,%d) -- (%d,%d)\n",dst_rectangle->ul_x,dst_rectangle->ul_y
    ,dst_rectangle->br_x,dst_rectangle->br_y);*/

    // Conversion of clipped rectangles to framebuffer coordinates
    r2d_local_to_global(src_gc,&(src_rectangle->ul_x),&(src_rectangle->ul_y));
    r2d_local_to_global(src_gc,&(src_rectangle->br_x),&(src_rectangle->br_y));
    r2d_local_to_global(dst_gc,&(dst_rectangle->ul_x),&(dst_rectangle->ul_y));
    r2d_local_to_global(dst_gc,&(dst_rectangle->br_x),&(dst_rectangle->br_y));

#if (R2D_DEBUG == R2D_ON)
#if (R2D_DEBUG_WARNING == R2D_DEBUG_HIGH)
	if (src_rectangle->ul_x<0)
	  rvf_send_trace("R2D : clipping shape error",26, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );

	if (src_rectangle->ul_y<0)
	  rvf_send_trace("R2D : clipping shape error",26, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );

	if (dst_rectangle->ul_x<0)
	  rvf_send_trace("R2D : clipping shape error",26, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );


	if (dst_rectangle->ul_y<0)
	  rvf_send_trace("R2D : clipping shape error",26, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );

	if (src_rectangle->br_x>r2d_get_width(src_gc))
	  rvf_send_trace("R2D : clipping shape error",26, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );

	if (src_rectangle->br_y>r2d_get_height(src_gc))
	  rvf_send_trace("R2D : clipping shape error",26, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );

	if (dst_rectangle->br_x>r2d_get_width(dst_gc))
	  rvf_send_trace("R2D : clipping shape error",26, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );

	if (dst_rectangle->br_y>r2d_get_height(dst_gc))
	  rvf_send_trace("R2D : clipping shape error",26, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );

#endif
#endif
    /*printf("src: (%d,%d) -- (%d,%d)\n",src_rectangle->ul_x,src_rectangle->ul_y
    ,src_rectangle->br_x,src_rectangle->br_y);
    printf("dst: (%d,%d) -- (%d,%d)\n",dst_rectangle->ul_x,dst_rectangle->ul_y
    ,dst_rectangle->br_x,dst_rectangle->br_y);*/
  }

  return(result);
}

T_R2D_ERROR           r2d_low_level_blit_rect(T_R2D_GC_PTR src_gc,T_R2D_GC_PTR dst_gc,
                         T_R2D_SHAPE_PTR org_src_rectangle, T_R2D_SHAPE_PTR org_dst_rectangle,
						 BOOLEAN src_mirrored,BOOLEAN dst_mirrored,
						 BOOLEAN use_foreground_color)
{

   INT16 kind_src,kind_dst,org_bx,org_by,org_ux,org_uy;
#if (R2D_ASM == R2D_ON)
   T_R2D_DRAWING_MODE mode;
#endif

   T_R2D_SHAPE_PTR src_rectangle,dst_rectangle;

#if (R2D_DEBUG == R2D_ON)
#if (R2D_DEBUG_WARNING == R2D_DEBUG_HIGH)
   if (src_gc==NULL)
   {
	  rvf_send_trace("src_gc NULL",11, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, r2d_use_id );
	  rvf_delay(RVF_SECS_TO_TICKS(1));
   }

   if (dst_gc==NULL)
   {
	  rvf_send_trace("dst_gc NULL",11, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, r2d_use_id );
	  rvf_delay(RVF_SECS_TO_TICKS(1));\
   }

   if (org_src_rectangle==NULL)
   {
	  rvf_send_trace("org_src NULL",12, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, r2d_use_id );
	  rvf_delay(RVF_SECS_TO_TICKS(1));\
   }

   if (org_dst_rectangle==NULL)
   {
	  rvf_send_trace("org_dst NULL",12, NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, r2d_use_id );
	  rvf_delay(RVF_SECS_TO_TICKS(1));\
   }
#endif
#endif

   

    src_rectangle=r2d_clone_shape(r2d_mb_id,org_src_rectangle);
    if (src_rectangle==NULL)
	   return(R2D_MEMORY_ERR);
	

    dst_rectangle=r2d_clone_shape(r2d_mb_id,org_dst_rectangle);
    if (dst_rectangle==NULL)
    {
	   r2d_release_shape(src_rectangle);
	   return(R2D_MEMORY_ERR);
    }

	r2d_disable_refresh();

	org_bx=((T_R2D_RECT*)src_rectangle)->br_x;
    org_by=((T_R2D_RECT*)src_rectangle)->br_y;
	org_ux=((T_R2D_RECT*)src_rectangle)->ul_x;
    org_uy=((T_R2D_RECT*)src_rectangle)->ul_y;
	r2d_local_to_global(src_gc,&org_ux,&org_uy);
	r2d_local_to_global(src_gc,&org_bx,&org_by);
    if (r2d_clipped_is_not_null(src_gc,dst_gc,src_rectangle,dst_rectangle))
	{
   // Rects are now clipped and in global coordinates

if (src_mirrored) 
  r2d_mirror_rectangle(src_gc,src_rectangle);

if (dst_mirrored)
   r2d_mirror_rectangle(dst_gc,dst_rectangle);

// In that case we are drawing text.
// If dst rect clipped by the right side, the src must be shifted to 
// the start of the char
// and must not remained aligned with the end of the char
// (don't forget that since char is drawn with mirror its start
// is corresponding to the right and bottom side of the bounding
// rectangle)
// There is the dual problem when the dst rect is clipped by the
// left side

if ((dst_mirrored) && (!src_mirrored))
{
  INT16 dbx,dby,dux,duy;
  dbx=0;
  dux=0;
  dby=0;
  duy=0;

#ifdef R2D_MIRRORED_X
  dbx=org_bx-((T_R2D_RECT*)src_rectangle)->br_x;
  dux=org_ux-((T_R2D_RECT*)src_rectangle)->ul_x;
#endif

#ifdef R2D_MIRRORED_Y
  dby=org_by-((T_R2D_RECT*)src_rectangle)->br_y;
  duy=org_uy-((T_R2D_RECT*)src_rectangle)->ul_y;
#endif

  r2d_translate_shape(src_rectangle,dbx,dby);
  r2d_translate_shape(src_rectangle,dux,duy);
}



 // After mirrong one is in L coordinates


  if (((T_R2D_FRAMEBUFFER*)((T_R2D_GC*)dst_gc)->p_frame_buffer)->kind==0)
          r2d_update_region((T_R2D_GC*)dst_gc,r2d_get_xmin(dst_rectangle),
		  r2d_get_ymin(dst_rectangle),
		  r2d_get_xmax(dst_rectangle),
		  r2d_get_ymax(dst_rectangle));

#if (R2D_REFRESH != R2D_VERTICAL)
  r2d_diagonal_mirror(src_rectangle);
  r2d_diagonal_mirror(dst_rectangle);
#endif

  // After swap one is in S coordinates

   kind_src=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)src_gc)->p_frame_buffer))->kind;
   kind_dst=((T_R2D_FRAMEBUFFER*)(((T_R2D_GC*)dst_gc)->p_frame_buffer))->kind;

    
#if (R2D_ASM == R2D_OFF)

   if ((kind_src!=R2D_FULL_KIND) && (kind_dst!=R2D_FULL_KIND))
     IND_r2d_blit_lcd_to_lcd(src_gc,dst_gc,src_rectangle,dst_rectangle,use_foreground_color);
   else
   if ((kind_src==R2D_FULL_KIND) && (kind_dst==R2D_FULL_KIND))
     IND_r2d_blit_color_to_color(src_gc,dst_gc,src_rectangle,dst_rectangle,use_foreground_color);
   else
   if ((kind_src!=R2D_FULL_KIND) && (kind_dst==R2D_FULL_KIND))
     IND_r2d_blit_lcd_to_color(src_gc,dst_gc,src_rectangle,dst_rectangle,use_foreground_color);
   else
   if ((kind_src==R2D_FULL_KIND) && (kind_dst!=R2D_FULL_KIND))
     IND_r2d_blit_color_to_lcd(src_gc,dst_gc,src_rectangle,dst_rectangle,use_foreground_color);

#else
   mode=(((T_R2D_GC*)dst_gc))->drawing_mode;
   rvf_lock_mutex(r2d_g_blit_mutex);

   if ((kind_src!=R2D_FULL_KIND) && (kind_dst!=R2D_FULL_KIND))
   {
	 r2d_patch_blit(dst_gc,mode,
					use_foreground_color,R2D_LCDLCD);
     r2d_blit_asm(src_gc,dst_gc,src_rectangle,dst_rectangle,
	 use_foreground_color,R2D_LCDLCD);
   }
   else
   if ((kind_src==R2D_FULL_KIND) && (kind_dst==R2D_FULL_KIND))
   {
	   r2d_patch_blit(dst_gc,mode,
					use_foreground_color,R2D_COLORCOLOR);
     r2d_blit_asm(src_gc,dst_gc,src_rectangle,dst_rectangle,
	 use_foreground_color,R2D_COLORCOLOR);
   }
   else
   if ((kind_src!=R2D_FULL_KIND) && (kind_dst==R2D_FULL_KIND))
   {
	   r2d_patch_blit(dst_gc,mode,
					use_foreground_color,R2D_LCDCOLOR);
     r2d_blit_asm(src_gc,dst_gc,src_rectangle,dst_rectangle,
	 use_foreground_color,R2D_LCDCOLOR);
   }
   else
   if ((kind_src==R2D_FULL_KIND) && (kind_dst!=R2D_FULL_KIND))
   {
	   r2d_patch_blit(dst_gc,mode,
					use_foreground_color,R2D_COLORLCD);
     r2d_blit_asm(src_gc,dst_gc,src_rectangle,dst_rectangle,
	 use_foreground_color,R2D_COLORLCD);
   }
   rvf_unlock_mutex(r2d_g_blit_mutex);

#endif

   
   r2d_check_and_send_event(dst_gc);
	}
	 r2d_release_shape(src_rectangle);
   r2d_release_shape(dst_rectangle);
   r2d_enable_refresh();
   return(R2D_OK);
}

T_R2D_ERROR           r2d_blit_rect(T_R2D_GC_PTR src_gc,T_R2D_GC_PTR dst_gc,
                         T_R2D_SHAPE_PTR org_src_rectangle, 
						 T_R2D_SHAPE_PTR org_dst_rectangle,
						 BOOLEAN use_foreground_color)
{
		// Allow reversing if needed
	return(r2d_low_level_blit_rect(src_gc,dst_gc,org_src_rectangle,org_dst_rectangle,TRUE,TRUE,use_foreground_color));
}



///////////////////////////////////////
//
// Text functions
//

T_R2D_CHAR_METRIC_PTR r2d_get_char_metrics(T_R2D_GC_PTR gc,UINT32 the_char)
{
  INT32 *p;
  INT32 new_char;

  new_char=r2d_ptree_find(((T_R2D_GC*)gc)->font_table,the_char);

  p=((T_R2D_GC*)gc)->font_metrics;
  p+=(new_char<<3);

  *p++;

  return((T_R2D_CHAR_METRIC_PTR)p);
}

T_R2D_ERROR r2d_draw_char(T_R2D_GC_PTR font_cache_gc,
                    T_R2D_GC_PTR gc,
                    T_R2D_GC_PTR fontgc,
                    INT16 x,INT16 y,INT16 org_size,T_R2D_CHAR_METRIC_PTR met)
{
    
    T_R2D_SHAPE_PTR src_rectangle,dst_rectangle,tdst_rectangle;
    

    INT32 *p;
    INT16 underline;
//	INT32 new_char;
	INT16 style;
	INT16 ascent;
	T_R2D_ERROR err;

	style=((T_R2D_GC *)gc)->internal_text_style;
	ascent=((T_R2D_GC*)gc)->font_metrics[R2D_BUFFER_WIDTH_POS+1];

	err=R2D_OK;


    p=((T_R2D_GC*)gc)->font_metrics;
    underline=*--p;
   

    
    {
       
	   
       
       if (style & R2D_BOLD)
       {
//           T_R2D_DRAWING_MODE the_mode;
//           T_R2D_ARGB_COLOR bg_color;

#if (R2D_REFRESH == R2D_VERTICAL)
           src_rectangle=r2d_new_rectangle(r2d_mb_id,r2d_get_char_x(met),0,
		   r2d_get_char_x(met)+r2d_get_char_width(met),
		   r2d_get_char_height(met));
#else
		   // In horizontal mode char are organized vertically
		   src_rectangle=r2d_new_rectangle(r2d_mb_id,0,r2d_get_char_x(met),
			   r2d_get_char_width(met),r2d_get_char_x(met)+r2d_get_char_height(met));
#endif
		   if (src_rectangle==NULL)
		   {
			   err=R2D_MEMORY_ERR;
			   return(err);
		   }
		   //dst_rectangle=r2d_new_rectangle(0,0,char_width+1,char_height);
		   //if (dst_rectangle==NULL)
		   //{
		//	   r2d_release_shape(src_rectangle);
		//	   *err=1;
		//	   return(0);
		   //}
           
           // erase temporary char if R2D is starting to draw a new char
           // (it is not always the case with diacritics chars)
           
		   //r2d_set_background_color_with_argb(font_cache_gc,0,0,255,0);
		   r2d_fill_rectangle(font_cache_gc,-1,-1,r2d_get_width(font_cache_gc)+1,
			   r2d_get_height(font_cache_gc)+1);
		   //r2d_set_background_color_with_argb(font_cache_gc,0,255,255,255);

           //r2d_release_shape(dst_rectangle);
                
           // Create destination rectangles 
		   dst_rectangle=r2d_new_rectangle(r2d_mb_id,0,0,r2d_get_char_width(met),
			   r2d_get_char_height(met));
		   if (dst_rectangle==NULL)
		   {
			   r2d_release_shape(src_rectangle);
			   err=R2D_MEMORY_ERR;
			   return(err);
		   }

           tdst_rectangle=r2d_clone_shape(r2d_mb_id,dst_rectangle);
		   if (tdst_rectangle==NULL)
		   {
			   r2d_release_shape(src_rectangle);
			   r2d_release_shape(dst_rectangle);
			   err=R2D_MEMORY_ERR;
			   return(err);
		   }

           r2d_translate_shape(tdst_rectangle,1,0);


           // set mode
           r2d_set_drawing_mode(font_cache_gc,R2D_OR_MODE);

           // Build bold char

           if (r2d_low_level_blit_rect(fontgc,font_cache_gc,src_rectangle,dst_rectangle,
			   FALSE,FALSE,FALSE)!=R2D_OK)
		   {
			   r2d_release_shape(src_rectangle);
			   r2d_release_shape(dst_rectangle);
			   r2d_release_shape(tdst_rectangle);
			   err=R2D_MEMORY_ERR;
			   return(err);
		   }

           if (r2d_low_level_blit_rect(fontgc,font_cache_gc,src_rectangle,tdst_rectangle,
			   FALSE,FALSE,FALSE)!=R2D_OK)
		   {
			   r2d_release_shape(src_rectangle);
			   r2d_release_shape(dst_rectangle);
			   r2d_release_shape(tdst_rectangle);
			   err=R2D_MEMORY_ERR;
			   return(err);
		   }

		   if (style & R2D_STRIKETHROUGH)
		   {
		     r2d_moveto(font_cache_gc,0,ascent>>1);
		     r2d_lineto(font_cache_gc,r2d_get_char_width(met),ascent>>1);
		   }

           // Reset mode
           r2d_set_drawing_mode(font_cache_gc,R2D_COPY_MODE);

           r2d_release_shape(tdst_rectangle);

           r2d_release_shape(dst_rectangle);
           r2d_release_shape(src_rectangle);

           // Recreate src and dest rectangle
           src_rectangle=r2d_new_rectangle(r2d_mb_id,0,0,r2d_get_char_width(met)+1,
			   r2d_get_char_height(met));
		   if (src_rectangle==NULL)
		   {
			   err=R2D_MEMORY_ERR;
			   return(err);
		   }
		   
		   if (org_size != 0)
		  {
			  INT16 tmp;

			  tmp=(org_size-r2d_get_char_width(met))>>1;
			  dst_rectangle=r2d_new_rectangle(r2d_mb_id,x+tmp,y-r2d_get_char_height(met),
				  x+tmp+r2d_get_char_width(met)+1,y);
		  }
		  else
          dst_rectangle=r2d_new_rectangle(r2d_mb_id,x+r2d_get_char_org_x(met),
		  y-r2d_get_char_org_y(met),
		  x+r2d_get_char_width(met)+r2d_get_char_org_x(met)+1,
		  y+r2d_get_char_height(met)-r2d_get_char_org_y(met));
          
           if (dst_rectangle==NULL)
		   {
			   r2d_release_shape(src_rectangle);
			   err=R2D_MEMORY_ERR;
			   return(err);
		   }
           //printf("free_pos=%d, char_width=%d\n",free_pos,char_width);
           if (r2d_low_level_blit_rect(font_cache_gc,gc,src_rectangle,dst_rectangle,
			   FALSE,TRUE,TRUE)!=R2D_OK)
		   {
			   r2d_release_shape(src_rectangle);
			   r2d_release_shape(dst_rectangle);
			   err=R2D_MEMORY_ERR;
			   return(err);
		   }

       }
       else 
       {
          #if (R2D_REFRESH == R2D_VERTICAL)
           src_rectangle=r2d_new_rectangle(r2d_mb_id,r2d_get_char_x(met),
			   0,
			   r2d_get_char_x(met)+r2d_get_char_width(met),
			   r2d_get_char_height(met));
#else
		   // In horizontal mode char are organized vertically
		   src_rectangle=r2d_new_rectangle(r2d_mb_id,0,
			   r2d_get_char_x(met),
			   r2d_get_char_width(met),
			   r2d_get_char_x(met)+r2d_get_char_height(met));
#endif
		  if (src_rectangle==NULL)
		  {
			   err=R2D_MEMORY_ERR;
			   return(err);
		  }
          
		  if (org_size != 0)
		  {
			  INT16 tmp;

			  tmp=(org_size-r2d_get_char_width(met))>>1;
			  dst_rectangle=r2d_new_rectangle(r2d_mb_id,x+tmp,
				  y-r2d_get_char_height(met),
				  x+tmp+r2d_get_char_width(met),y);
		  }
		  else
          dst_rectangle=r2d_new_rectangle(r2d_mb_id,
		  x+r2d_get_char_org_x(met),
		  y-r2d_get_char_org_y(met),
		  x+r2d_get_char_width(met)+r2d_get_char_org_x(met),
		  y+r2d_get_char_height(met)-r2d_get_char_org_y(met));
          
		  if (dst_rectangle==NULL)
		  {
			   r2d_release_shape(src_rectangle);
			   err=R2D_MEMORY_ERR;
			   return(err);
		  }

		  if (style & R2D_STRIKETHROUGH)
		  {
			  r2d_fill_rectangle(font_cache_gc,-1,-1,r2d_get_width(font_cache_gc)+1,
			   r2d_get_height(font_cache_gc)+1);
			  tdst_rectangle=r2d_new_rectangle(r2d_mb_id,0,0,r2d_get_char_width(met),
			   r2d_get_char_height(met));

            if (tdst_rectangle==NULL)
			{
			   r2d_release_shape(src_rectangle);
			   r2d_release_shape(dst_rectangle);
			   err=R2D_MEMORY_ERR;
			   return(err);
			}

              err=r2d_low_level_blit_rect(fontgc,font_cache_gc,src_rectangle,tdst_rectangle,
			  FALSE,FALSE,FALSE);
			  if (err==R2D_OK)
			  {
			    r2d_moveto(font_cache_gc,0,ascent>>1);
			    r2d_lineto(font_cache_gc,r2d_get_char_width(met),ascent>>1);
                err=r2d_low_level_blit_rect(font_cache_gc,gc,tdst_rectangle,dst_rectangle,
			      FALSE,TRUE,TRUE);
			  }

			  r2d_release_shape(tdst_rectangle);
		  }
		  else
		  {
			  err=r2d_low_level_blit_rect(fontgc,gc,src_rectangle,dst_rectangle,
			  FALSE,TRUE,TRUE);
		  }

          if (err!=R2D_OK)
		  {
			   r2d_release_shape(src_rectangle);
			   r2d_release_shape(dst_rectangle);
			   err=R2D_MEMORY_ERR;
			   return(err);
		  }


       }



       if (style & R2D_UNDERLINED)
       {
           r2d_moveto(gc,x+r2d_get_char_org_x(met),y+underline);
           r2d_lineto(gc,x+r2d_get_char_org_x(met)+
			   r2d_get_char_dx(met),y+underline);
       }
       
       r2d_release_shape(src_rectangle);
       r2d_release_shape(dst_rectangle);

       
    }
   return(err);
}


#define R2D_ENDIAN_SWAP(a) {misc=(a&0x0FF) << 8;a=a>>8;a=a|misc;a=a&0x0FFFF;}

UINT32 r2d_get_next_char(T_R2D_UTF16 *the_text,INT16 *pos,UINT16 max_chars,
							  BOOLEAN *swapping)
{
	T_R2D_UTF16 current;
	INT16 temp;
	INT32 the_char;
	BOOLEAN must_display,combining,done;
	T_R2D_UTF16 next, misc;
//	T_R2D_CHAR_METRIC_PTR p;
	// Swapping should be set to FALSE first time this function is called


	
	
	// current char consider a WHOLE char
	// (when combining char are used, they are considered
	// as making ONE char)
	done=FALSE;

   // Detection of byte order mark
	if (the_text[*pos] == 0xFFFE)
	{
		*swapping=TRUE;
		*pos=*pos+1;
	}
    while ((!done) && (the_text[*pos]!=0) && (*pos<max_chars))
    {
		must_display=FALSE;
		combining=FALSE;

        current=the_text[*pos];
		*pos=*pos+1;
        if (*swapping)
			R2D_ENDIAN_SWAP(current);
		
	    if ((current != 0x0FFFF))
		{
	     // If High-surrogate 
		 if ((current >= 0xd800) && (current <= 0xdbff))
		 {
			 // Then check that next char if a low-surrogate
			 next=the_text[*pos];
			 if (*swapping)
			   R2D_ENDIAN_SWAP(next);
			 
			 if ((next >= 0xdc00) && (next<=0xdfff))
			 {
				 *pos=*pos+1;
				 the_char=(current - 0xd800) * 0x400 + (next - 0xdc00) + 0x10000;
				 must_display=TRUE;
			 }
			 else
			 {
			     rvf_send_trace("r2d_get_next_char() missing low surrogate char",
			        strlen("r2d_get_next_char() missing low surrogate char"), NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );
			 }
		 }
		 else
		 {
			 // If not a high-surrogate then check it is not
			 // a low-surrogate
			 if ((current < 0xdc00) || (current>0xdfff))
			 {
				 the_char=current;
				 must_display=TRUE;
			 }
			 else
			 {
			     rvf_send_trace("R2D : r2d_get_next_char unexpected low surrogate char",
			        strlen("R2D : r2d_get_next_char unexpected low surrogate char"), NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );
			 }

		 }
		}
		
		 if ((the_char>=0x300) && (the_char <=0x36f))
			combining=TRUE;

		 if (must_display)
		 {
		   
		   if (!combining)
		   {
		     // Next char
			   done=TRUE;
			   
		   }
		 }
		
       
    }
	if (done)
	  return(the_char);
	else
		return(0);
}
//
static T_R2D_ERROR          r2d_low_draw_text(T_R2D_GC_PTR gc,INT16 x,INT16 y,
									   T_R2D_UTF16 *the_text,
									   T_R2D_TEXT_DRAWING_SETTINGS settings,
									   UINT16 max_words,
									   UINT16 *width,
									   UINT16 *height)
{
    T_R2D_GC_PTR fontgc;
    T_R2D_GC_PTR cache_gc;
    BOOLEAN draw;
    T_R2D_DRAWING_MODE the_mode;
	T_R2D_UTF16 *temp;
	INT16 err;
	INT16 current_word;
	INT32 the_char;
	BOOLEAN must_display,swapping,combining;
	INT16 delta,deltay,misc,current_y,maxx,delta_line,y_org;
	T_R2D_UTF16 next,current;
	T_R2D_CHAR_METRIC_PTR p;
	
	
    INT16 x_org;



	draw=((settings & R2D_TEXT_DRAW)==R2D_TEXT_DRAW);

	if (the_text==NULL)
		return(R2D_MEMORY_ERR);

	x_org=x;
	y_org=y;

	maxx=0;

	

	current_word=0; // We are at first word in string
	// current word consider a word which may be a partial char
	// (when combining char are used, they are considered
	// as making ONE char)
    swapping=FALSE;

    if (draw)
    {
        // +1 used since blit_rect is using a bounding rect
        cache_gc=r2d_new_font_buffer_context(r2d_mb_id,((T_R2D_GC*)gc)->font_frame_buffer->kind,
            ((T_R2D_GC*)gc)->font_metrics[R2D_BUFFER_WIDTH_POS]+1,// max width for free area
            ((T_R2D_GC*)gc)->font_metrics[R2D_BUFFER_WIDTH_POS+1]+ // ascent
            ((T_R2D_GC*)gc)->font_metrics[R2D_BUFFER_WIDTH_POS+2]+ // descent
            ((T_R2D_GC*)gc)->font_metrics[R2D_BUFFER_WIDTH_POS+3]); // leading
        
        delta_line=((T_R2D_GC*)gc)->font_metrics[R2D_BUFFER_WIDTH_POS+1]+ // ascent
            ((T_R2D_GC*)gc)->font_metrics[R2D_BUFFER_WIDTH_POS+2]+ // descent
            ((T_R2D_GC*)gc)->font_metrics[R2D_BUFFER_WIDTH_POS+3];
        
        
        if (cache_gc==NULL)
            return(R2D_MEMORY_ERR);
        
        r2d_context_lock(cache_gc);
        
        fontgc=r2d_new_context(r2d_mb_id,((T_R2D_GC*)gc)->font_frame_buffer);
        //r2d_release_framebuffer(((T_R2D_GC*)gc)->font_frame_buffer);
        
        
        if (fontgc==NULL)
        {
            r2d_context_unlock(cache_gc);
            r2d_release_context(cache_gc);
            return(R2D_MEMORY_ERR);
        }
        
        r2d_context_lock(fontgc);
    
        r2d_set_background_color_with_argb(fontgc,0,255,255,255);
        r2d_set_foreground_color_with_argb(fontgc,0,0,0,0);
    
        the_mode=r2d_get_drawing_mode(gc);
    }
    
    err=R2D_OK;
	delta=0;
	deltay=0;
	current_y=y;
	// Detection of byte order mark
	if (*the_text == 0xFFFE)
	{
		swapping=TRUE;
		the_text++;
		current_word++;
	}
    while((*the_text!=0) && (err==R2D_OK) && (current_word<max_words))
    {
		must_display=FALSE;
		combining=FALSE;
		if (the_char!=0xa)
		  x+=delta;

		delta = 0;

        current=*the_text++;
		current_word++;

		if (swapping)
			R2D_ENDIAN_SWAP(current);
		
	    if ((current != 0x0FFFF))
		{
	     // If High-surrogate 
		 if ((current >= 0xd800) && (current <= 0xdbff))
		 {
			 // Then check that next char if a low-surrogate
			 next=*the_text;
			 if (swapping)
			    R2D_ENDIAN_SWAP(next);
			 if ((next >= 0xdc00) && (next<=0xdfff))
			 {
				 the_text++;
				 current_word++;
				 the_char=(current - 0xd800) * 0x400 + (next - 0xdc00) + 0x10000;
				 must_display=TRUE;
			 }
			 else
			 {
			     rvf_send_trace("r2d_low_draw_text() missing low surrogate char",
			        strlen("r2d_low_draw_text() missing low surrogate char"), NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );
			 }
		 }
		 else
		 {
			 // If not a high-surrogate then check it is not
			 // a low-surrogate
			 if ((current < 0xdc00) || (current>0xdfff))
			 {
				 the_char=current;
				 must_display=TRUE;
			 }
			 else
			 {
			     rvf_send_trace("r2d_low_draw_text() unexpected low surrogate char",
			        strlen("r2d_low_draw_text() unexpected low surrogate char"), NULL_PARAM, 
				   RV_TRACE_LEVEL_ERROR, R2D_USE_ID );
			 }
		 }
		}
		
		 if ((the_char>=0x300) && (the_char <=0x36f))
			combining=TRUE;
		 else
			current_y=y;

		 if (the_char==0xa)
		 {
			 if ((x-x_org)>maxx)
				 maxx=x-x_org;
			 
			 if ((x_org-x)>maxx)
				 maxx=x_org-x;
			 x=x_org;
			 y += delta_line;

		 }

		 if ((must_display) && (the_char!=0xa))
		 {
		   p=r2d_get_char_metrics(gc,the_char);
		   if (combining)
		   {
			  
			  if (draw)
			  {
				
				current_y -= deltay;
				x=x-delta;
				
				if (((T_R2D_GC*)gc)->script_mode==R2D_LEFT_TO_RIGHT)
                  err=r2d_draw_char(cache_gc,gc,fontgc,x,current_y,delta,p);
				else
                  err=r2d_draw_char(cache_gc,gc,fontgc,x+delta,current_y,delta,p);
				deltay=r2d_get_char_height(p);
			  }
		   }
		   else
		   {
		     if (draw)
			 {
				 
                
				if (((T_R2D_GC*)gc)->script_mode==R2D_LEFT_TO_RIGHT)
				{
				  delta=r2d_get_char_dx(p);
				  err=r2d_draw_char(cache_gc,gc,fontgc,x,current_y,0,p);
			      
				}
				else
				{
				   delta=-r2d_get_char_dx(p);
				   err=r2d_draw_char(cache_gc,gc,fontgc,x+delta,current_y,0,p);
				}
				deltay=r2d_get_char_height(p);
				
			 }
			 else
			 {
				 
				if (((T_R2D_GC*)gc)->script_mode==R2D_LEFT_TO_RIGHT)
			      delta=r2d_get_char_dx(p);
				else
                  delta=-r2d_get_char_dx(p);
			 }
		   }
		 }
		
       
    }
	if (the_char!=0xa)
	  x+=delta;

	if ((x-x_org)>maxx)
				 maxx=x-x_org;
			 
	if ((x_org-x)>maxx)
				 maxx=x_org-x;

	/*if (((T_R2D_GC*)gc)->script_mode==R2D_LEFT_TO_RIGHT)
	  *result=x-x_org;
	else
      *result=x_org-x;*/

	*width=maxx;
	*height=y-y_org+delta_line;

    if (draw)
    {
        r2d_set_drawing_mode(gc,the_mode);

        r2d_context_unlock(fontgc);
        r2d_context_unlock(cache_gc);
        r2d_release_context(fontgc);
        r2d_release_context(cache_gc);

	    r2d_check_and_send_event(gc);
    }

	return(err);
	
}

T_R2D_ERROR   r2d_get_text_width(T_R2D_GC_PTR gc,T_R2D_UTF16 *the_text,UINT16 *size)
{
    UINT16 x,y;
	T_R2D_ERROR err;
	err=R2D_OK;


    err=r2d_low_draw_text(gc,0,0,the_text,0,-1,&x,&y);

	if (err!=R2D_OK)
	 *size=1;
    else
	{
	  if (x>=0)
        *size=x;
      else
        *size=-x;
	}

	return(err);
}

T_R2D_ERROR   r2d_get_width_of_chars(T_R2D_GC_PTR gc,T_R2D_UTF16 *the_text,
									 UINT16 nb_chars,UINT16 *size)
{
    UINT16 x,y;
	T_R2D_ERROR err;

    err=r2d_low_draw_text(gc,0,0,the_text,0,nb_chars,&x,&y);


	if (err!=R2D_OK)
		*size=1;
    else
	{
	  if (x>=0)
        *size=x;
      else
        *size=-x;
	}

	return(err);
}


T_R2D_ERROR          r2d_draw_text(T_R2D_GC_PTR gc,INT16 x,INT16 y,T_R2D_UTF16 *the_text)
{
	UINT16 r,h;
	return(r2d_low_draw_text(gc,x,y,the_text,R2D_TEXT_DRAW,-1,&r,&h));
}


T_R2D_ERROR          r2d_draw_chars(T_R2D_GC_PTR gc,INT16 x,INT16 y,
									T_R2D_UTF16 *the_text,UINT16 nb_chars)
{
	UINT16 r,h;
	return(r2d_low_draw_text(gc,x,y,the_text,R2D_TEXT_DRAW,nb_chars,&r,&h));
}

T_R2D_ERROR   r2d_draw_chars_and_get_size(T_R2D_GC_PTR gc,INT16 x,INT16 y,T_R2D_UTF16 *the_text,
							 UINT16 nb_words16,UINT16 *width,UINT16 *height)
{
	return(r2d_low_draw_text(gc,x,y,the_text,R2D_TEXT_DRAW,nb_words16,width,height));
}

T_R2D_UTF16 *r2d_new_unicode_from_cstring(T_RVF_MB_ID bank,unsigned char *the_string)
{
 T_R2D_UTF16 *result,*p;
// INT16 i;
 INT16 index;

 R2D_MALLOC(bank,T_R2D_UTF16,sizeof(T_R2D_UTF16)*(strlen((char*)the_string)+1),result);
 if (result!=NULL)
 {
   p=result;
   while(*the_string!='\0')
   {
	 index=*the_string++;
     *p++ = R2D_WIN_LATIN1_TO_UNICODE[index];
   }
   *p++ = 0;
 }
 return(result);
}

T_R2D_UTF16 *r2d_new_unicode_from_pstring(T_RVF_MB_ID bank,unsigned char *the_string)
{
 T_R2D_UTF16 *result,*p;
 INT16 l,index;
// INT16 i;

 R2D_MALLOC(bank,T_R2D_UTF16,sizeof(T_R2D_UTF16)*(the_string[0]+1),result);
 if (result!=NULL)
 {
   p=result;
   l=*the_string++;

   while(l!=0)
   {
	 index=*the_string++;
     *p++ = R2D_WIN_LATIN1_TO_UNICODE[index];
     l--;
   }
   *p++ = 0;
 }
 return(result);
}


void          r2d_get_font_info(T_R2D_GC_PTR gc,INT16 *ascent,INT16 *descent,INT16 *leading)
{
   INT32 *p;

    
   p=((T_R2D_GC*)gc)->font_metrics;

   *p--;
   *leading=*--p;
   *descent=*--p;
   *ascent=*--p;
   
}

INT16 r2d_str_nb_word16(T_R2D_UTF16 *l)
{
	INT16 res;
	T_R2D_UTF16 *p;

	if (l==NULL)
		return 0;

	p=l;
	res=0;

	while(*p!=0)
	{
		p++;
		res++;
	}
	return(res);
}

T_R2D_UTF16 *r2d_duplicate_text(T_RVF_MB_ID bank,T_R2D_UTF16 *l)
{
	T_R2D_UTF16 *ret;
	INT16 len;

	if (l==NULL)
		return(NULL);

	len=r2d_str_nb_word16(l);
	rvf_get_buf(bank,(len+1)*sizeof(T_R2D_UTF16),(void*)&ret);
	if (ret)
	{
		memcpy(ret,l,(len+1)*2);
		return(ret);
	}
    else return(NULL);
}



T_R2D_SCRIPT_MODE r2d_get_script_mode(T_R2D_GC_PTR gc)
{
	return(((T_R2D_GC*)gc)->script_mode);
}

void r2d_set_script_mode(T_R2D_GC_PTR gc,T_R2D_SCRIPT_MODE mode)
{
	((T_R2D_GC*)gc)->script_mode=mode;
}