[Date Prev][Date Next][Thread Prev][Thread Next][Thread Index]

Re: [XaraXtreme-dev] Cairo Port



Hi,

thanks for pointing me to some ressources - I hadn't stumbled across them yet. They will be a nice reading while I am travelling :-)

I have managed to actually draw something with Cairo now. It's only very basic path drawing, and it looks pretty bad still. But at least I got something on the screen.

I attached my changes to Carl's git-tree, in case anyone is interested.

Jonas
>From 2208eb750e865a3304ef6306813b7055e173d249 Mon Sep 17 00:00:00 2001
From: Jonas Diemer <jonas@JonasPC.(none)>
Date: Wed, 9 May 2007 16:39:25 +0200
Subject: [PATCH] Implemented very basic drawing with Cairo.

---
 GDraw/gconsts.h       |   12 +++-
 GDraw/gdraw-cairo.cpp |  148 ++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 150 insertions(+), 10 deletions(-)

diff --git a/GDraw/gconsts.h b/GDraw/gconsts.h
index b651780..ab6b359 100644
--- a/GDraw/gconsts.h
+++ b/GDraw/gconsts.h
@@ -104,6 +104,9 @@ service marks of Xara Group Ltd. All rights in these marks are reserved.
 #ifndef INC_GCONSTS
 #define	INC_GCONSTS
 
+
+#include <cairo.h>
+
 #if !defined(__WXMSW__)
 const BYTE PT_CLOSEFIGURE	= 1;
 const BYTE PT_LINETO		= 2;
