[Libreoffice-commits] core.git: include/vcl vcl/source
Jan Holesovsky
kendy at collabora.com
Tue May 19 07:00:38 PDT 2015
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 <kendy at 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;
More information about the Libreoffice-commits
mailing list