1490 lines
31 KiB
C++
1490 lines
31 KiB
C++
|
#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
|