@@ -234,11 +237,14 @@ enum DitherStyle {
 
 /////////////////////////////////////////////////////////////////////////////////////////////////
 
+// struct GCONTEXT {
+// 	DWORD Valid ;			// Valid if set to C90FDAA2.
+// 	DWORD Data[1] ;
+// } ;
 struct GCONTEXT {
-	DWORD Valid ;			// Valid if set to C90FDAA2.
-	DWORD Data[1] ;
+    DWORD Valid ;			// Valid if set to C90FDAA2.
+    cairo_t *cr ;
 } ;
-
 	
 
 struct DitherBlock {
diff --git a/GDraw/gdraw-cairo.cpp b/GDraw/gdraw-cairo.cpp
index e50ed64..44890d0 100644
--- a/GDraw/gdraw-cairo.cpp
+++ b/GDraw/gdraw-cairo.cpp
@@ -22,12 +22,23 @@
 
 #include <stdio.h>
 
+#include <cairo.h>
+
 #include "camtypes.h"
 #include "gdraw.h"
 #include "GVersion.h"
 
 #define STUB(func) fprintf (stderr, "FIXME: Need a cairo-based implementation of " func " here.\n")
 
+
+double toFloat(long long int x){
+    return ((double) x) / (1<<16);
+}
+
+INT32 toFixed16(double x){
+    return (INT32) (x * (1<<16));
+}
+
 DWORD
 GDraw_GetVersion (void)
 {
@@ -69,6 +80,10 @@ INT32
 GDraw_Initialise (pGCONTEXT pContext, pcGCONTEXT pOldContext)
 {
     STUB ("GDraw_Initialise");
+
+    pContext->cr = NULL;
+    pContext->Valid = 0;
+    
     return 0;
 }
 
@@ -257,15 +272,23 @@ GColour_SetHalftoneOrigin ( pGCONTEXT pContext, INT32 x,INT32 y )
 INT32
 GColour_SetColour ( pGCONTEXT pContext,COLORREF Colour )
 {
-    STUB ("GColour_SetColour");
-    return 0;
+    if (pContext->cr == NULL) return 0;
+    
+    cairo_set_source_rgb (pContext->cr, GetRValue(Colour), GetGValue(Colour), GetBValue(Colour));
+    
+    return 1;
 }
 
 INT32
 GColour_SetSolidColour ( pGCONTEXT pContext,COLORREF Colour,UINT32 BPP,UINT32 Format16BPP)
 {
     STUB ("GColour_SetSolidColour");
-    return 0;
+    // TODO: Does this need to behave different than SetColour?
+    
+    if (pContext->cr == NULL) return 0;
+    cairo_set_source_rgb (pContext->cr, GetRValue(Colour), GetGValue(Colour), GetBValue(Colour));
+    
+    return 1;
 }
 
 INT32
@@ -780,7 +803,51 @@ GDraw_SetDIBitmap (
     )
 {
     STUB ("GDraw_SetDIBitmap");
-    return 0;
+    if (Format16BPP != 2) { return 0;}
+    if (Bitmap == NULL) { return 0;}
+    
+//     printf("Format: %d, %d x %d, compression: 0x%x\n", 
+//            Format16BPP, BitmapInfo->biWidth, BitmapInfo->biHeight, BitmapInfo->biCompression);
+    
+    cairo_surface_t *surface = cairo_image_surface_create_for_data(
+            Bitmap,
+            CAIRO_FORMAT_ARGB32,
+            BitmapInfo->biWidth,
+            BitmapInfo->biHeight,
+            4*BitmapInfo->biWidth );
+    
+    cairo_matrix_t mat;
+    cairo_pattern_t* sourcePattern;
+    
+    if ( pContext->cr != NULL ){
+        // store part of the state
+        cairo_get_matrix(pContext->cr, &mat); 
+        sourcePattern = cairo_get_source(pContext->cr);
+        cairo_pattern_reference(sourcePattern);
+        
+        // destroy and recreace cairo_t. This is the only way to assign a new surface to a cairo_t...
+        cairo_destroy( pContext->cr );
+        pContext->cr = cairo_create(surface);
+        
+        // restore part of the state
+        cairo_set_matrix(pContext->cr, &mat);
+        cairo_set_source(pContext->cr, sourcePattern);
+        cairo_pattern_destroy(sourcePattern); // not sure
+    }else{
+        // FIrst time, so only create the context
+        pContext->cr = cairo_create(surface);
+    }
+   
+    // Delete image TODO: improve this
+    UINT32* IntPtr = (UINT32*) Bitmap;
+    *(IntPtr++) = 0x000000FF ;
+    for (int i=0; i < BitmapInfo->biWidth; i++){
+        for (int j=0; j < BitmapInfo->biHeight; j++){
+            *(IntPtr++) = 0xFFFFFFFF;//0x00000000;
+        }
+    }
+    
+    return 1;
 }
 
 INT32
@@ -799,7 +866,34 @@ INT32
 GDraw_SetMatrix ( pGCONTEXT pContext,pcGMATRIX Matrix )
 {
     STUB ("GDraw_SetMatrix");
-    return 0;
+    
+    if (pContext->cr == NULL) return 0;
+    
+    
+    cairo_matrix_t mat;
+    mat.xx = toFloat(Matrix->AX);
+    mat.xy = toFloat(Matrix->AY);
+    mat.yx = toFloat(Matrix->BX);
+    mat.yy = toFloat(Matrix->BY);
+    mat.x0 = toFloat(Matrix->CX)/(1<<16);
+    mat.y0 = toFloat(Matrix->CY)/(1<<16);
+    
+    mat.xx *= 4;
+    mat.xy *= 4;
+    mat.yx *= 4;
+    mat.yy *= 4;
+    mat.x0 *= 4;
+    mat.y0 *= 4;
+    
+    cairo_set_matrix(pContext->cr, &mat);
+    /*
+    cairo_get_matrix(pContext->cr, &mat);
+    printf("Xara Matrix:  AX=%d, AY=%d, BX=%d, BY=%d, CX=%lld, CY=%lld\n", 
+           Matrix->AX, Matrix->AY, Matrix->BX, Matrix->BY, Matrix->CX, Matrix->CY);
+    printf("Cairo matrix: xx=%f, xy=%f, yx=%f, yy=%f, x0=%f, y0=%f\n",
+           mat.xx, mat.xy, mat.yx, mat.yy, mat.x0, mat.y0);*/
+    
+    return 1;
 }
 
 INT32
@@ -855,6 +949,7 @@ INT32
 GDraw_SetFlatness ( pGCONTEXT pContext,UINT32 Flatness )
 {
     STUB ("GDraw_SetFlatness");
+//     printf("Context: valid=%d, data[0]=%d\n",pContext->Valid, pContext->Data[0]);
     return 0;
 }
 
@@ -920,7 +1015,18 @@ GDraw_StrokePath (
     )
 {
     STUB ("GDraw_StrokePath");
-    return 0;
+    if (pContext->cr == NULL) return 0;
+    if (Length <= 0) return 0;
+    
+    
+    cairo_set_line_width (pContext->cr, toFloat(LineWidth));
+    cairo_move_to(pContext->cr, toFloat(Points[0].x), toFloat(Points[0].y));
+    for (int i=1; i<Length; i++){
+        cairo_line_to(pContext->cr, toFloat(Points[i].x), toFloat(Points[i].y));
+    }
+    cairo_stroke(pContext->cr);
+    
+    return 1;
 }
 
 INT32
@@ -1137,7 +1243,35 @@ INT32
 GDraw_GetChangedBBox ( pcGCONTEXT pContext, pRECT Rectangle )
 {
     STUB ("GDraw_GetChangedBBox");
-    return 0;
+    
+    // determine the size of the 'changed' rectangle where pixels have been plotted.
+    // for now, this is the full surface
+    //
+    // This condition must be met: 
+    //(UsedRect.right >= UsedRect.left) && (UsedRect.bottom >= UsedRect.top ))
+    
+    
+    if (pContext->cr == NULL) return 0;
+    
+    // TODO: This doesn't seem to be perfect yet...
+    cairo_surface_t* target = cairo_get_target(pContext->cr);
+    
+    // The full image has changed
+    double left = 0;
+    double bottom = 0;
+    double right = cairo_image_surface_get_width(target);
+    double top = cairo_image_surface_get_height(target);
+    
+    cairo_device_to_user(pContext->cr, &left, &bottom);
+    cairo_device_to_user(pContext->cr, &right, &top);
+    
+    
+    Rectangle->left = toFixed16(left);
+    Rectangle->bottom = toFixed16(bottom);
+    Rectangle->right = toFixed16(right);
+    Rectangle->top = toFixed16(top);
+    
+    return 1;
 }
 
 INT32
-- 
1.4.4.2