xref: /aoo42x/main/vcl/aqua/source/gdi/salprn.cxx (revision cdf0e10c)
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 static struct PaperSizeEntry
189 {
190     double fWidth;
191     double fHeight;
192     Paper        nPaper;
193 } aPaperSizes[] =
194 {
195     { 842, 1191, PAPER_A3 },
196     { 595,  842, PAPER_A4 },
197     { 420,  595, PAPER_A5 },
198     { 612,  792, PAPER_LETTER },
199     { 612, 1008, PAPER_LEGAL },
200     { 728, 1032, PAPER_B4_JIS },
201     { 516,  729, PAPER_B5_JIS },
202     { 792, 1224, PAPER_TABLOID }
203 };
204 
205 static bool getPaperSize( double& o_fWidth, double& o_fHeight, const Paper i_ePaper )
206 {
207     for(unsigned int i = 0; i < sizeof(aPaperSizes)/sizeof(aPaperSizes[0]); i++ )
208     {
209         if( aPaperSizes[i].nPaper == i_ePaper )
210         {
211             o_fWidth = aPaperSizes[i].fWidth;
212             o_fHeight = aPaperSizes[i].fHeight;
213             return true;
214         }
215     }
216     return false;
217 }
218 
219 static Paper recognizePaper( double i_fWidth, double i_fHeight )
220 {
221     Paper aPaper = PAPER_USER;
222     sal_uInt64 nPaperDesc = 1000000*sal_uInt64(i_fWidth) + sal_uInt64(i_fHeight);
223     switch( nPaperDesc )
224     {
225     case 842001191: aPaper = PAPER_A3;      break;
226     case 595000842: aPaper = PAPER_A4;      break;
227     case 420000595: aPaper = PAPER_A5;      break;
228     case 612000792: aPaper = PAPER_LETTER;  break;
229     case 728001032: aPaper = PAPER_B4_JIS;  break;
230     case 516000729: aPaper = PAPER_B5_JIS;  break;
231     case 612001008: aPaper = PAPER_LEGAL;   break;
232     case 792001224: aPaper = PAPER_TABLOID; break;
233     default:
234         aPaper = PAPER_USER;
235         break;
236     }
237 
238     if( aPaper == PAPER_USER )
239     {
240         // search with fuzz factor
241         for( unsigned int i = 0; i < sizeof(aPaperSizes)/sizeof(aPaperSizes[0]); i++ )
242         {
243             double w = (i_fWidth > aPaperSizes[i].fWidth) ? i_fWidth - aPaperSizes[i].fWidth : aPaperSizes[i].fWidth - i_fWidth;
244             double h = (i_fHeight > aPaperSizes[i].fHeight) ? i_fHeight - aPaperSizes[i].fHeight : aPaperSizes[i].fHeight - i_fHeight;
245             if( w < 3 && h < 3 )
246             {
247                 aPaper = aPaperSizes[i].nPaper;
248                 break;
249             }
250         }
251     }
252 
253     return aPaper;
254 }
255 
256 sal_Bool AquaSalInfoPrinter::SetPrinterData( ImplJobSetup* io_pSetupData )
257 {
258     // FIXME: implement driver data
259     if( io_pSetupData && io_pSetupData->mpDriverData )
260         return SetData( ~0, io_pSetupData );
261 
262 
263     sal_Bool bSuccess = sal_True;
264 
265     // set system type
266     io_pSetupData->mnSystem = JOBSETUP_SYSTEM_MAC;
267 
268     // get paper format
269     if( mpPrintInfo )
270     {
271         NSSize aPaperSize = [mpPrintInfo paperSize];
272         double width = aPaperSize.width, height = aPaperSize.height;
273         // set paper
274         io_pSetupData->mePaperFormat = recognizePaper( width, height );
275         if( io_pSetupData->mePaperFormat == PAPER_USER )
276         {
277             io_pSetupData->mnPaperWidth = PtTo10Mu( width );
278             io_pSetupData->mnPaperHeight = PtTo10Mu( height );
279         }
280         else
281         {
282             io_pSetupData->mnPaperWidth = 0;
283             io_pSetupData->mnPaperHeight = 0;
284         }
285 
286         // set orientation
287         io_pSetupData->meOrientation = mePageOrientation;
288 
289         io_pSetupData->mnPaperBin = 0;
290         io_pSetupData->mpDriverData = reinterpret_cast<sal_uInt8*>(rtl_allocateMemory( 4 ));
291         io_pSetupData->mnDriverDataLen = 4;
292     }
293     else
294         bSuccess = sal_False;
295 
296 
297 	return bSuccess;
298 }
299 
300 // -----------------------------------------------------------------------
301 
302 void AquaSalInfoPrinter::setPaperSize( long i_nWidth, long i_nHeight, Orientation i_eSetOrientation )
303 {
304 
305     Orientation ePaperOrientation = ORIENTATION_PORTRAIT;
306     const PaperInfo* pPaper = matchPaper( i_nWidth, i_nHeight, ePaperOrientation );
307 
308     if( pPaper )
309     {
310         NSString* pPaperName = [CreateNSString( rtl::OStringToOUString(PaperInfo::toPSName(pPaper->getPaper()), RTL_TEXTENCODING_ASCII_US) ) autorelease];
311         [mpPrintInfo setPaperName: pPaperName];
312     }
313     else if( i_nWidth > 0 && i_nHeight > 0 )
314     {
315         NSSize aPaperSize = { TenMuToPt(i_nWidth), TenMuToPt(i_nHeight) };
316         [mpPrintInfo setPaperSize: aPaperSize];
317     }
318     // this seems counterintuitive
319     mePageOrientation = i_eSetOrientation;
320 }
321 
322 // -----------------------------------------------------------------------
323 
324 sal_Bool AquaSalInfoPrinter::SetData( sal_uLong i_nFlags, ImplJobSetup* io_pSetupData )
325 {
326     if( ! io_pSetupData || io_pSetupData->mnSystem != JOBSETUP_SYSTEM_MAC )
327         return sal_False;
328 
329 
330     if( mpPrintInfo )
331     {
332         if( (i_nFlags & SAL_JOBSET_ORIENTATION) != 0 )
333             mePageOrientation = io_pSetupData->meOrientation;
334 
335         if( (i_nFlags & SAL_JOBSET_PAPERSIZE) !=  0)
336         {
337             // set paper format
338             long width = 21000, height = 29700;
339             if( io_pSetupData->mePaperFormat == PAPER_USER )
340             {
341                 // #i101108# sanity check
342                 if( io_pSetupData->mnPaperWidth && io_pSetupData->mnPaperHeight )
343                 {
344                     width = io_pSetupData->mnPaperWidth;
345                     height = io_pSetupData->mnPaperHeight;
346                 }
347             }
348             else
349             {
350                 double w = 595,  h = 842;
351                 getPaperSize( w, h, io_pSetupData->mePaperFormat );
352                 width = static_cast<long>(PtTo10Mu( w ));
353                 height = static_cast<long>(PtTo10Mu( h ));
354             }
355 
356             setPaperSize( width, height, mePageOrientation );
357         }
358     }
359 
360 	return mpPrintInfo != nil;
361 }
362 
363 // -----------------------------------------------------------------------
364 
365 sal_uLong AquaSalInfoPrinter::GetPaperBinCount( const ImplJobSetup* )
366 {
367 	return 0;
368 }
369 
370 // -----------------------------------------------------------------------
371 
372 XubString AquaSalInfoPrinter::GetPaperBinName( const ImplJobSetup*, sal_uLong )
373 {
374 	return XubString();
375 }
376 
377 // -----------------------------------------------------------------------
378 
379 static bool getUseNativeDialog()
380 {
381     bool bNative = true;
382     try
383     {
384         // get service provider
385         uno::Reference< XMultiServiceFactory > xSMgr( unohelper::GetMultiServiceFactory() );
386         // create configuration hierachical access name
387         if( xSMgr.is() )
388         {
389             try
390             {
391                 uno::Reference< XMultiServiceFactory > xConfigProvider(
392                    uno::Reference< XMultiServiceFactory >(
393                         xSMgr->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
394                                         "com.sun.star.configuration.ConfigurationProvider" ))),
395                         UNO_QUERY )
396                     );
397                 if( xConfigProvider.is() )
398                 {
399                     Sequence< Any > aArgs(1);
400                     PropertyValue aVal;
401                     aVal.Name = OUString( RTL_CONSTASCII_USTRINGPARAM( "nodepath" ) );
402                     aVal.Value <<= OUString( RTL_CONSTASCII_USTRINGPARAM( "/org.openoffice.Office.Common/Misc" ) );
403                     aArgs.getArray()[0] <<= aVal;
404                     uno::Reference< XNameAccess > xConfigAccess(
405                         uno::Reference< XNameAccess >(
406                             xConfigProvider->createInstanceWithArguments( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(
407                                                 "com.sun.star.configuration.ConfigurationAccess" )),
408                                                                             aArgs ),
409                             UNO_QUERY )
410                         );
411                     if( xConfigAccess.is() )
412                     {
413                         try
414                         {
415                             sal_Bool bValue = sal_False;
416                             Any aAny = xConfigAccess->getByName( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "UseSystemPrintDialog" ) ) );
417                             if( aAny >>= bValue )
418                                 bNative = bValue;
419                         }
420                         catch( NoSuchElementException& )
421                         {
422                         }
423                         catch( WrappedTargetException& )
424                         {
425                         }
426                     }
427                 }
428             }
429             catch( Exception& )
430             {
431             }
432         }
433     }
434     catch( WrappedTargetException& )
435     {
436     }
437 
438     return bNative;
439 }
440 
441 sal_uLong AquaSalInfoPrinter::GetCapabilities( const ImplJobSetup*, sal_uInt16 i_nType )
442 {
443 	switch( i_nType )
444 	{
445 		case PRINTER_CAPABILITIES_SUPPORTDIALOG:
446 			return 0;
447 		case PRINTER_CAPABILITIES_COPIES:
448 			return 0xffff;
449 		case PRINTER_CAPABILITIES_COLLATECOPIES:
450 			return 0xffff;
451 		case PRINTER_CAPABILITIES_SETORIENTATION:
452 			return 1;
453 		case PRINTER_CAPABILITIES_SETDUPLEX:
454 			return 0;
455 		case PRINTER_CAPABILITIES_SETPAPERBIN:
456 			return 0;
457 		case PRINTER_CAPABILITIES_SETPAPERSIZE:
458 			return 1;
459 		case PRINTER_CAPABILITIES_SETPAPER:
460 			return 1;
461         case PRINTER_CAPABILITIES_EXTERNALDIALOG:
462             return getUseNativeDialog() ? 1 : 0;
463         case PRINTER_CAPABILITIES_PDF:
464             return 1;
465         case PRINTER_CAPABILITIES_USEPULLMODEL:
466             return 1;
467 		default: break;
468 	};
469 	return 0;
470 }
471 
472 // -----------------------------------------------------------------------
473 
474 void AquaSalInfoPrinter::GetPageInfo( const ImplJobSetup*,
475 								  long& o_rOutWidth, long& o_rOutHeight,
476 								  long& o_rPageOffX, long& o_rPageOffY,
477 								  long& o_rPageWidth, long& o_rPageHeight )
478 {
479     if( mpPrintInfo )
480     {
481         long nDPIX = 72, nDPIY = 72;
482         mpGraphics->GetResolution( nDPIX, nDPIY );
483         const double fXScaling = static_cast<double>(nDPIX)/72.0,
484                      fYScaling = static_cast<double>(nDPIY)/72.0;
485 
486         NSSize aPaperSize = [mpPrintInfo paperSize];
487         o_rPageWidth  = static_cast<long>( double(aPaperSize.width) * fXScaling );
488         o_rPageHeight = static_cast<long>( double(aPaperSize.height) * fYScaling );
489 
490         NSRect aImageRect = [mpPrintInfo imageablePageBounds];
491         o_rPageOffX   = static_cast<long>( aImageRect.origin.x * fXScaling );
492         o_rPageOffY   = static_cast<long>( (aPaperSize.height - aImageRect.size.height - aImageRect.origin.y) * fYScaling );
493         o_rOutWidth   = static_cast<long>( aImageRect.size.width * fXScaling );
494         o_rOutHeight  = static_cast<long>( aImageRect.size.height * fYScaling );
495 
496         if( mePageOrientation == ORIENTATION_LANDSCAPE )
497         {
498             std::swap( o_rOutWidth, o_rOutHeight );
499             std::swap( o_rPageWidth, o_rPageHeight );
500             std::swap( o_rPageOffX, o_rPageOffY );
501         }
502     }
503 }
504 
505 static Size getPageSize( vcl::PrinterController& i_rController, sal_Int32 i_nPage )
506 {
507     Size aPageSize;
508     Sequence< PropertyValue > aPageParms( i_rController.getPageParameters( i_nPage ) );
509     for( sal_Int32 nProperty = 0, nPropertyCount = aPageParms.getLength(); nProperty < nPropertyCount; ++nProperty )
510     {
511         if( aPageParms[ nProperty ].Name.equalsAscii( "PageSize" ) )
512         {
513             awt::Size aSize;
514             aPageParms[ nProperty].Value >>= aSize;
515             aPageSize.Width() = aSize.Width;
516             aPageSize.Height() = aSize.Height;
517             break;
518         }
519     }
520     return aPageSize;
521 }
522 
523 sal_Bool AquaSalInfoPrinter::StartJob( const String* i_pFileName,
524                                    const String& i_rJobName,
525                                    const String& /*i_rAppName*/,
526                                    ImplJobSetup* i_pSetupData,
527                                    vcl::PrinterController& i_rController
528                                    )
529 {
530     if( mbJob )
531         return sal_False;
532 
533     sal_Bool bSuccess = sal_False;
534     bool bWasAborted = false;
535     AquaSalInstance* pInst = GetSalData()->mpFirstInstance;
536     PrintAccessoryViewState aAccViewState;
537     sal_Int32 nAllPages = 0;
538 
539     // reset IsLastPage
540     i_rController.setLastPage( sal_False );
541 
542     // update job data
543     if( i_pSetupData )
544         SetData( ~0, i_pSetupData );
545 
546     // do we want a progress panel ?
547     sal_Bool bShowProgressPanel = sal_True;
548     beans::PropertyValue* pMonitor = i_rController.getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MonitorVisible" ) ) );
549     if( pMonitor )
550         pMonitor->Value >>= bShowProgressPanel;
551     if( ! i_rController.isShowDialogs() )
552         bShowProgressPanel = sal_False;
553 
554     // possibly create one job for collated output
555     sal_Bool bSinglePrintJobs = sal_False;
556     beans::PropertyValue* pSingleValue = i_rController.getValue( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "PrintCollateAsSingleJobs" ) ) );
557     if( pSingleValue )
558     {
559         pSingleValue->Value >>= bSinglePrintJobs;
560     }
561 
562     // FIXME: jobStarted() should be done after the print dialog has ended (if there is one)
563     // how do I know when that might be ?
564     i_rController.jobStarted();
565 
566 
567     int nCopies = i_rController.getPrinter()->GetCopyCount();
568     int nJobs = 1;
569     if( bSinglePrintJobs )
570     {
571         nJobs = nCopies;
572         nCopies = 1;
573     }
574 
575     for( int nCurJob = 0; nCurJob < nJobs; nCurJob++ )
576     {
577         aAccViewState.bNeedRestart = true;
578         do
579         {
580             if( aAccViewState.bNeedRestart )
581             {
582                 mnCurPageRangeStart = 0;
583                 mnCurPageRangeCount = 0;
584                 nAllPages = i_rController.getFilteredPageCount();
585             }
586 
587             aAccViewState.bNeedRestart = false;
588 
589             Size aCurSize( 21000, 29700 );
590             if( nAllPages > 0 )
591             {
592                 mnCurPageRangeCount = 1;
593                 aCurSize = getPageSize( i_rController, mnCurPageRangeStart );
594                 Size aNextSize( aCurSize );
595 
596                 // print pages up to a different size
597                 while( mnCurPageRangeCount + mnCurPageRangeStart < nAllPages )
598                 {
599                     aNextSize = getPageSize( i_rController, mnCurPageRangeStart + mnCurPageRangeCount );
600                     if( aCurSize == aNextSize // same page size
601                         ||
602                         (aCurSize.Width() == aNextSize.Height() && aCurSize.Height() == aNextSize.Width()) // same size, but different orientation
603                         )
604                     {
605                         mnCurPageRangeCount++;
606                     }
607                     else
608                         break;
609                 }
610             }
611             else
612                 mnCurPageRangeCount = 0;
613 
614             // now for the current run
615             mnStartPageOffsetX = mnStartPageOffsetY = 0;
616             // setup the paper size and orientation
617             // do this on our associated Printer object, since that is
618             // out interface to the applications which occasionally rely on the paper
619             // information (e.g. brochure printing scales to the found paper size)
620             // also SetPaperSizeUser has the advantage that we can share a
621             // platform independent paper matching algorithm
622             boost::shared_ptr<Printer> pPrinter( i_rController.getPrinter() );
623             pPrinter->SetMapMode( MapMode( MAP_100TH_MM ) );
624             pPrinter->SetPaperSizeUser( aCurSize, true );
625 
626             // create view
627             NSView* pPrintView = [[AquaPrintView alloc] initWithController: &i_rController withInfoPrinter: this];
628 
629             NSMutableDictionary* pPrintDict = [mpPrintInfo dictionary];
630 
631             // set filename
632             if( i_pFileName )
633             {
634                 [mpPrintInfo setJobDisposition: NSPrintSaveJob];
635                 NSString* pPath = CreateNSString( *i_pFileName );
636                 [pPrintDict setObject: pPath forKey: NSPrintSavePath];
637                 [pPath release];
638             }
639 
640             [pPrintDict setObject: [[NSNumber numberWithInt: nCopies] autorelease] forKey: NSPrintCopies];
641             if( nCopies > 1 )
642                 [pPrintDict setObject: [[NSNumber numberWithBool: pPrinter->IsCollateCopy()] autorelease] forKey: NSPrintMustCollate];
643             [pPrintDict setObject: [[NSNumber numberWithBool: YES] autorelease] forKey: NSPrintDetailedErrorReporting];
644             [pPrintDict setObject: [[NSNumber numberWithInt: 1] autorelease] forKey: NSPrintFirstPage];
645             // #i103253# weird: for some reason, autoreleasing the value below like the others above
646             // leads do a double free malloc error. Why this value should behave differently from all the others
647             // is a mystery.
648             [pPrintDict setObject: [NSNumber numberWithInt: mnCurPageRangeCount] forKey: NSPrintLastPage];
649 
650 
651             // create print operation
652             NSPrintOperation* pPrintOperation = [NSPrintOperation printOperationWithView: pPrintView printInfo: mpPrintInfo];
653 
654             if( pPrintOperation )
655             {
656                 NSObject* pReleaseAfterUse = nil;
657                 bool bShowPanel = (! i_rController.isDirectPrint() && getUseNativeDialog() && i_rController.isShowDialogs() );
658                 [pPrintOperation setShowsPrintPanel: bShowPanel ? YES : NO ];
659                 [pPrintOperation setShowsProgressPanel: bShowProgressPanel ? YES : NO];
660 
661                 // set job title (since MacOSX 10.5)
662                 if( [pPrintOperation respondsToSelector: @selector(setJobTitle:)] )
663                     [pPrintOperation performSelector: @selector(setJobTitle:) withObject: [CreateNSString( i_rJobName ) autorelease]];
664 
665                 if( bShowPanel && mnCurPageRangeStart == 0 && nCurJob == 0) // only the first range of pages (in the first job) gets the accesory view
666                     pReleaseAfterUse = [AquaPrintAccessoryView setupPrinterPanel: pPrintOperation withController: &i_rController withState: &aAccViewState];
667 
668                 bSuccess = sal_True;
669                 mbJob = true;
670                 pInst->startedPrintJob();
671                 [pPrintOperation runOperation];
672                 pInst->endedPrintJob();
673                 bWasAborted = [[[pPrintOperation printInfo] jobDisposition] compare: NSPrintCancelJob] == NSOrderedSame;
674                 mbJob = false;
675                 if( pReleaseAfterUse )
676                     [pReleaseAfterUse release];
677             }
678 
679             mnCurPageRangeStart += mnCurPageRangeCount;
680             mnCurPageRangeCount = 1;
681         } while( aAccViewState.bNeedRestart || mnCurPageRangeStart + mnCurPageRangeCount < nAllPages );
682     }
683 
684     // inform application that it can release its data
685     // this is awkward, but the XRenderable interface has no method for this,
686     // so we need to call XRenderadble::render one last time with IsLastPage = sal_True
687     i_rController.setLastPage( sal_True );
688     GDIMetaFile aPageFile;
689     if( mrContext )
690         SetupPrinterGraphics( mrContext );
691     i_rController.getFilteredPageFile( 0, aPageFile );
692 
693     i_rController.setJobState( bWasAborted
694                              ? view::PrintableState_JOB_ABORTED
695                              : view::PrintableState_JOB_SPOOLED );
696 
697     mnCurPageRangeStart = mnCurPageRangeCount = 0;
698 
699     return bSuccess;
700 }
701 
702 // -----------------------------------------------------------------------
703 
704 sal_Bool AquaSalInfoPrinter::EndJob()
705 {
706     mnStartPageOffsetX = mnStartPageOffsetY = 0;
707     mbJob = false;
708     return sal_True;
709 }
710 
711 // -----------------------------------------------------------------------
712 
713 sal_Bool AquaSalInfoPrinter::AbortJob()
714 {
715     mbJob = false;
716 
717     // FIXME: implementation
718 	return sal_False;
719 }
720 
721 // -----------------------------------------------------------------------
722 
723 SalGraphics* AquaSalInfoPrinter::StartPage( ImplJobSetup* i_pSetupData, sal_Bool i_bNewJobData )
724 {
725     if( i_bNewJobData && i_pSetupData )
726         SetPrinterData( i_pSetupData );
727 
728     CGContextRef rContext = reinterpret_cast<CGContextRef>([[NSGraphicsContext currentContext] graphicsPort]);
729 
730     SetupPrinterGraphics( rContext );
731 
732 	return mpGraphics;
733 }
734 
735 // -----------------------------------------------------------------------
736 
737 sal_Bool AquaSalInfoPrinter::EndPage()
738 {
739     mpGraphics->InvalidateContext();
740 	return sal_True;
741 }
742 
743 // -----------------------------------------------------------------------
744 
745 sal_uLong AquaSalInfoPrinter::GetErrorCode() const
746 {
747 	return 0;
748 }
749 
750 // =======================================================================
751 
752 AquaSalPrinter::AquaSalPrinter( AquaSalInfoPrinter* i_pInfoPrinter ) :
753     mpInfoPrinter( i_pInfoPrinter )
754 {
755 }
756 
757 // -----------------------------------------------------------------------
758 
759 AquaSalPrinter::~AquaSalPrinter()
760 {
761 }
762 
763 // -----------------------------------------------------------------------
764 
765 sal_Bool AquaSalPrinter::StartJob( const String* i_pFileName,
766                                const String& i_rJobName,
767                                const String& i_rAppName,
768                                ImplJobSetup* i_pSetupData,
769                                vcl::PrinterController& i_rController )
770 {
771     return mpInfoPrinter->StartJob( i_pFileName, i_rJobName, i_rAppName, i_pSetupData, i_rController );
772 }
773 
774 // -----------------------------------------------------------------------
775 
776 sal_Bool AquaSalPrinter::StartJob( const XubString* /*i_pFileName*/,
777                                const XubString& /*i_rJobName*/,
778                                const XubString& /*i_rAppName*/,
779                                sal_uLong /*i_nCopies*/,
780                                bool /*i_bCollate*/,
781                                bool /*i_bDirect*/,
782                                ImplJobSetup* )
783 {
784     DBG_ERROR( "should never be called" );
785     return sal_False;
786 }
787 
788 // -----------------------------------------------------------------------
789 
790 sal_Bool AquaSalPrinter::EndJob()
791 {
792 	return mpInfoPrinter->EndJob();
793 }
794 
795 // -----------------------------------------------------------------------
796 
797 sal_Bool AquaSalPrinter::AbortJob()
798 {
799 	return mpInfoPrinter->AbortJob();
800 }
801 
802 // -----------------------------------------------------------------------
803 
804 SalGraphics* AquaSalPrinter::StartPage( ImplJobSetup* i_pSetupData, sal_Bool i_bNewJobData )
805 {
806 	return mpInfoPrinter->StartPage( i_pSetupData, i_bNewJobData );
807 }
808 
809 // -----------------------------------------------------------------------
810 
811 sal_Bool AquaSalPrinter::EndPage()
812 {
813 	return mpInfoPrinter->EndPage();
814 }
815 
816 // -----------------------------------------------------------------------
817 
818 sal_uLong AquaSalPrinter::GetErrorCode()
819 {
820 	return mpInfoPrinter->GetErrorCode();
821 }
822 
823 void AquaSalInfoPrinter::InitPaperFormats( const ImplJobSetup* )
824 {
825     m_aPaperFormats.clear();
826     m_bPapersInit = true;
827 
828     if( mpPrinter )
829     {
830         if( [mpPrinter statusForTable: @"PPD"] == NSPrinterTableOK )
831         {
832             NSArray* pPaperNames = [mpPrinter stringListForKey: @"PageSize" inTable: @"PPD"];
833             if( pPaperNames )
834             {
835                 unsigned int nPapers = [pPaperNames count];
836                 for( unsigned int i = 0; i < nPapers; i++ )
837                 {
838                     NSString* pPaper = [pPaperNames objectAtIndex: i];
839                     // first try to match the name
840                     rtl::OString aPaperName( [pPaper UTF8String] );
841                     Paper ePaper = PaperInfo::fromPSName( aPaperName );
842                     if( ePaper != PAPER_USER )
843                     {
844                         m_aPaperFormats.push_back( PaperInfo( ePaper ) );
845                     }
846                     else
847                     {
848                         NSSize aPaperSize = [mpPrinter pageSizeForPaper: pPaper];
849                         if( aPaperSize.width > 0 && aPaperSize.height > 0 )
850                         {
851                             PaperInfo aInfo( PtTo10Mu( aPaperSize.width ),
852                                              PtTo10Mu( aPaperSize.height ) );
853                             if( aInfo.getPaper() == PAPER_USER )
854                                 aInfo.doSloppyFit();
855                             m_aPaperFormats.push_back( aInfo );
856                         }
857                     }
858                 }
859             }
860         }
861     }
862 }
863 
864 const PaperInfo* AquaSalInfoPrinter::matchPaper( long i_nWidth, long i_nHeight, Orientation& o_rOrientation ) const
865 {
866     if( ! m_bPapersInit )
867         const_cast<AquaSalInfoPrinter*>(this)->InitPaperFormats( NULL );
868 
869     const PaperInfo* pMatch = NULL;
870     o_rOrientation = ORIENTATION_PORTRAIT;
871     for( int n = 0; n < 2 ; n++ )
872     {
873         for( size_t i = 0; i < m_aPaperFormats.size(); i++ )
874         {
875             if( abs( m_aPaperFormats[i].getWidth() - i_nWidth ) < 50 &&
876                 abs( m_aPaperFormats[i].getHeight() - i_nHeight ) < 50 )
877             {
878                 pMatch = &m_aPaperFormats[i];
879                 return pMatch;
880             }
881         }
882         o_rOrientation = ORIENTATION_LANDSCAPE;
883         std::swap( i_nWidth, i_nHeight );
884     }
885     return pMatch;
886 }
887 
888 int AquaSalInfoPrinter::GetLandscapeAngle( const ImplJobSetup* )
889 {
890     return 900;
891 }
892 
893 
894