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 }