#ifndef _WIN32 #error this file is for windows only. Don't include it in your project/makefile for other platforms #else #include #include #include #include "canvas.h" #include #include #include #include #include #include #include "bltcanvas.h" #include #include #define CBCLASS Canvas START_DISPATCH; CB(GETHDC, getHDC); CB(GETROOTWND, getRootWnd); CB(GETBITS, getBits); VCB(GETOFFSETS, getOffsets); CB(ISFIXEDCOORDS, isFixedCoords); CB(GETDIM, getDim); CB(GETTEXTFONT, getTextFont); CB(GETTEXTSIZE, getTextSize); CB(GETTEXTBOLD, getTextBold); CB(GETTEXTOPAQUE, getTextOpaque); CB(GETTEXTUNDERLINE, getTextUnderline); CB(GETTEXTITALIC, getTextItalic); CB(GETTEXTALIGN, getTextAlign); CB(GETTEXTCOLOR, getTextColor); CB(GETTEXTBKCOLOR, getTextBkColor); CB(GETTEXTAA, getTextAntialias); CB(GETCLIPBOX, getClipBox); END_DISPATCH; #undef CBCLASS //NONPORTABLE extern const wchar_t wasabi_default_fontnameW[]; Canvas::Canvas() : hdc(NULL), bits(NULL), srcwnd(NULL), fcoord(FALSE), xoffset(0), yoffset(0), width(0), height(0), pitch(0), defpen(NULL), curpen(NULL), userFontInfo(0) { //tfont = new String; // using dynamic tfont here coz we need to manage em with stack, so stacking fonts won't take sizeof(String) and their destruction will not fuxor everything //tfont->setValue(wasabi_default_fontname); } Canvas::~Canvas() { if (getHDC() && defpen != NULL) { SelectObject(getHDC(), defpen); DeleteObject(curpen); } if (!penstack.isempty()) DebugStringW(L"Pen stack not empty in Canvas::~Canvas !"); } void Canvas::setBaseWnd(BaseWnd *b) { srcwnd = b; } HDC Canvas::getHDC() { return hdc; } ifc_window *Canvas::getRootWnd() { return srcwnd; } void *Canvas::getBits() { return bits; } bool Canvas::getDim(int *w, int *h, int *p) { if (w) *w = width; if (h) *h = height; if (p) *p = pitch; return FALSE; } void Canvas::getOffsets(int *x, int *y) { if (x != NULL) *x = getXOffset(); if (y != NULL) *y = getYOffset(); } bool Canvas::isFixedCoords() { return fcoord; } BaseWnd *Canvas::getBaseWnd() { return srcwnd; } void Canvas::fillRgn(RegionI *r, COLORREF color) { ASSERT(r != NULL); HBRUSH brush = CreateSolidBrush(color); FillRgn(hdc, r->getOSHandle(), brush); DeleteObject(brush); } void Canvas::fillRect(const RECT *r, COLORREF color) { ASSERT(r != NULL); #if 0 HBRUSH brush; if (color == RGB(0, 0, 0)) { FillRect(hdc, r, (HBRUSH)GetStockObject(BLACK_BRUSH)); return ; } RECT rr = *r; offsetRect(&rr); brush = CreateSolidBrush(color); FillRect(hdc, &rr, brush); DeleteObject(brush); #else // see: http://ooeygui.typepad.com/ooey_gui/2005/06/tip_fast_solid_.html COLORREF clrOld = SetBkColor(hdc, color); RECT rr = *r; offsetRect(&rr); ExtTextOutW(hdc, 0, 0, ETO_OPAQUE, &rr, NULL, 0, NULL); SetBkColor(hdc, clrOld); #endif } void Canvas::fillRectAlpha(const RECT *r, COLORREF color, int alpha) { RECT blitr; RECT clipr; getClipBox(&clipr); IntersectRect(&blitr, &clipr, r); uint8_t *bits8 = (uint8_t *)(bits) + blitr.left*4 + blitr.top * pitch; nsutil_image_FillRectAlpha_RGB32((RGB32 *)(bits8), pitch, blitr.right-blitr.left, blitr.bottom-blitr.top, color, alpha); } void Canvas::drawRect(const RECT *r, int solid, COLORREF color, int alpha) { #if 0 unsigned int blah = (unsigned int)alpha; color = RGBTOBGR(color); color = (color & 0xFFFFFF) | (blah << 24); BltCanvas::premultiply(&color, 1); int ox, oy; getOffsets(&ox, &oy); int w, h, pitch; getDim(&w, &h, &pitch); RECT _r = *r; _r.right = MIN(r->right, w); _r.bottom = MIN(r->bottom, h); int _l = r->bottom - r->top; int m = _r.bottom - _r.top; int l = _l; pitch /= 4; int *p = (int *)bits + ox + r->left + (oy + r->top) * pitch; int n = r->right - r->left; int maxn = _r.right - _r.left; while (l-- && m--) { int _n = maxn; if (l == _l - 1 || !l) { if (solid) { while (_n--) { *p = Blenders::BLEND_ADJ2(*p, color); p++; } } else { while (_n--) { if (_n % 2) *p = Blenders::BLEND_ADJ2(*p, color); p++; } } p += n - maxn; } else { if (solid || l % 2) *p = Blenders::BLEND_ADJ2(*p, color); p += n - 1; if (n == maxn && (solid || l % 2)) *p = Blenders::BLEND_ADJ2(*p, color); p++; } p += pitch - n; } #else HBRUSH oldbrush = (HBRUSH)SelectObject(hdc, GetStockObject(NULL_BRUSH)); HPEN oldpen, pen; pen = CreatePen(solid ? PS_SOLID : PS_DOT, 0, color); oldpen = (HPEN)SelectObject(hdc, pen); ASSERT(r != NULL); RECT rr = *r; offsetRect(&rr); Rectangle(hdc, rr.left, rr.top, rr.right, rr.bottom); SelectObject(hdc, oldpen); SelectObject(hdc, oldbrush); DeleteObject(pen); #endif } int Canvas::getTextAlign() { return getFontInfo()->alignFlags; } int Canvas::getTextOpaque() { return getFontInfo()->opaque; } int Canvas::getTextUnderline() { return getFontInfo()->underline; } int Canvas::getTextItalic() { return getFontInfo()->italic; } int Canvas::getTextBold() { return getFontInfo()->bold; } int Canvas::getTextAntialias() { return getFontInfo()->antialias; } void Canvas::pushPen(COLORREF color) { pushPen(PENSTYLE_SOLID, 1, color); } void Canvas::pushPen(int style, int width, COLORREF color) { ASSERT(getHDC() != NULL); penstyle = style; penwidth = width; pencolor = color; penstruct s; curpen = CreatePen(style, width, color); HPEN oldpen = (HPEN)SelectObject(getHDC(), curpen); s.style = style; s.width = width; s.color = color; s.hpen = oldpen; penstack.push(s); } void Canvas::popPen() { ASSERT(getHDC() != NULL); if (penstack.isempty()) return ; penstruct s; penstack.pop(&s); SelectObject(getHDC(), s.hpen); DeleteObject(curpen); } int Canvas::getPenStyle() { return penstyle; } COLORREF Canvas::getPenColor() { return pencolor; } int Canvas::getPenWidth() { return penwidth; } COLORREF Canvas::getTextColor() { return getFontInfo()->color; } COLORREF Canvas::getTextBkColor() { return getFontInfo()->bgColor; } int Canvas::getTextSize() { return getFontInfo()->pointSize; } const wchar_t *Canvas::getTextFont() { return getFontInfo()->face; } void Canvas::moveTo(int x, int y) { MoveToEx(hdc, x, y, NULL); } void Canvas::lineTo(int x, int y) { LineTo(hdc, x, y); } void Canvas::lineDraw(int fromX, int fromY, int toX, int toY) { MoveToEx(hdc, fromX, fromY, NULL); LineTo(hdc, toX, toY); } void Canvas::drawSysObject(const RECT *r, int sysobj, int alpha) { #ifndef _NOSTUDIO RECT i_dont_trust_ms_with_my_rect = *r; switch (sysobj) { case DrawSysObj::BUTTON: WASABI_API_WND->paintset_render(Paintset::BUTTONUP, this, r, alpha); break; case DrawSysObj::BUTTON_PUSHED: WASABI_API_WND->paintset_render(Paintset::BUTTONDOWN, this, r, alpha); break; case DrawSysObj::BUTTON_DISABLED: WASABI_API_WND->paintset_render(Paintset::BUTTONDISABLED, this, r, alpha); break; #ifdef WIN32 case DrawSysObj::OSBUTTON: { DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_BUTTON, DFCS_BUTTONPUSH); } break; case DrawSysObj::OSBUTTON_PUSHED: { DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_BUTTON, DFCS_BUTTONPUSH | DFCS_PUSHED); } break; case DrawSysObj::OSBUTTON_DISABLED: { DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_BUTTON, DFCS_BUTTONPUSH | DFCS_INACTIVE); } break; case DrawSysObj::OSBUTTON_CLOSE: { DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_CAPTION, DFCS_CAPTIONCLOSE); } break; case DrawSysObj::OSBUTTON_CLOSE_PUSHED: { DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_CAPTION, DFCS_CAPTIONCLOSE | DFCS_PUSHED); } break; case DrawSysObj::OSBUTTON_CLOSE_DISABLED: { DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_CAPTION, DFCS_CAPTIONCLOSE | DFCS_INACTIVE); } break; case DrawSysObj::OSBUTTON_MINIMIZE: { DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_CAPTION, DFCS_CAPTIONMIN); } break; case DrawSysObj::OSBUTTON_MINIMIZE_PUSHED: { DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_CAPTION, DFCS_CAPTIONMIN | DFCS_PUSHED); } break; case DrawSysObj::OSBUTTON_MINIMIZE_DISABLED: { DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_CAPTION, DFCS_CAPTIONMIN | DFCS_INACTIVE); } break; case DrawSysObj::OSBUTTON_MAXIMIZE: { DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_CAPTION, DFCS_CAPTIONMAX); } break; case DrawSysObj::OSBUTTON_MAXIMIZE_PUSHED: { DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_CAPTION, DFCS_CAPTIONMAX | DFCS_PUSHED); } break; case DrawSysObj::OSBUTTON_MAXIMIZE_DISABLED: { DrawFrameControl(getHDC(), &i_dont_trust_ms_with_my_rect, DFC_CAPTION, DFCS_CAPTIONMAX | DFCS_INACTIVE); } break; #else #error port me! #endif break; } #endif } void Canvas::textOut(int x, int y, const wchar_t *txt, const Wasabi::FontInfo *fontInfo) { userFontInfo = fontInfo; WASABI_API_FONT->font_textOut(this, WA_FONT_TEXTOUT_NORMAL, x, y, 0, 0, txt); userFontInfo = 0; } void Canvas::textOut(int x, int y, int w, int h, const wchar_t *txt, const Wasabi::FontInfo *fontInfo) { userFontInfo = fontInfo; WASABI_API_FONT->font_textOut(this, WA_FONT_TEXTOUT_RECT, x, y, w, h, txt); userFontInfo = 0; } void Canvas::textOutEllipsed(int x, int y, int w, int h, const wchar_t *txt, const Wasabi::FontInfo *fontInfo) { userFontInfo = fontInfo; WASABI_API_FONT->font_textOut(this, WA_FONT_TEXTOUT_ELLIPSED, x, y, w, h, txt); userFontInfo = 0; } void Canvas::textOutWrapped(int x, int y, int w, int h, const wchar_t *txt, const Wasabi::FontInfo *fontInfo) { userFontInfo = fontInfo; WASABI_API_FONT->font_textOut(this, WA_FONT_TEXTOUT_WRAPPED, x, y, w, h, (txt)); userFontInfo = 0; } void Canvas::textOutWrappedPathed(int x, int y, int w, const wchar_t *txt, const Wasabi::FontInfo *fontInfo) { userFontInfo = fontInfo; WASABI_API_FONT->font_textOut(this, WA_FONT_TEXTOUT_WRAPPEDPATHED, x, y, w, 0, (txt)); userFontInfo = 0; } void Canvas::textOutCentered(RECT *r, const wchar_t *txt, const Wasabi::FontInfo *fontInfo) { userFontInfo = fontInfo; WASABI_API_FONT->font_textOut(this, WA_FONT_TEXTOUT_CENTERED, r->left, r->top, r->right, r->bottom, (txt)); userFontInfo = 0; } int Canvas::getTextWidth(const wchar_t *text, const Wasabi::FontInfo *fontInfo) { userFontInfo = fontInfo; int ret = WASABI_API_FONT->font_getInfo(this, fontInfo->face, WA_FONT_GETINFO_WIDTH, (text), NULL, NULL); userFontInfo = 0; return ret; } int Canvas::getTextHeight(const wchar_t *text, const Wasabi::FontInfo *fontInfo) { userFontInfo = fontInfo; int ret = WASABI_API_FONT->font_getInfo(this, fontInfo->face, WA_FONT_GETINFO_HEIGHT, (text), NULL, NULL); userFontInfo = 0; return ret; } void Canvas::getTextExtent(const wchar_t *txt, int *w, int *h, const Wasabi::FontInfo *fontInfo) { userFontInfo = fontInfo; WASABI_API_FONT->font_getInfo(this, fontInfo->face, WA_FONT_GETINFO_WIDTHHEIGHT, (txt), w, h); userFontInfo = 0; } void Canvas::offsetRect(RECT *r) { ASSERT(r != NULL); r->left += xoffset; r->right += xoffset; r->top += yoffset; r->bottom += yoffset; } void Canvas::selectClipRgn(api_region *r) { SelectClipRgn(hdc, r ? r->getOSHandle() : NULL); } int Canvas::getClipBox(RECT *r) { RECT dummy; if (!r) r = &dummy; return GetClipBox(hdc, r); } int Canvas::getClipRgn(api_region *r) { ASSERT(r != NULL); return GetClipRgn(hdc, r->getOSHandle()); } //FG> added blit canvas to canvas void Canvas::blit(int srcx, int srcy, Canvas *dest, int dstx, int dsty, int dstw, int dsth) { char *srcbits = (char *)getBits(); char *destbits = (char *)dest->getBits(); RECT clipr; if (srcbits && destbits && GetClipBox(dest->getHDC(), &clipr) == SIMPLEREGION) { int srcimg_w, srcimg_h, srcimg_p; getDim(&srcimg_w, &srcimg_h, &srcimg_p); int dstimg_w, dstimg_h, dstimg_p; dest->getDim(&dstimg_w, &dstimg_h, &dstimg_p); if (srcx < 0) { dstx -= srcx; dstw += srcx; srcx = 0; } if (srcy < 0) { dsty -= srcy; dsth += srcy; srcy = 0; } if (srcx + dstw >= srcimg_w) dstw = srcimg_w - srcx; if (srcy + dsth >= srcimg_h) dsth = srcimg_h - srcy; if (dstx < clipr.left) { srcx += clipr.left - dstx; dstw -= clipr.left - dstx; dstx = clipr.left; } if (dsty < clipr.top) { srcy += clipr.top - dsty; dsth -= clipr.top - dsty; dsty = clipr.top; } if (dstx + dstw >= clipr.right) dstw = clipr.right - dstx; if (dsty + dsth >= clipr.bottom) dsth = clipr.bottom - dsty; if (!dstw || !dsth) return ; int y; int yl = dsty + dsth; for (y = dsty; y < yl; y++) { MEMCPY32(destbits + y*dstimg_p + dstx*4, srcbits + srcy*srcimg_p + srcx*4, dstw); srcy++; } } else { //GdiFlush(); BitBlt(dest->getHDC(), dstx, dsty, dstw, dsth, getHDC(), srcx, srcy, SRCCOPY); } } #pragma comment(lib, "msimg32.lib") void Canvas::stretch(ifc_canvas *canvas, int x, int y, int w, int h) { if (bits) { SkinBitmap temp((ARGB32 *)bits, width, height); temp.stretch(canvas, x,y,w,h); } else { BLENDFUNCTION blendFn; blendFn.BlendOp = AC_SRC_OVER; blendFn.BlendFlags = 0; blendFn.SourceConstantAlpha = 255; blendFn.AlphaFormat = AC_SRC_ALPHA; AlphaBlend(canvas->getHDC(), x, y, w, h, getHDC(), 0, 0, width, height, blendFn); } } void Canvas::blitAlpha(ifc_canvas *canvas, int x, int y, int alpha) { if (bits) { SkinBitmap temp((ARGB32 *)bits, width, height); temp.blitAlpha(canvas, x,y,alpha); } else { BLENDFUNCTION blendFn; blendFn.BlendOp = AC_SRC_OVER; blendFn.BlendFlags = 0; blendFn.SourceConstantAlpha = alpha; blendFn.AlphaFormat = AC_SRC_ALPHA; AlphaBlend(canvas->getHDC(), x, y, width, height, getHDC(), 0, 0, width, height, blendFn); } } void Canvas::stretchToRectAlpha(ifc_canvas *canvas, RECT *src, RECT *dst, int alpha) { if (bits) { SkinBitmap temp((ARGB32 *)bits, width, height); temp.stretchToRectAlpha(canvas, src, dst, alpha); } else { BLENDFUNCTION blendFn; blendFn.BlendOp = AC_SRC_OVER; blendFn.BlendFlags = 0; blendFn.SourceConstantAlpha = alpha; blendFn.AlphaFormat = AC_SRC_ALPHA; AlphaBlend(canvas->getHDC(), dst->left, dst->top, dst->right - dst->left, dst->bottom - dst->top, getHDC(), src->left, src->top, src->right - src->left, src->bottom - src->top, blendFn); } } void Canvas::blitToRect(ifc_canvas *canvas, RECT *src, RECT *dst, int alpha) { if (bits) { SkinBitmap temp((ARGB32 *)bits, width, height); temp.blitToRect(canvas, src, dst, alpha); } else { BLENDFUNCTION blendFn; blendFn.BlendOp = AC_SRC_OVER; blendFn.BlendFlags = 0; blendFn.SourceConstantAlpha = alpha; blendFn.AlphaFormat = AC_SRC_ALPHA; AlphaBlend(canvas->getHDC(), dst->left, dst->top, dst->right - dst->left, dst->bottom - dst->top, getHDC(), src->left, src->top, src->right - src->left, src->bottom - src->top, blendFn); } } // src* are in fixed point static void scale_internal(int srcx, int srcy, int srcw, int srch, void *srcdib, int srcdib_w, int srcdib_h, int srcdib_p, int dstx, int dsty, int dstw, int dsth, void *dstdib, int nofilter) { // scaling up if ((dstw << 16) >= srcw && (dsth << 16) >= srch) { int y; int SY, dX, dY; int Xend = (srcdib_w - 2) << 16; SY = srcy; dX = srcw / dstw; dY = srch / dsth; int xstart = 0; int xp = srcx >> 16; if (xp < 0) { xstart = -xp; srcx += xstart * dX; } int xend = dstw; xp = (srcx + (dX * (xend - xstart))) >> 16; if (xp > srcdib_w) { xend = xstart + srcdib_w - (srcx >> 16); } for (y = 0; y < dsth; y ++) { int yp = (SY >> 16); if (yp >= 0) { int x; int SX = srcx; unsigned int *out = (unsigned int*)dstdib + xstart + y * dstw; int end = yp >= srcdib_h - 1; if (nofilter || end) { if (end) yp = srcdib_h - 1; unsigned int *in = (unsigned int*)((char *)srcdib + yp * srcdib_p); for (x = xstart; x < xend; x ++) // quick hack to draw last line { *out++ = in[SX >> 16]; SX += dX; } if (end) break; } else { unsigned int *in = (unsigned int*)((char *)srcdib + yp * srcdib_p); #ifndef NO_MMX if (Blenders::MMX_AVAILABLE()) { for (x = xstart; x < xend; x ++) { if (SX > Xend) *out++ = Blenders::BLEND4_MMX(in + (Xend >> 16), srcdib_w, 0xffff, SY); else *out++ = Blenders::BLEND4_MMX(in + (SX >> 16), srcdib_w, SX, SY); SX += dX; } } else #endif { for (x = xstart; x < xend; x ++) { if (SX > Xend) *out++ = Blenders::BLEND4(in + (Xend >> 16), srcdib_w, 0xffff, SY); else *out++ = Blenders::BLEND4(in + (SX >> 16), srcdib_w, SX, SY); SX += dX; } } } } SY += dY; } // end of scaling up } else // we are scaling down -- THIS IS SLOW AND MAY BREAK THINGS. :) { int y; int SY, dX, dY; SY = srcy; dX = srcw / dstw; dY = srch / dsth; int xstart = 0; int xp = srcx >> 16; if (xp < 0) { xstart = -xp; srcx += xstart * dX; } int xend = dstw; xp = (srcx + (dX * (xend - xstart))) >> 16; if (xp > srcdib_w) { xend = xstart + srcdib_w - (srcx >> 16); } for (y = 0; y < dsth; y ++) { // start and end of y source block int vStart = SY; int vEnd = SY + dY; int x; int SX = srcx; unsigned char *out = (unsigned char *)((unsigned int*)dstdib + xstart + y * dstw); for (x = xstart; x < xend; x ++) { if (((char *)out+4) >= ((char *)dstdib + 4*dstw*dsth)) break; int uStart = SX; int uEnd = SX + dX; // calculate sum of rectangle. int cnt = 0; __int64 accum[4] = {0, }; int v, u; for (v = vStart; v < vEnd; v += 65536) { unsigned int vscale = 65535; if (v == vStart) { vscale = 65535 - (v & 0xffff); } else if ((vEnd - v) < 65536) { vscale = (vEnd - v) & 0xffff; } int vp = v >> 16; unsigned char *in = (unsigned char*)((char *)srcdib + vp * srcdib_p + 4 * (uStart >> 16)); for (u = uStart; u < uEnd; u += 65536) { if (((char *)in+4) >= ((char *)srcdib + srcdib_p*srcdib_h)) break; unsigned int uscale = vscale; if (u == uStart) { uscale *= 65535 - (u & 0xffff); uscale >>= 16; } else if ((uEnd - u) < 65536) { uscale *= (uEnd - u) & 0xffff; uscale >>= 16; } cnt += uscale; if (uscale == 65535) { accum[0] += (in[0] << 16) - in[0]; accum[1] += (in[1] << 16) - in[1]; accum[2] += (in[2] << 16) - in[2]; accum[3] += (in[3] << 16) - in[3]; } else { accum[0] += in[0] * uscale; accum[1] += in[1] * uscale; accum[2] += in[2] * uscale; accum[3] += in[3] * uscale; } in += 4; } } if (!cnt) cnt++; out[0] = (uint8_t)(accum[0] / cnt); out[1] = (uint8_t)(accum[1] / cnt); out[2] = (uint8_t)(accum[2] / cnt); out[3] = (uint8_t)(accum[3] / cnt); out += 4; SX += dX; } SY += dY; } // end of scaling down } #ifndef NO_MMX Blenders::BLEND_MMX_END(); #endif } // src* are in fixed point void Canvas::stretchblit(int srcx, int srcy, int srcw, int srch, Canvas *dest, int dstx, int dsty, int dstw, int dsth) { //GdiFlush(); int done = 0; void *srcdib = getBits(); if (!dstw || !dsth || !srcw || !srch) return ; if (srcdib) { int srcdib_w, srcdib_h, srcdib_p; getDim(&srcdib_w, &srcdib_h, &srcdib_p); void *dstdib; BITMAPINFO dstbmi = {0}; HDC hMemDC; HBITMAP hsrcdib; dstbmi.bmiHeader.biSize = sizeof(dstbmi.bmiHeader); dstbmi.bmiHeader.biWidth = dstw; dstbmi.bmiHeader.biHeight = -ABS(dsth); dstbmi.bmiHeader.biPlanes = 1; dstbmi.bmiHeader.biBitCount = 32; dstbmi.bmiHeader.biCompression = BI_RGB; hMemDC = CreateCompatibleDC(NULL); hsrcdib = CreateDIBSection(hMemDC, &dstbmi, DIB_RGB_COLORS, &dstdib, NULL, 0); if (hsrcdib) { HBITMAP hprev = (HBITMAP)SelectObject(hMemDC, hsrcdib); scale_internal(srcx,srcy,srcw,srch,srcdib,srcdib_w,srcdib_h,srcdib_p,dstx,dsty,dstw,dsth,dstdib,0); BitBlt(dest->getHDC(), dstx, dsty, dstw, dsth, hMemDC, 0, 0, SRCCOPY); done++; SelectObject(hMemDC, hprev); DeleteObject(hsrcdib); } DeleteDC(hMemDC); } if (!done) { SetStretchBltMode(dest->getHDC(), COLORONCOLOR); StretchBlt(dest->getHDC(), dstx, dsty, dstw, dsth, getHDC(), srcx >> 16, srcy >> 16, srcw >> 16, srch >> 16, SRCCOPY); } } #define DEBUG_SCREEN_SHIFT 0 void Canvas::debug() { SysCanvas c; int w, h; getDim(&w, &h, NULL); blit(0, 0, &c, DEBUG_SCREEN_SHIFT, 0, w, h); } #define BF2 (~((3<<24)|(3<<16)|(3<<8)|3)) void Canvas::antiAliasTo(Canvas *dest, int w, int h, int aafactor) { ASSERT(aafactor != 0); if (aafactor == 1) { blit(0, 0, dest, 0, 0, w, h); return ; } ASSERT(getBits() != NULL); ASSERT(dest->getBits() != NULL); if (getBits() == NULL || dest->getBits() == NULL) return ; ASSERTPR(aafactor <= 2, "too lazy to generalize the code right now :)"); //GdiFlush(); // we should really store the bpp too int aaw = w * aafactor; unsigned long *s1 = (unsigned long *)getBits(), *s2 = s1 + 1; unsigned long *s3 = s1 + aaw, *s4 = s3 + 1; unsigned long *d = (unsigned long *)dest->getBits(); #if 1 for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { unsigned long tmp = ((*s1 & BF2) >> 2) + ((*s2 & BF2) >> 2) + ((*s3 & BF2) >> 2) + ((*s4 & BF2) >> 2); *d++ = tmp; s1 += 2; s2 += 2; s3 += 2; s4 += 2; } s1 += aaw; s2 += aaw; s3 += aaw; s4 += aaw; } #else for (int x = 0; x < w * h; x++) d[x] = s1[x]; #endif } void Canvas::colorToColor(COLORREF from, COLORREF to, RECT *r) { int w, h, ox, oy; // convert to bitmap order from = RGBTOBGR(from); to = RGBTOBGR(to); COLORREF *p; getDim(&w, &h, NULL); p = (COLORREF *)getBits(); getOffsets(&ox, &oy); p += ox + r->left + (oy + r->top) * w; int rw = r->right - r->left; for (int j = r->top;j < r->bottom;j++) { for (int i = r->left;i < r->right;i++) { if (*p == from) *p = to; p++; } p += w - rw; } } double Canvas::getSystemFontScale() { if (WASABI_API_CONFIG) { int v = WASABI_API_CONFIG->getIntPublic(L"manualsysmetrics", -1); if (v != -1) return (v / 100.0f); } int nLogDPIX = GetDeviceCaps(getHDC(), LOGPIXELSX); return ((float)nLogDPIX / 96.0f); } void Canvas::premultiply(ARGB32 *m_pBits, int nwords, int newalpha) { if (newalpha == -1) { nsutil_alpha_Premultiply_RGB32(m_pBits, nwords, nwords, 1); /* for (; nwords > 0; nwords--, m_pBits++) { unsigned char *pixel = (unsigned char *)m_pBits; unsigned int alpha = pixel[3]; if (alpha == 255) continue; pixel[0] = (pixel[0] * alpha) >> 8; // blue pixel[1] = (pixel[1] * alpha) >> 8; // green pixel[2] = (pixel[2] * alpha) >> 8; // red } */ } else { nsutil_alpha_PremultiplyValue_RGB8(m_pBits, nwords, nwords, 1, newalpha); /* for (; nwords > 0; nwords--, m_pBits++) { unsigned char *pixel = (unsigned char *)m_pBits; pixel[0] = (pixel[0] * newalpha) >> 8; // blue pixel[1] = (pixel[1] * newalpha) >> 8; // green pixel[2] = (pixel[2] * newalpha) >> 8; // red pixel[3] = (pixel[3] * newalpha) >> 8; // alpha } */ } } TextInfoCanvas::TextInfoCanvas(BaseWnd *basewnd) { ASSERT(basewnd != NULL); hWnd = basewnd->gethWnd(); hdc = GetDC(hWnd); } TextInfoCanvas::~TextInfoCanvas() { if (hdc) ReleaseDC(hWnd, hdc); } WndCanvas::WndCanvas(BaseWnd *basewnd) { attachToClient(basewnd); } WndCanvas::WndCanvas() { hWnd = NULL; } WndCanvas::~WndCanvas() { if (hWnd != NULL && hdc != NULL) ReleaseDC(hWnd, hdc); hdc = NULL; } int WndCanvas::attachToClient(BaseWnd *basewnd) { if (basewnd == NULL) return 0; hWnd = basewnd->gethWnd(); if (hWnd == NULL) return 0; hdc = GetDC(hWnd); if (hdc == NULL) return 0; srcwnd = basewnd; return 1; } #if 0//CUT int WndCanvas::attachToWnd(HWND _hWnd) { hWnd = _hWnd; ASSERT(hWnd != NULL); hdc = GetWindowDC(hWnd); ASSERT(hdc != NULL); return 1; } #endif PaintCanvas::PaintCanvas() { hWnd = NULL; } PaintCanvas::~PaintCanvas() { if (hdc != NULL) EndPaint(hWnd, &ps); hdc = NULL; } void PaintCanvas::getRcPaint(RECT *r) { *r = ps.rcPaint; } int PaintCanvas::beginPaint(BaseWnd *basewnd) { hWnd = basewnd->gethWnd(); // NONPORTABLE ASSERT(hWnd != NULL); hdc = BeginPaint(hWnd, &ps); ASSERT(hdc != NULL); srcwnd = basewnd; return 1; } int PaintCanvas::beginPaint(HWND wnd) { hWnd = wnd; // NONPORTABLE ASSERT(hWnd != NULL); hdc = BeginPaint(hWnd, &ps); ASSERT(hdc != NULL); srcwnd = NULL; return 1; } PaintBltCanvas::PaintBltCanvas() { hWnd = NULL; wnddc = NULL; hbmp = NULL; prevbmp = NULL; bits = NULL; fcoord = TRUE; nonclient = FALSE; } PaintBltCanvas::~PaintBltCanvas() { RECT r; if (hdc == NULL) return ; ASSERT(srcwnd != NULL); if (nonclient) //FG> nonclient painting fix srcwnd->getNonClientRect(&r); else srcwnd->getClientRect(&r); // blt here //GdiFlush(); BitBlt(wnddc, r.left, r.top, r.right - r.left, r.bottom - r.top, hdc, 0, 0, SRCCOPY); //SelectClipRgn(hdc, NULL); // kill the bitmap and its DC SelectObject(hdc, prevbmp); DeleteDC(hdc); hdc = NULL; DeleteObject(hbmp); bits = NULL; width = 0; height = 0; pitch = 0; EndPaint(hWnd, &ps); // end of wnddc wnddc = NULL; } //FG> nonclient painting fix int PaintBltCanvas::beginPaintNC(BaseWnd *basewnd) { nonclient = TRUE; return beginPaint(basewnd); } void PaintBltCanvas::getRcPaint(RECT *r) { *r = ps.rcPaint; } int PaintBltCanvas::beginPaint(BaseWnd *basewnd) { RECT r; if (nonclient) basewnd->getNonClientRect(&r); //FG> nonclient painting fix else basewnd->getClientRect(&r); if (r.right - r.left <= 0 || r.bottom - r.top <= 0) return 0; hWnd = basewnd->gethWnd(); // NONPORTABLE ASSERT(hWnd != NULL); BITMAPINFO bmi; ZeroMemory(&bmi, sizeof bmi); bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = r.right - r.left; bmi.bmiHeader.biHeight = -(r.bottom - r.top); bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 32; bmi.bmiHeader.biCompression = BI_RGB; bmi.bmiHeader.biSizeImage = 0; bmi.bmiHeader.biXPelsPerMeter = 0; bmi.bmiHeader.biYPelsPerMeter = 0; bmi.bmiHeader.biClrUsed = 0; bmi.bmiHeader.biClrImportant = 0; wnddc = BeginPaint(hWnd, &ps); ASSERT(wnddc != NULL); //GdiFlush(); width = r.right - r.left; height = -ABS(r.bottom - r.top); pitch = width * 4; hbmp = CreateDIBSection(wnddc, &bmi, DIB_RGB_COLORS, &bits, NULL, 0); if (hbmp == NULL) { EndPaint(hWnd, &ps); // end of wnddc wnddc = NULL; return 0; } // create tha DC hdc = CreateCompatibleDC(wnddc); if (hdc == NULL) { DeleteObject(hbmp); EndPaint(hWnd, &ps); // end of wnddc wnddc = NULL; return 0; } prevbmp = (HBITMAP)SelectObject(hdc, hbmp); RegionI clip(&ps.rcPaint); selectClipRgn(&clip); srcwnd = basewnd; return 1; } void *PaintBltCanvas::getBits() { return bits; } MemCanvas::MemCanvas() {} MemCanvas::~MemCanvas() { DeleteDC(hdc); hdc = NULL; } int MemCanvas::createCompatible(Canvas *canvas) { ASSERT(canvas != NULL); ASSERT(canvas->getHDC() != NULL); hdc = CreateCompatibleDC(canvas->getHDC()); ASSERT(hdc != NULL); srcwnd = canvas->getBaseWnd(); return 1; } DCCanvas::DCCanvas(HDC clone, BaseWnd *srcWnd) { if (clone != NULL) cloneDC(clone, srcWnd); } DCCanvas::~DCCanvas() { hdc = NULL; } int DCCanvas::cloneDC(HDC clone, BaseWnd *srcWnd) { ASSERT(clone != NULL); hdc = clone; srcwnd = srcWnd; return 1; } SysCanvas::SysCanvas() { hdc = GetDC(NULL); } SysCanvas::~SysCanvas() { ReleaseDC(NULL, hdc); hdc = NULL; } DCBltCanvas::DCBltCanvas() { origdc = NULL; hbmp = prevbmp = NULL; } DCBltCanvas::~DCBltCanvas() { commitDC(); // kill the bitmap and its DC SelectObject(hdc, prevbmp); DeleteDC(hdc); hdc = NULL; DeleteObject(hbmp); // don't kill origdc, it's been cloned } int DCBltCanvas::setOrigDC(HDC neworigdc) { // FG> allows custom draw on lists to be much faster origdc = neworigdc; return 1; } int DCBltCanvas::commitDC(void) { //FG if (origdc) { RECT c; if (GetClipBox(origdc, &c) == NULLREGION) c = rect; // shlap it down in its original spot //GdiFlush(); BitBlt(origdc, c.left, c.top, c.right - c.left, c.bottom - c.top, hdc, c.left-rect.left, c.top-rect.top, SRCCOPY); } return 1; } int DCBltCanvas::cloneDC(HDC clone, RECT *r, BaseWnd *srcWnd) { origdc = clone; srcwnd = srcWnd; ASSERT(r != NULL); rect = *r; #if 1 BITMAPINFO bmi; ZeroMemory(&bmi, sizeof bmi); bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = r->right - r->left; bmi.bmiHeader.biHeight = -ABS(r->bottom - r->top); bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 32; bmi.bmiHeader.biCompression = BI_RGB; bmi.bmiHeader.biSizeImage = 0; bmi.bmiHeader.biXPelsPerMeter = 0; bmi.bmiHeader.biYPelsPerMeter = 0; bmi.bmiHeader.biClrUsed = 0; bmi.bmiHeader.biClrImportant = 0; hbmp = CreateDIBSection(origdc, &bmi, DIB_RGB_COLORS, &bits, NULL, 0); width = bmi.bmiHeader.biWidth; height = ABS(bmi.bmiHeader.biHeight); pitch = width * 4; #else hbmp = CreateCompatibleBitmap(clone, r->right - r->left, r->bottom - r->top); #endif ASSERT(hbmp != NULL); // create tha DC hdc = CreateCompatibleDC(origdc); prevbmp = (HBITMAP)SelectObject(hdc, hbmp); // adjust their rect for them r->right -= r->left; r->left = 0; r->bottom -= r->top; r->top = 0; return 1; } DCExBltCanvas::DCExBltCanvas(HWND hWnd, HRGN hrgnClip, DWORD flags) : hwnd(hWnd) { origdc = GetDCEx(hWnd, hrgnClip, flags); RECT r; GetWindowRect(hWnd, &r); OffsetRect(&r, -r.left, -r.top); cloneDC(origdc, &r); } DCExBltCanvas::~DCExBltCanvas() { commitDC(); ReleaseDC(hwnd, origdc); origdc=0; } BaseCloneCanvas::BaseCloneCanvas(ifc_canvas *cloner) { if (cloner != NULL) clone(cloner); } int BaseCloneCanvas::clone(ifc_canvas *cloner) { ASSERTPR(hdc == NULL, "can't clone twice"); hdc = cloner->getHDC(); bits = cloner->getBits(); cloner->getDim(&width, &height, &pitch); // srcwnd = cloner->getBaseWnd(); cloner->getOffsets(&xoffset, &yoffset); canvasFontInfo.face = cloner->getTextFont(); // just copies the pointer so be careful canvasFontInfo.pointSize = cloner->getTextSize(); canvasFontInfo.bold = cloner->getTextBold(); canvasFontInfo.opaque = !!cloner->getTextOpaque(); canvasFontInfo.underline = !!cloner->getTextUnderline(); canvasFontInfo.italic = !!cloner->getTextItalic(); canvasFontInfo.alignFlags = cloner->getTextAlign(); canvasFontInfo.color = cloner->getTextColor(); canvasFontInfo.bgColor = cloner->getTextBkColor(); return (hdc != NULL); } BaseCloneCanvas::~BaseCloneCanvas() { hdc = NULL; } DDSurfaceCanvas::DDSurfaceCanvas(LPDIRECTDRAWSURFACE surface, int w, int h) { surf = surface; _w = w; _h = h; hdc = NULL; bits = NULL; } DDSurfaceCanvas::~DDSurfaceCanvas() { if (isready()) exit(); } int DDSurfaceCanvas::isready() { return bits != NULL; } void DDSurfaceCanvas::enter() { DDSURFACEDESC d = {sizeof(d), }; if ((surf->Lock(NULL, &d, DDLOCK_WAIT, NULL)) != DD_OK) return ; surf->GetDC(&hdc); bits = d.lpSurface; } void DDSurfaceCanvas::exit() { surf->ReleaseDC(hdc); surf->Unlock(bits); bits = NULL; hdc = NULL; } #endif//WIN32