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  ();
01230         pDC->OutputToken    ( _T("%AI5_EndLayer") );
01231         pDC->OutputNewLine  ();
01232 
01233         // Set m_ActiveLayer to be FALSE.
01234         m_ActiveLayer = FALSE;
01235     }
01236 
01237     return TRUE;
01238 }
01239 
01240 /********************************************************************************************
01241 
01242 >   void AIEPSRenderRegion::WriteGradientFillInstance ()
01243 
01244     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
01245     Created:    9/03/00
01246     Purpose:    This function identifies whether or not the current fill is a gradient fill,
01247                 and writes in the appropriate values if it is. I've already created the
01248                 records of the gradients themselves (see above), so this is just a case of
01249                 matching the gradient with its ID, and Adobe Illustrator can then put the
01250                 records together.
01251 
01252                 (ChrisG 18/12/00) - all this does now is increment the counters used for 
01253                 determining which gradient fill is currently being used.
01254 
01255     SeeAlso:    EPSRenderRegion::WriteGradientFill, WriteGradientFillUsage
01256 
01257 ********************************************************************************************/
01258 
01259 void AIEPSRenderRegion::WriteGradientFillInstance ()
01260 {
01261     KernelDC *pDC = (KernelDC*)CCDC::ConvertFromNativeDC(RenderDC);
01262     FillGeometryAttribute   *pFillAttr  = ( FillGeometryAttribute* )
01263                                             CurrentAttrs[ATTR_FILLGEOMETRY].pAttr;
01264     DocCoord                StartPoint  = *( pFillAttr->GetStartPoint () );
01265     DocCoord                EndPoint    = *( pFillAttr->GetEndPoint () );
01266     DocCoord                Delta       = EndPoint - StartPoint;
01267     double                  Angle       = 90.0f;
01268     double                  Length      = FlashExportDC::CalculateLength ( Delta );
01269     TCHAR                   Name [80];
01270     BOOL                    IsRadial    = pFillAttr->IsARadialFill () ||
01271                                           pFillAttr->IsASquareFill ();
01272     INT32                   id          = 0;
01273 
01274     if (IsGradientFillValidForExport (pFillAttr))
01275     {
01276         id = FindGradientInCache (pFillAttr, GetFillEffect ());
01277 
01278         // If the fill is, or can be approximated by, a radial fill, set the the definition to
01279         // indicate this.
01280         if ( IsRadial )
01281         {
01282             // Set up the name to show that it's a radial gradient.
01283             camSprintf ( Name, _T("(%s %d)"), RadialGradient, id );
01284         }
01285         // Otherwise it's represented by a linear fill.
01286         else
01287         {
01288             // Set up the name to show that it's a linear gradient.
01289             camSprintf ( Name, _T("(%s %d)"), LinearGradient, id );
01290         
01291             // Reset the end point value if we're dealing with a three colour fill.
01292             if ( pFillAttr->IsAThreeColFill () )
01293             {
01294                 DocCoord    EndPoint2   = *( pFillAttr->GetEndPoint2 () );
01295 
01296                 // Complete the parallellogram of vectors.
01297                 EndPoint += EndPoint2 - StartPoint;
01298             }
01299         }
01300 
01301         // (ChrisG 16/01/01) Since all the endpoint calculations have now been done,
01302         //  we can determine Delta, length and angle. (NOTE: these cannot be done 
01303         //  before here, as we wouldn't be using the correct endpoint values.)
01304         Delta   = EndPoint - StartPoint;
01305         Length  = FlashExportDC::CalculateLength ( Delta );
01306 
01307         // The tangent of an angle is undefined for PI/2 radians. (i.e. when Delta.x
01308         // is zero.)
01309         if ( Delta.x != 0 )
01310         {
01311             Angle = atan ( ( double ) Delta.y / ( double ) Delta.x );
01312 
01313             // AI uses degrees, whereas the standard maths library uses radians, so
01314             // effect a conversion.
01315             Angle *= ( 180.0 / PI );    // Pi radians = 180 degrees.
01316 
01317             // Tan repeats itself every Pi radians, so add 180 degrees to the angle
01318             // if it's got a negative value of Delta.y. Special case: If Delta.x is
01319             // negative, and Delta.y is 0, the angle is 180 degrees.
01320             if ( Delta.x < 0 )
01321             {
01322                 // I want the angle to be in the interval ]-180, 180], and so I've
01323                 // got special case handling, depending on which quadrant it lies
01324                 // in initially. Without the if statement here, the interval would
01325                 // be ]-90, 270].
01326                 if ( Angle >= 0.0 )
01327                 {
01328                     Angle -= 180.0;
01329                 }
01330                 else
01331                 {
01332                     Angle += 180.0;
01333                 }
01334             }
01335         }
01336 
01337         // More special case stuff. If Delta.x is 0, then the angle must be either
01338         // +90 or -90 degrees. And we can get the sign of the angle from the sign
01339         // of Delta.y
01340         else if ( Delta.y < 0 )
01341         {
01342             Angle = -90.0;
01343         }
01344 
01345         // AI uses points as a co-ordinate system - we use millipoints. Dividing
01346         // the length of the fill by 1,000 will thus return it's value in points.
01347         Length /= 1000;
01348 
01349         // Write out the appropriate fill record.
01350         pDC->OutputToken    ( _T("1") );                // It is a clipped gradient.
01351         pDC->OutputToken    ( Name );               // The gradient's name.
01352         pDC->OutputCoord    ( StartPoint );         // Start point for the gradient fill.
01353         pDC->OutputReal     ( Angle );              // The angle of the fill from the X-Axis.
01354         pDC->OutputReal     ( Length );             // The length of the matrix.
01355         pDC->OutputToken    ( _T("1 0 0 1 0 0 Bg") );   // Matrix manipulating the fill. (Unused.)
01356         pDC->OutputNewLine  ();
01357 
01358     }   // End of IsGradientFillValidForExport.
01359 }
01360 
01361 /********************************************************************************************
01362 
01363 >   void AIEPSRenderRegion::OutputFillColour ()
01364 
01365     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
01366     Created:    29/3/00
01367     Purpose:    If the fill is a gradient fill, this method will invoke the
01368                 WriteGradientFillInstance method, otherwise it will call the base
01369                 EPSRenderRegion OutputFillColour method. This allows Camelot to support
01370                 gradient fills in the AI file format.
01371 
01372                 (ChrisG 30/3/2001) - Gradient fill instances should be exported when they 
01373                 are used on an object, not when a fill attribute is found. This way, fills 
01374                 can be applied to multiple objects.
01375 
01376     SeeAlso:    AIEPSRenderRegion::OutputStrokeColour
01377 
01378 ********************************************************************************************/
01379 
01380 void AIEPSRenderRegion::OutputFillColour ()
01381 {
01382     // Output the actual fill colour.
01383     EPSRenderRegion::OutputFillColour ();
01384 }
01385 
01386 /********************************************************************************************
01387 
01388 >   BOOL AIEPSRenderRegion::LoadBitmapMatrix ( NodeBitmap   *pNodeBMP )
01389 
01390     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
01391     Created:    4/4/00
01392     Inputs:     pNodeBitmap - A pointer to the bitmap node being exported.
01393     Returns:    TRUE        - Successful.
01394                 FALSE       - An error has occured.
01395     Purpose:    This code generates a matrix to position and manipulate a bitmap within
01396                 an AI file. Roughly, it calculates the angle of rotation, followed by the
01397                 skew angle, and creates a matrix using these values.
01398     See Also:   FlashExportDC::WriteBitmapFill ()
01399 
01400 ********************************************************************************************/
01401 
01402 BOOL AIEPSRenderRegion::LoadBitmapMatrix ( NodeBitmap   *pNodeBMP )
01403 {
01404     // Step 1:  Extract the co-ordinates of three corners from the bitmap record, and store
01405     //          them as named co-ordinates within this function. The names are a historical
01406     //          reference to the original names within the FlashExportDC, and refer to the
01407     //          positions of a bitmap fill.
01408     double          Angle       = pNodeBMP->GetRotationAngle ();
01409 
01410     double          SinRotate   = sin ( Angle );
01411     double          CosRotate   = cos ( Angle );
01412 //  double          Skew        = 0;
01413 
01414     DocCoord        LowLeft     = pNodeBMP->Parallel [3];   // Low corner of the bitmap.
01415     DocCoord        TopLeft     = pNodeBMP->Parallel [0];   // Max Y corner.
01416     DocCoord        LowRight    = pNodeBMP->Parallel [2];   // Max X corner.
01417 
01418     // Step 2:  Calculate the normalised dot product of the two vectors, and this forms
01419     //          the cosine of their internal angle.
01420     double          WidthX      = static_cast<double> ( LowLeft.x - LowRight.x ) / 1000;
01421     double          WidthY      = static_cast<double> ( LowLeft.y - LowRight.y ) / 1000;
01422     double          HeightX     = static_cast<double> ( TopLeft.x - LowLeft.x  ) / 1000;
01423     double          HeightY     = static_cast<double> ( TopLeft.y - LowLeft.y  ) / 1000;
01424     
01425     // Get the lengths of these vectors to normalise the dot-product. (Necessary for the
01426     // trignometric function calculations.)
01427     double          Width       = sqrt ( ( WidthX * WidthX ) + ( WidthY * WidthY ) );
01428     double          Height      = sqrt ( ( HeightX * HeightX ) + ( HeightY * HeightY ) );
01429 /*
01430     // The dot product calculation. By normalising the result, the cosine of the angle is
01431     // calculated.
01432     double      CosSkew = ( ( WidthX * HeightX ) + ( HeightY * WidthY ) ) /
01433                               ( Height * Width );
01434     double      SinSkew = sqrt ( 1 - ( CosSkew * CosSkew ) );
01435 
01436     // Multiply the width of the shape by the sine derived from the dot product. This will
01437     // give the actual width, and not the one distorted by skewing.
01438     Width *= SinSkew;
01439 
01440     // If the DotSine value is not 0, calculate the tan value that forms the skew angle.
01441     // Since tan is undefined for 0, I'm ignoring this state.
01442     if ( SinSkew != 0 )
01443     {
01444         Skew = - CosSkew / SinSkew;
01445     }
01446 */
01447     // Grab a reference to the bitmap, and pull it's height and width from it.
01448     KernelBitmap    *pBitmap    = pNodeBMP->GetBitmap ();   // A reference to the bitmap.
01449 
01450     double          BMPWidth    = static_cast<double> ( pBitmap->GetWidth () );
01451     double          BMPHeight   = static_cast<double> ( pBitmap->GetHeight () );
01452 
01453     // Catch BMPWidth or BMPHeight set to zero. This shouldn't happen...
01454     if ( BMPWidth == 0 )
01455         BMPWidth = 1;
01456 
01457     if ( BMPHeight == 0 )
01458         BMPHeight = 1;
01459 
01460     // Step 4:  Use the above values to calculate the values with which to populate the
01461     //          transformation matrix.
01462     double          ScaleX      = Width  / BMPWidth;
01463     double          ScaleY      = Height / BMPHeight;
01464 
01465     // Step 5:  Use these to build the matrix. The variables a, b, c, d refer to the AI
01466     //          matrix entries. The form of the matrix is:
01467     //
01468     //          | SinRotate     CosRotate | | ScaleX        0       |
01469     //          | -CosRotate    SinRotate | | Skew * ScaleY ScaleY  |
01470 
01471     m_a = ( SinRotate * ScaleX );   // + ( CosRotate * Skew * ScaleY );
01472     m_b = ( - CosRotate * ScaleX ); // + ( SinRotate * Skew * ScaleY );
01473     m_c = CosRotate * ScaleY;
01474     m_d = SinRotate * ScaleY;
01475 
01476     // There's a weird bug with the AI export, in that a small (>0.0001) value is misread
01477     // by Adobe Illustrator as a monstrous value. To get around this, I'm going to set all
01478     // near zero values to zero.
01479     if ( Absol ( m_a ) < 1e-4 )
01480     {
01481         m_a = 0;
01482     }
01483 
01484     if ( Absol ( m_b ) < 1e-4 )
01485     {
01486         m_b = 0;
01487     }
01488 
01489     if ( Absol ( m_c ) < 1e-4 )
01490     {
01491         m_c = 0;
01492     }
01493 
01494     if ( Absol ( m_d ) < 1e-4 )
01495     {
01496         m_d = 0;
01497     }
01498 
01499     // Step 6:  Calculate the translation part of the matrix.
01500     m_T = TopLeft;
01501 
01502     return TRUE;
01503 }
01504 
01505 /********************************************************************************************
01506 
01507 >   BOOL AIEPSRenderRegion::LoadTranslationMatrix ( DocCoord &Translation )
01508 
01509     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
01510     Created:    10/4/00
01511     Inputs:     -
01512     Returns:    TRUE    - Success.
01513                 FALSE   - An error occured.
01514     Purpose:    Loads the matrix with:
01515 
01516                 | 1 0 Translation.x |
01517                 | 0 1 Translation.y |
01518 
01519                 Which can then be written with WriteLoadedMatrix.
01520     SeeAlso:    AIESPRenderRegion::LoadBitmapMatrix, AIEPSRenderRegion::WriteLoadedMatrix
01521 
01522 ********************************************************************************************/
01523 
01524 BOOL AIEPSRenderRegion::LoadTranslationMatrix ( DocCoord &Translation )
01525 {
01526     // Set the transformation part of the matrix to be the identity matrix.
01527     m_a = 1;
01528     m_b = 0;
01529     m_c = 0;
01530     m_d = 1;
01531 
01532     // And load up the translation value.
01533     m_T = Translation;
01534 
01535     return TRUE;
01536 }
01537 
01538 /********************************************************************************************
01539 
01540 >   BOOL AIEPSRenderRegion::WriteLoadedMatrix ( void )
01541 
01542     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
01543     Created:    10/4/00
01544     Inputs:     -
01545     Returns:    TRUE    - Success.
01546                 FALSE   - An error occured.
01547     Purpose:    Writes a pre-loaded matrix to the file. I've added a couple of functions to
01548                 create a matrix first, since it'll be more efficient to store the data, and
01549                 re-write it as required, than to recalculate it twice.
01550     SeeAlso:    AIESPRenderRegion::LoadBitmapMatrix, AIEPSRenderRegion::LoadTranslationMatrix
01551 
01552 ********************************************************************************************/
01553 
01554 BOOL AIEPSRenderRegion::WriteLoadedMatrix ( void )
01555 {
01556     // Cast the DC pointer to be a KernelDC pointer. This allows it to access useful member
01557     // functions.
01558     KernelDC    *pDC    = static_cast<KernelDC *> ( CCDC::ConvertFromNativeDC(RenderDC) );
01559 
01560     // Write the matrix.
01561     pDC->OutputToken    ( _T("[") );
01562     pDC->OutputReal     ( m_a );
01563     pDC->OutputReal     ( m_b );
01564     pDC->OutputReal     ( m_c );
01565     pDC->OutputReal     ( m_d );
01566     pDC->OutputCoord    ( m_T );
01567     pDC->OutputToken    ( _T("]") );
01568 
01569     return TRUE;
01570 }
01571 
01572 /********************************************************************************************
01573 
01574 >   void AIEPSRenderRegion::WriteMask ( Path *MaskPath, BOOL OutputGroupToken = FALSE )
01575 
01576     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
01577     Created:    7/4/00
01578     Inputs:     DrawPath - The path to render.
01579                 OutputGroupToken    whether or not we output a 'q' clipping group token.
01580     Purpose:    Creates a path that defines a masking pattern. All successive paths (until
01581                 the end of mask operator) will be clipped to this shape.
01582 
01583                 I've repeated a lot of code from EPSRenderRegion::ExportPath because I'm
01584                 scared of changing what is a fairly fundamental class, and then finding
01585                 that there are several hundred resultant problems. A lot of the filters
01586                 are pretty shakey at the moment in any case.
01587     SeeAlso:    RenderRegion::ExportPath
01588 
01589 ********************************************************************************************/
01590 
01591 BOOL AIEPSRenderRegion::WriteMask ( Path *MaskPath, BOOL OutputGroupToken )
01592 {
01593     KernelDC    *pDC        = static_cast<KernelDC*> ( CCDC::ConvertFromNativeDC(RenderDC) );   // DC for export file.
01594     DocCoord    *Coords     = MaskPath->GetCoordArray();
01595     PathVerb    *Verbs      = MaskPath->GetVerbArray();
01596     INT32           NumCoords   = MaskPath->GetNumCoords();
01597     INT32           ReadPos     = 1;                                    // Reading data from.
01598     BOOL        IsCompound  = FALSE;
01599 
01600     // (ChrisG 16/01/01) Only write masks/clips if there is a path to clip to.
01601     if (NumCoords != 0)
01602     {
01603         if (OutputGroupToken)
01604         {
01605             // Start the mask.
01606             pDC->OutputToken    ( _T("q") );
01607             pDC->OutputNewLine  ();
01608         }
01609 
01610         // Check to see if this is a compound path. If it is, there will be more than one
01611         // moveto command.
01612         while ( ReadPos < NumCoords )
01613         {
01614             // Find out the type of element that we are over, after the close flag has been
01615             // removed.
01616             if ( ( ( Verbs [ReadPos] ) & ( ~PT_CLOSEFIGURE ) ) == PT_MOVETO )
01617             {
01618                 // This is a compound path - stop searching for moveto's.
01619                 IsCompound = TRUE;
01620 
01621                 // Write the tag to indicate that it's a compound path.
01622                 pDC->OutputToken    ( _T("*u") );
01623                 pDC->OutputNewLine  ();
01624                 break;
01625             }
01626             else
01627             {
01628                 // Try next point
01629                 ReadPos++;
01630             }
01631         }
01632 
01633         // Reset to start of path
01634         ReadPos   = 0;
01635 
01636         // loop through the whole path
01637         while(ReadPos < NumCoords)
01638         {
01639             // Find out the type of element that we are over (after the close flag has been removed)
01640 //          Coord P[4];
01641             switch ( (Verbs[ReadPos]) & (~PT_CLOSEFIGURE) )
01642             {
01643                 case PT_MOVETO:
01644                     // If this is in the middle of the path, specify how this sub-path
01645                     // should be rendered - this is needed so that we re-import all the flags
01646                     // correctly on complex paths (e.g. PT_CLOSEFIGURE)
01647                     if (ReadPos > 0)
01648                     {
01649                         // Write out the mask definition.
01650                         WriteMaskTags ();
01651                     }
01652 
01653                     // Output the moveto command
01654                     pDC->OutputCoord(Coords[ReadPos]);
01655                     pDC->OutputToken(TEXT("m"));
01656                     pDC->OutputNewLine();
01657                     ReadPos++;
01658                     break;
01659 
01660 
01661                 case PT_LINETO:
01662                     // Output the lineto command
01663                     pDC->OutputCoord(Coords[ReadPos]);
01664                     pDC->OutputToken(TEXT("l"));
01665                     pDC->OutputNewLine();
01666                     ReadPos++;
01667                     break;
01668 
01669 
01670                 case PT_BEZIERTO:
01671                     // If this point is a bezier, then the next 2 points should be beziers to
01672                     ENSURE((Verbs[ReadPos+1]) & (~PT_CLOSEFIGURE), "Bezier found with 1 point");
01673                     ENSURE((Verbs[ReadPos+2]) & (~PT_CLOSEFIGURE), "Bezier found with 2 points");
01674                     
01675                     // Make sure that this is not at the start of the path
01676                     ENSURE(ReadPos > 0, "Broken path found while exporting EPS" );
01677 
01678                     // Output the moveto command
01679                     pDC->OutputCoord(Coords[ReadPos]);
01680                     pDC->OutputCoord(Coords[ReadPos+1]);
01681                     pDC->OutputCoord(Coords[ReadPos+2]);
01682                     pDC->OutputToken(TEXT("c"));
01683                     pDC->OutputNewLine();
01684                     ReadPos += 3;
01685                     break;
01686 
01687                 default:
01688                     ENSURE( FALSE, "We found a Path Element that does not exist!" );
01689                     break;
01690             }
01691         }
01692 
01693         // Do the final (or possibly only) render command
01694         WriteMaskTags ();
01695 
01696         if ( IsCompound )
01697         {
01698 
01699             // End compound path
01700             pDC->OutputToken(_T("*U"));
01701             pDC->OutputNewLine();
01702         }
01703 
01704         // Wrap up the mask.
01705         pDC->OutputToken    ( _T("0 O") );
01706         pDC->OutputNewLine  ();
01707 
01708     }   // End of if there is a clip path.
01709 
01710     return TRUE;
01711 }
01712 
01713 /********************************************************************************************
01714 
01715 >   void AIEPSRenderRegion::WriteMaskTags ( void )
01716 
01717     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
01718     Created:    11/4/00
01719     Returns:    TRUE    - Success.
01720                 FALSE   - Error.
01721     Purpose:    Writes out the tags at the end of each block of a mask's definition.
01722     SeeAlso:    RenderRegion::ExportPath
01723 
01724 ********************************************************************************************/
01725 
01726 BOOL AIEPSRenderRegion::WriteMaskTags ()
01727 {
01728     KernelDC    *pDC    = static_cast<KernelDC*> ( CCDC::ConvertFromNativeDC(RenderDC) );   // DC for export file.
01729 
01730     // Write out the mask definition tags.
01731     pDC->OutputToken    ( _T("h") );
01732     pDC->OutputNewLine  ();
01733     pDC->OutputToken    ( _T("W") );
01734     pDC->OutputNewLine  ();
01735     pDC->OutputToken    ( _T("n") );
01736     pDC->OutputNewLine  ();
01737 
01738     return TRUE;
01739 }
01740 
01741 /********************************************************************************************
01742 
01743 >   BOOL AIEPSRenderRegion::WriteBitmapRecord ( OILBitmap   *pBitmap )
01744 
01745     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
01746     Created:    10/4/00
01747     Inputs:     pBitmap - A pointer to the OIL bitmap object being rendered.
01748     Returns:    TRUE    - If successful.
01749                 FALSE   - If an error is encountered.
01750     Purpose:    Creates a kernel bitmap instance within the AI file.
01751     SeeAlso:    NodeBitmap::ExportRender ()
01752 
01753 ********************************************************************************************/
01754 
01755 BOOL AIEPSRenderRegion::WriteBitmapRecord ( OILBitmap   *pBitmap )
01756 {
01757     // Set up the local variables.
01758 //  KernelDC    *pDC        = static_cast<KernelDC*> ( CCDC::ConvertFromNativeDC(RenderDC) );
01759     INT32       Width       = static_cast<INT32> ( pBitmap->GetWidth () );
01760     INT32       Height      = static_cast<INT32> ( pBitmap->GetHeight () );
01761 
01762     // Write out the bitmap header.
01763     WriteBitmapHeader ( Width, Height );
01764 
01765     // Write out the body.
01766     WriteBitmapBody ( pBitmap, Width, Height );
01767 
01768     // Finish off the bitmap record.
01769     WriteBitmapTail ();
01770 
01771     // It worked!
01772     return TRUE;
01773 }
01774 
01775 /********************************************************************************************
01776 
01777 >   BOOL AIEPSRenderRegion::WriteBitmapHeader ( UINT32 Width,
01778                                                 UINT32 Height )
01779 
01780     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
01781     Created:    13/4/00
01782     Inputs:     Width   - The width (in pixels) of the bitmap image.
01783                 Height  - The height (in pixels) of the bitmap image.
01784     Returns:    TRUE    - If successful.
01785                 FALSE   - If an error is encountered.
01786     Purpose:    Writes the AI header for a bitmap record.
01787     SeeAlso:    NodeBitmap::ExportRender ()
01788 
01789 ********************************************************************************************/
01790 
01791 BOOL AIEPSRenderRegion::WriteBitmapHeader ( INT32 Width,
01792                                             INT32 Height )
01793 {
01794     // Set up kernel DC up in an appropriate form.
01795     KernelDC    *pDC    = static_cast<KernelDC *> ( CCDC::ConvertFromNativeDC(RenderDC) );
01796 
01797     // Declare the bitmap record.
01798     pDC->OutputToken    ( _T("%AI5_File:") );
01799     pDC->OutputNewLine  ();
01800     pDC->OutputToken    ( _T("%AI5_BeginRaster") );
01801     pDC->OutputNewLine  ();
01802 
01803     // (ChrisG 23/11/00) The Xh operator has been removed, as it wasn't correct (it didn't 
01804     //  have the third, unknown, value), it isn't in the Illustrator File Format Manual, 
01805     //  and all the information in it seems to be duplicated in the standard XI operator, 
01806     //  which is written out immediately after the Xh one was.
01807 
01808     // The matrix.
01809 //  WriteLoadedMatrix ();
01810 
01811     // Height and width. (and an extra value - as there's no mention of this token in the
01812     //  Illustrator file format manual, I have no idea what it signifies, but Photoshop 
01813     //  needs it, or else it gives MPS Parser Errors).
01814 //  pDC->OutputValue    ( Width );
01815 //  pDC->OutputValue    ( Height );
01816 //  pDC->OutputValue    ( 0l );
01817 //  pDC->OutputToken    ( _T("Xh") );
01818 //  pDC->OutputNewLine  ();
01819 
01820 
01821     // Write out the XI operator.
01822 
01823     // The matrix.
01824     WriteLoadedMatrix ();
01825 
01826     // The bounds of the bitmap.
01827     pDC->OutputToken    ( _T("0 0") );
01828     pDC->OutputValue    ( Width );
01829     pDC->OutputValue    ( Height );
01830 
01831     // Height and width. Note: The AI documentation puts their order the other
01832     // way around, but the AI export from Fireworks uses this order.
01833     pDC->OutputValue    ( Width );
01834     pDC->OutputValue    ( Height );
01835 
01836     // These values are always constant, and so I don't need to worry about
01837     // them changing.
01838     pDC->OutputToken    ( _T("8 3 0 0 0 0") );
01839     pDC->OutputNewLine  ();
01840 
01841     // Write out the file size.
01842     pDC->OutputToken    ( _T("%%BeginData:") );
01843     pDC->OutputValue    ( static_cast<INT32> ( Height * Width * 3 ) );
01844     pDC->OutputNewLine  ();
01845 
01846     // Wrap out the XI operator.
01847     pDC->OutputToken    ( _T("XI") );
01848     pDC->OutputNewLine  ();
01849  
01850     return TRUE;
01851 }
01852 
01853 /********************************************************************************************
01854 
01855 >   BOOL AIEPSRenderRegion::WriteBitmapBody ( OILBitmap *pBitmap,
01856                                               INT32     Width,
01857                                               INT32     Height )
01858 
01859     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
01860     Created:    13/4/00
01861     Inputs:     pBitmap - A pointer to the OIL bitmap object being rendered.
01862                 Width   - The width of the bitmap in pixels.
01863                 Height  - The height of the bitmap in pixels.
01864     Returns:    TRUE    - If successful.
01865                 FALSE   - If an error is encountered.
01866     Purpose:    Writes the bitmap's data to the file.
01867     SeeAlso:    NodeBitmap::ExportRender ()
01868 
01869 ********************************************************************************************/
01870 
01871 BOOL AIEPSRenderRegion::WriteBitmapBody ( OILBitmap *pBitmap,
01872                                           INT32     Width,
01873                                           INT32     Height )
01874 {
01875     // Set up the local variables.
01876     KernelDC    *pDC    = static_cast<KernelDC*> ( CCDC::ConvertFromNativeDC(RenderDC) );
01877     INT32           Count   = 0;
01878 
01879     // Write the initial %.
01880     pDC->OutputToken    ( _T("%") );
01881 
01882     // Write out the bitmap data. It's necessary to go backwards through y
01883     // otherwise the bitmap is rendered upside down.
01884     for ( INT32 y = Height - 1; y >= 0; y-- )
01885     {
01886         for ( INT32 x = 0; x < Width; x++ )
01887         {
01888             Pixel32bpp  BMPPixel    = pBitmap->ReadPixel32bpp ( x, y );
01889             TCHAR       Output [7];
01890 
01891             // Wrap the line to keep the file tidy.
01892             if ( Count >= 10 )
01893             {
01894                 pDC->OutputNewLine  ();
01895                 pDC->OutputToken    ( _T("%") );
01896                 Count = 0;
01897             }
01898 
01899             // Translate the RGB values into an ASCII string.
01900             camSprintf ( Output, _T("%.2X%.2X%.2X"), BMPPixel.Red, BMPPixel.Green, BMPPixel.Blue );
01901 
01902             // And output them. I'm writing directly to the file because the OutputToken ()
01903             // function introduces spaces between the values, which is not a good thing for
01904             // the AI file format. This way, it's much happier. :)
01905             if ( !pDC->OutputTCHARAsChar ( Output, 6 ) )
01906             {
01907                 // There's been a problem.
01908                 return FALSE;
01909             }
01910 
01911             Count ++;
01912         }
01913     }
01914 
01915     // Write a new line after the bitmap record, to keep things tidy.
01916     pDC->OutputNewLine  ();
01917 
01918     return TRUE;
01919 }
01920 
01921 /********************************************************************************************
01922 
01923 >   BOOL AIEPSRenderRegion::WriteContoneBody ( OILBitmap    *pBitmap )
01924 
01925     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
01926     Created:    13/4/00
01927     Inputs:     pBitmap - A pointer to the OIL bitmap object being rendered.
01928     Returns:    TRUE    - If successful.
01929                 FALSE   - If an error is encountered.
01930     Purpose:    Writes a contone bitmap to the file as a 32bpp image.
01931     SeeAlso:    NodeBitmap::ExportRender ()
01932 
01933 ********************************************************************************************/
01934 
01935 BOOL AIEPSRenderRegion::WriteContoneBody ( OILBitmap    *pBitmap )
01936 {
01937     // Set up the local variables.
01938     KernelDC    *pDC    = static_cast<KernelDC*> ( CCDC::ConvertFromNativeDC(RenderDC) );
01939     INT32       Width   = static_cast<INT32> ( pBitmap->GetWidth () );
01940     INT32       Height  = static_cast<INT32> ( pBitmap->GetHeight () );
01941     INT32           Count   = 0;
01942 
01943     // Write the initial %.
01944     pDC->OutputToken    ( _T("%") );
01945 
01946     // Write out the bitmap data. It's necessary to go backwards through y
01947     // otherwise the bitmap is rendered upside down.
01948     for ( INT32 y = Height - 1; y >= 0; y-- )
01949     {
01950         for ( INT32 x = 0; x < Width; x++ )
01951         {
01952             UINT32          Index       = pBitmap->ReadPixelGreyscale ( x, y );
01953             DocColour       PixelColour = pBitmap->GetContonePaletteEntry ( Index );
01954             TCHAR           Output [7];
01955             INT32           lRed;
01956             INT32           lGreen;
01957             INT32           lBlue;
01958 
01959             // Extract the values from the DocColour.
01960             PixelColour.GetRGBValue ( &lRed, &lGreen, &lBlue );
01961             
01962             // Wrap the line to keep the file tidy.
01963             if ( Count >= 10 )
01964             {
01965                 pDC->OutputNewLine  ();
01966                 pDC->OutputToken    ( _T("%") );
01967                 Count = 0;
01968             }
01969 
01970             // Translate the RGB values into an ASCII string.
01971             camSprintf ( Output, _T("%.2X%.2X%.2X"), lRed, lGreen, lBlue );
01972 
01973             // And output them. I'm writing directly to the file because the OutputToken ()
01974             // function introduces spaces between the values, which is not a good thing for
01975             // the AI file format. This way, it's much happier. :)
01976             if ( !pDC->OutputTCHARAsChar ( Output, 6 ) )
01977             {
01978                 // There's been a problem.
01979                 return FALSE;
01980             }
01981 
01982             Count ++;
01983         }
01984     }
01985 
01986     // Write a new line after the bitmap record, to keep things tidy.
01987     pDC->OutputNewLine  ();
01988 
01989     return TRUE;
01990 }
01991 
01992 /********************************************************************************************
01993 
01994 >   BOOL AIEPSRenderRegion::WriteBitmapTail ( void )
01995 
01996     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
01997     Created:    13/4/00
01998     Inputs:     -
01999     Returns:    TRUE    - If successful.
02000                 FALSE   - If an error is encountered.
02001     Purpose:    Wraps up the bitmap instance.
02002     SeeAlso:    NodeBitmap::ExportRender ()
02003 
02004 ********************************************************************************************/
02005 
02006 BOOL AIEPSRenderRegion::WriteBitmapTail ( void )
02007 {
02008     // Set up kernel DC up in an appropriate form.
02009     KernelDC    *pDC    = static_cast<KernelDC *> ( CCDC::ConvertFromNativeDC(RenderDC) );
02010 
02011     // Wrap up the bitmap record.
02012     pDC->OutputToken    ( _T("%%EndData") );
02013     pDC->OutputNewLine  ();
02014     pDC->OutputToken    ( _T("XH") );
02015     pDC->OutputNewLine  ();
02016     pDC->OutputToken    ( _T("%AI5_EndRaster") );
02017     pDC->OutputNewLine  ();
02018 
02019     // ChrisG (27/10/00).
02020     // This token was changed from 'N' close unfilled path, to 'F' close filled path. The  
02021     //  latter preserves information about the current line width, join type, fill colour, 
02022     //  etc... Whereas the 'N' token clears all this info, so any text objects or paths which
02023     //  follow the bitmap were picking up colour and line info for an unfilled/unstroked path,
02024     //  rather than the current attributes.
02025     pDC->OutputToken    ( _T("F") );
02026     pDC->OutputNewLine  ();
02027 
02028     // The colours are no longer valid, as the bitmap definition has invalidated them.
02029     m_bValidPathAttrs = FALSE;
02030     m_bValidTextAttrs = FALSE;
02031 
02032     return TRUE;
02033 }
02034 
02035 
02036 /********************************************************************************************
02037 
02038 >   void AIEPSRenderRegion::OutputWindingRule ()
02039 
02040     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02041     Created:    19/12/00
02042     Purpose:    Output the winding rule used to AI EPS
02043 
02044 ********************************************************************************************/
02045 
02046 void AIEPSRenderRegion::OutputWindingRule ()
02047 {
02048     // Set up kernel DC up in an appropriate form.
02049     KernelDC    *pDC    = static_cast<KernelDC *> ( CCDC::ConvertFromNativeDC(RenderDC) );
02050 
02051     if (RR_WINDINGRULE() == EvenOddWinding)
02052     {
02053         // Even-Odd winding (Camelot's default)
02054         pDC->OutputValue ((INT32)1);
02055     }
02056     else if (RR_WINDINGRULE() == NonZeroWinding)
02057     {
02058         // Non-Zero winding (EPS's default)
02059         pDC->OutputValue ((INT32)0);
02060     }
02061     else
02062     {
02063         // Positive or negative winding (only Even-Odd and Non-Zero are supported in AI7),
02064         //  so assume that we're using camelot's default rule.
02065         pDC->OutputValue ((INT32)1);
02066     }
02067 
02068     pDC->OutputToken (_T("XR"));
02069     pDC->OutputNewLine ();
02070 }
02071 
02072 
02073 
02074 /********************************************************************************************
02075 
02076 >   void AIEPSRenderRegion::OutputLineWidth()
02077 
02078     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02079     Created:    1/11/00
02080     Purpose:    Output the standard line width token and measure for AI EPS
02081 
02082 ********************************************************************************************/
02083 
02084 void AIEPSRenderRegion::OutputLineWidth()
02085 {
02086     TCHAR buf [64];
02087 
02088     // Set line width
02089     if (ExportingOnPath ())
02090     {
02091         OverflowTextStartGap ();
02092         camSprintf (buf, _T("%.2f w\n"), ((double) RR_LINEWIDTH())/1000);
02093         OverflowTextWrite (buf);
02094     }
02095 
02096     EPSRenderRegion::OutputLineWidth ();
02097 }
02098 
02099 
02100 /********************************************************************************************
02101 
02102 >   void AIEPSRenderRegion::OutputJoinType()
02103 
02104     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02105     Created:    1/11/00
02106     Purpose:    Output the standard AI EPS join type
02107 
02108 ********************************************************************************************/
02109 
02110 void AIEPSRenderRegion::OutputJoinType()
02111 {
02112     TCHAR buf [64];
02113 
02114     // Set line Join Type
02115     if (ExportingOnPath ())
02116     {
02117         OverflowTextStartGap ();
02118         camSprintf (buf, _T("%d j\n"), (UINT32)RR_JOINTYPE());
02119         OverflowTextWrite (buf);
02120     }
02121 
02122     EPSRenderRegion::OutputJoinType ();
02123 }
02124 
02125 
02126 
02127 /********************************************************************************************
02128 
02129 >   void AIEPSRenderRegion::OutputDashPattern()
02130 
02131     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02132     Created:    1/11/00
02133     Purpose:    Outputs EPS dash pattern values. This function currently only exists so that
02134                 extra handling can be easily achieved for Illustrator EPS export of dash 
02135                 patterns in the future (if need be).
02136     SeeAlso:    EPSRenderRegion::OutputDashPattern ();
02137                 EPSRenderRegion::OutputDashPatternInit();
02138 
02139 ********************************************************************************************/
02140 
02141 void AIEPSRenderRegion::OutputDashPattern()
02142 {
02143     EPSRenderRegion::OutputDashPattern ();
02144 }
02145 
02146 
02147 /********************************************************************************************
02148 
02149 >   void AIEPSRenderRegion::OutputStartCap()
02150 
02151     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02152     Created:    1/11/00
02153     Purpose:    Output the start cap setting using the usual 'J' EPS token
02154 
02155 ********************************************************************************************/
02156 
02157 void AIEPSRenderRegion::OutputStartCap()
02158 {
02159     TCHAR buf [64];
02160 
02161     if (ExportingOnPath ())
02162     {
02163         OverflowTextStartGap ();
02164         camSprintf (buf, _T("%d J\n"), (UINT32)RR_STARTCAP());
02165         OverflowTextWrite (buf);
02166     }
02167 
02168     EPSRenderRegion::OutputStartCap ();
02169 }
02170 
02171 
02172 /********************************************************************************************
02173 
02174 >   void AIEPSRenderRegion::OutputMitreLimit()
02175 
02176     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02177     Created:    1/11/00
02178     Purpose:    Output the current mitre limit value using the usual 'M' EPS token.
02179                 Again, this is only here so that the AI export can be easily expanded or
02180                 modified.
02181 
02182 ********************************************************************************************/
02183 
02184 void AIEPSRenderRegion::OutputMitreLimit()
02185 {
02186     EPSRenderRegion::OutputMitreLimit ();
02187 }
02188 
02189 
02190 
02191 
02192 
02193 /********************************************************************************************
02194 
02195 >   void AIEPSRenderRegion::OutputStrokeColour()
02196 
02197     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02198     Created:    1/11/00
02199     Purpose:    Output the current stroke colour. This function will use one of the 
02200                 following EPS tokens
02201                 K - if not separating and colour is unnamed
02202                 X - if not separating and colour is named
02203                 G - if separating
02204     SeeAlso:    AIEPSRenderRegion::OutputFillColour
02205 
02206 ********************************************************************************************/
02207 
02208 void AIEPSRenderRegion::OutputStrokeColour()
02209 {
02210     // Write out the stroke colour
02211     EPSRenderRegion::OutputStrokeColour ();
02212 }
02213 
02214 
02215 
02216 
02217 
02218 
02219 
02220 
02221 /********************************************************************************************
02222 
02223 >   void AIEPSRenderRegion::OutputFontName()
02224 
02225     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02226     Created:    1/11/00
02227     Purpose:    Output an Illustrator format fontname and pointsize token. The format is    
02228                 /_fontname[-Bold|-Italic|-BoldItalic] pointsize Tf.
02229                 EncodeFontName will generate this format from an internal fontname.
02230                 DocodeFontName will return an internal format fontname and flags where nec.
02231 
02232 ********************************************************************************************/
02233 
02234 void AIEPSRenderRegion::OutputFontName()
02235 {
02236     if (ExportingOnPath ())
02237     {
02238         TCHAR buffer [64];
02239 
02240         OverflowTextStartGap ();
02241 
02242         String_64 FontName;
02243         String_64 EncodedFontName;
02244         String_64 Append(_T("/_"));
02245 
02246         // get information about the current font
02247         FONTMANAGER->GetFontName(RR_TXTFONTTYPEFACE(), FontName);
02248 
02249         // Graeme (31-3-00) - I've lifted this piece of code from the CamelotEPSRenderRegion. It
02250         // appears to map an existing, encoded font name onto its Postscript counterpart.
02251         FONTMANAGER->EncodeAndMapFontName(FontName, EncodedFontName, GetFontStyle());
02252         
02253         EncodedFontName.Insert(Append,0);
02254 
02255         // Output the fontsize next
02256         double PointSize = ((double)RR_TXTFONTSIZE())/1000;
02257         
02258         // finally do output the font token
02259         camSprintf (buffer, _T("%s %.1f Tf\n"), (TCHAR *)EncodedFontName, PointSize);
02260         OverflowTextWrite (buffer);
02261     }
02262     EPSRenderRegion::OutputFontName ();
02263 }
02264 
02265 
02266 
02267 /********************************************************************************************
02268 
02269 >   void AIEPSRenderRegion::OutputTextRenderMode()
02270 
02271     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02272     Created:    1/11/00
02273     Purpose:    Output the change in the text's Render Mode (Tr) - this happens when the 
02274                 text's fill or line colour changes to or from blank, see-through colour
02275 
02276 ********************************************************************************************/
02277 
02278 void AIEPSRenderRegion::OutputTextRenderMode ()
02279 {
02280     INT32 Style=0;
02281 
02282     if (ExportingOnPath ())
02283     {
02284         OverflowTextStartGap ();
02285 
02286         // Is there a currently active fill colour?
02287         if (! (RR_FILLCOLOUR().IsTransparent()) )
02288             Style+=1;
02289 
02290         // Is there a currently active line colour?
02291         if (! (RR_STROKECOLOUR().IsTransparent()) )
02292             Style+=2;
02293 
02294         switch (Style)
02295         {
02296             case 0: OverflowTextWrite (_T("3 Tr\n"));   // Invisible
02297                     break;
02298             case 1: OverflowTextWrite (_T("0 Tr\n"));   // filled only
02299                     break;
02300             case 2: OverflowTextWrite (_T("1 Tr\n"));   // stroked only
02301                     break;
02302             case 3: OverflowTextWrite (_T("2 Tr")); // filled and stroked
02303                     break;
02304         }
02305     }
02306 
02307     EPSRenderRegion::OutputTextRenderMode ();
02308 }
02309 
02310 
02311 
02312 /********************************************************************************************
02313 
02314 >   void AIEPSRenderRegion::OutputTextAspectRatio()
02315 
02316     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02317     Created:    1/11/00
02318     Purpose:    Output the change in the text's aspect ratio (Tz)
02319 
02320 ********************************************************************************************/
02321 
02322 void AIEPSRenderRegion::OutputTextAspectRatio ()
02323 {
02324     TCHAR buf [64];
02325 
02326     if (ExportingOnPath ())
02327     {
02328         OverflowTextStartGap ();
02329         camSprintf (buf, _T("%.0f Tz\n"), (RR_TXTASPECTRATIO().MakeDouble()*100.0));    // convert from ratio to %
02330         OverflowTextWrite (buf);
02331     }
02332 
02333     EPSRenderRegion::OutputTextAspectRatio ();
02334 }
02335 
02336 
02337 
02338 /********************************************************************************************
02339 
02340 >   void AIEPSRenderRegion::OutputTextTracking()
02341 
02342     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02343     Created:    1/11/00
02344     Purpose:    Output the change in the tracking (Tt)
02345 
02346 ********************************************************************************************/
02347 
02348 void AIEPSRenderRegion::OutputTextTracking ()
02349 {
02350     // Must be output in 1/1000 of an em.
02351     // 1 em = point size of font.
02352     // Tracking internally =millipoints.
02353     TCHAR buf [64];
02354 
02355     if (ExportingOnPath ())
02356     {
02357         OverflowTextStartGap ();
02358         camSprintf (buf, _T("%d Tt\n"), RR_TXTTRACKING());
02359         OverflowTextWrite (buf);
02360     }
02361 
02362     EPSRenderRegion::OutputTextTracking ();
02363 }
02364 
02365 
02366 
02367 /********************************************************************************************
02368 
02369 >   void EPSRenderRegion::OutputTextJustification()
02370 
02371     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02372     Created:    1/11/00
02373     Purpose:    Output the change in the text justification (Ta)
02374 
02375 ********************************************************************************************/
02376 
02377 void AIEPSRenderRegion::OutputTextJustification ()
02378 {
02379     TCHAR buf [64];
02380 
02381     if (ExportingOnPath ())
02382     {
02383         OverflowTextStartGap ();
02384 
02385         switch (RR_TXTJUSTIFICATION())
02386         {
02387         case JLEFT: 
02388             camSprintf (buf, _T("%d Ta\n"), ((INT32)0));
02389             break;
02390         case JRIGHT: 
02391             camSprintf (buf, _T("%d Ta\n"), ((INT32)2));
02392             break;
02393         case JCENTRE: 
02394             camSprintf (buf, _T("%d Ta\n"), ((INT32)1));
02395             break;
02396         case JFULL: 
02397             camSprintf (buf, _T("%d Ta\n"), ((INT32)3));
02398             break;
02399         }
02400         OverflowTextWrite (buf);
02401     }
02402 
02403     EPSRenderRegion::OutputTextJustification ();
02404 }
02405 
02406 /********************************************************************************************
02407 
02408 >   void AIEPSRenderRegion::OutputTextLineSpacing()
02409 
02410     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02411     Created:    1/11/00
02412     Purpose:    Output the change in the line spacing (Tl)
02413 
02414 ********************************************************************************************/
02415 
02416 void AIEPSRenderRegion::OutputTextLineSpacing ()
02417 {
02418 
02419     if (ExportingOnPath ())
02420     {
02421         TCHAR buf [64];
02422 
02423         OverflowTextStartGap ();
02424 
02425         // Output line spacing in points.
02426         // format - paraspace linespace Tl
02427         double ptLineSpace;
02428         double ptParaSpace=0;
02429 
02430         TxtLineSpaceAttribute* pLineSpace = (TxtLineSpaceAttribute*)(CurrentAttrs[ATTR_TXTLINESPACE].pAttr);
02431 
02432         // There are some rules for reading the linespacing value which I shall divulge
02433         // If IsARation is true then use the proportinal linespacing value.
02434         // else use the absolute linespacing
02435         // However if the absolute linespacing is zero, then we MUST use the proportional
02436         // linespacing. Eeek!
02437         // ie it is an error if (absolute==0 && !IsARatio()) which we will check for here
02438 
02439         double FontSize = (double)RR_TXTFONTSIZE();                 // in millipoints    12pt = 12000 mp
02440         double absLineSpace = (double)pLineSpace->Value;
02441         double proLineSpace = (pLineSpace->Ratio).MakeDouble();
02442 
02443         BOOL Proportional = pLineSpace->IsARatio();
02444 
02445         if (!Proportional && absLineSpace==0)
02446         {
02447             ERROR3("Absolute line spacing is zero yet IsARatio() is FALSE, in GetValidTextAttributes()");
02448             // Make sure we use the proportional value no matter what.
02449             Proportional=TRUE;
02450         }
02451 
02452         if (Proportional)
02453             ptLineSpace = FontSize*proLineSpace/1000;
02454         else
02455             ptLineSpace = absLineSpace/1000;
02456 
02457         camSprintf (buf, _T("%.0f %.0f Tl\n"), ptLineSpace, ptParaSpace);
02458         OverflowTextWrite (buf);
02459     }
02460 
02461     EPSRenderRegion::OutputTextLineSpacing ();
02462 }
02463 
02464 
02465 /********************************************************************************************
02466 
02467 >   void AIEPSRenderRegion::OutputTextBaselineShift()
02468 
02469     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02470     Created:    1/11/00
02471     Purpose:    Output the change in Baseline shift (Ts)
02472 
02473 ********************************************************************************************/
02474 
02475 void AIEPSRenderRegion::OutputTextBaselineShift ()
02476 {
02477     TCHAR buf [64];
02478 
02479     // Output baseline shift in points
02480     // format = rise Ts
02481     if (ExportingOnPath ())
02482     {
02483         OverflowTextStartGap ();
02484         double BaseLine = ((double)RR_TXTBASELINE())/1000;
02485         camSprintf (buf, _T("%.1f Ts\n"), BaseLine);
02486         OverflowTextWrite (buf);
02487     }
02488 
02489     EPSRenderRegion::OutputTextBaselineShift ();
02490 }
02491 
02492 
02493 /********************************************************************************************
02494 
02495 >   void AIEPSRenderRegion::OutputTextSubSuperScript()
02496 
02497     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02498     Created:    1/11/00
02499     Purpose:    Output the change in the Sub/Super script attribute (Ts)
02500 
02501 ********************************************************************************************/
02502 
02503 void AIEPSRenderRegion::OutputTextSubSuperScript ()
02504 {
02505     TCHAR buf [64];
02506     
02507     if (ExportingOnPath ())
02508     {
02509         OverflowTextStartGap ();
02510 
02511         // Output sub/superscript
02512         // in millipoints    12pt = 12000 mp
02513         double FontSize = ((double)RR_TXTFONTSIZE())/1000;
02514 
02515         TxtScriptAttribute* pScript = RR_TXTSCRIPT();
02516         double offset = (pScript->Offset).MakeDouble();
02517         double size = (pScript->Size).MakeDouble();
02518 
02519         OverflowTextWrite (_T("%%XSScript\n"));
02520 
02521         double rise = FontSize*offset;
02522 
02523         camSprintf (buf, _T("%.1f Ts\n"), rise);
02524         OverflowTextWrite (buf);
02525 
02526         double ptsize = FontSize*size;
02527 
02528         String_64 MappedFont;
02529         String_64 Append(_T("/_"));
02530 
02531         String_64 FontName;
02532         FONTMANAGER->GetFontName(RR_TXTFONTTYPEFACE(), FontName);
02533 
02534         // Graeme (31-3-00) - Map the encoded name onto the PS font name.
02535         FONTMANAGER->EncodeAndMapFontName(FontName,MappedFont,GetFontStyle());
02536 
02537         // Graeme (14-6-00) - I should add ascent and descent values, but Camelot doesn't
02538         // seem to store them anywhere.
02539         MappedFont.Insert(Append,0);
02540 
02541         camSprintf (buf, _T("%s %.1f Tf\n"),(TCHAR *)MappedFont, ptsize);
02542         // Output the ascent.
02543         // Output the descent.
02544         OverflowTextWrite (buf);
02545     }
02546 
02547     EPSRenderRegion::OutputTextSubSuperScript ();
02548 }
02549 
02550 /*------------*/
02551 
02552 
02553 
02554 //----------------------------------------------------------------
02555 //
02556 //  The following functions are all overflow text functions,
02557 //  which write an additional text line, terminated with the 
02558 //  token (TX), to the EPS file, the Output functions declared
02559 //  earlier should call these functions to add any attribute 
02560 //  changes, so that the two text blocks remain consistent.
02561 //
02562 //----------------------------------------------------------------
02563 
02564 
02565 /********************************************************************************************
02566 
02567 >   void AIEPSRenderRegion::ExportingOnPath()
02568 
02569     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02570     Created:    2/11/00
02571     Returns:    TRUE - yes, we are exporting on a path
02572                 FALSE - no, we aren't exporting on a path
02573     Purpose:    To determine whether this text is being exported on a path.
02574     SeeAlso:    
02575 
02576 ********************************************************************************************/
02577 
02578 BOOL AIEPSRenderRegion::ExportingOnPath ()
02579 {
02580     if (m_fpOverflowText)
02581         return TRUE;
02582     else
02583         return FALSE;
02584 }
02585 
02586 
02587 /********************************************************************************************
02588 
02589 >   void AIEPSRenderRegion::OverflowTextStart()
02590 
02591     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02592     Created:    1/11/00
02593     Purpose:    Start the overflow text block.
02594     SeeAlso:    
02595 
02596 ********************************************************************************************/
02597 
02598 void AIEPSRenderRegion::OverflowTextStart ()
02599 {
02600         // open overflow file
02601     m_fpOverflowText = fopen ("OverFlow.txt", "w");
02602 
02603     // write out start info - NOTE: we're currently in a gap from writing the initial 
02604     //  attributes, so we're going to have to close it.
02605     m_bInTextGap = TRUE;
02606 }
02607 
02608 
02609 /********************************************************************************************
02610 
02611 >   void AIEPSRenderRegion::OverflowTextFinish()
02612 
02613     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02614     Created:    1/11/00
02615     Purpose:    Finish the overflow text block and write both blocks to the actual EPS file.
02616     SeeAlso:    
02617 
02618 ********************************************************************************************/
02619 
02620 void AIEPSRenderRegion::OverflowTextFinish ()
02621 {
02622     ASSERT (m_fpOverflowText);
02623 
02624         // write out final information.
02625     OverflowTextStartGap ();
02626 
02627         // close files.
02628     fclose (m_fpOverflowText);
02629     m_fpOverflowText = NULL;
02630 
02631     // copy info into actual EPS file.
02632     char cbuffer [1025];
02633     TCHAR buffer [1025];
02634     KernelDC *pDC = (KernelDC*)CCDC::ConvertFromNativeDC(RenderDC);
02635     FILE * fp;
02636 
02637         // Write out the Extra info.
02638     fp = fopen ("OverFlow.txt", "r+t");
02639 
02640     while (fgets (cbuffer, 1024, fp) != NULL)
02641     {
02642         char c;
02643         INT32 i=0;
02644         cbuffer[1024]=0;
02645         do
02646         {
02647             c=cbuffer[i];
02648             buffer[i]=c; // 1:1 CHAR->TCHAR conversion
02649             i++;
02650         } while (c);
02651             
02652         // deal with newlines.
02653         pDC->OutputToken (buffer);
02654         pDC->OutputNewLine ();
02655     }
02656     fclose (fp);
02657 
02658 
02659         // clean up temp. files
02660     remove ("OverFlow.txt");
02661 }
02662 
02663 /********************************************************************************************
02664 
02665 >   void AIEPSRenderRegion::OverflowTextStartGap()
02666 
02667     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02668     Created:    2/11/00
02669     Purpose:    Starts a new gap in the Overflow text, so that attributes can be written into
02670                 the overflow blocks (the TX ones)
02671     SeeAlso:    AIEPSRenderRegion::OverflowTextFinishGap ()
02672 
02673 ********************************************************************************************/
02674 
02675 void AIEPSRenderRegion::OverflowTextStartGap ()
02676 {
02677     ASSERT (ExportingOnPath ());
02678 
02679     // if we're not in a gap, finish writing the old TX block and start a new gap, 
02680     if (m_bInTextGap == FALSE)
02681     {
02682         OverflowTextWrite (_T(") TX\n"));
02683         m_bInTextGap = TRUE;
02684     }
02685 }
02686 
02687 /********************************************************************************************
02688 
02689 >   void AIEPSRenderRegion::OverflowTextFinishGap()
02690 
02691     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02692     Created:    2/11/00
02693     Purpose:    Closes a gap for writing attributes in the overflow text, so that a new line 
02694                 of overflow text can be started.
02695     SeeAlso:    AIEPSRenderRegion::OverflowTextStartGap ();
02696 
02697 ********************************************************************************************/
02698 
02699 void AIEPSRenderRegion::OverflowTextFinishGap ()
02700 {
02701     ASSERT (ExportingOnPath ());
02702 
02703     // if we're in a text gap (for changing the attributes), start writing a new TX block.
02704     if (m_bInTextGap == TRUE)
02705     {
02706         OverflowTextWrite (_T("("));
02707         m_bInTextGap = FALSE;
02708     }
02709 }
02710 
02711 
02712 /********************************************************************************************
02713 
02714 >   void AIEPSRenderRegion::OverflowTextWrite()
02715 
02716     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02717     Created:    1/11/00
02718     Purpose:    Write some text to the overflow body file. This will store all the text and
02719                 modified attributes for the TX text block.
02720     SeeAlso:    
02721 
02722 ********************************************************************************************/
02723 
02724 void AIEPSRenderRegion::OverflowTextWrite (TCHAR * text)
02725 {
02726     ASSERT (ExportingOnPath ());
02727     while (*text)
02728     {
02729         fprintf (m_fpOverflowText, "%c", *text++);
02730     }
02731 }
02732 
02733 
02734 /********************************************************************************************
02735 
02736 >   BOOL AIEPSRenderRegion::OverflowTextWriteSingleColour (UINT32 n)
02737 
02738     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02739     Created:    3/11/00
02740     Inputs:     n - the colour value (range 0-255) to write to the EPS file.
02741     Purpose:    Output a colour value to the overflow text file.  A 'single colour' is a value
02742                 as used in the Camelot 'Colour' class, i.e. in the range 0 to 255.
02743                 This range is converted to the range 0.0 to 1.0, and output to the file.
02744     SeeAlso:    KernelDC::OutputColourValue
02745 
02746 ********************************************************************************************/
02747 
02748 void AIEPSRenderRegion::OverflowTextWriteSingleColour (UINT32 n)
02749 {
02750     // Output to string
02751     TCHAR buf[20];
02752 
02753     // Convert to points, getting integer and fractional parts
02754     camSprintf (buf, _T("%.2f "), ((double) n) / 255);
02755     OverflowTextWrite (buf);
02756 }
02757 
02758 /********************************************************************************************
02759 
02760 >   BOOL AIEPSRenderRegion::OverflowTextWriteColour(PColourCMYK *pCol)
02761 
02762     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02763     Created:    3/11/00
02764     Inputs:     Col - the CMYK colour values to be output.
02765     Purpose:    Output a colour, as expressed by the Camelot 'Colour' class.  This function
02766                 takes the CMYK variation, is this is most appropriate to EPS files.
02767                 Camelot colour values are converted from the 0-255 range to the 0.0-1.0
02768                 range before being output.
02769 
02770                 e.g.
02771                 MonoOn
02772                     PColourCMYK Col = { 255, 255, 128, 0 };
02773                     pDC->OutputColour(&Col);
02774                 MonoOff
02775                 will give the following output:
02776                 MonoOn
02777                     1.0 1.0 0.5 0.0
02778                 MonoOff
02779     SeeAlso:    KernelDC::OutputColourValue
02780     Errors:     Disk/file error => ERROR1
02781 
02782 ********************************************************************************************/
02783 
02784 void AIEPSRenderRegion::OverflowTextWriteColour (PColourCMYK *pCol)
02785 {
02786     // Write each of the colour values.
02787     OverflowTextWriteSingleColour (pCol->Cyan);
02788     OverflowTextWriteSingleColour (pCol->Magenta);
02789     OverflowTextWriteSingleColour (pCol->Yellow);
02790     OverflowTextWriteSingleColour (pCol->Key);
02791 }
02792 
02793 /********************************************************************************************
02794 
02795 >   void AIEPSRenderRegion::OverflowTextWriteNamedColour    (DocColour *pCol, 
02796                                                             ColourContext* pContext = NULL)
02797 
02798     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
02799     Created:    09/08/94
02800     Inputs:     pCol - the colour to output.
02801                 pContext - the context to use to convert the colour before output.
02802                            if this is NULL the default CMYK context will be used.
02803     Returns:    TRUE if the data was written ok;
02804                 FALSE if not => ERROR1
02805     Purpose:    Similar to OutputColour(), except it outputs the colour name and tint
02806                 of the colour as well.  If pCol does not reference an indexed colour,
02807                 then the name "NoName" is used.
02808     SeeAlso:    KernelDC::OutputColour
02809     Errors:     Disk/file error => ERROR1
02810 
02811 ********************************************************************************************/
02812 
02813 void AIEPSRenderRegion::OverflowTextWriteNamedColour(DocColour *pCol, ColourContext* pContext)
02814 {
02815     // Get CMYK version of this colour.
02816     PColourCMYK CMYK;
02817     pCol->GetCMYKValue(pContext, &CMYK);
02818 
02819     // Output CMYK version
02820     OverflowTextWriteColour (&CMYK);
02821         
02822     // Get the indexed colour from the DocColour.
02823     IndexedColour *pIndCol = pCol->FindParentIndexedColour();
02824 
02825     // Cope with the unexpected!
02826 //  ENSURE(pIndCol != NULL, "Named colour has no index colour!");
02827 
02828     if (pIndCol == NULL)
02829     {
02830         if (pCol->IsTransparent())
02831         {
02832             // This is a 'no colour' type colour, so output a zero-length colour name,
02833             // as this is the only way we can handle this at the moment.
02834             return;
02835         }
02836         else
02837         {
02838             // Otherwise make up a colour name (see epsfiltr.h).
02839             OverflowTextWrite (_T("("));
02840             OverflowTextWrite (ImmediateColourFudgeyBodgeName);
02841             OverflowTextWrite (_T(")"));
02842         }
02843     }
02844     else
02845     {
02846         // Got an indexed colour - output its name
02847         // (Pass in TRUE to get a unique-identifier for local colours rather than "Local colour")
02848         String_64 *ColName = pIndCol->GetName(TRUE);
02849         OverflowTextWrite (_T("("));
02850         OverflowTextWrite ((TCHAR *) (*ColName));
02851         OverflowTextWrite (_T(")"));
02852     }
02853 
02854     // Always tint 0
02855     OverflowTextWrite (_T(" 0 "));
02856 }
02857 
02858 /********************************************************************************************
02859 
02860 >   void AIEPSRenderRegion::OverflowTextWriteColourName (DocColour *pCol)
02861 
02862     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02863     Created:    18/12/00
02864     Inputs:     pCol - the colour to output.
02865     Purpose:    Outputs a named colour's name as a string. If pCol does not reference an 
02866                 indexed colour, then the name "NoName" is used. This was seperated from 
02867                 OutputNamedColour so that the DeviceContext will not need to worry about
02868                 which ColourModel to use (CMYK, RGB, etc...), as this will be determined 
02869                 by the RenderRegion.
02870     SeeAlso:    KernelDC::OutputNamedColour
02871     Errors:     Disk/file error => ERROR1
02872 
02873 ********************************************************************************************/
02874 
02875 void AIEPSRenderRegion::OverflowTextWriteColourName (DocColour *pCol)
02876 {
02877     // Get the indexed colour from the DocColour.
02878     IndexedColour *pIndCol = pCol->FindParentIndexedColour();
02879 
02880     if (pIndCol == NULL)
02881     {
02882         if (pCol->IsTransparent())
02883         {
02884             // This is a 'no colour' type colour, so output a zero-length colour name,
02885             // as this is the only way we can handle this at the moment.
02886             OverflowTextWrite (_T("()"));
02887         }
02888         else
02889         {
02890             // Otherwise make up a colour name (see epsfiltr.h).
02891             OverflowTextWrite (_T("("));
02892             OverflowTextWrite (ImmediateColourFudgeyBodgeName);
02893             OverflowTextWrite (_T(")"));
02894         }
02895     }
02896     else
02897     {
02898         // Got an indexed colour - output its name
02899         // (Pass in TRUE to get a unique-identifier for local colours rather than "Local colour")
02900         String_64 *ColName = pIndCol->GetName(TRUE);
02901         OverflowTextWrite (_T("("));
02902         OverflowTextWrite ((TCHAR *) (*ColName));
02903         OverflowTextWrite (_T(")"));
02904     }
02905 }
02906 
02907 
02908 
02909 
02910 
02911 /********************************************************************************************
02912 
02913 >   virtual void AIEPSRenderRegion::SetClipRegion(ClipRegionAttribute* pClipAttr, BOOL Temp)
02914 
02915     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02916     Created:    8th November 2000
02917     Inputs:     pClipAttr   ptr to the new ClipRegionAttribute to set as current in our RR.
02918                 Temp        whether the attr is temporary or not.
02919 
02920     Outputs:    Postscript's context is saved and the commands are output to intersect its
02921                 current clipping path with that defined by the ClipAttr.
02922                 Also, the RR's current attr context is updated to use this new ClipAttr.
02923 
02924     Purpose:    The Adobe Illustrator version of Karim's EPSRenderRegion::SetClipRegion,
02925                 This was needed as Illustrator uses non-standard EPS commands
02926                 
02927                 Shrink the RR's clipping region to the region defined by pClipAttr.
02928                 We do this by:
02929                     1.  Recording a save-state command.
02930                     2.  Exporting a description of the clipping path in pClipAttr.
02931                     3.  Recording a 'clip-to-last-path' command.
02932                     4.  Recording a 'start-new-path' command, as we don't want our clip-path
02933                         to get stroked or rendered in any way.
02934 
02935     Notes:      We mustn't record clipping commands when rendering the default attribute.
02936                 Therefore this method does *nothing whatsoever* unless pClipAttr's ptr to
02937                 its clipping-path is non-NULL. This ptr is NULL in the default attr.
02938 
02939     See also:   RenderRegion::SetClipRegion(), EPSRenderRegion::SetClipRegion()
02940 
02941 ********************************************************************************************/
02942 void AIEPSRenderRegion::SetClipRegion(ClipRegionAttribute* pClipAttr, BOOL Temp)
02943 {
02944     if (pClipAttr->GetClipPath() != NULL)
02945     {
02946         // Update the RR's table of current attributes.
02947         RenderRegion::SetClipRegion (pClipAttr, Temp);
02948 
02949         // Write out the clipping path as a mask.
02950         WriteMask(pClipAttr->GetClipPath(), pClipAttr->IsResponsibleForGrouping ());
02951     }
02952 }
02953 
02954 
02955 
02956 /********************************************************************************************
02957 
02958 >   virtual void AIEPSRenderRegion::RestoreClipRegion(ClipRegionAttribute* pClipAttr, BOOL Temp)
02959 
02960     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02961     Created:    8th November 2000
02962     Inputs:     pClipAttr   ptr to the ClipRegionAttribute to restore over the current one.
02963                 Temp        whether the attr is temporary or not.
02964 
02965     Outputs:    Postscript is told to restore its last saved context.
02966 
02967     Purpose:    Adobe Illustrator version of Karim's EPSRenderRegion::RestoreClipRegion.
02968                 See SetClipRegion for why this was necessary.
02969     
02970                 Restore the RR's clipping region.
02971                 We do this by recording a restore-state command.
02972 
02973     Errors:     ERROR3 if the current ClipRegionAttribute holds a NULL clip-path ptr.
02974                 This state of affairs should not happen. You can't set a ClipRegionAttribute
02975                 with a NULL clip-path ptr, so the only such attr is the default one, and you
02976                 should never be restoring over _that_.
02977 
02978     See also:   RenderRegion::RestoreClipRegion(), EPSRenderRegion::RestoreClipRegion()
02979 
02980 ********************************************************************************************/
02981 
02982 void AIEPSRenderRegion::RestoreClipRegion(ClipRegionAttribute* pClipAttr, BOOL Temp)
02983 {
02984     // we should never be entered when the current clipattr has a NULL path, as what this
02985     // means is that either somebody somehow did a SetClipRegion() with such an attr, or
02986     // somebody is trying to Restore() over the default ClipRegionAttribute (which holds a
02987     // NULL path ptr). Neither of these actions should occur.
02988 
02989     if (RR_CLIPREGION()->GetClipPath() == NULL)
02990     {
02991         ERROR3("EPSRenderRegion::RestoreClipRegion; Current ClipRegionAttribute has a NULL path");
02992     }
02993     else
02994     {
02995         // Update the RR's table of current attributes.
02996         RenderRegion::RestoreClipRegion(pClipAttr, Temp);
02997     }
02998 }
02999 
03000 
03001 /********************************************************************************************
03002 
03003 >   virtual void AIEPSRenderRegion::SetTextAsShapes (BOOL shapes)
03004 
03005     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
03006     Created:    8th November 2000
03007     Inputs:     shapes - whether to export text as shapes (TRUE) or characters (FALSE)
03008 
03009     Purpose:    Sets the export TextAsShapes flag
03010 
03011     See also:   AIEPSRenderRegion::RenderChar(), TextStory::PreExportRender, 
03012                 TextStory::ExportRender
03013 
03014 ********************************************************************************************/
03015 
03016 void AIEPSRenderRegion::SetTextAsShapes (BOOL shapes)
03017 {
03018     m_bTextAsShapes = shapes;
03019 }
03020 
03021 
03022 /********************************************************************************************
03023 
03024 >   virtual BOOL AIEPSRenderRegion::GetTextAsShapes ()
03025 
03026     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
03027     Created:    8th November 2000
03028     Returns:    BOOL - whether text is exported as shapes (TRUE) or characters (FALSE)
03029 
03030     Purpose:    Sets the export TextAsShapes flag
03031 
03032     See also:   AIEPSRenderRegion::GetTextAsShapes
03033 
03034 ********************************************************************************************/
03035 
03036 BOOL AIEPSRenderRegion::GetTextAsShapes ()
03037 {
03038     return m_bTextAsShapes;
03039 }
03040 
03041 
03042 /********************************************************************************************
03043 
03044 >   virtual BOOL AIEPSRenderRegion::WriteNewLine ()
03045 
03046     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
03047     Created:    9th November 2000
03048     Returns:    BOOL - whether the a new line was written successfully.
03049 
03050     Purpose:    Writes a new line to the output of text if text is exported as characters, 
03051                 does nothing if it's exported as shapes.
03052 
03053     See also:   EPSRenderRegion::WriteNewLine
03054 
03055 ********************************************************************************************/
03056 
03057 BOOL AIEPSRenderRegion::WriteNewLine ( void )
03058 {
03059     BOOL success;
03060 
03061     // don't write any newlines if we're exporting text as shapes (cos' it could stuff up 
03062     //  the eps).
03063     if (GetTextAsShapes () == TRUE)
03064     {
03065         success = TRUE;
03066     }
03067     else
03068     {
03069         success = EPSRenderRegion::WriteNewLine ();
03070     }
03071 
03072     return success;
03073 }
03074 
03075 
03076 
03077 /********************************************************************************************
03078 
03079 >   virtual void AIEPSRenderRegion::OutputFillRGBColour ()
03080 
03081     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
03082     Created:    18/12/00
03083     Purpose:    Writes additional info to the file for RGB fill colours 
03084     See also:   EPSRenderRegion::OutputFillRGBColour
03085 
03086 ********************************************************************************************/
03087 
03088 void AIEPSRenderRegion::OutputFillRGBColour ()
03089 {
03090     // NOTE: We need to export any changes to the overflow text here, 
03091     // as it's the last place we can catch the colour change.
03092     if (ExportingOnPath ())
03093     {
03094         OverflowTextStartGap ();
03095 
03096         // Colour values.
03097         INT32 red;
03098         INT32 green;
03099         INT32 blue;
03100         PColourCMYK CMYK;
03101 
03102         // Assume no local context at present - used as a check to make sure that we 
03103         //  aren't exporting as seperations.
03104         ColourContext* pContext;
03105         ColourPlate* pSeparation;
03106         GetOutputColourPlate (COLOURMODEL_CMYK, &pContext, &pSeparation);
03107 
03108         if (pSeparation==NULL)
03109         {
03110             // As expected, we ain't using seperations, so we can output as RGB.
03111 
03112             // Get the current line colour in RGB values and print them out.
03113             RR_FILLCOLOUR().GetRGBValue (&red, &green, &blue);
03114             OverflowTextWriteSingleColour (red);
03115             OverflowTextWriteSingleColour (green);
03116             OverflowTextWriteSingleColour (blue);
03117 
03118             if (RR_FILLCOLOUR().FindParentIndexedColour() == NULL)
03119             {
03120                 // Unnamed colour - just add 'Xa' token
03121                 OverflowTextWrite (_T("Xa\n"));
03122             }
03123             else
03124             {
03125                 // Named colour - add Name, tint value, RGB flag and 'Xx' token
03126                 OverflowTextWriteColourName (&(RR_FILLCOLOUR()));
03127                 OverflowTextWrite (_T(" 0 1 Xx\n"));
03128             }
03129         }
03130         else
03131         {
03132             // Since we are seperating the colours, then use CMYK mode.
03133 
03134             // Assume unnamed colour as 'g' grey fill operator does
03135             // not allow for custom greys.
03136             if (pSeparation->IsMonochrome())
03137             {
03138                 RR_FILLCOLOUR().GetCMYKValue(pContext, &CMYK);
03139                 BYTE c = 0xFF - CMYK.Key;
03140                 OverflowTextWriteSingleColour (c);
03141                 OverflowTextWrite (_T("g\n"));
03142             }
03143             else
03144             {
03145                 RR_FILLCOLOUR().GetCMYKValue(pContext, &CMYK);
03146                 OverflowTextWriteColour (&CMYK);
03147                 OverflowTextWrite (_T("x\n"));
03148             }
03149         }
03150     }
03151 
03152     // Write out the usual EPS colour tokens.
03153     EPSRenderRegion::OutputFillRGBColour ();
03154 }
03155 
03156 /********************************************************************************************
03157 
03158 >   virtual void AIEPSRenderRegion::OutputFillCMYKColour ()
03159 
03160     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
03161     Created:    18/12/00
03162     Purpose:    Writes additional info to the file for CMYK fill colours 
03163     See also:   EPSRenderRegion::OutputFillCMYKColour
03164 
03165 ********************************************************************************************/
03166 
03167 void AIEPSRenderRegion::OutputFillCMYKColour ()
03168 {
03169     // NOTE: We need to export any changes to the overflow text here, 
03170     // as it's the last place we can catch the colour change.
03171     if (ExportingOnPath ())
03172     {
03173         PColourCMYK CMYK;
03174 
03175         OverflowTextStartGap ();
03176 
03177         // Assume no local context at present
03178         ColourContext* pContext;
03179         ColourPlate* pSeparation;
03180         GetOutputColourPlate(COLOURMODEL_CMYK, &pContext, &pSeparation);
03181 
03182         if (pSeparation==NULL)
03183         {
03184             // Get the current line colour in CMYK values, unless it's transparent
03185             // Print out colour component values.
03186             if (RR_FILLCOLOUR().FindParentIndexedColour() == NULL)
03187             {
03188                 // Unnamed colour
03189                 // retrieve the colour value
03190                 RR_FILLCOLOUR().GetCMYKValue(pContext, &CMYK);
03191                 OverflowTextWriteColour (&CMYK);
03192                 OverflowTextWrite (_T("k\n"));
03193             }
03194             else
03195             {
03196                 // Named colour
03197                 OverflowTextWriteNamedColour (&(RR_FILLCOLOUR()), pContext);
03198                 OverflowTextWrite (_T("x\n"));
03199             }
03200         }
03201         else
03202         {
03203             // Assume unnamed colour as 'g' grey fill operator does
03204             // not allow for custom greys.
03205             if (pSeparation->IsMonochrome())
03206             {
03207                 RR_FILLCOLOUR().GetCMYKValue(pContext, &CMYK);
03208                 BYTE c = 0xFF - CMYK.Key;
03209                 OverflowTextWriteSingleColour (c);
03210                 OverflowTextWrite (_T("g\n"));
03211             }
03212             else
03213             {
03214                 RR_FILLCOLOUR().GetCMYKValue(pContext, &CMYK);
03215                 OverflowTextWriteColour (&CMYK);
03216                 OverflowTextWrite (_T("x\n"));
03217             }
03218         }
03219     }
03220 
03221     // Call the base class to write the ordinary info out
03222     EPSRenderRegion::OutputFillCMYKColour ();
03223 }
03224 
03225 /********************************************************************************************
03226 
03227 >   virtual void AIEPSRenderRegion::OutputStrokeRGBColour ()
03228 
03229     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
03230     Created:    18/12/00
03231     Purpose:    Writes additional info to the file for RGB stroke colours 
03232     See also:   EPSRenderRegion::OutputStrokeRGBColour
03233 
03234 ********************************************************************************************/
03235 
03236 void AIEPSRenderRegion::OutputStrokeRGBColour ()
03237 {   
03238     // NOTE: We need to export any changes to the overflow text here, 
03239     // as it's the last place we can catch the colour change.
03240     if (ExportingOnPath ())
03241     {
03242         OverflowTextStartGap ();
03243 
03244         // Colour values.
03245         INT32 red;
03246         INT32 green;
03247         INT32 blue;
03248         PColourCMYK CMYK;
03249 
03250         // Assume no local context at present - used as a check to make sure that we 
03251         //  aren't exporting as seperations.
03252         ColourContext* pContext;
03253         ColourPlate* pSeparation;
03254         GetOutputColourPlate (COLOURMODEL_CMYK, &pContext, &pSeparation);
03255 
03256         if (pSeparation==NULL)
03257         {
03258             // As expected, we ain't using seperations, so we can output as RGB.
03259 
03260             // Get the current line colour in RGB values and print them out.
03261             RR_STROKECOLOUR().GetRGBValue (&red, &green, &blue);
03262             OverflowTextWriteSingleColour (red);
03263             OverflowTextWriteSingleColour (green);
03264             OverflowTextWriteSingleColour (blue);
03265 
03266             if (RR_STROKECOLOUR().FindParentIndexedColour() == NULL)
03267             {
03268                 // Unnamed colour - just add 'XA' token
03269                 OverflowTextWrite (_T("XA\n"));
03270             }
03271             else
03272             {
03273                 // Named colour - add Name, tint value, RGB flag and 'XX' token
03274                 OverflowTextWriteColourName (&(RR_STROKECOLOUR()));
03275                 OverflowTextWrite (_T(" 0 1 XX\n"));
03276             }
03277         }
03278         else
03279         {
03280             // Since we are seperating the colours, then use CMYK mode.
03281 
03282             // Assume unnamed colour as 'g' grey fill operator does
03283             // not allow for custom greys.
03284             if (pSeparation->IsMonochrome())
03285             {
03286                 RR_STROKECOLOUR().GetCMYKValue(pContext, &CMYK);
03287                 BYTE c = 0xFF - CMYK.Key;
03288                 OverflowTextWriteSingleColour (c);
03289                 OverflowTextWrite (_T("G\n"));
03290             }
03291             else
03292             {
03293                 RR_STROKECOLOUR().GetCMYKValue(pContext, &CMYK);
03294                 OverflowTextWriteColour (&CMYK);
03295                 OverflowTextWrite (_T("X\n"));
03296             }
03297         }
03298     }
03299 
03300     // Call the base class to process the colour normally (i.e. to the EPS file itself)
03301     EPSRenderRegion::OutputStrokeRGBColour ();
03302 }
03303 
03304 
03305 /********************************************************************************************
03306 
03307 >   virtual void AIEPSRenderRegion::OutputStrokeCMYKColour ()
03308 
03309     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
03310     Created:    18/12/00
03311     Purpose:    Writes additional info to the file for CMYK fill colours 
03312     See also:   EPSRenderRegion::OutputFillCMYKColour
03313 
03314 ********************************************************************************************/
03315 
03316 void AIEPSRenderRegion::OutputStrokeCMYKColour ()
03317 {
03318     // Write out the colour to the overflow file if we're doing text on a path.
03319     if (ExportingOnPath ())
03320     {
03321         PColourCMYK CMYK;
03322         OverflowTextStartGap ();
03323 
03324         // Assume no local context at present
03325         ColourContext* pContext;
03326         ColourPlate* pSeparation;
03327         GetOutputColourPlate(COLOURMODEL_CMYK, &pContext, &pSeparation);
03328 
03329         if (pSeparation==NULL)
03330         {
03331             // Get the current line colour in CMYK values, unless it's transparent
03332             // Print out colour component values.
03333             if (RR_STROKECOLOUR().FindParentIndexedColour() == NULL)
03334             {
03335                 // Unnamed colour
03336                 // retrieve the colour value
03337                 RR_STROKECOLOUR().GetCMYKValue(pContext, &CMYK);
03338                 OverflowTextWriteColour (&CMYK);
03339                 OverflowTextWrite (_T("K\n"));
03340             }
03341             else
03342             {
03343                 // Named colour
03344                 OverflowTextWriteNamedColour (&(RR_STROKECOLOUR()), pContext);
03345                 OverflowTextWrite (_T("X\n"));
03346             }
03347         }
03348         else
03349         {
03350             // Assume unnamed colour as 'g' grey fill operator does
03351             // not allow for custom greys.
03352             if (pSeparation->IsMonochrome())
03353             {
03354                 RR_STROKECOLOUR().GetCMYKValue(pContext, &CMYK);
03355                 BYTE c = 0xFF - CMYK.Key;
03356                 OverflowTextWriteSingleColour (c);
03357                 OverflowTextWrite (_T("G\n"));
03358             }
03359             else
03360             {
03361                 RR_STROKECOLOUR().GetCMYKValue(pContext, &CMYK);
03362                 OverflowTextWriteColour (&CMYK);
03363                 OverflowTextWrite (_T("X\n"));
03364             }
03365         }
03366     }
03367 
03368     // Call the base class to write out the ordinary information
03369     EPSRenderRegion::OutputStrokeCMYKColour ();
03370 }
03371 
03372 
03373 /********************************************************************************************
03374 
03375 >   virtual BOOL AIEPSRenderRegion::IsGradientFillValidForExport ()
03376 
03377     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
03378     Created:    15/01/01
03379     Purpose:    Determines whether a particular fill can be used through the AI export
03380     See also:   AIEPSRenderRegion::WriteGradientFills, AIEPSRenderRegion::WriteGradientUsage
03381 
03382 ********************************************************************************************/
03383 BOOL AIEPSRenderRegion::IsGradientFillValidForExport (FillGeometryAttribute * pFill)
03384 {
03385     BOOL acceptable = FALSE;
03386 
03387     if ( pFill->IsAColourFill () &&         // Is it a colour fill?
03388          pFill->IsAGradFill () &&           // Is it a graduated fill?
03389          ! (pFill->IsAFractalFill ()) &&    // Is it not a fractal (clouds) fill?
03390          ! (pFill->IsANoiseFill ()) &&      // Is it not a fractal (plasma) fill?
03391          ! (pFill->IsABitmapFill ()) )      // Is it not a bitmap fill?
03392     {
03393         acceptable = TRUE;
03394     }
03395     else
03396     {
03397         acceptable = FALSE;
03398     }
03399 
03400     return acceptable;
03401 }
03402 
03403 
03404 /********************************************************************************************
03405 
03406 >   virtual BOOL AIEPSRenderRegion::IncludeGradientFill ()
03407 
03408     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
03409     Created:    5/2/2001
03410     Purpose:    Stores information about a fill so that the same fill isn't declared multiple
03411                 times.
03412     See also:   AIEPSRenderRegion::WriteGradientFills, AIEPSRenderRegion::WriteGradientUsage,
03413                 AIEPSRenderRegion::FindGradientInCache
03414 
03415 ********************************************************************************************/
03416 void AIEPSRenderRegion::IncludeGradientFill (FillGeometryAttribute * pFill, EFFECTTYPE effect)
03417 {
03418     ERROR3IF ((pFill == NULL), "AIEPSRenderRegion::IncludeGradientFill - Attempted to include NULL fill");
03419 
03420     ListFill * pNewList = NULL;
03421     FillGeometryAttribute * pNewFill = NULL;
03422 
03423     // don't try and store the fill if it's invalid.
03424     if (pFill != NULL)
03425     {
03426         // Create a new FillGeometryAttribute, of the same type as the one passed in.
03427 
03428         //  NOTE: Four colour fills are derived from three colour fills, so they return
03429         //      TRUE for IsAThreeColFill. This means that we need to process four colour
03430         //      fills before we process three colour fills, otherwise all four colour fills
03431         //      will become represented by three colour ones and the copy won't match the
03432         //      original.
03433 
03434         if (pFill->IsALinearFill ())
03435             pNewFill = new LinearFillAttribute;
03436         else if (pFill->IsARadialFill ())
03437             pNewFill = new RadialFillAttribute;
03438         else if (pFill->IsAConicalFill ())
03439             pNewFill = new ConicalFillAttribute;
03440         else if (pFill->IsASquareFill ())
03441             pNewFill = new SquareFillAttribute;
03442         else if (pFill->IsAFourColFill ())
03443             pNewFill = new FourColFillAttribute;
03444         else if (pFill->IsAThreeColFill ())
03445             pNewFill = new ThreeColFillAttribute;
03446         else if (pFill->IsAFractalFill ())
03447             pNewFill = new FractalFillAttribute;
03448         else if (pFill->IsANoiseFill ())
03449             pNewFill = new NoiseFillAttribute;
03450         else if (pFill->IsABitmapFill ())
03451             pNewFill = new BitmapFillAttribute;
03452         else
03453         {
03454             pNewFill = NULL;
03455             ERROR3 ("AIEPSRenderRegion::IncludeGradientFill - Unrecognised fill included");
03456         }
03457 
03458         // Copy fill data if the the fill is recognised. There's no point in doing this if
03459         //  we didn't recognise the fill, as the copy is bound to be different to the original.
03460         if (pNewFill != NULL)
03461         {
03462             // Copy all the relevant info.
03463             *(pNewFill) = *pFill;
03464             ERROR3IF ( !(*pFill == *pNewFill), "AIEPSRenderRegion::IncludeGradientFill - Copied fill doesn't match original");
03465 
03466             // New Fill is built, so add it into either the radial or linear list.
03467             if (pFill->IsARadialFill () || pFill->IsASquareFill ())
03468             {
03469                 pNewList = new ListFill (pNewFill, effect, m_pRadialGradList);
03470                 m_pRadialGradList = pNewList;
03471             }
03472             else
03473             {
03474                 pNewList = new ListFill (pNewFill, effect, m_pLinearGradList);
03475                 m_pLinearGradList = pNewList;
03476             }
03477         }
03478     }
03479 }
03480 
03481 /********************************************************************************************
03482 
03483 >   virtual void AIEPSRenderRegion::ClearGradientCache ()
03484 
03485     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
03486     Created:    30/3/2001
03487 
03488     Purpose:    Deletes the list of stored gradient fills, that was built up using 
03489                 IncludeGradientFill
03490 
03491     See also:   AIEPSRenderRegion::IncludeGradientFill, 
03492                 AIEPSRenderRegion::FindGradientInCache
03493 
03494 ********************************************************************************************/
03495 void AIEPSRenderRegion::ClearGradientCache ()
03496 {
03497     ListFill * pList = NULL;
03498 
03499     // only clear it if there is a list to clear
03500     if (m_pLinearGradList)
03501     {
03502         // Cycle through the linear list deleting each item in turn.
03503         while (m_pLinearGradList != NULL)
03504         {
03505             pList = m_pLinearGradList->pNext;
03506             delete m_pLinearGradList;
03507             m_pLinearGradList = pList;
03508         }
03509     }
03510 
03511     if (m_pRadialGradList)
03512     {
03513         // Cycle through the radial list deleting each item in turn.
03514         while (m_pRadialGradList != NULL)
03515         {
03516             pList = m_pRadialGradList->pNext;
03517             delete m_pRadialGradList;
03518             m_pRadialGradList = pList;
03519         }
03520     }
03521 }
03522 
03523 
03524 /********************************************************************************************
03525 
03526 >   virtual INT32 AIEPSRenderRegion::FindGradientInCache ()
03527 
03528     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
03529     Created:    30/3/2001
03530     Returns     the identifier of the found gradient fill, or 0 if it wasn't found
03531 
03532     Purpose:    Deletes the list of stored gradient fills, that was built up using 
03533                 IncludeGradientFill
03534 
03535     See also:   AIEPSRenderRegion::IncludeGradientFill, 
03536 
03537 ********************************************************************************************/
03538 INT32 AIEPSRenderRegion::FindGradientInCache (FillGeometryAttribute * pFill, EFFECTTYPE effect)
03539 {
03540     INT32 id    = 0;
03541     ListFill * pList = NULL;
03542     FillGeometryAttribute * pStoredFill = NULL;
03543 
03544     double fillBias = 0;
03545     CProfileBiasGain fillProfile = pFill->GetProfile ();
03546     fillBias = (double) fillProfile.GetBias ();
03547 
03548     // work out which list we want to search in.
03549     if (pFill->IsARadialFill () || pFill->IsASquareFill ())
03550         pList = m_pRadialGradList;
03551     else
03552         pList = m_pLinearGradList;
03553 
03554     // Cycle through all the fills until we find the one we want, or until we run out of fills
03555     while ((pList != NULL) && (id == 0))
03556     {
03557         pStoredFill = pList->pFill;
03558 
03559         // Because the start and end points for an Illustrator fill are not included in the
03560         //  cache, we don't need to worry about them being the same.
03561         //
03562         // So, we set all the start and end points to be the same (since they would cause two
03563         //  identical fills in different places, or of different lengths to be considered as
03564         //  different otherwise).
03565         pStoredFill->SetStartPoint (pFill->GetStartPoint ());
03566         pStoredFill->SetEndPoint (pFill->GetEndPoint ());
03567         pStoredFill->SetEndPoint2 (pFill->GetEndPoint2 ());
03568         pStoredFill->SetEndPoint3 (pFill->GetEndPoint3 ());
03569 
03570         // Now that the fill coords are the same, test to see whether they're 
03571         //  the same fill, or not.
03572         if (*pStoredFill == *pFill)
03573         {
03574             double storeBias = 0;
03575             CProfileBiasGain storeProfile = pStoredFill->GetProfile ();
03576             storeBias = (double) storeProfile.GetBias ();
03577 
03578             if ((storeBias == fillBias) && (pList->effect == effect))
03579                 id = pList->id;
03580         }
03581 
03582         // Check the next fill
03583         pList = pList->pNext;
03584     }
03585 
03586     return id;
03587 }
03588 
03589 /********************************************************************************************
03590 
03591 >   virtual void AIEPSRenderRegion::BuildGradientCache (Node * pStartNode)
03592 
03593     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
03594     Created:    20/3/2001
03595     Inputs:     pStartNode - the node to start looking from.
03596     Purpose:    Builds up a 'cache' of gradient fills.
03597 
03598     See also:   AIEPSRenderRegion::WriteGradientFills, AIEPSRenderRegion::WriteGradientDefinitions
03599 
03600 ********************************************************************************************/
03601 void AIEPSRenderRegion::BuildGradientCache (Node * pStartNode)
03602 {
03603 //  Node * pChild   = NULL;
03604 
03605     // Set up the gradient searching system
03606     AIEPSGradientScanRenderRegion scanRR (this);
03607     scanRR.AttachDevice (DocView::GetSelected (), RenderDC, RenderView->GetDoc()->FindFirstSpread ());
03608     scanRR.InitDevice ();
03609 
03610     // Although the counting system does return the number of fills found, it can be got from
03611     //  the scanner just as easily.
03612     BuildGradientCacheUsingScanner (pStartNode, &scanRR);
03613 }
03614 
03615 /********************************************************************************************
03616 
03617 >   virtual void AIEPSRenderRegion::BuildGradientCacheUsingScanner (Node * pNode,
03618                                                                     AIEPSGradientScanRenderRegion * pScan)
03619 
03620     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
03621     Created:    20/3/2001
03622     Inputs:     pNode - the node to start looking from.
03623                 pScan - the scanner to use
03624                 .
03625     Purpose:    Builds up the gradient cache by scanning through each node under pNode for new 
03626                 fills
03627 
03628     See also:   AIEPSRenderRegion::WriteGradientFills, AIEPSRenderRegion::WriteGradientDefinitions
03629 
03630 ********************************************************************************************/
03631 void AIEPSRenderRegion::BuildGradientCacheUsingScanner (Node * pNode, AIEPSGradientScanRenderRegion * pScan)
03632 {
03633     // Children are rendered first, so that attributes will be applied to the right objects.
03634     Node * pChild = pNode->FindFirstChild ();
03635     while (pChild!=NULL)
03636     {
03637         BuildGradientCacheUsingScanner (pChild, pScan);
03638         pChild = pChild->FindNext ();
03639     }
03640 
03641     // "Render" the node into the scanner. Currently, rendering is the only way to access
03642     //  the intermediate steps (and their attributes) in blends, contours and some others, 
03643     //  so we need to use a special Render Region to catch the gradient (fill) information.
03644     //
03645     // NOTE: Since this uses the same system as the main render loop, it shouldn't be possible
03646     //  for the gradient cache and the main file to become out of sync. Also, bevels and 
03647     //  shadows are excluded, as they are rendered as bitmaps in AI export.
03648     if (!pNode->IsABevel () && !pNode->IsAShadow ())
03649         pNode->Render (pScan);
03650 }
03651 
03652 /********************************************************************************************
03653 
03654 >   virtual void AIEPSRenderRegion::WriteGradientCount ()
03655 
03656     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
03657     Created:    20/3/2001
03658     Purpose:    Writes out the count of all the gradient fills in the Cache
03659 
03660     See also:   AIEPSRenderRegion::WriteGradientDefinitions, 
03661                 AIEPSRenderRegion::BuildGradientCache
03662 
03663 ********************************************************************************************/
03664 void AIEPSRenderRegion::WriteGradientCount ()
03665 {
03666     KernelDC *pDC = (KernelDC*)CCDC::ConvertFromNativeDC(RenderDC);
03667     ListFill * pList    = m_pLinearGradList;
03668     INT32 numFills      = 0;
03669 
03670     // Cycle through the gradient cache writing out fills as we go.
03671     //
03672     //  First count the linear fills
03673     while (pList != NULL)
03674     {
03675         numFills ++;
03676         pList = pList->pNext;
03677     }
03678 
03679     // Then count the radial fills.
03680     pList = m_pRadialGradList;
03681     while (pList != NULL)
03682     {
03683         numFills ++;
03684         pList = pList->pNext;
03685     }
03686 
03687     // If there are any fills, then write the count out.
03688     if (numFills)
03689     {
03690         pDC->OutputValue (numFills);
03691         pDC->OutputToken (_T("Bn"));
03692         pDC->OutputNewLine ();
03693     }
03694 }
03695 
03696 /********************************************************************************************
03697 
03698 >   virtual void AIEPSRenderRegion::WriteGradientDefinitions ()
03699 
03700     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
03701     Created:    5/2/2001
03702     Purpose:    Writes out the definitions of all the  gradient fills in the Cache
03703 
03704     See also:   AIEPSRenderRegion::WriteGradientCount, 
03705                 AIEPSRenderRegion::BuildGradientCache
03706 
03707 ********************************************************************************************/
03708 void AIEPSRenderRegion::WriteGradientDefinitions ()
03709 {
03710     ListFill *              pList = NULL;
03711     FillGeometryAttribute * pFill = NULL;
03712 
03713     // Cycle through the gradient cache writing out fills as we go.
03714     //
03715     //  First do the linear list.
03716     pList = m_pLinearGradList;
03717     while (pList != NULL)
03718     {
03719         pFill = pList->pFill;
03720         WriteLinearFill ( pFill, pList->effect, pList->id );
03721         pList = pList->pNext;
03722     }
03723 
03724     // Then do the radial list.
03725     pList = m_pRadialGradList;
03726     while (pList != NULL)
03727     {
03728         pFill = pList->pFill;
03729         WriteRadialFill ( pFill, pList->effect, pList->id );
03730         pList = pList->pNext;
03731     }
03732 }
03733 
03734 
03735 
03736 CC_IMPLEMENT_DYNAMIC(AIEPSGradientScanRenderRegion, VectorFileRenderRegion)
03737 
03738 
03739 /********************************************************************************************
03740 
03741 >   virtual void AIEPSGradientScanRenderRegion::AIEPSGradientScanRenderRegion (RenderRegion * pControllingRegion)
03742 
03743     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
03744     Created:    5/2/2001
03745     Inputs:     pControllingRegion - the AIEPSRenderRegion that created this..
03746     Purpose:    Used to scan the tree for gradient fills when exporting to AI EPS format. The 
03747                 objects are rendered into this region, which then stores the fills in a gradient
03748                 cache. This is necessary, as objects such as blends only allow access to the 
03749                 intermediate steps when they are being rendered, and any gradient fills need 
03750                 to be cached in the AI file before proper rendering starts. 
03751 
03752 ********************************************************************************************/
03753 AIEPSGradientScanRenderRegion::AIEPSGradientScanRenderRegion (RenderRegion * pControllingRegion)
03754  : VectorFileRenderRegion ()
03755 {
03756     SetControllingRegion (pControllingRegion);
03757 
03758     DocRect clipRect = pControllingRegion->GetClipRect ();
03759     SetClipRect (clipRect);
03760 }
03761 
03762 /********************************************************************************************
03763 
03764 >   virtual void AIEPSGradientScanRenderRegion::DrawPathToOutputDevice (Path *pPath, 
03765                                                           PathProcessor *pCaller = NULL, 
03766                                                           PathShape ShapePath = PATHSHAPE_PATH)
03767 
03768     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
03769     Created:    5/2/2001
03770     Inputs:     see RenderRegion::DrawPathToOutputDevice
03771     Purpose:    Used to catch gradient fills on objects (mainly in blends, contours, brushes, 
03772                 and other objects which won't show up in the tree) so that they can be included 
03773                 properly in the caching system.
03774 
03775     See also:   RenderRegion::DrawPath
03776 
03777 ********************************************************************************************/
03778 void AIEPSGradientScanRenderRegion::DrawPathToOutputDevice (Path *DrawPath, PathShape shapePath /*= PATHSHAPE_PATH*/)
03779 {
03780     FillGeometryAttribute * pFill = (FillGeometryAttribute *) CurrentAttrs[ATTR_FILLGEOMETRY].pAttr;
03781     AIEPSRenderRegion * pControl = (AIEPSRenderRegion *) GetControllingRegion ();
03782 
03783     EFFECTTYPE effect = GetFillEffect ();
03784 
03785     // Write and store the fill info it's got a gradient fill.
03786     if (pControl->IsGradientFillValidForExport (pFill) && 
03787         !pControl->FindGradientInCache (pFill, effect))
03788     {
03789         // Store this fill - function takes a copy of the whole fill (not just the pointer), 
03790         //  so this is safe. 
03791         pControl->IncludeGradientFill (pFill, effect);
03792     }
03793 
03794     // Reset the fill to RGB. This is temp, so it will be deleted when it is no longer used.
03795     SetFillEffect (new FillEffectFadeAttribute, TRUE);
03796 }
03797 
03798 /********************************************************************************************
03799 
03800 >   virtual void AIEPSGradientScanRenderRegion::SetControllingRegion (RenderRegion * pControllingRegion)
03801 
03802     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
03803     Created:    5/2/2001
03804     Inputs:     the AIEPSRenderRegion that we need to send all the information to once we've 
03805                 scanned it in.
03806     Purpose:    sets the controlling AIEPSRenderRegion. I.e. the one that needs to cache the 
03807                 gradient fills.
03808 
03809 ********************************************************************************************/
03810 void AIEPSGradientScanRenderRegion::SetControllingRegion (RenderRegion * pControllingRegion)
03811 {
03812     ERROR3IF (!pControllingRegion->IsKindOf (CC_RUNTIME_CLASS(AIEPSRenderRegion)), "AIEPSGradientScanRenderRegion::SetControllingRegion - controlling region is not an AIEPSRegion");
03813 
03814     m_pController = pControllingRegion;
03815 }
03816 
03817 
03818 
03819 CC_IMPLEMENT_DYNAMIC (ListFill, CCObject);
03820 
03821 /********************************************************************************************
03822 
03823 >   ListFill::ListFill ()
03824 
03825     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
03826     Created:    30/3/2001
03827     Purpose:    Constructor for a gradient fill holder, so it can be stored in a linked list
03828                 cache. All variables (esp. the id) should be set before use. It is better to 
03829                 use the constructor below, as this will allocate id numbers uniquely.
03830 
03831 ********************************************************************************************/
03832 ListFill::ListFill ()
03833 {
03834     pFill = NULL;
03835     pNext = NULL;
03836     id = 1;
03837     effect = EFFECT_RGB;
03838 }
03839 
03840 /********************************************************************************************
03841 
03842 >   ListFill::ListFill (FillGeometry * pNewFill, ListFill * pNewNext)
03843 
03844     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
03845     Created:    30/3/2001
03846     Inputs:     pNewFill    - The fill to be stored.
03847                 pNewNext    - The next item in the list.
03848     Purpose:    Constructor for a gradient fill holder, so it can be stored in a linked list
03849                 cache.
03850 
03851 ********************************************************************************************/
03852 ListFill::ListFill (FillGeometryAttribute * pNewFill, EFFECTTYPE eff, ListFill * pNewNext) 
03853 {
03854     pFill = pNewFill;
03855     effect = eff;
03856 
03857     pNext = pNewNext;
03858     if(pNewNext)
03859     {
03860         id = pNewNext->id + 1;
03861     }
03862     else
03863     {
03864         id = 1;
03865     }
03866 }
03867 
03868 /********************************************************************************************
03869 
03870 >   ListFill::~ListFill ()
03871 
03872     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
03873     Created:    30/3/2001
03874     Purpose:    Destructor for a ListFill item. This also cleans up the fill it contains (if
03875                 any).
03876 
03877 ********************************************************************************************/
03878 ListFill::~ListFill ()
03879 {
03880     if (pFill != NULL) 
03881         delete pFill;
03882 }
03883 
03884 

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