nodebmp.cpp

Go to the documentation of this file.
00001 // $Id: nodebmp.cpp 1771 2007-06-17 20:14:43Z 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 // Node representing a bitmap object.
00100 
00101 /*
00102 */
00103 
00104 #include "camtypes.h"
00105 #include "nodebmp.h"
00106 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00107 //#include "tim.h"
00108 //#include "rndrgn.h"
00109 //#include "doccolor.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00110 //#include "fillattr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00111 #include "lineattr.h"
00112 //#include "progress.h"
00113 #include "cameleps.h"
00114 #include "ai_epsrr.h"
00115 #include "bitmpinf.h"
00116 #include "nodepath.h"
00117 //#include "becomea.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00118 #include "draginfo.h"
00119 //#include "scrcamvw.h"
00120 #include "cliptype.h"
00121 #include "attrmap.h"
00122 #include "spread.h"
00123 #include "zoomops.h"
00124 #include "bitfilt.h"
00125 
00126 #include "colormgr.h"
00127 //#include "attrmgr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00128 //#include "jason.h"
00129 //#include "justin2.h"
00130 //#include "sglfills.h"
00131 //#include "xpehost.h"
00132 #include "grndrgn.h"
00133 //#include "matrix.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00134 #include "nodeliveeffect.h"
00135 
00136 // These are for CheckGreyscaleBitmap
00137 #ifndef WEBSTER
00138 //these should probably be #ifndef EXCLUDE_BFX rather than WEBSTER Martin-17/03/97
00139 //they aren't used any more anyway 10/04/97
00140 //#include "bfxalu.h"
00141 //#include "bitmapfx.h"
00142 #endif //WEBSTER
00143 //#include "resource.h"
00144 //#include "bmplist.h"
00145 #include "bmpcomp.h"
00146 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00147 //#include "will.h"
00148 #include "qualattr.h"
00149 //#include "view.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00150 //#include "will2.h"
00151 //#include "capturemanager.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00152 #include "fthrattr.h"
00153 #include "ophist.h"
00154 #include "objchge.h"
00155 
00156 // headers for the new file format
00157 //#include "camfiltr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00158 #include "cxfnbmp.h"
00159 
00160 // stuff for CMX rubbish
00161 //#include "cmxrendr.h"
00162 //#include "cmxexdc.h"
00163 
00164 // for popup menu
00165 #include "contmenu.h"
00166 //#include "bfxdlg.h"
00167 #include "tracedlg.h"
00168 
00169 //This includes the Hot Link class
00170 #include "userattr.h"
00171 //#include "webattr.h"
00172 #include "camview.h"
00173 
00174 #ifdef PHOTOSHOPPLUGINS
00175 // Only add in if required - general plug-in removal at present
00176 #include "plugmngr.h"   // OPTOKEN_PLUGINS_MENU
00177 #include "plugop.h"     // PlugInsContextMenu 
00178 #endif
00179 
00180 DECLARE_SOURCE("$Revision: 1771 $");
00181 
00182 CC_IMPLEMENT_DYNCREATE(NodeBitmap, NodeRect);
00183 #if !defined(EXCLUDE_FROM_RALPH)
00184 CC_IMPLEMENT_DYNCREATE(OpCreateNodeBitmap, UndoableOperation);
00185 #endif
00186 CC_IMPLEMENT_DYNCREATE(ChangeBitmapPtrAction, Action);
00187 
00188 // Declare smart memory handling in Debug builds
00189 #define new CAM_DEBUG_NEW
00190 
00191 
00192 /********************************************************************************************
00193 
00194 >   NodeBitmap::NodeBitmap(Node* ContextNode,  
00195                            AttachNodeDirection Direction,  
00196                            BOOL Locked, 
00197                            BOOL Mangled,  
00198                            BOOL Marked, 
00199                            BOOL Selected)
00200 
00201     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00202     Created:    30/08/94
00203 
00204     Inputs:     ContextNode: Pointer to a node which this node is to be attached to.     
00205         
00206                 Direction: 
00207             
00208                     Specifies the direction in which the node is to be attached to the 
00209                     ContextNode. The values this variable can take are as follows: 
00210                                   
00211                     PREV      : Attach node as a previous sibling of the context node
00212                     NEXT      : Attach node as a next sibling of the context node
00213                     FIRSTCHILD: Attach node as the first child of the context node
00214                     LASTCHILD : Attach node as a last child of the context node                               
00215                           
00216                 The remaining inputs specify the status of the node: 
00217             
00218                 Locked:     Is node locked ?
00219                 Mangled:    Is node mangled ?
00220                 Marked:     Is node marked ?
00221                 Selected:   Is node selected ?
00222             
00223     Purpose:    This constructor initialises the nodes flags and links it to ContextNode in 
00224                 the direction specified by Direction. All neccesary tree links are updated.         
00225             
00226     Note:       SetUpPath() must be called before the NodeBitmap is in a state in which it 
00227                 can be used.        
00228                 
00229     SeeAlso:    SetUpPath   
00230     
00231     Errors:     An assertion error will occur if ContextNode is NULL
00232 
00233 ********************************************************************************************/
00234 
00235 NodeBitmap::NodeBitmap(Node* ContextNode,  
00236                     AttachNodeDirection Direction,  
00237                     BOOL Locked, 
00238                     BOOL Mangled,  
00239                     BOOL Marked, 
00240                     BOOL Selected    
00241               ):NodeRect(ContextNode, Direction, Locked, Mangled, Marked, Selected )  
00242 {                         
00243     Colour = COLOUR_NONE;
00244     EndColour = COLOUR_NONE;
00245 
00246     ApplyContoneColour = FALSE;
00247 }                        
00248  
00249 
00250 /********************************************************************************************
00251 
00252 >   NodeBitmap::NodeBitmap()
00253 
00254     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00255     Created:    30/08/94
00256     Purpose:    This constructor creates a NodeBitmap linked to no other with all status
00257                 flags false and an uninitialized bounding rectangle.           
00258             
00259                 NB. SetUpPath() must be called before the NodeBitmap is in a state in which 
00260                     it can be used.         
00261                 
00262     SeeAlso:    SetUpPath                                                        
00263 
00264 ********************************************************************************************/
00265 
00266 NodeBitmap::NodeBitmap(): NodeRect()
00267 {
00268     Colour = COLOUR_NONE;
00269     EndColour = COLOUR_NONE;
00270 
00271     ApplyContoneColour = FALSE;
00272 }
00273 
00274 
00275 
00276 /***********************************************************************************************
00277 
00278 >   virtual Node* NodeBitmap::SimpleCopy()
00279 
00280     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
00281     Created:    26/5/93
00282     Returns:    Pointer to a Node
00283     Purpose:    Makes a copy of all the data in the node
00284 
00285 ***********************************************************************************************/
00286 
00287 Node* NodeBitmap::SimpleCopy()
00288 {
00289     // Make a new NodeBitmap and then copy things into it
00290     NodeBitmap* NodeCopy = new NodeBitmap();
00291     if (NodeCopy)
00292         CopyNodeContents(NodeCopy);
00293     
00294     return NodeCopy;
00295 }            
00296 
00297 
00298 /***********************************************************************************************
00299 
00300 >   void NodeBitmap::CopyNodeContents(NodeBitmap* NodeCopy)
00301 
00302     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00303     Created:    26/5/93
00304     Inputs:     NodeCopy - The node to copy
00305     Purpose:    Copies the data in the node by first calling the base class to get it to
00306                 copy its stuff, and then copying its own stuff
00307     Scope:      protected
00308     SeeAlso:    NodeRect::CopyNodeContents
00309 
00310 ***********************************************************************************************/
00311 
00312 void NodeBitmap::CopyNodeContents(NodeBitmap* NodeCopy)
00313 {
00314     NodeRect::CopyNodeContents(NodeCopy);
00315 
00316     // Copy contents specific to derived class here
00317 
00318     // Copy KernelBitmap reference
00319     NodeCopy->BitmapRef = BitmapRef;
00320 
00321     // We need to copy the cached bitmaps into the new node
00322     // But since this cached (option 2) bitmap is only ever used as an intermediate stage
00323     // in producing another cached bitmap, we probably don't need to copy it
00324     //CopyCached(pCopyOfNode, GetPixelWidth(), 2);  // Copy cached bitmaps, options 0, 1 and 2 (original and processed)
00325 }
00326 
00327 
00328 
00329 
00330 /***********************************************************************************************
00331 >   void NodeBitmap::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
00332 
00333     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00334     Created:    18/12/2003
00335     Outputs:    -
00336     Purpose:    Polymorphically copies the contents of this node to another
00337     Errors:     An assertion failure will occur if NodeCopy is NULL
00338     Scope:      protected
00339                                      
00340 ***********************************************************************************************/
00341 
00342 void NodeBitmap::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
00343 {
00344     ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node");
00345     ENSURE(IS_A(pNodeCopy, NodeBitmap), "PolyCopyNodeContents given wrong dest node type");
00346 
00347     if (IS_A(pNodeCopy, NodeBitmap))
00348         CopyNodeContents((NodeBitmap*)pNodeCopy);
00349 }
00350 
00351 
00352 
00353 /********************************************************************************************
00354 
00355 >   virtual String NodeBitmap::Describe(BOOL Plural, BOOL Verbose = TRUE)
00356 
00357     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00358     Created:    25/6/93
00359     Inputs:     Plural: Flag indicating if the string description should be plural or
00360                 singular. 
00361     Returns:    Description of the object                                    
00362     Purpose:    To return a description of the NodeBitmap object in either the singular or the 
00363                 plural. This method is called by the DescribeRange method.
00364                 The description will always begin with a lower case letter.   
00365     Errors:     A resource exception will be thrown if a problem occurs when loading the 
00366                 string resource. 
00367 
00368 ********************************************************************************************/
00369               
00370 String NodeBitmap::Describe(BOOL Plural, BOOL Verbose) 
00371 {     
00372 #if !defined(EXCLUDE_FROM_RALPH)
00373     if (Plural)
00374     {
00375         return(String(_R(IDS_BITMAP_DESCRP)));  
00376     }
00377     else
00378     {
00379         if (GetBitmap() == NULL || GetBitmap()->ActualBitmap == NULL)
00380             return(String(_R(IDS_BITMAP_DESCRS))); 
00381 
00382         // If we have a bitmap, then include it's name and actual dpi
00383         // in the desciption
00384 
00385         String_256 BmpName = GetBitmap()->ActualBitmap->GetName();
00386         String_64 TrunkName;
00387         if (BmpName.Length() > 12)
00388         {
00389             BmpName.Left(&TrunkName, 9);
00390             TrunkName += _T("...");
00391         }
00392         else
00393         {
00394             BmpName.Left(&TrunkName, 12);
00395         }
00396 
00397         String_256 DpiText;
00398         UINT32 dpi = GetBitmapDPI();
00399 
00400         if (dpi > 0)
00401         {
00402             String_256 jcf(_R(IDS_NODEBMP_DPI_FORMAT));
00403             camSnprintf(DpiText, 256, jcf, dpi);
00404         }
00405 
00406         String_64 TrunkDpi;
00407         DpiText.Left(&TrunkDpi, 11);
00408 
00409         String_256 Desc(_R(IDS_BITMAP_DESCRS));
00410         String_64 TrunkDesc;
00411         Desc.Left(&TrunkDesc, 6);
00412 
00413         if (Verbose)
00414         {
00415             String_32 ret = TrunkDesc;
00416             ret += TEXT(" '");
00417             ret += TrunkName;
00418             ret += TEXT("'");
00419             ret += TrunkDpi;
00420             return ret;
00421 //          return(String(TrunkDesc+TEXT(" '")+TrunkName+TEXT("'")+TrunkDpi));
00422         }
00423         else
00424         {
00425             String_32 ret = TrunkDesc;
00426             ret += TEXT(" ");
00427             ret += TrunkName;
00428             return ret;
00429 //          return(String(TrunkDesc+TEXT(" ")+TrunkName));
00430         }
00431     }
00432 #else
00433     return(String(_R(IDS_BITMAP_DESCRP)));  
00434 #endif
00435 }
00436 
00437 /********************************************************************************************
00438 
00439 >   UINT32 NodeBitmap::GetBitmapDPI()
00440 
00441     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
00442     Created:    16/2/95
00443     Returns:    The actual DPI of the bitmap.
00444     Purpose:    Caculates the actual DPI of the bitmap on the page.
00445 
00446 ********************************************************************************************/
00447 
00448 UINT32 NodeBitmap::GetBitmapDPI()
00449 {
00450     UINT32 Dpi = 0;
00451 
00452     if (GetBitmap() == NULL)
00453         return 0;
00454 
00455     // Do we have a valid bitmap ?
00456     OILBitmap *OilBM = GetBitmap()->ActualBitmap;
00457 
00458     if (OilBM != NULL)
00459     {
00460         BitmapInfo Info;
00461         OilBM->GetInfo(&Info);
00462 
00463         // Get the Width of the Bitmap in Pixels
00464         INT32 PixWidth  = Info.PixelWidth;
00465         INT32 PixHeight = Info.PixelHeight;
00466 
00467         // Get the Width of the Bitmap in Millipoints
00468         INT32 Width  = INT32(Parallel[0].Distance(Parallel[1]));
00469         INT32 Height = INT32(Parallel[1].Distance(Parallel[2]));
00470 
00471         // Use doubles so that we can round up as well as down. This improves
00472         // the dpi calculated.
00473         double HDpi = 0;
00474         double VDpi = 0;
00475 
00476         if (Width > 0)
00477             HDpi = ((double)PixWidth * 72000.0)/(double)Width;
00478 
00479         if (Height > 0)
00480             VDpi = ((double)PixHeight * 72000.0)/(double)Height;
00481 
00482         // Use the smaller of the two dpi values
00483         Dpi = (UINT32)(HDpi + 0.5);
00484         if (VDpi < Dpi)
00485             Dpi = (UINT32)(VDpi + 0.5);
00486     }
00487 
00488     return Dpi;
00489 }
00490 
00491 /********************************************************************************************
00492 
00493 >   virtual UINT32 NodeBitmap::GetNodeSize() const
00494 
00495     Author:     Simon_Maneggio (Xara Group Ltd) <camelotdev@xara.com>
00496     Created:    6/10/93
00497     Returns:    The size of the node in bytes 
00498     Purpose:    For finding the size of the node 
00499     SeeAlso:    Node::GetSubtreeSize
00500 
00501 ********************************************************************************************/
00502 
00503 UINT32 NodeBitmap::GetNodeSize() const 
00504 {     
00505     return (sizeof(NodeBitmap)); 
00506 }  
00507 
00508 
00509 
00510 /********************************************************************************************
00511 
00512 >   virtual BOOL NodeBitmap::OnNodePopUp(Spread* pSpread, DocCoord PointerPos, ContextMenu* pMenu)
00513 
00514     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00515     Created:    20/08/96
00516     Inputs:     pSpread     The spread in which things are happening
00517                 PointerPos  The Location of the mouse pointer at the time of the click
00518                 pMenu       The menu to which items should be added
00519     Returns:    BOOL - TRUE if the node claims the click as its own and FALSE if it is
00520                 not interested in the click
00521     Purpose:    Allows the Node to respond to pop up menu clicks on it (rather than its blobs).
00522 
00523 ********************************************************************************************/
00524 BOOL NodeBitmap::OnNodePopUp(Spread* pSpread, DocCoord PointerPos, ContextMenu* pMenu)
00525 {
00526 #if !defined(EXCLUDE_FROM_RALPH)
00527 
00528     BOOL ok = TRUE;
00529 
00530 PORTNOTE("liveeffects", "XPE menu option disabled")
00531 #ifndef EXCLUDE_FROM_XARALX
00532     ok = ok && pMenu->BuildCommand(OPTOKEN_XPE_EDIT, FALSE);
00533 #endif
00534 
00535     //ok = ok && pMenu->BuildCommand(OPTOKEN_BFXDLG, FALSE);
00536 
00537 #ifdef PHOTOSHOPPLUGINS
00538 // Only add in if required - general plug-in removal at present
00539     // Add a sub-menu tacked onto this which is the main PhotoShopContextMenu
00540     // we have real OpTokens and so can do it properly
00541     // Well, in fact we will ask the PhotoShopContextMenu to do it for us!
00542 //  ok = ok && pMenu->BuildCommand(OPTOKEN_PLUGINS_UNDO_MENU, FALSE);
00543 //  MenuItem* pMainRoot = pMenu->GetLastItem();
00544     MenuItem* pMainRoot = NULL;
00545     // Add a submenu which is the list of bitmap based plug-ins.
00546     // We have no need for specifying a document and a bitmap as this will be read
00547     // by the undoable op.
00548     // There should not be a separator and we should use the undoable versions
00549     // of the operations (hence FALSE, TRUE).
00550     ok = ok && PlugInsContextMenu::BuildMenu(NULL, NULL, pMenu, pMainRoot, FALSE, TRUE);
00551 #endif  // PHOTOSHOPPLUGINS
00552 
00553     ok = ok && pMenu->BuildCommand(OPTOKEN_TRACEDLG, TRUE);
00554 
00555     return ok;
00556 
00557 #else   // !defined(EXCLUDE_FROM_RALPH)
00558 
00559     return FALSE;
00560 
00561 #endif  // !defined(EXCLUDE_FROM_RALPH)
00562 }
00563 
00564 
00565 
00566 /********************************************************************************************
00567 
00568 >   void NodeBitmap::Render(RenderRegion* pRender)
00569 
00570     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00571     Created:    30/8/94
00572     Inputs:     Pointer to a render region
00573     Purpose:    Will render the bitmap contained within the object to the given render 
00574                 region.
00575 
00576 ********************************************************************************************/
00577 
00578 void NodeBitmap::Render(RenderRegion* pRender)
00579 {
00580     // No need to render if we are going to supply directly to a capture
00581     Capture* pCapture = pRender->GetTopCapture();
00582     if (!(pCapture && pCapture->ConsumeDirectBitmap(this)))
00583     {
00584         // Render the transformed bitmap
00585         pRender->DrawTransformedBitmap(this);
00586     }
00587 }  
00588 
00589 
00590 /********************************************************************************************
00591 
00592 >   void NodeBitmap::PreExportRender(RenderRegion*)
00593 
00594     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00595     Created:    12/10/94
00596     Inputs:     Ignored
00597     Purpose:    Prevent the base class NodeRect::PreExportRender() function from exporting 
00598                 anything to mark this as a rectangle object - because it's not; it's a 
00599                 bitmap object.
00600 
00601 ********************************************************************************************/
00602 
00603 void NodeBitmap::PreExportRender(RenderRegion*)
00604 {
00605     // No action, and we want to stop the base class from exporting any 'rectangly' 
00606     // information that might confuse us.
00607 }
00608 
00609 
00610 /********************************************************************************************
00611 
00612 >   BOOL NodeBitmap::ExportRender(RenderRegion* pRegion)
00613 
00614     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00615     Created:    01/09/94
00616     Inputs:     pRegion - the export render region to export to.
00617     Returns:    TRUE if the bitmap was exported ok;
00618                 FALSE if not.
00619     Purpose:    Export a bitmap object to a file.
00620     Errors:     Usual disk/file errors.
00621     SeeAlso:    Filter::ExportBitmap
00622 
00623 ********************************************************************************************/
00624 
00625 BOOL NodeBitmap::ExportRender(RenderRegion* pRegion) 
00626 {
00627 #ifdef DO_EXPORT
00628     if (pRegion->IsKindOf(CC_RUNTIME_CLASS(CamelotEPSRenderRegion)))
00629     {
00630         // Get valid transparency fill for this object
00631         CamelotEPSRenderRegion *pCamelotRegion = (CamelotEPSRenderRegion *) pRegion;
00632         pCamelotRegion->GetValidPathAttributes();
00633 
00634         // Output bitmap object position and keyword...
00635         EPSExportDC *pDC = (EPSExportDC *) pRegion->GetRenderDC();
00636 
00637         DocCoord *Coords = InkPath.GetCoordArray();
00638 
00639 // Bodge Code
00640 
00641 // So this is some Bodge code to make Bitmaps in moulds, save themselves
00642 // correctly if a Line colour is applied to the Mould.
00643 
00644 // This line colour makes the Bitmap think it has been contoned, so we save out
00645 // a contoned version, which is looks incorrect when re-loaded.
00646 
00647 // To get around this problem, this code checks specifically for the situation,
00648 // and forces the bitmap to be saved as  a non-contoned version.
00649 
00650         BOOL CanSaveAsContoned = TRUE;
00651         BOOL LineColourIsAppliedToMould = FALSE;
00652 
00653         if (GetBitmap() && GetBitmap()->GetBPP() <= 8)
00654         {
00655             // We only need to worry about this for < 8BPP
00656             NodeAttribute* pLineAttr;
00657     
00658             // So we find the applied Stroke Colour ...
00659             if (FindAppliedAttribute(CC_RUNTIME_CLASS(AttrStrokeColour), &pLineAttr))
00660             {
00661                 Node* pParent = pLineAttr->FindParent();
00662                 
00663                 // And if it has been applied to a Mould ...
00664                 if (pParent && IS_A(pParent, NodeMould))
00665                 {
00666                     LineColourIsAppliedToMould = TRUE;
00667 
00668                     // and there is no Flat Colour Applied to the Bitmap,
00669                     // then this flag will be FALSE, stopping the bitmap
00670                     // from being saved as contone.
00671                     CanSaveAsContoned = (GetEndColour() != NULL);
00672                 }
00673             }
00674         }
00675 
00676         if (CanSaveAsContoned && (GetStartColour() || GetEndColour()))
00677         {
00678             // Must be a contone bitmap
00679 
00680             // If either the start or end colour is NULL, we need
00681             // to output a dummy colour, because 'No_Colour' doesn't
00682             // get saved
00683             if (LineColourIsAppliedToMould || GetStartColour() == NULL)
00684             {
00685                 DocColour StartCol;
00686                 AttributeManager::FindDefaultColour(ColourManager::GetCurrentColourList(),
00687                                                     _R(IDS_BLACKNAME), &StartCol);
00688 
00689                 if (*GetEndColour() == StartCol)
00690                 {
00691                     AttributeManager::FindDefaultColour(ColourManager::GetCurrentColourList(),
00692                                                         _R(IDS_WHITENAME), &StartCol);
00693                 }
00694 
00695                 // Output dummy start colour here
00696                 if (StartCol.FindParentIndexedColour() == NULL)
00697                 {
00698                     // Unnamed colour
00699                     PColourCMYK CMYK;
00700                     StartCol.GetCMYKValue(&CMYK);
00701                     pDC->OutputColour(&CMYK);
00702                     pDC->OutputToken(_T("K"));
00703                 }
00704                 else
00705                 {
00706                     // Named colour
00707                     pDC->OutputNamedColour(&StartCol);
00708                     pDC->OutputToken(_T("X"));
00709                 }
00710 
00711                 pDC->OutputNewLine();
00712             }
00713             else if (GetEndColour() == NULL)
00714             {
00715                 DocColour EndCol;
00716                 AttributeManager::FindDefaultColour(ColourManager::GetCurrentColourList(),
00717                                                     _R(IDS_WHITENAME), &EndCol);
00718 
00719                 if (*GetStartColour() == EndCol)
00720                 {
00721                     AttributeManager::FindDefaultColour(ColourManager::GetCurrentColourList(),
00722                                                         _R(IDS_BLACKNAME), &EndCol);
00723                 }
00724 
00725                 // Output dummy end colour here
00726                 if (EndCol.FindParentIndexedColour() == NULL)
00727                 {
00728                     // Unnamed colour
00729                     PColourCMYK CMYK;
00730                     EndCol.GetCMYKValue(&CMYK);
00731                     pDC->OutputColour(&CMYK);
00732                     pDC->OutputToken(_T("k"));
00733                 }
00734                 else
00735                 {
00736                     // Named colour
00737                     pDC->OutputNamedColour(&EndCol);
00738                     pDC->OutputToken(_T("x"));
00739                 }
00740 
00741                 pDC->OutputNewLine();
00742             }
00743         
00744             // Co-ords first,
00745             for (INT32 i = 0; i <= 3; i++)
00746                 pDC->OutputCoord(Coords[i]);
00747 
00748             // ...then the bitmap object token.
00749             pDC->OutputToken(_T("cbm"));
00750             pDC->OutputNewLine();
00751 
00752             // ...and then the bitmap data itself.
00753             pDC->GetParentFilter()->ExportBitmap(*GetBitmap());
00754         }
00755         else
00756         {
00757             // It's not a contone bitmap.
00758             // Oh bum. We've made a bit of a bo-bo with these.
00759             // Since we don't save 'no-colour' we don't know that
00760             // the bitmap has no-colour when re-loaded, and so it
00761             // uses the 'current' fill colour, so sometimes the bitmaps
00762             // come out coloured, when they shouldn't be.
00763 
00764             // Solution .... We'll save this bitmap as a bitmap fill
00765             // (which already has a non-contone format), and save out
00766             // some extra stuff to tell the import routines that it's
00767             // not a bitmap fill, but really a bitmap object.
00768             // This means it will look correct in the Viewer (they'll
00769             // be loaded as bitmap filled paths), but will appear as 
00770             // bitmaps when loaded into the main program.
00771 
00772             // So first we'll output a new eps object (which will be Ignored by
00773             // the viewer), telling the main program that the following
00774             // object is really a bitmap object
00775                         
00776             pDC->OutputValue((INT32) EOTAG_BITMAPFLAGS);
00777             pDC->OutputToken(_T("cso"));    // Start of new object type
00778 
00779             pDC->OutputToken(_T("cbot"));   // Flag the next bitmap fill as an object
00780 
00781             pDC->OutputToken(_T("ceo"));    // End of new object type
00782             pDC->OutputNewLine();
00783 
00784             // Now output the Bitmap fill
00785             pDC->OutputCoord(Coords[3]);
00786             pDC->OutputCoord(Coords[2]);
00787             pDC->OutputCoord(Coords[0]);
00788 
00789             pDC->OutputValue((INT32) CAMEPS_FILL_BITMAP);
00790             pDC->OutputToken(_T("cax"));
00791             pDC->OutputNewLine();
00792 
00793             // ...and then the bitmap data itself.
00794             pDC->GetParentFilter()->ExportBitmap(*GetBitmap());
00795 
00796             // Now output a filled path for the Viewer to render
00797             // This will be skipped over by the new import code
00798             pDC->OutputCoord(Coords[0]);
00799             pDC->OutputToken(_T("m"));
00800             pDC->OutputNewLine();
00801             pDC->OutputCoord(Coords[1]);
00802             pDC->OutputToken(_T("l"));
00803             pDC->OutputNewLine();
00804             pDC->OutputCoord(Coords[2]);
00805             pDC->OutputToken(_T("l"));
00806             pDC->OutputNewLine();
00807             pDC->OutputCoord(Coords[3]);
00808             pDC->OutputToken(_T("l"));
00809             pDC->OutputNewLine();
00810             pDC->OutputCoord(Coords[0]);
00811             pDC->OutputToken(_T("l"));
00812             pDC->OutputNewLine();
00813             pDC->OutputToken(_T("F"));  // Filled path
00814             pDC->OutputNewLine();
00815         }
00816         
00817         // Now force the Fill Colour, Line Colour, and Line Width
00818         // attribute to output themselves again, 'cus old versions
00819         // (including the Viewer) will corrupt these attributes for 
00820         // any subsequent objects
00821 
00822         // Get rid of the current copies of the last output attrs
00823         delete pCamelotRegion->LastOutputAttrs[ATTR_FILLGEOMETRY].pAttr;
00824         delete pCamelotRegion->LastOutputAttrs[ATTR_STROKECOLOUR].pAttr;
00825         delete pCamelotRegion->LastOutputAttrs[ATTR_LINEWIDTH].pAttr;
00826         
00827         // NULL the pointers
00828         pCamelotRegion->LastOutputAttrs[ATTR_FILLGEOMETRY].pAttr = NULL;
00829         pCamelotRegion->LastOutputAttrs[ATTR_STROKECOLOUR].pAttr = NULL;
00830         pCamelotRegion->LastOutputAttrs[ATTR_LINEWIDTH].pAttr = NULL;
00831 
00832         // and clear the Temp flags so we don't try and delete them on exit
00833         pCamelotRegion->LastOutputAttrs[ATTR_FILLGEOMETRY].Temp = FALSE;
00834         pCamelotRegion->LastOutputAttrs[ATTR_STROKECOLOUR].Temp = FALSE;
00835         pCamelotRegion->LastOutputAttrs[ATTR_LINEWIDTH].Temp = FALSE;
00836 
00837         // Re-output the attributes we've just reset
00838         pCamelotRegion->GetValidPathAttributes();
00839 
00840         // Tell caller we rendered ourselves ok
00841         return TRUE;
00842     }
00843 PORTNOTE("cmx", "Disabled CMXRenderRegion")
00844 #ifndef EXCLUDE_FROM_XARALX
00845     else if (pRegion->IsKindOf(CC_RUNTIME_CLASS(CMXRenderRegion)))
00846     {
00847         // mark start of a group...
00848         CMXExportDC *pDC = (CMXExportDC *)pRegion->GetRenderDC();
00849         ERROR2IF(pDC == NULL, FALSE, "no dc in CMXRenderRegion");
00850         KernelBitmap *pBittyThingy = BitmapRef.GetBitmap();
00851         ERROR2IF(pBittyThingy == NULL, FALSE, "no bitmap in the node");
00852 
00853         pDC->WriteBitmap ( pBittyThingy, ( DocCoord * ) ( &Parallel ),
00854                            CMXExportDC::CMXBITMAPCOLOURSOURCE_LINEANDFILL );
00855 
00856         return TRUE;
00857     }
00858 #endif
00859     else if ( pRegion->IsKindOf ( CC_RUNTIME_CLASS ( AIEPSRenderRegion ) ) )
00860     {
00861         // Grab a pointer to the AIEPS_RenderRegion.
00862         AIEPSRenderRegion   *pAIEPSRR   = static_cast<AIEPSRenderRegion*> ( pRegion );
00863 
00864         // Write the bitmap using the render region's custom code.
00865         return pAIEPSRR->ExportBitmap ( this );
00866     }
00867 
00868 #endif
00869     // Render this node in the normal way
00870     return FALSE;
00871 }
00872 
00873 
00874 /********************************************************************************************
00875 
00876 >   INT32 NodeBitmap::GetSizeOfExport(Filter *pFilter)
00877 
00878     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00879     Created:    27/01/95
00880     Inputs:     pFilter - the filter that will be used to export this node.
00881     Returns:    The number of 'nodes' this bitmap is equivalent to (in size).
00882     Purpose:    Determine how many 'nodes' this bitmap is equivalent to.  We use the
00883                 rough approximation that each scanline taks the same amount of space as
00884                 a typical node.  This gives us enough granularity for a reasonably
00885                 accurate and smooth progress display update.
00886     SeeAlso:    -
00887 
00888 ********************************************************************************************/
00889 
00890 INT32 NodeBitmap::GetSizeOfExport(Filter *pFilter)
00891 {
00892 #ifdef DO_EXPORT
00893     // Are we going to save the bitmap out as part of this object?
00894     if (pFilter->GetBitmapSupportLevel() != SimpleBitmapSupport)
00895         // No - just one node
00896         return 1;
00897 
00898     // Find out how many scanlines there are, and return as the result.
00899     KernelBitmap *pBitmap = GetBitmap();
00900     BitmapInfo Info;
00901     if (!pBitmap->ActualBitmap->GetInfo(&Info))
00902         // something has gone wrong!
00903         return 1;
00904 
00905     // Return number of scanlines.
00906     return Info.PixelHeight;
00907 #else
00908     return 0;
00909 #endif
00910 }
00911 
00912 /********************************************************************************************
00913 
00914 >   BOOL NodeBitmap::RequiresAttrib(NodeAttribute* pAttrib, 
00915                                     BOOL Search = FALSE)
00916 
00917     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
00918     Created:    14/4/95
00919     Inputs:     pAttrib - specifies the attribute being enquired about.
00920                 Search - See NodeRenderableInk::RequiresAttrib (Has no effect in this fn) 
00921     Returns:    TRUE => object supports this kind of attribute.
00922                 FALSE => object does not support this kind of attribute, and so it
00923                          should not be applied.
00924     Purpose:    Determine which attributes a bitmap object supports a particular type of
00925                 attribute.   A bitmap only supports transparent fill geometries, 
00926                 mappings, and effects - all other attributes are rejected.
00927     SeeAlso:    NodeRenderableInk::RequiresAttrib
00928 
00929 ********************************************************************************************/
00930 
00931 BOOL NodeBitmap::RequiresAttrib(NodeAttribute* pAttrib, BOOL Search /*= FALSE*/)
00932 {
00933     // Sanity checks
00934     ERROR2IF(pAttrib == NULL, FALSE, "Pointer is null in NodeBitmap::RequiresAttrib");
00935 
00936     if ((pAttrib->IS_KIND_OF(AttrColourChange) ||
00937          pAttrib->IS_KIND_OF(AttrStrokeColourChange)))
00938     {
00939         // Someone's trying to apply a contone colour
00940         // Remember this, so we can do a conversion in the 
00941         // AllowOp routine.
00942         ApplyContoneColour = TRUE;
00943 
00944         // Just say yes
00945         return TRUE;
00946     }
00947 
00948     ApplyContoneColour = FALSE;
00949 
00950     // Is it one we want?
00951     return ((pAttrib->IsAColourFill() && pAttrib->IsAFlatFill()) ||
00952              pAttrib->IsAStrokeColour() ||
00953              pAttrib->IsATranspFill() ||
00954              pAttrib->IS_KIND_OF(AttrValueChange) ||
00955              pAttrib->IS_KIND_OF(AttrColourDrop) ||
00956              pAttrib->IS_KIND_OF(AttrTranspFillMapping) ||
00957              pAttrib->IS_KIND_OF(AttrFillEffect) ||
00958              pAttrib->IS_KIND_OF(AttrFillMapping) ||
00959 PORTNOTE("other","Removed AttrWebAddress")
00960 #ifndef EXCLUDE_FROM_XARALX
00961              pAttrib->IS_KIND_OF(AttrWebAddress) ||             //Added by Graham 1/9/96, so bitmaps can have HotLinks
00962 #endif
00963              pAttrib->IS_KIND_OF(AttrUser)
00964             );
00965 }
00966 
00967 /********************************************************************************************
00968 
00969 >   BOOL NodeBitmap::ApplyDefaultBitmapAttrs(UndoableOperation* pOp,
00970                                              AttrBitmapTranspFill* pTranspBitmap = NULL)
00971 
00972     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
00973     Created:    19/4/95
00974     Inputs:     pOp - the undoable operation in which this Node has been created.
00975                 pTranspBitmap - optional bitmap to apply as transparency. (Default = NULL)
00976     Returns:    TRUE => Default attribute where applied ok.
00977                 FALSE => Apply failed.
00978     Purpose:    Apply the default attributes that a NodeBitmap needs.
00979                 This is specific to Bitmap Nodes, which need the Start and End colours
00980                 to be NONE initially, and also need to ensure the line width is 0.
00981                 There is now an optional pointer to a transparent bitmap fill to be applied
00982                 over the current bitmap node. This is used by the transparent GIF import code.
00983                 
00984 
00985 ********************************************************************************************/
00986 
00987 /* Note by Will 12/1/96
00988 
00989     Removed Line transparency attr (AttrStrokeTransp), because this is no longer needed,
00990     and caused a bug where outlines disappeared when transparency is turned on (eg. after 
00991     slicing a bitmap and applying a line colour). It is no longer required because the 
00992     rendering code now looks at the line colour, rather than relying on the Line
00993     transparency attr being present.
00994 
00995 */
00996 
00997 BOOL NodeBitmap::ApplyDefaultBitmapAttrs(UndoableOperation* pOp,
00998                                          AttrBitmapTranspFill* pTranspBitmap)
00999 {
01000     if (pTranspBitmap != NULL)
01001     {
01002         pTranspBitmap->AttachNode(this, FIRSTCHILD);
01003 
01004         // Apply it as a single tiled fill. Otherwise in the GIF transparency case
01005         // the repeating can give ghost pixels along the edges.
01006         AttrTranspFillMappingLinear *pNoRepeatAttr = new AttrTranspFillMappingLinear;
01007         if (pNoRepeatAttr == NULL)
01008             return FALSE;
01009 
01010         pNoRepeatAttr->Value.Repeat = 1;
01011 
01012         pNoRepeatAttr->AttachNode(this, FIRSTCHILD);
01013     }
01014 
01015     Node* pLineColAttr = new AttrStrokeColour();
01016     if (pLineColAttr == NULL)
01017         return FALSE;
01018 
01019 /*
01020     Node* pLineTranspAttr = new AttrStrokeTransp();
01021     if (pLineTranspAttr == NULL)
01022     {
01023         delete pLineColAttr;
01024         return FALSE;
01025     }
01026  */
01027 
01028     Node* pFillColAttr = new AttrFlatColourFill();
01029     if (pFillColAttr == NULL)
01030     {
01031         delete pLineColAttr;
01032 //      delete pLineTranspAttr;
01033         return FALSE;
01034     }
01035 
01036     Node* pLineWidthAttr = new AttrLineWidth();
01037     if (pFillColAttr == NULL)
01038     {
01039         delete pLineColAttr;
01040 //      delete pLineTranspAttr;
01041         delete pFillColAttr;
01042         return FALSE;
01043     }
01044 
01045     DocColour           colorNull(COLOUR_NONE);
01046     ((AttrFillGeometry*)pLineColAttr)->SetStartColour( &colorNull );
01047     ((AttrFillGeometry*)pFillColAttr)->SetStartColour( &colorNull );
01048     ((AttrLineWidth*)pLineWidthAttr)->Value.LineWidth = 0;
01049 
01050 //  UINT32 LineTransp = 255;
01051 //  ((AttrFillGeometry*)pLineTranspAttr)->SetStartTransp(&LineTransp);
01052 //  ((AttrFillGeometry*)pLineTranspAttr)->SetTranspType(1);
01053 
01054     pLineColAttr->AttachNode(this, FIRSTCHILD);
01055 //  pLineTranspAttr->AttachNode(this, FIRSTCHILD);
01056     pFillColAttr->AttachNode(this, FIRSTCHILD);
01057     pLineWidthAttr->AttachNode(this, FIRSTCHILD);
01058 
01059     return TRUE;
01060 }
01061 
01062 /********************************************************************************************
01063 
01064 >   virtual BOOL NodeBitmap::CanBecomeA(BecomeA* pBecomeA)
01065 
01066     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01067     Created:    13/1/95
01068     Inputs:     pClass: The class of object
01069                 pNumObjects = ptr to place number of objects of type pClass that will be created (Note: can be NULL).
01070                               *pNumObects in undefined on entry
01071     Returns:    TRUE if the node, or any of its children can transmogrify themselves to become 
01072                 an InkClass object
01073     Purpose:    This function is used by the convert to shapes operation. It determines if 
01074                 the node or any of its children can convert themselves into an InkClass object.
01075                 In the case of a node bitmap we must stop it from it having the make shapes
01076                 applied as otherwise we will loose the bitmap from view.
01077                 NodeSimpleShape overrides the baseclass function to return True.
01078 
01079                 The number you put into pNumObjects (if it's not NULL) should exactly equal the total number
01080                 of pClass objects you create.  It should NOT contain any additional objects you may produce
01081                 such as group objects for containing the pClass object, or attributes.
01082 
01083                 Also, the entry value of *pNumObjects cannot be assumed to be 0.
01084 
01085 ********************************************************************************************/
01086 
01087 BOOL NodeBitmap::CanBecomeA(BecomeA* pBecomeA)
01088 {
01089     // The NodeBitmap can become a NodePath (with a bitmap fill)
01090     if (pBecomeA->BAPath())
01091     {
01092         pBecomeA->AddCount(1);
01093         return TRUE;
01094     }
01095 
01096     return FALSE;
01097 }
01098 
01099 /********************************************************************************************
01100 
01101 >   virtual BOOL NodeBitmap::DoBecomeA(CCRuntimeClass* InkClass, UndoableOperation* pOp) 
01102 
01103     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
01104     Created:    16/2/95
01105     Inputs:     pBecomeA =  ptr to a class that contains all the info needed to become a new
01106                             type of node.
01107     Outputs:    -
01108     Returns:    TRUE if the object has been transformed, FALSE if we run out of memory
01109 
01110     Purpose:    Transforms the object into another type of object. 
01111                 Note: changed 7/10/94 by MarkN to take the pBecomeA param, so that more data
01112                 could be passed to these functions in the future without causing massive
01113                 rebuilds due to the editing of node.h
01114     SeeAlso:    NodeSimpleShape::CanBecomeA
01115 
01116 ********************************************************************************************/
01117 
01118 BOOL NodeBitmap::DoBecomeA(BecomeA* pBecomeA)
01119 {
01120     // Check for a NULL entry param
01121     ERROR2IF_PF(pBecomeA == NULL,FALSE,("pBecomeA is NULL"));
01122 
01123     // This lump checks that the Reason is one that we understand
01124     // It also makes sure that we don't have a NULL UndoOp ptr
01125     BOOL ValidReason = (pBecomeA->GetReason() == BECOMEA_REPLACE || pBecomeA->GetReason() == BECOMEA_PASSBACK);
01126     ERROR2IF_PF(!ValidReason,FALSE,("Unkown BecomeA reason %d",pBecomeA->GetReason()));
01127 
01128     // pBecomeA->Reason is one that we understand.
01129 
01130     UndoableOperation* pUndoOp = pBecomeA->GetUndoOp();
01131     BOOL        Success = TRUE;         // Our success flag (Important that this defaults to TRUE)
01132     NodePath*   pNewNodePath = NULL;    // Ptr to a new NodePath, if we get to make one.
01133 
01134     if (pBecomeA->BAPath())
01135     {
01136         // We need to create a new NodePath, no matter what the reason.
01137         
01138         // Allocate a new NodePath node
01139         ALLOC_WITH_FAIL(pNewNodePath, (new NodePath), pBecomeA->GetUndoOp()); 
01140         Success = (pNewNodePath != NULL);
01141 
01142         // Initialise the path
01143         if (Success) CALL_WITH_FAIL(pNewNodePath->InkPath.Initialise(InkPath.GetNumCoords(),12), pBecomeA->GetUndoOp(), Success);
01144         if (Success) CALL_WITH_FAIL(pNewNodePath->InkPath.CopyPathDataFrom(&InkPath), pBecomeA->GetUndoOp(), Success);
01145         
01146         if (Success) pNewNodePath->InkPath.IsFilled = TRUE;
01147 
01148         // If Success is TRUE, then we now have a new NodePath object that contains this shape's path
01149 
01150         if (Success)
01151         {
01152             // Remember the contone colours before we go and hide the applied attributes
01153             DocColour* ContoneStart = GetStartColour();
01154             DocColour* ContoneEnd   = GetEndColour();
01155         
01156             switch (pBecomeA->GetReason())
01157             {
01158                 case BECOMEA_REPLACE :
01159                 {
01160                     // It's a BECOMEA_REPLACE, so replace this node with the new NodePath in an undoable way
01161 
01162                     // Can't do it in an undoable way without an Undo Op
01163 //                  ERROR2IF_PF(pBecomeA->GetUndoOp() == NULL,FALSE,("GetUndoOp() returned NULL"));
01164 
01165                     // The NodeBitmap uses the Fill and line colours to set it's
01166                     // contone colours.
01167                     // But the bitmap fill doesn't need them, so we will Hide
01168                     // any of these attributes that we find applied
01169                     Node* pChild = FindFirstChild();
01170                     while (pChild != NULL)
01171                     {
01172                         Node* pThisChild = pChild;
01173                         pChild = pChild->FindNext();    // Find next before we hide this child
01174                                                 
01175                         if (pThisChild->IsAnAttribute())
01176                         {
01177                             NodeAttribute* pAttr = (NodeAttribute*)pThisChild;
01178 
01179                             if (pAttr->IsAColourFill() ||
01180                                 pAttr->IsAStrokeColour() )
01181                             {
01182                                 if (pUndoOp)
01183                                 {
01184                                     // Hide and Fill or Line colour attributes
01185                                     NodeHidden* pNodeHidden; 
01186                                     Success = pBecomeA->GetUndoOp()->DoHideNode(pAttr, TRUE, &pNodeHidden);
01187                                 }
01188                                 else
01189                                 {
01190                                     pAttr->CascadeDelete();
01191                                     delete pAttr;
01192                                 }
01193                             }
01194                         }
01195                     }
01196 
01197                     // Now make a Bitmap Fill that is equivalent to this NodeBitmap
01198                     AttrFillGeometry* pBitmapFill;
01199                     ALLOC_WITH_FAIL(pBitmapFill , new AttrBitmapColourFill(), pBecomeA->GetUndoOp());
01200                     
01201                     if (pBitmapFill)
01202                     {
01203                         pBitmapFill->AttachBitmap(GetBitmap());
01204 
01205                         // Set any contone colours that we have
01206                         pBitmapFill->SetStartColour(ContoneStart);
01207                         pBitmapFill->SetEndColour(ContoneEnd);
01208 
01209                         // Set the control points from the NodeBitmap Parallelogram
01210                         pBitmapFill->SetStartPoint(&Parallel[3]);
01211                         pBitmapFill->SetEndPoint(&Parallel[2]);
01212                         pBitmapFill->SetEndPoint2(&Parallel[0]);
01213                         
01214                         pBitmapFill->AttachNode(this, FIRSTCHILD);
01215 
01216                         if (pUndoOp)
01217                         {
01218                             // Create a hide node action to hide the node when we undo 
01219                             HideNodeAction* UndoHideNodeAction;     
01220                             Success = (HideNodeAction::Init(pBecomeA->GetUndoOp(),
01221                                                      pBecomeA->GetUndoOp()->GetUndoActionList(),
01222                                                      pBitmapFill, 
01223                                                      TRUE,       // Include subtree size 
01224                                                      ( Action**)(&UndoHideNodeAction))
01225                                                      != AC_FAIL);
01226                         }
01227                     }
01228 
01229                     // We also need to make sure it has no line colour
01230                     AttrFillGeometry* pStrokeColour;
01231                     ALLOC_WITH_FAIL(pStrokeColour , new AttrStrokeColour(), pBecomeA->GetUndoOp());
01232                     
01233                     if (pStrokeColour)
01234                     {
01235                         // Ensure the line colour is set to NONE
01236                         DocColour NoCol = COLOUR_NONE;
01237                         pStrokeColour->SetStartColour(&NoCol);
01238                         
01239                         pStrokeColour->AttachNode(this, FIRSTCHILD);
01240 
01241                         if (pUndoOp)
01242                         {
01243                             // Create a hide node action to hide the node when we undo 
01244                             HideNodeAction* UndoHideNodeAction;     
01245                             Success = (HideNodeAction::Init(pBecomeA->GetUndoOp(),
01246                                                      pBecomeA->GetUndoOp()->GetUndoActionList(),
01247                                                      pStrokeColour, 
01248                                                      TRUE,       // Include subtree size 
01249                                                      ( Action**)(&UndoHideNodeAction))
01250                                                      != AC_FAIL);
01251                         }
01252                     }
01253 
01254                     // Copy the node's attributes
01255                     CALL_WITH_FAIL(CopyChildrenTo(pNewNodePath), pBecomeA->GetUndoOp(), Success); 
01256 
01257                     // Insert the new NodePath into the tree, next to this node
01258                     pNewNodePath->AttachNode(this,NEXT);
01259 
01260                     if (Success)
01261                     {
01262                         // Set the bounds  
01263                         pNewNodePath->InvalidateBoundingRect();
01264                         pNewNodePath->SetSelected(IsSelected());
01265 
01266                         if (pUndoOp)
01267                         {
01268                             // Create a hide node action to hide the node when we undo 
01269                             HideNodeAction* UndoHideNodeAction;     
01270                             Success = (HideNodeAction::Init(pBecomeA->GetUndoOp(),
01271                                                      pBecomeA->GetUndoOp()->GetUndoActionList(),
01272                                                      pNewNodePath, 
01273                                                      TRUE,       // Include subtree size 
01274                                                      ( Action**)(&UndoHideNodeAction))
01275                                                      != AC_FAIL);
01276                         }
01277                     }
01278 
01279                     if (Success)
01280                     {
01281                         CCAttrMap AttrMap;
01282                         CCAttrMap* pAttrMap = NULL;
01283                         BOOL bFoundAttrs = pNewNodePath->FindAppliedAttributes(&AttrMap);
01284                         if (bFoundAttrs)
01285                             pAttrMap = AttrMap.Copy();
01286                         pBecomeA->PassBack(pNewNodePath, this, pAttrMap);
01287                     }
01288 
01289                     // Now hide this NodeBitmap
01290                     if (pUndoOp)
01291                     {
01292                         NodeHidden* pNodeHidden; 
01293                         Success = pBecomeA->GetUndoOp()->DoHideNode(this, TRUE, &pNodeHidden);
01294                     }
01295                     else
01296                     {
01297                         CascadeDelete();
01298                         delete this;        // Scary!
01299                     }
01300                 }
01301                 break;
01302 
01303                 case BECOMEA_PASSBACK :
01304                 {
01305                     // First find all attributes applied to this node...
01306                     // 30 is a default value - this will grow if it needs more space
01307                     CCAttrMap* pAttribMap = new CCAttrMap(30);
01308                     CCAttrMap* pCopyOfAttrMap = NULL;
01309 
01310                     // Now find any attributes that are applied to this node.
01311                     /*BOOL FoundAttrs =*/ FindAppliedAttributes(pAttribMap);
01312 
01313 //                  size_t AttrCount = FoundAttrs ? pAttribMap->GetCount() : 30;
01314 
01315                     // Now make a copy of the applied attributes map
01316                     pCopyOfAttrMap = pAttribMap->Copy ();//new CCAttrMap(AttrCount);
01317                     if (pCopyOfAttrMap != NULL)
01318                     {           
01319                         // We've made a copy of the Attr map now, so we don't need
01320                         // the old one anymore
01321                         delete pAttribMap;
01322                      
01323                         // Replace the Fill and Line Colour attributes
01324                         // in the Attr Map copy
01325 
01326                         AttrFillGeometry* pBitmapFill = new AttrBitmapColourFill();
01327                         if (pBitmapFill)
01328                         {
01329                             // Make a Bitmap Fill that is equivalent to this
01330                             // node bitmap
01331                             pBitmapFill->AttachBitmap(GetBitmap());
01332 
01333                             // Set any contone colours that we have
01334                             pBitmapFill->SetStartColour(ContoneStart);
01335                             pBitmapFill->SetEndColour(ContoneEnd);
01336 
01337                             // Set the control points from the NodeBitmap Parallelogram
01338                             pBitmapFill->SetStartPoint(&Parallel[3]);
01339                             pBitmapFill->SetEndPoint(&Parallel[2]);
01340                             pBitmapFill->SetEndPoint2(&Parallel[0]);
01341 
01342                             void* pOldFill;
01343                             if( pCopyOfAttrMap->Lookup( CC_RUNTIME_CLASS(AttrFillGeometry), pOldFill ) )
01344                             {
01345                                 // We need to Remove and Delete the existing Fill Attr
01346                                 pCopyOfAttrMap->RemoveKey( CC_RUNTIME_CLASS(AttrFillGeometry) );
01347                                 delete (AttrFillGeometry*)pOldFill;
01348                             }
01349 
01350                             // Add the Bitmap fill into the Attr Map
01351                             pCopyOfAttrMap->SetAt( CC_RUNTIME_CLASS(AttrFillGeometry), (void*)pBitmapFill );
01352                         }
01353 
01354                         AttrFillGeometry* pStrokeColour = new AttrStrokeColour();
01355                         if (pStrokeColour)
01356                         {
01357                             // Ensure the line colour is set to NONE
01358                             DocColour NoCol = COLOUR_NONE;
01359                             pStrokeColour->SetStartColour(&NoCol);
01360 
01361                             void* pOldStroke;
01362                             if( pCopyOfAttrMap->Lookup( CC_RUNTIME_CLASS(AttrStrokeColour), pOldStroke ) )
01363                             {
01364                                 // We need to Remove and Delete the existing Stroke Colour Attr
01365                                 pCopyOfAttrMap->RemoveKey( CC_RUNTIME_CLASS(AttrStrokeColour) );
01366                                 delete (AttrFillGeometry*)pOldStroke;
01367                             }
01368 
01369                             // Add the new Stroke Colour into the Attr Map
01370                             pCopyOfAttrMap->SetAt( CC_RUNTIME_CLASS(AttrStrokeColour), (void*)pStrokeColour );
01371                         }
01372                     }
01373 
01374                     Success = pBecomeA->PassBack(pNewNodePath, this, pCopyOfAttrMap);
01375                 }
01376                 break;
01377 
01378                 case BECOMEA_TEST:
01379                     // Do nothing
01380                 break;
01381 
01382                 default:
01383                 {
01384                     ERROR3("Unhandled BecomeA type in NodeBitmap::DoBecomeA");
01385                 }
01386             }
01387         }
01388     }
01389 
01390     if (!Success)
01391     {
01392         if (pNewNodePath != NULL)
01393         {
01394             // Delete all the NodePath's children (if it has any) and unlink it from the tree (if it's linked)
01395             // This is all done by CascadeDelete()
01396             pNewNodePath->CascadeDelete(); 
01397             delete pNewNodePath;
01398             pNewNodePath = NULL;
01399         }
01400     }
01401 
01402     return Success;
01403 }
01404 
01405 /********************************************************************************************
01406 
01407 >   virtual BOOL NodeBitmap::AllowOp(ObjChangeParam* pParam,BOOL SetOpPermissionState = TRUE)
01408 
01409     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01410     Created:    3/02/95
01411     Inputs:     pParam               = describes the way an op wants to change the node
01412                 SetOpPermissionState = if TRUE the Op permission state of this node will be set according to
01413                                         the outcome of the call
01414     Outputs:    -
01415     Returns:    TRUE means the node and all its parents are happy with this op, FALSE means don't do it
01416     Purpose:    This is the way to ask a node if you can do an op to it.
01417 
01418                 The ObjChangeParam class contains flags that describe how it will change the node
01419 
01420                 For example, the op could change the node's appearence (e.g. attr application, editing a path), 
01421                 replace the node with another node (e.g. because it uses hidden nodes to hide the original and put another
01422                 node in its place, or "make shapes"), delete the node (e.g. the delete and cut ops), etc.
01423 
01424                 This function gives the node a chance to say NO.  It also gives the parents a chance to say no too.
01425                 E.g. a blend node will allow itself to be deleted, but it will NOT allow a child of itself to be deleted).
01426 
01427                 This call should only be made on selected, or parents of selected, nodes.  It makes a decision as a 
01428                 straight node if it is selected.  It makes a decision as a parent if it has selected children.
01429 
01430                 E.g. NodeBlend::AllowOp(...op delete...)
01431                     if the node is selected, then it will return TRUE (parents permitting), i.e. I can be deleted
01432                     if the node is a parent of selected it will return FALSE (i.e. can't delete children of blends).
01433 
01434                 So when the node is selected, you are asking the node if you can do the op to it.  When the node is
01435                 a parent of a selected node, you are asking if you can do the op to one of its children.
01436 
01437                 ********
01438 
01439                 If the 'SetOpPermissionState' param is TRUE, the following indented lines applies:
01440                     The node's op permission state is set according to the result of this function.
01441 
01442                     If TRUE  is returned, then the node's op permission state will be left unchanged.
01443                         AND the parent's op permission state will be set to PERMISSION_ALLOWED
01444 
01445                     if FALSE is returned, then the node's op permission state will be PERMISSION_DENIED,
01446                         AND all it's parents (up to the layer) will be set to PERMISSION_DENIED
01447 
01448                     Also, all parents of this node are called via their AllowOp() func with the same state 
01449                     as this node.  This means that after this call, you can guarantee that all of its parents will
01450                     have either a PERMISSION_DENIED or PERMISSION_ALLOWED state.
01451 
01452                     Note: Even if this node tries to set all it's parents to have a PERMISSION_DENIED state, if any
01453                     of its parents have previously been set to PERMISSION_ALLOWED they will remain in that state (see
01454                     SetOpPermission()). Why? Well, it is possible for a parent node to have one child with a 
01455                     PERMISSION_DENIED and another child with a PERMISSION_ALLOWED.  It this state the parent MUST be
01456                     in state PERMISSION_ALLOWED, because at least one of its children will allow the op to happen to it.
01457 
01458                     So, after this call:
01459                             The op permission state for this node will be either left unchanged (and
01460                             therefore remain PERMISSION_UNDEFINED), or PERMISSION_DENIED.
01461 
01462                             The parent's op permission state will be either PERMISSION_ALLOWED, or PERMISSION_DENIED.
01463 
01464                     This is so UndoableOperation::UpdateChangedNodes() will only call OnChildChange() on parent nodes,
01465                     because it only calls that func for nodes that have an op permission state of PERMISSION_ALLOWED.
01466 
01467                 ********
01468 
01469     SeeAlso:    GetOpPermission(),SetOpPermission();
01470 
01471 ********************************************************************************************/
01472 
01473 BOOL NodeBitmap::AllowOp(ObjChangeParam* pParam, BOOL SetOpPermissionState)
01474 {
01475     ERROR2IF(pParam==NULL,FALSE,"Node::AllowOp() - pParam==NULL");
01476 
01477     // if not called by a child AllowOp(), ensure AllowOp() called for all nodes in compound nodes,
01478     if (pParam->GetDirection()!=OBJCHANGE_CALLEDBYCHILD)
01479     {
01480         BOOL AnyAllowed=AllowOp_AccountForCompound(pParam, SetOpPermissionState);
01481         // if called by a parent, just pass this result back
01482         if (pParam->GetDirection()==OBJCHANGE_CALLEDBYPARENT)
01483             return AnyAllowed;
01484     }
01485     else
01486     {
01487         // clean out the calling-child ptr, so it doesn't get passed around unintentionally.
01488         pParam->SetCallingChild(NULL);
01489     }
01490 
01491     // at this point we must have been called directly by the op or via a child AllowOp()
01492 
01493     // decide if we allow it ... 
01494     BOOL allowed=TRUE;
01495     ObjChangeFlags Flags = pParam->GetChangeFlags();
01496 
01497     if (Flags.Attribute)
01498     {
01499         // Someone is applying an attribute .....
01500         // We really need to check the actual attribute, so for
01501         // now we'll rely on the fact that the 'RequiresAttrib()'
01502         // function will have been called before this one.
01503 
01504         // If we are applying a contone colour, then make sure we
01505         // are a Grey level bitmap, and give the user the option
01506         // of making one if not.
01507         if (ApplyContoneColour)
01508         {
01509             // 'ApplyContoneColour' is set in the 'RequiresAttrib()'
01510             // function if a contone colour change attr is applied.
01511             allowed = MakeContoneBitmap(pParam->GetOpPointer());        
01512         }       
01513     }
01514 
01515     // if we allowed it, see if our parents do ...
01516     if (allowed && Parent!=NULL)
01517     {
01518         ObjChangeDirection OldDirection=pParam->GetDirection();
01519         pParam->SetCallingChild(this);
01520         pParam->SetDirection(OBJCHANGE_CALLEDBYCHILD);
01521         allowed=Parent->AllowOp(pParam,SetOpPermissionState);
01522         pParam->SetDirection(OldDirection);
01523     }
01524 
01525     // if setting permisions ...
01526     if (SetOpPermissionState)
01527     {
01528         // if allowed, mark parent accordingly, else mark child as denied and update parents
01529         if (allowed)
01530             Parent->SetOpPermission(PERMISSION_ALLOWED);
01531         else
01532             SetOpPermission(PERMISSION_DENIED,TRUE);
01533     }
01534 
01535     // return result (directly, or indirectly via a child AllowOp()) to op
01536     return allowed;
01537 }
01538 
01539 /********************************************************************************************
01540 
01541 >   BOOL NodeBitmap::MakeContoneBitmap(UndoableOperation* pOperation)
01542 
01543     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
01544     Created:    27/6/95
01545     Purpose:    Make this NodeBitmap into a grey level version of itself.
01546 
01547 ********************************************************************************************/
01548 
01549 BOOL NodeBitmap::MakeContoneBitmap(UndoableOperation* pOperation)
01550 {
01551     KernelBitmap* pBitmap = GetBitmap();
01552     KernelBitmap* pGreyBmp = CheckGreyscaleBitmap(pBitmap, _R(IDS_MAKEGREY), _R(IDS_DOGREY));
01553 
01554     if (pGreyBmp == NULL)
01555         return FALSE;   // Failed in some way (or the user cancelled)
01556 
01557     return TRUE;
01558 }
01559 
01560 /********************************************************************************************
01561 
01562 >   static KernelBitmap* NodeBitmap::CheckGreyscaleBitmap(  KernelBitmap* pBitmap, 
01563                                                             UINT32 PromptID, UINT32 OkID)
01564 
01565     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
01566     Created:    27/6/95
01567     Purpose:    Checks a bitmap to see if can be applied as a texture,
01568                 and gives the option to create a grey level version if not.
01569 
01570 ********************************************************************************************/
01571 
01572 KernelBitmap* NodeBitmap::CheckGreyscaleBitmap(KernelBitmap* pBitmap, UINT32 PromptID, UINT32 OkID)
01573 {
01574 #if !defined(EXCLUDE_FROM_RALPH)
01575     ERROR2IF(pBitmap == NULL, NULL, "Null bitmap passed to CheckGreyscaleBitmap");
01576 
01577     // Don't need to do anything here now, as the greyscale bitmap is generated on the
01578     // fly when rendering
01579     
01580     return pBitmap;
01581 #else
01582     ERROR3("NodeBitmap::CheckGreyscaleBitmap");
01583     return NULL;
01584 #endif
01585 }
01586            
01587 /********************************************************************************************
01588 
01589 >   KernelBitmap* NodeBitmap::GetBitmap()
01590 
01591     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
01592     Created:    12/1/95
01593     Purpose:    Get the bitmap referenced by this node. 
01594 
01595 ********************************************************************************************/
01596 
01597 KernelBitmap* NodeBitmap::GetBitmap()
01598 {
01599     KernelBitmap* pBitmap = BitmapRef.GetBitmap();
01600     
01601     // Check for a deleted bitmap
01602     if (pBitmap && pBitmap->HasBeenDeleted())
01603     {
01604         ERROR2IF(pBitmap->GetParentBitmapList() == NULL, NULL, "Deleted bitmap has no parent list");
01605         
01606         // Use the default bitmap instead
01607         pBitmap = pBitmap->GetParentBitmapList()->FindDefaultBitmap();
01608 
01609         // There should always be a default bitmap in the list
01610         ERROR2IF(pBitmap == NULL, 0L, "Couldn't find the default bitmap");
01611     }
01612 
01613     return pBitmap;
01614 }
01615 
01616 /***********************************************************************************************
01617 
01618 >    virtual BOOL NodeBitmap::HidingNode()
01619 
01620      Author:    Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
01621      Created:   11/1/94
01622      Returns:   TRUE if all was ok. FALSE if an error occured.
01623      Purpose:   This virtual function is called whenever the node is hidden.
01624                 It allows the node do things like 'optimise' itself to use less memory or
01625                 send a message to let others know it is being hidden etc.
01626 
01627                 ALWAYS CALL THE BASE CLASS' FUNCTION FROM YOUR OVERRIDDEN FUNCTION.
01628 
01629 ***********************************************************************************************/
01630 
01631 BOOL NodeBitmap::HidingNode()
01632 {
01633     // Call the base class first
01634     if (!NodeRect::HidingNode())
01635         return FALSE;
01636 
01637     GetBitmapRef()->RemoveFromTree();
01638 
01639     return TRUE;
01640 }
01641 
01642 /***********************************************************************************************
01643 
01644 >    virtual BOOL NodeBitmap::ShowingNode()
01645 
01646      Author:    Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
01647      Created:   11/1/94
01648      Returns:   TRUE if all was ok. FALSE if an error occured (eg Out of memory).
01649      Purpose:   This virtual function is called whenever the node is re-shown after being 
01650                 Hidden.
01651                 It allows the node to reconstruct itself if it was optimised or
01652                 send a message to let others know it is back etc.
01653 
01654                 ALWAYS CALL THE BASE CLASS' FUNCTION FROM YOUR OVERRIDDEN FUNCTION.
01655 
01656 ***********************************************************************************************/
01657 
01658 BOOL NodeBitmap::ShowingNode()
01659 {
01660     // Call the base class first
01661     if (!NodeRect::ShowingNode())
01662         return FALSE;
01663 
01664     GetBitmapRef()->AddtoTree();
01665 
01666     return TRUE;
01667 }
01668 
01669 /********************************************************************************************
01670 
01671 >   void NodeBitmap::SetStartColour(DocColour* NewCol)
01672 
01673     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
01674     Created:    26/1/95
01675     Purpose:    Set the start colour of a bitmap palette
01676 
01677 ********************************************************************************************/
01678 
01679 void NodeBitmap::SetStartColour(DocColour* NewCol)
01680 {
01681     if (NewCol == NULL)
01682         Colour = COLOUR_NONE;
01683     else
01684         Colour = *NewCol;
01685 }
01686 
01687 /********************************************************************************************
01688 
01689 >   void NodeBitmap::SetEndColour(DocColour* NewCol)
01690 
01691     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
01692     Created:    26/1/95
01693     Purpose:    Set the end colour of a bitmap palette
01694 
01695 ********************************************************************************************/
01696 
01697 void NodeBitmap::SetEndColour(DocColour* NewCol)
01698 {
01699     if (NewCol == NULL)
01700         EndColour = COLOUR_NONE;
01701     else
01702         EndColour = *NewCol;
01703 }
01704 
01705 /********************************************************************************************
01706 
01707 >   DocColour* NodeBitmap::GetStartColour()
01708 
01709     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
01710     Created:    26/1/95
01711     Returns:    NULL if there is no colour (> 8bpp), or a pointer to the Start Colour.
01712     Purpose:    Gets the start colour of the bitmap palette
01713 
01714 ********************************************************************************************/
01715 
01716 DocColour* NodeBitmap::GetStartColour()
01717 {
01718 /*
01719     if (Colour == COLOUR_NONE)
01720         return NULL;
01721     else
01722         return &Colour;
01723 */
01724 
01725 //  if (GetBitmap()->GetBPP() <= 8)
01726 //  {
01727         NodeAttribute* pLineAttr;
01728         
01729         if (!FindAppliedAttribute(CC_RUNTIME_CLASS(AttrStrokeColour), &pLineAttr))
01730             return NULL;
01731 
01732         DocColour* Col = ((AttrStrokeColour*)pLineAttr)->GetStartColour();
01733         if (Col && *Col != COLOUR_NONE)
01734             return Col;
01735 //  }
01736 
01737     return NULL;
01738 }
01739 
01740 /********************************************************************************************
01741 
01742 >   DocColour* NodeBitmap::GetEndColour()
01743 
01744     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
01745     Created:    26/1/95
01746     Returns:    NULL if there is no colour (> 8bpp), or a pointer to the End Colour.
01747     Purpose:    Gets the end colour of the bitmap palette
01748 
01749 ********************************************************************************************/
01750 
01751 DocColour* NodeBitmap::GetEndColour()
01752 {
01753 /*
01754     if (EndColour == COLOUR_NONE)
01755         return NULL;
01756     else
01757         return &EndColour;
01758 */
01759 
01760 //  if (GetBitmap()->GetBPP() <= 8)
01761 //  {
01762         NodeAttribute* pFillAttr;
01763         
01764         if (!FindAppliedAttribute(CC_RUNTIME_CLASS(AttrFillGeometry), &pFillAttr))
01765             return NULL;
01766 
01767         DocColour* Col = ((AttrFillGeometry*)pFillAttr)->GetStartColour();
01768         if (Col && *Col != COLOUR_NONE)
01769             return Col;
01770 //  }
01771 
01772     return NULL;
01773 }
01774 
01775 
01776 /********************************************************************************************
01777 
01778 >   BOOL NodeBitmap::HasSimpleOrientation(RenderRegion *pRegion)
01779 
01780     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01781     Created:    31/7/95
01782     Inputs:     pRegion - the region that the bitmap orientation should be tested in.
01783     Returns:    TRUE if the bitmap orientation is a simple rectangular stretch, perpendicular
01784                 to the co-ordinate system;
01785                 FALSE if not (e.g. rotation or shearing applied to bitmap).
01786     Purpose:    Determine if a bitmap is classified as a 'simple' bitmap, for use during the
01787                 complex rendering of a view - if the render region can support simple bitmaps
01788                 and this function returns TRUE, then we render the bitmap directly, otherwise
01789                 it goes into the masked GDraw bitmap and is rendered that way.
01790     SeeAlso:    DrawTransformedBitmap
01791 
01792 ********************************************************************************************/
01793 
01794 BOOL NodeBitmap::HasSimpleOrientation(RenderRegion *pRegion)
01795 {
01796     PORTNOTETRACE("other","NodeBitmap::HasSimpleOrientation - do nothing");
01797 #ifndef EXCLUDE_FROM_XARALX
01798     // Get information from the render region
01799     View *RenderView = pRegion->GetRenderView();
01800     Matrix RenderMatrix = pRegion->GetMatrix();
01801 
01802     if (RenderView == NULL)
01803         // We can't tell - assume the worst
01804         return FALSE;
01805 
01806     // Check for sideways printing - if the render matrix has rotation, then we are
01807     // printing at 270 degrees rotation, so we can't do the blit.
01808     FIXED16 RenderABCD[4];
01809     INT32   RenderEF[2];
01810     RenderMatrix.GetComponents(RenderABCD, RenderEF);
01811     if ((RenderABCD[1] != FIXED16(0)) || (RenderABCD[2] != FIXED16(0)))
01812         // Rotated by 270 degrees - not simple orientation
01813         return FALSE;
01814 
01815     // Check the co-ordinates
01816     DocCoord *Coords = InkPath.GetCoordArray();
01817 
01818     // Use tolerance of 1 pixel when checking for perpendicular nature of the
01819     // bitmap, as undo/redo can cause small millipoint errors that we should
01820     // cope with.
01821     FIXED16 fxPixelSize;
01822     RenderView->GetScaledPixelSize(&fxPixelSize, &fxPixelSize);
01823     MILLIPOINT Tolerance = fxPixelSize.MakeLong();
01824 
01825     MILLIPOINT Diff1 = abs(Coords[0].x - Coords[3].x);
01826     MILLIPOINT Diff2 = abs(Coords[1].x - Coords[2].x);
01827     MILLIPOINT Diff3 = abs(Coords[0].y - Coords[1].y);
01828     MILLIPOINT Diff4 = abs(Coords[3].y - Coords[2].y);
01829 
01830     if ((Diff1 < Tolerance) && (Diff2 < Tolerance) &&
01831         (Diff3 < Tolerance) && (Diff4 < Tolerance))
01832     {
01833         // Yes - simple rectangular orientation.
01834         return TRUE;
01835     } 
01836 #endif
01837     // Complex bitmap orientation
01838     return FALSE;
01839 }
01840 
01841 
01842 
01843 
01844 /********************************************************************************************
01845 
01846 >   Matrix NodeBitmap::GetInstanceTransform()
01847 
01848     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01849     Created:    27/07/2005
01850     Inputs:     -
01851     Returns:    Matrix containing the combined transformations that are required to
01852                 get from the original bitmap size and position to that represented by the
01853                 current NodeSimpleShape parallelogram.
01854     Purpose:    Find the instance transform matrix
01855     Notes:      Parallelogram format includes 4 coords and is stored in this format:
01856                     0-------1
01857                     |       |
01858                     3-------2
01859                 (Why?)
01860 
01861 ********************************************************************************************/
01862 
01863 Matrix NodeBitmap::GetInstanceTransform()
01864 {
01865     // First construct matrix to get from OriginalBitmapRect to unit square
01866     // Then construct matrix to get from unit square to current parallelogram
01867     // Then combine the two matrices
01868     // Do the maths in doubles for speed and accuracy!
01869 
01870     DocRect oRect = GetOriginalBitmapRect();
01871 
01872     // Construct the original-to-unit matrix
01873     double oa = 1.0/oRect.Width();
01874     double ob = 0;
01875     double oc = 0;
01876     double od = 1.0/oRect.Height();
01877     double oe = -oRect.lo.x;
01878     double of = -oRect.lo.y;
01879 
01880     // Construct the matrix for unit-to-instance-on-page matrix
01881     double ia = Parallel[2].x-Parallel[3].x;
01882     double ib = Parallel[2].y-Parallel[3].y;
01883     double ic = Parallel[0].x-Parallel[3].x;
01884     double id = Parallel[0].y-Parallel[3].y;
01885     double ie = Parallel[3].x;
01886     double i_f = Parallel[3].y;
01887 
01888     // Multiply the two matrices
01889     double ra = oa * ia + ob * ic + 0 * ie;
01890     double rb = oa * ib + ob * id + 0 * i_f;
01891     double rc = oc * ia + od * ic + 0 * ie;
01892     double rd = oc * ib + od * id + 0 * i_f;
01893     double re = oe * ia + of * ic + 1 * ie;
01894     double rf = oe * ib + of * id + 1 * i_f;
01895 
01896     // Return a crappy old FIXED16-based Matrix object
01897     return Matrix(ra, rb, rc, rd, INT32(re), INT32(rf) );
01898 }
01899 
01900 
01901 
01902 
01903 /********************************************************************************************
01904 
01905 >   DocRect NodeBitmap::GetOriginalBitmapRect()
01906 
01907     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01908     Created:    27/07/2005
01909     Inputs:     -
01910     Returns:    DocRect containing the size of the bitmap if it were placed on the 
01911                 page untransformed.
01912     Purpose:    Find the starting point for the instance transform
01913 
01914 ********************************************************************************************/
01915 
01916 DocRect NodeBitmap::GetOriginalBitmapRect()
01917 {
01918     DocRect oRect;
01919     KernelBitmap* pkBitmap = GetBitmap();
01920     if (pkBitmap==NULL)
01921         return oRect;
01922 
01923     oRect.lo.x = 0;
01924     oRect.lo.y = 0;
01925 //  oRect.hi.x = 750.0 * pkBitmap->GetWidth();  // Note: Pixel width, ignoring bitmap's stated DPI
01926 //  oRect.hi.y = 750.0 * pkBitmap->GetHeight(); // Note: Pixel height, ignoring bitmap's stated DPI
01927     oRect.hi.x = pkBitmap->GetRecommendedWidth();
01928     oRect.hi.y = pkBitmap->GetRecommendedHeight();
01929 
01930     return oRect;
01931 }
01932 
01933 
01934 
01935 
01936 /********************************************************************************************
01937 
01938 >   BOOL NodeBitmap::GetDirectBitmap(RenderRegion* pRender, LPBITMAPINFO* plpInfo, LPBYTE* plpBits, DocRect* pRect, Matrix* pMat, double* pdRes)
01939 
01940     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01941     Created:    28/07/2005
01942     Inputs:     pMat    - pointer to matrix awaiting update
01943     Outputs:    plpInfo - LPBITMAPINFO pointer describing bitmap
01944                 plpBits - LPBYTE pointer to bitmap data
01945                 pRect   - rect of Original bitmap data
01946                 pMat    - matrix describing transform from pRect to this instance on the page
01947                 pdRes   - resolution of this bitmap (dpi)
01948     Returns:    TRUE if this node can supply direct bitmap data to the caller
01949                 FALSE otherwise
01950     Purpose:    Return details of direct bitmap to caller (caller is usually a NodeBitmapEffect)
01951 
01952 ********************************************************************************************/
01953 
01954 BOOL NodeBitmap::GetDirectBitmap(RenderRegion* pRender, LPBITMAPINFO* plpInfo, LPBYTE* plpBits, DocRect* pRect, Matrix* pMat, double* pdRes)
01955 {
01956     KernelBitmap* pkBitmap = GetBitmap();
01957 
01958     // Initial response is to return our raw bitmap info...
01959     if (plpInfo)    *plpInfo    = pkBitmap->GetBitmapInfo();
01960     if (plpBits)    *plpBits    = pkBitmap->GetBitmapBits();
01961     if (pRect)      *pRect      = GetOriginalBitmapRect();
01962     if (pMat)       *pMat       = GetInstanceTransform();
01963     if (pdRes)      *pdRes      = pkBitmap->GetHorizontalDPI();
01964 
01965     // Now test whether the user is asking for a bitmap and whether our raw bitmap needs to
01966     // be specially processed...
01967     if (plpInfo && plpBits && HasBitmapAttrs())
01968     {
01969         // Lookup processed bitmap in cache 
01970         CBitmapCache* pBitmapCache = Camelot.GetBitmapCache();
01971         if (pBitmapCache==NULL)
01972             return FALSE;
01973 
01974         CBitmapCacheKey inky(this, 72000.0/pkBitmap->GetHorizontalDPI(), 2);    // Option 2 is processed/rendered bitmap (see below)
01975         CCachedBitmap cbmp;
01976         BOOL bFound = pBitmapCache->Lookup(inky, cbmp);
01977         if (bFound)
01978         {
01979             if (plpInfo)    *plpInfo = cbmp.pbmpInfo;
01980             if (plpBits)    *plpBits = cbmp.pbmpBits;
01981             return TRUE;
01982         }
01983 
01984         // We need to create a new bitmap here that captures the effects of the attributes
01985         //
01986         // If we don't have a RenderRegion, we can't build it, so return NULLs to indicate
01987         // that we need to be called again with a RenderRegion (allows quick test)
01988         // (See EnsureLiveEffectOriginalBitmaps)
01989         if (pRender == NULL)
01990         {
01991             if (plpInfo)    *plpInfo    = NULL;
01992             if (plpBits)    *plpBits    = NULL;
01993             return TRUE;
01994         }
01995 
01996         // We must "render" this bitmap to capture the attributes that effect its appearance
01997         // By default, we can't do arbitrarily transformed bitmaps - use a bitmap fill.
01998         AttrFillGeometry* pTranspAttr = NULL;
01999         AttrFeather* pFeatherAttr = NULL;
02000         BitmapTranspFillAttribute* pFeatherTransp = NULL;
02001         KernelBitmap* pFeatherBitmap = NULL;
02002         MILLIPOINT mpScaledFeatherSize = 0;
02003         CProfileBiasGain profileFeather;
02004         DocRect CaptureRect = GetOriginalBitmapRect();
02005         CaptureFlags caFlags = CaptureFlags(cfLOCKEDTRANSPARENT | cfFULLCOVERAGE);
02006         pRender->StartCapture(this, CaptureRect, CAPTUREINFO(ctNESTABLE, caFlags), TRUE, FALSE, pkBitmap->GetHorizontalDPI());
02007         pRender->SaveContext();
02008 
02009         {   // ------------------------------------------------------
02010             // Setup coords for rendering in DirectBitmap domain
02011             DocCoord coords[3];
02012             coords[0] = CaptureRect.lo;
02013             coords[1] = DocCoord(CaptureRect.hi.x, CaptureRect.lo.y);
02014             coords[2] = DocCoord(CaptureRect.lo.x, CaptureRect.hi.y);
02015 
02016             // Create the path to be rendered in the DirectBitmap domain
02017             Path InkPath;
02018             InkPath.Initialise();
02019             InkPath.AddMoveTo(coords[0]);
02020             InkPath.AddLineTo(coords[1]);
02021             InkPath.AddLineTo(DocCoord(coords[2].x+coords[1].x-coords[0].x, coords[2].y+coords[1].y-coords[0].y));
02022             InkPath.AddLineTo(coords[2]);
02023             InkPath.AddLineTo(coords[0]);
02024             InkPath.CloseSubPath();
02025             InkPath.IsFilled = TRUE;
02026 
02027             // Compute the inverse transform matrix - a matrix to get from "Screen space" to "Direct space"
02028             Matrix matInverse = GetInstanceTransform().Inverse();
02029 
02030             // No lines on the rectangle
02031             pRender->SetLineColour(COLOUR_TRANS);
02032             pRender->SetLineWidth(0);
02033 
02034             // Render the transparency geometry using inverse Direct-Screen transform
02035             // (This bitmap is being rendered in "Direct space" whereas the transparency attribute
02036             // was applied in "Screen space")
02037             NodeAttribute* pAttr;
02038             if (FindAppliedAttribute(CC_RUNTIME_CLASS(AttrTranspFillGeometry), &pAttr))
02039             {
02040                 if (pAttr && !pAttr->IsADefaultAttr() && !pAttr->HasEquivalentDefaultValue(TRUE))
02041                 {
02042                     pTranspAttr = (AttrFillGeometry*) ((AttrFillGeometry*)pAttr)->SimpleCopy();
02043                     if (pTranspAttr)
02044                     {
02045                         DocCoord tcoords[4];
02046                         DocCoord* pCoord = NULL;
02047                         pCoord = pTranspAttr->GetStartPoint();
02048                         tcoords[0] = pCoord ? *pCoord : DocCoord(0,0);
02049                         pCoord = pTranspAttr->GetEndPoint();
02050                         tcoords[1] = pCoord ? *pCoord : DocCoord(0,0);
02051                         pCoord = pTranspAttr->GetEndPoint2();
02052                         tcoords[2] = pCoord ? *pCoord : DocCoord(0,0);
02053                         pCoord = pTranspAttr->GetEndPoint3();
02054                         tcoords[3] = pCoord ? *pCoord : DocCoord(0,0);
02055 
02056                         matInverse.transform(tcoords, 4);
02057 
02058                         pTranspAttr->SetStartPoint(&tcoords[0]);
02059                         pTranspAttr->SetEndPoint(&tcoords[1]);
02060                         pTranspAttr->SetEndPoint2(&tcoords[2]);
02061                         pTranspAttr->SetEndPoint3(&tcoords[3]);
02062 
02063                         pTranspAttr->Render(pRender);
02064                     }
02065                 }
02066             }
02067 
02068             // Render the feather attribute with inverse scaled feather width
02069             // (This bitmap is being rendered in "Direct space" whereas the attribute
02070             // was applied in "Screen space")
02071             if (FindAppliedAttribute(CC_RUNTIME_CLASS(AttrFeather), &pAttr))
02072             {
02073                 // currently, we only generate an offscreen bitmap for GRenderRegions, although we are
02074                 // 'rendered' into all RR's. therefore we must quit quietly if pRender is not a GRR.
02075                 if (pAttr && !pAttr->IsADefaultAttr() && !pAttr->HasEquivalentDefaultValue(TRUE) && pRender->IS_KIND_OF(GRenderRegion))
02076                 {
02077                     // We can't render the feather attribute or a copy of it because the crappy
02078                     // thing relies intimately on its connection to the tree to get geometric
02079                     // information.
02080                     GRenderRegion* pGRR = (GRenderRegion*)pRender;
02081                     pFeatherAttr = (AttrFeather*) ((AttrFeather*)pAttr)->SimpleCopy();
02082                     if (pFeatherAttr)
02083                     {
02084                         mpScaledFeatherSize = pFeatherAttr->Value.GetFeatherSize();
02085                         FIXED16 f16Scale;
02086                         matInverse.Decompose(&f16Scale);    // Should take aspect into account as well???
02087                         mpScaledFeatherSize = (MILLIPOINT)((double)mpScaledFeatherSize * f16Scale.MakeDouble() + 0.5);
02088                         pFeatherAttr->Value.SetFeatherSize(mpScaledFeatherSize);
02089 
02090                         profileFeather = pFeatherAttr->Value.GetProfile();
02091 
02092                         // Don't let the feather render itself, but call it's core functions with
02093                         // our special information to get it to create the crucial transparency bitmap fill
02094                         pFeatherAttr->Value.CreateFeatherTransp(pGRR, &InkPath, 72000.0/((double)(pkBitmap->GetHorizontalDPI())), &pFeatherTransp, &pFeatherBitmap);
02095 
02096                         if (pFeatherTransp)
02097                         {
02098                             TranspFillMappingLinearAttribute* pFeatherTranspMapping = new TranspFillMappingLinearAttribute;
02099                             pFeatherTranspMapping->Repeat = 0;
02100                             pRender->SetTranspFillMapping(pFeatherTranspMapping, TRUE);
02101 
02102                             pRender->SetTranspFillGeometry(pFeatherTransp, TRUE);
02103                         }
02104                     }
02105                 }
02106             }
02107 
02108             // Simple bitmap fill which fills the whole shape
02109             BitmapFillAttribute *pBitmapAttr = new BitmapFillAttribute;
02110             pBitmapAttr->GetBitmapRef()->SetBitmap(pkBitmap);
02111 
02112             if (GetStartColour())
02113                 pBitmapAttr->SetStartColour(GetStartColour());
02114         
02115             if (GetEndColour())
02116                 pBitmapAttr->SetEndColour(GetEndColour());
02117 
02118             // Set fill coords
02119             pBitmapAttr->StartPoint = coords[0];
02120             pBitmapAttr->EndPoint   = coords[1];
02121             pBitmapAttr->EndPoint2  = coords[2];
02122 
02123             // Set bitmap attribute, and get the render region to throw it away when it's finished
02124             // with (hence the TRUE parameter).
02125             pRender->SetFillGeometry(pBitmapAttr, TRUE);
02126 
02127             // Set the mapping to have no repeat, otherwise we get artifacts at the edges when
02128             // anti-aliasing is enabled (see bug 1391).
02129             FillMappingLinearAttribute *pNoRepeatAttr = new FillMappingLinearAttribute;
02130 
02131             // Prevent tesselation to get rid of possible edge effects
02132             pNoRepeatAttr->Repeat = 0;
02133 
02134             // Set mapping attribute, and get the render region to throw it away when it's finished
02135             // with (hence the TRUE parameter).
02136             pRender->SetFillMapping(pNoRepeatAttr, TRUE);
02137 
02138             // Draw the bitmap by rendering a bitmap filled path.
02139             pRender->DrawPath(&InkPath);
02140         }   // ------------------------------------------------------
02141 
02142         pRender->RestoreContext();
02143         if (pTranspAttr)
02144         {
02145             delete pTranspAttr;
02146             pTranspAttr = NULL;
02147         }
02148 
02149         if (pFeatherAttr)
02150         {
02151             delete pFeatherAttr;
02152             pFeatherAttr = NULL;
02153         }
02154 
02155 // Don't need this because pFeatherTransp is rendered with "Temp=TRUE" so that the RenderRegion will delete it
02156 //      if (pFeatherTransp)
02157 //      {
02158 //          delete pFeatherTransp;
02159 //          pFeatherTransp = NULL;
02160 //      }
02161 
02162         if (pFeatherBitmap != NULL)
02163         {
02164             delete pFeatherBitmap;
02165             pFeatherBitmap = NULL;
02166         }
02167 
02168         LPBITMAPINFO lpInfo = NULL;
02169         LPBYTE lpBits = NULL;
02170         pRender->StopCapture(this, FALSE, FALSE, &lpInfo, &lpBits, &CaptureRect);
02171 
02172         // We should now have a bitmap containing an upright version of the NodeBitmap
02173         // with transparency and contoning applied as per the attributes in the tree
02174         if (lpInfo && lpBits)
02175         {
02176             *plpInfo = lpInfo;
02177             *plpBits = lpBits;
02178 
02179             // Cache the PROCESSED/RENDERED bitmap as Option 2
02180             CBitmapCacheKey inky(this, 72000.0/pkBitmap->GetHorizontalDPI(), 2);
02181             CCachedBitmap cbmp;
02182             cbmp.pbmpBits = lpBits;
02183             cbmp.pbmpInfo = lpInfo;
02184             cbmp.SetCachedRect(CaptureRect);
02185             cbmp.nPriority = CACHEPRIORITY_TEMPBITMAP_HIGH;
02186             if (cbmp.IsValid())
02187                 pBitmapCache->StoreBitmap(inky, cbmp);
02188         }
02189     }
02190 
02191     return TRUE;
02192 }
02193 
02194 
02195 
02196 
02197 /********************************************************************************************
02198 
02199 >   BOOL NodeBitmap::HasBitmapAttrs()
02200 
02201     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02202     Created:    29/07/2005
02203     Inputs:     -
02204     Outputs:    -
02205     Returns:    TRUE if this node has attributes applied which affect the way it renders
02206                 FALSE otherwise
02207     Purpose:    Test whether we need to render this bitmap before we can return it from
02208                 GetDirectBitmap
02209 
02210 ********************************************************************************************/
02211 
02212 BOOL NodeBitmap::HasBitmapAttrs()
02213 {
02214     if (GetStartColour() || GetEndColour())
02215         return TRUE;
02216 
02217     NodeAttribute* pAttr;
02218     if (FindAppliedAttribute(CC_RUNTIME_CLASS(AttrTranspFillGeometry), &pAttr))
02219     {
02220         if (pAttr && !pAttr->IsADefaultAttr() && !pAttr->HasEquivalentDefaultValue(TRUE))
02221             return TRUE;
02222     }
02223 
02224     if (FindAppliedAttribute(CC_RUNTIME_CLASS(AttrFeather), &pAttr))
02225     {
02226         if (pAttr && !pAttr->IsADefaultAttr() && !pAttr->HasEquivalentDefaultValue(TRUE))
02227             return TRUE;
02228     }
02229 
02230     return FALSE;
02231 }
02232 
02233 
02234 
02235 
02236 /********************************************************************************************
02237 
02238 >   virtual BOOL NodeBitmap::ReleaseCached(BOOL bAndParents = TRUE,
02239                                                       BOOL bAndChildren = TRUE,
02240                                                       BOOL bSelf = TRUE,
02241                                                       BOOL bAndDerived = TRUE)
02242 
02243     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02244     Created:    30/07/2005
02245     Inputs:     bAndParents - TRUE if should release parent objects
02246                 bAndChildren - TRUE if should release child objects
02247                 bSelf - TRUE if should release own cached data
02248                 bAndDerived - TRUE if should release cached data derived from this object
02249     Outputs:    -
02250     Returns:    TRUE
02251     Purpose:    Get rid of cached data held in the tree
02252 
02253 ********************************************************************************************/
02254 
02255 BOOL NodeBitmap::ReleaseCached(BOOL bAndParents, BOOL bAndChildren, BOOL bSelf, BOOL bAndDerived)
02256 {
02257     BOOL bRemoveOpaqueBitmapsOnly = IsDragged();                // If we're being dragged, only remove opaque bmps
02258     CBitmapCache* pBitmapCache = Camelot.GetBitmapCache();
02259     if (pBitmapCache!=NULL && bSelf)
02260     {
02261         CBitmapCacheKey inky(this, 42);
02262         pBitmapCache->RemoveAllOwnedBitmaps(inky, bRemoveOpaqueBitmapsOnly);
02263     }
02264 
02265     // If we should release our children's caches as well...
02266     if (bAndChildren)
02267     {
02268         Node* pChild = FindFirstChild();
02269         while (pChild)
02270         {
02271             if (pChild->IsBounded())
02272                 ((NodeRenderableBounded*)pChild)->ReleaseCached(FALSE, TRUE, TRUE, TRUE);
02273 
02274             pChild = pChild->FindNext();
02275         }
02276     }
02277 
02278     // If I can't be cached, neither can my parent...
02279     if (bAndParents && FindParent() && FindParent()->IsBounded())
02280         ((NodeRenderableBounded*)FindParent())->ReleaseCached(TRUE, FALSE, TRUE, TRUE);
02281 
02282     return TRUE;
02283 }
02284 
02285 
02286 
02287 
02288 /********************************************************************************************
02289 
02290 >   virtual BOOL NodeBitmap::SupportsClipboardFormat(InternalClipboardFormat *Format) const
02291 
02292     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02293     Created:    26/4/95
02294 
02295     Returns:    TRUE  = This node supports the given format
02296                 FALSE = This node does not support the format (or the format is unknown)
02297 
02298     Purpose:    Determine if a node supports a given internal data type. This is used
02299                 by the clipboard when exporting to other applications in order to
02300                 determine if certain data types can be supplied.
02301 
02302                 e.g. The basic formats include:
02303                     Vector      - this is ALWAYS assumed to be available (Vector format
02304                                   includes every Node, e.g. export in Camelot .art format)
02305 
02306                     Text        - As well as paths, some objects can provide text chars
02307 
02308                     Bitmap      - Bitmap fills can render a filled object or supply the
02309                                   bitmap used for filling with.
02310 
02311                 See InternalClipboardFormat (kernel\cliptype.h) for more details
02312 
02313     Notes:      TextChars can be exported as either "vector" or "text" data
02314 
02315     SeeAlso:    InternalClipboardFormat; Node::SupportsClipboardFormat
02316 
02317 ********************************************************************************************/
02318 
02319 BOOL NodeBitmap::SupportsClipboardFormat(InternalClipboardFormat *Format) const
02320 {
02321 #if !defined(EXCLUDE_FROM_RALPH)
02322     // bitmaps can be exported as either "vector" or "bitmap" data
02323     InternalClipboardFormat temp(CLIPTYPE_BITMAP);
02324     return(Format->IsSameFormat(temp));
02325 //  return(Format->IsSameFormat(InternalClipboardFormat(CLIPTYPE_BITMAP)));
02326 #else
02327     return FALSE;
02328 #endif
02329 }
02330 
02331 /********************************************************************************************
02332 
02333 >   virtual BOOL NodeBitmap::NeedsTransparency() const
02334 
02335     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02336     Created:    5/6/96
02337     Inputs:     -
02338     Outputs:    -
02339     Returns:    TRUE if this node requires transparency mode to render properly.
02340     Purpose:    Called 
02341     Errors:     -
02342     SeeAlso:    Node::AttachNode
02343 
02344 ********************************************************************************************/
02345 
02346 BOOL NodeBitmap::NeedsTransparency() const
02347 {
02348     NodeBitmap* pNonConst = (NodeBitmap*) this;
02349 
02350 //  BOOL NeedsTransparency = FALSE;
02351 
02352     return(pNonConst->GetBitmap()->IsTransparent());
02353 
02354 /*  if (pNonConst->GetBitmap() != NULL)
02355     {
02356         // If the bitmap is 8 bpp or less then check for a transparent colour
02357         if(pNonConst->GetBitmap()->GetBPP() <= 8)
02358         {
02359             INT32 TranspIndex;
02360 
02361             // If the bitmap has a transparency index then we'll need to force transparency on
02362             if (pNonConst->GetBitmap()->GetTransparencyIndex(&TranspIndex))
02363                 return TRUE;
02364         }
02365         
02366         if(pNonConst->GetBitmap()->GetBPP() == 32)
02367         {
02368             // Mark H - If we`ve got a 32 bit bitmap then we must make sure we render into a 32bit
02369             // render region to get the correct output!
02370             return TRUE;
02371         }
02372     }
02373 
02374     return FALSE;
02375 */
02376 }
02377 
02378 /********************************************************************************************
02379 
02380 >   BOOL WritePreChildrenWeb(BaseCamelotFilter* pFilter);
02381     BOOL WritePreChildrenNative(BaseCamelotFilter* pFilter);
02382     
02383     Author:     Andy_Hayward (Xara Group Ltd) <camelotdev@xara.com>
02384     Created:    14/06/96
02385     Inputs:     pFilter - file filter to save to
02386     Returns:    TRUE if successful, false otherwise
02387     Purpose:    saves a NodeBitmap to the filter
02388 
02389 ********************************************************************************************/
02390 
02391 BOOL NodeBitmap::WritePreChildrenWeb(BaseCamelotFilter *pFilter)
02392 {
02393 #ifdef DO_EXPORT
02394     ERROR2IF(pFilter==NULL, FALSE, "Parameter pFilter == NULL");
02395 
02396     return CXaraFileNodeBitmap::WritePreChildrenWeb(pFilter, this);
02397 #else
02398     return FALSE;
02399 #endif
02400 }
02401 
02402 BOOL NodeBitmap::WritePreChildrenNative(BaseCamelotFilter *pFilter)
02403 {
02404 #ifdef DO_EXPORT
02405     ERROR2IF(pFilter==NULL, FALSE, "Parameter pFilter == NULL");
02406 
02407     return CXaraFileNodeBitmap::WritePreChildrenNative(pFilter, this);
02408 #else
02409     return FALSE;
02410 #endif
02411 }
02412 
02413 /********************************************************************************************
02414 
02415 >   KernelBitmap *NodeBitmap::EnumerateBitmaps(UINT32 Count)
02416 
02417     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02418     Created:    02/17/95
02419     Inputs:     Count - the bitmap to get (see Purpose).
02420     Returns:    The KernelBitmap in use by the node, or NULL if no more are used.
02421     Purpose:    Find out what bitmaps, if any, are used by this node.
02422 
02423                 The base class returns NULL always, so you over-ride this in any node classes
02424                 that use bitmaps.
02425 
02426                 This function supports nodes that use more than one bitmap - you call this
02427                 function repeatedly and keep incrementing the Count parameter that you pass
02428                 in each time by 1.  You should stop calling it when it returns NULL, as this
02429                 indicates that no more bitmaps are used by this node.
02430                 Count should start off as 0 for the first call.  Note that this function
02431                 can (and often will) return NULL for the first call, as many nodes don't
02432                 use bitmaps, obviously.
02433 
02434     SeeAlso:    KernelBitmap
02435 
02436 ********************************************************************************************/
02437 
02438 KernelBitmap *NodeBitmap::EnumerateBitmaps(UINT32 Count)
02439 {
02440     if (Count == 0) return GetBitmap();
02441 
02442     return NULL;
02443 }
02444 
02445 
02446 /****************************************************************************
02447 
02448 >   double NodeBitmap::GetEffectiveBitmapMinDPI(KernelBitmap* pBitmap)
02449 
02450     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
02451     Created:    07/08/2006
02452 
02453     Inputs:     pBitmap     - pointer to a KernelBitmap
02454     Returns:    
02455     Purpose:    
02456 
02457 ****************************************************************************/
02458 
02459 double NodeBitmap::GetEffectiveBitmapMinDPI(KernelBitmap* pBitmap)
02460 {
02461     if (GetBitmap() == pBitmap)
02462     {
02463         // Do we have a valid bitmap ?
02464         OILBitmap *OilBM = pBitmap->ActualBitmap;
02465         if (OilBM != NULL)
02466         {
02467             BitmapInfo Info;
02468             OilBM->GetInfo(&Info);
02469 
02470             // Get the Width of the Bitmap in Pixels
02471             INT32 PixWidth  = Info.PixelWidth;
02472             INT32 PixHeight = Info.PixelHeight;
02473 
02474             // Get the Width of the Bitmap in Millipoints
02475             INT32 Width  = INT32(Parallel[0].Distance(Parallel[1]));
02476             INT32 Height = INT32(Parallel[1].Distance(Parallel[2]));
02477 
02478             // Use doubles so that we can round up as well as down. This improves
02479             // the dpi calculated.
02480             double HDpi = 0;
02481             double VDpi = 0;
02482 
02483             if (Width > 0)
02484                 HDpi = ((double)PixWidth * 72000.0)/(double)Width;
02485 
02486             if (Height > 0)
02487                 VDpi = ((double)PixHeight * 72000.0)/(double)Height;
02488 
02489             // Use the smaller of the two dpi values
02490             if (HDpi < VDpi)
02491                 return(HDpi);
02492             else
02493                 return(VDpi);
02494         }
02495     }
02496 
02497     return(1e9);
02498 }
02499 
02500 
02501 
02502 /****************************************************************************
02503 
02504 >   BOOL NodeBitmap::ReplaceBitmap(KernelBitmap* pOrigBitmap, KernelBitmap* pNewBitmap)
02505 
02506     Author:     Gerry_Iles (Xara Group Ltd) <camelotdev@xara.com>
02507     Created:    07/08/2006
02508 
02509     Inputs:     pOrigBitmap - pointer to a KernelBitmap
02510                 pNewBitmap  - pointer to a KernelBitmap
02511     Returns:    TRUE if ok, FALSE if bother
02512     Purpose:    
02513 
02514 ****************************************************************************/
02515 
02516 BOOL NodeBitmap::ReplaceBitmap(KernelBitmap* pOrigBitmap, KernelBitmap* pNewBitmap)
02517 {
02518     if (GetBitmap() == pOrigBitmap)
02519     {
02520         BitmapRef.Attach(pNewBitmap);
02521         return(TRUE);
02522     }
02523 
02524     return FALSE;
02525 }
02526 
02527 
02528 /********************************************************************************************
02529 >   BOOL NodeBitmap::IsABitmap() const
02530 
02531     Author:     Justin_Flude (Xara Group Ltd) <camelotdev@xara.com>
02532     Created:    02/17/95
02533     Returns:    TRUE
02534     SeeAlso:    Node::IsABitmap
02535 ********************************************************************************************/
02536 
02537 BOOL NodeBitmap::IsABitmap() const
02538 {
02539     return TRUE;
02540 }
02541 
02542 
02543 
02544 /********************************************************************************************
02545 
02546 >   BOOL NodeBitmap::OnClick(DocCoord PointerPos,
02547                              ClickType Click,
02548                              ClickModifiers ClickMods,
02549                              Spread* pSpread)
02550 
02551     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02552     Created:    21/01/2004
02553     Inputs:     PointerPos - The Location of the mouse pointer at the time of the click
02554                 Click - The type of click received (single, double, drag etc)
02555                 ClickMods - The modifiers to the click (eg shift, control etc )
02556     Returns:    BOOL - TRUE if the node claims the click as its own and FALSE if it is
02557                 not interested in the click
02558     Purpose:    Allows the Node to respond to clicks by selecting its blobs or starting
02559                 drags etc.
02560                 This functions should be overridden in the all the NodeRenderableInk classes
02561                 so that this version never gets called. Eg the NodePath class might claim
02562                 the click if it happened over one of its unselected blobs.
02563 
02564 ********************************************************************************************/
02565 
02566 BOOL NodeBitmap::OnClick(DocCoord PointerPos,
02567                          ClickType Click,
02568                          ClickModifiers ClickMods,
02569                          Spread* pSpread)
02570 {
02571 PORTNOTE("other","OnClick - Remove XPE edit")
02572 #ifndef EXCLUDE_FROM_XARALX
02573     if (Click == CLICKTYPE_DOUBLE)
02574     {
02575         // We're going to start up a new dialog so we want to clear out any click
02576         // processing logic that may be in process...
02577         DocView* pDocView = DocView::GetCurrent();
02578         if (pDocView)
02579             pDocView->ClearClickState();
02580 
02581         // Invoke and XPE Edit operation
02582         OpDescriptor* pOpDesc = OpDescriptor::FindOpDescriptor(OPTOKEN_XPE_EDIT);
02583         if (pOpDesc)
02584         {
02585             pOpDesc->Invoke();
02586             return TRUE;
02587         }
02588     }
02589 #endif
02590     // did not use the click
02591     return FALSE;
02592 }
02593 
02594 
02595 
02596 
02597 /********************************************************************************************
02598 
02599 >   virtual void NodeBitmap::SetAspectRatio(double dExWidth, double dExHeight, BOOL bPathAndFill)
02600 
02601     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02602     Created:    27/01/2004
02603     Inputs:     dExWidth - Sample width (numerator)
02604                 dExHeight - Sample height (denominator)
02605                 bPathAndFill - Apply this logic to both the path and the bitmap fill???
02606     Returns:    -
02607     Purpose:    To reset the stored path and Parallelogram to retain their shape and scale
02608                 but to take on a new aspect ratio.
02609 
02610 ********************************************************************************************/
02611 
02612 void NodeBitmap::SetAspectRatio(double dExWidth, double dExHeight, BOOL bPathAndFill)
02613 {
02614 /*
02615     Gavin says:
02616     If the parallelogram is defined by the three points P0, P1, P2
02617     where P1-P0 is the x axis of the bitmap and P2-P0 is the y axis
02618     and the bitmap had old size W,H and new size NW, NH
02619     then the new parallelogram NP0,NP1,NP2 will be
02620         NP0 = P0
02621         NP1x = P0x+(P1x-P0x)*NW/W
02622         NP1y = P0y+(P1y-P0y)*NW/W
02623         NP2x = P0x+(P2x-P0x)*NH/H
02624         NP2y = P0y+(P2y-P0y)*NH/H
02625     The fourth points of the parallelogram can be found from the other three:
02626         P3 = P2+P1-P0
02627 
02628     If you dont want the centre to move then:
02629         C = (P1+P2)*0.5
02630         Dxx = (P1x-P0x)*NW/W
02631         Dxy = (P1y-P0y)*NW/W
02632         Dyx = (P2x-P0x)*NH/H
02633         Dyy = (P2y-P0y)*NH/H
02634         NP0x = (P1x+P2x-Dxx -Dyx)*0.5
02635         NP0y = (P1y+P2y-Dxy -Dyy)*0.5
02636         NP1x = NP0x+Dxx
02637         NP1y = NP0y+Dxy
02638         NP2x = NP0x+Dyx
02639         NP2y = NP0y+Dyy
02640         NP3x = NP0x+Dxx+Dyx
02641         NP3y = NP0y+Dxy+Dyy
02642 
02643     Phil says:
02644     Parallelogram points are stored in this order:
02645             3   <-  2
02646             v       ^
02647             0   ->  1
02648 */
02649     DocCoord p0 = Parallel[0];
02650     DocCoord p1 = Parallel[1];
02651     DocCoord p2 = Parallel[3];
02652 
02653     double              w = double(GetBitmap()->GetWidth());
02654     double              h = double(GetBitmap()->GetHeight());
02655 
02656     DocCoord C = DocCoord::OneHalf( p1, p2 );
02657     INT32 dxx = INT32(( p1.x - p0.x ) * dExWidth / w);
02658     INT32 dxy = INT32(( p1.y - p0.y ) * dExWidth / w);
02659     INT32 dyx = INT32(( p2.x - p0.x ) * dExHeight / h);
02660     INT32 dyy = INT32(( p2.y - p0.y ) * dExHeight / h);
02661 
02662     INT32 ox = INT32(( p1.x + p2.x - dxx - dyx ) * 0.5);
02663     INT32 oy = INT32(( p1.y + p2.y - dxy - dyy ) * 0.5);
02664     Parallel[0].x = ox;
02665     Parallel[0].y = oy;
02666     Parallel[1].x = ox+dxx;
02667     Parallel[1].y = oy+dxy;
02668     Parallel[3].x = ox+dyx;
02669     Parallel[3].y = oy+dyy;
02670     Parallel[2].x = ox+dxx+dyx;
02671     Parallel[2].y = oy+dxy+dyy;
02672 
02673     UpdateShape();
02674     InvalidateBoundingRect();
02675 }
02676 
02677 
02678 
02679 
02680 #if !defined(EXCLUDE_FROM_RALPH)
02681 //-----------------------------------------------------------------------------------------------
02682 
02683 // OpCreateNodeBitmap - the operation that is used to create a new NodeBitmap
02684 
02685 /********************************************************************************************
02686 
02687 >   BOOL OpCreateNodeBitmap::Init()
02688 
02689     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02690     Created:    31/1/95
02691     Inputs:     -
02692     Outputs:    -
02693     Returns:    TRUE if the operation could be successfully initialised 
02694                 FALSE if no more memory could be allocated 
02695                 
02696     Purpose:    OpCreateNodeBitmap initialiser method
02697     Errors:     ERROR will be called if there was insufficient memory to allocate the 
02698                 operation.
02699     SeeAlso:    -
02700 
02701 ********************************************************************************************/
02702 
02703 BOOL OpCreateNodeBitmap::Init()
02704 {
02705     return (RegisterOpDescriptor(
02706                                 0,
02707                                 0,
02708                                 CC_RUNTIME_CLASS(OpCreateNodeBitmap),
02709                                 OPTOKEN_CREATENODEBITMAP,
02710                                 OpCreateNodeBitmap::GetState,
02711                                 0,  /* help ID */
02712                                 0,
02713                                 0   /* bitmap ID */));
02714 }               
02715     
02716 /********************************************************************************************
02717 
02718 >   OpState OpCreateNodeBitmap::GetState(String_256*, OpDescriptor*)
02719 
02720     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02721     Created:    31/1/95
02722     Inputs:     -
02723     Outputs:    -
02724     Returns:    The state of the OpCreateNodeBitmap operation
02725     Purpose:    For finding the OpCreateNodeBitmap's state. 
02726     Errors:     -
02727     SeeAlso:    -
02728 
02729 ********************************************************************************************/
02730 
02731 OpState OpCreateNodeBitmap::GetState(String_256* UIDescription, OpDescriptor*)
02732 {
02733     OpState OpSt;
02734 
02735     // If there are no open documents, you can't create a node bitmap
02736     OpSt.Greyed = (Document::GetSelected() == NULL);
02737 
02738     return(OpSt);
02739 }
02740 
02741 /********************************************************************************************
02742 
02743 >   void OpCreateNodeBitmap::DoWithParam(OpDescriptor* OpDesc, OpParam* pOpParam)
02744 
02745     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02746     Created:    31/1/95
02747     Inputs:     -
02748     Outputs:    -
02749     Returns:    -
02750     Purpose:    Creates a new bitmap object
02751     Errors:     -
02752     SeeAlso:    -
02753 
02754 ********************************************************************************************/
02755 
02756 void OpCreateNodeBitmap::DoWithParam(OpDescriptor* OpDesc, OpParam* pOpParam)
02757 {
02758     BOOL ok = FALSE;
02759 
02760     ERROR3IF(pOpParam == NULL, "NULL OpParam passed to OpCreateNodeBitmap"); 
02761 
02762     KernelBitmap* KernelBmp = (KernelBitmap*)(void *)pOpParam->Param1;
02763     PageDropInfo* pDropInfo = (PageDropInfo*)(void *)pOpParam->Param2;
02764 
02765     DocView* pDocView   = DocView::GetCurrent();
02766     Spread* pSpread     = pDropInfo->pSpread;
02767     DocCoord DropPos    = pDropInfo->DropPos;
02768 
02769 
02770     NodeBitmap* pNodeBitmap = new NodeBitmap();
02771     if ((pNodeBitmap == NULL) || (!pNodeBitmap->SetUpPath(12,12)))
02772         goto EndOp;
02773 
02774     // Attach the Dropped Bitmap to our Node
02775     pNodeBitmap->GetBitmapRef()->Attach(KernelBmp);
02776     if (pNodeBitmap->GetBitmap() != KernelBmp)
02777     {
02778         // It didn't use the bitmap we gave it, so we can delete it
02779         delete KernelBmp;
02780     }
02781 
02782     {
02783         DocRect BoundsRect;
02784         BitmapInfo Info;
02785 
02786         // Import worked - try to add the bitmap object into the tree.
02787         // First, set the rectangle to the right size for the bitmap...
02788         pNodeBitmap->GetBitmap()->ActualBitmap->GetInfo(&Info);
02789 
02790         // When pasting from XPE we don't have a docview, so fabricate 96dpi measurement (NB this gives
02791         // no remainder, just expressed as division to make derivation clear)
02792         FIXED16     pixHorz = NULL != pDocView ? pDocView->GetPixelWidth()  : FIXED16( 72000 / 96 );
02793         FIXED16     pixVert = NULL != pDocView ? pDocView->GetPixelHeight() : FIXED16( 72000 / 96 );
02794         const INT32 HPixelSize = ( pixHorz + 0.5 ).MakeLong();  // Size of output pixel in millipoints
02795         const INT32 VPixelSize = ( pixVert + 0.5 ).MakeLong();  // Size of output pixel in millipoints
02796 
02797         // Make sure that this is snapped to a pixel grid
02798         BoundsRect.lo.x = DropPos.x - ( Info.RecommendedWidth / 2 );
02799         BoundsRect.lo.y = DropPos.y - ( Info.RecommendedHeight / 2 );
02800         BoundsRect.lo.x = GridLock(BoundsRect.lo.x, HPixelSize);
02801         BoundsRect.lo.y = GridLock(BoundsRect.lo.y, VPixelSize);
02802         // And now add in the rest of the bounds
02803         BoundsRect.hi.x = BoundsRect.lo.x + Info.RecommendedWidth;
02804         BoundsRect.hi.y = BoundsRect.lo.y + Info.RecommendedHeight;
02805         BoundsRect.hi.x = GridLock(BoundsRect.hi.x, HPixelSize);
02806         BoundsRect.hi.y = GridLock(BoundsRect.hi.y, VPixelSize);
02807 
02808         // And set this in our bitmap node
02809         pNodeBitmap->CreateShape(BoundsRect);
02810 
02811         // Set the default attrs
02812         // This Must be done before the NodeBitmap is inserted into the tree
02813         if (!pNodeBitmap->ApplyDefaultBitmapAttrs(this))
02814             goto EndOp;
02815             
02816         // Insert the node
02817         if (!DoInsertNewNode(pNodeBitmap, pSpread, TRUE))
02818         {
02819             // It didn't work - delete the sub-tree we just created.
02820             delete pNodeBitmap;
02821             goto EndOp;
02822         }
02823     
02824         // Get the spread's bounding rectangle and convert it to spread coords.
02825         DocRect SpreadRect = pSpread->GetPasteboardRect();
02826         pSpread->DocCoordToSpreadCoord(&SpreadRect);
02827 
02828         // If bounding box off the spread - limit it to the edge of the spread:
02829 
02830         // (a) Horizontal adjustment
02831         DocCoord Offset(0,0);
02832         if (BoundsRect.lo.x < SpreadRect.lo.x)
02833             Offset.x += (SpreadRect.lo.x - BoundsRect.lo.x);
02834         else if (BoundsRect.hi.x > SpreadRect.hi.x)
02835             Offset.x -= (BoundsRect.hi.x - SpreadRect.hi.x);
02836 
02837         // (b) Vertical adjustment (most useful to clip hi co-ords)
02838         if (BoundsRect.hi.y > SpreadRect.hi.y)
02839             Offset.y -= (BoundsRect.hi.y - SpreadRect.hi.y);
02840         else
02841         if (BoundsRect.lo.y < SpreadRect.lo.y)
02842             Offset.y += (SpreadRect.lo.y - BoundsRect.lo.y);
02843 
02844         // Actually do the translation if needed
02845         if( 0 != Offset.x ||
02846             0 != Offset.y )
02847         {
02848             Offset.x = GridLock(Offset.x, HPixelSize);
02849             Offset.y = GridLock(Offset.y, VPixelSize);
02850 
02851             // Build the matrix and transform the bitmap to the correct place
02852             Trans2DMatrix Xlate(Offset.x, Offset.y);
02853             pNodeBitmap->Transform(Xlate);
02854         }
02855 
02856         // We can't do this without a docview
02857         if( NULL != pDocView )
02858         {
02859             // Does the bitmap fit with our current view?
02860             DocRect     docrectBounds = pNodeBitmap->GetBoundingRect();
02861             DocRect     docrectView = pDocView->GetDocViewRect( pSpread );
02862             pSpread->DocCoordToSpreadCoord( &docrectView );
02863             if( ( docrectBounds.lo.x < docrectView.lo.x ||
02864                   docrectBounds.lo.y < docrectView.lo.y ||
02865                   docrectBounds.hi.x > docrectView.hi.x ||
02866                   docrectBounds.hi.y > docrectView.hi.y ) &&
02867                   BaseBitmapFilter::GetZoomOnImport() )
02868             {
02869                 // Calculate bounding rect of view plus new photo and then make sure that edges in
02870                 // in both axes grow by same amount. We make use of the fact that zoom code only allows
02871                 // zooming in both axes by the same amount, so we don't need to make sure that growth in
02872                 // both axes is by the same percentage.
02873                 docrectBounds = docrectBounds.Union( docrectView );
02874                 if( docrectView.lo.x - docrectBounds.lo.x > docrectBounds.hi.x - docrectView.hi.x )
02875                     docrectBounds.hi.x = docrectView.hi.x + docrectView.lo.x - docrectBounds.lo.x;
02876                 else
02877                     docrectBounds.lo.x = docrectView.lo.x - docrectBounds.hi.x + docrectView.hi.x;
02878                 if( docrectView.lo.y - docrectBounds.lo.y > docrectBounds.hi.y - docrectView.hi.y )
02879                     docrectBounds.hi.y = docrectView.hi.y + docrectView.lo.y - docrectBounds.lo.y;
02880                 else
02881                     docrectBounds.lo.y = docrectView.lo.y - docrectBounds.hi.y + docrectView.hi.y;
02882                 
02883                 // No, zoom out so the all the bitmap can be seen
02884                 OpZoomFitRectDescriptor* pOpDesc = (OpZoomFitRectDescriptor*)OpDescriptor::FindOpDescriptor( OPTOKEN_ZOOMRECT );
02885                 if( NULL != pOpDesc )
02886                 {
02887                     pOpDesc->SetZoomRect( docrectBounds );
02888                     pOpDesc->Invoke();
02889                 }
02890 
02891                 // Keep user informed about the zoom operation
02892                 if( !BaseBitmapFilter::GetWarnedZoomOnImport() )
02893                 {
02894                     ErrorInfo   Info;
02895                     memset( &Info, 0, sizeof(Info) );
02896                     Info.ErrorMsg   = _R(IDS_ZOOM_ON_IMAGE_IMPORT);
02897                     Info.Button[0]  = _R(IDS_OK);
02898                     Info.Button[1]  = _R(IDS_DONT_SHOW_AGAIN);
02899                     Info.OK         = 1;
02900                     if( _R(IDS_DONT_SHOW_AGAIN) == UINT32(InformMessage( &Info )) )
02901                         BaseBitmapFilter::SetWarnedZoomOnImport( TRUE );
02902                 }
02903             }
02904         }
02905     }
02906 
02907     ok = TRUE;
02908 
02909 EndOp:
02910     if (!ok)
02911         FailAndExecute();
02912 
02913     End();
02914 }
02915 
02916 void OpCreateNodeBitmap::GetOpName(String_256* OpName)
02917 {
02918     OpName->Load(_R(IDS_K_NODEBMP_CREATEBITMAP));
02919 }
02920 
02921 #endif
02922 
02924 //
02925 //              ChangeBitmapPtrAction class                                                              //
02926 //
02928 
02929 /********************************************************************************************
02930 
02931 >   ChangeBitmapPtrAction::ChangeBitmapPtrAction()
02932 
02933     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02934     Created:    27/6/95
02935     Inputs:     -
02936     Outputs:    -
02937     Returns:    -
02938     Purpose:    Constructor for the action to undo fill modification
02939     Errors:     -
02940     SeeAlso:    -
02941 
02942 ********************************************************************************************/
02943 
02944 ChangeBitmapPtrAction::ChangeBitmapPtrAction()
02945 {
02946     pChangedBmpNode = NULL;
02947 }
02948 
02949 /********************************************************************************************
02950 
02951 >   ActionCode ChangeBitmapPtrAction::Init( Operation* pOp,
02952                                             ActionList* pActionList,
02953                                             Action** NewAction)
02954 
02955     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02956     Created:    27/6/95
02957     Inputs:     pOp is the pointer to the operation to which this action belongs
02958                 pActionList is the action list to which this action should be added
02959     Outputs:    NewAction is a pointer to a pointer to an action, allowing the function to return
02960                 a pointer to the created action
02961     Returns:    ActionCode, one of AC_OK, AC_NO_RECORD or AC_FAIL
02962     Purpose:    This is the function which creates an instance of this action. If there is no room 
02963                 in the undo buffer (which is determined by the base class Init function called within)
02964                 the function will either return AC_NO_RECORD which means the operation can continue, 
02965                 but no undo information needs to be stored, or AC_OK which means the operation should
02966                 continue AND record undo information. If the function returns AC_FAIL, there was not 
02967                 enough memory to record the undo information, and the user has decided not to continue
02968                 with the operation.
02969     Errors:     -
02970     SeeAlso:    Action::Init()
02971 
02972 ********************************************************************************************/
02973 
02974 ActionCode ChangeBitmapPtrAction::Init( Operation* pOp,
02975                                         ActionList* pActionList,
02976                                         Action** NewAction)
02977 {
02978     UINT32 ActSize = sizeof(ChangeBitmapPtrAction);
02979     ActionCode Ac = Action::Init( pOp, pActionList, ActSize, CC_RUNTIME_CLASS(ChangeBitmapPtrAction), NewAction);
02980 
02981     TRACEUSER( "Will", _T("Creating ChangeBitmapPtrAction") );
02982 
02983     return Ac;
02984 }
02985 
02986 /********************************************************************************************
02987 
02988 >   void ChangeBitmapPtrAction::StoreChanges(NodeBitmap* pBmpNode)
02989 
02990     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
02991     Created:    27/6/95
02992     Inputs:     pBmpNode, is the NodeBitmap that is being changed.
02993     Outputs:    -
02994     Returns:    -
02995     Purpose:    This function initialises the array pointers in this action. Note that the 
02996                 variable NumElements is initialised in the Init function
02997     Errors:     -
02998     SeeAlso:    -
02999 
03000 ********************************************************************************************/
03001 
03002 void ChangeBitmapPtrAction::StoreChanges(NodeBitmap* pBmpNode)
03003 {
03004     ERROR3IF(pBmpNode == NULL, "NodeBitmap is NULL in ChangeBitmapPtrAction::StoreChanges()");
03005     if (pBmpNode == NULL)
03006         return;
03007 
03008     pChangedBmpNode = pBmpNode;
03009     BitmapRef.Attach(pBmpNode->GetBitmap(), pOperation->GetWorkingDoc());
03010     BitmapRef.RemoveFromTree();
03011 }
03012 
03013 /********************************************************************************************
03014 
03015 >   ActionCode ChangeBitmapPtrAction::Execute()
03016 
03017     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
03018     Created:    27/6/95
03019     Inputs:     -
03020     Outputs:    -
03021     Returns:    Action code, one of AC_OK, AC_NORECORD or AC_FAIL.
03022     Purpose:    This is the virtual function that is called when the action is executed
03023                 by the Undo/Redo system. This is the function that actually undoes the 
03024                 ChangeBitmapPtr action by changing the attribute values, and
03025                 records redo information from the current values.
03026     Errors:     -
03027     SeeAlso:    -
03028 
03029 ********************************************************************************************/
03030 
03031 ActionCode ChangeBitmapPtrAction::Execute()
03032 {
03033     ChangeBitmapPtrAction* ModAction;
03034     
03035     ActionCode Act;
03036     Act = ChangeBitmapPtrAction::Init(pOperation, pOppositeActLst, (Action**)(&ModAction));
03037     if (Act == AC_FAIL)
03038         return AC_FAIL;
03039 
03040     // Store away the current bitmap attached to the node
03041     ModAction->StoreChanges(pChangedBmpNode);
03042 
03043     // Now restore the old one
03044     pChangedBmpNode->GetBitmapRef()->Attach(BitmapRef.GetBitmap(), pOperation->GetWorkingDoc());
03045 
03046     ((UndoableOperation*)pOperation)->
03047             DoInvalidateNodeRegion((NodeRenderableInk*)pChangedBmpNode, TRUE);
03048 
03049         return Act;
03050 }

Generated on Sat Nov 10 03:45:58 2007 for Camelot by  doxygen 1.4.4