psrndrgn.cpp

Go to the documentation of this file.
00001 // $Id: psrndrgn.cpp 1365 2006-06-25 20:29:01Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 
00099 // Render region for rendering to PostScript devices.
00100 
00101 /*
00102 */
00103 
00104 #include "camtypes.h"
00105 
00106 #include "psrndrgn.h"
00107 #include "psdc.h"
00108 #include "page.h"
00109 //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00110 //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00111 //#include "fillval.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00112 #include "textfuns.h"
00113 #include "devcolor.h"
00114 #include "camelot.h"
00115 #include "colplate.h"
00116 //#include "isetres.h"
00117 //#include "tim.h"
00118 #include "oilfiles.h"
00119 #include "unicdman.h"  //For MBCS support
00120 //#include "xaracms.h"
00121 //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00122 #include "printctl.h"
00123 //#include "view.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00124 
00125 DECLARE_SOURCE("$Revision: 1365 $");
00126 
00127 CC_IMPLEMENT_DYNAMIC(PrintPSRenderRegion, CamelotEPSRenderRegion)
00128 
00129 #define new CAM_DEBUG_NEW
00130 
00131 
00132 /********************************************************************************************
00133 
00134 >   PrintPSRenderRegion(DocRect ClipRect, Matrix ConvertMatrix, FIXED16 ViewScale)
00135 
00136     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00137     Created:    15/04/94
00138     Purpose:    Initialise a render region for printing PostScript.
00139     SeeAlso:    CamelotEPSRenderRegion::CamelotEPSRenderRegion
00140 
00141 ********************************************************************************************/
00142 
00143 PrintPSRenderRegion::PrintPSRenderRegion(DocRect ClipRect,
00144                                          Matrix ConvertMatrix, 
00145                                          FIXED16 ViewScale) 
00146     : CamelotEPSRenderRegion(ClipRect, ConvertMatrix, ViewScale)
00147 {
00148     // We're a printing render region.
00149     RenderFlags.Printing = TRUE;
00150 }
00151 
00152 /********************************************************************************************
00153 
00154 >   PrintPSRenderRegion::~PrintPSRenderRegion()
00155 
00156     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00157     Created:    15/04/94
00158     Purpose:    Delete the region, flushing the PostScript output DC beforehand.
00159     SeeAlso:    PSPrintDC::Flush
00160 
00161 ********************************************************************************************/
00162 
00163 PrintPSRenderRegion::~PrintPSRenderRegion()
00164 {
00165     PSPrintDC *pPSPrintDC = (PSPrintDC *) CCDC::ConvertFromNativeDC(RenderDC);
00166 
00167     // Restore OS context - just pretend we want to do some OS output
00168     pPSPrintDC->StartOSOutput();
00169 
00170     // Flush the DC
00171     pPSPrintDC->FlushDC();
00172 
00173     pPSPrintDC->EndOSOutput();
00174 
00175     // Karim 06/06/2000 - free the memory! (hope this doesn't blow up something else...)
00176     // AB: Don't do this. RenderRegion's destructor deletes RenderDC
00177     //  delete pPSPrintDC;
00178     //  pPSPrintDC = NULL;
00179 }
00180 
00181 
00182 
00183 /********************************************************************************************
00184 
00185 >   BOOL PrintPSRenderRegion::InitDevice()
00186 
00187     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00188     Created:    27/05/94
00189     Returns:    TRUE if the device context is initialised ok;
00190                 FALSE if not.
00191     Purpose:    Initialise the device specific mechanisms for this render region.
00192                 For a PrintPSRenderRegion we need to change the DC slightly  - we use the
00193                 existing RenderDC to make a PSPrintDC, which allows us to output PostScript
00194                 directly to the device.
00195     Errors:     Same as base class.
00196     SeeAlso:    RenderRegion::InitDevice
00197 
00198 ********************************************************************************************/
00199 
00200 BOOL PrintPSRenderRegion::InitDevice()
00201 {
00202     // Ensure the current DC is suitable for postscript rendering
00203 
00204     CCDC *pCCDC = CCDC::ConvertFromNativeDC( RenderDC );
00205     ERROR2IF(!pCCDC || !pCCDC->IsKindOf(CC_RUNTIME_CLASS(PSPrintDC)), FALSE, "Trying to InitDevice on a non-Postscript CCDC");
00206 
00207     PSPrintDC *pPSPrintDC = (PSPrintDC *) pCCDC;
00208 
00209     pPSPrintDC->SetDCTransforms(RenderMatrix, RenderView);
00210 
00211     // Call base class - note that unlike other InitDevice() implementations, we don't
00212     // call this as the very first thing in the function - this is because we need to switch
00213     // the DC beforehand, as seen above.
00214     if (!RenderRegion::InitDevice())
00215         return FALSE;
00216 
00217     // Find out what this region can do
00218     GetRenderRegionCaps(&Caps);
00219 
00220     // All ok
00221     return TRUE;
00222 }
00223 
00224 /********************************************************************************************
00225 
00226 >   BOOL PrintPSRenderRegion::StartRender()
00227 
00228     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00229     Created:    30/03/94
00230     Returns:    TRUE if worked, FALSE if failed.
00231     Purpose:    Prepare the render region for rendering (exporting).
00232     SeeAlso:    EPSRenderRegion::Initialise; EPSRenderRegion::StopRender
00233 
00234 ********************************************************************************************/
00235 
00236 BOOL PrintPSRenderRegion::StartRender()
00237 {
00238     // If we are being restarted, reinstate our dictionary on the stack
00239 //  BOOL Restarted = RenderFlags.ValidDevice;
00240 
00241     // Call base class first
00242     if (!EPSRenderRegion::StartRender())
00243         return FALSE;
00244 
00245     // Attach the DC to this render region.
00246     PSPrintDC *pPSPrintDC = (PSPrintDC *) CCDC::ConvertFromNativeDC(RenderDC);
00247     pPSPrintDC->SetDCTransforms(RenderMatrix, RenderView);
00248     pPSPrintDC->AttachRenderRegion(this);
00249 
00250     Initialise();
00251 
00252     return TRUE;
00253 }
00254 
00255 
00256 
00257 /********************************************************************************************
00258 
00259 >   BOOL PrintPSRenderRegion::StopRender()
00260 
00261     Author:     Will_Cowling (Xara Group Ltd) <camelotdev@xara.com>
00262     Created:    11/5/93
00263     Inputs:     RenderState is a Node* pointing at the current rendering node in the tree,
00264                 or NULL if all objects rendered.
00265     Purpose:    Stops the rendering of a OSRenderRegion, saving it's current renderstate so
00266                 that rendering can continue where it left off, later on.  If the RenderState
00267                 passed is NULL then the RenderRegion will be unlinked from the list and will
00268                 then delete itself.
00269     SeeAlso:    OSRenderRegion::StartRender()
00270 
00271 ********************************************************************************************/
00272 
00273 BOOL PrintPSRenderRegion::StopRender()
00274 {
00275     // Call base class
00276     BOOL bHaveRendered = EPSRenderRegion::StopRender();
00277 
00278     // Flush our buffered PostScript device context.
00279     PSPrintDC *pPSPrintDC = (PSPrintDC *) CCDC::ConvertFromNativeDC(RenderDC);
00280     pPSPrintDC->FlushDC();
00281 
00282     // Detach the DC from this render region.
00283     pPSPrintDC->DetachRenderRegion();
00284 
00285     return bHaveRendered;
00286 }
00287 
00288 /********************************************************************************************
00289 
00290 >   BOOL PrintPSRenderRegion::CloseDown()
00291 
00292     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00293     Created:    05/09/95
00294     Returns:    TRUE (always)
00295     Purpose:    Close down a PostScript render region - in fact we do nothing as the
00296                 printer driver is responsible for tidying up, and we will already have
00297                 cleared our dictionary from the dict stack in StopRender()
00298     SeeAlso:    CamelotEPSRenderRegion::StopRender
00299 
00300 ********************************************************************************************/
00301 
00302 BOOL PrintPSRenderRegion::CloseDown()
00303 {
00304     // Do nothing - the printer driver should do it all for us...
00305     return TRUE;
00306 }
00307 
00308 /********************************************************************************************
00309 
00310 >   virtual void PrintPSRenderRegion::ConditionalSuicide ( void )
00311 
00312     Author:     Graeme_Sutherland (Xara Group Ltd) <camelotdev@xara.com>
00313     Created:    24/2/00
00314     Inputs:     -
00315     Returns:    -
00316     Purpose:    Causes the object to commit suicide. This is to get around using a few
00317                 if IS_A calls elsewhere in Camelot.
00318 
00319 ********************************************************************************************/
00320 
00321 void PrintPSRenderRegion::ConditionalSuicide ( void )
00322 {
00323     // Delete the object.
00324     delete this;
00325 }
00326 
00327 /********************************************************************************************
00328 
00329 >   BOOL PrintPSRenderRegion::WriteProlog(KernelDC *pDC)
00330 
00331     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00332     Created:    24/04/95
00333     Inputs:     pDC - the device context to output to.
00334     Outputs:    -
00335     Returns:    TRUE if ok;
00336                 FALSE if error (e.g. file/disk error or printer driver error)
00337     Purpose:    Output any PostScript prolog for this render region.  For EPS and printing,
00338                 this means output of our PostScript rendering procedures; for Native
00339                 files we do nothing.
00340     SeeAlso:    EPSRenderRegion::WriteSetup
00341 
00342 ********************************************************************************************/
00343 
00344 BOOL PrintPSRenderRegion::WriteProlog(KernelDC *pDC)
00345 {
00346     // Call base class to output our dictionary
00347     if (!CamelotEPSRenderRegion::WriteProlog(pDC))
00348         // Error
00349         return FALSE;
00350 
00351     // All done
00352     return TRUE;
00353 }
00354 
00355 /********************************************************************************************
00356 
00357 >   BOOL PrintPSRenderRegion::WriteSetup(KernelDC *pDC)
00358 
00359     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00360     Created:    24/04/95
00361     Inputs:     pDC - the device context to output to.
00362     Outputs:    -
00363     Returns:    TRUE if ok;
00364                 FALSE if error (e.g. file/disk error or printer driver error)
00365     Purpose:    Output any PostScript setup for this render region.  For EPS and printing,
00366                 this means output of our PostScript code to initialise the context for
00367                 rendering; for Native files we do nothing.
00368     SeeAlso:    EPSRenderRegion::WriteSetup
00369 
00370 ********************************************************************************************/
00371 
00372 BOOL PrintPSRenderRegion::WriteSetup(KernelDC *pDC)
00373 {
00374     // Call base class to output our setup code
00375     if (!CamelotEPSRenderRegion::WriteSetup(pDC))
00376         // Error
00377         return FALSE;
00378 
00379     // All ok
00380     return TRUE;
00381 }
00382 
00383 
00384 /********************************************************************************************
00385 
00386 >   virtual BOOL PrintPSRenderRegion::WriteSepTables(KernelDC *pDC)
00387 
00388     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00389     Created:    19/06/96
00390     Inputs:     pDC - the device context to output to.
00391     Outputs:    -
00392     Returns:    TRUE if ok;
00393                 FALSE if error (e.g. file/disk error or printer driver error)
00394     Purpose:    Output the current set of device printer profiles as Postscript hex
00395                 arrays. Our Postscript prolog functions will use these arrays when
00396                 creating separations. (if we are not separating, we do nothing)
00397     SeeAlso:    
00398 
00399 ********************************************************************************************/
00400 
00401 BOOL PrintPSRenderRegion::WriteSepTables(KernelDC *pDC)
00402 {
00403     ColourContext* pContext;
00404     ColourPlate* pSeparation;
00405     GetOutputColourPlate(COLOURMODEL_CMYK, &pContext, &pSeparation);
00406 
00407     // Note, we return true to all but the token output
00408     // functions. We will terminate the output only if
00409     // we receive a disc failure.
00410     
00411     // do nothing if we are not separating
00412     if (pSeparation==NULL)
00413         return TRUE;
00414 
00415     // check that we've got a colour context attached to us.
00416     if (pContext==NULL)
00417     {
00418         ERROR3("There is no current colour context in this render region!");
00419         return TRUE;
00420     }
00421 
00422     // Whip out the physical tables we will use to separate.
00423     BYTE Table[5*256];
00424     if (!pContext->GetProfileTables(Table))
00425         return TRUE;
00426 
00427     // output cyan
00428     BOOL ok = pDC->OutputToken(_T("/ccurve ["));
00429     ok = ok && WriteSepTablesHelper(pDC, Table);
00430     ok = ok && pDC->OutputToken(_T("] def"));
00431     ok = ok && pDC->OutputNewLine();
00432 
00433     // output magenta
00434     ok = ok && pDC->OutputToken(_T("/mcurve ["));
00435     ok = ok && WriteSepTablesHelper(pDC, Table+256);
00436     ok = ok && pDC->OutputToken(_T("] def"));
00437     ok = ok && pDC->OutputNewLine();
00438 
00439     // output yellow
00440     ok = ok && pDC->OutputToken(_T("/ycurve ["));
00441     ok = ok && WriteSepTablesHelper(pDC, Table+512);
00442     ok = ok && pDC->OutputToken(_T("] def"));
00443     ok = ok && pDC->OutputNewLine();
00444 
00445     // output ucr
00446     ok = ok && pDC->OutputToken(_T("/ucurve ["));
00447     ok = ok && WriteSepTablesHelper(pDC, Table+768);
00448     ok = ok && pDC->OutputToken(_T("] def"));
00449     ok = ok && pDC->OutputNewLine();
00450 
00451     // output black generation
00452     ok = ok && pDC->OutputToken(_T("/bcurve ["));
00453     ok = ok && WriteSepTablesHelper(pDC, Table+1024);
00454     ok = ok && pDC->OutputToken(_T("] def"));
00455     ok = ok && pDC->OutputNewLine();
00456 
00457     // Enable separations
00458     ok = ok && pDC->OutputToken(_T("1 setseps"));
00459     ok = ok && pDC->OutputNewLine();
00460 
00461     // Is this a mono plate?
00462     BOOL mono = pSeparation->IsMonochrome();
00463 
00464     // find what type of separation plate we are using
00465     ColourPlateType Type = pSeparation->GetType();
00466     switch (Type)
00467     {
00468         case COLOURPLATE_CYAN:
00469             ok = ok && pDC->OutputToken(_T("v_cpcy setplate"));
00470             ok = ok && pDC->OutputNewLine();
00471         break;
00472         case COLOURPLATE_MAGENTA:
00473             ok = ok && pDC->OutputToken(_T("v_cpmg setplate"));
00474             ok = ok && pDC->OutputNewLine();
00475         break;
00476         case COLOURPLATE_YELLOW:
00477             ok = ok && pDC->OutputToken(_T("v_cpyl setplate"));
00478             ok = ok && pDC->OutputNewLine();
00479         break;
00480         case COLOURPLATE_KEY:
00481             ok = ok && pDC->OutputToken(_T("v_cpky setplate"));
00482             ok = ok && pDC->OutputNewLine();
00483         break;
00484         case COLOURPLATE_SPOT:
00485             // Force mono to be true here, all spot colour will
00486             // be going out as weights of key, and hence are
00487             // really the same as mono c,m,y,k
00488             mono=TRUE;
00489         break;
00490         default:
00491             ERROR3("What kind of a plate is that?");
00492             break;
00493 
00494     }
00495 
00496     // Output the mono setting. This determins whether our postscript
00497     // colour fill and stroke functions will set colour using the
00498     // setgray function or setcmyk
00499     if (mono)
00500         ok = ok && pDC->OutputToken(_T("1 setmono"));
00501     else
00502         ok = ok && pDC->OutputToken(_T("0 setmono"));
00503     ok = ok && pDC->OutputNewLine();
00504 
00505     // All ok
00506     return ok;
00507 }
00508 
00509 
00510 /********************************************************************************************
00511 
00512 >   BOOL PrintPSRenderRegion::WriteSepTablesHelper(KernelDC *pDC, BYTE* Table)
00513 
00514     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00515     Created:    19/06/96
00516     Inputs:     pDC - the device context to output to.
00517                 Table = a pointer to a 256 byte entry table
00518     Outputs:    -
00519     Returns:    TRUE if ok;
00520                 FALSE if error (e.g. file/disk error or printer driver error)
00521     Purpose:    Output the table of 256 values to the output stream
00522 
00523 ********************************************************************************************/
00524 
00525 BOOL PrintPSRenderRegion::WriteSepTablesHelper(KernelDC *pDC, BYTE* Table)
00526 {
00527     BOOL ok;
00528     UINT32 val;
00529     for (INT32 i=0; i<256; i++)
00530     {
00531         val = (UINT32) (Table[i]);
00532         ok = pDC->OutputValue(val);
00533         if (!ok)
00534             return FALSE;
00535     }
00536     return TRUE;
00537 }
00538 
00539 
00540 
00541 /********************************************************************************************
00542 
00543 >   BOOL PrintPSRenderRegion::WritePlateName(KernelDC *pDC)
00544 
00545     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00546     Created:    24/06/96
00547     Inputs:     pDC - the device context to output to.
00548     Outputs:    -
00549     Returns:    TRUE if ok;
00550                 FALSE if error (e.g. file/disk error or printer driver error)
00551     Purpose:    Output the current plate name for this print separation, if there is one.
00552 
00553 ********************************************************************************************/
00554 
00555 BOOL PrintPSRenderRegion::WritePlateName(KernelDC *pDC)
00556 {
00557     ColourPlate* pSeparation;
00558     GetOutputColourPlate(COLOURMODEL_CMYK, NULL, &pSeparation);
00559     
00560     // do nothing if we are not separating
00561     if (pSeparation==NULL)
00562         return TRUE;
00563 
00564     // Get and output the plate name, cheers
00565     String_64 platename;
00566     pSeparation->GetDescription(&platename);
00567     TCHAR* pPlate = (TCHAR*)platename;
00568     // ok output the textural name
00569     BOOL ok = pDC->OutputToken(_T("%%PlateColor :"));
00570     ok = ok && pDC->OutputToken(pPlate);
00571     ok = ok && pDC->OutputNewLine();
00572 
00573     return ok;
00574 }
00575 
00576 
00577 
00578 
00579 /********************************************************************************************
00580 
00581 >   BOOL PrintPSRenderRegion::WritePlateScreen(KernelDC *pDC)
00582 
00583     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00584     Created:    24/06/96
00585     Inputs:     pDC - the device context to output to.
00586     Outputs:    -
00587     Returns:    TRUE if ok;
00588                 FALSE if error (e.g. file/disk error or printer driver error)
00589     Purpose:    Output the setscreen function for this plate.
00590 
00591 ********************************************************************************************/
00592 
00593 BOOL PrintPSRenderRegion::WritePlateScreen(KernelDC *pDC)
00594 {
00595     PrintControl *pPrintCtl=NULL;
00596     View *pView = GetRenderView();
00597     if (pView) pPrintCtl = pView->GetPrintControl();
00598     if (!pPrintCtl)
00599         return TRUE;
00600 
00601     // Get a pointer to the typeset info structure
00602     TypesetInfo *pInfo = pPrintCtl->GetTypesetInfo();
00603     
00604     double ang,freq;
00605     String_256 ScreenName;
00606     ScreenType scrtype;
00607 
00608     // If separating then interogate the current plate
00609     if (pInfo->AreSeparating())
00610     {
00611         ColourPlate* pSeparation;
00612         GetOutputColourPlate(COLOURMODEL_CMYK, NULL, &pSeparation);
00613         
00614         // do nothing if we are not separating
00615         if (pSeparation==NULL)
00616             return TRUE;
00617 
00618         // Make sure screening is on in this plate
00619         if (!pSeparation->ActiveScreening())
00620             return TRUE;
00621 
00622         // Get the screen type if enabled.
00623         scrtype = pSeparation->GetScreenFunction();
00624         if (scrtype==SCRTYPE_NONE)
00625             return TRUE;
00626 
00627         // ok we can get the angle and frequency
00628         ang = pSeparation->GetScreenAngle();
00629         freq = pSeparation->GetScreenFrequency();
00630     }
00631     else
00632     {
00633         // Is screening off?
00634         if (!pInfo->AreScreening())
00635             return TRUE;
00636 
00637         scrtype = pInfo->GetScreenFunction();
00638         if (scrtype==SCRTYPE_NONE)
00639             return TRUE;
00640 
00641         ang = 45.0;
00642         freq = pInfo->GetDefaultScreenFrequency();
00643     }
00644 
00645     // read the name of this screen
00646     pInfo->GetScreenName(scrtype, &ScreenName);
00647         
00648     String_256 fred;
00649     fred += String_8(_T("{"));
00650     fred += ScreenName;
00651     fred += String_8(_T("}"));
00652 
00653     // ok output 'freq ang screenfunc setscreen'
00654     BOOL ok = pDC->OutputFloat(freq, 4);
00655     ok = ok && pDC->OutputFloat(ang, 4);
00656     ok = ok && pDC->OutputToken(fred);
00657     ok = ok && pDC->OutputToken(_T("setscreen"));
00658     ok = ok && pDC->OutputNewLine();
00659 
00660     return ok;
00661 }
00662 
00663 
00664 
00665 /********************************************************************************************
00666 
00667 >   BOOL PrintPSRenderRegion::WriteSepFunctions(KernelDC *pDC)
00668 
00669     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00670     Created:    26/06/96
00671     Inputs:     pDC - the device context to output to.
00672     Outputs:    -
00673     Returns:    TRUE if ok;
00674                 FALSE if error (e.g. file/disk error or printer driver error)
00675     Purpose:    Output the setscreen functions file for this separation.
00676     SeeAlso:    WriteProlog
00677 
00678 ********************************************************************************************/
00679 
00680 BOOL PrintPSRenderRegion::WriteSepFunctions(KernelDC *pDC)
00681 {
00682     PrintControl *pPrintCtl=NULL;
00683     View *pView = GetRenderView();
00684     if (pView) pPrintCtl = pView->GetPrintControl();
00685     if (!pPrintCtl)
00686         return TRUE;
00687 
00688     // Get a pointer to the typeset info structure
00689     TypesetInfo *pInfo = pPrintCtl->GetTypesetInfo();
00690     // Is screening off?
00691     if (!pInfo->AreScreening())
00692         return TRUE;
00693 
00694     // Get hold of our PostScript prolog resource...
00695     CCResTextFile ScreenFile;
00696 
00697     // Open the file
00698     if (!ScreenFile.open(_R(IDM_PS_SPOTFUNCS), _R(IDT_PS_RES)))
00699     {
00700         // Failed to open the file...
00701         ERROR2(FALSE, "Could not get at PostScript resource!");
00702     } 
00703 
00704     // Read each line from the file and output it to the DC.
00705     String_256 LineBuf;
00706     TCHAR *pBuf = (TCHAR *) LineBuf;
00707     
00708     while (!ScreenFile.eof())
00709     {
00710         // Copy this line to output.
00711         ScreenFile.read(&LineBuf);
00712         pDC->OutputTCHARAsChar(pBuf, LineBuf.Length());
00713         pDC->OutputNewLine();
00714     }
00715     
00716     // All done
00717     ScreenFile.close();
00718 
00719     return TRUE;
00720 }
00721 
00722 
00723 
00724 
00725 /********************************************************************************************
00726 
00727 >   BOOL PrintPSRenderRegion::PushClipRegion(KernelDC *pDC, const DocRect& Rect)
00728 
00729     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00730     Created:    02/09/96
00731     Inputs:     pDC - the device context to output to.
00732                 Rect - the clipping rect to create.
00733     Outputs:    -
00734     Returns:    TRUE if ok;
00735                 FALSE if error (e.g. file/disk error or printer driver error)
00736     Purpose:    Stack the PostScript clipping rectangle. The clipping rectangle will be
00737                 active until our context is reset.
00738     SeeAlso:    PopClipRegion
00739 
00740 ********************************************************************************************/
00741 
00742 BOOL PrintPSRenderRegion::PushClipRegion(KernelDC *pDC, const DocRect& Rect)
00743 {
00744     BOOL ok = pDC->OutputToken(_T("gs"));
00745     ok = ok && pDC->OutputNewLine();
00746     ok = ok && WriteClipRegion(pDC,Rect);
00747     return ok;
00748 }
00749 
00750 
00751 /********************************************************************************************
00752 
00753 >   BOOL PrintPSRenderRegion::PopClipRegion(KernelDC *pDC)
00754 
00755     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00756     Created:    02/09/96
00757     Inputs:     pDC - the device context to output to.
00758     Outputs:    -
00759     Returns:    TRUE if ok;
00760                 FALSE if error (e.g. file/disk error or printer driver error)
00761     Purpose:    Unstack the current PostScript clip region. We simply pop the graphics state
00762                 here to return to the previous clipping region.
00763     SeeAlso:    PushClipRegion
00764 
00765 ********************************************************************************************/
00766 
00767 BOOL PrintPSRenderRegion::PopClipRegion(KernelDC *pDC)
00768 {
00769     BOOL ok = pDC->OutputToken(_T("gr"));
00770     ok = ok && pDC->OutputNewLine();
00771     return ok;
00772 }
00773 
00774 
00775 
00776 
00777 /********************************************************************************************
00778 
00779 >   BOOL PrintPSRenderRegion::WriteClipRegion(KernelDC *pDC, const DocRect& Rect)
00780 
00781     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00782     Created:    02/09/96
00783     Inputs:     pDC - the device context to output to.
00784                 Rect - the clipping rect to create.
00785     Outputs:    -
00786     Returns:    TRUE if ok;
00787                 FALSE if error (e.g. file/disk error or printer driver error)
00788     Purpose:    Set up a PostScript clipping rectangle. The clipping rectangle will be
00789                 active until our context is reset.
00790 
00791 ********************************************************************************************/
00792 
00793 BOOL PrintPSRenderRegion::WriteClipRegion(KernelDC *pDC, const DocRect& Rect)
00794 {
00795     if (!Rect.IsValid() || Rect.IsEmpty())
00796         return TRUE;
00797 
00798     DocCoord c0,c1;
00799     c0=Rect.lo;
00800     c1=Rect.hi;
00801     BOOL ok = pDC->OutputCoord(c0);
00802     ok = ok && pDC->OutputCoord(c1);
00803     ok = ok && pDC->OutputToken(TEXT("Cp"));
00804     ok = ok && pDC->OutputNewLine();
00805 
00806     return ok;
00807 }
00808 
00809 
00810 /********************************************************************************************
00811 
00812 >   BOOL PrintPSRenderRegion::WritePhotoNegative(KernelDC *pDC)
00813 
00814     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00815     Created:    29/08/96
00816     Inputs:     pDC - the device context to output to.
00817     Outputs:    -
00818     Returns:    TRUE if ok;
00819                 FALSE if error (e.g. file/disk error or printer driver error)
00820     Purpose:    Start photo negative rendering. All rendering will be photo-negated.
00821 
00822 ********************************************************************************************/
00823 
00824 BOOL PrintPSRenderRegion::WritePhotoNegative(KernelDC *pDC)
00825 {
00826 /*
00827     ColourPlate* pSeparation;
00828     GetOutputColourPlate(COLOURMODEL_CMYK, NULL, &pSeparation);
00829 
00830     // do nothing if we are not separating
00831     if (pSeparation==NULL)
00832         return TRUE;
00833 
00834     // if this plate says negative lets do it
00835     if (pSeparation->IsEPSNegative())
00836         return WriteSetTransfer(pDC);
00837 */
00838     // Find the print control structure.
00839     PrintControl *pControl = GetRenderView()->GetPrintControl();
00840     if (pControl)
00841     {
00842         TypesetInfo *pTypeset = pControl->GetTypesetInfo();
00843         if (pTypeset && pTypeset->PrintPhotoNegative())
00844             return WriteSetTransfer(pDC);
00845     }
00846 
00847     return TRUE;
00848 }
00849 
00850 BOOL PrintPSRenderRegion::WriteSetTransfer(KernelDC *pDC)
00851 {
00852     BOOL ok = pDC->OutputToken(_T("{1 exch sub} settransfer"));
00853          ok = ok && pDC->OutputNewLine();
00854     return ok;
00855 }
00856 
00857 
00858 /********************************************************************************************
00859 
00860 >   BOOL PrintPSRenderRegion::WriteRenderPaper(KernelDC *pDC)
00861 
00862     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00863     Created:    29/08/96
00864     Inputs:     pDC - the device context to output to.
00865     Outputs:    -
00866     Returns:    TRUE if ok;
00867                 FALSE if error (e.g. file/disk error or printer driver error)
00868     Purpose:    Fill the entire renderable area with white
00869 
00870 ********************************************************************************************/
00871 
00872 BOOL PrintPSRenderRegion::WriteRenderPaper(KernelDC *pDC)
00873 {
00874 /*
00875     ColourPlate* pSeparation;
00876     GetOutputColourPlate(COLOURMODEL_CMYK, NULL, &pSeparation);
00877 
00878     // do nothing if we are not separating
00879     if (pSeparation==NULL)
00880         return TRUE;
00881 
00882     // if this plate says negative lets do it
00883     if (pSeparation->IsEPSNegative())
00884         return WriteFillPaper(pDC);
00885 */
00886     // Find the print control structure.
00887     PrintControl *pControl = GetRenderView()->GetPrintControl();
00888     if (pControl)
00889     {
00890         TypesetInfo *pTypeset = pControl->GetTypesetInfo();
00891         if (pTypeset && pTypeset->PrintPhotoNegative())
00892             return WriteFillPaper(pDC);
00893     }
00894 
00895     return TRUE;
00896 }
00897 
00898 
00899 BOOL PrintPSRenderRegion::WriteFillPaper(KernelDC *pDC)
00900 {
00901     BOOL ok = pDC->OutputToken(_T("gsave clippath 1 setgray fill grestore"));
00902          ok = ok && pDC->OutputNewLine();
00903     return ok;
00904 }
00905 
00906 
00907 
00908 
00909 
00910 
00911 
00912 /********************************************************************************************
00913 
00914 >   BOOL PrintPSRenderRegion::OutputPSHeader()
00915 
00916     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com> & JustinF
00917     Created:    04/29/95
00918     Returns:    TRUE if ok;
00919                 FALSE if file/printer error occured.
00920     Purpose:    Output the PostScript header that Camelot needs in order for its PostScript
00921                 code to work.  NB. the original version of this function has been commented
00922                 out and moved to the end of this source file.
00923 
00924 ********************************************************************************************/
00925 
00926 BOOL PrintPSRenderRegion::OutputPSHeader()
00927 {
00928 PORTNOTE("printing", "Don't output strange rectangles")
00929 #ifndef EXCLUDE_FROM_XARALX
00930     // If running under Win95 or Win31, but not any flavour of WinNT, then begin with some
00931     // fake GDI output to force the buggy Postscript driver to flush its output buffer.
00932     if (IsWin32s())
00933     {
00934         // Justin says: please *don't* change this to *anything* else until you've
00935         // spoken to me or Phil.
00936         CBrush br;
00937         br.CreateStockObject(WHITE_BRUSH);
00938         CBrush* pOldBr = RenderDC->SelectObject(&br);
00939 
00940         CPen pn;
00941         pn.CreateStockObject(WHITE_PEN);
00942         CPen* pOldPn = RenderDC->SelectObject(&pn);
00943 
00944         // Draw a tiny white rectangle with a white outline.
00945         TRACEUSER( "JustinF", _T("Postscript pixel fix in action ...\n"));
00946         RenderDC->Rectangle(&CRect(0, 0, 1, 1));
00947 
00948         RenderDC->SelectObject(pOldPn);
00949         RenderDC->SelectObject(pOldBr);
00950     }
00951 #endif
00952 
00953     // Use the current DC to make a new one that is suitable for rendering
00954     // PostScript to directly.
00955     PSPrintDC* pPSPrintDC = new PSPrintDC(RenderDC);
00956     if (pPSPrintDC == NULL) return FALSE;
00957 
00958     // Set up this - don't need it but the DC might get upset if it has no view.
00959     RenderDC = pPSPrintDC->GetDC();
00960     pPSPrintDC->SetDCTransforms(RenderMatrix, RenderView);
00961 
00962     // Tell the DC (i) we want to do OS output - this prevents it from outputting a
00963     // reference to our dictionary before we have defined it (because it's trying to
00964     // set up the PostScript C ready for Camelot EPS commands); (ii) we have finished
00965     // doing our 'OS' output. :-)
00966     return pPSPrintDC->StartOSOutput() && pPSPrintDC->EndOSOutput();
00967 }
00968 
00969 
00970 
00971 /********************************************************************************************
00972 
00973 >   void PrintPSRenderRegion::Initialise()
00974 
00975     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00976     Created:    04/29/95
00977     Purpose:    Over-rides the EPS header output code - we don't want to do this everytime
00978                 we start a PostScript render region, only every time we start a print job.
00979     SeeAlso:    PrintPSRenderRegion::OutputPSHeader
00980 
00981 ********************************************************************************************/
00982 
00983 void PrintPSRenderRegion::Initialise()
00984 {
00985     // Set up render region
00986     InitClipping();
00987     InitAttributes();
00988 }
00989 
00990 /********************************************************************************************
00991 
00992 >   void PrintPSRenderRegion::DeInitialise()
00993 
00994     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
00995     Created:    04/29/95
00996     Purpose:    Over-rides the EPS trailer output code - we don't want to do this everytime
00997                 we delete a PostScript render region - the printer driver should do it for 
00998                 us.
00999     SeeAlso:    PrintPSRenderRegion::OutputPSHeader
01000 
01001 ********************************************************************************************/
01002 
01003 void PrintPSRenderRegion::DeInitialise()
01004 {
01005     // Clear up
01006     DeInitAttributes();
01007 }
01008 
01009 
01010 BOOL PrintPSRenderRegion::InitPSDevice(CNativeDC *pDC, PrintView *pPrintView)
01011 {
01012     // Make a new PSRenderRegion, and use it to output out PostScript header.
01013     DocRect DummyRect;
01014     Matrix DummyMatrix;
01015     FIXED16 DummyScale(0);
01016     PrintPSRenderRegion *pRegion = new PrintPSRenderRegion(DummyRect, DummyMatrix, DummyScale);
01017     if (pRegion == NULL)
01018         return FALSE;
01019 
01020     // Attach new region to the DC.
01021     pRegion->AttachDevice((View *) pPrintView, pDC, Document::GetSelectedSpread());
01022 
01023     // Output the header
01024     if (!pRegion->OutputPSHeader())
01025         return FALSE;
01026 
01027     delete pRegion;
01028 
01029     return TRUE;
01030 }
01031 
01032 
01033 /********************************************************************************************
01034 
01035 >   BOOL PrintPSRenderRegion::RenderChar(WCHAR ch, Matrix* pMatrix)
01036 
01037     Author:     Tim_Browse (Xara Group Ltd) <camelotdev@xara.com>
01038     Created:    30/4/95
01039     Inputs:     ch      - unicode value of char
01040                 pMatrix - matrix specifying transforms to place char correctly in document
01041     Returns:    FALSE if fails
01042     Purpose:    Render a character,
01043                 using the specified transform and current attributes in the render region.
01044 
01045 ********************************************************************************************/
01046 
01047 BOOL PrintPSRenderRegion::RenderChar(WCHAR ch, Matrix* pMatrix)
01048 {
01049 PORTNOTE("printing", "Disabled PS text rendering")
01050 #ifndef EXCLUDE_FROM_XARALX
01051     // If it is stroked or not simple flat fill, or not a standard ASCII character then we 
01052     //  must do this as paths.
01053     BOOL FlatFill = IS_A(CurrentAttrs[ATTR_FILLGEOMETRY].pAttr, FlatFillAttribute);
01054 
01055     if (!FlatFill || 
01056         !RR_STROKECOLOUR().IsTransparent() ||
01057         (FlatFill & RR_FILLCOLOUR().IsTransparent()) ||
01058         (ch > 255))
01059         return RenderRegion::RenderChar(ch, pMatrix);
01060 
01061     // Check for emulsion down printing
01062     PrintControl *pPrintCtl;
01063     View *pView = GetRenderView();
01064     if (pView && (pPrintCtl=pView->GetPrintControl())) 
01065     { 
01066         if (pPrintCtl->GetTypesetInfo()->PrintEmulsionDown())
01067         return RenderRegion::RenderChar(ch, pMatrix);
01068     }
01069 
01070     // get overall matrix - attribute matrix concatenated with given matrix if supplied
01071     Matrix matrix;
01072     if (GetCharAttributeMatrix(&matrix)==FALSE)
01073         return FALSE;
01074     if (pMatrix)
01075         matrix*=*pMatrix;
01076 
01077     // Can we do this using a GDI font?
01078     // We can if the matrix only specifies scaling and translation
01079     FIXED16 abcd[4];
01080     INT32   ef[2];
01081     matrix.GetComponents(abcd, ef);
01082 
01083     // GDI can't do y-axis flips, so we do it as shapes if this is detected (and x-axis
01084     // flips, for consistency).
01085     if ((abcd[0] < FIXED16(0)) || (abcd[3] < FIXED16(0)))
01086     {
01087         // Flipped in one or both axes - render as a path.
01088         return RenderRegion::RenderChar(ch, pMatrix);
01089     }
01090 
01091     // Work out how complex the transformation is.
01092     FIXED16 ScaleX, ScaleY;
01093     ANGLE   Rotation, Shear;
01094 
01095     if ((abcd[1] == FIXED16(0)) && (abcd[2] == FIXED16(0)))
01096     {
01097         // Simple scaling transformation.
01098         ScaleX   = abcd[0];
01099         ScaleY   = abcd[3];
01100         Rotation = FIXED16(0);
01101         Shear    = FIXED16(0);
01102     }
01103     else
01104     {
01105         // Decompose the matrix to find out how complex it is.
01106         // Pass in NULL for translation as we already know it is in 'ef'.
01107         FIXED16 Aspect;
01108         BOOL Result = matrix.Decompose(&ScaleY, &Aspect, &Rotation, &Shear, NULL);
01109 
01110         if (!Result || (Shear != FIXED16(0)))
01111             // Either there was a problem, or the character is sheared, in which case
01112             // we can't do it with GDI.
01113             return RenderRegion::RenderChar(ch, pMatrix);
01114 
01115         // Set up the ScaleX based on the aspect ratio
01116         ScaleX = ScaleY * Aspect;
01117     }
01118 
01119     // Check for sideways printing - if the render matrix has rotation, then we are
01120     // printing at 270 degrees rotation, so adjust the rotation accordingly.
01121 #if 1
01122     FIXED16 RenderABCD[4];
01123     INT32   RenderEF[2];
01124     RenderMatrix.GetComponents(RenderABCD, RenderEF);
01125     if ((RenderABCD[1] != FIXED16(0)) || (RenderABCD[2] != FIXED16(0)))
01126         // Rotate by 270 degrees (angle is in radians)
01127         Rotation += FIXED16(1.5 * PI);
01128 #endif
01129     // Simple transformation - we can do this with a GDI font.
01130     PSPrintDC *pPSDC = (PSPrintDC *) CCDC::ConvertFromNativeDC(RenderDC);
01131     if (!pPSDC->StartOSOutput())
01132         return FALSE;
01133 
01134 
01135     // Work out required width and height of the font
01136     MILLIPOINT ReferenceSize = TextManager::GetDefaultHeight();
01137     MILLIPOINT Width  = ReferenceSize * ScaleX;
01138     MILLIPOINT Height = ReferenceSize * ScaleY;
01139 
01140     if (!pPSDC->SelectNewFont(RR_TXTFONTTYPEFACE(), RR_TXTBOLD(), RR_TXTITALIC(),
01141                        Width, Height, Rotation))
01142     {
01143         // Could not select font (maybe because device can't rotate fonts)
01144         pPSDC->EndOSOutput();
01145         return RenderRegion::RenderChar(ch, pMatrix);
01146     }
01147 
01148     // Ok, so the OS might screw up our attributes/graphics state, so we force
01149     // attributes to be output specifically the next time we do some Camelot output.
01150     ResetOutputAttributes();
01151 
01152     // First, set up the text attributes that are not encoded in the font.
01153     UINT32 OldTextAlign = RenderDC->SetTextAlign(TA_BASELINE);
01154     INT32 OldBKMode = RenderDC->SetBkMode(TRANSPARENT);
01155     COLORREF TextColour = ConvertColourToScreenWord(CurrentColContext, &RR_FILLCOLOUR());
01156 
01157     // check for completely black text
01158     if (TextColour==0 && IsWindowsNT())
01159     {
01160         // All components are 0!
01161         // BODGE TEXT - The driver decides its a good idea not to ouput
01162         //              0 g when black is (it thinks) already set.
01163         //              Hence we get the colour previously set. So, we
01164         //              output a dummy black here, which it doesn't ignore.
01165         //              Done by Mike (04/07/96). It would be nice to find
01166         //              out why the driver is ignoring us but time is fleating
01167         
01168         TextColour = (DWORD)(0x00010101);
01169         
01170         /*
01171         This really is majorly dangerous! (Read comments in OutputDirect for why)
01172         We could use the following but we will destroy the graphics state of
01173         gdi for colour. ie if GDI does a 'save char col fill restore' we will 
01174         end up doing this
01175         col save char col fill restore
01176         and will have mucked up the graph state.
01177 
01178         String_32 LineBuf("0 g");
01179         LineBuf += '\n';
01180         TCHAR *pBuf = (TCHAR *) LineBuf;
01181         pPSDC->OutputTCHARAsChar(pBuf, LineBuf.Length());
01182         */
01183     }
01184 
01185     COLORREF OldTextColour = RenderDC->SetTextColor(TextColour);
01186 
01187     // Render the character in the specified position
01188     DocCoord DocPos(ef[0], ef[1]);
01189 
01190     // Convert DocCoord to WinCoord
01191     OilCoord OilPoint;
01192     RenderMatrix.GetComponents(abcd, ef);
01193     OilPoint.x = MatrixCalc(abcd[0], DocPos.x, abcd[2], DocPos.y) + ef[0];
01194     OilPoint.y = MatrixCalc(abcd[1], DocPos.x, abcd[3], DocPos.y) + ef[1];
01195     WinCoord WinPos = OilPoint.ToWin(RenderView);
01196 
01197     // Graham 5/8/96: "ch" is presently in UNICODE or ASCII
01198     // We need to convert it over to MBCS to deal with Japanese strings
01199     //So convert ch, which is of form WCHAR, over to a MBCS UINT32 character index
01200 
01201     UINT32 uiCharNumber = UnicodeManager::UnicodeToMultiByte(ch);
01202 
01203     //Now we want to put that UINT32 value into an array of char ready to pass to
01204     //RenderDC->TextOut. We do this using UnicodeManager::DecomposeMultiBytes
01205 
01206     BYTE bCharArray[2];
01207 
01208     UnicodeManager::DecomposeMultiBytes(uiCharNumber, &bCharArray[0], &bCharArray[1]);
01209 
01210     //Now, is the character in bCharArray one or two bytes long?
01211     //If it is one byte long, the first byte in bCharArray will be zero.
01212     if (bCharArray[0]==0)
01213         //It's a standard ASCII character, one byte long
01214         //So pass that character (bCharArray[1]) to the TextOut function.
01215         //The last parameter in text out is the number of bytes - in this case 1.
01216         RenderDC->TextOut(WinPos.x, WinPos.y, (CHAR*) &bCharArray[1], 1);
01217     else
01218         //The character is two bytes long (that is, it's a foreign character)
01219         //So we pass bCharArray[0] to TextOut and tell TextOut that it should
01220         //use two bytes from that address. We do this by setting the last
01221         //parameter to 2.
01222         RenderDC->TextOut(WinPos.x, WinPos.y, (CHAR*) &bCharArray[0], 2);
01223 
01224     // Clean up text attributes
01225     RenderDC->SetTextAlign(OldTextAlign);
01226     RenderDC->SetBkMode(OldBKMode);
01227     RenderDC->SetTextColor(OldTextColour);
01228 
01229     // Finished doing GDI output
01230     if (!pPSDC->EndOSOutput())
01231         return FALSE;
01232     return TRUE;
01233 #else
01234     return RenderRegion::RenderChar(ch, pMatrix);
01235 #endif  
01236 }
01237 

Generated on Sat Nov 10 03:46:38 2007 for Camelot by  doxygen 1.4.4