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