mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-26 02:02:33 +00:00
2460 lines
76 KiB
C++
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);
|
|
}
|
|
|