summaryrefslogtreecommitdiff
path: root/src/win32
diff options
context:
space:
mode:
Diffstat (limited to 'src/win32')
-rw-r--r--src/win32/cdwclp.c551
-rw-r--r--src/win32/cdwdbuf.c169
-rw-r--r--src/win32/cdwdib.c662
-rw-r--r--src/win32/cdwemf.c117
-rw-r--r--src/win32/cdwimg.c83
-rw-r--r--src/win32/cdwin.c2368
-rw-r--r--src/win32/cdwin.h181
-rw-r--r--src/win32/cdwnative.c209
-rw-r--r--src/win32/cdwprn.c184
-rw-r--r--src/win32/cdwwmf.c109
-rw-r--r--src/win32/wmf_emf.c2121
11 files changed, 6754 insertions, 0 deletions
diff --git a/src/win32/cdwclp.c b/src/win32/cdwclp.c
new file mode 100644
index 0000000..e39cb7f
--- /dev/null
+++ b/src/win32/cdwclp.c
@@ -0,0 +1,551 @@
+/** \file
+ * \brief Windows Clipboard Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "cdwin.h"
+#include "cdclipbd.h"
+#include "cdmf.h"
+#include "cdemf.h"
+#include "cdwmf.h"
+#include "cdmf_private.h"
+
+
+static cdSizeCB cdsizecb = NULL;
+
+static int cdregistercallback(int cb, cdCallback func)
+{
+ switch (cb)
+ {
+ case CD_SIZECB:
+ cdsizecb = (cdSizeCB)func;
+ return CD_OK;
+ }
+
+ return CD_ERROR;
+}
+
+/*
+%F cdPlay para Clipboard.
+Interpreta os dados do clipboard, seja metafile ou bitmap.
+*/
+static int cdplay(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax, void *data)
+{
+ char tmpPath[512];
+ char filename[1024];
+ HANDLE hFile;
+ DWORD dwSize, nBytesWrite;
+ int err;
+ char* buffer;
+
+ if (IsClipboardFormatAvailable(CF_TEXT))
+ {
+ HANDLE Handle;
+
+ GetTempPath(512, tmpPath);
+ GetTempFileName(tmpPath, "~cd", 0, filename);
+
+ OpenClipboard(NULL);
+ Handle = GetClipboardData(CF_TEXT);
+ if (Handle == NULL)
+ {
+ CloseClipboard();
+ return CD_ERROR;
+ }
+
+ buffer = (char*)GlobalLock(Handle);
+ dwSize = (DWORD)strlen(buffer);
+
+ hFile = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
+ WriteFile(hFile, buffer, dwSize, &nBytesWrite, NULL);
+ CloseHandle(hFile);
+
+ GlobalUnlock(Handle);
+
+ CloseClipboard();
+
+ err = cdCanvasPlay(canvas, CD_METAFILE, xmin, xmax, ymin, ymax, filename);
+
+ DeleteFile(filename);
+
+ if (err == CD_OK)
+ return err;
+ }
+
+ if (IsClipboardFormatAvailable(CF_ENHMETAFILE))
+ {
+ HENHMETAFILE Handle;
+
+ GetTempPath(512, tmpPath);
+ GetTempFileName(tmpPath, "~cd", 0, filename);
+
+ OpenClipboard(NULL);
+ Handle = (HENHMETAFILE)GetClipboardData(CF_ENHMETAFILE);
+ if (Handle == NULL)
+ {
+ CloseClipboard();
+ return CD_ERROR;
+ }
+
+ dwSize = GetEnhMetaFileBits(Handle, 0, NULL);
+
+ buffer = (char*)malloc(dwSize);
+
+ GetEnhMetaFileBits(Handle, dwSize, buffer);
+
+ hFile = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
+ WriteFile(hFile, buffer, dwSize, &nBytesWrite, NULL);
+ CloseHandle(hFile);
+
+ free(buffer);
+
+ CloseClipboard();
+
+ err = cdCanvasPlay(canvas, CD_EMF, xmin, xmax, ymin, ymax, filename);
+
+ DeleteFile(filename);
+
+ return err;
+ }
+
+ if (IsClipboardFormatAvailable(CF_METAFILEPICT))
+ {
+ HANDLE Handle;
+ METAFILEPICT* lpMFP;
+
+ GetTempPath(512, tmpPath);
+ GetTempFileName(tmpPath, "~cd", 0, filename);
+
+ OpenClipboard(NULL);
+ Handle = GetClipboardData(CF_METAFILEPICT);
+ if (Handle == NULL)
+ {
+ CloseClipboard();
+ return CD_ERROR;
+ }
+
+ lpMFP = (METAFILEPICT*) GlobalLock(Handle);
+
+ dwSize = GetMetaFileBitsEx(lpMFP->hMF, 0, NULL);
+ buffer = (char*)malloc(dwSize);
+
+ GetMetaFileBitsEx(lpMFP->hMF, dwSize, buffer);
+
+ hFile = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
+ wmfWritePlacebleFile(hFile, buffer, dwSize, lpMFP->mm, lpMFP->xExt, lpMFP->yExt);
+ CloseHandle(hFile);
+
+ GlobalUnlock(Handle);
+ free(buffer);
+
+ CloseClipboard();
+
+ err = cdCanvasPlay(canvas, CD_WMF, xmin, xmax, ymin, ymax, filename);
+
+ DeleteFile(filename);
+
+ return err;
+ }
+
+ if (IsClipboardFormatAvailable(CF_DIB))
+ {
+ HANDLE Handle;
+ int size;
+ cdwDIB dib;
+
+ OpenClipboard(NULL);
+ Handle = GetClipboardData(CF_DIB);
+ if (Handle == NULL)
+ {
+ CloseClipboard();
+ return CD_ERROR;
+ }
+
+ cdwDIBReference(&dib, (BYTE*) GlobalLock(Handle), NULL);
+
+ if (dib.type == -1)
+ {
+ GlobalUnlock(Handle);
+ CloseClipboard();
+ return CD_ERROR;
+ }
+
+ if (cdsizecb)
+ {
+ int err;
+ err = cdsizecb(canvas, dib.w, dib.h, dib.w, dib.h);
+ if (err)
+ {
+ GlobalUnlock(Handle);
+ CloseClipboard();
+ return CD_ERROR;
+ }
+ }
+
+ size = dib.w*dib.h;
+
+ if (xmax == 0) xmax = dib.w + xmin - 1;
+ if (ymax == 0) ymax = dib.h + ymin - 1;
+
+ if (dib.type == 0)
+ {
+ char *r, *g, *b;
+
+ r = (char*)malloc(size);
+ g = (char*)malloc(size);
+ b = (char*)malloc(size);
+
+ cdwDIBDecodeRGB(&dib, r, g, b);
+
+ cdCanvasPutImageRectRGB(canvas, dib.w, dib.h, r, g, b, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1, 0, 0, 0, 0);
+
+ free(r);
+ free(g);
+ free(b);
+ }
+ else
+ {
+ char *index;
+ long *colors;
+
+ index = (char*)malloc(size);
+ colors = (long*)malloc(256*sizeof(long));
+
+ cdwDIBDecodeMap(&dib, index, colors);
+
+ cdCanvasPutImageRectMap(canvas, dib.w, dib.h, index, colors, xmin, ymin, xmax - xmin + 1, ymax - ymin + 1, 0, 0, 0, 0);
+
+ free(index);
+ free(colors);
+ }
+
+ GlobalUnlock(Handle);
+
+ CloseClipboard();
+
+ return CD_ERROR;
+ }
+
+ if (IsClipboardFormatAvailable(CF_BITMAP))
+ {
+ HBITMAP Handle;
+ int size, type;
+ cdwDIB dib;
+ HDC ScreenDC;
+ SIZE sz;
+
+ OpenClipboard(NULL);
+ Handle = GetClipboardData(CF_BITMAP);
+ if (Handle == NULL)
+ {
+ CloseClipboard();
+ return CD_ERROR;
+ }
+
+ GetBitmapDimensionEx(Handle, &sz);
+
+ ScreenDC = GetDC(NULL);
+ if (GetDeviceCaps(ScreenDC, BITSPIXEL) > 8)
+ type = 0;
+ else
+ type = 1;
+
+ dib.w = sz.cx;
+ dib.h = sz.cy;
+ dib.type = type;
+
+ if (cdsizecb)
+ {
+ int err;
+ err = cdsizecb(canvas, dib.w, dib.h, dib.w, dib.h);
+ if (err)
+ {
+ ReleaseDC(NULL, ScreenDC);
+ CloseClipboard();
+ return CD_ERROR;
+ }
+ }
+
+ cdwCreateDIB(&dib);
+
+ GetDIBits(ScreenDC, Handle, 0, sz.cy, dib.bits, dib.bmi, DIB_RGB_COLORS);
+ ReleaseDC(NULL, ScreenDC);
+
+ size = dib.w*dib.h;
+
+ if (dib.type == 0)
+ {
+ char *r, *g, *b;
+
+ r = (char*)malloc(size);
+ g = (char*)malloc(size);
+ b = (char*)malloc(size);
+
+ cdwDIBDecodeRGB(&dib, r, g, b);
+
+ cdCanvasPutImageRectRGB(canvas, dib.w, dib.h, r, g, b, 0, 0, dib.w, dib.h, 0, 0, 0, 0);
+
+ free(r);
+ free(g);
+ free(b);
+ }
+ else
+ {
+ char *index;
+ long *colors;
+
+ index = (char*)malloc(size);
+ colors = (long*)malloc(256*sizeof(long));
+
+ cdwDIBDecodeMap(&dib, index, colors);
+
+ cdCanvasPutImageRectMap(canvas, dib.w, dib.h, index, colors, 0, 0, dib.w, dib.h, 0, 0, 0, 0);
+
+ free(index);
+ free(colors);
+ }
+
+ cdwKillDIB(&dib);
+
+ CloseClipboard();
+
+ return CD_ERROR;
+ }
+
+ return CD_ERROR;
+}
+
+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)
+{
+ cdwKillCanvas(ctxcanvas);
+
+ OpenClipboard(NULL);
+ EmptyClipboard();
+
+ if (ctxcanvas->wtype == CDW_WMF)
+ {
+ HMETAFILE hmf = CloseMetaFile(ctxcanvas->hDC);
+
+ HANDLE hMemG;
+ METAFILEPICT* lpMFP;
+
+ hMemG = GlobalAlloc(GHND|GMEM_DDESHARE, (DWORD)sizeof(METAFILEPICT));
+ lpMFP = (METAFILEPICT*) GlobalLock(hMemG);
+
+ lpMFP->mm = MM_ANISOTROPIC;
+ lpMFP->xExt = (long)(100 * ctxcanvas->canvas->w_mm);
+ lpMFP->yExt = (long)(100 * ctxcanvas->canvas->h_mm);
+
+ lpMFP->hMF = hmf;
+
+ GlobalUnlock(hMemG);
+ SetClipboardData(CF_METAFILEPICT, hMemG);
+ }
+ else if (ctxcanvas->wtype == CDW_EMF)
+ {
+ HENHMETAFILE hmf = CloseEnhMetaFile(ctxcanvas->hDC);
+ SetClipboardData(CF_ENHMETAFILE, hmf);
+ }
+ else
+ {
+ HANDLE hDib;
+
+ GdiFlush();
+
+ hDib = cdwCreateCopyHDIB(&ctxcanvas->bmiClip, ctxcanvas->bitsClip);
+
+ SelectObject(ctxcanvas->hDC, ctxcanvas->hOldBitmapClip);
+ DeleteObject(ctxcanvas->hBitmapClip);
+ DeleteDC(ctxcanvas->hDC);
+
+ SetClipboardData(CF_DIB, hDib);
+ }
+
+ CloseClipboard();
+
+ memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
+ free(ctxcanvas);
+}
+
+static void cdcreatecanvas(cdCanvas* canvas, void *data)
+{
+ char* strsize = (char*)data;
+ int w = 0, h = 0, wtype = CDW_EMF; /* default clipboard type */
+ double xres=0, yres=0;
+ HDC hDC;
+ BITMAPINFO bmi;
+ BYTE* bits;
+ HBITMAP hBitmapClip, hOldBitmapClip;
+
+ /* 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",&w, &h);
+ if (w == 0 || h == 0)
+ return;
+ }
+
+ if (wtype == CDW_EMF)
+ {
+ HDC ScreenDC = GetDC(NULL);
+ RECT rect;
+ /* LOGPIXELS can not be used for EMF */
+ xres = (double)GetDeviceCaps(ScreenDC, HORZRES) / (double)GetDeviceCaps(ScreenDC, HORZSIZE);
+ yres = (double)GetDeviceCaps(ScreenDC, VERTRES) / (double)GetDeviceCaps(ScreenDC, VERTSIZE);
+ rect.left = 0;
+ rect.top = 0;
+ rect.right = (int)(100. * w / xres);
+ rect.bottom = (int)(100. * h / yres);
+ hDC = CreateEnhMetaFile(ScreenDC,NULL,&rect,NULL);
+ ReleaseDC(NULL, ScreenDC);
+ }
+ else if (wtype == CDW_BMP)
+ {
+ HDC ScreenDC = GetDC(NULL);
+ hDC = CreateCompatibleDC(ScreenDC);
+ xres = (double)GetDeviceCaps(ScreenDC, HORZRES) / (double)GetDeviceCaps(ScreenDC, HORZSIZE);
+ yres = (double)GetDeviceCaps(ScreenDC, VERTRES) / (double)GetDeviceCaps(ScreenDC, VERTSIZE);
+
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi.bmiHeader.biWidth = w;
+ bmi.bmiHeader.biHeight = h;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 24;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ bmi.bmiHeader.biSizeImage = 0;
+ bmi.bmiHeader.biXPelsPerMeter = (long)(GetDeviceCaps(ScreenDC, LOGPIXELSX) / 0.0254);
+ bmi.bmiHeader.biYPelsPerMeter = (long)(GetDeviceCaps(ScreenDC, LOGPIXELSY) / 0.0254);
+ bmi.bmiHeader.biClrUsed = 0;
+ bmi.bmiHeader.biClrImportant = 0;
+
+ hBitmapClip = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, &bits, NULL, 0);
+
+ ReleaseDC(NULL, ScreenDC);
+
+ if (!hBitmapClip)
+ return;
+
+ hOldBitmapClip = SelectObject(hDC, hBitmapClip);
+ }
+
+ 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;
+
+ /* Inicializa driver WIN32 */
+ ctxcanvas = cdwCreateCanvas(canvas, NULL, hDC, wtype);
+
+ canvas->w = w;
+ canvas->h = h;
+ canvas->xres = xres;
+ canvas->yres = yres;
+ canvas->w_mm = ((double)w) / xres;
+ canvas->h_mm = ((double)h) / yres;
+ canvas->bpp = 24;
+ ctxcanvas->clip_pnt[2].x = ctxcanvas->clip_pnt[1].x = canvas->w - 1;
+ ctxcanvas->clip_pnt[3].y = ctxcanvas->clip_pnt[2].y = canvas->h - 1;
+
+ if (wtype == CDW_BMP)
+ {
+ ctxcanvas->hBitmapClip = hBitmapClip;
+ ctxcanvas->hOldBitmapClip = hOldBitmapClip;
+ ctxcanvas->bmiClip = bmi;
+ ctxcanvas->bitsClip = bits;
+ }
+ }
+}
+
+static void cdinittable(cdCanvas* canvas)
+{
+ if (canvas->invert_yaxis == 0) /* a simple way to distinguish MF from WIN */
+ {
+ cdinittableMF(canvas);
+ canvas->cxKillCanvas = cdkillcanvasCLIPBDMF;
+ }
+ else
+ {
+ cdwInitTable(canvas);
+ canvas->cxKillCanvas = cdkillcanvas;
+ }
+}
+
+static cdContext cdClipboardContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_YAXIS |
+ CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB | CD_CAP_IMAGESRV |
+ CD_CAP_FPRIMTIVES ),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ cdplay,
+ cdregistercallback
+};
+
+cdContext* cdContextClipboard(void)
+{
+ if (cdUseContextPlus(CD_QUERY))
+ {
+ cdContext* ctx = cdGetContextPlus(CD_CTX_CLIPBOARD);
+ if (ctx != NULL)
+ return ctx;
+ }
+
+ return &cdClipboardContext;
+}
diff --git a/src/win32/cdwdbuf.c b/src/win32/cdwdbuf.c
new file mode 100644
index 0000000..035e29e
--- /dev/null
+++ b/src/win32/cdwdbuf.c
@@ -0,0 +1,169 @@
+/** \file
+ * \brief Windows Double Buffer
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "cdwin.h"
+#include "cddbuf.h"
+
+
+static void cdkillcanvas(cdCtxCanvas *ctxcanvas)
+{
+ cdKillImage(ctxcanvas->image_dbuffer);
+ cdwKillCanvas(ctxcanvas);
+
+ memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
+ free(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;
+
+ GdiFlush();
+
+ /* 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)
+{
+ cdCtxCanvas* ctxcanvas;
+ cdImage* image_dbuffer;
+ cdCtxImage* ctximage;
+
+ /* this is done in the canvas_dbuffer context */
+ image_dbuffer = cdCanvasCreateImage(canvas_dbuffer, canvas_dbuffer->w, canvas_dbuffer->h);
+ if (!image_dbuffer)
+ return;
+
+ ctximage = image_dbuffer->ctximage;
+
+ /* Inicializa driver DBuffer */
+ ctxcanvas = cdwCreateCanvas(canvas, NULL, ctximage->hDC, CDW_BMP);
+
+ 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;
+ 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;
+}
+
+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->image_dbuffer->w ||
+ canvas_dbuffer->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;
+ cdcreatecanvas(canvas, canvas_dbuffer);
+ if (!canvas->ctxcanvas)
+ {
+ canvas->ctxcanvas = old_ctxcanvas;
+ return CD_ERROR;
+ }
+
+ /* remove the old image and canvas */
+ cdKillImage(old_image_dbuffer);
+ cdwKillCanvas(old_ctxcanvas);
+ free(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->use_matrix && canvas->cxTransform) canvas->cxTransform(ctxcanvas, canvas->matrix);
+ 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)
+{
+ cdwInitTable(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* cdContextDBuffer(void)
+{
+ if (cdUseContextPlus(CD_QUERY))
+ {
+ cdContext* ctx = cdGetContextPlus(CD_CTX_DBUFFER);
+ if (ctx != NULL)
+ return ctx;
+ }
+
+ return &cdDBufferContext;
+}
diff --git a/src/win32/cdwdib.c b/src/win32/cdwdib.c
new file mode 100644
index 0000000..aff3f64
--- /dev/null
+++ b/src/win32/cdwdib.c
@@ -0,0 +1,662 @@
+/** \file
+ * \brief Windows DIB Utilities
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include "cdwin.h"
+
+
+/*
+%F Calcula o tamanho de uma linha. O DIB existe em uma "long boundary",
+ou seja cada linha e' um multiplo de quatro bytes ou 32 bits.
+*/
+static int cdwDIBLineSize(int width, int bpp)
+{
+ return ((width * bpp + 31L) / 32L) * 4L;
+}
+
+
+/*
+%F Alloca memoria para o DIB com os par^ametros do cdwDIB.
+*/
+int cdwCreateDIB(cdwDIB* dib)
+{
+ int dibSize, pal_size;
+ BITMAPINFOHEADER* bmih;
+
+ pal_size = dib->type? 256: 0;
+ dibSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * pal_size + cdwDIBLineSize(dib->w, dib->type? 8: 24) * dib->h;
+
+ dib->dib = (BYTE*) calloc(dibSize, 1);
+ if (dib->dib == NULL)
+ return 0;
+
+ dib->bmi = (BITMAPINFO*)dib->dib;
+ dib->bmih = (BITMAPINFOHEADER*)dib->dib;
+ dib->bmic = (RGBQUAD*)(dib->dib + sizeof(BITMAPINFOHEADER));
+ dib->bits = dib->dib + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * pal_size;
+
+ bmih = dib->bmih;
+ bmih->biSize = sizeof(BITMAPINFOHEADER);
+ bmih->biWidth = dib->w;
+ bmih->biHeight = dib->h;
+ bmih->biPlanes = 1;
+ bmih->biBitCount = dib->type? 8: 24;
+ bmih->biCompression = 0;
+ bmih->biSizeImage = 0;
+ bmih->biXPelsPerMeter = 0;
+ bmih->biYPelsPerMeter = 0;
+ bmih->biClrUsed = dib->type? 256: 0;
+ bmih->biClrImportant = dib->type? 256: 0;
+
+ return 1;
+}
+
+HANDLE cdwCreateCopyHDIB(BITMAPINFO* bmi, BYTE* bits)
+{
+ int dibSize, pal_size, headerSize;
+ HANDLE hDib; unsigned char* pDib;
+
+ if (bmi->bmiHeader.biBitCount > 8)
+ {
+ pal_size = 0;
+
+ if (bmi->bmiHeader.biCompression == BI_BITFIELDS)
+ pal_size = 3;
+ }
+ else
+ {
+ if (bmi->bmiHeader.biClrUsed != 0)
+ pal_size = bmi->bmiHeader.biClrUsed;
+ else
+ pal_size = 1 << bmi->bmiHeader.biBitCount;
+ }
+
+ /* calc size */
+ headerSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * pal_size;
+ dibSize = headerSize + cdwDIBLineSize(bmi->bmiHeader.biWidth, bmi->bmiHeader.biBitCount) * bmi->bmiHeader.biHeight;
+
+ hDib = GlobalAlloc(GHND, dibSize);
+ if (!hDib)
+ return NULL;
+
+ /* Get a pointer to the memory block */
+ pDib = (LPBYTE)GlobalLock(hDib);
+
+ /* copy struct data */
+ CopyMemory(pDib, bmi, headerSize);
+
+ /* copy dib data */
+ CopyMemory(pDib + headerSize, bits, dibSize - headerSize);
+
+ GlobalUnlock(hDib);
+
+ return hDib;
+}
+
+int cdwCreateDIBRefBuffer(cdwDIB* dib, unsigned char* *bits, int *size)
+{
+ int dibSize, pal_size;
+ BITMAPINFOHEADER* bmih;
+
+ pal_size = dib->type? 256: 0;
+ dibSize = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * pal_size + cdwDIBLineSize(dib->w, dib->type? 8: 24) * dib->h;
+
+ /* bits may contains an allocated buffer, but no dib */
+ if (*bits && *size >= dibSize)
+ dib->dib = *bits;
+ else
+ {
+ *size = dibSize;
+
+ if (*bits)
+ *bits = realloc(*bits, *size);
+ else
+ *bits = malloc(*size);
+
+ dib->dib = *bits;
+ }
+
+ if (dib->dib == NULL)
+ return 0;
+
+ dib->bmi = (BITMAPINFO*)dib->dib;
+ dib->bmih = (BITMAPINFOHEADER*)dib->dib;
+ dib->bmic = (RGBQUAD*)(dib->dib + sizeof(BITMAPINFOHEADER));
+ dib->bits = dib->dib + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * pal_size;
+
+ bmih = dib->bmih;
+ bmih->biSize = sizeof(BITMAPINFOHEADER);
+ bmih->biWidth = dib->w;
+ bmih->biHeight = dib->h;
+ bmih->biPlanes = 1;
+ bmih->biBitCount = dib->type? 8: 24;
+ bmih->biCompression = 0;
+ bmih->biSizeImage = 0;
+ bmih->biXPelsPerMeter = 0;
+ bmih->biYPelsPerMeter = 0;
+ bmih->biClrUsed = dib->type? 256: 0;
+ bmih->biClrImportant = dib->type? 256: 0;
+
+ return 1;
+}
+
+void cdwCreateDIBRefBits(cdwDIB* dib, unsigned char *bits)
+{
+ BITMAPINFO* bmi = malloc(sizeof(BITMAPINFO));
+
+ bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi->bmiHeader.biWidth = dib->w;
+ bmi->bmiHeader.biHeight = dib->h;
+ bmi->bmiHeader.biPlanes = 1;
+ bmi->bmiHeader.biBitCount = dib->type==0? 24: 32;
+ bmi->bmiHeader.biCompression = BI_RGB;
+ bmi->bmiHeader.biXPelsPerMeter = 0;
+ bmi->bmiHeader.biYPelsPerMeter = 0;
+ bmi->bmiHeader.biSizeImage = 0;
+ bmi->bmiHeader.biClrUsed = 0;
+ bmi->bmiHeader.biClrImportant = 0;
+
+ cdwDIBReference(dib, (BYTE*)bmi, bits);
+
+ /* restore correct type */
+ if (bmi->bmiHeader.biBitCount == 32)
+ dib->type = 2;
+}
+
+HBITMAP cdwCreateDIBSection(cdwDIB* dib, HDC hDC)
+{
+ HBITMAP hbitmap;
+ BYTE *pvBits;
+ BITMAPINFO* bmi = malloc(sizeof(BITMAPINFO));
+
+ bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ bmi->bmiHeader.biWidth = dib->w;
+ bmi->bmiHeader.biHeight = dib->h;
+ bmi->bmiHeader.biPlanes = 1;
+ bmi->bmiHeader.biBitCount = dib->type==0? 24: 32;
+ bmi->bmiHeader.biCompression = BI_RGB;
+ bmi->bmiHeader.biXPelsPerMeter = (long)(GetDeviceCaps(hDC, LOGPIXELSX) / 0.0254);
+ bmi->bmiHeader.biYPelsPerMeter = (long)(GetDeviceCaps(hDC, LOGPIXELSY) / 0.0254);
+ bmi->bmiHeader.biSizeImage = 0;
+ bmi->bmiHeader.biClrUsed = 0;
+ bmi->bmiHeader.biClrImportant = 0;
+
+ hbitmap = CreateDIBSection(hDC, bmi, DIB_RGB_COLORS, &pvBits, NULL, 0x0);
+
+ if (hbitmap)
+ {
+ cdwDIBReference(dib, (BYTE*)bmi, pvBits);
+
+ /* restore correct type */
+ if (bmi->bmiHeader.biBitCount == 32)
+ dib->type = 2;
+ }
+ else
+ free(bmi);
+
+ return hbitmap;
+}
+
+void cdwDIBReference(cdwDIB* dib, BYTE* bmi, BYTE* bits)
+{
+ int pal_size;
+
+ dib->dib = bmi;
+
+ dib->bmi = (BITMAPINFO*)bmi;
+ dib->bmih = &dib->bmi->bmiHeader;
+ dib->bmic = dib->bmi->bmiColors;
+
+ if (dib->bmih->biBitCount > 8)
+ {
+ dib->type = 0;
+ pal_size = 0;
+
+ if (dib->bmih->biCompression == BI_BITFIELDS)
+ pal_size = 3;
+ }
+ else
+ {
+ dib->type = 1;
+
+ if (dib->bmih->biClrUsed != 0)
+ pal_size = dib->bmih->biClrUsed;
+ else
+ pal_size = 1 << dib->bmih->biBitCount;
+ }
+
+ if (bits == NULL)
+ dib->bits = dib->dib + sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * pal_size;
+ else
+ dib->bits = bits;
+
+ dib->w = dib->bmih->biWidth;
+ dib->h = dib->bmih->biHeight;
+}
+
+
+/* %F Libera a memoria alocada para o DIB. */
+void cdwKillDIB(cdwDIB* dib)
+{
+ free(dib->dib);
+}
+
+/* %F Converte cor de CD para DIB. */
+static RGBQUAD sColorToDIB(long cd_color)
+{
+ RGBQUAD color;
+ color.rgbRed = cdRed(cd_color);
+ color.rgbGreen = cdGreen(cd_color);
+ color.rgbBlue = cdBlue(cd_color);
+ return color;
+}
+
+void cdwDIBEncodeRGBRect(cdwDIB* dib, const unsigned char *red, const unsigned char *green, const unsigned char *blue, int xi, int yi, int wi, int hi)
+{
+ int x,y, resto1, resto2, offset;
+ BYTE* bits;
+
+ bits = dib->bits;
+ resto1 = cdwDIBLineSize(dib->w, 24) - dib->w * 3;
+ resto2 = wi - dib->w;
+
+ offset = wi * yi + xi;
+
+ red = red + offset;
+ green = green + offset;
+ blue = blue + offset;
+
+ for (y = 0; y < dib->h; y++)
+ {
+ for (x = 0; x < dib->w; x++)
+ {
+ *bits++ = *blue++;
+ *bits++ = *green++;
+ *bits++ = *red++;
+ }
+
+ bits += resto1;
+
+ red += resto2;
+ green += resto2;
+ blue += resto2;
+ }
+}
+
+/* RGB in RGBA DIBs are pre-multiplied by alpha to AlphaBlend usage. */
+#define CD_ALPHAPRE(_src, _alpha) (((_src)*(_alpha))/255)
+
+void cdwDIBEncodeRGBARect(cdwDIB* dib, const unsigned char *red, const unsigned char *green, const unsigned char *blue, const unsigned char *alpha, int xi, int yi, int wi, int hi)
+{
+ int x,y, resto1, resto2, offset;
+ BYTE* bits;
+
+ bits = dib->bits;
+ resto1 = cdwDIBLineSize(dib->w, 32) - dib->w * 4;
+ resto2 = wi - dib->w;
+
+ offset = wi * yi + xi;
+
+ red = red + offset;
+ green = green + offset;
+ blue = blue + offset;
+ alpha = alpha + offset;
+
+ for (y = 0; y < dib->h; y++)
+ {
+ for (x = 0; x < dib->w; x++)
+ {
+ *bits++ = CD_ALPHAPRE(*blue, *alpha); blue++;
+ *bits++ = CD_ALPHAPRE(*green, *alpha); green++;
+ *bits++ = CD_ALPHAPRE(*red, *alpha); red++;
+ *bits++ = *alpha++;
+ }
+
+ bits += resto1;
+
+ red += resto2;
+ green += resto2;
+ blue += resto2;
+ alpha += resto2;
+ }
+}
+
+void cdwDIBEncodeAlphaRect(cdwDIB* dib, const unsigned char *alpha, int xi, int yi, int wi, int hi)
+{
+ int x,y, resto1, resto2, offset;
+ BYTE* bits;
+
+ bits = dib->bits;
+ resto1 = cdwDIBLineSize(dib->w, 32) - dib->w * 4;
+ resto2 = wi - dib->w;
+
+ offset = wi * yi + xi;
+
+ alpha = alpha + offset;
+
+ for (y = 0; y < dib->h; y++)
+ {
+ for (x = 0; x < dib->w; x++)
+ {
+ *bits++ = CD_ALPHAPRE(*bits, *alpha);
+ *bits++ = CD_ALPHAPRE(*bits, *alpha);
+ *bits++ = CD_ALPHAPRE(*bits, *alpha);
+ *bits++ = *alpha++;
+ }
+
+ bits += resto1;
+ alpha += resto2;
+ }
+}
+
+void cdwDIBEncodeRGBARectZoom(cdwDIB* dib, const unsigned char *red, const unsigned char *green, const unsigned char *blue, const unsigned char *alpha, int w, int h, int xi, int yi, int wi, int hi)
+{
+ int x,y, resto1, resto2, offset;
+ BYTE* bits;
+ const unsigned char *_red, *_green, *_blue, *_alpha;
+ unsigned char a;
+
+ bits = dib->bits;
+ resto1 = cdwDIBLineSize(dib->w, 24) - dib->w * 3;
+
+ if (dib->w != wi || dib->h != hi)
+ {
+ int* XTab = cdGetZoomTable(dib->w, wi, xi);
+ int* YTab = cdGetZoomTable(dib->h, hi, yi);
+
+ for (y = 0; y < dib->h; y++)
+ {
+ offset = YTab[y] * w;
+ _red = red + offset;
+ _green = green + offset;
+ _blue = blue + offset;
+ _alpha = alpha + offset;
+
+ for (x = 0; x < dib->w; x++)
+ {
+ offset = XTab[x];
+ a = _alpha[offset];
+ *bits++ = CD_ALPHA_BLEND(_blue[offset], *bits, a);
+ *bits++ = CD_ALPHA_BLEND(_green[offset], *bits, a);
+ *bits++ = CD_ALPHA_BLEND(_red[offset], *bits, a);
+ }
+
+ bits += resto1;
+ }
+
+ free(XTab);
+ free(YTab);
+ }
+ else
+ {
+ resto2 = w - wi;
+
+ offset = w * yi + xi;
+ red = red + offset;
+ green = green + offset;
+ blue = blue + offset;
+ alpha = alpha + offset;
+
+ for (y = 0; y < dib->h; y++)
+ {
+ for (x = 0; x < dib->w; x++)
+ {
+ a = *alpha++;
+ *bits++ = CD_ALPHA_BLEND(*blue++, *bits, a);
+ *bits++ = CD_ALPHA_BLEND(*green++, *bits, a);
+ *bits++ = CD_ALPHA_BLEND(*red++, *bits, a);
+ }
+
+ bits += resto1;
+
+ red += resto2;
+ green += resto2;
+ blue += resto2;
+ alpha += resto2;
+ }
+ }
+}
+
+/*
+%F Copia os pixels de um DIB em 3 matrizes red, green e
+blue, respectivamente. As matrizes, armazenadas num vetor de bytes devem
+ter a mesma dimens~ao da imagem.
+*/
+void cdwDIBDecodeRGB(cdwDIB* dib, unsigned char *red, unsigned char *green, unsigned char *blue)
+{
+ int x,y, offset;
+ unsigned short color;
+ BYTE* bits;
+ unsigned long rmask=0, gmask=0, bmask=0,
+ roff = 0, goff = 0, boff = 0; /* pixel bit mask control when reading 16 and 32 bpp images */
+
+ bits = dib->bits;
+
+ if (dib->bmih->biBitCount == 16)
+ offset = cdwDIBLineSize(dib->w, dib->bmih->biBitCount);
+ else
+ offset = cdwDIBLineSize(dib->w, dib->bmih->biBitCount) - dib->w * (dib->bmih->biBitCount == 24?3:4);
+
+ if (dib->bmih->biCompression == BI_BITFIELDS)
+ {
+ unsigned long Mask;
+ unsigned long* palette = (unsigned long*)dib->bmic;
+
+ rmask = Mask = palette[0];
+ while (!(Mask & 0x01))
+ {Mask >>= 1; roff++;}
+
+ gmask = Mask = palette[1];
+ while (!(Mask & 0x01))
+ {Mask >>= 1; goff++;}
+
+ bmask = Mask = palette[2];
+ while (!(Mask & 0x01))
+ {Mask >>= 1; boff++;}
+ }
+ else if (dib->bmih->biBitCount == 16)
+ {
+ bmask = 0x001F;
+ gmask = 0x03E0;
+ rmask = 0x7C00;
+ boff = 0;
+ goff = 5;
+ roff = 10;
+ }
+
+ for (y = 0; y < dib->h; y++)
+ {
+ for (x = 0; x < dib->w; x++)
+ {
+ if (dib->bmih->biBitCount != 16)
+ {
+ *blue++ = *bits++;
+ *green++ = *bits++;
+ *red++ = *bits++;
+
+ if (dib->bmih->biBitCount == 32)
+ bits++;
+ }
+ else
+ {
+ color = ((unsigned short*)bits)[x];
+ *red++ = (unsigned char)((((rmask & color) >> roff) * 255) / (rmask >> roff));
+ *green++ = (unsigned char)((((gmask & color) >> goff) * 255) / (gmask >> goff));
+ *blue++ = (unsigned char)((((bmask & color) >> boff) * 255) / (bmask >> boff));
+ }
+ }
+
+ bits += offset;
+ }
+}
+
+void cdwDIBDecodeMap(cdwDIB* dib, unsigned char *index, long *colors)
+{
+ int x,y, line_size,c,pal_size;
+ BYTE* bits;
+ RGBQUAD* bmic;
+
+ bmic = dib->bmic;
+ bits = dib->bits;
+ line_size = cdwDIBLineSize(dib->w, dib->bmih->biBitCount);
+ pal_size = dib->bmih->biClrUsed != 0? dib->bmih->biClrUsed: 1 << dib->bmih->biBitCount;
+
+ for (y = 0; y < dib->h; y++)
+ {
+ for (x = 0; x < dib->w; x++)
+ {
+ switch (dib->bmih->biBitCount)
+ {
+ case 1:
+ *index++ = (unsigned char)((bits[x / 8] >> (7 - x % 8)) & 0x01);
+ break;
+ case 4:
+ *index++ = (unsigned char)((bits[x / 2] >> ((1 - x % 2) * 4)) & 0x0F);
+ break;
+ case 8:
+ *index++ = bits[x];
+ break;
+ }
+ }
+
+ bits += line_size;
+ }
+
+ for (c = 0; c < pal_size; c++)
+ {
+ colors[c] = cdEncodeColor(bmic->rgbRed, bmic->rgbGreen, bmic->rgbBlue);
+ bmic++;
+ }
+}
+
+/*
+%F Cria uma Logical palette a partir da palette do DIB.
+*/
+HPALETTE cdwDIBLogicalPalette(cdwDIB* dib)
+{
+ LOGPALETTE* pLogPal;
+ PALETTEENTRY* pPalEntry;
+ HPALETTE hPal;
+ RGBQUAD* bmic;
+ int c;
+
+ pLogPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) + 256 * sizeof(PALETTEENTRY));
+ pLogPal->palVersion = 0x300;
+ pLogPal->palNumEntries = 256;
+
+ bmic = dib->bmic;
+ pPalEntry = pLogPal->palPalEntry;
+
+ for (c = 0; c < 256; c++)
+ {
+ pPalEntry->peRed = bmic->rgbRed;
+ pPalEntry->peGreen = bmic->rgbGreen;
+ pPalEntry->peBlue = bmic->rgbBlue;
+ pPalEntry->peFlags = PC_NOCOLLAPSE;
+
+ pPalEntry++;
+ bmic++;
+ }
+
+ hPal = CreatePalette(pLogPal);
+ free(pLogPal);
+
+ return hPal;
+}
+
+/*
+%F Copia os pixels definidos por uma matriz de indices e palheta de
+de cores num DIB de mesma dimens~ao.
+*/
+void cdwDIBEncodeMap(cdwDIB* dib, unsigned char *index, long int *colors)
+{
+ int x,y, pal_size, resto, c;
+ BYTE* bits;
+ RGBQUAD* bmic;
+
+ bits = dib->bits;
+ bmic = dib->bmic;
+ resto = cdwDIBLineSize(dib->w, 8) - dib->w;
+
+ /* Como nao sabemos o tamanho da palette a priori,
+ teremos que ver qual o maior indice usado na imagem. */
+ pal_size = *index;
+
+ for (y = 0; y < dib->h; y++)
+ {
+ for (x = 0; x < dib->w; x++)
+ {
+ if (*index > pal_size)
+ pal_size = *index;
+
+ *bits++ = *index++;
+ }
+
+ bits += resto;
+ }
+
+ pal_size++;
+
+ for (c = 0; c < pal_size; c++)
+ *bmic++ = sColorToDIB(colors[c]);
+}
+
+void cdwDIBEncodeMapRect(cdwDIB* dib, const unsigned char *index, const long int *colors, int xi, int yi, int wi, int hi)
+{
+ int x,y, pal_size, resto1, resto2, c;
+ BYTE* bits;
+ RGBQUAD* bmic;
+
+ bits = dib->bits;
+ bmic = dib->bmic;
+ resto1 = cdwDIBLineSize(dib->w, 8) - dib->w;
+ resto2 = wi - dib->w;
+
+ index = index + (wi * yi + xi);
+
+ /* Como nao sabemos o tamanho da palette a priori,
+ teremos que ver qual o maior indice usado na imagem. */
+ pal_size = *index;
+
+ for (y = 0; y < dib->h; y++)
+ {
+ for (x = 0; x < dib->w; x++)
+ {
+ if (*index > pal_size)
+ pal_size = *index;
+
+ *bits++ = *index++;
+ }
+
+ bits += resto1;
+ index += resto2;
+ }
+
+ pal_size++;
+
+ for (c = 0; c < pal_size; c++)
+ *bmic++ = sColorToDIB(colors[c]);
+}
+
+void cdwDIBEncodePattern(cdwDIB* dib, const long int *colors)
+{
+ int x,y, resto1;
+ BYTE* bits;
+
+ bits = dib->bits;
+ resto1 = cdwDIBLineSize(dib->w, 24) - dib->w * 3;
+
+ for (y = 0; y < dib->h; y++)
+ {
+ for (x = 0; x < dib->w; x++)
+ {
+ *bits++ = cdBlue(*colors);
+ *bits++ = cdGreen(*colors);
+ *bits++ = cdRed(*colors);
+ colors++;
+ }
+ bits += resto1;
+ }
+}
diff --git a/src/win32/cdwemf.c b/src/win32/cdwemf.c
new file mode 100644
index 0000000..ad037c9
--- /dev/null
+++ b/src/win32/cdwemf.c
@@ -0,0 +1,117 @@
+/** \file
+ * \brief Windows EMF Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "cdwin.h"
+#include "cdemf.h"
+
+
+
+static void cdkillcanvas (cdCtxCanvas* ctxcanvas)
+{
+ HENHMETAFILE hmf;
+
+ cdwKillCanvas(ctxcanvas);
+
+ hmf = CloseEnhMetaFile(ctxcanvas->hDC);
+ DeleteEnhMetaFile(hmf);
+
+ memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
+ free(ctxcanvas);
+}
+
+/*
+%F cdCreateCanvas para EMF.
+O DC é um EMF em memoria.
+*/
+static void cdcreatecanvas(cdCanvas* canvas, void* data)
+{
+ cdCtxCanvas* ctxcanvas;
+ char* strdata = (char*)data;
+ int w = 0, h = 0;
+ double xres, yres;
+ FILE* file;
+ char filename[10240] = "";
+ HDC ScreenDC, hDC;
+ RECT rect;
+
+ /* Inicializa parametros */
+ if (strdata == NULL)
+ return;
+
+ strdata += cdGetFileName(strdata, filename);
+ if (filename[0] == 0)
+ return;
+
+ sscanf(strdata,"%dx%d", &w, &h);
+ if (w == 0 || h == 0)
+ return;
+
+ /* Verifica se o arquivo pode ser aberto para escrita */
+ file = fopen(filename, "wb");
+ if (file == NULL) return;
+ fclose(file);
+
+ ScreenDC = GetDC(NULL);
+ /* LOGPIXELS can not be used for EMF */
+ xres = (double)GetDeviceCaps(ScreenDC, HORZRES) / (double)GetDeviceCaps(ScreenDC, HORZSIZE);
+ yres = (double)GetDeviceCaps(ScreenDC, VERTRES) / (double)GetDeviceCaps(ScreenDC, VERTSIZE);
+ rect.left = 0;
+ rect.top = 0;
+ rect.right = (int)(100. * w / xres);
+ rect.bottom = (int)(100. * h / yres);
+ hDC = CreateEnhMetaFile(ScreenDC,filename,&rect,NULL);
+ ReleaseDC(NULL, ScreenDC);
+
+ if(!hDC)
+ return;
+
+ /* Inicializa driver WIN32 */
+ ctxcanvas = cdwCreateCanvas(canvas, NULL, hDC, CDW_EMF);
+
+ canvas->w = w;
+ canvas->h = h;
+ canvas->xres = xres;
+ canvas->yres = yres;
+ canvas->w_mm = ((double)w) / xres;
+ canvas->h_mm = ((double)h) / yres;
+ canvas->bpp = 24;
+ ctxcanvas->clip_pnt[2].x = ctxcanvas->clip_pnt[1].x = canvas->w - 1;
+ ctxcanvas->clip_pnt[3].y = ctxcanvas->clip_pnt[2].y = canvas->h - 1;
+}
+
+static void cdinittable(cdCanvas* canvas)
+{
+ cdwInitTable(canvas);
+
+ canvas->cxKillCanvas = cdkillcanvas;
+}
+
+static cdContext cdEMFContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_YAXIS |
+ CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB | CD_CAP_IMAGESRV |
+ CD_CAP_FPRIMTIVES ),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ cdplayEMF,
+ cdregistercallbackEMF
+};
+
+cdContext* cdContextEMF(void)
+{
+ if (cdUseContextPlus(CD_QUERY))
+ {
+ cdContext* ctx = cdGetContextPlus(CD_CTX_EMF);
+ if (ctx != NULL)
+ return ctx;
+ }
+
+ return &cdEMFContext;
+}
diff --git a/src/win32/cdwimg.c b/src/win32/cdwimg.c
new file mode 100644
index 0000000..47d99f9
--- /dev/null
+++ b/src/win32/cdwimg.c
@@ -0,0 +1,83 @@
+/** \file
+ * \brief Windows Image Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "cdwin.h"
+#include "cdimage.h"
+
+
+
+static void cdkillcanvas (cdCtxCanvas *ctxcanvas)
+{
+ cdwKillCanvas(ctxcanvas);
+
+ memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
+ free(ctxcanvas);
+}
+
+/*
+%F cdCreateCanvas para Image.
+O DC é um BITMAP em memoria.
+*/
+static void cdcreatecanvas(cdCanvas* canvas, void *data)
+{
+ cdCtxCanvas* ctxcanvas;
+ cdCtxImage* ctximage;
+
+ if (data == NULL)
+ return;
+
+ ctximage = ((cdImage*)data)->ctximage;
+
+ /* Inicializa parametros */
+ if (ctximage == NULL)
+ return;
+
+ /* Inicializa driver Image */
+ ctxcanvas = cdwCreateCanvas(canvas, NULL, ctximage->hDC, CDW_BMP);
+
+ 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;
+ ctxcanvas->clip_pnt[2].x = ctxcanvas->clip_pnt[1].x = canvas->w - 1;
+ ctxcanvas->clip_pnt[3].y = ctxcanvas->clip_pnt[2].y = canvas->h - 1;
+}
+
+static void cdinittable(cdCanvas* canvas)
+{
+ cdwInitTable(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* cdContextImage(void)
+{
+ if (cdUseContextPlus(CD_QUERY))
+ {
+ cdContext* ctx = cdGetContextPlus(CD_CTX_IMAGE);
+ if (ctx != NULL)
+ return ctx;
+ }
+
+ return &cdImageContext;
+}
diff --git a/src/win32/cdwin.c b/src/win32/cdwin.c
new file mode 100644
index 0000000..3a71746
--- /dev/null
+++ b/src/win32/cdwin.c
@@ -0,0 +1,2368 @@
+/** \file
+ * \brief Windows Base Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+
+#include "cdwin.h"
+
+#ifndef AC_SRC_ALPHA
+#define AC_SRC_ALPHA 0x01
+#endif
+
+/* CD region combine to WIN32 region combine */
+static int sCombineRegion2win [] ={RGN_OR, RGN_AND, RGN_DIFF, RGN_XOR};
+
+typedef BOOL (CALLBACK* AlphaBlendFunc)( HDC hdcDest,
+ int xoriginDest, int yoriginDest,
+ int wDest, int hDest, HDC hdcSrc,
+ int xoriginSrc, int yoriginSrc,
+ int wSrc, int hSrc,
+ BLENDFUNCTION ftn);
+static AlphaBlendFunc cdwAlphaBlend = NULL;
+
+/*
+%F Libera memoria e handles alocados pelo driver Windows.
+*/
+void cdwKillCanvas(cdCtxCanvas* ctxcanvas)
+{
+ if (ctxcanvas->clip_pnt != NULL)
+ free(ctxcanvas->clip_pnt);
+
+ if (ctxcanvas->dib_bits != NULL)
+ free(ctxcanvas->dib_bits);
+
+ /* apaga as areas de memoria do windows para os padroes */
+
+ if (ctxcanvas->clip_hrgn) DeleteObject(ctxcanvas->clip_hrgn);
+ if (ctxcanvas->new_rgn) DeleteObject(ctxcanvas->new_rgn);
+
+ if (ctxcanvas->hOldBitmapPat) SelectObject(ctxcanvas->hDCMemPat, ctxcanvas->hOldBitmapPat);
+ if (ctxcanvas->hBitmapPat) DeleteObject(ctxcanvas->hBitmapPat);
+ if (ctxcanvas->hDCMemPat) DeleteDC(ctxcanvas->hDCMemPat);
+
+ if (ctxcanvas->hOldBitmapStip) SelectObject(ctxcanvas->hDCMemStip, ctxcanvas->hOldBitmapStip);
+ if (ctxcanvas->hBitmapStip) DeleteObject(ctxcanvas->hBitmapStip);
+ if (ctxcanvas->hDCMemStip) DeleteDC(ctxcanvas->hDCMemStip);
+
+ if (ctxcanvas->img_mask) DeleteObject(ctxcanvas->img_mask);
+
+ SelectObject(ctxcanvas->hDC, ctxcanvas->hOldFont);
+ DeleteObject(ctxcanvas->hFont); /* Fonte */
+
+ SelectObject(ctxcanvas->hDC, ctxcanvas->hOldPen); /* restaura os objetos */
+ DeleteObject(ctxcanvas->hPen); /* Pen corrente */
+
+ SelectObject(ctxcanvas->hDC, ctxcanvas->hOldBrush); /* default do canvas */
+ DeleteObject(ctxcanvas->hBrush); /* Brush corrente */
+
+ DeleteObject(ctxcanvas->hNullPen); /* Pen para tirar borda */
+ DeleteObject(ctxcanvas->hBkBrush); /* Brush para o background */
+
+ /* ctxcanvas e ctxcanvas->hDC sao liberados em cada driver */
+}
+
+/*
+Restaura os atributos do CD que sao guardados no DC do Windows quando
+ha uma troca de DC. Usado pelos drivers Native Window e Printer.
+*/
+void cdwRestoreDC(cdCtxCanvas *ctxcanvas)
+{
+ /* cdClipArea */
+ SelectClipRgn(ctxcanvas->hDC, ctxcanvas->clip_hrgn);
+
+ /* cdForeground */
+ SetTextColor(ctxcanvas->hDC, ctxcanvas->fg);
+
+ /* cdBackground */
+ SetBkColor(ctxcanvas->hDC, ctxcanvas->bg);
+
+ /* cdBackOpacity */
+ switch (ctxcanvas->canvas->back_opacity)
+ {
+ case CD_TRANSPARENT:
+ SetBkMode(ctxcanvas->hDC, TRANSPARENT);
+ break;
+ case CD_OPAQUE:
+ SetBkMode(ctxcanvas->hDC, OPAQUE);
+ break;
+ }
+
+ /* cdWriteMode */
+ switch (ctxcanvas->canvas->write_mode)
+ {
+ case CD_REPLACE:
+ SetROP2(ctxcanvas->hDC, R2_COPYPEN);
+ break;
+ case CD_XOR:
+ SetROP2(ctxcanvas->hDC, R2_XORPEN);
+ break;
+ case CD_NOT_XOR:
+ SetROP2(ctxcanvas->hDC, R2_NOTXORPEN);
+ break;
+ }
+
+ /* Text Alignment is calculated from this state */
+ SetTextAlign(ctxcanvas->hDC,TA_LEFT|TA_BASELINE);
+
+ /* cdLineStyle e cdLineWidth */
+ ctxcanvas->hOldPen = SelectObject(ctxcanvas->hDC, ctxcanvas->hPen);
+
+ /* cdInteriorStyle */
+ ctxcanvas->hOldBrush = SelectObject(ctxcanvas->hDC, ctxcanvas->hBrush);
+
+ /* cdFont */
+ ctxcanvas->hOldFont = SelectObject(ctxcanvas->hDC, ctxcanvas->hFont);
+}
+
+
+/*********************************************************************/
+/*
+%S Cor
+*/
+/*********************************************************************/
+
+static long int sColorFromWindows(COLORREF color)
+{
+ return cdEncodeColor(GetRValue(color),GetGValue(color),GetBValue(color));
+}
+
+static COLORREF sColorToWindows(cdCtxCanvas* ctxcanvas, long int cd_color)
+{
+ unsigned char red,green,blue;
+ COLORREF color;
+
+ cdDecodeColor(cd_color,&red,&green,&blue);
+
+ if (ctxcanvas->canvas->bpp <= 8)
+ color=PALETTERGB((BYTE)red,(BYTE)green,(BYTE)blue);
+ else
+ color=RGB((BYTE)red,(BYTE)green,(BYTE)blue);
+
+ return color;
+}
+
+static long int cdforeground (cdCtxCanvas* ctxcanvas, long int color)
+{
+ ctxcanvas->fg = sColorToWindows(ctxcanvas, color);
+ SetTextColor(ctxcanvas->hDC, ctxcanvas->fg);
+ ctxcanvas->rebuild_pen = 1;
+ return color;
+}
+
+static void sCreatePen(cdCtxCanvas* ctxcanvas)
+{
+ int cd2win_cap[] = {PS_ENDCAP_FLAT, PS_ENDCAP_SQUARE, PS_ENDCAP_ROUND};
+ int cd2win_join[] = {PS_JOIN_MITER, PS_JOIN_BEVEL, PS_JOIN_ROUND};
+
+ ctxcanvas->logPen.lopnColor = ctxcanvas->fg;
+
+ if (ctxcanvas->hOldPen) SelectObject(ctxcanvas->hDC, ctxcanvas->hOldPen);
+ if (ctxcanvas->hPen) DeleteObject(ctxcanvas->hPen);
+
+ if (ctxcanvas->logPen.lopnWidth.x == 1)
+ {
+ LOGBRUSH LogBrush;
+ LogBrush.lbStyle = BS_SOLID;
+ LogBrush.lbColor = ctxcanvas->logPen.lopnColor;
+ LogBrush.lbHatch = 0;
+
+ if (ctxcanvas->canvas->line_style == CD_CUSTOM)
+ {
+ ctxcanvas->hPen = ExtCreatePen(PS_COSMETIC | PS_USERSTYLE,
+ 1, &LogBrush,
+ ctxcanvas->canvas->line_dashes_count, (DWORD*)ctxcanvas->canvas->line_dashes);
+ }
+ else
+ {
+ ctxcanvas->hPen = ExtCreatePen(PS_COSMETIC | ctxcanvas->logPen.lopnStyle,
+ 1, &LogBrush,
+ 0, NULL);
+ }
+ }
+ else
+ {
+ int style = PS_GEOMETRIC;
+ LOGBRUSH LogBrush;
+ LogBrush.lbStyle = BS_SOLID;
+ LogBrush.lbColor = ctxcanvas->logPen.lopnColor;
+ LogBrush.lbHatch = 0;
+
+ style |= cd2win_cap[ctxcanvas->canvas->line_cap];
+ style |= cd2win_join[ctxcanvas->canvas->line_join];
+
+ if (ctxcanvas->canvas->line_style == CD_CUSTOM)
+ {
+ ctxcanvas->hPen = ExtCreatePen( PS_USERSTYLE | style,
+ ctxcanvas->logPen.lopnWidth.x, &LogBrush,
+ ctxcanvas->canvas->line_dashes_count, (DWORD*)ctxcanvas->canvas->line_dashes);
+ }
+ else
+ ctxcanvas->hPen = ExtCreatePen( ctxcanvas->logPen.lopnStyle | style,
+ ctxcanvas->logPen.lopnWidth.x, &LogBrush,
+ 0, NULL);
+ }
+
+ ctxcanvas->hOldPen = SelectObject(ctxcanvas->hDC, ctxcanvas->hPen);
+ ctxcanvas->rebuild_pen = 0;
+}
+
+static int cdbackopacity (cdCtxCanvas* ctxcanvas, int opacity)
+{
+ switch (opacity)
+ {
+ case CD_TRANSPARENT:
+ SetBkMode(ctxcanvas->hDC, TRANSPARENT);
+ break;
+ case CD_OPAQUE:
+ SetBkMode(ctxcanvas->hDC, OPAQUE);
+ break;
+ }
+
+ return opacity;
+}
+
+static int cdwritemode (cdCtxCanvas* ctxcanvas, int mode)
+{
+ switch (mode)
+ {
+ case CD_REPLACE:
+ SetROP2(ctxcanvas->hDC, R2_COPYPEN);
+ ctxcanvas->RopBlt = SRCCOPY;
+ break;
+ case CD_XOR:
+ SetROP2(ctxcanvas->hDC, R2_XORPEN);
+ ctxcanvas->RopBlt = SRCINVERT;
+ break;
+ case CD_NOT_XOR:
+ SetROP2(ctxcanvas->hDC, R2_NOTXORPEN);
+ ctxcanvas->RopBlt = SRCINVERT;
+ break;
+ }
+
+ return mode;
+}
+
+static long int cdbackground (cdCtxCanvas* ctxcanvas, long int color)
+{
+ ctxcanvas->bg = sColorToWindows(ctxcanvas, color);
+ SetBkColor(ctxcanvas->hDC, ctxcanvas->bg);
+
+ if (ctxcanvas->hBkBrush) DeleteObject(ctxcanvas->hBkBrush);
+ ctxcanvas->hBkBrush = CreateSolidBrush(ctxcanvas->bg);
+
+ return color;
+}
+
+static void cdpalette(cdCtxCanvas* ctxcanvas, int n, const long int *palette, int mode)
+{
+ LOGPALETTE* pLogPal;
+ unsigned char red,green,blue;
+ int k, np = n;
+ (void)mode;
+
+ if (ctxcanvas->canvas->bpp > 8) /* se o sistema for true color */
+ return;
+
+ if (n < 246)
+ np += 10;
+
+ pLogPal = (LOGPALETTE*)malloc(sizeof(LOGPALETTE) + np * sizeof(PALETTEENTRY));
+ pLogPal->palVersion = 0x300;
+ pLogPal->palNumEntries = (WORD)np;
+
+ if (n < 246)
+ {
+ k = 10;
+ GetSystemPaletteEntries(ctxcanvas->hDC, 0, 10, pLogPal->palPalEntry);
+ }
+ else
+ k=0;
+
+ for (; k < np; k++)
+ {
+ cdDecodeColor(palette[k],&red,&green,&blue);
+
+ pLogPal->palPalEntry[k].peRed = (BYTE)red;
+ pLogPal->palPalEntry[k].peGreen = (BYTE)green;
+ pLogPal->palPalEntry[k].peBlue = (BYTE)blue;
+ pLogPal->palPalEntry[k].peFlags = PC_NOCOLLAPSE;
+ }
+
+ if (ctxcanvas->hPal)
+ {
+ if (ctxcanvas->hOldPal) SelectPalette(ctxcanvas->hDC, ctxcanvas->hOldPal, FALSE);
+ DeleteObject(ctxcanvas->hPal);
+ }
+
+ ctxcanvas->hPal = CreatePalette(pLogPal);
+ ctxcanvas->hOldPal = SelectPalette(ctxcanvas->hDC, ctxcanvas->hPal, FALSE);
+
+ RealizePalette(ctxcanvas->hDC);
+
+ free(pLogPal);
+}
+
+
+/*********************************************************************/
+/*
+%S Canvas e clipping
+*/
+/*********************************************************************/
+
+static HRGN sClipRect(cdCtxCanvas* ctxcanvas)
+{
+ HRGN clip_hrgn;
+
+ if (ctxcanvas->clip_hrgn)
+ DeleteObject(ctxcanvas->clip_hrgn);
+
+ clip_hrgn = CreateRectRgn(ctxcanvas->canvas->clip_rect.xmin, ctxcanvas->canvas->clip_rect.ymin,
+ ctxcanvas->canvas->clip_rect.xmax+1, ctxcanvas->canvas->clip_rect.ymax+1);
+
+ SelectClipRgn(ctxcanvas->hDC, clip_hrgn);
+ return clip_hrgn;
+}
+
+static HRGN sClipPoly(cdCtxCanvas* ctxcanvas)
+{
+ HRGN clip_hrgn;
+
+ if (ctxcanvas->clip_hrgn)
+ DeleteObject(ctxcanvas->clip_hrgn);
+
+ clip_hrgn = CreatePolygonRgn(ctxcanvas->clip_pnt,
+ ctxcanvas->clip_pnt_n,
+ ctxcanvas->canvas->fill_mode==CD_EVENODD?ALTERNATE:WINDING);
+ SelectClipRgn(ctxcanvas->hDC, clip_hrgn);
+ return clip_hrgn;
+}
+
+static int cdclip (cdCtxCanvas* ctxcanvas, int clip_mode)
+{
+ if (ctxcanvas->wtype == CDW_WMF)
+ return clip_mode;
+
+ switch (clip_mode)
+ {
+ case CD_CLIPOFF:
+ SelectClipRgn(ctxcanvas->hDC, NULL); /* toda 'area do canvas */
+ if (ctxcanvas->clip_hrgn)
+ DeleteObject(ctxcanvas->clip_hrgn);
+ ctxcanvas->clip_hrgn = NULL;
+ break;
+ case CD_CLIPAREA:
+ ctxcanvas->clip_hrgn = sClipRect(ctxcanvas);
+ break;
+ case CD_CLIPPOLYGON:
+ ctxcanvas->clip_hrgn = sClipPoly(ctxcanvas);
+ break;
+ case CD_CLIPREGION:
+ if (ctxcanvas->clip_hrgn)
+ DeleteObject(ctxcanvas->clip_hrgn);
+ ctxcanvas->clip_hrgn = CreateRectRgn(0,0,0,0);
+ CombineRgn(ctxcanvas->clip_hrgn, ctxcanvas->new_rgn, NULL, RGN_COPY);
+ SelectClipRgn(ctxcanvas->hDC, ctxcanvas->clip_hrgn);
+ break;
+ }
+
+ return clip_mode;
+}
+
+static void cdcliparea(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ if (ctxcanvas->wtype == CDW_WMF)
+ return;
+
+ 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;
+ ctxcanvas->clip_hrgn = sClipRect(ctxcanvas);
+ }
+}
+
+static void cdnewregion(cdCtxCanvas* ctxcanvas)
+{
+ if (ctxcanvas->new_rgn)
+ DeleteObject(ctxcanvas->new_rgn);
+ ctxcanvas->new_rgn = CreateRectRgn(0, 0, 0, 0);
+}
+
+static int cdispointinregion(cdCtxCanvas* ctxcanvas, int x, int y)
+{
+ if (!ctxcanvas->new_rgn)
+ return 0;
+
+ if (PtInRegion(ctxcanvas->new_rgn, x, y))
+ return 1;
+
+ return 0;
+}
+
+static void cdoffsetregion(cdCtxCanvas* ctxcanvas, int x, int y)
+{
+ if (!ctxcanvas->new_rgn)
+ return;
+
+ OffsetRgn(ctxcanvas->new_rgn, x, y);
+}
+
+static void cdgetregionbox(cdCtxCanvas* ctxcanvas, int *xmin, int *xmax, int *ymin, int *ymax)
+{
+ RECT rect;
+
+ if (!ctxcanvas->new_rgn)
+ return;
+
+ GetRgnBox(ctxcanvas->new_rgn, &rect);
+
+ /* RECT in Windows does not includes the right, bottom. */
+ *xmin = rect.left;
+ *xmax = rect.right-1;
+ *ymin = rect.top;
+ *ymax = rect.bottom-1;
+}
+
+/******************************************************************/
+/*
+%S Primitivas e seus atributos
+*/
+/******************************************************************/
+
+static int cdlinestyle (cdCtxCanvas* ctxcanvas, int style)
+{
+ switch (style)
+ {
+ case CD_CONTINUOUS:
+ ctxcanvas->logPen.lopnStyle = PS_SOLID;
+ break;
+ case CD_DASHED:
+ ctxcanvas->logPen.lopnStyle = PS_DASH;
+ break;
+ case CD_DOTTED:
+ ctxcanvas->logPen.lopnStyle = PS_DOT;
+ break;
+ case CD_DASH_DOT:
+ ctxcanvas->logPen.lopnStyle = PS_DASHDOT;
+ break;
+ case CD_DASH_DOT_DOT:
+ ctxcanvas->logPen.lopnStyle = PS_DASHDOTDOT;
+ break;
+ }
+
+ ctxcanvas->rebuild_pen = 1;
+
+ return style;
+}
+
+static int cdlinewidth (cdCtxCanvas* ctxcanvas, int width)
+{
+ ctxcanvas->logPen.lopnWidth.x = width;
+ ctxcanvas->rebuild_pen = 1;
+ return width;
+}
+
+static int cdlinecap (cdCtxCanvas* ctxcanvas, int cap)
+{
+ ctxcanvas->rebuild_pen = 1;
+ return cap;
+}
+
+static int cdlinejoin (cdCtxCanvas* ctxcanvas, int join)
+{
+ ctxcanvas->rebuild_pen = 1;
+ return join;
+}
+
+static int cdhatch (cdCtxCanvas* ctxcanvas, int hatch_style)
+{
+ switch (hatch_style)
+ {
+ case CD_HORIZONTAL:
+ ctxcanvas->logBrush.lbHatch = HS_HORIZONTAL;
+ break;
+ case CD_VERTICAL:
+ ctxcanvas->logBrush.lbHatch = HS_VERTICAL;
+ break;
+ case CD_FDIAGONAL:
+ ctxcanvas->logBrush.lbHatch = HS_FDIAGONAL;
+ break;
+ case CD_BDIAGONAL:
+ ctxcanvas->logBrush.lbHatch = HS_BDIAGONAL;
+ break;
+ case CD_CROSS:
+ ctxcanvas->logBrush.lbHatch = HS_CROSS;
+ break;
+ case CD_DIAGCROSS:
+ ctxcanvas->logBrush.lbHatch = HS_DIAGCROSS;
+ break;
+ }
+
+ ctxcanvas->logBrush.lbColor=ctxcanvas->fg;
+ ctxcanvas->logBrush.lbStyle=BS_HATCHED;
+
+ if (ctxcanvas->hOldBrush) SelectObject(ctxcanvas->hDC, ctxcanvas->hOldBrush);
+ if (ctxcanvas->hBrush) DeleteObject(ctxcanvas->hBrush);
+
+ ctxcanvas->hBrush = CreateBrushIndirect(&ctxcanvas->logBrush);
+ ctxcanvas->hOldBrush = SelectObject(ctxcanvas->hDC, ctxcanvas->hBrush);
+
+ return hatch_style;
+}
+
+static HBITMAP Stipple2Bitmap(int w, int h, const unsigned char *index, int negative)
+{
+ HBITMAP hBitmap;
+ BYTE *buffer;
+
+ int nb; /* number of bytes per line */
+ int x,y,k,offset;
+
+ /* Cria um bitmap com os indices dados */
+ nb = ((w + 15) / 16) * 2; /* Must be in a word boundary. */
+ buffer = (BYTE *) malloc (nb*h);
+ memset(buffer, 0xff, nb*h);
+
+ for (y=0; y<h; y++)
+ {
+ k=y*nb;
+ offset = ((h - 1) - y)*w; /* always consider a top-down bitmap */
+
+ for (x=0;x<w;x++)
+ {
+ if ((x % 8 == 0) && (x != 0))
+ k++;
+
+ /* In Windows: 0 is foreground, 1 is background. */
+ if (index[offset + x] != 0)
+ buffer[k] &= (BYTE)~(1 << (7 - x % 8));
+ }
+ }
+
+ if (negative)
+ {
+ for (k = 0; k < nb*h; k++)
+ buffer[k] = ~buffer[k];
+ }
+
+ hBitmap = CreateBitmap(w,h,1,1,(LPSTR)buffer);
+
+ free(buffer);
+
+ return hBitmap;
+}
+
+static void cdstipple(cdCtxCanvas* ctxcanvas, int w, int h, const unsigned char *index)
+{
+ HBITMAP hBitmap = Stipple2Bitmap(w, h, index, 0);
+
+ /* Cria um pincel com o Bitmap */
+ if (ctxcanvas->hOldBrush) SelectObject(ctxcanvas->hDC, ctxcanvas->hOldBrush);
+ if (ctxcanvas->hBrush) DeleteObject(ctxcanvas->hBrush);
+
+ ctxcanvas->hBrush = CreatePatternBrush(hBitmap);
+ ctxcanvas->hOldBrush = SelectObject(ctxcanvas->hDC, ctxcanvas->hBrush);
+
+ DeleteObject(hBitmap);
+}
+
+static void cdpattern(cdCtxCanvas* ctxcanvas, int w, int h, const long int *colors)
+{
+ cdwDIB dib;
+ HBRUSH hBrush;
+
+ if (ctxcanvas->wtype == CDW_WMF)
+ return;
+
+ dib.w = w;
+ dib.h = h;
+ dib.type = 0;
+ if (!cdwCreateDIB(&dib))
+ return;
+
+ cdwDIBEncodePattern(&dib, colors);
+ hBrush = CreateDIBPatternBrushPt(dib.dib, DIB_RGB_COLORS);
+ cdwKillDIB(&dib);
+
+ if (hBrush)
+ {
+ if (ctxcanvas->hOldBrush) SelectObject(ctxcanvas->hDC, ctxcanvas->hOldBrush);
+ if (ctxcanvas->hBrush) DeleteObject(ctxcanvas->hBrush);
+
+ ctxcanvas->hBrush = hBrush;
+ ctxcanvas->hOldBrush = SelectObject(ctxcanvas->hDC, ctxcanvas->hBrush);
+ }
+}
+
+static int cdinteriorstyle (cdCtxCanvas* ctxcanvas, int style)
+{
+ switch (style)
+ {
+ case CD_SOLID:
+ ctxcanvas->logBrush.lbStyle=BS_SOLID;
+ ctxcanvas->logBrush.lbColor=ctxcanvas->fg;
+
+ if (ctxcanvas->hOldBrush) SelectObject(ctxcanvas->hDC, ctxcanvas->hOldBrush);
+ if (ctxcanvas->hBrush) DeleteObject(ctxcanvas->hBrush);
+
+ ctxcanvas->hBrush = CreateBrushIndirect(&ctxcanvas->logBrush);
+ ctxcanvas->hOldBrush = SelectObject(ctxcanvas->hDC, ctxcanvas->hBrush);
+ 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:
+ if (ctxcanvas->wtype == CDW_WMF)
+ return style;
+ 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)
+{
+ if (ctxcanvas->rebuild_pen)
+ sCreatePen(ctxcanvas);
+
+ MoveToEx( ctxcanvas->hDC, x1, y1, NULL );
+ LineTo( ctxcanvas->hDC, x2, y2 );
+ SetPixelV(ctxcanvas->hDC, x2, y2, ctxcanvas->fg);
+}
+
+static void cdrect (cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ HBRUSH oldBrush;
+
+ if (ctxcanvas->rebuild_pen)
+ sCreatePen(ctxcanvas);
+
+ oldBrush = SelectObject(ctxcanvas->hDC, GetStockObject(NULL_BRUSH)); /* tira o desenho do interior */
+ Rectangle(ctxcanvas->hDC, xmin, ymin, xmax+1, ymax+1); /* +1 porque nao inclue right/bottom */
+ SelectObject(ctxcanvas->hDC, oldBrush); /* restaura o brush corrente */
+}
+
+static void cdbox (cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax)
+{
+ if ((ctxcanvas->logBrush.lbColor != ctxcanvas->fg) &&
+ (ctxcanvas->canvas->interior_style != CD_PATTERN) )
+ cdinteriorstyle(ctxcanvas, ctxcanvas->canvas->interior_style);
+
+ if (ctxcanvas->canvas->new_region)
+ {
+ HRGN rgn = CreateRectRgn(xmin, ymin, xmax+1, ymax+1);
+ CombineRgn(ctxcanvas->new_rgn, ctxcanvas->new_rgn, rgn, sCombineRegion2win[ctxcanvas->canvas->combine_mode]);
+ DeleteObject(rgn);
+ }
+ else
+ {
+ SelectObject(ctxcanvas->hDC, ctxcanvas->hNullPen); /* tira o desenho da borda */
+ Rectangle(ctxcanvas->hDC, xmin, ymin, xmax+2, ymax+2); /* +2 porque a pena e' NULL NULL e o nao inclue right/bottom */
+ SelectObject(ctxcanvas->hDC, ctxcanvas->hPen); /* restaura a Pen corrente */
+ }
+}
+
+typedef struct _winArcParam
+{
+ int LeftRect, /* x-coordinate of upper-left corner of bounding rectangle */
+ TopRect, /* y-coordinate of upper-left corner of bounding rectangle */
+ RightRect, /* x-coordinate of lower-right corner of bounding rectangle */
+ BottomRect, /* y-coordinate of lower-right corner of bounding rectangle */
+ XStartArc, /* first radial ending point */
+ YStartArc, /* first radial ending point */
+ XEndArc, /* second radial ending point */
+ YEndArc; /* second radial ending point */
+} winArcParam;
+
+static void calcArc(cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double angle1, double angle2, winArcParam* arc)
+{
+ arc->LeftRect = xc - w/2;
+ arc->RightRect = xc + w/2 + 1;
+ arc->XStartArc = xc + cdRound(w * cos(CD_DEG2RAD * angle1) / 2.0);
+ arc->XEndArc = xc + cdRound(w * cos(CD_DEG2RAD * angle2) / 2.0);
+
+ if (ctxcanvas->canvas->invert_yaxis)
+ {
+ arc->TopRect = yc - h/2;
+ arc->BottomRect = yc + h/2 + 1;
+ arc->YStartArc = yc - cdRound(h * sin(CD_DEG2RAD * angle1) / 2.0);
+ arc->YEndArc = yc - cdRound(h * sin(CD_DEG2RAD * angle2) / 2.0);
+ }
+ else
+ {
+ arc->BottomRect = yc - h/2;
+ arc->TopRect = yc + h/2 + 1;
+ arc->YStartArc = yc + cdRound(h * sin(CD_DEG2RAD * angle1) / 2.0);
+ arc->YEndArc = yc + cdRound(h * sin(CD_DEG2RAD * angle2) / 2.0);
+
+ /* it is clock-wise when axis inverted */
+ _cdSwapInt(arc->XStartArc, arc->XEndArc);
+ _cdSwapInt(arc->YStartArc, arc->YEndArc);
+ }
+}
+
+static void cdarc(cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double angle1, double angle2)
+{
+ winArcParam arc;
+ calcArc(ctxcanvas, xc, yc, w, h, angle1, angle2, &arc);
+
+ if (ctxcanvas->rebuild_pen)
+ sCreatePen(ctxcanvas);
+
+ Arc(ctxcanvas->hDC, arc.LeftRect, arc.TopRect, arc.RightRect, arc.BottomRect, arc.XStartArc, arc.YStartArc, arc.XEndArc, arc.YEndArc);
+}
+
+static void cdsector(cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double angle1, double angle2)
+{
+ winArcParam arc;
+ calcArc(ctxcanvas, xc, yc, w, h, angle1, angle2, &arc);
+
+ if ((ctxcanvas->logBrush.lbColor != ctxcanvas->fg) &&
+ (ctxcanvas->canvas->interior_style != CD_PATTERN) )
+ cdinteriorstyle(ctxcanvas, ctxcanvas->canvas->interior_style);
+
+ if (angle1==0 && angle2==360)
+ {
+ if (ctxcanvas->canvas->new_region)
+ {
+ HRGN rgn = CreateEllipticRgn(arc.LeftRect, arc.TopRect, arc.RightRect+1, arc.BottomRect+1);
+ CombineRgn(ctxcanvas->new_rgn, ctxcanvas->new_rgn, rgn, sCombineRegion2win[ctxcanvas->canvas->combine_mode]);
+ DeleteObject(rgn);
+ }
+ else
+ {
+ SelectObject(ctxcanvas->hDC, ctxcanvas->hNullPen); /* tira o desenho da borda */
+ Ellipse(ctxcanvas->hDC,arc.LeftRect, arc.TopRect, arc.RightRect+1, arc.BottomRect+1); /* +1 porque a pena e' NULL e +1 porque nao inclue right/bottom */
+ SelectObject(ctxcanvas->hDC, ctxcanvas->hPen); /* restaura a Pen corrente */
+ }
+ }
+ else
+ {
+ if (ctxcanvas->canvas->new_region)
+ BeginPath(ctxcanvas->hDC);
+
+ SelectObject(ctxcanvas->hDC, ctxcanvas->hNullPen); /* tira o desenho da borda */
+ Pie(ctxcanvas->hDC,arc.LeftRect, arc.TopRect, arc.RightRect+1, arc.BottomRect+1,arc.XStartArc, arc.YStartArc, arc.XEndArc, arc.YEndArc); /* +1 porque a pena e' NULL e +1 porque nao inclue right/bottom */
+ SelectObject(ctxcanvas->hDC, ctxcanvas->hPen); /* restaura a Pen corrente */
+
+ if (ctxcanvas->canvas->new_region)
+ {
+ HRGN rgn;
+ EndPath(ctxcanvas->hDC);
+ rgn = PathToRegion(ctxcanvas->hDC);
+ CombineRgn(ctxcanvas->new_rgn, ctxcanvas->new_rgn, rgn, sCombineRegion2win[ctxcanvas->canvas->combine_mode]);
+ DeleteObject(rgn);
+ }
+ }
+}
+
+static void cdchord(cdCtxCanvas* ctxcanvas, int xc, int yc, int w, int h, double angle1, double angle2)
+{
+ winArcParam arc;
+ calcArc(ctxcanvas, xc, yc, w, h, angle1, angle2, &arc);
+
+ if ((ctxcanvas->logBrush.lbColor != ctxcanvas->fg) &&
+ (ctxcanvas->canvas->interior_style != CD_PATTERN) )
+ cdinteriorstyle(ctxcanvas, ctxcanvas->canvas->interior_style);
+
+ if (angle1==0 && angle2==360)
+ {
+ if (ctxcanvas->canvas->new_region)
+ {
+ HRGN rgn = CreateEllipticRgn(arc.LeftRect, arc.TopRect, arc.RightRect+1, arc.BottomRect+1);
+ CombineRgn(ctxcanvas->new_rgn, ctxcanvas->new_rgn, rgn, sCombineRegion2win[ctxcanvas->canvas->combine_mode]);
+ DeleteObject(rgn);
+ }
+ else
+ {
+ SelectObject(ctxcanvas->hDC, ctxcanvas->hNullPen); /* tira o desenho da borda */
+ Ellipse(ctxcanvas->hDC,arc.LeftRect, arc.TopRect, arc.RightRect+1, arc.BottomRect+1); /* +1 porque a pena e' NULL e +1 porque nao inclue right/bottom */
+ SelectObject(ctxcanvas->hDC, ctxcanvas->hPen); /* restaura a Pen corrente */
+ }
+ }
+ else
+ {
+ if (ctxcanvas->canvas->new_region)
+ BeginPath(ctxcanvas->hDC);
+
+ SelectObject(ctxcanvas->hDC, ctxcanvas->hNullPen); /* tira o desenho da borda */
+ Chord(ctxcanvas->hDC,arc.LeftRect, arc.TopRect, arc.RightRect+1, arc.BottomRect+1,arc.XStartArc, arc.YStartArc, arc.XEndArc, arc.YEndArc); /* +2 porque a pena e' NULL e o nao inclue right/bottom */
+ SelectObject(ctxcanvas->hDC, ctxcanvas->hPen); /* restaura a Pen corrente */
+
+ if (ctxcanvas->canvas->new_region)
+ {
+ HRGN rgn;
+ EndPath(ctxcanvas->hDC);
+ rgn = PathToRegion(ctxcanvas->hDC);
+ CombineRgn(ctxcanvas->new_rgn, ctxcanvas->new_rgn, rgn, sCombineRegion2win[ctxcanvas->canvas->combine_mode]);
+ DeleteObject(rgn);
+ }
+ }
+}
+
+static void cdpoly(cdCtxCanvas* ctxcanvas, int mode, cdPoint* poly, int n)
+{
+ int i, t, nc;
+ POINT* pnt;
+ HPEN oldPen = NULL, Pen = NULL;
+
+ switch( mode )
+ {
+ case CD_CLOSED_LINES:
+ poly[n].x = poly[0].x;
+ poly[n].y = poly[0].y;
+ n++;
+ /* continua */
+ case CD_OPEN_LINES:
+ if (ctxcanvas->rebuild_pen)
+ sCreatePen(ctxcanvas);
+ Polyline(ctxcanvas->hDC, (POINT*)poly, n);
+ break;
+ case CD_BEZIER:
+ if (ctxcanvas->rebuild_pen)
+ sCreatePen(ctxcanvas);
+ PolyBezier(ctxcanvas->hDC, (POINT*)poly, n);
+ break;
+ case CD_FILL:
+ poly[n].x = poly[0].x;
+ poly[n].y = poly[0].y;
+ n++;
+ if (ctxcanvas->canvas->new_region)
+ {
+ HRGN rgn = CreatePolygonRgn((POINT*)poly, n, ctxcanvas->canvas->fill_mode==CD_EVENODD?ALTERNATE:WINDING);
+ CombineRgn(ctxcanvas->new_rgn, ctxcanvas->new_rgn, rgn, sCombineRegion2win[ctxcanvas->canvas->combine_mode]);
+ DeleteObject(rgn);
+ }
+ else
+ {
+ if ((ctxcanvas->logBrush.lbColor != ctxcanvas->fg) &&
+ (ctxcanvas->canvas->interior_style != CD_PATTERN))
+ cdinteriorstyle(ctxcanvas, ctxcanvas->canvas->interior_style);
+
+ if (ctxcanvas->canvas->interior_style != CD_SOLID || ctxcanvas->fill_attrib[0] == '0')
+ {
+ SelectObject(ctxcanvas->hDC, ctxcanvas->hNullPen); /* tira o desenho da borda */
+ }
+ else
+ {
+ Pen = CreatePen(PS_SOLID, 1, ctxcanvas->fg);
+ oldPen = SelectObject(ctxcanvas->hDC, Pen);
+ }
+
+ SetPolyFillMode(ctxcanvas->hDC, ctxcanvas->canvas->fill_mode==CD_EVENODD?ALTERNATE:WINDING);
+ Polygon(ctxcanvas->hDC, (POINT*)poly, n);
+
+ if (ctxcanvas->canvas->interior_style != CD_SOLID || ctxcanvas->fill_attrib[0] == '0')
+ {
+ SelectObject(ctxcanvas->hDC, ctxcanvas->hPen); /* restaura a Pen corrente */
+ }
+ else
+ {
+ SelectObject(ctxcanvas->hDC, oldPen);
+ DeleteObject(Pen);
+ }
+ }
+ break;
+ case CD_CLIP:
+ poly[n].x = poly[0].x;
+ poly[n].y = poly[0].y;
+ n++;
+
+ if (ctxcanvas->wtype == CDW_WMF)
+ return;
+
+ if (ctxcanvas->clip_pnt)
+ free(ctxcanvas->clip_pnt);
+
+ ctxcanvas->clip_pnt = (POINT*)malloc(n*sizeof(POINT));
+
+ pnt = (POINT*)poly;
+ t = n;
+ nc = 1;
+
+ ctxcanvas->clip_pnt[0] = *pnt;
+ pnt++;
+
+ for (i = 1; i < t-1; i++, pnt++)
+ {
+ if (!((pnt->x == ctxcanvas->clip_pnt[nc-1].x && pnt->x == (pnt + 1)->x) ||
+ (pnt->y == ctxcanvas->clip_pnt[nc-1].y && pnt->y == (pnt + 1)->y)))
+ {
+ ctxcanvas->clip_pnt[nc] = *pnt;
+ nc++;
+ }
+ }
+
+ ctxcanvas->clip_pnt_n = nc;
+
+ if (ctxcanvas->canvas->clip_mode == CD_CLIPPOLYGON)
+ ctxcanvas->clip_hrgn = sClipPoly(ctxcanvas);
+
+ break;
+ }
+}
+
+static void cdtransform(cdCtxCanvas *ctxcanvas, const double* matrix)
+{
+ if (matrix)
+ {
+ XFORM xForm;
+ SetGraphicsMode(ctxcanvas->hDC, GM_ADVANCED);
+ ModifyWorldTransform(ctxcanvas->hDC, NULL, MWT_IDENTITY);
+
+ /* configure a bottom-up coordinate system */
+
+ /* Equivalent of:
+ SetMapMode(ctxcanvas->hDC, MM_ISOTROPIC);
+ SetWindowExtEx(ctxcanvas->hDC, ctxcanvas->canvas->w-1, ctxcanvas->canvas->h-1, NULL);
+ SetWindowOrgEx(ctxcanvas->hDC, 0, 0, NULL);
+ SetViewportExtEx(ctxcanvas->hDC, ctxcanvas->canvas->w-1, -(ctxcanvas->canvas->h-1), NULL);
+ SetViewportOrgEx(ctxcanvas->hDC, 0, ctxcanvas->canvas->h-1, NULL);
+ */
+
+ xForm.eM11 = (FLOAT)1;
+ xForm.eM12 = (FLOAT)0;
+ xForm.eM21 = (FLOAT)0;
+ xForm.eM22 = (FLOAT)-1;
+ xForm.eDx = (FLOAT)0;
+ xForm.eDy = (FLOAT)(ctxcanvas->canvas->h-1);
+ ModifyWorldTransform(ctxcanvas->hDC, &xForm, MWT_LEFTMULTIPLY);
+
+ ctxcanvas->canvas->invert_yaxis = 0;
+
+ xForm.eM11 = (FLOAT)matrix[0];
+ xForm.eM12 = (FLOAT)matrix[1];
+ xForm.eM21 = (FLOAT)matrix[2];
+ xForm.eM22 = (FLOAT)matrix[3];
+ xForm.eDx = (FLOAT)matrix[4];
+ xForm.eDy = (FLOAT)matrix[5];
+ ModifyWorldTransform(ctxcanvas->hDC, &xForm, MWT_LEFTMULTIPLY);
+ }
+ else
+ {
+ ctxcanvas->canvas->invert_yaxis = 1;
+ ModifyWorldTransform(ctxcanvas->hDC, NULL, MWT_IDENTITY);
+ SetGraphicsMode(ctxcanvas->hDC, GM_COMPATIBLE);
+ }
+}
+
+static void sTextOutBlt(cdCtxCanvas* ctxcanvas, int px, int py, const char* s, int n)
+{
+ HDC hBitmapDC;
+ HBITMAP hBitmap, hOldBitmap;
+ HFONT hOldFont;
+ int w, h, wt, ht, x, y, off, px_off = 0, py_off = 0;
+ double teta = ctxcanvas->canvas->text_orientation*CD_DEG2RAD;
+ double cos_teta = cos(teta);
+ double sin_teta = sin(teta);
+
+ cdCanvasGetTextSize(ctxcanvas->canvas, s, &w, &h);
+ wt = w;
+ ht = h;
+
+ if (ctxcanvas->canvas->text_orientation != 0)
+ {
+ /* novo tamanho da imagem */
+ w = (int)(w * cos_teta + h * sin_teta);
+ h = (int)(h * cos_teta + w * sin_teta);
+ }
+
+ /* coloca no centro da imagem */
+ y = h/2;
+ x = w/2;
+
+ /* corrige alinhamento do centro */
+ off = ht/2 - ctxcanvas->font.descent;
+ if (ctxcanvas->canvas->text_orientation != 0)
+ {
+ y += (int)(off * cos_teta);
+ x += (int)(off * sin_teta);
+ }
+ else
+ y += off;
+
+ /* calcula o alinhamento da imagem no canvas */
+ if (ctxcanvas->canvas->text_orientation != 0)
+ {
+ double d = sqrt(wt*wt + ht*ht);
+
+ switch (ctxcanvas->canvas->text_alignment)
+ {
+ case CD_CENTER:
+ py_off = 0;
+ px_off = 0;
+ break;
+ case CD_BASE_LEFT:
+ py_off = - (int)(off * cos_teta + w/2 * sin_teta);
+ px_off = (int)(w/2 * cos_teta - off * sin_teta);
+ break;
+ case CD_BASE_CENTER:
+ py_off = - (int)(off * cos_teta);
+ px_off = - (int)(off * sin_teta);
+ break;
+ case CD_BASE_RIGHT:
+ py_off = - (int)(off * cos_teta - w/2 * sin_teta);
+ px_off = - (int)(w/2 * cos_teta + off * sin_teta);
+ break;
+ case CD_NORTH:
+ py_off = (int)(ht/2 * cos_teta);
+ px_off = (int)(ht/2 * sin_teta);
+ break;
+ case CD_SOUTH:
+ py_off = - (int)(ht/2 * cos_teta);
+ px_off = - (int)(ht/2 * sin_teta);
+ break;
+ case CD_EAST:
+ py_off = (int)(wt/2 * sin_teta);
+ px_off = - (int)(wt/2 * cos_teta);
+ break;
+ case CD_WEST:
+ py_off = - (int)(wt/2 * sin_teta);
+ px_off = (int)(wt/2 * cos_teta);
+ break;
+ case CD_NORTH_EAST:
+ py_off = (int)(h/2);
+ px_off = - (int)(sqrt(d*d - h*h)/2);
+ break;
+ case CD_NORTH_WEST:
+ py_off = (int)(sqrt(d*d - w*w)/2);
+ px_off = - (int)(w/2);
+ break;
+ case CD_SOUTH_WEST:
+ py_off = - (int)(h/2);
+ px_off = (int)(sqrt(d*d - h*h)/2);
+ break;
+ case CD_SOUTH_EAST:
+ py_off = - (int)(sqrt(d*d - w*w)/2);
+ px_off = (int)(w/2);
+ break;
+ }
+ }
+ else
+ {
+ switch (ctxcanvas->canvas->text_alignment)
+ {
+ case CD_BASE_RIGHT:
+ case CD_NORTH_EAST:
+ case CD_EAST:
+ case CD_SOUTH_EAST:
+ px_off = - w/2;
+ break;
+ case CD_BASE_CENTER:
+ case CD_CENTER:
+ case CD_NORTH:
+ case CD_SOUTH:
+ px_off = 0;
+ break;
+ case CD_BASE_LEFT:
+ case CD_NORTH_WEST:
+ case CD_WEST:
+ case CD_SOUTH_WEST:
+ px_off = w/2;
+ break;
+ }
+
+ switch (ctxcanvas->canvas->text_alignment)
+ {
+ case CD_BASE_LEFT:
+ case CD_BASE_CENTER:
+ case CD_BASE_RIGHT:
+ py_off = - off;
+ break;
+ case CD_SOUTH_EAST:
+ case CD_SOUTH_WEST:
+ case CD_SOUTH:
+ py_off = - h/2;
+ break;
+ case CD_NORTH_EAST:
+ case CD_NORTH:
+ case CD_NORTH_WEST:
+ py_off = + h/2;
+ break;
+ case CD_CENTER:
+ case CD_EAST:
+ case CD_WEST:
+ py_off = py;
+ break;
+ }
+ }
+
+ /* move do centro da imagem para o canto superior esquerdo da imagem */
+ px_off -= w/2;
+ py_off -= h/2;
+
+ /* desloca o ponto dado */
+ if (ctxcanvas->canvas->invert_yaxis)
+ {
+ px += px_off;
+ py += py_off;
+ }
+ else
+ {
+ px += px_off;
+ py -= py_off;
+ }
+
+ hBitmap = CreateCompatibleBitmap(ctxcanvas->hDC, w, h);
+ hBitmapDC = CreateCompatibleDC(ctxcanvas->hDC);
+
+ hOldBitmap = SelectObject(hBitmapDC, hBitmap);
+
+ /* copia a area do canvas para o bitmap */
+ BitBlt(hBitmapDC, 0, 0, w, h, ctxcanvas->hDC, px, py, SRCCOPY);
+
+ /* compensa a ROP antes de desenhar */
+ BitBlt(hBitmapDC, 0, 0, w, h, ctxcanvas->hDC, px, py, ctxcanvas->RopBlt);
+
+ SetBkMode(hBitmapDC, TRANSPARENT);
+ SetBkColor(hBitmapDC, ctxcanvas->bg);
+ SetTextColor(hBitmapDC, ctxcanvas->fg);
+ SetTextAlign(hBitmapDC, TA_CENTER | TA_BASELINE);
+ hOldFont = SelectObject(hBitmapDC, ctxcanvas->hFont);
+
+ TextOut(hBitmapDC, x, y, s, n);
+
+ if (ctxcanvas->canvas->invert_yaxis)
+ BitBlt(ctxcanvas->hDC, px, py, w, h, hBitmapDC, 0, 0, ctxcanvas->RopBlt);
+ else
+ StretchBlt(ctxcanvas->hDC, px, py, w, -h, hBitmapDC, 0, 0, w, h, ctxcanvas->RopBlt);
+
+ SelectObject(hBitmapDC, hOldFont);
+ SelectObject(hBitmapDC, hOldBitmap);
+
+ DeleteObject(hBitmap);
+ DeleteDC(hBitmapDC);
+}
+
+static void cdgettextsize (cdCtxCanvas* ctxcanvas, const char *s, int *width, int *height)
+{
+ SIZE size;
+
+ GetTextExtentPoint32(ctxcanvas->hDC, s, (int)strlen(s), &size);
+
+ if (width)
+ *width = size.cx;
+
+ if (height)
+ *height = size.cy;
+}
+
+static void cdwCanvasGetTextHeight(cdCanvas* canvas, int x, int y, const char *s, int *hbox, int *hoff)
+{
+ int w, h, ascent, height, baseline;
+ int xmin, xmax, ymin, ymax;
+
+ cdCanvasGetTextSize(canvas, s, &w, &h);
+ cdCanvasGetFontDim(canvas, NULL, &height, &ascent, NULL);
+ baseline = height - ascent;
+
+ /* move to bottom-left */
+ cdTextTranslatePoint(canvas, x, y, w, h, baseline, &xmin, &ymin);
+
+ *hoff = y - 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];
+
+ *hoff = (int)(*hoff * cos_theta);
+
+ 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 cdwTextTransform(cdCtxCanvas* ctxcanvas, const char* s, int *x, int *y)
+{
+ XFORM xForm;
+ int hoff, h;
+
+ cdwCanvasGetTextHeight(ctxcanvas->canvas, *x, *y, s, &h, &hoff);
+
+ /* move to (x,y) and remove a vertical offset since text reference point is top-left */
+ xForm.eM11 = (FLOAT)1;
+ xForm.eM12 = (FLOAT)0;
+ xForm.eM21 = (FLOAT)0;
+ xForm.eM22 = (FLOAT)1;
+ xForm.eDx = (FLOAT)*x;
+ xForm.eDy = (FLOAT)(*y - (h-1) - hoff);
+ ModifyWorldTransform(ctxcanvas->hDC, &xForm, MWT_LEFTMULTIPLY);
+
+ /* invert the text vertical orientation, relative to itself */
+ xForm.eM11 = (FLOAT)1;
+ xForm.eM12 = (FLOAT)0;
+ xForm.eM21 = (FLOAT)0;
+ xForm.eM22 = (FLOAT)-1;
+ xForm.eDx = (FLOAT)0;
+ xForm.eDy = (FLOAT)(h-1);
+ ModifyWorldTransform(ctxcanvas->hDC, &xForm, MWT_LEFTMULTIPLY);
+
+ *x = 0;
+ *y = 0;
+}
+
+static void cdtext(cdCtxCanvas* ctxcanvas, int x, int y, const char *s)
+{
+ int n = (int)strlen(s);
+
+ if (ctxcanvas->canvas->write_mode == CD_REPLACE ||
+ ctxcanvas->wtype == CDW_EMF ||
+ ctxcanvas->wtype == CDW_WMF ||
+ ctxcanvas->canvas->new_region)
+ {
+ int h = -1;
+
+ if ((ctxcanvas->canvas->text_alignment == CD_CENTER ||
+ ctxcanvas->canvas->text_alignment == CD_EAST ||
+ ctxcanvas->canvas->text_alignment == CD_WEST) &&
+ ctxcanvas->wtype != CDW_WMF)
+ {
+ /* compensa deficiencia do alinhamento no windows */
+ int off;
+ cdCanvasGetTextSize(ctxcanvas->canvas, s, NULL, &h);
+ off = h/2 - ctxcanvas->font.descent;
+
+ if (ctxcanvas->canvas->text_orientation != 0)
+ {
+ y += (int)(off * cos(ctxcanvas->canvas->text_orientation*CD_DEG2RAD));
+ x += (int)(off * sin(ctxcanvas->canvas->text_orientation*CD_DEG2RAD));
+ }
+ else
+ y += off;
+ }
+
+ if (ctxcanvas->canvas->back_opacity == CD_OPAQUE)
+ SetBkMode(ctxcanvas->hDC, TRANSPARENT);
+
+ if (ctxcanvas->canvas->new_region)
+ BeginPath(ctxcanvas->hDC);
+
+ if (ctxcanvas->canvas->use_matrix)
+ cdwTextTransform(ctxcanvas, s, &x, &y);
+
+ TextOut(ctxcanvas->hDC, x, y+1, s, n); /* compensa erro de desenho com +1 */
+
+ if (ctxcanvas->canvas->use_matrix)
+ cdtransform(ctxcanvas, ctxcanvas->canvas->matrix);
+
+ if (ctxcanvas->canvas->new_region)
+ {
+ HRGN rgn;
+ EndPath(ctxcanvas->hDC);
+ rgn = PathToRegion(ctxcanvas->hDC);
+ CombineRgn(ctxcanvas->new_rgn, ctxcanvas->new_rgn, rgn, sCombineRegion2win[ctxcanvas->canvas->combine_mode]);
+ DeleteObject(rgn);
+ }
+
+ if (ctxcanvas->canvas->back_opacity == CD_OPAQUE)
+ SetBkMode(ctxcanvas->hDC, OPAQUE);
+ }
+ else
+ sTextOutBlt(ctxcanvas, x, y+1, s, n);
+}
+
+static int cdtextalignment(cdCtxCanvas* ctxcanvas, int text_align)
+{
+ int align = TA_NOUPDATECP;
+
+ switch (text_align)
+ {
+ case CD_BASE_RIGHT:
+ case CD_NORTH_EAST:
+ case CD_EAST:
+ case CD_SOUTH_EAST:
+ align |= TA_RIGHT;
+ break;
+ case CD_BASE_CENTER:
+ case CD_CENTER:
+ case CD_NORTH:
+ case CD_SOUTH:
+ align |= TA_CENTER;
+ break;
+ case CD_BASE_LEFT:
+ case CD_NORTH_WEST:
+ case CD_WEST:
+ case CD_SOUTH_WEST:
+ align |= TA_LEFT;
+ break;
+ }
+
+ switch (text_align)
+ {
+ case CD_BASE_LEFT:
+ case CD_BASE_CENTER:
+ case CD_BASE_RIGHT:
+ align |= TA_BASELINE;
+ break;
+ case CD_SOUTH_EAST:
+ case CD_SOUTH_WEST:
+ case CD_SOUTH:
+ align |= TA_BOTTOM;
+ break;
+ case CD_NORTH_EAST:
+ case CD_NORTH:
+ case CD_NORTH_WEST:
+ align |= TA_TOP;
+ break;
+ case CD_CENTER:
+ case CD_EAST:
+ case CD_WEST:
+ align |= TA_BASELINE; /* tem que compensar ao desenhar o texto */
+ break;
+ }
+
+ SetTextAlign(ctxcanvas->hDC, align);
+
+ return text_align;
+}
+
+static int cdfont(cdCtxCanvas* ctxcanvas, const char *type_face, int style, int size)
+{
+ TEXTMETRIC tm;
+ DWORD bold, italic = 0, underline = 0, strikeout = 0;
+ int angle, size_pixel;
+ HFONT hFont;
+
+ if (style&CD_BOLD)
+ bold = FW_BOLD;
+ else
+ bold = FW_NORMAL;
+
+ if (style&CD_ITALIC)
+ italic = 1;
+
+ if (style&CD_UNDERLINE)
+ underline = 1;
+
+ if (style&CD_STRIKEOUT)
+ strikeout = 1;
+
+ angle = ctxcanvas->font_angle;
+
+ if (cdStrEqualNoCase(type_face, "Courier") || cdStrEqualNoCase(type_face, "Monospace"))
+ type_face = "Courier New";
+ else if (cdStrEqualNoCase(type_face, "Times") || cdStrEqualNoCase(type_face, "Serif"))
+ type_face = "Times New Roman";
+ else if (cdStrEqualNoCase(type_face, "Helvetica") || cdStrEqualNoCase(type_face, "Sans"))
+ type_face = "Arial";
+
+ size_pixel = cdGetFontSizePixels(ctxcanvas->canvas, size);
+ hFont = CreateFont(-size_pixel, 0, angle, angle, bold, italic, underline, strikeout,
+ DEFAULT_CHARSET,OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FF_DONTCARE|DEFAULT_PITCH,
+ type_face);
+ if (!hFont) return 0;
+
+ if (ctxcanvas->hOldFont) SelectObject(ctxcanvas->hDC, ctxcanvas->hOldFont);
+ if (ctxcanvas->hFont) DeleteObject(ctxcanvas->hFont);
+ ctxcanvas->hFont = hFont;
+ ctxcanvas->hOldFont = SelectObject(ctxcanvas->hDC, ctxcanvas->hFont);
+
+ GetTextMetrics (ctxcanvas->hDC, &tm);
+ ctxcanvas->font.max_width = tm.tmMaxCharWidth;
+ ctxcanvas->font.height = tm.tmHeight + tm.tmExternalLeading ;
+ ctxcanvas->font.ascent = tm.tmAscent;
+ ctxcanvas->font.descent = tm.tmDescent;
+
+ return 1;
+}
+
+static int cdnativefont (cdCtxCanvas* ctxcanvas, const char* nativefont)
+{
+ TEXTMETRIC tm;
+ HFONT hFont;
+ int size = 12, bold = FW_NORMAL, italic = 0,
+ style = CD_PLAIN, underline = 0, strikeout = 0,
+ size_pixel;
+ char type_face[1024];
+
+ if (nativefont[0] == '-' && nativefont[1] == 'd')
+ {
+ COLORREF rgbColors;
+ CHOOSEFONT cf;
+ LOGFONT lf;
+
+ 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;
+
+ GetTextFace(ctxcanvas->hDC, 50, type_face);
+ GetTextMetrics(ctxcanvas->hDC, &tm); /* get the current selected nativefont */
+
+ size_pixel = cdGetFontSizePixels(ctxcanvas->canvas, ctxcanvas->canvas->font_size);
+
+ strcpy(lf.lfFaceName, type_face);
+ lf.lfWeight = tm.tmWeight;
+ lf.lfHeight = -size_pixel;
+ lf.lfItalic = tm.tmItalic;
+ lf.lfUnderline = tm.tmUnderlined;
+ lf.lfStrikeOut = tm.tmStruckOut;
+ lf.lfCharSet = tm.tmCharSet;
+ lf.lfEscapement = ctxcanvas->font_angle;
+ lf.lfOrientation = ctxcanvas->font_angle;
+ lf.lfWidth = 0;
+ lf.lfOutPrecision = OUT_TT_PRECIS;
+ lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ lf.lfQuality = DEFAULT_QUALITY;
+ lf.lfPitchAndFamily = FF_DONTCARE|DEFAULT_PITCH;
+
+ if (ChooseFont(&cf))
+ {
+ if (rgbColors != cf.rgbColors)
+ cdCanvasSetForeground(ctxcanvas->canvas, sColorFromWindows(cf.rgbColors));
+
+ hFont = CreateFontIndirect(&lf);
+ }
+ else
+ return 0;
+
+ bold = lf.lfWeight;
+ italic = lf.lfItalic;
+ size = lf.lfHeight;
+ strcpy(type_face, lf.lfFaceName);
+ underline = lf.lfUnderline;
+ strikeout = lf.lfStrikeOut;
+
+ if (bold!=FW_NORMAL) 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 = FW_BOLD;
+ if (style&CD_ITALIC)
+ italic = 1;
+ if (style&CD_UNDERLINE)
+ underline = 1;
+ if (style&CD_STRIKEOUT)
+ strikeout = 1;
+
+ size_pixel = cdGetFontSizePixels(ctxcanvas->canvas, size);
+
+ hFont = CreateFont(-size_pixel, 0, ctxcanvas->font_angle, ctxcanvas->font_angle,
+ bold, italic, underline, strikeout,
+ DEFAULT_CHARSET,OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FF_DONTCARE|DEFAULT_PITCH, type_face);
+ if (!hFont) return 0;
+ }
+
+ if (ctxcanvas->hOldFont) SelectObject(ctxcanvas->hDC, ctxcanvas->hOldFont);
+ DeleteObject(ctxcanvas->hFont);
+ ctxcanvas->hFont = hFont;
+ ctxcanvas->hOldFont = SelectObject(ctxcanvas->hDC, ctxcanvas->hFont);
+
+ GetTextMetrics(ctxcanvas->hDC, &tm);
+ ctxcanvas->font.max_width = tm.tmMaxCharWidth;
+ ctxcanvas->font.height = tm.tmHeight + tm.tmExternalLeading;
+ ctxcanvas->font.ascent = tm.tmAscent;
+ ctxcanvas->font.descent = tm.tmDescent;
+
+ /* update cdfont parameters */
+ ctxcanvas->canvas->font_style = style;
+ ctxcanvas->canvas->font_size = size;
+ strcpy(ctxcanvas->canvas->font_type_face, type_face);
+
+ return 1;
+}
+
+static double cdtextorientation(cdCtxCanvas* ctxcanvas, double angle)
+{
+ if (ctxcanvas->font_angle == angle) /* first time angle=0, do not create font twice */
+ return angle;
+
+ ctxcanvas->font_angle = (int)(angle * 10);
+
+ cdfont(ctxcanvas, ctxcanvas->canvas->font_type_face, ctxcanvas->canvas->font_style, ctxcanvas->canvas->font_size);
+
+ return angle;
+}
+
+static void cdgetfontdim (cdCtxCanvas* ctxcanvas, int *max_width, int *line_height, int *ascent, int *descent)
+{
+ if (max_width)
+ *max_width = ctxcanvas->font.max_width;
+
+ if (line_height)
+ *line_height = ctxcanvas->font.height;
+
+ if (ascent)
+ *ascent = ctxcanvas->font.ascent;
+
+ if (descent)
+ *descent = ctxcanvas->font.descent;
+
+ return;
+}
+
+/*
+%F Desenha um retangulo no canvas todo com a cor do fundo.
+*/
+static void cdclear(cdCtxCanvas* ctxcanvas)
+{
+ RECT rect;
+
+ if (ctxcanvas->canvas->clip_mode != CD_CLIPOFF)
+ SelectClipRgn( ctxcanvas->hDC, NULL ); /* toda 'area do canvas */
+
+ SetRect(&rect, 0, 0, ctxcanvas->canvas->w, ctxcanvas->canvas->h);
+ FillRect(ctxcanvas->hDC, &rect, ctxcanvas->hBkBrush);
+
+ if (ctxcanvas->canvas->clip_mode != CD_CLIPOFF)
+ cdclip(ctxcanvas, ctxcanvas->canvas->clip_mode);
+}
+
+
+/******************************************************************/
+/*
+%S Funcoes de imagens do cliente
+*/
+/******************************************************************/
+
+static void cdgetimagergb(cdCtxCanvas* ctxcanvas, unsigned char *red, unsigned char *green, unsigned char *blue, int x, int y, int w, int h)
+{
+ XFORM xForm;
+ cdwDIB dib;
+ HDC hDCMem;
+ HBITMAP hOldBitmap,hBitmap;
+ int yr;
+
+ hBitmap = CreateCompatibleBitmap(ctxcanvas->hDC, w, h);
+ if (hBitmap == NULL)
+ return;
+
+ hDCMem = CreateCompatibleDC(ctxcanvas->hDC);
+
+ hOldBitmap = SelectObject(hDCMem, hBitmap);
+
+ if (GetGraphicsMode(ctxcanvas->hDC) == GM_ADVANCED)
+ {
+ GetWorldTransform(ctxcanvas->hDC, &xForm);
+ ModifyWorldTransform(ctxcanvas->hDC, NULL, MWT_IDENTITY);
+ }
+
+ if (ctxcanvas->canvas->invert_yaxis==0) // if 0, then the transform was reset
+ y = _cdInvertYAxis(ctxcanvas->canvas, y);
+
+ yr = y - (h - 1); /* y starts at the bottom of the image */
+ BitBlt(hDCMem,0,0,w,h,ctxcanvas->hDC, x, yr, SRCCOPY);
+
+ if (GetGraphicsMode(ctxcanvas->hDC) == GM_ADVANCED)
+ ModifyWorldTransform(ctxcanvas->hDC, &xForm, MWT_LEFTMULTIPLY);
+
+ dib.w = w;
+ dib.h = h;
+ dib.type = 0;
+
+ if (!cdwCreateDIB(&dib))
+ {
+ SelectObject(hDCMem, hOldBitmap);
+ DeleteObject(hBitmap);
+ DeleteDC(hDCMem);
+ return;
+ }
+
+ GetDIBits(ctxcanvas->hDC, hBitmap, 0, h, dib.bits, dib.bmi, DIB_RGB_COLORS);
+
+ SelectObject(hDCMem, hOldBitmap);
+ DeleteObject(hBitmap);
+ DeleteDC(hDCMem);
+
+ cdwDIBDecodeRGB(&dib, red, green, blue);
+
+ cdwKillDIB(&dib);
+}
+
+static void sFixImageY(cdCanvas* canvas, int *y, int *h)
+{
+ /* Here, y is from top to bottom,
+ is at the bottom-left corner of the image if h>0
+ is at the top-left corner of the image if h<0. (Undocumented feature)
+ cdCalcZoom expects Y at top-left if h>0
+ and Y at bottom-left if h<0
+ if h<0 then eh<0 to StretchDIBits mirror the image.
+ BUT!!!!!! AlphaBlend will NOT mirror the image. */
+
+ if (!canvas->invert_yaxis)
+ *h = -(*h);
+
+ if (*h < 0)
+ *y -= ((*h) + 1); /* compensate for cdCalcZoom */
+ else
+ *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)
+{
+ cdwDIB dib;
+ int ew, eh, ex, ey; /* posicao da imagem com zoom no canvas e tamanho da imagem com zoom depois de otimizado */
+ int bw, bh, bx, by; /* posicao dentro da imagem e tamanho dentro da imagem do pedaco que sera desenhado depois de otimizado */
+ int rw, rh; /* tamanho dentro da imagem antes de otimizado */
+
+ rw = xmax-xmin+1;
+ rh = ymax-ymin+1;
+
+ sFixImageY(ctxcanvas->canvas, &y, &h);
+
+ if (!cdCalcZoom(ctxcanvas->canvas->w, x, w, &ex, &ew, xmin, rw, &bx, &bw, 1))
+ return;
+
+ if (!cdCalcZoom(ctxcanvas->canvas->h, y, h, &ey, &eh, ymin, rh, &by, &bh, 0))
+ return;
+
+ dib.w = bw;
+ dib.h = bh;
+ dib.type = 1;
+
+ if (!cdwCreateDIBRefBuffer(&dib, &ctxcanvas->dib_bits, &ctxcanvas->bits_size))
+ return;
+
+ cdwDIBEncodeMapRect(&dib, index, colors, bx, by, width, height);
+
+ StretchDIBits(ctxcanvas->hDC,
+ ex, ey, ew, eh,
+ 0, 0, bw, bh,
+ dib.bits, dib.bmi, DIB_RGB_COLORS, ctxcanvas->RopBlt);
+}
+
+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)
+{
+ cdwDIB dib;
+ int ew, eh, ex, ey;
+ int bw, bh, bx, by;
+ int rw, rh;
+
+ rw = xmax-xmin+1;
+ rh = ymax-ymin+1;
+
+ sFixImageY(ctxcanvas->canvas, &y, &h);
+
+ if (!cdCalcZoom(ctxcanvas->canvas->w, x, w, &ex, &ew, xmin, rw, &bx, &bw, 1))
+ return;
+
+ if (!cdCalcZoom(ctxcanvas->canvas->h, y, h, &ey, &eh, ymin, rh, &by, &bh, 0))
+ return;
+
+ dib.w = bw;
+ dib.h = bh;
+ dib.type = 0;
+
+ if (!cdwCreateDIBRefBuffer(&dib, &ctxcanvas->dib_bits, &ctxcanvas->bits_size))
+ return;
+
+ cdwDIBEncodeRGBRect(&dib, red, green, blue, bx, by, width, height);
+
+ StretchDIBits(ctxcanvas->hDC,
+ ex, ey, ew, eh,
+ 0, 0, bw, bh,
+ dib.bits, dib.bmi, DIB_RGB_COLORS, ctxcanvas->RopBlt);
+}
+
+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)
+{
+ cdwDIB dib;
+ HDC hDCMem;
+ HBITMAP hOldBitmap, hBitmap;
+ int ew, eh, ex, ey;
+ int bw, bh, bx, by;
+ int rw, rh;
+
+ rw = xmax-xmin+1;
+ rh = ymax-ymin+1;
+
+ sFixImageY(ctxcanvas->canvas, &y, &h);
+
+ if (!cdCalcZoom(ctxcanvas->canvas->w, x, w, &ex, &ew, xmin, rw, &bx, &bw, 1))
+ return;
+
+ if (!cdCalcZoom(ctxcanvas->canvas->h, y, h, &ey, &eh, ymin, rh, &by, &bh, 0))
+ return;
+
+ hDCMem = CreateCompatibleDC(ctxcanvas->hDC);
+
+ if (cdwAlphaBlend)
+ {
+ BLENDFUNCTION blendfunc;
+
+ dib.w = bw;
+ dib.h = bh;
+ dib.type = 2; /* RGBA */
+
+ hBitmap = cdwCreateDIBSection(&dib, hDCMem);
+ if (!hBitmap)
+ {
+ DeleteDC(hDCMem);
+ return;
+ }
+
+ cdwDIBEncodeRGBARect(&dib, red, green, blue, alpha, bx, by, width, height);
+
+ if (eh < 0) /* must mirror the image */
+ {
+ XFORM xForm;
+
+ eh = -eh;
+
+ SetGraphicsMode(hDCMem, GM_ADVANCED);
+ ModifyWorldTransform(hDCMem, NULL, MWT_IDENTITY);
+
+ /* configure a bottom-up coordinate system */
+ xForm.eM11 = (FLOAT)1;
+ xForm.eM12 = (FLOAT)0;
+ xForm.eM21 = (FLOAT)0;
+ xForm.eM22 = (FLOAT)-1;
+ xForm.eDx = (FLOAT)0;
+ xForm.eDy = (FLOAT)(bh-1);
+ ModifyWorldTransform(hDCMem, &xForm, MWT_LEFTMULTIPLY);
+ }
+
+ hOldBitmap = SelectObject(hDCMem, hBitmap);
+
+ blendfunc.BlendOp = AC_SRC_OVER;
+ blendfunc.BlendFlags = 0;
+ blendfunc.SourceConstantAlpha = 0xFF;
+ blendfunc.AlphaFormat = AC_SRC_ALPHA;
+
+ cdwAlphaBlend(ctxcanvas->hDC,
+ ex, ey, ew, eh,
+ hDCMem,
+ 0, 0, bw, bh,
+ blendfunc);
+ }
+ else
+ {
+ hBitmap = CreateCompatibleBitmap(ctxcanvas->hDC, ew, eh); /* captura do tamanho do destino */
+ if (!hBitmap)
+ {
+ DeleteDC(hDCMem);
+ return;
+ }
+
+ hOldBitmap = SelectObject(hDCMem, hBitmap);
+
+ BitBlt(hDCMem, 0, 0, ew, eh, ctxcanvas->hDC, ex, ey, SRCCOPY);
+
+ dib.w = ew; /* neste caso o tamanho usado e´ o de destino */
+ dib.h = eh;
+ dib.type = 0;
+
+ if (!cdwCreateDIB(&dib))
+ {
+ SelectObject(hDCMem, hOldBitmap);
+ DeleteObject(hBitmap);
+ DeleteDC(hDCMem);
+ return;
+ }
+
+ GetDIBits(hDCMem, hBitmap, 0, eh, dib.bits, dib.bmi, DIB_RGB_COLORS);
+
+ cdwDIBEncodeRGBARectZoom(&dib, red, green, blue, alpha, width, height, bx, by, bw, bh);
+
+ StretchDIBits(ctxcanvas->hDC,
+ ex, ey, ew, eh,
+ 0, 0, ew, eh, /* Nao tem zoom neste caso, pois e´ feito manualmente pela EncodeRGBA */
+ dib.bits, dib.bmi, DIB_RGB_COLORS, ctxcanvas->RopBlt);
+ }
+
+ SelectObject(hDCMem, hOldBitmap);
+ DeleteObject(hBitmap);
+ DeleteDC(hDCMem);
+ cdwKillDIB(&dib);
+}
+
+
+/********************************************************************/
+/*
+%S Funcoes de imagens do servidor
+*/
+/********************************************************************/
+
+static void cdpixel(cdCtxCanvas* ctxcanvas, int x, int y, long int cd_color)
+{
+ SetPixelV(ctxcanvas->hDC, x, y, sColorToWindows(ctxcanvas, cd_color));
+}
+
+static cdCtxImage *cdcreateimage(cdCtxCanvas* ctxcanvas, int width, int height)
+{
+ HDC hDCMem;
+ HBITMAP hOldBitmap,hBitmap;
+ cdCtxImage *ctximage;
+ void* rgba_dib = NULL;
+ unsigned char* alpha = NULL;
+
+ if (ctxcanvas->img_format)
+ {
+ cdwDIB dib;
+
+ dib.w = width;
+ dib.h = height;
+ if (ctxcanvas->img_format == 32)
+ dib.type = CDW_RGBA;
+ else
+ dib.type = CDW_RGB;
+
+ hBitmap = cdwCreateDIBSection(&dib, ctxcanvas->hDC);
+ if (!hBitmap)
+ return NULL;
+
+ rgba_dib = dib.bits;
+ alpha = ctxcanvas->img_alpha;
+
+ cdwKillDIB(&dib); /* this will just remove the headers not the dib bits in this case */
+ }
+ else
+ {
+ hBitmap = CreateCompatibleBitmap(ctxcanvas->hDC, width, height);
+ if (!hBitmap)
+ return NULL;
+ }
+
+ hDCMem = CreateCompatibleDC(ctxcanvas->hDC);
+ hOldBitmap = SelectObject(hDCMem, hBitmap);
+
+ PatBlt(hDCMem, 0, 0, width, height, WHITENESS);
+
+ /* salva o contexto desta imagem */
+ ctximage = (cdCtxImage*)malloc(sizeof(cdCtxImage));
+
+ ctximage->hDC = hDCMem;
+ ctximage->hBitmap = hBitmap;
+ ctximage->hOldBitmap = hOldBitmap;
+ ctximage->w = width;
+ ctximage->h = height;
+ ctximage->rgba_dib = rgba_dib;
+ ctximage->alpha = alpha;
+
+ 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;
+
+ return ctximage;
+}
+
+static void cdgetimage(cdCtxCanvas* ctxcanvas, cdCtxImage *ctximage, int x, int y)
+{
+ int yr;
+ XFORM xForm;
+
+ if (GetGraphicsMode(ctxcanvas->hDC) == GM_ADVANCED)
+ {
+ GetWorldTransform(ctxcanvas->hDC, &xForm);
+ ModifyWorldTransform(ctxcanvas->hDC, NULL, MWT_IDENTITY);
+ }
+
+ if (ctxcanvas->canvas->invert_yaxis==0) // if 0, then the transform was reset
+ y = _cdInvertYAxis(ctxcanvas->canvas, y);
+
+ yr = y - (ctximage->h - 1);
+ BitBlt(ctximage->hDC, 0, 0, ctximage->w, ctximage->h, ctxcanvas->hDC, x, yr, SRCCOPY);
+
+ if (GetGraphicsMode(ctxcanvas->hDC) == GM_ADVANCED)
+ ModifyWorldTransform(ctxcanvas->hDC, &xForm, MWT_LEFTMULTIPLY);
+}
+
+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 */
+
+ if (ctximage->alpha && ctximage->bpp == 32 && cdwAlphaBlend)
+ {
+ cdwDIB dib;
+ BLENDFUNCTION blendfunc;
+ blendfunc.BlendOp = AC_SRC_OVER;
+ blendfunc.BlendFlags = 0;
+ blendfunc.SourceConstantAlpha = 0xFF;
+ blendfunc.AlphaFormat = AC_SRC_ALPHA;
+
+ dib.w = ctximage->w;
+ dib.h = ctximage->h;
+ dib.type = CDW_RGBA;
+ cdwCreateDIBRefBits(&dib, ctximage->rgba_dib);
+
+ cdwDIBEncodeAlphaRect(&dib, ctximage->alpha, 0, 0, ctximage->w, ctximage->h);
+
+ GdiFlush();
+ cdwAlphaBlend(ctxcanvas->hDC,
+ x0, yr, xmax-xmin+1, ymax-ymin+1,
+ ctximage->hDC,
+ xmin, ctximage->h-ymax-1, xmax-xmin+1, ymax-ymin+1,
+ blendfunc);
+
+ cdwKillDIB(&dib);
+ }
+ else 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);
+ }
+ PlgBlt(ctxcanvas->hDC, pts, ctximage->hDC, xmin, ctximage->h-ymax-1, xmax-xmin+1, ymax-ymin+1, ctxcanvas->img_mask, 0, 0);
+ }
+ else if (ctxcanvas->img_mask)
+ MaskBlt(ctxcanvas->hDC,x0,yr, xmax-xmin+1, ymax-ymin+1, ctximage->hDC, xmin, ctximage->h-ymax-1, ctxcanvas->img_mask, 0, 0, MAKEROP4(ctxcanvas->RopBlt, 0xAA0000));
+ else
+ BitBlt(ctxcanvas->hDC,x0,yr, xmax-xmin+1, ymax-ymin+1, ctximage->hDC, xmin, ctximage->h-ymax-1, ctxcanvas->RopBlt);
+}
+
+static void cdkillimage(cdCtxImage *ctximage)
+{
+ SelectObject(ctximage->hDC, ctximage->hOldBitmap);
+ DeleteObject(ctximage->hBitmap);
+ DeleteDC(ctximage->hDC);
+ free(ctximage);
+}
+
+static void cdscrollarea(cdCtxCanvas* ctxcanvas, int xmin, int xmax, int ymin, int ymax, int dx, int dy)
+{
+ XFORM xForm;
+ RECT rect;
+ rect.left = xmin;
+ rect.right = xmax+1;
+ rect.top = ymin;
+ rect.bottom = ymax+1;
+
+ if (GetGraphicsMode(ctxcanvas->hDC) == GM_ADVANCED)
+ {
+ GetWorldTransform(ctxcanvas->hDC, &xForm);
+ ModifyWorldTransform(ctxcanvas->hDC, NULL, MWT_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);
+ }
+
+ ScrollDC(ctxcanvas->hDC, dx, dy, &rect, NULL, NULL, NULL);
+
+ if (GetGraphicsMode(ctxcanvas->hDC) == GM_ADVANCED)
+ ModifyWorldTransform(ctxcanvas->hDC, &xForm, MWT_LEFTMULTIPLY);
+}
+
+static void cdflush(cdCtxCanvas* ctxcanvas)
+{
+ (void)ctxcanvas;
+ GdiFlush();
+}
+
+/********************************************************************/
+/*
+%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_mask_attrib(cdCtxCanvas* ctxcanvas, char* data)
+{
+ if (!data)
+ {
+ if (ctxcanvas->img_mask) DeleteObject(ctxcanvas->img_mask);
+ ctxcanvas->img_mask = NULL;
+ }
+ else
+ {
+ int w = 0, h = 0;
+ unsigned char *index = 0;
+ sscanf(data, "%d %d %p", &w, &h, &index);
+ if (w && h && index)
+ ctxcanvas->img_mask = Stipple2Bitmap(w, h, index, 1);
+ }
+}
+
+static cdAttribute img_mask_attrib =
+{
+ "IMAGEMASK",
+ set_img_mask_attrib,
+ NULL
+};
+
+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].x = p[0];
+ ctxcanvas->img_points[0].y = p[1];
+ ctxcanvas->img_points[1].x = p[2];
+ ctxcanvas->img_points[1].y = p[3];
+ ctxcanvas->img_points[2].x = p[4];
+ ctxcanvas->img_points[2].y = 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 void set_rotate_attrib(cdCtxCanvas* ctxcanvas, char* data)
+{
+ /* ignore ROTATE if transform is set */
+ 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);
+ }
+}
+
+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_fill_attrib(cdCtxCanvas* ctxcanvas, char* data)
+{
+ ctxcanvas->fill_attrib[0] = data[0];
+}
+
+static char* get_fill_attrib(cdCtxCanvas* ctxcanvas)
+{
+ return ctxcanvas->fill_attrib;
+}
+
+static cdAttribute fill_attrib =
+{
+ "PENFILLPOLY",
+ set_fill_attrib,
+ get_fill_attrib
+};
+
+static void set_window_rgn(cdCtxCanvas* ctxcanvas, char* data)
+{
+ if (data)
+ {
+ HRGN hrgn = CreateRectRgn(0,0,0,0);
+ CombineRgn(hrgn, ctxcanvas->new_rgn, NULL, RGN_COPY);
+ 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
+};
+
+/*
+%F Cria o canvas para o driver Windows.
+*/
+cdCtxCanvas *cdwCreateCanvas(cdCanvas* canvas, HWND hWnd, HDC hDC, int wtype)
+{
+ cdCtxCanvas* ctxcanvas;
+ LOGPEN logNullPen;
+
+ ctxcanvas = (cdCtxCanvas*)malloc(sizeof(cdCtxCanvas));
+ memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
+
+ /* store the base canvas */
+ ctxcanvas->canvas = canvas;
+
+ /* update canvas context */
+ canvas->ctxcanvas = ctxcanvas;
+
+ ctxcanvas->hWnd = hWnd;
+ ctxcanvas->hDC = hDC;
+ canvas->invert_yaxis = 1;
+
+ /* linha nula para fill de interior apenas */
+ logNullPen.lopnStyle = PS_NULL;
+ ctxcanvas->hNullPen = CreatePenIndirect(&logNullPen);
+
+ ctxcanvas->logPen.lopnStyle = PS_SOLID;
+ ctxcanvas->logPen.lopnWidth.x = 1; /* 1 para que a linha possa ter estilo */
+ ctxcanvas->logPen.lopnColor = 0;
+ ctxcanvas->rebuild_pen = 1;
+
+ ctxcanvas->logBrush.lbStyle = BS_SOLID;
+ ctxcanvas->logBrush.lbColor = 0;
+ ctxcanvas->logBrush.lbHatch = HS_BDIAGONAL;
+
+ ctxcanvas->clip_pnt = (POINT*)malloc(sizeof(POINT)*4);
+ memset(ctxcanvas->clip_pnt, 0, sizeof(POINT)*4);
+ ctxcanvas->clip_pnt_n = 4;
+
+ ctxcanvas->wtype = wtype;
+
+ SetStretchBltMode(ctxcanvas->hDC, COLORONCOLOR);
+
+ ctxcanvas->fill_attrib[0] = '1';
+ ctxcanvas->fill_attrib[1] = 0;
+
+ cdRegisterAttribute(canvas, &hdc_attrib);
+ cdRegisterAttribute(canvas, &fill_attrib);
+ cdRegisterAttribute(canvas, &img_points_attrib);
+ cdRegisterAttribute(canvas, &img_mask_attrib);
+ cdRegisterAttribute(canvas, &rotate_attrib);
+ cdRegisterAttribute(canvas, &img_alpha_attrib);
+ cdRegisterAttribute(canvas, &img_format_attrib);
+ cdRegisterAttribute(canvas, &window_rgn_attrib);
+
+ if (!cdwAlphaBlend)
+ {
+ HINSTANCE lib = LoadLibrary("Msimg32");
+ if (lib)
+ cdwAlphaBlend = (AlphaBlendFunc)GetProcAddress(lib, "AlphaBlend");
+ }
+
+ return ctxcanvas;
+}
+
+void cdwInitTable(cdCanvas* canvas)
+{
+ cdCtxCanvas* ctxcanvas = canvas->ctxcanvas;
+
+ 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->cxGetFontDim = cdgetfontdim;
+ canvas->cxGetTextSize = cdgettextsize;
+ canvas->cxPutImageRectRGB = cdputimagerectrgb;
+ canvas->cxPutImageRectMap = cdputimagerectmap;
+ canvas->cxScrollArea = cdscrollarea;
+ canvas->cxNewRegion = cdnewregion;
+ canvas->cxIsPointInRegion = cdispointinregion;
+ canvas->cxOffsetRegion = cdoffsetregion;
+ canvas->cxGetRegionBox = cdgetregionbox;
+
+ canvas->cxClip = cdclip;
+ canvas->cxClipArea = cdcliparea;
+ canvas->cxBackOpacity = cdbackopacity;
+ canvas->cxWriteMode = cdwritemode;
+ 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->cxTextOrientation = cdtextorientation;
+ canvas->cxTextAlignment = cdtextalignment;
+ canvas->cxPalette = cdpalette;
+ canvas->cxBackground = cdbackground;
+ canvas->cxForeground = cdforeground;
+ canvas->cxTransform = cdtransform;
+
+ canvas->cxKillCanvas = cdwKillCanvas;
+ canvas->cxFlush = cdflush;
+
+ if (ctxcanvas->wtype == CDW_WIN || ctxcanvas->wtype == CDW_BMP)
+ {
+ canvas->cxClear = cdclear;
+ canvas->cxGetImageRGB = cdgetimagergb;
+ canvas->cxPutImageRectRGBA = cdputimagerectrgba;
+ canvas->cxCreateImage = cdcreateimage;
+ canvas->cxGetImage = cdgetimage;
+ canvas->cxPutImageRect = cdputimagerect;
+ canvas->cxKillImage = cdkillimage;
+ }
+
+ if (ctxcanvas->wtype == CDW_EMF)
+ canvas->cxPutImageRectRGBA = cdputimagerectrgba;
+}
diff --git a/src/win32/cdwin.h b/src/win32/cdwin.h
new file mode 100644
index 0000000..1f4434f
--- /dev/null
+++ b/src/win32/cdwin.h
@@ -0,0 +1,181 @@
+/** \file
+ * \brief Windows Base Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#ifndef __CDWIN_H
+#define __CDWIN_H
+
+#include <windows.h>
+#include "cd.h"
+#include "cd_private.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+/* Contexto de cada imagem no servidor */
+struct _cdCtxImage
+{
+ HDC hDC; /* handle para o contexto de imagem na memoria */
+ HBITMAP hBitmap; /* handle para o bitmap associado */
+ HBITMAP hOldBitmap; /* handle para o bitmap associado inicialmente */
+ 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;
+
+ void* rgba_dib; /* used by 32 bpp to set alpha before putimage */
+ unsigned char* alpha; /* the alpha values must be stored here */
+};
+
+/* Contexto de cada canvas (CanvasContext). */
+struct _cdCtxCanvas
+{
+ cdCanvas* canvas;
+
+ HWND hWnd; /* handle para janela */
+ HDC hDC; /* contexto gr'afico para janela */
+ int release_dc;
+
+ COLORREF fg, bg; /* foreground, backgound */
+
+ LOGPEN logPen; /* pena logica - struct com tipo, cor,... */
+ HPEN hPen; /* handle para a pena corrente */
+ HPEN hNullPen; /* handle da pena que nao desenha nada */
+ HPEN hOldPen; /* pena anterior selecionado */
+ int rebuild_pen;
+
+ LOGBRUSH logBrush; /* pincel l'ogico - struct com tipo, cor,... */
+ HBRUSH hBrush; /* handle para o pincel corrente */
+ HBRUSH hOldBrush; /* brush anterior selecionado */
+ HBRUSH hBkBrush; /* handle para o pincel com a cor de fundo */
+
+ HDC hDCMemPat;
+ HBITMAP hOldBitmapPat,hBitmapPat;
+
+ HDC hDCMemStip;
+ HBITMAP hOldBitmapStip,hBitmapStip;
+
+ HFONT hFont; /* handle para o fonte corrente */
+ HFONT hOldFont;
+
+ int font_angle;
+
+ float rotate_angle;
+ int rotate_center_x,
+ rotate_center_y;
+
+ struct
+ {
+ int max_width;
+ int height;
+ int ascent;
+ int descent;
+ } font;
+
+ POINT *clip_pnt; /* coordenadas do pixel no X,Y */
+ int clip_pnt_n; /* numero de pontos correntes */
+ HRGN clip_hrgn;
+
+ HRGN new_rgn;
+
+ HPALETTE hPal, hOldPal; /* handle para a paleta corrente */
+ LOGPALETTE* pLogPal; /* paleta logica do canvas */
+
+ char *filename; /* Nome do arquivo para WMF */
+ int wtype; /* Flag indicando qual o tipo de superficie */
+
+ HBITMAP hBitmapClip, hOldBitmapClip; /* Bitmap para copiar para clipboard */
+ BITMAPINFO bmiClip;
+ BYTE* bitsClip;
+ DWORD RopBlt; /* Raster Operation for bitmaps */
+ int isOwnedDC; /* usado pelo Native canvas */
+
+ BYTE* dib_bits;
+ int bits_size;
+
+ cdImage* image_dbuffer; /* utilizado pelo driver de Double buffer */
+ cdCanvas* canvas_dbuffer;
+
+ HBITMAP img_mask; /* used by PutImage with mask and rotation and transparency */
+
+ POINT img_points[3];
+ int use_img_points;
+
+ char fill_attrib[2];
+
+ int img_format;
+ unsigned char* img_alpha;
+};
+
+enum{CDW_WIN, CDW_BMP, CDW_WMF, CDW_EMF};
+
+/* Cria um canvas no driver Windows e inicializa valores default */
+cdCtxCanvas *cdwCreateCanvas(cdCanvas* canvas, HWND hWnd, HDC hDC, int wtype);
+void cdwInitTable(cdCanvas* canvas);
+void cdwRestoreDC(cdCtxCanvas *ctxcanvas);
+
+/* Remove valores comuns do driver Windows, deve ser chamado por todos os drivers */
+void cdwKillCanvas(cdCtxCanvas* canvas);
+
+
+/* implemented in the wmfmeta.c module */
+void wmfMakePlaceableMetafile(HMETAFILE hmf, char* filename, int w, int h);
+void wmfWritePlacebleFile(HANDLE hFile, char* buffer, DWORD dwSize, LONG mm, LONG xExt, LONG yExt);
+
+/* implemented in the wmf_emf.c module */
+int cdplayWMF(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax, void *data);
+int cdregistercallbackWMF(int cb, cdCallback func);
+int cdplayEMF(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax, void *data);
+int cdregistercallbackEMF(int cb, cdCallback func);
+
+/* Estrutura que descreve um DIB. The secondary members are pointers to the main dib pointer. */
+typedef struct _cdwDIB
+{
+ BYTE* dib; /* The DIB as it is defined */
+ BITMAPINFO* bmi; /* Bitmap Info = Bitmap Info Header + Palette*/
+ BITMAPINFOHEADER* bmih; /* Bitmap Info Header */
+ RGBQUAD* bmic; /* Palette */
+ BYTE* bits; /* Bitmap Bits */
+ int w;
+ int h;
+ int type; /* RGB = 0 or MAP = 1 or RGBA = 2 (dib section only) */
+} cdwDIB;
+
+enum {CDW_RGB, CDW_MAP, CDW_RGBA};
+
+int cdwCreateDIB(cdwDIB* dib);
+void cdwKillDIB(cdwDIB* dib);
+
+HANDLE cdwCreateCopyHDIB(BITMAPINFO* bmi, BYTE* bits);
+void cdwDIBReference(cdwDIB* dib, BYTE* bmi, BYTE* bits);
+int cdwCreateDIBRefBuffer(cdwDIB* dib, unsigned char* *bits, int *size);
+void cdwCreateDIBRefBits(cdwDIB* dib, unsigned char *bits);
+HBITMAP cdwCreateDIBSection(cdwDIB* dib, HDC hDC);
+
+HPALETTE cdwDIBLogicalPalette(cdwDIB* dib);
+
+/* copy from DIB */
+void cdwDIBDecodeRGB(cdwDIB* dib, unsigned char *red, unsigned char *green, unsigned char *blue);
+void cdwDIBDecodeMap(cdwDIB* dib, unsigned char *index, long *colors);
+
+/* copy to DIB */
+void cdwDIBEncodePattern(cdwDIB* dib, const long int *colors);
+void cdwDIBEncodeMapRect(cdwDIB* dib, const unsigned char *index, const long int *colors, int xi, int yi, int wi, int hi);
+void cdwDIBEncodeRGBRect(cdwDIB* dib, const unsigned char *red, const unsigned char *green, const unsigned char *blue, int xi, int yi, int wi, int hi);
+void cdwDIBEncodeRGBARect(cdwDIB* dib, const unsigned char *red, const unsigned char *green, const unsigned char *blue, const unsigned char *alpha, int xi, int yi, int wi, int hi);
+void cdwDIBEncodeRGBARectZoom(cdwDIB* dib, const unsigned char *red, const unsigned char *green, const unsigned char *blue, const unsigned char *alpha, int w, int h, int xi, int yi, int wi, int hi);
+void cdwDIBEncodeAlphaRect(cdwDIB* dib, const unsigned char *alpha, int xi, int yi, int wi, int hi);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ifndef CDWIN_H */
+
diff --git a/src/win32/cdwnative.c b/src/win32/cdwnative.c
new file mode 100644
index 0000000..fdc223e
--- /dev/null
+++ b/src/win32/cdwnative.c
@@ -0,0 +1,209 @@
+/** \file
+ * \brief Windows Native Window Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "cdwin.h"
+#include "cdnative.h"
+
+
+int cdGetScreenColorPlanes(void)
+{
+ int bpp;
+ HDC ScreenDC = GetDC(NULL);
+ bpp = GetDeviceCaps(ScreenDC, BITSPIXEL);
+ ReleaseDC(NULL, ScreenDC);
+ return bpp;
+}
+
+void cdGetScreenSize(int *width, int *height, double *width_mm, double *height_mm)
+{
+ HDC ScreenDC = GetDC(NULL);
+ if (width) *width = GetDeviceCaps(ScreenDC, HORZRES);
+ if (height) *height = GetDeviceCaps(ScreenDC, VERTRES);
+ if (width_mm) *width_mm = ((GetDeviceCaps(ScreenDC, HORZRES) * 25.4) / GetDeviceCaps(ScreenDC, LOGPIXELSX));
+ if (height_mm) *height_mm = ((GetDeviceCaps(ScreenDC, VERTRES) * 25.4) / GetDeviceCaps(ScreenDC, LOGPIXELSY));
+ ReleaseDC(NULL, ScreenDC);
+}
+
+static void cdwReleaseDC(cdCtxCanvas *ctxcanvas)
+{
+ SelectObject(ctxcanvas->hDC, ctxcanvas->hOldBrush);
+ SelectObject(ctxcanvas->hDC, ctxcanvas->hOldPen);
+ SelectObject(ctxcanvas->hDC, ctxcanvas->hOldFont);
+ ReleaseDC(ctxcanvas->hWnd, ctxcanvas->hDC);
+ ctxcanvas->hDC = NULL;
+}
+
+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;
+
+ 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);
+ }
+
+ /* Se nao e' ownwer, tem que restaurar o contexto */
+ if (!ctxcanvas->isOwnedDC)
+ {
+ if (ctxcanvas->hDC) /* deactivate not called */
+ cdwReleaseDC(ctxcanvas);
+
+ ctxcanvas->hDC = GetDC(ctxcanvas->hWnd);
+ cdwRestoreDC(ctxcanvas);
+ }
+
+ return CD_OK;
+}
+
+static void cddeactivate(cdCtxCanvas *ctxcanvas)
+{
+ /* Se nao e' ownwer, tem que liberar o contexto */
+ if (!ctxcanvas->isOwnedDC && ctxcanvas->hDC)
+ cdwReleaseDC(ctxcanvas);
+}
+
+static void cdkillcanvas(cdCtxCanvas *ctxcanvas)
+{
+ /* se nao e' owner e nao esta' ativo, simula ativacao */
+ if (!ctxcanvas->isOwnedDC && !ctxcanvas->hDC)
+ {
+ ctxcanvas->hDC = GetDC(ctxcanvas->hWnd);
+ cdwRestoreDC(ctxcanvas);
+ }
+
+ cdwKillCanvas(ctxcanvas);
+
+ if (ctxcanvas->release_dc)
+ ReleaseDC(ctxcanvas->hWnd, ctxcanvas->hDC);
+
+ memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
+ free(ctxcanvas);
+}
+
+static void cdcreatecanvas(cdCanvas* canvas, void *data)
+{
+ cdCtxCanvas* ctxcanvas;
+ HWND hWnd = NULL;
+ HDC hDC, ScreenDC;
+ int release_dc = 0;
+
+ 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);
+ release_dc = 1;
+ canvas->w = GetDeviceCaps(hDC, HORZRES);
+ canvas->h = GetDeviceCaps(hDC, VERTRES);
+ }
+ else if (IsWindow((HWND)data))
+ {
+ RECT rect;
+ hWnd = (HWND)data;
+
+ hDC = GetDC(hWnd);
+ release_dc = 1;
+
+ GetClientRect(hWnd, &rect);
+ canvas->w = rect.right - rect.left;
+ canvas->h = rect.bottom - rect.top;
+ }
+ 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;
+ }
+ release_dc = 0;
+ }
+
+ canvas->w_mm = ((double)canvas->w) / canvas->xres;
+ canvas->h_mm = ((double)canvas->h) / canvas->yres;
+
+ /* Inicializa driver WIN32 */
+ ctxcanvas = cdwCreateCanvas(canvas, hWnd, hDC, CDW_WIN);
+
+ ctxcanvas->release_dc = release_dc;
+ ctxcanvas->clip_pnt[2].x = ctxcanvas->clip_pnt[1].x = canvas->w - 1;
+ ctxcanvas->clip_pnt[3].y = ctxcanvas->clip_pnt[2].y = canvas->h - 1;
+
+ if (hWnd)
+ {
+ LONG style;
+ style = GetClassLong(hWnd, GCL_STYLE);
+ ctxcanvas->isOwnedDC = (int) ((style & CS_OWNDC) || (style & CS_CLASSDC));
+ }
+ else
+ ctxcanvas->isOwnedDC = 1;
+
+ /* Se nao e' ownwer, tem que liberar o contexto */
+ if (!ctxcanvas->isOwnedDC)
+ cdwReleaseDC(ctxcanvas);
+}
+
+static void cdinittable(cdCanvas* canvas)
+{
+ cdwInitTable(canvas);
+
+ canvas->cxKillCanvas = cdkillcanvas;
+ canvas->cxActivate = cdactivate;
+ canvas->cxDeactivate = cddeactivate;
+}
+
+static cdContext cdNativeContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_PLAY | CD_CAP_YAXIS | CD_CAP_FPRIMTIVES ),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL,
+};
+
+cdContext* cdContextNativeWindow(void)
+{
+ if (cdUseContextPlus(CD_QUERY))
+ {
+ cdContext* ctx = cdGetContextPlus(CD_CTX_NATIVEWINDOW);
+ if (ctx != NULL)
+ return ctx;
+ }
+
+ return &cdNativeContext;
+}
diff --git a/src/win32/cdwprn.c b/src/win32/cdwprn.c
new file mode 100644
index 0000000..95e4aca
--- /dev/null
+++ b/src/win32/cdwprn.c
@@ -0,0 +1,184 @@
+/** \file
+ * \brief Windows Printer Driver
+ *
+ * See Copyright Notice in cd.h
+ */
+
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "cdwin.h"
+#include "cdprint.h"
+
+#ifndef DC_COLORDEVICE
+#define DC_COLORDEVICE 32 /* declared only if WINVER 0x0500 */
+#endif
+
+/*
+%F cdKillCanvas para Printer.
+Termina a pagina e termina o documento, enviando-o para a impressora.
+*/
+static void cdkillcanvas (cdCtxCanvas *ctxcanvas)
+{
+ EndPage(ctxcanvas->hDC);
+ EndDoc(ctxcanvas->hDC);
+
+ cdwKillCanvas(ctxcanvas);
+
+ DeleteDC(ctxcanvas->hDC);
+
+ memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
+ free(ctxcanvas);
+}
+
+/*
+%F cdFlush para Printer.
+Termina uma pagina e inicia outra.
+*/
+static void cdflush(cdCtxCanvas *ctxcanvas)
+{
+ GdiFlush();
+ EndPage(ctxcanvas->hDC);
+
+ StartPage(ctxcanvas->hDC);
+ cdwRestoreDC(ctxcanvas);
+}
+
+/*
+%F cdCreateCanvas para Impresora.
+Usa a impressora default.
+*/
+static void cdcreatecanvas(cdCanvas* canvas, void *data)
+{
+ cdCtxCanvas* ctxcanvas;
+ char *data_str = (char*) data;
+ char docname[256] = "CD - Canvas Draw Document";
+ DOCINFO di;
+ HDC hDC;
+ int dialog = 0, wtype;
+ PRINTDLG pd;
+
+ /* Inicializa parametros */
+ if (data_str == NULL)
+ return;
+
+ if (data_str[0] != 0)
+ {
+ 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;
+ }
+ }
+
+ ZeroMemory(&pd, sizeof(PRINTDLG));
+ pd.lStructSize = sizeof(PRINTDLG);
+ pd.nCopies = 1;
+
+ if (dialog)
+ {
+ pd.Flags = PD_RETURNDC | PD_USEDEVMODECOPIES | 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 = pd.hDC;
+
+ /* Inicializa documento */
+ di.cbSize = sizeof(DOCINFO);
+ di.lpszDocName = docname;
+ di.lpszOutput = (LPTSTR) NULL;
+ di.lpszDatatype = (LPTSTR) NULL;
+ di.fwType = 0;
+
+ StartDoc(hDC, &di);
+
+ StartPage(hDC);
+
+ wtype = CDW_EMF;
+
+ /* Inicializa driver WIN32 */
+ ctxcanvas = cdwCreateCanvas(canvas, NULL, hDC, wtype);
+
+ canvas->w = GetDeviceCaps(hDC, HORZRES);
+ canvas->h = GetDeviceCaps(hDC, VERTRES);
+ canvas->w_mm = (double) GetDeviceCaps(hDC, HORZSIZE);
+ canvas->h_mm = (double) GetDeviceCaps(hDC, VERTSIZE);
+ canvas->bpp = GetDeviceCaps(hDC, BITSPIXEL);
+ canvas->xres = canvas->w / canvas->w_mm;
+ canvas->yres = canvas->h / canvas->h_mm;
+ ctxcanvas->clip_pnt[2].x = ctxcanvas->clip_pnt[1].x = canvas->w - 1;
+ ctxcanvas->clip_pnt[3].y = ctxcanvas->clip_pnt[2].y = canvas->h - 1;
+
+ /* PDF Writer returns bpp=1, so we check if color is supported and overwrite this value */
+ if (canvas->bpp==1 && pd.hDevNames)
+ {
+ unsigned char* devnames = (unsigned char*)GlobalLock(pd.hDevNames);
+ DEVNAMES* dn = (DEVNAMES*)devnames;
+ char* name = (char*)(devnames + dn->wDeviceOffset);
+ char* port = (char*)(devnames + dn->wOutputOffset);
+
+ if (DeviceCapabilities(name, port, DC_COLORDEVICE, NULL, NULL))
+ canvas->bpp = 24;
+
+ GlobalUnlock(pd.hDevNames);
+ }
+
+ if(pd.hDevMode)
+ GlobalFree(pd.hDevMode);
+ if(pd.hDevNames)
+ GlobalFree(pd.hDevNames);
+}
+
+static void cdinittable(cdCanvas* canvas)
+{
+ cdwInitTable(canvas);
+
+ canvas->cxKillCanvas = cdkillcanvas;
+ canvas->cxFlush = cdflush;
+}
+
+static cdContext cdPrinterContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_PLAY | CD_CAP_YAXIS |
+ CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB | CD_CAP_IMAGESRV |
+ CD_CAP_FPRIMTIVES ),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ NULL,
+ NULL
+};
+
+cdContext* cdContextPrinter(void)
+{
+ if (cdUseContextPlus(CD_QUERY))
+ {
+ cdContext* ctx = cdGetContextPlus(CD_CTX_PRINTER);
+ if (ctx != NULL)
+ return ctx;
+ }
+
+ return &cdPrinterContext;
+}
diff --git a/src/win32/cdwwmf.c b/src/win32/cdwwmf.c
new file mode 100644
index 0000000..6b47aa5
--- /dev/null
+++ b/src/win32/cdwwmf.c
@@ -0,0 +1,109 @@
+/** \file
+ * \brief Windows WMF Driver
+ * Aldus Placeable Metafile
+ *
+ * See Copyright Notice in cd.h
+ */
+
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "cdwin.h"
+#include "cdwmf.h"
+
+
+static void cdkillcanvas(cdCtxCanvas *ctxcanvas)
+{
+ HMETAFILE hmf;
+
+ cdwKillCanvas(ctxcanvas);
+
+ hmf = CloseMetaFile(ctxcanvas->hDC);
+ wmfMakePlaceableMetafile(hmf, ctxcanvas->filename, ctxcanvas->canvas->w, ctxcanvas->canvas->h);
+ DeleteMetaFile(hmf);
+
+ free(ctxcanvas->filename);
+
+ memset(ctxcanvas, 0, sizeof(cdCtxCanvas));
+ free(ctxcanvas);
+}
+
+static void cdcreatecanvas(cdCanvas* canvas, void* data)
+{
+ cdCtxCanvas* ctxcanvas;
+ char* strdata = (char*)data;
+ int w = 0, h = 0;
+ float res;
+ HDC ScreenDC;
+ FILE* fh;
+ char filename[10240] = "";
+
+ /* Inicializa parametros */
+ if (strdata == NULL)
+ return;
+
+ ScreenDC = GetDC(NULL);
+ res = (float)(((double)GetDeviceCaps(ScreenDC, LOGPIXELSX)) / 25.4);
+ ReleaseDC(NULL, ScreenDC);
+
+ strdata += cdGetFileName(strdata, filename);
+ if (filename[0] == 0)
+ return;
+
+ sscanf(strdata,"%dx%d %g", &w, &h, &res);
+ if (w == 0 || h == 0)
+ return;
+
+ /* Verifica se o arquivo pode ser aberto para escrita */
+ fh = fopen(filename, "w");
+ if (fh == 0)
+ return;
+
+ fclose(fh);
+
+ /* Inicializa driver WIN32 */
+ ctxcanvas = cdwCreateCanvas(canvas, NULL, CreateMetaFile(NULL), CDW_WMF);
+
+ canvas->w = w;
+ canvas->h = h;
+ canvas->xres = res;
+ canvas->yres = res;
+ canvas->w_mm = ((double)w) / res;
+ canvas->h_mm = ((double)h) / res;
+ canvas->bpp = 24;
+ ctxcanvas->clip_pnt[2].x = ctxcanvas->clip_pnt[1].x = canvas->w - 1;
+ ctxcanvas->clip_pnt[3].y = ctxcanvas->clip_pnt[2].y = canvas->h - 1;
+
+ /* Inicializacao de variaveis particulares para o WMF */
+ ctxcanvas->filename = strdup(filename);
+}
+
+static void cdinittable(cdCanvas* canvas)
+{
+ cdwInitTable(canvas);
+
+ canvas->cxKillCanvas = cdkillcanvas;
+
+ /* overwrite the base Win32 driver functions */
+ canvas->cxGetTextSize = cdgettextsizeEX;
+}
+
+static cdContext cdWMFContext =
+{
+ CD_CAP_ALL & ~(CD_CAP_CLEAR | CD_CAP_YAXIS | CD_CAP_TEXTSIZE |
+ CD_CAP_CLIPAREA | CD_CAP_CLIPPOLY | CD_CAP_PATTERN |
+ CD_CAP_IMAGERGBA | CD_CAP_GETIMAGERGB | CD_CAP_IMAGESRV |
+ CD_CAP_LINECAP | CD_CAP_LINEJOIN |
+ CD_CAP_FPRIMTIVES ),
+ 0,
+ cdcreatecanvas,
+ cdinittable,
+ cdplayWMF,
+ cdregistercallbackWMF
+};
+
+cdContext* cdContextWMF(void)
+{
+ return &cdWMFContext;
+}
diff --git a/src/win32/wmf_emf.c b/src/win32/wmf_emf.c
new file mode 100644
index 0000000..36aeed0
--- /dev/null
+++ b/src/win32/wmf_emf.c
@@ -0,0 +1,2121 @@
+/** \file
+ * \brief EMF and WMF Play
+ *
+ * See Copyright Notice in cd.h
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <io.h>
+#include <fcntl.h>
+#include <math.h>
+
+#include "cdwin.h"
+#include "cdwmf.h"
+#include "cdemf.h"
+
+/* placeable metafile data definitions */
+#define ALDUSKEY 0x9AC6CDD7
+
+#ifndef PS_JOIN_MASK
+#define PS_JOIN_MASK 0x0000F000
+#endif
+
+/*
+%F Definicao do header do APM. Ver comentario no final deste arquivo.
+*/
+typedef struct _APMFILEHEADER
+{
+ WORD key1,
+ key2,
+ hmf,
+ bleft, btop, bright, bbottom,
+ inch,
+ reserved1,
+ reserved2,
+ checksum;
+} APMFILEHEADER;
+
+
+/* coordinates convertion */
+
+static double wmf_xfactor = 1;
+static double wmf_yfactor = -1; /* negative because top-down orientation */
+static int wmf_xmin = 0;
+static int wmf_ymin = 0;
+static int wmf_left = 0;
+static int wmf_bottom = 0; /* bottom and right are not included */
+static int wmf_top = 0;
+static int wmf_right = 0;
+
+static int sScaleX(int x)
+{
+ return cdRound((x - wmf_left) * wmf_xfactor + wmf_xmin);
+}
+
+static int sScaleY(int y)
+{
+ return cdRound((y - (wmf_bottom-1)) * wmf_yfactor + wmf_ymin);
+}
+
+static int sScaleW(int w)
+{
+ int s = (int)(w * fabs(wmf_xfactor) + 0.5);
+ return s > 0? s: 1;
+}
+
+static int sScaleH(int h)
+{
+ int s = (int)(h * fabs(wmf_yfactor) + 0.5);
+ return s > 0? s: 1;
+}
+
+static void sCalcSizeX(int x)
+{
+ if (x < wmf_left)
+ {
+ wmf_left = x;
+ return;
+ }
+
+ if (x+1 > wmf_right)
+ {
+ wmf_right = x+1;
+ return;
+ }
+}
+
+static void sCalcSizeY(int y)
+{
+ if (y < wmf_top)
+ {
+ wmf_top = y;
+ return;
+ }
+
+ if (y+1 > wmf_bottom)
+ {
+ wmf_bottom = y+1;
+ return;
+ }
+}
+
+static int CALLBACK CalcSizeEMFEnumProc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR, int nObj, LPARAM lpData)
+{
+ switch (lpEMFR->iType)
+ {
+ case EMR_POLYGON:
+ {
+ EMRPOLYGON* data = (EMRPOLYGON*)lpEMFR;
+ int i;
+ for (i = 0; i < (int)data->cptl; i++)
+ {
+ sCalcSizeX(data->aptl[i].x);
+ sCalcSizeY(data->aptl[i].y);
+ }
+
+ break;
+ }
+ case EMR_POLYLINE:
+ {
+ EMRPOLYLINE* data = (EMRPOLYLINE*)lpEMFR;
+ int i;
+ for (i = 0; i < (int)data->cptl; i++)
+ {
+ sCalcSizeX(data->aptl[i].x);
+ sCalcSizeY(data->aptl[i].y);
+ }
+
+ break;
+ }
+ case EMR_POLYLINETO:
+ {
+ EMRPOLYLINETO* data = (EMRPOLYLINETO*)lpEMFR;
+ int i;
+ for (i = 0; i < (int)data->cptl; i++)
+ {
+ sCalcSizeX(data->aptl[i].x);
+ sCalcSizeY(data->aptl[i].y);
+ }
+
+ break;
+ }
+ case EMR_POLYPOLYLINE:
+ {
+ EMRPOLYPOLYLINE* data = (EMRPOLYPOLYLINE*)lpEMFR;
+ POINTL* aptl = (POINTL*)(data->aPolyCounts + data->nPolys); /* skip the array of counts */
+ int c, i; /* data->aptl can not be used if count greater than 1 */
+ for (c = 0; c < (int)data->nPolys; c++)
+ {
+ for (i = 0; i < (int)data->aPolyCounts[c]; i++, aptl++)
+ {
+ sCalcSizeX(aptl->x);
+ sCalcSizeY(aptl->y);
+ }
+ }
+ break;
+ }
+ case EMR_POLYPOLYGON:
+ {
+ EMRPOLYPOLYGON* data = (EMRPOLYPOLYGON*)lpEMFR;
+ POINTL* aptl = (POINTL*)(data->aPolyCounts + data->nPolys); /* skip the array of counts */
+ int c, i; /* data->aptl can not be used if count greater than 1 */
+ for (c = 0; c < (int)data->nPolys; c++)
+ {
+ for (i = 0; i < (int)data->aPolyCounts[c]; i++, aptl++)
+ {
+ sCalcSizeX(aptl->x);
+ sCalcSizeY(aptl->y);
+ }
+ }
+ break;
+ }
+ case EMR_SETPIXELV:
+ {
+ EMRSETPIXELV* data = (EMRSETPIXELV*)lpEMFR;
+ sCalcSizeX(data->ptlPixel.x);
+ sCalcSizeY(data->ptlPixel.y);
+ break;
+ }
+ case EMR_MOVETOEX:
+ {
+ EMRMOVETOEX* data = (EMRMOVETOEX*)lpEMFR;
+ sCalcSizeX(data->ptl.x);
+ sCalcSizeY(data->ptl.y);
+ break;
+ }
+ case EMR_ANGLEARC:
+ {
+ EMRANGLEARC* data = (EMRANGLEARC*)lpEMFR;
+ int x, y;
+
+ x = (int)(data->nRadius * cos(CD_DEG2RAD * data->eStartAngle + data->eSweepAngle));
+ y = (int)(data->nRadius * sin(CD_DEG2RAD * data->eStartAngle + data->eSweepAngle));
+
+ sCalcSizeX(data->ptlCenter.x);
+ sCalcSizeY(data->ptlCenter.y);
+ sCalcSizeX(x);
+ sCalcSizeY(y);
+ break;
+ }
+ case EMR_ELLIPSE:
+ {
+ EMRELLIPSE* data = (EMRELLIPSE*)lpEMFR;
+ sCalcSizeX(data->rclBox.left);
+ sCalcSizeX(data->rclBox.right);
+ sCalcSizeY(data->rclBox.top);
+ sCalcSizeY(data->rclBox.bottom);
+ break;
+ }
+ case EMR_RECTANGLE:
+ {
+ EMRRECTANGLE* data = (EMRRECTANGLE*)lpEMFR;
+ sCalcSizeX(data->rclBox.left);
+ sCalcSizeX(data->rclBox.right);
+ sCalcSizeY(data->rclBox.bottom);
+ sCalcSizeY(data->rclBox.top);
+ break;
+ }
+ case EMR_ROUNDRECT:
+ {
+ EMRROUNDRECT* data = (EMRROUNDRECT*)lpEMFR;
+ sCalcSizeX(data->rclBox.left);
+ sCalcSizeX(data->rclBox.right);
+ sCalcSizeY(data->rclBox.bottom);
+ sCalcSizeY(data->rclBox.top);
+ break;
+ }
+ case EMR_ARC:
+ {
+ EMRARC* data = (EMRARC*)lpEMFR;
+ sCalcSizeX(data->rclBox.left);
+ sCalcSizeX(data->rclBox.right);
+ sCalcSizeY(data->rclBox.top);
+ sCalcSizeY(data->rclBox.bottom);
+ break;
+ }
+ case EMR_CHORD:
+ {
+ EMRCHORD* data = (EMRCHORD*)lpEMFR;
+ sCalcSizeX(data->rclBox.left);
+ sCalcSizeX(data->rclBox.right);
+ sCalcSizeY(data->rclBox.top);
+ sCalcSizeY(data->rclBox.bottom);
+ break;
+ }
+ case EMR_PIE:
+ {
+ EMRPIE* data = (EMRPIE*)lpEMFR;
+ sCalcSizeX(data->rclBox.left);
+ sCalcSizeX(data->rclBox.right);
+ sCalcSizeY(data->rclBox.top);
+ sCalcSizeY(data->rclBox.bottom);
+ break;
+ }
+ case EMR_LINETO:
+ {
+ EMRLINETO* data = (EMRLINETO*)lpEMFR;
+ sCalcSizeX(data->ptl.x);
+ sCalcSizeY(data->ptl.y);
+ break;
+ }
+ case EMR_ARCTO:
+ {
+ EMRARCTO* data = (EMRARCTO*)lpEMFR;
+ sCalcSizeX(data->rclBox.left);
+ sCalcSizeX(data->rclBox.right);
+ sCalcSizeY(data->rclBox.top);
+ sCalcSizeY(data->rclBox.bottom);
+ break;
+ }
+ case EMR_POLYDRAW:
+ {
+ int p;
+ EMRPOLYDRAW* data = (EMRPOLYDRAW*)lpEMFR;
+
+ for(p = 0; p < (int)data->cptl; p++)
+ {
+ switch (data->abTypes[p])
+ {
+ case PT_MOVETO:
+ {
+ sCalcSizeX(data->aptl[p].x);
+ sCalcSizeY(data->aptl[p].y);
+ break;
+ }
+ case PT_LINETO:
+ {
+ sCalcSizeX(data->aptl[p].x);
+ sCalcSizeY(data->aptl[p].y);
+ break;
+ }
+ }
+ }
+ break;
+ }
+ case EMR_BITBLT:
+ {
+ EMRBITBLT* data = (EMRBITBLT*)lpEMFR;
+ cdwDIB dib;
+
+ cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc);
+
+ if (dib.type == -1)
+ break;
+
+ sCalcSizeX(data->xDest);
+ sCalcSizeY(data->yDest);
+ sCalcSizeX(data->xDest + dib.w);
+ sCalcSizeY(data->yDest + abs(dib.h));
+ break;
+ }
+ case EMR_STRETCHBLT:
+ {
+ EMRSTRETCHBLT* data = (EMRSTRETCHBLT*)lpEMFR;
+ cdwDIB dib;
+
+ cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc);
+
+ if (dib.type == -1)
+ break;
+
+ sCalcSizeX(data->xDest);
+ sCalcSizeY(data->yDest);
+ sCalcSizeX(data->xDest + data->cxDest);
+ sCalcSizeY(data->yDest + data->cyDest);
+ break;
+ }
+ case EMR_MASKBLT:
+ {
+ EMRMASKBLT* data = (EMRMASKBLT*)lpEMFR;
+ cdwDIB dib;
+
+ cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc);
+
+ if (dib.type == -1)
+ break;
+
+ sCalcSizeX(data->xDest);
+ sCalcSizeY(data->yDest);
+ sCalcSizeX(data->xDest + dib.w);
+ sCalcSizeY(data->yDest + abs(dib.h));
+ break;
+ }
+ case EMR_SETDIBITSTODEVICE:
+ {
+ EMRSETDIBITSTODEVICE* data = (EMRSETDIBITSTODEVICE*)lpEMFR;
+ cdwDIB dib;
+
+ cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc);
+
+ if (dib.type == -1)
+ break;
+
+ sCalcSizeX(data->xDest);
+ sCalcSizeY(data->yDest);
+ sCalcSizeX(data->xDest + dib.w);
+ sCalcSizeY(data->yDest + abs(dib.h));
+ break;
+ }
+ case EMR_STRETCHDIBITS:
+ {
+ EMRSTRETCHDIBITS* data = (EMRSTRETCHDIBITS*)lpEMFR;
+ cdwDIB dib;
+
+ cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc);
+
+ if (dib.type == -1)
+ break;
+
+ sCalcSizeX(data->xDest);
+ sCalcSizeY(data->yDest);
+ sCalcSizeX(data->xDest + data->cxDest);
+ sCalcSizeY(data->yDest + data->cyDest);
+ break;
+ }
+ case EMR_EXTTEXTOUTA:
+ {
+ EMREXTTEXTOUTA* data = (EMREXTTEXTOUTA*)lpEMFR;
+ sCalcSizeX(data->emrtext.ptlReference.x);
+ sCalcSizeY(data->emrtext.ptlReference.y);
+ break;
+ }
+ case EMR_EXTTEXTOUTW:
+ {
+ EMREXTTEXTOUTW* data = (EMREXTTEXTOUTW*)lpEMFR;
+ sCalcSizeX(data->emrtext.ptlReference.x);
+ sCalcSizeY(data->emrtext.ptlReference.y);
+ break;
+ }
+ case EMR_POLYGON16:
+ {
+ EMRPOLYGON16* data = (EMRPOLYGON16*)lpEMFR;
+ int i;
+ for (i = 0; i < (int)data->cpts; i++)
+ {
+ sCalcSizeX(data->apts[i].x);
+ sCalcSizeY(data->apts[i].y);
+ }
+ break;
+ }
+ case EMR_POLYLINE16:
+ {
+ EMRPOLYLINE16* data = (EMRPOLYLINE16*)lpEMFR;
+ int i;
+ for (i = 0; i < (int)data->cpts; i++)
+ {
+ sCalcSizeX(data->apts[i].x);
+ sCalcSizeY(data->apts[i].y);
+ }
+ break;
+ }
+ case EMR_POLYLINETO16:
+ {
+ EMRPOLYLINETO16* data = (EMRPOLYLINETO16*)lpEMFR;
+ int i;
+ for (i = 0; i < (int)data->cpts; i++)
+ {
+ sCalcSizeX(data->apts[i].x);
+ sCalcSizeY(data->apts[i].y);
+ }
+ break;
+ }
+ case EMR_POLYPOLYLINE16:
+ {
+ EMRPOLYPOLYLINE16* data = (EMRPOLYPOLYLINE16*)lpEMFR;
+ POINTS* apts = (POINTS*)(data->aPolyCounts + data->nPolys); /* skip the array of counts */
+ int c, i; /* data->apts can not be used if count greater than 1 */
+ for (c = 0; c < (int)data->nPolys; c++)
+ {
+ for (i = 0; i < (int)data->aPolyCounts[c]; i++, apts++)
+ {
+ sCalcSizeX(apts->x);
+ sCalcSizeY(apts->y);
+ }
+ }
+ break;
+ }
+ case EMR_POLYPOLYGON16:
+ {
+ EMRPOLYPOLYGON16* data = (EMRPOLYPOLYGON16*)lpEMFR;
+ POINTS* apts = (POINTS*)(data->aPolyCounts + data->nPolys); /* skip the array of counts */
+ int c, i; /* data->apts can not be used if count greater than 1 */
+ for (c = 0; c < (int)data->nPolys; c++)
+ {
+ for (i = 0; i < (int)data->aPolyCounts[c]; i++, apts++)
+ {
+ sCalcSizeX(apts->x);
+ sCalcSizeY(apts->y);
+ }
+ }
+ break;
+ }
+ case EMR_POLYDRAW16:
+ {
+ EMRPOLYDRAW16* data = (EMRPOLYDRAW16*)lpEMFR;
+ int p;
+ for(p = 0; p < (int)data->cpts; p++)
+ {
+ switch (data->abTypes[p])
+ {
+ case PT_MOVETO:
+ {
+ sCalcSizeX(data->apts[p].x);
+ sCalcSizeY(data->apts[p].y);
+ break;
+ }
+ case PT_LINETO:
+ {
+ sCalcSizeX(data->apts[p].x);
+ sCalcSizeY(data->apts[p].y);
+ break;
+ }
+ }
+ }
+ break;
+ }
+ case EMR_POLYTEXTOUTA:
+ {
+ EMRPOLYTEXTOUTA* data = (EMRPOLYTEXTOUTA*)lpEMFR;
+ int t;
+ for (t = 0; t < data->cStrings; t++)
+ {
+ sCalcSizeX(data->aemrtext[t].ptlReference.x);
+ sCalcSizeY(data->aemrtext[t].ptlReference.y);
+ }
+ break;
+ }
+ case EMR_POLYTEXTOUTW:
+ {
+ EMRPOLYTEXTOUTW* data = (EMRPOLYTEXTOUTW*)lpEMFR;
+ int t;
+ for (t = 0; t < data->cStrings; t++)
+ {
+ sCalcSizeX(data->aemrtext[t].ptlReference.x);
+ sCalcSizeY(data->aemrtext[t].ptlReference.y);
+ }
+ break;
+ }
+ }
+
+ return 1;
+}
+
+static int CALLBACK EMFEnumProc(HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR, int nObj, LPARAM lpData)
+{
+ static int curx = 0, cury = 0;
+ static int upd_xy = 0;
+ cdCanvas* canvas = (cdCanvas*)lpData;
+
+ switch (lpEMFR->iType)
+ {
+ case EMR_SETWORLDTRANSFORM:
+ {
+ double matrix[6];
+ EMRSETWORLDTRANSFORM* data = (EMRSETWORLDTRANSFORM*)lpEMFR;
+ matrix[0] = data->xform.eM11;
+ matrix[1] = data->xform.eM12;
+ matrix[2] = data->xform.eM21;
+ matrix[3] = data->xform.eM22;
+ matrix[4] = data->xform.eDx;
+ matrix[5] = data->xform.eDy;
+ cdCanvasTransform(canvas, matrix);
+ break;
+ }
+ case EMR_MODIFYWORLDTRANSFORM:
+ {
+ EMRMODIFYWORLDTRANSFORM* data = (EMRMODIFYWORLDTRANSFORM*)lpEMFR;
+ if (data->iMode == MWT_IDENTITY)
+ cdCanvasTransform(canvas, NULL);
+ else if (data->iMode == MWT_LEFTMULTIPLY)
+ {
+ double matrix[6];
+ matrix[0] = data->xform.eM11;
+ matrix[1] = data->xform.eM12;
+ matrix[2] = data->xform.eM21;
+ matrix[3] = data->xform.eM22;
+ matrix[4] = data->xform.eDx;
+ matrix[5] = data->xform.eDy;
+ cdCanvasTransformMultiply(canvas, matrix);
+ }
+ break;
+ }
+ case EMR_POLYGON:
+ {
+ EMRPOLYGON* data = (EMRPOLYGON*)lpEMFR;
+ int i;
+
+ cdCanvasBegin(canvas, CD_FILL);
+
+ for (i = 0; i < (int)data->cptl; i++)
+ cdCanvasVertex(canvas, sScaleX(data->aptl[i].x), sScaleY(data->aptl[i].y));
+
+ cdCanvasEnd(canvas);
+ break;
+ }
+ case EMR_POLYLINE:
+ {
+ EMRPOLYLINE* data = (EMRPOLYLINE*)lpEMFR;
+ int i;
+
+ cdCanvasBegin(canvas, CD_OPEN_LINES);
+
+ for (i = 0; i < (int)data->cptl; i++)
+ cdCanvasVertex(canvas, sScaleX(data->aptl[i].x), sScaleY(data->aptl[i].y));
+
+ cdCanvasEnd(canvas);
+ break;
+ }
+ case EMR_POLYBEZIER:
+ {
+ EMRPOLYBEZIER* data = (EMRPOLYBEZIER*)lpEMFR;
+ int i;
+
+ cdCanvasBegin(canvas, CD_BEZIER);
+
+ for (i = 0; i < (int)data->cptl; i++)
+ cdCanvasVertex(canvas, sScaleX(data->aptl[i].x), sScaleY(data->aptl[i].y));
+
+ cdCanvasEnd(canvas);
+ break;
+ }
+ case EMR_POLYLINETO:
+ {
+ EMRPOLYLINETO* data = (EMRPOLYLINETO*)lpEMFR;
+ int i;
+
+ cdCanvasBegin(canvas, CD_OPEN_LINES);
+
+ for (i = 0; i < (int)data->cptl; i++)
+ cdCanvasVertex(canvas, sScaleX(data->aptl[i].x), sScaleY(data->aptl[i].y));
+
+ curx = data->aptl[data->cptl - 1].x;
+ cury = data->aptl[data->cptl - 1].y;
+
+ cdCanvasEnd(canvas);
+ break;
+ }
+ case EMR_POLYBEZIERTO:
+ {
+ EMRPOLYBEZIERTO* data = (EMRPOLYBEZIERTO*)lpEMFR;
+ int i;
+
+ cdCanvasBegin(canvas, CD_BEZIER);
+
+ for (i = 0; i < (int)data->cptl; i++)
+ cdCanvasVertex(canvas, sScaleX(data->aptl[i].x), sScaleY(data->aptl[i].y));
+
+ curx = data->aptl[data->cptl - 1].x;
+ cury = data->aptl[data->cptl - 1].y;
+
+ cdCanvasEnd(canvas);
+ break;
+ }
+ case EMR_POLYPOLYLINE:
+ {
+ EMRPOLYPOLYLINE* data = (EMRPOLYPOLYLINE*)lpEMFR;
+ POINTL* aptl = (POINTL*)(data->aPolyCounts + data->nPolys); /* skip the array of counts */
+ int c, i; /* data->aptl can not be used if count greater than 1 */
+
+ for (c = 0; c < (int)data->nPolys; c++)
+ {
+ cdCanvasBegin(canvas, CD_OPEN_LINES);
+
+ for (i = 0; i < (int)data->aPolyCounts[c]; i++, aptl++)
+ cdCanvasVertex(canvas, sScaleX(aptl->x), sScaleY(aptl->y));
+
+ cdCanvasEnd(canvas);
+ }
+ break;
+ }
+ case EMR_POLYPOLYGON:
+ {
+ EMRPOLYPOLYGON* data = (EMRPOLYPOLYGON*)lpEMFR;
+ POINTL* aptl = (POINTL*)(data->aPolyCounts + data->nPolys); /* skip the array of counts */
+ int c, i; /* data->aptl can not be used if count greater than 1 */
+
+ for (c = 0; c < (int)data->nPolys; c++)
+ {
+ cdCanvasBegin(canvas, CD_FILL);
+
+ for (i = 0; i < (int)data->aPolyCounts[c]; i++, aptl++)
+ cdCanvasVertex(canvas, sScaleX(aptl->x), sScaleY(aptl->y));
+
+ cdCanvasEnd(canvas);
+ }
+ break;
+ }
+ case EMR_SETPIXELV:
+ {
+ EMRSETPIXELV* data = (EMRSETPIXELV*)lpEMFR;
+ cdCanvasPixel(canvas, sScaleX(data->ptlPixel.x), sScaleY(data->ptlPixel.y), cdEncodeColor(GetRValue(data->crColor),GetGValue(data->crColor),GetBValue(data->crColor)));
+ break;
+ }
+ case EMR_SETBKMODE:
+ {
+ EMRSETBKMODE* data = (EMRSETBKMODE*)lpEMFR;
+ cdCanvasBackOpacity(canvas, data->iMode == TRANSPARENT? CD_TRANSPARENT: CD_OPAQUE);
+ break;
+ }
+ case EMR_SETROP2:
+ {
+ EMRSETROP2* data = (EMRSETROP2*)lpEMFR;
+ cdCanvasWriteMode(canvas, data->iMode == R2_NOTXORPEN? CD_NOT_XOR: (data->iMode == R2_XORPEN? CD_XOR: CD_REPLACE));
+ break;
+ }
+ case EMR_SETTEXTALIGN:
+ {
+ EMRSETTEXTALIGN* data = (EMRSETTEXTALIGN*)lpEMFR;
+ upd_xy = 0;
+
+ if (data->iMode & TA_UPDATECP)
+ {
+ upd_xy = 1;
+ data->iMode &= ~TA_UPDATECP;
+ }
+
+ switch (data->iMode)
+ {
+ case 0: /* top-left */
+ cdCanvasTextAlignment(canvas, CD_NORTH_WEST);
+ break;
+ case 2: /* top-right */
+ cdCanvasTextAlignment(canvas, CD_NORTH_EAST);
+ break;
+ case 6: /* top-center */
+ cdCanvasTextAlignment(canvas, CD_NORTH);
+ break;
+ case 8: /* bottom-left */
+ cdCanvasTextAlignment(canvas, CD_SOUTH_WEST);
+ break;
+ case 10: /* bottom-right */
+ cdCanvasTextAlignment(canvas, CD_SOUTH_EAST);
+ break;
+ case 14: /* bottom-center */
+ cdCanvasTextAlignment(canvas, CD_SOUTH);
+ break;
+ case 24: /* baseline-left */
+ cdCanvasTextAlignment(canvas, CD_BASE_LEFT);
+ break;
+ case 26: /* baseline-right */
+ cdCanvasTextAlignment(canvas, CD_BASE_RIGHT);
+ break;
+ case 30: /* baseline-center */
+ cdCanvasTextAlignment(canvas, CD_BASE_CENTER);
+ break;
+ }
+
+ break;
+ }
+ case EMR_SETTEXTCOLOR:
+ {
+ EMRSETTEXTCOLOR* data = (EMRSETTEXTCOLOR*)lpEMFR;
+ cdCanvasSetForeground(canvas, cdEncodeColor(GetRValue(data->crColor),GetGValue(data->crColor),GetBValue(data->crColor)));
+ break;
+ }
+ case EMR_SETBKCOLOR:
+ {
+ EMRSETBKCOLOR* data = (EMRSETBKCOLOR*)lpEMFR;
+ cdCanvasSetBackground(canvas, cdEncodeColor(GetRValue(data->crColor),GetGValue(data->crColor),GetBValue(data->crColor)));
+ break;
+ }
+ case EMR_MOVETOEX:
+ {
+ EMRMOVETOEX* data = (EMRMOVETOEX*)lpEMFR;
+ curx = data->ptl.x;
+ cury = data->ptl.y;
+ break;
+ }
+ case EMR_CREATEPEN:
+ {
+ EMRCREATEPEN* data = (EMRCREATEPEN*)lpEMFR;
+ int style;
+
+ switch (data->lopn.lopnStyle)
+ {
+ case PS_SOLID:
+ style = CD_CONTINUOUS;
+ break;
+ case PS_DASH:
+ style = CD_DASHED;
+ break;
+ case PS_DOT:
+ style = CD_DOTTED;
+ break;
+ case PS_DASHDOT:
+ style = CD_DASH_DOT;
+ break;
+ case PS_DASHDOTDOT:
+ style = CD_DASH_DOT_DOT;
+ break;
+ case PS_NULL:
+ style = -1;
+ break;
+ default:
+ style = CD_CONTINUOUS;
+ break;
+ }
+
+ if (style != -1)
+ {
+ cdCanvasLineStyle(canvas, style);
+ cdCanvasLineWidth(canvas, sScaleW(data->lopn.lopnWidth.x == 0? 1: data->lopn.lopnWidth.x));
+ cdCanvasSetForeground(canvas, cdEncodeColor(GetRValue(data->lopn.lopnColor),GetGValue(data->lopn.lopnColor),GetBValue(data->lopn.lopnColor)));
+ }
+ break;
+ }
+ case EMR_EXTCREATEPEN:
+ {
+ EMREXTCREATEPEN* data = (EMREXTCREATEPEN*)lpEMFR;
+ int style;
+
+ switch (data->elp.elpPenStyle & PS_STYLE_MASK)
+ {
+ case PS_SOLID:
+ style = CD_CONTINUOUS;
+ break;
+ case PS_DASH:
+ style = CD_DASHED;
+ break;
+ case PS_DOT:
+ style = CD_DOTTED;
+ break;
+ case PS_DASHDOT:
+ style = CD_DASH_DOT;
+ break;
+ case PS_DASHDOTDOT:
+ style = CD_DASH_DOT_DOT;
+ break;
+ case PS_NULL:
+ style = -1;
+ break;
+ case PS_USERSTYLE:
+ style = CD_CUSTOM;
+ cdCanvasLineStyleDashes(canvas, (int*)data->elp.elpStyleEntry, data->elp.elpNumEntries);
+ break;
+ default:
+ style = CD_CONTINUOUS;
+ break;
+ }
+
+ if (style != -1)
+ {
+ switch (data->elp.elpPenStyle & PS_ENDCAP_MASK)
+ {
+ case PS_ENDCAP_FLAT:
+ cdCanvasLineCap(canvas, CD_CAPFLAT);
+ break;
+ case PS_ENDCAP_ROUND:
+ cdCanvasLineCap(canvas, CD_CAPROUND);
+ break;
+ case PS_ENDCAP_SQUARE:
+ cdCanvasLineCap(canvas, CD_CAPSQUARE);
+ break;
+ }
+
+ switch (data->elp.elpPenStyle & PS_JOIN_MASK)
+ {
+ case PS_JOIN_MITER:
+ cdCanvasLineJoin(canvas, CD_MITER);
+ break;
+ case PS_JOIN_BEVEL:
+ cdCanvasLineJoin(canvas, CD_BEVEL);
+ break;
+ case PS_JOIN_ROUND:
+ cdCanvasLineJoin(canvas, CD_ROUND);
+ break;
+ }
+
+ cdCanvasLineStyle(canvas, style);
+ cdCanvasLineWidth(canvas, sScaleW(data->elp.elpWidth == 0? 1: data->elp.elpWidth));
+ cdCanvasSetForeground(canvas, cdEncodeColor(GetRValue(data->elp.elpColor),GetGValue(data->elp.elpColor),GetBValue(data->elp.elpColor)));
+ }
+ break;
+ }
+ case EMR_CREATEBRUSHINDIRECT:
+ {
+ EMRCREATEBRUSHINDIRECT* data = (EMRCREATEBRUSHINDIRECT*)lpEMFR;
+ cdCanvasSetForeground(canvas, cdEncodeColor(GetRValue(data->lb.lbColor),GetGValue(data->lb.lbColor),GetBValue(data->lb.lbColor)));
+
+ switch (data->lb.lbStyle)
+ {
+ case BS_HATCHED:
+ {
+ int hatch = 0;
+
+ switch (data->lb.lbHatch)
+ {
+ case HS_BDIAGONAL:
+ hatch = CD_BDIAGONAL;
+ break;
+ case HS_CROSS:
+ hatch = CD_CROSS;
+ break;
+ case HS_DIAGCROSS:
+ hatch = CD_DIAGCROSS;
+ break;
+ case HS_FDIAGONAL:
+ hatch = CD_FDIAGONAL;
+ break;
+ case HS_HORIZONTAL:
+ hatch = CD_HORIZONTAL;
+ break;
+ case HS_VERTICAL:
+ hatch = CD_VERTICAL;
+ break;
+ }
+
+ cdCanvasHatch(canvas, hatch);
+ cdCanvasInteriorStyle(canvas, CD_HATCH);
+ break;
+ }
+ case BS_SOLID:
+ cdCanvasInteriorStyle(canvas, CD_SOLID);
+ break;
+ case BS_NULL:
+ cdCanvasInteriorStyle(canvas, CD_HOLLOW);
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+ case EMR_ANGLEARC:
+ {
+ EMRANGLEARC* data = (EMRANGLEARC*)lpEMFR;
+ int x, y;
+
+ x = (int)(data->nRadius * cos(CD_DEG2RAD * data->eStartAngle + data->eSweepAngle));
+ y = (int)(data->nRadius * sin(CD_DEG2RAD * data->eStartAngle + data->eSweepAngle));
+
+ cdCanvasLine(canvas, sScaleX(data->ptlCenter.x), sScaleY(data->ptlCenter.y), sScaleX(x), sScaleY(y));
+ cdCanvasArc(canvas, data->ptlCenter.x, data->ptlCenter.y, 2 * data->nRadius, 2 * data->nRadius, data->eStartAngle, data->eStartAngle + data->eSweepAngle);
+ break;
+ }
+ case EMR_ELLIPSE:
+ {
+ EMRELLIPSE* data = (EMRELLIPSE*)lpEMFR;
+ int xc, yc, w, h;
+
+ xc = sScaleX((data->rclBox.left + data->rclBox.right - 1) / 2);
+ w = sScaleW(data->rclBox.right - data->rclBox.left - 1);
+ yc = sScaleY((data->rclBox.top + data->rclBox.bottom - 1) / 2);
+ h = sScaleH(data->rclBox.bottom - data->rclBox.top - 1);
+
+ cdCanvasSector(canvas, xc, yc, w, h, 0, 360);
+ break;
+ }
+ case EMR_RECTANGLE:
+ {
+ EMRRECTANGLE* data = (EMRRECTANGLE*)lpEMFR;
+ cdCanvasBox (canvas, sScaleX(data->rclBox.left), sScaleX(data->rclBox.right-2), sScaleY(data->rclBox.bottom-2), sScaleY(data->rclBox.top));
+ break;
+ }
+ case EMR_ROUNDRECT:
+ {
+ EMRROUNDRECT* data = (EMRROUNDRECT*)lpEMFR;
+ cdCanvasBox (canvas, sScaleX(data->rclBox.left), sScaleX(data->rclBox.right-2), sScaleY(data->rclBox.bottom-2), sScaleY(data->rclBox.top));
+ break;
+ }
+ case EMR_ARC:
+ {
+ EMRARC* data = (EMRARC*)lpEMFR;
+ int xc, yc, w, h;
+ double angle1, angle2;
+
+ xc = (data->rclBox.left + data->rclBox.right - 1) / 2;
+ yc = (data->rclBox.top + data->rclBox.bottom - 1) / 2;
+
+ w = sScaleW(data->rclBox.right - data->rclBox.left - 1);
+ h = sScaleH(data->rclBox.bottom - data->rclBox.top - 1);
+
+ angle1 = atan2((yc - data->ptlStart.y)*(data->rclBox.right - data->rclBox.left - 1), (data->ptlStart.x - xc)*(data->rclBox.bottom - data->rclBox.top - 1)) / CD_DEG2RAD;
+ angle2 = atan2((yc - data->ptlEnd.y)*(data->rclBox.right - data->rclBox.left - 1), (data->ptlEnd.x - xc)*(data->rclBox.bottom - data->rclBox.top - 1)) / CD_DEG2RAD;
+
+ if (angle1 == angle2)
+ angle2+=360;
+
+ xc = sScaleX(xc);
+ yc = sScaleY(yc);
+
+ cdCanvasArc(canvas, xc, yc, w, h, angle1, angle2);
+ break;
+ }
+ case EMR_CHORD:
+ {
+ EMRCHORD* data = (EMRCHORD*)lpEMFR;
+ int xc, yc, w, h;
+ double angle1, angle2;
+
+ xc = (data->rclBox.left + data->rclBox.right - 1) / 2;
+ yc = (data->rclBox.top + data->rclBox.bottom - 1) / 2;
+
+ w = sScaleW(data->rclBox.right - data->rclBox.left - 1);
+ h = sScaleH(data->rclBox.bottom - data->rclBox.top - 1);
+
+ angle1 = atan2((yc - data->ptlStart.y)*(data->rclBox.right - data->rclBox.left - 1), (data->ptlStart.x - xc)*(data->rclBox.bottom - data->rclBox.top - 1)) / CD_DEG2RAD;
+ angle2 = atan2((yc - data->ptlEnd.y)*(data->rclBox.right - data->rclBox.left - 1), (data->ptlEnd.x - xc)*(data->rclBox.bottom - data->rclBox.top - 1)) / CD_DEG2RAD;
+
+ if (angle1 == angle2)
+ angle2+=360;
+
+ xc = sScaleX(xc);
+ yc = sScaleY(yc);
+
+ cdCanvasChord(canvas, xc, yc, w, h, angle1, angle2);
+ break;
+ }
+ case EMR_PIE:
+ {
+ EMRPIE* data = (EMRPIE*)lpEMFR;
+ int xc, yc, w, h;
+ double angle1, angle2;
+
+ xc = (data->rclBox.left + data->rclBox.right - 1) / 2;
+ yc = (data->rclBox.top + data->rclBox.bottom - 1) / 2;
+
+ w = sScaleW(data->rclBox.right - data->rclBox.left - 1);
+ h = sScaleH(data->rclBox.bottom - data->rclBox.top - 1);
+
+ angle1 = atan2((yc - data->ptlStart.y)*(data->rclBox.right - data->rclBox.left - 1), (data->ptlStart.x - xc)*(data->rclBox.bottom - data->rclBox.top - 1)) / CD_DEG2RAD;
+ angle2 = atan2((yc - data->ptlEnd.y)*(data->rclBox.right - data->rclBox.left - 1), (data->ptlEnd.x - xc)*(data->rclBox.bottom - data->rclBox.top - 1)) / CD_DEG2RAD;
+
+ if (angle1 == angle2)
+ angle2+=360;
+
+ xc = sScaleX(xc);
+ yc = sScaleY(yc);
+
+ cdCanvasSector(canvas, xc, yc, w, h, angle1, angle2);
+ break;
+ }
+ case EMR_CREATEPALETTE:
+ {
+ int k;
+ EMRCREATEPALETTE* data = (EMRCREATEPALETTE*)lpEMFR;
+ long palette[256];
+
+ for (k=0; k < data->lgpl.palNumEntries; k++)
+ palette[k] = cdEncodeColor(data->lgpl.palPalEntry[k].peRed, data->lgpl.palPalEntry[k].peGreen, data->lgpl.palPalEntry[k].peBlue);
+
+ cdCanvasPalette(canvas, data->lgpl.palNumEntries, palette, CD_POLITE);
+ break;
+ }
+ case EMR_LINETO:
+ {
+ EMRLINETO* data = (EMRLINETO*)lpEMFR;
+ cdCanvasLine(canvas, sScaleX(curx), sScaleY(cury), sScaleX(data->ptl.x), sScaleY(data->ptl.y));
+ curx = data->ptl.x;
+ cury = data->ptl.y;
+ break;
+ }
+ case EMR_ARCTO:
+ {
+ EMRARCTO* data = (EMRARCTO*)lpEMFR;
+ int xc, yc, w, h;
+ double angle1, angle2;
+
+ xc = (data->rclBox.left + data->rclBox.right - 1) / 2;
+ yc = (data->rclBox.top + data->rclBox.bottom - 1) / 2;
+
+ w = sScaleW(data->rclBox.right - data->rclBox.left - 1);
+ h = sScaleH(data->rclBox.bottom - data->rclBox.top - 1);
+
+ angle1 = atan2((yc - data->ptlStart.y)*(data->rclBox.right - data->rclBox.left - 1), (data->ptlStart.x - xc)*(data->rclBox.bottom - data->rclBox.top - 1)) / CD_DEG2RAD;
+ angle2 = atan2((yc - data->ptlEnd.y)*(data->rclBox.right - data->rclBox.left - 1), (data->ptlEnd.x - xc)*(data->rclBox.bottom - data->rclBox.top - 1)) / CD_DEG2RAD;
+
+ if (angle1 == angle2)
+ angle2+=360;
+
+ xc = sScaleX(xc);
+ yc = sScaleY(yc);
+
+ cdCanvasArc(canvas, xc, yc, w, h, angle1, angle2);
+
+ curx = data->ptlEnd.x; /* isto nao esta' certo mas e' a minha melhor aproximacao */
+ cury = data->ptlEnd.y;
+ break;
+ }
+ case EMR_POLYDRAW:
+ {
+ int p;
+ EMRPOLYDRAW* data = (EMRPOLYDRAW*)lpEMFR;
+
+ for(p = 0; p < (int)data->cptl; p++)
+ {
+ switch (data->abTypes[p])
+ {
+ case PT_MOVETO:
+ {
+ curx = data->aptl[p].x;
+ cury = data->aptl[p].y;
+ break;
+ }
+ case PT_LINETO:
+ {
+ cdCanvasLine(canvas, sScaleX(curx), sScaleY(cury), sScaleX(data->aptl[p].x), sScaleY(data->aptl[p].y));
+ curx = data->aptl[p].x;
+ cury = data->aptl[p].y;
+ break;
+ }
+ }
+ }
+ break;
+ }
+ case EMR_BITBLT:
+ {
+ EMRBITBLT* data = (EMRBITBLT*)lpEMFR;
+ int size;
+ cdwDIB dib;
+ int old_write_mode;
+
+ if (data->dwRop == SRCINVERT)
+ old_write_mode = cdCanvasWriteMode(canvas, CD_XOR);
+ else
+ old_write_mode = cdCanvasWriteMode(canvas, CD_REPLACE);
+
+ cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc);
+
+ if (dib.type == -1)
+ break;
+
+ size = dib.w*abs(dib.h);
+
+ if (dib.type == 0)
+ {
+ char *r, *g, *b;
+
+ r = (char*)malloc(size);
+ g = (char*)malloc(size);
+ b = (char*)malloc(size);
+
+ cdwDIBDecodeRGB(&dib, r, g, b);
+
+ cdCanvasPutImageRectRGB(canvas, dib.w, abs(dib.h), r, g, b, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), dib.w, dib.h, 0, 0, 0, 0);
+
+ free(r);
+ free(g);
+ free(b);
+ }
+ else
+ {
+ char *index;
+ long *colors;
+
+ index = (char*)malloc(size);
+ colors = (long*)malloc(256*sizeof(long));
+
+ cdwDIBDecodeMap(&dib, index, colors);
+
+ cdCanvasPutImageRectMap(canvas, dib.w, abs(dib.h), index, colors, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), dib.w, dib.h, 0, 0, 0, 0);
+
+ free(index);
+ free(colors);
+ }
+
+ cdCanvasWriteMode(canvas, old_write_mode);
+ break;
+ }
+ case EMR_STRETCHBLT:
+ {
+ EMRSTRETCHBLT* data = (EMRSTRETCHBLT*)lpEMFR;
+ int size;
+ cdwDIB dib;
+ int old_write_mode;
+
+ if (data->dwRop == SRCINVERT)
+ old_write_mode = cdCanvasWriteMode(canvas, CD_XOR);
+ else
+ old_write_mode = cdCanvasWriteMode(canvas, CD_REPLACE);
+
+ cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc);
+
+ if (dib.type == -1)
+ break;
+
+ size = dib.w*abs(dib.h);
+
+ if (dib.type == 0)
+ {
+ char *r, *g, *b;
+
+ r = (char*)malloc(size);
+ g = (char*)malloc(size);
+ b = (char*)malloc(size);
+
+ cdwDIBDecodeRGB(&dib, r, g, b);
+
+ cdCanvasPutImageRectRGB(canvas, dib.w, abs(dib.h), r, g, b, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), sScaleW(data->cxDest), sScaleH(data->cyDest), 0, 0, 0, 0);
+
+ free(r);
+ free(g);
+ free(b);
+ }
+ else
+ {
+ char *index;
+ long *colors;
+
+ index = (char*)malloc(size);
+ colors = (long*)malloc(256*sizeof(long));
+
+ cdwDIBDecodeMap(&dib, index, colors);
+
+ cdCanvasPutImageRectMap(canvas, dib.w, abs(dib.h), index, colors, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), sScaleW(data->cxDest), sScaleH(data->cyDest), 0, 0, 0, 0);
+
+ free(index);
+ free(colors);
+ }
+
+ cdCanvasWriteMode(canvas, old_write_mode);
+ break;
+ }
+ case EMR_MASKBLT:
+ {
+ EMRMASKBLT* data = (EMRMASKBLT*)lpEMFR;
+ int size;
+ cdwDIB dib;
+ int old_write_mode;
+
+ if (data->dwRop == SRCINVERT)
+ old_write_mode = cdCanvasWriteMode(canvas, CD_XOR);
+ else
+ old_write_mode = cdCanvasWriteMode(canvas, CD_REPLACE);
+
+ cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc);
+
+ if (dib.type == -1)
+ break;
+
+ size = dib.w*abs(dib.h);
+
+ if (dib.type == 0)
+ {
+ char *r, *g, *b;
+
+ r = (char*)malloc(size);
+ g = (char*)malloc(size);
+ b = (char*)malloc(size);
+
+ cdwDIBDecodeRGB(&dib, r, g, b);
+
+ cdCanvasPutImageRectRGB(canvas, dib.w, abs(dib.h), r, g, b, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), dib.w, dib.h, 0, 0, 0, 0);
+
+ free(r);
+ free(g);
+ free(b);
+ }
+ else
+ {
+ char *index;
+ long *colors;
+
+ index = (char*)malloc(size);
+ colors = (long*)malloc(256*sizeof(long));
+
+ cdwDIBDecodeMap(&dib, index, colors);
+
+ cdCanvasPutImageRectMap(canvas, dib.w, abs(dib.h), index, colors, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), dib.w, dib.h, 0, 0, 0, 0);
+
+ free(index);
+ free(colors);
+ }
+
+ cdCanvasWriteMode(canvas, old_write_mode);
+ break;
+ }
+ case EMR_SETDIBITSTODEVICE:
+ {
+ EMRSETDIBITSTODEVICE* data = (EMRSETDIBITSTODEVICE*)lpEMFR;
+ int size;
+ cdwDIB dib;
+
+ cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc);
+
+ if (dib.type == -1)
+ break;
+
+ size = dib.w*abs(dib.h);
+
+ if (dib.type == 0)
+ {
+ char *r, *g, *b;
+
+ r = (char*)malloc(size);
+ g = (char*)malloc(size);
+ b = (char*)malloc(size);
+
+ cdwDIBDecodeRGB(&dib, r, g, b);
+
+ cdCanvasPutImageRectRGB(canvas, dib.w, abs(dib.h), r, g, b, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), dib.w, dib.h, 0, 0, 0, 0);
+
+ free(r);
+ free(g);
+ free(b);
+ }
+ else
+ {
+ char *index;
+ long *colors;
+
+ index = (char*)malloc(size);
+ colors = (long*)malloc(256*sizeof(long));
+
+ cdwDIBDecodeMap(&dib, index, colors);
+
+ cdCanvasPutImageRectMap(canvas, dib.w, abs(dib.h), index, colors, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), dib.w, dib.h, 0, 0, 0, 0);
+
+ free(index);
+ free(colors);
+ }
+ break;
+ }
+ case EMR_STRETCHDIBITS:
+ {
+ EMRSTRETCHDIBITS* data = (EMRSTRETCHDIBITS*)lpEMFR;
+ int size;
+ cdwDIB dib;
+
+ cdwDIBReference(&dib, ((BYTE*)data) + data->offBmiSrc, ((BYTE*)data) + data->offBitsSrc);
+
+ if (dib.type == -1)
+ break;
+
+ size = dib.w*abs(dib.h);
+
+ if (dib.type == 0)
+ {
+ char *r, *g, *b;
+
+ r = (char*)malloc(size);
+ g = (char*)malloc(size);
+ b = (char*)malloc(size);
+
+ cdwDIBDecodeRGB(&dib, r, g, b);
+
+ cdCanvasPutImageRectRGB(canvas, dib.w, abs(dib.h), r, g, b, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), sScaleW(data->cxDest), sScaleH(data->cyDest), 0, 0, 0, 0);
+
+ free(r);
+ free(g);
+ free(b);
+ }
+ else
+ {
+ char *index;
+ long *colors;
+
+ index = (char*)malloc(size);
+ colors = (long*)malloc(256*sizeof(long));
+
+ cdwDIBDecodeMap(&dib, index, colors);
+
+ cdCanvasPutImageRectMap(canvas, dib.w, abs(dib.h), index, colors, sScaleX(data->xDest), sScaleY(data->yDest + abs(dib.h)), sScaleW(data->cxDest), sScaleH(data->cyDest), 0, 0, 0, 0);
+
+ free(index);
+ free(colors);
+ }
+ break;
+ }
+ case EMR_EXTCREATEFONTINDIRECTW:
+ {
+ EMREXTCREATEFONTINDIRECTW* data = (EMREXTCREATEFONTINDIRECTW*)lpEMFR;
+ int style, size;
+ char type_face[256];
+
+ style = CD_PLAIN;
+
+ if (data->elfw.elfLogFont.lfWeight >= FW_BOLD)
+ style = CD_BOLD;
+
+ if (data->elfw.elfLogFont.lfItalic == 1)
+ style = CD_ITALIC;
+
+ if (data->elfw.elfLogFont.lfWeight >= FW_BOLD && data->elfw.elfLogFont.lfItalic == 1)
+ style = CD_BOLD_ITALIC;
+
+ if (data->elfw.elfLogFont.lfUnderline)
+ style |= CD_UNDERLINE;
+
+ if (data->elfw.elfLogFont.lfStrikeOut)
+ style |= CD_STRIKEOUT;
+
+ WideCharToMultiByte(CP_ACP, 0, data->elfw.elfLogFont.lfFaceName, LF_FACESIZE, type_face, 256, NULL, NULL);
+
+ size = sScaleH(abs(data->elfw.elfLogFont.lfHeight));
+ if (size < 5) size = 5;
+
+ if (data->elfw.elfLogFont.lfOrientation)
+ cdCanvasTextOrientation(canvas, data->elfw.elfLogFont.lfOrientation/10);
+
+ cdCanvasFont(canvas, type_face, style, -size);
+ break;
+ }
+ case EMR_EXTTEXTOUTA:
+ {
+ EMREXTTEXTOUTA* data = (EMREXTTEXTOUTA*)lpEMFR;
+
+ char* str = malloc(data->emrtext.nChars + 1);
+ memcpy(str, ((unsigned char*)data) + data->emrtext.offString, data->emrtext.nChars + 1);
+ str[data->emrtext.nChars] = 0;
+
+ cdCanvasText(canvas, sScaleX(data->emrtext.ptlReference.x), sScaleY(data->emrtext.ptlReference.y), str);
+
+ if (upd_xy == 1)
+ {
+ curx = data->emrtext.ptlReference.x;
+ cury = data->emrtext.ptlReference.y;
+ }
+
+ free(str);
+ break;
+ }
+ case EMR_EXTTEXTOUTW:
+ {
+ EMREXTTEXTOUTW* data = (EMREXTTEXTOUTW*)lpEMFR;
+ char str[256];
+
+ WideCharToMultiByte(CP_ACP, 0, (unsigned short*)(((unsigned char*)data) + data->emrtext.offString), data->emrtext.nChars, str, 256, NULL, NULL);
+
+ str[data->emrtext.nChars] = 0;
+
+ cdCanvasText(canvas, sScaleX(data->emrtext.ptlReference.x), sScaleY(data->emrtext.ptlReference.y), str);
+
+ if (upd_xy == 1)
+ {
+ curx = data->emrtext.ptlReference.x;
+ cury = data->emrtext.ptlReference.y;
+ }
+ break;
+ }
+ case EMR_SETPOLYFILLMODE:
+ {
+ EMRSETPOLYFILLMODE* data = (EMRSETPOLYFILLMODE*)lpEMFR;
+ if (data->iMode == ALTERNATE)
+ cdCanvasFillMode(canvas, CD_EVENODD);
+ else
+ cdCanvasFillMode(canvas, CD_WINDING);
+ break;
+ }
+ case EMR_POLYGON16:
+ {
+ EMRPOLYGON16* data = (EMRPOLYGON16*)lpEMFR;
+ int i;
+
+ cdCanvasBegin(canvas, CD_FILL);
+
+ for (i = 0; i < (int)data->cpts; i++)
+ cdCanvasVertex(canvas, sScaleX(data->apts[i].x), sScaleY(data->apts[i].y));
+
+ cdCanvasEnd(canvas);
+ break;
+ }
+ case EMR_POLYLINE16:
+ {
+ EMRPOLYLINE16* data = (EMRPOLYLINE16*)lpEMFR;
+ int i;
+
+ cdCanvasBegin(canvas, CD_OPEN_LINES);
+
+ for (i = 0; i < (int)data->cpts; i++)
+ cdCanvasVertex(canvas, sScaleX(data->apts[i].x), sScaleY(data->apts[i].y));
+
+ cdCanvasEnd(canvas);
+ break;
+ }
+ case EMR_POLYLINETO16:
+ {
+ EMRPOLYLINETO16* data = (EMRPOLYLINETO16*)lpEMFR;
+ int i;
+
+ cdCanvasBegin(canvas, CD_OPEN_LINES);
+
+ for (i = 0; i < (int)data->cpts; i++)
+ cdCanvasVertex(canvas, sScaleX(data->apts[i].x), sScaleY(data->apts[i].y));
+
+ curx = data->apts[data->cpts - 1].x;
+ cury = data->apts[data->cpts - 1].y;
+
+ cdCanvasEnd(canvas);
+ break;
+ }
+ case EMR_POLYBEZIER16:
+ {
+ EMRPOLYBEZIER16* data = (EMRPOLYBEZIER16*)lpEMFR;
+ int i;
+
+ cdCanvasBegin(canvas, CD_BEZIER);
+
+ for (i = 0; i < (int)data->cpts; i++)
+ cdCanvasVertex(canvas, sScaleX(data->apts[i].x), sScaleY(data->apts[i].y));
+
+ cdCanvasEnd(canvas);
+ break;
+ }
+ case EMR_POLYBEZIERTO16:
+ {
+ EMRPOLYBEZIERTO16* data = (EMRPOLYBEZIERTO16*)lpEMFR;
+ int i;
+
+ cdCanvasBegin(canvas, CD_BEZIER);
+
+ for (i = 0; i < (int)data->cpts; i++)
+ cdCanvasVertex(canvas, sScaleX(data->apts[i].x), sScaleY(data->apts[i].y));
+
+ curx = data->apts[data->cpts - 1].x;
+ cury = data->apts[data->cpts - 1].y;
+
+ cdCanvasEnd(canvas);
+ break;
+ }
+ case EMR_POLYPOLYLINE16:
+ {
+ EMRPOLYPOLYLINE16* data = (EMRPOLYPOLYLINE16*)lpEMFR;
+ POINTS* apts = (POINTS*)(data->aPolyCounts + data->nPolys); /* skip the array of counts */
+ int c, i; /* data->apts can not be used if count greater than 1 */
+
+ for (c = 0; c < (int)data->nPolys; c++)
+ {
+ cdCanvasBegin(canvas, CD_OPEN_LINES);
+
+ for (i = 0; i < (int)data->aPolyCounts[c]; i++, apts++)
+ cdCanvasVertex(canvas, sScaleX(apts->x), sScaleY(apts->y));
+
+ cdCanvasEnd(canvas);
+ }
+ break;
+ }
+ case EMR_POLYPOLYGON16:
+ {
+ EMRPOLYPOLYGON16* data = (EMRPOLYPOLYGON16*)lpEMFR;
+ POINTS* apts = (POINTS*)(data->aPolyCounts + data->nPolys); /* skip the array of counts */
+ int c, i; /* data->apts can not be used if count greater than 1 */
+
+ for (c = 0; c < (int)data->nPolys; c++)
+ {
+ cdCanvasBegin(canvas, CD_FILL);
+
+ for (i = 0; i < (int)data->aPolyCounts[c]; i++, apts++)
+ cdCanvasVertex(canvas, sScaleX(apts->x), sScaleY(apts->y));
+
+ cdCanvasEnd(canvas);
+ }
+ break;
+ }
+ case EMR_POLYDRAW16:
+ {
+ int p;
+ EMRPOLYDRAW16* data = (EMRPOLYDRAW16*)lpEMFR;
+
+ for(p = 0; p < (int)data->cpts; p++)
+ {
+ switch (data->abTypes[p])
+ {
+ case PT_MOVETO:
+ {
+ curx = data->apts[p].x;
+ cury = data->apts[p].y;
+ break;
+ }
+ case PT_LINETO:
+ {
+ cdCanvasLine(canvas, sScaleX(curx), sScaleY(cury), sScaleX(data->apts[p].x), sScaleY(data->apts[p].y));
+ curx = data->apts[p].x;
+ cury = data->apts[p].y;
+ break;
+ }
+ }
+ }
+ break;
+ }
+ case EMR_CREATEMONOBRUSH:
+ {
+ EMRCREATEMONOBRUSH* data = (EMRCREATEMONOBRUSH*)lpEMFR;
+ int size, i;
+ cdwDIB dib;
+ long *pattern;
+ unsigned char *stipple;
+
+ cdwDIBReference(&dib, ((BYTE*)data) + data->offBmi, ((BYTE*)data) + data->offBits);
+
+ if (dib.type == -1)
+ break;
+
+ size = dib.w*abs(dib.h);
+
+ if (dib.bmih->biBitCount == 1)
+ stipple = malloc(size);
+ else
+ pattern = (long*)malloc(size*sizeof(long));
+
+ if (dib.type == 0)
+ {
+ char *r, *g, *b;
+
+ r = (char*)malloc(size);
+ g = (char*)malloc(size);
+ b = (char*)malloc(size);
+
+ cdwDIBDecodeRGB(&dib, r, g, b);
+
+ for (i = 0; i < size; i++)
+ pattern[i] = cdEncodeColor(r[i], g[i], b[i]);
+
+ free(r);
+ free(g);
+ free(b);
+ }
+ else
+ {
+ unsigned char *index;
+ long *colors;
+
+ index = (unsigned char*)malloc(size);
+ colors = (long*)malloc(256*sizeof(long));
+
+ cdwDIBDecodeMap(&dib, index, colors);
+
+ if (dib.bmih->biBitCount == 1)
+ {
+ for (i = 0; i < size; i++)
+ stipple[i] = index[i]? 0: 1;
+ }
+ else
+ {
+ for (i = 0; i < size; i++)
+ pattern[i] = colors[index[i]];
+ }
+
+ free(index);
+ free(colors);
+ }
+
+ if (dib.bmih->biBitCount == 1)
+ {
+ cdCanvasStipple(canvas, dib.w, abs(dib.h), stipple);
+ free(stipple);
+ }
+ else
+ {
+ cdCanvasPattern(canvas, dib.w, abs(dib.h), pattern);
+ free(pattern);
+ }
+ break;
+ }
+ case EMR_CREATEDIBPATTERNBRUSHPT:
+ {
+ EMRCREATEDIBPATTERNBRUSHPT* data = (EMRCREATEDIBPATTERNBRUSHPT*)lpEMFR;
+ int size, i;
+ cdwDIB dib;
+ long *pattern;
+ unsigned char *stipple;
+
+ cdwDIBReference(&dib, ((BYTE*)data) + data->offBmi, ((BYTE*)data) + data->offBits);
+
+ if (dib.type == -1)
+ break;
+
+ size = dib.w*abs(dib.h);
+
+ if (dib.bmih->biBitCount == 1)
+ stipple = malloc(size);
+ else
+ pattern = malloc(size*sizeof(long));
+
+ if (dib.type == 0)
+ {
+ char *r, *g, *b;
+
+ r = (char*)malloc(size);
+ g = (char*)malloc(size);
+ b = (char*)malloc(size);
+
+ cdwDIBDecodeRGB(&dib, r, g, b);
+
+ for (i = 0; i < size; i++)
+ pattern[i] = cdEncodeColor(r[i], g[i], b[i]);
+
+ free(r);
+ free(g);
+ free(b);
+ }
+ else
+ {
+ char *index;
+ long *colors;
+
+ index = (char*)malloc(size);
+ colors = (long*)malloc(256*sizeof(long));
+
+ cdwDIBDecodeMap(&dib, index, colors);
+
+ if (dib.bmih->biBitCount == 1)
+ {
+ for (i = 0; i < size; i++)
+ stipple[i] = index[i]? 0: 1;
+ }
+ else
+ {
+ for (i = 0; i < size; i++)
+ pattern[i] = colors[index[i]];
+ }
+
+ free(index);
+ free(colors);
+ }
+
+ if (dib.bmih->biBitCount == 1)
+ {
+ cdCanvasStipple(canvas, dib.w, abs(dib.h), stipple);
+ free(stipple);
+ }
+ else
+ {
+ cdCanvasPattern(canvas, dib.w, abs(dib.h), pattern);
+ free(pattern);
+ }
+ break;
+ }
+ case EMR_POLYTEXTOUTA:
+ {
+ int t;
+ EMRPOLYTEXTOUTA* data = (EMRPOLYTEXTOUTA*)lpEMFR;
+
+ for (t = 0; t < data->cStrings; t++)
+ {
+ char* str = malloc(data->aemrtext[t].nChars + 1);
+ memcpy(str, ((unsigned char*)data) + data->aemrtext[t].offString, data->aemrtext[t].nChars + 1);
+ str[data->aemrtext[t].nChars] = 0;
+
+ cdCanvasText(canvas, sScaleX(data->aemrtext[t].ptlReference.x), sScaleY(data->aemrtext[t].ptlReference.y), str);
+
+ free(str);
+ }
+ break;
+ }
+ case EMR_POLYTEXTOUTW:
+ {
+ int t;
+ EMRPOLYTEXTOUTW* data = (EMRPOLYTEXTOUTW*)lpEMFR;
+ char str[256];
+
+ for (t = 0; t < data->cStrings; t++)
+ {
+ WideCharToMultiByte(CP_ACP, 0, (unsigned short*)(((unsigned char*)data) + data->aemrtext[t].offString), data->aemrtext[t].nChars, str, 256, NULL, NULL);
+ str[data->aemrtext[t].nChars] = 0;
+ cdCanvasText(canvas, sScaleX(data->aemrtext[t].ptlReference.x), sScaleY(data->aemrtext[t].ptlReference.y), str);
+ }
+ break;
+ }
+ }
+
+ return 1;
+}
+
+
+static cdSizeCB cdsizecbWMF = NULL;
+
+int cdregistercallbackWMF(int cb, cdCallback func)
+{
+ switch (cb)
+ {
+ case CD_SIZECB:
+ cdsizecbWMF = (cdSizeCB)func;
+ return CD_OK;
+ }
+
+ return CD_ERROR;
+}
+
+
+/***********************************************************************
+Read the metafile bits, metafile header and placeable
+metafile header of a placeable metafile.
+************************************************************************/
+
+static HANDLE GetPlaceableMetaFile(int fh)
+{
+ HANDLE hMF;
+ HANDLE hMem;
+ LPSTR lpMem;
+ int wBytesRead;
+ APMFILEHEADER aldusMFHeader;
+ METAHEADER mfHeader;
+
+ /* seek to beginning of file and read aldus header */
+ lseek(fh, 0, 0);
+
+ /* read the placeable header */
+ wBytesRead = read(fh, (LPSTR)&aldusMFHeader, sizeof(APMFILEHEADER));
+
+ /* if there is an error, return */
+ if(wBytesRead == -1 || wBytesRead < sizeof(APMFILEHEADER))
+ return NULL;
+
+ /* read the metafile header */
+ wBytesRead = read(fh, (LPSTR)&mfHeader, sizeof(METAHEADER));
+
+ /* if there is an error return */
+ if( wBytesRead == -1 || wBytesRead < sizeof(METAHEADER) )
+ return NULL;
+
+ /* allocate memory for the metafile bits */
+ if (!(hMem = GlobalAlloc(GHND, mfHeader.mtSize * 2L)))
+ return NULL;
+
+ /* lock the memory */
+ if (!(lpMem = GlobalLock(hMem)))
+ {
+ GlobalFree(hMem);
+ return NULL;
+ }
+
+ /* seek to the metafile bits */
+ lseek(fh, sizeof(APMFILEHEADER), 0);
+
+ /* read metafile bits */
+ wBytesRead = read(fh, lpMem, (WORD)(mfHeader.mtSize * 2L));
+
+ /* if there was an error */
+ if( wBytesRead == -1 )
+ {
+ GlobalUnlock(hMem);
+ GlobalFree(hMem);
+ return NULL;
+ }
+
+ if (!(hMF = SetMetaFileBitsEx(mfHeader.mtSize * 2L, lpMem)))
+ return NULL;
+
+ GlobalUnlock(hMem);
+ GlobalFree(hMem);
+
+ return hMF;
+}
+
+
+/*
+%F cdPlay para WMF.
+Interpreta os dados do WMF.
+*/
+int cdplayWMF(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax, void *data)
+{
+ char* filename = (char*)data;
+ int fh;
+ int wBytesRead;
+ DWORD dwIsAldus;
+ HANDLE hMF;
+ HENHMETAFILE hEMF;
+ ENHMETAHEADER emh;
+ BYTE* buffer;
+ int size;
+
+ /* try to open the file. */
+ fh = open(filename, O_BINARY | O_RDONLY);
+
+ /* if opened failed */
+ if (fh == -1)
+ return CD_ERROR;
+
+ /* read the first dword of the file to see if it is a placeable wmf */
+ wBytesRead = read(fh,(LPSTR)&dwIsAldus, sizeof(dwIsAldus));
+ if (wBytesRead == -1 || wBytesRead < sizeof(dwIsAldus))
+ {
+ close(fh);
+ return CD_ERROR;
+ }
+
+ /* if this is windows metafile, not a placeable wmf */
+ if (dwIsAldus != ALDUSKEY)
+ {
+ METAHEADER mfHeader;
+
+ /* seek to the beginning of the file */
+ lseek(fh, 0, 0);
+
+ /* read the wmf header */
+ wBytesRead = read(fh, (LPSTR)&mfHeader, sizeof(METAHEADER));
+
+ /* done with file so close it */
+ close(fh);
+
+ /* if read failed */
+ if (wBytesRead == -1 || wBytesRead < sizeof(METAHEADER))
+ return CD_ERROR;
+
+ hMF = GetMetaFile(filename);
+ }
+ else /* this is a placeable metafile */
+ {
+ /* convert the placeable format into something that can
+ be used with GDI metafile functions */
+ hMF = GetPlaceableMetaFile(fh);
+
+ /* close the file */
+ close(fh);
+ }
+
+ if (!hMF)
+ return CD_ERROR;
+
+ size = GetMetaFileBitsEx(hMF, 0, NULL);
+
+ buffer = malloc(size);
+
+ GetMetaFileBitsEx(hMF, size, buffer);
+
+ hEMF = SetWinMetaFileBits(size, buffer, NULL, NULL);
+
+ GetEnhMetaFileHeader(hEMF, sizeof(ENHMETAHEADER), &emh);
+
+ /* when converted from WMF, only rclBounds is available */
+ wmf_bottom = emh.rclBounds.bottom;
+ wmf_left = emh.rclBounds.left;
+ wmf_top = emh.rclBounds.top;
+ wmf_right = emh.rclBounds.right;
+
+ if ((xmax-xmin+1)>1 && (ymax-ymin+1)>1) /* always update wmf_rect when scaling */
+ EnumEnhMetaFile(NULL, hEMF, CalcSizeEMFEnumProc, NULL, NULL);
+
+ if ((wmf_bottom-wmf_top)>1 &&
+ (wmf_right-wmf_left)>1 &&
+ (xmax-xmin+1)>1 &&
+ (ymax-ymin+1)>1)
+ {
+ wmf_yfactor = ((double)(ymax-ymin+1)) / (double)(wmf_top-wmf_bottom); /* negative because top-down orientation */
+ wmf_xfactor = ((double)(xmax-xmin+1)) / (double)(wmf_right-wmf_left);
+ wmf_xmin = xmin;
+ wmf_ymin = ymin;
+ }
+ else
+ {
+ wmf_yfactor = -1; /* negative because top-down orientation */
+ wmf_xfactor = 1;
+ wmf_xmin = 0;
+ wmf_ymin = 0;
+ }
+
+ free(buffer);
+
+ if (cdsizecbWMF && dwIsAldus == ALDUSKEY)
+ {
+ int err;
+ err = cdsizecbWMF(canvas, wmf_right-wmf_left, wmf_bottom-wmf_top, 0, 0);
+ if (err)
+ {
+ DeleteEnhMetaFile (hEMF);
+ return CD_ERROR;
+ }
+ }
+
+ EnumEnhMetaFile(NULL, hEMF, EMFEnumProc, canvas, NULL);
+
+ DeleteEnhMetaFile (hEMF);
+
+ DeleteMetaFile (hMF);
+
+ return CD_OK;
+}
+
+
+static cdSizeCB cdsizecbEMF = NULL;
+
+int cdregistercallbackEMF(int cb, cdCallback func)
+{
+ switch (cb)
+ {
+ case CD_SIZECB:
+ cdsizecbEMF = (cdSizeCB)func;
+ return CD_OK;
+ }
+
+ return CD_ERROR;
+}
+
+
+int cdplayEMF(cdCanvas* canvas, int xmin, int xmax, int ymin, int ymax, void *data)
+{
+ char* filename = (char*)data;
+ HENHMETAFILE hEMF;
+ ENHMETAHEADER emh;
+ double xres, yres;
+
+ hEMF = GetEnhMetaFile(filename);
+
+ GetEnhMetaFileHeader(hEMF, sizeof(ENHMETAHEADER), &emh);
+
+ /* this is obtained from the hdcRef of CreateEnhMetaFile */
+ xres = ((double)emh.szlDevice.cx) / emh.szlMillimeters.cx;
+ yres = ((double)emh.szlDevice.cy) / emh.szlMillimeters.cy;
+
+ /* this is the same as used in RECT of CreateEnhMetaFile */
+ wmf_bottom = (int)((emh.rclFrame.bottom * yres) / 100);
+ wmf_left = (int)((emh.rclFrame.left * xres) / 100);
+ wmf_top = (int)((emh.rclFrame.top * yres) / 100);
+ wmf_right = (int)((emh.rclFrame.right * xres) / 100);
+
+ if ((xmax-xmin+1)>1 && (ymax-ymin+1)>1) /* always update wmf_rect when scaling */
+ EnumEnhMetaFile(NULL, hEMF, CalcSizeEMFEnumProc, NULL, NULL);
+
+ if ((wmf_bottom-wmf_top)>1 &&
+ (wmf_right-wmf_left)>1 &&
+ (xmax-xmin+1)>1 &&
+ (ymax-ymin+1)>1)
+ {
+ wmf_yfactor = ((double)(ymax-ymin+1)) / (double)(wmf_top-wmf_bottom); /* negative because top-down orientation */
+ wmf_xfactor = ((double)(xmax-xmin+1)) / (double)(wmf_right-wmf_left);
+ wmf_xmin = xmin;
+ wmf_ymin = ymin;
+ }
+ else
+ {
+ wmf_yfactor = -1; /* negative because top-down orientation */
+ wmf_xfactor = 1;
+ wmf_xmin = 0;
+ wmf_ymin = 0;
+ }
+
+ if (cdsizecbEMF)
+ {
+ int err;
+ err = cdsizecbEMF(canvas, wmf_right-wmf_left, wmf_bottom-wmf_top, 0, 0);
+ if (err)
+ {
+ DeleteEnhMetaFile (hEMF);
+ return CD_ERROR;
+ }
+ }
+
+ EnumEnhMetaFile(NULL, hEMF, EMFEnumProc, canvas, NULL);
+
+ DeleteEnhMetaFile (hEMF);
+
+ return CD_OK;
+}
+
+/*
+%F Calculo do CheckSum.
+*/
+static WORD sAPMChecksum(APMFILEHEADER* papm)
+{
+ WORD* pw = (WORD*)papm;
+ WORD wSum = 0;
+ int i;
+
+ /* The checksum in a Placeable Metafile header is calculated */
+ /* by XOR-ing the first 10 words of the header. */
+
+ for (i = 0; i < 10; i++)
+ wSum ^= *pw++;
+
+ return wSum;
+}
+
+
+
+/*
+Aldus placeable metafile format
+
+ DWORD key;
+ HANDLE hmf;
+ RECT bbox;
+ WORD inch;
+ DWORD reserved;
+ WORD checksum;
+ char metafileData[];
+
+ These fields have the following meanings:
+
+ Field Definition
+
+ key Binary key that uniquely identifies this
+ file type. This must be 0x9AC6CDD7L.
+
+ hmf Unused; must be zero.
+
+ bbox The coordinates of a rectangle that tightly
+ bounds the picture. These coordinates are in
+ metafile units as defined below.
+
+ inch The number of metafile units to the inch. To
+ avoid numeric overflow in PageMaker, this value
+ should be less than 1440.
+
+ reserved A reserved double word. Must be zero.
+
+ checksum A checksum of the 10 words that precede it,
+ calculated by XORing zero with these 10 words
+ and putting the result in the checksum field.
+
+ metafileData The actual content of the Windows metafile
+ retrieved by copying the data returned by
+ GetMetafileBits to the file. The number of
+ bytes should be equal to the MS-DOS file length
+ minus 22. The content of a PageMaker placeable
+ metafile cannot currently exceed 64K (this may
+ have changed in 4.0).
+*/
+
+/*
+%F Cria um APM em arquivo a partir de um WMF em memoria.
+*/
+void wmfMakePlaceableMetafile(HMETAFILE hmf, char* filename, int w, int h)
+{
+ int fh, nSize;
+ LPSTR lpData;
+ APMFILEHEADER APMHeader;
+
+ fh = open(filename, O_CREAT | O_BINARY | O_WRONLY);
+
+ APMHeader.key1 = 0xCDD7;
+ APMHeader.key2 = 0x9AC6;
+ APMHeader.hmf = 0;
+ APMHeader.bleft = 0;
+ APMHeader.btop = 0;
+ APMHeader.bright = (short)w;
+ APMHeader.bbottom = (short)h;
+ APMHeader.inch = 100; /* this number works fine in Word, etc.. */
+ APMHeader.reserved1 = 0;
+ APMHeader.reserved2 = 0;
+ APMHeader.checksum = sAPMChecksum(&APMHeader);
+
+ write(fh, (LPSTR)&APMHeader, sizeof(APMFILEHEADER));
+
+ nSize = GetMetaFileBitsEx(hmf, 0, NULL);
+ lpData = malloc(nSize);
+ GetMetaFileBitsEx(hmf, nSize, lpData);
+
+ write(fh, lpData, nSize);
+ free(lpData);
+
+ close(fh);
+}
+
+void wmfWritePlacebleFile(HANDLE hFile, char* buffer, DWORD dwSize, LONG mm, LONG xExt, LONG yExt)
+{
+ DWORD nBytesWrite;
+ APMFILEHEADER APMHeader;
+ int w = xExt, h = yExt;
+
+ if (mm == MM_ANISOTROPIC || mm == MM_ISOTROPIC)
+ {
+ int res = 30;
+ w = xExt / res;
+ h = yExt / res;
+ }
+
+ APMHeader.key1 = 0xCDD7;
+ APMHeader.key2 = 0x9AC6;
+ APMHeader.hmf = 0;
+ APMHeader.bleft = 0;
+ APMHeader.btop = 0;
+ APMHeader.bright = (short)w;
+ APMHeader.bbottom = (short)h;
+ APMHeader.inch = 100; /* this number works fine in Word, etc.. */
+ APMHeader.reserved1 = 0;
+ APMHeader.reserved2 = 0;
+ APMHeader.checksum = sAPMChecksum(&APMHeader);
+
+ WriteFile(hFile, (LPSTR)&APMHeader, sizeof(APMFILEHEADER), &nBytesWrite, NULL);
+ WriteFile(hFile, buffer, dwSize, &nBytesWrite, NULL);
+}
+