colcontx.cpp

Go to the documentation of this file.
00001 // $Id: colcontx.cpp 1402 2006-07-04 09:26:38Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 // colcontx.cpp - ColourContext and derived classes
00099 
00100 /*
00101 */
00102 
00103 
00104 #include "camtypes.h"
00105 
00106 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00107 #include "colcontx.h"
00108 #include "colormgr.h"
00109 #include "colourix.h"
00110 #include "colplate.h"
00111 //#include "doccolor.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00112 //#include "ensure.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00113 //#include "jason.h"
00114 //#include "view.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00115 #include "scunit.h"
00116 
00117 #if defined(EXCLUDE_FROM_RALPH) || defined(EXCLUDE_FROM_XARALX)
00118 #undef  NO_XARACMS
00119 #define NO_XARACMS
00120 #endif
00121 
00122 #ifndef NO_XARACMS
00123 #include "xaracms.h"
00124 #endif
00125 
00126 CC_IMPLEMENT_MEMDUMP(ColourContext,         ListItem)
00127 CC_IMPLEMENT_MEMDUMP(ColourContextRGBT,     ColourContext)
00128 CC_IMPLEMENT_MEMDUMP(ColourContextWebRGBT,  ColourContextRGBT)
00129 CC_IMPLEMENT_MEMDUMP(ColourContextCMYK,     ColourContext)
00130 CC_IMPLEMENT_MEMDUMP(ColourContextHSVT,     ColourContext)
00131 CC_IMPLEMENT_MEMDUMP(ColourContextGreyT,    ColourContext)
00132 
00133 #define new CAM_DEBUG_NEW
00134 
00135 /*  NOTE WELL ALL YE WHO ENTER HERE
00136  *
00137  *  If you are implementing a new context class, have a look at the implementation
00138  *  of RGBT, which is a simple base model. Note that you may also find it useful
00139  *  to look at CMYK, as it overrides the ConvertColourInternal to do special stuff.
00140  */
00141 
00142 
00143 
00144 /*  DefaultColourContexts
00145  *
00146  *  This is a 'global' array of default colour contexts for each of the
00147  *  possible 16 colour models Camelot can support. When defining/converting 
00148  *  colours, a default colour context is implicitly specified, if no colour
00149  *  context is given.
00150  *  Access is via the static function ColourContext::GetDefault()
00151  */
00152 
00153 ColourContextArray ColourContext::GlobalDefaultContext = 
00154 {
00155     { NULL, NULL, NULL, NULL,
00156     NULL, NULL, NULL, NULL,
00157     NULL, NULL, NULL, NULL,
00158     NULL, NULL, NULL, NULL }
00159 };
00160 
00161 
00162 
00163 /* NextColourContextHandle 
00164  *
00165  * This variable keeps track of the current handle - each colour context must have a 
00166  * unique handle - this is used in colour caches to identify the context in which
00167  * they are currently cached, so that they know when the cache is invalid.
00168  */
00169 
00170 ColourContextHandle ColourContext::NextColourContextHandle = 1;
00171 
00172 
00173 
00174 
00175 /********************************************************************************************
00176 
00177 >   void ColourContext::ColourContext(View *Scope)
00178 
00179     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00180     Created:    31/03/94
00181     Inputs:     Scope - The view within which this context is to be used, or NULL
00182                 for a global (non-view-specific) context
00183     Outputs:    -
00184     Returns:    -
00185     Purpose:    Constructor for a Colour context. This is shared code used by
00186                 all derived ColourContextXXXX classes. You cannot create
00187                 vanilla ColourContext objects (virtual functions abound)
00188 
00189     Notes:      The usage count for a colour context defaults to 0
00190                 ("not in use"). When using colour contexts, you should always
00191                 register them with the global ColContextList object (see
00192                 ColourContextList::AddContext for details)
00193 
00194                 When created, relevant conversion parameters (gamma correction
00195                 etc) are passed in to the constructor.The context stores these
00196                 parameters so it can quickly compare itself to another context,
00197                 but it may defer creation of tables and other essential stuff 
00198                 until the Init() function is called (when it is added to the
00199                 list of available colour contexts). Nobody but the context list
00200                 can call the Init() function.
00201 
00202                 The passed-in Scope may be NULL, in which case global scope is
00203                 used. However, if you're using this within the scope of any
00204                 view, note that you must set up ScopeView properly or colour
00205                 separated output of some colour models will be incorrect.
00206 
00207     Errors:     -
00208     SeeAlso:    ColourContextRGBT::ColourContextRGBT;
00209                 ColourContextCMYK::ColourContextCMYK;
00210                 ColourContextHSVT::ColourContextHSVT;
00211                 ColourContextList::AddContext
00212 
00213 ********************************************************************************************/
00214 
00215 ColourContext::ColourContext(View *Scope)
00216 {
00217     MyHandle = NextColourContextHandle++;
00218 
00219     ScopeView = Scope;
00220 
00221     UsageCount = 0;
00222 
00223     ColPlate = NULL;
00224 
00225 PORTNOTE("other","Removed HCMTRANSFORM usage")
00226 #ifndef EXCLUDE_FROM_XARALX
00227     CMSTransform = NULL;
00228 #endif
00229     // ColourModel and Model-specific data must be dealt with in the 
00230     // constructor/Init() for the derived ColourContextXXXX class
00231 }
00232 
00233 
00234 
00235 /********************************************************************************************
00236 
00237 >   void ColourContext::~ColourContext(void)
00238 
00239     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00240     Created:    31/03/94
00241 
00242     Purpose:    Colour context destructor
00243 
00244     Notes:      This destroys any attached ColourPlate descriptor
00245 
00246     SeeAlso:    ColourContextList::AddContext
00247 
00248 ********************************************************************************************/
00249 
00250 ColourContext::~ColourContext()
00251 {
00252     ENSURE(UsageCount == 0, "ColourContext deleted while still in use!");
00253 
00254     if (ColPlate != NULL)
00255     {
00256         delete ColPlate;
00257         ColPlate = NULL;
00258     }
00259 
00260 #ifndef NO_XARACMS
00261     if (CMSTransform != NULL)
00262     {
00263         if (GetApplication()->GetCMSManager() != NULL)
00264             GetApplication()->GetCMSManager()->DestroyTransform(CMSTransform);
00265         CMSTransform = NULL;
00266     }
00267 #endif
00268 }
00269 
00270 
00271 
00272 /********************************************************************************************
00273 
00274 >   BOOL ColourContext::Init(void)
00275 
00276     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00277     Created:    11/04/94
00278     Inputs:     -
00279     Outputs:    -
00280     Returns:    TRUE if it succeeds
00281                 FALSE if it fails (and it'll set an error description)
00282     Purpose:    Colour context initialiser. This is called by the ColourContextList
00283                 when it wishes to add a context to the list, and makes the context
00284                 ready for use. This allows the list to compare contexts, and only
00285                 initialise a given context when it knows the initialisation is
00286                 absolutely necessary (e.g. allocating a large chunk of memory or 
00287                 calculating a complex table is avoided until we are sure there are
00288                 no equivalent contexts already available)
00289                 This function is overridden by colour contexts which actually need to
00290                 do some initialisation other than just storing a few values away.
00291     Errors:     -
00292     SeeAlso:    ColourContextList::AddContext
00293 
00294 ********************************************************************************************/
00295 
00296 BOOL ColourContext::Init(void)
00297 {
00298     ENSURE(UsageCount == 0, "ColourContext initialised when in use?!?!");
00299 
00300     IncrementUsage();   // We are now in use. UsageCount is now 1
00301     return(TRUE);       // Initialisation succeeded
00302 }
00303 
00304 
00305 
00306 /********************************************************************************************
00307 
00308 >   void ColourContext::DecrementUsage(void)
00309 
00310     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00311     Created:    31/03/94
00312     Inputs:     -
00313     Outputs:    -
00314     Returns:    TRUE if the object is still in use
00315     Purpose:    Decrements usage-count for a colour context. This count allows us to
00316                 determine when we can delete unused contexts.
00317 
00318     Notes:      The usage count for a colour context defaults to 0
00319                 ("not in use"). When using colour contexts, you should always
00320                 register them with the global ColContextList object (see
00321                 ColourContextList::AddContext for details)
00322 
00323     Errors:     ENSURE fails if the usage count goes negative, indicating the context
00324                 is being 'released' more times than it is 'claimed'.
00325     SeeAlso:    ColourContext::IncrementUsage; ColourContextList::AddContext
00326 
00327 ********************************************************************************************/
00328 
00329 BOOL ColourContext::DecrementUsage(void)
00330 {
00331     ENSURE(UsageCount > 0, "ColourContext::DecrementUsage - Usage count is negative!");
00332     return((--UsageCount) != 0);
00333 }
00334 
00335 
00336 
00337 /********************************************************************************************
00338 
00339 >   virtual void ColourContext::PackColour(ColourGeneric *Source, ColourPacked *Result)
00340 
00341     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00342     Created:    31/03/94
00343     Inputs:     Source - A ColourGeneric structure defining the colour in the model
00344                 pertaining to this colour context.
00345                 Result - A Packed colour structure in the same model, into which the result
00346                 is copied.
00347 
00348     Outputs:    -
00349     Returns:    -
00350     Purpose:    Converts 128-bit colour representation to 32-bit packed form
00351 
00352     Notes:      This function operates on the colour using a generic component pattern
00353                 Colours such as ColourHSVT do not conform to this pattern and thus must
00354                 be unpacked with derived methods (ColourContextHSVT::UnpackColour)
00355                 However, this function will work on any 4-component model which uses 8bits
00356                 and 32-bits respectively for all 4 components, and the same 8.24 fixedpoint
00357                 32-bit representation. 
00358 
00359     Scope:      Private (used internally by friend class DocColour)
00360     Errors:     -
00361     SeeAlso:    ColourContext::UnpackColour
00362 
00363 ********************************************************************************************/
00364 
00365 void ColourContext::PackColour(ColourGeneric *Source, ColourPacked *Result)
00366 {
00367     PColourGeneric *bob = (PColourGeneric *) Result;
00368 
00369     bob->Component1 = PackColour256(Source->Component1);
00370     bob->Component2 = PackColour256(Source->Component2);
00371     bob->Component3 = PackColour256(Source->Component3);
00372     bob->Component4 = PackColour256(Source->Component4);
00373 }
00374 
00375 
00376 
00377 
00378 /********************************************************************************************
00379 
00380 >   virtual void ColourContext::UnpackColour(ColourPacked *Source, ColourGeneric *Result)
00381 
00382     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00383     Created:    31/03/94
00384     Inputs:     Source - A Packed Colour structure defining the colour in the model
00385                 pertaining to this colour context.
00386                 Result - A ColourGeneric structure in the same model, into which the 
00387                 result is copied.
00388     Outputs:    -
00389     Returns:    -
00390     Purpose:    Converts 32-bit packed colour representation to 128-bit form
00391 
00392     Notes:      This function operates on the colour using a generic component pattern
00393                 Colours such as ColourHSVT do not conform to this pattern and thus must
00394                 be unpacked with derived methods (ColourContextHSVT::UnpackColour)
00395                 However, this function will work on any 4-component model which uses 8bits
00396                 and 32-bits respectively for all 4 components, and the same 8.24 fixedpoint
00397                 32-bit representation. 
00398 
00399     Scope:      Private (used internally by friend class DocColour)
00400     Errors:     -
00401     SeeAlso:    ColourContext::PackColour
00402 
00403 ********************************************************************************************/
00404 
00405 void ColourContext::UnpackColour(ColourPacked *Source, ColourGeneric *Result)
00406 {
00407     PColourGeneric *bob = (PColourGeneric *) Source;
00408 
00409     UnpackColour256(bob->Component1, &Result->Component1);
00410     UnpackColour256(bob->Component2, &Result->Component2);
00411     UnpackColour256(bob->Component3, &Result->Component3);
00412     UnpackColour256(bob->Component4, &Result->Component4);
00413 }
00414 
00415 
00416 
00417 /********************************************************************************************
00418 
00419 >   virtual BOOL ColourContext::IsDifferent(ColourContext *Other) const
00420 
00421     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00422     Created:    13/04/94
00423     Inputs:     Other - a colour context to compare ourselves to
00424     Outputs:    -
00425     Returns:    TRUE if the other colour context object is different from
00426                 ourself, or FALSE if it is an exactly equivalent context.
00427     Purpose:    Determine if two colour contexts are not exactly equivalent
00428     Errors:     -
00429     SeeAlso:    -
00430 
00431 ********************************************************************************************/
00432 
00433 
00434 BOOL ColourContext::IsDifferent(ColourContext *Other) const
00435 {
00436     if (Other == this)
00437         return(FALSE);                      // Different object? (Nope)
00438 
00439     if (Other->ScopeView != ScopeView)
00440         return(TRUE);                       // Different Scope Views?
00441 
00442     return(Other->ColModel != ColModel);    // Different Colour Model?
00443 }
00444 
00445 
00446 
00447 
00448 /********************************************************************************************
00449 
00450 >   virtual void ColourContext::ConvertColourBase(ColourContext *SourceContext,
00451                                             ColourGeneric *Source, ColourGeneric *Result
00452                                             IndexedColour *SourceIxCol = NULL)
00453 
00454     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00455     Created:    31/03/94
00456     Inputs:     SourceContext - The context in which the source is defined 
00457 
00458                 Source - A ColourGeneric to convert
00459 
00460                 Result - A ColourGeneric structure to recieve the resulting converted colour,
00461                 as defined in this ColourContext.
00462 
00463                 SourceIxCol - NULL, or a pointer to the IndexedColour we are converting.
00464                 This is used only for handling spot colour separations, to determine if
00465                 the colour is a given spot colour or tint thereof.
00466 
00467     Outputs:    Result - will be returned with the converted colour
00468 
00469     Purpose:    Converts a Colour into this colour context, from the default colour context
00470                 implied by the given colour model
00471                 Post-processing (as described by the attached ColourPlate object) will
00472                 be applied to generate colour separations (etc) as required.
00473 
00474                 The converted colour will be supplied from a cache where possible
00475 
00476     Notes:      It is up to the caller to update caches etc if necessary
00477                 This is used as a base on which ConvertColourInternal methods are built
00478 
00479                 ColourContextCMYK overrides this base class method to provide direct
00480                 passthrough of CMYK colours into a CMYK output context. (passthrough
00481                 otherwise only occurs if the source & destination contexts are the
00482                 same object)
00483 
00484     Scope:      private to colcontx.cpp
00485     Errors:     -
00486     SeeAlso:    ColourContext::ConvertColour
00487 
00488 ********************************************************************************************/
00489 
00490 void ColourContext::ConvertColourBase(ColourContext *SourceContext,
00491                                         ColourGeneric *Source, ColourGeneric *Result,
00492                                         IndexedColour *SourceIxCol)
00493 {
00494 #ifndef NO_XARACMS
00495     // Last minute bodge for Composite preview of CMYK colours in RGB space
00496     // This is done here cos it's much faster, and gets around pre/post filter problems
00497     // with CMYK colours which aren't IndexedColours (like intermediate blend/gradfill DocColours)
00498     if (ColPlate != NULL && ColPlate->GetType() == COLOURPLATE_COMPOSITE &&
00499         GetColourModel() == COLOURMODEL_RGBT &&
00500         SourceContext->GetColourModel() == COLOURMODEL_CMYK)
00501     {
00502         // If it's a CMYK colour, then it's already in printer gamut, so we only apply
00503         // the backward colour correction factor to it.
00504         // Note that this means we chuck away the normal colour conversion system!
00505         XaraCMS* lpCMSMan = GetApplication()->GetCMSManager();
00506         if (lpCMSMan != NULL)
00507         {
00508             ColourCMYK Def;
00509             memcpy(&Def, Source, sizeof(ColourGeneric));
00510 
00511             lpCMSMan->ConvertColourForPaperView(&Def, (ColourRGBT *) Result);
00512             return;
00513         }
00514     }
00515 #endif
00516 
00517     // Copy the source colour into a temporary variable
00518     ColourGeneric FilteredSource;
00519     memcpy(&FilteredSource, Source, sizeof(ColourGeneric));
00520 
00521     // Call the SourceContext to allow it to pre-filter the colour. This is used to
00522     // provide colour separations and other doody features when converting CMYK colours
00523     // - when converting non-CMYK colours, this is usually done in the OutputFilter (below)
00524     if (ColPlate != NULL && !ColPlate->IsDisabled())
00525         SourceContext->ApplyInputFilter(ColPlate, this, &FilteredSource, SourceIxCol);
00526 
00527     // -----
00528     // Call levels expected:
00529     //  1 inline ConvertColour checks if can satisfy from cache
00530     //  2 function ConvertColourInternal does any short cuts it can, such
00531     //    as CMYK->CMYK passthrough
00532     //  3 Call ConvertColourBase, which
00533     //      a) Checks if in same colour model, and implements passthrough, or
00534     //      b) Converts colour properly via CIET space
00535 
00536     if (SourceContext == this)
00537     {
00538         // The SourceContext and Destination context are identical, so we can
00539         // just copy the definition directly across.
00540         memcpy(Result, &FilteredSource, sizeof(ColourGeneric));
00541     }
00542     else
00543     {
00544         DColourCIET IntermediateResult;
00545 
00546         SourceContext->ConvertToCIET(&FilteredSource, &IntermediateResult);
00547         ConvertFromCIET(&IntermediateResult, Result);
00548     }
00549 
00550 
00551     // Call the DestinationContext (derived class of this) to apply any output filtering -
00552     // non-CMYK colour conversions will separate the colour (as appropriate) here
00553     if (ColPlate != NULL && !ColPlate->IsDisabled())
00554         ApplyOutputFilter(ColPlate, SourceContext, Result, SourceIxCol);
00555 }
00556 
00557 
00558 
00559 
00560 /********************************************************************************************
00561 
00562 >   void ColourContext::ConvertColourInternal(DocColour *Source, ColourGeneric *Result)
00563 
00564     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00565     Created:    31/03/94
00566     Inputs:     Source - A Colour to convert
00567                 Result - A ColourGeneric structure to recieve the resulting converted colour,
00568                 as defined in this ColourContext.
00569     Outputs:    -
00570     Returns:    -
00571     Purpose:    Converts a Colour into this colour context.
00572                 The converted colour will be supplied from a cache where possible
00573 
00574     Notes:      This is used internally. It is only called by the inlined conversion
00575                 functions if they fail to return a cached result
00576     Errors:     -
00577     SeeAlso:    ColourContext::ConvertColour
00578 
00579 ********************************************************************************************/
00580 
00581 void ColourContext::ConvertColourInternal(DocColour *Source, ColourGeneric *Result)
00582 {
00583     if (Source->Info.SourceColourModel == COLOURMODEL_INDEXED)
00584     {
00585         IndexedColour *SrcIndexed = Source->SourceColour.Indexed.Colour;
00586 
00587         // Convert the indexed colour to our context
00588         ConvertColour(SrcIndexed, Result);
00589 
00590         // If IndexedColour, we do NOT want the colour cached at the DocColour
00591         // level (else if the IxCol changes, we'd have to search for all related
00592         // DocCols to fix their caches... erg!)
00593         return;
00594     }
00595 
00596     // Unpack the 32-bit colour into a 128-bit structure, and then invoke the
00597     // shared internal conversion routine.
00598     ColourGeneric SourceDefn;
00599 
00600     // If this DocColour should not be separated (it's a UI colour), then disable
00601     // any active colour plate to stop it separating the output - we'll save and restore
00602     // its previous state around the call to ConvertColourBase
00603     BOOL WasDisabled = TRUE;
00604     if (ColPlate != NULL)
00605     {
00606         WasDisabled = ColPlate->IsDisabled();
00607         ColPlate->SetDisabled(!Source->IsSeparable());
00608     }
00609 
00610         // Check if we're doing a spot colour plate. We either get the colour's source colour,
00611         // or if it shouldn't appear on the plate, we get White.
00612         if (ColPlate != NULL && !ColPlate->IsDisabled() && ColPlate->GetType() == COLOURPLATE_SPOT)
00613         {
00614             // We're doing a SPOT colour plate, but this colour is a local DocColour, so
00615             // it cannot possibly be a tint on this plate, so we just return white.
00616             GetGlobalDefault(Source->GetColourModel())->GetWhite(&SourceDefn);
00617         }
00618         else
00619         {
00620             // Unpack the colour
00621             GetGlobalDefault(Source->GetColourModel())->UnpackColour(&Source->SourceColour, &SourceDefn);
00622         }
00623 
00624         // Assume that the source context is a global default. Generally, this should be true,
00625         // as all source colours should be defined in terms of logical colour models.
00626         ConvertColourBase(GetGlobalDefault(Source->GetColourModel()),
00627                             &SourceDefn, Result);
00628 
00629     // And restore the previous ColourPlate "disabled" state
00630     if (ColPlate != NULL)
00631         ColPlate->SetDisabled(WasDisabled);
00632 
00633     PackColour(Result, &Source->CachedColour);  // And update the cache
00634 
00635     // Update cache flags - I am the context in which the cache is defined
00636     Source->Info.OCContextHandle  = MyHandle;
00637     Source->Info.CacheColourModel = ColModel;
00638 }
00639 
00640 
00641 
00642 /********************************************************************************************
00643 
00644 >   void ColourContext::ConvertColourInternal(DocColour *Source, ColourPacked *Result)
00645 
00646     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00647     Created:    14/04/94
00648     Inputs:     Source - A Colour to convert
00649                 Result - A PColourGeneric structure to recieve the resulting converted colour,
00650                 as defined in this ColourContext.
00651     Outputs:    -
00652     Returns:    -
00653     Purpose:    Converts a Colour into this colour context.
00654                 The converted colour will be supplied from a cache where possible (this check
00655                 is made by the caller function ConvertColour)
00656     Scope:      PRIVATE - for use only by 'friend' rendering classes:
00657                     OSRenderRegion, GRenderRegion
00658     Errors:     -
00659     SeeAlso:    ColourContext::ConvertColour
00660 
00661 ********************************************************************************************/
00662 
00663 void ColourContext::ConvertColourInternal(DocColour *Source, ColourPacked *Result)
00664 {
00665     ColourGeneric NewResult;
00666     ConvertColourInternal(Source, &NewResult);  // Convert
00667 
00668     PackColour(&NewResult, Result);             // Pack the colour into Result...
00669 
00670     if (Source->Info.SourceColourModel != COLOURMODEL_INDEXED)
00671     {
00672         // And (if not an IndexedColour) update the cache
00673         Source->Info.OCContextHandle  = MyHandle;
00674         Source->Info.CacheColourModel = ColModel;
00675         memcpy(&Source->CachedColour, Result, sizeof(ColourPacked));
00676     }
00677 }
00678 
00679 
00680 
00681 /********************************************************************************************
00682 
00683 >   void ColourContext::ConvertColour(IndexedColour *Source, ColourGeneric *Result)
00684 
00685     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00686     Created:    31/03/94
00687     Inputs:     Source - An IndexedColour to convert
00688                 Result - A ColourGeneric structure to recieve the resulting converted colour,
00689                 as defined in this ColourContext.
00690     Outputs:    -
00691     Returns:    -
00692     Purpose:    Converts an indexed colour into this colour context.
00693                 The converted colour will be supplied from a cache where possible
00694     Errors:     -
00695     SeeAlso:    -
00696 
00697 ********************************************************************************************/
00698 
00699 void ColourContext::ConvertColour(IndexedColour *Source, ColourGeneric *Result)
00700 {
00701     ENSURE(UsageCount > 0, "Colour context being used when not initialised!");
00702 
00703     if (Source->Info.OCContextHandle != MyHandle)   // Uncached so convert it into the cache
00704     {
00705         // Ask the colour to get its source colour for us. If this is a Linked/Tint colour,
00706         // this could well involve getting another colour's definition, converting it, and
00707         // generally giving us an extended tour of stack city.
00708         ColourGeneric SourceColour;
00709         Source->GetSourceColour(&SourceColour);
00710 
00711         // Check if we're doing a spot colour plate. We either get the colour's source colour,
00712         // or if it shouldn't appear on the plate, we get White.
00713         if (ColPlate != NULL && !ColPlate->IsDisabled())
00714         {
00715             switch(ColPlate->GetType())
00716             {
00717                 case COLOURPLATE_SPOT:
00718                     // If we're doing a spot plate and this isn't a descendant of the spot colour
00719                     // then we must eliminate it from this plate. We must also check that it's a "true"
00720                     // spot/tint, as opposed to a tint which is really a process colour.
00721                     if ((!Source->IsADescendantOf(ColPlate->GetSpotColour())) ||
00722                         (!Source->IsSpotOrTintOfSpot()))
00723                     {
00724                         // Fill it with whatever White is defined as in the source context
00725                         GetGlobalDefault(Source->GetColourModel())->GetWhite(&SourceColour);
00726                     }
00727                     break;
00728 
00729                 case COLOURPLATE_CYAN:
00730                 case COLOURPLATE_MAGENTA:
00731                 case COLOURPLATE_YELLOW:
00732                 case COLOURPLATE_KEY:
00733                     // If we're doing a process plate, eliminate any spot colours (or tints) from it
00734                     if (Source->IsSpotOrTintOfSpot())
00735                     {
00736                         // Fill it with whatever White is defined as in the source context
00737                         GetGlobalDefault(Source->GetColourModel())->GetWhite(&SourceColour);
00738                     }
00739                     break;
00740                 default:
00741                     break;
00742             }
00743         }
00744 
00745         ConvertColourBase(GetGlobalDefault(Source->GetColourModel()),
00746                             &SourceColour, &Source->CachedColour,
00747                             Source);
00748 
00749         Source->Info.OCContextHandle  = MyHandle;
00750         Source->Info.CacheColourModel = ColModel;
00751     }
00752 
00753     // Copy the result from our cache
00754     memcpy(Result, &Source->CachedColour, sizeof(ColourGeneric));
00755 }
00756 
00757 
00758 
00759 /********************************************************************************************
00760 
00761 >   void ColourContext::ConvertColour(ColourContext *SourceContext,
00762                                         ColourGeneric *SourceColour,
00763                                         ColourGeneric *Result)
00764 
00765     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00766     Created:    31/03/94
00767     Inputs:     SourceContext - The colour context in which the Source Colour is defined
00768                 Source - A ColourGeneric structure defining a colour to convert, in the
00769                 given SourceContext
00770                 Result - A ColourGeneric structure to recieve the resulting converted colour,
00771                 as defined in this ColourContext.
00772     Outputs:    -
00773     Returns:    -
00774     Purpose:    Converts a colour in any arbitrary colour context into this colour context.
00775                 The converted colour will be supplied from a cache where possible
00776     Errors:     -
00777     SeeAlso:    -
00778 
00779 ********************************************************************************************/
00780 
00781 void ColourContext::ConvertColour(ColourContext *SourceContext,
00782                                     ColourGeneric *SourceColour,
00783                                     ColourGeneric *Result)
00784 {
00785     ENSURE(UsageCount > 0, "Colour context being used when not initialised!");
00786 
00787     // This may look like an opportunity for optimisation, but
00788     // ConvertColourBase is actually an inline function
00789     ConvertColourBase(SourceContext, SourceColour, Result);
00790 }
00791 
00792 
00793 
00794 /********************************************************************************************
00795 
00796 >   virtual void ColourContext::CreateExternalTransform(void)
00797 
00798     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00799     Created:    12/05/96
00800     Inputs:     -
00801     Returns:    -
00802     Purpose:    Create an external transform to be used during colour conversions from
00803                 RGB to the current RCS space. This function uses the Winoil CMS Manager
00804                 to create the transform. Both forward and backward transforms use logical
00805                 RGB descriptions.
00806 
00807 ********************************************************************************************/
00808 
00809 void ColourContext::CreateExternalTransform()
00810 {
00811     // We do nothing here. If no one creates an external transform, the default
00812     // internal one will be used. To create an external transform, call the derived class
00813     // function, not this one as you can see it does nothing.
00814 }
00815 
00816 
00817 /********************************************************************************************
00818 
00819 >   virtual void ColourContext::ApplyInputFilter(ColourPlate *FilterDescription,
00820                                                     ColourContext *DestContext,
00821                                                     ColourGeneric *OutputColour,
00822                                                     IndexedColour *SourceIxCol);
00823 
00824     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00825     Created:    22/1/96
00826     Inputs:     FilterDescription - A ColourPlate describing how the colour is to be filtered
00827     
00828                 DestContext - Points to the context to which the OutputColour will be
00829                 converted after we return it.
00830 
00831                 OutputColour - The colour to be filtered
00832 
00833                 SourceIxCol - NULL, or the original IndexedColour which is being converted.
00834                 This is used for handling spot colour separation correctly.
00835 
00836     Outputs:    OutputColour - Will be modified as appropriate to the current colour
00837                 filtering options (see Purpose)
00838 
00839     Purpose:    All colour conversions call this function for the SOURCE context
00840                 immediately before converting the colour. This gives the input colour
00841                 context the chance to apply a filtering process to the colour.
00842 
00843                 This is usually used to provide colour separations. Often, this function
00844                 will do nothing to the output colour - generally it is only used by CMYK
00845                 contexts in order to colour-separate the colour in CMYK space.
00846 
00847     SeeAlso:    ColourContext::ConvertColourBase
00848 
00849 ********************************************************************************************/
00850 
00851 void ColourContext::ApplyInputFilter(ColourPlate *FilterDescription, ColourContext *DestContext,
00852                                             ColourGeneric *OutputColour, IndexedColour *SourceIxCol)
00853 {
00854 //  ERROR3IF(FilterDescription == NULL || DestContext == NULL || OutputColour == NULL, "Illegal NULL params");
00855 //
00856 //  if (FilterDescription == NULL)
00857 //      return;
00858 //
00859 }
00860 
00861 
00862 
00863 /********************************************************************************************
00864 
00865 >   virtual void ColourContext::ApplyOutputFilter(ColourPlate *FilterDescription,
00866                                                     ColourContext *SourceContext,
00867                                                     ColourGeneric *OutputColour,
00868                                                     IndexedColour *SourceIxCol);
00869 
00870     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00871     Created:    22/1/96
00872     Inputs:     FilterDescription - A ColourPlate describing how the colour is to be filtered
00873     
00874                 SourceContext - Points to the context from which the OutputColour has just
00875                 been converted. 
00876 
00877                 OutputColour - The colour to be filtered
00878 
00879                 SourceIxCol - NULL, or the IndexedColour which was the source of the colour
00880                 being converted. This is only used for information when preparing spot colour
00881                 separations.
00882 
00883     Outputs:    OutputColour - Will be modified as appropriate to the current colour
00884                 filtering options (see Purpose)
00885 
00886     Purpose:    All colour conversions call this function for the DEST context immediately
00887                 prior to returning the converted colour to the caller. This gives the output
00888                 colour context the chance to apply an output filtering process to the output
00889                 colour.
00890 
00891                 This is usually used to provide colour separations, and may also be used
00892                 to apply some colour corrections. Often, this function will do nothing
00893                 to the output colour.
00894 
00895     SeeAlso:    ColourContext::ConvertColourBase
00896 
00897 ********************************************************************************************/
00898 
00899 void ColourContext::ApplyOutputFilter(ColourPlate *FilterDescription, ColourContext *SourceContext,
00900                                             ColourGeneric *OutputColour, IndexedColour *SourceIxCol)
00901 {
00902 //  ERROR3IF(FilterDescription == NULL || SourceContext == NULL || OutputColour == NULL, "Illegal NULL params");
00903 //
00904 //  if (FilterDescription == NULL)
00905 //      return;
00906 }
00907 
00908 
00909 
00910 /********************************************************************************************
00911 
00912 >   void ColourContext::SetColourPlate(ColourPlate *NewColourPlate)
00913 
00914     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00915     Created:    31/01/96
00916     Inputs:     NULL (to disable colour seps), or points to the new ColourPlate descriptor object
00917                 NOTE that the ColourPlate object now belongs to the ColourContext, and will be
00918                 deleted by the context when it is finished with it.
00919 
00920     Purpose:    Sets a colour separation/plate for this context
00921 
00922     Notes:      The ColourPlate object now belongs to the ColourContext, and will be
00923                 deleted by the context when it is finished with it.
00924 
00925                 (To remove the ColourPlate again in a way that does not delete the ColourPlate,
00926                 call ColourContext::DetachColourPlate rather than SetColourPlate(NULL))
00927 
00928                 The Context's cache handle will be changed so that all cached colours
00929                 in this output context are effectively 'flushed'.
00930 
00931     SeeAlso:    ColourPlate; ColourContext::ApplyOutputFilter; ColourContext::GetColourPlate;
00932                 ColourContext::DetachColourPlate
00933 
00934 ********************************************************************************************/
00935 
00936 void ColourContext::SetColourPlate(ColourPlate *NewColourPlate)
00937 {
00938     // Trying to set ColourPlate to the one we're already using - ignore them!
00939     if (ColPlate == NewColourPlate)
00940         return;
00941 
00942     // Delete our current ColourPlate
00943     if (ColPlate != NULL)
00944     {
00945         delete ColPlate;
00946         ColPlate = NULL;
00947     }
00948 
00949     // Remember our new ColourPlate filter descriptor
00950     ColPlate = NewColourPlate;
00951 
00952     // Change our context handle so that all cached colours in this context
00953     // are effectively "flushed"
00954     ColourPlateHasChanged();
00955 }
00956 
00957 
00958 
00959 /********************************************************************************************
00960 
00961 >   ColourPlate *ColourContext::DetachColourPlate(void)
00962 
00963     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00964     Created:    11/6/96
00965 
00966     Returns:    The pointer to the previously attached ColourPlate (may be NULL)
00967 
00968     Purpose:    Detaches the ColourPlate (if any) currently attached to this ColourContext.
00969                 The context will no longer use the colour plate descriptor, and will return
00970                 to default colour separation/correction actions.
00971                 
00972                 ** The caller is now responsible for deleting the returned object **
00973 
00974     Notes:      The Context's cache handle will be changed so that all cached colours
00975                 in this output context are effectively 'flushed'.
00976 
00977     SeeAlso:    ColourPlate; ColourContext::GetColourPlate; ColourContext::SetColourPlate
00978 
00979 ********************************************************************************************/
00980 
00981 ColourPlate *ColourContext::DetachColourPlate(void)
00982 {
00983     ColourPlate *OldColourPlate = ColPlate;
00984 
00985     if (ColPlate != NULL)
00986     {
00987         ColPlate = NULL;
00988 
00989         // Change our context handle so that all cached colours in this context
00990         // are effectively "flushed"
00991         ColourPlateHasChanged();
00992     }
00993 
00994     return(OldColourPlate);
00995 }
00996 
00997 
00998 
00999 /********************************************************************************************
01000 
01001 >   ColourPlate *ColourContext::GetColourPlate(void)
01002 
01003     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01004     Created:    31/01/96
01005 
01006     Returns:    NULL if Colour separation is disabled on this context, else a pointer
01007                 to a ColourPlate descriptor object which describes the current colour
01008                 separation/filtering options.
01009 
01010     Purpose:    Reads the colour separation/plate for this context
01011 
01012     SeeAlso:    ColourPlate; ColourContext::ApplyOutputFilter; ColourContext::SetColourPlate
01013 
01014 ********************************************************************************************/
01015 
01016 ColourPlate *ColourContext::GetColourPlate(void)
01017 {
01018     return(ColPlate);
01019 }
01020 
01021 
01022 
01023 /********************************************************************************************
01024 
01025 >   void ColourContext::ColourPlateHasChanged(void)
01026 
01027     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01028     Created:    9/5/96
01029 
01030     Purpose:    Effectively flushes the caches of all colours currently cached in this
01031                 ColourContext, so that on the next redraw they will re-convert. 
01032 
01033     Notes:      This is achieved by generating a new unique handle for this Context.
01034                 Note that after 65536 handles, we will start re-using handles, and
01035                 things will look bad if we inadvertently use the same handle for 2
01036                 contexts. This is an extremely unlikely occurrence, but please do
01037                 not call this function unless it is absolutely necessary, to minimise
01038                 the number of handle changes that occur.
01039 
01040                 This function is automatically called whenever you change the
01041                 ColourPlate attached to this context in any way.
01042 
01043     Scope:      Intended as an internal routine; also called by ColourPlate class
01044                 Should not be called by anyone else
01045 
01046     SeeAlso:    ColourContext::SetColourPlate; IndexedColour; DocColour
01047 
01048 ********************************************************************************************/
01049 
01050 void ColourContext::ColourPlateHasChanged(void)
01051 {
01052     // We need to change this context's "MyHandle" so that all cached colours for this
01053     // context are treated as non-cached again, and will be converted correctly for
01054     // the new output filter.
01055     MyHandle = NextColourContextHandle++;
01056 }
01057 
01058 
01059 
01060 /********************************************************************************************
01061 
01062 >   virtual BOOL ColourContext::SetComponentUnitGroup(UINT32 ComponentID,
01063                                                         UnitGroup* pComponentUnitGroup)
01064     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
01065     Created:    02/05/96          
01066     Inputs:     ComponentIndex : the number of the component (1..GetComponentCount())
01067                 ComponentUnitGroup : pointer to the required UnitGroup for the component 
01068     Outputs:    -
01069     Returns:    TRUE if set OK
01070                 FALSE otherwise
01071     Purpose:    Allows the UnitGroup of the given component in the ColourModel to be set
01072     Errors:     ERROR2IF ComponentIndex < 1 or greater than number of components in model
01073 
01074 ********************************************************************************************/
01075 
01076 BOOL ColourContext::SetComponentUnitGroup(UINT32 ComponentID, UnitGroup* pComponentUnitGroup)
01077 {
01078     ERROR2IF(ComponentID < 1 || ComponentID > GetComponentCount(), FALSE, "Invalid Index");
01079     ERROR2IF(pComponentUnitGroup == NULL, FALSE, "Invalid UnitGroup");
01080 
01081     ERROR3IF(!pComponentUnitGroup->IS_KIND_OF(UnitGroup), "Invalid UnitGroup");
01082 
01083     UnitGroup** pUnitGroupArray = GetComponentUnitGroups();
01084     ERROR3IF(!(pUnitGroupArray[ComponentID - 1]->IS_KIND_OF(UnitGroup)), 
01085                 "ColourContext::GetComponentUnitGroup - Not UnitGroup array");
01086 
01087     pUnitGroupArray[ComponentID - 1] = pComponentUnitGroup;
01088     return TRUE;
01089 }
01090 
01091 
01092 
01093 /********************************************************************************************
01094 
01095 >   virtual UnitGroup *ColourContext::GetComponentUnitGroup(UINT32 ComponentID)
01096 
01097     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
01098     Created:    02/05/96          
01099     Inputs:     ComponentID - the number of the component (1..GetComponentCount())
01100     Outputs:    -
01101     Returns:    A pointer to the desired UnitGroup
01102     Purpose:    Provides the UnitGroup of the given component in the ColourModel
01103     Errors:     ERROR2IF ComponentIndex < 1 or greater than number of components in model
01104     See Also:   ColourContextCMYK::GetComponentUnitGroups()
01105                 ColourContextGreyT::GetComponentUnitGroups()
01106                 ColourContextHSVT::GetComponentUnitGroups()
01107                 ColourContextRGBT::GetComponentUnitGroups()
01108 
01109 ********************************************************************************************/
01110 
01111 UnitGroup *ColourContext::GetComponentUnitGroup(UINT32 ComponentID)
01112 {
01113     ERROR2IF(ComponentID < 1 || ComponentID > GetComponentCount(), FALSE, "Invalid ID");
01114     UnitGroup** pUnitGroupArray = GetComponentUnitGroups();
01115     ERROR3IF(!(pUnitGroupArray[ComponentID - 1]->IS_KIND_OF(UnitGroup)), 
01116                 "ColourContext::GetComponentUnitGroup - Not UnitGroup array");
01117 
01118     return pUnitGroupArray[ComponentID - 1];
01119 }
01120 
01121 
01122 
01123 
01124 
01125 
01126 
01127 
01128 
01129 
01130 
01131 
01132 
01133 
01134 
01135 
01136 
01137 
01138 /********************************************************************************************
01139 
01140 >   void ColourContextRGBT::ColourContextRGBT(View *Scope, double GammaValue = 1.0)
01141 
01142     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01143     Created:    31/03/94
01144     Inputs:     Scope - The view in which this context is to be used, or NULL
01145                 GammaValue - A gamma-correction gamma factor. You know... Gamma.
01146                 Heck, if you don't know what a gamma value is, then don't pass
01147                 anything in, because it has a good default value.
01148     Outputs:    -
01149     Returns:    -
01150     Purpose:    Constructor for an RGBT Colour context
01151 
01152     Notes:      Colour Contexts should not be created and used directly. See the
01153                 notes in the SeeAlso's for instructions on proper care and use.
01154 
01155     Errors:     -
01156     SeeAlso:    ColourContext::ColourContext; ColourContextList::AddContext
01157 
01158 ********************************************************************************************/
01159 
01160 ColourContextRGBT::ColourContextRGBT(View *Scope, double GammaValue)
01161                   : ColourContext(Scope)
01162 {
01163     ColModel = COLOURMODEL_RGBT;
01164     Gamma = GammaValue;
01165 
01166     CreateExternalTransform();
01167 }
01168 
01169 
01170 
01171 /********************************************************************************************
01172 
01173 >   ColourContextWebRGBT::ColourContextWebRGBT(View *Scope, double GammaValue)
01174                   : ColourContextRGBT(Scope, GammaValue)
01175 
01176     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
01177     Created:    ??/11/99
01178     Inputs:     Scope - The view in which this context is to be used, or NULL
01179                 GammaValue - A gamma-correction gamma factor. You know... Gamma.
01180                 Heck, if you don't know what a gamma value is, then don't pass
01181                 anything in, because it has a good default value.
01182     Outputs:    -
01183     Returns:    -
01184     Purpose:    Constructor for an RGBT Web Colour context
01185 
01186     Notes:      Colour Contexts should not be created and used directly. See the
01187                 notes in the SeeAlso's for instructions on proper care and use.
01188 
01189     Errors:     -
01190     SeeAlso:    ColourContext::ColourContext; ColourContextList::AddContext
01191 
01192 ********************************************************************************************/
01193 
01194 ColourContextWebRGBT::ColourContextWebRGBT(View *Scope, double GammaValue)
01195                   : ColourContextRGBT(Scope, GammaValue)
01196 {
01197     ColModel = COLOURMODEL_RGBT;
01198 }
01199 
01200 
01201 
01202 /********************************************************************************************
01203 
01204 >   void ColourContextRGBT::CreateExternalTransform(void)
01205 
01206     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01207     Created:    12/05/96
01208     Inputs:     -
01209     Returns:    -
01210     Purpose:    Create an external transform to be used during colour conversions from
01211                 RGB to the current RCS space. This function uses the Winoil CMS Manager
01212                 to create the transform. Both forward and backward transforms use logical
01213                 RGB descriptions.
01214 
01215 ********************************************************************************************/
01216 
01217 void ColourContextRGBT::CreateExternalTransform()
01218 {
01219 #ifndef NO_XARACMS
01220     CMSColourSpace cmsSpace;
01221     XaraCMS* lpCMSMan = GetApplication()->GetCMSManager();
01222 
01223     if (lpCMSMan != NULL)
01224     {
01225         // first read our internal colour calibration space
01226         lpCMSMan->GetLogicalProfile(&cmsSpace);
01227 
01228         // set this as the active colour profile
01229         UINT32 err = lpCMSMan->SetProfile(cmsSpace);
01230 
01231         // if we haven't got an error, create that transform
01232         if (err==0)
01233             CMSTransform = lpCMSMan->CreateTransform(DISPLAY_RCS);
01234     }
01235 #endif
01236 }
01237 
01238 
01239 /********************************************************************************************
01240 
01241 >   void ColourContextRGBT::ConvertToCIET(ColourGeneric *Source, DColourCIET *Result)
01242 
01243     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01244     Created:    31/03/94
01245     Inputs:     Source - A Colour defined in this RGBT context
01246                 Result - pointer to a structure to recieve the resulting colour as
01247                 defined in CIE space
01248     Outputs:    -
01249     Returns:    -
01250     Purpose:    Converts the given colour from our RGBT colourspace to CIET colourspace
01251                 This conversion will include Gamma correction etc as defined by
01252                 this colour context.
01253     Notes:      -
01254     Errors:     -
01255     SeeAlso:    ColourContextRGBT::ConvertFromCIET
01256 
01257 ********************************************************************************************/
01258 
01259 void ColourContextRGBT::ConvertToCIET(ColourGeneric *Source, DColourCIET *Result)
01260 {
01261     ENSURE(UsageCount > 0, "Colour context being used when not initialised!");
01262 
01263     ColourRGBT *bob = (ColourRGBT *) Source;
01264 
01265 #ifndef NO_XARACMS
01266     // If we've got a CMS manager, use it, else use the version 1.1 bodge
01267     XaraCMS* lpCMSMan = GetApplication()->GetCMSManager();
01268 
01269     if (lpCMSMan != NULL)
01270     {
01271         // The new colour calibration method
01272         CMSColour icol, ocol;
01273         icol.c0 = bob->Red.MakeDouble();
01274         icol.c1 = bob->Green.MakeDouble();
01275         icol.c2 = bob->Blue.MakeDouble();
01276 
01277         // If we have no colour transform, or if we don't want the colour corrected/separated,
01278         // then we will just do a "logical" conversion.
01279         if (CMSTransform == NULL || (ColPlate != NULL && ColPlate->IsDisabled()))
01280             lpCMSMan->ConvRGBtoCIEXYZ(icol, ocol);
01281         else
01282             lpCMSMan->GTransform(CMSTransform, cmsForward, icol, ocol);
01283 
01284         Result->X = ocol.c0;
01285         Result->Y = ocol.c1;
01286         Result->Z = ocol.c2;
01287     }
01288     else
01289 #endif
01290     {
01291         // The old rgb method
01292         Result->X = bob->Red.MakeDouble();
01293         Result->Y = bob->Green.MakeDouble();
01294         Result->Z = bob->Blue.MakeDouble();
01295     }
01296 
01297     Result->Transparent = 0.0;//bob->Transparent;
01298 }
01299 
01300 
01301 
01302 
01303 /********************************************************************************************
01304 
01305 >   void ColourContextRGBT::ConvertFromCIET(DColourCIET *Source, ColourGeneric *Result)
01306 
01307     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01308     Created:    31/03/94
01309     Inputs:     Source - A Colour defined in the CIET colourspace
01310                 Result - pointer to a structure to recieve the resulting colour as
01311                 defined in the RGBT space described by this colour context.
01312     Outputs:    -
01313     Returns:    -
01314     Purpose:    Converts the given colour to our RGBT colourspace from CIET colourspace
01315                 This conversion will include Gamma correction etc as defined by
01316                 this colour context.
01317     Notes:      -
01318     Errors:     -
01319     SeeAlso:    ColourContextRGBT::ConvertToCIET
01320 
01321 ********************************************************************************************/
01322 
01323 void ColourContextRGBT::ConvertFromCIET(DColourCIET *Source, ColourGeneric *Result)
01324 {
01325     ENSURE(UsageCount > 0, "Colour context being used when not initialised!");
01326 
01327     ColourRGBT *bob = (ColourRGBT *) Result;
01328 
01329 #ifndef NO_XARACMS
01330     // If we've got a CMS manager, use it, else use the version 1.1 bodge
01331     XaraCMS* lpCMSMan = GetApplication()->GetCMSManager();
01332 
01333     if (lpCMSMan != NULL)
01334     {
01335         // The new colour calibration method
01336         CMSColour icol, ocol;
01337         icol.c0 = Source->X;
01338         icol.c1 = Source->Y;
01339         icol.c2 = Source->Z;
01340 
01341         // If we have no colour transform, or if we don't want the colour corrected/separated,
01342         // then we will just do a "logical" conversion.
01343         if (CMSTransform == NULL || (ColPlate != NULL && ColPlate->IsDisabled()))
01344             lpCMSMan->ConvCIEXYZtoRGB(icol, ocol);
01345         else
01346             lpCMSMan->GTransform(CMSTransform, cmsReverse, icol, ocol);
01347 
01348         bob->Red    = ocol.c0;
01349         bob->Green  = ocol.c1;
01350         bob->Blue   = ocol.c2;
01351     }
01352     else
01353 #endif
01354     {
01355         // The old rgb method
01356         bob->Red    = Source->X;
01357         bob->Green  = Source->Y; 
01358         bob->Blue   = Source->Z;
01359     }
01360 
01361     bob->Transparent = 0;//Source->Transparent;
01362 }
01363 
01364 
01365 
01366 /********************************************************************************************
01367 
01368 >   virtual BOOL ColourContextRGBT::IsDifferent(ColourContext *Other) const
01369 
01370     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01371     Created:    13/04/94
01372     Inputs:     Other - a colour context to comapre ourselves to
01373     Outputs:    -
01374     Returns:    TRUE if the other colour context object is different from
01375                 ourself, or TRUE if it is an exactly equivalent context.
01376     Purpose:    Determine if two colour contexts are not exactly equivalent
01377     Errors:     -
01378     SeeAlso:    ColourContext::IsDifferent
01379 
01380 ********************************************************************************************/
01381 
01382 
01383 BOOL ColourContextRGBT::IsDifferent(ColourContext *Other) const
01384 {
01385     if(ColourContext::IsDifferent(Other))   // Different on generic ColourContext basis
01386         return(TRUE);
01387 
01388     // These must both be RGBT contexts, so check if they are equivalent
01389     return(Gamma != ((ColourContextRGBT *)Other)->Gamma);
01390 }
01391 
01392 
01393 
01394 /********************************************************************************************
01395 
01396 >   void ColourContextRGBT::GetModelName(StringBase *Result)
01397 
01398     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01399     Created:    1/6/94
01400     Inputs:     -
01401     Outputs:    Result returns continaing a String of the name of the context.
01402                 This string is guaranteed to fit within a String_32 - this is the
01403                 minimum size you should allocate. (Most names, in English at least,
01404                 are shorter than this (10 chars max, e.g. 'RGB' 'HSV' 'Greyscale')
01405                 so allow at least 10 chars of space in your displays as well)
01406     Returns:    -
01407     Purpose:    Returns the name of this context's colour model
01408 
01409 ********************************************************************************************/
01410 
01411 void ColourContextRGBT::GetModelName(StringBase *Result)
01412 {
01413     ENSURE(Result != NULL, "ColourContext::GetModelName called with NULL result pointer!");
01414 
01415     *Result = String_32(_R(IDS_COLMODEL_RGBT));
01416 }
01417 
01418 
01419 
01420 /********************************************************************************************
01421 
01422 >   void ColourContextWebRGBT::GetModelName(StringBase *Result)
01423 
01424     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
01425     Created:    ??/11/99
01426     Inputs:     -
01427     Outputs:    Result returns continaing a String of the name of the context.
01428                 This string is guaranteed to fit within a String_32 - this is the
01429                 minimum size you should allocate. (Most names, in English at least,
01430                 are shorter than this (10 chars max, e.g. 'RGB' 'HSV' 'Greyscale')
01431                 so allow at least 10 chars of space in your displays as well)
01432     Returns:    -
01433     Purpose:    Returns the name of this context's colour model
01434 
01435 ********************************************************************************************/
01436 
01437 void ColourContextWebRGBT::GetModelName(StringBase *Result)
01438 {
01439     ENSURE(Result != NULL, "ColourContext::GetModelName called with NULL result pointer!");
01440 
01441     *Result = String_32(_R(IDS_COLMODEL_WEBRGBT));
01442 }
01443 
01444 
01445 
01446 /********************************************************************************************
01447 
01448 >   BOOL ColourContextRGBT::GetComponentName(INT32 ComponentID, StringBase *Result,
01449                                              BOOL LongName = FALSE)
01450 
01451     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01452     Created:    26/7/94
01453     Inputs:     ComponentID - Index [1..4] of the component you want the name of
01454                 (Result is an output)
01455                 LongName - TRUE to get the long name, FALSE to get the short name
01456                             (e.g. "Magenta" vs "M", "Saturation" vs "Sat")
01457 
01458     Outputs:    Result returns containing a String of the name of the given component
01459                 of colours defined in this context.
01460                 This string is guaranteed to fit within a String_32 - this is the
01461                 minimum size you should allocate. (Most names, in English at least,
01462                 are shorter than this (10 chars max, e.g. 'Red' 'Hue' 'Saturation')
01463                 so allow at least 10 chars of space in your displays as well)
01464 
01465                 Note that Result can be passed in NULL in order to only determine if the
01466                 context supports a given component.
01467 
01468     Returns:    FALSE if this component is not used by this model.
01469     Purpose:    Returns the name of one of this context's colour components
01470 
01471     Notes:      The components are given in the same order as they appear in the
01472                 high-precision ColourXYZ structures defined in colmodel.h
01473 
01474 ********************************************************************************************/
01475 
01476 BOOL ColourContextRGBT::GetComponentName(INT32 ComponentID, StringBase *Result, BOOL LongName)
01477 {
01478     UINT32 StringID = 0;
01479     BOOL Used = TRUE;
01480 
01481     switch(ComponentID)
01482     {
01483         case 1:
01484             StringID = (LongName) ? _R(IDS_COLCOMPL_RED) : _R(IDS_COLCOMP_RED);
01485             break;
01486             
01487         case 2:
01488             StringID = (LongName) ? _R(IDS_COLCOMPL_GREEN) : _R(IDS_COLCOMP_GREEN);
01489             break;
01490 
01491         case 3:
01492             StringID = (LongName) ? _R(IDS_COLCOMPL_BLUE) : _R(IDS_COLCOMP_BLUE);
01493             break;
01494 #ifdef TRANSPARENTCOLOUR
01495         default:
01496             StringID = _R(IDS_COLCOMP_TRANS);
01497             break;
01498 #else
01499         default:
01500             Used = FALSE;
01501             break;
01502 #endif
01503     }
01504 
01505     if (Result != NULL && StringID != 0)
01506         *Result = String_32(StringID);
01507 
01508     return(Used);
01509 }
01510 
01511 
01512 
01513 /********************************************************************************************
01514 
01515 >   virtual UnitGroup **ColourContextRGBT::GetComponentUnitGroups()
01516 
01517     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
01518     Created:    02/05/96          
01519     Inputs:     -
01520     Outputs:    -
01521     Returns:    A pointer to the UnitGroup array
01522     Purpose:    Provides an array of UnitGroups primarily for use by the base class 
01523                 (ColourContext) members Set/GetComponentUnitGroup().
01524     Errors:     -
01525     See Also:   ColourContext::GetComponentUnitGroup()
01526                 ColourContext::SetComponentUnitGroup()
01527 
01528 ********************************************************************************************/
01529 
01530 UnitGroup **ColourContextRGBT::GetComponentUnitGroups()
01531 {
01532     return m_pUnitGroupArray;
01533 }
01534 
01535 
01536 UnitGroup *ColourContextRGBT::m_pUnitGroupArray[] =
01537 {
01538     &(StandardUnit::PercentGroup),
01539     &(StandardUnit::PercentGroup),
01540     &(StandardUnit::PercentGroup)
01541 };
01542 
01543 
01544 
01545 /********************************************************************************************
01546 
01547 >   UINT32 ColourContextRGBT::GetComponentCount()
01548 
01549     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
01550     Created:    02/05/96          
01551     Returns:    The number of components
01552     Purpose:    Provides number of components in the colour context's colour model
01553 
01554 ********************************************************************************************/
01555 
01556 UINT32 ColourContextRGBT::GetComponentCount()
01557 {
01558     return MAX_COMPONENTS;
01559 }
01560 
01561 
01562 /********************************************************************************************
01563 
01564 >   virtual void ColourContextRGBT::ApplyTint(ColourValue TintFraction,
01565                                                 ColourGeneric *SourceAndResult)
01566 
01567     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01568     Created:    17/11/94
01569     Inputs:     TintFraction - The fraction (as a FIXED24 ColourValue) by which the colour
01570                 should be tinted. This value is expected to lie between 0.0 and 1.0 inclusive
01571 
01572                 SourceAndResult - The source colour to be tinted, as defined in this
01573                 colour model
01574 
01575     Outputs:    SourceAndResult is tinted by the given TintFraction
01576                 If TintFraction <= 0.0, White is output
01577                 If TintFraction >= 1.0, The source colour is output
01578 
01579     Returns:    -
01580     Purpose:    Tints a colour (mixes it with white)
01581 
01582     Notes:      If the tinting value is out of range, either source-colour ow white (as
01583                 appropriate) will be output.
01584 
01585 ********************************************************************************************/
01586 
01587 void ColourContextRGBT::ApplyTint(ColourValue TintFraction, ColourGeneric *SourceAndResult)
01588 {
01589     ColourRGBT *Result = (ColourRGBT *) SourceAndResult;
01590     
01591     if (TintFraction <= FIXED24(0.0))       // 0% tint = White
01592     {
01593         Result->Red = Result->Green = Result->Blue = FIXED24(1.0);
01594         return;
01595     }
01596 
01597     if (TintFraction >= FIXED24(1.0))       // The Result colour is identical to the source
01598         return;
01599 
01600     // Otherwise, tint the colour...
01601     Result->Red   = FIXED24(1.0) - (TintFraction - (Result->Red   * TintFraction));
01602     Result->Green = FIXED24(1.0) - (TintFraction - (Result->Green * TintFraction));
01603     Result->Blue  = FIXED24(1.0) - (TintFraction - (Result->Blue  * TintFraction));
01604 }
01605 
01606 
01607 /********************************************************************************************
01608 
01609 >   void ColourContextRGBT::ApplyShade(ColourValue XFraction, ColourValue YFraction,
01610                                                 ColourGeneric *SourceAndResult)
01611 
01612     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01613     Created:    24/8/95
01614     Inputs:     XFraction - The fraction (as a FIXED24 ColourValue) by which the colour
01615                 should be saturated. This value is expected to lie between -1.0 and 1.0 inclusive
01616                 Values below 0.0 mean tint towards 0, while values above mean tint towards 1.
01617                 0.0 means no tinting
01618 
01619                 YFraction - The fraction (as a FIXED24 ColourValue) by which the colour
01620                 should be shaded. This value is expected to lie between -1.0 and 1.0 inclusive
01621                 Values below 0.0 mean shade towards 0, while values above mean shade towards 1.
01622                 0.0 means no shading
01623 
01624                 SourceAndResult - The source colour to be tinted, as defined in this
01625                 colour model
01626 
01627     Outputs:    SourceAndResult is shaded by the given Fractions
01628                 Any invalid value is clipped to 0.0
01629 
01630     Returns:    -
01631     Purpose:    Shades a colour (tweaks the saturation and value in a relative way)
01632 
01633     Notes:      Contexts other than HSV currently convert the colour to and from HSV
01634                 form in order to apply the shade. This is a tad inefficient, but a
01635                 quick'n'easy bodge that will get it going nice and quickly.
01636 
01637 ********************************************************************************************/
01638 
01639 void ColourContextRGBT::ApplyShade(ColourValue XFraction, ColourValue YFraction,
01640                                     ColourGeneric *SourceAndResult)
01641 {
01642     ColourHSVT HSVDef;
01643     ColourContext *cc = ColourContext::GetGlobalDefault(COLOURMODEL_HSVT);
01644     ERROR3IF(cc == NULL, "No default HSV colour context?!");
01645 
01646     cc->ConvertColour(this, SourceAndResult, (ColourGeneric *) &HSVDef);
01647     cc->ApplyShade(XFraction, YFraction,  (ColourGeneric *) &HSVDef);
01648     ConvertColour(cc, (ColourGeneric *) &HSVDef, SourceAndResult);
01649 }
01650 
01651 
01652 
01653 /********************************************************************************************
01654 
01655 >   virtual void ColourContextRGBT::ApplyOutputFilter(ColourPlate *FilterDescription,
01656                                                     ColourContext *SourceContext,
01657                                                     ColourGeneric *OutputColour,
01658                                                     IndexedColour *SourceIxCol)
01659 
01660     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01661     Created:    22/1/96
01662     Inputs:     FilterDescription - A ColourPlate describing how the colour is to be filtered
01663     
01664                 SourceContext - Points to the context from which the OutputColour has just
01665                 been converted. 
01666 
01667                 OutputColour - The colour to be filtered
01668 
01669                 SourceIxCol - NULL, or the IndexedColour which was the source of the colour
01670                 being converted. This is only used for information when preparing spot colour
01671                 separations.
01672 
01673     Outputs:    OutputColour - Will be modified as appropriate to the current colour
01674                 filtering options (see Purpose)
01675 
01676     Purpose:    All colour conversions call this function immediately prior to returning
01677                 the converted colour to the caller. This gives the output colour context
01678                 the chance to apply an output filtering process to the output colour.
01679 
01680                 This is usually used to provide colour separations, and may also be used
01681                 to apply some colour corrections. Often, this function will do nothing
01682                 to the output colour.
01683 
01684     SeeAlso:    ColourContext::ConvertColourBase
01685 
01686 ********************************************************************************************/
01687 
01688 void ColourContextRGBT::ApplyOutputFilter(ColourPlate *FilterDescription, ColourContext *SourceContext,
01689                                             ColourGeneric *OutputColour, IndexedColour *SourceIxCol)
01690 {
01691     ERROR3IF(FilterDescription == NULL || SourceContext == NULL || OutputColour == NULL, "Illegal NULL params");
01692 
01693     // No FilterDescription means no filtering, so we return immeidately
01694     // If the source colour was CMYK, we mustn't filter it, except when doing a composite preview, as
01695     // the filtering (separation) of CMYK all happens in ApplyInputFilter
01696     if (FilterDescription == NULL ||
01697         (SourceContext->GetColourModel() == COLOURMODEL_CMYK &&
01698          FilterDescription->GetType() != COLOURPLATE_COMPOSITE))
01699     {
01700         return;
01701     }
01702 
01703     ColourRGBT *OutputRGB = (ColourRGBT *)OutputColour;
01704     FIXED24 temp;
01705 
01706 
01707 /*-----------------------------------------------------------------------------------------------
01708     Local Macro GETCOLOURINCMYK(ColourCMYK RESULT)
01709 
01710     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01711     Date:       3/7/96
01712     Inputs:     RESULT - will be filled in with a CMYK definition for OutputRGB
01713     Purpose:    Converts our OutputRGB variable into a CMYK form.
01714 
01715     Notes:      This only works in the scope in which it is used below. It is merely to save
01716                 writing the code out longhand, and to make the repeated section of the code below
01717                 more readable.
01718 
01719                 Special care is taken with the conversion - We try to find a CMYK context from
01720                 our ScopeView, so that we use the correct colour-separation profile for the current
01721                 output device. We also do the conversion manually (to & from CIE space) rather
01722                 than just calling ConvertColour because (a) it's more efficient, and (b) we don't
01723                 want the CMYK context to do anything like colour separation on the colour!
01724 
01725                 This macro ius undefined at the end of the switch statement which uses it
01726 
01727   -----------------------------------------------------------------------------------------------
01728 */
01729 #define GETCOLOURINCMYK(RESULT)                                                                 \
01730     {                                                                                           \
01731         ColourContextCMYK *ccCMYK;                                                              \
01732         if (ScopeView != NULL)                                                                  \
01733             ccCMYK = (ColourContextCMYK *) ScopeView->GetColourContext(COLOURMODEL_CMYK);       \
01734         else                                                                                    \
01735             ccCMYK = (ColourContextCMYK *) ColourManager::GetColourContext(COLOURMODEL_CMYK);   \
01736                                                                                                 \
01737         DColourCIET IntermediateResult;                                                         \
01738         ConvertToCIET(OutputColour, &IntermediateResult);                                       \
01739         ccCMYK->ConvertFromCIET(&IntermediateResult, (ColourGeneric *)&(RESULT));               \
01740     }
01741 //-----------------------------------------------------------------------------------------------
01742 
01743 
01744     // Separate the colour as appropriate
01745     switch(FilterDescription->GetType())
01746     {
01747         case COLOURPLATE_CYAN:
01748             {
01749                 ColourCMYK cmyk;                                // Get OutputRGB as defined in cmyk
01750                 GETCOLOURINCMYK(cmyk);
01751 
01752                 if (FilterDescription->IsNegative())            // Negate the plate if necessary
01753                     OutputRGB->Red = cmyk.Cyan;
01754                 else
01755                     OutputRGB->Red = 1.0 - cmyk.Cyan;
01756 
01757                 if (FilterDescription->IsMonochrome())          // Make the plate a greyscale if necessary
01758                     OutputRGB->Green = OutputRGB->Blue = OutputRGB->Red;
01759                 else
01760                     OutputRGB->Green = OutputRGB->Blue = 1.0;
01761             }
01762             break;
01763 
01764         case COLOURPLATE_MAGENTA:
01765             {
01766                 ColourCMYK cmyk;                                // Get OutputRGB as defined in cmyk
01767                 GETCOLOURINCMYK(cmyk);
01768 
01769                 if (FilterDescription->IsNegative())            // Negate the plate if necessary
01770                     OutputRGB->Green = cmyk.Magenta;
01771                 else
01772                     OutputRGB->Green = 1.0 - cmyk.Magenta;
01773 
01774                 if (FilterDescription->IsMonochrome())          // Make the plate a greyscale if necessary
01775                     OutputRGB->Red = OutputRGB->Blue = OutputRGB->Green;
01776                 else
01777                     OutputRGB->Red = OutputRGB->Blue = 1.0;
01778             }
01779             break;
01780 
01781         case COLOURPLATE_YELLOW:
01782             {
01783                 ColourCMYK cmyk;                                // Get OutputRGB as defined in cmyk
01784                 GETCOLOURINCMYK(cmyk);
01785 
01786                 if (FilterDescription->IsNegative())            // Negate the plate if necessary
01787                     OutputRGB->Blue = cmyk.Yellow;
01788                 else
01789                     OutputRGB->Blue = 1.0 - cmyk.Yellow;
01790 
01791                 if (FilterDescription->IsMonochrome())          // Make the plate a greyscale if necessary
01792                     OutputRGB->Green = OutputRGB->Red = OutputRGB->Blue;
01793                 else
01794                     OutputRGB->Green = OutputRGB->Red = 1.0;
01795             }
01796             break;
01797 
01798         case COLOURPLATE_KEY:
01799             {
01800                 ColourCMYK cmyk;                                // Get OutputRGB as defined in cmyk
01801                 GETCOLOURINCMYK(cmyk);
01802 
01803                 // The FilterDescription->IsMonochrome() flag has no effect on this plate!
01804 
01805                 if (FilterDescription->IsNegative())
01806                     OutputRGB->Red = OutputRGB->Green = OutputRGB->Blue = cmyk.Key;
01807                 else
01808                     OutputRGB->Red = OutputRGB->Green = OutputRGB->Blue = 1.0 - cmyk.Key;
01809             }
01810             break;
01811 
01812         case COLOURPLATE_SPOT:
01813             // NOTE:
01814             // Spot colours are partially handled by the IndexedColour variants of
01815             // ConvertColour, so will be separated appropriately by the time they
01816             // reach us here. However, non-IndexedColours will not be, so we must
01817             // sit on them to make them white, so that DocColour and GenericColour
01818             // conversions are eliminated properly from spot plates.
01819             // However, if a spot colour gets this far, we need to generate an ink
01820             // density value for output, as well as applying the negate flag.
01821             //
01822             // Actually, I have decreed that all spot plates will always be monochrome,
01823             // because that makes coding DocColour::Mix much easier, and anyway it makes
01824             // a load more sense for the very good reason that if you don't believe me
01825             // I'll get my Dad to come around and beat up your dad.
01826 
01827             if (SourceIxCol == NULL)
01828             {
01829                 // It's not an IndexedColour, so can't appear on this plate - make it white
01830                 OutputRGB->Red = OutputRGB->Green = OutputRGB->Blue = 1.0;
01831             }
01832             else
01833             {
01834                 // We have a source IndexedColour, so we know it's been separated.
01835                 // We just have to get a decent ink density value out of the IxCol
01836                 if (SourceIxCol == FilterDescription->GetSpotColour())
01837                 {
01838                     // The spot colour itself is always considered a 100% tint (100% ink)
01839                     OutputRGB->Red = OutputRGB->Green = OutputRGB->Blue = 0.0;
01840                 }
01841                 else if (SourceIxCol->IsADescendantOf(FilterDescription->GetSpotColour()))
01842                 {
01843                     // It's not the spot colour, but it is a child - check that it's a tint
01844                     ERROR3IF(SourceIxCol->GetType() != COLOURTYPE_TINT ||
01845                              SourceIxCol->TintIsShade(),
01846                              "Spot colour children must all be tints!");
01847 
01848                     // Tint gives the amount of ink - we have to inverse this in RGB
01849                     // to get the appropriate grey level. Note that we get the accumulated
01850                     // tint value rather than the simple tint, which is the true output ink
01851                     // density.
01852                     OutputRGB->Red = OutputRGB->Green = OutputRGB->Blue =
01853                                             1.0 - SourceIxCol->GetAccumulatedTintValue();
01854                 }
01855             }
01856 
01857             // If negative, then photographically invert the colour
01858             if (FilterDescription->IsNegative())
01859             {
01860                 OutputRGB->Red   = 1.0 - OutputRGB->Red;
01861                 OutputRGB->Green = 1.0 - OutputRGB->Green;
01862                 OutputRGB->Blue  = 1.0 - OutputRGB->Blue;
01863             }
01864             break;
01865 
01866         case COLOURPLATE_COMPOSITE:
01867 #ifndef NO_XARACMS
01868             // Go to and from (printer) cmyk just for a laugh.
01869             // (NOTE that ConvertColourBase won't actually call us in this case any more)
01870             if (SourceIxCol != NULL && SourceIxCol->GetColourModel() == COLOURMODEL_CMYK)
01871             {
01872                 // If it's a CMYK colour, then it's already in printer gamut, so we only apply
01873                 // the backward colour correction factor to it.
01874                 // Note that this means we chuck away the entire colour conversion result!
01875                 XaraCMS* lpCMSMan = GetApplication()->GetCMSManager();
01876                 if (lpCMSMan != NULL)
01877                 {
01878                     ColourCMYK Def;
01879                     SourceIxCol->GetSourceColour((ColourGeneric *) &Def);
01880 
01881                     lpCMSMan->ConvertColourForPaperView(&Def, OutputRGB);
01882                 }
01883             }
01884             else
01885             {
01886                 // If it's a non-CMYK colour, then we go to and from printer gamut just for a laugh
01887                 // Find the CMS manager, and get it to do all the work
01888                 XaraCMS* lpCMSMan = GetApplication()->GetCMSManager();
01889                 if (lpCMSMan != NULL)
01890                     lpCMSMan->ConvertColourForPaperView(OutputRGB);
01891             }
01892 #endif
01893             // ... drop through to the default case to apply monochrome/negate
01894 
01895         default:
01896             // If monochrome, convert the image to a greyscale
01897             if (FilterDescription->IsMonochrome())
01898             {
01899                 FIXED24 temp = (OutputRGB->Red * 0.305) + (OutputRGB->Green * 0.586) + (OutputRGB->Blue * 0.109);
01900                 OutputRGB->Red = OutputRGB->Green = OutputRGB->Blue = temp;
01901             }
01902 
01903             // If negative, then photographically invert the colour
01904             if (FilterDescription->IsNegative())
01905             {
01906                 OutputRGB->Red   = 1.0 - OutputRGB->Red;
01907                 OutputRGB->Green = 1.0 - OutputRGB->Green;
01908                 OutputRGB->Blue  = 1.0 - OutputRGB->Blue;
01909             }
01910             break;
01911     }
01912 
01913 // And un-define our macro again to make sure it's not used out of its scope
01914 #undef GETCOLOURINCMYK
01915 }
01916 
01917 
01918 
01919 /********************************************************************************************
01920 
01921 >   virtual void ColourContextRGBT::GetWhite(ColourGeneric *Result);
01922 
01923     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01924     Created:    8/6/96
01925 
01926     Outputs:    Result - Will be filled in with White, however that is defined in
01927                 this context's colour model. (i.e. RGB(1,1,1) or CMYK(0,0,0,0), etc)
01928 
01929     Purpose:    An easy way to get a colour definition in this colour model which
01930                 is white (paper colour).
01931 
01932 ********************************************************************************************/
01933 
01934 void ColourContextRGBT::GetWhite(ColourGeneric *Result)
01935 {
01936     ColourRGBT *rgb = (ColourRGBT *) Result;
01937     rgb->Red = rgb->Green = rgb->Blue = 1.0;
01938     rgb->Transparent = 0;
01939 }
01940 
01941 
01942 
01943 
01944 
01945 
01946 
01947 
01948 
01949 
01950 /********************************************************************************************
01951 
01952 >   void ColourContextCMYK::ColourContextCMYK(View *Scope)
01953 
01954     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01955     Created:    14/04/94
01956     Inputs:     Scope - The view in which this context is to be used, or NULL
01957     Outputs:    -
01958     Returns:    -
01959     Purpose:    Constructor for a "logical" CMYK Colour context
01960 
01961                 A logical context represents an "ideal" CMYK printer. This is used
01962                 internally when converting colours between logical colour models,
01963                 and only used externally when no printer device profile is available.
01964 
01965     Notes:      Colour Contexts should not be created and used directly. See the
01966                 notes in the SeeAlso's for instructions on proper care and use.
01967 
01968     Errors:     -
01969     SeeAlso:    ColourContext::ColourContext; ColourContextList::AddContext
01970 
01971 ********************************************************************************************/
01972 
01973 ColourContextCMYK::ColourContextCMYK(View *Scope)
01974                   : ColourContext(Scope)
01975 {
01976     ColModel = COLOURMODEL_CMYK;
01977     CreateExternalTransform();
01978 }
01979 
01980 
01981 
01982 /********************************************************************************************
01983 
01984 >   void ColourContextCMYK::ColourContextCMYK(View *Scope, StringBase *ProfileName)
01985 
01986     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01987     Created:    6/6/96
01988     Inputs:     Scope - The view in which this context is to be used, or NULL
01989                 ProfileName - A string indicating the XaraCMS device profile which
01990                 describes the printer device this context represents
01991     Outputs:    -
01992     Returns:    -
01993     Purpose:    Constructor for a CMYK Colour context
01994 
01995     Notes:      Colour Contexts should not be created and used directly. See the
01996                 notes in the SeeAlso's for instructions on proper care and use.
01997 
01998                 XaraCMS::GetPrinterProfile() can be used to find the default printer
01999                 profile name.
02000 
02001     Errors:     -
02002     SeeAlso:    ColourContext::ColourContext; ColourContextList::AddContext
02003 
02004 ********************************************************************************************/
02005 
02006 ColourContextCMYK::ColourContextCMYK(View *Scope, StringBase *NewProfileName)
02007                   : ColourContext(Scope)
02008 {
02009     ColModel = COLOURMODEL_CMYK;
02010 
02011     if (NewProfileName == NULL)
02012     {
02013         ERROR3("Illegal NULL param");
02014         ProfileName.Empty();
02015     }
02016     else
02017         ProfileName = *NewProfileName;
02018 
02019     CreateExternalTransform();
02020 }
02021 
02022 
02023 
02024 /********************************************************************************************
02025 
02026 >   void ColourContextCMYK::CreateExternalTransform(void)
02027 
02028     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
02029     Created:    12/05/96
02030     Inputs:     -
02031     Returns:    -
02032     Purpose:    Create an external transform to be used during colour conversions from
02033                 CMYK to the current RCS space. This function uses the Winoil CMS Manager
02034                 to create the transform. Both forward and backward transforms use a physical
02035                 printer profile description.
02036 
02037 ********************************************************************************************/
02038 
02039 void ColourContextCMYK::CreateExternalTransform()
02040 {
02041 #ifndef NO_XARACMS
02042     XaraCMS* lpCMSMan = GetApplication()->GetCMSManager();
02043 
02044     // If we have a CMS and we are not a logical context, set up a transform
02045     if (lpCMSMan != NULL && !ProfileName.IsEmpty())
02046     {
02047         TCHAR* pProfile = (TCHAR*)ProfileName;
02048 
02049         // set this as the active colour profile
02050         UINT32 err = lpCMSMan->SetProfile(ptPrinter, pProfile);
02051 
02052         // if we haven't got an error, create that transform
02053         if (err==0)
02054             CMSTransform = lpCMSMan->CreateTransform(PRINT_RCS);
02055     }
02056 #endif
02057 }
02058 
02059 
02060 
02061 /********************************************************************************************
02062 
02063 >   void ColourContextCMYK::ConvertToCIET(ColourGeneric *Source, DColourCIET *Result)
02064 
02065     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02066     Created:    31/03/94
02067     Inputs:     Source - A Colour defined in this CMYK context
02068                 Result - pointer to a structure to recieve the resulting colour as
02069                 defined in CIE space
02070     Outputs:    -
02071     Returns:    -
02072     Purpose:    Converts the given colour from our CMYK colourspace to CIET colourspace
02073 
02074     Notes:      -
02075     Errors:     -
02076     SeeAlso:    ColourContextCMYK::ConvertFromCIET
02077 
02078 ********************************************************************************************/
02079 
02080 void ColourContextCMYK::ConvertToCIET(ColourGeneric *Source, DColourCIET *Result)
02081 {
02082     ENSURE(UsageCount > 0, "Colour context being used when not initialised!");
02083 
02084     ColourCMYK *bob = (ColourCMYK *) Source;
02085 
02086 #ifndef NO_XARACMS
02087     // If we've got a CMS manager, use it, else use the version 1.1 bodge
02088     XaraCMS* lpCMSMan = GetApplication()->GetCMSManager();
02089 
02090     if (lpCMSMan != NULL)
02091     {
02092         // The new colour calibration method
02093         CMSColour icol, ocol;
02094         icol.c0 = bob->Cyan.MakeDouble();
02095         icol.c1 = bob->Magenta.MakeDouble();
02096         icol.c2 = bob->Yellow.MakeDouble();
02097         icol.c3 = bob->Key.MakeDouble();
02098 
02099         // If we have no colour transform, or if we don't want the colour corrected/separated,
02100         // then we will just do a "logical" conversion.
02101         if (CMSTransform == NULL || (ColPlate != NULL && ColPlate->IsDisabled()))
02102             lpCMSMan->ConvCMYKtoCIEXYZ(icol, ocol);
02103         else
02104             lpCMSMan->GTransform(CMSTransform, cmsForward, icol, ocol);
02105 
02106         Result->X = ocol.c0;
02107         Result->Y = ocol.c1;
02108         Result->Z = ocol.c2;
02109     }
02110     else
02111 #endif
02112     {
02113         // The old rgb method
02114         Result->X = ( 1.0 - ( min( 1.0, ( bob->Cyan    + bob->Key ).MakeDouble() ) ) ); // R
02115         Result->Y = ( 1.0 - ( min( 1.0, ( bob->Magenta + bob->Key ).MakeDouble() ) ) ); // G
02116         Result->Z = ( 1.0 - ( min( 1.0, ( bob->Yellow  + bob->Key ).MakeDouble() ) ) ); // B
02117     }
02118 
02119     Result->Transparent = 0.0;              // CMYK values are not transparent
02120 }
02121 
02122 
02123 
02124 
02125 /********************************************************************************************
02126 
02127 >   void ColourContextCMYK::ConvertFromCIET(DColourCIET *Source, ColourGeneric *Result)
02128 
02129     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02130     Created:    14/04/94
02131     Inputs:     Source - A Colour defined in the CIET colourspace
02132                 Result - pointer to a structure to recieve the resulting colour as
02133                 defined in the CMYK space described by this colour context.
02134     Outputs:    -
02135     Returns:    -
02136     Purpose:    Converts the given colour to our CMYK colourspace from CIET colourspace
02137     Notes:      -
02138     Errors:     -
02139     SeeAlso:    ColourContextCMYK::ConvertToCIET
02140 
02141 ********************************************************************************************/
02142 
02143 void ColourContextCMYK::ConvertFromCIET(DColourCIET *Source, ColourGeneric *Result)
02144 {
02145     ENSURE(UsageCount > 0, "Colour context being used when not initialised!");
02146 
02147     ColourCMYK *cmyk = (ColourCMYK *) Result;
02148 
02149 #ifndef NO_XARACMS
02150     // If we've got a CMS manager, use it, else use the version 1.1 bodge
02151     XaraCMS* lpCMSMan = GetApplication()->GetCMSManager();
02152 
02153     if (lpCMSMan != NULL)
02154     {
02155         // The new colour calibration method
02156         CMSColour icol, ocol;
02157         icol.c0 = Source->X;
02158         icol.c1 = Source->Y;
02159         icol.c2 = Source->Z;
02160 
02161         // If we have no colour transform, or if we don't want the colour corrected/separated,
02162         // then we will just do a "logical" conversion.
02163         if (CMSTransform == NULL || (ColPlate != NULL && ColPlate->IsDisabled()))
02164             lpCMSMan->ConvCIEXYZtoCMYK(icol, ocol);
02165         else            
02166             lpCMSMan->GTransform(CMSTransform, cmsReverse, icol, ocol);
02167         
02168         cmyk->Cyan   = FIXED24(ocol.c0);
02169         cmyk->Magenta= FIXED24(ocol.c1);
02170         cmyk->Yellow = FIXED24(ocol.c2);
02171         cmyk->Key    = FIXED24(ocol.c3);
02172 
02173 /*
02174 #ifdef _DEBUG
02175         {
02176         // Check that the colour will round-trip from CIE to CMYK and back to CIE correctly
02177             DColourCIET temp;
02178             ConvertToCIET(Result, &temp);
02179             INT32 t1 = (INT32)(Source->X*1000.0);
02180             INT32 t2 = (INT32)(Source->Y*1000.0);
02181             INT32 t3 = (INT32)(Source->Z*1000.0);
02182             INT32 t4 = (INT32)INT32(temp.X*1000.0);
02183             INT32 t5 = (INT32)INT32(temp.Y*1000.0);
02184             INT32 t6 = (INT32)INT32(temp.Z*1000.0);
02185             CMSColour orgb, orgb2;
02186             lpCMSMan->ConvCIEXYZtoRGB(icol, orgb);
02187             if (t1==t4 && t2==t5 && t3==t6)
02188             {
02189                 TRACE( _T("CIE-CMYK-CIE roundtrip OK   : RGB(%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f,%.3f)\n"), orgb.c0, orgb.c1, orgb.c2, ocol.c0, ocol.c1, ocol.c2, ocol.c3);
02190             }
02191             else
02192             {
02193                 TRACE( _T("CIE-CMYK-CIE roundtrip error: RGB(%.3f,%.3f,%.3f) (%.3f,%.3f,%.3f,%.3f)\n"), orgb.c0, orgb.c1, orgb.c2, ocol.c0, ocol.c1, ocol.c2, ocol.c3);
02194                 TRACE( _T("                              CIEIn[%d,%d,%d] CIEOut[%d,%d,%d]\n"), t1, t2, t3, t4, t5, t6);
02195             }
02196 
02197 //          ERROR3IF((INT32)(temp.X*1000.0)!=(INT32)(Source->X*1000.0) ||
02198 //                  (INT32)(temp.Y*1000.0)!=(INT32)(Source->Y*1000.0) ||
02199 //                  (INT32)(temp.Z*1000.0)!=(INT32)(Source->Z*1000.0),
02200 //                  "CMYK does not round-trip!");
02201         }
02202 #endif
02203 */
02204 
02205     }
02206     else
02207 #endif
02208     {
02209         // The old rgb method
02210         ColourRGBT rgb;
02211         rgb.Red   = FIXED24(Source->X);
02212         rgb.Green = FIXED24(Source->Y);
02213         rgb.Blue  = FIXED24(Source->Z);
02214 
02215         // If all components are 0 then we know it's BLACK.
02216         if (rgb.Red <= 0 && rgb.Green <= 0 && rgb.Blue <= 0)
02217         {
02218             cmyk->Cyan = cmyk->Magenta = cmyk->Yellow = 0;
02219             cmyk->Key  = 1.0;
02220         }
02221         else
02222         {
02223             // Invert the Colour Vector
02224             cmyk->Cyan    = 1.0 - rgb.Red;
02225             cmyk->Magenta = 1.0 - rgb.Green;
02226             cmyk->Yellow  = 1.0 - rgb.Blue;
02227             
02228             double smallest;
02229             
02230             smallest = min(cmyk->Cyan.MakeDouble(), cmyk->Magenta.MakeDouble());    
02231             smallest = min(smallest, cmyk->Yellow.MakeDouble());
02232             smallest = max(smallest-0.5, 0.0);
02233 
02234             // Key starts being generated beyond threshold
02235             cmyk->Key = smallest;
02236 
02237             // Subtract KEY component.
02238             cmyk->Cyan    -= cmyk->Key;
02239             cmyk->Magenta -= cmyk->Key;
02240             cmyk->Yellow  -= cmyk->Key;
02241         }
02242     }
02243 }
02244 
02245 
02246 
02247 /********************************************************************************************
02248 
02249 >   BOOL ColourContextCMYK::GetProfileTables(BYTE* Tables)
02250 
02251     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
02252     Created:    14/04/94
02253     Inputs:     Tables = a byte pointer to a 5*256 byte buffer
02254     Outputs:    TRUE if the Tables buffer has been filled
02255                 FALSE otherwise.
02256     Purpose:    Uses the CMSManager to extract the profile data from our current CMSTransform
02257 
02258 ********************************************************************************************/
02259 
02260 BOOL ColourContextCMYK::GetProfileTables(BYTE* Tables)
02261 {
02262 PORTNOTE("other","Removed HCMTRANSFORM usage")
02263 #ifndef EXCLUDE_FROM_XARALX
02264     if (CMSTransform==NULL)
02265         return FALSE;
02266 #endif
02267 
02268 #ifdef NO_XARACMS
02269     return FALSE;
02270 #else
02271     XaraCMS* lpCMSMan = GetApplication()->GetCMSManager();
02272     if (lpCMSMan==NULL)
02273         return FALSE;
02274 
02275     return lpCMSMan->GetProfileTables(CMSTransform, Tables);
02276 #endif
02277 }
02278 
02279 
02280 
02281 /********************************************************************************************
02282 
02283 >   void ColourContextCMYK::GetModelName(StringBase *Result)
02284 
02285     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02286     Created:    1/6/94
02287     Inputs:     -
02288     Outputs:    Result returns continaing a String of the name of the context.
02289                 This string is guaranteed to fit within a String_32 - this is the
02290                 minimum size you should allocate. (Most names, in English at least,
02291                 are shorter than this (10 chars max, e.g. 'RGB' 'HSV' 'Greyscale')
02292                 so allow at least 10 chars of space in your displays as well)
02293     Returns:    -
02294     Purpose:    Returns the name of this context's colour model
02295     Notes:      
02296 
02297 ********************************************************************************************/
02298 
02299 void ColourContextCMYK::GetModelName(StringBase *Result)
02300 {
02301     ENSURE(Result != NULL, "ColourContext::GetModelName called with NULL result pointer!");
02302 
02303     *Result = String_32(_R(IDS_COLMODEL_CMYK));
02304 }
02305 
02306 
02307 
02308 /********************************************************************************************
02309 
02310 >   BOOL ColourContextCMYK::GetComponentName(INT32 ComponentID, StringBase *Result,
02311                                              BOOL LongName = FALSE)
02312 
02313     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02314     Created:    26/7/94
02315     Inputs:     ComponentID - Index [1..4] of the component you want the name of
02316                 (Result is an output)
02317                 LongName - TRUE to get the long name, FALSE to get the short name
02318                             (e.g. "Magenta" vs "M", "Saturation" vs "Sat")
02319 
02320     Outputs:    Result returns containing a String of the name of the given component
02321                 of colours defined in this context.
02322                 This string is guaranteed to fit within a String_32 - this is the
02323                 minimum size you should allocate. (Most names, in English at least,
02324                 are shorter than this (10 chars max, e.g. 'Red' 'Hue' 'Saturation')
02325                 so allow at least 10 chars of space in your displays as well)
02326 
02327                 Note that Result can be passed in NULL in order to only determine if the
02328                 context supports a given component.
02329 
02330     Returns:    FALSE if this component is not used by this model.
02331     Purpose:    Returns the name of one of this context's colour components
02332 
02333     Notes:      The components are given in the same order as they appear in the
02334                 high-precision ColourXYZ structures defined in colmodel.h
02335 
02336 ********************************************************************************************/
02337 
02338 BOOL ColourContextCMYK::GetComponentName(INT32 ComponentID, StringBase *Result, BOOL LongName)
02339 {
02340     UINT32 StringID = 0;
02341     BOOL Used = TRUE;
02342 
02343     switch(ComponentID)
02344     {
02345         case 1:
02346             StringID = (LongName) ? _R(IDS_COLCOMPL_CYAN) : _R(IDS_COLCOMP_CYAN);
02347             break;
02348             
02349         case 2:
02350             StringID = (LongName) ? _R(IDS_COLCOMPL_MAGENTA) : _R(IDS_COLCOMP_MAGENTA);
02351             break;
02352 
02353         case 3:
02354             StringID = (LongName) ? _R(IDS_COLCOMPL_YELLOW) : _R(IDS_COLCOMP_YELLOW);
02355             break;
02356 
02357         default:
02358             StringID = (LongName) ? _R(IDS_COLCOMPL_KEY) : _R(IDS_COLCOMP_KEY);
02359             break;
02360     }
02361 
02362     if (Result != NULL && StringID != 0)
02363         *Result = String_32(StringID);
02364 
02365     return(Used);
02366 }
02367 
02368 
02369 /********************************************************************************************
02370 
02371 >   virtual UnitGroup **ColourContextCMYK::GetComponentUnitGroups()
02372 
02373     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
02374     Created:    02/05/96          
02375     Inputs:     -
02376     Outputs:    -
02377     Returns:    A pointer to the UnitGroup array
02378     Purpose:    Provides an array of UnitGroups primarily for use by the base class 
02379                 (ColourContext) members Set/GetComponentUnitGroup().
02380     Errors:     -
02381     See Also:   ColourContext::GetComponentUnitGroup()
02382                 ColourContext::SetComponentUnitGroup()
02383 
02384 ********************************************************************************************/
02385 
02386 UnitGroup **ColourContextCMYK::GetComponentUnitGroups()
02387 {
02388     return m_pUnitGroupArray;
02389 }
02390 
02391 
02392 UnitGroup* ColourContextCMYK::m_pUnitGroupArray[] =
02393 {
02394     &(StandardUnit::PercentGroup),
02395     &(StandardUnit::PercentGroup),
02396     &(StandardUnit::PercentGroup),
02397     &(StandardUnit::PercentGroup)
02398 };
02399 
02400 
02401 
02402 /********************************************************************************************
02403 
02404 >   UINT32 ColourContextCMYK::GetComponentCount()
02405 
02406     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
02407     Created:    02/05/96          
02408     Returns:    The number of components
02409     Purpose:    Provides number of components in the colour context's colour model
02410 
02411 ********************************************************************************************/
02412 
02413 UINT32 ColourContextCMYK::GetComponentCount()
02414 {
02415     return MAX_COMPONENTS;
02416 }
02417 
02418 
02419 
02420 /********************************************************************************************
02421 
02422 >   virtual void ColourContextCMYK::ApplyTint(ColourValue TintFraction,
02423                                                 ColourGeneric *SourceAndResult)
02424 
02425     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02426     Created:    17/11/94
02427     Inputs:     TintFraction - The fraction (as a FIXED24 ColourValue) by which the colour
02428                 should be tinted. This value is expected to lie between 0.0 and 1.0 inclusive
02429 
02430                 SourceAndResult - The source colour to be tinted, as defined in this
02431                 colour model
02432 
02433     Outputs:    SourceAndResult is tinted by the given TintFraction
02434                 If TintFraction <= 0.0, White is output
02435                 If TintFraction >= 1.0, The source colour is output
02436 
02437     Returns:    -
02438     Purpose:    Tints a colour (mixes it with white)
02439 
02440     Notes:      If the tinting value is out of range, either source-colour ow white (as
02441                 appropriate) will be output.
02442 
02443 ********************************************************************************************/
02444 
02445 void ColourContextCMYK::ApplyTint(ColourValue TintFraction, ColourGeneric *SourceAndResult)
02446 {
02447     ColourCMYK *Result = (ColourCMYK *) SourceAndResult;
02448     
02449     if (TintFraction <= FIXED24(0.0))       // 0% tint = White
02450     {
02451         Result->Cyan = Result->Magenta = Result->Yellow = Result->Key = 0;
02452         return;
02453     }
02454 
02455     if (TintFraction >= FIXED24(1.0))       // The Result colour is identical to the source
02456         return;
02457 
02458     // Otherwise, tint the colour...
02459     Result->Cyan    = (Result->Cyan    * TintFraction);
02460     Result->Magenta = (Result->Magenta * TintFraction);
02461     Result->Yellow  = (Result->Yellow  * TintFraction);
02462     Result->Key     = (Result->Key     * TintFraction);
02463 }
02464 
02465 
02466 
02467 /********************************************************************************************
02468 
02469 >   void ColourContextCMYK::ApplyShade(ColourValue XFraction, ColourValue YFraction,
02470                                                 ColourGeneric *SourceAndResult)
02471 
02472     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02473     Created:    24/8/95
02474     Inputs:     XFraction - The fraction (as a FIXED24 ColourValue) by which the colour
02475                 should be saturated. This value is expected to lie between -1.0 and 1.0 inclusive
02476                 Values below 0.0 mean tint towards 0, while values above mean tint towards 1.
02477                 0.0 means no tinting
02478 
02479                 YFraction - The fraction (as a FIXED24 ColourValue) by which the colour
02480                 should be shaded. This value is expected to lie between -1.0 and 1.0 inclusive
02481                 Values below 0.0 mean shade towards 0, while values above mean shade towards 1.
02482                 0.0 means no shading
02483 
02484                 SourceAndResult - The source colour to be tinted, as defined in this
02485                 colour model
02486 
02487     Outputs:    SourceAndResult is shaded by the given Fractions
02488                 Any invalid value is clipped to 0.0
02489 
02490     Returns:    -
02491     Purpose:    Shades a colour (tweaks the saturation and value in a relative way)
02492 
02493     Notes:      Contexts other than HSV currently convert the colour to and from HSV
02494                 form in order to apply the shade. This is a tad inefficient, but a
02495                 quick'n'easy bodge that will get it going nice and quickly.
02496 
02497 ********************************************************************************************/
02498 
02499 void ColourContextCMYK::ApplyShade(ColourValue XFraction, ColourValue YFraction,
02500                                     ColourGeneric *SourceAndResult)
02501 {
02502     ColourHSVT HSVDef;
02503     ColourContext *cc = ColourContext::GetGlobalDefault(COLOURMODEL_HSVT);
02504     ERROR3IF(cc == NULL, "No default HSV colour context?!");
02505 
02506     cc->ConvertColour(this, SourceAndResult, (ColourGeneric *) &HSVDef);
02507     cc->ApplyShade(XFraction, YFraction,  (ColourGeneric *) &HSVDef);
02508     ConvertColour(cc, (ColourGeneric *) &HSVDef, SourceAndResult);
02509 }
02510 
02511 
02512 
02513 /********************************************************************************************
02514 
02515 >   virtual void ColourContextCMYK::ApplyInputFilter(ColourPlate *FilterDescription,
02516                                                     ColourContext *DestContext,
02517                                                     ColourGeneric *OutputColour,
02518                                                     IndexedColour *SourceIxCol);
02519 
02520     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02521     Created:    22/1/96
02522     Inputs:     FilterDescription - A ColourPlate describing how the colour is to be filtered
02523     
02524                 DestContext - Points to the context to which the OutputColour will be
02525                 converted after we return it (in case this information is useful)
02526 
02527                 OutputColour - The colour to be filtered
02528 
02529                 SourceIxCol - NULL, or the original IndexedColour which is being converted.
02530                 This is used for handling spot colour separation correctly.
02531 
02532     Outputs:    OutputColour - Will be modified as appropriate to the current colour
02533                 filtering options (see Purpose)
02534 
02535     Purpose:    All colour conversions call this function for the SOURCE context
02536                 immediately before converting the colour. This gives the input colour
02537                 context the chance to apply a filtering process to the colour.
02538 
02539                 This is usually used to provide colour separations. Often, this function
02540                 will do nothing to the output colour - generally it is only used by CMYK
02541                 contexts in order to colour-separate the colour in CMYK space.
02542 
02543     SeeAlso:    ColourContext::ConvertColourBase
02544 
02545 ********************************************************************************************/
02546 
02547 void ColourContextCMYK::ApplyInputFilter(ColourPlate *FilterDescription, ColourContext *DestContext,
02548                                             ColourGeneric *OutputColour, IndexedColour *SourceIxCol)
02549 {
02550     ERROR3IF(FilterDescription == NULL || DestContext == NULL || OutputColour == NULL, "Illegal NULL params");
02551 
02552     if (FilterDescription == NULL)
02553         return;
02554 
02555     ColourCMYK *OutputCMYK = (ColourCMYK *)OutputColour;
02556     FIXED24 temp;
02557 
02558     // Separate the colour as appropriate
02559     switch(FilterDescription->GetType())
02560     {
02561         case COLOURPLATE_CYAN:
02562             {
02563                 if (FilterDescription->IsNegative())        // Negate the plate if necessary
02564                     OutputCMYK->Cyan = 1.0 - OutputCMYK->Cyan;
02565 
02566                 if (FilterDescription->IsMonochrome())      // Make the plate a greyscale if necessary
02567                 {
02568                     OutputCMYK->Key = OutputCMYK->Cyan;
02569                     OutputCMYK->Cyan = OutputCMYK->Magenta = OutputCMYK->Yellow = 0.0;
02570                 }
02571                 else
02572                     OutputCMYK->Key = OutputCMYK->Magenta = OutputCMYK->Yellow = 0.0;
02573             }
02574             break;
02575 
02576         case COLOURPLATE_MAGENTA:
02577             {
02578                 if (FilterDescription->IsNegative())        // Negate the plate if necessary
02579                     OutputCMYK->Magenta = 1.0 - OutputCMYK->Magenta;
02580 
02581                 if (FilterDescription->IsMonochrome())      // Make the plate a greyscale if necessary
02582                 {
02583                     OutputCMYK->Key = OutputCMYK->Magenta;
02584                     OutputCMYK->Cyan = OutputCMYK->Magenta = OutputCMYK->Yellow = 0.0;
02585                 }
02586                 else
02587                     OutputCMYK->Key = OutputCMYK->Cyan = OutputCMYK->Yellow = 0.0;
02588             }
02589             break;
02590 
02591         case COLOURPLATE_YELLOW:
02592             {
02593                 if (FilterDescription->IsNegative())        // Negate the plate if necessary
02594                     OutputCMYK->Yellow = 1.0 - OutputCMYK->Yellow;
02595 
02596                 if (FilterDescription->IsMonochrome())      // Make the plate a greyscale if necessary
02597                 {
02598                     OutputCMYK->Key = OutputCMYK->Yellow;
02599                     OutputCMYK->Cyan = OutputCMYK->Magenta = OutputCMYK->Yellow = 0.0;
02600                 }
02601                 else
02602                     OutputCMYK->Key = OutputCMYK->Magenta = OutputCMYK->Cyan = 0.0;
02603             }
02604             break;
02605 
02606         case COLOURPLATE_KEY:
02607             {
02608                 OutputCMYK->Cyan = OutputCMYK->Magenta = OutputCMYK->Yellow = 0.0;
02609 
02610                 // The FilterDescription->IsMonochrome() flag has no effect on this plate!
02611 
02612                 if (FilterDescription->IsNegative())
02613                     OutputCMYK->Key = 1.0 - OutputCMYK->Key;
02614             }
02615             break;
02616 
02617             case COLOURPLATE_SPOT:
02618                 // NOTE:
02619                 // Real spot colours are generally sorted out by the higher level ConvertColour
02620                 // calls. However, 2 cases may seep through to this level:
02621                 // 1)   Colours which are not indexed colours (which can't be spots, so are always
02622                 //      just converted to white)
02623                 // 2)   Spot colours which *do* appear on this plate must be made into monochrome
02624                 //      ink density values (which we put into the Key component).
02625 
02626                 // In all cases, we're going monochrome in the Key only, so clear C/M/Y now.
02627                 OutputCMYK->Cyan = OutputCMYK->Magenta = OutputCMYK->Yellow = 0;
02628                 if (SourceIxCol == NULL)
02629                 {
02630                     // It's not an IndexedColour, so can't appear on this plate - make it white
02631                     OutputCMYK->Key = 0;
02632                 }
02633                 else
02634                 {
02635                     // We have a source IndexedColour, so we know it's been separated.
02636                     // We just have to get a decent ink density value out of the IxCol
02637                     if (SourceIxCol == FilterDescription->GetSpotColour())
02638                     {
02639                         // The spot colour itself is always considered a 100% tint (100% ink)
02640                         OutputCMYK->Key = 1.0;
02641                     }
02642                     else if (SourceIxCol->IsADescendantOf(FilterDescription->GetSpotColour()))
02643                     {
02644                         // It's not the spot colour, but it is a child - check that it's a tint
02645                         ERROR3IF(SourceIxCol->GetType() != COLOURTYPE_TINT ||
02646                                  SourceIxCol->TintIsShade(),
02647                                  "Spot colour children must all be tints!");
02648 
02649                         // Tint gives the amount of ink, which we stick into the Key plate.
02650                         // Note that we get the accumulated tint value rather than the simple
02651                         // tint, which is the true output ink density.
02652                         OutputCMYK->Key = SourceIxCol->GetAccumulatedTintValue();
02653                     }
02654                 }
02655 
02656                 // If negative, then photographically invert the colour
02657                 if (FilterDescription->IsNegative())
02658                 {
02659                     OutputCMYK->Cyan = OutputCMYK->Magenta = OutputCMYK->Yellow = 1.0;
02660                     OutputCMYK->Key  = 1.0 - OutputCMYK->Key;
02661                 }
02662                 break;
02663 
02664 //          case COLOURPLATE_COMPOSITE:
02665 //              -- We don't need to do anything here
02666 //              break;
02667 
02668             default:
02669                 // If monochrome, convert the image to a greyscale
02670                 if (FilterDescription->IsMonochrome())
02671                 {
02672                     // It is extremely unlikely that anyone will ever need to do this.
02673                     // (If you want a monochrome preview, you should really use a greyscale ColourContext)
02674                     ERROR3("Unimplemented: Filtering of composite CMYK colour to monochrome!");
02675                 }
02676 
02677                 // If negative, then photographically invert the colour
02678                 if (FilterDescription->IsNegative())
02679                 {
02680                     OutputCMYK->Cyan    = 1.0 - OutputCMYK->Cyan;
02681                     OutputCMYK->Magenta = 1.0 - OutputCMYK->Magenta;
02682                     OutputCMYK->Yellow  = 1.0 - OutputCMYK->Yellow;
02683                     OutputCMYK->Key     = 1.0 - OutputCMYK->Key;
02684                 }
02685                 break;
02686     }   
02687 }
02688 
02689 
02690 
02691 /********************************************************************************************
02692 
02693 >   virtual void ColourContextCMYK::ApplyOutputFilter(ColourPlate *FilterDescription,
02694                                                     ColourContext *SourceContext,
02695                                                     ColourGeneric *OutputColour,
02696                                                     IndexedColour *SourceIxCol)
02697 
02698     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02699     Created:    22/1/96
02700     Inputs:     FilterDescription - A ColourPlate describing how the colour is to be filtered
02701     
02702                 SourceContext - Points to the context from which the OutputColour has just
02703                 been converted. 
02704 
02705                 OutputColour - The colour to be filtered
02706 
02707                 SourceIxCol - NULL, or the IndexedColour which was the source of the colour
02708                 being converted. This is only used for information when preparing spot colour
02709                 separations.
02710 
02711     Outputs:    OutputColour - Will be modified as appropriate to the current colour
02712                 filtering options (see Purpose)
02713 
02714     Purpose:    All colour conversions call this function immediately prior to returning
02715                 the converted colour to the caller. This gives the output colour context
02716                 the chance to apply an output filtering process to the output colour.
02717 
02718                 This is usually used to provide colour separations, and may also be used
02719                 to apply some colour corrections. Often, this function will do nothing
02720                 to the output colour.
02721 
02722     SeeAlso:    ColourContext::ConvertColourBase
02723 
02724 ********************************************************************************************/
02725 
02726 void ColourContextCMYK::ApplyOutputFilter(ColourPlate *FilterDescription, ColourContext *SourceContext,
02727                                             ColourGeneric *OutputColour, IndexedColour *SourceIxCol)
02728 {
02729     ERROR3IF(FilterDescription == NULL || SourceContext == NULL || OutputColour == NULL, "Illegal NULL params");
02730 
02731     // No FilterDescription means no filtering; If the source colour was CMYK, we msutn't filter it
02732     // as the ApplyInputFilter will have dealt with it
02733     if (FilterDescription == NULL || SourceContext->GetColourModel() == COLOURMODEL_CMYK)
02734         return;
02735 
02736     ColourCMYK *OutputCMYK = (ColourCMYK *)OutputColour;
02737     FIXED24 temp;
02738 
02739     // Separate the colour as appropriate
02740     switch(FilterDescription->GetType())
02741     {
02742         case COLOURPLATE_CYAN:
02743             {
02744                 if (FilterDescription->IsNegative())            // Negate the plate if necessary
02745                     OutputCMYK->Cyan = 1.0 - OutputCMYK->Cyan;
02746 
02747                 if (FilterDescription->IsMonochrome())          // Make the plate a greyscale if necessary
02748                 {
02749                     // Move the Cyan value into the Key component
02750                     OutputCMYK->Key = OutputCMYK->Cyan;
02751                     OutputCMYK->Cyan = OutputCMYK->Magenta = OutputCMYK->Yellow = 0.0;
02752                 }
02753                 else
02754                     OutputCMYK->Key = OutputCMYK->Magenta = OutputCMYK->Yellow = 0.0;
02755             }
02756             break;
02757 
02758         case COLOURPLATE_MAGENTA:
02759             {
02760                 if (FilterDescription->IsNegative())            // Negate the plate if necessary
02761                     OutputCMYK->Magenta = 1.0 - OutputCMYK->Magenta;
02762 
02763                 if (FilterDescription->IsMonochrome())          // Make the plate a greyscale if necessary
02764                 {
02765                     // Move the Cyan value into the Key component
02766                     OutputCMYK->Key = OutputCMYK->Magenta;
02767                     OutputCMYK->Cyan = OutputCMYK->Magenta = OutputCMYK->Yellow = 0.0;
02768                 }
02769                 else
02770                     OutputCMYK->Key = OutputCMYK->Cyan = OutputCMYK->Yellow = 0.0;
02771             }
02772             break;
02773 
02774         case COLOURPLATE_YELLOW:
02775             {
02776                 if (FilterDescription->IsNegative())            // Negate the plate if necessary
02777                     OutputCMYK->Yellow = 1.0 - OutputCMYK->Yellow;
02778 
02779                 if (FilterDescription->IsMonochrome())          // Make the plate a greyscale if necessary
02780                 {
02781                     // Move the Cyan value into the Key component
02782                     OutputCMYK->Key = OutputCMYK->Yellow;
02783                     OutputCMYK->Cyan = OutputCMYK->Magenta = OutputCMYK->Yellow = 0.0;
02784                 }
02785                 else
02786                     OutputCMYK->Key = OutputCMYK->Cyan = OutputCMYK->Magenta = 0.0;
02787             }
02788             break;
02789 
02790         case COLOURPLATE_KEY:
02791             {
02792                 if (FilterDescription->IsNegative())            // Negate the plate if necessary
02793                     OutputCMYK->Key = 1.0 - OutputCMYK->Key;
02794 
02795                 // The monochrome flag has no effect on a key plate!
02796                 OutputCMYK->Cyan = OutputCMYK->Magenta = OutputCMYK->Yellow = 0.0;
02797             }
02798             break;
02799 
02800         case COLOURPLATE_SPOT:
02801             // NOTE:
02802             // Spot colours are partially handled by the IndexedColour variants of
02803             // ConvertColour, so will never reach us here if they have been
02804             // eliminated from the plate.
02805             // However, if a spot colour gets this far, we need to generate an ink
02806             // density value for output, as well as applying the negate flag.
02807             //
02808             // Actually, I have decreed that all spot plates will always be monochrome,
02809             // because that makes coding DocColour::Mix much easier, and anyway it makes
02810             // a load more sense for the very good reason that if you don't believe me
02811             // I'll get my Dad to come around and beat up your dad.
02812 
02813             if (SourceIxCol != NULL) // && FilterDescription->IsMonochrome())
02814             {
02815                 if (SourceIxCol == FilterDescription->GetSpotColour())
02816                 {
02817                     // The spot colour itself is always considered a 100% tint (100% ink)
02818                     OutputCMYK->Key = 1.0;
02819                     OutputCMYK->Cyan = OutputCMYK->Magenta = OutputCMYK->Yellow = 0.0;
02820                 }
02821                 else if (SourceIxCol->IsADescendantOf(FilterDescription->GetSpotColour()))
02822                 {
02823                     // It's not the spot colour, but it is a child - check that it's a tint
02824                     ERROR3IF(SourceIxCol->GetType() != COLOURTYPE_TINT ||
02825                              SourceIxCol->TintIsShade(),
02826                              "Spot colour children must all be tints!");
02827 
02828                     // Tint gives the amount of ink. Note that we get the accumlated
02829                     // tint value (true ink density) rather than the simple tint.
02830                     OutputCMYK->Key = SourceIxCol->GetAccumulatedTintValue();
02831                     OutputCMYK->Cyan = OutputCMYK->Magenta = OutputCMYK->Yellow = 0.0;
02832                 }
02833             }
02834 
02835             // If negative, then photographically invert the colour
02836             if (FilterDescription->IsNegative())
02837             {
02838                 OutputCMYK->Cyan    = 1.0 - OutputCMYK->Cyan;
02839                 OutputCMYK->Magenta = 1.0 - OutputCMYK->Magenta;
02840                 OutputCMYK->Yellow  = 1.0 - OutputCMYK->Yellow;
02841                 OutputCMYK->Key     = 1.0 - OutputCMYK->Key;
02842             }
02843             break;
02844 
02845         case COLOURPLATE_COMPOSITE:
02846 #ifndef NO_XARACMS
02847             {
02848 /*
02849                 // Go to and from (printer) cmyk just for a laugh
02850                 // Find the CMS manager, and get it to do all the work
02851                 XaraCMS* lpCMSMan = GetApplication()->GetCMSManager();
02852                 if (lpCMSMan != NULL)
02853                     lpCMSMan->ConvertColourForPaperView(OutputRGB);
02854 */
02855                 ERROR3("Composite preview to a CMYK colour context is barmy!");
02856             }
02857 #endif
02858             // ... drop through to the default case to apply monochrome/negate
02859 
02860         default:
02861             // If monochrome, convert the image to a greyscale
02862             if (FilterDescription->IsMonochrome())
02863             {
02864                 // Will anyone ever need this? It seems unlikely - but we may well get Key coming
02865                 // through here, which is entirely sensible, so we only error if there is colour info.
02866                 ERROR3IF(OutputCMYK->Cyan != 0 || OutputCMYK->Magenta != 0 || OutputCMYK->Yellow != 0,
02867                         "Monochrome output of colour CMYK to CMYK colour context is unimplemented");
02868             }
02869 
02870             // If negative, then photographically invert the colour
02871             if (FilterDescription->IsNegative())
02872             {
02873                 OutputCMYK->Cyan    = 1.0 - OutputCMYK->Cyan;
02874                 OutputCMYK->Magenta = 1.0 - OutputCMYK->Magenta;
02875                 OutputCMYK->Yellow  = 1.0 - OutputCMYK->Yellow;
02876                 OutputCMYK->Key     = 1.0 - OutputCMYK->Key;
02877             }
02878             break;
02879     }
02880 }
02881 
02882 
02883 
02884 /********************************************************************************************
02885 
02886 >   virtual BOOL ColourContextCMYK::IsDifferent(ColourContext *Other) const
02887 
02888     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02889     Created:    6/6/96
02890     Inputs:     Other - a colour context to comapre ourselves to
02891     Outputs:    -
02892     Returns:    TRUE if the other colour context object is different from
02893                 ourself, or TRUE if it is an exactly equivalent context.
02894     Purpose:    Determine if two colour contexts are not exactly equivalent
02895     Errors:     -
02896     SeeAlso:    ColourContext::IsDifferent
02897 
02898 ********************************************************************************************/
02899 
02900 BOOL ColourContextCMYK::IsDifferent(ColourContext *Other) const
02901 {
02902     if (ColourContext::IsDifferent(Other))  // Different on generic ColourContext basis
02903         return(TRUE);
02904 
02905     // These must both be CMYK contexts, so check if they are equivalent
02906     return(ProfileName.IsIdentical(((ColourContextCMYK *)Other)->ProfileName));
02907 }
02908 
02909 
02910 
02911 /********************************************************************************************
02912 
02913 >   virtual void ColourContextCMYK::GetWhite(ColourGeneric *Result);
02914 
02915     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02916     Created:    8/6/96
02917 
02918     Outputs:    Result - Will be filled in with White, however that is defined in
02919                 this context's colour model. (i.e. RGB(1,1,1) or CMYK(0,0,0,0), etc)
02920 
02921     Purpose:    An easy way to get a colour definition in this colour model which
02922                 is white (paper colour).
02923 
02924 ********************************************************************************************/
02925 
02926 void ColourContextCMYK::GetWhite(ColourGeneric *Result)
02927 {
02928     ColourCMYK *cmyk = (ColourCMYK *) Result;
02929     cmyk->Cyan = cmyk->Magenta = cmyk->Yellow = cmyk->Key = 0;
02930 }
02931 
02932 
02933 
02934 /********************************************************************************************
02935 
02936 >   virtual void ColourContextCMYK::ConvertColourBase(ColourContextCMYK *SourceContext,
02937                                         ColourGeneric *Source, ColourGeneric *Result
02938                                         IndexedColour *SourceIxCol = NULL)
02939 
02940     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02941     Created:    31/03/94
02942     Inputs:     SourceContext - The context in which the source is defined 
02943 
02944                 Source - A ColourGeneric to convert
02945 
02946                 Result - A ColourGeneric structure to recieve the resulting converted colour,
02947                 as defined in this ColourContextCMYK.
02948 
02949                 SourceIxCol - NULL, or a pointer to the IndexedColour we are converting.
02950                 This is used only for handling spot colour separations, to determine if
02951                 the colour is a given spot colour or tint thereof.
02952 
02953     Outputs:    Result - will be returned with the converted colour
02954 
02955     Purpose:    SEE ColourContext::ConvertColourbase
02956                 This method is identical to that function, except that it also passes the
02957                 colour directly through (rather than converting to/from CIET) if the source
02958                 and destination contexts are both CMYK (even if they are different contexts,
02959                 CMYK colours are always passed through without colour correction)
02960 
02961     Scope:      private to colcontx.cpp
02962     Errors:     -
02963     SeeAlso:    ColourContextCMYK::ConvertColour
02964 
02965 ********************************************************************************************/
02966 
02967 void ColourContextCMYK::ConvertColourBase(ColourContext *SourceContext,
02968                                         ColourGeneric *Source, ColourGeneric *Result,
02969                                         IndexedColour *SourceIxCol)
02970 {
02971     // Copy the source colour into a temporary variable
02972     ColourGeneric FilteredSource;
02973     memcpy(&FilteredSource, Source, sizeof(ColourGeneric));
02974 
02975     // Call the SourceContext to allow it to pre-filter the colour. This is used to
02976     // provide colour separations and other doody features when converting CMYK colours
02977     // - when converting non-CMYK colours, this is usually done in the OutputFilter (below)
02978     if (ColPlate != NULL && !ColPlate->IsDisabled())
02979         SourceContext->ApplyInputFilter(ColPlate, this, &FilteredSource, SourceIxCol);
02980 
02981     // -----
02982     // Call levels expected:
02983     //  1 inline ConvertColour checks if can satisfy from cache
02984     //  2 function ConvertColourInternal does any short cuts it can, such
02985     //    as CMYK->CMYK passthrough
02986     //  3 Call ConvertColourBase, which
02987     //      a) Checks if in same colour model, and implements passthrough, or
02988     //      b) Converts colour properly via CIET space
02989 
02990     if (SourceContext == this || SourceContext->GetColourModel() == COLOURMODEL_CMYK)
02991     {
02992         // The SourceContext and Destination context are identical, so we can
02993         // just copy the definition directly across.
02994         memcpy(Result, &FilteredSource, sizeof(ColourGeneric));
02995     }
02996     else
02997     {
02998         DColourCIET IntermediateResult;
02999 
03000         SourceContext->ConvertToCIET(&FilteredSource, &IntermediateResult);
03001         ConvertFromCIET(&IntermediateResult, Result);
03002     }
03003 
03004 
03005     // Call the DestinationContext (derived class of this) to apply any output filtering -
03006     // non-CMYK colour conversions will separate the colour (as appropriate) here
03007     if (ColPlate != NULL && !ColPlate->IsDisabled())
03008         ApplyOutputFilter(ColPlate, SourceContext, Result, SourceIxCol);
03009 }
03010 
03011 
03012 
03013 
03014 
03015 
03016 
03017 
03018 
03019 
03020 
03021 
03022 
03023 
03024 
03025 
03026 
03027 
03028 /********************************************************************************************
03029 
03030 >   void ColourContextHSVT::ColourContextHSVT(View *Scope)
03031 
03032     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03033     Created:    22/04/94
03034     Inputs:     Scope - The view in which this context is to be used, or NULL
03035     Outputs:    -
03036     Returns:    -
03037     Purpose:    Constructor for an HSVT Colour context
03038 
03039     Notes:      Colour Contexts should not be created and used directly. See the
03040                 notes in the SeeAlso's for instructions on proper care and use.
03041 
03042     Errors:     -
03043     SeeAlso:    ColourContext::ColourContext; ColourContextList::AddContext
03044 
03045 ********************************************************************************************/
03046 
03047 ColourContextHSVT::ColourContextHSVT(View *Scope)
03048                   : ColourContext(Scope)
03049 {
03050     ColModel = COLOURMODEL_HSVT;
03051 
03052     CreateExternalTransform();
03053 }
03054 
03055 /********************************************************************************************
03056 
03057 >   void ColourContextHSVT::CreateExternalTransform(void)
03058 
03059     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
03060     Created:    12/05/96
03061     Inputs:     -
03062     Returns:    -
03063     Purpose:    Create an external transform to be used during colour conversions from
03064                 HSV to the current RCS space. This function uses the Winoil CMS Manager
03065                 to create the transform. Both forward and backward transforms use a physical
03066                 printer profile description.
03067 
03068 ********************************************************************************************/
03069 
03070 void ColourContextHSVT::CreateExternalTransform()
03071 {
03072 #ifndef NO_XARACMS
03073     CMSColourSpace cmsSpace;
03074     XaraCMS* lpCMSMan = GetApplication()->GetCMSManager();
03075     
03076     if (lpCMSMan != NULL)
03077     {
03078         // first read our internal colour calibration space
03079         lpCMSMan->GetLogicalProfile(&cmsSpace);
03080         // set this as the active colour profile
03081         UINT32 err = lpCMSMan->SetProfile(cmsSpace);
03082         // if we haven't got an error, create that transform
03083         if (err==0)
03084             CMSTransform = lpCMSMan->CreateTransform(DISPLAY_RCS);
03085     }
03086 #endif
03087 }
03088 
03089 
03090 
03091 /********************************************************************************************
03092 
03093 >   void ColourContextHSVT::ConvertToCIET(ColourGeneric *Source, DColourCIET *Result)
03094 
03095     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03096     Created:    22/04/94
03097     Inputs:     Source - A Colour defined in this HSVT context
03098                 Result - pointer to a structure to recieve the resulting colour as
03099                 defined in CIE space
03100     Outputs:    -
03101     Returns:    -
03102     Purpose:    Converts the given colour from our HSVT colourspace to CIET colourspace
03103     Notes:      -
03104     Errors:     -
03105     SeeAlso:    ColourContextHSVT::ConvertFromCIET
03106 
03107 ********************************************************************************************/
03108 
03109 void ColourContextHSVT::ConvertToCIET(ColourGeneric *Source, DColourCIET *Result)
03110 {
03111     ENSURE(UsageCount > 0, "Colour context being used when not initialised!");
03112 
03113     // First, let's convert the HSV into RGB
03114     FIXED24 H,S,V, R,G,B, F, P,Q,T;         // Sorry, I just have to override the style guide here!
03115 
03116     H = ((ColourHSVT *)Source)->Hue;
03117     S = ((ColourHSVT *)Source)->Saturation;
03118     V = ((ColourHSVT *)Source)->Value;
03119 
03120     if (S == FIXED24(0))
03121     {
03122         R = V;
03123         G = V;
03124         B = V;
03125     }
03126     else
03127     {
03128         H *= 6;
03129         INT32 I = H.MakeInt();
03130         F = H - I;
03131         P = V * (1.0 - S);
03132         Q = V * (1.0 - (S * F));
03133         T = V * (1.0 - (S * (1.0 - F)));
03134 
03135         switch (I)
03136         {
03137             case 1:  R = Q; G = V; B = P; break;
03138             case 2:  R = P; G = V; B = T; break;
03139             case 3:  R = P; G = Q; B = V; break;
03140             case 4:  R = T; G = P; B = V; break;
03141             case 5:  R = V; G = P; B = Q; break;
03142             default: R = V; G = T; B = P; break;
03143         }
03144     }
03145 
03146 #ifndef NO_XARACMS
03147     // Now, convert the RGB to CIE
03148     // If we've got a CMS manager, use it, else use the version 1.1 bodge
03149     XaraCMS* lpCMSMan = GetApplication()->GetCMSManager();
03150 
03151     if (lpCMSMan != NULL)
03152     {
03153         // The new colour calibration method
03154         CMSColour icol, ocol;
03155         icol.c0 = R.MakeDouble();
03156         icol.c1 = G.MakeDouble();
03157         icol.c2 = B.MakeDouble();
03158         
03159         // If we have no colour transform, or if we don't want the colour corrected/separated,
03160         // then we will just do a "logical" conversion.
03161         if (CMSTransform == NULL || (ColPlate != NULL && ColPlate->IsDisabled()))
03162             lpCMSMan->ConvRGBtoCIEXYZ(icol, ocol);
03163         else
03164             lpCMSMan->GTransform(CMSTransform, cmsForward, icol, ocol);
03165         
03166         Result->X = ocol.c0;
03167         Result->Y = ocol.c1;
03168         Result->Z = ocol.c2;
03169         Result->Transparent = 0.0;//bob->Transparent;
03170     }
03171     else
03172 #endif
03173     {
03174         // The old rgb system
03175         Result->X = R.MakeDouble();
03176         Result->Y = G.MakeDouble();
03177         Result->Z = B.MakeDouble();
03178         Result->Transparent = 0;//((ColourHSVT *)Source)->Transparent;
03179     }
03180 }
03181 
03182 
03183 
03184 
03185 /********************************************************************************************
03186 
03187 >   void ColourContextHSVT::ConvertFromCIET(DColourCIET *Source, ColourGeneric *Result)
03188 
03189     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03190     Created:    22/04/94
03191     Inputs:     Source - A Colour defined in the CIET colourspace
03192                 Result - pointer to a structure to recieve the resulting colour as
03193                 defined in the HSVT space described by this colour context.
03194     Outputs:    -
03195     Returns:    -
03196     Purpose:    Converts the given colour to our HSVT colourspace from CIET colourspace
03197     Notes:      -
03198     Errors:     -
03199     SeeAlso:    ColourContextHSVT::ConvertToCIET
03200 
03201 ********************************************************************************************/
03202 
03203 void ColourContextHSVT::ConvertFromCIET(DColourCIET *Source, ColourGeneric *Result)
03204 {
03205     ENSURE(UsageCount > 0, "Colour context being used when not initialised!");
03206 
03207     // First, we'll convert from CIE to RGB
03208     double R, G, B;
03209 
03210 #ifndef NO_XARACMS
03211     // If we've got a CMS manager, use it, else use the version 1.1 bodge
03212     XaraCMS* lpCMSMan = GetApplication()->GetCMSManager();
03213 
03214     if (lpCMSMan != NULL)
03215     {
03216         // The new colour calibration method
03217         CMSColour icol, ocol;
03218         icol.c0 = Source->X;
03219         icol.c1 = Source->Y;
03220         icol.c2 = Source->Z;
03221 
03222         // If we have no colour transform, or if we don't want the colour corrected/separated,
03223         // then we will just do a "logical" conversion.
03224         if (CMSTransform == NULL || (ColPlate != NULL && ColPlate->IsDisabled()))
03225             lpCMSMan->ConvCIEXYZtoRGB(icol, ocol);
03226         else
03227             lpCMSMan->GTransform(CMSTransform, cmsReverse, icol, ocol);
03228 
03229         R = ocol.c0;
03230         G = ocol.c1;
03231         B = ocol.c2;
03232     }
03233     else
03234 #endif
03235     {
03236         // The old rgb system
03237         R = Source->X;
03238         G = Source->Y;
03239         B = Source->Z;
03240     }
03241 
03242 
03243     // Now, convert the RGB value into HSV
03244     double Min, Max, Delta, H, S, V;
03245     Min = min(R, G);
03246     Min = min(Min, B);
03247     Max = max(R, G);
03248     Max = max(Max, B);
03249 
03250     V = Max;
03251     Delta = Max - Min;
03252 
03253     if (fabs(Delta) > 0.000001)
03254     {
03255         if (Max > 0.0)
03256             S = Delta / Max;
03257         else
03258             S = 0.0;
03259 
03260         if (R == Max)
03261             H = (G - B) / Delta;
03262         else if (G == Max)
03263             H = 2.0 + (B - R) / Delta;
03264         else
03265             H = 4 + (R - G) / Delta;
03266 
03267 
03268         H = H / 6.0;
03269         if (H < 0.0) H += 1.0;
03270     }
03271     else
03272     {
03273         H = S = 0.0;
03274     }
03275 
03276     ((ColourHSVT *)Result)->Hue         = H;
03277     ((ColourHSVT *)Result)->Saturation  = S;
03278     ((ColourHSVT *)Result)->Value       = V;
03279     ((ColourHSVT *)Result)->Transparent = 0; //Source->Transparent;
03280 }
03281 
03282     
03283 
03284 /********************************************************************************************
03285 
03286 >   virtual void ColourContextHSVT::PackColour(ColourGeneric *Source, ColourPacked *Result)
03287 
03288     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03289     Created:    22/04/94
03290     Inputs:     Source - A ColourHSVT structure defining the colour in the model
03291                 pertaining to this colour context (HSVT)
03292                 Result - A Packed colour structure in the same model, into which the result
03293                 is copied.
03294 
03295     Outputs:    -
03296     Returns:    -
03297     Purpose:    Converts 128-bit colour representation to 32-bit packed form
03298 
03299                 Overrides the base class to provide special packing of HSV colours,
03300                 which use a 9-bit component for packed Hue, and a different component
03301                 ordering within the PColourHSVT structure.
03302 
03303     Scope:      Private (used internally by friend class DocColour)
03304     Errors:     -
03305     SeeAlso:    ColourContextHSVT::UnpackColour
03306 
03307 ********************************************************************************************/
03308 
03309 void ColourContextHSVT::PackColour(ColourGeneric *Source, ColourPacked *Result)
03310 {
03311     PColourHSVT *bob = (PColourHSVT *) Result;
03312 
03313     bob->Hue            = PackColour360(Source->Component1);
03314     bob->Saturation     = PackColour256(Source->Component2);
03315     bob->Value          = PackColour256(Source->Component3);
03316     bob->Transparent    = 0; //PackColour128(Source->Transparent);
03317 }
03318 
03319 
03320 
03321 /********************************************************************************************
03322 
03323 >   virtual void ColourContextHSVT::UnpackColour(ColourPacked *Source, ColourGeneric *Result)
03324 
03325     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03326     Created:    22/04/94
03327     Inputs:     Source - A Packed Colour structure defining the colour in the model
03328                 pertaining to this colour context (HSVT)
03329                 Result - A ColourGeneric structure in the same model, into which the 
03330                 result is copied.
03331     Outputs:    -
03332     Returns:    -
03333     Purpose:    Converts 32-bit packed colour representation to 128-bit form
03334 
03335                 Overrides the base class to provide special packing of HSV colours,
03336                 which use a 9-bit component for packed Hue, and a different component
03337                 ordering within the PColourHSVT structure.
03338 
03339     Scope:      Private (used internally by friend class DocColour)
03340     Errors:     -
03341     SeeAlso:    ColourContextHSVT::PackColour
03342 
03343 ********************************************************************************************/
03344 
03345 void ColourContextHSVT::UnpackColour(ColourPacked *Source, ColourGeneric *Result)
03346 {
03347     PColourHSVT *bob = (PColourHSVT *) Source;
03348 
03349     UnpackColour360(bob->Hue,        &Result->Component1);
03350     UnpackColour256(bob->Saturation, &Result->Component2);
03351     UnpackColour256(bob->Value,      &Result->Component3);
03352     Result->Component4 = 0;//UnpackColour128(bob->Transparent, &Result->Transparent);
03353 }
03354 
03355 
03356 
03357 /********************************************************************************************
03358 
03359 >   void ColourContextHSVT::GetModelName(StringBase *Result)
03360 
03361     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03362     Created:    1/6/94
03363     Inputs:     -
03364     Outputs:    Result returns continaing a String of the name of the context.
03365                 This string is guaranteed to fit within a String_32 - this is the
03366                 minimum size you should allocate. (Most names, in English at least,
03367                 are shorter than this (10 chars max, e.g. 'RGB' 'HSV' 'Greyscale')
03368                 so allow at least 10 chars of space in your displays as well)
03369     Returns:    -
03370     Purpose:    Returns the name of this context's colour model
03371     Notes:      
03372 
03373 ********************************************************************************************/
03374 
03375 void ColourContextHSVT::GetModelName(StringBase *Result)
03376 {
03377     ENSURE(Result != NULL, "ColourContext::GetModelName called with NULL result pointer!");
03378 
03379     *Result = String_32(_R(IDS_COLMODEL_HSVT));
03380 }
03381 
03382 
03383 
03384 /********************************************************************************************
03385 
03386 >   BOOL ColourContextHSVT::GetComponentName(INT32 ComponentID, StringBase *Result,
03387                                              BOOL LongName = FALSE)
03388 
03389     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03390     Created:    26/7/94
03391     Inputs:     ComponentID - Index [1..4] of the component you want the name of
03392                 (Result is an output)
03393                 LongName - TRUE to get the long name, FALSE to get the short name
03394                             (e.g. "Magenta" vs "M", "Saturation" vs "Sat")
03395 
03396     Outputs:    Result returns containing a String of the name of the given component
03397                 of colours defined in this context.
03398                 This string is guaranteed to fit within a String_32 - this is the
03399                 minimum size you should allocate. (Most names, in English at least,
03400                 are shorter than this (10 chars max, e.g. 'Red' 'Hue' 'Saturation')
03401                 so allow at least 10 chars of space in your displays as well)
03402 
03403                 Note that Result can be passed in NULL in order to only determine if the
03404                 context supports a given component.
03405 
03406     Returns:    FALSE if this component is not used by this model.
03407     Purpose:    Returns the name of one of this context's colour components
03408 
03409     Notes:      The components are given in the same order as they appear in the
03410                 high-precision ColourXYZ structures defined in colmodel.h
03411 
03412 ********************************************************************************************/
03413 
03414 BOOL ColourContextHSVT::GetComponentName(INT32 ComponentID, StringBase *Result, BOOL LongName)
03415 {
03416     UINT32 StringID = 0;
03417     BOOL Used = TRUE;
03418 
03419     switch(ComponentID)
03420     {
03421         case 1:
03422             StringID = (LongName) ? _R(IDS_COLCOMPL_HUE) : _R(IDS_COLCOMP_HUE);
03423             break;
03424             
03425         case 2:
03426             StringID = (LongName) ? _R(IDS_COLCOMPL_SATURATION) : _R(IDS_COLCOMP_SATURATION);
03427             break;
03428 
03429         case 3:
03430             StringID = (LongName) ? _R(IDS_COLCOMPL_VALUE) : _R(IDS_COLCOMP_VALUE);
03431             break;
03432 
03433 #ifdef TRANSPARENTCOLOUR
03434         default:
03435             StringID = _R(IDS_COLCOMP_TRANS);
03436             break;
03437 #else
03438         default:
03439             Used = FALSE;
03440             break;
03441 #endif
03442     }
03443 
03444     if (Result != NULL && StringID != 0)
03445         *Result = String_32(StringID);
03446 
03447     return(Used);
03448 }
03449 
03450 
03451 
03452 /********************************************************************************************
03453 
03454 >   virtual UnitGroup **ColourContextHSVT::GetComponentUnitGroups()
03455 
03456     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
03457     Created:    02/05/96          
03458     Inputs:     -
03459     Outputs:    -
03460     Returns:    A pointer to the UnitGroup array
03461     Purpose:    Provides an array of UnitGroups primarily for use by the base class 
03462                 (ColourContext) members Set/GetComponentUnitGroup().
03463     Errors:     -
03464     See Also:   ColourContext::GetComponentUnitGroup()
03465                 ColourContext::SetComponentUnitGroup()
03466 
03467 ********************************************************************************************/
03468 
03469 UnitGroup **ColourContextHSVT::GetComponentUnitGroups()
03470 {
03471     return m_pUnitGroupArray;
03472 }
03473 
03474 
03475 UnitGroup* ColourContextHSVT::m_pUnitGroupArray[] = 
03476 {
03477     &(StandardUnit::AngleGroup),
03478     &(StandardUnit::PercentGroup),
03479     &(StandardUnit::PercentGroup)
03480 };
03481 
03482 
03483 
03484 /********************************************************************************************
03485 
03486 >   virtual UINT32 ColourContextHSVT::GetComponentCount()
03487 
03488     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
03489     Created:    02/05/96          
03490     Returns:    The number of components
03491     Purpose:    Provides number of components in the colour context's colour model
03492 
03493 ********************************************************************************************/
03494 
03495 UINT32 ColourContextHSVT::GetComponentCount()
03496 {
03497     return MAX_COMPONENTS;
03498 }
03499 
03500 
03501 
03502 /********************************************************************************************
03503 
03504 >   virtual void ColourContextHSVT::ApplyTint(ColourValue TintFraction,
03505                                                 ColourGeneric *SourceAndResult)
03506 
03507     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03508     Created:    17/11/94
03509     Inputs:     TintFraction - The fraction (as a FIXED24 ColourValue) by which the colour
03510                 should be tinted. This value is expected to lie between 0.0 and 1.0 inclusive
03511 
03512                 SourceAndResult - The source colour to be tinted, as defined in this
03513                 colour model
03514 
03515     Outputs:    SourceAndResult is tinted by the given TintFraction
03516                 If TintFraction <= 0.0, White is output
03517                 If TintFraction >= 1.0, The source colour is output
03518 
03519     Returns:    -
03520     Purpose:    Tints a colour (mixes it with white)
03521 
03522     Notes:      If the tinting value is out of range, either source-colour ow white (as
03523                 appropriate) will be output.
03524 
03525 ********************************************************************************************/
03526 
03527 void ColourContextHSVT::ApplyTint(ColourValue TintFraction, ColourGeneric *SourceAndResult)
03528 {
03529     ColourHSVT *Result = (ColourHSVT *) SourceAndResult;
03530     
03531     if (TintFraction <= FIXED24(0.0))       // 0% tint = White
03532     {
03533         Result->Saturation = 0;
03534         Result->Value = FIXED24(1.0);
03535         return;
03536     }
03537 
03538     if (TintFraction >= FIXED24(1.0))       // The Result colour is identical to the source
03539         return;
03540 
03541     // Otherwise, tint the colour...
03542     // Hue remains constant
03543     Result->Saturation = Result->Saturation * TintFraction;
03544     Result->Value = FIXED24(1.0) - (TintFraction - (Result->Value * TintFraction));
03545 }
03546 
03547 
03548 
03549 /********************************************************************************************
03550 
03551 >   void ColourContextHSVT::ApplyShade(ColourValue XFraction, ColourValue YFraction,
03552                                                 ColourGeneric *SourceAndResult)
03553 
03554     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03555     Created:    24/8/95
03556     Inputs:     XFraction - The fraction (as a FIXED24 ColourValue) by which the colour
03557                 should be saturated. This value is expected to lie between -1.0 and 1.0 inclusive
03558                 Values below 0.0 mean tint towards 0, while values above mean tint towards 1.
03559                 0.0 means no tinting
03560 
03561                 YFraction - The fraction (as a FIXED24 ColourValue) by which the colour
03562                 should be shaded. This value is expected to lie between -1.0 and 1.0 inclusive
03563                 Values below 0.0 mean shade towards 0, while values above mean shade towards 1.
03564                 0.0 means no shading
03565 
03566                 SourceAndResult - The source colour to be tinted, as defined in this
03567                 colour model
03568 
03569     Outputs:    SourceAndResult is shaded by the given Fractions
03570                 Any invalid value is clipped to 0.0
03571 
03572     Returns:    -
03573     Purpose:    Shades a colour (tweaks the saturation and value in a relative way)
03574 
03575 ********************************************************************************************/
03576 
03577 void ColourContextHSVT::ApplyShade(ColourValue XFraction, ColourValue YFraction,
03578                                     ColourGeneric *SourceAndResult)
03579 {
03580     ColourHSVT *Result = (ColourHSVT *) SourceAndResult;
03581 
03582     ERROR3IF(XFraction < FIXED24(-1.0) || XFraction > FIXED24(1.0), "Illegal X Shading value");
03583     ERROR3IF(YFraction < FIXED24(-1.0) || YFraction > FIXED24(1.0), "Illegal Y Shading value");
03584 
03585     // Adjust the Saturation according to XFraction
03586     if (XFraction != FIXED24(0.0))
03587     {
03588         if (XFraction < FIXED24(0.0))
03589         {
03590             XFraction = -XFraction;
03591             Result->Saturation = Result->Saturation * (FIXED24(1.0) - XFraction);
03592         }
03593         else
03594             Result->Saturation = XFraction + Result->Saturation * (FIXED24(1.0) - XFraction);
03595     }
03596 
03597 
03598     // Adjust the Value according to YFraction
03599     if (YFraction != FIXED24(0.0))
03600     {
03601         if (YFraction < FIXED24(0.0))
03602         {
03603             YFraction = -YFraction;
03604             Result->Value = Result->Value * (FIXED24(1.0) - YFraction);
03605         }
03606         else
03607             Result->Value = YFraction + Result->Value * (FIXED24(1.0) - YFraction);
03608     }
03609 }
03610 
03611 
03612 
03613 /********************************************************************************************
03614 
03615 >   virtual void ColourContextHSVT::GetWhite(ColourGeneric *Result);
03616 
03617     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03618     Created:    8/6/96
03619 
03620     Outputs:    Result - Will be filled in with White, however that is defined in
03621                 this context's colour model. (i.e. RGB(1,1,1) or CMYK(0,0,0,0), etc)
03622 
03623     Purpose:    An easy way to get a colour definition in this colour model which
03624                 is white (paper colour).
03625 
03626 ********************************************************************************************/
03627 
03628 void ColourContextHSVT::GetWhite(ColourGeneric *Result)
03629 {
03630     ColourHSVT *hsvt = (ColourHSVT *) Result;
03631     hsvt->Hue = hsvt->Saturation = 0;
03632     hsvt->Value = 1.0;
03633     hsvt->Transparent = 0;
03634 }
03635 
03636 
03637 
03638 
03639 
03640 
03641 
03642 
03643 
03644 
03645 
03646 
03647 
03648 
03649 
03650 
03651 /********************************************************************************************
03652 
03653 >   void ColourContextGreyT::ColourContextGreyT(View *Scope)
03654 
03655     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03656     Created:    2/6/94
03657     Inputs:     Scope - The view in which this context is to be used, or NULL
03658     Outputs:    -
03659     Returns:    -
03660     Purpose:    Constructor for an GreyT Colour context
03661 
03662     Notes:      Colour Contexts should not be created and used directly. See the
03663                 notes in the SeeAlso's for instructions on proper care and use.
03664 
03665     Errors:     -
03666     SeeAlso:    ColourContext::ColourContext; ColourContextList::AddContext
03667 
03668 ********************************************************************************************/
03669 
03670 ColourContextGreyT::ColourContextGreyT(View *Scope)
03671                   : ColourContext(Scope)
03672 {
03673     ColModel = COLOURMODEL_GREYT;
03674 
03675     CreateExternalTransform();
03676 }
03677 
03678 
03679 
03680 /********************************************************************************************
03681 
03682 >   void ColourContextGreyT::CreateExternalTransform(void)
03683 
03684     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
03685     Created:    12/05/96
03686     Inputs:     -
03687     Returns:    -
03688     Purpose:    Create an external transform to be used during colour conversions from
03689                 Grey to the current RCS space. This function uses the Winoil CMS Manager
03690                 to create the transform. Both forward and backward transforms use logical
03691                 RGB descriptions.
03692 
03693 ********************************************************************************************/
03694 
03695 void ColourContextGreyT::CreateExternalTransform()
03696 {
03697 #ifndef NO_XARACMS
03698     CMSColourSpace cmsSpace;
03699     XaraCMS* lpCMSMan = GetApplication()->GetCMSManager();
03700     
03701     if (lpCMSMan != NULL)
03702     {
03703         // first read our internal colour calibration space
03704         lpCMSMan->GetLogicalProfile(&cmsSpace);
03705 
03706         // set this as the active colour profile
03707         UINT32 err = lpCMSMan->SetProfile(cmsSpace);
03708 
03709         // if we haven't got an error, create that transform
03710         if (err==0)
03711             CMSTransform = lpCMSMan->CreateTransform(DISPLAY_RCS);
03712     }
03713 #endif
03714 }
03715 
03716 
03717 /********************************************************************************************
03718 
03719 >   void ColourContextGreyT::ConvertToCIET(ColourGeneric *Source, DColourCIET *Result)
03720 
03721     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03722     Created:    2/6/94
03723     Inputs:     Source - A Colour defined in this GreyT context
03724                 Result - pointer to a structure to recieve the resulting colour as
03725                 defined in CIE space
03726     Outputs:    -
03727     Returns:    -
03728     Purpose:    Converts the given colour from our GreyT colourspace to CIET colourspace
03729     Notes:      -
03730     Errors:     -
03731     SeeAlso:    ColourContextGreyT::ConvertFromCIET
03732 
03733 ********************************************************************************************/
03734 
03735 void ColourContextGreyT::ConvertToCIET(ColourGeneric *Source, DColourCIET *Result)
03736 {
03737     ENSURE(UsageCount > 0, "Colour context being used when not initialised!");
03738 
03739 #ifndef NO_XARACMS
03740     // If we've got a CMS manager, use it, else use the version 1.1 bodge
03741     XaraCMS* lpCMSMan = GetApplication()->GetCMSManager();
03742 
03743     if (lpCMSMan != NULL)
03744     {
03745         // The new colour calibration method
03746         CMSColour icol, ocol;
03747 
03748         icol.c2 = ((ColourGreyT *)Source)->Intensity.MakeDouble();
03749         icol.c0 = icol.c1 = icol.c2;
03750 
03751         // If we have no colour transform, or if we don't want the colour corrected/separated,
03752         // then we will just do a "logical" conversion.
03753         if (CMSTransform == NULL || (ColPlate != NULL && ColPlate->IsDisabled()))
03754             lpCMSMan->ConvRGBtoCIEXYZ(icol, ocol);
03755         else
03756             lpCMSMan->GTransform(CMSTransform, cmsForward, icol, ocol);
03757 
03758         Result->X = ocol.c0;
03759         Result->Y = ocol.c1;
03760         Result->Z = ocol.c2;
03761     }
03762     else
03763 #endif
03764     {
03765         // The old rgb system
03766         Result->X = Result->Y = Result->Z = ((ColourGreyT *)Source)->Intensity.MakeDouble();
03767     }
03768 
03769     Result->Transparent = 0.0;//((ColourGreyT *)Source)->Transparent;
03770 }
03771 
03772 
03773 
03774 
03775 /********************************************************************************************
03776 
03777 >   void ColourContextGreyT::ConvertFromCIET(DColourCIET *Source, ColourGeneric *Result)
03778 
03779     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03780     Created:    22/04/94
03781     Inputs:     Source - A Colour defined in the CIET colourspace
03782                 Result - pointer to a structure to recieve the resulting colour as
03783                 defined in the GreyT space described by this colour context.
03784     Outputs:    -
03785     Returns:    -
03786     Purpose:    Converts the given colour to our GreyT colourspace from CIET colourspace
03787     Notes:      -
03788     Errors:     -
03789     SeeAlso:    ColourContextGreyT::ConvertToCIET
03790 
03791 ********************************************************************************************/
03792 
03793 void ColourContextGreyT::ConvertFromCIET(DColourCIET *Source, ColourGeneric *Result)
03794 {
03795     ENSURE(UsageCount > 0, "Colour context being used when not initialised!");
03796 
03797 #ifndef NO_XARACMS
03798     // If we've got a CMS manager, use it, else use the version 1.1 bodge
03799     XaraCMS* lpCMSMan = GetApplication()->GetCMSManager();
03800 
03801     if (lpCMSMan != NULL)
03802     {
03803         CMSColour icol, ocol;
03804 
03805         icol.c0 = Source->X;
03806         icol.c1 = Source->Y;
03807         icol.c2 = Source->Z;
03808 
03809         // If we have no colour transform, or if we don't want the colour corrected/separated,
03810         // then we will just do a "logical" conversion.
03811         if (CMSTransform == NULL || (ColPlate != NULL && ColPlate->IsDisabled()))
03812             lpCMSMan->ConvCIEXYZtoRGB(icol, ocol);
03813         else
03814             lpCMSMan->GTransform(CMSTransform, cmsReverse, icol, ocol);
03815 
03816         // The loadings below are taken from Gerry, the expert on colour loadings
03817         // in this particular office. No expense was spared to research these
03818         // values properly... ;-)
03819         double inten;
03820         inten = (ocol.c0 * 0.305) + (ocol.c1 * 0.586) + (ocol.c2 * 0.109);
03821         ((ColourGreyT *)Result)->Intensity = inten;
03822     }
03823     else
03824 #endif
03825     {
03826         double R, G, B;
03827         R = Source->X;
03828         G = Source->Y;
03829         B = Source->Z;
03830 
03831         // The loadings below are taken from Gerry, the expert on colour loadings
03832         // in this particular office. No expense was spared to research these
03833         // values properly... ;-)
03834         ((ColourGreyT *)Result)->Intensity = (R * 0.305) + (G * 0.586) + (B * 0.109);
03835     }
03836 
03837     // Set the transparency field
03838     ((ColourGreyT *)Result)->Transparent = 0;//Source->Transparent;
03839 
03840     // And ensure that the reserved fields are cleared
03841     ((ColourGreyT *)Result)->Reserved1 = ((ColourGreyT *)Result)->Reserved2 = 0;
03842 }
03843 
03844 
03845 
03846 /********************************************************************************************
03847 
03848 >   void ColourContextGreyT::GetModelName(StringBase *Result)
03849 
03850     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03851     Created:    1/6/94
03852     Inputs:     -
03853     Outputs:    Result returns continaing a String of the name of the context.
03854                 This string is guaranteed to fit within a String_32 - this is the
03855                 minimum size you should allocate. (Most names, in English at least,
03856                 are shorter than this (10 chars max, e.g. 'RGB' 'HSV' 'Greyscale')
03857                 so allow at least 10 chars of space in your displays as well)
03858     Returns:    -
03859     Purpose:    Returns the name of this context's colour model
03860     Notes:      
03861 
03862 ********************************************************************************************/
03863 
03864 void ColourContextGreyT::GetModelName(StringBase *Result)
03865 {
03866     ENSURE(Result != NULL, "ColourContext::GetModelName called with NULL result pointer!");
03867 
03868     *Result = String_32(_R(IDS_COLMODEL_GREY));
03869 }
03870 
03871 
03872 
03873 /********************************************************************************************
03874 
03875 >   BOOL ColourContextGreyT::GetComponentName(INT32 ComponentID, StringBase *Result,
03876                                              BOOL LongName = FALSE)
03877 
03878     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03879     Created:    26/7/94
03880     Inputs:     ComponentID - Index [1..4] of the component you want the name of
03881                 (Result is an output)
03882                 LongName - TRUE to get the long name, FALSE to get the short name
03883                             (e.g. "Magenta" vs "M", "Saturation" vs "Sat")
03884 
03885     Outputs:    Result returns containing a String of the name of the given component
03886                 of colours defined in this context.
03887                 This string is guaranteed to fit within a String_32 - this is the
03888                 minimum size you should allocate. (Most names, in English at least,
03889                 are shorter than this (10 chars max, e.g. 'Red' 'Hue' 'Saturation')
03890                 so allow at least 10 chars of space in your displays as well)
03891 
03892                 Note that Result can be passed in NULL in order to only determine if the
03893                 context supports a given component.
03894 
03895     Returns:    FALSE if this component is not used by this model.
03896     Purpose:    Returns the name of one of this context's colour components
03897 
03898     Notes:      The components are given in the same order as they appear in the
03899                 high-precision ColourXYZ structures defined in colmodel.h
03900 
03901 ********************************************************************************************/
03902 
03903 BOOL ColourContextGreyT::GetComponentName(INT32 ComponentID, StringBase *Result, BOOL LongName)
03904 {
03905     UINT32 StringID = 0;
03906     BOOL Used = TRUE;
03907 
03908     switch(ComponentID)
03909     {
03910         case 1:
03911             StringID = (LongName) ? _R(IDS_COLCOMPL_INTENSITY) : _R(IDS_COLCOMP_INTENSITY);
03912             break;
03913             
03914 #ifdef TRANSPARENTCOLOUR
03915         case 2:
03916         case 3:
03917             Used = FALSE;       // These components are not used
03918             break;
03919 
03920         default:
03921             StringID = _R(IDS_COLCOMP_TRANS);
03922             break;
03923 #else
03924         default:
03925             Used = FALSE;
03926             break;
03927 #endif
03928     }
03929 
03930     if (Result != NULL && StringID != 0)
03931         *Result = String_32(StringID);
03932 
03933     return(Used);
03934 }
03935 
03936 
03937 
03938 /********************************************************************************************
03939 
03940 >   virtual UnitGroup **ColourContextGreyT::GetComponentUnitGroups()
03941 
03942     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
03943     Created:    02/05/96          
03944     Inputs:     -
03945     Outputs:    -
03946     Returns:    A pointer to the UnitGroup array
03947     Purpose:    Provides an array of UnitGroups primarily for use by the base class 
03948                 (ColourContext) members Set/GetComponentUnitGroup().
03949     Errors:     -
03950     See Also:   ColourContext::GetComponentUnitGroup()
03951                 ColourContext::SetComponentUnitGroup()
03952 
03953 ********************************************************************************************/
03954 
03955 UnitGroup **ColourContextGreyT::GetComponentUnitGroups()
03956 {
03957     return m_pUnitGroupArray;
03958 }
03959 
03960 
03961 UnitGroup* ColourContextGreyT::m_pUnitGroupArray[] =
03962 {
03963     &(StandardUnit::PercentGroup)
03964 };
03965 
03966 
03967 
03968 /********************************************************************************************
03969 
03970 >   virtual UINT32 ColourContextGreyT::GetComponentCount()
03971 
03972     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
03973     Created:    02/05/96          
03974     Returns:    The number of components
03975     Purpose:    Provides number of components in the colour context's colour model
03976 
03977 ********************************************************************************************/
03978 
03979 UINT32 ColourContextGreyT::GetComponentCount()
03980 {
03981     return MAX_COMPONENTS;
03982 }
03983 
03984 
03985 
03986 /********************************************************************************************
03987 
03988 >   virtual void ColourContextGreyT::ApplyTint(ColourValue TintFraction,
03989                                                 ColourGeneric *SourceAndResult)
03990 
03991     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03992     Created:    17/11/94
03993     Inputs:     TintFraction - The fraction (as a FIXED24 ColourValue) by which the colour
03994                 should be tinted. This value is expected to lie between 0.0 and 1.0 inclusive
03995 
03996                 SourceAndResult - The source colour to be tinted, as defined in this
03997                 colour model
03998 
03999     Outputs:    SourceAndResult is tinted by the given TintFraction
04000                 If TintFraction <= 0.0, White is output
04001                 If TintFraction >= 1.0, The source colour is output
04002 
04003     Returns:    -
04004     Purpose:    Tints a colour (mixes it with white)
04005 
04006     Notes:      If the tinting value is out of range, either source-colour ow white (as
04007                 appropriate) will be output.
04008 
04009 ********************************************************************************************/
04010 
04011 void ColourContextGreyT::ApplyTint(ColourValue TintFraction, ColourGeneric *SourceAndResult)
04012 {
04013     ColourGreyT *Result = (ColourGreyT *) SourceAndResult;
04014     
04015     if (TintFraction <= FIXED24(0.0))       // 0% tint = White
04016     {
04017         Result->Intensity = FIXED24(1.0);
04018         return;
04019     }
04020 
04021     if (TintFraction >= FIXED24(1.0))       // The Result colour is identical to the source
04022         return;
04023 
04024     // Otherwise, tint the colour...
04025     Result->Intensity = FIXED24(1.0) - (TintFraction - (Result->Intensity * TintFraction));
04026 }
04027 
04028 
04029 
04030 /********************************************************************************************
04031 
04032 >   void ColourContextGreyT::ApplyShade(ColourValue XFraction, ColourValue YFraction,
04033                                                 ColourGeneric *SourceAndResult)
04034 
04035     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
04036     Created:    24/8/95
04037     Inputs:     XFraction - The fraction (as a FIXED24 ColourValue) by which the colour
04038                 should be saturated. This value is expected to lie between -1.0 and 1.0 inclusive
04039                 Values below 0.0 mean tint towards 0, while values above mean tint towards 1.
04040                 0.0 means no tinting
04041 
04042                 YFraction - The fraction (as a FIXED24 ColourValue) by which the colour
04043                 should be shaded. This value is expected to lie between -1.0 and 1.0 inclusive
04044                 Values below 0.0 mean shade towards 0, while values above mean shade towards 1.
04045                 0.0 means no shading
04046 
04047                 SourceAndResult - The source colour to be tinted, as defined in this
04048                 colour model
04049 
04050     Outputs:    SourceAndResult is shaded by the given Fractions
04051                 Any invalid value is clipped to 0.0
04052 
04053     Returns:    -
04054     Purpose:    Shades a colour (tweaks the saturation and value in a relative way)
04055 
04056     Notes:      Contexts other than HSV currently convert the colour to and from HSV
04057                 form in order to apply the shade. This is a tad inefficient, but a
04058                 quick'n'easy bodge that will get it going nice and quickly.
04059 
04060 ********************************************************************************************/
04061 
04062 void ColourContextGreyT::ApplyShade(ColourValue XFraction, ColourValue YFraction,
04063                                         ColourGeneric *SourceAndResult)
04064 {
04065     ColourHSVT HSVDef;
04066     ColourContext *cc = ColourContext::GetGlobalDefault(COLOURMODEL_HSVT);
04067     ERROR3IF(cc == NULL, "No default HSV colour context?!");
04068 
04069     cc->ConvertColour(this, SourceAndResult, (ColourGeneric *) &HSVDef);
04070     cc->ApplyShade(XFraction, YFraction,  (ColourGeneric *) &HSVDef);
04071     ConvertColour(cc, (ColourGeneric *) &HSVDef, SourceAndResult);
04072 }
04073 
04074 
04075 
04076 /********************************************************************************************
04077 
04078 >   virtual void ColourContextGreyT::GetWhite(ColourGeneric *Result);
04079 
04080     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
04081     Created:    8/6/96
04082 
04083     Outputs:    Result - Will be filled in with White, however that is defined in
04084                 this context's colour model. (i.e. RGB(1,1,1) or CMYK(0,0,0,0), etc)
04085 
04086     Purpose:    An easy way to get a colour definition in this colour model which
04087                 is white (paper colour).
04088 
04089 ********************************************************************************************/
04090 
04091 void ColourContextGreyT::GetWhite(ColourGeneric *Result)
04092 {
04093     ColourGreyT *grey = (ColourGreyT *) Result;
04094     grey->Intensity = 1.0;
04095 
04096     grey->Reserved1 = grey->Reserved2 = grey->Transparent = 0;
04097 }
04098 

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