diff options
author | scuri <scuri> | 2008-10-17 06:10:33 +0000 |
---|---|---|
committer | scuri <scuri> | 2008-10-17 06:10:33 +0000 |
commit | 7b52cc13af4e85f1ca2deb6b6c77de9c95ea0dcf (patch) | |
tree | d0857278bde2eff784227c57dcaf930346ceb7ac /src/win32/cdwin.c |
First commit - moving from LuaForge to SourceForge
Diffstat (limited to 'src/win32/cdwin.c')
-rw-r--r-- | src/win32/cdwin.c | 2368 |
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; +} |