cache invented mask bitmaps

svn: r1038
This commit is contained in:
Matthew Flatt 2005-10-10 22:10:42 +00:00
parent 12376454a3
commit 9da2dbe541
5 changed files with 193 additions and 121 deletions

View File

@ -159,9 +159,10 @@ class wxDC: public wxbDC
void SetRop(HDC cdc, int mode); void SetRop(HDC cdc, int mode);
void DoClipping(HDC cdc); void DoClipping(HDC cdc);
void SelectOldObjects(HDC dc); void SelectOldObjects(HDC dc);
HDC ThisDC(); HDC ThisDC(Bool flush_cache = TRUE);
void DoneDC(HDC dc); void DoneDC(HDC dc);
void ShiftXY(double x, double y, int *ix, int *iy); void ReleaseSelectedCache();
void ShiftXY(double x, double y, int *ix, int *iy);
Bool StartBrush(HDC dc, Bool no_stipple = FALSE); Bool StartBrush(HDC dc, Bool no_stipple = FALSE);
Bool StartPen(HDC dc); Bool StartPen(HDC dc);

View File

@ -20,6 +20,7 @@ class wxMemoryDC: public wxbMemoryDC
{ {
public: public:
Bool read_only; Bool read_only;
Bool refcount; /* when used as a mask cache */
wxMemoryDC(Bool read_only = 0); wxMemoryDC(Bool read_only = 0);
wxMemoryDC(wxCanvasDC *old_dc); // Create compatible DC wxMemoryDC(wxCanvasDC *old_dc); // Create compatible DC

View File

@ -122,6 +122,7 @@ class wxBrush: public wxbBrush
// Bitmap // Bitmap
class wxDC; class wxDC;
class wxMemoryDC;
class wxItem; class wxItem;
class wxGLConfig; class wxGLConfig;
@ -143,6 +144,7 @@ class wxBitmap: public wxObject
void *accounting; void *accounting;
wxDC *selectedInto; // So bitmap knows whether it's been selected into wxDC *selectedInto; // So bitmap knows whether it's been selected into
// a device context (for error checking) // a device context (for error checking)
wxMemoryDC *mask_cache; // the cached mask
Bool selectedIntoDC; Bool selectedIntoDC;
wxGLConfig *gl_cfg; wxGLConfig *gl_cfg;
@ -188,6 +190,8 @@ class wxBitmap: public wxObject
void SetGLConfig(wxGLConfig *gl_cfg); void SetGLConfig(wxGLConfig *gl_cfg);
wxGLConfig *GetGLConfig(void); wxGLConfig *GetGLConfig(void);
void ReleaseCachedMask();
}; };
// Cursor // Cursor

View File

@ -209,11 +209,14 @@ void wxDC::SelectOldObjects(HDC dc)
} }
} }
HDC wxDC::ThisDC(void) HDC wxDC::ThisDC(Bool flush_cache)
{ {
HDC dc = NULL; HDC dc = NULL;
wxWnd *wnd = NULL; wxWnd *wnd = NULL;
if (flush_cache)
ReleaseSelectedCache();
if (canvas) wnd = (wxWnd *)canvas->handle; if (canvas) wnd = (wxWnd *)canvas->handle;
if (cdc) if (cdc)
dc = cdc; dc = cdc;
@ -244,6 +247,37 @@ void wxDC::DoneDC(HDC dc)
} }
} }
void wxDC::ReleaseSelectedCache()
{
if (selected_bitmap) {
if (selected_bitmap->mask_cache) {
selected_bitmap->ReleaseCachedMask();
}
}
}
void wxBitmap::ReleaseCachedMask()
{
wxBitmap *bm;
wxMemoryDC *mdc;
if (mask_cache) {
mdc = mask_cache;
mask_cache = NULL;
bm = mdc->selected_bitmap;
if (bm) {
mdc->SelectObject(NULL);
DELETE_OBJ bm;
bm = NULL;
}
mdc->refcount--;
if (!mdc->refcount) {
DELETE_OBJ mdc;
mdc = NULL;
}
}
}
wxGL *wxDC::GetGL() wxGL *wxDC::GetGL()
{ {
if (!wx_gl) { if (!wx_gl) {
@ -385,7 +419,7 @@ void wxDC::SetClippingRegion(wxRegion *c)
if (clipping) if (clipping)
clipping->locked++; clipping->locked++;
dc = ThisDC(); dc = ThisDC(FALSE);
if (dc) DoClipping(dc); if (dc) DoClipping(dc);
DoneDC(dc); DoneDC(dc);
} }
@ -420,7 +454,7 @@ Bool wxDC::CanGetTextExtent(void)
HDC dc; HDC dc;
Bool tok; Bool tok;
dc = ThisDC(); dc = ThisDC(FALSE);
// What sort of display is it? // What sort of display is it?
@ -518,7 +552,7 @@ void wxDC::ReleaseGraphics(HDC given_dc)
if (given_dc) if (given_dc)
dc = given_dc; dc = given_dc;
else else
dc = ThisDC(); dc = ThisDC(FALSE);
if (dc) { if (dc) {
DoClipping(dc); DoClipping(dc);
if (!given_dc) if (!given_dc)
@ -540,7 +574,7 @@ void wxDC::OnCalcScroll(void)
ReleaseGraphics(); ReleaseGraphics();
if (clipping) { if (clipping) {
HDC dc; HDC dc;
dc = ThisDC(); dc = ThisDC(FALSE);
DoClipping(dc); DoClipping(dc);
DoneDC(dc); DoneDC(dc);
} }
@ -620,7 +654,7 @@ Bool wxDC::GlyphAvailable(int c, wxFont *f)
if (!f) if (!f)
f = font; f = font;
dc = ThisDC(); dc = ThisDC(FALSE);
if (!dc) return 0; if (!dc) return 0;
r = f->GlyphAvailable(c, dc, screen_font); r = f->GlyphAvailable(c, dc, screen_font);
@ -637,7 +671,7 @@ Bool wxDC::GetPixel(double x, double y, wxColour *col)
HDC dc; HDC dc;
COLORREF pixelcolor; COLORREF pixelcolor;
dc = ThisDC(); dc = ThisDC(FALSE);
if (!dc) return FALSE; if (!dc) return FALSE;
@ -1473,7 +1507,7 @@ void wxDC::SetFont(wxFont *the_font)
{ {
HDC dc; HDC dc;
dc = ThisDC(); dc = ThisDC(FALSE);
if (!dc) return; if (!dc) return;
font = the_font; font = the_font;
@ -1883,7 +1917,7 @@ void wxDC::SetBackground(wxColour *c)
} }
#endif #endif
dc = ThisDC(); dc = ThisDC(FALSE);
new_color = c->pixel; new_color = c->pixel;
if (new_color != cur_bk || dc != cur_dc) { if (new_color != cur_bk || dc != cur_dc) {
@ -2067,7 +2101,7 @@ double wxDC::GetCharHeight(void)
TEXTMETRIC lpTextMetric; TEXTMETRIC lpTextMetric;
HDC dc; HDC dc;
dc = ThisDC(); dc = ThisDC(FALSE);
if (!dc) return 10; if (!dc) return 10;
@ -2083,7 +2117,7 @@ double wxDC::GetCharWidth(void)
TEXTMETRIC lpTextMetric; TEXTMETRIC lpTextMetric;
HDC dc; HDC dc;
dc = ThisDC(); dc = ThisDC(FALSE);
if (!dc) return 5; if (!dc) return 5;
@ -2121,7 +2155,7 @@ void wxDC::GetTextExtent(const char *string, double *x, double *y,
fam = theFont->GetFamily(); fam = theFont->GetFamily();
dc = ThisDC(); dc = ThisDC(FALSE);
ReleaseGraphics(dc); ReleaseGraphics(dc);
@ -2186,7 +2220,7 @@ void wxDC::ResetMapMode(HDC given_dc)
if (given_dc) if (given_dc)
dc = given_dc; dc = given_dc;
else { else {
dc = ThisDC(); dc = ThisDC(FALSE);
if (!dc) return; if (!dc) return;
} }
@ -2415,10 +2449,10 @@ Bool wxDC::Blit(double xdest, double ydest, double width, double height,
sel = (wxMemoryDC *)source->selectedInto; sel = (wxMemoryDC *)source->selectedInto;
if (sel) { if (sel) {
sel->SetScaleMode(wxWX_SCALE); sel->SetScaleMode(wxWX_SCALE);
dc_src = sel->ThisDC(); dc_src = sel->ThisDC(FALSE);
} else { } else {
blit_dc->SelectObject(source); blit_dc->SelectObject(source);
dc_src = blit_dc->ThisDC(); dc_src = blit_dc->ThisDC(FALSE);
} }
if (!dc_src) { if (!dc_src) {
@ -2443,7 +2477,7 @@ Bool wxDC::Blit(double xdest, double ydest, double width, double height,
msel = (wxMemoryDC *)mask->selectedInto; msel = (wxMemoryDC *)mask->selectedInto;
if (msel) { if (msel) {
msel->SetScaleMode(wxWX_SCALE); msel->SetScaleMode(wxWX_SCALE);
mdc = msel->ThisDC(); mdc = msel->ThisDC(FALSE);
} else { } else {
if (!blit_mdc) { if (!blit_mdc) {
wxREGGLOB(blit_mdc); wxREGGLOB(blit_mdc);
@ -2451,119 +2485,146 @@ Bool wxDC::Blit(double xdest, double ydest, double width, double height,
} }
blit_mdc->SelectObject(mask); blit_mdc->SelectObject(mask);
mdc = blit_mdc->ThisDC(); mdc = blit_mdc->ThisDC(FALSE);
} }
} }
mono_src = (source->GetDepth() == 1); mono_src = (source->GetDepth() == 1);
invented = new wxBitmap(iw, ih, mono_src); if (mask->mask_cache
if (invented->Ok()) { && (mask->mask_cache == source->mask_cache)
GC_CAN_IGNORE void *pBits = NULL; /* set with use_alpha... */ && (mask != selected_bitmap)
&& (source != selected_bitmap)
&& (source->mask_cache->selected_bitmap)) {
invented = NULL;
invented_memdc = source->mask_cache;
invented_dc = invented_memdc->ThisDC();
if (mask->GetDepth() > 1) { if (mask->GetDepth() > 1) {
if (!tried_ab) {
HMODULE mod;
mod = LoadLibrary("Msimg32.dll");
if (mod)
wxAlphaBlend = (wxALPHA_BLEND)GetProcAddress(mod, "AlphaBlend");
tried_ab = 1;
}
if (wxAlphaBlend) if (wxAlphaBlend)
use_alpha = 1; use_alpha = 1;
/* Otherwise, no AlphaBlend. The result is somewhat unpredictable,
but somewhat as intended --- especially if we happend
to be drawing onto white. :) */
} }
} else {
invented = new wxBitmap(iw, ih, mono_src);
if (invented->Ok()) {
GC_CAN_IGNORE void *pBits = NULL; /* set with use_alpha... */
if (use_alpha) { if (mask->GetDepth() > 1) {
pBits = invented->ChangeToDIBSection(); if (!tried_ab) {
if (!pBits) { HMODULE mod;
use_alpha = 0; mod = LoadLibrary("Msimg32.dll");
/* half-failure... act like AlphaBlend isn't there */ if (mod)
wxAlphaBlend = (wxALPHA_BLEND)GetProcAddress(mod, "AlphaBlend");
tried_ab = 1;
}
if (wxAlphaBlend)
use_alpha = 1;
/* Otherwise, no AlphaBlend. The result is somewhat unpredictable,
but somewhat as intended --- especially if we happend
to be drawing onto white. :) */
} }
}
invented_memdc = new wxMemoryDC();
invented_memdc->SelectObject(invented);
if (invented_memdc->Ok()) {
invented_dc = invented_memdc->ThisDC();
/* Copy original src image here: */
BitBlt(invented_dc, 0, 0,
iw, ih,
dc_src, xsrc1, ysrc1,
SRCCOPY);
if (use_alpha) { if (use_alpha) {
/* "Pre-compute" alpha in the invented DC */ pBits = invented->ChangeToDIBSection();
GC_CAN_IGNORE BYTE *pPixel; if (!pBits) {
COLORREF mcol; use_alpha = 0;
int i, j, gray; /* half-failure... act like AlphaBlend isn't there */
GdiFlush();
for (j = 0; j < ih; j++) {
pPixel = (BYTE *) pBits + iw * 4 * (ih - j - 1);
for (i = 0; i < iw; i++) {
mcol = ::GetPixel(mdc, i + xsrc1, j + ysrc1);
gray = ((int)GetRValue(mcol)
+ (int)GetGValue(mcol)
+ (int)GetBValue(mcol)) / 3;
pPixel[0] = pPixel[0] * (255 - gray) / 255;
pPixel[1] = pPixel[1] * (255 - gray) / 255;
pPixel[2] = pPixel[2] * (255 - gray) / 255;
pPixel[3] = (255 - gray);
pPixel += 4;
}
}
} else {
/* Want white where mask was white,
src otherwise: */
BitBlt(invented_dc, 0, 0,
iw, ih,
mdc, xsrc1, ysrc1,
SRCPAINT /* DSo */);
/* Ignore the mask and... */
mask = NULL;
if (mono_src) {
/* Mono source: Now use invented_dc instead of src_dc,
and it all works out. */
xsrc1 = 0;
xsrc1 = 0;
} else {
/* Paint on dest using mask, then "and" invented image
with dest. */
invented_col = 1;
} }
} }
} else {
/* Failed (Rest of failure handling below since !invented_memdc) */
invented_memdc->SelectObject(NULL);
DELETE_OBJ invented_memdc;
invented_memdc = NULL;
DELETE_OBJ invented;
}
}
if (!invented_memdc) { invented_memdc = new wxMemoryDC();
/* Failed */ invented_memdc->SelectObject(invented);
if (msel) {
msel->DoneDC(mdc); if (invented_memdc->Ok()) {
} else { invented_dc = invented_memdc->ThisDC();
blit_mdc->DoneDC(mdc);
blit_mdc->SelectObject(NULL); /* Copy original src image here: */
BitBlt(invented_dc, 0, 0,
iw, ih,
dc_src, xsrc1, ysrc1,
SRCCOPY);
if (use_alpha) {
/* "Pre-compute" alpha in the invented DC */
GC_CAN_IGNORE BYTE *pPixel;
COLORREF mcol;
int i, j, gray;
GdiFlush();
for (j = 0; j < ih; j++) {
pPixel = (BYTE *) pBits + iw * 4 * (ih - j - 1);
for (i = 0; i < iw; i++) {
mcol = ::GetPixel(mdc, i + xsrc1, j + ysrc1);
gray = ((int)GetRValue(mcol)
+ (int)GetGValue(mcol)
+ (int)GetBValue(mcol)) / 3;
pPixel[0] = pPixel[0] * (255 - gray) / 255;
pPixel[1] = pPixel[1] * (255 - gray) / 255;
pPixel[2] = pPixel[2] * (255 - gray) / 255;
pPixel[3] = (255 - gray);
pPixel += 4;
}
}
} else {
/* Want white where mask was white,
src otherwise: */
BitBlt(invented_dc, 0, 0,
iw, ih,
mdc, xsrc1, ysrc1,
SRCPAINT /* DSo */);
/* Ignore the mask and... */
mask = NULL;
if (mono_src) {
/* Mono source: Now use invented_dc instead of src_dc,
and it all works out. */
xsrc1 = 0;
xsrc1 = 0;
} else {
/* Paint on dest using mask, then "and" invented image
with dest. */
invented_col = 1;
}
}
} else {
/* Failed (Rest of failure handling below since !invented_memdc) */
invented_memdc->SelectObject(NULL);
DELETE_OBJ invented_memdc;
invented_memdc = NULL;
DELETE_OBJ invented;
}
} }
DoneDC(dc);
if (sel) { if (!invented_memdc) {
sel->DoneDC(dc_src); /* Failed */
} else { if (msel) {
blit_dc->DoneDC(dc_src); msel->DoneDC(mdc);
blit_dc->SelectObject(NULL); } else {
blit_mdc->DoneDC(mdc);
blit_mdc->SelectObject(NULL);
}
DoneDC(dc);
if (sel) {
sel->DoneDC(dc_src);
} else {
blit_dc->DoneDC(dc_src);
blit_dc->SelectObject(NULL);
}
return 0;
}
if ((mask != selected_bitmap)
&& (source != selected_bitmap)) {
mask->ReleaseCachedMask();
source->ReleaseCachedMask();
mask->mask_cache = invented_memdc;
source->mask_cache = invented_memdc;
if (source == mask)
invented_memdc->refcount = 1;
else
invented_memdc->refcount = 2;
invented = NULL; /* indicates that we cached invented */
} }
return 0;
} }
} }
@ -2658,10 +2719,13 @@ Bool wxDC::Blit(double xdest, double ydest, double width, double height,
} }
} }
if (invented_memdc) { if (invented_memdc) {
invented_memdc->DoneDC(invented_dc); /* If invented, then cached, so don't delete here. */
invented_memdc->SelectObject(NULL); if (invented) {
DELETE_OBJ invented_memdc; invented_memdc->DoneDC(invented_dc);
DELETE_OBJ invented; invented_memdc->SelectObject(NULL);
DELETE_OBJ invented_memdc;
DELETE_OBJ invented;
}
} }
return success; return success;
@ -2672,7 +2736,7 @@ void wxDC::GetSize(double *width, double *height)
HDC dc; HDC dc;
int w, h; int w, h;
dc = ThisDC(); dc = ThisDC(FALSE);
if (!dc) { if (!dc) {
*width = *height = 0; *width = *height = 0;
@ -2692,7 +2756,7 @@ void wxDC::GetSizeMM(double *width, double *height)
HDC dc; HDC dc;
int w, h; int w, h;
dc = ThisDC(); dc = ThisDC(FALSE);
if (!dc) { if (!dc) {
*width = *height = 0; *width = *height = 0;
@ -2755,7 +2819,7 @@ void wxCanvasDC::TryColour(wxColour *src, wxColour *dest)
HDC dc; HDC dc;
int r, gr, b; int r, gr, b;
dc = ThisDC(); dc = ThisDC(FALSE);
if (!dc) { if (!dc) {
dest->Set(0, 0, 0); dest->Set(0, 0, 0);
return; return;

View File

@ -2008,6 +2008,8 @@ wxBitmap::~wxBitmap(void)
{ {
COUNT_M(bitmap_count); COUNT_M(bitmap_count);
ReleaseCachedMask();
if (selectedInto) { if (selectedInto) {
((wxMemoryDC *)selectedInto)->SelectObject(NULL); ((wxMemoryDC *)selectedInto)->SelectObject(NULL);
selectedInto = NULL; selectedInto = NULL;