include/vcl/window.hxx | 12 ++ vcl/source/window/paint.cxx | 179 +++++++++++++++++++++++--------------------- 2 files changed, 107 insertions(+), 84 deletions(-)
New commits: commit 5094075fb1544ad29c2505f86862774c32500545 Author: Jan Holesovsky <ke...@collabora.com> Date: Tue May 19 15:54:34 2015 +0200 rendercontext: Double-buffer an entire hierarchy. This finally allows real double-buffering. Also with the per-widget setting, no need to be experimental any more. Change-Id: I405b3b2ce084cb8176b761e7113d3c3c87a6febf diff --git a/include/vcl/window.hxx b/include/vcl/window.hxx index c86ecb8..d975ff8 100644 --- a/include/vcl/window.hxx +++ b/include/vcl/window.hxx @@ -609,7 +609,17 @@ private: SAL_DLLPRIVATE void ImplCalcOverlapRegion( const Rectangle& rSourceRect, vcl::Region& rRegion, bool bChildren, bool bParent, bool bSiblings ); - SAL_DLLPRIVATE void ImplCallPaint( const vcl::Region* pRegion, sal_uInt16 nPaintFlags ); + /** Invoke the actual painting. + + This function is kind of recursive - it may be called from the + PaintHelper destructor; and on the other hand it creates PaintHelper + that (when destructed) calls other ImplCallPaint()'s. + + @param rBuffer VirtualDevice for double-buffering. It is only passed + here, the actual handling happens in the PaintHelper. + */ + SAL_DLLPRIVATE void ImplCallPaint(const VclPtr<VirtualDevice>& rBuffer, const vcl::Region* pRegion, sal_uInt16 nPaintFlags); + SAL_DLLPRIVATE void ImplCallOverlapPaint(); SAL_DLLPRIVATE void ImplPostPaint(); diff --git a/vcl/source/window/paint.cxx b/vcl/source/window/paint.cxx index 4f7f9dd..374e5de 100644 --- a/vcl/source/window/paint.cxx +++ b/vcl/source/window/paint.cxx @@ -25,7 +25,6 @@ #include <vcl/cursor.hxx> #include <vcl/settings.hxx> -#include <officecfg/Office/Common.hxx> #include <sal/types.h> #include <window.h> @@ -44,15 +43,17 @@ class PaintHelper { private: VclPtr<vcl::Window> m_pWindow; + VclPtr<VirtualDevice> m_pBuffer; ///< Buffer for the double-buffering vcl::Region* m_pChildRegion; Rectangle m_aSelectionRect; Rectangle m_aPaintRect; vcl::Region m_aPaintRegion; sal_uInt16 m_nPaintFlags; - bool m_bPop; - bool m_bRestoreCursor; + bool m_bPop : 1; + bool m_bRestoreCursor : 1; + bool m_bCreatedBuffer : 1; ///< This PaintHelper created the buffer for the double-buffering, and should dispose it when being destructed (if it is still alive by then). public: - PaintHelper(vcl::Window* pWindow, sal_uInt16 nPaintFlags); + PaintHelper(vcl::Window* pWindow, const VclPtr<VirtualDevice>& rBuffer, sal_uInt16 nPaintFlags); void SetPop() { m_bPop = true; @@ -82,16 +83,75 @@ public: return m_aPaintRegion; } void DoPaint(const vcl::Region* pRegion); + + /// Create m_pBuffer, and set it up to have the same settings as m_pWindow. + void SetupBuffer(); + + /// Paint the content of the buffer to the current m_pWindow. + void PaintBuffer(); + ~PaintHelper(); }; -PaintHelper::PaintHelper(vcl::Window *pWindow, sal_uInt16 nPaintFlags) +PaintHelper::PaintHelper(vcl::Window *pWindow, const VclPtr<VirtualDevice>& rBuffer, sal_uInt16 nPaintFlags) : m_pWindow(pWindow) + , m_pBuffer(rBuffer) , m_pChildRegion(NULL) , m_nPaintFlags(nPaintFlags) , m_bPop(false) , m_bRestoreCursor(false) + , m_bCreatedBuffer(false) +{ +} + +void PaintHelper::SetupBuffer() +{ + assert(!m_pBuffer); + + m_pBuffer = VclPtrInstance<VirtualDevice>(); + m_bCreatedBuffer = true; + + // transfer various settings + // FIXME: this must disappear as we move to RenderContext only, + // the painting must become state-less, so that no actual + // vcl::Window setting affects this + if (m_pWindow->IsBackground()) + m_pBuffer->SetBackground(m_pWindow->GetBackground()); + else + SAL_WARN("vcl.doublebuffering", "the root of the double-buffering hierarchy should not have a transparent background"); + + m_pBuffer->SetClipRegion(m_pWindow->GetClipRegion()); + m_pBuffer->SetFillColor(m_pWindow->GetFillColor()); + m_pBuffer->SetFont(m_pWindow->GetFont()); + m_pBuffer->SetLineColor(m_pWindow->GetLineColor()); + m_pBuffer->SetMapMode(m_pWindow->GetMapMode()); + m_pBuffer->SetRefPoint(m_pWindow->GetRefPoint()); + m_pBuffer->SetSettings(m_pWindow->GetSettings()); + m_pBuffer->SetTextColor(m_pWindow->GetTextColor()); + m_pBuffer->SetTextLineColor(m_pWindow->GetTextLineColor()); + m_pBuffer->SetOverlineColor(m_pWindow->GetOverlineColor()); + m_pBuffer->SetTextFillColor(m_pWindow->GetTextFillColor()); + m_pBuffer->SetTextAlign(m_pWindow->GetTextAlign()); + m_pBuffer->SetRasterOp(m_pWindow->GetRasterOp()); + m_pBuffer->SetRefPoint(m_pWindow->GetRefPoint()); + m_pBuffer->SetLayoutMode(m_pWindow->GetLayoutMode()); + m_pBuffer->SetDigitLanguage(m_pWindow->GetDigitLanguage()); + + // update the output size now, after all the settings were copied + m_pBuffer->SetOutputSize(m_pWindow->GetOutputSize()); +} + +void PaintHelper::PaintBuffer() { + assert(m_pBuffer); + + // copy the buffer content to the actual window + // export VCL_DOUBLEBUFFERING_AVOID_PAINT=1 to see where we are + // painting directly instead of using Invalidate() + // [ie. everything you can see was painted directly to the + // window either above or in eg. an event handler] + if (!getenv("VCL_DOUBLEBUFFERING_AVOID_PAINT")) + m_pWindow->DrawOutDev(m_aPaintRect.TopLeft(), m_aPaintRect.GetSize(), m_aPaintRect.TopLeft(), m_aPaintRect.GetSize(), *m_pBuffer.get()); } void PaintHelper::DoPaint(const vcl::Region* pRegion) @@ -124,76 +184,22 @@ void PaintHelper::DoPaint(const vcl::Region* pRegion) { m_pWindow->BeginPaint(); - // double-buffering: normally just a selected subset - if (m_pWindow->SupportsDoubleBuffering() || officecfg::Office::Common::Misc::ExperimentalMode::get()) - { - m_pWindow->PushPaintHelper(this, *m_pWindow); + // double-buffering: setup the buffer if it does not exist + if (!m_pBuffer && m_pWindow->SupportsDoubleBuffering()) + SetupBuffer(); - ScopedVclPtrInstance<VirtualDevice> pDevice; - - // transfer various settings - // FIXME: this must disappear as we move to RenderContext only, - // the painting must become state-less, so that no actual - // vcl::Window setting affects this - pDevice->SetBackground(m_pWindow->GetBackground()); - pDevice->SetClipRegion(m_pWindow->GetClipRegion()); - pDevice->SetFillColor(m_pWindow->GetFillColor()); - pDevice->SetFont(m_pWindow->GetFont()); - pDevice->SetLineColor(m_pWindow->GetLineColor()); - pDevice->SetMapMode(m_pWindow->GetMapMode()); - pDevice->SetRefPoint(m_pWindow->GetRefPoint()); - pDevice->SetSettings(m_pWindow->GetSettings()); - pDevice->SetTextColor(m_pWindow->GetTextColor()); - pDevice->SetTextLineColor(m_pWindow->GetTextLineColor()); - pDevice->SetOverlineColor(m_pWindow->GetOverlineColor()); - pDevice->SetTextFillColor(m_pWindow->GetTextFillColor()); - pDevice->SetTextAlign(m_pWindow->GetTextAlign()); - pDevice->SetRasterOp(m_pWindow->GetRasterOp()); - pDevice->SetRefPoint(m_pWindow->GetRefPoint()); - pDevice->SetLayoutMode(m_pWindow->GetLayoutMode()); - pDevice->SetDigitLanguage(m_pWindow->GetDigitLanguage()); - - // update the output size now, after all the settings were copied - pDevice->SetOutputSize(m_pWindow->GetOutputSize()); - - // copy the underlying content to be able to handle trasparency - pDevice->DrawOutDev(m_aPaintRect.TopLeft(), m_aPaintRect.GetSize(), m_aPaintRect.TopLeft(), m_aPaintRect.GetSize(), *m_pWindow); - - m_pWindow->ApplySettings(*pDevice.get()); - - // paint to the VirtualDevice first - m_pWindow->Paint(*pDevice.get(), m_aPaintRect); - - // debugging of the areas - show where we are painting - // export VCL_DOUBLEBUFFERING_DEBUG=1 to see where are we - // painting - if (getenv("VCL_DOUBLEBUFFERING_DEBUG")) - { - Rectangle aTestRect(m_aPaintRect); - aTestRect.Right() -= 1; - aTestRect.Bottom() -= 1; - pDevice->SetLineColor(Color(COL_LIGHTRED)); - pDevice->SetFillColor(); - pDevice->DrawRect(aTestRect); - - pDevice->SetFillColor(Color(COL_LIGHTRED)); - aTestRect = Rectangle(m_aPaintRect.TopLeft(), Size(10, 10)); - pDevice->DrawRect(aTestRect); - aTestRect = Rectangle(Point(m_aPaintRect.Right() - 10, m_aPaintRect.Top()), Size(10, 10)); - pDevice->DrawRect(aTestRect); - aTestRect = Rectangle(Point(m_aPaintRect.Right() - 10, m_aPaintRect.Bottom() - 10), Size(10, 10)); - pDevice->DrawRect(aTestRect); - aTestRect = Rectangle(Point(m_aPaintRect.Left(), m_aPaintRect.Bottom() - 10), Size(10, 10)); - pDevice->DrawRect(aTestRect); - } + // double-buffering: if this window does not support double-buffering, + // but we are in the middle of double-buffered paint, we might be + // losing information + if (m_pBuffer && !m_pWindow->SupportsDoubleBuffering()) + SAL_WARN("vcl.doublebuffering", "non-double buffered window in the double-buffered hierarchy, painting directly: " << typeid(m_pWindow).name()); - // and then copy that to the actual window - // export VCL_DOUBLEBUFFERING_AVOID_PAINT=1 to see where we are - // painting directly instead of using Invalidate() - // [ie. everything you can see was painted directly to the - // window either above or in eg. an event handler] - if (!getenv("VCL_DOUBLEBUFFERING_AVOID_PAINT")) - m_pWindow->DrawOutDev(m_aPaintRect.TopLeft(), m_aPaintRect.GetSize(), m_aPaintRect.TopLeft(), m_aPaintRect.GetSize(), *pDevice.get()); + if (m_pBuffer) + { + // double-buffering + m_pWindow->PushPaintHelper(this, *m_pWindow); + m_pWindow->ApplySettings(*m_pBuffer.get()); + m_pWindow->Paint(*m_pBuffer.get(), m_aPaintRect); } else { @@ -434,10 +440,10 @@ PaintHelper::~PaintHelper() { // Paint from the bottom child window and frontward. vcl::Window* pTempWindow = pWindowImpl->mpLastChild; - while ( pTempWindow ) + while (pTempWindow) { - if ( pTempWindow->mpWindowImpl->mbVisible ) - pTempWindow->ImplCallPaint( m_pChildRegion, m_nPaintFlags ); + if (pTempWindow->mpWindowImpl->mbVisible) + pTempWindow->ImplCallPaint(m_pBuffer, m_pChildRegion, m_nPaintFlags); pTempWindow = pTempWindow->mpWindowImpl->mpPrev; } } @@ -448,6 +454,14 @@ PaintHelper::~PaintHelper() */ m_pWindow->InvertTracking( *(pWindowImpl->mpWinData->mpTrackRect), pWindowImpl->mpWinData->mnTrackFlags ); + // double-buffering: paint in case we created the buffer, the children are + // already painted inside + if (m_bCreatedBuffer && m_pBuffer) + { + PaintBuffer(); + m_pBuffer.disposeAndClear(); + } + // #98943# draw toolbox selection if( !m_aSelectionRect.IsEmpty() ) m_pWindow->DrawSelectionBackground( m_aSelectionRect, 3, false, true, false ); @@ -457,7 +471,7 @@ PaintHelper::~PaintHelper() namespace vcl { -void Window::ImplCallPaint(const vcl::Region* pRegion, sal_uInt16 nPaintFlags) +void Window::ImplCallPaint(const VclPtr<VirtualDevice>& rBuffer, const vcl::Region* pRegion, sal_uInt16 nPaintFlags) { // call PrePaint. PrePaint may add to the invalidate region as well as // other parameters used below. @@ -487,7 +501,7 @@ void Window::ImplCallPaint(const vcl::Region* pRegion, sal_uInt16 nPaintFlags) nPaintFlags = mpWindowImpl->mnPaintFlags & ~(IMPL_PAINT_PAINT); - PaintHelper aHelper(this, nPaintFlags); + PaintHelper aHelper(this, rBuffer, nPaintFlags); if (mpWindowImpl->mnPaintFlags & IMPL_PAINT_PAINT) aHelper.DoPaint(pRegion); @@ -515,7 +529,7 @@ void Window::ImplCallOverlapPaint() // because we were called from the Sal layer OutputDevice *pOutDev = GetOutDev(); pOutDev->BeginPaint(); - ImplCallPaint( NULL, mpWindowImpl->mnPaintFlags /*| IMPL_PAINT_CHECKRTL */); + ImplCallPaint(NULL, NULL, mpWindowImpl->mnPaintFlags /*| IMPL_PAINT_CHECKRTL */); pOutDev->EndPaint(); } } @@ -896,8 +910,8 @@ void Window::ImplUpdateAll( bool bOverlapWindows ) pWindow->ImplCallOverlapPaint(); else { - if ( pWindow->mpWindowImpl->mnPaintFlags & (IMPL_PAINT_PAINT | IMPL_PAINT_PAINTCHILDREN) ) - pWindow->ImplCallPaint( NULL, pWindow->mpWindowImpl->mnPaintFlags ); + if (pWindow->mpWindowImpl->mnPaintFlags & (IMPL_PAINT_PAINT | IMPL_PAINT_PAINTCHILDREN)) + pWindow->ImplCallPaint(NULL, NULL, pWindow->mpWindowImpl->mnPaintFlags); } if ( bFlush ) @@ -1172,7 +1186,6 @@ bool Window::HasPaintEvent() const void Window::Update() { - if ( mpWindowImpl->mpBorderWindow ) { mpWindowImpl->mpBorderWindow->Update(); @@ -1231,7 +1244,7 @@ void Window::Update() pUpdateOverlapWindow = pUpdateOverlapWindow->mpWindowImpl->mpNext; } - pUpdateWindow->ImplCallPaint( NULL, pUpdateWindow->mpWindowImpl->mnPaintFlags ); + pUpdateWindow->ImplCallPaint(NULL, NULL, pUpdateWindow->mpWindowImpl->mnPaintFlags); if (aDogTag.IsDead()) return; _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits