00001 // $Id: epsfiltr.cpp 1668 2006-08-04 11:45:17Z 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 // An EPS import/export filter system for Camelot. 00100 00101 00102 #include "camtypes.h" 00103 //#include "epsfiltr.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00104 00105 #include <ctype.h> 00106 00107 //#include "attrmgr.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00108 #include "bitfilt.h" 00109 #include "ccdc.h" 00110 #include "colcomp.h" 00111 #include "csrstack.h" 00112 //#include "doccomp.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00113 //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00114 //#include "docview.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00115 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00116 //#include "ensure.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00117 #include "prvwflt.h" 00118 #ifndef WEBSTER 00119 //#include "extfilts.h" 00120 #endif //WEBSTER 00121 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00122 //#include "group.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00123 #include "layer.h" 00124 #include "lineattr.h" 00125 #include "nativeps.h" // old native filter based on eps, used for version 1.1 00126 #include "nodeelip.h" 00127 #include "nodepath.h" 00128 #include "noderect.h" 00129 //#include "oilfltrs.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00130 #include "page.h" 00131 #include "paper.h" 00132 //#include "pathname.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00133 //#include "paths.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00134 #include "progress.h" 00135 //#include "resource.h" 00136 //#include "rik.h" 00137 #include "saveeps.h" 00138 #include "sglayer.h" 00139 #include "sprdmsg.h" 00140 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00141 //#include "tim.h" 00142 //#include "trans2d.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00143 #include "gclips.h" 00144 #include "nodetxts.h" 00145 #include "nodetxtl.h" 00146 #include "nodershp.h" 00147 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00148 #include "insertnd.h" 00149 #include "fontman.h" 00150 #include "guides.h" 00151 //#include "nev.h" // _R(IDN_USER_CANCELLED) 00152 //#include "will2.h" 00153 #include "moldshap.h" 00154 #include "ai_bmp.h" 00155 //#include "epsclist.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00156 #include "epscdef.h" 00157 #include "nodetext.h" 00158 00159 DECLARE_SOURCE("$Revision: 1668 $"); 00160 00161 CC_IMPLEMENT_DYNAMIC(EPSFilter, VectorFilter); 00162 CC_IMPLEMENT_MEMDUMP(RangeList, List); 00163 CC_IMPLEMENT_MEMDUMP(EPSClipContext, List); 00164 CC_IMPLEMENT_MEMDUMP(EPSClipContextItem, ListItem); 00165 00166 #define new CAM_DEBUG_NEW 00167 00168 // Job 10463: remove PS Level bits - default to Level 2 00169 INT32 EPSFilter::XSEPSExportPSType = 2; 00170 INT32 EPSFilter::XSEPSExportDPI = 200; 00171 BOOL EPSFilter::XSEPSExportTextAsCurves = FALSE; 00172 00173 /******************************************************************************************** 00174 00175 > class RangeListItem : public ListItem 00176 00177 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00178 Created: 28/09/94 00179 Purpose: Hold a range that 00180 SeeAlso: 00181 00182 ********************************************************************************************/ 00183 00184 class RangeListItem : public ListItem 00185 { 00186 CC_DECLARE_MEMDUMP(RangeListItem) 00187 00188 public: 00189 RangeListItem(Node *pFirst, Node *pLast); 00190 BOOL IsLayer; 00191 Range TheRange; 00192 Layer *TheLayer; 00193 }; 00194 00195 CC_IMPLEMENT_MEMDUMP(RangeListItem, ListItem) 00196 00197 /******************************************************************************************** 00198 00199 > RangeListItem::RangeListItem(Node *pFirst, Node *pLast) 00200 00201 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00202 Created: 29/09/94 00203 Inputs: pFirst, pLast - the first and last nodes in the range. 00204 Purpose: Create a range list item using the specified node range. 00205 SeeAlso: RangeListItem; RangeList 00206 00207 ********************************************************************************************/ 00208 00209 RangeListItem::RangeListItem(Node *pFirst, Node *pLast) 00210 { 00211 // range or layer? 00212 if(pFirst == pLast && IS_A(pFirst, Layer)) 00213 { 00214 // just a layer, so make a layer variant 00215 TheLayer = (Layer *)pFirst; 00216 IsLayer = TRUE; 00217 } 00218 else 00219 { 00220 // it's more than one, or not a layer 00221 00222 // We want all nodes to be included in the range 00223 RangeControl Flags; 00224 Flags.Selected = TRUE; 00225 Flags.Unselected = TRUE; 00226 00227 // Make the range and copy to where we want it (spot slight omission from Range class!) 00228 Range Tmp(pFirst, pLast, Flags); 00229 TheRange = Tmp; 00230 IsLayer = FALSE; 00231 } 00232 } 00233 00234 /******************************************************************************************** 00235 00236 > BOOL RangeList::AddRange(Node *pFirst, Node *pLast) 00237 00238 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00239 Created: 28/09/94 00240 Inputs: pFirst, pLast - the first and last nodes in the range. 00241 Returns: TRUE if the range was added ok; 00242 FALSE if not. 00243 Purpose: Adds another range to the range list. All nodes from pFirst to pLast 00244 are inclusively added to the range. 00245 SeeAlso: Range 00246 00247 ********************************************************************************************/ 00248 00249 BOOL RangeList::AddRange(Node *pFirst, Node *pLast) 00250 { 00251 // Get a new range 00252 RangeListItem *pItem = new RangeListItem(pFirst, pLast); 00253 if (pItem == NULL) 00254 // Out of memory 00255 return FALSE; 00256 00257 // Add it to the list and return success 00258 AddTail(pItem); 00259 return TRUE; 00260 } 00261 00262 /******************************************************************************************** 00263 00264 > DocRect RangeList::GetBoundingRect() 00265 00266 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00267 Created: 29/09/94 00268 Returns: The union of the bounding boxes of all nodes in this range list. 00269 Purpose: Goes through all nodes in all the ranges in this RangeList, and unions 00270 all the bounding boxes together. It uses the simple algorithm, which does 00271 not take account of the attributes applied to the nodes - i.e. it only 00272 gives an approximation (hence this function can result in bounding boxes 00273 being in the tree which are not entirely accurate). 00274 SeeAlso: RangeList 00275 00276 ********************************************************************************************/ 00277 00278 DocRect RangeList::GetBoundingRect() 00279 { 00280 // Start off with empty rectangle 00281 DocRect RangeBBox; 00282 00283 // Do each range in turn 00284 RangeListItem *pItem = (RangeListItem *) GetHead(); 00285 00286 while (pItem != NULL) 00287 { 00288 // Do each node in turn 00289 if(pItem->IsLayer) 00290 { 00291 // layer based calcuations 00292 00293 // see long note below 00294 RangeBBox = RangeBBox.Union(pItem->TheLayer->GetBoundingRect(TRUE)); 00295 } 00296 else 00297 { 00298 // range based calculations 00299 Node *pNode = pItem->TheRange.FindFirst(); 00300 00301 while (pNode != NULL) 00302 { 00303 // Does this node have a bounding rectangle? 00304 if (pNode->IsBounded()) 00305 { 00306 // Yes - add it to our union 00307 NodeRenderableBounded *pNodeBounded = (NodeRenderableBounded *) pNode; 00308 00309 // Pass in TRUE so that we don't do a 'proper' attribute scan for the 00310 // bounding box - we only need an approximate bounding rectangle 00311 // for centering it anyway. 00312 // NB. this results in inaccurate bounding boxes in the tree, but when 00313 // we call this we're about to transform them anyway, so they'll 00314 // be updated correctly afterwards. 00315 RangeBBox = RangeBBox.Union(pNodeBounded->GetBoundingRect(TRUE)); 00316 } 00317 else 00318 { 00319 ENSURE(FALSE, "Found a non-renderable node in the import range"); 00320 } 00321 00322 // Try the next node. 00323 pNode = pItem->TheRange.FindNext(pNode); 00324 } 00325 } 00326 00327 // Try the next range 00328 pItem = (RangeListItem *) GetNext(pItem); 00329 } 00330 00331 // Return the accumulated bounds 00332 return RangeBBox; 00333 } 00334 00335 /******************************************************************************************** 00336 00337 > void RangeList::Transform(TransformBase& Trans) 00338 00339 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00340 Created: 29/09/94 00341 Inputs: Trans - the transform object to transform all the nodes by. 00342 Purpose: Transforms all the nodes in all the ranges of this range list using the 00343 transform object given. 00344 SeeAlso: Range::Transform; TransformBase 00345 00346 ********************************************************************************************/ 00347 00348 void RangeList::Transform(TransformBase& Trans) 00349 { 00350 // Do each range in turn 00351 RangeListItem *pItem = (RangeListItem *) GetHead(); 00352 00353 while (pItem != NULL) 00354 { 00355 if(pItem->IsLayer) 00356 { 00357 pItem->TheLayer->Transform(Trans); 00358 } 00359 else 00360 { 00361 // Transform all nodes in this range 00362 Node *pNode = pItem->TheRange.FindFirst(); 00363 00364 while (pNode != NULL) 00365 { 00366 // Is this node renderable? 00367 if (pNode->IS_KIND_OF(NodeRenderable)) 00368 { 00369 // Yes - transform it. 00370 NodeRenderable *pNodeRenderable = (NodeRenderable *) pNode; 00371 pNodeRenderable->Transform(Trans); 00372 } 00373 else 00374 { 00375 ENSURE(FALSE, "Found a non-renderable node in the import range"); 00376 } 00377 00378 // Try the next node. 00379 pNode = pItem->TheRange.FindNext(pNode); 00380 } 00381 } 00382 00383 // Try the next range 00384 pItem = (RangeListItem *) GetNext(pItem); 00385 } 00386 } 00387 00388 /******************************************************************************************** 00389 00390 > EPSClipContextItem::EPSClipContextItem(INT32 TheContextLevel, InkPath *pNewClipPath) 00391 00392 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00393 Created: 05/22/95 00394 Inputs: TheContextLevel - the context level for this clip region. 00395 Purpose: Initialise the clip region item to sensible values. 00396 SeeAlso: EPSClipContext 00397 00398 ********************************************************************************************/ 00399 00400 EPSClipContextItem::EPSClipContextItem(INT32 TheContextLevel, Path *pNewClipPath) 00401 { 00402 ContextLevel = TheContextLevel; 00403 pClipPath = pNewClipPath; 00404 00405 // Defaults to not a complex region. 00406 ComplexRegionLevel = 0; 00407 } 00408 00409 /******************************************************************************************** 00410 00411 > EPSClipContextItem::~EPSClipContextItem() 00412 00413 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00414 Created: 05/22/95 00415 Purpose: Clean up the context item - this includes deleting the clipping path held 00416 in the region item. 00417 SeeAlso: EPSClipContext 00418 00419 ********************************************************************************************/ 00420 00421 EPSClipContextItem::~EPSClipContextItem() 00422 { 00423 delete pClipPath; 00424 } 00425 00426 /******************************************************************************************** 00427 00428 > EPSClipContext::EPSClipContext() 00429 00430 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00431 Created: 05/22/95 00432 Purpose: Initialise the context to a sensible state, i.e. a zero context level. 00433 00434 ********************************************************************************************/ 00435 00436 EPSClipContext::EPSClipContext() 00437 { 00438 ContextLevel = 0; 00439 ComplexRegionLevel = 0; 00440 00441 // Initially there is no clip region. 00442 pCachedClipPath = NULL; 00443 CacheIsValid = TRUE; 00444 00445 // set default clipping flags 00446 ClippingFlags = 2 | CLIPPING_CLIP_WINDING; 00447 } 00448 00449 /******************************************************************************************** 00450 00451 > void EPSClipContext::SaveContext() 00452 00453 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00454 Created: 05/22/95 00455 Purpose: Save the current clipping state for future use - no matter how many 00456 clip regions are added to the current context, the exact state of the 00457 current clipping context can be restore with a (balanced) call to 00458 EPSClipContext::RestoreContext(). 00459 SeeAlso: EPSClipContext::RestoreContext 00460 00461 ********************************************************************************************/ 00462 00463 void EPSClipContext::SaveContext() 00464 { 00465 ContextLevel++; 00466 } 00467 00468 /******************************************************************************************** 00469 00470 > BOOL EPSClipContext::RestoreContext() 00471 00472 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00473 Created: 05/22/95 00474 Purpose: Restores the clipping context to the state it was in the last time 00475 SaveContext() was called on this clip context. 00476 Errors: No call to SaveContext() has been made => ERROR2 00477 SeeAlso: EPSClipContext::SaveContext 00478 00479 ********************************************************************************************/ 00480 00481 BOOL EPSClipContext::RestoreContext() 00482 { 00483 // Invalidate cache 00484 CacheIsValid = FALSE; 00485 00486 // Sanity check 00487 ERROR2IF(ContextLevel == 0, FALSE, "Unbalanced call to EPSClipContext::RestoreContext()"); 00488 00489 // Decrement context level 00490 ContextLevel--; 00491 00492 // Delete all items added since save context was last called... 00493 EPSClipContextItem *pItem = (EPSClipContextItem *) GetTail(); 00494 00495 while ((pItem != NULL) && (pItem->ContextLevel > ContextLevel)) 00496 { 00497 delete RemoveTail(); 00498 00499 // Get the next item 00500 pItem = (EPSClipContextItem *) GetTail(); 00501 } 00502 00503 // If we get here then it's ok 00504 return TRUE; 00505 } 00506 00507 00508 /******************************************************************************************** 00509 00510 > BOOL EPSClipContext::StartComplexClipRegion() 00511 00512 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00513 Created: 05/22/95 00514 Returns: TRUE if ok; 00515 FALSE if out of memory. 00516 Purpose: Indicates that we are about to start constructing a complex clipping region. 00517 All future calls to AddNewClippingPath() will be joined into the current 00518 clipping region until EndComplexRegion is called. 00519 Note that you cannot interleave these calls with Save/Restore context calls; 00520 complex regions cannot be unbalanced across context levels. 00521 Errors: Out of memory => ERROR1 00522 SeeAlso: EPSClipContext::EndComplexClipRegion() 00523 00524 ********************************************************************************************/ 00525 00526 BOOL EPSClipContext::StartComplexClipRegion() 00527 { 00528 // Update complex region count 00529 ComplexRegionLevel++; 00530 00531 // We need to create a record to hold this complex region 00532 // (it has a NULL clipping region initially) 00533 EPSClipContextItem *pItem = new EPSClipContextItem(ContextLevel, NULL); 00534 if (pItem == NULL) 00535 // Out of memory 00536 return FALSE; 00537 00538 // It's a complex region so save the level 00539 pItem->ComplexRegionLevel = ComplexRegionLevel; 00540 00541 // Add to end of list 00542 AddTail(pItem); 00543 00544 // All ok 00545 return TRUE; 00546 } 00547 00548 /******************************************************************************************** 00549 00550 > BOOL EPSClipContext::EndComplexClipRegion() 00551 00552 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00553 Created: 05/22/95 00554 Returns: TRUE if ok; 00555 FALSE if no corresponding call to StartComplexClipRegion() has been 00556 encountered => ERROR2 00557 Purpose: See StartComplexClipRegion(). 00558 Errors: If unbalanced call is made => ERROR2 00559 SeeAlso: EPSClipContext::StartComplexClipRegion 00560 00561 ********************************************************************************************/ 00562 00563 BOOL EPSClipContext::EndComplexClipRegion() 00564 { 00565 ERROR2IF(ComplexRegionLevel == 0, FALSE, 00566 "Unbalanced call to EPSClipContext::EndComplexClipRegion()"); 00567 00568 // Adjust complex region level. 00569 ComplexRegionLevel--; 00570 00571 // All ok 00572 return TRUE; 00573 } 00574 00575 00576 /******************************************************************************************** 00577 00578 > BOOL EPSClipContext::AddNewClippingPath(Path *pNewClipPath) 00579 00580 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00581 Created: 05/22/95 00582 Inputs: The path to augment the current clipping region with. 00583 Returns: TRUE if clipping region updated ok; 00584 FALSE if not, i.e. out of memory => ERROR1 00585 Purpose: Takes a copy of the path passed in and merges it with the current clipping 00586 context. 00587 Errors: Out of memory => ERROR1 00588 00589 ********************************************************************************************/ 00590 00591 BOOL EPSClipContext::AddNewClippingPath(Path *pNewClipPath) 00592 { 00593 // Invalidate cache 00594 CacheIsValid = FALSE; 00595 00596 // Flag to indicate if we just do a straightforward copy 00597 BOOL SimpleCopy = FALSE; 00598 00599 EPSClipContextItem *pItem = NULL; 00600 00601 if (ComplexRegionLevel > 0) 00602 { 00603 // We are building a complex region, so join the new path with the existing one. 00604 00605 // First, make sure we have a clip path already? 00606 pItem = (EPSClipContextItem *) GetTail(); 00607 if (pItem->pClipPath == NULL) 00608 { 00609 // No clip path - just copy the new path and use that. 00610 SimpleCopy = TRUE; 00611 } 00612 else 00613 { 00614 // Already have a clip path - join with new one to form a complex path. 00615 if (!pItem->pClipPath->MergeTwoPaths(*pNewClipPath)) 00616 // Error occured (i.e. out of memory) 00617 return FALSE; 00618 } 00619 } 00620 else 00621 { 00622 // Just a simple clipping region 00623 pItem = new EPSClipContextItem(ContextLevel, NULL); 00624 00625 if (pItem == NULL) 00626 // Out of memory 00627 return FALSE; 00628 00629 // Add to end of list 00630 AddTail(pItem); 00631 00632 // Just copy the path passed in 00633 SimpleCopy = TRUE; 00634 } 00635 00636 // Should we just copy the path into the list item? 00637 if (SimpleCopy) 00638 { 00639 // Sanity check 00640 ERROR2IF(pItem == NULL, FALSE, "No clipping item found!"); 00641 00642 // (yes, this code is pretty tedious!) 00643 pItem->pClipPath = new Path; 00644 00645 if (pItem->pClipPath == NULL) 00646 // Out of memory 00647 return FALSE; 00648 00649 // Graeme (26/7/00) - Added a test for a NULL pointer to prevent access violations. 00650 if ( pNewClipPath != NULL && 00651 !pItem->pClipPath->Initialise ( pNewClipPath->GetNumCoords () + 3, 12 ) ) 00652 { 00653 // Failed to initialise - out of memory 00654 return FALSE; 00655 } 00656 00657 if (!pItem->pClipPath->CopyPathDataFrom(pNewClipPath)) 00658 // Failed to copy - out of memory - but this shouldn't happen as 00659 // we made sure we had enough space with the initialise call! 00660 ERROR2(FALSE, "Unexpected out-of-space error when copying clipping path"); 00661 } 00662 00663 // If we've got here, it must have worked... 00664 return TRUE; 00665 } 00666 00667 00668 /******************************************************************************************** 00669 00670 > BOOL EPSClipContext::ClipPathToRegion(Path *pPathToClip) 00671 00672 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00673 Created: 05/22/95 00674 Inputs: pPathToClip - the path object that we want to clip 00675 Outputs: pPathToClip - the clipped version of the path 00676 Returns: TRUE if clipped ok; 00677 FALSE if not. 00678 Purpose: Given a path, clip it to the current clipping region specified by this 00679 object. 00680 SeeAlso: EPSClipContext::GetClipRegion 00681 00682 ********************************************************************************************/ 00683 00684 BOOL EPSClipContext::ClipPathToRegion(Path *pPathToClip) 00685 { 00686 // Cope with NULL clip region first 00687 if (GetClipRegion() == NULL) 00688 // Path is already 'clipped' 00689 return TRUE; 00690 00691 // Ensure GetClipRegion validated the cache 00692 ERROR2IF(!CacheIsValid, FALSE, 00693 "Could not get valid clipping path in EPSClipContext::ClipPathToRegion()"); 00694 00695 // We now have a valid region, so use it to clip the given path 00696 // NB. we do an intersection using the cliping path's winding, with a tolerance of 0, 00697 // and flatness of 128 millipoints (arbitrary). 00698 if (pCachedClipPath->ClipPathToPath(*pPathToClip, pPathToClip, ClippingFlags, 00699 128, 256, 256) == -1) 00700 { 00701 // An error occured... 00702 return FALSE; 00703 } 00704 00705 // Initialise flags so the bezier tool is happy 00706 // [see comment for Path::ClipPathToPath()]. 00707 pPathToClip->InitialiseFlags(); 00708 00709 // If we get this far, it worked! 00710 return TRUE; 00711 } 00712 00713 /******************************************************************************************** 00714 00715 > Path *EPSClipContext::GetClipRegion() 00716 00717 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00718 Created: 05/22/95 00719 Returns: Pointer to the clipping path, or 00720 NULL if no clipping region is specified by this object. 00721 Purpose: Get the path which defines the current clipping region ofheld by this 00722 object. 00723 SeeAlso: EPSClipContext::ClipPathToRegion 00724 00725 ********************************************************************************************/ 00726 00727 Path *EPSClipContext::GetClipRegion() 00728 { 00729 if (!CacheIsValid) 00730 { 00731 // Cache is invalid - if there is no path in the cache, get a new one, otherwise 00732 // empty the one in the cache and use that. 00733 if (pCachedClipPath == NULL) 00734 { 00735 pCachedClipPath = new Path; 00736 00737 if (pCachedClipPath == NULL) 00738 // Out of memory 00739 return NULL; 00740 00741 if (!pCachedClipPath->Initialise(12, 12)) 00742 // Failed to initialise - out of memory 00743 return NULL; 00744 } 00745 else 00746 { 00747 // Just clear this path out so we can use it to build a clipping region. 00748 pCachedClipPath->ClearPath(); 00749 } 00750 00751 // Calculate the current clipping path - we do this by going along the region 00752 // list and combining the clip regions. 00753 EPSClipContextItem *pItem = (EPSClipContextItem *) GetHead(); 00754 00755 while (pItem != NULL) 00756 { 00757 if (pItem->pClipPath != NULL) 00758 { 00759 // Do we already have a clipping region? 00760 if (pCachedClipPath->GetNumCoords() > 0) 00761 { 00762 // Combine this clipping region with the region being constructed... 00763 if (pItem->pClipPath->ClipPathToPath(*pCachedClipPath, pCachedClipPath, 00764 2 | CLIPPING_CLIP_WINDING, 00765 128, 256, 256) == -1) 00766 { 00767 // An error occured... 00768 return FALSE; 00769 } 00770 } 00771 else 00772 { 00773 // No clipping region yet - just copy the data from this path 00774 if (!pCachedClipPath->MakeSpaceInPath(pItem->pClipPath->GetNumCoords() + 3)) 00775 // Failed to initialise - out of memory 00776 return FALSE; 00777 00778 if (!pCachedClipPath->CopyPathDataFrom(pItem->pClipPath)) 00779 // Failed to copy - out of memory - but this shouldn't happen as 00780 // we made sure we had enough space with the initialise call! 00781 ERROR2(FALSE, "Unexpected out-of-space error when copying clipping path"); 00782 } 00783 } 00784 00785 // Get the next item 00786 pItem = (EPSClipContextItem *) GetNext(pItem); 00787 } 00788 00789 // Did we get any clipping at all? 00790 if (pCachedClipPath->GetNumCoords() == 0) 00791 { 00792 // No clip region - delete and use NULL to indicate this. 00793 delete pCachedClipPath; 00794 pCachedClipPath = NULL; 00795 } 00796 00797 // Validate cache 00798 CacheIsValid = TRUE; 00799 } 00800 00801 // Cache must be valid, so return the contents of the cache. 00802 return pCachedClipPath; 00803 } 00804 00805 00806 // This is the array of ArtWorks EPS command/keyword names. 00807 CommandMap EPSFilter::Commands[] = 00808 { 00809 // Path Construction operators 00810 { EPSC_l, _T("l") }, 00811 { EPSC_c, _T("c") }, 00812 { EPSC_m, _T("m") }, 00813 { EPSC_L, _T("L") }, 00814 { EPSC_C, _T("C") }, 00815 { EPSC_v, _T("v") }, 00816 { EPSC_V, _T("V") }, 00817 { EPSC_y, _T("y") }, 00818 { EPSC_Y, _T("Y") }, 00819 00820 // Colour operators 00821 { EPSC_g, _T("g") }, 00822 { EPSC_G, _T("G") }, 00823 { EPSC_k, _T("k") }, 00824 { EPSC_K, _T("K") }, 00825 { EPSC_x, _T("x") }, 00826 { EPSC_X, _T("X") }, 00827 { EPSC_p, _T("p") }, 00828 { EPSC_P, _T("P") }, 00829 00830 // Path Painting operators 00831 { EPSC_N, _T("N") }, 00832 { EPSC_n, _T("n") }, 00833 { EPSC_F, _T("F") }, 00834 { EPSC_f, _T("f") }, 00835 { EPSC_S, _T("S") }, 00836 { EPSC_s, _T("s") }, 00837 { EPSC_B, _T("B") }, 00838 { EPSC_b, _T("b") }, 00839 { EPSC__u, _T("*u") }, 00840 { EPSC__U, _T("*U") }, 00841 00842 // Group operators 00843 { EPSC_u, _T("u") }, 00844 { EPSC_U, _T("U") }, 00845 00846 // Graphics state operators 00847 { EPSC_A, _T("A") }, 00848 { EPSC_d, _T("d") }, 00849 { EPSC_i, _T("i") }, 00850 { EPSC_D, _T("D") }, 00851 { EPSC_j, _T("j") }, 00852 { EPSC_J, _T("J") }, 00853 { EPSC_M, _T("M") }, 00854 { EPSC_w, _T("w") }, 00855 00856 // Special operators 00857 { EPSC_ArrayStart,_T("[") }, 00858 { EPSC_ArrayEnd,_T("]") }, 00859 { EPSC_Slash, _T("/") }, 00860 00861 // Overprint operators 00862 { EPSC_O, _T("O") }, 00863 { EPSC_R, _T("R") }, 00864 00865 // Clipping operators 00866 { EPSC_q, _T("q") }, 00867 { EPSC_Q, _T("Q") }, 00868 { EPSC_H, _T("H") }, 00869 { EPSC_h, _T("h") }, 00870 { EPSC_W, _T("W") }, 00871 00872 // Text operators 00873 { EPSC_To, _T("To") }, 00874 { EPSC_TO, _T("TO") }, 00875 { EPSC_Tp, _T("Tp") }, 00876 { EPSC_TP, _T("TP") }, 00877 00878 // Matrix operators 00879 { EPSC_Tm, _T("Tm") }, 00880 { EPSC_Td, _T("Td") }, 00881 { EPSC_T_, _T("T*") }, 00882 { EPSC_TR, _T("TR") }, 00883 00884 // Text Attribute operators 00885 { EPSC_Tr, _T("Tr") }, 00886 { EPSC_Tf, _T("Tf") }, 00887 { EPSC_Ta, _T("Ta") }, 00888 { EPSC_Tl, _T("Tl") }, 00889 { EPSC_Tt, _T("Tt") }, 00890 { EPSC_TW, _T("TW") }, 00891 { EPSC_Tw, _T("Tw") }, 00892 { EPSC_TC, _T("TC") }, 00893 { EPSC_Tc, _T("Tc") }, 00894 { EPSC_Ts, _T("Ts") }, 00895 { EPSC_Ti, _T("Ti") }, 00896 { EPSC_Tz, _T("Tz") }, 00897 { EPSC_TA, _T("TA") }, 00898 { EPSC_Tq, _T("Tq") }, 00899 00900 // Text Body operators 00901 { EPSC_Tx, _T("Tx") }, 00902 { EPSC_Tj, _T("Tj") }, 00903 { EPSC_TX, _T("TX") }, 00904 { EPSC_Tk, _T("Tk") }, 00905 { EPSC_TK, _T("TK") }, 00906 { EPSC_Tplus, _T("T+") }, 00907 { EPSC_Tminus, _T("T-") }, 00908 00909 // Misc 00910 { EPSC_showpage,_T("showpage") }, 00911 { EPSC_end, _T("end") }, 00912 { EPSC_ctx, _T("ctx") }, 00913 { EPSC_ctex, _T("ctex") }, 00914 00915 { EPSC_Invalid, _T("Invalid") }, 00916 00917 { EPSC_Name, _T("Name") }, 00918 { EPSC_Integer, _T("Integer") }, 00919 { EPSC_Double, _T("Double") }, 00920 { EPSC_FixedPoint,_T("FixedPt") }, 00921 { EPSC_String, _T("String") }, 00922 { EPSC_Comment, _T("Comment") }, 00923 { EPSC_EOL, _T("EOL") }, 00924 { EPSC_EOF, _T("EOF") } 00925 }; 00926 00927 00928 RangeList EPSFilter::ImportRange; 00929 00930 /******************************************************************************************** 00931 00932 > EPSFilter::EPSFilter() 00933 00934 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 00935 Created: 28/10/93 00936 Purpose: Constructor for an EPSFilter object. The object should be initialised 00937 before use. 00938 SeeAlso: EPSFilter::Init 00939 00940 ********************************************************************************************/ 00941 00942 EPSFilter::EPSFilter() 00943 { 00944 ImportMsgID = _R(IDT_IMPORTMSG_AI); 00945 Flags.CanImport = TRUE; 00946 //WEBSTER-Martin-27/01/97 00947 #ifdef WEBSTER 00948 Flags.CanExport = FALSE; 00949 #else 00950 Flags.CanExport = TRUE; 00951 #endif //WEBSTER 00952 FilterID = FILTERID_AIEPS; 00953 00954 #ifndef DO_EXPORT 00955 Flags.CanExport = FALSE; 00956 #endif 00957 00958 EPSFile = NULL; 00959 TokenBuf = NULL; 00960 pColours = NULL; 00961 00962 ExportDCPtr = NULL; 00963 ExportRegion = NULL; 00964 ExportMsgID = _R(IDT_EXPORTMSG_AI); 00965 00966 AdjustOrigin = TRUE; 00967 SupportsLayers = TRUE; 00968 00969 // The offsets into the file for the Preview thing 00970 EPSStart = 0; 00971 EPSEnd = 0; 00972 PreviewStart = 0; 00973 PreviewEnd = 0; 00974 00975 TextComment[0] = 0; 00976 TextComment[1] = 0; 00977 TextComment[2] = 1; 00978 00979 // set the font extras block vars. These indicate to the 00980 // filter to do something special with the next set of font attributes 00981 FontFlags.Bold = FALSE; 00982 FontFlags.Italic = FALSE; 00983 00984 // Set the font type to assume we are loading true type fonts unless 00985 // told otherwise. 00986 ClassOfFont = FC_TRUETYPE; 00987 00988 // Define the mould threshold default value. 00989 NewMouldThreshold = MOULD_V1THRESHOLD; 00990 00991 // We're not in a group at first. 00992 EPS_Group = FALSE; 00993 00994 // Clear the length of the file to the end of the EPS code. 00995 EndOfEPS = 0; 00996 00997 // Set up the comment list. These are the known DSC comments, and how to handle them. 00998 EPSComments.Add ( _T("%%BeginProlog"), _T("%%EndProlog"), TRUE, 0 ); 00999 EPSComments.Add ( _T("%%BeginSetup"), _T("%%EndSetup"), TRUE, 0 ); 01000 EPSComments.Add ( _T("%%BeginDocument"), _T("%%EndDocument"), FALSE, 0 ); 01001 EPSComments.Add ( _T("%%BeginPageSetup"), _T("%%EndPageSetup"), FALSE, 0 ); 01002 EPSComments.Add ( _T("%%BeginDefaults"), _T("%%EndDefaults"), FALSE, 0 ); 01003 EPSComments.Add ( _T("%%BeginEmulation"), _T("%%EndEmulation"), FALSE, 0 ); 01004 EPSComments.Add ( _T("%%BeginPreview"), _T("%%EndPreview"), FALSE, 0 ); 01005 EPSComments.Add ( _T("%%BeginFeature"), _T("%%EndFeature"), FALSE, 0 ); 01006 EPSComments.Add ( _T("%%BeginFile"), _T("%%EndFile"), FALSE, 0 ); 01007 EPSComments.Add ( _T("%%BeginFont"), _T("%%EndFont"), FALSE, 0 ); 01008 EPSComments.Add ( _T("%%BeginProcSet"), _T("%%EndProcSet"), FALSE, 0 ); 01009 EPSComments.Add ( _T("%%BeginResource"), _T("%%EndResource"), FALSE, 0 ); 01010 EPSComments.Add ( _T("%%BeginCustomColor"), _T("%%EndCustomColor"), FALSE, 0 ); 01011 EPSComments.Add ( _T("%%BeginProcessColor"), _T("%%EndProcessColor"), FALSE, 0 ); 01012 } 01013 01014 /******************************************************************************************** 01015 01016 > virtual BOOL EPSFilter::Init() 01017 01018 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 01019 Created: 28/10/93 01020 Returns: FALSE => don't use this class for real filters! 01021 Purpose: Initialise an EPSFilter object. This is a base class and so should 01022 never actually be initialised so this function will always return FALSE, 01023 and also ENSURE in debug builds. 01024 01025 ********************************************************************************************/ 01026 01027 BOOL EPSFilter::Init() 01028 { 01029 // This class is now used only as basis for deriving EPS filters - it should not 01030 // actually be used as a real filter. 01031 ENSURE(FALSE, "Base EPSFilter class called! Do not use this!"); 01032 return FALSE; 01033 } 01034 01035 /******************************************************************************************** 01036 01037 > BOOL EPSFilter::InitPrefs() 01038 01039 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 01040 Created: 06/01/95 01041 Purpose: Initialise preferences for EPS formats. This is used by the Camelot 01042 EPS export filter, and includes font mappings, DPI, PostScript language 01043 level control, and exporting text as curves. 01044 01045 ********************************************************************************************/ 01046 01047 BOOL EPSFilter::InitPrefs() 01048 { 01049 #ifndef STANDALONE 01050 01051 // Register preferences for EPS output. 01052 Camelot.DeclareSection(_T("EPS"), 5); 01053 Camelot.DeclarePref(NULL, _T("ExportPSType"), &XSEPSExportPSType, 0, 2); 01054 Camelot.DeclarePref(NULL, _T("ExportDPI"), &XSEPSExportDPI, 10, 600); 01055 Camelot.DeclarePref(NULL, _T("ExportTextAsCurves"), &XSEPSExportTextAsCurves); 01056 01057 // Register preferences for font mappings from TrueType to PostScript names. 01058 // This is used by Camelot EPS (or any other filter or class that wants to use it). 01059 Camelot.DeclareSection( _T("EPSFontMapping"), 50); 01060 01061 static const TCHAR FontMappings[][2][30] = 01062 { 01063 // Standard PostScript font mappings 01064 01065 // 01066 // TrueType name => PostScript name 01067 // 01068 { _T("Times-New-Roman"), _T("Times-Roman") }, 01069 { _T("Times-New-Roman-Bold"), _T("Times-Bold") }, 01070 { _T("Times-New-Roman-Italic"), _T("Times-Italic") }, 01071 { _T("Times-New-Roman-BoldItalic"), _T("Times-BoldItalic") }, 01072 { _T("Arial"), _T("Helvetica") }, 01073 { _T("Arial-Bold"), _T("Helvetica-Bold") }, 01074 { _T("Arial-Italic"), _T("Helvetica-Oblique") }, 01075 { _T("Arial-BoldItalic"), _T("Helvetica-BoldOblique") }, 01076 { _T("Courier-New"), _T("Courier") }, 01077 { _T("Courier-New-Bold"), _T("Courier-Bold") }, 01078 { _T("Courier-New-Italic"), _T("Courier-Oblique") }, 01079 { _T("Courier-New-BoldItalic"), _T("Courier-BoldOblique") }, 01080 { _T("Michael"), _T("Palatino-Roman") }, 01081 { _T("Michael-Bold"), _T("Palatino-Bold") }, 01082 { _T("Michael-Italic"), _T("Palatino-Italic") }, 01083 { _T("Michael-BoldItalic"), _T("Palatino-BoldItalic") }, 01084 { _T("NewSchbook"), _T("NewCenturySchlbk-Roman") }, 01085 { _T("NewSchbook-Bold"), _T("NewCenturySchlbk-Bold") }, 01086 { _T("NewSchbook-Italic"), _T("NewCenturySchlbk-Italic") }, 01087 { _T("NewSchbook-BoldItalic"), _T("NewCenturySchlbk-BoldItalic") }, 01088 { _T("ZapfDingbatsBT"), _T("ZapfDingbats") }, 01089 { _T("Symbol"), _T("Symbol") }, 01090 01091 #if 0 01092 // Currently we have no TrueType equivalents for these fonts. 01093 { _T(""), _T("AvantGarde-Book") }, 01094 { _T(""), _T("AvantGarde-Demi") }, 01095 { _T(""), _T("AvantGarde-BookOblique") }, 01096 { _T(""), _T("AvantGarde-DemiOblique") }, 01097 { _T(""), _T("Bookman-Light") }, 01098 { _T(""), _T("Bookman-Demi") }, 01099 { _T(""), _T("Bookman-LightItalic") }, 01100 { _T(""), _T("Bookman-DemiItalic") }, 01101 { _T(""), _T("ZapfChancery-MediumItalic") }, 01102 #endif 01103 01104 // Terminator 01105 { _T(""), _T("") } 01106 }; 01107 01108 // Loop to declare all of these font mappings... 01109 INT32 i = 0; 01110 while (camStrclen(FontMappings[i][0]) > 0) 01111 { 01112 Camelot.SetPrefDirect( _T("EPSFontMapping"), 01113 (TCHAR *) &FontMappings[i][0][0], 01114 &FontMappings[i][1][0]); 01115 i++; 01116 } 01117 01118 #endif 01119 01120 // All ok 01121 return TRUE; 01122 } 01123 01124 // The size of the buffer used to hold tokens 01125 const INT32 TokenBufSize = 256; 01126 01127 /******************************************************************************************** 01128 01129 > BOOL EPSFilter::PrepareToImport() 01130 01131 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 01132 Created: 22/02/94 01133 Returns: TRUE if succeeded, FALSE if not (e.g. no memory for EPS stack) 01134 Purpose: Prepare to import EPS data using this filter. This sets up the filter 01135 to a sensible state for reading. 01136 Errors: Out of memory. 01137 SeeAlso: EPSFilter::DoImport; EPSFilter::CleanUpAfterImport 01138 Scope: Private 01139 01140 ********************************************************************************************/ 01141 01142 BOOL EPSFilter::PrepareToImport() 01143 { 01144 if (!SetUpCurrentAttrs()) 01145 return FALSE; 01146 01147 // Start the selection operation. 01148 if (!ImportInfo.pOp->DoStartSelOp(FALSE)) 01149 return FALSE; 01150 01151 // Error if no file object. 01152 if (EPSFile == NULL) 01153 return FALSE; 01154 01155 // Get ready to parse EPS tokens. 01156 EPSFile->InitLexer(); 01157 EPSFile->SetDelimiters("()<>[]{}/%"); 01158 EPSFile->SetCommentMarker('%'); 01159 EPSFile->SetStringDelimiters("()"); 01160 01161 TokenBuf = EPSFile->GetTokenBuf(); 01162 Token = EPSC_Invalid; 01163 01164 EPSFlags.ComplexPath = 0;//FALSE; 01165 EPSFlags.StrokeComplexPath = FALSE; 01166 EPSFlags.NoAttributes = FALSE; 01167 EPSFlags.EPSErrorEncountered = FALSE; 01168 EPSFlags.AddToNewLayer = FALSE; 01169 EPSFlags.PathIsHidden = FALSE; 01170 01171 ThePathType = PATH_NORMAL; 01172 01173 01174 // Decide whether we need to use layers or not 01175 // Neville 7/8/97 - Layers are bad in Webster as they conflict with frames 01176 // Now the same is true in Camelot 01177 #ifndef WEBSTER 01178