nodeshad.cpp

Go to the documentation of this file.
00001 // $Id: nodeshad.cpp 1361 2006-06-25 16:43:38Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 
00099 /*
00100 */
00101 
00102 #include "camtypes.h"
00103 
00104 #ifdef BUILDSHADOWS
00105 
00106 #include <math.h>
00107 //#include "pathedit.h"
00108 
00109 #include "nodeshad.h"
00110 #include "nodecont.h"
00111 #include "noderect.h"
00112 
00113 // Code headers
00114 //#include "attrmgr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00115 //#include "fillval.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00116 //#include "fillattr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00117 #include "gclips.h"
00118 //#include "paths.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00119 #include "pathtrap.h"
00120 #include "grndrgn.h"
00121 #include "nodebmp.h"
00122 //#include "becomea.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00123 #include "bmpcomp.h"
00124 
00125 // New Bitmap Shadowing code
00126 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00127 #include "bshadow.h"
00128 
00129 // necessary for special case with bevelling
00130 #include "opbevel.h"
00131 #include "nodebev.h"
00132 
00133 // Save/load
00134 //#include "cxfdefs.h"  // TAG_SHADOW_SIZE - in camtypes.h [AUTOMATICALLY REMOVED]
00135 #include "cxftags.h"    // TAG_SHADOW
00136 //#include "cxfrec.h"       // CXaraFileRecord - in camtypes.h [AUTOMATICALLY REMOVED]
00137 //#include "camfiltr.h" // BaseCamelotFilter - in camtypes.h [AUTOMATICALLY REMOVED]
00138 #include "swfrndr.h"    // FlashRenderRegion
00139 #include "cmxrendr.h"   // CMXRenderRegion
00140 #include "ai_epsrr.h"   // AIEPSRenderRegion
00141 //#include "dibutil.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00142 #include "lineattr.h"
00143 
00144 // Resource headers
00145 //#include "resource.h"
00146 //#include "shadres.h"
00147 
00148 #include "moldtool.h"
00149 //#include "mario.h"
00150 #include "attrappl.h"
00151 //#include "view.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00152 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00153 #include "blobs.h"
00154 #include "attrmap.h"
00155 #include "extender.h"
00156 #include "ngcore.h"     // NameGallery, for stretching functionality
00157 
00158 #include "gdraw.h"
00159 
00160 #include "contmenu.h"
00161 #include "blndhelp.h"
00162 #include "osrndrgn.h"
00163 //#include "progress.h"
00164 //#include "spread.h"       // for class Spread - in camtypes.h [AUTOMATICALLY REMOVED]
00165 #include "qualattr.h"   // for class QualityAttribute
00166 //#include "rendbits.h" // for class OSRenderBitmap
00167 #include "nodebldr.h"   // for class NodeCompoundBlendBecomeA
00168 #include "offscrn.h"    // for GRenderRegionWrapper
00169 #include "oilbitmap.h"  // for WinBitmap
00170 #include "nodecntr.h"   // for ContourBecomeA
00171 #include "nodecont.h"   // for default shadow settings
00172 #include "fthrattr.h"   // for feather bodge.
00173 //#include "quality.h"  // for quality setting info - used for caching. - in camtypes.h [AUTOMATICALLY REMOVED]
00174 #include "brshattr.h"   // for AttrBrushType, which we don't want applied to us.
00175 #include "opfeathr.h"   // for OpChangeFeatherSize, which we don't want operating on us.
00176 #include "nodeliveeffect.h"
00177 #include "ophist.h"
00178 #include "objchge.h"
00179 
00180 //#include "prntview.h"
00181 
00182 DECLARE_SOURCE( "$Revision: 1361 $" );
00183 
00184 CC_IMPLEMENT_DYNCREATE(NodeShadow, NodeRenderableInk)
00185 
00186 // Declare smart memory handling in Debug builds
00187 #define new CAM_DEBUG_NEW
00188 
00189 // uncomment these to see the silhouette and final shadow bitmaps in the bitmap gallery.
00190 //#define ATTACH_SILHOUETTE_BMP
00191 //#define ATTACH_SHADOW_BMP
00192 
00193 #define NEW_GLOW_SILHOUETTE
00194 
00195 const UINT32 GlowWidthStrokeFlatness = 200;
00196 
00197 const double MaxShadowBitmapSize = 1024;
00198 const double MinShadowBitmapSize = 32;
00199 
00200 
00201 
00202 /***********************************************************************************************
00203 
00204 >   NodeShadow::NodeShadow(Node*    ContextNode,
00205                         AttachNodeDirection Direction,
00206                         const DocRect&      BoundingRect,
00207                         BOOL                Locked = FALSE,
00208                         BOOL                Mangled = FALSE,
00209                         BOOL                Marked = FALSE,
00210                         BOOL                Selected = FALSE,
00211                         BOOL                Renderable = FALSE
00212                         )
00213 
00214     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00215     Created:    16/11/94
00216     Inputs:     ContextNode: Pointer to a node which this node is to be attached to.
00217                 MonoOn Direction: MonoOff
00218                 Specifies the direction in which the node is to be attached to the
00219                 ContextNode. The values this variable can take are as follows:
00220                                   
00221                 PREV      : Attach node as a previous sibling of the context node
00222                 NEXT      : Attach node as a next sibling of the context node
00223                 FIRSTCHILD: Attach node as the first child of the context node
00224                 LASTCHILD : Attach node as a last child of the context node
00225 
00226                 BoundingRect: Bounding rectangle
00227 
00228                 The remaining inputs specify the status of the node:
00229             
00230                 Locked:     Is node locked ?
00231                 Mangled:    Is node mangled ?
00232                 Marked:     Is node marked ?
00233                 Selected:   Is node selected ?
00234 
00235     Purpose:    This constructor initialises the nodes flags and links it to ContextNode in the
00236                 direction specified by Direction. All neccesary tree links are updated.
00237     Note:       SetUpShape() must be called before the NodeRegularShape is in a state in which
00238                 it can be used.
00239     SeeAlso:    NodeRegularShape::SetUpShape
00240     Errors:     An ENSURE will occur if ContextNode is NULL
00241 
00242 ***********************************************************************************************/
00243 NodeShadow::NodeShadow(Node* ContextNode,  
00244                     AttachNodeDirection Direction,  
00245                     BOOL Locked, 
00246                     BOOL Mangled,  
00247                     BOOL Marked, 
00248                     BOOL Selected    
00249               ) : NodeRenderableInk(ContextNode, Direction, Locked, Mangled, Marked, Selected )
00250 {                         
00251     InitialiseMemberVars();
00252 }                        
00253 
00254 
00255  
00256 /*********************************************************************************************
00257 
00258 >   NodeShadow::NodeShadow() 
00259 
00260     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00261     Created:    16/11/94
00262     Purpose:    This constructor creates a NodeRegularShape linked to no other.
00263     Note:       SetUpShape() should be called to change the NodeRegularShape before use!
00264     SeeAlso:    NodeRegularShape::SetUpShape                                                        
00265 
00266 **********************************************************************************************/
00267 NodeShadow::NodeShadow() : NodeRenderableInk()
00268 {
00269     InitialiseMemberVars();
00270 }
00271 
00272 
00273 
00274 /*********************************************************************************************
00275 
00276 >   void NodeShadow::InitialiseMemberVars()
00277 
00278     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00279     Created:    18/6/96
00280     Inputs:     -
00281     Outputs:    Initalised member variables
00282     Returns:    -
00283     Purpose:    One consistant place to initialise all the member variables of a NodeRegularShape
00284 
00285 **********************************************************************************************/
00286 void NodeShadow::InitialiseMemberVars()
00287 {
00288     m_LastQualitySetting = (enum Quality::Fill)Quality::Solid;
00289     m_LastRequestedPixWidth = -1;
00290     m_LastActualPixWidth = -1;
00291     m_ShadowBitmap = NULL;
00292     m_RenderBitmaps = TRUE;
00293     m_bAmCopying = FALSE;
00294     m_bAmLoading = TRUE;
00295     m_Path.Initialise();
00296     m_NonTranslatedPath.Initialise();
00297     m_BitmapXOffset = 0;
00298 
00299     // m_CurrentBlur = 4 * 750;
00300     m_PreviousBlur = 0;
00301     m_ShadowWidth = 0;
00302     m_ShadowHeight = 0;
00303     // m_FloorShadowAngle = 20.0 * PI / 180.0;  
00304     // m_FloorShadowHeight = 1.0;
00305     m_dDarkness = 0.0;
00306     m_bHaveTransformed = TRUE;
00307 
00308     m_pBMPTransFill = NULL;
00309     
00310     // Get a pointer to the My new Render Selection functions
00311     m_pShadower = NULL;
00312 }
00313 
00314 
00315 
00316 /*********************************************************************************************
00317 
00318 >   NodeShadow::~NodeShadow() 
00319 
00320     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00321     Created:    31/1/95
00322     Purpose:    Distructor to delete the cached render path
00323     SeeAlso:    -
00324 
00325 **********************************************************************************************/
00326 NodeShadow::~NodeShadow()
00327 {
00328     DeleteCache();
00329 }
00330 
00331 
00332 
00333 /*******************************************************************************************
00334 >   void NodeShadow::DeleteCurrentShadowStuff()
00335 
00336     Author:     Mark_Howitt (Xara Group Ltd) <camelotdev@xara.com>
00337     Created:    16/9/98
00338     Purpose:    Deletes all Bitmaps and BitmapFillAttribute pointers
00339 ********************************************************************************************/
00340 void NodeShadow::DeleteCurrentShadowStuff()
00341 {
00342     
00343 }
00344 
00345 
00346 
00347 /***********************************************************************************************
00348 
00349 >   virtual Node* NodeShadow::SimpleCopy()
00350 
00351     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00352     Created:    16/11/94
00353     Returns:    Pointer to a Node or NULL if there was not enough memory for the new node
00354     Purpose:    Makes a copy of all the data in the node
00355 
00356 ***********************************************************************************************/
00357 Node* NodeShadow::SimpleCopy()
00358 {
00359     NodeShadow* pNodeCopy = new NodeShadow();
00360 
00361     if (pNodeCopy != NULL)
00362         CopyNodeContents(pNodeCopy);
00363 
00364     return pNodeCopy;
00365 }            
00366 
00367 
00368 
00369 /***********************************************************************************************
00370 
00371 >   void NodeShadow::CopyNodeContents(NodeShadow* NodeCopy)
00372 
00373     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00374     Created:    16/11/94
00375     Inputs:     NodeCopy - The node to copy the data into
00376     Purpose:    Copies the data in the node by first calling the base class to get it to
00377                 copy its stuff, and then copying its own stuff
00378                 Note : Copies FROM this TO NodeCopy
00379     SeeAlso:    NodeRenderableInk::CopyNodeContents
00380     Errors:     ERROR3 if passed a NULL pointer.
00381 
00382 ***********************************************************************************************/
00383 void NodeShadow::CopyNodeContents(NodeShadow* NodeCopy)
00384 {
00385     ERROR3IF(NodeCopy == NULL,"NodeShadow::CopyNodeContents was asked to copy into a NULL pointer");
00386 
00387     // copy the bitmaps and them fill too
00388     // if they're defined !
00389     if (NodeCopy->m_ShadowBitmap)
00390         delete NodeCopy->m_ShadowBitmap;
00391     NodeCopy->m_ShadowBitmap = NULL;
00392     if (m_ShadowBitmap)
00393     {
00394         NodeCopy->m_ShadowBitmap = new KernelBitmap(m_ShadowBitmap->GetWidth(),
00395                 m_ShadowBitmap->GetHeight(), 8, 0, TRUE);
00396 
00397         // ok, now copy the bitmap from me into the new bitmap on the copy node
00398         memcpy(NodeCopy->m_ShadowBitmap->GetBitmapBits(), m_ShadowBitmap->GetBitmapBits(), 
00399             DIBUtil::ScanlineSize(m_ShadowBitmap->GetWidth(), 8) * m_ShadowBitmap->GetHeight());
00400 
00401         // now, copy the palette
00402         LPRGBQUAD pTranspPalette = NodeCopy->m_ShadowBitmap->GetPaletteForBitmap();
00403 
00404         double dI = 0;
00405         
00406         for (INT32 i = 0 ; i < 256; i++)
00407         {
00408             dI = ((double)i / 255.0);
00409 
00410             dI = m_BiasGain.MapZeroToOne((AFp)dI);
00411 
00412             dI *= 255.0;
00413 
00414             if (dI > 255.0)
00415                 dI = 255.0;
00416 
00417             pTranspPalette->rgbBlue = (BYTE)dI;
00418             pTranspPalette->rgbRed = (BYTE)dI;
00419             pTranspPalette->rgbGreen = (BYTE)dI;
00420             pTranspPalette->rgbReserved = 0x00;
00421 
00422             pTranspPalette ++;
00423         }
00424 
00425         if (NodeCopy->m_pBMPTransFill)
00426             delete NodeCopy->m_pBMPTransFill;
00427         NodeCopy->m_pBMPTransFill = new BitmapTranspFillAttribute;
00428         if (NodeCopy->m_pBMPTransFill)
00429         {
00430             // Now work out the control points for the given Shadow
00431             DocCoord StartP(m_SelectedRect.lo.x, m_SelectedRect.lo.y);
00432             DocCoord EndPA(m_SelectedRect.hi.x, m_SelectedRect.lo.y);
00433             DocCoord EndPB(m_SelectedRect.lo.x, m_SelectedRect.hi.y);
00434 
00435             // Set the individual control points with the worked out values
00436             NodeCopy->m_pBMPTransFill->SetStartPoint(&StartP);
00437             NodeCopy->m_pBMPTransFill->SetEndPoint(&EndPA);
00438             NodeCopy->m_pBMPTransFill->SetEndPoint2(&EndPB);    
00439 
00440             NodeCopy->m_pBMPTransFill->SetTesselation(RT_Simple);
00441             NodeCopy->m_pBMPTransFill->SetTranspType(TT_Mix);
00442 
00443             NodeCopy->m_pBMPTransFill->BitmapRef.SetBitmap(NodeCopy->m_ShadowBitmap);       
00444 
00445             UINT32 startTrans = GetTransp();
00446                     
00447             NodeCopy->m_pBMPTransFill->SetStartTransp(&startTrans);
00448 
00449             UINT32 endTrans = 255;
00450 
00451             NodeCopy->m_pBMPTransFill->SetEndTransp(&endTrans); 
00452         }
00453     }
00454 
00455     // DocRect dr = NodeCopy->GetBoundingRect();
00456 
00457     // Make a copy of our internal state.
00458     NodeCopy->SetDarkness(GetDarkness());
00459     NodeCopy->SetBiasGain(GetBiasGain());
00460 
00461     // Remember to copy or blank cached path data without leaking memory...
00462     NodeCopy->m_Path.Initialise(m_Path.GetNumCoords());
00463     NodeCopy->m_Path.CopyPathDataFrom(&m_Path);
00464 
00465     NodeCopy->m_NonTranslatedPath.Initialise(m_NonTranslatedPath.GetNumCoords());
00466     NodeCopy->m_NonTranslatedPath.CopyPathDataFrom(&m_NonTranslatedPath);
00467 
00468     // Copy other member vars...
00469     NodeCopy->m_ShadowWidth = m_ShadowWidth;
00470     NodeCopy->m_ShadowHeight = m_ShadowHeight;
00471 
00472     NodeCopy->m_bHaveTransformed = m_bHaveTransformed;
00473     NodeCopy->m_RenderBitmaps = m_RenderBitmaps;
00474     NodeCopy->m_bAmCopying = m_bAmCopying;
00475     NodeCopy->m_bAmLoading = m_bAmLoading;
00476 //  NodeCopy->m_Darkness;
00477 
00478     NodeCopy->m_SelectedRect = m_SelectedRect;
00479     NodeCopy->m_PreviousBlur = m_PreviousBlur;
00480     
00481     // DMc the bitmap shadower (not the COM shadower flat)
00482 //  CBitmapShadow * m_pShadower;
00483 
00484     NodeCopy->m_BitmapXOffset = m_BitmapXOffset;
00485     NodeCopy->m_BiasGain = m_BiasGain;
00486     NodeCopy->m_LastRequestedPixWidth = m_LastRequestedPixWidth;
00487     NodeCopy->m_LastQualitySetting = m_LastQualitySetting;
00488     NodeCopy->m_LastActualPixWidth = m_LastActualPixWidth;
00489 
00490     // Copy from the base class
00491     NodeRenderableInk::CopyNodeContents(NodeCopy);
00492 }
00493 
00494 
00495 
00496 /***********************************************************************************************
00497 >   void NodeShadow::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
00498 
00499     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00500     Created:    18/12/2003
00501     Outputs:    -
00502     Purpose:    Polymorphically copies the contents of this node to another
00503     Errors:     An assertion failure will occur if NodeCopy is NULL
00504     Scope:      protected
00505                                      
00506 ***********************************************************************************************/
00507 
00508 void NodeShadow::PolyCopyNodeContents(NodeRenderable* pNodeCopy)
00509 {
00510     ENSURE(pNodeCopy, "Trying to copy a node's contents into a NULL node");
00511     ENSURE(IS_A(pNodeCopy, NodeShadow), "PolyCopyNodeContents given wrong dest node type");
00512 
00513     if (IS_A(pNodeCopy, NodeShadow))
00514         CopyNodeContents((NodeShadow*)pNodeCopy);
00515 }
00516 
00517 
00518 
00519 /***********************************************************************************************
00520 
00521 >   void NodeShadow::ShowDebugTreeDetails() const
00522 
00523     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00524     Created:    16/11/94
00525     Purpose:    Displays debugging info of the tree
00526     SeeAlso:    NodeRenderableInk::ShowDebugTreeDetails
00527 
00528 ***********************************************************************************************/
00529 void NodeShadow::ShowDebugTreeDetails() const
00530 {                     
00531     // Display a bit of debugging info
00532     // For now, we will just call the base class version
00533     TRACEALL( _T("NodeShadow  ") );
00534 #ifdef _DEBUG
00535     NodeRenderableInk::ShowDebugTreeDetails();  
00536 #endif
00537 }
00538 
00539 
00540 
00541 /********************************************************************************************
00542 
00543 >   void NodeShadow::GetDebugDetails( StringBase* Str )
00544 
00545     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00546     Created:    16/11/94
00547     Outputs:    Str: String giving debug info about the node
00548     Purpose:    For obtaining debug information about the Node (for
00549 
00550 ********************************************************************************************/
00551 void NodeShadow::GetDebugDetails( StringBase* Str )
00552 {
00553     // Call base class
00554 #ifdef _DEBUG
00555     if (Str)
00556     {
00557         NodeRenderableInk::GetDebugDetails( Str );
00558         
00559         String_256 TempStr;
00560         String_256 TempStr2;
00561         
00562         (*Str) += TEXT( "\r\nNode Shadow Data Dump\r\n" );
00563         
00564         DocRect BlobRect = GetBlobBoundingRect();
00565         TempStr._MakeMsg( TEXT("Blob Bounding Rect :\r\n\t#1%ld,\t#2%ld\r\n\t#3%ld,\t#4%ld\r\n"),
00566             BlobRect.lo.x, BlobRect.lo.y, BlobRect.hi.x, BlobRect.hi.y );
00567         (*Str) += TempStr;
00568     }
00569 #endif
00570 }
00571 
00572 
00573 
00574 /***********************************************************************************************
00575 
00576 >   BOOL NodeShadow::SetUpShape()
00577 
00578     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00579     Created:    16/11/94
00580     Inputs:     - 
00581     Returns:    TRUE if the shape was init'ed ok, FALSE otherwise
00582     Purpose:    To initialise the paths used by the shape into a state that can be used,
00583                 by allocating memory, setting up member variables properly.
00584 
00585 ***********************************************************************************************/
00586 BOOL NodeShadow::SetUpShape()
00587 {
00588     return TRUE;
00589 }
00590 
00591 
00592 
00593 /********************************************************************************************
00594 
00595 >   virtual void NodeShadow::Transform( TransformBase& Trans )
00596 
00597     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00598     Created:    21/11/94
00599     Inputs:     Trans - The transform Object
00600     Purpose:    Transforms the shape.
00601     SeeAlso:    NodeRenderableInk::Transform()
00602 
00603 ********************************************************************************************/
00604 void NodeShadow::Transform( TransformBase& Trans )
00605 {
00606     NodeShadowController* pControl = (NodeShadowController*)GetParentController();
00607     if (pControl && pControl->IsCapturingChildren())
00608     {
00609 //      TransformChildren(Trans);
00610         return;
00611     }
00612 
00613     if (m_pBMPTransFill)
00614     {
00615         Trans.Transform(m_pBMPTransFill->GetStartPoint(), 1);
00616         Trans.Transform(m_pBMPTransFill->GetEndPoint(), 1);
00617         Trans.Transform(m_pBMPTransFill->GetEndPoint2(), 1);
00618         Trans.Transform(m_pBMPTransFill->GetEndPoint3(), 1);
00619     }
00620 
00621     // transform my shape
00622     Trans.Transform(m_Path.GetCoordArray(), m_Path.GetNumCoords());
00623     Trans.Transform(m_NonTranslatedPath.GetCoordArray(), m_NonTranslatedPath.GetNumCoords());
00624 
00625     InvalidateBoundingRect();
00626 
00627     // transform the selection rect
00628 
00629     // check for a change in aspect
00630     if (Trans.IsTranslation())
00631     {
00632         if (pControl != NULL)
00633         {
00634             if (pControl->GetShadowType() == SHADOWTYPE_GLOW)
00635             {
00636                 Trans.Transform(&m_SelectedRect.lo, 1);
00637                 Trans.Transform(&m_SelectedRect.hi, 1);
00638             }
00639             else
00640             {
00641 //  Karim 19/10/2000
00642 //  Chris' last changes to this method amount to commenting out this line.
00643 //                  pControl->RegenerateNode(NULL);
00644             }
00645         }
00646     }
00647     else
00648     {
00649         // force a redraw of myself to stop rendering glitches
00650         Document * pDoc = Document::GetCurrent();
00651 
00652         if (pDoc)
00653         {
00654             DocRect dr(0,0,0,0);
00655             m_Path.GetTrueBoundingRect(&dr);
00656             pDoc->ForceRedraw(FindParentSpread(), dr, FALSE, this, FALSE);
00657         }
00658     }
00659 
00660     // transform my children
00661     TransformChildren(Trans);
00662 }
00663 
00664 
00665 
00666 /***********************************************************************************************
00667 
00668 >   void NodeShadow::Render(RenderRegion* pRender)
00669 
00670     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00671     Created:    16/11/94
00672     Inputs:     Pointer to a render region
00673     Purpose:    Will build a path for the shape and draw it to the given render region.
00674 
00675 ***********************************************************************************************/
00676 void NodeShadow::Render(RenderRegion* pRender)
00677 {
00678     m_bHaveTransformed = FALSE;
00679     m_RenderBitmaps    = FALSE;
00680 
00681     // check for us having something to render or not
00682     NodeShadowController* pController = (NodeShadowController*)GetParentController();
00683 
00684     if (pController)
00685     {
00686 #ifdef NEW_SHADOW_RENDER
00687         // If Controller has Effect Attributes applied
00688         // Then the Shadow Node must not render anything - it's RenderShadow
00689         // function will be called at the right time instead
00690         if (pController->IsCapturingChildren())
00691         {
00692 //          TRACEUSER( "Gerry", _T("Render# Controller is capturing\n"));
00693             // Normally we allow the ShadowController to render us when it wants to
00694             // But for hit detection we must render ourselves (aswell)
00695             //      or when render quality is outline
00696             if (pRender->IsHitDetect() || pRender->RRQuality.GetFillQuality() <= Quality::Solid)
00697             {
00698 //              TRACEUSER( "Gerry", _T("Render# Hit detect or outline\n"));
00699                 RenderShadow(pRender);
00700             }
00701             return;
00702         }
00703 #endif
00704         // if my inside bounding rect is empty (i.e. the bounding rect of all
00705         // the objects to be shadowed) then do nothing
00706         if (pController->GetInsideBoundingRect().IsEmpty())
00707         {
00708 //          TRACEUSER( "Gerry", _T("Render# Inside bounding rect is empty\n"));
00709             return;
00710         }
00711     }
00712 
00713     if (!RenderBitmapForDisplay(pRender))
00714     {
00715 //      TRACEUSER( "Gerry", _T("Render# RenderBitmapForDisplay failed\n"));
00716         return;
00717     }
00718 
00719     // check the quality setting - if it's too low, then we need to render a shadow outline.
00720     enum Quality::Fill CurrentQuality = pRender->RRQuality.GetFillQuality();
00721     if (CurrentQuality >= (enum Quality::Fill)Quality::Solid)
00722     {
00723 //      TRACEUSER( "Gerry", _T("Render# Calling RenderBitmap\n"));
00724         RenderBitmap(pRender);
00725     }
00726     else
00727     {
00728         // outlines only - we'll just render the shadow's bounding rect.
00729 //      TRACEUSER( "Gerry", _T("Render# Rendering bounding rect\n"));
00730         DocRect drBounds = GetBoundingRect();
00731         pRender->SaveContext();
00732         pRender->SetFillColour(COLOUR_NONE);
00733         pRender->SetLineColour(COLOUR_BLACK);
00734         pRender->DrawRect(&drBounds);
00735         pRender->RestoreContext();
00736     }
00737 
00738     // get the view out of the renderer
00739     // and reset its rendering clock
00740     View * pView = pRender->GetRenderView();
00741 
00742     if (pView)
00743     {
00744         if (pView->IS_KIND_OF(DocView))
00745         {
00746             ((DocView *)pView)->ResetRenderingStartTime();
00747         }
00748     }
00749 }  
00750 
00751 
00752 
00753 /********************************************************************************************
00754 
00755 >   void NodeShadow::RenderEorDrag( RenderRegion* pRender )
00756 
00757     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00758     Created:    16/11/94
00759     Inputs:     pRender - A Pointer to the current RenderRegion
00760     Purpose:    Renders a version of the shape for EORed dragging.
00761     SeeAlso:    NodeRenderableInk::RenderEorDrag
00762 
00763 ********************************************************************************************/
00764 void NodeShadow::RenderEorDrag( RenderRegion* pRender )
00765 {
00766     // outlines only - we'll just render the shadow's bounding rect.
00767     DocRect drBounds = GetBoundingRect();
00768 //  pRender->SaveContext();
00769 //  pRender->SetFillColour(COLOUR_NONE);
00770 //  pRender->SetLineColour(COLOUR_BLACK);
00771     pRender->DrawRect(&drBounds);
00772 //  pRender->RestoreContext();
00773 }
00774 
00775 
00776 
00777 /********************************************************************************************
00778 
00779 >   void NodeShadow::RenderObjectBlobs(RenderRegion* pRender)
00780 
00781     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00782     Created:    16/11/94
00783     Inputs:     pRender - the region to render the blobs to
00784     Purpose:    Renders the Object blobs for a NodeRegularShape
00785     SeeAlso:    BlobManager
00786 
00787 ********************************************************************************************/
00788 void NodeShadow::RenderObjectBlobs(RenderRegion* pRender)
00789 {
00790 }
00791 
00792 
00793 
00794 /********************************************************************************************
00795 
00796 >   void NodeShadow::RenderTinyBlobs(RenderRegion* pRender)
00797 
00798     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00799     Created:    16/11/94
00800     Inputs:     pRender - the region to render the blobs to
00801     Purpose:    Renders the Tiny blobs for a NodeRegularShape
00802     SeeAlso:    BlobManager
00803 
00804 ********************************************************************************************/
00805 void NodeShadow::RenderTinyBlobs(RenderRegion* pRender)
00806 {
00807     pRender->SaveContext();
00808     pRender->SetLineColour(COLOUR_NONE);
00809     pRender->SetFillColour(COLOUR_UNSELECTEDBLOB);
00810 
00811     // Render the blobs on the path
00812     BlobManager* BlobMgr = GetApplication()->GetBlobManager();
00813 
00814 //  DocRect dr = m_Path.GetBoundingRect(); MRH 19/5/00
00815     DocRect dr(0,0,0,0);
00816     m_Path.GetTrueBoundingRect(&dr);
00817 
00818     DocCoord Coord(dr.lo.x + (BlobMgr->GetBlobSize() / 2), 
00819         dr.hi.y - (BlobMgr->GetBlobSize() / 2));
00820     pRender->DrawBlob(Coord, BT_UNSELECTED);
00821     pRender->RestoreContext();
00822 }
00823 
00824 
00825 
00826 /********************************************************************************************
00827 
00828 >   DocRect NodeShadow::GetBoundingRect(BOOL DontUseAttrs = FALSE, BOOL HitTest = FALSE)
00829 
00830     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
00831     Created:    23/06/2000
00832     Inputs:     DontUseAttrs        TRUE if we should take node attributes into account.
00833                 HitTest             TRUE if we're being called during a hit-test.
00834 
00835     Returns:    This node's bounding rect.
00836 
00837     Purpose:    If the bounding rect has been marked as invalid, it is recalculated,
00838                 otherwise a cached bounding rectangle is returned.
00839 
00840     Errors:     ERROR3 if we find an unrecognised shadow type.
00841 
00842 ********************************************************************************************/
00843 DocRect NodeShadow::GetBoundingRect(BOOL DontUseAttrs, BOOL HitTest)
00844 {
00845     // is our cached bounding rect invalid?
00846     if (!IsBoundingRectValid)
00847     {
00848         DocRect drBounds(0, 0, 0, 0);
00849 
00850         // if our shadow path is valid, then just try to use its bounding rect.
00851         // This will give us a perfect bounds rect so cache it of appropriate
00852         if (m_Path.GetNumCoords() != 0)
00853         {
00854             if (m_Path.GetTrueBoundingRect(&drBounds) && !drBounds.IsEmpty())
00855             {
00856                 // if we're taking attributes into account then cache it.
00857                 if (!DontUseAttrs)
00858                 {
00859                     // update our cached bounding rect.
00860                     BoundingRectangle   = drBounds;
00861                     IsBoundingRectValid = TRUE;
00862                 }
00863 
00864                 return drBounds;
00865             }
00866         }
00867 
00868         // if that didn't work, then we'll use the lengthier method of finding bounds
00869         // for our next-siblings, and then transforming them appropriately.
00870         // However, we wont cache this result as it can be a bit small 
00871         // which causes problems when printing
00872 
00873         // Get bounds of the ink node at the bottom of the shadow stack
00874         NodeShadowController* pControl = (NodeShadowController*)GetParentController();
00875         if (pControl)
00876         {
00877             NodeShadowController* pBottomControl = pControl->FindBottomShadowController();
00878             NodeRenderableInk* pSibling = pBottomControl->GetInkNodeFromController();
00879             if (pSibling)
00880                 drBounds = drBounds.Union(pSibling->GetBoundingRect(DontUseAttrs, HitTest));
00881         }
00882 
00883         // a different transformation is required, according to our shadow type.
00884         if (pControl != NULL)
00885         {
00886             switch (pControl->GetShadowType())
00887             {
00888             case SHADOWTYPE_WALL:
00889                 drBounds.Translate(pControl->GetOffsetX(), pControl->GetOffsetY());
00890                 drBounds.Inflate(pControl->GetPenumbraWidth());
00891                 break;
00892 
00893             case SHADOWTYPE_GLOW:
00894                 drBounds.Inflate(pControl->GetGlowWidth());
00895                 drBounds.Inflate(pControl->GetPenumbraWidth());
00896                 break;
00897 
00898             case SHADOWTYPE_FLOOR:
00899                 {
00900                     DocCoord dcControlVector = pControl->GetFloorShadowVector();
00901 
00902                     drBounds.hi.y = drBounds.lo.y + dcControlVector.y;
00903                     drBounds.hi.y += pControl->GetPenumbraWidth();
00904 
00905                     if (dcControlVector.x > 0)
00906                     {
00907                         drBounds.hi.x += dcControlVector.x;
00908                         drBounds.hi.x += pControl->GetPenumbraWidth();
00909                     }
00910                     else
00911                     {
00912                         drBounds.lo.x += dcControlVector.x;
00913                         drBounds.lo.x -= pControl->GetPenumbraWidth();
00914                     }
00915                 }
00916                 break;
00917 
00918             case SHADOWTYPE_FEATHER:
00919                 drBounds.Inflate(pControl->GetFeatherWidth());  // TODO: /2?
00920                 drBounds.Inflate(pControl->GetPenumbraWidth());
00921                 break;
00922 
00923             default:
00924                 ERROR3("NodeShadow::GetBoundingRect; unknown parent shadow type!");
00925                 break;
00926             }
00927         }
00928 
00929         return drBounds;
00930     }
00931 
00932     return BoundingRectangle;
00933 }
00934 
00935 
00936 
00937 /********************************************************************************************
00938 
00939 >   DocRect NodeShadow::GetBlobBoundingRect()
00940 
00941     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00942     Created:    16/11/94
00943     Returns:    DocRect - Returns the bounding rect of the shape and its blobs
00944     Purpose:    This calculates the bounding box of the shape's path and adds in the
00945                 influence of the selection blobs. It does not consider if the blobs are
00946                 visible or not, it just gives the bounding box that they would occupy if
00947                 they were visible
00948 
00949 ********************************************************************************************/
00950 DocRect NodeShadow::GetBlobBoundingRect()
00951 {
00952     // Find the Shapes bounding rectangle
00953     DocRect Rect = GetBoundingRect();
00954 
00955     BlobManager * pBlobMgr = GetApplication()->GetBlobManager();
00956 
00957     Rect.lo.x -= pBlobMgr->GetBlobSize();
00958     Rect.lo.y -= pBlobMgr->GetBlobSize();
00959     Rect.hi.x += pBlobMgr->GetBlobSize();
00960     Rect.hi.y += pBlobMgr->GetBlobSize();
00961 
00962     // Make sure we include the Bounds of our children
00963     IncludeChildrensBoundingRects(&Rect);
00964 
00965     return Rect;
00966 }
00967 
00968 /********************************************************************************************
00969 
00970 >   virtual UINT32 NodeShadow::GetNodeSize() const
00971 
00972     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00973     Created:    16/11/94
00974     Returns:    The size of the node in bytes 
00975     Purpose:    For finding the size of the node 
00976     SeeAlso:    Node::GetSubtreeSize
00977 
00978 ********************************************************************************************/
00979 UINT32 NodeShadow::GetNodeSize() const 
00980 {     
00981     return (sizeof(NodeShadow)); 
00982 }  
00983 
00984 /********************************************************************************************
00985 
00986 >   BOOL NodeShadow::OnClick( DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods,
00987                                                 Spread* pSpread)
00988 
00989     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
00990     Created:    16/11/94
00991     Inputs:     PointerPos - The Location of the mouse pointer at the time of the click
00992                 Click - The type of click received (single, double, drag etc)
00993                 ClickMods - The modifiers to the click (eg shift, control etc )
00994     Returns:    BOOL - TRUE if the node claims the click as its own and FALSE if it is
00995                 not interested in the click
00996     Purpose:    Allows the QuickShape to respond to clicks by selecting its blobs or starting
00997                 drags etc.
00998 
00999 ********************************************************************************************/
01000 
01001 BOOL NodeShadow::OnClick( DocCoord PointerPos, ClickType Click, ClickModifiers ClickMods,
01002                                                         Spread* pSpread)
01003 {
01004     // did not use the click
01005     return FALSE;
01006 }
01007 
01008 /********************************************************************************************
01009 
01010 >   virtual BOOL NodeShadow::CanBecomeA(BecomeA* pBecomeA)
01011 
01012     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01013     Created:    16/11/94
01014     Inputs:     InkClass: The class of object
01015                 pNumObjects = ptr to place number of objects of type pClass that will be created (Note: can be NULL).
01016                               *pNumObects in undefined on entry
01017     Returns:    TRUE if the node, or any of its children can transmogrify themselves to become 
01018                 an InkClass object
01019     Purpose:    This function is used by the convert to shapes operation. It determines if 
01020                 the node or any of its children can convert themselves into an InkClass object. 
01021 
01022                 The number you put into pNumObjects (if it's not NULL) should exactly equal the total number
01023                 of pClass objects you create.  It should NOT contain any additional objects you may produce
01024                 such as group objects for containing the pClass object, or attributes.
01025 
01026                 Also, the entry value of *pNumObjects cannot be assumed to be 0.
01027 
01028 ********************************************************************************************/
01029 BOOL NodeShadow::CanBecomeA(BecomeA* pBecomeA)
01030 {
01031     // The NodeRegularShape can become a NodePath
01032     if (pBecomeA->BAPath())
01033     {
01034         pBecomeA->AddCount(1);
01035 
01036         return TRUE;
01037     }
01038 
01039     return FALSE;
01040 }
01041 
01042 
01043 
01044 /********************************************************************************************
01045 
01046 >   virtual BOOL NodeShadow::DoBecomeA(BecomeA* pBecomeA) 
01047 
01048     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01049     Created:    25/11/94
01050     Inputs:     pBecomeA =  ptr to a class that contains all the info needed to become a new
01051                             type of node.
01052     Outputs:    -
01053     Returns:    TRUE if the object has been transformed, FALSE if we run out of memory
01054     Purpose:    Transforms the object into another type of object. 
01055     SeeAlso:    NodeRegularShape::CanBecomeA
01056 
01057 ********************************************************************************************/
01058 BOOL NodeShadow::DoBecomeA(BecomeA* pBecomeA)
01059 {
01060     // Check for a NULL entry param
01061     ERROR2IF(pBecomeA == NULL,FALSE,"pBecomeA is NULL");
01062 
01063     // This lump checks that the Reason is one that we understand
01064     // It also makes sure that we don't have a NULL UndoOp ptr
01065     BOOL ValidReason = (pBecomeA->GetReason() == BECOMEA_REPLACE || pBecomeA->GetReason() == BECOMEA_PASSBACK);
01066     ERROR2IF_PF(!ValidReason,FALSE,("Unkown BecomeA reason %d",pBecomeA->GetReason()));
01067 
01068     // New behaviour: Leave shadow in the tree if the BecomeA claims
01069     // it will leave the result node in position in the tree
01070     if (pBecomeA->ResultsStayInPlace() && pBecomeA->IsCombineBecomeA())
01071     {
01072         return TRUE;
01073     }
01074 
01075     Node * pAttrNode = NULL;
01076     BitmapTranspFillAttribute   * pTranspBitmapFill         = NULL;
01077 
01078     NodeAttribute           * pAttr = NULL;
01079 
01080     BOOL bInsertNew = TRUE;             // By default we will insert a new node
01081     if (RenderBitmapForDisplay())
01082         ApplyProfileToShadowBitmap();
01083     else
01084         bInsertNew = FALSE;             // Failed to generate the shadow bitmap
01085 
01086     // if we're replacing we need to create a normal node path
01087     if (pBecomeA->GetReason() == BECOMEA_REPLACE)
01088     {
01089         DocRect dr(0, 0, 0, 0);
01090         m_Path.GetTrueBoundingRect(&dr);
01091         DocCoord dc1(dr.lo.x, dr.lo.y);
01092         DocCoord dc2(dr.hi.x, dr.lo.y);
01093         DocCoord dc3(dr.lo.x, dr.hi.y);
01094 
01095         UINT32 startTrans = GetTransp();
01096         UINT32 endTrans = 255;
01097 
01098         DocColour TransparentColour(COLOUR_NONE);
01099         AttrStrokeColour * pAttrStrokeColour = NULL;
01100 
01101         CCAttrMap * pAttrMap = NULL;
01102 
01103         // Get the current Transparency value to use!
01104         UndoableOperation* pUndoOp = pBecomeA->GetUndoOp();
01105         
01106         // We need to make sure that all the groups we may have produced have their attrs correctly
01107         // factored out.  This is so the final factoring out done by the NodeBlend node will be able
01108         // to complete the job.
01109         // Without this step, leaf nodes can have common child attrs that should be factored up the
01110         // to a higher level.
01111         Node* pNode = this->FindNext();
01112         while (pNode != NULL)
01113         {
01114             if (IS_A(pNode,NodeGroup))
01115             {
01116                 if (pUndoOp)
01117                 {
01118                     if (!pUndoOp->DoFactorOutCommonChildAttributes((NodeGroup*)pNode))
01119                         return FALSE;
01120                 }
01121                 else
01122                 {
01123                     if (!((NodeGroup*)pNode)->FactorOutCommonChildAttributes())
01124                         return FALSE;
01125                 }
01126             }
01127             
01128             pNode = pNode->FindNext();
01129         }                   
01130         
01131         if (bInsertNew)
01132         {
01133             // Make a new node to put the shadow bitmap into
01134             NodePath* pNodePath;
01135             ALLOC_WITH_FAIL(pNodePath, (new NodePath), pUndoOp); 
01136             if (pNodePath == NULL)
01137                 return FALSE;
01138             
01139             // apply the attribute map
01140             pAttrMap = CCAttrMap::MakeAppliedAttrMap(this);
01141             pNodePath->ApplyAttributes(pAttrMap, TRUE);
01142             delete pAttrMap;
01143             
01144             // remove all the appropriate attributes from this node
01145             pAttrNode = pNodePath->FindFirstChild();
01146             
01147             while (pAttrNode)
01148             {
01149                 if (pAttrNode->IsAnAttribute())
01150                 {
01151                     pAttr = (NodeAttribute *)pAttrNode;
01152                     
01153                     if (pAttr->IsAStrokeColour() ||
01154                         pAttr->IsATranspFill() ||
01155                         pAttr->IS_KIND_OF(AttrTranspFillMapping))
01156                     {
01157                         pAttrNode = pAttrNode->FindNext();
01158                         pAttr->UnlinkNodeFromTree();
01159                         delete pAttr;
01160                     }
01161                     else
01162                     {
01163                         pAttrNode = pAttrNode->FindNext();
01164                     }
01165                 }
01166                 else
01167                 {
01168                     pAttrNode = pAttrNode->FindNext();
01169                 }
01170             }
01171             
01172             // Setup the new Rect node that is to be replacing the shadow node.
01173             pNodePath->InkPath.Initialise();
01174             pNodePath->InkPath.CloneFrom(m_Path);
01175             pNodePath->InkPath.IsFilled = TRUE;
01176             pNodePath->InkPath.TryToClose();
01177             pNodePath->InkPath.InitialiseFlags(0, pNodePath->InkPath.GetNumCoords()-1);
01178             
01179             // set up the bitmap transparency fill
01180             AttrBitmapTranspFill * pAttrBitmapTranspFill = NULL;
01181             ALLOC_WITH_FAIL(pAttrBitmapTranspFill , (new AttrBitmapTranspFill), pUndoOp);
01182             
01183             pTranspBitmapFill = (BitmapTranspFillAttribute *)(pAttrBitmapTranspFill ->GetAttributeValue());
01184             
01185             pTranspBitmapFill->SetStartPoint(&dc1);
01186             pTranspBitmapFill->SetEndPoint(&dc2);
01187             pTranspBitmapFill->SetEndPoint2(&dc3);
01188             pTranspBitmapFill->SetTesselation(RT_Simple);
01189             pTranspBitmapFill->SetTranspType(TT_Mix);
01190             
01191             pTranspBitmapFill->SetStartTransp(&startTrans);
01192             pTranspBitmapFill->SetEndTransp(&endTrans);
01193             
01194             pTranspBitmapFill->AttachBitmap(m_ShadowBitmap);
01195             
01196             // attach it to the node
01197             pAttrBitmapTranspFill->AttachNode(pNodePath, FIRSTCHILD);
01198             
01199             // ensure the line colour is transparent
01200             ALLOC_WITH_FAIL(pAttrStrokeColour, (new AttrStrokeColour), pUndoOp);
01201             
01202             pAttrStrokeColour->Value.SetStartColour(&TransparentColour);
01203             
01204             pAttrStrokeColour->AttachNode(pNodePath, FIRSTCHILD);
01205             
01206             AttrTranspFillMappingLinear * pFillMapping = NULL;
01207             ALLOC_WITH_FAIL(pFillMapping, new AttrTranspFillMappingLinear, pUndoOp);
01208             pFillMapping->Value.Repeat = 1;
01209             
01210             pFillMapping->AttachNode(pNodePath, FIRSTCHILD);
01211             
01212             // Insert the NodeGroup where the NodeBlend used to be
01213             if (pUndoOp)
01214             {
01215                 if (!pUndoOp->DoInsertNewNode(pNodePath,this,PREV,TRUE,FALSE,FALSE,TRUE))
01216                     return FALSE;
01217             }
01218             else
01219             {
01220                 pNodePath->AttachNode(this, PREV);
01221                 pNodePath->NormaliseAttributes();
01222             }
01223 
01224             CCAttrMap ThisMap;
01225             CCAttrMap* pThisMap = NULL;
01226             if (pNodePath->FindAppliedAttributes(&ThisMap))
01227                 pThisMap = ThisMap.Copy();
01228             pBecomeA->PassBack(pNodePath, this, pThisMap);
01229         }
01230             
01231         if (pUndoOp)
01232         {
01233             NodeHidden* pHiddenNodeShadower = NULL;
01234             
01235             // hide this node
01236             if (!pUndoOp->DoHideNode(this, TRUE, &pHiddenNodeShadower, TRUE))
01237                 return FALSE;
01238         }
01239         else
01240         {
01241             CascadeDelete();
01242             delete this;
01243         }
01244     }
01245     else
01246     {
01247         return TRUE;
01248     }
01249     return TRUE;
01250 }
01251 
01252 
01253 
01254 /********************************************************************************************
01255 
01256 >   NodePath * NodeShadow::CreateShadowPassbackNode();
01257 
01258     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01259     Created:    20/11/96
01260     Inputs:     
01261     Returns:    NULL for failure, otherwise the new shadow passback node
01262     Purpose:    Creates the shadow passback node for the DoBeomeA - BECOMEA_PASSBACK 
01263                 mechanism
01264     SeeAlso:    NodeShadow::DoBecomeA
01265 
01266 ********************************************************************************************/
01267 NodePath * NodeShadow::CreateShadowPassbackNode()
01268 {
01269     NodePath *pPassbackNode = new NodePath();
01270 
01271     ERRORIF(pPassbackNode == NULL, _R(IDE_NOMORE_MEMORY), NULL);
01272 
01273     pPassbackNode->InkPath.Initialise();
01274 
01275     NodeRenderableInk * pInk = (NodeRenderableInk *)FindNext(CC_RUNTIME_CLASS(NodeRenderableInk));
01276 
01277     NodeShadowBecomeA MyBecomeA(BECOMEA_PASSBACK, CC_RUNTIME_CLASS(NodePath), NULL,
01278         FALSE, &(pPassbackNode->InkPath));
01279 
01280     while (pInk)
01281     {
01282         if (pInk->CanBecomeA(&MyBecomeA))
01283         {
01284             pInk->DoBecomeA(&MyBecomeA);
01285         }
01286 
01287         pInk = (NodeRenderableInk *)pInk->FindNext(CC_RUNTIME_CLASS(NodeRenderableInk));
01288     }
01289 
01290     pPassbackNode->InkPath.InitialiseFlags();
01291 
01292     return pPassbackNode;
01293 }
01294 
01295 
01296 
01297 /***********************************************************************************************
01298 
01299 >   BOOL NodeShadow::RenderBitmapForDisplay(RenderRegion* pRegion, List* pList = NULL)
01300 
01301     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
01302     Created:    19/4/2000
01303     Inputs:     pRegion     the render region to take the values from
01304                 pList       list of SumAllPathsElem's - if non-NULL, then we'll use
01305                                     this list as our source of paths for shadowing.
01306     Outputs:    
01307     Returns:    TRUE    - success
01308                 FALSE   - failure
01309                                                          
01310     Purpose:    Renders the shadow bitmap to the correct dpi
01311 
01312     Notes:      Karim 03/07/2000
01313                 To use the old shadow rendering code, comment out the USE_NEW_SHADOW_CODE
01314                 define up top. Note that as time progresses, the odds on something or other
01315                 breaking the old code do grow.
01316 
01317                 Also, sorry about lumping everything into one function - at some point,
01318                 this function should probably be hacked apart into several smaller, more
01319                 manageable pieces.
01320 
01321     Errors:     -   
01322     Scope:      protected
01323            
01324 **********************************************************************************************/
01325 BOOL NodeShadow::RenderBitmapForDisplay(RenderRegion* pRegion, List* pList)
01326 {
01327     // the shadow bitmap is cached, using the last scaled pixel width and quality settings.
01328     MILLIPOINT CurrentPixWidth = pRegion->GetScaledPixelWidth();
01329     enum Quality::Fill CurrentQuality = pRegion->RRQuality.GetFillQuality();
01330 
01331     if (m_ShadowBitmap != NULL)
01332         if (m_LastRequestedPixWidth == CurrentPixWidth &&
01333             m_LastQualitySetting    == CurrentQuality)
01334         {
01335 //          TRACEUSER( "Gerry", _T("RenderBitmapForDisplay# Same as last\n"));
01336             return TRUE;
01337         }
01338 
01339     // no need to regenerate the bitmap if quality is below a certain level.
01340     if (CurrentQuality < (enum Quality::Fill)Quality::Solid)
01341     {
01342 //      TRACEUSER( "Gerry", _T("RenderBitmapForDisplay# Quality too low\n"));
01343         return TRUE;
01344     }
01345 
01346     // we can only regenerate the bitmap if we're given a GRenderRegion.
01347     // don't return a failure code, as RRs such as ScanningRR may need to dummy-render us.
01348     if (!pRegion->IS_KIND_OF(GRenderRegion))
01349     {
01350 //      TRACEUSER( "Gerry", _T("RenderBitmapForDisplay# Not a GRenderRegion\n"));
01351         return TRUE;
01352     }
01353 
01354     // Bodge for effects that might change their bounds...
01355     // Floor shadows position themselves based on the bounding rect of the shadowed node
01356     // But the shadowed node might be an Effect that hasn't been generated yet and so
01357     // still has expanded bounds...
01358     // So we must ensure that the effect is rendered and knows its bounds before
01359     // we create and render the shadow
01360     // Note that this is not a huge overhead because the effect processing would have
01361     // taken place inside GetSilhouette bitmap anyway. Instead that function will get
01362     // the cached results of this render.
01363     NodeShadowController* pController = (NodeShadowController*)GetParentController();
01364     if (pController && pController->GetShadowType()==SHADOWTYPE_FLOOR)
01365     {
01366         // Check whether Ink node is an effect without a processed bitmap
01367         NodeRenderableInk* pInk = pController->GetInkNodeFromController();
01368         if (pInk && pInk->IsEffect() && ((NodeEffect*)pInk)->IsBitmapEffect())
01369         {
01370             NodeBitmapEffect* pEffect = (NodeBitmapEffect*)pInk;
01371             BOOL bOK = pEffect->GetProcessedBitmap(FALSE, NULL, NULL, NULL);
01372             if (!bOK)
01373             {
01374                 pRegion->SaveContext();
01375 
01376                 // Direct capture and ignore the bitmap handed back to us
01377                 // so that we avoid creating unused capture bitmap
01378                 CaptureFlags caFlags = CaptureFlags(cfLOCKEDTRANSPARENT | cfUNCLIP | cfALLOWDIRECT | cfPIXWIDTHSCALE);
01379                 DocRect CaptureRect = pEffect->GetBoundingRect();
01380                 pRegion->StartCapture(this, CaptureRect, CAPTUREINFO(ctNESTABLE, caFlags), TRUE, FALSE, 0, pEffect);
01381                 pRegion->RenderTree(pEffect, FALSE);
01382                 pRegion->StopCapture(this, FALSE, TRUE);
01383 
01384                 pRegion->RestoreContext();
01385             }
01386         }
01387     }
01388 
01389     // BitmapShadower does all the silhouette creation work, and exposes methods
01390     // which return useful shadow info, as well as the silhouette bitmap.
01391     BitmapShadower* pBmpShadower = BitmapShadower::CreateSilhouetteBitmap((NodeShadowController*)GetParentController(), (GRenderRegion*)pRegion, pList);
01392     if (pBmpShadower == NULL)
01393     {
01394 //      TRACEUSER( "Gerry", _T("RenderBitmapForDisplay# CreateSilhouetteBitmap failed\n"));
01395         return FALSE;
01396     }
01397 
01399     // Post-process the 32bpp 'silhouette' bitmap, to get the 8bpp greyscale shadow bitmap.
01401 
01402     // initialise the transparency fill attribute and clear our caches.
01403     SetupTransFill();
01404 
01405     // get the silhouette bitmap out of the shadower.
01406     KernelBitmap* pSilhouetteBmp = pBmpShadower->GetSilhouetteBitmap();
01407 
01408     // generate the shadow bitmap for the required blur diameter.
01409     const double pixBlurDiameter = pBmpShadower->GetPixBlurDiameter();
01410     BOOL bOK = GenerateShadowBitmap(pSilhouetteBmp, pixBlurDiameter);
01411     if (bOK)
01412     {
01413     // if desired, attach a debug copy of the final shadow bitmap within the bitmap gallery.
01414 #ifdef ATTACH_SHADOW_BMP
01415         m_ShadowBitmap->AttachDebugCopyToCurrentDocument("Shadow Final Bitmap");
01416 #endif
01417 
01418 //      TRACEUSER( "Gerry", _T("RenderBitmapForDisplay# GenerateShadowBitmap ok\n"));
01419 
01420         // ok, we're done! now remember the requested and actual pix-per-inch settings
01421         // at which we have just successfully created the new shadow bitmap.
01422         m_LastRequestedPixWidth = CurrentPixWidth;
01423         m_LastQualitySetting    = CurrentQuality;
01424         m_LastActualPixWidth = (CurrentPixWidth > 0) ? pBmpShadower->GetActualPixelWidth() : -1;
01425 
01426         // one last thing - create the path which the shadow bitmap-transparency is drawn into.
01427         DocRect drBounds = pBmpShadower->GetBitmapBounds();
01428         CreateBitmapPath(drBounds, m_LastActualPixWidth, pixBlurDiameter);
01429 
01430         // free up the shadower, now we've finished using it.
01431         delete pBmpShadower;
01432         pBmpShadower = NULL;
01433     }
01434 //  else
01435 //  {
01436 //      TRACEUSER( "Gerry", _T("RenderBitmapForDisplay# GenerateShadowBitmap failed\n"));
01437 //  }
01438 
01439     if (pSilhouetteBmp)
01440     {
01441 //      TRACE( _T("Warning - NodeShadow::RenderBitmapForDisplay not deleting bitmap\n") );
01442         delete pSilhouetteBmp;
01443         pSilhouetteBmp = NULL;
01444     }
01445 
01446     return bOK;
01447 }
01448 
01449 
01450 
01451 /********************************************************************************************
01452 
01453 >   BOOL NodeShadow::RenderBitmapForDisplay()
01454 
01455     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
01456     Created:    27/10/2000
01457 
01458     Outputs:    Our shadow bitmap and path will be set up ready for rendering, if successful.
01459 
01460     Returns:    TRUE if successful, FALSE otherwise.
01461 
01462     Purpose:    A simpler overload of the complicated function above.
01463                 Simpler because this function:
01464                 *   Does not use a render-region - it queries the current view
01465                     for render information instead.
01466                 *   Does not do any caching - providing we don't fail, we _will_ render
01467                     a new shadow whenever you call us, so do NOT use with abandon!
01468 
01469     Notes:      In order to call this function, we must be installed in the tree. Somewhere
01470                 deep in the innards of this routine, we need to access the Spread, in order
01471                 to get the rendering origin right.
01472 
01473     See also:   RenderBitmapForDisplay above, which is more fully featured and should be the
01474                 function called in normal use.
01475 
01476 ********************************************************************************************/
01477 BOOL NodeShadow::RenderBitmapForDisplay()
01478 {
01479     // Create a bitmap-shadower containing the shadow silhouette.
01480     BitmapShadower* pBmpShadower = BitmapShadower::CreateSilhouetteBitmap((NodeShadowController*)GetParentController());
01481     if (pBmpShadower == NULL)
01482         return FALSE;
01483 
01484     // initialise the transparency fill attribute and clear our caches.
01485     SetupTransFill();
01486 
01487     // get the silhouette bitmap out of the shadower.
01488     KernelBitmap* pSilhouetteBmp = pBmpShadower->GetSilhouetteBitmap();
01489 
01490     // Blur & grayscale the silhouette, to get the shadow bitmap.
01491     const double pixBlurDiameter = pBmpShadower->GetPixBlurDiameter();
01492     BOOL bOK = GenerateShadowBitmap(pSilhouetteBmp, pixBlurDiameter);
01493     if (bOK)
01494     {
01495         // Tell the bitmap what resolution people should render it at.
01496         // Doesn't affect rendering - just useful if it ends up in the bitmap gallery.
01497         LPBITMAPINFOHEADER pShadowHeader = m_ShadowBitmap->GetBitmapInfoHeader();
01498         const double PixPerMetre = MILLIPOINTS_PER_INCH * INCHES_PER_METRE / pBmpShadower->GetActualPixelWidth();
01499         pShadowHeader->biXPelsPerMeter = pShadowHeader->biYPelsPerMeter = (INT32)(PixPerMetre + 0.5);
01500 
01501 // attach a debug copy to the bitmap gallery, if required.
01502 #ifdef ATTACH_SHADOW_BMP
01503         m_ShadowBitmap->AttachDebugCopyToCurrentDocument("Shadow Final Bitmap");
01504 #endif
01505 
01506         // generate the path to hold the shadow bitmap.
01507         DocRect drBounds = pBmpShadower->GetBitmapBounds();
01508         CreateBitmapPath(drBounds, pBmpShadower->GetActualPixelWidth(), pixBlurDiameter);
01509 
01510         // the cached bitmap is now invalid, so mark it so via the last pixel width.
01511         m_LastRequestedPixWidth = -1;
01512 
01513         // free up our used bitmap-shadower.
01514         delete pBmpShadower;
01515         pBmpShadower = NULL;
01516     }
01517 
01518     if (pSilhouetteBmp)
01519     {
01520         delete pSilhouetteBmp;
01521         pSilhouetteBmp = NULL;
01522     }
01523 
01524     return bOK;
01525 }
01526 
01527 
01528 
01529 /********************************************************************************************
01530 
01531 >   BOOL NodeShadow::ApplyProfileToShadowBitmap()
01532 
01533     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
01534     Created:    30/10/2000
01535 
01536     Outputs:    The palette for m_ShadowBitmap will be set correctly, to use the information
01537                 from the shadow's profile control.
01538 
01539     Returns:    TRUE if successful, FALSE otherwise.
01540 
01541     Errors:     ERROR3 if m_ShadowBitmap is NULL or our profile control gives a bad result.
01542 
01543 ********************************************************************************************/
01544 BOOL NodeShadow::ApplyProfileToShadowBitmap()
01545 {
01546     if (m_ShadowBitmap == NULL)
01547     {
01548         ERROR3("NodeShadow::ApplyProfileToShadowBitmap; NULL shadow bitmap!");
01549         return FALSE;
01550     }
01551 
01552     LPRGBQUAD pPalette = m_ShadowBitmap->GetPaletteForBitmap();
01553 
01554     AFp res;
01555 
01556     m_BiasGain.SetBias(-m_BiasGain.GetBias());
01557 
01558     for (INT32 i = 0 ; i < 256; i++)
01559     {
01560         double d = ((double)i) / 255;
01561 
01562         res = m_BiasGain.MapZeroToOne((AFp)(d));
01563         res *= 255.0;
01564 
01565         ERROR3IF(res < 0 || res > 255,
01566                 "NodeShadow::ApplyProfileToShadowBitmap; Bad result from profile control!");
01567 
01568         pPalette[i].rgbRed = pPalette[i].rgbBlue = pPalette[i].rgbGreen = (BYTE)res;
01569     }
01570 
01571     m_BiasGain.SetBias(-m_BiasGain.GetBias());
01572 
01573     return TRUE;
01574 }
01575 
01576     
01577     
01578 /***********************************************************************************************
01579 
01580 > BOOL NodeShadow::Snap(DocCoord* pDocCoord)
01581 
01582     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01583     Created:    21/12/94
01584     Inputs:     pDocCoord   = a coord in Spread coords
01585     Outputs:    If the point is snapped then pDocCoord will contain the point of attraction.
01586     Returns:    TRUE    - the DocCoord has been snapped to the shapes path.
01587                 FALSE   - the DocCoord has not been processed.
01588                                                          
01589     Purpose:    Snaps to given coord to the nearest point on the shapes render path.  If it is
01590                 not appropriate to snap the coord to the shape (at the moment this means the
01591                 coord is too far awawy), then FALSE is returned.
01592     Errors:     -   
01593     Scope:      public
01594            
01595 **********************************************************************************************/
01596 BOOL NodeShadow::Snap(DocCoord* pDocCoord)
01597 {
01598     return FALSE;
01599 }
01600 
01601 
01602 
01603 /***********************************************************************************************
01604 
01605 > BOOL NodeShadow::Snap(DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord)
01606 
01607     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01608     Created:    21/9/94
01609     Inputs:     pDocCoord   - the rectangle to snap
01610                 StartDrag   - Start coord of drag
01611                 EndDrag     - End coord of drag
01612     Outputs:    
01613     Returns:    TRUE    - the DocRect been snapped to the grid.
01614                 FALSE   - the DocRect has not been processed.
01615                                                          
01616     Purpose:    Snaps the given rect to the nearest position on the grid, preserving its width
01617                 and height.
01618                 The coords of the rect used for the snapping are determined by the PrevCoord and
01619                 CurCoord coords supplied.  This is done to allow the user to control how a
01620                 selection rectangle is snapped to the grid by the direction of his/her last mouse 
01621                 movement.
01622                 To force the bottom left hand corner of the rect to be snapped, 
01623                 supply PrevCoord=(0,0) and CurCoord(-1,-1).
01624     Scope:      public
01625            
01626 **********************************************************************************************/
01627 BOOL NodeShadow::Snap(DocRect* pDocRect,const DocCoord& PrevCoord,const DocCoord& CurCoord)
01628 {
01629     return FALSE;
01630 }
01631 
01632 
01633 
01634 /********************************************************************************************
01635 
01636 >   BOOL NodeShadow::SnapToCoords(DocCoord* pDocCoord)
01637 
01638     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01639     Created:    29/3/95
01640     Inputs:     pDocCoord - the coord to try and snap to
01641     Outputs:    pDocCoord - The snapped coord, if it was close enough to any of the magnetic
01642                 points for a rectangle.
01643     Returns:    TRUE if it was snapped, FALSE if not
01644     Purpose:    Snaps the point magnetically to the the significant points of the shape
01645 
01646 ********************************************************************************************/
01647 BOOL NodeShadow::SnapToCoords(DocCoord* pDocCoord)
01648 {
01649     return FALSE;
01650 }
01651 
01652 
01653 
01654 /********************************************************************************************
01655 
01656 >   virtual String NodeShadow::Describe(BOOL Plural, BOOL Verbose = TRUE)
01657 
01658     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01659     Created:    22/11/94
01660     Inputs:     Plural: Flag indicating if the string description should be plural or
01661                 singular. 
01662     Returns:    Description of the object                                    
01663     Purpose:    To return a description of the NodeRegularShape object in either the singular
01664                 or the plural. This method is called by the DescribeRange method.
01665                 The description will always begin with a lower case letter.   
01666     Errors:     A resource exception will be thrown if a problem occurs when loading the 
01667                 string resource. 
01668 
01669 ********************************************************************************************/
01670 String NodeShadow::Describe(BOOL Plural, BOOL Verbose) 
01671 {     
01672     if (Plural)
01673     {
01674         String str(_R(IDS_SHADOWNODENAME));
01675         str += _T("s");
01676 
01677         return(str);
01678     }
01679     else
01680         return(String(_R(IDS_SHADOWNODENAME))); 
01681 }
01682 
01683 
01684 
01685 /********************************************************************************************
01686 
01687 >   virtual BOOL NodeShadow::ExportRender ( RenderRegion *pRegion )
01688 
01689     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
01690     Created:    14/12/99
01691     Inputs:     pRegion - A pointer to a RenderRegion.
01692 
01693     Outputs:    After this call, our cached shadow-rendering information may have changed.
01694 
01695     Returns:    TRUE if we successfully ExportRender()'ed the shadow,
01696                 FALSE otherwise.
01697 
01698     Purpose:    Used to output shadows into various export filters.
01699                 Shadows are usually exported as a bitmap or a transparent bitmap.
01700                 For more info, see the appropriate implementation of ExportShadow()
01701                 in the filter render-regions.
01702 
01703     Notes:      Rewritten by Karim 24/01/2000 for clarity and to stop unnecessary rendering.
01704 
01705 ********************************************************************************************/
01706 BOOL NodeShadow::ExportRender( RenderRegion *pRegion )
01707 {
01708     enum ShadowFilterType
01709     {
01710         NONE,
01711         FLASH,
01712         CMX,
01713         AIEPS
01714     };
01715     ShadowFilterType ftExportFilter =   pRegion->IS_KIND_OF(FlashRenderRegion)  ? FLASH :
01716 PORTNOTE("cmx","NodeShadow::ExportRender - ignore CMX ")
01717 #ifndef EXCLUDE_FROM_XARALX
01718                                     pRegion->IS_KIND_OF(CMXRenderRegion)    ? CMX   :
01719 #endif
01720                                     pRegion->IS_KIND_OF(AIEPSRenderRegion)  ? AIEPS :
01721                                     NONE;
01722 
01723     // Render our shadow bitmap at the export resolution.
01724     // Note that we choose to continue if ApplyProfileToShadowBitmap() fails.
01725     if (ftExportFilter != NONE)
01726     {
01727         if (!RenderBitmapForDisplay())
01728             return FALSE;
01729 
01730         ApplyProfileToShadowBitmap();
01731     }
01732 
01733     // OK, export our shadow!
01734     BOOL bResult = FALSE;
01735     switch (ftExportFilter)
01736     {
01737     // Flash export.
01738     case FLASH:
01739     {
01740         FlashRenderRegion   *pFlash     = static_cast<FlashRenderRegion*> ( pRegion );
01741         bResult = pFlash->ExportShadow( &m_Path,
01742                                         m_ShadowBitmap->GetActualBitmap (),
01743                                         GetTransp() );
01744     }
01745     break;
01746 
01747 PORTNOTE("cmx","NodeShadow::ExportRender - ignore CMX ")
01748 #ifndef EXCLUDE_FROM_XARALX
01749     // CMX export.
01750     case CMX:
01751     {
01752         CMXRenderRegion     *pCMX       = static_cast<CMXRenderRegion*> ( pRegion );
01753         bResult = pCMX->ExportShadow(   m_ShadowBitmap->GetActualBitmap (),
01754                                         GetTransp(),
01755                                         GetBoundingRect () );
01756     }
01757     break;
01758 #endif
01759 
01760     // AI EPS export.
01761     case AIEPS:
01762     {
01763         DocRect brect = GetBoundingRect();
01764         AIEPSRenderRegion   *pAIEPS     = static_cast<AIEPSRenderRegion*> ( pRegion );
01765         bResult = pAIEPS->ExportShadow( m_ShadowBitmap->GetActualBitmap (),
01766                                         GetTransp(),
01767                                         brect );
01768     }
01769     break;
01770 
01771     // Unrecognised filter.
01772     default:
01773         bResult = FALSE;
01774         break;
01775     }
01776 
01777     return bResult;
01778 }
01779 
01780 
01781 
01782 /********************************************************************************************
01783 
01784 >   BOOL NodeShadow::WritePreChildrenNative(BaseCamelotFilter * pFilter)
01785     BOOL NodeShadow::WritePreChildrenWeb(BaseCamelotFilter * pFilter)
01786 
01787     Author:     Andy_Hayward (Xara Group Ltd) <camelotdev@xara.com>
01788     Created:    03/06/96
01789     Inputs:     pFilter - filter to use
01790     Returns:    Boolean value indicating success
01791     Purpose:    Writes this regular shape to the filter
01792                 
01793                 NodeShadows do NOT save anything out in the current version of Camelot.
01794 
01795                 For now though, do save out just the place holder node
01796 
01797     Notes:      Karim 06/02/2001
01798                 Added code to write out the shadow Darkness.
01799 
01800 ********************************************************************************************/
01801 BOOL NodeShadow::WritePreChildrenNative(BaseCamelotFilter * pFilter)
01802 {
01803 #ifdef DO_EXPORT
01804     ERROR2IF(pFilter == NULL,FALSE,"NULL filter param");
01805     BOOL ok = TRUE;
01806     
01807     CXaraFileRecord Rec(TAG_SHADOW, TAG_SHADOW_SIZE);
01808 
01809 //  INT32 Blur = 0;
01810 
01811     Rec.Init();
01812     if (ok) ok = Rec.WriteDOUBLE((double)m_BiasGain.GetBias());
01813     if (ok) ok = Rec.WriteDOUBLE((double)m_BiasGain.GetGain());
01814     if (ok) ok = Rec.WriteDOUBLE(GetDarkness());
01815     if (ok) ok = pFilter->Write(&Rec);
01816 
01817     return ok;
01818 #else
01819     return FALSE;
01820 #endif
01821 }
01822 
01823 
01824 
01825 BOOL NodeShadow::WritePreChildrenWeb(BaseCamelotFilter * pFilter)
01826 {
01827     return WritePreChildrenNative(pFilter);
01828 }
01829 
01830 
01831 
01832 /********************************************************************************************
01833 
01834 >   virtual BOOL NodeShadow::CanWriteChildrenWeb(BaseCamelotFilter* pFilter)
01835 
01836     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01837     Created:    5/12/97
01838     Inputs:     pFilter = ptr to the filter to write to
01839     Returns:    TRUE if children can be written automatically, FALSE otherwise
01840     Purpose:    This allows a node to stop the filter from writing out the child nodes automatically.
01841 
01842                 NodeShadows do NOT save anything out in the current version of Camelot.
01843                 Therefore, none of it's children can be saved out either.
01844 
01845                 For now though, do save the childern
01846 
01847 ********************************************************************************************/
01848 BOOL NodeShadow::CanWriteChildrenWeb(BaseCamelotFilter* pFilter)
01849 {
01850     return TRUE;
01851 }
01852 
01853 
01854 
01855 //------------------------------------------------------------------
01856 // See comments for NodeMoulder::CanWriteChildrenNative(BaseCamelotFilter* pFilter)
01857 BOOL NodeShadow::CanWriteChildrenNative(BaseCamelotFilter* pFilter)
01858 {
01859     return CanWriteChildrenWeb(pFilter);
01860 }
01861 
01862 
01863 
01864 /*******************************************************************************************
01865 
01866 >   void NodeShadow::PreExportRender(RenderRegion* pRegion)
01867 
01868     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01869     Created:    2/2/95
01870     Inputs:     pRegion - points to the export render region
01871     Outputs:    -
01872     Returns:    -
01873     Purpose:    This function is called just before the shape is exported.  It outputs the 
01874                 shapes start token
01875     Errors:     -
01876     SeeAlso:    NodeRegularShape::ExportRender
01877 
01878 ********************************************************************************************/
01879 void NodeShadow::PreExportRender(RenderRegion* pRegion)
01880 {
01881 }
01882 
01883 
01884 
01885 /********************************************************************************************
01886 
01887 >   virtual BOOL NodeShadow::ReleaseCached( BOOL bAndParents = TRUE,
01888                                             BOOL bAndChildren = TRUE,
01889                                             BOOL bSelf = TRUE,
01890                                             BOOL bAndDerived = TRUE)
01891 
01892     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
01893     Created:    02/12/2004
01894     Returns:    TRUE if captured data was cached
01895     Purpose:    Protected Helper function
01896                 Use the CaptureManager to capture the results of rendering, cache them
01897                 and associate them with this Ink node
01898     SeeAlso:    NodeRenderableInk::RenderCached, CaptureCached
01899 
01900 ********************************************************************************************/
01901 
01902 BOOL NodeShadow::ReleaseCached(BOOL bAndParents, BOOL bAndChildren, BOOL bSelf, BOOL bAndDerived)
01903 {
01904     // Don't release cached data if the release request is the result of transformation
01905     // re-rendering because we can transform our cached data!
01906     if (!IsDragged() && bSelf)
01907     {
01908         DeleteCache();
01909     }
01910 
01911     // If we should release our children's caches as well...
01912     if (bAndChildren)
01913     {
01914         Node* pChild = FindFirstChild();
01915         while (pChild)
01916         {
01917             if (pChild->IsBounded())
01918                 ((NodeRenderableBounded*)pChild)->ReleaseCached(FALSE, TRUE, TRUE, TRUE);
01919 
01920             pChild = pChild->FindNext();
01921         }
01922     }
01923 
01924     // If I can't be cached, neither can my parent...
01925     if (bAndParents && FindParent() && FindParent()->IsBounded())
01926         ((NodeRenderableBounded*)FindParent())->ReleaseCached(TRUE, FALSE, TRUE, TRUE);
01927 
01928     return TRUE;
01929 }
01930 
01931 
01932 
01933 
01934 /*******************************************************************************************
01935 >   void NodeShadow::DeleteCache()
01936 
01937     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01938     Created:    4/12/96
01939     Inputs:     -
01940     Outputs:    -
01941     Returns:    -
01942     Purpose:    Deletes all cached shadow paths
01943 ********************************************************************************************/
01944 void NodeShadow::DeleteCache()
01945 {
01946 //  TRACEUSER( "Gerry", _T("DeleteCache\n"));
01947     
01948     m_LastRequestedPixWidth = -1;
01949 
01950     if (m_ShadowBitmap)
01951     {
01952         delete m_ShadowBitmap;
01953         m_ShadowBitmap = NULL;
01954     }
01955     
01956     if (m_pBMPTransFill)
01957     {
01958         delete m_pBMPTransFill;
01959         m_pBMPTransFill = NULL;
01960     }
01961 
01962     if (m_pShadower)
01963     {
01964         delete m_pShadower;
01965         m_pShadower = NULL;
01966     }
01967 }
01968 
01969 
01970 
01971 /*******************************************************************************************
01972 >   void NodeShadow::DeleteAndRefreshCache()
01973 
01974     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01975     Created:    4/12/96
01976     Inputs:     -
01977     Outputs:    -
01978     Returns:    -
01979     Purpose:    Deletes all cached shadow paths and regenerates them
01980 ********************************************************************************************/
01981 void NodeShadow::DeleteAndRefreshCache()
01982 {
01983     DeleteCache();  
01984 }
01985 
01986 
01987 
01988 /********************************************************************************************
01989 >   virtual NodeCompound* NodeShadow::GetParentController() const
01990 
01991     Author:     Peter_Arnold (Xara Group Ltd) <camelotdev@xara.com>
01992     Created:    4/12/96
01993     Inputs:     -
01994     Returns:    Pointer to parent shadow controller (NULL if not found!)
01995     Purpose:    Returns a type correct pointer to the parent shadow controller
01996 ********************************************************************************************/
01997 NodeCompound* NodeShadow::GetParentController() const
01998 {
01999     NodeShadowController* pBob = (NodeShadowController*)FindParent();
02000     if (pBob == NULL || !IS_A(pBob, NodeShadowController))
02001     {
02002 //      ERROR3("NodeShadow::GetParentController; cannot find NodeShadowController parent!");
02003         pBob = NULL;
02004     }
02005 
02006     return pBob;
02007 }
02008 
02009 
02010 
02011 /********************************************************************************************
02012 
02013 >   void NodeShadow::RenderBitmap(RenderRegion* pRender)
02014 
02015     Author:     Mark_Howitt (Xara Group Ltd) <camelotdev@xara.com>
02016     Created:    5/8/98
02017     Inputs:     pRender - The render region to use for rendering
02018     Purpose:    Renders the shadow using the bitmap shadowing system.
02019 
02020 ********************************************************************************************/
02021 void NodeShadow::RenderBitmap(RenderRegion* pRender)
02022 {
02023     // If we don't have a trans fill then try to create one
02024     if (m_pBMPTransFill == NULL)
02025     {
02026 //      TRACEUSER( "Gerry", _T("RenderBitmap# TransFill is NULL\n"));
02027         SetupTransFill();
02028     }
02029 
02030     // quit if we still have no bitmap transp fill.
02031     if (m_pBMPTransFill == NULL)
02032     {
02033 //      TRACEUSER( "Gerry", _T("RenderBitmap# TransFill is still NULL!!! *********\n"));
02034         return;
02035     }
02036 
02037     // if we have no shadow bitmap, then create a dummy one.
02038     if (m_ShadowBitmap == NULL)
02039     {
02040 //      TRACEUSER( "Gerry", _T("RenderBitmap# Creating dummy bitmap!!! ***********\n"));
02041         m_ShadowBitmap = new KernelBitmap(4, 4, 8, 0, TRUE);
02042         ::memset(m_ShadowBitmap->GetBitmapBits(), 0, DIBUtil::ScanlineSize(4, 8) * 4);
02043         m_pBMPTransFill->BitmapRef.SetBitmap(m_ShadowBitmap);
02044     }
02045 
02046     ApplyProfileToShadowBitmap();
02047 
02048     // Get the current Transparency value to use!
02049     UINT32 startTrans = GetTransp();
02050 
02051     // prepare a non-repeating bitmap-transp-fill type.
02052     AttrTranspFillMappingLinear FillMapping;
02053     FillMapping.Value.Repeat = 1;
02054 
02055     // do the bitmap fitting.
02056     DocRect dr(0,0,0,0);
02057     m_Path.GetTrueBoundingRect(&dr);
02058 
02059     DocCoord Centre(dr.lo.x, dr.lo.y);
02060     DocCoord HiX(dr.hi.x, dr.lo.y);
02061     DocCoord HiY(dr.lo.x, dr.hi.y);
02062 
02063 //  m_pBMPTransFill->SetStartPoint(&Centre);
02064 //  m_pBMPTransFill->SetEndPoint(&HiX);
02065 //  m_pBMPTransFill->SetEndPoint2(&HiY);
02066     DocCoord* pCoords = m_Path.GetCoordArray();     // These lines allow cached bitmap to be transformed
02067     m_pBMPTransFill->SetStartPoint(&pCoords[3]);
02068     m_pBMPTransFill->SetEndPoint(&pCoords[2]);
02069     m_pBMPTransFill->SetEndPoint2(&pCoords[0]);
02070 
02071     m_pBMPTransFill->SetStartTransp(&startTrans);
02072 
02073     // ok, do all the rendering.
02074     pRender->SaveContext();
02075 
02076     pRender->SetLineColour(COLOUR_NONE);
02077     m_pBMPTransFill->Render(pRender);
02078     FillMapping.Render(pRender);
02079 
02080 //  DocRect BoundsRect = m_Path.GetBoundingRect();
02081 //  TRACEUSER( "Gerry", _T("Rendering shadow = (%d, %d) - (%d, %d)\n"), BoundsRect.lox, BoundsRect.loy, BoundsRect.hix, BoundsRect.hiy);
02082 
02083     pRender->DrawPath(&m_Path);
02084 
02085     pRender->RestoreContext();
02086 }
02087 
02088 
02089 
02090 /********************************************************************************************
02091 
02092 >   BOOL NodeShadow::GenerateShadow()
02093 
02094     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
02095     Created:    16/9/98
02096     Inputs:     
02097     Purpose:    Can be called externally to set up this node with its shadow in the correct
02098                 place
02099 
02100 ********************************************************************************************/
02101 BOOL NodeShadow::GenerateShadow()
02102 {
02103     // find my parent & test to see if I've got anything to shadow
02104     NodeShadowController * pControl = (NodeShadowController *)FindParent();
02105 
02106     if (pControl)
02107     {
02108         if (pControl->GetInsideBoundingRect().IsEmpty())
02109         {
02110             return FALSE;
02111         }
02112     }
02113     else
02114     {
02115         return FALSE;
02116     }
02117 
02118     // ensure a render
02119 
02120     m_bHaveTransformed = TRUE;
02121 
02122     m_RenderBitmaps    = TRUE; 
02123 
02124     // regen the shape path & everything !!
02125     SetupTransFill();
02126 
02127     if (m_ShadowBitmap)
02128     {
02129         delete m_ShadowBitmap;
02130         m_ShadowBitmap = NULL;
02131     }
02132 
02133     ReleaseCached();
02134 
02135     // set these two to false, as we've already generated the shadow
02136     m_RenderBitmaps = FALSE;
02137     m_bHaveTransformed = FALSE;
02138 
02139     m_Path.ClearPath();
02140 
02141     if (pControl != NULL)
02142     {
02143         pControl->InvalidateBoundingRect(TRUE);
02144         InvalidateBoundingRect();
02145     }
02146 
02147     return TRUE;
02148 }
02149 
02150 
02151 
02152 /********************************************************************************************
02153 
02154 >   BOOL NodeShadow::GenerateShadowForBlends(List * pList, RenderRegion * pRegion)
02155 
02156     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
02157     Created:    10/3/2000
02158     Inputs:     List of SumAllPathsElems (see blndhelp.h)
02159     Purpose:    Creates the shadow using the given list
02160                 Can take place inside of a render loop
02161 
02162 ********************************************************************************************/
02163 BOOL NodeShadow::GenerateShadowForBlends(List * pList, RenderRegion * pRegion)
02164 {
02165     if (pList == NULL)
02166         return FALSE;
02167     else
02168         return RenderBitmapForDisplay(pRegion, pList);
02169 }
02170 
02171 
02172 
02173 /********************************************************************************************
02174 
02175 >   BOOL NodeShadow::GenerateShadowBitmap(double pixBlurDiameter)
02176 
02177     Author:     Mark_Howitt (Xara Group Ltd) <camelotdev@xara.com>
02178     Created:    16/9/98
02179     Inputs:     INT32 Blurr : Current value of the blurr setting
02180     Returns:    TRUE for Ok .. and FALSE for Not ok!
02181     Purpose:    Generates a Bitmap Shadow from the current Selection Bitmap with the current
02182                 Blurr setting.
02183 
02184 ********************************************************************************************/
02185 BOOL NodeShadow::GenerateShadowBitmap(KernelBitmap* pSilhouetteBmp, double pixBlurDiameter)
02186 {
02187     if (pSilhouetteBmp == NULL)
02188         return FALSE;
02189 
02190     KernelBitmap * p8BitDIB = NULL;
02191 
02192     NodeShadowController * pController = (NodeShadowController*)GetParentController();
02193     if (pController == NULL)
02194         return FALSE;
02195 
02196     if(m_RenderBitmaps || !m_ShadowBitmap || !m_pBMPTransFill)
02197     {
02198         // If we already have a shadow bitmap, get rid of it as it`s outa data!
02199         if(m_ShadowBitmap != NULL)
02200         {
02201             delete m_ShadowBitmap;
02202             m_ShadowBitmap = NULL;
02203         }
02204         
02205         // Set up a new kernel shadow bitmap with the selection bitmap as the reference to shadow with
02206         if (!m_pShadower)
02207         {
02208             m_pShadower = new CBitmapShadow;
02209 
02210             if (!m_pShadower)
02211             {
02212                 ERROR3("Can't create shadower");
02213                 return FALSE;
02214             }
02215         }
02216 
02217         INT32 i = 0 ;
02218         
02219         CNativeSize     ShadowSize( pSilhouetteBmp->GetWidth(), pSilhouetteBmp->GetHeight() );
02220 
02221         // create the shadow
02222         switch (pController->GetShadowType())
02223         {
02224         case SHADOWTYPE_WALL:
02225             {
02226                 m_pShadower->CreateShadow(TRUE,
02227                                             0,
02228                                             0,
02229                                             pixBlurDiameter,
02230                                             1.0,
02231                                             0,
02232                                             0,
02233                                             (UINT32*)pSilhouetteBmp->GetBitmapBits(),
02234                                             ShadowSize);
02235             }
02236             break;
02237 
02238         case SHADOWTYPE_FLOOR:
02239             {
02240                 m_pShadower->CreateShadow(FALSE,
02241                                             pController->GetFloorShadowHeight(),
02242                                             pController->GetFloorShadowAngle() * 180.0 / PI,
02243                                             pixBlurDiameter,
02244                                             1.0,
02245                                             0,
02246                                             0,
02247                                             (UINT32*)pSilhouetteBmp->GetBitmapBits(),
02248                                             ShadowSize);
02249                 
02250                 INT32 YOffset = 0;
02251                 m_pShadower->GetShadowOffset(&m_BitmapXOffset, &YOffset);
02252             }
02253             break;
02254 
02255         case SHADOWTYPE_GLOW:
02256             {
02257                 m_pShadower->CreateShadow(TRUE,
02258                                             0,
02259                                             0,
02260                                             pixBlurDiameter,
02261                                             1.0,
02262                                             0,
02263                                             0,
02264                                             (UINT32*)pSilhouetteBmp->GetBitmapBits(),
02265                                             ShadowSize);
02266             }
02267             break;
02268 
02269         case SHADOWTYPE_FEATHER:
02270             {
02271                 ERROR3("Unimplemented!");   // TODO:
02272             }
02273             break;
02274 
02275         default:
02276             ERROR3("Unknown Shadow type");
02277         }
02278 
02279         INT32 BWidth = m_pShadower->GetWidth();
02280         INT32 BHeight = m_pShadower->GetHeight();
02281         
02282         // floor shadows are generated as full 32 bit dibs, whereas wall shadows are
02283         // generated as 8 bit dibs
02284         if (m_pShadower->GetDepth() == 32)
02285         {
02286             m_ShadowBitmap = new KernelBitmap(BWidth, BHeight, 24, 96, TRUE);
02287 
02288             if (!m_ShadowBitmap)
02289             {
02290                 ERROR(_R(IDE_NOMORE_MEMORY), FALSE);
02291     
02292             }
02293             
02294             // change the shadow bitmap from being a 32 bit-DIB to a 24 bit-DIB
02295             BYTE * SrcPtr = ((LPBYTE)m_pShadower->GetBytes()) + 3;
02296             BYTE * DestPtr = (LPBYTE)m_ShadowBitmap->GetBitmapBits();       
02297             
02298             INT32 XSize = DIBUtil::ScanlineSize(BWidth, 24);
02299             INT32 XInc  = XSize - (BWidth * 3);
02300             
02301             INT32 XPos = 0;
02302             
02303             INT32 size = BWidth * BHeight;
02304             for (i = 0 ; i < size; i++)
02305             {
02306                 *(DestPtr + 0) = *(SrcPtr);
02307                 *(DestPtr + 1) = *(SrcPtr);
02308                 *(DestPtr + 2) = *(SrcPtr);
02309                 
02310                 XPos ++;
02311                 if (XPos < BWidth)
02312                 {
02313                     DestPtr += 3;
02314                 }
02315                 else
02316                 {
02317                     XPos = 0;
02318                     DestPtr += 3 + XInc;
02319                 }
02320                 
02321                 SrcPtr += 4;
02322             }
02323             
02324             // change it into an 8-bit DIB, if not printing
02325             if (!pController->IsPrinting())
02326             {   
02327                 if (Create8BitBitmap(m_ShadowBitmap, &p8BitDIB))
02328                 {
02329                     delete m_ShadowBitmap;
02330                     m_ShadowBitmap = p8BitDIB;
02331                 }
02332             }
02333         }
02334         else if (m_pShadower->GetDepth() == 8)
02335         {
02336             // the shadowed bitmap is already 8 bit, therefore just make it into a kernel bitmap
02337             m_ShadowBitmap = new KernelBitmap(BWidth, BHeight, 8, 96, TRUE);
02338 
02339             if (!m_ShadowBitmap)
02340             {
02341                 ERROR3("Can't create shadow bitmap");
02342                 return FALSE;
02343             }
02344 
02345             RGBQUAD * pQuad = NULL;
02346 
02347             pQuad = m_ShadowBitmap->GetPaletteForBitmap();
02348 
02349             // make the palette
02350             for (INT32 i = 0 ; i <= 255; i++)
02351             {
02352                 pQuad[i].rgbRed = i;
02353                 pQuad[i].rgbBlue = i;
02354                 pQuad[i].rgbGreen = i;
02355             }
02356 
02357             // copy the bits over
02358             memcpy(m_ShadowBitmap->GetBitmapBits(), m_pShadower->GetBytes(),
02359                 DIBUtil::ScanlineSize(BWidth, 8) * BHeight);
02360         }
02361         else
02362         {
02363             ERROR3("Shadower has an unrecognised bmp depth!");
02364         }
02365 
02366         // delete the shadower
02367         delete m_pShadower;
02368         m_pShadower = NULL;
02369     
02370         ERROR2IF(m_ShadowBitmap == NULL,FALSE,"Failed to create a shadow bitmap for shadowing!!!!");
02371 
02372         // DMc
02373         // New Trans Bitmap Fill Attributes
02374         // ah, but has the bitmap fill been initialised ?
02375         if (!m_pBMPTransFill)
02376         {
02377             SetupTransFill();
02378         }
02379 
02380         m_pBMPTransFill->BitmapRef.SetBitmap(m_ShadowBitmap);
02381 
02382         m_bHaveTransformed = TRUE;
02383     }
02384 
02385     return TRUE;
02386 }
02387 
02388 
02389 
02390 /********************************************************************************************
02391 
02392 >   BOOL NodeShadow::SetupTransFill();
02393 
02394     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
02395     Created:    20/4/99
02396     Inputs:     
02397     Returns:    TRUE = success, FALSE = fail
02398     Purpose:    Sets up the transparency fill for this node
02399 
02400 ********************************************************************************************/
02401 BOOL NodeShadow::SetupTransFill()
02402 {
02403     DeleteCache();
02404 
02405     m_pBMPTransFill = new BitmapTranspFillAttribute;
02406 
02407     UINT32 EndTransp = 255;
02408     
02409     if(m_pBMPTransFill == NULL)
02410     {
02411         ERROR3("Arrhhh! Didn`t get an m_pBMPTransFill ptr for the shadow!");
02412     }
02413     else
02414     {
02415         // Always have an end transparency of 100%
02416         m_pBMPTransFill->SetEndTransp(&EndTransp);
02417         // Always make the shadow bitmap non repeating!
02418         m_pBMPTransFill->SetTesselation(RT_Simple);
02419     }
02420 
02421     return TRUE;
02422 }
02423 
02424 
02425 
02426 /********************************************************************************************
02427 
02428 >   void NodeShadow::UpdateAfterWallOffset()
02429 
02430     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
02431     Created:    20/06/2000
02432 
02433     Outputs:    This NodeShadow may be translated so it is offset as defined by its parent
02434                 NodeShdaowController. Its bounding box will also be invalidated and
02435                 recalculated.
02436 
02437     Purpose:    Updates our bounds and shadow path after our NodeShadowController parent
02438                 has been told to move its wall shadow to a new offset.
02439 
02440                 After a wall-shadow offset, the shadow needn't be regenerated, but simply
02441                 translated. This method performs any necessary translation, so that the
02442                 wall shadow is where the parent NodeShadowController says it should be.
02443 
02444     SeeAlso:    NodeShadowController::SetWallShadowOffset();
02445 
02446 ********************************************************************************************/
02447 void NodeShadow::UpdateAfterWallOffset()
02448 {
02449     // update our path for the shadow bitmap-transparency.
02450     if (m_LastActualPixWidth > 0)
02451     {
02452         NodeShadowController* pControl = (NodeShadowController*)GetParentController();
02453         if (pControl != NULL)
02454         {
02455             m_Path.ClearPath();
02456             m_Path.CloneFrom(m_NonTranslatedPath);
02457             m_Path.IsFilled = TRUE;
02458             m_Path.Translate(pControl->GetWallShadowOffset());
02459         }
02460     }
02461     else
02462     {
02463 // DEBUG:
02464 //      TRACEUSER( "Karim", _T("NodeShadow::UpdateAfterWallOffset; Couldn't create shadow path!\n"));
02465     }
02466 
02467     // our bounds will likely be invalid after recalculating the shadow fill-path.
02468     InvalidateBoundingRect();
02469 }
02470 
02471 
02472 
02473 /********************************************************************************************
02474 
02475 >   BOOL NodeShadow::PostImport()
02476 
02477     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
02478     Created:    07/02/2001
02479 
02480     Purpose:    Called immediately after this NodeShadow and all its children have been
02481                 imported & installed in the tree, to ensure correct import of shadows
02482                 from the old Xara X format:
02483 
02484                 1. Overwrite our shadow transparency, from that of any non-default
02485                     attr-transp applied to us.
02486                 2. Delete all our attribute-children which we do not require.
02487 
02488 ********************************************************************************************/
02489 BOOL NodeShadow::PostImport()
02490 {
02491     NodeAttribute* pAttrTransp;
02492     if (FindAppliedAttribute(CC_RUNTIME_CLASS(AttrTranspFillGeometry), &pAttrTransp) &&
02493         !pAttrTransp->IsADefaultAttr())
02494     {
02495         SetTransp( * ((AttrFillGeometry*)pAttrTransp)->GetStartTransp() );
02496     }
02497 
02498     Node* pThisKid = FindFirstChild();
02499     Node* pNextKid = NULL;
02500     while (pThisKid != NULL)
02501     {
02502         pNextKid = pThisKid->FindNext();
02503 
02504         if (pThisKid->IsAnAttribute() &&
02505             !RequiresAttrib((NodeAttribute*)pThisKid) )
02506         {
02507             pThisKid->CascadeDelete();
02508             delete pThisKid;
02509         }
02510 
02511         pThisKid = pNextKid;
02512     }
02513 
02514     return TRUE;
02515 }
02516 
02517 
02518 
02519 /********************************************************************************************
02520 
02521 >   BOOL NodeShadow::PostDuplicate(UndoableOperation* pOp)
02522 
02523 
02524     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
02525     Created:    16/4/99
02526     Inputs:     
02527     Returns:    True if successful
02528     Purpose:    Does post-import stuff
02529 
02530 ********************************************************************************************/
02531 BOOL NodeShadow::PostDuplicate(UndoableOperation* pOp)
02532 {
02533     // force a regeneration of the shadow
02534     m_bAmCopying = FALSE;
02535 
02536     // GenerateShadow();
02537     NodeRenderableInk::PostDuplicate(pOp);
02538 
02539     IsBoundingRectValid = FALSE;
02540     DocRect dr = GetBoundingRect(FALSE, FALSE);
02541 
02542     return TRUE;
02543 }
02544 
02545 
02546 
02547 /********************************************************************************************
02548 
02549 >   BOOL NodeShadow::Create8BitBitmap(KernelBitmap * pSrcBitmap, KernelBitmap * pDestBitmap);
02550 
02551 
02552     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
02553     Created:    16/4/99
02554     Inputs:     The source 24-bit greyscale bitmap
02555     Returns:    True if successful
02556     Purpose:    Returns an 8-bit bitmap out of the 24-bit greyscale bitmap
02557 
02558 ********************************************************************************************/
02559 BOOL NodeShadow::Create8BitBitmap(KernelBitmap * pSrcBitmap, KernelBitmap ** ppDestBitmap)
02560 {
02561     if (!pSrcBitmap || !ppDestBitmap)
02562     {
02563         ERROR3("No source or destination bitmap defined");
02564         return FALSE;
02565     }
02566 
02567     if (pSrcBitmap->GetBPP() != 24)
02568     {
02569         ERROR3("Source bitmap not 24 bit");
02570         return FALSE;
02571     }
02572 
02573     UINT32 Width = pSrcBitmap->GetWidth();
02574     UINT32 Height = pSrcBitmap->GetHeight();
02575 
02576     // make the width a factor of 4
02577     
02578     *ppDestBitmap = new KernelBitmap(Width, Height, 8, pSrcBitmap->GetHorizontalDPI(), TRUE);
02579 
02580     if (!ppDestBitmap)
02581         return FALSE;
02582 
02583     // ok, we've created both bitmaps now, so fill their bits !
02584     BYTE * pDest = (*ppDestBitmap)->GetActualBitmap()->GetBitmapBits();
02585     BYTE * pStartDest = pDest;
02586     
02587     BYTE * pSrc  = pSrcBitmap->GetActualBitmap()->GetBitmapBits();
02588     BYTE * pStartSrc = pSrc;
02589 
02590     INT32 size = pSrcBitmap->GetWidth() * pSrcBitmap->GetHeight();
02591 
02592     UINT32 posX = 0;
02593     
02594     // get gavin's scanline size for 8-bit bitmaps
02595     UINT32 ScanlineSize24 = DIBUtil::ScanlineSize(Width, 24);
02596     UINT32 ScanlineSize8 = DIBUtil::ScanlineSize(Width, 8);
02597 
02598     // memset the destination so it's white
02599     memset(pDest, 0xff, ScanlineSize8 * Height);
02600 
02601     while (size > 0)
02602     {
02603         *pDest = *pSrc;
02604 
02605         pSrc += 3;
02606         pDest += 1;
02607 
02608         posX ++;
02609 
02610         if (posX >= Width)
02611         {
02612             pStartSrc += ScanlineSize24;
02613             pStartDest  += ScanlineSize8;
02614 
02615             pSrc = pStartSrc;
02616             pDest = pStartDest;
02617 
02618             posX = 0;
02619         }
02620 
02621         size --;
02622     }
02623 
02624     // and do their palettes
02625     LPRGBQUAD pTranspPalette = (*ppDestBitmap)->GetPaletteForBitmap();
02626 
02627     for (INT32 i = 0 ; i < 256; i++)
02628     {
02629         pTranspPalette->rgbBlue = (BYTE)i;
02630         pTranspPalette->rgbRed = (BYTE)i;
02631         pTranspPalette->rgbGreen = (BYTE)i;
02632         pTranspPalette->rgbReserved = 0x00;
02633 
02634         pTranspPalette ++;
02635     }
02636 
02637     return TRUE;
02638 }
02639 
02640 
02641 
02642 /********************************************************************************************
02643 
02644 >   void NodeShadow::CreateBitmapPath(  const DocRect& drInkForShadowing,
02645                                         const double PixelWidth,
02646                                         const double pixBlurDiameter )
02647     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
02648     Created:    15 September 2000
02649     Inputs:     drInkForShadowing   the bounding rect of the object to be shadowed.
02650                 PixelWidth          the width of an onscreen pixel, in millipoints.
02651                 pixBlurDiameter     the exact penumbra width, in pixels.
02652 
02653     Outputs:    m_NonTranslatedPath contains the path to render the shadow bmp into, but
02654                                     is centred on the object.
02655                 m_Path              contains the true path to render the shadow bmp into,
02656                                     ie m_NonTranslatedPath with any wall offset applied.
02657 
02658     Purpose:    Create the path into which we will render our shadow bitmap:
02659 
02660                 1.  Use PixelWidth together with the dimensions of our stored shadow bitmap,
02661                     to work out the exact dimensions of the bitmap onscreen, in millipoints.
02662                     If we get these dimensions wrong, then the bitmap will be slightly
02663                     squashed or stretched when it is rendered.
02664 
02665                 2.  Calculate the shadow path, using drInkForShadowing to determine its
02666                     location onscreen, and the bounds calculated above to determine its size.
02667 
02668     Notes:  +   Can cope with fractional values for PixelWidth, but RenderBitmapForDisplay
02669                 needs to be modified to send these more accurate values through. To see the
02670                 problem this would solve, zoom to 25601%, create and examine a wall or glow
02671                 shadow with no blur.
02672 
02673             +   This method could be made more robust, so that if an invalid PixelWidth is
02674                 passed in, or our bitmap is NULL, it will estimate a shadow path, based only
02675                 on drInkForShadowing.
02676 
02677 ********************************************************************************************/
02678 void NodeShadow::CreateBitmapPath(  const DocRect& drInkForShadowing,
02679                                     const double PixelWidth,
02680                                     const double pixBlurDiameter )
02681 {
02682     // clear our current shadow path.
02683     m_Path.ClearPath();
02684     m_NonTranslatedPath.ClearPath();
02685 
02686     // get a pointer to my controller node - if there is none, then exit.
02687     NodeShadowController* pControl = (NodeShadowController*)GetParentController();
02688     if (pControl == NULL)
02689     {
02690         ERROR3("NodeShadow::CreateBitmapPath; No parent controller!");
02691         return;
02692     }
02693 
02694     DocRect dr = drInkForShadowing;
02695 
02696     MILLIPOINT Width = 0;
02697     MILLIPOINT Height = 0;
02698 
02699 //  double LowWidth = 0;
02700 //  double LowHeight = 0;
02701 //  double HighWidth = 0;
02702 //  double HighHeight = 0;
02703 
02704     DocCoord dc1(0,0);
02705     DocCoord dc2(0,0);
02706     DocCoord dc3(0,0);
02707     DocCoord dc4(0,0);
02708     DocCoord Centre(0,0);
02709 
02710     // get the width and height of the bitmap in document coordinates.
02711     if (m_ShadowBitmap != NULL)
02712     {
02713         Width   = (MILLIPOINT)(0.5 + (PixelWidth * m_ShadowBitmap->GetWidth()));
02714         Height  = (MILLIPOINT)(0.5 + (PixelWidth * m_ShadowBitmap->GetHeight()));
02715     }
02716     else
02717     {
02718         Width   = dr.Width();
02719         Height  = dr.Height();
02720 
02721         if (pControl->GetShadowType() == SHADOWTYPE_GLOW)
02722         {
02723             MILLIPOINT ExtraGlow = pControl->GetPenumbraWidth() + pControl->GetGlowWidth();
02724             Width   += ExtraGlow;
02725             Height  += ExtraGlow;
02726         }
02727     }
02728 
02729     // different behaviours for different types of shadow.
02730     switch (pControl->GetShadowType())
02731     {
02732         case SHADOWTYPE_GLOW:
02733         case SHADOWTYPE_WALL:
02734         case SHADOWTYPE_FEATHER:
02735         {
02736 /*
02737  *  Karim 04/10/2000
02738  *  Shadows are now applied from the bottom left, as it is much easier
02739  *  to understand pixel-alignment issues this way!
02740  *
02741             // Apply from the centre
02742             Centre = dr.Centre();
02743 
02744             // need to get the offset of the centre left & right in order to make
02745             // sure the pixel size of the bitmap in document coordinates is exactly right
02746             LowWidth = floor(0.5 * Width);
02747             LowHeight = floor(0.5 * Height);
02748 
02749             // calculate the rect for the bitmap
02750             dr.lo.x = Centre.x - (MILLIPOINT)LowWidth;
02751             dr.lo.y = Centre.y - (MILLIPOINT)LowHeight;
02752 */
02753             MILLIPOINT DeltaBmpSize = CBitmapShadow::GetWholePixelBlurDiameter(pixBlurDiameter) - 1;
02754             MILLIPOINT HalfBlurWidth = MILLIPOINT((DeltaBmpSize < 0) ? 0 : PixelWidth * (DeltaBmpSize / 2));
02755 
02756             dr.lo.x -= HalfBlurWidth;
02757             dr.lo.y -= HalfBlurWidth;
02758 
02759             dr.hi.x = dr.lo.x + Width;
02760             dr.hi.y = dr.lo.y + Height;
02761         }
02762         break;
02763 
02764         case SHADOWTYPE_FLOOR:
02765         {
02766             // slight bug fix
02767             dr.lo.x += (MILLIPOINT)(0.5 + (PixelWidth * m_BitmapXOffset));
02768             dr.lo.y += (MILLIPOINT)PixelWidth;
02769 
02770             dr.hi.x = dr.lo.x + Width;
02771             dr.hi.y = dr.lo.y + Height;
02772         }
02773         break;
02774 
02775         default:
02776             ERROR3("NodeShadow::CreateBitmapPath; Unrecognised shadow type!");
02777             break;
02778     }
02779 
02780     m_NonTranslatedPath.CreatePathFromDocRect(&dr);
02781     m_Path.CloneFrom(m_NonTranslatedPath);
02782     m_Path.IsFilled = TRUE;
02783     if (pControl->GetShadowType() == SHADOWTYPE_WALL)
02784         m_Path.Translate(pControl->GetWallShadowOffset());
02785 
02786     m_Path.GetTrueBoundingRect(&m_SelectedRect);
02787 }
02788 
02789 
02790 
02791 /********************************************************************************************
02792 
02793 >   virtual BOOL NodeShadow::NeedsParent(Node* pClassNode) const
02794 
02795 
02796     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
02797     Created:    7/5/99
02798     Inputs:     A node to do the class checking on
02799     Returns:    
02800     Purpose:    Do we need a parent of the same class as the given node ???
02801     See also:   NodeCompound::OnChildChange
02802 
02803 ********************************************************************************************/
02804 BOOL NodeShadow::NeedsParent(Node* pClassNode) const
02805 {
02806     if (!pClassNode)
02807         return TRUE;
02808     
02809     if (pClassNode->IsKindOf(CC_RUNTIME_CLASS(NodeShadowController)))
02810         return TRUE;
02811 
02812     return FALSE;
02813 }
02814 
02815 
02816 
02817 /********************************************************************************************
02818 
02819 >   virtual BOOL NodeShadow::AllowOp(ObjChangeParam *pParam, BOOL SetOpPermissionState,
02820                                                              BOOL DoPreTriggerEdit)
02821 
02822     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>; Karim 20/01/2000
02823     Created:    20/11/96
02824     Inputs:     pParam                  describes the way an op wants to change the node
02825                 SetOpPermissionState    if TRUE the OpPermission of nodes should be set
02826                 DoPreTriggerEdit        if TRUE then NameGallery::PreTriggerEdit is called.
02827                                         *Must* be TRUE if the calling Op may make any nodes
02828                                         change their bounds, eg move, line width, cut.
02829                                         Use TRUE if unsure.
02830     Purpose:    
02831     SeeAlso:    
02832 
02833 ********************************************************************************************/
02834 BOOL NodeShadow::AllowOp(ObjChangeParam *pParam, BOOL SetOpPermissionState,
02835                                                  BOOL DoPreTriggerEdit)
02836 {
02837     TRACE( _T("Warning - NodeShadow::AllowOp called\n") );
02838     ERROR2IF(pParam == NULL, FALSE, "NodeShadowController::AllowOp(); NULL input(s) !!");
02839 
02840     // clean out the calling-child ptr, so it doesn't get passed around unintentionally.
02841     pParam->SetCallingChild(NULL);
02842 
02843     // A flag for whether or not we allow the Op.
02844     BOOL allowed = TRUE;
02845 
02846     UndoableOperation* pOp = pParam->GetOpPointer();
02847 
02848     // See if our parent allows this Op.
02849     if (allowed && Parent != NULL && pParam->GetDirection() != OBJCHANGE_CALLEDBYPARENT)
02850     {
02851         ObjChangeDirection OldDirection = pParam->GetDirection();
02852         pParam->SetCallingChild(this);
02853         pParam->SetDirection(OBJCHANGE_CALLEDBYCHILD);
02854         allowed = Parent->AllowOp(pParam, SetOpPermissionState, DoPreTriggerEdit);
02855         pParam->SetDirection(OldDirection);
02856     }
02857 
02858     // If our parent allowed the Op, then see what we think.
02859     if (allowed)
02860     {
02861         if (pOp)
02862         {
02863             // Shadows can't be moulded.
02864             if ((pOp->IS_KIND_OF(OpCreateNewMould))              ||
02865                  pOp->IsKindOf(CC_RUNTIME_CLASS(OpPasteEnvelope)) ||
02866                  pOp->IsKindOf(CC_RUNTIME_CLASS(OpPastePerspective)))
02867             {
02868                 allowed = FALSE;
02869             }
02870 
02871             // Shadows can't be feathered.
02872             else if (pParam->GetChangeFlags().Attribute)
02873                 if (pOp->IS_KIND_OF(OpChangeFeatherSize))
02874                     allowed = FALSE;
02875         }
02876     }
02877 
02878     // if necessary, set permissions for OnChildChange.
02879     if (SetOpPermissionState)
02880         SetOpPermission(allowed ? PERMISSION_ALLOWED : PERMISSION_DENIED, TRUE);
02881         
02882     // If we're ok so far and were asked to do a PreTriggerEdit, then
02883     // determine whether the Op may change the bounds of some nodes.
02884     // If it may, then call NameGallery::PreTriggerEdit.
02885     if (allowed && DoPreTriggerEdit)
02886     {
02887         // if the Op is non-NULL then query its MayChangeNodeBounds() method.
02888         UndoableOperation* pChangeOp = pParam->GetOpPointer();
02889         if (pChangeOp != NULL && pChangeOp->MayChangeNodeBounds())
02890         {
02891             if (NameGallery::Instance())
02892                 allowed = NameGallery::Instance()->PreTriggerEdit(pChangeOp, pParam, this);
02893         }
02894     }
02895 
02896     return allowed;
02897 }
02898 
02899 
02900 
02901 /********************************************************************************************
02902 
02903 >   void NodeShadow::SetBiasGain(CProfileBiasGain &gain)
02904 
02905     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
02906     Created:    20/11/96
02907     Inputs:     
02908     Purpose:    Sets the profile for the shadow node
02909     SeeAlso:    
02910 
02911 ********************************************************************************************/
02912 void NodeShadow::SetBiasGain(CProfileBiasGain &gain)
02913 {
02914     AFp BiasValue = gain.GetBias();
02915     AFp GainValue = gain.GetGain();
02916 
02917     m_BiasGain.SetBias(BiasValue);
02918     m_BiasGain.SetGain(GainValue);
02919 }
02920 
02921 
02922 
02923 /********************************************************************************************
02924 
02925 >   CProfileBiasGain &NodeShadow::GetBiasGain()
02926 
02927     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
02928     Created:    20/11/96
02929     Inputs:     
02930     Purpose:    Gets the profile for the shadow node
02931     SeeAlso:    
02932 
02933 ********************************************************************************************/
02934 CProfileBiasGain &NodeShadow::GetBiasGain()
02935 {
02936     static CProfileBiasGain Profile;
02937     
02938     AFp BiasValue = m_BiasGain.GetBias();
02939     AFp GainValue = m_BiasGain.GetGain();
02940 
02941     Profile.SetBias(BiasValue);
02942     Profile.SetGain(GainValue);
02943 
02944     return Profile;
02945 }
02946 
02947 CProfileBiasGain* NodeShadow::GetBiasGainPtr()
02948 {
02949     return (&m_BiasGain);
02950 }
02951 
02952 
02953 
02954 /********************************************************************************************
02955 
02956 >   virtual DocRect NodeShadow::ValidateExtend(const ExtendParams& ExtParams)
02957 
02958     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
02959     Created:    06/12/1999
02960     Inputs:     ExtParams       description parameters for the extension.
02961     Outputs:    
02962     Returns:    TRUE if extending this Nodewill be a reversible operation,
02963                 FALSE otherwise.
02964     Purpose:    Tests the reversibility of an Extend operation applied to this node.
02965 
02966                 A NodeShadow cannot itself extend, so instead it asks its parent controller
02967                 to extend for it. Infinite recursion does not occur, as the controller node
02968                 ignores its child node, this NodeShadow.
02969     Errors:     In debug builds, ERROR3 if this Node has no NodeShadowController,
02970                 in release, we return TRUE.
02971     See also:   IsTypeExtendible(), Extend().
02972 
02973 ********************************************************************************************/
02974 DocRect NodeShadow::ValidateExtend(const ExtendParams& ExtParams)
02975 {
02976     Node* pBob = GetParentController();
02977     if (pBob == NULL)
02978     {
02979         ERROR3("NodeShadow::ValidateExtend- no controller Node found!");
02980         return DocRect(INT32_MAX, INT32_MAX, INT32_MAX, INT32_MAX);
02981     }
02982     else
02983     {
02984         return pBob->ValidateExtend(ExtParams);
02985     }
02986 }
02987 
02988 
02989 
02990 /********************************************************************************************
02991 
02992 >   virtual void NodeShadow::Extend(const ExtendParams& ExtParams)
02993 
02994     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
02995     Created:    06/12/1999
02996     Inputs:     ExtParams       description parameters for the extension.
02997     Outputs:    Some of the child nodes of this ShadowNode's NodeShadowController may have
02998                 their dimensions altered.
02999     Returns:    
03000     Purpose:    Perform an Extend operation on this Node, and its children if appropriate.
03001 
03002                 A NodeShadow cannot itself extend, so instead it asks its parent controller
03003                 to extend for it. Infinite recursion does not occur, as the controller node
03004                 ignores its child node, this NodeShadow.
03005     Errors:     In debug builds, ERROR3 if this Node has no NodeShadowController,
03006                 in release, we do nothing.
03007     See also:   
03008 
03009 ********************************************************************************************/
03010 void NodeShadow::Extend(const ExtendParams& ExtParams)
03011 {
03012     Node* pBob = GetParentController();
03013     if (pBob == NULL)
03014     {
03015         ERROR3("NodeShadow::ValidateExtend- no controller Node found!");
03016     }
03017     else
03018     {
03019         pBob->Extend(ExtParams);
03020     }
03021 
03022     return;
03023 }
03024 
03025 
03026 
03027 /********************************************************************************************
03028 
03029 >   virtual BOOL NodeShadow::OnNodePopUp(Spread* pSpread, DocCoord PointerPos, ContextMenu* pMenu)
03030 
03031     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
03032     Created:    7/2/2000
03033     Inputs:     pSpread     The spread in which things are happening
03034                 PointerPos  The Location of the mouse pointer at the time of the click
03035                 pMenu       The menu to which items should be added
03036     Returns:    BOOL - TRUE if the node claims the click as its own and FALSE if it is
03037                 not interested in the click
03038     Purpose:    Allows the shadow to respond to the click
03039 
03040 ********************************************************************************************/
03041 BOOL NodeShadow::OnNodePopUp(Spread* pSpread, DocCoord PointerPos, ContextMenu* pMenu)
03042 {
03043     BOOL ok = TRUE;
03044 #ifndef NO_ADVANCED_TOOLS   
03045     ok = ok && pMenu->BuildCommand(TOOL_OPTOKEN_SOFTSHADOW, TRUE);
03046 #endif
03047     return ok;
03048 }
03049 
03050 
03051 
03052 /********************************************************************************************
03053 
03054 >   virtual INT32 NodeShadow::EstimateNodeComplexity (OpParam* details)
03055 
03056     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
03057     Created:    6/09/2000
03058 
03059     Inputs:     details     any data that should be used for the calculation
03060 
03061     Outputs:    -
03062 
03063     Returns:    an estimate of the nodes complexity
03064 
03065     Purpose:    This function estimates a complexity value for the node.  The complexity
03066                 value is based upon the total length of all paths in the node.
03067 
03068     See Also:   OpBlendNodes::DeterminBlendObjectsProcessorHit ()
03069 
03070 ********************************************************************************************/
03071 INT32 NodeShadow::EstimateNodeComplexity (OpParam* details)
03072 {
03073     return (m_Path.GetUsedSlots ());
03074 }
03075 
03076 
03077 
03078 /********************************************************************************************
03079 
03080 >   virtual BOOL NodeShadow::CanAttrBeAppliedToMe(CCRuntimeClass* pAttribClass)
03081 
03082     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
03083     Created:    22/08/2000
03084     Inputs:     pAttribClass    the attr type to test.
03085     Returns:    FALSE if pAttribClass is a brush attr,
03086                 TRUE otherwise.
03087 
03088     Purpose:    Determine whether the given attr type can be applied directly to us.
03089                 Any of those attrs which we require can be directly applied to us.
03090 
03091     Errors:     returns FALSE if pAttribClass is NULL.
03092 
03093 ********************************************************************************************/
03094 BOOL NodeShadow::CanAttrBeAppliedToMe(CCRuntimeClass* pAttribClass)
03095 {
03096     // For NodeShadow, this fn does the same thing as RequiresAttrib().
03097     return RequiresAttrib(pAttribClass);
03098 }
03099 
03100 
03101 
03102 /********************************************************************************************
03103 
03104 >   void NodeShadow::SetDarkness(double Darkness)
03105 
03106     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
03107     Created:    13/02/2001
03108     Purpose:    Set shadow darkness, from 0.0 (transparent) to 1.0 (opaque).
03109     Errors:     ERROR3 if input value is out of range.
03110 
03111 ********************************************************************************************/
03112 void NodeShadow::SetDarkness(double Darkness)
03113 {
03114     ERROR3IF(Darkness < 0.0 || Darkness > 1.0, "NodeShadow::SetDarkness; invalid input!");
03115     m_dDarkness =   Darkness < 0.0 ? 0.0 :
03116                     Darkness > 1.0 ? 1.0 :
03117                     Darkness ;
03118 }
03119 
03120 
03121 
03122 
03123 #ifdef NEW_SHADOW_RENDER
03124 /********************************************************************************************
03125 
03126 >   BOOL NodeShadow::MakeShadow(LPBITMAPINFO lpInfo, LPBYTE lpBits, DocRect orect)
03127 
03128     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03129     Created:    11/03/2005
03130     Purpose:    Create a shadow from the supplied 32BPP RGBA captured bitmap of the 
03131                 original objects
03132 
03133 ********************************************************************************************/
03134 BOOL NodeShadow::MakeShadow(LPBITMAPINFO lpInfo, LPBYTE lpBits, DocRect orect)
03135 {
03136     if (m_ShadowBitmap)
03137         return TRUE;
03138 
03139     // Get details of this shadow from our controller
03140     NodeCompound* pCompound = GetParentController();
03141     NodeShadowController* pController = NULL;
03142     if (pCompound && pCompound->IsAShadowController())
03143         pController = (NodeShadowController*)pCompound;
03144     if (pController==NULL)
03145         return FALSE;
03146 
03147     double dPixelWidth = pController->GetPixelWidth();
03148     double dPixBlurDiameter = pController->GetPenumbraWidth()/dPixelWidth;
03149 
03150     // Use the RGBT bitmap provided to create a suitable shadow
03151     // and store it in the cache
03152 //  LPBITMAPINFO lpShadowInfo = NULL;
03153 //  LPBYTE lpShadowBits = NULL;
03154     DocRect ShadowRect;
03155     BOOL bOK = FALSE;
03156 
03157 
03158     // ------------------------------------------------
03159     // This code lifted from RenderBitmapForDisplay
03160     //
03161     // initialise the transparency fill attribute and clear our caches.
03162     SetupTransFill();
03163 
03164     // Get a kernel version of the silhouette bitmap
03165     CWxBitmap          *pwBitmap    = new CWxBitmap(lpInfo, lpBits);
03166     KernelBitmap       *pkBitmap    = new KernelBitmap(pwBitmap);
03167 
03168     // generate the shadow bitmap for the required blur diameter.
03169     bOK = GenerateShadowBitmap(pkBitmap, dPixBlurDiameter);
03170     if (!bOK)
03171         return FALSE;
03172 
03173 // if desired, attach a debug copy of the final shadow bitmap within the bitmap gallery.
03174 #ifdef ATTACH_SHADOW_BMP
03175     m_ShadowBitmap->AttachDebugCopyToCurrentDocument("MakeShadow Bitmap");
03176 #endif
03177 
03178     // Get rid of temp kernel bitmap
03179     if (pwBitmap)
03180         pwBitmap->BMBytes = ((CWxBitmap*)OILBitmap::Default)->BMBytes;
03181     if (pkBitmap)
03182     {
03183         delete pkBitmap;
03184         pkBitmap = NULL;
03185     }
03186 
03187     m_LastRequestedPixWidth = MILLIPOINT(dPixelWidth);
03188 //  m_LastQualitySetting    = CurrentQuality;
03189     m_LastActualPixWidth = dPixelWidth;
03190 
03191     // one last thing - create the path which the shadow bitmap-transparency is drawn into.
03192     CreateBitmapPath(orect, dPixelWidth, dPixBlurDiameter);             // TODO: Set pixel width properly
03193     // ------------------------------------------------
03194 
03195 
03196     // No need to do this at the moment because GenerateShadowBitmap creates m_ShadowBitmap
03197 /*  CBitmapCache* pBitmapCache = Camelot.GetBitmapCache();
03198     if (pBitmapCache==NULL)
03199         return FALSE;
03200 
03201     if (lpInfo==NULL || lpBits==NULL)
03202         return FALSE;
03203 
03204     // Cache the ORIGINAL bitmap as Option 0
03205     // See also, SetOriginalBitmap
03206     double PixelWidth = 42;                     // TODO: Does this matter?
03207     CBitmapCacheKey inky(this, PixelWidth, 0);
03208 
03209     CCachedBitmap cbmp;
03210 
03211     cbmp.pbmpBits = lpShadowBits;
03212     cbmp.pbmpInfo = lpShadowInfo;
03213     cbmp.SetCachedRect(ShadowRect);
03214     cbmp.nPriority = CACHEPRIORITY_TEMPBITMAP_HIGH;
03215 
03216     if (cbmp.IsValid())
03217     {
03218         pBitmapCache->StoreBitmap(inky, cbmp);
03219         bCached = TRUE;
03220     }
03221 */
03222     return TRUE;
03223 }
03224 
03225 
03226 
03227 
03228 /********************************************************************************************
03229 
03230 >   BOOL NodeShadow::RenderShadow(RenderRegion* pRender)
03231 
03232     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03233     Created:    11/03/2005
03234     Purpose:    Render a previously prepared shadow
03235 
03236 ********************************************************************************************/
03237 BOOL NodeShadow::RenderShadow(RenderRegion* pRender)
03238 {
03239     enum Quality::Fill CurrentQuality = pRender->RRQuality.GetFillQuality();
03240 
03241     pRender->SaveContext();
03242 
03243     if (CurrentQuality >= (enum Quality::Fill)Quality::Solid)
03244     {
03245         pRender->SetFillColour(COLOUR_BLACK);   // make sure there's some shadow colour
03246 
03247         Node* pNode = FindFirstChild();
03248         while (pNode)
03249         {
03250             if (pNode->IsAnAttribute())
03251             {
03252                 pNode->Render(pRender);
03253             }
03254 
03255             pNode = pNode->FindNext();
03256         }
03257 
03258         RenderBitmap(pRender);
03259     }
03260     else
03261     {
03262         // outlines only - we'll just render the shadow's bounding rect.
03263         DocRect drBounds = GetBoundingRect();
03264         pRender->SetFillColour(COLOUR_NONE);
03265         pRender->SetLineColour(COLOUR_BLACK);
03266         pRender->DrawRect(&drBounds);
03267     }
03268 
03269     pRender->RestoreContext();
03270 
03271     return FALSE;
03272 }
03273 
03274 
03275 
03276 
03277 /********************************************************************************************
03278 
03279 >   BOOL NodeShadow::NeedsRemake()
03280 
03281     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03282     Created:    11/03/2005
03283     Purpose:    Create a shadow from the supplied 32BPP RGBA captured bitmap of the 
03284                 original objects
03285 
03286 ********************************************************************************************/
03287 BOOL NodeShadow::NeedsRemake()
03288 {
03289     return (m_ShadowBitmap == NULL);
03290 }
03291 
03292 
03293 
03294 
03295 /********************************************************************************************
03296 
03297 >   virtual BOOL NodeShadow::TransformShadow(TransformBase& Trans)
03298 
03299     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
03300     Created:    15/04/2005
03301     Inputs:     Trans - The transform Object
03302     Returns:    TRUE if could transform the shadow
03303                 FALSE otherwise
03304     Purpose:    Transforms the shadow when the controller is in IsCapturingChildren mode
03305                 if we can
03306     SeeAlso:    NodeRenderableInk::Transform()
03307 
03308 ********************************************************************************************/
03309 BOOL NodeShadow::TransformShadow(TransformBase& Trans)
03310 {
03311     NodeShadowController* pControl = (NodeShadowController*)GetParentController();
03312     if (pControl==NULL)
03313         return FALSE;
03314 
03315     ERROR3IF(!pControl->IsCapturingChildren(), "TransformShadow should only be called when IsCapturingChildren");
03316 
03317     ShadowType shadtype = pControl->GetShadowType();
03318 
03319     // We can only translate floor shadows!
03320     if (!Trans.IsTranslation() && shadtype==SHADOWTYPE_FLOOR)
03321         return FALSE;
03322 
03323     // We can't transform shadows unless the transform has a usable matrix
03324     if (!Trans.IS_KIND_OF(Trans2DMatrix))
03325         return FALSE;
03326 
03327     // Transform the base path
03328     Trans.Transform(m_NonTranslatedPath.GetCoordArray(), m_NonTranslatedPath.GetNumCoords());
03329 
03330     switch (shadtype)
03331     {
03332     case SHADOWTYPE_WALL:
03333         // Transform the shadow path using the modified transform
03334         m_Path.ClearPath();
03335         m_Path.CloneFrom(m_NonTranslatedPath);
03336         m_Path.IsFilled = TRUE;
03337         m_Path.Translate(pControl->GetWallShadowOffset());
03338         break;
03339 
03340     case SHADOWTYPE_FLOOR:
03341         Trans.Transform(m_Path.GetCoordArray(), m_Path.GetNumCoords());
03342         break;
03343 
03344     case SHADOWTYPE_GLOW:
03345         Trans.Transform(m_Path.GetCoordArray(), m_Path.GetNumCoords());
03346         break;
03347 
03348     default:
03349         ERROR3("NodeShadow::TransformShadow; unknown parent shadow type!");
03350         break;
03351     }
03352 
03353     TransformChildren(Trans);
03354 
03355     return TRUE;
03356 }
03357 #endif
03358 
03359 
03360 
03361 //-------------------------------------------------------------------------------------------
03362 //-------------------------------------------------------------------------------------------
03363 //-------------------------------------------------------------------------------------------
03364 //-------------------------------------------------------------------------------------------
03365 
03366 
03367 
03369 // The passback function for the shadow become a
03370 /********************************************************************************************
03371 
03372 >   BOOL NodeShadowBecomeA::PassBack(NodeRenderableInk* pNewNode,
03373                                  NodeRenderableInk* pCreatedByNode,CCAttrMap* pAttrMap)
03374 
03375 
03376     Author:     David_McClarnon (Xara Group Ltd) <camelotdev@xara.com>
03377     Created:    11/12/99
03378     Purpose:    Used by NodeShadow to produce the path for the NodeShadowPassback node
03379 
03380 ********************************************************************************************/
03381 BOOL NodeShadowBecomeA::PassBack(NodeRenderableInk* pNewNode,
03382                                  NodeRenderableInk* pCreatedByNode,CCAttrMap* pAttrMap)
03383 {
03384     if (pNewNode)
03385     {
03386         if (pNewNode->IsNodePath())
03387         {
03388             m_pPath->MergeTwoPaths(((NodePath *)pNewNode)->InkPath);
03389         }
03390 
03391         pNewNode->CascadeDelete();
03392         delete pNewNode;
03393     }
03394 
03395     return TRUE;
03396 }
03397 
03398 
03399 
03400 //-------------------------------------------------------------------------------------------
03401 //-------------------------------------------------------------------------------------------
03402 //-------------------------------------------------------------------------------------------
03403 //-------------------------------------------------------------------------------------------
03404 
03405 
03406 
03407 /********************************************************************************************
03408 
03409 >   BitmapShadower* BitmapShadower::CreateSilhouetteBitmap( NodeShadowController* pControl,
03410                                                             GRenderRegion* pGRR = NULL,
03411                                                             List* pList = NULL )
03412     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
03413     Created:    26/10/2000
03414 
03415     Inputs:     pControl    NodeShadowController of the shadow which we're creating.
03416                 pGRR        render region for which to generate the shadow bitmap.
03417                 pList       list of SumAllPathsElem's to shadow - usually NULL, in which
03418                             case we shadow the node lying within the shadow tree structure.
03419 
03420     Outputs:    If successful, a 32bpp silhouette + other shadow information is generated
03421                 and stored in a new instance of this class.
03422 
03423     Returns:    A new instance of this class, containing all relevant shadow information, or
03424                 NULL if we failed.
03425 
03426     Purpose:    Generate a 32bpp silhouette bitmap ready for shadowing.
03427                 All relevant shadow information is stored in the returned object.
03428 
03429                 At a later date, I may move all non-bshadow.cpp/.h shadow bitmap
03430                 generating code into this class.
03431 
03432     Errors:     ERROR1 with NULL if we cannot create a new BitmapShadower.
03433                 ERROR2 with NULL if pControl or pGRR is NULL.
03434                 ERROR3 with NULL if pList is NULL and the shadowed node is NULL too.
03435 
03436     See also:   NodeShadow::RenderBitmapForDisplay().
03437 
03438 ********************************************************************************************/
03439 BitmapShadower* BitmapShadower::CreateSilhouetteBitmap( NodeShadowController* pControl,
03440                                                         GRenderRegion* pGRR, List* pList )
03441 {
03442     // input validation.
03443     ERROR2IF(pControl == NULL, NULL, "BitmapShadower::CreateSilhouetteBitmap; NULL input params!");
03444 
03445     // create a new shadower.
03446     BitmapShadower* pBitmapShadower = new BitmapShadower;
03447     ERROR1IF(pBitmapShadower == NULL, NULL, _R(IDS_OUT_OF_MEMORY));
03448 
03449     // initialise it and tell it to do its stuff.
03450     BOOL    ok = pBitmapShadower->Initialise(pControl, pGRR, pList);
03451     if (ok) ok = pBitmapShadower->DoCreateSilhouetteBitmap();
03452 
03453     return ok ? pBitmapShadower : NULL;
03454 }
03455 
03456 
03457 
03458 /********************************************************************************************
03459 
03460 >   BitmapShadower::BitmapShadower()
03461 
03462     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
03463     Created:    26/10/2000
03464 
03465     Purpose:    Private constructor - you may only create this class through public static
03466                 interface.
03467 
03468     See also:   BitmapShadower::CreateSilhouetteBitmap().
03469 
03470 ********************************************************************************************/
03471 BitmapShadower::BitmapShadower()
03472 {
03473     m_pGRR          = NULL;
03474 
03475     m_pControl      = NULL;
03476     m_pShadow       = NULL;
03477     m_pShadowedNode = NULL;
03478     m_pShadowedList = NULL;
03479 
03480     m_ShadowType    = SHADOWTYPE_NONE;
03481 
03482     m_drShadowedBounds.MakeEmpty();
03483     m_ShadowScaleFactor = 1.0;
03484     m_ActualPixelWidth  = 0;
03485     m_pixBlurDiameter   = 0;
03486 
03487     m_pRendWrap     = NULL;
03488     m_pOffscreenRR  = NULL;
03489 
03490     m_pSilhouetteBitmap = NULL;
03491 }
03492 
03493 
03494 
03495 /********************************************************************************************
03496 
03497 >   BitmapShadower::~BitmapShadower()
03498 
03499     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
03500     Created:    26/10/2000
03501     Purpose:    Destructor - frees the silhouette bitmap if it has not been extracted.
03502 
03503 ********************************************************************************************/
03504 BitmapShadower::~BitmapShadower()
03505 {
03506     if (m_pSilhouetteBitmap != NULL)
03507     {
03508         delete m_pSilhouetteBitmap;
03509         m_pSilhouetteBitmap = NULL;
03510     }
03511 }
03512 
03513 
03514 
03515 /********************************************************************************************
03516 
03517 >   BOOL BitmapShadower::Initialise(NodeShadowController* pControl, GRenderRegion* pGRR,
03518                                                                              List* pList)
03519     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
03520     Created:    26/10/2000
03521     Inputs:     pControl    NodeShadowController of the shadow which we're creating.
03522                 pGRR        render region for which to generate the shadow bitmap.
03523                 pList       list of SumAllPathsElem's to shadow - usually NULL, in which
03524                             case we shadow the node lying within the shadow tree structure.
03525 
03526     Returns:    TRUE if successful, FALSE othewise.
03527 
03528     Purpose:    Initialises our state.
03529 
03530 ********************************************************************************************/
03531 BOOL BitmapShadower::Initialise(NodeShadowController* pControl, GRenderRegion* pGRR,
03532                                                                         List* pList)
03533 {
03534     m_pControl          = pControl;
03535     m_pGRR              = pGRR;
03536     m_ShadowType        = m_pControl->GetShadowType();
03537 
03538     if (pList == NULL)
03539         m_pShadowedNode = pControl->GetShadowedNode();
03540     else
03541         m_pShadowedList = pList;
03542 
03543     if (m_pShadowedList == NULL && m_pShadowedNode == NULL)
03544     {
03545         ERROR3("BitmapShadower called with NULL shadowed node or NULL path-list to shadow!");
03546         return FALSE;
03547     }
03548 
03549     return TRUE;
03550 }
03551 
03552 
03553 
03554 /********************************************************************************************
03555 
03556 >   BOOL BitmapShadower::DoCreateSilhouetteBitmap()
03557 
03558     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
03559     Created:    26/10/2000
03560     Returns:    TRUE if successful, FALSE otherwise.
03561     Purpose:    Creates the shadow silhouette bitmap.
03562 
03563 ********************************************************************************************/
03564 BOOL BitmapShadower::DoCreateSilhouetteBitmap()
03565 {
03566     BOOL    ok = CalculateBoundsAndScale1();
03567     if (ok) ok = (m_pGRR == NULL) ? CalculateBoundsAndScale2NoGRR() :
03568                                     CalculateBoundsAndScale2WithGRR() ;
03569     if (ok) ok = CreateOffscreenRR();
03570     if (ok) ok = RenderShadowedNodeOffscreen();
03571 
03572     return ok;
03573 }
03574 
03575 
03576 
03577 /********************************************************************************************
03578 
03579 >   BOOL BitmapShadower::CalculateBoundsAndScale()
03580 
03581     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
03582     Created:    26/10/2000
03583 
03584     Outputs:    Following member variables are initialised:
03585 
03586                 m_drShadowedBounds
03587                 m_ShadowType
03588                 m_ShadowScaleFactor
03589                 m_ActualPixelWidth
03590 
03591     Returns:    TRUE if successful, FALSE otherwise.
03592 
03593     Purpose:    Calculate the bounds and scaling factor for our shadow bitmap.
03594 
03595                 This function is split into two parts, 1 and 2.
03596                 This is because part 2 performs differently, depending on whether or not we
03597                 have a ptr to a GRenderRegion. A GRenderRegion ptr ensures that our rendering
03598                 matches exactly with the target output device, however if we have no GRR, we
03599                 must query the current view, which is likely to produce just as good results,
03600                 but 
03601 
03602 ********************************************************************************************/
03603 BOOL BitmapShadower::CalculateBoundsAndScale1()
03604 {
03605     // if we're shadowing a node in the tree (usual behaviour), use its bounds.
03606     if (m_pShadowedNode != NULL)
03607         m_drShadowedBounds = m_pShadowedNode->GetBoundingRect();
03608 
03609     // if we're shadowing a list of paths & attrs, use the union of their bounds,
03610     // taking into account any attributes attached.
03611     else if (m_pShadowedList != NULL)
03612     {
03613         SumAllPathsElem* pElem = (SumAllPathsElem*)m_pShadowedList->GetHead();
03614         while (pElem != NULL)
03615         {
03616             DocRect PathBounds(0,0,0,0);
03617             pElem->GetPath()->GetTrueBoundingRect(&PathBounds, 0, pElem->GetAttrMap());
03618             m_drShadowedBounds = m_drShadowedBounds.Union(PathBounds);
03619 
03621             //  This code block is a BODGE for feathers+blends, and does not belong here!
03622             //
03623             AttrFeather* appliedFeather = NULL;
03624             pElem->GetAttrMap()->Lookup( CC_RUNTIME_CLASS(AttrFeather), (void *&) appliedFeather);
03625 
03626             if (appliedFeather)
03627             {
03628                 if (!(((FeatherAttrValue*) appliedFeather->GetAttributeValue ())->IsDefaultFlagSet ()))
03629                 {
03630                     pElem->GetAttrMap ()->PostBlendInit ((pElem->GetPath()), CC_RUNTIME_CLASS (NodePath));
03631                 }
03632             }
03634 
03635             pElem = (SumAllPathsElem *)m_pShadowedList->GetNext(pElem);
03636         }
03637     }
03638 
03639     // glow shadows require a bitmap big enough to hold the glow contour.
03640     if (m_ShadowType == SHADOWTYPE_GLOW)
03641         m_drShadowedBounds.Inflate(m_pControl->GetGlowWidth());
03642 
03643     return TRUE;
03644 }
03645 
03646 
03647 
03648 BOOL BitmapShadower::CalculateBoundsAndScale2WithGRR()
03649 {
03650     // leave a pixel-width's safety-margin around the bitmap.
03651     // we don't use GetScaledPixelWidth(), as that is not always correct!
03652     FIXED16 ScaleFactor;
03653     m_pGRR->GetMatrix().Decompose(&ScaleFactor);
03654     double GRRPixelWidth = (double)m_pGRR->GetPixelWidth() / fabs(ScaleFactor.MakeDouble());
03655     m_drShadowedBounds.Inflate((INT32)(GRRPixelWidth + 0.5));
03656 
03657     // if the offscreen bitmap will be too big, then we'll render it as large
03658     // as we can, and remember how much further it needs to scale up.
03659     WinRect wrBounds = m_pGRR->CalculateWinRect(m_drShadowedBounds);
03660 
03661     INT32 XSize = wrBounds.width;
03662     INT32 YSize = wrBounds.height;
03663     if (XSize > YSize)
03664     {
03665         if (XSize > MaxShadowBitmapSize)
03666             m_ShadowScaleFactor = MaxShadowBitmapSize / (double)XSize;
03667     }
03668     else
03669     {
03670         if (YSize > MaxShadowBitmapSize)
03671             m_ShadowScaleFactor = MaxShadowBitmapSize / (double)YSize;
03672     }
03673 
03674     // use the shadow scaling factor to calculate the actual pixel-width
03675     // for the shadow bitmap, so it renders at the correct size onscreen.
03676     m_ActualPixelWidth  = GRRPixelWidth / m_ShadowScaleFactor;
03677 
03678     return TRUE;
03679 }
03680 
03681 
03682 
03683 BOOL BitmapShadower::CalculateBoundsAndScale2NoGRR()
03684 {
03685     // we have no render region, but we need a render matrix,
03686     // so we must get the view to construct a render matrix for us.
03687     View* pView = View::GetCurrent();
03688     if (pView == NULL)
03689         return FALSE;
03690 
03691     Spread* pSpread = m_pControl->FindParentSpread();
03692     if (pSpread == NULL)
03693         return FALSE;
03694 
03695     double PixelsPerInch = pView->GetConvertToEditableShapesDPI();
03696 
03697     // leave a pixel-width's safety-margin around the bitmap.
03698     FIXED16 ViewPixelWidth = pView->GetScaledPixelWidth();
03699     m_drShadowedBounds.Inflate(ViewPixelWidth.round().MakeLong());
03700 
03701     // if the offscreen bitmap will be too big, then we'll render it as large
03702     // as we can, and remember how much further it needs to scale up.
03703     Matrix RenderMatrix = pView->ConstructRenderingMatrix(pSpread);
03704     WinRect wrBounds = OSRenderRegion::DocRectToWin(RenderMatrix, m_drShadowedBounds, PixelsPerInch);
03705 
03706     INT32 XSize = wrBounds.width;
03707     INT32 YSize = wrBounds.height;
03708     if (XSize > YSize)
03709     {
03710         if (XSize > MaxShadowBitmapSize)
03711             m_ShadowScaleFactor = MaxShadowBitmapSize / (double)XSize;
03712     }
03713     else
03714     {
03715         if (YSize > MaxShadowBitmapSize)
03716             m_ShadowScaleFactor = MaxShadowBitmapSize / (double)YSize;
03717     }
03718 
03719     // use the shadow scaling factor to calculate the actual pixel-width
03720     // for the shadow bitmap, so it renders at the correct size onscreen.
03721     const double AppPixelWidth = MILLIPOINTS_PER_INCH / PixelsPerInch;
03722     m_ActualPixelWidth = AppPixelWidth / m_ShadowScaleFactor;
03723 
03724     // Work out the adjustment to the scale factor to account for 
03725     // not rendering at 96 dpi.  This must be done after the calculations 
03726     // above as the bitmap is always rendered at 96 dpi but with a scale factor 
03727     // to ensure it is rendered the correct size.  If we are rendering at 20 dpi 
03728     // then we need to render 20/96 of the size but this must NOT be included in 
03729     // the calculation of m_ActualPixelWidth or the bitmap will be rendered into 
03730     // the main render region at the wrong size.
03731 
03732 // Phil, 21/02/2006
03733 // This doesn't seme to be needed any more and in fact it causes bug BZ861
03734 // Note that the ScaledPixelWidth resolution of captures is better controlled
03735 // than when this bodge was added.
03736 // So I'm tentatively removing it again
03737 // Unfortunately, removing this causes problems with export of shadows to 
03738 // plugin filters so it is going back in for now...
03739     
03740     if (PixelsPerInch != 96.0)
03741     {
03742         double NewScale = PixelsPerInch / 96.0;
03743         m_ShadowScaleFactor *= NewScale;
03744     }
03745 
03746     return TRUE;
03747 }
03748 
03749 
03750 
03751 /********************************************************************************************
03752 
03753 >   BOOL BitmapShadower::CreateOffscreenRR()
03754 
03755     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
03756     Created:    26/10/2000
03757 
03758     Outputs:    Following member variables are initialised:
03759 
03760                 m_pRendWrap
03761                 m_pOffscreenRR
03762                 m_pixBlurDiameter
03763 
03764     Returns:    TRUE if successful, FALSE otherwise.
03765 
03766     Purpose:    Creates the offscreen render-region, ready for rendering into.
03767 
03768 ********************************************************************************************/
03769 BOOL BitmapShadower::CreateOffscreenRR()
03770 {
03771     // create a concurrent renderer please, scaling it up if necessary.
03772     // ConcurrentRenderer creates a new GRenderRegion, based on the given GRenderRegion.
03773     m_pRendWrap = GRenderRegionWrapper::GetConcurrentRenderer(  m_pGRR,
03774                                                                 m_ShadowScaleFactor,
03775                                                                 m_drShadowedBounds,
03776                                                                 32,
03777                                                                 TRUE );
03778     if (m_pRendWrap == NULL)
03779         return FALSE;
03780 
03781     m_pOffscreenRR = m_pRendWrap->GetRenderRegion();
03782 
03783     // work out the required blur diameter in pixels (allowed to be non-integer).
03784     m_pixBlurDiameter = m_pControl->GetPenumbraWidth() / m_ActualPixelWidth;
03785 
03786     // wall and glow shadows have alignment problems, which require that we:
03787     //  1. force the offscreen RR to always smooth bitmaps.
03788     //  2. turn off line hinting in the offscreen RR.
03789     //  3. offset the RR down and left by a half pixel if we have an even blur.
03790     //
03791     // Note: non-full-quality rendering can do this job properly,
03792     // so if we're not rendering at full quality then we can only do odd blurs.
03793     if (m_ShadowType == SHADOWTYPE_GLOW || m_ShadowType == SHADOWTYPE_WALL)
03794     {
03795         if (m_pOffscreenRR->RRQuality.GetAntialiasQuality() == (enum Quality::Antialias)Quality::FullAntialias)
03796         {
03797             m_pOffscreenRR->SetForceBitmapSmoothing(TRUE);
03798             m_pOffscreenRR->GetDrawContext()->SetHintingFlag(FALSE);
03799             if (CBitmapShadow::BlurringWillOffsetBitmap(m_pixBlurDiameter))
03800                 m_pOffscreenRR->OffsetByHalfPixel();
03801         }
03802         else
03803         {
03804             // if blurring will offset the bitmap, then make the blur odd: +1,
03805             // and round to the nearest whole pixel: (UINT32)(+0.5).
03806             if (CBitmapShadow::BlurringWillOffsetBitmap(m_pixBlurDiameter))
03807                 m_pixBlurDiameter = (UINT32)(m_pixBlurDiameter + 1.5);
03808         }
03809     }
03810 
03811     return TRUE;
03812 }
03813 
03814 
03815 
03816 #ifndef NEW_GLOW_SILHOUETTE
03817 /********************************************************************************************
03818 
03819 >   BOOL BitmapShadower::RenderShadowedNodeOffscreen()
03820 
03821     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
03822     Created:    26/10/2000
03823 
03824     Outputs:    Following member variables are initialised:
03825 
03826                 m_pSilhouetteBitmap
03827 
03828                 Following member variables are deinitialised:
03829 
03830                 m_pRendWrap
03831                 m_pOffscreenRR
03832 
03833     Returns:    TRUE if successful, FALSE otherwise.
03834 
03835     Purpose:    Render the shadowed node offscreen, to create the silhouette bitmap.
03836 
03837 ********************************************************************************************/
03838 BOOL BitmapShadower::RenderShadowedNodeOffscreen()
03839 {
03840     // if we're rendering our shadowed nodes, then we need to pre-render all
03841     // attributes which indirectly apply to it via the controller,
03842     // *except* for offscreen attributes, as they're meant to divert rendering offscreen
03843     // for our *controller* node, not us.
03844     if (m_pShadowedNode != NULL)
03845     {
03846         CCAttrMap* pControlMap = CCAttrMap::MakeAppliedAttrMap(m_pControl);
03847         if (pControlMap != NULL)
03848         {
03849             pControlMap->Render(m_pOffscreenRR, FALSE);
03850             delete pControlMap;
03851         }
03852     }
03853 
03854     // we save context here, as the rendered attributes are applied indirectly,
03855     // therefore normal rendering would have one or more SaveContext()'s before
03856     // the ink-node is rendered.
03857     m_pOffscreenRR->SaveContext();
03858 
03859     // Create some no-transp attrs, for possible use if we're a glow shadow.
03860     FlatTranspFillAttribute NoFillTransp(TT_NoTranspType);
03861     StrokeTranspAttribute NoLineTransp(TT_NoTranspType);
03862     
03863     // for glow shadows, we must contour out from what we're shadowing and render that.
03864     if (m_ShadowType == SHADOWTYPE_GLOW)
03865     {
03866         // do a glow-width contour out from the shadowed node.
03867         // TODO: test and act on failure of this function.
03868         Path ContouredPath;
03869         NodeContour::GenerateContourPathForNode(&ContouredPath, m_pShadowedNode,
03870                                                 m_pShadowedList, m_pControl->GetGlowWidth());
03871 
03872         // set the render region to draw black silhouettes.
03873         m_pOffscreenRR->SetFillColour(COLOUR_BLACK);
03874         m_pOffscreenRR->SetLineColour(COLOUR_TRANS);
03875 
03876         // glow shadows do not pay attention to any transparency affecting the shadowed nodes,
03877         // so we must turn off any transparency attributes which were rendered by our attr-map.
03878         m_pOffscreenRR->SetTranspFillGeometry(&NoFillTransp, FALSE);
03879         m_pOffscreenRR->SetLineTransp(&NoLineTransp, FALSE);
03880 
03881         // that should do it - render the path into the render-region.
03882         m_pOffscreenRR->DrawPath(&ContouredPath);
03883     }
03884 
03885     // for other shadow types, we just render the node/path-list.
03886     // note that this is done *uninterruptibly*, unlike normal rendering.
03887     else
03888     {
03889         if (m_pShadowedNode != NULL)
03890         {
03891             BOOL SubRenderStateLockedByShadower = FALSE;
03892             if (!m_pOffscreenRR->IsSubRenderStateLocked())
03893             {
03894                 m_pOffscreenRR->LockSubRenderState(TRUE);
03895                 SubRenderStateLockedByShadower = TRUE;
03896             }
03897             m_pShadowedNode->RenderTreeAtomic(m_pOffscreenRR);
03898             if (SubRenderStateLockedByShadower)
03899             {
03900                 m_pOffscreenRR->LockSubRenderState(FALSE);
03901                 SubRenderStateLockedByShadower = FALSE;
03902             }
03903         }
03904 
03905         else if (m_pShadowedList != NULL)
03906         {
03907             SumAllPathsElem* pElem = (SumAllPathsElem *)m_pShadowedList->GetHead();
03908             while (pElem != NULL)
03909             {
03910                 m_pOffscreenRR->SaveContext();
03911                 pElem->GetAttrMap()->Render(m_pOffscreenRR);
03912                 m_pOffscreenRR->DrawPath(pElem->GetPath());
03913                 m_pOffscreenRR->RestoreContext();
03914 
03915                 pElem = (SumAllPathsElem*)m_pShadowedList->GetNext(pElem);
03916             }
03917         }
03918     }
03919 
03920     // restore the context to match our SaveContext() above.
03921     m_pOffscreenRR->RestoreContext();
03922 
03923     // extract the bitmap from the offscreen RR before the RR is closed down.
03924     m_pSilhouetteBitmap = m_pRendWrap->GetKernelBitmap();
03925     if (m_pSilhouetteBitmap == NULL)
03926     {
03927         ERROR3("BitmapShadower::RenderShadowedNodeOffscreen; Couldn't extract KernelBitmap!");
03928         return FALSE;
03929     }
03930 
03931 // if desired, insert a debug copy of the silhouette bitmap within the bitmap gallery.
03932 #ifdef ATTACH_SILHOUETTE_BMP
03933     m_pSilhouetteBitmap->AttachDebugCopyToCurrentDocument("Shadow Silhouette Bitmap");
03934 #endif;
03935 
03936     // close down the offscreen render-region and clear our ptrs to prevent future nastiness.
03937     m_pRendWrap->RestorePreviousRendererState();
03938     m_pRendWrap     = NULL;
03939     m_pOffscreenRR  = NULL;
03940 
03941     return TRUE;
03942 }
03943 #endif
03944 
03945 
03946 #ifdef NEW_GLOW_SILHOUETTE
03947 /********************************************************************************************
03948 
03949 >   BOOL BitmapShadower::RenderShadowedNodeOffscreen()
03950 
03951     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
03952     Created:    26/10/2000
03953 
03954     Outputs:    Following member variables are initialised:
03955 
03956                 m_pSilhouetteBitmap
03957 
03958                 Following member variables are deinitialised:
03959 
03960                 m_pRendWrap
03961                 m_pOffscreenRR
03962 
03963     Returns:    TRUE if successful, FALSE otherwise.
03964 
03965     Purpose:    Render the shadowed node offscreen, to create the silhouette bitmap.
03966 
03967 ********************************************************************************************/
03968 BOOL BitmapShadower::RenderShadowedNodeOffscreen()
03969 {
03970     // if we're rendering our shadowed nodes, then we need to pre-render all
03971     // attributes which indirectly apply to it via the controller,
03972     // *except* for offscreen attributes, as they're meant to divert rendering offscreen
03973     // for our *controller* node, not us.
03974     if (m_pShadowedNode != NULL)
03975     {
03976         CCAttrMap* pControlMap = CCAttrMap::MakeAppliedAttrMap(m_pControl, TRUE, FALSE);
03977         if (pControlMap != NULL)
03978         {
03979             pControlMap->Render(m_pOffscreenRR, FALSE);
03980             delete pControlMap;
03981         }
03982     }
03983 
03984     // we save context here, as the rendered attributes are applied indirectly,
03985     // therefore normal rendering would have one or more SaveContext()'s before
03986     // the ink-node is rendered.
03987     m_pOffscreenRR->SaveContext();
03988 
03989     // Create some no-transp attrs, for possible use if we're a glow shadow.
03990     FlatTranspFillAttribute NoFillTransp(TT_NoTranspType);
03991     StrokeTranspAttribute NoLineTransp(TT_NoTranspType);
03992     
03993     // NOTE: This render is not interruptible for normal background rendering
03994     // NOTE: Should use Phil's new Capture system to avoid this extra render
03995     {
03996         if (m_pShadowedNode != NULL)
03997         {
03998             BOOL SubRenderStateLockedByShadower = FALSE;
03999             if (!m_pOffscreenRR->IsSubRenderStateLocked())
04000             {
04001                 m_pOffscreenRR->LockSubRenderState(TRUE);
04002                 SubRenderStateLockedByShadower = TRUE;
04003             }
04004             m_pShadowedNode->RenderTreeAtomic(m_pOffscreenRR);
04005             if (SubRenderStateLockedByShadower)
04006             {
04007                 m_pOffscreenRR->LockSubRenderState(FALSE);
04008                 SubRenderStateLockedByShadower = FALSE;
04009             }
04010         }
04011 
04012         else if (m_pShadowedList != NULL)
04013         {
04014             SumAllPathsElem* pElem = (SumAllPathsElem *)m_pShadowedList->GetHead();
04015             while (pElem != NULL)
04016             {
04017                 m_pOffscreenRR->SaveContext();
04018                 pElem->GetAttrMap()->Render(m_pOffscreenRR);
04019                 m_pOffscreenRR->DrawPath(pElem->GetPath());
04020                 m_pOffscreenRR->RestoreContext();
04021 
04022                 pElem = (SumAllPathsElem*)m_pShadowedList->GetNext(pElem);
04023             }
04024         }
04025     }
04026 
04027     // restore the context to match our SaveContext() above.
04028     m_pOffscreenRR->RestoreContext();
04029 
04030     // for glow shadows, we must contour out from what we're shadowing and render that.
04031     if (m_ShadowType == SHADOWTYPE_GLOW)
04032     {
04033         GRenderRegion* pRegion = NULL;
04034         LPBITMAPINFO lpInfo = NULL;
04035         LPBYTE lpBits = NULL;
04036         pRegion = m_pRendWrap->GetRenderRegion();
04037         m_pRendWrap->GetBitmapPointers(&lpInfo, &lpBits);
04038         ENSURE(pRegion && lpInfo && lpBits, "Failed to get offscreen region details in RenderShadowedNodeOffscreen");
04039 
04040         LPBITMAPINFO lpContourInfo = NULL;
04041         LPBYTE lpContourBits = NULL;
04042         double OffsetX = 0;
04043         double OffsetY = 0;
04044         double dPixelContour = (double)m_pControl->GetGlowWidth()/pRegion->GetScaledPixelWidthDouble();
04045 //      if (dPixelContour>MAX_CONTOUR)
04046 //          dPixelContour = MAX_CONTOUR;
04047 //        BOOL ok = CBitmapShadow::ContourBitmap(lpInfo,
04048 //                                             lpBits,
04049 //                                             dPixelContour,
04050 //                                             0xFE,            // Threshold
04051 //                                             &lpContourInfo,
04052 //                                             &lpContourBits,
04053 //                                             &OffsetX,
04054 //                                             &OffsetY
04055 //                                             );
04056         // Call ContourBitmap in 20 pixel steps - Gavin says this will be faster than
04057         // doing the whole contour at once and it overcomes the 100 pixel, MAX_CONTOUR
04058         // limit.
04059         BOOL ok = TRUE;
04060         double dPixRemaining = dPixelContour;
04061         if (dPixelContour<=0)
04062             ok = FALSE;
04063         LPBITMAPINFO lpIterInfo = lpInfo;
04064         LPBYTE lpIterBits = lpBits;
04065         while (ok && dPixRemaining>0)
04066         {
04067             double dPixIteration = dPixRemaining>20 ? 20 : dPixRemaining;
04068 
04069             double dx = 0;
04070             double dy = 0;
04071             ok = CBitmapShadow::ContourBitmap(lpIterInfo,
04072                                                lpIterBits,
04073                                                dPixIteration,
04074                                                0xFE,            // Threshold
04075                                                &lpContourInfo,
04076                                                &lpContourBits,
04077                                                &dx,
04078                                                &dy
04079                                                );
04080             OffsetX += dx;
04081             OffsetY += dy;
04082 
04083             dPixRemaining = dPixRemaining - dPixIteration;
04084             if (ok && lpIterInfo!=lpInfo && lpIterBits!=lpBits)
04085             {
04086                 FreeDIB(lpIterInfo, lpIterBits);
04087             }
04088             lpIterInfo = lpContourInfo;
04089             lpIterBits = lpContourBits;
04090         }
04091 
04092 //      ERROR3IF(!ok, "ContourBitmap failed in RenderShadowedNodeOffscreen");
04093 
04094         if (ok && lpContourInfo && lpContourBits)
04095         {
04096             if (m_pSilhouetteBitmap)
04097                 delete m_pSilhouetteBitmap;
04098 
04099             double PixelWidth = m_pOffscreenRR->GetScaledPixelWidthDouble();
04100             MILLIPOINT newWidth = MILLIPOINT(PixelWidth * lpContourInfo->bmiHeader.biWidth);
04101             MILLIPOINT newHeight = MILLIPOINT(PixelWidth * lpContourInfo->bmiHeader.biHeight);
04102             DocCoord newCorner = m_drShadowedBounds.lo;
04103             newCorner.x += INT32(OffsetX * PixelWidth);
04104             newCorner.y += INT32(OffsetY * PixelWidth);
04105             m_drShadowedBounds.lo = newCorner;
04106             m_drShadowedBounds.hi.x = newCorner.x + newWidth;
04107             m_drShadowedBounds.hi.y = newCorner.y + newHeight;
04108 
04109             CWxBitmap* wbmpSilhouette   = new CWxBitmap(lpContourInfo, lpContourBits);
04110             m_pSilhouetteBitmap         = new KernelBitmap(wbmpSilhouette, TRUE);
04111 
04112 
04113             // Make sure offscreen bitmap doesn't hang around
04114             KernelBitmap* pOffBitmap = m_pRendWrap->GetKernelBitmap();
04115             delete pOffBitmap;
04116         }
04117         else
04118         {
04119             // ContourBitmap failed!
04120             // extract the bitmap from the offscreen RR before the RR is closed down.
04121             m_pSilhouetteBitmap = m_pRendWrap->GetKernelBitmap();
04122         }
04123     }
04124     else
04125     {
04126         // extract the bitmap from the offscreen RR before the RR is closed down.
04127         m_pSilhouetteBitmap = m_pRendWrap->GetKernelBitmap();
04128     }
04129 
04130     // close down the offscreen render-region and clear our ptrs to prevent future nastiness.
04131     m_pRendWrap->RestorePreviousRendererState();
04132     m_pRendWrap     = NULL;
04133     m_pOffscreenRR  = NULL;
04134 
04135     if (m_pSilhouetteBitmap == NULL)
04136     {
04137         ERROR3("BitmapShadower::RenderShadowedNodeOffscreen; Couldn't extract KernelBitmap!");
04138         return FALSE;
04139     }
04140 
04141 // if desired, insert a debug copy of the silhouette bitmap within the bitmap gallery.
04142 #ifdef ATTACH_SILHOUETTE_BMP
04143     m_pSilhouetteBitmap->AttachDebugCopyToCurrentDocument("Shadow Silhouette Bitmap");
04144 #endif
04145 
04146     return TRUE;
04147 }
04148 #endif
04149 
04150 
04151 
04152 #endif  // BUILDSHADOWS

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