gecko-dev/cmd/winfe/cxprint.cpp

2460 lines
76 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "stdafx.h"
#include "cxprint.h"
#include "apipage.h" // page setup api
#include "netsvw.h"
#include "npapi.h"
#include "np.h"
#include "feimage.h"
#include "il_icons.h"
#include "netsprnt.h"
#include "cntritem.h"
#include "intl_csi.h"
#include "prefapi.h"
BOOL CPrintCX::m_bGlobalBlockDisplay = FALSE;
// A callback function from the print manager.
// See CDC::SetAbortProc for more information
BOOL CALLBACK EXPORT PrintAbortProc(HDC hDC, int iStatus) {
// See if we've cancelled..... Only we can't.
// This wasn't designed apparently to handle more than one print job per app
// at a time.
// Turn off display for a moment in all print contexts.
// This keeps us from going re-etrant into GDI.
BOOL bOldBlock = CPrintCX::m_bGlobalBlockDisplay;
CPrintCX::m_bGlobalBlockDisplay = TRUE;
// Here we shove all messages on through.
MSG msg;
while(::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE)) {
if(!theApp.NSPumpMessage()) {
// Restore display flag.
CPrintCX::m_bGlobalBlockDisplay = bOldBlock;
// Get out if WM_QUIT received.
return(FALSE);
}
}
// Restore display flag.
CPrintCX::m_bGlobalBlockDisplay = bOldBlock;
// Just continue printing.
return(TRUE);
}
extern "C" void FE_Print(const char *pUrl) {
CPrintCX::AutomatedPrint(pUrl, NULL, NULL, NULL);
}
// Print with no user intervention.
// Null on an argument means default.
void CPrintCX::AutomatedPrint(const char *pDocument, const char *pPrinter, const char *pDriver, const char *pPort) {
TRACE("Automated Print job starting (%s, %s, %s, %s)\n", pDocument, pPrinter, pDriver, pPort);
// Our document is probably local or a shortcut, convert to something networthy.
CString csUrl;
WFE_ConvertFile2Url(csUrl, pDocument);
// Create the actual URL struct.
URL_Struct *pUrl = NET_CreateURLStruct(csUrl, NET_DONT_RELOAD);
if(pUrl == NULL) {
return;
}
// Create a new print job.
CPrintCX *pPrint = new CPrintCX(pUrl);
// Set up the print job.
// Here, basically we need to do the necessary work that AFX
// normally does to generate a proper print DC.
pPrint->m_pcpiPrintJob = new CPrintInfo;
// Wether or not we'll actually continue with this.
BOOL bFailure = FALSE;
// Do the print setup process by manually fetching the DC.
TRY {
// Are we attempting the default printer or do we already know which printer.
if(pPrinter == NULL || pDriver == NULL || pPort == NULL) {
// Use a default, if we can figure one out.
if (!theApp.GetPrinterDeviceDefaults(&pPrint->m_pcpiPrintJob->m_pPD->m_pd)) {
AfxThrowResourceException();
}
if (pPrint->m_pcpiPrintJob->m_pPD->m_pd.hDC == NULL) {
// call CreatePrinterDC if DC was not created by above
if (pPrint->m_pcpiPrintJob->m_pPD->CreatePrinterDC() == NULL) {
AfxThrowResourceException();
}
pPrint->m_hdcPrint = pPrint->m_pcpiPrintJob->m_pPD->m_pd.hDC;
}
}
else {
if(!(pPrint->m_hdcPrint = ::CreateDC(pDriver, pPrinter, pPort, NULL))) {
AfxThrowResourceException();
}
}
// Set up the DC and print info.
pPrint->m_pcpiPrintJob->m_pPD->m_pd.nFromPage = 1;
pPrint->m_pcpiPrintJob->m_pPD->m_pd.nToPage = (unsigned short)-1;
pPrint->m_pcpiPrintJob->m_pPD->m_pd.nCopies = 1;
}
CATCH(CException, e) {
// View went away while print dialog was up and caused a GPF.
// This isn't an elegant fix.
bFailure = TRUE;
}
END_CATCH
if(bFailure) {
// We're not going to be printing, user hit cancel.
pPrint->DestroyContext();
NET_FreeURLStruct(pUrl);
return;
}
// Gleen relevant information from the CDC and the CPrintInfo.
pPrint->Initialize(FALSE);
// Ready to split off and do the print job.
pPrint->CommencePrinting(pUrl);
// We leave the context all alone, it will eventually destroy
// itself when the print job is completed.
}
void CPrintCX::PrintAnchorObject(URL_Struct *pUrl, CView *pView, SHIST_SavedData *pSavedData, char *pDisplayUrl) {
// Purpose: Indirect constructor for CPrintCX objects.
// Arguments: pUrl The URL to print.
// pView The view originating the print request.
// pSavedData The form element data we should copy.
// Returns: void
// Comments: This function effectively takes a print job and moves
// it outside of the view by putting it into a new
// context.
// Revision History:
// 05-27-95 created GAB
// Create a new print job.
CPrintCX *pPrint = new CPrintCX(pUrl, pSavedData, pDisplayUrl);
// Set up the print job.
pPrint->m_pcpiPrintJob = new CPrintInfo;
// Wether or not we'll actually continue with this.
BOOL bFailure = FALSE;
// Do the normal print setup process thorugh a print dialog.
int iCLSID;
NPEmbeddedApp *pPlugins;
TRY {
// CACHE some info while we're safe with the view going away.
MWContext *pViewContext = ((CNetscapeView*)pView)->GetContext()->GetContext();
// The mfc print dlg code uses our hidden frame for the owner. The owner should
// be the active frame (or one of its popups). Otherwise the frame is not disabled,
// effectively removing the modal aspect of the dialog.
CWnd *pSaveWnd = theApp.m_pActiveWnd;
theApp.m_pActiveWnd = CWnd::GetActiveWindow();
if(pView->DoPreparePrinting(pPrint->m_pcpiPrintJob) == FALSE) {
bFailure = TRUE;
}
else if(pPrint->m_pcpiPrintJob->m_pPD == NULL ||
pPrint->m_pcpiPrintJob->m_pPD->m_pd.hDC == NULL) {
// Whoa! DoPreparePrinting succeeded, but there is no DC???
// This happens when a printer driver is installed for a network
// printer (like a NetWare printer), and the user is not
// logged into that network.
// Give the user some type of error....
theApp.m_pActiveWnd = pSaveWnd;
CString temp;
temp.LoadString(IDS_CANTPRINT_LOGIN);
FE_Alert(pViewContext, temp);
bFailure = TRUE;
}
theApp.m_pActiveWnd = pSaveWnd;
// If the context is no longer in the list of contexts, get out as the view is gone.
if(XP_IsContextInList(pViewContext)) {
iCLSID = INTL_DefaultDocCharSetID(pViewContext);
pPlugins = ((CNetscapeView*)pView)->GetContext()->GetContext()->pluginList;
}
else {
// Fail now, the view is gone.
bFailure = TRUE;
}
}
CATCH(CException, e) {
// View went away while print dialog was up and caused a GPF.
// This isn't an elegant fix.
bFailure = TRUE;
}
END_CATCH
if(bFailure) {
// We're not going to be printing, user hit cancel.
pPrint->DestroyContext();
NET_FreeURLStruct(pUrl);
return;
}
// Set up the DC.
pPrint->m_hdcPrint = pPrint->m_pcpiPrintJob->m_pPD->m_pd.hDC;
// Gleen relevant information from the CDC and the CPrintInfo.
pPrint->Initialize(FALSE);
// Pass old document charset id to print context
// This will make i18n converter do right thing for each context
pPrint->m_iCSID = iCLSID;
if( iCLSID != CS_LATIN1)
{
INTL_CharSetInfo print_csi = LO_GetDocumentCharacterSetInfo(pPrint->GetContext());
INTL_SetCSIDocCSID(print_csi, iCLSID);
INTL_SetCSIWinCSID(print_csi, INTL_DocToWinCharSetID(iCLSID));
}
// Ready to split off and do the print job.
pPrint->CommencePrinting(pUrl);
// We leave the context all alone, it will eventually destroy
// itself when the print job is completed.
}
void CPrintCX::PreviewAnchorObject(CPrintCX *& pPreview, URL_Struct *pUrl, CView *pView, CDC *pDC,
CPrintInfo *pInfo, SHIST_SavedData *pSavedData, char *pDisplayUrl)
{
// Purpose: Indirect constructor for CPrintCX objects doing preview.
// Arguments: pPreview A reference to a pointer which will will assign in the
// context just prior to the network load.
// pAnchor The URL to print.
// pHist The history entry of the print job in the other context.
// pView The view originating the print request.
// pDC The DC of the preview (we don't use our own).
// pInfo The print job information.
// pSavedData Form element data we should copy.
// Returns: CPrintCX The print context doing the preview (we won't
// be destroying ourselves, they will be destroying us).
// Comments: This function effectively takes a print job and moves
// it outside of the view by putting it into a new
// context.
// pPreview is needed as a reference and not a retval since assignment
// of the variable needs to happen before we return (reentrancy
// problems in the calling function avoidance).
// Revision History:
// 06-14-95 created GAB
// Create a new print job.
CPrintCX *pPrint = new CPrintCX(pUrl, pSavedData, pDisplayUrl);
// Set up the print job.
pPrint->m_bPreview = TRUE;
pPrint->m_previewDC = pDC;
pPrint->m_pcpiPrintJob = pInfo;
// Set our preview view.
pPrint->m_pPreviewView = pView;
// Get information from the CDC and CPrintInfo.
pPrint->Initialize(FALSE);
// Assign what used to be the return value before we actually do the load
// from the network.
// We leave the context all alone, it will eventually get destroyed
// by those which created us.
pPreview = pPrint;
// Pass old document charset id to print context
// This will make i18n converter do right thing for each context
MWContext *context = ((CNetscapeView*)pView)->GetContext()->GetContext();
pPrint->m_iCSID = INTL_DefaultDocCharSetID(context);
if( pPrint->m_iCSID != CS_LATIN1)
{
INTL_CharSetInfo view_csi = LO_GetDocumentCharacterSetInfo(context);
INTL_CharSetInfo print_csi = LO_GetDocumentCharacterSetInfo(pPrint->GetContext());
INTL_SetCSIDocCSID(print_csi, INTL_GetCSIDocCSID(view_csi));
INTL_SetCSIWinCSID(print_csi, INTL_GetCSIWinCSID(view_csi));
}
pPrint->CommencePrinting(pUrl);
}
void CPrintCX::ScreenToPrint(POINT* point, int num)
{
POINT *tp = point;
for (int i = 0; i < num; i++, tp++) {
tp->x = tp->x * (printRes.cx / screenRes.cx);
tp->y = tp->y * (printRes.cy / screenRes.cy);
}
}
CPrintCX::CPrintCX(URL_Struct *pUrl, SHIST_SavedData *pSavedData, char *pDisplayUrl) {
// Purpose: Construct a context for printing.
// Arguments: pAnchor The anchor we're printing
// pSavedData The form data we want to copy to the print context.
// pDisplayUrl The URL text to display in header/footer
// Returns: none
// Comments: Sets the context type, etc.
// Revision History:
// 05-27-95 created GAB
TRACE("Creating CPrintCX %p\n", this);
// Clear URL position.
// If we don't, when the page is scrolled we can't print -- weird.
// Do not handle named anchors (strip them out), same reasons.
if(pUrl) {
pUrl->position_tag = 0;
if(pUrl->address) {
if(strrchr(pUrl->address, '#')) {
*strrchr(pUrl->address, '#') = '\0';
}
}
}
// this is a hack to save the layout data for embedlist. For embed layout will
// make a copy of the pSavedData. We need to free the memory here.
m_embedList = (lo_SavedEmbedListData*)pUrl->savedData.EmbedList;
m_cxType = Print;
GetContext()->type = MWContextPrint;
m_hdcPrint = NULL;
m_pcpiPrintJob = NULL;
p_TimeOut = NULL;
// Haven't printed anything yet.
m_iLastPagePrinted = 0;
// Save the anchor we're printing; might be used in DOCINFO
int len = strlen(pUrl->address);
m_pAnchor = new char[len + 1];
XP_STRNCPY_SAFE(m_pAnchor, pUrl->address, len + 1);
#ifdef EDITOR
// This is the Url address we are want to display
// in header or footers. m_pAnchor may be a local temp file
if(pDisplayUrl && strrchr(pDisplayUrl, '#'))
{
*strrchr(pDisplayUrl, '#') = '\0';
}
m_pDisplayUrl = pDisplayUrl ? XP_STRDUP(pDisplayUrl) : NULL;
#else
m_pDisplayUrl = NULL;
#endif
// No status dialog as of yet.
m_pStatusDialog = NULL;
// User hasn't cancelled yet.
m_bCancel = FALSE;
// We start off blocking all display calls
m_iDisplayMode = BLOCK_DISPLAY;
// Are we a preview context?
m_bPreview = FALSE;
m_pPreviewView = NULL;
// Do we need to call the start doc member yet again?
m_bNeedStartDoc = TRUE;
// How we end the document, in AbortDoc or EndDoc
// Start off with aborting (no output).
m_bAbort = TRUE;
m_bAllConnectionCompleteCalled = FALSE;
m_bFinishedLayoutCalled = FALSE;
m_bFormatStarted = FALSE;
// Font used for Header and Footer, should depending on current docuemnt charset
m_hFont = NULL;
m_iFontCSID = CS_LATIN1;
m_iCSID = CS_LATIN1;
m_pDrawable = NULL;
m_lDocWidth = 0;
m_lDocHeight = 0;
m_bHandleCancel = FALSE;
// Finally, copy the form data if present.
if(pSavedData && pSavedData->FormList) {
TRACE("Cloning form data for print job.\n");
#ifdef MOZ_NGLAYOUT
ASSERT(0);
#else
LO_CloneFormData(pSavedData, GetDocumentContext(), pUrl);
#endif
}
}
CPrintCX::~CPrintCX() {
// Purpose: Destruct a print context
// Arguments: void
// Returns: none
// Comments: Clean up any printing resources allocated.
// Revision History:
// 05-27-95 created GAB
TRACE("Deleting CPrintCX %p\n", this);
if(m_pStatusDialog != NULL) {
m_pStatusDialog->DestroyWindow();
delete m_pStatusDialog;
}
if (m_hFont) {
// The font has correctly unselected itself from the DC
// in the written code in this file, such that we do
// not need to unselect it before deletion.
::DeleteObject(m_hFont);
m_hFont = NULL;
}
if(m_cplCaptured.IsEmpty() == FALSE) {
POSITION rIndex = m_cplCaptured.GetHeadPosition();
LTRB *pFreeMe;
while(rIndex != NULL) {
pFreeMe = (LTRB *)m_cplCaptured.GetNext(rIndex);
delete pFreeMe;
}
m_cplCaptured.RemoveAll();
}
if(m_cplPages.IsEmpty() == FALSE) {
POSITION rIndex = m_cplPages.GetHeadPosition();
LTRB *pFreeMe;
while(rIndex != NULL) {
pFreeMe = (LTRB *)m_cplPages.GetNext(rIndex);
delete pFreeMe;
}
m_cplPages.RemoveAll();
}
if(IsPrintPreview() == FALSE) {
// Need to release our print job information.
// If we didn't need to start a document, then we started one in some manner,
// decide how we should end it.
if(m_bNeedStartDoc == FALSE) {
if(m_bAbort == TRUE) {
::AbortDoc(m_hdcPrint);
}
else {
::EndDoc(m_hdcPrint);
}
}
if(m_hdcPrint) {
::DeleteDC(m_hdcPrint);
}
delete m_pcpiPrintJob;
}
m_hdcPrint = NULL;
m_pcpiPrintJob = NULL;
if(m_pAnchor) {
delete [] m_pAnchor;
m_pAnchor = NULL;
}
XP_FREEIF(m_pDisplayUrl);
if (m_pDrawable) {
delete m_pDrawable;
m_pDrawable = NULL;
}
// MWH - this is a hack to free the embed list that layout make copy from the original
// SavedData. I removed the freeing from lib\layout\layfree.c lo_FreeDocumentEmbedListData.
// and free the data here. This will fix an OLE printing problem. The problem is when a .doc file
// is on the net, i.e. http://....//xxx.doc. When layout free the EmbedList in
// lo_FreeDocumentEmbedListData will cause the page not printed. Since for printing we need
// to use the cached data.
if (m_embedList && (m_embedList->embed_data_list != NULL)) {
int32 i;
lo_EmbedDataElement* embed_data_list;
PA_LOCK(embed_data_list, lo_EmbedDataElement*, m_embedList->embed_data_list);
for (i=0; i < m_embedList->embed_count; i++)
{
if (embed_data_list[i].freeProc && embed_data_list[i].data)
(*(embed_data_list[i].freeProc))(GetContext(), embed_data_list[i].data);
}
PA_UNLOCK(m_embedList->embed_data_list);
PA_FREE(m_embedList->embed_data_list);
m_embedList->embed_count = 0;
m_embedList->embed_data_list = NULL;
}
if (p_TimeOut) {
FE_ClearTimeout(p_TimeOut); // kill the timer.
p_TimeOut = 0;
}
}
HDC CPrintCX::GetAttribDC()
{
HDC hRetval = NULL;
if(IsPrintPreview()) {
hRetval = m_previewDC->m_hAttribDC;
}
else {
hRetval = m_hdcPrint;
}
return(hRetval);
}
void CPrintCX::ReleaseContextDC(HDC pDC) {
// Purpose: Release a DC previously gotten through GetContextDC.
// Arguments: pDC The CDC to release.
// Returns: void
// Comments: We don't do anything here, as the CDC is static
// throughout the print job.
// Revision History:
// 05-27-95 created GAB
}
void CPrintCX::Initialize(BOOL bOwnDC, RECT *pRect, BOOL bInitialPalette, BOOL bNewMemDC) {
// Purpose: Initialize any print parameters from preferences and
// print setup.
// Arguments: void
// Returns: void
// Comments: All instance specific print parameters should be
// initialized here.
// A CDC is required to do this.
// Revision History:
// 05-30-95 created GAB
// Call the base
HDC hdc = GetContextDC();
#ifdef XP_WIN32
m_hOrgPrintDC = hdc;
m_printBk = FALSE;
m_hOffscrnDC = 0;
#endif
CDCCX::Initialize(bOwnDC, pRect, bInitialPalette, bNewMemDC);
CDC * pAttrDC;
pAttrDC = theApp.m_pMainWnd->GetDC();
if (!IsPrintPreview()) {
SetMappingMode(hdc);
m_lConvertX = GetContext()->convertPixX = 1440 / pAttrDC->GetDeviceCaps(LOGPIXELSX);
m_lConvertY = GetContext()->convertPixY = 1440 / pAttrDC->GetDeviceCaps(LOGPIXELSY);
screenRes.cx = 0; // we don't care.
screenRes.cy = 0;
printRes.cx = 0;
printRes.cy = 0;
#ifdef XP_WIN32
PREF_GetBoolPref("browser.print_background",&m_printBk);
#endif
}
else {
screenRes.cx = ::GetDeviceCaps(m_previewDC->GetSafeHdc(), LOGPIXELSX);
screenRes.cy = ::GetDeviceCaps(m_previewDC->GetSafeHdc(), LOGPIXELSY);
printRes.cx = ::GetDeviceCaps(m_previewDC->m_hAttribDC, LOGPIXELSX);
printRes.cy = ::GetDeviceCaps(m_previewDC->m_hAttribDC, LOGPIXELSY);
m_lConvertX = GetContext()->convertPixX = printRes.cx / screenRes.cx;
m_lConvertY = GetContext()->convertPixY = printRes.cy / screenRes.cy;
}
// Have our FE conversions (class local for speed) be the same.
ApiPageSetup(api,0);
// Determine and set the page size.
SIZE csPageSize;
api->GetMargins ( &m_lLeftMargin, &m_lRightMargin, &m_lTopMargin, &m_lBottomMargin );
if (!IsPrintPreview()) {
csPageSize.cx = ::GetDeviceCaps(hdc, HORZRES);
csPageSize.cy = ::GetDeviceCaps(hdc, VERTRES);
#ifdef XP_WIN32
// MWH - The calculation below is to prepare a memory DC for printing
// background. I can not use printer's resoultion to calculate the size of bitmap
// for this memoryDC, because 600 dpi * 24 bit/pixel * width * height will cause
// the bitmap to be too big. I'm going to use the screen resolution here
// to figure the size of the bitmap for my memoryDC. When it is time to
// display the bitmap. DisplayPixmap will scale the image from 96 dpi to
// 600 dpi.
if (m_printBk) {
int xres, yres;
xres = pAttrDC->GetDeviceCaps(LOGPIXELSX);
yres = pAttrDC->GetDeviceCaps(LOGPIXELSY);
int width, height;
width = (csPageSize.cx + GetDeviceCaps(hdc, LOGPIXELSX)) / GetDeviceCaps(hdc, LOGPIXELSX);
height = (csPageSize.cy + GetDeviceCaps(hdc, LOGPIXELSY)) / GetDeviceCaps(hdc, LOGPIXELSY);
m_offscrnWidth = width * xres;
m_offscrnHeight = height * yres;
m_hOffscrnDC = ::CreateCompatibleDC(pAttrDC->GetSafeHdc());
if ( m_hOffscrnDC) {
BITMAPINFO lpbmi;
lpbmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
lpbmi.bmiHeader.biWidth = m_offscrnWidth;
lpbmi.bmiHeader.biHeight = m_offscrnHeight;
lpbmi.bmiHeader.biPlanes = 1;
lpbmi.bmiHeader.biBitCount = 24;
lpbmi.bmiHeader.biCompression = BI_RGB;
lpbmi.bmiHeader.biSizeImage = 0;
lpbmi.bmiHeader.biXPelsPerMeter = 0;
lpbmi.bmiHeader.biYPelsPerMeter = 0;
lpbmi.bmiHeader.biClrUsed = 0; // default value
lpbmi.bmiHeader.biClrImportant = 0; // all important
void* ptr;
m_hOffScrnBitmap = ::CreateDIBSection(pAttrDC->GetSafeHdc(),&lpbmi, DIB_RGB_COLORS,
&ptr, NULL, NULL);
::SetMapMode(m_hOffscrnDC, MM_TEXT);
if (m_hOffScrnBitmap) {
m_saveBitmap = (HBITMAP)::SelectObject(m_hOffscrnDC, ( HGDIOBJ)m_hOffScrnBitmap );
}
else {
m_printBk = FALSE;
::DeleteDC(m_hOffscrnDC);
m_hOffscrnDC = 0;
}
}
else {// Can not display Background, just print forground instead.
m_printBk = FALSE;
}
}
#endif
::DPtoLP(hdc, (POINT*)&csPageSize, 1);
}
else {
m_lLeftMargin = (m_lLeftMargin * printRes.cx) / 1440;
m_lRightMargin = (m_lRightMargin * printRes.cx) / 1440;
m_lTopMargin = (m_lTopMargin * printRes.cy) / 1440;
m_lBottomMargin = (m_lBottomMargin * printRes.cy) / 1440;
csPageSize.cx = ::GetDeviceCaps(m_previewDC->m_hAttribDC, HORZRES);
csPageSize.cy = ::GetDeviceCaps(m_previewDC->m_hAttribDC, VERTRES);
}
theApp.m_pMainWnd->ReleaseDC(pAttrDC);
ReleaseContextDC(hdc);
m_lPageHeight = csPageSize.cy;
m_lPageWidth = csPageSize.cx;
m_lWidth = csPageSize.cx - (m_lRightMargin + m_lLeftMargin);
m_lHeight = csPageSize.cy - (m_lBottomMargin + m_lTopMargin);
CreateHeaderFooterFont();
TEXTMETRIC tm;
if(m_hFont) {
HFONT hOldFont = (HFONT)::SelectObject(hdc, m_hFont);
::GetTextMetrics(hdc, &tm);
::SelectObject(hdc, hOldFont);
}
else {
AfxMessageBox(IDS_NOPRINTERFONT);
::GetTextMetrics(hdc, &tm);
}
m_iMaxWidth = CASTINT(( m_lPageWidth / tm.tmAveCharWidth ) / 2);
// What are we doing about colors?
m_bBlackText = api->BlackText();
m_bBlackLines = api->BlackLines();
// What are we doing about drawing?
m_bSolidLines = api->SolidLines();
m_bBitmaps = TRUE;
m_bBackground = FALSE;
m_bReverseOrder = api->ReverseOrder() ? TRUE : FALSE;
// Headers and footers?
m_bNumber = api->Footer() ? TRUE : FALSE;
m_bTitle = api->Header() ? TRUE : FALSE;
}
BOOL CPrintCX::AdjustRect(LTRB& Rect)
{
LTRB orgRect(Rect);
// Adjust for margins.
Rect.left += m_lLeftMargin;
Rect.top += m_lTopMargin;
Rect.right += m_lLeftMargin;
Rect.bottom += m_lTopMargin;
// Adjust the Y coordinate for the current page we are printing.
POSITION rIndex = m_cplPages.FindIndex(m_pcpiPrintJob->m_nCurPage - 1);
if(rIndex == NULL) {
// This could be called during incremental display.
// Don't allow drawing at that point.
return(FALSE);
}
LTRB *pPage = (LTRB *)m_cplPages.GetAt(rIndex);
Rect.top -= pPage->top;
Rect.bottom -= pPage->top;
// Form a Rect of the current page, in the same coords as the element.
// The bottom of the page is determined on a page by page basis.
LTRB Page;
Page.left = m_lLeftMargin;
Page.top = m_lTopMargin;
Page.right = Page.left + pPage->Width();
Page.bottom = Page.top + pPage->Height();
// Part of this element must fall within these coordinates to be drawn.
// Clipping will take care of partial display.
if(Rect.top >= Page.bottom || Rect.bottom <= Page.top ||
Rect.right <= Page.left || Rect.left >= Page.right) {
if(CanBlockDisplay()) {
return(FALSE);
}
}
// MHW - if we are printing background image, and the current printing
// operation is to the temparary offscreen, need to addjust the rect to
// the coordinate according to the offscreen dc.
#ifdef XP_WIN32
if (m_printBk && m_hdcPrint == m_hOffscrnDC) {
orgRect.top -= pPage->top;
orgRect.bottom -= pPage->top;
Rect.left = (orgRect.left + m_lConvertX) / m_lConvertX;
Rect.top = (orgRect.top + m_lConvertY)/ m_lConvertY;
Rect.right = (orgRect.right + m_lConvertX) / m_lConvertX;
Rect.bottom = (orgRect.bottom + m_lConvertY)/ m_lConvertY;
}
#endif
return (TRUE);
}
BOOL CPrintCX::ResolveElement(LTRB& Rect, LO_FormElementStruct *pFormElement) {
CDCCX::ResolveElement(Rect, pFormElement);
return AdjustRect(Rect);
}
BOOL CPrintCX::ResolveElement(LTRB& Rect, int32 x, int32 y, int32 x_offset, int32 y_offset,
int32 width, int32 height)
{
CDCCX::ResolveElement(Rect, x, y, x_offset, y_offset, width, height);
return AdjustRect(Rect);
}
BOOL CPrintCX::ResolveElement(LTRB& Rect, NI_Pixmap *pImage, int32 lX, int32 lY,
int32 orgx, int32 orgy,
uint32 ulWidth, uint32 ulHeight,
int32 lScaleWidth, int32 lScaleHeight)
{
// Call the base first.
CDCCX::ResolveElement(Rect, pImage, lX, lY, orgx, orgy, ulWidth, ulHeight, lScaleWidth,lScaleHeight);
return AdjustRect(Rect);
}
BOOL CPrintCX::ResolveElement(LTRB& Rect, LO_EmbedStruct *pEmbed, int iLocation, Bool bWindowed) {
// Call the base first.
CDCCX::ResolveElement(Rect, pEmbed, iLocation, bWindowed);
return AdjustRect(Rect);
}
BOOL CPrintCX::ResolveLineSolid() {
return(m_bSolidLines);
}
COLORREF CPrintCX::ResolveBGColor(unsigned uRed, unsigned uGreen, unsigned uBlue) {
// See if we're allowing the background color to be set.
if(m_bBackground == FALSE) {
// Nope, set it to be white.
return(RGB(255,255,255));
}
else {
// Do the default action.
return(CDCCX::ResolveBGColor(uRed, uGreen, uBlue));
}
}
BOOL CPrintCX::ResolveHRSolid(LO_HorizRuleStruct *pHorizRule) {
// See if we're allowing 3D HRs.
if(m_bSolidLines == TRUE) {
return(TRUE);
}
else {
// Do the default.
return(CDCCX::ResolveHRSolid(pHorizRule));
}
}
void CPrintCX::ResolveTransparentColor(unsigned uRed, unsigned uGreen, unsigned uBlue) {
// See what we're doing with the background.
if(m_bBackground == FALSE) {
// Set it to white.
CDCCX::ResolveTransparentColor(255, 255, 255);
}
else {
// Set it to whatever.
CDCCX::ResolveTransparentColor(uRed, uGreen, uBlue);
}
}
COLORREF CPrintCX::ResolveDarkLineColor() {
// See if we're drawing black lines.
if(m_bBlackLines == TRUE) {
return(RGB(0,0,0));
}
else {
// Do the default.
return(CDCCX::ResolveDarkLineColor());
}
}
COLORREF CPrintCX::ResolveLightLineColor() {
// See if we're drawing black lines.
if(m_bBlackLines == TRUE) {
return(RGB(0,0,0));
}
else {
// Do the default.
return(CDCCX::ResolveLightLineColor());
}
}
COLORREF CPrintCX::ResolveBorderColor(LO_TextAttr *pAttr) {
// See if we're drawing black lines.
if(m_bBlackLines == TRUE) {
return(RGB(0,0,0));
}
else {
// Do the default.
return(CDCCX::ResolveBorderColor(pAttr));
}
}
COLORREF CPrintCX::ResolveTextColor(LO_TextAttr *pAttr) {
// If we're only printing black text, then only select the color black.
// Otherwise, simply call the base.
COLORREF rgbRetval;
if(m_bBlackText == TRUE) {
rgbRetval = RGB(0,0,0);
}
else {
rgbRetval = CDCCX::ResolveTextColor(pAttr);
}
return(rgbRetval);
}
void CPrintCX::DisplayIcon(int32 x, int32 y, int icon_number)
{
if (GetDisplayMode() == BLOCK_DISPLAY)
return;
else if (GetDisplayMode() == CAPTURE_POSITION) {
int32 lOrgX, lOrgY;
int32 width, height;
GetDrawingOrigin(&lOrgX, &lOrgY);
GetIconDimensions(&width, &height, icon_number);
width *= m_lConvertX;
height *= m_lConvertY;
// Capture the coordinates of this element.
Capture(x + lOrgX, y + lOrgY, width, height);
// We don't actually allow display while we are capturing the area.
return;
}
// Block drawing of icons if we don't allow it.
// They might be attempting to determine the size of an icon.
if(m_bBitmaps == TRUE || x != NULL || y != NULL) {
#ifdef XP_WIN32
if (m_printBk && !IsPrintPreview()) {
SubOffscreenPrintDC();
CDCCX::DisplayIcon(x, y,
icon_number);
RestorePrintDC();
}
#endif
CDCCX::DisplayIcon(x, y,
icon_number);
}
}
void CPrintCX::LayoutNewDocument(MWContext *pContext, URL_Struct *pURL, int32 *pWidth, int32 *pHeight, int32 *pmWidth, int32 *pmHeight) {
// Purpose: This formally sets up margins and such with the Layout engine.
// Arguments: pContext The context under which this is loading.
// pURL The loading URL.
// pWidth The width of the page (adjust for margins).
// pHeight The height of the page (we report this as huge)
// so that we can figure it manually later.
// pmWidth Margin width, we report as 0.
// pmHeight Margin height, we report as 0.
// Returns: void
// Comments: The origin of the print job must always remain 0,0 for this
// to work correctly.
// It is important to note that we are handling all margins
// ourselves rather than letting the layout engine attempt
// to use them. This is done for finer control though harder.
// Revision History:
// 06-09-95 created GAB
// Call the base, though we'll override any values.
CDCCX::LayoutNewDocument(pContext, pURL, pWidth, pHeight, pmWidth, pmHeight);
// Assign the page width, but adjust for our internal margins.
// This should be the only place where we use the right margin.
*pWidth = m_lPageWidth - (m_lLeftMargin + m_lRightMargin);
// Assign the page height, but adjust for our internal margins.
// This should be the only place where we use the bottom margin.
*pHeight = m_lPageHeight - (m_lTopMargin + m_lBottomMargin);
// Make sure layout doesn't attempt to use any margins itself, regardless.
*pmWidth = 0;
*pmHeight = 0;
}
void CPrintCX::CommencePrinting(URL_Struct *pUrl) {
// Purpose: Officially start a print job.
// Arguments: pAnchor The anchor for which to print.
// Returns: void
// Comments: This won't print forms with post data....
// This has always been the case in all versions.
// If such a need exists, I don't see what would be so
// hard about doing it, but layout has mythical
// tendencies to not handle this correctly.
// Revision History:
// 05-30-95 created GAB
// Create the print status dialog if not in preview.
if(IsPrintPreview() == FALSE) {
m_pStatusDialog = new CPrintStatusDialog(NULL, this);
m_pStatusDialog->m_csLocation = pUrl->address;
WFE_CondenseURL(m_pStatusDialog->m_csLocation, 40, FALSE);
m_pStatusDialog->Create(CPrintStatusDialog::IDD, NULL);
StartDoc();
// Also attempt to start the document for the first time.
// This is to help the cannot start print job problem, we are experienced
// with technical diffculties.
}
MWContext *pContext = GetContext();
HDC hdc = GetContextDC();
CL_Drawable *pPrinterDrawable = NULL;
// Create a drawable that represents the printer
m_pDrawable = new CPrinterDrawable(hdc, m_lLeftMargin, m_lRightMargin,
m_lTopMargin, m_lBottomMargin, this);
if (m_pDrawable)
pPrinterDrawable = CL_NewDrawable(CASTUINT(0),
CASTUINT(0),
CL_PRINTER,
&wfe_drawable_vtable,
(void *)m_pDrawable);
if (pPrinterDrawable) {
// Create a compositor for the printer context
// The window size is initially 0,0,0,0. It's modified when
// we know the size of the document.
pContext->compositor = CL_NewCompositor(pPrinterDrawable,
NULL,
0, 0,
0, 0,
0);
if (pContext->compositor)
CL_SetCompositorDrawingMethod(pContext->compositor,
CL_DRAWING_METHOD_BACK_TO_FRONT_ONLY);
else
CL_DestroyDrawable(pPrinterDrawable);
}
else
pContext->compositor = NULL;
ReleaseContextDC(hdc);
// Create the URL which will handle the load, and ask for it.
GetUrl(pUrl, FO_CACHE_AND_PRINT);
}
CWnd *CPrintCX::GetDialogOwner() const {
// Purpose: Returns the owner of any dialogs which we will create.
// Arguments: void
// Returns: CWnd * The dialog owner
// Comments: Returns the print status dialog as the owner, so it
// must be present for this to work.
// Revision History:
// 05-30-95 created GAB
if(IsPrintPreview() == FALSE) {
return(m_pStatusDialog);
}
else {
return(((CGenericView *)m_pPreviewView)->GetFrame()->GetFrameWnd());
}
}
int CPrintCX::StartDoc() {
// For modularity purposes only.
// This is called from several places.
// If we're in preview, or if we've already started the document, just
// return success.
if(IsPrintPreview() == TRUE || m_bNeedStartDoc == FALSE || IsDestroyed() == TRUE) {
// Don't do this if we don't need it.
return(0);
}
// Attempt to start the print job.
HDC pDC = GetContextDC();
// Set the docinfo structure up.
// Be sure to first clear the structure to 0, this may or may
// not cause StartDoc to fail unexplainably if we don't.
// MSDN: Q135119
memset(&m_docInfo, 0, sizeof(m_docInfo));
m_docInfo.cbSize = sizeof(m_docInfo);
MWContext *pct = GetContext();
// DocName may be the "DisplayUrl" used by Composer when
// we are printing/previewing a temporary file URL
m_docInfo.lpszDocName = ((pct->title != NULL) ? pct->title :
(m_pDisplayUrl ? (const char *)m_pDisplayUrl : (const char *)m_pAnchor));
m_docInfo.lpszOutput = NULL;
// Hold the document name to 31 characters.
CString cs31 = m_docInfo.lpszDocName;
if(cs31.GetLength() > 31) {
cs31.ReleaseBuffer(31);
}
m_docInfo.lpszDocName = (const char *)cs31;
int iRetval = ::StartDoc(pDC, &m_docInfo);
if(iRetval >= 0) {
// We got through.
m_bNeedStartDoc = FALSE;
}
ReleaseContextDC(pDC);
return(iRetval);
}
// Record document height and width
void CPrintCX::SetDocDimension(MWContext *pContext, int iLocation, int32 lWidth, int32 lHeight) {
CDCCX::SetDocDimension(pContext, iLocation, lWidth, lHeight);
m_lDocWidth = lWidth;
m_lDocHeight = lHeight;
}
void CPrintCX::CapturePositions()
{
CL_Compositor *compositor;
// For capturing, we want all the elements in a document to display.
// Since we can't size the compositor window to be the size of the
// document (the compositor window must have coordinates that fit into
// a 16-bit coordinate space), we take snapshots. In other words,
// we make the compositor window the size of the physical page and
// keep scrolling down till capture the entire document.
compositor = GetContext()->compositor;
if (compositor) {
XP_Rect rect;
int n;
// The compositor window is the size of the page (minus margins)
CL_ResizeCompositorWindow(compositor, m_lWidth, m_lHeight);
rect.left = 0;
rect.top = 0;
rect.right = m_lWidth;
rect.bottom = m_lHeight;
// We display all the elements twice. This is to deal with the
// fact that certain elements (images, embeds and applets for
// instance) are always displayed in a compositor pass after
// the containing HTML content. We only capture during the
// second pass.
for (n = 0; n < 2; n++) {
// Till we've covered the entire document, we keep scrolling
// down and taking snapshots
for (m_lCaptureScrollOffset = 0;
m_lCaptureScrollOffset <= m_lDocHeight;
m_lCaptureScrollOffset += m_lHeight) {
CL_ScrollCompositorWindow(compositor,
0, m_lCaptureScrollOffset);
CL_RefreshWindowRect(GetContext()->compositor, &rect);
}
m_iDisplayMode = CAPTURE_POSITION;
}
CL_ScrollCompositorWindow(compositor, 0, 0);
}
else {
// Set that we want all Display* calls to capture document positions
m_iDisplayMode = CAPTURE_POSITION;
LO_RefreshArea(GetDocumentContext(), 0, 0, 0x7FFFFFFF, 0x7FFFFFFF);
}
}
void CPrintCX::GetUrlExitRoutine(URL_Struct *pUrl, int iStatus, MWContext *pContext)
{
/* bad status: finish printing now */
if((iStatus < 0) && !m_bFormatStarted)
FormatAndPrintPages(pContext);
CDCCX::GetUrlExitRoutine(pUrl, iStatus, pContext);
}
static void DeferredDestroyPrintContext(void *cx)
{
((CPrintCX*)(cx))->p_TimeOut = 0;
((CPrintCX*)(cx))->CDCCX::DestroyContext();
}
/* Avoid destroying the document out from underneath layout when DestroyContext() is
called (indirectly) from layout, as in FormatAndPrintPages() */
void CPrintCX::DestroyContext() {
m_bHandleCancel = TRUE;
//Trun back off the display.
m_iDisplayMode = BLOCK_DISPLAY;
p_TimeOut = FE_SetTimeout(DeferredDestroyPrintContext, this, 0);
#ifdef XP_WIN32
::SelectObject(m_hOffscrnDC, ( HGDIOBJ)m_saveBitmap );
::DeleteObject(m_hOffScrnBitmap);
if (m_hOffscrnDC)
::DeleteDC(m_hOffscrnDC);
#endif
}
void CPrintCX::FormatAndPrintPages(MWContext *pContext) {
// Check to see if the user cancelled the job, if so, we're done.
if(m_bCancel == TRUE ) {
TRACE("Destroying canceled print job.\n");
if (!m_bHandleCancel)
DestroyContext();
return;
}
m_bFormatStarted = TRUE;
CapturePositions();
CL_ResizeCompositorWindow(GetContext()->compositor, m_lWidth, m_lHeight);
// Now we're ready to actually start drawing the display elements
m_iDisplayMode = DISPLAY;
// Do the entire print job now.
// Calculating page boundries.
// All layout information has been detained by the print job while
// loading the first time.
FormatPages();
// If there are no pages, get out now.
if(m_cplPages.IsEmpty() == TRUE) {
CString temp;
temp.LoadString(IDS_NOPAGETOPRINT);
FE_Alert(GetContext(), temp);
if(IsPrintPreview() == FALSE) {
DestroyContext();
}
return;
}
// One last try.
// Do we need to attempt to start the document?
if(0 > StartDoc()) {
CString temp;
temp.LoadString(IDS_NOPRINTJOB);
CFE_Alert(GetContext(), temp);
DestroyContext();
return;
}
// If we're not in preview, then we do the real thing.
if(IsPrintPreview() == FALSE) {
// Attempt to start the print job.
HDC pDC = GetContextDC();
// Set the callback function.
::SetAbortProc(pDC, PrintAbortProc);
m_bAbort = FALSE; // We switch to wanting to use EndDoc now....
// Here is the main print loop.
UINT uFromPage = m_pcpiPrintJob->GetFromPage();
UINT uToPage = m_pcpiPrintJob->GetToPage();
if(m_bReverseOrder) {
uFromPage = m_pcpiPrintJob->GetToPage();
uToPage = m_pcpiPrintJob->GetFromPage();
}
if(uFromPage > (UINT)m_cplPages.GetCount()) {
uFromPage = m_cplPages.GetCount();
}
if(uToPage > (UINT)m_cplPages.GetCount()) {
uToPage = m_cplPages.GetCount();
}
int iStep = uToPage >= uFromPage ? 1 : -1;
for(m_pcpiPrintJob->m_nCurPage = uFromPage;
m_pcpiPrintJob->m_nCurPage - iStep != uToPage;
m_pcpiPrintJob->m_nCurPage += iStep) {
// See if the user wanted to abort the print job.
if(m_bCancel == TRUE) {
m_bAbort = TRUE;
break;
}
// See if the page we are about to print actually exists.
// If not, it's time to stop the print job.
POSITION rIndex = m_cplPages.FindIndex(m_pcpiPrintJob->m_nCurPage - 1);
if(rIndex == NULL) {
// Time to stop printing. The specified page isn't found.
m_pcpiPrintJob->m_bContinuePrinting = FALSE;
}
// See if we are to kick out of the print job (done).
if(m_pcpiPrintJob->m_bContinuePrinting == FALSE) {
break;
}
// Let the DC know a new page is starting.
if(0 > ::StartPage(pDC)) {
// Some type of error occurred.
m_bAbort = TRUE;
break;
}
SetMappingMode(pDC); //AJB Fix for scaling problem on some Win95 printers
// Print the page
PrintPage(m_pcpiPrintJob->m_nCurPage);
// Let the DC know a page is ending.
if(0 > ::EndPage(pDC)) {
// Some type of error occurred.
m_bAbort = TRUE;
break;
}
}
// Set this to make sure everyone knows we aren't continuing to print.
m_pcpiPrintJob->m_bContinuePrinting = FALSE;
// Done, remove this object.
// End doc or abort doc are called in the destructor.
ReleaseContextDC(pDC);
DestroyContext();
}
else {
// Otherwise, we tell the owning view to refresh itself.
// This is a PITA. For frames, just invalidating the frame doesn't cause
// a repaint. Resizing the window does (has something to do with the horkage
// regarding frames and print preview; see netsvw.cpp). So, we disable
// drawing, resize the frame a little, invalidate it, put the size back the
// way it was, enable drawing, then invalidate again. Whew.
CFrameWnd *pFrame = ((CGenericView *)m_pPreviewView)->GetFrame()->GetFrameWnd();
if (pFrame) {
RECT rect;
pFrame->GetWindowRect( &rect );
pFrame->LockWindowUpdate();
pFrame->SetWindowPos( NULL, rect.left, rect.top, rect.right-rect.left+1, rect.bottom-rect.top+1,
SWP_NOACTIVATE || SWP_NOMOVE || SWP_NOZORDER );
pFrame->Invalidate();
pFrame->SetWindowPos( NULL, rect.left, rect.top, rect.right-rect.left, rect.bottom-rect.top,
SWP_NOACTIVATE || SWP_NOMOVE || SWP_NOZORDER );
pFrame->UnlockWindowUpdate();
pFrame->Invalidate();
}
}
}
void CPrintCX::FinishedLayout(MWContext *pContext) {
// Call the base.
CDCCX::FinishedLayout(pContext);
if(IsDestroyed())
return;
m_bFinishedLayoutCalled = TRUE;
if(m_bAllConnectionCompleteCalled && !m_bFormatStarted)
{
FormatAndPrintPages(pContext);
}
}
void CPrintCX::AllConnectionsComplete(MWContext *pContext) {
// Call the base.
CDCCX::AllConnectionsComplete(pContext);
if(IsDestroyed())
return;
m_bAllConnectionCompleteCalled = TRUE;
if(m_bFinishedLayoutCalled && !m_bFormatStarted)
{
FormatAndPrintPages(pContext);
}
}
void CPrintCX::Progress(MWContext *pContext, const char *pMessage) {
// Purpose: Display the progression of the load.
// Arguments: pContext The context loading a URL.
// pMessage The message to display.
// Returns: void
// Comments: Updates the CPrintStatus dialog mainly.
// Revision History:
// 05-31-95 created GAB
// Call the base.
CDCCX::Progress(pContext, pMessage);
// Simply set the progress text in the dialog.
if(pMessage != NULL) {
if(IsPrintPreview() == FALSE) {
m_pStatusDialog->SetDlgItemText(IDC_PROGRESS, pMessage);
}
else {
// Get the frame from the preview view, and have it do some
// progress for us.
LPCHROME pChrome = ((CGenericView *)m_pPreviewView)->GetFrame()->GetChrome();
if(pChrome) {
LPNSSTATUSBAR pIStatusBar = NULL;
pChrome->QueryInterface( IID_INSStatusBar, (LPVOID *) &pIStatusBar );
if ( pIStatusBar ) {
pIStatusBar->SetStatusText( pMessage );
pIStatusBar->Release();
}
}
}
}
}
void CPrintCX::CancelPrintJob() {
// Purpose: Cancels the current print job.
// Arguments: void
// Returns: void
// Comments: This should fully cancel a print job at any stage.
// Revision History:
// 05-31-95 created GAB
if(m_bCancel == FALSE) {
TRACE("Marking the print job as cancelled.\n");
// First, set a member stating that we are cancelling the job.
m_bCancel = TRUE;
// Second, set a member in the print job saying that the load
// has been interrupted.
m_pcpiPrintJob->m_bContinuePrinting = FALSE;
// If we're loading, then we interrupt that load.
XP_InterruptContext(GetContext());
}
}
void CPrintCX::FormatPages() {
// Purpose: Take the information regarding all elements to be
// laid out and determine which elements fall on which
// page.
// Arguments: void
// Returns: void
// Comments: Herein is how to properly print tables....
// Revision History:
// 06-09-95 created GAB
TRACE("Figuring page boundries\n");
CString temp;
temp.LoadString(IDS_FORMATTING);
FE_Progress(GetContext(), temp);
// Figure out the dimensions of the page taking into account margins.
// We can't and don't care about width.
// We use positive height to match layout.
int32 lHeight = m_lPageHeight - (m_lTopMargin + m_lBottomMargin);
int32 lWidth = m_lPageWidth - (m_lLeftMargin + m_lRightMargin);
// The algorithm here is as follows:
// Find all boundry elements. A boundry element, is an element cut
// off by the bottom of a page.
// A boundry element, if not at the top of a page, consitutes starting
// a new page.
// When a boundry element starts a new page, all elements starting
// below that element go on the next page with the boundry element.
CPtrList cplCurPage;
LTRB PageRect(0, 0, lWidth, lHeight);
LTRB *pPage;
LTRB *pBoundry;
LTRB *pElement;
POSITION rIndex, rOldIndex;
BOOL bUseSmartClipping;
int32 iOldPageBottom;
BOOL bUsedClipping;
while(m_cplCaptured.IsEmpty() == FALSE) {
// First, go through all captured elements, and move any which begin
// on the current page into a separate list.
rIndex = m_cplCaptured.GetHeadPosition();
while(rIndex != NULL) {
rOldIndex = rIndex;
pElement = (LTRB *)m_cplCaptured.GetNext(rIndex);
if(pElement->top <= PageRect.bottom) {
m_cplCaptured.RemoveAt(rOldIndex);
cplCurPage.AddTail((void *)pElement);
}
}
// We'll want to attempt to use a smarter algorithm in most cases,
// such that we do not cut lines in half. However, we will
// give up on that approach if we lose over half of the page
// height.
bUseSmartClipping = TRUE;
iOldPageBottom = PageRect.bottom;
bUsedClipping = FALSE;
while(1) {
// Further, find in that new list all boundries, and remember
// the beginning of the worst one.
// Remember, that if it starts at the beginning of a page or before
// the beginning of this page, then there is nothing we can do.
// Also, don't use elements longer than a single page by themselves as a
// boundry.
pBoundry = NULL;
rIndex = cplCurPage.GetHeadPosition();
while(rIndex != NULL) {
pElement = (LTRB *)cplCurPage.GetNext(rIndex);
if(pElement->bottom > PageRect.bottom && pElement->top > PageRect.top) {
// Make sure the element won't fit on a page by itself before we
// approve it as a boundry.
if(pElement->Height() > PageRect.Height()) {
// To high to fit on a page. Don't use as a boundry.
continue;
}
BOOL bSetBoundry = FALSE;
if(NULL == pBoundry) {
pBoundry = pElement;
bSetBoundry = TRUE;
}
else if(pBoundry->top > pElement->top) {
pBoundry = pElement;
bSetBoundry = TRUE;
}
if(bSetBoundry && bUseSmartClipping) {
// Adjust the bottom of the page to the boundry.
// Also, reset the loop, to catch any new betrayers.
PageRect.bottom = pBoundry->top;
rIndex = cplCurPage.GetHeadPosition();
bUsedClipping = TRUE;
}
}
}
// If we lost over half the page, redo the algorithm
// not using smart clipping.
if(bUsedClipping && PageRect.Height() < (lHeight / 2)) {
bUsedClipping = FALSE;
bUseSmartClipping = FALSE;
PageRect.bottom = iOldPageBottom;
continue;
}
break;
}
// Next move all elements falling below the boundry (if it exists)
// back into the captured element list.
if(pBoundry != NULL) {
rIndex = cplCurPage.GetHeadPosition();
while(rIndex != NULL) {
rOldIndex = rIndex;
pElement = (LTRB *)cplCurPage.GetNext(rIndex);
if(pElement->top >= pBoundry->top) {
cplCurPage.RemoveAt(rOldIndex);
m_cplCaptured.AddTail((void *)pElement);
}
}
}
// Also, we need to move all elements falling below this new boundry
// back into the captured list so that they are counted as yet
// another page. (think: 1 element that is 50 pages long....)
rIndex = cplCurPage.GetHeadPosition();
while(rIndex != NULL) {
rOldIndex = rIndex;
pElement = (LTRB *)cplCurPage.GetNext(rIndex);
if(pElement->bottom > PageRect.bottom) {
cplCurPage.RemoveAt(rOldIndex);
m_cplCaptured.AddTail((void *)pElement);
}
}
// Cause all current page elements to be destroyed.
rIndex = cplCurPage.GetHeadPosition();
while(rIndex != NULL) {
rOldIndex = rIndex;
pElement = (LTRB *)cplCurPage.GetNext(rIndex);
cplCurPage.RemoveAt(rOldIndex);
delete pElement;
}
// Create the new page entry (duplicate of the current page).
// This will be used later in PrintPage.
pPage = new LTRB(PageRect.left, PageRect.top, PageRect.right,
PageRect.bottom);
m_cplPages.AddTail((void *)pPage);
// Update the value of the current page to be the next page.
PageRect.top = PageRect.bottom + 1;
PageRect.bottom = PageRect.top + lHeight;
}
}
void CPrintCX::PrintTextAllign ( HDC hdc, char * szBuffer, int position, int hpos )
{
SIZE csExtent;
int32 Y;
int32 X;
CString cs = szBuffer;
WFE_CondenseURL ( cs, m_iMaxWidth, FALSE );
CreateHeaderFooterFont();
HFONT hOldFont = NULL;
if(m_hFont) {
hOldFont = (HFONT)::SelectObject(hdc, m_hFont);
}
ResolveTextExtent(hdc, cs, strlen(cs), &csExtent);
if ( hpos == POS_FOOTER )
Y = m_lPageHeight - csExtent.cy - 1;
else
Y = 0;
switch ( position )
{
case POS_CENTER:
X = m_lPageWidth / 2 - csExtent.cx / 2;
break;
case POS_LEFT:
X = 0;
break;
case POS_RIGHT:
X = m_lPageWidth - csExtent.cx;
break;
}
CIntlWin::TextOut(m_iFontCSID , hdc, CASTINT(X), CASTINT(Y), cs, strlen(cs));
if(hOldFont) {
::SelectObject(hdc, hOldFont);
}
}
void CPrintCX::PrintPage(int iPage, HDC pNewDC, CPrintInfo *pNewInfo) {
// Purpose: Print a specific page.
// Arguments: iPage The page which to print.
// Returns: void
// Comments: This is the real thing. If there is no page information
// then we get out of the print loop.
// Revision History:
// 06-09-95 created GAB
// If we've got new information, use it.
if(pNewDC != NULL) {
m_hdcPrint = pNewDC;
}
if(pNewInfo != NULL) {
m_pcpiPrintJob = pNewInfo;
}
// Page numbers always go from 1 on up.
// Get the position of the page in out list.
POSITION rIndex = m_cplPages.FindIndex(iPage - 1);
if(rIndex == NULL) {
// Time to stop printing, the specified page isn't found.
// Only do this when we're actually printing.
if(IsPrintPreview() == FALSE) {
m_pcpiPrintJob->m_bContinuePrinting = FALSE;
}
return;
}
TRACE("Printing page %d\n", iPage);
m_iLastPagePrinted = iPage;
char szMessage[80];
PR_snprintf(szMessage, sizeof(szMessage), szLoadString(IDS_PRINTING_PAGE), iPage);
FE_Progress(GetContext(), szMessage);
// Get the actual page, and have layout refresh the area.
// This will in turn cause the display functions to be called, and this
// will in turn cause the display functions to call ResolveElement,
// and therein we adjust for margins and determine wether or not
// to output an actual element.
LTRB *pPage = (LTRB *)m_cplPages.GetAt(rIndex);
// Save the DC state, so that clipping information can be restored to
// defaults after the page is printed.
HDC hdc = GetContextDC();
int iSaveDC = ::SaveDC(hdc);
TRACE("LO_RefreshArea(%ld,%ld,%ld,%ld);\n", pPage->left, pPage->top,
pPage->Width(), pPage->Height());
// Instead of passing the actual page params, we have layout refresh
// everything possible.
// All ResolveElement functions will have to appropriately block display
// for the current page.
// In this manner, we correctly handle elements longer than one page.
CL_Compositor *compositor = GetContext()->compositor;
if (compositor) {
XP_Rect rect;
CL_ScrollCompositorWindow(compositor, 0, pPage->top);
rect.left = 0;
rect.top = 0;
rect.right = m_lWidth;
// For the last page, we use the complete height of the physical
// page so that, if there's a background, it won't get cut off
// early.
if (rIndex == m_cplPages.GetTailPosition())
rect.bottom = m_lHeight;
else
rect.bottom = pPage->Height();
CL_ResizeCompositorWindow(compositor, rect.right, rect.bottom);
CL_RefreshWindowRect(compositor, &rect);
}
else {
// Now, make it small enough for the page only.
::IntersectClipRect(hdc, CASTINT(m_lLeftMargin),
CASTINT(m_lTopMargin),
CASTINT(m_lLeftMargin + pPage->Width()),
CASTINT(m_lTopMargin + pPage->Height()));
LO_RefreshArea(GetDocumentContext(), 0, 0, 0x7FFFFFFF, 0x7FFFFFFF);
}
// Restore the DC state (clipping region).
::RestoreDC(hdc, iSaveDC);
// Headers and footers.
// Footers first! Footers first!
ApiPageSetup(api,0);
int iFooter = api->Footer ( );
int iPosDate = 0;
BOOL bPosTotal = 0;
int iPosCount = 0;
if ( iFooter & PRINT_PAGENO )
iPosCount = POS_CENTER;
if ( iFooter & PRINT_PAGECOUNT )
bPosTotal = TRUE;
if ( iFooter & PRINT_DATE )
if ( iPosCount )
{
iPosCount = POS_LEFT;
iPosDate = POS_RIGHT;
}
else
iPosDate = POS_CENTER;
// page number
if( iPosCount ) {
char szBuffer[32];
if ( bPosTotal )
PR_snprintf(szBuffer, sizeof(szBuffer), szLoadString(IDS_PAGE_N_OF_COUNT), iPage, m_cplPages.GetCount( ));
else
PR_snprintf(szBuffer, sizeof(szBuffer), "%d", iPage);
PrintTextAllign ( hdc, szBuffer, iPosCount, POS_FOOTER );
}
if ( iPosDate ) {
char aBuffer[65];
char szDate[30];
char szTime[30];
#ifdef XP_WIN32
GetDateFormat(LOCALE_SYSTEM_DEFAULT, DATE_SHORTDATE, NULL, NULL, szDate, 30);
GetTimeFormat(LOCALE_SYSTEM_DEFAULT, TIME_NOSECONDS, NULL, NULL, szTime, 30);
sprintf(aBuffer,"%s %s", szDate, szTime);
#else
sprintf(aBuffer,"%s %s", _strdate(szDate), _strtime(szTime) );
#endif
PrintTextAllign ( hdc, aBuffer, iPosDate, POS_FOOTER );
}
int iHeader = api->Header ( );
int iPosTitle = 0;
int iPosURL = 0;
if ( iHeader & PRINT_TITLE )
iPosTitle = POS_CENTER;
if ( iHeader & PRINT_URL )
if ( iPosTitle )
{
iPosTitle = POS_LEFT;
iPosURL = POS_RIGHT;
}
else
iPosURL = POS_CENTER;
if ( iPosTitle )
{
char *pTitle = GetContext()->title;
if(pTitle != NULL)
PrintTextAllign ( hdc, pTitle, iPosTitle, POS_HEADER );
}
if ( iPosURL )
{
// Here's where we finally use the DisplayURL
// instead of the temporary file URL in Composer
const char * pURL = m_pDisplayUrl ? m_pDisplayUrl : m_pAnchor;
if ( pURL && *pURL ) {
char *pszUrlType = NET_ParseURL( pURL, GET_PROTOCOL_PART );
if ( !pszUrlType || (XP_STRCASECMP(pszUrlType, "mailbox:") &&
XP_STRCASECMP(pszUrlType, "news:") &&
XP_STRCASECMP(pszUrlType, "snews:") &&
XP_STRCASECMP(pszUrlType, "imap:")) ) {
PrintTextAllign ( hdc, (char *)pURL, iPosURL, POS_HEADER );
}
if ( pszUrlType )
XP_FREE( pszUrlType );
}
}
ReleaseContextDC(hdc);
}
void CPrintCX::EraseBackground(MWContext *pContext, int iLocation,
int32 x, int32 y, uint32 width, uint32 height,
LO_Color *pColor)
{
int32 orgx, orgy, orgWidth, orgHeight;
orgx = x;
orgy = y;
orgWidth = width;
orgHeight = height;
if (GetDisplayMode() == DISPLAY) {
x += m_lLeftMargin;
y += m_lTopMargin;
// Adjust the Y coordinate for the current page we are printing.
POSITION rIndex = m_cplPages.FindIndex(m_pcpiPrintJob->m_nCurPage - 1);
if(rIndex == NULL) {
// This could be called during incremental display.
// Don't allow drawing at that point.
return;
}
LTRB *pPage = (LTRB *)m_cplPages.GetAt(rIndex);
y -= pPage->top;
// Form a Rect of the current page, in the same coords as the
// background. The bottom of the page is determined on a page
// by page basis.
LTRB Page;
Page.left = m_lLeftMargin;
Page.top = m_lTopMargin;
Page.right = Page.left + pPage->Width();
Page.bottom = Page.top + pPage->Height();
if(y >= Page.bottom || (y+(int32)height) <= Page.top ||
(x + (int32)width) <= Page.left || x >= Page.right)
return;
else {
#ifdef XP_WIN32
if ( m_printBk && !IsPrintPreview()) {
SubOffscreenPrintDC();
CDCCX::EraseBackground(pContext, iLocation,
orgx / m_lConvertX, orgy / m_lConvertY,
orgWidth / m_lConvertX, orgHeight / m_lConvertY, pColor);
RestorePrintDC();
}
#endif
CDCCX::EraseBackground(pContext, iLocation,
x, y,
width, height, pColor);
}
}
}
void CPrintCX::DisplayBullet(MWContext *pContext, int iLocation, LO_BullettStruct *pBullet) {
if (GetDisplayMode() == BLOCK_DISPLAY)
return;
else if (GetDisplayMode() == CAPTURE_POSITION) {
int32 lOrgX, lOrgY;
GetDrawingOrigin(&lOrgX, &lOrgY);
// Capture the coordinates of this element.
Capture(pBullet->x + pBullet->x_offset + lOrgX, pBullet->y + pBullet->y_offset + lOrgY, pBullet->width, pBullet->height);
// We don't actually allow display while we are capturing the area.
return;
}
// Call the base for actual display. It never works right
// in Bullet Basic code for some reason.
#ifdef XP_WIN32
if ( m_printBk && !IsPrintPreview()) {
SubOffscreenPrintDC();
CDCCX::DisplayBullet(pContext, iLocation, pBullet);
RestorePrintDC();
}
#endif
CDCCX::DisplayBullet(pContext, iLocation, pBullet);
}
#ifndef MOZ_NGLAYOUT
void CPrintCX::DisplayEmbed(MWContext *pContext, int iLocation, LO_EmbedStruct *pEmbed) {
if (GetDisplayMode() == BLOCK_DISPLAY)
return;
else if (GetDisplayMode() == CAPTURE_POSITION) {
// Capture the coordinates of this element.
Capture(pEmbed->objTag.x + pEmbed->objTag.x_offset, pEmbed->objTag.y + pEmbed->objTag.y_offset,
pEmbed->objTag.width, pEmbed->objTag.height);
// We don't actually allow display while we are capturing the area.
return;
}
// Call the base for actual display.
NPEmbeddedApp* pEmbeddedApp = (NPEmbeddedApp*)pEmbed->objTag.FE_Data;
if (pEmbeddedApp->type == NP_OLE) {
CNetscapeCntrItem *pItem = (CNetscapeCntrItem *)pEmbeddedApp->fe_data;
pItem->SetPrintDevice( &(m_pcpiPrintJob->m_pPD->m_pd) );
}
CDCCX::DisplayEmbed(pContext, iLocation, pEmbed);
}
void CPrintCX::DisplayFormElement(MWContext *pContext, int iLocation, LO_FormElementStruct *pFormElement) {
if (GetDisplayMode() == BLOCK_DISPLAY)
return;
else if (GetDisplayMode() == CAPTURE_POSITION) {
// Capture the coordinates of this element.
Capture(pFormElement->x + pFormElement->x_offset, pFormElement->y + pFormElement->y_offset, pFormElement->width, pFormElement->height);
// We don't actually allow display while we are capturing the area.
return;
}
// Call the base for actual display.
#ifdef XP_WIN32
if ( m_printBk && !IsPrintPreview()) {
SubOffscreenPrintDC();
CDCCX::DisplayFormElement(pContext, iLocation, pFormElement);
RestorePrintDC();
}
#endif
CDCCX::DisplayFormElement(pContext, iLocation, pFormElement);
}
#endif
void CPrintCX::DisplayHR(MWContext *pContext, int iLocation, LO_HorizRuleStruct *pHorizRule) {
if (GetDisplayMode() == BLOCK_DISPLAY)
return;
else if (GetDisplayMode() == CAPTURE_POSITION) {
int32 lOrgX, lOrgY;
GetDrawingOrigin(&lOrgX, &lOrgY);
// Capture the coordinates of this element.
Capture(pHorizRule->x + pHorizRule->x_offset + lOrgX, pHorizRule->y + pHorizRule->y_offset + lOrgY, pHorizRule->width, pHorizRule->height);
// We don't actually allow display while we are capturing the area.
return;
}
// Call the base for actual display.
#ifdef XP_WIN32
if ( m_printBk && !IsPrintPreview() ) {
SubOffscreenPrintDC();
CDCCX::DisplayHR(pContext, iLocation, pHorizRule);
RestorePrintDC();
}
#endif
CDCCX::DisplayHR(pContext, iLocation, pHorizRule);
}
BOOL CPrintCX::IsDeviceDC()
{
#ifdef XP_WIN32
if (!m_printBk) return TRUE;
else {
if (m_hdcPrint == m_hOrgPrintDC)
return TRUE;
else return FALSE;
}
#else
return TRUE;
#endif
}
#ifdef XP_WIN32
void CPrintCX::CopyOffscreenBitmap(NI_Pixmap* image, int32 x, int32 y, int32 x_offset, int32 y_offset, int32 width, int32 height, int32 lScaleWidth, int32 lScaleHeight, LTRB& Rect)
{
LTRB sourceRect(Rect);
ResolveElement(Rect, image,
x_offset * m_lConvertX,
y_offset* m_lConvertY,
x * m_lConvertX, y* m_lConvertY,
width * m_lConvertX,
height* m_lConvertY,
lScaleWidth * m_lConvertX,
lScaleHeight * m_lConvertY);
WORD nBitCount;
nBitCount = GetBitsPerPixel();
int nColorTable;
// We need to know how big the color table is. For 16-bit mode and 32-bit mode, we need to
// allocate room for 3 double-word color masks
if (nBitCount == 16 || nBitCount == 32)
nColorTable = 3;
else if (nBitCount < 16)
nColorTable = 1 << nBitCount;
else {
ASSERT(nBitCount == 24);
nColorTable = 0;
}
LPBITMAPINFOHEADER lpBmi;
// Allocate space for a BITMAPINFO structure (BITMAPINFOHEADER structure
// plus space for the color table)
lpBmi = (LPBITMAPINFOHEADER)calloc(sizeof(BITMAPINFOHEADER) + nColorTable * sizeof(RGBQUAD), 1);
if (lpBmi) {
// Initialize the BITMAPINFOHEADER structure
lpBmi->biSize = sizeof(BITMAPINFOHEADER);
lpBmi->biWidth = width;
lpBmi->biHeight = height;
lpBmi->biPlanes = 1;
lpBmi->biCompression = BI_RGB;
CDC *pAttrDC;
pAttrDC = theApp.m_pMainWnd->GetDC();
HDC tempDC = ::CreateCompatibleDC(pAttrDC->GetSafeHdc());
lpBmi->biBitCount = nBitCount;
// Ask the driver to tell us the number of bits we need to allocate
BITMAPINFO lpbmi;
lpbmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
lpbmi.bmiHeader.biWidth = lpBmi->biWidth;
lpbmi.bmiHeader.biHeight = lpBmi->biHeight;
lpbmi.bmiHeader.biPlanes = 1;
lpbmi.bmiHeader.biBitCount = 24;
lpbmi.bmiHeader.biCompression = BI_RGB;
lpbmi.bmiHeader.biSizeImage = 0;
lpbmi.bmiHeader.biXPelsPerMeter = 0;
lpbmi.bmiHeader.biYPelsPerMeter = 0;
lpbmi.bmiHeader.biClrUsed = 0; // default value
lpbmi.bmiHeader.biClrImportant = 0; // all important
void* ptr;
HBITMAP tempBmp = ::CreateDIBSection(pAttrDC->GetSafeHdc(),&lpbmi, DIB_RGB_COLORS,
&ptr, NULL, NULL);
HBITMAP hOldBmp = (HBITMAP)::SelectObject(tempDC, tempBmp);
::BitBlt(tempDC, 0, 0, width, height,
m_hOffscrnDC,
CASTINT(sourceRect.left),
CASTINT(sourceRect.top),
SRCCOPY);
(HBITMAP)::SelectObject(tempDC, hOldBmp);
lpBmi->biSizeImage = ((((lpBmi->biWidth * nBitCount) + 31) & ~31) >> 3) * lpBmi->biHeight;
// Allocate space for the bits
LPBYTE lpBits = (LPBYTE)HugeAlloc(lpBmi->biSizeImage, 1);
::GetDIBits(tempDC, tempBmp, 0, (int)lpBmi->biHeight, lpBits, (LPBITMAPINFO)lpBmi, DIB_RGB_COLORS);
::StretchDIBits(GetContextDC(),
CASTINT(Rect.left),
CASTINT(Rect.top),
CASTINT(Rect.right - Rect.left),
CASTINT(Rect.bottom - Rect.top),
0,
0,
CASTINT(width),
CASTINT(height),
lpBits,
(BITMAPINFO*)lpBmi,
DIB_RGB_COLORS,
SRCCOPY);
::DeleteDC(tempDC);
::DeleteObject(tempBmp);
free(lpBits);
free(lpBmi);
theApp.m_pMainWnd->ReleaseDC(pAttrDC);
}
}
#endif
int CPrintCX::DisplayPixmap(NI_Pixmap* image, NI_Pixmap* mask, int32 x, int32 y, int32 x_offset, int32 y_offset, int32 width, int32 height, int32 lScaleWidth, int32 lScaleHeight, LTRB& Rect)
{
// Figure out the width and height we will want to display on the screen.
// This is not a one to one with the width and height of the image,
// especially in scaling cases.
int32 lDisplayWidth;
int32 lDisplayHeight;
if((!lScaleWidth)&&(!lScaleHeight)){
lDisplayWidth = width;
lDisplayHeight = height;
}else{
if(lScaleWidth)
lDisplayWidth = lScaleWidth;
else
lDisplayWidth = (int32) width * (((float) lScaleHeight)/height );
if(lScaleHeight)
lDisplayHeight = lScaleHeight;
else
lDisplayHeight = (int32) height * (((float) lScaleWidth)/width );
}
// LTRB Rect;
if (GetDisplayMode() == BLOCK_DISPLAY)
return FALSE;
else if (GetDisplayMode() == CAPTURE_POSITION) {
int32 lOrgX, lOrgY;
GetDrawingOrigin(&lOrgX, &lOrgY);
// Capture the coordinates of this element.
Capture(x + (x_offset * m_lConvertX) + lOrgX, y + (y_offset * m_lConvertY) + lOrgY, width * m_lConvertX, height * m_lConvertY);
// We don't actually allow display while we are capturing the area.
return FALSE;
}
int iSaveDC = ::SaveDC(m_hdcPrint);
FEBitmapInfo *imageInfo;
imageInfo = (FEBitmapInfo*) image->client_data;
#ifdef XP_WIN32
if ( m_printBk && !IsPrintPreview()) {
SubOffscreenPrintDC();
CDCCX::DisplayPixmap(image, mask,
x, y,
x_offset, y_offset,
(imageInfo->width > width) ? imageInfo->width : width,
(imageInfo->height > height) ? imageInfo->height : height,
lScaleWidth,
lScaleHeight,
Rect);
RestorePrintDC();
}
if (mask && m_printBk && !IsPrintPreview()) {
CopyOffscreenBitmap(image, x, y, x_offset, y_offset, width, height, lScaleWidth, lScaleHeight, Rect);
}
else
CDCCX::DisplayPixmap(image, mask,
x, y,
x_offset, y_offset,
(imageInfo->width > width) ? imageInfo->width : width,
(imageInfo->height > height) ? imageInfo->height : height,
lDisplayWidth, lDisplayHeight,
Rect);
#else
if (ResolveElement(Rect, image,
(x_offset * m_lConvertX),
(y_offset * m_lConvertY),
x, y,
(width * m_lConvertX),
(height * m_lConvertY),
lScaleWidth * m_lConvertX,
lScaleHeight * m_lConvertY) {
if (IsPrintPreview())
CDCCX::DisplayPixmap(image, mask, x, y, x_offset,
y_offset, width, height,
lScaleWidth, lScaleHeight, Rect);
else {
StretchPixmap(GetContextDC(), image,
Rect.left,
Rect.top,
Rect.right - Rect.left,
Rect.bottom - Rect.top,
x_offset,
y_offset,
width,
height);
}
}
#endif
if(iSaveDC) {
::RestoreDC(m_hdcPrint, iSaveDC);
}
return TRUE;
}
void CPrintCX::DisplayLineFeed(MWContext *pContext, int iLocation, LO_LinefeedStruct *pLineFeed, XP_Bool iClear) {
if (GetDisplayMode() == BLOCK_DISPLAY)
return;
else if (GetDisplayMode() == CAPTURE_POSITION) {
int32 lOrgX, lOrgY;
GetDrawingOrigin(&lOrgX, &lOrgY);
// Capture the coordinates of this element.
Capture(pLineFeed->x + pLineFeed->x_offset + lOrgX, pLineFeed->y + pLineFeed->y_offset + lOrgY, pLineFeed->width, pLineFeed->height);
// We don't actually allow display while we are capturing the area.
return;
}
// Call the base for actual display.
#ifdef XP_WIN32
if ( m_printBk && !IsPrintPreview()) {
SubOffscreenPrintDC();
CDCCX::DisplayLineFeed(pContext, iLocation, pLineFeed, iClear);
RestorePrintDC();
}
#endif
CDCCX::DisplayLineFeed(pContext, iLocation, pLineFeed, iClear);
}
void CPrintCX::DisplaySubDoc(MWContext *pContext, int iLocation, LO_SubDocStruct *pSubDoc) {
if (GetDisplayMode() == BLOCK_DISPLAY)
return;
else if (GetDisplayMode() == CAPTURE_POSITION) {
int32 lOrgX, lOrgY;
GetDrawingOrigin(&lOrgX, &lOrgY);
// Capture the coordinates of this element.
Capture(pSubDoc->x + pSubDoc->x_offset + lOrgX, pSubDoc->y + pSubDoc->y_offset + lOrgY, pSubDoc->width, pSubDoc->height);
// We don't actually allow display while we are capturing the area.
return;
}
// Call the base for actual display.
#ifdef XP_WIN32
if ( m_printBk && !IsPrintPreview()) {
SubOffscreenPrintDC();
CDCCX::DisplaySubDoc(pContext, iLocation, pSubDoc);
RestorePrintDC();
}
#endif
CDCCX::DisplaySubDoc(pContext, iLocation, pSubDoc);
}
void CPrintCX::DisplayCell(MWContext *pContext, int iLocation, LO_CellStruct *pCell) {
if ((GetDisplayMode() == BLOCK_DISPLAY) ||
(GetDisplayMode() == CAPTURE_POSITION)) {
// Actually, we don't want to capture the area of a cell,
// as it is already surrounded by a table.
// If we have to cut a table in half, then we will do so
// without regard to the table cells.
// We don't actually allow display while we are capturing the area.
return;
}
// Call the base for actual display.
#ifdef XP_WIN32
if ( m_printBk && !IsPrintPreview()) {
SubOffscreenPrintDC();
CDCCX::DisplayCell(pContext, iLocation, pCell);
RestorePrintDC();
}
#endif
CDCCX::DisplayCell(pContext, iLocation, pCell);
}
void CPrintCX::DisplaySubtext(MWContext *pContext, int iLocation, LO_TextStruct *pText, int32 lStartPos, int32 lEndPos, XP_Bool iClear) {
if ((GetDisplayMode() == BLOCK_DISPLAY) ||
(GetDisplayMode() == CAPTURE_POSITION)) {
// Never capture the coordinates of this element.
// It is only part of a string, and DisplayText will correctly
// handle the coordinates.
// We don't actually allow display while we are capturing the area.
return;
}
// Don't need to call the base for actual display.
}
void CPrintCX::DisplayTable(MWContext *pContext, int iLocation, LO_TableStruct *pTable) {
if (GetDisplayMode() == BLOCK_DISPLAY)
return;
else if (GetDisplayMode() == CAPTURE_POSITION) {
int32 lOrgX, lOrgY;
GetDrawingOrigin(&lOrgX, &lOrgY);
// Capture the coordinates of this element.
Capture(pTable->x + pTable->x_offset + lOrgX, pTable->y + pTable->y_offset + lOrgY, pTable->width, pTable->height);
// We don't actually allow display while we are capturing the area.
return;
}
// Call the base for actual display.
#ifdef XP_WIN32
if ( m_printBk && !IsPrintPreview()) {
SubOffscreenPrintDC();
CDCCX::DisplayTable(pContext, iLocation, pTable);
RestorePrintDC();
}
#endif
CDCCX::DisplayTable(pContext, iLocation, pTable);
}
void CPrintCX::DisplayText(MWContext *pContext, int iLocation, LO_TextStruct *pText, XP_Bool iClear) {
if (GetDisplayMode() == BLOCK_DISPLAY)
return;
else if (GetDisplayMode() == CAPTURE_POSITION) {
int32 lOrgX, lOrgY;
GetDrawingOrigin(&lOrgX, &lOrgY);
// Capture the coordinates of this element.
Capture(pText->x + pText->x_offset + lOrgX, pText->y + pText->y_offset + lOrgY, pText->width, pText->height);
// We don't actually allow display while we are capturing the area.
return;
}
// Call the base for actual display.
#ifdef XP_WIN32
if ( m_printBk && !IsPrintPreview()) {
SubOffscreenPrintDC();
LO_TextAttr* pAttr = pText->text_attr;
CyaFont *pCachedFont = (CyaFont *)pAttr->FE_Data;
// this is a hack to trick the font engine so the font size
// will get regenerate again. Otherwise, we will end up getting
// the font size for printer.
pAttr->FE_Data = 0;
CDCCX::DisplayText(pContext, iLocation, pText, iClear);
pAttr->FE_Data = pCachedFont;
RestorePrintDC();
}
#endif
CDCCX::DisplayText(pContext, iLocation, pText, iClear);
}
void CPrintCX::Capture(int32 lOrgX, int32 lOrgY, int32 lWidth, int32 lHeight) {
// Purpose: Capture the rectangle in order to layout the document properly.
// Arguments: lOrgX X origin of the element.
// lOrgY Y origin of the element.
// lWidth The width of the element.
// lHeight The height of the lement.
// Returns: void
// Comments: The origin of the print job must always remain 0,0 for this
// to work correctly.
// Revision History:
// 06-09-95 created GAB
// Don't capture on no width and height.
if(lWidth <= 0 || lHeight <= 0) {
return;
}
// Don't capture areas we might already have captured
if (lOrgY < m_lCaptureScrollOffset) {
return;
}
// Allocate a new rectangle to hold the information.
LTRB *pRect = new LTRB(lOrgX, lOrgY, lOrgX + lWidth, lOrgY + lHeight);
// Add the rectangle to the list of elements we are considering.
m_cplCaptured.AddTail((void *)pRect);
}
void CPrintCX::DisplayWindowlessPlugin(MWContext *pContext,
LO_EmbedStruct *pEmbed,
NPEmbeddedApp *pEmbeddedApp,
int iLocation)
{
DisplayPlugin(pContext, pEmbed, pEmbeddedApp, iLocation);
}
// Resolve the dimensions of the plugin object rect and tell the plugin
// to print in that rect using the print HDC.
void CPrintCX::DisplayPlugin(MWContext *pContext, LO_EmbedStruct *pEmbed,
NPEmbeddedApp* pEmbeddedApp, int iLocation)
{
// get the print area and clamp it
LTRB Rect;
#ifdef MOZ_NGLAYOUT
XP_ASSERT(0);
#else
ResolveElement(Rect, pEmbed, iLocation, NPL_IsEmbedWindowed(pEmbeddedApp));
#endif
SafeSixteen(Rect);
// set the print area rect
NPPrint npPrint;
NPWindow* pWindow = &npPrint.print.embedPrint.window;
// Initialize struct
npPrint.mode = NP_EMBED;
pWindow->window = NULL;
pWindow->y = Rect.top;
pWindow->x = Rect.left;
pWindow->width = Rect.right - Rect.left;
pWindow->height = Rect.bottom - Rect.top;
pWindow->type = NPWindowTypeWindow;
// get the print HDC
HDC hdc = GetContextDC();
// Save the state of the DC so we can restore it if the Plugin
// changes it's state.
int iSaveDC = ::SaveDC(hdc);
npPrint.print.embedPrint.platformPrint = (void*)hdc;
#ifdef MOZ_NGLAYOUT
XP_ASSERT(0);
#else
(void)NPL_Print(pEmbeddedApp, &npPrint);
#endif
// Restore the DC's state.
if(iSaveDC) {
::RestoreDC(hdc, iSaveDC);
}
ReleaseContextDC(hdc);
}
// Do not allow incremental image display.
PRBool CPrintCX::ResolveIncrementalImages()
{
return(PR_FALSE);
}
// ReCreate Font for header and footer if possible.
VOID CPrintCX::CreateHeaderFooterFont()
{
if (m_hFont == NULL || m_iFontCSID != INTL_DocToWinCharSetID(m_iCSID))
{
if(m_hFont) {
::DeleteObject(m_hFont);
m_hFont = NULL;
}
HDC hdc = GetContextDC();
LOGFONT lf;
XP_MEMSET(&lf,0,sizeof(LOGFONT));
lf.lfPitchAndFamily = FF_SWISS | VARIABLE_PITCH ;
strcpy(lf.lfFaceName, IntlGetUIPropFaceName(m_iCSID));
lf.lfCharSet = IntlGetLfCharset(m_iCSID); // get global lfCharset
long height;
if (!IsPrintPreview() && ::GetDeviceCaps(hdc, LOGPIXELSY)) {
height = ( ( 10 * ::GetDeviceCaps(hdc, LOGPIXELSY) ) / 72 );
height = ( ( ( height * 1000L ) / ::GetDeviceCaps ( hdc, LOGPIXELSY ) ) * 1440L ) / 1000L;
}
else {
height = ( ( 18 * printRes.cx) / screenRes.cx );
}
lf.lfHeight = CASTINT(height);
lf.lfQuality = PROOF_QUALITY;
lf.lfWeight = FW_NORMAL;
m_hFont = ::CreateFontIndirect ( &lf );
m_iFontCSID = INTL_DocToWinCharSetID(m_iCSID);
ReleaseContextDC(hdc);
}
}
int CPrintCX::PageCount()
{
int iRetval = 0;
if(!m_cplPages.IsEmpty()) {
iRetval = m_cplPages.GetCount();
}
return(iRetval);
}
int CPrintCX::LastPagePrinted()
{
return(m_iLastPagePrinted);
}
void
CPrintCX::GetDrawingOrigin(int32 *plOrgX, int32 *plOrgY)
{
if (m_pDrawable)
m_pDrawable->GetOrigin(plOrgX, plOrgY);
else
*plOrgX = *plOrgY = 0;
}
FE_Region
CPrintCX::GetDrawingClip()
{
if (m_pDrawable)
return m_pDrawable->GetClip();
else
return NULL;
}
PrinterDisplayMode CPrintCX::GetDisplayMode() {
PrinterDisplayMode pdmRetval = m_iDisplayMode;
if(m_bGlobalBlockDisplay && pdmRetval == DISPLAY && !IsPrintPreview()) {
// Tell me if this ever happens, I'd like to study it -- blythe.
ASSERT(0);
pdmRetval = BLOCK_DISPLAY;
}
return(pdmRetval);
}