summaryrefslogtreecommitdiff
path: root/src/win32/cdwin.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/win32/cdwin.c')
-rw-r--r--src/win32/cdwin.c2368
1 files changed, 2368 insertions, 0 deletions
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;
+}