aw_eps.cpp

Go to the documentation of this file.
00001 // $Id: aw_eps.cpp 1319 2006-06-14 12:22:54Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 
00099 // Implementation of the ArtWorks EPS filter.
00100 
00101 #include "camtypes.h"
00102 #include "aw_eps.h"
00103 
00104 #include <sstream>
00105 #include <math.h>
00106 
00107 #include "nodepath.h"
00108 //#include "paths.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 //#include "tim.h"
00110 //#include "oilfltrs.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00111 #include "kerneldc.h"
00112 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00113 #include "page.h"
00114 //#include "fillattr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00115 //#include "attrmgr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00116 #include "nodeblnd.h"
00117 #include "nodebldr.h"
00118 #include "layer.h"
00119 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00120 #include "nodemold.h"
00121 #include "ndmldgrp.h"
00122 #include "nodemldr.h"
00123 #include "ndmldpth.h"
00124 #include "nodeshap.h"
00125 
00126 DECLARE_SOURCE("$Revision: 1319 $");
00127 
00128 #define new CAM_DEBUG_NEW
00129 
00130 CC_IMPLEMENT_DYNAMIC(ArtWorksEPSFilter, EPSFilter)
00131 
00132 
00133 // This is the array of ArtWorks EPS command/keyword names.
00134 CommandMap ArtWorksEPSFilter::ArtWorksCommands[] =
00135 {
00136     { EPSC_aoa,     _T("aoa")},
00137     { EPSC_aafs,        _T("aafs")},
00138     
00139     // Path related procedures
00140     { EPSC_ar,      _T("ar")},
00141     { EPSC_arr,     _T("arr")},
00142     { EPSC_ae,      _T("ae")},
00143     { EPSC_apl,     _T("apl")},
00144     { EPSC_apc,     _T("apc")},
00145     { EPSC_aof,     _T("aof")},
00146     
00147     // Text related procedures
00148     { EPSC_asto,        _T("asto")},
00149     { EPSC_aeto,        _T("aeto")},
00150     { EPSC_aco,     _T("aco")},
00151     { EPSC_atc,     _T("atc")},
00152     { EPSC_atph,        _T("atph")},
00153     { EPSC_atof,        _T("atof")},
00154     
00155     // Blend related procedures
00156     { EPSC_asbd,        _T("asbd")},
00157     { EPSC_aebd,        _T("aebd")},
00158     { EPSC_asbr,        _T("asbr")},
00159     { EPSC_aebr,        _T("aebr")},
00160     
00161     // Mould related procedures
00162     { EPSC_asev,        _T("asev")},
00163     { EPSC_aeev,        _T("aeev")},
00164     { EPSC_aspr,        _T("aspr")},
00165     { EPSC_aepr,        _T("aepr")},
00166     { EPSC_amm,     _T("amm")},
00167     { EPSC_aml,     _T("aml")},
00168     { EPSC_amc,     _T("amc")},
00169     { EPSC_amcp,        _T("amcp")},
00170     { EPSC_amep,        _T("amep")},
00171     
00172     // Group related procedures
00173     { EPSC_anu,     _T("anu")},
00174     
00175     // Linear/radial fills
00176     { EPSC_az,      _T("az")},
00177     { EPSC_ax,      _T("ax")},
00178     { EPSC_axm,     _T("axm")},
00179     
00180     // Overprint related procedures
00181     { EPSC_axop,        _T("axop")},
00182     
00183     // Others(!)
00184     { EPSC_awr,     _T("awr")},
00185     { EPSC_asc,     _T("asc")},
00186     { EPSC_aec,     _T("aec")},
00187     { EPSC_aca,     _T("aca")},
00188     { EPSC_asah,        _T("asah")},
00189     { EPSC_aeah,        _T("aeah")},
00190     { EPSC_asat,        _T("asat")},
00191     { EPSC_aeat,        _T("aeat")},
00192     
00193     // Procedures that define a text object
00194     { EPSC_atp,     _T("atp")},
00195     { EPSC_atf,     _T("atf")},
00196     { EPSC_atxy,        _T("atxy")},
00197     { EPSC_atrk,        _T("atrk")},
00198     { EPSC_akrn,        _T("akrn")},
00199     
00200     // Layer procedure
00201     { EPSC_alyr,        _T("alyr")},
00202     
00203     // Sprite procedure
00204     { EPSC_ass,     _T("ass")},
00205     { EPSC_aes,     _T("aes")},
00206 
00207     // Sentinel
00208     { EPSC_Invalid, _T("Invalid")}
00209 };
00210 
00211 /********************************************************************************************
00212 
00213 >   ArtWorksEPSFilter::ArtWorksEPSFilter()
00214 
00215     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00216     Created:    28/10/93
00217     Purpose:    Constructor for an ArtWorksEPSFilter object.  The object should be 
00218                 initialised before use.
00219     SeeAlso:    EPSFilter::Init
00220 
00221 ********************************************************************************************/
00222 
00223 ArtWorksEPSFilter::ArtWorksEPSFilter()
00224 {
00225     // Set up filter descriptions.
00226     FilterNameID = _R(IDT_AWEPS_FILTERNAME);
00227     FilterInfoID = _R(IDT_AWEPS_FILTERINFO);
00228     ImportMsgID  = _R(IDT_IMPORTMSG_ARTWORKS);
00229 
00230     FilterID = FILTERID_ARTWORKS_EPS;
00231 
00232 #ifndef STANDALONE
00233     Flags.CanImport = TRUE;
00234     //WEBSTER-Martin-27/01/97
00235 #ifdef WEBSTER
00236     Flags.CanExport = FALSE;
00237 #else
00238     Flags.CanExport = TRUE;
00239 #endif //WEBSTER
00240 #else
00241     Flags.CanImport = FALSE;
00242     Flags.CanExport = FALSE;
00243 #endif
00244 
00245     LastFillType = 0;
00246 }
00247 
00248 
00249 /********************************************************************************************
00250 
00251 >   BOOL ArtWorksEPSFilter::Init()
00252 
00253     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00254     Created:    28/02/94
00255     Returns:    TRUE if the filter was initialised ok, FALSE otherwise.
00256     Purpose:    Initialise an ArtWorksEPSFilter object.
00257     Errors:     Will fail if not enough memory to initialise the EPS stack.
00258     SeeAlso:    EPSStack
00259 
00260 ********************************************************************************************/
00261 
00262 BOOL ArtWorksEPSFilter::Init()
00263 {
00264     // Get the OILFilter object
00265     pOILFilter = new ArtWorksEPSOILFilter(this);
00266     if (pOILFilter == NULL)
00267         return FALSE;
00268 
00269     // Load the description strings
00270     FilterName.Load(FilterNameID);
00271     FilterInfo.Load(FilterInfoID);
00272 
00273     // All ok
00274     return TRUE;
00275 }
00276 
00277 /********************************************************************************************
00278 
00279 >   INT32 ArtWorksEPSFilter::EPSHeaderIsOk(ADDR pFileHeader, UINT32 HeaderSize)
00280 
00281     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00282     Created:    28/02/94
00283     Returns:    TRUE if the header is ok and import should proceed, FALSE if not.
00284     Purpose:    Checks to see if the EPS comment headers specify that this is an ArtWorks
00285                 generated EPS file, as required.
00286 
00287 ********************************************************************************************/
00288 
00289 INT32 ArtWorksEPSFilter::EPSHeaderIsOk(ADDR pFileHeader, UINT32 HeaderSize)
00290 {
00291     // this function is not Unicode
00292 
00293     // Check the first line in EPS file
00294     if (strncmp((char *) pFileHeader, "%!PS-Adobe-2.0 EPSF-1.2", 23) != 0)
00295     {
00296         // Incorrect version of EPS header line - we don't want this
00297         return 0;
00298     }
00299 
00300     // !PS-Adobe line is ok - check creator line...
00301     std::istringstream HeaderFile((char *) pFileHeader, ios_base::in /*, HeaderSize*/);
00302     char Buffer[200];
00303 
00304     UINT32 Lines = 0;
00305     while ((Lines < 20) && !HeaderFile.eof())
00306     {
00307         HeaderFile.getline(Buffer, 200);
00308         Lines++;
00309 
00310         // Return TRUE if this file was created by ArtWorks
00311         if (strncmp(Buffer, "%%Creator: ArtWorks", 19) == 0)
00312         {
00313             // ArtWorks is the creator - but has it exported it in an alien format?
00314             // Return 10 if it hasn't, 1 if it has.
00315             if (strstr(Buffer, "exported") == NULL)
00316                 return 10;
00317             else
00318                 // 5 because it *might* be "ArtWorks (exported by Mr. Blobby)", and
00319                 // we don't want to let the user not load this at all...
00320                 return 5;
00321         }
00322 
00323         // If we find the compression token then stop the search as we don't want to start
00324         // looking in the compressed data!
00325         if (strncmp(Buffer, "%%Compression:", 14)==0)
00326             break;
00327     }
00328 
00329     // Didn't find a suitable Creator line, but we did find an EPS line, so indicate
00330     // that we're interested, but not sure.
00331     return 5;
00332 }
00333 
00334 /********************************************************************************************
00335 
00336 >   BOOL ArtWorksEPSFilter::PrepareToExport(CCLexFile* pFile, Spread *pSpread)
00337 
00338     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00339     Created:    15/04/94
00340     Inputs:     pFile - The File to export to
00341                 pSpread - The spread to export
00342     Returns:    TRUE if succeeded, FALSE if not (e.g. no memory for EPS stack)
00343     Purpose:    Prepare to import EPS data using this filter.  This sets up the filter
00344                 to a sensible state for reading.
00345     Errors:     Out of memory.
00346     SeeAlso:    EPSFilter::DoImport; EPSFilter::CleanUpAfterImport
00347     Scope:      Private
00348 
00349 ********************************************************************************************/
00350 
00351 BOOL ArtWorksEPSFilter::PrepareToExport(CCLexFile* pFile, Spread *pSpread)
00352 {
00353 #ifdef DO_EXPORT
00354     // Created the 'file' DC for rendering and try to open the specified file.
00355     ExportDCPtr = new EPSExportDC(this);
00356     if (ExportDCPtr == NULL) return FALSE;
00357     
00358     // Tell it about the file
00359     if (!ExportDCPtr->Init(pFile)) return FALSE;
00360 
00361     // Get the position of the first page, and use this to set the origin.
00362     Page *pPage = pSpread->FindFirstPageInSpread(); 
00363     ENSURE(pPage != NULL, "Spread has no pages");
00364     ERRORIF(pPage == NULL, _R(IDT_DOC_BADSTRUCTURE), FALSE);
00365 
00366     // Use bottom left of page as origin
00367     DocRect PageRect = pPage->GetPageRect();
00368     ExportDCPtr->SetOrigin(PageRect.lo);
00369 
00370     // Create a new render region to export to:
00371 
00372     // Don't care about clip regions when exporting - create a null region.
00373     DocRect NullClipRect;
00374     NullClipRect.MakeEmpty();
00375 
00376     if (IS_A(this, ArtWorksEPSFilter))
00377     {
00378         // Don't use rendering matrix when exporting EPS as it uses fractional coordinates.
00379         Matrix Identity;
00380 
00381         // Don't use view scale; set to 1
00382         FIXED16 Scale(1);
00383 
00384         // Create the region
00385         ExportRegion = new ArtWorksEPSRenderRegion(NullClipRect, Identity, Scale);
00386         if (ExportRegion == NULL)
00387             return FALSE;
00388 
00389         // Attach to the right device.
00390         ExportRegion->AttachDevice(DocView::GetSelected(), ExportDCPtr->GetDC(), pSpread);
00391     }
00392 
00393     // All ok
00394     return TRUE;
00395 #else
00396     return FALSE;
00397 #endif
00398 };
00399 
00400 /********************************************************************************************
00401 
00402 >   void ArtWorksEPSFilter::LookUpToken()
00403 
00404     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00405     Created:    25/02/94
00406     Returns:    TRUE if the token is an ArtWorks EPS token; FALSE if not.
00407     Purpose:    Compare the current token against the ArtWorks keywords to see if it is
00408                 one of them.
00409     SeeAlso:    EPSFilter::LookUpToken; EPSFilter::DecodeToken
00410 
00411 ********************************************************************************************/
00412 
00413 void ArtWorksEPSFilter::LookUpToken()
00414 {
00415     // Not interested in comments
00416     if (Token == EPSC_Comment)
00417         return;
00418 
00419     // Check to see if it is a keyword - cycle through the array of keyword names and
00420     // compare against our token (could use a hash table?)
00421     INT32 i = 0;
00422     while (ArtWorksCommands[i].Cmd != EPSC_Invalid)
00423     {
00424         if (camStrcmp(TokenBuf, ArtWorksCommands[i].CmdStr) == 0)
00425         {
00426             // Found the token - set the token variable and return success
00427             Token = ArtWorksCommands[i].Cmd;
00428             return;
00429         }
00430         // Try next command
00431         i++;
00432     }
00433 
00434     // Did not find this token - pass on to base class.
00435     EPSFilter::LookUpToken();
00436 }
00437 
00438 /********************************************************************************************
00439 
00440 >   BOOL ArtWorksEPSFilter::ProcessToken()
00441 
00442     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00443     Created:    25/02/94
00444     Returns:    TRUE if token understood and processed ok, FALSE if not.
00445     Purpose:    Processes EPS tokens that are not part of the standard Illustrator set, or
00446                 which need to be handled differently to the standard Illustrator meanings.
00447                 i.e. this is the function that handles all the ArtWorks EPS operators.
00448     Errors:     Syntax error in EPS, Out of memory.
00449     SeeAlso:    EPSFilter::ProcessToken
00450 
00451 ********************************************************************************************/
00452 
00453 BOOL ArtWorksEPSFilter::ProcessToken()
00454 {
00455     // Variables used to extract operands from the stack
00456     DocCoord    Coords[3];
00457     String_64   ColName;
00458     PColourCMYK Col;
00459     TintType    Tint = TINT_NONE;
00460     FIXEDPOINT  TintVal;
00461     INT32       Long;
00462     DocCoord    StartPoint, 
00463                 EndPoint;
00464     PathFlags   Flags;
00465 
00466     // Decode the command, and execute it...
00467     switch (Token)
00468     {
00469         // LineTo - overridden to overcome ArtWorks EPS incompatibility with AI EPS.
00470         case EPSC_l:
00471             if (ThePathType == PATH_DISCARD || ThePathType == PATH_DISCARD_STICKY)
00472             {
00473                 if (!Stack.PopCoordPair(&Coords[0]))
00474                     goto EPSError;
00475                 break;
00476             }
00477 
00478             if (pInkPath == NULL)
00479                 // Paths must start with a moveto
00480                 goto EPSError;
00481             
00482             // Get the co-ordinate from the stack
00483             if (Stack.PopCoordPair(&Coords[0]))
00484             {
00485                 // ArtWorks doesn't save smoothing bit of the point, so default to
00486                 // no smoothing (it's the logical default).
00487                 Flags.IsSmooth = FALSE;
00488 
00489                 if (!pInkPath->InsertLineTo(Coords[0], &Flags))
00490                     // Not enough dynamic heap to insert the lineto command
00491                     goto NoMemory;
00492             }
00493             else
00494                 // Invalid number/type of coordinate operands
00495                 goto EPSError;
00496             break;
00497 
00498         // Curveto - overridden to overcome ArtWorks EPS incompatibility with AI EPS.
00499         case EPSC_c:
00500             if (ThePathType == PATH_DISCARD || ThePathType == PATH_DISCARD_STICKY)
00501             {
00502                 if (!Stack.PopCoordPair(&Coords[2]) ||
00503                     !Stack.PopCoordPair(&Coords[1]) ||
00504                     !Stack.PopCoordPair(&Coords[0]))
00505                     goto EPSError;
00506 
00507                 break;
00508             }
00509 
00510             if (pInkPath == NULL)
00511                 // Paths must start with a moveto
00512                 goto EPSError;
00513             
00514             // Get the co-ordinate from the stack
00515             if (Stack.PopCoordPair(&Coords[2]) &&
00516                 Stack.PopCoordPair(&Coords[1]) &&
00517                 Stack.PopCoordPair(&Coords[0]))
00518             {
00519                 // ArtWorks doesn't save smoothing bit of the point, so default to
00520                 // no smoothing (it's the logical default).
00521                 Flags.IsSmooth = FALSE;
00522 
00523                 if (!pInkPath->InsertCurveTo(Coords[0], Coords[1], Coords[2], &Flags))
00524                     // Not enough dynamic heap to insert the curveto command
00525                     goto NoMemory;
00526             }
00527             else
00528                 // Invalid number/type of coordinate operands
00529                 goto EPSError;
00530             break;
00531             
00532         case EPSC_aoa:
00533             // NOT IMPLEMENTED
00534             if (!Stack.Discard())
00535                 goto EPSError;
00536             break;
00537             
00538         case EPSC_aafs:
00539             // NOT IMPLEMENTED
00540             if (!Stack.Discard(3))
00541                 goto EPSError;
00542             break;
00543             
00544         
00545         // Path related procedures
00546         case EPSC_ar:
00547             // ArtWorks rectangle
00548             ThePathType = PATH_RECT;
00549             break;
00550         
00551         case EPSC_arr:
00552             // NOT IMPLEMENTED
00553             if (!Stack.Discard(7))
00554                 goto EPSError;
00555             break;
00556             
00557         case EPSC_ae:
00558         {
00559             // ArtWorks ellipse
00560             ThePathType = PATH_ELLIPSE;
00561 
00562             // Read in parallelogram bounding box.
00563             if (!Stack.PopCoordPair(&ShapeBBox[0]) ||
00564                 !Stack.PopCoordPair(&ShapeBBox[1]) ||
00565                 !Stack.PopCoordPair(&ShapeBBox[2]))
00566                 goto EPSError;
00567 
00568             // Fill in the 4th co-ordinate
00569             ShapeBBox[3].x = ShapeBBox[0].x + (ShapeBBox[2].x - ShapeBBox[1].x);
00570             ShapeBBox[3].y = ShapeBBox[0].y + (ShapeBBox[2].y - ShapeBBox[1].y);
00571 
00572             break;
00573         }
00574             
00575         case EPSC_apl:
00576             // NOT IMPLEMENTED
00577             if (!Stack.Discard())
00578                 goto EPSError;
00579             break;
00580             
00581         case EPSC_apc:
00582             // NOT IMPLEMENTED
00583             break;
00584             
00585         case EPSC_aof:
00586             // NOT IMPLEMENTED
00587             if (!Stack.Discard(2))
00588                 goto EPSError;
00589             break;
00590             
00591         
00592         // Text related procedures
00593         case EPSC_asto:
00594             // NOT IMPLEMENTED
00595             break;
00596             
00597         case EPSC_aeto:
00598             // NOT IMPLEMENTED
00599             break;
00600             
00601         case EPSC_aco:
00602             // NOT IMPLEMENTED
00603             if (!Stack.Discard(2))
00604                 goto EPSError;
00605             break;
00606             
00607         case EPSC_atc:
00608             // NOT IMPLEMENTED
00609             if (!Stack.Discard())
00610                 goto EPSError;
00611             break;
00612             
00613         case EPSC_atph:
00614             // NOT IMPLEMENTED
00615             if (!Stack.Discard())
00616                 goto EPSError;
00617             break;
00618             
00619         case EPSC_atof:
00620             // NOT IMPLEMENTED
00621             if (!Stack.Discard(2))
00622                 goto EPSError;
00623             break;
00624             
00625         
00626         // Blend related procedures
00627         case EPSC_asbd:
00628             return ProcessBlend();
00629             
00630         case EPSC_aebd:
00631             goto EPSError;
00632             
00633         case EPSC_asbr:
00634             return ProcessBlender();
00635             
00636         case EPSC_aebr:
00637             goto EPSError;
00638             
00639         
00640         // Mould related procedures
00641         case EPSC_asev:
00642             return ProcessEnvelope();
00643             
00644         case EPSC_aeev:
00645             goto EPSError;
00646             
00647         case EPSC_aspr:
00648             return ProcessPerspective();
00649             
00650         case EPSC_aepr:
00651             goto EPSError;
00652             
00653         case EPSC_amm:
00654             return ProcessMouldShape();
00655 
00656         case EPSC_aml:
00657         case EPSC_amc:
00658         case EPSC_amcp:
00659         case EPSC_amep:
00660             // all these tokens are mould path related and are
00661             // delt with inside ProcessMouldShape(). If they are found
00662             // on their own elsewhere then we obviously have an error
00663             goto EPSError;
00664                         
00665         
00666         // Group related procedures
00667         
00668         case EPSC_anu:
00669             // Discard the name - we don't do named groups.
00670             if (!Stack.Discard())
00671                 goto EPSError;
00672 
00673             // Process as a normal EPS group.
00674             GroupNesting++;
00675             return ProcessGroup();
00676             
00677         // Linear/radial fills
00678         case EPSC_ax:
00679             // Colours are described using a name and tint as well as CMYK.
00680             Tint = TINT_ILLUSTRATOR;
00681         case EPSC_az:
00682         {
00683             DocColour StartColour, EndColour;
00684             DocCoord StartPoint, EndPoint;
00685 
00686             // Get start and end positions for grad-fills
00687             if (!Stack.PopCoordPair(&EndPoint) || !Stack.PopCoordPair(&StartPoint))
00688                 goto EPSError;
00689             
00690             // Get start and end colours for grad-fills
00691             if (!Stack.PopColour(&Col, Tint, &TintVal, &ColName))
00692                 // Invalid colour operands
00693                 goto EPSError;
00694 
00695             // Keep hold of this colour definition 
00696             LastEndColour.Col = Col;
00697             LastEndColour.Tint = Tint;
00698             LastEndColour.TintVal = TintVal;
00699             LastEndColour.ColName = ColName;
00700 
00701             GetEPSColour(&EndColour, &Col, Tint, TintVal, &ColName);
00702 
00703             if (!Stack.PopColour(&Col, Tint, &TintVal, &ColName))
00704                 // Invalid colour operands
00705                 goto EPSError;
00706 
00707             // Keep hold of this colour definition 
00708             LastStartColour.Col = Col;
00709             LastStartColour.Tint = Tint;
00710             LastStartColour.TintVal = TintVal;
00711             LastStartColour.ColName = ColName;
00712 
00713             GetEPSColour(&StartColour, &Col, Tint, TintVal, &ColName);
00714                 
00715             // Get fill type
00716             if (!Stack.Pop(&Long))
00717                 goto EPSError;
00718 
00719             // Also save the last fill style
00720             LastFillType = Long;
00721 
00722             switch (Long)
00723             {
00724                 // Decode ArtWorks EPS grad fill codes
00725                 case 1:
00726                     // Check for silly grad fills first...
00727                     if (StartPoint == EndPoint)
00728                     {
00729                         // Zero length grad fill line!
00730                         // Just set a flat fill  using the first colour, cos that is
00731                         // how Arc GDraw renders such fills.
00732                         if (!SetFillColour(StartColour))
00733                             goto NoMemory;
00734                     }
00735                     else
00736                     {
00737                         if (!SetLinearFill(StartColour, EndColour, StartPoint, EndPoint))
00738                             goto NoMemory;
00739                     }
00740                     break;
00741 
00742                 case 2:
00743                     // Check for silly grad fills first...
00744                     if (StartPoint == EndPoint)
00745                     {
00746                         // Zero length grad fill line!
00747                         // Just set a flat fill  using the second colour, cos that is
00748                         // how Arc GDraw renders such fills.
00749                         //
00750                         // NB. This is different to linear fills above, which use the first 
00751                         // colour - that is how the GDraw cookie crumbles, cos that's
00752                         // the kind of guys we are! :-)
00753                         if (!SetFillColour(EndColour))
00754                             goto NoMemory;
00755                     }
00756                     else
00757                     {
00758                         if (!SetRadialFill(StartColour, EndColour, StartPoint, EndPoint))
00759                             goto NoMemory;
00760                     }
00761                     break;
00762 
00763                 default:
00764                     ENSURE(FALSE, "Unknown fill type found!");
00765                     break;  // Don't know this fill type
00766             }
00767             break;
00768         }
00769             
00770         case EPSC_axm:
00771         {
00772             // ignore axm in this context
00773             if (!HandleMouldedFill())
00774                 goto EPSError;
00775             break;
00776         }
00777 
00778         case EPSC_axop:
00779             // NOT IMPLEMENTED
00780             if (!Stack.Discard(4))
00781                 goto EPSError;
00782             break;
00783             
00784         
00785         // Others(!)
00786         case EPSC_awr:
00787             if (!Stack.Pop(&Long))
00788                 goto EPSError;
00789             // Decode winding rule
00790             ENSURE((Long == 0) || (Long == 1), "Bad winding rule found in Artworks EPS");
00791             if (Long == 0)
00792             {
00793                 if (!SetWindingRule(NonZeroWinding))
00794                     goto NoMemory;
00795             }
00796             else if (Long == 1)
00797             {
00798                 if (!SetWindingRule(EvenOddWinding))
00799                     goto NoMemory;
00800             }
00801             break;
00802             
00803         case EPSC_asc:
00804             // NOT IMPLEMENTED
00805             if (!Stack.Discard(3))
00806                 goto EPSError;
00807             break;
00808             
00809         case EPSC_aec:
00810             // NOT IMPLEMENTED
00811             if (!Stack.Discard(3))
00812                 goto EPSError;
00813             break;
00814             
00815         case EPSC_aca:
00816             // NOT IMPLEMENTED
00817             break;
00818             
00819         case EPSC_asah:
00820             // NOT IMPLEMENTED
00821             if (!Stack.Discard(3))
00822                 goto EPSError;
00823             break;
00824             
00825         case EPSC_aeah:
00826             // NOT IMPLEMENTED
00827             if (!Stack.Discard(3))
00828                 goto EPSError;
00829             break;
00830             
00831         case EPSC_asat:
00832             // NOT IMPLEMENTED
00833             if (!Stack.Discard(6))
00834                 goto EPSError;
00835             break;
00836             
00837         case EPSC_aeat:
00838             // NOT IMPLEMENTED
00839             if (!Stack.Discard(6))
00840                 goto EPSError;
00841             break;
00842             
00843         // Procedures that define a text object
00844         case EPSC_atp:
00845             // NOT IMPLEMENTED
00846             if (!Stack.Discard(2))
00847                 goto EPSError;
00848             break;
00849             
00850         case EPSC_atf:
00851             // NOT IMPLEMENTED
00852             if (!Stack.Discard())
00853                 goto EPSError;
00854             break;
00855             
00856         case EPSC_atxy:
00857             // NOT IMPLEMENTED
00858             if (!Stack.Discard(2))
00859                 goto EPSError;
00860             break;
00861             
00862         case EPSC_atrk:
00863             // NOT IMPLEMENTED
00864             if (!Stack.Discard(4))
00865                 goto EPSError;
00866             break;
00867             
00868         case EPSC_akrn:
00869             // NOT IMPLEMENTED
00870             if (!Stack.Discard(2))
00871                 goto EPSError;
00872             break;
00873             
00874         
00875         // Layer procedure
00876         case EPSC_alyr:
00877         {
00878             String_256 LayerName;
00879             INT32 Visible;
00880             INT32 Locked;
00881             INT32 Foreground;
00882             INT32 Printable;
00883 
00884             // We ignore the layer type and print over-ride flag (for now)
00885             if (!Stack.Pop(&Locked)     || 
00886                 !Stack.Pop(&Printable)  || 
00887                 !Stack.Pop(&Visible)    || 
00888                 !Stack.Pop(&Foreground) || 
00889                 !Stack.Pop(&LayerName))
00890                 goto EPSError;
00891 
00892             if (Filter::ImportWithLayers)
00893             {
00894                 // We are importing layers, so put all new nodes on this layer.
00895                 UseLayer(LayerName);
00896 
00897                 // Try to set the visible/locked flags on this layer, but only if
00898                 // we created a new one (i.e. don't change the flags of existing layers.
00899                 if (EPSFlags.AddToNewLayer)
00900                 {
00901                     // Here we force layers to be printable if they are in the foreground - just in case
00902                     // This will have to change if the UI allows Printable & Foreground to be specified
00903                     // independantly.
00904                     Printable = Foreground;
00905 
00906                     // Visible flag
00907                     pLayer->SetVisible(!(Visible == 0));
00908 
00909                     // Locked flag
00910                     pLayer->SetLocked(!(Locked == 0));
00911 
00912                     // Printable flag
00913                     pLayer->SetPrintable(!(Printable == 0));
00914 
00915                     // Background flag
00916                     pLayer->SetBackground(Foreground == 0);
00917                 }
00918             }
00919             break;
00920         }
00921             
00922         
00923         // Sprite procedure
00924         case EPSC_ass:
00925             // NOT IMPLEMENTED
00926             ERROR2RAW("EPS reader cannot handle Acorn sprites - Dream On!");
00927             goto EPSError;
00928             break;
00929             
00930         case EPSC_aes:
00931             // NOT IMPLEMENTED
00932             ERROR2RAW("EPS reader cannot handle Acorn sprites! - Dream On!");
00933             goto EPSError;
00934             break;
00935             
00936         default:
00937             // Token not understood - pass on to base class
00938             return EPSFilter::ProcessToken();
00939     }
00940 
00941 
00942     // No errors encountered while parsing this token and its operands.
00943     return TRUE;
00944     
00945     
00946     // Error handlers:
00947     
00948 EPSError:
00949     HandleEPSError();
00950     return FALSE;
00951 
00952 NoMemory:
00953     HandleNoMemory();
00954     return FALSE;
00955 }
00956 
00957 
00958 /********************************************************************************************
00959 
00960 >   TCHAR *ArtWorksEPSFilter::GetEPSCommand(EPSCommand Cmd)
00961 
00962     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00963     Created:    28/02/94
00964     Inputs:     Cmd - the EPS token, e.g. EPSC_aoa
00965     Returns:    Pointer to the string representation of the token, e.g. "aoa"
00966     Purpose:    Given an EPS token, return the string representation of it; mainly for
00967                 debugging purposes.
00968 
00969 ********************************************************************************************/
00970 
00971 TCHAR *ArtWorksEPSFilter::GetEPSCommand(EPSCommand Cmd)
00972 {
00973     INT32 i = 0;
00974     while (ArtWorksCommands[i].Cmd != EPSC_Invalid)
00975     {
00976         if (ArtWorksCommands[i].Cmd == Cmd)
00977             return ArtWorksCommands[i].CmdStr;
00978 
00979         // Try next command
00980         i++;
00981     }
00982 
00983     // Couldn't find it - default to base class method
00984     return EPSFilter::GetEPSCommand(Cmd);
00985 }
00986 
00987 /********************************************************************************************
00988 
00989 >   virtual BOOL ArtWorksEPSFilter::NeedsPrintComponents ()
00990 
00991     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
00992     Created:    23/5/00
00993     Returns:    FALSE - ArtWorks files don't need print components.
00994     Purpose:    Informs the print components code that no data should be written.
00995 
00996 ********************************************************************************************/
00997 
00998 BOOL ArtWorksEPSFilter::NeedsPrintComponents ()
00999 {
01000     // We don't want print components!
01001     return FALSE;
01002 }
01003 
01004 /********************************************************************************************
01005 
01006 >   BOOL ArtWorksEPSFilter::ProcessBlend()
01007 
01008     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01009     Created:    23/11/94
01010     Returns:    TRUE if the blend was processed correctly, FALSE if not.
01011     Purpose:    Reads in all the elements of a blend structure in the EPS file.
01012     Errors:     Syntax error in EPS file, Out of memory
01013 
01014 ********************************************************************************************/
01015 
01016 BOOL ArtWorksEPSFilter::ProcessBlend()
01017 {
01018     if (!StartBlend())
01019         return FALSE;
01020 
01021     // Keep processing tokens until we find the end of the blend
01022     do
01023     {
01024         GetToken();
01025 
01026         // Look for the end of the blend token...
01027         if (Token == EPSC_aebd)
01028         {
01029             return EndBlend();
01030         }
01031     }
01032     // Otherwise keep going until an error or eof is encountered
01033     while (HandleToken() && (!EPSFile->eof()));
01034 
01035     if (EPSFile->eof())
01036     {
01037         // Didn't find end of blend - syntax error; deal with it
01038         HandleEPSError();
01039     }
01040 
01041     // If we're here, something went wrong
01042     return FALSE;
01043 }
01044 
01045 /********************************************************************************************
01046 
01047 >   BOOL ArtWorksEPSFilter::StartBlend()
01048 
01049     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01050     Created:    23/11/94
01051     Returns:    TRUE if the new blend was created ok;
01052                 FALSE if not.
01053     Purpose:    Used when a blend structure needs to be created - after this is called,
01054                 all new nodes added with AddNewNode() will be added as children of this
01055                 new blend, until EndBlend is called.
01056     Errors:     Out of memory
01057     SeeAlso:    ArtWorksEPSFilter::EndBlend
01058 
01059 ********************************************************************************************/
01060 
01061 BOOL ArtWorksEPSFilter::StartBlend()
01062 {
01063     INT32 NumBlendShapes,Version,Expanded;
01064     
01065     // Read in the params
01066     BOOL    ok = Stack.Pop(&NumBlendShapes);
01067     if (ok) ok = Stack.Pop(&Expanded);
01068     if (ok) ok = Stack.Pop(&Version);
01069     if (!ok) 
01070     {
01071         HandleEPSError();
01072         return FALSE;
01073     }
01074 
01075     // If the version isn;t one we know, go b-b-b-bang!
01076     ERROR1IF(Version != 1,FALSE,_R(IDT_EPS_BADSYNTAX));
01077 
01078     // Make a new blend node for this blend
01079     NodeBlend *pBlend = new NodeBlend;
01080     if (pBlend==NULL)
01081     {
01082         HandleNoMemory();
01083         return FALSE;
01084     }
01085 
01086     // Add it into the tree
01087     if (!AddNewNode(pBlend))
01088     {
01089         HandleNoMemory();
01090         return FALSE;
01091     }
01092 
01093     // Make sure new objects are added as children of the node
01094     pNode = pBlend;
01095 
01096     // All ok
01097     return TRUE;
01098 }
01099 
01100 /********************************************************************************************
01101 
01102 >   BOOL ArtWorksEPSFilter::EndBlend()
01103 
01104     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01105     Created:    23/11/94
01106     Returns:    TRUE if the blend was ended ok;
01107                 FALSE if not.
01108     Purpose:    Used when a blend has finished being constructed and we want to return to
01109                 normal node positioning.  The blend is added to the document when this
01110                 function is called (although that depending on the current filter mode, 
01111                 i.e. whether this is a new or existing layer, it may not be added
01112                 directly to the documnent tree straight away - it may be deferred until
01113                 the next layer is found, or the import has ended).
01114     Errors:     Out of memory
01115     SeeAlso:    ArtWorksEPSFilter::StartBlend
01116 
01117 ********************************************************************************************/
01118 
01119 BOOL ArtWorksEPSFilter::EndBlend()
01120 {
01121     // Sanity check
01122     ENSURE(pNode->IsKindOf(CC_RUNTIME_CLASS(NodeBlend)), "No blend in ArtWorksEPSFilter::EndBlend");
01123 
01124     // Keep the blend ptr and find the first child of the node before we reset pNode.
01125     Node* pBlend     = pNode;
01126     Node* pChildNode = pNode->FindFirstChild();
01127 
01128     // Get the parent of the blend node, and use that to add new objects to
01129     pNode = pBlend->FindParent();
01130     ERROR2IF(pNode==NULL, FALSE, "Blend has no parent in EndBlend()");
01131 
01132     // Initialise all the child blender nodes
01133     UINT32 BlenderCount=0;
01134     while (pChildNode != NULL)
01135     {
01136         if (IS_A(pChildNode,NodeBlender))
01137         {
01138             NodeBlender* pNodeBlender = (NodeBlender*)pChildNode;
01139             INT32 PathIndexStart = pNodeBlender->GetPathIndexStart();
01140             INT32 PathIndexEnd   = pNodeBlender->GetPathIndexEnd();
01141 
01142             // Convert the AW path indexes into Camelot path indexes
01143             if (!pNodeBlender->ConvertAWPathIndexesToCamelot(&PathIndexStart,&PathIndexEnd))
01144             {
01145                 ERROR2(FALSE,"Unable to convert artworks path indexes in EndBlend()");
01146             }
01147 
01148             // Init the blender to blend the prev and next ink nodes together
01149             if (!pNodeBlender->Initialise(NULL,NULL,PathIndexStart,PathIndexEnd,ImportInfo.pOp,NULL,TRUE))
01150             {
01151                 ERROR2(FALSE,"Unable to initialise a node blender in EndBlend()");
01152             }
01153 
01154             BlenderCount++;
01155         }
01156         pChildNode = pChildNode->FindNext();
01157     }
01158 
01159     if (BlenderCount == 0)
01160     {
01161         ERROR3("Imported Blend node doesn't contain any blender nodes");
01162         if (!ImportInfo.pOp->DoHideNode(pBlend, TRUE))
01163             return FALSE;
01164     }
01165 
01166     return TRUE;
01167 }
01168 
01169 
01170 /********************************************************************************************
01171 
01172 >   BOOL ArtWorksEPSFilter::ProcessBlender()
01173 
01174     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01175     Created:    23/11/94
01176     Returns:    TRUE if the blender was processed correctly, FALSE if not.
01177     Purpose:    Reads in all the elements of a blender structure in the EPS file.
01178     Errors:     Syntax error in EPS file, Out of memory
01179 
01180 ********************************************************************************************/
01181 
01182 BOOL ArtWorksEPSFilter::ProcessBlender()
01183 {
01184     if (!StartBlender())
01185         return FALSE;
01186 
01187     // Keep processing tokens until we find the end of the blender
01188     do
01189     {
01190         GetToken();
01191 
01192         // Look for the end of the blender token...
01193         if (Token == EPSC_aebr)
01194         {
01195             return EndBlender();
01196         }
01197     }
01198     // Otherwise keep going until an error or eof is encountered
01199     while (HandleToken() && (!EPSFile->eof()));
01200 
01201     if (EPSFile->eof())
01202     {
01203         // Didn't find end of blender - syntax error; deal with it
01204         HandleEPSError();
01205     }
01206 
01207     // If we're here, something went wrong
01208     return FALSE;
01209 }
01210 
01211 /********************************************************************************************
01212 
01213 >   BOOL ArtWorksEPSFilter::StartBlender()
01214 
01215     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01216     Created:    23/11/94
01217     Returns:    TRUE if the new blender was created ok;
01218                 FALSE if not.
01219     Purpose:    Used when a blender structure needs to be created - after this is called,
01220                 all new paths will be discarded, until EndBlender is called.
01221     Errors:     Out of memory
01222     SeeAlso:    ArtWorksEPSFilter::EndBlender
01223 
01224 ********************************************************************************************/
01225 
01226 BOOL ArtWorksEPSFilter::StartBlender()
01227 {
01228     UINT32 NumBlendSteps;
01229     INT32 Expanded,OneToOne,Complex;
01230     INT32 PathIndexStart,PathIndexEnd;
01231     
01232     // Get the blender params
01233     BOOL    ok = Stack.Pop(&PathIndexEnd);
01234     if (ok) ok = Stack.Pop(&PathIndexStart);
01235     if (ok) ok = Stack.Pop(&NumBlendSteps);
01236     if (ok) ok = Stack.Pop(&OneToOne);
01237     if (ok) ok = Stack.Pop(&Complex);
01238     if (ok) ok = Stack.Pop(&Expanded);
01239     if (!ok)
01240     {
01241         HandleEPSError();
01242         return FALSE;
01243     }
01244 
01245     // Make a new blender node for this blender
01246     NodeBlender *pNodeBlender = new NodeBlender;
01247     if (pNodeBlender == NULL)
01248     {
01249         HandleNoMemory();
01250         return FALSE;
01251     }
01252 
01253     // Add it into the tree
01254     if (!AddNewNode(pNodeBlender))
01255     {
01256         delete pNodeBlender;
01257         HandleNoMemory();
01258         return FALSE;
01259     }
01260 
01261     // If both indexes are -ve, don't change the start points of the paths when blending
01262     if (PathIndexEnd < 0 && PathIndexEnd < 0)
01263         PathIndexStart = PathIndexEnd = 0;
01264 
01265     // Set the AW path indexes to be used when we get an "aebd" (end blend) token
01266     pNodeBlender->SetPathIndexStart(PathIndexStart);
01267     pNodeBlender->SetPathIndexEnd  (PathIndexEnd);
01268 
01269     // Some of these flags are stored in the parent blend node in Camelot - so set them!
01270     if (!IS_A(pNode,NodeBlend))
01271     {
01272         ERROR2(FALSE,"Found a blender token without finding a blend");
01273     }
01274 
01275     NodeBlend* pNodeBlend = (NodeBlend*)pNode;
01276     pNodeBlend->SetNumBlendSteps(NumBlendSteps-1);
01277     pNodeBlend->SetOneToOne(OneToOne);
01278 
01279     // Discard all paths between this and the aebr tokens
01280     ThePathType = PATH_DISCARD_STICKY;
01281 
01282     // All ok
01283     return TRUE;
01284 }
01285 
01286 /********************************************************************************************
01287 
01288 >   BOOL ArtWorksEPSFilter::EndBlender()
01289 
01290     Author:     Mark_Neves (Xara Group Ltd) <camelotdev@xara.com>
01291     Created:    23/11/94
01292     Returns:    TRUE if the blender was ended ok;
01293                 FALSE if not.
01294     Purpose:    Used when a blender has finished being constructed.
01295                 Paths are not longer discarded
01296     Errors:     -
01297     SeeAlso:    ArtWorksEPSFilter::StartBlender
01298 
01299 ********************************************************************************************/
01300 
01301 BOOL ArtWorksEPSFilter::EndBlender()
01302 {
01303     ThePathType = PATH_NORMAL;
01304     return TRUE;
01305 }
01306 
01307 
01308 
01309 /********************************************************************************************
01310 
01311 >   BOOL ArtWorksEPSFilter::ProcessEnvelope()
01312 
01313     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01314     Created:    06/03/94
01315     Returns:    TRUE if the envelope object was processed correctly, 
01316                 FALSE if not.
01317     Purpose:    Reads in all the elements of an envelope structure in the ArtWorksEPS file 
01318                 and builds the camelot envelope tree
01319     Errors:     Syntax error in EPS file, Out of memory
01320 
01321     Notes:      This reader is reasonably complex. It is made so soley by the problem of
01322                 being unable to calculate an inverse transform of an envelope. The crux of
01323                 the matter is this. If you apply attributes to an already enveloped set of
01324                 objects (lets call them the Dset), then in some way the attributes need to
01325                 be applied to the source objects (the Sset). Now when you do this in ArtWorks
01326                 eg, apply a linear fill to the Dset, the same fill is exported as applied to
01327                 the Sset. Import the file back in and ArtWorks rebuilds both Sset and Dset
01328                 from the file applying all necessary attributes there in. This works. But
01329                 now we have a Dset attribute applied to an Sset object. As soon as you
01330                 regenerate the Dset from the Sset (by tweeking the envelope shape) the new
01331                 attributes created are wrong, as it transforms already transformed 
01332                 attributes.
01333                 Ok, this problem prevents me from simply loading all Sset members from the
01334                 file and recreating the Dset automatically. The loaded image does not look
01335                 correct when grad fills are applied. (ie more often than not).
01336                 Complexity level 1.
01337                 To combat this problem, I'll do as ArtWorks did and load both Sset & Dset
01338                 members. However, another problem arrises here....
01339                 ArtWorks envelope structure is as follows
01340 
01341                   line col
01342                   fill col
01343                   start env
01344                      envelope shape
01345                      fill col
01346                      invisible path   (Sset)
01347                         mangled path  (Dset)
01348                      fill col
01349                      invisible path   (Sset)
01350                         mangled path  (Dset)
01351                   end env
01352 
01353                 and this is saved as such in its EPS structure. Now Camelots structure is
01354                 slightly different. It creates a source tree for Sset and a destination tree
01355                 for Dset. Hence we need to disassemble the AW structure into two trees with
01356                 the correct attributes in each.
01357                 How do we do this?
01358                 Complexity level 2.
01359                 We could do this while importing, keeping two trees on the go, importing the
01360                 correct bits into the correct tree. However this has many problems associated
01361                 with it. Globally applied atts will need to be created in both trees. Groups too.
01362                 We would have to intercept far more than the envelope tokens during import to
01363                 do it. - no chance.
01364                 So the only way to do it is to import the structure as is, creating an Artworks
01365                 envelope inside Camelot. This will be structured as follows
01366 
01367                   Env
01368                    |
01369                    > EnvShape => MouldGroup => Moulder
01370                                      |
01371                                      > { Sset + Dset objects }
01372 
01373 
01374                 Having done this, we will convert this into
01375 
01376                   Env
01377                    |
01378                    > EnvShape => MouldGroup => Moulder
01379                                      |           |
01380                                      > Sset      > Dset
01381 
01382                 So long as we can tell the difference between Sset and Dset objects, which
01383                 we can (all Dset objs are primary children of an Sset obj and Dset objects
01384                 never contain Sset objs as children) we can use object move technology to
01385                 build the correct moulder. Attributes will move (via inheritance) correctly 
01386                 with objects.
01387 
01388 ********************************************************************************************/
01389 
01390 BOOL ArtWorksEPSFilter::ProcessEnvelope()
01391 {
01392     // NOT IMPLEMENTED
01393     if (!StartMould(MOULDSPACE_ENVELOPE))
01394         return FALSE;
01395     
01396     if (ProcessMould())
01397         // If we've completed then all is well
01398         return EndMould();
01399 
01400     if (EPSFile->eof())
01401     {
01402         // Didn't find end of envelope - syntax error; deal with it
01403         HandleEPSError();
01404     }
01405 
01406     // if made it here all is not well
01407     return FALSE;
01408 }
01409 
01410 /********************************************************************************************
01411 
01412 >   BOOL ArtWorksEPSFilter::ProcessPerspective()
01413 
01414     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01415     Created:    06/03/94
01416     Returns:    TRUE if the perspective object was processed correctly, 
01417                 FALSE if not.
01418     Purpose:    Reads in all the elements of an perspective structure in the EPS file.
01419     Errors:     Syntax error in EPS file, Out of memory
01420     SeeAlso:    ProcessEnvelope() for furher details
01421 
01422 ********************************************************************************************/
01423 
01424 BOOL ArtWorksEPSFilter::ProcessPerspective()
01425 {
01426     // NOT IMPLEMENTED
01427     if (!StartMould(MOULDSPACE_PERSPECTIVE))
01428         return FALSE;
01429 
01430     // If we've completed then all is well
01431     if (ProcessMould())
01432         return EndMould();
01433 
01434     if (EPSFile->eof())
01435     {
01436         // Didn't find end of perspective - syntax error; deal with it
01437         HandleEPSError();
01438     }
01439 
01440     // if made it here all is not well
01441     return FALSE;
01442 }
01443 
01444 
01445 
01446 
01447 /********************************************************************************************
01448 
01449 >   BOOL ArtWorksEPSFilter::StartMould(MouldSpace mSpace)
01450 
01451     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> (from MarkN's)
01452     Created:    06/03/95
01453     Inputs:     mSpace = Mould geometry to define, either envelope or perspective
01454     Returns:    TRUE if the new mould object was created ok;
01455                 FALSE if not.
01456     Purpose:    Used when an mould structure needs to be created - after this is called,
01457                 all new nodes added with AddNewNode() will be added as children of this
01458                 new mould, until EndMould is called.
01459     Errors:     Out of memory
01460     SeeAlso:    ArtWorksEPSFilter::EndMould
01461 
01462 ********************************************************************************************/
01463 
01464 BOOL ArtWorksEPSFilter::StartMould(MouldSpace mSpace)
01465 {
01466     // Read in the bounding box of the original objects
01467     if (!Stack.PopCoordPair(&MouldRect.hi) || 
01468         !Stack.PopCoordPair(&MouldRect.lo))
01469     {
01470         HandleEPSError();
01471         return FALSE;
01472     }
01473 
01474     // create a mould parent and insert it in the tree
01475     NodeMould* pMouldParent = new NodeMould;
01476     if (pMouldParent==NULL)
01477     {
01478         HandleNoMemory();
01479         return FALSE;
01480     }
01481 
01482     // give the parent mould object a shape and mould space to work with and stick it
01483     // in the tree
01484     if (!pMouldParent->CreateGeometry(mSpace))
01485     {
01486         delete pMouldParent;
01487         HandleNoMemory();
01488         return FALSE;
01489     }
01490 
01491     if (!AddNewNode(pMouldParent))
01492     {
01493         HandleNoMemory();
01494         return FALSE;
01495     }
01496             
01497     // Make sure new objects are added as children of the mould
01498     pNode = pMouldParent;
01499 
01500     // All ok
01501     return TRUE;
01502 }
01503 
01504 
01505 
01506 /********************************************************************************************
01507 
01508 >   BOOL ArtWorksEPSFilter::EndEnvelope()
01509 
01510     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01511     Created:    06/03/95
01512     Returns:    TRUE if the envelope was ended ok;
01513                 FALSE if not.
01514     Purpose:    Used when a envelope has finished being constructed and we want to return to
01515                 normal node positioning.
01516     SeeAlso:    ArtWorksEPSFilter::StartEnvelope()
01517 
01518 ********************************************************************************************/
01519 
01520 BOOL ArtWorksEPSFilter::EndMould()
01521 {
01522     // Sanity check
01523     ERROR3IF(!pNode->IsKindOf(CC_RUNTIME_CLASS(NodeMouldGroup)), "No mouldgroup in ArtWorksEPSFilter::EndMould");
01524 //  NodeMouldGroup* pNodeMGroup = (NodeMouldGroup*)pNode;
01525     pNode = pNode->FindParent();
01526     ERROR3IF(!pNode->IsKindOf(CC_RUNTIME_CLASS(NodeMould)), "No MouldParent in ArtWorksEPSFilter::EndMould");
01527     NodeMould* pNodeMould = (NodeMould*)pNode;
01528 
01529     NodeMoulder* pMoulder = pNodeMould->CreateNewMoulder(NULL);
01530     if (!pMoulder)
01531     {
01532         HandleNoMemory();
01533         return FALSE;
01534     }
01535 
01536     // Add it into the tree as the last child of the mould
01537     if (!AddNewNode(pMoulder))
01538     {
01539         HandleNoMemory();
01540         return FALSE;
01541     }
01542 
01543     // Right, now we need to scan through all moulded objects and copy their fill and
01544     // stroke styles to the originals. We need to do this because the original objects
01545     // within the file are terminated by h and H functions. These describe closed and open
01546     // (none filled,none stroked) paths ie invisible paths. Hence to create the correct
01547     // original styles we need to take the definitions from the destination objects
01548     // instead. This means when we edit the imported mould the drawing doesn't suddenly
01549     // take on random fill and stroke styles.
01550 
01551     // Right here comes the difficult bit. What we have now is a really interresting
01552     // structure. We should have a complete tree beneath the mould group node. This tree
01553     // contains invisible source objects and visible moulded shapes. So if we we're to
01554     // render this tree, it would look sensible. Now we need to disassemble this tree
01555     // by placing all the moulded objects and their attributes inside our moulder object.
01556     // This we will do by copying the entire tree and deleting the right bits. (Isn't it
01557     // yuk but there you go, its the only sensible and simple way of doing it, without
01558     // massively duplicating bits of code.
01559 
01560     // go and convert the artworks tree
01561     if (!ConvertArtMould(pNodeMould))
01562     {
01563         HandleNoMemory();
01564         return FALSE;
01565     }
01566 
01567     // and finally move pNode up one level
01568     pNode = pNode->FindParent();
01569     ERROR3IF(pNode==NULL, "No parent of envelope in ArtWorksEPSFilter::EndMould");
01570 
01571     return TRUE;
01572 }
01573 
01574 
01575 /********************************************************************************************
01576 
01577 >   BOOL ArtWorksEPSFilter::ProcessMould()
01578 
01579     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01580     Created:    06/03/95
01581     Returns:    TRUE if the mould was processed ok;
01582                 FALSE if not.
01583     Purpose:    Processes tokens inside a mould object. Tokens specific to mould objects
01584                 are processed along with some overridding of default tokens such as groups
01585     SeeAlso:
01586     
01587 ********************************************************************************************/
01588 
01589 BOOL ArtWorksEPSFilter::ProcessMould()
01590 {
01591     // Keep processing tokens until we find the end of the envelope
01592     while (!EPSFile->eof())
01593     {
01594         GetToken();
01595 
01596         // Look for the end of the envelope token...
01597         switch (Token)
01598         {
01599             case EPSC_aeev:
01600             case EPSC_aepr:
01601                 // if we've found the envelope/perspective end then
01602                 // all is well.
01603                 return TRUE;
01604                 break;
01605 
01606             case EPSC_apc:
01607                 // Create next object as a child
01608                 if (!ProcessMangledObjs())
01609                     return FALSE;
01610                 break;
01611 
01612             case EPSC_u:
01613                 // NOT IMPLEMENTED INSIDE MOULDS
01614                 break;
01615 
01616             case EPSC_U:
01617                 // NOT IMPLEMENTED INSIDE MOULDS
01618                 break;
01619 
01620             case EPSC_aof:
01621                 // don't need this token
01622                 if (!Stack.Discard(2))
01623                 {
01624                     HandleEPSError();
01625                     return FALSE;
01626                 }
01627                 break;
01628 
01629             case EPSC_h:
01630                 Token = EPSC_b;
01631                 if (!HandleToken())
01632                     return FALSE;
01633                 break;
01634 
01635             case EPSC_H:
01636                 Token = EPSC_B;
01637                 if (!HandleToken())
01638                     return FALSE;
01639                 break;
01640 
01641             default:
01642                 // try to handle whatever token this is.
01643                 if (!HandleToken()) 
01644                     return FALSE;
01645                 break;
01646         }
01647     }
01648 
01649     HandleEPSError();
01650     return FALSE;
01651 }
01652 
01653 
01654 
01655 
01656 
01657 /********************************************************************************************
01658 
01659 >   BOOL ArtWorksEPSFilter::ProcessMouldShape()
01660 
01661     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01662     Created:    06/03/94
01663     Returns:    TRUE if the shape has been read correctly, 
01664                 FALSE if not.
01665     Purpose:    Reads in all the elements of a mould geometry held in the EPS file.
01666                 The description of the geometry for this particular file type is that of
01667                 a path. Depending on the geometry type (perspective or envelope) we will
01668                 obviously expect a slightly different path. The rules are, that currently
01669                 perspective geometry is described as {m,l,l,l,l} and envelope geometry
01670                 is {m,c,c,c,c}. Internally we are not restricted to these but ArtworksEPS
01671                 certainly is.
01672                 Input Stack = coord, coord
01673     Errors:     Syntax error in EPS file, Out of memory
01674 
01675 ********************************************************************************************/
01676 
01677 BOOL ArtWorksEPSFilter::ProcessMouldShape()
01678 {
01679     // We really should be inside a mould object at this stage
01680     if (!IS_A(pNode,NodeMould)) 
01681     {
01682         ERROR3("Mould shape found outside a mould object");
01683         return FALSE;
01684     }
01685 
01686     NodeMould* pNodeMould = (NodeMould*)pNode;
01687 
01688     // Create a path object to read the mould geometry into
01689     Path TempPath;
01690     if (!TempPath.Initialise(24,12))
01691     {
01692         HandleNoMemory();
01693         return FALSE;
01694     }
01695 
01696     // Set the current used slots to none
01697     INT32 numt = 0;
01698     DocCoord Ta,Tb,Tc;
01699     PathFlags flags;
01700     flags.IsSelected = FALSE;
01701 
01702     // ok, pop off the move stacked coordinate
01703     BOOL ok = Stack.PopCoordPair(&Ta);
01704     if (!ok)
01705     {
01706         HandleEPSError();
01707         return FALSE;
01708     }
01709 
01710     // Add this first element as a move to
01711     if (!TempPath.AddMoveTo(Ta, &flags))
01712     {
01713         HandleNoMemory();
01714         return FALSE;
01715     }
01716 
01717     // increase the number of tokens read
01718     numt++;
01719     BOOL done = FALSE;
01720 
01721     // Keep processing tokens until we find the end of the mould path
01722     while (!done && (!EPSFile->eof()))
01723     {
01724         GetToken();
01725 
01726         // {m,c,c,c,c,c,c,c,c,e} is current maximum
01727         // if more complex, then illegal
01728         if ((numt++)>60)
01729         {
01730             HandleEPSError();
01731             return FALSE;
01732         }
01733 
01734         switch (Token)
01735         {
01736             case EPSC_aml:
01737                 // lineto (x,y) found
01738                         ok = Stack.PopCoordPair(&Ta);
01739                 if (ok) ok = TempPath.AddLineTo(Ta, &flags);
01740                 break;
01741                                                 
01742             case EPSC_amc:
01743                 // curveto (x0,y0,x1,y1,x2,y2) found
01744                         ok = Stack.PopCoordPair(&Tc);
01745                 if (ok) ok = Stack.PopCoordPair(&Tb);
01746                 if (ok) ok = Stack.PopCoordPair(&Ta);
01747                 if (ok) ok = TempPath.AddCurveTo(Ta,Tb,Tc,&flags);
01748                 break;
01749 
01750             case EPSC_amcp:
01751                 // found a close path. That should be it for path elements
01752                 ok = TempPath.CloseSubPath();
01753                 break;
01754 
01755             case EPSC_amep:
01756                 // end path drawfile parameter completes the path
01757                 // it contains a single 'length' parameter which seems
01758                 // to be zero always
01759                 ok = Stack.Discard();
01760                 done = TRUE;
01761                 break;
01762 
01763             default:
01764                 // try to handle whatever token this is.
01765                 ok = HandleToken();
01766                 break;
01767         }
01768 
01769         if (!ok)
01770         {
01771             HandleNoMemory();
01772             return FALSE;
01773         }
01774     }
01775 
01776     // We have read the path so now lets try and build the geometry
01777     // check the shape we've been given is fine and lovely  
01778     UINT32 errID;
01779     if (!pNodeMould->GetGeometry()->Validate(&TempPath,errID))
01780     {
01781         // ok the path we read is invalid so lets try to build a valid one
01782         Path* pPath = NULL;
01783         INT32 Corners[4] = {0, 3, 6, 9}; 
01784 
01785         if (!pNodeMould->GetGeometry()->MakeValidFrom(&pPath, &TempPath, Corners))
01786         {
01787             ERROR2(FALSE,"Unable to rectify invalid mould path in ProcessMouldShape()");
01788         }
01789  
01790         if (!TempPath.CloneFrom(*pPath))
01791         {
01792             delete pPath;
01793             HandleNoMemory();
01794             return FALSE;
01795         }
01796 
01797         delete pPath;
01798     }
01799 
01800     // Build and if necessary fit the geometry
01801     NodeMouldPath* pNodeMPath = pNodeMould->CreateNewMouldShape(&TempPath,NULL,NULL);
01802     if (pNodeMPath==NULL) 
01803     {
01804         HandleNoMemory();   
01805         return FALSE;
01806     }
01807 
01808     // set the geometry using this new mould shape
01809     if (!pNodeMould->GetGeometry()->Define(&(pNodeMPath->InkPath), &MouldRect))
01810     {
01811         HandleNoMemory();
01812         return FALSE;
01813     }
01814 
01815     // having created the shape bung it in the tree.
01816     if (!AddNewNode(pNodeMPath))
01817     {
01818         delete pNodeMPath;
01819         HandleNoMemory();
01820         return FALSE;
01821     }
01822 
01823     // Create a mould group object
01824     NodeMouldGroup* pMouldGroup = pNodeMould->CreateNewMouldGroup(NULL);
01825     if (pMouldGroup==NULL)
01826     {
01827         HandleNoMemory();
01828         return FALSE;
01829     }
01830 
01831     if (!AddNewNode(pMouldGroup))
01832     {
01833         delete pMouldGroup;
01834         HandleNoMemory();
01835         return FALSE;
01836     }
01837 
01838     // finally leave the insert pointer on the MouldGroup object
01839     pNode = pMouldGroup;
01840 
01841     return TRUE;
01842 
01843 }
01844 
01845 
01846 
01847 /********************************************************************************************
01848 
01849 >   BOOL ArtWorksEPSFilter::ProcessMangledObjs()
01850 
01851     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01852     Created:    06/03/94
01853     Returns:    TRUE if the mangled object has been dealt with correctly
01854                 FALSE if not.
01855     Purpose:    On finding a 'apc' token in the input stream, this function is executed.
01856                 It will process all further tokens in the stream until a path termination
01857                 has been found. A path terminator is considered any of { s,S,b,B,f,F,h,H }
01858                 Its purpose is strictly defined. It must place the next set of attributes
01859                 and single path as children of the last object imported rather than the 
01860                 default action which would be to stick them in as siblings of the object.
01861 
01862     Errors:     Syntax error in EPS file, Out of memory
01863 
01864 ********************************************************************************************/
01865 
01866 BOOL ArtWorksEPSFilter::ProcessMangledObjs()
01867 {
01868     // Set the new position of pNode, our insert indicator
01869     Node *pOldPos = pNode;
01870     pNode=pNode->FindLastChild();
01871     if (pNode==NULL)
01872     {
01873         pNode=pOldPos;
01874         return FALSE;
01875     }
01876 
01877     BOOL ok = TRUE, end = FALSE;
01878 
01879     // The next path we create should be mangled
01880     ThePathType = PATH_MANGLED;
01881 
01882     while ((!end) && (!EPSFile->eof()) && (ok))
01883     {
01884         GetToken();
01885 
01886         switch (Token)
01887         {
01888             case EPSC_axm:
01889                 // ignore axm in this context
01890                 // See notes on func HandleMouldedFill below
01891                 ok = Stack.Discard(4);
01892                 break;
01893                 
01894             case EPSC_s: case EPSC_f: case EPSC_b: case EPSC_h:
01895             case EPSC_S: case EPSC_F: case EPSC_B: case EPSC_H:
01896                 // We've finished so set term flag
01897                 end = TRUE;
01898                 ok = HandleToken();
01899                 break;
01900 
01901             default:
01902                 // try to handle whatever token it was.
01903                 ok = HandleToken();
01904                 break;
01905         }
01906     }
01907 
01908     // Set the path back to something sensible
01909     ThePathType=PATH_NORMAL;
01910     pNode=pOldPos;
01911 
01912     if (ok && !(EPSFile->eof())) 
01913         return TRUE;
01914 
01915     // Arrgh didn't find an end-of-path token - syntax error; deal with it
01916     HandleEPSError();
01917     return FALSE;
01918 }
01919 
01920 
01921 
01922 /********************************************************************************************
01923 
01924 >   BOOL ArtWorksEPSFilter::HandleMouldedFill()
01925 
01926     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01927     Created:    06/03/94
01928     Inputs:     -
01929     Returns:    TRUE if the mangled fill has been dealt with correctly
01930                 FALSE if not.
01931     Purpose:    On finding a 'axm' token in the input stream, this function is executed.
01932                 It will build a graduated fill structure and set it as the current fill
01933                 style to be applied to future objects. The function has been split off from
01934                 the main structure for one very important reason. Fills applied to moulds
01935                 work in a random way. Imagine the senario, you have a rectangle, and you
01936                 envelope it. You then apply a linear grad fill to it. If this gets exported
01937                 as AWEPS what you get are two objects, one moulded and one rectangle. Now
01938                 you also get a moulded and none moulded fill style represented by ax and
01939                 axm. Unfortunately although ax stands for 'standard fill style' and axm is
01940                 used as an override describing the coordinates of a moulded fill (hence the
01941                 m) the coordinates of both fills are reversed. DONT ASK ME WHY, ASK THE
01942                 AUTHOR OF AWEPS! So we have to perform some brain dead processing here to
01943                 get the right attributes applied to the right objects.              
01944 
01945     Errors:     Syntax error in EPS file, Out of memory
01946 
01947 ********************************************************************************************/
01948 
01949 BOOL ArtWorksEPSFilter::HandleMouldedFill()
01950 {
01951 
01952     BOOL ok;
01953 
01954     DocCoord StartPoint, EndPoint;
01955     DocColour StartColour, EndColour;
01956 
01957     // Get start and end positions for grad-fills
01958     if (!Stack.PopCoordPair(&EndPoint) || !Stack.PopCoordPair(&StartPoint))
01959         return FALSE;
01960 
01961     // read the last definitions of set colours
01962     if (LastFillType>0)
01963     {
01964         GetEPSColour(&StartColour,
01965                      &LastStartColour.Col, 
01966                      LastStartColour.Tint,
01967                      LastStartColour.TintVal,
01968                      &LastStartColour.ColName);
01969 
01970         GetEPSColour(&EndColour,
01971                      &LastEndColour.Col, 
01972                      LastEndColour.Tint,
01973                      LastEndColour.TintVal,
01974                      &LastEndColour.ColName);
01975     }
01976 
01977     switch (LastFillType)
01978     {
01979         // Decode ArtWorks EPS grad fill codes
01980         case 1:
01981             // Check for silly grad fills first...
01982             if (StartPoint==EndPoint)
01983                 ok = SetFillColour(StartColour);
01984             else
01985                 ok = SetLinearFill(StartColour, EndColour, StartPoint, EndPoint);
01986             break;
01987 
01988         case 2:
01989             // Check for silly grad fills first...
01990             if (StartPoint==EndPoint)
01991                 ok=SetFillColour(EndColour);
01992             else
01993                 ok=SetRadialFill(StartColour, EndColour, StartPoint, EndPoint);
01994             break;
01995 
01996         default:
01997             // if there's no fill applied previously then this is rampant so ignore it.
01998             ok=Stack.Discard(4);
01999     }
02000     
02001     return ok;
02002 }
02003 
02004 /********************************************************************************************
02005 
02006 >   BOOL ArtWorksEPSFilter::ConvertMouldStyles(Node* pNode)
02007 
02008     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
02009     Created:    06/03/94
02010     Inputs:     pNode - a pointer to an object to start scanning from
02011     Returns:    TRUE if the mould styles have been converted correctly
02012                 FALSE if not.
02013     Purpose:    Scan through all moulded objects, copying their fill and stroke styles
02014                 to the original objects (which are currently their parents)
02015 
02016 ********************************************************************************************/
02017 
02018 BOOL ArtWorksEPSFilter::ConvertMouldStyles(Node* pNode)
02019 {
02020     Node *qNode, *rNode;
02021     BOOL IsFilled = FALSE, IsStroked = FALSE;
02022 
02023     while (pNode)
02024     {
02025         qNode=pNode;
02026         pNode=pNode->FindNext();
02027 
02028         // if its mangled delete it otherwise scan its kids
02029         if (qNode->IsMangled())
02030         {
02031             rNode = qNode->FindParent();
02032             if (rNode)
02033             {
02034                 // this should be polymorphic but there's no virtual func to
02035                 // do it so I'll have to be explicit.
02036                 if (IS_A(qNode, NodePath))
02037                 {
02038                     IsFilled  = ((NodePath*)qNode)->InkPath.IsFilled;
02039                     IsStroked = ((NodePath*)qNode)->InkPath.IsStroked;
02040 
02041                     if (rNode->IsKindOf(CC_RUNTIME_CLASS(NodePath)))
02042                     {
02043                         ((NodePath*)rNode)->InkPath.IsFilled  = IsFilled;
02044                         ((NodePath*)rNode)->InkPath.IsStroked = IsStroked;
02045                     }
02046                     else if (rNode->IsKindOf(CC_RUNTIME_CLASS(NodeSimpleShape)))
02047                     {
02048                         ((NodePath*)rNode)->InkPath.IsFilled  = IsFilled;
02049                         ((NodePath*)rNode)->InkPath.IsStroked = IsStroked;
02050                     }
02051                 }
02052             }
02053         }
02054         else
02055             ConvertMouldStyles(qNode->FindFirstChild());
02056     }
02057     return TRUE;
02058 }
02059 
02060 
02061 /********************************************************************************************
02062 
02063 >   BOOL ArtWorksEPSFilter::ConvertArtMould(NodeMould* pNodeMould)
02064 
02065     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
02066     Created:    06/03/94
02067     Inputs:     pNodeMould - a pointer to the mould object
02068     Returns:    TRUE if the artworks mould has been converted correctly
02069                 FALSE if not.
02070     Purpose:    Right here comes the difficult bit. What we have now is a really interresting
02071                 structure. We should have a complete tree beneath the mould group node 
02072                 containing invisible source objects and visible moulded shapes. So if we were to
02073                 render this tree, it would look sensible. Now we need to disassemble this tree
02074                 by placing all the moulded objects and their attributes inside our moulder object.
02075                 This we will do by copying the entire tree and deleting the right bits. (Isn't it
02076                 yuk but there you go, its the only sensible and simple way of doing it, without
02077                 massively duplicating bits of code.
02078     Errors:     Syntax error in EPS file, Out of memory
02079 
02080 ********************************************************************************************/
02081 
02082 BOOL ArtWorksEPSFilter::ConvertArtMould(NodeMould* pNodeMould)
02083 
02084 {
02085     ERROR2IF(pNodeMould==NULL, FALSE, "NULL mould pointer passed to ConvertArtMould()");
02086 
02087     NodeMouldGroup* pNodeMGroup = pNodeMould->FindMouldGroup();
02088     if (pNodeMGroup==NULL)
02089         return FALSE;
02090 
02091     NodeMoulder* pMoulder = pNodeMould->FindFirstMoulder();
02092     if (pMoulder==NULL)
02093         return FALSE;
02094 
02095     Node *pNode;
02096     // Stage 1
02097     // Copy all objects from the mould group to this new moulder object
02098 
02099     pNode = pNodeMGroup->FindFirstChild();
02100     while (pNode)
02101     {
02102         if (!pNode->CopyNode(pMoulder,LASTCHILD))
02103         {
02104             pMoulder->CascadeDelete();
02105             return FALSE;
02106         }
02107         pNode=pNode->FindNext();
02108     }
02109 
02110     // Stage2
02111     // Scan through deleting all mangled objects in the source tree
02112     pNode=pNodeMGroup->FindFirstChild();
02113     DeleteAllMangled(pNode);
02114 
02115     //Stage 3
02116     //Scan through deleting all none mangled objects in the destination tree
02117     //but leaving the mangled versions!
02118     pNode=pMoulder->FindFirstChild();
02119     DeleteAllNoneMangled(pNode);
02120 
02121     return TRUE;
02122 }
02123 
02124 
02125 
02126 /********************************************************************************************
02127 
02128 >   void ArtWorksEPSFilter::DeleteAllMangled(Node* pNode)
02129 
02130     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
02131     Created:    09/03/95
02132     Inputs:     pNode = a pointer to a node to start deleting from
02133     Returns:    -
02134     Purpose:    Delete all nodes with their mangled bits set at and below pNode
02135     SeeAlso:
02136 
02137 ********************************************************************************************/
02138 
02139 void ArtWorksEPSFilter::DeleteAllMangled(Node* pNode)
02140 {
02141     Node *qNode;
02142 
02143     while (pNode)
02144     {
02145         qNode=pNode;
02146         pNode=pNode->FindNext();
02147 
02148         // if its mangled delete it otherwise scan its kids
02149         if (qNode->IsMangled())
02150         {
02151             qNode->CascadeDelete();
02152             delete qNode;
02153         }
02154         else
02155             DeleteAllMangled(qNode->FindFirstChild());
02156     }
02157 }
02158         
02159 /********************************************************************************************
02160 
02161 >   void ArtWorksEPSFilter::DeleteAllNoneMangled(Node* pNode)
02162 
02163     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
02164     Created:    09/03/95
02165     Inputs:     pNode = a pointer to a node to start deleting from
02166     Returns:    -
02167     Purpose:    Delete all renderable parents of mangled objects from pNode onwards.
02168                 This really is a specialised function and should be used with care. It
02169                 scans through the tree, hunting for mangled objects. When one is found
02170                 it will attempt to promote the node to become a sibling of its parent and
02171                 delete the parent. It will only do so if the parent is renderable.
02172                 We know or are assuming this is a confined and sensible action. It is only
02173                 so having loaded an ArtWorksEPS envelope or perspective object.
02174     SeeAlso:
02175 
02176 ********************************************************************************************/
02177 
02178 BOOL ArtWorksEPSFilter::DeleteAllNoneMangled(Node* pNode)
02179 {
02180     Node* qNode;
02181     while (pNode)
02182     {
02183         qNode=pNode;
02184         pNode=pNode->FindNext();
02185         if (!PromoteMangled(qNode))
02186             DeleteAllNoneMangled(qNode->FindFirstChild());
02187     }
02188     return TRUE;
02189 }   
02190 
02191 /********************************************************************************************
02192 
02193 >   BOOL ArtWorksEPSFilter::PromoteMangled(Node* rNode)
02194 
02195     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
02196     Created:    09/03/95
02197     Inputs:     rNode = a pointer to a mangled node to promote
02198     Returns:    -
02199     Purpose:    Promote all mangled child nodes to siblings of their parents.
02200 
02201 ********************************************************************************************/
02202 
02203 BOOL ArtWorksEPSFilter::PromoteMangled(Node* rNode)
02204 {
02205     Node* sNode;
02206     sNode=rNode->FindFirstChild();
02207     while (sNode)
02208     {
02209         if (sNode->IsMangled())
02210         {
02211             sNode->SetMangled(FALSE);
02212             sNode->MoveNode(rNode,NEXT);
02213             rNode->CascadeDelete();
02214             delete rNode;
02215             return TRUE;
02216         }
02217         sNode=sNode->FindNext();
02218     }
02219     return FALSE;
02220 }
02221 
02222 /********************************************************************************************
02223 
02224 >   BitmapFilterSupport ArtWorksEPSFilter::GetBitmapSupportLevel()
02225 
02226     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
02227     Created:    30/01/95
02228     Returns:    SimpleBitmapSupport - This filter has simple support for bitmap images;
02229                                       they must be saved into the file whenever
02230                                       they are used.
02231     Purpose:    Determine how well this filter supports bitmaps when exporting.
02232 
02233 ********************************************************************************************/
02234 
02235 BitmapFilterSupport ArtWorksEPSFilter::GetBitmapSupportLevel()
02236 {
02237     // ArtWorks EPS has simple bitmap support
02238     return SimpleBitmapSupport;
02239 }
02240 
02242 // ArtWorksEPSRenderRegion methods.
02243 
02244 CC_IMPLEMENT_DYNAMIC(ArtWorksEPSRenderRegion, EPSRenderRegion)
02245 
02246 /********************************************************************************************
02247 
02248 >   ArtWorksEPSRenderRegion(DocRect ClipRect, Matrix ConvertMatrix, FIXED16 ViewScale)
02249 
02250     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
02251     Created:    15/04/94
02252     Purpose:    Initialise a render region for exporting ArtWorks EPS. Sets up the
02253                 string to put in the %%Creator comment.
02254     SeeAlso:    EPSRenderRegion::EPSRenderRegion
02255 
02256 ********************************************************************************************/
02257 
02258 ArtWorksEPSRenderRegion::ArtWorksEPSRenderRegion(DocRect ClipRect,
02259                                                  Matrix ConvertMatrix, 
02260                                                  FIXED16 ViewScale) 
02261     : EPSRenderRegion(ClipRect, ConvertMatrix, ViewScale)
02262 {
02263     CreatorString = _T("ArtWorks");
02264 }
02265 
02266 
02267 /********************************************************************************************
02268 
02269 >   BOOL ArtWorksEPSRenderRegion::StartRender()
02270 
02271     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
02272     Created:    06/12/94
02273     Returns:    TRUE if render region started rendering mechanisms ok.
02274     Purpose:    Over-rides normal EPS StartRender() function - this is because we want to
02275                 have a different default winding rule when exporting as ArtWorks EPS.
02276 
02277 ********************************************************************************************/
02278 
02279 BOOL ArtWorksEPSRenderRegion::StartRender()
02280 {
02281 #ifdef DO_EXPORT
02282     // Check the base class is working ok.
02283     if (!EPSRenderRegion::StartRender())
02284         return FALSE;
02285 
02286     // Set up normal ArtWorks default rendering - basic difference is that ArtWorks
02287     // uses even-odd winding rule.
02288     // NB. it only does it for 'proper' ArtWorks render regions, not any derived
02289     //     from this class.
02290     if (IS_A(this, ArtWorksEPSRenderRegion))
02291         SetWindingRule(EvenOddWinding);
02292 
02293     // All ok
02294     return TRUE;
02295 #else
02296     return FALSE;
02297 #endif
02298 }
02299 
02300 /********************************************************************************************
02301 
02302 >   void ArtWorksEPSRenderRegion::GetValidPathAttributes()
02303 
02304     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
02305     Created:    30/03/94
02306     Purpose:    See EPSRenderRegion::GetValidPathAttributes.
02307                 This version checks and handles grad fill colours before calling the
02308                 base class version.
02309     SeeAlso:    EPSRenderRegion::GetValidPathAttributes
02310 
02311 ********************************************************************************************/
02312 
02313 void ArtWorksEPSRenderRegion::GetValidPathAttributes()
02314 {
02315 #ifdef DO_EXPORT
02316     KernelDC *pDC = (KernelDC*)CCDC::ConvertFromNativeDC(RenderDC);
02317 
02318     FillGeometryAttribute *pFillAttr = (FillGeometryAttribute *) CurrentAttrs[ATTR_FILLGEOMETRY].pAttr;
02319 
02320     if ((pFillAttr->IsKindOf(CC_RUNTIME_CLASS(GradFillAttribute))) &&
02321         SetLastOutputAttribute(ATTR_FILLGEOMETRY))
02322     {
02323         // Output a grad fill command...
02324 
02325         // Output the fill type
02326         if (pFillAttr->IsKindOf(CC_RUNTIME_CLASS(LinearFillAttribute)))
02327         {
02328             pDC->OutputToken(_T("1"));
02329         }
02330         else if (pFillAttr->IsKindOf(CC_RUNTIME_CLASS(RadialFillAttribute)))
02331         {
02332             pDC->OutputToken(_T("2"));
02333         }
02334         else
02335         {
02336             // Bodge: ought to handle this more gracefully soon...i.e. get the
02337             // fill provider to render the fill using normal path rendering code.
02338             ENSURE(FALSE, "Unsupported grad fill encountered while exporting");
02339             EPSRenderRegion::GetValidPathAttributes();
02340             return;
02341         }
02342 
02343         // Get the start colour and end colour in CMYK, and output them.
02344         GradFillAttribute *pGradFillAttr = (GradFillAttribute *) pFillAttr;
02345         pDC->OutputNamedColour(&pGradFillAttr->Colour);
02346         pDC->OutputNamedColour(&pGradFillAttr->EndColour);
02347     
02348         // Output the start and end points of the grad fill
02349         pDC->OutputCoord(pGradFillAttr->StartPoint);
02350         pDC->OutputCoord(pGradFillAttr->EndPoint);
02351 
02352         // Output the grad fill token
02353         pDC->OutputToken(_T("ax"));
02354         pDC->OutputNewLine();
02355     }
02356 
02357     if (SetLastOutputAttribute(ATTR_WINDINGRULE))
02358     {
02359         WindingRuleAttribute *pWindingRuleAttr = 
02360             (WindingRuleAttribute *) CurrentAttrs[ATTR_WINDINGRULE].pAttr;
02361 
02362         switch (pWindingRuleAttr->WindingRule)
02363         {
02364             case NonZeroWinding:
02365                 // Change winding rule to 0, which means non-zero in ArtWorks EPS.
02366                 pDC->OutputToken(_T("0"));
02367                 pDC->OutputToken(_T("awr"));
02368                 pDC->OutputNewLine();
02369                 break;
02370 
02371             case EvenOddWinding:
02372                 // Change winding rule to 1, which means even-odd in ArtWorks EPS.
02373                 pDC->OutputToken(_T("1"));
02374                 pDC->OutputToken(_T("awr"));
02375                 pDC->OutputNewLine();
02376                 break;
02377 
02378             case NegativeWinding:
02379             case PositiveWinding:
02380                 // Not supported in ArtWorks EPS - ignore.
02381                 break;
02382 
02383             default:
02384                 ERROR3("Unknown winding rule encountered while exporting.");
02385                 break;
02386                 
02387         }
02388     }
02389 
02390     // Handle usual pens/brushes
02391     EPSRenderRegion::GetValidPathAttributes();
02392 #endif
02393 }
02394 
02395 /********************************************************************************************
02396 
02397 >   BOOL ArtWorksEPSRenderRegion::WriteEPSBoundingBox ( void )
02398 
02399     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
02400     Created:    19/5/000
02401     Inputs:     -
02402     Returns:    TRUE if ok;
02403                 FALSE if error (e.g. file/disk error or printer driver error)
02404     Purpose:    Writes an EPS bounding box.
02405     SeeAlso:    EPSRenderRegion::InitDevice
02406 
02407 ********************************************************************************************/
02408 
02409 BOOL ArtWorksEPSRenderRegion::WriteEPSBoundingBox ( void )
02410 {
02411     // Scale conversion between millipoints and millimetres.
02412     const double    Scale           = 25.4 / 72000.0;
02413 
02414     // Cast a pointer to the appropriate DC.
02415     KernelDC        *pDC            = static_cast<KernelDC*> ( CCDC::ConvertFromNativeDC(RenderDC) );
02416     DocRect         PageBounds      = RenderSpread->GetPageBounds ();
02417     DocRect         DrawingBounds   = RenderSpread->GetDrawingSize ();
02418     TCHAR           Buffer [256];
02419 
02420     // Set up the output buffer.
02421     camSnprintf( Buffer, 256, _T("%gmm %gmm"),
02422                static_cast<double> ( PageBounds.Width () )  * Scale,
02423                static_cast<double> ( PageBounds.Height () ) * Scale );
02424 
02425     // Output the page size data.
02426     pDC->OutputToken    (_T("%%DocumentPageSize:"));
02427     pDC->OutputToken    ( Buffer );
02428     pDC->OutputNewLine  ();
02429 
02430     // Write the AW bounding box out. I'm doing this manually because ArtWorks runs at a
02431     // higher resolution than standard EPS files. This way I get an extra two decimal
02432     // places of accuracy.
02433     pDC->OutputToken    ( _T("%%BoundingBox:") );
02434     pDC->OutputCoord    ( DrawingBounds.lo, ACCURACY_NORMAL );
02435     pDC->OutputCoord    ( DrawingBounds.hi, ACCURACY_NORMAL );
02436     pDC->OutputNewLine  ();
02437 
02438     // Success.
02439     return TRUE;
02440 }
02441 
02442 /********************************************************************************************
02443 
02444 >   BOOL ArtWorksEPSRenderRegion::WriteEPSTrailerComments ( void )
02445 
02446     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
02447     Created:    22/5/000
02448     Inputs:     -
02449     Returns:    TRUE if ok;
02450                 FALSE if error (e.g. file/disk error or printer driver error)
02451     Purpose:    Writes out an EPS trailer.
02452     SeeAlso:    EPSRenderRegion::CloseDown
02453 
02454 ********************************************************************************************/
02455 
02456 BOOL ArtWorksEPSRenderRegion::WriteEPSTrailerComments ( void )
02457 {
02458     // Get a pointer to the kernel DC.
02459     KernelDC    *pDC    = static_cast<KernelDC*> ( CCDC::ConvertFromNativeDC(RenderDC) );
02460 
02461     // Write out the trailer comments.
02462     pDC->OutputToken    ( _T("%%Trailer") );
02463     pDC->OutputNewLine  ();
02464     pDC->OutputToken    ( _T("showpage") );
02465     pDC->OutputNewLine  ();
02466 
02467     // Success.
02468     return TRUE;
02469 }
02470 
02471 
02472 /********************************************************************************************
02473 
02474 >   virtual void ArtWorksEPSRenderRegion::OutputStrokeColour ()
02475 
02476     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02477     Created:    7/12/00
02478     Inputs:     -
02479     Returns:    -
02480     Purpose:    Writes out the stroke colour. Since AW can't cope with our new Xa/XA and 
02481                 Xx/XX.RGB colour tokens, this function is overridden to use only the old 
02482                 CMYK tokens (k/K and x/X)
02483     SeeAlso:    EPSRenderRegion::OutputStrokeColour
02484 
02485 ********************************************************************************************/
02486 
02487 void ArtWorksEPSRenderRegion::OutputStrokeColour ()
02488 {
02489     EPSRenderRegion::OutputStrokeCMYKColour ();
02490 }
02491 
02492 
02493 /********************************************************************************************
02494 
02495 >   virtual void ArtWorksEPSRenderRegion::OutputFillColour ()
02496 
02497     Author:     Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com>
02498     Created:    7/12/00
02499     Inputs:     -
02500     Returns:    -
02501     Purpose:    Writes out the fill colour. Since AW can't cope with our new Xa/XA and 
02502                 Xx/XX.RGB colour tokens, this function is overridden to use only the old 
02503                 CMYK tokens (k/K and x/X)
02504     SeeAlso:    EPSRenderRegion::OutputStrokeColour
02505 
02506 ********************************************************************************************/
02507 
02508 void ArtWorksEPSRenderRegion::OutputFillColour ()
02509 {
02510     EPSRenderRegion::OutputFillCMYKColour ();
02511 }

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