diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/tataki/canvas/win/win32_canvas.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/tataki/canvas/win/win32_canvas.cpp')
-rw-r--r-- | Src/tataki/canvas/win/win32_canvas.cpp | 1489 |
1 files changed, 1489 insertions, 0 deletions
diff --git a/Src/tataki/canvas/win/win32_canvas.cpp b/Src/tataki/canvas/win/win32_canvas.cpp new file mode 100644 index 00000000..c3d2ad8b --- /dev/null +++ b/Src/tataki/canvas/win/win32_canvas.cpp @@ -0,0 +1,1489 @@ +#ifndef _WIN32 +#error this file is for windows only. Don't include it in your project/makefile for other platforms +#else +#include <tataki/export.h> +#include <tataki/api__tataki.h> +#include <tataki/blending/blending.h> +#include "canvas.h" +#include <tataki/bitmap/bitmap.h> +#include <tataki/region/region.h> +#include <api/wnd/basewnd.h> +#include <api/wnd/fontdef.h> +#include <api/wnd/paintsets.h> + +#include <bfc/assert.h> + +#include "bltcanvas.h" +#include <nsutil/alpha.h> +#include <nsutil/image.h> + +#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<int>(r->right, w); + _r.bottom = MIN<int>(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 |