1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <comphelper/lok.hxx>
23 #include <sal/log.hxx>
24 #include <tools/debug.hxx>
26 #include <vcl/pdfextoutdevdata.hxx>
27 #include <vcl/virdev.hxx>
29 #include <ImplOutDevData.hxx>
30 #include <font/PhysicalFontCollection.hxx>
31 #include <font/PhysicalFontFaceCollection.hxx>
32 #include <impfontcache.hxx>
33 #include <salinst.hxx>
38 using namespace ::com::sun::star::uno
;
40 bool VirtualDevice::CanEnableNativeWidget() const
42 const vcl::ExtOutDevData
* pOutDevData(GetExtOutDevData());
43 const vcl::PDFExtOutDevData
* pPDFData(dynamic_cast<const vcl::PDFExtOutDevData
*>(pOutDevData
));
44 return pPDFData
== nullptr;
47 bool VirtualDevice::AcquireGraphics() const
54 mbInitLineColor
= true;
55 mbInitFillColor
= true;
57 mbInitTextColor
= true;
58 mbInitClipRegion
= true;
60 ImplSVData
* pSVData
= ImplGetSVData();
64 mpGraphics
= mpVirDev
->AcquireGraphics();
65 // if needed retry after releasing least recently used virtual device graphics
68 if ( !pSVData
->maGDIData
.mpLastVirGraphics
)
70 pSVData
->maGDIData
.mpLastVirGraphics
->ReleaseGraphics();
71 mpGraphics
= mpVirDev
->AcquireGraphics();
73 // update global LRU list of virtual device graphics
76 mpNextGraphics
= pSVData
->maGDIData
.mpFirstVirGraphics
;
77 pSVData
->maGDIData
.mpFirstVirGraphics
= const_cast<VirtualDevice
*>(this);
79 mpNextGraphics
->mpPrevGraphics
= const_cast<VirtualDevice
*>(this);
80 if ( !pSVData
->maGDIData
.mpLastVirGraphics
)
81 pSVData
->maGDIData
.mpLastVirGraphics
= const_cast<VirtualDevice
*>(this);
87 mpGraphics
->SetXORMode( (RasterOp::Invert
== meRasterOp
) || (RasterOp::Xor
== meRasterOp
), RasterOp::Invert
== meRasterOp
);
88 mpGraphics
->setAntiAlias(bool(mnAntialiasing
& AntialiasingFlags::Enable
));
91 return mpGraphics
!= nullptr;
94 void VirtualDevice::ReleaseGraphics( bool bRelease
)
101 // release the fonts of the physically released graphics device
105 ImplSVData
* pSVData
= ImplGetSVData();
107 VirtualDevice
* pVirDev
= this;
110 pVirDev
->mpVirDev
->ReleaseGraphics( mpGraphics
);
111 // remove from global LRU list of virtual device graphics
112 if ( mpPrevGraphics
)
113 mpPrevGraphics
->mpNextGraphics
= mpNextGraphics
;
115 pSVData
->maGDIData
.mpFirstVirGraphics
= mpNextGraphics
;
116 if ( mpNextGraphics
)
117 mpNextGraphics
->mpPrevGraphics
= mpPrevGraphics
;
119 pSVData
->maGDIData
.mpLastVirGraphics
= mpPrevGraphics
;
121 mpGraphics
= nullptr;
122 mpPrevGraphics
= nullptr;
123 mpNextGraphics
= nullptr;
126 void VirtualDevice::ImplInitVirDev( const OutputDevice
* pOutDev
,
127 tools::Long nDX
, tools::Long nDY
, const SystemGraphicsData
*pData
)
129 SAL_INFO( "vcl.virdev", "ImplInitVirDev(" << nDX
<< "," << nDY
<< ")" );
131 meRefDevMode
= RefDevMode::NONE
;
132 mbForceZeroExtleadBug
= false;
134 mbScreenComp
= false;
137 bool bErase
= nDX
> 0 && nDY
> 0;
145 ImplSVData
* pSVData
= ImplGetSVData();
148 pOutDev
= ImplGetDefaultWindow()->GetOutDev();
152 SalGraphics
* pGraphics
;
153 if ( !pOutDev
->mpGraphics
)
154 (void)pOutDev
->AcquireGraphics();
155 pGraphics
= pOutDev
->mpGraphics
;
157 mpVirDev
= pSVData
->mpDefInst
->CreateVirtualDevice(*pGraphics
, nDX
, nDY
, meFormatAndAlpha
, pData
);
162 // do not abort but throw an exception, may be the current thread terminates anyway (plugin-scenario)
163 throw css::uno::RuntimeException(
164 u
"Could not create system bitmap!"_ustr
,
165 css::uno::Reference
< css::uno::XInterface
>() );
168 mnBitCount
= pOutDev
->GetBitCount();
172 mbScreenComp
= pOutDev
->IsScreenComp();
175 mxFontCollection
= pSVData
->maGDIData
.mxScreenFontList
;
176 mxFontCache
= pSVData
->maGDIData
.mxScreenFontCache
;
177 mnDPIX
= pOutDev
->mnDPIX
;
178 mnDPIY
= pOutDev
->mnDPIY
;
179 mnDPIScalePercentage
= pOutDev
->mnDPIScalePercentage
;
180 maFont
= pOutDev
->maFont
;
182 if( maTextColor
!= pOutDev
->maTextColor
)
184 maTextColor
= pOutDev
->maTextColor
;
185 mbInitTextColor
= true;
188 // virtual devices have white background by default
189 SetBackground( Wallpaper( COL_WHITE
) );
191 // #i59283# don't erase user-provided surface
192 if( !pData
&& bErase
)
195 // register VirDev in the list
196 mpNext
= pSVData
->maGDIData
.mpFirstVirDev
;
199 mpNext
->mpPrev
= this;
200 pSVData
->maGDIData
.mpFirstVirDev
= this;
203 VirtualDevice::VirtualDevice(const OutputDevice
* pCompDev
, DeviceFormat eFormatAndAlpha
,
204 OutDevType eOutDevType
)
205 : OutputDevice(eOutDevType
)
206 , meFormatAndAlpha(eFormatAndAlpha
)
208 SAL_INFO( "vcl.virdev", "VirtualDevice::VirtualDevice( " << static_cast<int>(eFormatAndAlpha
)
209 << ", " << static_cast<int>(eOutDevType
) << " )" );
211 ImplInitVirDev(pCompDev
? pCompDev
: Application::GetDefaultDevice(), 0, 0);
214 VirtualDevice::VirtualDevice(const SystemGraphicsData
& rData
, const Size
&rSize
,
215 DeviceFormat eFormat
)
216 : OutputDevice(OUTDEV_VIRDEV
)
217 , meFormatAndAlpha(eFormat
)
219 SAL_INFO( "vcl.virdev", "VirtualDevice::VirtualDevice( " << static_cast<int>(eFormat
) << " )" );
221 ImplInitVirDev(Application::GetDefaultDevice(), rSize
.Width(), rSize
.Height(), &rData
);
224 VirtualDevice::~VirtualDevice()
226 SAL_INFO( "vcl.virdev", "VirtualDevice::~VirtualDevice()" );
230 void VirtualDevice::dispose()
232 SAL_INFO( "vcl.virdev", "VirtualDevice::dispose()" );
234 ImplSVData
* pSVData
= ImplGetSVData();
240 // remove this VirtualDevice from the double-linked global list
242 mpPrev
->mpNext
= mpNext
;
244 pSVData
->maGDIData
.mpFirstVirDev
= mpNext
;
247 mpNext
->mpPrev
= mpPrev
;
249 OutputDevice::dispose();
252 bool VirtualDevice::InnerImplSetOutputSizePixel( const Size
& rNewSize
, bool bErase
,
253 sal_uInt8
*const pBuffer
)
255 SAL_INFO( "vcl.virdev",
256 "VirtualDevice::InnerImplSetOutputSizePixel( " << rNewSize
.Width() << ", "
257 << rNewSize
.Height() << ", " << int(bErase
) << " )" );
261 else if ( rNewSize
== GetOutputSizePixel() )
265 SAL_INFO( "vcl.virdev", "Trying to re-use a VirtualDevice but this time using a pre-allocated buffer");
270 tools::Long nNewWidth
= rNewSize
.Width(), nNewHeight
= rNewSize
.Height();
275 if ( nNewHeight
< 1 )
281 bRet
= mpVirDev
->SetSizeUsingBuffer( nNewWidth
, nNewHeight
, pBuffer
);
283 bRet
= mpVirDev
->SetSize( nNewWidth
, nNewHeight
);
287 mnOutWidth
= rNewSize
.Width();
288 mnOutHeight
= rNewSize
.Height();
294 std::unique_ptr
<SalVirtualDevice
> pNewVirDev
;
295 ImplSVData
* pSVData
= ImplGetSVData();
297 // we need a graphics
298 if ( !mpGraphics
&& !AcquireGraphics() )
303 pNewVirDev
= pSVData
->mpDefInst
->CreateVirtualDevice(*mpGraphics
, nNewWidth
, nNewHeight
, meFormatAndAlpha
);
306 SalGraphics
* pGraphics
= pNewVirDev
->AcquireGraphics();
311 if ( mnOutWidth
< nNewWidth
)
315 if ( mnOutHeight
< nNewHeight
)
316 nHeight
= mnOutHeight
;
318 nHeight
= nNewHeight
;
319 SalTwoRect
aPosAry(0, 0, nWidth
, nHeight
, 0, 0, nWidth
, nHeight
);
320 pGraphics
->CopyBits( aPosAry
, *mpGraphics
, *this, *this );
321 pNewVirDev
->ReleaseGraphics( pGraphics
);
323 mpVirDev
= std::move(pNewVirDev
);
324 mnOutWidth
= rNewSize
.Width();
325 mnOutHeight
= rNewSize
.Height();
340 // #i32109#: Fill opaque areas correctly (without relying on
341 // fill/linecolor state)
342 void VirtualDevice::ImplFillOpaqueRectangle( const tools::Rectangle
& rRect
)
344 // Set line and fill color to opaque,
345 // fill rect with that (linecolor, too, because of
346 // those pesky missing pixel problems)
347 Push( vcl::PushFlags::LINECOLOR
| vcl::PushFlags::FILLCOLOR
);
348 SetLineColor( COL_ALPHA_OPAQUE
);
349 SetFillColor( COL_ALPHA_OPAQUE
);
354 bool VirtualDevice::ImplSetOutputSizePixel( const Size
& rNewSize
, bool bErase
,
355 sal_uInt8
*const pBuffer
, bool bAlphaMaskTransparent
)
357 if( InnerImplSetOutputSizePixel(rNewSize
, bErase
, pBuffer
) )
359 if (meFormatAndAlpha
!= DeviceFormat::WITHOUT_ALPHA
)
361 // #110958# Setup alpha bitmap
362 if(mpAlphaVDev
&& mpAlphaVDev
->GetOutputSizePixel() != rNewSize
)
364 mpAlphaVDev
.disposeAndClear();
369 mpAlphaVDev
= VclPtr
<VirtualDevice
>::Create(*this, meFormatAndAlpha
);
370 mpAlphaVDev
->InnerImplSetOutputSizePixel(rNewSize
, bErase
, nullptr);
371 mpAlphaVDev
->SetBackground( Wallpaper(bAlphaMaskTransparent
? COL_ALPHA_TRANSPARENT
: COL_ALPHA_OPAQUE
) );
372 mpAlphaVDev
->Erase();
375 // TODO: copy full outdev state to new one, here. Also needed in outdev2.cxx:DrawOutDev
376 if( GetLineColor() != COL_TRANSPARENT
)
377 mpAlphaVDev
->SetLineColor( COL_ALPHA_OPAQUE
);
379 if( GetFillColor() != COL_TRANSPARENT
)
380 mpAlphaVDev
->SetFillColor( COL_ALPHA_OPAQUE
);
382 mpAlphaVDev
->SetMapMode( GetMapMode() );
384 mpAlphaVDev
->SetAntialiasing( GetAntialiasing() );
393 void VirtualDevice::EnableRTL( bool bEnable
)
395 // virdevs default to not mirroring, they will only be set to mirroring
396 // under rare circumstances in the UI, eg the valueset control
397 // because each virdev has its own SalGraphics we can safely switch the SalGraphics here
399 if( AcquireGraphics() )
400 mpGraphics
->SetLayout( bEnable
? SalLayoutFlags::BiDiRtl
: SalLayoutFlags::NONE
);
402 OutputDevice::EnableRTL(bEnable
);
405 bool VirtualDevice::SetOutputSizePixel( const Size
& rNewSize
, bool bErase
, bool bAlphaMaskTransparent
)
407 return ImplSetOutputSizePixel(rNewSize
, bErase
, nullptr, bAlphaMaskTransparent
);
410 bool VirtualDevice::SetOutputSizePixelScaleOffsetAndLOKBuffer(
411 const Size
& rNewSize
, const Fraction
& rScale
, const Point
& rNewOffset
,
412 sal_uInt8
*const pBuffer
)
414 // If this is ever needed for something else than LOK, changes will
415 // be needed in SvpSalVirtualDevice::CreateSurface() .
416 assert(comphelper::LibreOfficeKit::isActive());
418 MapMode mm
= GetMapMode();
419 mm
.SetOrigin( rNewOffset
);
420 mm
.SetScaleX( rScale
);
421 mm
.SetScaleY( rScale
);
423 return ImplSetOutputSizePixel(rNewSize
, true, pBuffer
);
426 void VirtualDevice::SetReferenceDevice( RefDevMode i_eRefDevMode
)
428 sal_Int32 nDPIX
= 600, nDPIY
= 600;
429 switch( i_eRefDevMode
)
431 case RefDevMode::NONE
:
433 SAL_WARN( "vcl.virdev", "VDev::SetRefDev illegal argument!" );
435 case RefDevMode::Dpi600
:
438 case RefDevMode::MSO1
:
439 nDPIX
= nDPIY
= 6*1440;
441 case RefDevMode::PDF1
:
445 ImplSetReferenceDevice( i_eRefDevMode
, nDPIX
, nDPIY
);
448 void VirtualDevice::SetReferenceDevice( sal_Int32 i_nDPIX
, sal_Int32 i_nDPIY
)
450 ImplSetReferenceDevice( RefDevMode::Custom
, i_nDPIX
, i_nDPIY
);
453 bool VirtualDevice::IsVirtual() const
458 void VirtualDevice::ImplSetReferenceDevice( RefDevMode i_eRefDevMode
, sal_Int32 i_nDPIX
, sal_Int32 i_nDPIY
)
462 mnDPIScalePercentage
= 100;
464 EnableOutput( false ); // prevent output on reference device
465 mbScreenComp
= false;
467 // invalidate currently selected fonts
471 // avoid adjusting font lists when already in refdev mode
472 RefDevMode nOldRefDevMode
= meRefDevMode
;
473 meRefDevMode
= i_eRefDevMode
;
474 if( nOldRefDevMode
!= RefDevMode::NONE
)
477 // the reference device should have only scalable fonts
478 // => clean up the original font lists before getting new ones
479 mpFontInstance
.clear();
480 mpFontFaceCollection
.reset();
482 // preserve global font lists
483 ImplSVData
* pSVData
= ImplGetSVData();
484 mxFontCollection
.reset();
487 // get font list with scalable fonts only
488 (void)AcquireGraphics();
489 mxFontCollection
= pSVData
->maGDIData
.mxScreenFontList
->Clone();
491 // prepare to use new font lists
492 mxFontCache
= std::make_shared
<ImplFontCache
>();
495 sal_uInt16
VirtualDevice::GetBitCount() const
500 bool VirtualDevice::UsePolyPolygonForComplexGradient()
505 void VirtualDevice::Compat_ZeroExtleadBug()
507 mbForceZeroExtleadBug
= true;
510 tools::Long
VirtualDevice::GetFontExtLeading() const
513 // backwards compatible line metrics after fixing #i60945#
514 if ( mbForceZeroExtleadBug
)
518 return mpFontInstance
->mxFontMetric
->GetExternalLeading();
521 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */