From b7d97c7ed82f0d0472cf0c2ae5d61e99a73b33a8 Mon Sep 17 00:00:00 2001 From: scuri Date: Wed, 12 May 2010 20:38:46 +0000 Subject: New Cairo driver --- html/en/drv/cairo.html | 134 +++ html/en/drv/gdiplus.html | 3 +- html/en/drv/pdf.html | 3 +- html/en/drv/ps.html | 3 +- html/en/drv/win32.html | 3 +- include/cd.h | 14 +- include/cd_private.h | 2 + include/cdcairo.h | 41 + include/cdpdf.h | 15 - include/cdps.h | 14 - mak.vc9/cd.sln | 25 + mak.vc9/cdcairo.vcproj | 173 ++++ mak.vc9/cdsimplegdk.vcproj | 4 +- mak.vc9/cdtestcairo.vcproj | 160 ++++ mak.vc9/cdx11.vcproj | 2 +- src/cairo/cdcairo.c | 1758 +++++++++++++++++++++++++++++++++++++++ src/cairo/cdcairoctx.h | 77 ++ src/cairo/cdcairodbuf.c | 170 ++++ src/cairo/cdcairoimg.c | 52 ++ src/cairo/cdcairoirgb.c | 159 ++++ src/cairo/cdcaironative_gdk.c | 80 ++ src/cairo/cdcaironative_win32.c | 160 ++++ src/cairo/cdcaironative_x11.c | 98 +++ src/cairo/cdcairopdf.c | 122 +++ src/cairo/cdcairoplus.c | 26 + src/cairo/cdcairops.c | 170 ++++ src/cairo/cdcairosvg.c | 81 ++ src/cd.c | 14 +- src/cd.def | 1 + src/cd_text.c | 2 +- src/cd_util.c | 48 ++ src/drv/cddebug.c | 7 - src/drv/cdirgb.c | 1 + src/drv/cdpdf.c | 83 +- src/drv/cdps.c | 47 +- src/gdiplus/cdwinp.cpp | 35 +- src/gdk/cdgdk.c | 35 +- src/svg/cdsvg.c | 34 +- src/win32/cdwdbuf.c | 1 + src/win32/cdwin.c | 88 +- src/win32/cdwnative.c | 11 +- src/x11/cdx11.c | 6 +- 42 files changed, 3707 insertions(+), 255 deletions(-) create mode 100644 html/en/drv/cairo.html create mode 100644 include/cdcairo.h create mode 100644 mak.vc9/cdcairo.vcproj create mode 100644 mak.vc9/cdtestcairo.vcproj create mode 100644 src/cairo/cdcairo.c create mode 100644 src/cairo/cdcairoctx.h create mode 100644 src/cairo/cdcairodbuf.c create mode 100644 src/cairo/cdcairoimg.c create mode 100644 src/cairo/cdcairoirgb.c create mode 100644 src/cairo/cdcaironative_gdk.c create mode 100644 src/cairo/cdcaironative_win32.c create mode 100644 src/cairo/cdcaironative_x11.c create mode 100644 src/cairo/cdcairopdf.c create mode 100644 src/cairo/cdcairoplus.c create mode 100644 src/cairo/cdcairops.c create mode 100644 src/cairo/cdcairosvg.c diff --git a/html/en/drv/cairo.html b/html/en/drv/cairo.html new file mode 100644 index 0000000..4977258 --- /dev/null +++ b/html/en/drv/cairo.html @@ -0,0 +1,134 @@ + + + + + + +CAIRO + + + + + +

CAIRO Base Driver

+ +

This driver represents a basic driver for all system-dependent drivers + implemented in the X-Windows and MS-Windows systems. The implementation uses the + Cairo API + functions and some GTK functions to support Unicode text. This driver can be + compiled and used in all systems Cairo is supported.

+

The main motivation for the use of Cairo was transparency for all the +primitives. Beyond that we got other features like anti-aliasing, gradient +filling, transformations and back-ends (support to rendering: PDF, PS, SVG and +PNG surfaces).

+

This driver still does not completely replace the X-Windows and GDI Windows +base drivers, because Cairo does not have support for bitwise XOR operations and +for complex clipping regions.

+ +

Behavior of Functions

+

Control 

+ +

Coordinate System and Clipping

+ +

Attributes

+ +

Colors

+ +

Exclusive Attributes

+ + + + + + + + + + + + + + + + + + + + + + diff --git a/html/en/drv/gdiplus.html b/html/en/drv/gdiplus.html index e4a2810..f5b89f4 100644 --- a/html/en/drv/gdiplus.html +++ b/html/en/drv/gdiplus.html @@ -182,7 +182,8 @@ diff --git a/include/cd.h b/include/cd.h index b3a8784..8d3826c 100644 --- a/include/cd.h +++ b/include/cd.h @@ -21,7 +21,7 @@ extern "C" { #define CD_COPYRIGHT "Copyright (C) 1994-2010 Tecgraf, PUC-Rio." #define CD_VERSION "5.3" /* bug fixes are reported only by cdVersion functions */ #define CD_VERSION_NUMBER 503000 -#define CD_VERSION_DATE "2010/01/26" +#define CD_VERSION_DATE "2010/01/26" /* does not include bug fix releases */ typedef struct _cdContext cdContext; typedef struct _cdCanvas cdCanvas; @@ -460,6 +460,18 @@ typedef int(*cdSizeCB)(cdCanvas *canvas, int w, int h, double w_mm, double h_mm) #define CD_RAD2DEG 57.295779513 /* radians to degrees (deg = CD_RAD2DEG * rad) */ #define CD_DEG2RAD 0.01745329252 /* degrees to radians (rad = CD_DEG2RAD * deg) */ +/* paper sizes */ +enum { + CD_A0, + CD_A1, + CD_A2, + CD_A3, + CD_A4, + CD_A5, + CD_LETTER, + CD_LEGAL +}; + #ifdef __cplusplus } diff --git a/include/cd_private.h b/include/cd_private.h index af216c5..a70469c 100644 --- a/include/cd_private.h +++ b/include/cd_private.h @@ -273,6 +273,7 @@ int cdStrEqualNoCase(const char* str1, const char* str2); int cdStrLineCount(const char* str); char* cdStrDup(const char* str); char* cdStrDupN(const char* str, int len); +void cdSetPaperSize(int size, double *w_pt, double *h_pt); #define _cdCheckCanvas(_canvas) (_canvas!=NULL && ((unsigned char*)_canvas)[0] == 'C' && ((unsigned char*)_canvas)[1] == 'D') #define _cdInvertYAxis(_canvas, _y) (_canvas->h - (_y) - 1) @@ -288,6 +289,7 @@ void cdMatrixTransformPoint(double* matrix, int x, int y, int *rx, int *ry); void cdfMatrixTransformPoint(double* matrix, double x, double y, double *rx, double *ry); void cdMatrixMultiply(const double* matrix, double* mul_matrix); void cdMatrixInverse(const double* matrix, double* inv_matrix); +void cdfRotatePoint(cdCanvas* canvas, double x, double y, double cx, double cy, double *rx, double *ry, double sin_theta, double cos_theta); void cdRotatePoint(cdCanvas* canvas, int x, int y, int cx, int cy, int *rx, int *ry, double sin_teta, double cos_teta); void cdRotatePointY(cdCanvas* canvas, int x, int y, int cx, int cy, int *ry, double sin_theta, double cos_theta); void cdTextTranslatePoint(cdCanvas* canvas, int x, int y, int w, int h, int baseline, int *rx, int *ry); diff --git a/include/cdcairo.h b/include/cdcairo.h new file mode 100644 index 0000000..2d01f2e --- /dev/null +++ b/include/cdcairo.h @@ -0,0 +1,41 @@ +/** \file + * \brief Cairo extra drivers. + * Rendering PDF, PS, SVG and IMAGERGB. + * + * See Copyright Notice in cd.h + */ + +#ifndef __CD_CAIRO_H +#define __CD_CAIRO_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* Some of these context can be used directly or by cdInitContextPlus, + as CD_NATIVEWINDOW, CD_IMAGE and CD_DBUFFER. + The other only directly. +*/ + +cdContext* cdContextCairoPS(void); +cdContext* cdContextCairoPDF(void); +cdContext* cdContextCairoSVG(void); +cdContext* cdContextCairoImageRGB(void); +cdContext* cdContextCairoDBuffer(void); +cdContext* cdContextCairoImage(void); +cdContext* cdContextCairoNativeWindow(void); + +#define CD_CAIRO_NATIVEWINDOW cdContextCairoNativeWindow() +#define CD_CAIRO_IMAGE cdContextCairoImage() +#define CD_CAIRO_DBUFFER cdContextCairoDBuffer() +#define CD_CAIRO_PS cdContextCairoPS() +#define CD_CAIRO_PDF cdContextCairoPDF() +#define CD_CAIRO_SVG cdContextCairoSVG() +#define CD_CAIRO_IMAGERGB cdContextCairoImageRGB() + + +#ifdef __cplusplus +} +#endif + +#endif /* ifndef __CD_CAIRO_ */ diff --git a/include/cdpdf.h b/include/cdpdf.h index 70d6df5..89486fc 100644 --- a/include/cdpdf.h +++ b/include/cdpdf.h @@ -15,21 +15,6 @@ cdContext* cdContextPDF(void); #define CD_PDF cdContextPDF() -#ifndef CD_PAPERSIZE -#define CD_PAPERSIZE -enum { /* paper sizes */ - CD_A0, - CD_A1, - CD_A2, - CD_A3, - CD_A4, - CD_A5, - CD_LETTER, - CD_LEGAL -}; -#endif - - #ifdef __cplusplus } #endif diff --git a/include/cdps.h b/include/cdps.h index 180ebad..0f4bdd8 100644 --- a/include/cdps.h +++ b/include/cdps.h @@ -15,20 +15,6 @@ cdContext* cdContextPS(void); #define CD_PS cdContextPS() -#ifndef CD_PAPERSIZE -#define CD_PAPERSIZE -enum { /* paper sizes */ - CD_A0, - CD_A1, - CD_A2, - CD_A3, - CD_A4, - CD_A5, - CD_LETTER, - CD_LEGAL -}; -#endif - #ifdef __cplusplus } #endif diff --git a/mak.vc9/cd.sln b/mak.vc9/cd.sln index 165a240..7def44e 100644 --- a/mak.vc9/cd.sln +++ b/mak.vc9/cd.sln @@ -89,6 +89,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cdgdk", "cdgdk.vcproj", "{0 EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cdsimplegdk", "cdsimplegdk.vcproj", "{82BC36B1-DDDD-41D4-ABCD-A12312378CE6}" ProjectSection(ProjectDependencies) = postProject + {01818D2C-AAAA-DD23-00AA-5678401C6461} = {01818D2C-AAAA-DD23-00AA-5678401C6461} {01818D2C-AAAA-4D5C-ABCD-1234401C6461} = {01818D2C-AAAA-4D5C-ABCD-1234401C6461} {8441F69D-7135-43B2-974F-45C6123C8467} = {8441F69D-7135-43B2-974F-45C6123C8467} EndProjectSection @@ -107,6 +108,20 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cdtestplus", "cdtestplus.vc {8441F69D-7135-43B2-974F-45C6123C8467} = {8441F69D-7135-43B2-974F-45C6123C8467} EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{1EE89DAC-3D3A-450C-9CF8-E200DF5E12E8}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cdcairo", "cdcairo.vcproj", "{01818D2C-AAAA-DD23-00AA-5678401C6461}" + ProjectSection(ProjectDependencies) = postProject + {01818D2C-1234-4D5C-ABCD-4DFF401C6461} = {01818D2C-1234-4D5C-ABCD-4DFF401C6461} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "cdtestcairo", "cdtestcairo.vcproj", "{A7E49FB8-0022-15EC-AB17-FFCDC7E83C00}" + ProjectSection(ProjectDependencies) = postProject + {01818D2C-AAAA-DD23-00AA-5678401C6461} = {01818D2C-AAAA-DD23-00AA-5678401C6461} + {01818D2C-AAAA-4D5C-ABCD-1234401C6461} = {01818D2C-AAAA-4D5C-ABCD-1234401C6461} + {8441F69D-7135-43B2-974F-45C6123C8467} = {8441F69D-7135-43B2-974F-45C6123C8467} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -150,11 +165,20 @@ Global {A7E49FB8-0000-45EC-1234-ABCDC7E83C00}.Debug|Win32.Build.0 = Debug|Win32 {A7E49FB8-5467-45EC-2211-FFAB7E83C100}.Debug|Win32.ActiveCfg = Debug|Win32 {A7E49FB8-5467-45EC-2211-FFAB7E83C100}.Debug|Win32.Build.0 = Debug|Win32 + {01818D2C-AAAA-DD23-00AA-5678401C6461}.Debug|Win32.ActiveCfg = Debug|Win32 + {01818D2C-AAAA-DD23-00AA-5678401C6461}.Debug|Win32.Build.0 = Debug|Win32 + {A7E49FB8-0022-15EC-AB17-FFCDC7E83C00}.Debug|Win32.ActiveCfg = Debug|Win32 + {A7E49FB8-0022-15EC-AB17-FFCDC7E83C00}.Debug|Win32.Build.0 = Debug|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution + {01818D2C-7689-4D5C-1234-4DFF401C6461} = {1EE89DAC-3D3A-450C-9CF8-E200DF5E12E8} + {01818D2C-AAAA-4D5C-ABCD-1234401C6461} = {1EE89DAC-3D3A-450C-9CF8-E200DF5E12E8} + {01818D2C-1234-4D5C-ABCD-4DFF401C6461} = {1EE89DAC-3D3A-450C-9CF8-E200DF5E12E8} + {01818D2C-65AF-4D5C-9452-4DFF401C6461} = {1EE89DAC-3D3A-450C-9CF8-E200DF5E12E8} + {01818D2C-AAAA-DD23-00AA-5678401C6461} = {1EE89DAC-3D3A-450C-9CF8-E200DF5E12E8} {B4823266-DF8C-AAAA-9999-C7E78C234EAC} = {E92DB6FF-5501-4FC0-81D2-00DB8EFA2434} {53FC9752-81C1-4AA6-B366-AF6D0A2B81F6} = {E92DB6FF-5501-4FC0-81D2-00DB8EFA2434} {B4823266-DF8C-1224-EE00-C7688C234EAC} = {EFB1BE3C-2981-456B-8E32-928CBDFF7822} @@ -166,6 +190,7 @@ Global {82BC36B1-DDDD-41D4-ABCD-A12312378CE6} = {162715BD-4DB3-4007-8B50-725C0BD11878} {A7E49FB8-0000-45EC-1234-ABCDC7E83C00} = {162715BD-4DB3-4007-8B50-725C0BD11878} {A7E49FB8-5467-45EC-2211-FFAB7E83C100} = {162715BD-4DB3-4007-8B50-725C0BD11878} + {A7E49FB8-0022-15EC-AB17-FFCDC7E83C00} = {162715BD-4DB3-4007-8B50-725C0BD11878} EndGlobalSection GlobalSection(DevPartner Solution Properties) = postSolution EndGlobalSection diff --git a/mak.vc9/cdcairo.vcproj b/mak.vc9/cdcairo.vcproj new file mode 100644 index 0000000..ec7c1e5 --- /dev/null +++ b/mak.vc9/cdcairo.vcproj @@ -0,0 +1,173 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mak.vc9/cdsimplegdk.vcproj b/mak.vc9/cdsimplegdk.vcproj index 57fe233..51310a6 100644 --- a/mak.vc9/cdsimplegdk.vcproj +++ b/mak.vc9/cdsimplegdk.vcproj @@ -44,7 +44,7 @@ Name="VCCLCompilerTool" Optimization="0" AdditionalIncludeDirectories="..\include,..\..\iup\include" - PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;__CD__;simple;_CRT_SECURE_NO_DEPRECATE;USE_GDK" + PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;__CD__;simple;_CRT_SECURE_NO_DEPRECATE;USE_GDK;USE_CONTEXTPLUS" BasicRuntimeChecks="3" RuntimeLibrary="1" PrecompiledHeaderFile=".\..\obj\cdsimplegdk/cdsimplegdk.pch" @@ -70,7 +70,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mak.vc9/cdx11.vcproj b/mak.vc9/cdx11.vcproj index 8336785..5d6398c 100644 --- a/mak.vc9/cdx11.vcproj +++ b/mak.vc9/cdx11.vcproj @@ -41,7 +41,7 @@ +#include +#include +#include +#include + +#include + +#include "cdcairoctx.h" + +#define HATCH_WIDTH 8 +#define HATCH_HEIGHT 8 + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + + +static int StrIsAscii(const char* str) +{ + while(*str) + { + int c = *str; + if (c < 0) + return 0; + str++; + } + return 1; +} + +static char* StrToUTF8(const char *str, const char* charset, int length) +{ + return g_convert(str, length, "UTF-8", charset, NULL, NULL, NULL); +} + +char* StrConvertToUTF8(cdCtxCanvas *ctxcanvas, const char* str, int length) +{ + const char *charset = NULL; + + if (!str || *str == 0) + return (char*)str; + + if (g_get_charset(&charset)) /* current locale is already UTF-8 */ + { + if (g_utf8_validate(str, -1, NULL)) + { + return (char*)str; + } + else + { + ctxcanvas->cairoLastConvertUTF8 = StrToUTF8(str, "ISO8859-1", length); /* if string is not UTF-8, assume ISO8859-1 */ + + if (!ctxcanvas->cairoLastConvertUTF8) + return (char*)str; + + return ctxcanvas->cairoLastConvertUTF8; + } + } + else + { + if (StrIsAscii(str) || !charset) + { + return (char*)str; + } + else if (charset) + { + ctxcanvas->cairoLastConvertUTF8 = StrToUTF8(str, charset, length); + + if (!ctxcanvas->cairoLastConvertUTF8) + return (char*)str; + + return ctxcanvas->cairoLastConvertUTF8; + } + } + + return (char*)str; +} + +static void update_fill(cdCtxCanvas *ctxcanvas, int fill) +{ + if (fill == 0 || ctxcanvas->canvas->interior_style == CD_SOLID) + { + if (ctxcanvas->last_source == 0) + return; + + cairo_set_source(ctxcanvas->cr, ctxcanvas->solid); + ctxcanvas->last_source = 0; + } + else + { + if (ctxcanvas->last_source == 1) + return; + + cairo_set_source(ctxcanvas->cr, ctxcanvas->pattern); + ctxcanvas->last_source = 1; + } +} + +/******************************************************/ + +void cdcairoKillCanvas(cdCtxCanvas *ctxcanvas) +{ + if (ctxcanvas->solid) + cairo_pattern_destroy(ctxcanvas->solid); + + if (ctxcanvas->pattern) + cairo_pattern_destroy(ctxcanvas->pattern); + + if (ctxcanvas->font) + cairo_scaled_font_destroy(ctxcanvas->font); + + if (ctxcanvas->cairoLastConvertUTF8) + g_free(ctxcanvas->cairoLastConvertUTF8); + + cairo_destroy(ctxcanvas->cr); + + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + free(ctxcanvas); +} + +/******************************************************/ + +static void cdflush(cdCtxCanvas *ctxcanvas) +{ + cairo_show_page(ctxcanvas->cr); +} + +/******************************************************/ + +static void setcliprect(cdCtxCanvas* ctxcanvas, double xmin, double ymin, double xmax, double ymax) +{ + cairo_reset_clip(ctxcanvas->cr); + cairo_rectangle(ctxcanvas->cr, xmin, ymin, xmax-xmin+1, ymax-ymin+1); + cairo_clip(ctxcanvas->cr); +} + +static void cdcliparea(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + if (ctxcanvas->canvas->clip_mode != CD_CLIPAREA) + return; + + setcliprect(ctxcanvas, (double)xmin, (double)ymin, (double)xmax, (double)ymax); +} + +static int cdclip(cdCtxCanvas *ctxcanvas, int mode) +{ + switch (mode) + { + case CD_CLIPOFF: + cairo_reset_clip(ctxcanvas->cr); + break; + case CD_CLIPAREA: + ctxcanvas->canvas->clip_mode = CD_CLIPAREA; + setcliprect(ctxcanvas, (double)ctxcanvas->canvas->clip_rect.xmin, + (double)ctxcanvas->canvas->clip_rect.ymin, + (double)ctxcanvas->canvas->clip_rect.xmax, + (double)ctxcanvas->canvas->clip_rect.ymax); + break; + case CD_CLIPPOLYGON: + { + int hole_index = 0; + int i; + cairo_reset_clip(ctxcanvas->cr); + + if (ctxcanvas->canvas->clip_poly) + { + cdPoint *poly = ctxcanvas->canvas->clip_poly; + cairo_move_to(ctxcanvas->cr, poly[0].x, poly[0].y); + for (i=1; icanvas->clip_poly_n; i++) + { + if (ctxcanvas->holes && i == ctxcanvas->poly_holes[hole_index]) + { + cairo_move_to(ctxcanvas->cr, poly[i].x, poly[i].y); + hole_index++; + } + else + cairo_line_to(ctxcanvas->cr, poly[i].x, poly[i].y); + } + } + else if (ctxcanvas->canvas->clip_fpoly) + { + cdfPoint *poly = ctxcanvas->canvas->clip_fpoly; + cairo_move_to(ctxcanvas->cr, poly[0].x, poly[0].y); + for (i=1; icanvas->clip_poly_n; i++) + { + if (ctxcanvas->holes && i == ctxcanvas->poly_holes[hole_index]) + { + cairo_move_to(ctxcanvas->cr, poly[i].x, poly[i].y); + hole_index++; + } + else + cairo_line_to(ctxcanvas->cr, poly[i].x, poly[i].y); + } + } + cairo_clip(ctxcanvas->cr); + break; + } + case CD_CLIPREGION: + break; + } + + return mode; +} + +/******************************************************/ + +static void make_pattern(cdCtxCanvas *ctxcanvas, int n, int m, void* data, int (*data2rgb)(cdCtxCanvas *ctxcanvas, int n, int i, int j, void* data, unsigned char*r, unsigned char*g, unsigned char*b, unsigned char*a)) +{ + int i, j; + unsigned char r, g, b, a; + cairo_surface_t* pattern_surface; + cairo_t* cr; + + pattern_surface = cairo_surface_create_similar(cairo_get_target(ctxcanvas->cr), CAIRO_CONTENT_COLOR_ALPHA, n, m); + + cr = cairo_create(pattern_surface); + + for (j = 0; j < m; j++) + { + for (i = 0; i < n; i++) + { + int ret = data2rgb(ctxcanvas, n, i, j, data, &r, &g, &b, &a); + if (ret == -1) + continue; + + cairo_set_source_rgba(cr, (double)r/255.0, (double)g/255.0, (double)b/255.0, (double)a/255.0); + + cairo_rectangle(cr, i, m-1-j, 1.0, 1.0); + cairo_fill(cr); + } + } + + if (ctxcanvas->pattern) + cairo_pattern_destroy(ctxcanvas->pattern); + + ctxcanvas->pattern = cairo_pattern_create_for_surface(pattern_surface); + cairo_pattern_set_extend(ctxcanvas->pattern, CAIRO_EXTEND_REPEAT); + + cairo_surface_destroy(pattern_surface); + cairo_destroy(cr); +} + +static int long2rgb(cdCtxCanvas *ctxcanvas, int n, int i, int j, void* data, unsigned char*r, unsigned char*g, unsigned char*b, unsigned char*a) +{ + long* long_data = (long*)data; + long c = long_data[j*n+i]; + (void)ctxcanvas; + cdDecodeColor(c, r, g, b); + *a = cdDecodeAlpha(c); + return 1; +} + +static void cdpattern(cdCtxCanvas *ctxcanvas, int n, int m, const long int *pattern) +{ + make_pattern(ctxcanvas, n, m, (void*)pattern, long2rgb); + cairo_set_source(ctxcanvas->cr, ctxcanvas->pattern); + ctxcanvas->last_source = 1; +} + +static int uchar2rgb(cdCtxCanvas *ctxcanvas, int n, int i, int j, void* data, unsigned char*r, unsigned char*g, unsigned char*b, unsigned char*a) +{ + unsigned char* uchar_data = (unsigned char*)data; + if (uchar_data[j*n+i]) + { + cdDecodeColor(ctxcanvas->canvas->foreground, r, g, b); + *a = cdDecodeAlpha(ctxcanvas->canvas->foreground); + } + else + { + if (ctxcanvas->canvas->back_opacity == CD_TRANSPARENT) + return -1; + else + { + cdDecodeColor(ctxcanvas->canvas->background, r, g, b); + *a = cdDecodeAlpha(ctxcanvas->canvas->background); + } + } + + return 1; +} + +static void cdstipple(cdCtxCanvas *ctxcanvas, int n, int m, const unsigned char *stipple) +{ + make_pattern(ctxcanvas, n, m, (void*)stipple, uchar2rgb); + cairo_set_source(ctxcanvas->cr, ctxcanvas->pattern); + ctxcanvas->last_source = 1; +} + +static int cdhatch(cdCtxCanvas *ctxcanvas, int style) +{ + int hsize = HATCH_WIDTH - 1; + int hhalf = hsize / 2; + cairo_surface_t* hatch_surface; + cairo_t* cr; + + hatch_surface = cairo_surface_create_similar(cairo_get_target(ctxcanvas->cr), CAIRO_CONTENT_COLOR_ALPHA, HATCH_WIDTH, HATCH_HEIGHT); + + cr = cairo_create(hatch_surface); + + if (ctxcanvas->canvas->back_opacity == CD_OPAQUE) + { + cairo_set_source_rgba(cr, cdCairoGetRed(ctxcanvas->canvas->background), cdCairoGetGreen(ctxcanvas->canvas->background), cdCairoGetBlue(ctxcanvas->canvas->background), cdCairoGetAlpha(ctxcanvas->canvas->background)); + cairo_rectangle(cr, 0, 0, hsize, hsize); + cairo_fill(cr); + } + + cairo_set_source_rgba(cr, cdCairoGetRed(ctxcanvas->canvas->foreground), cdCairoGetGreen(ctxcanvas->canvas->foreground), cdCairoGetBlue(ctxcanvas->canvas->foreground), cdCairoGetAlpha(ctxcanvas->canvas->foreground)); + + switch(style) + { + case CD_HORIZONTAL: + cairo_move_to(cr, 0.0, (double)hhalf); + cairo_line_to(cr, (double)hsize, (double)hhalf); + break; + case CD_VERTICAL: + cairo_move_to(cr, (double)hhalf, 0.0); + cairo_line_to(cr, (double)hhalf, (double)hsize); + break; + case CD_BDIAGONAL: + cairo_move_to(cr, 0.0, (double)hsize); + cairo_line_to(cr, (double)hsize, 0.0); + break; + case CD_FDIAGONAL: + cairo_move_to(cr, 0.0, 0.0); + cairo_line_to(cr, (double)hsize, (double)hsize); + break; + case CD_CROSS: + cairo_move_to(cr, (double)hsize, 0.0); + cairo_line_to(cr, (double)hsize, (double)hsize); + cairo_move_to(cr, 0.0, (double)hhalf); + cairo_line_to(cr, (double)hsize, (double)hhalf); + break; + case CD_DIAGCROSS: + cairo_move_to(cr, 0.0, 0.0); + cairo_line_to(cr, (double)hsize, (double)hsize); + cairo_move_to(cr, (double)hsize, 0.0); + cairo_line_to(cr, 0.0, (double)hsize); + break; + } + + cairo_stroke(cr); + + if (ctxcanvas->pattern) + cairo_pattern_destroy(ctxcanvas->pattern); + + ctxcanvas->pattern = cairo_pattern_create_for_surface(hatch_surface); + cairo_pattern_reference(ctxcanvas->pattern); + cairo_pattern_set_extend(ctxcanvas->pattern, CAIRO_EXTEND_REPEAT); + + cairo_surface_destroy(hatch_surface); + cairo_destroy(cr); + + cairo_set_source(ctxcanvas->cr, ctxcanvas->pattern); + ctxcanvas->last_source = 1; + + return style; +} + +/******************************************************/ +/* attributes */ +/******************************************************/ + +static int cdwritemode(cdCtxCanvas *ctxcanvas, int write_mode) +{ + switch (write_mode) + { + case CD_REPLACE: + cairo_set_operator (ctxcanvas->cr, CAIRO_OPERATOR_OVER); + break; + case CD_XOR: + cairo_set_operator (ctxcanvas->cr, CAIRO_OPERATOR_XOR); + break; + } + + return write_mode; +} + +static int cdinteriorstyle (cdCtxCanvas* ctxcanvas, int style) +{ + switch (style) + { + case CD_SOLID: + cairo_set_source(ctxcanvas->cr, ctxcanvas->solid); + ctxcanvas->last_source = 0; + break; + /* must recriate the current pattern */ + case CD_HATCH: + cdhatch(ctxcanvas, ctxcanvas->canvas->hatch_style); + break; + case CD_STIPPLE: + cdstipple(ctxcanvas, ctxcanvas->canvas->stipple_w, ctxcanvas->canvas->stipple_h, ctxcanvas->canvas->stipple); + break; + case CD_PATTERN: + cdpattern(ctxcanvas, ctxcanvas->canvas->pattern_w, ctxcanvas->canvas->pattern_h, ctxcanvas->canvas->pattern); + break; + } + + return style; +} + +static int cdlinestyle(cdCtxCanvas *ctxcanvas, int style) +{ + double dashes[10]; + + switch (style) + { + case CD_CONTINUOUS : /* empty dash */ + cairo_set_dash(ctxcanvas->cr, 0, 0, 0); + break; + case CD_DASHED : + dashes[0] = 6.0; dashes[1] = 2.0; + cairo_set_dash(ctxcanvas->cr, dashes, 2, 0); + break; + case CD_DOTTED : + dashes[0] = 2.0; dashes[1] = 2.0; + cairo_set_dash(ctxcanvas->cr, dashes, 2, 0); + break; + case CD_DASH_DOT : + dashes[0] = 6.0; dashes[1] = 2.0; + dashes[2] = 2.0; dashes[3] = 2.0; + cairo_set_dash(ctxcanvas->cr, dashes, 4, 0); + break; + case CD_DASH_DOT_DOT : + dashes[0] = 6.0; dashes[1] = 2.0; + dashes[2] = 2.0; dashes[3] = 2.0; + dashes[4] = 2.0; dashes[5] = 2.0; + cairo_set_dash(ctxcanvas->cr, dashes, 6, 0); + break; + case CD_CUSTOM : + { + int i; + double* dash_style = (double*)malloc(sizeof(double)*ctxcanvas->canvas->line_dashes_count); + + for (i = 0; i < ctxcanvas->canvas->line_dashes_count; i++) + dash_style[i] = (double)ctxcanvas->canvas->line_dashes[i]; + + cairo_set_dash(ctxcanvas->cr, dash_style, ctxcanvas->canvas->line_dashes_count, 0); + + free(dash_style); + } + break; + } + + return style; +} + +static int cdlinewidth(cdCtxCanvas *ctxcanvas, int width) +{ + if(width == 0) + width = 1; + + cairo_set_line_width(ctxcanvas->cr, (double)width); + + return width; +} + +static int cdlinejoin(cdCtxCanvas *ctxcanvas, int join) +{ + int cd2ps_join[] = {CAIRO_LINE_JOIN_MITER, CAIRO_LINE_JOIN_BEVEL, CAIRO_LINE_JOIN_ROUND}; + + cairo_set_line_join(ctxcanvas->cr, cd2ps_join[join]); + + return join; +} + +static int cdlinecap(cdCtxCanvas *ctxcanvas, int cap) +{ + int cd2pdf_cap[] = {CAIRO_LINE_CAP_BUTT, CAIRO_LINE_CAP_SQUARE, CAIRO_LINE_CAP_ROUND}; + + cairo_set_line_cap(ctxcanvas->cr, cd2pdf_cap[cap]); + + return cap; +} + +static int cdfont(cdCtxCanvas *ctxcanvas, const char *typeface, int style, int size) +{ + //TODO:pango + cairo_scaled_font_t *font; + cairo_font_slant_t slant = CAIRO_FONT_SLANT_NORMAL; /* default is */ + cairo_font_weight_t weight = CAIRO_FONT_WEIGHT_NORMAL; /* CD_PLAIN */ + + if (cdStrEqualNoCase(typeface, "Courier") || cdStrEqualNoCase(typeface, "Monospace")) + typeface = "Courier New"; + else if (cdStrEqualNoCase(typeface, "Times") || cdStrEqualNoCase(typeface, "Serif")) + typeface = "Times New Roman"; + else if (cdStrEqualNoCase(typeface, "Helvetica") || cdStrEqualNoCase(typeface, "Sans")) + typeface = "Arial"; + + /* no support to underline and strikeout */ + switch(style&3) + { + case CD_BOLD: + weight = CAIRO_FONT_WEIGHT_BOLD; + break; + case CD_ITALIC: + slant = CAIRO_FONT_SLANT_ITALIC; + break; + case CD_BOLD_ITALIC: + weight = CAIRO_FONT_WEIGHT_BOLD; + slant = CAIRO_FONT_SLANT_ITALIC; + break; + } + + cairo_select_font_face(ctxcanvas->cr, typeface, slant, weight); + cairo_set_font_size(ctxcanvas->cr, (double)cdGetFontSizePixels(ctxcanvas->canvas, size)); + + font = cairo_get_scaled_font(ctxcanvas->cr); + + if (!font) + return 0; + + font = cairo_scaled_font_reference(font); + ctxcanvas->font = font; + + return 1; +} + +static void cdgetfontdim(cdCtxCanvas *ctxcanvas, int *max_width, int *height, int *ascent, int *descent) +{ + cairo_font_extents_t extents; + + if (!ctxcanvas->font) + return; + + cairo_set_scaled_font(ctxcanvas->cr, ctxcanvas->font); + cairo_font_extents(ctxcanvas->cr, &extents); + + if (ascent) *ascent = (int)extents.ascent; + if (descent) *descent = (int)extents.descent; + if (height) *height = (int)extents.height; + if (max_width) *max_width = (int)extents.max_x_advance; +} + +static long int cdforeground(cdCtxCanvas *ctxcanvas, long int color) +{ + if (ctxcanvas->solid) + cairo_pattern_destroy(ctxcanvas->solid); + + cairo_set_source_rgba(ctxcanvas->cr, cdCairoGetRed(color), + cdCairoGetGreen(color), + cdCairoGetBlue(color), + cdCairoGetAlpha(color)); + ctxcanvas->solid = cairo_get_source(ctxcanvas->cr); + cairo_pattern_reference(ctxcanvas->solid); + ctxcanvas->last_source = 0; + return color; +} + + +/******************************************************/ + +static void cdclear(cdCtxCanvas* ctxcanvas) +{ + cairo_save (ctxcanvas->cr); + cairo_set_source_rgba(ctxcanvas->cr, cdCairoGetRed(ctxcanvas->canvas->background), cdCairoGetGreen(ctxcanvas->canvas->background), cdCairoGetBlue(ctxcanvas->canvas->background), cdCairoGetAlpha(ctxcanvas->canvas->background)); + cairo_set_operator (ctxcanvas->cr, CAIRO_OPERATOR_SOURCE); + cairo_paint (ctxcanvas->cr); /* paints the current source everywhere within the current clip region. */ + cairo_restore (ctxcanvas->cr); +} + +static void cdfline(cdCtxCanvas *ctxcanvas, double x1, double y1, double x2, double y2) +{ + update_fill(ctxcanvas, 0); + + cairo_move_to(ctxcanvas->cr, x1, y1); + cairo_line_to(ctxcanvas->cr, x2, y2); + cairo_stroke(ctxcanvas->cr); +} + +static void cdline(cdCtxCanvas *ctxcanvas, int x1, int y1, int x2, int y2) +{ + cdfline(ctxcanvas, (double)x1, (double)y1, (double)x2, (double)y2); +} + +static void cdfarc(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + update_fill(ctxcanvas, 0); + + if (w == h) + { + cairo_arc_negative(ctxcanvas->cr, xc, yc, 0.5*w, -a1*CD_DEG2RAD, -a2*CD_DEG2RAD); + cairo_stroke(ctxcanvas->cr); + } + else /* Ellipse: change the scale to create from the circle */ + { + cairo_save(ctxcanvas->cr); /* save to use the local transform */ + + cairo_translate(ctxcanvas->cr, xc, yc); + cairo_scale(ctxcanvas->cr, w/h, 1.0); + cairo_translate(ctxcanvas->cr, -xc, -yc); + + cairo_arc_negative(ctxcanvas->cr, xc, yc, 0.5*h, -a1*CD_DEG2RAD, -a2*CD_DEG2RAD); + cairo_stroke(ctxcanvas->cr); + + cairo_restore(ctxcanvas->cr); /* restore from local */ + } +} + +static void cdarc(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + cdfarc(ctxcanvas, (double)xc, (double)yc, (double)w, (double)h, a1, a2); +} + +static void cdfsector(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + update_fill(ctxcanvas, 1); + + if (w == h) + { + cairo_move_to(ctxcanvas->cr, xc, yc); + cairo_arc_negative(ctxcanvas->cr, xc, yc, 0.5*w, -a1*CD_DEG2RAD, -a2*CD_DEG2RAD); + cairo_fill(ctxcanvas->cr); + } + else /* Ellipse: change the scale to create from the circle */ + { + cairo_save(ctxcanvas->cr); /* save to use the local transform */ + + cairo_translate(ctxcanvas->cr, xc, yc); + cairo_scale(ctxcanvas->cr, w/h, 1.0); + cairo_translate(ctxcanvas->cr, -xc, -yc); + + cairo_move_to(ctxcanvas->cr, xc, yc); + cairo_arc_negative(ctxcanvas->cr, xc, yc, 0.5*h, -a1*CD_DEG2RAD, -a2*CD_DEG2RAD); + + if (ctxcanvas->canvas->interior_style == CD_SOLID || + ctxcanvas->canvas->interior_style == CD_PATTERN) + cairo_fill(ctxcanvas->cr); + else + { + cairo_line_to(ctxcanvas->cr, xc, yc); + cairo_stroke(ctxcanvas->cr); + } + + cairo_restore(ctxcanvas->cr); /* restore from local */ + } +} + +static void cdsector(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + cdfsector(ctxcanvas, (double)xc, (double)yc, (double)w, (double)h, a1, a2); +} + +static void cdfchord(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, double h, double a1, double a2) +{ + update_fill(ctxcanvas, 1); + + if (w == h) + { + cairo_arc_negative(ctxcanvas->cr, xc, yc, 0.5*w, -a1*CD_DEG2RAD, -a2*CD_DEG2RAD); + cairo_fill_preserve(ctxcanvas->cr); + cairo_stroke(ctxcanvas->cr); + } + else /* Ellipse: change the scale to create from the circle */ + { + cairo_save(ctxcanvas->cr); /* save to use the local transform */ + + /* local transform */ + cairo_translate(ctxcanvas->cr, xc, yc); + cairo_scale(ctxcanvas->cr, 1.0, w/h); + + cairo_arc_negative(ctxcanvas->cr, xc, yc, 0.5*w, -a1*CD_DEG2RAD, -a2*CD_DEG2RAD); + cairo_fill_preserve(ctxcanvas->cr); + cairo_stroke(ctxcanvas->cr); + + cairo_restore(ctxcanvas->cr); /* restore from local */ + } +} + +static void cdchord(cdCtxCanvas *ctxcanvas, int xc, int yc, int w, int h, double a1, double a2) +{ + cdfchord(ctxcanvas, (double)xc, (double)yc, (double)w, (double)h, a1, a2); +} + +static void cdfrect(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + update_fill(ctxcanvas, 0); + cairo_rectangle(ctxcanvas->cr, xmin, ymin, xmax-xmin+1, ymax-ymin+1); + cairo_stroke(ctxcanvas->cr); +} + +static void cdrect(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + cdfrect(ctxcanvas, (double)xmin, (double)xmax, (double)ymin, (double)ymax); +} + +static void cdfbox(cdCtxCanvas *ctxcanvas, double xmin, double xmax, double ymin, double ymax) +{ + update_fill(ctxcanvas, 1); + cairo_rectangle(ctxcanvas->cr, xmin, ymin, xmax-xmin+1, ymax-ymin+1); + cairo_fill(ctxcanvas->cr); +} + +static void cdbox(cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + cdfbox(ctxcanvas, (double)xmin, (double)xmax, (double)ymin, (double)ymax); +} + +static void cdftext(cdCtxCanvas *ctxcanvas, double x, double y, const char *s, int len) +{ + cairo_text_extents_t extents; + cairo_font_extents_t font_extents; + int dir = -1; + double x_origin = x; + double y_origin = y; + + s = StrConvertToUTF8(ctxcanvas, s, len); + + cairo_set_scaled_font(ctxcanvas->cr, ctxcanvas->font); + cairo_font_extents(ctxcanvas->cr, &font_extents); + cairo_text_extents(ctxcanvas->cr, s, &extents); + + switch (ctxcanvas->canvas->text_alignment) + { + case CD_BASE_RIGHT: + case CD_NORTH_EAST: + case CD_EAST: + case CD_SOUTH_EAST: + x = x - (int)extents.width; + break; + case CD_BASE_CENTER: + case CD_CENTER: + case CD_NORTH: + case CD_SOUTH: + x = x - (int)(extents.width/2); + break; + case CD_BASE_LEFT: + case CD_NORTH_WEST: + case CD_WEST: + case CD_SOUTH_WEST: + x = x; + break; + } + + if (ctxcanvas->canvas->invert_yaxis) + dir = 1; + + switch (ctxcanvas->canvas->text_alignment) + { + case CD_BASE_LEFT: + case CD_BASE_CENTER: + case CD_BASE_RIGHT: + y = y; + break; + case CD_SOUTH_EAST: + case CD_SOUTH_WEST: + case CD_SOUTH: + y = y - dir*(int)font_extents.descent; + break; + case CD_NORTH_EAST: + case CD_NORTH: + case CD_NORTH_WEST: + y = y + dir*(int)(extents.height - font_extents.descent); + break; + case CD_CENTER: + case CD_EAST: + case CD_WEST: + y = y + dir*(int)(extents.height/2 - font_extents.descent); + break; + } + + if (ctxcanvas->canvas->text_orientation != 0) + { + cairo_matrix_t matrix; + double angle = CD_DEG2RAD * ctxcanvas->canvas->text_orientation; + double cos_angle = cos(angle); + double sin_angle = sin(angle); + + cdfRotatePoint(ctxcanvas->canvas, x, y, x_origin, y_origin, &x, &y, sin_angle, cos_angle); + + cairo_get_font_matrix(ctxcanvas->cr, &matrix); + cairo_matrix_rotate(&matrix, -angle); + cairo_set_font_matrix(ctxcanvas->cr, &matrix); + } + + update_fill(ctxcanvas, 0); + + cairo_move_to(ctxcanvas->cr, x, y); + cairo_show_text(ctxcanvas->cr, s); + cairo_fill(ctxcanvas->cr); +} + +static void cdtext(cdCtxCanvas *ctxcanvas, int x, int y, const char *s, int len) +{ + cdftext(ctxcanvas, (double)x, (double)y, s, len); +} + +static void cdgettextsize(cdCtxCanvas *ctxcanvas, const char *s, int len, int *width, int *height) +{ + cairo_text_extents_t extents; + + if (!ctxcanvas->font) + return; + + s = StrConvertToUTF8(ctxcanvas, s, len); + + cairo_set_scaled_font(ctxcanvas->cr, ctxcanvas->font); + cairo_text_extents(ctxcanvas->cr, s, &extents); + + if (width) + *width = (int)extents.width; + + if (height) + *height = (int)extents.height; +} + +static void cdpoly(cdCtxCanvas *ctxcanvas, int mode, cdPoint* poly, int n) +{ + int i; + + if (mode == CD_CLIP) + return; + + if (mode == CD_FILL) + { + update_fill(ctxcanvas, 1); + + if (ctxcanvas->holes || ctxcanvas->canvas->fill_mode==CD_EVENODD) + cairo_set_fill_rule(ctxcanvas->cr, CAIRO_FILL_RULE_EVEN_ODD); + else + cairo_set_fill_rule(ctxcanvas->cr, CAIRO_FILL_RULE_WINDING); + } + else + update_fill(ctxcanvas, 0); + + cairo_move_to(ctxcanvas->cr, poly[0].x, poly[0].y); + + if (mode == CD_BEZIER) + { + for (i=1; icr, poly[i].x, poly[i].y, poly[i+1].x, poly[i+1].y, poly[i+2].x, poly[i+2].y); + } + else + { + int hole_index = 0; + + for (i=1; iholes && i == ctxcanvas->poly_holes[hole_index]) + { + cairo_move_to(ctxcanvas->cr, poly[i].x, poly[i].y); + hole_index++; + } + else + cairo_line_to(ctxcanvas->cr, poly[i].x, poly[i].y); + } + } + + switch (mode) + { + case CD_CLOSED_LINES : + cairo_close_path(ctxcanvas->cr); + cairo_stroke(ctxcanvas->cr); + break; + case CD_OPEN_LINES : + cairo_stroke(ctxcanvas->cr); + break; + case CD_BEZIER : + cairo_stroke(ctxcanvas->cr); + break; + case CD_FILL : + cairo_fill(ctxcanvas->cr); + break; + } +} + +static void cdfpoly(cdCtxCanvas *ctxcanvas, int mode, cdfPoint* poly, int n) +{ + int i; + + if (mode == CD_CLIP) + return; + + if (mode == CD_FILL) + { + update_fill(ctxcanvas, 1); + + if (ctxcanvas->holes || ctxcanvas->canvas->fill_mode==CD_EVENODD) + cairo_set_fill_rule(ctxcanvas->cr, CAIRO_FILL_RULE_EVEN_ODD); + else + cairo_set_fill_rule(ctxcanvas->cr, CAIRO_FILL_RULE_WINDING); + } + else + update_fill(ctxcanvas, 0); + + cairo_move_to(ctxcanvas->cr, poly[0].x, poly[0].y); + + if (mode == CD_BEZIER) + { + for (i=1; icr, poly[i].x, poly[i].y, poly[i+1].x, poly[i+1].y, poly[i+2].x, poly[i+2].y); + } + else + { + int hole_index = 0; + + for (i=1; iholes && i == ctxcanvas->poly_holes[hole_index]) + { + cairo_move_to(ctxcanvas->cr, poly[i].x, poly[i].y); + hole_index++; + } + else + cairo_line_to(ctxcanvas->cr, poly[i].x, poly[i].y); + } + } + + switch (mode) + { + case CD_CLOSED_LINES : + cairo_close_path(ctxcanvas->cr); + cairo_stroke(ctxcanvas->cr); + break; + case CD_OPEN_LINES : + cairo_stroke(ctxcanvas->cr); + break; + case CD_BEZIER : + cairo_stroke(ctxcanvas->cr); + break; + case CD_FILL : + cairo_fill(ctxcanvas->cr); + break; + } +} + +/******************************************************/ + +static void cdgetimagergb(cdCtxCanvas *ctxcanvas, unsigned char *r, unsigned char *g, unsigned char *b, int x, int y, int w, int h) +{ + int col, lin, pos; + double red, green, blue; + cairo_pattern_t *pattern; + + cairo_save (ctxcanvas->cr); + + /* reset to the identity. */ + cairo_identity_matrix(ctxcanvas->cr); + + if (ctxcanvas->canvas->invert_yaxis==0) // if 0, invert because the transform was reset here + y = _cdInvertYAxis(ctxcanvas->canvas, y); + + //TODO:fix + pattern = cairo_get_source(ctxcanvas->cr); + if (!pattern) + return; + + for (lin = (y-h+1); lin < h; lin++) + { + for (col = x; col < w; col++) + { + pos = (h-lin-1) * w + col; + cairo_pattern_get_color_stop_rgba(pattern, pos, NULL, &red, &green, &blue, NULL); + *r = (unsigned char)(red*255.0); + *g = (unsigned char)(green*255.0); + *b = (unsigned char)(blue*255.0); + } + } + + cairo_pattern_destroy(pattern); + cairo_restore (ctxcanvas->cr); +} + +static void cdputimagerectrgb(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int i, j, d, rw, rh; + unsigned char* rgb_data; + int stride; + cairo_surface_t* surface, *new_surface; + cairo_t* cr; + + if (xmin<0 || ymin<0 || xmax-xmin+1>iw || ymax-ymin+1>ih) return; + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + y -= (h - 1); /* Cairo image origin is at top-left */ + + stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, rw); + rgb_data = (unsigned char*)malloc(sizeof(unsigned char)*(stride * rh)); + + if (!rgb_data) return; + + surface = cairo_image_surface_create_for_data(rgb_data, CAIRO_FORMAT_RGB24, rw, rh, stride); + + d = 0; + for (i=ymax; i>=ymin; i--) + { + for (j=xmin; j<=xmax; j++) + { + rgb_data[d] = b[i*iw+j]; d++; + rgb_data[d] = g[i*iw+j]; d++; + rgb_data[d] = r[i*iw+j]; d++; + rgb_data[d] = (unsigned char)0; d++; + } + } + + /* Scaling surface to fit into the image */ +// if (w != rw || h != rh) + { + new_surface = cairo_surface_create_similar(surface, CAIRO_CONTENT_COLOR, w, h); + cr = cairo_create (new_surface); + + /* Scale *before* setting the source surface (1) */ + cairo_scale (cr, (double)w / rw, (double)h / rh); + cairo_set_source_surface (cr, surface, 0, 0); + + /* To avoid getting the edge pixels blended with 0 alpha, + * which would occur with the default EXTEND_NONE */ + cairo_pattern_set_extend (cairo_get_source(cr), CAIRO_EXTEND_REFLECT); + + /* Replace the destination with the source instead of overlaying */ + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + + cairo_paint (cr); + + cairo_destroy (cr); + } + + /* Put image rect */ + cairo_set_source_surface(ctxcanvas->cr, new_surface, x, y); + cairo_pattern_set_extend(cairo_get_source(ctxcanvas->cr), CAIRO_EXTEND_NONE); + cairo_paint(ctxcanvas->cr); + + cairo_surface_destroy(surface); + cairo_surface_destroy(new_surface); + free(rgb_data); +} + +static void cdputimagerectrgba(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *r, const unsigned char *g, const unsigned char *b, const unsigned char *a, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int i, j, d, rw, rh; + unsigned char* rgba_data; + int stride; + cairo_surface_t* surface, *new_surface, *new_alpha_surface; + cairo_t* cr; + + if (xmin<0 || ymin<0 || xmax-xmin+1>iw || ymax-ymin+1>ih) return; + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + y -= (h - 1); /* Cairo image origin is at top-left */ + + stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, rw); + rgba_data = (unsigned char*)malloc(sizeof(unsigned char)*(stride * rh)); + + if (!rgba_data) return; + + surface = cairo_image_surface_create_for_data(rgba_data, CAIRO_FORMAT_ARGB32, rw, rh, stride); + + d = 0; + for (i=ymax; i>=ymin; i--) + { + for (j=xmin; j<=xmax; j++) + { + rgba_data[d] = b[i*iw+j]; d++; + rgba_data[d] = g[i*iw+j]; d++; + rgba_data[d] = r[i*iw+j]; d++; + rgba_data[d] = a[i*iw+j]; d++; + } + } + + // TODO: use only one surface ????? + + /* Scaling RGB surface to fit into the image */ +// if (w != rw || h != rh) + { + new_surface = cairo_surface_create_similar(surface, CAIRO_CONTENT_COLOR, w, h); + cr = cairo_create (new_surface); + + /* Scale *before* setting the source surface (1) */ + cairo_scale (cr, (double)w / rw, (double)h / rh); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_paint (cr); + + cairo_destroy (cr); + } + + /* Scaling ALPHA surface to fit into the image */ + { + new_alpha_surface = cairo_surface_create_similar(surface, CAIRO_CONTENT_ALPHA, w, h); + cr = cairo_create (new_alpha_surface); + + /* Scale *before* setting the source surface (1) */ + cairo_scale (cr, (double)w / rw, (double)h / rh); + cairo_set_source_surface (cr, surface, 0, 0); + cairo_paint (cr); + + cairo_destroy (cr); + } + + /* Put image rect */ + cairo_set_source_surface(ctxcanvas->cr, new_surface, x, y); + cairo_mask_surface(ctxcanvas->cr, new_alpha_surface, x, y); +// cairo_pattern_set_extend(cairo_get_source(ctxcanvas->cr), CAIRO_EXTEND_NONE); +// cairo_paint(ctxcanvas->cr); + + cairo_surface_destroy(surface); + cairo_surface_destroy(new_surface); + cairo_surface_destroy(new_alpha_surface); + free(rgba_data); +} + +static void cdputimagerectmap(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsigned char *index, const long int *colors, int x, int y, int w, int h, int xmin, int xmax, int ymin, int ymax) +{ + int i, j, d, rw, rh; + unsigned char* rgb_data; + int stride; + cairo_surface_t* surface, *new_surface; + cairo_t* cr; + + if (xmin<0 || ymin<0 || xmax-xmin+1>iw || ymax-ymin+1>ih) return; + + rw = xmax-xmin+1; + rh = ymax-ymin+1; + y -= (h - 1); /* Cairo image origin is at top-left */ + + stride = cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, rw); + rgb_data = (unsigned char*)malloc(sizeof(unsigned char)*(stride * rh)); + + if (!rgb_data) return; + + surface = cairo_image_surface_create_for_data(rgb_data, CAIRO_FORMAT_RGB24, rw, rh, stride); + + d = 0; + for (i=ymax; i>=ymin; i--) + { + for (j=xmin; j<=xmax; j++) + { + long c = colors[index[i*iw+j]]; + rgb_data[d] = cdRed(c); d++; + rgb_data[d] = cdGreen(c); d++; + rgb_data[d] = cdBlue(c); d++; + rgb_data[d] = (unsigned char)0; d++; + } + } + + /* Scaling surface to fit into the image */ +// if (w != rw || h != rh) + { + new_surface = cairo_surface_create_similar(surface, CAIRO_CONTENT_COLOR, w, h); + cr = cairo_create (new_surface); + + /* Scale *before* setting the source surface (1) */ + cairo_scale (cr, (double)w / rw, (double)h / rh); + cairo_set_source_surface (cr, surface, 0, 0); + + /* To avoid getting the edge pixels blended with 0 alpha, + * which would occur with the default EXTEND_NONE */ + cairo_pattern_set_extend (cairo_get_source(cr), CAIRO_EXTEND_REFLECT); + + /* Replace the destination with the source instead of overlaying */ + cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE); + + cairo_paint (cr); + + cairo_destroy (cr); + } + + cairo_set_source_surface(ctxcanvas->cr, surface, x, y); + cairo_pattern_set_extend(cairo_get_source(ctxcanvas->cr), CAIRO_EXTEND_NONE); + cairo_paint(ctxcanvas->cr); + + cairo_surface_destroy(surface); + cairo_surface_destroy(new_surface); + free(rgb_data); +} + +static void cdpixel(cdCtxCanvas *ctxcanvas, int x, int y, long int color) +{ + cairo_pattern_t* old_source = cairo_get_source(ctxcanvas->cr); + cairo_set_source_rgba(ctxcanvas->cr, cdCairoGetRed(color), cdCairoGetGreen(color), cdCairoGetBlue(color), cdCairoGetAlpha(color)); + + cairo_move_to(ctxcanvas->cr, (double)x, (double)y); + cairo_arc(ctxcanvas->cr, (double)x, (double)y, 0.5, 0.0, 2 * M_PI); + + cairo_fill(ctxcanvas->cr); + cairo_set_source(ctxcanvas->cr, old_source); +} + +static cdCtxImage *cdcreateimage (cdCtxCanvas *ctxcanvas, int w, int h) +{ + cdCtxImage *ctximage = (cdCtxImage *)malloc(sizeof(cdCtxImage)); + cairo_surface_t* img_surface; + + ctximage->w = w; + ctximage->h = h; + ctximage->bpp = ctxcanvas->canvas->bpp; + ctximage->xres = ctxcanvas->canvas->xres; + ctximage->yres = ctxcanvas->canvas->yres; + ctximage->w_mm = ctximage->w / ctximage->xres; + ctximage->h_mm = ctximage->h / ctximage->yres; + + img_surface = cairo_surface_create_similar(cairo_get_target(ctxcanvas->cr), CAIRO_CONTENT_COLOR_ALPHA, w, h); + ctximage->img = cairo_create(img_surface); + + if (!ctximage->img) + { + free(ctximage); + return (void *)0; + } + + cairo_rectangle(ctximage->img, 0, 0, ctximage->w, ctximage->h); + cairo_set_source_rgba(ctximage->img, 1.0, 1.0, 1.0, 1.0); /* white opaque */ + cairo_fill(ctximage->img); + + cairo_surface_destroy(img_surface); + + return (void*)ctximage; +} + +static void cdkillimage (cdCtxImage *ctximage) +{ + cairo_destroy(ctximage->img); + free(ctximage); +} + +static void cdgetimage (cdCtxCanvas *ctxcanvas, cdCtxImage *ctximage, int x, int y) +{ + cairo_save (ctximage->img); + + /* reset to the identity. */ + cairo_identity_matrix(ctximage->img); + + cairo_reset_clip(ctximage->img); + + if (ctxcanvas->canvas->invert_yaxis==0) /* if 0, invert because the transform was reset here */ + y = _cdInvertYAxis(ctxcanvas->canvas, y); + + /* y is the bottom-left of the image in CD, must be at upper-left */ + y -= ctximage->h-1; + + /* creates a pattern from the canvas and sets it as source in the image. */ + cairo_set_source_surface(ctximage->img, cairo_get_target(ctxcanvas->cr), x, y); + + cairo_pattern_set_extend (cairo_get_source(ctximage->img), CAIRO_EXTEND_NONE); + cairo_set_operator (ctximage->img, CAIRO_OPERATOR_SOURCE); + cairo_paint(ctximage->img); /* paints the current source everywhere within the current clip region. */ + + /* must restore matrix, clipping and source */ + cairo_restore (ctximage->img); +} + +static void cdputimagerect (cdCtxCanvas *ctxcanvas, cdCtxImage *ctximage, int x, int y, int xmin, int xmax, int ymin, int ymax) +{ + cairo_save (ctxcanvas->cr); + + /* y is the bottom-left of the image region in CD */ + y -= (ymax-ymin+1)-1; + + cairo_reset_clip(ctxcanvas->cr); + cairo_rectangle(ctxcanvas->cr, x, y, xmax-xmin+1, ymax-ymin+1); + cairo_clip(ctxcanvas->cr); + + ymin = (ctximage->h-1) - ymax; /* ymin starts at the bottom of the image in CD, we want ymax, but oriented top-down */ + + /* creates a pattern from the image and sets it as source in the canvas. */ + cairo_set_source_surface(ctxcanvas->cr, cairo_get_target(ctximage->img), xmin, ymin); + + cairo_pattern_set_extend (cairo_get_source(ctxcanvas->cr), CAIRO_EXTEND_NONE); + cairo_set_operator (ctxcanvas->cr, CAIRO_OPERATOR_SOURCE); + cairo_paint(ctxcanvas->cr); /* paints the current source everywhere within the current clip region. */ + + /* must restore clipping and source */ + cairo_restore (ctxcanvas->cr); +} + +static void cdscrollarea (cdCtxCanvas *ctxcanvas, int xmin, int xmax, int ymin, int ymax, int dx, int dy) +{ + cairo_save (ctxcanvas->cr); + + /* reset to identity */ + cairo_identity_matrix(ctxcanvas->cr); + + if (ctxcanvas->canvas->invert_yaxis==0) /* if 0, invert because the transform was reset here */ + { + dy = -dy; + ymin = _cdInvertYAxis(ctxcanvas->canvas, ymin); + ymax = _cdInvertYAxis(ctxcanvas->canvas, ymax); + _cdSwapInt(ymin, ymax); + } + + cairo_reset_clip(ctxcanvas->cr); + cairo_rectangle(ctxcanvas->cr, xmin+dx, ymin+dy, xmax-xmin+1, ymax-ymin+1); + cairo_clip(ctxcanvas->cr); + + /* creates a pattern from the canvas and sets it as source in the canvas. */ + cairo_set_source_surface(ctxcanvas->cr, cairo_get_target(ctxcanvas->cr), xmin, ymin); + + cairo_pattern_set_extend (cairo_get_source(ctxcanvas->cr), CAIRO_EXTEND_NONE); + cairo_set_operator (ctxcanvas->cr, CAIRO_OPERATOR_SOURCE); + cairo_paint(ctxcanvas->cr); /* paints the current source everywhere within the current clip region. */ + + /* must restore matrix, clipping and source */ + cairo_restore (ctxcanvas->cr); +} + +static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix) +{ + /* reset to identity */ + cairo_identity_matrix(ctxcanvas->cr); + ctxcanvas->canvas->invert_yaxis = 1; + + if (matrix) + { + cairo_matrix_t mtx; + + /* configure a bottom-up coordinate system */ + mtx.xx = 1; mtx.yx = 0; + mtx.xy = 0; mtx.yy = -1; + mtx.x0 = 0; mtx.y0 = (ctxcanvas->canvas->h-1); + cairo_transform(ctxcanvas->cr, &mtx); + ctxcanvas->canvas->invert_yaxis = 0; + + mtx.xx = matrix[0]; mtx.yx = matrix[1]; + mtx.xy = matrix[2]; mtx.yy = matrix[3]; + mtx.x0 = matrix[4]; mtx.y0 = matrix[5]; + cairo_transform(ctxcanvas->cr, &mtx); + } + else if (ctxcanvas->rotate_angle) + { + /* rotation = translate to point + rotation + translate back */ + /* the rotation must be corrected because of the Y axis orientation */ + cairo_translate(ctxcanvas->cr, ctxcanvas->rotate_center_x, _cdInvertYAxis(ctxcanvas->canvas, ctxcanvas->rotate_center_y)); + cairo_rotate(ctxcanvas->cr, (double)-ctxcanvas->rotate_angle * CD_DEG2RAD); + cairo_translate(ctxcanvas->cr, -ctxcanvas->rotate_center_x, -_cdInvertYAxis(ctxcanvas->canvas, ctxcanvas->rotate_center_y)); + } +} + +/******************************************************************/ + +static void set_hatchboxsize_attrib(cdCtxCanvas *ctxcanvas, char* data) +{ + int hatchboxsize; + + if (data == NULL) + { + ctxcanvas->hatchboxsize = 8; + return; + } + + sscanf(data, "%d", &hatchboxsize); + ctxcanvas->hatchboxsize = hatchboxsize; +} + +static char* get_hatchboxsize_attrib(cdCtxCanvas *ctxcanvas) +{ + static char size[10]; + sprintf(size, "%d", ctxcanvas->hatchboxsize); + return size; +} + +static cdAttribute hatchboxsize_attrib = +{ + "HATCHBOXSIZE", + set_hatchboxsize_attrib, + get_hatchboxsize_attrib +}; + +static void set_poly_attrib(cdCtxCanvas *ctxcanvas, char* data) +{ + int hole; + + if (data == NULL) + { + ctxcanvas->holes = 0; + return; + } + + sscanf(data, "%d", &hole); + ctxcanvas->poly_holes[ctxcanvas->holes] = hole; + ctxcanvas->holes++; +} + +static char* get_poly_attrib(cdCtxCanvas *ctxcanvas) +{ + static char holes[10]; + sprintf(holes, "%d", ctxcanvas->holes); + return holes; +} + +static cdAttribute poly_attrib = +{ + "POLYHOLE", + set_poly_attrib, + get_poly_attrib +}; + +static void set_rotate_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + /* ignore ROTATE if transform is set, + because there is native support for transformations */ + if (ctxcanvas->canvas->use_matrix) + return; + + if (data) + { + sscanf(data, "%g %d %d", &ctxcanvas->rotate_angle, + &ctxcanvas->rotate_center_x, + &ctxcanvas->rotate_center_y); + } + else + { + ctxcanvas->rotate_angle = 0; + ctxcanvas->rotate_center_x = 0; + ctxcanvas->rotate_center_y = 0; + } + + cdtransform(ctxcanvas, NULL); +} + +static char* get_rotate_attrib(cdCtxCanvas* ctxcanvas) +{ + static char data[100]; + + if (!ctxcanvas->rotate_angle) + return NULL; + + sprintf(data, "%g %d %d", (double)ctxcanvas->rotate_angle, + ctxcanvas->rotate_center_x, + ctxcanvas->rotate_center_y); + + return data; +} + +static cdAttribute rotate_attrib = +{ + "ROTATE", + set_rotate_attrib, + get_rotate_attrib +}; + +static void set_aa_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + cairo_font_options_t* options = NULL; + cairo_scaled_font_get_font_options(ctxcanvas->font, options); + + if (!data || data[0] == '0') + { + cairo_set_antialias(ctxcanvas->cr, CAIRO_ANTIALIAS_NONE); + cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_NONE); + } + else + { + cairo_set_antialias(ctxcanvas->cr, CAIRO_ANTIALIAS_DEFAULT); + cairo_font_options_set_antialias(options, CAIRO_ANTIALIAS_DEFAULT); + } + + cairo_font_options_destroy(options); +} + +static char* get_aa_attrib(cdCtxCanvas* ctxcanvas) +{ + if (cairo_get_antialias(ctxcanvas->cr) != CAIRO_ANTIALIAS_NONE) + return "1"; + else + return "0"; +} + +static cdAttribute aa_attrib = +{ + "ANTIALIAS", + set_aa_attrib, + get_aa_attrib +}; + +static void set_linegradient_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (data) + { + int x1, y1, x2, y2; + double offset; + int count = 1; + + sscanf(data, "%d %d %d %d", &x1, &y1, &x2, &y2); + + if (ctxcanvas->canvas->invert_yaxis) + { + y1 = _cdInvertYAxis(ctxcanvas->canvas, y1); + y2 = _cdInvertYAxis(ctxcanvas->canvas, y2); + } + + if (ctxcanvas->pattern) + cairo_pattern_destroy(ctxcanvas->pattern); + + ctxcanvas->pattern = cairo_pattern_create_linear((double)x1, (double)y1, (double)x2, (double)y2); + cairo_pattern_reference(ctxcanvas->pattern); + + for(offset = 0.1; offset < 1.0; offset += 0.1) + { + if ( count % 2 ) + { + cairo_pattern_add_color_stop_rgb(ctxcanvas->pattern, offset, + cdCairoGetRed(ctxcanvas->canvas->foreground), + cdCairoGetGreen(ctxcanvas->canvas->foreground), + cdCairoGetBlue(ctxcanvas->canvas->foreground)); + } + else + { + cairo_pattern_add_color_stop_rgb(ctxcanvas->pattern, offset, + cdCairoGetRed(ctxcanvas->canvas->background), + cdCairoGetGreen(ctxcanvas->canvas->background), + cdCairoGetBlue(ctxcanvas->canvas->background)); + } + count++; + } + + cairo_pattern_set_extend(ctxcanvas->pattern, CAIRO_EXTEND_REPEAT); + + cairo_set_source(ctxcanvas->cr, ctxcanvas->pattern); + ctxcanvas->last_source = 1; + } +} + +static char* get_linegradient_attrib(cdCtxCanvas* ctxcanvas) +{ + double x1, y1, x2, y2; + + if (cairo_pattern_get_linear_points(ctxcanvas->pattern, &x1, &y1, &x2, &y2) == CAIRO_STATUS_SUCCESS) + { + static char data[100]; + sprintf(data, "%d %d %d %d", (int)x1, (int)y1, (int)x2, (int)y2); + return data; + } + else + return NULL; +} + +static cdAttribute linegradient_attrib = +{ + "LINEGRADIENT", + set_linegradient_attrib, + get_linegradient_attrib +}; + +static void set_radialgradient_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (data) + { + int cx1, cy1, cx2, cy2; + float rad1, rad2; + double offset; + int count = 1; + + sscanf(data, "%d %d %g %d %d %g", &cx1, &cy1, &rad1, &cx2, &cy2, &rad2); + + if (ctxcanvas->canvas->invert_yaxis) + { + cy1 = _cdInvertYAxis(ctxcanvas->canvas, cy1); + cy2 = _cdInvertYAxis(ctxcanvas->canvas, cy2); + } + + if (ctxcanvas->pattern) + cairo_pattern_destroy(ctxcanvas->pattern); + + ctxcanvas->pattern = cairo_pattern_create_radial((double)cx1, (double)cx1, (double)rad1, (double)cx2, (double)cx2, (double)rad2); + cairo_pattern_reference(ctxcanvas->pattern); + + for(offset = 0.1; offset < 1.0; offset += 0.1) + { + if ( count % 2 ) + { + cairo_pattern_add_color_stop_rgb(ctxcanvas->pattern, offset, + cdCairoGetRed(ctxcanvas->canvas->foreground), + cdCairoGetGreen(ctxcanvas->canvas->foreground), + cdCairoGetBlue(ctxcanvas->canvas->foreground)); + } + else + { + cairo_pattern_add_color_stop_rgb(ctxcanvas->pattern, offset, + cdCairoGetRed(ctxcanvas->canvas->background), + cdCairoGetGreen(ctxcanvas->canvas->background), + cdCairoGetBlue(ctxcanvas->canvas->background)); + } + count++; + } + + cairo_pattern_set_extend(ctxcanvas->pattern, CAIRO_EXTEND_REPEAT); + + cairo_set_source(ctxcanvas->cr, ctxcanvas->pattern); + ctxcanvas->last_source = 1; + } +} + +static char* get_radialgradient_attrib(cdCtxCanvas* ctxcanvas) +{ + double cx1, cy1, rad1, cx2, cy2, rad2; + + if (cairo_pattern_get_radial_circles(ctxcanvas->pattern, &cx1, &cy1, &rad1, &cx2, &cy2, &rad2) == CAIRO_STATUS_SUCCESS) + { + static char data[100]; + sprintf(data, "%d %d %g %d %d %g", (int)cx1, (int)cy1, (float)rad1, (int)cx2, (int)cy2, (float)rad2); + return data; + } + else + return NULL; +} + +static cdAttribute radialgradient_attrib = +{ + "RADIALGRADIENT", + set_radialgradient_attrib, + get_radialgradient_attrib +}; + +static char* get_version_attrib(cdCtxCanvas* ctxcanvas) +{ + (void)ctxcanvas; + return (char*)cairo_version_string(); +} + +static cdAttribute version_attrib = +{ + "CAIROVERSION", + NULL, + get_version_attrib +}; + +static void set_interp_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (data && cdStrEqualNoCase(data, "BEST")) + cairo_pattern_set_filter(cairo_get_source(ctxcanvas->cr), CAIRO_FILTER_BEST); + else if (data && cdStrEqualNoCase(data, "NEAREST")) + cairo_pattern_set_filter(cairo_get_source(ctxcanvas->cr), CAIRO_FILTER_NEAREST); + else if (data && cdStrEqualNoCase(data, "FAST")) + cairo_pattern_set_filter(cairo_get_source(ctxcanvas->cr), CAIRO_FILTER_FAST); + else if (data && cdStrEqualNoCase(data, "BILINEAR")) + cairo_pattern_set_filter(cairo_get_source(ctxcanvas->cr), CAIRO_FILTER_BILINEAR); + else + cairo_pattern_set_filter(cairo_get_source(ctxcanvas->cr), CAIRO_FILTER_GOOD); +} + +static char* get_interp_attrib(cdCtxCanvas* ctxcanvas) +{ + if(cairo_pattern_get_filter(cairo_get_source(ctxcanvas->cr)) == CAIRO_FILTER_BEST) + return "BEST"; + else if(cairo_pattern_get_filter(cairo_get_source(ctxcanvas->cr)) == CAIRO_FILTER_NEAREST) + return "NEAREST"; + else if(cairo_pattern_get_filter(cairo_get_source(ctxcanvas->cr)) == CAIRO_FILTER_FAST) + return "FAST"; + else if(cairo_pattern_get_filter(cairo_get_source(ctxcanvas->cr)) == CAIRO_FILTER_BILINEAR) + return "BILINEAR"; + else + return "GOOD"; +} + +static cdAttribute interp_attrib = +{ + "IMGINTERP", + set_interp_attrib, + get_interp_attrib +}; + +static char* get_cairodc_attrib(cdCtxCanvas *ctxcanvas) +{ + return (char*)ctxcanvas->cr; +} + +static cdAttribute cairodc_attrib = +{ + "CAIRODC", + NULL, + get_cairodc_attrib +}; + + +cdCtxCanvas *cdcairoCreateCanvas(cdCanvas* canvas, cairo_t* cr) +{ + cdCtxCanvas *ctxcanvas = (cdCtxCanvas *)malloc(sizeof(cdCtxCanvas)); + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + + ctxcanvas->cr = cr; + ctxcanvas->canvas = canvas; + ctxcanvas->last_source = -1; + + canvas->ctxcanvas = ctxcanvas; + canvas->invert_yaxis = 1; + + cdRegisterAttribute(canvas, &rotate_attrib); + cdRegisterAttribute(canvas, &version_attrib); + cdRegisterAttribute(canvas, &poly_attrib); + cdRegisterAttribute(canvas, &aa_attrib); + cdRegisterAttribute(canvas, &linegradient_attrib); + cdRegisterAttribute(canvas, &radialgradient_attrib); + cdRegisterAttribute(canvas, &interp_attrib); + cdRegisterAttribute(canvas, &cairodc_attrib); + cdRegisterAttribute(canvas, &hatchboxsize_attrib); + + cairo_save(ctxcanvas->cr); + cairo_set_operator(ctxcanvas->cr, CAIRO_OPERATOR_OVER); + + return ctxcanvas; +} + +void cdcairoInitTable(cdCanvas* canvas) +{ + canvas->cxFlush = cdflush; + canvas->cxClear = cdclear; + + canvas->cxPixel = cdpixel; + + canvas->cxLine = cdline; + canvas->cxPoly = cdpoly; + canvas->cxRect = cdrect; + canvas->cxBox = cdbox; + canvas->cxArc = cdarc; + canvas->cxSector = cdsector; + canvas->cxChord = cdchord; + canvas->cxText = cdtext; + + canvas->cxFLine = cdfline; + canvas->cxFPoly = cdfpoly; + canvas->cxFRect = cdfrect; + canvas->cxFBox = cdfbox; + canvas->cxFArc = cdfarc; + canvas->cxFSector = cdfsector; + canvas->cxFChord = cdfchord; + canvas->cxFText = cdftext; + + canvas->cxClip = cdclip; + canvas->cxClipArea = cdcliparea; + canvas->cxLineStyle = cdlinestyle; + canvas->cxLineWidth = cdlinewidth; + canvas->cxLineCap = cdlinecap; + canvas->cxLineJoin = cdlinejoin; + canvas->cxInteriorStyle = cdinteriorstyle; + canvas->cxHatch = cdhatch; + canvas->cxStipple = cdstipple; + canvas->cxPattern = cdpattern; + canvas->cxFont = cdfont; + canvas->cxGetFontDim = cdgetfontdim; + canvas->cxGetTextSize = cdgettextsize; + canvas->cxTransform = cdtransform; + canvas->cxWriteMode = cdwritemode; + canvas->cxForeground = cdforeground; + + canvas->cxGetImageRGB = cdgetimagergb; + canvas->cxScrollArea = cdscrollarea; + + canvas->cxCreateImage = cdcreateimage; + canvas->cxGetImage = cdgetimage; + canvas->cxPutImageRect = cdputimagerect; + canvas->cxKillImage = cdkillimage; + + canvas->cxPutImageRectRGB = cdputimagerectrgb; + canvas->cxPutImageRectMap = cdputimagerectmap; + canvas->cxPutImageRectRGBA = cdputimagerectrgba; +} + +/* +cairo_arc (cr, 128.0, 128.0, 76.8, 0, 2*M_PI); +cairo_clip (cr); +cairo_new_path (cr); // path not consumed by clip() +*/ diff --git a/src/cairo/cdcairoctx.h b/src/cairo/cdcairoctx.h new file mode 100644 index 0000000..266cfb3 --- /dev/null +++ b/src/cairo/cdcairoctx.h @@ -0,0 +1,77 @@ +/** \file + * \brief Cairo Base Driver + * + * See Copyright Notice in cd.h + */ + +#ifndef __CDCAIROCTX_H +#define __CDCAIROCTX_H + +#include + +#include "cd.h" +#include "cd_private.h" + + +struct _cdCtxImage { + unsigned int w, h; + double w_mm, h_mm; /* size in mm */ + double xres, yres; /* resolution in pixels/mm */ + int bpp; + cairo_t* img; +}; + +struct _cdCtxCanvas +{ + cdCanvas* canvas; + + cairo_t* cr; + + cairo_scaled_font_t* font; + + cairo_pattern_t *pattern, *solid; + int last_source; + + char* cairoLastConvertUTF8; + + /* custom attributes */ + + int img_format; + + float rotate_angle; + int rotate_center_x; + int rotate_center_y; + + int poly_holes[500]; + int holes; + + void* drawable; /* used in NativeWindow in GDK */ + +#ifdef WIN32 + void* hWnd; /* used in NativeWindow in Win32 */ + void* hDC; + int isOwnedDC; +#else + void* dpy; /* used in NativeWindow in X11 */ + unsigned long wnd; +#endif + + int user_image; /* used in ImageRGB */ + unsigned char *rgb; + + int eps; /* used in PS */ + + cdImage* image_dbuffer; /* Used by double buffer driver */ + cdCanvas* canvas_dbuffer; +}; + +#define cdCairoGetRed(_) (((double)cdRed(_))/255.) +#define cdCairoGetGreen(_) (((double)cdGreen(_))/255.) +#define cdCairoGetBlue(_) (((double)cdBlue(_))/255.) +#define cdCairoGetAlpha(_) (((double)cdAlpha(_))/255.) + +cdCtxCanvas *cdcairoCreateCanvas(cdCanvas* canvas, cairo_t* cr); +void cdcairoInitTable(cdCanvas* canvas); +void cdcairoKillCanvas(cdCtxCanvas *ctxcanvas); + +#endif diff --git a/src/cairo/cdcairodbuf.c b/src/cairo/cdcairodbuf.c new file mode 100644 index 0000000..0e23f06 --- /dev/null +++ b/src/cairo/cdcairodbuf.c @@ -0,0 +1,170 @@ +/** \file + * \brief Cairo Double Buffer Driver + * + * See Copyright Notice in cd.h + */ + +#include "cdcairoctx.h" +#include "cddbuf.h" +#include +#include + + +static void cdkillcanvas (cdCtxCanvas* ctxcanvas) +{ + cdKillImage(ctxcanvas->image_dbuffer); + cdcairoKillCanvas(ctxcanvas); +} + +static void cddeactivate(cdCtxCanvas* ctxcanvas) +{ + cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer; + /* this is done in the canvas_dbuffer context */ + cdCanvasDeactivate(canvas_dbuffer); +} + +static void cdflush(cdCtxCanvas* ctxcanvas) +{ + int old_writemode; + cdImage* image_dbuffer = ctxcanvas->image_dbuffer; + cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer; + + /* flush the writing in the image */ + cairo_show_page(ctxcanvas->cr); + + /* this is done in the canvas_dbuffer context */ + /* Flush can be affected by Origin and Clipping, but not WriteMode */ + old_writemode = cdCanvasWriteMode(canvas_dbuffer, CD_REPLACE); + cdCanvasPutImageRect(canvas_dbuffer, image_dbuffer, 0, 0, 0, 0, 0, 0); + cdCanvasWriteMode(canvas_dbuffer, old_writemode); +} + +static void cdcreatecanvas(cdCanvas* canvas, cdCanvas* canvas_dbuffer) +{ + int w, h; + cdCtxCanvas* ctxcanvas; + cdImage* image_dbuffer; + cdCtxImage* ctximage; + + cdCanvasActivate(canvas_dbuffer); + w = canvas_dbuffer->w; + h = canvas_dbuffer->h; + if (w==0) w=1; + if (h==0) h=1; + + /* this is done in the canvas_dbuffer context */ + image_dbuffer = cdCanvasCreateImage(canvas_dbuffer, w, h); + if (!image_dbuffer) + return; + + ctximage = image_dbuffer->ctximage; + + /* Init the driver DBuffer */ + ctxcanvas = cdcairoCreateCanvas(canvas, ctximage->img); + + if (!ctxcanvas) + return; + + ctxcanvas->image_dbuffer = image_dbuffer; + ctxcanvas->canvas_dbuffer = canvas_dbuffer; + + canvas->w = ctximage->w; + canvas->h = ctximage->h; + canvas->w_mm = ctximage->w_mm; + canvas->h_mm = ctximage->h_mm; + canvas->bpp = ctximage->bpp; + canvas->xres = ctximage->xres; + canvas->yres = ctximage->yres; +} + +static int cdactivate(cdCtxCanvas* ctxcanvas) +{ + int w, h; + cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer; + + /* this is done in the canvas_dbuffer context */ + /* this will update canvas size */ + cdCanvasActivate(canvas_dbuffer); + w = canvas_dbuffer->w; + h = canvas_dbuffer->h; + if (w==0) w=1; + if (h==0) h=1; + + /* check if the size changed */ + if (w != ctxcanvas->image_dbuffer->w || + h != ctxcanvas->image_dbuffer->h) + { + cdCanvas* canvas = ctxcanvas->canvas; + /* save the current, if the rebuild fail */ + cdImage* old_image_dbuffer = ctxcanvas->image_dbuffer; + cdCtxCanvas* old_ctxcanvas = ctxcanvas; + + /* if the image is rebuild, the canvas that uses the image must be also rebuild */ + + /* rebuild the image and the canvas */ + canvas->ctxcanvas = NULL; + canvas->context->cxCreateCanvas(canvas, canvas_dbuffer); + if (!canvas->ctxcanvas) + { + canvas->ctxcanvas = old_ctxcanvas; + return CD_ERROR; + } + + /* remove the old image and canvas */ + cdKillImage(old_image_dbuffer); + cdcairoKillCanvas(old_ctxcanvas); + + ctxcanvas = canvas->ctxcanvas; + + /* update canvas attributes */ + canvas->cxBackground(ctxcanvas, canvas->background); + canvas->cxForeground(ctxcanvas, canvas->foreground); + canvas->cxBackOpacity(ctxcanvas, canvas->back_opacity); + canvas->cxWriteMode(ctxcanvas, canvas->write_mode); + canvas->cxLineStyle(ctxcanvas, canvas->line_style); + canvas->cxLineWidth(ctxcanvas, canvas->line_width); + canvas->cxLineCap(ctxcanvas, canvas->line_cap); + canvas->cxLineJoin(ctxcanvas, canvas->line_join); + canvas->cxHatch(ctxcanvas, canvas->hatch_style); + if (canvas->stipple) canvas->cxStipple(ctxcanvas, canvas->stipple_w, canvas->stipple_h, canvas->stipple); + if (canvas->pattern) canvas->cxPattern(ctxcanvas, canvas->pattern_w, canvas->pattern_h, canvas->pattern); + canvas->cxInteriorStyle(ctxcanvas, canvas->interior_style); + if (canvas->native_font[0] == 0) canvas->cxFont(ctxcanvas, canvas->font_type_face, canvas->font_style, canvas->font_size); + else canvas->cxNativeFont(ctxcanvas, canvas->native_font); +/* canvas->cxTextAlignment(ctxcanvas, canvas->text_alignment); */ +/* canvas->cxTextOrientation(ctxcanvas, canvas->text_orientation); */ + if (canvas->clip_mode == CD_CLIPAREA && canvas->cxClipArea) canvas->cxClipArea(ctxcanvas, canvas->clip_rect.xmin, canvas->clip_rect.xmax, canvas->clip_rect.ymin, canvas->clip_rect.ymax); +/* if (canvas->clip_mode == CD_CLIPAREA && canvas->cxFClipArea) canvas->cxFClipArea(ctxcanvas, canvas->clip_frect.xmin, canvas->clip_frect.xmax, canvas->clip_frect.ymin, canvas->clip_frect.ymax); */ + if (canvas->clip_mode == CD_CLIPPOLYGON && canvas->clip_poly) canvas->cxPoly(ctxcanvas, CD_CLIP, canvas->clip_poly, canvas->clip_poly_n); +/* if (canvas->clip_mode == CD_CLIPPOLYGON && canvas->clip_fpoly) canvas->cxFPoly(ctxcanvas, CD_CLIP, canvas->clip_fpoly, canvas->clip_poly_n); */ + if (canvas->clip_mode != CD_CLIPOFF) canvas->cxClip(ctxcanvas, canvas->clip_mode); + } + + return CD_OK; +} + +static void cdinittable(cdCanvas* canvas) +{ + cdcairoInitTable(canvas); + + canvas->cxActivate = cdactivate; + canvas->cxDeactivate = cddeactivate; + canvas->cxFlush = cdflush; + canvas->cxKillCanvas = cdkillcanvas; +} + +static cdContext cdDBufferContext = +{ + CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | + CD_CAP_FPRIMTIVES ), + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + +cdContext* cdContextCairoDBuffer(void) +{ + return &cdDBufferContext; +} diff --git a/src/cairo/cdcairoimg.c b/src/cairo/cdcairoimg.c new file mode 100644 index 0000000..54c2fa7 --- /dev/null +++ b/src/cairo/cdcairoimg.c @@ -0,0 +1,52 @@ +/** \file + * \brief Cairo Image Driver + * + * See Copyright Notice in cd.h + */ + +#include + +#include "cdcairoctx.h" +#include "cdimage.h" + + +static void cdkillcanvas(cdCtxCanvas* ctxcanvas) +{ + cdcairoKillCanvas(ctxcanvas); +} + +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + cdCtxImage *ctximage = ((cdImage*)data)->ctximage; + cdcairoCreateCanvas(canvas, (cairo_t*)ctximage->img); + canvas->w = ctximage->w; + canvas->h = ctximage->h; + canvas->w_mm = ctximage->w_mm; + canvas->h_mm = ctximage->h_mm; + canvas->bpp = ctximage->bpp; + canvas->xres = ctximage->xres; + canvas->yres = ctximage->yres; +} + +static void cdinittable(cdCanvas* canvas) +{ + cdcairoInitTable(canvas); + + canvas->cxKillCanvas = cdkillcanvas; +} + +static cdContext cdImageContext = +{ + CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | CD_CAP_FPRIMTIVES ), + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL +}; + + +cdContext* cdContextCairoImage(void) +{ + return &cdImageContext; +} diff --git a/src/cairo/cdcairoirgb.c b/src/cairo/cdcairoirgb.c new file mode 100644 index 0000000..1bb9698 --- /dev/null +++ b/src/cairo/cdcairoirgb.c @@ -0,0 +1,159 @@ +/** \file + * \brief Cairo IMAGERGB Driver + * + * See Copyright Notice in cd.h + */ + +#include +#include +#include + +#include "cd.h" +#include "cdcairo.h" +#include "cdcairoctx.h" + + +static char* get_stride_attrib(cdCtxCanvas* ctxcanvas) +{ + static char data[100]; + sprintf(data, "%d", cairo_image_surface_get_stride(cairo_get_target(ctxcanvas->cr))); + return data; +} + +static cdAttribute stride_attrib = +{ + "STRIDE", + NULL, + get_stride_attrib +}; + +static void set_write2png_attrib(cdCtxCanvas *ctxcanvas, char* data) +{ + if (data) + cairo_surface_write_to_png(cairo_get_target(ctxcanvas->cr), data); +} + +static cdAttribute write2png_attrib = +{ + "WRITE2PNG", + set_write2png_attrib, + NULL +}; + +static char* get_data_attrib(cdCtxCanvas* ctxcanvas) +{ + return (char*)ctxcanvas->rgb; +} + +static cdAttribute data_attrib = +{ + "RGBDATA", + NULL, + get_data_attrib +}; + +static void cdkillcanvas (cdCtxCanvas *ctxcanvas) +{ + if (!ctxcanvas->user_image) + free(ctxcanvas->rgb); + + cdcairoKillCanvas(ctxcanvas); +} + +static void cdcreatecanvas(cdCanvas* canvas, void* data) +{ + cdCtxCanvas* ctxcanvas; + cairo_surface_t *surface; + int w = 0, h = 0, use_alpha = 0; + float res = (float)3.78; + unsigned char *rgb = NULL; + char* str_data = (char*)data; + char* res_ptr = NULL; + cairo_format_t format = CAIRO_FORMAT_RGB24; + + /* Starting parameters */ + if (str_data == NULL) + return; + + if (strstr(str_data, "-a")) + use_alpha = 1; + + res_ptr = strstr(str_data, "-r"); + if (res_ptr) + sscanf(res_ptr+2, "%g", &res); + + /* size and rgb */ +#ifdef SunOS_OLD + sscanf(str_data, "%dx%d %d", &w, &h, &rgb); +#else + sscanf(str_data, "%dx%d %p", &w, &h, &rgb); +#endif + + if (w == 0 || h == 0) + return; + + canvas->w = w; + canvas->h = h; + canvas->yres = res; + canvas->xres = res; + canvas->w_mm = ((double)w) / res; + canvas->h_mm = ((double)h) / res; + if (use_alpha) + { + canvas->bpp = 32; + format = CAIRO_FORMAT_ARGB32; + } + else + canvas->bpp = 24; /* fake value, image bpp is always 32 */ + + if (rgb) + surface = cairo_image_surface_create_for_data(rgb, format, w, h, w*32); + else + surface = cairo_image_surface_create(format, canvas->w, canvas->h); + + /* Starting Cairo driver */ + ctxcanvas = cdcairoCreateCanvas(canvas, cairo_create(surface)); + cairo_surface_destroy(surface); + + if (rgb) + { + ctxcanvas->user_image = 1; + ctxcanvas->rgb = rgb; + } + else + { + ctxcanvas->user_image = 0; + ctxcanvas->rgb = cairo_image_surface_get_data(cairo_get_target(ctxcanvas->cr)); + + /* fill with white */ + /* transparent, this is the normal alpha coding */ + cairo_set_source_rgba(ctxcanvas->cr, 1.0, 1.0, 1.0, 0.0); + cairo_rectangle(ctxcanvas->cr, 0, 0, canvas->w, canvas->h); + cairo_fill(ctxcanvas->cr); + } + + cdRegisterAttribute(canvas, &stride_attrib); + cdRegisterAttribute(canvas, &write2png_attrib); + cdRegisterAttribute(canvas, &data_attrib); +} + +static void cdinittable(cdCanvas* canvas) +{ + cdcairoInitTable(canvas); + canvas->cxKillCanvas = cdkillcanvas; +} + +static cdContext cdCairoImageRGBContext = +{ + CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | CD_CAP_REGION | CD_CAP_FPRIMTIVES), + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL +}; + +cdContext* cdContextCairoImageRGB(void) +{ + return &cdCairoImageRGBContext; +} diff --git a/src/cairo/cdcaironative_gdk.c b/src/cairo/cdcaironative_gdk.c new file mode 100644 index 0000000..98face0 --- /dev/null +++ b/src/cairo/cdcaironative_gdk.c @@ -0,0 +1,80 @@ +/** \file +* \brief Cairo Native Window Driver +* +* See Copyright Notice in cd.h +*/ + +#include +#include + +#include + +#include "cdcairoctx.h" +#include "cdnative.h" + + +static void cdkillcanvas(cdCtxCanvas *ctxcanvas) +{ + cdcairoKillCanvas(ctxcanvas); +} + +int cdactivate(cdCtxCanvas *ctxcanvas) +{ + gdk_drawable_get_size(ctxcanvas->drawable, &ctxcanvas->canvas->w, &ctxcanvas->canvas->h); + + ctxcanvas->canvas->w_mm = ((double)ctxcanvas->canvas->w) / ctxcanvas->canvas->xres; + ctxcanvas->canvas->h_mm = ((double)ctxcanvas->canvas->h) / ctxcanvas->canvas->yres; + + return CD_OK; +} + +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + cdCtxCanvas *ctxcanvas; + cairo_t* cr; + GdkScreen* screen; + GdkDrawable* drawable = (GdkDrawable*)data; + + cr = gdk_cairo_create(drawable); + if (!cr) + return; + + screen = gdk_drawable_get_screen(drawable); + canvas->bpp = gdk_drawable_get_depth(drawable); + canvas->xres = ((double)gdk_screen_get_width(screen) / (double)gdk_screen_get_width_mm(screen)); + canvas->yres = ((double)gdk_screen_get_height(screen) / (double)gdk_screen_get_height_mm(screen)); + gdk_drawable_get_size(drawable, &canvas->w, &canvas->h); + + canvas->w_mm = ((double)canvas->w) / canvas->xres; + canvas->h_mm = ((double)canvas->h) / canvas->yres; + + ctxcanvas = cdcairoCreateCanvas(canvas, cr); + + ctxcanvas->drawable = drawable; +} + +static void cdinittable(cdCanvas* canvas) +{ + cdcairoInitTable(canvas); + + canvas->cxKillCanvas = cdkillcanvas; + canvas->cxActivate = cdactivate; +} + +/******************************************************/ + +static cdContext cdNativeWindowContext = +{ + CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | CD_CAP_REGION | CD_CAP_WRITEMODE | CD_CAP_PALETTE | CD_CAP_FPRIMTIVES), + 1, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + + +cdContext* cdContextCairoNativeWindow(void) +{ + return &cdNativeWindowContext; +} diff --git a/src/cairo/cdcaironative_win32.c b/src/cairo/cdcaironative_win32.c new file mode 100644 index 0000000..b685d12 --- /dev/null +++ b/src/cairo/cdcaironative_win32.c @@ -0,0 +1,160 @@ +/** \file +* \brief Cairo Native Window Driver +* +* See Copyright Notice in cd.h +*/ + +#include +#include + +#include "cdcairoctx.h" +#include "cdnative.h" + +#include +#include + + +static void cdkillcanvas(cdCtxCanvas *ctxcanvas) +{ + if (ctxcanvas->hDC) + ReleaseDC(ctxcanvas->hWnd, ctxcanvas->hDC); + + cdcairoKillCanvas(ctxcanvas); +} + +int cdactivate(cdCtxCanvas *ctxcanvas) +{ + if (ctxcanvas->hWnd) + { + RECT rect; + GetClientRect(ctxcanvas->hWnd, &rect); + ctxcanvas->canvas->w = rect.right - rect.left; + ctxcanvas->canvas->h = rect.bottom - rect.top; + + ctxcanvas->canvas->bpp = cdGetScreenColorPlanes(); + } + + /* Se nao e' ownwer, tem que restaurar o contexto */ + if (!ctxcanvas->isOwnedDC) + { + cairo_surface_t *surface; + + if (ctxcanvas->hDC) /* deactivate not called */ + { + cairo_destroy(ctxcanvas->cr); + ReleaseDC(ctxcanvas->hWnd, ctxcanvas->hDC); + } + + ctxcanvas->hDC = GetDC(ctxcanvas->hWnd); + surface = cairo_win32_surface_create(ctxcanvas->hDC); + ctxcanvas->cr = cairo_create(surface); + cairo_surface_destroy(surface); + } + + ctxcanvas->canvas->w_mm = ((double)ctxcanvas->canvas->w) / ctxcanvas->canvas->xres; + ctxcanvas->canvas->h_mm = ((double)ctxcanvas->canvas->h) / ctxcanvas->canvas->yres; + + if (ctxcanvas->canvas->use_matrix) + ctxcanvas->canvas->cxTransform(ctxcanvas, ctxcanvas->canvas->matrix); + + return CD_OK; +} + +static void cddeactivate(cdCtxCanvas *ctxcanvas) +{ + /* If not owner, release the DC */ + if (!ctxcanvas->isOwnedDC && ctxcanvas->hDC) + { + cairo_destroy(ctxcanvas->cr); + ReleaseDC(ctxcanvas->hWnd, ctxcanvas->hDC); + ctxcanvas->cr = NULL; + ctxcanvas->hDC = NULL; + } +} + +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + cdCtxCanvas* ctxcanvas; + cairo_surface_t *surface; + + HWND hWnd = (HWND)data; + HDC ScreenDC, hDC; + HRGN clip_hrgn; + + ScreenDC = GetDC(NULL); + canvas->bpp = GetDeviceCaps(ScreenDC, BITSPIXEL); + canvas->xres = (float)(((double)GetDeviceCaps(ScreenDC, LOGPIXELSX)) / 25.4); + canvas->yres = (float)(((double)GetDeviceCaps(ScreenDC, LOGPIXELSY)) / 25.4); + ReleaseDC(NULL, ScreenDC); + + if (!data) + { + hDC = GetDC(NULL); + canvas->w = GetDeviceCaps(hDC, HORZRES); + canvas->h = GetDeviceCaps(hDC, VERTRES); + } + else + { + RECT rect; + hWnd = (HWND)data; + + hDC = GetDC(hWnd); + + GetClientRect(hWnd, &rect); + canvas->w = rect.right - rect.left; + canvas->h = rect.bottom - rect.top; + } + + /* initial clip extents controls size */ + clip_hrgn = CreateRectRgn(0, 0, canvas->w, canvas->h); + SelectClipRgn(hDC, clip_hrgn); + DeleteObject(clip_hrgn); + + surface = cairo_win32_surface_create(hDC); + + canvas->w_mm = ((double)canvas->w) / canvas->xres; + canvas->h_mm = ((double)canvas->h) / canvas->yres; + + ctxcanvas = cdcairoCreateCanvas(canvas, cairo_create(surface)); + cairo_surface_destroy(surface); + + ctxcanvas->hDC = hDC; + ctxcanvas->hWnd = hWnd; + + if (hWnd) + { + LONG style = GetClassLong(hWnd, GCL_STYLE); + ctxcanvas->isOwnedDC = (int) ((style & CS_OWNDC) || (style & CS_CLASSDC)); + } + else + ctxcanvas->isOwnedDC = 1; +} + +static void cdinittable(cdCanvas* canvas) +{ + cdcairoInitTable(canvas); + + canvas->cxKillCanvas = cdkillcanvas; + canvas->cxActivate = cdactivate; + canvas->cxDeactivate = cddeactivate; +} + +/******************************************************/ + +static cdContext cdNativeWindowContext = +{ + CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | CD_CAP_REGION | CD_CAP_WRITEMODE | CD_CAP_PALETTE | CD_CAP_FPRIMTIVES), + 1, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + + +cdContext* cdContextCairoNativeWindow(void) +{ + return &cdNativeWindowContext; +} + +// cairo_win32_printing_surface_create CD_PRINTER diff --git a/src/cairo/cdcaironative_x11.c b/src/cairo/cdcaironative_x11.c new file mode 100644 index 0000000..027de4e --- /dev/null +++ b/src/cairo/cdcaironative_x11.c @@ -0,0 +1,98 @@ +/** \file +* \brief Cairo Native Window Driver +* +* See Copyright Notice in cd.h +*/ + +#include +#include + +#include "cdcairoctx.h" +#include "cdnative.h" + +#include +#include +#include + + +static void cdkillcanvas(cdCtxCanvas *ctxcanvas) +{ + cdcairoKillCanvas(ctxcanvas); +} + +int cdactivate(cdCtxCanvas *ctxcanvas) +{ + Window root; + int x, y; + unsigned int bw, d; + XGetGeometry(ctxcanvas->dpy, ctxcanvas->wnd, &root, &x, &y, + (unsigned int*)&ctxcanvas->canvas->w, (unsigned int*)&ctxcanvas->canvas->h, &bw, &d); + + ctxcanvas->canvas->w_mm = ((double)ctxcanvas->canvas->w) / ctxcanvas->canvas->xres; + ctxcanvas->canvas->h_mm = ((double)ctxcanvas->canvas->h) / ctxcanvas->canvas->yres; + + return CD_OK; +} + +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + cdCtxCanvas* ctxcanvas; + cairo_surface_t *surface; + char* data_str = (char*)data; + Window wnd, root; + Display *dpy; + XWindowAttributes wa; + int x, y; + unsigned int bw; + +#ifdef SunOS_OLD + sscanf(data_str, "%d %lu", &dpy, &wnd); +#else + sscanf(data_str, "%p %lu", &dpy, &wnd); +#endif + if (!dpy || !wnd) + return; + + XGetWindowAttributes(dpy, wnd, &wa); + + XGetGeometry(dpy, wnd, &root, &x, &y, (unsigned int*)&canvas->w, (unsigned int*)&canvas->h, &bw, (unsigned int*)&canvas->bpp); + canvas->xres = ((double)DisplayWidth(dpy, XScreenNumberOfScreen(wa.screen)) / (double)DisplayWidthMM(dpy, XScreenNumberOfScreen(wa.screen))); + canvas->yres = ((double)DisplayHeight(dpy, XScreenNumberOfScreen(wa.screen)) / (double)DisplayHeightMM(dpy, XScreenNumberOfScreen(wa.screen))); + + surface = cairo_xlib_surface_create(dpy, wnd, wa.visual, canvas->w, canvas->h); + + canvas->w_mm = ((double)canvas->w) / canvas->xres; + canvas->h_mm = ((double)canvas->h) / canvas->yres; + + ctxcanvas = cdcairoCreateCanvas(canvas, cairo_create(surface)); + cairo_surface_destroy(surface); + + ctxcanvas->dpy = dpy; + ctxcanvas->wnd = wnd; +} + +static void cdinittable(cdCanvas* canvas) +{ + cdcairoInitTable(canvas); + + canvas->cxKillCanvas = cdkillcanvas; + canvas->cxActivate = cdactivate; +} + +/******************************************************/ + +static cdContext cdNativeWindowContext = +{ + CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | CD_CAP_REGION | CD_CAP_WRITEMODE | CD_CAP_PALETTE | CD_CAP_FPRIMTIVES), + 1, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + + +cdContext* cdContextCairoNativeWindow(void) +{ + return &cdNativeWindowContext; +} diff --git a/src/cairo/cdcairopdf.c b/src/cairo/cdcairopdf.c new file mode 100644 index 0000000..880a2e5 --- /dev/null +++ b/src/cairo/cdcairopdf.c @@ -0,0 +1,122 @@ +/** \file + * \brief Cairo PDF Driver + * + * See Copyright Notice in cd.h + */ + +#include +#include + +#include "cd.h" +#include "cdcairo.h" +#include "cdcairoctx.h" + +#include + + +static void cdkillcanvas (cdCtxCanvas *ctxcanvas) +{ + cdcairoKillCanvas(ctxcanvas); +} + +static void cdcreatecanvas(cdCanvas* canvas, void* data) +{ + cdCtxCanvas* ctxcanvas; + char* strdata = (char*)data; + char filename[10240] = ""; + cairo_surface_t *surface; + int res = 300; + double w_pt; /* Largura do papel (points) */ + double h_pt; /* Altura do papel (points) */ + double scale; /* Fator de conversao de coordenadas (pixel2points) */ + int landscape = 0; /* page orientation */ + + /* Starting parameters */ + if (strdata == NULL) + return; + + strdata += cdGetFileName(strdata, filename); + if (filename[0] == 0) + return; + + cdSetPaperSize(CD_A4, &w_pt, &h_pt); + + while (*strdata != '\0') + { + while (*strdata != '\0' && *strdata != '-') + strdata++; + + if (*strdata != '\0') + { + float num; + strdata++; + switch (*strdata++) + { + case 'p': + { + int paper; + sscanf(strdata, "%d", &paper); + cdSetPaperSize(paper, &w_pt, &h_pt); + break; + } + case 'w': + sscanf(strdata, "%g", &num); + w_pt = CD_MM2PT*num; + break; + case 'h': + sscanf(strdata, "%g", &num); + h_pt = CD_MM2PT*num; + break; + case 'o': + landscape = 1; + break; + case 's': + sscanf(strdata, "%d", &res); + break; + } + } + + while (*strdata != '\0' && *strdata != ' ') + strdata++; + } + + if (landscape) + _cdSwapDouble(w_pt, h_pt); + + scale = 72.0/res; + + canvas->w = (int)(w_pt/scale + 0.5); /* Converte p/ unidades do usuario */ + canvas->h = (int)(h_pt/scale + 0.5); /* Converte p/ unidades do usuario */ + canvas->w_mm = w_pt/CD_MM2PT; /* Converte p/ milimetros */ + canvas->h_mm = h_pt/CD_MM2PT; /* Converte p/ milimetros */ + canvas->bpp = 24; + canvas->xres = canvas->w / canvas->w_mm; + canvas->yres = canvas->h / canvas->h_mm; + + surface = cairo_pdf_surface_create(filename, w_pt, h_pt); + + /* Starting Cairo driver */ + ctxcanvas = cdcairoCreateCanvas(canvas, cairo_create(surface)); + cairo_surface_destroy(surface); +} + +static void cdinittable(cdCanvas* canvas) +{ + cdcairoInitTable(canvas); + canvas->cxKillCanvas = cdkillcanvas; +} + +static cdContext cdCairoPDFContext = +{ + CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | CD_CAP_REGION | CD_CAP_FPRIMTIVES), + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL +}; + +cdContext* cdContextCairoPDF(void) +{ + return &cdCairoPDFContext; +} diff --git a/src/cairo/cdcairoplus.c b/src/cairo/cdcairoplus.c new file mode 100644 index 0000000..c50f1ec --- /dev/null +++ b/src/cairo/cdcairoplus.c @@ -0,0 +1,26 @@ +/** \file + * \brief Cairo as Context Plus + * + * See Copyright Notice in cd.h + */ + +#include "cd.h" +#include "cd_private.h" +#include "cdcairo.h" +#include +#include + +void cdInitContextPlus(void) +{ + cdContext* ctx_list[NUM_CONTEXTPLUS]; + memset(ctx_list, 0, sizeof(ctx_list)); + + ctx_list[CD_CTX_NATIVEWINDOW] = cdContextCairoNativeWindow(); + ctx_list[CD_CTX_IMAGE] = cdContextCairoImage(); + ctx_list[CD_CTX_DBUFFER] = cdContextCairoDBuffer(); +#ifdef WIN32 +// ctx_list[CD_CTX_PRINTER] = cdContextCairoPrinter(); +#endif + + cdInitContextPlusList(ctx_list); +} diff --git a/src/cairo/cdcairops.c b/src/cairo/cdcairops.c new file mode 100644 index 0000000..ed58723 --- /dev/null +++ b/src/cairo/cdcairops.c @@ -0,0 +1,170 @@ +/** \file + * \brief Cairo PS Driver + * + * See Copyright Notice in cd.h + */ + +#include +#include + +#include "cd.h" +#include "cdps.h" +#include "cdcairo.h" +#include "cdcairoctx.h" + +#include + + +static void set_comment_attrib(cdCtxCanvas *ctxcanvas, char* data) +{ + if (data) + cairo_ps_surface_dsc_comment(cairo_get_target(ctxcanvas->cr), data); +} + +static cdAttribute comment_attrib = +{ + "DSCCOMMENT", + set_comment_attrib, + NULL +}; + +static void cdkillcanvas (cdCtxCanvas *ctxcanvas) +{ + cdcairoKillCanvas(ctxcanvas); +} + +static void cdflush(cdCtxCanvas *ctxcanvas) +{ + if (!ctxcanvas->eps) + cairo_show_page(ctxcanvas->cr); +} + +static void cdcreatecanvas(cdCanvas* canvas, void* data) +{ + cdCtxCanvas *ctxcanvas; + char* strdata = (char*)data; + char filename[10240] = ""; + cairo_surface_t *surface; + int res = 300; + double w_pt; /* Largura do papel (points) */ + double h_pt; /* Altura do papel (points) */ + double scale; /* Fator de conversao de coordenadas (pixel2points) */ + int eps = 0; /* Postscrip encapsulado? */ + int level = 0; + int landscape = 0; /* page orientation */ + + /* Starting parameters */ + if (strdata == NULL) + return; + + strdata += cdGetFileName(strdata, filename); + if (filename[0] == 0) + return; + + cdSetPaperSize(CD_A4, &w_pt, &h_pt); + + while (*strdata != '\0') + { + while (*strdata != '\0' && *strdata != '-') + strdata++; + + if (*strdata != '\0') + { + float num; + strdata++; + switch (*strdata++) + { + case 'p': + { + int paper; + sscanf(strdata, "%d", &paper); + cdSetPaperSize(paper, &w_pt, &h_pt); + break; + } + case 'w': + sscanf(strdata, "%g", &num); + w_pt = CD_MM2PT*num; + break; + case 'h': + sscanf(strdata, "%g", &num); + h_pt = CD_MM2PT*num; + break; + case 'e': + eps = 1; + break; + case 'o': + landscape = 1; + break; + case '2': + level = 2; + break; + case '3': + level = 3; + break; + case 's': + sscanf(strdata, "%d", &res); + break; + } + } + + while (*strdata != '\0' && *strdata != ' ') + strdata++; + } + + if (landscape) + _cdSwapDouble(w_pt, h_pt); + + scale = 72.0/res; + + canvas->w = (int)(w_pt/scale + 0.5); /* Converte p/ unidades do usuario */ + canvas->h = (int)(h_pt/scale + 0.5); /* Converte p/ unidades do usuario */ + canvas->w_mm = w_pt/CD_MM2PT; /* Converte p/ milimetros */ + canvas->h_mm = h_pt/CD_MM2PT; /* Converte p/ milimetros */ + canvas->bpp = 24; + canvas->xres = canvas->w / canvas->w_mm; + canvas->yres = canvas->h / canvas->h_mm; + + surface = cairo_ps_surface_create(filename, w_pt, h_pt); + + if (level == 2) + cairo_ps_surface_restrict_to_level(surface, CAIRO_PS_LEVEL_2); + else if (level == 3) + cairo_ps_surface_restrict_to_level(surface, CAIRO_PS_LEVEL_3); + + if (eps) + cairo_ps_surface_set_eps(surface, 1); + + cairo_ps_surface_dsc_comment(surface, "%%Title: CanvasDraw"); + cairo_ps_surface_dsc_begin_setup (surface); + cairo_ps_surface_dsc_begin_page_setup (surface); + + ctxcanvas = cdcairoCreateCanvas(canvas, cairo_create(surface)); + ctxcanvas->eps = eps; + + cairo_surface_destroy(surface); + + cdRegisterAttribute(canvas, &comment_attrib); +} + +static void cdinittable(cdCanvas* canvas) +{ + cdcairoInitTable(canvas); + canvas->cxKillCanvas = cdkillcanvas; + canvas->cxFlush = cdflush; +} + +static cdContext cdCairoPSContext = +{ + CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | CD_CAP_REGION | CD_CAP_FPRIMTIVES), + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL +}; + +cdContext* cdContextCairoPS(void) +{ + return &cdCairoPSContext; +} + diff --git a/src/cairo/cdcairosvg.c b/src/cairo/cdcairosvg.c new file mode 100644 index 0000000..ce36758 --- /dev/null +++ b/src/cairo/cdcairosvg.c @@ -0,0 +1,81 @@ +/** \file + * \brief Cairo SVG Driver + * + * See Copyright Notice in cd.h + */ + +#include +#include + +#include "cd.h" +#include "cdcairo.h" +#include "cdcairoctx.h" + +#include + + +static void cdflush(cdCtxCanvas *ctxcanvas) +{ + (void)ctxcanvas; /* Nothing to do */ +} + +static void cdkillcanvas (cdCtxCanvas *ctxcanvas) +{ + cdcairoKillCanvas(ctxcanvas); +} + +static void cdcreatecanvas(cdCanvas* canvas, void* data) +{ + cdCtxCanvas* ctxcanvas; + char* strdata = (char*)data; + char filename[10240] = ""; + double w_mm = INT_MAX*3.78, h_mm = INT_MAX*3.78, res = 3.78; + cairo_surface_t *surface; + + /* Starting parameters */ + if (strdata == NULL) + return; + + strdata += cdGetFileName(strdata, filename); + if (filename[0] == 0) + return; + + sscanf(strdata, "%lgx%lg %lg", &w_mm, &h_mm, &res); + + /* update canvas context */ + canvas->w = (int)(w_mm * res); + canvas->h = (int)(h_mm * res); + canvas->w_mm = w_mm; + canvas->h_mm = h_mm; + canvas->bpp = 24; + canvas->xres = res; + canvas->yres = res; + + surface = cairo_svg_surface_create(filename, CD_MM2PT*w_mm, CD_MM2PT*h_mm); + + /* Starting Cairo driver */ + ctxcanvas = cdcairoCreateCanvas(canvas, cairo_create(surface)); + cairo_surface_destroy(surface); +} + +static void cdinittable(cdCanvas* canvas) +{ + cdcairoInitTable(canvas); + canvas->cxKillCanvas = cdkillcanvas; + canvas->cxFlush = cdflush; +} + +static cdContext cdCairoSVGContext = +{ + CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | CD_CAP_REGION | CD_CAP_FPRIMTIVES), + 0, + cdcreatecanvas, + cdinittable, + NULL, + NULL +}; + +cdContext* cdContextCairoSVG(void) +{ + return &cdCairoSVGContext; +} diff --git a/src/cd.c b/src/cd.c index 6435d0a..1843a27 100644 --- a/src/cd.c +++ b/src/cd.c @@ -20,6 +20,7 @@ /* This appears only here to avoid changing the cd.h header fo bug fixes */ #define CD_VERSION_FIX "" #define CD_VERSION_FIX_NUMBER 0 +/* #define CD_VERSION_FIX_DATE "" */ const char cd_ident[] = "$CD: " CD_VERSION CD_VERSION_FIX " " CD_COPYRIGHT " $\n" @@ -36,7 +37,11 @@ char* cdVersion(void) char* cdVersionDate(void) { +#ifdef CD_VERSION_FIX_DATE + return CD_VERSION_FIX_DATE; +#else return CD_VERSION_DATE; +#endif } int cdVersionNumber(void) @@ -716,14 +721,13 @@ static cdContext* context_plus[NUM_CONTEXTPLUS] = {NULL, NULL, NULL, NULL, NULL, int cdUseContextPlus(int use) { + int old_use_context_plus = use_context_plus; + if (use == CD_QUERY) return use_context_plus; - { - int old_use_context_plus = use_context_plus; - use_context_plus = use; - return old_use_context_plus; - } + use_context_plus = use; + return old_use_context_plus; } void cdInitContextPlusList(cdContext* ctx_list[]) diff --git a/src/cd.def b/src/cd.def index c087d9d..f5ae417 100644 --- a/src/cd.def +++ b/src/cd.def @@ -219,6 +219,7 @@ EXPORTS cdGetFontSizePixels cdGetFontSizePoints cdStrEqualNoCase + cdSetPaperSize wdCanvasLineWidth wdCanvasMarkSize diff --git a/src/cd_text.c b/src/cd_text.c index 2568e25..32b0645 100644 --- a/src/cd_text.c +++ b/src/cd_text.c @@ -319,7 +319,7 @@ char* cdCanvasNativeFont(cdCanvas* canvas, const char* font) else { char type_face[1024]; - int size, style = CD_PLAIN; + int size = 12, style = CD_PLAIN; if (!cdParseIupWinFont(font, type_face, &style, &size)) { diff --git a/src/cd_util.c b/src/cd_util.c index 1767ac4..39d491d 100644 --- a/src/cd_util.c +++ b/src/cd_util.c @@ -263,6 +263,29 @@ void cdRotatePoint(cdCanvas* canvas, int x, int y, int cx, int cy, int *rx, int *ry = *ry + cy; } +void cdfRotatePoint(cdCanvas* canvas, double x, double y, double cx, double cy, double *rx, double *ry, double sin_theta, double cos_theta) +{ + /* translate to (cx,cy) */ + x = x - cx; + y = y - cy; + + /* rotate */ + if (canvas->invert_yaxis) + { + *rx = (x * cos_theta) + (y * sin_theta); + *ry = -(x * sin_theta) + (y * cos_theta); + } + else + { + *rx = (x * cos_theta) - (y * sin_theta); + *ry = (x * sin_theta) + (y * cos_theta); + } + + /* translate back */ + *rx = *rx + cx; + *ry = *ry + cy; +} + void cdRotatePointY(cdCanvas* canvas, int x, int y, int cx, int cy, int *ry, double sin_theta, double cos_theta) { double t; @@ -349,3 +372,28 @@ char* cdStrDupN(const char *str, int len) } return NULL; } + +void cdSetPaperSize(int size, double *w_pt, double *h_pt) +{ + static struct + { + int w_pt; + int h_pt; + } paper[] = + { + { 2393, 3391 }, /* A0 */ + { 1689, 2393 }, /* A1 */ + { 1192, 1689 }, /* A2 */ + { 842, 1192 }, /* A3 */ + { 595, 842 }, /* A4 */ + { 420, 595 }, /* A5 */ + { 612, 792 }, /* LETTER */ + { 612, 1008 } /* LEGAL */ + }; + + if (sizeCD_LEGAL) + return; + + *w_pt = (double)paper[size].w_pt; + *h_pt = (double)paper[size].h_pt; +} diff --git a/src/drv/cddebug.c b/src/drv/cddebug.c index 23d8446..0c5fd0d 100644 --- a/src/drv/cddebug.c +++ b/src/drv/cddebug.c @@ -68,7 +68,6 @@ struct _cdCtxCanvas { cdCanvas* canvas; - char* filename; FILE* file; int last_line_style; int last_fill_mode; @@ -601,7 +600,6 @@ static void cdgettextsize(cdCtxCanvas* ctxcanvas, const char *s, int len, int *w static void cdkillcanvas(cdCtxCanvas *ctxcanvas) { fprintf(ctxcanvas->file, "KillCanvas()\n"); - free(ctxcanvas->filename); fclose(ctxcanvas->file); memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); free(ctxcanvas); @@ -613,7 +611,6 @@ static void cdcreatecanvas(cdCanvas *canvas, void *data) char* strdata = (char*)data; double w_mm = INT_MAX*3.78, h_mm = INT_MAX*3.78, res = 3.78; cdCtxCanvas* ctxcanvas; - int size; strdata += cdGetFileName(strdata, filename); if (filename[0] == 0) @@ -631,10 +628,6 @@ static void cdcreatecanvas(cdCanvas *canvas, void *data) return; } - size = strlen(filename); - ctxcanvas->filename = malloc(size+1); - memcpy(ctxcanvas->filename, filename, size+1); - ctxcanvas->canvas = canvas; /* update canvas context */ diff --git a/src/drv/cdirgb.c b/src/drv/cdirgb.c index 8baef1e..8135fa1 100644 --- a/src/drv/cdirgb.c +++ b/src/drv/cdirgb.c @@ -1781,6 +1781,7 @@ static void set_rotate_attrib(cdCtxCanvas* ctxcanvas, char* data) { if (data) { + /* use this configuration when there is NO native tranformation support */ sscanf(data, "%g %d %d", &ctxcanvas->rotate_angle, &ctxcanvas->rotate_center_x, &ctxcanvas->rotate_center_y); diff --git a/src/drv/cdpdf.c b/src/drv/cdpdf.c index a5d91d4..6a20748 100644 --- a/src/drv/cdpdf.c +++ b/src/drv/cdpdf.c @@ -55,36 +55,6 @@ struct _cdCtxCanvas }; -/* -%F Ajusta o tamanho do papel em points. -*/ -static void setpdfpapersize(cdCtxCanvas* ctxcanvas, int size) -{ - static struct - { - int width; - int height; - } paper[] = - { - { 2393, 3391 }, /* A0 */ - { 1689, 2393 }, /* A1 */ - { 1192, 1689 }, /* A2 */ - { 842, 1192 }, /* A3 */ - { 595, 842 }, /* A4 */ - { 420, 595 }, /* A5 */ - { 612, 792 }, /* LETTER */ - { 612, 1008 } /* LEGAL */ - }; - - if (sizeCD_LEGAL) - return; - - ctxcanvas->width_pt = paper[size].width; - ctxcanvas->height_pt = paper[size].height; - ctxcanvas->width_mm = ctxcanvas->width_pt/CD_MM2PT; - ctxcanvas->height_mm = ctxcanvas->height_pt/CD_MM2PT; -} - /* %F Registra os valores default para impressao. */ @@ -93,7 +63,9 @@ static void setpdfdefaultvalues(cdCtxCanvas* ctxcanvas) int i; /* all the other values are set to 0 */ - setpdfpapersize(ctxcanvas, CD_A4); + cdSetPaperSize(CD_A4, &ctxcanvas->width_pt, &ctxcanvas->height_pt); + ctxcanvas->width_mm = ctxcanvas->width_pt/CD_MM2PT; + ctxcanvas->height_mm = ctxcanvas->height_pt/CD_MM2PT; ctxcanvas->res = 300; ctxcanvas->hatchboxsize = 8; ctxcanvas->opacity = 255; /* full opaque */ @@ -361,7 +333,7 @@ static void cdfarc(cdCtxCanvas *ctxcanvas, double xc, double yc, double w, doubl PDF_arc(ctxcanvas->pdf, xc, yc, 0.5*w, a1, a2); PDF_stroke(ctxcanvas->pdf); } - else /* Elipse: mudar a escala p/ criar a partir do circulo */ + else /* Ellipse: change the scale to create from the circle */ { PDF_save(ctxcanvas->pdf); /* save to use the local transform */ @@ -487,8 +459,8 @@ static void cdftext(cdCtxCanvas *ctxcanvas, double x, double y, const char *s, i char temp[200], options[200]; PDF_setcolor(ctxcanvas->pdf, "fill", "rgb", get_red(ctxcanvas->canvas->foreground), - get_green(ctxcanvas->canvas->foreground), - get_blue(ctxcanvas->canvas->foreground), 0); + get_green(ctxcanvas->canvas->foreground), + get_blue(ctxcanvas->canvas->foreground), 0); strcpy(options, ""); @@ -768,7 +740,6 @@ static void make_pattern(cdCtxCanvas *ctxcanvas, int n, int m, void* data, int ( PDF_suspend_page(ctxcanvas->pdf, ""); ctxcanvas->pattern = PDF_begin_pattern(ctxcanvas->pdf, n, m, ((double)n)*ctxcanvas->scale, ((double)m)*ctxcanvas->scale, 1); - PDF_scale(ctxcanvas->pdf, ctxcanvas->scale, ctxcanvas->scale); for (j=0; jcanvas->foreground, r, g, b); - ret = 1; - } else { - cdDecodeColor(ctxcanvas->canvas->background, r, g, b); if (ctxcanvas->canvas->back_opacity==CD_TRANSPARENT) - ret = -1; + return -1; + else + cdDecodeColor(ctxcanvas->canvas->background, r, g, b); } - return ret; + return 1; } static void cdstipple(cdCtxCanvas *ctxcanvas, int n, int m, const unsigned char *stipple) @@ -824,14 +792,14 @@ static void cdstipple(cdCtxCanvas *ctxcanvas, int n, int m, const unsigned char make_pattern(ctxcanvas, n, m, (void*)stipple, uchar2rgb); } -static void make_hatch(cdCtxCanvas *ctxcanvas, int style) +static int cdhatch(cdCtxCanvas *ctxcanvas, int style) { unsigned char r, g, b; int hsize = ctxcanvas->hatchboxsize - 1; int hhalf = hsize / 2; PDF_suspend_page(ctxcanvas->pdf, ""); - ctxcanvas->pattern = PDF_begin_pattern(ctxcanvas->pdf, hsize + 1, hsize + 1, + ctxcanvas->pattern = PDF_begin_pattern(ctxcanvas->pdf, hsize+1, hsize+1, ((double)hsize)*ctxcanvas->scale, ((double)hsize)*ctxcanvas->scale, 1); PDF_scale(ctxcanvas->pdf, ctxcanvas->scale, ctxcanvas->scale); @@ -883,11 +851,6 @@ static void make_hatch(cdCtxCanvas *ctxcanvas, int style) PDF_end_pattern(ctxcanvas->pdf); PDF_resume_page(ctxcanvas->pdf, ""); -} - -static int cdhatch(cdCtxCanvas *ctxcanvas, int style) -{ - make_hatch(ctxcanvas, style); return style; } @@ -976,6 +939,7 @@ static int cdfont(cdCtxCanvas *ctxcanvas, const char *type_face, int style, int static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix) { + /* reset to identity */ PDF_setmatrix(ctxcanvas->pdf, 1, 0, 0, 1, 0, 0); /* default coordinate system is in points, change it to pixels. */ @@ -1202,7 +1166,8 @@ static cdAttribute hatchboxsize_attrib = static void set_rotate_attrib(cdCtxCanvas *ctxcanvas, char* data) { - /* ignore ROTATE if transform is set */ + /* ignore ROTATE if transform is set, + because there is native support for transformations */ if (ctxcanvas->canvas->use_matrix) return; @@ -1219,15 +1184,7 @@ static void set_rotate_attrib(cdCtxCanvas *ctxcanvas, char* data) ctxcanvas->rotate_center_y = 0; } - PDF_setmatrix(ctxcanvas->pdf, 1, 0, 0, 1, 0, 0); - - if (ctxcanvas->rotate_angle) - { - /* rotation = translate to point + rotation + translate back */ - PDF_translate(ctxcanvas->pdf, ctxcanvas->rotate_center_x, ctxcanvas->rotate_center_y); - PDF_rotate(ctxcanvas->pdf, (double)ctxcanvas->rotate_angle); - PDF_translate(ctxcanvas->pdf, -ctxcanvas->rotate_center_x, -ctxcanvas->rotate_center_y); - } + cdtransform(ctxcanvas, NULL); } static char* get_rotate_attrib(cdCtxCanvas *ctxcanvas) @@ -1469,7 +1426,9 @@ static void cdcreatecanvas(cdCanvas* canvas, void *data) { int paper; sscanf(line, "%d", &paper); - setpdfpapersize(ctxcanvas, paper); + cdSetPaperSize(paper, &ctxcanvas->width_pt, &ctxcanvas->height_pt); + ctxcanvas->width_mm = ctxcanvas->width_pt/CD_MM2PT; + ctxcanvas->height_mm = ctxcanvas->height_pt/CD_MM2PT; break; } case 'w': @@ -1513,7 +1472,9 @@ static void cdcreatecanvas(cdCanvas* canvas, void *data) static void cdinittable(cdCanvas* canvas) { canvas->cxFlush = cdflush; + canvas->cxPixel = cdpixel; + canvas->cxLine = cdline; canvas->cxPoly = cdpoly; canvas->cxRect = cdrect; @@ -1522,6 +1483,7 @@ static void cdinittable(cdCanvas* canvas) canvas->cxSector = cdsector; canvas->cxChord = cdchord; canvas->cxText = cdtext; + canvas->cxFLine = cdfline; canvas->cxFPoly = cdfpoly; canvas->cxFRect = cdfrect; @@ -1530,6 +1492,7 @@ static void cdinittable(cdCanvas* canvas) canvas->cxFSector = cdfsector; canvas->cxFChord = cdfchord; canvas->cxFText = cdftext; + canvas->cxGetFontDim = cdgetfontdim; canvas->cxGetTextSize = cdgettextsize; canvas->cxPutImageRectRGB = cdputimagerectrgb; diff --git a/src/drv/cdps.c b/src/drv/cdps.c index ef77c4d..c54c95a 100644 --- a/src/drv/cdps.c +++ b/src/drv/cdps.c @@ -76,42 +76,13 @@ struct _cdCtxCanvas }; - -/* -%F Ajusta o tamanho do papel em points. -*/ -static void setpspapersize(cdCtxCanvas *ctxcanvas, int size) -{ - static struct - { - int width; - int height; - } paper[] = - { - { 2393, 3391 }, /* A0 */ - { 1689, 2393 }, /* A1 */ - { 1192, 1689 }, /* A2 */ - { 842, 1192 }, /* A3 */ - { 595, 842 }, /* A4 */ - { 420, 595 }, /* A5 */ - { 612, 792 }, /* LETTER */ - { 612, 1008 } /* LEGAL */ - }; - - if (sizeCD_LEGAL) - return; - - ctxcanvas->width = (double)paper[size].width; - ctxcanvas->height = (double)paper[size].height; -} - /* %F Registra os valores default para impressao. */ static void setpsdefaultvalues(cdCtxCanvas *ctxcanvas) { /* all the other values are set to 0 */ - setpspapersize(ctxcanvas, CD_A4); + cdSetPaperSize(CD_A4, &ctxcanvas->width, &ctxcanvas->height); ctxcanvas->xmin = 25.4; /* ainda em mm, sera' convertido para points na init_ps */ ctxcanvas->xmax = 25.4; ctxcanvas->ymin = 25.4; @@ -1379,6 +1350,7 @@ static int cdfont(cdCtxCanvas *ctxcanvas, const char *type_face, int style, int static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix) { + /* reset to identity */ set_default_matrix(ctxcanvas); if (matrix) @@ -1568,7 +1540,8 @@ static void cdpixel(cdCtxCanvas *ctxcanvas, int x, int y, long int color) static void set_rotate_attrib(cdCtxCanvas *ctxcanvas, char* data) { - /* ignore ROTATE if transform is set */ + /* ignore ROTATE if transform is set, + because there is native support for transformations */ if (ctxcanvas->canvas->use_matrix) return; @@ -1585,15 +1558,7 @@ static void set_rotate_attrib(cdCtxCanvas *ctxcanvas, char* data) ctxcanvas->rotate_center_y = 0; } - set_default_matrix(ctxcanvas); - - if (ctxcanvas->rotate_angle) - { - /* rotation = translate to point + rotation + translate back */ - fprintf(ctxcanvas->file, "%d %d translate\n", ctxcanvas->rotate_center_x, ctxcanvas->rotate_center_y); - fprintf(ctxcanvas->file, "%g rotate\n", (double)ctxcanvas->rotate_angle); - fprintf(ctxcanvas->file, "%d %d translate\n", -ctxcanvas->rotate_center_x, -ctxcanvas->rotate_center_y); - } + cdtransform(ctxcanvas, NULL); } static char* get_rotate_attrib(cdCtxCanvas *ctxcanvas) @@ -1715,7 +1680,7 @@ static void cdcreatecanvas(cdCanvas* canvas, void *data) { int paper; sscanf(line, "%d", &paper); - setpspapersize(ctxcanvas, paper); + cdSetPaperSize(paper, &ctxcanvas->width, &ctxcanvas->height); break; } case 'w': diff --git a/src/gdiplus/cdwinp.cpp b/src/gdiplus/cdwinp.cpp index 1cbed3c..aba6c1e 100644 --- a/src/gdiplus/cdwinp.cpp +++ b/src/gdiplus/cdwinp.cpp @@ -551,6 +551,7 @@ static int cdinteriorstyle(cdCtxCanvas* ctxcanvas, int style) delete ctxcanvas->fillBrush; ctxcanvas->fillBrush = new SolidBrush(ctxcanvas->fg); break; + /* the remaining styles must recreate the current brush */ case CD_HATCH: cdhatch(ctxcanvas, ctxcanvas->canvas->hatch_style); break; @@ -1173,6 +1174,10 @@ static void sRGB2Bitmap(Bitmap& image, int width, int height, const unsigned cha Rect rect(0,0,image.GetWidth(),image.GetHeight()); image.LockBits(&rect, ImageLockModeWrite, PixelFormat24bppRGB, &bitmapData); + /* ymin and xmax unused */ + (void)ymin; + (void)xmax; + int line_offset; for(int j = 0; j < rect.Height; j++) { @@ -1206,6 +1211,10 @@ static void sRGBA2Bitmap(Bitmap& image, int width, int height, const unsigned ch Rect rect(0,0,image.GetWidth(),image.GetHeight()); image.LockBits(&rect, ImageLockModeWrite, PixelFormat32bppARGB, &bitmapData); + /* ymin and xmax unused */ + (void)ymin; + (void)xmax; + int line_offset; for(int j = 0; j < rect.Height; j++) { @@ -1237,6 +1246,10 @@ static void sAlpha2Bitmap(Bitmap& image, int width, int height, const unsigned c Rect rect(0,0,image.GetWidth(),image.GetHeight()); image.LockBits(&rect, ImageLockModeWrite, PixelFormat32bppARGB, &bitmapData); + /* ymin and xmax unused */ + (void)ymin; + (void)xmax; + int line_offset; for(int j = 0; j < rect.Height; j++) { @@ -1279,6 +1292,10 @@ static void sMap2Bitmap(Bitmap& image, int width, int height, const unsigned cha Rect rect(0,0,image.GetWidth(),image.GetHeight()); image.LockBits(&rect, ImageLockModeWrite, PixelFormat24bppRGB, &bitmapData); + /* ymin and xmax unused */ + (void)ymin; + (void)xmax; + int line_offset; for(int j = 0; j < rect.Height; j++) { @@ -1337,7 +1354,7 @@ static void cdgetimagergb(cdCtxCanvas* ctxcanvas, unsigned char *red, unsigned c if (!transformMatrix.IsIdentity()) ctxcanvas->graphics->ResetTransform(); // reset to the identity. - if (ctxcanvas->canvas->invert_yaxis==0) // if 0, then the transform was reset + if (ctxcanvas->canvas->invert_yaxis==0) // if 0, invert because the transform was reset here y = _cdInvertYAxis(ctxcanvas->canvas, y); int yr = y - (h - 1); /* y starts at the bottom of the image */ @@ -1649,10 +1666,11 @@ static void cdgetimage(cdCtxCanvas* ctxcanvas, cdCtxImage *ctximage, int x, int if (!transformMatrix.IsIdentity()) ctxcanvas->graphics->ResetTransform(); // reset to the identity. - if (ctxcanvas->canvas->invert_yaxis==0) // if 0, then the transform was reset + if (ctxcanvas->canvas->invert_yaxis==0) // if 0, invert because the transform was reset here y = _cdInvertYAxis(ctxcanvas->canvas, y); - int yr = y - (ctximage->h - 1); /* y0 starts at the bottom of the image */ + /* y is the bottom-left of the image in CD, must be at upper-left */ + y -= ctximage->h-1; if (ctxcanvas->wtype == CDW_BMP) { @@ -1660,7 +1678,7 @@ static void cdgetimage(cdCtxCanvas* ctxcanvas, cdCtxImage *ctximage, int x, int imggraphics.DrawImage(ctxcanvas->bitmap, Rect(0, 0, ctximage->w,ctximage->h), - x, yr, ctximage->w, ctximage->h, UnitPixel, + x, y, ctximage->w, ctximage->h, UnitPixel, NULL, NULL, NULL); } else @@ -1670,7 +1688,7 @@ static void cdgetimage(cdCtxCanvas* ctxcanvas, cdCtxImage *ctximage, int x, int HDC hdc = ctxcanvas->graphics->GetHDC(); HDC img_hdc = imggraphics.GetHDC(); - BitBlt(img_hdc,0,0,ctximage->w,ctximage->h,hdc,x,yr,SRCCOPY); + BitBlt(img_hdc,0,0,ctximage->w,ctximage->h,hdc,x,y,SRCCOPY); imggraphics.ReleaseHDC(img_hdc); ctxcanvas->graphics->ReleaseHDC(hdc); @@ -1740,7 +1758,7 @@ static void cdscrollarea(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, i if (!transformMatrix.IsIdentity()) ctxcanvas->graphics->ResetTransform(); // reset to the identity. - if (ctxcanvas->canvas->invert_yaxis==0) // if 0, then the transform was reset + if (ctxcanvas->canvas->invert_yaxis==0) // if 0, invert because the transform was reset here { dy = -dy; ymin = _cdInvertYAxis(ctxcanvas->canvas, ymin); @@ -1992,7 +2010,8 @@ static cdAttribute linecap_attrib = static void set_rotate_attrib(cdCtxCanvas* ctxcanvas, char* data) { - /* ignore ROTATE if transform is set */ + /* ignore ROTATE if transform is set, + because there is native support for transformations */ if (ctxcanvas->canvas->use_matrix) return; @@ -2009,7 +2028,7 @@ static void set_rotate_attrib(cdCtxCanvas* ctxcanvas, char* data) ctxcanvas->rotate_center_y = 0; } - cdwpUpdateTransform(ctxcanvas); + cdtransform(ctxcanvas, NULL); } static char* get_rotate_attrib(cdCtxCanvas* ctxcanvas) diff --git a/src/gdk/cdgdk.c b/src/gdk/cdgdk.c index b0c8ea8..1eccaa8 100644 --- a/src/gdk/cdgdk.c +++ b/src/gdk/cdgdk.c @@ -12,8 +12,6 @@ #include "cdgdk.h" -#include - #define NUM_HATCHES 6 #define HATCH_WIDTH 8 #define HATCH_HEIGHT 8 @@ -52,7 +50,7 @@ static char* gdkStrToUTF8(const char *str, const char* charset, int length) return g_convert(str, length, "UTF-8", charset, NULL, NULL, NULL); } -char* cdgdkStrConvertToUTF8(cdCtxCanvas *ctxcanvas, const char* str, int length) /* From CD to GTK/GDK */ +char* cdgdkStrConvertToUTF8(cdCtxCanvas *ctxcanvas, const char* str, int length) /* From CD to GDK */ { const char *charset = NULL; @@ -562,28 +560,6 @@ static int cdfont(cdCtxCanvas *ctxcanvas, const char *typeface, int style, int s return 1; } -static int cdnativefont(cdCtxCanvas *ctxcanvas, const char* nativefont) -{ - int size = 12, style = CD_PLAIN; - char typeface[1024]; - - /* parse the old Windows format first */ - if (!cdParseIupWinFont(nativefont, typeface, &style, &size)) - if (!cdParseXWinFont(nativefont, typeface, &style, &size)) - if (!cdParsePangoFont(nativefont, typeface, &style, &size)) - return 0; - - if (!cdfont(ctxcanvas, typeface, style, size)) - return 0; - - /* update cdfont parameters */ - ctxcanvas->canvas->font_style = style; - ctxcanvas->canvas->font_size = size; - strcpy(ctxcanvas->canvas->font_type_face, typeface); - - return 1; -} - static void cdgetfontdim(cdCtxCanvas *ctxcanvas, int *max_width, int *height, int *ascent, int *descent) { PangoFontMetrics* metrics; @@ -1353,7 +1329,7 @@ static void cdputimagerectmap(cdCtxCanvas *ctxcanvas, int iw, int ih, const unsi rw = xmax-xmin+1; rh = ymax-ymin+1; - y -= (h - 1); /* GdkPixbuf origin is at top-left */ + y -= (h - 1); /* GdkPixbuf image origin is at top-left */ if (!cdCalcZoom(ctxcanvas->canvas->w, x, w, &ex, &ew, xmin, rw, &bx, &bw, 1)) return; @@ -1429,8 +1405,11 @@ static cdCtxImage *cdcreateimage (cdCtxCanvas *ctxcanvas, int w, int h) static void cdgetimage (cdCtxCanvas *ctxcanvas, cdCtxImage *ctximage, int x, int y) { + /* y is the bottom-left of the image in CD, must be at upper-left */ + y -= ctximage->h-1; + gdk_draw_drawable(ctximage->img, ctxcanvas->gc, - ctxcanvas->wnd, x, y - ctximage->h+1, 0, 0, + ctxcanvas->wnd, x, y, 0, 0, ctximage->w, ctximage->h); } @@ -1491,6 +1470,7 @@ static void set_rotate_attrib(cdCtxCanvas* ctxcanvas, char* data) { if (data) { + /* use this configuration when there is NO native tranformation support */ sscanf(data, "%g %d %d", &ctxcanvas->rotate_angle, &ctxcanvas->rotate_center_x, &ctxcanvas->rotate_center_y); @@ -1687,7 +1667,6 @@ void cdgdkInitTable(cdCanvas* canvas) canvas->cxStipple = cdstipple; canvas->cxPattern = cdpattern; canvas->cxFont = cdfont; - canvas->cxNativeFont = cdnativefont; canvas->cxGetFontDim = cdgetfontdim; canvas->cxGetTextSize = cdgettextsize; canvas->cxPalette = cdpalette; diff --git a/src/svg/cdsvg.c b/src/svg/cdsvg.c index 90e70d9..2441523 100644 --- a/src/svg/cdsvg.c +++ b/src/svg/cdsvg.c @@ -23,7 +23,6 @@ struct _cdCtxCanvas { cdCanvas* canvas; - char* filename; char bgColor[20]; char fgColor[20]; @@ -67,7 +66,6 @@ static void cdkillcanvas(cdCtxCanvas* ctxcanvas) fprintf(ctxcanvas->file, "\n"); /* close global container */ fprintf(ctxcanvas->file, "\n"); - free(ctxcanvas->filename); fclose(ctxcanvas->file); memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); @@ -564,31 +562,31 @@ static int cdhatch(cdCtxCanvas *ctxcanvas, int style) { case CD_HORIZONTAL: fprintf(ctxcanvas->file, "\n", - 0, hhalf, hsize, hhalf, ctxcanvas->fgColor, ctxcanvas->canvas->line_width, ctxcanvas->opacity); + 0, hhalf, hsize, hhalf, ctxcanvas->fgColor, ctxcanvas->opacity); break; case CD_VERTICAL: fprintf(ctxcanvas->file, "\n", - hhalf, 0, hhalf, hsize, ctxcanvas->fgColor, ctxcanvas->canvas->line_width, ctxcanvas->opacity); + hhalf, 0, hhalf, hsize, ctxcanvas->fgColor, ctxcanvas->opacity); break; case CD_BDIAGONAL: fprintf(ctxcanvas->file, "\n", - 0, hsize, hsize, 0, ctxcanvas->fgColor, ctxcanvas->canvas->line_width, ctxcanvas->opacity); + 0, hsize, hsize, 0, ctxcanvas->fgColor, ctxcanvas->opacity); break; case CD_FDIAGONAL: fprintf(ctxcanvas->file, "\n", - 0, 0, hsize, hsize, ctxcanvas->fgColor, ctxcanvas->canvas->line_width, ctxcanvas->opacity); + 0, 0, hsize, hsize, ctxcanvas->fgColor, ctxcanvas->opacity); break; case CD_CROSS: fprintf(ctxcanvas->file, "\n", - hsize, 0, hsize, hsize, ctxcanvas->fgColor, ctxcanvas->canvas->line_width, ctxcanvas->opacity); + hsize, 0, hsize, hsize, ctxcanvas->fgColor, ctxcanvas->opacity); fprintf(ctxcanvas->file, "\n", - 0, hhalf, hsize, hhalf, ctxcanvas->fgColor, ctxcanvas->canvas->line_width, ctxcanvas->opacity); + 0, hhalf, hsize, hhalf, ctxcanvas->fgColor, ctxcanvas->opacity); break; case CD_DIAGCROSS: fprintf(ctxcanvas->file, "\n", - 0, 0, hsize, hsize, ctxcanvas->fgColor, ctxcanvas->canvas->line_width, ctxcanvas->opacity); + 0, 0, hsize, hsize, ctxcanvas->fgColor, ctxcanvas->opacity); fprintf(ctxcanvas->file, "\n", - hsize, 0, 0, hsize, ctxcanvas->fgColor, ctxcanvas->canvas->line_width, ctxcanvas->opacity); + hsize, 0, 0, hsize, ctxcanvas->fgColor, ctxcanvas->opacity); break; } @@ -642,21 +640,18 @@ static void cdpattern(cdCtxCanvas *ctxcanvas, int n, int m, const long int *patt static int uchar2rgb(cdCtxCanvas *ctxcanvas, int n, int i, int j, void* data, unsigned char*r, unsigned char*g, unsigned char*b) { - int ret = 1; unsigned char* uchar_data = (unsigned char*)data; if (uchar_data[j*n+i]) - { cdDecodeColor(ctxcanvas->canvas->foreground, r, g, b); - ret = 1; - } else { - cdDecodeColor(ctxcanvas->canvas->background, r, g, b); if (ctxcanvas->canvas->back_opacity==CD_TRANSPARENT) - ret = -1; + return -1; + else + cdDecodeColor(ctxcanvas->canvas->background, r, g, b); } - return ret; + return 1; } static void cdstipple(cdCtxCanvas *ctxcanvas, int n, int m, const unsigned char *stipple) @@ -966,7 +961,6 @@ static void cdcreatecanvas(cdCanvas *canvas, void *data) char* strdata = (char*)data; double w_mm = INT_MAX*3.78, h_mm = INT_MAX*3.78, res = 3.78; cdCtxCanvas* ctxcanvas; - int size; strdata += cdGetFileName(strdata, filename); if (filename[0] == 0) @@ -984,10 +978,6 @@ static void cdcreatecanvas(cdCanvas *canvas, void *data) return; } - size = strlen(filename); - ctxcanvas->filename = malloc(size+1); - memcpy(ctxcanvas->filename, filename, size+1); - /* store the base canvas */ ctxcanvas->canvas = canvas; diff --git a/src/win32/cdwdbuf.c b/src/win32/cdwdbuf.c index 85af87c..4beac10 100644 --- a/src/win32/cdwdbuf.c +++ b/src/win32/cdwdbuf.c @@ -75,6 +75,7 @@ static void cdcreatecanvas(cdCanvas* canvas, cdCanvas* canvas_dbuffer) canvas->bpp = ctximage->bpp; canvas->xres = ctximage->xres; canvas->yres = ctximage->yres; + ctxcanvas->clip_pnt[2].x = ctxcanvas->clip_pnt[1].x = ctximage->w - 1; ctxcanvas->clip_pnt[3].y = ctxcanvas->clip_pnt[2].y = ctximage->h - 1; } diff --git a/src/win32/cdwin.c b/src/win32/cdwin.c index 313e833..da9bf9d 100644 --- a/src/win32/cdwin.c +++ b/src/win32/cdwin.c @@ -626,6 +626,7 @@ static int cdinteriorstyle (cdCtxCanvas* ctxcanvas, int style) ctxcanvas->hBrush = CreateBrushIndirect(&ctxcanvas->logBrush); ctxcanvas->hOldBrush = SelectObject(ctxcanvas->hDC, ctxcanvas->hBrush); break; + /* the remaining styles must recreate the current brush */ case CD_HATCH: cdhatch(ctxcanvas, ctxcanvas->canvas->hatch_style); break; @@ -963,8 +964,37 @@ static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix) else { ctxcanvas->canvas->invert_yaxis = 1; - ModifyWorldTransform(ctxcanvas->hDC, NULL, MWT_IDENTITY); - SetGraphicsMode(ctxcanvas->hDC, GM_COMPATIBLE); + + if (ctxcanvas->rotate_angle) + { + XFORM xForm; + + /* the rotation must be corrected because of the Y axis orientation */ + + SetGraphicsMode(ctxcanvas->hDC, GM_ADVANCED); + ModifyWorldTransform(ctxcanvas->hDC, NULL, MWT_IDENTITY); + + xForm.eM11 = (FLOAT) cos(-CD_DEG2RAD*ctxcanvas->rotate_angle); + xForm.eM12 = (FLOAT) sin(-CD_DEG2RAD*ctxcanvas->rotate_angle); + xForm.eM21 = (FLOAT) -xForm.eM12; + xForm.eM22 = (FLOAT) xForm.eM11; + xForm.eDx = (FLOAT) ctxcanvas->rotate_center_x; + xForm.eDy = (FLOAT) _cdInvertYAxis(ctxcanvas->canvas, ctxcanvas->rotate_center_y); + ModifyWorldTransform(ctxcanvas->hDC, &xForm, MWT_LEFTMULTIPLY); + + xForm.eM11 = (FLOAT) 1; + xForm.eM12 = (FLOAT) 0; + xForm.eM21 = (FLOAT) 0; + xForm.eM22 = (FLOAT) 1; + xForm.eDx = (FLOAT) -ctxcanvas->rotate_center_x; + xForm.eDy = (FLOAT) -_cdInvertYAxis(ctxcanvas->canvas, ctxcanvas->rotate_center_y); + ModifyWorldTransform(ctxcanvas->hDC, &xForm, MWT_LEFTMULTIPLY); + } + else + { + ModifyWorldTransform(ctxcanvas->hDC, NULL, MWT_IDENTITY); + SetGraphicsMode(ctxcanvas->hDC, GM_COMPATIBLE); + } } } @@ -1581,11 +1611,12 @@ static void cdgetimagergb(cdCtxCanvas* ctxcanvas, unsigned char *red, unsigned c if (GetGraphicsMode(ctxcanvas->hDC) == GM_ADVANCED) { + /* reset to the identity. */ GetWorldTransform(ctxcanvas->hDC, &xForm); ModifyWorldTransform(ctxcanvas->hDC, NULL, MWT_IDENTITY); } - if (ctxcanvas->canvas->invert_yaxis==0) // if 0, then the transform was reset + if (ctxcanvas->canvas->invert_yaxis==0) /* if 0, invert because the transform was reset here */ y = _cdInvertYAxis(ctxcanvas->canvas, y); yr = y - (h - 1); /* y starts at the bottom of the image */ @@ -1891,20 +1922,21 @@ static cdCtxImage *cdcreateimage(cdCtxCanvas* ctxcanvas, int width, int height) static void cdgetimage(cdCtxCanvas* ctxcanvas, cdCtxImage *ctximage, int x, int y) { - int yr; XFORM xForm; if (GetGraphicsMode(ctxcanvas->hDC) == GM_ADVANCED) { + /* reset to the identity. */ GetWorldTransform(ctxcanvas->hDC, &xForm); ModifyWorldTransform(ctxcanvas->hDC, NULL, MWT_IDENTITY); } - if (ctxcanvas->canvas->invert_yaxis==0) // if 0, then the transform was reset + if (ctxcanvas->canvas->invert_yaxis==0) /* if 0, invert because the transform was reset here */ y = _cdInvertYAxis(ctxcanvas->canvas, y); - yr = y - (ctximage->h - 1); - BitBlt(ctximage->hDC, 0, 0, ctximage->w, ctximage->h, ctxcanvas->hDC, x, yr, SRCCOPY); + /* y is the bottom-left of the image in CD, must be at upper-left */ + y -= ctximage->h-1; + BitBlt(ctximage->hDC, 0, 0, ctximage->w, ctximage->h, ctxcanvas->hDC, x, y, SRCCOPY); if (GetGraphicsMode(ctxcanvas->hDC) == GM_ADVANCED) ModifyWorldTransform(ctxcanvas->hDC, &xForm, MWT_LEFTMULTIPLY); @@ -1971,18 +2003,15 @@ static void cdscrollarea(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, i { XFORM xForm; RECT rect; - rect.left = xmin; - rect.right = xmax+1; - rect.top = ymin; - rect.bottom = ymax+1; if (GetGraphicsMode(ctxcanvas->hDC) == GM_ADVANCED) { + /* reset to the identity. */ GetWorldTransform(ctxcanvas->hDC, &xForm); ModifyWorldTransform(ctxcanvas->hDC, NULL, MWT_IDENTITY); } - if (ctxcanvas->canvas->invert_yaxis==0) // if 0, then the transform was reset + if (ctxcanvas->canvas->invert_yaxis==0) /* if 0, invert because the transform was reset here */ { dy = -dy; ymin = _cdInvertYAxis(ctxcanvas->canvas, ymin); @@ -1990,6 +2019,11 @@ static void cdscrollarea(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, i _cdSwapInt(ymin, ymax); } + rect.left = xmin; + rect.right = xmax+1; + rect.top = ymin; + rect.bottom = ymax+1; + ScrollDC(ctxcanvas->hDC, dx, dy, &rect, NULL, NULL, NULL); if (GetGraphicsMode(ctxcanvas->hDC) == GM_ADVANCED) @@ -2136,47 +2170,25 @@ static cdAttribute img_points_attrib = static void set_rotate_attrib(cdCtxCanvas* ctxcanvas, char* data) { - /* ignore ROTATE if transform is set */ + /* ignore ROTATE if transform is set, + because there is native support for transformations */ if (ctxcanvas->canvas->use_matrix) return; if (data) { - XFORM xForm; sscanf(data, "%g %d %d", &ctxcanvas->rotate_angle, &ctxcanvas->rotate_center_x, &ctxcanvas->rotate_center_y); - - /* the rotation must be corrected because of the Y axis orientation */ - - SetGraphicsMode(ctxcanvas->hDC, GM_ADVANCED); - ModifyWorldTransform(ctxcanvas->hDC, NULL, MWT_IDENTITY); - - xForm.eM11 = (FLOAT) cos(-CD_DEG2RAD*ctxcanvas->rotate_angle); - xForm.eM12 = (FLOAT) sin(-CD_DEG2RAD*ctxcanvas->rotate_angle); - xForm.eM21 = (FLOAT) -xForm.eM12; - xForm.eM22 = (FLOAT) xForm.eM11; - xForm.eDx = (FLOAT) ctxcanvas->rotate_center_x; - xForm.eDy = (FLOAT) _cdInvertYAxis(ctxcanvas->canvas, ctxcanvas->rotate_center_y); - ModifyWorldTransform(ctxcanvas->hDC, &xForm, MWT_LEFTMULTIPLY); - - xForm.eM11 = (FLOAT) 1; - xForm.eM12 = (FLOAT) 0; - xForm.eM21 = (FLOAT) 0; - xForm.eM22 = (FLOAT) 1; - xForm.eDx = (FLOAT) -ctxcanvas->rotate_center_x; - xForm.eDy = (FLOAT) -_cdInvertYAxis(ctxcanvas->canvas, ctxcanvas->rotate_center_y); - ModifyWorldTransform(ctxcanvas->hDC, &xForm, MWT_LEFTMULTIPLY); } else { ctxcanvas->rotate_angle = 0; ctxcanvas->rotate_center_x = 0; ctxcanvas->rotate_center_y = 0; - - ModifyWorldTransform(ctxcanvas->hDC, NULL, MWT_IDENTITY); - SetGraphicsMode(ctxcanvas->hDC, GM_COMPATIBLE); } + + cdtransform(ctxcanvas, NULL); } static char* get_rotate_attrib(cdCtxCanvas* ctxcanvas) diff --git a/src/win32/cdwnative.c b/src/win32/cdwnative.c index 69623e1..3534c6e 100644 --- a/src/win32/cdwnative.c +++ b/src/win32/cdwnative.c @@ -44,7 +44,6 @@ static int cdactivate(cdCtxCanvas *ctxcanvas) if (ctxcanvas->hWnd) { RECT rect; - HDC ScreenDC; GetClientRect(ctxcanvas->hWnd, &rect); ctxcanvas->canvas->w = rect.right - rect.left; ctxcanvas->canvas->h = rect.bottom - rect.top; @@ -52,12 +51,7 @@ static int cdactivate(cdCtxCanvas *ctxcanvas) ctxcanvas->canvas->w_mm = ((double)ctxcanvas->canvas->w) / ctxcanvas->canvas->xres; ctxcanvas->canvas->h_mm = ((double)ctxcanvas->canvas->h) / ctxcanvas->canvas->yres; - ScreenDC = GetDC(NULL); - ctxcanvas->canvas->bpp = GetDeviceCaps(ScreenDC, BITSPIXEL); - ReleaseDC(NULL, ScreenDC); - - if (ctxcanvas->canvas->use_matrix) - ctxcanvas->canvas->cxTransform(ctxcanvas, ctxcanvas->canvas->matrix); + ctxcanvas->canvas->bpp = cdGetScreenColorPlanes(); } /* Se nao e' ownwer, tem que restaurar o contexto */ @@ -70,6 +64,9 @@ static int cdactivate(cdCtxCanvas *ctxcanvas) cdwRestoreDC(ctxcanvas); } + if (ctxcanvas->canvas->use_matrix) + ctxcanvas->canvas->cxTransform(ctxcanvas, ctxcanvas->canvas->matrix); + return CD_OK; } diff --git a/src/x11/cdx11.c b/src/x11/cdx11.c index 94aae39..35342db 100644 --- a/src/x11/cdx11.c +++ b/src/x11/cdx11.c @@ -2192,8 +2192,11 @@ static cdCtxImage *cdcreateimage (cdCtxCanvas *ctxcanvas, int w, int h) static void cdgetimage (cdCtxCanvas *ctxcanvas, cdCtxImage *ctximage, int x, int y) { + /* y is the bottom-left of the image in CD, must be at upper-left */ + y -= ctximage->h-1; + XCopyArea(ctxcanvas->dpy, ctxcanvas->wnd, ctximage->img, ctxcanvas->gc, - x, y - ctximage->h+1, ctximage->w, ctximage->h, 0, 0); + x, y, ctximage->w, ctximage->h, 0, 0); } static void cdputimagerect (cdCtxCanvas *ctxcanvas, cdCtxImage *ctximage, int x, int y, int xmin, int xmax, int ymin, int ymax) @@ -2243,6 +2246,7 @@ static void set_rotate_attrib(cdCtxCanvas* ctxcanvas, char* data) { if (data) { + /* use this configuration when there is NO native tranformation support */ sscanf(data, "%g %d %d", &ctxcanvas->rotate_angle, &ctxcanvas->rotate_center_x, &ctxcanvas->rotate_center_y); -- cgit v1.2.3