Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / vcl / source / gdi / print.cxx
blob7941632b89fc6ba082ac6505f9b08e5cd64d500d
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>
22 #include <tools/resary.hxx>
23 #include <tools/helpers.hxx>
25 #include <vcl/virdev.hxx>
26 #include <vcl/print.hxx>
28 #include <comphelper/processfactory.hxx>
30 #include "salinst.hxx"
31 #include "salvd.hxx"
32 #include "salgdi.hxx"
33 #include "salptype.hxx"
34 #include "salprn.hxx"
35 #include "svdata.hxx"
36 #include "svids.hrc"
37 #include "jobset.h"
38 #include "outdev.h"
39 #include "PhysicalFontCollection.hxx"
40 #include "print.h"
42 #include "com/sun/star/beans/XPropertySet.hpp"
43 #include "com/sun/star/configuration/theDefaultProvider.hpp"
44 #include "com/sun/star/container/XNameAccess.hpp"
45 #include "com/sun/star/lang/XMultiServiceFactory.hpp"
46 #include "com/sun/star/uno/Sequence.h"
48 int nImplSysDialog = 0;
50 namespace
52 Paper ImplGetPaperFormat( long nWidth100thMM, long nHeight100thMM )
54 PaperInfo aInfo(nWidth100thMM, nHeight100thMM);
55 aInfo.doSloppyFit();
56 return aInfo.getPaper();
59 const PaperInfo& ImplGetEmptyPaper()
61 static PaperInfo aInfo(PAPER_USER);
62 return aInfo;
66 void ImplUpdateJobSetupPaper( JobSetup& rJobSetup )
68 const ImplJobSetup& rConstData = rJobSetup.ImplGetConstData();
70 if ( !rConstData.GetPaperWidth() || !rConstData.GetPaperHeight() )
72 if ( rConstData.GetPaperFormat() != PAPER_USER )
74 PaperInfo aInfo(rConstData.GetPaperFormat());
76 ImplJobSetup& rData = rJobSetup.ImplGetData();
77 rData.SetPaperWidth( aInfo.getWidth() );
78 rData.SetPaperHeight( aInfo.getHeight() );
81 else if ( rConstData.GetPaperFormat() == PAPER_USER )
83 Paper ePaper = ImplGetPaperFormat( rConstData.GetPaperWidth(), rConstData.GetPaperHeight() );
84 if ( ePaper != PAPER_USER )
85 rJobSetup.ImplGetData().SetPaperFormat(ePaper);
89 // PrinterOptions
90 PrinterOptions::PrinterOptions() :
91 mbReduceTransparency( false ),
92 meReducedTransparencyMode( PrinterTransparencyMode::Auto ),
93 mbReduceGradients( false ),
94 meReducedGradientsMode( PrinterGradientMode::Stripes ),
95 mnReducedGradientStepCount( 64 ),
96 mbReduceBitmaps( false ),
97 meReducedBitmapMode( PrinterBitmapMode::Normal ),
98 mnReducedBitmapResolution( 200 ),
99 mbReducedBitmapsIncludeTransparency( true ),
100 mbConvertToGreyscales( false ),
101 mbPDFAsStandardPrintJobFormat( false )
105 PrinterOptions::~PrinterOptions()
109 bool PrinterOptions::ReadFromConfig( bool i_bFile )
111 bool bSuccess = false;
112 // save old state in case something goes wrong
113 PrinterOptions aOldValues( *this );
115 // get the configuration service
116 css::uno::Reference< css::lang::XMultiServiceFactory > xConfigProvider;
117 css::uno::Reference< css::container::XNameAccess > xConfigAccess;
120 // get service provider
121 css::uno::Reference< css::uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
122 // create configuration hierarchical access name
125 xConfigProvider = css::configuration::theDefaultProvider::get( xContext );
127 css::uno::Sequence< css::uno::Any > aArgs(1);
128 css::beans::PropertyValue aVal;
129 aVal.Name = "nodepath";
130 if( i_bFile )
131 aVal.Value <<= OUString( "/org.openoffice.Office.Common/Print/Option/File" );
132 else
133 aVal.Value <<= OUString( "/org.openoffice.Office.Common/Print/Option/Printer" );
134 aArgs.getArray()[0] <<= aVal;
135 xConfigAccess.set(
136 xConfigProvider->createInstanceWithArguments(
137 "com.sun.star.configuration.ConfigurationAccess", aArgs ),
138 css::uno::UNO_QUERY );
139 if( xConfigAccess.is() )
141 css::uno::Reference< css::beans::XPropertySet > xSet( xConfigAccess, css::uno::UNO_QUERY );
142 if( xSet.is() )
144 sal_Int32 nValue = 0;
145 bool bValue = false;
146 if( xSet->getPropertyValue("ReduceTransparency") >>= bValue )
147 SetReduceTransparency( bValue );
148 if( xSet->getPropertyValue("ReducedTransparencyMode") >>= nValue )
149 SetReducedTransparencyMode( (PrinterTransparencyMode)nValue );
150 if( xSet->getPropertyValue("ReduceGradients") >>= bValue )
151 SetReduceGradients( bValue );
152 if( xSet->getPropertyValue("ReducedGradientMode") >>= nValue )
153 SetReducedGradientMode( (PrinterGradientMode)nValue );
154 if( xSet->getPropertyValue("ReducedGradientStepCount") >>= nValue )
155 SetReducedGradientStepCount( (sal_uInt16)nValue );
156 if( xSet->getPropertyValue("ReduceBitmaps") >>= bValue )
157 SetReduceBitmaps( bValue );
158 if( xSet->getPropertyValue("ReducedBitmapMode") >>= nValue )
159 SetReducedBitmapMode( (PrinterBitmapMode)nValue );
160 if( xSet->getPropertyValue("ReducedBitmapResolution") >>= nValue )
161 SetReducedBitmapResolution( (sal_uInt16)nValue );
162 if( xSet->getPropertyValue("ReducedBitmapIncludesTransparency") >>= bValue )
163 SetReducedBitmapIncludesTransparency( bValue );
164 if( xSet->getPropertyValue("ConvertToGreyscales") >>= bValue )
165 SetConvertToGreyscales( bValue );
166 if( xSet->getPropertyValue("PDFAsStandardPrintJobFormat") >>= bValue )
167 SetPDFAsStandardPrintJobFormat( bValue );
169 bSuccess = true;
173 catch( const css::uno::Exception& )
177 catch( const css::lang::WrappedTargetException& )
181 if( ! bSuccess )
182 *this = aOldValues;
183 return bSuccess;
186 bool Printer::DrawTransformBitmapExDirect(
187 const basegfx::B2DHomMatrix& /*aFullTransform*/,
188 const BitmapEx& /*rBitmapEx*/)
190 // printers can't draw bitmaps directly
191 return false;
194 bool Printer::TransformAndReduceBitmapExToTargetRange(
195 const basegfx::B2DHomMatrix& /*aFullTransform*/,
196 basegfx::B2DRange& /*aVisibleRange*/,
197 double& /*fMaximumArea*/)
199 // deliberately do nothing - you can't reduce the
200 // target range for a printer at all
201 return true;
204 void Printer::DrawDeviceBitmap( const Point& rDestPt, const Size& rDestSize,
205 const Point& rSrcPtPixel, const Size& rSrcSizePixel,
206 BitmapEx& rBmpEx )
208 if( rBmpEx.IsAlpha() )
210 // #107169# For true alpha bitmaps, no longer masking the
211 // bitmap, but perform a full alpha blend against a white
212 // background here.
213 Bitmap aBmp( rBmpEx.GetBitmap() );
214 aBmp.Blend( rBmpEx.GetAlpha(), Color( COL_WHITE) );
215 DrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, aBmp );
217 else
219 Bitmap aBmp( rBmpEx.GetBitmap() ), aMask( rBmpEx.GetMask() );
220 aBmp.Replace( aMask, Color( COL_WHITE ) );
221 ImplPrintTransparent( aBmp, aMask, rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel );
225 void Printer::EmulateDrawTransparent ( const tools::PolyPolygon& rPolyPoly,
226 sal_uInt16 nTransparencePercent )
228 // #110958# Disable alpha VDev, we perform the necessary
229 VirtualDevice* pOldAlphaVDev = mpAlphaVDev;
231 // operation explicitly further below.
232 if( mpAlphaVDev )
233 mpAlphaVDev = nullptr;
235 GDIMetaFile* pOldMetaFile = mpMetaFile;
236 mpMetaFile = nullptr;
238 mpMetaFile = pOldMetaFile;
240 // #110958# Restore disabled alpha VDev
241 mpAlphaVDev = pOldAlphaVDev;
243 tools::Rectangle aPolyRect( LogicToPixel( rPolyPoly ).GetBoundRect() );
244 const Size aDPISize( LogicToPixel( Size( 1, 1 ), MapUnit::MapInch ) );
245 const long nBaseExtent = std::max( FRound( aDPISize.Width() / 300. ), 1L );
246 long nMove;
247 const sal_uInt16 nTrans = ( nTransparencePercent < 13 ) ? 0 :
248 ( nTransparencePercent < 38 ) ? 25 :
249 ( nTransparencePercent < 63 ) ? 50 :
250 ( nTransparencePercent < 88 ) ? 75 : 100;
252 switch( nTrans )
254 case 25: nMove = nBaseExtent * 3; break;
255 case 50: nMove = nBaseExtent * 4; break;
256 case 75: nMove = nBaseExtent * 6; break;
258 // #i112959# very transparent (88 < nTransparencePercent <= 99)
259 case 100: nMove = nBaseExtent * 8; break;
261 // #i112959# not transparent (nTransparencePercent < 13)
262 default: nMove = 0; break;
265 Push( PushFlags::CLIPREGION | PushFlags::LINECOLOR );
266 IntersectClipRegion(vcl::Region(rPolyPoly));
267 SetLineColor( GetFillColor() );
268 const bool bOldMap = mbMap;
269 EnableMapMode( false );
271 if(nMove)
273 tools::Rectangle aRect( aPolyRect.TopLeft(), Size( aPolyRect.GetWidth(), nBaseExtent ) );
274 while( aRect.Top() <= aPolyRect.Bottom() )
276 DrawRect( aRect );
277 aRect.Move( 0, nMove );
280 aRect = tools::Rectangle( aPolyRect.TopLeft(), Size( nBaseExtent, aPolyRect.GetHeight() ) );
281 while( aRect.Left() <= aPolyRect.Right() )
283 DrawRect( aRect );
284 aRect.Move( nMove, 0 );
287 else
289 // #i112959# if not transparent, draw full rectangle in clip region
290 DrawRect( aPolyRect );
293 EnableMapMode( bOldMap );
294 Pop();
296 mpMetaFile = pOldMetaFile;
298 // #110958# Restore disabled alpha VDev
299 mpAlphaVDev = pOldAlphaVDev;
302 void Printer::DrawOutDev( const Point& /*rDestPt*/, const Size& /*rDestSize*/,
303 const Point& /*rSrcPt*/, const Size& /*rSrcSize*/ )
305 SAL_WARN( "vcl.gdi", "Don't use OutputDevice::DrawOutDev(...) with printer devices!" );
308 void Printer::DrawOutDev( const Point& /*rDestPt*/, const Size& /*rDestSize*/,
309 const Point& /*rSrcPt*/, const Size& /*rSrcSize*/,
310 const OutputDevice& /*rOutDev*/ )
312 SAL_WARN( "vcl.gdi", "Don't use OutputDevice::DrawOutDev(...) with printer devices!" );
315 void Printer::CopyArea( const Point& /*rDestPt*/,
316 const Point& /*rSrcPt*/, const Size& /*rSrcSize*/,
317 bool /*bWindowInvalidate*/ )
319 SAL_WARN( "vcl.gdi", "Don't use OutputDevice::CopyArea(...) with printer devices!" );
322 void Printer::SetPrinterOptions( const PrinterOptions& i_rOptions )
324 *mpPrinterOptions = i_rOptions;
327 bool Printer::HasMirroredGraphics() const
329 // due to a "hotfix" for AOO bug i55719, this needs to return false
330 return false;
333 // QueueInfo
334 QueueInfo::QueueInfo()
336 mnStatus = PrintQueueFlags::NONE;
337 mnJobs = 0;
340 QueueInfo::QueueInfo( const QueueInfo& rInfo ) :
341 maPrinterName( rInfo.maPrinterName ),
342 maDriver( rInfo.maDriver ),
343 maLocation( rInfo.maLocation ),
344 maComment( rInfo.maComment ),
345 mnStatus( rInfo.mnStatus ),
346 mnJobs( rInfo.mnJobs )
350 QueueInfo::~QueueInfo()
354 SalPrinterQueueInfo::SalPrinterQueueInfo()
356 mnStatus = PrintQueueFlags::NONE;
357 mnJobs = QUEUE_JOBS_DONTKNOW;
358 mpSysData = nullptr;
361 SalPrinterQueueInfo::~SalPrinterQueueInfo()
365 ImplPrnQueueList::~ImplPrnQueueList()
367 ImplSVData* pSVData = ImplGetSVData();
368 for(ImplPrnQueueData & rQueueInfo : m_aQueueInfos)
370 delete rQueueInfo.mpQueueInfo;
371 pSVData->mpDefInst->DeletePrinterQueueInfo( rQueueInfo.mpSalQueueInfo );
375 void ImplPrnQueueList::Add( SalPrinterQueueInfo* pData )
377 std::unordered_map< OUString, sal_Int32, OUStringHash >::iterator it =
378 m_aNameToIndex.find( pData->maPrinterName );
379 if( it == m_aNameToIndex.end() )
381 m_aNameToIndex[ pData->maPrinterName ] = m_aQueueInfos.size();
382 m_aQueueInfos.push_back( ImplPrnQueueData() );
383 m_aQueueInfos.back().mpQueueInfo = nullptr;
384 m_aQueueInfos.back().mpSalQueueInfo = pData;
385 m_aPrinterList.push_back( pData->maPrinterName );
387 else // this should not happen, but ...
389 ImplPrnQueueData& rData = m_aQueueInfos[ it->second ];
390 delete rData.mpQueueInfo;
391 rData.mpQueueInfo = nullptr;
392 ImplGetSVData()->mpDefInst->DeletePrinterQueueInfo( rData.mpSalQueueInfo );
393 rData.mpSalQueueInfo = pData;
397 ImplPrnQueueData* ImplPrnQueueList::Get( const OUString& rPrinter )
399 ImplPrnQueueData* pData = nullptr;
400 std::unordered_map<OUString,sal_Int32,OUStringHash>::iterator it =
401 m_aNameToIndex.find( rPrinter );
402 if( it != m_aNameToIndex.end() )
403 pData = &m_aQueueInfos[it->second];
404 return pData;
407 static void ImplInitPrnQueueList()
409 ImplSVData* pSVData = ImplGetSVData();
411 pSVData->maGDIData.mpPrinterQueueList = new ImplPrnQueueList;
413 static const char* pEnv = getenv( "SAL_DISABLE_PRINTERLIST" );
414 if( !pEnv || !*pEnv )
415 pSVData->mpDefInst->GetPrinterQueueInfo( pSVData->maGDIData.mpPrinterQueueList );
418 void ImplDeletePrnQueueList()
420 ImplSVData* pSVData = ImplGetSVData();
421 ImplPrnQueueList* pPrnList = pSVData->maGDIData.mpPrinterQueueList;
423 if ( pPrnList )
425 delete pPrnList;
426 pSVData->maGDIData.mpPrinterQueueList = nullptr;
430 const std::vector<OUString>& Printer::GetPrinterQueues()
432 ImplSVData* pSVData = ImplGetSVData();
433 if ( !pSVData->maGDIData.mpPrinterQueueList )
434 ImplInitPrnQueueList();
435 return pSVData->maGDIData.mpPrinterQueueList->m_aPrinterList;
438 const QueueInfo* Printer::GetQueueInfo( const OUString& rPrinterName, bool bStatusUpdate )
440 ImplSVData* pSVData = ImplGetSVData();
442 if ( !pSVData->maGDIData.mpPrinterQueueList )
443 ImplInitPrnQueueList();
445 if ( !pSVData->maGDIData.mpPrinterQueueList )
446 return nullptr;
448 ImplPrnQueueData* pInfo = pSVData->maGDIData.mpPrinterQueueList->Get( rPrinterName );
449 if( pInfo )
451 if( !pInfo->mpQueueInfo || bStatusUpdate )
452 pSVData->mpDefInst->GetPrinterQueueState( pInfo->mpSalQueueInfo );
454 if ( !pInfo->mpQueueInfo )
455 pInfo->mpQueueInfo = new QueueInfo;
457 pInfo->mpQueueInfo->maPrinterName = pInfo->mpSalQueueInfo->maPrinterName;
458 pInfo->mpQueueInfo->maDriver = pInfo->mpSalQueueInfo->maDriver;
459 pInfo->mpQueueInfo->maLocation = pInfo->mpSalQueueInfo->maLocation;
460 pInfo->mpQueueInfo->maComment = pInfo->mpSalQueueInfo->maComment;
461 pInfo->mpQueueInfo->mnStatus = pInfo->mpSalQueueInfo->mnStatus;
462 pInfo->mpQueueInfo->mnJobs = pInfo->mpSalQueueInfo->mnJobs;
463 return pInfo->mpQueueInfo;
465 return nullptr;
468 OUString Printer::GetDefaultPrinterName()
470 static const char* pEnv = getenv( "SAL_DISABLE_DEFAULTPRINTER" );
471 if( !pEnv || !*pEnv )
473 ImplSVData* pSVData = ImplGetSVData();
475 return pSVData->mpDefInst->GetDefaultPrinter();
477 return OUString();
480 void Printer::ImplInitData()
482 mbDevOutput = false;
483 meOutDevType = OUTDEV_PRINTER;
484 mbDefPrinter = false;
485 mnError = 0;
486 mnCurPage = 0;
487 mnCurPrintPage = 0;
488 mnPageQueueSize = 0;
489 mnCopyCount = 1;
490 mbCollateCopy = false;
491 mbPrinting = false;
492 mbJobActive = false;
493 mbPrintFile = false;
494 mbInPrintPage = false;
495 mbNewJobSetup = false;
496 mpInfoPrinter = nullptr;
497 mpPrinter = nullptr;
498 mpDisplayDev = nullptr;
499 mpPrinterOptions = new PrinterOptions;
501 // Add printer to the list
502 ImplSVData* pSVData = ImplGetSVData();
503 mpNext = pSVData->maGDIData.mpFirstPrinter;
504 mpPrev = nullptr;
505 if ( mpNext )
506 mpNext->mpPrev = this;
507 else
508 pSVData->maGDIData.mpLastPrinter = this;
509 pSVData->maGDIData.mpFirstPrinter = this;
512 bool Printer::AcquireGraphics() const
514 DBG_TESTSOLARMUTEX();
516 if ( mpGraphics )
517 return true;
519 mbInitLineColor = true;
520 mbInitFillColor = true;
521 mbInitFont = true;
522 mbInitTextColor = true;
523 mbInitClipRegion = true;
525 ImplSVData* pSVData = ImplGetSVData();
527 if ( mpJobGraphics )
528 mpGraphics = mpJobGraphics;
529 else if ( mpDisplayDev )
531 const VirtualDevice* pVirDev = mpDisplayDev;
532 mpGraphics = pVirDev->mpVirDev->AcquireGraphics();
533 // if needed retry after releasing least recently used virtual device graphics
534 while ( !mpGraphics )
536 if ( !pSVData->maGDIData.mpLastVirGraphics )
537 break;
538 pSVData->maGDIData.mpLastVirGraphics->ReleaseGraphics();
539 mpGraphics = pVirDev->mpVirDev->AcquireGraphics();
541 // update global LRU list of virtual device graphics
542 if ( mpGraphics )
544 mpNextGraphics = pSVData->maGDIData.mpFirstVirGraphics;
545 pSVData->maGDIData.mpFirstVirGraphics = const_cast<Printer*>(this);
546 if ( mpNextGraphics )
547 mpNextGraphics->mpPrevGraphics = const_cast<Printer*>(this);
548 if ( !pSVData->maGDIData.mpLastVirGraphics )
549 pSVData->maGDIData.mpLastVirGraphics = const_cast<Printer*>(this);
552 else
554 mpGraphics = mpInfoPrinter->AcquireGraphics();
555 // if needed retry after releasing least recently used printer graphics
556 while ( !mpGraphics )
558 if ( !pSVData->maGDIData.mpLastPrnGraphics )
559 break;
560 pSVData->maGDIData.mpLastPrnGraphics->ReleaseGraphics();
561 mpGraphics = mpInfoPrinter->AcquireGraphics();
563 // update global LRU list of printer graphics
564 if ( mpGraphics )
566 mpNextGraphics = pSVData->maGDIData.mpFirstPrnGraphics;
567 pSVData->maGDIData.mpFirstPrnGraphics = const_cast<Printer*>(this);
568 if ( mpNextGraphics )
569 mpNextGraphics->mpPrevGraphics = const_cast<Printer*>(this);
570 if ( !pSVData->maGDIData.mpLastPrnGraphics )
571 pSVData->maGDIData.mpLastPrnGraphics = const_cast<Printer*>(this);
575 if ( mpGraphics )
577 mpGraphics->SetXORMode( (RasterOp::Invert == meRasterOp) || (RasterOp::Xor == meRasterOp) );
578 mpGraphics->setAntiAliasB2DDraw(bool(mnAntialiasing & AntialiasingFlags::EnableB2dDraw));
581 return mpGraphics != nullptr;
584 void Printer::ImplReleaseFonts()
586 #ifdef UNX
587 // HACK to fix an urgent P1 printing issue fast
588 // WinSalPrinter does not respect GetGraphics/ReleaseGraphics conventions
589 // so Printer::mpGraphics often points to a dead WinSalGraphics
590 // TODO: fix WinSalPrinter's GetGraphics/ReleaseGraphics handling
591 mpGraphics->ReleaseFonts();
592 #endif
593 mbNewFont = true;
594 mbInitFont = true;
596 if ( mpFontInstance )
598 mpFontCache->Release( mpFontInstance );
599 mpFontInstance = nullptr;
602 if ( mpDeviceFontList )
604 delete mpDeviceFontList;
605 mpDeviceFontList = nullptr;
608 if ( mpDeviceFontSizeList )
610 delete mpDeviceFontSizeList;
611 mpDeviceFontSizeList = nullptr;
615 void Printer::ReleaseGraphics( bool bRelease )
617 DBG_TESTSOLARMUTEX();
619 if ( !mpGraphics )
620 return;
622 // release the fonts of the physically released graphics device
623 if( bRelease )
624 ImplReleaseFonts();
626 ImplSVData* pSVData = ImplGetSVData();
628 Printer* pPrinter = this;
630 if ( !pPrinter->mpJobGraphics )
632 if ( pPrinter->mpDisplayDev )
634 VirtualDevice* pVirDev = pPrinter->mpDisplayDev;
635 if ( bRelease )
636 pVirDev->mpVirDev->ReleaseGraphics( mpGraphics );
637 // remove from global LRU list of virtual device graphics
638 if ( mpPrevGraphics )
639 mpPrevGraphics->mpNextGraphics = mpNextGraphics;
640 else
641 pSVData->maGDIData.mpFirstVirGraphics = mpNextGraphics;
642 if ( mpNextGraphics )
643 mpNextGraphics->mpPrevGraphics = mpPrevGraphics;
644 else
645 pSVData->maGDIData.mpLastVirGraphics = mpPrevGraphics;
647 else
649 if ( bRelease )
650 pPrinter->mpInfoPrinter->ReleaseGraphics( mpGraphics );
651 // remove from global LRU list of printer graphics
652 if ( mpPrevGraphics )
653 mpPrevGraphics->mpNextGraphics = mpNextGraphics;
654 else
655 pSVData->maGDIData.mpFirstPrnGraphics = mpNextGraphics;
656 if ( mpNextGraphics )
657 mpNextGraphics->mpPrevGraphics = mpPrevGraphics;
658 else
659 pSVData->maGDIData.mpLastPrnGraphics = mpPrevGraphics;
663 mpGraphics = nullptr;
664 mpPrevGraphics = nullptr;
665 mpNextGraphics = nullptr;
668 void Printer::ImplInit( SalPrinterQueueInfo* pInfo )
670 ImplSVData* pSVData = ImplGetSVData();
671 // #i74084# update info for this specific SalPrinterQueueInfo
672 pSVData->mpDefInst->GetPrinterQueueState( pInfo );
674 // Test whether the driver actually matches the JobSetup
675 ImplJobSetup& rData = maJobSetup.ImplGetData();
676 if ( rData.GetDriverData() )
678 if ( rData.GetPrinterName() != pInfo->maPrinterName ||
679 rData.GetDriver() != pInfo->maDriver )
681 rtl_freeMemory( const_cast<sal_uInt8*>(rData.GetDriverData()) );
682 rData.SetDriverData(nullptr);
683 rData.SetDriverDataLen(0);
687 // Remember printer name
688 maPrinterName = pInfo->maPrinterName;
689 maDriver = pInfo->maDriver;
691 // Add printer name to JobSetup
692 rData.SetPrinterName( maPrinterName );
693 rData.SetDriver( maDriver );
695 mpInfoPrinter = pSVData->mpDefInst->CreateInfoPrinter( pInfo, &rData );
696 mpPrinter = nullptr;
697 mpJobGraphics = nullptr;
698 ImplUpdateJobSetupPaper( maJobSetup );
700 if ( !mpInfoPrinter )
702 ImplInitDisplay();
703 return;
706 // we need a graphics
707 if ( !AcquireGraphics() )
709 ImplInitDisplay();
710 return;
713 // Init data
714 ImplUpdatePageData();
715 mpFontCollection = new PhysicalFontCollection();
716 mpFontCache = new ImplFontCache();
717 mpGraphics->GetDevFontList( mpFontCollection );
720 void Printer::ImplInitDisplay()
722 ImplSVData* pSVData = ImplGetSVData();
724 mpInfoPrinter = nullptr;
725 mpPrinter = nullptr;
726 mpJobGraphics = nullptr;
728 mpDisplayDev = VclPtr<VirtualDevice>::Create();
729 mpFontCollection = pSVData->maGDIData.mpScreenFontList;
730 mpFontCache = pSVData->maGDIData.mpScreenFontCache;
731 mnDPIX = mpDisplayDev->mnDPIX;
732 mnDPIY = mpDisplayDev->mnDPIY;
735 void Printer::DrawDeviceMask( const Bitmap& rMask, const Color& rMaskColor,
736 const Point& rDestPt, const Size& rDestSize,
737 const Point& rSrcPtPixel, const Size& rSrcSizePixel )
739 Point aPt;
740 Point aDestPt( LogicToPixel( rDestPt ) );
741 Size aDestSz( LogicToPixel( rDestSize ) );
742 tools::Rectangle aSrcRect( rSrcPtPixel, rSrcSizePixel );
744 aSrcRect.Justify();
746 if( !rMask.IsEmpty() && aSrcRect.GetWidth() && aSrcRect.GetHeight() && aDestSz.Width() && aDestSz.Height() )
748 Bitmap aMask( rMask );
749 BmpMirrorFlags nMirrFlags = BmpMirrorFlags::NONE;
751 if( aMask.GetBitCount() > 1 )
752 aMask.Convert( BmpConversion::N1BitThreshold );
754 // mirrored horizontically
755 if( aDestSz.Width() < 0 )
757 aDestSz.Width() = -aDestSz.Width();
758 aDestPt.X() -= ( aDestSz.Width() - 1 );
759 nMirrFlags |= BmpMirrorFlags::Horizontal;
762 // mirrored vertically
763 if( aDestSz.Height() < 0 )
765 aDestSz.Height() = -aDestSz.Height();
766 aDestPt.Y() -= ( aDestSz.Height() - 1 );
767 nMirrFlags |= BmpMirrorFlags::Vertical;
770 // source cropped?
771 if( aSrcRect != tools::Rectangle( aPt, aMask.GetSizePixel() ) )
772 aMask.Crop( aSrcRect );
774 // destination mirrored
775 if( nMirrFlags != BmpMirrorFlags::NONE)
776 aMask.Mirror( nMirrFlags );
778 // do painting
779 const long nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight();
780 long nX, nY; //, nWorkX, nWorkY, nWorkWidth, nWorkHeight;
781 long* pMapX = new long[ nSrcWidth + 1 ];
782 long* pMapY = new long[ nSrcHeight + 1 ];
783 GDIMetaFile* pOldMetaFile = mpMetaFile;
784 const bool bOldMap = mbMap;
786 mpMetaFile = nullptr;
787 mbMap = false;
788 Push( PushFlags::FILLCOLOR | PushFlags::LINECOLOR );
789 SetLineColor( rMaskColor );
790 SetFillColor( rMaskColor );
791 InitLineColor();
792 InitFillColor();
794 // create forward mapping tables
795 for( nX = 0; nX <= nSrcWidth; nX++ )
796 pMapX[ nX ] = aDestPt.X() + FRound( (double) aDestSz.Width() * nX / nSrcWidth );
798 for( nY = 0; nY <= nSrcHeight; nY++ )
799 pMapY[ nY ] = aDestPt.Y() + FRound( (double) aDestSz.Height() * nY / nSrcHeight );
801 // walk through all rectangles of mask
802 const vcl::Region aWorkRgn(aMask.CreateRegion(COL_BLACK, tools::Rectangle(Point(), aMask.GetSizePixel())));
803 RectangleVector aRectangles;
804 aWorkRgn.GetRegionRectangles(aRectangles);
806 for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter)
808 const Point aMapPt(pMapX[aRectIter->Left()], pMapY[aRectIter->Top()]);
809 const Size aMapSz(
810 pMapX[aRectIter->Right() + 1] - aMapPt.X(), // pMapX[L + W] -> L + ((R - L) + 1) -> R + 1
811 pMapY[aRectIter->Bottom() + 1] - aMapPt.Y()); // same for Y
813 DrawRect(tools::Rectangle(aMapPt, aMapSz));
816 Pop();
817 delete[] pMapX;
818 delete[] pMapY;
819 mbMap = bOldMap;
820 mpMetaFile = pOldMetaFile;
824 SalPrinterQueueInfo* Printer::ImplGetQueueInfo( const OUString& rPrinterName,
825 const OUString* pDriver )
827 ImplSVData* pSVData = ImplGetSVData();
828 if ( !pSVData->maGDIData.mpPrinterQueueList )
829 ImplInitPrnQueueList();
831 ImplPrnQueueList* pPrnList = pSVData->maGDIData.mpPrinterQueueList;
832 if ( pPrnList && pPrnList->m_aQueueInfos.size() )
834 // first search for the printer name directly
835 ImplPrnQueueData* pInfo = pPrnList->Get( rPrinterName );
836 if( pInfo )
837 return pInfo->mpSalQueueInfo;
839 // then search case insensitive
840 for(ImplPrnQueueData & rQueueInfo : pPrnList->m_aQueueInfos)
842 if( rQueueInfo.mpSalQueueInfo->maPrinterName.equalsIgnoreAsciiCase( rPrinterName ) )
843 return rQueueInfo.mpSalQueueInfo;
846 // then search for driver name
847 if ( pDriver )
849 for(ImplPrnQueueData & rQueueInfo : pPrnList->m_aQueueInfos)
851 if( rQueueInfo.mpSalQueueInfo->maDriver == *pDriver )
852 return rQueueInfo.mpSalQueueInfo;
856 // then the default printer
857 pInfo = pPrnList->Get( GetDefaultPrinterName() );
858 if( pInfo )
859 return pInfo->mpSalQueueInfo;
861 // last chance: the first available printer
862 return pPrnList->m_aQueueInfos[0].mpSalQueueInfo;
865 return nullptr;
868 void Printer::ImplUpdatePageData()
870 // we need a graphics
871 if ( !AcquireGraphics() )
872 return;
874 mpGraphics->GetResolution( mnDPIX, mnDPIY );
875 mpInfoPrinter->GetPageInfo( &maJobSetup.ImplGetConstData(),
876 mnOutWidth, mnOutHeight,
877 maPageOffset.X(), maPageOffset.Y(),
878 maPaperSize.Width(), maPaperSize.Height() );
881 void Printer::ImplUpdateFontList()
883 ImplUpdateFontData();
886 long Printer::GetGradientStepCount( long nMinRect )
888 // use display-equivalent step size calculation
889 long nInc = (nMinRect < 800) ? 10 : 20;
891 return nInc;
894 Printer::Printer()
896 ImplInitData();
897 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( GetDefaultPrinterName(), nullptr );
898 if ( pInfo )
900 ImplInit( pInfo );
901 if ( !IsDisplayPrinter() )
902 mbDefPrinter = true;
904 else
905 ImplInitDisplay();
908 Printer::Printer( const JobSetup& rJobSetup ) :
909 maJobSetup( rJobSetup )
911 ImplInitData();
912 const ImplJobSetup& rConstData = rJobSetup.ImplGetConstData();
913 OUString aDriver = rConstData.GetDriver();
914 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( rConstData.GetPrinterName(),
915 &aDriver );
916 if ( pInfo )
918 ImplInit( pInfo );
919 SetJobSetup( rJobSetup );
921 else
923 ImplInitDisplay();
924 maJobSetup = JobSetup();
928 Printer::Printer( const QueueInfo& rQueueInfo )
930 ImplInitData();
931 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( rQueueInfo.GetPrinterName(),
932 &rQueueInfo.GetDriver() );
933 if ( pInfo )
934 ImplInit( pInfo );
935 else
936 ImplInitDisplay();
939 Printer::Printer( const OUString& rPrinterName )
941 ImplInitData();
942 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( rPrinterName, nullptr );
943 if ( pInfo )
944 ImplInit( pInfo );
945 else
946 ImplInitDisplay();
949 Printer::~Printer()
951 disposeOnce();
954 void Printer::dispose()
956 SAL_WARN_IF( IsPrinting(), "vcl.gdi", "Printer::~Printer() - Job is printing" );
957 SAL_WARN_IF( IsJobActive(), "vcl.gdi", "Printer::~Printer() - Job is active" );
959 delete mpPrinterOptions;
960 mpPrinterOptions = nullptr;
962 ReleaseGraphics();
963 if ( mpInfoPrinter )
964 ImplGetSVData()->mpDefInst->DestroyInfoPrinter( mpInfoPrinter );
965 if ( mpDisplayDev )
966 mpDisplayDev.disposeAndClear();
967 else
969 // OutputDevice Dtor is trying the same thing; that why we need to set
970 // the FontEntry to NULL here
971 // TODO: consolidate duplicate cleanup by Printer and OutputDevice
972 if ( mpFontInstance )
974 mpFontCache->Release( mpFontInstance );
975 mpFontInstance = nullptr;
977 if ( mpDeviceFontList )
979 delete mpDeviceFontList;
980 mpDeviceFontList = nullptr;
982 if ( mpDeviceFontSizeList )
984 delete mpDeviceFontSizeList;
985 mpDeviceFontSizeList = nullptr;
987 delete mpFontCache;
988 mpFontCache = nullptr;
989 // font list deleted by OutputDevice dtor
992 // Add printer from the list
993 ImplSVData* pSVData = ImplGetSVData();
994 if ( mpPrev )
995 mpPrev->mpNext = mpNext;
996 else
997 pSVData->maGDIData.mpFirstPrinter = mpNext;
998 if ( mpNext )
999 mpNext->mpPrev = mpPrev;
1000 else
1001 pSVData->maGDIData.mpLastPrinter = mpPrev;
1003 mpPrev.clear();
1004 mpNext.clear();
1005 OutputDevice::dispose();
1008 sal_uInt32 Printer::GetCapabilities( PrinterCapType nType ) const
1010 if ( IsDisplayPrinter() )
1011 return 0;
1013 if( mpInfoPrinter )
1014 return mpInfoPrinter->GetCapabilities( &maJobSetup.ImplGetConstData(), nType );
1015 else
1016 return 0;
1019 bool Printer::HasSupport( PrinterSupport eFeature ) const
1021 switch ( eFeature )
1023 case PrinterSupport::SetOrientation:
1024 return GetCapabilities( PrinterCapType::SetOrientation ) != 0;
1025 case PrinterSupport::SetPaperSize:
1026 return GetCapabilities( PrinterCapType::SetPaperSize ) != 0;
1027 case PrinterSupport::SetPaper:
1028 return GetCapabilities( PrinterCapType::SetPaper ) != 0;
1029 case PrinterSupport::CollateCopy:
1030 return (GetCapabilities( PrinterCapType::CollateCopies ) != 0);
1031 case PrinterSupport::SetupDialog:
1032 return GetCapabilities( PrinterCapType::SupportDialog ) != 0;
1035 return true;
1038 bool Printer::SetJobSetup( const JobSetup& rSetup )
1040 if ( IsDisplayPrinter() || mbInPrintPage )
1041 return false;
1043 JobSetup aJobSetup = rSetup;
1045 ReleaseGraphics();
1046 if ( mpInfoPrinter->SetPrinterData( &aJobSetup.ImplGetData() ) )
1048 ImplUpdateJobSetupPaper( aJobSetup );
1049 mbNewJobSetup = true;
1050 maJobSetup = aJobSetup;
1051 ImplUpdatePageData();
1052 ImplUpdateFontList();
1053 return true;
1056 return false;
1059 bool Printer::Setup( vcl::Window* pWindow, bool bPapersizeFromSetup )
1061 if ( IsDisplayPrinter() )
1062 return false;
1064 if ( IsJobActive() || IsPrinting() )
1065 return false;
1067 JobSetup aJobSetup = maJobSetup;
1068 ImplJobSetup& rData = aJobSetup.ImplGetData();
1069 rData.SetPapersizeFromSetup( bPapersizeFromSetup );
1070 SalFrame* pFrame;
1071 if ( !pWindow )
1072 pWindow = ImplGetDefaultWindow();
1073 if( !pWindow )
1074 return false;
1076 pFrame = pWindow->ImplGetFrame();
1077 ReleaseGraphics();
1078 ImplSVData* pSVData = ImplGetSVData();
1079 pSVData->maAppData.mnModalMode++;
1080 nImplSysDialog++;
1081 bool bSetup = mpInfoPrinter->Setup( pFrame, &rData );
1082 pSVData->maAppData.mnModalMode--;
1083 nImplSysDialog--;
1084 if ( bSetup )
1086 ImplUpdateJobSetupPaper( aJobSetup );
1087 mbNewJobSetup = true;
1088 maJobSetup = aJobSetup;
1089 ImplUpdatePageData();
1090 ImplUpdateFontList();
1091 return true;
1093 return false;
1096 bool Printer::SetPrinterProps( const Printer* pPrinter )
1098 if ( IsJobActive() || IsPrinting() )
1099 return false;
1101 ImplSVData* pSVData = ImplGetSVData();
1103 mbDefPrinter = pPrinter->mbDefPrinter;
1104 maPrintFile = pPrinter->maPrintFile;
1105 mbPrintFile = pPrinter->mbPrintFile;
1106 mnCopyCount = pPrinter->mnCopyCount;
1107 mbCollateCopy = pPrinter->mbCollateCopy;
1108 mnPageQueueSize = pPrinter->mnPageQueueSize;
1109 *mpPrinterOptions = *pPrinter->mpPrinterOptions;
1111 if ( pPrinter->IsDisplayPrinter() )
1113 // Destroy old printer
1114 if ( !IsDisplayPrinter() )
1116 ReleaseGraphics();
1117 pSVData->mpDefInst->DestroyInfoPrinter( mpInfoPrinter );
1118 if ( mpFontInstance )
1120 mpFontCache->Release( mpFontInstance );
1121 mpFontInstance = nullptr;
1123 if ( mpDeviceFontList )
1125 delete mpDeviceFontList;
1126 mpDeviceFontList = nullptr;
1128 if ( mpDeviceFontSizeList )
1130 delete mpDeviceFontSizeList;
1131 mpDeviceFontSizeList = nullptr;
1133 // clean up font list
1134 delete mpFontCache;
1135 delete mpFontCollection;
1136 mpFontCache = nullptr;
1137 mpFontCollection = nullptr;
1139 mbInitFont = true;
1140 mbNewFont = true;
1141 mpInfoPrinter = nullptr;
1144 // Construct new printer
1145 ImplInitDisplay();
1146 return true;
1149 // Destroy old printer?
1150 if ( GetName() != pPrinter->GetName() )
1152 ReleaseGraphics();
1153 if ( mpDisplayDev )
1155 mpDisplayDev.disposeAndClear();
1157 else
1159 pSVData->mpDefInst->DestroyInfoPrinter( mpInfoPrinter );
1161 if ( mpFontInstance )
1163 mpFontCache->Release( mpFontInstance );
1164 mpFontInstance = nullptr;
1166 if ( mpDeviceFontList )
1168 delete mpDeviceFontList;
1169 mpDeviceFontList = nullptr;
1171 if ( mpDeviceFontSizeList )
1173 delete mpDeviceFontSizeList;
1174 mpDeviceFontSizeList = nullptr;
1176 delete mpFontCache;
1177 delete mpFontCollection;
1178 mpFontCache = nullptr;
1179 mpFontCollection = nullptr;
1180 mbInitFont = true;
1181 mbNewFont = true;
1182 mpInfoPrinter = nullptr;
1185 // Construct new printer
1186 OUString aDriver = pPrinter->GetDriverName();
1187 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( pPrinter->GetName(), &aDriver );
1188 if ( pInfo )
1190 ImplInit( pInfo );
1191 SetJobSetup( pPrinter->GetJobSetup() );
1193 else
1194 ImplInitDisplay();
1196 else
1197 SetJobSetup( pPrinter->GetJobSetup() );
1199 return false;
1202 bool Printer::SetOrientation( Orientation eOrientation )
1204 if ( mbInPrintPage )
1205 return false;
1207 if ( maJobSetup.ImplGetConstData().GetOrientation() != eOrientation )
1209 JobSetup aJobSetup = maJobSetup;
1210 ImplJobSetup& rData = aJobSetup.ImplGetData();
1212 rData.SetOrientation(eOrientation);
1214 if ( IsDisplayPrinter() )
1216 mbNewJobSetup = true;
1217 maJobSetup = aJobSetup;
1218 return true;
1221 ReleaseGraphics();
1222 if ( mpInfoPrinter->SetData( JobSetFlags::ORIENTATION, &rData ) )
1224 ImplUpdateJobSetupPaper( aJobSetup );
1225 mbNewJobSetup = true;
1226 maJobSetup = aJobSetup;
1227 ImplUpdatePageData();
1228 ImplUpdateFontList();
1229 return true;
1231 else
1232 return false;
1235 return true;
1238 Orientation Printer::GetOrientation() const
1240 return maJobSetup.ImplGetConstData().GetOrientation();
1243 bool Printer::SetPaperBin( sal_uInt16 nPaperBin )
1245 if ( mbInPrintPage )
1246 return false;
1248 if ( maJobSetup.ImplGetConstData().GetPaperBin() != nPaperBin &&
1249 nPaperBin < GetPaperBinCount() )
1251 JobSetup aJobSetup = maJobSetup;
1252 ImplJobSetup& rData = aJobSetup.ImplGetData();
1253 rData.SetPaperBin(nPaperBin);
1255 if ( IsDisplayPrinter() )
1257 mbNewJobSetup = true;
1258 maJobSetup = aJobSetup;
1259 return true;
1262 ReleaseGraphics();
1263 if ( mpInfoPrinter->SetData( JobSetFlags::PAPERBIN, &rData ) )
1265 ImplUpdateJobSetupPaper( aJobSetup );
1266 mbNewJobSetup = true;
1267 maJobSetup = aJobSetup;
1268 ImplUpdatePageData();
1269 ImplUpdateFontList();
1270 return true;
1272 else
1273 return false;
1276 return true;
1279 sal_uInt16 Printer::GetPaperBin() const
1281 return maJobSetup.ImplGetConstData().GetPaperBin();
1284 // Map user paper format to a available printer paper formats
1285 void Printer::ImplFindPaperFormatForUserSize( JobSetup& aJobSetup, bool bMatchNearest )
1287 ImplJobSetup& rData = aJobSetup.ImplGetData();
1289 // The angle that a landscape page will be turned counterclockwise wrt to portrait.
1290 int nLandscapeAngle = mpInfoPrinter ? mpInfoPrinter->GetLandscapeAngle( &maJobSetup.ImplGetConstData() ) : 900;
1292 int nPaperCount = GetPaperInfoCount();
1293 bool bFound = false;
1295 PaperInfo aInfo(rData.GetPaperWidth(), rData.GetPaperHeight());
1297 // Compare all paper formats and get the appropriate one
1298 for ( int i = 0; i < nPaperCount; i++ )
1300 const PaperInfo& rPaperInfo = GetPaperInfo( i );
1302 if ( aInfo.sloppyEqual(rPaperInfo) )
1304 rData.SetPaperFormat(
1305 ImplGetPaperFormat( rPaperInfo.getWidth(),
1306 rPaperInfo.getHeight() ));
1307 rData.SetOrientation( Orientation::Portrait );
1308 bFound = true;
1309 break;
1313 // If the printer supports landscape orientation, check paper sizes again
1314 // with landscape orientation. This is necessary as a printer driver provides
1315 // all paper sizes with portrait orientation only!!
1316 if ( rData.GetPaperFormat() == PAPER_USER &&
1317 nLandscapeAngle != 0 &&
1318 HasSupport( PrinterSupport::SetOrientation ))
1320 const long nRotatedWidth = rData.GetPaperHeight();
1321 const long nRotatedHeight = rData.GetPaperWidth();
1322 PaperInfo aRotatedInfo(nRotatedWidth, nRotatedHeight);
1324 for ( int i = 0; i < nPaperCount; i++ )
1326 const PaperInfo& rPaperInfo = GetPaperInfo( i );
1328 if ( aRotatedInfo.sloppyEqual( rPaperInfo ) )
1330 rData.SetPaperFormat(
1331 ImplGetPaperFormat( rPaperInfo.getWidth(),
1332 rPaperInfo.getHeight() ));
1333 rData.SetOrientation( Orientation::Landscape );
1334 bFound = true;
1335 break;
1340 if( ! bFound && bMatchNearest )
1342 sal_Int64 nBestMatch = SAL_MAX_INT64;
1343 int nBestIndex = 0;
1344 Orientation eBestOrientation = Orientation::Portrait;
1345 for( int i = 0; i < nPaperCount; i++ )
1347 const PaperInfo& rPaperInfo = GetPaperInfo( i );
1349 // check portrait match
1350 sal_Int64 nDX = rData.GetPaperWidth() - rPaperInfo.getWidth();
1351 sal_Int64 nDY = rData.GetPaperHeight() - rPaperInfo.getHeight();
1352 sal_Int64 nMatch = nDX*nDX + nDY*nDY;
1353 if( nMatch < nBestMatch )
1355 nBestMatch = nMatch;
1356 nBestIndex = i;
1357 eBestOrientation = Orientation::Portrait;
1360 // check landscape match
1361 nDX = rData.GetPaperWidth() - rPaperInfo.getHeight();
1362 nDY = rData.GetPaperHeight() - rPaperInfo.getWidth();
1363 nMatch = nDX*nDX + nDY*nDY;
1364 if( nMatch < nBestMatch )
1366 nBestMatch = nMatch;
1367 nBestIndex = i;
1368 eBestOrientation = Orientation::Landscape;
1371 const PaperInfo& rBestInfo = GetPaperInfo( nBestIndex );
1372 rData.SetPaperFormat(
1373 ImplGetPaperFormat( rBestInfo.getWidth(),
1374 rBestInfo.getHeight() ));
1375 rData.SetOrientation(eBestOrientation);
1379 bool Printer::SetPaper( Paper ePaper )
1381 if ( mbInPrintPage )
1382 return false;
1384 if ( maJobSetup.ImplGetConstData().GetPaperFormat() != ePaper )
1386 JobSetup aJobSetup = maJobSetup;
1387 ImplJobSetup& rData = aJobSetup.ImplGetData();
1389 rData.SetPaperFormat( ePaper );
1390 if ( ePaper != PAPER_USER )
1392 PaperInfo aInfo(ePaper);
1393 rData.SetPaperWidth( aInfo.getWidth() );
1394 rData.SetPaperHeight( aInfo.getHeight() );
1397 if ( IsDisplayPrinter() )
1399 mbNewJobSetup = true;
1400 maJobSetup = aJobSetup;
1401 return true;
1404 ReleaseGraphics();
1405 if ( ePaper == PAPER_USER )
1406 ImplFindPaperFormatForUserSize( aJobSetup, false );
1407 if ( mpInfoPrinter->SetData( JobSetFlags::PAPERSIZE | JobSetFlags::ORIENTATION, &rData ))
1409 ImplUpdateJobSetupPaper( aJobSetup );
1410 mbNewJobSetup = true;
1411 maJobSetup = aJobSetup;
1412 ImplUpdatePageData();
1413 ImplUpdateFontList();
1414 return true;
1416 else
1417 return false;
1420 return true;
1423 bool Printer::SetPaperSizeUser( const Size& rSize )
1425 return SetPaperSizeUser( rSize, false );
1428 bool Printer::SetPaperSizeUser( const Size& rSize, bool bMatchNearest )
1430 if ( mbInPrintPage )
1431 return false;
1433 const Size aPixSize = LogicToPixel( rSize );
1434 const Size aPageSize = PixelToLogic( aPixSize, MapUnit::Map100thMM );
1435 bool bNeedToChange(maJobSetup.ImplGetConstData().GetPaperWidth() != aPageSize.Width() ||
1436 maJobSetup.ImplGetConstData().GetPaperHeight() != aPageSize.Height());
1438 if(!bNeedToChange)
1440 // #i122984# only need to change when Paper is different from PAPER_USER and
1441 // the mapped Paper which will created below in the call to ImplFindPaperFormatForUserSize
1442 // and will replace maJobSetup.ImplGetConstData()->GetPaperFormat(). This leads to
1443 // unnecessary JobSetups, e.g. when printing a multi-page fax, but also with
1444 // normal print
1445 const Paper aPaper = ImplGetPaperFormat(aPageSize.Width(), aPageSize.Height());
1447 bNeedToChange = maJobSetup.ImplGetConstData().GetPaperFormat() != PAPER_USER &&
1448 maJobSetup.ImplGetConstData().GetPaperFormat() != aPaper;
1451 if(bNeedToChange)
1453 JobSetup aJobSetup = maJobSetup;
1454 ImplJobSetup& rData = aJobSetup.ImplGetData();
1455 rData.SetPaperFormat( PAPER_USER );
1456 rData.SetPaperWidth( aPageSize.Width() );
1457 rData.SetPaperHeight( aPageSize.Height() );
1459 if ( IsDisplayPrinter() )
1461 mbNewJobSetup = true;
1462 maJobSetup = aJobSetup;
1463 return true;
1466 ReleaseGraphics();
1467 ImplFindPaperFormatForUserSize( aJobSetup, bMatchNearest );
1469 // Changing the paper size can also change the orientation!
1470 if ( mpInfoPrinter->SetData( JobSetFlags::PAPERSIZE | JobSetFlags::ORIENTATION, &rData ))
1472 ImplUpdateJobSetupPaper( aJobSetup );
1473 mbNewJobSetup = true;
1474 maJobSetup = aJobSetup;
1475 ImplUpdatePageData();
1476 ImplUpdateFontList();
1477 return true;
1479 else
1480 return false;
1483 return true;
1486 int Printer::GetPaperInfoCount() const
1488 if( ! mpInfoPrinter )
1489 return 0;
1490 if( ! mpInfoPrinter->m_bPapersInit )
1491 mpInfoPrinter->InitPaperFormats( &maJobSetup.ImplGetConstData() );
1492 return mpInfoPrinter->m_aPaperFormats.size();
1495 OUString Printer::GetPaperName( Paper ePaper )
1497 ImplSVData* pSVData = ImplGetSVData();
1498 if( ! pSVData->mpPaperNames )
1500 pSVData->mpPaperNames = new std::unordered_map< int, OUString >;
1501 if( ImplGetResMgr() )
1503 ResStringArray aPaperStrings( VclResId( RID_STR_PAPERNAMES ) );
1504 static const int PaperIndex[] =
1506 PAPER_A0, PAPER_A1, PAPER_A2, PAPER_A3, PAPER_A4, PAPER_A5,
1507 PAPER_B4_ISO, PAPER_B5_ISO, PAPER_LETTER, PAPER_LEGAL, PAPER_TABLOID,
1508 PAPER_USER, PAPER_B6_ISO, PAPER_ENV_C4, PAPER_ENV_C5, PAPER_ENV_C6, PAPER_ENV_C65,
1509 PAPER_ENV_DL, PAPER_SLIDE_DIA, PAPER_C, PAPER_D, PAPER_E,
1510 PAPER_EXECUTIVE, PAPER_FANFOLD_LEGAL_DE, PAPER_ENV_MONARCH, PAPER_ENV_PERSONAL,
1511 PAPER_ENV_9, PAPER_ENV_10, PAPER_ENV_11, PAPER_ENV_12, PAPER_KAI16,
1512 PAPER_KAI32, PAPER_KAI32BIG, PAPER_B4_JIS, PAPER_B5_JIS, PAPER_B6_JIS,
1513 PAPER_POSTCARD_JP
1515 OSL_ENSURE( sal_uInt32(SAL_N_ELEMENTS(PaperIndex)) == aPaperStrings.Count(), "localized paper name count wrong" );
1516 for( int i = 0; i < int(SAL_N_ELEMENTS(PaperIndex)); i++ )
1517 (*pSVData->mpPaperNames)[PaperIndex[i]] = aPaperStrings.GetString(i);
1521 std::unordered_map<int,OUString>::const_iterator it = pSVData->mpPaperNames->find( (int)ePaper );
1522 return (it != pSVData->mpPaperNames->end()) ? it->second : OUString();
1525 OUString Printer::GetPaperName() const
1527 Size aPageSize = PixelToLogic( GetPaperSizePixel(), MapUnit::Map100thMM );
1528 Paper ePaper = ImplGetPaperFormat( aPageSize.Width(), aPageSize.Height() );
1529 if( ePaper == PAPER_USER )
1530 ePaper = ImplGetPaperFormat( aPageSize.Height(), aPageSize.Width() );
1531 return (ePaper != PAPER_USER) ? GetPaperName( ePaper ) : OUString();
1534 const PaperInfo& Printer::GetPaperInfo( int nPaper ) const
1536 if( ! mpInfoPrinter )
1537 return ImplGetEmptyPaper();
1538 if( ! mpInfoPrinter->m_bPapersInit )
1539 mpInfoPrinter->InitPaperFormats( &maJobSetup.ImplGetConstData() );
1540 if( mpInfoPrinter->m_aPaperFormats.empty() || nPaper < 0 || nPaper >= int(mpInfoPrinter->m_aPaperFormats.size()) )
1541 return ImplGetEmptyPaper();
1542 return mpInfoPrinter->m_aPaperFormats[nPaper];
1545 bool Printer::SetDuplexMode( DuplexMode eDuplex )
1547 if ( mbInPrintPage )
1548 return false;
1550 if ( maJobSetup.ImplGetConstData().GetDuplexMode() != eDuplex )
1552 JobSetup aJobSetup = maJobSetup;
1553 ImplJobSetup& rData = aJobSetup.ImplGetData();
1555 rData.SetDuplexMode( eDuplex );
1557 if ( IsDisplayPrinter() )
1559 mbNewJobSetup = true;
1560 maJobSetup = aJobSetup;
1561 return true;
1564 ReleaseGraphics();
1565 if ( mpInfoPrinter->SetData( JobSetFlags::DUPLEXMODE, &rData ) )
1567 ImplUpdateJobSetupPaper( aJobSetup );
1568 mbNewJobSetup = true;
1569 maJobSetup = aJobSetup;
1570 ImplUpdatePageData();
1571 ImplUpdateFontList();
1572 return true;
1574 else
1575 return false;
1578 return true;
1581 Paper Printer::GetPaper() const
1583 return maJobSetup.ImplGetConstData().GetPaperFormat();
1586 sal_uInt16 Printer::GetPaperBinCount() const
1588 if ( IsDisplayPrinter() )
1589 return 0;
1591 return mpInfoPrinter->GetPaperBinCount( &maJobSetup.ImplGetConstData() );
1594 OUString Printer::GetPaperBinName( sal_uInt16 nPaperBin ) const
1596 if ( IsDisplayPrinter() )
1597 return OUString();
1599 if ( nPaperBin < GetPaperBinCount() )
1600 return mpInfoPrinter->GetPaperBinName( &maJobSetup.ImplGetConstData(), nPaperBin );
1601 else
1602 return OUString();
1605 bool Printer::SetCopyCount( sal_uInt16 nCopy, bool bCollate )
1607 mnCopyCount = nCopy;
1608 mbCollateCopy = bCollate;
1609 return true;
1612 sal_uLong Printer::ImplSalPrinterErrorCodeToVCL( sal_uLong nError )
1614 sal_uLong nVCLError;
1615 switch ( nError )
1617 case 0:
1618 nVCLError = PRINTER_OK;
1619 break;
1620 case SAL_PRINTER_ERROR_ABORT:
1621 nVCLError = PRINTER_ABORT;
1622 break;
1623 default:
1624 nVCLError = PRINTER_GENERALERROR;
1625 break;
1628 return nVCLError;
1631 bool Printer::EndJob()
1633 bool bRet = false;
1634 if ( !IsJobActive() )
1635 return bRet;
1637 SAL_WARN_IF( mbInPrintPage, "vcl.gdi", "Printer::EndJob() - StartPage() without EndPage() called" );
1639 mbJobActive = false;
1641 if ( mpPrinter )
1643 ReleaseGraphics();
1645 mnCurPage = 0;
1647 mbPrinting = false;
1648 mnCurPrintPage = 0;
1649 maJobName.clear();
1651 mbDevOutput = false;
1652 bRet = mpPrinter->EndJob();
1653 // FIXME: Do not destroy the printer asynchronously as Win95
1654 // can't handle destroying a printer object and printing
1655 // at the same time
1656 ImplGetSVData()->mpDefInst->DestroyPrinter( mpPrinter );
1657 mpPrinter = nullptr;
1660 return bRet;
1663 void Printer::ImplStartPage()
1665 if ( !IsJobActive() )
1666 return;
1668 if ( mpPrinter )
1670 SalGraphics* pGraphics = mpPrinter->StartPage( &maJobSetup.ImplGetData(),
1671 mbNewJobSetup );
1672 if ( pGraphics )
1674 ReleaseGraphics();
1675 mpJobGraphics = pGraphics;
1677 mbDevOutput = true;
1679 // PrintJob not aborted ???
1680 if ( IsJobActive() )
1682 mbInPrintPage = true;
1683 mnCurPage++;
1684 mnCurPrintPage++;
1689 void Printer::ImplEndPage()
1691 if ( !IsJobActive() )
1692 return;
1694 mbInPrintPage = false;
1696 if ( mpPrinter )
1698 mpPrinter->EndPage();
1699 ReleaseGraphics();
1700 mbDevOutput = false;
1702 mpJobGraphics = nullptr;
1703 mbNewJobSetup = false;
1707 void Printer::updatePrinters()
1709 ImplSVData* pSVData = ImplGetSVData();
1710 ImplPrnQueueList* pPrnList = pSVData->maGDIData.mpPrinterQueueList;
1712 if ( pPrnList )
1714 ImplPrnQueueList* pNewList = new ImplPrnQueueList;
1715 pSVData->mpDefInst->GetPrinterQueueInfo( pNewList );
1717 bool bChanged = pPrnList->m_aQueueInfos.size() != pNewList->m_aQueueInfos.size();
1718 for( decltype(pPrnList->m_aQueueInfos)::size_type i = 0; ! bChanged && i < pPrnList->m_aQueueInfos.size(); i++ )
1720 ImplPrnQueueData& rInfo = pPrnList->m_aQueueInfos[i];
1721 ImplPrnQueueData& rNewInfo = pNewList->m_aQueueInfos[i];
1722 if( ! rInfo.mpSalQueueInfo || ! rNewInfo.mpSalQueueInfo || // sanity check
1723 rInfo.mpSalQueueInfo->maPrinterName != rNewInfo.mpSalQueueInfo->maPrinterName )
1725 bChanged = true;
1728 if( bChanged )
1730 ImplDeletePrnQueueList();
1731 pSVData->maGDIData.mpPrinterQueueList = pNewList;
1733 Application* pApp = GetpApp();
1734 if( pApp )
1736 DataChangedEvent aDCEvt( DataChangedEventType::PRINTER );
1737 Application::NotifyAllWindows( aDCEvt );
1740 else
1741 delete pNewList;
1745 bool Printer::UsePolyPolygonForComplexGradient()
1747 return true;
1750 void Printer::ClipAndDrawGradientMetafile ( const Gradient &rGradient, const tools::PolyPolygon &rPolyPoly )
1752 const tools::Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
1754 Push( PushFlags::CLIPREGION );
1755 IntersectClipRegion(vcl::Region(rPolyPoly));
1756 DrawGradient( aBoundRect, rGradient );
1757 Pop();
1760 void Printer::InitFont() const
1762 DBG_TESTSOLARMUTEX();
1764 if (!mpFontInstance)
1765 return;
1767 if ( mbInitFont )
1769 // select font in the device layers
1770 mpGraphics->SetFont( &(mpFontInstance->maFontSelData), 0 );
1771 mbInitFont = false;
1775 void Printer::SetFontOrientation( LogicalFontInstance* const pFontEntry ) const
1777 pFontEntry->mnOrientation = pFontEntry->mxFontMetric->GetOrientation();
1780 Bitmap Printer::GetBitmap( const Point& rSrcPt, const Size& rSize ) const
1782 SAL_WARN("vcl.gdi", "GetBitmap(): This should never be called on by a Printer instance");
1784 return OutputDevice::GetBitmap( rSrcPt, rSize );
1787 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */