// This is a part of the Microsoft Foundation Classes C++ library. // Copyright (C) 1992-1998 Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Microsoft Foundation Classes Reference and related // electronic documentation provided with the library. // See these sources for detailed information regarding the // Microsoft Foundation Classes product. #include "stdafx.h" #ifdef AFX_PRINT_SEG #pragma code_seg(AFX_PRINT_SEG) #endif #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define new DEBUG_NEW ///////////////////////////////////////////////////////////////////////////// // CMetaFileDC CMetaFileDC::CMetaFileDC() { } void CMetaFileDC::SetOutputDC(HDC) { TRACE0("Must use Create() or Get() to set Metafile Output DC.\n"); ASSERT(FALSE); } void CMetaFileDC::ReleaseOutputDC() { TRACE0("Must use Close() to release output Metafile DC.\n"); ASSERT(FALSE); } void CMetaFileDC::SetAttribDC(HDC hDC) // Set the Attribute DC { if (hDC != m_hDC) CDC::SetAttribDC(hDC); if (m_hDC == m_hAttribDC) // if we somehow got to this, correct it ReleaseAttribDC(); } CMetaFileDC::~CMetaFileDC() { if (m_hDC != NULL) // Must be not wanting to keep the metafile { TRACE0("Warning! Destroying CMetaFileDC without closing.\n"); HMETAFILE hmfTemp = Close(); ::DeleteMetaFile(hmfTemp); } } ///////////////////////////////////////////////////////////////////////////// // Device-Context Functions // Clipping Functions // Normally both Set and Get clipping functions go directly to the output DC // With metafiles, we must mirror to both DCs and ask the Attribute DC for // the Get. int CMetaFileDC::GetClipBox(LPRECT lpRect) const { ASSERT(m_hAttribDC != NULL); ASSERT(lpRect != NULL); ASSERT(AfxIsValidAddress(lpRect, sizeof(RECT))); return ::GetClipBox(m_hAttribDC, lpRect); } BOOL CMetaFileDC::PtVisible(int x, int y) const { ASSERT(m_hAttribDC != NULL); return ::PtVisible(m_hAttribDC, x, y); } BOOL CMetaFileDC::RectVisible(LPCRECT) const { ASSERT(m_hAttribDC != NULL); return TRUE; // rect is always visible for metafiles } // Text Functions BOOL CMetaFileDC::TextOut(int x, int y, LPCTSTR lpszString, int nCount) { ASSERT(m_hDC != NULL); ASSERT(m_hDC != m_hAttribDC); ASSERT(lpszString != NULL); ASSERT(AfxIsValidAddress(lpszString, nCount, FALSE)); BOOL bSuccess = ::TextOut(m_hDC, x, y, lpszString, nCount); if (bSuccess && m_hAttribDC != NULL && (GetTextAlign() & TA_UPDATECP)) { CSize size = GetTextExtent(lpszString, nCount); TEXTMETRIC tm; GetTextMetrics(&tm); AdjustCP(size.cx - tm.tmOverhang); } return bSuccess; } BOOL CMetaFileDC::ExtTextOut(int x, int y, UINT nOptions, LPCRECT lpRect, LPCTSTR lpszString, UINT nCount, LPINT lpDxWidths) { ASSERT(m_hDC != NULL); ASSERT(m_hDC != m_hAttribDC); ASSERT(lpszString != NULL); ASSERT(lpDxWidths == NULL || AfxIsValidAddress(lpDxWidths, sizeof(int) * nCount, FALSE)); ASSERT(AfxIsValidAddress(lpszString, nCount, FALSE)); BOOL bSuccess = ::ExtTextOut(m_hDC, x, y, nOptions, lpRect, lpszString, nCount, lpDxWidths); if (bSuccess && m_hAttribDC != NULL && (GetTextAlign() & TA_UPDATECP)) { int nWidth = 0; for (UINT i = 0; i < nCount; i++) nWidth += *lpDxWidths++; AdjustCP(nWidth); } return bSuccess; } CSize CMetaFileDC::TabbedTextOut(int x, int y, LPCTSTR lpszString, int nCount, int nTabPositions, LPINT lpnTabStopPositions, int nTabOrigin) { ASSERT(m_hDC != NULL); ASSERT(m_hAttribDC != NULL); ASSERT(m_hDC != m_hAttribDC); ASSERT(lpszString != NULL); ASSERT(AfxIsValidAddress(lpszString, nCount, FALSE)); int xStart = x; CSize size; int cxTabStop = 0; int cxDefaultTab = (int)LOWORD( ::GetTabbedTextExtentA(m_hAttribDC, "\t", 1, 0, NULL)); if (!lpnTabStopPositions) { // no tab stops given, use default tab stop cxTabStop = cxDefaultTab; } else if (nTabPositions == 1) { // one tab stop given, use it instead of default tab stop cxTabStop = lpnTabStopPositions[0]; if (cxTabStop == 0) cxTabStop = 1; } // write the string out in tab delimited runs while (nCount != 0) { // find next tab character LPCTSTR lpszTab = lpszString; while (nCount != 0 && *lpszTab != '\t') { if (_istlead(*lpszTab)) ++lpszTab, --nCount; ++lpszTab; --nCount; } // write the string int nChars = lpszTab - lpszString; ::TextOut(m_hDC, x, y, lpszString, nChars); // advance by its extent CSize size; ::GetTextExtentPoint32(m_hAttribDC, lpszString, nChars, &size); x += size.cx; // advance current x co-ordinate based on tab stops if (nCount != 0) { ASSERT(*lpszTab == '\t'); lpszString = lpszTab + 1; // skip over the tab --nCount; // calculate next x position based on tab stops if (cxTabStop == 0) { for (int i = 0; i < nTabPositions; i++) { if (x < lpnTabStopPositions[i]+nTabOrigin) { x = lpnTabStopPositions[i]+nTabOrigin; break; } } if (i == nTabPositions) { // when all out of tab stops, go back to default tab stops cxTabStop = cxDefaultTab; } } if (cxTabStop != 0) { // advance based on single tab stop x = ((x - nTabOrigin) / cxTabStop) * cxTabStop + cxTabStop + nTabOrigin; } } } // adjust the current position if (m_hAttribDC != NULL && (GetTextAlign() & TA_UPDATECP)) { TEXTMETRIC tm; GetTextMetrics(&tm); AdjustCP(x - xStart - tm.tmOverhang); } // return the extent size.cx = x - xStart; return size; } void CMetaFileDC::AdjustCP(int cx) { if (m_hAttribDC == NULL) return; // do nothing UINT nAlign = GetTextAlign() & (TA_LEFT|TA_CENTER|TA_RIGHT); if (nAlign == TA_CENTER) return; // Center Alignment does not affect CP if (nAlign == TA_RIGHT) cx = -cx; CPoint point = GetCurrentPosition(); point.x += cx; ::MoveToEx(m_hAttribDC, point.x, point.y, NULL); } int CMetaFileDC::DrawText(LPCTSTR lpszString, int nCount, LPRECT lpRect, UINT nFormat) { ASSERT(m_hDC != NULL); ASSERT(m_hDC != m_hAttribDC); ASSERT(lpszString != NULL); ASSERT(lpRect != NULL); ASSERT(AfxIsValidAddress(lpRect, sizeof(RECT))); ASSERT(nCount == -1 || AfxIsValidAddress(lpszString, nCount, FALSE)); int nHeight = ::DrawText(m_hDC, lpszString, nCount, lpRect, nFormat); // If adjusting CP: if (m_hAttribDC != NULL && (GetTextAlign() & TA_UPDATECP) && ((nFormat & DT_CALCRECT) == 0)) { CRect rect(lpRect->left, lpRect->top, lpRect->right, lpRect->bottom); nHeight = ::DrawText(m_hAttribDC, lpszString, nCount, &rect, nFormat | DT_CALCRECT | DT_SINGLELINE); AdjustCP(rect.Width()); } return nHeight; } // Printer Escape Functions int CMetaFileDC::Escape(int nEscape, int nCount, LPCSTR lpszInData, LPVOID lpOutData) { ASSERT(m_hDC != NULL); ASSERT(m_hDC != m_hAttribDC); int nRet = ::Escape(m_hDC, nEscape, nCount, lpszInData, lpOutData); if (m_hAttribDC == NULL) return nRet; // The tact here is to NOT allow any of the document control escapes // to be passed through. Elimination of StartDoc and EndDoc should // eliminate anything actually going to the printer. Also anything // that actually draws something will be filtered. // switch (nEscape) { case NEXTBAND: case SETCOLORTABLE: case GETCOLORTABLE: case FLUSHOUTPUT: case DRAFTMODE: case QUERYESCSUPPORT: case GETPHYSPAGESIZE: case GETPRINTINGOFFSET: case GETSCALINGFACTOR: case GETPENWIDTH: case SETCOPYCOUNT: case SELECTPAPERSOURCE: case GETTECHNOLOGY: case SETLINECAP: case SETLINEJOIN: case SETMITERLIMIT: case BANDINFO: case GETVECTORPENSIZE: case GETVECTORBRUSHSIZE: case ENABLEDUPLEX: case GETSETPAPERBINS: case GETSETPRINTORIENT: case ENUMPAPERBINS: case SETDIBSCALING: case ENUMPAPERMETRICS: case GETSETPAPERMETRICS: case GETEXTENDEDTEXTMETRICS: case GETEXTENTTABLE: case GETPAIRKERNTABLE: case GETTRACKKERNTABLE: case ENABLERELATIVEWIDTHS: case ENABLEPAIRKERNING: case SETKERNTRACK: case SETALLJUSTVALUES: case SETCHARSET: case SET_BACKGROUND_COLOR: case SET_SCREEN_ANGLE: case SET_SPREAD: return ::Escape(m_hAttribDC, nEscape, nCount, lpszInData, lpOutData); default: break; // return output DC return value } return nRet; } // Viewport origin and Viewport extent overrides // (usually, don't modify viewport orgin and extent on the output dc) CPoint CMetaFileDC::SetViewportOrg(int x, int y) { ASSERT(m_hDC != NULL); CPoint point; if (m_hAttribDC == NULL) ::SetViewportOrgEx(m_hDC, x, y, &point); else ::SetViewportOrgEx(m_hAttribDC, x, y, &point); return point; } CPoint CMetaFileDC::OffsetViewportOrg(int nWidth, int nHeight) { ASSERT(m_hDC != NULL); CPoint point; if (m_hAttribDC == NULL) ::OffsetViewportOrgEx(m_hDC, nWidth, nHeight, &point); else ::OffsetViewportOrgEx(m_hAttribDC, nWidth, nHeight, &point); return point; } CSize CMetaFileDC::SetViewportExt(int x, int y) { ASSERT(m_hDC != NULL); CSize size; if (m_hAttribDC == NULL) ::SetViewportExtEx(m_hDC, x, y, &size); else ::SetViewportExtEx(m_hAttribDC, x, y, &size); return size; } CSize CMetaFileDC::ScaleViewportExt(int xNum, int xDenom, int yNum, int yDenom) { ASSERT(m_hDC != NULL); CSize size; if (m_hAttribDC == NULL) ::ScaleViewportExtEx(m_hDC, xNum, xDenom, yNum, yDenom, &size); else ::ScaleViewportExtEx(m_hAttribDC, xNum, xDenom, yNum, yDenom, &size); return size; } #ifdef AFX_INIT_SEG #pragma code_seg(AFX_INIT_SEG) #endif IMPLEMENT_DYNAMIC(CMetaFileDC, CDC) /////////////////////////////////////////////////////////////////////////////