colcomp.cpp

Go to the documentation of this file.
00001 // $Id: colcomp.cpp 1315 2006-06-14 09:51:34Z 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 // The document component for the document's colour list.
00100 
00101 /*
00102 */
00103 
00104 #include "camtypes.h"
00105 
00106 #include "colcomp.h"
00107 
00108 //#include "basedoc.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00110 #include "collist.h"
00111 #include "colormgr.h"
00112 //#include "colmodel.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00113 #include "aw_eps.h"
00114 #include "cameleps.h"
00115 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00116 #include "ccdc.h"
00117 #include "colourix.h"
00118 //#include "doccolor.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00119 //#include "tim.h"
00120 //#include "resource.h"
00121 //#include "grndrgn.h"
00122 #include "impcol.h"
00123 //#include "jason.h"
00124 #include "unicdman.h"
00125 //#include "sgcolour.h"
00126 
00127 //#include "camfiltr.h" // BaseCamelotFilter - version 2 native filter - in camtypes.h [AUTOMATICALLY REMOVED]
00128 #include "cxftags.h"    // TAG_DEFINERGBCOLOUR TAG_DEFINECOMPLEXCOLOUR
00129 //#include "cxfdefs.h"  // SIZE_DEFINERGBCOLOUR SIZE_DEFINECOMPLEXCOLOUR - in camtypes.h [AUTOMATICALLY REMOVED]
00130 #include "cxfcols.h"    // REF_DEFAULTCOLOUR_TRANSPARENT
00131 #include "cxfile.h"     // CXF_UNKNOWN_SIZE
00132 #include "expcol.h"     // ExportedColours handling class
00133 //#include "cxfrec.h"       // CXaraFileRecord handler - in camtypes.h [AUTOMATICALLY REMOVED]
00134 //#include "filtrres.h" // _R(IDS_NATIVE_COLOURWARNING)
00135 
00136 DECLARE_SOURCE("$Revision: 1315 $");
00137 
00138 // Declare smart memory handling in Debug builds
00139 #define new CAM_DEBUG_NEW
00140 
00141 CC_IMPLEMENT_DYNAMIC(ColourListComponentClass,  DocComponentClass)
00142 CC_IMPLEMENT_DYNAMIC(ColourListComponent,       DocComponent)
00143 
00144 // The error limit to use when comparing colour definitions
00145 #define COL_ACCURACY (0.00001)
00146 
00147 // This is our special linked value for native/web files
00148 const FIXED24 LinkValue = FIXED24(-8.0);
00149 
00150 // If we do no load a colour definition, then this is the colour that we will use instead
00151 #define REPLACEMENTCOLOUR COLOUR_BLACK
00152 
00153 // WEBSTER - markn 14/2/97
00154 // Introduced WEBSTER_IGNORE_NAME_MATCHING so that Webster can ignore the name when
00155 // trying to find an identical colour
00156 // Set to FALSE if you want it to behave the same as v1.5
00157 #ifndef WEBSTER
00158 #define WEBSTER_IGNORE_NAME_MATCHING FALSE
00159 #else
00160 #define WEBSTER_IGNORE_NAME_MATCHING TRUE
00161 #endif // WEBSTER
00162 
00163 /********************************************************************************************
00164 ********************************************************************************************/
00165 
00166 /********************************************************************************************
00167 
00168 >   BOOL ColourListComponentClass::Init()
00169 
00170     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00171     Created:    02/08/94
00172     Returns:    TRUE if all went well;
00173                 FALSE if not.
00174     Purpose:    Register the colour list document component with the main application.
00175     Errors:     Out of memory.
00176     SeeAlso:    DocComponent
00177 
00178 ********************************************************************************************/
00179 
00180 BOOL ColourListComponentClass::Init()
00181 {
00182     // Instantiate a component class to register with the application.
00183     ColourListComponentClass *pClass = new ColourListComponentClass;
00184     if (pClass == NULL)
00185         return FALSE;
00186 
00187     // Register it
00188     GetApplication()->RegisterDocComponent(pClass);
00189 
00190     // All ok
00191     return TRUE;
00192 }
00193 
00194 
00195 /********************************************************************************************
00196 
00197 >   BOOL ColourListComponentClass::AddComponent(BaseDocument *pDocument)
00198 
00199     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00200     Created:    02/08/94
00201     Inputs:     pDocument - the document to add the colour list to.
00202     Returns:    TRUE if the colour list was added ok;
00203                 FALSE if not.
00204     Purpose:    Add a colour list component to the specified document.
00205     Errors:     Out of memory
00206     SeeAlso:    ColourListComponentClass
00207 
00208 ********************************************************************************************/
00209 
00210 BOOL ColourListComponentClass::AddComponent(BaseDocument *pDocument)
00211 {
00212     // Check to see if this document already has a colour list; if so, leave it alone.
00213     if (pDocument->GetDocComponent(CC_RUNTIME_CLASS(ColourListComponent)) != NULL)
00214         return TRUE;
00215 
00216     // No colour list - try to create a new one for this document.
00217     ColourList *pList = new ColourList;
00218     if(pList == NULL)
00219         return FALSE;
00220 
00221     pList->Init( pDocument );       // Let the ColourList know what its parent document is
00222 
00223     // Ok - create the colour list component using this list.
00224     ColourListComponent *pComponent = new ColourListComponent(pList);
00225     if (pComponent == NULL)
00226     {
00227         // Out of memory...
00228         delete pList;
00229         return FALSE;
00230     }
00231 
00232     // All ok - add the component to the document.
00233     pDocument->AddDocComponent(pComponent);
00234     return true;
00235 }
00236 
00237 
00238 
00239 /********************************************************************************************
00240 
00241 >   ColourListComponent::ColourListComponent()
00242 
00243     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00244     Created:    8/11/94
00245     Purpose:    Construct a colour list component. DO NOT use this constructor. It gives
00246                 and ERROR3 (and sets up this in a semi-safe default state)
00247     SeeAlso:    ColourListComponent
00248 
00249 ********************************************************************************************/
00250 
00251 ColourListComponent::ColourListComponent()
00252 {
00253     ERROR3("ColourListComponent constructed with default constructor!?\n");
00254     
00255     // We don't have a colour list! Eek!
00256     pIndexedColours = NULL;
00257 
00258     // Initialise importer colour maps etc
00259     pNewColours = NULL;
00260 
00261     // Initialise Exporter colour list
00262     pExportedColours = NULL;
00263     
00264     // Initialise IndexedColour ComponentCopy array pointers
00265     SourceColours   = NULL;
00266     DestColours     = NULL;
00267     ColourTableSize = 32;
00268 
00269     // Our link to the BaseCamelotFilter
00270     pCamFilter = NULL;
00271     // Set our variable so that we warn about a possible replacement only once
00272     WarnedBefore = FALSE;
00273 }
00274 
00275 
00276 
00277 /********************************************************************************************
00278 
00279 >   ColourListComponent::ColourListComponent(ColourList *pColList)
00280 
00281     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00282     Created:    02/08/94
00283     Inputs:     pColList - the colour list to use for this colour list componet.
00284     Purpose:    Construct a colour list component using the given colour list.
00285 
00286     Notes:      NOTE that the list you pass in now "belongs" to this CLC, and it
00287                 will be automatically deleted when you delete this CLC object.
00288 
00289     Errors:     ENSURE if pColList is NULL.
00290     SeeAlso:    ColourListComponent
00291 
00292 ********************************************************************************************/
00293 
00294 ColourListComponent::ColourListComponent(ColourList *pColList)
00295 {
00296     ENSURE(pColList != NULL, "NULL colour list in colour list component constructor!");
00297 
00298     // Install this colour list.
00299     pIndexedColours = pColList;
00300 
00301     // Initialise importer colour tables etc
00302     pNewColours = NULL;
00303 
00304     // Initialise Exporter colour list
00305     pExportedColours = NULL;
00306 
00307     // Initialise IndexedColour ComponentCopy array pointers
00308     SourceColours   = NULL;
00309     DestColours     = NULL;
00310     ColourTableSize = 32;
00311 
00312     // Our link to the BaseCamelotFilter
00313     pCamFilter = NULL;
00314     // Set our variable so that we warn about a possible replacement only once
00315     WarnedBefore = FALSE;
00316 }
00317 
00318 /********************************************************************************************
00319 
00320 >   ColourListComponent::~ColourListComponent()
00321 
00322     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00323     Created:    08/09/94
00324     Purpose:    Clean up a colour list component's data structures - deletes the colour
00325                 list.
00326     Errors:     ENSURE if IndexedColour copying stuff has not been cleaned up (this will
00327                 occur if End/AbortComponentCopy is not called after a component copy)
00328     SeeAlso:    ColourListComponent
00329 
00330 ********************************************************************************************/
00331 
00332 ColourListComponent::~ColourListComponent()
00333 {
00334     // Delete our colour list.
00335     if (pIndexedColours != NULL)
00336     {
00337         pIndexedColours->DeleteAll();
00338 
00339         delete pIndexedColours;
00340         pIndexedColours = NULL;
00341     }
00342 
00343     // Sanity check to see if we've done something terrible...
00344     ENSURE(SourceColours == NULL && DestColours == NULL,
00345             "Someone failed to EndComponentCopy before destructing a ColourListComponent");
00346 
00347     // As we have finished with it now, destroy the list of exported colours
00348     if (pExportedColours)
00349     {
00350         delete pExportedColours;
00351         pExportedColours = NULL;
00352     }
00353 }
00354 
00355 /********************************************************************************************
00356 ********************************************************************************************/
00357 
00358 // Saving/loading code for the new native/web file format
00359 
00360 /********************************************************************************************
00361 ********************************************************************************************/
00362 
00363 /********************************************************************************************
00364 
00365 >   BOOL ColourListComponent::StartImport(BaseCamelotFilter *pFilter)
00366 
00367     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00368     Created:    21/5/96
00369     Inputs:     pFilter - the BaseCamelotFilter filter that is being used to import a file.
00370     Returns:    TRUE if the component was able to prepare for importing;
00371                 FALSE if not (e.g. out of memory)
00372     Purpose:    Inform the colour list document component that a Native or Web import is
00373                 about to start.
00374     SeeAlso:    DocComponent
00375 
00376 ********************************************************************************************/
00377 
00378 BOOL ColourListComponent::StartImport(BaseCamelotFilter *pFilter)
00379 {
00380 TRACEUSER( "Neville",_T("ColourListComponent::StartImport\n") );
00381     if (pFilter == NULL)
00382     {
00383         ERROR3("ColourListComponent::StartImport filter is null!");
00384         return TRUE;
00385     }
00386 
00387     // Save this in our link to the BaseCamelotFilter
00388     pCamFilter = pFilter;
00389     // Set our variable so that we warn about a possible replacement only once
00390     WarnedBefore = FALSE;
00391     
00392     // Get a colour table and don't do strict checking (as per Camelot EPS and Native EPS).
00393     pNewColours = new ImportedColours(this, FALSE);
00394     if ((pNewColours == NULL) || !pNewColours->Init())
00395         return FALSE;
00396 
00397     // We keep a record of how nested we are with respect to linking colours, e.g.
00398     // links of links of links.
00399     // A nesting of 0 is no nesting.
00400     // Do this so that we are consistent with the EPS form
00401     LinkNesting = 0;
00402 
00403     return TRUE;
00404 }
00405 
00406 /********************************************************************************************
00407 
00408 >   BOOL ColourListComponent::EndImport(BaseCamelotFilter *pFilter, BOOL Success)
00409 
00410     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00411     Created:    21/5/96
00412     Inputs:     pFilter - the BaseCamelotFilter filter that is being used to import a file.
00413                 Success - TRUE => The import was successful;
00414                          FALSE => The import failed - abandon any changes.
00415     Returns:    TRUE if the component was able to end the importing;
00416                 FALSE if not (e.g. out of memory)
00417     Purpose:    Inform the colour list document component that a Native or Web import has
00418                 just finished.
00419     SeeAlso:    DocComponent
00420 
00421 ********************************************************************************************/
00422 
00423 BOOL ColourListComponent::EndImport(BaseCamelotFilter *pFilter, BOOL Success)
00424 {
00425 TRACEUSER( "Neville", _T("ColourListComponent::EndImport\n") );
00426     if (pFilter == NULL)
00427     {
00428         ERROR3("ColourListComponent::EndImport filter is null!");
00429         return TRUE;
00430     }
00431 
00432     // If we didn't even get to initialise, then return quietly.
00433     if (pNewColours == NULL)
00434     {
00435         ERROR3("ColourListComponent::EndImport pNewColours is null!");
00436         return TRUE;
00437     }
00438 
00439     // Import is finished, so add any outstanding colours to the document (if the
00440     // import was successful), and delete the colour table
00441     if (Success)
00442     {
00443         // Try and sort the imported colour list by the entry number that was saved
00444         // in the colour definition on export. This was the colour's position in 
00445         // the indexed colour list.
00446         pNewColours->SortColoursByEntryNumber();
00447         
00448         // Adds the colours to the system, with undo
00449         pNewColours->AddColoursToDocument();
00450     }
00451     else
00452     {
00453         // Import failed - destroy all the colours.
00454         pNewColours->DestroyColours();
00455     }
00456 
00457     // Finally, delete the IndexedColour table.
00458     delete pNewColours;
00459     pNewColours = NULL;
00460 
00461     // Null our link to the BaseCamelotFilter
00462     pCamFilter = NULL;
00463     // Set our variable so that we warn about a possible replacement only once
00464     WarnedBefore = FALSE;
00465 
00466     return TRUE;
00467 }
00468 
00469 /********************************************************************************************
00470 
00471 >   BOOL ColourListComponent::GetDocColour(INT32 ColourRef, CXaraFileRecord* pCXFileRec, DocColour* pDocColour)
00472 
00473     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00474     Created:    30/5/96
00475     Inputs:     ColourRef   - The colour reference or record number that the record handler has loaded
00476                             from the record.
00477     Outputs:    pDocColour  - A pointer to return the required doc colour in
00478     Returns:    TRUE if the colour reference was succesfully converted into a DocColour;
00479                 FALSE if not (e.g. out of memory)
00480     Purpose:    Try and convert a colour reference i.e. record number into a previously
00481                 imported colour definition which should now be an indexed colour in the document.
00482     SeeAlso:    ColourRecordHandler; 
00483 
00484 ********************************************************************************************/
00485 
00486 BOOL ColourListComponent::GetDocColour(INT32 ColourRef, DocColour* pDocColour)
00487 {
00488     ERROR2IF(pDocColour == NULL,FALSE,"ColourListComponent::GetDocColour NULL pCXFileRec");
00489     ERROR2IF(pNewColours == NULL,FALSE,"ColourListComponent::ImportSimpleColour NULL pNewColours");
00490 //TRACEUSER( "Neville", _T("GetDocColour for ref %d\n"), ColourRef);
00491     
00492     // First check to see if the colour refers to any of the built in colours.
00493     // These will have negative record numbers
00494     if (ColourRef < 0)
00495     {
00496         // At present, we only use the one colour reference
00497         StockColour defaultcolour = COLOUR_NONE;
00498         switch (ColourRef)
00499         {
00500             case REF_DEFAULTCOLOUR_TRANSPARENT:
00501                 defaultcolour = COLOUR_TRANS;
00502                 break;
00503             case REF_DEFAULTCOLOUR_BLACK:
00504                 defaultcolour = COLOUR_BLACK;
00505                 break;
00506             case REF_DEFAULTCOLOUR_WHITE:
00507                 defaultcolour = COLOUR_WHITE;
00508                 break;
00509             case REF_DEFAULTCOLOUR_RED:
00510                 defaultcolour = COLOUR_RED;
00511                 break;
00512             case REF_DEFAULTCOLOUR_GREEN:
00513                 defaultcolour = COLOUR_GREEN;
00514                 break;
00515             case REF_DEFAULTCOLOUR_BLUE:
00516                 defaultcolour = COLOUR_BLUE;
00517                 break;
00518             case REF_DEFAULTCOLOUR_CYAN:
00519                 defaultcolour = COLOUR_CYAN;
00520                 break;
00521             case REF_DEFAULTCOLOUR_MAGENTA:
00522                 defaultcolour = COLOUR_MAGENTA;
00523                 break;
00524             case REF_DEFAULTCOLOUR_YELLOW:
00525                 defaultcolour = COLOUR_YELLOW;
00526                 break;
00527             default:
00528             {
00529                 defaultcolour = REPLACEMENTCOLOUR;
00530                 // It is an unknown default colour reference
00531                 // We will warn the user and use a replacement colour instead
00532                 // If we have a pFilter then ask the default warning handle to append our message
00533                 if (pCamFilter)
00534                 {
00535                     if (!WarnedBefore)
00536                     {
00537                         pCamFilter->AppendWarning(_R(IDS_NATIVE_COLOURWARNING));
00538                         WarnedBefore = TRUE;
00539                     }
00540 
00541                 }
00542                 else
00543                     ERROR2(FALSE,"ColourListComponent::GetDocColour negative ColourRef is unknown");
00544                 break;
00545             }
00546         }
00547         
00548         // Make ourselves the required colour
00549         DocColour * pReplacementCol = new DocColour(defaultcolour);
00550         // Make the return colour this
00551         *pDocColour = *pReplacementCol;
00552         // And now delete that temp replacement colour
00553         delete pReplacementCol;
00554     }
00555     else
00556     {
00557         // In case of early exit set the return DocColour pointer to NULL, i.e. nothing found
00558         //*pDocColour = NULL;
00559 
00560         // Try and find the specified record number in our colour list
00561         IndexedColour *pCol = pNewColours->GetColour(ColourRef);
00562         // If not found then this is a problem as a colour must have been defined before its being
00563         // referenced 
00564         // We will warn the user and use a replacement colour instead
00565         if (pCol == NULL)
00566         {
00567             // If we have a pFilter then ask the default warning handle to append our message
00568             if (pCamFilter)
00569             {
00570                 if (!WarnedBefore)
00571                 {
00572                     pCamFilter->AppendWarning(_R(IDS_NATIVE_COLOURWARNING));
00573                     WarnedBefore = TRUE;
00574                 }
00575 
00576                 // Make ourselves a colour to use instead
00577                 DocColour * pReplacementCol =  new DocColour(REPLACEMENTCOLOUR);
00578                 // Make the return colour this
00579                 *pDocColour = *pReplacementCol;
00580                 // And now delete that temp replacement colour
00581                 delete pReplacementCol;
00582             }
00583             else
00584                 ERROR2(FALSE,"ColourListComponent::GetDocColour ColourRef cannot be found");
00585         }
00586         else
00587         {       
00588             // Make the specified DocColour referencing this IndexedColour.
00589             pDocColour->MakeRefToIndexedColour(pCol);
00590         }
00591     }
00592 
00593     return TRUE;
00594 }
00595 
00596 /********************************************************************************************
00597 
00598 >   BOOL ColourListComponent::ImportSimpleColour(CXaraFileRecord* pCXFileRec)
00599 
00600     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00601     Created:    30/5/96
00602     Inputs:     pCXFileRec - The CXaraFileRecord that is being used to provide read functions etc.
00603     Returns:    TRUE if the record was succesfully imported;
00604                 FALSE if not (e.g. out of memory)
00605     Purpose:    Try and import a simple RGB colour definition record into the document.
00606     SeeAlso:    ColourRecordHandler; 
00607 
00608 ********************************************************************************************/
00609 
00610 BOOL ColourListComponent::ImportSimpleColour(CXaraFileRecord* pCXFileRec)
00611 {
00612     ERROR2IF(pCXFileRec == NULL,FALSE,"ColourListComponent::ImportSimpleColour NULL pCXFileRec");
00613     ERROR2IF(pNewColours == NULL,FALSE,"ColourListComponent::ImportSimpleColour NULL pNewColours");
00614 
00615 //TRACEUSER( "Neville", _T("ImportSimpleColour\n"));
00616     // Read in the simple RGB colour
00617     BYTE Red;
00618     BYTE Green;
00619     BYTE Blue;
00620     BOOL ok = pCXFileRec->ReadBYTE(&Red);
00621     if (ok) ok = pCXFileRec->ReadBYTE(&Green);
00622     if (ok) ok = pCXFileRec->ReadBYTE(&Blue);
00623 
00624     NewColourInfo ColourInfo;
00625     // Flag we are importing a web/native style colour and so use the specified parent and not
00626     // the context form.
00627     ColourInfo.RecordNumber = pCXFileRec->GetRecordNumber();
00628     ColourInfo.WebNativeColour = TRUE;
00629     ColourRGBT NewRGBT;
00630     String_64 ColName; //(TEXT("_"));
00631     // Make the name unique by adding a text form of the record number 
00632     TCHAR              *pNewName = (TCHAR *)ColName;
00633     camSnprintf( pNewName, 64, _T("_%d"), ColourInfo.RecordNumber );
00634 
00635     NewRGBT.Red = (double)((double)Red/256.0);  
00636     NewRGBT.Green = (double)((double)Green/256.0);  
00637     NewRGBT.Blue = (double)((double)Blue/256.0);    
00638     if (ok) ok = pNewColours->AddColour(&ColName, &NewRGBT, &ColourInfo);
00639 
00640     return ok;
00641 }
00642 
00643 /********************************************************************************************
00644 
00645 >   BOOL ColourListComponent::ImportColourDefinition(CXaraFileRecord* pCXFileRec)
00646 
00647     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00648     Created:    28/5/96
00649     Inputs:     pCXFileRec - The CXaraFileRecord that is being used to provide read functions etc.
00650     Returns:    TRUE if the record was succesfully imported;
00651                 FALSE if not (e.g. out of memory)
00652     Purpose:    Try and import a colour definition record into the document.
00653     SeeAlso:    ColourRecordHandler; 
00654 
00655 ********************************************************************************************/
00656 
00657 BOOL ColourListComponent::ImportColourDefinition(CXaraFileRecord* pCXFileRec)
00658 {
00659     ERROR2IF(pCXFileRec == NULL,FALSE,"ColourListComponent::ImportColourDefinition NULL pCXFileRec");
00660     ERROR2IF(pNewColours == NULL,FALSE,"ColourListComponent::ImportColourDefinition NULL pNewColours");
00661     
00662 
00663     // Check for special types (NB a colour cannot be both a spot colour and a linked colour).
00664     NewColourInfo ColourInfo;
00665 //  BOOL Linked = FALSE;
00666     // Flag we are importing a web/native style colour and so use the specified parent and not
00667     // the context form.
00668     ColourInfo.RecordNumber = pCXFileRec->GetRecordNumber();
00669     ColourInfo.WebNativeColour = TRUE;
00670     //IndexedColour *pParent = NULL;
00671 
00672     // Read in the simple RGB colour, which we won't need
00673     BYTE Red;
00674     BYTE Green;
00675     BYTE Blue;
00676     BOOL ok = pCXFileRec->ReadBYTE(&Red);
00677     if (ok) ok = pCXFileRec->ReadBYTE(&Green);
00678     if (ok) ok = pCXFileRec->ReadBYTE(&Blue);
00679 
00680     // read in the colour model
00681     ColourModel ColModel = COLOURMODEL_RGBT;
00682     BYTE temp;
00683     if (ok) ok = pCXFileRec->ReadBYTE(&temp);
00684     ColModel = (ColourModel)temp;
00685 
00686     // read in the colour type
00687     ExportColourType ColType = EXPORT_COLOURTYPE_NORMAL;
00688     if (ok) ok = pCXFileRec->ReadBYTE(&temp);
00689     ColType = (ExportColourType)temp;
00690 
00691     // read in the entry number that this colour should be in the list of colours
00692     UINT32 EntryNumber = 0;
00693     if (ok) ok = pCXFileRec->ReadUINT32(&EntryNumber);
00694     ColourInfo.EntryNumber = EntryNumber;
00695 
00696     // read in the record number of the parent colour
00697     UINT32 ParentColour = 0;
00698     if (ok) ok = pCXFileRec->ReadUINT32(&ParentColour);
00699     // Now convert this into a indexed colour pointer, if required
00700     if (ok && (ColType == EXPORT_COLOURTYPE_LINKED || ColType == EXPORT_COLOURTYPE_TINT ||
00701         ColType == EXPORT_COLOURTYPE_SHADE))
00702     {
00703         TRACEUSER( "Neville", _T("Trying to find parent reference %d\n"),ParentColour);
00704         ColourInfo.pParentCol = pNewColours->GetColour(ParentColour);
00705         if (ColourInfo.pParentCol == NULL)
00706         {
00707             TRACEUSER( "Neville", _T("Cannot convert parent colour reference %d into an IndexedColour\n"),ParentColour);
00708             ERROR2(FALSE,"Cannot find parent IndexedColour");
00709         }
00710     }
00711 
00712     // Read in the four colour components
00713     UINT32 Comp1 = 0;
00714     if (ok) ok = pCXFileRec->ReadUINT32(&Comp1);
00715     UINT32 Comp2 = 0;
00716     if (ok) ok = pCXFileRec->ReadUINT32(&Comp2);
00717     UINT32 Comp3 = 0;
00718     if (ok) ok = pCXFileRec->ReadUINT32(&Comp3);
00719     UINT32 Comp4 = 0;
00720     if (ok) ok = pCXFileRec->ReadUINT32(&Comp4);
00721     
00722     String_64 ColName; 
00723     if (ok) ok = pCXFileRec->ReadUnicode(&ColName);//, ColName.MaxLength());
00724     
00725     if (ColName.Length() == 0 )
00726     {   
00727         // We are an unnamed colour and so make up a name based on the record number
00728         // This is so that all the existing import code can be reused.
00729         // Make the name unique by adding a text form of the record number 
00730         TCHAR          *pNewName = (TCHAR *)ColName;
00731         camSnprintf( pNewName, 64, _T("_%d"), ColourInfo.RecordNumber );
00732     }
00733 TRACEUSER( "Neville", _T("ImportColourDefinition Name %s RecordNumber %d, EntryNumber %d\n"),(TCHAR*)ColName,ColourInfo.RecordNumber,EntryNumber);
00734     
00735     // We had a problem reading the colour definition so stop now
00736     if (!ok)
00737         return FALSE;
00738 
00739     // Read the colour components according to the colour model.
00740     switch (ColType)
00741     {
00742         case EXPORT_COLOURTYPE_NORMAL:
00743                 // Set the correct colour type
00744                 ColourInfo.Type = COLOURTYPE_NORMAL;
00745                 // Fall through below
00746         case EXPORT_COLOURTYPE_SPOT:
00747         case EXPORT_COLOURTYPE_LINKED:
00748             // Set the correct colour type
00749             if (ColType == EXPORT_COLOURTYPE_SPOT)
00750                 ColourInfo.Type = COLOURTYPE_SPOT;
00751             else if (ColType == EXPORT_COLOURTYPE_LINKED)
00752                 ColourInfo.Type = COLOURTYPE_LINKED;
00753 
00754             // These all require the same handling
00755             // Linked colours save out the components in the normal fashion
00756             switch (ColModel)
00757             {
00758                 case COLOURMODEL_RGBT:
00759                     {
00760                         ColourRGBT NewRGBT;
00761                         ReadRGB(&NewRGBT, &ColourInfo, Comp1, Comp2, Comp3, Comp4);
00762                         if (!pNewColours->AddColour(&ColName, &NewRGBT, &ColourInfo))
00763                             return FALSE;
00764                     }
00765                     break;
00766 
00767                 case COLOURMODEL_CMYK:
00768                     {
00769                         ColourCMYK NewCMYK;
00770                         ReadCMYK(&NewCMYK, &ColourInfo, Comp1, Comp2, Comp3, Comp4);
00771                         if (!pNewColours->AddColour(&ColName, &NewCMYK, &ColourInfo))
00772                             return FALSE;
00773                     }
00774                     break;
00775 
00776                 case COLOURMODEL_HSVT:
00777                     {
00778                         ColourHSVT NewHSVT;
00779                         ReadHSV(&NewHSVT, &ColourInfo, Comp1, Comp2, Comp3, Comp4);
00780                         if (!pNewColours->AddColour(&ColName, &NewHSVT, &ColourInfo))
00781                             return FALSE;
00782                     }
00783                     break;
00784 
00785                 case COLOURMODEL_GREYT:
00786                     {
00787                         ColourGreyT NewGreyT;
00788                         ReadGrey(&NewGreyT, &ColourInfo, Comp1);
00789                         if (!pNewColours->AddColour(&ColName, &NewGreyT, &ColourInfo))
00790                             return FALSE;
00791                     }
00792                     break;
00793                 
00794                     default:
00795                         ERROR3("ColourListComponent::ImportColourDefinition unknown colour model!");
00796                         break;
00797             }
00798             break;
00799 
00800         case EXPORT_COLOURTYPE_TINT:
00801             {
00802                 // Set the correct colour type
00803                 ColourInfo.Type = COLOURTYPE_TINT;
00804 
00805                 // Read in the tint value from the colour definition record
00806                 ReadTint(&ColourInfo, Comp1);
00807 
00808                 // Now, try and add that to the system
00809                 if (!pNewColours->AddTintOrShade(&ColName, &ColourInfo))
00810                     return FALSE;
00811             }
00812             break;
00813 
00814         case EXPORT_COLOURTYPE_SHADE:
00815             {
00816                 // Set the correct colour type
00817                 ColourInfo.Type = COLOURTYPE_TINT;
00818 
00819                 // Read in the shade value from the colour definition record
00820                 ReadShade(&ColourInfo, Comp1, Comp2);
00821 
00822                 // Now, try and add that to the system
00823                 if (!pNewColours->AddTintOrShade(&ColName, &ColourInfo))
00824                     return FALSE;
00825             }
00826             break;
00827 
00828         default:
00829             ERROR3("ColourListComponent::ImportColourDefinition unknown colourtype!");
00830             break;
00831     }
00832 
00833     return ok;
00834 }
00835 
00836 /********************************************************************************************
00837 
00838 >   BOOL ColourListComponent::ReadRGB(ColourRGBT *pCol, NewColourInfo *pColourInfo,
00839                                       UINT32 Comp1, UINT32 Comp2, UINT32 Comp3, UINT32 Comp4)
00840 
00841     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00842     Created:    29/5/96
00843     Inputs:     pCol        - RGB colour data to fill in
00844                 pColourInfo - pointer to the colour info to fill in
00845                 Comp1 .. 4  - colour components read in from the record 
00846     Outputs:    The data in the pCol and pColourInfo will have been filled in
00847     Returns:    True if value read ok, False otherwise.
00848     Purpose:    Read the RGB values from a Camelot RGB colour definition record.
00849     SeeAlso:    ColourListComponent::ImportColourDefinition;
00850 
00851 ********************************************************************************************/
00852 
00853 BOOL ColourListComponent::ReadRGB(ColourRGBT *pCol, NewColourInfo *pColourInfo,
00854                                   UINT32 Comp1, UINT32 Comp2, UINT32 Comp3, UINT32 Comp4)
00855 {
00856     ERROR2IF(pCol == NULL,FALSE,"ColourListComponent::ReadRGB NULL pCol");
00857     ERROR2IF(pColourInfo == NULL,FALSE,"ColourListComponent::ReadRGB NULL pColourInfo");
00858 
00859     BOOL Linked = (pColourInfo != NULL) && (pColourInfo->Type == COLOURTYPE_LINKED);
00860 
00861     // read the Red colour component in
00862     FIXED24 Value24 = 0.0;
00863     Value24.SetAsFixed24(Comp1);
00864     if (Linked && (Value24 == LinkValue))
00865         pColourInfo->Inherits[0] = TRUE;
00866     else
00867         pCol->Red = Value24;
00868 
00869     // read the Green colour component in
00870     Value24.SetAsFixed24(Comp2);
00871     if (Linked && (Value24 == LinkValue))
00872         pColourInfo->Inherits[1] = TRUE;
00873     else
00874         pCol->Green = Value24;
00875 
00876     // read the Blue colour component in
00877     Value24.SetAsFixed24(Comp3);
00878     if (Linked && (Value24 == LinkValue))
00879         pColourInfo->Inherits[2] = TRUE;
00880     else
00881         pCol->Blue = Value24;
00882 
00883     // No transparency
00884     pCol->Transparent = 0.0;
00885 
00886     return TRUE;
00887 }
00888 
00889 /********************************************************************************************
00890 
00891 >   BOOL ColourListComponent::ReadCMYK(ColourCMYK *pCol, NewColourInfo *pColourInfo,
00892                                        UINT32 Comp1, UINT32 Comp2, UINT32 Comp3, UINT32 Comp4)
00893 
00894     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00895     Created:    29/5/96
00896     Inputs:     pCol    - RGB colour data to fill in
00897                 pColourInfo - pointer to the colour info to fill in             
00898                 Comp1 .. 4  - colour components read in from the record 
00899     Outputs:    The data in the pCol and pColourInfo will have been filled in
00900     Returns:    True if value read ok, False otherwise.
00901     Purpose:    Read the CMYK values from a Camelot CMYK colour definition record.
00902     SeeAlso:    ColourListComponent::ImportColourDefinition;
00903 
00904 ********************************************************************************************/
00905 
00906 BOOL ColourListComponent::ReadCMYK(ColourCMYK *pCol, NewColourInfo *pColourInfo,
00907                                    UINT32 Comp1, UINT32 Comp2, UINT32 Comp3, UINT32 Comp4)
00908 {
00909     ERROR2IF(pCol == NULL,FALSE,"ColourListComponent::ReadCMYK NULL pCol");
00910     ERROR2IF(pColourInfo == NULL,FALSE,"ColourListComponent::ReadCMYK NULL pColourInfo");
00911 
00912     BOOL Linked = (pColourInfo != NULL) && (pColourInfo->Type == COLOURTYPE_LINKED);
00913 
00914     // read the Cyan colour component in
00915     FIXED24 Value24 = 0.0;
00916     Value24.SetAsFixed24(Comp1);
00917     if (Linked && (Value24 == LinkValue))
00918         pColourInfo->Inherits[0] = TRUE;
00919     else
00920         pCol->Cyan = Value24;
00921 
00922     // read the Magenta colour component in
00923     Value24.SetAsFixed24(Comp2);
00924     if (Linked && (Value24 == LinkValue))
00925         pColourInfo->Inherits[1] = TRUE;
00926     else
00927         pCol->Magenta = Value24;
00928 
00929     // read the Yellow colour component in
00930     Value24.SetAsFixed24(Comp3);
00931     if (Linked && (Value24 == LinkValue))
00932         pColourInfo->Inherits[2] = TRUE;
00933     else
00934         pCol->Yellow = Value24;
00935 
00936     // read the Key colour component in
00937     Value24.SetAsFixed24(Comp4);
00938     if (Linked && (Value24 == LinkValue))
00939         pColourInfo->Inherits[3] = TRUE;
00940     else
00941         pCol->Key = Value24;
00942 
00943     return TRUE;
00944 }
00945 
00946 /********************************************************************************************
00947 
00948 >   BOOL ColourListComponent::ReadHSV(ColourHSVT *pCol, NewColourInfo *pColourInfo,
00949                                       UINT32 Comp1, UINT32 Comp2, UINT32 Comp3, UINT32 Comp4)
00950 
00951     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
00952     Created:    29/5/96
00953     Inputs:     pCol    - HSVT colour data to fill in
00954                 pColourInfo - pointer to the colour info to fill in             
00955                 Comp1 .. 4  - colour components read in from the record 
00956     Outputs:    The data in the pCol and pColourInfo will have been filled in
00957     Returns:    True if value read ok, False otherwise.
00958     Purpose:    Read the HSV values from a Camelot HSV colour definition record.
00959     SeeAlso:    ColourListComponent::ImportColourDefinition;
00960 
00961 ********************************************************************************************/
00962 
00963 BOOL ColourListComponent::ReadHSV(ColourHSVT *pCol, NewColourInfo *pColourInfo,
00964                                   UINT32 Comp1, UINT32 Comp2, UINT32 Comp3, UINT32 Comp4)
00965 {
00966     ERROR2IF(pCol == NULL,FALSE,"ColourListComponent::ReadHSV NULL pCol");
00967     ERROR2IF(pColourInfo == NULL,FALSE,"ColourListComponent::ReadHSV NULL pColourInfo");
00968 
00969     BOOL Linked = (pColourInfo != NULL) && (pColourInfo->Type == COLOURTYPE_LINKED);
00970 
00971     // read the Hue colour component in
00972     FIXED24 Value24 = 0.0;
00973     Value24.SetAsFixed24(Comp1);
00974     if (Linked && (Value24 == LinkValue))
00975         pColourInfo->Inherits[0] = TRUE;
00976     else
00977         pCol->Hue = Value24;
00978 
00979     // read the Saturation colour component in
00980     Value24.SetAsFixed24(Comp2);
00981     if (Linked && (Value24 == LinkValue))
00982         pColourInfo->Inherits[1] = TRUE;
00983     else
00984         pCol->Saturation = Value24;
00985 
00986     // read the Value colour component in
00987     Value24.SetAsFixed24(Comp3);
00988     if (Linked && (Value24 == LinkValue))
00989         pColourInfo->Inherits[2] = TRUE;
00990     else
00991         pCol->Value = Value24;
00992     
00993     // No transparency
00994     pCol->Transparent = 0.0;
00995 
00996     return TRUE;
00997 }
00998 
00999 /********************************************************************************************
01000 
01001 >   BOOL ColourListComponent::ReadGrey(ColourGreyT *pCol, NewColourInfo *pColourInfo, UINT32 Comp1)
01002 
01003     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01004     Created:    29/5/96
01005     Inputs:     pCol    - Grey colour data to fill in
01006                 pColourInfo - pointer to the colour info to fill in             
01007                 Comp1   - the first of the colour components read in from the record 
01008     Outputs:    The data in the pCol and pColourInfo will have been filled in
01009     Returns:    True if value read ok, False otherwise.
01010     Purpose:    Read the Grey values from a Camelot Grey colour definition record.
01011     SeeAlso:    ColourListComponent::ImportColourDefinition;
01012 
01013 ********************************************************************************************/
01014 
01015 BOOL ColourListComponent::ReadGrey(ColourGreyT *pCol, NewColourInfo *pColourInfo, UINT32 Comp1)
01016 {
01017     ERROR2IF(pCol == NULL,FALSE,"ColourListComponent::ReadGrey NULL pCol");
01018     ERROR2IF(pColourInfo == NULL,FALSE,"ColourListComponent::ReadGrey NULL pColourInfo");
01019 
01020     BOOL Linked = (pColourInfo != NULL) && (pColourInfo->Type == COLOURTYPE_LINKED);
01021 
01022     // read the grey Intensity colour component in
01023     FIXED24 Value24 = 0.0;
01024     Value24.SetAsFixed24(Comp1);
01025     if (Linked && (Value24 == LinkValue))
01026         pColourInfo->Inherits[0] = TRUE;
01027     else
01028         pCol->Intensity = Value24;
01029 
01030     // Clear the reserved words to 0.
01031     pCol->Reserved1 = 0.0;
01032     pCol->Reserved2 = 0.0;
01033 
01034     // No transparency
01035     pCol->Transparent = 0.0;
01036 
01037     return TRUE;
01038 }
01039 
01040 /********************************************************************************************
01041 
01042 >   BOOL ColourListComponent::ReadTint(NewColourInfo *pColourInfo, UINT32 Comp1)
01043 
01044     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01045     Created:    29/5/96
01046     Inputs:     pColourInfo - pointer to the colour info to fill in             
01047                 Comp1       - the first of the colour components read in from the record 
01048     Outputs:    The data in the pCol and pColourInfo will have been filled in
01049     Returns:    True if value read ok, False otherwise.
01050     Purpose:    Read the tint values from a Camelot tint colour definition record.
01051     SeeAlso:    ColourListComponent::ImportColourDefinition;
01052 
01053 ********************************************************************************************/
01054 
01055 BOOL ColourListComponent::ReadTint(NewColourInfo *pColourInfo, UINT32 Comp1)
01056 {
01057     ERROR2IF(pColourInfo == NULL,FALSE,"ColourListComponent::ReadTint NULL pColourInfo");
01058 
01059     BOOL Linked = (pColourInfo != NULL) && (pColourInfo->Type == COLOURTYPE_LINKED);
01060 
01061     // read the grey Intensity colour component in
01062     FIXED24 Value24 = 0.0;
01063     Value24.SetAsFixed24(Comp1);
01064     if (Linked && (Value24 == LinkValue))
01065         pColourInfo->Inherits[0] = TRUE;
01066 
01067     pColourInfo->TintValue = Value24;
01068 
01069     pColourInfo->Type = COLOURTYPE_TINT;
01070     // And flag the fact that this "tint" is a tint rather than a shade!
01071     pColourInfo->TintIsShade = FALSE;
01072 
01073     return TRUE;
01074 }
01075 
01076 /********************************************************************************************
01077 
01078 >   BOOL ColourListComponent::ReadShade(NewColourInfo *pColourInfo, UINT32 Comp1, UINT32 Comp2)
01079 
01080     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01081     Created:    29/5/96
01082     Inputs:     pColourInfo - pointer to the colour info to fill in             
01083                 Comp1 .. 2  - the first two colour components read in from the record 
01084     Outputs:    The data in the pCol and pColourInfo will have been filled in
01085     Returns:    True if value read ok, False otherwise.
01086     Purpose:    Read the shade values from a Camelot shade colour definition record.
01087     SeeAlso:    ColourListComponent::ImportColourDefinition;
01088 
01089 ********************************************************************************************/
01090 
01091 BOOL ColourListComponent::ReadShade(NewColourInfo *pColourInfo, UINT32 Comp1, UINT32 Comp2)
01092 {
01093     ERROR2IF(pColourInfo == NULL,FALSE,"ColourListComponent::ReadShade NULL pColourInfo");
01094 
01095     BOOL Linked = (pColourInfo != NULL) && (pColourInfo->Type == COLOURTYPE_LINKED);
01096 
01097     FIXED24 Value24 = 0.0;
01098     Value24.SetAsFixed24(Comp1);
01099     if (Linked && (Value24 == LinkValue))
01100         pColourInfo->Inherits[0] = TRUE;
01101     pColourInfo->TintValue = Value24;
01102 
01103     Value24.SetAsFixed24(Comp2);
01104     if (Linked && (Value24 == LinkValue))
01105         pColourInfo->Inherits[1] = TRUE;
01106     pColourInfo->ShadeValue = Value24;
01107 
01108     pColourInfo->Type = COLOURTYPE_TINT;
01109     // And flag the fact that this "tint" is a really a shade!
01110     pColourInfo->TintIsShade = TRUE;
01111 
01112     return TRUE;
01113 }
01114 
01115 
01116 /********************************************************************************************
01117 ********************************************************************************************/
01118 
01119 
01120 /********************************************************************************************
01121 
01122 >   BOOL ColourListComponent::StartExport(BaseCamelotFilter *pFilter)
01123 
01124     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01125     Created:    21/5/96
01126     Returns:    TRUE if the component was able to prepare for exporting;
01127                 FALSE if not (e.g. out of memory)
01128     Inputs:     pFilter - the BaseCamelotFilter filter that is being used to export a file.
01129     Purpose:    Inform the colour list document component that a WEb or Native export is
01130                 about to start.
01131     SeeAlso:    DocComponent
01132 
01133 ********************************************************************************************/
01134 
01135 BOOL ColourListComponent::StartExport(BaseCamelotFilter *pFilter)
01136 {
01137 #ifdef DO_EXPORT
01138 TRACEUSER( "Neville", _T("ColourListComponent::StartExport\n"));
01139     // Mark all colours as unsaved 
01140     if (pFilter == NULL)
01141     {
01142         ERROR3("ColourListComponent::StartExport filter is null!");
01143         return TRUE;
01144     }
01145 
01146     // Save this in our link to the BaseCamelotFilter
01147     pCamFilter = pFilter;
01148 
01149     // Set up and start the exported colour list
01150     pExportedColours = new ExportedColours();
01151     if (pExportedColours == NULL)
01152         return FALSE;
01153 #endif
01154     return TRUE;
01155 }
01156 
01157 /********************************************************************************************
01158 
01159 >   BOOL ColourListComponent::EndExport(BaseCamelotFilter *pFilter)
01160 
01161     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01162     Created:    21/5/96
01163     Inputs:     pFilter - the BaseCamelotFilter filter that is being used to import a file.
01164                 Success - True if everything went swimmingly, False if just a clean up is required.
01165     Purpose:    Inform the colour list document component that a Web or Native export has
01166                 just finished.
01167     Returns:    TRUE if the component was able to end the importing;
01168                 FALSE if not (e.g. out of memory)
01169     SeeAlso:    DocComponent
01170 
01171 ********************************************************************************************/
01172 
01173 BOOL ColourListComponent::EndExport(BaseCamelotFilter *pFilter, BOOL Success)
01174 {
01175 #ifdef DO_EXPORT
01176 //  ERROR2IF(pExportedColours == NULL, FALSE, "ColourListComponent::EndExport no pExportedColours!");
01177     // If we error about the pExportedColours then we assume that the EndImport has been called.
01178     // This may not be the case if we are in clean up mode. So just handle it!
01179 
01180 TRACEUSER( "Neville", _T("ColourListComponent::EndExport\n"));
01181     if (pFilter == NULL)
01182     {
01183         ERROR3("ColourListComponent::EndExport filter is null!");
01184         return TRUE;
01185     }
01186 
01187     // Check if we should be saving unused colours or not. Usually this is controlled by the
01188     // user in Web files and always done in Native files.
01189     // Do not do if we are just in clean up mode or have no pExportedColours (indicating in clean up mode)
01190     if (!pFilter->IsWebFilter() && !pFilter->GetRemoveUnusedColours() && Success && pExportedColours)
01191     {
01192 TRACEUSER( "Neville", _T("ColourListComponent::EndExport exporting unsaved colours\n"));
01193         // Iterate over the document's list of named IndexedColours...
01194         IndexedColour *pCol = (IndexedColour *) pIndexedColours->GetHead();
01195         BOOL ok = TRUE;
01196         while (ok && pCol != NULL)
01197         {
01198             if (!pCol->IsDeleted())
01199             {
01200                 // The colour is in use - save it to the file.
01201                 ok = SaveColourAndParents(pCol, pFilter, 0);
01202             }
01203 
01204             // Try the next colour
01205             pCol = (IndexedColour *) pIndexedColours->GetNext(pCol);
01206         }
01207 
01208         // Iterate over the document's list of unnamed IndexedColours...
01209         List *pUnnamedColours = pIndexedColours->GetUnnamedColours();
01210 
01211         pCol = (IndexedColour *) pUnnamedColours->GetHead();
01212 
01213         ok = TRUE;
01214         while (ok && pCol != NULL)
01215         {
01216             if (!pCol->IsDeleted() && pCol->IsInUse())
01217             {
01218                 // The colour is in use and is not deleted
01219                 // - save it to the file.
01220                 ok = SaveColourAndParents(pCol, pFilter, 0);
01221             }
01222 
01223             // Try the next colour
01224             pCol = (IndexedColour *) pUnnamedColours->GetNext(pCol);
01225         }
01226     }
01227 
01228 #endif      
01229     return TRUE;
01230 }
01231 
01232 
01233 
01234 /********************************************************************************************
01235 
01236 >   virtual void ColourListComponent::CleanUpAfterExport(BOOL Success)
01237 
01238     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01239     Created:    21/8/96
01240     Inputs:     Success - True if everything went swimmingly, False if the export failed
01241 
01242     Purpose:    Inform the document component that a Web or Native export has just finished.
01243 
01244     Notes:      This is called after EndExport, so that the component can clean up any 
01245                 during-export data structures. This allows situations like: PrintComponent
01246                 wants to save a colour reference in it's EndExport call, but is called after
01247                 the ColourComponent EndExport. The ColourComponent EndExport does not delete
01248                 its data structures, so is still able to supply colour references to other
01249                 components' EndExport functions.
01250 
01251     SeeAlso:    ColourListComponent::EndExport; DocComponent::CleanUpAfterExport
01252 
01253 ********************************************************************************************/
01254 
01255 void ColourListComponent::CleanUpAfterExport(BOOL Success)
01256 {
01257 #ifdef DO_EXPORT
01258     // As we have finished with it now, destroy the list of exported colours
01259     if (pExportedColours)
01260     {
01261         delete pExportedColours;
01262         pExportedColours = NULL;
01263     }
01264 
01265     // Null our link to the BaseCamelotFilter
01266     pCamFilter = NULL;
01267 
01268 #endif      
01269     return;
01270 }
01271 
01272 
01273 
01274 /********************************************************************************************
01275 
01276 >   INT32 ColourListComponent::GetWriteColourReference(DocColour* pDocColour, BaseCamelotFilter *pFilter)
01277 
01278     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01279     Created:    24/5/96
01280     Inputs:     pDocCololour    - The document colour to save
01281                 pFilter         - The filter to use for saving
01282     Outputs:    -
01283     Returns:    The colour reference for the doccolour ready for writing in a record.
01284                 This will be zero if a problem has occurred. May return -1 if it does not
01285                 need to save anything i.e if the colour is not in use and not named.
01286 
01287     Purpose:    Return the colour reference to the caller, who will then use it to write the
01288                 colour in the record that they are preparing to save to a Web or Native file.
01289                 In the process of getting the colour reference, the colour definition record
01290                 for the colour reference will be generated and saved to the file. In Web format
01291                 this will just be the simple colour record, in native files this will be the
01292                 full colour definition, possibly preceeded by the parents for the colour, as
01293                 these must be saved before the children as the children must have a valid
01294                 colour reference.
01295                 NOTE: As this does save information into the record stream, it *MUST* be called
01296                 before the caller has called StartRecord() as otherwise the records will become
01297                 intertwined!
01298     Errors:     -
01299     SeeAlso:    IndexedColour; SaveComplexColour; SaveSimpleColour; SaveColourAndParents;
01300 
01301 ********************************************************************************************/
01302 
01303 INT32 ColourListComponent::GetWriteColourReference(DocColour* pDocColour, BaseCamelotFilter *pFilter)
01304 {
01305 #ifdef DO_EXPORT
01306     ERROR2IF(pDocColour == NULL,0L,"ColourListComponent::GetWriteColourReference null pDocColour");
01307     ERROR2IF(pFilter == NULL,0L,"ColourListComponent::GetWriteColourReference null pFilter");
01308 
01309     INT32 RecordNumber = 0L;
01310     
01311     // First, check to see if the doc colour is transparent. If so then just return the default
01312     // default reference for this
01313     if (pDocColour->IsTransparent())
01314         return REF_DEFAULTCOLOUR_TRANSPARENT;
01315     
01316     // Get the indexed colour which this DocColour refers to, if any.
01317     IndexedColour * pCol = pDocColour->FindParentIndexedColour();
01318     if (pCol)
01319     {
01320         // Its an indexed colour so either save it as a simple colour or a complex colour
01321         // depending on whether we are in Web or Native mode.
01322         if (pFilter->IsWebFilter())
01323         {
01324             // We are in Web mode so save the simple colour
01325             RecordNumber = SaveSimpleColour(pCol, pFilter);
01326         }
01327         else
01328         {
01329             // We are in Web mode so save the simple colour
01330             RecordNumber = SaveColourAndParents(pCol, pFilter);
01331         }
01332     }
01333     else
01334     {
01335         // its a simple colour, so save this out as a simple colour. 
01336         if (pFilter->IsWebFilter())
01337         {
01338             // its a simple colour, so just save this as a simple colour. 
01339             // We must add the RGB colours to our exported list, so that we only save the
01340             // definition out once. 
01341             RecordNumber = SaveSimpleColour(pDocColour, pFilter, TRUE);
01342         }
01343         else
01344         {
01345             // TODO:
01346             // Could change this later to save out a complex colour in native files so that
01347             // these are converted to indexed colours on loading. Jason reckons this is favourable.
01348             // If we save it as a simple colour then there are bound to be conversion errors as
01349             // we are going from 24 bit components down to 8 bits and then back.
01350 
01351             // Find a global colour context to convert this colour into RGB for us.
01352             ColourContextRGBT *cc = (ColourContextRGBT *)ColourManager::GetColourContext(COLOURMODEL_RGBT);
01353             ERROR3IF(cc == NULL, "ColourListComponent::GetWriteColourReference No global RGB colour context!? Something is very broken");
01354             if (cc == NULL)
01355                 return 0L;
01356             
01357             // And convert the colour into a *packed* (8-bit components) colour structure
01358             PColourRGBT Result;
01359             cc->ConvertColour(pDocColour, (ColourPacked *)&Result);
01360 
01361             // Only write this record out if we have not done so already
01362             // Check by seeing if the colour is already in our exported colour list
01363             ExportColour* pExportCol = NULL;
01364             pExportCol = pExportedColours->GetColour(&Result);
01365             // If it is then do not save this colour
01366             if (pExportCol)
01367             {
01368                 // Just return the record number as the colour reference to the caller
01369                 RecordNumber = pExportCol->RecordNumber;
01370             }
01371             else
01372             {   
01373                 // Create ourselves a new indexed colour to put our data in
01374                 // Use the DocColour we have been supplied with, this should create an unnamed colour by default
01375                 IndexedColour *pNewCol = new IndexedColour(*pDocColour);
01376                 if (pNewCol)
01377                 {
01378                     // DY 3/5/2000 Now that I am now using the Reserved flag to indicate whether or not a doccolour
01379                     // was created from a named colour and then de-indexed. For details see LineDefinition::ConvertIndexedColours
01380                     // This means that if we get a doccolour with that flag set it was originally created by an indexed colour, so
01381                     // we can call our function to find the parent
01382     
01383                     
01384                     IndexedColour* pIndexedCol = NULL;
01385                     if (pDocColour->IsNamed())
01386                     {
01387                         // Diccon, this is a named colour that was originally generated from an indexed colour but
01388                         // subsequently de-indexed for various reasons. Its original parent should be in the list
01389                         // somewhere
01390                         pIndexedCol = GetIndexedParentOfColour(*pDocColour);
01391                     
01392                     }
01393                     else
01394                         pNewCol->SetUnnamed();
01395         
01396                     // Now save out the colour data in a complex colour record out to file
01397                     // We cannot ask the routine to add this colour to the exported list as it is
01398                     // not a REAL indexed colour in the indexed colour list, so say False.
01399                     if (pIndexedCol == NULL)
01400                         RecordNumber = SaveComplexColour(pNewCol, pFilter, FALSE);
01401                     else
01402                     // if we found an indexed colour then save out normally - DY
01403                         RecordNumber = SaveColourAndParents(pIndexedCol, pFilter);  
01404 
01405                     if (RecordNumber > 0)
01406                     {
01407                         // Add this colour to our list of exported items
01408                         /*BOOL ok =*/ pExportedColours->AddColour(&Result, RecordNumber);
01409                         // Should return this error to the caller but not fatal so just continue
01410                     }
01411 
01412                     // We have finished with our indexed colour and so remove it
01413                     delete pNewCol;
01414                 }
01415                 else
01416                 {
01417                     // We failed to create the complex colour so we have no choice but to save
01418                     // it as a simple colour. 
01419                     // We must add the RGB colours to our exported list, so that we only save the
01420                     // definition out once. 
01421                     RecordNumber = SaveSimpleColour(pDocColour, pFilter, TRUE);
01422                 }
01423             }
01424         }
01425     }
01426     
01427     return RecordNumber;
01428 #endif
01429     return 0L;
01430 }
01431 
01432 /********************************************************************************************
01433 
01434 >   INT32 ColourListComponent::SaveSimpleColour(IndexedColour *pCol, BaseCamelotFilter *pFilter)
01435 
01436     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01437     Created:    21/5/96
01438     Inputs:     pCol        - The (root) colour to save
01439                 pFilter     - The filter to use for saving
01440     Outputs:    -
01441     Returns:    The record number for this colour, if it has been saved correctly or zero
01442                 if a problem has occurred. May return -1 if it does not need to save anything
01443                 i.e if the colour is not in use and not named.
01444     Purpose:    Save out an indexed colour to a Web or Native file. Returns a record number or
01445                 colour reference to the caller ready for use by somebody else to save in their
01446                 record.
01447                 This is the Web file form of saving colours.
01448     Errors:     -
01449     SeeAlso:    -
01450 
01451 ********************************************************************************************/
01452 
01453 INT32 ColourListComponent::SaveSimpleColour(IndexedColour *pCol, BaseCamelotFilter *pFilter)
01454 {
01455 #ifdef DO_EXPORT
01456     ERROR2IF(pCol == NULL || pFilter == NULL, 0L, "ColourListComponent::SaveSimpleColour no pCol or pFilter supplied!");
01457     ERROR2IF(pExportedColours == NULL, 0L, "ColourListComponent::SaveSimpleColour no pExportedColours!");
01458     
01459     // Use same condition as SaveColourAndChildren so that if the colour is unnamed
01460     // and it's not actually used anywhere, don't bother saving it.
01461     // This optimises out temporary locals that are no longer needed. At the worst,
01462     // if something goes horribly wrong, this just means that some locals might turn up
01463     // as CMYK definitions on reloading, but this shouldn't cause any problems unless
01464     // something deeply scary has happened to the colour system.
01465     if (!pCol->IsNamed() && !pCol->IsInUse())
01466         return -1L;
01467 
01468     // Only write this record out if we have not done so already
01469     // Check by seeing if the colour is already in our exported colour list
01470     ExportColour* pExportCol = NULL;
01471     pExportCol = pExportedColours->GetColour(pCol);
01472     // If it is then do not save this colour
01473     if (pExportCol)
01474     {
01475         // Just return the record number as the colour reference to the caller
01476         return pExportCol->RecordNumber;
01477     }   
01478 
01479     // Create a DocColour referencing this IndexedColour.
01480     DocColour SimpleColour;
01481     SimpleColour.MakeRefToIndexedColour(pCol);
01482 
01483     // Save this as a document colour, don't check the export colour list as we are an indexed colour
01484     // really and so have cope with the list ourselves.
01485     INT32 RecordNumber = SaveSimpleColour(&SimpleColour, pFilter, FALSE);
01486     // returns 0 if there was a problem, exit now
01487     if (RecordNumber == 0)
01488         return RecordNumber;
01489 
01490     // Add this colour to our list of exported items
01491     BOOL ok = pExportedColours->AddColour(pCol, RecordNumber);
01492     // If we have had a problem at any of the stages then return that to the caller
01493     if (!ok)
01494         return 0L;
01495 
01496     // Everything went tickety boo, so return the record number to the caller.
01497     return RecordNumber;
01498 #else
01499     return 0L;
01500 #endif
01501 }
01502 
01503 /********************************************************************************************
01504 
01505 >   INT32 ColourListComponent::SaveSimpleColour(DocColour *pDocCol, BaseCamelotFilter *pFilter,
01506                                                BOOL CheckSimpleColourList = FALSE)
01507 
01508     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01509     Created:    21/5/96
01510     Inputs:     pDocCol     - The document colour to save
01511                 pFilter     - The filter to use for saving
01512                 CheckSimpleColourList - If TRUE then check the export colour list to see if we
01513                                         have saved this simple colour before
01514                                         If FALSE then this is an indexed colour so don't search
01515                                         the export colour list
01516     Outputs:    -
01517     Returns:    The record number for this colour, if it has been saved correctly or zero
01518                 if a problem has occurred. May return -1 if it does not need to save anything
01519                 i.e if the colour is not in use and not named.
01520     Purpose:    Save out a document colour to a Web or Native file. Returns a record number or
01521                 colour reference to the caller ready for use by somebody else to save in their
01522                 record.
01523                 This is the Web file form of saving colours.
01524     Errors:     -
01525     SeeAlso:    -
01526 
01527 ********************************************************************************************/
01528 
01529 INT32 ColourListComponent::SaveSimpleColour(DocColour *pDocCol, BaseCamelotFilter *pFilter,
01530                                            BOOL CheckSimpleColourList)
01531 {
01532 #ifdef DO_EXPORT
01533     ERROR2IF(pDocCol == NULL || pFilter == NULL, 0L, "ColourListComponent::SaveSimpleColour no pCol or pFilter supplied!");
01534 
01535     // Find a global colour context to convert this colour into RGB for us.
01536     ColourContextRGBT *cc = (ColourContextRGBT *)ColourManager::GetColourContext(COLOURMODEL_RGBT);
01537     ERROR3IF(cc == NULL, "ColourListComponent::SaveSimpleColour No global RGB colour context!? Something is very broken");
01538     if (cc == NULL)
01539         return 0L;
01540     
01541     // And convert the colour into a *packed* (8-bit components) colour structure
01542     PColourRGBT Result;
01543     cc->ConvertColour(pDocCol, (ColourPacked *)&Result);
01544 
01545     // If this is a simple colour rather than a simple colour of an indexed colour then
01546     // check to see if we have saved it already. If so then just return the record number
01547     if (CheckSimpleColourList)
01548     {
01549         // Only write this record out if we have not done so already
01550         // Check by seeing if the colour is already in our exported colour list
01551         ExportColour* pExportCol = NULL;
01552         pExportCol = pExportedColours->GetColour(&Result);
01553         // If it is then do not save this colour
01554         if (pExportCol)
01555         {
01556             // Just return the record number as the colour reference to the caller
01557             return pExportCol->RecordNumber;
01558         }   
01559     }
01560 
01561     // And finally, read the bytes out of the packed colour struct.
01562     BYTE RedByteValue = Result.Red;
01563     BYTE GreenByteValue = Result.Green;
01564     BYTE BlueByteValue = Result.Blue;
01565 
01566     INT32 RecordNumber = 0L;
01567     if (RedByteValue == 0xFF && GreenByteValue == 0xFF && BlueByteValue == 0xFF)
01568     {
01569         RecordNumber = REF_DEFAULTCOLOUR_WHITE;
01570     }
01571     else if (RedByteValue == 0x00 && GreenByteValue == 0x00 && BlueByteValue == 0x00)
01572     {
01573         RecordNumber = REF_DEFAULTCOLOUR_BLACK;
01574     }
01575     else if (RedByteValue == 0xFF && GreenByteValue == 0x00 && BlueByteValue == 0x00)
01576     {
01577         RecordNumber = REF_DEFAULTCOLOUR_RED;
01578     }
01579     else if (RedByteValue == 0x00 && GreenByteValue == 0xFF && BlueByteValue == 0x00)
01580     {
01581         RecordNumber = REF_DEFAULTCOLOUR_GREEN;
01582     }
01583     else if (RedByteValue == 0x00 && GreenByteValue == 0x00 && BlueByteValue == 0xFF)
01584     {
01585         RecordNumber = REF_DEFAULTCOLOUR_BLUE;
01586     }
01587     else if (RedByteValue == 0x00 && GreenByteValue == 0xFF && BlueByteValue == 0xFF)
01588     {
01589         RecordNumber = REF_DEFAULTCOLOUR_CYAN;
01590     }
01591     else if (RedByteValue == 0xFF && GreenByteValue == 0x00 && BlueByteValue == 0xFF)
01592     {
01593         RecordNumber = REF_DEFAULTCOLOUR_MAGENTA;
01594     }
01595     else if (RedByteValue == 0xFF && GreenByteValue == 0xFF && BlueByteValue == 0x00)
01596     {
01597         RecordNumber = REF_DEFAULTCOLOUR_YELLOW;
01598     }
01599     else
01600     {
01601         BOOL ok = TRUE;
01602         // Write the data out to the file
01603         //INT32 RecordNumber = pFilter->StartRecord(TAG_DEFINERGBCOLOUR, TAG_DEFINERGBCOLOUR_SIZE);
01604         CXaraFileRecord Rec(TAG_DEFINERGBCOLOUR,TAG_DEFINERGBCOLOUR_SIZE);
01605         ok = Rec.Init();
01606 
01607         if (ok) ok = Rec.WriteBYTE(RedByteValue);
01608         if (ok) ok = Rec.WriteBYTE(GreenByteValue);
01609         if (ok) ok = Rec.WriteBYTE(BlueByteValue);
01610 
01611         // Finally, write the record out to file
01612         // In the process get the record number that this was written out as
01613         if (ok) RecordNumber = pFilter->WriteDefinitionRecord(&Rec);
01614         
01615         // If we have had a problem at any of the stages then return that to the caller
01616         if (!ok || RecordNumber <= 0)
01617             return 0L;
01618     }
01619 
01620     // If this is a simple colour rather than a simple colour of an indexed colour then
01621     // add it to the list so that we do not save out the definition twice!
01622     if (CheckSimpleColourList)
01623     {
01624         // Add this colour to our list of exported items
01625         BOOL ok = pExportedColours->AddColour(&Result, RecordNumber);
01626         // If we have had a problem at any of the stages then return that to the caller
01627         if (!ok)
01628             return 0L;
01629     }
01630 
01631     // Everything went tickety boo, so return the record number to the caller.
01632     return RecordNumber;
01633 #else
01634     return 0L;
01635 #endif
01636 }
01637 
01638 // Simple macro to make the code in SaveColourAndParents() a bit neater.
01639 #define LINKED_COLOUR(ID) (Linked && pCol->InheritsComponent((ID)))
01640 
01641 /********************************************************************************************
01642 
01643 >   INT32 ColourListComponent::SaveColourAndParents(IndexedColour *pCol, BaseCamelotFilter *pFilter,
01644                                                     INT32 NestingLevel = 0)
01645 
01646     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01647     Created:    21/5/96
01648     Inputs:     pCol            - The (root) colour to save
01649                 pFilter         - The filter to use for saving
01650                 NestingLevel    - How many parental levels up we have gone so far
01651     Outputs:    -
01652     Returns:    The record number for this colour, if it has been saved correctly or zero
01653                 if a problem has occurred. May return -1 if it does not need to save anything
01654                 i.e if the colour is not in use and not named.
01655     Purpose:    Save out an indexed colour to a Web or Native file. Returns a record number or
01656                 colour reference to the caller ready for use by somebody else to save in their
01657                 record.
01658                 This is the Web file form of saving colours.
01659     Purpose:    Save out an indexed colour in its complex form usually to a Native file.
01660                 If it has any parents then these must be saved out before it, as the colour
01661                 reference for the parent *MUST* be a real record number which has been 
01662                 previously saved into the stream.
01663                 Returns a record number or colour reference to the caller ready for use by
01664                 somebody else to save in their record.
01665                 This is the Native file form of saving colours.
01666     Errors:     -
01667     SeeAlso:    -
01668 
01669 ********************************************************************************************/
01670 
01671 INT32 ColourListComponent::SaveColourAndParents(IndexedColour *pCol, BaseCamelotFilter *pFilter,
01672                                                 INT32 NestingLevel)
01673 {
01674 #ifdef DO_EXPORT
01675     ERROR2IF(pCol == NULL || pFilter == NULL, 0L, "ColourListComponent::SaveColourAndParents no pCol or pFilter!");
01676     ERROR2IF(pExportedColours == NULL, 0L, "ColourListComponent::SaveColourAndParents no pExportedColours!");
01677     
01678     // Use same condition as SaveColourAndChildren so that if the colour is unnamed
01679     // and it's not actually used anywhere, don't bother saving it.
01680     // This optimises out temporary locals that are no longer needed. At the worst,
01681     // if something goes horribly wrong, this just means that some locals might turn up
01682     // as CMYK definitions on reloading, but this shouldn't cause any problems unless
01683     // something deeply scary has happened to the colour system.
01684     if (!pCol->IsNamed() && !pCol->IsInUse())
01685         return -1L;
01686 
01687     // Check for silly recursion errors [not that you can get circular references with
01688     // the amazingly strict and careful checking done by the IndexedColour class.
01689     // Same test as SaveColourAndChildren.
01690     ERROR2IF(NestingLevel > 200, 0L, "ColourListComponent::SaveColourAndParents - Rampant linked colour nesting detected!");
01691 
01692     // ****
01693     // **** First, save parents of this colour, if any and if not saved previously
01694     // ****
01695 
01696     // Before we save out this colour, we must check if it has a parent, if so then
01697     // we must save out the parents first as we must reference parents by a record
01698     // number and hence it must have already been saved!
01699 
01700     // So, recurse and save out any parents of this colour (links or tints)...
01701 
01702     // Get all the named colours that are immediate children of this colour
01703     // This only returns a parent if this is a colour with a valid parent e.g. tint
01704     IndexedColour *pParent = pCol->FindLinkedParent();
01705     //IndexedColour *pParentCol = pParent;
01706     ExportColour* pExportCol = NULL;
01707     while (pParent != NULL)
01708     {
01709         if (!pParent->IsDeleted())
01710         {
01711             // Found a parent - save out via recursion so we save all its ascendants in the
01712             // right order...
01713             // To save time, check here if this parent is already in our list, if it this
01714             // then no point in recursing through the chain of parents as they all have already
01715             // been saved.
01716             pExportCol = pExportedColours->GetColour(pParent);
01717             // If it is NULL then we have not already saved this colour, so do so.
01718             if (pExportCol == NULL)
01719                 SaveColourAndParents(pParent, pFilter, NestingLevel + 1);
01720         }
01721 
01722         // Try the next colour
01723         pParent = pParent->FindLinkedParent();
01724     }
01725 
01726     // ****
01727     // **** Saved this colour before?
01728     // ****
01729 
01730     // Only write this record out if we have not done so already
01731     // Check by seeing if the colour is already in our exported colour list
01732     pExportCol = pExportedColours->GetColour(pCol);
01733     // If it is then do not save this colour
01734     if (pExportCol)
01735     {
01736         // Just return the record number as the colour reference to the caller
01737         return pExportCol->RecordNumber;
01738     }   
01739 
01740     // Now save out the colour data in a complex colour record out to file
01741     // We want this indexed colour adding to the exported list and so say TRUE
01742     INT32 RecordNumber = SaveComplexColour(pCol, pFilter, TRUE);
01743 
01744     // Everything went tickety boo, so return the record number to the caller.
01745     return RecordNumber;
01746 #else
01747     return 0L;
01748 #endif
01749 }
01750 
01751 /********************************************************************************************
01752 
01753 >   INT32 ColourListComponent::SaveComplexColour(IndexedColour *pCol, BaseCamelotFilter *pFilter,
01754                                                 BOOL AddColourToList = TRUE)
01755 
01756     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
01757     Created:    4/6/96
01758     Inputs:     pCol            - The (root) colour to save
01759                 pFilter         - The filter to use for saving
01760                 AddColourToList - True if we are to add this colour to the exported colour list
01761                                 - False if the caller has already done this
01762     Outputs:    -
01763     Returns:    The record number for this colour, if it has been saved correctly or zero
01764                 if a problem has occurred. May return -1 if it does not need to save anything
01765                 i.e if the colour is not in use and not named.
01766     Purpose:    Actually save out an indexed colour to a Web or Native file in a complex colour
01767                 record. Returns a record number or colour reference to the caller ready for use
01768                 by somebody else to save in their record.
01769                 If it has any parents then these must be saved out before it, as the colour
01770                 reference for the parent *MUST* be a real record number which has been 
01771                 previously saved into the stream.
01772                 Returns a record number or colour reference to the caller ready for use by
01773                 somebody else to save in their record.
01774                 This is the Native file form of saving colours.
01775     Errors:     -
01776     SeeAlso:    SaveColourAndParents; GetWriteColourReference;
01777 
01778 ********************************************************************************************/
01779 INT32 ColourListComponent::SaveComplexColour(IndexedColour *pCol, BaseCamelotFilter *pFilter,
01780                                             BOOL AddColourToList)
01781 {
01782 #ifdef DO_EXPORT
01783 
01784     ERROR2IF(pCol == NULL || pFilter == NULL, 0L, "ColourListComponent::SaveComplexColour no pCol or pFilter!");
01785     ERROR2IF(pExportedColours == NULL, 0L, "ColourListComponent::SaveComplexColour no pExportedColours!");
01786 
01787     // When GetColourLinePosition is TRUE, it means that we want to save the colour's pos on the colour
01788     // line, so that it can be imported in the correct order.
01789     //
01790     // This is set to AddColourToList by default - i.e. assume that if it's being added to the list of exported
01791     // colours, then we probably want to preserve the colour' pos
01792     BOOL GetColourLinePosition = AddColourToList;
01793 
01794     // ****
01795     // **** Get the information on the colour
01796     // ****
01797 
01798     // Get information on the colour - ask for its full identifier rather than just the name,
01799     // so we get a unique id for unnamed colours rather than just "Local colour"
01800     ColourModel Model = pCol->GetColourModel();
01801     ColourGeneric GenCol;
01802     IndexedColourType ColType = pCol->GetType();
01803     pCol->GetSourceColour(&GenCol);
01804     String_64 ColName = *(pCol->GetName(TRUE));
01805     if (ColName[0] == '_')
01806     {
01807         // We have an unnamed colour and so the name should be blank
01808         ColName.Empty();
01809 
01810         // If it's an unnamed colour, then it's assumed it's not on the colour line, so we
01811         // won't need to find it's pos on the colour line
01812         GetColourLinePosition = FALSE;
01813     }
01814 
01815     //TCHAR *ColName = (TCHAR *) (*(pCol->GetName(TRUE)));
01816 
01817     // Find a global colour context to convert this colour into RGB for us.
01818     ColourContextRGBT *cc = (ColourContextRGBT *)ColourManager::GetColourContext(COLOURMODEL_RGBT);
01819     ERROR3IF(cc == NULL, "ColourListComponent::SaveComplexColour No global RGB colour context!? Something is very broken");
01820     if (cc == NULL)
01821         return 0L;
01822 
01823     BOOL ok = FALSE;
01824     // Create a DocColour referencing this IndexedColour.
01825     DocColour SimpleColour;
01826     SimpleColour.MakeRefToIndexedColour(pCol);
01827 
01828     // And convert the colour into a *packed* (8-bit components) colour structure
01829     PColourRGBT Result;
01830     cc->ConvertColour(&SimpleColour, (ColourPacked *)&Result);
01831 
01832     // And finally, read the bytes out of the packed colour struct.
01833     BYTE RedByteValue = Result.Red;
01834     BYTE GreenByteValue = Result.Green;
01835     BYTE BlueByteValue = Result.Blue;
01836 
01837     // ****
01838     // **** Save the record
01839     // ****
01840 
01841     // Write the data out to the file
01842     UINT32 Size = TAG_DEFINECOMPLEXCOLOUR_SIZE;
01843     // If there is a string name, then add it to this size
01844     // REMEMBER: We save out unicode strings and so we need to double the length of the returned string length
01845     Size += (ColName.Length() + 1) * SIZEOF_XAR_UTF16;
01846 
01847 //  INT32 RecordNumber = pFilter->StartRecord(TAG_DEFINECOMPLEXCOLOUR, Size);
01848     CXaraFileRecord Rec(TAG_DEFINECOMPLEXCOLOUR, Size);
01849     ok = Rec.Init();
01850 
01851     // Start with the simple RGB colour
01852     if (ok) ok = Rec.WriteBYTE(RedByteValue);
01853     if (ok) ok = Rec.WriteBYTE(GreenByteValue);
01854     if (ok) ok = Rec.WriteBYTE(BlueByteValue);
01855 
01856     // Now write out the colour model...
01857     if (ok) ok = Rec.WriteBYTE((BYTE)Model);
01858 
01859     // Now write out the colour type...
01860     // Include flags about linking in colour type?
01861     // If the colour is linked, we save out the component as an illegal known value
01862     // Convert the colour types into export colour types
01863     // Should be a straight conversion but just in case...
01864     ExportColourType ExpColType=EXPORT_COLOURTYPE_NORMAL;
01865     switch (ColType)
01866     {
01867         case COLOURTYPE_NORMAL: ExpColType = EXPORT_COLOURTYPE_NORMAL;  break;
01868         case COLOURTYPE_SPOT:   ExpColType = EXPORT_COLOURTYPE_SPOT;    break;
01869         case COLOURTYPE_LINKED: ExpColType = EXPORT_COLOURTYPE_LINKED;  break;
01870         case COLOURTYPE_TINT:
01871             if (pCol->TintIsShade())
01872                 ExpColType = EXPORT_COLOURTYPE_SHADE;
01873             else
01874                 ExpColType = EXPORT_COLOURTYPE_TINT;
01875             break;
01876         default:
01877             ERROR3("ColourListComponent::SaveColour - Unknown colour model!");
01878             break;
01879     }
01880     if (ok) ok = Rec.WriteBYTE((BYTE)ExpColType);
01881 
01882     // Write out the entry number this colour is in the indexed colour list
01883     UINT32 ColourListNumber = 0L;
01884     // If GetColourLinePosition is False then the indexed colour is not on the colour line.
01885     // so do NOT try and go through the list of colours to find its pos number, just use zero.
01886     if (GetColourLinePosition)
01887         ColourListNumber = GetIndexColourNumber(pCol); 
01888     if (ok) ok = Rec.WriteUINT32(ColourListNumber);
01889 
01890     // Write out the reference number of the parent colour
01891     UINT32 ParentColourRef = 0L; 
01892     IndexedColour *pParentCol = pCol->FindLinkedParent();
01893     ExportColour* pExportCol = NULL;
01894     if (pParentCol)
01895     {
01896         // If there is a parent then recover the record number from the exported colours list 
01897         pExportCol = pExportedColours->GetColour(pParentCol);
01898         ERROR2IF(pExportCol == NULL,FALSE,"ColourListComponent::SaveComplexColour Not exported parent before child!");
01899         ParentColourRef = pExportCol->RecordNumber;
01900         TRACEUSER( "Neville", _T("Saving parent reference %d\n"),ParentColourRef);
01901     }
01902 
01903     if (ok) ok = Rec.WriteReference(ParentColourRef);
01904 
01905     BOOL Linked = (ColType == COLOURTYPE_LINKED);
01906     switch (ColType)
01907     {
01908         
01909         case COLOURTYPE_NORMAL:
01910         case COLOURTYPE_SPOT:
01911         case COLOURTYPE_LINKED:
01912         {
01913             // These all require the same handling
01914             // Linked colours save out the components in the normal fashion
01915 
01916             // Now write out the colour component values depending on the model in use...
01917             switch (Model)
01918             {
01919                 case COLOURMODEL_RGBT:
01920                     // Now add the RGB components.
01921                     // Stored as FIXED24s.
01922                     ColourRGBT *pRGBT;
01923                     pRGBT = (ColourRGBT *) &GenCol;
01924                     if (ok) ok = Rec.WriteUINT32(AddComponentValue(pRGBT->Red, LINKED_COLOUR(1)));
01925                     if (ok) ok = Rec.WriteUINT32(AddComponentValue(pRGBT->Green,    LINKED_COLOUR(2)));
01926                     if (ok) ok = Rec.WriteUINT32(AddComponentValue(pRGBT->Blue, LINKED_COLOUR(3)));
01927                     if (ok) ok = Rec.WriteUINT32(AddComponentValue(pRGBT->Transparent, LINKED_COLOUR(4)));
01928                     break;
01929 
01930                 case COLOURMODEL_HSVT:
01931                     // Now add the HSV components.
01932                     ColourHSVT *pHSVT;
01933                     pHSVT = (ColourHSVT *) &GenCol;
01934                     if (ok) ok = Rec.WriteUINT32(AddComponentValue(pHSVT->Hue, LINKED_COLOUR(1)));
01935                     if (ok) ok = Rec.WriteUINT32(AddComponentValue(pHSVT->Saturation, LINKED_COLOUR(2)));
01936                     if (ok) ok = Rec.WriteUINT32(AddComponentValue(pHSVT->Value, LINKED_COLOUR(3)));
01937                     if (ok) ok = Rec.WriteUINT32(0);    // pad to 4 colour components
01938                     break;
01939 
01940                 case COLOURMODEL_CMYK:
01941                     // Now add the CMYK components.
01942                     ColourCMYK *pCMYK;
01943                     pCMYK = (ColourCMYK *) &GenCol;
01944                     if (ok) ok = Rec.WriteUINT32(AddComponentValue(pCMYK->Cyan, LINKED_COLOUR(1)));
01945                     if (ok) ok = Rec.WriteUINT32(AddComponentValue(pCMYK->Magenta, LINKED_COLOUR(2)));
01946                     if (ok) ok = Rec.WriteUINT32(AddComponentValue(pCMYK->Yellow, LINKED_COLOUR(3)));
01947                     if (ok) ok = Rec.WriteUINT32(AddComponentValue(pCMYK->Key, LINKED_COLOUR(4)));
01948                     break;
01949 
01950                 case COLOURMODEL_GREYT:
01951                     // greyscale colour.
01952                     ColourGreyT *pGreyT;
01953                     pGreyT = (ColourGreyT *) &GenCol;
01954                     if (ok) ok = Rec.WriteUINT32(AddComponentValue(pGreyT->Intensity, LINKED_COLOUR(1)));
01955                     if (ok) ok = Rec.WriteUINT32(0);    // pad to 4 colour components
01956                     if (ok) ok = Rec.WriteUINT32(0);    // pad to 4 colour components
01957                     if (ok) ok = Rec.WriteUINT32(0);    // pad to 4 colour components
01958                     break;
01959 
01960                 default:
01961                     ERROR3("ColourListComponent::SaveColour - Unknown colour model!");
01962                     break;
01963             }
01964             break;
01965         }
01966 
01967         case COLOURTYPE_TINT:
01968         {
01969             // If we have a tint colour then this needs special handling
01970             FIXED24 TintVal(0.0);
01971             FIXED24 ShadeVal(0.0);
01972             // Is the tint a tint or is it really a shade
01973             // Add tint identifier to colour definition
01974             if (pCol->TintIsShade())
01975             {
01976                 ShadeVal = pCol->GetShadeValueX();
01977                 TintVal  = pCol->GetShadeValueY();
01978                 if (ok) ok = Rec.WriteUINT32(AddComponentValue(ShadeVal, LINKED_COLOUR(1)));
01979                 if (ok) ok = Rec.WriteUINT32(AddComponentValue(TintVal, LINKED_COLOUR(1)));
01980                 if (ok) ok = Rec.WriteUINT32(0);    // pad to 4 colour components
01981                 if (ok) ok = Rec.WriteUINT32(0);    // pad to 4 colour components
01982             }
01983             else
01984             {
01985                 TintVal  = pCol->GetTintValue();
01986                 if (ok) ok = Rec.WriteUINT32(AddComponentValue(TintVal, LINKED_COLOUR(1)));
01987                 if (ok) ok = Rec.WriteUINT32(0);    // pad to 4 colour components
01988                 if (ok) ok = Rec.WriteUINT32(0);    // pad to 4 colour components
01989                 if (ok) ok = Rec.WriteUINT32(0);    // pad to 4 colour components
01990             }
01991             break;
01992         }
01993         default:
01994             ERROR3("ColourListComponent::SaveColour - Unknown colour type!");
01995             break;
01996     }
01997 
01998     // Write out the name of the colour
01999     if (ok) ok = Rec.WriteUnicode(ColName);
02000 
02001     // Finally, write the record out to file
02002     INT32 RecordNumber = 0L;
02003     if (ok) RecordNumber = pFilter->WriteDefinitionRecord(&Rec);
02004 
02005     // Has the caller handled adding this to the colour list already? No, so do it oursleves.
02006     if (AddColourToList && RecordNumber > 0)
02007     {
02008         // Add this colour to our list of exported items
02009         ok = pExportedColours->AddColour(pCol, RecordNumber);
02010     }
02011 //TRACEUSER( "Neville", _T("Saving colour %s, number %d, entry number %d\n"),(TCHAR*)ColName, RecordNumber, ColourListNumber);
02012 
02013     // If we have had a problem at any of the stages then return that to the caller
02014     if (!ok)
02015         return 0L;
02016 
02017     // Everything went tickety boo, so return the record number to the caller.
02018     return RecordNumber;
02019 #else
02020     return 0L;
02021 #endif
02022 }
02023 
02024 /********************************************************************************************
02025 
02026 >   UINT32 ColourListComponent::AddComponentValue(FIXED24 ComponentValue, BOOL Inherited)
02027 
02028     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
02029     Created:    28/5/96
02030     Inputs:     ComponentValue - the value to be returned.
02031                 Inherited - TRUE => This component is inherited, so just output a known illegal value
02032                            FALSE => This component is not inherited, so output the
02033                                     actual value to the string
02034     Outputs:    -
02035     Returns:    The colour component as a UINT32 ready to write out to file.
02036     Purpose:    Returns either the colour component value or if it is inherited, a known illegal
02037                 value which we can intepret on import to be an overridden value. 
02038                 Doing it in a function centralises the syntax of inherited components.
02039     Errors:     -
02040     SeeAlso:    ColourListComponent::SaveColourAndParents
02041 
02042 ********************************************************************************************/
02043 
02044 UINT32 ColourListComponent::AddComponentValue(FIXED24 ComponentValue, BOOL Inherited)
02045 {
02046     // Construct the colour component value
02047     UINT32 ColourValue = 0L;
02048 
02049     // If this is a linked colour, and this component is inherited, then just add a '-'.
02050     if (Inherited)
02051     {
02052         ColourValue = FIXED24(-8.0).GetAsFixed24();
02053     }
02054     else
02055     {
02056         // We have to output the component....
02057         ColourValue = ComponentValue.GetAsFixed24();
02058     }
02059 
02060     return ColourValue;
02061 }
02062 
02063 /********************************************************************************************
02064 
02065 >   INT32 ColourListComponent::GetIndexColourNumber(IndexedColour *pCol)
02066 
02067     Author:     Neville_Humphrys (Xara Group Ltd) <camelotdev@xara.com>
02068     Created:    21/5/96
02069     Inputs:     pCol - the indexed colour to search out the number for.
02070     Returns:    The number of this indexed colour in the list of colours (i.e.position)
02071     Purpose:    Work out the index of this colour in the list of indexed colours so that we
02072                 can try and load back the colours in the same order.
02073                 Unfortunately, the only way it seems that we can work out this number is by
02074                 counting back to the start of the indexed colour list. Doh!
02075     SeeAlso:    IndexedColour
02076 
02077 ********************************************************************************************/
02078 
02079 INT32 ColourListComponent::GetIndexColourNumber(IndexedColour *pCol)
02080 {
02081     ERROR2IF(pCol==NULL,0,"ColourListComponent::GetIndexColourNumber no Colour pointer");
02082     ERROR2IF(pIndexedColours==NULL,0,"ColourListComponent::GetIndexColourNumber no pIndexedColours");
02083 
02084     INT32 number = 0;
02085 
02086     // Due to pants list class, we need to check that there is a previous memember before we
02087     // call GetPrev, otherwise it ensures all over the place. Why it can't just return NULL!
02088     if (pIndexedColours->IsEmpty())
02089         return number;
02090 
02091     // Go from this item to the start of the inddexed colour list, counting items as we go
02092     while (pCol)
02093     {
02094         pCol = (IndexedColour *) pIndexedColours->GetPrev(pCol);
02095         // If the colour is not deleted then count it
02096         if (pCol && !pCol->IsDeleted())
02097             number ++;
02098     }
02099 
02100     return number;
02101 }
02102 
02103 
02104 /********************************************************************************************
02105 ********************************************************************************************/
02106 
02107 // Remove the preceeding code on all builds but those who want it
02108 
02109 /********************************************************************************************
02110 ********************************************************************************************/
02111 
02112 /********************************************************************************************
02113 
02114 >   BOOL ColourListComponent::EPSStartImport(EPSFilter *pFilter)
02115 
02116     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
02117     Created:    03/08/94
02118     Inputs:     pFilter - the EPS filter that is being used to import a file.
02119     Purpose:    Inform the colour list document component that an EPS import is about to 
02120                 start.
02121     SeeAlso:    DocComponent
02122 
02123 ********************************************************************************************/
02124 
02125 BOOL ColourListComponent::EPSStartImport(EPSFilter *pFilter)
02126 {
02127     // Is this a Camelot EPS filter?
02128     BOOL CamelotEPS = pFilter->IS_KIND_OF(CamelotEPSFilter);
02129 
02130     // Get a colour table (and don't do strict checking if we are loading Camelot EPS).
02131     pNewColours = new ImportedColours(this, !CamelotEPS);
02132     if ((pNewColours == NULL) || !pNewColours->Init())
02133         return FALSE;
02134 
02135     // We keep a record of how nested we are with respect to linking colours, e.g.
02136     // links of links of links.
02137     // A nesting of 0 is no nesting.
02138     LinkNesting = 0;
02139 
02140     // Must have worked
02141     return TRUE;
02142 }
02143 
02144 /********************************************************************************************
02145 
02146 >   void ColourListComponent::EPSEndImport(EPSFilter *pFilter, BOOL Success)
02147 
02148     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
02149     Created:    03/08/94
02150     Inputs:     pFilter - the EPS filter that is being used to import a file.
02151                 Success - TRUE => The import was successful;
02152                          FALSE => The import failed - abandon any changes.
02153     Purpose:    Inform the colour list document component that an EPS import has just 
02154                 finished.
02155     SeeAlso:    DocComponent
02156 
02157 ********************************************************************************************/
02158 
02159 void ColourListComponent::EPSEndImport(EPSFilter *pFilter, BOOL Success)
02160 {
02161     ERROR3IF(pNewColours == NULL, "No colour table in EndEPSImport");
02162 
02163     // If we didn't even get to initialise, then return quietly.
02164     if (pNewColours == NULL)
02165         return;
02166 
02167     // Import is finished, so add any outstanding colours to the document (if the
02168     // import was successful), and delete the colour table
02169     if (Success)
02170     {
02171         pNewColours->AddColoursToDocument();
02172     }
02173     else
02174     {
02175         // Import failed - destroy all the colours.
02176         pNewColours->DestroyColours();
02177     }
02178 
02179     // Finally, delete the IndexedColour table.
02180     delete pNewColours;
02181     pNewColours = NULL;
02182 }
02183 
02184 
02185 
02186 /********************************************************************************************
02187 
02188 >   void ColourListComponent::AddNewColour(IndexedColour *pNewCol)
02189 
02190     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
02191     Created:    08/08/94
02192     Inputs:     pNewCol - the colour to add.
02193     Purpose:    Adds an indexed colour to the colour list (which in turn ensures that
02194                 it has a unique colour name)
02195     SeeAlso:    ColourList::AddItem
02196 
02197 ********************************************************************************************/
02198 
02199 void ColourListComponent::AddNewColour(IndexedColour *pNewCol)
02200 {
02201     ERROR3IF(pNewCol == NULL,
02202                 "ColourListComponent::AddNewColour: The colour to add is NULL!");
02203     ERROR3IF(pIndexedColours == NULL,
02204                 "ColourListComponent::AddNewColour: I have no IndexedColour list!");
02205 
02206     // Add the colour, ensuring that it has a unique name
02207     pIndexedColours->AddItem(pNewCol);
02208 }
02209 
02210 
02211 
02212 /********************************************************************************************
02213 
02214 >   BOOL ColourListComponent::WriteEPSComments(EPSFilter *pFilter)
02215 
02216     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
02217     Created:    02/08/94
02218     Inputs:     pFilter - the filter being used to import the EPS file.
02219     Returns:    TRUE if the colour table was written successfully;
02220                 FALSE if not.
02221     Purpose:    Writes out the colour table in the form of EPS comments in the 'header'
02222                 comments of the EPS file.
02223 
02224     Notes:      IMPORTANT: Version 1.1 file extensions (Jason, 7/9/95 & 14/10/95)
02225                 For this version, Shade colours have been added. 
02226                 To retain backward compatability,
02227                 all shades and their children are written into a second colour table
02228                 (a %%JWColourTable). This means old loader code will skip them and use
02229                 the inlined CMYK definitions, thus retaining the appearance of the document
02230                 while only losing unsupported colour linking info.
02231                 Thus, we do a 2-pass scheme. The first pass will (by use of default params
02232                 in SaveColourAndChildren) fail to save out any shades and children.
02233                 The second pass then saves all shades and their parents and children.
02234                 Note this means parent colours can be saved twice, but these will be
02235                 happily merged on loading, so no bad effects occur.
02236 
02237                 Shades are only saved out in CamelotEPS. In Artworks EPS mode, they
02238                 become standalone named colours.
02239 
02240     Errors:     Out of disk space, and similar disk errors.
02241     SeeAlso:    DocComponent::WriteEPSComments;
02242                 DocComponent
02243 
02244 ********************************************************************************************/
02245 
02246 BOOL ColourListComponent::WriteEPSComments(EPSFilter *pFilter)
02247 {
02248 #ifdef DO_EXPORT
02249     if (pFilter->IsKindOf(CC_RUNTIME_CLASS(ArtWorksEPSFilter)))
02250     {
02251         // Is it a Camelot specific filter?
02252         BOOL CamelotEPS = pFilter->IsKindOf(CC_RUNTIME_CLASS(CamelotEPSFilter));
02253 
02254         // Output the colour table in ArtWorks format.
02255         EPSExportDC *pDC = pFilter->GetExportDC();
02256 
02257         // The ArtWorks EPS comment:
02258         pDC->OutputToken(_T("%%AWColourTable"));
02259         pDC->OutputNewLine();
02260 
02261         // Iterate over the document's list of named IndexedColours...
02262         IndexedColour *pCol = (IndexedColour *) pIndexedColours->GetHead();
02263 
02264         while (pCol != NULL)
02265         {
02266             if (!pCol->IsDeleted() && 
02267                 ((pCol->GetType() == COLOURTYPE_NORMAL) || 
02268                  (pCol->GetType() == COLOURTYPE_SPOT)))
02269             {
02270                 // The colour is in use and is not a linked colour or tint - save it to 
02271                 // the EPS file.
02272                 SaveColourAndChildren(pCol, pDC, CamelotEPS);
02273 
02274             }
02275 
02276             // Try the next colour
02277             pCol = (IndexedColour *) pIndexedColours->GetNext(pCol);
02278         }
02279 
02280         // Iterate over the document's list of unnamed IndexedColours...
02281         List *pUnnamedColours = pIndexedColours->GetUnnamedColours();
02282 
02283         pCol = (IndexedColour *) pUnnamedColours->GetHead();
02284 
02285         while (pCol != NULL)
02286         {
02287             if (!pCol->IsDeleted() && pCol->IsInUse() &&
02288                 ((pCol->GetType() == COLOURTYPE_NORMAL) || 
02289                  (pCol->GetType() == COLOURTYPE_SPOT)))
02290             {
02291                 // The colour is in use and is not a linked colour or tint - save it to 
02292                 // the EPS file.
02293                 SaveColourAndChildren(pCol, pDC, CamelotEPS);
02294             }
02295 
02296             // Try the next colour
02297             pCol = (IndexedColour *) pUnnamedColours->GetNext(pCol);
02298         }
02299 
02300 
02301         // --- PASS 2 - version 1.1 second colour table for shades and other extensions
02302         if (CamelotEPS)
02303         {
02304             // This variable is used to stop us outputting the colour table section
02305             // if it is not needed - we only output the header line when we write the
02306             // first colour out to this table.
02307             BOOL HaveOutputHeader = FALSE;
02308 
02309             // Iterate over the document's list of named IndexedColours...
02310             IndexedColour *pCol = (IndexedColour *) pIndexedColours->GetHead();
02311 
02312             while (pCol != NULL)
02313             {
02314                 if (!pCol->IsDeleted() && 
02315                     ((pCol->GetType() == COLOURTYPE_NORMAL) || 
02316                      (pCol->GetType() == COLOURTYPE_SPOT)))
02317                 {
02318                     // The colour is in use and is not a linked colour or tint - save it to 
02319                     // the EPS file.
02320                     if (ColourOrChildIsShade(pCol))
02321                     {
02322                         if (!HaveOutputHeader)
02323                         {
02324                             // Output the header comment if we haven't already done so
02325                             pDC->OutputToken(_T("%%JWColourTable"));
02326                             pDC->OutputNewLine();
02327                             HaveOutputHeader = TRUE;
02328                         }
02329 
02330                         SaveColourAndChildren(pCol, pDC, CamelotEPS, 0, TRUE);
02331                     }
02332                 }
02333 
02334                 // Try the next colour
02335                 pCol = (IndexedColour *) pIndexedColours->GetNext(pCol);
02336             }
02337 
02338             // Iterate over the document's list of unnamed IndexedColours...
02339             List *pUnnamedColours = pIndexedColours->GetUnnamedColours();
02340 
02341             pCol = (IndexedColour *) pUnnamedColours->GetHead();
02342 
02343             while (pCol != NULL)
02344             {
02345                 if (!pCol->IsDeleted() && pCol->IsInUse() &&
02346                     ((pCol->GetType() == COLOURTYPE_NORMAL) || 
02347                      (pCol->GetType() == COLOURTYPE_SPOT)))
02348                 {
02349                     // The colour is in use and is not a linked colour or tint - save it to 
02350                     // the EPS file.
02351                     if (ColourOrChildIsShade(pCol))
02352                     {
02353                         if (!HaveOutputHeader)
02354                         {
02355                             // Output the header comment if we haven't already done so
02356                             pDC->OutputToken(_T("%%JWColourTable"));
02357                             pDC->OutputNewLine();
02358                             HaveOutputHeader = TRUE;
02359                         }
02360 
02361                         SaveColourAndChildren(pCol, pDC, CamelotEPS, 0, TRUE);
02362                     }
02363                 }
02364 
02365                 // Try the next colour
02366                 pCol = (IndexedColour *) pUnnamedColours->GetNext(pCol);
02367             }
02368             
02369         }
02370     }
02371 #endif
02372     // All ok.
02373     return TRUE;
02374 }
02375 
02376 /********************************************************************************************
02377 
02378 >   void ColourListComponent::AddComponentValue(char *ColDef, char *Format, 
02379                                                 double ComponentValue, BOOL Inherited)
02380 
02381     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
02382     Created:    05/12/94
02383     Inputs:     ColDef - the current colour definition string, which this routine should
02384                          append the component value to.
02385                 Format - the printf format to use when converting the value to ASCII.
02386                 ComponentValue - the value to add to the string.
02387                 Inherited - TRUE => This component is inherited, so just output a '-'
02388                            FALSE => This component is not inherited, so output the
02389                                     actual value to the string
02390     Outputs:    ColDef - the updated colour definition string, with the value converted to 
02391                          ASCII (taking into account the Inherited flag), and appended (with 
02392                          a leading space so the values don't join together).
02393     Purpose:    Add a colour component value to a colour definition string.  This is used
02394                 to build up the entries in the EPS colour table.  It also centralises the
02395                 syntax of inherited components.
02396     Errors:     -
02397     SeeAlso:    ColourListComponent::SaveColourAndChildren
02398 
02399 ********************************************************************************************/
02400 
02401 void ColourListComponent::AddComponentValue( PTSTR ColDef, PCTSTR Format, 
02402                                             double ComponentValue, BOOL Inherited)
02403 {
02404     // Construct the colour component value
02405     TCHAR               CompVal[20];
02406 
02407     // If this is a linked colour, and this component is inherited, then just add a '-'.
02408     if (Inherited)
02409     {
02410         camStrcpy( CompVal, _T("-") );
02411     }
02412     else
02413     {
02414         // We have to output the component....
02415         camSnprintf( CompVal, 20, const_cast<TCHAR *>(Format), ComponentValue );
02416     }
02417 
02418     // Add the value onto the end of the string
02419     camStrcat( ColDef, _T(" ") );
02420     camStrcat( ColDef, CompVal );
02421 }
02422 
02423 
02424 
02425 /********************************************************************************************
02426 
02427 >   BOOL ColourListComponent::ColourOrChildIsShade(IndexedColour *pCol)
02428 
02429     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02430     Created:    7/9/95
02431     Inputs:     pCol - The (root) colour to check
02432 
02433     Returns:    TRUE if this colour or a descendant is a Shade colour
02434 
02435     Purpose:    To determine if a colour is a Shade or has descendants which are Shades.
02436 
02437 ********************************************************************************************/
02438 
02439 BOOL ColourListComponent::ColourOrChildIsShade(IndexedColour *pCol)
02440 {
02441     // Check if this colour exists
02442     if (pCol->IsDeleted())
02443         return(FALSE);
02444 
02445     // Check if this colour is a shade
02446     if (pCol->GetType() == COLOURTYPE_TINT && pCol->TintIsShade())
02447         return(TRUE);
02448 
02449     // If this has no children, then no point in scanning further
02450     if (!pCol->HasLinkedChildren())
02451         return(FALSE);
02452 
02453 
02454     // Ask all the named colours that are immediate children of this colour
02455     IndexedColour *pChild = (IndexedColour *) pIndexedColours->GetHead();
02456 
02457     while (pChild != NULL)
02458     {
02459         if (!pChild->IsDeleted() && pChild->FindLinkedParent() == pCol)
02460         {
02461             // Found a child - recurse on it
02462             if (ColourOrChildIsShade(pChild))
02463                 return(TRUE);
02464         }
02465 
02466         // Try the next colour
02467         pChild = (IndexedColour *) pIndexedColours->GetNext(pChild);
02468     }
02469 
02470     // Get all the unnamed colours that are immediate children of this colour
02471     List *pUnnamedList = pIndexedColours->GetUnnamedColours();
02472     pChild = (IndexedColour *) pUnnamedList->GetHead();
02473 
02474     while (pChild != NULL)
02475     {
02476         if (!pChild->IsDeleted() && pChild->FindLinkedParent() == pCol)
02477         {
02478             // Found a child - recurse on it
02479             if (ColourOrChildIsShade(pChild))
02480                 return(TRUE);
02481         }
02482 
02483         // Try the next colour
02484         pChild = (IndexedColour *) pUnnamedList->GetNext(pChild);
02485     }
02486 
02487     return(FALSE);
02488 }
02489 
02490 
02491 
02492 // Simple macro to make the code in SaveColourAndChildren() a bit neater.
02493 #define LINKED(ID) (Linked && pCol->InheritsComponent((ID)))
02494 
02495 /********************************************************************************************
02496 
02497 >   BOOL ColourListComponent::SaveColourAndChildren(IndexedColour *pCol, EPSExportDC *pDC, 
02498                                                 BOOL CamelotEPS, INT32 NestingLevel = 0,
02499                                                 BOOL SaveShades = FALSE)
02500 
02501     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
02502     Created:    05/12/94
02503     Inputs:     pCol        - The (root) colour to save
02504                 pDC         - The EPS export DC to save to
02505                 CamelotEPS  - TRUE if exporting Camelot EPS
02506                 NestingLevel- The nesting level of tint/shade/link colours. Used in
02507                               recursion - external callers should pass in 0
02508                 SaveShades  - Indicates if Shades and their children should be saved. Used
02509                               in version 1.1 CamelotEPS to save out 2 colour tables, the
02510                               second of which includes the shades. (In this way, we could
02511                               retain load-compatability with older versions)
02512     Outputs:    -
02513     Returns:    -
02514     Purpose:    Save out an indexed colour to an EPS file, and all the colours that rely
02515                 on it, i.e. any other indexed colours which are tints of, or links to, this
02516                 colour.
02517     Errors:     -
02518     SeeAlso:    -
02519 
02520 ********************************************************************************************/
02521 
02522 BOOL ColourListComponent::SaveColourAndChildren(IndexedColour *pCol, EPSExportDC *pDC, 
02523                                                 BOOL CamelotEPS, INT32 NestingLevel,
02524                                                 BOOL SaveShades)
02525 {
02526 #ifdef DO_EXPORT
02527 
02528     // (Jason 27/10/95) If the colour is unnamed and it's not actually used anywhere,
02529     // don't bother saving it. This optimises out temporary locals that are no longer
02530     // needed. At the worst, if something goes horribly wrong, this just means that
02531     // some locals might turn up as CMYK definitions on reloading, but this shouldn't
02532     // cause any problems unless something deeply scary has happened to the colour system.
02533     if (!pCol->IsNamed() && !pCol->IsInUse())
02534         return(TRUE);
02535 
02536     // Check for silly recursion errors [not that you can get circular references with
02537     // the amazingly strict and careful checking done by the IndexedColour class - JW ;-]
02538     ERROR2IF(NestingLevel > 200, FALSE, "Rampant linked colour nesting detected!");
02539 
02540     // First, save out this indexed colour.
02541     ColourModel Model = pCol->GetColourModel();
02542 
02543     // Buffer to build up colour defs in.
02544     TCHAR ColDef[256];
02545     camStrcpy(ColDef, _T("%%+"));
02546 
02547     // Buffer for temporary strings
02548     TCHAR TmpBuf[256];
02549 
02550     // Get information on the colour - ask for its full identifier rather than just the name,
02551     // so we get a unique id for unnamed colours rather than just "Local colour"
02552     ColourGeneric GenCol;
02553     IndexedColourType ColType = pCol->GetType();
02554     pCol->GetSourceColour(&GenCol);
02555     TCHAR *ColName = (TCHAR *) (*(pCol->GetName(TRUE)));
02556 
02557     // Special check - Shades are only properly preserved in CamelotEPS. In all others, they
02558     // are treated as unlinked, normal colours, so that they will be read happily.
02559     if (!CamelotEPS && ColType == COLOURTYPE_TINT && pCol->TintIsShade())
02560     {
02561         ColType = COLOURTYPE_NORMAL;
02562     }
02563 
02564     // If we shouldn't be saving shade colours or their children on this pass, then don't
02565     // do anything for them this time.
02566     if (!SaveShades && ColType == COLOURTYPE_TINT && pCol->TintIsShade())
02567         return(TRUE);
02568 
02569     // If saving shades, then don't bother with non-shade colours which have no children, as
02570     // they do not need to be output.
02571     if (SaveShades && (ColType != COLOURTYPE_TINT || !pCol->TintIsShade()) && !pCol->HasLinkedChildren())
02572         return(TRUE);
02573 
02574     // Check for tints
02575     if (ColType == COLOURTYPE_TINT)
02576     {
02577         FIXED24 TintVal(0.0);
02578         FIXED24 ShadeVal(0.0);
02579 
02580         // Add tint identifier to colour definition
02581         if (pCol->TintIsShade())
02582         {
02583             camStrcat(ColDef, _T("d"));     // Is a shaDe
02584             TintVal = pCol->GetShadeValueY();       // Note that it is written out as "Y X"
02585             ShadeVal = pCol->GetShadeValueX();      // to make backward compatability easier
02586         }
02587         else
02588         {
02589             camStrcat(ColDef, _T("t"));     // Is a Tint
02590             TintVal = pCol->GetTintValue();
02591         }
02592 
02593         ERROR3IF(NestingLevel < 1, "Bad nesting when saving a tint/shade colour");
02594 
02595         // Get tint/shade value as an integer in range 0 - 100.
02596         INT32 Tint = (INT32) ((TintVal.MakeDouble() * 100.0) + ((TintVal < 0) ? -0.5 : 0.5));
02597         INT32 Shade = (INT32) ((ShadeVal.MakeDouble() * 100.0) + ((ShadeVal < 0) ? -0.5 : 0.5));
02598 
02599         if (NestingLevel > 1)
02600         {
02601             // Write out the nesting level
02602             camSnprintf(TmpBuf, 256, _T(" %d"), NestingLevel);
02603             camStrcat(ColDef, TmpBuf);
02604         }
02605 
02606         // Add the colour name and tint value
02607         if (pCol->TintIsShade())
02608             camSnprintf(TmpBuf, 256, _T(" (%s) %d %d"), ColName, Tint, Shade);
02609         else
02610             camSnprintf(TmpBuf, 256, _T(" (%s) %d"), ColName, Tint);
02611             camStrcat(ColDef, TmpBuf);
02612     }
02613     else
02614     {
02615         // Is this a linked colour?
02616         BOOL Linked = (ColType == COLOURTYPE_LINKED);
02617 
02618         // We only do linked colours in CamelotEPS
02619         Linked = Linked && CamelotEPS;
02620 
02621         
02622         if (Linked)
02623         {
02624             // Mark this as a linked colour
02625             camStrcat(ColDef, _T("l"));
02626         }
02627         else if (CamelotEPS && (ColType == COLOURTYPE_SPOT))
02628         {
02629             // Mark this as a spot colour
02630             camStrcat(ColDef, _T("s"));
02631         }
02632 
02633         // Save out colour model, nesting level and colour name
02634         switch (Model)
02635         {
02636             case COLOURMODEL_RGBT:
02637                 camStrcat(ColDef, _T("r"));
02638                 break;
02639 
02640             case COLOURMODEL_HSVT:
02641                 camStrcat(ColDef, _T("h"));
02642                 break;
02643 
02644             case COLOURMODEL_CMYK:
02645                 camStrcat(ColDef, _T("c"));
02646                 break;
02647 
02648             case COLOURMODEL_GREYT:
02649                 // Special case - only Camelot can handle greyscales - ArtWorks can't.
02650                 if (CamelotEPS)
02651                     camStrcat(ColDef, _T("g"));
02652                 else
02653                     camStrcat(ColDef, _T("r"));
02654                 break;
02655 
02656             default:
02657                 break;
02658         }
02659 
02660         // Add nesting level, if needed
02661         if (NestingLevel > 1)
02662         {
02663             // Write out the nesting level
02664             camSnprintf(TmpBuf, 256, _T(" %d"), NestingLevel);
02665             camStrcat(ColDef, TmpBuf);
02666         }
02667 
02668         // Add colour name
02669         camStrcat(ColDef , _T(" ("));
02670         camStrcat(ColDef, ColName);
02671         camStrcat(ColDef, _T(")"));
02672 
02673         // Now write out the colour component values...
02674         switch (Model)
02675         {
02676             case COLOURMODEL_RGBT:
02677                 // Now add the RGB components.
02678                 ColourRGBT *pRGBT;
02679                 pRGBT = (ColourRGBT *) &GenCol;
02680 
02681                 AddComponentValue(ColDef, _T("%.3f"), pRGBT->Red.MakeDouble(),   LINKED(1));
02682                 AddComponentValue(ColDef, _T("%.3f"), pRGBT->Green.MakeDouble(), LINKED(2));
02683                 AddComponentValue(ColDef, _T("%.3f"), pRGBT->Blue.MakeDouble(),  LINKED(3));
02684                 break;
02685 
02686             case COLOURMODEL_HSVT:
02687                 // Now add the HSV components.
02688                 ColourHSVT *pHSVT;
02689                 pHSVT = (ColourHSVT *) &GenCol;
02690 
02691                 AddComponentValue(ColDef, _T("%.1f"), pHSVT->Hue.MakeDouble() * 360.0, LINKED(1));
02692                 AddComponentValue(ColDef, _T("%.1f"), pHSVT->Saturation.MakeDouble() * 100.0, LINKED(2));
02693                 AddComponentValue(ColDef, _T("%.1f"), pHSVT->Value.MakeDouble() * 100.0, LINKED(3));
02694                 break;
02695 
02696             case COLOURMODEL_CMYK:
02697                 // Now add the CMYK components.
02698                 ColourCMYK *pCMYK;
02699                 pCMYK = (ColourCMYK *) &GenCol;
02700 
02701                 AddComponentValue(ColDef, _T("%.3f"), pCMYK->Cyan.MakeDouble(),    LINKED(1));
02702                 AddComponentValue(ColDef, _T("%.3f"), pCMYK->Magenta.MakeDouble(), LINKED(2));
02703                 AddComponentValue(ColDef, _T("%.3f"), pCMYK->Yellow.MakeDouble(),  LINKED(3));
02704                 AddComponentValue(ColDef, _T("%.3f"), pCMYK->Key.MakeDouble(),     LINKED(4));
02705                 break;
02706 
02707             case COLOURMODEL_GREYT:
02708                 // ArtWorks doesn't have explicit greyscale colours - use RGB model.
02709                 ColourGreyT *pGreyT;
02710                 pGreyT = (ColourGreyT *) &GenCol;
02711                 double Intensity;
02712                 Intensity = pGreyT->Intensity.MakeDouble();
02713                 if (CamelotEPS)
02714                 {
02715                     // General greyscale format...just add the intensity component
02716                     AddComponentValue(ColDef, _T("%.3f"), Intensity, LINKED(1));
02717                 }
02718                 else
02719                 {
02720                     // Fake a greyscale for ArtWorks with an RGB colour
02721                     // where R = G = B.
02722                     for (INT32 i = 1; i <= 3; i++)
02723                     {
02724                         AddComponentValue(ColDef, _T("%.3f"), Intensity, FALSE);
02725                     }
02726                 }
02727                 break;
02728 
02729             default:
02730                 ERROR3("Unknown colour type found in EPS export!");
02731                 break;
02732         }
02733     }
02734 
02735     // Output colour definition to the EPS file
02736     pDC->OutputToken(ColDef);
02737     pDC->OutputNewLine();
02738 
02739 
02740     // (Jason 27/10/95) If it doesn't have linked children, don't recurse.
02741     // On large files, this saves a *lot* of time (O(n*n) becomes O(n)), because
02742     // (a) linked colours are only usually used sporadically, and (b) local colours,
02743     // which make up the bulk of saved colours, cannot have any children.
02744     if (!pCol->HasLinkedChildren())
02745         return(TRUE);
02746 
02747 
02748     // ---------- recurse ----------
02749 
02750 
02751     // Now recurse to save out any children of this colour (links or tints)...
02752 
02753     // Get all the named colours that are immediate children of this colour
02754     IndexedColour *pChild = (IndexedColour *) pIndexedColours->GetHead();
02755 
02756     while (pChild != NULL)
02757     {
02758         if (!pChild->IsDeleted() && pChild->FindLinkedParent() == pCol)
02759         {
02760             // Found a child - save out via recursion so we save all its descendants in the
02761             // right order...
02762             SaveColourAndChildren(pChild, pDC, CamelotEPS, NestingLevel + 1, SaveShades);
02763         }
02764 
02765         // Try the next colour
02766         pChild = (IndexedColour *) pIndexedColours->GetNext(pChild);
02767     }
02768 
02769     // Get all the unnamed colours that are immediate children of this colour
02770     List *pUnnamedList = pIndexedColours->GetUnnamedColours();
02771 
02772     pChild = (IndexedColour *) pUnnamedList->GetHead();
02773 
02774     while (pChild != NULL)
02775     {
02776         if (!pChild->IsDeleted() && pChild->FindLinkedParent() == pCol)
02777         {
02778             // Found a child - save out via recursion so we save all its descendants in the
02779             // right order...
02780             SaveColourAndChildren(pChild, pDC, CamelotEPS, NestingLevel + 1, SaveShades);
02781         }
02782 
02783         // Try the next colour
02784         pChild = (IndexedColour *) pUnnamedList->GetNext(pChild);
02785     }
02786 #endif
02787     return TRUE;
02788 }
02789 
02790 
02791 /********************************************************************************************
02792 
02793 >   ProcessEPSResult ColourListComponent::ProcessEPSComment(EPSFilter *pFilter, 
02794                                                             const char *pComment)
02795 
02796     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
02797     Created:    02/08/94
02798     Inputs:     pFilter - the EPS filter that is being used to import a file.
02799                 pComment - pointer to the comment to process.
02800     Returns:    EPSCommentUnknown    - This EPS comment is not recognised by the document
02801                                        component.
02802                 EPSCommentError      - This EPS comment was recognised by this document
02803                                        component, but it contained an error.
02804                 EPSCommentOK         - This EPS comment was recognised as a legal comment by 
02805                                        this document component, and was processed
02806                                        successfully.
02807     Purpose:    Process an EPS comment - if this is a colour table comment, this component
02808                 will claim it and try to decode it.
02809 
02810     Notes:      IMPORTANT
02811                 There is a new colour field (which should only be put in a JWColourTable
02812                 in CamelotEPS) which starts a comment line with "%%+x". The remainder of the
02813                 line is undefined, but is treated as a valid line. This will make it possible
02814                 to add data to the colour list in future without losing backward compatability
02815                 or having to add yet another colour table type!
02816                 If you use this, make sure your code happily *ignores* unknown x extensions.
02817 
02818     Errors:     Badly formed EPS comment.
02819     SeeAlso:    DocComponent::ProcessEPSComment
02820 
02821 ********************************************************************************************/
02822 
02823 ProcessEPSResult ColourListComponent::ProcessEPSComment(EPSFilter *pFilter, 
02824                                                         PCTSTR pComment)
02825 {
02826     if (pFilter->IsKindOf(CC_RUNTIME_CLASS(ArtWorksEPSFilter)))
02827     {
02828         // Is it a Camelot specific filter?
02829         BOOL CamelotEPS = pFilter->IsKindOf(CC_RUNTIME_CLASS(CamelotEPSFilter));
02830 
02831         // ArtWorks EPS (or derivative)
02832         if (camStrncmp(pComment, _T("%%AWColourTable"), 15) == 0)
02833         {
02834             // Found a colour table
02835             return EPSCommentOK;
02836         }
02837         else if (camStrncmp(pComment, _T("%%JWColourTable"), 15) == 0)
02838         {
02839             // Found a version 1.1 extended colour table
02840             return EPSCommentOK;            
02841         }
02842         else if (camStrncmp(pComment, _T("%%+"), 3) == 0)
02843         {
02844             // Found a colour - add it to the colour list for the document.
02845 
02846             // Take a copy of this comment
02847             TCHAR Comment[256];
02848             camStrcpy(Comment, pComment);
02849 
02850             // Find out the colour model (c, h, r, or t)
02851             INT32 i = 3;
02852             TCHAR ColModel = Comment[i++];
02853 
02854             // Check for special types (NB a colour cannot be both a spot colour and
02855             // a linked colour).
02856             NewColourInfo ColourInfo;
02857             BOOL Linked = FALSE;
02858 
02859             // Is it a spot colour?
02860             if  (ColModel == 's')
02861             {
02862                 ColourInfo.Type = COLOURTYPE_SPOT;
02863                 ColModel = Comment[i++];
02864             }
02865             else if (ColModel == 'l')
02866             {
02867                 // It's a link, then find out the colour model of the linked colour.
02868                 Linked = TRUE;
02869                 ColourInfo.Type = COLOURTYPE_LINKED;
02870                 ColModel = Comment[i++];
02871             }
02872 
02873             // If a tint/shade or link, find the nesting level, if any
02874             INT32 ColourNesting = 0;
02875             if ((ColModel == 't') || (ColModel == 'd') || Linked)
02876             {
02877                 // Skip until we find a digit, a '(' or a terminator
02878                 while (!isdigit(Comment[i]) && (Comment[i] != '(') && (Comment[i] != 0))
02879                     i++;
02880 
02881                 // Is there a nesting level?
02882                 if (isdigit(Comment[i]))
02883                 {
02884                     // Yes - extract it and skip past it.
02885                     ColourNesting = camAtol(Comment+i);
02886 
02887                     while (isdigit(Comment[i]))
02888                         i++;
02889                 }
02890                 else
02891                 {
02892                     // Must be level 1
02893                     ColourNesting = 1;
02894                 }
02895             }
02896 
02897             // Do we need to alter the link context?
02898             if (ColourNesting == 0)
02899             {
02900                 // Normal colour
02901                 pNewColours->RestoreContextTo(0);
02902             }
02903             else if (ColourNesting <= LinkNesting)
02904             {
02905                 // Falling back to a previous nesting level - restore context to one
02906                 // less than the nesting of this link/tint
02907                 // (because we want to link/tint the colour one level below this one
02908                 // in the nesting).
02909                 LinkNesting = ColourNesting - 1;
02910                 pNewColours->RestoreContextTo(LinkNesting);
02911             }
02912 
02913             // Find the colour name
02914             while ((Comment[i] != '(') && (Comment[i] != 0))
02915                 i++;
02916 
02917             // Got it - copy it out of the string (skip the opening parenthesis)
02918             TCHAR ColName[128];
02919             i = ExtractString(Comment, i+1, ColName);
02920             String_64 ColNameS = ColName;
02921 
02922             // Copied the name - skip any whitespace
02923             while (((Comment[i] == ' ') || (Comment[i] == '\t')) &&
02924                    (Comment[i] != 0))
02925             {
02926                 i++;
02927             }
02928             
02929             // Check for the overprint flag
02930             if (Comment[i] == 'o')
02931             {
02932                 // Ignore it for now...
02933                 i++;
02934                 while (((Comment[i] == ' ') || (Comment[i] == '\t')) &&
02935                        (Comment[i] != 0))
02936                 {
02937                     i++;
02938                 }
02939             }
02940 
02941 
02942             // Validate the colour model for this filter.
02943             if ((ColModel != 'r') && (ColModel != 'c') &&           // Rgb, Cmyk
02944                 (ColModel != 'h') && (ColModel != 't'))             // Hsv, Tint
02945             {
02946                 // Reject outright if this is an ArtWorks file
02947                 if (!CamelotEPS)
02948                 {
02949                     pFilter->HandleEPSError();
02950                     return EPSCommentSyntaxError;
02951                 }
02952             }
02953 
02954             // Do we need to save the context before adding this colour?
02955             if (Linked || (ColModel == 't') || (ColModel == 'd'))
02956             {
02957                 pNewColours->SaveContext();
02958                 LinkNesting++;
02959             }
02960 
02961             // Read the colour components according to the colour model.
02962             switch (ColModel)
02963             {
02964                 case 'r':
02965                 case 'R':
02966                     {
02967                         ColourRGBT NewRGBT;
02968                         ReadEPS_RGB(&NewRGBT, Comment + i, &ColourInfo);
02969                         if (!pNewColours->AddColour(&ColNameS, &NewRGBT, &ColourInfo))
02970                             return EPSCommentSystemError;
02971                     }
02972                     break;
02973 
02974                 case 'c':
02975                     {
02976                         ColourCMYK NewCMYK;
02977                         ReadEPS_CMYK(&NewCMYK, Comment + i, &ColourInfo);
02978                         if (!pNewColours->AddColour(&ColNameS, &NewCMYK, &ColourInfo))
02979                             return EPSCommentSystemError;
02980                     }
02981                     break;
02982 
02983                 case 'h':
02984                 case 'H':
02985                     {
02986                         ColourHSVT NewHSVT;
02987                         ReadEPS_HSV(&NewHSVT, Comment + i, &ColourInfo);
02988                         if (!pNewColours->AddColour(&ColNameS, &NewHSVT, &ColourInfo))
02989                             return EPSCommentSystemError;
02990                     }
02991                     break;
02992 
02993                 case 't':       // Tint
02994                     {
02995                         UINT32 Tint = ReadEPS_Tint(Comment + i);
02996 
02997                         if (!pNewColours->AddTint(&ColNameS, Tint))
02998                             return EPSCommentSystemError;
02999                     }
03000                     break;
03001 
03002                 case 'd':       // Shade - saved in same format as tint, so re-use ReadEPS_Tint method
03003                     {
03004                         INT32 ShadeX;
03005                         INT32 ShadeY;
03006                         ReadEPS_Shade(Comment + i, &ShadeX, &ShadeY);
03007 
03008                         if (!pNewColours->AddShade(&ColNameS, ShadeX, ShadeY))
03009                             return EPSCommentSystemError;
03010                     }
03011                     break;
03012 
03013                 case 'G':
03014                 case 'g':
03015                     {
03016                         ColourGreyT NewGreyT;
03017                         ReadEPS_Grey(&NewGreyT, Comment + i, &ColourInfo);
03018 
03019                         // Bodge for version 2
03020                         // We really want black to be defined as CMYK so that it colour separates
03021                         // more cleanly (and also merges on import better with new docs). Prior to v2,
03022                         // the default black was defined as a greyscale so we sit on it during import
03023                         // and turn it into a CMYK colour.
03024                         if (NewGreyT.Intensity == 0 && ColNameS == String_64(TEXT("Black")))
03025                         {
03026                             ColourCMYK Bodge;
03027                             Bodge.Cyan = Bodge.Magenta = Bodge.Yellow = 0;
03028                             Bodge.Key = 1.0;
03029 
03030                             if (!pNewColours->AddColour(&ColNameS, &Bodge, &ColourInfo))
03031                                 return EPSCommentSystemError;
03032                         }
03033                         else
03034                         {
03035                             if (!pNewColours->AddColour(&ColNameS, &NewGreyT, &ColourInfo))
03036                                 return EPSCommentSystemError;
03037                         }
03038                     }
03039                     break;
03040             }
03041 
03042             // Parsed this colour ok.
03043             return EPSCommentOK;
03044         }
03045     }
03046     // Ignore all other comments
03047     return EPSCommentUnknown;
03048 }
03049 
03050 
03051 /********************************************************************************************
03052 
03053 >   INT32 ColourListComponent::ExtractString(const char *Comment, INT32 Start, char *String)
03054 
03055     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
03056     Created:    07/08/94
03057     Inputs:     Comment - pointer to the comment.
03058                 Start - offset into Comment of the first character of the string (not
03059                         including the first opening parenthesis).
03060     Outputs:    String - the PostScript string.
03061     Returns:    The offset to the first character after the closing parenthesis of
03062                 the string.
03063     Purpose:    Copy a PostScript string out of the given EPS comment.  It handles
03064                 nested parentheses - e.g. a string like (Hello (there)) will be
03065                 correctly returned in String as "Hello (there)".
03066                 The end of the comment is also taken as terminating the string.
03067 
03068 ********************************************************************************************/
03069 
03070 INT32 ColourListComponent::ExtractString( PCTSTR Comment, INT32 Start, PTSTR String)
03071 {
03072 //  INT32 i = Start;
03073 //  INT32 j = 0;
03074 //  INT32 StringNesting = 1;
03075     
03076     // Look for the last closing Parenthesis in this string...
03077     const TCHAR        *End = camStrrchr(Comment, ')');
03078 
03079     if ((End == NULL) || (End < (Comment + Start)))
03080     {
03081         // Something's gone wrong - don't extract string and put a warning where the colour name
03082         // should be.
03083         camStrcpy( String, _T("Colour Import Error") );
03084         return Start;
03085     }
03086 
03087     // Copy the colour name from the comment into the string provided, and NULL
03088     // terminate it.
03089     INT32 NameLength = End - Comment;
03090     NameLength -= Start;
03091 
03092     camStrncpy( String, Comment + Start, NameLength );
03093     String[NameLength] = 0;
03094 
03095     // Return the next character position after the string's closing parenthesis.
03096     return Start + NameLength + 1;
03097 }
03098 
03099 /********************************************************************************************
03100 
03101 >   void ColourListComponent::ReadEPS_RGB(ColourRGBT *pCol, char *pComment, 
03102                                       NewColourInfo *pColourInfo)
03103 
03104     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
03105     Created:    03/08/94
03106     Inputs:     pCol - the colour to initialise from the comment.
03107                 pComment - pointer to the comment fields to use.
03108                 pColourInfo - if NULL, then this is not a linked colour
03109                               if non-NULL, then this is a linked colour, and the fields
03110                                 should be filled in according to the inheritance flags
03111                                 found in the colour definition.
03112     Purpose:    Read the RGB components from an ArtWorks EPS colour table comment, and
03113                 initialise an indexed colour object using these values.
03114                 The comment passed in is expected to be a pointer to the character just
03115                 after the colour name/overprint flag, i.e. the start of the colour
03116                 description.  Leading white space is permissible.
03117     SeeAlso:    ColourListComponent::ReadEPS_CMYK; ColourListComponent::ReadEPS_HSV;
03118                 ColourListComponent::ReadEPS_Tint
03119 
03120 ********************************************************************************************/
03121 
03122 void ColourListComponent::ReadEPS_RGB( ColourRGBT *pCol, PTSTR pComment, 
03123                                   NewColourInfo *pColourInfo )
03124 {
03125     BOOL Linked = (pColourInfo != NULL) && (pColourInfo->Type == COLOURTYPE_LINKED);
03126 
03127     PTSTR pszTokMark = NULL ;
03128     PTSTR Value = camStrtok(pComment, _T(" \t"), &pszTokMark);
03129     if (Value != NULL)
03130     {
03131         if (Linked && (camStrcmp(Value, _T("-") ) == 0))
03132             pColourInfo->Inherits[0] = TRUE;
03133         else
03134             pCol->Red = camStrtof( Value, &pszTokMark );
03135     }
03136 
03137     Value = camStrtok( NULL, _T(" \t"), &pszTokMark );
03138     if (Value != NULL)
03139     {
03140         if (Linked && (camStrcmp(Value, _T("-") ) == 0))
03141             pColourInfo->Inherits[1] = TRUE;
03142         else
03143             pCol->Green = camStrtof( Value, &pszTokMark );
03144     }
03145 
03146     Value = camStrtok( NULL, _T(" \t"), &pszTokMark );
03147     if (Value != NULL)
03148     {
03149         if (Linked && (camStrcmp(Value, _T("-") ) == 0))
03150             pColourInfo->Inherits[2] = TRUE;
03151         else
03152             pCol->Blue = camStrtof( Value, &pszTokMark );
03153     }
03154 
03155     // No transparency
03156     pCol->Transparent = 0.0;
03157 }
03158 
03159 /********************************************************************************************
03160 
03161 >   void ColourListComponent::ReadEPS_CMYK(ColourCMYK *pCol, char *pComment, 
03162                                        NewColourInfo *pColourInfo)
03163 
03164     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
03165     Created:    03/08/94
03166     Inputs:     pCol - the colour to initialise from the comment.
03167                 pComment - pointer to the comment fields to use.
03168     Purpose:    Read the CMYK components from an ArtWorks EPS colour table comment, and
03169                 initialise an indexed colour object using these values.
03170                 The comment passed in is expected to be a pointer to the character just
03171                 after the colour name/overprint flag, i.e. the start of the colour
03172                 description.  Leading white space is permissible.
03173     SeeAlso:    ColourListComponent::ReadEPS_RGB; ColourListComponent::ReadEPS_HSV;
03174                 ColourListComponent::ReadEPS_Tint
03175 
03176 ********************************************************************************************/
03177 
03178 void ColourListComponent::ReadEPS_CMYK(ColourCMYK *pCol, PTSTR pComment, 
03179                                    NewColourInfo *pColourInfo)
03180 {
03181     BOOL Linked = (pColourInfo != NULL) && (pColourInfo->Type == COLOURTYPE_LINKED);
03182 
03183     TCHAR *State = NULL;
03184     TCHAR *Value = camStrtok(pComment, _T(" \t"), &State);
03185     if (Value != NULL)
03186     {
03187         if (Linked && (camStrcmp(Value, _T("-")) == 0))
03188             pColourInfo->Inherits[0] = TRUE;
03189         else
03190             pCol->Cyan = camAtof(Value);
03191     }
03192 
03193     Value = camStrtok(NULL, _T(" \t"), &State);
03194     if (Value != NULL)
03195     {
03196         if (Linked && (camStrcmp(Value, _T("-")) == 0))
03197             pColourInfo->Inherits[1] = TRUE;
03198         else
03199             pCol->Magenta = camAtof(Value);
03200     }
03201 
03202     Value = camStrtok(NULL, _T(" \t"), &State);
03203     if (Value != NULL)
03204     {
03205         if (Linked && (camStrcmp(Value, _T("-")) == 0))
03206             pColourInfo->Inherits[2] = TRUE;
03207         else
03208             pCol->Yellow = camAtof(Value);
03209     }
03210 
03211     Value = camStrtok(NULL, _T(" \t"), &State);
03212     if (Value != NULL)
03213     {
03214         if (Linked && (camStrcmp(Value, _T("-")) == 0))
03215             pColourInfo->Inherits[3] = TRUE;
03216         else
03217             pCol->Key = camAtof(Value);
03218     }
03219 
03220 }
03221 
03222 /********************************************************************************************
03223 
03224 >   void ColourListComponent::ReadEPS_HSV(ColourHSVT *pCol, char *pComment,
03225                                       NewColourInfo *pColourInfo)
03226 
03227     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
03228     Created:    03/08/94
03229     Inputs:     pCol - the colour to initialise from the comment.
03230                 pComment - pointer to the comment fields to use.
03231     Purpose:    Read the HSV components from an ArtWorks EPS colour table comment, and
03232                 initialise an indexed colour object using these values.
03233                 The comment passed in is expected to be a pointer to the character just
03234                 after the colour name/overprint flag, i.e. the start of the colour
03235                 description.  Leading white space is permissible.
03236     SeeAlso:    ColourListComponent::ReadEPS_RGB; ColourListComponent::ReadEPS_CMYK;
03237                 ColourListComponent::ReadEPS_Tint
03238 
03239 ********************************************************************************************/
03240 
03241 void ColourListComponent::ReadEPS_HSV(ColourHSVT *pCol, PTSTR pComment,
03242                                   NewColourInfo *pColourInfo)
03243 {
03244     BOOL Linked = (pColourInfo != NULL) && (pColourInfo->Type == COLOURTYPE_LINKED);
03245 
03246     TCHAR *State = NULL;
03247     TCHAR *Value = camStrtok(pComment, _T(" \t"), &State);
03248     if (Value != NULL)
03249     {
03250         if (Linked && (camStrcmp(Value, _T("-")) == 0))
03251             pColourInfo->Inherits[0] = TRUE;
03252         else
03253             pCol->Hue = camAtof(Value) / 360.0;
03254     }
03255 
03256     Value = camStrtok(NULL, _T(" \t"), &State);
03257     if (Value != NULL)
03258     {
03259         if (Linked && (camStrcmp(Value, _T("-")) == 0))
03260             pColourInfo->Inherits[1] = TRUE;
03261         else
03262             pCol->Saturation = camAtof(Value) / 100.0;
03263     }
03264 
03265     Value = camStrtok(NULL, _T(" \t"), &State);
03266     if (Value != NULL)
03267     {
03268         if (Linked && (camStrcmp(Value, _T("-")) == 0))
03269             pColourInfo->Inherits[2] = TRUE;
03270         else
03271             pCol->Value = camAtof(Value) / 100.0;
03272     }
03273 
03274     // No transparency
03275     pCol->Transparent = 0.0;
03276 
03277 }
03278 
03279 /********************************************************************************************
03280 
03281 >   void ColourListComponent::ReadEPS_Grey(ColourGreyT *pCol, char *pComment,
03282                                        NewColourInfo *pColourInfo)
03283 
03284     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
03285     Created:    03/08/94
03286     Inputs:     pCol - the colour to initialise from the comment.
03287                 pComment - pointer to the comment fields to use.
03288     Purpose:    Read the HSV components from an ArtWorks EPS colour table comment, and
03289                 initialise an indexed colour object using these values.
03290                 The comment passed in is expected to be a pointer to the character just
03291                 after the colour name/overprint flag, i.e. the start of the colour
03292                 description.  Leading white space is permissible.
03293     SeeAlso:    ColourListComponent::ReadEPS_RGB; ColourListComponent::ReadEPS_CMYK;
03294                 ColourListComponent::ReadEPS_Tint
03295 
03296 ********************************************************************************************/
03297 
03298 void ColourListComponent::ReadEPS_Grey(ColourGreyT *pCol, PTSTR pComment,
03299                                    NewColourInfo *pColourInfo)
03300 {
03301     BOOL Linked = (pColourInfo != NULL) && (pColourInfo->Type == COLOURTYPE_LINKED);
03302 
03303     TCHAR * State=NULL;
03304     TCHAR *Value = camStrtok(pComment, _T(" \t"), &State);
03305     if (Value != NULL)
03306     {
03307         if (Linked && (camStrcmp(Value, _T("-")) == 0))
03308             pColourInfo->Inherits[0] = TRUE;
03309         else
03310             pCol->Intensity = camAtof(Value);
03311     }
03312 
03313     // Clear the reserved words to 0.
03314     pCol->Reserved1 = 0.0;
03315     pCol->Reserved2 = 0.0;
03316 
03317     // No transparency
03318     pCol->Transparent = 0.0;
03319 }
03320 
03321 /********************************************************************************************
03322 
03323 >   void ColourListComponent::ReadEPS_Tint(char *pComment)
03324 
03325     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
03326     Created:    07/08/94
03327     Inputs:     pComment - pointer to the comment fields to use.
03328     Purpose:    Read the tint value from an ArtWorks style tint colour definition comment.
03329 
03330                 (OR Read the shade value out of a CamelotEPS shade ("d") comment. Shades
03331                 are stored in identical; format to tints)
03332 
03333     SeeAlso:    ColourListComponent::ReadEPS_RGB; ColourListComponent::ReadEPS_CMYK;
03334                 ColourListComponent::ReadEPS_HSVT
03335 
03336 ********************************************************************************************/
03337 
03338 UINT32 ColourListComponent::ReadEPS_Tint( PTSTR pComment )
03339 {
03340     PTSTR pszTokMark = NULL;
03341     PTSTR Value = camStrtok( pComment, _T(" \t"), &pszTokMark );
03342     INT32 Tint = 0;
03343     if (Value != NULL)
03344     {
03345         // Get the tint value
03346         Tint = camStrtol( Value, &pszTokMark, 10 );
03347         if (Tint < 0)
03348             Tint = 0;
03349     }
03350 
03351     return (UINT32) Tint;
03352 }
03353 
03354 
03355 
03356 /********************************************************************************************
03357 
03358 >   void ColourListComponent::ReadEPS_Shade(char *pComment, INT32 *ResultX, INT32 *ResultY)
03359 
03360     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03361     Created:    13/10/95
03362     Inputs:     pComment - pointer to the comment fields to use.
03363 
03364     Outputs:    ResultX,ResultY - returned with the shade values
03365 
03366     Purpose:    Read the shade values from a Camelot shade colour definition comment.
03367 
03368                 (OR Read the shade value out of a CamelotEPS shade ("d") comment. Shades
03369                 are stored in identical; format to tints)
03370 
03371     Notes:      Old style shades had only one relative value (Y). If this is missing,
03372                 then an appropriate default is chosen such that it all still works.
03373 
03374     SeeAlso:    ColourListComponent::ReadEPS_RGB; ColourListComponent::ReadEPS_CMYK;
03375                 ColourListComponent::ReadEPS_HSVT
03376 
03377 ********************************************************************************************/
03378 
03379 void ColourListComponent::ReadEPS_Shade( PTSTR pComment, INT32 *ResultX, INT32 *ResultY)
03380 {
03381     PTSTR pszTokMark = NULL;
03382     PTSTR Value = camStrtok( pComment, _T(" \t"), &pszTokMark );
03383     INT32  Val = 0;
03384     if( Value != NULL )
03385         Val = camStrtol( Value, &pszTokMark, 10 );
03386 
03387     *ResultY = (INT32)Val;
03388 
03389     Value = camStrtok( NULL, _T(" \t"), &pszTokMark );
03390     if (Value != NULL)
03391     {
03392         Val = camStrtol( Value, &pszTokMark, 10 );
03393 
03394 TRACEUSER( "Jason", _T("Load new shade %ld %ld\n"), Val, (INT32)*ResultY);
03395     }
03396     else
03397     {
03398         // There is no second token - it must be in the old save format
03399         // The old value was a 0-100 shade-to-black, so to convert into the new
03400         // format we just negate it. Happy Happy Bodge Bodge.
03401         *ResultY = -(*ResultY);
03402         
03403         // And set a sensible X value
03404         Val = 0;
03405 TRACEUSER( "Jason", _T("Load OLD shade %ld %ld\n"), Val, (INT32)*ResultY);
03406     }
03407 
03408     *ResultX = (INT32)Val;
03409 }
03410 
03411 
03412 
03413 
03414 /********************************************************************************************
03415 
03416 >   void ColourListComponent::EndOfEPSComment(EPSFilter *pFilter)
03417 
03418     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
03419     Created:    02/08/94
03420     Inputs:     pFilter - the EPS filter that is being used to import a file.
03421     Purpose:    Informs the document component that the comment it has been decoding has
03422                 now finished, and it should take whatever action required to act on
03423                 the comment.
03424     SeeAlso:    DocComponent::EndOfPESComment
03425 
03426 ********************************************************************************************/
03427 
03428 void ColourListComponent::EndOfEPSComment(EPSFilter *pFilter)
03429 {
03430     // Do any cleanup we need to here after loading in a colour table...
03431 }
03432 
03433 
03434 
03435 /********************************************************************************************
03436 
03437 >   IndexedColour *ColourListComponent::FindNamedColour(const char *pName, 
03438                                                         DocColour *ColDef = NULL,
03439                                                         UINT32 Tint = 100,
03440                                                         BOOL Strict = FALSE)
03441 
03442     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
03443     Created:    04/08/94
03444     Inputs:     pName - the name of the colour to find.
03445                 ColDef - the colour definition that it should match.
03446                 Tint - the tint value applied to ColDef (NB it should already have been
03447                        applied); 100 = same colour, 0 = white.
03448 
03449                 Strict - not used (obsolete)
03450 
03451     Returns:    Pointer to the indexed colour that corresponds to the file's named colour;
03452                 or NULL if the colour could not be found (the caller should fall back to
03453                    an immediate colour in this case).
03454     Purpose:    Given the name of an imported named colour, return the relevant indexed
03455                 colour.  This allows attributes to be added when importing that use
03456                 named colours.
03457                 If ColDef is not NULL, then the Indexed colour found is checked to see
03458                 if it agrees with the definition in ColDef - if not, then a new indexed
03459                 colour is made, and a pointer to that is returned instead.  This means we
03460                 can cope with brain-damaged formats that have two or more named colours
03461                 with the same format.  It also makes it easy to cope with formats that
03462                 use unnamed colours, as we just keep making colours called "Unnamed colour"
03463                 or similar, and this function works it all out for us.
03464 
03465                 If the named colour is not found, and ColDef is not NULL, then again a
03466                 new Indexed colour is created, and a pointer to it is returned.
03467 
03468                 NB. The name of the indexed colour returned MAY NOT have the same name as
03469                 specified in pName, because it may clash with colours already in the
03470                 document, and hence may have been mangled to make it unambiguous.
03471 
03472 ********************************************************************************************/
03473 
03474 IndexedColour *ColourListComponent::FindNamedColour( PCTSTR pName, 
03475                                                     DocColour *ColDef,
03476                                                     UINT32 Tint,
03477                                                     BOOL Strict)
03478 {
03479     // Sanity check
03480     ENSURE(pNewColours != NULL, "Someone asked for an imported colour when there is no import going on!");
03481 
03482     if (pNewColours == NULL)
03483         return NULL;
03484 
03485     // Special case for tinted colours - if the Tint is not 100%, then we must look for
03486     // or create a tinted version of the colour.
03487     if (Tint != 100)
03488     {
03489         // Create a new name to indicate this is tinted
03490         String_64 NewName(pName);
03491 
03492         // Work out where to add the tint comment to the colour name.
03493         // Comment is of the form: " (xx% tint)", which is 11 characters long.
03494         INT32 Len = NewName.Length();
03495         if (Len > 50)
03496         {
03497             // This should give us enough room for our tint comment
03498             Len = 50;
03499         }
03500 
03501         TCHAR          *pNewName = (TCHAR *)NewName;
03502         camSnprintf( pNewName + Len, 64 - Len, _T(" (%d%% tint)"), Tint );
03503 
03504         // Ok - we have a name - recurse so we can get a new colour (or use an existing
03505         // one created by this bit of code).
03506         return FindNamedColour(NewName, ColDef);
03507     }
03508 
03509     // Find the colour in the imported colour table.
03510     IndexedColour *pColour;
03511     PColourCMYK CMYK;
03512     ColDef->GetCMYKValue(&CMYK);
03513     pColour = pNewColours->GetColour( pName, &CMYK );
03514 
03515     // Is there one that fits the bill?
03516     if (pColour != NULL)
03517         return pColour;
03518 
03519     // Colour not found - can we make a new one?
03520     if (ColDef != NULL)
03521     {
03522         // Yes - add a new colour...
03523 
03524         // Make a proper definition:
03525         ColourCMYK FullCMYK;
03526         FullCMYK.Cyan    = FIXED24( ((double) CMYK.Cyan)    / 255.0 );
03527         FullCMYK.Magenta = FIXED24( ((double) CMYK.Magenta) / 255.0 );
03528         FullCMYK.Yellow  = FIXED24( ((double) CMYK.Yellow)  / 255.0 );
03529         FullCMYK.Key     = FIXED24( ((double) CMYK.Key)     / 255.0 );
03530 
03531         // And use it to add the colour
03532         String_64 NewName(pName);
03533         if (pNewColours->AddColour(&NewName, &FullCMYK))
03534         {
03535             // It worked - return the colour created
03536             return pNewColours->GetColour( pName, &CMYK );
03537         }
03538         else
03539         {
03540             // Failed to add a new colour
03541             return NULL;
03542         }
03543     }
03544 
03545     // Can't make a new one without a colour definition - give up.
03546     return NULL;
03547 }
03548 
03549 
03550 /********************************************************************************************
03551 
03552 >   BOOL ColourListComponent::FindIdenticalColour(IndexedColour *pColour,
03553                                                   IndexedColour **pResult)
03554 
03555     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
03556     Created:    07/08/94
03557     Inputs:     pColour - the colour to match with.
03558     Outputs:    pResult - pointer to the matching colour, if found;
03559                           NULL otherwise.
03560     Returns:    TRUE if a colour with this *name* was found in the document;
03561                 FALSE if not.
03562     Purpose:    Find out if there is already a colour exactly the same as the one passed
03563                 in in the existing colour list.  If so, return a pointer to it, otherwise
03564                 return NULL.
03565                 Also indicates whether or not a colour with this name already exists in the
03566                 document, regardless of whether the colour data is the same.
03567 
03568 ********************************************************************************************/
03569 
03570 BOOL ColourListComponent::FindIdenticalColour(IndexedColour *pColour,
03571                                               IndexedColour **pResult)
03572 {
03573     IndexedColour *pItem = (IndexedColour *) pIndexedColours->GetHead();
03574 
03575     BOOL FoundSameName = FALSE;
03576 
03577     // Get the name/ID for this colour. TRUE is passed in so that unnamed colours return
03578     // their unique id string rather than "Local colour"
03579     String_64 *Name1 = pColour->GetName(TRUE);
03580 
03581     while (pItem != NULL)
03582     {
03583         // Don't bother with deleted colours
03584         if (!pItem->IsDeleted())
03585         {
03586             // WEBSTER - markn 14/2/97
03587             // Introduced WEBSTER_IGNORE_NAME_MATCHING so that Webster can ignore the name when
03588             // trying to find an identical colour
03589 
03590             #if WEBSTER_IGNORE_NAME_MATCHING 
03591             if (pIndexedColours != NULL)
03592             {
03593                 if (!pItem->IsDifferent(*pColour, COL_ACCURACY))
03594                 {
03595                     if (ColourSGallery::CanAddColourToGallery(pItem,pIndexedColours))
03596                     {
03597                         *pResult = pItem;
03598                         return TRUE;
03599                     }
03600                 }
03601             }
03602             #else
03603             // Compare names
03604             String_64 *Name2 = pItem->GetName(TRUE);
03605             if ((*Name1) == (*Name2))
03606             {
03607                 FoundSameName = TRUE;
03608 
03609                 // Name is the same - what about colour model + definition?
03610                 if (!pItem->IsDifferent(*pColour, COL_ACCURACY))
03611                 {
03612                     // The colour defn the same too - it's a match
03613                     *pResult = pItem;
03614                     return TRUE;
03615                 }
03616             }
03617             #endif // WEBSTER_IGNORE_NAME_MATCHING 
03618         }
03619 
03620         // Try the next colour
03621         pItem = (IndexedColour *) pIndexedColours->GetNext(pItem);
03622     }
03623 
03624     // No match - tell caller whether we found one with the same name.
03625     *pResult = NULL;
03626     return FoundSameName;
03627 }
03628 
03629 
03630 
03631 
03632 
03633 
03634 
03635 
03636 /********************************************************************************************
03637 
03638 >   IndexedColour *ColourListComponent::ExactMatchExists(IndexedColour *SourceColour)
03639 
03640     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03641     Created:    18/10/94
03642 
03643     Inputs:     SourceColour - The colour to match
03644     Returns:    A pointer to the IndexedColour in this document which exactly matches the
03645                 given SourceColour, or NULL if no matching colour exists.
03646 
03647     Purpose:    Determine if a colour is already available in the paste-destination document
03648                 This allows us to merge IndexedColours on the clipboard with those in the
03649                 target document when doing a paste operation.
03650 
03651     Notes:      Exact match means: Another non-deleted colour which is not IsDifferent
03652                 and which has an identical (sortof - see below) name string.
03653 
03654                 SPECIAL behaviour: The name string match now ignores digits on the end
03655                 of the string. This is so that if you copy and paste "Red" such that the pasted
03656                 colour is "Red 2", a subsequent paste will match the source "Red" and the
03657                 destination "Red 2", rather than adding an identical "Red 3"!
03658 
03659                 Unnamed colours will never match.
03660 
03661     SeeAlso:    ColourListComponent::CopyColourAcross
03662 
03663 ********************************************************************************************/
03664 
03665 IndexedColour *ColourListComponent::ExactMatchExists(IndexedColour *SourceColour)
03666 {
03667     // If it's an unnamed (local) colour, then we don't bother looking for a match
03668     if (!SourceColour->IsNamed())
03669         return(NULL);
03670 
03671     IndexedColour *pItem = (IndexedColour *) pIndexedColours->GetHead();
03672 
03673     // --- First check for any *exact* matches
03674     // Get the name/ID for this colour. TRUE is passed in so that unnamed colours return
03675     // their unique id string rather than "Local colour" (hmmm... we aren't checking 
03676     // unnamed colours, so this is a bit of a moot point! ;-)
03677     String_64 SourceName = *(SourceColour->GetName(TRUE));
03678 
03679     while (pItem != NULL)
03680     {
03681         if (!pItem->IsDeleted() && !pItem->IsDifferent(*SourceColour))  // not different, so check name
03682         {
03683             if (SourceName.CompareTo(*pItem->GetName(TRUE)) == 0)       // If has same name then...
03684                 return(pItem);                                          // Return it as match
03685         }
03686 
03687         // Try the next colour
03688         pItem = (IndexedColour *) pIndexedColours->GetNext(pItem);
03689     }
03690 
03691 
03692     // --- Second, check for near-matches.
03693     // This is an exact match except it ignores the space and digits appended to a name
03694     // in the quest for a unique name. This means if the name "Red" is in use, and we paste
03695     // a different colour called "Red" it will add "Red 2" the first paste, but subsequent
03696     // pastes will match "Red 2" and simply merge with that colour (rather than adding Red 2
03697     // Red 3, Red 4, ect ad infinitum!)
03698     pItem = (IndexedColour *) pIndexedColours->GetHead();
03699     while (pItem != NULL)
03700     {
03701         if (!pItem->IsDeleted() && !pItem->IsDifferent(*SourceColour))          // not different, so check name
03702         {
03703             // Get the string as a TCHAR array so we can actually do something with it (grr)
03704             TCHAR *StrPtr = (TCHAR *) (*pItem->GetName(TRUE));
03705 
03706             // Find the zero terminator
03707             INT32 Index = 0;
03708             while (StrPtr[Index] != (TCHAR)'\0')
03709                 Index++;
03710 
03711             // Now make index point at the last character
03712             Index -= 1;
03713             if (Index > 0)
03714             {
03715                 if (UnicodeManager::IsDBCSLeadByte(StrPtr[Index-1]))
03716                     Index -= 1;
03717             }
03718 
03719             // Scan backwards, skipping all digits that we find
03720             INT32 EndIndex = Index;
03721             while (Index > 0)
03722             {
03723                 if (!StringBase::IsNumeric(StrPtr[Index]))
03724                     break;
03725 
03726                 Index -= 1;
03727                 if (Index > 0)
03728                 {
03729                     if (UnicodeManager::IsDBCSLeadByte(StrPtr[Index-1]))
03730                         Index -= 1;
03731                 }
03732             }
03733 
03734             // Now, if we found digits, scan back over this char if it is a space
03735             if (Index > 0 && Index < EndIndex && StrPtr[Index] == (TCHAR)' ')
03736             {
03737                 // Rightoh. This looks like an auto-generated unique-name, so does the text
03738                 // without the unique-ness number match our name?
03739                 String_64 ToCheck;
03740                 pItem->GetName(TRUE)->Left(&ToCheck, Index);
03741 
03742                 if (SourceName.CompareTo(ToCheck) == 0)
03743                     return(pItem);                  // Yep - the names match
03744             }
03745         }
03746 
03747         // Try the next colour
03748         pItem = (IndexedColour *) pIndexedColours->GetNext(pItem);
03749     }
03750 
03751     // No match was found for this colour
03752     return(NULL);
03753 }
03754 
03755 
03756 
03757 /********************************************************************************************
03758 
03759 >   virtual BOOL ColourListComponent::StartComponentCopy();
03760 
03761     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03762     Created:    10/9/94
03763     Inputs:     -
03764     Outputs:    -
03765     Returns:    TRUE if it succeeded. FALSE if the copy must be aborted
03766     Purpose:    This function gets called to prepare for a copy of indexed colours into
03767                 the document. It sets up the various arrays and other thangs which the
03768                 colour copy will need.
03769     Errors:     ENSURE failure if called when a component copy is already under way.
03770                 Errors will be reported if memory is unavailable
03771     SeeAlso:    ColourListComponent::EndComponentCopy;
03772                 ColourListComponent::AbortComponentCopy;
03773                 ColourListComponent::CopyColourAcross
03774 
03775 ********************************************************************************************/
03776 
03777 BOOL ColourListComponent::StartComponentCopy()
03778 {
03779     // Make sure the fn has not been called before
03780     if (SourceColours != NULL || DestColours != NULL)
03781     {
03782         ERROR3("StartComponentCopy already called");
03783         return(TRUE);
03784     }
03785 
03786     ColourTableSize = 64;           // Start off with 64-entry table. This may grow if
03787                                     // we find we have a lot of colours to copy over
03788 
03789     SourceColours = (IndexedColour **) CCMalloc(ColourTableSize * sizeof(IndexedColour *));
03790     if (SourceColours == NULL)
03791     {
03792         InformError();              // Out of memory - inform the user
03793         return(FALSE);
03794     }
03795 
03796     DestColours = (IndexedColour **) CCMalloc((ColourTableSize+1) * sizeof(IndexedColour *));
03797     if (DestColours == NULL)
03798     {
03799         InformError();              // Out of memory - inform the user
03800 
03801         CCFree(SourceColours);      // And release our other memory - we can't use it now
03802         SourceColours = NULL;
03803         return(FALSE);
03804     }
03805 
03806     MergeColours = (BOOL *) CCMalloc(ColourTableSize * sizeof(BOOL));
03807     if (MergeColours == NULL)
03808     {
03809         InformError();              // Out of memory - inform the user
03810 
03811         CCFree(SourceColours);      // And release our other memory - we can't use it now
03812         CCFree(DestColours);
03813         SourceColours = DestColours = NULL;
03814         return(FALSE);
03815     }
03816 
03817     // Initialise the arrays
03818     for (INT32 i = 0; i < ColourTableSize; i++)
03819     {
03820         SourceColours[i] = DestColours[i] = NULL;
03821         MergeColours[i]  = FALSE;
03822     }
03823 
03824     DestColours[ColourTableSize] = NULL;    // And add a NULL terminator to dest. list
03825 
03826     return(TRUE);
03827 }
03828 
03829 
03830 
03831 /********************************************************************************************
03832 
03833 >   virtual BOOL ColourListComponent::EndComponentCopy()
03834 
03835     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03836     Created:    10/9/94
03837 
03838     Returns:    TRUE if it succeeded
03839     Purpose:    Will commit all changes made by doing the component copy, returning TRUE.
03840                 Any new colours will be inserted as instructed by the InsertBefore parameter.
03841                 If some colours will not be insterted because they were merged, then a report
03842                 to this effect can be given if desired.
03843 
03844     Notes:      May be called multiple times - subsequent calls will be ignored
03845 
03846                 Overrides the base class method. Calls an internal variant on this method.
03847 
03848     SeeAlso:    ColourListComponent::StartComponentCopy;
03849                 ColourListComponent::AbortComponentCopy;
03850                 ColourListComponent::CopyColourAcross
03851 
03852 ********************************************************************************************/
03853 
03854 BOOL ColourListComponent::EndComponentCopy()
03855 {
03856     return(ColourListComponent::EndComponentCopy(NULL, FALSE));
03857 }
03858 
03859 
03860 
03861 /********************************************************************************************
03862 
03863 >   virtual BOOL ColourListComponent::EndComponentCopy(IndexedColour *InsertBefore,
03864                                                         BOOL Report);
03865 
03866     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03867     Created:    10/9/94
03868     Inputs:     InsertBefore - NULL to insert at the end of the colour list, else a pointer
03869                 the the IndexedColour before which you wish to insert the colours.
03870 
03871                 Report - FALSE to do it quietly, TRUE if you'd like a report given if any colours
03872                 were merged (used by the colour gallery when copying colours, as merged colours
03873                 will fail to appear in the chunk of copied colours, which can confuse the user)
03874 
03875     Returns:    TRUE if it succeeded
03876     Purpose:    Will commit all changes made by doing the component copy, returning TRUE.
03877                 Any new colours will be inserted as instructed by the InsertBefore parameter.
03878                 If some colours will not be insterted because they were merged, then a report
03879                 to this effect can be given if desired.
03880 
03881     Notes:      May be called multiple times - subsequent calls will be ignored
03882 
03883                 WARNING: This is NOT an override of the base class method. Be careful
03884 
03885     SeeAlso:    ColourListComponent::StartComponentCopy;
03886                 ColourListComponent::AbortComponentCopy;
03887                 ColourListComponent::CopyColourAcross
03888 
03889 ********************************************************************************************/
03890 
03891 BOOL ColourListComponent::EndComponentCopy(IndexedColour *InsertBefore, BOOL Report)
03892 {
03893     BOOL NeedToReport = FALSE;
03894 
03895     if (SourceColours != NULL)  // Free the source mapping array
03896     {
03897         CCFree(SourceColours);
03898         SourceColours = NULL;
03899     }
03900 
03901     if (DestColours != NULL)
03902     {
03903         // Add the colours in the 'Destination' array to the ColourList for the dest. doc.
03904         // We only add those colours which have not been merged with existing colours in the
03905         // destination list. The AddItem() call ensures their names are unique in this doc.
03906         INT32               i;
03907         for ( i = 0; i < ColourTableSize; i++)
03908         {
03909             if (DestColours[i] != NULL && !MergeColours[i])
03910             {
03911                 if (InsertBefore == NULL || !DestColours[i]->IsNamed())
03912                     pIndexedColours->AddItem(DestColours[i]);
03913                 else
03914                     pIndexedColours->InsertBefore(InsertBefore, DestColours[i]);
03915             }
03916         }
03917 
03918         // Now, remove all merged colours from the list of colours to be 'unhidden' for undo
03919         // NOTE that DestColours is guaranteed to be NULL terminated
03920 
03921         // We delete each merged colour from the list by copying the first valid list item
03922         // over the top of the merged item; we keep track of the valid list start with
03923         // 'ListStart'. Once finished, we pass any remainder of the array to UnHideColours
03924         INT32 ListStart = 0;
03925         for (i = 0; i < ColourTableSize; i++)
03926         {
03927             if (DestColours[i] == NULL)         // Stop at NULL terminator
03928                 break;
03929 
03930             if (MergeColours[i] || !DestColours[i]->IsNamed())
03931             {
03932                 // A merged or unnamed colour - copy list item '0' over it, so that we do not
03933                 // try to do any undo record for it.
03934                 DestColours[i] = DestColours[ListStart];
03935                 DestColours[ListStart] = NULL;
03936                 ListStart++;
03937 
03938                 NeedToReport = TRUE;
03939             }
03940         }
03941 
03942         if (DestColours[ListStart] != NULL)     // If there are non-merged named colours, create undo
03943             ColourManager::UnHideColours(pIndexedColours, &DestColours[ListStart]);
03944 
03945         // Lose our workspace array of pointers to these colours
03946         CCFree(DestColours);
03947         DestColours = NULL;
03948     }
03949 
03950     if (MergeColours != NULL)   // Free the 'merged'-flag array
03951     {
03952         CCFree(MergeColours);
03953         MergeColours = NULL;
03954     }
03955 
03956     // If the caller wants us to, report (if necessary) that some of the colours
03957     // were not copied, as they were already present in the dest. doc
03958     if (Report && NeedToReport)
03959         InformMessage(_R(IDS_COLOURSMERGED), _R(IDS_OK));
03960 
03961     return(TRUE);
03962 }
03963 
03964 
03965 
03966 /********************************************************************************************
03967 
03968 >   virtual void ColourListComponent::AbortComponentCopy();
03969 
03970     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03971     Created:    10/9/94
03972     Inputs:     -
03973     Outputs:    -
03974     Returns:    -
03975     Purpose:    Will abort all changes made for component copies.
03976                 This means that things such as the colours referenced by the nodes
03977                 you have just copied do not exist, so you must clean up to the state
03978                 the document was in before you strated copying.
03979     Errors:     -
03980     Notes:      May be called even if StartComponentCopy has not been called.
03981                 May be called multiple times
03982 
03983     SeeAlso:    ColourListComponent::EndComponentCopy;
03984                 ColourListComponent::AbortComponentCopy;
03985                 ColourListComponent::CopyColourAcross
03986 
03987 ********************************************************************************************/
03988 
03989 void ColourListComponent::AbortComponentCopy()
03990 {
03991     // Clean up by deleting all the new indexedColours we created. We hope that by the
03992     // time we do this, all DocColours referencing these colours will have been vaped.
03993     if (DestColours != NULL)
03994     {
03995         for (INT32 i = 0; i < ColourTableSize; i++)
03996         {
03997             if (DestColours[i] != NULL && !MergeColours[i])
03998             {
03999                 delete DestColours[i];
04000                 DestColours[i] = NULL;
04001             }
04002         }
04003     }
04004 
04005     // And release our working arrays
04006     if (SourceColours != NULL)
04007     {
04008         CCFree(SourceColours);
04009         SourceColours = NULL;
04010     }
04011 
04012     if (DestColours != NULL)
04013     {
04014         CCFree(DestColours);
04015         DestColours = NULL;
04016     }
04017 
04018     if (MergeColours != NULL)
04019     {
04020         CCFree(MergeColours);
04021         MergeColours = NULL;
04022     }
04023 }
04024 
04025 
04026 
04027 /********************************************************************************************
04028 
04029 >   INT32 ColourListComponent::ExtendTables(void)
04030 
04031     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
04032     Created:    28/11/94 (Separated from CopyColourAcross)
04033     Inputs:     -
04034     Outputs:    (The mapping arrays may have been moved by realloc)
04035     Returns:    -1 if it fails (it will have already reported the error
04036                 else the index of the first free entry in the mapping tables
04037 
04038     Purpose:    Called by Component Copy routines to extend the size of the copy mapping
04039                 tables (SourceColours[], DestColours[], and MergeColours[]). This returns
04040                 the index of the first free entry in the new tables, or -1 if it fails.
04041 
04042     Errors:     Memory errors are reported immediately
04043 
04044     SeeAlso:    ColourListComponent::StartComponentCopy;
04045                 ColourListComponent::AbortComponentCopy;
04046                 ColourListComponent::EndComponentCopy
04047 
04048 ********************************************************************************************/
04049 
04050 INT32 ColourListComponent::ExtendTables(void)
04051 {
04052     INT32 i = ColourTableSize;  // Set the index to the first new array entry
04053 
04054     ColourTableSize += 64;      // Increase the size of our mapping arrays
04055     IndexedColour **TempArray;
04056 
04057     // Realloc the Source array, with error handling
04058     TempArray = (IndexedColour **) CCRealloc(SourceColours,
04059                                             ColourTableSize * sizeof(IndexedColour *));
04060     if (TempArray == NULL)
04061     {
04062         InformError();
04063         return(-1);
04064     }
04065 
04066     SourceColours = TempArray;  // Realloc succeeded - set the new SourceColour ptr
04067     
04068     // Realloc the Dest array, with error handling
04069     TempArray = (IndexedColour **) CCRealloc(DestColours,
04070                                             (ColourTableSize+1) * sizeof(IndexedColour *));
04071     if (TempArray == NULL)
04072     {
04073         InformError();
04074         return(-1);
04075     }
04076 
04077     DestColours = TempArray;    // Realloc succeeded - set the new DestColour ptr
04078 
04079     // Realloc the 'Merged'-flag array, with error handling
04080     BOOL *TempBoolArray = (BOOL *) CCRealloc(MergeColours,
04081                                             ColourTableSize * sizeof(BOOL));
04082     if (TempBoolArray == NULL)
04083     {
04084         InformError();
04085         return(-1);
04086     }
04087 
04088     MergeColours = TempBoolArray;   // Realloc succeeded - set the new MergeColour ptr
04089 
04090     // Initialise the new portions of the arrays
04091     for (INT32 j = i; j < ColourTableSize; j++)
04092     {
04093         SourceColours[j] = DestColours[j] = NULL;
04094         MergeColours[j] = FALSE;
04095     }
04096 
04097     DestColours[ColourTableSize] = NULL;    // And add a NULL terminator to dest. list
04098 
04099     return(i);
04100 }
04101 
04102 
04103 
04104 /********************************************************************************************
04105 
04106 >   IndexedColour *ColourListComponent::MapColour(IndexedColour *SourceColour,
04107                                                     BOOL *AlreadyThere = NULL,
04108                                                     BOOL SourceIsUnique = FALSE)
04109 
04110     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
04111     Created:    29/10/94
04112 
04113     Inputs:     SourceColour - pointer to an IndexedColour to map
04114 
04115                 (AlreadyThere is an output only)
04116 
04117                 SourceIsUnique - FALSE (the default) if you're copying existing document
04118                                  colours around, and therefore could attempt to copy the
04119                                  same colour multiple times.
04120 
04121                                  TRUE if you can guarantee that this colour will only be
04122                                  copied once. This is used only for copying library colours
04123                                  into a document in the colour gallery (where it uses a temporary
04124                                  IndexedColour, which causes problems when several different
04125                                  colours accidentally map to the same temporary memory allocation,
04126                                  thus causing rampant incorrect colour merging to occur).
04127 
04128     Outputs:    AlreadyThere - (if non-NULL) is filled in with TRUE if the colour was merged
04129                 or FALSE if a new colour had to be created.
04130 
04131     Returns:    NULL if it fails (the error will have been reported)
04132                 Otherwise, a pointer to the IndexedColour resulting from the mapping
04133 
04134     Purpose:    Used internally in ColourListComponent Component Copy routines.
04135                 This method keeps track of mappings between source document and destination
04136                 document colours. It determines the mapping from source to dest, and returns
04137                 the appropriate destination-docuemnt IndexedColour. This may be a new colour
04138                 which will later be added to the destination document or a colour already in
04139                 the dest. doc (merged colour). Once an IndexedColour is mapped, future calls
04140                 to this method will be very efficient (a simple table search and lookup of
04141                 the previous mapping)
04142 
04143     Notes:      This method is recursive. This allows it to cope with a chain of parent
04144                 tint/link colours which may or may not be mapped already. Special care
04145                 is taken to ensure that only destination-document references are left
04146                 at the end of the copy operation (as obviously, references to the source
04147                 doc are highly dangerous, and usually fatal)
04148 
04149     SeeAlso:    ColourListComponent::StartComponentCopy;
04150                 ColourListComponent::AbortComponentCopy;
04151                 ColourListComponent::EndComponentCopy
04152 
04153 ********************************************************************************************/
04154 
04155 IndexedColour *ColourListComponent::MapColour(IndexedColour *SourceColour,
04156                                                 BOOL *AlreadyThere, BOOL SourceIsUnique)
04157 {
04158     if (AlreadyThere != NULL)   // Set a safe return value
04159         *AlreadyThere = FALSE;
04160 
04161     // First, check if the colour is already mapped; if so, just return its mapping
04162     // If SourceIsUnique, then we know no two source colours will never be the same,
04163     // and to fix a temporary-colour-reuse (2 colours in the same memory location)
04164     // problem in colour gallery library colour copies, we don't cache the mappings.
04165     // This is fine, because those copies only copy each colour once, so there is
04166     // no need to cache mappings for them anyway.
04167     if (!SourceIsUnique)
04168     {
04169         INT32 i = 0;
04170         while (i < ColourTableSize && SourceColours[i] != NULL && SourceColours[i] != SourceColour)
04171             i++;
04172 
04173         if (i < ColourTableSize && SourceColours[i] == SourceColour)
04174         {
04175             // If it was merged, return a value indicating that case
04176             if (AlreadyThere != NULL && MergeColours[i])
04177                 *AlreadyThere = TRUE;
04178 
04179             return(DestColours[i]);
04180         }
04181     }
04182 
04183     // Next, copy the colour being mapped
04184     IndexedColour *DestColour = new IndexedColour(*SourceColour);
04185     if (DestColour == NULL)
04186         return(NULL);
04187 
04188 
04189     // Now ensure our parent/ancestors are mapped, ...
04190     IndexedColour *SourceParent = SourceColour->FindLinkedParent();
04191     IndexedColour *DestParent = NULL;
04192     if (SourceParent != NULL)
04193     {
04194         DestParent = MapColour(SourceParent);
04195         if (DestParent == NULL)
04196         {
04197             delete DestColour;
04198             return(NULL);
04199         }
04200     }
04201 
04202     // ... and set the copied colour's parent to the mapped (dest doc) parent, rather than
04203     // the source doc version of the parent.
04204     // Note that if this is not a tint/linked colour, this has the side effect of ensuring
04205     // that Parent is NULL, rather than referencing a parent in a different document
04206     DestColour->SetLinkedParent(DestParent, DestColour->GetType());
04207     
04208 
04209     // Finally, map ourselves...
04210     // Find a blank entry in the mapping tables
04211     INT32 i = 0;
04212     while (i < ColourTableSize && SourceColours[i] != NULL)
04213         i++;
04214 
04215     if (i >= ColourTableSize)   // If no free entries, extend them and get first free entry
04216         i = ExtendTables();
04217 
04218     if (i < 0)                  // We failed - no memory for tables
04219     {
04220         delete DestColour;
04221         return(NULL);
04222     }
04223 
04224     // Check if there is already a matching colour in the dest. document.
04225     // If there is one, then chuck away DestColour, and use the matching colour instead
04226     IndexedColour *MatchColour = ExactMatchExists(DestColour);
04227     if (MatchColour != NULL)    
04228     {
04229         delete DestColour;
04230         DestColour = MatchColour;
04231 
04232         if (AlreadyThere != NULL)   // And return info to indicate that the colour is merged
04233             *AlreadyThere = TRUE;
04234     }
04235 
04236     // And finally, write the new entry into the mapping tables
04237     // (but only if we need to cache the mappings - NOTE that we need to store a
04238     // mapping (at least to the extent of having a destination part of the mapping)
04239     // or the new colours won't be added in EndComponentCopy. Unfortunately this
04240     // means we need a source mapping that isn't NULL or it all falls apart.
04241     if (SourceIsUnique)
04242         SourceColours[i] = (IndexedColour *) 1;     // Yeek! Have to stop this being null
04243     else
04244         SourceColours[i] = SourceColour;
04245 
04246     DestColours[i]   = DestColour;
04247     MergeColours[i]  = (MatchColour != NULL);
04248 
04249     return(DestColour);     // And return the result of the mapping operation
04250 
04251     return NULL;
04252 }
04253 
04254 
04255 
04256 /********************************************************************************************
04257 
04258 >   ColCompCopyResult CopyColourAcross(DocColour* pDocColour, BOOL SourceIsUnique = FALSE);
04259 
04260     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
04261     Created:    10/9/94
04262 
04263     Inputs:     pDocColour - The colour which resulted from copying across from one document
04264                 to our document.
04265 
04266                 SourceIsUnique - FALSE (the default) if you're copying existing document
04267                                  colours around, and therefore could attempt to copy the
04268                                  same colour multiple times.
04269 
04270                                  TRUE if you can guarantee that this colour will only be
04271                                  copied once. This is used only for copying library colours
04272                                  into a document in the colour gallery (where it uses a temporary
04273                                  IndexedColour, which causes problems when several different
04274                                  colours accidentally map to the same temporary memory allocation,
04275                                  thus causing rampant incorrect colour merging to occur).
04276                                  ** ONLY USE THIS IF YOU REALLY REALLY BELIEVE YOU MUST - **
04277                                  ** IT SHOULD NOT BE NECESSARY UNDER NORMAL CIRCUMSTANCES **
04278 
04279     Returns:    CCCOPY_FAILED = 0/FALSE - if it failed, in which case the error has been reported
04280 
04281                 CCCOPY_NEWCOLOUR        - if it succeeded by creating a new colour
04282 
04283                 CCCOPY_MERGEDCOLOUR     - if it succeeded by merging (using an existing colour)
04284 
04285     Purpose:    If the DocColour references an IndexedColour then a copy of that IxColour is
04286                 made and remembered. The DocColour is then changed to reference the new
04287                 indexed colour. On calling EndComponentCopy, these new IndexedColours will
04288                 be added to the document. If a failure occurs at any stage, you must
04289                 *immediately* undo the entire copy operation, deleting all the nodes
04290                 referencing the new colours we've created, before calling AbortComponentCopy
04291 
04292                 Chains of linked/tint IndexedColours are also handled properly.
04293 
04294     Notes:      If this function returns FALSE, you MUST clean up and then call 
04295                 AbortComponentCopy to clean up.
04296 
04297     Errors:     Memory errors are reported immediately
04298                 If StartComponentCopy has not been called, or an internal consistency failure
04299                 occurs (our working array pointer(s) are NULL), an ERROR2 will be reported.
04300 
04301     SeeAlso:    ColourListComponent::StartComponentCopy;
04302                 ColourListComponent::AbortComponentCopy;
04303                 ColourListComponent::EndComponentCopy
04304 
04305 ********************************************************************************************/
04306 
04307 ColCompCopyResult ColourListComponent::CopyColourAcross(DocColour* pDocColour, BOOL SourceIsUnique)
04308 {
04309     IndexedColour *SourceColour = pDocColour->FindParentIndexedColour(); 
04310 
04311     if (SourceColour == NULL)   // Doesn't reference an IndexedColour, so return success
04312         return(CCCOPY_MERGEDCOLOUR);
04313 
04314     if (SourceColours == NULL || DestColours == NULL || MergeColours == NULL)
04315     {
04316         ERROR2RAW("ColourListComponent::CopyColourAcross called without a prior StartComponentCopy");
04317         InformError();
04318         return(CCCOPY_FAILED);
04319     }
04320 
04321     BOOL WasMerged = FALSE;
04322     IndexedColour *NewColour = MapColour(SourceColour, &WasMerged, SourceIsUnique);
04323     if (NewColour == NULL)      // An error (no memory) occurred - abort component copy
04324         return(CCCOPY_FAILED);
04325 
04326     // Fix the colour to reference the destination copy of the indexed colour
04327     pDocColour->MakeRefToIndexedColour(NewColour);
04328     return((WasMerged) ? CCCOPY_MERGEDCOLOUR : CCCOPY_NEWCOLOUR);
04329 
04330     return CCCOPY_FAILED;
04331 }
04332 
04333 
04334 /********************************************************************************************
04335 
04336 >   IndexedColour* ColourListComponent::GetIndexedParentOfColour(DocColour Colour)
04337 
04338     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
04339     Created:    17/5/2000
04340     Inputs:     Colour - the doccolour that was originally created from an indexed colour
04341     Outputs:    -
04342     Returns:    the indexed colour that originally created Colour, if there is one, else NULL
04343     Purpose:    It is possible for us to create doccolours from indexed colours and then convert
04344                 them so that they are standalone.  This method goes through all the indexed
04345                 colours to try and find out which indexed colour (if any) originally created the input
04346 
04347 ********************************************************************************************/
04348 
04349 IndexedColour* ColourListComponent::GetIndexedParentOfColour(DocColour Colour)
04350 {
04351     ColourList* pList = GetColourList();
04352     if (pList == NULL)
04353         return NULL;
04354 
04355     ColourGeneric ColDef;
04356     ColourContext *cc = ColourManager::GetColourContext(Colour.GetColourModel());
04357     ERROR2IF(cc == NULL, NULL,  "Can't find colour context?!");
04358     DocColour ConvertedDocCol;
04359     
04360     IndexedColour* pItem = (IndexedColour*)pList->GetHead();
04361 
04362     // what we have to do is get each indexed colour as a standalone definition then
04363     // ask it to make a doccolour. If this is the same as our input then we have our match
04364     while (pItem != NULL)
04365     {
04366         // Get the IndexedColour definition as a standalone colour definition
04367         cc->ConvertColour(pItem, &ColDef);
04368 
04369         // Make the DocColour into a simple standalone "lookalike" of the parent colour
04370         ConvertedDocCol = DocColour(Colour.GetColourModel(), &ColDef);
04371         
04372         // now test to see if its the same, if so we've got what we want
04373         if (ConvertedDocCol == Colour)
04374             break;
04375 
04376         pItem = (IndexedColour*)pList->GetNext(pItem);
04377         
04378     
04379     }
04380     return pItem;
04381 }

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