diff options
author | scuri <scuri> | 2008-10-17 06:10:33 +0000 |
---|---|---|
committer | scuri <scuri> | 2008-10-17 06:10:33 +0000 |
commit | 7b52cc13af4e85f1ca2deb6b6c77de9c95ea0dcf (patch) | |
tree | d0857278bde2eff784227c57dcaf930346ceb7ac /src/gdiplus |
First commit - moving from LuaForge to SourceForge
Diffstat (limited to 'src/gdiplus')
-rw-r--r-- | src/gdiplus/cdcontextplus.def | 9 | ||||
-rw-r--r-- | src/gdiplus/cdgdiplus.def | 9 | ||||
-rw-r--r-- | src/gdiplus/cdwclpp.cpp | 206 | ||||
-rw-r--r-- | src/gdiplus/cdwdbufp.cpp | 152 | ||||
-rw-r--r-- | src/gdiplus/cdwemfp.cpp | 105 | ||||
-rw-r--r-- | src/gdiplus/cdwgdiplus.c | 42 | ||||
-rw-r--r-- | src/gdiplus/cdwimgp.cpp | 65 | ||||
-rw-r--r-- | src/gdiplus/cdwinp.cpp | 2337 | ||||
-rw-r--r-- | src/gdiplus/cdwinp.h | 112 | ||||
-rw-r--r-- | src/gdiplus/cdwnativep.cpp | 138 | ||||
-rw-r--r-- | src/gdiplus/cdwprnp.cpp | 158 |
11 files changed, 3333 insertions, 0 deletions
diff --git a/src/gdiplus/cdcontextplus.def b/src/gdiplus/cdcontextplus.def new file mode 100644 index 0000000..92175a6 --- /dev/null +++ b/src/gdiplus/cdcontextplus.def @@ -0,0 +1,9 @@ +EXPORTS + cdInitContextPlus + cdInitGdiPlus + cdwpCreateCanvas + cdwpGdiPlusStartup + cdwpGdiPlusShutdown + cdwpInitTable + cdwpUpdateCanvas + cdwpKillCanvas diff --git a/src/gdiplus/cdgdiplus.def b/src/gdiplus/cdgdiplus.def new file mode 100644 index 0000000..92175a6 --- /dev/null +++ b/src/gdiplus/cdgdiplus.def @@ -0,0 +1,9 @@ +EXPORTS + cdInitContextPlus + cdInitGdiPlus + cdwpCreateCanvas + cdwpGdiPlusStartup + cdwpGdiPlusShutdown + cdwpInitTable + cdwpUpdateCanvas + cdwpKillCanvas diff --git a/src/gdiplus/cdwclpp.cpp b/src/gdiplus/cdwclpp.cpp new file mode 100644 index 0000000..719713f --- /dev/null +++ b/src/gdiplus/cdwclpp.cpp @@ -0,0 +1,206 @@ +/** \file + * \brief Windows GDI+ Clipboard Driver + * + * See Copyright Notice in cd.h + */ + +#include "cdwinp.h" +#include "cdclipbd.h" +#include "cdmf.h" +#include "cdemf.h" + +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +#include "cdmf_private.h" + + +static void cdkillcanvasCLIPBDMF (cdCtxCanvas* ctxcanvas) +{ + HANDLE Handle, hFile; + char* buffer; + DWORD dwSize, nBytesRead; + char filename[10240]; + cdCanvasMF* mfcanvas = (cdCanvasMF*)ctxcanvas; + + /* guardar antes de remover o canvas */ + strcpy(filename, mfcanvas->filename); + + OpenClipboard(NULL); + EmptyClipboard(); + + cdkillcanvasMF(mfcanvas); /* this will close the file */ + + hFile = CreateFile(filename, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, NULL); + dwSize = GetFileSize (hFile, NULL) ; + + Handle = GlobalAlloc(GMEM_MOVEABLE, dwSize+1); + buffer = (char*)GlobalLock(Handle); + ReadFile(hFile, buffer, dwSize, &nBytesRead, NULL); + buffer[dwSize] = 0; + GlobalUnlock(Handle); + + CloseHandle(hFile); + + SetClipboardData(CF_TEXT, Handle); + + CloseClipboard(); +} + +static void cdkillcanvas (cdCtxCanvas* ctxcanvas) +{ + cdwpKillCanvas(ctxcanvas); + + OpenClipboard(NULL); + EmptyClipboard(); + + if (ctxcanvas->wtype == CDW_EMF) + { + HENHMETAFILE hEmf = ctxcanvas->metafile->GetHENHMETAFILE(); + SetClipboardData(CF_ENHMETAFILE, hEmf); + delete ctxcanvas->metafile; + } + else + { + HBITMAP hBitmap; + ctxcanvas->bitmap->GetHBITMAP(ctxcanvas->bg, &hBitmap); + SetClipboardData(CF_BITMAP, hBitmap); + delete ctxcanvas->bitmap; + } + + CloseClipboard(); + + delete ctxcanvas; +} + +/* +%F cdCreateCanvas para Clipboard +O DC pode ser um WMF ou um BITMAP. +*/ +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + char* strsize = (char*)data; + int w = 0, h = 0, wtype = CDW_EMF; /* default clipboard type */ + double res = 0; /* used only for BMP */ + Metafile* metafile = NULL; + Bitmap* bitmap = NULL; + Graphics* graphics; + + /* Inicializa parametros */ + if (strsize == NULL) + return; + + if (strstr(strsize, "-b") != NULL) + wtype = CDW_BMP; + else if (strstr(strsize, "-m") != NULL) + wtype = -1; /* CD METAFILE */ + + if (wtype != -1) + { + sscanf(strsize,"%dx%d %g",&w, &h, &res); + if (w == 0 || h == 0) + return; + } + + if (wtype == CDW_EMF) + { + HDC ScreenDC = GetDC(NULL); + /* LOGPIXELS can not be used for EMF */ + canvas->xres = (double)GetDeviceCaps(ScreenDC, HORZRES) / (double)GetDeviceCaps(ScreenDC, HORZSIZE); + canvas->yres = (double)GetDeviceCaps(ScreenDC, VERTRES) / (double)GetDeviceCaps(ScreenDC, VERTSIZE); + + Rect frameRect(0, 0, (int)(100 * w / canvas->xres), (int)(100 * h / canvas->yres)); + + metafile = new Metafile(ScreenDC, frameRect, MetafileFrameUnitGdi, EmfTypeEmfPlusDual, NULL); + ReleaseDC(NULL, ScreenDC); + + if (!metafile) + return; + + graphics = new Graphics(metafile); + } + else if (wtype == CDW_BMP) + { + if (!res) + { + HDC ScreenDC = GetDC(NULL); + canvas->xres = (double)GetDeviceCaps(ScreenDC, HORZRES) / (double)GetDeviceCaps(ScreenDC, HORZSIZE); + canvas->yres = (double)GetDeviceCaps(ScreenDC, VERTRES) / (double)GetDeviceCaps(ScreenDC, VERTSIZE); + ReleaseDC(NULL, ScreenDC); + } + else + { + canvas->xres = res; + canvas->yres = res; + } + + bitmap = new Bitmap(w, h, PixelFormat24bppRGB); + if (!bitmap) + return; + + bitmap->SetResolution((REAL)(canvas->xres*25.4), (REAL)(canvas->xres*25.4)); + + graphics = new Graphics(bitmap); + } + + if (wtype == -1) + { + char filename[1024]; + char tmpPath[512]; + char str[1024]; + + GetTempPath(512, tmpPath); + GetTempFileName(tmpPath, "~cd", 0, filename); + + sprintf(str, "%s %s", filename, strsize); + cdcreatecanvasMF(canvas, str); + } + else + { + cdCtxCanvas* ctxcanvas = cdwpCreateCanvas(canvas, graphics, wtype); + + canvas->w = w; + canvas->h = h; + canvas->bpp = 24; + + if (wtype == CDW_BMP) + ctxcanvas->bitmap = bitmap; + else + ctxcanvas->metafile = metafile; + } +} + +static void cdinittable(cdCanvas* canvas) +{ + if (canvas->invert_yaxis == 0) /* a simple way to distinguish MF from WIN */ + { + cdinittableMF(canvas); + canvas->cxKillCanvas = cdkillcanvasCLIPBDMF; + } + else + { + cdwpInitTable(canvas); + canvas->cxKillCanvas = cdkillcanvas; + } +} + +static cdContext cdClipboardContext = +{ + CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_FLUSH | CD_CAP_YAXIS | + CD_CAP_PLAY | + CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB | CD_CAP_IMAGESRV | + CD_CAP_FPRIMTIVES ), + 1, + cdcreatecanvas, + cdinittable, + NULL, + NULL +}; + +extern "C" { +cdContext* cdContextClipboardPlus(void) +{ + return &cdClipboardContext; +} +} diff --git a/src/gdiplus/cdwdbufp.cpp b/src/gdiplus/cdwdbufp.cpp new file mode 100644 index 0000000..6d968b2 --- /dev/null +++ b/src/gdiplus/cdwdbufp.cpp @@ -0,0 +1,152 @@ +/** \file + * \brief Windows GDI+ Double Buffer + * + * See Copyright Notice in cd.h + */ + +#include "cdwinp.h" +#include "cddbuf.h" +#include <stdlib.h> +#include <stdio.h> + + +static void cdkillcanvas(cdCtxCanvas* ctxcanvas) +{ + cdwpKillCanvas(ctxcanvas); + + if (ctxcanvas->bitmap_dbuffer) delete ctxcanvas->bitmap_dbuffer; + delete ctxcanvas->bitmap; + + delete 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) +{ + cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer; + + if (ctxcanvas->dirty || ctxcanvas->bitmap_dbuffer == NULL) + { + ctxcanvas->dirty = 0; + if (ctxcanvas->bitmap_dbuffer) delete ctxcanvas->bitmap_dbuffer; + ctxcanvas->bitmap_dbuffer = new CachedBitmap(ctxcanvas->bitmap, canvas_dbuffer->ctxcanvas->graphics); + } + + ctxcanvas->graphics->Flush(FlushIntentionSync); + + /* this is done in the canvas_dbuffer context */ + /* Flush can be affected by Origin and Clipping, but not WriteMode */ + canvas_dbuffer->ctxcanvas->graphics->ResetTransform(); + + int x = 0, y = 0; + if (canvas_dbuffer->use_origin) + { + x += canvas_dbuffer->origin.x; + if (canvas_dbuffer->invert_yaxis) + y -= canvas_dbuffer->origin.y; // top down shift + else + y += canvas_dbuffer->origin.y; + } + + int old_writemode = cdCanvasWriteMode(canvas_dbuffer, CD_REPLACE); + canvas_dbuffer->ctxcanvas->graphics->DrawCachedBitmap(ctxcanvas->bitmap_dbuffer, x, y); + canvas_dbuffer->ctxcanvas->graphics->Flush(FlushIntentionSync); + cdCanvasWriteMode(canvas_dbuffer, old_writemode); +} + +static int cdactivate(cdCtxCanvas* ctxcanvas) +{ + cdCanvas* canvas_dbuffer = ctxcanvas->canvas_dbuffer; + + /* this is done in the canvas_dbuffer context */ + /* this will update canvas size */ + cdCanvasActivate(canvas_dbuffer); + + /* check if the size changed */ + if (canvas_dbuffer->w != ctxcanvas->canvas->w || + canvas_dbuffer->h != ctxcanvas->canvas->h) + { + delete ctxcanvas->graphics; + delete ctxcanvas->bitmap; + if (ctxcanvas->bitmap_dbuffer) delete ctxcanvas->bitmap_dbuffer; + ctxcanvas->bitmap_dbuffer = NULL; + + Bitmap* bitmap = new Bitmap(canvas_dbuffer->w, canvas_dbuffer->h, PixelFormat24bppRGB); + bitmap->SetResolution((REAL)(canvas_dbuffer->xres*25.4), (REAL)(canvas_dbuffer->yres*25.4)); + + ctxcanvas->bitmap = bitmap; + ctxcanvas->graphics = new Graphics(bitmap); + + ctxcanvas->canvas->w = canvas_dbuffer->w; + ctxcanvas->canvas->h = canvas_dbuffer->h; + + ctxcanvas->dirty = 1; + + cdwpUpdateCanvas(ctxcanvas); + } + + return CD_OK; +} + +/* +%F cdCreateCanvas para DBuffer. +O DC é um BITMAP em memoria. +*/ +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + cdCanvas* canvas_dbuffer = (cdCanvas*)data; + if (!canvas_dbuffer) + return; + + Bitmap* bitmap = new Bitmap(canvas_dbuffer->w, canvas_dbuffer->h, PixelFormat24bppRGB); + bitmap->SetResolution((REAL)(canvas_dbuffer->xres*25.4), (REAL)(canvas_dbuffer->yres*25.4)); + + Graphics imggraphics(bitmap); + imggraphics.Clear(Color::White); + + Graphics* graphics = new Graphics(bitmap); + + canvas->w = canvas_dbuffer->w; + canvas->h = canvas_dbuffer->h; + canvas->bpp = 24; + + /* Initialize base driver */ + cdCtxCanvas* ctxcanvas = cdwpCreateCanvas(canvas, graphics, CDW_BMP); + + ctxcanvas->bitmap = bitmap; + ctxcanvas->canvas_dbuffer = canvas_dbuffer; +} + +static void cdinittable(cdCanvas* canvas) +{ + cdwpInitTable(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), + 1, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + +extern "C" { +cdContext* cdContextDBufferPlus(void) +{ + return &cdDBufferContext; +} +} diff --git a/src/gdiplus/cdwemfp.cpp b/src/gdiplus/cdwemfp.cpp new file mode 100644 index 0000000..38b4200 --- /dev/null +++ b/src/gdiplus/cdwemfp.cpp @@ -0,0 +1,105 @@ +/** \file + * \brief Windows GDI+ EMF Driver + * + * See Copyright Notice in cd.h + */ + +#include "cdwinp.h" +#include "cdemf.h" +#include <stdlib.h> +#include <stdio.h> + + + +static void cdkillcanvas (cdCtxCanvas* ctxcanvas) +{ + cdwpKillCanvas(ctxcanvas); + delete ctxcanvas->metafile; + delete ctxcanvas; +} + +/* +%F cdCreateCanvas para EMF. +O DC é um EMF em memoria. +*/ +static void cdcreatecanvas(cdCanvas* canvas, void* data) +{ + char* strdata = (char*)data; + char filename[10240] = ""; + Metafile* metafile; + + /* Inicializa parametros */ + if (strdata == NULL) + return; + + strdata += cdGetFileName(strdata, filename); + if (filename[0] == 0) + return; + + int w = 0, h = 0; + sscanf(strdata,"%dx%d", &w, &h); + if (w == 0 || h == 0) + return; + + { + /* Verifica se o arquivo pode ser aberto para escrita */ + FILE* file = fopen(filename, "wb"); + if (file == NULL) + return; + fclose(file); + } + + { + HDC ScreenDC = GetDC(NULL); + /* LOGPIXELS can not be used for EMF */ + canvas->xres = (double)GetDeviceCaps(ScreenDC, HORZRES) / (double)GetDeviceCaps(ScreenDC, HORZSIZE); + canvas->yres = (double)GetDeviceCaps(ScreenDC, VERTRES) / (double)GetDeviceCaps(ScreenDC, VERTSIZE); + + Rect frameRect(0, 0, (int)(100 * w / canvas->xres), (int)(100 * h / canvas->yres)); + + metafile = new Metafile(cdwpString2Unicode(filename, strlen(filename)), + ScreenDC, frameRect, MetafileFrameUnitGdi, EmfTypeEmfPlusDual, NULL); + + ReleaseDC(NULL, ScreenDC); + } + + canvas->w = w; + canvas->h = h; + canvas->bpp = 24; + + Graphics* graphics = new Graphics(metafile); + + /* Inicializa driver WIN32 */ + cdCtxCanvas* ctxcanvas = cdwpCreateCanvas(canvas, graphics, CDW_EMF); + + /* Inicializacao de variaveis particulares para o EMF */ + ctxcanvas->metafile = metafile; +} + +static void cdinittable(cdCanvas* canvas) +{ + cdwpInitTable(canvas); + + canvas->cxKillCanvas = cdkillcanvas; +} + +static cdContext cdEMFContext = +{ + CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_PLAY | CD_CAP_FLUSH | CD_CAP_YAXIS | + CD_CAP_FPRIMTIVES | + CD_CAP_GETIMAGERGB | CD_CAP_IMAGESRV), + 1, + cdcreatecanvas, + cdinittable, + NULL, + NULL +}; + +extern "C" { +cdContext* cdContextEMFPlus(void) +{ + return &cdEMFContext; +} +} + + diff --git a/src/gdiplus/cdwgdiplus.c b/src/gdiplus/cdwgdiplus.c new file mode 100644 index 0000000..a6862bc --- /dev/null +++ b/src/gdiplus/cdwgdiplus.c @@ -0,0 +1,42 @@ +/** \file + * \brief GDI+ Control + * + * See Copyright Notice in cd.h + */ + +#include "cd.h" +#include "cd_private.h" +#include "cdgdiplus.h" +#include <stdlib.h> +#include <memory.h> + +cdContext* cdContextNativeWindowPlus(void); +cdContext* cdContextImagePlus(void); +cdContext* cdContextDBufferPlus(void); +cdContext* cdContextPrinterPlus(void); +cdContext* cdContextEMFPlus(void); +cdContext* cdContextClipboardPlus(void); +void cdwpGdiPlusStartup(int debug); + +void cdInitGdiPlus(void) +{ + cdInitContextPlus(); +} + +void cdInitContextPlus(void) +{ + cdContext* ctx_list[NUM_CONTEXTPLUS]; + memset(ctx_list, 0, sizeof(ctx_list)); + + ctx_list[CD_CTX_NATIVEWINDOW] = cdContextNativeWindowPlus(); + ctx_list[CD_CTX_IMAGE] = cdContextImagePlus(); + ctx_list[CD_CTX_DBUFFER] = cdContextDBufferPlus(); + ctx_list[CD_CTX_PRINTER] = cdContextPrinterPlus(); + ctx_list[CD_CTX_EMF] = cdContextEMFPlus(); + ctx_list[CD_CTX_CLIPBOARD] = cdContextClipboardPlus(); + + cdInitContextPlusList(ctx_list); + + cdwpGdiPlusStartup(0); +} + diff --git a/src/gdiplus/cdwimgp.cpp b/src/gdiplus/cdwimgp.cpp new file mode 100644 index 0000000..697ff40 --- /dev/null +++ b/src/gdiplus/cdwimgp.cpp @@ -0,0 +1,65 @@ +/** \file + * \brief Windows GDI+ Image Driver + * + * See Copyright Notice in cd.h + */ + +#include "cdwinp.h" +#include "cdimage.h" +#include <stdlib.h> +#include <stdio.h> + + +static void cdkillcanvas (cdCtxCanvas* ctxcanvas) +{ + cdwpKillCanvas(ctxcanvas); + delete ctxcanvas; +} + +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + if (data == NULL) + return; + + cdCtxImage* ctximage = ((cdImage*)data)->ctximage; + + /* Inicializa parametros */ + if (ctximage == NULL) + return; + + Graphics* graphics = new Graphics(ctximage->bitmap); + + canvas->w = ctximage->w; + canvas->h = ctximage->h; + canvas->bpp = ctximage->bpp; + + /* Inicializa driver Image */ + cdCtxCanvas* ctxcanvas = cdwpCreateCanvas(canvas, graphics, CDW_BMP); + + ctxcanvas->bitmap = ctximage->bitmap; +} + +static void cdinittable(cdCanvas* canvas) +{ + cdwpInitTable(canvas); + + canvas->cxKillCanvas = cdkillcanvas; +} + +static cdContext cdImageContext = +{ + CD_CAP_ALL & ~(CD_CAP_FLUSH | CD_CAP_PLAY | CD_CAP_YAXIS | + CD_CAP_FPRIMTIVES ), + 1, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + +extern "C" { +cdContext* cdContextImagePlus(void) +{ + return &cdImageContext; +} +} diff --git a/src/gdiplus/cdwinp.cpp b/src/gdiplus/cdwinp.cpp new file mode 100644 index 0000000..d91ef6c --- /dev/null +++ b/src/gdiplus/cdwinp.cpp @@ -0,0 +1,2337 @@ +/** \file + * \brief Windows GDI+ Base Driver + * + * See Copyright Notice in cd.h + */ + +#include "cdwinp.h" +#include "cdgdiplus.h" +#include "wd.h" +#include <stdlib.h> +#include <stdio.h> +#include <math.h> + +static void cdstipple(cdCtxCanvas* ctxcanvas, int w, int h, const unsigned char *index); + +void cdwpShowStatus(const char* title, Status status) +{ + char* status_str = ""; + switch(status) + { + case Ok: status_str = "Ok"; break; + case GenericError: status_str = "GenericError"; break; + case InvalidParameter: status_str = "InvalidParameter"; break; + case OutOfMemory: status_str = "OutOfMemory"; break; + case ObjectBusy: status_str = "ObjectBusy"; break; + case InsufficientBuffer: status_str = "InsufficientBuffer"; break; + case NotImplemented: status_str = "NotImplemented"; break; + case Win32Error: status_str = "Win32Error"; break; + case WrongState: status_str = "WrongState"; break; + case Aborted: status_str = "Aborted"; break; + case FileNotFound: status_str = "FileNotFound"; break; + case ValueOverflow: status_str = "ValueOverflow"; break; + case AccessDenied: status_str = "AccessDenied"; break; + case UnknownImageFormat: status_str = "UnknownImageFormat"; break; + case FontFamilyNotFound: status_str = "FontFamilyNotFound"; break; + case FontStyleNotFound: status_str = "FontStyleNotFound"; break; + case NotTrueTypeFont: status_str = "NotTrueTypeFont"; break; + case UnsupportedGdiplusVersion: status_str = "UnsupportedGdiplusVersion"; break; + case GdiplusNotInitialized: status_str = "GdiplusNotInitialized"; break; + case PropertyNotFound: status_str = "PropertyNotFound"; break; + case PropertyNotSupported: status_str = "PropertyNotSupported"; break; + } + + if (status != Ok) + MessageBox(NULL, status_str, title, MB_OK); +} + +/* +%F Libera memoria e handles alocados pelo driver Windows. +*/ +void cdwpKillCanvas(cdCtxCanvas* ctxcanvas) +{ + if (ctxcanvas->clip_poly) delete[] ctxcanvas->clip_poly; + if (ctxcanvas->clip_region) delete ctxcanvas->clip_region; + if (ctxcanvas->new_region) delete ctxcanvas->new_region; + if (ctxcanvas->font) delete ctxcanvas->font; + if (ctxcanvas->wdpoly) delete ctxcanvas->wdpoly; + + delete ctxcanvas->fillBrush; + delete ctxcanvas->lineBrush; + delete ctxcanvas->linePen; + + delete ctxcanvas->graphics; + + /* ctxcanvas e´ liberado em cada driver */ +} + +static int cdwpSetTransform(cdCtxCanvas* ctxcanvas, Matrix &transformMatrix, const double* matrix) +{ + if (matrix) + { + // configure a bottom-up coordinate system + Matrix Matrix1((REAL)1, (REAL)0, (REAL)0, (REAL)-1, (REAL)0, (REAL)(ctxcanvas->canvas->h-1)); + transformMatrix.Multiply(&Matrix1); + // add the global transform + Matrix Matrix2((REAL)matrix[0], (REAL)matrix[1], (REAL)matrix[2], (REAL)matrix[3], (REAL)matrix[4], (REAL)matrix[5]); + transformMatrix.Multiply(&Matrix2); + return 1; + } + else if (ctxcanvas->rotate_angle) + { + /* the rotation must be corrected because of the Y axis orientation */ + transformMatrix.Translate((REAL)ctxcanvas->rotate_center_x, (REAL)_cdInvertYAxis(ctxcanvas->canvas, ctxcanvas->rotate_center_y)); + transformMatrix.Rotate((REAL)-ctxcanvas->rotate_angle); + transformMatrix.Translate((REAL)-ctxcanvas->rotate_center_x, (REAL)-_cdInvertYAxis(ctxcanvas->canvas, ctxcanvas->rotate_center_y)); + return 1; + } + + return 0; +} + +static void cdwpUpdateTransform(cdCtxCanvas* ctxcanvas) +{ + Matrix transformMatrix; + ctxcanvas->graphics->ResetTransform(); // reset to the identity. + if (cdwpSetTransform(ctxcanvas, transformMatrix, ctxcanvas->canvas->use_matrix? ctxcanvas->canvas->matrix: NULL)) + ctxcanvas->graphics->SetTransform(&transformMatrix); +} + +/*********************************************************************/ +/* +%S Cor +*/ +/*********************************************************************/ + +static Color sColor2Windows(long int cd_color) +{ + return Color(cdAlpha(cd_color),cdRed(cd_color),cdGreen(cd_color),cdBlue(cd_color)); +} + +static void sUpdateFillBrush(cdCtxCanvas* ctxcanvas) +{ + // must update the fill brush that is dependent from the Foreground and Background Color. + BrushType type = ctxcanvas->fillBrush->GetType(); + switch(type) + { + case BrushTypeSolidColor: + { + SolidBrush* solidbrush = (SolidBrush*)ctxcanvas->fillBrush; + solidbrush->SetColor(ctxcanvas->fg); + break; + } + case BrushTypeHatchFill: + { + HatchBrush* hatchbrush = (HatchBrush*)ctxcanvas->fillBrush; + HatchStyle hatchStyle = hatchbrush->GetHatchStyle(); + delete ctxcanvas->fillBrush; + ctxcanvas->fillBrush = new HatchBrush(hatchStyle, ctxcanvas->fg, ctxcanvas->bg); + break; + } + case BrushTypeLinearGradient: + { + LinearGradientBrush* gradientbrush = (LinearGradientBrush*)ctxcanvas->fillBrush; + gradientbrush->SetLinearColors(ctxcanvas->fg, ctxcanvas->bg); + break; + } + case BrushTypeTextureFill: + { + // only stipple depends on Foreground and Background Color. + if (ctxcanvas->canvas->interior_style == CD_STIPPLE) + { + cdstipple(ctxcanvas, ctxcanvas->canvas->stipple_w, ctxcanvas->canvas->stipple_h, ctxcanvas->canvas->stipple); + } + break; + } + } +} + +static long int cdforeground(cdCtxCanvas* ctxcanvas, long int color) +{ + ctxcanvas->fg = sColor2Windows(color); + ctxcanvas->linePen->SetColor(ctxcanvas->fg); + ctxcanvas->lineBrush->SetColor(ctxcanvas->fg); + + sUpdateFillBrush(ctxcanvas); + + return color; +} + +static Color sSetAlpha(const Color& c, BYTE alpha) +{ + return Color(alpha, c.GetRed(), c.GetGreen(), c.GetBlue()); +} + +static long int cdbackground(cdCtxCanvas* ctxcanvas, long int color) +{ + ctxcanvas->bg = sColor2Windows(color); + + if ((ctxcanvas->canvas->back_opacity == CD_TRANSPARENT) && + (cdAlpha(ctxcanvas->canvas->background) == 255)) + ctxcanvas->bg = sSetAlpha(ctxcanvas->bg, (BYTE)0); + + sUpdateFillBrush(ctxcanvas); + + return color; +} + +static int cdbackopacity(cdCtxCanvas* ctxcanvas, int opacity) +{ + switch (opacity) + { + case CD_TRANSPARENT: + ctxcanvas->bg = sSetAlpha(ctxcanvas->bg, (BYTE)0); + break; + case CD_OPAQUE: + ctxcanvas->bg = sSetAlpha(ctxcanvas->bg, (BYTE)255); + break; + } + + sUpdateFillBrush(ctxcanvas); + + return opacity; +} + +static void cdpalette(cdCtxCanvas* ctxcanvas, int pal_size, const long int *colors, int mode) +{ + (void)mode; + + if (ctxcanvas->wtype == CDW_BMP && + (ctxcanvas->bitmap->GetPixelFormat() == PixelFormat1bppIndexed || + ctxcanvas->bitmap->GetPixelFormat() == PixelFormat4bppIndexed || + ctxcanvas->bitmap->GetPixelFormat() == PixelFormat8bppIndexed)) + { + UINT size = ctxcanvas->bitmap->GetPaletteSize(); + ColorPalette* palette = new ColorPalette [size]; + + palette->Count = pal_size; + palette->Flags = 0; + + for (int c = 0; c < pal_size; c++) + { + palette->Entries[c] = sColor2Windows(colors[c]).GetValue(); + } + + ctxcanvas->bitmap->SetPalette(palette); + delete palette; + } +} + +/*********************************************************************/ +/* +%S Canvas e clipping +*/ +/*********************************************************************/ + +static void sClipRect(cdCtxCanvas* ctxcanvas) +{ + if (ctxcanvas->clip_region) + delete ctxcanvas->clip_region; + + Rect rect(ctxcanvas->canvas->clip_rect.xmin, + ctxcanvas->canvas->clip_rect.ymin, + ctxcanvas->canvas->clip_rect.xmax-ctxcanvas->canvas->clip_rect.xmin+1, + ctxcanvas->canvas->clip_rect.ymax-ctxcanvas->canvas->clip_rect.ymin+1); + + ctxcanvas->clip_region = new Region(rect); + + ctxcanvas->graphics->SetClip(ctxcanvas->clip_region); +} + +static void sClipPoly(cdCtxCanvas* ctxcanvas) +{ + if (ctxcanvas->clip_region) + delete ctxcanvas->clip_region; + + GraphicsPath path; + path.SetFillMode(ctxcanvas->canvas->fill_mode==CD_EVENODD?FillModeAlternate:FillModeWinding); + path.AddPolygon(ctxcanvas->clip_poly, ctxcanvas->clip_poly_n); + ctxcanvas->clip_region = new Region(&path); + + ctxcanvas->graphics->SetClip(ctxcanvas->clip_region); +} + +static int cdclip(cdCtxCanvas* ctxcanvas, int clip_mode) +{ + switch (clip_mode) + { + case CD_CLIPOFF: + ctxcanvas->graphics->ResetClip(); + if (ctxcanvas->clip_region) + delete ctxcanvas->clip_region; + ctxcanvas->clip_region = NULL; + break; + case CD_CLIPAREA: + sClipRect(ctxcanvas); + break; + case CD_CLIPPOLYGON: + sClipPoly(ctxcanvas); + break; + case CD_CLIPREGION: + if (ctxcanvas->clip_region) + delete ctxcanvas->clip_region; + ctxcanvas->clip_region = ctxcanvas->new_region->Clone(); + ctxcanvas->graphics->SetClip(ctxcanvas->clip_region); + break; + } + + return clip_mode; +} + +static void cdcliparea(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + if (ctxcanvas->canvas->clip_mode == CD_CLIPAREA) + { + ctxcanvas->canvas->clip_rect.xmin = xmin; + ctxcanvas->canvas->clip_rect.xmax = xmax; + ctxcanvas->canvas->clip_rect.ymin = ymin; + ctxcanvas->canvas->clip_rect.ymax = ymax; + + sClipRect(ctxcanvas); + } +} + +static void cdnewregion(cdCtxCanvas* ctxcanvas) +{ + if (ctxcanvas->new_region) + delete ctxcanvas->new_region; + ctxcanvas->new_region = new Region(); + ctxcanvas->new_region->MakeEmpty(); +} + +static int cdispointinregion(cdCtxCanvas* ctxcanvas, int x, int y) +{ + if (!ctxcanvas->new_region) + return 0; + + if (ctxcanvas->new_region->IsVisible(x, y)) + return 1; + + return 0; +} + +static void cdoffsetregion(cdCtxCanvas* ctxcanvas, int x, int y) +{ + if (!ctxcanvas->new_region) + return; + + ctxcanvas->new_region->Translate(x, y); +} + +static void cdgetregionbox(cdCtxCanvas* ctxcanvas, int *xmin, int *xmax, int *ymin, int *ymax) +{ + Rect rect; + + if (!ctxcanvas->new_region) + return; + + ctxcanvas->new_region->GetBounds(&rect, ctxcanvas->graphics); + + *xmin = rect.X; + *xmax = rect.X+rect.Width-1; + *ymin = rect.Y; + *ymax = rect.Y+rect.Height-1; +} + +static void sCombineRegion(cdCtxCanvas* ctxcanvas, Region& region) +{ + switch(ctxcanvas->canvas->combine_mode) + { + case CD_UNION: + ctxcanvas->new_region->Union(®ion); + break; + case CD_INTERSECT: + ctxcanvas->new_region->Intersect(®ion); + break; + case CD_DIFFERENCE: + ctxcanvas->new_region->Exclude(®ion); + break; + case CD_NOTINTERSECT: + ctxcanvas->new_region->Xor(®ion); + break; + } +} + +/******************************************************************/ +/* +%S Primitivas e seus atributos +*/ +/******************************************************************/ + +static int cdlinestyle(cdCtxCanvas* ctxcanvas, int style) +{ + switch (style) + { + case (CD_CONTINUOUS): + { + ctxcanvas->linePen->SetDashStyle(DashStyleSolid); + break; + } + case CD_DASHED: + { + if (ctxcanvas->canvas->line_width == 1) + { + REAL dashed[2] = {18.0f, 6.0f}; + ctxcanvas->linePen->SetDashPattern(dashed, 2); + } + else + ctxcanvas->linePen->SetDashStyle(DashStyleDash); + break; + } + case CD_DOTTED: + { + if (ctxcanvas->canvas->line_width == 1) + { + REAL dotted[2] = {3.0f, 3.0f}; + ctxcanvas->linePen->SetDashPattern(dotted, 2); + } + else + ctxcanvas->linePen->SetDashStyle(DashStyleDot); + break; + } + case CD_DASH_DOT: + { + if (ctxcanvas->canvas->line_width == 1) + { + REAL dash_dot[6] = {9.0f, 6.0f, 3.0f, 6.0f}; + ctxcanvas->linePen->SetDashPattern(dash_dot, 4); + } + else + ctxcanvas->linePen->SetDashStyle(DashStyleDashDot); + break; + } + case CD_DASH_DOT_DOT: + { + if (ctxcanvas->canvas->line_width == 1) + { + REAL dash_dot_dot[6] = {9.0f, 3.0f, 3.0f, 3.0f, 3.0f, 3.0f}; + ctxcanvas->linePen->SetDashPattern(dash_dot_dot, 6); + } + else + ctxcanvas->linePen->SetDashStyle(DashStyleDashDotDot); + break; + } + case CD_CUSTOM: + { + REAL* dash_style = new REAL [ctxcanvas->canvas->line_dashes_count]; + for (int i = 0; i < ctxcanvas->canvas->line_dashes_count; i++) + dash_style[i] = (REAL)ctxcanvas->canvas->line_dashes[i]/(REAL)ctxcanvas->canvas->line_width; + ctxcanvas->linePen->SetDashPattern(dash_style, ctxcanvas->canvas->line_dashes_count); + delete [] dash_style; + break; + } + } + + return style; +} + +static int cdlinecap(cdCtxCanvas* ctxcanvas, int cap) +{ + LineCap cd2win_lcap[] = {LineCapFlat, LineCapSquare, LineCapRound}; + DashCap cd2win_dcap[] = {DashCapFlat, DashCapFlat, DashCapRound}; + + ctxcanvas->linePen->SetLineCap(cd2win_lcap[cap], cd2win_lcap[cap], cd2win_dcap[cap]); + + return cap; +} + +static int cdlinejoin(cdCtxCanvas* ctxcanvas, int join) +{ + LineJoin cd2win_join[] = {LineJoinMiter, LineJoinBevel, LineJoinRound}; + + ctxcanvas->linePen->SetLineJoin(cd2win_join[join]); + + return join; +} + +static int cdlinewidth(cdCtxCanvas* ctxcanvas, int width) +{ + ctxcanvas->linePen->SetWidth((REAL)width); + cdlinestyle(ctxcanvas, ctxcanvas->canvas->line_style); + return width; +} + +static int cdhatch(cdCtxCanvas* ctxcanvas, int hatch_style) +{ + HatchStyle hatchStyle; + + switch (hatch_style) + { + default: // CD_HORIZONTAL: + hatchStyle = HatchStyleHorizontal; + break; + case CD_VERTICAL: + hatchStyle = HatchStyleVertical; + break; + case CD_FDIAGONAL: + hatchStyle = HatchStyleForwardDiagonal; + break; + case CD_BDIAGONAL: + hatchStyle = HatchStyleBackwardDiagonal; + break; + case CD_CROSS: + hatchStyle = HatchStyleCross; + break; + case CD_DIAGCROSS: + hatchStyle = HatchStyleDiagonalCross; + break; + } + + delete ctxcanvas->fillBrush; + ctxcanvas->fillBrush = new HatchBrush(hatchStyle, ctxcanvas->fg, ctxcanvas->bg); + + return hatch_style; +} + +static void cdstipple(cdCtxCanvas* ctxcanvas, int w, int h, const unsigned char *index) +{ + ULONG* bitmap_data = new ULONG [w*h]; + + for(int j = 0; j < h; j++) + { + int line_offset_index; + int line_offset = j*w; + if (ctxcanvas->canvas->invert_yaxis) + line_offset_index = ((h - 1) - j)*w; // Fix up side down + else + line_offset_index = line_offset; + + for(int i = 0; i < w; i++) + { + if (index[line_offset_index+i] != 0) + bitmap_data[line_offset+i] = ctxcanvas->fg.GetValue(); + else + bitmap_data[line_offset+i] = ctxcanvas->bg.GetValue(); + } + } + + Bitmap StippleImage(w, h, 4*w, PixelFormat32bppARGB, (BYTE*)bitmap_data); + StippleImage.SetResolution(ctxcanvas->graphics->GetDpiX(), ctxcanvas->graphics->GetDpiX()); + + delete ctxcanvas->fillBrush; + ctxcanvas->fillBrush = new TextureBrush(&StippleImage); + + delete bitmap_data; +} + +static void cdpattern(cdCtxCanvas* ctxcanvas, int w, int h, const long int *colors) +{ + int stride = 4*w; + BYTE* bitmap_data = new BYTE [stride*h]; + + for(int j = 0; j < h; j++) + { + int line_offset_colors; + int line_offset = j*stride; + if (ctxcanvas->canvas->invert_yaxis) + line_offset_colors = ((h - 1) - j)*w; // Fix up side down + else + line_offset_colors = j*w; + memcpy(bitmap_data + line_offset, colors + line_offset_colors, stride); + + // Fix alpha values + for(int i = 3; i < stride; i+=4) + bitmap_data[line_offset+i] = ~bitmap_data[line_offset+i]; + } + + Bitmap PatternImage(w, h, stride, PixelFormat32bppARGB, bitmap_data); + PatternImage.SetResolution(ctxcanvas->graphics->GetDpiX(), ctxcanvas->graphics->GetDpiX()); + + delete ctxcanvas->fillBrush; + ctxcanvas->fillBrush = new TextureBrush(&PatternImage); + + delete bitmap_data; +} + +static int cdinteriorstyle(cdCtxCanvas* ctxcanvas, int style) +{ + switch (style) + { + case CD_SOLID: + delete ctxcanvas->fillBrush; + ctxcanvas->fillBrush = new SolidBrush(ctxcanvas->fg); + break; + 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 void cdline(cdCtxCanvas* ctxcanvas, int x1, int y1, int x2, int y2) +{ + ctxcanvas->graphics->DrawLine(ctxcanvas->linePen, x1, y1, x2, y2); + ctxcanvas->dirty = 1; +} + +static void cdrect(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + Rect rect(xmin, ymin, xmax-xmin, ymax-ymin); // in this case Size = Max - Min + ctxcanvas->graphics->DrawRectangle(ctxcanvas->linePen, rect); + ctxcanvas->dirty = 1; +} + +static void cdbox(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax) +{ + Rect rect(xmin, ymin, xmax-xmin+1, ymax-ymin+1); + if (ctxcanvas->canvas->new_region) + { + Region region(rect); + sCombineRegion(ctxcanvas, region); + } + else + { + ctxcanvas->graphics->FillRectangle(ctxcanvas->fillBrush, rect); + ctxcanvas->dirty = 1; + } +} + +static void cdwpFixAngles(cdCtxCanvas* ctxcanvas, double *angle1, double *angle2) +{ + if (ctxcanvas->canvas->invert_yaxis) + { + // GDI+ angle are clock-wise by default + *angle1 *= -1; + *angle2 *= -1; + } +} + +static void cdarc(cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double angle1, double angle2) +{ + Rect rect(xc - w/2, yc - h/2, w, h); + if (angle1 == 0 && angle2 == 360) + ctxcanvas->graphics->DrawEllipse(ctxcanvas->linePen, rect); + else + { + cdwpFixAngles(ctxcanvas, &angle1, &angle2); + ctxcanvas->graphics->DrawArc(ctxcanvas->linePen, rect, (REAL)angle1, (REAL)(angle2-angle1)); + } + ctxcanvas->dirty = 1; +} + +static void cdsector(cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double angle1, double angle2) +{ + Rect rect(xc - w/2, yc - h/2, w, h); + if (ctxcanvas->canvas->new_region) + { + GraphicsPath path; + if (angle1==0 && angle2==360) + path.AddEllipse(rect); + else + { + cdwpFixAngles(ctxcanvas, &angle1, &angle2); + path.AddPie(rect, (REAL)angle1, (REAL)(angle2-angle1)); + } + Region region(&path); + sCombineRegion(ctxcanvas, region); + } + else + { + // complete the remaining pixels using an Arc + Pen pen(ctxcanvas->fillBrush); + + if (angle1==0 && angle2==360) + { + ctxcanvas->graphics->FillEllipse(ctxcanvas->fillBrush, rect); + ctxcanvas->graphics->DrawEllipse(&pen, rect); + } + else + { + cdwpFixAngles(ctxcanvas, &angle1, &angle2); + ctxcanvas->graphics->FillPie(ctxcanvas->fillBrush, rect, (REAL)angle1, (REAL)(angle2-angle1)); + ctxcanvas->graphics->DrawArc(&pen, rect, (REAL)angle1, (REAL)(angle2-angle1)); + } + ctxcanvas->dirty = 1; + } +} + +static void cdchord(cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double angle1, double angle2) +{ + Rect rect(xc - w/2, yc - h/2, w, h); + if (ctxcanvas->canvas->new_region) + { + GraphicsPath path; + if (angle1==0 && angle2==360) + path.AddEllipse(rect); + else + { + cdwpFixAngles(ctxcanvas, &angle1, &angle2); + path.AddArc(rect, (REAL)angle1, (REAL)(angle2-angle1)); + path.CloseFigure(); + } + Region region(&path); + sCombineRegion(ctxcanvas, region); + } + else + { + if (angle1==0 && angle2==360) + ctxcanvas->graphics->FillEllipse(ctxcanvas->fillBrush, rect); + else + { + GraphicsPath path; + cdwpFixAngles(ctxcanvas, &angle1, &angle2); + path.AddArc(rect, (REAL)angle1, (REAL)(angle2-angle1)); + ctxcanvas->graphics->FillPath(ctxcanvas->fillBrush, &path); + } + Pen pen(ctxcanvas->fillBrush); // complete the remaining pixels using an Arc + ctxcanvas->graphics->DrawArc(&pen, rect, (REAL)angle1, (REAL)(angle2-angle1)); + ctxcanvas->dirty = 1; + } +} + +static void cdpoly(cdCtxCanvas* ctxcanvas, int mode, cdPoint* poly, int n) +{ + switch( mode ) + { + case CD_BEZIER: + if (n < 4) return; + ctxcanvas->graphics->DrawBeziers(ctxcanvas->linePen, (Point*)poly, n); + break; + case CD_FILLSPLINE: + if (n < 4) return; + if (ctxcanvas->canvas->new_region) + { + GraphicsPath path(ctxcanvas->canvas->fill_mode==CD_EVENODD?FillModeAlternate:FillModeWinding); + path.AddClosedCurve((Point*)poly, n); + Region region(&path); + sCombineRegion(ctxcanvas, region); + } + else + ctxcanvas->graphics->FillClosedCurve(ctxcanvas->fillBrush, (Point*)poly, n); + break; + case CD_SPLINE: + if (n < 4) return; + ctxcanvas->graphics->DrawClosedCurve(ctxcanvas->linePen, (Point*)poly, n); + break; + case CD_CLOSED_LINES: + poly[n].x = poly[0].x; + poly[n].y = poly[0].y; + n++; + /* continue */ + case CD_OPEN_LINES: + ctxcanvas->graphics->DrawLines(ctxcanvas->linePen, (Point*)poly, n); + break; + case CD_FILLGRADIENT: + { + int count = n; + PathGradientBrush* brush = new PathGradientBrush((Point*)poly, n); + brush->SetSurroundColors(ctxcanvas->pathGradient, &count); + brush->SetCenterColor(ctxcanvas->pathGradient[n]); + ctxcanvas->graphics->FillPolygon(brush, (Point*)poly, n, ctxcanvas->canvas->fill_mode==CD_EVENODD?FillModeAlternate:FillModeWinding); + } + break; + case CD_FILL: + poly[n].x = poly[0].x; + poly[n].y = poly[0].y; + n++; + if (ctxcanvas->canvas->new_region) + { + GraphicsPath path(ctxcanvas->canvas->fill_mode==CD_EVENODD?FillModeAlternate:FillModeWinding); + path.AddPolygon((Point*)poly, n); + Region region(&path); + sCombineRegion(ctxcanvas, region); + } + else + ctxcanvas->graphics->FillPolygon(ctxcanvas->fillBrush, (Point*)poly, n, ctxcanvas->canvas->fill_mode==CD_EVENODD?FillModeAlternate:FillModeWinding); + break; + case CD_CLIP: + poly[n].x = poly[0].x; + poly[n].y = poly[0].y; + n++; + + if (ctxcanvas->clip_poly) + delete[] ctxcanvas->clip_poly; + + ctxcanvas->clip_poly = new Point [n]; + + Point* pnt = (Point*)poly; + int t = n; + int nc = 1; + + ctxcanvas->clip_poly[0] = *pnt; + pnt++; + + for (int i = 1; i < t-1; i++, pnt++) + { + if (!((pnt->X == ctxcanvas->clip_poly[nc-1].X && pnt->X == (pnt + 1)->X) || + (pnt->Y == ctxcanvas->clip_poly[nc-1].Y && pnt->Y == (pnt + 1)->Y))) + { + ctxcanvas->clip_poly[nc] = *pnt; + nc++; + } + } + + ctxcanvas->clip_poly_n = nc; + + if (ctxcanvas->canvas->clip_mode == CD_CLIPPOLYGON) + sClipPoly(ctxcanvas); + + break; + } + + ctxcanvas->dirty = 1; +} + +WCHAR* cdwpString2Unicode(const char* s, int len) +{ + static WCHAR wstr[10240] = L""; + if (len >= 10240) len = 10239; + MultiByteToWideChar(CP_ACP, 0, s, -1, wstr, len+1); + return wstr; +} + +static int cdwpCompensateHeight(int height) +{ + return (int)floor(height/10. + 0.5); /* 10% */ +} + +static void cdgettextsize(cdCtxCanvas* ctxcanvas, const char *s, int *width, int *height) +{ + RectF boundingBox; + int len = strlen(s); + + ctxcanvas->graphics->MeasureString(cdwpString2Unicode(s, len), len, + ctxcanvas->font, PointF(0,0), + &boundingBox); + if (width) + *width = (int)boundingBox.Width; + + if (height) + *height = (int)boundingBox.Height - cdwpCompensateHeight(ctxcanvas->fontinfo.height); +} + +static void sTextBox(cdCtxCanvas* ctxcanvas, WCHAR *ws, int len, int x, int y, int *w, int *h, int *xmin, int *ymin) +{ + int ydir = 1; + if (ctxcanvas->canvas->invert_yaxis) + ydir = -1; + + RectF boundingBox; + ctxcanvas->graphics->MeasureString(ws, len, + ctxcanvas->font, PointF(0,0), + &boundingBox); + *w = (int)boundingBox.Width; + *h = (int)boundingBox.Height - cdwpCompensateHeight(ctxcanvas->fontinfo.height); + + // distance from bottom to baseline + int baseline = ctxcanvas->fontinfo.height - ctxcanvas->fontinfo.ascent; + + // move to bottom-left + cdTextTranslatePoint(ctxcanvas->canvas, x, y, *w, *h, baseline, xmin, ymin); + + // move to top-left + *ymin += ydir * (*h); +} + +static void cdwpCanvasGetTextHeight(cdCanvas* canvas, int x, int y, const char *s, int w, int h, int *hbox) +{ + int xmin, xmax, ymin, ymax; + + // distance from bottom to baseline + int baseline = canvas->ctxcanvas->fontinfo.height - canvas->ctxcanvas->fontinfo.ascent; + + /* move to bottom-left */ + cdTextTranslatePoint(canvas, x, y, w, h, baseline, &xmin, &ymin); + + xmax = xmin + w-1; + ymax = ymin + h-1; + + if (canvas->text_orientation) + { + double cos_theta = cos(canvas->text_orientation*CD_DEG2RAD); + double sin_theta = sin(canvas->text_orientation*CD_DEG2RAD); + int rectY[4]; + + cdRotatePointY(canvas, xmin, ymin, x, y, &rectY[0], sin_theta, cos_theta); + cdRotatePointY(canvas, xmax, ymin, x, y, &rectY[1], sin_theta, cos_theta); + cdRotatePointY(canvas, xmax, ymax, x, y, &rectY[2], sin_theta, cos_theta); + cdRotatePointY(canvas, xmin, ymax, x, y, &rectY[3], sin_theta, cos_theta); + + ymin = ymax = rectY[0]; + if (rectY[1] < ymin) ymin = rectY[1]; + if (rectY[2] < ymin) ymin = rectY[2]; + if (rectY[3] < ymin) ymin = rectY[3]; + if (rectY[1] > ymax) ymax = rectY[1]; + if (rectY[2] > ymax) ymax = rectY[2]; + if (rectY[3] > ymax) ymax = rectY[3]; + } + + *hbox = ymax-ymin+1; +} + +static void cdwpTextTransform(cdCtxCanvas* ctxcanvas, const char* s, int *x, int *y, int w, int h, Matrix &transformMatrix) +{ + int hbox; + double* matrix = ctxcanvas->canvas->matrix; + Matrix m1; + + cdwpCanvasGetTextHeight(ctxcanvas->canvas, *x, *y, s, w, h, &hbox); + + // configure a bottom-up coordinate system + m1.SetElements((REAL)1, (REAL)0, (REAL)0, (REAL)-1, (REAL)0, (REAL)(ctxcanvas->canvas->h-1)); + transformMatrix.Multiply(&m1); + + // add the global transform + m1.SetElements((REAL)matrix[0], (REAL)matrix[1], (REAL)matrix[2], (REAL)matrix[3], (REAL)matrix[4], (REAL)matrix[5]); + transformMatrix.Multiply(&m1); + + // move to (x,y) and remove a vertical offset since text reference point is top-left + m1.SetElements((REAL)1, (REAL)0, (REAL)0, (REAL)1, (REAL)*x, (REAL)(*y - (hbox-1))); + transformMatrix.Multiply(&m1); + + // invert the text vertical orientation, relative to itself + m1.SetElements((REAL)1, (REAL)0, (REAL)0, (REAL)-1, (REAL)0, (REAL)(hbox-1)); + transformMatrix.Multiply(&m1); + + *x = 0; + *y = 0; +} + +static void cdtext(cdCtxCanvas* ctxcanvas, int x, int y, const char *s) +{ + Matrix transformMatrix; + int len = strlen(s), use_transform = 0, w, h; + WCHAR* ws = cdwpString2Unicode(s, len); + + if (ctxcanvas->canvas->text_orientation) + { + transformMatrix.Translate((REAL)x, (REAL)y); + transformMatrix.Rotate((REAL)-ctxcanvas->canvas->text_orientation); + transformMatrix.Translate((REAL)-x, (REAL)-y); + use_transform = 1; + } + + // Move (x,y) to top-left + sTextBox(ctxcanvas, ws, len, x, y, &w, &h, &x, &y); + + if (ctxcanvas->canvas->use_matrix) + { + cdwpTextTransform(ctxcanvas, s, &x, &y, w, h, transformMatrix); + use_transform = 1; + } + else if (cdwpSetTransform(ctxcanvas, transformMatrix, NULL)) + use_transform = 1; + + if (ctxcanvas->canvas->new_region) + { + GraphicsPath path(ctxcanvas->canvas->fill_mode==CD_EVENODD?FillModeAlternate:FillModeWinding); + + if (use_transform) + path.Transform(&transformMatrix); + + FontFamily family; + ctxcanvas->font->GetFamily(&family); + path.AddString(ws, len, &family, ctxcanvas->font->GetStyle(), + ctxcanvas->font->GetSize(), + Point(x, y), NULL); + + Region region(&path); + sCombineRegion(ctxcanvas, region); + return; + } + + if (use_transform) + ctxcanvas->graphics->SetTransform(&transformMatrix); + + ctxcanvas->graphics->DrawString(ws, len, + ctxcanvas->font, PointF((REAL)x, (REAL)y), + ctxcanvas->lineBrush); + + if (use_transform) + cdwpUpdateTransform(ctxcanvas); // reset transform + + ctxcanvas->dirty = 1; +} + +static int sDesign2Pixel(int x, REAL size, int height) +{ + return (int)((x * size) / height); +} + +static int cdfont(cdCtxCanvas* ctxcanvas, const char *type_face, int style, int size) +{ + FontFamily* fontFamily; + + if (cdStrEqualNoCase(type_face, "Courier") || cdStrEqualNoCase(type_face, "Monospace")) + fontFamily = new FontFamily(L"Courier New"); + else if (cdStrEqualNoCase(type_face, "Times") || cdStrEqualNoCase(type_face, "Serif")) + fontFamily = new FontFamily(L"Times New Roman"); + else if (cdStrEqualNoCase(type_face, "Helvetica") || cdStrEqualNoCase(type_face, "Sans")) + fontFamily = new FontFamily(L"Arial"); + else if (cdStrEqualNoCase(type_face, "System")) + fontFamily = FontFamily::GenericSansSerif()->Clone(); + else + fontFamily = new FontFamily(cdwpString2Unicode(type_face, strlen(type_face))); + + REAL emSize = (REAL)(cdGetFontSizePixels(ctxcanvas->canvas, size)); + + INT fontStyle = FontStyleRegular; + if (style&CD_BOLD) fontStyle |= FontStyleBold; + if (style&CD_ITALIC) fontStyle |= FontStyleItalic; + if (style&CD_UNDERLINE) fontStyle |= FontStyleUnderline; + if (style&CD_STRIKEOUT) fontStyle |= FontStyleStrikeout; + + if (ctxcanvas->font) delete ctxcanvas->font; + ctxcanvas->font = new Font(fontFamily, emSize, fontStyle, UnitPixel); + + REAL fontSize = ctxcanvas->font->GetSize(); + int emHeight = fontFamily->GetEmHeight(fontStyle); + ctxcanvas->fontinfo.height = sDesign2Pixel(fontFamily->GetLineSpacing(fontStyle), fontSize, emHeight); + ctxcanvas->fontinfo.ascent = sDesign2Pixel(fontFamily->GetCellAscent(fontStyle), fontSize, emHeight); + ctxcanvas->fontinfo.descent = sDesign2Pixel(fontFamily->GetCellDescent(fontStyle), fontSize, emHeight); + + delete fontFamily; + + return 1; +} + +static int cdnativefont(cdCtxCanvas* ctxcanvas, const char* nativefont) +{ + int size = 12, bold = 0, italic = 0, underline = 0, strikeout = 0, style = CD_PLAIN; + char type_face[1024]; + + if (nativefont[0] == '-' && nativefont[1] == 'd') + { + COLORREF rgbColors; + LOGFONT lf; + ctxcanvas->font->GetLogFontA(ctxcanvas->graphics, &lf); + + CHOOSEFONT cf; + ZeroMemory(&cf, sizeof(CHOOSEFONT)); + + cf.lStructSize = sizeof(CHOOSEFONT); + cf.hwndOwner = GetForegroundWindow(); + cf.lpLogFont = &lf; + cf.Flags = CF_SCREENFONTS | CF_EFFECTS | CF_INITTOLOGFONTSTRUCT; + rgbColors = cf.rgbColors = ctxcanvas->fg.ToCOLORREF(); + + if (!ChooseFont(&cf)) + return 0; + + if (rgbColors != cf.rgbColors) + cdCanvasSetForeground(ctxcanvas->canvas, cdEncodeColor(GetRValue(cf.rgbColors),GetGValue(cf.rgbColors),GetBValue(cf.rgbColors))); + + bold = lf.lfWeight>FW_NORMAL? 1: 0; + italic = lf.lfItalic; + size = lf.lfHeight; + strcpy(type_face, lf.lfFaceName); + underline = lf.lfUnderline; + strikeout = lf.lfStrikeOut; + + if (bold) style |= CD_BOLD; + if (italic) style |= CD_ITALIC; + if (underline) style |= CD_UNDERLINE; + if (strikeout) style |= CD_STRIKEOUT; + } + else + { + if (!cdParseIupWinFont(nativefont, type_face, &style, &size)) + { + if (!cdParsePangoFont(nativefont, type_face, &style, &size)) + return 0; + } + + if (style&CD_BOLD) + bold = 1; + if (style&CD_ITALIC) + italic = 1; + if (style&CD_UNDERLINE) + underline = 1; + if (style&CD_STRIKEOUT) + strikeout = 1; + } + + REAL emSize = (REAL)(cdGetFontSizePixels(ctxcanvas->canvas, size)); + + INT fontStyle = FontStyleRegular; + if (bold) fontStyle |= FontStyleBold; + if (italic) fontStyle |= FontStyleItalic; + if (underline) fontStyle |= FontStyleUnderline; + if (strikeout) fontStyle |= FontStyleStrikeout; + + const char* new_type_face = type_face; + if (strstr(type_face, "Times") != NULL) + new_type_face = "Times"; + + if (strstr(type_face, "Courier") != NULL) + new_type_face = "Courier"; + + if (strstr(type_face, "Arial") != NULL) + new_type_face = "Helvetica"; + + if (strstr(type_face, "Helv") != NULL) + new_type_face = "Helvetica"; + + FontFamily *fontFamily; + if (strstr(type_face, "System") != NULL) + { + new_type_face = "System"; + fontFamily = FontFamily::GenericSansSerif()->Clone(); + } + else + fontFamily = new FontFamily(cdwpString2Unicode(type_face, strlen(type_face))); + + if (!fontFamily->IsAvailable()) + { + delete fontFamily; + return 0; + } + + Font* font = new Font(fontFamily, emSize, fontStyle, UnitPixel); + if (!font->IsAvailable()) + { + delete fontFamily; + delete font; + return 0; + } + + if (ctxcanvas->font) delete ctxcanvas->font; + ctxcanvas->font = font; + + REAL fontSize = ctxcanvas->font->GetSize(); + int emHeight = fontFamily->GetEmHeight(fontStyle); + ctxcanvas->fontinfo.height = sDesign2Pixel(fontFamily->GetLineSpacing(fontStyle), fontSize, emHeight); + ctxcanvas->fontinfo.ascent = sDesign2Pixel(fontFamily->GetCellAscent(fontStyle), fontSize, emHeight); + ctxcanvas->fontinfo.descent = sDesign2Pixel(fontFamily->GetCellDescent(fontStyle), fontSize, emHeight); + + delete fontFamily; + + /* update cdfont parameters */ + ctxcanvas->canvas->font_style = style; + ctxcanvas->canvas->font_size = size; + strcpy(ctxcanvas->canvas->font_type_face, new_type_face); + + return 1; +} + +static void cdgetfontdim(cdCtxCanvas* ctxcanvas, int *max_width, int *line_height, int *ascent, int *descent) +{ + if (max_width) + { + RectF boundingBox; + ctxcanvas->graphics->MeasureString(L"W", 2, + ctxcanvas->font, PointF(0,0), + &boundingBox); + *max_width = (int)(boundingBox.Width/2); + } + + if (line_height) + *line_height = ctxcanvas->fontinfo.height; + + if (ascent) + *ascent = ctxcanvas->fontinfo.ascent; + + if (descent) + *descent = ctxcanvas->fontinfo.descent; +} + +static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix) +{ + Matrix transformMatrix; + ctxcanvas->graphics->ResetTransform(); // reset to the identity. + + if (matrix) + ctxcanvas->canvas->invert_yaxis = 0; + else + ctxcanvas->canvas->invert_yaxis = 1; + + if (cdwpSetTransform(ctxcanvas, transformMatrix, matrix)) + ctxcanvas->graphics->SetTransform(&transformMatrix); +} + +static void cdclear(cdCtxCanvas* ctxcanvas) +{ + if (ctxcanvas->canvas->clip_mode != CD_CLIPOFF) + ctxcanvas->graphics->ResetClip(); + + ctxcanvas->graphics->Clear(sSetAlpha(ctxcanvas->bg, (BYTE)255)); + + if (ctxcanvas->canvas->clip_mode != CD_CLIPOFF) + cdclip(ctxcanvas, ctxcanvas->canvas->clip_mode); + + ctxcanvas->dirty = 1; +} + +/******************************************************************/ +/* +%S Funcoes de imagens do cliente +*/ +/******************************************************************/ + +static void sRGB2Bitmap(Bitmap& image, int width, int height, const unsigned char *red, + const unsigned char *green, + const unsigned char *blue, + int xmin, int xmax, int ymin, int ymax, int topdown) +{ + BitmapData bitmapData; + Rect rect(0,0,image.GetWidth(),image.GetHeight()); + image.LockBits(&rect, ImageLockModeWrite, PixelFormat24bppRGB, &bitmapData); + + int line_offset; + for(int j = 0; j < rect.Height; j++) + { + if (topdown) + line_offset = (height - (ymax - j) - 1)*width; + else + line_offset = (ymax - j)*width; + + BYTE* line_data = (BYTE*)bitmapData.Scan0 + j*bitmapData.Stride; + + for(int i = 0; i < rect.Width; i++) + { + int offset = line_offset + i + xmin; + int offset_data = i*3; + line_data[offset_data+0] = blue[offset]; + line_data[offset_data+1] = green[offset]; + line_data[offset_data+2] = red[offset]; + } + } + + image.UnlockBits(&bitmapData); +} + +static void sRGBA2Bitmap(Bitmap& image, int width, int height, const unsigned char *red, + const unsigned char *green, + const unsigned char *blue, + const unsigned char *alpha, + int xmin, int xmax, int ymin, int ymax, int topdown) +{ + BitmapData bitmapData; + Rect rect(0,0,image.GetWidth(),image.GetHeight()); + image.LockBits(&rect, ImageLockModeWrite, PixelFormat32bppARGB, &bitmapData); + + int line_offset; + for(int j = 0; j < rect.Height; j++) + { + if (topdown) + line_offset = (height - (ymax - j) - 1)*width; + else + line_offset = (ymax - j)*width; + + BYTE* line_data = (BYTE*)bitmapData.Scan0 + j*bitmapData.Stride; + + for(int i = 0; i < rect.Width; i++) + { + int offset = line_offset + i + xmin; + int offset_data = i*4; + line_data[offset_data+0] = blue? blue[offset]: 0; + line_data[offset_data+1] = green? green[offset]: 0; + line_data[offset_data+2] = red? red[offset]: 0; + line_data[offset_data+3] = alpha[offset]; + } + } + + image.UnlockBits(&bitmapData); +} + +static void sAlpha2Bitmap(Bitmap& image, int width, int height, const unsigned char *alpha, + int xmin, int xmax, int ymin, int ymax, int topdown) +{ + BitmapData bitmapData; + Rect rect(0,0,image.GetWidth(),image.GetHeight()); + image.LockBits(&rect, ImageLockModeWrite, PixelFormat32bppARGB, &bitmapData); + + int line_offset; + for(int j = 0; j < rect.Height; j++) + { + if (topdown) + line_offset = (height - (ymax - j) - 1)*width; + else + line_offset = (ymax - j)*width; + + BYTE* line_data = (BYTE*)bitmapData.Scan0 + j*bitmapData.Stride; + + for(int i = 0; i < rect.Width; i++) + { + int offset = line_offset + i + xmin; + int offset_data = i*4; + line_data[offset_data+3] = alpha[offset]; + } + } + + image.UnlockBits(&bitmapData); +} + +/* +GDI+ does not natively work with palettized images. + +GDI+ will not try to draw on a palettized image as it would +require color reducing the drawing result. + +GDI+ will work natively with 32bpp image data behind the scenes anyway so +there is no economy in trying to work with 8bpp images. + +Full support for palettized images was on the feature list but it did not +make the cut for version 1 of GDI+. +*/ + +static void sMap2Bitmap(Bitmap& image, int width, int height, const unsigned char *index, + const long int *colors, + int xmin, int xmax, int ymin, int ymax, int topdown) +{ + BitmapData bitmapData; + Rect rect(0,0,image.GetWidth(),image.GetHeight()); + image.LockBits(&rect, ImageLockModeWrite, PixelFormat24bppRGB, &bitmapData); + + int line_offset; + for(int j = 0; j < rect.Height; j++) + { + if (topdown) + line_offset = (height - (ymax - j) - 1)*width; + else + line_offset = (ymax - j)*width; + + BYTE* line_data = (BYTE*)bitmapData.Scan0 + j*bitmapData.Stride; + + for(int i = 0; i < rect.Width; i++) + { + int map_index = index[line_offset + i + xmin]; + long color = colors[map_index]; + + int offset_data = i*3; + line_data[offset_data+0] = cdBlue(color); + line_data[offset_data+1] = cdGreen(color); + line_data[offset_data+2] = cdRed(color); + } + } + + image.UnlockBits(&bitmapData); +} + +static void sBitmap2RGB(Bitmap& image, unsigned char *red, unsigned char *green, unsigned char *blue) +{ + BitmapData bitmapData; + Rect rect(0,0,image.GetWidth(),image.GetHeight()); + image.LockBits(&rect, ImageLockModeRead, PixelFormat24bppRGB, &bitmapData); + + for(int j = 0; j < rect.Height; j++) + { + int line_offset = ((rect.Height-1) - j)*rect.Width; + + BYTE* line_data = (BYTE*)bitmapData.Scan0 + j*bitmapData.Stride; + + for(int i = 0; i < rect.Width; i++) + { + int offset = line_offset + i; + int offset_data = i*3; + blue[offset] = line_data[offset_data+0]; + green[offset] = line_data[offset_data+1]; + red[offset] = line_data[offset_data+2]; + } + } + + image.UnlockBits(&bitmapData); +} + +static void cdgetimagergb(cdCtxCanvas* ctxcanvas, unsigned char *red, unsigned char *green, unsigned char *blue, + int x, int y, int w, int h) +{ + Matrix transformMatrix; + ctxcanvas->graphics->GetTransform(&transformMatrix); + if (!transformMatrix.IsIdentity()) + ctxcanvas->graphics->ResetTransform(); // reset to the identity. + + if (ctxcanvas->canvas->invert_yaxis==0) // if 0, then the transform was reset + y = _cdInvertYAxis(ctxcanvas->canvas, y); + + int yr = y - (h - 1); /* y starts at the bottom of the image */ + Bitmap image(w, h, PixelFormat24bppRGB); + image.SetResolution(ctxcanvas->graphics->GetDpiX(), ctxcanvas->graphics->GetDpiX()); + + Graphics* imggraphics = new Graphics(&image); + + if (ctxcanvas->wtype == CDW_BMP) + { + imggraphics->DrawImage(ctxcanvas->bitmap, + Rect(0, 0, w, h), + x, yr, w, h, UnitPixel, + NULL, NULL, NULL); + } + else + { + HDC hdc = ctxcanvas->graphics->GetHDC(); + HDC img_hdc = imggraphics->GetHDC(); + + BitBlt(img_hdc,0,0,w,h,hdc,x,yr,SRCCOPY); + + imggraphics->ReleaseHDC(img_hdc); + ctxcanvas->graphics->ReleaseHDC(hdc); + } + + delete imggraphics; + + sBitmap2RGB(image, red, green, blue); + + if (!transformMatrix.IsIdentity()) + ctxcanvas->graphics->SetTransform(&transformMatrix); +} + +static void sFixImageY(cdCanvas* canvas, int *topdown, int *y, int *h) +{ + if (canvas->invert_yaxis) + { + if (*h < 0) + *topdown = 1; + else + *topdown = 0; + } + else + { + if (*h < 0) + *topdown = 0; + else + *topdown = 1; + } + + if (*h < 0) + *h = -(*h); // y is at top-left corner (UNDOCUMENTED FEATURE) + + if (!(*topdown)) + *y -= ((*h) - 1); // move Y to top-left corner, since it was at the bottom of the image +} + +static void cdputimagerectmap(cdCtxCanvas* ctxcanvas, int width, int height, 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 topdown; + Bitmap image(xmax-xmin+1, ymax-ymin+1, PixelFormat24bppRGB); + image.SetResolution(ctxcanvas->graphics->GetDpiX(), ctxcanvas->graphics->GetDpiX()); + + sFixImageY(ctxcanvas->canvas, &topdown, &y, &h); + sMap2Bitmap(image, width, height, index, colors, xmin, xmax, ymin, ymax, topdown); + + ImageAttributes imageAttributes; + if (ctxcanvas->use_img_transp) + imageAttributes.SetColorKey(ctxcanvas->img_transp[0], ctxcanvas->img_transp[1], ColorAdjustTypeBitmap); + + if(ctxcanvas->use_img_points) + { + Point pts[3]; + pts[0] = ctxcanvas->img_points[0]; + pts[1] = ctxcanvas->img_points[1]; + pts[2] = ctxcanvas->img_points[2]; + if (ctxcanvas->canvas->invert_yaxis) + { + pts[0].Y = _cdInvertYAxis(ctxcanvas->canvas, pts[0].Y); + pts[1].Y = _cdInvertYAxis(ctxcanvas->canvas, pts[1].Y); + pts[2].Y = _cdInvertYAxis(ctxcanvas->canvas, pts[2].Y); + } + ctxcanvas->graphics->DrawImage(&image, pts, 3, + 0, 0, image.GetWidth(), image.GetHeight(), UnitPixel, + &imageAttributes, NULL, NULL); + } + else + { + REAL bw = (REAL)image.GetWidth(); + REAL bh = (REAL)image.GetHeight(); + if (w > bw) bw-=0.5; // Fix the problem of not using PixelOffsetModeHalf + if (h > bh) bh-=0.5; + ctxcanvas->graphics->DrawImage(&image, RectF((REAL)x, (REAL)y, (REAL)w, (REAL)h), + 0, 0, bw, bh, UnitPixel, + &imageAttributes, NULL, NULL); + } + + ctxcanvas->dirty = 1; +} + +static void cdputimagerectrgb(cdCtxCanvas* ctxcanvas, int width, int height, const unsigned char *red, + const unsigned char *green, + const unsigned char *blue, + int x, int y, int w, int h, + int xmin, int xmax, int ymin, int ymax) +{ + int topdown; + Bitmap image(xmax-xmin+1, ymax-ymin+1, PixelFormat24bppRGB); + image.SetResolution(ctxcanvas->graphics->GetDpiX(), ctxcanvas->graphics->GetDpiX()); + + sFixImageY(ctxcanvas->canvas, &topdown, &y, &h); + sRGB2Bitmap(image, width, height, red, green, blue, xmin, xmax, ymin, ymax, topdown); + + ImageAttributes imageAttributes; + if (ctxcanvas->use_img_transp) + imageAttributes.SetColorKey(ctxcanvas->img_transp[0], ctxcanvas->img_transp[1], ColorAdjustTypeBitmap); + + if(ctxcanvas->use_img_points) + { + Point pts[3]; + pts[0] = ctxcanvas->img_points[0]; + pts[1] = ctxcanvas->img_points[1]; + pts[2] = ctxcanvas->img_points[2]; + if (ctxcanvas->canvas->invert_yaxis) + { + pts[0].Y = _cdInvertYAxis(ctxcanvas->canvas, pts[0].Y); + pts[1].Y = _cdInvertYAxis(ctxcanvas->canvas, pts[1].Y); + pts[2].Y = _cdInvertYAxis(ctxcanvas->canvas, pts[2].Y); + } + ctxcanvas->graphics->DrawImage(&image, pts, 3, + 0, 0, image.GetWidth(), image.GetHeight(), UnitPixel, + &imageAttributes, NULL, NULL); + } + else + { + REAL bw = (REAL)image.GetWidth(); + REAL bh = (REAL)image.GetHeight(); + if (w > bw) bw-=0.5; // Fix the problem of not using PixelOffsetModeHalf + if (h > bh) bh-=0.5; + ctxcanvas->graphics->DrawImage(&image, RectF((REAL)x, (REAL)y, (REAL)w, (REAL)h), + 0, 0, bw, bh, UnitPixel, + &imageAttributes, NULL, NULL); + } + + ctxcanvas->dirty = 1; +} + +static void cdputimagerectrgba(cdCtxCanvas* ctxcanvas, int width, int height, const unsigned char *red, + const unsigned char *green, + const unsigned char *blue, + const unsigned char *alpha, + int x, int y, int w, int h, + int xmin, int xmax, int ymin, int ymax) +{ + int topdown; + Bitmap image(xmax-xmin+1, ymax-ymin+1, PixelFormat32bppARGB); + image.SetResolution(ctxcanvas->graphics->GetDpiX(), ctxcanvas->graphics->GetDpiX()); + + sFixImageY(ctxcanvas->canvas, &topdown, &y, &h); + sRGBA2Bitmap(image, width, height, red, green, blue, alpha, xmin, xmax, ymin, ymax, topdown); + + ImageAttributes imageAttributes; + if(ctxcanvas->use_img_points) + { + Point pts[3]; + pts[0] = ctxcanvas->img_points[0]; + pts[1] = ctxcanvas->img_points[1]; + pts[2] = ctxcanvas->img_points[2]; + if (ctxcanvas->canvas->invert_yaxis) + { + pts[0].Y = _cdInvertYAxis(ctxcanvas->canvas, pts[0].Y); + pts[1].Y = _cdInvertYAxis(ctxcanvas->canvas, pts[1].Y); + pts[2].Y = _cdInvertYAxis(ctxcanvas->canvas, pts[2].Y); + } + ctxcanvas->graphics->DrawImage(&image, pts, 3, + 0, 0, image.GetWidth(), image.GetHeight(), UnitPixel, + &imageAttributes, NULL, NULL); + } + else + { + REAL bw = (REAL)image.GetWidth(); + REAL bh = (REAL)image.GetHeight(); + if (w > bw) bw-=0.5; // Fix the problem of not using PixelOffsetModeHalf + if (h > bh) bh-=0.5; + ctxcanvas->graphics->DrawImage(&image, RectF((REAL)x, (REAL)y, (REAL)w, (REAL)h), + 0, 0, bw, bh, UnitPixel, + &imageAttributes, NULL, NULL); + } + + ctxcanvas->dirty = 1; +} + +/********************************************************************/ +/* +%S Funcoes de imagens do servidor +*/ +/********************************************************************/ + +static void cdpixel(cdCtxCanvas* ctxcanvas, int x, int y, long int cd_color) +{ + if (!ctxcanvas->graphics->IsVisible(x, y)) + return; + + if (ctxcanvas->wtype == CDW_BMP) + { + ctxcanvas->bitmap->SetPixel(x, y, sColor2Windows(cd_color)); + } + else + { + if (ctxcanvas->canvas->use_matrix) + { + Point p = Point(x, y); + ctxcanvas->graphics->TransformPoints(CoordinateSpacePage, CoordinateSpaceWorld, &p, 1); + x = p.X; + y = p.Y; + } + HDC hdc = ctxcanvas->graphics->GetHDC(); + SetPixelV(hdc, x, y, sColor2Windows(cd_color).ToCOLORREF()); + ctxcanvas->graphics->ReleaseHDC(hdc); + } + + ctxcanvas->dirty = 1; +} + +static int sFormat2Bpp(PixelFormat pixelFormat) +{ + switch(pixelFormat) + { + case PixelFormat1bppIndexed: + return 1; + case PixelFormat4bppIndexed: + return 4; + case PixelFormat8bppIndexed: + return 8; + case PixelFormat16bppARGB1555: + case PixelFormat16bppGrayScale: + case PixelFormat16bppRGB555: + case PixelFormat16bppRGB565: + return 16; + case PixelFormat24bppRGB: + return 24; + case PixelFormat32bppARGB: + case PixelFormat32bppPARGB: + case PixelFormat32bppRGB: + return 32; + case PixelFormat48bppRGB: + return 48; + case PixelFormat64bppARGB: + case PixelFormat64bppPARGB: + return 64; + } + + return 0; +} + +static cdCtxImage *cdcreateimage(cdCtxCanvas* ctxcanvas, int width, int height) +{ + cdCtxImage *ctximage = new cdCtxImage; + ctximage->alpha = NULL; + + if (ctxcanvas->img_format) + { + ctximage->bitmap = new Bitmap(width, height, ctxcanvas->img_format==24? PixelFormat24bppRGB: PixelFormat32bppARGB); + if (!ctximage->bitmap) + { + delete ctximage; + return NULL; + } + + if (ctxcanvas->img_format==32 && ctxcanvas->img_alpha) + ctximage->alpha = ctxcanvas->img_alpha; + + ctximage->bitmap->SetResolution(ctxcanvas->graphics->GetDpiX(), ctxcanvas->graphics->GetDpiX()); + } + else + { + ctximage->bitmap = new Bitmap(width, height, ctxcanvas->graphics); + if (!ctximage->bitmap) + { + delete ctximage; + return NULL; + } + } + + ctximage->w = width; + ctximage->h = height; + + ctximage->bpp = sFormat2Bpp(ctximage->bitmap->GetPixelFormat()); + ctximage->xres = ctximage->bitmap->GetHorizontalResolution() / 25.4; + ctximage->yres = ctximage->bitmap->GetVerticalResolution() / 25.4; + + ctximage->w_mm = ctximage->w / ctximage->xres; + ctximage->h_mm = ctximage->h / ctximage->yres; + + Graphics imggraphics(ctximage->bitmap); + imggraphics.Clear(Color::White); + + return ctximage; +} + +static void cdgetimage(cdCtxCanvas* ctxcanvas, cdCtxImage *ctximage, int x, int y) +{ + Matrix transformMatrix; + ctxcanvas->graphics->GetTransform(&transformMatrix); + if (!transformMatrix.IsIdentity()) + ctxcanvas->graphics->ResetTransform(); // reset to the identity. + + if (ctxcanvas->canvas->invert_yaxis==0) // if 0, then the transform was reset + y = _cdInvertYAxis(ctxcanvas->canvas, y); + + int yr = y - (ctximage->h - 1); /* y0 starts at the bottom of the image */ + + if (ctxcanvas->wtype == CDW_BMP) + { + Graphics imggraphics(ctximage->bitmap); + + imggraphics.DrawImage(ctxcanvas->bitmap, + Rect(0, 0, ctximage->w,ctximage->h), + x, yr, ctximage->w, ctximage->h, UnitPixel, + NULL, NULL, NULL); + } + else + { + Graphics imggraphics(ctximage->bitmap); + + HDC hdc = ctxcanvas->graphics->GetHDC(); + HDC img_hdc = imggraphics.GetHDC(); + + BitBlt(img_hdc,0,0,ctximage->w,ctximage->h,hdc,x,yr,SRCCOPY); + + imggraphics.ReleaseHDC(img_hdc); + ctxcanvas->graphics->ReleaseHDC(hdc); + } + + if (!transformMatrix.IsIdentity()) + ctxcanvas->graphics->SetTransform(&transformMatrix); +} + +static void cdputimagerect(cdCtxCanvas* ctxcanvas, cdCtxImage *ctximage, int x0, int y0, int xmin, int xmax, int ymin, int ymax) +{ + int yr = y0 - (ymax-ymin+1)+1; /* y0 starts at the bottom of the image */ + + INT srcx = xmin; + INT srcy = (ctximage->h-1)-ymax; + INT srcwidth = xmax-xmin+1; + INT srcheight = ymax-ymin+1; + Rect destRect(x0, yr, srcwidth, srcheight); + + ImageAttributes imageAttributes; + + if (ctxcanvas->use_img_transp) + imageAttributes.SetColorKey(ctxcanvas->img_transp[0], ctxcanvas->img_transp[1], ColorAdjustTypeBitmap); + + if (ctximage->bpp == 32 && ctximage->alpha) + { + sAlpha2Bitmap(*ctximage->bitmap, ctximage->w, ctximage->h, ctximage->alpha, + 0, ctximage->w-1, 0, ctximage->h-1, 0); + } + + if(ctxcanvas->use_img_points) + { + Point pts[3]; + pts[0] = ctxcanvas->img_points[0]; + pts[1] = ctxcanvas->img_points[1]; + pts[2] = ctxcanvas->img_points[2]; + if (ctxcanvas->canvas->invert_yaxis) + { + pts[0].Y = _cdInvertYAxis(ctxcanvas->canvas, pts[0].Y); + pts[1].Y = _cdInvertYAxis(ctxcanvas->canvas, pts[1].Y); + pts[2].Y = _cdInvertYAxis(ctxcanvas->canvas, pts[2].Y); + } + ctxcanvas->graphics->DrawImage(ctximage->bitmap, pts, 3, + srcx, srcy, srcwidth, srcheight, UnitPixel, + &imageAttributes, NULL, NULL); + } + else + { + ctxcanvas->graphics->DrawImage(ctximage->bitmap, destRect, + srcx, srcy, srcwidth, srcheight, UnitPixel, + &imageAttributes, NULL, NULL); + } + + ctxcanvas->dirty = 1; +} + +static void cdkillimage(cdCtxImage *ctximage) +{ + delete ctximage->bitmap; + delete ctximage; +} + +static void cdscrollarea(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax, int dx, int dy) +{ + Matrix transformMatrix; + ctxcanvas->graphics->GetTransform(&transformMatrix); + if (!transformMatrix.IsIdentity()) + ctxcanvas->graphics->ResetTransform(); // reset to the identity. + + if (ctxcanvas->canvas->invert_yaxis==0) // if 0, then the transform was reset + { + dy = -dy; + ymin = _cdInvertYAxis(ctxcanvas->canvas, ymin); + ymax = _cdInvertYAxis(ctxcanvas->canvas, ymax); + _cdSwapInt(ymin, ymax); + } + + if (ctxcanvas->wtype == CDW_BMP) + { + Rect rect(xmin, ymin, xmax-xmin+1, ymax-ymin+1); + + Bitmap* bitmap = ctxcanvas->bitmap->Clone(rect, ctxcanvas->bitmap->GetPixelFormat()); + + rect.Offset(dx, dy); + + ctxcanvas->graphics->DrawImage(bitmap, rect, + 0, 0, rect.Width, rect.Height, UnitPixel, + NULL, NULL, NULL); + delete bitmap; + } + else + { + RECT rect; + rect.left = xmin; + rect.right = xmax+1; + rect.top = ymin; + rect.bottom = ymax+1; + + HDC hdc = ctxcanvas->graphics->GetHDC(); + ScrollDC(hdc, dx, dy, &rect, NULL, NULL, NULL); + ctxcanvas->graphics->ReleaseHDC(hdc); + } + + ctxcanvas->dirty = 1; + + if (!transformMatrix.IsIdentity()) + ctxcanvas->graphics->SetTransform(&transformMatrix); +} + +static void cdflush(cdCtxCanvas* ctxcanvas) +{ + ctxcanvas->graphics->Flush(FlushIntentionSync); +} + +/********************************************************************/ +/* +%S Atributos personalizados +*/ +/********************************************************************/ + +static void set_img_format_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (!data) + ctxcanvas->img_format = 0; + else + { + int bpp = 0; + sscanf(data, "%d", &bpp); + if (bpp == 0) + return; + + if (bpp == 32) + ctxcanvas->img_format = 32; + else + ctxcanvas->img_format = 24; + } +} + +static char* get_img_format_attrib(cdCtxCanvas* ctxcanvas) +{ + if (!ctxcanvas->img_format) + return NULL; + + if (ctxcanvas->img_format == 32) + return "32"; + else + return "24"; +} + +static cdAttribute img_format_attrib = +{ + "IMAGEFORMAT", + set_img_format_attrib, + get_img_format_attrib +}; + +static void set_img_alpha_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (!data) + ctxcanvas->img_alpha = NULL; + else + ctxcanvas->img_alpha = (unsigned char*)data; +} + +static char* get_img_alpha_attrib(cdCtxCanvas* ctxcanvas) +{ + return (char*)ctxcanvas->img_alpha; +} + +static cdAttribute img_alpha_attrib = +{ + "IMAGEALPHA", + set_img_alpha_attrib, + get_img_alpha_attrib +}; + +static void set_img_transp_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (!data) + ctxcanvas->use_img_transp = 0; + else + { + int r1, g1, b1, r2, g2, b2; + ctxcanvas->use_img_transp = 1; + sscanf(data, "%d %d %d %d %d %d", &r1, &g1, &b1, &r2, &g2, &b2); + ctxcanvas->img_transp[0] = Color((BYTE)r1, (BYTE)g1, (BYTE)b1); + ctxcanvas->img_transp[1] = Color((BYTE)r2, (BYTE)g2, (BYTE)b2); + } +} + + +static char* get_img_transp_attrib(cdCtxCanvas* ctxcanvas) +{ + if (!ctxcanvas->use_img_transp) + return NULL; + + int r1 = ctxcanvas->img_transp[0].GetRed(); + int g1 = ctxcanvas->img_transp[0].GetGreen(); + int b1 = ctxcanvas->img_transp[0].GetBlue(); + int r2 = ctxcanvas->img_transp[1].GetRed(); + int g2 = ctxcanvas->img_transp[1].GetGreen(); + int b2 = ctxcanvas->img_transp[1].GetBlue(); + + static char data[50]; + sprintf(data, "%d %d %d %d %d %d", r1, g1, b1, r2, g2, b2); + return data; +} + +static cdAttribute img_transp_attrib = +{ + "IMAGETRANSP", + set_img_transp_attrib, + get_img_transp_attrib +}; + +static void set_gradientcolor_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + // used by CD_FILLGRADIENT + if (data) + { + int r, g, b, cur_vertex; + sscanf(data, "%d %d %d", &r, &g, &b); + + cur_vertex = ctxcanvas->canvas->poly_n; + if (cur_vertex < 500) + ctxcanvas->pathGradient[cur_vertex] = Color((BYTE)r, (BYTE)g, (BYTE)b); + } +} + +static cdAttribute gradientcolor_attrib = +{ + "GRADIENTCOLOR", + set_gradientcolor_attrib, + NULL +}; + +static void set_linegradient_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (data) + { + int x1, y1, x2, y2; + sscanf(data, "%d %d %d %d", &x1, &y1, &x2, &y2); + + Point p1 = Point(x1, y1); + Point p2 = Point(x2, y2); + ctxcanvas->gradient[0] = p1; + ctxcanvas->gradient[1] = p2; + if (ctxcanvas->canvas->invert_yaxis) + { + p1.Y = _cdInvertYAxis(ctxcanvas->canvas, p1.Y); + p2.Y = _cdInvertYAxis(ctxcanvas->canvas, p2.Y); + } + delete ctxcanvas->fillBrush; + ctxcanvas->fillBrush = new LinearGradientBrush(p1, p2, ctxcanvas->fg, ctxcanvas->bg); + } +} + +static char* get_linegradient_attrib(cdCtxCanvas* ctxcanvas) +{ + static char data[100]; + + sprintf(data, "%d %d %d %d", ctxcanvas->gradient[0].X, + ctxcanvas->gradient[0].Y, + ctxcanvas->gradient[1].X, + ctxcanvas->gradient[1].Y); + + return data; +} + +static cdAttribute linegradient_attrib = +{ + "LINEGRADIENT", + set_linegradient_attrib, + get_linegradient_attrib +}; + +static void set_linecap_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (data) + { + LineCap cap = LineCapFlat; + + switch(data[0]) + { + case 'T': + cap = LineCapTriangle; + ctxcanvas->linePen->SetDashCap(DashCapTriangle); + break; + case 'N': + cap = LineCapNoAnchor; + break; + case 'S': + cap = LineCapSquareAnchor; + break; + case 'R': + cap = LineCapRoundAnchor; + break; + case 'D': + cap = LineCapDiamondAnchor; + break; + case 'A': + cap = LineCapArrowAnchor; + break; + default: + return; + } + + ctxcanvas->linePen->SetStartCap(cap); + ctxcanvas->linePen->SetEndCap(cap); + } +} + +static cdAttribute linecap_attrib = +{ + "LINECAP", + set_linecap_attrib, + NULL +}; + +static void set_rotate_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + /* ignore ROTATE if transform is set */ + 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; + } + + cdwpUpdateTransform(ctxcanvas); +} + +static char* get_rotate_attrib(cdCtxCanvas* ctxcanvas) +{ + static char data[100]; + + 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_img_points_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + int p[6]; + + if (!data) + { + ctxcanvas->use_img_points = 0; + return; + } + + sscanf(data, "%d %d %d %d %d %d", &p[0], &p[1], &p[2], &p[3], &p[4], &p[5]); + + ctxcanvas->img_points[0] = Point(p[0], p[1]); + ctxcanvas->img_points[1] = Point(p[2], p[3]); + ctxcanvas->img_points[2] = Point(p[4], p[5]); + + ctxcanvas->use_img_points = 1; +} + +static char* get_img_points_attrib(cdCtxCanvas* ctxcanvas) +{ + static char data[100]; + + if (!ctxcanvas->use_img_points) + return NULL; + + sprintf(data, "%d %d %d %d %d %d", ctxcanvas->img_points[0].X, + ctxcanvas->img_points[0].Y, + ctxcanvas->img_points[1].X, + ctxcanvas->img_points[1].Y, + ctxcanvas->img_points[2].X, + ctxcanvas->img_points[2].Y); + + return data; +} + +static cdAttribute img_points_attrib = +{ + "IMAGEPOINTS", + set_img_points_attrib, + get_img_points_attrib +}; + +static BOOL Is_WinXP_or_Later(void) +{ + OSVERSIONINFO osvi; + ZeroMemory(&osvi, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx (&osvi); + + BOOL bIsWindowsXPorLater = + (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) && + ( (osvi.dwMajorVersion > 5) || ( (osvi.dwMajorVersion == 5) && + (osvi.dwMinorVersion >= 1))); + + return bIsWindowsXPorLater; +} + +static void set_aa_attrib(cdCtxCanvas* ctxcanvas, char* data) +{ + if (!data || data[0] == '0') + { + ctxcanvas->graphics->SetInterpolationMode(InterpolationModeNearestNeighbor); + ctxcanvas->graphics->SetSmoothingMode(SmoothingModeNone); + ctxcanvas->graphics->SetTextRenderingHint(TextRenderingHintSingleBitPerPixelGridFit); + ctxcanvas->antialias = 0; + } + else + { + ctxcanvas->graphics->SetInterpolationMode(InterpolationModeBilinear); + ctxcanvas->graphics->SetSmoothingMode(SmoothingModeAntiAlias); + if (Is_WinXP_or_Later()) + ctxcanvas->graphics->SetTextRenderingHint(TextRenderingHintClearTypeGridFit); + else + ctxcanvas->graphics->SetTextRenderingHint(TextRenderingHintAntiAliasGridFit); +/* ctxcanvas->graphics->SetPixelOffsetMode(PixelOffsetModeHalf); + Do NOT set PixelOffsetMode because some graphic objects move their position and size. +*/ + ctxcanvas->antialias = 1; + } +} + +static char* get_aa_attrib(cdCtxCanvas* ctxcanvas) +{ + if (ctxcanvas->antialias) + return "1"; + else + return "0"; +} + +static cdAttribute aa_attrib = +{ + "ANTIALIAS", + set_aa_attrib, + get_aa_attrib +}; + +static void set_window_rgn(cdCtxCanvas* ctxcanvas, char* data) +{ + if (data) + { + HRGN hrgn = ctxcanvas->new_region->GetHRGN(ctxcanvas->graphics); + SetWindowRgn(ctxcanvas->hWnd, hrgn, TRUE); + } + else + SetWindowRgn(ctxcanvas->hWnd, NULL, TRUE); +} + +static cdAttribute window_rgn_attrib = +{ + "WINDOWRGN", + set_window_rgn, + NULL +}; + +static char* get_hdc_attrib(cdCtxCanvas* ctxcanvas) +{ + return (char*)ctxcanvas->hDC; +} + +static cdAttribute hdc_attrib = +{ + "HDC", + NULL, + get_hdc_attrib +}; + +static char* get_gdiplus_attrib(cdCtxCanvas* ctxcanvas) +{ + return "1"; +} + +static cdAttribute gdiplus_attrib = +{ + "GDI+", + NULL, + get_gdiplus_attrib +}; + +void cdwpUpdateCanvas(cdCtxCanvas* ctxcanvas) +{ + if (ctxcanvas->wtype == CDW_EMF && ctxcanvas->metafile) // first update metafile is NULL. + { + MetafileHeader metaHeader; + ctxcanvas->metafile->GetMetafileHeader(&metaHeader); + ctxcanvas->canvas->xres = metaHeader.GetDpiX() / 25.4; + ctxcanvas->canvas->yres = metaHeader.GetDpiY() / 25.4; + } + else + { + ctxcanvas->canvas->xres = ctxcanvas->graphics->GetDpiX() / 25.4; + ctxcanvas->canvas->yres = ctxcanvas->graphics->GetDpiY() / 25.4; + } + + ctxcanvas->canvas->w_mm = ((double)ctxcanvas->canvas->w) / ctxcanvas->canvas->xres; + ctxcanvas->canvas->h_mm = ((double)ctxcanvas->canvas->h) / ctxcanvas->canvas->yres; + + ctxcanvas->graphics->SetPageScale(1); + ctxcanvas->graphics->SetPageUnit(UnitPixel); + ctxcanvas->graphics->SetCompositingMode(CompositingModeSourceOver); + ctxcanvas->graphics->SetCompositingQuality(CompositingQualityDefault); + + if (ctxcanvas->antialias) + set_aa_attrib(ctxcanvas, "1"); + else + set_aa_attrib(ctxcanvas, NULL); + + cdwpUpdateTransform(ctxcanvas); +} + +/* +%F Cria o canvas para o driver Windows. +*/ +cdCtxCanvas *cdwpCreateCanvas(cdCanvas* canvas, Graphics* graphics, int wtype) +{ + cdCtxCanvas* ctxcanvas = new cdCtxCanvas; + memset(ctxcanvas, 0, sizeof(cdCtxCanvas)); + + /* update canvas context */ + ctxcanvas->canvas = canvas; + canvas->ctxcanvas = ctxcanvas; + + ctxcanvas->wtype = wtype; + ctxcanvas->graphics = graphics; + + ctxcanvas->linePen = new Pen(Color()); + ctxcanvas->lineBrush = new SolidBrush(Color()); + ctxcanvas->fillBrush = new SolidBrush(Color()); + ctxcanvas->font = NULL; // will be created in the update default attrib + + set_aa_attrib(ctxcanvas, "1"); // default is ANTIALIAS=1 + + ctxcanvas->fg = Color(); // black + ctxcanvas->bg = Color(255, 255, 255); // white + + canvas->invert_yaxis = 1; + + ctxcanvas->clip_poly = NULL; + ctxcanvas->clip_poly_n = 0; + ctxcanvas->clip_region = NULL; + ctxcanvas->new_region = NULL; + + cdRegisterAttribute(canvas, &img_points_attrib); + cdRegisterAttribute(canvas, &img_transp_attrib); + cdRegisterAttribute(canvas, &img_format_attrib); + cdRegisterAttribute(canvas, &img_alpha_attrib); + cdRegisterAttribute(canvas, &aa_attrib); + cdRegisterAttribute(canvas, &gradientcolor_attrib); + cdRegisterAttribute(canvas, &linegradient_attrib); + cdRegisterAttribute(canvas, &rotate_attrib); + cdRegisterAttribute(canvas, &linecap_attrib); + cdRegisterAttribute(canvas, &hdc_attrib); + cdRegisterAttribute(canvas, &window_rgn_attrib); + cdRegisterAttribute(canvas, &gdiplus_attrib); + + cdwpUpdateCanvas(ctxcanvas); + + return ctxcanvas; +} + +static ULONG_PTR cd_gdiplusToken = NULL; + +static void __stdcall DebugEvent(DebugEventLevel level, char* msg) +{ + MessageBox(NULL, msg, "GDI+ Debug", 0); +} + +void cdwpGdiPlusStartup(int debug) +{ + if (cd_gdiplusToken == NULL) + { + GdiplusStartupInput input; + if (debug) + input.DebugEventCallback = DebugEvent; + + // Initialize GDI+. + GdiplusStartup(&cd_gdiplusToken, &input, NULL); + } +} + +void cdwpGdiPlusShutdown(void) +{ + if (cd_gdiplusToken) + GdiplusShutdown(cd_gdiplusToken); +} + +void cdwpInitTable(cdCanvas* canvas) +{ + cdCtxCanvas* ctxcanvas = canvas->ctxcanvas; + + canvas->cxFlush = cdflush; + 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->cxNewRegion = cdnewregion; + canvas->cxIsPointInRegion = cdispointinregion; + canvas->cxOffsetRegion = cdoffsetregion; + canvas->cxGetRegionBox = cdgetregionbox; + + canvas->cxGetFontDim = cdgetfontdim; + canvas->cxGetTextSize = cdgettextsize; + canvas->cxPutImageRectRGB = cdputimagerectrgb; + canvas->cxPutImageRectMap = cdputimagerectmap; + canvas->cxPutImageRectRGBA = cdputimagerectrgba; + + canvas->cxClip = cdclip; + canvas->cxClipArea = cdcliparea; + canvas->cxBackOpacity = cdbackopacity; + 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->cxNativeFont = cdnativefont; + canvas->cxBackground = cdbackground; + canvas->cxForeground = cdforeground; + canvas->cxPalette = cdpalette; + canvas->cxTransform = cdtransform; + + if (ctxcanvas->wtype == CDW_WIN || ctxcanvas->wtype == CDW_BMP) + { + canvas->cxClear = cdclear; + + canvas->cxGetImageRGB = cdgetimagergb; + + canvas->cxCreateImage = cdcreateimage; + canvas->cxGetImage = cdgetimage; + canvas->cxPutImageRect = cdputimagerect; + canvas->cxKillImage = cdkillimage; + + canvas->cxScrollArea = cdscrollarea; + } +} diff --git a/src/gdiplus/cdwinp.h b/src/gdiplus/cdwinp.h new file mode 100644 index 0000000..0c4ae55 --- /dev/null +++ b/src/gdiplus/cdwinp.h @@ -0,0 +1,112 @@ +/** \file + * \brief Windows GDI+ Base Driver + * + * See Copyright Notice in cd.h + */ + +#ifndef __CDWINP_H +#define __CDWINP_H + +#include <windows.h> +#include <gdiplus.h> +using namespace Gdiplus; + +#include "cd.h" +#include "cd_private.h" + + +/* Contexto de cada imagem no servidor */ +struct _cdCtxImage +{ + Bitmap *bitmap; /* bitmap associado */ + int w; /* largura da imagem */ + int h; /* altura da imagem */ + double w_mm, h_mm; /* size in mm */ + double xres, yres; /* resolution in pixels/mm */ + int bpp; + unsigned char* alpha; /* the alpha values must be stored here to be used at putimage */ +}; + +/* Contexto de todos os canvas GDI+ (CanvasContext). */ +struct _cdCtxCanvas +{ + cdCanvas* canvas; + + Graphics *graphics; + + Pen *linePen; + SolidBrush *lineBrush; + Brush *fillBrush; + Color fg, bg; /* foreground, backgound */ + Font *font; + + struct + { + int height; + int ascent; + int descent; + } fontinfo; + + Point *clip_poly; /* coordenadas do pixel no X,Y */ + int clip_poly_n; /* numero de pontos correntes */ + Region *clip_region; + + Region *new_region; + + int max_points; + PointF *wdpoly; // cache buffer for wdpoly + Point *cdpoly; // alias to cache buffer (float=int) + + int antialias; + + Point gradient[2]; + + Color pathGradient[500]; + + int img_format; + unsigned char* img_alpha; + + float rotate_angle; + int rotate_center_x, + rotate_center_y; + + Point img_points[3]; + int use_img_points; + + Color img_transp[2]; + int use_img_transp; + + int wtype; /* Flag indicando qual o tipo de superficie */ + + HWND hWnd; /* CDW_WIN handle */ + HDC hDC; /* GDI Device Context handle */ + int release_dc; + + HANDLE printerHandle; // Used by the printer driver + + Metafile* metafile; /* CDW_EMF handle */ + Bitmap* bitmap; /* CDW_BMP handle */ + + int dirty; // Used by the double buffer driver + CachedBitmap* bitmap_dbuffer; /* not the image_dbuffer, just a cache */ + cdCanvas* canvas_dbuffer; +}; + +enum{CDW_WIN, CDW_BMP, CDW_EMF}; + +cdCtxCanvas *cdwpCreateCanvas(cdCanvas* canvas, Graphics* graphics, int wtype); +void cdwpKillCanvas(cdCtxCanvas* ctxcanvas); + +void cdwpInitTable(cdCanvas* canvas); +void cdwpUpdateCanvas(cdCtxCanvas* canvas); + +WCHAR* cdwpString2Unicode(const char* s, int len); +void cdwpShowStatus(const char* title, Status status); + +extern "C" { +void cdwpGdiPlusStartup(int debug); +void cdwpGdiPlusShutdown(void); +} + +#endif /* ifndef CDWINP_H */ + diff --git a/src/gdiplus/cdwnativep.cpp b/src/gdiplus/cdwnativep.cpp new file mode 100644 index 0000000..fffd044 --- /dev/null +++ b/src/gdiplus/cdwnativep.cpp @@ -0,0 +1,138 @@ +/** \file + * \brief Windows GDI+ Native Window Driver + * + * See Copyright Notice in cd.h + */ + +#include "cdwinp.h" +#include "cdnative.h" +#include <stdlib.h> +#include <stdio.h> + + +static int cdactivate(cdCtxCanvas* ctxcanvas) +{ + if (ctxcanvas->hWnd) + { + RECT rect; + GetClientRect(ctxcanvas->hWnd, &rect); + int w = rect.right - rect.left; + int h = rect.bottom - rect.top; + int bpp = cdGetScreenColorPlanes(); + + if(ctxcanvas->canvas->w != w || + ctxcanvas->canvas->h != h || + ctxcanvas->canvas->bpp != bpp) + { + ctxcanvas->canvas->w = w; + ctxcanvas->canvas->h = h; + ctxcanvas->canvas->bpp = bpp; + + delete ctxcanvas->graphics; + ctxcanvas->graphics = new Graphics(ctxcanvas->hWnd); + + cdwpUpdateCanvas(ctxcanvas); + } + } + + return CD_OK; +} + +static void cdkillcanvas(cdCtxCanvas* ctxcanvas) +{ + cdwpKillCanvas(ctxcanvas); + + if (ctxcanvas->release_dc) + ReleaseDC(ctxcanvas->hWnd, ctxcanvas->hDC); + + delete ctxcanvas; +} + +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + HWND hWnd = NULL; + HDC hDC = NULL; + Graphics* graphics; + int release_dc = 0; + + if (!data) + { + hDC = GetDC(NULL); + release_dc = 1; + + canvas->w = GetDeviceCaps(hDC, HORZRES); + canvas->h = GetDeviceCaps(hDC, VERTRES); + + graphics = new Graphics(hDC); + } + else if (IsWindow((HWND)data)) + { + hWnd = (HWND)data; + release_dc = 0; + + RECT rect; + GetClientRect(hWnd, &rect); + canvas->w = rect.right - rect.left; + canvas->h = rect.bottom - rect.top; + + graphics = new Graphics(hWnd); + } + else /* can be a HDC or a string */ + { + DWORD objtype = GetObjectType((HGDIOBJ)data); + if (objtype == OBJ_DC || objtype == OBJ_MEMDC || + objtype == OBJ_ENHMETADC || objtype == OBJ_METADC) + { + hDC = (HDC)data; + canvas->w = GetDeviceCaps(hDC, HORZRES); + canvas->h = GetDeviceCaps(hDC, VERTRES); + } + else + { + hDC = NULL; + canvas->w = 0; + canvas->h = 0; + sscanf((char*)data,"%p %dx%d", &hDC, &canvas->w, &canvas->h); + + if (!hDC || !canvas->w || !canvas->h) + return; + } + + graphics = new Graphics(hDC); + release_dc = 0; + } + + canvas->bpp = cdGetScreenColorPlanes(); + + /* Inicializa driver WIN32 */ + cdCtxCanvas* ctxcanvas = cdwpCreateCanvas(canvas, graphics, CDW_WIN); + ctxcanvas->hWnd = hWnd; + ctxcanvas->hDC = hDC; + ctxcanvas->release_dc = release_dc; +} + +static void cdinittable(cdCanvas* canvas) +{ + cdwpInitTable(canvas); + + canvas->cxKillCanvas = cdkillcanvas; + canvas->cxActivate = cdactivate; +} + +static cdContext cdNativeContext = +{ + CD_CAP_ALL & ~(CD_CAP_FLUSH | CD_CAP_PLAY | CD_CAP_YAXIS | + CD_CAP_FPRIMTIVES ), + 1, + cdcreatecanvas, + cdinittable, + NULL, + NULL, +}; + +extern "C" { +cdContext* cdContextNativeWindowPlus(void) +{ + return &cdNativeContext; +} +} diff --git a/src/gdiplus/cdwprnp.cpp b/src/gdiplus/cdwprnp.cpp new file mode 100644 index 0000000..3d2b9f7 --- /dev/null +++ b/src/gdiplus/cdwprnp.cpp @@ -0,0 +1,158 @@ +/** \file + * \brief Windows GDI+ Printer Driver + * + * See Copyright Notice in cd.h + */ + +#include "cdwinp.h" +#include "cdprint.h" +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +/* +%F cdKillCanvas para Printer. +Termina a pagina e termina o documento, enviando-o para a impressora. +*/ +static void cdkillcanvas (cdCtxCanvas* ctxcanvas) +{ + cdwpKillCanvas(ctxcanvas); + + EndPage(ctxcanvas->hDC); + EndDoc(ctxcanvas->hDC); + + ClosePrinter(ctxcanvas->printerHandle); + DeleteDC(ctxcanvas->hDC); + + delete ctxcanvas; +} + +/* +%F cdFlush para Printer. +Termina uma pagina e inicia outra. +*/ +static void cdflush(cdCtxCanvas* ctxcanvas) +{ + delete ctxcanvas->graphics; + EndPage(ctxcanvas->hDC); + + StartPage(ctxcanvas->hDC); + ctxcanvas->graphics = new Graphics(ctxcanvas->hDC, ctxcanvas->printerHandle); + + cdwpUpdateCanvas(ctxcanvas); +} + +static void cdcreatecanvas(cdCanvas* canvas, void *data) +{ + char *data_str = (char*) data; + char docname[256] = "CD - Canvas Draw Document"; + int dialog = 0; + + /* Inicializa parametros */ + if (data_str == NULL) + return; + + if (data_str[0] != 0) + { + const char *ptr = strstr(data_str, "-d"); + + if (ptr != NULL) + dialog = 1; + + if (data_str[0] != '-') + { + strcpy(docname, data_str); + + if (dialog) + docname[ptr - data_str - 1] = 0; + } + } + + PRINTDLG pd; + ZeroMemory(&pd, sizeof(PRINTDLG)); + pd.lStructSize = sizeof(PRINTDLG); + pd.nCopies = 1; + + if (dialog) + { + pd.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE | PD_COLLATE | PD_NOPAGENUMS | PD_NOSELECTION; + pd.hwndOwner = GetForegroundWindow(); + } + else + { + pd.Flags = PD_RETURNDC | PD_RETURNDEFAULT; + } + + if (!PrintDlg(&pd)) + { + if(pd.hDevMode) + GlobalFree(pd.hDevMode); + if(pd.hDevNames) + GlobalFree(pd.hDevNames); + return; + } + + HDC hDC = pd.hDC; + + DEVMODE* devideMode = (DEVMODE*)GlobalLock(pd.hDevMode); + HANDLE printerHandle; + OpenPrinter((char*)devideMode->dmDeviceName, &printerHandle, NULL); + GlobalUnlock(pd.hDevMode); + + { + /* Inicializa documento */ + DOCINFO docInfo; + ZeroMemory(&docInfo, sizeof(docInfo)); + docInfo.cbSize = sizeof(docInfo); + docInfo.lpszDocName = docname; + + StartDoc(hDC, &docInfo); + } + + StartPage(hDC); + + canvas->w = GetDeviceCaps(hDC, HORZRES); + canvas->h = GetDeviceCaps(hDC, VERTRES); + canvas->bpp = GetDeviceCaps(hDC, BITSPIXEL); + + Graphics* graphics = new Graphics(hDC, printerHandle); + + /* Inicializa driver WIN32 */ + cdCtxCanvas* ctxcanvas = cdwpCreateCanvas(canvas, graphics, CDW_EMF); + + ctxcanvas->hDC = hDC; + ctxcanvas->printerHandle = printerHandle; + + if(pd.hDevMode) + GlobalFree(pd.hDevMode); + if(pd.hDevNames) + GlobalFree(pd.hDevNames); +} + +static void cdinittable(cdCanvas* canvas) +{ + cdwpInitTable(canvas); + + canvas->cxKillCanvas = cdkillcanvas; + canvas->cxFlush = cdflush; +} + +static cdContext cdPrinterContext = +{ + CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_PLAY | CD_CAP_YAXIS | + CD_CAP_FPRIMTIVES | + CD_CAP_GETIMAGERGB | CD_CAP_IMAGESRV), + 1, + cdcreatecanvas, + cdinittable, + NULL, + NULL +}; + +extern "C" { +cdContext* cdContextPrinterPlus(void) +{ + return &cdPrinterContext; +} +} + |