LCOV - code coverage report
Current view: top level - usr/local/src/libreoffice/vcl/generic/print - genprnpsp.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 104 664 15.7 %
Date: 2013-07-09 Functions: 10 58 17.2 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10