You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

205 lines
5.5 KiB
C++

#include "StdAfx.h"
#include "QBufferDC.h"
#ifdef _DEBUG
// #define DEBUG_QBUFFERDC // Uncomment this if you want to see debugging info.
#endif
using namespace NItem;
QBufferDC::QBufferDC(CDC * pDC, DWORD dwRopCode /* = SRCCOPY */)
: m_pDC(pDC)
, m_pOldBitmap(NULL)
, m_RopCode(dwRopCode)
{
if (! pDC) return;
ASSERT_VALID(pDC);
if (pDC->IsPrinting())
{
// Do not use a bitmap when printing. There is nothing to gain.
if (pDC->m_hDC != pDC->m_hAttribDC) // Print Preview
{
// This is a hack. In debug mode, Print Preview yields an assert,
// stating: "Cannot Release Output hDC on Attached CDC."
// Although I have not found any nasty consequences, up till now,
// simply setting the handles in stead of attaching seems to work.
m_hDC = pDC->m_hDC;
m_hAttribDC = pDC->m_hAttribDC;
}
else VERIFY(Attach(pDC->Detach())); // Attach this to the mother DC's handle,
// so this in effect becomes a 'normal' DC.
return;
}
// Get the clipping boundary of the mother DC, in logical coordinates
CRect rcClip;
VERIFY(pDC->GetClipBox(rcClip) != ERROR);
// Transform to device coordinates (pixels), and normalize
pDC->LPtoDP(rcClip);
rcClip.NormalizeRect();
if (m_BufferBitmap.ReserveBitmap(pDC, rcClip.Size()))
{
// Create a compatible DC
VERIFY(CreateCompatibleDC(pDC));
// Select the bitmap in it
ASSERT(m_pOldBitmap == 0);
m_pOldBitmap = (CBitmap *) SelectObject(& m_BufferBitmap.m_Bitmap);
// Copy the mapping settings
int mapmode = pDC->GetMapMode();
SetMapMode(mapmode);
SetWindowOrg(pDC->GetWindowOrg());
SetViewportOrg(pDC->GetViewportOrg());
if (mapmode > MM_MAX_FIXEDSCALE)
{
// These are only relevant to MM_ISOTROPIC and MM_ANISOTROPIC
SetWindowExt(pDC->GetWindowExt());
SetViewportExt(pDC->GetViewportExt());
}
// Fill the clipping boundary with pDC's background color
COLORREF col = pDC->GetBkColor();
#ifdef QBUFFER_DEMO
// In demo mode, change the color slightly so we can see which parts are updated
if (m_bDemoMode) col ^= RGB(rand() % 32, rand() % 32, rand() % 32);
#endif
// Get the mother DC's clipping boundary in logical coordinates
// and fill it.
VERIFY(pDC->GetClipBox(rcClip) != ERROR);
rcClip.NormalizeRect();
if (mapmode != MM_TEXT)
{
// Other mapping modes may lead to roundof errors, causing artefacts
// on the screen. To compensate, we inflate the bounding rectangle
// with two pixels.
CSize szPixels(2, 2);
DPtoLP(& szPixels);
rcClip.InflateRect(szPixels.cx, szPixels.cy);
}
FillSolidRect(rcClip, col);
// Initialize accumulation of boundary information
SetBoundsRect(NULL, DCB_ENABLE | DCB_ACCUMULATE | DCB_RESET);
}
else // We don't have a bitmap
{
#ifdef DEBUG_QBUFFERDC
afxDump << _T("We can't make a bitmap\n");
#endif
// Attach this to the mother DC's handle, so this in effect becomes a 'normal' DC.
VERIFY(Attach(pDC->Detach()));
}
}
QBufferDC::~QBufferDC(void)
{
if (!m_pDC) return;
if (m_pDC->IsPrinting() && m_pDC->m_hDC != m_pDC->m_hAttribDC) return;
// Nothing to do if Print Previewing. See remarks in constructor code.
if (m_BufferBitmap.IsValid() && !m_pDC->IsPrinting())
// We have a bitmap, and we are not printing.
{
// We only have to bitblt what is inside the accumulated bounding rectangle.
CRect rcBounds;
GetBoundsRect(rcBounds, DCB_RESET);
rcBounds.NormalizeRect();
#ifdef DEBUG_QBUFFERDC
afxDump << _T("Bounding rectangle: ") << rcBounds << _T("\n");
#endif
// No point in bitblt'ing anything outside the clipping box
CRect rcClip;
m_pDC->GetClipBox(rcClip);
rcClip.NormalizeRect();
// So intersect it with the bounding rectangle.
rcBounds &= rcClip;
#ifdef DEBUG_QBUFFERDC
afxDump << _T(" after clipping: ") << rcBounds
<< _T("\n clipping rectangle: ") << rcClip << _T("\n");
#endif
if (! rcBounds.IsRectEmpty())
{
if (GetMapMode() != MM_TEXT)
{
// Other mapping modes may lead to roundof errors, causing artefacts
// on the screen. To compensate, we inflate the bounding rectangle
// with two pixels.
CSize szPixels(2, 2);
DPtoLP(& szPixels);
rcBounds.InflateRect(szPixels.cx, szPixels.cy);
}
// BitBlt the important part of the bitmap to the screen
VERIFY(m_pDC->BitBlt(
rcBounds.left, rcBounds.top,
rcBounds.Width(), rcBounds.Height(),
this,
rcBounds.left, rcBounds.top,
m_RopCode));
}
// Clean up, deselect the bitmap.
if (m_pOldBitmap) SelectObject(m_pOldBitmap);
}
else // We don't have a bitmap, or we are printing.
{
// Detach from the mother's DC handle, and reattach to the mother
VERIFY(m_pDC->Attach(Detach()));
}
}
BOOL QBufferDC::BufferBitmap::ReserveBitmap(CDC * pDC, CSize sz)
{
if (IsValid()) // We have a bitmap
{
BITMAP bm;
m_Bitmap.GetBitmap(& bm);
#ifdef DEBUG_QBUFFERDC
afxDump << _T("We already have a bitmap, size: ") << CSize(bm.bmWidth, bm.bmHeight) << _T("\n");
#endif
// Compare the bitmap size (in pixels) with the requested size (also in pixels)
if (sz.cx > bm.bmWidth || sz.cy > bm.bmHeight)
{
// If the bitmap is too small, delete it; handle will be set to zero
m_Bitmap.DeleteObject();
#ifdef DEBUG_QBUFFERDC
afxDump << _T("Too small, deleted\n");
#endif
}
else return TRUE; // Bitmap is big enough
}
// Try to create a bitmap of sufficient size
BOOL r = m_Bitmap.CreateCompatibleBitmap(pDC, sz.cx, sz.cy);
#ifdef DEBUG_QBUFFERDC
afxDump << _T("Tried to create a bitmap, size: ") << sz
<< (r ? _T(" - succeeded\n") : _T(" - failed\n"));
#endif
return r;
}
QBufferDC::BufferBitmap QBufferDC::m_BufferBitmap;
#ifdef QBUFFER_DEMO
BOOL QBufferDC::m_bDemoMode = TRUE;
#endif