diff src/cs/drivers/drv_app/r2d/r2d.c @ 0:4e78acac3d88

src/{condat,cs,gpf,nucleus}: import from Selenite
author Mychaela Falconia <falcon@freecalypso.org>
date Fri, 16 Oct 2020 06:23:26 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/cs/drivers/drv_app/r2d/r2d.c	Fri Oct 16 06:23:26 2020 +0000
@@ -0,0 +1,5365 @@
+/**
+                                                                          
+  @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;
+}