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;
121 // struct ImplOutDevData- see #i82615#
122 mpOutDevData
.reset(new ImplOutDevData
);
123 mpOutDevData
->mpRotateDev
= nullptr;
124 mpOutDevData
->mpRecordLayout
= nullptr;
127 mpOutDevData
->mpViewTransform
= nullptr;
128 mpOutDevData
->mpInverseViewTransform
= nullptr;
131 OutputDevice::~OutputDevice()
136 void OutputDevice::dispose()
138 if ( GetUnoGraphicsList() )
140 UnoWrapperBase
* pWrapper
= UnoWrapperBase::GetUnoWrapper( false );
142 pWrapper
->ReleaseAllGraphics( this );
143 delete mpUnoGraphicsList
;
144 mpUnoGraphicsList
= nullptr;
147 mpOutDevData
->mpRotateDev
.disposeAndClear();
150 ImplInvalidateViewTransform();
152 mpOutDevData
.reset();
154 // for some reason, we haven't removed state from the stack properly
155 if ( !maOutDevStateStack
.empty() )
156 SAL_WARN( "vcl.gdi", "OutputDevice::~OutputDevice(): OutputDevice::Push() calls != OutputDevice::Pop() calls" );
157 maOutDevStateStack
.clear();
159 // release the active font instance
160 mpFontInstance
.clear();
162 // remove cached results of GetDevFontList/GetDevSizeList
163 mpDeviceFontList
.reset();
164 mpDeviceFontSizeList
.reset();
166 // release ImplFontCache specific to this OutputDevice
169 // release ImplFontList specific to this OutputDevice
170 mxFontCollection
.reset();
172 mpAlphaVDev
.disposeAndClear();
173 mpPrevGraphics
.clear();
174 mpNextGraphics
.clear();
175 VclReferenceBase::dispose();
178 bool OutputDevice::IsVirtual() const
183 SalGraphics
* OutputDevice::GetGraphics()
185 DBG_TESTSOLARMUTEX();
187 if (!mpGraphics
&& !AcquireGraphics())
188 SAL_WARN("vcl.gdi", "No mpGraphics set");
193 SalGraphics
const *OutputDevice::GetGraphics() const
195 DBG_TESTSOLARMUTEX();
197 if (!mpGraphics
&& !AcquireGraphics())
198 SAL_WARN("vcl.gdi", "No mpGraphics set");
203 void OutputDevice::SetConnectMetaFile( GDIMetaFile
* pMtf
)
208 void OutputDevice::SetSettings( const AllSettings
& rSettings
)
210 *mxSettings
= rSettings
;
213 mpAlphaVDev
->SetSettings( rSettings
);
216 SystemGraphicsData
OutputDevice::GetSystemGfxData() const
218 if (!mpGraphics
&& !AcquireGraphics())
219 return SystemGraphicsData();
221 return mpGraphics
->GetGraphicsData();
224 #if ENABLE_CAIRO_CANVAS
226 bool OutputDevice::SupportsCairo() const
228 if (!mpGraphics
&& !AcquireGraphics())
231 return mpGraphics
->SupportsCairo();
234 cairo::SurfaceSharedPtr
OutputDevice::CreateSurface(const cairo::CairoSurfaceSharedPtr
& rSurface
) const
236 if (!mpGraphics
&& !AcquireGraphics())
237 return cairo::SurfaceSharedPtr();
238 return mpGraphics
->CreateSurface(rSurface
);
241 cairo::SurfaceSharedPtr
OutputDevice::CreateSurface(int x
, int y
, int width
, int height
) const
243 if (!mpGraphics
&& !AcquireGraphics())
244 return cairo::SurfaceSharedPtr();
245 return mpGraphics
->CreateSurface(*this, x
, y
, width
, height
);
248 cairo::SurfaceSharedPtr
OutputDevice::CreateBitmapSurface(const BitmapSystemData
& rData
, const Size
& rSize
) const
250 if (!mpGraphics
&& !AcquireGraphics())
251 return cairo::SurfaceSharedPtr();
252 return mpGraphics
->CreateBitmapSurface(*this, rData
, rSize
);
255 css::uno::Any
OutputDevice::GetNativeSurfaceHandle(cairo::SurfaceSharedPtr
& rSurface
, const basegfx::B2ISize
& rSize
) const
257 if (!mpGraphics
&& !AcquireGraphics())
258 return css::uno::Any();
259 return mpGraphics
->GetNativeSurfaceHandle(rSurface
, rSize
);
262 #endif // ENABLE_CAIRO_CANVAS
264 css::uno::Any
OutputDevice::GetSystemGfxDataAny() const
266 const SystemGraphicsData aSysData
= GetSystemGfxData();
267 css::uno::Sequence
< sal_Int8
> aSeq( reinterpret_cast<sal_Int8
const *>(&aSysData
),
270 return css::uno::makeAny(aSeq
);
273 void OutputDevice::SetRefPoint()
277 mpMetaFile
->AddAction( new MetaRefPointAction( Point(), false ) );
284 mpAlphaVDev
->SetRefPoint();
287 void OutputDevice::SetRefPoint( const Point
& rRefPoint
)
291 mpMetaFile
->AddAction( new MetaRefPointAction( rRefPoint
, true ) );
294 maRefPoint
= rRefPoint
;
297 mpAlphaVDev
->SetRefPoint( rRefPoint
);
300 sal_uInt16
OutputDevice::GetBitCount() const
302 // we need a graphics instance
303 if ( !mpGraphics
&& !AcquireGraphics() )
306 return mpGraphics
->GetBitCount();
309 void OutputDevice::SetOutOffXPixel(tools::Long nOutOffX
)
311 mnOutOffX
= nOutOffX
;
314 void OutputDevice::SetOutOffYPixel(tools::Long nOutOffY
)
316 mnOutOffY
= nOutOffY
;
319 css::uno::Reference
< css::awt::XGraphics
> OutputDevice::CreateUnoGraphics()
321 UnoWrapperBase
* pWrapper
= UnoWrapperBase::GetUnoWrapper();
322 return pWrapper
? pWrapper
->CreateGraphics( this ) : css::uno::Reference
< css::awt::XGraphics
>();
325 std::vector
< VCLXGraphics
* > *OutputDevice::CreateUnoGraphicsList()
327 mpUnoGraphicsList
= new std::vector
< VCLXGraphics
* >;
328 return mpUnoGraphicsList
;
331 // Helper public function
333 bool OutputDevice::SupportsOperation( OutDevSupportType eType
) const
335 if( !mpGraphics
&& !AcquireGraphics() )
337 const bool bHasSupport
= mpGraphics
->supportsOperation( eType
);
341 // Direct OutputDevice drawing public functions
343 void OutputDevice::DrawOutDev( const Point
& rDestPt
, const Size
& rDestSize
,
344 const Point
& rSrcPt
, const Size
& rSrcSize
)
346 if( ImplIsRecordLayout() )
349 if ( RasterOp::Invert
== meRasterOp
)
351 DrawRect( tools::Rectangle( rDestPt
, rDestSize
) );
357 const Bitmap
aBmp( GetBitmap( rSrcPt
, rSrcSize
) );
358 mpMetaFile
->AddAction( new MetaBmpScaleAction( rDestPt
, rDestSize
, aBmp
) );
361 if ( !IsDeviceOutputNecessary() )
364 if ( !mpGraphics
&& !AcquireGraphics() )
367 if ( mbInitClipRegion
)
370 if ( mbOutputClipped
)
373 tools::Long nSrcWidth
= ImplLogicWidthToDevicePixel( rSrcSize
.Width() );
374 tools::Long nSrcHeight
= ImplLogicHeightToDevicePixel( rSrcSize
.Height() );
375 tools::Long nDestWidth
= ImplLogicWidthToDevicePixel( rDestSize
.Width() );
376 tools::Long nDestHeight
= ImplLogicHeightToDevicePixel( rDestSize
.Height() );
378 if (nSrcWidth
&& nSrcHeight
&& nDestWidth
&& nDestHeight
)
380 SalTwoRect
aPosAry(ImplLogicXToDevicePixel(rSrcPt
.X()), ImplLogicYToDevicePixel(rSrcPt
.Y()),
381 nSrcWidth
, nSrcHeight
,
382 ImplLogicXToDevicePixel(rDestPt
.X()), ImplLogicYToDevicePixel(rDestPt
.Y()),
383 nDestWidth
, nDestHeight
);
385 const tools::Rectangle
aSrcOutRect( Point( mnOutOffX
, mnOutOffY
),
386 Size( mnOutWidth
, mnOutHeight
) );
388 AdjustTwoRect( aPosAry
, aSrcOutRect
);
390 if ( aPosAry
.mnSrcWidth
&& aPosAry
.mnSrcHeight
&& aPosAry
.mnDestWidth
&& aPosAry
.mnDestHeight
)
391 mpGraphics
->CopyBits( aPosAry
, nullptr, this, nullptr );
395 mpAlphaVDev
->DrawOutDev( rDestPt
, rDestSize
, rSrcPt
, rSrcSize
);
398 void OutputDevice::DrawOutDev( const Point
& rDestPt
, const Size
& rDestSize
,
399 const Point
& rSrcPt
, const Size
& rSrcSize
,
400 const OutputDevice
& rOutDev
)
402 if ( ImplIsRecordLayout() )
405 if ( RasterOp::Invert
== meRasterOp
)
407 DrawRect( tools::Rectangle( rDestPt
, rDestSize
) );
413 if (rOutDev
.mpAlphaVDev
)
415 const BitmapEx
aBmpEx(rOutDev
.GetBitmapEx(rSrcPt
, rSrcSize
));
416 mpMetaFile
->AddAction(new MetaBmpExScaleAction(rDestPt
, rDestSize
, aBmpEx
));
420 const Bitmap
aBmp(rOutDev
.GetBitmap(rSrcPt
, rSrcSize
));
421 mpMetaFile
->AddAction(new MetaBmpScaleAction(rDestPt
, rDestSize
, aBmp
));
425 if ( !IsDeviceOutputNecessary() )
428 if ( !mpGraphics
&& !AcquireGraphics() )
431 if ( mbInitClipRegion
)
434 if ( mbOutputClipped
)
437 if (rOutDev
.mpAlphaVDev
)
439 // alpha-blend source over destination
440 DrawBitmapEx(rDestPt
, rDestSize
, rOutDev
.GetBitmapEx(rSrcPt
, rSrcSize
));
444 SalTwoRect
aPosAry(rOutDev
.ImplLogicXToDevicePixel(rSrcPt
.X()),
445 rOutDev
.ImplLogicYToDevicePixel(rSrcPt
.Y()),
446 rOutDev
.ImplLogicWidthToDevicePixel(rSrcSize
.Width()),
447 rOutDev
.ImplLogicHeightToDevicePixel(rSrcSize
.Height()),
448 ImplLogicXToDevicePixel(rDestPt
.X()),
449 ImplLogicYToDevicePixel(rDestPt
.Y()),
450 ImplLogicWidthToDevicePixel(rDestSize
.Width()),
451 ImplLogicHeightToDevicePixel(rDestSize
.Height()));
453 drawOutDevDirect(&rOutDev
, aPosAry
);
455 // #i32109#: make destination rectangle opaque - source has no alpha
457 mpAlphaVDev
->ImplFillOpaqueRectangle(tools::Rectangle(rDestPt
, rDestSize
));
461 void OutputDevice::CopyArea( const Point
& rDestPt
,
462 const Point
& rSrcPt
, const Size
& rSrcSize
,
463 bool bWindowInvalidate
)
465 if ( ImplIsRecordLayout() )
468 RasterOp eOldRop
= GetRasterOp();
469 SetRasterOp( RasterOp::OverPaint
);
471 if ( !IsDeviceOutputNecessary() )
474 if ( !mpGraphics
&& !AcquireGraphics() )
477 if ( mbInitClipRegion
)
480 if ( mbOutputClipped
)
483 tools::Long nSrcWidth
= ImplLogicWidthToDevicePixel( rSrcSize
.Width() );
484 tools::Long nSrcHeight
= ImplLogicHeightToDevicePixel( rSrcSize
.Height() );
485 if (nSrcWidth
&& nSrcHeight
)
487 SalTwoRect
aPosAry(ImplLogicXToDevicePixel(rSrcPt
.X()), ImplLogicYToDevicePixel(rSrcPt
.Y()),
488 nSrcWidth
, nSrcHeight
,
489 ImplLogicXToDevicePixel(rDestPt
.X()), ImplLogicYToDevicePixel(rDestPt
.Y()),
490 nSrcWidth
, nSrcHeight
);
492 const tools::Rectangle
aSrcOutRect( Point( mnOutOffX
, mnOutOffY
),
493 Size( mnOutWidth
, mnOutHeight
) );
495 AdjustTwoRect( aPosAry
, aSrcOutRect
);
497 CopyDeviceArea( aPosAry
, bWindowInvalidate
);
500 SetRasterOp( eOldRop
);
503 mpAlphaVDev
->CopyArea( rDestPt
, rSrcPt
, rSrcSize
, bWindowInvalidate
);
506 // Direct OutputDevice drawing protected function
508 void OutputDevice::CopyDeviceArea( SalTwoRect
& aPosAry
, bool /*bWindowInvalidate*/)
510 if (aPosAry
.mnSrcWidth
== 0 || aPosAry
.mnSrcHeight
== 0 || aPosAry
.mnDestWidth
== 0 || aPosAry
.mnDestHeight
== 0)
513 aPosAry
.mnDestWidth
= aPosAry
.mnSrcWidth
;
514 aPosAry
.mnDestHeight
= aPosAry
.mnSrcHeight
;
515 mpGraphics
->CopyBits(aPosAry
, nullptr, this, nullptr);
518 // Direct OutputDevice drawing private function
520 void OutputDevice::drawOutDevDirect( const OutputDevice
* pSrcDev
, SalTwoRect
& rPosAry
)
522 SalGraphics
* pSrcGraphics
;
523 if (const OutputDevice
* pCheckedSrc
= DrawOutDevDirectCheck(pSrcDev
))
525 if (!pCheckedSrc
->mpGraphics
&& !pCheckedSrc
->AcquireGraphics())
527 pSrcGraphics
= pCheckedSrc
->mpGraphics
;
530 pSrcGraphics
= nullptr;
532 if (!mpGraphics
&& !AcquireGraphics())
535 // #102532# Offset only has to be pseudo window offset
536 const tools::Rectangle
aSrcOutRect( Point( pSrcDev
->mnOutOffX
, pSrcDev
->mnOutOffY
),
537 Size( pSrcDev
->mnOutWidth
, pSrcDev
->mnOutHeight
) );
539 AdjustTwoRect( rPosAry
, aSrcOutRect
);
541 if ( rPosAry
.mnSrcWidth
&& rPosAry
.mnSrcHeight
&& rPosAry
.mnDestWidth
&& rPosAry
.mnDestHeight
)
543 // if this is no window, but pSrcDev is a window
544 // mirroring may be required
545 // because only windows have a SalGraphicsLayout
546 // mirroring is performed here
547 DrawOutDevDirectProcess( pSrcDev
, rPosAry
, pSrcGraphics
);
551 const OutputDevice
* OutputDevice::DrawOutDevDirectCheck(const OutputDevice
* pSrcDev
) const
553 return this == pSrcDev
? nullptr : pSrcDev
;
556 void OutputDevice::DrawOutDevDirectProcess( const OutputDevice
* pSrcDev
, SalTwoRect
& rPosAry
, SalGraphics
* pSrcGraphics
)
558 if( pSrcGraphics
&& (pSrcGraphics
->GetLayout() & SalLayoutFlags::BiDiRtl
) )
560 SalTwoRect aPosAry2
= rPosAry
;
561 pSrcGraphics
->mirror( aPosAry2
.mnSrcX
, aPosAry2
.mnSrcWidth
, pSrcDev
);
562 mpGraphics
->CopyBits( aPosAry2
, pSrcGraphics
, this, pSrcDev
);
565 mpGraphics
->CopyBits( rPosAry
, pSrcGraphics
, this, pSrcDev
);
568 tools::Rectangle
OutputDevice::GetBackgroundComponentBounds() const
570 return tools::Rectangle( Point( 0, 0 ), GetOutputSizePixel() );
573 // Layout public functions
575 void OutputDevice::EnableRTL( bool bEnable
)
577 mbEnableRTL
= bEnable
;
580 mpAlphaVDev
->EnableRTL( bEnable
);
583 bool OutputDevice::ImplIsAntiparallel() const
586 if( AcquireGraphics() )
588 if( ( (mpGraphics
->GetLayout() & SalLayoutFlags::BiDiRtl
) && ! IsRTLEnabled() ) ||
589 ( ! (mpGraphics
->GetLayout() & SalLayoutFlags::BiDiRtl
) && IsRTLEnabled() ) )
597 // note: the coordinates to be remirrored are in frame coordinates !
599 void OutputDevice::ReMirror( Point
&rPoint
) const
601 rPoint
.setX( mnOutOffX
+ mnOutWidth
- 1 - rPoint
.X() + mnOutOffX
);
603 void OutputDevice::ReMirror( tools::Rectangle
&rRect
) const
605 tools::Long nWidth
= rRect
.Right() - rRect
.Left();
607 //long lc_x = rRect.nLeft - mnOutOffX; // normalize
608 //lc_x = mnOutWidth - nWidth - 1 - lc_x; // mirror
609 //rRect.nLeft = lc_x + mnOutOffX; // re-normalize
611 rRect
.SetLeft( mnOutOffX
+ mnOutWidth
- nWidth
- 1 - rRect
.Left() + mnOutOffX
);
612 rRect
.SetRight( rRect
.Left() + nWidth
);
615 void OutputDevice::ReMirror( vcl::Region
&rRegion
) const
617 RectangleVector aRectangles
;
618 rRegion
.GetRegionRectangles(aRectangles
);
619 vcl::Region aMirroredRegion
;
621 for (auto & rectangle
: aRectangles
)
624 aMirroredRegion
.Union(rectangle
);
627 rRegion
= aMirroredRegion
;
631 bool OutputDevice::HasMirroredGraphics() const
633 return ( AcquireGraphics() && (mpGraphics
->GetLayout() & SalLayoutFlags::BiDiRtl
) );
636 bool OutputDevice::ImplIsRecordLayout() const
641 return mpOutDevData
->mpRecordLayout
;
644 // EPS public function
646 bool OutputDevice::DrawEPS( const Point
& rPoint
, const Size
& rSize
,
647 const GfxLink
& rGfxLink
, GDIMetaFile
* pSubst
)
658 mpMetaFile
->AddAction( new MetaEPSAction( rPoint
, rSize
, rGfxLink
, aSubst
) );
661 if ( !IsDeviceOutputNecessary() || ImplIsRecordLayout() )
664 if( mbOutputClipped
)
667 tools::Rectangle
aRect( ImplLogicToDevicePixel( tools::Rectangle( rPoint
, rSize
) ) );
669 if( !aRect
.IsEmpty() )
671 // draw the real EPS graphics
672 if( rGfxLink
.GetData() && rGfxLink
.GetDataSize() )
674 if( !mpGraphics
&& !AcquireGraphics() )
677 if( mbInitClipRegion
)
681 bDrawn
= mpGraphics
->DrawEPS( aRect
.Left(), aRect
.Top(), aRect
.GetWidth(), aRect
.GetHeight(),
682 const_cast<sal_uInt8
*>(rGfxLink
.GetData()), rGfxLink
.GetDataSize(), this );
685 // else draw the substitution graphics
686 if( !bDrawn
&& pSubst
)
688 GDIMetaFile
* pOldMetaFile
= mpMetaFile
;
690 mpMetaFile
= nullptr;
691 Graphic( *pSubst
).Draw( this, rPoint
, rSize
);
692 mpMetaFile
= pOldMetaFile
;
697 mpAlphaVDev
->DrawEPS( rPoint
, rSize
, rGfxLink
, pSubst
);
702 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */