nodeliveeffect.cpp

Go to the documentation of this file.
00001 // $Id: nodeliveeffect.cpp 1688 2006-08-10 12:05:20Z gerry $
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 /*
00100 */
00101 
00102 #include "camtypes.h"
00103 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00104 //#include "node.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00105 #include "nodeliveeffect.h"
00106 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00107 //#include "xpehost.h"
00108 //#include "dibutil.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 #include "cxftags.h"
00110 //#include "cxfrec.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00111 #include "blobs.h"
00112 //#include "bitmap.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00113 #include "bmpcomp.h"    
00114 #include "oilbitmap.h"
00115 #include "bshadow.h"
00116 //#include "fillval.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00117 //#include "becomea.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00118 #include "nodepath.h"
00119 #include "lineattr.h"
00120 #include "blndtool.h"
00121 #include "nodebmp.h"
00122 #include "attrmap.h"
00123 
00124 // Resource headers
00125 //#include "resource.h"
00126 //#include "mario.h"
00127 //#include "phil.h"
00128 //#include "tim.h"
00129 #include "transop.h"
00130 //#include "opfeathr.h"
00131 
00132 #include "pmaskrgn.h"
00133 #include "scanrr.h"
00134 
00135 #include "ophist.h"
00136 
00137 DECLARE_SOURCE( "$Revision: 1688 $" );
00138 
00139 CC_IMPLEMENT_DYNCREATE(NodeBitmapEffect, NodeEffect)
00140 CC_IMPLEMENT_DYNCREATE(NodeLiveEffect, NodeBitmapEffect)
00141 CC_IMPLEMENT_DYNCREATE(NodeLockedEffect, NodeBitmapEffect)
00142 #ifdef FEATHER_EFFECT
00143 CC_IMPLEMENT_DYNCREATE(NodeFeatherEffect, NodeLiveEffect)
00144 #endif
00145 CC_IMPLEMENT_DYNAMIC(LiveEffectRecordHandler, CamelotRecordHandler)
00146 
00147 // Declare smart memory handling in Debug builds
00148 #define new CAM_DEBUG_NEW
00149 
00150 
00151 #ifdef DEBUG
00152 #define DEBUGATTACH(STATE, LABEL) {STATE.AttachToDoc(LABEL);}
00153 #else
00154 #define DEBUGATTACH(STATE, LABEL) {}
00155 #endif
00156 
00157 // Define this if you think captured shapes need a 1 pixel border to allow for anti-aliasing
00158 #define CAPTURE_BORDER 1
00159 
00160 // Define this if you want to test the Atomic skipping of live, locked and feather tags
00161 // during XAR file loading
00162 #ifdef DEBUG
00163 //  #define TEST_NO_EFFECT_LOADING
00164 #endif
00165 
00166 
00167 
00168 /********************************************************************************************
00169 
00170     Preference: DefaultLivePixelsPerInch
00171     Section:    Effects
00172     Range:      0-72000
00173     Purpose:    
00174 
00175 ********************************************************************************************/
00176 
00177 UINT32 NodeBitmapEffect::DefaultLivePixelsPerInch = 96;     // default is 96 dpi
00178 
00179 
00180 
00181 
00182 /********************************************************************************************
00183 
00184     Preference: DefaultLockedPixelsPerInch
00185     Section:    Effects
00186     Range:      1-72000
00187     Purpose:    
00188 
00189 ********************************************************************************************/
00190 
00191 UINT32 NodeBitmapEffect::DefaultLockedPixelsPerInch = 150;      // default is 150 dpi
00192 
00193 
00194 
00195 
00196 /********************************************************************************************
00197 
00198     Preference: GroupPixelsPerInch
00199     Section:    Effects
00200     Range:      0-72000
00201     Purpose:    
00202 
00203 ********************************************************************************************/
00204 
00205 UINT32 NodeBitmapEffect::GroupPixelsPerInch = 0;                // default is "Automatic" dpi
00206 
00207 
00208 
00209 
00210 /********************************************************************************************
00211 
00212     Preference: ShadowPixelsPerInch
00213     Section:    Effects
00214     Range:      0-72000
00215     Purpose:    
00216 
00217 ********************************************************************************************/
00218 
00219 UINT32 NodeBitmapEffect::ShadowPixelsPerInch = 0;               // default is "Automatic" dpi
00220 
00221 
00222 
00223 
00224 /********************************************************************************************
00225 
00226     Preference: DefaultLocked
00227     Section:    Effects
00228     Range:      FALSE-TRUE
00229     Purpose:    
00230 
00231 ********************************************************************************************/
00232 
00233 BOOL NodeBitmapEffect::DefaultLocked = FALSE;               // Default is to create live effects
00234 
00235 
00236 
00237 
00238 /********************************************************************************************
00239 
00240 >   static BOOL NodeBitmapEffect::Init()
00241 
00242     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00243     Created:    08/09/2004
00244     Inputs:     -
00245     Purpose:    Initialise the NodeBitmapEffect class
00246 
00247 ********************************************************************************************/
00248 
00249 BOOL NodeBitmapEffect::Init()
00250 {
00251     if (Camelot.DeclareSection( _T("Effects"), 10))
00252     {
00253         Camelot.DeclarePref(NULL, _T("DefaultLivePixelsPerInch"), (INT32*)&DefaultLivePixelsPerInch, 0, 72000);
00254         Camelot.DeclarePref(NULL, _T("DefaultLockedPixelsPerInch"), (INT32*)&DefaultLockedPixelsPerInch, 1, 72000);
00255         Camelot.DeclarePref(NULL, _T("DefaultLocked"), (INT32*)&DefaultLocked, FALSE, TRUE);
00256         Camelot.DeclarePref(NULL, _T("GroupPixelsPerInch"), (INT32*)&GroupPixelsPerInch, 0, 72000);
00257         Camelot.DeclarePref(NULL, _T("ShadowPixelsPerInch"), (INT32*)&ShadowPixelsPerInch, 0, 72000);
00258     }
00259 
00260     return TRUE;
00261 }
00262 
00263 
00264 
00265 
00266 /***********************************************************************************************
00267 
00268 >   NodeBitmapEffect::NodeBitmapEffect(Node*    ContextNode,
00269                         AttachNodeDirection Direction,
00270                         const DocRect&      BoundingRect,
00271                         BOOL                Locked = FALSE,
00272                         BOOL                Mangled = FALSE,
00273                         BOOL                Marked = FALSE,
00274                         BOOL                Selected = FALSE,
00275                         BOOL                Renderable = FALSE
00276                         )
00277 
00278     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00279     Created:    07/09/2004
00280     Inputs:     ContextNode: Pointer to a node which this node is to be attached to.
00281                 MonoOn Direction: MonoOff
00282                 Specifies the direction in which the node is to be attached to the
00283                 ContextNode. The values this variable can take are as follows:
00284                                   
00285                 PREV      : Attach node as a previous sibling of the context node
00286                 NEXT      : Attach node as a next sibling of the context node
00287                 FIRSTCHILD: Attach node as the first child of the context node
00288                 LASTCHILD : Attach node as a last child of the context node
00289 
00290                 BoundingRect: Bounding rectangle
00291 
00292                 The remaining inputs specify the status of the node:
00293             
00294                 Locked:     Is node locked ?
00295                 Mangled:    Is node mangled ?
00296                 Marked:     Is node marked ?
00297                 Selected:   Is node selected ?
00298 
00299     Purpose:    This constructor initialises the nodes flags and links it to ContextNode in the
00300                 direction specified by Direction. All neccesary tree links are updated.
00301     Note:       SetUpShape() must be called before the NodeRegularShape is in a state in which
00302                 it can be used.
00303     SeeAlso:    NodeRegularShape::SetUpShape
00304     Errors:     An ENSURE will occur if ContextNode is NULL
00305 
00306 ***********************************************************************************************/
00307 NodeBitmapEffect::NodeBitmapEffect(Node* ContextNode,  
00308                     AttachNodeDirection Direction,  
00309                     BOOL Locked, 
00310                     BOOL Mangled,  
00311                     BOOL Marked, 
00312                     BOOL Selected    
00313               ) : NodeEffect(ContextNode, Direction, Locked, Mangled, Marked, Selected )
00314 {                         
00315     m_pEditsDoc = NULL;
00316     m_bHasChangedRecently = FALSE;
00317     m_strPostProID = String(_T(""));
00318     m_strDisplayName = String(_T(""));
00319     m_rectDirectBitmap = DocRect(0,0,0,0);
00320 }
00321 
00322 
00323 
00324 
00325 /*********************************************************************************************
00326 
00327 >   NodeBitmapEffect::NodeBitmapEffect() 
00328 
00329     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00330     Created:    07/09/2004
00331     Purpose:    
00332     Note:       
00333     SeeAlso:    
00334 
00335 **********************************************************************************************/
00336 NodeBitmapEffect::NodeBitmapEffect() : NodeEffect()
00337 {
00338     m_pEditsDoc = NULL;
00339     m_bHasChangedRecently = FALSE;
00340     m_strPostProID = String( _T("") );
00341     m_strDisplayName = String( _T("") );
00342 }
00343 
00344 
00345 
00346 
00347 /*********************************************************************************************
00348 
00349 >   NodeBitmapEffect::~NodeBitmapEffect() 
00350 
00351     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00352     Created:    07/09/2004
00353     Purpose:    Destructor
00354     Note:       
00355     SeeAlso:    
00356 
00357 **********************************************************************************************/
00358 NodeBitmapEffect::~NodeBitmapEffect()
00359 {
00360     m_pEditsDoc = NULL;             // m_pEditsDoc is a smart pointer so NULLing it Releases the COM interface
00361                                     // and releases any memory
00362     // Note that NodeBitmapEffect stores original bitmap data in the cache
00363     // but this destructor relies no derived classes clareing cached data when they
00364     // are destroyed for efficiency.
00365 }
00366 
00367 
00368 
00369 
00370 /********************************************************************************************
00371 
00372 >   virtual double NodeBitmapEffect::GetPixelsPerInch()
00373 
00374     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00375     Created:    09/09/2004
00376     Inputs:     - 
00377     Outputs:    Pixel resolution for this live effect bitmap in pixels per inch (double)
00378     Returns:        Description of the group node 
00379     Purpose:    To get the required/stored pixel res of this node
00380     Errors:     -
00381     SeeAlso:    -
00382 
00383 ********************************************************************************************/
00384 
00385 double NodeBitmapEffect::GetPixelsPerInch()
00386 {
00387     double dPPI = 0.0;
00388 
00389     if (m_dPixelsPerInch==0)
00390     {
00391         // 0 means automatic
00392         // Automatic means get resolution in context
00393         // Context means either:
00394         //  * Respond to a direct bitmap below us
00395         //  * or respond to a fixed resolution above us in the tree
00396         //  * or get resolution from current view
00397         BOOL bDirectResolution = GetChildDirectBitmap(NULL, NULL, NULL, NULL, NULL, &dPPI);
00398         if (bDirectResolution && dPPI!=0)
00399             return dPPI;
00400 
00401         Node* pParent = this->FindParent();
00402 //      while (pParent && (pParent->IsBitmapEffect() || pParent->IsNodeHidden()))
00403         while (pParent && !pParent->IsLayer())
00404         {
00405             if (pParent->IsBitmapEffect())
00406             {
00407                 dPPI = ((NodeBitmapEffect*)pParent)->GetPixelsPerInchValue();
00408                 if (dPPI!=0)
00409                     break;
00410             }
00411 
00412             pParent = pParent->FindParent();
00413         }
00414 
00415         if (dPPI==0)
00416         {
00417             // See also OpEffectLock::DoEffectNodeOp
00418             View* pView = View::GetCurrent();
00419             if (pView) dPPI = 72000.0 / pView->GetPixelWidth().MakeDouble();
00420         }
00421     }
00422 
00423     if (dPPI==0)
00424         dPPI = m_dPixelsPerInch;
00425 
00426     if (dPPI==0)
00427     {
00428         // Shouldn't ever reach this clause but just in case...
00429         ERROR3("GetPixelsPerInch can't get sensible PPI so defaulting to 96");
00430         dPPI = 96.0;
00431     }
00432 
00433     return dPPI;
00434 };
00435 
00436 
00437 
00438 
00439 /********************************************************************************************
00440 
00441 >   virtual void NodeBitmapEffect::SetPixelsPerInch(double dPixelsPerInch)
00442 
00443     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00444     Created:    09/09/2004
00445     Inputs:     - 
00446     Outputs:    Pixel resolution for this live effect bitmap in pixels per inch (double)
00447     Retuns:     Description of the group node 
00448     Purpose:    To get the required/stored pixel res of this node
00449     Errors:     -
00450     SeeAlso:    -
00451 
00452 ********************************************************************************************/
00453 
00454 void NodeBitmapEffect::SetPixelsPerInch(double dPixelsPerInch)
00455 {
00456     m_dPixelsPerInch = dPixelsPerInch;
00457 };
00458 
00459 /********************************************************************************************
00460 
00461 >   virtual double NodeBitmapEffect::GetPixelWidth()
00462 
00463     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00464     Created:    08/09/2004
00465     Inputs:     - 
00466     Outputs:    Pixel width for live effect bitmap in millipoints (double)
00467     Retuns:     Description of the group node 
00468     Purpose:    To get the required/stored pixel width of this node
00469     Errors:     -
00470     SeeAlso:    -
00471 
00472 ********************************************************************************************/
00473 
00474 /*double NodeBitmapEffect::GetPixelWidth()
00475 {
00476     return 72000.0 / GetPixelsPerInch();
00477 };*/
00478 
00479 
00480 
00481 
00482 /********************************************************************************************
00483 
00484 >   BOOL NodeBitmapEffect::GetOriginalBitmap(LPBITMAPINFO* plpInfo, LPBYTE* plpBits, DocRect* pRect = NULL)
00485 
00486     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00487     Created:    10/09/2004
00488     Inputs:     -
00489     Outputs:    lpInfo - reference to LPBITMAPINFO pointer to be written to for bitmap info
00490                 lpBits - reference to LPBYTE pointer to be written to for bitmap data
00491     Purpose:    -
00492 
00493 ********************************************************************************************/
00494 
00495 BOOL NodeBitmapEffect::GetOriginalBitmap(LPBITMAPINFO* plpInfo, LPBYTE* plpBits, DocRect* pRect)
00496 {
00497     // ---------------------------------------------------------
00498     // New!
00499     // Discover whether our child can supply a DirectBitmap for
00500     // us to use as the original for processing...
00501     //
00502     LPBITMAPINFO lpLocalInfo = NULL;
00503     LPBYTE lpLocalBits = NULL;
00504     DocRect rectLocal;
00505     BOOL bFound = GetChildDirectBitmap(NULL, &lpLocalInfo, &lpLocalBits, &rectLocal);
00506     if (bFound)
00507     {
00508         if (plpInfo)    *plpInfo = lpLocalInfo;
00509         if (plpBits)    *plpBits = lpLocalBits;
00510         if (pRect)      *pRect = rectLocal;
00511         return (lpLocalInfo!=NULL && lpLocalBits!=NULL);        // Only return TRUE if we got good bitmap data
00512     }
00513     // ---------------------------------------------------------
00514 
00515     CBitmapCache* pBitmapCache = Camelot.GetBitmapCache();
00516     if (pBitmapCache)
00517     {
00518         // Look for a cached bitmap at the appropriate pixel size...
00519         CBitmapCacheKey inky(this, GetPixelWidth());                    // Get cached BMP for this node at our dpi
00520         CCachedBitmap cbmp;
00521         BOOL bFound = pBitmapCache->Lookup(inky, cbmp);
00522         if (bFound)
00523         {
00524             if (plpInfo)    *plpInfo = cbmp.pbmpInfo;
00525             if (plpBits)    *plpBits = cbmp.pbmpBits;
00526             if (pRect)      *pRect = cbmp.GetCachedRect();
00527             return TRUE;
00528         }
00529     }
00530 
00531     if (plpInfo)    *plpInfo = NULL;
00532     if (plpBits)    *plpBits = NULL;
00533 
00534     return FALSE;
00535 }
00536 
00537 
00538 
00539 
00540 /********************************************************************************************
00541 
00542 >   Void NodeBitmapEffect::SetOriginalBitmap(LPBITMAPINFO lpInfo, LPBYTE lpBits, DocRect rect)
00543 
00544     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00545     Created:    13/09/2004
00546     Inputs:     -
00547     Outputs:    lpInfo - reference to LPBITMAPINFO pointer for bitmap info
00548                 lpBits - reference to LPBYTE pointer for bitmap data
00549     Purpose:    -
00550 
00551 ********************************************************************************************/
00552 
00553 void NodeBitmapEffect::SetOriginalBitmap(LPBITMAPINFO lpInfo, LPBYTE lpBits, DocRect rect)
00554 {
00555     CBitmapCache* pBitmapCache = Camelot.GetBitmapCache();
00556     if (pBitmapCache==NULL)
00557         return;
00558 
00559     if (rect.IsEmpty())
00560     {
00561         rect = GetChildBoundingRect();
00562         rect.Inflate(CAPTURE_BORDER*(INT32)GetPixelWidth());
00563     }
00564 
00565     CBitmapCacheKey inky(this, GetPixelWidth());                        // Get cached BMP for this node at our dpi
00566 
00567     // Deallocate any cached DIB here
00568     CCachedBitmap cbmp;
00569     BOOL bFound = pBitmapCache->Lookup(inky, cbmp);
00570     if (bFound)
00571     {
00572         pBitmapCache->RemoveBitmap(inky);
00573         cbmp.Release();
00574     }
00575 
00576     if (lpInfo && lpBits)
00577     {
00578         cbmp.pbmpInfo = lpInfo;
00579         cbmp.pbmpBits = lpBits;
00580         cbmp.SetCachedRect(rect);
00581         cbmp.nPriority = CACHEPRIORITY_TEMPBITMAP_HIGH;
00582 
00583         pBitmapCache->StoreBitmap(inky, cbmp);
00584     }
00585 }
00586 
00587 /********************************************************************************************
00588 
00589 >   virtual BOOL NodeBitmapEffect::GetChildDirectBitmap(RenderRegion* pRender,
00590                                                         LPBITMAPINFO* plpInfo = NULL,
00591                                                         LPBYTE* plpBits = NULL,
00592                                                         DocRect* pRect = NULL,
00593                                                         Matrix* pMat = NULL,
00594                                                         double* pdRes = NULL
00595                                                         )
00596 
00597     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00598     Created:    26/07/2005
00599     Inputs:     -
00600     Outputs:    lpInfo - reference to LPBITMAPINFO pointer to be written to for bitmap info
00601                 lpBits - reference to LPBYTE pointer to be written to for bitmap data
00602     Purpose:    -
00603 
00604 ********************************************************************************************/
00605 
00606 BOOL NodeBitmapEffect::GetChildDirectBitmap(RenderRegion* pRender,
00607                                             LPBITMAPINFO* plpInfo,
00608                                             LPBYTE* plpBits,
00609                                             DocRect* pRect,
00610                                             Matrix* pMat,
00611                                             double* pdRes
00612                                             )
00613 {
00614     NodeRenderableInk* pInkNode = GetInkNodeFromController();
00615     if (pInkNode==NULL)
00616         return FALSE;
00617 
00618     // This is the point to choke off all DirectBitmap handling if required
00619     // by returning FALSE;
00620 
00621 // TEMP BODGE! DO NOT RELEASE!
00622 //return FALSE;
00623     if (!EnableDirectCapture())
00624         return FALSE;
00625 
00626     return pInkNode->GetDirectBitmap(pRender, plpInfo, plpBits, pRect, pMat, pdRes);
00627 }
00628 
00629 
00630 
00631 
00632 /********************************************************************************************
00633 
00634 >   BOOL NodeBitmapEffect::GetDirectBitmap(RenderRegion* pRender, LPBITMAPINFO* plpInfo, LPBYTE* plpBits, DocRect* pRect, Matrix* pMat, double* pdRes)
00635 
00636     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00637     Created:    28/07/2005
00638     Inputs:     pMat    - pointer to matrix awaiting update
00639     Outputs:    plpInfo - LPBITMAPINFO pointer describing bitmap
00640                 plpBits - LPBYTE pointer to bitmap data
00641                 pRect   - rect of Original bitmap data
00642                 pMat    - matrix describing transform from pRect to this instance on the page
00643                 pdRes   - resolution of this bitmap (dpi)
00644     Returns:    TRUE if this node can supply direct bitmap data to the caller
00645                 FALSE otherwise
00646     Purpose:    Return details of direct bitmap to caller (caller is usually a NodeBitmapEffect)
00647 
00648 ********************************************************************************************/
00649 
00650 BOOL NodeBitmapEffect::GetDirectBitmap(RenderRegion* pRender, LPBITMAPINFO* plpInfo, LPBYTE* plpBits, DocRect* pRect, Matrix* pMat, double* pdRes)
00651 {
00652     DocRect rectDirect;
00653     Matrix matLocalTransform;
00654     double dResolution = 0;
00655 
00656     // We don't change our child's instance transformation or resolution
00657     // So just get them directly from the child
00658     BOOL bChildDirect = GetChildDirectBitmap(pRender, NULL, NULL, NULL, &matLocalTransform, &dResolution);
00659     if (pMat)   *pMat = matLocalTransform;
00660     if (pdRes)  *pdRes = dResolution;
00661 
00662     // Initial response is to simply get the cached results of our processing
00663     // (See also HasCachedDirectBitmap())
00664     GetProcessedBitmap(bChildDirect && !matLocalTransform.IsIdentity(), plpInfo, plpBits, &rectDirect); // Rect is in DirectBitmap domain
00665     if (pRect)  *pRect = rectDirect;
00666 
00667     // We should return our native res if our child didn't supply one
00668     // So that callers can check whether they have the same res and optionally make a direct connection
00669     // to our bitmap.
00670     if (!bChildDirect && pdRes)
00671                 *pdRes = GetPixelsPerInch();
00672 
00673     // If we have effect attrs applied then we must make a subtree bitmap to capture them
00674     if (plpInfo && plpBits && HasEffectAttrs())
00675     {
00676         AttrFillGeometry* pTranspAttr = NULL;
00677         double dPixelWidth = GetPixelWidth();
00678 
00679         // Lookup processed bitmap in cache 
00680         CBitmapCache* pBitmapCache = Camelot.GetBitmapCache();
00681         if (pBitmapCache==NULL)
00682             return FALSE;
00683 
00684         CBitmapCacheKey inky2(this, dPixelWidth, 2);            // Option 2 is processed/rendered bitmap (see below)
00685         CCachedBitmap cbmp2;
00686         BOOL bFound = pBitmapCache->Lookup(inky2, cbmp2);
00687         if (bFound)
00688         {
00689             if (plpInfo)    *plpInfo = cbmp2.pbmpInfo;
00690             if (plpBits)    *plpBits = cbmp2.pbmpBits;
00691             return TRUE;
00692         }
00693 
00694         // TODO: Implement NodeFeatherEffect::GetDirectBitmap
00695         ERROR2IF(IsFeatherEffect(), FALSE, "TODO! Give NodeFeatherEffect its own implementation of GetDirectBitmap!");
00696 
00697         // We need to create a new bitmap here that captures the effects of the attributes
00698         //
00699         // If we don't have a RenderRegion, we can't build it, so return NULLs to indicate
00700         // that we need to be called again with a RenderRegion (allows quick test)
00701         // (See EnsureLiveEffectOriginalBitmaps)
00702         if (pRender == NULL)
00703         {
00704             if (plpInfo)    *plpInfo    = NULL;
00705             if (plpBits)    *plpBits    = NULL;
00706             return TRUE;
00707         }
00708 
00709         // We must "render" this bitmap to capture the attributes that effect its appearance
00710         // By default, we can't do arbitrarily transformed bitmaps - use a bitmap fill.
00711 //      CBitmapCacheKey inky(this, dPixelWidth, 1);             // Option 1 is processed bitmap not including rendering
00712 //      CCachedBitmap cbmp;
00713 //      BOOL bFoundCached = pBitmapCache->Lookup(inky, cbmp);
00714 //      ERROR3IF(!bFoundCached, "Effect:GetDirectBitmap failed to find processed bitmap!");
00715 //      LPBITMAPINFO lpInfo = cbmp.pbmpInfo;
00716 //      LPBYTE lpBits = cbmp.pbmpBits;
00717 
00718         // In the bitmap domain, we need to upright version of the bitmap, not the 
00719         // transformed parallelogram and bounds stored with the cbmp, the processed bitmap
00720 //      DocRect CaptureRect(0, 0, lpInfo->bmiHeader.biWidth*dPixelWidth, lpInfo->bmiHeader.biHeight*dPixelWidth);
00721 
00722         ERROR3IF(*plpInfo==NULL || *plpBits==NULL, "How come we got here with no processed bitmap?");
00723         DocRect CaptureRect = rectDirect;
00724 
00725         CaptureFlags caFlags = CaptureFlags(cfLOCKEDTRANSPARENT | cfFULLCOVERAGE);
00726         pRender->StartCapture(this, CaptureRect, CAPTUREINFO(ctNESTABLE, caFlags), TRUE, FALSE, dResolution);
00727         pRender->SaveContext();
00728 
00729         {   // ------------------------------------------------------
00730             // Setup coords for rendering in DirectBitmap domain
00731             DocCoord coords[3];
00732             coords[0] = CaptureRect.lo;
00733             coords[1] = DocCoord(CaptureRect.hi.x, CaptureRect.lo.y);
00734             coords[2] = DocCoord(CaptureRect.lo.x, CaptureRect.hi.y);
00735 
00736             // NOTE! We can only deal with effect transparency at the moment!
00737             // Render the transparency geometry using inverse Direct-Screen transform
00738             // (This bitmap is being rendered in "Direct space" whereas the transparency attribute
00739             // was applied in "Screen space")
00740             NodeAttribute* pAttr;
00741             if (FindAppliedAttribute(CC_RUNTIME_CLASS(AttrTranspFillGeometry), &pAttr))
00742             {
00743                 if (pAttr &&
00744                     !pAttr->IsADefaultAttr() &&
00745                     !pAttr->HasEquivalentDefaultValue(TRUE) &&
00746                     pAttr->IsEffectAttribute())
00747                 {
00748                     pTranspAttr = (AttrFillGeometry*) ((AttrFillGeometry*)pAttr)->SimpleCopy();
00749                     DocCoord tcoords[4];
00750                     DocCoord* pCoord = NULL;
00751                     pCoord = pTranspAttr->GetStartPoint();
00752                     tcoords[0] = pCoord ? *pCoord : DocCoord(0,0);
00753                     pCoord = pTranspAttr->GetEndPoint();
00754                     tcoords[1] = pCoord ? *pCoord : DocCoord(0,0);
00755                     pCoord = pTranspAttr->GetEndPoint2();
00756                     tcoords[2] = pCoord ? *pCoord : DocCoord(0,0);
00757                     pCoord = pTranspAttr->GetEndPoint3();
00758                     tcoords[3] = pCoord ? *pCoord : DocCoord(0,0);
00759 
00760                     Matrix matInverse = matLocalTransform.Inverse();
00761                     matInverse.transform(tcoords, 4);
00762 
00763                     pTranspAttr->SetStartPoint(&tcoords[0]);
00764                     pTranspAttr->SetEndPoint(&tcoords[1]);
00765                     pTranspAttr->SetEndPoint2(&tcoords[2]);
00766                     pTranspAttr->SetEndPoint3(&tcoords[3]);
00767 
00768                     pTranspAttr->Render(pRender);
00769                 }
00770             }
00771 
00772             pRender->RenderBits(*plpInfo, *plpBits, coords, 3, FALSE, NULL);
00773         }   // ------------------------------------------------------
00774 
00775         pRender->RestoreContext();
00776         if (pTranspAttr)
00777         {
00778             delete pTranspAttr;
00779             pTranspAttr = NULL;
00780         }
00781 
00782         LPBITMAPINFO lpInfo = NULL;
00783         LPBYTE lpBits = NULL;
00784         pRender->StopCapture(this, FALSE, FALSE, &lpInfo, &lpBits, &CaptureRect);
00785 
00786         // We should now have a bitmap containing an upright version of the NodeBitmap
00787         // with transparency and contoning applied as per the attributes in the tree
00788         if (lpInfo && lpBits)
00789         {
00790             *plpInfo = lpInfo;
00791             *plpBits = lpBits;
00792 
00793             // Cache the PROCESSED/RENDERED bitmap as Option 2
00794             cbmp2.pbmpBits = lpBits;
00795             cbmp2.pbmpInfo = lpInfo;
00796             cbmp2.SetCachedRect(CaptureRect);
00797             cbmp2.nPriority = CACHEPRIORITY_TEMPBITMAP_HIGH;
00798             if (cbmp2.IsValid())
00799                 pBitmapCache->StoreBitmap(inky2, cbmp2);
00800         }
00801     }
00802 
00803     return TRUE;
00804 }
00805 
00806 
00807 
00808 
00809 /********************************************************************************************
00810 
00811 >   virtual BOOL NodeBitmapEffect::CanGetChildDirectBitmap()
00812 
00813     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00814     Created:    26/07/2005
00815     Inputs:     -
00816     Outputs:    -
00817     Returns:    TRUE if we can get a bitmap dircetly from our controlled child node
00818                 FALSE otherwise
00819     Purpose:    FInd out whether our controlled child can give us a DirectBitmap
00820 
00821 ********************************************************************************************/
00822 
00823 BOOL NodeBitmapEffect::CanGetChildDirectBitmap()
00824 {
00825     NodeRenderableInk* pInkNode = GetInkNodeFromController();
00826     if (pInkNode==NULL)
00827         return FALSE;
00828 
00829     BOOL bOK = EnableDirectCapture() && pInkNode->CanSupplyDirectBitmap();
00830 
00831     return bOK;
00832 }
00833 
00834 
00835 
00836 
00837 /********************************************************************************************
00838 
00839 >   BOOL NodeBitmapEffect::RenderDirectBitmapState(RenderRegion* pRender)
00840 
00841     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00842     Created:    30/07/2005
00843     Inputs:     -
00844     Outputs:    -
00845     Returns:    -
00846     Purpose:    Render the current state into the renderregion if we haven't yet done so.
00847                 Only used in background rendering timeslice screen update
00848 
00849 ********************************************************************************************/
00850 
00851 BOOL NodeBitmapEffect::RenderDirectBitmapState(RenderRegion* pRender)
00852 {
00853     CBitmapCache* pBitmapCache = Camelot.GetBitmapCache();
00854     if (pBitmapCache!=NULL && pRender->RRQuality.GetFillQuality() > Quality::Solid)
00855     {
00856         RenderCachedEffect(pBitmapCache, pRender, TRUE);
00857     }
00858 
00859     return TRUE;
00860 }
00861 
00862 
00863 
00864 
00865 /********************************************************************************************
00866 
00867 >   BOOL NodeBitmapEffect::HasCachedDirectBitmap()
00868 
00869     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00870     Created:    29/07/2005
00871     Inputs:     -
00872     Outputs:    -
00873     Returns:    - 
00874     Purpose:    -
00875 
00876 ********************************************************************************************/
00877 
00878 BOOL NodeBitmapEffect::HasCachedDirectBitmap()
00879 {
00880     Matrix matTrans;
00881     BOOL bDirect = GetChildDirectBitmap(NULL, NULL, NULL, NULL, &matTrans, NULL);
00882     return (bDirect && !matTrans.IsIdentity());         // ??? Non-ident used to indicate that a direct bitmap was found under the effect...
00883 }
00884 
00885 
00886 
00887 
00888 /********************************************************************************************
00889 
00890 >   BOOL NodeBitmapEffect::EnableDirectCapture()
00891 
00892     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00893     Created:    04/08/2005
00894     Inputs:     -
00895     Outputs:    -
00896     Returns:    - 
00897     Purpose:    Determine whether this effect can do a direct capture of its child node(s)
00898                 or whether it needs to do a normal, rendering capture.
00899                 At the moment, this depends solely on whether the DirectBitmap supplier
00900                 can supply a bitmap at the same resolution as this effect requires
00901 
00902 ********************************************************************************************/
00903 
00904 BOOL NodeBitmapEffect::EnableDirectCapture()
00905 {
00906     NodeRenderableInk* pInkNode = GetInkNodeFromController();
00907     if (pInkNode==NULL)
00908         return FALSE;
00909 
00910 PORTNOTE("effects", "EnableDirectCapture returns FALSE until effects work. Forces base objects to render themselves.");
00911 #if !defined(EXCLUDE_FROM_XARALX)
00912     double dChildPPI = 0;
00913     BOOL bDirectResolution = pInkNode->GetDirectBitmap(NULL, NULL, NULL, NULL, NULL, &dChildPPI);
00914     if (!bDirectResolution || dChildPPI==0)
00915         return FALSE;
00916 
00917     // Enable Direct Capture if we are "automatic" PPI or we are the same PPI as the child direct bitmap
00918     if (m_dPixelsPerInch==0 || dChildPPI==m_dPixelsPerInch)
00919         return TRUE;
00920 #endif 
00921 
00922     return FALSE;
00923 }
00924 
00925 
00926 
00927 
00928 /********************************************************************************************
00929 
00930 >   DocRect NodeBitmapEffect::AdjustPixelOffsets(DocRect inRect, INT32 width, INT32 height, INT32 xOffset, INT32 yOffset, double dPixelWidth = 0)
00931 
00932     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00933     Created:    14/09/2004
00934     Inputs:     -
00935     Outputs:    -
00936     Purpose:    -
00937     Notes:      Width, height, xoffset, yoffset refer to bitmap in standard Windows
00938                 fashion - Y coords increase downwards, offsets refer to top-left corner
00939                 This routine must move from one coord system to the other while it updates the
00940                 supplied rectangle
00941 
00942 ********************************************************************************************/
00943 
00944 DocRect NodeBitmapEffect::AdjustPixelOffsets(DocRect inRect, INT32 width, INT32 height, double xOffset, double yOffset, double dPixelWidth)
00945 {
00946     if (dPixelWidth==0)
00947         dPixelWidth = GetPixelWidth();
00948 
00949     DocRect outRect(inRect.lo.x, inRect.hi.y, inRect.lo.x, inRect.hi.y);
00950                                                             // Set new bitmap origin to old bitmap origin
00951     outRect.lo.x += INT32( xOffset * dPixelWidth );         // Set new bitmap origin X (-ve offset means "move left")
00952     outRect.hi.y -= INT32( yOffset * dPixelWidth );         // Set new bitmap origin Y (-ve yoffset means "move up")
00953 
00954     if (width==0)
00955         outRect.hi.x = outRect.lo.x + inRect.Width();
00956     else
00957         outRect.hi.x = outRect.lo.x + INT32( width * dPixelWidth ); // Set width of new bitmap
00958 
00959     if (height==0)
00960         outRect.lo.y = outRect.hi.y - inRect.Height();
00961     else
00962         outRect.lo.y = outRect.hi.y - INT32( height * dPixelWidth );    // Set height of new bitmap
00963 
00964     return outRect;
00965 }
00966 
00967 
00968 
00969 
00970 /********************************************************************************************
00971 
00972 >   IXMLDOMDocumentPtr NodeBitmapEffect::GetEditList()
00973 
00974     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00975     Created:    10/09/2004
00976     Inputs:     -
00977     Outputs:    -
00978     Purpose:    -
00979 
00980 ********************************************************************************************/
00981 
00982 IXMLDOMDocumentPtr NodeBitmapEffect::GetEditList()
00983 {
00984     return m_pEditsDoc;
00985 }
00986 
00987 
00988 
00989 
00990 /********************************************************************************************
00991 
00992 >   void NodeBitmapEffect::SetEditList(IXMLDOMDocumentPtr pNewEditsDoc)
00993 
00994     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00995     Created:    14/09/2004
00996     Inputs:     -
00997     Outputs:    -
00998     Purpose:    -
00999 
01000 ********************************************************************************************/
01001 
01002 void NodeBitmapEffect::SetEditList(IXMLDOMDocumentPtr pNewEditsDoc)
01003 {
01004     m_pEditsDoc = pNewEditsDoc;
01005 }
01006 
01007 
01008 
01009 
01010 /********************************************************************************************
01011 
01012 >   BOOL NodeBitmapEffect::SetDefaultEditList()
01013 
01014     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01015     Created:    27/07/2005
01016     Inputs:     -
01017     Outputs:    -
01018     Purpose:    -
01019 
01020 ********************************************************************************************/
01021 
01022 BOOL NodeBitmapEffect::SetDefaultEditList()
01023 {
01024     PORTNOTETRACE("other","NodeBitmapEffect::SetDefaultEditList - do nothing");
01025 #ifndef EXCLUDE_FROM_XARALX
01026     // Ensure that we have an edit list
01027     if (m_pEditsDoc==NULL)
01028     {
01029         m_pEditsDoc = CXMLUtils::NewDocument();
01030         ERROR3IF(m_pEditsDoc==NULL, "Can't make default edit document");
01031         return (m_pEditsDoc!=NULL);
01032     }
01033 #endif
01034     return TRUE;
01035 }
01036 
01037 
01038 
01039 
01040 /********************************************************************************************
01041 
01042 >   void NodeBitmapEffect::RenderAfterSubtree(RenderRegion* pRender)
01043 
01044     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01045     Created:    07/09/2004
01046     Inputs:     pRender - The region to render into
01047     Purpose:    Capture the group as a cached bitmap
01048 
01049 ********************************************************************************************/
01050 
01051 void NodeBitmapEffect::RenderAfterSubtree(RenderRegion* pRender)
01052 {
01053     Matrix matTrans;
01054     double dResolution = 0;
01055 
01056     CBitmapCache* pBitmapCache = Camelot.GetBitmapCache();
01057     if (pBitmapCache==NULL)
01058     {
01059         return;
01060     }
01061 
01062     // --------------------------------------------------------------------------------------
01063     // Note that we use the Capture system to store the state of rendering
01064     // in this node in the scope of the rendering system rather than storing
01065     // it temporarilly in the document tree (e.g. in this node). This means
01066     // the tree is stateless and can be rendered by several different "threads"
01067     // with different states at the same time.
01068     // In this context a "thread" is a background, rendering RenderRegion but
01069     // it could be a real thread one day.
01070     //
01071     Capture* pCapture = pRender->GetTopCapture();
01072     if (pCapture==NULL)                                         // If nothing was captured
01073         return;                                                 // Then do nothing
01074 
01075     // Only stop the capture if we started it
01076     // (means we only capture whole subtrees at the mo.)
01077     if (pCapture->GetOwner()==this)
01078     {
01079         // End this capture:
01080         // Blit capture to screen
01081         // Retain bitmap because we will release it ourselves only if we fail to cache it
01082         BOOL bCached = FALSE;
01083         BOOL bCaptureIsDirect = pCapture->IsDirect();
01084         LPBITMAPINFO lpInfo = NULL;
01085         LPBYTE lpBits = NULL;
01086         DocRect CaptureRect = GetChildBoundingRect();               // Set maximum size we allow
01087         CaptureRect.Inflate(CAPTURE_BORDER*(INT32)GetPixelWidth());
01088         pRender->StopCapture(this, FALSE, FALSE, &lpInfo, &lpBits, &CaptureRect, &matTrans, &dResolution);
01089                                                                     // pCapture is deleted now...
01090 
01091         // Is this capture direct?
01092         if (bCaptureIsDirect)
01093         {
01094             ERROR3IF(dResolution==0, "Direct Capture returned 0 pixels per inch\n");
01095             // If we are supplied with a direct bitmap, try to process it and cache
01096             // the results.
01097             // 
01098             // Note that CaptureRect is in DirectBitmap space, not drawing space
01099             // and that matTransform holds the matrix to map from DirectBitmap space
01100             // to drawing space...
01101             //
01102             if (lpInfo && lpBits && CaptureRect.IsValid())
01103             {
01104                 // Process the bitmap using appropriate virtual functions from derived class
01105                 LPBITMAPINFO lpProcessedInfo = NULL;
01106                 LPBYTE lpProcessedBits = NULL;
01107                 double xOffset = 0;
01108                 double yOffset = 0;
01109                 ProcessBitmap(pRender, pBitmapCache, lpInfo, lpBits, CaptureRect, lpProcessedInfo, lpProcessedBits, &xOffset, &yOffset);
01110 
01111                 if (lpProcessedInfo && lpProcessedBits)
01112                 {
01113                     // Cache the PROCESSED bitmap, as Option 1
01114                     //
01115                     // Note that SetProcessedBitmap stores the bitmap with coords transformed into Drawing space
01116                     // So that rendering into drawing space will be quick and simple
01117                     // The rectangle in DirectBitmap space is stored in a member variable m_rectDirectBitmap
01118                     SetProcessedBitmap(lpProcessedInfo, lpProcessedBits, CaptureRect, lpProcessedInfo->bmiHeader.biWidth, lpProcessedInfo->bmiHeader.biHeight, xOffset, yOffset, 72000.0/dResolution, &matTrans);
01119 
01120                     // Note RenderCachedEffect only does anything if the current capture
01121                     // doesn't consume this bitmap directly
01122                     RenderCachedEffect(pBitmapCache, pRender);
01123                 }
01124             }
01125         }
01126         else
01127         {
01128             // If the capture gave us back a bitmap, try to cache it
01129             if (lpInfo && lpBits && CaptureRect.IsValid())
01130             {
01131                 // Cache the ORIGINAL bitmap as Option 0
01132                 // See also, SetOriginalBitmap
01133                 double PixelWidth = GetPixelWidth();
01134                 CBitmapCacheKey inky(this, PixelWidth, 0);
01135 
01136                 CCachedBitmap cbmp;
01137 
01138                 cbmp.pbmpBits = lpBits;
01139                 cbmp.pbmpInfo = lpInfo;
01140                 cbmp.SetCachedRect(CaptureRect);
01141                 cbmp.nPriority = CACHEPRIORITY_TEMPBITMAP_HIGH;
01142 
01143                 if (cbmp.IsValid())
01144                 {
01145                     pBitmapCache->StoreBitmap(inky, cbmp);
01146                     bCached = TRUE;
01147                 }
01148 
01149                 // Process the bitmap using appropriate virtual processor for derived class
01150                 LPBITMAPINFO lpProcessedInfo = NULL;
01151                 LPBYTE lpProcessedBits = NULL;
01152                 double xOffset = 0;
01153                 double yOffset = 0;
01154 
01155                 //BOOL bOK =
01156                 ProcessBitmap(pRender, pBitmapCache, lpInfo, lpBits, CaptureRect, lpProcessedInfo, lpProcessedBits, &xOffset, &yOffset);
01157 //              ERROR3IF(!bOK, "NodeBitmapEffect::RenderAfterSubtree ProcessBitmap failed\n");
01158 
01159                 if (lpProcessedInfo && lpProcessedBits)
01160                 {
01161                     // Cache the PROCESSED bitmap as well, as Option 1
01162                     CaptureRect = SetProcessedBitmap(lpProcessedInfo, lpProcessedBits, CaptureRect, lpProcessedInfo->bmiHeader.biWidth, lpProcessedInfo->bmiHeader.biHeight, xOffset, yOffset);
01163 
01164                     // Render it
01165                     RenderCachedEffect(pBitmapCache, pRender);
01166 
01167                     // If we are rendering during printing, there may be multiple passes
01168                     // through the tree to do different aspects of printing. The
01169                     // PrintingMaskedRenderRegion produces a monochrome mask so we
01170                     // definitely don't want to cache that!
01171                     if (pRender->IsKindOf(CC_RUNTIME_CLASS(PrintingMaskedRenderRegion)))
01172                     {
01173                         double PixelWidth = GetPixelWidth();
01174                         CBitmapCacheKey inky(this, PixelWidth, 0);
01175                         pBitmapCache->RemoveBitmap(inky);
01176 
01177                         CBitmapCacheKey inky2(this, PixelWidth, 1);
01178                         pBitmapCache->RemoveBitmap(inky2);
01179 
01180                         bCached = FALSE;
01181                     }
01182 
01183                     // If we failed to cache the captured bitmap then release it
01184                     if (lpProcessedInfo!=NULL && lpProcessedBits!=NULL && !bCached)
01185                     {
01186                         FreeDIB(lpProcessedInfo, lpProcessedBits, NULL, FALSE);
01187                     }
01188                 }
01189                 else
01190                 {
01191                     // If we failed to process the captured bitmap for some reason
01192                     // Then just plot it back to the screen so the user sees something
01193 //                  ERROR3("NodeBitmapEffect::RenderAfterSubtree ProcessBitmap failed\n");
01194                     pRender->RenderBits(lpInfo, lpBits, CaptureRect);
01195                 }
01196             }
01197 
01198             // If we failed to cache the captured bitmap then release it
01199             if (lpInfo!=NULL && lpBits!=NULL && !bCached)
01200             {
01201                 FreeDIB(lpInfo, lpBits, NULL, FALSE);
01202             }
01203         }
01204     }
01205 }
01206 
01207 
01208 
01209 
01210 /***********************************************************************************************
01211 
01212 >   virtual void NodeBitmapEffect::Render(RenderRegion* pRRegion)
01213 
01214     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01215     Created:    13/12/2004
01216     Inputs:     Pointer to a render region
01217     Purpose:    Will render the liveeffect iff we have it cached - for hit detection reasons
01218 
01219 ***********************************************************************************************/
01220 
01221 void NodeBitmapEffect::Render(RenderRegion* pRender)
01222 {
01223     CBitmapCache* pBitmapCache = Camelot.GetBitmapCache();
01224     if (pBitmapCache!=NULL && pRender->IsHitDetect() && pRender->RRQuality.GetFillQuality() > Quality::Solid)
01225     {
01226         RenderCachedEffect(pBitmapCache, pRender, TRUE);
01227     }
01228 }
01229 
01230 
01231 
01232 /********************************************************************************************
01233 
01234 >   virtual BOOL NodeBitmapEffect::FindCachedEffect(CBitmapCache* pBitmapCache)
01235 
01236     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01237     Created:    24/11/2004
01238     Inputs:     -
01239     Outputs:    -
01240     Purpose:    Find all cached items this node needs to call RenderCachedEffect
01241                 succesfully
01242 
01243 ********************************************************************************************/
01244 
01245 BOOL NodeBitmapEffect::FindCachedEffect(CBitmapCache* pBitmapCache)
01246 {
01247 //  BOOL bRendered = FALSE;
01248 
01249     CBitmapCacheKey inky(this, GetPixelWidth(), 1);                     // Get cached BMP for this PROCESSED node at our dpi
01250     CCachedBitmap cbmp;
01251     BOOL bFoundCached = pBitmapCache->Lookup(inky, cbmp);
01252 
01253     return bFoundCached;
01254 }
01255 
01256 
01257 
01258 
01259 /********************************************************************************************
01260 
01261 >   BOOL NodeBitmapEffect::RenderCachedEffect(CBitmapCache* pBitmapCache, RenderRegion* pRender, BOOL bIgnoreCapture = FALSE)
01262 
01263     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01264     Created:    24/11/2004
01265     Inputs:     -
01266     Outputs:    -
01267     Returns:    TRUE if the cached effect was rendered or passed on to a consumer capture
01268                 FALSE if the cached effect was not present or could not be consumed or rendered
01269     Purpose:    Render the cached version of this node
01270 
01271 ********************************************************************************************/
01272 
01273 BOOL NodeBitmapEffect::RenderCachedEffect(CBitmapCache* pBitmapCache, RenderRegion* pRender, BOOL bIgnoreCapture)
01274 {
01275     BOOL bRendered = FALSE;
01276 
01277     CBitmapCacheKey inky(this, GetPixelWidth(), 1);                     // Get cached BMP for this PROCESSED node at our dpi
01278     CCachedBitmap cbmp;
01279     BOOL bFoundCached = pBitmapCache->Lookup(inky, cbmp);
01280 
01281     if (bFoundCached)
01282     {
01283         // No need to render if we are going to supply to a capture
01284         Capture* pCapture = pRender->GetTopCapture();
01285         if (!bIgnoreCapture && pCapture && pCapture->ConsumeDirectBitmap(this))
01286         {
01287             // Tell the caller that the effect has been "rendered"
01288             bRendered = TRUE;
01289         }
01290         else
01291         {
01292             // Allow RenderBits to render any effect attributes that are attached to us
01293             // before rendering the bitmap so that they affect its appearance
01294             // by passing it a pointer to this node to search for effect attributes
01295             bRendered = pRender->RenderBits(cbmp.pbmpInfo, cbmp.pbmpBits, &cbmp.coord0, 3, TRUE, this);
01296         }
01297     } 
01298 
01299     return bRendered;
01300 }
01301 
01302 
01303 
01304 
01305 /********************************************************************************************
01306 >   virtual BOOL NodeBitmapEffect::ProcessBitmap(RenderRegion* pRender,
01307                                                   CBitmapCache* pBitmapCache,
01308                                                   LPBITMAPINFO pBMPInfo,
01309                                                   LPBYTE pBMPBits,
01310                                                   DocRect BMPRect,
01311                                                   LPBITMAPINFO& pOutputInfo,
01312                                                   LPBYTE& pOutputBits,
01313                                                   double* pXOffset,
01314                                                   double* pYOffset)
01315 
01316     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01317     Created:    24/11/2004
01318     Returns:    
01319     Purpose:    Processes the bitmap produced by the children of this node.
01320                 Can be overridden by derived classes to perofrm special processing
01321 
01322 ********************************************************************************************/
01323 
01324 BOOL NodeBitmapEffect::ProcessBitmap(RenderRegion* pRender,
01325                                       CBitmapCache* pBitmapCache,
01326                                       LPBITMAPINFO pBMPInfo,
01327                                       LPBYTE pBMPBits,
01328                                       DocRect BMPRect,
01329                                       LPBITMAPINFO& pOutputInfo,
01330                                       LPBYTE& pOutputBits,
01331                                       double* pXOffset,
01332                                       double* pYOffset)
01333 {
01334     BOOL                bOK = TRUE;
01335 
01336     PORTNOTETRACE("other","NodeBitmapEffect::ProcessBitmap - do nothing, CXMLUtils, XPEEditOp");
01337 #ifndef EXCLUDE_FROM_XARALX
01338     // Apply the effect to the newly captured bitmap
01339     BOOL bValidEditList = TRUE;
01340     if (m_pEditsDoc==NULL)
01341     {
01342         HRESULT hr = E_FAIL;
01343         m_pEditsDoc = CXMLUtils::NewDocument();
01344         bValidEditList = FALSE;
01345         ERROR3IF(m_pEditsDoc==NULL, "Can't make default edit document");
01346     }
01347 
01348     if (bValidEditList)
01349     {
01350 //TRACEUSER( "Phil", _T("NodeLiveEffect calling ProcessBitmap %x %s\n"), this, this->GetRuntimeClass()->m_lpszClassName);
01351         INT32 iXOffset = (INT32)*pXOffset;
01352         INT32 iYOffset = (INT32)*pYOffset;
01353         bOK = XPEEditOp::ProcessBitmap(pBMPInfo, pBMPBits, pOutputInfo, pOutputBits, m_pEditsDoc, &iXOffset, &iYOffset);
01354         *pXOffset = iXOffset;
01355         *pYOffset = iYOffset;
01356 //TRACEUSER( "Phil", _T("NodeLiveEffect back from ProcessBitmap\n"));
01357     } 
01358 #endif
01359     return bOK;
01360 }
01361 
01362             
01363 
01364             
01365 /********************************************************************************************
01366 >   DocRect NodeBitmapEffect::GetBlobBoundingRect()
01367 
01368     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> (re-written)
01369     Created:    29/6/95
01370     Returns:    DocRect - The bounding rect of the group and its blobs
01371     Purpose:    Finds the bounding rect of the group along with its blobs. Its main use is
01372                 to determine which areas of the document to invalidate
01373 ********************************************************************************************/
01374 
01375 DocRect NodeBitmapEffect::GetBlobBoundingRect()
01376 {
01377     DocRect NewRect = DocRect(0,0,0,0);
01378 
01379 #if !defined(EXCLUDE_FROM_RALPH)
01380     // Find the Blob manager
01381     BlobManager* pBlobMgr = GetApplication()->GetBlobManager();
01382     if (pBlobMgr!= NULL)
01383     {
01384 //      BlobStyle VisibleBlobs = pBlobMgr->GetCurrentInterest();
01385 //      if (VisibleBlobs.Object)
01386 //      {
01387             DocRect BoundingRect = GetBoundingRect();
01388 
01389             // Object blobs are visible, so include blob in each
01390             // corner of the group bounds
01391             DocRect BlobSize;
01392 
01393             // Find out where the blobs will be drawn
01394             DocCoord Low  = BoundingRect.LowCorner();
01395             DocCoord High = BoundingRect.HighCorner();
01396 
01397             // Include the object blob in each corner
01398             pBlobMgr->GetBlobRect(Low, &BlobSize);
01399             NewRect = NewRect.Union(BlobSize);
01400             pBlobMgr->GetBlobRect(High, &BlobSize);
01401             NewRect = NewRect.Union(BlobSize);
01402             pBlobMgr->GetBlobRect(DocCoord(Low.x, High.y), &BlobSize);
01403             NewRect = NewRect.Union(BlobSize);
01404             pBlobMgr->GetBlobRect(DocCoord(High.x, Low.y), &BlobSize);
01405             NewRect = NewRect.Union(BlobSize);
01406 //      }
01407     }
01408 
01409     Node* pNode=FindFirstChild();
01410     while (pNode!=NULL)
01411     {
01412         if (pNode->IsBounded())
01413             NewRect = NewRect.Union(((NodeRenderableBounded*)pNode)->GetBlobBoundingRect());
01414         pNode = pNode->FindNext();
01415     }
01416 
01417     IncludeChildrensBoundingRects(&NewRect);
01418 #endif
01419     return NewRect;
01420 }
01421 
01422 
01423 
01424 
01425 /********************************************************************************************
01426 >   virtual BOOL NodeBitmapEffect::CompareState(NodeEffect* pPPNode)
01427 
01428     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01429     Created:    12/11/2004
01430     Returns:    TRUE if this state matches the state (and type) of the supplied node
01431     Purpose:    -
01432     Notes:      Would be more efficient to pass in level xml instead of getting it inside
01433                 this function
01434 
01435 ********************************************************************************************/
01436 
01437 BOOL NodeBitmapEffect::CompareState(NodeEffect* pPPNode)
01438 {
01439     if (!pPPNode->IsBitmapEffect())
01440         return FALSE;
01441 
01442     PORTNOTETRACE("other","NodeBitmapEffect::CompareState - do nothing, XML and BSTR");
01443 #ifndef EXCLUDE_FROM_XARALX
01444     BSTR temp;
01445     HRESULT hr;
01446 
01447     _bstr_t bstrThisEditDoc;
01448     IXMLDOMDocumentPtr pThisEditDoc = GetEditList();
01449     hr = pThisEditDoc->get_xml(&temp);
01450     bstrThisEditDoc = temp;
01451 
01452     _bstr_t bstrTestEditDoc;
01453     IXMLDOMDocumentPtr pTestEditDoc = ((NodeBitmapEffect*)pPPNode)->GetEditList();
01454     hr = pTestEditDoc->get_xml(&temp);
01455     bstrTestEditDoc = temp;
01456 
01457     return (bstrTestEditDoc == bstrThisEditDoc); */
01458 #else
01459     return false;
01460 #endif
01461 }
01462 
01463 
01464 
01465 
01466 /********************************************************************************************
01467 
01468 >   BOOL NodeBitmapEffect::DoBecomeA(BecomeA* pBecomeA);
01469 
01470     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01471     Created:    08/02/2005
01472     Inputs:     BecomeA struct
01473     Purpose:    Converts me to a path
01474     Notes:      Note that when this routine creates paths it does NOT call DoBecomeA on its
01475                 children because the paths and the bitmap fills represetn everything the
01476                 child objects have rendered.
01477     SeeAlso:    
01478 
01479 ********************************************************************************************/
01480 BOOL NodeBitmapEffect::DoBecomeA(BecomeA* pBecomeA)
01481 {
01482     // Check for a NULL entry param
01483     ERROR2IF(pBecomeA == NULL, FALSE, "pBecomeA is NULL");
01484 
01485     if (!pBecomeA->BAPath())
01486         return FALSE;
01487 
01488     // This lump checks that the Reason is one that we understand
01489     // It also makes sure that we don't have a NULL UndoOp ptr
01490     BOOL ValidReason = (pBecomeA->GetReason() == BECOMEA_REPLACE || pBecomeA->GetReason() == BECOMEA_PASSBACK);
01491     ERROR2IF_PF(!ValidReason,FALSE,("Unkown BecomeA reason %d",pBecomeA->GetReason()));
01492 
01493     BOOL bOK                        = FALSE;
01494     NodePath* pNewNodePath          = NULL;
01495     NodeAttribute* pAttr            = NULL;
01496     NodeHidden* pHiddenNode         = NULL;
01497 //  AttrLineWidth* pLineWidth       = NULL;
01498     UndoableOperation* pOp          = pBecomeA->GetUndoOp();
01499 
01500     // Don't make a dumb square bitmap if the Op is a blend op because in that case
01501     // it's more useful to have the original shape with the effect
01502     // Or if this node is in the top surface of those being considered
01503     //      and the op tells us that the results of dobecomea will be left in place (i.e. under
01504     //      and effect stack)
01505     if (!IsLockedEffect())
01506     {
01507         if (pBecomeA->IsBlendBecomeA() || pBecomeA->DoSilhouette() || pBecomeA->OnlyNeedPaths() || pBecomeA->ResultsStayInPlace())
01508             return NodeEffect::DoBecomeA(pBecomeA);
01509     }
01510     else
01511     {
01512         if (pBecomeA->OnlyNeedPaths() || (pBecomeA->IsBlendBecomeA() && pBecomeA->GetReason() == BECOMEA_PASSBACK))
01513             return NodeEffect::DoBecomeA(pBecomeA);
01514     }
01515 
01516     // We only do conversions if we are the top effect in the stack
01517     if (!IsLockedEffect() && FindParent() && FindParent()->IsEffect())
01518         return TRUE;
01519 
01520     // Get a permanent kernel bitmap to fill the path
01521     DocCoord coords[3];
01522     KernelBitmap* kBitmap = GetKernelBitmap(coords, TRUE);  // Retain the cached data because we may be called again (blends with multiple paths)
01523     // Note: kBitmap may be NULL
01524 
01525     // Create a NodePath containing the parallelogram from the cache
01526     ALLOC_WITH_FAIL(pNewNodePath, new NodePath, pOp); 
01527     if (pNewNodePath)
01528     {
01529         Path InkPath;
01530         InkPath.Initialise();
01531         InkPath.AddMoveTo(coords[0]);
01532         InkPath.AddLineTo(coords[1]);
01533         InkPath.AddLineTo(DocCoord(coords[2].x+coords[1].x-coords[0].x, coords[2].y+coords[1].y-coords[0].y));
01534         InkPath.AddLineTo(coords[2]);
01535         InkPath.AddLineTo(coords[0]);
01536         InkPath.CloseSubPath();
01537 
01538         pNewNodePath->InkPath.Initialise();
01539         pNewNodePath->InkPath.CloneFrom(InkPath);
01540         pNewNodePath->InkPath.IsFilled = TRUE;
01541         pNewNodePath->InkPath.TryToClose();
01542         pNewNodePath->InkPath.InitialiseFlags();
01543 
01544         switch (pBecomeA->GetReason())
01545         {
01546         case BECOMEA_REPLACE:
01547             {
01548                 // Note! In many cases we are just being asked to become a path to get
01549                 // the path data ignoring the attributes.
01550                 // So if we can't make the attribute, it's better tp just go ahead
01551                 // and return the path data without them.
01552                 //
01553                 // Make a new bitmap fill attribute referring to the newly created Kernel bitmap
01554                 BitmapFillAttribute* pBitmapAttr = NULL;
01555                 ALLOC_WITH_FAIL(pBitmapAttr, new BitmapFillAttribute, pOp);
01556                 if (pBitmapAttr!=NULL && kBitmap)
01557                 {
01558                     pBitmapAttr->GetBitmapRef()->SetBitmap(kBitmap);
01559                     pBitmapAttr->StartPoint = coords[0];
01560                     pBitmapAttr->EndPoint   = coords[1];
01561                     pBitmapAttr->EndPoint2  = coords[2];
01562 
01563                     // Make sure the Fill attributes point to the new bitmap!
01564                     pAttr = pBitmapAttr->MakeNode();
01565                     pAttr->AttachNode(pNewNodePath, FIRSTCHILD);
01566                     delete pBitmapAttr;
01567                     pBitmapAttr = NULL;
01568                 }
01569 
01570                 AttrStrokeColour* pStrokeColour = NULL;
01571                 ALLOC_WITH_FAIL(pStrokeColour, new AttrStrokeColour, pOp);
01572                 if (pStrokeColour!=NULL)
01573                 {
01574                     // Also make the line colour NONE
01575                     DocColour colNone(COLOUR_NONE);
01576                     pStrokeColour->SetStartColour(&colNone);
01577                     pStrokeColour->AttachNode(pNewNodePath, FIRSTCHILD);
01578                 }
01579 
01580                 bOK = TRUE;
01581 
01582                 // Copy any effect attributes over to the new node
01583                 // where they can become normal attributes now that we have captured
01584                 // the effect as a bitmap
01585                 NodeAttribute* pEffectAttr = NodeAttribute::FindFirstAppliedAttr(this);
01586                 while (bOK && pEffectAttr && pEffectAttr->IsEffectAttribute())
01587                 {
01588                     CALL_WITH_FAIL(pEffectAttr->CopyNode(pNewNodePath, FIRSTCHILD), pOp, bOK);
01589 
01590                     pEffectAttr = NodeAttribute::FindPrevAppliedAttr(pEffectAttr);
01591                 }
01592 
01593                 // Now insert the new node
01594                 if (bOK)
01595                 {
01596                     if (pOp)
01597                     {
01598                         bOK = pOp->DoInsertNewNode(pNewNodePath, this, NEXT, TRUE, FALSE, this->IsSelected() || this->IsParentOfSelected(), TRUE);
01599                     }
01600                     else
01601                     {
01602                         pNewNodePath->AttachNode(this, NEXT);
01603                         pNewNodePath->Select(this->IsSelected() || this->IsParentOfSelected());
01604                     }
01605                 }
01606 
01607                 // Handle the passback bits
01608                 if (bOK)
01609                 {
01610                     CCAttrMap ThisMap;
01611                     CCAttrMap* pThisMap = NULL;
01612                     if (pNewNodePath->FindAppliedAttributes(&ThisMap))
01613                         pThisMap = ThisMap.Copy();
01614                     pBecomeA->PassBack(pNewNodePath, this, pThisMap);
01615                 }
01616 
01617                 // Now hide (or delete) this node
01618                 if (bOK)
01619                 {
01620                     if (pOp)
01621                     {
01622                         bOK = pOp->DoHideNode(this, TRUE, &pHiddenNode, FALSE);
01623                     }
01624                     else
01625                     {
01626                         CascadeDelete();
01627                         delete this;    // SCARY!
01628                     }
01629                 }
01630             }
01631             break;
01632 
01633         case BECOMEA_PASSBACK:
01634             {
01635                 // if we're passing back, just do the first path
01636                 CCAttrMap ThisMap;
01637                 if (FindAppliedAttributes(&ThisMap))
01638                 {
01639                     // make a copy of this attribute map
01640                     CCAttrMap* pNewAttrMap = ThisMap.Copy();
01641                     AttrStrokeColour* pStrokeColour = NULL;
01642                     // get the stroke colour attribute out of this map and set it to COLOUR_NONE
01643                     if( pNewAttrMap->Lookup( CC_RUNTIME_CLASS(AttrStrokeColour), (void*&)(pStrokeColour) ) )
01644                     {
01645                         if (pStrokeColour && pStrokeColour->GetStartColour())
01646                         {
01647                             DocColour colNone(COLOUR_NONE);
01648                             pStrokeColour->SetStartColour(&colNone);
01649                         }
01650                     }
01651 
01652                     // Replace the Fill attribute in the Attr Map copy
01653                     // with a bitmap fill
01654                     AttrFillGeometry* pBitmapFill = new AttrBitmapColourFill();
01655                     if (pBitmapFill && kBitmap)
01656                     {
01657                         // Make a Bitmap Fill that is equivalent to this
01658                         // node bitmap
01659                         pBitmapFill->AttachBitmap(kBitmap);
01660 
01661                         // Set any contone colours that we have
01662 //                      pBitmapFill->SetStartColour(ContoneStart);
01663 //                      pBitmapFill->SetEndColour(ContoneEnd);
01664 
01665                         // Set the control points from the NodeBitmap Parallelogram
01666                         pBitmapFill->SetStartPoint(&coords[0]);
01667                         pBitmapFill->SetEndPoint(&coords[1]);
01668                         pBitmapFill->SetEndPoint2(&coords[2]);
01669 
01670                         void* pOldFill;
01671                         if (pNewAttrMap->Lookup(CC_RUNTIME_CLASS(AttrFillGeometry), pOldFill))
01672                         {
01673                             // We need to Remove and Delete the existing Fill Attr
01674                             pNewAttrMap->RemoveKey(CC_RUNTIME_CLASS(AttrFillGeometry));
01675                             delete (AttrFillGeometry*)pOldFill;
01676                         }
01677 
01678                         // Add the Bitmap fill into the Attr Map
01679                         pNewAttrMap->SetAt(CC_RUNTIME_CLASS(AttrFillGeometry),(void*)pBitmapFill);
01680                     }
01681 
01682                     // ok, now lets set up the attribute maps
01683                     pBecomeA->PassBack(pNewNodePath, this, pNewAttrMap);
01684                     bOK = TRUE;
01685                 }
01686             }
01687             break;
01688 
01689         case BECOMEA_TEST:
01690             ERROR3("Unhandled BECOMEA type\n");
01691             break;
01692         }
01693     }
01694 
01695     if (!bOK)
01696     {
01697         if (pNewNodePath != NULL)
01698         {
01699             // Delete all the NodePath's children (if it has any) and unlink it from the tree (if it's linked)
01700             // This is all done by CascadeDelete()
01701             pNewNodePath->CascadeDelete(); 
01702             delete pNewNodePath;
01703             pNewNodePath = NULL;
01704         }
01705     }
01706 
01707     return bOK;
01708 }
01709 
01710 
01711 
01712 
01713 /********************************************************************************************
01714 
01715 >   BOOL NodeBitmapEffect::CanBecomeA(BecomeA* pBecomeA);
01716 
01717     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01718     Created:    08/02/2005
01719     Inputs:     Ink class to test
01720     Purpose:    Can become a path !
01721     SeeAlso:    
01722 
01723 ********************************************************************************************/
01724 
01725 BOOL NodeBitmapEffect::CanBecomeA(BecomeA* pBecomeA)
01726 {
01727     // Don't make a dumb square bitmap if the Op is a blend op because in that case
01728     // it's more useful to have the original shape with the effect
01729     // Or if this node is in the top surface of those being considered
01730     //      and the op tells us that the results of dobecomea will be left in place (i.e. under
01731     //      and effect stack)
01732     if (!IsLockedEffect())
01733     {
01734         if (pBecomeA->IsBlendBecomeA() || pBecomeA->ResultsStayInPlace())
01735         {
01736             return NodeEffect::CanBecomeA(pBecomeA);
01737         }
01738     }
01739 
01740     // We only do conversions if we are the top effect in the stack
01741     if (!IsLockedEffect() && FindParent() && FindParent()->IsEffect())
01742         return FALSE;
01743 
01744     if (pBecomeA->BAPath())
01745     {
01746         pBecomeA->AddCount(1);
01747 
01748         return TRUE;
01749     }
01750 
01751     return FALSE;
01752 }
01753 
01754 /********************************************************************************************
01755 
01756 >   virtual BOOL NodeBitmapEffect::CanGenerateBitmap()
01757 
01758     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01759     Created:    01/07/2005
01760     Inputs:     -
01761     Returns:    TRUE if this effect node can generate an original bitmap
01762                 FALSE otherwise
01763     Purpose:    Test whether node is big enough to bother with
01764     SeeAlso:    
01765 
01766 ********************************************************************************************/
01767 
01768 BOOL NodeBitmapEffect::CanGenerateBitmap()
01769 {
01770     double PixelWidth = GetPixelWidth();
01771     DocRect CaptureRect = GetChildBoundingRect();
01772     return (CaptureRect.Width()>=PixelWidth && CaptureRect.Height()>=PixelWidth);
01773 }
01774 
01775 
01776 
01777 
01778 /********************************************************************************************
01779 
01780 >   virtual BOOL NodeBitmapEffect::WriteBoundsRecord(BaseCamelotFilter* pFilter)
01781 
01782     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01783     Created:    30/09/2005
01784     Inputs:     pFilter = ptr to filter to write to
01785     Returns:    TRUE if ok, FALSE otherwise
01786     Purpose:    Begin to write out your child records, in the native format
01787 
01788                 The base class will write out a TAG_DOWN record, but only if it has a child ptr
01789 
01790     SeeAlso:    WritePostChildrenWeb(), WritePreChildrenWeb()
01791 
01792 ********************************************************************************************/
01793 
01794 BOOL NodeBitmapEffect::WriteBoundsRecord(BaseCamelotFilter* pFilter)
01795 {
01796     BOOL ok = TRUE;
01797 
01798     // Add a description of the TAG_COMPOUNDRENDER record, for older importers that don't understand this record
01799     pFilter->AddTagDescription(TAG_COMPOUNDRENDER, _R(IDS_TAG_COMPOUNDRENDER));
01800 
01801     // Write out the record
01802     DocRect Rect = GetChildBoundingRect();
01803 
01804     CamelotFileRecord Rec(pFilter, TAG_COMPOUNDRENDER, TAG_COMPOUNDRENDER_SIZE);
01805     ok = Rec.Init();
01806     if (ok) ok = Rec.WriteUINT32(0);            // Reserved
01807     if (ok) ok = Rec.WriteCoord(Rect.lo);
01808     if (ok) ok = Rec.WriteCoord(Rect.hi);
01809     if (ok) ok = pFilter->Write(&Rec);
01810 
01811     return ok;
01812 }
01813 
01814 
01815 
01816 
01817 
01818 /********************************************************************************************
01819     Class:      NodeLiveEffect
01820 
01821 ********************************************************************************************/
01822 
01823 /***********************************************************************************************
01824 
01825 >   NodeLiveEffect::NodeLiveEffect(Node*    ContextNode,
01826                         AttachNodeDirection Direction,
01827                         const DocRect&      BoundingRect,
01828                         BOOL                Locked = FALSE,
01829                         BOOL                Mangled = FALSE,
01830                         BOOL                Marked = FALSE,
01831                         BOOL                Selected = FALSE,
01832                         BOOL                Renderable = FALSE
01833                         )
01834 
01835     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01836     Created:    07/09/2004
01837     Inputs:     ContextNode: Pointer to a node which this node is to be attached to.
01838                 MonoOn Direction: MonoOff
01839                 Specifies the direction in which the node is to be attached to the
01840                 ContextNode. The values this variable can take are as follows:
01841                                   
01842                 PREV      : Attach node as a previous sibling of the context node
01843                 NEXT      : Attach node as a next sibling of the context node
01844                 FIRSTCHILD: Attach node as the first child of the context node
01845                 LASTCHILD : Attach node as a last child of the context node
01846 
01847                 BoundingRect: Bounding rectangle
01848 
01849                 The remaining inputs specify the status of the node:
01850             
01851                 Locked:     Is node locked ?
01852                 Mangled:    Is node mangled ?
01853                 Marked:     Is node marked ?
01854                 Selected:   Is node selected ?
01855 
01856     Purpose:    This constructor initialises the nodes flags and links it to ContextNode in the
01857                 direction specified by Direction. All neccesary tree links are updated.
01858     Note:       SetUpShape() must be called before the NodeRegularShape is in a state in which
01859                 it can be used.
01860     SeeAlso:    NodeRegularShape::SetUpShape
01861     Errors:     An ENSURE will occur if ContextNode is NULL
01862 
01863 ***********************************************************************************************/
01864 NodeLiveEffect::NodeLiveEffect(Node* ContextNode,  
01865                     AttachNodeDirection Direction,  
01866                     BOOL Locked, 
01867                     BOOL Mangled,  
01868                     BOOL Marked, 
01869                     BOOL Selected    
01870               ) : NodeBitmapEffect(ContextNode, Direction, Locked, Mangled, Marked, Selected )
01871 {                         
01872     m_rectEstimatedBounds = DocRect(0,0,0,0);
01873     m_lMaxBorder = 0;
01874     m_dPixelsPerInch = (double)NodeBitmapEffect::DefaultLivePixelsPerInch;
01875 }                        
01876  
01877 
01878 
01879 
01880 /*********************************************************************************************
01881 
01882 >   NodeLiveEffect::NodeLiveEffect() 
01883 
01884     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01885     Created:    07/09/2004
01886     Purpose:    
01887     Note:       
01888     SeeAlso:    
01889 
01890 **********************************************************************************************/
01891 NodeLiveEffect::NodeLiveEffect() : NodeBitmapEffect()
01892 {
01893     m_rectEstimatedBounds = DocRect(0,0,0,0);
01894     m_lMaxBorder = 0;
01895     m_dPixelsPerInch = (double)NodeBitmapEffect::DefaultLivePixelsPerInch;
01896 }
01897 
01898 
01899 
01900 
01901 /*********************************************************************************************
01902 
01903 >   NodeLiveEffect::~NodeLiveEffect() 
01904 
01905     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01906     Created:    07/09/2004
01907     Purpose:    Destructor
01908     Note:       
01909     SeeAlso:    
01910 
01911 **********************************************************************************************/
01912 NodeLiveEffect::~NodeLiveEffect()
01913 {
01914     m_pEditsDoc = NULL;             // m_pEditsDoc is a smart pointer so NULLing it Releases the COM interface
01915                                     // and releases any memory
01916     CBitmapCache* pBitmapCache = Camelot.GetBitmapCache();
01917     if (pBitmapCache!=NULL)
01918     {
01919         CBitmapCacheKey inky(this, 42);
01920         pBitmapCache->RemoveAllOwnedBitmaps(inky, FALSE, CACHEPRIORITY_PERMANENT);
01921     }
01922 }
01923 
01924 
01925 
01926 
01927 /********************************************************************************************
01928 
01929 >   DocRect NodeLiveEffect::GetBoundingRect(BOOL DontUseAttrs, BOOL HitTest)
01930 
01931     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01932     Created:    20/09/2004
01933     Returns:    The bounding box of the live effect
01934     Purpose:    Get the bounding rect of the cached processed bitmap
01935                 or the original bitmap if the processed isn't set yet...
01936                 or the children if neither is set yet...
01937 
01938 ********************************************************************************************/
01939 
01940 DocRect NodeLiveEffect::GetBoundingRect(BOOL DontUseAttrs, BOOL HitTest)
01941 {
01942     // Let sanity prevail!
01943     BOOL bIncludeAttrs = !DontUseAttrs;
01944 
01945     // Optimise this function by returning fast cached info if we know it's valid.
01946     if (IsBoundingRectValid && bIncludeAttrs)
01947         return BoundingRectangle;
01948 
01949     // Else work it out by looking up the cached bitmaps
01950     // and failing that by scanning our children
01951     if (bIncludeAttrs)
01952     {
01953         // We can check the bounds of our whacky effects bitmap
01954         CBitmapCache* pBitmapCache = Camelot.GetBitmapCache();
01955         if (pBitmapCache!=NULL)
01956         {
01957             // Look for cached processed bitmap
01958             CBitmapCacheKey inky(this, GetPixelWidth(), 1);             // Get cached BMP for this node at our dpi
01959             CCachedBitmap cbmp;
01960             BOOL bFound = pBitmapCache->Lookup(inky, cbmp);
01961             if (bFound)
01962             {
01963                 BoundingRectangle = cbmp.GetCachedRect();
01964                 IsBoundingRectValid = TRUE;
01965                 return BoundingRectangle;
01966             }
01967         }
01968     }
01969 
01970     // If we get here, we don't know what the bounds of the effect bitmap
01971     // or what they might be...
01972     // Make a best guess using previous knowledge if we have it
01973     //      m_rectEstimatedBounds
01974     //      m_lMaxBorder
01975     // and factor in an arbitrary border to allow the effect to create
01976     // a bigger bitmap than the original data.
01977     //
01978     DocRect brect = GetChildBoundingRect(bIncludeAttrs);                // Note - don't set IsBoundingRectValid yet
01979 
01980     if (bIncludeAttrs)
01981     {
01982         brect.Inflate(CAPTURE_BORDER*(INT32)GetPixelWidth());
01983 
01984         // Inflate by the previously known border width
01985         brect.Inflate((INT32)m_lMaxBorder);
01986 
01987         // NOTE! There's a possible optimisation to be had here:
01988         // If the border is known (not just default value) and is zero then we know that
01989         // the effect will not spread the bounds and so we don't need to expand the bounds
01990         // by 50 pixels to cope with it!
01991         //
01992         // Expand bounds to account for as yet unknown size increases that effects might apply
01993         brect.Inflate((INT32)GetPixelWidth()*50);
01994 
01995         // Include transformed bounds of last known bounding rect
01996         if (!m_rectEstimatedBounds.IsEmpty())
01997             brect = brect.Union(m_rectEstimatedBounds);
01998     }
01999 
02000     return brect;
02001 }
02002 
02003 
02004 
02005 
02006 /********************************************************************************************
02007 
02008 >   SubtreeRenderState NodeLiveEffect::RenderSubtree(RenderRegion* pRender, Node** ppNextNode, BOOL bClip)
02009 
02010     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02011     Created:    07/09/2004
02012     Inputs:     pRender - The region render into (or use as context for decisions about subtree)
02013                 ppNextNode - Address of node pointer for next node to render or run to after this
02014                 bClip - flag indicating whether to clip or not
02015     Purpose:    Do clever stuff on the way into a subtree, possibly modifying rendering
02016                 behaviour.
02017 
02018 ********************************************************************************************/
02019 
02020 SubtreeRenderState NodeLiveEffect::RenderSubtree(RenderRegion* pRender, Node** ppNextNode, BOOL bClip)
02021 {
02022     BOOL bRendered = FALSE;
02023 
02024     if (pRender == NULL)                            // If no render region supplied, assume we need to be rendered
02025         return SUBTREE_ROOTANDCHILDREN;
02026 
02027     // Let children render themselves directly if we're not showing filled paths so the user can
02028     // see their outlines
02029     if (pRender->RRQuality.GetFillQuality() <= Quality::Solid)
02030         return SUBTREE_ROOTANDCHILDREN;
02031 
02032     // Live effects need to be rendered in the complex bitmap stages of printing
02033     if (pRender->IsKindOf(CC_RUNTIME_CLASS(ScanningRenderRegion)))
02034     {
02035         ScanningRenderRegion* pScanner = (ScanningRenderRegion*)pRender;
02036         pScanner->ComplexShapeFoundWrapper();
02037         return SUBTREE_NORENDER;    // Don't render any of our children
02038     }
02039 
02040     CBitmapCache* pBitmapCache = Camelot.GetBitmapCache();
02041     if (pBitmapCache==NULL)
02042         return SUBTREE_NORENDER;
02043 
02044     // Find out whether we have a cached processed bitmap for this node...
02045     BOOL bFoundCached = FindCachedEffect(pBitmapCache);
02046 
02047     // Go find out about my bounding rectangle
02048     // If we don't have a cached bitmap then expand the bounding rect to ensure it will cover an expansion caused by the effect
02049     // If we do have a cached bitmap then use the bounding rect stored with the processed bitmap
02050     DocRect BoundingRect = GetBoundingRect();
02051     if (!BoundingRect.IsValid())
02052         return SUBTREE_ROOTANDCHILDREN;
02053 
02054     if (!bFoundCached)
02055         BoundingRect.Inflate((INT32)(GetPixelWidth()*150));     // Bodge to ensure LE is rendered before it grows
02056     DocRect ClipRect = pRender->GetClipRect();
02057 
02058     if (bClip && !ClipRect.IsIntersectedWith(BoundingRect))     // If not within the clipping rect then
02059         return SUBTREE_NORENDER;                                // Don't render us or our children
02060 
02061     // No need to check BackmostChanged node here because we never capture
02062     // our background in a 24BPP bitmap we always capture at 32BPP using cfLOCKEDTRANSPARENT
02063 
02064     // Now ask our derived classes to render what they need to render
02065     bRendered = RenderCachedEffect(pBitmapCache, pRender);
02066 
02067     if (bRendered)
02068         return SUBTREE_NORENDER;
02069 
02070     // If this region is "immediate rendering" then we should always render
02071     // Else try to avoid rendering to keep the user experience smooth...
02072     if (!pRender->GetImmediateRender())
02073     {
02074         // Any sort of drag prevents new cacheing (to keep drags running smoothly)
02075         if (GetQuickRender())
02076             return SUBTREE_ROOTANDCHILDREN;
02077 
02078         // XPE editing op can prevent new cacheing (to keep XPE edits running smoothly)
02079 PORTNOTE("xpe", "NodeLiveEffect::RenderSubtree - removed use of XPE")
02080 #if !defined(EXCLUDE_FROM_XARALX)
02081         if (!XPEHost::EnableLERendering(this))
02082             return SUBTREE_ROOTANDCHILDREN;                         // But allow children to render
02083 #endif
02084     }
02085 
02086     // If we couldn't find or render a cached bitmap then try to cache a new one
02087     // Only cache if it's worth it!
02088     if (CanGenerateBitmap())
02089     {
02090         DocRect CaptureRect = GetChildBoundingRect();           // Make sure we get our child bound not result of processing!
02091         CaptureRect.Inflate(CAPTURE_BORDER*(INT32)GetPixelWidth());
02092 
02093         // If child node can supply a bitmap directly then we'll have it!
02094         // Note that RenderAfterSubtree will only do anything if it finds this capture
02095         // (This is crucial because RenderCallback filtering might prevent RenderSubtree being
02096         //  called but it does not then also prevent RenderAfterSubtree being called for the
02097         //  same node)
02098         CaptureFlags caFlags = CaptureFlags(cfLOCKEDTRANSPARENT | cfFULLCOVERAGE | cfUNCLIP | (EnableDirectCapture() ? cfALLOWDIRECT : cfNONE));
02099         double dResolution = GetPixelsPerInch();
02100         //Capture* pCapture =
02101         pRender->StartCapture(this, CaptureRect, CAPTUREINFO(ctNESTABLE, caFlags), TRUE, FALSE, dResolution, GetInkNodeFromController());
02102 //      if (pCapture && pCapture->IsDirect())
02103 //          return SUBTREE_ROOTONLY;                            // Capture gets bitmap directly from child so child does not need to be rendered
02104     }
02105 
02106     return SUBTREE_ROOTANDCHILDREN;                             // We must render ourselves and our children
02107 }
02108 
02109 /********************************************************************************************
02110 
02111 >   BOOL NodeLiveEffect::GetProcessedBitmap(BOOL bDirect, LPBITMAPINFO* plpInfo, LPBYTE* plpBits, DocRect* pRect)
02112 
02113     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02114     Created:    13/09/2004
02115     Inputs:     bDirect - TRUE to get bounding rect in DirectBitmap space
02116                           FALSE to get bounding rect in Drawing space
02117     Outputs:    plpInfo - pointer to LPBITMAPINFO pointer to be written to for bitmap info
02118                 plpBits - pointer to LPBYTE pointer to be written to for bitmap data
02119                 pRect   - pointer to DocRect describing bitmap bounds
02120     Purpose:    -
02121 
02122 ********************************************************************************************/
02123 
02124 BOOL NodeLiveEffect::GetProcessedBitmap(BOOL bDirect, LPBITMAPINFO* plpInfo, LPBYTE* plpBits, DocRect* pRect)
02125 {
02126     CBitmapCache* pBitmapCache = Camelot.GetBitmapCache();
02127     if (pBitmapCache==NULL)
02128         return FALSE;
02129 
02130     CBitmapCacheKey inky(this, GetPixelWidth(), 1);                     // Get cached BMP for this node at our dpi
02131 
02132     // Look for a cached bitmap at the appropriate pixel size...
02133     CCachedBitmap       cbmp;
02134     BOOL                bFound = pBitmapCache->Lookup(inky, cbmp);
02135     if (bFound)
02136     {
02137         if (plpInfo)
02138             *plpInfo = cbmp.pbmpInfo;
02139         if (plpBits)
02140             *plpBits = cbmp.pbmpBits;
02141         if (pRect)
02142         {
02143             if (bDirect)
02144                 *pRect = m_rectDirectBitmap;
02145             else
02146                 *pRect = cbmp.GetCachedRect();
02147         }
02148         return TRUE;
02149     }
02150 
02151     if (plpInfo)
02152         *plpInfo = NULL;
02153     if (plpBits)
02154         *plpBits = NULL;
02155 
02156     return FALSE;
02157 }
02158 
02159 
02160 
02161 
02162 /********************************************************************************************
02163 
02164 >   DocRect NodeLiveEffect::SetProcessedBitmap(LPBITMAPINFO lpInfo, LPBYTE lpBits, DocRect rect, double xOffset, double yOffset, double dPixelWidth = 0, Matrix* pmatTransform = NULL)
02165 
02166     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02167     Created:    13/09/2004
02168     Inputs:     -
02169     Outputs:    lpInfo - reference to LPBITMAPINFO pointer for bitmap info
02170                 lpBits - reference to LPBYTE pointer for bitmap data
02171     Purpose:    -
02172 
02173 ********************************************************************************************/
02174 
02175 DocRect NodeLiveEffect::SetProcessedBitmap(LPBITMAPINFO lpInfo, LPBYTE lpBits, DocRect rect, INT32 width, INT32 height, double xOffset, double yOffset, double dPixelWidth, Matrix* pmatTransform)
02176 {
02177     BOOL bWasInvalidBounds = !IsBoundingRectValid;
02178     CBitmapCache* pBitmapCache = Camelot.GetBitmapCache();
02179     if (pBitmapCache==NULL)
02180         return rect;
02181 
02182     if (dPixelWidth==0)
02183         dPixelWidth = GetPixelWidth();
02184 
02185     if (rect.IsEmpty())
02186     {
02187         rect = GetChildBoundingRect();
02188         rect.Inflate(CAPTURE_BORDER*(INT32)dPixelWidth);
02189     }
02190 
02191     CBitmapCacheKey inky(this, dPixelWidth, 1);                     // Get cached BMP for this node at our dpi
02192     DocRect crect = AdjustPixelOffsets(rect, width, height, xOffset, yOffset, dPixelWidth);
02193     DocRect uprect = crect;
02194 
02195     // If we have a transform, then we must transform our coords before rendering
02196     DocCoord coords[3];
02197     coords[0] = crect.lo;
02198     coords[1] = DocCoord(crect.hi.x, crect.lo.y);
02199     coords[2] = DocCoord(crect.lo.x, crect.hi.y);
02200     if (pmatTransform)
02201         pmatTransform->transform(coords, 3);
02202 
02203     // Deallocate any cached DIB here
02204     CCachedBitmap cbmp;
02205     BOOL bFound = pBitmapCache->Lookup(inky, cbmp);
02206     if (bFound)
02207     {
02208         pBitmapCache->RemoveBitmap(inky);
02209         cbmp.Release();
02210         m_rectDirectBitmap = DocRect(0,0,0,0);
02211     }
02212 
02213     if (lpInfo!=NULL && lpBits!=NULL)
02214     {
02215         cbmp.pbmpInfo = lpInfo;
02216         cbmp.pbmpBits = lpBits;
02217 //      cbmp.SetCachedRect(crect);
02218         cbmp.SetCachedParallelogram(coords, 3);
02219         cbmp.nPriority = CACHEPRIORITY_PERMANENT;
02220 
02221         pBitmapCache->StoreBitmap(inky, cbmp);
02222 
02223         m_rectDirectBitmap = crect;         // "Cache" rectangle in DirectBitmap space for GetProcessedBitmap
02224 
02225         uprect = cbmp.GetCachedRect();
02226 
02227         IsBoundingRectValid = TRUE;         // URGH! Force InvalidateBoundingRect to go up parent links!
02228         InvalidateBoundingRect();           // Tell our parents that our bounds have changed
02229         BoundingRectangle = uprect;         // But we know our bounding rectangle now
02230         IsBoundingRectValid = TRUE;         // And we know that it's valid
02231 
02232         // Store some data about the bounds while we know it
02233         m_rectEstimatedBounds = uprect;
02234 
02235         // Store max border created by this effect so we can redraw correctly after scaling
02236         // rect is in DirectBitmap space, crect is in Drawing space, so we must get a version of rect
02237         // in Drawing space before we can compare the two rects to get m_lMaxBorder measured in
02238         // Drawing space dimensions...
02239         //
02240         // Transform rect into Drawing space...
02241         DocCoord OrigCoords[4];
02242         OrigCoords[0] = rect.lo;
02243         OrigCoords[1] = DocCoord(rect.lo.x, rect.hi.y);
02244         OrigCoords[2] = DocCoord(rect.hi.x, rect.lo.y);
02245         OrigCoords[3] = rect.hi;
02246         if (pmatTransform)
02247             pmatTransform->transform(OrigCoords, 4);
02248         // Form upright rect enclosing transformed coords...
02249         DocRect OrigRect(OrigCoords[0], OrigCoords[0]);
02250         OrigRect.IncludePoint(OrigCoords[1]);
02251         OrigRect.IncludePoint(OrigCoords[2]);
02252         OrigRect.IncludePoint(OrigCoords[3]);
02253         // Compare upright original rect against new upright rect to find max offset in Drawing space...
02254         m_lMaxBorder = max(OrigRect.lo.x-uprect.lo.x, OrigRect.lo.y-uprect.lo.y);
02255         m_lMaxBorder = max(uprect.hi.x-OrigRect.hi.x, m_lMaxBorder);
02256         m_lMaxBorder = max(uprect.hi.y-OrigRect.hi.y, m_lMaxBorder);
02257         // Safety check
02258         if ( !Error::IsUserName("Gavin") )
02259             ERROR3IF(m_lMaxBorder<0, "m_lMaxBorder has become negative!");
02260         m_lMaxBorder = 0;
02261 
02262         // If the processed bitmap is bigger than the original we must ensure the bounds are updated
02263         // (Compare two rects in DirectBitmap space)
02264         if (rect!=crect || bWasInvalidBounds)
02265         {
02266             DocView* pView = DocView::GetCurrent();
02267             if (pView)
02268                 pView->NotifyBoundsChanged();
02269         }
02270     }
02271 
02272     // Note! Leave bounds alone if setting processed bitmap to NULL in the hope they will persist...
02273     return uprect;
02274 }
02275 
02276 
02277 
02278 
02279 /********************************************************************************************
02280 
02281 >   virtual String NodeLiveEffect::Describe(BOOL Plural, BOOL Verbose = TRUE)
02282 
02283     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02284     Created:    07/09/2004
02285     Inputs:     Plural: Flag indicating if the string description should be plural or
02286                         singular. 
02287     Outputs:    -
02288     Retuns:     Description of the group node 
02289     Purpose:    To return a description of the Group object in either the singular or the 
02290                 plural. This method is called by the DescribeRange method.
02291                 
02292                 The description will always begin with a lower case letter.   
02293                 
02294     Errors:     (Need to do this)
02295     SeeAlso:    -
02296 
02297 ********************************************************************************************/
02298 
02299 String NodeLiveEffect::Describe(BOOL Plural, BOOL Verbose)
02300 {
02301     if (Plural)
02302         return(String(_R(IDS_LIVEEFFECT_DESCRP)));
02303     else
02304         return(String(_R(IDS_LIVEEFFECT_DESCRS)));
02305 };
02306 
02307 
02308 
02309 
02310 /***********************************************************************************************
02311 > Node* NodeLiveEffect::SimpleCopy()  
02312 
02313     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02314     Created:    09/09/2004
02315     Inputs:     -  
02316     Outputs:    
02317     Returns:    A copy of the node, or NULL if memory has run out 
02318          
02319     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
02320                 The function is virtual, and must be defined for all derived classes.  
02321                 
02322     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of memory
02323                 error and the function returns NULL.                                                                      
02324                                                                                  
02325 **********************************************************************************************/
02326 
02327 Node* NodeLiveEffect::SimpleCopy()
02328 {
02329     NodeLiveEffect* NodeCopy; 
02330     NodeCopy = new NodeLiveEffect();
02331     ERRORIF(NodeCopy == NULL, _R(IDE_NOMORE_MEMORY), NULL); 
02332     CopyNodeContents(NodeCopy);         
02333     return (NodeCopy);
02334 }   
02335 
02336 
02337 
02338    
02339 /***********************************************************************************************
02340 
02341 >   void NodeLiveEffect::CopyNodeContents(Node* pCopyOfNode)
02342 
02343     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02344     Created:    09/09/2004
02345     Inputs:     pCopyOfNode - The node to copy data to
02346     Outputs:    -
02347     Returns:    -
02348     Purpose:    Copies the data from this node to pCopyOfNode by first calling the base class to get it to
02349                 copy its stuff, and then copying its own stuff
02350     Scope:      protected
02351     SeeAlso:    NodeGroup::CopyNodeContents
02352 
02353 ***********************************************************************************************/
02354 
02355 void NodeLiveEffect::CopyNodeContents(NodeLiveEffect* pCopyOfNode)
02356 {
02357     NodeBitmapEffect::CopyNodeContents(pCopyOfNode);
02358 
02359     // Copy member vars here
02360     if (m_pEditsDoc)
02361     {
02362 PORTNOTETRACE("other","NodeLiveEffect::CopyNodeContents - not copying XML data");
02363 #ifndef EXCLUDE_FROM_XARALX
02364         pCopyOfNode->m_pEditsDoc = CXMLUtils::NewDocument(m_pEditsDoc);
02365 #endif
02366     }
02367     else
02368         pCopyOfNode->m_pEditsDoc = NULL;
02369     pCopyOfNode->m_dPixelsPerInch = m_dPixelsPerInch;
02370     pCopyOfNode->m_strDisplayName = m_strDisplayName;
02371     pCopyOfNode->m_rectEstimatedBounds = m_rectEstimatedBounds;
02372     pCopyOfNode->m_lMaxBorder = m_lMaxBorder;
02373     pCopyOfNode->m_rectDirectBitmap = m_rectDirectBitmap;
02374 
02375     // If this node cannot remake it's associated bitmap
02376     // Then we need to copy the cached bitmaps into the new node
02377     CopyCached(pCopyOfNode, GetPixelWidth(), 1);    // Copy cached bitmaps, options 0 and 1 (original and processed)
02378 }
02379 
02380 
02381 
02382 
02383 /***********************************************************************************************
02384 >   void NodeLiveEffect::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
02385 
02386     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02387     Created:    09/09/2004
02388     Outputs:    -
02389     Purpose:    Polymorphically copies the contents of this node to another
02390     Errors:     An assertion failure will occur if NodeCopy is NULL
02391     Scope:      protected
02392                                      
02393 ***********************************************************************************************/
02394 
02395 void NodeLiveEffect::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
02396 {
02397     ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node");
02398     ENSURE(IS_A(pNodeCopy, NodeLiveEffect), "PolyCopyNodeContents given wrong dest node type");
02399 
02400     if (IS_A(pNodeCopy, NodeLiveEffect))
02401         CopyNodeContents((NodeLiveEffect*)pNodeCopy);
02402 }
02403 
02404 
02405 
02406 
02407 /********************************************************************************************
02408 
02409 >   virtual UINT32 NodeLiveEffect::GetNodeSize() const
02410 
02411     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02412     Created:    09/09/2004
02413     Inputs:     -
02414     Outputs:    -
02415     Returns:    The size of the node in bytes
02416     Purpose:    For finding the size of the node 
02417                 
02418     SeeAlso:    Node::GetSubtreeSize
02419 
02420 ********************************************************************************************/
02421 
02422 UINT32 NodeLiveEffect::GetNodeSize() const 
02423 {     
02424     return sizeof(NodeLiveEffect);
02425 }  
02426 
02427 
02428 
02429 
02430 /********************************************************************************************
02431 
02432 >   virtual void NodeLiveEffect::Transform( TransformBase& Trans )
02433 
02434     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02435     Created:    21/09/2004
02436     Inputs:     Trans - The transform Object
02437     Purpose:    Transforms the LiveEffect node.
02438     SeeAlso:    NodeRenderableInk::Transform()
02439 
02440 ********************************************************************************************/
02441 
02442 void NodeLiveEffect::Transform( TransformBase& Trans )
02443 {
02444     CBitmapCache* pBitmapCache = Camelot.GetBitmapCache();
02445     ERROR3IF(pBitmapCache==NULL, "Can't find BitmapCache");
02446 
02447     // Transform the cached bitmaps
02448     CCachedBitmap cbmp;
02449     CBitmapCacheKey inky(this, GetPixelWidth(), 0);                     // Get cached BMP for this ORIGINAL node at our dpi
02450     BOOL bFound = pBitmapCache->Lookup(inky, cbmp);
02451     if (bFound)
02452     {
02453         cbmp.Transform(Trans);
02454         pBitmapCache->StoreBitmap(inky, cbmp);
02455     }
02456 
02457     CBitmapCacheKey inky1(this, GetPixelWidth(), 1);                    // Get cached BMP for this PROCESSED node at our dpi
02458     bFound = pBitmapCache->Lookup(inky1, cbmp);
02459     if (bFound)
02460     {
02461         cbmp.Transform(Trans);
02462         pBitmapCache->StoreBitmap(inky1, cbmp);
02463     }
02464     else
02465     {
02466         Trans.bHaveTransformedCached = FALSE;
02467         Trans.bTransformYourChildren = TRUE;
02468     }
02469 
02470     // No need to transform Option 2, processed/rendered bitmap because it is only
02471     // an intermediate stage for producing other cached bitmaps
02472     // and exists outside the drawing geometry domain anyway
02473 
02474     // Transform the estimated bounds
02475     DocCoord t[3];
02476     t[0] = m_rectEstimatedBounds.lo;
02477     t[1] = DocCoord(m_rectEstimatedBounds.hi.x, m_rectEstimatedBounds.lo.y);
02478     t[2] = DocCoord(m_rectEstimatedBounds.lo.x, m_rectEstimatedBounds.hi.y);
02479 
02480     Trans.Transform(t, 3);
02481 
02482     m_rectEstimatedBounds = DocRect(t[0], t[0]);
02483     m_rectEstimatedBounds.IncludePoint(t[1]);
02484     m_rectEstimatedBounds.IncludePoint(t[2]);
02485     m_rectEstimatedBounds.IncludePoint(DocCoord(t[2].x+t[1].x-t[0].x, t[2].y+t[1].y-t[0].y));
02486 
02487     // Note that we don't scale the m_lMaxBorder field here so that, if m_rectEstimatedBounds
02488     // gets smaller, m_lMaxBorder won't and will generate a better guess at the resulting
02489     // bounds in GetBoundingRect
02490 
02491     InvalidateBoundingRect();
02492 
02493     // Preserve current state of transformed cache flag
02494     BOOL bTransCache = Trans.bHaveTransformedCached;
02495 
02496     // Transform all the children...
02497     // No need to transfom children if we are being dragged and we have successfully transformed our cached bitmap
02498 //  if (!(IsDragged() && bFound))
02499     if (Trans.bTransformYourChildren)
02500         TransformChildren(Trans);
02501     else
02502     {
02503         TransformEffectAttrs(Trans);
02504         Trans.bHaveTransformedChildren = FALSE;
02505     }
02506 
02507     // If the current transform is a translation then we have successfully
02508     // transformed our cached info so don't allow our children to modify the state of
02509     // bHaveTransformedCached
02510     Trans.bHaveTransformedCached = bTransCache;
02511 //  if (bTransCache && Trans.IsTranslation())
02512 //  {
02513 //      Trans.bHaveTransformedCached = TRUE;
02514 //  } 
02515 }
02516 
02517 
02518 
02519 
02520 /********************************************************************************************
02521 
02522 >   virtual BOOL NodeLiveEffect::ReleaseCached(BOOL bAndParents = TRUE,
02523                                                      BOOL bAndChildren = TRUE,
02524                                                      BOOL bSelf = TRUE,
02525                                                      BOOL bAndDerived = TRUE)
02526 
02527     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02528     Created:    30/06/2004
02529     Returns:    TRUE if captured data was cached
02530     Purpose:    Protected Helper function
02531                 Use the CaptureManager to capture the results of rendering, cache them
02532                 and associate them with this Ink node
02533     SeeAlso:    NodeRenderableInk::RenderCached, CaptureCached
02534 
02535 ********************************************************************************************/
02536 
02537 BOOL NodeLiveEffect::ReleaseCached(BOOL bAndParents, BOOL bAndChildren, BOOL bSelf, BOOL bAndDerived)
02538 {
02539     // Don't release cached data if the release request is the result of transformation
02540     // re-rendering because we can transform our cached data!
02541     if (!IsDragged())
02542     {
02543         CBitmapCache* pBitmapCache = Camelot.GetBitmapCache();
02544         if (pBitmapCache!=NULL && bSelf)
02545         {
02546             CBitmapCacheKey inky(this, 42);
02547             pBitmapCache->RemoveAllOwnedBitmaps(inky, FALSE, CACHEPRIORITY_PERMANENT);
02548             m_rectDirectBitmap = DocRect(0,0,0,0);
02549         }
02550     }
02551 
02552     // If we should release our children's caches as well...
02553     if (bAndChildren)
02554     {
02555         Node* pChild = FindFirstChild();
02556         while (pChild)
02557         {
02558             if (pChild->IsBounded())
02559                 ((NodeRenderableBounded*)pChild)->ReleaseCached(FALSE, TRUE, TRUE, TRUE);
02560 
02561             pChild = pChild->FindNext();
02562         }
02563     }
02564 
02565     // If I can't be cached, neither can my parent...
02566     if (bAndParents && FindParent() && FindParent()->IsBounded())
02567         ((NodeRenderableBounded*)FindParent())->ReleaseCached(TRUE, FALSE, TRUE, TRUE);
02568 
02569     return TRUE;
02570 }
02571 
02572 
02573 
02574 
02575 /********************************************************************************************
02576 
02577 >   virtual BOOL NodeLiveEffect::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
02578 
02579     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02580     Created:    27/09/2004
02581     Inputs:     pFilter = ptr to the filter
02582     Returns:    TRUE if record is written, FALSE if not
02583     Purpose:    Writes the path record to the filter
02584     SeeAlso:    -
02585 
02586 ********************************************************************************************/
02587 
02588 BOOL NodeLiveEffect::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
02589 {
02590 #ifdef DO_EXPORT
02591 
02592     BOOL ok = TRUE;
02593 
02594     ok = WriteLiveEffect(pFilter);
02595 
02596     return ok;
02597 
02598 #else
02599     return FALSE;
02600 #endif
02601 }
02602 
02603 /********************************************************************************************
02604 
02605 >   virtual BOOL NodeLiveEffect::WritePreChildrenNative(BaseCamelotFilter* pFilter)
02606 
02607     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02608     Created:    27/09/2004
02609     Inputs:     pFilter = ptr to the filter
02610     Returns:    TRUE if record is written, FALSE if not
02611     Purpose:    Writes the path record to the filter
02612     SeeAlso:    -
02613 
02614 ********************************************************************************************/
02615 
02616 BOOL NodeLiveEffect::WritePreChildrenNative(BaseCamelotFilter* pFilter)
02617 {
02618 #ifdef DO_EXPORT
02619 
02620     BOOL ok = TRUE;
02621 
02622     ok = WriteLiveEffect(pFilter);
02623 
02624     return ok;
02625 
02626 #else
02627     return FALSE;
02628 #endif
02629 }
02630 
02631 
02632 
02633 
02634 /********************************************************************************************
02635 
02636 >   virtual BOOL NodeLiveEffect::WriteLiveEffect(BaseCamelotFilter* pFilter)
02637 
02638     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02639     Created:    27/09/2004
02640     Inputs:     pFilter = ptr to the filter
02641     Returns:    TRUE if record is written, FALSE if not
02642     Purpose:    Writes the path record to the filter
02643     SeeAlso:    -
02644 
02645 ********************************************************************************************/
02646 
02647 BOOL NodeLiveEffect::WriteLiveEffect(BaseCamelotFilter* pFilter)
02648 {
02649 #ifdef DO_EXPORT
02650     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
02651 
02652     BOOL ok = TRUE;
02653     BYTE Flags = 0;
02654 
02655     UINT32 Tag = TAG_LIVE_EFFECT;
02656 
02657     CXaraFileRecord Rec(Tag);
02658 
02659 PORTNOTETRACE("other","NodeLiveEffect::WriteLiveEffect - removed use of XML");
02660 #ifndef EXCLUDE_FROM_XARALX
02661     BSTR bstrValue;
02662     HRESULT hr;
02663     hr = m_pEditsDoc->get_xml(&bstrValue);
02664     ok = (SUCCEEDED(hr));
02665 #endif
02666     if (ok) ok = Rec.Init();
02667     if (ok) ok = Rec.WriteBYTE(Flags);                  // flags
02668     if (ok) ok = Rec.WriteDOUBLE(m_dPixelsPerInch);     // Resolution
02669     if (ok) ok = Rec.WriteUnicode(m_strPostProID);      // Effect ID
02670     if (ok) ok = Rec.WriteUnicode(m_strDisplayName);    // Display Name
02671     if (ok) ok = Rec.WriteUTF16STR(m_vstrEdits);        // UNICODE xml string edits list
02672 
02673     // Write the record
02674     if (ok) ok = pFilter->Write(&Rec);
02675 
02676     return ok;
02677 #else
02678     return FALSE;
02679 #endif
02680 }
02681 
02682 
02683 
02684 
02685 /********************************************************************************************
02686 
02687 >   virtual NodeRenderableInk* NodeLiveEffect::FindNodeAtPointHelper(const Spread* pSpread, const DocCoord dcPoint)
02688 
02689     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02690     Created:    29/09/2004
02691     Inputs:     pSpread - pointer to relevant spread (should be our ancestor somewhere)
02692                 dcPoint - point on spread under consideration
02693     Returns:    Pointer to node that should become selected as result of hit detection at
02694                 this point
02695     Purpose:    Allows a node class to control hit detection and selection of itself
02696     SeeAlso:    -
02697 
02698 ********************************************************************************************/
02699 
02700 NodeRenderableInk* NodeLiveEffect::FindNodeAtPointHelper(const Spread* pSpread, const DocCoord dcPoint)
02701 {
02702     // Non-destructive LiveEffects should be invisible to selection...
02703     // But they do render into the hit-detection bitmap so that the user can click
02704     // them where they are bigger than the original object
02705     // So skip down the tree until we hit a "real" object
02706     // NOTE! We assume that a non-destructive LiveEffect only contains one renderablechild
02707     NodeRenderableInk* pNode = this;
02708     while (pNode!=NULL && pNode->IsCompoundClass() && !(pNode->CanSelectAsCompoundParent() && pNode->PromoteHitTestOnChildrenToMe()))
02709     {
02710         pNode = ((NodeCompound*)pNode)->GetInkNodeFromController();
02711     }
02712 
02713     return pNode;
02714 }
02715 
02716 
02717 
02718 
02719 /********************************************************************************************
02720 
02721 >   virtual KernelBitmap* NodeLiveEffect::GetKernelBitmap(DocCoord* pCoords, BOOL bRetainCached = FALSE)
02722 
02723     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02724     Created:    09/02/2005
02725     Inputs:     bRetainCached - TRUE to retain the cached version when making the permanent bitmap
02726     Outputs:    pCoords - Array of coords filled in with 3 points defining parallelogram
02727     Returns:    Pointer to new KernelBitmap
02728     Purpose:    Allows a bitmap effect to create a permanent kernel bitmap version of itself
02729     SeeAlso:    -
02730 
02731 ********************************************************************************************/
02732 
02733 KernelBitmap* NodeLiveEffect::GetKernelBitmap(DocCoord* pCoords, BOOL bRetainCached)
02734 {
02735     // Get bitmap out of cache (hope it's still in there!)
02736     CBitmapCache* pBitmapCache = Camelot.GetBitmapCache();
02737     CBitmapCacheKey inky(this, GetPixelWidth(), 1);                     // Get cached BMP for this PROCESSED node at our dpi
02738     CCachedBitmap cbmp;
02739     BOOL bFoundCached = pBitmapCache->Lookup(inky, cbmp);
02740     if (!bFoundCached)
02741         return NULL;
02742 
02743     CWxBitmap          *wBitmap     = new CWxBitmap(cbmp.pbmpInfo, cbmp.pbmpBits);
02744     if (wBitmap==NULL)
02745         return NULL;
02746 
02747     wBitmap->SetHidden(TRUE);                                           // We don't want the user to see this bitmap in the gallery
02748     KernelBitmap* kBitmap   = new KernelBitmap(wBitmap);
02749     if (kBitmap==NULL)
02750     {
02751         delete wBitmap;
02752         return NULL;
02753     }
02754     Document* pDoc = Document::GetCurrent();
02755     BitmapList* pBmpList = pDoc->GetBitmapList();
02756     kBitmap->Attach(pBmpList);
02757 PORTNOTE("xpe", "NodeLiveEffect::GetKernelBitmap - removed use of XPE")
02758 #if !defined(EXCLUDE_FROM_XARALX)
02759     XPEHost::GetEffectDetails(m_strPostProID, &m_strDisplayName);
02760 #endif
02761     String_256 name(m_strDisplayName);
02762     kBitmap->SetName(name);
02763 
02764     if (pCoords)
02765     {
02766         pCoords[0] = cbmp.coord0;
02767         pCoords[1] = cbmp.coord1;
02768         pCoords[2] = cbmp.coord2;
02769     }
02770 
02771     if (!bRetainCached)
02772         pBitmapCache->RemoveBitmap(inky);
02773 
02774     return kBitmap;
02775 }
02776 
02777 
02778 
02779 
02780 /********************************************************************************************
02781 
02782 >   void NodeLiveEffect::RemoveBitmapFromCache()
02783 
02784     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02785     Created:    13/06/2005
02786     Inputs:     -
02787     Outputs:    -
02788     Returns:    -
02789     Purpose:    Remove the bitmap from the cache but don't vape the bitmap itself from memory
02790     SeeAlso:    -
02791 
02792 ********************************************************************************************/
02793 
02794 void NodeLiveEffect::RemoveBitmapFromCache()
02795 {
02796     CBitmapCache* pBitmapCache = Camelot.GetBitmapCache();
02797     CBitmapCacheKey inky(this, GetPixelWidth(), 1);         // Get cached BMP for this PROCESSED node at our dpi
02798     pBitmapCache->RemoveBitmap(inky);
02799 }
02800 
02801 
02802 
02803 
02804 /********************************************************************************************
02805     Class:      NodeLockedEffect
02806 
02807 ********************************************************************************************/
02808 
02809 /***********************************************************************************************
02810 
02811 >   NodeLockedEffect::NodeLockedEffect(Node*    ContextNode,
02812                         AttachNodeDirection Direction,
02813                         const DocRect&      BoundingRect,
02814                         BOOL                Locked = FALSE,
02815                         BOOL                Mangled = FALSE,
02816                         BOOL                Marked = FALSE,
02817                         BOOL                Selected = FALSE,
02818                         BOOL                Renderable = FALSE
02819                         )
02820 
02821     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02822     Created:    07/09/2004
02823     Inputs:     ContextNode: Pointer to a node which this node is to be attached to.
02824                 MonoOn Direction: MonoOff
02825                 Specifies the direction in which the node is to be attached to the
02826                 ContextNode. The values this variable can take are as follows:
02827                                   
02828                 PREV      : Attach node as a previous sibling of the context node
02829                 NEXT      : Attach node as a next sibling of the context node
02830                 FIRSTCHILD: Attach node as the first child of the context node
02831                 LASTCHILD : Attach node as a last child of the context node
02832 
02833                 BoundingRect: Bounding rectangle
02834 
02835                 The remaining inputs specify the status of the node:
02836             
02837                 Locked:     Is node locked ?
02838                 Mangled:    Is node mangled ?
02839                 Marked:     Is node marked ?
02840                 Selected:   Is node selected ?
02841 
02842     Purpose:    This constructor initialises the nodes flags and links it to ContextNode in the
02843                 direction specified by Direction. All neccesary tree links are updated.
02844     Note:       SetUpShape() must be called before the NodeRegularShape is in a state in which
02845                 it can be used.
02846     SeeAlso:    NodeRegularShape::SetUpShape
02847     Errors:     An ENSURE will occur if ContextNode is NULL
02848 
02849 ***********************************************************************************************/
02850 NodeLockedEffect::NodeLockedEffect(Node* ContextNode,  
02851                     AttachNodeDirection Direction,  
02852                     BOOL Locked, 
02853                     BOOL Mangled,  
02854                     BOOL Marked, 
02855                     BOOL Selected    
02856               ) : NodeBitmapEffect(ContextNode, Direction, Locked, Mangled, Marked, Selected )
02857 {
02858     m_PGram[0] = DocCoord(0,0);
02859     m_PGram[1] = DocCoord(0,0);
02860     m_PGram[2] = DocCoord(0,0);
02861 
02862     m_dPixelsPerInch = (double)NodeBitmapEffect::DefaultLockedPixelsPerInch;
02863     m_bIsDestructive    = TRUE;
02864 }                        
02865 
02866 
02867 
02868 
02869 /*********************************************************************************************
02870 
02871 >   NodeLockedEffect::NodeLockedEffect() 
02872 
02873     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02874     Created:    07/09/2004
02875     Purpose:    
02876     Note:       
02877     SeeAlso:    
02878 
02879 **********************************************************************************************/
02880 NodeLockedEffect::NodeLockedEffect() : NodeBitmapEffect()
02881 {
02882     m_PGram[0] = DocCoord(0,0);
02883     m_PGram[1] = DocCoord(0,0);
02884     m_PGram[2] = DocCoord(0,0);
02885 
02886     m_dPixelsPerInch = (double)NodeBitmapEffect::DefaultLockedPixelsPerInch;
02887     m_bIsDestructive    = TRUE;
02888 }
02889 
02890 
02891 
02892 
02893 /*********************************************************************************************
02894 
02895 >   NodeLockedEffect::~NodeLockedEffect() 
02896 
02897     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02898     Created:    08/11/2004
02899     Purpose:    Destructor
02900     Note:       
02901     SeeAlso:    
02902 
02903 **********************************************************************************************/
02904 NodeLockedEffect::~NodeLockedEffect()
02905 {
02906     m_BitmapRef.Detach();           // Detach bitmap ref
02907     m_pEditsDoc = NULL;             // m_pEditsDoc is a smart pointer so NULLing it Releases the COM interface
02908                                     // and releases any memory
02909 
02910     // Get rid of our original bitmap(s)
02911     CBitmapCache* pBitmapCache = Camelot.GetBitmapCache();
02912     if (pBitmapCache!=NULL)
02913     {
02914         CBitmapCacheKey inky(this, 42);
02915         pBitmapCache->RemoveAllOwnedBitmaps(inky, FALSE, CACHEPRIORITY_PERMANENT);
02916     }
02917 }
02918 
02919 
02920 
02921 
02922 /*********************************************************************************************
02923 
02924 >   virtual void NodeLockedEffect::UnlinkNodeFromTree(BaseDocument* pOwnerDoc)
02925 
02926     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02927     Created:    05/09/2005
02928     Purpose:    Pre-Destructor
02929                 Do smart tidy up of bitmap usage if we are being deleted from the tree
02930                 rather than simply unlinked temporarilly (signalled by pOwnerDoc being
02931                 non-null)
02932     Note:       
02933     SeeAlso:    
02934 
02935 **********************************************************************************************/
02936 void NodeLockedEffect::UnlinkNodeFromTree(BaseDocument* pOwnerDoc)
02937 {
02938     KernelBitmap* pOldBitmap = m_BitmapRef.GetBitmap();
02939     if (pOldBitmap && pOwnerDoc)
02940     {
02941         m_BitmapRef.Detach();       // Detach so that Enumerate function below returns NULL and OilBitmap::IsUsedInDocument operates correctly
02942 
02943         BitmapList* pBmpList = pOldBitmap->GetParentBitmapList();
02944         if (pBmpList)
02945         {
02946             if (pOwnerDoc && pOwnerDoc->IsKindOf(CC_RUNTIME_CLASS(Document)))
02947             {
02948                 Document* pBitmapDoc = (Document*)pOwnerDoc;
02949                 if (pBitmapDoc && !pOldBitmap->IsUsedInDocument(pBitmapDoc, TRUE))
02950                 {
02951                     pOldBitmap->Detach();
02952                     BROADCAST_TO_ALL(BitmapListChangedMsg(pBmpList, pOldBitmap));
02953                     delete pOldBitmap;
02954 
02955                     // Free up any unused bitmaps in the global list
02956                     // (just deleting the KernelBitmaps doesn't seem to do it)
02957                     Camelot.GetGlobalBitmapList()->DeleteAllUnusedBitmaps();
02958                 }
02959             }
02960         }
02961     }
02962 
02963     // Call base class
02964     NodeBitmapEffect::UnlinkNodeFromTree(pOwnerDoc);
02965 }
02966 
02967 
02968 
02969 
02970 /********************************************************************************************
02971 
02972 >   KernelBitmap* NodeLockedEffect::EnumerateBitmaps(UINT32 Count)
02973 
02974     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
02975     Created:    21/06/2005
02976     Inputs:     Count - the bitmap to get (see Purpose).
02977     Returns:    The KernelBitmap in use by the node, or NULL if no more are used.
02978     Purpose:    Find out what bitmaps, if any, are used by this node.
02979 
02980                 The base class returns NULL always, so you over-ride this in any node classes
02981                 that use bitmaps.
02982 
02983                 This function supports nodes that use more than one bitmap - you call this
02984                 function repeatedly and keep incrementing the Count parameter that you pass
02985                 in each time by 1.  You should stop calling it when it returns NULL, as this
02986                 indicates that no more bitmaps are used by this node.
02987                 Count should start off as 0 for the first call.  Note that this function
02988                 can (and often will) return NULL for the first call, as many nodes don't
02989                 use bitmaps, obviously.
02990 
02991     SeeAlso:    KernelBitmap, NodeBitmap
02992 
02993 ********************************************************************************************/
02994 
02995 KernelBitmap* NodeLockedEffect::EnumerateBitmaps(UINT32 Count)
02996 {
02997     if (Count == 0) return m_BitmapRef.GetBitmap();
02998 
02999     return NULL;
03000 }
03001 
03002 
03003 
03004 /********************************************************************************************
03005 
03006 >   DocRect NodeLockedEffect::GetBoundingRect(BOOL DontUseAttrs, BOOL HitTest)
03007 
03008     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03009     Created:    20/09/2004
03010     Returns:    The bounding box of the live effect
03011     Purpose:    Get the bounding rect of the cached processed bitmap
03012                 or the original bitmap if the processed isn't set yet...
03013                 or the children if neither is set yet...
03014 
03015 ********************************************************************************************/
03016 
03017 DocRect NodeLockedEffect::GetBoundingRect(BOOL DontUseAttrs, BOOL HitTest)
03018 {
03019     // Let sanity prevail!
03020     BOOL bIncludeAttrs = !DontUseAttrs;
03021 
03022     // Optimise this function by returning fast cached info if we know it's valid.
03023     if (IsBoundingRectValid && bIncludeAttrs)
03024         return BoundingRectangle;
03025 
03026     // Else work it out by looking up the cached bitmaps
03027     // and failing that by scanning our children
03028     if (bIncludeAttrs)
03029     {
03030         // We can check the bounds of our whacky effects bitmap
03031         if (m_BitmapRef.GetBitmap()!=NULL)
03032         {
03033             DocRect r(m_PGram[0], m_PGram[0]);
03034             r.IncludePoint(m_PGram[1]);
03035             r.IncludePoint(m_PGram[2]);
03036             r.IncludePoint(DocCoord(m_PGram[2].x+m_PGram[1].x-m_PGram[0].x, m_PGram[2].y+m_PGram[1].y-m_PGram[0].y));
03037             IsBoundingRectValid = TRUE;
03038             BoundingRectangle = r;
03039             return r;
03040         }
03041     }
03042 
03043     DocRect brect = GetChildBoundingRect(bIncludeAttrs);                // Note - don't set IsBoundingRectValid yet
03044 
03045     // Expand bounds to account for as yet unknown size increases that effects might apply
03046     if (bIncludeAttrs)
03047         brect.Inflate((INT32)(GetPixelWidth()*50+0.5));
03048 
03049     return brect;
03050 }
03051 
03052 
03053 
03054 
03055 /********************************************************************************************
03056 
03057 >   SubtreeRenderState NodeLockedEffect::RenderSubtree(RenderRegion* pRender, Node** ppNextNode, BOOL bClip)
03058 
03059     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03060     Created:    07/09/2004
03061     Inputs:     pRender - The region render into (or use as context for decisions about subtree)
03062                 ppNextNode - Address of node pointer for next node to render or run to after this
03063                 bClip - flag indicating whether to clip or not
03064     Purpose:    Do clever stuff on the way into a subtree, possibly modifying rendering
03065                 behaviour.
03066 
03067 ********************************************************************************************/
03068 
03069 SubtreeRenderState NodeLockedEffect::RenderSubtree(RenderRegion* pRender, Node** ppNextNode, BOOL bClip)
03070 {
03071 //  BOOL bRendered = FALSE;
03072 
03073     if (pRender == NULL)                            // If no render region supplied, assume we need to be rendered
03074         return SUBTREE_ROOTANDCHILDREN;
03075 
03076     DocRect BoundingRect = GetBoundingRect();
03077     if (!BoundingRect.IsValid())
03078         return SUBTREE_ROOTANDCHILDREN;
03079 
03080     DocRect ClipRect = pRender->GetClipRect();
03081     if (m_BitmapRef.GetBitmap()!=NULL)
03082     {
03083         // Go find out about my bounding rectangle
03084         // If we don't have a cached bitmap then expand the bounding rect to ensure it will cover an expansion caused by the effect
03085         // If we do have a cached bitmap then use the bounding rect stored with the processed bitmap
03086 
03087         if (bClip && !ClipRect.IsIntersectedWith(BoundingRect)) // If not within the clipping rect then
03088             return SUBTREE_NORENDER;                    // Don't render us or our children
03089 
03090         KernelBitmap* pkBitmap = m_BitmapRef.GetBitmap();
03091         if (pkBitmap==NULL || pkBitmap->HasBeenDeleted())
03092             return SUBTREE_ROOTANDCHILDREN;
03093 
03094 #ifdef _DEBUG
03095         BOOL bRendered = RenderCachedEffect(NULL, pRender);
03096         ERROR3IF(!bRendered, "How can something so simple fail to render?");
03097 #else
03098         RenderCachedEffect(NULL, pRender);
03099 #endif
03100 
03101         return SUBTREE_NORENDER;
03102     }
03103 
03104     BoundingRect.Inflate((INT32)(GetPixelWidth()*150));                     // Bodge to ensure LE is rendered before it grows
03105     if (bClip && !ClipRect.IsIntersectedWith(BoundingRect)) // If not within the clipping rect then
03106         return SUBTREE_NORENDER;                    // Don't render us or our children
03107 
03108     // If we couldn't find or render a cached bitmap then try to cache a new one
03109 //  double PixelWidth = GetPixelWidth();
03110 
03111     // Work out how much of the object we propose to capture
03112     // (This may change during the Capture if we have to fall back to 24BPP opaque capture)
03113     DocRect viewrect = ClipRect;
03114     DocRect CaptureRect = GetChildBoundingRect();           // Make sure we get our child bound not result of processing!
03115 
03116     // Only cache if it's worth it!
03117     if (CanGenerateBitmap())
03118     {
03119         // It's quicker to scan ahead looking for non-mix transparency than to find it
03120         // half way through rendering a bitmap...
03121         //
03122         // Note that RenderAfterSubtree will only do anything if it finds this capture
03123         // (This is crucial because RenderCallback filtering might prevent RenderSubtree being
03124         //  called but it does not then also prevent RenderAfterSubtree being called for the
03125         //  same node)
03126         DocRect CaptureRect = GetChildBoundingRect();   // Make sure we get our child bound not result of processing!
03127         CaptureRect.Inflate(CAPTURE_BORDER*(INT32)GetPixelWidth());
03128         CaptureFlags caFlags = CaptureFlags(cfLOCKEDTRANSPARENT | cfFULLCOVERAGE | cfUNCLIP | (EnableDirectCapture() ? cfALLOWDIRECT : cfNONE));
03129         double dResolution = GetPixelsPerInch();
03130         //Capture* pCapture =
03131         pRender->StartCapture(this, CaptureRect, CAPTUREINFO(ctNESTABLE, caFlags), TRUE, FALSE, dResolution, GetInkNodeFromController());
03132 //      if (pCapture && pCapture->IsDirect())
03133 //          return SUBTREE_ROOTONLY;                // Capture gets bitmap directly from child so child does not need to be rendered
03134     } 
03135 
03136     return SUBTREE_ROOTANDCHILDREN;                 // We must render ourselves and our children
03137 }
03138 
03139 
03140 
03141 
03142 /***********************************************************************************************
03143 
03144 >   virtual void NodeLockedEffect::Render(RenderRegion* pRRegion)
03145 
03146     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03147     Created:    14/12/2004
03148     Inputs:     Pointer to a render region
03149     Purpose:    Will render the liveeffect iff we have it cached - for hit detection reasons
03150 
03151 ***********************************************************************************************/
03152 
03153 void NodeLockedEffect::Render(RenderRegion* pRender)
03154 {
03155     if (m_BitmapRef.GetBitmap()!=NULL && pRender->IsHitDetect())
03156     {
03157         CWxBitmap* pWBitmap = (CWxBitmap*)m_BitmapRef.GetBitmap()->GetActualBitmap();
03158         if (pWBitmap==NULL || pWBitmap->HasBeenDeleted())
03159             return;
03160 
03161         LPBITMAPINFO lpInfo = pWBitmap->BMInfo;
03162         LPBYTE lpBits = pWBitmap->BMBytes;
03163 #ifdef _DEBUG
03164         BOOL bRendered = pRender->RenderBits(lpInfo, lpBits, m_PGram, 3, TRUE, this);
03165         ERROR3IF(!bRendered, "How can something so simple fail to render?");
03166 #else
03167         pRender->RenderBits(lpInfo, lpBits, m_PGram, 3, TRUE, this);
03168 #endif
03169     }
03170 }
03171 
03172 
03173 
03174 /********************************************************************************************
03175 
03176 >   BOOL NodeLockedEffect::GetProcessedBitmap(BOOL bDirect, LPBITMAPINFO* plpInfo, LPBYTE* plpBits, DocRect* pRect)
03177 
03178     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03179     Created:    13/09/2004
03180     Inputs:     -
03181     Outputs:    plpInfo - pointer to LPBITMAPINFO pointer to be written to for bitmap info
03182                 plpBits - pointer to LPBYTE pointer to be written to for bitmap data
03183     Purpose:    -
03184 
03185 ********************************************************************************************/
03186 
03187 BOOL NodeLockedEffect::GetProcessedBitmap(BOOL bDirect, LPBITMAPINFO* plpInfo, LPBYTE* plpBits, DocRect* pRect)
03188 {
03189     if (plpInfo)    *plpInfo = NULL;
03190     if (plpBits)    *plpBits = NULL;
03191 
03192     if (m_BitmapRef.GetBitmap()!=NULL)
03193     {
03194         CWxBitmap* pWBitmap = (CWxBitmap*)m_BitmapRef.GetBitmap()->GetActualBitmap();
03195         if (pWBitmap!=NULL && !pWBitmap->HasBeenDeleted())
03196         {
03197             if (plpInfo)    *plpInfo = pWBitmap->BMInfo;
03198             if (plpBits)    *plpBits = pWBitmap->BMBytes;
03199             if (pRect)
03200             {
03201                 if (bDirect)
03202                     *pRect = m_rectDirectBitmap;
03203                 else
03204                 {
03205                     DocRect uprect = DocRect(m_PGram[0], m_PGram[0]);
03206                     uprect.IncludePoint(m_PGram[1]);
03207                     uprect.IncludePoint(m_PGram[2]);
03208                     uprect.IncludePoint(DocCoord(m_PGram[2].x+m_PGram[1].x-m_PGram[0].x, m_PGram[2].y+m_PGram[1].y-m_PGram[0].y));
03209                     *pRect = uprect;
03210                 }
03211             }
03212 
03213             return TRUE;
03214         }
03215     }
03216 
03217     return FALSE;
03218 }
03219 
03220 /********************************************************************************************
03221 
03222 >   DocRect NodeLockedEffect::SetProcessedBitmap(LPBITMAPINFO lpInfo, LPBYTE lpBits, DocRect rect, double xOffset, double yOffset, double dPixelWidth = 0, Matrix* pmatTransform = NULL)
03223 
03224     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03225     Created:    13/09/2004
03226     Inputs:     -
03227     Outputs:    lpInfo - reference to LPBITMAPINFO pointer for bitmap info
03228                 lpBits - reference to LPBYTE pointer for bitmap data
03229     Purpose:    -
03230 
03231 ********************************************************************************************/
03232 
03233 DocRect NodeLockedEffect::SetProcessedBitmap(LPBITMAPINFO lpInfo, LPBYTE lpBits, DocRect rect, INT32 width, INT32 height, double xOffset, double yOffset, double dPixelWidth, Matrix* pmatTransform)
03234 {
03235     BOOL bWasInvalidBounds = !IsBoundingRectValid;
03236 
03237     if (dPixelWidth==0)
03238         dPixelWidth = GetPixelWidth();
03239 
03240     if (rect.IsEmpty())
03241     {
03242         rect = GetChildBoundingRect();
03243         rect.Inflate(CAPTURE_BORDER*(INT32)dPixelWidth);
03244     }
03245 
03246     DocRect crect = AdjustPixelOffsets(rect, width, height, xOffset, yOffset, dPixelWidth);
03247     DocRect uprect = crect;
03248 
03249     // If we have a transform, then we must transform our coords before rendering
03250     DocCoord coords[3];
03251     coords[0] = crect.lo;
03252     coords[1] = DocCoord(crect.hi.x, crect.lo.y);
03253     coords[2] = DocCoord(crect.lo.x, crect.hi.y);
03254 
03255     if (pmatTransform)
03256     {
03257         pmatTransform->transform(coords, 3);
03258 
03259         // Get new upright bounding rect for transformed coords
03260         uprect = DocRect(coords[0], coords[0]);
03261         uprect.IncludePoint(coords[1]);
03262         uprect.IncludePoint(coords[2]);
03263         uprect.IncludePoint(DocCoord(coords[2].x+coords[1].x-coords[0].x, coords[2].y+coords[1].y-coords[0].y));
03264     }
03265 
03266     // Store locked bitmaps using the old style Kernel/OilBitmap technology
03267     // so that they are permanent and can be loaded and saved more easily
03268     m_BitmapRef.Detach();
03269     m_rectDirectBitmap = DocRect(0,0,0,0);
03270 
03271     if (lpInfo && lpBits)
03272     {
03273         // Create a Kernel bitmap from the bmp data.
03274         CWxBitmap* wBitmap      = new CWxBitmap(lpInfo, lpBits);
03275         if (wBitmap==NULL)
03276             return uprect;
03277         wBitmap->SetHidden(TRUE);           // We don't want the user to see this bitmap in the gallery
03278         KernelBitmap* kBitmap   = new KernelBitmap(wBitmap);
03279         if (kBitmap==NULL)
03280         {
03281             delete wBitmap;
03282             return uprect;
03283         }
03284 
03285         m_rectDirectBitmap = crect;
03286 
03287         Document* pDoc = Document::GetCurrent();
03288         BitmapList* pBmpList = pDoc->GetBitmapList();
03289         kBitmap->Attach(pBmpList);
03290 PORTNOTE("xpe", "NodeLockedEffect::SetProcessedBitmap - removed use of XPE")
03291 #if !defined(EXCLUDE_FROM_XARALX)
03292         XPEHost::GetEffectDetails(m_strPostProID, &m_strDisplayName);
03293 #endif
03294         String_256 strName(m_strDisplayName);
03295         kBitmap->SetName(strName);
03296         m_BitmapRef.Attach(kBitmap);
03297 
03298         IsBoundingRectValid = TRUE;         // URGH! Force InvalidateBoundingRect to go up parent links!
03299         InvalidateBoundingRect();           // Tell our parents that our bounds have changed
03300         BoundingRectangle = uprect;         // But we know our bounding rectangle now
03301         m_PGram[0] = coords[0];
03302         m_PGram[1] = coords[1];
03303         m_PGram[2] = coords[2];
03304         IsBoundingRectValid = TRUE;         // And we know that it's valid
03305 
03306         // If the processed bitmap is bigger than the original we must ensure the bounds are updated
03307         if (rect!=uprect || bWasInvalidBounds)
03308         {
03309             DocView* pView = DocView::GetCurrent();
03310             if (pView)
03311                 pView->NotifyBoundsChanged();
03312         }
03313     }
03314 
03315     // Note! Leave bounds alone if not setting processed bitmap
03316     return uprect;
03317 }
03318 
03319 
03320 
03321 
03322 /********************************************************************************************
03323 
03324 >   BOOL NodeLockedEffect::RenderCachedEffect(CBitmapCache* pBitmapCache, RenderRegion* pRender, BOOL bIgnoreCapture = FALSE)
03325 
03326     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03327     Created:    01/08/2005
03328     Inputs:     -
03329     Outputs:    DocRect - rectangle of Processed bitmap in DirectBitmap space
03330     Returns:    TRUE if a rectangle was obtained successfully
03331                 FALSE otherwise
03332     Purpose:    -
03333 
03334 ********************************************************************************************/
03335 
03336 BOOL NodeLockedEffect::RenderCachedEffect(CBitmapCache* pBitmapCache, RenderRegion* pRender, BOOL bIgnoreCapture)
03337 {
03338     BOOL bRendered = FALSE;
03339 
03340     // No need to render if we are going to supply to a capture
03341     Capture* pCapture = pRender->GetTopCapture();
03342     if (!bIgnoreCapture && pCapture && pCapture->ConsumeDirectBitmap(this))
03343     {
03344         // Tell the caller that the effect has been "rendered"
03345         bRendered = TRUE;
03346     }
03347     else
03348     {
03349         CWxBitmap* pWBitmap = (CWxBitmap*)m_BitmapRef.GetBitmap()->GetActualBitmap();
03350         if (pWBitmap==NULL || pWBitmap->HasBeenDeleted())
03351             return FALSE;
03352 
03353         LPBITMAPINFO lpInfo = pWBitmap->BMInfo;
03354         LPBYTE lpBits = pWBitmap->BMBytes;
03355         bRendered = pRender->RenderBits(lpInfo, lpBits, m_PGram, 3, TRUE, this);
03356         ENSURE(bRendered, "How can something so simple fail to render?");
03357     }
03358 
03359     return bRendered;
03360 }
03361 
03362 
03363 
03364 
03365 /********************************************************************************************
03366 
03367 >   virtual String NodeLockedEffect::Describe(BOOL Plural, BOOL Verbose = TRUE)
03368 
03369     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03370     Created:    05/11/2004
03371     Inputs:     Plural: Flag indicating if the string description should be plural or
03372                         singular. 
03373     Outputs:    -
03374     Retuns:     Description of the group node 
03375     Purpose:    To return a description of the Group object in either the singular or the 
03376                 plural. This method is called by the DescribeRange method.
03377                 
03378                 The description will always begin with a lower case letter.   
03379                 
03380     Errors:     (Need to do this)
03381     SeeAlso:    -
03382 
03383 ********************************************************************************************/
03384 
03385 String NodeLockedEffect::Describe(BOOL Plural, BOOL Verbose)
03386 {
03387     if (Plural)
03388         return(String(_R(IDS_DLIVEEFFECT_DESCRP)));
03389     else
03390         return(String(_R(IDS_DLIVEEFFECT_DESCRS)));
03391 };
03392 
03393 
03394 
03395 
03396 /***********************************************************************************************
03397 > Node* NodeLockedEffect::SimpleCopy()  
03398 
03399     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03400     Created:    09/09/2004
03401     Inputs:     -  
03402     Outputs:    
03403     Returns:    A copy of the node, or NULL if memory has run out 
03404          
03405     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
03406                 The function is virtual, and must be defined for all derived classes.  
03407                 
03408     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of memory
03409                 error and the function returns NULL.                                                                      
03410                                                                                  
03411 **********************************************************************************************/
03412 
03413 Node* NodeLockedEffect::SimpleCopy()
03414 {
03415     NodeLockedEffect* NodeCopy; 
03416     NodeCopy = new NodeLockedEffect();
03417     ERRORIF(NodeCopy == NULL, _R(IDE_NOMORE_MEMORY), NULL); 
03418     CopyNodeContents(NodeCopy);         
03419     return (NodeCopy);
03420 }   
03421 
03422 
03423 
03424    
03425 /***********************************************************************************************
03426 
03427 >   void NodeLockedEffect::CopyNodeContents(Node* pCopyOfNode)
03428 
03429     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03430     Created:    09/09/2004
03431     Inputs:     pCopyOfNode - The node to copy data to
03432     Outputs:    -
03433     Returns:    -
03434     Purpose:    Copies the data from this node to pCopyOfNode by first calling the base class to get it to
03435                 copy its stuff, and then copying its own stuff
03436     Scope:      protected
03437     SeeAlso:    NodeGroup::CopyNodeContents
03438 
03439 ***********************************************************************************************/
03440 
03441 void NodeLockedEffect::CopyNodeContents(NodeLockedEffect* pCopyOfNode)
03442 {
03443     NodeBitmapEffect::CopyNodeContents(pCopyOfNode);
03444 
03445     // Copy member vars here
03446 PORTNOTE("other","NodeLockedEffect::CopyNodeContents - Removed CXMLUtils usage")
03447 #ifndef EXCLUDE_FROM_XARALX
03448     pCopyOfNode->m_pEditsDoc = CXMLUtils::NewDocument(m_pEditsDoc);
03449 #endif
03450     pCopyOfNode->m_dPixelsPerInch = m_dPixelsPerInch;
03451     pCopyOfNode->m_strDisplayName = m_strDisplayName;
03452     pCopyOfNode->m_rectDirectBitmap = m_rectDirectBitmap;
03453 
03454     pCopyOfNode->m_BitmapRef = m_BitmapRef;
03455     pCopyOfNode->m_PGram[0] = m_PGram[0];
03456     pCopyOfNode->m_PGram[1] = m_PGram[1];
03457     pCopyOfNode->m_PGram[2] = m_PGram[2];
03458     pCopyOfNode->m_bIsDestructive = m_bIsDestructive;
03459 }
03460 
03461 
03462 
03463 
03464 /***********************************************************************************************
03465 >   void NodeLiveEffect::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
03466 
03467     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03468     Created:    09/09/2004
03469     Outputs:    -
03470     Purpose:    Polymorphically copies the contents of this node to another
03471     Errors:     An assertion failure will occur if NodeCopy is NULL
03472     Scope:      protected
03473                                      
03474 ***********************************************************************************************/
03475 
03476 void NodeLockedEffect::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
03477 {
03478     ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node");
03479     ENSURE(IS_A(pNodeCopy, NodeLockedEffect), "PolyCopyNodeContents given wrong dest node type");
03480 
03481     if (IS_A(pNodeCopy, NodeLockedEffect))
03482         CopyNodeContents((NodeLockedEffect*)pNodeCopy);
03483 }
03484 
03485 
03486 
03487 
03488 /********************************************************************************************
03489 
03490 >   virtual UINT32 NodeLockedEffect::GetNodeSize() const
03491 
03492     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03493     Created:    09/09/2004
03494     Inputs:     -
03495     Outputs:    -
03496     Returns:    The size of the node in bytes
03497     Purpose:    For finding the size of the node 
03498                 
03499     SeeAlso:    Node::GetSubtreeSize
03500 
03501 ********************************************************************************************/
03502 
03503 UINT32 NodeLockedEffect::GetNodeSize() const 
03504 {     
03505     UINT32 Size = sizeof(NodeLockedEffect);
03506 
03507     // Nasty cast here to avoid const-ness of this pointer
03508     KernelBitmap* pBitmap = ((NodeLockedEffect*)this)->m_BitmapRef.GetBitmap();
03509     if (pBitmap && pBitmap->ActualBitmap)
03510     {
03511         Size += pBitmap->ActualBitmap->GetBitmapSize();
03512     }
03513 
03514     return Size;
03515 }  
03516 
03517 
03518 
03519 
03520 /********************************************************************************************
03521 
03522 >   virtual void NodeLockedEffect::Transform( TransformBase& Trans )
03523 
03524     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03525     Created:    21/09/2004
03526     Inputs:     Trans - The transform Object
03527     Purpose:    Transforms the LiveEffect node.
03528     SeeAlso:    NodeRenderableInk::Transform()
03529 
03530 ********************************************************************************************/
03531 
03532 void NodeLockedEffect::Transform( TransformBase& Trans )
03533 {
03534     // Transform the DocCoords of the parallelogram
03535     Trans.Transform(m_PGram, 3);
03536 
03537     InvalidateBoundingRect();
03538 
03539     // Transform all the children...
03540     if (Trans.bTransformYourChildren)
03541         TransformChildren(Trans);
03542     else
03543         TransformEffectAttrs(Trans);
03544 }
03545 
03546 
03547 
03548 
03549 /********************************************************************************************
03550 
03551 >   virtual BOOL NodeLockedEffect::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
03552 
03553     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03554     Created:    27/09/2004
03555     Inputs:     pFilter = ptr to the filter
03556     Returns:    TRUE if record is written, FALSE if not
03557     Purpose:    Writes the path record to the filter
03558     SeeAlso:    -
03559 
03560 ********************************************************************************************/
03561 
03562 BOOL NodeLockedEffect::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
03563 {
03564 #ifdef DO_EXPORT
03565 
03566     BOOL ok = TRUE;
03567 
03568     ok = WriteLockedEffect(pFilter);
03569 
03570     return ok;
03571 
03572 #else
03573     return FALSE;
03574 #endif
03575 }
03576 
03577 /********************************************************************************************
03578 
03579 >   virtual BOOL NodeLockedEffect::WritePreChildrenNative(BaseCamelotFilter* pFilter)
03580 
03581     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03582     Created:    27/09/2004
03583     Inputs:     pFilter = ptr to the filter
03584     Returns:    TRUE if record is written, FALSE if not
03585     Purpose:    Writes the path record to the filter
03586     SeeAlso:    -
03587 
03588 ********************************************************************************************/
03589 
03590 BOOL NodeLockedEffect::WritePreChildrenNative(BaseCamelotFilter* pFilter)
03591 {
03592 #ifdef DO_EXPORT
03593 
03594     BOOL ok = TRUE;
03595 
03596     ok = WriteLockedEffect(pFilter);
03597 
03598     return ok;
03599 
03600 #else
03601     return FALSE;
03602 #endif
03603 }
03604 
03605 
03606 
03607 
03608 /********************************************************************************************
03609 
03610 >   virtual BOOL NodeLockedEffect::WriteLockedEffect(BaseCamelotFilter* pFilter)
03611 
03612     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03613     Created:    27/09/2004
03614     Inputs:     pFilter = ptr to the filter
03615     Returns:    TRUE if record is written, FALSE if not
03616     Purpose:    Writes the path record to the filter
03617     SeeAlso:    -
03618 
03619 ********************************************************************************************/
03620 
03621 BOOL NodeLockedEffect::WriteLockedEffect(BaseCamelotFilter* pFilter)
03622 {
03623 #ifdef DO_EXPORT
03624     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
03625 
03626     BOOL ok = TRUE;
03627     BYTE Flags = 0;
03628     if (!m_bIsDestructive)      Flags |= 0x02;          // Flag set when NOT destructive for back-compatibility
03629 
03630     // Find the kernel bmp
03631     KernelBitmap* pBmp = m_BitmapRef.GetBitmap();
03632     ERROR2IF(pBmp == NULL, FALSE, "NULL kernel bitmap in WriteLockedEffect");
03633 
03634     // Must write out the bitmap first
03635     INT32 BitmapRecordRef = pFilter->WriteRecord(pBmp);
03636     ERROR2IF(BitmapRecordRef == 0, FALSE, "Bitmap ref is zero in WriteLockedEffect");
03637 
03638     // Is the bmp reference ok?
03639     if (ok) ok = (BitmapRecordRef != 0);
03640         
03641     UINT32 Tag = TAG_LOCKED_EFFECT;
03642 
03643     CXaraFileRecord Rec(Tag);
03644 
03645 PORTNOTETRACE("other","NodeLockedEffect::WriteLockedEffect - removed use of XML");
03646 #ifndef EXCLUDE_FROM_XARALX
03647     BSTR bstrValue;
03648     HRESULT hr;
03649     hr = m_pEditsDoc->get_xml(&bstrValue);
03650     ok = (SUCCEEDED(hr));
03651 #endif
03652     if (ok) ok = Rec.Init();
03653     if (ok) ok = Rec.WriteBYTE(Flags);                  // flags
03654     if (ok) ok = Rec.WriteDOUBLE(m_dPixelsPerInch);     // Resolution
03655     if (ok) ok = Rec.WriteReference(BitmapRecordRef);   // Bitmap Record Reference
03656     if (ok) ok = Rec.WriteCoordTrans(m_PGram[0], 0, 0); // Coords
03657     if (ok) ok = Rec.WriteCoordTrans(m_PGram[1], 0, 0);
03658     if (ok) ok = Rec.WriteCoordTrans(m_PGram[2], 0, 0);
03659     if (ok) ok = Rec.WriteUnicode(m_strPostProID);      // Effect ID
03660     if (ok) ok = Rec.WriteUnicode(m_strDisplayName);    // Display Name
03661     if (ok) ok = Rec.WriteUTF16STR(m_vstrEdits);        // UNICODE xml string edits list
03662 
03663     // Write the record
03664     if (ok) ok = pFilter->Write(&Rec);
03665 
03666     return ok;
03667 #else
03668     return FALSE;
03669 #endif
03670 }
03671 
03672 
03673 
03674 
03675 /********************************************************************************************
03676 
03677 >   virtual KernelBitmap* NodeLockedEffect::GetKernelBitmap(DocCoord* pCoords, BOOL bRetainCached = FALSE)
03678 
03679     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03680     Created:    09/02/2005
03681     Inputs:     bRetainCached - TRUE to retain the cached version when making the permanent bitmap
03682     Outputs:    pCoords - Array of coords filled in with 3 points defining parallelogram
03683     Returns:    Pointer to new KernelBitmap
03684     Purpose:    Allows a bitmap effect to create a permanent kernel bitmap version of itself
03685     SeeAlso:    -
03686 
03687 ********************************************************************************************/
03688 
03689 KernelBitmap* NodeLockedEffect::GetKernelBitmap(DocCoord* pCoords, BOOL bRetainCached)
03690 {
03691     KernelBitmap* kBitmap = m_BitmapRef.GetBitmap();
03692 
03693     if (pCoords)
03694     {
03695         pCoords[0] = m_PGram[0];
03696         pCoords[1] = m_PGram[1];
03697         pCoords[2] = m_PGram[2];
03698     }
03699 
03700     return kBitmap;
03701 }
03702 
03703 
03704 
03705 
03706 /********************************************************************************************
03707 
03708 >   void NodeLockedEffect::RenderObjectBlobs(RenderRegion* pRender)
03709 
03710     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03711     Created:    ??/1/2005
03712     Inputs:     pRender - the region to render the blobs to
03713     Purpose:    Renders the Object blobs for a Node Shape
03714     SeeAlso:    BlobManager
03715 
03716 ********************************************************************************************/
03717 
03718 void NodeLockedEffect::RenderObjectBlobs(RenderRegion* pRender)
03719 {
03720 #if !defined(EXCLUDE_FROM_RALPH)
03721     ERROR3IF(!IsSelected(), "Who's asking us to render blobs when we're not selected?");
03722     // Set the line colours etc as we need them
03723     DocRect r = GetBoundingRect();
03724     pRender->SetLineColour(COLOUR_NONE);
03725     pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
03726 
03727     pRender->DrawBlob(r.lo, BT_UNSELECTED);
03728     pRender->DrawBlob(DocCoord(r.hi.x, r.lo.y), BT_UNSELECTED);
03729     pRender->DrawBlob(r.hi, BT_UNSELECTED);
03730     pRender->DrawBlob(DocCoord(r.lo.x, r.hi.y), BT_UNSELECTED);
03731 #endif
03732 }
03733 
03734 
03735 
03736 /********************************************************************************************
03737 
03738 >   void NodeLockedEffect::RenderTinyBlobs(RenderRegion* pRender)
03739 
03740     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03741     Created:    ??/1/2005
03742     Inputs:     pRender - the region to render the blobs to
03743     Purpose:    Renders the Tiny blobs for a Node Shape
03744     SeeAlso:    BlobManager
03745 
03746 ********************************************************************************************/
03747 
03748 void NodeLockedEffect::RenderTinyBlobs(RenderRegion* pRender)
03749 {
03750 #if !defined(EXCLUDE_FROM_RALPH)
03751 //  ERROR3IF(!IsSelected(), "Who's asking us to render blobs when we're not selected?");
03752     // Set the line colours etc as we need them
03753     DocRect r = GetBoundingRect();
03754     pRender->SetLineColour(COLOUR_NONE);
03755     pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
03756 
03757     pRender->DrawBlob(r.hi, BT_UNSELECTED);
03758 #endif
03759 }
03760 
03761 
03762 
03763 
03764 /********************************************************************************************
03765 
03766 >   virtual NodeRenderableInk* NodeLockedEffect::GetInkNodeFromController() const
03767 
03768     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03769     Created:    06/08/2005
03770     Inputs:     -
03771     Outputs:    -
03772     Returns:    NodeRenderableInk* - Pointer to the single child ink node that this effect
03773                 derives all its input from (if there is just one child ink node)
03774                 Otherise NULL
03775     Purpose:    Find next node down in the effects stack
03776 
03777 ********************************************************************************************/
03778 
03779 NodeRenderableInk* NodeLockedEffect::GetInkNodeFromController() const
03780 {
03781     NodeRenderableInk* pNode = FindFirstChildInk();
03782     if (pNode == FindLastChildInk())
03783         return pNode;
03784 
03785     return NULL;
03786 }
03787 
03788 
03789 
03790 
03791 
03792 
03793 
03794 
03795 #ifdef FEATHER_EFFECT
03796 /********************************************************************************************
03797     Class:      NodeFeatherEffect
03798 
03799 ********************************************************************************************/
03800 
03801 /***********************************************************************************************
03802 
03803 >   NodeFeatherEffect::NodeFeatherEffect(Node*  ContextNode,
03804                         AttachNodeDirection Direction,
03805                         const DocRect&      BoundingRect,
03806                         BOOL                Locked = FALSE,
03807                         BOOL                Mangled = FALSE,
03808                         BOOL                Marked = FALSE,
03809                         BOOL                Selected = FALSE,
03810                         BOOL                Renderable = FALSE
03811                         )
03812 
03813     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03814     Created:    24/11/2004
03815     Inputs:     ContextNode: Pointer to a node which this node is to be attached to.
03816                 MonoOn Direction: MonoOff
03817                 Specifies the direction in which the node is to be attached to the
03818                 ContextNode. The values this variable can take are as follows:
03819                                   
03820                 PREV      : Attach node as a previous sibling of the context node
03821                 NEXT      : Attach node as a next sibling of the context node
03822                 FIRSTCHILD: Attach node as the first child of the context node
03823                 LASTCHILD : Attach node as a last child of the context node
03824 
03825                 BoundingRect: Bounding rectangle
03826 
03827                 The remaining inputs specify the status of the node:
03828             
03829                 Locked:     Is node locked ?
03830                 Mangled:    Is node mangled ?
03831                 Marked:     Is node marked ?
03832                 Selected:   Is node selected ?
03833 
03834     Purpose:    This constructor initialises the nodes flags and links it to ContextNode in the
03835                 direction specified by Direction. All neccesary tree links are updated.
03836     Note:       SetUpShape() must be called before the NodeRegularShape is in a state in which
03837                 it can be used.
03838     SeeAlso:    NodeRegularShape::SetUpShape
03839     Errors:     An ENSURE will occur if ContextNode is NULL
03840 
03841 ***********************************************************************************************/
03842 NodeFeatherEffect::NodeFeatherEffect(Node* ContextNode,  
03843                     AttachNodeDirection Direction,  
03844                     BOOL Locked, 
03845                     BOOL Mangled,  
03846                     BOOL Marked, 
03847                     BOOL Selected    
03848               ) : NodeLiveEffect(ContextNode, Direction, Locked, Mangled, Marked, Selected )
03849 {                         
03850 //  m_Profile = CProfileBiasGain()              // Defaults to this
03851     m_FeatherSize = 0;                          // Document base Feather has 0 feather size.
03852                                                 // The doc base feather is created when camelot
03853                                                 // initialises a new document.
03854                                                 // The default feather applied to each new object
03855                                                 // is also setup by this constructor.
03856 }                        
03857  
03858 
03859 
03860 
03861 /*********************************************************************************************
03862 
03863 >   NodeFeatherEffect::NodeFeatherEffect() 
03864 
03865     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03866     Created:    24/11/2004
03867     Purpose:    
03868     Note:       
03869     SeeAlso:    
03870 
03871 **********************************************************************************************/
03872 NodeFeatherEffect::NodeFeatherEffect() : NodeLiveEffect()
03873 {
03874 //  m_Profile = CProfileBiasGain()              // Defaults to this
03875     m_FeatherSize = 0;                          // Document base Feather has 0 feather size.
03876                                                 // The doc base feather is created when camelot
03877                                                 // initialises a new document.
03878                                                 // The default feather applied to each new object
03879                                                 // is also setup by this constructor.
03880 }
03881 
03882 
03883 
03884 
03885 /*********************************************************************************************
03886 
03887 >   NodeFeatherEffect::~NodeFeatherEffect() 
03888 
03889     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03890     Created:    24/11/2004
03891     Purpose:    Destructor
03892     Note:       
03893     SeeAlso:    
03894 
03895 **********************************************************************************************/
03896 NodeFeatherEffect::~NodeFeatherEffect()
03897 {
03898     CBitmapCache* pBitmapCache = Camelot.GetBitmapCache();
03899     if (pBitmapCache!=NULL)
03900     {
03901         CBitmapCacheKey inky(this, 42);
03902         pBitmapCache->RemoveAllOwnedBitmaps(inky, FALSE, CACHEPRIORITY_PERMANENT);
03903     }
03904 }
03905 
03906 
03907 
03908 
03909 /********************************************************************************************
03910 
03911 >   virtual String NodeFeatherEffect::Describe(BOOL Plural, BOOL Verbose = TRUE)
03912 
03913     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03914     Created:    24/11/2004
03915     Inputs:     Plural: Flag indicating if the string description should be plural or
03916                         singular. 
03917     Outputs:    -
03918     Retuns:     Description of the group node 
03919     Purpose:    To return a description of the Group object in either the singular or the 
03920                 plural. This method is called by the DescribeRange method.
03921                 
03922                 The description will always begin with a lower case letter.   
03923                 
03924     Errors:     (Need to do this)
03925     SeeAlso:    -
03926 
03927 ********************************************************************************************/
03928 
03929 String NodeFeatherEffect::Describe(BOOL Plural, BOOL Verbose)
03930 {
03931     if (Plural)
03932         return(String(_R(IDS_FEATHEREFFECT_DESCRP)));
03933     else
03934         return(String(_R(IDS_FEATHEREFFECT_DESCRS)));
03935 };
03936 
03937 
03938 
03939 
03940 /***********************************************************************************************
03941 > Node* NodeFeatherEffect::SimpleCopy()  
03942 
03943     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03944     Created:    24/11/2004
03945     Inputs:     -  
03946     Outputs:    
03947     Returns:    A copy of the node, or NULL if memory has run out 
03948          
03949     Purpose:    This method returns a shallow copy of the node with all Node pointers NULL. 
03950                 The function is virtual, and must be defined for all derived classes.  
03951                 
03952     Errors:     If memory runs out when trying to copy, then ERROR is called with an out of memory
03953                 error and the function returns NULL.                                                                      
03954                                                                                  
03955 **********************************************************************************************/
03956 
03957 Node* NodeFeatherEffect::SimpleCopy()
03958 {
03959     NodeFeatherEffect* NodeCopy; 
03960     NodeCopy = new NodeFeatherEffect();
03961     ERRORIF(NodeCopy == NULL, _R(IDE_NOMORE_MEMORY), NULL); 
03962     CopyNodeContents(NodeCopy);         
03963     return (NodeCopy);
03964 }   
03965 
03966 
03967 
03968    
03969 /***********************************************************************************************
03970 
03971 >   void NodeFeatherEffect::CopyNodeContents(Node* pCopyOfNode)
03972 
03973     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03974     Created:    24/11/2004
03975     Inputs:     pCopyOfNode - The node to copy data to
03976     Outputs:    -
03977     Returns:    -
03978     Purpose:    Copies the data from this node to pCopyOfNode by first calling the base class to get it to
03979                 copy its stuff, and then copying its own stuff
03980     Scope:      protected
03981     SeeAlso:    NodeGroup::CopyNodeContents
03982 
03983 ***********************************************************************************************/
03984 
03985 void NodeFeatherEffect::CopyNodeContents(NodeFeatherEffect* pCopyOfNode)
03986 {
03987     NodeLiveEffect::CopyNodeContents(pCopyOfNode);
03988 
03989     // Copy member vars here
03990     pCopyOfNode->m_FeatherSize = m_FeatherSize;
03991     pCopyOfNode->m_Profile = m_Profile;
03992 }
03993 
03994 
03995 
03996 
03997 /***********************************************************************************************
03998 >   void NodeLiveEffect::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
03999 
04000     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
04001     Created:    09/09/2004
04002     Outputs:    -
04003     Purpose:    Polymorphically copies the contents of this node to another
04004     Errors:     An assertion failure will occur if NodeCopy is NULL
04005     Scope:      protected
04006                                      
04007 ***********************************************************************************************/
04008 
04009 void NodeFeatherEffect::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
04010 {
04011     ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node");
04012     ENSURE(IS_A(pNodeCopy, NodeFeatherEffect), "PolyCopyNodeContents given wrong dest node type");
04013 
04014     if (IS_A(pNodeCopy, NodeFeatherEffect))
04015         CopyNodeContents((NodeFeatherEffect*)pNodeCopy);
04016 }
04017 
04018 
04019 
04020 
04021 /********************************************************************************************
04022 
04023 >   virtual UINT32 NodeFeatherEffect::GetNodeSize() const
04024 
04025     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
04026     Created:    24/11/2004
04027     Inputs:     -
04028     Outputs:    -
04029     Returns:    The size of the node in bytes
04030     Purpose:    For finding the size of the node 
04031                 
04032     SeeAlso:    Node::GetSubtreeSize
04033 
04034 ********************************************************************************************/
04035 
04036 UINT32 NodeFeatherEffect::GetNodeSize() const 
04037 {     
04038     return sizeof(NodeFeatherEffect);
04039 }  
04040 
04041 
04042 
04043 
04044 /********************************************************************************************
04045 
04046 >   virtual BOOL NodeFeatherEffect::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
04047 
04048     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
04049     Created:    27/09/2004
04050     Inputs:     pFilter = ptr to the filter
04051     Returns:    TRUE if record is written, FALSE if not
04052     Purpose:    Writes the path record to the filter
04053     SeeAlso:    -
04054 
04055 ********************************************************************************************/
04056 
04057 BOOL NodeFeatherEffect::WritePreChildrenWeb(BaseCamelotFilter* pFilter)
04058 {
04059 #ifdef DO_EXPORT
04060 
04061     BOOL ok = TRUE;
04062 
04063     ok = WriteFeatherEffect(pFilter);
04064 
04065     return ok;
04066 
04067 #else
04068     return FALSE;
04069 #endif
04070 }
04071 
04072 /********************************************************************************************
04073 
04074 >   virtual BOOL NodeFeatherEffect::WritePreChildrenNative(BaseCamelotFilter* pFilter)
04075 
04076     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
04077     Created:    27/09/2004
04078     Inputs:     pFilter = ptr to the filter
04079     Returns:    TRUE if record is written, FALSE if not
04080     Purpose:    Writes the path record to the filter
04081     SeeAlso:    -
04082 
04083 ********************************************************************************************/
04084 
04085 BOOL NodeFeatherEffect::WritePreChildrenNative(BaseCamelotFilter* pFilter)
04086 {
04087 #ifdef DO_EXPORT
04088 
04089     BOOL ok = TRUE;
04090 
04091     ok = WriteFeatherEffect(pFilter);
04092 
04093     return ok;
04094 
04095 #else
04096     return FALSE;
04097 #endif
04098 }
04099 
04100 
04101 
04102 
04103 /********************************************************************************************
04104 
04105 >   virtual BOOL NodeFeatherEffect::WriteFeatherEffect(BaseCamelotFilter* pFilter)
04106 
04107     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
04108     Created:    24/11/2004
04109     Inputs:     pFilter = ptr to the filter
04110     Returns:    TRUE if record is written, FALSE if not
04111     Purpose:    Writes the path record to the filter
04112     SeeAlso:    -
04113 
04114 ********************************************************************************************/
04115 
04116 BOOL NodeFeatherEffect::WriteFeatherEffect(BaseCamelotFilter* pFilter)
04117 {
04118 #ifdef DO_EXPORT
04119     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
04120 
04121     BOOL ok = TRUE;
04122     BYTE Flags = 0;
04123 
04124     UINT32 Tag = TAG_FEATHER_EFFECT;
04125 
04126     CXaraFileRecord Rec(Tag);
04127 
04128     if (ok) ok = Rec.Init();
04129     if (ok) ok = Rec.WriteBYTE(Flags);                  // flags
04130     if (ok) ok = Rec.WriteDOUBLE(m_dPixelsPerInch);     // Resolution
04131     if (ok) ok = Rec.WriteUnicode(m_strPostProID);      // Effect ID
04132     if (ok) ok = Rec.WriteUnicode(m_strDisplayName);    // Display Name
04133     if (ok) ok = Rec.WriteINT32(m_FeatherSize);         // MILLIPOINT Feather size
04134     if (ok) ok = Rec.WriteDOUBLE((double)m_Profile.GetBias());  // Profile Bias
04135     if (ok) ok = Rec.WriteDOUBLE((double)m_Profile.GetGain());  // Profile Gain
04136 
04137     // Write the record
04138     if (ok) ok = pFilter->Write(&Rec);
04139 
04140     return ok;
04141 #else
04142     return FALSE;
04143 #endif
04144 }
04145 
04146 
04147 
04148 
04149 /********************************************************************************************
04150 >   virtual BOOL NodeFeatherEffect::ProcessBitmap(RenderRegion* pRender,
04151                                                   CBitmapCache* pBitmapCache,
04152                                                   LPBITMAPINFO pBMPInfo,
04153                                                   LPBYTE pBMPBits,
04154                                                   DocRect BMPRect,
04155                                                   LPBITMAPINFO& pOutputInfo,
04156                                                   LPBYTE& pOutputBits,
04157                                                   double* pXOffset,
04158                                                   double* pYOffset)
04159 
04160     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
04161     Created:    24/11/2004
04162     Returns:    
04163     Purpose:    Processes the bitmap produced by the children of this node.
04164                 Can be overridden by derived classes to perform special processing
04165 
04166 ********************************************************************************************/
04167 
04168 BOOL NodeFeatherEffect::ProcessBitmap(RenderRegion* pRender,
04169                                       CBitmapCache* pBitmapCache,
04170                                       LPBITMAPINFO pBMPInfo,
04171                                       LPBYTE pBMPBits,
04172                                       DocRect BMPRect,
04173                                       LPBITMAPINFO& pOutputInfo,
04174                                       LPBYTE& pOutputBits,
04175                                       double* pXOffset,
04176                                       double* pYOffset)
04177 {
04178     pOutputInfo = NULL;
04179     pOutputBits = NULL;
04180     *pXOffset = 0;
04181     *pYOffset = 0;
04182 
04184     //  Create the feather bitmap transparency mask.
04186 
04187     // 1. Extract a mask from the RGBT input bitmap
04188     // 2. Contour inwards by half the blur diameter
04189     // 3. Blur by blur diameter
04190 
04191     double dPixBlurDiameter = (double)m_FeatherSize/GetPixelWidth();
04192     double dRemainingContour = dPixBlurDiameter/2;
04193     double dContourStep = 20;
04194 
04195     if (dPixBlurDiameter<1)
04196         return TRUE;
04197 
04198     // Initialise the processing pipeline state
04199     ProcessBitmapState bmpstate(pBMPInfo, pBMPBits, 0, 0, FALSE);
04200 //                                          DEBUGATTACH(bmpstate, "Feather Capture");
04201 
04202     // ----------------------------------
04203     // This is the processing pipeline
04204     // Note that contouring is sped up by doing it in steps of 20 pixels or less
04205     //
04206     // At each step:
04207     //  * Transform one state to the next (inside the function),
04208     //  * Record the new state (assign result to bmpstate)
04209     //  * Delete previous temp state (inside ProcessBitmapState assignment operator)
04210     //
04211     bmpstate = bmpstate.Create8BPPMask();
04212 //                                          DEBUGATTACH(bmpstate, "Feather Mask");
04213 
04214 //  bmpstate = bmpstate.Contour8BPP(-dPixBlurDiameter/2);
04215     while (dRemainingContour>0)
04216     {
04217         if (dContourStep>dRemainingContour) dContourStep = dRemainingContour;
04218         bmpstate = bmpstate.Contour8BPP(-dContourStep);
04219 //                                          DEBUGATTACH(bmpstate, "Feather Contour");
04220         dRemainingContour -= dContourStep;
04221     }
04222 //  bmpstate = bmpstate.Expand8BPP((INT32)(dPixBlurDiameter+1), 0xFF);
04223     UINT32 uBlurDiameter = UINT32(dPixBlurDiameter+0.5)-1 ;
04224     bmpstate = bmpstate.Expand8BPP(uBlurDiameter, 0xFF);
04225 //                                          DEBUGATTACH(bmpstate, "Feather Expand");
04226     bmpstate = bmpstate.Blur8BPP(dPixBlurDiameter);
04227 //                                          DEBUGATTACH(bmpstate, "Feather Blur");
04228     // ----------------------------------
04229 
04230     // If the final state is OK Extract the results from the pipeline
04231     if (bmpstate.IsOK())
04232     {
04233         bmpstate.GetPixelOffsets(pXOffset, pYOffset);
04234         bmpstate.GetBitmap(pOutputInfo, pOutputBits);       // (Makes final bitmap "permanent")
04235     }
04236     else
04237         bmpstate.DeInit();
04238 
04239     return bmpstate.IsOK();
04240 }
04241 
04242             
04243 
04244             
04245 /********************************************************************************************
04246 
04247 >   virtual BOOL NodeFeatherEffect::FindCachedEffect(CBitmapCache* pBitmapCache)
04248 
04249     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
04250     Created:    24/11/2004
04251     Inputs:     -
04252     Outputs:    -
04253     Purpose:    Find all cached items this node needs to call RenderCachedEffect
04254                 succesfully
04255                 Feathers need two bitmaps - captured objects and feather mask
04256 
04257 ********************************************************************************************/
04258 
04259 BOOL NodeFeatherEffect::FindCachedEffect(CBitmapCache* pBitmapCache)
04260 {
04261     BOOL bFoundCached = FALSE;
04262     CCachedBitmap cbmp;
04263 
04264     // TODO: Call GetChildDirectBitmap here?
04265     CBitmapCacheKey inky(this, GetPixelWidth(), 0);                     // Get cached BMP for this ORIGINAL node at our dpi
04266     bFoundCached = pBitmapCache->Lookup(inky, cbmp);
04267 //  bFoundCached = GetOriginalBitmap();
04268 
04269     CBitmapCacheKey inky2(this, GetPixelWidth(), 1);                    // Get cached BMP for this PROCESSED FEATHER node at our dpi
04270     bFoundCached = bFoundCached & pBitmapCache->Lookup(inky2, cbmp);
04271 
04272     return bFoundCached;
04273 }
04274 
04275 
04276 
04277 
04278 /********************************************************************************************
04279 
04280 >   BOOL NodeFeatherEffect::RenderCachedEffect(CBitmapCache* pBitmapCache, RenderRegion* pRender, BOOL bIgnoreCapture = FALSE)
04281 
04282     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
04283     Created:    24/11/2004
04284     Inputs:     -
04285     Outputs:    -
04286     Purpose:    Render the cached version of this node
04287                 Feathers need two bitmaps - captured objects and feather mask
04288 
04289 ********************************************************************************************/
04290 
04291 BOOL NodeFeatherEffect::RenderCachedEffect(CBitmapCache* pBitmapCache, RenderRegion* pRender, BOOL bIgnoreCapture)
04292 {
04293     BOOL bRendered = FALSE;
04294     BOOL bFoundCached = FALSE;
04295 
04296     // TODO: Call GetChildDirectBitmap here?
04297     CBitmapCacheKey inky(this, GetPixelWidth(), 0);                     // Get cached BMP for this ORIGINAL node at our dpi
04298     CCachedBitmap cbmp;
04299     bFoundCached = pBitmapCache->Lookup(inky, cbmp);
04300 //  LPBITMAPINFO lpOriginalInfo = NULL;
04301 //  LPBYTE lpOriginalBits = NULL;
04302 //  bFoundCached = GetOriginalBitmap();
04303 
04304     CBitmapCacheKey inky2(this, GetPixelWidth(), 1);                    // Get cached BMP for this PROCESSED FEATHER node at our dpi
04305     CCachedBitmap cbmpFeather;
04306     bFoundCached = bFoundCached & pBitmapCache->Lookup(inky2, cbmpFeather);
04307 
04308     if (bFoundCached)
04309     {
04310         // No need to render if we are going to supply to a capture
04311         Capture* pCapture = pRender->GetTopCapture();
04312         if (!bIgnoreCapture && pCapture && pCapture->ConsumeDirectBitmap(this))
04313         {
04314             // Tell the caller that the effect has been "rendered"
04315             bRendered = TRUE;
04316         }
04317         else
04318         {
04319             pRender->SaveContext();
04320 
04321 //#ifdef DEBUG
04322 //      bRendered = pRender->RenderBits(cbmpFeather.pbmpInfo, cbmpFeather.pbmpBits, &cbmpFeather.coord0, 3);
04323 //#endif
04324 
04325             CWxBitmap* wFeatherBitmap       = new CWxBitmap(cbmpFeather.pbmpInfo, cbmpFeather.pbmpBits);
04326             KernelBitmap* kFeatherBitmap    = new KernelBitmap(wFeatherBitmap,TRUE);
04327             if (kFeatherBitmap->GetBPP()==8)
04328             {
04329                 LPRGBQUAD pPalette = kFeatherBitmap->GetPaletteForBitmap();
04330                 for ( INT32 i=0 ; i<0x100 ; i++ )
04331                     (UINT32&)pPalette[i] = i*0x010101 ;
04332                     
04333                 kFeatherBitmap->SetAsGreyscale();
04334             }
04335 
04336             BitmapTranspFillAttribute* pBmpTranspFill = new BitmapTranspFillAttribute;
04337             TranspFillMappingLinearAttribute* pNoRepeatAttr = new TranspFillMappingLinearAttribute;
04338             if (kFeatherBitmap != NULL)
04339             {
04340                 pNoRepeatAttr->Repeat = 0;
04341                 pRender->SetTranspFillMapping(pNoRepeatAttr, TRUE);     // Temp, attribute will be deleted when unused
04342 
04343                 CreateBitmapTranspFill(kFeatherBitmap, &cbmpFeather.coord0, pBmpTranspFill);
04344                 pRender->SetTranspFillGeometry(pBmpTranspFill, TRUE);   // Temp, attribute will be deleted when unused
04345             }
04346 
04347             // URGH!    We're using transparency attr to implement feather
04348             // BUT      The user might want to apply an effect transparency attribute as well...
04349             // SO       We must capture the results of our feather transp, then apply the effect attrs
04350             if (!this->HasEffectAttrs())
04351                 // Simple, just render it as we always intended...
04352                 bRendered = pRender->RenderBits(cbmp.pbmpInfo, cbmp.pbmpBits, &cbmp.coord0, 3, FALSE, NULL);
04353             else
04354             {
04355                 // Tricky, capture feather transp, then apply effect attrs...
04356                 pRender->SaveContext();
04357 
04358                 LPBITMAPINFO lpCapturedInfo = NULL;
04359                 LPBYTE lpCapturedBits = NULL;
04360                 CaptureFlags caFlags = CaptureFlags(cfLOCKEDTRANSPARENT | cfUNCLIP | cfPIXWIDTHSCALE);
04361                 DocRect CaptureRect = GetBoundingRect();
04362                 pRender->StartCapture(this, CaptureRect, CAPTUREINFO(ctNESTABLE, caFlags), TRUE, FALSE, 0);
04363                 bRendered = pRender->RenderBits(cbmp.pbmpInfo, cbmp.pbmpBits, &cbmp.coord0, 3, FALSE, NULL);
04364                 pRender->StopCapture(this, FALSE, FALSE, &lpCapturedInfo, &lpCapturedBits, &CaptureRect);
04365 
04366                 pRender->RestoreContext();
04367 
04368                 if (bRendered && lpCapturedInfo && lpCapturedBits)
04369                 {
04370                     // Now render the bitmap we just captured using the effect attrs that are applied   vvvv
04371                     bRendered = pRender->RenderBits(lpCapturedInfo, lpCapturedBits, CaptureRect, FALSE, this);
04372                     FreeDIB(lpCapturedInfo, lpCapturedBits);
04373                 }
04374             }
04375 
04376             if (wFeatherBitmap)
04377                 wFeatherBitmap->BMBytes = ((CWxBitmap*)OILBitmap::Default)->BMBytes;
04378             if (kFeatherBitmap)
04379                 delete kFeatherBitmap;
04380 
04381             pRender->RestoreContext();
04382         }
04383     }
04384 
04385     return bRendered;
04386 }
04387 
04388 
04389 
04390 /********************************************************************************************
04391 
04392 >   BOOL NodeFeatherEffect::CreateBitmapTranspFill(KernelBitmap* pFeather, DocCoord* pCoords, BitmapTranspFillAttribute* BmpTranspFill)
04393 
04394     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
04395     Created:    24/01/2005
04396     Inputs:     -
04397     Outputs:    -
04398     Purpose:    Render the cached version of this node
04399                 Feathers need two bitmaps - captured objects and feather mask
04400 
04401 ********************************************************************************************/
04402 
04403 BOOL NodeFeatherEffect::CreateBitmapTranspFill(KernelBitmap* pFeather, DocCoord* pCoords, BitmapTranspFillAttribute* BmpTranspFill)
04404 {
04405     // Transp fill is same size as viewable part of the bitmap 
04406     BmpTranspFill->StartPoint = pCoords[0];
04407     BmpTranspFill->EndPoint   = pCoords[1];
04408     BmpTranspFill->EndPoint2    = pCoords[2];
04409     BmpTranspFill->EndPoint3    = DocCoord(pCoords[1].x, pCoords[2].y);
04410     BmpTranspFill->GetBitmapRef()->SetBitmap(pFeather);
04411     BmpTranspFill->Transp = 0;
04412     BmpTranspFill->EndTransp = 255;
04413     m_Profile.SetIsAFeatherProfile(TRUE);       // enable extra processing on the profile
04414     BmpTranspFill->SetProfile(m_Profile);
04415 
04416     return TRUE;
04417 }
04418 
04419 
04420 
04421 
04422 /********************************************************************************************
04423 >   static BOOL NodeFeatherEffect::ProcessBitmap( LPBITMAPINFO pBMPInfo,
04424                                                   LPBYTE pBMPBits,
04425                                                   double dPixBlurDiameter,
04426                                                   CProfileBiasGain profileFeather)
04427 
04428     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
04429     Created:    24/11/2004
04430     Returns:    
04431     Purpose:    Processes the bitmap produced by the children of this node.
04432                 Can be overridden by derived classes to perform special processing
04433 
04434 ********************************************************************************************/
04435 
04436 BOOL NodeFeatherEffect::ProcessBitmap(LPBITMAPINFO pBMPInfo,
04437                                       LPBYTE pBMPBits,
04438                                       double dPixBlurDiameter,
04439                                       CProfileBiasGain profileFeather)
04440 {
04441     LPBITMAPINFO pOutputInfo = NULL;
04442     LPBYTE pOutputBits = NULL;
04443 //  double XOffset = 0;
04444 //  double YOffset = 0;
04445 
04447     //  Create the feather bitmap transparency mask.
04449 
04450     // 1. Extract a mask from the RGBT input bitmap
04451     // 2. Contour inwards by half the blur diameter
04452     // 3. Blur by blur diameter
04453 
04454     dPixBlurDiameter = floor(dPixBlurDiameter+0.5);
04455     double dRemainingContour = dPixBlurDiameter/2;
04456     double dContourStep = 20;
04457 
04458     if (dPixBlurDiameter<1)
04459         return TRUE;
04460 
04461     // Initialise the processing pipeline state
04462     ProcessBitmapState bmpstate(pBMPInfo, pBMPBits, 0, 0, FALSE);
04463 //                                          DEBUGATTACH(bmpstate, "Feather Capture");
04464 
04465     // ----------------------------------
04466     // This is the processing pipeline
04467     // Note that contouring is sped up by doing it in steps of 20 pixels or less
04468     //
04469     // At each step:
04470     //  * Transform one state to the next (inside the function),
04471     //  * Record the new state (assign result to bmpstate)
04472     //  * Delete previous temp state (inside ProcessBitmapState assignment operator)
04473     //
04474     bmpstate = bmpstate.Create8BPPMask();
04475 //                                          DEBUGATTACH(bmpstate, "Feather Mask");
04476 
04477 //  bmpstate = bmpstate.Contour8BPP(-dPixBlurDiameter/2);
04478     while (dRemainingContour>0)
04479     {
04480         if (dContourStep>dRemainingContour) dContourStep = dRemainingContour;
04481         bmpstate = bmpstate.Contour8BPP(-dContourStep);
04482 //                                          DEBUGATTACH(bmpstate, "Feather Contour");
04483         dRemainingContour -= dContourStep;
04484     }
04485 //  bmpstate = bmpstate.Expand8BPP((INT32)(dPixBlurDiameter+1), 0xFF);
04486     UINT32 uBlurDiameter = UINT32(dPixBlurDiameter+0.5)-1 ;
04487     bmpstate = bmpstate.Expand8BPP(uBlurDiameter, 0xFF);
04488 //                                          DEBUGATTACH(bmpstate, "Feather Expand");
04489     bmpstate = bmpstate.Blur8BPP(dPixBlurDiameter);
04490 //                                          DEBUGATTACH(bmpstate, "Feather Blur");
04491     bmpstate = bmpstate.AddMaskTo(pBMPInfo, pBMPBits);
04492 //                                          DEBUGATTACH(bmpstate, "Feathered Bitmap");
04493     // ----------------------------------
04494 
04495     // If the final state is OK Extract the results from the pipeline
04496     if (bmpstate.IsOK())
04497     {
04498 //      bmpstate.GetPixelOffsets(pXOffset, pYOffset);
04499         bmpstate.GetBitmap(pOutputInfo, pOutputBits);       // (Makes final bitmap "permanent")
04500     }
04501     else
04502         bmpstate.DeInit();
04503 
04504     return bmpstate.IsOK();
04505 }
04506 
04507             
04508 
04509             
04510 /********************************************************************************************
04511 
04512 >   BOOL NodeFeatherEffect::GetDirectBitmap(RenderRegion* pRender, LPBITMAPINFO* plpInfo, LPBYTE* plpBits, DocRect* pRect, Matrix* pMat, double* pdRes)
04513 
04514     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
04515     Created:    03/08/2005
04516     Inputs:     pMat    - pointer to matrix awaiting update
04517     Outputs:    plpInfo - LPBITMAPINFO pointer describing bitmap
04518                 plpBits - LPBYTE pointer to bitmap data
04519                 pRect   - rect of Original bitmap data
04520                 pMat    - matrix describing transform from pRect to this instance on the page
04521                 pdRes   - resolution of this bitmap (dpi)
04522     Returns:    TRUE if this node can supply direct bitmap data to the caller
04523                 FALSE otherwise
04524     Purpose:    Return details of direct bitmap to caller (caller is usually a NodeBitmapEffect)
04525 
04526 ********************************************************************************************/
04527 
04528 /*BOOL NodeFeatherEffect::GetDirectBitmap(RenderRegion* pRender, LPBITMAPINFO* plpInfo, LPBYTE* plpBits, DocRect* pRect, Matrix* pMat, double* pdRes)
04529 {
04530     DocRect rectDirect;
04531     Matrix matLocalTransform;
04532     double dResolution = 0;
04533 
04534     GetDirectBitmapDetails(&rectDirect, &dResolution);
04535     if (pRect)  *pRect = rectDirect;
04536     if (pdRes)  *pdRes = dResolution;
04537 
04538     // We don't change our child's instance transformation
04539     // So just get that directly from the child
04540     BOOL bChildDirect = GetChildDirectBitmap(pRender, NULL, NULL, NULL, &matLocalTransform);
04541     if (pMat)   *pMat = matLocalTransform;
04542 
04543     // If we have effect attrs applied then we must make a subtree bitmap to capture them
04544     if (plpInfo && plpBits)
04545     {
04546         AttrFillGeometry* pTranspAttr = NULL;
04547         double dPixelWidth = 72000.0/dResolution;
04548 
04549         // Lookup processed bitmap in cache 
04550         CBitmapCache* pBitmapCache = Camelot.GetBitmapCache();
04551         if (pBitmapCache==NULL)
04552             return FALSE;
04553 
04554         CBitmapCacheKey inky2(this, dPixelWidth, 2);            // Option 2 is processed/rendered bitmap (see below)
04555         CCachedBitmap cbmp2;
04556         BOOL bFound = pBitmapCache->Lookup(inky2, cbmp2);
04557         if (bFound)
04558         {
04559             if (plpInfo)    *plpInfo = cbmp2.pbmpInfo;
04560             if (plpBits)    *plpBits = cbmp2.pbmpBits;
04561             return TRUE;
04562         }
04563 
04564         // We need to create a new bitmap here that captures the effects of the attributes
04565         //
04566         // If we don't have a RenderRegion, we can't build it, so return NULLs to indicate
04567         // that we need to be called again with a RenderRegion (allows quick test)
04568         // (See EnsureLiveEffectOriginalBitmaps)
04569         if (pRender == NULL)
04570         {
04571             if (plpInfo)    *plpInfo    = NULL;
04572             if (plpBits)    *plpBits    = NULL;
04573             return TRUE;
04574         }
04575 
04576         // We must "render" this bitmap to capture the attributes that effect its appearance
04577         // By default, we can't do arbitrarily transformed bitmaps - use a bitmap fill.
04578         DocRect CaptureRect = rectDirect;
04579 
04580         CaptureFlags caFlags = CaptureFlags(cfLOCKEDTRANSPARENT | cfFULLCOVERAGE);
04581         pRender->StartCapture(this, CaptureRect, CAPTUREINFO(ctNESTABLE, caFlags), TRUE, FALSE, dResolution);
04582         pRender->SaveContext();
04583 
04584         {   // ------------------------------------------------------
04585             // Setup coords for rendering in DirectBitmap domain
04586             DocCoord coords[3];
04587             coords[0] = CaptureRect.lo;
04588             coords[1] = DocCoord(CaptureRect.hix, CaptureRect.loy);
04589             coords[2] = DocCoord(CaptureRect.lox, CaptureRect.hiy);
04590 
04591             // NOTE! We can only deal with effect transparency at the moment!
04592             // Render the transparency geometry using inverse Direct-Screen transform
04593             // (This bitmap is being rendered in "Direct space" whereas the transparency attribute
04594             // was applied in "Screen space")
04595             NodeAttribute* pAttr;
04596             if (FindAppliedAttribute(CC_RUNTIME_CLASS(AttrTranspFillGeometry), &pAttr))
04597             {
04598                 if (pAttr &&
04599                     !pAttr->IsADefaultAttr() &&
04600                     !pAttr->HasEquivalentDefaultValue(TRUE) &&
04601                     pAttr->IsEffectAttribute())
04602                 {
04603                     pTranspAttr = (AttrFillGeometry*) ((AttrFillGeometry*)pAttr)->SimpleCopy();
04604                     DocCoord tcoords[4];
04605                     tcoords[0] = *pTranspAttr->GetStartPoint();
04606                     tcoords[1] = *pTranspAttr->GetEndPoint();
04607                     tcoords[2] = *pTranspAttr->GetEndPoint2();
04608                     tcoords[3] = *pTranspAttr->GetEndPoint3();
04609 
04610                     Matrix matInverse = matLocalTransform.Inverse();
04611                     matInverse.transform(tcoords, 4);
04612 
04613                     pTranspAttr->SetStartPoint(&tcoords[0]);
04614                     pTranspAttr->SetEndPoint(&tcoords[1]);
04615                     pTranspAttr->SetEndPoint2(&tcoords[2]);
04616                     pTranspAttr->SetEndPoint3(&tcoords[3]);
04617 
04618                     pTranspAttr->Render(pRender);
04619                 }
04620             }
04621 
04622             // TODO: This probably won't work because the geometry will need to be inverted into DirectBitmap space
04623             RenderCachedEffect(pBitmapCache, pRender, TRUE);
04624         }   // ------------------------------------------------------
04625 
04626         pRender->RestoreContext();
04627         if (pTranspAttr)
04628         {
04629             delete pTranspAttr;
04630             pTranspAttr = NULL;
04631         }
04632 
04633         LPBITMAPINFO lpInfo = NULL;
04634         LPBYTE lpBits = NULL;
04635         pRender->StopCapture(this, FALSE, FALSE, &lpInfo, &lpBits, &CaptureRect);
04636 
04637         // We should now have a bitmap containing an upright version of the NodeBitmap
04638         // with transparency and contoning applied as per the attributes in the tree
04639         if (lpInfo && lpBits)
04640         {
04641             *plpInfo = lpInfo;
04642             *plpBits = lpBits;
04643 
04644             // Cache the PROCESSED/RENDERED bitmap as Option 2
04645             cbmp2.pbmpBits = lpBits;
04646             cbmp2.pbmpInfo = lpInfo;
04647             cbmp2.SetCachedRect(CaptureRect);
04648             cbmp2.nPriority = CACHEPRIORITY_TEMPBITMAP_HIGH;
04649             if (cbmp2.IsValid())
04650                 pBitmapCache->StoreBitmap(inky2, cbmp2);
04651         }
04652     }
04653 
04654     return TRUE;
04655 }*/
04656 
04657 
04658 
04659 
04660 /********************************************************************************************
04661 >   virtual BOOL NodeFeatherEffect::CompareState(NodeEffect* pPPNode)
04662 
04663     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
04664     Created:    03/03/2005
04665     Returns:    TRUE if this state matches the state (and type) of the supplied node
04666     Purpose:    -
04667 
04668 ********************************************************************************************/
04669 
04670 BOOL NodeFeatherEffect::CompareState(NodeEffect* pPPNode)
04671 {
04672     if (!pPPNode->IsFeatherEffect())
04673         return FALSE;
04674 
04675     NodeFeatherEffect* pTest = (NodeFeatherEffect*)pPPNode;
04676 
04677     BOOL bSame = m_FeatherSize == pTest->m_FeatherSize;
04678     bSame = bSame && m_Profile == pTest->m_Profile;
04679 
04680     return bSame;
04681 }
04682 
04683 
04684 
04685 
04686 /********************************************************************************************
04687 >   virtual BOOL NodeFeatherEffect::GetQuickRender()
04688 
04689     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
04690     Created:    03/03/2005
04691     Returns:    TRUE if this feather effect should not start new captures at the minute
04692     Purpose:    -
04693 
04694 ********************************************************************************************/
04695 
04696 BOOL NodeFeatherEffect::GetQuickRender()
04697 {
04698     if (Operation::GetQuickRender(this)==FALSE)
04699         return FALSE;
04700 
04701     // Operation wants us to be quick but if it's a feather editing op
04702     // then we've got to re-render anyway!
04703     // Urgh! This is getting tortuous...
04704 PORTNOTE("effects", "NodeFeatherEffect::GetQuickRender - removed OpChangeFeatherSize usage.");
04705 #if defined(EXCLUDE_FROM_XARALX)
04706     return FALSE;
04707 #else
04708     Operation* pOp = Operation::GetCurrentDragOp();
04709     return (pOp!=NULL && !pOp->IsKindOf(CC_RUNTIME_CLASS(OpChangeFeatherSize)));
04710 #endif
04711 }
04712 #endif
04713 
04714 
04715 
04716 
04717 /********************************************************************************************
04718     Class:      LiveEffectRecordHandler
04719 
04720 ********************************************************************************************/
04721 
04722 /********************************************************************************************
04723 
04724 >   virtual UINT32* LiveEffectRecordHandler::GetTagList()
04725 
04726     Author:     Andy_Hills (Xara Group Ltd) <camelotdev@xara.com>
04727     Created:    30/10/00
04728     Inputs:     -
04729     Returns:    Ptr to a list of tag values, terminated by CXFRH_TAG_LIST_END
04730     Purpose:    Provides the record handler system with a list of records handled by this
04731                 handler
04732     SeeAlso:    -
04733 
04734 ********************************************************************************************/
04735 
04736 UINT32* LiveEffectRecordHandler::GetTagList()
04737 {
04738     static UINT32 TagList[] = { TAG_LIVE_EFFECT,
04739                                 TAG_LOCKED_EFFECT,
04740                                 TAG_FEATHER_EFFECT,
04741 
04742                                 CXFRH_TAG_LIST_END};
04743 
04744     return (UINT32*)&TagList;
04745 }
04746 
04747 
04748 /********************************************************************************************
04749 
04750 >   virtual BOOL LiveEffectRecordHandler::IsStreamed(UINT32 Tag)
04751 
04752     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
04753     Created:    29/01/2004
04754     Inputs:     The tag of the record
04755     Returns:    TRUE if this is a streamed record
04756                 FALSE otherwise
04757     Purpose:    Function to find out if the record is streamed or not.
04758     Errors:     -
04759     SeeAlso:    -
04760 
04761 ********************************************************************************************/
04762 
04763 BOOL LiveEffectRecordHandler::IsStreamed(UINT32 Tag)
04764 {
04765     // We handle both types so check what we need to do by the tag we have been given
04766     BOOL Streamed = FALSE;
04767     switch (Tag)
04768     {
04769         case TAG_LIVE_EFFECT:
04770         case TAG_LOCKED_EFFECT:
04771         case TAG_FEATHER_EFFECT:
04772             Streamed = FALSE;
04773 
04774             break;
04775         default:
04776             Streamed = FALSE;
04777             ERROR3_PF(("LiveEffectRecordHandler::IsStreamed I don't handle records with the tag (%d)\n", Tag));
04778             break;
04779     }
04780 
04781     return Streamed;
04782 }
04783 
04784 /********************************************************************************************
04785 
04786 >   virtual BOOL LiveEffectRecordHandler::HandleRecord(CXaraFileRecord* pCXaraFileRecord)
04787 
04788     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
04789     Created:    ??/10/2004
04790     Inputs:     pCXaraFileRecord = ptr to record to handle
04791     Returns:    TRUE if handled successfuly
04792                 FALSE otherwise
04793     Purpose:    Handles the given record.
04794     SeeAlso:    -
04795 
04796 ********************************************************************************************/
04797 
04798 BOOL LiveEffectRecordHandler::HandleRecord(CXaraFileRecord* pCXaraFileRecord)
04799 {
04800     ERROR2IF(pCXaraFileRecord == NULL,FALSE,"LiveEffectRecordHandler::HandleRecord pCXaraFileRecord is NULL");
04801 
04802     BOOL ok = TRUE;
04803     INT32 tag = pCXaraFileRecord->GetTag();
04804     switch (tag)
04805     {
04806     case TAG_LIVE_EFFECT:
04807         {
04808             // read in the record ---------------------------------------------------------
04809             // read flags
04810             BYTE Flags;
04811             if (ok) ok = pCXaraFileRecord->ReadBYTE(&Flags);
04812 
04813             // Read resolution
04814             double dPixelsPerInch;
04815             if (ok) ok = pCXaraFileRecord->ReadDOUBLE(&dPixelsPerInch);
04816 
04817             // Read Effect ID
04818             String_256 strPostProID;
04819             if (ok) ok = pCXaraFileRecord->ReadUnicode(&strPostProID);
04820 
04821             // Read Display Name
04822             String_256 strDisplayName;
04823             if (ok) ok = pCXaraFileRecord->ReadUnicode(&strDisplayName);
04824 
04825             // Read edits list
04826 //          _bstr_t bstrXML;
04827 //          if (ok) ok = pCXaraFileRecord->ReadBSTR(&bstrXML, pCXaraFileRecord->GetSize());
04828             StringVar strXML;
04829             if (ok) ok = pCXaraFileRecord->ReadUTF16STR(&strXML, pCXaraFileRecord->GetSize());
04830 
04831             // process the record ---------------------------------------------------------
04832             if (ok)
04833             {
04834                 NodeLiveEffect* pLE = new NodeLiveEffect();
04835 
04836                 pLE->m_dPixelsPerInch = dPixelsPerInch;
04837 
04838                 pLE->m_strPostProID = strPostProID;
04839 
04840                 pLE->m_strDisplayName = strDisplayName;
04841 
04842 PORTNOTETRACE("other","LiveEffectRecordHandler::HandleRecord - removed use of XML");
04843 #ifndef EXCLUDE_FROM_XARALX
04844                 VARIANT_BOOL varResult;
04845                 IXMLDOMDocumentPtr pxmlDoc = CXMLUtils::NewDocument();
04846                 HRESULT hr = pxmlDoc->loadXML(bstrXML, &varResult);
04847                 ok =  (SUCCEEDED(hr) && VARIANT_TRUE == varResult);
04848                 if (ok) pLE->m_pEditsDoc = pxmlDoc;
04849 #else
04850     pLE->m_pEditsDoc = NULL;
04851     pLE->m_vstrEdits = strXML;
04852 #endif
04853 
04854                 if (ok) ok = InsertNode(pLE);
04855             }
04856             return ok;
04857         }
04858         break;
04859 
04860     case TAG_LOCKED_EFFECT:
04861         {
04862             // read in the record ---------------------------------------------------------
04863             // read flags
04864             BYTE Flags;
04865             if (ok) ok = pCXaraFileRecord->ReadBYTE(&Flags);
04866 
04867             // Read resolution
04868             double dPixelsPerInch;
04869             if (ok) ok = pCXaraFileRecord->ReadDOUBLE(&dPixelsPerInch);
04870 
04871             // Read bitmap ref
04872             INT32 BitmapRef;
04873             if (ok) ok = pCXaraFileRecord->ReadINT32(&BitmapRef);
04874 
04875             // Read coords
04876             DocCoord tc[3];
04877             if (ok) ok = pCXaraFileRecord->ReadCoordTrans(&tc[0], 0, 0);
04878             if (ok) ok = pCXaraFileRecord->ReadCoordTrans(&tc[1], 0, 0);
04879             if (ok) ok = pCXaraFileRecord->ReadCoordTrans(&tc[2], 0, 0);
04880 
04881             // Read Effect ID
04882             String_256 strPostProID;
04883             if (ok) ok = pCXaraFileRecord->ReadUnicode(&strPostProID);
04884 
04885             // Read Display Name
04886             String_256 strDisplayName;
04887             if (ok) ok = pCXaraFileRecord->ReadUnicode(&strDisplayName);
04888 
04889             // Read edits list
04890 //          _bstr_t bstrXML;
04891 //          if (ok) ok = pCXaraFileRecord->ReadBSTR(&bstrXML, pCXaraFileRecord->GetSize());
04892             StringVar strXML;
04893             if (ok) ok = pCXaraFileRecord->ReadUTF16STR(&strXML, pCXaraFileRecord->GetSize());
04894 
04895             // process the record ---------------------------------------------------------
04896             if (ok)
04897             {
04898                 NodeLockedEffect* pLE = new NodeLockedEffect();
04899 
04900                 pLE->m_bIsDestructive = !((Flags & 0x02) == 0x02);      // Flag set in file when NOT destructive for back-compatibility
04901 
04902                 pLE->m_dPixelsPerInch = dPixelsPerInch;
04903                 pLE->m_strPostProID = strPostProID;
04904                 pLE->m_strDisplayName = strDisplayName;
04905                 pLE->m_PGram[0] = tc[0];
04906                 pLE->m_PGram[1] = tc[1];
04907                 pLE->m_PGram[2] = tc[2];
04908 
04909 PORTNOTETRACE("other","LiveEffectRecordHandler::HandleRecord - removed use of XML");
04910 #ifndef EXCLUDE_FROM_XARALX
04911                 VARIANT_BOOL varResult;
04912                 IXMLDOMDocumentPtr pxmlDoc = CXMLUtils::NewDocument();
04913                 HRESULT hr = pxmlDoc->loadXML(bstrXML, &varResult);
04914                 ok =  (SUCCEEDED(hr) && VARIANT_TRUE == varResult);
04915                 if (ok) pLE->m_pEditsDoc = pxmlDoc;
04916 #else
04917     pLE->m_pEditsDoc = NULL;
04918     pLE->m_vstrEdits = strXML;
04919 #endif
04920 
04921                 // Convert the bmp reference into a kernel bmp
04922                 if (ok)
04923                 {
04924                     KernelBitmap* pBitmap = NULL;
04925                     pBitmap = GetReadBitmapReference(BitmapRef);
04926                     pBitmap->GetActualBitmap()->SetHidden(TRUE);        // We don't want the user to see this bitmap in the gallery
04927                     ok = (pBitmap != NULL);
04928                     if (ok) pLE->m_BitmapRef.Attach(pBitmap);
04929                 }
04930 
04931                 if (ok) ok = InsertNode(pLE);
04932             }
04933 
04934             return ok;
04935         }
04936         break;
04937 
04938 #ifdef FEATHER_EFFECT
04939     case TAG_FEATHER_EFFECT:
04940         {
04941             // read in the record ---------------------------------------------------------
04942             // read flags
04943             BYTE Flags;
04944             if (ok) ok = pCXaraFileRecord->ReadBYTE(&Flags);
04945 
04946             // Read resolution
04947             double dPixelsPerInch;
04948             if (ok) ok = pCXaraFileRecord->ReadDOUBLE(&dPixelsPerInch);
04949 
04950             // Read Effect ID
04951             String_256 strPostProID;
04952             if (ok) ok = pCXaraFileRecord->ReadUnicode(&strPostProID);
04953 
04954             // Read Display Name
04955             String_256 strDisplayName;
04956             if (ok) ok = pCXaraFileRecord->ReadUnicode(&strDisplayName);
04957 
04958             // Read feather details
04959             MILLIPOINT mpFeatherSize = 0;
04960             double dBias = 0;
04961             double dGain = 0;
04962             if (ok) ok = pCXaraFileRecord->ReadINT32(&mpFeatherSize);
04963             if (ok) ok = pCXaraFileRecord->ReadDOUBLE(&dBias);
04964             if (ok) ok = pCXaraFileRecord->ReadDOUBLE(&dGain);
04965 
04966             // process the record ---------------------------------------------------------
04967             if (ok)
04968             {
04969                 NodeFeatherEffect* pFE = new NodeFeatherEffect();
04970 
04971                 pFE->m_dPixelsPerInch = dPixelsPerInch;
04972 
04973                 pFE->m_strPostProID = strPostProID;
04974 
04975                 pFE->m_strDisplayName = strDisplayName;
04976 
04977                 pFE->SetFeatherSize(mpFeatherSize);
04978 
04979                 CProfileBiasGain Profile((AFp)dBias, (AFp)dGain);
04980                 pFE->SetProfile(Profile);
04981 
04982                 if (ok) ok = InsertNode(pFE);
04983             }
04984 
04985             return ok;
04986         }
04987         break;
04988 #endif
04989 
04990     default:
04991         ERROR3_PF(("I don't handle records with the tag (%d)\n", pCXaraFileRecord->GetTag()));
04992         break;
04993     }
04994 
04995     return FALSE;
04996 }
04997 
04998 
04999 
05000 
05001 /********************************************************************************************
05002 
05003 >   virtual BOOL LiveEffectRecordHandler::HandleStreamedRecord(CXaraFile * pCXFile, UINT32 Tag,UINT32 Size,UINT32 RecordNumber)
05004 
05005     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
05006     Created:    29/01/2004
05007     Inputs:     pCXFile = access to the CXaraFile class
05008                 Tag  = the tag value
05009                 Size = size of record
05010                 RecordNumber = the record number in the file
05011     Returns:    TRUE if handled ok
05012                 FALSE otherwise
05013     Purpose:    This is the bitmap streamed record handler. It handles the loading of bitmap
05014                 definitions.
05015     Errors:     -
05016     SeeAlso:    -
05017 
05018 ********************************************************************************************/
05019 
05020 BOOL LiveEffectRecordHandler::HandleStreamedRecord(CXaraFile * pCXFile, UINT32 Tag,UINT32 Size,UINT32 RecordNumber)
05021 {
05022     ERROR2IF(pCXFile == NULL,FALSE,"BitmapRecordHandler::HandleStreamedRecord pCXFile is NULL");
05023 
05024     ERROR3_PF(("Unimplemented!", Tag));
05025 
05026     return TRUE;
05027 }
05028 
05029 
05030 
05031 
05032 /********************************************************************************************
05033 
05034 >   virtual void LiveEffectRecordHandler::GetRecordDescriptionText(CXaraFileRecord* pRecord,StringBase* pStr)
05035 
05036     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
05037     Created:    30/09/2005
05038     Inputs:     pRecord = ptr to a record
05039                 pStr = ptr to string to update
05040     Returns:    -
05041     Purpose:    Produce a textual description of the specified record
05042     Errors:     -
05043     SeeAlso:    -
05044 
05045 ********************************************************************************************/
05046 
05047 #ifdef XAR_TREE_DIALOG
05048 void LiveEffectRecordHandler::GetRecordDescriptionText(CXaraFileRecord* pCXaraFileRecord, StringBase* pStr)
05049 {
05050     if (pStr == NULL || pCXaraFileRecord == NULL)
05051         return;
05052 
05053     TCHAR s[256];
05054     BOOL ok = TRUE;
05055 
05056     // Call base class first
05057     CamelotRecordHandler::GetRecordDescriptionText(pCXaraFileRecord, pStr);
05058 
05059     switch (pCXaraFileRecord->GetTag())
05060     {
05061     case TAG_LIVE_EFFECT:
05062         {
05063             // read in the record ---------------------------------------------------------
05064             // read flags
05065             BYTE Flags;
05066             if (ok) ok = pCXaraFileRecord->ReadBYTE(&Flags);
05067 
05068             // Read resolution
05069             double dPixelsPerInch;
05070             if (ok) ok = pCXaraFileRecord->ReadDOUBLE(&dPixelsPerInch);
05071 
05072             // Read Effect ID
05073             String_256 strPostProID;
05074             if (ok) ok = pCXaraFileRecord->ReadUnicode(&strPostProID);
05075 
05076             // Read Display Name
05077             String_256 strDisplayName;
05078             if (ok) ok = pCXaraFileRecord->ReadUnicode(&strDisplayName);
05079 
05080             // Read edits list
05081 //          _bstr_t bstrXML;
05082 //          if (ok) ok = pCXaraFileRecord->ReadBSTR(&bstrXML, pCXaraFileRecord->GetSize());
05083             StringVar strXML;
05084             if (ok) ok = pCXaraFileRecord->ReadUTF16STR(&strXML, pCXaraFileRecord->GetSize());
05085 
05086             // --------------------------------------------------------------
05087             camSprintf(s,_T("Flags\t\t= %d\r\n"), (INT32)Flags);
05088             (*pStr) += s;
05089         }
05090         break;
05091 
05092     case TAG_LOCKED_EFFECT:
05093         {
05094             // read in the record ---------------------------------------------------------
05095             // read flags
05096             BYTE Flags;
05097             if (ok) ok = pCXaraFileRecord->ReadBYTE(&Flags);
05098 
05099             // Read resolution
05100             double dPixelsPerInch;
05101             if (ok) ok = pCXaraFileRecord->ReadDOUBLE(&dPixelsPerInch);
05102 
05103             // Read bitmap ref
05104             INT32 BitmapRef;
05105             if (ok) ok = pCXaraFileRecord->ReadINT32(&BitmapRef);
05106 
05107             // Read coords
05108             DocCoord tc[3];
05109             if (ok) ok = pCXaraFileRecord->ReadCoordTrans(&tc[0], 0, 0);
05110             if (ok) ok = pCXaraFileRecord->ReadCoordTrans(&tc[1], 0, 0);
05111             if (ok) ok = pCXaraFileRecord->ReadCoordTrans(&tc[2], 0, 0);
05112 
05113             // Read Effect ID
05114             String_256 strPostProID;
05115             if (ok) ok = pCXaraFileRecord->ReadUnicode(&strPostProID);
05116 
05117             // Read Display Name
05118             String_256 strDisplayName;
05119             if (ok) ok = pCXaraFileRecord->ReadUnicode(&strDisplayName);
05120 
05121             // Read edits list
05122 //          _bstr_t bstrXML;
05123 //          if (ok) ok = pCXaraFileRecord->ReadBSTR(&bstrXML, pCXaraFileRecord->GetSize());
05124             StringVar strXML;
05125             if (ok) ok = pCXaraFileRecord->ReadUTF16STR(&strXML, pCXaraFileRecord->GetSize());
05126 
05127             // --------------------------------------------------------------
05128             camSprintf(s,_T("Flags\t\t= %d\r\n"), (INT32)Flags);
05129             (*pStr) += s;
05130         }
05131         break;
05132 
05133 #ifdef FEATHER_EFFECT
05134     case TAG_FEATHER_EFFECT:
05135         {
05136             // read in the record ---------------------------------------------------------
05137             // read flags
05138             BYTE Flags;
05139             if (ok) ok = pCXaraFileRecord->ReadBYTE(&Flags);
05140 
05141             // Read resolution
05142             double dPixelsPerInch;
05143             if (ok) ok = pCXaraFileRecord->ReadDOUBLE(&dPixelsPerInch);
05144 
05145             // Read Effect ID
05146             String_256 strPostProID;
05147             if (ok) ok = pCXaraFileRecord->ReadUnicode(&strPostProID);
05148 
05149             // Read Display Name
05150             String_256 strDisplayName;
05151             if (ok) ok = pCXaraFileRecord->ReadUnicode(&strDisplayName);
05152 
05153             // Read feather details
05154             MILLIPOINT mpFeatherSize = 0;
05155             double dBias = 0;
05156             double dGain = 0;
05157             if (ok) ok = pCXaraFileRecord->ReadINT32(&mpFeatherSize);
05158             if (ok) ok = pCXaraFileRecord->ReadDOUBLE(&dBias);
05159             if (ok) ok = pCXaraFileRecord->ReadDOUBLE(&dGain);
05160 
05161             // --------------------------------------------------------------
05162             camSprintf(s,_T("Flags\t\t= %d\r\n"), (INT32)Flags);
05163             (*pStr) += s;
05164         }
05165         break;
05166 #endif
05167 
05168 /*      case TAG_GROUP:
05169             break;
05170 
05171         case TAG_COMPOUNDRENDER:
05172             INT32 reserved = 0;
05173             pRecord->ReadINT32(&reserved);
05174             camSprintf(s,_T("Reserved\t\t= %d\r\n"), reserved);
05175             (*pStr) += s;
05176 
05177             DocRect rbounds;
05178             pRecord->ReadCoord(&rbounds.lo);
05179             pRecord->ReadCoord(&rbounds.hi);
05180             camSprintf(s,_T("Bounds\t\t= %d, %d, %d, %d\r\n"), rbounds.lox, rbounds.loy, rbounds.hix, rbounds.hiy);
05181             (*pStr) += s;
05182             break;
05183 */
05184     }
05185 }
05186 #endif
05187 
05188 
05189 
05190 
05191 /********************************************************************************************
05192 
05193 >   ProcessBitmapState::ProcessBitmapState(LPBITMAPINFO lpInitialInfo,
05194                         LPBYTE lpInitialBits,
05195                         double InitialXOffset = 0,
05196                         double InitialYOffset = 0,
05197                         BOOL bInitialTempState = FALSE)
05198 
05199     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
05200     Created:    28/04/2005
05201     Inputs:     lpInitialInfo - pointer to bitmap info structure
05202                 lpInitialBits - pointer to bitmap data
05203                 InitialXOffset - Start position of bitmap in pixel space 
05204                 InitialYOffset -
05205                 bInitialTempState - TRUE if this state represents a temporary bitmap
05206                                     that can be deallocated when the state dies
05207     Outputs     -
05208     Returns:    -
05209     Purpose:    Building constructor
05210 
05211 ********************************************************************************************/
05212 
05213 #ifdef FEATHER_EFFECT
05214 ProcessBitmapState::ProcessBitmapState(LPBITMAPINFO lpInitialInfo,
05215                         LPBYTE lpInitialBits,
05216                         double InitialXOffset,
05217                         double InitialYOffset,
05218                         BOOL bInitialTempState)
05219 {
05220     m_lpInfo = lpInitialInfo;
05221     m_lpBits = lpInitialBits;
05222     m_XOffset = InitialXOffset;
05223     m_YOffset = InitialYOffset;
05224     m_XPelsPerMeter = 0;
05225     m_YPelsPerMeter = 0;
05226     m_bTemp = bInitialTempState;
05227     m_bOK = TRUE;
05228 }
05229 
05230 
05231 
05232 
05233 /********************************************************************************************
05234 
05235 >   ProcessBitmapState::ProcessBitmapState(const ProcessBitmapState& copystate)
05236 
05237     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
05238     Created:    28/04/2005
05239     Inputs:     
05240     Outputs     -
05241     Returns:    -
05242     Purpose:    Copy constructor
05243 
05244 ********************************************************************************************/
05245 
05246 ProcessBitmapState::ProcessBitmapState(const ProcessBitmapState& copystate)
05247 {
05248     m_lpInfo = copystate.m_lpInfo;
05249     m_lpBits = copystate.m_lpBits;
05250     m_XOffset = copystate.m_XOffset;
05251     m_YOffset = copystate.m_YOffset;
05252     m_XPelsPerMeter = copystate.m_XPelsPerMeter;
05253     m_YPelsPerMeter = copystate.m_YPelsPerMeter;
05254     m_bTemp = copystate.m_bTemp;
05255     m_bOK = copystate.m_bOK;
05256 }
05257 
05258 
05259 
05260 
05261 /********************************************************************************************
05262 
05263 >   void ProcessBitmapState::InitPipelineSettings(ProcessBitmapState* const prevstate)
05264 
05265     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
05266     Created:    28/04/2005
05267     Inputs:     
05268     Outputs     -
05269     Returns:    -
05270     Purpose:    Copy member vars that should propagate from one state to the next
05271                 in a pipeline
05272 
05273 ********************************************************************************************/
05274 
05275 void ProcessBitmapState::InitPipelineSettings(ProcessBitmapState* const prevstate)
05276 {
05277     m_XOffset = prevstate->m_XOffset;
05278     m_YOffset = prevstate->m_YOffset;
05279 
05280     if (m_lpInfo)
05281     {
05282         m_lpInfo->bmiHeader.biXPelsPerMeter = prevstate->GetXPelsPerMeter();
05283         m_lpInfo->bmiHeader.biYPelsPerMeter = prevstate->GetYPelsPerMeter();
05284     }
05285     else
05286     {
05287         m_XPelsPerMeter = prevstate->GetXPelsPerMeter();
05288         m_YPelsPerMeter = prevstate->GetYPelsPerMeter();
05289     }
05290 }
05291 
05292 
05293 
05294 
05295 /********************************************************************************************
05296 
05297 >   void ProcessBitmapState::DeInit()
05298 
05299     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
05300     Created:    29/04/2005
05301     Inputs:     
05302     Outputs     -
05303     Returns:    -
05304     Purpose:    Copy member vars that should propagate from one state to the next
05305                 in a pipeline
05306 
05307 ********************************************************************************************/
05308 
05309 void ProcessBitmapState::DeInit()
05310 {
05311     if (m_lpInfo && m_lpBits && m_bTemp)
05312     {
05313 		::FreeDIB(m_lpInfo, m_lpBits);
05314         m_lpInfo = NULL;
05315         m_lpBits = NULL;
05316     }
05317 }
05318 
05319 
05320 
05321 
05322 /********************************************************************************************
05323 
05324 >   ProcessBitmap& ProcessBitmapState::operator=(const ProcessBitmapState& rhsstate)
05325 
05326     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
05327     Created:    28/04/2005
05328     Inputs:     lpInitialInfo - pointer to bitmap info structure
05329                 lpInitialBits - pointer to bitmap data
05330                 InitialXOffset - Start position of bitmap in pixel space 
05331                 InitialYOffset -
05332                 bInitialTempState - TRUE if this state represents a temporary bitmap
05333                                     that can be deallocated when the state dies
05334     Outputs     -
05335     Returns:    -
05336     Purpose:    Assignment operator
05337 
05338 ********************************************************************************************/
05339 
05340 ProcessBitmapState& ProcessBitmapState::operator=(const ProcessBitmapState& rhsstate)
05341 {
05342     if (m_lpInfo && m_lpBits && m_bTemp && m_lpInfo!=rhsstate.m_lpInfo && m_lpBits!=rhsstate.m_lpBits)
05343     {
05344 		::FreeDIB(m_lpInfo, m_lpBits);
05345         m_lpInfo = NULL;
05346         m_lpBits = NULL;
05347     }
05348 
05349     m_lpInfo = rhsstate.m_lpInfo;
05350     m_lpBits = rhsstate.m_lpBits;
05351     m_XOffset = rhsstate.m_XOffset;
05352     m_YOffset = rhsstate.m_YOffset;
05353     m_bTemp = rhsstate.m_bTemp;
05354     m_bOK = rhsstate.m_bOK;
05355 
05356     if (m_lpInfo)
05357     {
05358         m_lpInfo->bmiHeader.biXPelsPerMeter = rhsstate.GetXPelsPerMeter();
05359         m_lpInfo->bmiHeader.biYPelsPerMeter = rhsstate.GetYPelsPerMeter();
05360         m_XPelsPerMeter = 0;
05361         m_YPelsPerMeter = 0;
05362     }
05363     else
05364     {
05365         m_XPelsPerMeter = rhsstate.GetXPelsPerMeter();
05366         m_YPelsPerMeter = rhsstate.GetYPelsPerMeter();
05367     }
05368 
05369     return *this;
05370 }
05371 
05372 
05373 
05374 
05375 /********************************************************************************************
05376 
05377 >   void        ProcessBitmapState::GetBitmap(LPBITMAPINFO& pOutputInfo, LPBYTE& pOutputBits, BOOL bTemp = FALSE)
05378 
05379     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
05380     Created:    28/04/2005
05381     Inputs:     bTemp - TRUE if the bitmap state should be marked temporary
05382                         FALSE if the bitmap state should be marked permanent (default)
05383     Outputs     pOutputInfo - Pointer to bitmap info structure
05384                 pOutputBits - Pointer to bitmap data
05385     Returns:    -
05386     Purpose:    Extract the bitmap from the current pipeline state
05387     Errors:     -
05388     SeeAlso:    -
05389 
05390 ********************************************************************************************/
05391 
05392 void ProcessBitmapState::GetBitmap(LPBITMAPINFO& pOutputInfo, LPBYTE& pOutputBits, BOOL bTemp)
05393 {
05394     if (m_lpInfo && m_XPelsPerMeter!=0 && m_YPelsPerMeter!=0)
05395     {
05396         m_lpInfo->bmiHeader.biXPelsPerMeter = m_XPelsPerMeter;
05397         m_lpInfo->bmiHeader.biYPelsPerMeter = m_YPelsPerMeter;
05398         m_XPelsPerMeter = 0;
05399         m_YPelsPerMeter = 0;
05400     }
05401 
05402     pOutputInfo = m_lpInfo;
05403     pOutputBits = m_lpBits;
05404     m_bTemp = bTemp;
05405 }
05406 
05407 
05408 
05409 
05410 /********************************************************************************************
05411 
05412 >   BOOL ProcessBitmapState::AllocDIB(UINT32 Width, UINT32 Height, UINT32 Depth)
05413 
05414     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
05415     Created:    28/04/2005
05416     Inputs:     bTemp - TRUE if the bitmap state should be marked temporary
05417                         FALSE if the bitmap state should be marked permanent (default)
05418     Outputs     pOutputInfo - Pointer to bitmap info structure
05419                 pOutputBits - Pointer to bitmap data
05420     Returns:    -
05421     Purpose:    Extract the bitmap from the current pipeline state
05422     Errors:     -
05423     SeeAlso:    -
05424 
05425 ********************************************************************************************/
05426 
05427 BOOL ProcessBitmapState::AllocDIB(UINT32 Width, UINT32 Height, UINT32 Depth)
05428 {
05429     m_bOK = FALSE;
05430     m_lpInfo = ::AllocDIB(Width, Height, Depth, &m_lpBits);
05431     if (m_lpInfo)
05432     {
05433         m_bOK = TRUE;
05434         if (m_XPelsPerMeter!=0 && m_YPelsPerMeter!=0)
05435         {
05436             m_lpInfo->bmiHeader.biXPelsPerMeter = m_XPelsPerMeter;
05437             m_lpInfo->bmiHeader.biYPelsPerMeter = m_YPelsPerMeter;
05438             m_XPelsPerMeter = 0;
05439             m_YPelsPerMeter = 0;
05440         }
05441     }
05442 
05443     return m_bOK;
05444 }
05445 
05446 
05447 
05448 
05449 /********************************************************************************************
05450 
05451 >   ProcessBitmapState ProcessBitmapState::Create8BPPMask()
05452 
05453     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
05454     Created:    28/04/2005
05455     Inputs:     -
05456     Outputs     -
05457     Returns:    New ProcessBitmapState (may be invalid)
05458     Purpose:    Extract the 8bpp T channel from this bitmap state
05459     Errors:     -
05460     SeeAlso:    -
05461 
05462 ********************************************************************************************/
05463 
05464 ProcessBitmapState ProcessBitmapState::Create8BPPMask()
05465 {
05466     // Create the next state
05467     ProcessBitmapState mask;
05468     mask.InitPipelineSettings(this);
05469 
05470     // Don't process if the current state is invalid
05471     if (!m_bOK)
05472         return mask;        // IsOK = FALSE
05473 
05474 //  ERROR3IF(GetDepth()!=32, "Create8BPPMask only copes with 32BPP inputs at the moment");
05475 
05476     // Get the alpha channel bitmap out of the capture bitmap and invert it
05477     // because we want ContourBitmap to generate an INNER contour...
05478     mask.AllocDIB(GetWidth(), GetHeight(), 8);
05479     if (!mask.IsOK())
05480         return mask;        // IsOK = FALSE
05481 
05482     if (GetDepth()==32)
05483     {
05484         UINT32 uWidth  = mask.GetWidth();
05485         UINT32 uHeight = mask.GetHeight();
05486         UINT32 uByteWidth8 = DIBUtil::ScanlineSize(uWidth, 8);
05487         UINT32 uByteWidth32 = DIBUtil::ScanlineSize(GetWidth(), GetDepth())/sizeof(UINT32); // width in words
05488 
05489         LPBYTE pDst = mask.m_lpBits;
05490         UINT32* pSrc = (UINT32*)m_lpBits;
05491         UINT32 i;
05492         UINT32 j;
05493         for ( j=0 ; j<uHeight ; j++ )
05494         {
05495             for ( i=0 ; i<uWidth ; i++ )
05496             {
05497                 // Combine alpha channel info with colour info to get silhouette
05498                 // Unrendered areas are BGRT = 0x000000FF (T=0xFF for fully transparent)
05499                 // Wherever transp is FE or less
05500     //          pDst[i] = (pSrc[i]==0xFF000000) ? 0 : 0xFF;     // Invert
05501     //          pDst[i] = (pSrc[i]==0xFF000000) ? 0xFF : 0;
05502                 pDst[i] = (pSrc[i]&0xFF000000) >> 24;
05503             }
05504             pDst += uByteWidth8;
05505             pSrc += uByteWidth32;
05506         }
05507     }
05508     else
05509     {
05510         // TODO!
05511         // Should try to get mask data from other formats here!
05512         // At the moment just create a solid rectangle...
05513         UINT32 uWidth  = mask.GetWidth();
05514         UINT32 uHeight = mask.GetHeight();
05515         UINT32 uByteWidth8 = DIBUtil::ScanlineSize(uWidth, 8);
05516 
05517         LPBYTE pDst = mask.m_lpBits;
05518         UINT32 i;
05519         UINT32 j;
05520         for ( j=0 ; j<uHeight ; j++ )
05521         {
05522             for ( i=0 ; i<uWidth ; i++ )
05523             {
05524                 pDst[i] = 0;
05525             }
05526             pDst += uByteWidth8;
05527         }
05528     }
05529 
05530     return mask;
05531 }
05532 
05533 
05534 
05535 
05536 /********************************************************************************************
05537 
05538 >   ProcessBitmapState ProcessBitmapState::AddMaskTo(LPBITMAPINFO lpDeepInfo, LPBYTE lpDeepBits)
05539 
05540     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
05541     Created:    03/08/2005
05542     Inputs:     -
05543     Outputs     -
05544     Returns:    New ProcessBitmapState (may be invalid)
05545     Purpose:    Put this bitmap state into another DIB as the transparency channel
05546     Errors:     -
05547     SeeAlso:    -
05548 
05549 ********************************************************************************************/
05550 
05551 ProcessBitmapState ProcessBitmapState::AddMaskTo(LPBITMAPINFO lpDeepInfo, LPBYTE lpDeepBits)
05552 {
05553     // Create the next state
05554     ProcessBitmapState deep;
05555     deep.InitPipelineSettings(this);
05556 
05557     // Don't process if the current state is invalid
05558     if (!m_bOK)
05559         return deep;        // IsOK = FALSE
05560 
05561     ERROR3IF(GetDepth()!=8, "Error");
05562     ERROR3IF(lpDeepInfo->bmiHeader.biBitCount != 32, "Error");
05563     ERROR3IF(lpDeepInfo->bmiHeader.biWidth != (INT32)GetWidth(), "Error");
05564     ERROR3IF(lpDeepInfo->bmiHeader.biHeight != (INT32)GetHeight(), "Error");
05565     if (GetDepth()!=8) return deep;
05566     if (lpDeepInfo->bmiHeader.biBitCount != 32) return deep;
05567     if (lpDeepInfo->bmiHeader.biWidth != (INT32)GetWidth()) return deep;
05568     if (lpDeepInfo->bmiHeader.biHeight != (INT32)GetHeight()) return deep;
05569 
05570     deep.m_lpInfo = lpDeepInfo;
05571     deep.m_lpBits = lpDeepBits;
05572     if (!deep.IsOK())
05573         return deep;        // IsOK = FALSE
05574 
05575     UINT32 uWidth  = GetWidth();
05576     UINT32 uHeight = GetHeight();
05577     UINT32 uByteWidth8 = DIBUtil::ScanlineSize(uWidth, 8);
05578     UINT32 uByteWidth32 = DIBUtil::ScanlineSize(deep.GetWidth(), deep.GetDepth())/sizeof(UINT32);   // width in words
05579 
05580     UINT32* pDst = (UINT32*)lpDeepBits;
05581     LPBYTE pSrc = m_lpBits;
05582     UINT32 i;
05583     UINT32 j;
05584     for ( j=0 ; j<uHeight ; j++ )
05585     {
05586         for ( i=0 ; i<uWidth ; i++ )
05587         {
05588             pDst[i] = (pDst[i]&0xFF000000) | pSrc[i] << 24;
05589         }
05590         pDst += uByteWidth32;
05591         pSrc += uByteWidth8;
05592     }
05593 
05594     return deep;
05595 }
05596 
05597 
05598 
05599 
05600 /********************************************************************************************
05601 
05602 >   ProcessBitmapState ProcessBitmapState::Contour8BPP(double dContourWidth)
05603 
05604     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
05605     Created:    28/04/2005
05606     Inputs:     -
05607     Outputs     -
05608     Returns:    -
05609     Purpose:    Contour this state return resulting state
05610     Errors:     -
05611     SeeAlso:    -
05612 
05613 ********************************************************************************************/
05614 
05615 ProcessBitmapState ProcessBitmapState::Contour8BPP(double dContourWidth)
05616 {
05617     // Create the next state
05618     double OffsetX = 0;
05619     double OffsetY = 0;
05620     ProcessBitmapState contour;
05621     contour.InitPipelineSettings(this);
05622 
05623     // Don't process if the current state is invalid
05624     if (!m_bOK)
05625         return contour;     // IsOK = FALSE
05626 
05627     ERROR3IF(GetDepth()!=8, "Contour8BPP only copes with 8BPP inputs at the moment");
05628     ERROR3IF(dContourWidth>=0, "Contour8BPP only copes with inner contours at the moment");
05629 
05630     // Now generate an Inner contour of half the feather width
05631     contour.m_bOK = CBitmapShadow::ContourBitmap(m_lpInfo,
05632                                            m_lpBits,
05633                                            fabs(dContourWidth),
05634                                            (dContourWidth<0),
05635                                            0xFE,            // Threshold
05636                                            &contour.m_lpInfo,
05637                                            &contour.m_lpBits,
05638                                            &OffsetX,
05639                                            &OffsetY
05640                                            );
05641     ERROR3IF(!contour.IsOK(), "ContourBitmap failed in RenderShadowedNodeOffscreen");
05642     if (!contour.IsOK())
05643         return contour;
05644 
05645     // If the contour produced a NULL bitmap
05646     // Just return a copy of the current state...
05647     if (contour.m_lpInfo==NULL)
05648         return *this;
05649 
05650     contour.m_XOffset += OffsetX;   // Assume ContourBitmap has set sense correctly for inside/outside contouring
05651     contour.m_YOffset += OffsetY;
05652 
05653     return contour;
05654 }
05655 
05656 
05657 
05658 
05659 /********************************************************************************************
05660 
05661 >   ProcessBitmapState ProcessBitmapState::Blur8BPP(double dBlurWidth)
05662 
05663     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
05664     Created:    28/04/2005
05665     Inputs:     -
05666     Outputs     -
05667     Returns:    -
05668     Purpose:    Contour the source bitmap
05669     Errors:     -
05670     SeeAlso:    -
05671 
05672 ********************************************************************************************/
05673 
05674 ProcessBitmapState ProcessBitmapState::Blur8BPP(double dBlurWidth)
05675 {
05676     // Create the next state
05677     ProcessBitmapState blur;
05678     blur.InitPipelineSettings(this);
05679 
05680     // Don't process if the current state is invalid
05681     if (!m_bOK)
05682         return blur;        // IsOK = FALSE
05683 
05684     ERROR3IF(GetDepth()!=8, "Blur8BPP only copes with 8BPP inputs at the moment");
05685 
05686     // Now blur
05687     UINT32 DWordWidth = DIBUtil::ScanlineSize(GetWidth(), GetDepth());
05688     // Alloc a destination DIB for the convolution.
05689     UINT32 uBlurDiameter = UINT32(dBlurWidth+0.5)-1 ;
05690     blur.AllocDIB(GetWidth()-uBlurDiameter, GetHeight()-uBlurDiameter, 8);
05691     if (!blur.IsOK())
05692         return blur;        // IsOK = FALSE
05693 
05694     CBitmapShadow::Blur8BppBitmap(&m_lpInfo->bmiHeader, m_lpBits, &blur.m_lpInfo->bmiHeader, blur.m_lpBits, DWordWidth, dBlurWidth/2);
05695 
05696     // Blur result is offset by blur radius
05697     // So to position blur bitmap correctly we must move it down and left by blur radius
05698     blur.m_XOffset += dBlurWidth/2;
05699     blur.m_YOffset += dBlurWidth/2;
05700 
05701     return blur;
05702 }
05703 
05704 
05705 
05706 
05707 /********************************************************************************************
05708 
05709 >   ProcessBitmapState ProcessBitmapState::Expand8BPP(INT32 nPixels, BYTE fill)
05710 
05711     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
05712     Created:    28/04/2005
05713     Inputs:     -
05714     Outputs     -
05715     Returns:    -
05716     Purpose:    Expand the source bitmap, filling pixels with specified value
05717     Errors:     -
05718     SeeAlso:    -
05719 
05720 ********************************************************************************************/
05721 
05722 ProcessBitmapState ProcessBitmapState::Expand8BPP(INT32 nPixels, BYTE fill)
05723 {
05724     ProcessBitmapState expand;
05725     expand.InitPipelineSettings(this);
05726 
05727     // Don't process if the current state is invalid
05728     if (!m_bOK)
05729         return expand;      // IsOK = FALSE
05730 
05731     ERROR3IF(GetDepth()!=8, "Expand8BPP only copes with 8BPP inputs at the moment");
05732 
05733     expand.AllocDIB(GetWidth()+nPixels*2, GetHeight()+nPixels*2, 8);
05734     if (!expand.IsOK())
05735         return expand;      // IsOK = FALSE
05736 
05737     UINT32 uSrcWidth8  = GetWidth();
05738     UINT32 uSrcHeight8 = GetHeight();
05739     UINT32 uSrcByteWidth8 = DIBUtil::ScanlineSize(uSrcWidth8, 8);
05740 
05741     UINT32 uExWidth8  = expand.GetWidth();
05742     UINT32 uExHeight8 = expand.GetHeight();
05743     UINT32 uExByteWidth8 = DIBUtil::ScanlineSize(uExWidth8, 8);
05744 
05745     LPBYTE pSrc = m_lpBits;
05746     LPBYTE pDst = expand.m_lpBits + uExByteWidth8*nPixels + nPixels;
05747     UINT32 i,j;
05748 
05749     memset(expand.m_lpBits, fill, uExByteWidth8*uExHeight8);
05750 
05751     for ( j=0 ; j<uSrcHeight8 ; j++ )
05752     {
05753         for ( i=0 ; i<uSrcWidth8 ; i++ )
05754             pDst[i] = pSrc[i];
05755 
05756         pSrc += uSrcByteWidth8;
05757         pDst +=  uExByteWidth8;
05758     }
05759 
05760     // Resulting bitmap is bigger than original by nPixels all round so corner moves down and left
05761     expand.m_XOffset -= (double)nPixels;
05762     expand.m_YOffset -= (double)nPixels;
05763 
05764     return expand;
05765 }
05766 
05767 
05768 
05769 
05770 /********************************************************************************************
05771 
05772 >   ProcessBitmapState ProcessBitmapState::AttachToDoc()
05773 
05774     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
05775     Created:    28/04/2005
05776     Inputs:     -
05777     Outputs     -
05778     Returns:    -
05779     Purpose:    Expand the source bitmap, filling pixels with specified value
05780     Errors:     -
05781     SeeAlso:    -
05782 
05783 ********************************************************************************************/
05784 
05785 #ifdef DEBUG
05786 void ProcessBitmapState::AttachToDoc(String_256 strName)
05787 {
05788     if (m_lpInfo != NULL && m_lpBits != NULL)
05789     {
05790         CWxBitmap*      wbmp = new CWxBitmap(m_lpInfo, m_lpBits);
05791         KernelBitmap*   kbmp = new KernelBitmap(wbmp, TRUE);
05792         if (kbmp->GetBPP()==8)
05793         {
05794             LPRGBQUAD pPalette = kbmp->GetPaletteForBitmap();
05795             for ( INT32 i=0 ; i<0x100 ; i++ )
05796                 (UINT32&)pPalette[i] = i*0x010101 ;
05797                 
05798             kbmp->SetAsGreyscale();
05799         }
05800         kbmp->AttachDebugCopyToCurrentDocument(strName);
05801         wbmp->BMBytes = ((CWxBitmap*)OILBitmap::Default)->BMBytes;
05802         delete kbmp;
05803     }
05804 }
05805 #endif
05806 
05807 #endif

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