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>
21 #include <sal/log.hxx>
23 #include <tools/debug.hxx>
24 #include <vcl/gdimtf.hxx>
25 #include <vcl/graph.hxx>
26 #include <vcl/metaact.hxx>
27 #include <vcl/virdev.hxx>
28 #include <vcl/outdev.hxx>
29 #include <vcl/toolkit/unowrap.hxx>
30 #include <vcl/svapp.hxx>
31 #include <vcl/sysdata.hxx>
37 #ifdef DISABLE_DYNLOADING
38 // Linking all needed LO code into one .so/executable, these already
39 // exist in the tools library, so put them in the anonymous namespace
40 // here to avoid clash...
43 #ifdef DISABLE_DYNLOADING
47 // Begin initializer and accessor public functions
49 OutputDevice::OutputDevice(OutDevType eOutDevType
) :
50 meOutDevType(eOutDevType
),
52 maFillColor( COL_WHITE
),
53 maTextLineColor( COL_TRANSPARENT
),
54 mxSettings( new AllSettings(Application::GetSettings()) )
57 mpUnoGraphicsList
= nullptr;
58 mpPrevGraphics
= nullptr;
59 mpNextGraphics
= nullptr;
61 mpFontInstance
= nullptr;
62 mpDeviceFontList
= nullptr;
63 mpDeviceFontSizeList
= nullptr;
64 mpAlphaVDev
= nullptr;
65 mpExtOutDevData
= nullptr;
72 mnDPIScalePercentage
= 100;
80 mnEmphasisDescent
= 0;
81 mnDrawMode
= DrawModeFlags::Default
;
82 mnTextLayoutMode
= ComplexTextLayoutFlags::Default
;
84 if( AllSettings::GetLayoutRTL() ) //#i84553# tip BiDi preference to RTL
85 mnTextLayoutMode
= ComplexTextLayoutFlags::BiDiRtl
| ComplexTextLayoutFlags::TextOriginLeft
;
87 meOutDevViewType
= OutDevViewType::DontKnow
;
93 mbOutputClipped
= false;
94 maTextColor
= COL_BLACK
;
95 maOverlineColor
= COL_TRANSPARENT
;
96 meRasterOp
= RasterOp::OverPaint
;
97 mnAntialiasing
= AntialiasingFlags::NONE
;
98 meTextLanguage
= LANGUAGE_SYSTEM
; // TODO: get default from configuration?
101 mbInitLineColor
= true;
102 mbInitFillColor
= true;
104 mbInitTextColor
= true;
105 mbInitClipRegion
= true;
106 mbClipRegionSet
= false;
109 mbTextSpecial
= false;
111 mbEnableRTL
= false; // mirroring must be explicitly allowed (typically for windows only)
114 maMapRes
.mnMapOfsX
= 0;
115 maMapRes
.mnMapOfsY
= 0;
116 maMapRes
.mnMapScNumX
= 1;
117 maMapRes
.mnMapScNumY
= 1;
118 maMapRes
.mnMapScDenomX
= 1;
119 maMapRes
.mnMapScDenomY
= 1;
120 // struct ImplThresholdRes
121 maThresRes
.mnThresLogToPixX
= 0;
122 maThresRes
.mnThresLogToPixY
= 0;
123 maThresRes
.mnThresPixToLogX
= 0;
124 maThresRes
.mnThresPixToLogY
= 0;
126 // struct ImplOutDevData- see #i82615#
127 mpOutDevData
.reset(new ImplOutDevData
);
128 mpOutDevData
->mpRotateDev
= nullptr;
129 mpOutDevData
->mpRecordLayout
= nullptr;
132 mpOutDevData
->mpViewTransform
= nullptr;
133 mpOutDevData
->mpInverseViewTransform
= nullptr;
136 OutputDevice::~OutputDevice()
141 void OutputDevice::dispose()
143 if ( GetUnoGraphicsList() )
145 UnoWrapperBase
* pWrapper
= UnoWrapperBase::GetUnoWrapper( false );
147 pWrapper
->ReleaseAllGraphics( this );
148 delete mpUnoGraphicsList
;
149 mpUnoGraphicsList
= nullptr;
152 mpOutDevData
->mpRotateDev
.disposeAndClear();
155 ImplInvalidateViewTransform();
157 mpOutDevData
.reset();
159 // for some reason, we haven't removed state from the stack properly
160 if ( !maOutDevStateStack
.empty() )
161 SAL_WARN( "vcl.gdi", "OutputDevice::~OutputDevice(): OutputDevice::Push() calls != OutputDevice::Pop() calls" );
162 maOutDevStateStack
.clear();
164 // release the active font instance
165 mpFontInstance
.clear();
167 // remove cached results of GetDevFontList/GetDevSizeList
168 mpDeviceFontList
.reset();
169 mpDeviceFontSizeList
.reset();
171 // release ImplFontCache specific to this OutputDevice
174 // release ImplFontList specific to this OutputDevice
175 mxFontCollection
.reset();
177 mpAlphaVDev
.disposeAndClear();
178 mpPrevGraphics
.clear();
179 mpNextGraphics
.clear();
180 VclReferenceBase::dispose();
183 bool OutputDevice::IsVirtual() const
188 SalGraphics
* OutputDevice::GetGraphics()
190 DBG_TESTSOLARMUTEX();
192 if (!mpGraphics
&& !AcquireGraphics())
193 SAL_WARN("vcl.gdi", "No mpGraphics set");
198 SalGraphics
const *OutputDevice::GetGraphics() const
200 DBG_TESTSOLARMUTEX();
202 if (!mpGraphics
&& !AcquireGraphics())
203 SAL_WARN("vcl.gdi", "No mpGraphics set");
208 void OutputDevice::SetConnectMetaFile( GDIMetaFile
* pMtf
)
213 void OutputDevice::SetSettings( const AllSettings
& rSettings
)
215 *mxSettings
= rSettings
;
218 mpAlphaVDev
->SetSettings( rSettings
);
221 SystemGraphicsData
OutputDevice::GetSystemGfxData() const
223 if (!mpGraphics
&& !AcquireGraphics())
224 return SystemGraphicsData();
226 return mpGraphics
->GetGraphicsData();
229 #if ENABLE_CAIRO_CANVAS
231 bool OutputDevice::SupportsCairo() const
233 if (!mpGraphics
&& !AcquireGraphics())
236 return mpGraphics
->SupportsCairo();
239 cairo::SurfaceSharedPtr
OutputDevice::CreateSurface(const cairo::CairoSurfaceSharedPtr
& rSurface
) const
241 if (!mpGraphics
&& !AcquireGraphics())
242 return cairo::SurfaceSharedPtr();
243 return mpGraphics
->CreateSurface(rSurface
);
246 cairo::SurfaceSharedPtr
OutputDevice::CreateSurface(int x
, int y
, int width
, int height
) const
248 if (!mpGraphics
&& !AcquireGraphics())
249 return cairo::SurfaceSharedPtr();
250 return mpGraphics
->CreateSurface(*this, x
, y
, width
, height
);
253 cairo::SurfaceSharedPtr
OutputDevice::CreateBitmapSurface(const BitmapSystemData
& rData
, const Size
& rSize
) const
255 if (!mpGraphics
&& !AcquireGraphics())
256 return cairo::SurfaceSharedPtr();
257 return mpGraphics
->CreateBitmapSurface(*this, rData
, rSize
);
260 css::uno::Any
OutputDevice::GetNativeSurfaceHandle(cairo::SurfaceSharedPtr
& rSurface
, const basegfx::B2ISize
& rSize
) const
262 if (!mpGraphics
&& !AcquireGraphics())
263 return css::uno::Any();
264 return mpGraphics
->GetNativeSurfaceHandle(rSurface
, rSize
);
267 #endif // ENABLE_CAIRO_CANVAS
269 css::uno::Any
OutputDevice::GetSystemGfxDataAny() const
271 const SystemGraphicsData aSysData
= GetSystemGfxData();
272 css::uno::Sequence
< sal_Int8
> aSeq( reinterpret_cast<sal_Int8
const *>(&aSysData
),
275 return css::uno::makeAny(aSeq
);
278 void OutputDevice::SetRefPoint()
282 mpMetaFile
->AddAction( new MetaRefPointAction( Point(), false ) );
289 mpAlphaVDev
->SetRefPoint();
292 void OutputDevice::SetRefPoint( const Point
& rRefPoint
)
296 mpMetaFile
->AddAction( new MetaRefPointAction( rRefPoint
, true ) );
299 maRefPoint
= rRefPoint
;
302 mpAlphaVDev
->SetRefPoint( rRefPoint
);
305 sal_uInt16
OutputDevice::GetBitCount() const
307 // we need a graphics instance
308 if ( !mpGraphics
&& !AcquireGraphics() )
311 return mpGraphics
->GetBitCount();
314 void OutputDevice::SetOutOffXPixel(long nOutOffX
)
316 mnOutOffX
= nOutOffX
;
319 void OutputDevice::SetOutOffYPixel(long nOutOffY
)
321 mnOutOffY
= nOutOffY
;
324 css::uno::Reference
< css::awt::XGraphics
> OutputDevice::CreateUnoGraphics()
326 UnoWrapperBase
* pWrapper
= UnoWrapperBase::GetUnoWrapper();
327 return pWrapper
? pWrapper
->CreateGraphics( this ) : css::uno::Reference
< css::awt::XGraphics
>();
330 std::vector
< VCLXGraphics
* > *OutputDevice::CreateUnoGraphicsList()
332 mpUnoGraphicsList
= new std::vector
< VCLXGraphics
* >;
333 return mpUnoGraphicsList
;
336 // Helper public function
338 bool OutputDevice::SupportsOperation( OutDevSupportType eType
) const
340 if( !mpGraphics
&& !AcquireGraphics() )
342 const bool bHasSupport
= mpGraphics
->supportsOperation( eType
);
346 // Direct OutputDevice drawing public functions
348 void OutputDevice::DrawOutDev( const Point
& rDestPt
, const Size
& rDestSize
,
349 const Point
& rSrcPt
, const Size
& rSrcSize
)
351 if( ImplIsRecordLayout() )
354 if ( RasterOp::Invert
== meRasterOp
)
356 DrawRect( tools::Rectangle( rDestPt
, rDestSize
) );
362 const Bitmap
aBmp( GetBitmap( rSrcPt
, rSrcSize
) );
363 mpMetaFile
->AddAction( new MetaBmpScaleAction( rDestPt
, rDestSize
, aBmp
) );
366 if ( !IsDeviceOutputNecessary() )
369 if ( !mpGraphics
&& !AcquireGraphics() )
372 if ( mbInitClipRegion
)
375 if ( mbOutputClipped
)
378 long nSrcWidth
= ImplLogicWidthToDevicePixel( rSrcSize
.Width() );
379 long nSrcHeight
= ImplLogicHeightToDevicePixel( rSrcSize
.Height() );
380 long nDestWidth
= ImplLogicWidthToDevicePixel( rDestSize
.Width() );
381 long nDestHeight
= ImplLogicHeightToDevicePixel( rDestSize
.Height() );
383 if (nSrcWidth
&& nSrcHeight
&& nDestWidth
&& nDestHeight
)
385 SalTwoRect
aPosAry(ImplLogicXToDevicePixel(rSrcPt
.X()), ImplLogicYToDevicePixel(rSrcPt
.Y()),
386 nSrcWidth
, nSrcHeight
,
387 ImplLogicXToDevicePixel(rDestPt
.X()), ImplLogicYToDevicePixel(rDestPt
.Y()),
388 nDestWidth
, nDestHeight
);
390 const tools::Rectangle
aSrcOutRect( Point( mnOutOffX
, mnOutOffY
),
391 Size( mnOutWidth
, mnOutHeight
) );
393 AdjustTwoRect( aPosAry
, aSrcOutRect
);
395 if ( aPosAry
.mnSrcWidth
&& aPosAry
.mnSrcHeight
&& aPosAry
.mnDestWidth
&& aPosAry
.mnDestHeight
)
396 mpGraphics
->CopyBits( aPosAry
, nullptr, this, nullptr );
400 mpAlphaVDev
->DrawOutDev( rDestPt
, rDestSize
, rSrcPt
, rSrcSize
);
403 void OutputDevice::DrawOutDev( const Point
& rDestPt
, const Size
& rDestSize
,
404 const Point
& rSrcPt
, const Size
& rSrcSize
,
405 const OutputDevice
& rOutDev
)
407 if ( ImplIsRecordLayout() )
410 if ( RasterOp::Invert
== meRasterOp
)
412 DrawRect( tools::Rectangle( rDestPt
, rDestSize
) );
418 const Bitmap
aBmp( rOutDev
.GetBitmap( rSrcPt
, rSrcSize
) );
419 mpMetaFile
->AddAction( new MetaBmpScaleAction( rDestPt
, rDestSize
, aBmp
) );
422 if ( !IsDeviceOutputNecessary() )
425 if ( !mpGraphics
&& !AcquireGraphics() )
428 if ( mbInitClipRegion
)
431 if ( mbOutputClipped
)
434 SalTwoRect
aPosAry(rOutDev
.ImplLogicXToDevicePixel(rSrcPt
.X()),
435 rOutDev
.ImplLogicYToDevicePixel(rSrcPt
.Y()),
436 rOutDev
.ImplLogicWidthToDevicePixel(rSrcSize
.Width()),
437 rOutDev
.ImplLogicHeightToDevicePixel(rSrcSize
.Height()),
438 ImplLogicXToDevicePixel(rDestPt
.X()),
439 ImplLogicYToDevicePixel(rDestPt
.Y()),
440 ImplLogicWidthToDevicePixel(rDestSize
.Width()),
441 ImplLogicHeightToDevicePixel(rDestSize
.Height()));
445 if( rOutDev
.mpAlphaVDev
)
447 // alpha-blend source over destination
448 DrawBitmapEx( rDestPt
, rDestSize
, rOutDev
.GetBitmapEx(rSrcPt
, rSrcSize
) );
452 drawOutDevDirect( &rOutDev
, aPosAry
);
454 // #i32109#: make destination rectangle opaque - source has no alpha
455 mpAlphaVDev
->ImplFillOpaqueRectangle( tools::Rectangle(rDestPt
, rDestSize
) );
460 if( rOutDev
.mpAlphaVDev
)
462 // alpha-blend source over destination
463 DrawBitmapEx( rDestPt
, rDestSize
, rOutDev
.GetBitmapEx(rSrcPt
, rSrcSize
) );
467 // no alpha at all, neither in source nor destination device
468 drawOutDevDirect( &rOutDev
, aPosAry
);
473 void OutputDevice::CopyArea( const Point
& rDestPt
,
474 const Point
& rSrcPt
, const Size
& rSrcSize
,
475 bool bWindowInvalidate
)
477 if ( ImplIsRecordLayout() )
480 RasterOp eOldRop
= GetRasterOp();
481 SetRasterOp( RasterOp::OverPaint
);
483 if ( !IsDeviceOutputNecessary() )
486 if ( !mpGraphics
&& !AcquireGraphics() )
489 if ( mbInitClipRegion
)
492 if ( mbOutputClipped
)
495 long nSrcWidth
= ImplLogicWidthToDevicePixel( rSrcSize
.Width() );
496 long nSrcHeight
= ImplLogicHeightToDevicePixel( rSrcSize
.Height() );
497 if (nSrcWidth
&& nSrcHeight
)
499 SalTwoRect
aPosAry(ImplLogicXToDevicePixel(rSrcPt
.X()), ImplLogicYToDevicePixel(rSrcPt
.Y()),
500 nSrcWidth
, nSrcHeight
,
501 ImplLogicXToDevicePixel(rDestPt
.X()), ImplLogicYToDevicePixel(rDestPt
.Y()),
502 nSrcWidth
, nSrcHeight
);
504 const tools::Rectangle
aSrcOutRect( Point( mnOutOffX
, mnOutOffY
),
505 Size( mnOutWidth
, mnOutHeight
) );
507 AdjustTwoRect( aPosAry
, aSrcOutRect
);
509 CopyDeviceArea( aPosAry
, bWindowInvalidate
);
512 SetRasterOp( eOldRop
);
515 mpAlphaVDev
->CopyArea( rDestPt
, rSrcPt
, rSrcSize
, bWindowInvalidate
);
518 // Direct OutputDevice drawing protected function
520 void OutputDevice::CopyDeviceArea( SalTwoRect
& aPosAry
, bool /*bWindowInvalidate*/)
522 if (aPosAry
.mnSrcWidth
== 0 || aPosAry
.mnSrcHeight
== 0 || aPosAry
.mnDestWidth
== 0 || aPosAry
.mnDestHeight
== 0)
525 aPosAry
.mnDestWidth
= aPosAry
.mnSrcWidth
;
526 aPosAry
.mnDestHeight
= aPosAry
.mnSrcHeight
;
527 mpGraphics
->CopyBits(aPosAry
, nullptr, this, nullptr);
530 // Direct OutputDevice drawing private function
532 void OutputDevice::drawOutDevDirect( const OutputDevice
* pSrcDev
, SalTwoRect
& rPosAry
)
534 SalGraphics
* pSrcGraphics
;
536 if ( this == pSrcDev
)
537 pSrcGraphics
= nullptr;
540 if ( (GetOutDevType() != pSrcDev
->GetOutDevType()) ||
541 (GetOutDevType() != OUTDEV_WINDOW
) )
543 if ( !pSrcDev
->mpGraphics
)
545 if ( !pSrcDev
->AcquireGraphics() )
548 pSrcGraphics
= pSrcDev
->mpGraphics
;
552 if ( static_cast<vcl::Window
*>(this)->mpWindowImpl
->mpFrameWindow
== static_cast<const vcl::Window
*>(pSrcDev
)->mpWindowImpl
->mpFrameWindow
)
553 pSrcGraphics
= nullptr;
556 if ( !pSrcDev
->mpGraphics
)
558 if ( !pSrcDev
->AcquireGraphics() )
561 pSrcGraphics
= pSrcDev
->mpGraphics
;
563 if ( !mpGraphics
&& !AcquireGraphics() )
565 SAL_WARN_IF( !mpGraphics
|| !pSrcDev
->mpGraphics
, "vcl.gdi",
566 "OutputDevice::DrawOutDev(): We need more than one Graphics" );
571 // #102532# Offset only has to be pseudo window offset
572 const tools::Rectangle
aSrcOutRect( Point( pSrcDev
->mnOutOffX
, pSrcDev
->mnOutOffY
),
573 Size( pSrcDev
->mnOutWidth
, pSrcDev
->mnOutHeight
) );
575 AdjustTwoRect( rPosAry
, aSrcOutRect
);
577 if ( rPosAry
.mnSrcWidth
&& rPosAry
.mnSrcHeight
&& rPosAry
.mnDestWidth
&& rPosAry
.mnDestHeight
)
579 // if this is no window, but pSrcDev is a window
580 // mirroring may be required
581 // because only windows have a SalGraphicsLayout
582 // mirroring is performed here
583 if( (GetOutDevType() != OUTDEV_WINDOW
) && pSrcGraphics
&& (pSrcGraphics
->GetLayout() & SalLayoutFlags::BiDiRtl
) )
585 SalTwoRect aPosAry2
= rPosAry
;
586 pSrcGraphics
->mirror( aPosAry2
.mnSrcX
, aPosAry2
.mnSrcWidth
, pSrcDev
);
587 mpGraphics
->CopyBits( aPosAry2
, pSrcGraphics
, this, pSrcDev
);
590 mpGraphics
->CopyBits( rPosAry
, pSrcGraphics
, this, pSrcDev
);
594 // Layout public functions
596 void OutputDevice::EnableRTL( bool bEnable
)
598 mbEnableRTL
= bEnable
;
601 mpAlphaVDev
->EnableRTL( bEnable
);
604 bool OutputDevice::ImplIsAntiparallel() const
607 if( AcquireGraphics() )
609 if( ( (mpGraphics
->GetLayout() & SalLayoutFlags::BiDiRtl
) && ! IsRTLEnabled() ) ||
610 ( ! (mpGraphics
->GetLayout() & SalLayoutFlags::BiDiRtl
) && IsRTLEnabled() ) )
618 // note: the coordinates to be remirrored are in frame coordinates !
620 void OutputDevice::ReMirror( Point
&rPoint
) const
622 rPoint
.setX( mnOutOffX
+ mnOutWidth
- 1 - rPoint
.X() + mnOutOffX
);
624 void OutputDevice::ReMirror( tools::Rectangle
&rRect
) const
626 long nWidth
= rRect
.Right() - rRect
.Left();
628 //long lc_x = rRect.nLeft - mnOutOffX; // normalize
629 //lc_x = mnOutWidth - nWidth - 1 - lc_x; // mirror
630 //rRect.nLeft = lc_x + mnOutOffX; // re-normalize
632 rRect
.SetLeft( mnOutOffX
+ mnOutWidth
- nWidth
- 1 - rRect
.Left() + mnOutOffX
);
633 rRect
.SetRight( rRect
.Left() + nWidth
);
636 void OutputDevice::ReMirror( vcl::Region
&rRegion
) const
638 RectangleVector aRectangles
;
639 rRegion
.GetRegionRectangles(aRectangles
);
640 vcl::Region aMirroredRegion
;
642 for (auto & rectangle
: aRectangles
)
645 aMirroredRegion
.Union(rectangle
);
648 rRegion
= aMirroredRegion
;
652 bool OutputDevice::HasMirroredGraphics() const
654 return ( AcquireGraphics() && (mpGraphics
->GetLayout() & SalLayoutFlags::BiDiRtl
) );
657 bool OutputDevice::ImplIsRecordLayout() const
662 return mpOutDevData
->mpRecordLayout
;
665 // EPS public function
667 bool OutputDevice::DrawEPS( const Point
& rPoint
, const Size
& rSize
,
668 const GfxLink
& rGfxLink
, GDIMetaFile
* pSubst
)
679 mpMetaFile
->AddAction( new MetaEPSAction( rPoint
, rSize
, rGfxLink
, aSubst
) );
682 if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
685 if( mbOutputClipped
)
688 tools::Rectangle
aRect( ImplLogicToDevicePixel( tools::Rectangle( rPoint
, rSize
) ) );
690 if( !aRect
.IsEmpty() )
692 // draw the real EPS graphics
693 if( rGfxLink
.GetData() && rGfxLink
.GetDataSize() )
695 if( !mpGraphics
&& !AcquireGraphics() )
698 if( mbInitClipRegion
)
702 bDrawn
= mpGraphics
->DrawEPS( aRect
.Left(), aRect
.Top(), aRect
.GetWidth(), aRect
.GetHeight(),
703 const_cast<sal_uInt8
*>(rGfxLink
.GetData()), rGfxLink
.GetDataSize(), this );
706 // else draw the substitution graphics
707 if( !bDrawn
&& pSubst
)
709 GDIMetaFile
* pOldMetaFile
= mpMetaFile
;
711 mpMetaFile
= nullptr;
712 Graphic( *pSubst
).Draw( this, rPoint
, rSize
);
713 mpMetaFile
= pOldMetaFile
;
718 mpAlphaVDev
->DrawEPS( rPoint
, rSize
, rGfxLink
, pSubst
);
723 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */