1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20 #include <sal/types.h>
21 #include <sal/log.hxx>
22
23 #include <tools/helpers.hxx>
24 #include <tools/debug.hxx>
25
26 #include <vcl/QueueInfo.hxx>
27 #include <vcl/event.hxx>
28 #include <vcl/virdev.hxx>
29 #include <vcl/print.hxx>
30
31 #include <comphelper/processfactory.hxx>
32
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>
44
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>
50
51 int nImplSysDialog = 0;
52
53 namespace
54 {
ImplGetPaperFormat(tools::Long nWidth100thMM,tools::Long nHeight100thMM)55 Paper ImplGetPaperFormat( tools::Long nWidth100thMM, tools::Long nHeight100thMM )
56 {
57 PaperInfo aInfo(nWidth100thMM, nHeight100thMM);
58 aInfo.doSloppyFit();
59 return aInfo.getPaper();
60 }
61
ImplGetEmptyPaper()62 const PaperInfo& ImplGetEmptyPaper()
63 {
64 static PaperInfo aInfo(PAPER_USER);
65 return aInfo;
66 }
67 }
68
ImplUpdateJobSetupPaper(JobSetup & rJobSetup)69 void ImplUpdateJobSetupPaper( JobSetup& rJobSetup )
70 {
71 const ImplJobSetup& rConstData = rJobSetup.ImplGetConstData();
72
73 if ( !rConstData.GetPaperWidth() || !rConstData.GetPaperHeight() )
74 {
75 if ( rConstData.GetPaperFormat() != PAPER_USER )
76 {
77 PaperInfo aInfo(rConstData.GetPaperFormat());
78
79 ImplJobSetup& rData = rJobSetup.ImplGetData();
80 rData.SetPaperWidth( aInfo.getWidth() );
81 rData.SetPaperHeight( aInfo.getHeight() );
82 }
83 }
84 else if ( rConstData.GetPaperFormat() == PAPER_USER )
85 {
86 Paper ePaper = ImplGetPaperFormat( rConstData.GetPaperWidth(), rConstData.GetPaperHeight() );
87 if ( ePaper != PAPER_USER )
88 rJobSetup.ImplGetData().SetPaperFormat(ePaper);
89 }
90 }
91
92 // PrinterOptions
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 )
105 {
106 }
107
ReadFromConfig(bool i_bFile)108 void PrinterOptions::ReadFromConfig( bool i_bFile )
109 {
110 bool bSuccess = false;
111 // save old state in case something goes wrong
112 PrinterOptions aOldValues( *this );
113
114 // get the configuration service
115 css::uno::Reference< css::lang::XMultiServiceFactory > xConfigProvider;
116 css::uno::Reference< css::container::XNameAccess > xConfigAccess;
117 try
118 {
119 // get service provider
120 css::uno::Reference< css::uno::XComponentContext > xContext( comphelper::getProcessComponentContext() );
121 // create configuration hierarchical access name
122 try
123 {
124 xConfigProvider = css::configuration::theDefaultProvider::get( xContext );
125
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() )
137 {
138 css::uno::Reference< css::beans::XPropertySet > xSet( xConfigAccess, css::uno::UNO_QUERY );
139 if( xSet.is() )
140 {
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 );
165
166 bSuccess = true;
167 }
168 }
169 }
170 catch( const css::uno::Exception& )
171 {
172 }
173 }
174 catch( const css::lang::WrappedTargetException& )
175 {
176 }
177
178 if( ! bSuccess )
179 *this = aOldValues;
180 }
181
ImplPrintTransparent(const Bitmap & rBmp,const Bitmap & rMask,const Point & rDestPt,const Size & rDestSize,const Point & rSrcPtPixel,const Size & rSrcSizePixel)182 void Printer::ImplPrintTransparent( const Bitmap& rBmp, const Bitmap& rMask,
183 const Point& rDestPt, const Size& rDestSize,
184 const Point& rSrcPtPixel, const Size& rSrcSizePixel )
185 {
186 Point aDestPt( LogicToPixel( rDestPt ) );
187 Size aDestSz( LogicToPixel( rDestSize ) );
188 tools::Rectangle aSrcRect( rSrcPtPixel, rSrcSizePixel );
189
190 aSrcRect.Justify();
191
192 if( rBmp.IsEmpty() || !aSrcRect.GetWidth() || !aSrcRect.GetHeight() || !aDestSz.Width() || !aDestSz.Height() )
193 return;
194
195 Bitmap aPaint( rBmp ), aMask( rMask );
196 BmpMirrorFlags nMirrFlags = BmpMirrorFlags::NONE;
197
198 if (aMask.getPixelFormat() > vcl::PixelFormat::N1_BPP)
199 aMask.Convert( BmpConversion::N1BitThreshold );
200
201 // mirrored horizontally
202 if( aDestSz.Width() < 0 )
203 {
204 aDestSz.setWidth( -aDestSz.Width() );
205 aDestPt.AdjustX( -( aDestSz.Width() - 1 ) );
206 nMirrFlags |= BmpMirrorFlags::Horizontal;
207 }
208
209 // mirrored vertically
210 if( aDestSz.Height() < 0 )
211 {
212 aDestSz.setHeight( -aDestSz.Height() );
213 aDestPt.AdjustY( -( aDestSz.Height() - 1 ) );
214 nMirrFlags |= BmpMirrorFlags::Vertical;
215 }
216
217 // source cropped?
218 if( aSrcRect != tools::Rectangle( Point(), aPaint.GetSizePixel() ) )
219 {
220 aPaint.Crop( aSrcRect );
221 aMask.Crop( aSrcRect );
222 }
223
224 // destination mirrored
225 if( nMirrFlags != BmpMirrorFlags::NONE )
226 {
227 aPaint.Mirror( nMirrFlags );
228 aMask.Mirror( nMirrFlags );
229 }
230
231 // we always want to have a mask
232 if( aMask.IsEmpty() )
233 {
234 aMask = Bitmap(aSrcRect.GetSize(), vcl::PixelFormat::N1_BPP);
235 aMask.Erase( COL_BLACK );
236 }
237
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;
244
245 mbMap = false;
246
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 );
250
251 for( nY = 0; nY <= nSrcHeight; nY++ )
252 pMapY[ nY ] = aDestPt.Y() + FRound( static_cast<double>(aDestSz.Height()) * nY / nSrcHeight );
253
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);
258
259 for (auto const& rectangle : aRectangles)
260 {
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);
265
266 aBandBmp.Crop(rectangle);
267 DrawBitmap(aMapPt, aMapSz, Point(), aBandBmp.GetSizePixel(), aBandBmp);
268 }
269
270 mbMap = bOldMap;
271
272 }
273
DrawTransformBitmapExDirect(const basegfx::B2DHomMatrix &,const BitmapEx &,double)274 bool Printer::DrawTransformBitmapExDirect(
275 const basegfx::B2DHomMatrix& /*aFullTransform*/,
276 const BitmapEx& /*rBitmapEx*/,
277 double /*fAlpha*/)
278 {
279 // printers can't draw bitmaps directly
280 return false;
281 }
282
TransformAndReduceBitmapExToTargetRange(const basegfx::B2DHomMatrix &,basegfx::B2DRange &,double &)283 bool Printer::TransformAndReduceBitmapExToTargetRange(
284 const basegfx::B2DHomMatrix& /*aFullTransform*/,
285 basegfx::B2DRange& /*aVisibleRange*/,
286 double& /*fMaximumArea*/)
287 {
288 // deliberately do nothing - you can't reduce the
289 // target range for a printer at all
290 return true;
291 }
292
DrawDeviceBitmap(const Point & rDestPt,const Size & rDestSize,const Point & rSrcPtPixel,const Size & rSrcSizePixel,BitmapEx & rBmpEx)293 void Printer::DrawDeviceBitmap( const Point& rDestPt, const Size& rDestSize,
294 const Point& rSrcPtPixel, const Size& rSrcSizePixel,
295 BitmapEx& rBmpEx )
296 {
297 if( rBmpEx.IsAlpha() )
298 {
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 );
305 }
306 else
307 {
308 Bitmap aBmp( rBmpEx.GetBitmap() );
309 ImplPrintTransparent( aBmp, Bitmap(), rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel );
310 }
311 }
312
EmulateDrawTransparent(const tools::PolyPolygon & rPolyPoly,sal_uInt16 nTransparencePercent)313 void Printer::EmulateDrawTransparent ( const tools::PolyPolygon& rPolyPoly,
314 sal_uInt16 nTransparencePercent )
315 {
316 // #110958# Disable alpha VDev, we perform the necessary
317 VirtualDevice* pOldAlphaVDev = mpAlphaVDev;
318
319 // operation explicitly further below.
320 if( mpAlphaVDev )
321 mpAlphaVDev = nullptr;
322
323 GDIMetaFile* pOldMetaFile = mpMetaFile;
324 mpMetaFile = nullptr;
325
326 mpMetaFile = pOldMetaFile;
327
328 // #110958# Restore disabled alpha VDev
329 mpAlphaVDev = pOldAlphaVDev;
330
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;
339
340 switch( nTrans )
341 {
342 case 25: nMove = nBaseExtent * 3; break;
343 case 50: nMove = nBaseExtent * 4; break;
344 case 75: nMove = nBaseExtent * 6; break;
345
346 // #i112959# very transparent (88 < nTransparencePercent <= 99)
347 case 100: nMove = nBaseExtent * 8; break;
348
349 // #i112959# not transparent (nTransparencePercent < 13)
350 default: nMove = 0; break;
351 }
352
353 Push( PushFlags::CLIPREGION | PushFlags::LINECOLOR );
354 IntersectClipRegion(vcl::Region(rPolyPoly));
355 SetLineColor( GetFillColor() );
356 const bool bOldMap = mbMap;
357 EnableMapMode( false );
358
359 if(nMove)
360 {
361 tools::Rectangle aRect( aPolyRect.TopLeft(), Size( aPolyRect.GetWidth(), nBaseExtent ) );
362 while( aRect.Top() <= aPolyRect.Bottom() )
363 {
364 DrawRect( aRect );
365 aRect.Move( 0, nMove );
366 }
367
368 aRect = tools::Rectangle( aPolyRect.TopLeft(), Size( nBaseExtent, aPolyRect.GetHeight() ) );
369 while( aRect.Left() <= aPolyRect.Right() )
370 {
371 DrawRect( aRect );
372 aRect.Move( nMove, 0 );
373 }
374 }
375 else
376 {
377 // #i112959# if not transparent, draw full rectangle in clip region
378 DrawRect( aPolyRect );
379 }
380
381 EnableMapMode( bOldMap );
382 Pop();
383
384 mpMetaFile = pOldMetaFile;
385
386 // #110958# Restore disabled alpha VDev
387 mpAlphaVDev = pOldAlphaVDev;
388 }
389
DrawOutDev(const Point &,const Size &,const Point &,const Size &)390 void Printer::DrawOutDev( const Point& /*rDestPt*/, const Size& /*rDestSize*/,
391 const Point& /*rSrcPt*/, const Size& /*rSrcSize*/ )
392 {
393 SAL_WARN( "vcl.gdi", "Don't use OutputDevice::DrawOutDev(...) with printer devices!" );
394 }
395
DrawOutDev(const Point &,const Size &,const Point &,const Size &,const OutputDevice &)396 void Printer::DrawOutDev( const Point& /*rDestPt*/, const Size& /*rDestSize*/,
397 const Point& /*rSrcPt*/, const Size& /*rSrcSize*/,
398 const OutputDevice& /*rOutDev*/ )
399 {
400 SAL_WARN( "vcl.gdi", "Don't use OutputDevice::DrawOutDev(...) with printer devices!" );
401 }
402
CopyArea(const Point &,const Point &,const Size &,bool)403 void Printer::CopyArea( const Point& /*rDestPt*/,
404 const Point& /*rSrcPt*/, const Size& /*rSrcSize*/,
405 bool /*bWindowInvalidate*/ )
406 {
407 SAL_WARN( "vcl.gdi", "Don't use OutputDevice::CopyArea(...) with printer devices!" );
408 }
409
GetBackgroundComponentBounds() const410 tools::Rectangle Printer::GetBackgroundComponentBounds() const
411 {
412 Point aPageOffset = Point( 0, 0 ) - this->GetPageOffsetPixel();
413 Size aSize = this->GetPaperSizePixel();
414 return tools::Rectangle( aPageOffset, aSize );
415 }
416
SetPrinterOptions(const PrinterOptions & i_rOptions)417 void Printer::SetPrinterOptions( const PrinterOptions& i_rOptions )
418 {
419 *mpPrinterOptions = i_rOptions;
420 }
421
HasMirroredGraphics() const422 bool Printer::HasMirroredGraphics() const
423 {
424 // due to a "hotfix" for AOO bug i55719, this needs to return false
425 return false;
426 }
427
SalPrinterQueueInfo()428 SalPrinterQueueInfo::SalPrinterQueueInfo()
429 {
430 mnStatus = PrintQueueFlags::NONE;
431 mnJobs = QUEUE_JOBS_DONTKNOW;
432 }
433
~SalPrinterQueueInfo()434 SalPrinterQueueInfo::~SalPrinterQueueInfo()
435 {
436 }
437
~ImplPrnQueueList()438 ImplPrnQueueList::~ImplPrnQueueList()
439 {
440 }
441
Add(std::unique_ptr<SalPrinterQueueInfo> pData)442 void ImplPrnQueueList::Add( std::unique_ptr<SalPrinterQueueInfo> pData )
443 {
444 std::unordered_map< OUString, sal_Int32 >::iterator it =
445 m_aNameToIndex.find( pData->maPrinterName );
446 if( it == m_aNameToIndex.end() )
447 {
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);
453 }
454 else // this should not happen, but ...
455 {
456 ImplPrnQueueData& rData = m_aQueueInfos[ it->second ];
457 rData.mpQueueInfo.reset();
458 rData.mpSalQueueInfo = std::move(pData);
459 }
460 }
461
Get(const OUString & rPrinter)462 ImplPrnQueueData* ImplPrnQueueList::Get( const OUString& rPrinter )
463 {
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;
470 }
471
ImplInitPrnQueueList()472 static void ImplInitPrnQueueList()
473 {
474 ImplSVData* pSVData = ImplGetSVData();
475
476 pSVData->maGDIData.mpPrinterQueueList.reset(new ImplPrnQueueList);
477
478 static const char* pEnv = getenv( "SAL_DISABLE_PRINTERLIST" );
479 if( !pEnv || !*pEnv )
480 pSVData->mpDefInst->GetPrinterQueueInfo( pSVData->maGDIData.mpPrinterQueueList.get() );
481 }
482
ImplDeletePrnQueueList()483 void ImplDeletePrnQueueList()
484 {
485 ImplSVData* pSVData = ImplGetSVData();
486 pSVData->maGDIData.mpPrinterQueueList.reset();
487 }
488
GetPrinterQueues()489 const std::vector<OUString>& Printer::GetPrinterQueues()
490 {
491 ImplSVData* pSVData = ImplGetSVData();
492 if ( !pSVData->maGDIData.mpPrinterQueueList )
493 ImplInitPrnQueueList();
494 return pSVData->maGDIData.mpPrinterQueueList->m_aPrinterList;
495 }
496
GetQueueInfo(const OUString & rPrinterName,bool bStatusUpdate)497 const QueueInfo* Printer::GetQueueInfo( const OUString& rPrinterName, bool bStatusUpdate )
498 {
499 ImplSVData* pSVData = ImplGetSVData();
500
501 if ( !pSVData->maGDIData.mpPrinterQueueList )
502 ImplInitPrnQueueList();
503
504 if ( !pSVData->maGDIData.mpPrinterQueueList )
505 return nullptr;
506
507 ImplPrnQueueData* pInfo = pSVData->maGDIData.mpPrinterQueueList->Get( rPrinterName );
508 if( pInfo )
509 {
510 if( !pInfo->mpQueueInfo || bStatusUpdate )
511 pSVData->mpDefInst->GetPrinterQueueState( pInfo->mpSalQueueInfo.get() );
512
513 if ( !pInfo->mpQueueInfo )
514 pInfo->mpQueueInfo.reset(new QueueInfo);
515
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();
523 }
524 return nullptr;
525 }
526
GetDefaultPrinterName()527 OUString Printer::GetDefaultPrinterName()
528 {
529 static const char* pEnv = getenv( "SAL_DISABLE_DEFAULTPRINTER" );
530 if( !pEnv || !*pEnv )
531 {
532 ImplSVData* pSVData = ImplGetSVData();
533
534 return pSVData->mpDefInst->GetDefaultPrinter();
535 }
536 return OUString();
537 }
538
ImplInitData()539 void Printer::ImplInitData()
540 {
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);
557
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;
565 }
566
AcquireGraphics() const567 bool Printer::AcquireGraphics() const
568 {
569 DBG_TESTSOLARMUTEX();
570
571 if ( mpGraphics )
572 return true;
573
574 mbInitLineColor = true;
575 mbInitFillColor = true;
576 mbInitFont = true;
577 mbInitTextColor = true;
578 mbInitClipRegion = true;
579
580 ImplSVData* pSVData = ImplGetSVData();
581
582 if ( mpJobGraphics )
583 mpGraphics = mpJobGraphics;
584 else if ( mpDisplayDev )
585 {
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 )
590 {
591 if ( !pSVData->maGDIData.mpLastVirGraphics )
592 break;
593 pSVData->maGDIData.mpLastVirGraphics->ReleaseGraphics();
594 mpGraphics = pVirDev->mpVirDev->AcquireGraphics();
595 }
596 // update global LRU list of virtual device graphics
597 if ( mpGraphics )
598 {
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);
605 }
606 }
607 else
608 {
609 mpGraphics = mpInfoPrinter->AcquireGraphics();
610 // if needed retry after releasing least recently used printer graphics
611 while ( !mpGraphics )
612 {
613 if ( !pSVData->maGDIData.mpLastPrnGraphics )
614 break;
615 pSVData->maGDIData.mpLastPrnGraphics->ReleaseGraphics();
616 mpGraphics = mpInfoPrinter->AcquireGraphics();
617 }
618 // update global LRU list of printer graphics
619 if ( mpGraphics )
620 {
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);
627 }
628 }
629
630 if ( mpGraphics )
631 {
632 mpGraphics->SetXORMode( (RasterOp::Invert == meRasterOp) || (RasterOp::Xor == meRasterOp), RasterOp::Invert == meRasterOp );
633 mpGraphics->setAntiAlias(bool(mnAntialiasing & AntialiasingFlags::Enable));
634 }
635
636 return mpGraphics != nullptr;
637 }
638
ImplReleaseFonts()639 void Printer::ImplReleaseFonts()
640 {
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;
650
651 mpFontInstance.clear();
652 mpDeviceFontList.reset();
653 mpDeviceFontSizeList.reset();
654 }
655
ReleaseGraphics(bool bRelease)656 void Printer::ReleaseGraphics( bool bRelease )
657 {
658 DBG_TESTSOLARMUTEX();
659
660 if ( !mpGraphics )
661 return;
662
663 // release the fonts of the physically released graphics device
664 if( bRelease )
665 ImplReleaseFonts();
666
667 ImplSVData* pSVData = ImplGetSVData();
668
669 Printer* pPrinter = this;
670
671 if ( !pPrinter->mpJobGraphics )
672 {
673 if ( pPrinter->mpDisplayDev )
674 {
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;
687 }
688 else
689 {
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());
701 }
702 }
703
704 mpGraphics = nullptr;
705 mpPrevGraphics = nullptr;
706 mpNextGraphics = nullptr;
707 }
708
ImplInit(SalPrinterQueueInfo * pInfo)709 void Printer::ImplInit( SalPrinterQueueInfo* pInfo )
710 {
711 ImplSVData* pSVData = ImplGetSVData();
712 // #i74084# update info for this specific SalPrinterQueueInfo
713 pSVData->mpDefInst->GetPrinterQueueState( pInfo );
714
715 // Test whether the driver actually matches the JobSetup
716 ImplJobSetup& rData = maJobSetup.ImplGetData();
717 if ( rData.GetDriverData() )
718 {
719 if ( rData.GetPrinterName() != pInfo->maPrinterName ||
720 rData.GetDriver() != pInfo->maDriver )
721 {
722 std::free( const_cast<sal_uInt8*>(rData.GetDriverData()) );
723 rData.SetDriverData(nullptr);
724 rData.SetDriverDataLen(0);
725 }
726 }
727
728 // Remember printer name
729 maPrinterName = pInfo->maPrinterName;
730 maDriver = pInfo->maDriver;
731
732 // Add printer name to JobSetup
733 rData.SetPrinterName( maPrinterName );
734 rData.SetDriver( maDriver );
735
736 mpInfoPrinter = pSVData->mpDefInst->CreateInfoPrinter( pInfo, &rData );
737 mpPrinter = nullptr;
738 mpJobGraphics = nullptr;
739 ImplUpdateJobSetupPaper( maJobSetup );
740
741 if ( !mpInfoPrinter )
742 {
743 ImplInitDisplay();
744 return;
745 }
746
747 // we need a graphics
748 if ( !AcquireGraphics() )
749 {
750 ImplInitDisplay();
751 return;
752 }
753
754 // Init data
755 ImplUpdatePageData();
756 mxFontCollection = std::make_shared<PhysicalFontCollection>();
757 mxFontCache = std::make_shared<ImplFontCache>();
758 mpGraphics->GetDevFontList(mxFontCollection.get());
759 }
760
ImplInitDisplay()761 void Printer::ImplInitDisplay()
762 {
763 ImplSVData* pSVData = ImplGetSVData();
764
765 mpInfoPrinter = nullptr;
766 mpPrinter = nullptr;
767 mpJobGraphics = nullptr;
768
769 mpDisplayDev = VclPtr<VirtualDevice>::Create();
770 mxFontCollection = pSVData->maGDIData.mxScreenFontList;
771 mxFontCache = pSVData->maGDIData.mxScreenFontCache;
772 mnDPIX = mpDisplayDev->mnDPIX;
773 mnDPIY = mpDisplayDev->mnDPIY;
774 }
775
DrawDeviceMask(const Bitmap & rMask,const Color & rMaskColor,const Point & rDestPt,const Size & rDestSize,const Point & rSrcPtPixel,const Size & rSrcSizePixel)776 void Printer::DrawDeviceMask( const Bitmap& rMask, const Color& rMaskColor,
777 const Point& rDestPt, const Size& rDestSize,
778 const Point& rSrcPtPixel, const Size& rSrcSizePixel )
779 {
780 Point aDestPt( LogicToPixel( rDestPt ) );
781 Size aDestSz( LogicToPixel( rDestSize ) );
782 tools::Rectangle aSrcRect( rSrcPtPixel, rSrcSizePixel );
783
784 aSrcRect.Justify();
785
786 if( !(!rMask.IsEmpty() && aSrcRect.GetWidth() && aSrcRect.GetHeight() && aDestSz.Width() && aDestSz.Height()) )
787 return;
788
789 Bitmap aMask( rMask );
790 BmpMirrorFlags nMirrFlags = BmpMirrorFlags::NONE;
791
792 if (aMask.getPixelFormat() > vcl::PixelFormat::N1_BPP)
793 aMask.Convert( BmpConversion::N1BitThreshold );
794
795 // mirrored horizontally
796 if( aDestSz.Width() < 0 )
797 {
798 aDestSz.setWidth( -aDestSz.Width() );
799 aDestPt.AdjustX( -( aDestSz.Width() - 1 ) );
800 nMirrFlags |= BmpMirrorFlags::Horizontal;
801 }
802
803 // mirrored vertically
804 if( aDestSz.Height() < 0 )
805 {
806 aDestSz.setHeight( -aDestSz.Height() );
807 aDestPt.AdjustY( -( aDestSz.Height() - 1 ) );
808 nMirrFlags |= BmpMirrorFlags::Vertical;
809 }
810
811 // source cropped?
812 if( aSrcRect != tools::Rectangle( Point(), aMask.GetSizePixel() ) )
813 aMask.Crop( aSrcRect );
814
815 // destination mirrored
816 if( nMirrFlags != BmpMirrorFlags::NONE)
817 aMask.Mirror( nMirrFlags );
818
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;
826
827 mpMetaFile = nullptr;
828 mbMap = false;
829 Push( PushFlags::FILLCOLOR | PushFlags::LINECOLOR );
830 SetLineColor( rMaskColor );
831 SetFillColor( rMaskColor );
832 InitLineColor();
833 InitFillColor();
834
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 );
838
839 for( nY = 0; nY <= nSrcHeight; nY++ )
840 pMapY[ nY ] = aDestPt.Y() + FRound( static_cast<double>(aDestSz.Height()) * nY / nSrcHeight );
841
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);
846
847 for (auto const& rectangle : aRectangles)
848 {
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
853
854 DrawRect(tools::Rectangle(aMapPt, aMapSz));
855 }
856
857 Pop();
858 mbMap = bOldMap;
859 mpMetaFile = pOldMetaFile;
860 }
861
ImplGetQueueInfo(const OUString & rPrinterName,const OUString * pDriver)862 SalPrinterQueueInfo* Printer::ImplGetQueueInfo( const OUString& rPrinterName,
863 const OUString* pDriver )
864 {
865 ImplSVData* pSVData = ImplGetSVData();
866 if ( !pSVData->maGDIData.mpPrinterQueueList )
867 ImplInitPrnQueueList();
868
869 ImplPrnQueueList* pPrnList = pSVData->maGDIData.mpPrinterQueueList.get();
870 if ( pPrnList && !pPrnList->m_aQueueInfos.empty() )
871 {
872 // first search for the printer name directly
873 ImplPrnQueueData* pInfo = pPrnList->Get( rPrinterName );
874 if( pInfo )
875 return pInfo->mpSalQueueInfo.get();
876
877 // then search case insensitive
878 for(const ImplPrnQueueData & rQueueInfo : pPrnList->m_aQueueInfos)
879 {
880 if( rQueueInfo.mpSalQueueInfo->maPrinterName.equalsIgnoreAsciiCase( rPrinterName ) )
881 return rQueueInfo.mpSalQueueInfo.get();
882 }
883
884 // then search for driver name
885 if ( pDriver )
886 {
887 for(const ImplPrnQueueData & rQueueInfo : pPrnList->m_aQueueInfos)
888 {
889 if( rQueueInfo.mpSalQueueInfo->maDriver == *pDriver )
890 return rQueueInfo.mpSalQueueInfo.get();
891 }
892 }
893
894 // then the default printer
895 pInfo = pPrnList->Get( GetDefaultPrinterName() );
896 if( pInfo )
897 return pInfo->mpSalQueueInfo.get();
898
899 // last chance: the first available printer
900 return pPrnList->m_aQueueInfos[0].mpSalQueueInfo.get();
901 }
902
903 return nullptr;
904 }
905
ImplUpdatePageData()906 void Printer::ImplUpdatePageData()
907 {
908 // we need a graphics
909 if ( !AcquireGraphics() )
910 return;
911
912 mpGraphics->GetResolution( mnDPIX, mnDPIY );
913 mpInfoPrinter->GetPageInfo( &maJobSetup.ImplGetConstData(),
914 mnOutWidth, mnOutHeight,
915 maPageOffset,
916 maPaperSize );
917 }
918
ImplUpdateFontList()919 void Printer::ImplUpdateFontList()
920 {
921 ImplUpdateFontData();
922 }
923
GetGradientStepCount(tools::Long nMinRect)924 tools::Long Printer::GetGradientStepCount( tools::Long nMinRect )
925 {
926 // use display-equivalent step size calculation
927 tools::Long nInc = (nMinRect < 800) ? 10 : 20;
928
929 return nInc;
930 }
931
Printer()932 Printer::Printer()
933 : OutputDevice(OUTDEV_PRINTER)
934 {
935 ImplInitData();
936 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( GetDefaultPrinterName(), nullptr );
937 if ( pInfo )
938 {
939 ImplInit( pInfo );
940 if ( !IsDisplayPrinter() )
941 mbDefPrinter = true;
942 }
943 else
944 ImplInitDisplay();
945 }
946
Printer(const JobSetup & rJobSetup)947 Printer::Printer( const JobSetup& rJobSetup )
948 : OutputDevice(OUTDEV_PRINTER)
949 , maJobSetup(rJobSetup)
950 {
951 ImplInitData();
952 const ImplJobSetup& rConstData = rJobSetup.ImplGetConstData();
953 OUString aDriver = rConstData.GetDriver();
954 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( rConstData.GetPrinterName(),
955 &aDriver );
956 if ( pInfo )
957 {
958 ImplInit( pInfo );
959 SetJobSetup( rJobSetup );
960 }
961 else
962 {
963 ImplInitDisplay();
964 maJobSetup = JobSetup();
965 }
966 }
967
Printer(const QueueInfo & rQueueInfo)968 Printer::Printer( const QueueInfo& rQueueInfo )
969 : OutputDevice(OUTDEV_PRINTER)
970 {
971 ImplInitData();
972 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( rQueueInfo.GetPrinterName(),
973 &rQueueInfo.GetDriver() );
974 if ( pInfo )
975 ImplInit( pInfo );
976 else
977 ImplInitDisplay();
978 }
979
Printer(const OUString & rPrinterName)980 Printer::Printer( const OUString& rPrinterName )
981 : OutputDevice(OUTDEV_PRINTER)
982 {
983 ImplInitData();
984 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( rPrinterName, nullptr );
985 if ( pInfo )
986 ImplInit( pInfo );
987 else
988 ImplInitDisplay();
989 }
990
~Printer()991 Printer::~Printer()
992 {
993 disposeOnce();
994 }
995
dispose()996 void Printer::dispose()
997 {
998 SAL_WARN_IF( IsPrinting(), "vcl.gdi", "Printer::~Printer() - Job is printing" );
999 SAL_WARN_IF( IsJobActive(), "vcl.gdi", "Printer::~Printer() - Job is active" );
1000
1001 mpPrinterOptions.reset();
1002
1003 ReleaseGraphics();
1004 if ( mpInfoPrinter )
1005 ImplGetSVData()->mpDefInst->DestroyInfoPrinter( mpInfoPrinter );
1006 if ( mpDisplayDev )
1007 mpDisplayDev.disposeAndClear();
1008 else
1009 {
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
1018 }
1019
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;
1028
1029 mpPrev.clear();
1030 mpNext.clear();
1031 OutputDevice::dispose();
1032 }
1033
GetButtonBorderSize()1034 Size Printer::GetButtonBorderSize()
1035 {
1036 Size aBrdSize(LogicToPixel(Size(20, 20), MapMode(MapUnit::Map100thMM)));
1037
1038 if (!aBrdSize.Width())
1039 aBrdSize.setWidth(1);
1040
1041 if (!aBrdSize.Height())
1042 aBrdSize.setHeight(1);
1043
1044 return aBrdSize;
1045 }
1046
GetCapabilities(PrinterCapType nType) const1047 sal_uInt32 Printer::GetCapabilities( PrinterCapType nType ) const
1048 {
1049 if ( IsDisplayPrinter() )
1050 return 0;
1051
1052 if( mpInfoPrinter )
1053 return mpInfoPrinter->GetCapabilities( &maJobSetup.ImplGetConstData(), nType );
1054 else
1055 return 0;
1056 }
1057
HasSupport(PrinterSupport eFeature) const1058 bool Printer::HasSupport( PrinterSupport eFeature ) const
1059 {
1060 switch ( eFeature )
1061 {
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;
1072 }
1073
1074 return true;
1075 }
1076
SetJobSetup(const JobSetup & rSetup)1077 bool Printer::SetJobSetup( const JobSetup& rSetup )
1078 {
1079 if ( IsDisplayPrinter() || mbInPrintPage )
1080 return false;
1081
1082 JobSetup aJobSetup = rSetup;
1083
1084 ReleaseGraphics();
1085 if ( mpInfoPrinter->SetPrinterData( &aJobSetup.ImplGetData() ) )
1086 {
1087 ImplUpdateJobSetupPaper( aJobSetup );
1088 mbNewJobSetup = true;
1089 maJobSetup = aJobSetup;
1090 ImplUpdatePageData();
1091 ImplUpdateFontList();
1092 return true;
1093 }
1094
1095 return false;
1096 }
1097
Setup(weld::Window * pWindow,PrinterSetupMode eMode)1098 bool Printer::Setup(weld::Window* pWindow, PrinterSetupMode eMode)
1099 {
1100 if ( IsDisplayPrinter() )
1101 return false;
1102
1103 if ( IsJobActive() || IsPrinting() )
1104 return false;
1105
1106 JobSetup aJobSetup = maJobSetup;
1107 ImplJobSetup& rData = aJobSetup.ImplGetData();
1108 rData.SetPrinterSetupMode( eMode );
1109 // TODO: orig page size
1110
1111 if (!pWindow)
1112 {
1113 vcl::Window* pDefWin = ImplGetDefaultWindow();
1114 pWindow = pDefWin ? pDefWin->GetFrameWeld() : nullptr;
1115 }
1116 if( !pWindow )
1117 return false;
1118
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 )
1127 {
1128 ImplUpdateJobSetupPaper( aJobSetup );
1129 mbNewJobSetup = true;
1130 maJobSetup = aJobSetup;
1131 ImplUpdatePageData();
1132 ImplUpdateFontList();
1133 return true;
1134 }
1135 return false;
1136 }
1137
SetPrinterProps(const Printer * pPrinter)1138 bool Printer::SetPrinterProps( const Printer* pPrinter )
1139 {
1140 if ( IsJobActive() || IsPrinting() )
1141 return false;
1142
1143 ImplSVData* pSVData = ImplGetSVData();
1144
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;
1152
1153 if ( pPrinter->IsDisplayPrinter() )
1154 {
1155 // Destroy old printer
1156 if ( !IsDisplayPrinter() )
1157 {
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();
1166
1167 mbInitFont = true;
1168 mbNewFont = true;
1169 mpInfoPrinter = nullptr;
1170 }
1171
1172 // Construct new printer
1173 ImplInitDisplay();
1174 return true;
1175 }
1176
1177 // Destroy old printer?
1178 if ( GetName() != pPrinter->GetName() )
1179 {
1180 ReleaseGraphics();
1181 if ( mpDisplayDev )
1182 {
1183 mpDisplayDev.disposeAndClear();
1184 }
1185 else
1186 {
1187 pSVData->mpDefInst->DestroyInfoPrinter( mpInfoPrinter );
1188
1189 mpFontInstance.clear();
1190 mpDeviceFontList.reset();
1191 mpDeviceFontSizeList.reset();
1192 mxFontCache.reset();
1193 mxFontCollection.reset();
1194 mbInitFont = true;
1195 mbNewFont = true;
1196 mpInfoPrinter = nullptr;
1197 }
1198
1199 // Construct new printer
1200 OUString aDriver = pPrinter->GetDriverName();
1201 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( pPrinter->GetName(), &aDriver );
1202 if ( pInfo )
1203 {
1204 ImplInit( pInfo );
1205 SetJobSetup( pPrinter->GetJobSetup() );
1206 }
1207 else
1208 ImplInitDisplay();
1209 }
1210 else
1211 SetJobSetup( pPrinter->GetJobSetup() );
1212
1213 return false;
1214 }
1215
SetOrientation(Orientation eOrientation)1216 bool Printer::SetOrientation( Orientation eOrientation )
1217 {
1218 if ( mbInPrintPage )
1219 return false;
1220
1221 if ( maJobSetup.ImplGetConstData().GetOrientation() != eOrientation )
1222 {
1223 JobSetup aJobSetup = maJobSetup;
1224 ImplJobSetup& rData = aJobSetup.ImplGetData();
1225
1226 rData.SetOrientation(eOrientation);
1227
1228 if ( IsDisplayPrinter() )
1229 {
1230 mbNewJobSetup = true;
1231 maJobSetup = aJobSetup;
1232 return true;
1233 }
1234
1235 ReleaseGraphics();
1236 if ( mpInfoPrinter->SetData( JobSetFlags::ORIENTATION, &rData ) )
1237 {
1238 ImplUpdateJobSetupPaper( aJobSetup );
1239 mbNewJobSetup = true;
1240 maJobSetup = aJobSetup;
1241 ImplUpdatePageData();
1242 ImplUpdateFontList();
1243 return true;
1244 }
1245 else
1246 return false;
1247 }
1248
1249 return true;
1250 }
1251
GetOrientation() const1252 Orientation Printer::GetOrientation() const
1253 {
1254 return maJobSetup.ImplGetConstData().GetOrientation();
1255 }
1256
SetPaperBin(sal_uInt16 nPaperBin)1257 bool Printer::SetPaperBin( sal_uInt16 nPaperBin )
1258 {
1259 if ( mbInPrintPage )
1260 return false;
1261
1262 if ( maJobSetup.ImplGetConstData().GetPaperBin() != nPaperBin &&
1263 nPaperBin < GetPaperBinCount() )
1264 {
1265 JobSetup aJobSetup = maJobSetup;
1266 ImplJobSetup& rData = aJobSetup.ImplGetData();
1267 rData.SetPaperBin(nPaperBin);
1268
1269 if ( IsDisplayPrinter() )
1270 {
1271 mbNewJobSetup = true;
1272 maJobSetup = aJobSetup;
1273 return true;
1274 }
1275
1276 ReleaseGraphics();
1277 if ( mpInfoPrinter->SetData( JobSetFlags::PAPERBIN, &rData ) )
1278 {
1279 ImplUpdateJobSetupPaper( aJobSetup );
1280 mbNewJobSetup = true;
1281 maJobSetup = aJobSetup;
1282 ImplUpdatePageData();
1283 ImplUpdateFontList();
1284 return true;
1285 }
1286 else
1287 return false;
1288 }
1289
1290 return true;
1291 }
1292
GetPaperBin() const1293 sal_uInt16 Printer::GetPaperBin() const
1294 {
1295 return maJobSetup.ImplGetConstData().GetPaperBin();
1296 }
1297
GetPrinterSettingsPreferred() const1298 bool Printer::GetPrinterSettingsPreferred() const
1299 {
1300 return maJobSetup.ImplGetConstData().GetPapersizeFromSetup();
1301 }
1302
1303 // dear loplugins, DO NOT REMOVE this code
1304 // it will be used in follow-up commits
SetPrinterSettingsPreferred(bool bPaperSizeFromSetup)1305 void Printer::SetPrinterSettingsPreferred( bool bPaperSizeFromSetup)
1306 {
1307 if ( maJobSetup.ImplGetConstData().GetPapersizeFromSetup() != bPaperSizeFromSetup )
1308 {
1309 JobSetup aJobSetup = maJobSetup;
1310 ImplJobSetup& rData = aJobSetup.ImplGetData();
1311 rData.SetPapersizeFromSetup(bPaperSizeFromSetup);
1312
1313 mbNewJobSetup = true;
1314 maJobSetup = aJobSetup;
1315 }
1316 }
1317
1318 // Map user paper format to an available printer paper format
ImplFindPaperFormatForUserSize(JobSetup & aJobSetup)1319 void Printer::ImplFindPaperFormatForUserSize( JobSetup& aJobSetup )
1320 {
1321 ImplJobSetup& rData = aJobSetup.ImplGetData();
1322
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());
1327
1328 // Compare all paper formats and get the appropriate one
1329 for ( int i = 0; i < nPaperCount; i++ )
1330 {
1331 const PaperInfo& rPaperInfo = GetPaperInfo( i );
1332
1333 if ( aInfo.sloppyEqual(rPaperInfo) )
1334 {
1335 rData.SetPaperFormat(
1336 ImplGetPaperFormat( rPaperInfo.getWidth(),
1337 rPaperInfo.getHeight() ));
1338 rData.SetOrientation( Orientation::Portrait );
1339 return;
1340 }
1341 }
1342
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;
1350
1351 const tools::Long nRotatedWidth = rData.GetPaperHeight();
1352 const tools::Long nRotatedHeight = rData.GetPaperWidth();
1353 PaperInfo aRotatedInfo(nRotatedWidth, nRotatedHeight);
1354
1355 for ( int i = 0; i < nPaperCount; i++ )
1356 {
1357 const PaperInfo& rPaperInfo = GetPaperInfo( i );
1358
1359 if ( aRotatedInfo.sloppyEqual( rPaperInfo ) )
1360 {
1361 rData.SetPaperFormat(
1362 ImplGetPaperFormat( rPaperInfo.getWidth(),
1363 rPaperInfo.getHeight() ));
1364 rData.SetOrientation( Orientation::Landscape );
1365 return;
1366 }
1367 }
1368 }
1369
SetPaper(Paper ePaper)1370 void Printer::SetPaper( Paper ePaper )
1371 {
1372 if ( mbInPrintPage )
1373 return;
1374
1375 if ( maJobSetup.ImplGetConstData().GetPaperFormat() == ePaper )
1376 return;
1377
1378 JobSetup aJobSetup = maJobSetup;
1379 ImplJobSetup& rData = aJobSetup.ImplGetData();
1380
1381 rData.SetPaperFormat( ePaper );
1382 if ( ePaper != PAPER_USER )
1383 {
1384 PaperInfo aInfo(ePaper);
1385 rData.SetPaperWidth( aInfo.getWidth() );
1386 rData.SetPaperHeight( aInfo.getHeight() );
1387 }
1388
1389 if ( IsDisplayPrinter() )
1390 {
1391 mbNewJobSetup = true;
1392 maJobSetup = aJobSetup;
1393 return;
1394 }
1395
1396 ReleaseGraphics();
1397 if ( ePaper == PAPER_USER )
1398 ImplFindPaperFormatForUserSize( aJobSetup );
1399 if ( mpInfoPrinter->SetData( JobSetFlags::PAPERSIZE | JobSetFlags::ORIENTATION, &rData ))
1400 {
1401 ImplUpdateJobSetupPaper( aJobSetup );
1402 mbNewJobSetup = true;
1403 maJobSetup = aJobSetup;
1404 ImplUpdatePageData();
1405 ImplUpdateFontList();
1406 }
1407 }
1408
SetPaperSizeUser(const Size & rSize)1409 bool Printer::SetPaperSizeUser( const Size& rSize )
1410 {
1411 if ( mbInPrintPage )
1412 return false;
1413
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());
1418
1419 if(!bNeedToChange)
1420 {
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());
1427
1428 bNeedToChange = maJobSetup.ImplGetConstData().GetPaperFormat() != PAPER_USER &&
1429 maJobSetup.ImplGetConstData().GetPaperFormat() != aPaper;
1430 }
1431
1432 if(bNeedToChange)
1433 {
1434 JobSetup aJobSetup = maJobSetup;
1435 ImplJobSetup& rData = aJobSetup.ImplGetData();
1436 rData.SetPaperFormat( PAPER_USER );
1437 rData.SetPaperWidth( aPageSize.Width() );
1438 rData.SetPaperHeight( aPageSize.Height() );
1439
1440 if ( IsDisplayPrinter() )
1441 {
1442 mbNewJobSetup = true;
1443 maJobSetup = aJobSetup;
1444 return true;
1445 }
1446
1447 ReleaseGraphics();
1448 ImplFindPaperFormatForUserSize( aJobSetup );
1449
1450 // Changing the paper size can also change the orientation!
1451 if ( mpInfoPrinter->SetData( JobSetFlags::PAPERSIZE | JobSetFlags::ORIENTATION, &rData ))
1452 {
1453 ImplUpdateJobSetupPaper( aJobSetup );
1454 mbNewJobSetup = true;
1455 maJobSetup = aJobSetup;
1456 ImplUpdatePageData();
1457 ImplUpdateFontList();
1458 return true;
1459 }
1460 else
1461 return false;
1462 }
1463
1464 return true;
1465 }
1466
GetPaperInfoCount() const1467 int Printer::GetPaperInfoCount() const
1468 {
1469 if( ! mpInfoPrinter )
1470 return 0;
1471 if( ! mpInfoPrinter->m_bPapersInit )
1472 mpInfoPrinter->InitPaperFormats( &maJobSetup.ImplGetConstData() );
1473 return mpInfoPrinter->m_aPaperFormats.size();
1474 }
1475
GetPaperName(Paper ePaper)1476 OUString Printer::GetPaperName( Paper ePaper )
1477 {
1478 ImplSVData* pSVData = ImplGetSVData();
1479 if( pSVData->maPaperNames.empty() )
1480 {
1481 static const int PaperIndex[] =
1482 {
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
1495 };
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]);
1499 }
1500
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();
1503 }
1504
GetPaperInfo(int nPaper) const1505 const PaperInfo& Printer::GetPaperInfo( int nPaper ) const
1506 {
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];
1514 }
1515
GetPaperSize(int nPaper)1516 Size Printer::GetPaperSize( int nPaper )
1517 {
1518 PaperInfo aInfo = GetPaperInfo( nPaper );
1519 return PixelToLogic( Size( aInfo.getWidth(), aInfo.getHeight() ) );
1520 }
1521
SetDuplexMode(DuplexMode eDuplex)1522 void Printer::SetDuplexMode( DuplexMode eDuplex )
1523 {
1524 if ( mbInPrintPage )
1525 return;
1526
1527 if ( maJobSetup.ImplGetConstData().GetDuplexMode() == eDuplex )
1528 return;
1529
1530 JobSetup aJobSetup = maJobSetup;
1531 ImplJobSetup& rData = aJobSetup.ImplGetData();
1532
1533 rData.SetDuplexMode( eDuplex );
1534
1535 if ( IsDisplayPrinter() )
1536 {
1537 mbNewJobSetup = true;
1538 maJobSetup = aJobSetup;
1539 return;
1540 }
1541
1542 ReleaseGraphics();
1543 if ( mpInfoPrinter->SetData( JobSetFlags::DUPLEXMODE, &rData ) )
1544 {
1545 ImplUpdateJobSetupPaper( aJobSetup );
1546 mbNewJobSetup = true;
1547 maJobSetup = aJobSetup;
1548 ImplUpdatePageData();
1549 ImplUpdateFontList();
1550 }
1551 }
1552
GetDuplexMode() const1553 DuplexMode Printer::GetDuplexMode() const
1554 {
1555 return maJobSetup.ImplGetConstData().GetDuplexMode();
1556 }
1557
GetPaper() const1558 Paper Printer::GetPaper() const
1559 {
1560 return maJobSetup.ImplGetConstData().GetPaperFormat();
1561 }
1562
GetPaperBinCount() const1563 sal_uInt16 Printer::GetPaperBinCount() const
1564 {
1565 if ( IsDisplayPrinter() )
1566 return 0;
1567
1568 return mpInfoPrinter->GetPaperBinCount( &maJobSetup.ImplGetConstData() );
1569 }
1570
GetPaperBinName(sal_uInt16 nPaperBin) const1571 OUString Printer::GetPaperBinName( sal_uInt16 nPaperBin ) const
1572 {
1573 if ( IsDisplayPrinter() )
1574 return OUString();
1575
1576 if ( nPaperBin < GetPaperBinCount() )
1577 return mpInfoPrinter->GetPaperBinName( &maJobSetup.ImplGetConstData(), nPaperBin );
1578 else
1579 return OUString();
1580 }
1581
SetCopyCount(sal_uInt16 nCopy,bool bCollate)1582 void Printer::SetCopyCount( sal_uInt16 nCopy, bool bCollate )
1583 {
1584 mnCopyCount = nCopy;
1585 mbCollateCopy = bCollate;
1586 }
1587
ImplSalPrinterErrorCodeToVCL(SalPrinterError nError)1588 ErrCode Printer::ImplSalPrinterErrorCodeToVCL( SalPrinterError nError )
1589 {
1590 ErrCode nVCLError;
1591 switch ( nError )
1592 {
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;
1602 }
1603
1604 return nVCLError;
1605 }
1606
EndJob()1607 void Printer::EndJob()
1608 {
1609 if ( !IsJobActive() )
1610 return;
1611
1612 SAL_WARN_IF( mbInPrintPage, "vcl.gdi", "Printer::EndJob() - StartPage() without EndPage() called" );
1613
1614 mbJobActive = false;
1615
1616 if ( mpPrinter )
1617 {
1618 ReleaseGraphics();
1619
1620 mbPrinting = false;
1621
1622 mbDevOutput = false;
1623 mpPrinter->EndJob();
1624 mpPrinter.reset();
1625 }
1626 }
1627
ImplStartPage()1628 void Printer::ImplStartPage()
1629 {
1630 if ( !IsJobActive() )
1631 return;
1632
1633 if ( !mpPrinter )
1634 return;
1635
1636 SalGraphics* pGraphics = mpPrinter->StartPage( &maJobSetup.ImplGetData(),
1637 mbNewJobSetup );
1638 if ( pGraphics )
1639 {
1640 ReleaseGraphics();
1641 mpJobGraphics = pGraphics;
1642 }
1643 mbDevOutput = true;
1644
1645 // PrintJob not aborted ???
1646 if ( IsJobActive() )
1647 mbInPrintPage = true;
1648 }
1649
ImplEndPage()1650 void Printer::ImplEndPage()
1651 {
1652 if ( !IsJobActive() )
1653 return;
1654
1655 mbInPrintPage = false;
1656
1657 if ( mpPrinter )
1658 {
1659 mpPrinter->EndPage();
1660 ReleaseGraphics();
1661 mbDevOutput = false;
1662
1663 mpJobGraphics = nullptr;
1664 mbNewJobSetup = false;
1665 }
1666 }
1667
updatePrinters()1668 void Printer::updatePrinters()
1669 {
1670 ImplSVData* pSVData = ImplGetSVData();
1671 ImplPrnQueueList* pPrnList = pSVData->maGDIData.mpPrinterQueueList.get();
1672
1673 if ( !pPrnList )
1674 return;
1675
1676 std::unique_ptr<ImplPrnQueueList> pNewList(new ImplPrnQueueList);
1677 pSVData->mpDefInst->GetPrinterQueueInfo( pNewList.get() );
1678
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++ )
1681 {
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 )
1686 {
1687 bChanged = true;
1688 }
1689 }
1690 if( !bChanged )
1691 return;
1692
1693 ImplDeletePrnQueueList();
1694 pSVData->maGDIData.mpPrinterQueueList = std::move(pNewList);
1695
1696 Application* pApp = GetpApp();
1697 if( pApp )
1698 {
1699 DataChangedEvent aDCEvt( DataChangedEventType::PRINTER );
1700 Application::ImplCallEventListenersApplicationDataChanged(&aDCEvt);
1701 Application::NotifyAllWindows( aDCEvt );
1702 }
1703 }
1704
UsePolyPolygonForComplexGradient()1705 bool Printer::UsePolyPolygonForComplexGradient()
1706 {
1707 return true;
1708 }
1709
ClipAndDrawGradientMetafile(const Gradient & rGradient,const tools::PolyPolygon & rPolyPoly)1710 void Printer::ClipAndDrawGradientMetafile ( const Gradient &rGradient, const tools::PolyPolygon &rPolyPoly )
1711 {
1712 const tools::Rectangle aBoundRect( rPolyPoly.GetBoundRect() );
1713
1714 Push( PushFlags::CLIPREGION );
1715 IntersectClipRegion(vcl::Region(rPolyPoly));
1716 DrawGradient( aBoundRect, rGradient );
1717 Pop();
1718 }
1719
SetFontOrientation(LogicalFontInstance * const pFontEntry) const1720 void Printer::SetFontOrientation( LogicalFontInstance* const pFontEntry ) const
1721 {
1722 pFontEntry->mnOrientation = pFontEntry->mxFontMetric->GetOrientation();
1723 }
1724
ClipToDeviceBounds(vcl::Region aRegion) const1725 vcl::Region Printer::ClipToDeviceBounds(vcl::Region aRegion) const
1726 {
1727 return aRegion;
1728 }
1729
GetBitmap(const Point & rSrcPt,const Size & rSize) const1730 Bitmap Printer::GetBitmap( const Point& rSrcPt, const Size& rSize ) const
1731 {
1732 SAL_WARN("vcl.gdi", "GetBitmap(): This should never be called on by a Printer instance");
1733
1734 return OutputDevice::GetBitmap( rSrcPt, rSize );
1735 }
1736
GetDeviceInfo() const1737 css::awt::DeviceInfo Printer::GetDeviceInfo() const
1738 {
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;
1748
1749 return aInfo;
1750 }
1751
1752 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1753