view.cpp

Go to the documentation of this file.
00001 // $Id: view.cpp 1357 2006-06-25 11:31:45Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085         MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 
00099 // Base class for kernel View objects.
00100 
00101 /*
00102 */
00103 
00104 #include "camtypes.h"
00105 #include "camview.h"
00106 //#include "view.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00107 #include "vstate.h"
00108 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 //#include "doccoord.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00110 //#include "oilcoord.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00111 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00112 //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00113 #include "osrndrgn.h"
00114 //#include "rndrgn.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00115 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00116 #include "camelot.h"
00117 #include "ccdc.h"
00118 #include "chapter.h"
00119 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00120 #include "scanrr.h"
00121 #include "grndbmp.h"
00122 #include "maskedrr.h"
00123 #include "oilbitmap.h"
00124 #include "princomp.h"
00125 #include "printctl.h"
00126 //#include "prncamvw.h"
00127 #include "prdlgctl.h"
00128 #include "cameleps.h"
00129 //#include "tim.h"
00130 #include "progress.h"
00131 //#include "prdlgctl.h"
00132 #include "qualattr.h"
00133 #include "pmaskrgn.h"
00134 #include "layer.h"
00135 #include "colcontx.h"
00136 #include "colormgr.h"
00137 //#include "colplate.h"
00138 //#include "ndcchbmp.h"
00139 #include "nodebev.h"
00140 #include "prncamvw.h"
00141 
00142 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00143 #include "prnmks.h"
00144 #include "prnmkcom.h"
00145 
00146 #ifdef RALPH
00147 #include "ralphdoc.h"
00148 #endif
00149 
00150 DECLARE_SOURCE("$Revision: 1357 $");
00151 
00152 CC_IMPLEMENT_DYNAMIC(View, ListItem)
00153 
00154 #define new CAM_DEBUG_NEW
00155 
00156 #ifdef _DEBUG
00157 //  #define _DEBUG_ATTACH_OPTIMAL_BITMAP
00158 //  #define _DEBUG_ATTACH_OPTIMAL_MASK
00159 #endif
00160 
00161 //-----------------------------------------------------------------------------------------//
00162 // Initialise class static variables...
00163 //
00164 View *View::Current = NULL;
00165 PaperRenderRegion *View::pPaperRegion = NULL;
00166 PaperRenderRegion *View::pOnTopRegion = NULL;
00167 
00168 
00169 /********************************************************************************************
00170 
00171 >   View::View()
00172 
00173     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00174     Created:    02/23/95
00175     Purpose:    Initialise a View object.
00176     SeeAlso:    View
00177 
00178 ********************************************************************************************/
00179 
00180 View::View()
00181 {
00182     // No connections yet...
00183     pViewWindow = NULL;
00184     pDoc = NULL;
00185     pVState= NULL;
00186 
00187     // Actual size of OIL pixels that this view uses - default to 96dpi.
00188     PixelWidth = PixelHeight = FIXED16(72000.0 / 96);
00189 
00190     // Scaled size of OIL pixels that this view uses - default to scale of 100%
00191     ScaledPixelWidth = ScaledPixelHeight = PixelWidth;
00192 
00193     // View scale factor - default to 100%
00194     Scale = 1.0;
00195 
00196     // Initialise our ColourPlate and colour contexts to NULL pointers
00197     ForceDefaultColourContexts = FALSE;
00198     ColPlate = NULL;
00199 
00200     for (INT32 i = 0; i < (INT32) MAX_COLOURMODELS; i++)
00201     {
00202         ColourContexts.Context[i] = NULL;
00203         ShouldDeleteContext[i] = TRUE;
00204     }
00205 
00206     m_bSolidDrag = FALSE;
00207 }
00208 
00209 
00210 
00211 /********************************************************************************************
00212 
00213 >   View::~View()
00214 
00215     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00216     Created:    02/23/95
00217     Purpose:    Cleans up a view object.
00218     SeeAlso:    View
00219 
00220 ********************************************************************************************/
00221 
00222 View::~View()
00223 {
00224     if (this == Current)
00225         SetNoCurrent();
00226 
00227     // Decommission all colour contexts that we own
00228     ColourContextList  *cclist = ColourContextList::GetList();
00229     ERROR3IF( cclist == NULL, "No ColourContextList? What's up?" );
00230 
00231     // Delete any old context we had in use (ignoring the ShouldDeleteContext flags)
00232     for (INT32 i = 0; i < (INT32) MAX_COLOURMODELS; i++)
00233     {
00234         if (ColourContexts.Context[i] != NULL)
00235             cclist->RemoveContext(&(ColourContexts.Context[i]));
00236     }
00237 
00238     if (ColPlate != NULL)
00239         delete ColPlate;
00240 
00241     if (pVState != NULL)
00242     {
00243         delete pVState;
00244         pVState=NULL;
00245     }
00246 }
00247 
00248 /********************************************************************************************
00249 
00250 >   void View::AllocateDC()
00251 
00252     Author:     Alex Bligh <alex@alex.org.uk>
00253     Created:    12/06/2006
00254     Purpose:    Hints that we've done with our DC
00255     SeeAlso:    View; PaperRenderRegion.
00256 
00257 Note this is merely a hint. This routine is not guaranteed to eb called
00258 
00259 ********************************************************************************************/
00260 
00261 void View::AllocateDC()
00262 {
00263     if (pViewWindow)
00264         pViewWindow->AllocateDC();
00265 }
00266 
00267 /********************************************************************************************
00268 
00269 >   void View::DoneWithDC()
00270 
00271     Author:     Alex Bligh <alex@alex.org.uk>
00272     Created:    12/06/2006
00273     Purpose:    Hints that we've done with our DC
00274     SeeAlso:    View; PaperRenderRegion.
00275 
00276 Note this is merely a hint. This routine is not guaranteed to eb called
00277 
00278 ********************************************************************************************/
00279 
00280 void View::DoneWithDC()
00281 {
00282     if (pViewWindow)
00283         pViewWindow->DoneWithDC();
00284 }
00285 
00286 /********************************************************************************************
00287 
00288 >   void View::Deinit()
00289 
00290     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00291     Created:    02/23/95
00292     Purpose:    De-initialises the view system.  At the moment this involves destroying
00293                 our PaperRenderRegion.
00294     SeeAlso:    View; PaperRenderRegion.
00295 
00296 ********************************************************************************************/
00297 
00298 void View::Deinit()
00299 {
00300     // Lose our PaperRenderRegion...
00301     delete pPaperRegion;
00302     delete pOnTopRegion;
00303 }
00304 
00305 
00306 /********************************************************************************************
00307 
00308 >   BOOL View::ConnectToOilView(CCamView* pOilView)
00309 
00310     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00311     Created:    18/5/93
00312     Inputs:     Pointer to view object in the OIL layer which we will mirror.
00313     Outputs:    None
00314     Returns:    None
00315     Purpose:    To set up the bi-directional connection between the OIL view object and the
00316                 View. The OIL view object causes the creation of the View and so
00317                 already has a pointer to it when it calls this routine to set up the
00318                 connection in the other direction.
00319     Errors:     None
00320 
00321 ********************************************************************************************/
00322 
00323 BOOL View::ConnectToOilView(CCamView* pOilView)
00324 {
00325     ERROR2IF(this==NULL,FALSE,"View member func called on NULL pointer");
00326 
00327     ERROR2IF(pViewWindow != NULL, FALSE,
00328                 "View::ConnectToOilView called when connection already established");
00329 
00330     pViewWindow = pOilView;
00331 
00332     return TRUE;
00333 }
00334 
00335 
00336 /********************************************************************************************
00337 
00338 >   CCamView* View::GetConnectionToOilView()
00339 
00340     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00341     Created:    18/5/93
00342     Returns:    Pointer to the OIL view object which mirrors this one.
00343     Purpose:    To get a pointer to the OIL view object which mirrors this one. Note that
00344                 this can return NULL if the View does not have a mirroring OIL object. In
00345                 this case the view is closed but the View remains available so that in the
00346                 future a new view will be able to use all of its viewing parameters.
00347 
00348 ********************************************************************************************/
00349 
00350 CCamView* View::GetConnectionToOilView() const
00351 {
00352     return pViewWindow;
00353 }
00354 
00355 
00356 
00357 /********************************************************************************************
00358 
00359 >   Document* View::GetDoc() const
00360 
00361     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
00362     Created:    28/3/94
00363     Returns:    A pointer to the kernel Document associated with this View.
00364     Purpose:    Returns the linake between this View and its Document.
00365 
00366 ********************************************************************************************/
00367 
00368 Document* View::GetDoc() const
00369 {
00370     return pDoc;
00371 }
00372 
00373 
00374 /*********************************************************************************************
00375 
00376 >   static View *View::GetCurrent()
00377 
00378     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00379     Created:    24/5/93
00380     Returns:    Pointer to the current View object.
00381     Purpose:    Find the current View object which SHOULD have been set as one of the very 
00382                 first actions during event processing.             
00383                                                                  
00384 *********************************************************************************************/
00385 
00386 View *View::GetCurrent()
00387 {
00388 #ifdef RALPH
00389     if(::GetCurrentThreadId() == RalphDocument::GetImportingThreadID())
00390     {
00391         return RalphDocument::GetImportingDoc()->GetFirstDocView();
00392     }
00393 #endif
00394 
00395     return Current;
00396 }
00397 
00398 
00399 /*********************************************************************************************
00400 
00401 >   BOOL View::SetCurrent()
00402 
00403     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00404     Created:    24/5/93
00405     Returns:    TRUE if function set current correctly
00406                 FALSE otherwise (then an Error has been set)
00407     Purpose:    Make this object be the 'current' View.
00408 
00409 *********************************************************************************************/
00410 
00411 BOOL View::SetCurrent()
00412 {
00413 #ifdef RALPH
00414     // if we are being called from the load thread just ignore 
00415     if(::GetCurrentThreadId() == RalphDocument::GetImportingThreadID())
00416         return TRUE;
00417 #endif
00418     if (Current!=this)
00419     {
00420         Current = this;
00421 
00422         if (this != NULL)
00423         {
00424             SetViewPixelSize();
00425             if (pDoc != NULL) 
00426                 pDoc->SetCurrent();
00427         }
00428     }
00429 
00430     return TRUE;
00431 }                                                     
00432 
00433 
00434 
00435 /*********************************************************************************************
00436 
00437 >   static void View::SetNoCurrent()
00438 
00439     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00440     Created:    24/5/93
00441     Purpose:    Set the current View pointer to be NULL, i.e., there is no current
00442                 View object.
00443                                                                  
00444 *********************************************************************************************/
00445 
00446 void View::SetNoCurrent()
00447 {
00448 #ifdef RALPH
00449     // if we are being called from the load thread just ignore 
00450     if(::GetCurrentThreadId() == RalphDocument::GetImportingThreadID())
00451         return ;
00452 #endif
00453 
00454     // Set no current View or Document.
00455     Current = NULL;
00456     Document::SetNoCurrent();
00457 }
00458 
00459 
00460 
00461 /********************************************************************************************
00462 
00463 >   void View::SetViewState(ViewState*)
00464 
00465     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00466     Created:    18/5/93
00467     Returns:    A pointer to the ViewState object associated with this View.
00468     Purpose:    Sets the structure which is shared by both View and the OIL view
00469                 object to which it is connected.  NB. PrintViews do NOT share the
00470                 ViewState with the OIL view, because the OIL view is the screen based view,
00471                 so the PrintView is the only one that needs to use the view state.  The
00472                 CCamView always uses the ViewState of its DocView, not its PrintView.
00473 
00474 ********************************************************************************************/
00475 
00476 void View::SetViewState(ViewState* pvs)
00477 {
00478     ERROR3IF(pvs == NULL, "View::SetViewState called with a null parameter!");
00479     
00480     // Justin here: removed this ERROR3 because it stops the workspace restoration code
00481     // working.  This is a temp fix, just for the 1.1 release.  What we need is a function
00482     // that allows you to *change* the ViewState this View refers to, and unfortunately
00483     // the effect of these two ERROR3's is to make that impossible, as you can't pass a new
00484     // ViewState, or set th existing one to null.
00485 //  ERROR3IF(pVState != NULL, "View::SetViewState called when view already has a view state.");
00486     
00487     pVState = pvs;
00488     
00489     // Inform the ViewState object which view it is describing.
00490     pVState->pView = this;
00491 }
00492 
00493 /*********************************************************************************************
00494 
00495 >   RenderRegion *View::NewRenderRegion(DocRect InvalidRect, Matrix& ViewMatrix,
00496                                         CDC* pDevContext, Spread* pSpread, 
00497                                         RenderType rType)
00498     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00499     Created:    27/5/93
00500     Inputs:     rType gives a hint of the type of the device
00501     Returns:    Pointer to a new RenderRegion, or NULL if failed.
00502     Scope:      Protected
00503     Purpose:    Make a new RenderRegion of the correct type
00504                 then do all the common things that have to be done to a new RenderRegion before 
00505                 returning it.
00506                 If the rectangle passed in is empty then no region will be created!
00507     Errors:     NULL return if RR::Create or AttachDevice failed.
00508                                                                  
00509 *********************************************************************************************/
00510 
00511 RenderRegion *View::NewRenderRegion(DocRect InvalidRect, Matrix& ViewMatrix,
00512                                     CNativeDC *pDevContext, Spread* pSpread, RenderType rType,
00513                                     bool fOwned /*= false*/ )
00514 {
00515     RenderRegion *pNewRRegion;
00516 
00517     if (rType == RENDERTYPE_SCREENXOR)
00518     {
00519         if (pOnTopRegion == NULL)
00520         {
00521             // No OnTop rendering region - get a new render region of 
00522             // the special type RENDERTYPE_SCREENPAPER.
00523             pOnTopRegion = (PaperRenderRegion *) NewRenderRegion(InvalidRect, ViewMatrix,
00524                                                                  pDevContext, pSpread,
00525                                                                  RENDERTYPE_SCREENPAPER, fOwned );
00526             pOnTopRegion->SaveContext();
00527         }
00528         else
00529         {
00530             // Change the device of the OnTop rendering region
00531             pOnTopRegion->AttachDevice(this, pSpread, pDevContext, 
00532                                        ViewMatrix, Scale, InvalidRect, fOwned );
00533         }
00534 
00535         pNewRRegion = pOnTopRegion;
00536     }
00537     else
00538     {
00539         // JCF: added 'this' argument to the end of the list.
00540         pNewRRegion = OSRenderRegion::Create(InvalidRect, ViewMatrix, Scale, rType, this);
00541 
00542         // If the construction was succesful then
00543         // Attach the new RenderRegion to a Window and its DC for rendering...
00544         if (pNewRRegion)
00545         {
00546             if (!pNewRRegion->AttachDevice(this, pDevContext, pSpread, fOwned))
00547             {
00548                 // the AttachDevice failed, so tidy up
00549                 delete pNewRRegion;
00550                 pNewRRegion = NULL;
00551             }
00552         }
00553     }
00554 
00555     return pNewRRegion;
00556 }
00557 
00558 /*********************************************************************************************
00559 
00560 >   void View::DeInitOnTopRegion()
00561 
00562     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
00563     Created:    2/5/95
00564     Purpose:    Deinitialises the static OnTop RenderRegion, used for blob rendering.
00565                                                                  
00566 *********************************************************************************************/
00567 
00568 void View::DeInitOnTopRegion()
00569 {
00570     if (pOnTopRegion)
00571         pOnTopRegion->DetachDevice();
00572 }
00573 
00574 
00575 /********************************************************************************************
00576 
00577 >   void View::MakeNewRenderRegion(Spread *pSpread, DocRect ClipRect, CDC *pDevContext,
00578                                    RenderType rType, BOOL PaintPaper = FALSE, Node* pInvalidNode = NULL)
00579 
00580     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00581     Created:    14/12/94
00582     Inputs:     pSpread - pointer to the spread concerned
00583                 ClipRect - Rectangle to create region from
00584                 pDevContect - pointer to the device context for this region (may be NULL
00585                                 if PaintPaper == FALSE)
00586                 rType - type of rendering
00587                 PaintPaper - TRUE if paper should be redrawn immediately, FALSE otherwise
00588                              (ignored for non-screen render regions).
00589     Outputs:    -
00590     Returns:    -
00591     Purpose:    Makes a new render region and adds it to the list associated with the DocView.
00592                 Depending on the type of render region requested, it may be rendered to
00593                 completion immediately (e.g. print regions are).
00594                 Note that if PaintPaper is FALSE, pDevContext isn't used, so can be NULL.
00595 
00596 ********************************************************************************************/
00597 
00598 void View::MakeNewRenderRegion(Spread *pSpread, DocRect ClipRect, CNativeDC *pDevContext,
00599                                RenderType rType, BOOL PaintPaper, Node* pInvalidNode)
00600 {
00601     // Construct the transformation matrix for the spread.
00602     Matrix RenderMatrix = ConstructRenderingMatrix(pSpread);
00603 
00604     // Go and create the new render region
00605     RenderRegion *NewRegion = NULL;
00606 
00607     if (pViewWindow != NULL)
00608     {
00609 //      NewRegion = NewRenderRegion(ClipRect, RenderMatrix, GetRenderDC(), pSpread, rType);
00610         // GAT - Is it safe to change the above line to the one below?
00611         NewRegion = NewRenderRegion(ClipRect, RenderMatrix, pDevContext, pSpread, rType);
00612     }
00613 
00614     if (NewRegion == NULL)
00615     {
00616         TRACEALL( _T("Not enough memory to create render region\n") );
00617         return;
00618     }
00619 
00620     if (rType == RENDERTYPE_SCREEN)
00621     {
00622         if (PaintPaper)
00623         {
00624             // Call helper function defined below
00625             RenderPaper(pSpread, ClipRect, pDevContext, RenderMatrix);
00626         }
00627         else
00628         {
00629             // Caller does not want paper to be rendered, so set the flag to indicate that
00630             // OS paper rendering is not needed.
00631             NewRegion->NeedsOSPaper = FALSE;
00632         }
00633     }
00634 
00635     NewRegion->SetBackmostChangedNode(pInvalidNode);
00636 
00637     // Add the region to the list of regions to render and start the
00638     // rendering process off if it has some ink to render
00639     Camelot.AddRenderRegion(NewRegion);
00640 }
00641 
00642 
00643 
00644 /********************************************************************************************
00645 
00646 >   virtual void View::RenderPaper(Spread *pSpread, DocRect ClipRect, CDC *pDevContext, Matrix& RenderMatrix)
00647 
00648     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
00649     Created:    30/6/95
00650     Inputs:     pSpread - pointer to the spread concerned
00651                 ClipRect - Rectangle to create region from
00652                 pDevContect - pointer to the device context for this region (may be NULL
00653                                 if PaintPaper == FALSE)
00654     Outputs:    -
00655     Returns:    -
00656     Purpose:    Actually renders the paper onto the screen. Moved from 'MakeNewRenderRegion'
00657                 so that it can be called from outside (eg. ResetRegion)
00658 
00659 ********************************************************************************************/
00660 
00661 void View::RenderPaper(Spread *pSpread, DocRect ClipRect, CNativeDC *pDevContext, Matrix& RenderMatrix)
00662 {
00663 //  TRACE( _T("View::RenderPaper\n") );
00664     if (pPaperRegion == NULL)
00665     {
00666         // No paper rendering region - get a new render region of 
00667         // the special type RENDERTYPE_SCREENPAPER.
00668         pPaperRegion = (PaperRenderRegion *) NewRenderRegion(ClipRect, RenderMatrix,
00669                                                              pDevContext, pSpread,
00670                                                              RENDERTYPE_SCREENPAPER);
00671 
00672         // We save the context here, so that PaperRenderRegion::DetachDevice() can
00673         // throw away all the attributes.  We only need to do it here because
00674         // PaperRenderRegion::AttachDevice() (see 2 inches below) calls SaveContext()
00675         // automagically.
00676         pPaperRegion->SaveContext();
00677     }
00678     else
00679     {
00680         // Change the device of the paper rendering region
00681         pPaperRegion->AttachDevice(this, pSpread, pDevContext, 
00682                                    RenderMatrix, Scale, ClipRect);
00683     }
00684 
00685     // Set up the rendering system.
00686     if (!pPaperRegion->StartRender())
00687     {
00688         TRACEALL( _T("StartRender failed for paper in OnDraw\n") );
00689         return;
00690     }
00691 
00692     // Render the paper objects using the permanent PaperRenderRegion.
00693     pPaperRegion->SaveContext();
00694     RenderPaper(pPaperRegion, pSpread);
00695     pPaperRegion->RestoreContext();
00696     pPaperRegion->StopRender();
00697     pPaperRegion->DetachDevice();
00698 
00699     // Draw the DragBlobs.
00700     Operation* pOp = Operation::GetCurrentDragOp();
00701     if (pOp != NULL)
00702         pOp->RenderDragBlobs(ClipRect, pSpread, m_bSolidDrag);
00703 }
00704 
00705 
00706 /********************************************************************************************
00707 
00708 >   virtual void View::RenderPaper(RenderRegion* pRRegion, Spread* pSpread) 
00709 
00710     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00711     Created:    19/5/93
00712     Inputs:     pRRegion - The render region to draw in
00713                 pSpread - the spread to draw
00714     Scope:      Private
00715     Purpose:    To render the parts of a Document which are not rendered when printing. Ie. all 
00716                 the parts of the document that represent the paper on which the ink will be 
00717                 rendered.
00718                 This function does not take any notice of the RenderControl object - it renders 
00719                 until it has finished so that at least the pages, pasteboard, etc. will be 
00720                 drawn when any region is invalidated.
00721 
00722 ********************************************************************************************/
00723 /*
00724 Technical notes:
00725                 Assumes that the node that it is passed is the first node in the tree and that 
00726                 this node does NOT need to be rendered as part of the Paper view.
00727 
00728 ********************************************************************************************/
00729 
00730 void View::RenderPaper(RenderRegion* pRRegion, Spread* pSpread)
00731 {
00732     // We always want paper to render to the same display quality level.
00733     pRRegion->SetDefaultQuality();
00734 
00735     Node* pn = (Node*) pSpread;
00736 
00737     // First render all the paper nodes in the tree through the given RenderRegion...
00738     while (pn != NULL)
00739     {
00740 //TRACEUSER("Phil", _T("RenderPaper for %x - %x\n"), pSpread, pn);
00741         pn->Render(pRRegion);
00742         pn = pn->FindNextForClippedPaperRender();
00743     }
00744 
00745 #ifndef STANDALONE
00746     // Render the printable area using the document's PrintControl object, but only if this
00747     // is a DocView & the ShowPrintBorder's flag is set
00748     if (GetRuntimeClass() == CC_RUNTIME_CLASS(DocView))
00749     {
00750         DocView* pDocView = (DocView*)this;
00751 
00752         if (pDoc!=NULL)
00753         {
00754             if (pDocView->GetShowPrintBorders())
00755             {
00756                 PrintComponent* pPrComp = (PrintComponent*)pDoc->GetDocComponent(CC_RUNTIME_CLASS(PrintComponent));
00757                 if (pPrComp != NULL)
00758                 {
00759                     PrintControl* pPrCtrl = pPrComp->GetPrintControl();
00760                     if (pPrCtrl != NULL)
00761                         pPrCtrl->RenderPrintBorder(pRRegion);
00762                 }
00763             }
00764         }
00765     }   
00766 #endif
00767 }
00768 
00769 
00770 
00771 /********************************************************************************************
00772 
00773 >   virtual void View::RenderPageMarks(Spread *pSpread, 
00774                                        DocRect ClipRect,
00775                                        CDC *pDevContext,
00776                                        Matrix& RenderMatrix
00777                                        RenderType rType)
00778 
00779     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00780     Created:    08/08/96
00781     Inputs:     pSpread     - pointer to the spread concerned
00782                 ClipRect    - Rectangle to create region from
00783                 pDevContect - pointer to the device context for this region (may be NULL
00784                                 if PaintPaper == FALSE)
00785                 RenderMatrix- the render matrix to use.
00786                 rType       - the type of render to give the region
00787 
00788     Outputs:    -
00789     Returns:    -
00790     Purpose:    Performs the rendering of page marks, ie crop marks, registration marks etc
00791                 to the screen and printer. This base class version does nothing. All
00792                 mark rendering technology is held in DocView and PrintView.
00793     SeeAlso:    DocView, PrintView
00794 
00795 ********************************************************************************************/
00796 
00797 BOOL View::RenderPageMarks(RenderRegion *pCurrRegion, Matrix &ViewTrans, DocRect &ClipRect, Spread *pSpread)
00798 {
00799 #if !defined(EXCLUDE_FROM_RALPH)
00800 #ifndef STANDALONE
00801 
00802 /*
00803     // Ask the render region not to render complex shapes
00804     BOOL OldState = pCurrRegion->SetRenderComplexShapes(FALSE);
00805 
00806     // Create and set an identity matrix. We will cope with
00807     // the view transform later
00808     Matrix OldMatrix = pCurrRegion->GetMatrix();
00809     Matrix Identity;
00810 
00811     // Work out the transformed clip rectangle onto the paper
00812     DocRect TransformedClipRect(ClipRect);
00813     ViewTrans.transform(&TransformedClipRect.lo);
00814     ViewTrans.transform(&TransformedClipRect.hi);
00815 
00816     MILLIPOINT Tmp;
00817 
00818     if (TransformedClipRect.lo.x > TransformedClipRect.hi.x)
00819     {
00820         Tmp = TransformedClipRect.lo.x;
00821         TransformedClipRect.lo.x = TransformedClipRect.hi.x;
00822         TransformedClipRect.hi.x = Tmp;
00823     }
00824 
00825     if (TransformedClipRect.lo.y > TransformedClipRect.hi.y)
00826     {
00827         Tmp = TransformedClipRect.lo.y;
00828         TransformedClipRect.lo.y = TransformedClipRect.hi.y;
00829         TransformedClipRect.hi.y = Tmp;
00830     }
00831 
00832 //  pCurrRegion->SetMatrix(ViewTrans);
00833     pCurrRegion->SetClipRect(TransformedClipRect);
00834     pCurrRegion->SetMatrix(Identity);
00835 
00836     // Start the render region and return if it fails
00837     if (!pCurrRegion->StartRender())
00838     {
00839         pCurrRegion->SetMatrix(OldMatrix);
00840 
00841         pCurrRegion->SetRenderComplexShapes(OldState);
00842         return FALSE;
00843     }
00844 */
00845     // start a save context for attributes
00846     pCurrRegion->SaveContext();
00847 
00848     if (pCurrRegion!=NULL && pSpread!=NULL)
00849     {
00850         if (!IS_A(pCurrRegion,PaperRenderRegion))
00851         {
00852             // find this documents print mark component.
00853             Document* pDoc = (Document*)pSpread->FindOwnerDoc();
00854             if (pDoc)
00855             {
00856                 // ok, render all the print marks where necessary.
00857                 PrintMarksMan* pMarksMan = GetApplication()->GetMarksManager();
00858                 if (pMarksMan!=NULL)
00859                 {
00860                     // find this documents print mark component.
00861                     PrintMarksComponent* pMarksComp = (PrintMarksComponent*)pDoc->GetDocComponent(CC_RUNTIME_CLASS(PrintMarksComponent));
00862                     if (pMarksComp != NULL)
00863                         pMarksMan->RenderPrintMarks(pMarksComp, pCurrRegion, ViewTrans, ClipRect, pSpread);
00864                 }
00865             }
00866         }
00867     }
00868 
00869     pCurrRegion->RestoreContext();
00870 /*
00871     pCurrRegion->StopRender();
00872 
00873     // Done rendering the print marks
00874     pCurrRegion->SetMatrix(OldMatrix);
00875     pCurrRegion->SetClipRect(ClipRect);
00876     pCurrRegion->SetRenderComplexShapes(OldState);
00877 */
00878 
00879 #endif
00880 #endif
00881     return TRUE;    
00882 }
00883 
00884 
00885 
00886 
00887 /********************************************************************************************
00888 
00889 >   void View::OnDraw(CDC* pDevContext, OilRect OilClipRect)
00890 
00891     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> & Rik & JustinF
00892     Created:    10/12/93
00893     Inputs:     pDevContext - the device context of the view to render.
00894                 OilClipRect - the clipping rectangle of the invalid region (in OilCoords).
00895     Purpose:    Do the drawing, guv.
00896 
00897 ********************************************************************************************/
00898 
00899 void View::OnDraw( CNativeDC *pDevContext, OilRect OilClipRect )
00900 {
00901     if (CCamApp::IsDisabled())
00902         return;                             // If the system is disabled, ignore
00903 
00904 //  TRACE( _T("View::OnDraw\n") );
00905     
00906 //  TRACE( _T("Rect = (%d, %d, %d, %d)"), OilClipRect.lo.x, OilClipRect.lo.y, OilClipRect.hi.x, OilClipRect.hi.y );
00907 
00908     // find type of rendering device
00909     const RenderType rType = CCDC::GetType(pDevContext, TRUE);
00910 
00911     // Convert OilClipRect to 64 bit WorkCoords
00912     WorkRect ClipRect = OilClipRect.ToWork(pVState->GetScrollPos());
00913 //TRACE( _T("View::GetScrollPos : %d %d"),(INT32)(pVState->GetScrollPos().x/750),(INT32)(pVState->GetScrollPos().y/750));
00914 //TRACE( _T("ClipRect : %d %d %d %d\n"),(INT32)(ClipRect.lo.x/750),(INT32)(ClipRect.lo.y/750),(INT32)(ClipRect.hi.x/750),(INT32)(ClipRect.hi.y/750));
00915 
00916     ERROR3IF(ClipRect.lo.x > ClipRect.hi.x, "DocView::OnDraw clipping rect is invalid");
00917     ERROR3IF(ClipRect.lo.y > ClipRect.hi.y, "DocView::OnDraw clipping rect is invalid");
00918 
00919     // Use the last chapter as a sentinel.
00920     Chapter* pLastChapter = (Chapter*) pDoc->GetFirstNode()->
00921                                 FindNext()->FindLastChild(CC_RUNTIME_CLASS(Chapter));
00922 
00923     // Find all the spreads in the document that intersect the clipping rect, and create
00924     // a render region for each of them.
00925 
00926     // Iterate over the chapters in the document.
00927     for (Chapter* pChapter = Node::FindFirstChapter(pDoc);
00928          pChapter != 0;
00929          pChapter = pChapter->FindNextChapter())
00930     {
00931         // Convert chapter bounding box to logical coords
00932         WorkRect LogChapterRect;
00933         DocRect PhysChapterRect = pChapter->GetPasteboardRect(TRUE, this);
00934         LogChapterRect.lo = PhysChapterRect.lo.ToWork(pDoc, this);
00935         LogChapterRect.hi = PhysChapterRect.hi.ToWork(pDoc, this);
00936 
00937         BOOL IsLastChapter = (pChapter == pLastChapter);
00938 
00939         // Check to see if this chapter intersects the clipping rectangle.
00940         // If the chapter is the last one in the document, then the chapter's pasteboard
00941         // does not include the area of the bottom of the last spread, so we only check
00942         // the chapter's top boundary.
00943         if (ClipRect.lo.y <= LogChapterRect.hi.y &&
00944             (IsLastChapter || ClipRect.hi.y >= LogChapterRect.lo.y))
00945         {
00946             // Find the last spread in the chapter.
00947             Spread* pLastSpread = (Spread*) pChapter->FindLastChild(CC_RUNTIME_CLASS(Spread));
00948 
00949             // Iterate over the spreads in the chapter.
00950             for (Spread* pSpread = pChapter->FindFirstSpread();
00951                  pSpread != 0;
00952                  pSpread = pSpread->FindNextSpread())
00953             {
00954                 // Convert spread bounding box to logical coords
00955                 DocRect PhysSpreadRect = pSpread->GetPasteboardRect(TRUE, this);    // Pixelised
00956 
00957                 WorkRect LogSpreadRect;
00958                 LogSpreadRect.lo = PhysSpreadRect.lo.ToWork(pSpread, this);
00959                 LogSpreadRect.hi = PhysSpreadRect.hi.ToWork(pSpread, this);
00960 
00961                 BOOL IsLastSpread = (pSpread == pLastSpread);
00962 
00963                 // Check if spread intersects the clipping rect
00964                 if (ClipRect.lo.y <= LogSpreadRect.hi.y &&
00965                     ((IsLastChapter && IsLastSpread) || ClipRect.hi.y >= LogSpreadRect.lo.y))
00966                 {
00967                     // Make render region for intersection between spread and cliprect.
00968                     DocRect SpreadClipRect = pSpread->GetWidePasteboard(this);
00969 
00970                     // Convert clip rectangle to document coords
00971                     DocRect DocClipRect = OilClipRect.ToDoc(pSpread, this);
00972 
00973                     // Clip to spread rectangle
00974                     SpreadClipRect = SpreadClipRect.Intersection(DocClipRect);
00975 
00976                     // Make sure that the clip region is valid after the intersection
00977                     if (SpreadClipRect.IsValid() && !SpreadClipRect.IsEmpty())
00978                     {
00979                         // Convert document coords to spread coords and make a render region.
00980                         pSpread->DocCoordToSpreadCoord(&SpreadClipRect);
00981                         MakeNewRenderRegion(pSpread, SpreadClipRect, pDevContext, rType, TRUE);
00982                     }
00983                 }
00984             }
00985         }
00986     }
00987 
00988 //  TRACE( _T("Leaving View::OnDraw\n") );
00989 }
00990 
00991 
00992 
00993 /********************************************************************************************
00994 
00995 >   BOOL View::SetScrollOffsets(WorkCoord NewTopLeft, BOOL RedrawNeeded = TRUE)
00996 
00997     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00998     Created:    6/7/93
00999     Inputs:     New scroll offsets
01000                 Flag to control whether redraw is needed or not
01001     Purpose:    To scroll this view to a new position over the document. The coordinate
01002                 supplied is the coordinate of the top left corner of the viewport onto the
01003                 document. The RedrawNeeded flag is TRUE when any invalid areas created should
01004                 be redrawn immediately and FALSE if they should be ignored.
01005 
01006 ********************************************************************************************/
01007 
01008 BOOL View::SetScrollOffsets(WorkCoord NewTopLeft, BOOL RedrawNeeded)
01009 {
01010 //  TRACE(_T("View::SetScrollOffsets(%d, %d)\n"), (INT32)(NewTopLeft.x), (INT32)(NewTopLeft.y));
01011     ERROR2IF(this==NULL,FALSE,"View member func called on NULL pointer");
01012 
01013     //Graham 7/12/97: Downgraded to an error 3, otherwise this can go off in retail builds
01014     if (NewTopLeft.x < (XLONG)0  || NewTopLeft.y > (XLONG)0)
01015     {
01016         ERROR3("View::SetScrollOffsets - invalid parameters");
01017         return FALSE;
01018     }
01019 
01020     pVState->SetScrollPos(NewTopLeft);          // Set the new scroll offsets
01021     return TRUE;
01022 }
01023 
01024 
01025 
01026 
01027 /********************************************************************************************
01028 
01029 >   WorkCoord View::GetScrollOffsets() const
01030 
01031     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01032     Created:    6/7/93
01033     Returns:    Top left corner of the viewport in WorkCoords.
01034     Purpose:    To find the position of the top left corner of the display.
01035 
01036 ********************************************************************************************/
01037 
01038 WorkCoord View::GetScrollOffsets() const
01039 {
01040     ERROR2IF(this==NULL,WorkCoord(0,0),"View member func called on NULL pointer");
01041 
01042     return pVState->GetScrollPos();
01043 }
01044 
01045 
01046 
01047 /*********************************************************************************************
01048 
01049 >   BOOL View::SetViewScale(FIXED16 NewScale)
01050 
01051     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01052     Created:    31/5/93
01053     Inputs:     New view scale factor
01054     Purpose:    Set the viewing scale factor for this view.
01055                 (Also, sets up the scaled pixel size in DocCoord if this View is current.
01056                                                                  
01057 *********************************************************************************************/
01058 
01059 BOOL View::SetViewScale(FIXED16 NewScale)
01060 {
01061     ERROR2IF(this==NULL,FALSE,"View member func called on NULL pointer");
01062     ERROR2IF(pVState==NULL,FALSE,"View not connected to ViewState");
01063 
01064     // Set the new scale
01065     pVState->ViewScale = Scale = NewScale;
01066 
01067     // Set up the scaled pixel size for this view according to new scale.
01068     SetViewPixelSize();
01069 
01070     // Inform the Viewstate that it has been changed and that the doc extent may
01071     // need to be recomputed...
01072     ViewStateChanged();
01073 
01074     return TRUE;
01075 }
01076 
01077 
01078 
01079 
01080 /*********************************************************************************************
01081 
01082 >   FIXED16 View::GetViewScale() const
01083 
01084     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01085     Created:    31/5/93
01086     Returns:    Viewing scale factor for this view.
01087     Purpose:    Inquire the viewing scale factor from this View.
01088                                                                  
01089 *********************************************************************************************/
01090 
01091 FIXED16 View::GetViewScale() const
01092 {
01093     return Scale;
01094 }
01095 
01096 
01097 
01098 
01099 /********************************************************************************************
01100 
01101 >   Matrix View::ConstructRenderingMatrix(Spread *pSpread)
01102 
01103     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> & Rik
01104     Created:    10/12/93
01105     Inputs:     pSpread - the spread that is to be rendered.
01106     Returns:    The required transformation matrix.
01107     Purpose:    From the given spread, construct a matrix that will convert spread
01108                 coordinates to OS coordinates.
01109     SeeAlso:    DocView::OnDraw
01110 
01111 ********************************************************************************************/
01112 
01113 Matrix View::ConstructRenderingMatrix(Spread *pSpread)
01114 {
01115     // Get the PIXELISED origin of spread coordinates, in document coords
01116     DocCoord SpreadCoordOrigin = pSpread->GetSpreadCoordOrigin(TRUE, this);
01117 
01118     // Convert it into logical Work Coords
01119     // NOTE: We convert this via the spread, because the Spread Coord Origin can now
01120     // lie *outside* the current chapter/spread pasteboard bounds, and so the version
01121     // of this call that takes a document pointer can't find the enclosing chapter!
01122     // Of course, we know the enclosing chapter, because this point is in a known spread!
01123     WorkCoord WorkCoordOffset = SpreadCoordOrigin.ToWork(pSpread, this);
01124 
01125     // Offset it by the window scroll position
01126     WorkCoordOffset.x -= pVState->GetScrollPos().x;
01127     WorkCoordOffset.y -= pVState->GetScrollPos().y;
01128 
01129     // Just in case the above hasn't work (the DocCoord conversion seems to produce some rounding
01130     // errors), Pixelize the offset
01131     WorkCoordOffset.Pixelise(72000.0/PixelWidth.MakeDouble(),72000.0/PixelHeight.MakeDouble());
01132     
01133     // Construct the transformation matrix for the spread.
01134     Matrix RenderMatrix;
01135 
01136     // We can chop the 64bit values down to 32bit now, as we have them in the correct range
01137     Matrix TranslateToOrigin( (INT32)WorkCoordOffset.x, (INT32)WorkCoordOffset.y);
01138 
01139     Matrix ScaleMat(Scale, Scale);
01140 
01141     // The following matrix compositions MUST be performed in this order.
01142     // If you are tempted to optimise this code MAKE SURE THAT THEY ARE STILL
01143     // IN THIS ORDER WHEN YOU'VE FINISHED!
01144 
01145     // Apply scale factors to convert from millipoint distances to pixel distances...
01146     RenderMatrix *= ScaleMat;
01147 
01148     // Apply scroll-offset translation to move origin to viewing position...
01149     RenderMatrix *= TranslateToOrigin;
01150 
01151     return RenderMatrix;
01152 }
01153 
01154 /********************************************************************************************
01155 
01156 >   Matrix View::ConstructScaledRenderingMatrix(Spread *pSpread, double ScaleFactor)
01157 
01158     Author:     Ilan_Copelyn (Xara Group Ltd) <camelotdev@xara.com>
01159     Created:    06/06/00
01160     Inputs:     pSpread     = the spread that is to be rendered.
01161                 ScaleFactor = multiplier for current Scale (ie zoom factor)
01162     Returns:    The required transformation matrix.
01163     Purpose:    Create a rendermatrix at ScaleFactor precision of the current Scale
01164                 Allows you to create a bitmap with higher/lower resolution than the
01165                 current view
01166                 eg used to create a bitmap of a given invalid region at double the current
01167                 zoom factor (ie synonymous concept to "double resolution" or "double DPI")
01168     SeeAlso:    View::ConstructRenderingMatrix(Spread *pSpread)
01169 
01170 ********************************************************************************************/
01171 Matrix View::ConstructScaledRenderingMatrix(Spread *pSpread, double ScaleFactor)
01172 {
01173     // Get the PIXELISED origin of spread coordinates, in document coords
01174     DocCoord SpreadCoordOrigin = pSpread->GetSpreadCoordOrigin(TRUE, this);
01175 
01176     // Convert it into logical Work Coords
01177     // NOTE: We convert this via the spread, because the Spread Coord Origin can now
01178     // lie *outside* the current chapter/spread pasteboard bounds, and so the version
01179     // of this call that takes a document pointer can't find the enclosing chapter!
01180     // Of course, we know the enclosing chapter, because this point is in a known spread!
01181     WorkCoord WorkCoordOffset = SpreadCoordOrigin.ToWork(pSpread, this);
01182 
01183     // Offset it by the window scroll position
01184     WorkCoordOffset.x -= pVState->GetScrollPos().x;
01185     WorkCoordOffset.y -= pVState->GetScrollPos().y;
01186     
01187     // Construct the transformation matrix for the spread.
01188     Matrix RenderMatrix;
01189 
01190     // We can chop the 64bit values down to 32bit now, as we have them in the correct range
01191     Matrix TranslateToOrigin( (INT32)WorkCoordOffset.x, (INT32)WorkCoordOffset.y);
01192 
01193     FIXED16 ScaledScale = Scale.MakeDouble() * ScaleFactor;
01194     Matrix ScaleMat(ScaledScale, ScaledScale);
01195 
01196     // The following matrix compositions MUST be performed in this order.
01197     // If you are tempted to optimise this code MAKE SURE THAT THEY ARE STILL
01198     // IN THIS ORDER WHEN YOU'VE FINISHED!
01199 
01200     // Apply scale factors to convert from millipoint distances to pixel distances...
01201     RenderMatrix *= ScaleMat;
01202 
01203     // Apply scroll-offset translation to move origin to viewing position...
01204     RenderMatrix *= TranslateToOrigin;
01205 
01206     return RenderMatrix;
01207 }
01208 
01209 
01210 /********************************************************************************************
01211 
01212 >   FIXED16 View::GetPixelWidth()
01213 
01214     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01215     Created:    02/19/95
01216     Returns:    The pixel width for this view
01217     Purpose:    Get the width of a pixel in this view.
01218 
01219 ********************************************************************************************/
01220 
01221 FIXED16 View::GetPixelWidth()
01222 {
01223     return PixelWidth;
01224 }
01225 
01226 
01227 /********************************************************************************************
01228 
01229 >   FIXED16 View::GetPixelHeight()
01230 
01231     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01232     Created:    02/19/95
01233     Returns:    The pixel height for this view
01234     Purpose:    Get the height of a pixel in this view.
01235 
01236 ********************************************************************************************/
01237 
01238 FIXED16 View::GetPixelHeight()
01239 {
01240     return PixelHeight;
01241 }
01242 
01243 /********************************************************************************************
01244 
01245 >   void View::GetPixelSize(FIXED16 *pPixelWidth, FIXED16 *pPixelHeight)
01246 
01247     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01248     Created:    02/10/95
01249     Outputs:    pPixelWidth, pPixelHeight - pixel size.
01250     Purpose:    Get the size of a pixel in this view.
01251 
01252 ********************************************************************************************/
01253 
01254 void View::GetPixelSize(FIXED16 *pPixelWidth, FIXED16 *pPixelHeight)
01255 {
01256     *pPixelWidth = PixelWidth;
01257     *pPixelHeight = PixelHeight;
01258 }
01259 
01260 
01261 /********************************************************************************************
01262 
01263 >   void View::SetPixelSize(FIXED16 NewPixelWidth, FIXED16 NewPixelHeight)
01264 
01265     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01266     Created:    02/10/95
01267     Inputs:     PixelWidth, PixelHeight - new pixel size to use.
01268     Purpose:    Set the size of a pixel in this view.
01269 
01270 ********************************************************************************************/
01271 
01272 void View::SetPixelSize(FIXED16 NewPixelWidth, FIXED16 NewPixelHeight)
01273 {
01274     PixelWidth = NewPixelWidth;
01275     PixelHeight = NewPixelHeight;
01276 }
01277 
01278 
01279 /********************************************************************************************
01280 
01281 >   FIXED16 View::GetScaledPixelWidth()
01282 
01283     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01284     Created:    02/19/95
01285     Returns:    The scaled pixel width for this view
01286     Purpose:    Get the width of a scaled pixel in this view.
01287 
01288 ********************************************************************************************/
01289 
01290 FIXED16 View::GetScaledPixelWidth()
01291 {
01292     return ScaledPixelWidth;
01293 }
01294 
01295 
01296 /********************************************************************************************
01297 
01298 >   FIXED16 View::GetScaledPixelHeight()
01299 
01300     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01301     Created:    02/19/95
01302     Returns:    The scaled pixel height for this view
01303     Purpose:    Get the height of a scaled pixel in this view.
01304 
01305 ********************************************************************************************/
01306 
01307 FIXED16 View::GetScaledPixelHeight()
01308 {
01309     return ScaledPixelHeight;
01310 }
01311 
01312 /********************************************************************************************
01313 
01314 >   void View::GetScaledPixelSize(FIXED16 *pScaledPixelWidth, FIXED16 *pScaledPixelHeight)
01315 
01316     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01317     Created:    02/10/95
01318     Outputs:    pScaledPixelWidth, pScaledPixelHeight - scaled pixel size.
01319     Purpose:    Get the size of a scaled pixel in this view.
01320 
01321 ********************************************************************************************/
01322 
01323 void View::GetScaledPixelSize(FIXED16 *pScaledPixelWidth, FIXED16 *pScaledPixelHeight)
01324 {
01325     *pScaledPixelWidth = ScaledPixelWidth;
01326     *pScaledPixelHeight = ScaledPixelHeight;
01327 }
01328 
01329 
01330 /****************************************************************************
01331 
01332 >   double View::GetConvertToEditableShapesDPI()
01333 
01334     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
01335     Created:    18/08/2005
01336 
01337     Returns:    The resolution to use for convert top editable shapes 
01338                 operations while this view is current
01339     Purpose:    Allows derived view classes to override the reolution
01340 
01341 ****************************************************************************/
01342 
01343 double View::GetConvertToEditableShapesDPI()
01344 {
01345     INT32 iPixPerInch = 0;
01346     if (!GetApplication()->GetConvertToEditableShapesDPI(&iPixPerInch))
01347     {
01348         ERROR3("View::GetConvertToEditableShapesDPI; Couldn't get app's dpi");
01349         iPixPerInch = 96;
01350     }
01351 
01352     return(iPixPerInch);
01353 }
01354 
01355 
01356 /********************************************************************************************
01357 
01358 >   void View::SetScaledPixelSize(FIXED16 NewScaledPixelWidth, FIXED16 NewScaledPixelHeight)
01359 
01360     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01361     Created:    02/10/95
01362     Inputs:     NewScaledPixelWidth, NewScaledPixelHeight - new scaled pixel size to use.
01363     Purpose:    Set the size of a scaled pixel in this view.
01364 
01365 ********************************************************************************************/
01366 
01367 void View::SetScaledPixelSize(FIXED16 NewScaledPixelWidth, FIXED16 NewScaledPixelHeight)
01368 {
01369     ScaledPixelWidth = NewScaledPixelWidth;
01370     ScaledPixelHeight = NewScaledPixelHeight;
01371 }
01372 
01373 
01374 
01375 /********************************************************************************************
01376 
01377 >   ColourContext *View::GetColourContext(ColourModel Model, BOOL ReturnNULLIfNone = FALSE)
01378 
01379     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01380     Created:    22/5/96
01381 
01382     Inputs:     Model - The colour model of the context you want to find
01383                 ReturnNULLIfNone - if FALSE, an appropriate view will be found, by
01384                     searching my parent document and global contexts if necessary.
01385                     if TRUE, then if this view hasn't got it's own special context
01386                     it will immediately return NULL.
01387 
01388     Returns:    NULL, or a pointer to an appropriate context.
01389 
01390     Purpose:    To find an appropriate colour context in the given colour model
01391                 for use when rendering into this view. This allows us to control
01392                 colour separation and correction down to a per-view level.
01393 
01394     Notes:      This only functions for RGB and CMYK contexts at present. If you wish
01395                 to render to a view using an output context of a different type, you
01396                 will need to upgrade tios method.
01397 
01398                 ONLY Use the returned pointer temporarily - If the view is deleted
01399                 or if the ColourPlate options on the view are changed, the context
01400                 will be deleted. You should thus always call this function to get
01401                 the current Context - it's cached, and quick after the first call.
01402 
01403     SeeAlso:    View::GetColourPlate; View::SetColourPlate; ColourContext; ColourManager
01404 
01405 ********************************************************************************************/
01406 
01407 ColourContext *View::GetColourContext(ColourModel Model, BOOL ReturnNULLIfNone)
01408 {
01409     // If our internal flag is set, we will return a default global colour context
01410     // This allows View::RenderOptimalBitmapPhase to create RenderRegions which will
01411     // not colour spearate or correct (as we want to do the correction as a post process
01412     // on the produced bitmap)
01413     if (ForceDefaultColourContexts)
01414         return(ColourManager::GetColourContext(Model, pDoc));
01415 
01416 
01417     // Under normal circumstances, if we have a special ColourPlate, we look in our
01418     // cache for an appropriate context. First, we'll make sure an appropriate context
01419     // is cached (We don't do this if the caller specified ReturnNULLIfNone)
01420     if (!ReturnNULLIfNone && ColourContexts.Context[Model] == NULL && ColPlate != NULL)
01421     {
01422         // It's not cached yet - create a new context of this type
01423         ColourContext *NewCC = NULL;
01424 
01425         switch(Model)
01426         {
01427             case COLOURMODEL_RGBT:
01428                 NewCC = new ColourContextRGBT(this);
01429                 break;
01430 
01431             case COLOURMODEL_CMYK:
01432                 NewCC = new ColourContextCMYK(this);
01433                 break;
01434 
01435             default:
01436                 ERROR3("View::GetColourContext only supports RGB/CMYK contexts at present");
01437                 break;
01438         }
01439 
01440         if (NewCC != NULL)
01441         {
01442             // Copy our ColourPlate
01443             ColourPlate *NewPlate = new ColourPlate(*ColPlate);
01444 
01445             if (NewPlate == NULL)
01446             {
01447                 // Failure - delete the ColourContext and abandon the attempt
01448                 delete NewCC;
01449                 NewCC = NULL;
01450             }
01451             else
01452             {
01453                 // Attach the ColourPlate to the context, add it into our cache of ColourContexts,
01454                 // and add the new context to the context list
01455                 NewCC->SetColourPlate(NewPlate);
01456 
01457                 ColourContextList *cclist = ColourContextList::GetList();
01458                 ERROR3IF(cclist == NULL, "No ColourContextList? What's up?");
01459 
01460                 ColourContexts.Context[Model] = NewCC;
01461                 cclist->AddContext(&(ColourContexts.Context[Model]));
01462             }
01463         }
01464     }
01465 
01466     // See if we've got a cached context we can return
01467     ColourContext *cc = ColourContexts.Context[Model];
01468 
01469     // If we own our own colour context, then use it. Otherwise, find a suitable
01470     // context from our parent document; if that has none, then use a global default.
01471     // (We don't do this if the caller specified ReturnNULLIfNone)
01472     if (cc == NULL && !ReturnNULLIfNone)
01473         cc = ColourManager::GetColourContext(Model, pDoc);
01474 
01475     return(cc);
01476 }
01477 
01478 
01479 
01480 /********************************************************************************************
01481 
01482 >   ColourPlate *View::GetColourPlate(void)
01483 
01484     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01485     Created:    13/6/96
01486 
01487     Returns:    NULL, or a pointer to the current ouptut ColourPlate
01488 
01489     Purpose:    To find out what colour separation options are currently in use by this view
01490 
01491     SeeAlso:    View::SetColourPlate; View::GetColourContext
01492 
01493 ********************************************************************************************/
01494 
01495 ColourPlate *View::GetColourPlate(void)
01496 {
01497     return(ColPlate);
01498 }
01499 
01500 
01501 
01502 /********************************************************************************************
01503 
01504 >   void View::SetColourPlate(ColourPlate *NewPlate, BOOL bSendContextChanged = TRUE)
01505 
01506     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01507     Created:    13/6/96
01508 
01509     Inputs:     NewPlate - NULL (to remove any attached plate), or a pointer to a new
01510                 ColourPlate to use - (the existing COlourPLate attached to this view
01511                 will be deleted, and replaced with a copy of this new ColourPlate)
01512 
01513     Purpose:    Sets a new colour plate (colour separation description for this view.
01514                 Any future requests for colour contexts for this view (e.g. the next
01515                 time it is redrawn, etc) will return a ColourContext using this new
01516                 ColourPlate.
01517 
01518     Notes:      A copy is made of the ColourPlate object - you still own the one you
01519                 lent us.
01520 
01521     SeeAlso:    View::GetColourPlate; View::GetColourContext
01522 
01523 ********************************************************************************************/
01524 
01525 void View::SetColourPlate(ColourPlate *NewPlate, BOOL bSendContextChanged)
01526 {
01527     if (ColPlate != NULL)
01528     {
01529         delete ColPlate;
01530         ColPlate = NULL;
01531     }
01532 
01533     if (NewPlate != NULL)
01534         ColPlate = new ColourPlate(*NewPlate);
01535 
01536     // Wipe any cached colour contexts for the old ColourPlate
01537     ColourContextList *cclist = ColourContextList::GetList();
01538     ERROR3IF(cclist == NULL, "No ColourContextList? What's up?");
01539 
01540     for (INT32 i = 0; i < (INT32) MAX_COLOURMODELS; i++)
01541     {
01542         if (ColourContexts.Context[i] != NULL)
01543         {
01544             if (ShouldDeleteContext[i])
01545                 cclist->RemoveContext(&(ColourContexts.Context[i]));
01546             else
01547             {
01548                 // We didn't cache this context, so we shouldn't delete it
01549                 // Instead, we should just change it over to use the new ColourPlate
01550                 ColourPlate *NewPlate = NULL;
01551                 if (ColPlate != NULL)
01552                     NewPlate = new ColourPlate(*ColPlate);
01553 
01554                 // Attach the ColourPlate to the context - even if it is NULL this is safe
01555                 ColourContexts.Context[i]->SetColourPlate(NewPlate);
01556             }
01557         }
01558     }
01559 
01560     // And if necessary, inform everybody that the colour separation options for 
01561     // the selected view have been changed
01562     if (bSendContextChanged && this == DocView::GetSelected())
01563         ColourManager::SelViewContextHasChanged();
01564 }
01565 
01566 
01567 
01568 /********************************************************************************************
01569 
01570 >   void View::SetColourContext(ColourModel Model, ColourContext *NewContext = NULL)
01571 
01572     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01573     Created:    18/6/96
01574 
01575     Inputs:     Model      - The colour model of this context
01576                 NewContext - NULL to delete any existing context attached to this view,
01577                              or a pointer to the new context to use. Any old attached
01578                              context will be deleted. The new context is now "owned" by the
01579                              view, which will delete it when it is finished with it.
01580 
01581     Purpose:    Sets a new colour context for this view. 
01582 
01583                 When we render to a view, an appropriate CMYK or RGB context is used
01584                 for output, fetched by calling View::GetColourContext. Normally, the view
01585                 will get a global default context, attach a copy of the View's ColourPlate
01586                 (see View::SetColourPlate) to it, and return that. However, if you set
01587                 a special context, this will be used instead of a global default.
01588                 
01589                 This is only currently used by the printing system to use a CMYK context
01590                 which knows how to colour-correct separated output for the output printer
01591                 device.
01592 
01593     Notes:      Once given to a view, the ColourContext is "Owned" by the view, and will
01594                 be deleted when the view is deleted, or when this function is called to
01595                 set a different context active. Call this function with a NULL pointer
01596                 to clear any existing ColourContext attached to the view.
01597 
01598                 The View will attach the context to the global ColourContext list for you
01599 
01600                 The View will always attach its own ColourPlate to the ColourContext
01601                 that you pass in, overriding any ColourPlate you may have given it.
01602 
01603                 (Implementation) The View keeps a special array of BOOLs next to its
01604                 Array of contexts, which tell it whether the context in the cache
01605                 is one created on demand by the view (which it can delete when the
01606                 ColourPlate is changed) or one passed in by the caller (which should
01607                 only be deleted on destruction or Context change)
01608 
01609     SeeAlso:    View::SetColourPlate; View::GetColourPlate; View::GetColourContext
01610 
01611 ********************************************************************************************/
01612 
01613 void View::SetColourContext(ColourModel Model, ColourContext *NewContext)
01614 {
01615     ColourContextList *cclist = ColourContextList::GetList();
01616     ERROR3IF(cclist == NULL, "No ColourContextList? What's up?");
01617 
01618     if (ColourContexts.Context[Model] != NULL)
01619         cclist->RemoveContext(&(ColourContexts.Context[Model]));
01620 
01621     ColourContexts.Context[Model] = NewContext;
01622     ShouldDeleteContext[Model] = TRUE;      // Reset the auto-delete flag by default
01623 
01624     if (NewContext != NULL)
01625     {
01626         ERROR3IF(Model != NewContext->GetColourModel(),
01627                     "View::SetColourContext - Model must match colour context's model!");
01628 
01629         ColourPlate *NewPlate = NULL;
01630         if (ColPlate != NULL)
01631             NewPlate = new ColourPlate(*ColPlate);
01632 
01633         // Attach our ColourPlate to the context, add it into our cache of ColourContexts,
01634         // and add the new context to the context list
01635         NewContext->SetColourPlate(NewPlate);
01636 
01637         cclist->AddContext(&(ColourContexts.Context[Model]));
01638 
01639         if (ColourContexts.Context[Model] != NULL)
01640         {
01641             // Instruct ourselves not to auto-delete this context from the cache
01642             ShouldDeleteContext[Model] = FALSE;
01643         }
01644     }
01645 }
01646 
01647 /********************************************************************************************
01648 
01649 >   ProgressDisplay::ProgressDisplay()
01650 
01651     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01652     Created:    05/25/95
01653     Purpose:    Initialise the progress display object.  Defaults to no progress display.
01654 
01655 ********************************************************************************************/
01656 
01657 ProgressDisplay::ProgressDisplay()
01658 {
01659     //  WEBSTER-ranbirr-13/11/96
01660 #ifndef WEBSTER
01661 #ifndef STANDALONE
01662     pPrintInfo = CCPrintInfo::GetCurrent();
01663 #else
01664     pPrintInfo = NULL;
01665 #endif
01666 #endif //webster
01667     DoProgressDisplay = FALSE;
01668     IsPrinting = FALSE;
01669     NumNodesRendered = 0;
01670     LastProgressUpdate = 0;
01671     ProgressInterval = 1;
01672     TotalNodes = 0;
01673 
01674     // Currently we use a scale factor of 256 so that we get decent resolution even
01675     // when exporting only a few nodes that have lots of transparency.
01676     // We use 256 (a power of 2) so that muls and divs are fast.
01677     ProgressScaleFactor = 256;
01678 }
01679 
01680 
01681 /********************************************************************************************
01682 
01683 >   void ProgressDisplay::SetUp(RenderRegion *pRender, ScanningRenderRegion *pScanner)
01684 
01685     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01686     Created:    05/25/95
01687     Inputs:     pRender - the render region we are going to render into.
01688                 Scanner - the scanning render region that contains information about
01689                           what shapes we are going to render into this region.
01690     Purpose:    Sets up the progress display object based on the render regions passed in.
01691     SeeAlso:    ScanningRenderRegion
01692 
01693 ********************************************************************************************/
01694 
01695 void ProgressDisplay::SetUp(RenderRegion *pRender, ScanningRenderRegion *pScanner)
01696 {
01697 #ifndef STANDALONE
01698     // Work out if we need a progress display
01699     IsPrinting = pRender->IsPrinting();
01700     if (!IsPrinting && !IS_A(pRender, CamelotEPSRenderRegion))
01701         // No - stop here
01702         return;
01703 
01704     // We need a progress display
01705     DoProgressDisplay = TRUE;
01706 
01707     // Find out how many nodes the stages need to render...
01708     BOOL FoundLastComplex = FALSE;
01709     FirstStageCount = 0;
01710     SecondStageCount = 0;
01711     ThirdStageCount = 0;
01712 
01713     DocRect ClipRect = pRender->GetClipRect();
01714     Spread *pSpread = pRender->GetRenderSpread();
01715 
01716     // ----------------------------------------------------------------
01717     // NOTE! This is the last use of FindFirstForClippedInkRender!
01718     // It should be replaced by RenderTree and a Callback object
01719     Node *pNode = pSpread->FindFirstForClippedInkRender(&ClipRect, pRender);
01720     // ----------------------------------------------------------------
01721 
01722     Node *pLastComplexNode = pScanner->GetLastComplexObject();
01723 
01724     // Work out whether to count just selected objects, or all of them.
01725     BOOL CountAllObjects = TRUE;
01726 //  WEBSTER-ranbirr-13/11/96
01727 #ifndef WEBSTER
01728     if (IsPrinting && pPrintInfo != NULL)
01729     {
01730         PrintControl *pPrCtrl = pPrintInfo->GetPrintControl();
01731         ERROR3IF(pPrCtrl == NULL, "Unable to find PrintControl object from PrintInfo.");
01732         CountAllObjects = (pPrCtrl->GetObjPrintRange() == PRINTRANGEOBJ_ALL);
01733     }
01734 #endif //webster
01735     if (CountAllObjects)
01736     {
01737         // Count *all* objects
01738         while (pNode != NULL)
01739         {
01740             // Count the node that we have
01741             if (FoundLastComplex)
01742                 ThirdStageCount++;
01743             else
01744                 FirstStageCount++;
01745 
01746             // Have we found the last complex node yet?
01747             // (If so, then we start incrementing ThirdStageCount instead of 
01748             // FirstStageCount).
01749             if (pNode == pLastComplexNode)
01750                 FoundLastComplex = TRUE;
01751 
01752             // Find another one to count
01753             pNode = pNode->FindNextForClippedInkRender(&ClipRect, pRender);
01754         }
01755     }
01756     else
01757     {
01758         // Count only *selected objects*
01759         // (We do this by not rendering any bounded object that is not selected).
01760         //
01761         // This is in a different loop so that we don't impact performance of
01762         // normal printing.
01763         while (pNode != NULL)
01764         {
01765             // Count the node that we have, unless it is bounded but not selected.
01766             if (View::IsPrintableNodeSelected(pNode))
01767             {
01768                 if (FoundLastComplex)
01769                     ThirdStageCount++;
01770                 else
01771                     FirstStageCount++;
01772             }
01773 
01774             // Have we found the last complex node yet?
01775             // (If so, then we start incrementing ThirdStageCount instead of 
01776             // FirstStageCount).
01777             if (pNode == pLastComplexNode)
01778                 FoundLastComplex = TRUE;
01779 
01780             // Find another one to render
01781             pNode = pNode->FindNextForClippedInkRender(&ClipRect, pRender);
01782         }
01783     }
01784 
01785 
01786     // Ok - now we need to set the slider range for the print progress dialog.
01787     // We do this on a number of nodes basis - the first and second stages render the
01788     // same number of nodes, so we count the 'first' count twice, and then add the
01789     // 'third' count.
01790     if (pScanner->GetNumComplex() != 0)
01791     {
01792         SecondStageCount = FirstStageCount;
01793 
01794         // Check to see if we do not do the first stage, - if not then we do the whole
01795         // thing as a bitmap without bothering with the mask (becuase it's too much for
01796         // most printer drivers to cope with).
01797         if ((PrintMonitor::PrintMaskType==PrintMonitor::MASK_SIMPLE) &&
01798             (CCDC::GetType(pRender->GetRenderDC(), TRUE) != RENDERTYPE_PRINTER_PS))
01799         {
01800             FirstStageCount = 0;
01801         }
01802     }
01803 
01804     INT32 Range = FirstStageCount + SecondStageCount + ThirdStageCount;
01805 //  WEBSTER-ranbirr-13/11/96
01806 #ifndef WEBSTER
01807     if (IsPrinting)
01808     {
01809 //      if (pPrintInfo == NULL)
01810 //      {
01811 //          ERROR2RAW("No PrintInfo object found!");
01812 //          InformError();
01813 //          return;
01814 //      }
01815 
01816         if (pPrintInfo != NULL)
01817         {
01818             pPrintInfo->SetSliderSubRangeMax(Range * ProgressScaleFactor);
01819             pPrintInfo->SetSliderSubRangePos(0);
01820         }
01821     }
01822     else
01823 #endif //wesbter
01824     {
01825         // Start progress display (with no initial delay) for Camelot EPS export
01826         String_64 ExportMsg(_R(IDT_EXPORTMSG_CAMEPS));
01827         BeginSlowJob(Range * ProgressScaleFactor, FALSE, &ExportMsg);
01828     }
01829 
01830     // Provide a progress update for every 1%
01831     ProgressInterval = (Range * ProgressScaleFactor) / 100;
01832 #else
01833     // Do nothing as not required on standalone viewer
01834     return;
01835 #endif
01836 
01837 }
01838 
01839 
01840 /********************************************************************************************
01841 
01842 >   BOOL ProgressDisplay::IncProgress(INT32 NumNodes = 1)
01843 
01844     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01845     Created:    05/25/95
01846     Inputs:     NumNodes - the number of nodes that have just been rendered.
01847     Returns:    TRUE if updated ok;
01848                 FALSE if user requested that operation is aborted, e.g. presing Escape.
01849     Purpose:    Updates the rendered node count by the number specified.  If the progress
01850                 display needs updating, then it is updated.
01851     SeeAlso:    ProgressDisplay
01852 
01853 ********************************************************************************************/
01854 
01855 BOOL ProgressDisplay::IncProgress(INT32 NumNodes)
01856 {
01857 #ifndef STANDALONE
01858 
01859     NumNodesRendered++;
01860 
01861     if (!DoProgressDisplay)
01862         // No progress display needed.
01863         return TRUE;
01864 //  WEBSTER-ranbirr-13/11/96
01865 #ifndef WEBSTER
01866     if (IsPrinting && (pPrintInfo != NULL) && (pPrintInfo->m_bContinuePrinting == FALSE))
01867         // User has cancelled job
01868         return FALSE;
01869 #endif //webster
01870     if ((NumNodesRendered * ProgressScaleFactor) > (LastProgressUpdate + ProgressInterval))
01871     {
01872         // Time to update the progress display.
01873         LastProgressUpdate = NumNodesRendered * ProgressScaleFactor;
01874 //  WEBSTER-ranbirr-13/11/96
01875 #ifndef WEBSTER
01876         if (IsPrinting && pPrintInfo != NULL)
01877         {
01878             // Update slider
01879             pPrintInfo->SetSliderSubRangePos(LastProgressUpdate);
01880 
01881             // Does user want to suspend printing?
01882             if (pPrintInfo->Abort())
01883                 return FALSE;
01884         }
01885         else
01886 #endif //webster
01887         return ContinueSlowJob(LastProgressUpdate);
01888     }
01889 
01890 #endif
01891 
01892     // All ok
01893     return TRUE;
01894 }
01895 
01896 
01897 /********************************************************************************************
01898 
01899 >   BOOL ProgressDisplay::FirstStageDone()
01900 
01901     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01902     Created:    05/25/95
01903     Returns:    TRUE if updated ok;
01904                 FALSE if user requested that operation is aborted, e.g. presing Escape.
01905     Purpose:    Should be called when the first stage of 3-pass rendering is complete.
01906     SeeAlso:    ProgressDisplay::SecondStageDone
01907 
01908 ********************************************************************************************/
01909 
01910 BOOL ProgressDisplay::FirstStageDone()
01911 {
01912 #ifndef STANDALONE
01913 
01914     NumNodesRendered = FirstStageCount;
01915 
01916     if (!DoProgressDisplay)
01917         // No progress display needed.
01918         return TRUE;
01919 //  WEBSTER-ranbirr-13/11/96
01920 #ifndef WEBSTER
01921     if (IsPrinting && pPrintInfo != NULL)
01922         pPrintInfo->SetSliderSubRangePos(NumNodesRendered * ProgressScaleFactor);
01923     else
01924 #endif //webster
01925         return ContinueSlowJob(NumNodesRendered * ProgressScaleFactor);
01926 
01927 #endif
01928 
01929     // All ok
01930     return TRUE;
01931 }
01932 
01933 
01934 /********************************************************************************************
01935 
01936 >   BOOL ProgressDisplay::SecondStageDone()
01937 
01938     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01939     Created:    05/25/95
01940     Returns:    TRUE if updated ok;
01941                 FALSE if user requested that operation is aborted, e.g. presing Escape.
01942     Purpose:    Should be called when the second stage of 3-pass rendering is complete.
01943     SeeAlso:    ProgressDisplay::FirstStageDone
01944 
01945 ********************************************************************************************/
01946 
01947 BOOL ProgressDisplay::SecondStageDone()
01948 {
01949 #ifndef STANDALONE
01950 
01951     NumNodesRendered = FirstStageCount + SecondStageCount;
01952 
01953     if (!DoProgressDisplay)
01954         // No progress display needed.
01955         return TRUE;
01956 //  WEBSTER-ranbirr-13/11/96
01957 #ifndef WEBSTER
01958     if (IsPrinting && pPrintInfo != NULL)
01959     {
01960         // Update slider
01961         pPrintInfo->SetSliderSubRangePos(NumNodesRendered * ProgressScaleFactor);
01962 
01963         // Does user want to suspend printing?
01964         if (pPrintInfo->Abort())
01965             return FALSE;
01966     }
01967     else
01968 #endif //webster
01969         return ContinueSlowJob(NumNodesRendered * ProgressScaleFactor);
01970 
01971 #endif
01972 
01973     // All ok
01974     return TRUE;
01975 }
01976 
01977 /********************************************************************************************
01978 
01979 >   void ProgressDisplay::AllStagesDone()
01980 
01981     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01982     Created:    05/25/95
01983     Purpose:    Should be called when the 3-pass rendering has been finished.  This
01984                 causes the progress bar to be de-initialised when exporting Camelot EPS.
01985     SeeAlso:    ProgressDisplay
01986 
01987 ********************************************************************************************/
01988 
01989 void ProgressDisplay::AllStagesDone()
01990 {
01991 #ifndef STANDALONE
01992     // If we are exporting EPS, end the progress indicator as we're all done.
01993     if (DoProgressDisplay && !IsPrinting)
01994         EndSlowJob();
01995 #endif
01996 }
01997 
01998 
01999 /********************************************************************************************
02000 
02001 >   void ProgressDisplay::StartBitmapPhase(INT32 NumBands)
02002 
02003     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
02004     Created:    05/25/95
02005     Inputs:     NumBands - the number of bands required to render the bitmap phase.
02006     Purpose:    Gets ready to render the banded bitmap phase of the rendering.
02007                 Works out how much each band should update the progress position by.
02008     SeeAlso:    ProgressDisplay::RenderedBitmapPhaseBand
02009 
02010 ********************************************************************************************/
02011 
02012 void ProgressDisplay::StartBitmapPhase(INT32 NumBands)
02013 {
02014     if (!DoProgressDisplay)
02015         return;
02016 
02017     // Work out how much of the progress range we can use for each band.
02018     BandSize = (SecondStageCount * ProgressScaleFactor) / NumBands;
02019     BandOffset = 0;
02020 }
02021 
02022 /********************************************************************************************
02023 
02024 >   void ProgressDisplay::StartBitmapPhaseBand(INT32 TotalNumScanlines)
02025 
02026     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
02027     Created:    05/25/95
02028     Inputs:     TotalNumScanLines - the height of this ban in pixels.
02029     Purpose:    Inform the progress display that a band is about to start being rendered,
02030                 and how many scanlines high it will be.
02031     SeeAlso:    ProgressDisplay::BitmapPhaseBandRenderedTo
02032 
02033 ********************************************************************************************/
02034 
02035 void ProgressDisplay::StartBitmapPhaseBand(INT32 TotalNumScanlines)
02036 {
02037     // Remember how high this band is.
02038     BandHeight = TotalNumScanlines;
02039 
02040     // Work out how much to move the progress display by for each scanline.
02041     BandIncrement = BandSize / BandHeight;
02042 }
02043 
02044 
02045 /********************************************************************************************
02046 
02047 >   BOOL ProgressDisplay::BitmapPhaseBandRenderedTo(INT32 ScanlinesRendered)
02048 
02049     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
02050     Created:    05/25/95
02051     Inputs:     ScanlinesRendered - the numbr of scanlines rendered so far in this band.
02052     Returns:    TRUE if updated ok;
02053                 FALSE if user requested that operation is aborted, e.g. presing Escape.
02054     Purpose:    Update the progress to reflect how many scanlines have been rendered in
02055                 this band of the bitmap rendering phase.
02056     SeeAlso:    ProgressDisplay::StartBitmapPhaseBand
02057 
02058 ********************************************************************************************/
02059 
02060 BOOL ProgressDisplay::BitmapPhaseBandRenderedTo(INT32 ScanlinesRendered)
02061 {
02062 #ifndef STANDALONE
02063 
02064     if (!DoProgressDisplay)
02065         // No progress display needed.
02066         return TRUE;
02067 
02068     // Work out how far into this band we have got.
02069     BandOffset = ScanlinesRendered * BandIncrement;
02070     if (BandOffset > BandSize)
02071         BandOffset = BandSize;
02072     INT32 ProgressPos = (NumNodesRendered * ProgressScaleFactor) + BandOffset;
02073 
02074 //  WEBSTER-ranbirr-13/11/96
02075 #ifndef WEBSTER
02076     // Update progress indicators
02077     if (IsPrinting && pPrintInfo != NULL)
02078     {
02079         // Update slider
02080         pPrintInfo->SetSliderSubRangePos(ProgressPos);
02081 
02082         // Does user want to suspend printing?
02083         if (pPrintInfo->Abort())
02084             return FALSE;
02085     }
02086     else
02087 #endif //webster
02088         return ContinueSlowJob(ProgressPos);
02089 
02090 #endif
02091 
02092     // All ok
02093     return TRUE;
02094 }
02095 
02096 
02097 /********************************************************************************************
02098 
02099 >   BOOL ProgressDisplay::EndBitmapPhaseBand()
02100 
02101     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
02102     Created:    05/25/95
02103     Returns:    TRUE if updated ok;
02104                 FALSE if user requested that operation is aborted, e.g. presing Escape.
02105     Purpose:    Another band of the bitmap rendering phase has been finished, so update
02106                 the progress display.
02107 
02108 ********************************************************************************************/
02109 
02110 BOOL ProgressDisplay::EndBitmapPhaseBand()
02111 {
02112 #ifndef STANDALONE
02113 
02114     if (!DoProgressDisplay)
02115         return TRUE;
02116 
02117     // Move on, but limit to range! (in case of cock-ups)
02118     NumNodesRendered += (BandSize / ProgressScaleFactor);
02119     if (NumNodesRendered > (FirstStageCount + SecondStageCount))
02120         NumNodesRendered = (FirstStageCount + SecondStageCount);
02121 //  WEBSTER-ranbirr-13/11/96
02122 #ifndef WEBSTER
02123     if (IsPrinting && pPrintInfo != NULL)
02124     {
02125         // Update slider
02126         pPrintInfo->SetSliderSubRangePos(NumNodesRendered * ProgressScaleFactor);
02127 
02128         // Does user want to suspend printing?
02129         if (pPrintInfo->Abort())
02130             return FALSE;
02131     }
02132     else
02133 #endif //webster
02134         return ContinueSlowJob(NumNodesRendered * ProgressScaleFactor);
02135 #endif
02136     // All ok
02137     return TRUE;
02138 }
02139 
02140 
02141 /********************************************************************************************
02142 
02143 >   SlowJobResult View::RenderSimpleNodes(Node *pNode, RenderRegion *pRender,
02144                              ProgressDisplay& Progress, Node *pLastComplexNode = NULL)
02145 
02146     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
02147     Created:    05/25/95
02148     Inputs:     pNode - the node to start rendering at.
02149                 pRender - the render region to render the nodes into.
02150                 Progress - usual progress info object.
02151                 pLastComplexNode - optional: if not NULL, then stop rendering when this
02152                                              node is reached, otherwise render to completion.
02153     Returns:    SLOWJOB_SUCCESS if rendered ok;
02154                 SLOWJOB_FAILURE if an error occured;
02155                 SLOWJOB_USERABORT if the user intervened - e.g. pressed Escape.
02156     Purpose:    Function to render nodes 'normally' during 3-pass rendering.  This copes
02157                 with stopping at the specified last complex node, and with only printing
02158                 selected objects if the user has requested it.
02159     SeeAlso:    ProgressInfo; View::RenderSimpleView
02160 
02161 ********************************************************************************************/
02162 
02163 SlowJobResult View::RenderSimpleNodes(Node *pNode, RenderRegion *pRender,
02164                              ProgressDisplay& Progress, Node *pLastComplexNode)
02165 {
02166 #ifndef STANDALONE
02167     DocRect ClipRect = pRender->GetClipRect();
02168 
02169     // Work out whether we need to render all objects, or just the selected ones.
02170     BOOL RenderAllObjects = TRUE;
02171 //  WEBSTER-ranbirr-13/11/96
02172 #ifndef WEBSTER
02173     if (pRender->IsPrinting())
02174     {
02175         CCPrintInfo *pPrintInfo = CCPrintInfo::GetCurrent();
02176 //      ERROR2IF(pPrintInfo == NULL, SLOWJOB_FAILURE, "No print info while printing!");
02177         if (pPrintInfo != NULL)
02178         {
02179             PrintControl *pPrCtrl = pPrintInfo->GetPrintControl();
02180             RenderAllObjects = (pPrCtrl->GetObjPrintRange() == PRINTRANGEOBJ_ALL);
02181         }
02182     }
02183 #endif //webster
02184     // Render nodes into specified render region
02185     while ((pNode!=NULL) && (pNode != pLastComplexNode))
02186     {
02187         if (pNode->IsRenderable() && (RenderAllObjects || IsPrintableNodeSelected(pNode)))
02188         {
02189             // Render the node that we have
02190             pNode->Render(pRender);
02191 
02192             // If progress display is needed, update it if it's time.
02193             if (!Progress.IncProgress())
02194                 return SLOWJOB_USERABORT;
02195         }
02196 
02197         // Find another one to render
02198         pNode = pNode->FindNextForClippedInkRender(&ClipRect, pRender);
02199     }
02200 
02201     // All ok
02202     return SLOWJOB_SUCCESS;
02203 #else
02204     return SLOWJOB_FAILURE;
02205 #endif
02206 }
02207 
02208 
02209 /********************************************************************************************
02210 
02211 >   BOOL View::IsPrintableNodeSelected(Node *pNode)
02212 
02213     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
02214     Created:    05/28/95
02215     Inputs:     pNode - the node to check.
02216     Returns:    TRUE if the node should be printed;
02217                 FALSE if not.
02218     Purpose:    Determine whether a given node should be rendered when we are printing
02219                 with "selected objects only" enabled.  It checks to see if the node is
02220                 bounded - if it isn't, then it's an attribute or similar and so is always
02221                 rendered.  If it is bounded then return TRUE if it is selected or if it is
02222                 the child of a selected object.  Otherwise we return FALSE to indicate that
02223                 it should not be printed.
02224     SeeAlso:    View::RenderSimpleNodes
02225 
02226 ********************************************************************************************/
02227 
02228 BOOL View::IsPrintableNodeSelected(Node *pNode)
02229 {
02230     if (pNode->IsBounded())
02231     {
02232         // We must check the selected status of this node.
02233         // Even if this node is not selected, its parent might be, so we
02234         // scan upwards until we find a layer, or a selected node.
02235         Node *pTestNode = pNode;
02236         while ((pTestNode != NULL) && 
02237                (!pTestNode->IsSelected()) && 
02238                (!pTestNode->IsLayer()))
02239         {
02240             pTestNode = pTestNode->FindParent();
02241         }
02242 
02243         // If we failed to find a parent at some point then it can't possibly be selected
02244         if (pTestNode == NULL)
02245             return(FALSE);
02246 
02247         // If it is selected then we'd better print this node
02248         if (pTestNode->IsSelected())
02249             return(TRUE);
02250 
02251         // If the original node is a shadow then we should test the right sibling
02252         // and print this node if that is selected
02253         if (pNode->IsAShadow())
02254         {
02255             Node* pRightSibling = pNode->FindNext();
02256             if (pRightSibling && pRightSibling->IsSelected())
02257                 return(TRUE);
02258         }
02259 
02260         // Fall back to not printing this node
02261         return(FALSE);
02262 
02263         // Ok, what did we find?
02264 //      return ((pTestNode != NULL) && pTestNode->IsSelected());
02265     }
02266     else
02267     {
02268         // It is a non-bounded node such as an attribute so we render it always.
02269         return TRUE;
02270     }
02271 }
02272 
02273 
02274 
02275 
02276 // This should be moved somewhere sensible when dependencies stop being an issue
02277 
02278 /********************************************************************************************
02279 
02280 >   class ScannerRenderCallback : public RenderCallback
02281 
02282     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
02283     Created:    09/12/2004
02284     Purpose:    Handling callbacks from RenderTree
02285     Notes:      RenderTree function calls the main function in this class when it's about
02286                 to render any Node.
02287 
02288 ********************************************************************************************/
02289 
02290 class ScannerRenderCallback : public RenderCallback
02291 {
02292 public:
02293     ScannerRenderCallback(View* pView, BOOL bRenderAll, ScanningRenderRegion* pScanRR)
02294     {
02295         m_pView = pView;
02296         m_bRenderAll = bRenderAll;
02297         m_pScanRR = pScanRR;
02298     }
02299 
02300     virtual BOOL BeforeNode(RenderRegion* pRegion, Node* pNode)
02301     {
02302         BOOL bRender = m_bRenderAll || m_pView->IsPrintableNodeSelected(pNode);
02303 //      TRACE( _T("SRC# BeforeNode    0x%08x - %s   returning %s\n", pNode, pNode->GetRuntimeClass()->GetClassName(), bRender ? "true" : "false"));
02304 //      TRACE( _T("SRC# BN 0x%08x %s\n", pNode, bRender ? "true" : "false"));
02305         m_pScanRR->SetRenderState(pNode);
02306         return(bRender);
02307     }
02308 
02309     virtual BOOL BeforeSubtree(RenderRegion* pRegion, Node* pNode, Node** ppNextNode, 
02310                                     BOOL bClip, SubtreeRenderState* pState)
02311     {
02312 //      TRACE( _T("SRC# BeforeSubtree 0x%08x - %s\n"), pNode, pNode->GetRuntimeClass()->GetClassName());
02313 //      TRACE( _T("SRC# BS 0x%08x\n"), pNode);
02314         m_pScanRR->SetRenderState(pNode);
02315         return(FALSE);
02316     }
02317 
02318 //  virtual BOOL AfterSubtree(RenderRegion* pRegion, Node* pNode);
02319 
02320 private:
02321     View* m_pView;
02322     BOOL m_bRenderAll;
02323     ScanningRenderRegion* m_pScanRR;
02324 };
02325 
02326 
02327 class OptimalPrintRenderCallback : public RenderCallback
02328 {
02329 public:
02330     OptimalPrintRenderCallback(View* pView, Spread* pSpread, BOOL bRenderAll, ScanningRenderRegion* pScanRR,
02331                                 BOOL bPrintPaper, INT32* pNodesSoFar, ProgressDisplay* pProgress, BOOL bCount)
02332     {
02333         m_pView = pView;
02334         m_bRenderAll = bRenderAll;
02335         m_pScanRR = pScanRR;
02336         m_bPrintPaper = bPrintPaper;
02337         m_pNextAction = m_pScanRR->FindFirstFromList();
02338         m_bNextComplex = m_pScanRR->IsThisNodeComplex();
02339         m_NextBoundsRect = m_pScanRR->GetSpanBounds();
02340         m_bDoingComplex = FALSE;
02341         m_pSpread = pSpread;
02342         m_pNodesSoFar = pNodesSoFar;
02343         m_pProgress = pProgress;
02344         m_bCount = bCount;
02345         m_ComplexCount = 0;
02346     }
02347 
02348     virtual BOOL BeforeNode(RenderRegion* pRegion, Node* pNode)
02349     {
02350         BOOL bRender = (!m_bDoingComplex || (pNode->IsAnAttribute() || pNode->IsANodeClipView())) &&
02351                         (m_bRenderAll || m_pView->IsPrintableNodeSelected(pNode));
02352 //      TRACE( _T("OPRC# BeforeNode    0x%08x - %s  returning %s\n", pNode, pNode->GetRuntimeClass()->GetClassName(), bRender ? "true" : "false"));
02353 
02354         if (!m_bCount && m_bDoingComplex)
02355             m_ComplexCount++;
02356         else if (m_pNodesSoFar)
02357             (*m_pNodesSoFar)++;
02358 
02359         if (m_bCount)
02360             return(FALSE);
02361 
02362         if (m_pProgress)
02363         {
02364             if (!m_pProgress->SetNodesRendered(*m_pNodesSoFar))
02365             {
02366                 TRACE( _T("*****************************\n"));
02367                 TRACE( _T("************ User aborted job\n"));
02368                 TRACE( _T("*****************************\n"));
02369             }
02370         }
02371 
02372         return(bRender);
02373     }
02374 
02375     virtual BOOL BeforeSubtree(RenderRegion* pRegion, Node* pNode, Node** ppNextNode, 
02376                                     BOOL bClip, SubtreeRenderState* pState)
02377     {
02378 //      TRACE( _T("OPRC# BeforeSubtree 0x%08x - %s\n"), pNode, pNode->GetRuntimeClass()->GetClassName());
02379 
02380         if (!m_bCount && pNode == m_pNextAction)
02381         {
02382             BOOL bIsComplex = m_bNextComplex;
02383             TRACEUSER("noone", _T("OPRC# BeforeSubtree 0x%08x - %s\n"), pNode, pNode->GetRuntimeClass()->GetClassName());
02384             TRACEUSER("noone", _T("Hit Start of %s span\n"), bIsComplex ? _T("complex") : _T("simple") );
02385             // If we have been doing a complex span then we need to render it now
02386             if (m_bDoingComplex)
02387             {
02388                 TRACEUSER("noone", _T("Try to render the last complex span NumNodes = %d\n"), m_ComplexCount);
02389                 RenderLastComplexSpan(pRegion, pNode);
02390             }
02391             
02392             m_SpanBoundsRect = m_NextBoundsRect;
02393             m_pNextAction = m_pScanRR->FindNextFromList();
02394             m_bNextComplex = m_pScanRR->IsThisNodeComplex();
02395             m_NextBoundsRect = m_pScanRR->GetSpanBounds();
02396             TRACEUSER("noone", _T("NextBounds = (%d, %d) - (%d, %d)\n"), m_NextBoundsRect.lo.x, m_NextBoundsRect.lo.y, 
02397                 m_NextBoundsRect.hi.x, m_NextBoundsRect.hi.y );
02398             TRACEUSER("noone", _T("NextAction is %s 0x%08x - %s\n"), m_bNextComplex ? _T("complex") : _T("simple"), m_pNextAction, 
02399                 m_pNextAction ? m_pNextAction->GetRuntimeClass()->GetClassName() : _T("") );
02400             m_ComplexCount = 0;
02401             m_pComplexStart = bIsComplex ? pNode : NULL;
02402             m_bDoingComplex = bIsComplex;
02403         }
02404         
02405         return(FALSE);
02406     }
02407 
02408 //  virtual BOOL AfterSubtree(RenderRegion* pRegion, Node* pNode);
02409 
02410     BOOL FinishRendering(RenderRegion* pRegion)
02411     {
02412         if (!m_bCount && m_bDoingComplex)
02413         {
02414             RenderLastComplexSpan(pRegion, NULL);
02415         }
02416 
02417         return true; 
02418     }
02419 
02420 protected:
02421     BOOL RenderLastComplexSpan(RenderRegion* pRegion, Node* pNextSpanStart)
02422     {
02423         // Call RenderOptimalBitmapPhase to handle this
02424         SlowJobResult BitmapResult;
02425         DocRect ClipRect = pRegion->GetClipRect();
02426         ClipRect = ClipRect.Intersection(m_SpanBoundsRect);
02427 //      TRACE( _T("ClipRect = (%d, %d) - (%d, %d)\n"), ClipRect.lox, ClipRect.loy, ClipRect.hix, ClipRect.hiy);
02428         if (ClipRect.IsValid() && !ClipRect.IsEmpty())
02429         {
02430             Matrix ViewTrans = pRegion->GetMatrix();
02431 //          TRACE( _T("Rendering from 0x%08x - %s\n", m_pComplexStart, m_pComplexStart?m_pComplexStart->GetRuntimeClass()->m_lpszClassName:""));
02432 //          TRACE( _T("Rendering to   0x%08x - %s\n", pNextSpanStart, pNextSpanStart?pNextSpanStart->GetRuntimeClass()->m_lpszClassName:""));
02433             BitmapResult = m_pView->RenderOptimalBitmapPhase(ClipRect, ViewTrans, m_pSpread, pRegion,
02434                                               m_pComplexStart, pNextSpanStart, m_bRenderAll,
02435                                               m_bPrintPaper, *m_pNodesSoFar, m_pProgress, m_ComplexCount);
02436         }
02437 
02438         return true; 
02439     }
02440 
02441 private:
02442     View* m_pView;
02443     Spread* m_pSpread;
02444     BOOL m_bRenderAll;
02445     ScanningRenderRegion* m_pScanRR;
02446     BOOL m_bPrintPaper;
02447     INT32* m_pNodesSoFar;
02448     ProgressDisplay* m_pProgress;
02449 
02450     Node* m_pNextAction;        // The Node pointer that starts the next run
02451     Node* m_pComplexStart;
02452     BOOL m_bNextComplex;        // TRUE if the next action is for a complex span
02453     BOOL m_bDoingComplex;       // TRUE if currently handling a complex span
02454     BOOL m_bCount;
02455     INT32 m_ComplexCount;
02456     DocRect m_SpanBoundsRect;
02457     DocRect m_NextBoundsRect;
02458 };
02459 
02460 
02461 class OptimalBitmapRenderCallback : public RenderCallback
02462 {
02463 public:
02464     typedef enum
02465     {
02466         RS_BEFORECOMPLEX = 0,
02467         RS_INCOMPLEX,
02468         RS_AFTERCOMPLEX,
02469     } RenderStateType;
02470     
02471     OptimalBitmapRenderCallback(View* pView, BOOL bRenderAll, Node* pFirstComplex, Node* pNextNormal, BOOL bRenderMask,
02472                 double RegionArea, INT32* pNodesSoFar, ProgressDisplay* pProgress, BOOL bCount, double NodeIncrement = 1.0)
02473     {
02474         m_pView = pView;
02475         m_bRenderAll = bRenderAll;
02476         m_pFirstComplex = pFirstComplex;
02477         m_pNextNormal = pNextNormal;
02478         m_bRenderMask = bRenderMask;
02479         m_RenderState = RS_BEFORECOMPLEX;
02480         m_RegionArea = RegionArea;
02481         m_pNodesSoFar = pNodesSoFar;
02482         m_pProgress = pProgress;
02483         m_bCount = bCount;
02484         m_NodeIncrement = NodeIncrement;
02485         m_dNodesSoFar = m_pNodesSoFar ? *pNodesSoFar : 0;
02486     }
02487 
02488     virtual BOOL BeforeNode(RenderRegion* pRegion, Node* pNode)
02489     {
02490         if (m_bCount)
02491         {
02492             if (m_pNodesSoFar)
02493                 (*m_pNodesSoFar)++;
02494 
02495             return(FALSE);
02496         }
02497         else
02498         {
02499             m_dNodesSoFar += m_NodeIncrement;
02500             if (m_pNodesSoFar)
02501                 *m_pNodesSoFar = (INT32)m_dNodesSoFar;
02502             if (m_pProgress)
02503             {
02504                 if (!m_pProgress->SetNodesRendered(*m_pNodesSoFar))
02505                 {
02506                     TRACE( _T("*****************************\n"));
02507                     TRACE( _T("************ User aborted job\n"));
02508                     TRACE( _T("*****************************\n"));
02509                 }
02510             }
02511         }
02512 //      BOOL bRender = (m_bRenderAll || m_pView->IsPrintableNodeSelected(pNode)) && pNode->NeedsToRender(pRegion);
02513         BOOL bRender = (m_bRenderAll || m_pView->IsPrintableNodeSelected(pNode));
02514         if (bRender)
02515         {
02516             if (m_bRenderMask)
02517             {
02518                 switch (m_RenderState)
02519                 {
02520                     case RS_BEFORECOMPLEX:
02521                         // We must skip nodes except for attributes and clipviews
02522                         bRender = FALSE;
02523                         if (pNode->IsAnAttribute() || pNode->IsANodeClipView())
02524                         {
02525                             // Let it render normally
02526                             bRender = TRUE;
02527                         }
02528                         break;
02529 
02530                     case RS_INCOMPLEX:
02531                         // Use the standard case below
02532                         break;
02533                     
02534                     case RS_AFTERCOMPLEX:
02535                         // if it is bounded, then decide if it is worth doing this
02536                         // Don't do this for NodeClipView's or large objects clipped by small ones
02537                         // Will not get clipped when they are rendered causing holes in the complex
02538                         // area that really shouldn't be there
02539                         if (pNode->IsBounded() && !pNode->IsANodeClipView())
02540                         {
02541                             // Find out the bounds
02542                             DocRect BoundsRect = ((NodeRenderableBounded*)pNode)->GetBoundingRect();
02543                             
02544                             // if it is small, then don't draw it
02545                             double BoundsArea = (double)BoundsRect.Width() * (double)BoundsRect.Height();
02546                             if (BoundsArea > 0)
02547                             {
02548                                 // work out the coverage of this node as a percentage of the whole region
02549                                 if (m_RegionArea != 0)
02550                                 {
02551                                     BoundsArea = (BoundsArea * 100) / m_RegionArea;
02552                                     if (BoundsArea < 6.0)
02553                                         bRender = FALSE;
02554                                 }
02555                             }
02556                         }
02557                         break;
02558 
02559                     default:
02560                         TRACE( _T("OBRC# Bad RenderState in BeforeNode\n"));
02561                         break;
02562                 }           
02563             }
02564             else    // m_bRenderMask
02565             {
02566 
02567                 switch (m_RenderState)
02568                 {
02569                     case RS_BEFORECOMPLEX:
02570                     case RS_INCOMPLEX:
02571                         // Use the standard case below
02572                         break;
02573                     
02574                     case RS_AFTERCOMPLEX:
02575                         // Must skip everything until the end
02576                         bRender = FALSE;
02577                         break;
02578 
02579                     default:
02580                         TRACE( _T("OBRC# Bad RenderState in BeforeNode\n"));
02581                         break;
02582                 }           
02583             }
02584         }       
02585 
02586 //      TRACE( _T("OBRC%s# BeforeNode    0x%08x - %s    returning %s\n", m_bRenderMask?"M":"B", pNode, pNode->GetRuntimeClass()->GetClassName(), bRender ? "true" : "false"));
02587         return(bRender);
02588     }
02589 
02590     virtual BOOL BeforeSubtree(RenderRegion* pRegion, Node* pNode, Node** ppNextNode, BOOL bClip, SubtreeRenderState* pState)
02591     {
02592 //      if (!m_bCount)
02593 //      {
02594 //          TRACE( _T("OBRC%s# BeforeSubtree 0x%08x - %s\n", m_bRenderMask?"M":"B"), pNode, pNode->GetRuntimeClass()->GetClassName());
02595 //      }
02596 
02597         switch (m_RenderState)
02598         {
02599             case RS_BEFORECOMPLEX:
02600                 if (pNode == m_pFirstComplex)
02601                 {
02602 //                  TRACE( _T("OBRC# Hit FirstComplex\n"));
02603                     if (m_bRenderMask)
02604                     {
02605                         // We must switch the render region to drawing complex
02606                         PrintingMaskedRenderRegion* pMaskRegion = (PrintingMaskedRenderRegion*)pRegion;
02607                         pMaskRegion->SetMaskDrawingMode(TRUE);
02608                     }
02609                     
02610                     // And change state to be in the complex span
02611                     m_RenderState = RS_INCOMPLEX;
02612                 }
02613                 break;
02614 
02615             case RS_INCOMPLEX:
02616                 if (pNode == m_pNextNormal)
02617                 {
02618 //                  TRACE( _T("OBRC# Hit NextNormal\n"));
02619                     if (m_bRenderMask)
02620                     {
02621                         // We must switch the render region to drawing simple
02622                         PrintingMaskedRenderRegion* pMaskRegion = (PrintingMaskedRenderRegion*)pRegion;
02623                         pMaskRegion->SetMaskDrawingMode(FALSE);
02624                     }
02625                     
02626                     // And change state to be after the complex span
02627                     m_RenderState = RS_AFTERCOMPLEX;
02628 
02629                     if (!m_bRenderMask)
02630                     {
02631                         *pState = SUBTREE_NORENDER;
02632                         return(TRUE);
02633                     }
02634                 }
02635                 break;
02636 
02637             case RS_AFTERCOMPLEX:
02638                 break;
02639 
02640             default:
02641                 TRACE( _T("OBRC# Bad RenderState in BeforeSubtree\n"));
02642                 break;
02643         }
02644         return(FALSE);
02645     }
02646 
02647 //  virtual BOOL AfterSubtree(RenderRegion* pRegion, Node* pNode);
02648 
02649 private:
02650     View* m_pView;
02651     BOOL m_bRenderAll;
02652     Node* m_pFirstComplex;
02653     Node* m_pNextNormal;
02654     BOOL m_bRenderMask;         // TRUE if currently handling a complex span
02655     RenderStateType m_RenderState;
02656     double m_RegionArea;
02657     INT32* m_pNodesSoFar;
02658     ProgressDisplay* m_pProgress;
02659     BOOL m_bCount;
02660     double m_NodeIncrement;
02661     double m_dNodesSoFar;
02662 };
02663 
02664 
02665 
02666 /********************************************************************************************
02667 
02668 >   RenderViewResult View::RenderOptimalView(RenderRegion* pRender, Matrix& ViewTrans,
02669                                              Spread* pSpread, BOOL PrintPaper)
02670 
02671     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
02672     Created:    25/7/95
02673     Inputs:     pRender - The render region to render into
02674                 ViewTrans - the transform matrix to use for the rendering
02675                 pSpread - the spread to render
02676                 PrintPaper - TRUE if the paper should be rendered as well
02677     Returns:    RENDERVIEW_SUCCESS   - view was rendered successfully
02678                 RENDERVIEW_FAILURE   - an error occured while rendering the view.
02679                 RENDERVIEW_NOTNEEDED - the view was not rendered as the usual RenderView
02680                                        call can be used instead.
02681                 RENDERVIEW_USERABORT - the user aborted the rendering operation.
02682                                        (e.g. pressing Escape, or aborting the print job)
02683     Purpose:    This function has been designed along similar lines to the RenderView()
02684                 function found elsewhere in this file. This version of the function is
02685                 slightly different though. This version of the function is able to render
02686                 complex objects, such as transparent objects into normal render regions.
02687                 It does this by first scanning through all the objects that need rendering
02688                 to see if any of them require complex things. If they do, then part of the
02689                 rendering is done into a bitmap and blitted over the rest of the shapes using
02690                 a masked blit. All very complicated really! This is the optimal version of
02691                 this function, that will render individual complex shapes to the device
02692                 instead of building them all up and blitting them in one go. This will
02693                 produce the best quality results as as many objects as possible will be
02694                 rendered to the resolution of the device.
02695     SeeAlso:    DocView::RenderView
02696 
02697 ********************************************************************************************/
02698 
02699 RenderViewResult View::RenderOptimalView(RenderRegion* pRender, Matrix& ViewTrans, Spread* pSpread,
02700                                         BOOL PrintPaper)
02701 {
02702 //  TRACEUSER( "Gerry", _T("View::RenderOptimalView\n"));
02703     ERROR3IF(PrintMonitor::PrintMaskType!=PrintMonitor::MASK_OPTIMAL, "PrintMaskType must be OPTIMAL here\n");
02704 
02705     // Find out what the host render region is capable of
02706     RRCaps Caps;
02707     pRender->GetRenderRegionCaps(&Caps);
02708 
02709     // Whether or not the rendering was successful.
02710     RenderViewResult Result = RENDERVIEW_FAILURE;
02711 
02712     // Find out the Clipping rectangle of the render region to draw into
02713     DocRect ClipRect = pRender->GetClipRect();
02714 
02715     BOOL Printing = pRender->IsPrinting();
02716 
02717     // Create and set up a new Scanning render region
02718     ScanningRenderRegion Scanner(Printing);
02719 
02720     // Attach a device to the scanning render region
02721     // Since this rr does no real rendering, it does not need a Device context
02722     Scanner.AttachDevice(this, (CNativeDC*) NULL, pSpread);
02723 
02724     // Get it ready to render
02725     Scanner.SetMatrix(ViewTrans);
02726     Scanner.SetClipRect(ClipRect);
02727     
02728     // Start the render region and return if it fails
02729     if (Scanner.StartRender())
02730     {           
02731         // and tell the scanning render region about the caps of the host region
02732         Scanner.SetHostRRCaps(Caps);
02733 
02734         // Work out whether we need to render all objects, or just the selected ones.
02735         BOOL RenderAllObjects = TRUE;
02736         CCPrintInfo *pPrintInfo = NULL;
02737         if (Printing)
02738         {
02739             pPrintInfo = CCPrintInfo::GetCurrent();
02740             if (pPrintInfo != NULL)
02741             {
02742                 PrintControl *pPrCtrl = pPrintInfo->GetPrintControl();
02743                 RenderAllObjects = (pPrCtrl->GetObjPrintRange() == PRINTRANGEOBJ_ALL);
02744             }
02745         }
02746 
02747 //      BOOL ReallyPrinting = Printing && (pPrintInfo != NULL);
02748 
02749         // We going to analyse the document
02750         if (pPrintInfo != NULL)
02751             pPrintInfo->SetAnalysing();
02752 
02753         ScannerRenderCallback ScanCallback(this, RenderAllObjects, &Scanner);
02754 
02755         // Call RenderTree to do the rendering
02756         Scanner.RenderTree(pSpread, FALSE, TRUE, &ScanCallback);
02757 
02758         // Thats all the nodes rendered, so stop rendering
02759         Scanner.StopRender();
02760 
02761         // Ok, we now have a Scanning render region that has all the info we need to know in it.
02762 #ifdef _DEBUG
02763         // Dump out the node span info
02764 //      Scanner.DumpNodeRuns();
02765 #endif
02766 
02767         // We going to print the document now
02768         if (pPrintInfo != NULL)
02769             pPrintInfo->SetPrinting();
02770 
02771         // Set up the matrix and clipping rect
02772         pRender->SetMatrix(ViewTrans);
02773         pRender->SetClipRect(ClipRect);
02774 
02775         // Ask the render region not to render complex shapes
02776         pRender->SetRenderComplexShapes(FALSE);
02777     
02778         // Start the render region and get out if it fails
02779         if (!pRender->StartRender())
02780             goto OptimalRenderError;
02781 
02782         // I think it likely we need to put something in here.
02783         if (Printing)
02784         {
02785             // Render the spreads paper marks where necessary
02786             RenderPageMarks(pRender, ViewTrans, ClipRect, pSpread);
02787         }
02788 
02789         // Draw the paper if we have been asked to do so.
02790         if (PrintPaper)
02791         {
02792             // Render all paper nodes from there into the real render region
02793             pRender->SaveContext();
02794             RenderPaper(pRender, pSpread);
02795             pRender->RestoreContext();
02796 
02797             if (pRender->NeedsOSPaper)
02798             {
02799                 // This render region uses the OS to render paper, so if we don't
02800                 // render anything except paper then there is no need for e.g.
02801                 // GRenderRegions to blit anything.  Hence we call this function
02802                 // to clear the changed bbox.
02803                 pRender->SetClean(TRUE, FALSE);
02804             }
02805 
02806             // The Paper is now done
02807             pRender->IsPaperRendered = TRUE;
02808         }
02809 
02810         ProgressDisplay Progress;
02811         Progress.SetUpOptimal(pRender, &Scanner);
02812         INT32 NodesRendered = 0;
02813 
02814 //      TRACE( _T("Starting main render\n"));
02815         // We need to call RenderTree for the spread
02816         // We pass the ScanningRenderRegion to the RenderCallback object
02817         // so that it can tell which objects are normal and which are complex
02818         // We also pass the progress object so that can be updated
02819         OptimalPrintRenderCallback MyCallback(this, pSpread, RenderAllObjects, &Scanner, PrintPaper, &NodesRendered, &Progress, FALSE);
02820         pRender->RenderTree(pSpread, FALSE, FALSE, &MyCallback);
02821         MyCallback.FinishRendering(pRender);
02822 
02823         // Examine the callback object to see if anything went wrong
02824 
02825         // And stop rendering
02826         pRender->StopRender();
02827 
02828         // All worked, so return success
02829         Result = RENDERVIEW_SUCCESS;
02830     }
02831     
02832 OptimalRenderError:
02833 #ifdef _DEBUG
02834     if (Result != RENDERVIEW_SUCCESS)
02835         TRACEUSER( "Gerry", _T("RenderOptimalView failed\n"));
02836 #endif
02837 
02838     // Unlink the RenderRegion from list and error if it was not there
02839     BOOL InList = Camelot.DeleteRenderRegion(pRender);
02840     CAM_USE(InList); // Suppress unused variable warning on retail build
02841     ERROR3IF(!InList, "DocView::RenderOptimalView tried to delete a RenderRegion not in the list");
02842 
02843     // Instruct the render region to commit suicide. This call doesn't work on a CamelotEPS
02844     // render region.
02845     pRender->ConditionalSuicide ();
02846 
02847 //  TRACEUSER( "Gerry", _T("End of View::RenderOptimalView\n"));
02848 
02849     return Result;
02850 }
02851 
02852 /********************************************************************************************
02853 
02854 >   SlowJobResult View::RenderOptimalBitmapPhase(DocRect& ClipRect, Matrix& ViewTrans, Spread* pSpread,
02855                                             RenderRegion* pRender, Node* pLastNormalInRun,
02856                                             Node* pLastComplexInRun, BOOL RenderAllObjects,
02857                                             BOOL bPrintPaper,
02858                                             INT32& NodesSoFar, ProgressDisplay& Progress)
02859 
02860     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
02861     Created:    28/7/95
02862     Inputs:     ClipRect - the Clipping rectangle
02863                 ViewTrans - the view matrix to use
02864                 pSpread - the Spread to render to
02865                 pRender - the host render region
02866                 pLastNormalInRun - The last normal node in this run
02867                 pLastComplexInRun - the last complex node in the run
02868                 RenderAllObjects - TRUE if we render all objects, FALSE if its just the selection
02869                 NodesSoFar - the number of nodes rendered so far
02870                 Progress - the Progress display object
02871     Outputs:    NodesSoFar - The Number of nodes rendered after the Complex ones have been done
02872     Returns:    SLOWJOB_SUCCESS - if all went well
02873                 SLOWJOB_FAILURE - if all went bad 
02874                 SLOWJOB_USERABORT - if the user press 'esc'
02875     Purpose:    Renders the masked bitmap part of the process. This function will get called
02876                 many times during the typical rendering of the document (once for each run
02877                 of complex nodes in the document).
02878 
02879     Notes:      All rendering to the bitmap is done in composite colour (by ignoring the
02880                 ColourPlate attached to this view). The bitmap is then plotted into the output
02881                 RenderRegion, at which point it will be separated/corrected according to the
02882                 ColourPlate settings. This is for 2 reasons:
02883                 1) If we didn't stop it here, the output would be colour corrected twice, 
02884                    and thus come out wrong
02885                 2) Bleach transparency does not work correctly on pre-separated colours,
02886                    so we must render using composite colour in order to nmake such
02887                    transparent objects come out correctly.
02888 
02889 ********************************************************************************************/
02890 
02891 SlowJobResult View::RenderOptimalBitmapPhase(DocRect& ClipRect, Matrix& ViewTrans, Spread* pSpread,
02892                                             RenderRegion* pRender, Node* pLastNormalInRun,
02893                                             Node* pLastComplexInRun, BOOL RenderAllObjects,
02894                                             BOOL bPrintPaper, INT32& NodesSoFar, ProgressDisplay* pProgress,
02895                                             INT32 TotalProgress)
02896 {
02897     TRACEUSER( "Gerry", _T("View::RenderOptimalBitmapPhase TotalProgress = %d\n"), TotalProgress);
02898 
02899     INT32 EndProgress = NodesSoFar + TotalProgress;
02900 
02901     // work out the DPI - this is a bit complicated really
02902     double Dpi = 96.0;
02903     if (!pRender->IS_KIND_OF(GRenderRegion) && pRender->IsPrinting())
02904     {
02905         // we are printing, so ask the print options
02906         PrintControl *pPrintControl = GetPrintControl();
02907         ERROR2IF(pPrintControl == NULL, SLOWJOB_FAILURE, "No print control in RenderOptimalView");
02908         Dpi = (double) pPrintControl->GetDotsPerInch();
02909     }
02910     else if (IS_A(pRender, CamelotEPSRenderRegion))
02911     {
02912         // Use DPI as set in EPS export options dialog.
02913         Dpi = (double) EPSFilter::XSEPSExportDPI;
02914     }
02915     else
02916     {
02917         // Default to something reasonable (only really used for screens).
02918         Dpi = (double) (72000.0 / PixelWidth.MakeDouble());
02919     }
02920 
02921     // Markn 27/10/95
02922     // Scan the layers finding the union of the bounds of all the layers that should be rendered
02923     // This will be used to calc the Bitmap clip rect
02924     DocRect BitmapClipRect;
02925     Layer* pLayer = pSpread->FindFirstLayer();
02926     while (pLayer != NULL)
02927     {
02928         if (pLayer->NeedsToRender(pRender))
02929             BitmapClipRect = BitmapClipRect.Union(pLayer->GetBoundingRect());
02930 
02931         pLayer = pLayer->FindNextLayer();
02932     }
02933     // Make sure that the BitmapClipRect does not incude an area that's not included in the entry ClipRect
02934     BitmapClipRect = BitmapClipRect.Intersection(ClipRect);
02935 
02936     // Now we make sure the clip rect is pixel aligned
02937     INT32 TempPixels;
02938     double dPixelWidth = 72000.0 / Dpi;
02939     if (BitmapClipRect.Width() < dPixelWidth || BitmapClipRect.Height() < dPixelWidth)
02940     {
02941         TRACE( _T("Very small rectangle\n"));
02942     }
02943     TempPixels = (INT32)(((double)BitmapClipRect.lo.x) / dPixelWidth);
02944     BitmapClipRect.lo.x = (INT32)(((double)TempPixels) * dPixelWidth);
02945     if (BitmapClipRect.Width() < dPixelWidth)
02946         BitmapClipRect.hi.x = (INT32)(BitmapClipRect.lo.x + dPixelWidth);
02947     
02948     TempPixels = (INT32)(((double)BitmapClipRect.lo.y) / dPixelWidth);
02949     BitmapClipRect.lo.y = (INT32)(((double)TempPixels) * dPixelWidth);
02950     if (BitmapClipRect.Height() < dPixelWidth)
02951         BitmapClipRect.hi.y = INT32(BitmapClipRect.lo.y + dPixelWidth);
02952 
02953     // Markn 26/10/95
02954     // Find out if this render region is printing or not.
02955     // This is used as a param to the constructors of the bitmap-related render regions so that they
02956     // have the same printing state as the main render region.
02957     // If they don't, some nodes that shouldn't render when printing (e.g. background layers) will get 
02958     // rendered into the bitmaps.
02959     BOOL Printing = pRender->IsPrinting();
02960 
02961     // During this function, we force the View::GetColourContext function to return default
02962     // global contexts to anyone who asks, in order to disable any attempts to
02963     // colour separate or correct the output (we want a normal composite bitmap which
02964     // will be colour corrected by the main render region when we call PlotBitmap, below)
02965     BOOL OldForceState = ForceDefaultColourContexts;
02966     ForceDefaultColourContexts = TRUE;
02967 
02968     // Create a new GDraw context so we don't have to keep stopping and starting our regions
02969     GDrawAsm TempContext;
02970     if (!TempContext.Init())
02971     {
02972         return SLOWJOB_FAILURE;
02973     }
02974 
02975     // Use the temporary GDrawContext
02976     GDrawContext* pOldGD = GRenderRegion::SetTempDrawContext(&TempContext);
02977     if (pOldGD == NULL)
02978     {
02979         TRACEUSER( "Gerry", _T("NULL GDraw context returned from SetTempDrawContext\n"));
02980     }
02981 
02982     // Feathers require that the ScaleFactor of the render region be set correctly 
02983     // or they will only render correctly at 100%
02984     FIXED16 TempScale;
02985     ViewTrans.Decompose(&TempScale, NULL, NULL, NULL, NULL);
02986 
02987     // Also create a masked mono bitmap and Set them up
02988     PrintingMaskedRenderRegion MaskedBitmap(BitmapClipRect, ViewTrans, TempScale, Dpi, Printing);
02989     MaskedBitmap.AttachDevice(this, NULL, pSpread);
02990 
02991     // Create the colour Render Region as well
02992     GRenderBitmap BitmapRR(BitmapClipRect, ViewTrans, TempScale, 32, Dpi, Printing);
02993     BitmapRR.AttachDevice(this, NULL, pSpread);
02994 
02995     // ask for the bands to overlap
02996     BitmapRR.SetOverlapBands(TRUE);
02997     MaskedBitmap.SetOverlapBands(TRUE);
02998 
02999     // Start the first band in both of our renderregions
03000     if (!BitmapRR.SetFirstBand() || !MaskedBitmap.SetFirstBand())
03001     {
03002         ForceDefaultColourContexts = OldForceState;
03003         return SLOWJOB_FAILURE;
03004     }
03005 
03006     // Count the nodes in this complex run
03007 //  BOOL StartCounting = FALSE;
03008     INT32 TotalBands = MaskedBitmap.GetNumBands();
03009 
03010     // Count the nodes to be rendered so we can calculate the increment to use
03011     if (!MaskedBitmap.StartRender())
03012     {
03013         // Restore the ForceDefaultContext flag
03014         ForceDefaultColourContexts = OldForceState;
03015         GRenderRegion::SetTempDrawContext(pOldGD);
03016         return SLOWJOB_FAILURE;
03017     }
03018 
03019     // Find out what the host can do
03020     RRCaps HostCaps;
03021     pRender->GetRenderRegionCaps(&HostCaps);
03022     MaskedBitmap.SetHostCaps(&HostCaps);
03023     INT32 TotalNodes = 0;
03024 
03025     OptimalBitmapRenderCallback CountCallback(this, RenderAllObjects, pLastNormalInRun, pLastComplexInRun, TRUE, 0, &TotalNodes, pProgress, TRUE);
03026     MaskedBitmap.RenderTree(pSpread, FALSE, FALSE, &CountCallback);
03027 
03028     // Tell the render region we are done rendering
03029     MaskedBitmap.StopRender();
03030 
03031     double NodesPerBand = 0.0;
03032     if (TotalBands != 0)
03033         NodesPerBand = ((double)TotalProgress) / ((double)TotalBands * 3.0);
03034     double NodeIncrement = 0.0;
03035     if (TotalNodes != 0)
03036         NodeIncrement = NodesPerBand / ((double) TotalNodes);
03037 
03038 //  TRACEUSER( "Gerry", _T("TotalNodes - %ld\n"), TotalNodes);
03039 //  TRACEUSER( "Gerry", _T("TotalBands - %ld\n"), TotalBands);
03040 //  TRACEUSER( "Gerry", _T("NodesPerBand - %f\n"), NodesPerBand);
03041 //  TRACEUSER( "Gerry", _T("NodeIncrement - %f\n"), NodeIncrement);
03042 
03043     INT32 CurrentBand = 0;
03044 
03045     // loop through all the available bands
03046     BOOL MoreBands = FALSE;
03047     do
03048     {
03049         // Update the current band variable
03050         CurrentBand++;
03051 //      TRACEUSER( "Gerry", _T("Printing Band %d of %d\n"),CurrentBand,TotalBands);
03052 
03053         // Start it up
03054         if (!MaskedBitmap.StartRender())
03055         {
03056             // Restore the ForceDefaultContext flag
03057             ForceDefaultColourContexts = OldForceState;
03058             GRenderRegion::SetTempDrawContext(pOldGD);
03059             return SLOWJOB_FAILURE;
03060         }
03061 
03062         // Find out what the host can do
03063         RRCaps HostCaps;
03064         pRender->GetRenderRegionCaps(&HostCaps);
03065         MaskedBitmap.SetHostCaps(&HostCaps);
03066 
03067         // Fill the mask in white
03068         DocRect DrawRect = ClipRect;
03069 
03070         // Inflate the rect by 2 pixels
03071         DrawRect.Inflate((INT32)(2*72000.0/Dpi + 0.5)); 
03072 
03073         // Tell the masked render region that the following nodes are Simple
03074         MaskedBitmap.SetMaskDrawingMode(FALSE);
03075 
03076         MaskedBitmap.SaveContext();
03077         DocColour white(255,255,255);
03078         MaskedBitmap.SetFillColour(white);
03079         MaskedBitmap.DrawRect(&DrawRect);
03080         MaskedBitmap.RestoreContext();
03081 
03082         // Find out the size of the Region
03083         DocRect SizeOfRegion = MaskedBitmap.GetClipRect();
03084 
03085         // start actually rendering nodes in to the mask. Just the ones in this
03086         // complex run are actually rendering solid into the mask. All other nodes,
03087         // before and after the run are punched out.
03088         double RegionArea = (double)SizeOfRegion.Width() * (double)SizeOfRegion.Height();
03089         OptimalBitmapRenderCallback MaskCallback(this, RenderAllObjects, pLastNormalInRun, pLastComplexInRun, TRUE, RegionArea, &NodesSoFar, pProgress, FALSE, NodeIncrement);
03090         MaskedBitmap.RenderTree(pSpread, FALSE, FALSE, &MaskCallback);
03091 
03092         ENSURE(MaskedBitmap.GetCaptureDepth()==1, "Mask capture nesting not unwound correctly in RenderOptimalBitmapPhase\n");
03093 
03094         // Tell the render region we are done rendering
03095         MaskedBitmap.StopRender();
03096 
03097         // Make the mask a little bigger, to cover any errors from different dpis
03098         MaskedBitmap.SpreadMask();
03099 
03100 #ifdef _DEBUG_ATTACH_OPTIMAL_MASK
03101 OILBitmap* pMaskBitmap = MaskedBitmap.ExtractBitmapCopy();
03102 KernelBitmap* pRealMaskBmp = new KernelBitmap(pMaskBitmap, TRUE);
03103 pRealMaskBmp->AttachDebugCopyToCurrentDocument("TestMask");
03104 delete pRealMaskBmp;
03105 #endif
03106 
03107         // Draw the colour bitmap
03108         if (MaskedBitmap.FindCoverage()>0)
03109         {
03110             // Start rendering into the bitmap
03111             {
03112                 // Start the render region up.
03113                 BOOL ok = BitmapRR.StartRender();
03114                 if (!ok)
03115                 {
03116                     // Restore the ForceDefaultContext flag
03117                     ForceDefaultColourContexts = OldForceState;
03118                     GRenderRegion::SetTempDrawContext(pOldGD);
03119                     return SLOWJOB_FAILURE;
03120                 }
03121             }
03122 
03123             // Should draw a big white rectangle here, into the bitmap render region or
03124             // transparent objects will not fade to white where you can see the paper under them
03125             // Draw it into the real bitmap
03126             if (bPrintPaper)
03127             {
03128                 BitmapRR.SaveContext();
03129                 RenderPaper(&BitmapRR, pSpread);
03130                 BitmapRR.RestoreContext();
03131             }
03132             else
03133             {
03134                 BitmapRR.SaveContext();
03135                 DocColour white(255,255,255);
03136                 BitmapRR.SetFillColour(white);
03137                 BitmapRR.DrawRect(&DrawRect);
03138                 BitmapRR.RestoreContext();
03139             }
03140 
03141             // We always anti-alias the bitmap output
03142             QualityAttribute *pAttr = new QualityAttribute();
03143             pAttr->QualityValue.SetQuality(QUALITY_MAX);
03144             BitmapRR.SetQuality(pAttr, TRUE);
03145 
03146             OptimalBitmapRenderCallback ImageCallback(this, RenderAllObjects, pLastNormalInRun, pLastComplexInRun, FALSE, RegionArea, &NodesSoFar, pProgress, FALSE, NodeIncrement);
03147             BitmapRR.RenderTree(pSpread, FALSE, FALSE, &ImageCallback);
03148 
03149             ENSURE(BitmapRR.GetCaptureDepth()==1, "Bitmap capture nesting not unwound correctly in RenderOptimalBitmapPhase\n");
03150 
03151             // Stop rendering
03152             BitmapRR.StopRender();
03153 
03154             // Get the bitmaps from the render region
03155             OILBitmap* pFullBitmap = BitmapRR.ExtractBitmap();
03156             KernelBitmap* pRealBmp = new KernelBitmap(pFullBitmap, TRUE);
03157 
03158 #ifdef _DEBUG_ATTACH_OPTIMAL_BITMAP
03159 pRealBmp->AttachDebugCopyToCurrentDocument("TestBmp");
03160 #endif
03161 
03162             // Restore the ForceDefaultContext flag around the output rendering section
03163             ForceDefaultColourContexts = OldForceState;
03164 
03165             if (GRenderRegion::SetTempDrawContext(pOldGD) != &TempContext)
03166             {
03167                 TRACEUSER( "Gerry", _T("Not &TempContext when restoring\n"));
03168             }
03169             pOldGD = NULL;
03170 
03171 //          TRACE( _T("Rendering bitmap with mask\n"));
03172             // Save the context
03173             pRender->SaveContext();
03174 
03175             // Render the bitmap using the mask
03176             DocRect BandClipRect = BitmapRR.GetClipRect();
03177             SlowJobResult Result = pRender->DrawMaskedBitmap(BandClipRect, pRealBmp, &MaskedBitmap, NULL);
03178             if (Result != SLOWJOB_SUCCESS)
03179             {
03180                 // Either something has gone wrong, or an error has occured, so clean up.
03181 
03182                 // Get rid of the bitmaps. We have to detach it once, as it was attached 
03183                 // when extracted from the render region.
03184 //              pFullBitmap->Detach();
03185                 delete pRealBmp;
03186                 pRealBmp = NULL;
03187 
03188                 return SLOWJOB_FAILURE;
03189             }
03190 
03191             // restore the context and stop rendering
03192             pRender->RestoreContext();
03193 
03194             NodesSoFar += (INT32)NodesPerBand;
03195             if (pProgress)
03196             {
03197                 if (!pProgress->SetNodesRendered(NodesSoFar))
03198                 {
03199                     TRACE( _T("*****************************\n"));
03200                     TRACE( _T("************ User aborted job\n"));
03201                     TRACE( _T("*****************************\n"));
03202                 }
03203             }
03204 
03205             ForceDefaultColourContexts = TRUE;
03206 
03207             // Use the temporary GDrawContext
03208             pOldGD = GRenderRegion::SetTempDrawContext(&TempContext);
03209             if (pOldGD == NULL)
03210             {
03211                 TRACEUSER( "Gerry", _T("NULL GDraw context returned from SetTempDrawContext\n"));
03212             }
03213 
03214             // get rid of the bitmaps. We have to detach it once, as it was attached when extracted from the rr
03215 //          pFullBitmap->Detach();
03216             delete pRealBmp;
03217             pRealBmp = NULL;
03218         }
03219         else
03220         {
03221 //          TRACEUSER( "Gerry", _T("No mask coverage\n"));
03222 
03223             NodesSoFar += (INT32)(NodesPerBand * 2.0);
03224             if (pProgress)
03225             {
03226                 if (!pProgress->SetNodesRendered(NodesSoFar))
03227                 {
03228                     TRACE( _T("*****************************\n"));
03229                     TRACE( _T("************ User aborted job\n"));
03230                     TRACE( _T("*****************************\n"));
03231                 }
03232             }
03233         }
03234 
03235         // Ensure all captures are cleared before setting up next band
03236         BitmapRR.FreeOffscreenState();
03237 
03238         // Get the next bands ready
03239         BOOL MoreMaskedBands = MaskedBitmap.GetNextBand();
03240 TRACEUSER( "Phil", _T("GetNextBand (Before) %d, %d\n"), BitmapRR.GetClipRect().lo.y, BitmapRR.GetClipRect().hi.y);
03241         MoreBands = BitmapRR.GetNextBand();
03242 TRACEUSER( "Phil", _T("GetNextBand (After)  %d, %d\n"), BitmapRR.GetClipRect().lo.y, BitmapRR.GetClipRect().hi.y);
03243         ERROR3IF(MoreMaskedBands!=MoreBands, "Bands don't match");
03244         if (MoreMaskedBands!=MoreBands)
03245            MoreBands = FALSE;
03246 
03247     } while (MoreBands);
03248 
03249 
03250     // Restore the ForceDefaultContext flag
03251     ForceDefaultColourContexts = OldForceState;
03252 
03253     if (GRenderRegion::SetTempDrawContext(pOldGD) != &TempContext)
03254     {
03255         TRACEUSER( "Gerry", _T("Not &TempContext when restoring\n"));
03256     }
03257     pOldGD = NULL;
03258     
03259     // All went well so makesure the progress is at the right point
03260     NodesSoFar = EndProgress;
03261     if (pProgress)
03262         pProgress->SetNodesRendered(NodesSoFar);
03263 
03264     TRACEUSER( "Gerry", _T("End of View::RenderOptimalBitmapPhase\n"));
03265     return SLOWJOB_SUCCESS;
03266 }
03267 
03268 class SimplePrintRenderCallback : public RenderCallback
03269 {
03270 public:
03271     SimplePrintRenderCallback(View* pView, Spread* pSpread, BOOL bRenderAll, ScanningRenderRegion* pScanRR, BOOL bDoMasked, BOOL bPrintPaper, INT32* pNodesSoFar, ProgressDisplay* pProgress)
03272     {
03273         m_pView = pView;
03274         m_bRenderAll = bRenderAll;
03275         m_pScanRR = pScanRR;
03276         m_pFirstComplex = pScanRR->GetFirstComplexObject();
03277         m_pLastComplex = pScanRR->GetLastComplexObject();
03278         m_bDoMasked = bDoMasked;
03279         m_bPrintPaper = bPrintPaper;
03280         m_bDoComplex = FALSE;
03281         m_pSpread = pSpread;
03282         m_pNodesSoFar = pNodesSoFar;
03283         m_pProgress = pProgress;
03284     }
03285 
03286     virtual BOOL BeforeNode(RenderRegion* pRegion, Node* pNode)
03287     {
03288 //      BOOL bRender = (pNode->IsAnAttribute() || pNode->IsANodeClipView()) && (m_bRenderAll || m_pView->IsPrintableNodeSelected(pNode));
03289         BOOL bRender = m_bRenderAll || m_pView->IsPrintableNodeSelected(pNode);
03290 //      TRACE( _T("SPRC# BeforeNode    0x%08x - %s  returning %s\n", pNode, pNode->GetRuntimeClass()->GetClassName(), bRender ? "true" : "false"));
03291         if (pNode == m_pLastComplex)
03292             m_bDoComplex = TRUE;
03293         return(bRender);
03294     }
03295 
03296     virtual BOOL BeforeSubtree(RenderRegion* pRegion, Node* pNode, Node** ppNextNode, BOOL bClip, SubtreeRenderState* pState)
03297     {
03298 //      TRACE( _T("Warning - SimplePrintRenderCallback::BeforeSubtree called\n") );
03299 //      TRACE( _T("SPRC# BeforeSubtree 0x%08x - %s\n"), pNode, pNode->GetRuntimeClass()->GetClassName());
03300 
03301         if (m_bDoComplex)
03302         {
03303             // We need to render the complex span and start skipping
03304             m_bDoComplex = FALSE;
03305 
03306             DocRect ComplexRect;
03307             DocRect ClipRect = pRegion->GetClipRect();
03308             if (m_bDoMasked)
03309             {
03310                 // Render all the complex bits into a bitmap and mask blit it into the render region
03311                 ComplexRect = m_pScanRR->GetComplexBounds();
03312                 ComplexRect = ComplexRect.Intersection(ClipRect);
03313             }
03314             else
03315             {
03316                 // No masking - just do everything as a rectangular bitmap.
03317                 ComplexRect = ClipRect;
03318             }
03319 
03320             if (ComplexRect.IsValid())
03321             {
03322 //              TRACE( _T("Entire complex span rendered here\n"));
03323 //              TRACE( _T("ComplexRect = (%d, %d) - (%d, %d)\n"), ComplexRect.lo.x, ComplexRect.lo.y, ComplexRect.hi.x, ComplexRect.hi.y);
03324                 // Call RenderBitmapPhase to handle this
03325                 SlowJobResult BitmapResult;
03326                 Matrix ViewTrans = pRegion->GetMatrix();
03327                 BitmapResult = m_pView->RenderBitmapPhase(ComplexRect, ViewTrans, m_pSpread, pRegion,
03328                                                   m_pFirstComplex, m_pLastComplex, m_bRenderAll,
03329                                                   m_bPrintPaper, *m_pProgress);
03330             }
03331         }
03332         
03333         return(FALSE);
03334     }
03335 
03336 //  virtual BOOL AfterSubtree(RenderRegion* pRegion, Node* pNode);
03337 
03338 private:
03339     View* m_pView;
03340     Spread* m_pSpread;
03341     ScanningRenderRegion* m_pScanRR;
03342     Node* m_pFirstComplex;
03343     Node* m_pLastComplex;
03344     BOOL m_bDoMasked;
03345     BOOL m_bRenderAll;
03346     BOOL m_bPrintPaper;
03347     INT32* m_pNodesSoFar;
03348     ProgressDisplay* m_pProgress;
03349 
03350     BOOL m_bDoComplex;      // TRUE to make next call to BeforeSubtree render the complex phase
03351 };
03352 
03353 
03354 class SimpleBitmapRenderCallback : public RenderCallback
03355 {
03356 public:
03357     typedef enum
03358     {
03359         RS_BEFORECOMPLEX = 0,
03360         RS_INCOMPLEX,
03361         RS_AFTERCOMPLEX,
03362     } RenderStateType;
03363     
03364     SimpleBitmapRenderCallback(View* pView, BOOL bRenderAll, Node* pFirstComplex, Node* pLastComplex, BOOL bRenderMask)
03365     {
03366         m_pView = pView;
03367         m_bRenderAll = bRenderAll;
03368         m_pFirstComplex = pFirstComplex;
03369         m_pLastComplex = pLastComplex;
03370         m_bRenderMask = bRenderMask;
03371         m_RenderState = RS_BEFORECOMPLEX;
03372     }
03373 
03374     virtual BOOL BeforeNode(RenderRegion* pRegion, Node* pNode)
03375     {
03376 //      BOOL bRender = (m_bRenderAll || m_pView->IsPrintableNodeSelected(pNode)) && pNode->NeedsToRender(pRegion);
03377         BOOL bRender = (m_bRenderAll || m_pView->IsPrintableNodeSelected(pNode));
03378         if (m_RenderState == RS_AFTERCOMPLEX)
03379             bRender = FALSE;
03380         if (m_RenderState == RS_INCOMPLEX && pNode == m_pLastComplex)
03381         {
03382 //          TRACE( _T("SBRC# Hit LastComplex\n"));
03383             m_RenderState = RS_AFTERCOMPLEX;
03384         }
03385 
03386 //      if (m_bRenderMask)
03387 //          TRACE( _T("SBRCM# BeforeNode    0x%08x - %s returning %s\n", pNode, pNode->GetRuntimeClass()->GetClassName(), bRender ? "true" : "false"));
03388 //      else
03389 //          TRACE( _T("SBRCB# BeforeNode    0x%08x - %s returning %s\n", pNode, pNode->GetRuntimeClass()->GetClassName(), bRender ? "true" : "false"));
03390         return(bRender);
03391     }
03392 
03393     virtual BOOL BeforeSubtree(RenderRegion* pRegion, Node* pNode, Node** ppNextNode, BOOL bClip, SubtreeRenderState* pState)
03394     {
03395 //      if (m_bRenderMask)
03396 //          TRACE( _T("SBRCM# BeforeSubtree 0x%08x - %s\n"), pNode, pNode->GetRuntimeClass()->GetClassName());
03397 //      else
03398 //          TRACE( _T("SBRCB# BeforeSubtree 0x%08x - %s\n"), pNode, pNode->GetRuntimeClass()->GetClassName());
03399 
03400         if (pNode == m_pFirstComplex)
03401         {
03402             if (m_RenderState == RS_BEFORECOMPLEX)
03403             {
03404 //              TRACE( _T("SBRC# Hit FirstComplex\n"));
03405                 // Change state to be in the complex span
03406                 m_RenderState = RS_INCOMPLEX;
03407             }
03408         }
03409         
03410         return(FALSE);
03411     }
03412 
03413 //  virtual BOOL AfterSubtree(RenderRegion* pRegion, Node* pNode);
03414 
03415 private:
03416     View* m_pView;
03417     BOOL m_bRenderAll;
03418     Node* m_pFirstComplex;
03419     Node* m_pLastComplex;
03420     BOOL m_bRenderMask;         // TRUE if rendering the mask bitmap
03421     RenderStateType m_RenderState;
03422 };
03423 
03424 
03425 
03426 /********************************************************************************************
03427 
03428 >   RenderViewResult View::RenderSimpleView(RenderRegion* pRender, Matrix& ViewTrans,
03429                                 Spread* pSpread, BOOL PrintPaper)
03430 
03431 
03432     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
03433     Created:    10/4/95
03434     Inputs:     pRender - The render region to render into
03435                 ViewTrans - the transform matrix to use for the rendering
03436                 pSpread - the spread to render
03437                 PrintPaper - TRUE if the paper should be rendered as well
03438     Returns:    RENDERVIEW_SUCCESS   - view was rendered successfully
03439                 RENDERVIEW_FAILURE   - an error occured while rendering the view.
03440                 RENDERVIEW_NOTNEEDED - the view was not rendered as the usual RenderView
03441                                        call can be used instead.
03442                 RENDERVIEW_USERABORT - the user aborted the rendering operation.
03443                                        (e.g. pressing Escape, or aborting the print job)
03444     Purpose:    This function has been designed along similar lines to the RenderView()
03445                 function found elsewhere in this file. This version of the function is
03446                 slightly different though. This version of the function is able to render
03447                 complex objects, such as transparent objects into normal render regions.
03448                 It does this by first scanning through all the objects that need rendering
03449                 to see if any of them require complex things. If they do, then part of the
03450                 rendering is done into a bitmap and blitted over the rest of the shapes using
03451                 a masked blit. All very complicated really!
03452     SeeAlso:    DocView::RenderView
03453 
03454 ********************************************************************************************/
03455 
03456 /*
03457 Technical notes:
03458     The process...
03459 
03460     Build a scanning render region
03461     Scanning render the document
03462 
03463     see if there were any complex shapes.
03464         Render the document up to the complex shapes as normal
03465 
03466         Start a masked Bitmap render region
03467         render the appropriate bits of the document into it
03468 
03469         blit the bitmap into the render region
03470 
03471     render all remaining shapes (may be all the shapes, if there were no complex ones)
03472 */
03473 RenderViewResult View::RenderSimpleView(RenderRegion* pRender, Matrix& ViewTrans, Spread* pSpread,
03474                                         BOOL PrintPaper)
03475 {
03476 #ifndef STANDALONE
03477 //  TRACEUSER( "Gerry", _T("View::RenderSimpleView\n"));
03478 
03479     BOOL bIsOnScreen = pRender->IS_KIND_OF(GRenderRegion);
03480 
03481     // if the preference says we should not be in this function then call the other function
03482     if (!bIsOnScreen && PrintMonitor::PrintMaskType==PrintMonitor::MASK_OPTIMAL)
03483         return RenderOptimalView(pRender, ViewTrans, pSpread, PrintPaper);
03484 
03485     // Find out what the host render region is capable of
03486     RRCaps Caps;
03487     pRender->GetRenderRegionCaps(&Caps);
03488 
03489     // Whether or not the rendering was successful.
03490     RenderViewResult Result = RENDERVIEW_FAILURE;
03491 
03492     // Find out the Clipping rectangle of the render region to draw into
03493     DocRect ClipRect = pRender->GetClipRect();
03494 
03495     // Work out whether we need to render all objects, or just the selected ones.
03496     BOOL RenderAllObjects = TRUE;
03497 #ifndef WEBSTER
03498     CCPrintInfo *pPrintInfo = NULL;
03499     if (!bIsOnScreen && pRender->IsPrinting())
03500     {
03501         pPrintInfo = CCPrintInfo::GetCurrent();
03502 //      ERROR2IF(pPrintInfo == NULL, RENDERVIEW_FAILURE, "No print info while printing!");
03503         if (pPrintInfo != NULL)
03504         {
03505             PrintControl *pPrCtrl = pPrintInfo->GetPrintControl();
03506             RenderAllObjects = (pPrCtrl->GetObjPrintRange() == PRINTRANGEOBJ_ALL);
03507         }
03508     }
03509 #endif //webster
03510     // Create and set up a new Scanning render region
03511     ScanningRenderRegion Scanner(pRender->IsPrinting());
03512 
03513     BOOL bDoScan = TRUE;
03514     
03515     if (bIsOnScreen)
03516     {
03517         // Now check the print method to determine if we need to do a three-pass render
03518         // Get document pointer
03519         Document* pDoc = GetDoc();
03520 
03521         // Get print information for this document.
03522         PrintComponent *pPrint = (PrintComponent *) pDoc->GetDocComponent(CC_RUNTIME_CLASS(PrintComponent));
03523         if (pPrint)
03524         {
03525             PrintControl *pPrintControl = pPrint->GetPrintControl();
03526             if (pPrintControl)
03527             {
03528                 if (pPrintControl->GetPrintMethod() != PRINTMETHOD_NORMAL)
03529                 {
03530                     bDoScan = FALSE;
03531                 }
03532             }
03533         }
03534     }
03535 
03536     // Declare some useful vars before the scanning chunk
03537 //  Node* pFirstInkNode = NULL;
03538 //  Node* pNode = NULL;
03539     if (bDoScan)
03540     {
03541         // Attach a device to the scanning render region
03542         // Since this rr does no real rendering, it does not need a Device context
03543         Scanner.AttachDevice(this, (CNativeDC *)NULL, pSpread);
03544 
03545         // Get it ready to render
03546         Scanner.SetMatrix(ViewTrans);
03547         Scanner.SetClipRect(ClipRect);
03548         
03549         // Start the render region and return if it fails
03550         if (!Scanner.StartRender())
03551             return RENDERVIEW_FAILURE;
03552         
03553         // and tell the scanning render region about the caps of the host region
03554         Scanner.SetHostRRCaps(Caps);
03555 
03556         //  WEBSTER-ranbirr-13/11/96
03557 #ifndef WEBSTER
03558         // We going to analyse the document
03559         if (pPrintInfo != NULL)
03560             pPrintInfo->SetAnalysing();
03561 #endif //webster
03562         // Find the first node to render
03563 //      pFirstInkNode = pSpread->FindFirstForUnclippedInkRender(&Scanner);
03564 //      Scanner.SetRenderState(pFirstInkNode);
03565 
03566         ScannerRenderCallback ScanCallback(this, RenderAllObjects, &Scanner);
03567 
03568         // Call RenderTree to do the rendering
03569         Scanner.RenderTree(pSpread, FALSE, FALSE, &ScanCallback);
03570         
03571         // Thats all the nodes rendered, so stop rendering  
03572         Scanner.StopRender();
03573     }
03574     
03575     //  WEBSTER-ranbirr-13/11/96
03576 #ifndef WEBSTER
03577     // We going to print the document now
03578     if (pPrintInfo != NULL)
03579         pPrintInfo->SetPrinting();
03580 #endif //webster
03581 
03582     // Ok, we now have a Scanning render region that has all the info we need to know in it.
03583     // See if there were any complex shapes in the region
03584     // If we didn't do a scan then pretend there is one complex node
03585     /*INT32 NumComplex =*/ bDoScan ? Scanner.GetNumComplex() : 1;
03586 
03587     // Oh well, there are complex shapes to draw, so we had better do the comlpex thing
03588 
03589     pRender->SetMatrix(ViewTrans);
03590     pRender->SetClipRect(ClipRect);
03591     
03592     // Ask the render region not to render complex shapes
03593     pRender->SetRenderComplexShapes(FALSE);
03594     
03595     // Start the render region and return if it fails
03596     if (!pRender->StartRender())
03597         return RENDERVIEW_FAILURE;
03598 
03599     // I think it likely we need to put something in here.
03600     if (pRender->IsPrinting())
03601     {
03602         // Render the spreads paper marks where necessary
03603         RenderPageMarks(pRender, ViewTrans, ClipRect, pSpread);
03604     }
03605 
03606     // Draw the paper if we have been asked to do so.
03607     if (PrintPaper)
03608     {
03609         // Render all paper nodes from there into the real render region
03610         pRender->SaveContext();
03611         RenderPaper(pRender, pSpread);
03612         pRender->RestoreContext();
03613 
03614         if (pRender->NeedsOSPaper)
03615         {
03616             // This render region uses the OS to render paper, so if we don't
03617             // render anything except paper then there is no need for e.g.
03618             // GRenderRegions to blit anything.  Hence we call this function
03619             // to clear the changed bbox.
03620             pRender->SetClean(TRUE, FALSE);
03621         }
03622 
03623         // The Paper is now done
03624         pRender->IsPaperRendered = TRUE;
03625     }
03626 
03627     // Find the first and last complex node in the document
03628     Node* pFirstComplexNode = Scanner.GetFirstComplexObject();  
03629     Node* pLastComplexNode = Scanner.GetLastComplexObject();
03630 
03631     // Create and initialise the progress display.
03632     // (NB. we don't always do progress display, e.g. for screens we don't bother)
03633     ProgressDisplay Progress;
03634 //  Progress.SetUp(pRender, &Scanner);
03635     INT32 NodesRendered = 0;
03636 
03637     // Find the first node to render
03638 //  pFirstInkNode = pSpread->FindFirstForUnclippedInkRender(pRender);
03639     if (!bDoScan)
03640     {
03641         pFirstComplexNode = pSpread;
03642         pLastComplexNode = NULL;
03643     }
03644 
03645     TRACE( _T("pFirstComplexNode = 0x%08x\n"), pFirstComplexNode);
03646     TRACE( _T("pLastComplexNode  = 0x%08x\n"), pLastComplexNode);
03647     
03648 //  pRender->SetRenderState(pFirstInkNode);
03649 
03650     // Find out about the first node and the first complex node
03651 //  pNode = pRender->GetRenderState();
03652 
03653     // Check to see if we should do a masked blit.
03654     // We always do it under NT, or to a PostScript printer or EPS file; under other conditions
03655     // we are controlled by the printing preference.
03656     BOOL DoMaskedBlit = FALSE;
03657     if (//IsWin32NT() || 
03658         bIsOnScreen ||
03659         (PrintMonitor::PrintMaskType==PrintMonitor::MASK_MASKED) ||
03660         (CCDC::GetType(pRender->GetRenderDC(), TRUE) == RENDERTYPE_PRINTER_PS) ||
03661         IS_A(pRender, CamelotEPSRenderRegion))
03662     {
03663         DoMaskedBlit = bDoScan;             // Don't render simple phase if not scanning
03664     }
03665     SimplePrintRenderCallback MyCallback(this, pSpread, RenderAllObjects, &Scanner, DoMaskedBlit, PrintPaper, &NodesRendered, &Progress);
03666     pRender->RenderTree(pSpread, FALSE, FALSE, &MyCallback);
03667 
03668     pRender->StopRender();
03669 
03670     // If we get here, it all worked
03671     Result = RENDERVIEW_SUCCESS;
03672 
03673 //ExitRenderSimpleView:
03674 
03675     // Unlink the RenderRegion from list and error if it was not there
03676     BOOL InList = Camelot.DeleteRenderRegion(pRender);
03677     ERROR2IF(!InList,RENDERVIEW_FAILURE,"DocView::RenderView tried to delete a RenderRegion not in the list");
03678 
03679     // Instruct the render region to commit suicide. This call doesn't work on a CamelotEPS
03680     // render region.
03681     pRender->ConditionalSuicide ();
03682 
03683     // Finish progress bar for EPS export
03684     if (Result == RENDERVIEW_SUCCESS)
03685         Progress.AllStagesDone();
03686 
03687 //  TRACEUSER( "Gerry", _T("End of View::RenderSimpleView\n"));
03688 
03689     return Result;
03690 
03691 #else
03692     return RENDERVIEW_USERABORT;
03693 #endif
03694 }
03695 
03696 /********************************************************************************************
03697 
03698 >   SlowJobResult View::RenderBitmapPhase(DocRect& ClipRect, Matrix& ViewTrans, Spread* pSpread,
03699                                           RenderRegion* pHostRegion, Node* pFirstComplex, Node* pLastComplex,
03700                                           BOOL bRenderAll, BOOL bPrintPaper, ProgressDisplay& Progress)
03701 
03702     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
03703     Created:    12/4/95
03704     Inputs:     ClipRect - the clipping rectangle of the region
03705                 ViewTrans - the matrix to render through
03706                 pSpread - The Spread we are drawing
03707                 pHostRegion - The Render Region we are rendering on behalf of
03708                 pFirstComplex - The first complex node that needs rendering
03709                 pLastComplex - The last complex node that needs rendering
03710                 Progress - the usual progress display object.
03711     Returns:    TRUE if everything was fabby, FALSE if there was a problem
03712     Purpose:    This function is called from RenderSimpleView if it ends up having to
03713                 do the 3 phase rendering system. This function performs the bitmap phase,
03714                 where all the objects deemed to be complex by the Host render region are
03715                 rendered into a bitmap using GDraw and a mono, mask bitmap. The bitmap
03716                 is blitted into the host render region using the mask bitmap, minimising
03717                 the amount of bitmaps ending up in the view (important for things like
03718                 postscript that do not really like bitmaps very much).
03719     SeeAlso:    DocView::RenderSimpleView; ProgressDisplay
03720 
03721 ********************************************************************************************/
03722 
03723 /*
03724     IMPORTANT TECHNICAL NOTE:
03725 
03726     Note that we must scan the tree without using the region's clip rectangle, because otherwise
03727     we will miss the 'last complex node' when searching, because e.g. it is outside the
03728     clipping rectangle of a particular band, so we will keep rendering until we reach the top 
03729     of the drawing object stack, which is bad.  Therefore, we scan without doing region tests,
03730     but we check whether the node actually needs to render using the current band's
03731     clipping region.
03732 
03733     This means we don't render too much in each band, and we stop rendering when we should.
03734 */
03735 
03736 SlowJobResult View::RenderBitmapPhase(DocRect& ComplexClipRect, Matrix& ViewTrans, Spread* pSpread,
03737                                       RenderRegion* pHostRegion, Node* pFirstComplex, Node* pLastComplex,
03738                                       BOOL bRenderAll, BOOL bPrintPaper, ProgressDisplay& Progress)
03739 {
03740 #ifndef STANDALONE
03741 //  TRACEUSER( "Gerry", _T("View::RenderBitmapPhase\n"));
03742 
03743     BOOL bIsOnScreen = pHostRegion->IS_KIND_OF(GRenderRegion);
03744 
03745     ERROR3IF(!bIsOnScreen &&
03746              PrintMonitor::PrintMaskType==PrintMonitor::MASK_OPTIMAL,
03747             "PrintMaskType must be SIMPLE or MASKED here\n");
03748 
03749     // This needs to be done in 2 phases - one to create the bitmap we will blit into the
03750     // host render region and one to create the mask to show us which parts of the bitmap
03751     // need to be blitted. First we will create the bitmap to blit into the host.
03752     // create the bitmap render region
03753 //  CNativeDC* pDC = pHostRegion->GetRenderDC();
03754 
03755     double Dpi;
03756     if (bIsOnScreen)
03757     {
03758         Dpi = (double) (72000.0 / PixelWidth.MakeDouble());
03759 //      Dpi = Dpi / 4.0;
03760     }
03761     else if (pHostRegion->IsPrinting())
03762     {
03763         PrintControl *pPrintControl = GetPrintControl();
03764         ERROR2IF(pPrintControl == NULL, SLOWJOB_FAILURE, "No print control in RenderBitmapPhase()");
03765         Dpi = (double) pPrintControl->GetDotsPerInch();
03766     }
03767     else if (IS_A(pHostRegion, CamelotEPSRenderRegion))
03768     {
03769         // Use DPI as set in EPS export options dialog.
03770         Dpi = (double) EPSFilter::XSEPSExportDPI;
03771     }
03772     else
03773     {
03774         // Default to something reasonable (only really used for screens).
03775         Dpi = (double) (72000.0 / PixelWidth.MakeDouble());
03776     }
03777 
03778     BOOL bDoScan = TRUE;
03779     if (bIsOnScreen)
03780     {
03781         // Now check the print method to determine if we need to do a three-pass render
03782         // Get document pointer
03783         Document* pDoc = GetDoc();
03784 
03785         // Get print information for this document.
03786         PrintComponent *pPrint = (PrintComponent *) pDoc->GetDocComponent(CC_RUNTIME_CLASS(PrintComponent));
03787         if (pPrint)
03788         {
03789             PrintControl *pPrintControl = pPrint->GetPrintControl();
03790             if (pPrintControl)
03791             {
03792                 if (pPrintControl->GetPrintMethod() != PRINTMETHOD_NORMAL)
03793                 {
03794                     bDoScan = FALSE;
03795                 }
03796             }
03797         }
03798     }
03799 
03800     // Check to see if we should do a masked blit.
03801     // We always do it under NT, or to a PostScript printer; under other conditions
03802     // we are controlled by the printing preference.
03803     BOOL DoMaskedBlit = FALSE;
03804     if (//IsWin32NT() || 
03805         bIsOnScreen ||
03806         (PrintMonitor::PrintMaskType==PrintMonitor::MASK_MASKED) ||
03807         (CCDC::GetType(pHostRegion->GetRenderDC(), TRUE) == RENDERTYPE_PRINTER_PS) ||
03808         IS_A(pHostRegion, CamelotEPSRenderRegion))
03809     {
03810         DoMaskedBlit = TRUE;
03811     }
03812 
03813     // Work out the clip rect to use
03814     DocRect ClipRect = ComplexClipRect;
03815     ClipRect.Inflate((INT32)(2*72000.0/Dpi + 0.5));
03816 
03817     // We will need the clip rect of the whole region too
03818     DocRect RClipRect = pHostRegion->GetRegionRect();
03819 
03820 //  pHostRegion->StopRender();
03821 
03822     // During this function, we force the View::GetColourContext function to return default
03823     // global contexts to anyone who asks, in order to disable any attempts to
03824     // colour separate or correct the output (we want a normal composite bitmap which
03825     // will be colour corrected by the main render region when we call PlotBitmap, below)
03826     BOOL OldForceState = ForceDefaultColourContexts;
03827     ForceDefaultColourContexts = TRUE;
03828 
03829     // Create a new GDraw context so we don't have to keep stopping and starting our regions
03830     GDrawAsm TempContext;
03831     if (!TempContext.Init())
03832     {
03833         ForceDefaultColourContexts = OldForceState;
03834         return SLOWJOB_FAILURE;
03835     }
03836 
03837     // Replace the static GDraw context with our temp one
03838 //  GDrawContext* pOldGD = NULL;
03839 
03840     GDrawContext* pOldGD = GRenderRegion::SetTempDrawContext(&TempContext);
03841     if (pOldGD == NULL)
03842     {
03843         TRACEUSER( "Gerry", _T("NULL GDraw context returned from SetTempDrawContext\n"));
03844     }
03845 
03846     // Feathers require that the ScaleFactor of the render region be set correctly 
03847     // or they will only render correctly at 100%
03848     FIXED16 TempScale;
03849     ViewTrans.Decompose(&TempScale, NULL, NULL, NULL, NULL);
03850 
03851     // Set it up
03852     GRenderBitmap BitmapRR(ClipRect, ViewTrans, TempScale, 32, Dpi);
03853     BitmapRR.AttachDevice(this, NULL, pSpread);
03854 
03855     // Update progress display if necessary.
03856     Progress.StartBitmapPhase(BitmapRR.GetNumBands());
03857 
03858     // Also create a masked mono bitmap and Set them up
03859     MaskedRenderRegion MaskedBitmap(ClipRect, ViewTrans, TempScale, Dpi);
03860     MaskedBitmap.AttachDevice(this, NULL, pSpread);
03861 
03862     // ask for the bands to overlap
03863     BitmapRR.SetOverlapBands(TRUE);
03864     MaskedBitmap.SetOverlapBands(TRUE);
03865 
03866     // Start the first band
03867     if (!BitmapRR.SetFirstBand())
03868     {
03869         ForceDefaultColourContexts = OldForceState;
03870         return SLOWJOB_FAILURE;
03871     }
03872 
03873     // in the masked region as well
03874     if (!MaskedBitmap.SetFirstBand())
03875     {
03876         ForceDefaultColourContexts = OldForceState;
03877         return SLOWJOB_FAILURE;
03878     }
03879 
03880     INT32 CurrentBand = 0;
03881 
03882     // loop through all the available bands
03883     BOOL MoreBands = FALSE;
03884     do
03885     {
03886         CurrentBand++;
03887 //      TRACEUSER( "Gerry", _T("Printing Band %d\n"),CurrentBand);
03888 
03889         // Start rendering into the bitmap
03890         if (!BitmapRR.StartRender())
03891         {
03892             GRenderRegion::SetTempDrawContext(pOldGD);
03893             ForceDefaultColourContexts = OldForceState;
03894             return SLOWJOB_FAILURE;
03895         }
03896 
03897         // Should draw a big white rectangle here, into the bitmap render region or
03898         // transparent objects will not fade to white where you can see the paper under them
03899         DocRect DrawRect = ClipRect;
03900         // Inflate the rect by 2 pixels
03901         DrawRect.Inflate( (INT32)(2*72000.0/Dpi + 0.5) );
03902 
03903         if (bPrintPaper)
03904         {
03905             BitmapRR.SaveContext();
03906             RenderPaper(&BitmapRR, pSpread);
03907             BitmapRR.RestoreContext();
03908         }
03909         else
03910         {
03911             // Draw it into the real bitmap
03912             BitmapRR.SaveContext();
03913             DocColour white(255,255,255);
03914             BitmapRR.SetFillColour(white);
03915             BitmapRR.DrawRect(&DrawRect);
03916             BitmapRR.RestoreContext();
03917         }
03918 
03919         // We anti-alias the transparency mask 
03920         QualityAttribute *pAttr = new QualityAttribute();
03921         pAttr->QualityValue.SetQuality(QUALITY_MAX);
03922         BitmapRR.SetQuality(pAttr, TRUE);
03923 //      BitmapRR.RRQuality.SetQuality(QUALITY_MAX);
03924 //      BitmapRR.SetQualityLevel();
03925 
03926         RRCaps HostCaps;
03927         pHostRegion->GetRenderRegionCaps(&HostCaps);
03928 
03929         SimpleBitmapRenderCallback ImageCallback(this, bRenderAll, pFirstComplex, pLastComplex, FALSE);
03930         BitmapRR.RenderTree(pSpread, FALSE, FALSE, &ImageCallback);
03931 
03932         // Stop rendering
03933         BitmapRR.StopRender();
03934 
03935         // Start it up
03936         if (!MaskedBitmap.StartRender())
03937         {
03938             GRenderRegion::SetTempDrawContext(pOldGD);
03939             ForceDefaultColourContexts = OldForceState;
03940             return SLOWJOB_FAILURE;
03941         }
03942 
03943         // Now, either we are rendering a masked bitmap, in which case we only want the complex
03944         // objects to render in the mask, or we are rendering the objects with a rectangular
03945         // bitmap, in which case we want *all* objects to render into the mask.
03946         if (DoMaskedBlit)
03947         {
03948             // Find out what the host can do
03949             pHostRegion->GetRenderRegionCaps(&HostCaps);
03950         }
03951         else
03952         {
03953             // Mark this region as not able to do anything, so the bitmap render region
03954             // will do everything for it (i.e. all objects will render into the mask).
03955             HostCaps.CanDoNothing();
03956         }
03957 
03958         MaskedBitmap.SetHostCaps(&HostCaps);
03959 
03960         // Fill the mask in "simple"
03961         MaskedBitmap.SaveContext();
03962         DocColour white(255,255,255);
03963         MaskedBitmap.SetFillColour(white);
03964         MaskedBitmap.DrawRect(&DrawRect);
03965         MaskedBitmap.RestoreContext();
03966 
03967         if (!bDoScan)
03968         {
03969             HostCaps.CanDoNothing();
03970             MaskedBitmap.SetHostCaps(&HostCaps);
03971         }
03972 
03973         SimpleBitmapRenderCallback MaskCallback(this, bRenderAll, pFirstComplex, pLastComplex, TRUE);
03974         MaskedBitmap.RenderTree(pSpread, FALSE, FALSE, &MaskCallback);
03975 
03976         // Tell the render region we are done rendering
03977         MaskedBitmap.StopRender();
03978         
03979         // Make the mask a little bigger, to cover any errors from different dpis
03980         MaskedBitmap.SpreadMask();
03981 
03982         // Get the mask bitmap from the render region
03983 //      OILBitmap* pMaskBitmap = MaskedBitmap.ExtractBitmapCopy();
03984 //      KernelBitmap* pRealMaskBmp = new KernelBitmap(pMaskBitmap, TRUE);
03985 //      pRealMaskBmp->AttachDebugCopyToCurrentDocument("TestMask");
03986 //      delete pRealMaskBmp;
03987         
03988         // Get the bitmaps from the render region
03989         OILBitmap* pFullBitmap = BitmapRR.ExtractBitmap();
03990         KernelBitmap* pRealBmp = new KernelBitmap(pFullBitmap, TRUE);
03991 
03992 //      pRealBmp->AttachDebugCopyToCurrentDocument("TestBmp");
03993 
03994         // Restore the ForceDefaultContext flag around the output rendering section
03995         ForceDefaultColourContexts = OldForceState;
03996         
03997         // Restore the original GDrawContext
03998         if (GRenderRegion::SetTempDrawContext(pOldGD) != &TempContext)
03999         {
04000             TRACEUSER( "Gerry", _T("Not &TempContext when restoring\n"));
04001         }
04002         pOldGD = NULL;
04003 
04004         // Now render the bitmap we have into the host render region.
04005 //      if (pHostRegion->StartRender())
04006 //      {
04007             // Save the context
04008             pHostRegion->SaveContext();
04009 
04010             // Render the bitmap using the mask
04011             DocRect BandClipRect = BitmapRR.GetClipRect();
04012 //          TRACE( _T("BandClipRect = (%d, %d) - (%d, %d)\n"), BandClipRect.lo.x, BandClipRect.lo.y, BandClipRect.hi.x, BandClipRect.hi.y);
04013 //          TRACE( _T("BandMatrix = \n"));
04014 //          Matrix HostMatrix = pHostRegion->GetMatrix();
04015 //          HostMatrix.Dump();
04016             SlowJobResult Result = pHostRegion->DrawMaskedBitmap(BandClipRect, pRealBmp, 
04017                                                                  &MaskedBitmap, &Progress);
04018 
04019             if (Result != SLOWJOB_SUCCESS)
04020             {
04021                 // Either something has gone wrong, or an error has occured, so clean up.
04022 
04023                 // Get rid of the bitmaps. We have to detach it once, as it was attached 
04024                 // when extracted from the render region.
04025 //              pFullBitmap->Detach();
04026                 delete pRealBmp;
04027                 pRealBmp = NULL;
04028 
04029                 return Result;
04030             }
04031 
04032             // restore the context and stop rendering
04033             pHostRegion->RestoreContext();
04034 //          pHostRegion->StopRender();
04035 //      }
04036 
04037         ForceDefaultColourContexts = TRUE;
04038 
04039         // Make sure we are using the temporary GDrawContext
04040         pOldGD = GRenderRegion::SetTempDrawContext(&TempContext);
04041         if (pOldGD == NULL)
04042         {
04043             TRACEUSER( "Gerry", _T("NULL GDraw context returned from SetTempDrawContext\n"));
04044         }
04045 
04046         // get rid of the bitmaps. We have to detach it once, as it was attached when extracted from the rr
04047 //      pFullBitmap->Detach();
04048         delete pRealBmp;
04049         pRealBmp = NULL;
04050 
04051         // Ensure all captures are cleared before setting up next band.
04052         MaskedBitmap.FreeOffscreenState();
04053         BitmapRR.FreeOffscreenState();
04054 
04055         // Get the next bands ready
04056         BOOL MoreMaskedBands = MaskedBitmap.GetNextBand();
04057         MoreBands = BitmapRR.GetNextBand();
04058         CAM_USE(MoreMaskedBands); // suppress unused variable wanring on retail builds
04059         ERROR3IF(MoreMaskedBands!=MoreBands, "Bands don't match");
04060 
04061         // Update progress display
04062         if (!Progress.EndBitmapPhaseBand())
04063         {
04064             ForceDefaultColourContexts = OldForceState;
04065             // User has aborted operation
04066             return SLOWJOB_USERABORT;
04067         }
04068 
04069     } while (MoreBands);
04070 
04071 #endif
04072 
04073     // Restore the ForceDefaultContext flag
04074     ForceDefaultColourContexts = OldForceState;
04075 
04076     // Restore the original GDrawContext
04077     if (GRenderRegion::SetTempDrawContext(pOldGD) != &TempContext)
04078     {
04079         TRACEUSER( "Gerry", _T("Not &TempContext when restoring\n"));
04080     }
04081     pOldGD = NULL;
04082 
04083 //  pHostRegion->StartRender();
04084     
04085 //  TRACEUSER( "Gerry", _T("End of View::RenderBitmapPhase\n"));
04086 
04087     // all worked
04088     return SLOWJOB_SUCCESS;
04089 }
04090 
04091 
04092 /********************************************************************************************
04093 
04094 >   SlowJobResult View::RenderSimpleNodesUnclipped(Node *pNode, RenderRegion *pRender,
04095                              ProgressDisplay& Progress, Node *pLastComplexNode = NULL)
04096 
04097     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
04098     Created:    08/03/2004
04099     Inputs:     pNode - the node to start rendering at.
04100                 pRender - the render region to render the nodes into.
04101                 Progress - usual progress info object.
04102                 pLastComplexNode - optional: if not NULL, then stop rendering when this
04103                                              node is reached, otherwise render to completion.
04104     Returns:    SLOWJOB_SUCCESS if rendered ok;
04105                 SLOWJOB_FAILURE if an error occured;
04106                 SLOWJOB_USERABORT if the user intervened - e.g. pressed Escape.
04107     Purpose:    Function to render nodes 'normally' during 3-pass rendering.  This copes
04108                 with stopping at the specified last complex node, and with only printing
04109                 selected objects if the user has requested it.
04110     SeeAlso:    ProgressInfo; View::RenderSimpleView
04111 
04112 ********************************************************************************************/
04113 
04114 SlowJobResult View::RenderSimpleNodesUnclipped(Node *pNode, RenderRegion *pRender,
04115                              ProgressDisplay& Progress, Node *pLastComplexNode)
04116 {
04117 #ifndef STANDALONE
04118     // Work out whether we need to render all objects, or just the selected ones.
04119     BOOL RenderAllObjects = TRUE;
04120 //  WEBSTER-ranbirr-13/11/96
04121 #ifndef WEBSTER
04122     if (pRender->IsPrinting())
04123     {
04124         CCPrintInfo *pPrintInfo = CCPrintInfo::GetCurrent();
04125 //      ERROR2IF(pPrintInfo == NULL, SLOWJOB_FAILURE, "No print info while printing!");
04126         if (pPrintInfo != NULL)
04127         {
04128             PrintControl *pPrCtrl = pPrintInfo->GetPrintControl();
04129             RenderAllObjects = (pPrCtrl->GetObjPrintRange() == PRINTRANGEOBJ_ALL);
04130         }
04131     }
04132 #endif //webster
04133     // Render nodes into specified render region
04134     while ((pNode!=NULL) && (pNode != pLastComplexNode))
04135     {
04136         if (pNode->IsRenderable() && (RenderAllObjects || IsPrintableNodeSelected(pNode)) && pNode->NeedsToRender(pRender))
04137         {
04138             // Render the node that we have
04139             pNode->Render(pRender);
04140 
04141             // If progress display is needed, update it if it's time.
04142             if (!Progress.IncProgress())
04143                 return SLOWJOB_USERABORT;
04144         }
04145 
04146         // Find another one to render
04147         pNode = pNode->FindNextForUnclippedInkRender(pRender);
04148     }
04149 
04150     // All ok
04151     return SLOWJOB_SUCCESS;
04152 #else
04153     return SLOWJOB_FAILURE;
04154 #endif
04155 }
04156 
04157 
04158 /********************************************************************************************
04159 
04160 >   PrintControl *View::GetPrintControl()
04161 
04162     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
04163     Created:    05/09/95
04164     Returns:    Pointer to the PrintControl object, or 
04165                 NULL if none found, or the view is not attached to a document.
04166     Purpose:    Simple way of getting the PrintControl object associated with this view's
04167                 document.
04168     Errors:     If no print control found => ERROR2
04169 
04170 ********************************************************************************************/
04171 
04172 PrintControl *View::GetPrintControl()
04173 {
04174 #ifndef STANDALONE
04175 
04176     if (pDoc == NULL)
04177         // This view is not attached to a document (e.g. it's a DialogView)
04178         return NULL;
04179 
04180     // Find print control object for this document, to see if we are
04181     // printing via bitmap, and so if we need to band the output.
04182     PrintComponent *pPrintComponent = (PrintComponent *)
04183         pDoc->GetDocComponent(CC_RUNTIME_CLASS(PrintComponent));
04184     ERROR2IF(pPrintComponent == NULL, NULL, 
04185              "Unable to find PrintComponent object in document.");
04186 
04187     PrintControl *pPrintControl = pPrintComponent->GetPrintControl();
04188     ERROR2IF(pPrintControl == NULL, NULL, 
04189              "Unable to find PrintControl object in document component.");
04190 
04191     return pPrintControl;
04192 
04193 #else
04194     return NULL;
04195 #endif
04196 }
04197 
04198 
04199 
04200 
04201 /********************************************************************************************
04202 
04203 >   void ProgressDisplay::SetUpOptimal(RenderRegion *pRender, ScanningRenderRegion* pScanner)
04204 
04205     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
04206     Created:    28/7/95
04207     Inputs:     pRender - the render region we are rendering to
04208                 pScanner - the Scanning render region that knows about the things we are rendering
04209     Purpose:    This function sets up the Progress display ready to start rendering the nodes.
04210     SeeAlso:    ProgressDisplay::SetUp
04211 
04212 ********************************************************************************************/
04213 
04214 void ProgressDisplay::SetUpOptimal(RenderRegion *pRender, ScanningRenderRegion* pScanner)
04215 {
04216 #ifndef STANDALONE
04217     // Work out if we need a progress display
04218     IsPrinting = pRender->IsPrinting();
04219     if (!IsPrinting && !IS_A(pRender, CamelotEPSRenderRegion))
04220         // No - stop here
04221         return;
04222 
04223     // We need a progress display
04224     DoProgressDisplay = TRUE;
04225     DocRect ClipRect = pRender->GetClipRect();
04226     Spread *pSpread = pRender->GetRenderSpread();
04227 //  Node *pNode = pSpread->FindFirstForClippedInkRender(&ClipRect, pRender);
04228     TotalNodes = 0;
04229 
04230     // Work out whether to count just selected objects, or all of them.
04231     BOOL CountAllObjects = TRUE;
04232 //  WEBSTER-ranbirr-13/11/96
04233 #ifndef WEBSTER
04234     if ((IsPrinting) && (pPrintInfo!=NULL))
04235     {
04236         PrintControl *pPrCtrl = pPrintInfo->GetPrintControl();
04237         CountAllObjects = (pPrCtrl->GetObjPrintRange() == PRINTRANGEOBJ_ALL);
04238     }
04239 #endif //webster
04240 
04241     OptimalPrintRenderCallback MyCallback(pRender->GetRenderView(), pSpread, CountAllObjects, pScanner, FALSE, &TotalNodes, NULL, TRUE);
04242     pRender->RenderTree(pSpread, FALSE, FALSE, &MyCallback);
04243 
04244     TRACE( _T("TotalNodes = %d\n"), TotalNodes);
04245 
04246 //  WEBSTER-ranbirr-13/11/96
04247 #ifndef WEBSTER
04248     // Set up the slider according to the printing flag
04249     if (IsPrinting)
04250     {
04251         if (pPrintInfo != NULL)
04252         {
04253             // actually set the slider
04254             TRACEUSER( "Gerry", _T("Setting Progress slider up to %ld\n"), TotalNodes * ProgressScaleFactor);
04255             pPrintInfo->SetSliderSubRangeMax(TotalNodes * ProgressScaleFactor);
04256             pPrintInfo->SetSliderSubRangePos(0);
04257         }
04258     }
04259     else
04260 #endif //webster
04261     {
04262         // Start progress display (with no initial delay) for Camelot EPS export
04263         String_64 ExportMsg(_R(IDT_EXPORTMSG_CAMEPS));
04264         BeginSlowJob(TotalNodes*ProgressScaleFactor, FALSE, &ExportMsg);
04265     }
04266 
04267     // Provide a progress update for every 1%
04268     ProgressInterval = (TotalNodes * ProgressScaleFactor) / 100;
04269     TRACE( _T("ProgressInterval = %d\n"), ProgressInterval);
04270 #endif
04271 }
04272 
04273 
04274 
04275 /********************************************************************************************
04276 
04277 >   BOOL ProgressDisplay::SetNodesRendered(INT32 NumNodes)
04278 
04279     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
04280     Created:    28/7/95
04281     Inputs:     NumNodes - the number of nodes that have been rendered so far
04282     Returns:    TRUE if all went well, FALSE if we should stop now.
04283     Purpose:    Lets the rendering loop tell the display system when a node has been rendered.
04284                 It can act on this to update the progress display whenever needed.
04285 
04286 ********************************************************************************************/
04287 
04288 BOOL ProgressDisplay::SetNodesRendered(INT32 NumNodes)
04289 {
04290 #ifndef STANDALONE
04291     // If we have advanced a node, then update
04292     if (NumNodes>NumNodesRendered)
04293     {
04294 //      TRACE( _T("SetNodesRendered = %d\n"), NumNodes);
04295         NumNodesRendered = NumNodes;
04296     }
04297 
04298     if (!DoProgressDisplay)
04299         // No progress display needed.
04300         return TRUE;
04301 //  WEBSTER-ranbirr-13/11/96
04302 #ifndef WEBSTER
04303     if (IsPrinting && (pPrintInfo != NULL) && (pPrintInfo->m_bContinuePrinting == FALSE))
04304         // User has cancelled job
04305         return FALSE;
04306 #endif //webster
04307     if ((NumNodesRendered * ProgressScaleFactor) > (LastProgressUpdate + ProgressInterval))
04308     {
04309         // Time to update the progress display.
04310         LastProgressUpdate = NumNodesRendered * ProgressScaleFactor;
04311     //  WEBSTER-ranbirr-13/11/96
04312 #ifndef WEBSTER
04313         if (IsPrinting && pPrintInfo != NULL)
04314         {
04315             // Update slider
04316             pPrintInfo->SetSliderSubRangePos(LastProgressUpdate);
04317 
04318             // Does user want to suspend printing?
04319             if (pPrintInfo->Abort())
04320                 return FALSE;
04321         }
04322         else
04323 #endif //webster
04324             return ContinueSlowJob(LastProgressUpdate);
04325     }
04326 
04327 #endif
04328 
04329     // All ok
04330     return TRUE;
04331 }
04332 

Generated on Sat Nov 10 03:47:20 2007 for Camelot by  doxygen 1.4.4