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 { 55 Paper ImplGetPaperFormat( long nWidth100thMM, long nHeight100thMM ) 56 { 57 PaperInfo aInfo(nWidth100thMM, nHeight100thMM); 58 aInfo.doSloppyFit(); 59 return aInfo.getPaper(); 60 } 61 62 const PaperInfo& ImplGetEmptyPaper() 63 { 64 static PaperInfo aInfo(PAPER_USER); 65 return aInfo; 66 } 67 } 68 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 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 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::uno::Sequence< css::uno::Any > aArgs(1); 127 css::beans::PropertyValue aVal; 128 aVal.Name = "nodepath"; 129 if( i_bFile ) 130 aVal.Value <<= OUString( "/org.openoffice.Office.Common/Print/Option/File" ); 131 else 132 aVal.Value <<= OUString( "/org.openoffice.Office.Common/Print/Option/Printer" ); 133 aArgs.getArray()[0] <<= aVal; 134 xConfigAccess.set( 135 xConfigProvider->createInstanceWithArguments( 136 "com.sun.star.configuration.ConfigurationAccess", aArgs ), 137 css::uno::UNO_QUERY ); 138 if( xConfigAccess.is() ) 139 { 140 css::uno::Reference< css::beans::XPropertySet > xSet( xConfigAccess, css::uno::UNO_QUERY ); 141 if( xSet.is() ) 142 { 143 sal_Int32 nValue = 0; 144 bool bValue = false; 145 if( xSet->getPropertyValue("ReduceTransparency") >>= bValue ) 146 SetReduceTransparency( bValue ); 147 if( xSet->getPropertyValue("ReducedTransparencyMode") >>= nValue ) 148 SetReducedTransparencyMode( static_cast<PrinterTransparencyMode>(nValue) ); 149 if( xSet->getPropertyValue("ReduceGradients") >>= bValue ) 150 SetReduceGradients( bValue ); 151 if( xSet->getPropertyValue("ReducedGradientMode") >>= nValue ) 152 SetReducedGradientMode( static_cast<PrinterGradientMode>(nValue) ); 153 if( xSet->getPropertyValue("ReducedGradientStepCount") >>= nValue ) 154 SetReducedGradientStepCount( static_cast<sal_uInt16>(nValue) ); 155 if( xSet->getPropertyValue("ReduceBitmaps") >>= bValue ) 156 SetReduceBitmaps( bValue ); 157 if( xSet->getPropertyValue("ReducedBitmapMode") >>= nValue ) 158 SetReducedBitmapMode( static_cast<PrinterBitmapMode>(nValue) ); 159 if( xSet->getPropertyValue("ReducedBitmapResolution") >>= nValue ) 160 SetReducedBitmapResolution( static_cast<sal_uInt16>(nValue) ); 161 if( xSet->getPropertyValue("ReducedBitmapIncludesTransparency") >>= bValue ) 162 SetReducedBitmapIncludesTransparency( bValue ); 163 if( xSet->getPropertyValue("ConvertToGreyscales") >>= bValue ) 164 SetConvertToGreyscales( bValue ); 165 if( xSet->getPropertyValue("PDFAsStandardPrintJobFormat") >>= bValue ) 166 SetPDFAsStandardPrintJobFormat( bValue ); 167 168 bSuccess = true; 169 } 170 } 171 } 172 catch( const css::uno::Exception& ) 173 { 174 } 175 } 176 catch( const css::lang::WrappedTargetException& ) 177 { 178 } 179 180 if( ! bSuccess ) 181 *this = aOldValues; 182 } 183 184 bool Printer::DrawTransformBitmapExDirect( 185 const basegfx::B2DHomMatrix& /*aFullTransform*/, 186 const BitmapEx& /*rBitmapEx*/) 187 { 188 // printers can't draw bitmaps directly 189 return false; 190 } 191 192 bool Printer::TransformAndReduceBitmapExToTargetRange( 193 const basegfx::B2DHomMatrix& /*aFullTransform*/, 194 basegfx::B2DRange& /*aVisibleRange*/, 195 double& /*fMaximumArea*/) 196 { 197 // deliberately do nothing - you can't reduce the 198 // target range for a printer at all 199 return true; 200 } 201 202 void Printer::DrawDeviceBitmap( const Point& rDestPt, const Size& rDestSize, 203 const Point& rSrcPtPixel, const Size& rSrcSizePixel, 204 BitmapEx& rBmpEx ) 205 { 206 if( rBmpEx.IsAlpha() ) 207 { 208 // #107169# For true alpha bitmaps, no longer masking the 209 // bitmap, but perform a full alpha blend against a white 210 // background here. 211 Bitmap aBmp( rBmpEx.GetBitmap() ); 212 aBmp.Blend( rBmpEx.GetAlpha(), COL_WHITE ); 213 DrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, aBmp ); 214 } 215 else 216 { 217 Bitmap aBmp( rBmpEx.GetBitmap() ), aMask( rBmpEx.GetMask() ); 218 aBmp.Replace( aMask, COL_WHITE ); 219 ImplPrintTransparent( aBmp, aMask, rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel ); 220 } 221 } 222 223 void Printer::EmulateDrawTransparent ( const tools::PolyPolygon& rPolyPoly, 224 sal_uInt16 nTransparencePercent ) 225 { 226 // #110958# Disable alpha VDev, we perform the necessary 227 VirtualDevice* pOldAlphaVDev = mpAlphaVDev; 228 229 // operation explicitly further below. 230 if( mpAlphaVDev ) 231 mpAlphaVDev = nullptr; 232 233 GDIMetaFile* pOldMetaFile = mpMetaFile; 234 mpMetaFile = nullptr; 235 236 mpMetaFile = pOldMetaFile; 237 238 // #110958# Restore disabled alpha VDev 239 mpAlphaVDev = pOldAlphaVDev; 240 241 tools::Rectangle aPolyRect( LogicToPixel( rPolyPoly ).GetBoundRect() ); 242 const Size aDPISize( LogicToPixel(Size(1, 1), MapMode(MapUnit::MapInch)) ); 243 const long nBaseExtent = std::max( FRound( aDPISize.Width() / 300. ), 1L ); 244 long nMove; 245 const sal_uInt16 nTrans = ( nTransparencePercent < 13 ) ? 0 : 246 ( nTransparencePercent < 38 ) ? 25 : 247 ( nTransparencePercent < 63 ) ? 50 : 248 ( nTransparencePercent < 88 ) ? 75 : 100; 249 250 switch( nTrans ) 251 { 252 case 25: nMove = nBaseExtent * 3; break; 253 case 50: nMove = nBaseExtent * 4; break; 254 case 75: nMove = nBaseExtent * 6; break; 255 256 // #i112959# very transparent (88 < nTransparencePercent <= 99) 257 case 100: nMove = nBaseExtent * 8; break; 258 259 // #i112959# not transparent (nTransparencePercent < 13) 260 default: nMove = 0; break; 261 } 262 263 Push( PushFlags::CLIPREGION | PushFlags::LINECOLOR ); 264 IntersectClipRegion(vcl::Region(rPolyPoly)); 265 SetLineColor( GetFillColor() ); 266 const bool bOldMap = mbMap; 267 EnableMapMode( false ); 268 269 if(nMove) 270 { 271 tools::Rectangle aRect( aPolyRect.TopLeft(), Size( aPolyRect.GetWidth(), nBaseExtent ) ); 272 while( aRect.Top() <= aPolyRect.Bottom() ) 273 { 274 DrawRect( aRect ); 275 aRect.Move( 0, nMove ); 276 } 277 278 aRect = tools::Rectangle( aPolyRect.TopLeft(), Size( nBaseExtent, aPolyRect.GetHeight() ) ); 279 while( aRect.Left() <= aPolyRect.Right() ) 280 { 281 DrawRect( aRect ); 282 aRect.Move( nMove, 0 ); 283 } 284 } 285 else 286 { 287 // #i112959# if not transparent, draw full rectangle in clip region 288 DrawRect( aPolyRect ); 289 } 290 291 EnableMapMode( bOldMap ); 292 Pop(); 293 294 mpMetaFile = pOldMetaFile; 295 296 // #110958# Restore disabled alpha VDev 297 mpAlphaVDev = pOldAlphaVDev; 298 } 299 300 void Printer::DrawOutDev( const Point& /*rDestPt*/, const Size& /*rDestSize*/, 301 const Point& /*rSrcPt*/, const Size& /*rSrcSize*/ ) 302 { 303 SAL_WARN( "vcl.gdi", "Don't use OutputDevice::DrawOutDev(...) with printer devices!" ); 304 } 305 306 void Printer::DrawOutDev( const Point& /*rDestPt*/, const Size& /*rDestSize*/, 307 const Point& /*rSrcPt*/, const Size& /*rSrcSize*/, 308 const OutputDevice& /*rOutDev*/ ) 309 { 310 SAL_WARN( "vcl.gdi", "Don't use OutputDevice::DrawOutDev(...) with printer devices!" ); 311 } 312 313 void Printer::CopyArea( const Point& /*rDestPt*/, 314 const Point& /*rSrcPt*/, const Size& /*rSrcSize*/, 315 bool /*bWindowInvalidate*/ ) 316 { 317 SAL_WARN( "vcl.gdi", "Don't use OutputDevice::CopyArea(...) with printer devices!" ); 318 } 319 320 tools::Rectangle Printer::GetBackgroundComponentBounds() const 321 { 322 Point aPageOffset = Point( 0, 0 ) - this->GetPageOffsetPixel(); 323 Size aSize = this->GetPaperSizePixel(); 324 return tools::Rectangle( aPageOffset, aSize ); 325 } 326 327 void Printer::SetPrinterOptions( const PrinterOptions& i_rOptions ) 328 { 329 *mpPrinterOptions = i_rOptions; 330 } 331 332 bool Printer::HasMirroredGraphics() const 333 { 334 // due to a "hotfix" for AOO bug i55719, this needs to return false 335 return false; 336 } 337 338 SalPrinterQueueInfo::SalPrinterQueueInfo() 339 { 340 mnStatus = PrintQueueFlags::NONE; 341 mnJobs = QUEUE_JOBS_DONTKNOW; 342 } 343 344 SalPrinterQueueInfo::~SalPrinterQueueInfo() 345 { 346 } 347 348 ImplPrnQueueList::~ImplPrnQueueList() 349 { 350 } 351 352 void ImplPrnQueueList::Add( std::unique_ptr<SalPrinterQueueInfo> pData ) 353 { 354 std::unordered_map< OUString, sal_Int32 >::iterator it = 355 m_aNameToIndex.find( pData->maPrinterName ); 356 if( it == m_aNameToIndex.end() ) 357 { 358 m_aNameToIndex[ pData->maPrinterName ] = m_aQueueInfos.size(); 359 m_aPrinterList.push_back( pData->maPrinterName ); 360 m_aQueueInfos.push_back( ImplPrnQueueData() ); 361 m_aQueueInfos.back().mpQueueInfo = nullptr; 362 m_aQueueInfos.back().mpSalQueueInfo = std::move(pData); 363 } 364 else // this should not happen, but ... 365 { 366 ImplPrnQueueData& rData = m_aQueueInfos[ it->second ]; 367 rData.mpQueueInfo.reset(); 368 rData.mpSalQueueInfo = std::move(pData); 369 } 370 } 371 372 ImplPrnQueueData* ImplPrnQueueList::Get( const OUString& rPrinter ) 373 { 374 ImplPrnQueueData* pData = nullptr; 375 std::unordered_map<OUString,sal_Int32>::iterator it = 376 m_aNameToIndex.find( rPrinter ); 377 if( it != m_aNameToIndex.end() ) 378 pData = &m_aQueueInfos[it->second]; 379 return pData; 380 } 381 382 static void ImplInitPrnQueueList() 383 { 384 ImplSVData* pSVData = ImplGetSVData(); 385 386 pSVData->maGDIData.mpPrinterQueueList.reset(new ImplPrnQueueList); 387 388 static const char* pEnv = getenv( "SAL_DISABLE_PRINTERLIST" ); 389 if( !pEnv || !*pEnv ) 390 pSVData->mpDefInst->GetPrinterQueueInfo( pSVData->maGDIData.mpPrinterQueueList.get() ); 391 } 392 393 void ImplDeletePrnQueueList() 394 { 395 ImplSVData* pSVData = ImplGetSVData(); 396 pSVData->maGDIData.mpPrinterQueueList.reset(); 397 } 398 399 const std::vector<OUString>& Printer::GetPrinterQueues() 400 { 401 ImplSVData* pSVData = ImplGetSVData(); 402 if ( !pSVData->maGDIData.mpPrinterQueueList ) 403 ImplInitPrnQueueList(); 404 return pSVData->maGDIData.mpPrinterQueueList->m_aPrinterList; 405 } 406 407 const QueueInfo* Printer::GetQueueInfo( const OUString& rPrinterName, bool bStatusUpdate ) 408 { 409 ImplSVData* pSVData = ImplGetSVData(); 410 411 if ( !pSVData->maGDIData.mpPrinterQueueList ) 412 ImplInitPrnQueueList(); 413 414 if ( !pSVData->maGDIData.mpPrinterQueueList ) 415 return nullptr; 416 417 ImplPrnQueueData* pInfo = pSVData->maGDIData.mpPrinterQueueList->Get( rPrinterName ); 418 if( pInfo ) 419 { 420 if( !pInfo->mpQueueInfo || bStatusUpdate ) 421 pSVData->mpDefInst->GetPrinterQueueState( pInfo->mpSalQueueInfo.get() ); 422 423 if ( !pInfo->mpQueueInfo ) 424 pInfo->mpQueueInfo.reset(new QueueInfo); 425 426 pInfo->mpQueueInfo->maPrinterName = pInfo->mpSalQueueInfo->maPrinterName; 427 pInfo->mpQueueInfo->maDriver = pInfo->mpSalQueueInfo->maDriver; 428 pInfo->mpQueueInfo->maLocation = pInfo->mpSalQueueInfo->maLocation; 429 pInfo->mpQueueInfo->maComment = pInfo->mpSalQueueInfo->maComment; 430 pInfo->mpQueueInfo->mnStatus = pInfo->mpSalQueueInfo->mnStatus; 431 pInfo->mpQueueInfo->mnJobs = pInfo->mpSalQueueInfo->mnJobs; 432 return pInfo->mpQueueInfo.get(); 433 } 434 return nullptr; 435 } 436 437 OUString Printer::GetDefaultPrinterName() 438 { 439 static const char* pEnv = getenv( "SAL_DISABLE_DEFAULTPRINTER" ); 440 if( !pEnv || !*pEnv ) 441 { 442 ImplSVData* pSVData = ImplGetSVData(); 443 444 return pSVData->mpDefInst->GetDefaultPrinter(); 445 } 446 return OUString(); 447 } 448 449 void Printer::ImplInitData() 450 { 451 mbDevOutput = false; 452 mbDefPrinter = false; 453 mnError = ERRCODE_NONE; 454 mnPageQueueSize = 0; 455 mnCopyCount = 1; 456 mbCollateCopy = false; 457 mbPrinting = false; 458 mbJobActive = false; 459 mbPrintFile = false; 460 mbInPrintPage = false; 461 mbNewJobSetup = false; 462 mpInfoPrinter = nullptr; 463 mpPrinter = nullptr; 464 mpDisplayDev = nullptr; 465 mpPrinterOptions.reset(new PrinterOptions); 466 467 // Add printer to the list 468 ImplSVData* pSVData = ImplGetSVData(); 469 mpNext = pSVData->maGDIData.mpFirstPrinter; 470 mpPrev = nullptr; 471 if ( mpNext ) 472 mpNext->mpPrev = this; 473 pSVData->maGDIData.mpFirstPrinter = this; 474 } 475 476 bool Printer::AcquireGraphics() const 477 { 478 DBG_TESTSOLARMUTEX(); 479 480 if ( mpGraphics ) 481 return true; 482 483 mbInitLineColor = true; 484 mbInitFillColor = true; 485 mbInitFont = true; 486 mbInitTextColor = true; 487 mbInitClipRegion = true; 488 489 ImplSVData* pSVData = ImplGetSVData(); 490 491 if ( mpJobGraphics ) 492 mpGraphics = mpJobGraphics; 493 else if ( mpDisplayDev ) 494 { 495 const VirtualDevice* pVirDev = mpDisplayDev; 496 mpGraphics = pVirDev->mpVirDev->AcquireGraphics(); 497 // if needed retry after releasing least recently used virtual device graphics 498 while ( !mpGraphics ) 499 { 500 if ( !pSVData->maGDIData.mpLastVirGraphics ) 501 break; 502 pSVData->maGDIData.mpLastVirGraphics->ReleaseGraphics(); 503 mpGraphics = pVirDev->mpVirDev->AcquireGraphics(); 504 } 505 // update global LRU list of virtual device graphics 506 if ( mpGraphics ) 507 { 508 mpNextGraphics = pSVData->maGDIData.mpFirstVirGraphics; 509 pSVData->maGDIData.mpFirstVirGraphics = const_cast<Printer*>(this); 510 if ( mpNextGraphics ) 511 mpNextGraphics->mpPrevGraphics = const_cast<Printer*>(this); 512 if ( !pSVData->maGDIData.mpLastVirGraphics ) 513 pSVData->maGDIData.mpLastVirGraphics = const_cast<Printer*>(this); 514 } 515 } 516 else 517 { 518 mpGraphics = mpInfoPrinter->AcquireGraphics(); 519 // if needed retry after releasing least recently used printer graphics 520 while ( !mpGraphics ) 521 { 522 if ( !pSVData->maGDIData.mpLastPrnGraphics ) 523 break; 524 pSVData->maGDIData.mpLastPrnGraphics->ReleaseGraphics(); 525 mpGraphics = mpInfoPrinter->AcquireGraphics(); 526 } 527 // update global LRU list of printer graphics 528 if ( mpGraphics ) 529 { 530 mpNextGraphics = pSVData->maGDIData.mpFirstPrnGraphics; 531 pSVData->maGDIData.mpFirstPrnGraphics = const_cast<Printer*>(this); 532 if ( mpNextGraphics ) 533 mpNextGraphics->mpPrevGraphics = const_cast<Printer*>(this); 534 if ( !pSVData->maGDIData.mpLastPrnGraphics ) 535 pSVData->maGDIData.mpLastPrnGraphics = const_cast<Printer*>(this); 536 } 537 } 538 539 if ( mpGraphics ) 540 { 541 mpGraphics->SetXORMode( (RasterOp::Invert == meRasterOp) || (RasterOp::Xor == meRasterOp), RasterOp::Invert == meRasterOp ); 542 mpGraphics->setAntiAliasB2DDraw(bool(mnAntialiasing & AntialiasingFlags::EnableB2dDraw)); 543 } 544 545 return mpGraphics != nullptr; 546 } 547 548 void Printer::ImplReleaseFonts() 549 { 550 #ifdef UNX 551 // HACK to fix an urgent P1 printing issue fast 552 // WinSalPrinter does not respect GetGraphics/ReleaseGraphics conventions 553 // so Printer::mpGraphics often points to a dead WinSalGraphics 554 // TODO: fix WinSalPrinter's GetGraphics/ReleaseGraphics handling 555 mpGraphics->ReleaseFonts(); 556 #endif 557 mbNewFont = true; 558 mbInitFont = true; 559 560 mpFontInstance.clear(); 561 mpDeviceFontList.reset(); 562 mpDeviceFontSizeList.reset(); 563 } 564 565 void Printer::ReleaseGraphics( bool bRelease ) 566 { 567 DBG_TESTSOLARMUTEX(); 568 569 if ( !mpGraphics ) 570 return; 571 572 // release the fonts of the physically released graphics device 573 if( bRelease ) 574 ImplReleaseFonts(); 575 576 ImplSVData* pSVData = ImplGetSVData(); 577 578 Printer* pPrinter = this; 579 580 if ( !pPrinter->mpJobGraphics ) 581 { 582 if ( pPrinter->mpDisplayDev ) 583 { 584 VirtualDevice* pVirDev = pPrinter->mpDisplayDev; 585 if ( bRelease ) 586 pVirDev->mpVirDev->ReleaseGraphics( mpGraphics ); 587 // remove from global LRU list of virtual device graphics 588 if ( mpPrevGraphics ) 589 mpPrevGraphics->mpNextGraphics = mpNextGraphics; 590 else 591 pSVData->maGDIData.mpFirstVirGraphics = mpNextGraphics; 592 if ( mpNextGraphics ) 593 mpNextGraphics->mpPrevGraphics = mpPrevGraphics; 594 else 595 pSVData->maGDIData.mpLastVirGraphics = mpPrevGraphics; 596 } 597 else 598 { 599 if ( bRelease ) 600 pPrinter->mpInfoPrinter->ReleaseGraphics( mpGraphics ); 601 // remove from global LRU list of printer graphics 602 if ( mpPrevGraphics ) 603 mpPrevGraphics->mpNextGraphics = mpNextGraphics; 604 else 605 pSVData->maGDIData.mpFirstPrnGraphics = mpNextGraphics; 606 if ( mpNextGraphics ) 607 mpNextGraphics->mpPrevGraphics = mpPrevGraphics; 608 else 609 pSVData->maGDIData.mpLastPrnGraphics = mpPrevGraphics; 610 } 611 } 612 613 mpGraphics = nullptr; 614 mpPrevGraphics = nullptr; 615 mpNextGraphics = nullptr; 616 } 617 618 void Printer::ImplInit( SalPrinterQueueInfo* pInfo ) 619 { 620 ImplSVData* pSVData = ImplGetSVData(); 621 // #i74084# update info for this specific SalPrinterQueueInfo 622 pSVData->mpDefInst->GetPrinterQueueState( pInfo ); 623 624 // Test whether the driver actually matches the JobSetup 625 ImplJobSetup& rData = maJobSetup.ImplGetData(); 626 if ( rData.GetDriverData() ) 627 { 628 if ( rData.GetPrinterName() != pInfo->maPrinterName || 629 rData.GetDriver() != pInfo->maDriver ) 630 { 631 std::free( const_cast<sal_uInt8*>(rData.GetDriverData()) ); 632 rData.SetDriverData(nullptr); 633 rData.SetDriverDataLen(0); 634 } 635 } 636 637 // Remember printer name 638 maPrinterName = pInfo->maPrinterName; 639 maDriver = pInfo->maDriver; 640 641 // Add printer name to JobSetup 642 rData.SetPrinterName( maPrinterName ); 643 rData.SetDriver( maDriver ); 644 645 mpInfoPrinter = pSVData->mpDefInst->CreateInfoPrinter( pInfo, &rData ); 646 mpPrinter = nullptr; 647 mpJobGraphics = nullptr; 648 ImplUpdateJobSetupPaper( maJobSetup ); 649 650 if ( !mpInfoPrinter ) 651 { 652 ImplInitDisplay(); 653 return; 654 } 655 656 // we need a graphics 657 if ( !AcquireGraphics() ) 658 { 659 ImplInitDisplay(); 660 return; 661 } 662 663 // Init data 664 ImplUpdatePageData(); 665 mxFontCollection = std::make_shared<PhysicalFontCollection>(); 666 mxFontCache = std::make_shared<ImplFontCache>(); 667 mpGraphics->GetDevFontList(mxFontCollection.get()); 668 } 669 670 void Printer::ImplInitDisplay() 671 { 672 ImplSVData* pSVData = ImplGetSVData(); 673 674 mpInfoPrinter = nullptr; 675 mpPrinter = nullptr; 676 mpJobGraphics = nullptr; 677 678 mpDisplayDev = VclPtr<VirtualDevice>::Create(); 679 mxFontCollection = pSVData->maGDIData.mxScreenFontList; 680 mxFontCache = pSVData->maGDIData.mxScreenFontCache; 681 mnDPIX = mpDisplayDev->mnDPIX; 682 mnDPIY = mpDisplayDev->mnDPIY; 683 } 684 685 void Printer::DrawDeviceMask( const Bitmap& rMask, const Color& rMaskColor, 686 const Point& rDestPt, const Size& rDestSize, 687 const Point& rSrcPtPixel, const Size& rSrcSizePixel ) 688 { 689 Point aDestPt( LogicToPixel( rDestPt ) ); 690 Size aDestSz( LogicToPixel( rDestSize ) ); 691 tools::Rectangle aSrcRect( rSrcPtPixel, rSrcSizePixel ); 692 693 aSrcRect.Justify(); 694 695 if( !(!rMask.IsEmpty() && aSrcRect.GetWidth() && aSrcRect.GetHeight() && aDestSz.Width() && aDestSz.Height()) ) 696 return; 697 698 Bitmap aMask( rMask ); 699 BmpMirrorFlags nMirrFlags = BmpMirrorFlags::NONE; 700 701 if( aMask.GetBitCount() > 1 ) 702 aMask.Convert( BmpConversion::N1BitThreshold ); 703 704 // mirrored horizontically 705 if( aDestSz.Width() < 0 ) 706 { 707 aDestSz.setWidth( -aDestSz.Width() ); 708 aDestPt.AdjustX( -( aDestSz.Width() - 1 ) ); 709 nMirrFlags |= BmpMirrorFlags::Horizontal; 710 } 711 712 // mirrored vertically 713 if( aDestSz.Height() < 0 ) 714 { 715 aDestSz.setHeight( -aDestSz.Height() ); 716 aDestPt.AdjustY( -( aDestSz.Height() - 1 ) ); 717 nMirrFlags |= BmpMirrorFlags::Vertical; 718 } 719 720 // source cropped? 721 if( aSrcRect != tools::Rectangle( Point(), aMask.GetSizePixel() ) ) 722 aMask.Crop( aSrcRect ); 723 724 // destination mirrored 725 if( nMirrFlags != BmpMirrorFlags::NONE) 726 aMask.Mirror( nMirrFlags ); 727 728 // do painting 729 const long nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight(); 730 long nX, nY; //, nWorkX, nWorkY, nWorkWidth, nWorkHeight; 731 std::unique_ptr<long[]> pMapX( new long[ nSrcWidth + 1 ] ); 732 std::unique_ptr<long[]> pMapY( new long[ nSrcHeight + 1 ] ); 733 GDIMetaFile* pOldMetaFile = mpMetaFile; 734 const bool bOldMap = mbMap; 735 736 mpMetaFile = nullptr; 737 mbMap = false; 738 Push( PushFlags::FILLCOLOR | PushFlags::LINECOLOR ); 739 SetLineColor( rMaskColor ); 740 SetFillColor( rMaskColor ); 741 InitLineColor(); 742 InitFillColor(); 743 744 // create forward mapping tables 745 for( nX = 0; nX <= nSrcWidth; nX++ ) 746 pMapX[ nX ] = aDestPt.X() + FRound( static_cast<double>(aDestSz.Width()) * nX / nSrcWidth ); 747 748 for( nY = 0; nY <= nSrcHeight; nY++ ) 749 pMapY[ nY ] = aDestPt.Y() + FRound( static_cast<double>(aDestSz.Height()) * nY / nSrcHeight ); 750 751 // walk through all rectangles of mask 752 const vcl::Region aWorkRgn(aMask.CreateRegion(COL_BLACK, tools::Rectangle(Point(), aMask.GetSizePixel()))); 753 RectangleVector aRectangles; 754 aWorkRgn.GetRegionRectangles(aRectangles); 755 756 for (auto const& rectangle : aRectangles) 757 { 758 const Point aMapPt(pMapX[rectangle.Left()], pMapY[rectangle.Top()]); 759 const Size aMapSz( 760 pMapX[rectangle.Right() + 1] - aMapPt.X(), // pMapX[L + W] -> L + ((R - L) + 1) -> R + 1 761 pMapY[rectangle.Bottom() + 1] - aMapPt.Y()); // same for Y 762 763 DrawRect(tools::Rectangle(aMapPt, aMapSz)); 764 } 765 766 Pop(); 767 mbMap = bOldMap; 768 mpMetaFile = pOldMetaFile; 769 } 770 771 SalPrinterQueueInfo* Printer::ImplGetQueueInfo( const OUString& rPrinterName, 772 const OUString* pDriver ) 773 { 774 ImplSVData* pSVData = ImplGetSVData(); 775 if ( !pSVData->maGDIData.mpPrinterQueueList ) 776 ImplInitPrnQueueList(); 777 778 ImplPrnQueueList* pPrnList = pSVData->maGDIData.mpPrinterQueueList.get(); 779 if ( pPrnList && !pPrnList->m_aQueueInfos.empty() ) 780 { 781 // first search for the printer name directly 782 ImplPrnQueueData* pInfo = pPrnList->Get( rPrinterName ); 783 if( pInfo ) 784 return pInfo->mpSalQueueInfo.get(); 785 786 // then search case insensitive 787 for(const ImplPrnQueueData & rQueueInfo : pPrnList->m_aQueueInfos) 788 { 789 if( rQueueInfo.mpSalQueueInfo->maPrinterName.equalsIgnoreAsciiCase( rPrinterName ) ) 790 return rQueueInfo.mpSalQueueInfo.get(); 791 } 792 793 // then search for driver name 794 if ( pDriver ) 795 { 796 for(const ImplPrnQueueData & rQueueInfo : pPrnList->m_aQueueInfos) 797 { 798 if( rQueueInfo.mpSalQueueInfo->maDriver == *pDriver ) 799 return rQueueInfo.mpSalQueueInfo.get(); 800 } 801 } 802 803 // then the default printer 804 pInfo = pPrnList->Get( GetDefaultPrinterName() ); 805 if( pInfo ) 806 return pInfo->mpSalQueueInfo.get(); 807 808 // last chance: the first available printer 809 return pPrnList->m_aQueueInfos[0].mpSalQueueInfo.get(); 810 } 811 812 return nullptr; 813 } 814 815 void Printer::ImplUpdatePageData() 816 { 817 // we need a graphics 818 if ( !AcquireGraphics() ) 819 return; 820 821 mpGraphics->GetResolution( mnDPIX, mnDPIY ); 822 mpInfoPrinter->GetPageInfo( &maJobSetup.ImplGetConstData(), 823 mnOutWidth, mnOutHeight, 824 maPageOffset, 825 maPaperSize ); 826 } 827 828 void Printer::ImplUpdateFontList() 829 { 830 ImplUpdateFontData(); 831 } 832 833 long Printer::GetGradientStepCount( long nMinRect ) 834 { 835 // use display-equivalent step size calculation 836 long nInc = (nMinRect < 800) ? 10 : 20; 837 838 return nInc; 839 } 840 841 Printer::Printer() 842 : OutputDevice(OUTDEV_PRINTER) 843 { 844 ImplInitData(); 845 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( GetDefaultPrinterName(), nullptr ); 846 if ( pInfo ) 847 { 848 ImplInit( pInfo ); 849 if ( !IsDisplayPrinter() ) 850 mbDefPrinter = true; 851 } 852 else 853 ImplInitDisplay(); 854 } 855 856 Printer::Printer( const JobSetup& rJobSetup ) 857 : OutputDevice(OUTDEV_PRINTER) 858 , maJobSetup(rJobSetup) 859 { 860 ImplInitData(); 861 const ImplJobSetup& rConstData = rJobSetup.ImplGetConstData(); 862 OUString aDriver = rConstData.GetDriver(); 863 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( rConstData.GetPrinterName(), 864 &aDriver ); 865 if ( pInfo ) 866 { 867 ImplInit( pInfo ); 868 SetJobSetup( rJobSetup ); 869 } 870 else 871 { 872 ImplInitDisplay(); 873 maJobSetup = JobSetup(); 874 } 875 } 876 877 Printer::Printer( const QueueInfo& rQueueInfo ) 878 : OutputDevice(OUTDEV_PRINTER) 879 { 880 ImplInitData(); 881 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( rQueueInfo.GetPrinterName(), 882 &rQueueInfo.GetDriver() ); 883 if ( pInfo ) 884 ImplInit( pInfo ); 885 else 886 ImplInitDisplay(); 887 } 888 889 Printer::Printer( const OUString& rPrinterName ) 890 : OutputDevice(OUTDEV_PRINTER) 891 { 892 ImplInitData(); 893 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( rPrinterName, nullptr ); 894 if ( pInfo ) 895 ImplInit( pInfo ); 896 else 897 ImplInitDisplay(); 898 } 899 900 Printer::~Printer() 901 { 902 disposeOnce(); 903 } 904 905 void Printer::dispose() 906 { 907 SAL_WARN_IF( IsPrinting(), "vcl.gdi", "Printer::~Printer() - Job is printing" ); 908 SAL_WARN_IF( IsJobActive(), "vcl.gdi", "Printer::~Printer() - Job is active" ); 909 910 mpPrinterOptions.reset(); 911 912 ReleaseGraphics(); 913 if ( mpInfoPrinter ) 914 ImplGetSVData()->mpDefInst->DestroyInfoPrinter( mpInfoPrinter ); 915 if ( mpDisplayDev ) 916 mpDisplayDev.disposeAndClear(); 917 else 918 { 919 // OutputDevice Dtor is trying the same thing; that why we need to set 920 // the FontEntry to NULL here 921 // TODO: consolidate duplicate cleanup by Printer and OutputDevice 922 mpFontInstance.clear(); 923 mpDeviceFontList.reset(); 924 mpDeviceFontSizeList.reset(); 925 mxFontCache.reset(); 926 // font list deleted by OutputDevice dtor 927 } 928 929 // Add printer from the list 930 ImplSVData* pSVData = ImplGetSVData(); 931 if ( mpPrev ) 932 mpPrev->mpNext = mpNext; 933 else 934 pSVData->maGDIData.mpFirstPrinter = mpNext; 935 if ( mpNext ) 936 mpNext->mpPrev = mpPrev; 937 938 mpPrev.clear(); 939 mpNext.clear(); 940 OutputDevice::dispose(); 941 } 942 943 Size Printer::GetButtonBorderSize() 944 { 945 Size aBrdSize(LogicToPixel(Size(20, 20), MapMode(MapUnit::Map100thMM))); 946 947 if (!aBrdSize.Width()) 948 aBrdSize.setWidth(1); 949 950 if (!aBrdSize.Height()) 951 aBrdSize.setHeight(1); 952 953 return aBrdSize; 954 } 955 956 sal_uInt32 Printer::GetCapabilities( PrinterCapType nType ) const 957 { 958 if ( IsDisplayPrinter() ) 959 return 0; 960 961 if( mpInfoPrinter ) 962 return mpInfoPrinter->GetCapabilities( &maJobSetup.ImplGetConstData(), nType ); 963 else 964 return 0; 965 } 966 967 bool Printer::HasSupport( PrinterSupport eFeature ) const 968 { 969 switch ( eFeature ) 970 { 971 case PrinterSupport::SetOrientation: 972 return GetCapabilities( PrinterCapType::SetOrientation ) != 0; 973 case PrinterSupport::SetPaperSize: 974 return GetCapabilities( PrinterCapType::SetPaperSize ) != 0; 975 case PrinterSupport::SetPaper: 976 return GetCapabilities( PrinterCapType::SetPaper ) != 0; 977 case PrinterSupport::CollateCopy: 978 return (GetCapabilities( PrinterCapType::CollateCopies ) != 0); 979 case PrinterSupport::SetupDialog: 980 return GetCapabilities( PrinterCapType::SupportDialog ) != 0; 981 } 982 983 return true; 984 } 985 986 bool Printer::SetJobSetup( const JobSetup& rSetup ) 987 { 988 if ( IsDisplayPrinter() || mbInPrintPage ) 989 return false; 990 991 JobSetup aJobSetup = rSetup; 992 993 ReleaseGraphics(); 994 if ( mpInfoPrinter->SetPrinterData( &aJobSetup.ImplGetData() ) ) 995 { 996 ImplUpdateJobSetupPaper( aJobSetup ); 997 mbNewJobSetup = true; 998 maJobSetup = aJobSetup; 999 ImplUpdatePageData(); 1000 ImplUpdateFontList(); 1001 return true; 1002 } 1003 1004 return false; 1005 } 1006 1007 bool Printer::Setup(weld::Window* pWindow, PrinterSetupMode eMode) 1008 { 1009 if ( IsDisplayPrinter() ) 1010 return false; 1011 1012 if ( IsJobActive() || IsPrinting() ) 1013 return false; 1014 1015 JobSetup aJobSetup = maJobSetup; 1016 ImplJobSetup& rData = aJobSetup.ImplGetData(); 1017 rData.SetPrinterSetupMode( eMode ); 1018 // TODO: orig page size 1019 1020 if (!pWindow) 1021 { 1022 vcl::Window* pDefWin = ImplGetDefaultWindow(); 1023 pWindow = pDefWin ? pDefWin->GetFrameWeld() : nullptr; 1024 } 1025 if( !pWindow ) 1026 return false; 1027 1028 ReleaseGraphics(); 1029 ImplSVData* pSVData = ImplGetSVData(); 1030 pSVData->maAppData.mnModalMode++; 1031 nImplSysDialog++; 1032 bool bSetup = mpInfoPrinter->Setup(pWindow, &rData); 1033 pSVData->maAppData.mnModalMode--; 1034 nImplSysDialog--; 1035 if ( bSetup ) 1036 { 1037 ImplUpdateJobSetupPaper( aJobSetup ); 1038 mbNewJobSetup = true; 1039 maJobSetup = aJobSetup; 1040 ImplUpdatePageData(); 1041 ImplUpdateFontList(); 1042 return true; 1043 } 1044 return false; 1045 } 1046 1047 bool Printer::SetPrinterProps( const Printer* pPrinter ) 1048 { 1049 if ( IsJobActive() || IsPrinting() ) 1050 return false; 1051 1052 ImplSVData* pSVData = ImplGetSVData(); 1053 1054 mbDefPrinter = pPrinter->mbDefPrinter; 1055 maPrintFile = pPrinter->maPrintFile; 1056 mbPrintFile = pPrinter->mbPrintFile; 1057 mnCopyCount = pPrinter->mnCopyCount; 1058 mbCollateCopy = pPrinter->mbCollateCopy; 1059 mnPageQueueSize = pPrinter->mnPageQueueSize; 1060 *mpPrinterOptions = *pPrinter->mpPrinterOptions; 1061 1062 if ( pPrinter->IsDisplayPrinter() ) 1063 { 1064 // Destroy old printer 1065 if ( !IsDisplayPrinter() ) 1066 { 1067 ReleaseGraphics(); 1068 pSVData->mpDefInst->DestroyInfoPrinter( mpInfoPrinter ); 1069 mpFontInstance.clear(); 1070 mpDeviceFontList.reset(); 1071 mpDeviceFontSizeList.reset(); 1072 // clean up font list 1073 mxFontCache.reset(); 1074 mxFontCollection.reset(); 1075 1076 mbInitFont = true; 1077 mbNewFont = true; 1078 mpInfoPrinter = nullptr; 1079 } 1080 1081 // Construct new printer 1082 ImplInitDisplay(); 1083 return true; 1084 } 1085 1086 // Destroy old printer? 1087 if ( GetName() != pPrinter->GetName() ) 1088 { 1089 ReleaseGraphics(); 1090 if ( mpDisplayDev ) 1091 { 1092 mpDisplayDev.disposeAndClear(); 1093 } 1094 else 1095 { 1096 pSVData->mpDefInst->DestroyInfoPrinter( mpInfoPrinter ); 1097 1098 mpFontInstance.clear(); 1099 mpDeviceFontList.reset(); 1100 mpDeviceFontSizeList.reset(); 1101 mxFontCache.reset(); 1102 mxFontCollection.reset(); 1103 mbInitFont = true; 1104 mbNewFont = true; 1105 mpInfoPrinter = nullptr; 1106 } 1107 1108 // Construct new printer 1109 OUString aDriver = pPrinter->GetDriverName(); 1110 SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( pPrinter->GetName(), &aDriver ); 1111 if ( pInfo ) 1112 { 1113 ImplInit( pInfo ); 1114 SetJobSetup( pPrinter->GetJobSetup() ); 1115 } 1116 else 1117 ImplInitDisplay(); 1118 } 1119 else 1120 SetJobSetup( pPrinter->GetJobSetup() ); 1121 1122 return false; 1123 } 1124 1125 bool Printer::SetOrientation( Orientation eOrientation ) 1126 { 1127 if ( mbInPrintPage ) 1128 return false; 1129 1130 if ( maJobSetup.ImplGetConstData().GetOrientation() != eOrientation ) 1131 { 1132 JobSetup aJobSetup = maJobSetup; 1133 ImplJobSetup& rData = aJobSetup.ImplGetData(); 1134 1135 rData.SetOrientation(eOrientation); 1136 1137 if ( IsDisplayPrinter() ) 1138 { 1139 mbNewJobSetup = true; 1140 maJobSetup = aJobSetup; 1141 return true; 1142 } 1143 1144 ReleaseGraphics(); 1145 if ( mpInfoPrinter->SetData( JobSetFlags::ORIENTATION, &rData ) ) 1146 { 1147 ImplUpdateJobSetupPaper( aJobSetup ); 1148 mbNewJobSetup = true; 1149 maJobSetup = aJobSetup; 1150 ImplUpdatePageData(); 1151 ImplUpdateFontList(); 1152 return true; 1153 } 1154 else 1155 return false; 1156 } 1157 1158 return true; 1159 } 1160 1161 Orientation Printer::GetOrientation() const 1162 { 1163 return maJobSetup.ImplGetConstData().GetOrientation(); 1164 } 1165 1166 bool Printer::SetPaperBin( sal_uInt16 nPaperBin ) 1167 { 1168 if ( mbInPrintPage ) 1169 return false; 1170 1171 if ( maJobSetup.ImplGetConstData().GetPaperBin() != nPaperBin && 1172 nPaperBin < GetPaperBinCount() ) 1173 { 1174 JobSetup aJobSetup = maJobSetup; 1175 ImplJobSetup& rData = aJobSetup.ImplGetData(); 1176 rData.SetPaperBin(nPaperBin); 1177 1178 if ( IsDisplayPrinter() ) 1179 { 1180 mbNewJobSetup = true; 1181 maJobSetup = aJobSetup; 1182 return true; 1183 } 1184 1185 ReleaseGraphics(); 1186 if ( mpInfoPrinter->SetData( JobSetFlags::PAPERBIN, &rData ) ) 1187 { 1188 ImplUpdateJobSetupPaper( aJobSetup ); 1189 mbNewJobSetup = true; 1190 maJobSetup = aJobSetup; 1191 ImplUpdatePageData(); 1192 ImplUpdateFontList(); 1193 return true; 1194 } 1195 else 1196 return false; 1197 } 1198 1199 return true; 1200 } 1201 1202 sal_uInt16 Printer::GetPaperBin() const 1203 { 1204 return maJobSetup.ImplGetConstData().GetPaperBin(); 1205 } 1206 1207 bool Printer::GetPrinterSettingsPreferred() const 1208 { 1209 return maJobSetup.ImplGetConstData().GetPapersizeFromSetup(); 1210 } 1211 1212 // dear loplugins, DO NOT REMOVE this code 1213 // it will be used in follow-up commits 1214 void Printer::SetPrinterSettingsPreferred( bool bPaperSizeFromSetup) 1215 { 1216 if ( maJobSetup.ImplGetConstData().GetPapersizeFromSetup() != bPaperSizeFromSetup ) 1217 { 1218 JobSetup aJobSetup = maJobSetup; 1219 ImplJobSetup& rData = aJobSetup.ImplGetData(); 1220 rData.SetPapersizeFromSetup(bPaperSizeFromSetup); 1221 1222 mbNewJobSetup = true; 1223 maJobSetup = aJobSetup; 1224 } 1225 } 1226 1227 // Map user paper format to an available printer paper format 1228 void Printer::ImplFindPaperFormatForUserSize( JobSetup& aJobSetup ) 1229 { 1230 ImplJobSetup& rData = aJobSetup.ImplGetData(); 1231 1232 // The angle that a landscape page will be turned counterclockwise wrt to portrait. 1233 int nLandscapeAngle = mpInfoPrinter ? mpInfoPrinter->GetLandscapeAngle( &maJobSetup.ImplGetConstData() ) : 900; 1234 int nPaperCount = GetPaperInfoCount(); 1235 PaperInfo aInfo(rData.GetPaperWidth(), rData.GetPaperHeight()); 1236 1237 // Compare all paper formats and get the appropriate one 1238 for ( int i = 0; i < nPaperCount; i++ ) 1239 { 1240 const PaperInfo& rPaperInfo = GetPaperInfo( i ); 1241 1242 if ( aInfo.sloppyEqual(rPaperInfo) ) 1243 { 1244 rData.SetPaperFormat( 1245 ImplGetPaperFormat( rPaperInfo.getWidth(), 1246 rPaperInfo.getHeight() )); 1247 rData.SetOrientation( Orientation::Portrait ); 1248 return; 1249 } 1250 } 1251 1252 // If the printer supports landscape orientation, check paper sizes again 1253 // with landscape orientation. This is necessary as a printer driver provides 1254 // all paper sizes with portrait orientation only!! 1255 if ( !(rData.GetPaperFormat() == PAPER_USER && 1256 nLandscapeAngle != 0 && 1257 HasSupport( PrinterSupport::SetOrientation ))) 1258 return; 1259 1260 const long nRotatedWidth = rData.GetPaperHeight(); 1261 const long nRotatedHeight = rData.GetPaperWidth(); 1262 PaperInfo aRotatedInfo(nRotatedWidth, nRotatedHeight); 1263 1264 for ( int i = 0; i < nPaperCount; i++ ) 1265 { 1266 const PaperInfo& rPaperInfo = GetPaperInfo( i ); 1267 1268 if ( aRotatedInfo.sloppyEqual( rPaperInfo ) ) 1269 { 1270 rData.SetPaperFormat( 1271 ImplGetPaperFormat( rPaperInfo.getWidth(), 1272 rPaperInfo.getHeight() )); 1273 rData.SetOrientation( Orientation::Landscape ); 1274 return; 1275 } 1276 } 1277 } 1278 1279 void Printer::SetPaper( Paper ePaper ) 1280 { 1281 if ( mbInPrintPage ) 1282 return; 1283 1284 if ( maJobSetup.ImplGetConstData().GetPaperFormat() == ePaper ) 1285 return; 1286 1287 JobSetup aJobSetup = maJobSetup; 1288 ImplJobSetup& rData = aJobSetup.ImplGetData(); 1289 1290 rData.SetPaperFormat( ePaper ); 1291 if ( ePaper != PAPER_USER ) 1292 { 1293 PaperInfo aInfo(ePaper); 1294 rData.SetPaperWidth( aInfo.getWidth() ); 1295 rData.SetPaperHeight( aInfo.getHeight() ); 1296 } 1297 1298 if ( IsDisplayPrinter() ) 1299 { 1300 mbNewJobSetup = true; 1301 maJobSetup = aJobSetup; 1302 return; 1303 } 1304 1305 ReleaseGraphics(); 1306 if ( ePaper == PAPER_USER ) 1307 ImplFindPaperFormatForUserSize( aJobSetup ); 1308 if ( mpInfoPrinter->SetData( JobSetFlags::PAPERSIZE | JobSetFlags::ORIENTATION, &rData )) 1309 { 1310 ImplUpdateJobSetupPaper( aJobSetup ); 1311 mbNewJobSetup = true; 1312 maJobSetup = aJobSetup; 1313 ImplUpdatePageData(); 1314 ImplUpdateFontList(); 1315 } 1316 } 1317 1318 bool Printer::SetPaperSizeUser( const Size& rSize ) 1319 { 1320 if ( mbInPrintPage ) 1321 return false; 1322 1323 const Size aPixSize = LogicToPixel( rSize ); 1324 const Size aPageSize = PixelToLogic(aPixSize, MapMode(MapUnit::Map100thMM)); 1325 bool bNeedToChange(maJobSetup.ImplGetConstData().GetPaperWidth() != aPageSize.Width() || 1326 maJobSetup.ImplGetConstData().GetPaperHeight() != aPageSize.Height()); 1327 1328 if(!bNeedToChange) 1329 { 1330 // #i122984# only need to change when Paper is different from PAPER_USER and 1331 // the mapped Paper which will created below in the call to ImplFindPaperFormatForUserSize 1332 // and will replace maJobSetup.ImplGetConstData()->GetPaperFormat(). This leads to 1333 // unnecessary JobSetups, e.g. when printing a multi-page fax, but also with 1334 // normal print 1335 const Paper aPaper = ImplGetPaperFormat(aPageSize.Width(), aPageSize.Height()); 1336 1337 bNeedToChange = maJobSetup.ImplGetConstData().GetPaperFormat() != PAPER_USER && 1338 maJobSetup.ImplGetConstData().GetPaperFormat() != aPaper; 1339 } 1340 1341 if(bNeedToChange) 1342 { 1343 JobSetup aJobSetup = maJobSetup; 1344 ImplJobSetup& rData = aJobSetup.ImplGetData(); 1345 rData.SetPaperFormat( PAPER_USER ); 1346 rData.SetPaperWidth( aPageSize.Width() ); 1347 rData.SetPaperHeight( aPageSize.Height() ); 1348 1349 if ( IsDisplayPrinter() ) 1350 { 1351 mbNewJobSetup = true; 1352 maJobSetup = aJobSetup; 1353 return true; 1354 } 1355 1356 ReleaseGraphics(); 1357 ImplFindPaperFormatForUserSize( aJobSetup ); 1358 1359 // Changing the paper size can also change the orientation! 1360 if ( mpInfoPrinter->SetData( JobSetFlags::PAPERSIZE | JobSetFlags::ORIENTATION, &rData )) 1361 { 1362 ImplUpdateJobSetupPaper( aJobSetup ); 1363 mbNewJobSetup = true; 1364 maJobSetup = aJobSetup; 1365 ImplUpdatePageData(); 1366 ImplUpdateFontList(); 1367 return true; 1368 } 1369 else 1370 return false; 1371 } 1372 1373 return true; 1374 } 1375 1376 int Printer::GetPaperInfoCount() const 1377 { 1378 if( ! mpInfoPrinter ) 1379 return 0; 1380 if( ! mpInfoPrinter->m_bPapersInit ) 1381 mpInfoPrinter->InitPaperFormats( &maJobSetup.ImplGetConstData() ); 1382 return mpInfoPrinter->m_aPaperFormats.size(); 1383 } 1384 1385 OUString Printer::GetPaperName( Paper ePaper ) 1386 { 1387 ImplSVData* pSVData = ImplGetSVData(); 1388 if( pSVData->maPaperNames.empty() ) 1389 { 1390 static const int PaperIndex[] = 1391 { 1392 PAPER_A0, PAPER_A1, PAPER_A2, PAPER_A3, PAPER_A4, PAPER_A5, PAPER_B4_ISO, PAPER_B5_ISO, 1393 PAPER_LETTER, PAPER_LEGAL, PAPER_TABLOID, PAPER_USER, PAPER_B6_ISO, PAPER_ENV_C4, PAPER_ENV_C5, 1394 PAPER_ENV_C6, PAPER_ENV_C65, PAPER_ENV_DL, PAPER_SLIDE_DIA, PAPER_SCREEN_4_3, PAPER_C, PAPER_D, 1395 PAPER_E, PAPER_EXECUTIVE, PAPER_FANFOLD_LEGAL_DE, PAPER_ENV_MONARCH, PAPER_ENV_PERSONAL, PAPER_ENV_9, 1396 PAPER_ENV_10, PAPER_ENV_11, PAPER_ENV_12, PAPER_KAI16, PAPER_KAI32, PAPER_KAI32BIG, PAPER_B4_JIS, 1397 PAPER_B5_JIS, PAPER_B6_JIS, PAPER_LEDGER, PAPER_STATEMENT, PAPER_QUARTO, PAPER_10x14, PAPER_ENV_14, 1398 PAPER_ENV_C3, PAPER_ENV_ITALY, PAPER_FANFOLD_US, PAPER_FANFOLD_DE, PAPER_POSTCARD_JP, PAPER_9x11, 1399 PAPER_10x11, PAPER_15x11, PAPER_ENV_INVITE, PAPER_A_PLUS, PAPER_B_PLUS, PAPER_LETTER_PLUS, PAPER_A4_PLUS, 1400 PAPER_DOUBLEPOSTCARD_JP, PAPER_A6, PAPER_12x11, PAPER_A7, PAPER_A8, PAPER_A9, PAPER_A10, PAPER_B0_ISO, 1401 PAPER_B1_ISO, PAPER_B2_ISO, PAPER_B3_ISO, PAPER_B7_ISO, PAPER_B8_ISO, PAPER_B9_ISO, PAPER_B10_ISO, 1402 PAPER_ENV_C2, PAPER_ENV_C7, PAPER_ENV_C8, PAPER_ARCHA, PAPER_ARCHB, PAPER_ARCHC, PAPER_ARCHD, 1403 PAPER_ARCHE, PAPER_SCREEN_16_9, PAPER_SCREEN_16_10, PAPER_16K_195x270, PAPER_16K_197x273 1404 }; 1405 assert(SAL_N_ELEMENTS(PaperIndex) == SAL_N_ELEMENTS(RID_STR_PAPERNAMES) && "localized paper name count wrong"); 1406 for (size_t i = 0; i < SAL_N_ELEMENTS(PaperIndex); ++i) 1407 pSVData->maPaperNames[PaperIndex[i]] = VclResId(RID_STR_PAPERNAMES[i]); 1408 } 1409 1410 std::unordered_map<int,OUString>::const_iterator it = pSVData->maPaperNames.find( static_cast<int>(ePaper) ); 1411 return (it != pSVData->maPaperNames.end()) ? it->second : OUString(); 1412 } 1413 1414 const PaperInfo& Printer::GetPaperInfo( int nPaper ) const 1415 { 1416 if( ! mpInfoPrinter ) 1417 return ImplGetEmptyPaper(); 1418 if( ! mpInfoPrinter->m_bPapersInit ) 1419 mpInfoPrinter->InitPaperFormats( &maJobSetup.ImplGetConstData() ); 1420 if( mpInfoPrinter->m_aPaperFormats.empty() || nPaper < 0 || nPaper >= int(mpInfoPrinter->m_aPaperFormats.size()) ) 1421 return ImplGetEmptyPaper(); 1422 return mpInfoPrinter->m_aPaperFormats[nPaper]; 1423 } 1424 1425 Size Printer::GetPaperSize( int nPaper ) 1426 { 1427 PaperInfo aInfo = GetPaperInfo( nPaper ); 1428 return PixelToLogic( Size( aInfo.getWidth(), aInfo.getHeight() ) ); 1429 } 1430 1431 void Printer::SetDuplexMode( DuplexMode eDuplex ) 1432 { 1433 if ( mbInPrintPage ) 1434 return; 1435 1436 if ( maJobSetup.ImplGetConstData().GetDuplexMode() == eDuplex ) 1437 return; 1438 1439 JobSetup aJobSetup = maJobSetup; 1440 ImplJobSetup& rData = aJobSetup.ImplGetData(); 1441 1442 rData.SetDuplexMode( eDuplex ); 1443 1444 if ( IsDisplayPrinter() ) 1445 { 1446 mbNewJobSetup = true; 1447 maJobSetup = aJobSetup; 1448 return; 1449 } 1450 1451 ReleaseGraphics(); 1452 if ( mpInfoPrinter->SetData( JobSetFlags::DUPLEXMODE, &rData ) ) 1453 { 1454 ImplUpdateJobSetupPaper( aJobSetup ); 1455 mbNewJobSetup = true; 1456 maJobSetup = aJobSetup; 1457 ImplUpdatePageData(); 1458 ImplUpdateFontList(); 1459 } 1460 } 1461 1462 DuplexMode Printer::GetDuplexMode() const 1463 { 1464 return maJobSetup.ImplGetConstData().GetDuplexMode(); 1465 } 1466 1467 Paper Printer::GetPaper() const 1468 { 1469 return maJobSetup.ImplGetConstData().GetPaperFormat(); 1470 } 1471 1472 sal_uInt16 Printer::GetPaperBinCount() const 1473 { 1474 if ( IsDisplayPrinter() ) 1475 return 0; 1476 1477 return mpInfoPrinter->GetPaperBinCount( &maJobSetup.ImplGetConstData() ); 1478 } 1479 1480 OUString Printer::GetPaperBinName( sal_uInt16 nPaperBin ) const 1481 { 1482 if ( IsDisplayPrinter() ) 1483 return OUString(); 1484 1485 if ( nPaperBin < GetPaperBinCount() ) 1486 return mpInfoPrinter->GetPaperBinName( &maJobSetup.ImplGetConstData(), nPaperBin ); 1487 else 1488 return OUString(); 1489 } 1490 1491 void Printer::SetCopyCount( sal_uInt16 nCopy, bool bCollate ) 1492 { 1493 mnCopyCount = nCopy; 1494 mbCollateCopy = bCollate; 1495 } 1496 1497 ErrCode Printer::ImplSalPrinterErrorCodeToVCL( SalPrinterError nError ) 1498 { 1499 ErrCode nVCLError; 1500 switch ( nError ) 1501 { 1502 case SalPrinterError::NONE: 1503 nVCLError = ERRCODE_NONE; 1504 break; 1505 case SalPrinterError::Abort: 1506 nVCLError = PRINTER_ABORT; 1507 break; 1508 default: 1509 nVCLError = PRINTER_GENERALERROR; 1510 break; 1511 } 1512 1513 return nVCLError; 1514 } 1515 1516 void Printer::EndJob() 1517 { 1518 if ( !IsJobActive() ) 1519 return; 1520 1521 SAL_WARN_IF( mbInPrintPage, "vcl.gdi", "Printer::EndJob() - StartPage() without EndPage() called" ); 1522 1523 mbJobActive = false; 1524 1525 if ( mpPrinter ) 1526 { 1527 ReleaseGraphics(); 1528 1529 mbPrinting = false; 1530 1531 mbDevOutput = false; 1532 mpPrinter->EndJob(); 1533 mpPrinter.reset(); 1534 } 1535 } 1536 1537 void Printer::ImplStartPage() 1538 { 1539 if ( !IsJobActive() ) 1540 return; 1541 1542 if ( !mpPrinter ) 1543 return; 1544 1545 SalGraphics* pGraphics = mpPrinter->StartPage( &maJobSetup.ImplGetData(), 1546 mbNewJobSetup ); 1547 if ( pGraphics ) 1548 { 1549 ReleaseGraphics(); 1550 mpJobGraphics = pGraphics; 1551 } 1552 mbDevOutput = true; 1553 1554 // PrintJob not aborted ??? 1555 if ( IsJobActive() ) 1556 mbInPrintPage = true; 1557 } 1558 1559 void Printer::ImplEndPage() 1560 { 1561 if ( !IsJobActive() ) 1562 return; 1563 1564 mbInPrintPage = false; 1565 1566 if ( mpPrinter ) 1567 { 1568 mpPrinter->EndPage(); 1569 ReleaseGraphics(); 1570 mbDevOutput = false; 1571 1572 mpJobGraphics = nullptr; 1573 mbNewJobSetup = false; 1574 } 1575 } 1576 1577 void Printer::updatePrinters() 1578 { 1579 ImplSVData* pSVData = ImplGetSVData(); 1580 ImplPrnQueueList* pPrnList = pSVData->maGDIData.mpPrinterQueueList.get(); 1581 1582 if ( !pPrnList ) 1583 return; 1584 1585 std::unique_ptr<ImplPrnQueueList> pNewList(new ImplPrnQueueList); 1586 pSVData->mpDefInst->GetPrinterQueueInfo( pNewList.get() ); 1587 1588 bool bChanged = pPrnList->m_aQueueInfos.size() != pNewList->m_aQueueInfos.size(); 1589 for( decltype(pPrnList->m_aQueueInfos)::size_type i = 0; ! bChanged && i < pPrnList->m_aQueueInfos.size(); i++ ) 1590 { 1591 ImplPrnQueueData& rInfo = pPrnList->m_aQueueInfos[i]; 1592 ImplPrnQueueData& rNewInfo = pNewList->m_aQueueInfos[i]; 1593 if( ! rInfo.mpSalQueueInfo || ! rNewInfo.mpSalQueueInfo || // sanity check 1594 rInfo.mpSalQueueInfo->maPrinterName != rNewInfo.mpSalQueueInfo->maPrinterName ) 1595 { 1596 bChanged = true; 1597 } 1598 } 1599 if( !bChanged ) 1600 return; 1601 1602 ImplDeletePrnQueueList(); 1603 pSVData->maGDIData.mpPrinterQueueList = std::move(pNewList); 1604 1605 Application* pApp = GetpApp(); 1606 if( pApp ) 1607 { 1608 DataChangedEvent aDCEvt( DataChangedEventType::PRINTER ); 1609 Application::ImplCallEventListenersApplicationDataChanged(&aDCEvt); 1610 Application::NotifyAllWindows( aDCEvt ); 1611 } 1612 } 1613 1614 bool Printer::UsePolyPolygonForComplexGradient() 1615 { 1616 return true; 1617 } 1618 1619 void Printer::ClipAndDrawGradientMetafile ( const Gradient &rGradient, const tools::PolyPolygon &rPolyPoly ) 1620 { 1621 const tools::Rectangle aBoundRect( rPolyPoly.GetBoundRect() ); 1622 1623 Push( PushFlags::CLIPREGION ); 1624 IntersectClipRegion(vcl::Region(rPolyPoly)); 1625 DrawGradient( aBoundRect, rGradient ); 1626 Pop(); 1627 } 1628 1629 void Printer::SetFontOrientation( LogicalFontInstance* const pFontEntry ) const 1630 { 1631 pFontEntry->mnOrientation = pFontEntry->mxFontMetric->GetOrientation(); 1632 } 1633 1634 vcl::Region Printer::ClipToDeviceBounds(vcl::Region aRegion) const 1635 { 1636 return aRegion; 1637 } 1638 1639 Bitmap Printer::GetBitmap( const Point& rSrcPt, const Size& rSize ) const 1640 { 1641 SAL_WARN("vcl.gdi", "GetBitmap(): This should never be called on by a Printer instance"); 1642 1643 return OutputDevice::GetBitmap( rSrcPt, rSize ); 1644 } 1645 1646 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 1647
