// $Id: psrndrgn.cpp 1365 2006-06-25 20:29:01Z alex $ /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE ================================XARAHEADERSTART=========================== Xara LX, a vector drawing and manipulation program. Copyright (C) 1993-2006 Xara Group Ltd. Copyright on certain contributions may be held in joint with their respective authors. See AUTHORS file for details. LICENSE TO USE AND MODIFY SOFTWARE ---------------------------------- This file is part of Xara LX. Xara LX is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as published by the Free Software Foundation. Xara LX and its component source files are distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Xara LX (see the file GPL in the root directory of the distribution); if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ADDITIONAL RIGHTS ----------------- Conditional upon your continuing compliance with the GNU General Public License described above, Xara Group Ltd grants to you certain additional rights. The additional rights are to use, modify, and distribute the software together with the wxWidgets library, the wxXtra library, and the "CDraw" library and any other such library that any version of Xara LX relased by Xara Group Ltd requires in order to compile and execute, including the static linking of that library to XaraLX. In the case of the "CDraw" library, you may satisfy obligation under the GNU General Public License to provide source code by providing a binary copy of the library concerned and a copy of the license accompanying it. Nothing in this section restricts any of the rights you have under the GNU General Public License. SCOPE OF LICENSE ---------------- This license applies to this program (XaraLX) and its constituent source files only, and does not necessarily apply to other Xara products which may in part share the same code base, and are subject to their own licensing terms. This license does not apply to files in the wxXtra directory, which are built into a separate library, and are subject to the wxWindows license contained within that directory in the file "WXXTRA-LICENSE". This license does not apply to the binary libraries (if any) within the "libs" directory, which are subject to a separate license contained within that directory in the file "LIBS-LICENSE". ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS ---------------------------------------------- Subject to the terms of the GNU Public License (see above), you are free to do whatever you like with your modifications. However, you may (at your option) wish contribute them to Xara's source tree. You can find details of how to do this at: http://www.xaraxtreme.org/developers/ Prior to contributing your modifications, you will need to complete our contributor agreement. This can be found at: http://www.xaraxtreme.org/developers/contribute/ Please note that Xara will not accept modifications which modify any of the text between the start and end of this header (marked XARAHEADERSTART and XARAHEADEREND). MARKS ----- Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara designs are registered or unregistered trademarks, design-marks, and/or service marks of Xara Group Ltd. All rights in these marks are reserved. Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. http://www.xara.com/ =================================XARAHEADEREND============================ */ // Render region for rendering to PostScript devices. /* */ #include "camtypes.h" #include "psrndrgn.h" #include "psdc.h" #include "page.h" //#include "spread.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "document.h" - in camtypes.h [AUTOMATICALLY REMOVED] //#include "fillval.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "textfuns.h" #include "devcolor.h" #include "camelot.h" #include "colplate.h" //#include "isetres.h" //#include "tim.h" #include "oilfiles.h" #include "unicdman.h" //For MBCS support //#include "xaracms.h" //#include "app.h" - in camtypes.h [AUTOMATICALLY REMOVED] #include "printctl.h" //#include "view.h" - in camtypes.h [AUTOMATICALLY REMOVED] DECLARE_SOURCE("$Revision: 1365 $"); CC_IMPLEMENT_DYNAMIC(PrintPSRenderRegion, CamelotEPSRenderRegion) #define new CAM_DEBUG_NEW /******************************************************************************************** > PrintPSRenderRegion(DocRect ClipRect, Matrix ConvertMatrix, FIXED16 ViewScale) Author: Tim_Browse (Xara Group Ltd) Created: 15/04/94 Purpose: Initialise a render region for printing PostScript. SeeAlso: CamelotEPSRenderRegion::CamelotEPSRenderRegion ********************************************************************************************/ PrintPSRenderRegion::PrintPSRenderRegion(DocRect ClipRect, Matrix ConvertMatrix, FIXED16 ViewScale) : CamelotEPSRenderRegion(ClipRect, ConvertMatrix, ViewScale) { // We're a printing render region. RenderFlags.Printing = TRUE; } /******************************************************************************************** > PrintPSRenderRegion::~PrintPSRenderRegion() Author: Tim_Browse (Xara Group Ltd) Created: 15/04/94 Purpose: Delete the region, flushing the PostScript output DC beforehand. SeeAlso: PSPrintDC::Flush ********************************************************************************************/ PrintPSRenderRegion::~PrintPSRenderRegion() { PSPrintDC *pPSPrintDC = (PSPrintDC *) CCDC::ConvertFromNativeDC(RenderDC); // Restore OS context - just pretend we want to do some OS output pPSPrintDC->StartOSOutput(); // Flush the DC pPSPrintDC->FlushDC(); pPSPrintDC->EndOSOutput(); // Karim 06/06/2000 - free the memory! (hope this doesn't blow up something else...) // AB: Don't do this. RenderRegion's destructor deletes RenderDC // delete pPSPrintDC; // pPSPrintDC = NULL; } /******************************************************************************************** > BOOL PrintPSRenderRegion::InitDevice() Author: Tim_Browse (Xara Group Ltd) Created: 27/05/94 Returns: TRUE if the device context is initialised ok; FALSE if not. Purpose: Initialise the device specific mechanisms for this render region. For a PrintPSRenderRegion we need to change the DC slightly - we use the existing RenderDC to make a PSPrintDC, which allows us to output PostScript directly to the device. Errors: Same as base class. SeeAlso: RenderRegion::InitDevice ********************************************************************************************/ BOOL PrintPSRenderRegion::InitDevice() { // Ensure the current DC is suitable for postscript rendering CCDC *pCCDC = CCDC::ConvertFromNativeDC( RenderDC ); ERROR2IF(!pCCDC || !pCCDC->IsKindOf(CC_RUNTIME_CLASS(PSPrintDC)), FALSE, "Trying to InitDevice on a non-Postscript CCDC"); PSPrintDC *pPSPrintDC = (PSPrintDC *) pCCDC; pPSPrintDC->SetDCTransforms(RenderMatrix, RenderView); // Call base class - note that unlike other InitDevice() implementations, we don't // call this as the very first thing in the function - this is because we need to switch // the DC beforehand, as seen above. if (!RenderRegion::InitDevice()) return FALSE; // Find out what this region can do GetRenderRegionCaps(&Caps); // All ok return TRUE; } /******************************************************************************************** > BOOL PrintPSRenderRegion::StartRender() Author: Tim_Browse (Xara Group Ltd) Created: 30/03/94 Returns: TRUE if worked, FALSE if failed. Purpose: Prepare the render region for rendering (exporting). SeeAlso: EPSRenderRegion::Initialise; EPSRenderRegion::StopRender ********************************************************************************************/ BOOL PrintPSRenderRegion::StartRender() { // If we are being restarted, reinstate our dictionary on the stack // BOOL Restarted = RenderFlags.ValidDevice; // Call base class first if (!EPSRenderRegion::StartRender()) return FALSE; // Attach the DC to this render region. PSPrintDC *pPSPrintDC = (PSPrintDC *) CCDC::ConvertFromNativeDC(RenderDC); pPSPrintDC->SetDCTransforms(RenderMatrix, RenderView); pPSPrintDC->AttachRenderRegion(this); Initialise(); return TRUE; } /******************************************************************************************** > BOOL PrintPSRenderRegion::StopRender() Author: Will_Cowling (Xara Group Ltd) Created: 11/5/93 Inputs: RenderState is a Node* pointing at the current rendering node in the tree, or NULL if all objects rendered. Purpose: Stops the rendering of a OSRenderRegion, saving it's current renderstate so that rendering can continue where it left off, later on. If the RenderState passed is NULL then the RenderRegion will be unlinked from the list and will then delete itself. SeeAlso: OSRenderRegion::StartRender() ********************************************************************************************/ BOOL PrintPSRenderRegion::StopRender() { // Call base class BOOL bHaveRendered = EPSRenderRegion::StopRender(); // Flush our buffered PostScript device context. PSPrintDC *pPSPrintDC = (PSPrintDC *) CCDC::ConvertFromNativeDC(RenderDC); pPSPrintDC->FlushDC(); // Detach the DC from this render region. pPSPrintDC->DetachRenderRegion(); return bHaveRendered; } /******************************************************************************************** > BOOL PrintPSRenderRegion::CloseDown() Author: Tim_Browse (Xara Group Ltd) Created: 05/09/95 Returns: TRUE (always) Purpose: Close down a PostScript render region - in fact we do nothing as the printer driver is responsible for tidying up, and we will already have cleared our dictionary from the dict stack in StopRender() SeeAlso: CamelotEPSRenderRegion::StopRender ********************************************************************************************/ BOOL PrintPSRenderRegion::CloseDown() { // Do nothing - the printer driver should do it all for us... return TRUE; } /******************************************************************************************** > virtual void PrintPSRenderRegion::ConditionalSuicide ( void ) Author: Graeme_Sutherland (Xara Group Ltd) Created: 24/2/00 Inputs: - Returns: - Purpose: Causes the object to commit suicide. This is to get around using a few if IS_A calls elsewhere in Camelot. ********************************************************************************************/ void PrintPSRenderRegion::ConditionalSuicide ( void ) { // Delete the object. delete this; } /******************************************************************************************** > BOOL PrintPSRenderRegion::WriteProlog(KernelDC *pDC) Author: Tim_Browse (Xara Group Ltd) Created: 24/04/95 Inputs: pDC - the device context to output to. Outputs: - Returns: TRUE if ok; FALSE if error (e.g. file/disk error or printer driver error) Purpose: Output any PostScript prolog for this render region. For EPS and printing, this means output of our PostScript rendering procedures; for Native files we do nothing. SeeAlso: EPSRenderRegion::WriteSetup ********************************************************************************************/ BOOL PrintPSRenderRegion::WriteProlog(KernelDC *pDC) { // Call base class to output our dictionary if (!CamelotEPSRenderRegion::WriteProlog(pDC)) // Error return FALSE; // All done return TRUE; } /******************************************************************************************** > BOOL PrintPSRenderRegion::WriteSetup(KernelDC *pDC) Author: Tim_Browse (Xara Group Ltd) Created: 24/04/95 Inputs: pDC - the device context to output to. Outputs: - Returns: TRUE if ok; FALSE if error (e.g. file/disk error or printer driver error) Purpose: Output any PostScript setup for this render region. For EPS and printing, this means output of our PostScript code to initialise the context for rendering; for Native files we do nothing. SeeAlso: EPSRenderRegion::WriteSetup ********************************************************************************************/ BOOL PrintPSRenderRegion::WriteSetup(KernelDC *pDC) { // Call base class to output our setup code if (!CamelotEPSRenderRegion::WriteSetup(pDC)) // Error return FALSE; // All ok return TRUE; } /******************************************************************************************** > virtual BOOL PrintPSRenderRegion::WriteSepTables(KernelDC *pDC) Author: Mike_Kenny (Xara Group Ltd) Created: 19/06/96 Inputs: pDC - the device context to output to. Outputs: - Returns: TRUE if ok; FALSE if error (e.g. file/disk error or printer driver error) Purpose: Output the current set of device printer profiles as Postscript hex arrays. Our Postscript prolog functions will use these arrays when creating separations. (if we are not separating, we do nothing) SeeAlso: ********************************************************************************************/ BOOL PrintPSRenderRegion::WriteSepTables(KernelDC *pDC) { ColourContext* pContext; ColourPlate* pSeparation; GetOutputColourPlate(COLOURMODEL_CMYK, &pContext, &pSeparation); // Note, we return true to all but the token output // functions. We will terminate the output only if // we receive a disc failure. // do nothing if we are not separating if (pSeparation==NULL) return TRUE; // check that we've got a colour context attached to us. if (pContext==NULL) { ERROR3("There is no current colour context in this render region!"); return TRUE; } // Whip out the physical tables we will use to separate. BYTE Table[5*256]; if (!pContext->GetProfileTables(Table)) return TRUE; // output cyan BOOL ok = pDC->OutputToken(_T("/ccurve [")); ok = ok && WriteSepTablesHelper(pDC, Table); ok = ok && pDC->OutputToken(_T("] def")); ok = ok && pDC->OutputNewLine(); // output magenta ok = ok && pDC->OutputToken(_T("/mcurve [")); ok = ok && WriteSepTablesHelper(pDC, Table+256); ok = ok && pDC->OutputToken(_T("] def")); ok = ok && pDC->OutputNewLine(); // output yellow ok = ok && pDC->OutputToken(_T("/ycurve [")); ok = ok && WriteSepTablesHelper(pDC, Table+512); ok = ok && pDC->OutputToken(_T("] def")); ok = ok && pDC->OutputNewLine(); // output ucr ok = ok && pDC->OutputToken(_T("/ucurve [")); ok = ok && WriteSepTablesHelper(pDC, Table+768); ok = ok && pDC->OutputToken(_T("] def")); ok = ok && pDC->OutputNewLine(); // output black generation ok = ok && pDC->OutputToken(_T("/bcurve [")); ok = ok && WriteSepTablesHelper(pDC, Table+1024); ok = ok && pDC->OutputToken(_T("] def")); ok = ok && pDC->OutputNewLine(); // Enable separations ok = ok && pDC->OutputToken(_T("1 setseps")); ok = ok && pDC->OutputNewLine(); // Is this a mono plate? BOOL mono = pSeparation->IsMonochrome(); // find what type of separation plate we are using ColourPlateType Type = pSeparation->GetType(); switch (Type) { case COLOURPLATE_CYAN: ok = ok && pDC->OutputToken(_T("v_cpcy setplate")); ok = ok && pDC->OutputNewLine(); break; case COLOURPLATE_MAGENTA: ok = ok && pDC->OutputToken(_T("v_cpmg setplate")); ok = ok && pDC->OutputNewLine(); break; case COLOURPLATE_YELLOW: ok = ok && pDC->OutputToken(_T("v_cpyl setplate")); ok = ok && pDC->OutputNewLine(); break; case COLOURPLATE_KEY: ok = ok && pDC->OutputToken(_T("v_cpky setplate")); ok = ok && pDC->OutputNewLine(); break; case COLOURPLATE_SPOT: // Force mono to be true here, all spot colour will // be going out as weights of key, and hence are // really the same as mono c,m,y,k mono=TRUE; break; default: ERROR3("What kind of a plate is that?"); break; } // Output the mono setting. This determins whether our postscript // colour fill and stroke functions will set colour using the // setgray function or setcmyk if (mono) ok = ok && pDC->OutputToken(_T("1 setmono")); else ok = ok && pDC->OutputToken(_T("0 setmono")); ok = ok && pDC->OutputNewLine(); // All ok return ok; } /******************************************************************************************** > BOOL PrintPSRenderRegion::WriteSepTablesHelper(KernelDC *pDC, BYTE* Table) Author: Mike_Kenny (Xara Group Ltd) Created: 19/06/96 Inputs: pDC - the device context to output to. Table = a pointer to a 256 byte entry table Outputs: - Returns: TRUE if ok; FALSE if error (e.g. file/disk error or printer driver error) Purpose: Output the table of 256 values to the output stream ********************************************************************************************/ BOOL PrintPSRenderRegion::WriteSepTablesHelper(KernelDC *pDC, BYTE* Table) { BOOL ok; UINT32 val; for (INT32 i=0; i<256; i++) { val = (UINT32) (Table[i]); ok = pDC->OutputValue(val); if (!ok) return FALSE; } return TRUE; } /******************************************************************************************** > BOOL PrintPSRenderRegion::WritePlateName(KernelDC *pDC) Author: Mike_Kenny (Xara Group Ltd) Created: 24/06/96 Inputs: pDC - the device context to output to. Outputs: - Returns: TRUE if ok; FALSE if error (e.g. file/disk error or printer driver error) Purpose: Output the current plate name for this print separation, if there is one. ********************************************************************************************/ BOOL PrintPSRenderRegion::WritePlateName(KernelDC *pDC) { ColourPlate* pSeparation; GetOutputColourPlate(COLOURMODEL_CMYK, NULL, &pSeparation); // do nothing if we are not separating if (pSeparation==NULL) return TRUE; // Get and output the plate name, cheers String_64 platename; pSeparation->GetDescription(&platename); TCHAR* pPlate = (TCHAR*)platename; // ok output the textural name BOOL ok = pDC->OutputToken(_T("%%PlateColor :")); ok = ok && pDC->OutputToken(pPlate); ok = ok && pDC->OutputNewLine(); return ok; } /******************************************************************************************** > BOOL PrintPSRenderRegion::WritePlateScreen(KernelDC *pDC) Author: Mike_Kenny (Xara Group Ltd) Created: 24/06/96 Inputs: pDC - the device context to output to. Outputs: - Returns: TRUE if ok; FALSE if error (e.g. file/disk error or printer driver error) Purpose: Output the setscreen function for this plate. ********************************************************************************************/ BOOL PrintPSRenderRegion::WritePlateScreen(KernelDC *pDC) { PrintControl *pPrintCtl=NULL; View *pView = GetRenderView(); if (pView) pPrintCtl = pView->GetPrintControl(); if (!pPrintCtl) return TRUE; // Get a pointer to the typeset info structure TypesetInfo *pInfo = pPrintCtl->GetTypesetInfo(); double ang,freq; String_256 ScreenName; ScreenType scrtype; // If separating then interogate the current plate if (pInfo->AreSeparating()) { ColourPlate* pSeparation; GetOutputColourPlate(COLOURMODEL_CMYK, NULL, &pSeparation); // do nothing if we are not separating if (pSeparation==NULL) return TRUE; // Make sure screening is on in this plate if (!pSeparation->ActiveScreening()) return TRUE; // Get the screen type if enabled. scrtype = pSeparation->GetScreenFunction(); if (scrtype==SCRTYPE_NONE) return TRUE; // ok we can get the angle and frequency ang = pSeparation->GetScreenAngle(); freq = pSeparation->GetScreenFrequency(); } else { // Is screening off? if (!pInfo->AreScreening()) return TRUE; scrtype = pInfo->GetScreenFunction(); if (scrtype==SCRTYPE_NONE) return TRUE; ang = 45.0; freq = pInfo->GetDefaultScreenFrequency(); } // read the name of this screen pInfo->GetScreenName(scrtype, &ScreenName); String_256 fred; fred += String_8(_T("{")); fred += ScreenName; fred += String_8(_T("}")); // ok output 'freq ang screenfunc setscreen' BOOL ok = pDC->OutputFloat(freq, 4); ok = ok && pDC->OutputFloat(ang, 4); ok = ok && pDC->OutputToken(fred); ok = ok && pDC->OutputToken(_T("setscreen")); ok = ok && pDC->OutputNewLine(); return ok; } /******************************************************************************************** > BOOL PrintPSRenderRegion::WriteSepFunctions(KernelDC *pDC) Author: Mike_Kenny (Xara Group Ltd) Created: 26/06/96 Inputs: pDC - the device context to output to. Outputs: - Returns: TRUE if ok; FALSE if error (e.g. file/disk error or printer driver error) Purpose: Output the setscreen functions file for this separation. SeeAlso: WriteProlog ********************************************************************************************/ BOOL PrintPSRenderRegion::WriteSepFunctions(KernelDC *pDC) { PrintControl *pPrintCtl=NULL; View *pView = GetRenderView(); if (pView) pPrintCtl = pView->GetPrintControl(); if (!pPrintCtl) return TRUE; // Get a pointer to the typeset info structure TypesetInfo *pInfo = pPrintCtl->GetTypesetInfo(); // Is screening off? if (!pInfo->AreScreening()) return TRUE; // Get hold of our PostScript prolog resource... CCResTextFile ScreenFile; // Open the file if (!ScreenFile.open(_R(IDM_PS_SPOTFUNCS), _R(IDT_PS_RES))) { // Failed to open the file... ERROR2(FALSE, "Could not get at PostScript resource!"); } // Read each line from the file and output it to the DC. String_256 LineBuf; TCHAR *pBuf = (TCHAR *) LineBuf; while (!ScreenFile.eof()) { // Copy this line to output. ScreenFile.read(&LineBuf); pDC->OutputTCHARAsChar(pBuf, LineBuf.Length()); pDC->OutputNewLine(); } // All done ScreenFile.close(); return TRUE; } /******************************************************************************************** > BOOL PrintPSRenderRegion::PushClipRegion(KernelDC *pDC, const DocRect& Rect) Author: Mike_Kenny (Xara Group Ltd) Created: 02/09/96 Inputs: pDC - the device context to output to. Rect - the clipping rect to create. Outputs: - Returns: TRUE if ok; FALSE if error (e.g. file/disk error or printer driver error) Purpose: Stack the PostScript clipping rectangle. The clipping rectangle will be active until our context is reset. SeeAlso: PopClipRegion ********************************************************************************************/ BOOL PrintPSRenderRegion::PushClipRegion(KernelDC *pDC, const DocRect& Rect) { BOOL ok = pDC->OutputToken(_T("gs")); ok = ok && pDC->OutputNewLine(); ok = ok && WriteClipRegion(pDC,Rect); return ok; } /******************************************************************************************** > BOOL PrintPSRenderRegion::PopClipRegion(KernelDC *pDC) Author: Mike_Kenny (Xara Group Ltd) Created: 02/09/96 Inputs: pDC - the device context to output to. Outputs: - Returns: TRUE if ok; FALSE if error (e.g. file/disk error or printer driver error) Purpose: Unstack the current PostScript clip region. We simply pop the graphics state here to return to the previous clipping region. SeeAlso: PushClipRegion ********************************************************************************************/ BOOL PrintPSRenderRegion::PopClipRegion(KernelDC *pDC) { BOOL ok = pDC->OutputToken(_T("gr")); ok = ok && pDC->OutputNewLine(); return ok; } /******************************************************************************************** > BOOL PrintPSRenderRegion::WriteClipRegion(KernelDC *pDC, const DocRect& Rect) Author: Mike_Kenny (Xara Group Ltd) Created: 02/09/96 Inputs: pDC - the device context to output to. Rect - the clipping rect to create. Outputs: - Returns: TRUE if ok; FALSE if error (e.g. file/disk error or printer driver error) Purpose: Set up a PostScript clipping rectangle. The clipping rectangle will be active until our context is reset. ********************************************************************************************/ BOOL PrintPSRenderRegion::WriteClipRegion(KernelDC *pDC, const DocRect& Rect) { if (!Rect.IsValid() || Rect.IsEmpty()) return TRUE; DocCoord c0,c1; c0=Rect.lo; c1=Rect.hi; BOOL ok = pDC->OutputCoord(c0); ok = ok && pDC->OutputCoord(c1); ok = ok && pDC->OutputToken(TEXT("Cp")); ok = ok && pDC->OutputNewLine(); return ok; } /******************************************************************************************** > BOOL PrintPSRenderRegion::WritePhotoNegative(KernelDC *pDC) Author: Mike_Kenny (Xara Group Ltd) Created: 29/08/96 Inputs: pDC - the device context to output to. Outputs: - Returns: TRUE if ok; FALSE if error (e.g. file/disk error or printer driver error) Purpose: Start photo negative rendering. All rendering will be photo-negated. ********************************************************************************************/ BOOL PrintPSRenderRegion::WritePhotoNegative(KernelDC *pDC) { /* ColourPlate* pSeparation; GetOutputColourPlate(COLOURMODEL_CMYK, NULL, &pSeparation); // do nothing if we are not separating if (pSeparation==NULL) return TRUE; // if this plate says negative lets do it if (pSeparation->IsEPSNegative()) return WriteSetTransfer(pDC); */ // Find the print control structure. PrintControl *pControl = GetRenderView()->GetPrintControl(); if (pControl) { TypesetInfo *pTypeset = pControl->GetTypesetInfo(); if (pTypeset && pTypeset->PrintPhotoNegative()) return WriteSetTransfer(pDC); } return TRUE; } BOOL PrintPSRenderRegion::WriteSetTransfer(KernelDC *pDC) { BOOL ok = pDC->OutputToken(_T("{1 exch sub} settransfer")); ok = ok && pDC->OutputNewLine(); return ok; } /******************************************************************************************** > BOOL PrintPSRenderRegion::WriteRenderPaper(KernelDC *pDC) Author: Mike_Kenny (Xara Group Ltd) Created: 29/08/96 Inputs: pDC - the device context to output to. Outputs: - Returns: TRUE if ok; FALSE if error (e.g. file/disk error or printer driver error) Purpose: Fill the entire renderable area with white ********************************************************************************************/ BOOL PrintPSRenderRegion::WriteRenderPaper(KernelDC *pDC) { /* ColourPlate* pSeparation; GetOutputColourPlate(COLOURMODEL_CMYK, NULL, &pSeparation); // do nothing if we are not separating if (pSeparation==NULL) return TRUE; // if this plate says negative lets do it if (pSeparation->IsEPSNegative()) return WriteFillPaper(pDC); */ // Find the print control structure. PrintControl *pControl = GetRenderView()->GetPrintControl(); if (pControl) { TypesetInfo *pTypeset = pControl->GetTypesetInfo(); if (pTypeset && pTypeset->PrintPhotoNegative()) return WriteFillPaper(pDC); } return TRUE; } BOOL PrintPSRenderRegion::WriteFillPaper(KernelDC *pDC) { BOOL ok = pDC->OutputToken(_T("gsave clippath 1 setgray fill grestore")); ok = ok && pDC->OutputNewLine(); return ok; } /******************************************************************************************** > BOOL PrintPSRenderRegion::OutputPSHeader() Author: Tim_Browse (Xara Group Ltd) & JustinF Created: 04/29/95 Returns: TRUE if ok; FALSE if file/printer error occured. Purpose: Output the PostScript header that Camelot needs in order for its PostScript code to work. NB. the original version of this function has been commented out and moved to the end of this source file. ********************************************************************************************/ BOOL PrintPSRenderRegion::OutputPSHeader() { PORTNOTE("printing", "Don't output strange rectangles") #ifndef EXCLUDE_FROM_XARALX // If running under Win95 or Win31, but not any flavour of WinNT, then begin with some // fake GDI output to force the buggy Postscript driver to flush its output buffer. if (IsWin32s()) { // Justin says: please *don't* change this to *anything* else until you've // spoken to me or Phil. CBrush br; br.CreateStockObject(WHITE_BRUSH); CBrush* pOldBr = RenderDC->SelectObject(&br); CPen pn; pn.CreateStockObject(WHITE_PEN); CPen* pOldPn = RenderDC->SelectObject(&pn); // Draw a tiny white rectangle with a white outline. TRACEUSER( "JustinF", _T("Postscript pixel fix in action ...\n")); RenderDC->Rectangle(&CRect(0, 0, 1, 1)); RenderDC->SelectObject(pOldPn); RenderDC->SelectObject(pOldBr); } #endif // Use the current DC to make a new one that is suitable for rendering // PostScript to directly. PSPrintDC* pPSPrintDC = new PSPrintDC(RenderDC); if (pPSPrintDC == NULL) return FALSE; // Set up this - don't need it but the DC might get upset if it has no view. RenderDC = pPSPrintDC->GetDC(); pPSPrintDC->SetDCTransforms(RenderMatrix, RenderView); // Tell the DC (i) we want to do OS output - this prevents it from outputting a // reference to our dictionary before we have defined it (because it's trying to // set up the PostScript C ready for Camelot EPS commands); (ii) we have finished // doing our 'OS' output. :-) return pPSPrintDC->StartOSOutput() && pPSPrintDC->EndOSOutput(); } /******************************************************************************************** > void PrintPSRenderRegion::Initialise() Author: Tim_Browse (Xara Group Ltd) Created: 04/29/95 Purpose: Over-rides the EPS header output code - we don't want to do this everytime we start a PostScript render region, only every time we start a print job. SeeAlso: PrintPSRenderRegion::OutputPSHeader ********************************************************************************************/ void PrintPSRenderRegion::Initialise() { // Set up render region InitClipping(); InitAttributes(); } /******************************************************************************************** > void PrintPSRenderRegion::DeInitialise() Author: Tim_Browse (Xara Group Ltd) Created: 04/29/95 Purpose: Over-rides the EPS trailer output code - we don't want to do this everytime we delete a PostScript render region - the printer driver should do it for us. SeeAlso: PrintPSRenderRegion::OutputPSHeader ********************************************************************************************/ void PrintPSRenderRegion::DeInitialise() { // Clear up DeInitAttributes(); } BOOL PrintPSRenderRegion::InitPSDevice(CNativeDC *pDC, PrintView *pPrintView) { // Make a new PSRenderRegion, and use it to output out PostScript header. DocRect DummyRect; Matrix DummyMatrix; FIXED16 DummyScale(0); PrintPSRenderRegion *pRegion = new PrintPSRenderRegion(DummyRect, DummyMatrix, DummyScale); if (pRegion == NULL) return FALSE; // Attach new region to the DC. pRegion->AttachDevice((View *) pPrintView, pDC, Document::GetSelectedSpread()); // Output the header if (!pRegion->OutputPSHeader()) return FALSE; delete pRegion; return TRUE; } /******************************************************************************************** > BOOL PrintPSRenderRegion::RenderChar(WCHAR ch, Matrix* pMatrix) Author: Tim_Browse (Xara Group Ltd) Created: 30/4/95 Inputs: ch - unicode value of char pMatrix - matrix specifying transforms to place char correctly in document Returns: FALSE if fails Purpose: Render a character, using the specified transform and current attributes in the render region. ********************************************************************************************/ BOOL PrintPSRenderRegion::RenderChar(WCHAR ch, Matrix* pMatrix) { PORTNOTE("printing", "Disabled PS text rendering") #ifndef EXCLUDE_FROM_XARALX // If it is stroked or not simple flat fill, or not a standard ASCII character then we // must do this as paths. BOOL FlatFill = IS_A(CurrentAttrs[ATTR_FILLGEOMETRY].pAttr, FlatFillAttribute); if (!FlatFill || !RR_STROKECOLOUR().IsTransparent() || (FlatFill & RR_FILLCOLOUR().IsTransparent()) || (ch > 255)) return RenderRegion::RenderChar(ch, pMatrix); // Check for emulsion down printing PrintControl *pPrintCtl; View *pView = GetRenderView(); if (pView && (pPrintCtl=pView->GetPrintControl())) { if (pPrintCtl->GetTypesetInfo()->PrintEmulsionDown()) return RenderRegion::RenderChar(ch, pMatrix); } // get overall matrix - attribute matrix concatenated with given matrix if supplied Matrix matrix; if (GetCharAttributeMatrix(&matrix)==FALSE) return FALSE; if (pMatrix) matrix*=*pMatrix; // Can we do this using a GDI font? // We can if the matrix only specifies scaling and translation FIXED16 abcd[4]; INT32 ef[2]; matrix.GetComponents(abcd, ef); // GDI can't do y-axis flips, so we do it as shapes if this is detected (and x-axis // flips, for consistency). if ((abcd[0] < FIXED16(0)) || (abcd[3] < FIXED16(0))) { // Flipped in one or both axes - render as a path. return RenderRegion::RenderChar(ch, pMatrix); } // Work out how complex the transformation is. FIXED16 ScaleX, ScaleY; ANGLE Rotation, Shear; if ((abcd[1] == FIXED16(0)) && (abcd[2] == FIXED16(0))) { // Simple scaling transformation. ScaleX = abcd[0]; ScaleY = abcd[3]; Rotation = FIXED16(0); Shear = FIXED16(0); } else { // Decompose the matrix to find out how complex it is. // Pass in NULL for translation as we already know it is in 'ef'. FIXED16 Aspect; BOOL Result = matrix.Decompose(&ScaleY, &Aspect, &Rotation, &Shear, NULL); if (!Result || (Shear != FIXED16(0))) // Either there was a problem, or the character is sheared, in which case // we can't do it with GDI. return RenderRegion::RenderChar(ch, pMatrix); // Set up the ScaleX based on the aspect ratio ScaleX = ScaleY * Aspect; } // Check for sideways printing - if the render matrix has rotation, then we are // printing at 270 degrees rotation, so adjust the rotation accordingly. #if 1 FIXED16 RenderABCD[4]; INT32 RenderEF[2]; RenderMatrix.GetComponents(RenderABCD, RenderEF); if ((RenderABCD[1] != FIXED16(0)) || (RenderABCD[2] != FIXED16(0))) // Rotate by 270 degrees (angle is in radians) Rotation += FIXED16(1.5 * PI); #endif // Simple transformation - we can do this with a GDI font. PSPrintDC *pPSDC = (PSPrintDC *) CCDC::ConvertFromNativeDC(RenderDC); if (!pPSDC->StartOSOutput()) return FALSE; // Work out required width and height of the font MILLIPOINT ReferenceSize = TextManager::GetDefaultHeight(); MILLIPOINT Width = ReferenceSize * ScaleX; MILLIPOINT Height = ReferenceSize * ScaleY; if (!pPSDC->SelectNewFont(RR_TXTFONTTYPEFACE(), RR_TXTBOLD(), RR_TXTITALIC(), Width, Height, Rotation)) { // Could not select font (maybe because device can't rotate fonts) pPSDC->EndOSOutput(); return RenderRegion::RenderChar(ch, pMatrix); } // Ok, so the OS might screw up our attributes/graphics state, so we force // attributes to be output specifically the next time we do some Camelot output. ResetOutputAttributes(); // First, set up the text attributes that are not encoded in the font. UINT32 OldTextAlign = RenderDC->SetTextAlign(TA_BASELINE); INT32 OldBKMode = RenderDC->SetBkMode(TRANSPARENT); COLORREF TextColour = ConvertColourToScreenWord(CurrentColContext, &RR_FILLCOLOUR()); // check for completely black text if (TextColour==0 && IsWindowsNT()) { // All components are 0! // BODGE TEXT - The driver decides its a good idea not to ouput // 0 g when black is (it thinks) already set. // Hence we get the colour previously set. So, we // output a dummy black here, which it doesn't ignore. // Done by Mike (04/07/96). It would be nice to find // out why the driver is ignoring us but time is fleating TextColour = (DWORD)(0x00010101); /* This really is majorly dangerous! (Read comments in OutputDirect for why) We could use the following but we will destroy the graphics state of gdi for colour. ie if GDI does a 'save char col fill restore' we will end up doing this col save char col fill restore and will have mucked up the graph state. String_32 LineBuf("0 g"); LineBuf += '\n'; TCHAR *pBuf = (TCHAR *) LineBuf; pPSDC->OutputTCHARAsChar(pBuf, LineBuf.Length()); */ } COLORREF OldTextColour = RenderDC->SetTextColor(TextColour); // Render the character in the specified position DocCoord DocPos(ef[0], ef[1]); // Convert DocCoord to WinCoord OilCoord OilPoint; RenderMatrix.GetComponents(abcd, ef); OilPoint.x = MatrixCalc(abcd[0], DocPos.x, abcd[2], DocPos.y) + ef[0]; OilPoint.y = MatrixCalc(abcd[1], DocPos.x, abcd[3], DocPos.y) + ef[1]; WinCoord WinPos = OilPoint.ToWin(RenderView); // Graham 5/8/96: "ch" is presently in UNICODE or ASCII // We need to convert it over to MBCS to deal with Japanese strings //So convert ch, which is of form WCHAR, over to a MBCS UINT32 character index UINT32 uiCharNumber = UnicodeManager::UnicodeToMultiByte(ch); //Now we want to put that UINT32 value into an array of char ready to pass to //RenderDC->TextOut. We do this using UnicodeManager::DecomposeMultiBytes BYTE bCharArray[2]; UnicodeManager::DecomposeMultiBytes(uiCharNumber, &bCharArray[0], &bCharArray[1]); //Now, is the character in bCharArray one or two bytes long? //If it is one byte long, the first byte in bCharArray will be zero. if (bCharArray[0]==0) //It's a standard ASCII character, one byte long //So pass that character (bCharArray[1]) to the TextOut function. //The last parameter in text out is the number of bytes - in this case 1. RenderDC->TextOut(WinPos.x, WinPos.y, (CHAR*) &bCharArray[1], 1); else //The character is two bytes long (that is, it's a foreign character) //So we pass bCharArray[0] to TextOut and tell TextOut that it should //use two bytes from that address. We do this by setting the last //parameter to 2. RenderDC->TextOut(WinPos.x, WinPos.y, (CHAR*) &bCharArray[0], 2); // Clean up text attributes RenderDC->SetTextAlign(OldTextAlign); RenderDC->SetBkMode(OldBKMode); RenderDC->SetTextColor(OldTextColour); // Finished doing GDI output if (!pPSDC->EndOSOutput()) return FALSE; return TRUE; #else return RenderRegion::RenderChar(ch, pMatrix); #endif }