brushref.cpp

Go to the documentation of this file.
00001 // $Id: brushref.cpp 1282 2006-06-09 09:46:49Z 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 // BrushRef implementation
00100 
00101 
00102 #include "camtypes.h"
00103 #include "brushref.h"
00104 #include "nodebldr.h"
00105 //#include "docrect.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00106 //#include "doccoord.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00107 //#include "fillval.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00108 //#include "fillattr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 #include "nodebldr.h"
00110 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00111 #include "nodepath.h"
00112 //#include "nodecomp.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00113 #include "gblend.h"
00114 #include "nodeblnd.h"
00115 #include "nodeclip.h"
00116 #include "lineattr.h"
00117 #include "attrmap.h"
00118 
00119 CC_IMPLEMENT_MEMDUMP(BrushRef, BlendRef)
00120 CC_IMPLEMENT_MEMDUMP(BrushRefBlender, CC_CLASS_MEMDUMP);
00121 
00122 #define DELPTR(p) if (p != NULL) { delete p; p = NULL; }
00123 #define FLATNESS 1024
00124 
00125 // Declare smart memory handling in Debug builds
00126 #define new CAM_DEBUG_NEW    
00127 
00128 /***********************************************************************************************
00129 
00130 >   void BlendPathOffset::CalculateAngleAndMagnitude()
00131 
00132     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00133     Created:    7/12/99
00134     Inputs:     -
00135     Outputs:    -
00136     Returns:    -
00137     Purpose:    takes the x and y offset members and calculates the angle and magnitude of that vector
00138 
00139 ***********************************************************************************************/
00140 
00141 void BlendPathOffset::CalculateAngleAndMagnitude()
00142 {
00143     MILLIPOINT Xsq = m_XOffset * m_XOffset;
00144     MILLIPOINT Ysq = m_YOffset * m_YOffset;
00145     double Hypotenuse = sqrt((double)Xsq + (double)Ysq);
00146     double Calc = ((double)m_XOffset / Hypotenuse);
00147     double RadAngle = acos(Calc);
00148 //  double DegAngle = RadAngle * (180 / PI);
00149 
00150     m_Angle = RadAngle;
00151     m_Magnitude = (MILLIPOINT)Hypotenuse;
00152 }
00153 
00154 
00155 /***********************************************************************************************
00156 
00157 >   void BlendPathOffset::GetAngleAndMagnitude(double* pAngle, MILLIPOINT* pMagnitude)
00158 
00159     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00160     Created:    7/12/99
00161     Inputs:     -
00162     Outputs:    pAngle
00163                 pMagnitude
00164     Returns:    -
00165     Purpose:    to get the angle and magnitude of this vector
00166 
00167 ***********************************************************************************************/
00168 
00169 void BlendPathOffset::GetAngleAndMagnitude(double* pAngle, MILLIPOINT* pMagnitude)
00170 {
00171     *pAngle = m_Angle;
00172     *pMagnitude = m_Magnitude;
00173 }
00174 
00175 
00176 /***********************************************************************************************
00177 
00178 >   void BlendPathOffset::RotateByAngle(double Angle, MILLIPOINT* pXOffset, MILLIPOINT* pYOffset)
00179 
00180     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00181     Created:    7/12/99
00182     Inputs:     Angle - the angle to rotate by
00183     Outputs:    pXOffset - the resulting scalar value of the vector
00184                 pYOffset
00185     Returns:    -
00186     Purpose:    to find out the x and y offset values if this blendpathoffset were to be rotated
00187                 by the given angle
00188 
00189 ***********************************************************************************************/
00190 
00191 void BlendPathOffset::RotateByAngle(double Angle, MILLIPOINT* pXOffset, MILLIPOINT* pYOffset)
00192 {
00193     double NewAngle = m_Angle + Angle;
00194 
00195     *pXOffset = (MILLIPOINT)(m_Magnitude * cos(NewAngle));
00196     *pYOffset = (MILLIPOINT)(m_Magnitude * sin(NewAngle));
00197 }
00198 
00199 
00200 
00201 /***********************************************************************************************
00202 
00203 > BrushRef::BrushRef()
00204 
00205     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00206     Created:    7/12/99
00207     Inputs:     -
00208     Outputs:    -
00209     Returns:    -
00210     Purpose:    Default constructor.
00211 
00212 ***********************************************************************************************/
00213 
00214 BrushRef::BrushRef() 
00215 {
00216     m_pNode             = NULL;
00217     m_NumBlendPaths     = 0;
00218     m_pBlendPathAttrMap = NULL;
00219     m_CachedRect        = DocRect(0,0,0,0);
00220     m_pCurrentBlendPath = NULL;
00221 }
00222 
00223 /***********************************************************************************************
00224 
00225 > BrushRef::~BrushRef()
00226 
00227     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
00228     Created:    12/10/94
00229     Inputs:     -
00230     Outputs:    -
00231     Returns:    -
00232     Purpose:    Default destructor.
00233 
00234 ***********************************************************************************************/
00235 
00236 BrushRef::~BrushRef()
00237 {
00238     FreeAttributes();
00239     m_BlendPathList.DeleteAll();
00240     m_OffsetList.clear();
00241 }
00242 
00243 /***********************************************************************************************
00244 
00245 > BOOL BrushRef::Initialise(NodeRenderableInk* pInitNode)
00246 
00247     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00248     Created:    7/12/99
00249     Inputs:     pInitNode   = ptr to the node this BrushRef refers to.
00250             
00251     Outputs:    -
00252     Returns:    TRUE if successfully initialises, FALSE otherwise
00253     Purpose:    This inits the BrushRef object with the given node.  Essentially a wrapper for
00254                 the blendref initialise function.  However it also works out 
00255                 the blendpath offsets, if there are any
00256 
00257 ***********************************************************************************************/
00258 
00259 BOOL BrushRef::Initialise(NodeRenderableInk* pInitNode)
00260 {
00261     ERROR2IF(pInitNode == NULL, FALSE, "Ink node is NULL in BrushRef::Initialise");
00262     
00263     // Note that BrushDefinition::GenerateBrush now prevents objects with brush attributes being
00264     // used to generate brushes, instead it converts them to groups of nodepaths as per Convert Line to Shapes
00265 
00266     pInitNode->MakeAttributeComplete(); // just in case we're missing any
00267 
00268     BOOL ok = BlendRef::InitialiseForBrush(pInitNode); 
00269 
00270     if (ok)
00271     {
00272         // if we have made a brushref from a group then the different 
00273         // blendpaths will be offset from the centre of.  work out these
00274         // offsets and store them in a list
00275         m_OffsetList.clear();
00276         DocRect BRect = GetBoundingRect();
00277         DocCoord Centre = BRect.Centre();
00278         
00279         BlendPath* pBlendPath = GetFirstBlendPath();
00280         
00281         while (pBlendPath != NULL)
00282         {   
00283             Path* pPath = pBlendPath->GetPath();
00284             if (pPath)
00285             {
00286                 DocRect BlendPathRect = pPath->GetBoundingRect();
00287                 DocCoord BlendPathCentre = BlendPathRect.Centre();
00288                 
00289                 BlendPathOffset ThisOffset;
00290                 ThisOffset.m_XOffset = BlendPathCentre.x - Centre.x ;
00291                 ThisOffset.m_YOffset = BlendPathCentre.y - Centre.y;
00292                 ThisOffset.CalculateAngleAndMagnitude();
00293                 m_OffsetList.push_back(ThisOffset);
00294                 pBlendPath->FindAppliedAttributes();
00295                 pBlendPath = GetNextBlendPath(pBlendPath);
00296             }
00297             else
00298             {
00299                 ERROR3("BlendPath has no path");
00300                 return FALSE;
00301             }
00302         }
00303         // if we have a bitmap fill we need to do some special things..
00304         SetBitmapFillFlags();
00305         PreBlend();
00306         if (pInitNode->IsABlend())
00307             ((NodeBlend*)pInitNode)->Deinit();
00308         return TRUE;
00309     }
00310     
00311 
00312     return FALSE;
00313 
00314 }
00315 
00316 
00317 /***********************************************************************************************
00318 
00319 >  BOOL BrushRef::MakeCopiesForRendering()
00320 
00321     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00322     Created:    12/9/2000
00323     Inputs:     -
00324     Outputs:    -
00325     Returns:    TRUE if successful, FALSE otherwise (e.g. out of memory)
00326                 
00327     Purpose:    Asks the blendpaths to make copies of their paths and attributes which
00328                 we will use to render with
00329 
00330 ***********************************************************************************************/
00331 
00332 BOOL BrushRef::MakeCopiesForRendering()
00333 {
00334 //  BlendPath* pLastPath = NULL;
00335     BlendPath* pBlendPath = GetFirstBlendPath();
00336     BOOL ok = TRUE;
00337     while (pBlendPath != NULL)
00338     {
00339         if (ok)
00340             ok = pBlendPath->MakeCopyPathAndAttributes();
00341         pBlendPath = GetNextBlendPath(pBlendPath);
00342     
00343     }
00344     return ok;
00345 
00346 }
00347 
00348 
00349 /***********************************************************************************************
00350 
00351 >  BOOL BrushRef::UpdateCopies()
00352 
00353     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00354     Created:    14/01/2004
00355     Inputs:     -
00356     Outputs:    -
00357     Returns:    TRUE if successful, FALSE otherwise (e.g. out of memory)
00358                 
00359     Purpose:    Asks the blendpaths to make copies of their paths and attributes which
00360                 we will use to render with
00361 
00362 ***********************************************************************************************/
00363 
00364 BOOL BrushRef::UpdateCopies()
00365 {
00366 //  BlendPath* pLastPath = NULL;
00367     BlendPath* pBlendPath = GetFirstBlendPath();
00368     BOOL ok = TRUE;
00369     while (pBlendPath != NULL && ok)
00370     {
00371         pBlendPath->UpdateCopyPathAndAttributes();
00372         pBlendPath = GetNextBlendPath(pBlendPath);
00373     
00374     }
00375     return ok;
00376 
00377 }
00378 
00379 
00380 /***********************************************************************************************
00381 
00382 >  BOOL BrushRef::MakeCopiesForRendering()
00383 
00384     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00385     Created:    12/9/2000
00386     Inputs:     -
00387     Outputs:    -
00388     Returns:    -
00389                 
00390     Purpose:    Asks the blendpaths to delete the copies of paths and attributes
00391 
00392 ***********************************************************************************************/
00393 
00394 void BrushRef::DeleteRenderCopies()
00395 {
00396 //  BlendPath* pLastPath = NULL;
00397     BlendPath* pBlendPath = GetFirstBlendPath();
00398     while (pBlendPath != NULL)
00399     {
00400         pBlendPath->DeleteCopyPathAndAttributes();
00401         pBlendPath = GetNextBlendPath(pBlendPath);
00402     
00403     }
00404 }
00405 
00406 
00407 /***********************************************************************************************
00408 
00409 >  Path* BrushRef::GetFirstCopyPath()
00410 
00411     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00412     Created:    12/9/2000
00413     Inputs:     -
00414     Outputs:    -
00415     Returns:    the copy of the path made by the first blendpath that we should use for 
00416                 rendering
00417                 
00418     Purpose:    Makes the first blendpath our current blendpath member and returns the 
00419                 copy of its path.
00420                 Basically you should use the system like this:
00421 
00422                 
00423                 Path* pPath = pBrushRef->GetFirstCopyPath();
00424                 CCAttrMap* pMap = NULL;
00425 
00426                 while (pPath)
00427                 {
00428                     pMap = pBrushRef->GetCurrentAttributeCopy();
00429 
00430                     pMap->Render(or whatever)
00431                     pPath->Render (or whatever)
00432                     
00433                     pPath = pBrushRef->GetNextCopyPath();
00434                 }
00435 
00436 ***********************************************************************************************/
00437 
00438 Path* BrushRef::GetFirstCopyPath()
00439 {
00440     m_pCurrentBlendPath = GetFirstBlendPath();
00441     if (m_pCurrentBlendPath == NULL)
00442     {
00443         ERROR3("First blendpath is NULL in BrushRef::GetFirstCopyPath");
00444         return NULL;
00445     }
00446     return m_pCurrentBlendPath->GetCopyPath();
00447 }
00448 
00449 
00450 /***********************************************************************************************
00451 
00452 >  Path* BrushRef::GetFirstCopyPath()
00453 
00454     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00455     Created:    12/9/2000
00456     Inputs:     -
00457     Outputs:    -
00458     Returns:    the next path to be rendered
00459                 
00460     Purpose:    Increments our current blendpath member and returns the copy path of
00461                 the next blendpath
00462 
00463 ***********************************************************************************************/
00464 
00465 Path* BrushRef::GetNextCopyPath()
00466 {
00467     // If our current blendpath isn't set yet then its an error
00468     if (m_pCurrentBlendPath == NULL)
00469     {
00470         ERROR3("Current blendpath is NULL in BrushRef::GetNextCopyPath");
00471         return NULL;
00472     }
00473     m_pCurrentBlendPath = GetNextBlendPath(m_pCurrentBlendPath);
00474     
00475     if (m_pCurrentBlendPath != NULL)
00476         return m_pCurrentBlendPath->GetCopyPath();
00477 
00478     // we've hit the end of the line
00479     return NULL;
00480 }
00481 
00482 
00483 
00484 /***********************************************************************************************
00485 
00486 >  CCAttrMap* BrushRef::GetCurrentAttributeCopy()
00487 
00488     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00489     Created:    12/9/2000
00490     Inputs:     -
00491     Outputs:    -
00492     Returns:    the attribute map that we should render with our current copy path
00493                 
00494     Purpose:    
00495 
00496 ***********************************************************************************************/
00497 
00498 CCAttrMap* BrushRef::GetCurrentAttributeCopy()
00499 {
00500     if (m_pCurrentBlendPath == NULL)
00501     {
00502         ERROR3("Current blendpath is NULL in BrushRef::GetCurrentAttributeCopy");
00503         return NULL;
00504     }
00505     return m_pCurrentBlendPath->GetCopyAttributes();
00506 
00507 }
00508 
00509 /***********************************************************************************************
00510 
00511 >   MILLIPOINT  BrushRef::GetFirstOffset(POSITION* pHeadPosition)
00512 
00513     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00514     Created:    7/12/99
00515     Inputs:     pListPosition - uninitialised POSITION variable
00516     Outputs:    pListPosition - the position of the head of the list - use it to pass into GetNextOffset
00517     Returns:    the value of the first offset in the m_offset list.  If the list is empty it
00518                 returns -1.
00519     Purpose:    as above
00520 
00521 ***********************************************************************************************/
00522 
00523 BlendPathOffset *BrushRef::GetFirstOffset( iterator *pHeadPosition )
00524 {
00525     if (m_OffsetList.empty())
00526         return NULL;
00527     else
00528     {
00529         *pHeadPosition = m_OffsetList.begin();
00530         return &( *(*pHeadPosition)++ );
00531     }
00532 }
00533 
00534 
00535 /***********************************************************************************************
00536 
00537 >   MILLIPOINT  BrushRef::GetNextOffset(POSITION* pPosition)
00538 
00539     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00540     Created:    7/12/99
00541     Inputs:     pPosition -  the position to get in the list
00542     Outputs:    pPosition - the next position in the list (or NULL)
00543     Returns:    the value of the next offset in the m_offset list.  If the list is empty it
00544                 returns NULL.
00545     Purpose:    as above
00546 
00547 ***********************************************************************************************/
00548 
00549 BlendPathOffset* BrushRef::GetNextOffset( iterator *pHeadPosition )
00550 {
00551     if( m_OffsetList.empty() )
00552         return NULL;
00553     else
00554         return &( *(*pHeadPosition)++ );
00555 }
00556 
00557 
00558 /***********************************************************************************************
00559 
00560 >   DocRect  BrushRef::GetBoundingRect()
00561 
00562     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00563     Created:    7/12/99
00564     Inputs:     
00565     Outputs:    
00566     Returns:    the bounding rect of this brushref
00567     Purpose:    as above, unions the bounding boxes 
00568 
00569 ***********************************************************************************************/
00570 
00571 DocRect BrushRef::GetBoundingRect()
00572 {
00573     DocRect Rect;
00574 
00575     BlendPath          *pBlendPath = GetFirstBlendPath();
00576     BlendPathOffset     Offset;
00577     iterator            ListPos = m_OffsetList.begin();
00578     CCAttrMap          *pAttrMap = NULL;
00579     while (pBlendPath != NULL)
00580     {
00581         DocRect PathRect;
00582         pAttrMap = pBlendPath->FindAppliedAttributes();
00583         pBlendPath->m_pPath->GetTrueBoundingRect(&PathRect, 0, pAttrMap);
00584         if (ListPos != m_OffsetList.end() )
00585         {
00586             Offset = *ListPos++;
00587         /*  PathRect.hix += Offset.m_XOffset;
00588             PathRect.lox += Offset.m_XOffset;
00589             PathRect.hiy += Offset.m_YOffset;
00590             PathRect.loy += Offset.m_YOffset;
00591         */
00592         }
00593         Rect = Rect.Union(PathRect);
00594         pAttrMap = NULL;
00595         pBlendPath = GetNextBlendPath(pBlendPath);
00596     }
00597     
00598     return Rect;
00599 }
00600 
00601 
00602 /***********************************************************************************************
00603 
00604 >   BOOL  BrushRef::SetBitmapFillFlags()
00605 
00606     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00607     Created:    7/12/99
00608     Inputs:     
00609     Outputs:    
00610     Returns:    TRUE if we don't have a bitmap fill, or if we do and successfully made a copy
00611     Purpose:    Because brush definitions exist independently of documents, but bitmap fills do not.
00612                 Therefore if we make a brush with a bitmap fill and then delete them document we 
00613                 created it in we lose the fill. However the brush still exists, therefore this 
00614                 function searches for a bitmap fill attribute, and sets flags that tell the bitmap
00615                 not to delete itself.
00616                 NOTE: This means that we are responsible for deleting the bitmap fills that belong to us
00617 ***********************************************************************************************/
00618 
00619 BOOL BrushRef::SetBitmapFillFlags()
00620 {
00621     // for each blendpath we wish to find out if they have an applied bitmap fill attribute.
00622     // if so then we want to copy it, and replace it in the attribute map
00623     BlendPath* pBlendPath = GetFirstBlendPath();
00624 
00625     while (pBlendPath != NULL)
00626     {
00627         // there may be both a colour fill and transparency attribute, so get both
00628         AttrBitmapFill* pBMPFill = pBlendPath->GetAppliedBitmapColourFill();
00629         if (pBMPFill != NULL)
00630         {
00631             // Get the attribute value
00632             BitmapFillAttribute* pVal = (BitmapFillAttribute*)pBMPFill->GetAttributeValue();
00633 
00634             if (pVal == NULL)
00635             {
00636                 ERROR3("Couldn't retrieve attribute value");    
00637                 return FALSE;
00638             }
00639 
00640             KernelBitmap* pKBitmap = pVal->GetBitmap();
00641             if (pKBitmap != NULL)
00642             {
00643                 OILBitmap* pOBitmap = pKBitmap->GetActualBitmap();
00644                 
00645                 // tell the bitmaps that they are being used by us so that if the 
00646                 // document closes they don't get deleted
00647                 if (pOBitmap != NULL)
00648                 {
00649                     pOBitmap->SetUsedByBrush(TRUE);
00650                     pKBitmap->SetUsedByBrush(TRUE);
00651                 }
00652 
00653             }
00654         }
00655         
00656         AttrBitmapFill* pTranspFill = pBlendPath->GetAppliedBitmapTranspFill();
00657         if (pTranspFill != NULL)
00658         {
00659             // Get the attribute value
00660             BitmapFillAttribute* pVal = (BitmapFillAttribute*)pTranspFill->GetAttributeValue();
00661 
00662             if (pVal == NULL)
00663             {
00664                 ERROR3("Couldn't retrieve attribute value");    
00665                 return FALSE;
00666             }
00667 
00668             KernelBitmap* pKBitmap = pVal->GetBitmap();
00669             if (pKBitmap != NULL)
00670             {
00671                 OILBitmap* pOBitmap = pKBitmap->GetActualBitmap();
00672                 
00673                 // tell the bitmaps that they are being used by us so that if the 
00674                 // document closes they don't get deleted
00675                 if (pOBitmap != NULL)
00676                 {
00677                     pOBitmap->SetUsedByBrush(TRUE);
00678                     pKBitmap->SetUsedByBrush(TRUE);
00679                 }
00680 
00681             }
00682         }
00683 
00684         pBlendPath = GetNextBlendPath(pBlendPath);
00685     }
00686     return TRUE;
00687 }
00688 
00689 
00690 
00691 /***********************************************************************************************
00692 
00693 >   void  BrushRef::DeleteBitmapFills()
00694 
00695     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00696     Created:    7/12/99
00697     Inputs:     
00698     Outputs:    
00699     Returns:    -
00700     Purpose:    Searches for bitmap fill attributes and deletes their bitmaps, see previous function
00701                 for the rationale.
00702                 Note that this function was designed to be called by the BrushDefinition destructor.
00703                 I cannot think of a good reason for wanting to use it anywhere else.
00704 ***********************************************************************************************/
00705 
00706 void BrushRef::DeleteBitmapFills()
00707 {
00708     // loop through each blendpath
00709     BlendPath* pBlendPath = GetFirstBlendPath();
00710 
00711     while (pBlendPath != NULL)
00712     {
00713         // retrieve the attribute node
00714         AttrBitmapFill* pBMPFill = pBlendPath->GetAppliedBitmapColourFill();
00715         if (pBMPFill != NULL)
00716         {
00717             // get the attribute value
00718             BitmapFillAttribute* pVal = (BitmapFillAttribute*)pBMPFill->GetAttributeValue();
00719             if (pVal != NULL)
00720             {
00721                 // get the bitmap
00722                 KernelBitmap* pBitmap = pVal->GetBitmap();
00723                 // if it has been flagged by us then zap it
00724                 if (pBitmap != NULL && pBitmap->IsUsedByBrush())
00725                 {
00726                     pBitmap->SetUsedByBrush(FALSE);
00727                     pBitmap->Detach();
00728                     delete pBitmap;
00729                 }
00730             }
00731         }
00732         pBlendPath = GetNextBlendPath(pBlendPath);
00733     }
00734 }
00735 
00736 
00737 
00738 /***********************************************************************************************
00739 
00740 >   void  BrushRef::DeleteAttributesAndPath()
00741 
00742     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00743     Created:    7/12/99
00744     Inputs:     
00745     Outputs:    
00746     Returns:    -
00747     Purpose:    Goes through all of the blendpaths and sets a flag which ensures that all the 
00748                 applied attributes of this blendpath are deleted upon destruction.  This must not 
00749                 be used under normal circumstances because these attributes will still be in use
00750                 by other objects.  It was designed for when we are blending brush attributes and have
00751                 to generate our attribute maps from scratch
00752 ***********************************************************************************************/
00753 
00754 void BrushRef::DeleteAttributesAndPath()
00755 {
00756 //  BlendPath* pLastPath = NULL;
00757     BlendPath* pBlendPath = GetFirstBlendPath();
00758     while (pBlendPath != NULL)
00759     {
00760         // ensures that all the applied attributes will be deleted when the object is deleted
00761         pBlendPath->DeleteAttributesAndPath();
00762         pBlendPath = GetNextBlendPath(pBlendPath);
00763     
00764     }
00765 }
00766 
00767 
00768 /***********************************************************************************************
00769 
00770 >   void  BrushRef::FreeAttributes()
00771 
00772     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00773     Created:    7/12/99
00774     Inputs:     
00775     Outputs:    
00776     Returns:    -
00777     Purpose:    Goes through the blendpaths and asks them to delete their cached attribute map
00778 ***********************************************************************************************/
00779 
00780 void BrushRef::FreeAttributes()
00781 {
00782 //  BlendPath* pLastPath = NULL;
00783     BlendPath* pBlendPath = GetFirstBlendPath();
00784     while (pBlendPath != NULL)
00785     {
00786         pBlendPath->SetFreeAttributeFlag(TRUE);
00787         pBlendPath = GetNextBlendPath(pBlendPath);
00788     
00789     }
00790     //DeleteBitmapFills(); // disabled until I get it working properly
00791 }
00792 
00793 /***********************************************************************************************
00794 
00795 >   void BrushRef::TranslateTo(DocCoord Destination)
00796 
00797     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00798     Created:    7/12/99
00799     Inputs:     Destination - the coord to translateto
00800             
00801     Outputs:    -
00802     Returns:    -
00803     Purpose:    Translates the blendpaths and their applied attributes to Destination
00804 ***********************************************************************************************/
00805 
00806 void BrushRef::TranslateTo(DocCoord Destination)
00807 {
00808     BlendPath* pBlendPath = GetFirstBlendPath();
00809     CCAttrMap* pAttrMap = NULL;
00810     DocRect BRect;
00811     DocCoord CurrentCentre;
00812     Trans2DMatrix Trans;
00813 
00814     while (pBlendPath != NULL)
00815     {
00816         // find out where we are
00817         BRect = pBlendPath->m_pPath->GetBoundingRect();
00818         CurrentCentre = BRect.Centre();
00819 
00820         // set the translation in the matrix
00821         Trans.SetTransform(Destination.x - CurrentCentre.x, Destination.y - CurrentCentre.y);
00822         
00823         // we want to transform attributes too
00824         pAttrMap = pBlendPath->FindAppliedAttributes();
00825         if (pAttrMap == NULL)
00826         {
00827             ERROR3("No applied attributes");
00828         }
00829         else
00830         {
00831             pAttrMap->Transform(Trans);
00832             pAttrMap = NULL;
00833         }
00834         pBlendPath->Transform(Trans);
00835         
00836         pBlendPath = GetNextBlendPath(pBlendPath);
00837     }
00838 }
00839 
00840 
00841 /***********************************************************************************************
00842 
00843 >   void BrushRef::TransformBitmapAttributes(TransformBase& Trans)
00844 
00845     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00846     Created:    7/12/99
00847     Inputs:     Trans - the transformation to perform
00848             
00849     Outputs:    -
00850     Returns:    -
00851     Purpose:    When a brush stroke is transformed in the document we do not really need to transform
00852                 the blendpaths however we do need tot transform the attributes, otherwise bitmap
00853                 fills become incorrect as do line widths etc.
00854                 However if we transform all attributes then we also need to transform the blendpaths,
00855                 because such things as radial fills are translated by the brush code from the position
00856                 of the blendpaths.
00857                 It is important however that we do not scale the blendpaths, as the scaling code
00858                 assumes that they always stay the same size.
00859 ***********************************************************************************************/
00860 
00861 void BrushRef::TransformAttributes(TransformBase& Trans)
00862 {
00863     BlendPath          *pBlendPath = GetFirstBlendPath();
00864     CCAttrMap          *pAttrMap = NULL;
00865     
00866     CCRuntimeClass     *pType;
00867     void               *pVal;
00868     NodeAttribute      *pNodeAttr;
00869 
00870     while (pBlendPath != NULL)
00871     {   
00872         // we want to transform attributes too
00873         pAttrMap = pBlendPath->FindAppliedAttributes();
00874         if (pAttrMap == NULL)
00875         {
00876             ERROR3("No applied attributes");
00877         }
00878         else
00879         {
00880             // monster bodge - currently we only actually want to transform line widths and bitmap fills
00881             for( CCAttrMap::iterator Pos = pAttrMap->GetStartPosition(); Pos != pAttrMap->GetEndPosition(); )
00882             {
00883                 // Get attr at position Pos
00884                 pAttrMap->GetNextAssoc( Pos, pType, pVal );
00885 
00886                 // pVal is actually an attribute, so get a ptr to it and render it
00887                 pNodeAttr = (NodeAttribute *)pVal;
00888 
00889                 if (pNodeAttr->IsABitmapFill()) 
00890                     pNodeAttr->Transform(Trans);
00891             
00892                 if( pNodeAttr->IsALineWidthAttr() && FALSE != Trans.TransLines )
00893                 {
00894                     INT32 Test = labs( INT32(Trans.GetScalar().MakeDouble() * ((AttrLineWidth*)pNodeAttr)->Value.LineWidth) );
00895                     if (Test >= 10)
00896                         pNodeAttr->Transform(Trans);
00897                 }
00898                 
00899 
00900             }
00901 
00902             pAttrMap = NULL;        
00903         }
00904     
00905         pBlendPath = GetNextBlendPath(pBlendPath);
00906     }
00907     return;
00908 }
00909 
00910 /*---------------------------------------------------------------------------------------------
00911 -----------------------------------------------------------------------------------------------
00912 ------------------The BrushRefBlender Class----------------------------------------------------
00913 ----------------------------------------------------------------------------------------------*/
00914 
00915 /***********************************************************************************************
00916 
00917 > BrushRefBlender::BrushRefBlender()
00918 
00919     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00920     Created:    28/3/2000
00921     Inputs:     -
00922     Outputs:    -
00923     Returns:    -
00924     Purpose:    Default constructor.
00925 
00926 ***********************************************************************************************/
00927 
00928 BrushRefBlender::BrushRefBlender()
00929 {
00930     m_pStartBrushRef    = NULL;  
00931     m_pEndBrushRef      = NULL;
00932 
00933     m_pTempCoords       = NULL;
00934     m_pTempVerbs        = NULL;
00935     m_pTempFlags        = NULL;
00936     m_GBlendBuffSize    = 0;
00937     m_pGBlendBuff       = NULL;
00938     m_ArrayLength       = 0;
00939 }
00940 
00941 
00942 /***********************************************************************************************
00943 
00944 > BrushRefBlender::~BrushRefBlender()
00945 
00946     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00947     Created:    28/3/2000
00948     Inputs:     -
00949     Outputs:    -
00950     Returns:    -
00951     Purpose:    Default destructor.
00952 
00953 ***********************************************************************************************/
00954 
00955 BrushRefBlender::~BrushRefBlender()
00956 {
00957     DeallocTempBuffers();
00958 }
00959 
00960 /***********************************************************************************************
00961 
00962 >   void BrushRefBlender::SetBrushref(BrushRef* pBrushRef, BOOL Start)
00963 
00964     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00965     Created:    28/3/2000
00966     Inputs:     the brushref to set, and whether it is the first or last brushref
00967     Outputs:    -
00968     Returns:    -
00969     Purpose:    Default destructor.
00970 
00971 ***********************************************************************************************/
00972 
00973 void BrushRefBlender::SetBrushRef(BrushRef* pBrushRef, BOOL Start)
00974 {
00975     if (pBrushRef == NULL)
00976         return;
00977     if (Start)
00978         m_pStartBrushRef = pBrushRef;
00979     else
00980         m_pEndBrushRef = pBrushRef;
00981 }
00982 
00983 
00984 /***********************************************************************************************
00985 
00986 >   BrushRef*  BrushRefBlender::Blend(BrushRef* pStartBrush, BrushRef* pEndBrush, double Ratio)
00987 
00988     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00989     Created:    7/12/99
00990     Inputs:     pStartBrush - the first brushref to blend 
00991                 pEndBrush - the other brushref to blend to 
00992                 Ratio - the ratio of that to this
00993     Outputs:    
00994     Returns:    a newly allocated brushref created by blending this with pOther
00995     Purpose:    as above.  A lot of this code is similar to that of NodeBlender::CreateBlends, however
00996                 it is actuall used by the BrushComponent
00997 ***********************************************************************************************/
00998 
00999 BrushRef* BrushRefBlender::Blend(BrushRef* pStartBrush, BrushRef* pEndBrush, double Ratio)
01000 {
01001     if (pStartBrush == NULL || pEndBrush == NULL)
01002     {
01003         ERROR3("brush ref is NULL in BrushRef::Blend");
01004         return NULL;
01005     }
01006 
01007     if (Ratio < 0 || Ratio > 1)
01008     {
01009         ERROR3("Invalid blend ratio");
01010         return NULL;
01011     }
01012 
01013     // allocate the extra memory that we need
01014     if (!ReallocTempBuffers(1000))
01015         return NULL;
01016 
01017     // right, lets go to work.  The first thing to do is translate both sets of paths to 0,0
01018     // the reason for this is that in the course of its normal existence the blendpaths can get
01019     // translated all over the place, so in order for our blend to make sense they should at least
01020     // be centered in the same place
01021     // We will also want to store their current location in order to translate them back when we're done
01022 //  DocRect StartRect = pStartBrush->GetBoundingRect();
01023 //  DocRect EndRect   = pEndBrush->GetBoundingRect();
01024 //  DocCoord StartCoord = StartRect.Centre();
01025 //  DocCoord EndCoord   = EndRect.Centre();
01026 
01027 //  pStartBrush->TranslateTo(DocCoord(0,0));
01028 //  pEndBrush->TranslateTo(DocCoord(0,0));
01029 
01030 
01031     // Find num blend paths in start and end, and keep hold of the MAX value
01032     UINT32 NumPathsInStart = pStartBrush->GetNumBlendPaths();
01033     UINT32 NumPathsInEnd   = pEndBrush->GetNumBlendPaths();
01034     UINT32 MaxNumPaths   = max(NumPathsInStart,NumPathsInEnd);
01035 
01036     if (NumPathsInStart == 0 || NumPathsInEnd == 0)
01037         return NULL;
01038 
01039     // This object is used to step along the the two lists of objects choosing a pair to go and blend.
01040     // It mainly comes into play when there are different numbers of objects in the two lists.
01041     ListStepper Stepper;
01042     Stepper.Init(NumPathsInStart, NumPathsInEnd, 0);
01043     INT32 NextPathStart, NextPathEnd;
01044 
01045     //allocate our new brushref
01046     BrushRef* pBlendedBrushRef = new BrushRef;
01047     if (pBlendedBrushRef == NULL)
01048         return NULL;
01049 
01050     // set up our variables, they will be allocated in the loop (slow I know)
01051     Path*      pBlendedPath = NULL;
01052     BlendPath* pNewBlendPath = NULL;
01053     CCAttrMap* pBlendedAttrMap = NULL;
01054 
01055     // Get the first pair of objects to blend
01056     Stepper.GetNext(&NextPathStart,&NextPathEnd);
01057 
01058     // The first pair of blend paths become the current blend path pair
01059     // Get ptrs to these, plus the subpath IDs of these
01060     BlendPath*  pCurrBlendPathStart = pStartBrush->GetBlendPath(NextPathStart);
01061     BlendPath*  pCurrBlendPathEnd   = pEndBrush->GetBlendPath(NextPathEnd  );
01062     UINT32      CurrSubPathIDStart  = pCurrBlendPathStart->GetSubPathID();
01063     UINT32      CurrSubPathIDEnd    = pCurrBlendPathEnd  ->GetSubPathID();
01064 
01065     // We also need info on the next blend path pair, so get some vars ready
01066     BlendPath*  pNextBlendPathStart = NULL;
01067     BlendPath*  pNextBlendPathEnd   = NULL;
01068     UINT32      NextSubPathIDStart = CurrSubPathIDStart; // This was uninitialized - AMB guessed a good value
01069     UINT32      NextSubPathIDEnd = CurrSubPathIDEnd; // This was uninitialized - AMB guessed a good value
01070 
01071     for (UINT32 NextPath = 0; NextPath < MaxNumPaths; NextPath++)
01072     {
01073         // allocate the variables
01074         pBlendedPath = new Path;
01075         pBlendedAttrMap = new CCAttrMap(30);
01076         
01077         if (pBlendedPath == NULL || pBlendedAttrMap == NULL )
01078             goto ExitNull;
01079         if (!pBlendedPath->Initialise())
01080             goto ExitNull;
01081 
01082         // Get the next pair of objects to blend
01083         Stepper.GetNext(&NextPathStart,&NextPathEnd);
01084         
01085         // if we haven't run out then assign the next path variables
01086         if (NextPathStart >= 0 && NextPathEnd >= 0)
01087         {
01088             pNextBlendPathStart = pStartBrush->GetBlendPath(NextPathStart);
01089             pNextBlendPathEnd   = pEndBrush->GetBlendPath(NextPathEnd);
01090             NextSubPathIDStart  = pNextBlendPathStart->GetSubPathID();
01091             NextSubPathIDEnd    = pNextBlendPathEnd->GetSubPathID();
01092         }
01093     
01094 
01095         if (BlendAttributes(pCurrBlendPathStart, pCurrBlendPathEnd, pBlendedAttrMap, Ratio))
01096         {
01097             // Blend the paths together, putting the blended path in BlendedPath
01098             if (BlendPaths(pCurrBlendPathStart,pCurrBlendPathEnd,Ratio))
01099             {
01100                 // The blended path will be filled  if either of the paths are filled
01101                 // The blended path will be stroked if either of the paths are stroked
01102                 BOOL Filled  = pCurrBlendPathStart->IsFilled()  || pCurrBlendPathEnd->IsFilled();
01103                 BOOL Stroked = pCurrBlendPathStart->IsStroked() || pCurrBlendPathEnd->IsStroked();
01104                     
01105                 if (!pBlendedPath->MakeSpaceInPath(m_ArrayLength)) 
01106                     goto ExitNull;
01107                 pBlendedPath->MergeTwoPaths(m_pTempCoords,m_pTempVerbs,m_pTempFlags,m_ArrayLength,Filled);
01108                 pBlendedPath->IsFilled  = Filled;
01109                 pBlendedPath->IsStroked = Stroked;
01110                 
01111                 // We haven't yet got a complete path to render or pass back if next path has the same ID and is
01112                 // a different path
01113                 // (this applies to the start OR the end path)
01114                 BOOL NotACompletePath = ((CurrSubPathIDStart == NextSubPathIDStart && pCurrBlendPathStart != pNextBlendPathStart) ||
01115                     (CurrSubPathIDEnd   == NextSubPathIDEnd   && pCurrBlendPathEnd   != pNextBlendPathEnd  ));
01116                 
01117                 if (!NotACompletePath)
01118                 {   
01119                     // it all worked, lets allocate a new blendpath
01120                     pNewBlendPath = new BlendPath;
01121                     if (pNewBlendPath == NULL)
01122                         goto ExitNull;
01123                 
01124                     // tell it to use our blended path and attributes
01125                     pNewBlendPath->SetPath(pBlendedPath);
01126                     pNewBlendPath->SetAppliedAttributes(pBlendedAttrMap);
01127 
01128                     // give it to the brushref
01129                     pBlendedBrushRef->AddBlendPath(pNewBlendPath);
01130                 }
01131                 else
01132                     goto ExitNull;
01133 
01134                 pNewBlendPath = NULL;
01135                 pBlendedPath = NULL;
01136                 pBlendedAttrMap = NULL;
01137             }
01138             else // end if blendpaths
01139                 goto ExitNull;
01140         } // end if blendattributes
01141         else
01142             goto ExitNull;
01143     } // end for
01144 
01145 //  DeallocTempBuffers();
01146     
01147     // translate the brushes back
01148     //pStartBrush->TranslateTo(StartCoord);
01149     //pEndBrush->TranslateTo(EndCoord);
01150     return pBlendedBrushRef;
01151 
01152 // just so I don't have to keep repeating this code, if an allocation fails then come here where everything is deleted
01153 ExitNull:
01154     if (pBlendedPath != NULL)
01155         delete pBlendedPath;
01156     if (pBlendedBrushRef != NULL)
01157         delete pBlendedBrushRef;
01158     if (pBlendedAttrMap != NULL)
01159         delete pBlendedAttrMap;
01160     if (pNewBlendPath != NULL)
01161         delete pNewBlendPath;
01162     ERROR3("Something went wrong in BrushRefBlender::Blend");
01163     return NULL;
01164 }
01165 
01166 
01167 
01168 /********************************************************************************************
01169 
01170 >   DocCoord*  BrushRefBlender::GetCoordArray(UINT32 MinSize);
01171 
01172     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01173     Created:    7/11/94
01174     Inputs:     MinSize = min size the array should be
01175     Outputs:    -
01176     Returns:    Ptr to the array, or NULL if can't get memory
01177     Purpose:    Used to get an array you can write to.
01178     SeeAlso:    -
01179 
01180 ********************************************************************************************/
01181 
01182 DocCoord* BrushRefBlender::GetCoordArray(UINT32 MinSize)
01183 {
01184     MinSize++;
01185     if (m_TempArraySize >= MinSize) return m_pTempCoords;
01186 
01187     if (ReallocTempBuffers(MinSize))
01188         return m_pTempCoords;
01189     else
01190         return NULL;
01191 }
01192 
01193 /********************************************************************************************
01194 
01195 >   PathVerb*  BrushRefBlender::GetVerbArray(UINT32 MinSize);
01196 
01197     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01198     Created:    7/11/94
01199     Inputs:     MinSize = min size the array should be
01200     Outputs:    -
01201     Returns:    Ptr to the array, or NULL if can't get memory
01202     Purpose:    Used to get an array you can write to.
01203     SeeAlso:    -
01204 
01205 ********************************************************************************************/
01206 
01207 PathVerb* BrushRefBlender::GetVerbArray(UINT32 MinSize)
01208 {
01209     MinSize++;
01210     if (m_TempArraySize >= MinSize) return m_pTempVerbs;
01211 
01212     if (ReallocTempBuffers(MinSize))
01213         return m_pTempVerbs;
01214     else
01215         return NULL;
01216 }
01217 
01218 /********************************************************************************************
01219 
01220 >   PathFlags*  BrushRefBlender::GetFlagArray(UINT32 MinSize);
01221 
01222     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01223     Created:    7/11/94
01224     Inputs:     MinSize = min size the array should be
01225     Outputs:    -
01226     Returns:    Ptr to the array, or NULL if can't get memory
01227     Purpose:    Used to get an array you can write to.
01228     SeeAlso:    -
01229 
01230 ********************************************************************************************/
01231 
01232 PathFlags* BrushRefBlender::GetFlagArray(UINT32 MinSize)
01233 {
01234     MinSize++;
01235     if (m_TempArraySize >= MinSize) return m_pTempFlags;
01236 
01237     if (ReallocTempBuffers(MinSize))
01238         return m_pTempFlags;
01239     else
01240         return NULL;
01241 }
01242 
01243 /********************************************************************************************
01244 
01245 >   UINT32*  BrushRefBlender::GetGBlendBuff(UINT32 MinSize);
01246 
01247     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01248     Created:    7/11/94
01249     Inputs:     MinSize = min size the buffer should be
01250     Outputs:    -
01251     Returns:    Ptr to the buffer, or NULL if can't get memory
01252     Purpose:    Used to get a buffer you can write to.
01253     SeeAlso:    -
01254 
01255 ********************************************************************************************/
01256 
01257 UINT32* BrushRefBlender::GetGBlendBuff(UINT32 MinSize)
01258 {
01259     MinSize++;
01260     if (m_GBlendBuffSize >= MinSize) return m_pGBlendBuff;
01261 
01262     if (m_pGBlendBuff != NULL) CCFree(m_pGBlendBuff);
01263 
01264     m_pGBlendBuff = (UINT32*) CCMalloc(MinSize*sizeof(UINT32));
01265 
01266     if (m_pGBlendBuff != NULL)
01267         m_GBlendBuffSize = MinSize;
01268     else
01269         m_GBlendBuffSize = 0;
01270 
01271     return m_pGBlendBuff;
01272 }
01273 
01274 
01275 /********************************************************************************************
01276 
01277 > BOOL BrushRefBlender::ReallocTempBuffers(UINT32 Size)
01278 
01279     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01280     Created:    28/3/2000
01281     Inputs:     Size = Size the temp arrays should be
01282     Outputs:    -
01283     Returns:    -
01284     Purpose:    Allocates memory for the temp path arrays, and sets the size var to 0
01285                 You can use calls to GetCoordArray(), GetVerbArray() and GetFlagArray() to get the alloced arrays.
01286     SeeAlso:    -
01287 
01288 ********************************************************************************************/
01289 
01290 BOOL BrushRefBlender::ReallocTempBuffers(UINT32 Size)
01291 {
01292     DeallocTempBuffers();
01293 
01294     // Allocate the arrays
01295     m_TempArraySize = Size;
01296     m_pTempCoords   = (DocCoord*)  CCMalloc(Size*sizeof(DocCoord));
01297     m_pTempVerbs    = (PathVerb*)  CCMalloc(Size*sizeof(PathVerb));
01298     m_pTempFlags    = (PathFlags*) CCMalloc(Size*sizeof(PathFlags));
01299 
01300     // If any of the arrays are not allocated, dealloc the alloced ones, and return FALSE
01301     if (m_pTempCoords == NULL || m_pTempVerbs == NULL || m_pTempFlags == NULL)
01302     {
01303         DeallocTempBuffers();
01304         return FALSE;
01305     }
01306 
01307     // It's all OK, so return TRUE
01308     return TRUE;
01309 }
01310 
01311 /********************************************************************************************
01312 
01313 >   void BrushRefBlender::DeallocTempBuffers()
01314 
01315     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01316     Created:    28/3/2000
01317     Inputs:     -
01318     Outputs:    -
01319     Returns:    -
01320     Purpose:    Releases memory allocated for the temp path arrays, and sets the size var to 0
01321     SeeAlso:    -
01322 
01323 ********************************************************************************************/
01324 
01325 void BrushRefBlender::DeallocTempBuffers()
01326 {
01327     if (m_pTempCoords != NULL) { CCFree(m_pTempCoords); m_pTempCoords = NULL; }
01328     if (m_pTempVerbs  != NULL) { CCFree(m_pTempVerbs);  m_pTempVerbs  = NULL; }
01329     if (m_pTempFlags  != NULL) { CCFree(m_pTempFlags);  m_pTempFlags  = NULL; }
01330     m_TempArraySize = 0;
01331 
01332     if (m_pGBlendBuff != NULL) { CCFree(m_pGBlendBuff); m_pGBlendBuff = NULL; }
01333     m_GBlendBuffSize = 0;
01334 }
01335 
01336 
01337 /********************************************************************************************
01338 
01339 >   BOOL BrushRefBlender::BlendAttributes(BlendPath* pBlendPathStart, BlendPath* pBlendPathEnd,
01340                                     CCAttrMap* pBlendedAttrMap,double BlendRatio)
01341 
01342     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01343     Created:    27/3/2000
01344     Inputs:     
01345                 pBlendPathStart     = ptr to blend path to blend from
01346                 pBlendPathEnd       = ptr to blend path to blend to
01347                 pBlendedAttrMap     = ptr to map to store the blended attributes in
01348                 BlendRatio          = amount to blend by (0.0 <= BlendPath <= 1.0)
01349     Outputs:    -
01350     Returns:    TRUE if successful, FALSE otherwise
01351     Purpose:    Blends the attributes of the two BlendPath objects by the amount specified in BlendRatio
01352                 This is pretty much the same as the fn. by the same name in NodeBlender
01353     SeeAlso:    -
01354 
01355 ********************************************************************************************/
01356 
01357 BOOL BrushRefBlender::BlendAttributes( BlendPath* pBlendPathStart, BlendPath* pBlendPathEnd,
01358                                CCAttrMap* pBlendedAttrMap,double BlendRatio)
01359 {
01360     // Check entry params
01361     BOOL ok = (pBlendPathStart != NULL &&
01362                 pBlendPathEnd != NULL && pBlendedAttrMap != NULL);
01363     ERROR3IF(!ok,"One or more NULL entry params");
01364     if (!ok) return FALSE;
01365 
01366     // Find the attributes that are applied to the blend paths
01367     CCAttrMap* pAttrMapStart = pBlendPathStart->FindAppliedAttributes();
01368     CCAttrMap* pAttrMapEnd   = pBlendPathEnd->FindAppliedAttributes();
01369 
01370     // If either are NULL, return FALSE
01371     if (pAttrMapStart == NULL || pAttrMapEnd == NULL) return FALSE;
01372 
01373     // These vars are used as params to the CCAttrMap funcs
01374     CCRuntimeClass     *pTypeStart;
01375     void               *pValStart;
01376     void               *pValEnd;
01377     double              OldBlendRatio = BlendRatio;
01378     // Process each attribute in turn
01379     CCAttrMap::iterator PosStart = pAttrMapStart->GetStartPosition();
01380     for (;PosStart != pAttrMapStart->GetEndPosition();)
01381     {
01382         // Get a ptr to the attr at position PosStart in the start node's attr map
01383         pAttrMapStart->GetNextAssoc( PosStart, pTypeStart, pValStart );
01384         NodeAttribute* pNodeAttrStart = (NodeAttribute *)pValStart;
01385     
01386         BlendRatio = OldBlendRatio; 
01387         // Diccon 10/99 When using non-linear profiles for the objects those attributes
01388         // that make use of control points were not being profiled, making the objects look strange.
01389         // to avoid this those attributes now share the same profiles as the objects.
01390     /*  if (pNodeAttrStart->IsAGradFill())
01391         {
01392         
01393             if (!((AttrFillGeometry*)pNodeAttrStart)->IsAColourFill())
01394             {
01395                 
01396                 BlendRatio = GetObjectRatio();
01397             
01398             }
01399             else
01400             {
01401                 BlendRatio = GetInvertedAttributeRatio();
01402             
01403             }
01404 
01405         }
01406         if (pNodeAttrStart->IsAFlatFill() || (pNodeAttrStart->GetRuntimeClass() == CC_RUNTIME_CLASS(AttrLineWidth)))
01407         {
01408             BlendRatio = GetInvertedAttributeRatio();
01409         }
01410 
01411         */      
01412         // Get a blended attribute
01413         NodeAttribute* pBlendedNodeAttr = NULL;
01414 
01415         // Find an attr of the same type in the end object's attr list,
01416         // and blend the two attrs together
01417         if( pAttrMapEnd->Lookup( pTypeStart, pValEnd ) )
01418         {
01419             // We've found a matching end attr, so try to blend it with the start attr
01420 
01421             // Set up the param object to pass to the start attr's blend method
01422             BlendAttrParam BlendParam;
01423             
01424             // Initialise the BlendParam with the end attr and blend ratio
01425             if (BlendParam.Init(NULL,
01426                                 (NodeAttribute *)pValEnd,BlendRatio,COLOURBLEND_FADE,
01427                                 pAttrMapStart, pAttrMapEnd))
01428             {
01429                 // Successfully initialised, so now try blending the attributes
01430                 if (pNodeAttrStart->Blend(&BlendParam))
01431                 {
01432                     // Attrs successfully blended, now get a ptr to the new attr.
01433                     // Once we get the blended attr ptr, it belongs to us, so we have
01434                     // to delete it when it is not needed
01435                     pBlendedNodeAttr = BlendParam.GetBlendedAttr();
01436                 }
01437             }
01438         }
01439 
01440         // If we have a blended attr, pBlendedNodeAttr != NULL
01441         if (pBlendedNodeAttr != NULL)
01442         {
01443             // Get the type of the blended attr
01444             CCRuntimeClass *pTypeBlend = pBlendedNodeAttr->GetAttributeType();
01445             void       *pValBlend;
01446 
01447             // If we already have an attr in the blended attr map of the same type,
01448             // remove it and delete it, before inserting a new attr of this type
01449             if (pBlendedAttrMap->Lookup(pTypeBlend,pValBlend))
01450             {
01451                 if (pValBlend != NULL)
01452                 {
01453                     pBlendedAttrMap->RemoveKey(pTypeBlend);
01454                     delete (NodeAttribute*)pValBlend;
01455                 }
01456             }
01457             // add it to the blend map
01458             pBlendedAttrMap->SetAt( pTypeBlend, pBlendedNodeAttr );
01459         }
01460     }
01461 
01462 
01463     return TRUE;
01464 }
01465 
01466 
01467 /********************************************************************************************
01468 
01469 >   BOOL BrushRefBlender::BlendPaths(BlendPath* pBlendPathStart,BlendPath* pBlendPathEnd,double BlendRatio)
01470 
01471     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01472     Created:    27/3/2000
01473     Inputs:     pBlendPathStart = ptr to blend path to blend from
01474                 pBlendPathEnd   = ptr to blend path to blend to
01475                 BlendRatio      = amount to blend by (0.0 <= BlendPath <= 1.0)
01476     Outputs:    The blended path is stored in three arrays: the coords, the verbs, and the flags.
01477                 The arrays are:
01478     
01479                     pTempCoords
01480                     pTempVerbs
01481                     pTempFlags
01482 
01483                     ArrayLength = the length of all three arrays
01484 
01485                 This allows the caller to decide what to do with the blended path in a very flexible way.
01486 
01487     Returns:    TRUE if successful, FALSE otherwise
01488     Purpose:    Blends two BlendPath objects by the amount specified in BlendRatio
01489                 This is pretty much the same as the fn. by the same name in NodeBlender
01490     SeeAlso:
01491 
01492 ********************************************************************************************/
01493 
01494 BOOL BrushRefBlender::BlendPaths(BlendPath* pBlendPathStart,BlendPath* pBlendPathEnd,double BlendRatio)
01495 {
01496     // Check entry params
01497     BOOL    ok = (pBlendPathStart != NULL && pBlendPathEnd != NULL);
01498     if (ok) ok = (pBlendPathStart->GetBlendNode() != NULL && pBlendPathEnd->GetBlendNode() != NULL);
01499     ERROR3IF(!ok,"One or more NULL entry params");
01500     if (!ok) return FALSE;
01501 
01502     // Get the types of the two paths
01503     PathTypeEnum PathTypeStart = pBlendPathStart->GetPathType();
01504     PathTypeEnum PathTypeEnd   = pBlendPathEnd  ->GetPathType();
01505 
01506     // The blended path will be closed if either of the paths is a shape
01507     BOOL Closed = (PathTypeStart == PATHTYPE_SHAPE) || (PathTypeEnd == PATHTYPE_SHAPE);
01508 
01509     Path * pPathStart = NULL;
01510 
01511     // Find the paths associated with the start and end blend paths
01512     if (pBlendPathStart->GetBlendNode()->IsNodePath())
01513     {
01514         pPathStart = &(((NodePath *)pBlendPathStart->GetBlendNode())->InkPath);
01515     }
01516     else
01517     {
01518         pPathStart = &(((NodePath *)((NodeCompound *)pBlendPathStart->GetBlendNode())->GetNodeToBlend())->InkPath);
01519     }
01520 
01521     Path * pPathEnd = NULL;
01522 
01523     if (pBlendPathEnd->GetBlendNode()->IsNodePath())
01524     {
01525         pPathEnd   = &(((NodePath *)pBlendPathEnd->GetBlendNode())->InkPath);
01526     }
01527     else
01528     {
01529         pPathEnd = &(((NodePath *)((NodeCompound *)pBlendPathEnd->GetBlendNode())->GetNodeToBlend())->InkPath);
01530     }
01531 
01532     // Calculate how large the arrays have to be to store the blended path definition
01533     INT32 DestPathSize = ((pPathStart->GetNumCoords()+pPathEnd->GetNumCoords())*3)+500;
01534 
01535     // Get some arrays used to hold the blended path data, and error if any are NULL
01536     DocCoord*   pDestCoords = GetCoordArray(DestPathSize);
01537     PathVerb*   pDestVerbs  = GetVerbArray(DestPathSize);
01538     PathFlags*  pDestFlags  = GetFlagArray(DestPathSize);
01539     UINT32*         pBuff       = GetGBlendBuff(DestPathSize);
01540     if (pDestCoords == NULL || pDestVerbs == NULL || pDestFlags == NULL || pBuff == NULL)
01541         return FALSE;
01542 
01543     // This section copes with the case when blending a line with a shape.
01544     // In this case we need to get a temp path the is actually a shape version of the line.
01545     // The line is simply reversed back onto itself to form a shape that would look identical to the 
01546     // line if rendered.  This allows the line to appear to open up to the shape when blended.
01547     Path Shape;
01548     if (PathTypeStart != PathTypeEnd)
01549     {
01550         BOOL ok = FALSE;
01551         if (!Shape.Initialise()) return FALSE;
01552 
01553         // if going from a line to a shape, convert the start path to a shape
01554         if (PathTypeStart == PATHTYPE_LINE && PathTypeEnd == PATHTYPE_SHAPE)
01555         {
01556             ok = NodeBlender::ConvertLineToShape(pPathStart,&Shape);
01557             pPathStart = &Shape;
01558         }
01559 
01560         // if going from a shape to a line, convert the end path to a shape
01561         if (PathTypeStart == PATHTYPE_SHAPE && PathTypeEnd == PATHTYPE_LINE)
01562         {
01563             ok = NodeBlender::ConvertLineToShape(pPathEnd,&Shape);
01564             pPathEnd = &Shape;
01565         }
01566 
01567         if (!ok) return FALSE;
01568     }
01569 
01570     BOOL OneToOne = FALSE;
01571     // Now actually blend the two paths
01572 
01573     GBlend GBlendObj;
01574 
01575     // Define the blend
01576     GBlendObj.Define(   (PPOINT)pPathStart->GetCoordArray(),    // Specify the start path
01577                         pPathStart->GetVerbArray(),
01578                         pPathStart->GetNumCoords(),
01579 
01580                         (PPOINT)pPathEnd  ->GetCoordArray(),    // Specify the end path
01581                         pPathEnd  ->GetVerbArray(),
01582                         pPathEnd  ->GetNumCoords(),
01583 
01584                         OneToOne,                               // The one-to-one flag
01585                         FLATNESS,                               // Flatness
01586 
01587                         pBuff,                                  // Buffer for GBlend to use
01588                         DestPathSize*sizeof(UINT32));           // The buffer size
01589 
01590     // Blend the paths
01591     m_ArrayLength = GBlendObj.Blend(BlendRatio,                 // The blend ratio, 0.0 < BlendRatio < 1.0
01592                                     (PPOINT)pDestCoords,        // Array to store blended coords
01593                                     pDestVerbs,                 // Array to store blended verbs
01594                                     DestPathSize);              // The num elements in the two arrays
01595 
01596 
01597     // If we're blending a line to another line, we need to make sure that the blended line
01598     // is going in a direction that corresponds to the source lines.  This ensures attributes
01599     // that depend on this direction (e.g. start and end arrows) look correct.
01600     //
01601     // When creating blend paths of lines, we can detect if the blend path has been reversed,
01602     // in relation to the original path, by the original mapping value.
01603     // If it's 0 it has NOT been reversed, otherwise it's been reversed.
01604     //
01605     // If the blend ratio is <=0.5, the blended path is closest to the start blend path,
01606     // so we look at the start blend path's original mapping.
01607     //
01608     // If blend ration > 0.5, look at the end blend path's original mapping.
01609     //
01610     // The (BlendRation <= 0.5) cut-off point is the same as the cut-off point used in the blending
01611     // of attributes.
01612     if (pBlendPathStart->IsLine() && pBlendPathEnd->IsLine())
01613     {
01614         BlendPath* pBlendPath;
01615         if (BlendRatio <= 0.5) 
01616             pBlendPath = pBlendPathStart;
01617         else
01618             pBlendPath = pBlendPathEnd;
01619 
01620         if (pBlendPath->GetOrigMapping() != 0)
01621             NodeBlender::ReversePath(pDestCoords,pDestVerbs,m_ArrayLength);
01622     }
01623 
01624     // We need to do some work on the blended path
01625     if (!NodeBlender::ProcessBlendedPath(pDestCoords,pDestVerbs,pDestFlags,m_ArrayLength,Closed))
01626         return FALSE;
01627 
01628     return TRUE;
01629 }
01630 
01631 

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