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++
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
|