ai_epsrr.cpp

Go to the documentation of this file.
00001 // $Id: ai_epsrr.cpp 1336 2006-06-17 16:18:41Z alex $
00002 // Implementation of Adobe Illustrator EPS filter.
00003 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00004 ================================XARAHEADERSTART===========================
00005  
00006                Xara LX, a vector drawing and manipulation program.
00007                     Copyright (C) 1993-2006 Xara Group Ltd.
00008        Copyright on certain contributions may be held in joint with their
00009               respective authors. See AUTHORS file for details.
00010 
00011 LICENSE TO USE AND MODIFY SOFTWARE
00012 ----------------------------------
00013 
00014 This file is part of Xara LX.
00015 
00016 Xara LX is free software; you can redistribute it and/or modify it
00017 under the terms of the GNU General Public License version 2 as published
00018 by the Free Software Foundation.
00019 
00020 Xara LX and its component source files are distributed in the hope
00021 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00022 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00023 See the GNU General Public License for more details.
00024 
00025 You should have received a copy of the GNU General Public License along
00026 with Xara LX (see the file GPL in the root directory of the
00027 distribution); if not, write to the Free Software Foundation, Inc., 51
00028 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00029 
00030 
00031 ADDITIONAL RIGHTS
00032 -----------------
00033 
00034 Conditional upon your continuing compliance with the GNU General Public
00035 License described above, Xara Group Ltd grants to you certain additional
00036 rights. 
00037 
00038 The additional rights are to use, modify, and distribute the software
00039 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00040 library and any other such library that any version of Xara LX relased
00041 by Xara Group Ltd requires in order to compile and execute, including
00042 the static linking of that library to XaraLX. In the case of the
00043 "CDraw" library, you may satisfy obligation under the GNU General Public
00044 License to provide source code by providing a binary copy of the library
00045 concerned and a copy of the license accompanying it.
00046 
00047 Nothing in this section restricts any of the rights you have under
00048 the GNU General Public License.
00049 
00050 
00051 SCOPE OF LICENSE
00052 ----------------
00053 
00054 This license applies to this program (XaraLX) and its constituent source
00055 files only, and does not necessarily apply to other Xara products which may
00056 in part share the same code base, and are subject to their own licensing
00057 terms.
00058 
00059 This license does not apply to files in the wxXtra directory, which
00060 are built into a separate library, and are subject to the wxWindows
00061 license contained within that directory in the file "WXXTRA-LICENSE".
00062 
00063 This license does not apply to the binary libraries (if any) within
00064 the "libs" directory, which are subject to a separate license contained
00065 within that directory in the file "LIBS-LICENSE".
00066 
00067 
00068 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00069 ----------------------------------------------
00070 
00071 Subject to the terms of the GNU Public License (see above), you are
00072 free to do whatever you like with your modifications. However, you may
00073 (at your option) wish contribute them to Xara's source tree. You can
00074 find details of how to do this at:
00075   http://www.xaraxtreme.org/developers/
00076 
00077 Prior to contributing your modifications, you will need to complete our
00078 contributor agreement. This can be found at:
00079   http://www.xaraxtreme.org/developers/contribute/
00080 
00081 Please note that Xara will not accept modifications which modify any of
00082 the text between the start and end of this header (marked
00083 XARAHEADERSTART and XARAHEADEREND).
00084 
00085 
00086 MARKS
00087 -----
00088 
00089 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00090 designs are registered or unregistered trademarks, design-marks, and/or
00091 service marks of Xara Group Ltd. All rights in these marks are reserved.
00092 
00093 
00094       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00095                         http://www.xara.com/
00096 
00097 =================================XARAHEADEREND============================
00098  */
00099 
00100 #include "camtypes.h"
00101 
00102 #include "ai_epsrr.h"
00103 
00104 #include <stdio.h>
00105 #include <math.h>
00106 
00107 #include "vectrndr.h"
00108 #include "ccdc.h"
00109 //#include "colmodel.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00110 //#include "fillattr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00111 #include "opbevel.h"
00112 #include "swfexpdc.h"
00113 #include "swfrndr.h"
00114 #include "slicehelper.h"
00115 #include "fillramp.h"
00116 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00117 #include "nodebmp.h"
00118 //#include "bitmap.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00119 //#include "range.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00120 //#include "rendsel.h"
00121 //#include "dibutil.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00122 #include "fontman.h"        // for FontManager - for writing font changes to overflow text
00123 #include "colplate.h"       // for ColourPlate - in overflow text functions
00124 #include "colourix.h"       // for Indexed Colour - for writing colour changes to overflow
00125 #include "nodebev.h"
00126 #include "layer.h"
00127 #include "clipattr.h"
00128 
00129 CC_IMPLEMENT_DYNAMIC(AIEPSRenderRegion, EPSRenderRegion)
00130 
00131 /********************************************************************************************
00132 
00133 >   AIEPSRenderRegion::AIEPSRenderRegion ( DocRect  ClipRect,
00134                                            Matrix   ConvertMatrix,
00135                                            FIXED16  ViewScale )
00136 
00137     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
00138     Created:    29/3/00
00139     Purpose:    Create and initialise a render region for exporting AI EPS. Sets up the
00140                 string to put in the %%Creator comment.
00141     SeeAlso:    EPSRenderRegion::EPSRenderRegion ()
00142 
00143 ********************************************************************************************/
00144 
00145 AIEPSRenderRegion::AIEPSRenderRegion ( DocRect  ClipRect,
00146                                        Matrix   ConvertMatrix,
00147                                        FIXED16  ViewScale )
00148     : EPSRenderRegion ( ClipRect, ConvertMatrix, ViewScale )
00149 {
00150     // Set up member variables.
00151     m_a             = 1;
00152     m_b             = 0;
00153     m_c             = 0;
00154     m_d             = 1;
00155     m_T             = DocCoord ( 0, 0 );
00156     m_ActiveLayer   = FALSE;
00157     m_LayerColour   = 0;
00158 
00159     m_fpOverflowText    = NULL;
00160 
00161     m_bInTextGap        = FALSE;
00162     m_bTextAsShapes     = FALSE;
00163     
00164     m_pLinearGradList   = NULL;
00165     m_pRadialGradList   = NULL;
00166 
00167     // Initialise the creator string to show that it's an AI file.
00168     CreatorString = _T("Adobe Illustrator(TM) 7.0 by Xara.");
00169 }
00170 
00171 /********************************************************************************************
00172 
00173 >   AIEPSRenderRegion::~AIEPSRenderRegion 
00174     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
00175     Created:    30/3/2001
00176     Purpose:    Destructor for an AI render region. All this really does is dispose of the 
00177                 gradient fill cache (if there is one)
00178     SeeAlso:    EPSRenderRegion::EPSRenderRegion ()
00179 
00180 ********************************************************************************************/
00181 AIEPSRenderRegion::~AIEPSRenderRegion ()
00182 {
00183     ClearGradientCache ();
00184 }
00185 
00186 /********************************************************************************************
00187 
00188 >   BOOL AIEPSRenderRegion::ExportBitmap ( NodeBitmap   *pNodeBMP )
00189 
00190     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
00191     Created:    31/3/00
00192     Inputs:     pNodeBMP    - A pointer to the NodeBitmap being exported.
00193     Returns:    TRUE        - If successful.
00194                 FALSE       - If an error is encountered.
00195     Purpose:    Kicks off the NodeBitmap export process..
00196     SeeAlso:    NodeBitmap::ExportRender ()
00197 
00198 ********************************************************************************************/
00199 
00200 BOOL AIEPSRenderRegion::ExportBitmap ( NodeBitmap   *pNodeBMP )
00201 {
00202     // Set up the local variables.
00203     KernelBitmap    *pBitmap    = pNodeBMP->GetBitmap ();
00204 
00205     // Set up the bitmap's transformation matrix.
00206     LoadBitmapMatrix ( pNodeBMP );
00207 
00208     // Write out the bitmap record.
00209     WriteBitmapRecord ( pBitmap->GetActualBitmap () );
00210 
00211     return TRUE;
00212 }
00213 
00214 /********************************************************************************************
00215 
00216 >   BOOL AIEPSRenderRegion::ExportBevel ( NodeBevel *pBevel )
00217 
00218     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
00219     Created:    6/4/00
00220     Inputs:     pBevel  - A pointer to a bevel node.
00221     Returns:    TRUE    - Success.
00222                 FALSE   - An error occured.
00223     Purpose:    Renders a bevel into a DIB, and exports this as a bitmap to the AI file.
00224     SeeAlso:    NodeBevel::ExportRender
00225 
00226 ********************************************************************************************/
00227 
00228 BOOL AIEPSRenderRegion::ExportBevel ( NodeBevel *pBevel )
00229 {
00230     // Set up the local variables.
00231     KernelDC                *pDC            = static_cast<KernelDC *> ( CCDC::ConvertFromNativeDC(RenderDC) );
00232     RangeControl            ControlFlags    ( TRUE, TRUE );
00233     Range                   ToRender        ( pBevel, pBevel, ControlFlags );
00234     KernelBitmap            *pBitmap        = NULL;
00235     Path                    *pSourcePath    = &( pBevel->InkPath );
00236     DocRect                 Bounds          = pBevel->GetBoundingRect ();
00237     DocCoord                Position        ( Bounds.lo.x, Bounds.hi.y );
00238     double                  Width           = static_cast<double> ( Bounds.Width () );
00239     double                  Height          = static_cast<double> ( Bounds.Height () );
00240 
00241     // Create and render the bitmap.
00242     pBitmap = pBevel->CreateBitmapCopy(-1.0,FALSE);
00243 
00244     if(!pBitmap)
00245         return FALSE;
00246 
00247     // Get the width and height of the bitmap.
00248     double                  BMPWidth        = static_cast<double> ( pBitmap->GetWidth () );
00249     double                  BMPHeight       = static_cast<double> ( pBitmap->GetHeight () );
00250 
00251     // Write the path. (ChrisG 16/01/01) If we have one.
00252     if (pSourcePath->GetNumCoords () != 0)
00253     {
00254         WriteMask ( pSourcePath, TRUE );
00255     }
00256 
00257     // Set up the bitmap translation matrix.
00258     LoadTranslationMatrix ( Position );
00259 
00260     // Scale width and height to be valid value for AI co-ordinates.
00261     Width   /= 1000;
00262     Height  /= 1000;
00263     
00264     // And calcuate the scale values for placing the bitmap.
00265     m_a = Width  / BMPWidth;
00266     m_d = Height / BMPHeight;
00267 
00268     // Write the bitmap record.
00269     WriteBitmapRecord ( pBitmap->ActualBitmap );
00270 
00271     // Write the end of mask operator. (ChrisG 16/01/01) If we've written a mask.
00272     if (pSourcePath->GetNumCoords () != 0)
00273     {
00274         pDC->OutputToken    ( _T("Q") );
00275         pDC->OutputNewLine  ();
00276     }
00277 
00278     if(pBitmap)
00279     {
00280         pBitmap->DestroyGreyscaleVersion();
00281         delete pBitmap;
00282     }
00283 
00284     // Success!
00285     return TRUE;
00286 }
00287 
00288 /********************************************************************************************
00289 
00290 >   BOOL AIEPSRenderRegion::ExportShadow ( OILBitmap    *pBitmap,
00291                                            UINT32           Darkness,
00292                                            DocRect      &Bounds )
00293 
00294     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
00295     Created:    11/4/00
00296     Inputs:     pShadow - A pointer to a shadow node.
00297     Returns:    TRUE    - Success.
00298                 FALSE   - An error occured.
00299     Purpose:    Renders a shadow into a DIB, and exports this as a bitmap to the AI file.
00300     SeeAlso:    NodeBevel::ExportRender
00301 
00302 ********************************************************************************************/
00303 
00304 BOOL AIEPSRenderRegion::ExportShadow ( OILBitmap    *pBitmap,
00305                                        UINT32           Darkness,
00306                                        DocRect      &Bounds )
00307 {
00308     // Set up the local variables.
00309 //  KernelDC *pDC = (KernelDC*)CCDC::ConvertFromNativeDC(RenderDC);
00310     DocCoord    Position        ( Bounds.lo.x, Bounds.hi.y );
00311     double      Width           = static_cast<double> ( Bounds.Width () ) / 1000;
00312     double      Height          = static_cast<double> ( Bounds.Height () ) / 1000;
00313     double      BMPWidth        = static_cast<double> ( pBitmap->GetWidth () );
00314     double      BMPHeight       = static_cast<double> ( pBitmap->GetHeight () );
00315     DocColour   ShadowColour    = *( static_cast<FillGeometryAttribute*>
00316                                      ( GetCurrentAttribute ( ATTR_FILLGEOMETRY ) )
00317                                      ->GetStartColour () );
00318     DocColour   BlendedShadow   = AlphaBlend ( ShadowColour, mBackgroundColour, Darkness );
00319 
00320     // And use the shadow colour to build a contone bitmap palette.
00321     pBitmap->BuildContonePalette ( BlendedShadow, mBackgroundColour, EFFECT_RGB,
00322                                    RenderView );
00323 
00324     // Set up the bitmap translation matrix.
00325     LoadTranslationMatrix ( Position );
00326     
00327     // And calcuate the scale values for placing the bitmap.
00328     m_a = Width  / BMPWidth;
00329     m_d = Height / BMPHeight;
00330 
00331     // Write out the bitmap header.
00332     WriteBitmapHeader ( (INT32)BMPWidth, (INT32)BMPHeight );
00333 
00334     // Export the bitmap.
00335     WriteContoneBody ( pBitmap );
00336 
00337     // Finish off the bitmap record.
00338     WriteBitmapTail ();
00339 
00340     return TRUE;
00341 }
00342 
00343 /********************************************************************************************
00344 
00345 >   BOOL AIEPSRenderRegion::ExportLayer ( Layer *pLayer )
00346 
00347     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
00348     Created:    11/4/00
00349     Inputs:     pLayer  - A pointer to a layer object.
00350     Returns:    TRUE    - Success.
00351                 FALSE   - An error occured.
00352     Purpose:    If there is an existing layer, it writes the end of layer tags, before
00353                 creating a new layer record.
00354     SeeAlso:    AIEPSRenderRegion::EndLayer ()
00355 
00356 ********************************************************************************************/
00357 
00358 BOOL AIEPSRenderRegion::ExportLayer ( Layer *pLayer )
00359 {
00360     // Tidy up the existing layer, if it exists.
00361     EndLayer ();
00362 
00363     // And write out the next layer.
00364     return StartLayer ( static_cast<Layer*> ( pLayer->FindNext
00365                                               ( CC_RUNTIME_CLASS ( Layer ) ) ) );
00366 }
00367 
00368 /********************************************************************************************
00369 
00370 >   BOOL AIEPSRenderRegion::StartLayer ( Layer  *pLayer )
00371 
00372     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
00373     Created:    11/4/00
00374     Inputs:     pLayer  - A pointer to a layer object.
00375     Returns:    TRUE    - Success.
00376                 FALSE   - An error occured.
00377     Purpose:    Writes a layer record to the file.
00378     SeeAlso:    AIEPSRenderRegion::EndLayer ()
00379 
00380 ********************************************************************************************/
00381 
00382 BOOL AIEPSRenderRegion::StartLayer ( Layer  *pLayer )
00383 {
00384     // Catch null pointers to layers.
00385     if ( pLayer != NULL )
00386     {
00387         KernelDC    *pDC            = static_cast<KernelDC *> ( CCDC::ConvertFromNativeDC(RenderDC) );
00388         TCHAR       LayerName [258];
00389 
00390         // Set up the layer's name.
00391         camSprintf ( LayerName, _T("(%s)"), ( TCHAR* ) pLayer->GetLayerID () );
00392 
00393         // Start a layer definition.
00394         pDC->OutputToken    ( _T("%AI5_BeginLayer") );
00395         pDC->OutputNewLine  ();
00396 
00397         // Set the layer's properties.
00398         pDC->OutputValue    ( ( UINT32 ) pLayer->IsVisible () );    // Is the layer visible?
00399         pDC->OutputValue    ( ( UINT32 ) 1 );                   // Is the layer previewed?
00400         pDC->OutputValue    ( ( UINT32 ) !pLayer->IsLocked () );    // Is the layer enabled?
00401         pDC->OutputValue    ( ( UINT32 ) pLayer->IsPrintable () );//Is the layer printable?
00402         pDC->OutputValue    ( ( UINT32 ) 0 );                   // Is the layer dimmed?
00403         pDC->OutputValue    ( ( UINT32 ) 0 );                   // No multilayer masks.
00404 
00405         // The ID colour.
00406         pDC->OutputValue    ( ( UINT32 ) m_LayerColour % 27 );  // Set the layer's ID colour.
00407         m_LayerColour ++;                                       // Increment colour ID.
00408 
00409         // Colour values - I don't know what they're used for.
00410         pDC->OutputValue    ( ( UINT32 ) 0 );                   // Red intensity.
00411         pDC->OutputValue    ( ( UINT32 ) 0 );                   // Blue intensity.
00412         pDC->OutputValue    ( ( UINT32 ) 0 );                   // Green intensity.
00413 
00414         // Write out the Lb tag.
00415         pDC->OutputToken    ( _T("Lb") );
00416         pDC->OutputNewLine  ();
00417 
00418         // Set the layer's name.
00419         pDC->OutputToken    ( LayerName );
00420         pDC->OutputToken    ( _T("Ln") );
00421         pDC->OutputNewLine  ();
00422 
00423         // Tell Camelot that there is an active layer.
00424         m_ActiveLayer = TRUE;
00425     }
00426 
00427     // Success!
00428     return TRUE;
00429 }
00430 
00431 /********************************************************************************************
00432 
00433 >   void AIEPSRenderRegion::RenderChar (WCHAR ch, Matrix * pMatrix)
00434 
00435     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
00436     Created:    1/11/00
00437     Purpose:    Overrides the default behaviour for rendering a single character. Used to 
00438                 store additional information on text blocks needed for AI text. i.e. the
00439                 overflow text block ((xxxxxxxxx) TX) which occurs after the unjustified 
00440                 ((x) Tx\n (x) Tx\n) block. Both of these are needed for correct Illustrator
00441                 export of text.
00442     SeeAlso:    EPSRenderRegion::RenderChar
00443 
00444 ********************************************************************************************/
00445 
00446 BOOL AIEPSRenderRegion::RenderChar(WCHAR ch, Matrix* pMatrix)
00447 {
00448     TCHAR buf[20];
00449     BOOL result = FALSE;        // assume failure if nothing given.
00450 
00451     if (m_bTextAsShapes)
00452     {
00453         result = RenderCharAsShape (ch, pMatrix);
00454     }
00455     else
00456     {
00457         // Output matrix (a b c d e f Tm\n) - a,b,c and d are in the range 1.0 to -1.0
00458         // Only do this for text on paths
00459         if (ExportingOnPath ())
00460         {
00461             KernelDC *pDC = (KernelDC*)CCDC::ConvertFromNativeDC(RenderDC);
00462 
00463             pDC->OutputMatrix(pMatrix);
00464             pDC->OutputToken(_T("Tm"));
00465             pDC->OutputNewLine();
00466         }
00467 
00468         // call the base class first, so that the attributes are exported BEFORE the character
00469         result = EPSRenderRegion::RenderChar (ch, pMatrix);;
00470         
00471             // store any extra information, closing an attribute gap if one is open.
00472         if (ExportingOnPath ())
00473         {
00474             OverflowTextFinishGap ();
00475             camSprintf (buf,_T("%c"),ch);
00476             OverflowTextWrite (buf);
00477         }
00478     }
00479         // Call the base class' function to do the standard export.
00480     return result;
00481 }
00482 
00483 
00484 /********************************************************************************************
00485 
00486 >   void AIEPSRenderRegion::RenderCharAsShape (WCHAR ch, Matrix * pMatrix)
00487 
00488     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
00489     Created:    1/11/00
00490     Purpose:    Allows text to be drawn as shapes, not characters, so that AI can cope
00491                 with gradient filled text.
00492     SeeAlso:    AIEPSRenderRegion::RenderChar, EPSRenderRegion::RenderChar
00493 
00494 ********************************************************************************************/
00495 
00496 BOOL AIEPSRenderRegion::RenderCharAsShape (WCHAR ch, Matrix* pMatrix)
00497 {
00498     BOOL result = FALSE;
00499 
00500     // create the char's path
00501     Path* pCharPath=CreateCharPath(ch,pMatrix);
00502 
00503     // if the path got created correctly, then we done good...
00504     if (pCharPath!=NULL)
00505     {
00506         // if at least one point, draw path using current attibutes in render region
00507         if (pCharPath->GetNumCoords()!=0)
00508             DrawPath(pCharPath);
00509 
00510         // clean up
00511         delete pCharPath;
00512 
00513         result = TRUE;
00514     }
00515 
00516     return result;
00517 }
00518 
00519 /********************************************************************************************
00520 
00521 >   void AIEPSRenderRegion::Initialise()
00522 
00523     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
00524     Created:    29/3/00
00525     Purpose:    Sets up render region - it outputs the AIEPS file header comments, and
00526                 intialises the rendering attributes.
00527     SeeAlso:    EPSRenderRegion::Initialise, EPSRenderRegion::InitAttributes
00528 
00529 ********************************************************************************************/
00530 
00531 void AIEPSRenderRegion::Initialise()
00532 {
00533     // Set up member variables.
00534     m_a             = 1;
00535     m_b             = 0;
00536     m_c             = 0;
00537     m_d             = 1;
00538     m_T             = DocCoord ( 0, 0 );
00539     m_ActiveLayer   = FALSE;
00540     m_LayerColour   = 0;
00541 
00542     ClearGradientCache ();
00543 
00544     // Call the EPSRenderRegion method to re-enter the export loop.
00545     EPSRenderRegion::InitAttributes ();
00546 }
00547 
00548 /********************************************************************************************
00549 
00550 >   BOOL AIEPSRenderRegion::WriteEPSVersion ( void )
00551 
00552     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
00553     Created:    28/3/000
00554     Inputs:     pDC - The device context to output to.
00555     Returns:    TRUE if ok;
00556                 FALSE if error (e.g. file/disk error or printer driver error)
00557     Purpose:    Writes the relevant EPS version declaration.
00558     SeeAlso:    EPSRenderRegion::WriteEPSVersion
00559 
00560 ********************************************************************************************/
00561 
00562 BOOL AIEPSRenderRegion::WriteEPSVersion ( void )
00563 {
00564     // Cast the pointer to an appropriate DC.
00565     KernelDC *pDC = static_cast<KernelDC *> ( CCDC::ConvertFromNativeDC(RenderDC) );
00566 
00567     // Output the special AIEPS header start token.
00568     pDC->OutputToken    ( _T("%!PS-Adobe-3.0") );
00569     pDC->OutputNewLine  ();
00570 
00571     return TRUE;
00572 }
00573 
00574 /********************************************************************************************
00575 
00576 >   BOOL AIEPSRenderRegion::WriteEPSProcessColours ( void )
00577 
00578     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
00579     Created:    28/3/000
00580     Inputs:     pDC - The device context to output to.
00581     Returns:    TRUE if ok;
00582                 FALSE if error (e.g. file/disk error or printer driver error)
00583     Purpose:    Writes the colour type used to disk.
00584     SeeAlso:    EPSRenderRegion::WriteEPSProcessColours
00585 
00586 ********************************************************************************************/
00587 
00588 BOOL AIEPSRenderRegion::WriteEPSProcessColours ( void )
00589 {
00590     // Cast a pointer to the appropriate DC.
00591     KernelDC *pDC = (KernelDC*)CCDC::ConvertFromNativeDC(RenderDC);
00592 
00593     // Output the process colours
00594     pDC->OutputToken    ( _T("%%DocumentProcessColors: Cyan Magenta Yellow Black") );
00595     pDC->OutputNewLine  ();
00596 
00597     return TRUE;
00598 }
00599 
00600 /********************************************************************************************
00601 
00602 >   BOOL AIEPSRenderRegion::WriteEPSResources ( EPSFilter   *pFilter,
00603                                                 Document    *pDocument )
00604 
00605     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
00606     Created:    28/3/00
00607     Inputs:     pDC - The device context to output to.
00608     Returns:    TRUE if ok;
00609                 FALSE if error (e.g. file/disk error or printer driver error)
00610     Purpose:    This function writes out the resource inclusion string required for the AI
00611                 file.
00612     SeeAlso:    EPSRenderRegion::WriteSetup
00613 
00614 ********************************************************************************************/
00615 
00616 BOOL AIEPSRenderRegion::WriteEPSResources ( EPSFilter   *pFilter,
00617                                             Document    *pDocument )
00618 {
00619     // Cast a pointer to the appropriate DC.
00620     KernelDC *pDC = (KernelDC*)CCDC::ConvertFromNativeDC(RenderDC);
00621     
00622     // Call the export method in the document.
00623     pDocument->WriteEPSResources ( pFilter );
00624 
00625     // Add a few things necessary for the AI file format.
00626     pDC->OutputToken    ( _T("%AI3_ColorUsage: Color") );
00627     pDC->OutputNewLine  ();
00628     pDC->OutputToken    ( _T("%AI5_FileFormat 2.0") );
00629     pDC->OutputNewLine  ();
00630 
00631     // All done.
00632     return TRUE;
00633 }
00634 
00635 /********************************************************************************************
00636 
00637 >   BOOL AIEPSRenderRegion::WriteEPSProlog ( EPSFilter  *pFilter,
00638                                              Document   *pDocument )
00639 
00640     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
00641     Created:    28/3/00
00642     Inputs:     pDC - The device context to output to.
00643     Returns:    TRUE if ok;
00644                 FALSE if error (e.g. file/disk error or printer driver error)
00645     Purpose:    This method writes out the initialisation code for the included resources.
00646     SeeAlso:    EPSRenderRegion::WriteSetup
00647 
00648 ********************************************************************************************/
00649 
00650 BOOL AIEPSRenderRegion::WriteEPSProlog ( EPSFilter  *pFilter,
00651                                          Document   *pDocument )
00652 {
00653     // Call the export method in the document.
00654     pDocument->WriteEPSProlog ( pFilter );
00655 
00656     // All done.
00657     return TRUE;
00658 }
00659 
00660 /********************************************************************************************
00661 
00662 >   virtual BOOL AIEPSRenderRegion::WriteGradientFills ( Document *pDocument )
00663 
00664     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
00665     Created:    1/3/00
00666     Inputs:     pDocument - The document to be written.
00667     Outputs:    -
00668     Returns:    TRUE if successful.
00669                 FALSE if error (e.g. file/disk error)
00670     Purpose:    Parses through the tree, identifies any gradient fills, and writes them to
00671                 the export DC's file.
00672 
00673 ********************************************************************************************/
00674 
00675 BOOL AIEPSRenderRegion::WriteGradientFills ( Document *pDocument )
00676 {
00677     // Get the spread from the document.
00678     Spread      *pSpread        = pDocument->FindFirstSpread ();
00679 
00680     // Build the gradient cache up from all the fills under the spread, after cleaning any 
00681     //  junk out of it (there shouldn't be any there, but that ain't the point)
00682     ClearGradientCache ();
00683     BuildGradientCache (pSpread);
00684 
00685     // Write out the number of fills and their definition.
00686     WriteGradientCount ();
00687     WriteGradientDefinitions ();
00688 
00689     // The fill has been successfully saved, so return TRUE.
00690     return TRUE;
00691 }
00692 
00693 /********************************************************************************************
00694 
00695 >   BOOL AIEPSRenderRegion::WriteLinearFill ( FillGeometryAttribute *pFill, INT32 id )
00696 
00697     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
00698     Created:    1/3/00
00699     Inputs:     pFill   - A pointer to the fill attribute record.
00700                 id      - the id number for the fill
00701     Returns:    TRUE    - If successful.
00702                 FALSE   - The was an error (e.g. file/disk error).
00703     Purpose:    Writes a linear fill to the disk file.
00704 
00705 ********************************************************************************************/
00706 
00707 BOOL AIEPSRenderRegion::WriteLinearFill ( FillGeometryAttribute * pFill, EFFECTTYPE effect, INT32 id )
00708 {
00709     // Extract the fill attribute - this is necessary for processing the fill type.
00710     KernelDC                *pDC                = static_cast<KernelDC *> ( CCDC::ConvertFromNativeDC(RenderDC) );
00711     INT32                       Colours             = 2;
00712     TCHAR                   GradientName [32];
00713     DocColour               StartColour         = *( pFill->GetStartColour () );
00714     DocColour               EndColour;
00715     ColourRamp              *pRamp              = pFill->GetColourRamp ();
00716 
00717     // The fill is, or can be approximated by, a linear fill.
00718     camSprintf ( GradientName, _T("(%s %d)"), LinearGradient, id );
00719 
00720     // (ChrisG 16/01/01) Four colour fill MUST come first, as it's derived from Three
00721     //  colour fill, and returns valid for IsThreeColFill().
00722     if ( pFill->IsAFourColFill () )
00723     {
00724         // I'm going to use a version of the below here, but for now I'll just
00725         // set up the end colour as the most distant end colour.
00726         EndColour   = *( pFill->GetEndColour3 () );
00727     }
00728     else if ( pFill->IsAThreeColFill () )
00729     {
00730         // AI doesn't support three colour fills, so I'm going to fake it. This
00731         // code merges the two end colours to approximate the fill with a two
00732         // colour linear fill.
00733         EndColour.Mix ( pFill->GetEndColour (), pFill->GetEndColour2(),
00734                         0.5f, NULL, FALSE, NULL );
00735     }
00736     else
00737     {
00738         // Set up the end colour value appropriately.
00739         EndColour   = *( pFill->GetEndColour () );
00740     }
00741 
00742     // Count the number of colours.
00743     if ( pRamp != NULL )
00744     {
00745         UINT32  First   = 0;
00746         UINT32  Last    = 0;
00747 
00748         // Extract the indices from the colour ramp.
00749         pRamp->GetIndexRange ( &First, &Last );
00750 
00751         // And add their difference to the colour count. Note, you need to add one
00752         // to the result so that you don't register having no colours. There really
00753         // should be a count number of elements method in the ramp code, though.
00754         Colours += 1 + Last - First;
00755     }
00756 
00757     // (ChrisG 15/01/01) If this is a four colour fill, since we will be adding a mid-colour
00758     //  below, then we need to include it in the definition
00759     if (pFill->IsAFourColFill ())
00760     {
00761         Colours ++;
00762     }
00763 
00764     // (ChrisG 4/4/2001) Add in the extra colours given from the HSV fill effect emulation
00765     if (effect == EFFECT_HSV_SHORT || effect == EFFECT_HSV_LONG)
00766     {
00767         Colours += (Colours - 1) * NumFillEmulationSteps;
00768     }
00769 
00770     // Write the gradient's header.
00771     pDC->OutputToken    ( _T("%AI5_BeginGradient:") );
00772     pDC->OutputToken    ( GradientName );
00773     pDC->OutputNewLine  ();
00774 
00775     // Then the type definition.
00776     pDC->OutputToken    ( GradientName );
00777     pDC->OutputValue    ( static_cast<INT32> ( LinearFill ) );
00778     pDC->OutputValue    ( static_cast<INT32> ( Colours ) );
00779     pDC->OutputToken    ( _T("Bd") );
00780     pDC->OutputNewLine  ();
00781     pDC->OutputToken    ( _T("[") );
00782     pDC->OutputNewLine  ();
00783 
00784     // (ChrisG 3/4/2001) Get bias and convert to 0-100 range (from -1 to +1)
00785     //  This will be used later on to offset the positions
00786     CProfileBiasGain profile = pFill->GetProfile ();
00787     INT32 bias = (INT32) ((1 - (double) profile.GetBias ()) * 50);
00788 
00789     // Write out the last colour.
00790     WriteGradientEntry ( &EndColour, 100, 50 );
00791 
00792     // set up the last colour and position (for the fill effect emulation.
00793     DocColour * pLastColour = &EndColour;
00794     INT32 lastPos = 100;
00795 
00796     // Mid colour for four colour fills - this needs to be stored longer so that it can be
00797     //  re-used in the case of HSV fill effects.
00798     DocColour   MidColour;
00799 
00800     // If the fill is a four colour fill, add a mid-colour that's a blend of the
00801     // second and third colours.
00802     if ( pFill->IsAFourColFill () )
00803     {
00804 
00805         MidColour.Mix ( pFill->GetEndColour (), pFill->GetEndColour2 (),
00806                         0.5f, NULL, FALSE, NULL );
00807 
00808         // Write out the extra fill steps, if there are any.
00809         if (effect != EFFECT_RGB)
00810         {
00811             WriteFillEffectSteps (pLastColour, lastPos, &MidColour, 50, bias, effect);
00812             pLastColour = &MidColour;
00813         }
00814 
00815         // And set the value.
00816         WriteGradientEntry ( &MidColour, 50, bias);
00817     }
00818 
00819     // Otherwise, process the colour ramp.
00820     else if ( pRamp != NULL )
00821     {
00822         ColRampItem *pItem = pRamp->GetLastCol ();
00823 
00824         // Write in the ramp's colour values.
00825         while ( pItem != NULL )
00826         {
00827             // Get the position of the colour in the fill.
00828             INT32       Ratio   = static_cast <INT32> ( 100 * pItem->GetPosition () );
00829             DocColour   *pCol   = pItem->GetColourAddr ();
00830 
00831             // Write out the extra fill steps, if there are any.
00832             if (effect != EFFECT_RGB)
00833             {
00834                 WriteFillEffectSteps (pLastColour, lastPos, pCol, Ratio, bias, effect);
00835                 pLastColour = pCol;
00836                 lastPos = Ratio;
00837             }
00838 
00839             // And set the value.
00840             WriteGradientEntry ( pCol, Ratio, 50 );
00841 
00842             // Increment the pointer onto the next item.
00843             pItem = pRamp->GetPrevCol ( pItem );
00844         }
00845     }
00846 
00847     // Write out the extra fill steps, if there are any.
00848     if (effect != EFFECT_RGB)
00849     {
00850         WriteFillEffectSteps (pLastColour, lastPos, &StartColour, 0, bias, effect);
00851     }
00852 
00853     // Write out the start colour.
00854     WriteGradientEntry ( &StartColour, 0, bias );
00855 
00856     // Write out the end of gradient tokens.
00857     pDC->OutputToken    ( _T("BD") );
00858     pDC->OutputNewLine  ();
00859     pDC->OutputToken    ( _T("%AI5_EndGradient") );
00860     pDC->OutputNewLine  ();
00861 
00862     // It worked!
00863     return TRUE;
00864 }
00865 
00866 
00867 /********************************************************************************************
00868 
00869 >   BOOL AIEPSRenderRegion::WriteRadialFill ( AttrFillGeometry  *pFill, INT32 id )
00870 
00871     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
00872     Created:    1/3/00
00873     Inputs:     pFill   - A pointer to the fill attribute record.
00874                 id      - The fill's id number
00875     Returns:    TRUE    - If successful.
00876                 FALSE   - The was an error (e.g. file/disk error).
00877     Purpose:    Writes a Radial fill to the disk file.
00878 
00879 ********************************************************************************************/
00880 BOOL AIEPSRenderRegion::WriteRadialFill (FillGeometryAttribute * pFill, EFFECTTYPE effect, INT32 id)
00881 {
00882     // Extract the fill attribute - this is necessary for processing the fill type.
00883     KernelDC                *pDC                = static_cast<KernelDC *> ( CCDC::ConvertFromNativeDC(RenderDC) );
00884     INT32                       Colours             = 2;
00885     TCHAR                   GradientName [32];
00886     DocColour               StartColour         = *( pFill->GetStartColour () );
00887     DocColour               EndColour           = *( pFill->GetEndColour () );
00888     ColourRamp              *pRamp              = pFill->GetColourRamp ();
00889 
00890     // The fill is, or can be approximated by, a Radial fill.
00891     camSprintf ( GradientName, _T("(%s %d)"), RadialGradient, id );
00892 
00893     // Count the number of colours.
00894     if ( pRamp != NULL )
00895     {
00896         UINT32  First   = 0;
00897         UINT32  Last    = 0;
00898 
00899         // Extract the indices from the colour ramp.
00900         pRamp->GetIndexRange ( &First, &Last );
00901 
00902         // And add their difference to the colour count. Note, you need to add one
00903         // to the result so that you don't register having no colours. There really
00904         // should be a count number of elements method in the ramp code, though.
00905         Colours += 1 + Last - First;
00906 
00907         if (effect != EFFECT_RGB)
00908         {
00909             // Add in the extra steps for the fill effect (Five extra steps between each 
00910             //  pair of colours).
00911             Colours += (Colours - 1) * NumFillEmulationSteps;
00912         }
00913     }
00914 
00915     // Write the gradient's header.
00916     pDC->OutputToken    ( _T("%AI5_BeginGradient:") );
00917     pDC->OutputToken    ( GradientName );
00918     pDC->OutputNewLine  ();
00919 
00920     // Then the type definition.
00921     pDC->OutputToken    ( GradientName );
00922     pDC->OutputValue    ( static_cast<INT32> ( RadialFill ) );
00923     pDC->OutputValue    ( static_cast<INT32> ( Colours ) );
00924     pDC->OutputToken    ( _T("Bd") );
00925     pDC->OutputNewLine  ();
00926     pDC->OutputToken    ( _T("[") );
00927     pDC->OutputNewLine  ();
00928 
00929     // (ChrisG 3/4/2001) Get bias and convert to 0-100 range (from -1 to +1)
00930     CProfileBiasGain profile = pFill->GetProfile ();
00931     INT32 bias = (INT32) ((1 - (double) profile.GetBias ()) * 50);
00932         
00933     // Write out the start colour.
00934     WriteGradientEntry ( &StartColour, 0, bias );
00935 
00936     DocColour * pLastCol = &StartColour;
00937     INT32 lastPos = 0;
00938 
00939     // Process the colour ramp.
00940     if ( pRamp != NULL )
00941     {
00942         ColRampItem *pItem = pRamp->GetFirstCol ();
00943 
00944         // Write in the ramp's colour values.
00945         while ( pItem != NULL )
00946         {
00947             // Get the position of the colour in the fill.
00948             INT32       Ratio   = static_cast <INT32> ( 100 * pItem->GetPosition () );
00949             DocColour   *pCol   = pItem->GetColourAddr ();
00950 
00951             // Write out the intermediate fill steps (if there are any).
00952             if (effect != EFFECT_RGB)
00953             {
00954                 WriteFillEffectSteps (pLastCol, lastPos, pCol, Ratio, bias, effect);
00955                 pLastCol = pCol;
00956                 lastPos = Ratio;
00957             }
00958 
00959             // And set the value.
00960             WriteGradientEntry ( pCol, Ratio, 50 );
00961 
00962             // Increment the pointer onto the next item.
00963             pItem = pRamp->GetNextCol ( pItem );
00964         }
00965     }
00966 
00967     // Write out the intermediate fill steps (if there are any).
00968     if (effect != EFFECT_RGB)
00969     {
00970         WriteFillEffectSteps (pLastCol, lastPos, &EndColour, 100, bias, effect);
00971     }
00972 
00973     // Write out the last colour.
00974     WriteGradientEntry ( &EndColour, 100, 50 );
00975 
00976     // Write out the end of gradient tokens.
00977     pDC->OutputToken    ( _T("BD") );
00978     pDC->OutputNewLine  ();
00979     pDC->OutputToken    ( _T("%AI5_EndGradient") );
00980     pDC->OutputNewLine  ();
00981 
00982     // It worked!
00983     return TRUE;
00984 }
00985 
00986 /********************************************************************************************
00987 
00988 >   virtual BOOL AIEPSRenderRegion::WriteGradientEntry ( DocColour  *pColour,
00989                                                          INT32      Position,
00990                                                          INT32      Midpoint )
00991 
00992     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
00993     Created:    24/3/00
00994     Inputs:     pColour     - A pointer to a Camelot colour.
00995                 Position    - The position of the colour within the fill.
00996                 Midpoint    - The midpoint of the fill.
00997     Returns:    TRUE if successful.
00998                 FALSE if error (e.g. file/disk error)
00999     Purpose:    Writes a line into the definition of a gradient fill.
01000 
01001 ********************************************************************************************/
01002 BOOL AIEPSRenderRegion::WriteGradientEntry ( DocColour  *pColour,
01003                                              INT32      Position,
01004                                              INT32      Midpoint )
01005 {
01006     INT32 red;                                          //
01007     INT32 green;                                            // RGB colour values
01008     INT32 blue;                                         //
01009     PColourCMYK CMYKColour;                             // The colour to be stored.
01010 
01011     KernelDC *pDC = (KernelDC*)CCDC::ConvertFromNativeDC(RenderDC);
01012     TCHAR       Line [80];                              // Contains the string to be stored.
01013 
01014     // (ChrisG 3/4/2001) 
01015     if (Midpoint < 13)
01016         Midpoint = 13;
01017     else if (Midpoint > 87)
01018         Midpoint = 87;
01019 
01020     pColour->GetCMYKValue ( &CMYKColour );              // Extract the CMYK value.
01021 
01022     if (pColour->GetColourModel () == COLOURMODEL_RGBT ||
01023         pColour->GetColourModel () == COLOURMODEL_HSVT)
01024     {
01025         // Use RGB syntax.
01026         pColour->GetRGBValue ( &red, &green, &blue );
01027 
01028         camSprintf ( Line, _T("2 %d %d%%_Bs"), Midpoint, Position );
01029         pDC->OutputColour       ( &CMYKColour );
01030         pDC->OutputColourValue  ( red );
01031         pDC->OutputColourValue  ( green );
01032         pDC->OutputColourValue  ( blue );
01033         pDC->OutputToken        ( Line );
01034         pDC->OutputNewLine      ();
01035     }
01036     else
01037     {
01038 
01039         // It is necessary to build the output line like this, so that there isn't a space
01040         // between the position of the colour, and the %_Bs operator.
01041         camSprintf ( Line, _T("1 %d %d%%_Bs"), Midpoint, Position );    // Build the output string.
01042 
01043         pDC->OutputColour   ( &CMYKColour );                // Write the colour to the file.
01044         pDC->OutputToken    ( Line );                       // Write the output string out.
01045         pDC->OutputNewLine  ();                             // And write a new-line tag.
01046     }
01047 
01048     return TRUE;                                        // All done successfully.
01049 }
01050 
01051 /********************************************************************************************
01052 
01053 >   virtual BOOL AIEPSRenderRegion::WriteFillEffectSteps (  DocColour * pColour1,
01054                                                             INT32       pos1,
01055                                                             DocColour * pColour2,
01056                                                             INT32       pos2,
01057                                                             INT32       bias,
01058                                                             EFFECTTYPE  effect)
01059 
01060     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
01061     Created:    4/4/2001
01062     Inputs:     pColour1    - The colour to start from.
01063                 pos1        - The position of the start colour within the fill (0-100%).
01064                 pColour2    - The colour to end at.
01065                 pos2        - The position of the end colour within the entire fill (0-100%)
01066                 bias        - The fill's bias part of any profile (0-100%).
01067                 effect      - The type of fill effect (EFFECT_HSV_SHORT or EFFECT_HSV_LONG)
01068     Returns:    TRUE if successful.
01069                 FALSE if error (e.g. file/disk error)
01070     Purpose:    Writes the additional entries required for a special fill effect (rainbow or
01071                 alt-rainbow) to the gradient definition, as a series of steps.
01072     See Also:   AIEPSRenderRegion::WriteGradientEntry
01073                 AIEPSRenderRegion::WriteLinearFill
01074                 AIEPSRenderRegion::WriteRadialFill
01075 
01076 ********************************************************************************************/
01077 BOOL AIEPSRenderRegion::WriteFillEffectSteps (  DocColour *pColour1,
01078                                                 INT32 pos1, 
01079                                                 DocColour *pColour2, 
01080                                                 INT32 pos2, 
01081                                                 INT32 bias, 
01082                                                 EFFECTTYPE effect)
01083 {
01084     ERROR3IF (effect == EFFECT_RGB, "AIEPSRenderRegion::WriteFillEffectSteps, an attempt was made to write HSV fill effect steps on an RGB fade fill");
01085 
01086     // RGB fades are the 'standard' fill, so we don't want to do any special processing on them
01087     if (effect != EFFECT_RGB)
01088     {
01089         // Start and end colour values
01090         INT32 h1 = 0;
01091         INT32 h2 = 0;
01092         INT32 s1 = 0;
01093         INT32 s2 = 0;
01094         INT32 v1 = 0;
01095         INT32 v2 = 0;
01096 
01097         // intermediate colour values / increments
01098         DocColour midColour;
01099         double hAdd = 0;
01100         double sAdd = 0;
01101         double vAdd = 0;
01102         double posAdd = 0;
01103 
01104         // First get the start and end colour components
01105         pColour1->GetHSVValue (&h1, &s1, &v1);
01106         pColour2->GetHSVValue (&h2, &s2, &v2);
01107 
01108         // Calculate the increments  
01109         //
01110         //  NOTE: if the hue changes by more than 180 deg. in a short HSV (rainbow) fill
01111         //  (or not more than 180 deg. in a long HSV (alt-rainbow) fill), then the direction
01112         //  must be reversed. This is done by changing the hue increment value.
01113         hAdd = h2-h1;
01114         if (effect == EFFECT_HSV_SHORT)
01115         {
01116             if (hAdd > 180)
01117                 hAdd -= 360;
01118             else if (hAdd < -180)
01119                 hAdd += 360;
01120         }
01121         else
01122         {
01123             if ((hAdd > 0) && (hAdd <= 180))
01124                 hAdd -= 360;
01125             else if ((hAdd <= 0) && (hAdd >= -180))
01126                 hAdd += 360;
01127         }
01128         hAdd = hAdd / (NumFillEmulationSteps + 1);
01129         sAdd = (s2-s1) / (NumFillEmulationSteps + 1);
01130         vAdd = (v2-v1) / (NumFillEmulationSteps + 1);
01131         posAdd = ((double) pos2-pos1) / (NumFillEmulationSteps + 1);
01132 
01133         // Cycle through the stops calcuating each stop's colour and position, before 
01134         //  writing them out.
01135         for (INT32 i=1; i<NumFillEmulationSteps + 1; i++)
01136         {
01137             // increment each colour value and the position
01138             h2 = (INT32)(h1 + (i * hAdd));
01139             s2 = (INT32)(s1 + (i * sAdd));
01140             v2 = (INT32)(v1 + (i * vAdd));
01141             pos2 = (INT32)(pos1 + (i * posAdd));
01142 
01143             // wrap the hue around if it's gone past 360 deg or 0 deg.
01144             if (h2>=360)
01145                 h2 -= 360;
01146             else if (h2<0)
01147                 h2 += 360;
01148 
01149             // create the colour and export.
01150             midColour.SetHSVValue (h2, s2, v2);
01151             WriteGradientEntry (&midColour, pos2, 50);
01152         }
01153     }   // End of is fill effect not an RGB fade.
01154 
01155     return TRUE;
01156 }
01157 
01158 /********************************************************************************************
01159 
01160 >   virtual BOOL AIEPSRenderRegion::WriteDocumentSetup ( Document   *pDocument,
01161                                                          EPSFilter  *pFilter )
01162 
01163     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
01164     Created:    24/3/00
01165     Inputs:     pDocument   - The document being outputted.
01166                 pFilter     - A pointer to the export filter.
01167     Outputs:    -
01168     Returns:    TRUE if successful.
01169                 FALSE if error (e.g. file/disk error)
01170     Purpose:    Browse through the tree, and if a text story is found invoke the document
01171                 setup function. By only exporting the font setup when necessary, the file
01172                 size produced is smaller (which makes it easier for me to interpret :) ),
01173                 and it should hopefully make the filter run a bit faster too.
01174 
01175 ********************************************************************************************/
01176 
01177 BOOL AIEPSRenderRegion::WriteDocumentSetup ( Document   *pDocument,
01178                                              EPSFilter  *pFilter )
01179 {
01180     // Get the spread from the document.
01181     Spread      *pSpread    = pDocument->FindFirstSpread ();
01182     Node        *pTextStory = NULL;
01183 
01184     // Try to find a single instance of the TextStory node.
01185     pTextStory = SliceHelper::FindNextOfClass ( pSpread, pSpread,
01186                                                 CC_RUNTIME_CLASS ( TextStory ) );
01187 
01188     // If something was found...
01189     if ( pTextStory != NULL )
01190     {
01191         // ... write out the font set-up.
01192         pDocument->WriteEPSSetup ( pFilter );
01193     }
01194     else
01195     {
01196         // Otherwise just get the relevant bits.
01197         pDocument->AIExportExtras ( pFilter->GetExportDC () );
01198     }
01199 
01200     // It worked!
01201     return TRUE;
01202 }
01203 
01204 /********************************************************************************************
01205 
01206 >   BOOL AIEPSRenderRegion::EndLayer ()
01207 
01208     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
01209     Created:    11/4/00
01210     Inputs:     -
01211     Returns:    TRUE    - Success.
01212                 FALSE   - An error occured.
01213     Purpose:    If there is an existing layer, it writes the end of layer tags, before
01214                 creating a new layer record.
01215     SeeAlso:    AIEPSRenderRegion::ExportLayer ()
01216 
01217 ********************************************************************************************/
01218 
01219 BOOL AIEPSRenderRegion::EndLayer ()
01220 {
01221     // Only act if there's an active layer.
01222     if ( m_ActiveLayer )
01223     {
01224         // Cast the RenderDC pointer into a useful form.
01225         KernelDC    *pDC    = static_cast<KernelDC *> ( CCDC::ConvertFromNativeDC(RenderDC) );
01226 
01227         // Write out the end of layer tag.
01228         pDC->OutputToken    ( _T("LB") );
01229         pDC->OutputNewLine</