home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / winfe / cxprint.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  75.6 KB  |  2,394 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18.  
  19. #include "stdafx.h"
  20.  
  21. #include "cxprint.h"
  22. #include "apipage.h"    // page setup api
  23. #include "netsvw.h"
  24. #include "npapi.h"
  25. #include "np.h"
  26. #include "feimage.h"
  27. #include "il_icons.h"
  28. #include "netsprnt.h"
  29. #include "cntritem.h"
  30. #include "intl_csi.h"
  31. #include "prefapi.h"
  32.  
  33. BOOL CPrintCX::m_bGlobalBlockDisplay = FALSE;
  34.  
  35. //    A callback function from the print manager.
  36. //    See CDC::SetAbortProc for more information
  37. BOOL CALLBACK EXPORT PrintAbortProc(HDC hDC, int iStatus)    {
  38.     //    See if we've cancelled.....  Only we can't.
  39.     //    This wasn't designed apparently to handle more than one print job per app
  40.     //        at a time.
  41.  
  42.     //  Turn off display for a moment in all print contexts.
  43.     //  This keeps us from going re-etrant into GDI.
  44.     BOOL bOldBlock = CPrintCX::m_bGlobalBlockDisplay;
  45.     CPrintCX::m_bGlobalBlockDisplay = TRUE;
  46.     
  47.     //    Here we shove all messages on through.
  48.     MSG msg;
  49.     while(::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE))    {
  50.         if(!theApp.NSPumpMessage()) {
  51.             //  Restore display flag.
  52.             CPrintCX::m_bGlobalBlockDisplay = bOldBlock;
  53.  
  54.             //    Get out if WM_QUIT received.
  55.             return(FALSE);
  56.         }
  57.     }
  58.  
  59.     //  Restore display flag.
  60.     CPrintCX::m_bGlobalBlockDisplay = bOldBlock;
  61.  
  62.     //    Just continue printing.
  63.     return(TRUE);
  64. }
  65.  
  66. extern "C" void FE_Print(const char *pUrl)  {
  67.     CPrintCX::AutomatedPrint(pUrl, NULL, NULL, NULL);
  68. }
  69.  
  70. //  Print with no user intervention.
  71. //  Null on an argument means default.
  72. void CPrintCX::AutomatedPrint(const char *pDocument, const char *pPrinter, const char *pDriver, const char *pPort)  {
  73.     TRACE("Automated Print job starting (%s, %s, %s, %s)\n", pDocument, pPrinter, pDriver, pPort);
  74.  
  75.     //  Our document is probably local or a shortcut, convert to something networthy.
  76.     CString csUrl;
  77.     WFE_ConvertFile2Url(csUrl, pDocument);
  78.  
  79.     //  Create the actual URL struct.
  80.     URL_Struct *pUrl = NET_CreateURLStruct(csUrl, NET_DONT_RELOAD);
  81.     if(pUrl == NULL)    {
  82.         return;
  83.     }
  84.  
  85.     //    Create a new print job.
  86.     CPrintCX *pPrint = new CPrintCX(pUrl);
  87.  
  88.     //    Set up the print job.
  89.     //    Here, basically we need to do the necessary work that AFX
  90.     //        normally does to generate a proper print DC.
  91.     pPrint->m_pcpiPrintJob = new CPrintInfo;
  92.  
  93.     //    Wether or not we'll actually continue with this.
  94.     BOOL bFailure = FALSE;
  95.  
  96.     //    Do the print setup process by manually fetching the DC.
  97.     TRY    {
  98.         //  Are we attempting the default printer or do we already know which printer.
  99.         if(pPrinter == NULL || pDriver == NULL || pPort == NULL)    {
  100.             //  Use a default, if we can figure one out.
  101.             if (!theApp.GetPrinterDeviceDefaults(&pPrint->m_pcpiPrintJob->m_pPD->m_pd))  {
  102.                 AfxThrowResourceException();
  103.             }
  104.  
  105.             if (pPrint->m_pcpiPrintJob->m_pPD->m_pd.hDC == NULL) {
  106.                 // call CreatePrinterDC if DC was not created by above
  107.                 if (pPrint->m_pcpiPrintJob->m_pPD->CreatePrinterDC() == NULL)    {
  108.                     AfxThrowResourceException();
  109.                 }
  110.                 pPrint->m_hdcPrint = pPrint->m_pcpiPrintJob->m_pPD->m_pd.hDC;
  111.             }
  112.         }
  113.         else    {
  114.             if(!(pPrint->m_hdcPrint = ::CreateDC(pDriver, pPrinter, pPort, NULL)))   {
  115.                 AfxThrowResourceException();
  116.             }
  117.         }
  118.  
  119.         //    Set up the DC and print info.
  120.         pPrint->m_pcpiPrintJob->m_pPD->m_pd.nFromPage = 1;
  121.         pPrint->m_pcpiPrintJob->m_pPD->m_pd.nToPage = (unsigned short)-1;
  122.         pPrint->m_pcpiPrintJob->m_pPD->m_pd.nCopies = 1;    
  123.     }
  124.     CATCH(CException, e)    {
  125.         //    View went away while print dialog was up and caused a GPF.
  126.         //    This isn't an elegant fix.
  127.         bFailure = TRUE;
  128.     }
  129.     END_CATCH
  130.  
  131.     if(bFailure)    {
  132.         //    We're not going to be printing, user hit cancel.
  133.         pPrint->DestroyContext();
  134.         NET_FreeURLStruct(pUrl);
  135.         return;
  136.     }
  137.  
  138.     //    Gleen relevant information from the CDC and the CPrintInfo.
  139.     pPrint->Initialize(FALSE);
  140.  
  141.     //    Ready to split off and do the print job.
  142.     pPrint->CommencePrinting(pUrl);
  143.  
  144.     //    We leave the context all alone, it will eventually destroy
  145.     //        itself when the print job is completed.
  146. }
  147.  
  148. void CPrintCX::PrintAnchorObject(URL_Struct *pUrl, CView *pView, SHIST_SavedData *pSavedData, char *pDisplayUrl) {
  149. //    Purpose:    Indirect constructor for CPrintCX objects.
  150. //    Arguments:    pUrl    The URL to print.
  151. //                pView    The view originating the print request.
  152. //              pSavedData  The form element data we should copy.
  153. //    Returns:    void
  154. //    Comments:    This function effectively takes a print job and moves
  155. //                    it outside of the view by putting it into a new
  156. //                    context.
  157. //    Revision History:
  158. //        05-27-95    created GAB
  159.  
  160.     //    Create a new print job.
  161.     CPrintCX *pPrint = new CPrintCX(pUrl, pSavedData, pDisplayUrl);
  162.  
  163.     //    Set up the print job.
  164.     pPrint->m_pcpiPrintJob = new CPrintInfo;
  165.  
  166.     //    Wether or not we'll actually continue with this.
  167.     BOOL bFailure = FALSE;
  168.  
  169.     //    Do the normal print setup process thorugh a print dialog.
  170.     int iCLSID;
  171.     NPEmbeddedApp *pPlugins;
  172.     TRY    {
  173.         //  CACHE some info while we're safe with the view going away.
  174.         MWContext *pViewContext = ((CNetscapeView*)pView)->GetContext()->GetContext();
  175.  
  176.         // The mfc print dlg code uses our hidden frame for the owner.  The owner should
  177.         // be the active frame (or one of its popups).  Otherwise the frame is not disabled,
  178.         // effectively removing the modal aspect of the dialog.
  179.         CWnd *pSaveWnd = theApp.m_pActiveWnd;
  180.         theApp.m_pActiveWnd = CWnd::GetActiveWindow();
  181.       
  182.         if(pView->DoPreparePrinting(pPrint->m_pcpiPrintJob) == FALSE)    {
  183.             bFailure = TRUE;
  184.         }
  185.         else if(pPrint->m_pcpiPrintJob->m_pPD == NULL ||
  186.             pPrint->m_pcpiPrintJob->m_pPD->m_pd.hDC == NULL)    {
  187.  
  188.             //  Whoa!  DoPreparePrinting succeeded, but there is no DC???
  189.             //  This happens when a printer driver is installed for a network
  190.             //      printer (like a NetWare printer), and the user is not
  191.             //      logged into that network.
  192.             //  Give the user some type of error....
  193.  
  194.             theApp.m_pActiveWnd = pSaveWnd;
  195.             
  196.             CString temp;
  197.             temp.LoadString(IDS_CANTPRINT_LOGIN);
  198.             FE_Alert(pViewContext, temp);
  199.  
  200.             bFailure = TRUE;
  201.         }
  202.         theApp.m_pActiveWnd = pSaveWnd;    
  203.         
  204.         //  If the context is no longer in the list of contexts, get out as the view is gone.
  205.         if(XP_IsContextInList(pViewContext))    {
  206.             iCLSID = INTL_DefaultDocCharSetID(pViewContext);
  207.             pPlugins = ((CNetscapeView*)pView)->GetContext()->GetContext()->pluginList;
  208.         }
  209.         else    {
  210.             //  Fail now, the view is gone.
  211.             bFailure = TRUE;
  212.         }
  213.     }
  214.     CATCH(CException, e)    {
  215.         //    View went away while print dialog was up and caused a GPF.
  216.         //    This isn't an elegant fix.
  217.         bFailure = TRUE;
  218.     }
  219.     END_CATCH
  220.  
  221.     if(bFailure)    {
  222.         //    We're not going to be printing, user hit cancel.
  223.         pPrint->DestroyContext();
  224.         NET_FreeURLStruct(pUrl);
  225.         return;
  226.     }
  227.  
  228.     //    Set up the DC.
  229.     pPrint->m_hdcPrint = pPrint->m_pcpiPrintJob->m_pPD->m_pd.hDC;
  230.  
  231.     //    Gleen relevant information from the CDC and the CPrintInfo.
  232.     pPrint->Initialize(FALSE);
  233.  
  234.     // Pass old document charset id to print context
  235.     // This will make i18n converter do right thing for each context
  236.     pPrint->m_iCSID = iCLSID;
  237.  
  238.     if(    iCLSID != CS_LATIN1)
  239.     {
  240.         INTL_CharSetInfo print_csi = LO_GetDocumentCharacterSetInfo(pPrint->GetContext());
  241.         INTL_SetCSIDocCSID(print_csi, iCLSID);
  242.         INTL_SetCSIWinCSID(print_csi, INTL_DocToWinCharSetID(iCLSID));
  243.     }
  244.     //    Ready to split off and do the print job.
  245.     pPrint->CommencePrinting(pUrl);
  246.  
  247.     //    We leave the context all alone, it will eventually destroy
  248.     //        itself when the print job is completed.
  249. }
  250.  
  251. void CPrintCX::PreviewAnchorObject(CPrintCX *& pPreview, URL_Struct *pUrl, CView *pView, CDC *pDC, 
  252.                                    CPrintInfo *pInfo, SHIST_SavedData *pSavedData, char *pDisplayUrl)
  253. {
  254. //    Purpose:    Indirect constructor for CPrintCX objects doing preview.
  255. //    Arguments:    pPreview    A reference to a pointer which will will assign in the
  256. //                                context just prior to the network load.
  257. //                pAnchor    The URL to print.
  258. //                pHist    The history entry of the print job in the other context.
  259. //                pView    The view originating the print request.
  260. //                pDC        The DC of the preview (we don't use our own).
  261. //                pInfo    The print job information.
  262. //              pSavedData  Form element data we should copy.
  263. //    Returns:    CPrintCX    The print context doing the preview (we won't
  264. //                    be destroying ourselves, they will be destroying us).
  265. //    Comments:    This function effectively takes a print job and moves
  266. //                    it outside of the view by putting it into a new
  267. //                    context.
  268. //                pPreview is needed as a reference and not a retval since assignment
  269. //                    of the variable needs to happen before we return (reentrancy
  270. //                    problems in the calling function avoidance).
  271. //    Revision History:
  272. //        06-14-95    created GAB
  273.  
  274.     //    Create a new print job.
  275.     CPrintCX *pPrint = new CPrintCX(pUrl, pSavedData, pDisplayUrl);
  276.  
  277.     //    Set up the print job.
  278.     pPrint->m_bPreview = TRUE;
  279.     pPrint->m_previewDC = pDC;
  280.     pPrint->m_pcpiPrintJob = pInfo;
  281.  
  282.     //    Set our preview view.
  283.     pPrint->m_pPreviewView = pView;
  284.  
  285.     //    Get information from the CDC and CPrintInfo.
  286.     pPrint->Initialize(FALSE);
  287.  
  288.     //    Assign what used to be the return value before we actually do the load
  289.     //        from the network.
  290.     //    We leave the context all alone, it will eventually get destroyed
  291.     //        by those which created us.
  292.     pPreview = pPrint;
  293.  
  294.     // Pass old document charset id to print context
  295.     // This will make i18n converter do right thing for each context
  296.     MWContext *context = ((CNetscapeView*)pView)->GetContext()->GetContext();
  297.     pPrint->m_iCSID = INTL_DefaultDocCharSetID(context);
  298.  
  299.     if(    pPrint->m_iCSID != CS_LATIN1) 
  300.     {
  301.         INTL_CharSetInfo view_csi = LO_GetDocumentCharacterSetInfo(context);
  302.         INTL_CharSetInfo print_csi = LO_GetDocumentCharacterSetInfo(pPrint->GetContext());
  303.         INTL_SetCSIDocCSID(print_csi, INTL_GetCSIDocCSID(view_csi));
  304.         INTL_SetCSIWinCSID(print_csi, INTL_GetCSIWinCSID(view_csi));
  305.     }
  306.  
  307.     pPrint->CommencePrinting(pUrl);
  308. }
  309.  
  310. void CPrintCX::ScreenToPrint(POINT* point, int num)
  311. {
  312.     POINT *tp = point;
  313.     for (int i = 0; i < num; i++, tp++) {
  314.         tp->x = tp->x * (printRes.cx / screenRes.cx);
  315.         tp->y = tp->y * (printRes.cy / screenRes.cy);
  316.     }    
  317. }
  318.  
  319. CPrintCX::CPrintCX(URL_Struct *pUrl, SHIST_SavedData *pSavedData, char *pDisplayUrl)    {
  320. //    Purpose:    Construct a context for printing.
  321. //    Arguments:    pAnchor    The anchor we're printing
  322. //              pSavedData  The form data we want to copy to the print context.
  323. //              pDisplayUrl The URL text to display in header/footer
  324. //    Returns:    none
  325. //    Comments:    Sets the context type, etc.
  326. //    Revision History:
  327. //        05-27-95    created GAB
  328.  
  329.      TRACE("Creating CPrintCX %p\n", this);
  330.  
  331.     //  Clear URL position.
  332.     //  If we don't, when the page is scrolled we can't print -- weird.
  333.     //  Do not handle named anchors (strip them out), same reasons.
  334.     if(pUrl)    {
  335.         pUrl->position_tag = 0;
  336.         if(pUrl->address) {
  337.             if(strrchr(pUrl->address, '#')) {
  338.                 *strrchr(pUrl->address, '#') = '\0';
  339.             }
  340.         }
  341.     }
  342.  
  343.     // this is a hack to save the layout data for embedlist.  For embed layout will
  344.     // make a copy of the pSavedData.  We need to free the memory here.
  345.     m_embedList = (lo_SavedEmbedListData*)pUrl->savedData.EmbedList;
  346.     m_cxType = Print;
  347.     GetContext()->type = MWContextPrint;
  348.  
  349.     m_hdcPrint = NULL;
  350.     m_pcpiPrintJob = NULL;
  351.     p_TimeOut = NULL;
  352.     //  Haven't printed anything yet.
  353.     m_iLastPagePrinted = 0;
  354.  
  355.     //    Save the anchor we're printing; might be used in DOCINFO
  356.     int len = strlen(pUrl->address);
  357.     m_pAnchor = new char[len + 1];
  358.  
  359.     XP_STRNCPY_SAFE(m_pAnchor, pUrl->address, len + 1);
  360.  
  361. #ifdef EDITOR
  362.     // This is the Url address we are want to display
  363.     // in header or footers. m_pAnchor may be a local temp file
  364.     if(pDisplayUrl && strrchr(pDisplayUrl, '#'))
  365.     {
  366.         *strrchr(pDisplayUrl, '#') = '\0';
  367.     }
  368.     m_pDisplayUrl = pDisplayUrl ? XP_STRDUP(pDisplayUrl) : NULL;
  369. #else
  370.     m_pDisplayUrl = NULL;
  371. #endif
  372.  
  373.     //    No status dialog as of yet.
  374.     m_pStatusDialog = NULL;
  375.  
  376.     //    User hasn't cancelled yet.
  377.     m_bCancel = FALSE;
  378.  
  379.     //    We start off blocking all display calls
  380.     m_iDisplayMode = BLOCK_DISPLAY;
  381.  
  382.     //    Are we a preview context?
  383.     m_bPreview = FALSE;
  384.     m_pPreviewView = NULL;
  385.  
  386.  
  387.     //    Do we need to call the start doc member yet again?
  388.     m_bNeedStartDoc = TRUE;
  389.  
  390.     //    How we end the document, in AbortDoc or EndDoc
  391.     //    Start off with aborting (no output).
  392.     m_bAbort = TRUE;
  393.  
  394.     m_bAllConnectionCompleteCalled = FALSE;
  395.     m_bFinishedLayoutCalled = FALSE;
  396.     m_bFormatStarted = FALSE;
  397.  
  398.     // Font used for Header and Footer, should depending on current docuemnt charset
  399.        m_hFont = NULL;
  400.     m_iFontCSID = CS_LATIN1;
  401.     m_iCSID = CS_LATIN1;
  402.  
  403.     m_pDrawable = NULL;
  404.     
  405.     m_lDocWidth = 0;
  406.     m_lDocHeight = 0;
  407.     m_bHandleCancel = FALSE;
  408.  
  409.     //  Finally, copy the form data if present.
  410.     if(pSavedData && pSavedData->FormList)  {
  411.         TRACE("Cloning form data for print job.\n");
  412.         LO_CloneFormData(pSavedData, GetDocumentContext(), pUrl);
  413.     }
  414. }
  415.  
  416. CPrintCX::~CPrintCX()    {
  417. //    Purpose:    Destruct a print context
  418. //    Arguments:    void
  419. //    Returns:    none
  420. //    Comments:    Clean up any printing resources allocated.
  421. //    Revision History:
  422. //        05-27-95    created GAB
  423.  
  424.     TRACE("Deleting CPrintCX %p\n", this);
  425.  
  426.     if(m_pStatusDialog != NULL)    {
  427.         m_pStatusDialog->DestroyWindow();
  428.         delete m_pStatusDialog;
  429.     }
  430.  
  431.     if (m_hFont) {
  432.         //  The font has correctly unselected itself from the DC
  433.         //      in the written code in this file, such that we do
  434.         //      not need to unselect it before deletion.
  435.         ::DeleteObject(m_hFont);
  436.         m_hFont = NULL;
  437.     }
  438.  
  439.  
  440.     if(m_cplCaptured.IsEmpty() == FALSE)    {
  441.         POSITION rIndex = m_cplCaptured.GetHeadPosition();
  442.         LTRB *pFreeMe;
  443.         while(rIndex != NULL)    {
  444.             pFreeMe = (LTRB *)m_cplCaptured.GetNext(rIndex);
  445.             delete pFreeMe;
  446.         }
  447.  
  448.         m_cplCaptured.RemoveAll();
  449.     }
  450.  
  451.     if(m_cplPages.IsEmpty() == FALSE)    {
  452.         POSITION rIndex = m_cplPages.GetHeadPosition();
  453.         LTRB *pFreeMe;
  454.         while(rIndex != NULL)    {
  455.             pFreeMe = (LTRB *)m_cplPages.GetNext(rIndex);
  456.             delete pFreeMe;
  457.         }
  458.  
  459.         m_cplPages.RemoveAll();
  460.     }
  461.  
  462.     if(IsPrintPreview() == FALSE)    {
  463.         //    Need to release our print job information.
  464.         //    If we didn't need to start a document, then we started one in some manner,
  465.         //        decide how we should end it.
  466.         if(m_bNeedStartDoc == FALSE)    {
  467.             if(m_bAbort == TRUE)    {
  468.                 ::AbortDoc(m_hdcPrint);
  469.             }
  470.             else    {
  471.                 ::EndDoc(m_hdcPrint);
  472.             }
  473.         }
  474.         if(m_hdcPrint)  {
  475.             ::DeleteDC(m_hdcPrint);
  476.         }
  477.  
  478.         delete m_pcpiPrintJob;
  479.     }
  480.     m_hdcPrint = NULL;
  481.     m_pcpiPrintJob = NULL;
  482.  
  483.     if(m_pAnchor)   {
  484.         delete [] m_pAnchor;
  485.         m_pAnchor = NULL;
  486.     }
  487.     XP_FREEIF(m_pDisplayUrl);
  488.  
  489.     if (m_pDrawable) {
  490.         delete m_pDrawable;
  491.         m_pDrawable = NULL;
  492.     }
  493.  
  494.     // MWH - this is a hack to free the embed list that layout make copy from the original
  495.     // SavedData.  I removed the freeing from lib\layout\layfree.c lo_FreeDocumentEmbedListData.
  496.     // and free the data here.  This will fix an OLE printing problem.  The problem is when a .doc file
  497.     // is on the net, i.e. http://....//xxx.doc.  When layout free the EmbedList in 
  498.     // lo_FreeDocumentEmbedListData will cause the page not printed.  Since for printing we need
  499.     // to use the cached data.
  500.  
  501.     if (m_embedList && (m_embedList->embed_data_list != NULL)) {
  502.         int32 i;
  503.         lo_EmbedDataElement* embed_data_list;
  504.  
  505.         PA_LOCK(embed_data_list, lo_EmbedDataElement*, m_embedList->embed_data_list);
  506.         for (i=0; i < m_embedList->embed_count; i++)
  507.         {
  508.             if (embed_data_list[i].freeProc && embed_data_list[i].data)
  509.                 (*(embed_data_list[i].freeProc))(GetContext(), embed_data_list[i].data);
  510.         }
  511.         PA_UNLOCK(m_embedList->embed_data_list);
  512.         PA_FREE(m_embedList->embed_data_list);
  513.  
  514.         m_embedList->embed_count = 0;
  515.         m_embedList->embed_data_list = NULL;
  516.  
  517.     }
  518.     if (p_TimeOut) {
  519.         FE_ClearTimeout(p_TimeOut);  // kill the timer.
  520.         p_TimeOut = 0;
  521.     }
  522. }
  523.  
  524. HDC CPrintCX::GetAttribDC()
  525. {
  526.     HDC hRetval = NULL;
  527.     if(IsPrintPreview())    {
  528.         hRetval = m_previewDC->m_hAttribDC;
  529.     }
  530.     else    {
  531.         hRetval = m_hdcPrint;
  532.     }
  533.  
  534.     return(hRetval);
  535. }
  536.  
  537.  
  538. void CPrintCX::ReleaseContextDC(HDC pDC)    {
  539. //    Purpose:    Release a DC previously gotten through GetContextDC.
  540. //    Arguments:    pDC    The CDC to release.
  541. //    Returns:    void
  542. //    Comments:    We don't do anything here, as the CDC is static
  543. //                    throughout the print job.
  544. //    Revision History:
  545. //        05-27-95    created GAB
  546. }
  547.  
  548. void CPrintCX::Initialize(BOOL bOwnDC, RECT *pRect, BOOL bInitialPalette, BOOL bNewMemDC)    {
  549. //    Purpose:    Initialize any print parameters from preferences and
  550. //                    print setup.
  551. //    Arguments:    void
  552. //    Returns:    void
  553. //    Comments:    All instance specific print parameters should be
  554. //                    initialized here.
  555. //                A CDC is required to do this.
  556. //    Revision History:
  557. //        05-30-95    created GAB
  558.  
  559.     //    Call the base
  560.     HDC hdc = GetContextDC();
  561. #ifdef XP_WIN32
  562.     m_hOrgPrintDC = hdc;
  563.     m_printBk = FALSE;
  564.     m_hOffscrnDC = 0;
  565. #endif
  566.  
  567.     CDCCX::Initialize(bOwnDC, pRect, bInitialPalette, bNewMemDC);
  568.  
  569.     CDC * pAttrDC;
  570.     pAttrDC = theApp.m_pMainWnd->GetDC();
  571.     if (!IsPrintPreview())    {
  572.         SetMappingMode(hdc);
  573.         m_lConvertX = GetContext()->convertPixX = 1440 / pAttrDC->GetDeviceCaps(LOGPIXELSX);
  574.         m_lConvertY = GetContext()->convertPixY = 1440 / pAttrDC->GetDeviceCaps(LOGPIXELSY);
  575.         screenRes.cx = 0; // we don't care.
  576.         screenRes.cy = 0;
  577.         printRes.cx = 0;
  578.         printRes.cy = 0;
  579. #ifdef XP_WIN32
  580.         PREF_GetBoolPref("browser.print_background",&m_printBk);
  581. #endif
  582.     }
  583.     else {
  584.         screenRes.cx = ::GetDeviceCaps(m_previewDC->GetSafeHdc(), LOGPIXELSX);
  585.         screenRes.cy = ::GetDeviceCaps(m_previewDC->GetSafeHdc(), LOGPIXELSY);
  586.         printRes.cx = ::GetDeviceCaps(m_previewDC->m_hAttribDC, LOGPIXELSX);
  587.         printRes.cy = ::GetDeviceCaps(m_previewDC->m_hAttribDC, LOGPIXELSY);
  588.         m_lConvertX = GetContext()->convertPixX = printRes.cx  / screenRes.cx;
  589.         m_lConvertY = GetContext()->convertPixY = printRes.cy / screenRes.cy;
  590.  
  591.     }
  592.     //    Have our FE conversions (class local for speed) be the same.
  593.     ApiPageSetup(api,0);
  594.  
  595.  
  596.     //    Determine and set the page size.
  597.     SIZE csPageSize;
  598.     api->GetMargins ( &m_lLeftMargin, &m_lRightMargin, &m_lTopMargin, &m_lBottomMargin );
  599.     if (!IsPrintPreview()) {
  600.         csPageSize.cx = ::GetDeviceCaps(hdc, HORZRES);
  601.         csPageSize.cy = ::GetDeviceCaps(hdc, VERTRES);
  602. #ifdef XP_WIN32
  603.         // MWH - The calculation below is to prepare a memory DC for printing
  604.         // background.  I can not use printer's resoultion to calculate the size of bitmap
  605.         // for this memoryDC, because 600 dpi * 24 bit/pixel * width * height will cause
  606.         // the bitmap to be too big.  I'm going to use the screen resolution here
  607.         // to figure the size of the bitmap for my memoryDC.  When it is time to 
  608.         // display the bitmap.  DisplayPixmap will scale the image from 96 dpi to
  609.         // 600 dpi.
  610.         if (m_printBk) {
  611.             int xres, yres;
  612.             xres = pAttrDC->GetDeviceCaps(LOGPIXELSX);
  613.             yres = pAttrDC->GetDeviceCaps(LOGPIXELSY);
  614.             int width, height;
  615.             width = (csPageSize.cx +  GetDeviceCaps(hdc, LOGPIXELSX)) / GetDeviceCaps(hdc, LOGPIXELSX);
  616.             height = (csPageSize.cy +  GetDeviceCaps(hdc, LOGPIXELSY)) / GetDeviceCaps(hdc, LOGPIXELSY);
  617.             m_offscrnWidth = width * xres;
  618.             m_offscrnHeight = height * yres;
  619.  
  620.             m_hOffscrnDC = ::CreateCompatibleDC(pAttrDC->GetSafeHdc());
  621.             if ( m_hOffscrnDC) {
  622.                 BITMAPINFO lpbmi;
  623.                 lpbmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  624.                 lpbmi.bmiHeader.biWidth = m_offscrnWidth;
  625.                 lpbmi.bmiHeader.biHeight = m_offscrnHeight;
  626.                 lpbmi.bmiHeader.biPlanes = 1;
  627.                 lpbmi.bmiHeader.biBitCount = 24;
  628.                 lpbmi.bmiHeader.biCompression = BI_RGB;
  629.                 lpbmi.bmiHeader.biSizeImage = 0;
  630.                 lpbmi.bmiHeader.biXPelsPerMeter = 0;
  631.                 lpbmi.bmiHeader.biYPelsPerMeter = 0;
  632.  
  633.                 lpbmi.bmiHeader.biClrUsed = 0;        // default value    
  634.                 lpbmi.bmiHeader.biClrImportant = 0;   // all important
  635.                 void* ptr;
  636.                 m_hOffScrnBitmap = ::CreateDIBSection(pAttrDC->GetSafeHdc(),&lpbmi, DIB_RGB_COLORS,  
  637.                     &ptr, NULL, NULL);
  638.  
  639.                 ::SetMapMode(m_hOffscrnDC, MM_TEXT);
  640.                 if (m_hOffScrnBitmap) {
  641.                     m_saveBitmap = (HBITMAP)::SelectObject(m_hOffscrnDC, ( HGDIOBJ)m_hOffScrnBitmap );
  642.                 }
  643.                 else {
  644.                     m_printBk = FALSE;
  645.                     ::DeleteDC(m_hOffscrnDC);
  646.                     m_hOffscrnDC = 0;
  647.  
  648.                 }
  649.             }
  650.             else {// Can not display Background, just print forground instead.
  651.                 m_printBk = FALSE;
  652.             }
  653.         }
  654. #endif
  655.         ::DPtoLP(hdc, (POINT*)&csPageSize, 1);
  656.     }
  657.     else {
  658.         m_lLeftMargin = (m_lLeftMargin * printRes.cx) / 1440;
  659.         m_lRightMargin = (m_lRightMargin * printRes.cx) / 1440;
  660.         m_lTopMargin = (m_lTopMargin * printRes.cy) / 1440;
  661.         m_lBottomMargin = (m_lBottomMargin * printRes.cy) / 1440;
  662.  
  663.         csPageSize.cx = ::GetDeviceCaps(m_previewDC->m_hAttribDC, HORZRES);
  664.          csPageSize.cy = ::GetDeviceCaps(m_previewDC->m_hAttribDC, VERTRES);
  665.  
  666.     }
  667.  
  668.     theApp.m_pMainWnd->ReleaseDC(pAttrDC);
  669.     ReleaseContextDC(hdc);
  670.     m_lPageHeight = csPageSize.cy;
  671.     m_lPageWidth = csPageSize.cx;
  672.     m_lWidth = csPageSize.cx - (m_lRightMargin + m_lLeftMargin);
  673.     m_lHeight = csPageSize.cy - (m_lBottomMargin + m_lTopMargin);
  674.  
  675.     CreateHeaderFooterFont();
  676.  
  677.     TEXTMETRIC tm;
  678.     if(m_hFont) {
  679.         HFONT hOldFont = (HFONT)::SelectObject(hdc, m_hFont);
  680.         ::GetTextMetrics(hdc, &tm);
  681.         ::SelectObject(hdc, hOldFont);
  682.     }
  683.     else {
  684.         AfxMessageBox(IDS_NOPRINTERFONT);
  685.         ::GetTextMetrics(hdc, &tm);
  686.     }
  687.  
  688.     m_iMaxWidth = CASTINT(( m_lPageWidth / tm.tmAveCharWidth ) / 2);
  689.  
  690.     //    What are we doing about colors?
  691.     m_bBlackText = api->BlackText();
  692.     m_bBlackLines = api->BlackLines();
  693.  
  694.     //    What are we doing about drawing?
  695.     m_bSolidLines = api->SolidLines();
  696.     m_bBitmaps = TRUE;
  697.     m_bBackground = FALSE;
  698.     m_bReverseOrder = api->ReverseOrder() ? TRUE : FALSE;
  699.  
  700.     //    Headers and footers?
  701.     m_bNumber = api->Footer() ? TRUE : FALSE;
  702.     m_bTitle = api->Header() ? TRUE : FALSE;
  703. }
  704.  
  705. BOOL CPrintCX::AdjustRect(LTRB& Rect)
  706. {
  707.     LTRB orgRect(Rect);
  708.     //  Adjust for margins.
  709.     Rect.left += m_lLeftMargin;
  710.     Rect.top += m_lTopMargin;
  711.     Rect.right += m_lLeftMargin;
  712.     Rect.bottom += m_lTopMargin;
  713.     //    Adjust the Y coordinate for the current page we are printing.
  714.     POSITION rIndex = m_cplPages.FindIndex(m_pcpiPrintJob->m_nCurPage - 1);
  715.     if(rIndex == NULL)    {
  716.         //    This could be called during incremental display.
  717.         //    Don't allow drawing at that point.
  718.         return(FALSE);
  719.     }
  720.     LTRB *pPage = (LTRB *)m_cplPages.GetAt(rIndex);
  721.     Rect.top -= pPage->top;
  722.     Rect.bottom -= pPage->top;
  723.  
  724.     //    Form a Rect of the current page, in the same coords as the element.
  725.     //    The bottom of the page is determined on a page by page basis.
  726.     LTRB Page;
  727.     Page.left = m_lLeftMargin;
  728.     Page.top = m_lTopMargin;
  729.     Page.right = Page.left + pPage->Width();
  730.     Page.bottom = Page.top + pPage->Height();
  731.  
  732.     //    Part of this element must fall within these coordinates to be drawn.
  733.     //    Clipping will take care of partial display.
  734.     if(Rect.top >= Page.bottom || Rect.bottom <= Page.top ||
  735.         Rect.right <= Page.left || Rect.left >= Page.right)    {
  736.         if(CanBlockDisplay())    {
  737.             return(FALSE);
  738.         }
  739.     }
  740.     // MHW - if we are printing background image, and the current printing
  741.     // operation is to the temparary offscreen, need to addjust    the rect to 
  742.     // the coordinate according to the offscreen dc.
  743. #ifdef XP_WIN32
  744.     if (m_printBk && m_hdcPrint == m_hOffscrnDC) {
  745.         orgRect.top -= pPage->top;
  746.         orgRect.bottom -= pPage->top;
  747.         Rect.left = (orgRect.left + m_lConvertX) / m_lConvertX;
  748.         Rect.top = (orgRect.top + m_lConvertY)/ m_lConvertY;
  749.         Rect.right = (orgRect.right + m_lConvertX) / m_lConvertX;
  750.         Rect.bottom = (orgRect.bottom + m_lConvertY)/  m_lConvertY;
  751.  
  752.     }
  753. #endif
  754.     return (TRUE);
  755. }
  756.  
  757. BOOL CPrintCX::ResolveElement(LTRB& Rect, LO_FormElementStruct *pFormElement)    {
  758.     CDCCX::ResolveElement(Rect, pFormElement);
  759.     return AdjustRect(Rect);
  760. }
  761.  
  762. BOOL CPrintCX::ResolveElement(LTRB& Rect, int32 x, int32 y, int32 x_offset, int32 y_offset,
  763.                                 int32 width, int32 height)
  764. {
  765.     CDCCX::ResolveElement(Rect, x, y, x_offset, y_offset, width, height);
  766.     return AdjustRect(Rect);
  767. }
  768.  
  769. BOOL CPrintCX::ResolveElement(LTRB& Rect, NI_Pixmap *pImage, int32 lX, int32 lY, 
  770.                                 int32 orgx, int32 orgy, 
  771.                                 uint32 ulWidth, uint32 ulHeight)
  772. {
  773.     //    Call the base first.
  774.     CDCCX::ResolveElement(Rect, pImage, lX, lY, orgx, orgy, ulWidth, ulHeight);
  775.     return AdjustRect(Rect);
  776. }
  777.  
  778. BOOL CPrintCX::ResolveElement(LTRB& Rect, LO_EmbedStruct *pEmbed, int iLocation, Bool bWindowed)    {
  779.     //    Call the base first.
  780.     CDCCX::ResolveElement(Rect, pEmbed, iLocation, bWindowed);
  781.     return AdjustRect(Rect);
  782. }
  783.  
  784. BOOL CPrintCX::ResolveLineSolid()    {
  785.     return(m_bSolidLines);
  786. }
  787.  
  788. COLORREF CPrintCX::ResolveBGColor(unsigned uRed, unsigned uGreen, unsigned uBlue)    {
  789.     //    See if we're allowing the background color to be set.
  790.     if(m_bBackground == FALSE)    {
  791.         //    Nope, set it to be white.
  792.         return(RGB(255,255,255));
  793.     }
  794.     else    {
  795.         //    Do the default action.
  796.         return(CDCCX::ResolveBGColor(uRed, uGreen, uBlue));
  797.     }
  798. }
  799.  
  800. BOOL CPrintCX::ResolveHRSolid(LO_HorizRuleStruct *pHorizRule)    {
  801.     //    See if we're allowing 3D HRs.
  802.     if(m_bSolidLines == TRUE)    {
  803.         return(TRUE);
  804.     }
  805.     else    {
  806.         //    Do the default.
  807.         return(CDCCX::ResolveHRSolid(pHorizRule));
  808.     }
  809. }
  810.  
  811. void CPrintCX::ResolveTransparentColor(unsigned uRed, unsigned uGreen, unsigned uBlue)    {
  812.     //    See what we're doing with the background.
  813.     if(m_bBackground == FALSE)    {
  814.         //    Set it to white.
  815.         CDCCX::ResolveTransparentColor(255, 255, 255);
  816.     }
  817.     else    {
  818.         //    Set it to whatever.
  819.         CDCCX::ResolveTransparentColor(uRed, uGreen, uBlue);
  820.     }
  821. }
  822.  
  823. COLORREF CPrintCX::ResolveDarkLineColor()    {
  824.     //    See if we're drawing black lines.
  825.     if(m_bBlackLines == TRUE)    {
  826.         return(RGB(0,0,0));
  827.     }
  828.     else    {
  829.         //    Do the default.
  830.         return(CDCCX::ResolveDarkLineColor());
  831.     }
  832. }
  833.  
  834. COLORREF CPrintCX::ResolveLightLineColor()    {
  835.     //    See if we're drawing black lines.
  836.     if(m_bBlackLines == TRUE)    {
  837.         return(RGB(0,0,0));
  838.     }
  839.     else    {
  840.         //    Do the default.
  841.         return(CDCCX::ResolveLightLineColor());
  842.     }
  843. }
  844.  
  845. COLORREF CPrintCX::ResolveBorderColor(LO_TextAttr *pAttr)    {
  846.     //    See if we're drawing black lines.
  847.     if(m_bBlackLines == TRUE)    {
  848.         return(RGB(0,0,0));
  849.     }
  850.     else    {
  851.         //    Do the default.
  852.         return(CDCCX::ResolveBorderColor(pAttr));
  853.     }
  854. }
  855.  
  856. COLORREF CPrintCX::ResolveTextColor(LO_TextAttr *pAttr)    {
  857.     //    If we're only printing black text, then only select the color black.
  858.     //    Otherwise, simply call the base.
  859.     COLORREF rgbRetval;
  860.     if(m_bBlackText == TRUE)    {
  861.         rgbRetval = RGB(0,0,0);
  862.     }
  863.     else    {
  864.         rgbRetval = CDCCX::ResolveTextColor(pAttr);
  865.     }
  866.  
  867.     return(rgbRetval);
  868. }
  869.  
  870. void CPrintCX::DisplayIcon(int32 x, int32 y, int icon_number)
  871. {
  872.     if (GetDisplayMode() == BLOCK_DISPLAY)
  873.         return;
  874.     else if (GetDisplayMode() == CAPTURE_POSITION)    {
  875.         int32 lOrgX, lOrgY;
  876.         int32 width, height;
  877.  
  878.         GetDrawingOrigin(&lOrgX, &lOrgY);
  879.         GetIconDimensions(&width, &height, icon_number);
  880.         
  881.         width *= m_lConvertX;
  882.         height *= m_lConvertY;
  883.  
  884.         //    Capture the coordinates of this element.
  885.         Capture(x + lOrgX, y + lOrgY, width, height);
  886.  
  887.         //    We don't actually allow display while we are capturing the area.
  888.         return;
  889.     }
  890.  
  891.     //    Block drawing of icons if we don't allow it.
  892.     //    They might be attempting to determine the size of an icon.
  893.     if(m_bBitmaps == TRUE || x != NULL || y != NULL)    {
  894. #ifdef XP_WIN32
  895.         if (m_printBk && !IsPrintPreview()) {
  896.             SubOffscreenPrintDC();
  897.             CDCCX::DisplayIcon(x, y, 
  898.                                 icon_number);
  899.             RestorePrintDC();
  900.         }
  901. #endif
  902.         CDCCX::DisplayIcon(x, y, 
  903.                             icon_number);
  904.     }
  905. }
  906.  
  907. void CPrintCX::LayoutNewDocument(MWContext *pContext, URL_Struct *pURL, int32 *pWidth, int32 *pHeight, int32 *pmWidth, int32 *pmHeight)    {
  908. //    Purpose:    This formally sets up margins and such with the Layout engine.
  909. //    Arguments:    pContext    The context under which this is loading.
  910. //                pURL        The loading URL.
  911. //                pWidth        The width of the page (adjust for margins).
  912. //                pHeight        The height of the page (we report this as huge)
  913. //                                so that we can figure it manually later.
  914. //                pmWidth        Margin width, we report as 0.
  915. //                pmHeight    Margin height, we report as 0.
  916. //    Returns:    void
  917. //    Comments:    The origin of the print job must always remain 0,0 for this
  918. //                    to work correctly.
  919. //                It is important to note that we are handling all margins
  920. //                    ourselves rather than letting the layout engine attempt
  921. //                    to use them.  This is done for finer control though harder.
  922. //    Revision History:
  923. //        06-09-95    created GAB
  924.  
  925.     //    Call the base, though we'll override any values.
  926.     CDCCX::LayoutNewDocument(pContext, pURL, pWidth, pHeight, pmWidth, pmHeight);
  927.  
  928.     //    Assign the page width, but adjust for our internal margins.
  929.     //    This should be the only place where we use the right margin.
  930.     *pWidth = m_lPageWidth - (m_lLeftMargin + m_lRightMargin);
  931.  
  932.     //    Assign the page height, but adjust for our internal margins.
  933.     //    This should be the only place where we use the bottom margin.
  934.     *pHeight = m_lPageHeight - (m_lTopMargin + m_lBottomMargin);
  935.  
  936.     //    Make sure layout doesn't attempt to use any margins itself, regardless.
  937.     *pmWidth = 0;
  938.     *pmHeight = 0;
  939. }
  940.  
  941. void CPrintCX::CommencePrinting(URL_Struct *pUrl)    {
  942. //    Purpose:    Officially start a print job.
  943. //    Arguments:    pAnchor    The anchor for which to print.
  944. //    Returns:    void
  945. //    Comments:    This won't print forms with post data....
  946. //                This has always been the case in all versions.
  947. //                If such a need exists, I don't see what would be so
  948. //                    hard about doing it, but layout has mythical
  949. //                    tendencies to not handle this correctly.
  950. //    Revision History:
  951. //        05-30-95    created GAB
  952.  
  953.     //    Create the print status dialog if not in preview.
  954.     if(IsPrintPreview() == FALSE)    {
  955.         m_pStatusDialog = new CPrintStatusDialog(NULL, this);
  956.         m_pStatusDialog->m_csLocation = pUrl->address;
  957.         WFE_CondenseURL(m_pStatusDialog->m_csLocation, 40, FALSE);
  958.         m_pStatusDialog->Create(CPrintStatusDialog::IDD, NULL);
  959.         StartDoc();
  960.  
  961.         //    Also attempt to start the document for the first time.
  962.         //    This is to help the cannot start print job problem, we are experienced
  963.         //        with technical diffculties.
  964.     }
  965.  
  966.     MWContext *pContext = GetContext();    
  967.     HDC hdc = GetContextDC();    
  968.     CL_Drawable *pPrinterDrawable = NULL;
  969.     
  970.     // Create a drawable that represents the printer
  971.     m_pDrawable = new CPrinterDrawable(hdc, m_lLeftMargin, m_lRightMargin,
  972.                                        m_lTopMargin, m_lBottomMargin, this);
  973.     if (m_pDrawable)
  974.         pPrinterDrawable = CL_NewDrawable(CASTUINT(0), 
  975.                                           CASTUINT(0),
  976.                                           CL_PRINTER,
  977.                                           &wfe_drawable_vtable,
  978.                                           (void *)m_pDrawable);
  979.  
  980.     if (pPrinterDrawable) {
  981.         // Create a compositor for the printer context
  982.         // The window size is initially 0,0,0,0. It's modified when
  983.         // we know the size of the document.
  984.         pContext->compositor = CL_NewCompositor(pPrinterDrawable,
  985.                                                 NULL,
  986.                                                 0, 0, 
  987.                                                 0, 0,
  988.                                                 0);
  989.     
  990.         if (pContext->compositor)
  991.             CL_SetCompositorDrawingMethod(pContext->compositor,
  992.                                           CL_DRAWING_METHOD_BACK_TO_FRONT_ONLY);
  993.         else
  994.             CL_DestroyDrawable(pPrinterDrawable);
  995.     }
  996.     else
  997.         pContext->compositor = NULL;
  998.     ReleaseContextDC(hdc);
  999.  
  1000.     //    Create the URL which will handle the load, and ask for it.
  1001.     GetUrl(pUrl, FO_CACHE_AND_PRINT);
  1002. }
  1003.  
  1004. CWnd *CPrintCX::GetDialogOwner() const    {
  1005. //    Purpose:    Returns the owner of any dialogs which we will create.
  1006. //    Arguments:    void
  1007. //    Returns:    CWnd *    The dialog owner
  1008. //    Comments:    Returns the print status dialog as the owner, so it
  1009. //                    must be present for this to work.
  1010. //    Revision History:
  1011. //        05-30-95    created GAB
  1012.  
  1013.     if(IsPrintPreview() == FALSE)    {
  1014.         return(m_pStatusDialog);
  1015.     }
  1016.     else    {
  1017.         return(((CGenericView *)m_pPreviewView)->GetFrame()->GetFrameWnd());
  1018.     }
  1019. }
  1020.  
  1021. int CPrintCX::StartDoc()    {
  1022.     //    For modularity purposes only.
  1023.     //    This is called from several places.
  1024.  
  1025.     //    If we're in preview, or if we've already started the document, just
  1026.     //        return success.
  1027.     if(IsPrintPreview() == TRUE || m_bNeedStartDoc == FALSE || IsDestroyed() == TRUE)    {
  1028.         //    Don't do this if we don't need it.
  1029.         return(0);
  1030.     }
  1031.  
  1032.     //    Attempt to start the print job.
  1033.     HDC pDC = GetContextDC();
  1034.  
  1035.     //    Set the docinfo structure up.
  1036.     //    Be sure to first clear the structure to 0, this may or may
  1037.     //        not cause StartDoc to fail unexplainably if we don't.
  1038.     //    MSDN: Q135119
  1039.     memset(&m_docInfo, 0, sizeof(m_docInfo));
  1040.     m_docInfo.cbSize = sizeof(m_docInfo);
  1041.     MWContext *pct = GetContext();
  1042.     // DocName may be the "DisplayUrl" used by Composer when
  1043.     //  we are printing/previewing a temporary file URL 
  1044.     m_docInfo.lpszDocName = ((pct->title != NULL) ? pct->title : 
  1045.                               (m_pDisplayUrl ? (const char *)m_pDisplayUrl : (const char *)m_pAnchor));
  1046.     m_docInfo.lpszOutput = NULL;
  1047.  
  1048.     //    Hold the document name to 31 characters.
  1049.     CString cs31 = m_docInfo.lpszDocName;
  1050.     if(cs31.GetLength() > 31)    {
  1051.         cs31.ReleaseBuffer(31);
  1052.     }
  1053.     m_docInfo.lpszDocName = (const char *)cs31;
  1054.  
  1055.     int iRetval = ::StartDoc(pDC, &m_docInfo);
  1056.  
  1057.     if(iRetval >= 0)    {
  1058.         //    We got through.
  1059.         m_bNeedStartDoc = FALSE;
  1060.     }
  1061.     ReleaseContextDC(pDC);
  1062.  
  1063.     return(iRetval);
  1064. }
  1065.  
  1066. // Record document height and width
  1067. void CPrintCX::SetDocDimension(MWContext *pContext, int iLocation, int32 lWidth, int32 lHeight)   {
  1068.     CDCCX::SetDocDimension(pContext, iLocation, lWidth, lHeight);
  1069.     
  1070.     m_lDocWidth = lWidth;
  1071.     m_lDocHeight = lHeight;
  1072. }
  1073.  
  1074. void CPrintCX::CapturePositions()
  1075. {
  1076.     CL_Compositor *compositor;
  1077.     
  1078.  
  1079.     //  For capturing, we want all the elements in a document to display.
  1080.     //  Since we can't size the compositor window to be the size of the
  1081.     //  document (the compositor window must have coordinates that fit into
  1082.     //  a 16-bit coordinate space), we take snapshots. In other words,
  1083.     //  we make the compositor window the size of the physical page and
  1084.     //  keep scrolling down till capture the entire document.
  1085.     compositor = GetContext()->compositor;
  1086.     if (compositor) {
  1087.         XP_Rect rect;
  1088.         int n;
  1089.  
  1090.         // The compositor window is the size of the page (minus margins)
  1091.         CL_ResizeCompositorWindow(compositor, m_lWidth, m_lHeight);
  1092.         
  1093.         rect.left = 0;
  1094.         rect.top = 0;
  1095.         rect.right = m_lWidth;
  1096.         rect.bottom = m_lHeight;
  1097.  
  1098.         // We display all the elements twice. This is to deal with the
  1099.         // fact that certain elements (images, embeds and applets for
  1100.         // instance) are always displayed in a compositor pass after
  1101.         // the containing HTML content. We only capture during the
  1102.         // second pass.
  1103.         for (n = 0; n < 2; n++) {
  1104.             // Till we've covered the entire document, we keep scrolling
  1105.             // down and taking snapshots
  1106.             for (m_lCaptureScrollOffset = 0; 
  1107.                  m_lCaptureScrollOffset <= m_lDocHeight; 
  1108.                  m_lCaptureScrollOffset += m_lHeight) {
  1109.                 CL_ScrollCompositorWindow(compositor, 
  1110.                                           0, m_lCaptureScrollOffset);
  1111.                 CL_RefreshWindowRect(GetContext()->compositor, &rect);
  1112.             }
  1113.             m_iDisplayMode = CAPTURE_POSITION;
  1114.         }
  1115.  
  1116.         CL_ScrollCompositorWindow(compositor, 0, 0);
  1117.     }
  1118.     else {
  1119.         //    Set that we want all  Display* calls to capture document positions
  1120.         m_iDisplayMode = CAPTURE_POSITION;
  1121.         LO_RefreshArea(GetDocumentContext(), 0, 0, 0x7FFFFFFF, 0x7FFFFFFF);
  1122.     }
  1123. }
  1124.  
  1125. void CPrintCX::GetUrlExitRoutine(URL_Struct *pUrl, int iStatus, MWContext *pContext)
  1126. {
  1127.     /* bad status: finish printing now */
  1128.     if((iStatus < 0) && !m_bFormatStarted)
  1129.         FormatAndPrintPages(pContext);
  1130.  
  1131.     CDCCX::GetUrlExitRoutine(pUrl, iStatus, pContext);
  1132. }
  1133.  
  1134. static void DeferredDestroyPrintContext(void *cx)
  1135. {
  1136.     ((CPrintCX*)(cx))->p_TimeOut = 0;
  1137.     ((CPrintCX*)(cx))->CDCCX::DestroyContext();
  1138. }
  1139.  
  1140. /* Avoid destroying the document out from underneath layout when DestroyContext() is
  1141.    called (indirectly) from layout, as in FormatAndPrintPages() */
  1142. void CPrintCX::DestroyContext()    {
  1143.     m_bHandleCancel = TRUE;
  1144.     //Trun back off the display.
  1145.     m_iDisplayMode = BLOCK_DISPLAY;
  1146.     p_TimeOut = FE_SetTimeout(DeferredDestroyPrintContext, this, 0);
  1147. #ifdef XP_WIN32
  1148.     ::SelectObject(m_hOffscrnDC, ( HGDIOBJ)m_saveBitmap );
  1149.     ::DeleteObject(m_hOffScrnBitmap);
  1150.     if (m_hOffscrnDC)
  1151.         ::DeleteDC(m_hOffscrnDC);
  1152. #endif
  1153. }
  1154.  
  1155. void CPrintCX::FormatAndPrintPages(MWContext *pContext)    {
  1156.     //    Check to see if the user cancelled the job, if so, we're done.
  1157.     if(m_bCancel == TRUE )    {
  1158.         TRACE("Destroying canceled print job.\n");
  1159.         if (!m_bHandleCancel)
  1160.             DestroyContext();
  1161.         return;
  1162.     }
  1163.  
  1164.     m_bFormatStarted = TRUE;
  1165.  
  1166.     CapturePositions();
  1167.  
  1168.     CL_ResizeCompositorWindow(GetContext()->compositor, m_lWidth, m_lHeight);
  1169.  
  1170.     //      Now we're ready to actually start drawing the display elements
  1171.     m_iDisplayMode = DISPLAY;
  1172.         
  1173.     //    Do the entire print job now.
  1174.  
  1175.     //    Calculating page boundries.
  1176.     //    All layout information has been detained by the print job while
  1177.     //        loading the first time.
  1178.     FormatPages();
  1179.  
  1180.     //    If there are no pages, get out now.
  1181.     if(m_cplPages.IsEmpty() == TRUE)    {
  1182.         CString temp;
  1183.         temp.LoadString(IDS_NOPAGETOPRINT);
  1184.         FE_Alert(GetContext(), temp);
  1185.         if(IsPrintPreview() == FALSE)    {
  1186.             DestroyContext();
  1187.         }
  1188.         return;
  1189.     }
  1190.  
  1191.     //    One last try.
  1192.     //    Do we need to attempt to start the document?
  1193.     if(0 > StartDoc())    {
  1194.         CString temp;
  1195.         temp.LoadString(IDS_NOPRINTJOB);
  1196.         CFE_Alert(GetContext(), temp);
  1197.         DestroyContext();
  1198.         return;
  1199.     }
  1200.  
  1201.     //    If we're not in preview, then we do the real thing.
  1202.     if(IsPrintPreview() == FALSE)    {
  1203.         //    Attempt to start the print job.
  1204.         HDC pDC = GetContextDC();
  1205.  
  1206.         //    Set the callback function.
  1207.         ::SetAbortProc(pDC, PrintAbortProc);
  1208.  
  1209.         m_bAbort = FALSE;    //    We switch to wanting to use EndDoc now....
  1210.  
  1211.         //    Here is the main print loop.
  1212.         UINT uFromPage = m_pcpiPrintJob->GetFromPage();
  1213.         UINT uToPage = m_pcpiPrintJob->GetToPage();
  1214.         if(m_bReverseOrder) {
  1215.             uFromPage = m_pcpiPrintJob->GetToPage();
  1216.             uToPage = m_pcpiPrintJob->GetFromPage();
  1217.         }
  1218.         if(uFromPage > (UINT)m_cplPages.GetCount())   {
  1219.             uFromPage = m_cplPages.GetCount();
  1220.         }
  1221.         if(uToPage > (UINT)m_cplPages.GetCount())   {
  1222.             uToPage = m_cplPages.GetCount();
  1223.         }
  1224.  
  1225.         int iStep = uToPage >= uFromPage ? 1 : -1;
  1226.         for(m_pcpiPrintJob->m_nCurPage = uFromPage;
  1227.             m_pcpiPrintJob->m_nCurPage - iStep != uToPage;
  1228.             m_pcpiPrintJob->m_nCurPage += iStep)    {
  1229.  
  1230.             //    See if the user wanted to abort the print job.
  1231.             if(m_bCancel == TRUE)    {
  1232.                 m_bAbort = TRUE;
  1233.                 break;
  1234.             }
  1235.  
  1236.             //    See if the page we are about to print actually exists.
  1237.             //    If not, it's time to stop the print job.
  1238.             POSITION rIndex = m_cplPages.FindIndex(m_pcpiPrintJob->m_nCurPage - 1);
  1239.             if(rIndex == NULL)    {
  1240.                 //    Time to stop printing.  The specified page isn't found.
  1241.                 m_pcpiPrintJob->m_bContinuePrinting = FALSE;
  1242.             }
  1243.  
  1244.             //    See if we are to kick out of the print job (done).
  1245.             if(m_pcpiPrintJob->m_bContinuePrinting == FALSE)    {
  1246.                 break;
  1247.             }
  1248.  
  1249.             //    Let the DC know a new page is starting.
  1250.             if(0 > ::StartPage(pDC))    {
  1251.                 //    Some type of error occurred.
  1252.                 m_bAbort = TRUE;
  1253.                 break;
  1254.             }
  1255.  
  1256.             //    Print the page
  1257.             PrintPage(m_pcpiPrintJob->m_nCurPage);
  1258.  
  1259.             //    Let the DC know a page is ending.
  1260.             if(0 > ::EndPage(pDC))    {
  1261.                 //    Some type of error occurred.
  1262.                 m_bAbort = TRUE;
  1263.                 break;
  1264.             }
  1265.         }
  1266.  
  1267.         //    Set this to make sure everyone knows we aren't continuing to print.
  1268.         m_pcpiPrintJob->m_bContinuePrinting = FALSE;
  1269.  
  1270.         //    Done, remove this object.
  1271.         //    End doc or abort doc are called in the destructor.
  1272.         ReleaseContextDC(pDC);
  1273.         DestroyContext();
  1274.     }
  1275.     else    {
  1276.         //    Otherwise, we tell the owning view to refresh itself.
  1277.         ((CGenericView *)m_pPreviewView)->GetFrame()->GetFrameWnd()->Invalidate();
  1278.     }
  1279. }
  1280.  
  1281. void CPrintCX::FinishedLayout(MWContext *pContext)    {
  1282.  
  1283.     //    Call the base.
  1284.     CDCCX::FinishedLayout(pContext);
  1285.  
  1286.     if(IsDestroyed())
  1287.         return;
  1288.  
  1289.     m_bFinishedLayoutCalled = TRUE;
  1290.  
  1291.     if(m_bAllConnectionCompleteCalled && !m_bFormatStarted)
  1292.     {
  1293.         FormatAndPrintPages(pContext);
  1294.     }
  1295. }
  1296.  
  1297. void CPrintCX::AllConnectionsComplete(MWContext *pContext)    {
  1298.  
  1299.     //    Call the base.
  1300.     CDCCX::AllConnectionsComplete(pContext);
  1301.  
  1302.     if(IsDestroyed())
  1303.         return;
  1304.  
  1305.     m_bAllConnectionCompleteCalled = TRUE;
  1306.  
  1307.     if(m_bFinishedLayoutCalled && !m_bFormatStarted)
  1308.     {
  1309.         FormatAndPrintPages(pContext);
  1310.     }
  1311. }
  1312.  
  1313. void CPrintCX::Progress(MWContext *pContext, const char *pMessage)    {
  1314. //    Purpose:    Display the progression of the load.
  1315. //    Arguments:    pContext    The context loading a URL.
  1316. //                pMessage    The message to display.
  1317. //    Returns:    void
  1318. //    Comments:    Updates the CPrintStatus dialog mainly.
  1319. //    Revision History:
  1320. //        05-31-95    created GAB
  1321.  
  1322.     //    Call the base.
  1323.     CDCCX::Progress(pContext, pMessage);
  1324.  
  1325.     //    Simply set the progress text in the dialog.
  1326.     if(pMessage != NULL)    {
  1327.         if(IsPrintPreview() == FALSE)    {
  1328.             m_pStatusDialog->SetDlgItemText(IDC_PROGRESS, pMessage);
  1329.         }
  1330.         else    {
  1331.             //    Get the frame from the preview view, and have it do some
  1332.             //        progress for us.
  1333.             LPCHROME pChrome = ((CGenericView *)m_pPreviewView)->GetFrame()->GetChrome();
  1334.             if(pChrome) {
  1335.                 LPNSSTATUSBAR pIStatusBar = NULL;
  1336.                 pChrome->QueryInterface( IID_INSStatusBar, (LPVOID *) &pIStatusBar );
  1337.                 if ( pIStatusBar ) {
  1338.                     pIStatusBar->SetStatusText( pMessage );
  1339.                     pIStatusBar->Release();
  1340.                 }
  1341.             }
  1342.         }
  1343.     }
  1344. }
  1345.  
  1346. void CPrintCX::CancelPrintJob()    {
  1347. //    Purpose:    Cancels the current print job.
  1348. //    Arguments:    void
  1349. //    Returns:    void
  1350. //    Comments:    This should fully cancel a print job at any stage.
  1351. //    Revision History:
  1352. //        05-31-95    created GAB
  1353.  
  1354.     if(m_bCancel == FALSE)    {
  1355.         TRACE("Marking the print job as cancelled.\n");
  1356.  
  1357.         //    First, set a member stating that we are cancelling the job.
  1358.         m_bCancel = TRUE;
  1359.  
  1360.         //    Second, set a member in the print job saying that the load
  1361.         //        has been interrupted.
  1362.         m_pcpiPrintJob->m_bContinuePrinting = FALSE;
  1363.  
  1364.         //    If we're loading, then we interrupt that load.
  1365.         XP_InterruptContext(GetContext());
  1366.     }
  1367. }
  1368.  
  1369. void CPrintCX::FormatPages()    {
  1370. //    Purpose:    Take the information regarding all elements to be
  1371. //                    laid out and determine which elements fall on which
  1372. //                    page.
  1373. //    Arguments:    void
  1374. //    Returns:    void
  1375. //    Comments:    Herein is how to properly print tables....
  1376. //    Revision History:
  1377. //        06-09-95    created GAB
  1378.  
  1379.     TRACE("Figuring page boundries\n");
  1380.     CString temp;
  1381.     temp.LoadString(IDS_FORMATTING);
  1382.     FE_Progress(GetContext(), temp);
  1383.  
  1384.     //    Figure out the dimensions of the page taking into account margins.
  1385.     //    We can't and don't care about width.
  1386.     //    We use positive height to match layout.
  1387.  
  1388.     int32 lHeight = m_lPageHeight - (m_lTopMargin + m_lBottomMargin);
  1389.     int32 lWidth = m_lPageWidth - (m_lLeftMargin + m_lRightMargin);
  1390.  
  1391.     //    The algorithm here is as follows:
  1392.     //        Find all boundry elements. A boundry element, is an element cut
  1393.     //            off by the bottom of a page.
  1394.     //        A boundry element, if not at the top of a page, consitutes starting
  1395.     //            a new page.
  1396.     //        When a boundry element starts a new page, all elements starting
  1397.     //            below that element go on the next page with the boundry element.
  1398.  
  1399.     CPtrList cplCurPage;
  1400.     LTRB PageRect(0, 0, lWidth, lHeight);
  1401.     LTRB *pPage;
  1402.     LTRB *pBoundry;
  1403.     LTRB *pElement;
  1404.     POSITION rIndex, rOldIndex;
  1405.     BOOL bUseSmartClipping;
  1406.     int32 iOldPageBottom;
  1407.     BOOL bUsedClipping;
  1408.  
  1409.     while(m_cplCaptured.IsEmpty() == FALSE)    {
  1410.         //    First, go through all captured elements, and move any which begin
  1411.         //        on the current page into a separate list.
  1412.         rIndex = m_cplCaptured.GetHeadPosition();
  1413.         while(rIndex != NULL)    {
  1414.             rOldIndex = rIndex;
  1415.             pElement = (LTRB *)m_cplCaptured.GetNext(rIndex);
  1416.             
  1417.             if(pElement->top <= PageRect.bottom)    {
  1418.                 m_cplCaptured.RemoveAt(rOldIndex);
  1419.                 cplCurPage.AddTail((void *)pElement);
  1420.             }
  1421.         }
  1422.  
  1423.         //  We'll want to attempt to use a smarter algorithm in most cases,
  1424.         //      such that we do not cut lines in half.  However, we will
  1425.         //      give up on that approach if we lose over half of the page
  1426.         //      height.
  1427.         bUseSmartClipping = TRUE;
  1428.         iOldPageBottom = PageRect.bottom;
  1429.         bUsedClipping = FALSE;
  1430.  
  1431.         while(1) {
  1432.             //    Further, find in that new list all boundries, and remember
  1433.             //        the beginning of the worst one.
  1434.             //    Remember, that if it starts at the beginning of a page or before
  1435.             //        the beginning of this page, then there is nothing we can do.
  1436.             //    Also, don't use elements longer than a single page by themselves as a
  1437.             //        boundry.
  1438.             pBoundry = NULL;
  1439.             rIndex = cplCurPage.GetHeadPosition();
  1440.             while(rIndex != NULL)    {
  1441.                 pElement = (LTRB *)cplCurPage.GetNext(rIndex);
  1442.                 if(pElement->bottom > PageRect.bottom && pElement->top > PageRect.top)    {
  1443.                     //    Make sure the element won't fit on a page by itself before we
  1444.                     //        approve it as a boundry.
  1445.                     if(pElement->Height() > PageRect.Height())    {
  1446.                         //    To high to fit on a page.  Don't use as a boundry.
  1447.                         continue;
  1448.                     }
  1449.  
  1450.                     BOOL bSetBoundry = FALSE;
  1451.                     if(NULL == pBoundry)    {
  1452.                         pBoundry = pElement;
  1453.                         bSetBoundry = TRUE;
  1454.                     }
  1455.                     else if(pBoundry->top > pElement->top)    {
  1456.                         pBoundry = pElement;                    
  1457.                         bSetBoundry = TRUE;
  1458.                     }
  1459.  
  1460.                     if(bSetBoundry && bUseSmartClipping) {
  1461.                         //  Adjust the bottom of the page to the boundry.
  1462.                         //  Also, reset the loop, to catch any new betrayers.
  1463.                         PageRect.bottom = pBoundry->top;
  1464.                         rIndex = cplCurPage.GetHeadPosition();
  1465.                         bUsedClipping = TRUE;
  1466.                     }
  1467.                 }
  1468.             }
  1469.  
  1470.             //  If we lost over half the page, redo the algorithm
  1471.             //      not using smart clipping.
  1472.             if(bUsedClipping && PageRect.Height() < (lHeight / 2))   {
  1473.                 bUsedClipping = FALSE;
  1474.                 bUseSmartClipping = FALSE;
  1475.                 PageRect.bottom = iOldPageBottom;
  1476.                 continue;
  1477.             }
  1478.             break;
  1479.         }
  1480.  
  1481.         //    Next move all elements falling below the boundry (if it exists)
  1482.         //        back into the captured element list.
  1483.         if(pBoundry != NULL)    {
  1484.             rIndex = cplCurPage.GetHeadPosition();
  1485.             while(rIndex != NULL)    {
  1486.                 rOldIndex = rIndex;
  1487.                 pElement = (LTRB *)cplCurPage.GetNext(rIndex);
  1488.                 if(pElement->top >= pBoundry->top)    {
  1489.                     cplCurPage.RemoveAt(rOldIndex);
  1490.                     m_cplCaptured.AddTail((void *)pElement);
  1491.                 }
  1492.             }
  1493.         }
  1494.  
  1495.         //    Also, we need to move all elements falling below this new boundry
  1496.         //        back into the captured list so that they are counted as yet
  1497.         //        another page. (think: 1 element that is 50 pages long....)
  1498.         rIndex = cplCurPage.GetHeadPosition();
  1499.         while(rIndex != NULL)    {
  1500.             rOldIndex = rIndex;
  1501.             pElement = (LTRB *)cplCurPage.GetNext(rIndex);
  1502.             if(pElement->bottom > PageRect.bottom)    {
  1503.                 cplCurPage.RemoveAt(rOldIndex);
  1504.                 m_cplCaptured.AddTail((void *)pElement);
  1505.             }
  1506.         }
  1507.  
  1508.         //    Cause all current page elements to be destroyed.
  1509.         rIndex = cplCurPage.GetHeadPosition();
  1510.         while(rIndex != NULL)    {
  1511.             rOldIndex = rIndex;
  1512.             pElement = (LTRB *)cplCurPage.GetNext(rIndex);
  1513.             cplCurPage.RemoveAt(rOldIndex);
  1514.             delete pElement;
  1515.         }
  1516.  
  1517.         //    Create the new page entry (duplicate of the current page).
  1518.         //    This will be used later in PrintPage.
  1519.         pPage = new LTRB(PageRect.left, PageRect.top, PageRect.right,
  1520.             PageRect.bottom);
  1521.         m_cplPages.AddTail((void *)pPage);
  1522.  
  1523.         //    Update the value of the current page to be the next page.
  1524.         PageRect.top = PageRect.bottom + 1;
  1525.         PageRect.bottom = PageRect.top + lHeight;
  1526.     }
  1527. }
  1528.  
  1529. void CPrintCX::PrintTextAllign ( HDC hdc, char * szBuffer, int position, int hpos )
  1530. {
  1531.     SIZE csExtent;
  1532.     int32 Y; 
  1533.     int32 X;
  1534.     CString cs = szBuffer;
  1535.     WFE_CondenseURL ( cs, m_iMaxWidth, FALSE );
  1536.  
  1537.     CreateHeaderFooterFont();
  1538.  
  1539.     HFONT hOldFont = NULL;
  1540.     if(m_hFont) {
  1541.         hOldFont = (HFONT)::SelectObject(hdc, m_hFont);
  1542.     }
  1543.  
  1544.     ResolveTextExtent(hdc, cs, strlen(cs), &csExtent);
  1545.  
  1546.     if ( hpos == POS_FOOTER )
  1547.         Y = m_lPageHeight - csExtent.cy - 1;
  1548.     else
  1549.         Y = 0;
  1550.  
  1551.     switch ( position )
  1552.     {
  1553.         case POS_CENTER:
  1554.             X = m_lPageWidth / 2 - csExtent.cx / 2;
  1555.             break;
  1556.         case POS_LEFT:
  1557.             X = 0;
  1558.             break;                                                                                                      
  1559.         case POS_RIGHT:
  1560.             X = m_lPageWidth - csExtent.cx;
  1561.             break;
  1562.  
  1563.     }
  1564.  
  1565.     CIntlWin::TextOut(m_iFontCSID , hdc, CASTINT(X), CASTINT(Y), cs, strlen(cs));
  1566.  
  1567.     if(hOldFont) {
  1568.         ::SelectObject(hdc, hOldFont);
  1569.     }
  1570. }
  1571.  
  1572. void CPrintCX::PrintPage(int iPage, HDC pNewDC, CPrintInfo *pNewInfo)    {
  1573. //    Purpose:    Print a specific page.
  1574. //    Arguments:    iPage    The page which to print.
  1575. //    Returns:    void
  1576. //    Comments:    This is the real thing.  If there is no page information
  1577. //                    then we get out of the print loop.
  1578. //    Revision History:
  1579. //        06-09-95    created GAB
  1580.  
  1581.     //    If we've got new information, use it.
  1582.     if(pNewDC != NULL)    {
  1583.         m_hdcPrint = pNewDC;
  1584.     }
  1585.     if(pNewInfo != NULL)    {
  1586.         m_pcpiPrintJob = pNewInfo;
  1587.     }
  1588.  
  1589.     //    Page numbers always go from 1 on up.
  1590.     //    Get the position of the page in out list.
  1591.     POSITION rIndex = m_cplPages.FindIndex(iPage - 1);
  1592.     if(rIndex == NULL)    {
  1593.         //    Time to stop printing, the specified page isn't found.
  1594.         //    Only do this when we're actually printing.
  1595.         if(IsPrintPreview() == FALSE)    {
  1596.             m_pcpiPrintJob->m_bContinuePrinting = FALSE;
  1597.         }
  1598.         return;
  1599.     }
  1600.  
  1601.     TRACE("Printing page %d\n", iPage);
  1602.     m_iLastPagePrinted = iPage;
  1603.  
  1604.     char szMessage[80];
  1605.     PR_snprintf(szMessage, sizeof(szMessage), szLoadString(IDS_PRINTING_PAGE), iPage);
  1606.     FE_Progress(GetContext(), szMessage);
  1607.  
  1608.     //    Get the actual page, and have layout refresh the area.
  1609.     //    This will in turn cause the display functions to be called, and this
  1610.     //        will in turn cause the display functions to call ResolveElement,
  1611.     //        and therein we adjust for margins and determine wether or not
  1612.     //        to output an actual element.
  1613.     LTRB *pPage = (LTRB *)m_cplPages.GetAt(rIndex);
  1614.  
  1615.     //    Save the DC state, so that clipping information can be restored to
  1616.     //        defaults after the page is printed.
  1617.     HDC hdc = GetContextDC();
  1618.     int iSaveDC = ::SaveDC(hdc);
  1619.  
  1620.  
  1621.     TRACE("LO_RefreshArea(%ld,%ld,%ld,%ld);\n", pPage->left, pPage->top,
  1622.         pPage->Width(), pPage->Height());
  1623.  
  1624.     //    Instead of passing the actual page params, we have layout refresh
  1625.     //        everything possible.
  1626.     //    All ResolveElement functions will have to appropriately block display
  1627.     //        for the current page.
  1628.     //    In this manner, we correctly handle elements longer than one page.
  1629.     CL_Compositor *compositor = GetContext()->compositor;
  1630.     if (compositor) {
  1631.         XP_Rect rect;
  1632.         
  1633.         CL_ScrollCompositorWindow(compositor, 0, pPage->top);
  1634.         
  1635.         rect.left = 0;
  1636.         rect.top = 0;
  1637.         rect.right = m_lWidth;
  1638.         // For the last page, we use the complete height of the physical
  1639.         // page so that, if there's a background, it won't get cut off
  1640.         // early.
  1641.         if (rIndex == m_cplPages.GetTailPosition())
  1642.             rect.bottom = m_lHeight;
  1643.         else
  1644.             rect.bottom = pPage->Height();
  1645.  
  1646.         CL_ResizeCompositorWindow(compositor, rect.right, rect.bottom);
  1647.         CL_RefreshWindowRect(compositor, &rect);
  1648.     }
  1649.     else {
  1650.         //    Now, make it small enough for the page only.
  1651.         ::IntersectClipRect(hdc, CASTINT(m_lLeftMargin),
  1652.                             CASTINT(m_lTopMargin),
  1653.                             CASTINT(m_lLeftMargin + pPage->Width()),
  1654.                             CASTINT(m_lTopMargin + pPage->Height()));
  1655.         LO_RefreshArea(GetDocumentContext(), 0, 0, 0x7FFFFFFF, 0x7FFFFFFF);
  1656.     }
  1657.  
  1658.     //    Restore the DC state (clipping region).
  1659.     ::RestoreDC(hdc, iSaveDC);
  1660.  
  1661.     //    Headers and footers.
  1662.  
  1663.     //  Footers first! Footers first!
  1664.  
  1665.     ApiPageSetup(api,0);
  1666.     int iFooter = api->Footer ( );
  1667.     int iPosDate = 0;
  1668.     BOOL bPosTotal = 0;
  1669.     int iPosCount = 0;
  1670.  
  1671.     if ( iFooter & PRINT_PAGENO )
  1672.         iPosCount = POS_CENTER;
  1673.  
  1674.     if ( iFooter & PRINT_PAGECOUNT )
  1675.         bPosTotal = TRUE;
  1676.  
  1677.     if ( iFooter & PRINT_DATE )
  1678.         if ( iPosCount )
  1679.         {
  1680.             iPosCount = POS_LEFT;
  1681.             iPosDate  = POS_RIGHT;
  1682.         }
  1683.         else
  1684.             iPosDate = POS_CENTER;
  1685.  
  1686.     // page number
  1687.     if( iPosCount )    {
  1688.         char szBuffer[32];
  1689.  
  1690.         if ( bPosTotal )
  1691.             PR_snprintf(szBuffer, sizeof(szBuffer), szLoadString(IDS_PAGE_N_OF_COUNT), iPage, m_cplPages.GetCount( ));
  1692.         else
  1693.             PR_snprintf(szBuffer, sizeof(szBuffer), "%d", iPage);
  1694.  
  1695.         PrintTextAllign ( hdc, szBuffer, iPosCount, POS_FOOTER );
  1696.  
  1697.     }
  1698.  
  1699.     if ( iPosDate ) {
  1700.         char aBuffer[65];
  1701.         char szDate[30];
  1702.         char szTime[30];
  1703. #ifdef XP_WIN32
  1704.         GetDateFormat(LOCALE_SYSTEM_DEFAULT, DATE_SHORTDATE, NULL, NULL, szDate, 30);
  1705.         GetTimeFormat(LOCALE_SYSTEM_DEFAULT, TIME_NOSECONDS, NULL, NULL, szTime, 30);
  1706.         sprintf(aBuffer,"%s %s", szDate, szTime);
  1707. #else
  1708.         sprintf(aBuffer,"%s %s", _strdate(szDate), _strtime(szTime) );
  1709. #endif
  1710.         PrintTextAllign ( hdc, aBuffer, iPosDate, POS_FOOTER );
  1711.     }
  1712.  
  1713.     int iHeader = api->Header ( );
  1714.     int iPosTitle = 0;
  1715.     int iPosURL = 0;
  1716.  
  1717.     if ( iHeader & PRINT_TITLE )
  1718.         iPosTitle = POS_CENTER;
  1719.  
  1720.     if ( iHeader & PRINT_URL )
  1721.         if ( iPosTitle )
  1722.         {
  1723.             iPosTitle = POS_LEFT;
  1724.             iPosURL  = POS_RIGHT;
  1725.         }
  1726.         else
  1727.             iPosURL = POS_CENTER;
  1728.  
  1729.     if ( iPosTitle )
  1730.     {
  1731.         char *pTitle = GetContext()->title;
  1732.         if(pTitle != NULL)    
  1733.             PrintTextAllign ( hdc, pTitle, iPosTitle, POS_HEADER );
  1734.     }
  1735.  
  1736.     if ( iPosURL )
  1737.     {
  1738.         // Here's where we finally use the DisplayURL
  1739.         //   instead of the temporary file URL in Composer
  1740.         const char * pURL = m_pDisplayUrl ? m_pDisplayUrl : m_pAnchor;
  1741.         if ( pURL && *pURL ) {
  1742.             char *pszUrlType = NET_ParseURL( pURL, GET_PROTOCOL_PART );
  1743.  
  1744.             if ( !pszUrlType || (XP_STRCASECMP(pszUrlType, "mailbox:") && 
  1745.                                  XP_STRCASECMP(pszUrlType, "news:")    &&
  1746.                                  XP_STRCASECMP(pszUrlType, "snews:")   &&
  1747.                                  XP_STRCASECMP(pszUrlType, "imap:")) ) {
  1748.                                  
  1749.                 PrintTextAllign ( hdc, (char *)pURL, iPosURL, POS_HEADER );
  1750.             }
  1751.             
  1752.             if ( pszUrlType )
  1753.                 XP_FREE( pszUrlType );
  1754.         }
  1755.     }
  1756.  
  1757.     ReleaseContextDC(hdc);    
  1758. }
  1759.  
  1760. void CPrintCX::EraseBackground(MWContext *pContext, int iLocation, 
  1761.                 int32 x, int32 y, uint32 width, uint32 height,
  1762.                                LO_Color *pColor)
  1763. {
  1764.     int32 orgx, orgy, orgWidth, orgHeight;
  1765.  
  1766.     orgx = x;
  1767.     orgy = y;
  1768.     orgWidth = width;
  1769.     orgHeight = height;
  1770.     if (GetDisplayMode() == DISPLAY) {
  1771.         x += m_lLeftMargin;
  1772.         y += m_lTopMargin;
  1773.         
  1774.         //    Adjust the Y coordinate for the current page we are printing.
  1775.         POSITION rIndex = m_cplPages.FindIndex(m_pcpiPrintJob->m_nCurPage - 1);
  1776.         if(rIndex == NULL)    {
  1777.             //    This could be called during incremental display.
  1778.             //    Don't allow drawing at that point.
  1779.             return;
  1780.         }
  1781.         LTRB *pPage = (LTRB *)m_cplPages.GetAt(rIndex);
  1782.         y -= pPage->top;
  1783.         
  1784.         //    Form a Rect of the current page, in the same coords as the 
  1785.         //      background. The bottom of the page is determined on a page 
  1786.         //      by page basis.
  1787.         LTRB Page;
  1788.         Page.left = m_lLeftMargin;
  1789.         Page.top = m_lTopMargin;
  1790.         Page.right = Page.left + pPage->Width();
  1791.         Page.bottom = Page.top + pPage->Height();
  1792.         
  1793.         if(y >= Page.bottom || (y+(int32)height) <= Page.top ||
  1794.            (x + (int32)width) <= Page.left || x >= Page.right)
  1795.             return;
  1796.         else {
  1797. #ifdef XP_WIN32
  1798.             if ( m_printBk && !IsPrintPreview()) {
  1799.                 SubOffscreenPrintDC();
  1800.                 CDCCX::EraseBackground(pContext, iLocation, 
  1801.                                    orgx / m_lConvertX, orgy / m_lConvertY,
  1802.                                    orgWidth / m_lConvertX, orgHeight / m_lConvertY, pColor);
  1803.                 RestorePrintDC();
  1804.             }
  1805. #endif
  1806.             CDCCX::EraseBackground(pContext, iLocation, 
  1807.                                    x, y,
  1808.                                    width, height, pColor);
  1809.         }
  1810.     }
  1811. }
  1812.  
  1813.  
  1814. void CPrintCX::DisplayBullet(MWContext *pContext, int iLocation, LO_BullettStruct *pBullet)    {
  1815.     if (GetDisplayMode() == BLOCK_DISPLAY)
  1816.         return;
  1817.     else if (GetDisplayMode() == CAPTURE_POSITION)    {
  1818.         int32 lOrgX, lOrgY;
  1819.         
  1820.         GetDrawingOrigin(&lOrgX, &lOrgY);
  1821.         
  1822.         //    Capture the coordinates of this element.
  1823.         Capture(pBullet->x + pBullet->x_offset + lOrgX, pBullet->y + pBullet->y_offset + lOrgY, pBullet->width, pBullet->height);
  1824.  
  1825.         //    We don't actually allow display while we are capturing the area.
  1826.         return;
  1827.     }
  1828.  
  1829.     //     Call the base for actual display.  It never works right
  1830.     //        in Bullet Basic code for some reason.
  1831. #ifdef XP_WIN32
  1832.     if ( m_printBk && !IsPrintPreview()) {
  1833.         SubOffscreenPrintDC();
  1834.         CDCCX::DisplayBullet(pContext, iLocation, pBullet);
  1835.         RestorePrintDC();
  1836.     }
  1837. #endif
  1838.     CDCCX::DisplayBullet(pContext, iLocation, pBullet);
  1839. }
  1840.  
  1841. void CPrintCX::DisplayEmbed(MWContext *pContext, int iLocation, LO_EmbedStruct *pEmbed)    {
  1842.     if (GetDisplayMode() == BLOCK_DISPLAY)
  1843.         return;
  1844.     else if (GetDisplayMode() == CAPTURE_POSITION)    {
  1845.         //    Capture the coordinates of this element.
  1846.         Capture(pEmbed->x + pEmbed->x_offset, pEmbed->y + pEmbed->y_offset, pEmbed->width, pEmbed->height);
  1847.  
  1848.         //    We don't actually allow display while we are capturing the area.
  1849.         return;
  1850.     }
  1851.  
  1852.     //    Call the base for actual display.
  1853.     NPEmbeddedApp* pEmbeddedApp = (NPEmbeddedApp*)pEmbed->FE_Data;
  1854.     if (pEmbeddedApp->type ==  NP_OLE) {
  1855.         CNetscapeCntrItem *pItem = (CNetscapeCntrItem *)pEmbeddedApp->fe_data;
  1856.         pItem->SetPrintDevice( &(m_pcpiPrintJob->m_pPD->m_pd) );
  1857.     }
  1858.     CDCCX::DisplayEmbed(pContext, iLocation, pEmbed);
  1859. }
  1860.  
  1861. void CPrintCX::DisplayFormElement(MWContext *pContext, int iLocation, LO_FormElementStruct *pFormElement)    {
  1862.     if (GetDisplayMode() == BLOCK_DISPLAY)
  1863.         return;
  1864.     else if (GetDisplayMode() == CAPTURE_POSITION)    {
  1865.         //    Capture the coordinates of this element.
  1866.         Capture(pFormElement->x + pFormElement->x_offset, pFormElement->y + pFormElement->y_offset, pFormElement->width, pFormElement->height);
  1867.  
  1868.         //    We don't actually allow display while we are capturing the area.
  1869.         return;
  1870.     }
  1871.  
  1872.     //    Call the base for actual display.
  1873. #ifdef XP_WIN32
  1874.     if ( m_printBk && !IsPrintPreview()) {
  1875.         SubOffscreenPrintDC();
  1876.         CDCCX::DisplayFormElement(pContext, iLocation, pFormElement);
  1877.         RestorePrintDC();
  1878.     }
  1879. #endif
  1880.     CDCCX::DisplayFormElement(pContext, iLocation, pFormElement);
  1881. }
  1882.  
  1883. void CPrintCX::DisplayHR(MWContext *pContext, int iLocation, LO_HorizRuleStruct *pHorizRule)    {
  1884.     if (GetDisplayMode() == BLOCK_DISPLAY)
  1885.         return;
  1886.     else if (GetDisplayMode() == CAPTURE_POSITION)    {
  1887.         int32 lOrgX, lOrgY;
  1888.         
  1889.         GetDrawingOrigin(&lOrgX, &lOrgY);
  1890.         
  1891.         //    Capture the coordinates of this element.
  1892.         Capture(pHorizRule->x + pHorizRule->x_offset + lOrgX, pHorizRule->y + pHorizRule->y_offset + lOrgY, pHorizRule->width, pHorizRule->height);
  1893.  
  1894.         //    We don't actually allow display while we are capturing the area.
  1895.         return;
  1896.     }
  1897.  
  1898.     //    Call the base for actual display.
  1899. #ifdef XP_WIN32
  1900.     if ( m_printBk && !IsPrintPreview() ) {
  1901.         SubOffscreenPrintDC();
  1902.         CDCCX::DisplayHR(pContext, iLocation, pHorizRule);
  1903.         RestorePrintDC();
  1904.     }
  1905. #endif
  1906.     CDCCX::DisplayHR(pContext, iLocation, pHorizRule);
  1907. }
  1908. BOOL CPrintCX::IsDeviceDC() 
  1909. #ifdef XP_WIN32
  1910.     if (!m_printBk) return TRUE;
  1911.     else {
  1912.         if (m_hdcPrint == m_hOrgPrintDC)
  1913.             return TRUE;
  1914.         else return FALSE;
  1915.     }
  1916. #else
  1917.     return TRUE;
  1918. #endif
  1919. }
  1920.  
  1921. #ifdef XP_WIN32
  1922. void CPrintCX::CopyOffscreenBitmap(NI_Pixmap* image, int32 x, int32 y, int32 x_offset, int32 y_offset, int32 width, int32 height, LTRB& Rect)
  1923. {
  1924.     LTRB sourceRect(Rect);
  1925.     ResolveElement(Rect, image, 
  1926.                    x_offset * m_lConvertX, 
  1927.                    y_offset* m_lConvertY, 
  1928.                    x * m_lConvertX, y* m_lConvertY, 
  1929.                    width * m_lConvertX, 
  1930.                    height* m_lConvertY);
  1931.     WORD nBitCount;
  1932.     nBitCount = GetBitsPerPixel();
  1933.     int    nColorTable;
  1934.  
  1935.     // We need to know how big the color table is. For 16-bit mode and 32-bit mode, we need to
  1936.     // allocate room for 3 double-word color masks
  1937.     if (nBitCount == 16 || nBitCount == 32)
  1938.         nColorTable = 3;
  1939.     else if (nBitCount < 16)
  1940.         nColorTable = 1 << nBitCount;
  1941.     else {
  1942.         ASSERT(nBitCount == 24);
  1943.         nColorTable = 0;
  1944.     }
  1945.     LPBITMAPINFOHEADER    lpBmi;
  1946.     // Allocate space for a BITMAPINFO structure (BITMAPINFOHEADER structure
  1947.     // plus space for the color table)
  1948.  
  1949.     lpBmi = (LPBITMAPINFOHEADER)calloc(sizeof(BITMAPINFOHEADER) + nColorTable * sizeof(RGBQUAD), 1);
  1950.     if (lpBmi) {
  1951.         // Initialize the BITMAPINFOHEADER structure
  1952.         lpBmi->biSize = sizeof(BITMAPINFOHEADER);
  1953.         lpBmi->biWidth = width;
  1954.         lpBmi->biHeight = height;
  1955.         lpBmi->biPlanes = 1;
  1956.         lpBmi->biCompression = BI_RGB;
  1957.  
  1958.         CDC *pAttrDC;
  1959.         pAttrDC = theApp.m_pMainWnd->GetDC();
  1960.         HDC tempDC = ::CreateCompatibleDC(pAttrDC->GetSafeHdc());
  1961.         lpBmi->biBitCount = nBitCount;
  1962.         HPALETTE hOldPal;
  1963.         // Ask the driver to tell us the number of bits we need to allocate
  1964.         BITMAPINFO lpbmi;
  1965.         lpbmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  1966.         lpbmi.bmiHeader.biWidth = lpBmi->biWidth;
  1967.         lpbmi.bmiHeader.biHeight = lpBmi->biHeight;
  1968.         lpbmi.bmiHeader.biPlanes = 1;
  1969.         lpbmi.bmiHeader.biBitCount = 24;
  1970.         lpbmi.bmiHeader.biCompression = BI_RGB;
  1971.         lpbmi.bmiHeader.biSizeImage = 0;
  1972.         lpbmi.bmiHeader.biXPelsPerMeter = 0;
  1973.         lpbmi.bmiHeader.biYPelsPerMeter = 0;
  1974.  
  1975.         lpbmi.bmiHeader.biClrUsed = 0;        // default value    
  1976.         lpbmi.bmiHeader.biClrImportant = 0;   // all important
  1977.         void* ptr;
  1978.         HBITMAP tempBmp = ::CreateDIBSection(pAttrDC->GetSafeHdc(),&lpbmi, DIB_RGB_COLORS,  
  1979.             &ptr, NULL, NULL);
  1980.         HBITMAP    hOldBmp = (HBITMAP)::SelectObject(tempDC, tempBmp);
  1981.         ::BitBlt(tempDC, 0, 0, width, height, 
  1982.                             m_hOffscrnDC,
  1983.                             CASTINT(sourceRect.left),
  1984.                             CASTINT(sourceRect.top),
  1985.                              SRCCOPY);
  1986.         (HBITMAP)::SelectObject(tempDC, hOldBmp);
  1987.         lpBmi->biSizeImage = ((((lpBmi->biWidth * nBitCount) + 31) & ~31) >> 3) * lpBmi->biHeight;
  1988.         // Allocate space for the bits
  1989.         LPBYTE lpBits = (LPBYTE)HugeAlloc(lpBmi->biSizeImage, 1);
  1990.         ::GetDIBits(tempDC, tempBmp, 0, (int)lpBmi->biHeight, lpBits, (LPBITMAPINFO)lpBmi, DIB_RGB_COLORS);
  1991.  
  1992.         ::StretchDIBits(GetContextDC(),
  1993.                             CASTINT(Rect.left),
  1994.                             CASTINT(Rect.top),
  1995.                             CASTINT(Rect.right - Rect.left),
  1996.                             CASTINT(Rect.bottom - Rect.top),
  1997.                             0,
  1998.                             0,
  1999.                             CASTINT(width),
  2000.                             CASTINT(height),
  2001.                             lpBits,
  2002.                             (BITMAPINFO*)lpBmi,
  2003.                             DIB_RGB_COLORS,
  2004.                              SRCCOPY);
  2005.  
  2006.         ::DeleteDC(tempDC);
  2007.         ::DeleteObject(tempBmp);
  2008.         free(lpBits);
  2009.         free(lpBmi);
  2010.         theApp.m_pMainWnd->ReleaseDC(pAttrDC);
  2011.     }
  2012. }
  2013. #endif
  2014.  
  2015. int     CPrintCX::DisplayPixmap(NI_Pixmap* image, NI_Pixmap* mask, int32 x, int32 y, int32 x_offset, int32 y_offset, int32 width, int32 height, LTRB& Rect)
  2016. {
  2017. //    LTRB Rect;
  2018.     if (GetDisplayMode() == BLOCK_DISPLAY)
  2019.         return FALSE;
  2020.     else if (GetDisplayMode() == CAPTURE_POSITION)    {
  2021.         int32 lOrgX, lOrgY;
  2022.         
  2023.         GetDrawingOrigin(&lOrgX, &lOrgY);
  2024.         
  2025.         //    Capture the coordinates of this element.
  2026.         Capture(x + (x_offset * m_lConvertX) + lOrgX, y + (y_offset * m_lConvertY) + lOrgY, width * m_lConvertX, height * m_lConvertY);
  2027.  
  2028.         //    We don't actually allow display while we are capturing the area.
  2029.         return FALSE;
  2030.     }
  2031.     int iSaveDC = ::SaveDC(m_hdcPrint);
  2032.     FEBitmapInfo *imageInfo;
  2033.     imageInfo = (FEBitmapInfo*) image->client_data;
  2034. #ifdef XP_WIN32
  2035.     if ( m_printBk && !IsPrintPreview()) {
  2036.         SubOffscreenPrintDC();
  2037.         CDCCX::DisplayPixmap(image, mask, 
  2038.                     x, y, 
  2039.                     x_offset, y_offset, 
  2040.                     (imageInfo->width > width) ? imageInfo->width : width, 
  2041.                     (imageInfo->height > height) ? imageInfo->height : height, 
  2042.                     Rect);
  2043.         RestorePrintDC();
  2044.     }
  2045.  
  2046.     if (mask && m_printBk && !IsPrintPreview()) {
  2047.         CopyOffscreenBitmap(image, x, y, x_offset, y_offset, width, height, Rect);
  2048.     }
  2049.     else
  2050.         CDCCX::DisplayPixmap(image, mask, 
  2051.                         x, y, 
  2052.                         x_offset, y_offset, 
  2053.                         (imageInfo->width > width) ? imageInfo->width : width, 
  2054.                         (imageInfo->height > height) ? imageInfo->height : height, 
  2055.                         Rect);
  2056. #else
  2057.     if (ResolveElement(Rect, image, 
  2058.                        (x_offset * m_lConvertX), 
  2059.                        (y_offset * m_lConvertY), 
  2060.                        x, y, 
  2061.                        (width * m_lConvertX), 
  2062.                        (height * m_lConvertY))) {
  2063.         if (IsPrintPreview())
  2064.             CDCCX::DisplayPixmap(image, mask, x, y, x_offset, 
  2065.                         y_offset, width, height, Rect);
  2066.         else {
  2067.             StretchPixmap(GetContextDC(), image, 
  2068.                 Rect.left,
  2069.                 Rect.top,
  2070.                 Rect.right - Rect.left,
  2071.                 Rect.bottom - Rect.top,
  2072.                 x_offset,
  2073.                 y_offset, 
  2074.                 width, 
  2075.                 height);
  2076.         }
  2077.     }
  2078. #endif
  2079.     if(iSaveDC) {
  2080.         ::RestoreDC(m_hdcPrint, iSaveDC);
  2081.     }
  2082.     return TRUE;
  2083. }
  2084.  
  2085. void CPrintCX::DisplayLineFeed(MWContext *pContext, int iLocation, LO_LinefeedStruct *pLineFeed, XP_Bool iClear)    {
  2086.     if (GetDisplayMode() == BLOCK_DISPLAY)
  2087.         return;
  2088.     else if (GetDisplayMode() == CAPTURE_POSITION)    {
  2089.         int32 lOrgX, lOrgY;
  2090.         
  2091.         GetDrawingOrigin(&lOrgX, &lOrgY);
  2092.         
  2093.         //    Capture the coordinates of this element.
  2094.         Capture(pLineFeed->x + pLineFeed->x_offset + lOrgX, pLineFeed->y + pLineFeed->y_offset + lOrgY, pLineFeed->width, pLineFeed->height);
  2095.  
  2096.         //    We don't actually allow display while we are capturing the area.
  2097.         return;
  2098.     }
  2099.  
  2100.     //    Call the base for actual display.
  2101. #ifdef XP_WIN32
  2102.     if ( m_printBk && !IsPrintPreview()) {
  2103.         SubOffscreenPrintDC();
  2104.         CDCCX::DisplayLineFeed(pContext, iLocation, pLineFeed, iClear);
  2105.         RestorePrintDC();
  2106.     }
  2107. #endif
  2108.     CDCCX::DisplayLineFeed(pContext, iLocation, pLineFeed, iClear);
  2109. }
  2110.  
  2111. void CPrintCX::DisplaySubDoc(MWContext *pContext, int iLocation, LO_SubDocStruct *pSubDoc)    {
  2112.     if (GetDisplayMode() == BLOCK_DISPLAY)
  2113.         return;
  2114.     else if (GetDisplayMode() == CAPTURE_POSITION)    {
  2115.         int32 lOrgX, lOrgY;
  2116.         
  2117.         GetDrawingOrigin(&lOrgX, &lOrgY);
  2118.         
  2119.         //    Capture the coordinates of this element.
  2120.         Capture(pSubDoc->x + pSubDoc->x_offset + lOrgX, pSubDoc->y + pSubDoc->y_offset + lOrgY, pSubDoc->width, pSubDoc->height);
  2121.  
  2122.         //    We don't actually allow display while we are capturing the area.
  2123.         return;
  2124.     }
  2125.  
  2126.     //    Call the base for actual display.
  2127. #ifdef XP_WIN32
  2128.     if ( m_printBk && !IsPrintPreview()) {
  2129.         SubOffscreenPrintDC();
  2130.         CDCCX::DisplaySubDoc(pContext, iLocation, pSubDoc);
  2131.         RestorePrintDC();
  2132.     }
  2133. #endif
  2134.     CDCCX::DisplaySubDoc(pContext, iLocation, pSubDoc);
  2135. }
  2136.  
  2137. void CPrintCX::DisplayCell(MWContext *pContext, int iLocation, LO_CellStruct *pCell)    {
  2138.     if ((GetDisplayMode() == BLOCK_DISPLAY) ||
  2139.         (GetDisplayMode() == CAPTURE_POSITION))    {
  2140.         //  Actually, we don't want to capture the area of a cell,
  2141.         //      as it is already surrounded by a table.
  2142.         //  If we have to cut a table in half, then we will do so
  2143.         //      without regard to the table cells.
  2144.  
  2145.         //    We don't actually allow display while we are capturing the area.
  2146.         return;
  2147.     }
  2148.  
  2149.     //    Call the base for actual display.
  2150. #ifdef XP_WIN32
  2151.     if ( m_printBk && !IsPrintPreview()) {
  2152.         SubOffscreenPrintDC();
  2153.         CDCCX::DisplayCell(pContext, iLocation, pCell);
  2154.         RestorePrintDC();
  2155.     }
  2156. #endif
  2157.     CDCCX::DisplayCell(pContext, iLocation, pCell);
  2158. }
  2159. void CPrintCX::DisplaySubtext(MWContext *pContext, int iLocation, LO_TextStruct *pText, int32 lStartPos, int32 lEndPos, XP_Bool iClear)    {
  2160.     if ((GetDisplayMode() == BLOCK_DISPLAY) ||
  2161.         (GetDisplayMode() == CAPTURE_POSITION))    {
  2162.         //    Never capture the coordinates of this element.
  2163.         //    It is only part of a string, and DisplayText will correctly
  2164.         //        handle the coordinates.
  2165.         //    We don't actually allow display while we are capturing the area.
  2166.         return;
  2167.     }
  2168.  
  2169.     //    Don't need to call the base for actual display.
  2170. }
  2171.  
  2172. void CPrintCX::DisplayTable(MWContext *pContext, int iLocation, LO_TableStruct *pTable)    {
  2173.     if (GetDisplayMode() == BLOCK_DISPLAY)
  2174.         return;
  2175.     else if (GetDisplayMode() == CAPTURE_POSITION)    {
  2176.         int32 lOrgX, lOrgY;
  2177.         
  2178.         GetDrawingOrigin(&lOrgX, &lOrgY);
  2179.         
  2180.         //    Capture the coordinates of this element.
  2181.         Capture(pTable->x + pTable->x_offset + lOrgX, pTable->y + pTable->y_offset + lOrgY, pTable->width, pTable->height);
  2182.  
  2183.         //    We don't actually allow display while we are capturing the area.
  2184.         return;
  2185.     }
  2186.  
  2187.     //    Call the base for actual display.
  2188. #ifdef XP_WIN32
  2189.     if ( m_printBk && !IsPrintPreview()) {
  2190.         SubOffscreenPrintDC();
  2191.         CDCCX::DisplayTable(pContext, iLocation, pTable);
  2192.         RestorePrintDC();
  2193.     }
  2194. #endif
  2195.     CDCCX::DisplayTable(pContext, iLocation, pTable);
  2196. }
  2197.  
  2198. void CPrintCX::DisplayText(MWContext *pContext, int iLocation, LO_TextStruct *pText, XP_Bool iClear)   {
  2199.     if (GetDisplayMode() == BLOCK_DISPLAY)
  2200.         return;
  2201.     else if (GetDisplayMode() == CAPTURE_POSITION)    {
  2202.         int32 lOrgX, lOrgY;
  2203.         
  2204.         GetDrawingOrigin(&lOrgX, &lOrgY);
  2205.         
  2206.         //    Capture the coordinates of this element.
  2207.         Capture(pText->x + pText->x_offset + lOrgX, pText->y + pText->y_offset + lOrgY, pText->width, pText->height);
  2208.  
  2209.         //    We don't actually allow display while we are capturing the area.
  2210.         return;
  2211.     }
  2212.  
  2213.     //    Call the base for actual display.
  2214. #ifdef XP_WIN32
  2215.     if ( m_printBk && !IsPrintPreview()) {
  2216.         SubOffscreenPrintDC();
  2217.         LO_TextAttr* pAttr =  pText->text_attr;
  2218.         CyaFont *pCachedFont = (CyaFont *)pAttr->FE_Data;
  2219.         // this is a hack to trick the font engine so the font size
  2220.         // will get regenerate again.  Otherwise, we will end up getting
  2221.         // the font size for printer.
  2222.         pAttr->FE_Data = 0;
  2223.         CDCCX::DisplayText(pContext, iLocation, pText, iClear);
  2224.         pAttr->FE_Data = pCachedFont;
  2225.         RestorePrintDC();
  2226.     }
  2227. #endif
  2228.     CDCCX::DisplayText(pContext, iLocation, pText, iClear);
  2229. }
  2230.  
  2231. void CPrintCX::Capture(int32 lOrgX, int32 lOrgY, int32 lWidth, int32 lHeight)    {
  2232. //    Purpose:    Capture the rectangle in order to layout the document properly.
  2233. //    Arguments:    lOrgX    X origin of the element.
  2234. //                lOrgY    Y origin of the element.
  2235. //                lWidth    The width of the element.
  2236. //                lHeight    The height of the lement.
  2237. //    Returns:    void
  2238. //    Comments:    The origin of the print job must always remain 0,0 for this
  2239. //                    to work correctly.
  2240. //    Revision History:
  2241. //        06-09-95    created GAB
  2242.  
  2243.     //    Don't capture on no width and height.
  2244.     if(lWidth <= 0 || lHeight <= 0)    {
  2245.         return;
  2246.     }
  2247.  
  2248.     //  Don't capture areas we might already have captured
  2249.     if (lOrgY < m_lCaptureScrollOffset) {
  2250.         return;
  2251.     }
  2252.     
  2253.     //    Allocate a new rectangle to hold the information.
  2254.     LTRB *pRect = new LTRB(lOrgX, lOrgY, lOrgX + lWidth, lOrgY + lHeight);
  2255.  
  2256.     //    Add the rectangle to the list of elements we are considering.
  2257.     m_cplCaptured.AddTail((void *)pRect);
  2258. }
  2259.  
  2260. void CPrintCX::DisplayWindowlessPlugin(MWContext *pContext, 
  2261.                                        LO_EmbedStruct *pEmbed,
  2262.                                        NPEmbeddedApp *pEmbeddedApp,
  2263.                                        int iLocation)
  2264. {
  2265.     DisplayPlugin(pContext, pEmbed, pEmbeddedApp, iLocation);
  2266. }
  2267.  
  2268.  
  2269. // Resolve the dimensions of the plugin object rect and tell the plugin
  2270. // to print in that rect using the print HDC.
  2271. void CPrintCX::DisplayPlugin(MWContext *pContext, LO_EmbedStruct *pEmbed,
  2272.                              NPEmbeddedApp* pEmbeddedApp, int iLocation)
  2273. {
  2274.     // get the print area and clamp it
  2275.     LTRB Rect;
  2276.     ResolveElement(Rect, pEmbed, iLocation, NPL_IsEmbedWindowed(pEmbeddedApp));
  2277.     SafeSixteen(Rect);
  2278.  
  2279.     // set the print area rect
  2280.     NPPrint npPrint;
  2281.     NPWindow* pWindow = &npPrint.print.embedPrint.window;
  2282.  
  2283.     // Initialize struct
  2284.     npPrint.mode = NP_EMBED;
  2285.  
  2286.     pWindow->window = NULL;
  2287.     pWindow->y      = Rect.top;
  2288.     pWindow->x      = Rect.left;
  2289.     pWindow->width  = Rect.right - Rect.left;
  2290.     pWindow->height = Rect.bottom - Rect.top;
  2291.     pWindow->type    = NPWindowTypeWindow;
  2292.  
  2293.     // get the print HDC
  2294.     HDC hdc = GetContextDC();
  2295.  
  2296.     //  Save the state of the DC so we can restore it if the Plugin
  2297.     //      changes it's state.
  2298.     int iSaveDC = ::SaveDC(hdc);
  2299.  
  2300.     npPrint.print.embedPrint.platformPrint = (void*)hdc;
  2301.  
  2302.     (void)NPL_Print(pEmbeddedApp, &npPrint);
  2303.  
  2304.     //  Restore the DC's state.
  2305.     if(iSaveDC) {
  2306.         ::RestoreDC(hdc, iSaveDC);
  2307.     }
  2308.  
  2309.     ReleaseContextDC(hdc);
  2310. }
  2311.  
  2312. //    Do not allow incremental image display.
  2313. PRBool CPrintCX::ResolveIncrementalImages()
  2314. {
  2315.     return(PR_FALSE);
  2316. }
  2317.  
  2318. //    ReCreate Font for header and footer if possible.
  2319. VOID CPrintCX::CreateHeaderFooterFont()
  2320. {
  2321.     if (m_hFont == NULL || m_iFontCSID != INTL_DocToWinCharSetID(m_iCSID))
  2322.     {
  2323.         if(m_hFont) {
  2324.             ::DeleteObject(m_hFont);
  2325.             m_hFont = NULL;
  2326.         }
  2327.             
  2328.         HDC hdc = GetContextDC();
  2329.         LOGFONT lf;
  2330.         XP_MEMSET(&lf,0,sizeof(LOGFONT));
  2331.         lf.lfPitchAndFamily = FF_SWISS | VARIABLE_PITCH ;
  2332.         strcpy(lf.lfFaceName, IntlGetUIPropFaceName(m_iCSID));
  2333.         lf.lfCharSet = IntlGetLfCharset(m_iCSID);  // get global lfCharset
  2334.         long height;
  2335.         if (!IsPrintPreview() && ::GetDeviceCaps(hdc, LOGPIXELSY)) {
  2336.             height = ( ( 10 * ::GetDeviceCaps(hdc, LOGPIXELSY) ) / 72 );
  2337.             height = ( ( ( height * 1000L ) / ::GetDeviceCaps ( hdc, LOGPIXELSY ) ) * 1440L ) / 1000L;
  2338.         }
  2339.         else {
  2340.             height = ( ( 18 * printRes.cx)  / screenRes.cx );
  2341.         }
  2342.         lf.lfHeight = CASTINT(height);
  2343.         lf.lfQuality = PROOF_QUALITY;    
  2344.         lf.lfWeight = FW_NORMAL;
  2345.         m_hFont = ::CreateFontIndirect ( &lf );
  2346.         m_iFontCSID = INTL_DocToWinCharSetID(m_iCSID);
  2347.         ReleaseContextDC(hdc);
  2348.     }
  2349. }
  2350.  
  2351. int CPrintCX::PageCount()
  2352. {
  2353.     int iRetval = 0;
  2354.     if(!m_cplPages.IsEmpty())    {
  2355.         iRetval = m_cplPages.GetCount();
  2356.     }
  2357.     return(iRetval);
  2358. }
  2359.  
  2360. int CPrintCX::LastPagePrinted()
  2361. {
  2362.     return(m_iLastPagePrinted);
  2363. }
  2364.  
  2365. void 
  2366. CPrintCX::GetDrawingOrigin(int32 *plOrgX, int32 *plOrgY)
  2367. {
  2368.     if (m_pDrawable) 
  2369.         m_pDrawable->GetOrigin(plOrgX, plOrgY);
  2370.     else
  2371.         *plOrgX = *plOrgY = 0;
  2372. }
  2373.  
  2374. FE_Region
  2375. CPrintCX::GetDrawingClip()
  2376. {
  2377.     if (m_pDrawable)
  2378.         return m_pDrawable->GetClip();
  2379.     else
  2380.         return NULL;
  2381. }
  2382.  
  2383. PrinterDisplayMode CPrintCX::GetDisplayMode() {
  2384.     PrinterDisplayMode pdmRetval = m_iDisplayMode;
  2385.     if(m_bGlobalBlockDisplay && pdmRetval == DISPLAY && !IsPrintPreview()) {
  2386.         //  Tell me if this ever happens, I'd like to study it -- blythe.
  2387.         ASSERT(0);
  2388.         pdmRetval = BLOCK_DISPLAY;
  2389.     }
  2390.     return(pdmRetval);
  2391. }
  2392.  
  2393.