/** \file * \brief Windows Base Driver * * See Copyright Notice in cd.h */ #include #include #include #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; static void cdgettextsize (cdCtxCanvas* ctxcanvas, const char *s, int len, int *width, int *height); /* %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; yhOldBrush) 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 set_dib_res(cdwDIB* dib, cdCtxCanvas* ctxcanvas) { dib->bmih->biXPelsPerMeter = (LONG)(ctxcanvas->canvas->xres*1000); dib->bmih->biYPelsPerMeter = (LONG)(ctxcanvas->canvas->yres*1000); } 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; /* trying to preserve pattern size during printing */ set_dib_res(&dib, ctxcanvas); 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; /* the remaining styles must recreate the current brush */ 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 sUpdateFill(cdCtxCanvas* ctxcanvas, int fill) { if (fill) { if ((ctxcanvas->logBrush.lbColor != ctxcanvas->fg) && (ctxcanvas->canvas->interior_style != CD_PATTERN)) cdinteriorstyle(ctxcanvas, ctxcanvas->canvas->interior_style); } else { if (ctxcanvas->rebuild_pen) sCreatePen(ctxcanvas); } } /*******************************************************************************/ static void cdline (cdCtxCanvas* ctxcanvas, int x1, int y1, int x2, int y2) { sUpdateFill(ctxcanvas, 0); 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; sUpdateFill(ctxcanvas, 0); 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) { sUpdateFill(ctxcanvas, 1); 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 sCalcArc(cdCanvas* canvas, int xc, int yc, int w, int h, double a1, double a2, winArcParam* arc, int swap) { /* computation is done as if the angles are counter-clockwise, and yaxis is NOT inverted. */ arc->LeftRect = xc - w/2; arc->TopRect = yc - h/2; arc->RightRect = xc + w/2 + 1; arc->BottomRect = yc + h/2 + 1; /* GDI orientation is the same as CD */ if (!canvas->invert_yaxis) _cdSwapInt(arc->BottomRect, arc->TopRect); /* not necessary, but done for clarity */ cdCanvasGetArcStartEnd(xc, yc, w, h, a1, a2, &(arc->XStartArc), &(arc->YStartArc), &(arc->XEndArc), &(arc->YEndArc)); if (canvas->invert_yaxis) { /* fix axis orientation */ arc->YStartArc = 2*yc - arc->YStartArc; arc->YEndArc = 2*yc - arc->YEndArc; } else { /* it is clock-wise when axis NOT inverted */ if (swap) { _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; sCalcArc(ctxcanvas->canvas, xc, yc, w, h, angle1, angle2, &arc, 1); sUpdateFill(ctxcanvas, 0); 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; sCalcArc(ctxcanvas->canvas, xc, yc, w, h, angle1, angle2, &arc, 1); sUpdateFill(ctxcanvas, 1); 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; sCalcArc(ctxcanvas->canvas, xc, yc, w, h, angle1, angle2, &arc, 1); sUpdateFill(ctxcanvas, 1); 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; if (mode == CD_PATH) { int p, current_set; /* if there is any current path, remove it */ BeginPath(ctxcanvas->hDC); current_set = 0; i = 0; for (p=0; pcanvas->path_n; p++) { switch(ctxcanvas->canvas->path[p]) { case CD_PATH_NEW: EndPath(ctxcanvas->hDC); BeginPath(ctxcanvas->hDC); current_set = 0; break; case CD_PATH_MOVETO: if (i+1 > n) return; MoveToEx(ctxcanvas->hDC, poly[i].x, poly[i].y, NULL); current_set = 1; i++; break; case CD_PATH_LINETO: if (i+1 > n) return; LineTo(ctxcanvas->hDC, poly[i].x, poly[i].y); current_set = 1; i++; break; case CD_PATH_ARC: { int xc, yc, w, h, old_arcmode = 0; double a1, a2; winArcParam arc; if (i+3 > n) return; if (!cdCanvasGetArcPath(ctxcanvas->canvas, poly+i, &xc, &yc, &w, &h, &a1, &a2)) return; sCalcArc(ctxcanvas->canvas, xc, yc, w, h, a1, a2, &arc, 0); if (current_set) LineTo(ctxcanvas->hDC, arc.XStartArc, arc.YStartArc); if ((a2-a1)<0) /* can be clockwise */ { /* Arc behave diferent when GM_ADVANCED is set */ old_arcmode = SetArcDirection(ctxcanvas->hDC, ctxcanvas->canvas->invert_yaxis? AD_CLOCKWISE: AD_COUNTERCLOCKWISE); } ArcTo(ctxcanvas->hDC, arc.LeftRect, arc.TopRect, arc.RightRect, arc.BottomRect, arc.XStartArc, arc.YStartArc, arc.XEndArc, arc.YEndArc); if (old_arcmode) /* restore */ SetArcDirection(ctxcanvas->hDC, old_arcmode); current_set = 1; i += 3; } break; case CD_PATH_CURVETO: if (i+3 > n) return; PolyBezierTo(ctxcanvas->hDC, (POINT*)(poly + i), 3); current_set = 1; i += 3; break; case CD_PATH_CLOSE: CloseFigure(ctxcanvas->hDC); break; case CD_PATH_FILL: sUpdateFill(ctxcanvas, 1); SetPolyFillMode(ctxcanvas->hDC, ctxcanvas->canvas->fill_mode==CD_EVENODD?ALTERNATE:WINDING); EndPath(ctxcanvas->hDC); FillPath(ctxcanvas->hDC); break; case CD_PATH_STROKE: sUpdateFill(ctxcanvas, 0); EndPath(ctxcanvas->hDC); StrokePath(ctxcanvas->hDC); break; case CD_PATH_FILLSTROKE: sUpdateFill(ctxcanvas, 1); sUpdateFill(ctxcanvas, 0); SetPolyFillMode(ctxcanvas->hDC, ctxcanvas->canvas->fill_mode==CD_EVENODD?ALTERNATE:WINDING); EndPath(ctxcanvas->hDC); StrokeAndFillPath(ctxcanvas->hDC); break; case CD_PATH_CLIP: SetPolyFillMode(ctxcanvas->hDC, ctxcanvas->canvas->fill_mode==CD_EVENODD?ALTERNATE:WINDING); EndPath(ctxcanvas->hDC); SelectClipPath(ctxcanvas->hDC, RGN_AND); break; } } return; } switch( mode ) { case CD_CLOSED_LINES: poly[n].x = poly[0].x; poly[n].y = poly[0].y; n++; /* continua */ case CD_OPEN_LINES: sUpdateFill(ctxcanvas, 0); Polyline(ctxcanvas->hDC, (POINT*)poly, n); break; case CD_BEZIER: sUpdateFill(ctxcanvas, 0); 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 { sUpdateFill(ctxcanvas, 1); 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; if (ctxcanvas->rotate_angle) { XFORM xForm; /* 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 { ModifyWorldTransform(ctxcanvas->hDC, NULL, MWT_IDENTITY); SetGraphicsMode(ctxcanvas->hDC, GM_COMPATIBLE); } } } static void sTextOutBlt(cdCtxCanvas* ctxcanvas, int px, int py, const char* s, int len) { 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); cdgettextsize(ctxcanvas, s, len, &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) { 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)(ht/2 * cos_teta + wt/2 * sin_teta); px_off = (int)(ht/2 * sin_teta - wt/2 * cos_teta); break; case CD_SOUTH_WEST: py_off = - (int)(ht/2 * cos_teta + wt/2 * sin_teta); px_off = - (int)(ht/2 * sin_teta - wt/2 * cos_teta); break; case CD_NORTH_WEST: py_off = (int)(ht/2 * cos_teta - wt/2 * sin_teta); px_off = (int)(ht/2 * sin_teta + wt/2 * cos_teta); break; case CD_SOUTH_EAST: py_off = - (int)(ht/2 * cos_teta - wt/2 * sin_teta); px_off = - (int)(ht/2 * sin_teta + wt/2 * cos_teta); 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 = 0; 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, len); 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 len, int *width, int *height) { SIZE size; GetTextExtentPoint32(ctxcanvas->hDC, s, len, &size); if (width) *width = size.cx; if (height) *height = size.cy; } static void cdwCanvasGetTextHeight(cdCanvas* canvas, int x, int y, const char *s, int len, int *hbox, int *hoff) { int w, h, ascent, height, baseline; int xmin, xmax, ymin, ymax; cdgettextsize(canvas->ctxcanvas, s, len, &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 len, int *x, int *y) { XFORM xForm; int hoff, h; cdwCanvasGetTextHeight(ctxcanvas->canvas, *x, *y, s, len, &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 len) { 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; cdgettextsize(ctxcanvas, s, len, 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, len, &x, &y); TextOut(ctxcanvas->hDC, x, y+1, s, len); /* 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, len); } 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) { /* reset to the identity. */ GetWorldTransform(ctxcanvas->hDC, &xForm); ModifyWorldTransform(ctxcanvas->hDC, NULL, MWT_IDENTITY); } if (ctxcanvas->canvas->invert_yaxis==0) /* if 0, invert because the transform was reset here */ 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. So it must be manually made there. */ 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; } if (eh < 0) /* must mirror the image */ { /* Fix position */ eh = -eh; ey = ey - eh; cdwDIBEncodeRGBARectMirror(&dib, red, green, blue, alpha, bx, by, width, height); } else cdwDIBEncodeRGBARect(&dib, red, green, blue, alpha, bx, by, width, height); 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) { XFORM xForm; if (GetGraphicsMode(ctxcanvas->hDC) == GM_ADVANCED) { /* reset to the identity. */ GetWorldTransform(ctxcanvas->hDC, &xForm); ModifyWorldTransform(ctxcanvas->hDC, NULL, MWT_IDENTITY); } if (ctxcanvas->canvas->invert_yaxis==0) /* if 0, invert because the transform was reset here */ y = _cdInvertYAxis(ctxcanvas->canvas, y); /* y is the bottom-left of the image in CD, must be at upper-left */ y -= ctximage->h-1; BitBlt(ctximage->hDC, 0, 0, ctximage->w, ctximage->h, ctxcanvas->hDC, x, y, 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; if (GetGraphicsMode(ctxcanvas->hDC) == GM_ADVANCED) { /* reset to the identity. */ GetWorldTransform(ctxcanvas->hDC, &xForm); ModifyWorldTransform(ctxcanvas->hDC, NULL, MWT_IDENTITY); } if (ctxcanvas->canvas->invert_yaxis==0) /* if 0, invert because the transform was reset here */ { dy = -dy; ymin = _cdInvertYAxis(ctxcanvas->canvas, ymin); ymax = _cdInvertYAxis(ctxcanvas->canvas, ymax); _cdSwapInt(ymin, ymax); } rect.left = xmin; rect.right = xmax+1; rect.top = ymin; rect.bottom = ymax+1; 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, because there is native support for transformations */ if (ctxcanvas->canvas->use_matrix) return; if (data) { sscanf(data, "%g %d %d", &ctxcanvas->rotate_angle, &ctxcanvas->rotate_center_x, &ctxcanvas->rotate_center_y); } else { ctxcanvas->rotate_angle = 0; ctxcanvas->rotate_center_x = 0; ctxcanvas->rotate_center_y = 0; } cdtransform(ctxcanvas, NULL); } 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; } int cdBaseDriver(void) { return CD_BASE_WIN; }