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 <salinst.hxx>
24 #include <PhysicalFontCollection.hxx>
26 #include <vcl/virdev.hxx>
27 #include <sal/log.hxx>
28 #include <tools/debug.hxx>
30 using namespace ::com::sun::star::uno
;
32 bool VirtualDevice::AcquireGraphics() const
39 mbInitLineColor
= true;
40 mbInitFillColor
= true;
42 mbInitTextColor
= true;
43 mbInitClipRegion
= true;
45 ImplSVData
* pSVData
= ImplGetSVData();
49 mpGraphics
= mpVirDev
->AcquireGraphics();
50 // if needed retry after releasing least recently used virtual device graphics
53 if ( !pSVData
->maGDIData
.mpLastVirGraphics
)
55 pSVData
->maGDIData
.mpLastVirGraphics
->ReleaseGraphics();
56 mpGraphics
= mpVirDev
->AcquireGraphics();
58 // update global LRU list of virtual device graphics
61 mpNextGraphics
= pSVData
->maGDIData
.mpFirstVirGraphics
;
62 pSVData
->maGDIData
.mpFirstVirGraphics
= const_cast<VirtualDevice
*>(this);
64 mpNextGraphics
->mpPrevGraphics
= const_cast<VirtualDevice
*>(this);
65 if ( !pSVData
->maGDIData
.mpLastVirGraphics
)
66 pSVData
->maGDIData
.mpLastVirGraphics
= const_cast<VirtualDevice
*>(this);
72 mpGraphics
->SetXORMode( (RasterOp::Invert
== meRasterOp
) || (RasterOp::Xor
== meRasterOp
), RasterOp::Invert
== meRasterOp
);
73 mpGraphics
->setAntiAliasB2DDraw(bool(mnAntialiasing
& AntialiasingFlags::EnableB2dDraw
));
76 return mpGraphics
!= nullptr;
79 void VirtualDevice::ReleaseGraphics( bool bRelease
)
86 // release the fonts of the physically released graphics device
90 ImplSVData
* pSVData
= ImplGetSVData();
92 VirtualDevice
* pVirDev
= this;
95 pVirDev
->mpVirDev
->ReleaseGraphics( mpGraphics
);
96 // remove from global LRU list of virtual device graphics
98 mpPrevGraphics
->mpNextGraphics
= mpNextGraphics
;
100 pSVData
->maGDIData
.mpFirstVirGraphics
= mpNextGraphics
;
101 if ( mpNextGraphics
)
102 mpNextGraphics
->mpPrevGraphics
= mpPrevGraphics
;
104 pSVData
->maGDIData
.mpLastVirGraphics
= mpPrevGraphics
;
106 mpGraphics
= nullptr;
107 mpPrevGraphics
= nullptr;
108 mpNextGraphics
= nullptr;
111 void VirtualDevice::ImplInitVirDev( const OutputDevice
* pOutDev
,
112 long nDX
, long nDY
, const SystemGraphicsData
*pData
)
114 SAL_INFO( "vcl.virdev", "ImplInitVirDev(" << nDX
<< "," << nDY
<< ")" );
116 meRefDevMode
= RefDevMode::NONE
;
117 mbForceZeroExtleadBug
= false;
119 bool bErase
= nDX
> 0 && nDY
> 0;
127 ImplSVData
* pSVData
= ImplGetSVData();
130 pOutDev
= ImplGetDefaultWindow();
134 SalGraphics
* pGraphics
;
135 if ( !pOutDev
->mpGraphics
)
136 (void)pOutDev
->AcquireGraphics();
137 pGraphics
= pOutDev
->mpGraphics
;
139 mpVirDev
= pSVData
->mpDefInst
->CreateVirtualDevice(pGraphics
, nDX
, nDY
, meFormat
, pData
);
144 // do not abort but throw an exception, may be the current thread terminates anyway (plugin-scenario)
145 throw css::uno::RuntimeException(
146 "Could not create system bitmap!",
147 css::uno::Reference
< css::uno::XInterface
>() );
152 case DeviceFormat::BITMASK
:
156 mnBitCount
= pOutDev
->GetBitCount();
163 if (meFormat
== DeviceFormat::BITMASK
)
164 SetAntialiasing( AntialiasingFlags::DisableText
);
166 if ( pOutDev
->GetOutDevType() == OUTDEV_PRINTER
)
167 mbScreenComp
= false;
168 else if ( pOutDev
->IsVirtual() )
169 mbScreenComp
= static_cast<const VirtualDevice
*>(pOutDev
)->mbScreenComp
;
172 mxFontCollection
= pSVData
->maGDIData
.mxScreenFontList
;
173 mxFontCache
= pSVData
->maGDIData
.mxScreenFontCache
;
174 mnDPIX
= pOutDev
->mnDPIX
;
175 mnDPIY
= pOutDev
->mnDPIY
;
176 mnDPIScalePercentage
= pOutDev
->mnDPIScalePercentage
;
177 maFont
= pOutDev
->maFont
;
179 if( maTextColor
!= pOutDev
->maTextColor
)
181 maTextColor
= pOutDev
->maTextColor
;
182 mbInitTextColor
= true;
185 // virtual devices have white background by default
186 SetBackground( Wallpaper( COL_WHITE
) );
188 // #i59283# don't erase user-provided surface
189 if( !pData
&& bErase
)
192 // register VirDev in the list
193 mpNext
= pSVData
->maGDIData
.mpFirstVirDev
;
196 mpNext
->mpPrev
= this;
197 pSVData
->maGDIData
.mpFirstVirDev
= this;
200 VirtualDevice::VirtualDevice(const OutputDevice
* pCompDev
, DeviceFormat eFormat
,
201 DeviceFormat eAlphaFormat
, OutDevType eOutDevType
)
202 : OutputDevice(eOutDevType
)
204 , meAlphaFormat(eAlphaFormat
)
206 SAL_INFO( "vcl.virdev", "VirtualDevice::VirtualDevice( " << static_cast<int>(eFormat
)
207 << ", " << static_cast<int>(eAlphaFormat
)
208 << ", " << static_cast<int>(eOutDevType
) << " )" );
210 ImplInitVirDev(pCompDev
? pCompDev
: Application::GetDefaultDevice(), 0, 0);
213 VirtualDevice::VirtualDevice(const SystemGraphicsData
& rData
, const Size
&rSize
,
214 DeviceFormat eFormat
)
215 : OutputDevice(OUTDEV_VIRDEV
)
217 , meAlphaFormat(DeviceFormat::NONE
)
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 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() )
301 pNewVirDev
= pSVData
->mpDefInst
->CreateVirtualDevice(mpGraphics
, nNewWidth
, nNewHeight
, meFormat
);
304 SalGraphics
* pGraphics
= pNewVirDev
->AcquireGraphics();
309 if ( mnOutWidth
< nNewWidth
)
313 if ( mnOutHeight
< nNewHeight
)
314 nHeight
= mnOutHeight
;
316 nHeight
= nNewHeight
;
317 SalTwoRect
aPosAry(0, 0, nWidth
, nHeight
, 0, 0, nWidth
, nHeight
);
318 pGraphics
->CopyBits( aPosAry
, mpGraphics
, this, this );
319 pNewVirDev
->ReleaseGraphics( pGraphics
);
321 mpVirDev
= std::move(pNewVirDev
);
322 mnOutWidth
= rNewSize
.Width();
323 mnOutHeight
= rNewSize
.Height();
338 // #i32109#: Fill opaque areas correctly (without relying on
339 // fill/linecolor state)
340 void VirtualDevice::ImplFillOpaqueRectangle( const tools::Rectangle
& rRect
)
342 // Set line and fill color to black (->opaque),
343 // fill rect with that (linecolor, too, because of
344 // those pesky missing pixel problems)
345 Push( PushFlags::LINECOLOR
| PushFlags::FILLCOLOR
);
346 SetLineColor( COL_BLACK
);
347 SetFillColor( COL_BLACK
);
352 bool VirtualDevice::ImplSetOutputSizePixel( const Size
& rNewSize
, bool bErase
,
353 sal_uInt8
*const pBuffer
)
355 if( InnerImplSetOutputSizePixel(rNewSize
, bErase
, pBuffer
) )
357 if (meAlphaFormat
!= DeviceFormat::NONE
)
359 // #110958# Setup alpha bitmap
360 if(mpAlphaVDev
&& mpAlphaVDev
->GetOutputSizePixel() != rNewSize
)
362 mpAlphaVDev
.disposeAndClear();
367 mpAlphaVDev
= VclPtr
<VirtualDevice
>::Create(*this, meAlphaFormat
);
368 mpAlphaVDev
->InnerImplSetOutputSizePixel(rNewSize
, bErase
, nullptr);
371 // TODO: copy full outdev state to new one, here. Also needed in outdev2.cxx:DrawOutDev
372 if( GetLineColor() != COL_TRANSPARENT
)
373 mpAlphaVDev
->SetLineColor( COL_BLACK
);
375 if( GetFillColor() != COL_TRANSPARENT
)
376 mpAlphaVDev
->SetFillColor( COL_BLACK
);
378 mpAlphaVDev
->SetMapMode( GetMapMode() );
387 void VirtualDevice::EnableRTL( bool bEnable
)
389 // virdevs default to not mirroring, they will only be set to mirroring
390 // under rare circumstances in the UI, eg the valueset control
391 // because each virdev has its own SalGraphics we can safely switch the SalGraphics here
393 if( AcquireGraphics() )
394 mpGraphics
->SetLayout( bEnable
? SalLayoutFlags::BiDiRtl
: SalLayoutFlags::NONE
);
396 OutputDevice::EnableRTL(bEnable
);
399 bool VirtualDevice::SetOutputSizePixel( const Size
& rNewSize
, bool bErase
)
401 return ImplSetOutputSizePixel(rNewSize
, bErase
, nullptr);
404 bool VirtualDevice::SetOutputSizePixelScaleOffsetAndBuffer(
405 const Size
& rNewSize
, const Fraction
& rScale
, const Point
& rNewOffset
,
406 sal_uInt8
*const pBuffer
)
409 MapMode mm
= GetMapMode();
410 mm
.SetOrigin( rNewOffset
);
411 mm
.SetScaleX( rScale
);
412 mm
.SetScaleY( rScale
);
415 return ImplSetOutputSizePixel(rNewSize
, true, pBuffer
);
418 void VirtualDevice::SetReferenceDevice( RefDevMode i_eRefDevMode
)
420 sal_Int32 nDPIX
= 600, nDPIY
= 600;
421 switch( i_eRefDevMode
)
423 case RefDevMode::NONE
:
425 SAL_WARN( "vcl.virdev", "VDev::SetRefDev illegal argument!" );
427 case RefDevMode::Dpi600
:
430 case RefDevMode::MSO1
:
431 nDPIX
= nDPIY
= 6*1440;
433 case RefDevMode::PDF1
:
437 ImplSetReferenceDevice( i_eRefDevMode
, nDPIX
, nDPIY
);
440 void VirtualDevice::SetReferenceDevice( sal_Int32 i_nDPIX
, sal_Int32 i_nDPIY
)
442 ImplSetReferenceDevice( RefDevMode::Custom
, i_nDPIX
, i_nDPIY
);
445 bool VirtualDevice::IsVirtual() const
450 void VirtualDevice::ImplSetReferenceDevice( RefDevMode i_eRefDevMode
, sal_Int32 i_nDPIX
, sal_Int32 i_nDPIY
)
454 mnDPIScalePercentage
= 100;
456 EnableOutput( false ); // prevent output on reference device
457 mbScreenComp
= false;
459 // invalidate currently selected fonts
463 // avoid adjusting font lists when already in refdev mode
464 RefDevMode nOldRefDevMode
= meRefDevMode
;
465 meRefDevMode
= i_eRefDevMode
;
466 if( nOldRefDevMode
!= RefDevMode::NONE
)
469 // the reference device should have only scalable fonts
470 // => clean up the original font lists before getting new ones
471 mpFontInstance
.clear();
472 mpDeviceFontList
.reset();
473 mpDeviceFontSizeList
.reset();
475 // preserve global font lists
476 ImplSVData
* pSVData
= ImplGetSVData();
477 mxFontCollection
.reset();
480 // get font list with scalable fonts only
481 (void)AcquireGraphics();
482 mxFontCollection
= pSVData
->maGDIData
.mxScreenFontList
->Clone();
484 // prepare to use new font lists
485 mxFontCache
.reset(new ImplFontCache
);
488 sal_uInt16
VirtualDevice::GetBitCount() const
493 bool VirtualDevice::UsePolyPolygonForComplexGradient()
498 void VirtualDevice::Compat_ZeroExtleadBug()
500 mbForceZeroExtleadBug
= true;
503 long VirtualDevice::GetFontExtLeading() const
506 // backwards compatible line metrics after fixing #i60945#
507 if ( mbForceZeroExtleadBug
)
511 return mpFontInstance
->mxFontMetric
->GetExternalLeading();
514 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */