00001 // $Id: ai_epsrr.cpp 1336 2006-06-17 16:18:41Z alex $ 00002 // Implementation of Adobe Illustrator EPS filter. 00003 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE 00004 ================================XARAHEADERSTART=========================== 00005 00006 Xara LX, a vector drawing and manipulation program. 00007 Copyright (C) 1993-2006 Xara Group Ltd. 00008 Copyright on certain contributions may be held in joint with their 00009 respective authors. See AUTHORS file for details. 00010 00011 LICENSE TO USE AND MODIFY SOFTWARE 00012 ---------------------------------- 00013 00014 This file is part of Xara LX. 00015 00016 Xara LX is free software; you can redistribute it and/or modify it 00017 under the terms of the GNU General Public License version 2 as published 00018 by the Free Software Foundation. 00019 00020 Xara LX and its component source files are distributed in the hope 00021 that it will be useful, but WITHOUT ANY WARRANTY; without even the 00022 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00023 See the GNU General Public License for more details. 00024 00025 You should have received a copy of the GNU General Public License along 00026 with Xara LX (see the file GPL in the root directory of the 00027 distribution); if not, write to the Free Software Foundation, Inc., 51 00028 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00029 00030 00031 ADDITIONAL RIGHTS 00032 ----------------- 00033 00034 Conditional upon your continuing compliance with the GNU General Public 00035 License described above, Xara Group Ltd grants to you certain additional 00036 rights. 00037 00038 The additional rights are to use, modify, and distribute the software 00039 together with the wxWidgets library, the wxXtra library, and the "CDraw" 00040 library and any other such library that any version of Xara LX relased 00041 by Xara Group Ltd requires in order to compile and execute, including 00042 the static linking of that library to XaraLX. In the case of the 00043 "CDraw" library, you may satisfy obligation under the GNU General Public 00044 License to provide source code by providing a binary copy of the library 00045 concerned and a copy of the license accompanying it. 00046 00047 Nothing in this section restricts any of the rights you have under 00048 the GNU General Public License. 00049 00050 00051 SCOPE OF LICENSE 00052 ---------------- 00053 00054 This license applies to this program (XaraLX) and its constituent source 00055 files only, and does not necessarily apply to other Xara products which may 00056 in part share the same code base, and are subject to their own licensing 00057 terms. 00058 00059 This license does not apply to files in the wxXtra directory, which 00060 are built into a separate library, and are subject to the wxWindows 00061 license contained within that directory in the file "WXXTRA-LICENSE". 00062 00063 This license does not apply to the binary libraries (if any) within 00064 the "libs" directory, which are subject to a separate license contained 00065 within that directory in the file "LIBS-LICENSE". 00066 00067 00068 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS 00069 ---------------------------------------------- 00070 00071 Subject to the terms of the GNU Public License (see above), you are 00072 free to do whatever you like with your modifications. However, you may 00073 (at your option) wish contribute them to Xara's source tree. You can 00074 find details of how to do this at: 00075 http://www.xaraxtreme.org/developers/ 00076 00077 Prior to contributing your modifications, you will need to complete our 00078 contributor agreement. This can be found at: 00079 http://www.xaraxtreme.org/developers/contribute/ 00080 00081 Please note that Xara will not accept modifications which modify any of 00082 the text between the start and end of this header (marked 00083 XARAHEADERSTART and XARAHEADEREND). 00084 00085 00086 MARKS 00087 ----- 00088 00089 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara 00090 designs are registered or unregistered trademarks, design-marks, and/or 00091 service marks of Xara Group Ltd. All rights in these marks are reserved. 00092 00093 00094 Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. 00095 http://www.xara.com/ 00096 00097 =================================XARAHEADEREND============================ 00098 */ 00099 00100 #include "camtypes.h" 00101 00102 #include "ai_epsrr.h" 00103 00104 #include <stdio.h> 00105 #include <math.h> 00106 00107 #include "vectrndr.h" 00108 #include "ccdc.h" 00109 //#include "colmodel.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00110 //#include "fillattr.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00111 #include "opbevel.h" 00112 #include "swfexpdc.h" 00113 #include "swfrndr.h" 00114 #include "slicehelper.h" 00115 #include "fillramp.h" 00116 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00117 #include "nodebmp.h" 00118 //#include "bitmap.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00119 //#include "range.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00120 //#include "rendsel.h" 00121 //#include "dibutil.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00122 #include "fontman.h" // for FontManager - for writing font changes to overflow text 00123 #include "colplate.h" // for ColourPlate - in overflow text functions 00124 #include "colourix.h" // for Indexed Colour - for writing colour changes to overflow 00125 #include "nodebev.h" 00126 #include "layer.h" 00127 #include "clipattr.h" 00128 00129 CC_IMPLEMENT_DYNAMIC(AIEPSRenderRegion, EPSRenderRegion) 00130 00131 /******************************************************************************************** 00132 00133 > AIEPSRenderRegion::AIEPSRenderRegion ( DocRect ClipRect, 00134 Matrix ConvertMatrix, 00135 FIXED16 ViewScale ) 00136 00137 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 00138 Created: 29/3/00 00139 Purpose: Create and initialise a render region for exporting AI EPS. Sets up the 00140 string to put in the %%Creator comment. 00141 SeeAlso: EPSRenderRegion::EPSRenderRegion () 00142 00143 ********************************************************************************************/ 00144 00145 AIEPSRenderRegion::AIEPSRenderRegion ( DocRect ClipRect, 00146 Matrix ConvertMatrix, 00147 FIXED16 ViewScale ) 00148 : EPSRenderRegion ( ClipRect, ConvertMatrix, ViewScale ) 00149 { 00150 // Set up member variables. 00151 m_a = 1; 00152 m_b = 0; 00153 m_c = 0; 00154 m_d = 1; 00155 m_T = DocCoord ( 0, 0 ); 00156 m_ActiveLayer = FALSE; 00157 m_LayerColour = 0; 00158 00159 m_fpOverflowText = NULL; 00160 00161 m_bInTextGap = FALSE; 00162 m_bTextAsShapes = FALSE; 00163 00164 m_pLinearGradList = NULL; 00165 m_pRadialGradList = NULL; 00166 00167 // Initialise the creator string to show that it's an AI file. 00168 CreatorString = _T("Adobe Illustrator(TM) 7.0 by Xara."); 00169 } 00170 00171 /******************************************************************************************** 00172 00173 > AIEPSRenderRegion::~AIEPSRenderRegion 00174 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 00175 Created: 30/3/2001 00176 Purpose: Destructor for an AI render region. All this really does is dispose of the 00177 gradient fill cache (if there is one) 00178 SeeAlso: EPSRenderRegion::EPSRenderRegion () 00179 00180 ********************************************************************************************/ 00181 AIEPSRenderRegion::~AIEPSRenderRegion () 00182 { 00183 ClearGradientCache (); 00184 } 00185 00186 /******************************************************************************************** 00187 00188 > BOOL AIEPSRenderRegion::ExportBitmap ( NodeBitmap *pNodeBMP ) 00189 00190 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 00191 Created: 31/3/00 00192 Inputs: pNodeBMP - A pointer to the NodeBitmap being exported. 00193 Returns: TRUE - If successful. 00194 FALSE - If an error is encountered. 00195 Purpose: Kicks off the NodeBitmap export process.. 00196 SeeAlso: NodeBitmap::ExportRender () 00197 00198 ********************************************************************************************/ 00199 00200 BOOL AIEPSRenderRegion::ExportBitmap ( NodeBitmap *pNodeBMP ) 00201 { 00202 // Set up the local variables. 00203 KernelBitmap *pBitmap = pNodeBMP->GetBitmap (); 00204 00205 // Set up the bitmap's transformation matrix. 00206 LoadBitmapMatrix ( pNodeBMP ); 00207 00208 // Write out the bitmap record. 00209 WriteBitmapRecord ( pBitmap->GetActualBitmap () ); 00210 00211 return TRUE; 00212 } 00213 00214 /******************************************************************************************** 00215 00216 > BOOL AIEPSRenderRegion::ExportBevel ( NodeBevel *pBevel ) 00217 00218 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 00219 Created: 6/4/00 00220 Inputs: pBevel - A pointer to a bevel node. 00221 Returns: TRUE - Success. 00222 FALSE - An error occured. 00223 Purpose: Renders a bevel into a DIB, and exports this as a bitmap to the AI file. 00224 SeeAlso: NodeBevel::ExportRender 00225 00226 ********************************************************************************************/ 00227 00228 BOOL AIEPSRenderRegion::ExportBevel ( NodeBevel *pBevel ) 00229 { 00230 // Set up the local variables. 00231 KernelDC *pDC = static_cast<KernelDC *> ( CCDC::ConvertFromNativeDC(RenderDC) ); 00232 RangeControl ControlFlags ( TRUE, TRUE ); 00233 Range ToRender ( pBevel, pBevel, ControlFlags ); 00234 KernelBitmap *pBitmap = NULL; 00235 Path *pSourcePath = &( pBevel->InkPath ); 00236 DocRect Bounds = pBevel->GetBoundingRect (); 00237 DocCoord Position ( Bounds.lo.x, Bounds.hi.y ); 00238 double Width = static_cast<double> ( Bounds.Width () ); 00239 double Height = static_cast<double> ( Bounds.Height () ); 00240 00241 // Create and render the bitmap. 00242 pBitmap = pBevel->CreateBitmapCopy(-1.0,FALSE); 00243 00244 if(!pBitmap) 00245 return FALSE; 00246 00247 // Get the width and height of the bitmap. 00248 double BMPWidth = static_cast<double> ( pBitmap->GetWidth () ); 00249 double BMPHeight = static_cast<double> ( pBitmap->GetHeight () ); 00250 00251 // Write the path. (ChrisG 16/01/01) If we have one. 00252 if (pSourcePath->GetNumCoords () != 0) 00253 { 00254 WriteMask ( pSourcePath, TRUE ); 00255 } 00256 00257 // Set up the bitmap translation matrix. 00258 LoadTranslationMatrix ( Position ); 00259 00260 // Scale width and height to be valid value for AI co-ordinates. 00261 Width /= 1000; 00262 Height /= 1000; 00263 00264 // And calcuate the scale values for placing the bitmap. 00265 m_a = Width / BMPWidth; 00266 m_d = Height / BMPHeight; 00267 00268 // Write the bitmap record. 00269 WriteBitmapRecord ( pBitmap->ActualBitmap ); 00270 00271 // Write the end of mask operator. (ChrisG 16/01/01) If we've written a mask. 00272 if (pSourcePath->GetNumCoords () != 0) 00273 { 00274 pDC->OutputToken ( _T("Q") ); 00275 pDC->OutputNewLine (); 00276 } 00277 00278 if(pBitmap) 00279 { 00280 pBitmap->DestroyGreyscaleVersion(); 00281 delete pBitmap; 00282 } 00283 00284 // Success! 00285 return TRUE; 00286 } 00287 00288 /******************************************************************************************** 00289 00290 > BOOL AIEPSRenderRegion::ExportShadow ( OILBitmap *pBitmap, 00291 UINT32 Darkness, 00292 DocRect &Bounds ) 00293 00294 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 00295 Created: 11/4/00 00296 Inputs: pShadow - A pointer to a shadow node. 00297 Returns: TRUE - Success. 00298 FALSE - An error occured. 00299 Purpose: Renders a shadow into a DIB, and exports this as a bitmap to the AI file. 00300 SeeAlso: NodeBevel::ExportRender 00301 00302 ********************************************************************************************/ 00303 00304 BOOL AIEPSRenderRegion::ExportShadow ( OILBitmap *pBitmap, 00305 UINT32 Darkness, 00306 DocRect &Bounds ) 00307 { 00308 // Set up the local variables. 00309 // KernelDC *pDC = (KernelDC*)CCDC::ConvertFromNativeDC(RenderDC); 00310 DocCoord Position ( Bounds.lo.x, Bounds.hi.y ); 00311 double Width = static_cast<double> ( Bounds.Width () ) / 1000; 00312 double Height = static_cast<double> ( Bounds.Height () ) / 1000; 00313 double BMPWidth = static_cast<double> ( pBitmap->GetWidth () ); 00314 double BMPHeight = static_cast<double> ( pBitmap->GetHeight () ); 00315 DocColour ShadowColour = *( static_cast<FillGeometryAttribute*> 00316 ( GetCurrentAttribute ( ATTR_FILLGEOMETRY ) ) 00317 ->GetStartColour () ); 00318 DocColour BlendedShadow = AlphaBlend ( ShadowColour, mBackgroundColour, Darkness ); 00319 00320 // And use the shadow colour to build a contone bitmap palette. 00321 pBitmap->BuildContonePalette ( BlendedShadow, mBackgroundColour, EFFECT_RGB, 00322 RenderView ); 00323 00324 // Set up the bitmap translation matrix. 00325 LoadTranslationMatrix ( Position ); 00326 00327 // And calcuate the scale values for placing the bitmap. 00328 m_a = Width / BMPWidth; 00329 m_d = Height / BMPHeight; 00330 00331 // Write out the bitmap header. 00332 WriteBitmapHeader ( (INT32)BMPWidth, (INT32)BMPHeight ); 00333 00334 // Export the bitmap. 00335 WriteContoneBody ( pBitmap ); 00336 00337 // Finish off the bitmap record. 00338 WriteBitmapTail (); 00339 00340 return TRUE; 00341 } 00342 00343 /******************************************************************************************** 00344 00345 > BOOL AIEPSRenderRegion::ExportLayer ( Layer *pLayer ) 00346 00347 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 00348 Created: 11/4/00 00349 Inputs: pLayer - A pointer to a layer object. 00350 Returns: TRUE - Success. 00351 FALSE - An error occured. 00352 Purpose: If there is an existing layer, it writes the end of layer tags, before 00353 creating a new layer record. 00354 SeeAlso: AIEPSRenderRegion::EndLayer () 00355 00356 ********************************************************************************************/ 00357 00358 BOOL AIEPSRenderRegion::ExportLayer ( Layer *pLayer ) 00359 { 00360 // Tidy up the existing layer, if it exists. 00361 EndLayer (); 00362 00363 // And write out the next layer. 00364 return StartLayer ( static_cast<Layer*> ( pLayer->FindNext 00365 ( CC_RUNTIME_CLASS ( Layer ) ) ) ); 00366 } 00367 00368 /******************************************************************************************** 00369 00370 > BOOL AIEPSRenderRegion::StartLayer ( Layer *pLayer ) 00371 00372 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 00373 Created: 11/4/00 00374 Inputs: pLayer - A pointer to a layer object. 00375 Returns: TRUE - Success. 00376 FALSE - An error occured. 00377 Purpose: Writes a layer record to the file. 00378 SeeAlso: AIEPSRenderRegion::EndLayer () 00379 00380 ********************************************************************************************/ 00381 00382 BOOL AIEPSRenderRegion::StartLayer ( Layer *pLayer ) 00383 { 00384 // Catch null pointers to layers. 00385 if ( pLayer != NULL ) 00386 { 00387 KernelDC *pDC = static_cast<KernelDC *> ( CCDC::ConvertFromNativeDC(RenderDC) ); 00388 TCHAR LayerName [258]; 00389 00390 // Set up the layer's name. 00391 camSprintf ( LayerName, _T("(%s)"), ( TCHAR* ) pLayer->GetLayerID () ); 00392 00393 // Start a layer definition. 00394 pDC->OutputToken ( _T("%AI5_BeginLayer") ); 00395 pDC->OutputNewLine (); 00396 00397 // Set the layer's properties. 00398 pDC->OutputValue ( ( UINT32 ) pLayer->IsVisible () ); // Is the layer visible? 00399 pDC->OutputValue ( ( UINT32 ) 1 ); // Is the layer previewed? 00400 pDC->OutputValue ( ( UINT32 ) !pLayer->IsLocked () ); // Is the layer enabled? 00401 pDC->OutputValue ( ( UINT32 ) pLayer->IsPrintable () );//Is the layer printable? 00402 pDC->OutputValue ( ( UINT32 ) 0 ); // Is the layer dimmed? 00403 pDC->OutputValue ( ( UINT32 ) 0 ); // No multilayer masks. 00404 00405 // The ID colour. 00406 pDC->OutputValue ( ( UINT32 ) m_LayerColour % 27 ); // Set the layer's ID colour. 00407 m_LayerColour ++; // Increment colour ID. 00408 00409 // Colour values - I don't know what they're used for. 00410 pDC->OutputValue ( ( UINT32 ) 0 ); // Red intensity. 00411 pDC->OutputValue ( ( UINT32 ) 0 ); // Blue intensity. 00412 pDC->OutputValue ( ( UINT32 ) 0 ); // Green intensity. 00413 00414 // Write out the Lb tag. 00415 pDC->OutputToken ( _T("Lb") ); 00416 pDC->OutputNewLine (); 00417 00418 // Set the layer's name. 00419 pDC->OutputToken ( LayerName ); 00420 pDC->OutputToken ( _T("Ln") ); 00421 pDC->OutputNewLine (); 00422 00423 // Tell Camelot that there is an active layer. 00424 m_ActiveLayer = TRUE; 00425 } 00426 00427 // Success! 00428 return TRUE; 00429 } 00430 00431 /******************************************************************************************** 00432 00433 > void AIEPSRenderRegion::RenderChar (WCHAR ch, Matrix * pMatrix) 00434 00435 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 00436 Created: 1/11/00 00437 Purpose: Overrides the default behaviour for rendering a single character. Used to 00438 store additional information on text blocks needed for AI text. i.e. the 00439 overflow text block ((xxxxxxxxx) TX) which occurs after the unjustified 00440 ((x) Tx\n (x) Tx\n) block. Both of these are needed for correct Illustrator 00441 export of text. 00442 SeeAlso: EPSRenderRegion::RenderChar 00443 00444 ********************************************************************************************/ 00445 00446 BOOL AIEPSRenderRegion::RenderChar(WCHAR ch, Matrix* pMatrix) 00447 { 00448 TCHAR buf[20]; 00449 BOOL result = FALSE; // assume failure if nothing given. 00450 00451 if (m_bTextAsShapes) 00452 { 00453 result = RenderCharAsShape (ch, pMatrix); 00454 } 00455 else 00456 { 00457 // Output matrix (a b c d e f Tm\n) - a,b,c and d are in the range 1.0 to -1.0 00458 // Only do this for text on paths 00459 if (ExportingOnPath ()) 00460 { 00461 KernelDC *pDC = (KernelDC*)CCDC::ConvertFromNativeDC(RenderDC); 00462 00463 pDC->OutputMatrix(pMatrix); 00464 pDC->OutputToken(_T("Tm")); 00465 pDC->OutputNewLine(); 00466 } 00467 00468 // call the base class first, so that the attributes are exported BEFORE the character 00469 result = EPSRenderRegion::RenderChar (ch, pMatrix);; 00470 00471 // store any extra information, closing an attribute gap if one is open. 00472 if (ExportingOnPath ()) 00473 { 00474 OverflowTextFinishGap (); 00475 camSprintf (buf,_T("%c"),ch); 00476 OverflowTextWrite (buf); 00477 } 00478 } 00479 // Call the base class' function to do the standard export. 00480 return result; 00481 } 00482 00483 00484 /******************************************************************************************** 00485 00486 > void AIEPSRenderRegion::RenderCharAsShape (WCHAR ch, Matrix * pMatrix) 00487 00488 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 00489 Created: 1/11/00 00490 Purpose: Allows text to be drawn as shapes, not characters, so that AI can cope 00491 with gradient filled text. 00492 SeeAlso: AIEPSRenderRegion::RenderChar, EPSRenderRegion::RenderChar 00493 00494 ********************************************************************************************/ 00495 00496 BOOL AIEPSRenderRegion::RenderCharAsShape (WCHAR ch, Matrix* pMatrix) 00497 { 00498 BOOL result = FALSE; 00499 00500 // create the char's path 00501 Path* pCharPath=CreateCharPath(ch,pMatrix); 00502 00503 // if the path got created correctly, then we done good... 00504 if (pCharPath!=NULL) 00505 { 00506 // if at least one point, draw path using current attibutes in render region 00507 if (pCharPath->GetNumCoords()!=0) 00508 DrawPath(pCharPath); 00509 00510 // clean up 00511 delete pCharPath; 00512 00513 result = TRUE; 00514 } 00515 00516 return result; 00517 } 00518 00519 /******************************************************************************************** 00520 00521 > void AIEPSRenderRegion::Initialise() 00522 00523 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 00524 Created: 29/3/00 00525 Purpose: Sets up render region - it outputs the AIEPS file header comments, and 00526 intialises the rendering attributes. 00527 SeeAlso: EPSRenderRegion::Initialise, EPSRenderRegion::InitAttributes 00528 00529 ********************************************************************************************/ 00530 00531 void AIEPSRenderRegion::Initialise() 00532 { 00533 // Set up member variables. 00534 m_a = 1; 00535 m_b = 0; 00536 m_c = 0; 00537 m_d = 1; 00538 m_T = DocCoord ( 0, 0 ); 00539 m_ActiveLayer = FALSE; 00540 m_LayerColour = 0; 00541 00542 ClearGradientCache (); 00543 00544 // Call the EPSRenderRegion method to re-enter the export loop. 00545 EPSRenderRegion::InitAttributes (); 00546 } 00547 00548 /******************************************************************************************** 00549 00550 > BOOL AIEPSRenderRegion::WriteEPSVersion ( void ) 00551 00552 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 00553 Created: 28/3/000 00554 Inputs: pDC - The device context to output to. 00555 Returns: TRUE if ok; 00556 FALSE if error (e.g. file/disk error or printer driver error) 00557 Purpose: Writes the relevant EPS version declaration. 00558 SeeAlso: EPSRenderRegion::WriteEPSVersion 00559 00560 ********************************************************************************************/ 00561 00562 BOOL AIEPSRenderRegion::WriteEPSVersion ( void ) 00563 { 00564 // Cast the pointer to an appropriate DC. 00565 KernelDC *pDC = static_cast<KernelDC *> ( CCDC::ConvertFromNativeDC(RenderDC) ); 00566 00567 // Output the special AIEPS header start token. 00568 pDC->OutputToken ( _T("%!PS-Adobe-3.0") ); 00569 pDC->OutputNewLine (); 00570 00571 return TRUE; 00572 } 00573 00574 /******************************************************************************************** 00575 00576 > BOOL AIEPSRenderRegion::WriteEPSProcessColours ( void ) 00577 00578 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 00579 Created: 28/3/000 00580 Inputs: pDC - The device context to output to. 00581 Returns: TRUE if ok; 00582 FALSE if error (e.g. file/disk error or printer driver error) 00583 Purpose: Writes the colour type used to disk. 00584 SeeAlso: EPSRenderRegion::WriteEPSProcessColours 00585 00586 ********************************************************************************************/ 00587 00588 BOOL AIEPSRenderRegion::WriteEPSProcessColours ( void ) 00589 { 00590 // Cast a pointer to the appropriate DC. 00591 KernelDC *pDC = (KernelDC*)CCDC::ConvertFromNativeDC(RenderDC); 00592 00593 // Output the process colours 00594 pDC->OutputToken ( _T("%%DocumentProcessColors: Cyan Magenta Yellow Black") ); 00595 pDC->OutputNewLine (); 00596 00597 return TRUE; 00598 } 00599 00600 /******************************************************************************************** 00601 00602 > BOOL AIEPSRenderRegion::WriteEPSResources ( EPSFilter *pFilter, 00603 Document *pDocument ) 00604 00605 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 00606 Created: 28/3/00 00607 Inputs: pDC - The device context to output to. 00608 Returns: TRUE if ok; 00609 FALSE if error (e.g. file/disk error or printer driver error) 00610 Purpose: This function writes out the resource inclusion string required for the AI 00611 file. 00612 SeeAlso: EPSRenderRegion::WriteSetup 00613 00614 ********************************************************************************************/ 00615 00616 BOOL AIEPSRenderRegion::WriteEPSResources ( EPSFilter *pFilter, 00617 Document *pDocument ) 00618 { 00619 // Cast a pointer to the appropriate DC. 00620 KernelDC *pDC = (KernelDC*)CCDC::ConvertFromNativeDC(RenderDC); 00621 00622 // Call the export method in the document. 00623 pDocument->WriteEPSResources ( pFilter ); 00624 00625 // Add a few things necessary for the AI file format. 00626 pDC->OutputToken ( _T("%AI3_ColorUsage: Color") ); 00627 pDC->OutputNewLine (); 00628 pDC->OutputToken ( _T("%AI5_FileFormat 2.0") ); 00629 pDC->OutputNewLine (); 00630 00631 // All done. 00632 return TRUE; 00633 } 00634 00635 /******************************************************************************************** 00636 00637 > BOOL AIEPSRenderRegion::WriteEPSProlog ( EPSFilter *pFilter, 00638 Document *pDocument ) 00639 00640 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 00641 Created: 28/3/00 00642 Inputs: pDC - The device context to output to. 00643 Returns: TRUE if ok; 00644 FALSE if error (e.g. file/disk error or printer driver error) 00645 Purpose: This method writes out the initialisation code for the included resources. 00646 SeeAlso: EPSRenderRegion::WriteSetup 00647 00648 ********************************************************************************************/ 00649 00650 BOOL AIEPSRenderRegion::WriteEPSProlog ( EPSFilter *pFilter, 00651 Document *pDocument ) 00652 { 00653 // Call the export method in the document. 00654 pDocument->WriteEPSProlog ( pFilter ); 00655 00656 // All done. 00657 return TRUE; 00658 } 00659 00660 /******************************************************************************************** 00661 00662 > virtual BOOL AIEPSRenderRegion::WriteGradientFills ( Document *pDocument ) 00663 00664 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 00665 Created: 1/3/00 00666 Inputs: pDocument - The document to be written. 00667 Outputs: - 00668 Returns: TRUE if successful. 00669 FALSE if error (e.g. file/disk error) 00670 Purpose: Parses through the tree, identifies any gradient fills, and writes them to 00671 the export DC's file. 00672 00673 ********************************************************************************************/ 00674 00675 BOOL AIEPSRenderRegion::WriteGradientFills ( Document *pDocument ) 00676 { 00677 // Get the spread from the document. 00678 Spread *pSpread = pDocument->FindFirstSpread (); 00679 00680 // Build the gradient cache up from all the fills under the spread, after cleaning any 00681 // junk out of it (there shouldn't be any there, but that ain't the point) 00682 ClearGradientCache (); 00683 BuildGradientCache (pSpread); 00684 00685 // Write out the number of fills and their definition. 00686 WriteGradientCount (); 00687 WriteGradientDefinitions (); 00688 00689 // The fill has been successfully saved, so return TRUE. 00690 return TRUE; 00691 } 00692 00693 /******************************************************************************************** 00694 00695 > BOOL AIEPSRenderRegion::WriteLinearFill ( FillGeometryAttribute *pFill, INT32 id ) 00696 00697 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 00698 Created: 1/3/00 00699 Inputs: pFill - A pointer to the fill attribute record. 00700 id - the id number for the fill 00701 Returns: TRUE - If successful. 00702 FALSE - The was an error (e.g. file/disk error). 00703 Purpose: Writes a linear fill to the disk file. 00704 00705 ********************************************************************************************/ 00706 00707 BOOL AIEPSRenderRegion::WriteLinearFill ( FillGeometryAttribute * pFill, EFFECTTYPE effect, INT32 id ) 00708 { 00709 // Extract the fill attribute - this is necessary for processing the fill type. 00710 KernelDC *pDC = static_cast<KernelDC *> ( CCDC::ConvertFromNativeDC(RenderDC) ); 00711 INT32 Colours = 2; 00712 TCHAR GradientName [32]; 00713 DocColour StartColour = *( pFill->GetStartColour () ); 00714 DocColour EndColour; 00715 ColourRamp *pRamp = pFill->GetColourRamp (); 00716 00717 // The fill is, or can be approximated by, a linear fill. 00718 camSprintf ( GradientName, _T("(%s %d)"), LinearGradient, id ); 00719 00720 // (ChrisG 16/01/01) Four colour fill MUST come first, as it's derived from Three 00721 // colour fill, and returns valid for IsThreeColFill(). 00722 if ( pFill->IsAFourColFill () ) 00723 { 00724 // I'm going to use a version of the below here, but for now I'll just 00725 // set up the end colour as the most distant end colour. 00726 EndColour = *( pFill->GetEndColour3 () ); 00727 } 00728 else if ( pFill->IsAThreeColFill () ) 00729 { 00730 // AI doesn't support three colour fills, so I'm going to fake it. This 00731 // code merges the two end colours to approximate the fill with a two 00732 // colour linear fill. 00733 EndColour.Mix ( pFill->GetEndColour (), pFill->GetEndColour2(), 00734 0.5f, NULL, FALSE, NULL ); 00735 } 00736 else 00737 { 00738 // Set up the end colour value appropriately. 00739 EndColour = *( pFill->GetEndColour () ); 00740 } 00741 00742 // Count the number of colours. 00743 if ( pRamp != NULL ) 00744 { 00745 UINT32 First = 0; 00746 UINT32 Last = 0; 00747 00748 // Extract the indices from the colour ramp. 00749 pRamp->GetIndexRange ( &First, &Last ); 00750 00751 // And add their difference to the colour count. Note, you need to add one 00752 // to the result so that you don't register having no colours. There really 00753 // should be a count number of elements method in the ramp code, though. 00754 Colours += 1 + Last - First; 00755 } 00756 00757 // (ChrisG 15/01/01) If this is a four colour fill, since we will be adding a mid-colour 00758 // below, then we need to include it in the definition 00759 if (pFill->IsAFourColFill ()) 00760 { 00761 Colours ++; 00762 } 00763 00764 // (ChrisG 4/4/2001) Add in the extra colours given from the HSV fill effect emulation 00765 if (effect == EFFECT_HSV_SHORT || effect == EFFECT_HSV_LONG) 00766 { 00767 Colours += (Colours - 1) * NumFillEmulationSteps; 00768 } 00769 00770 // Write the gradient's header. 00771 pDC->OutputToken ( _T("%AI5_BeginGradient:") ); 00772 pDC->OutputToken ( GradientName ); 00773 pDC->OutputNewLine (); 00774 00775 // Then the type definition. 00776 pDC->OutputToken ( GradientName ); 00777 pDC->OutputValue ( static_cast<INT32> ( LinearFill ) ); 00778 pDC->OutputValue ( static_cast<INT32> ( Colours ) ); 00779 pDC->OutputToken ( _T("Bd") ); 00780 pDC->OutputNewLine (); 00781 pDC->OutputToken ( _T("[") ); 00782 pDC->OutputNewLine (); 00783 00784 // (ChrisG 3/4/2001) Get bias and convert to 0-100 range (from -1 to +1) 00785 // This will be used later on to offset the positions 00786 CProfileBiasGain profile = pFill->GetProfile (); 00787 INT32 bias = (INT32) ((1 - (double) profile.GetBias ()) * 50); 00788 00789 // Write out the last colour. 00790 WriteGradientEntry ( &EndColour, 100, 50 ); 00791 00792 // set up the last colour and position (for the fill effect emulation. 00793 DocColour * pLastColour = &EndColour; 00794 INT32 lastPos = 100; 00795 00796 // Mid colour for four colour fills - this needs to be stored longer so that it can be 00797 // re-used in the case of HSV fill effects. 00798 DocColour MidColour; 00799 00800 // If the fill is a four colour fill, add a mid-colour that's a blend of the 00801 // second and third colours. 00802 if ( pFill->IsAFourColFill () ) 00803 { 00804 00805 MidColour.Mix ( pFill->GetEndColour (), pFill->GetEndColour2 (), 00806 0.5f, NULL, FALSE, NULL ); 00807 00808 // Write out the extra fill steps, if there are any. 00809 if (effect != EFFECT_RGB) 00810 { 00811 WriteFillEffectSteps (pLastColour, lastPos, &MidColour, 50, bias, effect); 00812 pLastColour = &MidColour; 00813 } 00814 00815 // And set the value. 00816 WriteGradientEntry ( &MidColour, 50, bias); 00817 } 00818 00819 // Otherwise, process the colour ramp. 00820 else if ( pRamp != NULL ) 00821 { 00822 ColRampItem *pItem = pRamp->GetLastCol (); 00823 00824 // Write in the ramp's colour values. 00825 while ( pItem != NULL ) 00826 { 00827 // Get the position of the colour in the fill. 00828 INT32 Ratio = static_cast <INT32> ( 100 * pItem->GetPosition () ); 00829 DocColour *pCol = pItem->GetColourAddr (); 00830 00831 // Write out the extra fill steps, if there are any. 00832 if (effect != EFFECT_RGB) 00833 { 00834 WriteFillEffectSteps (pLastColour, lastPos, pCol, Ratio, bias, effect); 00835 pLastColour = pCol; 00836 lastPos = Ratio; 00837 } 00838 00839 // And set the value. 00840 WriteGradientEntry ( pCol, Ratio, 50 ); 00841 00842 // Increment the pointer onto the next item. 00843 pItem = pRamp->GetPrevCol ( pItem ); 00844 } 00845 } 00846 00847 // Write out the extra fill steps, if there are any. 00848 if (effect != EFFECT_RGB) 00849 { 00850 WriteFillEffectSteps (pLastColour, lastPos, &StartColour, 0, bias, effect); 00851 } 00852 00853 // Write out the start colour. 00854 WriteGradientEntry ( &StartColour, 0, bias ); 00855 00856 // Write out the end of gradient tokens. 00857 pDC->OutputToken ( _T("BD") ); 00858 pDC->OutputNewLine (); 00859 pDC->OutputToken ( _T("%AI5_EndGradient") ); 00860 pDC->OutputNewLine (); 00861 00862 // It worked! 00863 return TRUE; 00864 } 00865 00866 00867 /******************************************************************************************** 00868 00869 > BOOL AIEPSRenderRegion::WriteRadialFill ( AttrFillGeometry *pFill, INT32 id ) 00870 00871 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 00872 Created: 1/3/00 00873 Inputs: pFill - A pointer to the fill attribute record. 00874 id - The fill's id number 00875 Returns: TRUE - If successful. 00876 FALSE - The was an error (e.g. file/disk error). 00877 Purpose: Writes a Radial fill to the disk file. 00878 00879 ********************************************************************************************/ 00880 BOOL AIEPSRenderRegion::WriteRadialFill (FillGeometryAttribute * pFill, EFFECTTYPE effect, INT32 id) 00881 { 00882 // Extract the fill attribute - this is necessary for processing the fill type. 00883 KernelDC *pDC = static_cast<KernelDC *> ( CCDC::ConvertFromNativeDC(RenderDC) ); 00884 INT32 Colours = 2; 00885 TCHAR GradientName [32]; 00886 DocColour StartColour = *( pFill->GetStartColour () ); 00887 DocColour EndColour = *( pFill->GetEndColour () ); 00888 ColourRamp *pRamp = pFill->GetColourRamp (); 00889 00890 // The fill is, or can be approximated by, a Radial fill. 00891 camSprintf ( GradientName, _T("(%s %d)"), RadialGradient, id ); 00892 00893 // Count the number of colours. 00894 if ( pRamp != NULL ) 00895 { 00896 UINT32 First = 0; 00897 UINT32 Last = 0; 00898 00899 // Extract the indices from the colour ramp. 00900 pRamp->GetIndexRange ( &First, &Last ); 00901 00902 // And add their difference to the colour count. Note, you need to add one 00903 // to the result so that you don't register having no colours. There really 00904 // should be a count number of elements method in the ramp code, though. 00905 Colours += 1 + Last - First; 00906 00907 if (effect != EFFECT_RGB) 00908 { 00909 // Add in the extra steps for the fill effect (Five extra steps between each 00910 // pair of colours). 00911 Colours += (Colours - 1) * NumFillEmulationSteps; 00912 } 00913 } 00914 00915 // Write the gradient's header. 00916 pDC->OutputToken ( _T("%AI5_BeginGradient:") ); 00917 pDC->OutputToken ( GradientName ); 00918 pDC->OutputNewLine (); 00919 00920 // Then the type definition. 00921 pDC->OutputToken ( GradientName ); 00922 pDC->OutputValue ( static_cast<INT32> ( RadialFill ) ); 00923 pDC->OutputValue ( static_cast<INT32> ( Colours ) ); 00924 pDC->OutputToken ( _T("Bd") ); 00925 pDC->OutputNewLine (); 00926 pDC->OutputToken ( _T("[") ); 00927 pDC->OutputNewLine (); 00928 00929 // (ChrisG 3/4/2001) Get bias and convert to 0-100 range (from -1 to +1) 00930 CProfileBiasGain profile = pFill->GetProfile (); 00931 INT32 bias = (INT32) ((1 - (double) profile.GetBias ()) * 50); 00932 00933 // Write out the start colour. 00934 WriteGradientEntry ( &StartColour, 0, bias ); 00935 00936 DocColour * pLastCol = &StartColour; 00937 INT32 lastPos = 0; 00938 00939 // Process the colour ramp. 00940 if ( pRamp != NULL ) 00941 { 00942 ColRampItem *pItem = pRamp->GetFirstCol (); 00943 00944 // Write in the ramp's colour values. 00945 while ( pItem != NULL ) 00946 { 00947 // Get the position of the colour in the fill. 00948 INT32 Ratio = static_cast <INT32> ( 100 * pItem->GetPosition () ); 00949 DocColour *pCol = pItem->GetColourAddr (); 00950 00951 // Write out the intermediate fill steps (if there are any). 00952 if (effect != EFFECT_RGB) 00953 { 00954 WriteFillEffectSteps (pLastCol, lastPos, pCol, Ratio, bias, effect); 00955 pLastCol = pCol; 00956 lastPos = Ratio; 00957 } 00958 00959 // And set the value. 00960 WriteGradientEntry ( pCol, Ratio, 50 ); 00961 00962 // Increment the pointer onto the next item. 00963 pItem = pRamp->GetNextCol ( pItem ); 00964 } 00965 } 00966 00967 // Write out the intermediate fill steps (if there are any). 00968 if (effect != EFFECT_RGB) 00969 { 00970 WriteFillEffectSteps (pLastCol, lastPos, &EndColour, 100, bias, effect); 00971 } 00972 00973 // Write out the last colour. 00974 WriteGradientEntry ( &EndColour, 100, 50 ); 00975 00976 // Write out the end of gradient tokens. 00977 pDC->OutputToken ( _T("BD") ); 00978 pDC->OutputNewLine (); 00979 pDC->OutputToken ( _T("%AI5_EndGradient") ); 00980 pDC->OutputNewLine (); 00981 00982 // It worked! 00983 return TRUE; 00984 } 00985 00986 /******************************************************************************************** 00987 00988 > virtual BOOL AIEPSRenderRegion::WriteGradientEntry ( DocColour *pColour, 00989 INT32 Position, 00990 INT32 Midpoint ) 00991 00992 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 00993 Created: 24/3/00 00994 Inputs: pColour - A pointer to a Camelot colour. 00995 Position - The position of the colour within the fill. 00996 Midpoint - The midpoint of the fill. 00997 Returns: TRUE if successful. 00998 FALSE if error (e.g. file/disk error) 00999 Purpose: Writes a line into the definition of a gradient fill. 01000 01001 ********************************************************************************************/ 01002 BOOL AIEPSRenderRegion::WriteGradientEntry ( DocColour *pColour, 01003 INT32 Position, 01004 INT32 Midpoint ) 01005 { 01006 INT32 red; // 01007 INT32 green; // RGB colour values 01008 INT32 blue; // 01009 PColourCMYK CMYKColour; // The colour to be stored. 01010 01011 KernelDC *pDC = (KernelDC*)CCDC::ConvertFromNativeDC(RenderDC); 01012 TCHAR Line [80]; // Contains the string to be stored. 01013 01014 // (ChrisG 3/4/2001) 01015 if (Midpoint < 13) 01016 Midpoint = 13; 01017 else if (Midpoint > 87) 01018 Midpoint = 87; 01019 01020 pColour->GetCMYKValue ( &CMYKColour ); // Extract the CMYK value. 01021 01022 if (pColour->GetColourModel () == COLOURMODEL_RGBT || 01023 pColour->GetColourModel () == COLOURMODEL_HSVT) 01024 { 01025 // Use RGB syntax. 01026 pColour->GetRGBValue ( &red, &green, &blue ); 01027 01028 camSprintf ( Line, _T("2 %d %d%%_Bs"), Midpoint, Position ); 01029 pDC->OutputColour ( &CMYKColour ); 01030 pDC->OutputColourValue ( red ); 01031 pDC->OutputColourValue ( green ); 01032 pDC->OutputColourValue ( blue ); 01033 pDC->OutputToken ( Line ); 01034 pDC->OutputNewLine (); 01035 } 01036 else 01037 { 01038 01039 // It is necessary to build the output line like this, so that there isn't a space 01040 // between the position of the colour, and the %_Bs operator. 01041 camSprintf ( Line, _T("1 %d %d%%_Bs"), Midpoint, Position ); // Build the output string. 01042 01043 pDC->OutputColour ( &CMYKColour ); // Write the colour to the file. 01044 pDC->OutputToken ( Line ); // Write the output string out. 01045 pDC->OutputNewLine (); // And write a new-line tag. 01046 } 01047 01048 return TRUE; // All done successfully. 01049 } 01050 01051 /******************************************************************************************** 01052 01053 > virtual BOOL AIEPSRenderRegion::WriteFillEffectSteps ( DocColour * pColour1, 01054 INT32 pos1, 01055 DocColour * pColour2, 01056 INT32 pos2, 01057 INT32 bias, 01058 EFFECTTYPE effect) 01059 01060 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 01061 Created: 4/4/2001 01062 Inputs: pColour1 - The colour to start from. 01063 pos1 - The position of the start colour within the fill (0-100%). 01064 pColour2 - The colour to end at. 01065 pos2 - The position of the end colour within the entire fill (0-100%) 01066 bias - The fill's bias part of any profile (0-100%). 01067 effect - The type of fill effect (EFFECT_HSV_SHORT or EFFECT_HSV_LONG) 01068 Returns: TRUE if successful. 01069 FALSE if error (e.g. file/disk error) 01070 Purpose: Writes the additional entries required for a special fill effect (rainbow or 01071 alt-rainbow) to the gradient definition, as a series of steps. 01072 See Also: AIEPSRenderRegion::WriteGradientEntry 01073 AIEPSRenderRegion::WriteLinearFill 01074 AIEPSRenderRegion::WriteRadialFill 01075 01076 ********************************************************************************************/ 01077 BOOL AIEPSRenderRegion::WriteFillEffectSteps ( DocColour *pColour1, 01078 INT32 pos1, 01079 DocColour *pColour2, 01080 INT32 pos2, 01081 INT32 bias, 01082 EFFECTTYPE effect) 01083 { 01084 ERROR3IF (effect == EFFECT_RGB, "AIEPSRenderRegion::WriteFillEffectSteps, an attempt was made to write HSV fill effect steps on an RGB fade fill"); 01085 01086 // RGB fades are the 'standard' fill, so we don't want to do any special processing on them 01087 if (effect != EFFECT_RGB) 01088 { 01089 // Start and end colour values 01090 INT32 h1 = 0; 01091 INT32 h2 = 0; 01092 INT32 s1 = 0; 01093 INT32 s2 = 0; 01094 INT32 v1 = 0; 01095 INT32 v2 = 0; 01096 01097 // intermediate colour values / increments 01098 DocColour midColour; 01099 double hAdd = 0; 01100 double sAdd = 0; 01101 double vAdd = 0; 01102 double posAdd = 0; 01103 01104 // First get the start and end colour components 01105 pColour1->GetHSVValue (&h1, &s1, &v1); 01106 pColour2->GetHSVValue (&h2, &s2, &v2); 01107 01108 // Calculate the increments 01109 // 01110 // NOTE: if the hue changes by more than 180 deg. in a short HSV (rainbow) fill 01111 // (or not more than 180 deg. in a long HSV (alt-rainbow) fill), then the direction 01112 // must be reversed. This is done by changing the hue increment value. 01113 hAdd = h2-h1; 01114 if (effect == EFFECT_HSV_SHORT) 01115 { 01116 if (hAdd > 180) 01117 hAdd -= 360; 01118 else if (hAdd < -180) 01119 hAdd += 360; 01120 } 01121 else 01122 { 01123 if ((hAdd > 0) && (hAdd <= 180)) 01124 hAdd -= 360; 01125 else if ((hAdd <= 0) && (hAdd >= -180)) 01126 hAdd += 360; 01127 } 01128 hAdd = hAdd / (NumFillEmulationSteps + 1); 01129 sAdd = (s2-s1) / (NumFillEmulationSteps + 1); 01130 vAdd = (v2-v1) / (NumFillEmulationSteps + 1); 01131 posAdd = ((double) pos2-pos1) / (NumFillEmulationSteps + 1); 01132 01133 // Cycle through the stops calcuating each stop's colour and position, before 01134 // writing them out. 01135 for (INT32 i=1; i<NumFillEmulationSteps + 1; i++) 01136 { 01137 // increment each colour value and the position 01138 h2 = (INT32)(h1 + (i * hAdd)); 01139 s2 = (INT32)(s1 + (i * sAdd)); 01140 v2 = (INT32)(v1 + (i * vAdd)); 01141 pos2 = (INT32)(pos1 + (i * posAdd)); 01142 01143 // wrap the hue around if it's gone past 360 deg or 0 deg. 01144 if (h2>=360) 01145 h2 -= 360; 01146 else if (h2<0) 01147 h2 += 360; 01148 01149 // create the colour and export. 01150 midColour.SetHSVValue (h2, s2, v2); 01151 WriteGradientEntry (&midColour, pos2, 50); 01152 } 01153 } // End of is fill effect not an RGB fade. 01154 01155 return TRUE; 01156 } 01157 01158 /******************************************************************************************** 01159 01160 > virtual BOOL AIEPSRenderRegion::WriteDocumentSetup ( Document *pDocument, 01161 EPSFilter *pFilter ) 01162 01163 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 01164 Created: 24/3/00 01165 Inputs: pDocument - The document being outputted. 01166 pFilter - A pointer to the export filter. 01167 Outputs: - 01168 Returns: TRUE if successful. 01169 FALSE if error (e.g. file/disk error) 01170 Purpose: Browse through the tree, and if a text story is found invoke the document 01171 setup function. By only exporting the font setup when necessary, the file 01172 size produced is smaller (which makes it easier for me to interpret :) ), 01173 and it should hopefully make the filter run a bit faster too. 01174 01175 ********************************************************************************************/ 01176 01177 BOOL AIEPSRenderRegion::WriteDocumentSetup ( Document *pDocument, 01178 EPSFilter *pFilter ) 01179 { 01180 // Get the spread from the document. 01181 Spread *pSpread = pDocument->FindFirstSpread (); 01182 Node *pTextStory = NULL; 01183 01184 // Try to find a single instance of the TextStory node. 01185 pTextStory = SliceHelper::FindNextOfClass ( pSpread, pSpread, 01186 CC_RUNTIME_CLASS ( TextStory ) ); 01187 01188 // If something was found... 01189 if ( pTextStory != NULL ) 01190 { 01191 // ... write out the font set-up. 01192 pDocument->WriteEPSSetup ( pFilter ); 01193 } 01194 else 01195 { 01196 // Otherwise just get the relevant bits. 01197 pDocument->AIExportExtras ( pFilter->GetExportDC () ); 01198 } 01199 01200 // It worked! 01201 return TRUE; 01202 } 01203 01204 /******************************************************************************************** 01205 01206 > BOOL AIEPSRenderRegion::EndLayer () 01207 01208 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 01209 Created: 11/4/00 01210 Inputs: - 01211 Returns: TRUE - Success. 01212 FALSE - An error occured. 01213 Purpose: If there is an existing layer, it writes the end of layer tags, before 01214 creating a new layer record. 01215 SeeAlso: AIEPSRenderRegion::ExportLayer () 01216 01217 ********************************************************************************************/ 01218 01219 BOOL AIEPSRenderRegion::EndLayer () 01220 { 01221 // Only act if there's an active layer. 01222 if ( m_ActiveLayer ) 01223 { 01224 // Cast the RenderDC pointer into a useful form. 01225 KernelDC *pDC = static_cast<KernelDC *> ( CCDC::ConvertFromNativeDC(RenderDC) ); 01226 01227 // Write out the end of layer tag. 01228 pDC->OutputToken ( _T("LB") ); 01229 pDC->OutputNewLine (); 01230 pDC->OutputToken ( _T("%AI5_EndLayer") ); 01231 pDC->OutputNewLine (); 01232 01233 // Set m_ActiveLayer to be FALSE. 01234 m_ActiveLayer = FALSE; 01235 } 01236 01237 return TRUE; 01238 } 01239 01240 /******************************************************************************************** 01241 01242 > void AIEPSRenderRegion::WriteGradientFillInstance () 01243 01244 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 01245 Created: 9/03/00 01246 Purpose: This function identifies whether or not the current fill is a gradient fill, 01247 and writes in the appropriate values if it is. I've already created the 01248 records of the gradients themselves (see above), so this is just a case of 01249 matching the gradient with its ID, and Adobe Illustrator can then put the 01250 records together. 01251 01252 (ChrisG 18/12/00) - all this does now is increment the counters used for 01253 determining which gradient fill is currently being used. 01254 01255 SeeAlso: EPSRenderRegion::WriteGradientFill, WriteGradientFillUsage 01256 01257 ********************************************************************************************/ 01258 01259 void AIEPSRenderRegion::WriteGradientFillInstance () 01260 { 01261 KernelDC *pDC = (KernelDC*)CCDC::ConvertFromNativeDC(RenderDC); 01262 FillGeometryAttribute *pFillAttr = ( FillGeometryAttribute* ) 01263 CurrentAttrs[ATTR_FILLGEOMETRY].pAttr; 01264 DocCoord StartPoint = *( pFillAttr->GetStartPoint () ); 01265 DocCoord EndPoint = *( pFillAttr->GetEndPoint () ); 01266 DocCoord Delta = EndPoint - StartPoint; 01267 double Angle = 90.0f; 01268 double Length = FlashExportDC::CalculateLength ( Delta ); 01269 TCHAR Name [80]; 01270 BOOL IsRadial = pFillAttr->IsARadialFill () || 01271 pFillAttr->IsASquareFill (); 01272 INT32 id = 0; 01273 01274 if (IsGradientFillValidForExport (pFillAttr)) 01275 { 01276 id = FindGradientInCache (pFillAttr, GetFillEffect ()); 01277 01278 // If the fill is, or can be approximated by, a radial fill, set the the definition to 01279 // indicate this. 01280 if ( IsRadial ) 01281 { 01282 // Set up the name to show that it's a radial gradient. 01283 camSprintf ( Name, _T("(%s %d)"), RadialGradient, id ); 01284 } 01285 // Otherwise it's represented by a linear fill. 01286 else 01287 { 01288 // Set up the name to show that it's a linear gradient. 01289 camSprintf ( Name, _T("(%s %d)"), LinearGradient, id ); 01290 01291 // Reset the end point value if we're dealing with a three colour fill. 01292 if ( pFillAttr->IsAThreeColFill () ) 01293 { 01294 DocCoord EndPoint2 = *( pFillAttr->GetEndPoint2 () ); 01295 01296 // Complete the parallellogram of vectors. 01297 EndPoint += EndPoint2 - StartPoint; 01298 } 01299 } 01300 01301 // (ChrisG 16/01/01) Since all the endpoint calculations have now been done, 01302 // we can determine Delta, length and angle. (NOTE: these cannot be done 01303 // before here, as we wouldn't be using the correct endpoint values.) 01304 Delta = EndPoint - StartPoint; 01305 Length = FlashExportDC::CalculateLength ( Delta ); 01306 01307 // The tangent of an angle is undefined for PI/2 radians. (i.e. when Delta.x 01308 // is zero.) 01309 if ( Delta.x != 0 ) 01310 { 01311 Angle = atan ( ( double ) Delta.y / ( double ) Delta.x ); 01312 01313 // AI uses degrees, whereas the standard maths library uses radians, so 01314 // effect a conversion. 01315 Angle *= ( 180.0 / PI ); // Pi radians = 180 degrees. 01316 01317 // Tan repeats itself every Pi radians, so add 180 degrees to the angle 01318 // if it's got a negative value of Delta.y. Special case: If Delta.x is 01319 // negative, and Delta.y is 0, the angle is 180 degrees. 01320 if ( Delta.x < 0 ) 01321 { 01322 // I want the angle to be in the interval ]-180, 180], and so I've 01323 // got special case handling, depending on which quadrant it lies 01324 // in initially. Without the if statement here, the interval would 01325 // be ]-90, 270]. 01326 if ( Angle >= 0.0 ) 01327 { 01328 Angle -= 180.0; 01329 } 01330 else 01331 { 01332 Angle += 180.0; 01333 } 01334 } 01335 } 01336 01337 // More special case stuff. If Delta.x is 0, then the angle must be either 01338 // +90 or -90 degrees. And we can get the sign of the angle from the sign 01339 // of Delta.y 01340 else if ( Delta.y < 0 ) 01341 { 01342 Angle = -90.0; 01343 } 01344 01345 // AI uses points as a co-ordinate system - we use millipoints. Dividing 01346 // the length of the fill by 1,000 will thus return it's value in points. 01347 Length /= 1000; 01348 01349 // Write out the appropriate fill record. 01350 pDC->OutputToken ( _T("1") ); // It is a clipped gradient. 01351 pDC->OutputToken ( Name ); // The gradient's name. 01352 pDC->OutputCoord ( StartPoint ); // Start point for the gradient fill. 01353 pDC->OutputReal ( Angle ); // The angle of the fill from the X-Axis. 01354 pDC->OutputReal ( Length ); // The length of the matrix. 01355 pDC->OutputToken ( _T("1 0 0 1 0 0 Bg") ); // Matrix manipulating the fill. (Unused.) 01356 pDC->OutputNewLine (); 01357 01358 } // End of IsGradientFillValidForExport. 01359 } 01360 01361 /******************************************************************************************** 01362 01363 > void AIEPSRenderRegion::OutputFillColour () 01364 01365 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 01366 Created: 29/3/00 01367 Purpose: If the fill is a gradient fill, this method will invoke the 01368 WriteGradientFillInstance method, otherwise it will call the base 01369 EPSRenderRegion OutputFillColour method. This allows Camelot to support 01370 gradient fills in the AI file format. 01371 01372 (ChrisG 30/3/2001) - Gradient fill instances should be exported when they 01373 are used on an object, not when a fill attribute is found. This way, fills 01374 can be applied to multiple objects. 01375 01376 SeeAlso: AIEPSRenderRegion::OutputStrokeColour 01377 01378 ********************************************************************************************/ 01379 01380 void AIEPSRenderRegion::OutputFillColour () 01381 { 01382 // Output the actual fill colour. 01383 EPSRenderRegion::OutputFillColour (); 01384 } 01385 01386 /******************************************************************************************** 01387 01388 > BOOL AIEPSRenderRegion::LoadBitmapMatrix ( NodeBitmap *pNodeBMP ) 01389 01390 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 01391 Created: 4/4/00 01392 Inputs: pNodeBitmap - A pointer to the bitmap node being exported. 01393 Returns: TRUE - Successful. 01394 FALSE - An error has occured. 01395 Purpose: This code generates a matrix to position and manipulate a bitmap within 01396 an AI file. Roughly, it calculates the angle of rotation, followed by the 01397 skew angle, and creates a matrix using these values. 01398 See Also: FlashExportDC::WriteBitmapFill () 01399 01400 ********************************************************************************************/ 01401 01402 BOOL AIEPSRenderRegion::LoadBitmapMatrix ( NodeBitmap *pNodeBMP ) 01403 { 01404 // Step 1: Extract the co-ordinates of three corners from the bitmap record, and store 01405 // them as named co-ordinates within this function. The names are a historical 01406 // reference to the original names within the FlashExportDC, and refer to the 01407 // positions of a bitmap fill. 01408 double Angle = pNodeBMP->GetRotationAngle (); 01409 01410 double SinRotate = sin ( Angle ); 01411 double CosRotate = cos ( Angle ); 01412 // double Skew = 0; 01413 01414 DocCoord LowLeft = pNodeBMP->Parallel [3]; // Low corner of the bitmap. 01415 DocCoord TopLeft = pNodeBMP->Parallel [0]; // Max Y corner. 01416 DocCoord LowRight = pNodeBMP->Parallel [2]; // Max X corner. 01417 01418 // Step 2: Calculate the normalised dot product of the two vectors, and this forms 01419 // the cosine of their internal angle. 01420 double WidthX = static_cast<double> ( LowLeft.x - LowRight.x ) / 1000; 01421 double WidthY = static_cast<double> ( LowLeft.y - LowRight.y ) / 1000; 01422 double HeightX = static_cast<double> ( TopLeft.x - LowLeft.x ) / 1000; 01423 double HeightY = static_cast<double> ( TopLeft.y - LowLeft.y ) / 1000; 01424 01425 // Get the lengths of these vectors to normalise the dot-product. (Necessary for the 01426 // trignometric function calculations.) 01427 double Width = sqrt ( ( WidthX * WidthX ) + ( WidthY * WidthY ) ); 01428 double Height = sqrt ( ( HeightX * HeightX ) + ( HeightY * HeightY ) ); 01429 /* 01430 // The dot product calculation. By normalising the result, the cosine of the angle is 01431 // calculated. 01432 double CosSkew = ( ( WidthX * HeightX ) + ( HeightY * WidthY ) ) / 01433 ( Height * Width ); 01434 double SinSkew = sqrt ( 1 - ( CosSkew * CosSkew ) ); 01435 01436 // Multiply the width of the shape by the sine derived from the dot product. This will 01437 // give the actual width, and not the one distorted by skewing. 01438 Width *= SinSkew; 01439 01440 // If the DotSine value is not 0, calculate the tan value that forms the skew angle. 01441 // Since tan is undefined for 0, I'm ignoring this state. 01442 if ( SinSkew != 0 ) 01443 { 01444 Skew = - CosSkew / SinSkew; 01445 } 01446 */ 01447 // Grab a reference to the bitmap, and pull it's height and width from it. 01448 KernelBitmap *pBitmap = pNodeBMP->GetBitmap (); // A reference to the bitmap. 01449 01450 double BMPWidth = static_cast<double> ( pBitmap->GetWidth () ); 01451 double BMPHeight = static_cast<double> ( pBitmap->GetHeight () ); 01452 01453 // Catch BMPWidth or BMPHeight set to zero. This shouldn't happen... 01454 if ( BMPWidth == 0 ) 01455 BMPWidth = 1; 01456 01457 if ( BMPHeight == 0 ) 01458 BMPHeight = 1; 01459 01460 // Step 4: Use the above values to calculate the values with which to populate the 01461 // transformation matrix. 01462 double ScaleX = Width / BMPWidth; 01463 double ScaleY = Height / BMPHeight; 01464 01465 // Step 5: Use these to build the matrix. The variables a, b, c, d refer to the AI 01466 // matrix entries. The form of the matrix is: 01467 // 01468 // | SinRotate CosRotate | | ScaleX 0 | 01469 // | -CosRotate SinRotate | | Skew * ScaleY ScaleY | 01470 01471 m_a = ( SinRotate * ScaleX ); // + ( CosRotate * Skew * ScaleY ); 01472 m_b = ( - CosRotate * ScaleX ); // + ( SinRotate * Skew * ScaleY ); 01473 m_c = CosRotate * ScaleY; 01474 m_d = SinRotate * ScaleY; 01475 01476 // There's a weird bug with the AI export, in that a small (>0.0001) value is misread 01477 // by Adobe Illustrator as a monstrous value. To get around this, I'm going to set all 01478 // near zero values to zero. 01479 if ( Absol ( m_a ) < 1e-4 ) 01480 { 01481 m_a = 0; 01482 } 01483 01484 if ( Absol ( m_b ) < 1e-4 ) 01485 { 01486 m_b = 0; 01487 } 01488 01489 if ( Absol ( m_c ) < 1e-4 ) 01490 { 01491 m_c = 0; 01492 } 01493 01494 if ( Absol ( m_d ) < 1e-4 ) 01495 { 01496 m_d = 0; 01497 } 01498 01499 // Step 6: Calculate the translation part of the matrix. 01500 m_T = TopLeft; 01501 01502 return TRUE; 01503 } 01504 01505 /******************************************************************************************** 01506 01507 > BOOL AIEPSRenderRegion::LoadTranslationMatrix ( DocCoord &Translation ) 01508 01509 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 01510 Created: 10/4/00 01511 Inputs: - 01512 Returns: TRUE - Success. 01513 FALSE - An error occured. 01514 Purpose: Loads the matrix with: 01515 01516 | 1 0 Translation.x | 01517 | 0 1 Translation.y | 01518 01519 Which can then be written with WriteLoadedMatrix. 01520 SeeAlso: AIESPRenderRegion::LoadBitmapMatrix, AIEPSRenderRegion::WriteLoadedMatrix 01521 01522 ********************************************************************************************/ 01523 01524 BOOL AIEPSRenderRegion::LoadTranslationMatrix ( DocCoord &Translation ) 01525 { 01526 // Set the transformation part of the matrix to be the identity matrix. 01527 m_a = 1; 01528 m_b = 0; 01529 m_c = 0; 01530 m_d = 1; 01531 01532 // And load up the translation value. 01533 m_T = Translation; 01534 01535 return TRUE; 01536 } 01537 01538 /******************************************************************************************** 01539 01540 > BOOL AIEPSRenderRegion::WriteLoadedMatrix ( void ) 01541 01542 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 01543 Created: 10/4/00 01544 Inputs: - 01545 Returns: TRUE - Success. 01546 FALSE - An error occured. 01547 Purpose: Writes a pre-loaded matrix to the file. I've added a couple of functions to 01548 create a matrix first, since it'll be more efficient to store the data, and 01549 re-write it as required, than to recalculate it twice. 01550 SeeAlso: AIESPRenderRegion::LoadBitmapMatrix, AIEPSRenderRegion::LoadTranslationMatrix 01551 01552 ********************************************************************************************/ 01553 01554 BOOL AIEPSRenderRegion::WriteLoadedMatrix ( void ) 01555 { 01556 // Cast the DC pointer to be a KernelDC pointer. This allows it to access useful member 01557 // functions. 01558 KernelDC *pDC = static_cast<KernelDC *> ( CCDC::ConvertFromNativeDC(RenderDC) ); 01559 01560 // Write the matrix. 01561 pDC->OutputToken ( _T("[") ); 01562 pDC->OutputReal ( m_a ); 01563 pDC->OutputReal ( m_b ); 01564 pDC->OutputReal ( m_c ); 01565 pDC->OutputReal ( m_d ); 01566 pDC->OutputCoord ( m_T ); 01567 pDC->OutputToken ( _T("]") ); 01568 01569 return TRUE; 01570 } 01571 01572 /******************************************************************************************** 01573 01574 > void AIEPSRenderRegion::WriteMask ( Path *MaskPath, BOOL OutputGroupToken = FALSE ) 01575 01576 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 01577 Created: 7/4/00 01578 Inputs: DrawPath - The path to render. 01579 OutputGroupToken whether or not we output a 'q' clipping group token. 01580 Purpose: Creates a path that defines a masking pattern. All successive paths (until 01581 the end of mask operator) will be clipped to this shape. 01582 01583 I've repeated a lot of code from EPSRenderRegion::ExportPath because I'm 01584 scared of changing what is a fairly fundamental class, and then finding 01585 that there are several hundred resultant problems. A lot of the filters 01586 are pretty shakey at the moment in any case. 01587 SeeAlso: RenderRegion::ExportPath 01588 01589 ********************************************************************************************/ 01590 01591 BOOL AIEPSRenderRegion::WriteMask ( Path *MaskPath, BOOL OutputGroupToken ) 01592 { 01593 KernelDC *pDC = static_cast<KernelDC*> ( CCDC::ConvertFromNativeDC(RenderDC) ); // DC for export file. 01594 DocCoord *Coords = MaskPath->GetCoordArray(); 01595 PathVerb *Verbs = MaskPath->GetVerbArray(); 01596 INT32 NumCoords = MaskPath->GetNumCoords(); 01597 INT32 ReadPos = 1; // Reading data from. 01598 BOOL IsCompound = FALSE; 01599 01600 // (ChrisG 16/01/01) Only write masks/clips if there is a path to clip to. 01601 if (NumCoords != 0) 01602 { 01603 if (OutputGroupToken) 01604 { 01605 // Start the mask. 01606 pDC->OutputToken ( _T("q") ); 01607 pDC->OutputNewLine (); 01608 } 01609 01610 // Check to see if this is a compound path. If it is, there will be more than one 01611 // moveto command. 01612 while ( ReadPos < NumCoords ) 01613 { 01614 // Find out the type of element that we are over, after the close flag has been 01615 // removed. 01616 if ( ( ( Verbs [ReadPos] ) & ( ~PT_CLOSEFIGURE ) ) == PT_MOVETO ) 01617 { 01618 // This is a compound path - stop searching for moveto's. 01619 IsCompound = TRUE; 01620 01621 // Write the tag to indicate that it's a compound path. 01622 pDC->OutputToken ( _T("*u") ); 01623 pDC->OutputNewLine (); 01624 break; 01625 } 01626 else 01627 { 01628 // Try next point 01629 ReadPos++; 01630 } 01631 } 01632 01633 // Reset to start of path 01634 ReadPos = 0; 01635 01636 // loop through the whole path 01637 while(ReadPos < NumCoords) 01638 { 01639 // Find out the type of element that we are over (after the close flag has been removed) 01640 // Coord P[4]; 01641 switch ( (Verbs[ReadPos]) & (~PT_CLOSEFIGURE) ) 01642 { 01643 case PT_MOVETO: 01644 // If this is in the middle of the path, specify how this sub-path 01645 // should be rendered - this is needed so that we re-import all the flags 01646 // correctly on complex paths (e.g. PT_CLOSEFIGURE) 01647 if (ReadPos > 0) 01648 { 01649 // Write out the mask definition. 01650 WriteMaskTags (); 01651 } 01652 01653 // Output the moveto command 01654 pDC->OutputCoord(Coords[ReadPos]); 01655 pDC->OutputToken(TEXT("m")); 01656 pDC->OutputNewLine(); 01657 ReadPos++; 01658 break; 01659 01660 01661 case PT_LINETO: 01662 // Output the lineto command 01663 pDC->OutputCoord(Coords[ReadPos]); 01664 pDC->OutputToken(TEXT("l")); 01665 pDC->OutputNewLine(); 01666 ReadPos++; 01667 break; 01668 01669 01670 case PT_BEZIERTO: 01671 // If this point is a bezier, then the next 2 points should be beziers to 01672 ENSURE((Verbs[ReadPos+1]) & (~PT_CLOSEFIGURE), "Bezier found with 1 point"); 01673 ENSURE((Verbs[ReadPos+2]) & (~PT_CLOSEFIGURE), "Bezier found with 2 points"); 01674 01675 // Make sure that this is not at the start of the path 01676 ENSURE(ReadPos > 0, "Broken path found while exporting EPS" ); 01677 01678 // Output the moveto command 01679 pDC->OutputCoord(Coords[ReadPos]); 01680 pDC->OutputCoord(Coords[ReadPos+1]); 01681 pDC->OutputCoord(Coords[ReadPos+2]); 01682 pDC->OutputToken(TEXT("c")); 01683 pDC->OutputNewLine(); 01684 ReadPos += 3; 01685 break; 01686 01687 default: 01688 ENSURE( FALSE, "We found a Path Element that does not exist!" ); 01689 break; 01690 } 01691 } 01692 01693 // Do the final (or possibly only) render command 01694 WriteMaskTags (); 01695 01696 if ( IsCompound ) 01697 { 01698 01699 // End compound path 01700 pDC->OutputToken(_T("*U")); 01701 pDC->OutputNewLine(); 01702 } 01703 01704 // Wrap up the mask. 01705 pDC->OutputToken ( _T("0 O") ); 01706 pDC->OutputNewLine (); 01707 01708 } // End of if there is a clip path. 01709 01710 return TRUE; 01711 } 01712 01713 /******************************************************************************************** 01714 01715 > void AIEPSRenderRegion::WriteMaskTags ( void ) 01716 01717 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 01718 Created: 11/4/00 01719 Returns: TRUE - Success. 01720 FALSE - Error. 01721 Purpose: Writes out the tags at the end of each block of a mask's definition. 01722 SeeAlso: RenderRegion::ExportPath 01723 01724 ********************************************************************************************/ 01725 01726 BOOL AIEPSRenderRegion::WriteMaskTags () 01727 { 01728 KernelDC *pDC = static_cast<KernelDC*> ( CCDC::ConvertFromNativeDC(RenderDC) ); // DC for export file. 01729 01730 // Write out the mask definition tags. 01731 pDC->OutputToken ( _T("h") ); 01732 pDC->OutputNewLine (); 01733 pDC->OutputToken ( _T("W") ); 01734 pDC->OutputNewLine (); 01735 pDC->OutputToken ( _T("n") ); 01736 pDC->OutputNewLine (); 01737 01738 return TRUE; 01739 } 01740 01741 /******************************************************************************************** 01742 01743 > BOOL AIEPSRenderRegion::WriteBitmapRecord ( OILBitmap *pBitmap ) 01744 01745 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 01746 Created: 10/4/00 01747 Inputs: pBitmap - A pointer to the OIL bitmap object being rendered. 01748 Returns: TRUE - If successful. 01749 FALSE - If an error is encountered. 01750 Purpose: Creates a kernel bitmap instance within the AI file. 01751 SeeAlso: NodeBitmap::ExportRender () 01752 01753 ********************************************************************************************/ 01754 01755 BOOL AIEPSRenderRegion::WriteBitmapRecord ( OILBitmap *pBitmap ) 01756 { 01757 // Set up the local variables. 01758 // KernelDC *pDC = static_cast<KernelDC*> ( CCDC::ConvertFromNativeDC(RenderDC) ); 01759 INT32 Width = static_cast<INT32> ( pBitmap->GetWidth () ); 01760 INT32 Height = static_cast<INT32> ( pBitmap->GetHeight () ); 01761 01762 // Write out the bitmap header. 01763 WriteBitmapHeader ( Width, Height ); 01764 01765 // Write out the body. 01766 WriteBitmapBody ( pBitmap, Width, Height ); 01767 01768 // Finish off the bitmap record. 01769 WriteBitmapTail (); 01770 01771 // It worked! 01772 return TRUE; 01773 } 01774 01775 /******************************************************************************************** 01776 01777 > BOOL AIEPSRenderRegion::WriteBitmapHeader ( UINT32 Width, 01778 UINT32 Height ) 01779 01780 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 01781 Created: 13/4/00 01782 Inputs: Width - The width (in pixels) of the bitmap image. 01783 Height - The height (in pixels) of the bitmap image. 01784 Returns: TRUE - If successful. 01785 FALSE - If an error is encountered. 01786 Purpose: Writes the AI header for a bitmap record. 01787 SeeAlso: NodeBitmap::ExportRender () 01788 01789 ********************************************************************************************/ 01790 01791 BOOL AIEPSRenderRegion::WriteBitmapHeader ( INT32 Width, 01792 INT32 Height ) 01793 { 01794 // Set up kernel DC up in an appropriate form. 01795 KernelDC *pDC = static_cast<KernelDC *> ( CCDC::ConvertFromNativeDC(RenderDC) ); 01796 01797 // Declare the bitmap record. 01798 pDC->OutputToken ( _T("%AI5_File:") ); 01799 pDC->OutputNewLine (); 01800 pDC->OutputToken ( _T("%AI5_BeginRaster") ); 01801 pDC->OutputNewLine (); 01802 01803 // (ChrisG 23/11/00) The Xh operator has been removed, as it wasn't correct (it didn't 01804 // have the third, unknown, value), it isn't in the Illustrator File Format Manual, 01805 // and all the information in it seems to be duplicated in the standard XI operator, 01806 // which is written out immediately after the Xh one was. 01807 01808 // The matrix. 01809 // WriteLoadedMatrix (); 01810 01811 // Height and width. (and an extra value - as there's no mention of this token in the 01812 // Illustrator file format manual, I have no idea what it signifies, but Photoshop 01813 // needs it, or else it gives MPS Parser Errors). 01814 // pDC->OutputValue ( Width ); 01815 // pDC->OutputValue ( Height ); 01816 // pDC->OutputValue ( 0l ); 01817 // pDC->OutputToken ( _T("Xh") ); 01818 // pDC->OutputNewLine (); 01819 01820 01821 // Write out the XI operator. 01822 01823 // The matrix. 01824 WriteLoadedMatrix (); 01825 01826 // The bounds of the bitmap. 01827 pDC->OutputToken ( _T("0 0") ); 01828 pDC->OutputValue ( Width ); 01829 pDC->OutputValue ( Height ); 01830 01831 // Height and width. Note: The AI documentation puts their order the other 01832 // way around, but the AI export from Fireworks uses this order. 01833 pDC->OutputValue ( Width ); 01834 pDC->OutputValue ( Height ); 01835 01836 // These values are always constant, and so I don't need to worry about 01837 // them changing. 01838 pDC->OutputToken ( _T("8 3 0 0 0 0") ); 01839 pDC->OutputNewLine (); 01840 01841 // Write out the file size. 01842 pDC->OutputToken ( _T("%%BeginData:") ); 01843 pDC->OutputValue ( static_cast<INT32> ( Height * Width * 3 ) ); 01844 pDC->OutputNewLine (); 01845 01846 // Wrap out the XI operator. 01847 pDC->OutputToken ( _T("XI") ); 01848 pDC->OutputNewLine (); 01849 01850 return TRUE; 01851 } 01852 01853 /******************************************************************************************** 01854 01855 > BOOL AIEPSRenderRegion::WriteBitmapBody ( OILBitmap *pBitmap, 01856 INT32 Width, 01857 INT32 Height ) 01858 01859 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 01860 Created: 13/4/00 01861 Inputs: pBitmap - A pointer to the OIL bitmap object being rendered. 01862 Width - The width of the bitmap in pixels. 01863 Height - The height of the bitmap in pixels. 01864 Returns: TRUE - If successful. 01865 FALSE - If an error is encountered. 01866 Purpose: Writes the bitmap's data to the file. 01867 SeeAlso: NodeBitmap::ExportRender () 01868 01869 ********************************************************************************************/ 01870 01871 BOOL AIEPSRenderRegion::WriteBitmapBody ( OILBitmap *pBitmap, 01872 INT32 Width, 01873 INT32 Height ) 01874 { 01875 // Set up the local variables. 01876 KernelDC *pDC = static_cast<KernelDC*> ( CCDC::ConvertFromNativeDC(RenderDC) ); 01877 INT32 Count = 0; 01878 01879 // Write the initial %. 01880 pDC->OutputToken ( _T("%") ); 01881 01882 // Write out the bitmap data. It's necessary to go backwards through y 01883 // otherwise the bitmap is rendered upside down. 01884 for ( INT32 y = Height - 1; y >= 0; y-- ) 01885 { 01886 for ( INT32 x = 0; x < Width; x++ ) 01887 { 01888 Pixel32bpp BMPPixel = pBitmap->ReadPixel32bpp ( x, y ); 01889 TCHAR Output [7]; 01890 01891 // Wrap the line to keep the file tidy. 01892 if ( Count >= 10 ) 01893 { 01894 pDC->OutputNewLine (); 01895 pDC->OutputToken ( _T("%") ); 01896 Count = 0; 01897 } 01898 01899 // Translate the RGB values into an ASCII string. 01900 camSprintf ( Output, _T("%.2X%.2X%.2X"), BMPPixel.Red, BMPPixel.Green, BMPPixel.Blue ); 01901 01902 // And output them. I'm writing directly to the file because the OutputToken () 01903 // function introduces spaces between the values, which is not a good thing for 01904 // the AI file format. This way, it's much happier. :) 01905 if ( !pDC->OutputTCHARAsChar ( Output, 6 ) ) 01906 { 01907 // There's been a problem. 01908 return FALSE; 01909 } 01910 01911 Count ++; 01912 } 01913 } 01914 01915 // Write a new line after the bitmap record, to keep things tidy. 01916 pDC->OutputNewLine (); 01917 01918 return TRUE; 01919 } 01920 01921 /******************************************************************************************** 01922 01923 > BOOL AIEPSRenderRegion::WriteContoneBody ( OILBitmap *pBitmap ) 01924 01925 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 01926 Created: 13/4/00 01927 Inputs: pBitmap - A pointer to the OIL bitmap object being rendered. 01928 Returns: TRUE - If successful. 01929 FALSE - If an error is encountered. 01930 Purpose: Writes a contone bitmap to the file as a 32bpp image. 01931 SeeAlso: NodeBitmap::ExportRender () 01932 01933 ********************************************************************************************/ 01934 01935 BOOL AIEPSRenderRegion::WriteContoneBody ( OILBitmap *pBitmap ) 01936 { 01937 // Set up the local variables. 01938 KernelDC *pDC = static_cast<KernelDC*> ( CCDC::ConvertFromNativeDC(RenderDC) ); 01939 INT32 Width = static_cast<INT32> ( pBitmap->GetWidth () ); 01940 INT32 Height = static_cast<INT32> ( pBitmap->GetHeight () ); 01941 INT32 Count = 0; 01942 01943 // Write the initial %. 01944 pDC->OutputToken ( _T("%") ); 01945 01946 // Write out the bitmap data. It's necessary to go backwards through y 01947 // otherwise the bitmap is rendered upside down. 01948 for ( INT32 y = Height - 1; y >= 0; y-- ) 01949 { 01950 for ( INT32 x = 0; x < Width; x++ ) 01951 { 01952 UINT32 Index = pBitmap->ReadPixelGreyscale ( x, y ); 01953 DocColour PixelColour = pBitmap->GetContonePaletteEntry ( Index ); 01954 TCHAR Output [7]; 01955 INT32 lRed; 01956 INT32 lGreen; 01957 INT32 lBlue; 01958 01959 // Extract the values from the DocColour. 01960 PixelColour.GetRGBValue ( &lRed, &lGreen, &lBlue ); 01961 01962 // Wrap the line to keep the file tidy. 01963 if ( Count >= 10 ) 01964 { 01965 pDC->OutputNewLine (); 01966 pDC->OutputToken ( _T("%") ); 01967 Count = 0; 01968 } 01969 01970 // Translate the RGB values into an ASCII string. 01971 camSprintf ( Output, _T("%.2X%.2X%.2X"), lRed, lGreen, lBlue ); 01972 01973 // And output them. I'm writing directly to the file because the OutputToken () 01974 // function introduces spaces between the values, which is not a good thing for 01975 // the AI file format. This way, it's much happier. :) 01976 if ( !pDC->OutputTCHARAsChar ( Output, 6 ) ) 01977 { 01978 // There's been a problem. 01979 return FALSE; 01980 } 01981 01982 Count ++; 01983 } 01984 } 01985 01986 // Write a new line after the bitmap record, to keep things tidy. 01987 pDC->OutputNewLine (); 01988 01989 return TRUE; 01990 } 01991 01992 /******************************************************************************************** 01993 01994 > BOOL AIEPSRenderRegion::WriteBitmapTail ( void ) 01995 01996 Author: Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com> 01997 Created: 13/4/00 01998 Inputs: - 01999 Returns: TRUE - If successful. 02000 FALSE - If an error is encountered. 02001 Purpose: Wraps up the bitmap instance. 02002 SeeAlso: NodeBitmap::ExportRender () 02003 02004 ********************************************************************************************/ 02005 02006 BOOL AIEPSRenderRegion::WriteBitmapTail ( void ) 02007 { 02008 // Set up kernel DC up in an appropriate form. 02009 KernelDC *pDC = static_cast<KernelDC *> ( CCDC::ConvertFromNativeDC(RenderDC) ); 02010 02011 // Wrap up the bitmap record. 02012 pDC->OutputToken ( _T("%%EndData") ); 02013 pDC->OutputNewLine (); 02014 pDC->OutputToken ( _T("XH") ); 02015 pDC->OutputNewLine (); 02016 pDC->OutputToken ( _T("%AI5_EndRaster") ); 02017 pDC->OutputNewLine (); 02018 02019 // ChrisG (27/10/00). 02020 // This token was changed from 'N' close unfilled path, to 'F' close filled path. The 02021 // latter preserves information about the current line width, join type, fill colour, 02022 // etc... Whereas the 'N' token clears all this info, so any text objects or paths which 02023 // follow the bitmap were picking up colour and line info for an unfilled/unstroked path, 02024 // rather than the current attributes. 02025 pDC->OutputToken ( _T("F") ); 02026 pDC->OutputNewLine (); 02027 02028 // The colours are no longer valid, as the bitmap definition has invalidated them. 02029 m_bValidPathAttrs = FALSE; 02030 m_bValidTextAttrs = FALSE; 02031 02032 return TRUE; 02033 } 02034 02035 02036 /******************************************************************************************** 02037 02038 > void AIEPSRenderRegion::OutputWindingRule () 02039 02040 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 02041 Created: 19/12/00 02042 Purpose: Output the winding rule used to AI EPS 02043 02044 ********************************************************************************************/ 02045 02046 void AIEPSRenderRegion::OutputWindingRule () 02047 { 02048 // Set up kernel DC up in an appropriate form. 02049 KernelDC *pDC = static_cast<KernelDC *> ( CCDC::ConvertFromNativeDC(RenderDC) ); 02050 02051 if (RR_WINDINGRULE() == EvenOddWinding) 02052 { 02053 // Even-Odd winding (Camelot's default) 02054 pDC->OutputValue ((INT32)1); 02055 } 02056 else if (RR_WINDINGRULE() == NonZeroWinding) 02057 { 02058 // Non-Zero winding (EPS's default) 02059 pDC->OutputValue ((INT32)0); 02060 } 02061 else 02062 { 02063 // Positive or negative winding (only Even-Odd and Non-Zero are supported in AI7), 02064 // so assume that we're using camelot's default rule. 02065 pDC->OutputValue ((INT32)1); 02066 } 02067 02068 pDC->OutputToken (_T("XR")); 02069 pDC->OutputNewLine (); 02070 } 02071 02072 02073 02074 /******************************************************************************************** 02075 02076 > void AIEPSRenderRegion::OutputLineWidth() 02077 02078 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 02079 Created: 1/11/00 02080 Purpose: Output the standard line width token and measure for AI EPS 02081 02082 ********************************************************************************************/ 02083 02084 void AIEPSRenderRegion::OutputLineWidth() 02085 { 02086 TCHAR buf [64]; 02087 02088 // Set line width 02089 if (ExportingOnPath ()) 02090 { 02091 OverflowTextStartGap (); 02092 camSprintf (buf, _T("%.2f w\n"), ((double) RR_LINEWIDTH())/1000); 02093 OverflowTextWrite (buf); 02094 } 02095 02096 EPSRenderRegion::OutputLineWidth (); 02097 } 02098 02099 02100 /******************************************************************************************** 02101 02102 > void AIEPSRenderRegion::OutputJoinType() 02103 02104 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 02105 Created: 1/11/00 02106 Purpose: Output the standard AI EPS join type 02107 02108 ********************************************************************************************/ 02109 02110 void AIEPSRenderRegion::OutputJoinType() 02111 { 02112 TCHAR buf [64]; 02113 02114 // Set line Join Type 02115 if (ExportingOnPath ()) 02116 { 02117 OverflowTextStartGap (); 02118 camSprintf (buf, _T("%d j\n"), (UINT32)RR_JOINTYPE()); 02119 OverflowTextWrite (buf); 02120 } 02121 02122 EPSRenderRegion::OutputJoinType (); 02123 } 02124 02125 02126 02127 /******************************************************************************************** 02128 02129 > void AIEPSRenderRegion::OutputDashPattern() 02130 02131 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 02132 Created: 1/11/00 02133 Purpose: Outputs EPS dash pattern values. This function currently only exists so that 02134 extra handling can be easily achieved for Illustrator EPS export of dash 02135 patterns in the future (if need be). 02136 SeeAlso: EPSRenderRegion::OutputDashPattern (); 02137 EPSRenderRegion::OutputDashPatternInit(); 02138 02139 ********************************************************************************************/ 02140 02141 void AIEPSRenderRegion::OutputDashPattern() 02142 { 02143 EPSRenderRegion::OutputDashPattern (); 02144 } 02145 02146 02147 /******************************************************************************************** 02148 02149 > void AIEPSRenderRegion::OutputStartCap() 02150 02151 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 02152 Created: 1/11/00 02153 Purpose: Output the start cap setting using the usual 'J' EPS token 02154 02155 ********************************************************************************************/ 02156 02157 void AIEPSRenderRegion::OutputStartCap() 02158 { 02159 TCHAR buf [64]; 02160 02161 if (ExportingOnPath ()) 02162 { 02163 OverflowTextStartGap (); 02164 camSprintf (buf, _T("%d J\n"), (UINT32)RR_STARTCAP()); 02165 OverflowTextWrite (buf); 02166 } 02167 02168 EPSRenderRegion::OutputStartCap (); 02169 } 02170 02171 02172 /******************************************************************************************** 02173 02174 > void AIEPSRenderRegion::OutputMitreLimit() 02175 02176 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 02177 Created: 1/11/00 02178 Purpose: Output the current mitre limit value using the usual 'M' EPS token. 02179 Again, this is only here so that the AI export can be easily expanded or 02180 modified. 02181 02182 ********************************************************************************************/ 02183 02184 void AIEPSRenderRegion::OutputMitreLimit() 02185 { 02186 EPSRenderRegion::OutputMitreLimit (); 02187 } 02188 02189 02190 02191 02192 02193 /******************************************************************************************** 02194 02195 > void AIEPSRenderRegion::OutputStrokeColour() 02196 02197 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 02198 Created: 1/11/00 02199 Purpose: Output the current stroke colour. This function will use one of the 02200 following EPS tokens 02201 K - if not separating and colour is unnamed 02202 X - if not separating and colour is named 02203 G - if separating 02204 SeeAlso: AIEPSRenderRegion::OutputFillColour 02205 02206 ********************************************************************************************/ 02207 02208 void AIEPSRenderRegion::OutputStrokeColour() 02209 { 02210 // Write out the stroke colour 02211 EPSRenderRegion::OutputStrokeColour (); 02212 } 02213 02214 02215 02216 02217 02218 02219 02220 02221 /******************************************************************************************** 02222 02223 > void AIEPSRenderRegion::OutputFontName() 02224 02225 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 02226 Created: 1/11/00 02227 Purpose: Output an Illustrator format fontname and pointsize token. The format is 02228 /_fontname[-Bold|-Italic|-BoldItalic] pointsize Tf. 02229 EncodeFontName will generate this format from an internal fontname. 02230 DocodeFontName will return an internal format fontname and flags where nec. 02231 02232 ********************************************************************************************/ 02233 02234 void AIEPSRenderRegion::OutputFontName() 02235 { 02236 if (ExportingOnPath ()) 02237 { 02238 TCHAR buffer [64]; 02239 02240 OverflowTextStartGap (); 02241 02242 String_64 FontName; 02243 String_64 EncodedFontName; 02244 String_64 Append(_T("/_")); 02245 02246 // get information about the current font 02247 FONTMANAGER->GetFontName(RR_TXTFONTTYPEFACE(), FontName); 02248 02249 // Graeme (31-3-00) - I've lifted this piece of code from the CamelotEPSRenderRegion. It 02250 // appears to map an existing, encoded font name onto its Postscript counterpart. 02251 FONTMANAGER->EncodeAndMapFontName(FontName, EncodedFontName, GetFontStyle()); 02252 02253 EncodedFontName.Insert(Append,0); 02254 02255 // Output the fontsize next 02256 double PointSize = ((double)RR_TXTFONTSIZE())/1000; 02257 02258 // finally do output the font token 02259 camSprintf (buffer, _T("%s %.1f Tf\n"), (TCHAR *)EncodedFontName, PointSize); 02260 OverflowTextWrite (buffer); 02261 } 02262 EPSRenderRegion::OutputFontName (); 02263 } 02264 02265 02266 02267 /******************************************************************************************** 02268 02269 > void AIEPSRenderRegion::OutputTextRenderMode() 02270 02271 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 02272 Created: 1/11/00 02273 Purpose: Output the change in the text's Render Mode (Tr) - this happens when the 02274 text's fill or line colour changes to or from blank, see-through colour 02275 02276 ********************************************************************************************/ 02277 02278 void AIEPSRenderRegion::OutputTextRenderMode () 02279 { 02280 INT32 Style=0; 02281 02282 if (ExportingOnPath ()) 02283 { 02284 OverflowTextStartGap (); 02285 02286 // Is there a currently active fill colour? 02287 if (! (RR_FILLCOLOUR().IsTransparent()) ) 02288 Style+=1; 02289 02290 // Is there a currently active line colour? 02291 if (! (RR_STROKECOLOUR().IsTransparent()) ) 02292 Style+=2; 02293 02294 switch (Style) 02295 { 02296 case 0: OverflowTextWrite (_T("3 Tr\n")); // Invisible 02297 break; 02298 case 1: OverflowTextWrite (_T("0 Tr\n")); // filled only 02299 break; 02300 case 2: OverflowTextWrite (_T("1 Tr\n")); // stroked only 02301 break; 02302 case 3: OverflowTextWrite (_T("2 Tr")); // filled and stroked 02303 break; 02304 } 02305 } 02306 02307 EPSRenderRegion::OutputTextRenderMode (); 02308 } 02309 02310 02311 02312 /******************************************************************************************** 02313 02314 > void AIEPSRenderRegion::OutputTextAspectRatio() 02315 02316 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 02317 Created: 1/11/00 02318 Purpose: Output the change in the text's aspect ratio (Tz) 02319 02320 ********************************************************************************************/ 02321 02322 void AIEPSRenderRegion::OutputTextAspectRatio () 02323 { 02324 TCHAR buf [64]; 02325 02326 if (ExportingOnPath ()) 02327 { 02328 OverflowTextStartGap (); 02329 camSprintf (buf, _T("%.0f Tz\n"), (RR_TXTASPECTRATIO().MakeDouble()*100.0)); // convert from ratio to % 02330 OverflowTextWrite (buf); 02331 } 02332 02333 EPSRenderRegion::OutputTextAspectRatio (); 02334 } 02335 02336 02337 02338 /******************************************************************************************** 02339 02340 > void AIEPSRenderRegion::OutputTextTracking() 02341 02342 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 02343 Created: 1/11/00 02344 Purpose: Output the change in the tracking (Tt) 02345 02346 ********************************************************************************************/ 02347 02348 void AIEPSRenderRegion::OutputTextTracking () 02349 { 02350 // Must be output in 1/1000 of an em. 02351 // 1 em = point size of font. 02352 // Tracking internally =millipoints. 02353 TCHAR buf [64]; 02354 02355 if (ExportingOnPath ()) 02356 { 02357 OverflowTextStartGap (); 02358 camSprintf (buf, _T("%d Tt\n"), RR_TXTTRACKING()); 02359 OverflowTextWrite (buf); 02360 } 02361 02362 EPSRenderRegion::OutputTextTracking (); 02363 } 02364 02365 02366 02367 /******************************************************************************************** 02368 02369 > void EPSRenderRegion::OutputTextJustification() 02370 02371 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 02372 Created: 1/11/00 02373 Purpose: Output the change in the text justification (Ta) 02374 02375 ********************************************************************************************/ 02376 02377 void AIEPSRenderRegion::OutputTextJustification () 02378 { 02379 TCHAR buf [64]; 02380 02381 if (ExportingOnPath ()) 02382 { 02383 OverflowTextStartGap (); 02384 02385 switch (RR_TXTJUSTIFICATION()) 02386 { 02387 case JLEFT: 02388 camSprintf (buf, _T("%d Ta\n"), ((INT32)0)); 02389 break; 02390 case JRIGHT: 02391 camSprintf (buf, _T("%d Ta\n"), ((INT32)2)); 02392 break; 02393 case JCENTRE: 02394 camSprintf (buf, _T("%d Ta\n"), ((INT32)1)); 02395 break; 02396 case JFULL: 02397 camSprintf (buf, _T("%d Ta\n"), ((INT32)3)); 02398 break; 02399 } 02400 OverflowTextWrite (buf); 02401 } 02402 02403 EPSRenderRegion::OutputTextJustification (); 02404 } 02405 02406 /******************************************************************************************** 02407 02408 > void AIEPSRenderRegion::OutputTextLineSpacing() 02409 02410 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 02411 Created: 1/11/00 02412 Purpose: Output the change in the line spacing (Tl) 02413 02414 ********************************************************************************************/ 02415 02416 void AIEPSRenderRegion::OutputTextLineSpacing () 02417 { 02418 02419 if (ExportingOnPath ()) 02420 { 02421 TCHAR buf [64]; 02422 02423 OverflowTextStartGap (); 02424 02425 // Output line spacing in points. 02426 // format - paraspace linespace Tl 02427 double ptLineSpace; 02428 double ptParaSpace=0; 02429 02430 TxtLineSpaceAttribute* pLineSpace = (TxtLineSpaceAttribute*)(CurrentAttrs[ATTR_TXTLINESPACE].pAttr); 02431 02432 // There are some rules for reading the linespacing value which I shall divulge 02433 // If IsARation is true then use the proportinal linespacing value. 02434 // else use the absolute linespacing 02435 // However if the absolute linespacing is zero, then we MUST use the proportional 02436 // linespacing. Eeek! 02437 // ie it is an error if (absolute==0 && !IsARatio()) which we will check for here 02438 02439 double FontSize = (double)RR_TXTFONTSIZE(); // in millipoints 12pt = 12000 mp 02440 double absLineSpace = (double)pLineSpace->Value; 02441 double proLineSpace = (pLineSpace->Ratio).MakeDouble(); 02442 02443 BOOL Proportional = pLineSpace->IsARatio(); 02444 02445 if (!Proportional && absLineSpace==0) 02446 { 02447 ERROR3("Absolute line spacing is zero yet IsARatio() is FALSE, in GetValidTextAttributes()"); 02448 // Make sure we use the proportional value no matter what. 02449 Proportional=TRUE; 02450 } 02451 02452 if (Proportional) 02453 ptLineSpace = FontSize*proLineSpace/1000; 02454 else 02455 ptLineSpace = absLineSpace/1000; 02456 02457 camSprintf (buf, _T("%.0f %.0f Tl\n"), ptLineSpace, ptParaSpace); 02458 OverflowTextWrite (buf); 02459 } 02460 02461 EPSRenderRegion::OutputTextLineSpacing (); 02462 } 02463 02464 02465 /******************************************************************************************** 02466 02467 > void AIEPSRenderRegion::OutputTextBaselineShift() 02468 02469 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 02470 Created: 1/11/00 02471 Purpose: Output the change in Baseline shift (Ts) 02472 02473 ********************************************************************************************/ 02474 02475 void AIEPSRenderRegion::OutputTextBaselineShift () 02476 { 02477 TCHAR buf [64]; 02478 02479 // Output baseline shift in points 02480 // format = rise Ts 02481 if (ExportingOnPath ()) 02482 { 02483 OverflowTextStartGap (); 02484 double BaseLine = ((double)RR_TXTBASELINE())/1000; 02485 camSprintf (buf, _T("%.1f Ts\n"), BaseLine); 02486 OverflowTextWrite (buf); 02487 } 02488 02489 EPSRenderRegion::OutputTextBaselineShift (); 02490 } 02491 02492 02493 /******************************************************************************************** 02494 02495 > void AIEPSRenderRegion::OutputTextSubSuperScript() 02496 02497 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 02498 Created: 1/11/00 02499 Purpose: Output the change in the Sub/Super script attribute (Ts) 02500 02501 ********************************************************************************************/ 02502 02503 void AIEPSRenderRegion::OutputTextSubSuperScript () 02504 { 02505 TCHAR buf [64]; 02506 02507 if (ExportingOnPath ()) 02508 { 02509 OverflowTextStartGap (); 02510 02511 // Output sub/superscript 02512 // in millipoints 12pt = 12000 mp 02513 double FontSize = ((double)RR_TXTFONTSIZE())/1000; 02514 02515 TxtScriptAttribute* pScript = RR_TXTSCRIPT(); 02516 double offset = (pScript->Offset).MakeDouble(); 02517 double size = (pScript->Size).MakeDouble(); 02518 02519 OverflowTextWrite (_T("%%XSScript\n")); 02520 02521 double rise = FontSize*offset; 02522 02523 camSprintf (buf, _T("%.1f Ts\n"), rise); 02524 OverflowTextWrite (buf); 02525 02526 double ptsize = FontSize*size; 02527 02528 String_64 MappedFont; 02529 String_64 Append(_T("/_")); 02530 02531 String_64 FontName; 02532 FONTMANAGER->GetFontName(RR_TXTFONTTYPEFACE(), FontName); 02533 02534 // Graeme (31-3-00) - Map the encoded name onto the PS font name. 02535 FONTMANAGER->EncodeAndMapFontName(FontName,MappedFont,GetFontStyle()); 02536 02537 // Graeme (14-6-00) - I should add ascent and descent values, but Camelot doesn't 02538 // seem to store them anywhere. 02539 MappedFont.Insert(Append,0); 02540 02541 camSprintf (buf, _T("%s %.1f Tf\n"),(TCHAR *)MappedFont, ptsize); 02542 // Output the ascent. 02543 // Output the descent. 02544 OverflowTextWrite (buf); 02545 } 02546 02547 EPSRenderRegion::OutputTextSubSuperScript (); 02548 } 02549 02550 /*------------*/ 02551 02552 02553 02554 //---------------------------------------------------------------- 02555 // 02556 // The following functions are all overflow text functions, 02557 // which write an additional text line, terminated with the 02558 // token (TX), to the EPS file, the Output functions declared 02559 // earlier should call these functions to add any attribute 02560 // changes, so that the two text blocks remain consistent. 02561 // 02562 //---------------------------------------------------------------- 02563 02564 02565 /******************************************************************************************** 02566 02567 > void AIEPSRenderRegion::ExportingOnPath() 02568 02569 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 02570 Created: 2/11/00 02571 Returns: TRUE - yes, we are exporting on a path 02572 FALSE - no, we aren't exporting on a path 02573 Purpose: To determine whether this text is being exported on a path. 02574 SeeAlso: 02575 02576 ********************************************************************************************/ 02577 02578 BOOL AIEPSRenderRegion::ExportingOnPath () 02579 { 02580 if (m_fpOverflowText) 02581 return TRUE; 02582 else 02583 return FALSE; 02584 } 02585 02586 02587 /******************************************************************************************** 02588 02589 > void AIEPSRenderRegion::OverflowTextStart() 02590 02591 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 02592 Created: 1/11/00 02593 Purpose: Start the overflow text block. 02594 SeeAlso: 02595 02596 ********************************************************************************************/ 02597 02598 void AIEPSRenderRegion::OverflowTextStart () 02599 { 02600 // open overflow file 02601 m_fpOverflowText = fopen ("OverFlow.txt", "w"); 02602 02603 // write out start info - NOTE: we're currently in a gap from writing the initial 02604 // attributes, so we're going to have to close it. 02605 m_bInTextGap = TRUE; 02606 } 02607 02608 02609 /******************************************************************************************** 02610 02611 > void AIEPSRenderRegion::OverflowTextFinish() 02612 02613 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 02614 Created: 1/11/00 02615 Purpose: Finish the overflow text block and write both blocks to the actual EPS file. 02616 SeeAlso: 02617 02618 ********************************************************************************************/ 02619 02620 void AIEPSRenderRegion::OverflowTextFinish () 02621 { 02622 ASSERT (m_fpOverflowText); 02623 02624 // write out final information. 02625 OverflowTextStartGap (); 02626 02627 // close files. 02628 fclose (m_fpOverflowText); 02629 m_fpOverflowText = NULL; 02630 02631 // copy info into actual EPS file. 02632 char cbuffer [1025]; 02633 TCHAR buffer [1025]; 02634 KernelDC *pDC = (KernelDC*)CCDC::ConvertFromNativeDC(RenderDC); 02635 FILE * fp; 02636 02637 // Write out the Extra info. 02638 fp = fopen ("OverFlow.txt", "r+t"); 02639 02640 while (fgets (cbuffer, 1024, fp) != NULL) 02641 { 02642 char c; 02643 INT32 i=0; 02644 cbuffer[1024]=0; 02645 do 02646 { 02647 c=cbuffer[i]; 02648 buffer[i]=c; // 1:1 CHAR->TCHAR conversion 02649 i++; 02650 } while (c); 02651 02652 // deal with newlines. 02653 pDC->OutputToken (buffer); 02654 pDC->OutputNewLine (); 02655 } 02656 fclose (fp); 02657 02658 02659 // clean up temp. files 02660 remove ("OverFlow.txt"); 02661 } 02662 02663 /******************************************************************************************** 02664 02665 > void AIEPSRenderRegion::OverflowTextStartGap() 02666 02667 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 02668 Created: 2/11/00 02669 Purpose: Starts a new gap in the Overflow text, so that attributes can be written into 02670 the overflow blocks (the TX ones) 02671 SeeAlso: AIEPSRenderRegion::OverflowTextFinishGap () 02672 02673 ********************************************************************************************/ 02674 02675 void AIEPSRenderRegion::OverflowTextStartGap () 02676 { 02677 ASSERT (ExportingOnPath ()); 02678 02679 // if we're not in a gap, finish writing the old TX block and start a new gap, 02680 if (m_bInTextGap == FALSE) 02681 { 02682 OverflowTextWrite (_T(") TX\n")); 02683 m_bInTextGap = TRUE; 02684 } 02685 } 02686 02687 /******************************************************************************************** 02688 02689 > void AIEPSRenderRegion::OverflowTextFinishGap() 02690 02691 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 02692 Created: 2/11/00 02693 Purpose: Closes a gap for writing attributes in the overflow text, so that a new line 02694 of overflow text can be started. 02695 SeeAlso: AIEPSRenderRegion::OverflowTextStartGap (); 02696 02697 ********************************************************************************************/ 02698 02699 void AIEPSRenderRegion::OverflowTextFinishGap () 02700 { 02701 ASSERT (ExportingOnPath ()); 02702 02703 // if we're in a text gap (for changing the attributes), start writing a new TX block. 02704 if (m_bInTextGap == TRUE) 02705 { 02706 OverflowTextWrite (_T("(")); 02707 m_bInTextGap = FALSE; 02708 } 02709 } 02710 02711 02712 /******************************************************************************************** 02713 02714 > void AIEPSRenderRegion::OverflowTextWrite() 02715 02716 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 02717 Created: 1/11/00 02718 Purpose: Write some text to the overflow body file. This will store all the text and 02719 modified attributes for the TX text block. 02720 SeeAlso: 02721 02722 ********************************************************************************************/ 02723 02724 void AIEPSRenderRegion::OverflowTextWrite (TCHAR * text) 02725 { 02726 ASSERT (ExportingOnPath ()); 02727 while (*text) 02728 { 02729 fprintf (m_fpOverflowText, "%c", *text++); 02730 } 02731 } 02732 02733 02734 /******************************************************************************************** 02735 02736 > BOOL AIEPSRenderRegion::OverflowTextWriteSingleColour (UINT32 n) 02737 02738 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 02739 Created: 3/11/00 02740 Inputs: n - the colour value (range 0-255) to write to the EPS file. 02741 Purpose: Output a colour value to the overflow text file. A 'single colour' is a value 02742 as used in the Camelot 'Colour' class, i.e. in the range 0 to 255. 02743 This range is converted to the range 0.0 to 1.0, and output to the file. 02744 SeeAlso: KernelDC::OutputColourValue 02745 02746 ********************************************************************************************/ 02747 02748 void AIEPSRenderRegion::OverflowTextWriteSingleColour (UINT32 n) 02749 { 02750 // Output to string 02751 TCHAR buf[20]; 02752 02753 // Convert to points, getting integer and fractional parts 02754 camSprintf (buf, _T("%.2f "), ((double) n) / 255); 02755 OverflowTextWrite (buf); 02756 } 02757 02758 /******************************************************************************************** 02759 02760 > BOOL AIEPSRenderRegion::OverflowTextWriteColour(PColourCMYK *pCol) 02761 02762 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 02763 Created: 3/11/00 02764 Inputs: Col - the CMYK colour values to be output. 02765 Purpose: Output a colour, as expressed by the Camelot 'Colour' class. This function 02766 takes the CMYK variation, is this is most appropriate to EPS files. 02767 Camelot colour values are converted from the 0-255 range to the 0.0-1.0 02768 range before being output. 02769 02770 e.g. 02771 MonoOn 02772 PColourCMYK Col = { 255, 255, 128, 0 }; 02773 pDC->OutputColour(&Col); 02774 MonoOff 02775 will give the following output: 02776 MonoOn 02777 1.0 1.0 0.5 0.0 02778 MonoOff 02779 SeeAlso: KernelDC::OutputColourValue 02780 Errors: Disk/file error => ERROR1 02781 02782 ********************************************************************************************/ 02783 02784 void AIEPSRenderRegion::OverflowTextWriteColour (PColourCMYK *pCol) 02785 { 02786 // Write each of the colour values. 02787 OverflowTextWriteSingleColour (pCol->Cyan); 02788 OverflowTextWriteSingleColour (pCol->Magenta); 02789 OverflowTextWriteSingleColour (pCol->Yellow); 02790 OverflowTextWriteSingleColour (pCol->Key); 02791 } 02792 02793 /******************************************************************************************** 02794 02795 > void AIEPSRenderRegion::OverflowTextWriteNamedColour (DocColour *pCol, 02796 ColourContext* pContext = NULL) 02797 02798 Author: Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> 02799 Created: 09/08/94 02800 Inputs: pCol - the colour to output. 02801 pContext - the context to use to convert the colour before output. 02802 if this is NULL the default CMYK context will be used. 02803 Returns: TRUE if the data was written ok; 02804 FALSE if not => ERROR1 02805 Purpose: Similar to OutputColour(), except it outputs the colour name and tint 02806 of the colour as well. If pCol does not reference an indexed colour, 02807 then the name "NoName" is used. 02808 SeeAlso: KernelDC::OutputColour 02809 Errors: Disk/file error => ERROR1 02810 02811 ********************************************************************************************/ 02812 02813 void AIEPSRenderRegion::OverflowTextWriteNamedColour(DocColour *pCol, ColourContext* pContext) 02814 { 02815 // Get CMYK version of this colour. 02816 PColourCMYK CMYK; 02817 pCol->GetCMYKValue(pContext, &CMYK); 02818 02819 // Output CMYK version 02820 OverflowTextWriteColour (&CMYK); 02821 02822 // Get the indexed colour from the DocColour. 02823 IndexedColour *pIndCol = pCol->FindParentIndexedColour(); 02824 02825 // Cope with the unexpected! 02826 // ENSURE(pIndCol != NULL, "Named colour has no index colour!"); 02827 02828 if (pIndCol == NULL) 02829 { 02830 if (pCol->IsTransparent()) 02831 { 02832 // This is a 'no colour' type colour, so output a zero-length colour name, 02833 // as this is the only way we can handle this at the moment. 02834 return; 02835 } 02836 else 02837 { 02838 // Otherwise make up a colour name (see epsfiltr.h). 02839 OverflowTextWrite (_T("(")); 02840 OverflowTextWrite (ImmediateColourFudgeyBodgeName); 02841 OverflowTextWrite (_T(")")); 02842 } 02843 } 02844 else 02845 { 02846 // Got an indexed colour - output its name 02847 // (Pass in TRUE to get a unique-identifier for local colours rather than "Local colour") 02848 String_64 *ColName = pIndCol->GetName(TRUE); 02849 OverflowTextWrite (_T("(")); 02850 OverflowTextWrite ((TCHAR *) (*ColName)); 02851 OverflowTextWrite (_T(")")); 02852 } 02853 02854 // Always tint 0 02855 OverflowTextWrite (_T(" 0 ")); 02856 } 02857 02858 /******************************************************************************************** 02859 02860 > void AIEPSRenderRegion::OverflowTextWriteColourName (DocColour *pCol) 02861 02862 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 02863 Created: 18/12/00 02864 Inputs: pCol - the colour to output. 02865 Purpose: Outputs a named colour's name as a string. If pCol does not reference an 02866 indexed colour, then the name "NoName" is used. This was seperated from 02867 OutputNamedColour so that the DeviceContext will not need to worry about 02868 which ColourModel to use (CMYK, RGB, etc...), as this will be determined 02869 by the RenderRegion. 02870 SeeAlso: KernelDC::OutputNamedColour 02871 Errors: Disk/file error => ERROR1 02872 02873 ********************************************************************************************/ 02874 02875 void AIEPSRenderRegion::OverflowTextWriteColourName (DocColour *pCol) 02876 { 02877 // Get the indexed colour from the DocColour. 02878 IndexedColour *pIndCol = pCol->FindParentIndexedColour(); 02879 02880 if (pIndCol == NULL) 02881 { 02882 if (pCol->IsTransparent()) 02883 { 02884 // This is a 'no colour' type colour, so output a zero-length colour name, 02885 // as this is the only way we can handle this at the moment. 02886 OverflowTextWrite (_T("()")); 02887 } 02888 else 02889 { 02890 // Otherwise make up a colour name (see epsfiltr.h). 02891 OverflowTextWrite (_T("(")); 02892 OverflowTextWrite (ImmediateColourFudgeyBodgeName); 02893 OverflowTextWrite (_T(")")); 02894 } 02895 } 02896 else 02897 { 02898 // Got an indexed colour - output its name 02899 // (Pass in TRUE to get a unique-identifier for local colours rather than "Local colour") 02900 String_64 *ColName = pIndCol->GetName(TRUE); 02901 OverflowTextWrite (_T("(")); 02902 OverflowTextWrite ((TCHAR *) (*ColName)); 02903 OverflowTextWrite (_T(")")); 02904 } 02905 } 02906 02907 02908 02909 02910 02911 /******************************************************************************************** 02912 02913 > virtual void AIEPSRenderRegion::SetClipRegion(ClipRegionAttribute* pClipAttr, BOOL Temp) 02914 02915 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 02916 Created: 8th November 2000 02917 Inputs: pClipAttr ptr to the new ClipRegionAttribute to set as current in our RR. 02918 Temp whether the attr is temporary or not. 02919 02920 Outputs: Postscript's context is saved and the commands are output to intersect its 02921 current clipping path with that defined by the ClipAttr. 02922 Also, the RR's current attr context is updated to use this new ClipAttr. 02923 02924 Purpose: The Adobe Illustrator version of Karim's EPSRenderRegion::SetClipRegion, 02925 This was needed as Illustrator uses non-standard EPS commands 02926 02927 Shrink the RR's clipping region to the region defined by pClipAttr. 02928 We do this by: 02929 1. Recording a save-state command. 02930 2. Exporting a description of the clipping path in pClipAttr. 02931 3. Recording a 'clip-to-last-path' command. 02932 4. Recording a 'start-new-path' command, as we don't want our clip-path 02933 to get stroked or rendered in any way. 02934 02935 Notes: We mustn't record clipping commands when rendering the default attribute. 02936 Therefore this method does *nothing whatsoever* unless pClipAttr's ptr to 02937 its clipping-path is non-NULL. This ptr is NULL in the default attr. 02938 02939 See also: RenderRegion::SetClipRegion(), EPSRenderRegion::SetClipRegion() 02940 02941 ********************************************************************************************/ 02942 void AIEPSRenderRegion::SetClipRegion(ClipRegionAttribute* pClipAttr, BOOL Temp) 02943 { 02944 if (pClipAttr->GetClipPath() != NULL) 02945 { 02946 // Update the RR's table of current attributes. 02947 RenderRegion::SetClipRegion (pClipAttr, Temp); 02948 02949 // Write out the clipping path as a mask. 02950 WriteMask(pClipAttr->GetClipPath(), pClipAttr->IsResponsibleForGrouping ()); 02951 } 02952 } 02953 02954 02955 02956 /******************************************************************************************** 02957 02958 > virtual void AIEPSRenderRegion::RestoreClipRegion(ClipRegionAttribute* pClipAttr, BOOL Temp) 02959 02960 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 02961 Created: 8th November 2000 02962 Inputs: pClipAttr ptr to the ClipRegionAttribute to restore over the current one. 02963 Temp whether the attr is temporary or not. 02964 02965 Outputs: Postscript is told to restore its last saved context. 02966 02967 Purpose: Adobe Illustrator version of Karim's EPSRenderRegion::RestoreClipRegion. 02968 See SetClipRegion for why this was necessary. 02969 02970 Restore the RR's clipping region. 02971 We do this by recording a restore-state command. 02972 02973 Errors: ERROR3 if the current ClipRegionAttribute holds a NULL clip-path ptr. 02974 This state of affairs should not happen. You can't set a ClipRegionAttribute 02975 with a NULL clip-path ptr, so the only such attr is the default one, and you 02976 should never be restoring over _that_. 02977 02978 See also: RenderRegion::RestoreClipRegion(), EPSRenderRegion::RestoreClipRegion() 02979 02980 ********************************************************************************************/ 02981 02982 void AIEPSRenderRegion::RestoreClipRegion(ClipRegionAttribute* pClipAttr, BOOL Temp) 02983 { 02984 // we should never be entered when the current clipattr has a NULL path, as what this 02985 // means is that either somebody somehow did a SetClipRegion() with such an attr, or 02986 // somebody is trying to Restore() over the default ClipRegionAttribute (which holds a 02987 // NULL path ptr). Neither of these actions should occur. 02988 02989 if (RR_CLIPREGION()->GetClipPath() == NULL) 02990 { 02991 ERROR3("EPSRenderRegion::RestoreClipRegion; Current ClipRegionAttribute has a NULL path"); 02992 } 02993 else 02994 { 02995 // Update the RR's table of current attributes. 02996 RenderRegion::RestoreClipRegion(pClipAttr, Temp); 02997 } 02998 } 02999 03000 03001 /******************************************************************************************** 03002 03003 > virtual void AIEPSRenderRegion::SetTextAsShapes (BOOL shapes) 03004 03005 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 03006 Created: 8th November 2000 03007 Inputs: shapes - whether to export text as shapes (TRUE) or characters (FALSE) 03008 03009 Purpose: Sets the export TextAsShapes flag 03010 03011 See also: AIEPSRenderRegion::RenderChar(), TextStory::PreExportRender, 03012 TextStory::ExportRender 03013 03014 ********************************************************************************************/ 03015 03016 void AIEPSRenderRegion::SetTextAsShapes (BOOL shapes) 03017 { 03018 m_bTextAsShapes = shapes; 03019 } 03020 03021 03022 /******************************************************************************************** 03023 03024 > virtual BOOL AIEPSRenderRegion::GetTextAsShapes () 03025 03026 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 03027 Created: 8th November 2000 03028 Returns: BOOL - whether text is exported as shapes (TRUE) or characters (FALSE) 03029 03030 Purpose: Sets the export TextAsShapes flag 03031 03032 See also: AIEPSRenderRegion::GetTextAsShapes 03033 03034 ********************************************************************************************/ 03035 03036 BOOL AIEPSRenderRegion::GetTextAsShapes () 03037 { 03038 return m_bTextAsShapes; 03039 } 03040 03041 03042 /******************************************************************************************** 03043 03044 > virtual BOOL AIEPSRenderRegion::WriteNewLine () 03045 03046 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 03047 Created: 9th November 2000 03048 Returns: BOOL - whether the a new line was written successfully. 03049 03050 Purpose: Writes a new line to the output of text if text is exported as characters, 03051 does nothing if it's exported as shapes. 03052 03053 See also: EPSRenderRegion::WriteNewLine 03054 03055 ********************************************************************************************/ 03056 03057 BOOL AIEPSRenderRegion::WriteNewLine ( void ) 03058 { 03059 BOOL success; 03060 03061 // don't write any newlines if we're exporting text as shapes (cos' it could stuff up 03062 // the eps). 03063 if (GetTextAsShapes () == TRUE) 03064 { 03065 success = TRUE; 03066 } 03067 else 03068 { 03069 success = EPSRenderRegion::WriteNewLine (); 03070 } 03071 03072 return success; 03073 } 03074 03075 03076 03077 /******************************************************************************************** 03078 03079 > virtual void AIEPSRenderRegion::OutputFillRGBColour () 03080 03081 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 03082 Created: 18/12/00 03083 Purpose: Writes additional info to the file for RGB fill colours 03084 See also: EPSRenderRegion::OutputFillRGBColour 03085 03086 ********************************************************************************************/ 03087 03088 void AIEPSRenderRegion::OutputFillRGBColour () 03089 { 03090 // NOTE: We need to export any changes to the overflow text here, 03091 // as it's the last place we can catch the colour change. 03092 if (ExportingOnPath ()) 03093 { 03094 OverflowTextStartGap (); 03095 03096 // Colour values. 03097 INT32 red; 03098 INT32 green; 03099 INT32 blue; 03100 PColourCMYK CMYK; 03101 03102 // Assume no local context at present - used as a check to make sure that we 03103 // aren't exporting as seperations. 03104 ColourContext* pContext; 03105 ColourPlate* pSeparation; 03106 GetOutputColourPlate (COLOURMODEL_CMYK, &pContext, &pSeparation); 03107 03108 if (pSeparation==NULL) 03109 { 03110 // As expected, we ain't using seperations, so we can output as RGB. 03111 03112 // Get the current line colour in RGB values and print them out. 03113 RR_FILLCOLOUR().GetRGBValue (&red, &green, &blue); 03114 OverflowTextWriteSingleColour (red); 03115 OverflowTextWriteSingleColour (green); 03116 OverflowTextWriteSingleColour (blue); 03117 03118 if (RR_FILLCOLOUR().FindParentIndexedColour() == NULL) 03119 { 03120 // Unnamed colour - just add 'Xa' token 03121 OverflowTextWrite (_T("Xa\n")); 03122 } 03123 else 03124 { 03125 // Named colour - add Name, tint value, RGB flag and 'Xx' token 03126 OverflowTextWriteColourName (&(RR_FILLCOLOUR())); 03127 OverflowTextWrite (_T(" 0 1 Xx\n")); 03128 } 03129 } 03130 else 03131 { 03132 // Since we are seperating the colours, then use CMYK mode. 03133 03134 // Assume unnamed colour as 'g' grey fill operator does 03135 // not allow for custom greys. 03136 if (pSeparation->IsMonochrome()) 03137 { 03138 RR_FILLCOLOUR().GetCMYKValue(pContext, &CMYK); 03139 BYTE c = 0xFF - CMYK.Key; 03140 OverflowTextWriteSingleColour (c); 03141 OverflowTextWrite (_T("g\n")); 03142 } 03143 else 03144 { 03145 RR_FILLCOLOUR().GetCMYKValue(pContext, &CMYK); 03146 OverflowTextWriteColour (&CMYK); 03147 OverflowTextWrite (_T("x\n")); 03148 } 03149 } 03150 } 03151 03152 // Write out the usual EPS colour tokens. 03153 EPSRenderRegion::OutputFillRGBColour (); 03154 } 03155 03156 /******************************************************************************************** 03157 03158 > virtual void AIEPSRenderRegion::OutputFillCMYKColour () 03159 03160 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 03161 Created: 18/12/00 03162 Purpose: Writes additional info to the file for CMYK fill colours 03163 See also: EPSRenderRegion::OutputFillCMYKColour 03164 03165 ********************************************************************************************/ 03166 03167 void AIEPSRenderRegion::OutputFillCMYKColour () 03168 { 03169 // NOTE: We need to export any changes to the overflow text here, 03170 // as it's the last place we can catch the colour change. 03171 if (ExportingOnPath ()) 03172 { 03173 PColourCMYK CMYK; 03174 03175 OverflowTextStartGap (); 03176 03177 // Assume no local context at present 03178 ColourContext* pContext; 03179 ColourPlate* pSeparation; 03180 GetOutputColourPlate(COLOURMODEL_CMYK, &pContext, &pSeparation); 03181 03182 if (pSeparation==NULL) 03183 { 03184 // Get the current line colour in CMYK values, unless it's transparent 03185 // Print out colour component values. 03186 if (RR_FILLCOLOUR().FindParentIndexedColour() == NULL) 03187 { 03188 // Unnamed colour 03189 // retrieve the colour value 03190 RR_FILLCOLOUR().GetCMYKValue(pContext, &CMYK); 03191 OverflowTextWriteColour (&CMYK); 03192 OverflowTextWrite (_T("k\n")); 03193 } 03194 else 03195 { 03196 // Named colour 03197 OverflowTextWriteNamedColour (&(RR_FILLCOLOUR()), pContext); 03198 OverflowTextWrite (_T("x\n")); 03199 } 03200 } 03201 else 03202 { 03203 // Assume unnamed colour as 'g' grey fill operator does 03204 // not allow for custom greys. 03205 if (pSeparation->IsMonochrome()) 03206 { 03207 RR_FILLCOLOUR().GetCMYKValue(pContext, &CMYK); 03208 BYTE c = 0xFF - CMYK.Key; 03209 OverflowTextWriteSingleColour (c); 03210 OverflowTextWrite (_T("g\n")); 03211 } 03212 else 03213 { 03214 RR_FILLCOLOUR().GetCMYKValue(pContext, &CMYK); 03215 OverflowTextWriteColour (&CMYK); 03216 OverflowTextWrite (_T("x\n")); 03217 } 03218 } 03219 } 03220 03221 // Call the base class to write the ordinary info out 03222 EPSRenderRegion::OutputFillCMYKColour (); 03223 } 03224 03225 /******************************************************************************************** 03226 03227 > virtual void AIEPSRenderRegion::OutputStrokeRGBColour () 03228 03229 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 03230 Created: 18/12/00 03231 Purpose: Writes additional info to the file for RGB stroke colours 03232 See also: EPSRenderRegion::OutputStrokeRGBColour 03233 03234 ********************************************************************************************/ 03235 03236 void AIEPSRenderRegion::OutputStrokeRGBColour () 03237 { 03238 // NOTE: We need to export any changes to the overflow text here, 03239 // as it's the last place we can catch the colour change. 03240 if (ExportingOnPath ()) 03241 { 03242 OverflowTextStartGap (); 03243 03244 // Colour values. 03245 INT32 red; 03246 INT32 green; 03247 INT32 blue; 03248 PColourCMYK CMYK; 03249 03250 // Assume no local context at present - used as a check to make sure that we 03251 // aren't exporting as seperations. 03252 ColourContext* pContext; 03253 ColourPlate* pSeparation; 03254 GetOutputColourPlate (COLOURMODEL_CMYK, &pContext, &pSeparation); 03255 03256 if (pSeparation==NULL) 03257 { 03258 // As expected, we ain't using seperations, so we can output as RGB. 03259 03260 // Get the current line colour in RGB values and print them out. 03261 RR_STROKECOLOUR().GetRGBValue (&red, &green, &blue); 03262 OverflowTextWriteSingleColour (red); 03263 OverflowTextWriteSingleColour (green); 03264 OverflowTextWriteSingleColour (blue); 03265 03266 if (RR_STROKECOLOUR().FindParentIndexedColour() == NULL) 03267 { 03268 // Unnamed colour - just add 'XA' token 03269 OverflowTextWrite (_T("XA\n")); 03270 } 03271 else 03272 { 03273 // Named colour - add Name, tint value, RGB flag and 'XX' token 03274 OverflowTextWriteColourName (&(RR_STROKECOLOUR())); 03275 OverflowTextWrite (_T(" 0 1 XX\n")); 03276 } 03277 } 03278 else 03279 { 03280 // Since we are seperating the colours, then use CMYK mode. 03281 03282 // Assume unnamed colour as 'g' grey fill operator does 03283 // not allow for custom greys. 03284 if (pSeparation->IsMonochrome()) 03285 { 03286 RR_STROKECOLOUR().GetCMYKValue(pContext, &CMYK); 03287 BYTE c = 0xFF - CMYK.Key; 03288 OverflowTextWriteSingleColour (c); 03289 OverflowTextWrite (_T("G\n")); 03290 } 03291 else 03292 { 03293 RR_STROKECOLOUR().GetCMYKValue(pContext, &CMYK); 03294 OverflowTextWriteColour (&CMYK); 03295 OverflowTextWrite (_T("X\n")); 03296 } 03297 } 03298 } 03299 03300 // Call the base class to process the colour normally (i.e. to the EPS file itself) 03301 EPSRenderRegion::OutputStrokeRGBColour (); 03302 } 03303 03304 03305 /******************************************************************************************** 03306 03307 > virtual void AIEPSRenderRegion::OutputStrokeCMYKColour () 03308 03309 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 03310 Created: 18/12/00 03311 Purpose: Writes additional info to the file for CMYK fill colours 03312 See also: EPSRenderRegion::OutputFillCMYKColour 03313 03314 ********************************************************************************************/ 03315 03316 void AIEPSRenderRegion::OutputStrokeCMYKColour () 03317 { 03318 // Write out the colour to the overflow file if we're doing text on a path. 03319 if (ExportingOnPath ()) 03320 { 03321 PColourCMYK CMYK; 03322 OverflowTextStartGap (); 03323 03324 // Assume no local context at present 03325 ColourContext* pContext; 03326 ColourPlate* pSeparation; 03327 GetOutputColourPlate(COLOURMODEL_CMYK, &pContext, &pSeparation); 03328 03329 if (pSeparation==NULL) 03330 { 03331 // Get the current line colour in CMYK values, unless it's transparent 03332 // Print out colour component values. 03333 if (RR_STROKECOLOUR().FindParentIndexedColour() == NULL) 03334 { 03335 // Unnamed colour 03336 // retrieve the colour value 03337 RR_STROKECOLOUR().GetCMYKValue(pContext, &CMYK); 03338 OverflowTextWriteColour (&CMYK); 03339 OverflowTextWrite (_T("K\n")); 03340 } 03341 else 03342 { 03343 // Named colour 03344 OverflowTextWriteNamedColour (&(RR_STROKECOLOUR()), pContext); 03345 OverflowTextWrite (_T("X\n")); 03346 } 03347 } 03348 else 03349 { 03350 // Assume unnamed colour as 'g' grey fill operator does 03351 // not allow for custom greys. 03352 if (pSeparation->IsMonochrome()) 03353 { 03354 RR_STROKECOLOUR().GetCMYKValue(pContext, &CMYK); 03355 BYTE c = 0xFF - CMYK.Key; 03356 OverflowTextWriteSingleColour (c); 03357 OverflowTextWrite (_T("G\n")); 03358 } 03359 else 03360 { 03361 RR_STROKECOLOUR().GetCMYKValue(pContext, &CMYK); 03362 OverflowTextWriteColour (&CMYK); 03363 OverflowTextWrite (_T("X\n")); 03364 } 03365 } 03366 } 03367 03368 // Call the base class to write out the ordinary information 03369 EPSRenderRegion::OutputStrokeCMYKColour (); 03370 } 03371 03372 03373 /******************************************************************************************** 03374 03375 > virtual BOOL AIEPSRenderRegion::IsGradientFillValidForExport () 03376 03377 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 03378 Created: 15/01/01 03379 Purpose: Determines whether a particular fill can be used through the AI export 03380 See also: AIEPSRenderRegion::WriteGradientFills, AIEPSRenderRegion::WriteGradientUsage 03381 03382 ********************************************************************************************/ 03383 BOOL AIEPSRenderRegion::IsGradientFillValidForExport (FillGeometryAttribute * pFill) 03384 { 03385 BOOL acceptable = FALSE; 03386 03387 if ( pFill->IsAColourFill () && // Is it a colour fill? 03388 pFill->IsAGradFill () && // Is it a graduated fill? 03389 ! (pFill->IsAFractalFill ()) && // Is it not a fractal (clouds) fill? 03390 ! (pFill->IsANoiseFill ()) && // Is it not a fractal (plasma) fill? 03391 ! (pFill->IsABitmapFill ()) ) // Is it not a bitmap fill? 03392 { 03393 acceptable = TRUE; 03394 } 03395 else 03396 { 03397 acceptable = FALSE; 03398 } 03399 03400 return acceptable; 03401 } 03402 03403 03404 /******************************************************************************************** 03405 03406 > virtual BOOL AIEPSRenderRegion::IncludeGradientFill () 03407 03408 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 03409 Created: 5/2/2001 03410 Purpose: Stores information about a fill so that the same fill isn't declared multiple 03411 times. 03412 See also: AIEPSRenderRegion::WriteGradientFills, AIEPSRenderRegion::WriteGradientUsage, 03413 AIEPSRenderRegion::FindGradientInCache 03414 03415 ********************************************************************************************/ 03416 void AIEPSRenderRegion::IncludeGradientFill (FillGeometryAttribute * pFill, EFFECTTYPE effect) 03417 { 03418 ERROR3IF ((pFill == NULL), "AIEPSRenderRegion::IncludeGradientFill - Attempted to include NULL fill"); 03419 03420 ListFill * pNewList = NULL; 03421 FillGeometryAttribute * pNewFill = NULL; 03422 03423 // don't try and store the fill if it's invalid. 03424 if (pFill != NULL) 03425 { 03426 // Create a new FillGeometryAttribute, of the same type as the one passed in. 03427 03428 // NOTE: Four colour fills are derived from three colour fills, so they return 03429 // TRUE for IsAThreeColFill. This means that we need to process four colour 03430 // fills before we process three colour fills, otherwise all four colour fills 03431 // will become represented by three colour ones and the copy won't match the 03432 // original. 03433 03434 if (pFill->IsALinearFill ()) 03435 pNewFill = new LinearFillAttribute; 03436 else if (pFill->IsARadialFill ()) 03437 pNewFill = new RadialFillAttribute; 03438 else if (pFill->IsAConicalFill ()) 03439 pNewFill = new ConicalFillAttribute; 03440 else if (pFill->IsASquareFill ()) 03441 pNewFill = new SquareFillAttribute; 03442 else if (pFill->IsAFourColFill ()) 03443 pNewFill = new FourColFillAttribute; 03444 else if (pFill->IsAThreeColFill ()) 03445 pNewFill = new ThreeColFillAttribute; 03446 else if (pFill->IsAFractalFill ()) 03447 pNewFill = new FractalFillAttribute; 03448 else if (pFill->IsANoiseFill ()) 03449 pNewFill = new NoiseFillAttribute; 03450 else if (pFill->IsABitmapFill ()) 03451 pNewFill = new BitmapFillAttribute; 03452 else 03453 { 03454 pNewFill = NULL; 03455 ERROR3 ("AIEPSRenderRegion::IncludeGradientFill - Unrecognised fill included"); 03456 } 03457 03458 // Copy fill data if the the fill is recognised. There's no point in doing this if 03459 // we didn't recognise the fill, as the copy is bound to be different to the original. 03460 if (pNewFill != NULL) 03461 { 03462 // Copy all the relevant info. 03463 *(pNewFill) = *pFill; 03464 ERROR3IF ( !(*pFill == *pNewFill), "AIEPSRenderRegion::IncludeGradientFill - Copied fill doesn't match original"); 03465 03466 // New Fill is built, so add it into either the radial or linear list. 03467 if (pFill->IsARadialFill () || pFill->IsASquareFill ()) 03468 { 03469 pNewList = new ListFill (pNewFill, effect, m_pRadialGradList); 03470 m_pRadialGradList = pNewList; 03471 } 03472 else 03473 { 03474 pNewList = new ListFill (pNewFill, effect, m_pLinearGradList); 03475 m_pLinearGradList = pNewList; 03476 } 03477 } 03478 } 03479 } 03480 03481 /******************************************************************************************** 03482 03483 > virtual void AIEPSRenderRegion::ClearGradientCache () 03484 03485 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 03486 Created: 30/3/2001 03487 03488 Purpose: Deletes the list of stored gradient fills, that was built up using 03489 IncludeGradientFill 03490 03491 See also: AIEPSRenderRegion::IncludeGradientFill, 03492 AIEPSRenderRegion::FindGradientInCache 03493 03494 ********************************************************************************************/ 03495 void AIEPSRenderRegion::ClearGradientCache () 03496 { 03497 ListFill * pList = NULL; 03498 03499 // only clear it if there is a list to clear 03500 if (m_pLinearGradList) 03501 { 03502 // Cycle through the linear list deleting each item in turn. 03503 while (m_pLinearGradList != NULL) 03504 { 03505 pList = m_pLinearGradList->pNext; 03506 delete m_pLinearGradList; 03507 m_pLinearGradList = pList; 03508 } 03509 } 03510 03511 if (m_pRadialGradList) 03512 { 03513 // Cycle through the radial list deleting each item in turn. 03514 while (m_pRadialGradList != NULL) 03515 { 03516 pList = m_pRadialGradList->pNext; 03517 delete m_pRadialGradList; 03518 m_pRadialGradList = pList; 03519 } 03520 } 03521 } 03522 03523 03524 /******************************************************************************************** 03525 03526 > virtual INT32 AIEPSRenderRegion::FindGradientInCache () 03527 03528 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 03529 Created: 30/3/2001 03530 Returns the identifier of the found gradient fill, or 0 if it wasn't found 03531 03532 Purpose: Deletes the list of stored gradient fills, that was built up using 03533 IncludeGradientFill 03534 03535 See also: AIEPSRenderRegion::IncludeGradientFill, 03536 03537 ********************************************************************************************/ 03538 INT32 AIEPSRenderRegion::FindGradientInCache (FillGeometryAttribute * pFill, EFFECTTYPE effect) 03539 { 03540 INT32 id = 0; 03541 ListFill * pList = NULL; 03542 FillGeometryAttribute * pStoredFill = NULL; 03543 03544 double fillBias = 0; 03545 CProfileBiasGain fillProfile = pFill->GetProfile (); 03546 fillBias = (double) fillProfile.GetBias (); 03547 03548 // work out which list we want to search in. 03549 if (pFill->IsARadialFill () || pFill->IsASquareFill ()) 03550 pList = m_pRadialGradList; 03551 else 03552 pList = m_pLinearGradList; 03553 03554 // Cycle through all the fills until we find the one we want, or until we run out of fills 03555 while ((pList != NULL) && (id == 0)) 03556 { 03557 pStoredFill = pList->pFill; 03558 03559 // Because the start and end points for an Illustrator fill are not included in the 03560 // cache, we don't need to worry about them being the same. 03561 // 03562 // So, we set all the start and end points to be the same (since they would cause two 03563 // identical fills in different places, or of different lengths to be considered as 03564 // different otherwise). 03565 pStoredFill->SetStartPoint (pFill->GetStartPoint ()); 03566 pStoredFill->SetEndPoint (pFill->GetEndPoint ()); 03567 pStoredFill->SetEndPoint2 (pFill->GetEndPoint2 ()); 03568 pStoredFill->SetEndPoint3 (pFill->GetEndPoint3 ()); 03569 03570 // Now that the fill coords are the same, test to see whether they're 03571 // the same fill, or not. 03572 if (*pStoredFill == *pFill) 03573 { 03574 double storeBias = 0; 03575 CProfileBiasGain storeProfile = pStoredFill->GetProfile (); 03576 storeBias = (double) storeProfile.GetBias (); 03577 03578 if ((storeBias == fillBias) && (pList->effect == effect)) 03579 id = pList->id; 03580 } 03581 03582 // Check the next fill 03583 pList = pList->pNext; 03584 } 03585 03586 return id; 03587 } 03588 03589 /******************************************************************************************** 03590 03591 > virtual void AIEPSRenderRegion::BuildGradientCache (Node * pStartNode) 03592 03593 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 03594 Created: 20/3/2001 03595 Inputs: pStartNode - the node to start looking from. 03596 Purpose: Builds up a 'cache' of gradient fills. 03597 03598 See also: AIEPSRenderRegion::WriteGradientFills, AIEPSRenderRegion::WriteGradientDefinitions 03599 03600 ********************************************************************************************/ 03601 void AIEPSRenderRegion::BuildGradientCache (Node * pStartNode) 03602 { 03603 // Node * pChild = NULL; 03604 03605 // Set up the gradient searching system 03606 AIEPSGradientScanRenderRegion scanRR (this); 03607 scanRR.AttachDevice (DocView::GetSelected (), RenderDC, RenderView->GetDoc()->FindFirstSpread ()); 03608 scanRR.InitDevice (); 03609 03610 // Although the counting system does return the number of fills found, it can be got from 03611 // the scanner just as easily. 03612 BuildGradientCacheUsingScanner (pStartNode, &scanRR); 03613 } 03614 03615 /******************************************************************************************** 03616 03617 > virtual void AIEPSRenderRegion::BuildGradientCacheUsingScanner (Node * pNode, 03618 AIEPSGradientScanRenderRegion * pScan) 03619 03620 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 03621 Created: 20/3/2001 03622 Inputs: pNode - the node to start looking from. 03623 pScan - the scanner to use 03624 . 03625 Purpose: Builds up the gradient cache by scanning through each node under pNode for new 03626 fills 03627 03628 See also: AIEPSRenderRegion::WriteGradientFills, AIEPSRenderRegion::WriteGradientDefinitions 03629 03630 ********************************************************************************************/ 03631 void AIEPSRenderRegion::BuildGradientCacheUsingScanner (Node * pNode, AIEPSGradientScanRenderRegion * pScan) 03632 { 03633 // Children are rendered first, so that attributes will be applied to the right objects. 03634 Node * pChild = pNode->FindFirstChild (); 03635 while (pChild!=NULL) 03636 { 03637 BuildGradientCacheUsingScanner (pChild, pScan); 03638 pChild = pChild->FindNext (); 03639 } 03640 03641 // "Render" the node into the scanner. Currently, rendering is the only way to access 03642 // the intermediate steps (and their attributes) in blends, contours and some others, 03643 // so we need to use a special Render Region to catch the gradient (fill) information. 03644 // 03645 // NOTE: Since this uses the same system as the main render loop, it shouldn't be possible 03646 // for the gradient cache and the main file to become out of sync. Also, bevels and 03647 // shadows are excluded, as they are rendered as bitmaps in AI export. 03648 if (!pNode->IsABevel () && !pNode->IsAShadow ()) 03649 pNode->Render (pScan); 03650 } 03651 03652 /******************************************************************************************** 03653 03654 > virtual void AIEPSRenderRegion::WriteGradientCount () 03655 03656 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 03657 Created: 20/3/2001 03658 Purpose: Writes out the count of all the gradient fills in the Cache 03659 03660 See also: AIEPSRenderRegion::WriteGradientDefinitions, 03661 AIEPSRenderRegion::BuildGradientCache 03662 03663 ********************************************************************************************/ 03664 void AIEPSRenderRegion::WriteGradientCount () 03665 { 03666 KernelDC *pDC = (KernelDC*)CCDC::ConvertFromNativeDC(RenderDC); 03667 ListFill * pList = m_pLinearGradList; 03668 INT32 numFills = 0; 03669 03670 // Cycle through the gradient cache writing out fills as we go. 03671 // 03672 // First count the linear fills 03673 while (pList != NULL) 03674 { 03675 numFills ++; 03676 pList = pList->pNext; 03677 } 03678 03679 // Then count the radial fills. 03680 pList = m_pRadialGradList; 03681 while (pList != NULL) 03682 { 03683 numFills ++; 03684 pList = pList->pNext; 03685 } 03686 03687 // If there are any fills, then write the count out. 03688 if (numFills) 03689 { 03690 pDC->OutputValue (numFills); 03691 pDC->OutputToken (_T("Bn")); 03692 pDC->OutputNewLine (); 03693 } 03694 } 03695 03696 /******************************************************************************************** 03697 03698 > virtual void AIEPSRenderRegion::WriteGradientDefinitions () 03699 03700 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 03701 Created: 5/2/2001 03702 Purpose: Writes out the definitions of all the gradient fills in the Cache 03703 03704 See also: AIEPSRenderRegion::WriteGradientCount, 03705 AIEPSRenderRegion::BuildGradientCache 03706 03707 ********************************************************************************************/ 03708 void AIEPSRenderRegion::WriteGradientDefinitions () 03709 { 03710 ListFill * pList = NULL; 03711 FillGeometryAttribute * pFill = NULL; 03712 03713 // Cycle through the gradient cache writing out fills as we go. 03714 // 03715 // First do the linear list. 03716 pList = m_pLinearGradList; 03717 while (pList != NULL) 03718 { 03719 pFill = pList->pFill; 03720 WriteLinearFill ( pFill, pList->effect, pList->id ); 03721 pList = pList->pNext; 03722 } 03723 03724 // Then do the radial list. 03725 pList = m_pRadialGradList; 03726 while (pList != NULL) 03727 { 03728 pFill = pList->pFill; 03729 WriteRadialFill ( pFill, pList->effect, pList->id ); 03730 pList = pList->pNext; 03731 } 03732 } 03733 03734 03735 03736 CC_IMPLEMENT_DYNAMIC(AIEPSGradientScanRenderRegion, VectorFileRenderRegion) 03737 03738 03739 /******************************************************************************************** 03740 03741 > virtual void AIEPSGradientScanRenderRegion::AIEPSGradientScanRenderRegion (RenderRegion * pControllingRegion) 03742 03743 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 03744 Created: 5/2/2001 03745 Inputs: pControllingRegion - the AIEPSRenderRegion that created this.. 03746 Purpose: Used to scan the tree for gradient fills when exporting to AI EPS format. The 03747 objects are rendered into this region, which then stores the fills in a gradient 03748 cache. This is necessary, as objects such as blends only allow access to the 03749 intermediate steps when they are being rendered, and any gradient fills need 03750 to be cached in the AI file before proper rendering starts. 03751 03752 ********************************************************************************************/ 03753 AIEPSGradientScanRenderRegion::AIEPSGradientScanRenderRegion (RenderRegion * pControllingRegion) 03754 : VectorFileRenderRegion () 03755 { 03756 SetControllingRegion (pControllingRegion); 03757 03758 DocRect clipRect = pControllingRegion->GetClipRect (); 03759 SetClipRect (clipRect); 03760 } 03761 03762 /******************************************************************************************** 03763 03764 > virtual void AIEPSGradientScanRenderRegion::DrawPathToOutputDevice (Path *pPath, 03765 PathProcessor *pCaller = NULL, 03766 PathShape ShapePath = PATHSHAPE_PATH) 03767 03768 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 03769 Created: 5/2/2001 03770 Inputs: see RenderRegion::DrawPathToOutputDevice 03771 Purpose: Used to catch gradient fills on objects (mainly in blends, contours, brushes, 03772 and other objects which won't show up in the tree) so that they can be included 03773 properly in the caching system. 03774 03775 See also: RenderRegion::DrawPath 03776 03777 ********************************************************************************************/ 03778 void AIEPSGradientScanRenderRegion::DrawPathToOutputDevice (Path *DrawPath, PathShape shapePath /*= PATHSHAPE_PATH*/) 03779 { 03780 FillGeometryAttribute * pFill = (FillGeometryAttribute *) CurrentAttrs[ATTR_FILLGEOMETRY].pAttr; 03781 AIEPSRenderRegion * pControl = (AIEPSRenderRegion *) GetControllingRegion (); 03782 03783 EFFECTTYPE effect = GetFillEffect (); 03784 03785 // Write and store the fill info it's got a gradient fill. 03786 if (pControl->IsGradientFillValidForExport (pFill) && 03787 !pControl->FindGradientInCache (pFill, effect)) 03788 { 03789 // Store this fill - function takes a copy of the whole fill (not just the pointer), 03790 // so this is safe. 03791 pControl->IncludeGradientFill (pFill, effect); 03792 } 03793 03794 // Reset the fill to RGB. This is temp, so it will be deleted when it is no longer used. 03795 SetFillEffect (new FillEffectFadeAttribute, TRUE); 03796 } 03797 03798 /******************************************************************************************** 03799 03800 > virtual void AIEPSGradientScanRenderRegion::SetControllingRegion (RenderRegion * pControllingRegion) 03801 03802 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 03803 Created: 5/2/2001 03804 Inputs: the AIEPSRenderRegion that we need to send all the information to once we've 03805 scanned it in. 03806 Purpose: sets the controlling AIEPSRenderRegion. I.e. the one that needs to cache the 03807 gradient fills. 03808 03809 ********************************************************************************************/ 03810 void AIEPSGradientScanRenderRegion::SetControllingRegion (RenderRegion * pControllingRegion) 03811 { 03812 ERROR3IF (!pControllingRegion->IsKindOf (CC_RUNTIME_CLASS(AIEPSRenderRegion)), "AIEPSGradientScanRenderRegion::SetControllingRegion - controlling region is not an AIEPSRegion"); 03813 03814 m_pController = pControllingRegion; 03815 } 03816 03817 03818 03819 CC_IMPLEMENT_DYNAMIC (ListFill, CCObject); 03820 03821 /******************************************************************************************** 03822 03823 > ListFill::ListFill () 03824 03825 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 03826 Created: 30/3/2001 03827 Purpose: Constructor for a gradient fill holder, so it can be stored in a linked list 03828 cache. All variables (esp. the id) should be set before use. It is better to 03829 use the constructor below, as this will allocate id numbers uniquely. 03830 03831 ********************************************************************************************/ 03832 ListFill::ListFill () 03833 { 03834 pFill = NULL; 03835 pNext = NULL; 03836 id = 1; 03837 effect = EFFECT_RGB; 03838 } 03839 03840 /******************************************************************************************** 03841 03842 > ListFill::ListFill (FillGeometry * pNewFill, ListFill * pNewNext) 03843 03844 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 03845 Created: 30/3/2001 03846 Inputs: pNewFill - The fill to be stored. 03847 pNewNext - The next item in the list. 03848 Purpose: Constructor for a gradient fill holder, so it can be stored in a linked list 03849 cache. 03850 03851 ********************************************************************************************/ 03852 ListFill::ListFill (FillGeometryAttribute * pNewFill, EFFECTTYPE eff, ListFill * pNewNext) 03853 { 03854 pFill = pNewFill; 03855 effect = eff; 03856 03857 pNext = pNewNext; 03858 if(pNewNext) 03859 { 03860 id = pNewNext->id + 1; 03861 } 03862 else 03863 { 03864 id = 1; 03865 } 03866 } 03867 03868 /******************************************************************************************** 03869 03870 > ListFill::~ListFill () 03871 03872 Author: Chris_Gallimore (Xara Group Ltd) <camelotdev@xara.com> 03873 Created: 30/3/2001 03874 Purpose: Destructor for a ListFill item. This also cleans up the fill it contains (if 03875 any). 03876 03877 ********************************************************************************************/ 03878 ListFill::~ListFill () 03879 { 03880 if (pFill != NULL) 03881 delete pFill; 03882 } 03883 03884