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/log.hxx>
21 #include <tools/debug.hxx>
23 #include <vcl/pdfextoutdevdata.hxx>
24 #include <vcl/virdev.hxx>
27 #include <PhysicalFontCollection.hxx>
28 #include <salinst.hxx>
33 using namespace ::com::sun::star::uno
;
35 bool VirtualDevice::CanEnableNativeWidget() const
37 const vcl::ExtOutDevData
* pOutDevData(GetExtOutDevData());
38 const vcl::PDFExtOutDevData
* pPDFData(dynamic_cast<const vcl::PDFExtOutDevData
*>(pOutDevData
));
39 return pPDFData
== nullptr;
42 bool VirtualDevice::AcquireGraphics() const
49 mbInitLineColor
= true;
50 mbInitFillColor
= true;
52 mbInitTextColor
= true;
53 mbInitClipRegion
= true;
55 ImplSVData
* pSVData
= ImplGetSVData();
59 mpGraphics
= mpVirDev
->AcquireGraphics();
60 // if needed retry after releasing least recently used virtual device graphics
63 if ( !pSVData
->maGDIData
.mpLastVirGraphics
)
65 pSVData
->maGDIData
.mpLastVirGraphics
->ReleaseGraphics();
66 mpGraphics
= mpVirDev
->AcquireGraphics();
68 // update global LRU list of virtual device graphics
71 mpNextGraphics
= pSVData
->maGDIData
.mpFirstVirGraphics
;
72 pSVData
->maGDIData
.mpFirstVirGraphics
= const_cast<VirtualDevice
*>(this);
74 mpNextGraphics
->mpPrevGraphics
= const_cast<VirtualDevice
*>(this);
75 if ( !pSVData
->maGDIData
.mpLastVirGraphics
)
76 pSVData
->maGDIData
.mpLastVirGraphics
= const_cast<VirtualDevice
*>(this);
82 mpGraphics
->SetXORMode( (RasterOp::Invert
== meRasterOp
) || (RasterOp::Xor
== meRasterOp
), RasterOp::Invert
== meRasterOp
);
83 mpGraphics
->setAntiAlias(bool(mnAntialiasing
& AntialiasingFlags::Enable
));
86 return mpGraphics
!= nullptr;
89 void VirtualDevice::ReleaseGraphics( bool bRelease
)
96 // release the fonts of the physically released graphics device
100 ImplSVData
* pSVData
= ImplGetSVData();
102 VirtualDevice
* pVirDev
= this;
105 pVirDev
->mpVirDev
->ReleaseGraphics( mpGraphics
);
106 // remove from global LRU list of virtual device graphics
107 if ( mpPrevGraphics
)
108 mpPrevGraphics
->mpNextGraphics
= mpNextGraphics
;
110 pSVData
->maGDIData
.mpFirstVirGraphics
= mpNextGraphics
;
111 if ( mpNextGraphics
)
112 mpNextGraphics
->mpPrevGraphics
= mpPrevGraphics
;
114 pSVData
->maGDIData
.mpLastVirGraphics
= mpPrevGraphics
;
116 mpGraphics
= nullptr;
117 mpPrevGraphics
= nullptr;
118 mpNextGraphics
= nullptr;
121 void VirtualDevice::ImplInitVirDev( const OutputDevice
* pOutDev
,
122 tools::Long nDX
, tools::Long nDY
, const SystemGraphicsData
*pData
)
124 SAL_INFO( "vcl.virdev", "ImplInitVirDev(" << nDX
<< "," << nDY
<< ")" );
126 meRefDevMode
= RefDevMode::NONE
;
127 mbForceZeroExtleadBug
= false;
129 bool bErase
= nDX
> 0 && nDY
> 0;
137 ImplSVData
* pSVData
= ImplGetSVData();
140 pOutDev
= ImplGetDefaultWindow()->GetOutDev();
144 SalGraphics
* pGraphics
;
145 if ( !pOutDev
->mpGraphics
)
146 (void)pOutDev
->AcquireGraphics();
147 pGraphics
= pOutDev
->mpGraphics
;
149 mpVirDev
= pSVData
->mpDefInst
->CreateVirtualDevice(*pGraphics
, nDX
, nDY
, meFormat
, pData
);
154 // do not abort but throw an exception, may be the current thread terminates anyway (plugin-scenario)
155 throw css::uno::RuntimeException(
156 "Could not create system bitmap!",
157 css::uno::Reference
< css::uno::XInterface
>() );
160 mnBitCount
= pOutDev
->GetBitCount();
164 mbScreenComp
= pOutDev
->IsScreenComp();
167 mxFontCollection
= pSVData
->maGDIData
.mxScreenFontList
;
168 mxFontCache
= pSVData
->maGDIData
.mxScreenFontCache
;
169 mnDPIX
= pOutDev
->mnDPIX
;
170 mnDPIY
= pOutDev
->mnDPIY
;
171 mnDPIScalePercentage
= pOutDev
->mnDPIScalePercentage
;
172 maFont
= pOutDev
->maFont
;
174 if( maTextColor
!= pOutDev
->maTextColor
)
176 maTextColor
= pOutDev
->maTextColor
;
177 mbInitTextColor
= true;
180 // virtual devices have white background by default
181 SetBackground( Wallpaper( COL_WHITE
) );
183 // #i59283# don't erase user-provided surface
184 if( !pData
&& bErase
)
187 // register VirDev in the list
188 mpNext
= pSVData
->maGDIData
.mpFirstVirDev
;
191 mpNext
->mpPrev
= this;
192 pSVData
->maGDIData
.mpFirstVirDev
= this;
195 VirtualDevice::VirtualDevice(const OutputDevice
* pCompDev
, DeviceFormat eFormat
,
196 DeviceFormat eAlphaFormat
, OutDevType eOutDevType
)
197 : OutputDevice(eOutDevType
)
199 , meAlphaFormat(eAlphaFormat
)
201 SAL_INFO( "vcl.virdev", "VirtualDevice::VirtualDevice( " << static_cast<int>(eFormat
)
202 << ", " << static_cast<int>(eAlphaFormat
)
203 << ", " << static_cast<int>(eOutDevType
) << " )" );
205 ImplInitVirDev(pCompDev
? pCompDev
: Application::GetDefaultDevice(), 0, 0);
208 VirtualDevice::VirtualDevice(const SystemGraphicsData
& rData
, const Size
&rSize
,
209 DeviceFormat eFormat
)
210 : OutputDevice(OUTDEV_VIRDEV
)
212 , meAlphaFormat(DeviceFormat::NONE
)
214 SAL_INFO( "vcl.virdev", "VirtualDevice::VirtualDevice( " << static_cast<int>(eFormat
) << " )" );
216 ImplInitVirDev(Application::GetDefaultDevice(), rSize
.Width(), rSize
.Height(), &rData
);
219 VirtualDevice::~VirtualDevice()
221 SAL_INFO( "vcl.virdev", "VirtualDevice::~VirtualDevice()" );
225 void VirtualDevice::dispose()
227 SAL_INFO( "vcl.virdev", "VirtualDevice::dispose()" );
229 ImplSVData
* pSVData
= ImplGetSVData();
235 // remove this VirtualDevice from the double-linked global list
237 mpPrev
->mpNext
= mpNext
;
239 pSVData
->maGDIData
.mpFirstVirDev
= mpNext
;
242 mpNext
->mpPrev
= mpPrev
;
244 OutputDevice::dispose();
247 bool VirtualDevice::InnerImplSetOutputSizePixel( const Size
& rNewSize
, bool bErase
,
248 sal_uInt8
*const pBuffer
)
250 SAL_INFO( "vcl.virdev",
251 "VirtualDevice::InnerImplSetOutputSizePixel( " << rNewSize
.Width() << ", "
252 << rNewSize
.Height() << ", " << int(bErase
) << " )" );
256 else if ( rNewSize
== GetOutputSizePixel() )
260 SAL_INFO( "vcl.virdev", "Trying to re-use a VirtualDevice but this time using a pre-allocated buffer");
265 tools::Long nNewWidth
= rNewSize
.Width(), nNewHeight
= rNewSize
.Height();
270 if ( nNewHeight
< 1 )
276 bRet
= mpVirDev
->SetSizeUsingBuffer( nNewWidth
, nNewHeight
, pBuffer
);
278 bRet
= mpVirDev
->SetSize( nNewWidth
, nNewHeight
);
282 mnOutWidth
= rNewSize
.Width();
283 mnOutHeight
= rNewSize
.Height();
289 std::unique_ptr
<SalVirtualDevice
> pNewVirDev
;
290 ImplSVData
* pSVData
= ImplGetSVData();
292 // we need a graphics
293 if ( !mpGraphics
&& !AcquireGraphics() )
298 pNewVirDev
= pSVData
->mpDefInst
->CreateVirtualDevice(*mpGraphics
, nNewWidth
, nNewHeight
, meFormat
);
301 SalGraphics
* pGraphics
= pNewVirDev
->AcquireGraphics();
306 if ( mnOutWidth
< nNewWidth
)
310 if ( mnOutHeight
< nNewHeight
)
311 nHeight
= mnOutHeight
;
313 nHeight
= nNewHeight
;
314 SalTwoRect
aPosAry(0, 0, nWidth
, nHeight
, 0, 0, nWidth
, nHeight
);
315 pGraphics
->CopyBits( aPosAry
, *mpGraphics
, *this, *this );
316 pNewVirDev
->ReleaseGraphics( pGraphics
);
318 mpVirDev
= std::move(pNewVirDev
);
319 mnOutWidth
= rNewSize
.Width();
320 mnOutHeight
= rNewSize
.Height();
335 // #i32109#: Fill opaque areas correctly (without relying on
336 // fill/linecolor state)
337 void VirtualDevice::ImplFillOpaqueRectangle( const tools::Rectangle
& rRect
)
339 // Set line and fill color to black (->opaque),
340 // fill rect with that (linecolor, too, because of
341 // those pesky missing pixel problems)
342 Push( PushFlags::LINECOLOR
| PushFlags::FILLCOLOR
);
343 SetLineColor( COL_BLACK
);
344 SetFillColor( COL_BLACK
);
349 bool VirtualDevice::ImplSetOutputSizePixel( const Size
& rNewSize
, bool bErase
,
350 sal_uInt8
*const pBuffer
)
352 if( InnerImplSetOutputSizePixel(rNewSize
, bErase
, pBuffer
) )
354 if (meAlphaFormat
!= DeviceFormat::NONE
)
356 // #110958# Setup alpha bitmap
357 if(mpAlphaVDev
&& mpAlphaVDev
->GetOutputSizePixel() != rNewSize
)
359 mpAlphaVDev
.disposeAndClear();
364 mpAlphaVDev
= VclPtr
<VirtualDevice
>::Create(*this, meAlphaFormat
);
365 mpAlphaVDev
->InnerImplSetOutputSizePixel(rNewSize
, bErase
, nullptr);
368 // TODO: copy full outdev state to new one, here. Also needed in outdev2.cxx:DrawOutDev
369 if( GetLineColor() != COL_TRANSPARENT
)
370 mpAlphaVDev
->SetLineColor( COL_BLACK
);
372 if( GetFillColor() != COL_TRANSPARENT
)
373 mpAlphaVDev
->SetFillColor( COL_BLACK
);
375 mpAlphaVDev
->SetMapMode( GetMapMode() );
384 void VirtualDevice::EnableRTL( bool bEnable
)
386 // virdevs default to not mirroring, they will only be set to mirroring
387 // under rare circumstances in the UI, eg the valueset control
388 // because each virdev has its own SalGraphics we can safely switch the SalGraphics here
390 if( AcquireGraphics() )
391 mpGraphics
->SetLayout( bEnable
? SalLayoutFlags::BiDiRtl
: SalLayoutFlags::NONE
);
393 OutputDevice::EnableRTL(bEnable
);
396 bool VirtualDevice::SetOutputSizePixel( const Size
& rNewSize
, bool bErase
)
398 return ImplSetOutputSizePixel(rNewSize
, bErase
, nullptr);
401 bool VirtualDevice::SetOutputSizePixelScaleOffsetAndBuffer(
402 const Size
& rNewSize
, const Fraction
& rScale
, const Point
& rNewOffset
,
403 sal_uInt8
*const pBuffer
)
406 MapMode mm
= GetMapMode();
407 mm
.SetOrigin( rNewOffset
);
408 mm
.SetScaleX( rScale
);
409 mm
.SetScaleY( rScale
);
412 return ImplSetOutputSizePixel(rNewSize
, true, pBuffer
);
415 void VirtualDevice::SetReferenceDevice( RefDevMode i_eRefDevMode
)
417 sal_Int32 nDPIX
= 600, nDPIY
= 600;
418 switch( i_eRefDevMode
)
420 case RefDevMode::NONE
:
422 SAL_WARN( "vcl.virdev", "VDev::SetRefDev illegal argument!" );
424 case RefDevMode::Dpi600
:
427 case RefDevMode::MSO1
:
428 nDPIX
= nDPIY
= 6*1440;
430 case RefDevMode::PDF1
:
434 ImplSetReferenceDevice( i_eRefDevMode
, nDPIX
, nDPIY
);
437 void VirtualDevice::SetReferenceDevice( sal_Int32 i_nDPIX
, sal_Int32 i_nDPIY
)
439 ImplSetReferenceDevice( RefDevMode::Custom
, i_nDPIX
, i_nDPIY
);
442 bool VirtualDevice::IsVirtual() const
447 void VirtualDevice::ImplSetReferenceDevice( RefDevMode i_eRefDevMode
, sal_Int32 i_nDPIX
, sal_Int32 i_nDPIY
)
451 mnDPIScalePercentage
= 100;
453 EnableOutput( false ); // prevent output on reference device
454 mbScreenComp
= false;
456 // invalidate currently selected fonts
460 // avoid adjusting font lists when already in refdev mode
461 RefDevMode nOldRefDevMode
= meRefDevMode
;
462 meRefDevMode
= i_eRefDevMode
;
463 if( nOldRefDevMode
!= RefDevMode::NONE
)
466 // the reference device should have only scalable fonts
467 // => clean up the original font lists before getting new ones
468 mpFontInstance
.clear();
469 mpDeviceFontList
.reset();
470 mpDeviceFontSizeList
.reset();
472 // preserve global font lists
473 ImplSVData
* pSVData
= ImplGetSVData();
474 mxFontCollection
.reset();
477 // get font list with scalable fonts only
478 (void)AcquireGraphics();
479 mxFontCollection
= pSVData
->maGDIData
.mxScreenFontList
->Clone();
481 // prepare to use new font lists
482 mxFontCache
= std::make_shared
<ImplFontCache
>();
485 sal_uInt16
VirtualDevice::GetBitCount() const
490 bool VirtualDevice::UsePolyPolygonForComplexGradient()
495 void VirtualDevice::Compat_ZeroExtleadBug()
497 mbForceZeroExtleadBug
= true;
500 tools::Long
VirtualDevice::GetFontExtLeading() const
503 // backwards compatible line metrics after fixing #i60945#
504 if ( mbForceZeroExtleadBug
)
508 return mpFontInstance
->mxFontMetric
->GetExternalLeading();
511 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */