Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / vcl / source / gdi / print.cxx
blobe80fc25d777b7f7de0d9eece95651273da496a5f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/types.h>
21 #include <sal/log.hxx>
23 #include <tools/helpers.hxx>
24 #include <tools/debug.hxx>
26 #include <vcl/event.hxx>
27 #include <vcl/virdev.hxx>
28 #include <vcl/print.hxx>
30 #include <comphelper/processfactory.hxx>
32 #include <salinst.hxx>
33 #include <salvd.hxx>
34 #include <salgdi.hxx>
35 #include <salptype.hxx>
36 #include <salprn.hxx>
37 #include <svdata.hxx>
38 #include <print.hrc>
39 #include <jobset.h>
40 #include <outdev.h>
41 #include <PhysicalFontCollection.hxx>
42 #include <print.h>
44 #include <com/sun/star/beans/XPropertySet.hpp>
45 #include <com/sun/star/configuration/theDefaultProvider.hpp>
46 #include <com/sun/star/container/XNameAccess.hpp>
47 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
48 #include <com/sun/star/uno/Sequence.h>
50 int nImplSysDialog = 0;
52 namespace
54 Paper ImplGetPaperFormat( long nWidth100thMM, long nHeight100thMM )
56 PaperInfo aInfo(nWidth100thMM, nHeight100thMM);
57 aInfo.doSloppyFit();
58 return aInfo.getPaper();
61 const PaperInfo& ImplGetEmptyPaper()
63 static PaperInfo aInfo(PAPER_USER);
64 return aInfo;
68 void ImplUpdateJobSetupPaper( JobSetup& rJobSetup )
70 const ImplJobSetup& rConstData = rJobSetup.ImplGetConstData();
72 if ( !rConstData.GetPaperWidth() || !rConstData.GetPaperHeight() )
74 if ( rConstData.GetPaperFormat() != PAPER_USER )
76 PaperInfo aInfo(rConstData.GetPaperFormat());
78 ImplJobSetup& rData = rJobSetup.ImplGetData();
79 rData.SetPaperWidth( aInfo.getWidth() );
80 rData.SetPaperHeight( aInfo.getHeight() );
83 else if ( rConstData.GetPaperFormat() == PAPER_USER )
85 Paper ePaper = ImplGetPaperFormat( rConstData.GetPaperWidth(), rConstData.GetPaperHeight() );
86 if ( ePaper != PAPER_USER )
87 rJobSetup.ImplGetData().SetPaperFormat(ePaper);
91 // PrinterOptions
92 PrinterOptions::PrinterOptions() :
93 mbReduceTransparency( false ),
94 meReducedTransparencyMode( PrinterTransparencyMode::Auto ),
95 mbReduceGradients( false ),
96 meReducedGradientsMode( PrinterGradientMode::Stripes ),
97 mnReducedGradientStepCount( 64 ),
98 mbReduceBitmaps( false ),
99 meReducedBitmapMode( PrinterBitmapMode::Normal ),
100 mnReducedBitmapResolution( 200 ),
101 mbReducedBitmapsIncludeTransparency( true ),
102 mbConvertToGreyscales( false ),
103 mbPDFAsStandardPrintJobFormat( false )
107 void PrinterOptions::ReadFromConfig( bool i_bFile )
109 bool bSuccess = false;
110 // save old state in case something goes wrong
111 PrinterOptions aOldValues( *this );
113 // get the configuration service
114 css::uno::Reference< css::lang::XMultiServiceFactory > xConfigProvider;
115 css::uno::Reference< css::container::XNameAccess > xConfigAccess;
118 // get service provider
119 css::uno::Reference< css::uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
120 // create configuration hierarchical access name
123 xConfigProvider = css::configuration::theDefaultProvider::get( xContext );
125 css::uno::Sequence< css::uno::Any > aArgs(1);
126 css::beans::PropertyValue aVal;
127 aVal.Name = "nodepath";
128 if( i_bFile )
129 aVal.Value <<= OUString( "/org.openoffice.Office.Common/Print/Option/File" );
130 else
131 aVal.Value <<= OUString( "/org.openoffice.Office.Common/Print/Option/Printer" );
132 aArgs.getArray()[0] <<= aVal;
133 xConfigAccess.set(
134 xConfigProvider->createInstanceWithArguments(
135 "com.sun.star.configuration.ConfigurationAccess", aArgs ),
136 css::uno::UNO_QUERY );
137 if( xConfigAccess.is() )
139 css::uno::Reference< css::beans::XPropertySet > xSet( xConfigAccess, css::uno::UNO_QUERY );
140 if( xSet.is() )
142 sal_Int32 nValue = 0;
143 bool bValue = false;
144 if( xSet->getPropertyValue("ReduceTransparency") >>= bValue )
145 SetReduceTransparency( bValue );
146 if( xSet->getPropertyValue("ReducedTransparencyMode") >>= nValue )
147 SetReducedTransparencyMode( static_cast<PrinterTransparencyMode>(nValue) );
148 if( xSet->getPropertyValue("ReduceGradients") >>= bValue )
149 SetReduceGradients( bValue );
150 if( xSet->getPropertyValue("ReducedGradientMode") >>= nValue )
151 SetReducedGradientMode( static_cast<PrinterGradientMode>(nValue) );
152 if( xSet->getPropertyValue("ReducedGradientStepCount") >>= nValue )
153 SetReducedGradientStepCount( static_cast<sal_uInt16>(nValue) );
154 if( xSet->getPropertyValue("ReduceBitmaps") >>= bValue )
155 SetReduceBitmaps( bValue );
156 if( xSet->getPropertyValue("ReducedBitmapMode") >>= nValue )
157 SetReducedBitmapMode( static_cast<PrinterBitmapMode>(nValue) );
158 if( xSet->getPropertyValue("ReducedBitmapResolution") >>= nValue )
159 SetReducedBitmapResolution( static_cast<sal_uInt16>(nValue) );
160 if( xSet->getPropertyValue("ReducedBitmapIncludesTransparency") >>= bValue )
161 SetReducedBitmapIncludesTransparency( bValue );
162 if( xSet->getPropertyValue("ConvertToGreyscales") >>= bValue )
163 SetConvertToGreyscales( bValue );
164 if( xSet->getPropertyValue("PDFAsStandardPrintJobFormat") >>= bValue )
165 SetPDFAsStandardPrintJobFormat( bValue );
167 bSuccess = true;
171 catch( const css::uno::Exception& )
175 catch( const css::lang::WrappedTargetException& )
179 if( ! bSuccess )
180 *this = aOldValues;
183 bool Printer::DrawTransformBitmapExDirect(
184 const basegfx::B2DHomMatrix& /*aFullTransform*/,
185 const BitmapEx& /*rBitmapEx*/)
187 // printers can't draw bitmaps directly
188 return false;
191 bool Printer::TransformAndReduceBitmapExToTargetRange(
192 const basegfx::B2DHomMatrix& /*aFullTransform*/,
193 basegfx::B2DRange& /*aVisibleRange*/,
194 double& /*fMaximumArea*/)
196 // deliberately do nothing - you can't reduce the
197 // target range for a printer at all
198 return true;
201 void Printer::DrawDeviceBitmap( const Point& rDestPt, const Size& rDestSize,
202 const Point& rSrcPtPixel, const Size& rSrcSizePixel,
203 BitmapEx& rBmpEx )
205 if( rBmpEx.IsAlpha() )
207 // #107169# For true alpha bitmaps, no longer masking the
208 // bitmap, but perform a full alpha blend against a white
209 // background here.
210 Bitmap aBmp( rBmpEx.GetBitmap() );
211 aBmp.Blend( rBmpEx.GetAlpha(), COL_WHITE );
212 DrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, aBmp );
214 else
216 Bitmap aBmp( rBmpEx.GetBitmap() ), aMask( rBmpEx.GetMask() );
217 aBmp.Replace( aMask, COL_WHITE );
218 ImplPrintTransparent( aBmp, aMask, rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel );
222 void Printer::EmulateDrawTransparent ( const tools::PolyPolygon& rPolyPoly,
223 sal_uInt16 nTransparencePercent )
225 // #110958# Disable alpha VDev, we perform the necessary
226 VirtualDevice* pOldAlphaVDev = mpAlphaVDev;
228 // operation explicitly further below.
229 if( mpAlphaVDev )
230 mpAlphaVDev = nullptr;
232 GDIMetaFile* pOldMetaFile = mpMetaFile;
233 mpMetaFile = nullptr;
235 mpMetaFile = pOldMetaFile;
237 // #110958# Restore disabled alpha VDev
238 mpAlphaVDev = pOldAlphaVDev;
240 tools::Rectangle aPolyRect( LogicToPixel( rPolyPoly ).GetBoundRect() );
241 const Size aDPISize( LogicToPixel(Size(1, 1), MapMode(MapUnit::MapInch)) );
242 const long nBaseExtent = std::max( FRound( aDPISize.Width() / 300. ), 1L );
243 long nMove;
244 const sal_uInt16 nTrans = ( nTransparencePercent < 13 ) ? 0 :
245 ( nTransparencePercent < 38 ) ? 25 :
246 ( nTransparencePercent < 63 ) ? 50 :
247 ( nTransparencePercent < 88 ) ? 75 : 100;
249 switch( nTrans )
251 case 25: nMove = nBaseExtent * 3; break;
252 case 50: nMove = nBaseExtent * 4; break;
253 case 75: nMove = nBaseExtent * 6; break;
255 // #i112959# very transparent (88 < nTransparencePercent <= 99)
256 case 100: nMove = nBaseExtent * 8; break;
258 // #i112959# not transparent (nTransparencePercent < 13)
259 default: nMove = 0; break;
262 Push( PushFlags::CLIPREGION | PushFlags::LINECOLOR );
263 IntersectClipRegion(vcl::Region(rPolyPoly));
264 SetLineColor( GetFillColor() );
265 const bool bOldMap = mbMap;
266 EnableMapMode( false );
268 if(nMove)
270 tools::Rectangle aRect( aPolyRect.TopLeft(), Size( aPolyRect.GetWidth(), nBaseExtent ) );
271 while( aRect.Top() <= aPolyRect.Bottom() )
273 DrawRect( aRect );
274 aRect.Move( 0, nMove );
277 aRect = tools::Rectangle( aPolyRect.TopLeft(), Size( nBaseExtent, aPolyRect.GetHeight() ) );
278 while( aRect.Left() <= aPolyRect.Right() )
280 DrawRect( aRect );
281 aRect.Move( nMove, 0 );
284 else
286 // #i112959# if not transparent, draw full rectangle in clip region
287 DrawRect( aPolyRect );
290 EnableMapMode( bOldMap );
291 Pop();
293 mpMetaFile = pOldMetaFile;
295 // #110958# Restore disabled alpha VDev
296 mpAlphaVDev = pOldAlphaVDev;
299 void Printer::DrawOutDev( const Point& /*rDestPt*/, const Size& /*rDestSize*/,
300 const Point& /*rSrcPt*/, const Size& /*rSrcSize*/ )
302 SAL_WARN( "vcl.gdi", "Don't use OutputDevice::DrawOutDev(...) with printer devices!" );
305 void Printer::DrawOutDev( const Point& /*rDestPt*/, const Size& /*rDestSize*/,
306 const Point& /*rSrcPt*/, const Size& /*rSrcSize*/,
307 const OutputDevice& /*rOutDev*/ )
309 SAL_WARN( "vcl.gdi", "Don't use OutputDevice::DrawOutDev(...) with printer devices!" );
312 void Printer::CopyArea( const Point& /*rDestPt*/,
313 const Point& /*rSrcPt*/, const Size& /*rSrcSize*/,
314 bool /*bWindowInvalidate*/ )
316 SAL_WARN( "vcl.gdi", "Don't use OutputDevice::CopyArea(...) with printer devices!" );
319 void Printer::SetPrinterOptions( const PrinterOptions& i_rOptions )
321 *mpPrinterOptions = i_rOptions;
324 bool Printer::HasMirroredGraphics() const
326 // due to a "hotfix" for AOO bug i55719, this needs to return false
327 return false;
330 // QueueInfo
331 QueueInfo::QueueInfo()
333 mnStatus = PrintQueueFlags::NONE;
334 mnJobs = 0;
337 SalPrinterQueueInfo::SalPrinterQueueInfo()
339 mnStatus = PrintQueueFlags::NONE;
340 mnJobs = QUEUE_JOBS_DONTKNOW;
343 SalPrinterQueueInfo::~SalPrinterQueueInfo()
347 ImplPrnQueueList::~ImplPrnQueueList()
351 void ImplPrnQueueList::Add( std::unique_ptr<SalPrinterQueueInfo> pData )
353 std::unordered_map< OUString, sal_Int32 >::iterator it =
354 m_aNameToIndex.find( pData->maPrinterName );
355 if( it == m_aNameToIndex.end() )
357 m_aNameToIndex[ pData->maPrinterName ] = m_aQueueInfos.size();
358 m_aPrinterList.push_back( pData->maPrinterName );
359 m_aQueueInfos.push_back( ImplPrnQueueData() );
360 m_aQueueInfos.back().mpQueueInfo = nullptr;
361 m_aQueueInfos.back().mpSalQueueInfo = std::move(pData);
363 else // this should not happen, but ...
365 ImplPrnQueueData& rData = m_aQueueInfos[ it->second ];
366 rData.mpQueueInfo.reset();
367 rData.mpSalQueueInfo = std::move(pData);
371 ImplPrnQueueData* ImplPrnQueueList::Get( const OUString& rPrinter )
373 ImplPrnQueueData* pData = nullptr;
374 std::unordered_map<OUString,sal_Int32>::iterator it =
375 m_aNameToIndex.find( rPrinter );
376 if( it != m_aNameToIndex.end() )
377 pData = &m_aQueueInfos[it->second];
378 return pData;
381 static void ImplInitPrnQueueList()
383 ImplSVData* pSVData = ImplGetSVData();
385 pSVData->maGDIData.mpPrinterQueueList.reset(new ImplPrnQueueList);
387 static const char* pEnv = getenv( "SAL_DISABLE_PRINTERLIST" );
388 if( !pEnv || !*pEnv )
389 pSVData->mpDefInst->GetPrinterQueueInfo( pSVData->maGDIData.mpPrinterQueueList.get() );
392 void ImplDeletePrnQueueList()
394 ImplSVData* pSVData = ImplGetSVData();
395 pSVData->maGDIData.mpPrinterQueueList.reset();
398 const std::vector<OUString>& Printer::GetPrinterQueues()
400 ImplSVData* pSVData = ImplGetSVData();
401 if ( !pSVData->maGDIData.mpPrinterQueueList )
402 ImplInitPrnQueueList();
403 return pSVData->maGDIData.mpPrinterQueueList->m_aPrinterList;
406 const QueueInfo* Printer::GetQueueInfo( const OUString& rPrinterName, bool bStatusUpdate )
408 ImplSVData* pSVData = ImplGetSVData();
410 if ( !pSVData->maGDIData.mpPrinterQueueList )
411 ImplInitPrnQueueList();
413 if ( !pSVData->maGDIData.mpPrinterQueueList )
414 return nullptr;
416 ImplPrnQueueData* pInfo = pSVData->maGDIData.mpPrinterQueueList->Get( rPrinterName );
417 if( pInfo )
419 if( !pInfo->mpQueueInfo || bStatusUpdate )
420 pSVData->mpDefInst->GetPrinterQueueState( pInfo->mpSalQueueInfo.get() );
422 if ( !pInfo->mpQueueInfo )
423 pInfo->mpQueueInfo.reset(new QueueInfo);
425 pInfo->mpQueueInfo->maPrinterName = pInfo->mpSalQueueInfo->maPrinterName;
426 pInfo->mpQueueInfo->maDriver = pInfo->mpSalQueueInfo->maDriver;
427 pInfo->mpQueueInfo->maLocation = pInfo->mpSalQueueInfo->maLocation;
428 pInfo->mpQueueInfo->maComment = pInfo->mpSalQueueInfo->maComment;
429 pInfo->mpQueueInfo->mnStatus = pInfo->mpSalQueueInfo->mnStatus;
430 pInfo->mpQueueInfo->mnJobs = pInfo->mpSalQueueInfo->mnJobs;
431 return pInfo->mpQueueInfo.get();
433 return nullptr;
436 OUString Printer::GetDefaultPrinterName()
438 static const char* pEnv = getenv( "SAL_DISABLE_DEFAULTPRINTER" );
439 if( !pEnv || !*pEnv )
441 ImplSVData* pSVData = ImplGetSVData();
443 return pSVData->mpDefInst->GetDefaultPrinter();
445 return OUString();
448 void Printer::ImplInitData()
450 mbDevOutput = false;
451 mbDefPrinter = false;
452 mnError = ERRCODE_NONE;
453 mnPageQueueSize = 0;
454 mnCopyCount = 1;
455 mbCollateCopy = false;
456 mbPrinting = false;
457 mbJobActive = false;
458 mbPrintFile = false;
459 mbInPrintPage = false;
460 mbNewJobSetup = false;
461 mpInfoPrinter = nullptr;
462 mpPrinter = nullptr;
463 mpDisplayDev = nullptr;
464 mpPrinterOptions.reset(new PrinterOptions);
466 // Add printer to the list
467 ImplSVData* pSVData = ImplGetSVData();
468 mpNext = pSVData->maGDIData.mpFirstPrinter;
469 mpPrev = nullptr;
470 if ( mpNext )
471 mpNext->mpPrev = this;
472 pSVData->maGDIData.mpFirstPrinter = this;
475 bool Printer::AcquireGraphics() const
477 DBG_TESTSOLARMUTEX();
479 if ( mpGraphics )
480 return true;
482 mbInitLineColor = true;
483 mbInitFillColor = true;
484 mbInitFont = true;
485 mbInitTextColor = true;
486 mbInitClipRegion = true;
488 ImplSVData* pSVData = ImplGetSVData();
490 if ( mpJobGraphics )
491 mpGraphics = mpJobGraphics;
492 else if ( mpDisplayDev )
494 const VirtualDevice* pVirDev = mpDisplayDev;
495 mpGraphics = pVirDev->mpVirDev->AcquireGraphics();
496 // if needed retry after releasing least recently used virtual device graphics
497 while ( !mpGraphics )
499 if ( !pSVData->maGDIData.mpLastVirGraphics )
500 break;
501 pSVData->maGDIData.mpLastVirGraphics->ReleaseGraphics();
502 mpGraphics = pVirDev->mpVirDev->AcquireGraphics();
504 // update global LRU list of virtual device graphics
505 if ( mpGraphics )
507 mpNextGraphics = pSVData->maGDIData.mpFirstVirGraphics;
508 pSVData->maGDIData.mpFirstVirGraphics = const_cast<Printer*>(this);
509 if ( mpNextGraphics )
510 mpNextGraphics->mpPrevGraphics = const_cast<Printer*>(this);
511 if ( !pSVData->maGDIData.mpLastVirGraphics )
512 pSVData->maGDIData.mpLastVirGraphics = const_cast<Printer*>(this);
515 else
517 mpGraphics = mpInfoPrinter->AcquireGraphics();
518 // if needed retry after releasing least recently used printer graphics
519 while ( !mpGraphics )
521 if ( !pSVData->maGDIData.mpLastPrnGraphics )
522 break;
523 pSVData->maGDIData.mpLastPrnGraphics->ReleaseGraphics();
524 mpGraphics = mpInfoPrinter->AcquireGraphics();
526 // update global LRU list of printer graphics
527 if ( mpGraphics )
529 mpNextGraphics = pSVData->maGDIData.mpFirstPrnGraphics;
530 pSVData->maGDIData.mpFirstPrnGraphics = const_cast<Printer*>(this);
531 if ( mpNextGraphics )
532 mpNextGraphics->mpPrevGraphics = const_cast<Printer*>(this);
533 if ( !pSVData->maGDIData.mpLastPrnGraphics )
534 pSVData->maGDIData.mpLastPrnGraphics = const_cast<Printer*>(this);
538 if ( mpGraphics )
540 mpGraphics->SetXORMode( (RasterOp::Invert == meRasterOp) || (RasterOp::Xor == meRasterOp), RasterOp::Invert == meRasterOp );
541 mpGraphics->setAntiAliasB2DDraw(bool(mnAntialiasing & AntialiasingFlags::EnableB2dDraw));
544 return mpGraphics != nullptr;
547 void Printer::ImplReleaseFonts()
549 #ifdef UNX
550 // HACK to fix an urgent P1 printing issue fast
551 // WinSalPrinter does not respect GetGraphics/ReleaseGraphics conventions
552 // so Printer::mpGraphics often points to a dead WinSalGraphics
553 // TODO: fix WinSalPrinter's GetGraphics/ReleaseGraphics handling
554 mpGraphics->ReleaseFonts();
555 #endif
556 mbNewFont = true;
557 mbInitFont = true;
559 mpFontInstance.clear();
560 mpDeviceFontList.reset();
561 mpDeviceFontSizeList.reset();
564 void Printer::ReleaseGraphics( bool bRelease )
566 DBG_TESTSOLARMUTEX();
568 if ( !mpGraphics )
569 return;
571 // release the fonts of the physically released graphics device
572 if( bRelease )
573 ImplReleaseFonts();
575 ImplSVData* pSVData = ImplGetSVData();
577 Printer* pPrinter = this;
579 if ( !pPrinter->mpJobGraphics )
581 if ( pPrinter->mpDisplayDev )
583 VirtualDevice* pVirDev = pPrinter->mpDisplayDev;
584 if ( bRelease )
585 pVirDev->mpVirDev->ReleaseGraphics( mpGraphics );
586 // remove from global LRU list of virtual device graphics
587 if ( mpPrevGraphics )
588 mpPrevGraphics->mpNextGraphics = mpNextGraphics;
589 else
590 pSVData->maGDIData.mpFirstVirGraphics = mpNextGraphics;
591 if ( mpNextGraphics )
592 mpNextGraphics->mpPrevGraphics = mpPrevGraphics;
593 else
594 pSVData->maGDIData.mpLastVirGraphics = mpPrevGraphics;
596 else
598 if ( bRelease )
599 pPrinter->mpInfoPrinter->ReleaseGraphics( mpGraphics );
600 // remove from global LRU list of printer graphics
601 if ( mpPrevGraphics )
602 mpPrevGraphics->mpNextGraphics = mpNextGraphics;
603 else
604 pSVData->maGDIData.mpFirstPrnGraphics = mpNextGraphics;
605 if ( mpNextGraphics )
606 mpNextGraphics->mpPrevGraphics = mpPrevGraphics;
607 else
608 pSVData->maGDIData.mpLastPrnGraphics = mpPrevGraphics;
612 mpGraphics = nullptr;
613 mpPrevGraphics = nullptr;
614 mpNextGraphics = nullptr;
617 void Printer::ImplInit( SalPrinterQueueInfo* pInfo )
619 ImplSVData* pSVData = ImplGetSVData();
620 // #i74084# update info for this specific SalPrinterQueueInfo
621 pSVData->mpDefInst->GetPrinterQueueState( pInfo );
623 // Test whether the driver actually matches the JobSetup
624 ImplJobSetup& rData = maJobSetup.ImplGetData();
625 if ( rData.GetDriverData() )
627 if ( rData.GetPrinterName() != pInfo->maPrinterName ||
628 rData.GetDriver() != pInfo->maDriver )
630 std::free( const_cast<sal_uInt8*>(rData.GetDriverData()) );
631 rData.SetDriverData(nullptr);
632 rData.SetDriverDataLen(0);
636 // Remember printer name
637 maPrinterName = pInfo->maPrinterName;
638 maDriver = pInfo->maDriver;
640 // Add printer name to JobSetup
641 rData.SetPrinterName( maPrinterName );
642 rData.SetDriver( maDriver );
644 mpInfoPrinter = pSVData->mpDefInst->CreateInfoPrinter( pInfo, &rData );
645 mpPrinter = nullptr;
646 mpJobGraphics = nullptr;
647 ImplUpdateJobSetupPaper( maJobSetup );
649 if ( !mpInfoPrinter )
651 ImplInitDisplay();
652 return;
655 // we need a graphics
656 if ( !AcquireGraphics() )
658 ImplInitDisplay();
659 return;
662 // Init data
663 ImplUpdatePageData();
664 mxFontCollection.reset(new PhysicalFontCollection);
665 mxFontCache.reset(new ImplFontCache);
666 mpGraphics->GetDevFontList(mxFontCollection.get());
669 void Printer::ImplInitDisplay()
671 ImplSVData* pSVData = ImplGetSVData();
673 mpInfoPrinter = nullptr;
674 mpPrinter = nullptr;
675 mpJobGraphics = nullptr;
677 mpDisplayDev = VclPtr<VirtualDevice>::Create();
678 mxFontCollection = pSVData->maGDIData.mxScreenFontList;
679 mxFontCache = pSVData->maGDIData.mxScreenFontCache;
680 mnDPIX = mpDisplayDev->mnDPIX;
681 mnDPIY = mpDisplayDev->mnDPIY;
684 void Printer::DrawDeviceMask( const Bitmap& rMask, const Color& rMaskColor,
685 const Point& rDestPt, const Size& rDestSize,
686 const Point& rSrcPtPixel, const Size& rSrcSizePixel )
688 Point aDestPt( LogicToPixel( rDestPt ) );
689 Size aDestSz( LogicToPixel( rDestSize ) );
690 tools::Rectangle aSrcRect( rSrcPtPixel, rSrcSizePixel );
692 aSrcRect.Justify();
694 if( !(!rMask.IsEmpty() && aSrcRect.GetWidth() && aSrcRect.GetHeight() && aDestSz.Width() && aDestSz.Height()) )
695 return;
697 Bitmap aMask( rMask );
698 BmpMirrorFlags nMirrFlags = BmpMirrorFlags::NONE;
700 if( aMask.GetBitCount() > 1 )
701 aMask.Convert( BmpConversion::N1BitThreshold );
703 // mirrored horizontically
704 if( aDestSz.Width() < 0 )
706 aDestSz.setWidth( -aDestSz.Width() );
707 aDestPt.AdjustX( -( aDestSz.Width() - 1 ) );
708 nMirrFlags |= BmpMirrorFlags::Horizontal;
711 // mirrored vertically
712 if( aDestSz.Height() < 0 )
714 aDestSz.setHeight( -aDestSz.Height() );
715 aDestPt.AdjustY( -( aDestSz.Height() - 1 ) );
716 nMirrFlags |= BmpMirrorFlags::Vertical;
719 // source cropped?
720 if( aSrcRect != tools::Rectangle( Point(), aMask.GetSizePixel() ) )
721 aMask.Crop( aSrcRect );
723 // destination mirrored
724 if( nMirrFlags != BmpMirrorFlags::NONE)
725 aMask.Mirror( nMirrFlags );
727 // do painting
728 const long nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight();
729 long nX, nY; //, nWorkX, nWorkY, nWorkWidth, nWorkHeight;
730 std::unique_ptr<long[]> pMapX( new long[ nSrcWidth + 1 ] );
731 std::unique_ptr<long[]> pMapY( new long[ nSrcHeight + 1 ] );
732 GDIMetaFile* pOldMetaFile = mpMetaFile;
733 const bool bOldMap = mbMap;
735 mpMetaFile = nullptr;
736 mbMap = false;
737 Push( PushFlags::FILLCOLOR | PushFlags::LINECOLOR );
738 SetLineColor( rMaskColor );
739 SetFillColor( rMaskColor );
740 InitLineColor();
741 InitFillColor();
743 // create forward mapping tables
744 for( nX = 0; nX <= nSrcWidth; nX++ )
745 pMapX[ nX ] = aDestPt.X() + FRound( static_cast<double>(aDestSz.Width()) * nX / nSrcWidth );
747 for( nY = 0; nY <= nSrcHeight; nY++ )
748 pMapY[ nY ] = aDestPt.Y() + FRound( static_cast<double>(aDestSz.Height()) * nY / nSrcHeight );
750 // walk through all rectangles of mask
751 const vcl::Region aWorkRgn(aMask.CreateRegion(COL_BLACK, tools::Rectangle(Point(), aMask.GetSizePixel())));
752 RectangleVector aRectangles;
753 aWorkRgn.GetRegionRectangles(aRectangles);
755 for (auto const& rectangle : aRectangles)
757 const Point aMapPt(pMapX[rectangle.Left()], pMapY[rectangle.Top()]);
758 const Size aMapSz(
759 pMapX[rectangle.Right() + 1] - aMapPt.X(), // pMapX[L + W] -> L + ((R - L) + 1) -> R + 1
760 pMapY[rectangle.Bottom() + 1] - aMapPt.Y()); // same for Y
762 DrawRect(tools::Rectangle(aMapPt, aMapSz));
765 Pop();
766 mbMap = bOldMap;
767 mpMetaFile = pOldMetaFile;
770 SalPrinterQueueInfo* Printer::ImplGetQueueInfo( const OUString& rPrinterName,
771 const OUString* pDriver )
773 ImplSVData* pSVData = ImplGetSVData();
774 if ( !pSVData->maGDIData.mpPrinterQueueList )
775 ImplInitPrnQueueList();
777 ImplPrnQueueList* pPrnList = pSVData->maGDIData.mpPrinterQueueList.get();
778 if ( pPrnList && !pPrnList->m_aQueueInfos.empty() )
780 // first search for the printer name directly
781 ImplPrnQueueData* pInfo = pPrnList->Get( rPrinterName );
782 if( pInfo )
783 return pInfo->mpSalQueueInfo.get();
785 // then search case insensitive
786 for(const ImplPrnQueueData & rQueueInfo : pPrnList->m_aQueueInfos)
788 if( rQueueInfo.mpSalQueueInfo->maPrinterName.equalsIgnoreAsciiCase( rPrinterName ) )
789 return rQueueInfo.mpSalQueueInfo.get();
792 // then search for driver name
793 if ( pDriver )
795 for(const ImplPrnQueueData & rQueueInfo : pPrnList->m_aQueueInfos)
797 if( rQueueInfo.mpSalQueueInfo->maDriver == *pDriver )
798 return rQueueInfo.mpSalQueueInfo.get();
802 // then the default printer
803 pInfo = pPrnList->Get( GetDefaultPrinterName() );
804 if( pInfo )
805 return pInfo->mpSalQueueInfo.get();
807 // last chance: the first available printer
808 return pPrnList->m_aQueueInfos[0].mpSalQueueInfo.get();
811 return nullptr;
814 void Printer::ImplUpdatePageData()
816 // we need a graphics
817 if ( !AcquireGraphics() )
818 return;
820 mpGraphics->GetResolution( mnDPIX, mnDPIY );
821 mpInfoPrinter->GetPageInfo( &maJobSetup.ImplGetConstData(),
822 mnOutWidth, mnOutHeight,
823 maPageOffset,
824 maPaperSize );
827 void Printer::ImplUpdateFontList()
829 ImplUpdateFontData();
832 long Printer::GetGradientStepCount( long nMinRect )
834 // use display-equivalent step size calculation
835 long nInc = (nMinRect < 800) ? 10 : 20;
837 return nInc;
840 Printer::Printer()
841 : OutputDevice(OUTDEV_PRINTER)
843 ImplInitData();
844 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( GetDefaultPrinterName(), nullptr );
845 if ( pInfo )
847 ImplInit( pInfo );
848 if ( !IsDisplayPrinter() )
849 mbDefPrinter = true;
851 else
852 ImplInitDisplay();
855 Printer::Printer( const JobSetup& rJobSetup )
856 : OutputDevice(OUTDEV_PRINTER)
857 , maJobSetup(rJobSetup)
859 ImplInitData();
860 const ImplJobSetup& rConstData = rJobSetup.ImplGetConstData();
861 OUString aDriver = rConstData.GetDriver();
862 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( rConstData.GetPrinterName(),
863 &aDriver );
864 if ( pInfo )
866 ImplInit( pInfo );
867 SetJobSetup( rJobSetup );
869 else
871 ImplInitDisplay();
872 maJobSetup = JobSetup();
876 Printer::Printer( const QueueInfo& rQueueInfo )
877 : OutputDevice(OUTDEV_PRINTER)
879 ImplInitData();
880 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( rQueueInfo.GetPrinterName(),
881 &rQueueInfo.GetDriver() );
882 if ( pInfo )
883 ImplInit( pInfo );
884 else
885 ImplInitDisplay();
888 Printer::Printer( const OUString& rPrinterName )
889 : OutputDevice(OUTDEV_PRINTER)
891 ImplInitData();
892 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( rPrinterName, nullptr );
893 if ( pInfo )
894 ImplInit( pInfo );
895 else
896 ImplInitDisplay();
899 Printer::~Printer()
901 disposeOnce();
904 void Printer::dispose()
906 SAL_WARN_IF( IsPrinting(), "vcl.gdi", "Printer::~Printer() - Job is printing" );
907 SAL_WARN_IF( IsJobActive(), "vcl.gdi", "Printer::~Printer() - Job is active" );
909 mpPrinterOptions.reset();
911 ReleaseGraphics();
912 if ( mpInfoPrinter )
913 ImplGetSVData()->mpDefInst->DestroyInfoPrinter( mpInfoPrinter );
914 if ( mpDisplayDev )
915 mpDisplayDev.disposeAndClear();
916 else
918 // OutputDevice Dtor is trying the same thing; that why we need to set
919 // the FontEntry to NULL here
920 // TODO: consolidate duplicate cleanup by Printer and OutputDevice
921 mpFontInstance.clear();
922 mpDeviceFontList.reset();
923 mpDeviceFontSizeList.reset();
924 mxFontCache.reset();
925 // font list deleted by OutputDevice dtor
928 // Add printer from the list
929 ImplSVData* pSVData = ImplGetSVData();
930 if ( mpPrev )
931 mpPrev->mpNext = mpNext;
932 else
933 pSVData->maGDIData.mpFirstPrinter = mpNext;
934 if ( mpNext )
935 mpNext->mpPrev = mpPrev;
937 mpPrev.clear();
938 mpNext.clear();
939 OutputDevice::dispose();
942 sal_uInt32 Printer::GetCapabilities( PrinterCapType nType ) const
944 if ( IsDisplayPrinter() )
945 return 0;
947 if( mpInfoPrinter )
948 return mpInfoPrinter->GetCapabilities( &maJobSetup.ImplGetConstData(), nType );
949 else
950 return 0;
953 bool Printer::HasSupport( PrinterSupport eFeature ) const
955 switch ( eFeature )
957 case PrinterSupport::SetOrientation:
958 return GetCapabilities( PrinterCapType::SetOrientation ) != 0;
959 case PrinterSupport::SetPaperSize:
960 return GetCapabilities( PrinterCapType::SetPaperSize ) != 0;
961 case PrinterSupport::SetPaper:
962 return GetCapabilities( PrinterCapType::SetPaper ) != 0;
963 case PrinterSupport::CollateCopy:
964 return (GetCapabilities( PrinterCapType::CollateCopies ) != 0);
965 case PrinterSupport::SetupDialog:
966 return GetCapabilities( PrinterCapType::SupportDialog ) != 0;
969 return true;
972 bool Printer::SetJobSetup( const JobSetup& rSetup )
974 if ( IsDisplayPrinter() || mbInPrintPage )
975 return false;
977 JobSetup aJobSetup = rSetup;
979 ReleaseGraphics();
980 if ( mpInfoPrinter->SetPrinterData( &aJobSetup.ImplGetData() ) )
982 ImplUpdateJobSetupPaper( aJobSetup );
983 mbNewJobSetup = true;
984 maJobSetup = aJobSetup;
985 ImplUpdatePageData();
986 ImplUpdateFontList();
987 return true;
990 return false;
993 bool Printer::Setup(weld::Window* pWindow, PrinterSetupMode eMode)
995 if ( IsDisplayPrinter() )
996 return false;
998 if ( IsJobActive() || IsPrinting() )
999 return false;
1001 JobSetup aJobSetup = maJobSetup;
1002 ImplJobSetup& rData = aJobSetup.ImplGetData();
1003 rData.SetPrinterSetupMode( eMode );
1004 // TODO: orig page size
1006 if (!pWindow)
1008 vcl::Window* pDefWin = ImplGetDefaultWindow();
1009 pWindow = pDefWin ? pDefWin->GetFrameWeld() : nullptr;
1011 if( !pWindow )
1012 return false;
1014 ReleaseGraphics();
1015 ImplSVData* pSVData = ImplGetSVData();
1016 pSVData->maAppData.mnModalMode++;
1017 nImplSysDialog++;
1018 bool bSetup = mpInfoPrinter->Setup(pWindow, &rData);
1019 pSVData->maAppData.mnModalMode--;
1020 nImplSysDialog--;
1021 if ( bSetup )
1023 ImplUpdateJobSetupPaper( aJobSetup );
1024 mbNewJobSetup = true;
1025 maJobSetup = aJobSetup;
1026 ImplUpdatePageData();
1027 ImplUpdateFontList();
1028 return true;
1030 return false;
1033 bool Printer::SetPrinterProps( const Printer* pPrinter )
1035 if ( IsJobActive() || IsPrinting() )
1036 return false;
1038 ImplSVData* pSVData = ImplGetSVData();
1040 mbDefPrinter = pPrinter->mbDefPrinter;
1041 maPrintFile = pPrinter->maPrintFile;
1042 mbPrintFile = pPrinter->mbPrintFile;
1043 mnCopyCount = pPrinter->mnCopyCount;
1044 mbCollateCopy = pPrinter->mbCollateCopy;
1045 mnPageQueueSize = pPrinter->mnPageQueueSize;
1046 *mpPrinterOptions = *pPrinter->mpPrinterOptions;
1048 if ( pPrinter->IsDisplayPrinter() )
1050 // Destroy old printer
1051 if ( !IsDisplayPrinter() )
1053 ReleaseGraphics();
1054 pSVData->mpDefInst->DestroyInfoPrinter( mpInfoPrinter );
1055 mpFontInstance.clear();
1056 mpDeviceFontList.reset();
1057 mpDeviceFontSizeList.reset();
1058 // clean up font list
1059 mxFontCache.reset();
1060 mxFontCollection.reset();
1062 mbInitFont = true;
1063 mbNewFont = true;
1064 mpInfoPrinter = nullptr;
1067 // Construct new printer
1068 ImplInitDisplay();
1069 return true;
1072 // Destroy old printer?
1073 if ( GetName() != pPrinter->GetName() )
1075 ReleaseGraphics();
1076 if ( mpDisplayDev )
1078 mpDisplayDev.disposeAndClear();
1080 else
1082 pSVData->mpDefInst->DestroyInfoPrinter( mpInfoPrinter );
1084 mpFontInstance.clear();
1085 mpDeviceFontList.reset();
1086 mpDeviceFontSizeList.reset();
1087 mxFontCache.reset();
1088 mxFontCollection.reset();
1089 mbInitFont = true;
1090 mbNewFont = true;
1091 mpInfoPrinter = nullptr;
1094 // Construct new printer
1095 OUString aDriver = pPrinter->GetDriverName();
1096 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( pPrinter->GetName(), &aDriver );
1097 if ( pInfo )
1099 ImplInit( pInfo );
1100 SetJobSetup( pPrinter->GetJobSetup() );
1102 else
1103 ImplInitDisplay();
1105 else
1106 SetJobSetup( pPrinter->GetJobSetup() );
1108 return false;
1111 bool Printer::SetOrientation( Orientation eOrientation )
1113 if ( mbInPrintPage )
1114 return false;
1116 if ( maJobSetup.ImplGetConstData().GetOrientation() != eOrientation )
1118 JobSetup aJobSetup = maJobSetup;
1119 ImplJobSetup& rData = aJobSetup.ImplGetData();
1121 rData.SetOrientation(eOrientation);
1123 if ( IsDisplayPrinter() )
1125 mbNewJobSetup = true;
1126 maJobSetup = aJobSetup;
1127 return true;
1130 ReleaseGraphics();
1131 if ( mpInfoPrinter->SetData( JobSetFlags::ORIENTATION, &rData ) )
1133 ImplUpdateJobSetupPaper( aJobSetup );
1134 mbNewJobSetup = true;
1135 maJobSetup = aJobSetup;
1136 ImplUpdatePageData();
1137 ImplUpdateFontList();
1138 return true;
1140 else
1141 return false;
1144 return true;
1147 Orientation Printer::GetOrientation() const
1149 return maJobSetup.ImplGetConstData().GetOrientation();
1152 bool Printer::SetPaperBin( sal_uInt16 nPaperBin )
1154 if ( mbInPrintPage )
1155 return false;
1157 if ( maJobSetup.ImplGetConstData().GetPaperBin() != nPaperBin &&
1158 nPaperBin < GetPaperBinCount() )
1160 JobSetup aJobSetup = maJobSetup;
1161 ImplJobSetup& rData = aJobSetup.ImplGetData();
1162 rData.SetPaperBin(nPaperBin);
1164 if ( IsDisplayPrinter() )
1166 mbNewJobSetup = true;
1167 maJobSetup = aJobSetup;
1168 return true;
1171 ReleaseGraphics();
1172 if ( mpInfoPrinter->SetData( JobSetFlags::PAPERBIN, &rData ) )
1174 ImplUpdateJobSetupPaper( aJobSetup );
1175 mbNewJobSetup = true;
1176 maJobSetup = aJobSetup;
1177 ImplUpdatePageData();
1178 ImplUpdateFontList();
1179 return true;
1181 else
1182 return false;
1185 return true;
1188 sal_uInt16 Printer::GetPaperBin() const
1190 return maJobSetup.ImplGetConstData().GetPaperBin();
1193 bool Printer::GetPrinterSettingsPreferred() const
1195 return maJobSetup.ImplGetConstData().GetPapersizeFromSetup();
1198 // dear loplugins, DO NOT REMOVE this code
1199 // it will be used in follow-up commits
1200 void Printer::SetPrinterSettingsPreferred( bool bPaperSizeFromSetup)
1202 if ( maJobSetup.ImplGetConstData().GetPapersizeFromSetup() != bPaperSizeFromSetup )
1204 JobSetup aJobSetup = maJobSetup;
1205 ImplJobSetup& rData = aJobSetup.ImplGetData();
1206 rData.SetPapersizeFromSetup(bPaperSizeFromSetup);
1208 mbNewJobSetup = true;
1209 maJobSetup = aJobSetup;
1213 // Map user paper format to an available printer paper format
1214 void Printer::ImplFindPaperFormatForUserSize( JobSetup& aJobSetup, bool bMatchNearest )
1216 ImplJobSetup& rData = aJobSetup.ImplGetData();
1218 // The angle that a landscape page will be turned counterclockwise wrt to portrait.
1219 int nLandscapeAngle = mpInfoPrinter ? mpInfoPrinter->GetLandscapeAngle( &maJobSetup.ImplGetConstData() ) : 900;
1221 int nPaperCount = GetPaperInfoCount();
1222 bool bFound = false;
1224 PaperInfo aInfo(rData.GetPaperWidth(), rData.GetPaperHeight());
1226 // Compare all paper formats and get the appropriate one
1227 for ( int i = 0; i < nPaperCount; i++ )
1229 const PaperInfo& rPaperInfo = GetPaperInfo( i );
1231 if ( aInfo.sloppyEqual(rPaperInfo) )
1233 rData.SetPaperFormat(
1234 ImplGetPaperFormat( rPaperInfo.getWidth(),
1235 rPaperInfo.getHeight() ));
1236 rData.SetOrientation( Orientation::Portrait );
1237 bFound = true;
1238 break;
1242 // If the printer supports landscape orientation, check paper sizes again
1243 // with landscape orientation. This is necessary as a printer driver provides
1244 // all paper sizes with portrait orientation only!!
1245 if ( rData.GetPaperFormat() == PAPER_USER &&
1246 nLandscapeAngle != 0 &&
1247 HasSupport( PrinterSupport::SetOrientation ))
1249 const long nRotatedWidth = rData.GetPaperHeight();
1250 const long nRotatedHeight = rData.GetPaperWidth();
1251 PaperInfo aRotatedInfo(nRotatedWidth, nRotatedHeight);
1253 for ( int i = 0; i < nPaperCount; i++ )
1255 const PaperInfo& rPaperInfo = GetPaperInfo( i );
1257 if ( aRotatedInfo.sloppyEqual( rPaperInfo ) )
1259 rData.SetPaperFormat(
1260 ImplGetPaperFormat( rPaperInfo.getWidth(),
1261 rPaperInfo.getHeight() ));
1262 rData.SetOrientation( Orientation::Landscape );
1263 bFound = true;
1264 break;
1269 if( ! bFound && bMatchNearest )
1271 sal_Int64 nBestMatch = SAL_MAX_INT64;
1272 int nBestIndex = 0;
1273 Orientation eBestOrientation = Orientation::Portrait;
1274 for( int i = 0; i < nPaperCount; i++ )
1276 const PaperInfo& rPaperInfo = GetPaperInfo( i );
1278 // check portrait match
1279 sal_Int64 nDX = rData.GetPaperWidth() - rPaperInfo.getWidth();
1280 sal_Int64 nDY = rData.GetPaperHeight() - rPaperInfo.getHeight();
1281 sal_Int64 nMatch = nDX*nDX + nDY*nDY;
1282 if( nMatch < nBestMatch )
1284 nBestMatch = nMatch;
1285 nBestIndex = i;
1286 eBestOrientation = Orientation::Portrait;
1289 // check landscape match
1290 nDX = rData.GetPaperWidth() - rPaperInfo.getHeight();
1291 nDY = rData.GetPaperHeight() - rPaperInfo.getWidth();
1292 nMatch = nDX*nDX + nDY*nDY;
1293 if( nMatch < nBestMatch )
1295 nBestMatch = nMatch;
1296 nBestIndex = i;
1297 eBestOrientation = Orientation::Landscape;
1300 const PaperInfo& rBestInfo = GetPaperInfo( nBestIndex );
1301 rData.SetPaperFormat(
1302 ImplGetPaperFormat( rBestInfo.getWidth(),
1303 rBestInfo.getHeight() ));
1304 rData.SetOrientation(eBestOrientation);
1308 void Printer::SetPaper( Paper ePaper )
1310 if ( mbInPrintPage )
1311 return;
1313 if ( maJobSetup.ImplGetConstData().GetPaperFormat() != ePaper )
1315 JobSetup aJobSetup = maJobSetup;
1316 ImplJobSetup& rData = aJobSetup.ImplGetData();
1318 rData.SetPaperFormat( ePaper );
1319 if ( ePaper != PAPER_USER )
1321 PaperInfo aInfo(ePaper);
1322 rData.SetPaperWidth( aInfo.getWidth() );
1323 rData.SetPaperHeight( aInfo.getHeight() );
1326 if ( IsDisplayPrinter() )
1328 mbNewJobSetup = true;
1329 maJobSetup = aJobSetup;
1330 return;
1333 ReleaseGraphics();
1334 if ( ePaper == PAPER_USER )
1335 ImplFindPaperFormatForUserSize( aJobSetup, false );
1336 if ( mpInfoPrinter->SetData( JobSetFlags::PAPERSIZE | JobSetFlags::ORIENTATION, &rData ))
1338 ImplUpdateJobSetupPaper( aJobSetup );
1339 mbNewJobSetup = true;
1340 maJobSetup = aJobSetup;
1341 ImplUpdatePageData();
1342 ImplUpdateFontList();
1347 bool Printer::SetPaperSizeUser( const Size& rSize )
1349 return SetPaperSizeUser( rSize, false );
1352 bool Printer::SetPaperSizeUser( const Size& rSize, bool bMatchNearest )
1354 if ( mbInPrintPage )
1355 return false;
1357 const Size aPixSize = LogicToPixel( rSize );
1358 const Size aPageSize = PixelToLogic(aPixSize, MapMode(MapUnit::Map100thMM));
1359 bool bNeedToChange(maJobSetup.ImplGetConstData().GetPaperWidth() != aPageSize.Width() ||
1360 maJobSetup.ImplGetConstData().GetPaperHeight() != aPageSize.Height());
1362 if(!bNeedToChange)
1364 // #i122984# only need to change when Paper is different from PAPER_USER and
1365 // the mapped Paper which will created below in the call to ImplFindPaperFormatForUserSize
1366 // and will replace maJobSetup.ImplGetConstData()->GetPaperFormat(). This leads to
1367 // unnecessary JobSetups, e.g. when printing a multi-page fax, but also with
1368 // normal print
1369 const Paper aPaper = ImplGetPaperFormat(aPageSize.Width(), aPageSize.Height());
1371 bNeedToChange = maJobSetup.ImplGetConstData().GetPaperFormat() != PAPER_USER &&
1372 maJobSetup.ImplGetConstData().GetPaperFormat() != aPaper;
1375 if(bNeedToChange)
1377 JobSetup aJobSetup = maJobSetup;
1378 ImplJobSetup& rData = aJobSetup.ImplGetData();
1379 rData.SetPaperFormat( PAPER_USER );
1380 rData.SetPaperWidth( aPageSize.Width() );
1381 rData.SetPaperHeight( aPageSize.Height() );
1383 if ( IsDisplayPrinter() )
1385 mbNewJobSetup = true;
1386 maJobSetup = aJobSetup;
1387 return true;
1390 ReleaseGraphics();
1391 ImplFindPaperFormatForUserSize( aJobSetup, bMatchNearest );
1393 // Changing the paper size can also change the orientation!
1394 if ( mpInfoPrinter->SetData( JobSetFlags::PAPERSIZE | JobSetFlags::ORIENTATION, &rData ))
1396 ImplUpdateJobSetupPaper( aJobSetup );
1397 mbNewJobSetup = true;
1398 maJobSetup = aJobSetup;
1399 ImplUpdatePageData();
1400 ImplUpdateFontList();
1401 return true;
1403 else
1404 return false;
1407 return true;
1410 int Printer::GetPaperInfoCount() const
1412 if( ! mpInfoPrinter )
1413 return 0;
1414 if( ! mpInfoPrinter->m_bPapersInit )
1415 mpInfoPrinter->InitPaperFormats( &maJobSetup.ImplGetConstData() );
1416 return mpInfoPrinter->m_aPaperFormats.size();
1419 OUString Printer::GetPaperName( Paper ePaper )
1421 ImplSVData* pSVData = ImplGetSVData();
1422 if( pSVData->maPaperNames.empty() )
1424 static const int PaperIndex[] =
1426 PAPER_A0, PAPER_A1, PAPER_A2, PAPER_A3, PAPER_A4, PAPER_A5, PAPER_B4_ISO, PAPER_B5_ISO,
1427 PAPER_LETTER, PAPER_LEGAL, PAPER_TABLOID, PAPER_USER, PAPER_B6_ISO, PAPER_ENV_C4, PAPER_ENV_C5,
1428 PAPER_ENV_C6, PAPER_ENV_C65, PAPER_ENV_DL, PAPER_SLIDE_DIA, PAPER_SCREEN_4_3, PAPER_C, PAPER_D,
1429 PAPER_E, PAPER_EXECUTIVE, PAPER_FANFOLD_LEGAL_DE, PAPER_ENV_MONARCH, PAPER_ENV_PERSONAL, PAPER_ENV_9,
1430 PAPER_ENV_10, PAPER_ENV_11, PAPER_ENV_12, PAPER_KAI16, PAPER_KAI32, PAPER_KAI32BIG, PAPER_B4_JIS,
1431 PAPER_B5_JIS, PAPER_B6_JIS, PAPER_LEDGER, PAPER_STATEMENT, PAPER_QUARTO, PAPER_10x14, PAPER_ENV_14,
1432 PAPER_ENV_C3, PAPER_ENV_ITALY, PAPER_FANFOLD_US, PAPER_FANFOLD_DE, PAPER_POSTCARD_JP, PAPER_9x11,
1433 PAPER_10x11, PAPER_15x11, PAPER_ENV_INVITE, PAPER_A_PLUS, PAPER_B_PLUS, PAPER_LETTER_PLUS, PAPER_A4_PLUS,
1434 PAPER_DOUBLEPOSTCARD_JP, PAPER_A6, PAPER_12x11, PAPER_A7, PAPER_A8, PAPER_A9, PAPER_A10, PAPER_B0_ISO,
1435 PAPER_B1_ISO, PAPER_B2_ISO, PAPER_B3_ISO, PAPER_B7_ISO, PAPER_B8_ISO, PAPER_B9_ISO, PAPER_B10_ISO,
1436 PAPER_ENV_C2, PAPER_ENV_C7, PAPER_ENV_C8, PAPER_ARCHA, PAPER_ARCHB, PAPER_ARCHC, PAPER_ARCHD,
1437 PAPER_ARCHE, PAPER_SCREEN_16_9, PAPER_SCREEN_16_10, PAPER_16K_195x270, PAPER_16K_197x273
1439 assert(SAL_N_ELEMENTS(PaperIndex) == SAL_N_ELEMENTS(RID_STR_PAPERNAMES) && "localized paper name count wrong");
1440 for (size_t i = 0; i < SAL_N_ELEMENTS(PaperIndex); ++i)
1441 pSVData->maPaperNames[PaperIndex[i]] = VclResId(RID_STR_PAPERNAMES[i]);
1444 std::unordered_map<int,OUString>::const_iterator it = pSVData->maPaperNames.find( static_cast<int>(ePaper) );
1445 return (it != pSVData->maPaperNames.end()) ? it->second : OUString();
1448 const PaperInfo& Printer::GetPaperInfo( int nPaper ) const
1450 if( ! mpInfoPrinter )
1451 return ImplGetEmptyPaper();
1452 if( ! mpInfoPrinter->m_bPapersInit )
1453 mpInfoPrinter->InitPaperFormats( &maJobSetup.ImplGetConstData() );
1454 if( mpInfoPrinter->m_aPaperFormats.empty() || nPaper < 0 || nPaper >= int(mpInfoPrinter->m_aPaperFormats.size()) )
1455 return ImplGetEmptyPaper();
1456 return mpInfoPrinter->m_aPaperFormats[nPaper];
1459 Size Printer::GetPaperSize( int nPaper )
1461 PaperInfo aInfo = GetPaperInfo( nPaper );
1462 return PixelToLogic( Size( aInfo.getWidth(), aInfo.getHeight() ) );
1465 void Printer::SetDuplexMode( DuplexMode eDuplex )
1467 if ( mbInPrintPage )
1468 return;
1470 if ( maJobSetup.ImplGetConstData().GetDuplexMode() != eDuplex )
1472 JobSetup aJobSetup = maJobSetup;
1473 ImplJobSetup& rData = aJobSetup.ImplGetData();
1475 rData.SetDuplexMode( eDuplex );
1477 if ( IsDisplayPrinter() )
1479 mbNewJobSetup = true;
1480 maJobSetup = aJobSetup;
1481 return;
1484 ReleaseGraphics();
1485 if ( mpInfoPrinter->SetData( JobSetFlags::DUPLEXMODE, &rData ) )
1487 ImplUpdateJobSetupPaper( aJobSetup );
1488 mbNewJobSetup = true;
1489 maJobSetup = aJobSetup;
1490 ImplUpdatePageData();
1491 ImplUpdateFontList();
1496 DuplexMode Printer::GetDuplexMode() const
1498 return maJobSetup.ImplGetConstData().GetDuplexMode();
1501 Paper Printer::GetPaper() const
1503 return maJobSetup.ImplGetConstData().GetPaperFormat();
1506 sal_uInt16 Printer::GetPaperBinCount() const
1508 if ( IsDisplayPrinter() )
1509 return 0;
1511 return mpInfoPrinter->GetPaperBinCount( &maJobSetup.ImplGetConstData() );
1514 OUString Printer::GetPaperBinName( sal_uInt16 nPaperBin ) const
1516 if ( IsDisplayPrinter() )
1517 return OUString();
1519 if ( nPaperBin < GetPaperBinCount() )
1520 return mpInfoPrinter->GetPaperBinName( &maJobSetup.ImplGetConstData(), nPaperBin );
1521 else
1522 return OUString();
1525 void Printer::SetCopyCount( sal_uInt16 nCopy, bool bCollate )
1527 mnCopyCount = nCopy;
1528 mbCollateCopy = bCollate;
1531 ErrCode Printer::ImplSalPrinterErrorCodeToVCL( SalPrinterError nError )
1533 ErrCode nVCLError;
1534 switch ( nError )
1536 case SalPrinterError::NONE:
1537 nVCLError = ERRCODE_NONE;
1538 break;
1539 case SalPrinterError::Abort:
1540 nVCLError = PRINTER_ABORT;
1541 break;
1542 default:
1543 nVCLError = PRINTER_GENERALERROR;
1544 break;
1547 return nVCLError;
1550 void Printer::EndJob()
1552 if ( !IsJobActive() )
1553 return;
1555 SAL_WARN_IF( mbInPrintPage, "vcl.gdi", "Printer::EndJob() - StartPage() without EndPage() called" );
1557 mbJobActive = false;
1559 if ( mpPrinter )
1561 ReleaseGraphics();
1563 mbPrinting = false;
1565 mbDevOutput = false;
1566 mpPrinter->EndJob();
1567 mpPrinter.reset();
1571 void Printer::ImplStartPage()
1573 if ( !IsJobActive() )
1574 return;
1576 if ( mpPrinter )
1578 SalGraphics* pGraphics = mpPrinter->StartPage( &maJobSetup.ImplGetData(),
1579 mbNewJobSetup );
1580 if ( pGraphics )
1582 ReleaseGraphics();
1583 mpJobGraphics = pGraphics;
1585 mbDevOutput = true;
1587 // PrintJob not aborted ???
1588 if ( IsJobActive() )
1589 mbInPrintPage = true;
1593 void Printer::ImplEndPage()
1595 if ( !IsJobActive() )
1596 return;
1598 mbInPrintPage = false;
1600 if ( mpPrinter )
1602 mpPrinter->EndPage();
1603 ReleaseGraphics();
1604 mbDevOutput = false;
1606 mpJobGraphics = nullptr;
1607 mbNewJobSetup = false;
1611 void Printer::updatePrinters()
1613 ImplSVData* pSVData = ImplGetSVData();
1614 ImplPrnQueueList* pPrnList = pSVData->maGDIData.mpPrinterQueueList.get();
1616 if ( pPrnList )
1618 std::unique_ptr<ImplPrnQueueList> pNewList(new ImplPrnQueueList);
1619 pSVData->mpDefInst->GetPrinterQueueInfo( pNewList.get() );
1621 bool bChanged = pPrnList->m_aQueueInfos.size() != pNewList->m_aQueueInfos.size();
1622 for( decltype(pPrnList->m_aQueueInfos)::size_type i = 0; ! bChanged && i < pPrnList->m_aQueueInfos.size(); i++ )
1624 ImplPrnQueueData& rInfo = pPrnList->m_aQueueInfos[i];
1625 ImplPrnQueueData& rNewInfo = pNewList->m_aQueueInfos[i];
1626 if( ! rInfo.mpSalQueueInfo || ! rNewInfo.mpSalQueueInfo || // sanity check
1627 rInfo.mpSalQueueInfo->maPrinterName != rNewInfo.mpSalQueueInfo->maPrinterName )
1629 bChanged = true;
1632 if( bChanged )
1634 ImplDeletePrnQueueList();
1635 pSVData->maGDIData.mpPrinterQueueList = std::move(pNewList);
1637 Application* pApp = GetpApp();
1638 if( pApp )
1640 DataChangedEvent aDCEvt( DataChangedEventType::PRINTER );
1641 Application::ImplCallEventListenersApplicationDataChanged(&aDCEvt);
1642 Application::NotifyAllWindows( aDCEvt );
1648 bool Printer::UsePolyPolygonForComplexGradient()
1650 return true;
1653 void Printer::ClipAndDrawGradientMetafile ( const Gradient &rGradient, const tools::PolyPolygon &rPolyPoly )
1655 const tools::Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
1657 Push( PushFlags::CLIPREGION );
1658 IntersectClipRegion(vcl::Region(rPolyPoly));
1659 DrawGradient( aBoundRect, rGradient );
1660 Pop();
1663 void Printer::SetFontOrientation( LogicalFontInstance* const pFontEntry ) const
1665 pFontEntry->mnOrientation = pFontEntry->mxFontMetric->GetOrientation();
1668 vcl::Region Printer::ClipToDeviceBounds(vcl::Region aRegion) const
1670 return aRegion;
1673 Bitmap Printer::GetBitmap( const Point& rSrcPt, const Size& rSize ) const
1675 SAL_WARN("vcl.gdi", "GetBitmap(): This should never be called on by a Printer instance");
1677 return OutputDevice::GetBitmap( rSrcPt, rSize );
1680 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */