diff options
Diffstat (limited to 'vcl/source/gdi/print.cxx')
-rw-r--r-- | vcl/source/gdi/print.cxx | 1694 |
1 files changed, 1694 insertions, 0 deletions
diff --git a/vcl/source/gdi/print.cxx b/vcl/source/gdi/print.cxx new file mode 100644 index 000000000..001bb28e9 --- /dev/null +++ b/vcl/source/gdi/print.cxx @@ -0,0 +1,1694 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <sal/config.h> + +#include <sal/types.h> +#include <sal/log.hxx> +#include <comphelper/processfactory.hxx> +#include <o3tl/safeint.hxx> +#include <tools/debug.hxx> +#include <tools/helpers.hxx> + +#include <vcl/QueueInfo.hxx> +#include <vcl/event.hxx> +#include <vcl/virdev.hxx> +#include <vcl/print.hxx> +#include <vcl/printer/Options.hxx> + +#include <jobset.h> +#include <print.h> +#include <ImplOutDevData.hxx> +#include <font/PhysicalFontCollection.hxx> +#include <font/PhysicalFontFaceCollection.hxx> +#include <font/fontsubstitution.hxx> +#include <impfontcache.hxx> +#include <print.hrc> +#include <salgdi.hxx> +#include <salinst.hxx> +#include <salprn.hxx> +#include <salptype.hxx> +#include <salvd.hxx> +#include <svdata.hxx> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/configuration/theDefaultProvider.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/uno/Sequence.h> + +int nImplSysDialog = 0; + +namespace +{ + Paper ImplGetPaperFormat( tools::Long nWidth100thMM, tools::Long nHeight100thMM ) + { + PaperInfo aInfo(nWidth100thMM, nHeight100thMM); + aInfo.doSloppyFit(); + return aInfo.getPaper(); + } + + const PaperInfo& ImplGetEmptyPaper() + { + static PaperInfo aInfo(PAPER_USER); + return aInfo; + } +} + +void ImplUpdateJobSetupPaper( JobSetup& rJobSetup ) +{ + const ImplJobSetup& rConstData = rJobSetup.ImplGetConstData(); + + if ( !rConstData.GetPaperWidth() || !rConstData.GetPaperHeight() ) + { + if ( rConstData.GetPaperFormat() != PAPER_USER ) + { + PaperInfo aInfo(rConstData.GetPaperFormat()); + + ImplJobSetup& rData = rJobSetup.ImplGetData(); + rData.SetPaperWidth( aInfo.getWidth() ); + rData.SetPaperHeight( aInfo.getHeight() ); + } + } + else if ( rConstData.GetPaperFormat() == PAPER_USER ) + { + Paper ePaper = ImplGetPaperFormat( rConstData.GetPaperWidth(), rConstData.GetPaperHeight() ); + if ( ePaper != PAPER_USER ) + rJobSetup.ImplGetData().SetPaperFormat(ePaper); + } +} + +void Printer::ImplPrintTransparent( const Bitmap& rBmp, const Bitmap& rMask, + const Point& rDestPt, const Size& rDestSize, + const Point& rSrcPtPixel, const Size& rSrcSizePixel ) +{ + Point aDestPt( LogicToPixel( rDestPt ) ); + Size aDestSz( LogicToPixel( rDestSize ) ); + tools::Rectangle aSrcRect( rSrcPtPixel, rSrcSizePixel ); + + aSrcRect.Justify(); + + if( rBmp.IsEmpty() || !aSrcRect.GetWidth() || !aSrcRect.GetHeight() || !aDestSz.Width() || !aDestSz.Height() ) + return; + + Bitmap aPaint( rBmp ), aMask( rMask ); + BmpMirrorFlags nMirrFlags = BmpMirrorFlags::NONE; + + if (aMask.getPixelFormat() > vcl::PixelFormat::N1_BPP) + aMask.Convert( BmpConversion::N1BitThreshold ); + + // mirrored horizontally + if( aDestSz.Width() < 0 ) + { + aDestSz.setWidth( -aDestSz.Width() ); + aDestPt.AdjustX( -( aDestSz.Width() - 1 ) ); + nMirrFlags |= BmpMirrorFlags::Horizontal; + } + + // mirrored vertically + if( aDestSz.Height() < 0 ) + { + aDestSz.setHeight( -aDestSz.Height() ); + aDestPt.AdjustY( -( aDestSz.Height() - 1 ) ); + nMirrFlags |= BmpMirrorFlags::Vertical; + } + + // source cropped? + if( aSrcRect != tools::Rectangle( Point(), aPaint.GetSizePixel() ) ) + { + aPaint.Crop( aSrcRect ); + aMask.Crop( aSrcRect ); + } + + // destination mirrored + if( nMirrFlags != BmpMirrorFlags::NONE ) + { + aPaint.Mirror( nMirrFlags ); + aMask.Mirror( nMirrFlags ); + } + + // we always want to have a mask + if( aMask.IsEmpty() ) + { + aMask = Bitmap(aSrcRect.GetSize(), vcl::PixelFormat::N1_BPP); + aMask.Erase( COL_BLACK ); + } + + // do painting + const tools::Long nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight(); + tools::Long nX, nY; // , nWorkX, nWorkY, nWorkWidth, nWorkHeight; + std::unique_ptr<tools::Long[]> pMapX(new tools::Long[ nSrcWidth + 1 ]); + std::unique_ptr<tools::Long[]> pMapY(new tools::Long[ nSrcHeight + 1 ]); + const bool bOldMap = mbMap; + + mbMap = false; + + // create forward mapping tables + for( nX = 0; nX <= nSrcWidth; nX++ ) + pMapX[ nX ] = aDestPt.X() + FRound( static_cast<double>(aDestSz.Width()) * nX / nSrcWidth ); + + for( nY = 0; nY <= nSrcHeight; nY++ ) + pMapY[ nY ] = aDestPt.Y() + FRound( static_cast<double>(aDestSz.Height()) * nY / nSrcHeight ); + + // walk through all rectangles of mask + const vcl::Region aWorkRgn(aMask.CreateRegion(COL_BLACK, tools::Rectangle(Point(), aMask.GetSizePixel()))); + RectangleVector aRectangles; + aWorkRgn.GetRegionRectangles(aRectangles); + + for (auto const& rectangle : aRectangles) + { + const Point aMapPt(pMapX[rectangle.Left()], pMapY[rectangle.Top()]); + const Size aMapSz( pMapX[rectangle.Right() + 1] - aMapPt.X(), // pMapX[L + W] -> L + ((R - L) + 1) -> R + 1 + pMapY[rectangle.Bottom() + 1] - aMapPt.Y()); // same for Y + Bitmap aBandBmp(aPaint); + + aBandBmp.Crop(rectangle); + DrawBitmap(aMapPt, aMapSz, Point(), aBandBmp.GetSizePixel(), aBandBmp); + } + + mbMap = bOldMap; + +} + +bool Printer::DrawTransformBitmapExDirect( + const basegfx::B2DHomMatrix& /*aFullTransform*/, + const BitmapEx& /*rBitmapEx*/, + double /*fAlpha*/) +{ + // printers can't draw bitmaps directly + return false; +} + +bool Printer::TransformAndReduceBitmapExToTargetRange( + const basegfx::B2DHomMatrix& /*aFullTransform*/, + basegfx::B2DRange& /*aVisibleRange*/, + double& /*fMaximumArea*/) +{ + // deliberately do nothing - you can't reduce the + // target range for a printer at all + return true; +} + +void Printer::DrawDeviceBitmapEx( const Point& rDestPt, const Size& rDestSize, + const Point& rSrcPtPixel, const Size& rSrcSizePixel, + BitmapEx& rBmpEx ) +{ + if( rBmpEx.IsAlpha() ) + { + // #107169# For true alpha bitmaps, no longer masking the + // bitmap, but perform a full alpha blend against a white + // background here. + Bitmap aBmp( rBmpEx.GetBitmap() ); + aBmp.Blend( rBmpEx.GetAlpha(), COL_WHITE ); + DrawBitmap( rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel, aBmp ); + } + else + { + Bitmap aBmp( rBmpEx.GetBitmap() ); + ImplPrintTransparent( aBmp, Bitmap(), rDestPt, rDestSize, rSrcPtPixel, rSrcSizePixel ); + } +} + +void Printer::EmulateDrawTransparent ( const tools::PolyPolygon& rPolyPoly, + sal_uInt16 nTransparencePercent ) +{ + // #110958# Disable alpha VDev, we perform the necessary + VirtualDevice* pOldAlphaVDev = mpAlphaVDev; + + // operation explicitly further below. + if( mpAlphaVDev ) + mpAlphaVDev = nullptr; + + GDIMetaFile* pOldMetaFile = mpMetaFile; + mpMetaFile = nullptr; + + mpMetaFile = pOldMetaFile; + + // #110958# Restore disabled alpha VDev + mpAlphaVDev = pOldAlphaVDev; + + tools::Rectangle aPolyRect( LogicToPixel( rPolyPoly ).GetBoundRect() ); + const Size aDPISize( LogicToPixel(Size(1, 1), MapMode(MapUnit::MapInch)) ); + const tools::Long nBaseExtent = std::max<tools::Long>( FRound( aDPISize.Width() / 300. ), 1 ); + tools::Long nMove; + const sal_uInt16 nTrans = ( nTransparencePercent < 13 ) ? 0 : + ( nTransparencePercent < 38 ) ? 25 : + ( nTransparencePercent < 63 ) ? 50 : + ( nTransparencePercent < 88 ) ? 75 : 100; + + switch( nTrans ) + { + case 25: nMove = nBaseExtent * 3; break; + case 50: nMove = nBaseExtent * 4; break; + case 75: nMove = nBaseExtent * 6; break; + + // #i112959# very transparent (88 < nTransparencePercent <= 99) + case 100: nMove = nBaseExtent * 8; break; + + // #i112959# not transparent (nTransparencePercent < 13) + default: nMove = 0; break; + } + + Push( vcl::PushFlags::CLIPREGION | vcl::PushFlags::LINECOLOR ); + IntersectClipRegion(vcl::Region(rPolyPoly)); + SetLineColor( GetFillColor() ); + const bool bOldMap = mbMap; + EnableMapMode( false ); + + if(nMove) + { + tools::Rectangle aRect( aPolyRect.TopLeft(), Size( aPolyRect.GetWidth(), nBaseExtent ) ); + while( aRect.Top() <= aPolyRect.Bottom() ) + { + DrawRect( aRect ); + aRect.Move( 0, nMove ); + } + + aRect = tools::Rectangle( aPolyRect.TopLeft(), Size( nBaseExtent, aPolyRect.GetHeight() ) ); + while( aRect.Left() <= aPolyRect.Right() ) + { + DrawRect( aRect ); + aRect.Move( nMove, 0 ); + } + } + else + { + // #i112959# if not transparent, draw full rectangle in clip region + DrawRect( aPolyRect ); + } + + EnableMapMode( bOldMap ); + Pop(); + + mpMetaFile = pOldMetaFile; + + // #110958# Restore disabled alpha VDev + mpAlphaVDev = pOldAlphaVDev; +} + +void Printer::DrawOutDev( const Point& /*rDestPt*/, const Size& /*rDestSize*/, + const Point& /*rSrcPt*/, const Size& /*rSrcSize*/ ) +{ + SAL_WARN( "vcl.gdi", "Don't use OutputDevice::DrawOutDev(...) with printer devices!" ); +} + +void Printer::DrawOutDev( const Point& /*rDestPt*/, const Size& /*rDestSize*/, + const Point& /*rSrcPt*/, const Size& /*rSrcSize*/, + const OutputDevice& /*rOutDev*/ ) +{ + SAL_WARN( "vcl.gdi", "Don't use OutputDevice::DrawOutDev(...) with printer devices!" ); +} + +void Printer::CopyArea( const Point& /*rDestPt*/, + const Point& /*rSrcPt*/, const Size& /*rSrcSize*/, + bool /*bWindowInvalidate*/ ) +{ + SAL_WARN( "vcl.gdi", "Don't use OutputDevice::CopyArea(...) with printer devices!" ); +} + +tools::Rectangle Printer::GetBackgroundComponentBounds() const +{ + Point aPageOffset = Point( 0, 0 ) - this->GetPageOffsetPixel(); + Size aSize = this->GetPaperSizePixel(); + return tools::Rectangle( aPageOffset, aSize ); +} + +void Printer::SetPrinterOptions( const vcl::printer::Options& i_rOptions ) +{ + *mpPrinterOptions = i_rOptions; +} + +bool Printer::HasMirroredGraphics() const +{ + // due to a "hotfix" for AOO bug i55719, this needs to return false + return false; +} + +SalPrinterQueueInfo::SalPrinterQueueInfo() +{ + mnStatus = PrintQueueFlags::NONE; + mnJobs = QUEUE_JOBS_DONTKNOW; +} + +SalPrinterQueueInfo::~SalPrinterQueueInfo() +{ +} + +ImplPrnQueueList::~ImplPrnQueueList() +{ +} + +void ImplPrnQueueList::Add( std::unique_ptr<SalPrinterQueueInfo> pData ) +{ + std::unordered_map< OUString, sal_Int32 >::iterator it = + m_aNameToIndex.find( pData->maPrinterName ); + if( it == m_aNameToIndex.end() ) + { + m_aNameToIndex[ pData->maPrinterName ] = m_aQueueInfos.size(); + m_aPrinterList.push_back( pData->maPrinterName ); + m_aQueueInfos.push_back( ImplPrnQueueData() ); + m_aQueueInfos.back().mpQueueInfo = nullptr; + m_aQueueInfos.back().mpSalQueueInfo = std::move(pData); + } + else // this should not happen, but ... + { + ImplPrnQueueData& rData = m_aQueueInfos[ it->second ]; + rData.mpQueueInfo.reset(); + rData.mpSalQueueInfo = std::move(pData); + } +} + +ImplPrnQueueData* ImplPrnQueueList::Get( const OUString& rPrinter ) +{ + ImplPrnQueueData* pData = nullptr; + std::unordered_map<OUString,sal_Int32>::iterator it = + m_aNameToIndex.find( rPrinter ); + if( it != m_aNameToIndex.end() ) + pData = &m_aQueueInfos[it->second]; + return pData; +} + +static void ImplInitPrnQueueList() +{ + ImplSVData* pSVData = ImplGetSVData(); + + pSVData->maGDIData.mpPrinterQueueList.reset(new ImplPrnQueueList); + + static const char* pEnv = getenv( "SAL_DISABLE_PRINTERLIST" ); + if( !pEnv || !*pEnv ) + pSVData->mpDefInst->GetPrinterQueueInfo( pSVData->maGDIData.mpPrinterQueueList.get() ); +} + +void ImplDeletePrnQueueList() +{ + ImplSVData* pSVData = ImplGetSVData(); + pSVData->maGDIData.mpPrinterQueueList.reset(); +} + +const std::vector<OUString>& Printer::GetPrinterQueues() +{ + ImplSVData* pSVData = ImplGetSVData(); + if ( !pSVData->maGDIData.mpPrinterQueueList ) + ImplInitPrnQueueList(); + assert(pSVData->maGDIData.mpPrinterQueueList && "mpPrinterQueueList exists by now"); + return pSVData->maGDIData.mpPrinterQueueList->m_aPrinterList; +} + +const QueueInfo* Printer::GetQueueInfo( const OUString& rPrinterName, bool bStatusUpdate ) +{ + ImplSVData* pSVData = ImplGetSVData(); + + if ( !pSVData->maGDIData.mpPrinterQueueList ) + ImplInitPrnQueueList(); + + if ( !pSVData->maGDIData.mpPrinterQueueList ) + return nullptr; + + ImplPrnQueueData* pInfo = pSVData->maGDIData.mpPrinterQueueList->Get( rPrinterName ); + if( pInfo ) + { + if( !pInfo->mpQueueInfo || bStatusUpdate ) + pSVData->mpDefInst->GetPrinterQueueState( pInfo->mpSalQueueInfo.get() ); + + if ( !pInfo->mpQueueInfo ) + pInfo->mpQueueInfo.reset(new QueueInfo); + + pInfo->mpQueueInfo->maPrinterName = pInfo->mpSalQueueInfo->maPrinterName; + pInfo->mpQueueInfo->maDriver = pInfo->mpSalQueueInfo->maDriver; + pInfo->mpQueueInfo->maLocation = pInfo->mpSalQueueInfo->maLocation; + pInfo->mpQueueInfo->maComment = pInfo->mpSalQueueInfo->maComment; + pInfo->mpQueueInfo->mnStatus = pInfo->mpSalQueueInfo->mnStatus; + pInfo->mpQueueInfo->mnJobs = pInfo->mpSalQueueInfo->mnJobs; + return pInfo->mpQueueInfo.get(); + } + return nullptr; +} + +OUString Printer::GetDefaultPrinterName() +{ + static const char* pEnv = getenv( "SAL_DISABLE_DEFAULTPRINTER" ); + if( !pEnv || !*pEnv ) + { + ImplSVData* pSVData = ImplGetSVData(); + + return pSVData->mpDefInst->GetDefaultPrinter(); + } + return OUString(); +} + +void Printer::ImplInitData() +{ + mbDevOutput = false; + mbDefPrinter = false; + mnError = ERRCODE_NONE; + mnPageQueueSize = 0; + mnCopyCount = 1; + mbCollateCopy = false; + mbPrinting = false; + mbJobActive = false; + mbPrintFile = false; + mbInPrintPage = false; + mbNewJobSetup = false; + mbSinglePrintJobs = false; + mpInfoPrinter = nullptr; + mpPrinter = nullptr; + mpDisplayDev = nullptr; + mpPrinterOptions.reset(new vcl::printer::Options); + + // Add printer to the list + ImplSVData* pSVData = ImplGetSVData(); + mpNext = pSVData->maGDIData.mpFirstPrinter; + mpPrev = nullptr; + if ( mpNext ) + mpNext->mpPrev = this; + pSVData->maGDIData.mpFirstPrinter = this; +} + +bool Printer::AcquireGraphics() const +{ + DBG_TESTSOLARMUTEX(); + + if ( mpGraphics ) + return true; + + mbInitLineColor = true; + mbInitFillColor = true; + mbInitFont = true; + mbInitTextColor = true; + mbInitClipRegion = true; + + ImplSVData* pSVData = ImplGetSVData(); + + if ( mpJobGraphics ) + mpGraphics = mpJobGraphics; + else if ( mpDisplayDev ) + { + const VirtualDevice* pVirDev = mpDisplayDev; + mpGraphics = pVirDev->mpVirDev->AcquireGraphics(); + // if needed retry after releasing least recently used virtual device graphics + while ( !mpGraphics ) + { + if ( !pSVData->maGDIData.mpLastVirGraphics ) + break; + pSVData->maGDIData.mpLastVirGraphics->ReleaseGraphics(); + mpGraphics = pVirDev->mpVirDev->AcquireGraphics(); + } + // update global LRU list of virtual device graphics + if ( mpGraphics ) + { + mpNextGraphics = pSVData->maGDIData.mpFirstVirGraphics; + pSVData->maGDIData.mpFirstVirGraphics = const_cast<Printer*>(this); + if ( mpNextGraphics ) + mpNextGraphics->mpPrevGraphics = const_cast<Printer*>(this); + if ( !pSVData->maGDIData.mpLastVirGraphics ) + pSVData->maGDIData.mpLastVirGraphics = const_cast<Printer*>(this); + } + } + else + { + mpGraphics = mpInfoPrinter->AcquireGraphics(); + // if needed retry after releasing least recently used printer graphics + while ( !mpGraphics ) + { + if ( !pSVData->maGDIData.mpLastPrnGraphics ) + break; + pSVData->maGDIData.mpLastPrnGraphics->ReleaseGraphics(); + mpGraphics = mpInfoPrinter->AcquireGraphics(); + } + // update global LRU list of printer graphics + if ( mpGraphics ) + { + mpNextGraphics = pSVData->maGDIData.mpFirstPrnGraphics; + pSVData->maGDIData.mpFirstPrnGraphics = const_cast<Printer*>(this); + if ( mpNextGraphics ) + mpNextGraphics->mpPrevGraphics = const_cast<Printer*>(this); + if ( !pSVData->maGDIData.mpLastPrnGraphics ) + pSVData->maGDIData.mpLastPrnGraphics = const_cast<Printer*>(this); + } + } + + if ( mpGraphics ) + { + mpGraphics->SetXORMode( (RasterOp::Invert == meRasterOp) || (RasterOp::Xor == meRasterOp), RasterOp::Invert == meRasterOp ); + mpGraphics->setAntiAlias(bool(mnAntialiasing & AntialiasingFlags::Enable)); + } + + return mpGraphics != nullptr; +} + +void Printer::ImplReleaseFonts() +{ + mpGraphics->ReleaseFonts(); + mbNewFont = true; + mbInitFont = true; + + mpFontInstance.clear(); + mpFontFaceCollection.reset(); +} + +void Printer::ImplReleaseGraphics(bool bRelease) +{ + DBG_TESTSOLARMUTEX(); + + if ( !mpGraphics ) + return; + + // release the fonts of the physically released graphics device + if( bRelease ) + ImplReleaseFonts(); + + ImplSVData* pSVData = ImplGetSVData(); + + Printer* pPrinter = this; + + if ( !pPrinter->mpJobGraphics ) + { + if ( pPrinter->mpDisplayDev ) + { + VirtualDevice* pVirDev = pPrinter->mpDisplayDev; + if ( bRelease ) + pVirDev->mpVirDev->ReleaseGraphics( mpGraphics ); + // remove from global LRU list of virtual device graphics + if ( mpPrevGraphics ) + mpPrevGraphics->mpNextGraphics = mpNextGraphics; + else + pSVData->maGDIData.mpFirstVirGraphics = mpNextGraphics; + if ( mpNextGraphics ) + mpNextGraphics->mpPrevGraphics = mpPrevGraphics; + else + pSVData->maGDIData.mpLastVirGraphics = mpPrevGraphics; + } + else + { + if ( bRelease ) + pPrinter->mpInfoPrinter->ReleaseGraphics( mpGraphics ); + // remove from global LRU list of printer graphics + if ( mpPrevGraphics ) + mpPrevGraphics->mpNextGraphics = mpNextGraphics; + else + pSVData->maGDIData.mpFirstPrnGraphics = static_cast<Printer*>(mpNextGraphics.get()); + if ( mpNextGraphics ) + mpNextGraphics->mpPrevGraphics = mpPrevGraphics; + else + pSVData->maGDIData.mpLastPrnGraphics = static_cast<Printer*>(mpPrevGraphics.get()); + } + } + + mpGraphics = nullptr; + mpPrevGraphics = nullptr; + mpNextGraphics = nullptr; +} + +void Printer::ReleaseGraphics(bool bRelease) +{ + ImplReleaseGraphics(bRelease); +} + +void Printer::ImplInit( SalPrinterQueueInfo* pInfo ) +{ + ImplSVData* pSVData = ImplGetSVData(); + // #i74084# update info for this specific SalPrinterQueueInfo + pSVData->mpDefInst->GetPrinterQueueState( pInfo ); + + // Test whether the driver actually matches the JobSetup + ImplJobSetup& rData = maJobSetup.ImplGetData(); + if ( rData.GetDriverData() ) + { + if ( rData.GetPrinterName() != pInfo->maPrinterName || + rData.GetDriver() != pInfo->maDriver ) + { + std::free( const_cast<sal_uInt8*>(rData.GetDriverData()) ); + rData.SetDriverData(nullptr); + rData.SetDriverDataLen(0); + } + } + + // Remember printer name + maPrinterName = pInfo->maPrinterName; + maDriver = pInfo->maDriver; + + // Add printer name to JobSetup + rData.SetPrinterName( maPrinterName ); + rData.SetDriver( maDriver ); + + mpInfoPrinter = pSVData->mpDefInst->CreateInfoPrinter( pInfo, &rData ); + mpPrinter = nullptr; + mpJobGraphics = nullptr; + ImplUpdateJobSetupPaper( maJobSetup ); + + if ( !mpInfoPrinter ) + { + ImplInitDisplay(); + return; + } + + // we need a graphics + if ( !AcquireGraphics() ) + { + ImplInitDisplay(); + return; + } + + // Init data + ImplUpdatePageData(); + mxFontCollection = std::make_shared<vcl::font::PhysicalFontCollection>(); + mxFontCache = std::make_shared<ImplFontCache>(); + mpGraphics->GetDevFontList(mxFontCollection.get()); +} + +void Printer::ImplInitDisplay() +{ + ImplSVData* pSVData = ImplGetSVData(); + + mpInfoPrinter = nullptr; + mpPrinter = nullptr; + mpJobGraphics = nullptr; + + mpDisplayDev = VclPtr<VirtualDevice>::Create(); + mxFontCollection = pSVData->maGDIData.mxScreenFontList; + mxFontCache = pSVData->maGDIData.mxScreenFontCache; + mnDPIX = mpDisplayDev->mnDPIX; + mnDPIY = mpDisplayDev->mnDPIY; +} + +void Printer::DrawDeviceMask( const Bitmap& rMask, const Color& rMaskColor, + const Point& rDestPt, const Size& rDestSize, + const Point& rSrcPtPixel, const Size& rSrcSizePixel ) +{ + Point aDestPt( LogicToPixel( rDestPt ) ); + Size aDestSz( LogicToPixel( rDestSize ) ); + tools::Rectangle aSrcRect( rSrcPtPixel, rSrcSizePixel ); + + aSrcRect.Justify(); + + if( !(!rMask.IsEmpty() && aSrcRect.GetWidth() && aSrcRect.GetHeight() && aDestSz.Width() && aDestSz.Height()) ) + return; + + Bitmap aMask( rMask ); + BmpMirrorFlags nMirrFlags = BmpMirrorFlags::NONE; + + if (aMask.getPixelFormat() > vcl::PixelFormat::N1_BPP) + aMask.Convert( BmpConversion::N1BitThreshold ); + + // mirrored horizontally + if( aDestSz.Width() < 0 ) + { + aDestSz.setWidth( -aDestSz.Width() ); + aDestPt.AdjustX( -( aDestSz.Width() - 1 ) ); + nMirrFlags |= BmpMirrorFlags::Horizontal; + } + + // mirrored vertically + if( aDestSz.Height() < 0 ) + { + aDestSz.setHeight( -aDestSz.Height() ); + aDestPt.AdjustY( -( aDestSz.Height() - 1 ) ); + nMirrFlags |= BmpMirrorFlags::Vertical; + } + + // source cropped? + if( aSrcRect != tools::Rectangle( Point(), aMask.GetSizePixel() ) ) + aMask.Crop( aSrcRect ); + + // destination mirrored + if( nMirrFlags != BmpMirrorFlags::NONE) + aMask.Mirror( nMirrFlags ); + + // do painting + const tools::Long nSrcWidth = aSrcRect.GetWidth(), nSrcHeight = aSrcRect.GetHeight(); + tools::Long nX, nY; //, nWorkX, nWorkY, nWorkWidth, nWorkHeight; + std::unique_ptr<tools::Long[]> pMapX( new tools::Long[ nSrcWidth + 1 ] ); + std::unique_ptr<tools::Long[]> pMapY( new tools::Long[ nSrcHeight + 1 ] ); + GDIMetaFile* pOldMetaFile = mpMetaFile; + const bool bOldMap = mbMap; + + mpMetaFile = nullptr; + mbMap = false; + Push( vcl::PushFlags::FILLCOLOR | vcl::PushFlags::LINECOLOR ); + SetLineColor( rMaskColor ); + SetFillColor( rMaskColor ); + InitLineColor(); + InitFillColor(); + + // create forward mapping tables + for( nX = 0; nX <= nSrcWidth; nX++ ) + pMapX[ nX ] = aDestPt.X() + FRound( static_cast<double>(aDestSz.Width()) * nX / nSrcWidth ); + + for( nY = 0; nY <= nSrcHeight; nY++ ) + pMapY[ nY ] = aDestPt.Y() + FRound( static_cast<double>(aDestSz.Height()) * nY / nSrcHeight ); + + // walk through all rectangles of mask + const vcl::Region aWorkRgn(aMask.CreateRegion(COL_BLACK, tools::Rectangle(Point(), aMask.GetSizePixel()))); + RectangleVector aRectangles; + aWorkRgn.GetRegionRectangles(aRectangles); + + for (auto const& rectangle : aRectangles) + { + const Point aMapPt(pMapX[rectangle.Left()], pMapY[rectangle.Top()]); + const Size aMapSz( + pMapX[rectangle.Right() + 1] - aMapPt.X(), // pMapX[L + W] -> L + ((R - L) + 1) -> R + 1 + pMapY[rectangle.Bottom() + 1] - aMapPt.Y()); // same for Y + + DrawRect(tools::Rectangle(aMapPt, aMapSz)); + } + + Pop(); + mbMap = bOldMap; + mpMetaFile = pOldMetaFile; +} + +SalPrinterQueueInfo* Printer::ImplGetQueueInfo( const OUString& rPrinterName, + const OUString* pDriver ) +{ + ImplSVData* pSVData = ImplGetSVData(); + if ( !pSVData->maGDIData.mpPrinterQueueList ) + ImplInitPrnQueueList(); + + ImplPrnQueueList* pPrnList = pSVData->maGDIData.mpPrinterQueueList.get(); + if ( pPrnList && !pPrnList->m_aQueueInfos.empty() ) + { + // first search for the printer name directly + ImplPrnQueueData* pInfo = pPrnList->Get( rPrinterName ); + if( pInfo ) + return pInfo->mpSalQueueInfo.get(); + + // then search case insensitive + for(const ImplPrnQueueData & rQueueInfo : pPrnList->m_aQueueInfos) + { + if( rQueueInfo.mpSalQueueInfo->maPrinterName.equalsIgnoreAsciiCase( rPrinterName ) ) + return rQueueInfo.mpSalQueueInfo.get(); + } + + // then search for driver name + if ( pDriver ) + { + for(const ImplPrnQueueData & rQueueInfo : pPrnList->m_aQueueInfos) + { + if( rQueueInfo.mpSalQueueInfo->maDriver == *pDriver ) + return rQueueInfo.mpSalQueueInfo.get(); + } + } + + // then the default printer + pInfo = pPrnList->Get( GetDefaultPrinterName() ); + if( pInfo ) + return pInfo->mpSalQueueInfo.get(); + + // last chance: the first available printer + return pPrnList->m_aQueueInfos[0].mpSalQueueInfo.get(); + } + + return nullptr; +} + +void Printer::ImplUpdatePageData() +{ + // we need a graphics + if ( !AcquireGraphics() ) + return; + + mpGraphics->GetResolution( mnDPIX, mnDPIY ); + mpInfoPrinter->GetPageInfo( &maJobSetup.ImplGetConstData(), + mnOutWidth, mnOutHeight, + maPageOffset, + maPaperSize ); +} + +void Printer::ImplUpdateFontList() +{ + ImplUpdateFontData(); +} + +tools::Long Printer::GetGradientStepCount( tools::Long nMinRect ) +{ + // use display-equivalent step size calculation + tools::Long nInc = (nMinRect < 800) ? 10 : 20; + + return nInc; +} + +Printer::Printer() + : OutputDevice(OUTDEV_PRINTER) +{ + ImplInitData(); + SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( GetDefaultPrinterName(), nullptr ); + if ( pInfo ) + { + ImplInit( pInfo ); + if ( !IsDisplayPrinter() ) + mbDefPrinter = true; + } + else + ImplInitDisplay(); +} + +Printer::Printer( const JobSetup& rJobSetup ) + : OutputDevice(OUTDEV_PRINTER) + , maJobSetup(rJobSetup) +{ + ImplInitData(); + const ImplJobSetup& rConstData = rJobSetup.ImplGetConstData(); + OUString aDriver = rConstData.GetDriver(); + SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( rConstData.GetPrinterName(), + &aDriver ); + if ( pInfo ) + { + ImplInit( pInfo ); + SetJobSetup( rJobSetup ); + } + else + { + ImplInitDisplay(); + maJobSetup = JobSetup(); + } +} + +Printer::Printer( const QueueInfo& rQueueInfo ) + : OutputDevice(OUTDEV_PRINTER) +{ + ImplInitData(); + SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( rQueueInfo.GetPrinterName(), + &rQueueInfo.GetDriver() ); + if ( pInfo ) + ImplInit( pInfo ); + else + ImplInitDisplay(); +} + +Printer::Printer( const OUString& rPrinterName ) + : OutputDevice(OUTDEV_PRINTER) +{ + ImplInitData(); + SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( rPrinterName, nullptr ); + if ( pInfo ) + ImplInit( pInfo ); + else + ImplInitDisplay(); +} + +Printer::~Printer() +{ + disposeOnce(); +} + +void Printer::dispose() +{ + SAL_WARN_IF( IsPrinting(), "vcl.gdi", "Printer::~Printer() - Job is printing" ); + SAL_WARN_IF( IsJobActive(), "vcl.gdi", "Printer::~Printer() - Job is active" ); + + mpPrinterOptions.reset(); + + ImplReleaseGraphics(); + if ( mpInfoPrinter ) + ImplGetSVData()->mpDefInst->DestroyInfoPrinter( mpInfoPrinter ); + if ( mpDisplayDev ) + mpDisplayDev.disposeAndClear(); + else + { + // OutputDevice Dtor is trying the same thing; that why we need to set + // the FontEntry to NULL here + // TODO: consolidate duplicate cleanup by Printer and OutputDevice + mpFontInstance.clear(); + mpFontFaceCollection.reset(); + mxFontCache.reset(); + // font list deleted by OutputDevice dtor + } + + // Add printer from the list + ImplSVData* pSVData = ImplGetSVData(); + if ( mpPrev ) + mpPrev->mpNext = mpNext; + else + pSVData->maGDIData.mpFirstPrinter = mpNext; + if ( mpNext ) + mpNext->mpPrev = mpPrev; + + mpPrev.clear(); + mpNext.clear(); + OutputDevice::dispose(); +} + +Size Printer::GetButtonBorderSize() +{ + Size aBrdSize(LogicToPixel(Size(20, 20), MapMode(MapUnit::Map100thMM))); + + if (!aBrdSize.Width()) + aBrdSize.setWidth(1); + + if (!aBrdSize.Height()) + aBrdSize.setHeight(1); + + return aBrdSize; +} + +sal_uInt32 Printer::GetCapabilities( PrinterCapType nType ) const +{ + if ( IsDisplayPrinter() ) + return 0; + + if( mpInfoPrinter ) + return mpInfoPrinter->GetCapabilities( &maJobSetup.ImplGetConstData(), nType ); + else + return 0; +} + +bool Printer::HasSupport( PrinterSupport eFeature ) const +{ + switch ( eFeature ) + { + case PrinterSupport::SetOrientation: + return GetCapabilities( PrinterCapType::SetOrientation ) != 0; + case PrinterSupport::SetPaperSize: + return GetCapabilities( PrinterCapType::SetPaperSize ) != 0; + case PrinterSupport::SetPaper: + return GetCapabilities( PrinterCapType::SetPaper ) != 0; + case PrinterSupport::CollateCopy: + return (GetCapabilities( PrinterCapType::CollateCopies ) != 0); + case PrinterSupport::SetupDialog: + return GetCapabilities( PrinterCapType::SupportDialog ) != 0; + } + + return true; +} + +bool Printer::SetJobSetup( const JobSetup& rSetup ) +{ + if ( IsDisplayPrinter() || mbInPrintPage ) + return false; + + JobSetup aJobSetup = rSetup; + + ReleaseGraphics(); + if ( mpInfoPrinter->SetPrinterData( &aJobSetup.ImplGetData() ) ) + { + ImplUpdateJobSetupPaper( aJobSetup ); + mbNewJobSetup = true; + maJobSetup = aJobSetup; + ImplUpdatePageData(); + ImplUpdateFontList(); + return true; + } + + return false; +} + +bool Printer::Setup(weld::Window* pWindow, PrinterSetupMode eMode) +{ + if ( IsDisplayPrinter() ) + return false; + + if ( IsJobActive() || IsPrinting() ) + return false; + + JobSetup aJobSetup = maJobSetup; + ImplJobSetup& rData = aJobSetup.ImplGetData(); + rData.SetPrinterSetupMode( eMode ); + // TODO: orig page size + + if (!pWindow) + { + vcl::Window* pDefWin = ImplGetDefaultWindow(); + pWindow = pDefWin ? pDefWin->GetFrameWeld() : nullptr; + } + if( !pWindow ) + return false; + + ReleaseGraphics(); + ImplSVData* pSVData = ImplGetSVData(); + pSVData->maAppData.mnModalMode++; + nImplSysDialog++; + bool bSetup = mpInfoPrinter->Setup(pWindow, &rData); + pSVData->maAppData.mnModalMode--; + nImplSysDialog--; + if ( bSetup ) + { + ImplUpdateJobSetupPaper( aJobSetup ); + mbNewJobSetup = true; + maJobSetup = aJobSetup; + ImplUpdatePageData(); + ImplUpdateFontList(); + return true; + } + return false; +} + +bool Printer::SetPrinterProps( const Printer* pPrinter ) +{ + if ( IsJobActive() || IsPrinting() ) + return false; + + ImplSVData* pSVData = ImplGetSVData(); + + mbDefPrinter = pPrinter->mbDefPrinter; + maPrintFile = pPrinter->maPrintFile; + mbPrintFile = pPrinter->mbPrintFile; + mnCopyCount = pPrinter->mnCopyCount; + mbCollateCopy = pPrinter->mbCollateCopy; + mnPageQueueSize = pPrinter->mnPageQueueSize; + *mpPrinterOptions = *pPrinter->mpPrinterOptions; + + if ( pPrinter->IsDisplayPrinter() ) + { + // Destroy old printer + if ( !IsDisplayPrinter() ) + { + ReleaseGraphics(); + pSVData->mpDefInst->DestroyInfoPrinter( mpInfoPrinter ); + mpFontInstance.clear(); + mpFontFaceCollection.reset(); + // clean up font list + mxFontCache.reset(); + mxFontCollection.reset(); + + mbInitFont = true; + mbNewFont = true; + mpInfoPrinter = nullptr; + } + + // Construct new printer + ImplInitDisplay(); + return true; + } + + // Destroy old printer? + if ( GetName() != pPrinter->GetName() ) + { + ReleaseGraphics(); + if ( mpDisplayDev ) + { + mpDisplayDev.disposeAndClear(); + } + else + { + pSVData->mpDefInst->DestroyInfoPrinter( mpInfoPrinter ); + + mpFontInstance.clear(); + mpFontFaceCollection.reset(); + mxFontCache.reset(); + mxFontCollection.reset(); + mbInitFont = true; + mbNewFont = true; + mpInfoPrinter = nullptr; + } + + // Construct new printer + OUString aDriver = pPrinter->GetDriverName(); + SalPrinterQueueInfo* pInfo = ImplGetQueueInfo( pPrinter->GetName(), &aDriver ); + if ( pInfo ) + { + ImplInit( pInfo ); + SetJobSetup( pPrinter->GetJobSetup() ); + } + else + ImplInitDisplay(); + } + else + SetJobSetup( pPrinter->GetJobSetup() ); + + return false; +} + +bool Printer::SetOrientation( Orientation eOrientation ) +{ + if ( mbInPrintPage ) + return false; + + if ( maJobSetup.ImplGetConstData().GetOrientation() != eOrientation ) + { + JobSetup aJobSetup = maJobSetup; + ImplJobSetup& rData = aJobSetup.ImplGetData(); + + rData.SetOrientation(eOrientation); + + if ( IsDisplayPrinter() ) + { + mbNewJobSetup = true; + maJobSetup = aJobSetup; + return true; + } + + ReleaseGraphics(); + if ( mpInfoPrinter->SetData( JobSetFlags::ORIENTATION, &rData ) ) + { + ImplUpdateJobSetupPaper( aJobSetup ); + mbNewJobSetup = true; + maJobSetup = aJobSetup; + ImplUpdatePageData(); + ImplUpdateFontList(); + return true; + } + else + return false; + } + + return true; +} + +Orientation Printer::GetOrientation() const +{ + return maJobSetup.ImplGetConstData().GetOrientation(); +} + +bool Printer::SetPaperBin( sal_uInt16 nPaperBin ) +{ + if ( mbInPrintPage ) + return false; + + if ( maJobSetup.ImplGetConstData().GetPaperBin() != nPaperBin && + nPaperBin < GetPaperBinCount() ) + { + JobSetup aJobSetup = maJobSetup; + ImplJobSetup& rData = aJobSetup.ImplGetData(); + rData.SetPaperBin(nPaperBin); + + if ( IsDisplayPrinter() ) + { + mbNewJobSetup = true; + maJobSetup = aJobSetup; + return true; + } + + ReleaseGraphics(); + if ( mpInfoPrinter->SetData( JobSetFlags::PAPERBIN, &rData ) ) + { + ImplUpdateJobSetupPaper( aJobSetup ); + mbNewJobSetup = true; + maJobSetup = aJobSetup; + ImplUpdatePageData(); + ImplUpdateFontList(); + return true; + } + else + return false; + } + + return true; +} + +sal_uInt16 Printer::GetPaperBin() const +{ + return maJobSetup.ImplGetConstData().GetPaperBin(); +} + +bool Printer::GetPrinterSettingsPreferred() const +{ + return maJobSetup.ImplGetConstData().GetPapersizeFromSetup(); +} + +// dear loplugins, DO NOT REMOVE this code +// it will be used in follow-up commits +void Printer::SetPrinterSettingsPreferred( bool bPaperSizeFromSetup) +{ + if ( maJobSetup.ImplGetConstData().GetPapersizeFromSetup() != bPaperSizeFromSetup ) + { + JobSetup aJobSetup = maJobSetup; + ImplJobSetup& rData = aJobSetup.ImplGetData(); + rData.SetPapersizeFromSetup(bPaperSizeFromSetup); + + mbNewJobSetup = true; + maJobSetup = aJobSetup; + } +} + +// Map user paper format to an available printer paper format +void Printer::ImplFindPaperFormatForUserSize( JobSetup& aJobSetup ) +{ + ImplJobSetup& rData = aJobSetup.ImplGetData(); + + // The angle that a landscape page will be turned counterclockwise wrt to portrait. + int nLandscapeAngle = mpInfoPrinter ? mpInfoPrinter->GetLandscapeAngle( &maJobSetup.ImplGetConstData() ) : 900; + int nPaperCount = GetPaperInfoCount(); + PaperInfo aInfo(rData.GetPaperWidth(), rData.GetPaperHeight()); + + // Compare all paper formats and get the appropriate one + for ( int i = 0; i < nPaperCount; i++ ) + { + const PaperInfo& rPaperInfo = GetPaperInfo( i ); + + if ( aInfo.sloppyEqual(rPaperInfo) ) + { + rData.SetPaperFormat( + ImplGetPaperFormat( rPaperInfo.getWidth(), + rPaperInfo.getHeight() )); + rData.SetOrientation( Orientation::Portrait ); + return; + } + } + + // If the printer supports landscape orientation, check paper sizes again + // with landscape orientation. This is necessary as a printer driver provides + // all paper sizes with portrait orientation only!! + if ( !(rData.GetPaperFormat() == PAPER_USER && + nLandscapeAngle != 0 && + HasSupport( PrinterSupport::SetOrientation ))) + return; + + const tools::Long nRotatedWidth = rData.GetPaperHeight(); + const tools::Long nRotatedHeight = rData.GetPaperWidth(); + PaperInfo aRotatedInfo(nRotatedWidth, nRotatedHeight); + + for ( int i = 0; i < nPaperCount; i++ ) + { + const PaperInfo& rPaperInfo = GetPaperInfo( i ); + + if ( aRotatedInfo.sloppyEqual( rPaperInfo ) ) + { + rData.SetPaperFormat( + ImplGetPaperFormat( rPaperInfo.getWidth(), + rPaperInfo.getHeight() )); + rData.SetOrientation( Orientation::Landscape ); + return; + } + } +} + +void Printer::SetPaper( Paper ePaper ) +{ + if ( mbInPrintPage ) + return; + + if ( maJobSetup.ImplGetConstData().GetPaperFormat() == ePaper ) + return; + + JobSetup aJobSetup = maJobSetup; + ImplJobSetup& rData = aJobSetup.ImplGetData(); + + rData.SetPaperFormat( ePaper ); + if ( ePaper != PAPER_USER ) + { + PaperInfo aInfo(ePaper); + rData.SetPaperWidth( aInfo.getWidth() ); + rData.SetPaperHeight( aInfo.getHeight() ); + } + + if ( IsDisplayPrinter() ) + { + mbNewJobSetup = true; + maJobSetup = aJobSetup; + return; + } + + ReleaseGraphics(); + if ( ePaper == PAPER_USER ) + ImplFindPaperFormatForUserSize( aJobSetup ); + if ( mpInfoPrinter->SetData( JobSetFlags::PAPERSIZE | JobSetFlags::ORIENTATION, &rData )) + { + ImplUpdateJobSetupPaper( aJobSetup ); + mbNewJobSetup = true; + maJobSetup = aJobSetup; + ImplUpdatePageData(); + ImplUpdateFontList(); + } +} + +bool Printer::SetPaperSizeUser( const Size& rSize ) +{ + if ( mbInPrintPage ) + return false; + + const Size aPixSize = LogicToPixel( rSize ); + const Size aPageSize = PixelToLogic(aPixSize, MapMode(MapUnit::Map100thMM)); + bool bNeedToChange(maJobSetup.ImplGetConstData().GetPaperWidth() != aPageSize.Width() || + maJobSetup.ImplGetConstData().GetPaperHeight() != aPageSize.Height()); + + if(!bNeedToChange) + { + // #i122984# only need to change when Paper is different from PAPER_USER and + // the mapped Paper which will created below in the call to ImplFindPaperFormatForUserSize + // and will replace maJobSetup.ImplGetConstData()->GetPaperFormat(). This leads to + // unnecessary JobSetups, e.g. when printing a multi-page fax, but also with + // normal print + const Paper aPaper = ImplGetPaperFormat(aPageSize.Width(), aPageSize.Height()); + + bNeedToChange = maJobSetup.ImplGetConstData().GetPaperFormat() != PAPER_USER && + maJobSetup.ImplGetConstData().GetPaperFormat() != aPaper; + } + + if(bNeedToChange) + { + JobSetup aJobSetup = maJobSetup; + ImplJobSetup& rData = aJobSetup.ImplGetData(); + rData.SetPaperFormat( PAPER_USER ); + rData.SetPaperWidth( aPageSize.Width() ); + rData.SetPaperHeight( aPageSize.Height() ); + + if ( IsDisplayPrinter() ) + { + mbNewJobSetup = true; + maJobSetup = aJobSetup; + return true; + } + + ReleaseGraphics(); + ImplFindPaperFormatForUserSize( aJobSetup ); + + // Changing the paper size can also change the orientation! + if ( mpInfoPrinter->SetData( JobSetFlags::PAPERSIZE | JobSetFlags::ORIENTATION, &rData )) + { + ImplUpdateJobSetupPaper( aJobSetup ); + mbNewJobSetup = true; + maJobSetup = aJobSetup; + ImplUpdatePageData(); + ImplUpdateFontList(); + return true; + } + else + return false; + } + + return true; +} + +int Printer::GetPaperInfoCount() const +{ + if( ! mpInfoPrinter ) + return 0; + if( ! mpInfoPrinter->m_bPapersInit ) + mpInfoPrinter->InitPaperFormats( &maJobSetup.ImplGetConstData() ); + return mpInfoPrinter->m_aPaperFormats.size(); +} + +OUString Printer::GetPaperName( Paper ePaper ) +{ + ImplSVData* pSVData = ImplGetSVData(); + if( pSVData->maPaperNames.empty() ) + { + // This array must (probably) match exactly the enum Paper in <i18nutil/paper.hxx> + static const int PaperIndex[] = + { + PAPER_A0, PAPER_A1, PAPER_A2, PAPER_A3, PAPER_A4, PAPER_A5, PAPER_B4_ISO, PAPER_B5_ISO, + PAPER_LETTER, PAPER_LEGAL, PAPER_TABLOID, PAPER_USER, PAPER_B6_ISO, PAPER_ENV_C4, PAPER_ENV_C5, + PAPER_ENV_C6, PAPER_ENV_C65, PAPER_ENV_DL, PAPER_SLIDE_DIA, PAPER_SCREEN_4_3, PAPER_C, PAPER_D, + PAPER_E, PAPER_EXECUTIVE, PAPER_FANFOLD_LEGAL_DE, PAPER_ENV_MONARCH, PAPER_ENV_PERSONAL, PAPER_ENV_9, + PAPER_ENV_10, PAPER_ENV_11, PAPER_ENV_12, PAPER_KAI16, PAPER_KAI32, PAPER_KAI32BIG, PAPER_B4_JIS, + PAPER_B5_JIS, PAPER_B6_JIS, PAPER_LEDGER, PAPER_STATEMENT, PAPER_QUARTO, PAPER_10x14, PAPER_ENV_14, + PAPER_ENV_C3, PAPER_ENV_ITALY, PAPER_FANFOLD_US, PAPER_FANFOLD_DE, PAPER_POSTCARD_JP, PAPER_9x11, + PAPER_10x11, PAPER_15x11, PAPER_ENV_INVITE, PAPER_A_PLUS, PAPER_B_PLUS, PAPER_LETTER_PLUS, PAPER_A4_PLUS, + PAPER_DOUBLEPOSTCARD_JP, PAPER_A6, PAPER_12x11, PAPER_A7, PAPER_A8, PAPER_A9, PAPER_A10, PAPER_B0_ISO, + PAPER_B1_ISO, PAPER_B2_ISO, PAPER_B3_ISO, PAPER_B7_ISO, PAPER_B8_ISO, PAPER_B9_ISO, PAPER_B10_ISO, + PAPER_ENV_C2, PAPER_ENV_C7, PAPER_ENV_C8, PAPER_ARCHA, PAPER_ARCHB, PAPER_ARCHC, PAPER_ARCHD, + PAPER_ARCHE, PAPER_SCREEN_16_9, PAPER_SCREEN_16_10, PAPER_16K_195x270, PAPER_16K_197x273, + PAPER_WIDESCREEN, PAPER_ONSCREENSHOW_4_3, PAPER_ONSCREENSHOW_16_9, PAPER_ONSCREENSHOW_16_10 + }; + static_assert(SAL_N_ELEMENTS(PaperIndex) == SAL_N_ELEMENTS(RID_STR_PAPERNAMES), "localized paper name count wrong"); + for (size_t i = 0; i < SAL_N_ELEMENTS(PaperIndex); ++i) + pSVData->maPaperNames[PaperIndex[i]] = VclResId(RID_STR_PAPERNAMES[i]); + } + + std::unordered_map<int,OUString>::const_iterator it = pSVData->maPaperNames.find( static_cast<int>(ePaper) ); + return (it != pSVData->maPaperNames.end()) ? it->second : OUString(); +} + +const PaperInfo& Printer::GetPaperInfo( int nPaper ) const +{ + if( ! mpInfoPrinter ) + return ImplGetEmptyPaper(); + if( ! mpInfoPrinter->m_bPapersInit ) + mpInfoPrinter->InitPaperFormats( &maJobSetup.ImplGetConstData() ); + if( mpInfoPrinter->m_aPaperFormats.empty() || nPaper < 0 || o3tl::make_unsigned(nPaper) >= mpInfoPrinter->m_aPaperFormats.size() ) + return ImplGetEmptyPaper(); + return mpInfoPrinter->m_aPaperFormats[nPaper]; +} + +Size Printer::GetPaperSize( int nPaper ) const +{ + PaperInfo aInfo = GetPaperInfo( nPaper ); + return PixelToLogic( Size( aInfo.getWidth(), aInfo.getHeight() ) ); +} + +void Printer::SetDuplexMode( DuplexMode eDuplex ) +{ + if ( mbInPrintPage ) + return; + + if ( maJobSetup.ImplGetConstData().GetDuplexMode() == eDuplex ) + return; + + JobSetup aJobSetup = maJobSetup; + ImplJobSetup& rData = aJobSetup.ImplGetData(); + + rData.SetDuplexMode( eDuplex ); + + if ( IsDisplayPrinter() ) + { + mbNewJobSetup = true; + maJobSetup = aJobSetup; + return; + } + + ReleaseGraphics(); + if ( mpInfoPrinter->SetData( JobSetFlags::DUPLEXMODE, &rData ) ) + { + ImplUpdateJobSetupPaper( aJobSetup ); + mbNewJobSetup = true; + maJobSetup = aJobSetup; + ImplUpdatePageData(); + ImplUpdateFontList(); + } +} + +DuplexMode Printer::GetDuplexMode() const +{ + return maJobSetup.ImplGetConstData().GetDuplexMode(); +} + +Paper Printer::GetPaper() const +{ + return maJobSetup.ImplGetConstData().GetPaperFormat(); +} + +Size Printer::GetSizeOfPaper() const +{ + return Size(maJobSetup.ImplGetConstData().GetPaperWidth(), maJobSetup.ImplGetConstData().GetPaperHeight()); +} + +sal_uInt16 Printer::GetPaperBinCount() const +{ + if ( IsDisplayPrinter() ) + return 0; + + return mpInfoPrinter->GetPaperBinCount( &maJobSetup.ImplGetConstData() ); +} + +OUString Printer::GetPaperBinName( sal_uInt16 nPaperBin ) const +{ + if ( IsDisplayPrinter() ) + return OUString(); + + if ( nPaperBin < GetPaperBinCount() ) + return mpInfoPrinter->GetPaperBinName( &maJobSetup.ImplGetConstData(), nPaperBin ); + else + return OUString(); +} + +void Printer::SetCopyCount( sal_uInt16 nCopy, bool bCollate ) +{ + mnCopyCount = nCopy; + mbCollateCopy = bCollate; +} + +ErrCode Printer::ImplSalPrinterErrorCodeToVCL( SalPrinterError nError ) +{ + ErrCode nVCLError; + switch ( nError ) + { + case SalPrinterError::NONE: + nVCLError = ERRCODE_NONE; + break; + case SalPrinterError::Abort: + nVCLError = PRINTER_ABORT; + break; + default: + nVCLError = PRINTER_GENERALERROR; + break; + } + + return nVCLError; +} + +void Printer::EndJob() +{ + if ( !IsJobActive() ) + return; + + SAL_WARN_IF( mbInPrintPage, "vcl.gdi", "Printer::EndJob() - StartPage() without EndPage() called" ); + + mbJobActive = false; + + if ( mpPrinter ) + { + ReleaseGraphics(); + + mbPrinting = false; + + mbDevOutput = false; + mpPrinter->EndJob(); + mpPrinter.reset(); + } +} + +void Printer::ImplStartPage() +{ + if ( !IsJobActive() ) + return; + + if ( !mpPrinter ) + return; + + SalGraphics* pGraphics = mpPrinter->StartPage( &maJobSetup.ImplGetData(), + mbNewJobSetup ); + if ( pGraphics ) + { + ReleaseGraphics(); + mpJobGraphics = pGraphics; + } + mbDevOutput = true; + + // PrintJob not aborted ??? + if ( IsJobActive() ) + mbInPrintPage = true; +} + +void Printer::ImplEndPage() +{ + if ( !IsJobActive() ) + return; + + mbInPrintPage = false; + + if ( mpPrinter ) + { + ReleaseGraphics(); + mpPrinter->EndPage(); + mbDevOutput = false; + + mpJobGraphics = nullptr; + mbNewJobSetup = false; + } +} + +void Printer::updatePrinters() +{ + ImplSVData* pSVData = ImplGetSVData(); + ImplPrnQueueList* pPrnList = pSVData->maGDIData.mpPrinterQueueList.get(); + + if ( !pPrnList ) + return; + + std::unique_ptr<ImplPrnQueueList> pNewList(new ImplPrnQueueList); + pSVData->mpDefInst->GetPrinterQueueInfo( pNewList.get() ); + + bool bChanged = pPrnList->m_aQueueInfos.size() != pNewList->m_aQueueInfos.size(); + for( decltype(pPrnList->m_aQueueInfos)::size_type i = 0; ! bChanged && i < pPrnList->m_aQueueInfos.size(); i++ ) + { + ImplPrnQueueData& rInfo = pPrnList->m_aQueueInfos[i]; + ImplPrnQueueData& rNewInfo = pNewList->m_aQueueInfos[i]; + if( ! rInfo.mpSalQueueInfo || ! rNewInfo.mpSalQueueInfo || // sanity check + rInfo.mpSalQueueInfo->maPrinterName != rNewInfo.mpSalQueueInfo->maPrinterName ) + { + bChanged = true; + } + } + if( !bChanged ) + return; + + ImplDeletePrnQueueList(); + pSVData->maGDIData.mpPrinterQueueList = std::move(pNewList); + + Application* pApp = GetpApp(); + if( pApp ) + { + DataChangedEvent aDCEvt( DataChangedEventType::PRINTER ); + Application::ImplCallEventListenersApplicationDataChanged(&aDCEvt); + Application::NotifyAllWindows( aDCEvt ); + } +} + +bool Printer::UsePolyPolygonForComplexGradient() +{ + return true; +} + +void Printer::ClipAndDrawGradientMetafile ( const Gradient &rGradient, const tools::PolyPolygon &rPolyPoly ) +{ + const tools::Rectangle aBoundRect( rPolyPoly.GetBoundRect() ); + + Push( vcl::PushFlags::CLIPREGION ); + IntersectClipRegion(vcl::Region(rPolyPoly)); + DrawGradient( aBoundRect, rGradient ); + Pop(); +} + +void Printer::SetFontOrientation( LogicalFontInstance* const pFontEntry ) const +{ + pFontEntry->mnOrientation = pFontEntry->mxFontMetric->GetOrientation(); +} + +vcl::Region Printer::ClipToDeviceBounds(vcl::Region aRegion) const +{ + return aRegion; +} + +Bitmap Printer::GetBitmap( const Point& rSrcPt, const Size& rSize ) const +{ + SAL_WARN("vcl.gdi", "GetBitmap(): This should never be called on by a Printer instance"); + + return OutputDevice::GetBitmap( rSrcPt, rSize ); +} + +css::awt::DeviceInfo Printer::GetDeviceInfo() const +{ + Size aDevSz = GetPaperSizePixel(); + css::awt::DeviceInfo aInfo = GetCommonDeviceInfo(aDevSz); + Size aOutSz = GetOutputSizePixel(); + Point aOffset = GetPageOffset(); + aInfo.LeftInset = aOffset.X(); + aInfo.TopInset = aOffset.Y(); + aInfo.RightInset = aDevSz.Width() - aOutSz.Width() - aOffset.X(); + aInfo.BottomInset = aDevSz.Height() - aOutSz.Height() - aOffset.Y(); + aInfo.Capabilities = 0; + + return aInfo; +} + +void Printer::SetWaveLineColors(Color const& rColor, tools::Long) +{ + if (mbLineColor || mbInitLineColor) + { + mpGraphics->SetLineColor(); + mbInitLineColor = true; + } + + mpGraphics->SetFillColor(rColor); + mbInitFillColor = true; +} + +Size Printer::GetWaveLineSize(tools::Long nLineWidth) const +{ + // FIXME - do we have a bug here? If the linewidth is 0, then we will return + // Size(0, 0) - is this correct? + return Size(nLineWidth, ((nLineWidth*mnDPIX)+(mnDPIY/2))/mnDPIY); +} + +void Printer::SetSystemTextColor(SystemTextColorFlags, bool) +{ + SetTextColor(COL_BLACK); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ |