1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
22 #include <sys/types.h>
27 #include "psputil.hxx"
28 #include "glyphset.hxx"
30 #include "generic/printerjob.hxx"
31 #include "generic/printergfx.hxx"
32 #include "vcl/ppdparser.hxx"
33 #include "vcl/strhelper.hxx"
34 #include "vcl/printerinfomanager.hxx"
36 #include "rtl/ustring.hxx"
37 #include "rtl/strbuf.hxx"
38 #include "rtl/ustrbuf.hxx"
40 #include <osl/thread.h>
41 #include <osl/security.hxx>
42 #include <sal/alloca.h>
43 #include <sal/macros.h>
50 using ::rtl::OUString
;
51 using ::rtl::OUStringToOString
;
53 using ::rtl::OStringBuffer
;
55 // forward declaration
57 #define nBLOCKSIZE 0x2000
63 AppendPS (FILE* pDst
, osl::File
* pSrc
, sal_uChar
* pBuffer
,
64 sal_uInt32 nBlockSize
= nBLOCKSIZE
)
66 if ((pDst
== NULL
) || (pSrc
== NULL
))
69 if (pSrc
->setPos(osl_Pos_Absolut
, 0) != osl::FileBase::E_None
)
73 nBlockSize
= nBLOCKSIZE
;
75 pBuffer
= (sal_uChar
*)alloca (nBlockSize
);
81 pSrc
->read (pBuffer
, nBlockSize
, nIn
);
83 nOut
= fwrite (pBuffer
, 1, sal::static_int_cast
<sal_uInt32
>(nIn
), pDst
);
85 while ((nIn
> 0) && (nIn
== nOut
));
93 * private convenience routines for file handling
97 PrinterJob::CreateSpoolFile (const rtl::OUString
& rName
, const rtl::OUString
& rExtension
)
99 osl::File::RC nError
= osl::File::E_None
;
100 osl::File
* pFile
= NULL
;
102 rtl::OUString aFile
= rName
+ rExtension
;
103 rtl::OUString aFileURL
;
104 nError
= osl::File::getFileURLFromSystemPath( aFile
, aFileURL
);
105 if (nError
!= osl::File::E_None
)
107 aFileURL
= maSpoolDirName
+ rtl::OUString("/") + aFileURL
;
109 pFile
= new osl::File (aFileURL
);
110 nError
= pFile
->open (osl_File_OpenFlag_Read
| osl_File_OpenFlag_Write
| osl_File_OpenFlag_Create
);
111 if (nError
!= osl::File::E_None
)
117 pFile
->setAttributes (aFileURL
,
118 osl_File_Attribute_OwnWrite
| osl_File_Attribute_OwnRead
);
123 * public methods of PrinterJob: for use in PrinterGfx
127 PrinterJob::GetScale (double &rXScale
, double &rYScale
) const
134 PrinterJob::GetDepth () const
136 sal_Int32 nLevel
= GetPostscriptLevel();
137 sal_Bool bColor
= IsColorPrinter ();
139 return nLevel
> 1 && bColor
? 24 : 8;
143 PrinterJob::GetPostscriptLevel (const JobData
*pJobData
) const
145 sal_uInt16 nPSLevel
= 2;
147 if( pJobData
== NULL
)
148 pJobData
= &m_aLastJobData
;
150 if( pJobData
->m_nPSLevel
)
151 nPSLevel
= pJobData
->m_nPSLevel
;
153 if( pJobData
->m_pParser
)
154 nPSLevel
= pJobData
->m_pParser
->getLanguageLevel();
160 PrinterJob::IsColorPrinter () const
162 sal_Bool bColor
= sal_False
;
164 if( m_aLastJobData
.m_nColorDevice
)
165 bColor
= m_aLastJobData
.m_nColorDevice
== -1 ? sal_False
: sal_True
;
166 else if( m_aLastJobData
.m_pParser
)
167 bColor
= m_aLastJobData
.m_pParser
->isColorDevice() ? sal_True
: sal_False
;
173 PrinterJob::GetCurrentPageHeader ()
175 return maHeaderList
.back();
179 PrinterJob::GetCurrentPageBody ()
181 return maPageList
.back();
185 * public methods of PrinterJob: the actual job / spool handling
188 PrinterJob::PrinterJob () :
190 mpJobTrailer( NULL
),
195 /* remove all our temporary files, uses external program "rm", since
196 osl functionality is inadequate */
198 removeSpoolDir (const rtl::OUString
& rSpoolDir
)
200 rtl::OUString aSysPath
;
201 if( osl::File::E_None
!= osl::File::getSystemPathFromFileURL( rSpoolDir
, aSysPath
) )
203 // Conversion did not work, as this is quite a dangerous action,
204 // we should abort here ....
205 OSL_FAIL( "psprint: couldn't remove spool directory" );
208 rtl::OString aSysPathByte
=
209 rtl::OUStringToOString (aSysPath
, osl_getThreadTextEncoding());
210 sal_Char pSystem
[128];
213 nChar
= psp::appendStr ("rm -rf ", pSystem
);
214 nChar
+= psp::appendStr (aSysPathByte
.getStr(), pSystem
+ nChar
);
216 if (system (pSystem
) == -1)
217 OSL_FAIL( "psprint: couldn't remove spool directory" );
220 /* creates a spool directory with a "pidgin random" value based on
221 current system time */
226 osl_getSystemTime( &aCur
);
227 sal_Int32 nRand
= aCur
.Seconds
^ (aCur
.Nanosec
/1000);
229 rtl::OUString aTmpDir
;
230 osl_getTempDirURL( &aTmpDir
.pData
);
234 rtl::OUStringBuffer
aDir( aTmpDir
.getLength() + 16 );
235 aDir
.append( aTmpDir
);
236 aDir
.appendAscii( "/psp" );
238 rtl::OUString aResult
= aDir
.makeStringAndClear();
239 if( osl::Directory::create( aResult
) == osl::FileBase::E_None
)
241 osl::File::setAttributes( aResult
,
242 osl_File_Attribute_OwnWrite
243 | osl_File_Attribute_OwnRead
244 | osl_File_Attribute_OwnExe
);
249 return rtl::OUString();
252 PrinterJob::~PrinterJob ()
254 std::list
< osl::File
* >::iterator pPage
;
255 for (pPage
= maPageList
.begin(); pPage
!= maPageList
.end(); ++pPage
)
257 //(*pPage)->remove();
260 for (pPage
= maHeaderList
.begin(); pPage
!= maHeaderList
.end(); ++pPage
)
262 //(*pPage)->remove();
265 // mpJobHeader->remove();
267 // mpJobTrailer->remove();
270 // XXX should really call osl::remove routines
271 if( !maSpoolDirName
.isEmpty() )
272 removeSpoolDir (maSpoolDirName
);
274 // osl::Directory::remove (maSpoolDirName);
277 static void WriteLocalTimePS( osl::File
*rFile
)
279 TimeValue m_start_time
, tLocal
;
280 oslDateTime date_time
;
281 if (osl_getSystemTime( &m_start_time
) &&
282 osl_getLocalTimeFromSystemTime( &m_start_time
, &tLocal
) &&
283 osl_getDateTimeFromTimeValue( &tLocal
, &date_time
))
288 "%04d-%02d-%02d %02d:%02d:%02d ",
289 date_time
.Year
, date_time
.Month
, date_time
.Day
,
290 date_time
.Hours
, date_time
.Minutes
, date_time
.Seconds
);
291 WritePS( rFile
, ar
);
294 WritePS( rFile
, "Unknown-Time" );
297 static bool isAscii( const rtl::OUString
& rStr
)
299 sal_Int32 nLen
= rStr
.getLength();
300 for( sal_Int32 i
= 0; i
< nLen
; i
++ )
307 PrinterJob::StartJob (
308 const rtl::OUString
& rFileName
,
310 const rtl::OUString
& rJobName
,
311 const rtl::OUString
& rAppName
,
312 const JobData
& rSetupData
,
313 PrinterGfx
* pGraphics
,
317 m_bQuickJob
= bIsQuickJob
;
318 mnMaxWidthPt
= mnMaxHeightPt
= 0;
319 mnLandscapes
= mnPortraits
= 0;
320 m_pGraphics
= pGraphics
;
321 InitPaperSize (rSetupData
);
323 // create file container for document header and trailer
324 maFileName
= rFileName
;
326 maSpoolDirName
= createSpoolDir ();
327 maJobTitle
= rJobName
;
329 rtl::OUString
aExt(".ps");
330 mpJobHeader
= CreateSpoolFile (rtl::OUString("psp_head"), aExt
);
331 mpJobTrailer
= CreateSpoolFile (rtl::OUString("psp_tail"), aExt
);
332 if( ! (mpJobHeader
&& mpJobTrailer
) ) // existing files are removed in destructor
335 // write document header according to Document Structuring Conventions (DSC)
336 WritePS (mpJobHeader
,
338 "%%BoundingBox: (atend)\n" );
340 rtl::OUString aFilterWS
;
342 // Creator (this application)
343 aFilterWS
= WhitespaceToSpace( rAppName
, sal_False
);
344 WritePS (mpJobHeader
, "%%Creator: (");
345 WritePS (mpJobHeader
, aFilterWS
);
346 WritePS (mpJobHeader
, ")\n");
349 osl::Security aSecurity
;
350 rtl::OUString aUserName
;
351 if( aSecurity
.getUserName( aUserName
) )
353 WritePS (mpJobHeader
, "%%For: (");
354 WritePS (mpJobHeader
, aUserName
);
355 WritePS (mpJobHeader
, ")\n");
358 // Creation Date (locale independent local time)
359 WritePS (mpJobHeader
, "%%CreationDate: (");
360 WriteLocalTimePS (mpJobHeader
);
361 WritePS (mpJobHeader
, ")\n");
365 * The title should be clean ascii; rJobName however may
366 * contain any Unicode character. So implement the following
368 * use rJobName, if it contains only ascii
369 * use the filename, if it contains only ascii
372 aFilterWS
= WhitespaceToSpace( rJobName
, sal_False
);
373 rtl::OUString
aTitle( aFilterWS
);
374 if( ! isAscii( aTitle
) )
376 sal_Int32 nIndex
= 0;
377 while( nIndex
!= -1 )
378 aTitle
= rFileName
.getToken( 0, '/', nIndex
);
379 aTitle
= WhitespaceToSpace( aTitle
, sal_False
);
380 if( ! isAscii( aTitle
) )
381 aTitle
= rtl::OUString();
384 maJobTitle
= aFilterWS
;
385 if( !aTitle
.isEmpty() )
387 WritePS (mpJobHeader
, "%%Title: (");
388 WritePS (mpJobHeader
, aTitle
);
389 WritePS (mpJobHeader
, ")\n");
394 sal_Int32 nSz
= getValueOf(GetPostscriptLevel(&rSetupData
), pLevel
);
395 pLevel
[nSz
++] = '\n';
397 WritePS (mpJobHeader
, "%%LanguageLevel: ");
398 WritePS (mpJobHeader
, pLevel
);
401 WritePS (mpJobHeader
, "%%DocumentData: Clean7Bit\n");
402 WritePS (mpJobHeader
, "%%Pages: (atend)\n");
403 WritePS (mpJobHeader
, "%%Orientation: (atend)\n");
404 WritePS (mpJobHeader
, "%%PageOrder: Ascend\n");
405 WritePS (mpJobHeader
, "%%EndComments\n");
408 writeProlog (mpJobHeader
, rSetupData
);
410 // mark last job setup as not set
411 m_aLastJobData
.m_pParser
= NULL
;
412 m_aLastJobData
.m_aContext
.setParser( NULL
);
418 PrinterJob::EndJob ()
420 // no pages ? that really means no print job
421 if( maPageList
.empty() )
424 // write document setup (done here because it
425 // includes the accumulated fonts
427 writeSetup( mpJobHeader
, m_aDocumentJobData
);
428 m_pGraphics
->OnEndJob();
429 if( ! (mpJobHeader
&& mpJobTrailer
) )
432 // write document trailer according to Document Structuring Conventions (DSC)
433 rtl::OStringBuffer
aTrailer(512);
434 aTrailer
.append( "%%Trailer\n" );
435 aTrailer
.append( "%%BoundingBox: 0 0 " );
436 aTrailer
.append( (sal_Int32
)mnMaxWidthPt
);
437 aTrailer
.append( " " );
438 aTrailer
.append( (sal_Int32
)mnMaxHeightPt
);
439 if( mnLandscapes
> mnPortraits
)
440 aTrailer
.append("\n%%Orientation: Landscape");
442 aTrailer
.append("\n%%Orientation: Portrait");
443 aTrailer
.append( "\n%%Pages: " );
444 aTrailer
.append( (sal_Int32
)maPageList
.size() );
445 aTrailer
.append( "\n%%EOF\n" );
446 WritePS (mpJobTrailer
, aTrailer
.getStr());
449 * spool the set of files to their final destination, this is U**X dependent
452 FILE* pDestFILE
= NULL
;
454 /* create a destination either as file or as a pipe */
455 sal_Bool bSpoolToFile
= !maFileName
.isEmpty();
458 const rtl::OString aFileName
= rtl::OUStringToOString (maFileName
,
459 osl_getThreadTextEncoding());
462 int nFile
= open( aFileName
.getStr(), O_CREAT
| O_EXCL
| O_RDWR
, mnFileMode
);
465 pDestFILE
= fdopen( nFile
, "w" );
466 if( pDestFILE
== NULL
)
469 unlink( aFileName
.getStr() );
474 chmod( aFileName
.getStr(), mnFileMode
);
476 if (pDestFILE
== NULL
)
477 pDestFILE
= fopen (aFileName
.getStr(), "w");
479 if (pDestFILE
== NULL
)
484 PrinterInfoManager
& rPrinterInfoManager
= PrinterInfoManager::get ();
485 pDestFILE
= rPrinterInfoManager
.startSpool( m_aLastJobData
.m_aPrinterName
, m_bQuickJob
);
486 if (pDestFILE
== NULL
)
490 /* spool the document parts to the destination */
492 sal_uChar pBuffer
[ nBLOCKSIZE
];
494 AppendPS (pDestFILE
, mpJobHeader
, pBuffer
);
495 mpJobHeader
->close();
497 sal_Bool bSuccess
= sal_True
;
498 std::list
< osl::File
* >::iterator pPageBody
;
499 std::list
< osl::File
* >::iterator pPageHead
;
500 for (pPageBody
= maPageList
.begin(), pPageHead
= maHeaderList
.begin();
501 pPageBody
!= maPageList
.end() && pPageHead
!= maHeaderList
.end();
502 ++pPageBody
, ++pPageHead
)
506 osl::File::RC nError
= (*pPageHead
)->open(osl_File_OpenFlag_Read
);
507 if (nError
== osl::File::E_None
)
509 AppendPS (pDestFILE
, *pPageHead
, pBuffer
);
510 (*pPageHead
)->close();
514 bSuccess
= sal_False
;
517 osl::File::RC nError
= (*pPageBody
)->open(osl_File_OpenFlag_Read
);
518 if (nError
== osl::File::E_None
)
520 AppendPS (pDestFILE
, *pPageBody
, pBuffer
);
521 (*pPageBody
)->close();
525 bSuccess
= sal_False
;
528 AppendPS (pDestFILE
, mpJobTrailer
, pBuffer
);
529 mpJobTrailer
->close();
537 PrinterInfoManager
& rPrinterInfoManager
= PrinterInfoManager::get();
538 if (0 == rPrinterInfoManager
.endSpool( m_aLastJobData
.m_aPrinterName
,
539 maJobTitle
, pDestFILE
, m_aDocumentJobData
, true ))
541 bSuccess
= sal_False
;
549 PrinterJob::AbortJob ()
551 m_pGraphics
->OnEndJob();
556 PrinterJob::InitPaperSize (const JobData
& rJobSetup
)
558 int nRes
= rJobSetup
.m_aContext
.getRenderResolution ();
560 rtl::OUString aPaper
;
562 rJobSetup
.m_aContext
.getPageSize (aPaper
, nWidth
, nHeight
);
564 int nLeft
= 0, nRight
= 0, nUpper
= 0, nLower
= 0;
565 const PPDParser
* pParser
= rJobSetup
.m_aContext
.getParser();
567 pParser
->getMargins (aPaper
, nLeft
, nRight
, nUpper
, nLower
);
572 mnHeightPt
= nHeight
;
574 if( mnWidthPt
> mnMaxWidthPt
)
575 mnMaxWidthPt
= mnWidthPt
;
576 if( mnHeightPt
> mnMaxHeightPt
)
577 mnMaxHeightPt
= mnHeightPt
;
580 mnRMarginPt
= nRight
;
581 mnTMarginPt
= nUpper
;
582 mnBMarginPt
= nLower
;
584 mfXScale
= (double)72.0 / (double)mnResolution
;
585 mfYScale
= -1.0 * (double)72.0 / (double)mnResolution
;
590 PrinterJob::StartPage (const JobData
& rJobSetup
)
592 InitPaperSize (rJobSetup
);
594 rtl::OUString aPageNo
= rtl::OUString::valueOf ((sal_Int32
)maPageList
.size()+1); // sequential page number must start with 1
595 rtl::OUString aExt
= aPageNo
+ rtl::OUString(".ps");
597 osl::File
* pPageHeader
= CreateSpoolFile ( rtl::OUString("psp_pghead"), aExt
);
598 osl::File
* pPageBody
= CreateSpoolFile ( rtl::OUString("psp_pgbody"), aExt
);
600 maHeaderList
.push_back (pPageHeader
);
601 maPageList
.push_back (pPageBody
);
603 if( ! (pPageHeader
&& pPageBody
) )
606 // write page header according to Document Structuring Conventions (DSC)
607 WritePS (pPageHeader
, "%%Page: ");
608 WritePS (pPageHeader
, aPageNo
);
609 WritePS (pPageHeader
, " ");
610 WritePS (pPageHeader
, aPageNo
);
611 WritePS (pPageHeader
, "\n");
613 if( rJobSetup
.m_eOrientation
== orientation::Landscape
)
615 WritePS (pPageHeader
, "%%PageOrientation: Landscape\n");
620 WritePS (pPageHeader
, "%%PageOrientation: Portrait\n");
624 sal_Char pBBox
[256];
627 nChar
= psp::appendStr ("%%PageBoundingBox: ", pBBox
);
628 nChar
+= psp::getValueOf (mnLMarginPt
, pBBox
+ nChar
);
629 nChar
+= psp::appendStr (" ", pBBox
+ nChar
);
630 nChar
+= psp::getValueOf (mnBMarginPt
, pBBox
+ nChar
);
631 nChar
+= psp::appendStr (" ", pBBox
+ nChar
);
632 nChar
+= psp::getValueOf (mnWidthPt
- mnRMarginPt
, pBBox
+ nChar
);
633 nChar
+= psp::appendStr (" ", pBBox
+ nChar
);
634 nChar
+= psp::getValueOf (mnHeightPt
- mnTMarginPt
, pBBox
+ nChar
);
635 nChar
+= psp::appendStr ("\n", pBBox
+ nChar
);
637 WritePS (pPageHeader
, pBBox
);
639 /* #i7262# #i65491# write setup only before first page
640 * (to %%Begin(End)Setup, instead of %%Begin(End)PageSetup)
641 * don't do this in StartJob since the jobsetup there may be
644 bool bWriteFeatures
= true;
645 if( 1 == maPageList
.size() )
647 m_aDocumentJobData
= rJobSetup
;
648 bWriteFeatures
= false;
651 if ( writePageSetup( pPageHeader
, rJobSetup
, bWriteFeatures
) )
653 m_aLastJobData
= rJobSetup
;
661 PrinterJob::EndPage ()
663 m_pGraphics
->OnEndPage();
665 osl::File
* pPageHeader
= maHeaderList
.back();
666 osl::File
* pPageBody
= maPageList
.back();
668 if( ! (pPageBody
&& pPageHeader
) )
671 // copy page to paper and write page trailer according to DSC
673 sal_Char pTrailer
[256];
675 nChar
= psp::appendStr ("grestore grestore\n", pTrailer
);
676 nChar
+= psp::appendStr ("showpage\n", pTrailer
+ nChar
);
677 nChar
+= psp::appendStr ("%%PageTrailer\n\n", pTrailer
+ nChar
);
678 WritePS (pPageBody
, pTrailer
);
680 // this page is done for now, close it to avoid having too many open fd's
682 pPageHeader
->close();
688 struct less_ppd_key
: public ::std::binary_function
<double, double, bool>
690 bool operator()(const PPDKey
* left
, const PPDKey
* right
)
691 { return left
->getOrderDependency() < right
->getOrderDependency(); }
694 static bool writeFeature( osl::File
* pFile
, const PPDKey
* pKey
, const PPDValue
* pValue
, bool bUseIncluseFeature
)
696 if( ! pKey
|| ! pValue
)
699 OStringBuffer
aFeature(256);
700 aFeature
.append( "[{\n" );
701 if( bUseIncluseFeature
)
702 aFeature
.append( "%%IncludeFeature:" );
704 aFeature
.append( "%%BeginFeature:" );
705 aFeature
.append( " *" );
706 aFeature
.append( OUStringToOString( pKey
->getKey(), RTL_TEXTENCODING_ASCII_US
) );
707 aFeature
.append( ' ' );
708 aFeature
.append( OUStringToOString( pValue
->m_aOption
, RTL_TEXTENCODING_ASCII_US
) );
709 if( !bUseIncluseFeature
)
711 aFeature
.append( '\n' );
712 aFeature
.append( OUStringToOString( pValue
->m_aValue
, RTL_TEXTENCODING_ASCII_US
) );
713 aFeature
.append( "\n%%EndFeature" );
715 aFeature
.append( "\n} stopped cleartomark\n" );
716 sal_uInt64 nWritten
= 0;
717 return pFile
->write( aFeature
.getStr(), aFeature
.getLength(), nWritten
)
718 || nWritten
!= (sal_uInt64
)aFeature
.getLength() ? false : true;
721 bool PrinterJob::writeFeatureList( osl::File
* pFile
, const JobData
& rJob
, bool bDocumentSetup
)
723 bool bSuccess
= true;
725 // emit features ordered to OrderDependency
726 // ignore features that are set to default
729 if( rJob
.m_pParser
== rJob
.m_aContext
.getParser() &&
731 ( m_aLastJobData
.m_pParser
== rJob
.m_pParser
|| m_aLastJobData
.m_pParser
== NULL
)
735 int nKeys
= rJob
.m_aContext
.countValuesModified();
736 ::std::vector
< const PPDKey
* > aKeys( nKeys
);
737 for( i
= 0; i
< nKeys
; i
++ )
738 aKeys
[i
] = rJob
.m_aContext
.getModifiedKey( i
);
739 ::std::sort( aKeys
.begin(), aKeys
.end(), less_ppd_key() );
741 for( i
= 0; i
< nKeys
&& bSuccess
; i
++ )
743 const PPDKey
* pKey
= aKeys
[i
];
747 if( pKey
->getSetupType() == PPDKey::DocumentSetup
)
750 if( pKey
->getSetupType() == PPDKey::PageSetup
||
751 pKey
->getSetupType() == PPDKey::AnySetup
)
755 const PPDValue
* pValue
= rJob
.m_aContext
.getValue( pKey
);
757 && pValue
->m_eType
== eInvocation
758 && ( m_aLastJobData
.m_pParser
== NULL
759 || m_aLastJobData
.m_aContext
.getValue( pKey
) != pValue
764 // try to avoid PS level 2 feature commands if level is set to 1
765 if( GetPostscriptLevel( &rJob
) == 1 )
768 ( pValue
->m_aValue
.SearchAscii( "<<" ) != STRING_NOTFOUND
)
770 ( pValue
->m_aValue
.SearchAscii( ">>" ) != STRING_NOTFOUND
);
774 bSuccess
= writeFeature( pFile
, pKey
, pValue
, PrinterInfoManager::get().getUseIncludeFeature() );
785 bool PrinterJob::writePageSetup( osl::File
* pFile
, const JobData
& rJob
, bool bWriteFeatures
)
787 bool bSuccess
= true;
789 WritePS (pFile
, "%%BeginPageSetup\n%\n");
790 if ( bWriteFeatures
)
791 bSuccess
= writeFeatureList( pFile
, rJob
, false );
792 WritePS (pFile
, "%%EndPageSetup\n");
794 sal_Char pTranslate
[128];
797 if( rJob
.m_eOrientation
== orientation::Portrait
)
799 nChar
= psp::appendStr ("gsave\n[", pTranslate
);
800 nChar
+= psp::getValueOfDouble ( pTranslate
+ nChar
, mfXScale
, 5);
801 nChar
+= psp::appendStr (" 0 0 ", pTranslate
+ nChar
);
802 nChar
+= psp::getValueOfDouble ( pTranslate
+ nChar
, mfYScale
, 5);
803 nChar
+= psp::appendStr (" ", pTranslate
+ nChar
);
804 nChar
+= psp::getValueOf (mnRMarginPt
, pTranslate
+ nChar
);
805 nChar
+= psp::appendStr (" ", pTranslate
+ nChar
);
806 nChar
+= psp::getValueOf (mnHeightPt
-mnTMarginPt
,
808 nChar
+= psp::appendStr ("] concat\ngsave\n",
813 nChar
= psp::appendStr ("gsave\n", pTranslate
);
814 nChar
+= psp::appendStr ("[ 0 ", pTranslate
+ nChar
);
815 nChar
+= psp::getValueOfDouble ( pTranslate
+ nChar
, -mfYScale
, 5);
816 nChar
+= psp::appendStr (" ", pTranslate
+ nChar
);
817 nChar
+= psp::getValueOfDouble ( pTranslate
+ nChar
, mfXScale
, 5);
818 nChar
+= psp::appendStr (" 0 ", pTranslate
+ nChar
);
819 nChar
+= psp::getValueOfDouble ( pTranslate
+ nChar
, mnLMarginPt
, 5 );
820 nChar
+= psp::appendStr (" ", pTranslate
+ nChar
);
821 nChar
+= psp::getValueOf (mnBMarginPt
, pTranslate
+ nChar
);
822 nChar
+= psp::appendStr ("] concat\ngsave\n",
826 WritePS (pFile
, pTranslate
);
831 void PrinterJob::writeJobPatch( osl::File
* pFile
, const JobData
& rJobData
)
833 if( ! PrinterInfoManager::get().getUseJobPatch() )
836 const PPDKey
* pKey
= NULL
;
838 if( rJobData
.m_pParser
)
839 pKey
= rJobData
.m_pParser
->getKey( OUString( "JobPatchFile" ) );
843 // order the patch files
844 // according to PPD spec the JobPatchFile options must be int
845 // and should be emitted in order
846 std::list
< sal_Int32
> patch_order
;
847 int nValueCount
= pKey
->countValues();
848 for( int i
= 0; i
< nValueCount
; i
++ )
850 const PPDValue
* pVal
= pKey
->getValue( i
);
851 patch_order
.push_back( pVal
->m_aOption
.ToInt32() );
852 if( patch_order
.back() == 0 && ! pVal
->m_aOption
.EqualsAscii( "0" ) )
854 WritePS( pFile
, "% Warning: left out JobPatchFile option \"" );
855 OString aOption
= OUStringToOString( pVal
->m_aOption
, RTL_TEXTENCODING_ASCII_US
);
856 WritePS( pFile
, aOption
.getStr() );
858 "\"\n% as it violates the PPD spec;\n"
859 "% JobPatchFile options need to be numbered for ordering.\n" );
864 patch_order
.unique();
866 while( patch_order
.begin() != patch_order
.end() )
868 // note: this discards patch files not adhering to the "int" scheme
869 // as there won't be a value for them
870 writeFeature( pFile
, pKey
, pKey
->getValue( OUString::valueOf( patch_order
.front() ) ), false );
871 patch_order
.pop_front();
875 bool PrinterJob::writeProlog (osl::File
* pFile
, const JobData
& rJobData
)
877 WritePS( pFile
, "%%BeginProlog\n" );
879 // JobPatchFile feature needs to be emitted at begin of prolog
880 writeJobPatch( pFile
, rJobData
);
882 static const sal_Char pProlog
[] = {
883 "%%BeginResource: procset PSPrint-Prolog 1.0 0\n"
884 "/ISO1252Encoding [\n"
885 "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
886 "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
887 "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
888 "/.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef\n"
889 "/space /exclam /quotedbl /numbersign /dollar /percent /ampersand /quotesingle\n"
890 "/parenleft /parenright /asterisk /plus /comma /hyphen /period /slash\n"
891 "/zero /one /two /three /four /five /six /seven\n"
892 "/eight /nine /colon /semicolon /less /equal /greater /question\n"
893 "/at /A /B /C /D /E /F /G\n"
894 "/H /I /J /K /L /M /N /O\n"
895 "/P /Q /R /S /T /U /V /W\n"
896 "/X /Y /Z /bracketleft /backslash /bracketright /asciicircum /underscore\n"
897 "/grave /a /b /c /d /e /f /g\n"
898 "/h /i /j /k /l /m /n /o\n"
899 "/p /q /r /s /t /u /v /w\n"
900 "/x /y /z /braceleft /bar /braceright /asciitilde /unused\n"
901 "/Euro /unused /quotesinglbase /florin /quotedblbase /ellipsis /dagger /daggerdbl\n"
902 "/circumflex /perthousand /Scaron /guilsinglleft /OE /unused /Zcaron /unused\n"
903 "/unused /quoteleft /quoteright /quotedblleft /quotedblright /bullet /endash /emdash\n"
904 "/tilde /trademark /scaron /guilsinglright /oe /unused /zcaron /Ydieresis\n"
905 "/space /exclamdown /cent /sterling /currency /yen /brokenbar /section\n"
906 "/dieresis /copyright /ordfeminine /guillemotleft /logicalnot /hyphen /registered /macron\n"
907 "/degree /plusminus /twosuperior /threesuperior /acute /mu /paragraph /periodcentered\n"
908 "/cedilla /onesuperior /ordmasculine /guillemotright /onequarter /onehalf /threequarters /questiondown\n"
909 "/Agrave /Aacute /Acircumflex /Atilde /Adieresis /Aring /AE /Ccedilla\n"
910 "/Egrave /Eacute /Ecircumflex /Edieresis /Igrave /Iacute /Icircumflex /Idieresis\n"
911 "/Eth /Ntilde /Ograve /Oacute /Ocircumflex /Otilde /Odieresis /multiply\n"
912 "/Oslash /Ugrave /Uacute /Ucircumflex /Udieresis /Yacute /Thorn /germandbls\n"
913 "/agrave /aacute /acircumflex /atilde /adieresis /aring /ae /ccedilla\n"
914 "/egrave /eacute /ecircumflex /edieresis /igrave /iacute /icircumflex /idieresis\n"
915 "/eth /ntilde /ograve /oacute /ocircumflex /otilde /odieresis /divide\n"
916 "/oslash /ugrave /uacute /ucircumflex /udieresis /yacute /thorn /ydieresis] def\n"
918 "/psp_definefont { exch dup findfont dup length dict begin { 1 index /FID ne\n"
919 "{ def } { pop pop } ifelse } forall /Encoding 3 -1 roll def\n"
920 "currentdict end exch pop definefont pop } def\n"
922 "/pathdict dup 8 dict def load begin\n"
923 "/rcmd { { currentfile 1 string readstring pop 0 get dup 32 gt { exit }\n"
924 "{ pop } ifelse } loop dup 126 eq { pop exit } if 65 sub dup 16#3 and 1\n"
925 "add exch dup 16#C and -2 bitshift 16#3 and 1 add exch 16#10 and 16#10\n"
926 "eq 3 1 roll exch } def\n"
927 "/rhex { dup 1 sub exch currentfile exch string readhexstring pop dup 0\n"
928 "get dup 16#80 and 16#80 eq dup 3 1 roll { 16#7f and } if 2 index 0 3\n"
929 "-1 roll put 3 1 roll 0 0 1 5 -1 roll { 2 index exch get add 256 mul }\n"
930 "for 256 div exch pop exch { neg } if } def\n"
931 "/xcmd { rcmd exch rhex exch rhex exch 5 -1 roll add exch 4 -1 roll add\n"
932 "1 index 1 index 5 -1 roll { moveto } { lineto } ifelse } def end\n"
933 "/readpath { 0 0 pathdict begin { xcmd } loop end pop pop } def\n"
935 "systemdict /languagelevel known not {\n"
936 "/xshow { exch dup length 0 1 3 -1 roll 1 sub { dup 3 index exch get\n"
937 "exch 2 index exch get 1 string dup 0 4 -1 roll put currentpoint 3 -1\n"
938 "roll show moveto 0 rmoveto } for pop pop } def\n"
939 "/rectangle { 4 -2 roll moveto 1 index 0 rlineto 0 exch rlineto neg 0\n"
940 "rlineto closepath } def\n"
941 "/rectfill { rectangle fill } def\n"
942 "/rectstroke { rectangle stroke } def } if\n"
943 "/bshow { currentlinewidth 3 1 roll currentpoint 3 index show moveto\n"
944 "setlinewidth false charpath stroke setlinewidth } def\n"
945 "/bxshow { currentlinewidth 4 1 roll setlinewidth exch dup length 1 sub\n"
946 "0 1 3 -1 roll { 1 string 2 index 2 index get 1 index exch 0 exch put dup\n"
947 "currentpoint 3 -1 roll show moveto currentpoint 3 -1 roll false charpath\n"
948 "stroke moveto 2 index exch get 0 rmoveto } for pop pop setlinewidth } def\n"
950 "/psp_lzwfilter { currentfile /ASCII85Decode filter /LZWDecode filter } def\n"
951 "/psp_ascii85filter { currentfile /ASCII85Decode filter } def\n"
952 "/psp_lzwstring { psp_lzwfilter 1024 string readstring } def\n"
953 "/psp_ascii85string { psp_ascii85filter 1024 string readstring } def\n"
955 "/psp_bitspercomponent { 3 eq { 1 }{ 8 } ifelse } def\n"
956 "/psp_decodearray { [ [0 1 0 1 0 1] [0 255] [0 1] [0 255] ] exch get }\n"
958 "/ImageType 1 put dup\n"
959 "/Width 7 -1 roll put dup\n"
960 "/Height 5 index put dup\n"
961 "/BitsPerComponent 4 index psp_bitspercomponent put dup\n"
962 "/Decode 5 -1 roll psp_decodearray put dup\n"
963 "/ImageMatrix [1 0 0 1 0 0] dup 5 8 -1 roll put put dup\n"
964 "/DataSource 4 -1 roll 1 eq { psp_lzwfilter } { psp_ascii85filter } ifelse put\n"
969 WritePS (pFile
, pProlog
);
974 bool PrinterJob::writeSetup( osl::File
* pFile
, const JobData
& rJob
)
976 WritePS (pFile
, "%%BeginSetup\n%\n");
979 std::list
< rtl::OString
> aFonts
[2];
980 m_pGraphics
->writeResources( pFile
, aFonts
[0], aFonts
[1] );
982 for( int i
= 0; i
< 2; i
++ )
984 if( !aFonts
[i
].empty() )
986 std::list
< rtl::OString
>::const_iterator it
= aFonts
[i
].begin();
987 rtl::OStringBuffer
aLine( 256 );
989 aLine
.append( "%%DocumentSuppliedResources: font " );
991 aLine
.append( "%%DocumentNeededResources: font " );
993 aLine
.append( "\n" );
994 WritePS ( pFile
, aLine
.getStr() );
995 while( (++it
) != aFonts
[i
].end() )
998 aLine
.append( "%%+ font " );
1000 aLine
.append( "\n" );
1001 WritePS ( pFile
, aLine
.getStr() );
1006 bool bSuccess
= true;
1007 // in case of external print dialog the number of copies is prepended
1008 // to the job, let us not complicate things by emitting our own copy count
1009 bool bExternalDialog
= PrinterInfoManager::get().checkFeatureToken( GetPrinterName(), "external_dialog" );
1010 if( ! bExternalDialog
&& rJob
.m_nCopies
> 1 )
1013 rtl::OStringBuffer
aLine(RTL_CONSTASCII_STRINGPARAM("/#copies "));
1014 aLine
.append(static_cast<sal_Int32
>(rJob
.m_nCopies
));
1015 aLine
.append(RTL_CONSTASCII_STRINGPARAM(" def\n"));
1016 sal_uInt64 nWritten
= 0;
1017 bSuccess
= pFile
->write(aLine
.getStr(), aLine
.getLength(), nWritten
)
1018 || nWritten
!= static_cast<sal_uInt64
>(aLine
.getLength()) ?
1021 if( bSuccess
&& GetPostscriptLevel( &rJob
) >= 2 )
1022 WritePS (pFile
, "<< /NumCopies null /Policies << /NumCopies 1 >> >> setpagedevice\n" );
1025 bool bFeatureSuccess
= writeFeatureList( pFile
, rJob
, true );
1027 WritePS (pFile
, "%%EndSetup\n");
1029 return bSuccess
&& bFeatureSuccess
;
1032 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */