[Libreoffice-commits] core.git: include/svx svx/source sw/source
Noel Grandin (via logerrit)
logerrit at kemper.freedesktop.org
Thu Aug 20 14:38:33 UTC 2020
include/svx/sdrpagewindow.hxx | 4 ++--
svx/source/svdraw/sdrpagewindow.cxx | 33 ++++++++++++++++++++++++++-------
svx/source/svdraw/svdpagv.cxx | 11 ++++++-----
sw/source/core/view/viewsh.cxx | 5 +++--
4 files changed, 37 insertions(+), 16 deletions(-)
New commits:
commit 445cf499666f21c2d480ce1df9ce6004b9450b64
Author: Noel Grandin <noel.grandin at collabora.co.uk>
AuthorDate: Thu Aug 20 11:27:29 2020 +0200
Commit: Noel Grandin <noel.grandin at collabora.co.uk>
CommitDate: Thu Aug 20 16:37:51 2020 +0200
tdf#132940 Crash in mergedlo!vcl::Region::operator=
We had a SdrPageWindow accessing a SdPaintWindow that had already been
freed.
Turns that SdrPageWindow can be "patched" more than once given enough
stuff going on in writer, so make the call sites restore the previous
state as the stack unwinds.
Change-Id: Ia1ef5c9b2f818b7873e8e739c9cdf257554e403a
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/101044
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin at collabora.co.uk>
diff --git a/include/svx/sdrpagewindow.hxx b/include/svx/sdrpagewindow.hxx
index 1e6e9301b0cb..c7278233c313 100644
--- a/include/svx/sdrpagewindow.hxx
+++ b/include/svx/sdrpagewindow.hxx
@@ -66,8 +66,8 @@ public:
rtl::Reference< sdr::overlay::OverlayManager > const & GetOverlayManager() const;
// #i72752# allow patcing SdrPaintWindow from SdrPageView::DrawLayer if needed
- void patchPaintWindow(SdrPaintWindow& rPaintWindow);
- void unpatchPaintWindow();
+ [[nodiscard]] SdrPaintWindow* patchPaintWindow(SdrPaintWindow& rPaintWindow);
+ void unpatchPaintWindow(SdrPaintWindow* pPreviousPaintWindow);
// the repaint method. For migration from pPaintProc, use one more parameter
void PrePaint();
diff --git a/svx/source/svdraw/sdrpagewindow.cxx b/svx/source/svdraw/sdrpagewindow.cxx
index 823205a22e65..0b0ea0536945 100644
--- a/svx/source/svdraw/sdrpagewindow.cxx
+++ b/svx/source/svdraw/sdrpagewindow.cxx
@@ -163,22 +163,41 @@ rtl::Reference< sdr::overlay::OverlayManager > const & SdrPageWindow::GetOverlay
return GetPaintWindow().GetOverlayManager();
}
-void SdrPageWindow::patchPaintWindow(SdrPaintWindow& rPaintWindow)
+SdrPaintWindow* SdrPageWindow::patchPaintWindow(SdrPaintWindow& rPaintWindow)
{
- mpImpl->mpOriginalPaintWindow = mpImpl->mpPaintWindow;
- mpImpl->mpPaintWindow = &rPaintWindow;
- mpImpl->mpOriginalPaintWindow->setPatched(&rPaintWindow);
+ if (!mpImpl->mpOriginalPaintWindow)
+ {
+ // first patch
+ mpImpl->mpOriginalPaintWindow = mpImpl->mpPaintWindow;
+ mpImpl->mpPaintWindow = &rPaintWindow;
+ mpImpl->mpOriginalPaintWindow->setPatched(&rPaintWindow);
+ return mpImpl->mpOriginalPaintWindow;
+ }
+ else
+ {
+ // second or more patch
+ auto pPreviousPaintWindow = mpImpl->mpPaintWindow;
+ mpImpl->mpPaintWindow = &rPaintWindow;
+ mpImpl->mpOriginalPaintWindow->setPatched(&rPaintWindow);
+ return pPreviousPaintWindow;
+ }
}
-void SdrPageWindow::unpatchPaintWindow()
+void SdrPageWindow::unpatchPaintWindow(SdrPaintWindow* pPreviousPaintWindow)
{
- DBG_ASSERT(mpImpl->mpOriginalPaintWindow, "SdrPageWindow::unpatchPaintWindow: paint window not patched!" );
- if (mpImpl->mpOriginalPaintWindow)
+ if (pPreviousPaintWindow == mpImpl->mpOriginalPaintWindow)
{
+ // first patch
mpImpl->mpPaintWindow = mpImpl->mpOriginalPaintWindow;
mpImpl->mpOriginalPaintWindow->setPatched(nullptr);
mpImpl->mpOriginalPaintWindow = nullptr;
}
+ else
+ {
+ // second or more patch
+ mpImpl->mpPaintWindow = pPreviousPaintWindow;
+ mpImpl->mpOriginalPaintWindow->setPatched(pPreviousPaintWindow);
+ }
}
void SdrPageWindow::PrePaint()
diff --git a/svx/source/svdraw/svdpagv.cxx b/svx/source/svdraw/svdpagv.cxx
index b95109ed6886..ad38d0ad3395 100644
--- a/svx/source/svdraw/svdpagv.cxx
+++ b/svx/source/svdraw/svdpagv.cxx
@@ -32,6 +32,7 @@
#include <svx/sdrpagewindow.hxx>
#include <svx/sdrpaintwindow.hxx>
#include <comphelper/lok.hxx>
+#include <comphelper/scopeguard.hxx>
#include <basegfx/range/b2irectangle.hxx>
using namespace ::com::sun::star;
@@ -290,14 +291,14 @@ void SdrPageView::DrawLayer(SdrLayerID nID, OutputDevice* pGivenTarget,
aTemporaryPaintWindow.SetRedrawRegion(rExistingRegion);
else
aTemporaryPaintWindow.SetRedrawRegion(vcl::Region(rRect));
- // patch the ExistingPageWindow
- pPreparedTarget->patchPaintWindow(aTemporaryPaintWindow);
+ // patch the ExistingPageWindow
+ auto pPreviousWindow = pPreparedTarget->patchPaintWindow(aTemporaryPaintWindow);
+ // unpatch window when leaving the scope
+ const ::comphelper::ScopeGuard aGuard(
+ [&pPreviousWindow, &pPreparedTarget]() { pPreparedTarget->unpatchPaintWindow(pPreviousWindow); } );
// redraw the layer
pPreparedTarget->RedrawLayer(&nID, pRedirector, pPageFrame);
-
- // restore the ExistingPageWindow
- pPreparedTarget->unpatchPaintWindow();
}
else
{
diff --git a/sw/source/core/view/viewsh.cxx b/sw/source/core/view/viewsh.cxx
index cd171c79ba06..7f2f6e4466bb 100644
--- a/sw/source/core/view/viewsh.cxx
+++ b/sw/source/core/view/viewsh.cxx
@@ -1716,6 +1716,7 @@ class RenderContextGuard
{
std::unique_ptr<SdrPaintWindow> m_TemporaryPaintWindow;
SdrPageWindow* m_pPatchedPageWindow;
+ SdrPaintWindow* m_pPreviousPaintWindow = nullptr;
public:
RenderContextGuard(VclPtr<vcl::RenderContext>& pRef, vcl::RenderContext* pValue, SwViewShell* pShell)
@@ -1740,7 +1741,7 @@ public:
if (nullptr != m_pPatchedPageWindow)
{
m_TemporaryPaintWindow.reset(new SdrPaintWindow(*pDrawView, *pValue));
- m_pPatchedPageWindow->patchPaintWindow(*m_TemporaryPaintWindow);
+ m_pPreviousPaintWindow = m_pPatchedPageWindow->patchPaintWindow(*m_TemporaryPaintWindow);
}
}
}
@@ -1749,7 +1750,7 @@ public:
{
if(nullptr != m_pPatchedPageWindow)
{
- m_pPatchedPageWindow->unpatchPaintWindow();
+ m_pPatchedPageWindow->unpatchPaintWindow(m_pPreviousPaintWindow);
}
}
};
More information about the Libreoffice-commits
mailing list