diff options
Diffstat (limited to 'src/win32')
-rw-r--r-- | src/win32/cdwclp.c | 551 | ||||
-rw-r--r-- | src/win32/cdwdbuf.c | 169 | ||||
-rw-r--r-- | src/win32/cdwdib.c | 662 | ||||
-rw-r--r-- | src/win32/cdwemf.c | 117 | ||||
-rw-r--r-- | src/win32/cdwimg.c | 83 | ||||
-rw-r--r-- | src/win32/cdwin.c | 2368 | ||||
-rw-r--r-- | src/win32/cdwin.h | 181 | ||||
-rw-r--r-- | src/win32/cdwnative.c | 209 | ||||
-rw-r--r-- | src/win32/cdwprn.c | 184 | ||||
-rw-r--r-- | src/win32/cdwwmf.c | 109 | ||||
-rw-r--r-- | src/win32/wmf_emf.c | 2121 |
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); +} + |