tdf#130857 qt weld: Implement QtInstanceWidget::get_text_height
[LibreOffice.git] / vcl / source / gdi / print.cxx
blobf0308a5ec68694ba33e132da48deaca6b8290b6f
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/config.h>
22 #include <sal/types.h>
23 #include <sal/log.hxx>
24 #include <comphelper/processfactory.hxx>
25 #include <o3tl/safeint.hxx>
26 #include <tools/debug.hxx>
27 #include <tools/helpers.hxx>
29 #include <vcl/QueueInfo.hxx>
30 #include <vcl/event.hxx>
31 #include <vcl/virdev.hxx>
32 #include <vcl/print.hxx>
33 #include <vcl/printer/Options.hxx>
35 #include <jobset.h>
36 #include <print.h>
37 #include <ImplOutDevData.hxx>
38 #include <font/PhysicalFontCollection.hxx>
39 #include <font/PhysicalFontFaceCollection.hxx>
40 #include <font/fontsubstitution.hxx>
41 #include <impfontcache.hxx>
42 #include <print.hrc>
43 #include <salgdi.hxx>
44 #include <salinst.hxx>
45 #include <salprn.hxx>
46 #include <salptype.hxx>
47 #include <salvd.hxx>
48 #include <svdata.hxx>
50 #include <com/sun/star/beans/XPropertySet.hpp>
51 #include <com/sun/star/configuration/theDefaultProvider.hpp>
52 #include <com/sun/star/container/XNameAccess.hpp>
53 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
54 #include <com/sun/star/uno/Sequence.h>
56 int nImplSysDialog = 0;
58 namespace
60 Paper ImplGetPaperFormat( tools::Long nWidth100thMM, tools::Long nHeight100thMM )
62 PaperInfo aInfo(nWidth100thMM, nHeight100thMM);
63 aInfo.doSloppyFit();
64 return aInfo.getPaper();
67 const PaperInfo& ImplGetEmptyPaper()
69 static PaperInfo aInfo(PAPER_USER);
70 return aInfo;
74 void ImplUpdateJobSetupPaper( JobSetup& rJobSetup )
76 const ImplJobSetup& rConstData = rJobSetup.ImplGetConstData();
78 if ( !rConstData.GetPaperWidth() || !rConstData.GetPaperHeight() )
80 if ( rConstData.GetPaperFormat() != PAPER_USER )
82 PaperInfo aInfo(rConstData.GetPaperFormat());
84 ImplJobSetup& rData = rJobSetup.ImplGetData();
85 rData.SetPaperWidth( aInfo.getWidth() );
86 rData.SetPaperHeight( aInfo.getHeight() );
89 else if ( rConstData.GetPaperFormat() == PAPER_USER )
91 Paper ePaper = ImplGetPaperFormat( rConstData.GetPaperWidth(), rConstData.GetPaperHeight() );
92 if ( ePaper != PAPER_USER )
93 rJobSetup.ImplGetData().SetPaperFormat(ePaper);
97 void Printer::ImplPrintTransparent( const Bitmap& rBmp,
98 const Point& rDestPt, const Size& rDestSize,
99 const Point& rSrcPtPixel, const Size& rSrcSizePixel )
101 Point aDestPt( LogicToPixel( rDestPt ) );
102 Size aDestSz( LogicToPixel( rDestSize ) );
103 tools::Rectangle aSrcRect( rSrcPtPixel, rSrcSizePixel );
105 aSrcRect.Normalize();
107 if( rBmp.IsEmpty() || !aSrcRect.GetWidth() || !aSrcRect.GetHeight() || !aDestSz.Width() || !aDestSz.Height() )
108 return;
110 Bitmap aPaint( rBmp );
111 BmpMirrorFlags nMirrFlags = BmpMirrorFlags::NONE;
113 // mirrored horizontally
114 if( aDestSz.Width() < 0 )
116 aDestSz.setWidth( -aDestSz.Width() );
117 aDestPt.AdjustX( -( aDestSz.Width() - 1 ) );
118 nMirrFlags |= BmpMirrorFlags::Horizontal;
121 // mirrored vertically
122 if( aDestSz.Height() < 0 )
124 aDestSz.setHeight( -aDestSz.Height() );
125 aDestPt.AdjustY( -( aDestSz.Height() - 1 ) );
126 nMirrFlags |= BmpMirrorFlags::Vertical;
129 // source cropped?
130 if( aSrcRect != tools::Rectangle( Point(), aPaint.GetSizePixel() ) )
132 aPaint.Crop( aSrcRect );
135 // destination mirrored
136 if( nMirrFlags != BmpMirrorFlags::NONE )
138 aPaint.Mirror( nMirrFlags );
141 // we always want to have a mask
142 AlphaMask aAlphaMask(aSrcRect.GetSize());
143 aAlphaMask.Erase( 0 );
145 // do painting
146 const tools::Long nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight();
147 tools::Long nX, nY; // , nWorkX, nWorkY, nWorkWidth, nWorkHeight;
148 std::unique_ptr<tools::Long[]> pMapX(new tools::Long[ nSrcWidth + 1 ]);
149 std::unique_ptr<tools::Long[]> pMapY(new tools::Long[ nSrcHeight + 1 ]);
150 const bool bOldMap = mbMap;
152 mbMap = false;
154 // create forward mapping tables
155 for( nX = 0; nX <= nSrcWidth; nX++ )
156 pMapX[ nX ] = aDestPt.X() + basegfx::fround<tools::Long>( static_cast<double>(aDestSz.Width()) * nX / nSrcWidth );
158 for( nY = 0; nY <= nSrcHeight; nY++ )
159 pMapY[ nY ] = aDestPt.Y() + basegfx::fround<tools::Long>( static_cast<double>(aDestSz.Height()) * nY / nSrcHeight );
161 tools::Rectangle rectangle { Point(0,0), aSrcRect.GetSize() };
162 const Point aMapPt(pMapX[rectangle.Left()], pMapY[rectangle.Top()]);
163 const Size aMapSz( pMapX[rectangle.Right() + 1] - aMapPt.X(), // pMapX[L + W] -> L + ((R - L) + 1) -> R + 1
164 pMapY[rectangle.Bottom() + 1] - aMapPt.Y()); // same for Y
165 Bitmap aBandBmp(aPaint);
167 DrawBitmap(aMapPt, aMapSz, Point(), aBandBmp.GetSizePixel(), aBandBmp);
169 mbMap = bOldMap;
172 bool Printer::DrawTransformBitmapExDirect(
173 const basegfx::B2DHomMatrix& /*aFullTransform*/,
174 const BitmapEx& /*rBitmapEx*/,
175 double /*fAlpha*/)
177 // printers can't draw bitmaps directly
178 return false;
181 bool Printer::TransformAndReduceBitmapExToTargetRange(
182 const basegfx::B2DHomMatrix& /*aFullTransform*/,
183 basegfx::B2DRange& /*aVisibleRange*/,
184 double& /*fMaximumArea*/)
186 // deliberately do nothing - you can't reduce the
187 // target range for a printer at all
188 return true;
191 void Printer::DrawDeviceBitmapEx( const Point& rDestPt, const Size& rDestSize,
192 const Point& rSrcPtPixel, const Size& rSrcSizePixel,
193 BitmapEx& rBmpEx )
195 if( rBmpEx.IsAlpha() )
197 // #107169# For true alpha bitmaps, no longer masking the
198 // bitmap, but perform a full alpha blend against a white
199 // background here.
200 Bitmap aBmp( rBmpEx.GetBitmap() );
201 aBmp.Blend( rBmpEx.GetAlphaMask(), COL_WHITE );
202 DrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, aBmp );
204 else
206 const Bitmap& aBmp( rBmpEx.GetBitmap() );
207 ImplPrintTransparent( aBmp, rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel );
211 void Printer::EmulateDrawTransparent ( const tools::PolyPolygon& rPolyPoly,
212 sal_uInt16 nTransparencePercent )
214 // #110958# Disable alpha VDev, we perform the necessary
215 VirtualDevice* pOldAlphaVDev = mpAlphaVDev;
217 // operation explicitly further below.
218 if( mpAlphaVDev )
219 mpAlphaVDev = nullptr;
221 GDIMetaFile* pOldMetaFile = mpMetaFile;
222 mpMetaFile = nullptr;
224 tools::Rectangle aPolyRect( LogicToPixel( rPolyPoly ).GetBoundRect() );
225 const Size aDPISize( LogicToPixel(Size(1, 1), MapMode(MapUnit::MapInch)) );
226 const tools::Long nBaseExtent = std::max<tools::Long>( basegfx::fround<tools::Long>( aDPISize.Width() / 300. ), 1 );
227 tools::Long nMove;
228 const sal_uInt16 nTrans = ( nTransparencePercent < 13 ) ? 0 :
229 ( nTransparencePercent < 38 ) ? 25 :
230 ( nTransparencePercent < 63 ) ? 50 :
231 ( nTransparencePercent < 88 ) ? 75 : 100;
233 switch( nTrans )
235 case 25: nMove = nBaseExtent * 3; break;
236 case 50: nMove = nBaseExtent * 4; break;
237 case 75: nMove = nBaseExtent * 6; break;
239 // #i112959# very transparent (88 < nTransparencePercent <= 99)
240 case 100: nMove = nBaseExtent * 8; break;
242 // #i112959# not transparent (nTransparencePercent < 13)
243 default: nMove = 0; break;
246 Push( vcl::PushFlags::CLIPREGION | vcl::PushFlags::LINECOLOR );
247 IntersectClipRegion(vcl::Region(rPolyPoly));
248 SetLineColor( GetFillColor() );
249 const bool bOldMap = mbMap;
250 EnableMapMode( false );
252 if(nMove)
254 tools::Rectangle aRect( aPolyRect.TopLeft(), Size( aPolyRect.GetWidth(), nBaseExtent ) );
255 while( aRect.Top() <= aPolyRect.Bottom() )
257 DrawRect( aRect );
258 aRect.Move( 0, nMove );
261 aRect = tools::Rectangle( aPolyRect.TopLeft(), Size( nBaseExtent, aPolyRect.GetHeight() ) );
262 while( aRect.Left() <= aPolyRect.Right() )
264 DrawRect( aRect );
265 aRect.Move( nMove, 0 );
268 else
270 // #i112959# if not transparent, draw full rectangle in clip region
271 DrawRect( aPolyRect );
274 EnableMapMode( bOldMap );
275 Pop();
277 mpMetaFile = pOldMetaFile;
279 // #110958# Restore disabled alpha VDev
280 mpAlphaVDev = pOldAlphaVDev;
283 void Printer::DrawOutDev( const Point& /*rDestPt*/, const Size& /*rDestSize*/,
284 const Point& /*rSrcPt*/, const Size& /*rSrcSize*/ )
286 SAL_WARN( "vcl.gdi", "Don't use OutputDevice::DrawOutDev(...) with printer devices!" );
289 void Printer::DrawOutDev( const Point& /*rDestPt*/, const Size& /*rDestSize*/,
290 const Point& /*rSrcPt*/, const Size& /*rSrcSize*/,
291 const OutputDevice& /*rOutDev*/ )
293 SAL_WARN( "vcl.gdi", "Don't use OutputDevice::DrawOutDev(...) with printer devices!" );
296 void Printer::CopyArea( const Point& /*rDestPt*/,
297 const Point& /*rSrcPt*/, const Size& /*rSrcSize*/,
298 bool /*bWindowInvalidate*/ )
300 SAL_WARN( "vcl.gdi", "Don't use OutputDevice::CopyArea(...) with printer devices!" );
303 tools::Rectangle Printer::GetBackgroundComponentBounds() const
305 Point aPageOffset = Point( 0, 0 ) - this->GetPageOffsetPixel();
306 Size aSize = this->GetPaperSizePixel();
307 return tools::Rectangle( aPageOffset, aSize );
310 void Printer::SetPrinterOptions( const vcl::printer::Options& i_rOptions )
312 *mpPrinterOptions = i_rOptions;
315 bool Printer::HasMirroredGraphics() const
317 // due to a "hotfix" for AOO bug i55719, this needs to return false
318 return false;
321 SalPrinterQueueInfo::SalPrinterQueueInfo()
323 mnStatus = PrintQueueFlags::NONE;
324 mnJobs = QUEUE_JOBS_DONTKNOW;
327 SalPrinterQueueInfo::~SalPrinterQueueInfo()
331 ImplPrnQueueList::~ImplPrnQueueList()
335 void ImplPrnQueueList::Add( std::unique_ptr<SalPrinterQueueInfo> pData )
337 std::unordered_map< OUString, sal_Int32 >::iterator it =
338 m_aNameToIndex.find( pData->maPrinterName );
339 if( it == m_aNameToIndex.end() )
341 m_aNameToIndex[ pData->maPrinterName ] = m_aQueueInfos.size();
342 m_aPrinterList.push_back( pData->maPrinterName );
343 m_aQueueInfos.push_back( ImplPrnQueueData() );
344 m_aQueueInfos.back().mpQueueInfo = nullptr;
345 m_aQueueInfos.back().mpSalQueueInfo = std::move(pData);
347 else // this should not happen, but ...
349 ImplPrnQueueData& rData = m_aQueueInfos[ it->second ];
350 rData.mpQueueInfo.reset();
351 rData.mpSalQueueInfo = std::move(pData);
355 ImplPrnQueueData* ImplPrnQueueList::Get( const OUString& rPrinter )
357 ImplPrnQueueData* pData = nullptr;
358 std::unordered_map<OUString,sal_Int32>::iterator it =
359 m_aNameToIndex.find( rPrinter );
360 if( it != m_aNameToIndex.end() )
361 pData = &m_aQueueInfos[it->second];
362 return pData;
365 static void ImplInitPrnQueueList()
367 ImplSVData* pSVData = ImplGetSVData();
369 pSVData->maGDIData.mpPrinterQueueList.reset(new ImplPrnQueueList);
371 static const char* pEnv = getenv( "SAL_DISABLE_PRINTERLIST" );
372 if( !pEnv || !*pEnv )
373 pSVData->mpDefInst->GetPrinterQueueInfo( pSVData->maGDIData.mpPrinterQueueList.get() );
376 void ImplDeletePrnQueueList()
378 ImplSVData* pSVData = ImplGetSVData();
379 pSVData->maGDIData.mpPrinterQueueList.reset();
382 const std::vector<OUString>& Printer::GetPrinterQueues()
384 ImplSVData* pSVData = ImplGetSVData();
385 if ( !pSVData->maGDIData.mpPrinterQueueList )
386 ImplInitPrnQueueList();
387 assert(pSVData->maGDIData.mpPrinterQueueList && "mpPrinterQueueList exists by now");
388 return pSVData->maGDIData.mpPrinterQueueList->m_aPrinterList;
391 const QueueInfo* Printer::GetQueueInfo( const OUString& rPrinterName, bool bStatusUpdate )
393 ImplSVData* pSVData = ImplGetSVData();
395 if ( !pSVData->maGDIData.mpPrinterQueueList )
396 ImplInitPrnQueueList();
398 if ( !pSVData->maGDIData.mpPrinterQueueList )
399 return nullptr;
401 ImplPrnQueueData* pInfo = pSVData->maGDIData.mpPrinterQueueList->Get( rPrinterName );
402 if( pInfo )
404 if( !pInfo->mpQueueInfo || bStatusUpdate )
405 pSVData->mpDefInst->GetPrinterQueueState( pInfo->mpSalQueueInfo.get() );
407 if ( !pInfo->mpQueueInfo )
408 pInfo->mpQueueInfo.reset(new QueueInfo);
410 pInfo->mpQueueInfo->maPrinterName = pInfo->mpSalQueueInfo->maPrinterName;
411 pInfo->mpQueueInfo->maDriver = pInfo->mpSalQueueInfo->maDriver;
412 pInfo->mpQueueInfo->maLocation = pInfo->mpSalQueueInfo->maLocation;
413 pInfo->mpQueueInfo->maComment = pInfo->mpSalQueueInfo->maComment;
414 pInfo->mpQueueInfo->mnStatus = pInfo->mpSalQueueInfo->mnStatus;
415 pInfo->mpQueueInfo->mnJobs = pInfo->mpSalQueueInfo->mnJobs;
416 return pInfo->mpQueueInfo.get();
418 return nullptr;
421 OUString Printer::GetDefaultPrinterName()
423 static const char* pEnv = getenv( "SAL_DISABLE_DEFAULTPRINTER" );
424 if( !pEnv || !*pEnv )
426 ImplSVData* pSVData = ImplGetSVData();
428 return pSVData->mpDefInst->GetDefaultPrinter();
430 return OUString();
433 void Printer::ImplInitData()
435 mbDevOutput = false;
436 mbDefPrinter = false;
437 mnError = ERRCODE_NONE;
438 mnPageQueueSize = 0;
439 mnCopyCount = 1;
440 mbCollateCopy = false;
441 mbPrinting = false;
442 mbJobActive = false;
443 mbPrintFile = false;
444 mbInPrintPage = false;
445 mbNewJobSetup = false;
446 mbSinglePrintJobs = false;
447 mbUsePrintSetting = false;
448 mbResetPrintArea = false;
449 mpInfoPrinter = nullptr;
450 mpPrinter = nullptr;
451 mpDisplayDev = nullptr;
452 mpPrinterOptions.reset(new vcl::printer::Options);
454 // Add printer to the list
455 ImplSVData* pSVData = ImplGetSVData();
456 mpNext = pSVData->maGDIData.mpFirstPrinter;
457 mpPrev = nullptr;
458 if ( mpNext )
459 mpNext->mpPrev = this;
460 pSVData->maGDIData.mpFirstPrinter = this;
463 bool Printer::AcquireGraphics() const
465 DBG_TESTSOLARMUTEX();
467 if ( mpGraphics )
468 return true;
470 mbInitLineColor = true;
471 mbInitFillColor = true;
472 mbInitFont = true;
473 mbInitTextColor = true;
474 mbInitClipRegion = true;
476 ImplSVData* pSVData = ImplGetSVData();
478 if ( mpJobGraphics )
479 mpGraphics = mpJobGraphics;
480 else if ( mpDisplayDev )
482 const VirtualDevice* pVirDev = mpDisplayDev;
483 mpGraphics = pVirDev->mpVirDev->AcquireGraphics();
484 // if needed retry after releasing least recently used virtual device graphics
485 while ( !mpGraphics )
487 if ( !pSVData->maGDIData.mpLastVirGraphics )
488 break;
489 pSVData->maGDIData.mpLastVirGraphics->ReleaseGraphics();
490 mpGraphics = pVirDev->mpVirDev->AcquireGraphics();
492 // update global LRU list of virtual device graphics
493 if ( mpGraphics )
495 mpNextGraphics = pSVData->maGDIData.mpFirstVirGraphics;
496 pSVData->maGDIData.mpFirstVirGraphics = const_cast<Printer*>(this);
497 if ( mpNextGraphics )
498 mpNextGraphics->mpPrevGraphics = const_cast<Printer*>(this);
499 if ( !pSVData->maGDIData.mpLastVirGraphics )
500 pSVData->maGDIData.mpLastVirGraphics = const_cast<Printer*>(this);
503 else
505 mpGraphics = mpInfoPrinter->AcquireGraphics();
506 // if needed retry after releasing least recently used printer graphics
507 while ( !mpGraphics )
509 if ( !pSVData->maGDIData.mpLastPrnGraphics )
510 break;
511 pSVData->maGDIData.mpLastPrnGraphics->ReleaseGraphics();
512 mpGraphics = mpInfoPrinter->AcquireGraphics();
514 // update global LRU list of printer graphics
515 if ( mpGraphics )
517 mpNextGraphics = pSVData->maGDIData.mpFirstPrnGraphics;
518 pSVData->maGDIData.mpFirstPrnGraphics = const_cast<Printer*>(this);
519 if ( mpNextGraphics )
520 mpNextGraphics->mpPrevGraphics = const_cast<Printer*>(this);
521 if ( !pSVData->maGDIData.mpLastPrnGraphics )
522 pSVData->maGDIData.mpLastPrnGraphics = const_cast<Printer*>(this);
526 if ( mpGraphics )
528 mpGraphics->SetXORMode( (RasterOp::Invert == meRasterOp) || (RasterOp::Xor == meRasterOp), RasterOp::Invert == meRasterOp );
529 mpGraphics->setAntiAlias(bool(mnAntialiasing & AntialiasingFlags::Enable));
532 return mpGraphics != nullptr;
535 void Printer::ImplReleaseFonts()
537 mpGraphics->ReleaseFonts();
538 mbNewFont = true;
539 mbInitFont = true;
541 mpFontInstance.clear();
542 mpFontFaceCollection.reset();
545 void Printer::ImplReleaseGraphics(bool bRelease)
547 DBG_TESTSOLARMUTEX();
549 if ( !mpGraphics )
550 return;
552 // release the fonts of the physically released graphics device
553 if( bRelease )
554 ImplReleaseFonts();
556 ImplSVData* pSVData = ImplGetSVData();
558 Printer* pPrinter = this;
560 if ( !pPrinter->mpJobGraphics )
562 if ( pPrinter->mpDisplayDev )
564 VirtualDevice* pVirDev = pPrinter->mpDisplayDev;
565 if ( bRelease )
566 pVirDev->mpVirDev->ReleaseGraphics( mpGraphics );
567 // remove from global LRU list of virtual device graphics
568 if ( mpPrevGraphics )
569 mpPrevGraphics->mpNextGraphics = mpNextGraphics;
570 else
571 pSVData->maGDIData.mpFirstVirGraphics = mpNextGraphics;
572 if ( mpNextGraphics )
573 mpNextGraphics->mpPrevGraphics = mpPrevGraphics;
574 else
575 pSVData->maGDIData.mpLastVirGraphics = mpPrevGraphics;
577 else
579 if ( bRelease )
580 pPrinter->mpInfoPrinter->ReleaseGraphics( mpGraphics );
581 // remove from global LRU list of printer graphics
582 if ( mpPrevGraphics )
583 mpPrevGraphics->mpNextGraphics = mpNextGraphics;
584 else
585 pSVData->maGDIData.mpFirstPrnGraphics = static_cast<Printer*>(mpNextGraphics.get());
586 if ( mpNextGraphics )
587 mpNextGraphics->mpPrevGraphics = mpPrevGraphics;
588 else
589 pSVData->maGDIData.mpLastPrnGraphics = static_cast<Printer*>(mpPrevGraphics.get());
593 mpGraphics = nullptr;
594 mpPrevGraphics = nullptr;
595 mpNextGraphics = nullptr;
598 void Printer::ReleaseGraphics(bool bRelease)
600 ImplReleaseGraphics(bRelease);
603 void Printer::ImplInit( SalPrinterQueueInfo* pInfo )
605 ImplSVData* pSVData = ImplGetSVData();
606 // #i74084# update info for this specific SalPrinterQueueInfo
607 pSVData->mpDefInst->GetPrinterQueueState( pInfo );
609 // Test whether the driver actually matches the JobSetup
610 ImplJobSetup& rData = maJobSetup.ImplGetData();
611 if ( rData.GetDriverData() )
613 if ( rData.GetPrinterName() != pInfo->maPrinterName ||
614 rData.GetDriver() != pInfo->maDriver )
616 rData.SetDriverData(nullptr, 0);
620 // Remember printer name
621 maPrinterName = pInfo->maPrinterName;
622 maDriver = pInfo->maDriver;
624 // Add printer name to JobSetup
625 rData.SetPrinterName( maPrinterName );
626 rData.SetDriver( maDriver );
628 mpInfoPrinter = pSVData->mpDefInst->CreateInfoPrinter( pInfo, &rData );
629 mpPrinter = nullptr;
630 mpJobGraphics = nullptr;
631 ImplUpdateJobSetupPaper( maJobSetup );
633 if ( !mpInfoPrinter )
635 ImplInitDisplay();
636 return;
639 // we need a graphics
640 if ( !AcquireGraphics() )
642 ImplInitDisplay();
643 return;
646 // Init data
647 ImplUpdatePageData();
648 mxFontCollection = std::make_shared<vcl::font::PhysicalFontCollection>();
649 mxFontCache = std::make_shared<ImplFontCache>();
650 mpGraphics->GetDevFontList(mxFontCollection.get());
653 void Printer::ImplInitDisplay()
655 ImplSVData* pSVData = ImplGetSVData();
657 mpInfoPrinter = nullptr;
658 mpPrinter = nullptr;
659 mpJobGraphics = nullptr;
661 mpDisplayDev = VclPtr<VirtualDevice>::Create();
662 mxFontCollection = pSVData->maGDIData.mxScreenFontList;
663 mxFontCache = pSVData->maGDIData.mxScreenFontCache;
664 mnDPIX = mpDisplayDev->mnDPIX;
665 mnDPIY = mpDisplayDev->mnDPIY;
668 void Printer::DrawDeviceMask( const Bitmap& rMask, const Color& rMaskColor,
669 const Point& rDestPt, const Size& rDestSize,
670 const Point& rSrcPtPixel, const Size& rSrcSizePixel )
672 Point aDestPt( LogicToPixel( rDestPt ) );
673 Size aDestSz( LogicToPixel( rDestSize ) );
674 tools::Rectangle aSrcRect( rSrcPtPixel, rSrcSizePixel );
676 aSrcRect.Normalize();
678 if( !(!rMask.IsEmpty() && aSrcRect.GetWidth() && aSrcRect.GetHeight() && aDestSz.Width() && aDestSz.Height()) )
679 return;
681 Bitmap aMask( rMask );
682 BmpMirrorFlags nMirrFlags = BmpMirrorFlags::NONE;
684 if (aMask.getPixelFormat() >= vcl::PixelFormat::N8_BPP)
685 aMask.Convert( BmpConversion::N1BitThreshold );
687 // mirrored horizontally
688 if( aDestSz.Width() < 0 )
690 aDestSz.setWidth( -aDestSz.Width() );
691 aDestPt.AdjustX( -( aDestSz.Width() - 1 ) );
692 nMirrFlags |= BmpMirrorFlags::Horizontal;
695 // mirrored vertically
696 if( aDestSz.Height() < 0 )
698 aDestSz.setHeight( -aDestSz.Height() );
699 aDestPt.AdjustY( -( aDestSz.Height() - 1 ) );
700 nMirrFlags |= BmpMirrorFlags::Vertical;
703 // source cropped?
704 if( aSrcRect != tools::Rectangle( Point(), aMask.GetSizePixel() ) )
705 aMask.Crop( aSrcRect );
707 // destination mirrored
708 if( nMirrFlags != BmpMirrorFlags::NONE)
709 aMask.Mirror( nMirrFlags );
711 // do painting
712 const tools::Long nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight();
713 tools::Long nX, nY; //, nWorkX, nWorkY, nWorkWidth, nWorkHeight;
714 std::unique_ptr<tools::Long[]> pMapX( new tools::Long[ nSrcWidth + 1 ] );
715 std::unique_ptr<tools::Long[]> pMapY( new tools::Long[ nSrcHeight + 1 ] );
716 GDIMetaFile* pOldMetaFile = mpMetaFile;
717 const bool bOldMap = mbMap;
719 mpMetaFile = nullptr;
720 mbMap = false;
721 Push( vcl::PushFlags::FILLCOLOR | vcl::PushFlags::LINECOLOR );
722 SetLineColor( rMaskColor );
723 SetFillColor( rMaskColor );
724 InitLineColor();
725 InitFillColor();
727 // create forward mapping tables
728 for( nX = 0; nX <= nSrcWidth; nX++ )
729 pMapX[ nX ] = aDestPt.X() + basegfx::fround<tools::Long>( static_cast<double>(aDestSz.Width()) * nX / nSrcWidth );
731 for( nY = 0; nY <= nSrcHeight; nY++ )
732 pMapY[ nY ] = aDestPt.Y() + basegfx::fround<tools::Long>( static_cast<double>(aDestSz.Height()) * nY / nSrcHeight );
734 // walk through all rectangles of mask
735 const vcl::Region aWorkRgn(aMask.CreateRegion(COL_BLACK, tools::Rectangle(Point(), aMask.GetSizePixel())));
736 RectangleVector aRectangles;
737 aWorkRgn.GetRegionRectangles(aRectangles);
739 for (auto const& rectangle : aRectangles)
741 const Point aMapPt(pMapX[rectangle.Left()], pMapY[rectangle.Top()]);
742 const Size aMapSz(
743 pMapX[rectangle.Right() + 1] - aMapPt.X(), // pMapX[L + W] -> L + ((R - L) + 1) -> R + 1
744 pMapY[rectangle.Bottom() + 1] - aMapPt.Y()); // same for Y
746 DrawRect(tools::Rectangle(aMapPt, aMapSz));
749 Pop();
750 mbMap = bOldMap;
751 mpMetaFile = pOldMetaFile;
754 SalPrinterQueueInfo* Printer::ImplGetQueueInfo( const OUString& rPrinterName,
755 const OUString* pDriver )
757 ImplSVData* pSVData = ImplGetSVData();
758 if ( !pSVData->maGDIData.mpPrinterQueueList )
759 ImplInitPrnQueueList();
761 ImplPrnQueueList* pPrnList = pSVData->maGDIData.mpPrinterQueueList.get();
762 if ( pPrnList && !pPrnList->m_aQueueInfos.empty() )
764 // first search for the printer name directly
765 ImplPrnQueueData* pInfo = pPrnList->Get( rPrinterName );
766 if( pInfo )
767 return pInfo->mpSalQueueInfo.get();
769 // then search case insensitive
770 for(const ImplPrnQueueData & rQueueInfo : pPrnList->m_aQueueInfos)
772 if( rQueueInfo.mpSalQueueInfo->maPrinterName.equalsIgnoreAsciiCase( rPrinterName ) )
773 return rQueueInfo.mpSalQueueInfo.get();
776 // then search for driver name
777 if ( pDriver )
779 for(const ImplPrnQueueData & rQueueInfo : pPrnList->m_aQueueInfos)
781 if( rQueueInfo.mpSalQueueInfo->maDriver == *pDriver )
782 return rQueueInfo.mpSalQueueInfo.get();
786 // then the default printer
787 pInfo = pPrnList->Get( GetDefaultPrinterName() );
788 if( pInfo )
789 return pInfo->mpSalQueueInfo.get();
791 // last chance: the first available printer
792 return pPrnList->m_aQueueInfos[0].mpSalQueueInfo.get();
795 return nullptr;
798 void Printer::ImplUpdatePageData()
800 // we need a graphics
801 if ( !AcquireGraphics() )
802 return;
804 mpGraphics->GetResolution( mnDPIX, mnDPIY );
805 mpInfoPrinter->GetPageInfo( &maJobSetup.ImplGetConstData(),
806 mnOutWidth, mnOutHeight,
807 maPageOffset,
808 maPaperSize );
811 void Printer::ImplUpdateFontList()
813 ImplUpdateFontData();
816 tools::Long Printer::GetGradientStepCount( tools::Long nMinRect )
818 // use display-equivalent step size calculation
819 tools::Long nInc = (nMinRect < 800) ? 10 : 20;
821 return nInc;
824 Printer::Printer()
825 : OutputDevice(OUTDEV_PRINTER)
827 ImplInitData();
828 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( GetDefaultPrinterName(), nullptr );
829 if ( pInfo )
831 ImplInit( pInfo );
832 if ( !IsDisplayPrinter() )
833 mbDefPrinter = true;
835 else
836 ImplInitDisplay();
839 Printer::Printer( const JobSetup& rJobSetup )
840 : OutputDevice(OUTDEV_PRINTER)
841 , maJobSetup(rJobSetup)
843 ImplInitData();
844 const ImplJobSetup& rConstData = rJobSetup.ImplGetConstData();
845 const OUString& aDriver = rConstData.GetDriver();
846 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( rConstData.GetPrinterName(),
847 &aDriver );
848 if ( pInfo )
850 ImplInit( pInfo );
851 SetJobSetup( rJobSetup );
853 else
855 ImplInitDisplay();
856 maJobSetup = JobSetup();
860 Printer::Printer( const QueueInfo& rQueueInfo )
861 : OutputDevice(OUTDEV_PRINTER)
863 ImplInitData();
864 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( rQueueInfo.GetPrinterName(),
865 &rQueueInfo.GetDriver() );
866 if ( pInfo )
867 ImplInit( pInfo );
868 else
869 ImplInitDisplay();
872 Printer::Printer( const OUString& rPrinterName )
873 : OutputDevice(OUTDEV_PRINTER)
875 ImplInitData();
876 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( rPrinterName, nullptr );
877 if ( pInfo )
878 ImplInit( pInfo );
879 else
880 ImplInitDisplay();
883 Printer::~Printer()
885 disposeOnce();
888 void Printer::dispose()
890 SAL_WARN_IF( IsPrinting(), "vcl.gdi", "Printer::~Printer() - Job is printing" );
891 SAL_WARN_IF( IsJobActive(), "vcl.gdi", "Printer::~Printer() - Job is active" );
893 mpPrinterOptions.reset();
895 ImplReleaseGraphics();
896 if ( mpInfoPrinter )
897 ImplGetSVData()->mpDefInst->DestroyInfoPrinter( mpInfoPrinter );
898 if ( mpDisplayDev )
899 mpDisplayDev.disposeAndClear();
900 else
902 // OutputDevice Dtor is trying the same thing; that why we need to set
903 // the FontEntry to NULL here
904 // TODO: consolidate duplicate cleanup by Printer and OutputDevice
905 mpFontInstance.clear();
906 mpFontFaceCollection.reset();
907 mxFontCache.reset();
908 // font list deleted by OutputDevice dtor
911 // Add printer from the list
912 ImplSVData* pSVData = ImplGetSVData();
913 if ( mpPrev )
914 mpPrev->mpNext = mpNext;
915 else
916 pSVData->maGDIData.mpFirstPrinter = mpNext;
917 if ( mpNext )
918 mpNext->mpPrev = mpPrev;
920 mpPrev.clear();
921 mpNext.clear();
922 OutputDevice::dispose();
925 Size Printer::GetButtonBorderSize()
927 Size aBrdSize(LogicToPixel(Size(20, 20), MapMode(MapUnit::Map100thMM)));
929 if (!aBrdSize.Width())
930 aBrdSize.setWidth(1);
932 if (!aBrdSize.Height())
933 aBrdSize.setHeight(1);
935 return aBrdSize;
938 sal_uInt32 Printer::GetCapabilities( PrinterCapType nType ) const
940 if ( IsDisplayPrinter() )
941 return 0;
943 if( mpInfoPrinter )
944 return mpInfoPrinter->GetCapabilities( &maJobSetup.ImplGetConstData(), nType );
945 else
946 return 0;
949 bool Printer::HasSupport( PrinterSupport eFeature ) const
951 switch ( eFeature )
953 case PrinterSupport::SetOrientation:
954 return GetCapabilities( PrinterCapType::SetOrientation ) != 0;
955 case PrinterSupport::SetPaperSize:
956 return GetCapabilities( PrinterCapType::SetPaperSize ) != 0;
957 case PrinterSupport::SetPaper:
958 return GetCapabilities( PrinterCapType::SetPaper ) != 0;
959 case PrinterSupport::CollateCopy:
960 return (GetCapabilities( PrinterCapType::CollateCopies ) != 0);
961 case PrinterSupport::SetupDialog:
962 return GetCapabilities( PrinterCapType::SupportDialog ) != 0;
965 return true;
968 bool Printer::SetJobSetup( const JobSetup& rSetup )
970 if ( IsDisplayPrinter() || mbInPrintPage )
971 return false;
973 JobSetup aJobSetup = rSetup;
975 ReleaseGraphics();
976 if ( mpInfoPrinter->SetPrinterData( &aJobSetup.ImplGetData() ) )
978 ImplUpdateJobSetupPaper( aJobSetup );
979 mbNewJobSetup = true;
980 maJobSetup = std::move(aJobSetup);
981 ImplUpdatePageData();
982 ImplUpdateFontList();
983 return true;
986 return false;
989 bool Printer::Setup(weld::Window* pWindow, PrinterSetupMode eMode)
991 if ( IsDisplayPrinter() )
992 return false;
994 if ( IsJobActive() || IsPrinting() )
995 return false;
997 JobSetup aJobSetup = maJobSetup;
998 ImplJobSetup& rData = aJobSetup.ImplGetData();
999 rData.SetPrinterSetupMode( eMode );
1000 // TODO: orig page size
1002 if (!pWindow)
1004 vcl::Window* pDefWin = ImplGetDefaultWindow();
1005 pWindow = pDefWin ? pDefWin->GetFrameWeld() : nullptr;
1007 if( !pWindow )
1008 return false;
1010 ReleaseGraphics();
1011 ImplSVData* pSVData = ImplGetSVData();
1012 pSVData->maAppData.mnModalMode++;
1013 nImplSysDialog++;
1014 bool bSetup = mpInfoPrinter->Setup(pWindow, &rData);
1015 pSVData->maAppData.mnModalMode--;
1016 nImplSysDialog--;
1017 if ( bSetup )
1019 ImplUpdateJobSetupPaper( aJobSetup );
1020 mbNewJobSetup = true;
1021 maJobSetup = std::move(aJobSetup);
1022 ImplUpdatePageData();
1023 ImplUpdateFontList();
1024 return true;
1026 return false;
1029 bool Printer::SetPrinterProps( const Printer* pPrinter )
1031 if ( IsJobActive() || IsPrinting() )
1032 return false;
1034 ImplSVData* pSVData = ImplGetSVData();
1036 mbDefPrinter = pPrinter->mbDefPrinter;
1037 maPrintFile = pPrinter->maPrintFile;
1038 mbPrintFile = pPrinter->mbPrintFile;
1039 mnCopyCount = pPrinter->mnCopyCount;
1040 mbCollateCopy = pPrinter->mbCollateCopy;
1041 mnPageQueueSize = pPrinter->mnPageQueueSize;
1042 *mpPrinterOptions = *pPrinter->mpPrinterOptions;
1044 if ( pPrinter->IsDisplayPrinter() )
1046 // Destroy old printer
1047 if ( !IsDisplayPrinter() )
1049 ReleaseGraphics();
1050 pSVData->mpDefInst->DestroyInfoPrinter( mpInfoPrinter );
1051 mpFontInstance.clear();
1052 mpFontFaceCollection.reset();
1053 // clean up font list
1054 mxFontCache.reset();
1055 mxFontCollection.reset();
1057 mbInitFont = true;
1058 mbNewFont = true;
1059 mpInfoPrinter = nullptr;
1062 // Construct new printer
1063 ImplInitDisplay();
1064 return true;
1067 // Destroy old printer?
1068 if ( GetName() != pPrinter->GetName() )
1070 ReleaseGraphics();
1071 if ( mpDisplayDev )
1073 mpDisplayDev.disposeAndClear();
1075 else
1077 pSVData->mpDefInst->DestroyInfoPrinter( mpInfoPrinter );
1079 mpFontInstance.clear();
1080 mpFontFaceCollection.reset();
1081 mxFontCache.reset();
1082 mxFontCollection.reset();
1083 mbInitFont = true;
1084 mbNewFont = true;
1085 mpInfoPrinter = nullptr;
1088 // Construct new printer
1089 const OUString& aDriver = pPrinter->GetDriverName();
1090 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( pPrinter->GetName(), &aDriver );
1091 if ( pInfo )
1093 ImplInit( pInfo );
1094 SetJobSetup( pPrinter->GetJobSetup() );
1096 else
1097 ImplInitDisplay();
1099 else
1100 SetJobSetup( pPrinter->GetJobSetup() );
1102 return false;
1105 bool Printer::SetOrientation( Orientation eOrientation )
1107 if ( mbInPrintPage )
1108 return false;
1110 if ( maJobSetup.ImplGetConstData().GetOrientation() != eOrientation )
1112 JobSetup aJobSetup = maJobSetup;
1113 ImplJobSetup& rData = aJobSetup.ImplGetData();
1115 rData.SetOrientation(eOrientation);
1117 if ( IsDisplayPrinter() )
1119 mbNewJobSetup = true;
1120 maJobSetup = aJobSetup;
1121 return true;
1124 ReleaseGraphics();
1125 if ( mpInfoPrinter->SetData( JobSetFlags::ORIENTATION, &rData ) )
1127 ImplUpdateJobSetupPaper( aJobSetup );
1128 mbNewJobSetup = true;
1129 maJobSetup = std::move(aJobSetup);
1130 ImplUpdatePageData();
1131 ImplUpdateFontList();
1132 return true;
1134 else
1135 return false;
1138 return true;
1141 Orientation Printer::GetOrientation() const
1143 return maJobSetup.ImplGetConstData().GetOrientation();
1146 bool Printer::SetPaperBin( sal_uInt16 nPaperBin )
1148 if ( mbInPrintPage )
1149 return false;
1151 if ( maJobSetup.ImplGetConstData().GetPaperBin() != nPaperBin &&
1152 nPaperBin < GetPaperBinCount() )
1154 JobSetup aJobSetup = maJobSetup;
1155 ImplJobSetup& rData = aJobSetup.ImplGetData();
1156 rData.SetPaperBin(nPaperBin);
1158 if ( IsDisplayPrinter() )
1160 mbNewJobSetup = true;
1161 maJobSetup = aJobSetup;
1162 return true;
1165 ReleaseGraphics();
1166 if ( mpInfoPrinter->SetData( JobSetFlags::PAPERBIN, &rData ) )
1168 ImplUpdateJobSetupPaper( aJobSetup );
1169 mbNewJobSetup = true;
1170 maJobSetup = std::move(aJobSetup);
1171 ImplUpdatePageData();
1172 ImplUpdateFontList();
1173 return true;
1175 else
1176 return false;
1179 return true;
1182 sal_uInt16 Printer::GetPaperBin() const
1184 return maJobSetup.ImplGetConstData().GetPaperBin();
1187 bool Printer::GetPrinterSettingsPreferred() const
1189 return maJobSetup.ImplGetConstData().GetPapersizeFromSetup();
1192 // dear loplugins, DO NOT REMOVE this code
1193 // it will be used in follow-up commits
1194 void Printer::SetPrinterSettingsPreferred( bool bPaperSizeFromSetup)
1196 if ( maJobSetup.ImplGetConstData().GetPapersizeFromSetup() != bPaperSizeFromSetup )
1198 JobSetup aJobSetup = maJobSetup;
1199 ImplJobSetup& rData = aJobSetup.ImplGetData();
1200 rData.SetPapersizeFromSetup(bPaperSizeFromSetup);
1202 mbNewJobSetup = true;
1203 maJobSetup = std::move(aJobSetup);
1207 // Map user paper format to an available printer paper format
1208 void Printer::ImplFindPaperFormatForUserSize( JobSetup& aJobSetup )
1210 ImplJobSetup& rData = aJobSetup.ImplGetData();
1212 // The angle that a landscape page will be turned counterclockwise wrt to portrait.
1213 int nLandscapeAngle = mpInfoPrinter ? mpInfoPrinter->GetLandscapeAngle( &maJobSetup.ImplGetConstData() ) : 900;
1214 int nPaperCount = GetPaperInfoCount();
1215 PaperInfo aInfo(rData.GetPaperWidth(), rData.GetPaperHeight());
1217 // Compare all paper formats and get the appropriate one
1218 for ( int i = 0; i < nPaperCount; i++ )
1220 const PaperInfo& rPaperInfo = GetPaperInfo( i );
1222 if ( aInfo.sloppyEqual(rPaperInfo) )
1224 rData.SetPaperFormat(
1225 ImplGetPaperFormat( rPaperInfo.getWidth(),
1226 rPaperInfo.getHeight() ));
1227 rData.SetOrientation( Orientation::Portrait );
1228 return;
1232 // If the printer supports landscape orientation, check paper sizes again
1233 // with landscape orientation. This is necessary as a printer driver provides
1234 // all paper sizes with portrait orientation only!!
1235 if ( !(rData.GetPaperFormat() == PAPER_USER &&
1236 nLandscapeAngle != 0 &&
1237 HasSupport( PrinterSupport::SetOrientation )))
1238 return;
1240 const tools::Long nRotatedWidth = rData.GetPaperHeight();
1241 const tools::Long nRotatedHeight = rData.GetPaperWidth();
1242 PaperInfo aRotatedInfo(nRotatedWidth, nRotatedHeight);
1244 for ( int i = 0; i < nPaperCount; i++ )
1246 const PaperInfo& rPaperInfo = GetPaperInfo( i );
1248 if ( aRotatedInfo.sloppyEqual( rPaperInfo ) )
1250 rData.SetPaperFormat(
1251 ImplGetPaperFormat( rPaperInfo.getWidth(),
1252 rPaperInfo.getHeight() ));
1253 rData.SetOrientation( Orientation::Landscape );
1254 return;
1259 void Printer::SetPaper( Paper ePaper )
1261 if ( mbInPrintPage )
1262 return;
1264 if ( maJobSetup.ImplGetConstData().GetPaperFormat() == ePaper )
1265 return;
1267 JobSetup aJobSetup = maJobSetup;
1268 ImplJobSetup& rData = aJobSetup.ImplGetData();
1270 rData.SetPaperFormat( ePaper );
1271 if ( ePaper != PAPER_USER )
1273 PaperInfo aInfo(ePaper);
1274 rData.SetPaperWidth( aInfo.getWidth() );
1275 rData.SetPaperHeight( aInfo.getHeight() );
1278 if ( IsDisplayPrinter() )
1280 mbNewJobSetup = true;
1281 maJobSetup = aJobSetup;
1282 return;
1285 ReleaseGraphics();
1286 if ( ePaper == PAPER_USER )
1287 ImplFindPaperFormatForUserSize( aJobSetup );
1288 if ( mpInfoPrinter->SetData( JobSetFlags::PAPERSIZE | JobSetFlags::ORIENTATION, &rData ))
1290 ImplUpdateJobSetupPaper( aJobSetup );
1291 mbNewJobSetup = true;
1292 maJobSetup = std::move(aJobSetup);
1293 ImplUpdatePageData();
1294 ImplUpdateFontList();
1298 bool Printer::SetPaperSizeUser( const Size& rSize )
1300 if ( mbInPrintPage )
1301 return false;
1303 const Size aPixSize = LogicToPixel( rSize );
1304 const Size aPageSize = PixelToLogic(aPixSize, MapMode(MapUnit::Map100thMM));
1305 bool bNeedToChange(maJobSetup.ImplGetConstData().GetPaperWidth() != aPageSize.Width() ||
1306 maJobSetup.ImplGetConstData().GetPaperHeight() != aPageSize.Height());
1308 if(!bNeedToChange)
1310 // #i122984# only need to change when Paper is different from PAPER_USER and
1311 // the mapped Paper which will created below in the call to ImplFindPaperFormatForUserSize
1312 // and will replace maJobSetup.ImplGetConstData()->GetPaperFormat(). This leads to
1313 // unnecessary JobSetups, e.g. when printing a multi-page fax, but also with
1314 // normal print
1315 const Paper aPaper = ImplGetPaperFormat(aPageSize.Width(), aPageSize.Height());
1317 bNeedToChange = maJobSetup.ImplGetConstData().GetPaperFormat() != PAPER_USER &&
1318 maJobSetup.ImplGetConstData().GetPaperFormat() != aPaper;
1320 if (!bNeedToChange)
1322 Size aPaperSize = GetPaperSizePixel();
1323 bNeedToChange = (aPageSize.Width() < aPageSize.Height()
1324 && aPaperSize.Width() > aPaperSize.Height())
1325 || (aPageSize.Width() > aPageSize.Height()
1326 && aPaperSize.Width() < aPaperSize.Height());
1330 if(bNeedToChange)
1332 JobSetup aJobSetup = maJobSetup;
1333 ImplJobSetup& rData = aJobSetup.ImplGetData();
1334 rData.SetPaperFormat( PAPER_USER );
1335 rData.SetPaperWidth( aPageSize.Width() );
1336 rData.SetPaperHeight( aPageSize.Height() );
1337 rData.SetOrientation( Orientation::Portrait );
1339 if ( IsDisplayPrinter() )
1341 mbNewJobSetup = true;
1342 maJobSetup = std::move(aJobSetup);
1343 return true;
1346 ReleaseGraphics();
1347 ImplFindPaperFormatForUserSize( aJobSetup );
1349 // Changing the paper size can also change the orientation!
1350 if ( mpInfoPrinter->SetData( JobSetFlags::PAPERSIZE | JobSetFlags::ORIENTATION, &rData ))
1352 ImplUpdateJobSetupPaper( aJobSetup );
1353 mbNewJobSetup = true;
1354 maJobSetup = std::move(aJobSetup);
1355 ImplUpdatePageData();
1356 ImplUpdateFontList();
1357 return true;
1359 else
1360 return false;
1363 return true;
1366 int Printer::GetPaperInfoCount() const
1368 if( ! mpInfoPrinter )
1369 return 0;
1370 if( ! mpInfoPrinter->m_bPapersInit )
1371 mpInfoPrinter->InitPaperFormats( &maJobSetup.ImplGetConstData() );
1372 return mpInfoPrinter->m_aPaperFormats.size();
1375 OUString Printer::GetPaperName( Paper ePaper )
1377 ImplSVData* pSVData = ImplGetSVData();
1378 if( pSVData->maPaperNames.empty() )
1380 // This array must (probably) match exactly the enum Paper in <i18nutil/paper.hxx>
1381 static const int PaperIndex[] =
1383 PAPER_A0, PAPER_A1, PAPER_A2, PAPER_A3, PAPER_A4, PAPER_A5, PAPER_B4_ISO, PAPER_B5_ISO,
1384 PAPER_LETTER, PAPER_LEGAL, PAPER_TABLOID, PAPER_USER, PAPER_B6_ISO, PAPER_ENV_C4, PAPER_ENV_C5,
1385 PAPER_ENV_C6, PAPER_ENV_C65, PAPER_ENV_DL, PAPER_SLIDE_DIA, PAPER_SCREEN_4_3, PAPER_C, PAPER_D,
1386 PAPER_E, PAPER_EXECUTIVE, PAPER_FANFOLD_LEGAL_DE, PAPER_ENV_MONARCH, PAPER_ENV_PERSONAL, PAPER_ENV_9,
1387 PAPER_ENV_10, PAPER_ENV_11, PAPER_ENV_12, PAPER_KAI16, PAPER_KAI32, PAPER_KAI32BIG, PAPER_B4_JIS,
1388 PAPER_B5_JIS, PAPER_B6_JIS, PAPER_LEDGER, PAPER_STATEMENT, PAPER_QUARTO, PAPER_10x14, PAPER_ENV_14,
1389 PAPER_ENV_C3, PAPER_ENV_ITALY, PAPER_FANFOLD_US, PAPER_FANFOLD_DE, PAPER_POSTCARD_JP, PAPER_9x11,
1390 PAPER_10x11, PAPER_15x11, PAPER_ENV_INVITE, PAPER_A_PLUS, PAPER_B_PLUS, PAPER_LETTER_PLUS, PAPER_A4_PLUS,
1391 PAPER_DOUBLEPOSTCARD_JP, PAPER_A6, PAPER_12x11, PAPER_A7, PAPER_A8, PAPER_A9, PAPER_A10, PAPER_B0_ISO,
1392 PAPER_B1_ISO, PAPER_B2_ISO, PAPER_B3_ISO, PAPER_B7_ISO, PAPER_B8_ISO, PAPER_B9_ISO, PAPER_B10_ISO,
1393 PAPER_ENV_C2, PAPER_ENV_C7, PAPER_ENV_C8, PAPER_ARCHA, PAPER_ARCHB, PAPER_ARCHC, PAPER_ARCHD,
1394 PAPER_ARCHE, PAPER_SCREEN_16_9, PAPER_SCREEN_16_10, PAPER_16K_195x270, PAPER_16K_197x273,
1395 PAPER_WIDESCREEN, PAPER_ONSCREENSHOW_4_3, PAPER_ONSCREENSHOW_16_9, PAPER_ONSCREENSHOW_16_10
1397 static_assert(SAL_N_ELEMENTS(PaperIndex) == SAL_N_ELEMENTS(RID_STR_PAPERNAMES), "localized paper name count wrong");
1398 for (size_t i = 0; i < SAL_N_ELEMENTS(PaperIndex); ++i)
1399 pSVData->maPaperNames[PaperIndex[i]] = VclResId(RID_STR_PAPERNAMES[i]);
1402 std::unordered_map<int,OUString>::const_iterator it = pSVData->maPaperNames.find( static_cast<int>(ePaper) );
1403 return (it != pSVData->maPaperNames.end()) ? it->second : OUString();
1406 const PaperInfo& Printer::GetPaperInfo( int nPaper ) const
1408 if( ! mpInfoPrinter )
1409 return ImplGetEmptyPaper();
1410 if( ! mpInfoPrinter->m_bPapersInit )
1411 mpInfoPrinter->InitPaperFormats( &maJobSetup.ImplGetConstData() );
1412 if( mpInfoPrinter->m_aPaperFormats.empty() || nPaper < 0 || o3tl::make_unsigned(nPaper) >= mpInfoPrinter->m_aPaperFormats.size() )
1413 return ImplGetEmptyPaper();
1414 return mpInfoPrinter->m_aPaperFormats[nPaper];
1417 Size Printer::GetPaperSize( int nPaper ) const
1419 PaperInfo aInfo = GetPaperInfo( nPaper );
1420 return PixelToLogic( Size( aInfo.getWidth(), aInfo.getHeight() ) );
1423 void Printer::SetDuplexMode( DuplexMode eDuplex )
1425 if ( mbInPrintPage )
1426 return;
1428 if ( maJobSetup.ImplGetConstData().GetDuplexMode() == eDuplex )
1429 return;
1431 JobSetup aJobSetup = maJobSetup;
1432 ImplJobSetup& rData = aJobSetup.ImplGetData();
1434 rData.SetDuplexMode( eDuplex );
1436 if ( IsDisplayPrinter() )
1438 mbNewJobSetup = true;
1439 maJobSetup = aJobSetup;
1440 return;
1443 ReleaseGraphics();
1444 if ( mpInfoPrinter->SetData( JobSetFlags::DUPLEXMODE, &rData ) )
1446 ImplUpdateJobSetupPaper( aJobSetup );
1447 mbNewJobSetup = true;
1448 maJobSetup = std::move(aJobSetup);
1449 ImplUpdatePageData();
1450 ImplUpdateFontList();
1454 DuplexMode Printer::GetDuplexMode() const
1456 return maJobSetup.ImplGetConstData().GetDuplexMode();
1459 Paper Printer::GetPaper() const
1461 return maJobSetup.ImplGetConstData().GetPaperFormat();
1464 Size Printer::GetSizeOfPaper() const
1466 return Size(maJobSetup.ImplGetConstData().GetPaperWidth(), maJobSetup.ImplGetConstData().GetPaperHeight());
1469 sal_uInt16 Printer::GetPaperBinCount() const
1471 if ( IsDisplayPrinter() )
1472 return 0;
1474 return mpInfoPrinter->GetPaperBinCount( &maJobSetup.ImplGetConstData() );
1477 OUString Printer::GetPaperBinName( sal_uInt16 nPaperBin ) const
1479 if ( IsDisplayPrinter() )
1480 return OUString();
1482 if ( nPaperBin < GetPaperBinCount() )
1483 return mpInfoPrinter->GetPaperBinName( &maJobSetup.ImplGetConstData(), nPaperBin );
1484 else
1485 return OUString();
1488 sal_uInt16 Printer::GetPaperBinBySourceIndex(sal_uInt16 nPaperSource) const
1490 if ( IsDisplayPrinter() )
1491 return 0;
1493 return mpInfoPrinter->GetPaperBinBySourceIndex( &maJobSetup.ImplGetConstData(), nPaperSource );
1496 sal_uInt16 Printer::GetSourceIndexByPaperBin(sal_uInt16 nPaperBin) const
1498 if (IsDisplayPrinter())
1499 return 0;
1501 return mpInfoPrinter->GetSourceIndexByPaperBin( &maJobSetup.ImplGetConstData(), nPaperBin);
1504 void Printer::SetCopyCount( sal_uInt16 nCopy, bool bCollate )
1506 mnCopyCount = nCopy;
1507 mbCollateCopy = bCollate;
1510 ErrCode Printer::ImplSalPrinterErrorCodeToVCL( SalPrinterError nError )
1512 ErrCode nVCLError;
1513 switch ( nError )
1515 case SalPrinterError::NONE:
1516 nVCLError = ERRCODE_NONE;
1517 break;
1518 case SalPrinterError::Abort:
1519 nVCLError = PRINTER_ABORT;
1520 break;
1521 default:
1522 nVCLError = PRINTER_GENERALERROR;
1523 break;
1526 return nVCLError;
1529 void Printer::EndJob()
1531 if ( !IsJobActive() )
1532 return;
1534 SAL_WARN_IF( mbInPrintPage, "vcl.gdi", "Printer::EndJob() - StartPage() without EndPage() called" );
1536 mbJobActive = false;
1538 if ( mpPrinter )
1540 ReleaseGraphics();
1542 mbPrinting = false;
1544 mbDevOutput = false;
1545 mpPrinter->EndJob();
1546 mpPrinter.reset();
1550 void Printer::ImplStartPage()
1552 if ( !IsJobActive() )
1553 return;
1555 if ( !mpPrinter )
1556 return;
1558 SalGraphics* pGraphics = mpPrinter->StartPage( &maJobSetup.ImplGetData(),
1559 mbNewJobSetup );
1560 if ( pGraphics )
1562 ReleaseGraphics();
1563 mpJobGraphics = pGraphics;
1565 mbDevOutput = true;
1567 // PrintJob not aborted ???
1568 if ( IsJobActive() )
1569 mbInPrintPage = true;
1572 void Printer::ImplEndPage()
1574 if ( !IsJobActive() )
1575 return;
1577 mbInPrintPage = false;
1579 if ( mpPrinter )
1581 ReleaseGraphics();
1582 mpPrinter->EndPage();
1583 mbDevOutput = false;
1585 mpJobGraphics = nullptr;
1586 mbNewJobSetup = false;
1590 void Printer::updatePrinters()
1592 ImplSVData* pSVData = ImplGetSVData();
1593 ImplPrnQueueList* pPrnList = pSVData->maGDIData.mpPrinterQueueList.get();
1595 if ( !pPrnList )
1596 return;
1598 std::unique_ptr<ImplPrnQueueList> pNewList(new ImplPrnQueueList);
1599 pSVData->mpDefInst->GetPrinterQueueInfo( pNewList.get() );
1601 bool bChanged = pPrnList->m_aQueueInfos.size() != pNewList->m_aQueueInfos.size();
1602 for( decltype(pPrnList->m_aQueueInfos)::size_type i = 0; ! bChanged && i < pPrnList->m_aQueueInfos.size(); i++ )
1604 ImplPrnQueueData& rInfo = pPrnList->m_aQueueInfos[i];
1605 ImplPrnQueueData& rNewInfo = pNewList->m_aQueueInfos[i];
1606 if( ! rInfo.mpSalQueueInfo || ! rNewInfo.mpSalQueueInfo || // sanity check
1607 rInfo.mpSalQueueInfo->maPrinterName != rNewInfo.mpSalQueueInfo->maPrinterName )
1609 bChanged = true;
1612 if( !bChanged )
1613 return;
1615 ImplDeletePrnQueueList();
1616 pSVData->maGDIData.mpPrinterQueueList = std::move(pNewList);
1618 Application* pApp = GetpApp();
1619 if( pApp )
1621 DataChangedEvent aDCEvt( DataChangedEventType::PRINTER );
1622 Application::ImplCallEventListenersApplicationDataChanged(&aDCEvt);
1623 Application::NotifyAllWindows( aDCEvt );
1627 bool Printer::UsePolyPolygonForComplexGradient()
1629 return true;
1632 void Printer::ClipAndDrawGradientMetafile ( const Gradient &rGradient, const tools::PolyPolygon &rPolyPoly )
1634 const tools::Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
1636 Push( vcl::PushFlags::CLIPREGION );
1637 IntersectClipRegion(vcl::Region(rPolyPoly));
1638 DrawGradient( aBoundRect, rGradient );
1639 Pop();
1642 void Printer::SetFontOrientation( LogicalFontInstance* const pFontEntry ) const
1644 pFontEntry->mnOrientation = pFontEntry->mxFontMetric->GetOrientation();
1647 vcl::Region Printer::ClipToDeviceBounds(vcl::Region aRegion) const
1649 return aRegion;
1652 Bitmap Printer::GetBitmap( const Point& rSrcPt, const Size& rSize ) const
1654 SAL_WARN("vcl.gdi", "GetBitmap(): This should never be called on by a Printer instance");
1656 return OutputDevice::GetBitmap( rSrcPt, rSize );
1659 css::awt::DeviceInfo Printer::GetDeviceInfo() const
1661 Size aDevSz = GetPaperSizePixel();
1662 css::awt::DeviceInfo aInfo = GetCommonDeviceInfo(aDevSz);
1663 Size aOutSz = GetOutputSizePixel();
1664 Point aOffset = GetPageOffset();
1665 aInfo.LeftInset = aOffset.X();
1666 aInfo.TopInset = aOffset.Y();
1667 aInfo.RightInset = aDevSz.Width() - aOutSz.Width() - aOffset.X();
1668 aInfo.BottomInset = aDevSz.Height() - aOutSz.Height() - aOffset.Y();
1669 aInfo.Capabilities = 0;
1671 return aInfo;
1674 void Printer::SetWaveLineColors(Color const& rColor, tools::Long)
1676 if (mbLineColor || mbInitLineColor)
1678 mpGraphics->SetLineColor();
1679 mbInitLineColor = true;
1682 mpGraphics->SetFillColor(rColor);
1683 mbInitFillColor = true;
1686 Size Printer::GetWaveLineSize(tools::Long nLineWidth) const
1688 // FIXME - do we have a bug here? If the linewidth is 0, then we will return
1689 // Size(0, 0) - is this correct?
1690 return Size(nLineWidth, ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY);
1693 void Printer::SetSystemTextColor(SystemTextColorFlags, bool)
1695 SetTextColor(COL_BLACK);
1698 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */