bump product version to 7.2.5.1
[LibreOffice.git] / vcl / source / gdi / print.cxx
blob652bc00c58be7f57b2af0a3c703330c34767c2a5
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/QueueInfo.hxx>
27 #include <vcl/event.hxx>
28 #include <vcl/virdev.hxx>
29 #include <vcl/print.hxx>
31 #include <comphelper/processfactory.hxx>
33 #include <salinst.hxx>
34 #include <salvd.hxx>
35 #include <salgdi.hxx>
36 #include <salptype.hxx>
37 #include <salprn.hxx>
38 #include <svdata.hxx>
39 #include <print.hrc>
40 #include <jobset.h>
41 #include <outdev.h>
42 #include <PhysicalFontCollection.hxx>
43 #include <print.h>
45 #include <com/sun/star/beans/XPropertySet.hpp>
46 #include <com/sun/star/configuration/theDefaultProvider.hpp>
47 #include <com/sun/star/container/XNameAccess.hpp>
48 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
49 #include <com/sun/star/uno/Sequence.h>
51 int nImplSysDialog = 0;
53 namespace
55 Paper ImplGetPaperFormat( tools::Long nWidth100thMM, tools::Long nHeight100thMM )
57 PaperInfo aInfo(nWidth100thMM, nHeight100thMM);
58 aInfo.doSloppyFit();
59 return aInfo.getPaper();
62 const PaperInfo& ImplGetEmptyPaper()
64 static PaperInfo aInfo(PAPER_USER);
65 return aInfo;
69 void ImplUpdateJobSetupPaper( JobSetup& rJobSetup )
71 const ImplJobSetup& rConstData = rJobSetup.ImplGetConstData();
73 if ( !rConstData.GetPaperWidth() || !rConstData.GetPaperHeight() )
75 if ( rConstData.GetPaperFormat() != PAPER_USER )
77 PaperInfo aInfo(rConstData.GetPaperFormat());
79 ImplJobSetup& rData = rJobSetup.ImplGetData();
80 rData.SetPaperWidth( aInfo.getWidth() );
81 rData.SetPaperHeight( aInfo.getHeight() );
84 else if ( rConstData.GetPaperFormat() == PAPER_USER )
86 Paper ePaper = ImplGetPaperFormat( rConstData.GetPaperWidth(), rConstData.GetPaperHeight() );
87 if ( ePaper != PAPER_USER )
88 rJobSetup.ImplGetData().SetPaperFormat(ePaper);
92 // PrinterOptions
93 PrinterOptions::PrinterOptions() :
94 mbReduceTransparency( false ),
95 meReducedTransparencyMode( PrinterTransparencyMode::Auto ),
96 mbReduceGradients( false ),
97 meReducedGradientsMode( PrinterGradientMode::Stripes ),
98 mnReducedGradientStepCount( 64 ),
99 mbReduceBitmaps( false ),
100 meReducedBitmapMode( PrinterBitmapMode::Normal ),
101 mnReducedBitmapResolution( 200 ),
102 mbReducedBitmapsIncludeTransparency( true ),
103 mbConvertToGreyscales( false ),
104 mbPDFAsStandardPrintJobFormat( false )
108 void PrinterOptions::ReadFromConfig( bool i_bFile )
110 bool bSuccess = false;
111 // save old state in case something goes wrong
112 PrinterOptions aOldValues( *this );
114 // get the configuration service
115 css::uno::Reference< css::lang::XMultiServiceFactory > xConfigProvider;
116 css::uno::Reference< css::container::XNameAccess > xConfigAccess;
119 // get service provider
120 css::uno::Reference< css::uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
121 // create configuration hierarchical access name
124 xConfigProvider = css::configuration::theDefaultProvider::get( xContext );
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 xConfigAccess.set(
133 xConfigProvider->createInstanceWithArguments(
134 "com.sun.star.configuration.ConfigurationAccess", { css::uno::Any(aVal) } ),
135 css::uno::UNO_QUERY );
136 if( xConfigAccess.is() )
138 css::uno::Reference< css::beans::XPropertySet > xSet( xConfigAccess, css::uno::UNO_QUERY );
139 if( xSet.is() )
141 sal_Int32 nValue = 0;
142 bool bValue = false;
143 if( xSet->getPropertyValue("ReduceTransparency") >>= bValue )
144 SetReduceTransparency( bValue );
145 if( xSet->getPropertyValue("ReducedTransparencyMode") >>= nValue )
146 SetReducedTransparencyMode( static_cast<PrinterTransparencyMode>(nValue) );
147 if( xSet->getPropertyValue("ReduceGradients") >>= bValue )
148 SetReduceGradients( bValue );
149 if( xSet->getPropertyValue("ReducedGradientMode") >>= nValue )
150 SetReducedGradientMode( static_cast<PrinterGradientMode>(nValue) );
151 if( xSet->getPropertyValue("ReducedGradientStepCount") >>= nValue )
152 SetReducedGradientStepCount( static_cast<sal_uInt16>(nValue) );
153 if( xSet->getPropertyValue("ReduceBitmaps") >>= bValue )
154 SetReduceBitmaps( bValue );
155 if( xSet->getPropertyValue("ReducedBitmapMode") >>= nValue )
156 SetReducedBitmapMode( static_cast<PrinterBitmapMode>(nValue) );
157 if( xSet->getPropertyValue("ReducedBitmapResolution") >>= nValue )
158 SetReducedBitmapResolution( static_cast<sal_uInt16>(nValue) );
159 if( xSet->getPropertyValue("ReducedBitmapIncludesTransparency") >>= bValue )
160 SetReducedBitmapIncludesTransparency( bValue );
161 if( xSet->getPropertyValue("ConvertToGreyscales") >>= bValue )
162 SetConvertToGreyscales( bValue );
163 if( xSet->getPropertyValue("PDFAsStandardPrintJobFormat") >>= bValue )
164 SetPDFAsStandardPrintJobFormat( bValue );
166 bSuccess = true;
170 catch( const css::uno::Exception& )
174 catch( const css::lang::WrappedTargetException& )
178 if( ! bSuccess )
179 *this = aOldValues;
182 void Printer::ImplPrintTransparent( const Bitmap& rBmp, const Bitmap& rMask,
183 const Point& rDestPt, const Size& rDestSize,
184 const Point& rSrcPtPixel, const Size& rSrcSizePixel )
186 Point aDestPt( LogicToPixel( rDestPt ) );
187 Size aDestSz( LogicToPixel( rDestSize ) );
188 tools::Rectangle aSrcRect( rSrcPtPixel, rSrcSizePixel );
190 aSrcRect.Justify();
192 if( rBmp.IsEmpty() || !aSrcRect.GetWidth() || !aSrcRect.GetHeight() || !aDestSz.Width() || !aDestSz.Height() )
193 return;
195 Bitmap aPaint( rBmp ), aMask( rMask );
196 BmpMirrorFlags nMirrFlags = BmpMirrorFlags::NONE;
198 if (aMask.getPixelFormat() > vcl::PixelFormat::N1_BPP)
199 aMask.Convert( BmpConversion::N1BitThreshold );
201 // mirrored horizontally
202 if( aDestSz.Width() < 0 )
204 aDestSz.setWidth( -aDestSz.Width() );
205 aDestPt.AdjustX( -( aDestSz.Width() - 1 ) );
206 nMirrFlags |= BmpMirrorFlags::Horizontal;
209 // mirrored vertically
210 if( aDestSz.Height() < 0 )
212 aDestSz.setHeight( -aDestSz.Height() );
213 aDestPt.AdjustY( -( aDestSz.Height() - 1 ) );
214 nMirrFlags |= BmpMirrorFlags::Vertical;
217 // source cropped?
218 if( aSrcRect != tools::Rectangle( Point(), aPaint.GetSizePixel() ) )
220 aPaint.Crop( aSrcRect );
221 aMask.Crop( aSrcRect );
224 // destination mirrored
225 if( nMirrFlags != BmpMirrorFlags::NONE )
227 aPaint.Mirror( nMirrFlags );
228 aMask.Mirror( nMirrFlags );
231 // we always want to have a mask
232 if( aMask.IsEmpty() )
234 aMask = Bitmap(aSrcRect.GetSize(), vcl::PixelFormat::N1_BPP);
235 aMask.Erase( COL_BLACK );
238 // do painting
239 const tools::Long nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight();
240 tools::Long nX, nY; // , nWorkX, nWorkY, nWorkWidth, nWorkHeight;
241 std::unique_ptr<tools::Long[]> pMapX(new tools::Long[ nSrcWidth + 1 ]);
242 std::unique_ptr<tools::Long[]> pMapY(new tools::Long[ nSrcHeight + 1 ]);
243 const bool bOldMap = mbMap;
245 mbMap = false;
247 // create forward mapping tables
248 for( nX = 0; nX <= nSrcWidth; nX++ )
249 pMapX[ nX ] = aDestPt.X() + FRound( static_cast<double>(aDestSz.Width()) * nX / nSrcWidth );
251 for( nY = 0; nY <= nSrcHeight; nY++ )
252 pMapY[ nY ] = aDestPt.Y() + FRound( static_cast<double>(aDestSz.Height()) * nY / nSrcHeight );
254 // walk through all rectangles of mask
255 const vcl::Region aWorkRgn(aMask.CreateRegion(COL_BLACK, tools::Rectangle(Point(), aMask.GetSizePixel())));
256 RectangleVector aRectangles;
257 aWorkRgn.GetRegionRectangles(aRectangles);
259 for (auto const& rectangle : aRectangles)
261 const Point aMapPt(pMapX[rectangle.Left()], pMapY[rectangle.Top()]);
262 const Size aMapSz( pMapX[rectangle.Right() + 1] - aMapPt.X(), // pMapX[L + W] -> L + ((R - L) + 1) -> R + 1
263 pMapY[rectangle.Bottom() + 1] - aMapPt.Y()); // same for Y
264 Bitmap aBandBmp(aPaint);
266 aBandBmp.Crop(rectangle);
267 DrawBitmap(aMapPt, aMapSz, Point(), aBandBmp.GetSizePixel(), aBandBmp);
270 mbMap = bOldMap;
274 bool Printer::DrawTransformBitmapExDirect(
275 const basegfx::B2DHomMatrix& /*aFullTransform*/,
276 const BitmapEx& /*rBitmapEx*/,
277 double /*fAlpha*/)
279 // printers can't draw bitmaps directly
280 return false;
283 bool Printer::TransformAndReduceBitmapExToTargetRange(
284 const basegfx::B2DHomMatrix& /*aFullTransform*/,
285 basegfx::B2DRange& /*aVisibleRange*/,
286 double& /*fMaximumArea*/)
288 // deliberately do nothing - you can't reduce the
289 // target range for a printer at all
290 return true;
293 void Printer::DrawDeviceBitmap( const Point& rDestPt, const Size& rDestSize,
294 const Point& rSrcPtPixel, const Size& rSrcSizePixel,
295 BitmapEx& rBmpEx )
297 if( rBmpEx.IsAlpha() )
299 // #107169# For true alpha bitmaps, no longer masking the
300 // bitmap, but perform a full alpha blend against a white
301 // background here.
302 Bitmap aBmp( rBmpEx.GetBitmap() );
303 aBmp.Blend( rBmpEx.GetAlpha(), COL_WHITE );
304 DrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, aBmp );
306 else
308 Bitmap aBmp( rBmpEx.GetBitmap() );
309 ImplPrintTransparent( aBmp, Bitmap(), rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel );
313 void Printer::EmulateDrawTransparent ( const tools::PolyPolygon& rPolyPoly,
314 sal_uInt16 nTransparencePercent )
316 // #110958# Disable alpha VDev, we perform the necessary
317 VirtualDevice* pOldAlphaVDev = mpAlphaVDev;
319 // operation explicitly further below.
320 if( mpAlphaVDev )
321 mpAlphaVDev = nullptr;
323 GDIMetaFile* pOldMetaFile = mpMetaFile;
324 mpMetaFile = nullptr;
326 mpMetaFile = pOldMetaFile;
328 // #110958# Restore disabled alpha VDev
329 mpAlphaVDev = pOldAlphaVDev;
331 tools::Rectangle aPolyRect( LogicToPixel( rPolyPoly ).GetBoundRect() );
332 const Size aDPISize( LogicToPixel(Size(1, 1), MapMode(MapUnit::MapInch)) );
333 const tools::Long nBaseExtent = std::max<tools::Long>( FRound( aDPISize.Width() / 300. ), 1 );
334 tools::Long nMove;
335 const sal_uInt16 nTrans = ( nTransparencePercent < 13 ) ? 0 :
336 ( nTransparencePercent < 38 ) ? 25 :
337 ( nTransparencePercent < 63 ) ? 50 :
338 ( nTransparencePercent < 88 ) ? 75 : 100;
340 switch( nTrans )
342 case 25: nMove = nBaseExtent * 3; break;
343 case 50: nMove = nBaseExtent * 4; break;
344 case 75: nMove = nBaseExtent * 6; break;
346 // #i112959# very transparent (88 < nTransparencePercent <= 99)
347 case 100: nMove = nBaseExtent * 8; break;
349 // #i112959# not transparent (nTransparencePercent < 13)
350 default: nMove = 0; break;
353 Push( PushFlags::CLIPREGION | PushFlags::LINECOLOR );
354 IntersectClipRegion(vcl::Region(rPolyPoly));
355 SetLineColor( GetFillColor() );
356 const bool bOldMap = mbMap;
357 EnableMapMode( false );
359 if(nMove)
361 tools::Rectangle aRect( aPolyRect.TopLeft(), Size( aPolyRect.GetWidth(), nBaseExtent ) );
362 while( aRect.Top() <= aPolyRect.Bottom() )
364 DrawRect( aRect );
365 aRect.Move( 0, nMove );
368 aRect = tools::Rectangle( aPolyRect.TopLeft(), Size( nBaseExtent, aPolyRect.GetHeight() ) );
369 while( aRect.Left() <= aPolyRect.Right() )
371 DrawRect( aRect );
372 aRect.Move( nMove, 0 );
375 else
377 // #i112959# if not transparent, draw full rectangle in clip region
378 DrawRect( aPolyRect );
381 EnableMapMode( bOldMap );
382 Pop();
384 mpMetaFile = pOldMetaFile;
386 // #110958# Restore disabled alpha VDev
387 mpAlphaVDev = pOldAlphaVDev;
390 void Printer::DrawOutDev( const Point& /*rDestPt*/, const Size& /*rDestSize*/,
391 const Point& /*rSrcPt*/, const Size& /*rSrcSize*/ )
393 SAL_WARN( "vcl.gdi", "Don't use OutputDevice::DrawOutDev(...) with printer devices!" );
396 void Printer::DrawOutDev( const Point& /*rDestPt*/, const Size& /*rDestSize*/,
397 const Point& /*rSrcPt*/, const Size& /*rSrcSize*/,
398 const OutputDevice& /*rOutDev*/ )
400 SAL_WARN( "vcl.gdi", "Don't use OutputDevice::DrawOutDev(...) with printer devices!" );
403 void Printer::CopyArea( const Point& /*rDestPt*/,
404 const Point& /*rSrcPt*/, const Size& /*rSrcSize*/,
405 bool /*bWindowInvalidate*/ )
407 SAL_WARN( "vcl.gdi", "Don't use OutputDevice::CopyArea(...) with printer devices!" );
410 tools::Rectangle Printer::GetBackgroundComponentBounds() const
412 Point aPageOffset = Point( 0, 0 ) - this->GetPageOffsetPixel();
413 Size aSize = this->GetPaperSizePixel();
414 return tools::Rectangle( aPageOffset, aSize );
417 void Printer::SetPrinterOptions( const PrinterOptions& i_rOptions )
419 *mpPrinterOptions = i_rOptions;
422 bool Printer::HasMirroredGraphics() const
424 // due to a "hotfix" for AOO bug i55719, this needs to return false
425 return false;
428 SalPrinterQueueInfo::SalPrinterQueueInfo()
430 mnStatus = PrintQueueFlags::NONE;
431 mnJobs = QUEUE_JOBS_DONTKNOW;
434 SalPrinterQueueInfo::~SalPrinterQueueInfo()
438 ImplPrnQueueList::~ImplPrnQueueList()
442 void ImplPrnQueueList::Add( std::unique_ptr<SalPrinterQueueInfo> pData )
444 std::unordered_map< OUString, sal_Int32 >::iterator it =
445 m_aNameToIndex.find( pData->maPrinterName );
446 if( it == m_aNameToIndex.end() )
448 m_aNameToIndex[ pData->maPrinterName ] = m_aQueueInfos.size();
449 m_aPrinterList.push_back( pData->maPrinterName );
450 m_aQueueInfos.push_back( ImplPrnQueueData() );
451 m_aQueueInfos.back().mpQueueInfo = nullptr;
452 m_aQueueInfos.back().mpSalQueueInfo = std::move(pData);
454 else // this should not happen, but ...
456 ImplPrnQueueData& rData = m_aQueueInfos[ it->second ];
457 rData.mpQueueInfo.reset();
458 rData.mpSalQueueInfo = std::move(pData);
462 ImplPrnQueueData* ImplPrnQueueList::Get( const OUString& rPrinter )
464 ImplPrnQueueData* pData = nullptr;
465 std::unordered_map<OUString,sal_Int32>::iterator it =
466 m_aNameToIndex.find( rPrinter );
467 if( it != m_aNameToIndex.end() )
468 pData = &m_aQueueInfos[it->second];
469 return pData;
472 static void ImplInitPrnQueueList()
474 ImplSVData* pSVData = ImplGetSVData();
476 pSVData->maGDIData.mpPrinterQueueList.reset(new ImplPrnQueueList);
478 static const char* pEnv = getenv( "SAL_DISABLE_PRINTERLIST" );
479 if( !pEnv || !*pEnv )
480 pSVData->mpDefInst->GetPrinterQueueInfo( pSVData->maGDIData.mpPrinterQueueList.get() );
483 void ImplDeletePrnQueueList()
485 ImplSVData* pSVData = ImplGetSVData();
486 pSVData->maGDIData.mpPrinterQueueList.reset();
489 const std::vector<OUString>& Printer::GetPrinterQueues()
491 ImplSVData* pSVData = ImplGetSVData();
492 if ( !pSVData->maGDIData.mpPrinterQueueList )
493 ImplInitPrnQueueList();
494 return pSVData->maGDIData.mpPrinterQueueList->m_aPrinterList;
497 const QueueInfo* Printer::GetQueueInfo( const OUString& rPrinterName, bool bStatusUpdate )
499 ImplSVData* pSVData = ImplGetSVData();
501 if ( !pSVData->maGDIData.mpPrinterQueueList )
502 ImplInitPrnQueueList();
504 if ( !pSVData->maGDIData.mpPrinterQueueList )
505 return nullptr;
507 ImplPrnQueueData* pInfo = pSVData->maGDIData.mpPrinterQueueList->Get( rPrinterName );
508 if( pInfo )
510 if( !pInfo->mpQueueInfo || bStatusUpdate )
511 pSVData->mpDefInst->GetPrinterQueueState( pInfo->mpSalQueueInfo.get() );
513 if ( !pInfo->mpQueueInfo )
514 pInfo->mpQueueInfo.reset(new QueueInfo);
516 pInfo->mpQueueInfo->maPrinterName = pInfo->mpSalQueueInfo->maPrinterName;
517 pInfo->mpQueueInfo->maDriver = pInfo->mpSalQueueInfo->maDriver;
518 pInfo->mpQueueInfo->maLocation = pInfo->mpSalQueueInfo->maLocation;
519 pInfo->mpQueueInfo->maComment = pInfo->mpSalQueueInfo->maComment;
520 pInfo->mpQueueInfo->mnStatus = pInfo->mpSalQueueInfo->mnStatus;
521 pInfo->mpQueueInfo->mnJobs = pInfo->mpSalQueueInfo->mnJobs;
522 return pInfo->mpQueueInfo.get();
524 return nullptr;
527 OUString Printer::GetDefaultPrinterName()
529 static const char* pEnv = getenv( "SAL_DISABLE_DEFAULTPRINTER" );
530 if( !pEnv || !*pEnv )
532 ImplSVData* pSVData = ImplGetSVData();
534 return pSVData->mpDefInst->GetDefaultPrinter();
536 return OUString();
539 void Printer::ImplInitData()
541 mbDevOutput = false;
542 mbDefPrinter = false;
543 mnError = ERRCODE_NONE;
544 mnPageQueueSize = 0;
545 mnCopyCount = 1;
546 mbCollateCopy = false;
547 mbPrinting = false;
548 mbJobActive = false;
549 mbPrintFile = false;
550 mbInPrintPage = false;
551 mbNewJobSetup = false;
552 mbSinglePrintJobs = false;
553 mpInfoPrinter = nullptr;
554 mpPrinter = nullptr;
555 mpDisplayDev = nullptr;
556 mpPrinterOptions.reset(new PrinterOptions);
558 // Add printer to the list
559 ImplSVData* pSVData = ImplGetSVData();
560 mpNext = pSVData->maGDIData.mpFirstPrinter;
561 mpPrev = nullptr;
562 if ( mpNext )
563 mpNext->mpPrev = this;
564 pSVData->maGDIData.mpFirstPrinter = this;
567 bool Printer::AcquireGraphics() const
569 DBG_TESTSOLARMUTEX();
571 if ( mpGraphics )
572 return true;
574 mbInitLineColor = true;
575 mbInitFillColor = true;
576 mbInitFont = true;
577 mbInitTextColor = true;
578 mbInitClipRegion = true;
580 ImplSVData* pSVData = ImplGetSVData();
582 if ( mpJobGraphics )
583 mpGraphics = mpJobGraphics;
584 else if ( mpDisplayDev )
586 const VirtualDevice* pVirDev = mpDisplayDev;
587 mpGraphics = pVirDev->mpVirDev->AcquireGraphics();
588 // if needed retry after releasing least recently used virtual device graphics
589 while ( !mpGraphics )
591 if ( !pSVData->maGDIData.mpLastVirGraphics )
592 break;
593 pSVData->maGDIData.mpLastVirGraphics->ReleaseGraphics();
594 mpGraphics = pVirDev->mpVirDev->AcquireGraphics();
596 // update global LRU list of virtual device graphics
597 if ( mpGraphics )
599 mpNextGraphics = pSVData->maGDIData.mpFirstVirGraphics;
600 pSVData->maGDIData.mpFirstVirGraphics = const_cast<Printer*>(this);
601 if ( mpNextGraphics )
602 mpNextGraphics->mpPrevGraphics = const_cast<Printer*>(this);
603 if ( !pSVData->maGDIData.mpLastVirGraphics )
604 pSVData->maGDIData.mpLastVirGraphics = const_cast<Printer*>(this);
607 else
609 mpGraphics = mpInfoPrinter->AcquireGraphics();
610 // if needed retry after releasing least recently used printer graphics
611 while ( !mpGraphics )
613 if ( !pSVData->maGDIData.mpLastPrnGraphics )
614 break;
615 pSVData->maGDIData.mpLastPrnGraphics->ReleaseGraphics();
616 mpGraphics = mpInfoPrinter->AcquireGraphics();
618 // update global LRU list of printer graphics
619 if ( mpGraphics )
621 mpNextGraphics = pSVData->maGDIData.mpFirstPrnGraphics;
622 pSVData->maGDIData.mpFirstPrnGraphics = const_cast<Printer*>(this);
623 if ( mpNextGraphics )
624 mpNextGraphics->mpPrevGraphics = const_cast<Printer*>(this);
625 if ( !pSVData->maGDIData.mpLastPrnGraphics )
626 pSVData->maGDIData.mpLastPrnGraphics = const_cast<Printer*>(this);
630 if ( mpGraphics )
632 mpGraphics->SetXORMode( (RasterOp::Invert == meRasterOp) || (RasterOp::Xor == meRasterOp), RasterOp::Invert == meRasterOp );
633 mpGraphics->setAntiAlias(bool(mnAntialiasing & AntialiasingFlags::Enable));
636 return mpGraphics != nullptr;
639 void Printer::ImplReleaseFonts()
641 #ifdef UNX
642 // HACK to fix an urgent P1 printing issue fast
643 // WinSalPrinter does not respect GetGraphics/ReleaseGraphics conventions
644 // so Printer::mpGraphics often points to a dead WinSalGraphics
645 // TODO: fix WinSalPrinter's GetGraphics/ReleaseGraphics handling
646 mpGraphics->ReleaseFonts();
647 #endif
648 mbNewFont = true;
649 mbInitFont = true;
651 mpFontInstance.clear();
652 mpDeviceFontList.reset();
653 mpDeviceFontSizeList.reset();
656 void Printer::ReleaseGraphics( bool bRelease )
658 DBG_TESTSOLARMUTEX();
660 if ( !mpGraphics )
661 return;
663 // release the fonts of the physically released graphics device
664 if( bRelease )
665 ImplReleaseFonts();
667 ImplSVData* pSVData = ImplGetSVData();
669 Printer* pPrinter = this;
671 if ( !pPrinter->mpJobGraphics )
673 if ( pPrinter->mpDisplayDev )
675 VirtualDevice* pVirDev = pPrinter->mpDisplayDev;
676 if ( bRelease )
677 pVirDev->mpVirDev->ReleaseGraphics( mpGraphics );
678 // remove from global LRU list of virtual device graphics
679 if ( mpPrevGraphics )
680 mpPrevGraphics->mpNextGraphics = mpNextGraphics;
681 else
682 pSVData->maGDIData.mpFirstVirGraphics = mpNextGraphics;
683 if ( mpNextGraphics )
684 mpNextGraphics->mpPrevGraphics = mpPrevGraphics;
685 else
686 pSVData->maGDIData.mpLastVirGraphics = mpPrevGraphics;
688 else
690 if ( bRelease )
691 pPrinter->mpInfoPrinter->ReleaseGraphics( mpGraphics );
692 // remove from global LRU list of printer graphics
693 if ( mpPrevGraphics )
694 mpPrevGraphics->mpNextGraphics = mpNextGraphics;
695 else
696 pSVData->maGDIData.mpFirstPrnGraphics = static_cast<Printer*>(mpNextGraphics.get());
697 if ( mpNextGraphics )
698 mpNextGraphics->mpPrevGraphics = mpPrevGraphics;
699 else
700 pSVData->maGDIData.mpLastPrnGraphics = static_cast<Printer*>(mpPrevGraphics.get());
704 mpGraphics = nullptr;
705 mpPrevGraphics = nullptr;
706 mpNextGraphics = nullptr;
709 void Printer::ImplInit( SalPrinterQueueInfo* pInfo )
711 ImplSVData* pSVData = ImplGetSVData();
712 // #i74084# update info for this specific SalPrinterQueueInfo
713 pSVData->mpDefInst->GetPrinterQueueState( pInfo );
715 // Test whether the driver actually matches the JobSetup
716 ImplJobSetup& rData = maJobSetup.ImplGetData();
717 if ( rData.GetDriverData() )
719 if ( rData.GetPrinterName() != pInfo->maPrinterName ||
720 rData.GetDriver() != pInfo->maDriver )
722 std::free( const_cast<sal_uInt8*>(rData.GetDriverData()) );
723 rData.SetDriverData(nullptr);
724 rData.SetDriverDataLen(0);
728 // Remember printer name
729 maPrinterName = pInfo->maPrinterName;
730 maDriver = pInfo->maDriver;
732 // Add printer name to JobSetup
733 rData.SetPrinterName( maPrinterName );
734 rData.SetDriver( maDriver );
736 mpInfoPrinter = pSVData->mpDefInst->CreateInfoPrinter( pInfo, &rData );
737 mpPrinter = nullptr;
738 mpJobGraphics = nullptr;
739 ImplUpdateJobSetupPaper( maJobSetup );
741 if ( !mpInfoPrinter )
743 ImplInitDisplay();
744 return;
747 // we need a graphics
748 if ( !AcquireGraphics() )
750 ImplInitDisplay();
751 return;
754 // Init data
755 ImplUpdatePageData();
756 mxFontCollection = std::make_shared<PhysicalFontCollection>();
757 mxFontCache = std::make_shared<ImplFontCache>();
758 mpGraphics->GetDevFontList(mxFontCollection.get());
761 void Printer::ImplInitDisplay()
763 ImplSVData* pSVData = ImplGetSVData();
765 mpInfoPrinter = nullptr;
766 mpPrinter = nullptr;
767 mpJobGraphics = nullptr;
769 mpDisplayDev = VclPtr<VirtualDevice>::Create();
770 mxFontCollection = pSVData->maGDIData.mxScreenFontList;
771 mxFontCache = pSVData->maGDIData.mxScreenFontCache;
772 mnDPIX = mpDisplayDev->mnDPIX;
773 mnDPIY = mpDisplayDev->mnDPIY;
776 void Printer::DrawDeviceMask( const Bitmap& rMask, const Color& rMaskColor,
777 const Point& rDestPt, const Size& rDestSize,
778 const Point& rSrcPtPixel, const Size& rSrcSizePixel )
780 Point aDestPt( LogicToPixel( rDestPt ) );
781 Size aDestSz( LogicToPixel( rDestSize ) );
782 tools::Rectangle aSrcRect( rSrcPtPixel, rSrcSizePixel );
784 aSrcRect.Justify();
786 if( !(!rMask.IsEmpty() && aSrcRect.GetWidth() && aSrcRect.GetHeight() && aDestSz.Width() && aDestSz.Height()) )
787 return;
789 Bitmap aMask( rMask );
790 BmpMirrorFlags nMirrFlags = BmpMirrorFlags::NONE;
792 if (aMask.getPixelFormat() > vcl::PixelFormat::N1_BPP)
793 aMask.Convert( BmpConversion::N1BitThreshold );
795 // mirrored horizontally
796 if( aDestSz.Width() < 0 )
798 aDestSz.setWidth( -aDestSz.Width() );
799 aDestPt.AdjustX( -( aDestSz.Width() - 1 ) );
800 nMirrFlags |= BmpMirrorFlags::Horizontal;
803 // mirrored vertically
804 if( aDestSz.Height() < 0 )
806 aDestSz.setHeight( -aDestSz.Height() );
807 aDestPt.AdjustY( -( aDestSz.Height() - 1 ) );
808 nMirrFlags |= BmpMirrorFlags::Vertical;
811 // source cropped?
812 if( aSrcRect != tools::Rectangle( Point(), aMask.GetSizePixel() ) )
813 aMask.Crop( aSrcRect );
815 // destination mirrored
816 if( nMirrFlags != BmpMirrorFlags::NONE)
817 aMask.Mirror( nMirrFlags );
819 // do painting
820 const tools::Long nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight();
821 tools::Long nX, nY; //, nWorkX, nWorkY, nWorkWidth, nWorkHeight;
822 std::unique_ptr<tools::Long[]> pMapX( new tools::Long[ nSrcWidth + 1 ] );
823 std::unique_ptr<tools::Long[]> pMapY( new tools::Long[ nSrcHeight + 1 ] );
824 GDIMetaFile* pOldMetaFile = mpMetaFile;
825 const bool bOldMap = mbMap;
827 mpMetaFile = nullptr;
828 mbMap = false;
829 Push( PushFlags::FILLCOLOR | PushFlags::LINECOLOR );
830 SetLineColor( rMaskColor );
831 SetFillColor( rMaskColor );
832 InitLineColor();
833 InitFillColor();
835 // create forward mapping tables
836 for( nX = 0; nX <= nSrcWidth; nX++ )
837 pMapX[ nX ] = aDestPt.X() + FRound( static_cast<double>(aDestSz.Width()) * nX / nSrcWidth );
839 for( nY = 0; nY <= nSrcHeight; nY++ )
840 pMapY[ nY ] = aDestPt.Y() + FRound( static_cast<double>(aDestSz.Height()) * nY / nSrcHeight );
842 // walk through all rectangles of mask
843 const vcl::Region aWorkRgn(aMask.CreateRegion(COL_BLACK, tools::Rectangle(Point(), aMask.GetSizePixel())));
844 RectangleVector aRectangles;
845 aWorkRgn.GetRegionRectangles(aRectangles);
847 for (auto const& rectangle : aRectangles)
849 const Point aMapPt(pMapX[rectangle.Left()], pMapY[rectangle.Top()]);
850 const Size aMapSz(
851 pMapX[rectangle.Right() + 1] - aMapPt.X(), // pMapX[L + W] -> L + ((R - L) + 1) -> R + 1
852 pMapY[rectangle.Bottom() + 1] - aMapPt.Y()); // same for Y
854 DrawRect(tools::Rectangle(aMapPt, aMapSz));
857 Pop();
858 mbMap = bOldMap;
859 mpMetaFile = pOldMetaFile;
862 SalPrinterQueueInfo* Printer::ImplGetQueueInfo( const OUString& rPrinterName,
863 const OUString* pDriver )
865 ImplSVData* pSVData = ImplGetSVData();
866 if ( !pSVData->maGDIData.mpPrinterQueueList )
867 ImplInitPrnQueueList();
869 ImplPrnQueueList* pPrnList = pSVData->maGDIData.mpPrinterQueueList.get();
870 if ( pPrnList && !pPrnList->m_aQueueInfos.empty() )
872 // first search for the printer name directly
873 ImplPrnQueueData* pInfo = pPrnList->Get( rPrinterName );
874 if( pInfo )
875 return pInfo->mpSalQueueInfo.get();
877 // then search case insensitive
878 for(const ImplPrnQueueData & rQueueInfo : pPrnList->m_aQueueInfos)
880 if( rQueueInfo.mpSalQueueInfo->maPrinterName.equalsIgnoreAsciiCase( rPrinterName ) )
881 return rQueueInfo.mpSalQueueInfo.get();
884 // then search for driver name
885 if ( pDriver )
887 for(const ImplPrnQueueData & rQueueInfo : pPrnList->m_aQueueInfos)
889 if( rQueueInfo.mpSalQueueInfo->maDriver == *pDriver )
890 return rQueueInfo.mpSalQueueInfo.get();
894 // then the default printer
895 pInfo = pPrnList->Get( GetDefaultPrinterName() );
896 if( pInfo )
897 return pInfo->mpSalQueueInfo.get();
899 // last chance: the first available printer
900 return pPrnList->m_aQueueInfos[0].mpSalQueueInfo.get();
903 return nullptr;
906 void Printer::ImplUpdatePageData()
908 // we need a graphics
909 if ( !AcquireGraphics() )
910 return;
912 mpGraphics->GetResolution( mnDPIX, mnDPIY );
913 mpInfoPrinter->GetPageInfo( &maJobSetup.ImplGetConstData(),
914 mnOutWidth, mnOutHeight,
915 maPageOffset,
916 maPaperSize );
919 void Printer::ImplUpdateFontList()
921 ImplUpdateFontData();
924 tools::Long Printer::GetGradientStepCount( tools::Long nMinRect )
926 // use display-equivalent step size calculation
927 tools::Long nInc = (nMinRect < 800) ? 10 : 20;
929 return nInc;
932 Printer::Printer()
933 : OutputDevice(OUTDEV_PRINTER)
935 ImplInitData();
936 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( GetDefaultPrinterName(), nullptr );
937 if ( pInfo )
939 ImplInit( pInfo );
940 if ( !IsDisplayPrinter() )
941 mbDefPrinter = true;
943 else
944 ImplInitDisplay();
947 Printer::Printer( const JobSetup& rJobSetup )
948 : OutputDevice(OUTDEV_PRINTER)
949 , maJobSetup(rJobSetup)
951 ImplInitData();
952 const ImplJobSetup& rConstData = rJobSetup.ImplGetConstData();
953 OUString aDriver = rConstData.GetDriver();
954 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( rConstData.GetPrinterName(),
955 &aDriver );
956 if ( pInfo )
958 ImplInit( pInfo );
959 SetJobSetup( rJobSetup );
961 else
963 ImplInitDisplay();
964 maJobSetup = JobSetup();
968 Printer::Printer( const QueueInfo& rQueueInfo )
969 : OutputDevice(OUTDEV_PRINTER)
971 ImplInitData();
972 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( rQueueInfo.GetPrinterName(),
973 &rQueueInfo.GetDriver() );
974 if ( pInfo )
975 ImplInit( pInfo );
976 else
977 ImplInitDisplay();
980 Printer::Printer( const OUString& rPrinterName )
981 : OutputDevice(OUTDEV_PRINTER)
983 ImplInitData();
984 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( rPrinterName, nullptr );
985 if ( pInfo )
986 ImplInit( pInfo );
987 else
988 ImplInitDisplay();
991 Printer::~Printer()
993 disposeOnce();
996 void Printer::dispose()
998 SAL_WARN_IF( IsPrinting(), "vcl.gdi", "Printer::~Printer() - Job is printing" );
999 SAL_WARN_IF( IsJobActive(), "vcl.gdi", "Printer::~Printer() - Job is active" );
1001 mpPrinterOptions.reset();
1003 ReleaseGraphics();
1004 if ( mpInfoPrinter )
1005 ImplGetSVData()->mpDefInst->DestroyInfoPrinter( mpInfoPrinter );
1006 if ( mpDisplayDev )
1007 mpDisplayDev.disposeAndClear();
1008 else
1010 // OutputDevice Dtor is trying the same thing; that why we need to set
1011 // the FontEntry to NULL here
1012 // TODO: consolidate duplicate cleanup by Printer and OutputDevice
1013 mpFontInstance.clear();
1014 mpDeviceFontList.reset();
1015 mpDeviceFontSizeList.reset();
1016 mxFontCache.reset();
1017 // font list deleted by OutputDevice dtor
1020 // Add printer from the list
1021 ImplSVData* pSVData = ImplGetSVData();
1022 if ( mpPrev )
1023 mpPrev->mpNext = mpNext;
1024 else
1025 pSVData->maGDIData.mpFirstPrinter = mpNext;
1026 if ( mpNext )
1027 mpNext->mpPrev = mpPrev;
1029 mpPrev.clear();
1030 mpNext.clear();
1031 OutputDevice::dispose();
1034 Size Printer::GetButtonBorderSize()
1036 Size aBrdSize(LogicToPixel(Size(20, 20), MapMode(MapUnit::Map100thMM)));
1038 if (!aBrdSize.Width())
1039 aBrdSize.setWidth(1);
1041 if (!aBrdSize.Height())
1042 aBrdSize.setHeight(1);
1044 return aBrdSize;
1047 sal_uInt32 Printer::GetCapabilities( PrinterCapType nType ) const
1049 if ( IsDisplayPrinter() )
1050 return 0;
1052 if( mpInfoPrinter )
1053 return mpInfoPrinter->GetCapabilities( &maJobSetup.ImplGetConstData(), nType );
1054 else
1055 return 0;
1058 bool Printer::HasSupport( PrinterSupport eFeature ) const
1060 switch ( eFeature )
1062 case PrinterSupport::SetOrientation:
1063 return GetCapabilities( PrinterCapType::SetOrientation ) != 0;
1064 case PrinterSupport::SetPaperSize:
1065 return GetCapabilities( PrinterCapType::SetPaperSize ) != 0;
1066 case PrinterSupport::SetPaper:
1067 return GetCapabilities( PrinterCapType::SetPaper ) != 0;
1068 case PrinterSupport::CollateCopy:
1069 return (GetCapabilities( PrinterCapType::CollateCopies ) != 0);
1070 case PrinterSupport::SetupDialog:
1071 return GetCapabilities( PrinterCapType::SupportDialog ) != 0;
1074 return true;
1077 bool Printer::SetJobSetup( const JobSetup& rSetup )
1079 if ( IsDisplayPrinter() || mbInPrintPage )
1080 return false;
1082 JobSetup aJobSetup = rSetup;
1084 ReleaseGraphics();
1085 if ( mpInfoPrinter->SetPrinterData( &aJobSetup.ImplGetData() ) )
1087 ImplUpdateJobSetupPaper( aJobSetup );
1088 mbNewJobSetup = true;
1089 maJobSetup = aJobSetup;
1090 ImplUpdatePageData();
1091 ImplUpdateFontList();
1092 return true;
1095 return false;
1098 bool Printer::Setup(weld::Window* pWindow, PrinterSetupMode eMode)
1100 if ( IsDisplayPrinter() )
1101 return false;
1103 if ( IsJobActive() || IsPrinting() )
1104 return false;
1106 JobSetup aJobSetup = maJobSetup;
1107 ImplJobSetup& rData = aJobSetup.ImplGetData();
1108 rData.SetPrinterSetupMode( eMode );
1109 // TODO: orig page size
1111 if (!pWindow)
1113 vcl::Window* pDefWin = ImplGetDefaultWindow();
1114 pWindow = pDefWin ? pDefWin->GetFrameWeld() : nullptr;
1116 if( !pWindow )
1117 return false;
1119 ReleaseGraphics();
1120 ImplSVData* pSVData = ImplGetSVData();
1121 pSVData->maAppData.mnModalMode++;
1122 nImplSysDialog++;
1123 bool bSetup = mpInfoPrinter->Setup(pWindow, &rData);
1124 pSVData->maAppData.mnModalMode--;
1125 nImplSysDialog--;
1126 if ( bSetup )
1128 ImplUpdateJobSetupPaper( aJobSetup );
1129 mbNewJobSetup = true;
1130 maJobSetup = aJobSetup;
1131 ImplUpdatePageData();
1132 ImplUpdateFontList();
1133 return true;
1135 return false;
1138 bool Printer::SetPrinterProps( const Printer* pPrinter )
1140 if ( IsJobActive() || IsPrinting() )
1141 return false;
1143 ImplSVData* pSVData = ImplGetSVData();
1145 mbDefPrinter = pPrinter->mbDefPrinter;
1146 maPrintFile = pPrinter->maPrintFile;
1147 mbPrintFile = pPrinter->mbPrintFile;
1148 mnCopyCount = pPrinter->mnCopyCount;
1149 mbCollateCopy = pPrinter->mbCollateCopy;
1150 mnPageQueueSize = pPrinter->mnPageQueueSize;
1151 *mpPrinterOptions = *pPrinter->mpPrinterOptions;
1153 if ( pPrinter->IsDisplayPrinter() )
1155 // Destroy old printer
1156 if ( !IsDisplayPrinter() )
1158 ReleaseGraphics();
1159 pSVData->mpDefInst->DestroyInfoPrinter( mpInfoPrinter );
1160 mpFontInstance.clear();
1161 mpDeviceFontList.reset();
1162 mpDeviceFontSizeList.reset();
1163 // clean up font list
1164 mxFontCache.reset();
1165 mxFontCollection.reset();
1167 mbInitFont = true;
1168 mbNewFont = true;
1169 mpInfoPrinter = nullptr;
1172 // Construct new printer
1173 ImplInitDisplay();
1174 return true;
1177 // Destroy old printer?
1178 if ( GetName() != pPrinter->GetName() )
1180 ReleaseGraphics();
1181 if ( mpDisplayDev )
1183 mpDisplayDev.disposeAndClear();
1185 else
1187 pSVData->mpDefInst->DestroyInfoPrinter( mpInfoPrinter );
1189 mpFontInstance.clear();
1190 mpDeviceFontList.reset();
1191 mpDeviceFontSizeList.reset();
1192 mxFontCache.reset();
1193 mxFontCollection.reset();
1194 mbInitFont = true;
1195 mbNewFont = true;
1196 mpInfoPrinter = nullptr;
1199 // Construct new printer
1200 OUString aDriver = pPrinter->GetDriverName();
1201 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( pPrinter->GetName(), &aDriver );
1202 if ( pInfo )
1204 ImplInit( pInfo );
1205 SetJobSetup( pPrinter->GetJobSetup() );
1207 else
1208 ImplInitDisplay();
1210 else
1211 SetJobSetup( pPrinter->GetJobSetup() );
1213 return false;
1216 bool Printer::SetOrientation( Orientation eOrientation )
1218 if ( mbInPrintPage )
1219 return false;
1221 if ( maJobSetup.ImplGetConstData().GetOrientation() != eOrientation )
1223 JobSetup aJobSetup = maJobSetup;
1224 ImplJobSetup& rData = aJobSetup.ImplGetData();
1226 rData.SetOrientation(eOrientation);
1228 if ( IsDisplayPrinter() )
1230 mbNewJobSetup = true;
1231 maJobSetup = aJobSetup;
1232 return true;
1235 ReleaseGraphics();
1236 if ( mpInfoPrinter->SetData( JobSetFlags::ORIENTATION, &rData ) )
1238 ImplUpdateJobSetupPaper( aJobSetup );
1239 mbNewJobSetup = true;
1240 maJobSetup = aJobSetup;
1241 ImplUpdatePageData();
1242 ImplUpdateFontList();
1243 return true;
1245 else
1246 return false;
1249 return true;
1252 Orientation Printer::GetOrientation() const
1254 return maJobSetup.ImplGetConstData().GetOrientation();
1257 bool Printer::SetPaperBin( sal_uInt16 nPaperBin )
1259 if ( mbInPrintPage )
1260 return false;
1262 if ( maJobSetup.ImplGetConstData().GetPaperBin() != nPaperBin &&
1263 nPaperBin < GetPaperBinCount() )
1265 JobSetup aJobSetup = maJobSetup;
1266 ImplJobSetup& rData = aJobSetup.ImplGetData();
1267 rData.SetPaperBin(nPaperBin);
1269 if ( IsDisplayPrinter() )
1271 mbNewJobSetup = true;
1272 maJobSetup = aJobSetup;
1273 return true;
1276 ReleaseGraphics();
1277 if ( mpInfoPrinter->SetData( JobSetFlags::PAPERBIN, &rData ) )
1279 ImplUpdateJobSetupPaper( aJobSetup );
1280 mbNewJobSetup = true;
1281 maJobSetup = aJobSetup;
1282 ImplUpdatePageData();
1283 ImplUpdateFontList();
1284 return true;
1286 else
1287 return false;
1290 return true;
1293 sal_uInt16 Printer::GetPaperBin() const
1295 return maJobSetup.ImplGetConstData().GetPaperBin();
1298 bool Printer::GetPrinterSettingsPreferred() const
1300 return maJobSetup.ImplGetConstData().GetPapersizeFromSetup();
1303 // dear loplugins, DO NOT REMOVE this code
1304 // it will be used in follow-up commits
1305 void Printer::SetPrinterSettingsPreferred( bool bPaperSizeFromSetup)
1307 if ( maJobSetup.ImplGetConstData().GetPapersizeFromSetup() != bPaperSizeFromSetup )
1309 JobSetup aJobSetup = maJobSetup;
1310 ImplJobSetup& rData = aJobSetup.ImplGetData();
1311 rData.SetPapersizeFromSetup(bPaperSizeFromSetup);
1313 mbNewJobSetup = true;
1314 maJobSetup = aJobSetup;
1318 // Map user paper format to an available printer paper format
1319 void Printer::ImplFindPaperFormatForUserSize( JobSetup& aJobSetup )
1321 ImplJobSetup& rData = aJobSetup.ImplGetData();
1323 // The angle that a landscape page will be turned counterclockwise wrt to portrait.
1324 int nLandscapeAngle = mpInfoPrinter ? mpInfoPrinter->GetLandscapeAngle( &maJobSetup.ImplGetConstData() ) : 900;
1325 int nPaperCount = GetPaperInfoCount();
1326 PaperInfo aInfo(rData.GetPaperWidth(), rData.GetPaperHeight());
1328 // Compare all paper formats and get the appropriate one
1329 for ( int i = 0; i < nPaperCount; i++ )
1331 const PaperInfo& rPaperInfo = GetPaperInfo( i );
1333 if ( aInfo.sloppyEqual(rPaperInfo) )
1335 rData.SetPaperFormat(
1336 ImplGetPaperFormat( rPaperInfo.getWidth(),
1337 rPaperInfo.getHeight() ));
1338 rData.SetOrientation( Orientation::Portrait );
1339 return;
1343 // If the printer supports landscape orientation, check paper sizes again
1344 // with landscape orientation. This is necessary as a printer driver provides
1345 // all paper sizes with portrait orientation only!!
1346 if ( !(rData.GetPaperFormat() == PAPER_USER &&
1347 nLandscapeAngle != 0 &&
1348 HasSupport( PrinterSupport::SetOrientation )))
1349 return;
1351 const tools::Long nRotatedWidth = rData.GetPaperHeight();
1352 const tools::Long nRotatedHeight = rData.GetPaperWidth();
1353 PaperInfo aRotatedInfo(nRotatedWidth, nRotatedHeight);
1355 for ( int i = 0; i < nPaperCount; i++ )
1357 const PaperInfo& rPaperInfo = GetPaperInfo( i );
1359 if ( aRotatedInfo.sloppyEqual( rPaperInfo ) )
1361 rData.SetPaperFormat(
1362 ImplGetPaperFormat( rPaperInfo.getWidth(),
1363 rPaperInfo.getHeight() ));
1364 rData.SetOrientation( Orientation::Landscape );
1365 return;
1370 void Printer::SetPaper( Paper ePaper )
1372 if ( mbInPrintPage )
1373 return;
1375 if ( maJobSetup.ImplGetConstData().GetPaperFormat() == ePaper )
1376 return;
1378 JobSetup aJobSetup = maJobSetup;
1379 ImplJobSetup& rData = aJobSetup.ImplGetData();
1381 rData.SetPaperFormat( ePaper );
1382 if ( ePaper != PAPER_USER )
1384 PaperInfo aInfo(ePaper);
1385 rData.SetPaperWidth( aInfo.getWidth() );
1386 rData.SetPaperHeight( aInfo.getHeight() );
1389 if ( IsDisplayPrinter() )
1391 mbNewJobSetup = true;
1392 maJobSetup = aJobSetup;
1393 return;
1396 ReleaseGraphics();
1397 if ( ePaper == PAPER_USER )
1398 ImplFindPaperFormatForUserSize( aJobSetup );
1399 if ( mpInfoPrinter->SetData( JobSetFlags::PAPERSIZE | JobSetFlags::ORIENTATION, &rData ))
1401 ImplUpdateJobSetupPaper( aJobSetup );
1402 mbNewJobSetup = true;
1403 maJobSetup = aJobSetup;
1404 ImplUpdatePageData();
1405 ImplUpdateFontList();
1409 bool Printer::SetPaperSizeUser( const Size& rSize )
1411 if ( mbInPrintPage )
1412 return false;
1414 const Size aPixSize = LogicToPixel( rSize );
1415 const Size aPageSize = PixelToLogic(aPixSize, MapMode(MapUnit::Map100thMM));
1416 bool bNeedToChange(maJobSetup.ImplGetConstData().GetPaperWidth() != aPageSize.Width() ||
1417 maJobSetup.ImplGetConstData().GetPaperHeight() != aPageSize.Height());
1419 if(!bNeedToChange)
1421 // #i122984# only need to change when Paper is different from PAPER_USER and
1422 // the mapped Paper which will created below in the call to ImplFindPaperFormatForUserSize
1423 // and will replace maJobSetup.ImplGetConstData()->GetPaperFormat(). This leads to
1424 // unnecessary JobSetups, e.g. when printing a multi-page fax, but also with
1425 // normal print
1426 const Paper aPaper = ImplGetPaperFormat(aPageSize.Width(), aPageSize.Height());
1428 bNeedToChange = maJobSetup.ImplGetConstData().GetPaperFormat() != PAPER_USER &&
1429 maJobSetup.ImplGetConstData().GetPaperFormat() != aPaper;
1432 if(bNeedToChange)
1434 JobSetup aJobSetup = maJobSetup;
1435 ImplJobSetup& rData = aJobSetup.ImplGetData();
1436 rData.SetPaperFormat( PAPER_USER );
1437 rData.SetPaperWidth( aPageSize.Width() );
1438 rData.SetPaperHeight( aPageSize.Height() );
1440 if ( IsDisplayPrinter() )
1442 mbNewJobSetup = true;
1443 maJobSetup = aJobSetup;
1444 return true;
1447 ReleaseGraphics();
1448 ImplFindPaperFormatForUserSize( aJobSetup );
1450 // Changing the paper size can also change the orientation!
1451 if ( mpInfoPrinter->SetData( JobSetFlags::PAPERSIZE | JobSetFlags::ORIENTATION, &rData ))
1453 ImplUpdateJobSetupPaper( aJobSetup );
1454 mbNewJobSetup = true;
1455 maJobSetup = aJobSetup;
1456 ImplUpdatePageData();
1457 ImplUpdateFontList();
1458 return true;
1460 else
1461 return false;
1464 return true;
1467 int Printer::GetPaperInfoCount() const
1469 if( ! mpInfoPrinter )
1470 return 0;
1471 if( ! mpInfoPrinter->m_bPapersInit )
1472 mpInfoPrinter->InitPaperFormats( &maJobSetup.ImplGetConstData() );
1473 return mpInfoPrinter->m_aPaperFormats.size();
1476 OUString Printer::GetPaperName( Paper ePaper )
1478 ImplSVData* pSVData = ImplGetSVData();
1479 if( pSVData->maPaperNames.empty() )
1481 static const int PaperIndex[] =
1483 PAPER_A0, PAPER_A1, PAPER_A2, PAPER_A3, PAPER_A4, PAPER_A5, PAPER_B4_ISO, PAPER_B5_ISO,
1484 PAPER_LETTER, PAPER_LEGAL, PAPER_TABLOID, PAPER_USER, PAPER_B6_ISO, PAPER_ENV_C4, PAPER_ENV_C5,
1485 PAPER_ENV_C6, PAPER_ENV_C65, PAPER_ENV_DL, PAPER_SLIDE_DIA, PAPER_SCREEN_4_3, PAPER_C, PAPER_D,
1486 PAPER_E, PAPER_EXECUTIVE, PAPER_FANFOLD_LEGAL_DE, PAPER_ENV_MONARCH, PAPER_ENV_PERSONAL, PAPER_ENV_9,
1487 PAPER_ENV_10, PAPER_ENV_11, PAPER_ENV_12, PAPER_KAI16, PAPER_KAI32, PAPER_KAI32BIG, PAPER_B4_JIS,
1488 PAPER_B5_JIS, PAPER_B6_JIS, PAPER_LEDGER, PAPER_STATEMENT, PAPER_QUARTO, PAPER_10x14, PAPER_ENV_14,
1489 PAPER_ENV_C3, PAPER_ENV_ITALY, PAPER_FANFOLD_US, PAPER_FANFOLD_DE, PAPER_POSTCARD_JP, PAPER_9x11,
1490 PAPER_10x11, PAPER_15x11, PAPER_ENV_INVITE, PAPER_A_PLUS, PAPER_B_PLUS, PAPER_LETTER_PLUS, PAPER_A4_PLUS,
1491 PAPER_DOUBLEPOSTCARD_JP, PAPER_A6, PAPER_12x11, PAPER_A7, PAPER_A8, PAPER_A9, PAPER_A10, PAPER_B0_ISO,
1492 PAPER_B1_ISO, PAPER_B2_ISO, PAPER_B3_ISO, PAPER_B7_ISO, PAPER_B8_ISO, PAPER_B9_ISO, PAPER_B10_ISO,
1493 PAPER_ENV_C2, PAPER_ENV_C7, PAPER_ENV_C8, PAPER_ARCHA, PAPER_ARCHB, PAPER_ARCHC, PAPER_ARCHD,
1494 PAPER_ARCHE, PAPER_SCREEN_16_9, PAPER_SCREEN_16_10, PAPER_16K_195x270, PAPER_16K_197x273
1496 assert(SAL_N_ELEMENTS(PaperIndex) == SAL_N_ELEMENTS(RID_STR_PAPERNAMES) && "localized paper name count wrong");
1497 for (size_t i = 0; i < SAL_N_ELEMENTS(PaperIndex); ++i)
1498 pSVData->maPaperNames[PaperIndex[i]] = VclResId(RID_STR_PAPERNAMES[i]);
1501 std::unordered_map<int,OUString>::const_iterator it = pSVData->maPaperNames.find( static_cast<int>(ePaper) );
1502 return (it != pSVData->maPaperNames.end()) ? it->second : OUString();
1505 const PaperInfo& Printer::GetPaperInfo( int nPaper ) const
1507 if( ! mpInfoPrinter )
1508 return ImplGetEmptyPaper();
1509 if( ! mpInfoPrinter->m_bPapersInit )
1510 mpInfoPrinter->InitPaperFormats( &maJobSetup.ImplGetConstData() );
1511 if( mpInfoPrinter->m_aPaperFormats.empty() || nPaper < 0 || nPaper >= int(mpInfoPrinter->m_aPaperFormats.size()) )
1512 return ImplGetEmptyPaper();
1513 return mpInfoPrinter->m_aPaperFormats[nPaper];
1516 Size Printer::GetPaperSize( int nPaper )
1518 PaperInfo aInfo = GetPaperInfo( nPaper );
1519 return PixelToLogic( Size( aInfo.getWidth(), aInfo.getHeight() ) );
1522 void Printer::SetDuplexMode( DuplexMode eDuplex )
1524 if ( mbInPrintPage )
1525 return;
1527 if ( maJobSetup.ImplGetConstData().GetDuplexMode() == eDuplex )
1528 return;
1530 JobSetup aJobSetup = maJobSetup;
1531 ImplJobSetup& rData = aJobSetup.ImplGetData();
1533 rData.SetDuplexMode( eDuplex );
1535 if ( IsDisplayPrinter() )
1537 mbNewJobSetup = true;
1538 maJobSetup = aJobSetup;
1539 return;
1542 ReleaseGraphics();
1543 if ( mpInfoPrinter->SetData( JobSetFlags::DUPLEXMODE, &rData ) )
1545 ImplUpdateJobSetupPaper( aJobSetup );
1546 mbNewJobSetup = true;
1547 maJobSetup = aJobSetup;
1548 ImplUpdatePageData();
1549 ImplUpdateFontList();
1553 DuplexMode Printer::GetDuplexMode() const
1555 return maJobSetup.ImplGetConstData().GetDuplexMode();
1558 Paper Printer::GetPaper() const
1560 return maJobSetup.ImplGetConstData().GetPaperFormat();
1563 sal_uInt16 Printer::GetPaperBinCount() const
1565 if ( IsDisplayPrinter() )
1566 return 0;
1568 return mpInfoPrinter->GetPaperBinCount( &maJobSetup.ImplGetConstData() );
1571 OUString Printer::GetPaperBinName( sal_uInt16 nPaperBin ) const
1573 if ( IsDisplayPrinter() )
1574 return OUString();
1576 if ( nPaperBin < GetPaperBinCount() )
1577 return mpInfoPrinter->GetPaperBinName( &maJobSetup.ImplGetConstData(), nPaperBin );
1578 else
1579 return OUString();
1582 void Printer::SetCopyCount( sal_uInt16 nCopy, bool bCollate )
1584 mnCopyCount = nCopy;
1585 mbCollateCopy = bCollate;
1588 ErrCode Printer::ImplSalPrinterErrorCodeToVCL( SalPrinterError nError )
1590 ErrCode nVCLError;
1591 switch ( nError )
1593 case SalPrinterError::NONE:
1594 nVCLError = ERRCODE_NONE;
1595 break;
1596 case SalPrinterError::Abort:
1597 nVCLError = PRINTER_ABORT;
1598 break;
1599 default:
1600 nVCLError = PRINTER_GENERALERROR;
1601 break;
1604 return nVCLError;
1607 void Printer::EndJob()
1609 if ( !IsJobActive() )
1610 return;
1612 SAL_WARN_IF( mbInPrintPage, "vcl.gdi", "Printer::EndJob() - StartPage() without EndPage() called" );
1614 mbJobActive = false;
1616 if ( mpPrinter )
1618 ReleaseGraphics();
1620 mbPrinting = false;
1622 mbDevOutput = false;
1623 mpPrinter->EndJob();
1624 mpPrinter.reset();
1628 void Printer::ImplStartPage()
1630 if ( !IsJobActive() )
1631 return;
1633 if ( !mpPrinter )
1634 return;
1636 SalGraphics* pGraphics = mpPrinter->StartPage( &maJobSetup.ImplGetData(),
1637 mbNewJobSetup );
1638 if ( pGraphics )
1640 ReleaseGraphics();
1641 mpJobGraphics = pGraphics;
1643 mbDevOutput = true;
1645 // PrintJob not aborted ???
1646 if ( IsJobActive() )
1647 mbInPrintPage = true;
1650 void Printer::ImplEndPage()
1652 if ( !IsJobActive() )
1653 return;
1655 mbInPrintPage = false;
1657 if ( mpPrinter )
1659 mpPrinter->EndPage();
1660 ReleaseGraphics();
1661 mbDevOutput = false;
1663 mpJobGraphics = nullptr;
1664 mbNewJobSetup = false;
1668 void Printer::updatePrinters()
1670 ImplSVData* pSVData = ImplGetSVData();
1671 ImplPrnQueueList* pPrnList = pSVData->maGDIData.mpPrinterQueueList.get();
1673 if ( !pPrnList )
1674 return;
1676 std::unique_ptr<ImplPrnQueueList> pNewList(new ImplPrnQueueList);
1677 pSVData->mpDefInst->GetPrinterQueueInfo( pNewList.get() );
1679 bool bChanged = pPrnList->m_aQueueInfos.size() != pNewList->m_aQueueInfos.size();
1680 for( decltype(pPrnList->m_aQueueInfos)::size_type i = 0; ! bChanged && i < pPrnList->m_aQueueInfos.size(); i++ )
1682 ImplPrnQueueData& rInfo = pPrnList->m_aQueueInfos[i];
1683 ImplPrnQueueData& rNewInfo = pNewList->m_aQueueInfos[i];
1684 if( ! rInfo.mpSalQueueInfo || ! rNewInfo.mpSalQueueInfo || // sanity check
1685 rInfo.mpSalQueueInfo->maPrinterName != rNewInfo.mpSalQueueInfo->maPrinterName )
1687 bChanged = true;
1690 if( !bChanged )
1691 return;
1693 ImplDeletePrnQueueList();
1694 pSVData->maGDIData.mpPrinterQueueList = std::move(pNewList);
1696 Application* pApp = GetpApp();
1697 if( pApp )
1699 DataChangedEvent aDCEvt( DataChangedEventType::PRINTER );
1700 Application::ImplCallEventListenersApplicationDataChanged(&aDCEvt);
1701 Application::NotifyAllWindows( aDCEvt );
1705 bool Printer::UsePolyPolygonForComplexGradient()
1707 return true;
1710 void Printer::ClipAndDrawGradientMetafile ( const Gradient &rGradient, const tools::PolyPolygon &rPolyPoly )
1712 const tools::Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
1714 Push( PushFlags::CLIPREGION );
1715 IntersectClipRegion(vcl::Region(rPolyPoly));
1716 DrawGradient( aBoundRect, rGradient );
1717 Pop();
1720 void Printer::SetFontOrientation( LogicalFontInstance* const pFontEntry ) const
1722 pFontEntry->mnOrientation = pFontEntry->mxFontMetric->GetOrientation();
1725 vcl::Region Printer::ClipToDeviceBounds(vcl::Region aRegion) const
1727 return aRegion;
1730 Bitmap Printer::GetBitmap( const Point& rSrcPt, const Size& rSize ) const
1732 SAL_WARN("vcl.gdi", "GetBitmap(): This should never be called on by a Printer instance");
1734 return OutputDevice::GetBitmap( rSrcPt, rSize );
1737 css::awt::DeviceInfo Printer::GetDeviceInfo() const
1739 Size aDevSz = GetPaperSizePixel();
1740 css::awt::DeviceInfo aInfo = GetCommonDeviceInfo(aDevSz);
1741 Size aOutSz = GetOutputSizePixel();
1742 Point aOffset = GetPageOffset();
1743 aInfo.LeftInset = aOffset.X();
1744 aInfo.TopInset = aOffset.Y();
1745 aInfo.RightInset = aDevSz.Width() - aOutSz.Width() - aOffset.X();
1746 aInfo.BottomInset = aDevSz.Height() - aOutSz.Height() - aOffset.Y();
1747 aInfo.Capabilities = 0;
1749 return aInfo;
1752 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */