xref: /trunk/main/vcl/unx/generic/gdi/salprnpsp.cxx (revision 74cbd1f1)
1  /**************************************************************
2   *
3   * Licensed to the Apache Software Foundation (ASF) under one
4   * or more contributor license agreements.  See the NOTICE file
5   * distributed with this work for additional information
6   * regarding copyright ownership.  The ASF licenses this file
7   * to you under the Apache License, Version 2.0 (the
8   * "License"); you may not use this file except in compliance
9   * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   *
20   *************************************************************/
21  
22  
23  
24  // MARKER(update_precomp.py): autogen include statement, do not remove
25  #include "precompiled_vcl.hxx"
26  
27  /**
28    this file implements the sal printer interface ( SalPrinter, SalInfoPrinter
29    and some printer relevant methods of SalInstance and SalGraphicsData )
30  
31    as aunderlying library the printer features of psprint are used.
32  
33    The query methods of a SalInfoPrinter are implemented by querying psprint
34  
35    The job methods of a SalPrinter are implemented by calling psprint
36    printer job functions.
37   */
38  
39  #include <unistd.h>
40  #include <sys/wait.h>
41  #include <sys/stat.h>
42  
43  #include "rtl/ustring.hxx"
44  
45  #include "osl/module.h"
46  
47  #include "vcl/svapp.hxx"
48  #include "vcl/print.hxx"
49  #include "vcl/pdfwriter.hxx"
50  #include "vcl/printerinfomanager.hxx"
51  
52  #include <unx/salunx.h>
53  #include "unx/saldisp.hxx"
54  #include "unx/salinst.h"
55  #include "unx/salprn.h"
56  #include "unx/salframe.h"
57  #include "unx/pspgraphics.h"
58  #include "unx/saldata.hxx"
59  
60  #include "jobset.h"
61  #include "print.h"
62  #include "salptype.hxx"
63  
64  using namespace psp;
65  using namespace rtl;
66  using namespace com::sun::star;
67  
68  /*
69   *	static helpers
70   */
71  
72  static oslModule driverLib					= NULL;
73  extern "C"
74  {
75  typedef int(*setupFunction)(PrinterInfo&);
76  static setupFunction pSetupFunction         = NULL;
77  typedef int(*faxFunction)(String&);
78  static faxFunction pFaxNrFunction           = NULL;
79  }
80  
getPdfDir(const PrinterInfo & rInfo)81  static String getPdfDir( const PrinterInfo& rInfo )
82  {
83  	String aDir;
84      sal_Int32 nIndex = 0;
85      while( nIndex != -1 )
86  	{
87  		OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
88  		if( ! aToken.compareToAscii( "pdf=", 4 ) )
89  		{
90              sal_Int32 nPos = 0;
91  			aDir = aToken.getToken( 1, '=', nPos );
92  			if( ! aDir.Len() )
93  				aDir = String( ByteString( getenv( "HOME" ) ), osl_getThreadTextEncoding() );
94  			break;
95  		}
96  	}
97  	return aDir;
98  }
99  
getPaLib()100  static void getPaLib()
101  {
102  	if( ! driverLib )
103  	{
104          driverLib	= osl_loadAsciiModuleRelative( (oslGenericFunction)getPaLib, _XSALSET_LIBNAME, SAL_LOADMODULE_DEFAULT );
105          if ( !driverLib )
106          {
107              return;
108          }
109  
110          pSetupFunction	= (setupFunction)osl_getAsciiFunctionSymbol( driverLib, "Sal_SetupPrinterDriver" );
111          if ( !pSetupFunction )
112              fprintf( stderr, "could not resolve Sal_SetupPrinterDriver\n" );
113  
114          pFaxNrFunction = (faxFunction)osl_getAsciiFunctionSymbol( driverLib, "Sal_queryFaxNumber" );
115          if ( !pFaxNrFunction )
116              fprintf( stderr, "could not resolve Sal_queryFaxNumber\n" );
117  	}
118  }
119  
PtTo10Mu(int nPoints)120  inline int PtTo10Mu( int nPoints ) { return (int)((((double)nPoints)*35.27777778)+0.5); }
121  
TenMuToPt(int nUnits)122  inline int TenMuToPt( int nUnits ) { return (int)((((double)nUnits)/35.27777778)+0.5); }
123  
copyJobDataToJobSetup(ImplJobSetup * pJobSetup,JobData & rData)124  static void copyJobDataToJobSetup( ImplJobSetup* pJobSetup, JobData& rData )
125  {
126  	pJobSetup->meOrientation	= (Orientation)(rData.m_eOrientation == orientation::Landscape ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT);
127  
128  	// copy page size
129  	String aPaper;
130  	int width, height;
131  
132  	rData.m_aContext.getPageSize( aPaper, width, height );
133  	pJobSetup->mePaperFormat	= PaperInfo::fromPSName(OUStringToOString( aPaper, RTL_TEXTENCODING_ISO_8859_1 ));
134  
135  	pJobSetup->mnPaperWidth		= 0;
136  	pJobSetup->mnPaperHeight	= 0;
137  	if( pJobSetup->mePaperFormat == PAPER_USER )
138  	{
139  		// transform to 100dth mm
140  		width				= PtTo10Mu( width );
141  		height				= PtTo10Mu( height );
142  
143          if( rData.m_eOrientation == psp::orientation::Portrait )
144          {
145              pJobSetup->mnPaperWidth	= width;
146              pJobSetup->mnPaperHeight= height;
147          }
148          else
149          {
150              pJobSetup->mnPaperWidth	= height;
151              pJobSetup->mnPaperHeight= width;
152          }
153  	}
154  
155  	// copy input slot
156  	const PPDKey* pKey = NULL;
157  	const PPDValue* pValue = NULL;
158  
159      pJobSetup->mnPaperBin = 0;
160      if( rData.m_pParser )
161  	    pKey					= rData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) );
162      if( pKey )
163          pValue					= rData.m_aContext.getValue( pKey );
164      if( pKey && pValue )
165      {
166          for( pJobSetup->mnPaperBin = 0;
167               pValue != pKey->getValue( pJobSetup->mnPaperBin ) &&
168                   pJobSetup->mnPaperBin < pKey->countValues();
169               pJobSetup->mnPaperBin++ )
170              ;
171          if( pJobSetup->mnPaperBin >= pKey->countValues() )
172              pJobSetup->mnPaperBin = 0;
173      }
174  
175      // copy duplex
176      pKey = NULL;
177      pValue = NULL;
178  
179      pJobSetup->meDuplexMode = DUPLEX_UNKNOWN;
180      if( rData.m_pParser )
181          pKey = rData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) );
182      if( pKey )
183          pValue = rData.m_aContext.getValue( pKey );
184      if( pKey && pValue )
185      {
186          if( pValue->m_aOption.EqualsIgnoreCaseAscii( "None" ) ||
187              pValue->m_aOption.EqualsIgnoreCaseAscii( "Simplex", 0, 7 )
188             )
189          {
190              pJobSetup->meDuplexMode = DUPLEX_OFF;
191          }
192          else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexNoTumble" ) )
193          {
194              pJobSetup->meDuplexMode = DUPLEX_LONGEDGE;
195          }
196          else if( pValue->m_aOption.EqualsIgnoreCaseAscii( "DuplexTumble" ) )
197          {
198              pJobSetup->meDuplexMode = DUPLEX_SHORTEDGE;
199          }
200      }
201  
202  	// copy the whole context
203  	if( pJobSetup->mpDriverData )
204  		rtl_freeMemory( pJobSetup->mpDriverData );
205  
206  	int nBytes;
207  	void* pBuffer = NULL;
208  	if( rData.getStreamBuffer( pBuffer, nBytes ) )
209  	{
210  		pJobSetup->mnDriverDataLen = nBytes;
211  		pJobSetup->mpDriverData = (sal_uInt8*)pBuffer;
212  	}
213  	else
214  	{
215  		pJobSetup->mnDriverDataLen = 0;
216  		pJobSetup->mpDriverData = NULL;
217  	}
218  }
219  
passFileToCommandLine(const String & rFilename,const String & rCommandLine,bool bRemoveFile=true)220  static bool passFileToCommandLine( const String& rFilename, const String& rCommandLine, bool bRemoveFile = true )
221  {
222  	bool bSuccess = false;
223  
224  	rtl_TextEncoding aEncoding = osl_getThreadTextEncoding();
225  	ByteString aCmdLine( rCommandLine, aEncoding );
226  	ByteString aFilename( rFilename, aEncoding );
227  
228  	bool bPipe = aCmdLine.Search( "(TMP)" ) != STRING_NOTFOUND ? false : true;
229  
230  	// setup command line for exec
231  	if( ! bPipe )
232  		while( aCmdLine.SearchAndReplace( "(TMP)", aFilename ) != STRING_NOTFOUND )
233  			;
234  
235  #if OSL_DEBUG_LEVEL > 1
236  	fprintf( stderr, "%s commandline: \"%s\"\n",
237  			 bPipe ? "piping to" : "executing",
238  			 aCmdLine.GetBuffer() );
239      struct stat aStat;
240      if( stat( aFilename.GetBuffer(), &aStat ) )
241          fprintf( stderr, "stat( %s ) failed\n", aFilename.GetBuffer() );
242      fprintf( stderr, "Tmp file %s has modes: 0%03lo\n", aFilename.GetBuffer(), (long)aStat.st_mode );
243  #endif
244  	const char* argv[4];
245  	if( ! ( argv[ 0 ] = getenv( "SHELL" ) ) )
246  		argv[ 0 ] = "/bin/sh";
247  	argv[ 1 ] = "-c";
248  	argv[ 2 ] = aCmdLine.GetBuffer();
249  	argv[ 3 ] = 0;
250  
251  	bool bHavePipes = false;
252  	int pid, fd[2];
253  
254  	if( bPipe )
255  		bHavePipes = pipe( fd ) ? false : true;
256  	if( ( pid = fork() ) > 0 )
257  	{
258  		if( bPipe && bHavePipes )
259  		{
260  			close( fd[0] );
261  			char aBuffer[ 2048 ];
262  			FILE* fp = fopen( aFilename.GetBuffer(), "r" );
263  			while( fp && ! feof( fp ) )
264  			{
265  				int nBytes = fread( aBuffer, 1, sizeof( aBuffer ), fp );
266  				if( nBytes )
267  					write( fd[ 1 ], aBuffer, nBytes );
268  			}
269  			fclose( fp );
270  			close( fd[ 1 ] );
271  		}
272  		int status = 0;
273  		waitpid( pid, &status, 0 );
274  		if( ! status )
275  			bSuccess = true;
276  	}
277  	else if( ! pid )
278  	{
279  		if( bPipe && bHavePipes )
280  		{
281  			close( fd[1] );
282  			if( fd[0] != STDIN_FILENO ) // not probable, but who knows :)
283  				dup2( fd[0], STDIN_FILENO );
284  		}
285  		execv( argv[0], const_cast<char**>(argv) );
286  		fprintf( stderr, "failed to execute \"%s\"\n", aCmdLine.GetBuffer() );
287  		_exit( 1 );
288  	}
289  	else
290  		fprintf( stderr, "failed to fork\n" );
291  
292  	// clean up the mess
293      if( bRemoveFile )
294          unlink( aFilename.GetBuffer() );
295  
296  	return bSuccess;
297  }
298  
sendAFax(const String & rFaxNumber,const String & rFileName,const String & rCommand)299  static bool sendAFax( const String& rFaxNumber, const String& rFileName, const String& rCommand )
300  {
301      std::list< OUString > aFaxNumbers;
302  
303  	if( ! rFaxNumber.Len() )
304  	{
305  		getPaLib();
306  		if( pFaxNrFunction )
307  		{
308  			String aNewNr;
309  			if( pFaxNrFunction( aNewNr ) )
310  				aFaxNumbers.push_back( OUString( aNewNr ) );
311  		}
312  	}
313      else
314      {
315          sal_Int32 nIndex = 0;
316          OUString aFaxes( rFaxNumber );
317          OUString aBeginToken( RTL_CONSTASCII_USTRINGPARAM("<Fax#>") );
318          OUString aEndToken( RTL_CONSTASCII_USTRINGPARAM("</Fax#>") );
319          while( nIndex != -1 )
320          {
321              nIndex = aFaxes.indexOf( aBeginToken, nIndex );
322              if( nIndex != -1 )
323              {
324                  sal_Int32 nBegin = nIndex + aBeginToken.getLength();
325                  nIndex = aFaxes.indexOf( aEndToken, nIndex );
326                  if( nIndex != -1 )
327                  {
328                      aFaxNumbers.push_back( aFaxes.copy( nBegin, nIndex-nBegin ) );
329                      nIndex += aEndToken.getLength();
330                  }
331              }
332          }
333      }
334  
335      bool bSuccess = true;
336      if( aFaxNumbers.begin() != aFaxNumbers.end() )
337  	{
338          while( aFaxNumbers.begin() != aFaxNumbers.end() && bSuccess )
339          {
340              String aCmdLine( rCommand );
341              String aFaxNumber( aFaxNumbers.front() );
342              aFaxNumbers.pop_front();
343              while( aCmdLine.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "(PHONE)" ) ), aFaxNumber ) != STRING_NOTFOUND )
344                  ;
345  #if OSL_DEBUG_LEVEL > 1
346              fprintf( stderr, "sending fax to \"%s\"\n", OUStringToOString( aFaxNumber, osl_getThreadTextEncoding() ).getStr() );
347  #endif
348              bSuccess = passFileToCommandLine( rFileName, aCmdLine, false );
349          }
350  	}
351      else
352          bSuccess = false;
353  
354      // clean up temp file
355      unlink( ByteString( rFileName, osl_getThreadTextEncoding() ).GetBuffer() );
356  
357      return bSuccess;
358  }
359  
createPdf(const String & rToFile,const String & rFromFile,const String & rCommandLine)360  static bool createPdf( const String& rToFile, const String& rFromFile, const String& rCommandLine )
361  {
362  	String aCommandLine( rCommandLine );
363  	while( aCommandLine.SearchAndReplace( String( RTL_CONSTASCII_USTRINGPARAM( "(OUTFILE)" ) ), rToFile ) != STRING_NOTFOUND )
364  		;
365  	return passFileToCommandLine( rFromFile, aCommandLine );
366  }
367  
368  /*
369   *	SalInstance
370   */
371  
372  // -----------------------------------------------------------------------
373  
CreateInfoPrinter(SalPrinterQueueInfo * pQueueInfo,ImplJobSetup * pJobSetup)374  SalInfoPrinter* X11SalInstance::CreateInfoPrinter( SalPrinterQueueInfo*	pQueueInfo,
375                                                     ImplJobSetup*			pJobSetup )
376  {
377      mbPrinterInit = true;
378  	// create and initialize SalInfoPrinter
379  	PspSalInfoPrinter* pPrinter = new PspSalInfoPrinter;
380  
381  	if( pJobSetup )
382  	{
383  		PrinterInfoManager& rManager( PrinterInfoManager::get() );
384  		PrinterInfo aInfo( rManager.getPrinterInfo( pQueueInfo->maPrinterName ) );
385  		pPrinter->m_aJobData = aInfo;
386  		pPrinter->m_aPrinterGfx.Init( pPrinter->m_aJobData );
387  
388  		if( pJobSetup->mpDriverData )
389  			JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aInfo );
390  
391  		pJobSetup->mnSystem			= JOBSETUP_SYSTEM_UNIX;
392  		pJobSetup->maPrinterName	= pQueueInfo->maPrinterName;
393  		pJobSetup->maDriver			= aInfo.m_aDriverName;
394  		copyJobDataToJobSetup( pJobSetup, aInfo );
395  
396          // set/clear backwards compatibility flag
397          bool bStrictSO52Compatibility = false;
398          std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it =
399              pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) );
400  
401          if( compat_it != pJobSetup->maValueMap.end() )
402          {
403              if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) )
404                  bStrictSO52Compatibility = true;
405          }
406          pPrinter->m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility );
407  	}
408  
409  
410  	return pPrinter;
411  }
412  
413  // -----------------------------------------------------------------------
414  
DestroyInfoPrinter(SalInfoPrinter * pPrinter)415  void X11SalInstance::DestroyInfoPrinter( SalInfoPrinter* pPrinter )
416  {
417  	delete pPrinter;
418  }
419  
420  // -----------------------------------------------------------------------
421  
CreatePrinter(SalInfoPrinter * pInfoPrinter)422  SalPrinter* X11SalInstance::CreatePrinter( SalInfoPrinter* pInfoPrinter )
423  {
424      mbPrinterInit = true;
425  	// create and initialize SalPrinter
426  	PspSalPrinter* pPrinter = new PspSalPrinter( pInfoPrinter );
427  	pPrinter->m_aJobData = static_cast<PspSalInfoPrinter*>(pInfoPrinter)->m_aJobData;
428  
429  	return pPrinter;
430  }
431  
432  // -----------------------------------------------------------------------
433  
DestroyPrinter(SalPrinter * pPrinter)434  void X11SalInstance::DestroyPrinter( SalPrinter* pPrinter )
435  {
436  	delete pPrinter;
437  }
438  
439  // -----------------------------------------------------------------------
440  
GetPrinterQueueInfo(ImplPrnQueueList * pList)441  void X11SalInstance::GetPrinterQueueInfo( ImplPrnQueueList* pList )
442  {
443      mbPrinterInit = true;
444  	PrinterInfoManager& rManager( PrinterInfoManager::get() );
445      static const char* pNoSyncDetection = getenv( "SAL_DISABLE_SYNCHRONOUS_PRINTER_DETECTION" );
446      if( ! pNoSyncDetection || ! *pNoSyncDetection )
447      {
448          // #i62663# synchronize possible asynchronouse printer detection now
449          rManager.checkPrintersChanged( true );
450      }
451  	::std::list< OUString > aPrinters;
452  	rManager.listPrinters( aPrinters );
453  
454  	for( ::std::list< OUString >::iterator it = aPrinters.begin(); it != aPrinters.end(); ++it )
455  	{
456  		const PrinterInfo& rInfo( rManager.getPrinterInfo( *it ) );
457  		// Neuen Eintrag anlegen
458  		SalPrinterQueueInfo* pInfo = new SalPrinterQueueInfo;
459  		pInfo->maPrinterName	= *it;
460  		pInfo->maDriver			= rInfo.m_aDriverName;
461  		pInfo->maLocation		= rInfo.m_aLocation;
462  		pInfo->maComment      	= rInfo.m_aComment;
463  		pInfo->mpSysData		= NULL;
464  
465          sal_Int32 nIndex = 0;
466          while( nIndex != -1 )
467  		{
468  			String aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
469  			if( aToken.CompareToAscii( "pdf=", 4 ) == COMPARE_EQUAL )
470  			{
471  				pInfo->maLocation = getPdfDir( rInfo );
472  				break;
473  			}
474  		}
475  
476  		pList->Add( pInfo );
477  	}
478  }
479  
480  // -----------------------------------------------------------------------
481  
DeletePrinterQueueInfo(SalPrinterQueueInfo * pInfo)482  void X11SalInstance::DeletePrinterQueueInfo( SalPrinterQueueInfo* pInfo )
483  {
484  	delete pInfo;
485  }
486  
487  // -----------------------------------------------------------------------
488  
GetPrinterQueueState(SalPrinterQueueInfo *)489  void X11SalInstance::GetPrinterQueueState( SalPrinterQueueInfo* )
490  {
491      mbPrinterInit = true;
492  }
493  
494  // -----------------------------------------------------------------------
495  
GetDefaultPrinter()496  String X11SalInstance::GetDefaultPrinter()
497  {
498      mbPrinterInit = true;
499  	PrinterInfoManager& rManager( PrinterInfoManager::get() );
500  	return rManager.getDefaultPrinter();
501  }
502  
503  // =======================================================================
504  
PspSalInfoPrinter()505  PspSalInfoPrinter::PspSalInfoPrinter()
506  {
507  	m_pGraphics = NULL;
508      m_bPapersInit = false;
509  }
510  
511  // -----------------------------------------------------------------------
512  
~PspSalInfoPrinter()513  PspSalInfoPrinter::~PspSalInfoPrinter()
514  {
515  	if( m_pGraphics )
516  	{
517  		delete m_pGraphics;
518  		m_pGraphics = NULL;
519  	}
520  }
521  
522  // -----------------------------------------------------------------------
523  
InitPaperFormats(const ImplJobSetup *)524  void PspSalInfoPrinter::InitPaperFormats( const ImplJobSetup* )
525  {
526      m_aPaperFormats.clear();
527      m_bPapersInit = true;
528  
529      if( m_aJobData.m_pParser )
530      {
531          const PPDKey* pKey = m_aJobData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
532          if( pKey )
533          {
534              int nValues = pKey->countValues();
535              for( int i = 0; i < nValues; i++ )
536              {
537                  const PPDValue* pValue = pKey->getValue( i );
538                  int nWidth = 0, nHeight = 0;
539                  m_aJobData.m_pParser->getPaperDimension( pValue->m_aOption, nWidth, nHeight );
540                  PaperInfo aInfo(PtTo10Mu( nWidth ), PtTo10Mu( nHeight ));
541                  m_aPaperFormats.push_back( aInfo );
542              }
543          }
544      }
545  }
546  
547  // -----------------------------------------------------------------------
548  
GetLandscapeAngle(const ImplJobSetup *)549  int PspSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* )
550  {
551      return 900;
552  }
553  
554  // -----------------------------------------------------------------------
555  
GetGraphics()556  SalGraphics* PspSalInfoPrinter::GetGraphics()
557  {
558  	// return a valid pointer only once
559  	// the reasoning behind this is that we could have different
560  	// SalGraphics that can run in multiple threads
561  	// (future plans)
562  	SalGraphics* pRet = NULL;
563  	if( ! m_pGraphics )
564  	{
565  		m_pGraphics = new PspGraphics( &m_aJobData, &m_aPrinterGfx, NULL, false, this );
566          m_pGraphics->SetLayout( 0 );
567  		pRet = m_pGraphics;
568  	}
569  	return pRet;
570  }
571  
572  // -----------------------------------------------------------------------
573  
ReleaseGraphics(SalGraphics * pGraphics)574  void PspSalInfoPrinter::ReleaseGraphics( SalGraphics* pGraphics )
575  {
576  	if( pGraphics == m_pGraphics )
577  	{
578  		delete pGraphics;
579  		m_pGraphics = NULL;
580  	}
581  	return;
582  }
583  
584  // -----------------------------------------------------------------------
585  
Setup(SalFrame * pFrame,ImplJobSetup * pJobSetup)586  sal_Bool PspSalInfoPrinter::Setup( SalFrame* pFrame, ImplJobSetup* pJobSetup )
587  {
588  	if( ! pFrame || ! pJobSetup )
589  		return sal_False;
590  
591  	getPaLib();
592  
593  	if( ! pSetupFunction )
594  		return sal_False;
595  
596  	PrinterInfoManager& rManager = PrinterInfoManager::get();
597  
598  	PrinterInfo aInfo( rManager.getPrinterInfo( pJobSetup->maPrinterName ) );
599  	if ( pJobSetup->mpDriverData )
600      {
601  		SetData( ~0, pJobSetup );
602  		JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aInfo );
603      }
604  
605  	if( pSetupFunction( aInfo ) )
606  	{
607  		rtl_freeMemory( pJobSetup->mpDriverData );
608  		pJobSetup->mpDriverData = NULL;
609  
610  		int nBytes;
611  		void* pBuffer = NULL;
612  		aInfo.getStreamBuffer( pBuffer, nBytes );
613  		pJobSetup->mnDriverDataLen	= nBytes;
614  		pJobSetup->mpDriverData		= (sal_uInt8*)pBuffer;
615  
616  		// copy everything to job setup
617  		copyJobDataToJobSetup( pJobSetup, aInfo );
618  		JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData );
619          return sal_True;
620  	}
621  	return sal_False;
622  }
623  
624  // -----------------------------------------------------------------------
625  
626  // This function gets the driver data and puts it into pJobSetup
627  // If pJobSetup->mpDriverData is NOT NULL, then the independend
628  // data should be merged into the driver data
629  // If pJobSetup->mpDriverData IS NULL, then the driver defaults
630  // should be merged into the independent data
SetPrinterData(ImplJobSetup * pJobSetup)631  sal_Bool PspSalInfoPrinter::SetPrinterData( ImplJobSetup* pJobSetup )
632  {
633      // set/clear backwards compatibility flag
634      bool bStrictSO52Compatibility = false;
635      std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it =
636          pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) );
637  
638      if( compat_it != pJobSetup->maValueMap.end() )
639      {
640          if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) )
641              bStrictSO52Compatibility = true;
642      }
643      m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility );
644  
645  	if( pJobSetup->mpDriverData )
646  		return SetData( ~0, pJobSetup );
647  
648  	copyJobDataToJobSetup( pJobSetup, m_aJobData );
649  
650      return sal_True;
651  }
652  
653  // -----------------------------------------------------------------------
654  
655  // This function merges the independ driver data
656  // and sets the new independ data in pJobSetup
657  // Only the data must be changed, where the bit
658  // in nGetDataFlags is set
SetData(sal_uLong nSetDataFlags,ImplJobSetup * pJobSetup)659  sal_Bool PspSalInfoPrinter::SetData(
660  	sal_uLong nSetDataFlags,
661  	ImplJobSetup* pJobSetup )
662  {
663  	JobData aData;
664  	JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
665  
666  	if( aData.m_pParser )
667  	{
668  		const PPDKey* pKey;
669  		const PPDValue* pValue;
670  
671  		// merge papersize if necessary
672  		if( nSetDataFlags & SAL_JOBSET_PAPERSIZE )
673  		{
674              int nWidth, nHeight;
675              if( pJobSetup->meOrientation == ORIENTATION_PORTRAIT )
676              {
677                  nWidth	= pJobSetup->mnPaperWidth;
678                  nHeight	= pJobSetup->mnPaperHeight;
679              }
680              else
681              {
682                  nWidth	= pJobSetup->mnPaperHeight;
683                  nHeight	= pJobSetup->mnPaperWidth;
684              }
685  			String aPaper;
686  
687              if( pJobSetup->mePaperFormat == PAPER_USER )
688                  aPaper = aData.m_pParser->matchPaper(
689                      TenMuToPt( pJobSetup->mnPaperWidth ),
690                      TenMuToPt( pJobSetup->mnPaperHeight ) );
691              else
692  				aPaper = rtl::OStringToOUString(PaperInfo::toPSName(pJobSetup->mePaperFormat), RTL_TEXTENCODING_ISO_8859_1);
693  
694  			pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "PageSize" ) ) );
695  			pValue = pKey ? pKey->getValueCaseInsensitive( aPaper ) : NULL;
696  
697              // some PPD files do not specify the standard paper names (e.g. C5 instead of EnvC5)
698              // try to find the correct paper anyway using the size
699              if( pKey && ! pValue && pJobSetup->mePaperFormat != PAPER_USER )
700              {
701                  PaperInfo aInfo( pJobSetup->mePaperFormat );
702                  aPaper = aData.m_pParser->matchPaper(
703                      TenMuToPt( aInfo.getWidth() ),
704                      TenMuToPt( aInfo.getHeight() ) );
705                  pValue = pKey->getValueCaseInsensitive( aPaper );
706              }
707  
708  			if( ! ( pKey && pValue && aData.m_aContext.setValue( pKey, pValue, false ) == pValue ) )
709  				return sal_False;
710  		}
711  
712  		// merge paperbin if necessary
713  		if( nSetDataFlags & SAL_JOBSET_PAPERBIN )
714  		{
715  			pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) );
716  			if( pKey )
717  			{
718  				int nPaperBin = pJobSetup->mnPaperBin;
719  				if( nPaperBin >= pKey->countValues() )
720  					pValue = pKey->getDefaultValue();
721  				else
722                      pValue = pKey->getValue( pJobSetup->mnPaperBin );
723  
724                  // may fail due to constraints;
725                  // real paper bin is copied back to jobsetup in that case
726  				aData.m_aContext.setValue( pKey, pValue );
727  			}
728  			// if printer has no InputSlot key simply ignore this setting
729  			// (e.g. SGENPRT has no InputSlot)
730  		}
731  
732  		// merge orientation if necessary
733  		if( nSetDataFlags & SAL_JOBSET_ORIENTATION )
734  			aData.m_eOrientation = pJobSetup->meOrientation == ORIENTATION_LANDSCAPE ? orientation::Landscape : orientation::Portrait;
735  
736          // merge duplex if necessary
737          if( nSetDataFlags & SAL_JOBSET_DUPLEXMODE )
738          {
739              pKey = aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Duplex" ) ) );
740              if( pKey )
741              {
742                  pValue = NULL;
743                  switch( pJobSetup->meDuplexMode )
744                  {
745                  case DUPLEX_OFF:
746                      pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "None" ) ) );
747                      if( pValue == NULL )
748                          pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "SimplexNoTumble" ) ) );
749                      break;
750                  case DUPLEX_SHORTEDGE:
751                      pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "DuplexTumble" ) ) );
752                      break;
753                  case DUPLEX_LONGEDGE:
754                      pValue = pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "DuplexNoTumble" ) ) );
755                      break;
756                  case DUPLEX_UNKNOWN:
757                  default:
758                      pValue = 0;
759                      break;
760                  }
761                  if( ! pValue )
762                      pValue = pKey->getDefaultValue();
763                  aData.m_aContext.setValue( pKey, pValue );
764              }
765          }
766  
767  		m_aJobData = aData;
768  		copyJobDataToJobSetup( pJobSetup, aData );
769  		return sal_True;
770  	}
771  
772  	return sal_False;
773  }
774  
775  // -----------------------------------------------------------------------
776  
GetPageInfo(const ImplJobSetup * pJobSetup,long & rOutWidth,long & rOutHeight,long & rPageOffX,long & rPageOffY,long & rPageWidth,long & rPageHeight)777  void PspSalInfoPrinter::GetPageInfo(
778  	const ImplJobSetup* pJobSetup,
779  	long& rOutWidth, long& rOutHeight,
780  	long& rPageOffX, long& rPageOffY,
781  	long& rPageWidth, long& rPageHeight )
782  {
783  	if( ! pJobSetup )
784  		return;
785  
786  	JobData aData;
787  	JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
788  
789  	// get the selected page size
790  	if( aData.m_pParser )
791  	{
792  
793  		String aPaper;
794  		int width, height;
795  		int left = 0, top = 0, right = 0, bottom = 0;
796  		int nDPI = aData.m_aContext.getRenderResolution();
797  
798  
799          if( aData.m_eOrientation == psp::orientation::Portrait )
800          {
801              aData.m_aContext.getPageSize( aPaper, width, height );
802              aData.m_pParser->getMargins( aPaper, left, right, top, bottom );
803          }
804          else
805          {
806              aData.m_aContext.getPageSize( aPaper, height, width );
807              aData.m_pParser->getMargins( aPaper, top, bottom, right, left );
808          }
809  
810  		rPageWidth	= width * nDPI / 72;
811  		rPageHeight	= height * nDPI / 72;
812  		rPageOffX	= left * nDPI / 72;
813  		rPageOffY	= top * nDPI / 72;
814  		rOutWidth	= ( width  - left - right ) * nDPI / 72;
815  		rOutHeight	= ( height - top  - bottom ) * nDPI / 72;
816  	}
817  }
818  
819  // -----------------------------------------------------------------------
820  
GetPaperBinCount(const ImplJobSetup * pJobSetup)821  sal_uLong PspSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* pJobSetup )
822  {
823  	if( ! pJobSetup )
824  		return 0;
825  
826  	JobData aData;
827  	JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
828  
829  	const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ): NULL;
830      return pKey ? pKey->countValues() : 0;
831  }
832  
833  // -----------------------------------------------------------------------
834  
GetPaperBinName(const ImplJobSetup * pJobSetup,sal_uLong nPaperBin)835  String PspSalInfoPrinter::GetPaperBinName( const ImplJobSetup* pJobSetup, sal_uLong nPaperBin )
836  {
837  	JobData aData;
838  	JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
839  
840  	String aRet;
841  	if( aData.m_pParser )
842  	{
843  		const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "InputSlot" ) ) ): NULL;
844  		if( ! pKey || nPaperBin >= (sal_uLong)pKey->countValues() )
845  			aRet = aData.m_pParser->getDefaultInputSlot();
846  		else
847          {
848              const PPDValue* pValue = pKey->getValue( nPaperBin );
849              if( pValue )
850                  aRet = aData.m_pParser->translateOption( pKey->getKey(), pValue->m_aOption );
851          }
852  	}
853  
854  	return aRet;
855  }
856  
857  // -----------------------------------------------------------------------
858  
GetCapabilities(const ImplJobSetup * pJobSetup,sal_uInt16 nType)859  sal_uLong PspSalInfoPrinter::GetCapabilities( const ImplJobSetup* pJobSetup, sal_uInt16 nType )
860  {
861  	switch( nType )
862  	{
863  		case PRINTER_CAPABILITIES_SUPPORTDIALOG:
864  			return 1;
865  		case PRINTER_CAPABILITIES_COPIES:
866  			return 0xffff;
867  		case PRINTER_CAPABILITIES_COLLATECOPIES:
868          {
869              // see if the PPD contains a value to set Collate to True
870              JobData aData;
871              JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
872  
873              const PPDKey* pKey = aData.m_pParser ? aData.m_pParser->getKey( String( RTL_CONSTASCII_USTRINGPARAM( "Collate" ) ) ) : NULL;
874              const PPDValue* pVal = pKey ? pKey->getValue( String( RTL_CONSTASCII_USTRINGPARAM( "True" ) ) ) : NULL;
875  
876              // PPDs don't mention the number of possible collated copies.
877              // so let's guess as many as we want ?
878  			return pVal ? 0xffff : 0;
879          }
880  		case PRINTER_CAPABILITIES_SETORIENTATION:
881  			return 1;
882  		case PRINTER_CAPABILITIES_SETDUPLEX:
883  			return 1;
884  		case PRINTER_CAPABILITIES_SETPAPERBIN:
885  			return 1;
886  		case PRINTER_CAPABILITIES_SETPAPERSIZE:
887  			return 1;
888  		case PRINTER_CAPABILITIES_SETPAPER:
889  			return 0;
890  		case PRINTER_CAPABILITIES_FAX:
891              return PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "fax" ) ? 1 : 0;
892  		case PRINTER_CAPABILITIES_PDF:
893              if( PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "pdf" ) )
894                  return 1;
895              else
896              {
897                  // see if the PPD contains a value to set Collate to True
898                  JobData aData = PrinterInfoManager::get().getPrinterInfo( pJobSetup->maPrinterName );
899                  if( pJobSetup->mpDriverData )
900                      JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
901                  return aData.m_nPDFDevice > 0 ? 1 : 0;
902              }
903  		case PRINTER_CAPABILITIES_EXTERNALDIALOG:
904              return PrinterInfoManager::get().checkFeatureToken( pJobSetup->maPrinterName, "external_dialog" ) ? 1 : 0;
905          case PRINTER_CAPABILITIES_USEPULLMODEL:
906          {
907              // see if the PPD contains a value to set Collate to True
908              JobData aData = PrinterInfoManager::get().getPrinterInfo( pJobSetup->maPrinterName );
909              if( pJobSetup->mpDriverData )
910                  JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, aData );
911              return aData.m_nPDFDevice > 0 ? 1 : 0;
912          }
913  		default: break;
914  	};
915  	return 0;
916  }
917  
918  // =======================================================================
919  
920  /*
921   *	SalPrinter
922   */
923  
PspSalPrinter(SalInfoPrinter * pInfoPrinter)924   PspSalPrinter::PspSalPrinter( SalInfoPrinter* pInfoPrinter )
925   : m_bFax( false ),
926     m_bPdf( false ),
927     m_bSwallowFaxNo( false ),
928     m_bIsPDFWriterJob( false ),
929     m_pGraphics( NULL ),
930     m_nCopies( 1 ),
931     m_bCollate( false ),
932     m_pInfoPrinter( pInfoPrinter )
933  {
934  }
935  
936  // -----------------------------------------------------------------------
937  
~PspSalPrinter()938  PspSalPrinter::~PspSalPrinter()
939  {
940  }
941  
942  // -----------------------------------------------------------------------
943  
getTmpName()944  static String getTmpName()
945  {
946      rtl::OUString aTmp, aSys;
947      osl_createTempFile( NULL, NULL, &aTmp.pData );
948      osl_getSystemPathFromFileURL( aTmp.pData, &aSys.pData );
949  
950      return aSys;
951  }
952  
StartJob(const XubString * pFileName,const XubString & rJobName,const XubString & rAppName,sal_uLong nCopies,bool bCollate,bool bDirect,ImplJobSetup * pJobSetup)953  sal_Bool PspSalPrinter::StartJob(
954  	const XubString* pFileName,
955  	const XubString& rJobName,
956  	const XubString& rAppName,
957  	sal_uLong nCopies,
958      bool bCollate,
959      bool bDirect,
960  	ImplJobSetup* pJobSetup )
961  {
962      vcl_sal::PrinterUpdate::jobStarted();
963  
964  	m_bFax		= false;
965  	m_bPdf		= false;
966  	m_aFileName	= pFileName ? *pFileName : String();
967  	m_aTmpFile	= String();
968      m_nCopies	= nCopies;
969      m_bCollate  = bCollate;
970  
971  	JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData );
972      if( m_nCopies > 1 )
973      {
974          // in case user did not do anything (m_nCopies=1)
975          // take the default from jobsetup
976          m_aJobData.m_nCopies = m_nCopies;
977          m_aJobData.setCollate( bCollate );
978      }
979  
980  	// check whether this printer is configured as fax
981      int nMode = 0;
982  	const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
983      sal_Int32 nIndex = 0;
984      while( nIndex != -1 )
985  	{
986  		OUString aToken( rInfo.m_aFeatures.getToken( 0, ',', nIndex ) );
987  		if( ! aToken.compareToAscii( "fax", 3 ) )
988  		{
989  			m_bFax = true;
990  			m_aTmpFile = getTmpName();
991              nMode = S_IRUSR | S_IWUSR;
992  
993  			::std::hash_map< ::rtl::OUString, ::rtl::OUString, ::rtl::OUStringHash >::const_iterator it;
994  			it = pJobSetup->maValueMap.find( ::rtl::OUString::createFromAscii( "FAX#" ) );
995  			if( it != pJobSetup->maValueMap.end() )
996  				m_aFaxNr = it->second;
997  
998              sal_Int32 nPos = 0;
999  			m_bSwallowFaxNo = ! aToken.getToken( 1, '=', nPos ).compareToAscii( "swallow", 7 ) ? true : false;
1000  
1001  			break;
1002  		}
1003  		if( ! aToken.compareToAscii( "pdf=", 4 ) )
1004  		{
1005  			m_bPdf = true;
1006  			m_aTmpFile = getTmpName();
1007              nMode = S_IRUSR | S_IWUSR;
1008  
1009  			if( ! m_aFileName.Len() )
1010  			{
1011  				m_aFileName = getPdfDir( rInfo );
1012  				m_aFileName.Append( '/' );
1013  				m_aFileName.Append( rJobName );
1014  				m_aFileName.AppendAscii( ".pdf" );
1015  			}
1016  			break;
1017  		}
1018  	}
1019  	m_aPrinterGfx.Init( m_aJobData );
1020  
1021      // set/clear backwards compatibility flag
1022      bool bStrictSO52Compatibility = false;
1023      std::hash_map<rtl::OUString, rtl::OUString, rtl::OUStringHash >::const_iterator compat_it =
1024          pJobSetup->maValueMap.find( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StrictSO52Compatibility" ) ) );
1025  
1026      if( compat_it != pJobSetup->maValueMap.end() )
1027      {
1028          if( compat_it->second.equalsIgnoreAsciiCaseAscii( "true" ) )
1029              bStrictSO52Compatibility = true;
1030      }
1031      m_aPrinterGfx.setStrictSO52Compatibility( bStrictSO52Compatibility );
1032  
1033  	return m_aPrintJob.StartJob( m_aTmpFile.Len() ? m_aTmpFile : m_aFileName, nMode, rJobName, rAppName, m_aJobData, &m_aPrinterGfx, bDirect ) ? sal_True : sal_False;
1034  }
1035  
1036  // -----------------------------------------------------------------------
1037  
EndJob()1038  sal_Bool PspSalPrinter::EndJob()
1039  {
1040      sal_Bool bSuccess = sal_False;
1041      if( m_bIsPDFWriterJob )
1042          bSuccess = sal_True;
1043      else
1044      {
1045          bSuccess = m_aPrintJob.EndJob();
1046  
1047          if( bSuccess )
1048          {
1049              // check for fax
1050              if( m_bFax )
1051              {
1052  
1053                  const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
1054                  // sendAFax removes the file after use
1055                  bSuccess = sendAFax( m_aFaxNr, m_aTmpFile, rInfo.m_aCommand );
1056              }
1057              else if( m_bPdf )
1058              {
1059                  const PrinterInfo& rInfo( PrinterInfoManager::get().getPrinterInfo( m_aJobData.m_aPrinterName ) );
1060                  bSuccess = createPdf( m_aFileName, m_aTmpFile, rInfo.m_aCommand );
1061              }
1062          }
1063      }
1064      vcl_sal::PrinterUpdate::jobEnded();
1065  	return bSuccess;
1066  }
1067  
1068  // -----------------------------------------------------------------------
1069  
AbortJob()1070  sal_Bool PspSalPrinter::AbortJob()
1071  {
1072      sal_Bool bAbort = m_aPrintJob.AbortJob() ? sal_True : sal_False;
1073      vcl_sal::PrinterUpdate::jobEnded();
1074  	return bAbort;
1075  }
1076  
1077  // -----------------------------------------------------------------------
1078  
StartPage(ImplJobSetup * pJobSetup,sal_Bool)1079  SalGraphics* PspSalPrinter::StartPage( ImplJobSetup* pJobSetup, sal_Bool )
1080  {
1081  	JobData::constructFromStreamBuffer( pJobSetup->mpDriverData, pJobSetup->mnDriverDataLen, m_aJobData );
1082  	m_pGraphics = new PspGraphics( &m_aJobData, &m_aPrinterGfx, m_bFax ? &m_aFaxNr : NULL, m_bSwallowFaxNo, m_pInfoPrinter  );
1083      m_pGraphics->SetLayout( 0 );
1084      if( m_nCopies > 1 )
1085      {
1086          // in case user did not do anything (m_nCopies=1)
1087          // take the default from jobsetup
1088          m_aJobData.m_nCopies = m_nCopies;
1089          m_aJobData.setCollate( m_nCopies > 1 && m_bCollate );
1090      }
1091  
1092  	m_aPrintJob.StartPage( m_aJobData );
1093  	m_aPrinterGfx.Init( m_aPrintJob );
1094  
1095  	return m_pGraphics;
1096  }
1097  
1098  // -----------------------------------------------------------------------
1099  
EndPage()1100  sal_Bool PspSalPrinter::EndPage()
1101  {
1102  	sal_Bool bResult = m_aPrintJob.EndPage();
1103  	m_aPrinterGfx.Clear();
1104  	return bResult ? sal_True : sal_False;
1105  }
1106  
1107  // -----------------------------------------------------------------------
1108  
GetErrorCode()1109  sal_uLong PspSalPrinter::GetErrorCode()
1110  {
1111  	return 0;
1112  }
1113  
1114  // -----------------------------------------------------------------------
1115  
1116  struct PDFNewJobParameters
1117  {
1118      Size        maPageSize;
1119      sal_uInt16      mnPaperBin;
1120  
PDFNewJobParametersPDFNewJobParameters1121      PDFNewJobParameters( const Size& i_rSize = Size(),
1122                           sal_uInt16 i_nPaperBin = 0xffff )
1123      : maPageSize( i_rSize ), mnPaperBin( i_nPaperBin ) {}
1124  
operator !=PDFNewJobParameters1125      bool operator!=(const PDFNewJobParameters& rComp ) const
1126      {
1127          Size aCompLSSize( rComp.maPageSize.Height(), rComp.maPageSize.Width() );
1128          return
1129              (maPageSize != rComp.maPageSize && maPageSize != aCompLSSize)
1130          ||  mnPaperBin != rComp.mnPaperBin
1131          ;
1132      }
1133  
operator ==PDFNewJobParameters1134      bool operator==(const PDFNewJobParameters& rComp) const
1135      {
1136          return ! this->operator!=(rComp);
1137      }
1138  };
1139  
1140  struct PDFPrintFile
1141  {
1142      rtl::OUString       maTmpURL;
1143      PDFNewJobParameters maParameters;
1144  
PDFPrintFilePDFPrintFile1145      PDFPrintFile( const rtl::OUString& i_rURL, const PDFNewJobParameters& i_rNewParameters )
1146      : maTmpURL( i_rURL )
1147      , maParameters( i_rNewParameters ) {}
1148  };
1149  
StartJob(const String * i_pFileName,const String & i_rJobName,const String & i_rAppName,ImplJobSetup * i_pSetupData,vcl::PrinterController & i_rController)1150  sal_Bool PspSalPrinter::StartJob( const String* i_pFileName, const String& i_rJobName, const String& i_rAppName,
1151                                ImplJobSetup* i_pSetupData, vcl::PrinterController& i_rController )
1152  {
1153      OSL_TRACE( "StartJob with controller: pFilename = %s", i_pFileName ? rtl::OUStringToOString( *i_pFileName, RTL_TEXTENCODING_UTF8 ).getStr() : "<nil>" );
1154      // mark for endjob
1155      m_bIsPDFWriterJob = true;
1156      // reset IsLastPage
1157      i_rController.setLastPage( sal_False );
1158  
1159      // update job data
1160      if( i_pSetupData )
1161          JobData::constructFromStreamBuffer( i_pSetupData->mpDriverData, i_pSetupData->mnDriverDataLen, m_aJobData );
1162  
1163      OSL_ASSERT( m_aJobData.m_nPDFDevice > 0 );
1164      m_aJobData.m_nPDFDevice = 1;
1165  
1166      // possibly create one job for collated output
1167      sal_Bool bSinglePrintJobs = sal_False;
1168      beans::PropertyValue* pSingleValue = i_rController.getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintCollateAsSingleJobs" ) ) );
1169      if( pSingleValue )
1170      {
1171          pSingleValue->Value >>= bSinglePrintJobs;
1172      }
1173  
1174      int nCopies = i_rController.getPrinter()->GetCopyCount();
1175      bool bCollate = i_rController.getPrinter()->IsCollateCopy();
1176  
1177      // notify start of real print job
1178      i_rController.jobStarted();
1179  
1180      // setup PDFWriter context
1181      vcl::PDFWriter::PDFWriterContext aContext;
1182      aContext.Version            = vcl::PDFWriter::PDF_1_4;
1183      aContext.Tagged             = false;
1184      aContext.EmbedStandardFonts = true;
1185      aContext.DocumentLocale     = Application::GetSettings().GetLocale();
1186      aContext.ColorMode          = i_rController.getPrinter()->GetPrinterOptions().IsConvertToGreyscales()
1187      ? vcl::PDFWriter::DrawGreyscale : vcl::PDFWriter::DrawColor;
1188  
1189      // prepare doc info
1190      aContext.DocumentInfo.Title              = i_rJobName;
1191      aContext.DocumentInfo.Creator            = i_rAppName;
1192      aContext.DocumentInfo.Producer           = i_rAppName;
1193  
1194      // define how we handle metafiles in PDFWriter
1195      vcl::PDFWriter::PlayMetafileContext aMtfContext;
1196      aMtfContext.m_bOnlyLosslessCompression = true;
1197  
1198      boost::shared_ptr<vcl::PDFWriter> pWriter;
1199      std::vector< PDFPrintFile > aPDFFiles;
1200      boost::shared_ptr<Printer> pPrinter( i_rController.getPrinter() );
1201      int nAllPages = i_rController.getFilteredPageCount();
1202      i_rController.createProgressDialog();
1203      bool bAborted = false;
1204      PDFNewJobParameters aLastParm;
1205  
1206      aContext.DPIx = pPrinter->ImplGetDPIX();
1207      aContext.DPIy = pPrinter->ImplGetDPIY();
1208      for( int nPage = 0; nPage < nAllPages && ! bAborted; nPage++ )
1209      {
1210          if( nPage == nAllPages-1 )
1211              i_rController.setLastPage( sal_True );
1212  
1213          // get the page's metafile
1214          GDIMetaFile aPageFile;
1215          vcl::PrinterController::PageSize aPageSize = i_rController.getFilteredPageFile( nPage, aPageFile );
1216          if( i_rController.isProgressCanceled() )
1217          {
1218              bAborted = true;
1219              if( nPage != nAllPages-1 )
1220              {
1221                  i_rController.createProgressDialog();
1222                  i_rController.setLastPage( sal_True );
1223                  i_rController.getFilteredPageFile( nPage, aPageFile );
1224              }
1225          }
1226          else
1227          {
1228              pPrinter->SetMapMode( MapMode( MAP_100TH_MM ) );
1229              pPrinter->SetPaperSizeUser( aPageSize.aSize, true );
1230              PDFNewJobParameters aNewParm( pPrinter->GetPaperSize(), pPrinter->GetPaperBin() );
1231  
1232              // create PDF writer on demand
1233              // either on first page
1234              // or on paper format change - cups does not support multiple paper formats per job (yet?)
1235              // so we need to start a new job to get a new paper format from the printer
1236              // orientation switches (that is switch of height and width) is handled transparently by CUPS
1237              if( ! pWriter ||
1238                  (aNewParm != aLastParm && ! i_pFileName ) )
1239              {
1240                  if( pWriter )
1241                  {
1242                      pWriter->Emit();
1243                  }
1244                  // produce PDF file
1245                  OUString aPDFUrl;
1246                  if( i_pFileName )
1247                      aPDFUrl = *i_pFileName;
1248                  else
1249                      osl_createTempFile( NULL, NULL, &aPDFUrl.pData );
1250                  // normalize to file URL
1251                  if( aPDFUrl.compareToAscii( "file:", 5 ) != 0 )
1252                  {
1253                      // this is not a file URL, but it should
1254                      // form it into a osl friendly file URL
1255                      rtl::OUString aTmp;
1256                      osl_getFileURLFromSystemPath( aPDFUrl.pData, &aTmp.pData );
1257                      aPDFUrl = aTmp;
1258                  }
1259                  // save current file and paper format
1260                  aLastParm = aNewParm;
1261                  aPDFFiles.push_back( PDFPrintFile( aPDFUrl, aNewParm ) );
1262                  // update context
1263                  aContext.URL = aPDFUrl;
1264  
1265                  // create and initialize PDFWriter
1266                  #if defined __SUNPRO_CC
1267                  #pragma disable_warn
1268                  #endif
1269                  pWriter.reset( new vcl::PDFWriter( aContext, uno::Reference< beans::XMaterialHolder >() ) );
1270                  #if defined __SUNPRO_CC
1271                  #pragma enable_warn
1272                  #endif
1273              }
1274  
1275              pWriter->NewPage( TenMuToPt( aNewParm.maPageSize.Width() ),
1276                                TenMuToPt( aNewParm.maPageSize.Height() ),
1277                                vcl::PDFWriter::Portrait );
1278  
1279              pWriter->PlayMetafile( aPageFile, aMtfContext, NULL );
1280          }
1281      }
1282  
1283      // emit the last file
1284      if( pWriter )
1285          pWriter->Emit();
1286  
1287      // handle collate, copy count and multiple jobs correctly
1288      int nOuterJobs = 1;
1289      if( bSinglePrintJobs )
1290      {
1291          nOuterJobs = nCopies;
1292          m_aJobData.m_nCopies = 1;
1293      }
1294      else
1295      {
1296          if( bCollate )
1297          {
1298              if( aPDFFiles.size() == 1 && pPrinter->HasSupport( SUPPORT_COLLATECOPY ) )
1299              {
1300                  m_aJobData.setCollate( true );
1301                  m_aJobData.m_nCopies = nCopies;
1302              }
1303              else
1304              {
1305                  nOuterJobs = nCopies;
1306                  m_aJobData.m_nCopies = 1;
1307              }
1308          }
1309          else
1310          {
1311              m_aJobData.setCollate( false );
1312              m_aJobData.m_nCopies = nCopies;
1313          }
1314      }
1315  
1316      // spool files
1317      if( ! i_pFileName && ! bAborted )
1318      {
1319          bool bFirstJob = true;
1320          for( int nCurJob = 0; nCurJob < nOuterJobs; nCurJob++ )
1321          {
1322              for( size_t i = 0; i < aPDFFiles.size(); i++ )
1323              {
1324                  oslFileHandle pFile = NULL;
1325                  osl_openFile( aPDFFiles[i].maTmpURL.pData, &pFile, osl_File_OpenFlag_Read );
1326                  if( pFile )
1327                  {
1328                      osl_setFilePos( pFile, osl_Pos_Absolut, 0 );
1329                      std::vector< char > buffer( 0x10000, 0 );
1330                      // update job data with current page size
1331                      Size aPageSize( aPDFFiles[i].maParameters.maPageSize );
1332                      m_aJobData.setPaper( TenMuToPt( aPageSize.Width() ), TenMuToPt( aPageSize.Height() ) );
1333                      // update job data with current paperbin
1334                      m_aJobData.setPaperBin( aPDFFiles[i].maParameters.mnPaperBin );
1335  
1336                      // spool current file
1337                      FILE* fp = PrinterInfoManager::get().startSpool( pPrinter->GetName(), i_rController.isDirectPrint() );
1338                      if( fp )
1339                      {
1340                          sal_uInt64 nBytesRead = 0;
1341                          do
1342                          {
1343                              osl_readFile( pFile, &buffer[0], buffer.size(), &nBytesRead );
1344                              if( nBytesRead > 0 )
1345                                  fwrite( &buffer[0], 1, nBytesRead, fp );
1346                          } while( nBytesRead == buffer.size() );
1347                          rtl::OUStringBuffer aBuf( i_rJobName.Len() + 8 );
1348                          aBuf.append( i_rJobName );
1349                          if( i > 0 || nCurJob > 0 )
1350                          {
1351                              aBuf.append( sal_Unicode(' ') );
1352                              aBuf.append( sal_Int32( i + nCurJob * aPDFFiles.size() ) );
1353                          }
1354                          PrinterInfoManager::get().endSpool( pPrinter->GetName(), aBuf.makeStringAndClear(), fp, m_aJobData, bFirstJob );
1355                          bFirstJob = false;
1356                      }
1357                  }
1358                  osl_closeFile( pFile );
1359              }
1360          }
1361      }
1362  
1363      // job has been spooled
1364      i_rController.setJobState( bAborted ? view::PrintableState_JOB_ABORTED : view::PrintableState_JOB_SPOOLED );
1365  
1366      // clean up the temporary PDF files
1367      if( ! i_pFileName || bAborted )
1368      {
1369          for( size_t i = 0; i < aPDFFiles.size(); i++ )
1370          {
1371              osl_removeFile( aPDFFiles[i].maTmpURL.pData );
1372              OSL_TRACE( "removed print PDF file %s\n", rtl::OUStringToOString( aPDFFiles[i].maTmpURL, RTL_TEXTENCODING_UTF8 ).getStr() );
1373          }
1374      }
1375  
1376      return sal_True;
1377  }
1378  
1379  
1380  
1381  /*
1382   *  vcl::PrinterUpdate
1383   */
1384  
1385  Timer* vcl_sal::PrinterUpdate::pPrinterUpdateTimer = NULL;
1386  int vcl_sal::PrinterUpdate::nActiveJobs = 0;
1387  
doUpdate()1388  void vcl_sal::PrinterUpdate::doUpdate()
1389  {
1390      ::psp::PrinterInfoManager& rManager( ::psp::PrinterInfoManager::get() );
1391      if( rManager.checkPrintersChanged( false ) )
1392      {
1393          SalDisplay* pDisp = GetX11SalData()->GetDisplay();
1394          const std::list< SalFrame* >& rList = pDisp->getFrames();
1395          for( std::list< SalFrame* >::const_iterator it = rList.begin();
1396               it != rList.end(); ++it )
1397              pDisp->SendInternalEvent( *it, NULL, SALEVENT_PRINTERCHANGED );
1398      }
1399  }
1400  
1401  // -----------------------------------------------------------------------
1402  
IMPL_STATIC_LINK_NOINSTANCE(vcl_sal::PrinterUpdate,UpdateTimerHdl,void *,EMPTYARG)1403  IMPL_STATIC_LINK_NOINSTANCE( vcl_sal::PrinterUpdate, UpdateTimerHdl, void*, EMPTYARG )
1404  {
1405      if( nActiveJobs < 1 )
1406      {
1407          doUpdate();
1408          delete pPrinterUpdateTimer;
1409          pPrinterUpdateTimer = NULL;
1410      }
1411      else
1412          pPrinterUpdateTimer->Start();
1413  
1414      return 0;
1415  }
1416  
1417  // -----------------------------------------------------------------------
1418  
update()1419  void vcl_sal::PrinterUpdate::update()
1420  {
1421      if( Application::GetSettings().GetMiscSettings().GetDisablePrinting() )
1422          return;
1423  
1424      if( ! static_cast< X11SalInstance* >(GetSalData()->m_pInstance)->isPrinterInit() )
1425      {
1426          // #i45389# start background printer detection
1427          psp::PrinterInfoManager::get();
1428          return;
1429      }
1430  
1431      if( nActiveJobs < 1 )
1432          doUpdate();
1433      else if( ! pPrinterUpdateTimer )
1434      {
1435          pPrinterUpdateTimer = new Timer();
1436          pPrinterUpdateTimer->SetTimeout( 500 );
1437          pPrinterUpdateTimer->SetTimeoutHdl( STATIC_LINK( NULL, vcl_sal::PrinterUpdate, UpdateTimerHdl ) );
1438          pPrinterUpdateTimer->Start();
1439      }
1440  }
1441  
1442  // -----------------------------------------------------------------------
1443  
jobEnded()1444  void vcl_sal::PrinterUpdate::jobEnded()
1445  {
1446      nActiveJobs--;
1447      if( nActiveJobs < 1 )
1448      {
1449          if( pPrinterUpdateTimer )
1450          {
1451              pPrinterUpdateTimer->Stop();
1452              delete pPrinterUpdateTimer;
1453              pPrinterUpdateTimer = NULL;
1454              doUpdate();
1455          }
1456      }
1457  }
1458