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