xref: /aoo41x/main/vcl/aqua/source/gdi/salprn.cxx (revision 92a1bdef)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 
31 #include <boost/bind.hpp>
32 
33 #include "vcl/print.hxx"
34 #include "vcl/unohelp.hxx"
35 
36 #include "aqua/salinst.h"
37 #include "aqua/salprn.h"
38 #include "aqua/aquaprintview.h"
39 #include "aqua/salgdi.h"
40 #include "aqua/saldata.hxx"
41 
42 #include "jobset.h"
43 #include "salptype.hxx"
44 
45 #include "com/sun/star/lang/XMultiServiceFactory.hpp"
46 #include "com/sun/star/container/XNameAccess.hpp"
47 #include "com/sun/star/beans/PropertyValue.hpp"
48 #include "com/sun/star/awt/Size.hpp"
49 
50 #include <algorithm>
51 
52 using namespace rtl;
53 using namespace vcl;
54 using namespace com::sun::star;
55 using namespace com::sun::star::uno;
56 using namespace com::sun::star::lang;
57 using namespace com::sun::star::beans;
58 using namespace com::sun::star::container;
59 
60 // =======================================================================
61 
62 AquaSalInfoPrinter::AquaSalInfoPrinter( const SalPrinterQueueInfo& i_rQueue ) :
63     mpGraphics( 0 ),
64     mbGraphics( false ),
65     mbJob( false ),
66     mpPrinter( nil ),
67     mpPrintInfo( nil ),
68     mePageOrientation( ORIENTATION_PORTRAIT ),
69     mnStartPageOffsetX( 0 ),
70     mnStartPageOffsetY( 0 ),
71     mnCurPageRangeStart( 0 ),
72     mnCurPageRangeCount( 0 )
73 {
74     NSString* pStr = CreateNSString( i_rQueue.maPrinterName );
75     mpPrinter = [NSPrinter printerWithName: pStr];
76     [pStr release];
77 
78     NSPrintInfo* pShared = [NSPrintInfo sharedPrintInfo];
79     if( pShared )
80     {
81         mpPrintInfo = [pShared copy];
82         [mpPrintInfo setPrinter: mpPrinter];
83         mePageOrientation = ([mpPrintInfo orientation] == NSLandscapeOrientation) ? ORIENTATION_LANDSCAPE : ORIENTATION_PORTRAIT;
84         [mpPrintInfo setOrientation: NSPortraitOrientation];
85     }
86 
87     mpGraphics = new AquaSalGraphics();
88 
89     const int nWidth = 100, nHeight = 100;
90     maContextMemory.reset( reinterpret_cast<sal_uInt8*>( rtl_allocateMemory( nWidth * 4 * nHeight ) ),
91                            boost::bind( rtl_freeMemory, _1 ) );
92 
93     if( maContextMemory )
94     {
95         mrContext = CGBitmapContextCreate( maContextMemory.get(), nWidth, nHeight, 8, nWidth * 4, GetSalData()->mxRGBSpace, kCGImageAlphaNoneSkipFirst );
96         if( mrContext )
97             SetupPrinterGraphics( mrContext );
98     }
99 }
100 
101 // -----------------------------------------------------------------------
102 
103 AquaSalInfoPrinter::~AquaSalInfoPrinter()
104 {
105     delete mpGraphics;
106     if( mpPrintInfo )
107         [mpPrintInfo release];
108     #if 0
109     // FIXME: verify that NSPrintInfo releases the printer
110     // else we have a leak here
111     if( mpPrinter )
112         [mpPrinter release];
113     #endif
114     if( mrContext )
115         CFRelease( mrContext );
116 }
117 
118 // -----------------------------------------------------------------------
119 
120 void AquaSalInfoPrinter::SetupPrinterGraphics( CGContextRef i_rContext ) const
121 {
122     if( mpGraphics )
123     {
124         if( mpPrintInfo )
125         {
126             // FIXME: get printer resolution
127             long nDPIX = 720, nDPIY = 720;
128             NSSize aPaperSize = [mpPrintInfo paperSize];
129 
130             NSRect aImageRect = [mpPrintInfo imageablePageBounds];
131             if( mePageOrientation == ORIENTATION_PORTRAIT )
132             {
133                 // move mirrored CTM back into paper
134                 double dX = 0, dY = aPaperSize.height;
135                 // move CTM to reflect imageable area
136                 dX += aImageRect.origin.x;
137                 dY -= aPaperSize.height - aImageRect.size.height - aImageRect.origin.y;
138                 CGContextTranslateCTM( i_rContext, dX + mnStartPageOffsetX, dY - mnStartPageOffsetY );
139                 // scale to be top/down and reflect our "virtual" DPI
140                 CGContextScaleCTM( i_rContext, 72.0/double(nDPIX), -(72.0/double(nDPIY)) );
141             }
142             else
143             {
144                 // move CTM to reflect imageable area
145                 double dX = aImageRect.origin.x, dY = aPaperSize.height - aImageRect.size.height - aImageRect.origin.y;
146                 CGContextTranslateCTM( i_rContext, -dX, -dY );
147                 // turn by 90 degree
148                 CGContextRotateCTM( i_rContext, M_PI/2 );
149                 // move turned CTM back into paper
150                 dX = aPaperSize.height;
151                 dY = -aPaperSize.width;
152                 CGContextTranslateCTM( i_rContext, dX + mnStartPageOffsetY, dY - mnStartPageOffsetX );
153                 // scale to be top/down and reflect our "virtual" DPI
154                 CGContextScaleCTM( i_rContext, -(72.0/double(nDPIY)), (72.0/double(nDPIX)) );
155             }
156             mpGraphics->SetPrinterGraphics( i_rContext, nDPIX, nDPIY, 1.0 );
157         }
158         else
159             DBG_ERROR( "no print info in SetupPrinterGraphics" );
160     }
161 }
162 
163 // -----------------------------------------------------------------------
164 
165 SalGraphics* AquaSalInfoPrinter::GetGraphics()
166 {
167     SalGraphics* pGraphics = mbGraphics ? NULL : mpGraphics;
168     mbGraphics = true;
169 	return pGraphics;
170 }
171 
172 // -----------------------------------------------------------------------
173 
174 void AquaSalInfoPrinter::ReleaseGraphics( SalGraphics* )
175 {
176     mbGraphics = false;
177 }
178 
179 // -----------------------------------------------------------------------
180 
181 sal_Bool AquaSalInfoPrinter::Setup( SalFrame*, ImplJobSetup* )
182 {
183 	return sal_False;
184 }
185 
186 // -----------------------------------------------------------------------
187 
188 sal_Bool AquaSalInfoPrinter::SetPrinterData( ImplJobSetup* io_pSetupData )
189 {
190     // FIXME: implement driver data
191     if( io_pSetupData && io_pSetupData->mpDriverData )
192         return SetData( ~0, io_pSetupData );
193 
194 
195     sal_Bool bSuccess = sal_True;
196 
197     // set system type
198     io_pSetupData->mnSystem = JOBSETUP_SYSTEM_MAC;
199 
200     // get paper format
201     if( mpPrintInfo )
202     {
203         NSSize aPaperSize = [mpPrintInfo paperSize];
204         double width = aPaperSize.width, height = aPaperSize.height;
205         // set paper
206         PaperInfo aInfo( PtTo10Mu( width ), PtTo10Mu( height ) );
207         aInfo.doSloppyFit();
208         io_pSetupData->mePaperFormat = aInfo.getPaper();
209         if( io_pSetupData->mePaperFormat == PAPER_USER )
210         {
211             io_pSetupData->mnPaperWidth = PtTo10Mu( width );
212             io_pSetupData->mnPaperHeight = PtTo10Mu( height );
213         }
214         else
215         {
216             io_pSetupData->mnPaperWidth = 0;
217             io_pSetupData->mnPaperHeight = 0;
218         }
219 
220         // set orientation
221         io_pSetupData->meOrientation = mePageOrientation;
222 
223         io_pSetupData->mnPaperBin = 0;
224         io_pSetupData->mpDriverData = reinterpret_cast<sal_uInt8*>(rtl_allocateMemory( 4 ));
225         io_pSetupData->mnDriverDataLen = 4;
226     }
227     else
228         bSuccess = sal_False;
229 
230 
231 	return bSuccess;
232 }
233 
234 // -----------------------------------------------------------------------
235 
236 void AquaSalInfoPrinter::setPaperSize( long i_nWidth, long i_nHeight, Orientation i_eSetOrientation )
237 {
238 
239     Orientation ePaperOrientation = ORIENTATION_PORTRAIT;
240     const PaperInfo* pPaper = matchPaper( i_nWidth, i_nHeight, ePaperOrientation );
241 
242     if( pPaper )
243     {
244         NSString* pPaperName = [CreateNSString( rtl::OStringToOUString(PaperInfo::toPSName(pPaper->getPaper()), RTL_TEXTENCODING_ASCII_US) ) autorelease];
245         [mpPrintInfo setPaperName: pPaperName];
246     }
247     else if( i_nWidth > 0 && i_nHeight > 0 )
248     {
249         NSSize aPaperSize = { TenMuToPt(i_nWidth), TenMuToPt(i_nHeight) };
250         [mpPrintInfo setPaperSize: aPaperSize];
251     }
252     // this seems counterintuitive
253     mePageOrientation = i_eSetOrientation;
254 }
255 
256 // -----------------------------------------------------------------------
257 
258 sal_Bool AquaSalInfoPrinter::SetData( sal_uLong i_nFlags, ImplJobSetup* io_pSetupData )
259 {
260     if( ! io_pSetupData || io_pSetupData->mnSystem != JOBSETUP_SYSTEM_MAC )
261         return sal_False;
262 
263 
264     if( mpPrintInfo )
265     {
266         if( (i_nFlags & SAL_JOBSET_ORIENTATION) != 0 )
267             mePageOrientation = io_pSetupData->meOrientation;
268 
269         if( (i_nFlags & SAL_JOBSET_PAPERSIZE) !=  0)
270         {
271             // set paper format
272             long width = 21000, height = 29700;
273             if( io_pSetupData->mePaperFormat == PAPER_USER )
274             {
275                 // #i101108# sanity check
276                 if( io_pSetupData->mnPaperWidth && io_pSetupData->mnPaperHeight )
277                 {
278                     width = io_pSetupData->mnPaperWidth;
279                     height = io_pSetupData->mnPaperHeight;
280                 }
281             }
282             else
283             {
284                 PaperInfo aInfo( io_pSetupData->mePaperFormat );
285                 width = aInfo.getWidth();
286                 height = aInfo.getHeight();
287             }
288 
289             setPaperSize( width, height, mePageOrientation );
290         }
291     }
292 
293 	return mpPrintInfo != nil;
294 }
295 
296 // -----------------------------------------------------------------------
297 
298 sal_uLong AquaSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* )
299 {
300 	return 0;
301 }
302 
303 // -----------------------------------------------------------------------
304 
305 XubString AquaSalInfoPrinter::GetPaperBinName( const ImplJobSetup*, sal_uLong )
306 {
307 	return XubString();
308 }
309 
310 // -----------------------------------------------------------------------
311 
312 static bool getUseNativeDialog()
313 {
314     bool bNative = true;
315     try
316     {
317         // get service provider
318         uno::Reference< XMultiServiceFactory > xSMgr( unohelper::GetMultiServiceFactory() );
319         // create configuration hierachical access name
320         if( xSMgr.is() )
321         {
322             try
323             {
324                 uno::Reference< XMultiServiceFactory > xConfigProvider(
325                    uno::Reference< XMultiServiceFactory >(
326                         xSMgr->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
327                                         "com.sun.star.configuration.ConfigurationProvider" ))),
328                         UNO_QUERY )
329                     );
330                 if( xConfigProvider.is() )
331                 {
332                     Sequence< Any > aArgs(1);
333                     PropertyValue aVal;
334                     aVal.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "nodepath" ) );
335                     aVal.Value <<= OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Office.Common/Misc" ) );
336                     aArgs.getArray()[0] <<= aVal;
337                     uno::Reference< XNameAccess > xConfigAccess(
338                         uno::Reference< XNameAccess >(
339                             xConfigProvider->createInstanceWithArguments( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
340                                                 "com.sun.star.configuration.ConfigurationAccess" )),
341                                                                             aArgs ),
342                             UNO_QUERY )
343                         );
344                     if( xConfigAccess.is() )
345                     {
346                         try
347                         {
348                             sal_Bool bValue = sal_False;
349                             Any aAny = xConfigAccess->getByName( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UseSystemPrintDialog" ) ) );
350                             if( aAny >>= bValue )
351                                 bNative = bValue;
352                         }
353                         catch( NoSuchElementException& )
354                         {
355                         }
356                         catch( WrappedTargetException& )
357                         {
358                         }
359                     }
360                 }
361             }
362             catch( Exception& )
363             {
364             }
365         }
366     }
367     catch( WrappedTargetException& )
368     {
369     }
370 
371     return bNative;
372 }
373 
374 sal_uLong AquaSalInfoPrinter::GetCapabilities( const ImplJobSetup*, sal_uInt16 i_nType )
375 {
376 	switch( i_nType )
377 	{
378 		case PRINTER_CAPABILITIES_SUPPORTDIALOG:
379 			return 0;
380 		case PRINTER_CAPABILITIES_COPIES:
381 			return 0xffff;
382 		case PRINTER_CAPABILITIES_COLLATECOPIES:
383 			return 0xffff;
384 		case PRINTER_CAPABILITIES_SETORIENTATION:
385 			return 1;
386 		case PRINTER_CAPABILITIES_SETDUPLEX:
387 			return 0;
388 		case PRINTER_CAPABILITIES_SETPAPERBIN:
389 			return 0;
390 		case PRINTER_CAPABILITIES_SETPAPERSIZE:
391 			return 1;
392 		case PRINTER_CAPABILITIES_SETPAPER:
393 			return 1;
394         case PRINTER_CAPABILITIES_EXTERNALDIALOG:
395             return getUseNativeDialog() ? 1 : 0;
396         case PRINTER_CAPABILITIES_PDF:
397             return 1;
398         case PRINTER_CAPABILITIES_USEPULLMODEL:
399             return 1;
400 		default: break;
401 	};
402 	return 0;
403 }
404 
405 // -----------------------------------------------------------------------
406 
407 void AquaSalInfoPrinter::GetPageInfo( const ImplJobSetup*,
408 								  long& o_rOutWidth, long& o_rOutHeight,
409 								  long& o_rPageOffX, long& o_rPageOffY,
410 								  long& o_rPageWidth, long& o_rPageHeight )
411 {
412     if( mpPrintInfo )
413     {
414         long nDPIX = 72, nDPIY = 72;
415         mpGraphics->GetResolution( nDPIX, nDPIY );
416         const double fXScaling = static_cast<double>(nDPIX)/72.0,
417                      fYScaling = static_cast<double>(nDPIY)/72.0;
418 
419         NSSize aPaperSize = [mpPrintInfo paperSize];
420         o_rPageWidth  = static_cast<long>( double(aPaperSize.width) * fXScaling );
421         o_rPageHeight = static_cast<long>( double(aPaperSize.height) * fYScaling );
422 
423         NSRect aImageRect = [mpPrintInfo imageablePageBounds];
424         o_rPageOffX   = static_cast<long>( aImageRect.origin.x * fXScaling );
425         o_rPageOffY   = static_cast<long>( (aPaperSize.height - aImageRect.size.height - aImageRect.origin.y) * fYScaling );
426         o_rOutWidth   = static_cast<long>( aImageRect.size.width * fXScaling );
427         o_rOutHeight  = static_cast<long>( aImageRect.size.height * fYScaling );
428 
429         if( mePageOrientation == ORIENTATION_LANDSCAPE )
430         {
431             std::swap( o_rOutWidth, o_rOutHeight );
432             std::swap( o_rPageWidth, o_rPageHeight );
433             std::swap( o_rPageOffX, o_rPageOffY );
434         }
435     }
436 }
437 
438 static Size getPageSize( vcl::PrinterController& i_rController, sal_Int32 i_nPage )
439 {
440     Size aPageSize;
441     Sequence< PropertyValue > aPageParms( i_rController.getPageParameters( i_nPage ) );
442     for( sal_Int32 nProperty = 0, nPropertyCount = aPageParms.getLength(); nProperty < nPropertyCount; ++nProperty )
443     {
444         if( aPageParms[ nProperty ].Name.equalsAscii( "PageSize" ) )
445         {
446             awt::Size aSize;
447             aPageParms[ nProperty].Value >>= aSize;
448             aPageSize.Width() = aSize.Width;
449             aPageSize.Height() = aSize.Height;
450             break;
451         }
452     }
453     return aPageSize;
454 }
455 
456 sal_Bool AquaSalInfoPrinter::StartJob( const String* i_pFileName,
457                                    const String& i_rJobName,
458                                    const String& /*i_rAppName*/,
459                                    ImplJobSetup* i_pSetupData,
460                                    vcl::PrinterController& i_rController
461                                    )
462 {
463     if( mbJob )
464         return sal_False;
465 
466     sal_Bool bSuccess = sal_False;
467     bool bWasAborted = false;
468     AquaSalInstance* pInst = GetSalData()->mpFirstInstance;
469     PrintAccessoryViewState aAccViewState;
470     sal_Int32 nAllPages = 0;
471 
472     // reset IsLastPage
473     i_rController.setLastPage( sal_False );
474 
475     // update job data
476     if( i_pSetupData )
477         SetData( ~0, i_pSetupData );
478 
479     // do we want a progress panel ?
480     sal_Bool bShowProgressPanel = sal_True;
481     beans::PropertyValue* pMonitor = i_rController.getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MonitorVisible" ) ) );
482     if( pMonitor )
483         pMonitor->Value >>= bShowProgressPanel;
484     if( ! i_rController.isShowDialogs() )
485         bShowProgressPanel = sal_False;
486 
487     // possibly create one job for collated output
488     sal_Bool bSinglePrintJobs = sal_False;
489     beans::PropertyValue* pSingleValue = i_rController.getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintCollateAsSingleJobs" ) ) );
490     if( pSingleValue )
491     {
492         pSingleValue->Value >>= bSinglePrintJobs;
493     }
494 
495     // FIXME: jobStarted() should be done after the print dialog has ended (if there is one)
496     // how do I know when that might be ?
497     i_rController.jobStarted();
498 
499 
500     int nCopies = i_rController.getPrinter()->GetCopyCount();
501     int nJobs = 1;
502     if( bSinglePrintJobs )
503     {
504         nJobs = nCopies;
505         nCopies = 1;
506     }
507 
508     for( int nCurJob = 0; nCurJob < nJobs; nCurJob++ )
509     {
510         aAccViewState.bNeedRestart = true;
511         do
512         {
513             if( aAccViewState.bNeedRestart )
514             {
515                 mnCurPageRangeStart = 0;
516                 mnCurPageRangeCount = 0;
517                 nAllPages = i_rController.getFilteredPageCount();
518             }
519 
520             aAccViewState.bNeedRestart = false;
521 
522             Size aCurSize( 21000, 29700 );
523             if( nAllPages > 0 )
524             {
525                 mnCurPageRangeCount = 1;
526                 aCurSize = getPageSize( i_rController, mnCurPageRangeStart );
527                 Size aNextSize( aCurSize );
528 
529                 // print pages up to a different size
530                 while( mnCurPageRangeCount + mnCurPageRangeStart < nAllPages )
531                 {
532                     aNextSize = getPageSize( i_rController, mnCurPageRangeStart + mnCurPageRangeCount );
533                     if( aCurSize == aNextSize // same page size
534                         ||
535                         (aCurSize.Width() == aNextSize.Height() && aCurSize.Height() == aNextSize.Width()) // same size, but different orientation
536                         )
537                     {
538                         mnCurPageRangeCount++;
539                     }
540                     else
541                         break;
542                 }
543             }
544             else
545                 mnCurPageRangeCount = 0;
546 
547             // now for the current run
548             mnStartPageOffsetX = mnStartPageOffsetY = 0;
549             // setup the paper size and orientation
550             // do this on our associated Printer object, since that is
551             // out interface to the applications which occasionally rely on the paper
552             // information (e.g. brochure printing scales to the found paper size)
553             // also SetPaperSizeUser has the advantage that we can share a
554             // platform independent paper matching algorithm
555             boost::shared_ptr<Printer> pPrinter( i_rController.getPrinter() );
556             pPrinter->SetMapMode( MapMode( MAP_100TH_MM ) );
557             pPrinter->SetPaperSizeUser( aCurSize, true );
558 
559             // create view
560             NSView* pPrintView = [[AquaPrintView alloc] initWithController: &i_rController withInfoPrinter: this];
561 
562             NSMutableDictionary* pPrintDict = [mpPrintInfo dictionary];
563 
564             // set filename
565             if( i_pFileName )
566             {
567                 [mpPrintInfo setJobDisposition: NSPrintSaveJob];
568                 NSString* pPath = CreateNSString( *i_pFileName );
569                 [pPrintDict setObject: pPath forKey: NSPrintSavePath];
570                 [pPath release];
571             }
572 
573             [pPrintDict setObject: [[NSNumber numberWithInt: nCopies] autorelease] forKey: NSPrintCopies];
574             if( nCopies > 1 )
575                 [pPrintDict setObject: [[NSNumber numberWithBool: pPrinter->IsCollateCopy()] autorelease] forKey: NSPrintMustCollate];
576             [pPrintDict setObject: [[NSNumber numberWithBool: YES] autorelease] forKey: NSPrintDetailedErrorReporting];
577             [pPrintDict setObject: [[NSNumber numberWithInt: 1] autorelease] forKey: NSPrintFirstPage];
578             // #i103253# weird: for some reason, autoreleasing the value below like the others above
579             // leads do a double free malloc error. Why this value should behave differently from all the others
580             // is a mystery.
581             [pPrintDict setObject: [NSNumber numberWithInt: mnCurPageRangeCount] forKey: NSPrintLastPage];
582 
583 
584             // create print operation
585             NSPrintOperation* pPrintOperation = [NSPrintOperation printOperationWithView: pPrintView printInfo: mpPrintInfo];
586 
587             if( pPrintOperation )
588             {
589                 NSObject* pReleaseAfterUse = nil;
590                 bool bShowPanel = (! i_rController.isDirectPrint() && getUseNativeDialog() && i_rController.isShowDialogs() );
591                 [pPrintOperation setShowsPrintPanel: bShowPanel ? YES : NO ];
592                 [pPrintOperation setShowsProgressPanel: bShowProgressPanel ? YES : NO];
593 
594                 // set job title (since MacOSX 10.5)
595                 if( [pPrintOperation respondsToSelector: @selector(setJobTitle:)] )
596                     [pPrintOperation performSelector: @selector(setJobTitle:) withObject: [CreateNSString( i_rJobName ) autorelease]];
597 
598                 if( bShowPanel && mnCurPageRangeStart == 0 && nCurJob == 0) // only the first range of pages (in the first job) gets the accesory view
599                     pReleaseAfterUse = [AquaPrintAccessoryView setupPrinterPanel: pPrintOperation withController: &i_rController withState: &aAccViewState];
600 
601                 bSuccess = sal_True;
602                 mbJob = true;
603                 pInst->startedPrintJob();
604                 [pPrintOperation runOperation];
605                 pInst->endedPrintJob();
606                 bWasAborted = [[[pPrintOperation printInfo] jobDisposition] compare: NSPrintCancelJob] == NSOrderedSame;
607                 mbJob = false;
608                 if( pReleaseAfterUse )
609                     [pReleaseAfterUse release];
610             }
611 
612             mnCurPageRangeStart += mnCurPageRangeCount;
613             mnCurPageRangeCount = 1;
614         } while( aAccViewState.bNeedRestart || mnCurPageRangeStart + mnCurPageRangeCount < nAllPages );
615     }
616 
617     // inform application that it can release its data
618     // this is awkward, but the XRenderable interface has no method for this,
619     // so we need to call XRenderadble::render one last time with IsLastPage = sal_True
620     i_rController.setLastPage( sal_True );
621     GDIMetaFile aPageFile;
622     if( mrContext )
623         SetupPrinterGraphics( mrContext );
624     i_rController.getFilteredPageFile( 0, aPageFile );
625 
626     i_rController.setJobState( bWasAborted
627                              ? view::PrintableState_JOB_ABORTED
628                              : view::PrintableState_JOB_SPOOLED );
629 
630     mnCurPageRangeStart = mnCurPageRangeCount = 0;
631 
632     return bSuccess;
633 }
634 
635 // -----------------------------------------------------------------------
636 
637 sal_Bool AquaSalInfoPrinter::EndJob()
638 {
639     mnStartPageOffsetX = mnStartPageOffsetY = 0;
640     mbJob = false;
641     return sal_True;
642 }
643 
644 // -----------------------------------------------------------------------
645 
646 sal_Bool AquaSalInfoPrinter::AbortJob()
647 {
648     mbJob = false;
649 
650     // FIXME: implementation
651 	return sal_False;
652 }
653 
654 // -----------------------------------------------------------------------
655 
656 SalGraphics* AquaSalInfoPrinter::StartPage( ImplJobSetup* i_pSetupData, sal_Bool i_bNewJobData )
657 {
658     if( i_bNewJobData && i_pSetupData )
659         SetPrinterData( i_pSetupData );
660 
661     CGContextRef rContext = reinterpret_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]);
662 
663     SetupPrinterGraphics( rContext );
664 
665 	return mpGraphics;
666 }
667 
668 // -----------------------------------------------------------------------
669 
670 sal_Bool AquaSalInfoPrinter::EndPage()
671 {
672     mpGraphics->InvalidateContext();
673 	return sal_True;
674 }
675 
676 // -----------------------------------------------------------------------
677 
678 sal_uLong AquaSalInfoPrinter::GetErrorCode() const
679 {
680 	return 0;
681 }
682 
683 // =======================================================================
684 
685 AquaSalPrinter::AquaSalPrinter( AquaSalInfoPrinter* i_pInfoPrinter ) :
686     mpInfoPrinter( i_pInfoPrinter )
687 {
688 }
689 
690 // -----------------------------------------------------------------------
691 
692 AquaSalPrinter::~AquaSalPrinter()
693 {
694 }
695 
696 // -----------------------------------------------------------------------
697 
698 sal_Bool AquaSalPrinter::StartJob( const String* i_pFileName,
699                                const String& i_rJobName,
700                                const String& i_rAppName,
701                                ImplJobSetup* i_pSetupData,
702                                vcl::PrinterController& i_rController )
703 {
704     return mpInfoPrinter->StartJob( i_pFileName, i_rJobName, i_rAppName, i_pSetupData, i_rController );
705 }
706 
707 // -----------------------------------------------------------------------
708 
709 sal_Bool AquaSalPrinter::StartJob( const XubString* /*i_pFileName*/,
710                                const XubString& /*i_rJobName*/,
711                                const XubString& /*i_rAppName*/,
712                                sal_uLong /*i_nCopies*/,
713                                bool /*i_bCollate*/,
714                                bool /*i_bDirect*/,
715                                ImplJobSetup* )
716 {
717     DBG_ERROR( "should never be called" );
718     return sal_False;
719 }
720 
721 // -----------------------------------------------------------------------
722 
723 sal_Bool AquaSalPrinter::EndJob()
724 {
725 	return mpInfoPrinter->EndJob();
726 }
727 
728 // -----------------------------------------------------------------------
729 
730 sal_Bool AquaSalPrinter::AbortJob()
731 {
732 	return mpInfoPrinter->AbortJob();
733 }
734 
735 // -----------------------------------------------------------------------
736 
737 SalGraphics* AquaSalPrinter::StartPage( ImplJobSetup* i_pSetupData, sal_Bool i_bNewJobData )
738 {
739 	return mpInfoPrinter->StartPage( i_pSetupData, i_bNewJobData );
740 }
741 
742 // -----------------------------------------------------------------------
743 
744 sal_Bool AquaSalPrinter::EndPage()
745 {
746 	return mpInfoPrinter->EndPage();
747 }
748 
749 // -----------------------------------------------------------------------
750 
751 sal_uLong AquaSalPrinter::GetErrorCode()
752 {
753 	return mpInfoPrinter->GetErrorCode();
754 }
755 
756 void AquaSalInfoPrinter::InitPaperFormats( const ImplJobSetup* )
757 {
758     m_aPaperFormats.clear();
759     m_bPapersInit = true;
760 
761     if( mpPrinter )
762     {
763         if( [mpPrinter statusForTable: @"PPD"] == NSPrinterTableOK )
764         {
765             NSArray* pPaperNames = [mpPrinter stringListForKey: @"PageSize" inTable: @"PPD"];
766             if( pPaperNames )
767             {
768                 unsigned int nPapers = [pPaperNames count];
769                 for( unsigned int i = 0; i < nPapers; i++ )
770                 {
771                     NSString* pPaper = [pPaperNames objectAtIndex: i];
772                     // first try to match the name
773                     rtl::OString aPaperName( [pPaper UTF8String] );
774                     Paper ePaper = PaperInfo::fromPSName( aPaperName );
775                     if( ePaper != PAPER_USER )
776                     {
777                         m_aPaperFormats.push_back( PaperInfo( ePaper ) );
778                     }
779                     else
780                     {
781                         NSSize aPaperSize = [mpPrinter pageSizeForPaper: pPaper];
782                         if( aPaperSize.width > 0 && aPaperSize.height > 0 )
783                         {
784                             PaperInfo aInfo( PtTo10Mu( aPaperSize.width ),
785                                              PtTo10Mu( aPaperSize.height ) );
786                             if( aInfo.getPaper() == PAPER_USER )
787                                 aInfo.doSloppyFit();
788                             m_aPaperFormats.push_back( aInfo );
789                         }
790                     }
791                 }
792             }
793         }
794     }
795 }
796 
797 const PaperInfo* AquaSalInfoPrinter::matchPaper( long i_nWidth, long i_nHeight, Orientation& o_rOrientation ) const
798 {
799     if( ! m_bPapersInit )
800         const_cast<AquaSalInfoPrinter*>(this)->InitPaperFormats( NULL );
801 
802     const PaperInfo* pMatch = NULL;
803     o_rOrientation = ORIENTATION_PORTRAIT;
804     for( int n = 0; n < 2 ; n++ )
805     {
806         for( size_t i = 0; i < m_aPaperFormats.size(); i++ )
807         {
808             if( abs( m_aPaperFormats[i].getWidth() - i_nWidth ) < 50 &&
809                 abs( m_aPaperFormats[i].getHeight() - i_nHeight ) < 50 )
810             {
811                 pMatch = &m_aPaperFormats[i];
812                 return pMatch;
813             }
814         }
815         o_rOrientation = ORIENTATION_LANDSCAPE;
816         std::swap( i_nWidth, i_nHeight );
817     }
818     return pMatch;
819 }
820 
821 int AquaSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* )
822 {
823     return 900;
824 }
825 
826 
827