Kaydet (Commit) ec5da2f7 authored tarafından Miklos Vajna's avatar Miklos Vajna Kaydeden (comit) Tomaž Vajngerl

Resolves: tdf#92982 vcl rendercontext: handle buffered paint of vcl::Cursor

Instead of painting on the vcl::Window directly, take a
PaintBufferGuard, and use the vcl::RenderContext of it, that may be
either the vcl::Window or the toplevel frame's buffer.

Trigger the paint of the buffer by informing the guard what area was
painted. In case of direct painting, both the ctor and the dtor of the
guard is a NOP.

This means that finally we can also assert Invert() calls on the output
device, so that direct paint can't happen when double-buffering.

Also:

- make PaintBufferGuard visible outside paint.cxx
- move buffer paint logic to PaintBufferGuard

(cherry picked from commits c85b2511,
a6c7a0bf and
c64a7ce1)

Change-Id: I0322563369dc63b3c49061cbe7c4a911cb13a2e2
Reviewed-on: https://gerrit.libreoffice.org/17576Reviewed-by: 's avatarTomaž Vajngerl <quikee@gmail.com>
Tested-by: 's avatarJenkins <ci@libreoffice.org>
üst 48bb5030
......@@ -378,6 +378,26 @@ public:
::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > mxDNDListenerContainer;
};
/// Sets up the buffer to have settings matching the window, and restores the original state in the dtor.
class PaintBufferGuard
{
ImplFrameData* mpFrameData;
VclPtr<vcl::Window> m_pWindow;
bool mbBackground;
Wallpaper maBackground;
AllSettings maSettings;
long mnOutOffX;
long mnOutOffY;
Rectangle m_aPaintRect;
public:
PaintBufferGuard(ImplFrameData* pFrameData, vcl::Window* pWindow);
~PaintBufferGuard();
/// If this is called, then the dtor will also copy rRectangle to the window from the buffer, before restoring the state.
void SetPaintRect(const Rectangle& rRectangle);
/// Returns either the frame's buffer or the window, in case of no buffering.
vcl::RenderContext* GetRenderContext();
};
// helper methods
bool ImplHandleMouseEvent( vcl::Window* pWindow, MouseNotifyEvent nSVEvent, bool bMouseLeave,
......
......@@ -131,6 +131,7 @@ void OutputDevice::DrawRect( const Rectangle& rRect,
void OutputDevice::Invert( const Rectangle& rRect, sal_uInt16 nFlags )
{
assert(!is_double_buffered_window());
if ( !IsDeviceOutputNecessary() )
return;
......@@ -163,6 +164,7 @@ void OutputDevice::Invert( const Rectangle& rRect, sal_uInt16 nFlags )
void OutputDevice::Invert( const Polygon& rPoly, sal_uInt16 nFlags )
{
assert(!is_double_buffered_window());
if ( !IsDeviceOutputNecessary() )
return;
......
......@@ -44,7 +44,9 @@ struct ImplCursorData
static void ImplCursorInvert( ImplCursorData* pData )
{
vcl::Window* pWindow = pData->mpWindow;
vcl::RenderContext* pRenderContext = pWindow->GetOutDev();
PaintBufferGuard aGuard(pWindow->ImplGetWindowImpl()->mpFrameData, pWindow);
vcl::RenderContext* pRenderContext = aGuard.GetRenderContext();
Rectangle aPaintRect;
bool bMapMode = pRenderContext->IsMapModeEnabled();
pRenderContext->EnableMapMode( false );
sal_uInt16 nInvertStyle;
......@@ -109,11 +111,16 @@ static void ImplCursorInvert( ImplCursorData* pData )
if ( pData->mnOrientation )
aPoly.Rotate( pData->maPixRotOff, pData->mnOrientation );
pRenderContext->Invert( aPoly, nInvertStyle );
aPaintRect = aPoly.GetBoundRect();
}
}
else
{
pRenderContext->Invert( aRect, nInvertStyle );
aPaintRect = aRect;
}
pRenderContext->EnableMapMode( bMapMode );
aGuard.SetPaintRect(pRenderContext->PixelToLogic(aPaintRect));
}
void vcl::Cursor::ImplDraw()
......
......@@ -40,87 +40,124 @@
#define IMPL_PAINT_ERASE ((sal_uInt16)0x0010)
#define IMPL_PAINT_CHECKRTL ((sal_uInt16)0x0020)
/// Sets up the buffer to have settings matching the window, and restore the original state in the dtor.
class PaintBufferGuard
// PaintBufferGuard
PaintBufferGuard::PaintBufferGuard(ImplFrameData* pFrameData, vcl::Window* pWindow)
: mpFrameData(pFrameData),
m_pWindow(pWindow),
mbBackground(false),
mnOutOffX(0),
mnOutOffY(0)
{
ImplFrameData* mpFrameData;
bool mbBackground;
Wallpaper maBackground;
AllSettings maSettings;
long mnOutOffX;
long mnOutOffY;
public:
PaintBufferGuard(ImplFrameData* pFrameData, vcl::Window* pWindow)
: mpFrameData(pFrameData),
mbBackground(false),
mnOutOffX(0),
mnOutOffY(0)
{
// 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
mbBackground = pFrameData->mpBuffer->IsBackground();
if (pWindow->IsBackground())
if (!pFrameData->mpBuffer)
return;
// 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
mbBackground = pFrameData->mpBuffer->IsBackground();
if (pWindow->IsBackground())
{
maBackground = pFrameData->mpBuffer->GetBackground();
pFrameData->mpBuffer->SetBackground(pWindow->GetBackground());
}
//else
//SAL_WARN("vcl.doublebuffering", "the root of the double-buffering hierarchy should not have a transparent background");
PushFlags nFlags = PushFlags::NONE;
nFlags |= PushFlags::CLIPREGION;
nFlags |= PushFlags::FILLCOLOR;
nFlags |= PushFlags::FONT;
nFlags |= PushFlags::LINECOLOR;
nFlags |= PushFlags::MAPMODE;
maSettings = pFrameData->mpBuffer->GetSettings();
nFlags |= PushFlags::REFPOINT;
nFlags |= PushFlags::TEXTCOLOR;
nFlags |= PushFlags::TEXTLINECOLOR;
nFlags |= PushFlags::OVERLINECOLOR;
nFlags |= PushFlags::TEXTFILLCOLOR;
nFlags |= PushFlags::TEXTALIGN;
nFlags |= PushFlags::RASTEROP;
nFlags |= PushFlags::TEXTLAYOUTMODE;
nFlags |= PushFlags::TEXTLANGUAGE;
pFrameData->mpBuffer->Push(nFlags);
pFrameData->mpBuffer->SetClipRegion(pWindow->GetClipRegion());
pFrameData->mpBuffer->SetFillColor(pWindow->GetFillColor());
pFrameData->mpBuffer->SetFont(pWindow->GetFont());
pFrameData->mpBuffer->SetLineColor(pWindow->GetLineColor());
pFrameData->mpBuffer->SetMapMode(pWindow->GetMapMode());
pFrameData->mpBuffer->SetRefPoint(pWindow->GetRefPoint());
pFrameData->mpBuffer->SetSettings(pWindow->GetSettings());
pFrameData->mpBuffer->SetTextColor(pWindow->GetTextColor());
pFrameData->mpBuffer->SetTextLineColor(pWindow->GetTextLineColor());
pFrameData->mpBuffer->SetOverlineColor(pWindow->GetOverlineColor());
pFrameData->mpBuffer->SetTextFillColor(pWindow->GetTextFillColor());
pFrameData->mpBuffer->SetTextAlign(pWindow->GetTextAlign());
pFrameData->mpBuffer->SetRasterOp(pWindow->GetRasterOp());
pFrameData->mpBuffer->SetLayoutMode(pWindow->GetLayoutMode());
pFrameData->mpBuffer->SetDigitLanguage(pWindow->GetDigitLanguage());
mnOutOffX = pFrameData->mpBuffer->GetOutOffXPixel();
mnOutOffY = pFrameData->mpBuffer->GetOutOffYPixel();
pFrameData->mpBuffer->SetOutOffXPixel(pWindow->GetOutOffXPixel());
pFrameData->mpBuffer->SetOutOffYPixel(pWindow->GetOutOffYPixel());
}
PaintBufferGuard::~PaintBufferGuard()
{
if (!mpFrameData->mpBuffer)
return;
if (!m_aPaintRect.IsEmpty())
{
// 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"))
{
maBackground = pFrameData->mpBuffer->GetBackground();
pFrameData->mpBuffer->SetBackground(pWindow->GetBackground());
// Make sure that the +1 value GetSize() adds to the size is in pixels.
Size aPaintRectSize;
if (m_pWindow->GetMapMode().GetMapUnit() == MAP_PIXEL)
{
aPaintRectSize = m_aPaintRect.GetSize();
}
else
{
Rectangle aRectanglePixel = m_pWindow->LogicToPixel(m_aPaintRect);
aPaintRectSize = m_pWindow->PixelToLogic(aRectanglePixel.GetSize());
}
m_pWindow->DrawOutDev(m_aPaintRect.TopLeft(), aPaintRectSize, m_aPaintRect.TopLeft(), aPaintRectSize, *mpFrameData->mpBuffer.get());
}
//else
//SAL_WARN("vcl.doublebuffering", "the root of the double-buffering hierarchy should not have a transparent background");
PushFlags nFlags = PushFlags::NONE;
nFlags |= PushFlags::CLIPREGION;
nFlags |= PushFlags::FILLCOLOR;
nFlags |= PushFlags::FONT;
nFlags |= PushFlags::LINECOLOR;
nFlags |= PushFlags::MAPMODE;
maSettings = pFrameData->mpBuffer->GetSettings();
nFlags |= PushFlags::REFPOINT;
nFlags |= PushFlags::TEXTCOLOR;
nFlags |= PushFlags::TEXTLINECOLOR;
nFlags |= PushFlags::OVERLINECOLOR;
nFlags |= PushFlags::TEXTFILLCOLOR;
nFlags |= PushFlags::TEXTALIGN;
nFlags |= PushFlags::RASTEROP;
nFlags |= PushFlags::TEXTLAYOUTMODE;
nFlags |= PushFlags::TEXTLANGUAGE;
pFrameData->mpBuffer->Push(nFlags);
pFrameData->mpBuffer->SetClipRegion(pWindow->GetClipRegion());
pFrameData->mpBuffer->SetFillColor(pWindow->GetFillColor());
pFrameData->mpBuffer->SetFont(pWindow->GetFont());
pFrameData->mpBuffer->SetLineColor(pWindow->GetLineColor());
pFrameData->mpBuffer->SetMapMode(pWindow->GetMapMode());
pFrameData->mpBuffer->SetRefPoint(pWindow->GetRefPoint());
pFrameData->mpBuffer->SetSettings(pWindow->GetSettings());
pFrameData->mpBuffer->SetTextColor(pWindow->GetTextColor());
pFrameData->mpBuffer->SetTextLineColor(pWindow->GetTextLineColor());
pFrameData->mpBuffer->SetOverlineColor(pWindow->GetOverlineColor());
pFrameData->mpBuffer->SetTextFillColor(pWindow->GetTextFillColor());
pFrameData->mpBuffer->SetTextAlign(pWindow->GetTextAlign());
pFrameData->mpBuffer->SetRasterOp(pWindow->GetRasterOp());
pFrameData->mpBuffer->SetLayoutMode(pWindow->GetLayoutMode());
pFrameData->mpBuffer->SetDigitLanguage(pWindow->GetDigitLanguage());
mnOutOffX = pFrameData->mpBuffer->GetOutOffXPixel();
mnOutOffY = pFrameData->mpBuffer->GetOutOffYPixel();
pFrameData->mpBuffer->SetOutOffXPixel(pWindow->GetOutOffXPixel());
pFrameData->mpBuffer->SetOutOffYPixel(pWindow->GetOutOffYPixel());
}
~PaintBufferGuard()
{
// Restore buffer state.
mpFrameData->mpBuffer->SetOutOffXPixel(mnOutOffX);
mpFrameData->mpBuffer->SetOutOffYPixel(mnOutOffY);
mpFrameData->mpBuffer->Pop();
mpFrameData->mpBuffer->SetSettings(maSettings);
if (mbBackground)
mpFrameData->mpBuffer->SetBackground(maBackground);
else
mpFrameData->mpBuffer->SetBackground();
}
};
// Restore buffer state.
mpFrameData->mpBuffer->SetOutOffXPixel(mnOutOffX);
mpFrameData->mpBuffer->SetOutOffYPixel(mnOutOffY);
mpFrameData->mpBuffer->Pop();
mpFrameData->mpBuffer->SetSettings(maSettings);
if (mbBackground)
mpFrameData->mpBuffer->SetBackground(maBackground);
else
mpFrameData->mpBuffer->SetBackground();
}
void PaintBufferGuard::SetPaintRect(const Rectangle& rRectangle)
{
m_aPaintRect = rRectangle;
}
vcl::RenderContext* PaintBufferGuard::GetRenderContext()
{
if (mpFrameData->mpBuffer)
return mpFrameData->mpBuffer;
else
return m_pWindow;
}
class PaintHelper
{
......@@ -200,28 +237,8 @@ void PaintHelper::PaintBuffer()
assert(pFrameData->mbInBufferedPaint);
assert(m_bStartedBufferedPaint);
// 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"))
{
// Make sure that the +1 value GetSize() adds to the size is in pixels.
Size aPaintRectSize;
if (m_pWindow->GetMapMode().GetMapUnit() == MAP_PIXEL)
{
aPaintRectSize = m_aPaintRect.GetSize();
}
else
{
Rectangle aRectanglePixel = m_pWindow->LogicToPixel(m_aPaintRect);
aPaintRectSize = m_pWindow->PixelToLogic(aRectanglePixel.GetSize());
}
PaintBufferGuard g(pFrameData, m_pWindow);
m_pWindow->DrawOutDev(m_aPaintRect.TopLeft(), aPaintRectSize, m_aPaintRect.TopLeft(), aPaintRectSize, *pFrameData->mpBuffer.get());
}
PaintBufferGuard aGuard(pFrameData, m_pWindow);
aGuard.SetPaintRect(m_aPaintRect);
}
void PaintHelper::DoPaint(const vcl::Region* pRegion)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment