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 DoClipping(HDC cdc);
void SelectOldObjects(HDC dc);
HDC ThisDC();
void DoneDC(HDC dc);
void ShiftXY(double x, double y, int *ix, int *iy);
HDC ThisDC(Bool flush_cache = TRUE);
void DoneDC(HDC dc);
void ReleaseSelectedCache();
void ShiftXY(double x, double y, int *ix, int *iy);
Bool StartBrush(HDC dc, Bool no_stipple = FALSE);
Bool StartPen(HDC dc);

View File

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

View File

@ -122,6 +122,7 @@ class wxBrush: public wxbBrush
// Bitmap
class wxDC;
class wxMemoryDC;
class wxItem;
class wxGLConfig;
@ -143,6 +144,7 @@ class wxBitmap: public wxObject
void *accounting;
wxDC *selectedInto; // So bitmap knows whether it's been selected into
// a device context (for error checking)
wxMemoryDC *mask_cache; // the cached mask
Bool selectedIntoDC;
wxGLConfig *gl_cfg;
@ -188,6 +190,8 @@ class wxBitmap: public wxObject
void SetGLConfig(wxGLConfig *gl_cfg);
wxGLConfig *GetGLConfig(void);
void ReleaseCachedMask();
};
// 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;
wxWnd *wnd = NULL;
if (flush_cache)
ReleaseSelectedCache();
if (canvas) wnd = (wxWnd *)canvas->handle;
if (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()
{
if (!wx_gl) {
@ -385,7 +419,7 @@ void wxDC::SetClippingRegion(wxRegion *c)
if (clipping)
clipping->locked++;
dc = ThisDC();
dc = ThisDC(FALSE);
if (dc) DoClipping(dc);
DoneDC(dc);
}
@ -420,7 +454,7 @@ Bool wxDC::CanGetTextExtent(void)
HDC dc;
Bool tok;
dc = ThisDC();
dc = ThisDC(FALSE);
// What sort of display is it?
@ -518,7 +552,7 @@ void wxDC::ReleaseGraphics(HDC given_dc)
if (given_dc)
dc = given_dc;
else
dc = ThisDC();
dc = ThisDC(FALSE);
if (dc) {
DoClipping(dc);
if (!given_dc)
@ -540,7 +574,7 @@ void wxDC::OnCalcScroll(void)
ReleaseGraphics();
if (clipping) {
HDC dc;
dc = ThisDC();
dc = ThisDC(FALSE);
DoClipping(dc);
DoneDC(dc);
}
@ -620,7 +654,7 @@ Bool wxDC::GlyphAvailable(int c, wxFont *f)
if (!f)
f = font;
dc = ThisDC();
dc = ThisDC(FALSE);
if (!dc) return 0;
r = f->GlyphAvailable(c, dc, screen_font);
@ -637,7 +671,7 @@ Bool wxDC::GetPixel(double x, double y, wxColour *col)
HDC dc;
COLORREF pixelcolor;
dc = ThisDC();
dc = ThisDC(FALSE);
if (!dc) return FALSE;
@ -1473,7 +1507,7 @@ void wxDC::SetFont(wxFont *the_font)
{
HDC dc;
dc = ThisDC();
dc = ThisDC(FALSE);
if (!dc) return;
font = the_font;
@ -1883,7 +1917,7 @@ void wxDC::SetBackground(wxColour *c)
}
#endif
dc = ThisDC();
dc = ThisDC(FALSE);
new_color = c->pixel;
if (new_color != cur_bk || dc != cur_dc) {
@ -2067,7 +2101,7 @@ double wxDC::GetCharHeight(void)
TEXTMETRIC lpTextMetric;
HDC dc;
dc = ThisDC();
dc = ThisDC(FALSE);
if (!dc) return 10;
@ -2083,7 +2117,7 @@ double wxDC::GetCharWidth(void)
TEXTMETRIC lpTextMetric;
HDC dc;
dc = ThisDC();
dc = ThisDC(FALSE);
if (!dc) return 5;
@ -2121,7 +2155,7 @@ void wxDC::GetTextExtent(const char *string, double *x, double *y,
fam = theFont->GetFamily();
dc = ThisDC();
dc = ThisDC(FALSE);
ReleaseGraphics(dc);
@ -2186,7 +2220,7 @@ void wxDC::ResetMapMode(HDC given_dc)
if (given_dc)
dc = given_dc;
else {
dc = ThisDC();
dc = ThisDC(FALSE);
if (!dc) return;
}
@ -2415,10 +2449,10 @@ Bool wxDC::Blit(double xdest, double ydest, double width, double height,
sel = (wxMemoryDC *)source->selectedInto;
if (sel) {
sel->SetScaleMode(wxWX_SCALE);
dc_src = sel->ThisDC();
dc_src = sel->ThisDC(FALSE);
} else {
blit_dc->SelectObject(source);
dc_src = blit_dc->ThisDC();
dc_src = blit_dc->ThisDC(FALSE);
}
if (!dc_src) {
@ -2443,7 +2477,7 @@ Bool wxDC::Blit(double xdest, double ydest, double width, double height,
msel = (wxMemoryDC *)mask->selectedInto;
if (msel) {
msel->SetScaleMode(wxWX_SCALE);
mdc = msel->ThisDC();
mdc = msel->ThisDC(FALSE);
} else {
if (!blit_mdc) {
wxREGGLOB(blit_mdc);
@ -2451,119 +2485,146 @@ Bool wxDC::Blit(double xdest, double ydest, double width, double height,
}
blit_mdc->SelectObject(mask);
mdc = blit_mdc->ThisDC();
mdc = blit_mdc->ThisDC(FALSE);
}
}
mono_src = (source->GetDepth() == 1);
invented = new wxBitmap(iw, ih, mono_src);
if (invented->Ok()) {
GC_CAN_IGNORE void *pBits = NULL; /* set with use_alpha... */
if (mask->mask_cache
&& (mask->mask_cache == source->mask_cache)
&& (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 (!tried_ab) {
HMODULE mod;
mod = LoadLibrary("Msimg32.dll");
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. :) */
}
} else {
invented = new wxBitmap(iw, ih, mono_src);
if (invented->Ok()) {
GC_CAN_IGNORE void *pBits = NULL; /* set with use_alpha... */
if (use_alpha) {
pBits = invented->ChangeToDIBSection();
if (!pBits) {
use_alpha = 0;
/* half-failure... act like AlphaBlend isn't there */
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)
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) {
/* "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;
pBits = invented->ChangeToDIBSection();
if (!pBits) {
use_alpha = 0;
/* half-failure... act like AlphaBlend isn't there */
}
}
} 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) {
/* Failed */
if (msel) {
msel->DoneDC(mdc);
} else {
blit_mdc->DoneDC(mdc);
blit_mdc->SelectObject(NULL);
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) {
/* "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) {
sel->DoneDC(dc_src);
} else {
blit_dc->DoneDC(dc_src);
blit_dc->SelectObject(NULL);
if (!invented_memdc) {
/* Failed */
if (msel) {
msel->DoneDC(mdc);
} 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) {
invented_memdc->DoneDC(invented_dc);
invented_memdc->SelectObject(NULL);
DELETE_OBJ invented_memdc;
DELETE_OBJ invented;
/* If invented, then cached, so don't delete here. */
if (invented) {
invented_memdc->DoneDC(invented_dc);
invented_memdc->SelectObject(NULL);
DELETE_OBJ invented_memdc;
DELETE_OBJ invented;
}
}
return success;
@ -2672,7 +2736,7 @@ void wxDC::GetSize(double *width, double *height)
HDC dc;
int w, h;
dc = ThisDC();
dc = ThisDC(FALSE);
if (!dc) {
*width = *height = 0;
@ -2692,7 +2756,7 @@ void wxDC::GetSizeMM(double *width, double *height)
HDC dc;
int w, h;
dc = ThisDC();
dc = ThisDC(FALSE);
if (!dc) {
*width = *height = 0;
@ -2755,7 +2819,7 @@ void wxCanvasDC::TryColour(wxColour *src, wxColour *dest)
HDC dc;
int r, gr, b;
dc = ThisDC();
dc = ThisDC(FALSE);
if (!dc) {
dest->Set(0, 0, 0);
return;

View File

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