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